]> de.git.xonotic.org Git - xonotic/netradiant.git/commitdiff
Merge commit 'b681f28130ff2e9789253eff1c1d41163e427eaa' into master-merge
authorThomas Debesse <dev@illwieckz.net>
Mon, 20 Jun 2022 02:39:42 +0000 (04:39 +0200)
committerThomas Debesse <dev@illwieckz.net>
Mon, 20 Jun 2022 02:39:42 +0000 (04:39 +0200)
1  2 
radiant/environment.cpp
radiant/mainframe.cpp
radiant/map.cpp
radiant/texwindow.cpp
tools/quake3/q3map2/bspfile_abstract.c
tools/quake3/q3map2/light_bounce.c
tools/quake3/q3map2/lightmaps_ydnar.c
tools/quake3/q3map2/q3map2.h
tools/quake3/q3map2/shaders.c
tools/quake3/q3map2/surface_meta.c

diff --combined radiant/environment.cpp
index f2315b85a743960d7acb2c5354c982f97916f5ff,38c93c41006b978dc44b9530af6cb105d77bc7dd..e7b48a6bf188d763cebc1fc26f00ece80e3e105f
@@@ -110,7 -110,8 +110,8 @@@ bool gamedetect_check_game( char const 
  void gamedetect(){
        // if we're inside a Nexuiz install
        // default to nexuiz.game (unless the user used an option to inhibit this)
-       bool nogamedetect = false;
+       //bool nogamedetect = false;
+       bool nogamedetect = true;
        int i;
        for ( i = 1; i < g_argc - 1; ++i )
        {
                        if ( gamedetect_check_game( "nexuiz.game", "data/common-spog.pk3", "nexuiz.exe", buf, p - buf ) )
  #elif GDEF_OS_MACOS
                        if ( gamedetect_check_game( "nexuiz.game", "data/common-spog.pk3", "Nexuiz.app/Contents/Info.plist", buf, p - buf ) )
 -#else
 +#elif GDEF_OS_LINUX
                        if ( gamedetect_check_game( "nexuiz.game", "data/common-spog.pk3", "nexuiz-linux-glx.sh", buf, p - buf ) )
 +#else
 +                      if ( gamedetect_check_game( "nexuiz.game", "data/common-spog.pk3", NULL, buf, p - buf ) )
  #endif
                        { return; }
  
  
  namespace
  {
 -CopiedString home_path;
 -CopiedString app_path;
 +      // executable file path
 +      CopiedString app_filepath;
 +      // directory paths
 +      CopiedString home_path;
 +      CopiedString app_path;
 +      CopiedString lib_path;
 +      CopiedString data_path;
 +}
 +
 +const char* environment_get_app_filepath(){
 +      return app_filepath.c_str();
  }
  
  const char* environment_get_home_path(){
@@@ -188,20 -178,10 +189,20 @@@ const char* environment_get_app_path()
        return app_path.c_str();
  }
  
 +const char *environment_get_lib_path()
 +{
 +      return lib_path.c_str();
 +}
 +
 +const char *environment_get_data_path()
 +{
 +      return data_path.c_str();
 +}
 +
  bool portable_app_setup(){
        StringOutputStream confdir( 256 );
        confdir << app_path.c_str() << "settings/";
 -      if ( file_exists( confdir.c_str() ) ) {
 +      if ( file_is_directory( confdir.c_str() ) ) {
                home_path = confdir.c_str();
                return true;
        }
  const char* LINK_NAME =
  #if GDEF_OS_LINUX
        "/proc/self/exe"
 -#else // FreeBSD and OSX
 +#else // FreeBSD and macOS
        "/proc/curproc/file"
  #endif
  ;
  
 -/// brief Returns the filename of the executable belonging to the current process, or 0 if not found.
 +/// brief Returns the filename of the executable belonging to the current process, or empty string if not found.
  char const* getexename( char *buf ){
        /* Now read the symbolic link */
 -      int ret = readlink( LINK_NAME, buf, PATH_MAX );
 +      const int ret = readlink( LINK_NAME, buf, PATH_MAX );
  
        if ( ret == -1 ) {
                globalOutputStream() << "getexename: falling back to argv[0]: " << makeQuoted( g_argv[0] );
 -              const char* path = realpath( g_argv[0], buf );
 -              if ( path == 0 ) {
 +              if( realpath( g_argv[0], buf ) == 0 ) {
                        /* In case of an error, leave the handling up to the caller */
 -                      return "";
 +                      *buf = '\0';
                }
        }
 +      else {
 +              /* Ensure proper NUL termination */
 +              buf[ret] = 0;
 +      }
  
 -      /* Ensure proper NUL termination */
 -      buf[ret] = 0;
 +      return buf;
 +}
  
 +char const* getexepath( char *buf ) {
        /* delete the program name */
        *( strrchr( buf, '/' ) ) = '\0';
  
@@@ -272,69 -248,16 +273,69 @@@ void environment_init( int argc, char c
  
        {
                char real[PATH_MAX];
 -              app_path = getexename( real );
 -              ASSERT_MESSAGE( !string_empty( app_path.c_str() ), "failed to deduce app path" );
 +              app_filepath = getexename( real );
 +              ASSERT_MESSAGE( !string_empty( app_filepath.c_str() ), "failed to deduce app path" );
 +
 +              strncpy( real, app_filepath.c_str(), strlen( app_filepath.c_str() ) );
 +              app_path = getexepath( real );
 +      }
 +
 +      {
 +#if defined(RADIANT_FHS_INSTALL)
 +              StringOutputStream buffer;
 +      #if defined(RADIANT_ADDONS_DIR)
 +              buffer << RADIANT_ADDONS_DIR << "/";
 +      #else
 +              buffer << app_path.c_str() << "../lib/";
 +              buffer << RADIANT_LIB_ARCH << "/";
 +              buffer << RADIANT_BASENAME << "/";
 +      #endif
 +              lib_path = buffer.c_str();
 +#else
 +              lib_path = app_path.c_str();
 +#endif
 +      }
 +
 +      {
 +#if defined(RADIANT_FHS_INSTALL)
 +              StringOutputStream buffer;
 +      #if defined(RADIANT_DATA_DIR)
 +              buffer << RADIANT_DATA_DIR << "/";
 +      #else
 +              buffer << app_path.c_str() << "../share/";
 +              buffer << RADIANT_BASENAME << "/";
 +      #endif
 +              data_path = buffer.c_str();
 +#else
 +              data_path = app_path.c_str();
 +#endif
        }
  
        if ( !portable_app_setup() ) {
                StringOutputStream home( 256 );
 -              home << DirectoryCleaned( g_get_user_config_dir() ) << "netradiant/";
 +#if GDEF_OS_MACOS
 +              /* This is used on macOS, this will produce
 +              ~/Library/Application Support/NetRadiant folder. */
 +              home << DirectoryCleaned( g_get_home_dir() );
 +              Q_mkdir( home.c_str() );
 +              home << "Library/";
 +              Q_mkdir( home.c_str() );
 +              home << "Application Support/";
 +              Q_mkdir( home.c_str() );
 +              home << RADIANT_NAME << "/";
 +#else // if GDEF_OS_XDG
 +              /* This is used on both Linux and FreeBSD,
 +              this will produce ~/.config/netradiant folder
 +              when environment has default settings, the
 +              XDG_CONFIG_HOME variable modifies it. */
 +              home << DirectoryCleaned( g_get_user_config_dir() );
 +              Q_mkdir( home.c_str() );
 +              home << RADIANT_BASENAME << "/";
 +#endif // ! GDEF_OS_MACOS
                Q_mkdir( home.c_str() );
                home_path = home.c_str();
        }
 +
        gamedetect();
  }
  
@@@ -348,14 -271,7 +349,14 @@@ void environment_init( int argc, char c
        {
                // get path to the editor
                char filename[MAX_PATH + 1];
 +              StringOutputStream app_filepath_stream( 256 );
 +              StringOutputStream app_path_stream( 256 );
 +
                GetModuleFileName( 0, filename, MAX_PATH );
 +              
 +              app_filepath_stream << PathCleaned( filename );
 +              app_filepath = app_filepath_stream.c_str();
 +
                char* last_separator = strrchr( filename, '\\' );
                if ( last_separator != 0 ) {
                        *( last_separator + 1 ) = '\0';
                {
                        filename[0] = '\0';
                }
 -              StringOutputStream app( 256 );
 -              app << PathCleaned( filename );
 -              app_path = app.c_str();
 +
 +              app_path_stream << PathCleaned( filename );
 +              app_path = app_path_stream.c_str();
 +
 +              lib_path = app_path;
 +              data_path = app_path;
        }
  
        if ( !portable_app_setup() ) {
                char *appdata = getenv( "APPDATA" );
 +
                StringOutputStream home( 256 );
                home << PathCleaned( appdata );
 -              home << "/NetRadiantSettings/";
 +              home << "/";
 +              home << RADIANT_NAME;
 +              home << "/";
 +
                Q_mkdir( home.c_str() );
                home_path = home.c_str();
        }
diff --combined radiant/mainframe.cpp
index 1bea47d16daa80c47f0b4ca559b64d8e9871ba7b,6f377579f484b3015ce5876c606a19e35b1e3023..84ab042c1bcf94e39487b28e1ba4f2ba2ba3db08
  #include "referencecache.h"
  #include "texwindow.h"
  
 +#if GDEF_OS_WINDOWS
 +#include <process.h>
 +#else
 +#include <spawn.h>
 +#endif
 +
 +#ifdef WORKAROUND_WINDOWS_GTK2_GLWIDGET
 +/* workaround for gtk 2.24 issue: not displayed glwidget after toggle */
 +#define WORKAROUND_GOBJECT_SET_GLWIDGET(window, widget) g_object_set_data( G_OBJECT( window ), "glwidget", G_OBJECT( widget ) )
 +#else
 +#define WORKAROUND_GOBJECT_SET_GLWIDGET(window, widget)
 +#endif
  
  struct layout_globals_t
  {
@@@ -167,8 -155,6 +167,8 @@@ void VFS_Refresh()
        RefreshReferences();
        // also refresh texture browser
        TextureBrowser_RefreshShaders();
 +      // also show textures (all or common)
 +      TextureBrowser_ShowStartupShaders( GlobalTextureBrowser() );
  }
  
  void VFS_Restart(){
@@@ -227,7 -213,9 +227,7 @@@ void HomePaths_Realise()
                        }
                        path.clear();
                        path << DirectoryCleaned( g_get_home_dir() ) << prefix << "/";
 -#endif
 -
 -#if GDEF_OS_WINDOWS
 +#elif GDEF_OS_WINDOWS
                        TCHAR mydocsdir[MAX_PATH + 1];
                        wchar_t *mydocsdirw;
                        HMODULE shfolder = LoadLibrary( "shfolder.dll" );
                                        break;
                                }
                        }
 -#endif
 -
 -#if GDEF_OS_POSIX
 +#elif GDEF_OS_XDG
 +                      path.clear();
 +                      path << DirectoryCleaned( g_get_user_data_dir() ) << ( prefix + 1 ) << "/";
 +                      if ( file_exists( path.c_str() ) && file_is_directory( path.c_str() ) ) {
 +                              g_qeglobals.m_userEnginePath = path.c_str();
 +                              break;
 +                      }
 +                      else {
                        path.clear();
                        path << DirectoryCleaned( g_get_home_dir() ) << prefix << "/";
                        g_qeglobals.m_userEnginePath = path.c_str();
                        break;
 +                      }
  #endif
                }
  
@@@ -452,32 -434,14 +452,32 @@@ void setPakPath( int num, const char* p
  }
  
  
 -// App Path
 +// executable file path (full path)
 +CopiedString g_strAppFilePath;
  
 -CopiedString g_strAppPath;                 ///< holds the full path of the executable
 +// directory paths
 +CopiedString g_strAppPath; 
 +CopiedString g_strLibPath;
 +CopiedString g_strDataPath;
 +
 +const char* AppFilePath_get(){
 +      return g_strAppFilePath.c_str();
 +}
  
  const char* AppPath_get(){
        return g_strAppPath.c_str();
  }
  
 +const char *LibPath_get()
 +{
 +    return g_strLibPath.c_str();
 +}
 +
 +const char *DataPath_get()
 +{
 +    return g_strDataPath.c_str();
 +}
 +
  /// the path to the local rc-dir
  const char* LocalRcPath_get( void ){
        static CopiedString rc_path;
@@@ -576,28 -540,39 +576,28 @@@ struct PakPath4 
  bool g_disableEnginePath = false;
  bool g_disableHomePath = false;
  
 -void Paths_constructPreferences( PreferencesPage& page ){
 +void Paths_constructBasicPreferences(  PreferencesPage& page ) {
        page.appendPathEntry( "Engine Path", true, make_property<EnginePath>(g_strEnginePath) );
 +}
  
 -      page.appendCheckBox(
 -              "", "Do not use Engine Path",
 -              g_disableEnginePath
 -                                                );
 +void Paths_constructPreferences( PreferencesPage& page ){
 +      Paths_constructBasicPreferences( page );
  
 -      page.appendCheckBox(
 -              "", "Do not use Home Path",
 -              g_disableHomePath
 -              );
 +      page.appendSpacer( 4 );
 +      page.appendLabel( "", "Advanced options" );
 +      page.appendCheckBox( "", "Do not use Engine Path", g_disableEnginePath );
 +      page.appendCheckBox( "", "Do not use Home Path", g_disableHomePath );
  
 -      for ( int i = 0; i < g_pakPathCount; i++ ) {
 -              std::string label = "Pak Path " + std::to_string(i);
 -              switch (i) {
 -                      case 0:
 -                      page.appendPathEntry( label.c_str(), true, make_property<PakPath0>( g_strPakPath[i] ) );
 -                      break;
 -                      case 1:
 -                      page.appendPathEntry( label.c_str(), true, make_property<PakPath1>( g_strPakPath[i] ) );
 -                      break;
 -                      case 2:
 -                      page.appendPathEntry( label.c_str(), true, make_property<PakPath2>( g_strPakPath[i] ) );
 -                      break;
 -                      case 3:
 -                      page.appendPathEntry( label.c_str(), true, make_property<PakPath3>( g_strPakPath[i] ) );
 -                      break;
 -                      case 4:
 -                      page.appendPathEntry( label.c_str(), true, make_property<PakPath4>( g_strPakPath[i] ) );
 -                      break;
 -}
 -      }
 +      page.appendSpacer( 4 );
 +      page.appendLabel( "", "Only a very few games support Pak Paths," );
 +      page.appendLabel( "", "if you don't know what it is, leave this blank." );
 +
 +      const char *label = "Pak Path ";
 +      page.appendPathEntry( label, true, make_property<PakPath0>( g_strPakPath[0] ) );
 +      page.appendPathEntry( label, true, make_property<PakPath1>( g_strPakPath[1] ) );
 +      page.appendPathEntry( label, true, make_property<PakPath2>( g_strPakPath[2] ) );
 +      page.appendPathEntry( label, true, make_property<PakPath3>( g_strPakPath[3] ) );
 +      page.appendPathEntry( label, true, make_property<PakPath4>( g_strPakPath[4] ) );
  }
  
  void Paths_constructPage( PreferenceGroup& group ){
@@@ -614,14 -589,14 +614,14 @@@ class PathsDialog : public Dialo
  {
  public:
  ui::Window BuildDialog(){
 -      auto frame = create_dialog_frame( "Path settings", ui::Shadow::ETCHED_IN );
 +      auto frame = create_dialog_frame( "Path Settings", ui::Shadow::ETCHED_IN );
  
        auto vbox2 = create_dialog_vbox( 0, 4 );
        frame.add(vbox2);
  
        {
 -              PreferencesPage preferencesPage( *this, vbox2 );
 -              Paths_constructPreferences( preferencesPage );
 +              PreferencesPage page( *this, vbox2 );
 +              Paths_constructBasicPreferences( page );
        }
  
        return ui::Window(create_simple_modal_dialog_window( "Engine Path Not Found", m_modal, frame ));
  
  PathsDialog g_PathsDialog;
  
+ bool g_strEnginePath_was_empty_1st_start = false;
  void EnginePath_verify(){
-       if ( !file_exists( g_strEnginePath.c_str() ) ) {
+       if ( !file_exists( g_strEnginePath.c_str() ) || g_strEnginePath_was_empty_1st_start ) {
                g_PathsDialog.Create();
                g_PathsDialog.DoModal();
                g_PathsDialog.Destroy();
@@@ -778,7 -755,7 +780,7 @@@ void Radiant_detachGameToolsPathObserve
  void Radiant_Initialise(){
        GlobalModuleServer_Initialise();
  
 -      Radiant_loadModulesFromRoot( AppPath_get() );
 +      Radiant_loadModulesFromRoot( LibPath_get() );
  
        Preferences_Load();
  
@@@ -807,7 -784,7 +809,7 @@@ void Radiant_Shutdown()
  }
  
  void Exit(){
 -      if ( ConfirmModified( "Exit Radiant" ) ) {
 +      if ( ConfirmModified( "Exit " RADIANT_NAME ) ) {
                gtk_main_quit();
        }
  }
@@@ -968,53 -945,6 +970,53 @@@ void ColorScheme_Ydnar()
        XY_UpdateAllWindows();
  }
  
 +/* color scheme to fit the GTK Adwaita Dark theme */
 +void ColorScheme_AdwaitaDark()
 +{
 +      // SI_Colors0
 +      // GlobalTextureBrowser().color_textureback
 +      TextureBrowser_setBackgroundColour(GlobalTextureBrowser(), Vector3(0.25f, 0.25f, 0.25f));
 +
 +      // SI_Colors4
 +      g_camwindow_globals.color_cameraback = Vector3(0.25f, 0.25f, 0.25f);
 +      // SI_Colors12
 +      g_camwindow_globals.color_selbrushes3d = Vector3(1.0f, 0.0f, 0.0f);
 +      CamWnd_Update(*g_pParentWnd->GetCamWnd());
 +
 +      // SI_Colors1
 +      g_xywindow_globals.color_gridback = Vector3(0.25f, 0.25f, 0.25f);
 +      // SI_Colors2
 +      g_xywindow_globals.color_gridminor = Vector3(0.21f, 0.23f, 0.23f);
 +      // SI_Colors3
 +      g_xywindow_globals.color_gridmajor = Vector3(0.14f, 0.15f, 0.15f);
 +      // SI_Colors14
 +      g_xywindow_globals.color_gridmajor_alt = Vector3(1.0f, 0.0f, 0.0f);
 +      // SI_Colors6
 +      g_xywindow_globals.color_gridblock = Vector3(1.0f, 1.0f, 1.0f);
 +      // SI_Colors7
 +      g_xywindow_globals.color_gridtext = Vector3(0.0f, 0.0f, 0.0f);
 +      // ??
 +      g_xywindow_globals.color_selbrushes = Vector3(1.0f, 0.0f, 0.0f);
 +      // ??
 +      g_xywindow_globals.color_clipper = Vector3(0.0f, 0.0f, 1.0f);
 +      // SI_Colors8
 +      g_xywindow_globals.color_brushes = Vector3(0.73f, 0.73f, 0.73f);
 +
 +      // SI_AxisColors0
 +      g_xywindow_globals.AxisColorX = Vector3(1.0f, 0.0f, 0.0f);
 +      // SI_AxisColors1
 +      g_xywindow_globals.AxisColorY = Vector3(0.0f, 1.0f, 0.0f);
 +      // SI_AxisColors2
 +      g_xywindow_globals.AxisColorZ = Vector3(0.0f, 0.0f, 1.0f);
 +      SetWorldspawnColour(g_xywindow_globals.color_brushes);
 +      // ??
 +      g_xywindow_globals.color_viewname = Vector3(0.5f, 0.0f, 0.75f);
 +      XY_UpdateAllWindows();
 +
 +      // SI_Colors5
 +      // g_entity_globals.color_entity = Vector3(0.0f, 0.0f, 0.0f);
 +}
 +
  typedef Callback<void(Vector3&)> GetColourCallback;
  typedef Callback<void(const Vector3&)> SetColourCallback;
  
@@@ -1132,7 -1062,6 +1134,7 @@@ ui::MenuItem create_colours_menu()
        create_menu_item_with_mnemonic( menu_3, "Q3Radiant Original", "ColorSchemeQER" );
        create_menu_item_with_mnemonic( menu_3, "Black and Green", "ColorSchemeBlackAndGreen" );
        create_menu_item_with_mnemonic( menu_3, "Maya/Max/Lightwave Emulation", "ColorSchemeYdnar" );
 +      create_menu_item_with_mnemonic(menu_3, "Adwaita Dark", "ColorSchemeAdwaitaDark");
  
        menu_separator( menu_in_menu );
  
@@@ -1806,11 -1735,9 +1808,11 @@@ void Selection_SnapToGrid()
  
  
  static gint qe_every_second( gpointer data ){
 -      GdkModifierType mask;
 +      if (g_pParentWnd == nullptr)
 +              return TRUE;
  
 -      gdk_window_get_pointer( 0, 0, 0, &mask );
 +      GdkModifierType mask;
 +      gdk_window_get_pointer( gtk_widget_get_window(g_pParentWnd->m_window), nullptr, nullptr, &mask );
  
        if ( ( mask & ( GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK ) ) == 0 ) {
                QE_CheckAutoSave();
@@@ -1922,18 -1849,15 +1924,18 @@@ void ScreenUpdates_Disable( const char
                bool isActiveApp = MainFrame_isActiveApp();
  
                g_wait = create_wait_dialog( title, message );
 -              gtk_grab_add( g_wait.m_window  );
  
                if ( isActiveApp ) {
                        g_wait.m_window.show();
 +                      gtk_grab_add( g_wait.m_window  );
                        ScreenUpdates_process();
                }
        }
        else if ( g_wait.m_window.visible() ) {
                g_wait.m_label.text(message);
 +              if ( GTK_IS_WINDOW(g_wait.m_window) ) {
 +                      gtk_grab_add(g_wait.m_window);
 +              }
                ScreenUpdates_process();
        }
        g_wait_stack.push_back( message );
@@@ -2160,9 -2084,6 +2162,9 @@@ ui::MenuItem create_view_menu( MainFram
                create_menu_item_with_mnemonic( camera_menu, "Far Clip Plane In", "CubicClipZoomIn" );
                create_menu_item_with_mnemonic( camera_menu, "Far Clip Plane Out", "CubicClipZoomOut" );
                menu_separator( camera_menu );
 +              create_menu_item_with_mnemonic( camera_menu, "Decrease FOV", "FOVDec" );
 +              create_menu_item_with_mnemonic( camera_menu, "Increase FOV", "FOVInc" );
 +              menu_separator( camera_menu );
                create_menu_item_with_mnemonic( camera_menu, "Next leak spot", "NextLeakSpot" );
                create_menu_item_with_mnemonic( camera_menu, "Previous leak spot", "PrevLeakSpot" );
                menu_separator( camera_menu );
@@@ -2412,7 -2333,7 +2414,7 @@@ ui::MenuItem create_help_menu()
  
        create_menu_item_with_mnemonic( menu, "Bug report", makeCallbackF(OpenBugReportURL) );
        create_menu_item_with_mnemonic( menu, "Shortcuts list", makeCallbackF(DoCommandListDlg) );
 -      create_menu_item_with_mnemonic( menu, "_About", makeCallbackF(DoAbout) );
 +      create_menu_item_with_mnemonic( menu, "_About...", makeCallbackF(DoAbout) );
  
        return help_menu_item;
  }
@@@ -2791,14 -2712,10 +2793,14 @@@ MainFrame::~MainFrame()
  
        for ( std::vector<ui::Widget>::iterator i = g_floating_windows.begin(); i != g_floating_windows.end(); ++i )
        {
 +#ifndef WORKAROUND_MACOS_GTK2_DESTROY
                i->destroy();
 +#endif
        }
  
 +#ifndef WORKAROUND_MACOS_GTK2_DESTROY
        m_window.destroy();
 +#endif
  }
  
  void MainFrame::SetActiveXY( XYWnd* p ){
@@@ -2955,16 -2872,13 +2957,16 @@@ WindowPositionTracker g_posXZWnd
  WindowPositionTracker g_posYZWnd;
  
  static gint mainframe_delete( ui::Widget widget, GdkEvent *event, gpointer data ){
 -      if ( ConfirmModified( "Exit Radiant" ) ) {
 +      if ( ConfirmModified( "Exit " RADIANT_NAME ) ) {
                gtk_main_quit();
        }
  
        return TRUE;
  }
  
 +PanedState g_single_hpaned = { 0.75f, -1, };
 +PanedState g_single_vpaned = { 0.75f, -1, };
 +
  void MainFrame::Create(){
        ui::Window window = ui::Window( ui::window_type::TOP );
  
  
        window.show();
  
 -      if ( CurrentStyle() == eRegular || CurrentStyle() == eRegularLeft ) {
 +      if ( CurrentStyle() == eRegular || CurrentStyle() == eRegularLeft )
 +      {
                {
                        ui::Widget hsplit = ui::HPaned(ui::New);
                        m_vSplit = hsplit;
                        vbox.pack_start( hsplit, TRUE, TRUE, 0 );
                        hsplit.show();
                        {
-                       ui::Widget vsplit = ui::VPaned(ui::New);
+                               ui::Widget vsplit = ui::VPaned(ui::New);
                                vsplit.show();
-                       m_vSplit = vsplit;
+                               m_vSplit = vsplit;
                                ui::Widget vsplit2 = ui::VPaned(ui::New);
                                vsplit2.show();
                                m_vSplit = vsplit2;
                                        gtk_paned_add1( GTK_PANED( hsplit ), vsplit2 );
                                }
  
-                       // console
-                       ui::Widget console_window = Console_constructWindow( window );
-                       gtk_paned_pack2( GTK_PANED( vsplit ), console_window, FALSE, TRUE );
+                               // console
+                               ui::Widget console_window = Console_constructWindow( window );
+                               gtk_paned_pack2( GTK_PANED( vsplit ), console_window, FALSE, TRUE );
+                               
                                // xy
                                m_pXYWnd = new XYWnd();
                                m_pXYWnd->SetViewType( XY );
  
                gtk_paned_set_position( GTK_PANED( m_vSplit2 ), g_layout_globals.nCamHeight );
        }
 -      else if ( CurrentStyle() == eFloating ) {
 +      else if ( CurrentStyle() == eFloating )
 +      {
                {
                        ui::Window window = ui::Window(create_persistent_floating_window( "Camera", m_window ));
                        global_accel_connect_window( window );
                        }
                        CamWnd_setParent( *m_pCamWnd, window );
  
 +                      WORKAROUND_GOBJECT_SET_GLWIDGET( window, CamWnd_getWidget( *m_pCamWnd ) );
 +
                        g_floating_windows.push_back( window );
                }
  
                        }
                        XY_Top_Shown_Construct( window );
  
 +                      WORKAROUND_GOBJECT_SET_GLWIDGET( window, m_pXYWnd->GetWidget() );
 +
                        g_floating_windows.push_back( window );
                }
  
  
                        XZ_Front_Shown_Construct( window );
  
 +                      WORKAROUND_GOBJECT_SET_GLWIDGET( window, m_pXZWnd->GetWidget() );
 +
                        g_floating_windows.push_back( window );
                }
  
  
                        YZ_Side_Shown_Construct( window );
  
 +                      WORKAROUND_GOBJECT_SET_GLWIDGET( window, m_pYZWnd->GetWidget() );
 +
                        g_floating_windows.push_back( window );
                }
  
                {
                        auto frame = create_framed_widget( TextureBrowser_constructWindow( GroupDialog_getWindow() ) );
                        g_page_textures = GroupDialog_addPage( "Textures", frame, TextureBrowserExportTitleCaller() );
 +
 +                      WORKAROUND_GOBJECT_SET_GLWIDGET( GroupDialog_getWindow(), TextureBrowser_getGLWidget() );
                }
  
                GroupDialog_show();
        }
 -      else // 4 way
 +      else if ( CurrentStyle() == eSplit )
        {
                m_pCamWnd = NewCamWnd();
                GlobalCamera_setCamWnd( *m_pCamWnd );
                {
              auto frame = create_framed_widget( TextureBrowser_constructWindow( window ) );
                        g_page_textures = GroupDialog_addPage( "Textures", frame, TextureBrowserExportTitleCaller() );
 +
 +                      WORKAROUND_GOBJECT_SET_GLWIDGET( window, TextureBrowser_getGLWidget() );
                }
        }
 +      else // single window
 +      {
 +              m_pCamWnd = NewCamWnd();
 +              GlobalCamera_setCamWnd( *m_pCamWnd );
 +              CamWnd_setParent( *m_pCamWnd, window );
 +
 +              ui::Widget camera = CamWnd_getWidget( *m_pCamWnd );
 +
 +              m_pYZWnd = new XYWnd();
 +              m_pYZWnd->SetViewType( YZ );
 +
 +              ui::Widget yz = m_pYZWnd->GetWidget();
 +
 +              m_pXYWnd = new XYWnd();
 +              m_pXYWnd->SetViewType( XY );
 +
 +              ui::Widget xy = m_pXYWnd->GetWidget();
 +
 +              m_pXZWnd = new XYWnd();
 +              m_pXZWnd->SetViewType( XZ );
 +
 +              ui::Widget xz = m_pXZWnd->GetWidget();
 +
 +              ui::Widget hsplit = ui::HPaned(ui::New);
 +              vbox.pack_start( hsplit, TRUE, TRUE, 0 );
 +              hsplit.show();
 +
 +              ui::Widget split = create_split_views( camera, yz, xy, xz );
 +
 +              ui::Widget vsplit = ui::VPaned(ui::New);
 +              vsplit.show();
 +
 +              // textures
 +              ui::Widget texture_window = create_framed_widget( TextureBrowser_constructWindow( window ) );
 +
 +              // console
 +              ui::Widget console_window = create_framed_widget( Console_constructWindow( window ) );
 +
 +              gtk_paned_add1( GTK_PANED( hsplit ), split );
 +              gtk_paned_add2( GTK_PANED( hsplit ), vsplit );
 +
 +              gtk_paned_add1( GTK_PANED( vsplit ), texture_window  );
 +              gtk_paned_add2( GTK_PANED( vsplit ), console_window  );
 +
 +              hsplit.connect( "size_allocate", G_CALLBACK( hpaned_allocate ), &g_single_hpaned );
 +              hsplit.connect( "notify::position", G_CALLBACK( paned_position ), &g_single_hpaned );
 +
 +              vsplit.connect( "size_allocate", G_CALLBACK( vpaned_allocate ), &g_single_vpaned );
 +              vsplit.connect( "notify::position", G_CALLBACK( paned_position ), &g_single_vpaned );
 +      }
  
        EntityList_constructWindow( window );
        PreferencesDialog_constructWindow( window );
@@@ -3407,7 -3257,7 +3409,7 @@@ void MainFrame::SetStatusText( CopiedSt
  }
  
  void Sys_Status( const char* status ){
 -      if ( g_pParentWnd != 0 ) {
 +      if ( g_pParentWnd != nullptr ) {
                g_pParentWnd->SetStatusText( g_pParentWnd->m_command_status, status );
        }
  }
@@@ -3439,7 -3289,7 +3441,7 @@@ void MainFrame::SetGridStatus()
  }
  
  void GridStatus_onTextureLockEnabledChanged(){
 -      if ( g_pParentWnd != 0 ) {
 +      if ( g_pParentWnd != nullptr ) {
                g_pParentWnd->SetGridStatus();
        }
  }
@@@ -3484,7 -3334,7 +3486,7 @@@ void GlobalGL_sharedContextDestroyed()
  
  void Layout_constructPreferences( PreferencesPage& page ){
        {
 -              const char* layouts[] = { "window1.png", "window2.png", "window3.png", "window4.png" };
 +              const char* layouts[] = { "window1.png", "window2.png", "window3.png", "window4.png", "window5.png" };
                page.appendRadioIcons(
                        "Window Layout",
                        STRING_ARRAY_RANGE( layouts ),
@@@ -3520,9 -3370,9 +3522,9 @@@ void Layout_registerPreferencesPage()
        PreferencesDialog_addInterfacePage( makeCallbackF(Layout_constructPage) );
  }
  
 -
  #include "preferencesystem.h"
  #include "stringio.h"
 +#include "transformpath/transformpath.h"
  
  void MainFrame_Construct(){
        GlobalCommands_insert( "OpenManual", makeCallbackF(OpenHelpURL), Accelerator( GDK_KEY_F1 ) );
        GlobalCommands_insert( "ColorSchemeQER", makeCallbackF(ColorScheme_QER) );
        GlobalCommands_insert( "ColorSchemeBlackAndGreen", makeCallbackF(ColorScheme_Black) );
        GlobalCommands_insert( "ColorSchemeYdnar", makeCallbackF(ColorScheme_Ydnar) );
 +      GlobalCommands_insert("ColorSchemeAdwaitaDark", makeCallbackF(ColorScheme_AdwaitaDark));
        GlobalCommands_insert( "ChooseTextureBackgroundColor", makeCallback( g_ColoursMenu.m_textureback ) );
        GlobalCommands_insert( "ChooseGridBackgroundColor", makeCallback( g_ColoursMenu.m_xyback ) );
        GlobalCommands_insert( "ChooseGridMajorColor", makeCallback( g_ColoursMenu.m_gridmajor ) );
        GlobalPreferenceSystem().registerPreference( "YZWnd", make_property<WindowPositionTracker_String>(g_posYZWnd) );
        GlobalPreferenceSystem().registerPreference( "XZWnd", make_property<WindowPositionTracker_String>(g_posXZWnd) );
  
+       GlobalPreferenceSystem().registerPreference( "EnginePath", make_property_string( g_strEnginePath ) );
+       if ( g_strEnginePath.empty() )
        {
+               g_strEnginePath_was_empty_1st_start = true;
                const char* ENGINEPATH_ATTRIBUTE =
  #if GDEF_OS_WINDOWS
                        "enginepath_win32"
  #error "unknown platform"
  #endif
                ;
 +
                StringOutputStream path( 256 );
                path << DirectoryCleaned( g_pGameDescription->getRequiredKeyValue( ENGINEPATH_ATTRIBUTE ) );
 -              g_strEnginePath = path.c_str();
 +
 +              g_strEnginePath = transformPath( path.c_str() ).c_str();
+               GlobalPreferenceSystem().registerPreference( "EnginePath", make_property_string( g_strEnginePath ) );
        }
  
-       GlobalPreferenceSystem().registerPreference( "EnginePath", make_property_string( g_strEnginePath ) );
        GlobalPreferenceSystem().registerPreference( "DisableEnginePath", make_property_string( g_disableEnginePath ) );
        GlobalPreferenceSystem().registerPreference( "DisableHomePath", make_property_string( g_disableHomePath ) );
  
        g_entityCount.setCountChangedCallback( makeCallbackF(QE_entityCountChanged) );
        GlobalEntityCreator().setCounter( &g_entityCount );
  
 -      GLWidget_sharedContextCreated = GlobalGL_sharedContextCreated;
 -      GLWidget_sharedContextDestroyed = GlobalGL_sharedContextDestroyed;
 +      glwidget_set_shared_context_constructors( GlobalGL_sharedContextCreated, GlobalGL_sharedContextDestroyed);
  
        GlobalEntityClassManager().attach( g_WorldspawnColourEntityClassObserver );
  }
@@@ -3730,61 -3580,3 +3734,61 @@@ void GLWindow_Construct()
  
  void GLWindow_Destroy(){
  }
 +
 +/* HACK: If ui::main is not called yet,
 +gtk_main_quit will not quit, so tell main
 +to not call ui::main. This happens when a
 +map is loaded from command line and require
 +a restart because of wrong format.
 +Delete this when the code to not have to
 +restart to load another format is merged. */
 +extern bool g_dontStart;
 +
 +void Radiant_Restart(){
 +      // preferences are expected to be already saved in any way
 +      // this is just to be sure and be future proof
 +      Preferences_Save();
 +
 +      // this asks user for saving if map is modified
 +      // user can chose to not save, it's ok
 +      ConfirmModified( "Restart " RADIANT_NAME );
 +
 +      int status;
 +
 +      char *argv[ 3 ];
 +      char exe_file[ 256 ];
 +      char map_file[ 256 ];
 +      bool with_map = false;
 +
 +      strncpy( exe_file, g_strAppFilePath.c_str(), 256 );
 +
 +      if ( !Map_Unnamed( g_map ) ) {
 +              strncpy( map_file, Map_Name( g_map ), 256 );
 +              with_map = true;
 +      }
 +
 +      argv[ 0 ] = exe_file;
 +      argv[ 1 ] = with_map ? map_file : NULL;
 +      argv[ 2 ] = NULL;
 +
 +#if GDEF_OS_WINDOWS
 +      status = !_spawnvpe( P_NOWAIT, exe_file, argv, environ );
 +#else
 +      pid_t pid;
 +
 +      status = posix_spawn( &pid, exe_file, NULL, NULL, argv, environ );
 +#endif
 +
 +      // quit if radiant successfully started
 +      if ( status == 0 ) {
 +              gtk_main_quit();
 +              /* HACK: If ui::main is not called yet,
 +              gtk_main_quit will not quit, so tell main
 +              to not call ui::main. This happens when a
 +              map is loaded from command line and require
 +              a restart because of wrong format.
 +              Delete this when the code to not have to
 +              restart to load another format is merged. */
 +              g_dontStart = true;
 +      }
 +}
diff --combined radiant/map.cpp
index a5ac53f899e63e2a27e863482a12091851efd4ce,a192231e30e63b02a911a9dd8af3d19425087cb7..b8c727ba3d8e87bf6f6b833013fca1b10f099a2b
@@@ -966,8 -966,6 +966,8 @@@ void Map_LoadFile( const char *filenam
        MRU_AddFile( filename );
        g_strLastMapFolder = g_path_get_dirname( filename );
  
 +      bool switch_format = false;
 +
        {
                ScopeTimer timer( "map load" );
  
                                if ( !format->wrongFormat ) {
                                        break;
                                }
 +                              switch_format = !switch_format;
                        }
                }
  
        Map_StartPosition();
  
        g_currentMap = &g_map;
 +
 +      Brush_switchFormat( switch_format );
  }
  
  class Excluder
@@@ -1583,55 -1578,54 +1583,55 @@@ tryDecompile
        const char *type = GlobalRadiant().getGameDescriptionKeyValue( "q3map2_type" );
        int n = string_length( path_get_extension( filename ) );
        if ( n && ( extension_equal( path_get_extension( filename ), "bsp" ) || extension_equal( path_get_extension( filename ), "map" ) ) ) {
 -              StringBuffer output;
 -              output.push_string( AppPath_get() );
 -              output.push_string( "q3map2." );
 -              output.push_string( RADIANT_EXECUTABLE );
 -              output.push_string( " -v -game " );
 -              output.push_string( ( type && *type ) ? type : "quake3" );
 -              output.push_string( " -fs_basepath \"" );
 -              output.push_string( EnginePath_get() );
 -              output.push_string( "\" -fs_homepath \"" );
 -              output.push_string( g_qeglobals.m_userEnginePath.c_str() );
 -              output.push_string( "\"" );
 +              std::string output;
 +              output += AppPath_get();
 +              output += "q3map2";
 +              output += GDEF_OS_EXE_EXT;
 +
 +              output += " -v -game ";
 +              output += ( type && *type ) ? type : "quake3";
 +              output += " -fs_basepath \"";
 +              output += EnginePath_get();
 +              output += "\" -fs_homepath \"";
 +              output += g_qeglobals.m_userEnginePath.c_str();
 +              output += "\"";
  
                // extra pakpaths
                for ( int i = 0; i < g_pakPathCount; i++ ) {
                        if ( g_strcmp0( g_strPakPath[i].c_str(), "") ) {
 -                              output.push_string( " -fs_pakpath \"" );
 -                              output.push_string( g_strPakPath[i].c_str() );
 -                              output.push_string( "\"" );
 +                              output += " -fs_pakpath \"";
 +                              output += g_strPakPath[i].c_str();
 +                              output += "\"";
                        }
                }
  
                // extra switches
                if ( g_disableEnginePath ) {
 -                      output.push_string( " -fs_nobasepath " );
 +                      output += " -fs_nobasepath ";
                }
  
                if ( g_disableHomePath ) {
 -                      output.push_string( " -fs_nohomepath " );
 +                      output += " -fs_nohomepath ";
                }
  
 -              output.push_string( " -fs_game " );
 -              output.push_string( gamename_get() );
 -              output.push_string( " -convert -format " );
 -              output.push_string( Brush::m_type == eBrushTypeQuake3BP ? "map_bp" : "map" );
 +              output += " -fs_game ";
 +              output += gamename_get();
 +              output += " -convert -format ";
 +              output += Brush::m_type == eBrushTypeQuake3BP ? "map_bp" : "map";
                if ( extension_equal( path_get_extension( filename ), "map" ) ) {
 -                      output.push_string( " -readmap " );
 +                      output += " -readmap ";
                }
 -              output.push_string( " \"" );
 -              output.push_string( filename );
 -              output.push_string( "\"" );
 +              output += " \"";
 +              output += filename;
 +              output += "\"";
  
                // run
                Q_Exec( NULL, output.c_str(), NULL, false, true );
  
                // rebuild filename as "filenamewithoutext_converted.map"
 -              output.clear();
 -              output.push_range( filename, filename + string_length( filename ) - ( n + 1 ) );
 -              output.push_string( "_converted.map" );
 +              output = "";
 +              output.append( filename, string_length( filename ) - ( n + 1 ) );
 +              output += "_converted.map";
                filename = output.c_str();
  
                // open
@@@ -1681,21 -1675,19 +1681,19 @@@ bool Map_SaveSelected( const char* file
        return MapResource_saveFile( MapFormat_forFile( filename ), GlobalSceneGraph().root(), Map_Traverse_Selected, filename );
  }
  
  class ParentSelectedBrushesToEntityWalker : public scene::Graph::Walker
  {
- scene::Node& m_parent;
+       scene::Node& m_parent;
+       mutable bool m_emptyOldParent;
  public:
- ParentSelectedBrushesToEntityWalker( scene::Node& parent ) : m_parent( parent ){
+ ParentSelectedBrushesToEntityWalker( scene::Node& parent ) : m_parent( parent ), m_emptyOldParent( false ){
  }
  
  bool pre( const scene::Path& path, scene::Instance& instance ) const {
-       if ( path.top().get_pointer() != &m_parent
-                && Node_isPrimitive( path.top() ) ) {
+       if ( path.top().get_pointer() != &m_parent && ( Node_isPrimitive( path.top() ) || m_emptyOldParent ) ) {
                Selectable* selectable = Instance_getSelectable( instance );
-               if ( selectable != 0
-                        && selectable->isSelected()
-                        && path.size() > 1 ) {
+               if ( selectable && selectable->isSelected() && path.size() > 1 ) {
                        return false;
                }
        }
  }
  
  void post( const scene::Path& path, scene::Instance& instance ) const {
-       if ( path.top().get_pointer() != &m_parent
-                && Node_isPrimitive( path.top() ) ) {
+       if ( path.top().get_pointer() == &m_parent )
+               return;
+       if ( Node_isPrimitive( path.top() ) ){
+               m_emptyOldParent = false;
                Selectable* selectable = Instance_getSelectable( instance );
-               if ( selectable != 0
-                        && selectable->isSelected()
-                        && path.size() > 1 ) {
+               if ( selectable && selectable->isSelected() && path.size() > 1 ){
                        scene::Node& parent = path.parent();
-                       if ( &parent != &m_parent ) {
+                       if ( &parent != &m_parent ){
                                NodeSmartReference node( path.top().get() );
-                               Node_getTraversable( parent )->erase( node );
+                               scene::Traversable* traversable_parent = Node_getTraversable( parent );
+                               traversable_parent->erase( node );
                                Node_getTraversable( m_parent )->insert( node );
+                               if ( traversable_parent->empty() )
+                                       m_emptyOldParent = true;
                        }
                }
        }
+       else if ( m_emptyOldParent ){
+               m_emptyOldParent = false;
+               // delete empty entities
+               Entity* entity = Node_getEntity( path.top() );
+               if ( entity != 0 && path.top().get_pointer() != Map_FindWorldspawn( g_map )     && Node_getTraversable( path.top() )->empty() ) {
+                       Path_deleteTop( path );
+               }
+       }
  }
  };
  
diff --combined radiant/texwindow.cpp
index 6640b97e7b04b873fb8d9ece04b4df78f5e9aca8,2b4ad1843dce5bd505e1653fe074a85936775a9e..edfe4bc7562ee7e96501b38a3321f629bd0c99ff
@@@ -101,7 -101,12 +101,7 @@@ typedef std::set<CopiedString> TextureG
  
  void TextureGroups_addWad( TextureGroups& groups, const char* archive ){
        if ( extension_equal( path_get_extension( archive ), "wad" ) ) {
 -#if 1
                groups.insert( archive );
 -#else
 -              CopiedString archiveBaseName( path_get_filename_start( archive ), path_get_filename_base_end( archive ) );
 -              groups.insert( archiveBaseName );
 -#endif
        }
  }
  
@@@ -267,14 -272,6 +267,14 @@@ int m_nTotalHeight
  CopiedString shader;
  
  ui::Window m_parent{ui::null};
 +#ifdef WORKAROUND_MACOS_GTK2_GLWIDGET
 +ui::VBox m_vframe{ui::null};
 +ui::VBox m_vfiller{ui::null};
 +ui::HBox m_hframe{ui::null};
 +ui::HBox m_hfiller{ui::null};
 +#else // !WORKAROUND_MACOS_GTK2_GLWIDGET
 +ui::VBox m_frame{ui::null};
 +#endif // !WORKAROUND_MACOS_GTK2_GLWIDGET
  ui::GLArea m_gl_widget{ui::null};
  ui::Widget m_texture_scroll{ui::null};
  ui::TreeView m_treeViewTree{ui::New};
@@@ -347,11 -344,11 +347,11 @@@ int m_uniformTextureMinSize
                else if ( tex->width <= m_uniformTextureMinSize ){
                        *width = m_uniformTextureMinSize;
                        *height = (int)( m_uniformTextureMinSize * ( (float)tex->height / tex->width ) );
-       }
-       else {
+               }
+               else {
                        *width = tex->width;
                        *height = tex->height;
-       }
+               }
        }
        else {
                // Texture taller than it is wide
  }
  
  */
- void getTextureWH( qtexture_t* tex, int *width, int *height ){
+ void getTextureWH( qtexture_t* tex, int &W, int &H ){
                // Don't use uniform size
-               *width = (int)( tex->width * ( (float)m_textureScale / 100 ) );
-               *height = (int)( tex->height * ( (float)m_textureScale / 100 ) );
+               W = (int)( tex->width * ( (float)m_textureScale / 100 ) );
+               H = (int)( tex->height * ( (float)m_textureScale / 100 ) );
  
        if ( g_TextureBrowser_fixedSize ){
-               int W = *width;
-               int H = *height;
                if      ( W >= H ) {
                        // Texture is square, or wider than it is tall
                        if ( W >= m_uniformTextureSize ){
-                               *width = m_uniformTextureSize;
-                               *height = m_uniformTextureSize * H / W;
-       }
+                               H = m_uniformTextureSize * H / W;
+                               W = m_uniformTextureSize;
+                       }
                        else if ( W <= m_uniformTextureMinSize ){
-                               *width = m_uniformTextureMinSize;
-                               *height = m_uniformTextureMinSize * H / W;
+                               H = m_uniformTextureMinSize * H / W;
+                               W = m_uniformTextureMinSize;
                        }
-       }
-       else {
+               }
+               else {
                        // Texture taller than it is wide
                        if ( H >= m_uniformTextureSize ){
-                               *height = m_uniformTextureSize;
-                               *width = m_uniformTextureSize * W / H;
-       }
+                               W = m_uniformTextureSize * W / H;
+                               H = m_uniformTextureSize;
+                       }
                        else if ( H <= m_uniformTextureMinSize ){
-                               *height = m_uniformTextureMinSize;
-                               *width = m_uniformTextureMinSize * W / H;
+                               W = m_uniformTextureMinSize * W / H;
+                               H = m_uniformTextureMinSize;
                        }
                }
        }
@@@ -437,7 -432,7 +435,7 @@@ void ( *TextureBrowser_textureSelected 
  void TextureBrowser_updateScroll( TextureBrowser& textureBrowser );
  
  
 -const char* TextureBrowser_getComonShadersName(){
 +const char* TextureBrowser_getCommonShadersName(){
        const char* value = g_pGameDescription->getKeyValue( "common_shaders_name" );
        if ( !string_empty( value ) ) {
                return value;
        return "Common";
  }
  
 -const char* TextureBrowser_getComonShadersDir(){
 +const char* TextureBrowser_getCommonShadersDir(){
        const char* value = g_pGameDescription->getKeyValue( "common_shaders_dir" );
        if ( !string_empty( value ) ) {
                return value;
@@@ -529,7 -524,7 +527,7 @@@ void Texture_NextPos( TextureBrowser& t
        qtexture_t* q = current_texture;
  
        int nWidth, nHeight;
-       textureBrowser.getTextureWH( q, &nWidth, &nHeight );
+       textureBrowser.getTextureWH( q, nWidth, nHeight );
        if ( layout.current_x + nWidth > textureBrowser.width - 8 && layout.current_row ) { // go to the next row unless the texture is the first on the row
                layout.current_x = 8;
                layout.current_y -= layout.current_row + TextureBrowser_fontHeight( textureBrowser ) + 4;
@@@ -617,15 -612,7 +615,15 @@@ bool Texture_IsShown( IShader* shader, 
                }
        }
        else {
 -              if ( !shader_equal_prefix( shader_get_textureName( shader->getName() ), g_TextureBrowser_currentDirectory.c_str() ) ) {
 +              if ( TextureBrowser_showWads() )
 +              {
 +                      if ( g_TextureBrowser_currentDirectory != ""
 +                              && !string_equal( shader->getWadName(), g_TextureBrowser_currentDirectory.c_str() ) )
 +                      {
 +                              return false;
 +                      }
 +              }
 +              else if ( !shader_equal_prefix( shader_get_textureName( shader->getName() ), g_TextureBrowser_currentDirectory.c_str() ) ) {
                        return false;
                }
        }
@@@ -659,7 -646,7 +657,7 @@@ void TextureBrowser_evaluateHeight( Tex
                        int x, y;
                        Texture_NextPos( textureBrowser, layout, shader->getTexture(), &x, &y );
                        int nWidth, nHeight;
-                       textureBrowser.getTextureWH( shader->getTexture(), &nWidth, &nHeight );
+                       textureBrowser.getTextureWH( shader->getTexture(), nWidth, nHeight );
                        textureBrowser.m_nTotalHeight = std::max( textureBrowser.m_nTotalHeight, abs( layout.current_y ) + TextureBrowser_fontHeight( textureBrowser ) + nHeight + 4 );
                }
        }
@@@ -822,7 -809,6 +820,7 @@@ public
  void visit( const char* name ){
        IShader* shader = QERApp_Shader_ForName( CopiedString( StringRange( name, path_get_filename_base_end( name ) ) ).c_str() );
        shader->DecRef();
 +      shader->setWadName( g_TextureBrowser_currentDirectory.c_str() );
  }
  };
  
@@@ -865,14 -851,6 +863,14 @@@ void operator()( const char* name ) con
  };
  
  void TextureDirectory_loadTexture( const char* directory, const char* texture ){
 +      // Doom3-like dds/ prefix (used by DarkPlaces).
 +      // When we list dds/textures/ folder,
 +      // store the texture names without dds/ prefix.
 +      if ( !strncmp( "dds/", directory, 4 ) )
 +      {
 +              directory = &directory[ 4 ];
 +      }
 +
        StringOutputStream name( 256 );
        name << directory << StringRange( texture, path_get_filename_base_end( texture ) );
  
@@@ -907,22 -885,10 +905,22 @@@ void visit( const char* minor, const _Q
  
  void TextureBrowser_ShowDirectory( TextureBrowser& textureBrowser, const char* directory ){
        if ( TextureBrowser_showWads() ) {
 +              g_TextureBrowser_currentDirectory = directory;
 +              TextureBrowser_heightChanged( textureBrowser );
 +
                Archive* archive = GlobalFileSystem().getArchive( directory );
 -              ASSERT_NOTNULL( archive );
 +              if ( archive != nullptr )
 +              {
                LoadShaderVisitor visitor;
                archive->forEachFile( Archive::VisitorFunc( visitor, Archive::eFiles, 0 ), "textures/" );
 +
 +                      // Doom3-like dds/ prefix (used by DarkPlaces).
 +                      archive->forEachFile( Archive::VisitorFunc( visitor, Archive::eFiles, 0 ), "dds/textures/" );
 +              }
 +              else if ( extension_equal_i( path_get_extension( directory ), "wad" ) )
 +              {
 +                      globalErrorStream() << "Failed to load " << directory << "\n";
 +              }
        }
        else
        {
                        StringOutputStream dirstring( 64 );
                        dirstring << "textures/" << directory;
  
 -                      Radiant_getImageModules().foreachModule( LoadTexturesByTypeVisitor( dirstring.c_str() ) );
 +                      {
 +                              LoadTexturesByTypeVisitor visitor( dirstring.c_str() );
 +                              Radiant_getImageModules().foreachModule( visitor );
 +                      }
 +
 +                      // Doom3-like dds/ prefix (used by DarkPlaces).
 +                      dirstring.clear();
 +                      dirstring << "dds/textures/" << directory;
 +
 +                      {
 +                              LoadTexturesByTypeVisitor visitor( dirstring.c_str() );
 +                              Radiant_getImageModules().foreachModule( visitor );
 +                      }
                }
        }
  
@@@ -978,15 -932,6 +976,15 @@@ void TextureBrowser_ShowTagSearchResult
                        LoadTexturesByTypeVisitor visitor( dirstring.c_str() );
                        Radiant_getImageModules().foreachModule( visitor );
                }
 +
 +              // Doom3-like dds/ prefix (used by DarkPlaces).
 +              dirstring.clear();
 +              dirstring << "dds/textures/" << directory;
 +
 +              {
 +                      LoadTexturesByTypeVisitor visitor( dirstring.c_str() );
 +                      Radiant_getImageModules().foreachModule( visitor );
 +              }
        }
  
        // we'll display the newly loaded textures + all the ones already in use
@@@ -1055,7 -1000,7 +1053,7 @@@ void TextureBrowser_SetHideUnused( Text
  
  void TextureBrowser_ShowStartupShaders( TextureBrowser& textureBrowser ){
        if ( textureBrowser.m_startupShaders == STARTUPSHADERS_COMMON ) {
 -              TextureBrowser_ShowDirectory( textureBrowser, TextureBrowser_getComonShadersDir() );
 +              TextureBrowser_ShowDirectory( textureBrowser, TextureBrowser_getCommonShadersDir() );
        }
  }
  
@@@ -1126,7 -1071,7 +1124,7 @@@ IShader* Texture_At( TextureBrowser& te
                }
  
                int nWidth, nHeight;
-               textureBrowser.getTextureWH( q, &nWidth, &nHeight );
+               textureBrowser.getTextureWH( q, nWidth, nHeight );
                if ( mx > x && mx - x < nWidth
                         && my < y && y - my < nHeight + TextureBrowser_fontHeight( textureBrowser ) ) {
                        return shader;
@@@ -1191,11 -1136,11 +1189,11 @@@ void TextureBrowser_trackingDelta( int 
  }
  
  void TextureBrowser_Tracking_MouseDown( TextureBrowser& textureBrowser ){
 -      textureBrowser.m_freezePointer.freeze_pointer( textureBrowser.m_parent, TextureBrowser_trackingDelta, &textureBrowser );
 +      textureBrowser.m_freezePointer.freeze_pointer( textureBrowser.m_gl_widget, TextureBrowser_trackingDelta, &textureBrowser );
  }
  
  void TextureBrowser_Tracking_MouseUp( TextureBrowser& textureBrowser ){
 -      textureBrowser.m_freezePointer.unfreeze_pointer( textureBrowser.m_parent );
 +      textureBrowser.m_freezePointer.unfreeze_pointer( textureBrowser.m_gl_widget );
  }
  
  void TextureBrowser_Selection_MouseDown( TextureBrowser& textureBrowser, guint32 flags, int pointx, int pointy ){
@@@ -1225,7 -1170,6 +1223,7 @@@ void Texture_Draw( TextureBrowser& text
                                  textureBrowser.color_textureback[1],
                                  textureBrowser.color_textureback[2],
                                  0 );
 +
        glViewport( 0, 0, textureBrowser.width, textureBrowser.height );
        glMatrixMode( GL_PROJECTION );
        glLoadIdentity();
                }
  
                int nWidth, nHeight;
-               textureBrowser.getTextureWH( q, &nWidth, &nHeight );
+               textureBrowser.getTextureWH( q, nWidth, nHeight );
  
                if ( y != last_y ) {
                        last_y = y;
@@@ -1504,7 -1448,7 +1502,7 @@@ void BuildStoreAvailableTags(   ui::Lis
  gboolean TextureBrowser_button_press( ui::Widget widget, GdkEventButton* event, TextureBrowser* textureBrowser ){
        if ( event->type == GDK_BUTTON_PRESS ) {
                if ( event->button == 3 ) {
 -                      if ( GlobalTextureBrowser().m_tags ) {
 +                      if ( textureBrowser->m_tags ) {
                                textureBrowser->m_rmbSelected = true;
                                TextureBrowser_Selection_MouseDown( *textureBrowser, event->state, static_cast<int>( event->x ), static_cast<int>( event->y ) );
  
                else if ( event->button == 1 ) {
                        TextureBrowser_Selection_MouseDown( *textureBrowser, event->state, static_cast<int>( event->x ), static_cast<int>( event->y ) );
  
 -                      if ( GlobalTextureBrowser().m_tags ) {
 +                      if ( textureBrowser->m_tags ) {
                                textureBrowser->m_rmbSelected = false;
                                textureBrowser->m_tag_frame.hide();
                        }
  gboolean TextureBrowser_button_release( ui::Widget widget, GdkEventButton* event, TextureBrowser* textureBrowser ){
        if ( event->type == GDK_BUTTON_RELEASE ) {
                if ( event->button == 3 ) {
 -                      if ( !GlobalTextureBrowser().m_tags ) {
 +                      if ( !textureBrowser->m_tags ) {
                                TextureBrowser_Tracking_MouseUp( *textureBrowser );
                        }
                }
@@@ -1596,7 -1540,7 +1594,7 @@@ gboolean TextureBrowser_size_allocate( 
        return FALSE;
  }
  
 -gboolean TextureBrowser_expose( ui::Widget widget, GdkEventExpose* event, TextureBrowser* textureBrowser ){
 +void TextureBrowser_redraw( TextureBrowser* textureBrowser ){
        if ( glwidget_make_current( textureBrowser->m_gl_widget ) != FALSE ) {
                GlobalOpenGL_debugAssertNoErrors();
                TextureBrowser_evaluateHeight( *textureBrowser );
                GlobalOpenGL_debugAssertNoErrors();
                glwidget_swap_buffers( textureBrowser->m_gl_widget );
        }
 -      return FALSE;
  }
  
 -
 -TextureBrowser g_TextureBrowser;
 +gboolean TextureBrowser_expose( ui::Widget widget, GdkEventExpose* event, TextureBrowser* textureBrowser ){
 +      TextureBrowser_redraw( textureBrowser );
 +      return FALSE;
 +}
  
  TextureBrowser& GlobalTextureBrowser(){
 -      return g_TextureBrowser;
 +      static TextureBrowser textureBrowser;
 +      return textureBrowser;
  }
  
  bool TextureBrowser_hideUnused(){
 -      return g_TextureBrowser.m_hideUnused;
 +      return GlobalTextureBrowser().m_hideUnused;
  }
  
  void TextureBrowser_ToggleHideUnused(){
 -      if ( g_TextureBrowser.m_hideUnused ) {
 -              TextureBrowser_SetHideUnused( g_TextureBrowser, false );
 +      TextureBrowser &textureBrowser = GlobalTextureBrowser();
 +      if ( textureBrowser.m_hideUnused ) {
 +              TextureBrowser_SetHideUnused( textureBrowser, false );
        }
        else
        {
 -              TextureBrowser_SetHideUnused( g_TextureBrowser, true );
 +              TextureBrowser_SetHideUnused( textureBrowser, true );
 +      }
 +}
 +
 +const char* TextureGroups_transformDirName( const char* dirName, StringOutputStream *archiveName )
 +{
 +      if ( TextureBrowser_showWads() ) {
 +              archiveName->clear();
 +              *archiveName << StringRange( path_get_filename_start( dirName ), path_get_filename_base_end( dirName ) ) \
 +                      << "." << path_get_extension( dirName );
 +              return archiveName->c_str();
        }
 +      return dirName;
  }
  
  void TextureGroups_constructTreeModel( TextureGroups groups, ui::TreeStore store ){
        TextureGroups::const_iterator i = groups.begin();
        while ( i != groups.end() )
        {
 -              const char* dirName = ( *i ).c_str();
 +              StringOutputStream archiveName;
 +              StringOutputStream nextArchiveName;
 +              const char* dirName = TextureGroups_transformDirName( ( *i ).c_str(), &archiveName );
 +
                const char* firstUnderscore = strchr( dirName, '_' );
                StringRange dirRoot( dirName, ( firstUnderscore == 0 ) ? dirName : firstUnderscore + 1 );
  
                TextureGroups::const_iterator next = i;
                ++next;
 +
                if ( firstUnderscore != 0
                         && next != groups.end()
 -                       && string_equal_start( ( *next ).c_str(), dirRoot ) ) {
 +                       && string_equal_start( TextureGroups_transformDirName( ( *next ).c_str(), &nextArchiveName ), dirRoot ) ) {
                        gtk_tree_store_append( store, &iter, NULL );
                        gtk_tree_store_set( store, &iter, 0, CopiedString( StringRange( dirName, firstUnderscore ) ).c_str(), -1 );
  
                        // keep going...
 -                      while ( i != groups.end() && string_equal_start( ( *i ).c_str(), dirRoot ) )
 +                      while ( i != groups.end() && string_equal_start( TextureGroups_transformDirName( ( *i ).c_str(), &nextArchiveName ), dirRoot ) )
                        {
                                gtk_tree_store_append( store, &child, &iter );
 -                              gtk_tree_store_set( store, &child, 0, ( *i ).c_str(), -1 );
 +                              gtk_tree_store_set( store, &child, 0, TextureGroups_transformDirName( ( *i ).c_str(), &nextArchiveName ), -1 );
                                ++i;
                        }
                }
@@@ -1706,18 -1632,17 +1704,18 @@@ void TextureBrowser_constructTreeStore(
        auto store = ui::TreeStore::from(gtk_tree_store_new( 1, G_TYPE_STRING ));
        TextureGroups_constructTreeModel( groups, store );
  
 -      gtk_tree_view_set_model(g_TextureBrowser.m_treeViewTree, store);
 +      gtk_tree_view_set_model(GlobalTextureBrowser().m_treeViewTree, store);
  
        g_object_unref( G_OBJECT( store ) );
  }
  
  void TextureBrowser_constructTreeStoreTags(){
        TextureGroups groups;
 +      TextureBrowser &textureBrowser = GlobalTextureBrowser();
        auto store = ui::TreeStore::from(gtk_tree_store_new( 1, G_TYPE_STRING ));
 -    auto model = g_TextureBrowser.m_all_tags_list;
 +      auto model = GlobalTextureBrowser().m_all_tags_list;
  
 -      gtk_tree_view_set_model(g_TextureBrowser.m_treeViewTags, model );
 +      gtk_tree_view_set_model(GlobalTextureBrowser().m_treeViewTags, model );
  
        g_object_unref( G_OBJECT( store ) );
  }
@@@ -1735,7 -1660,7 +1733,7 @@@ void TreeView_onRowActivated( ui::TreeV
                strcpy( dirName, buffer );
                g_free( buffer );
  
 -              g_TextureBrowser.m_searchedTags = false;
 +              GlobalTextureBrowser().m_searchedTags = false;
  
                if ( !TextureBrowser_showWads() ) {
                        strcat( dirName, "/" );
  }
  
  void TextureBrowser_createTreeViewTree(){
 -      gtk_tree_view_set_enable_search(g_TextureBrowser.m_treeViewTree, FALSE );
 +      TextureBrowser &textureBrowser = GlobalTextureBrowser();
 +      gtk_tree_view_set_enable_search(textureBrowser.m_treeViewTree, FALSE );
  
 -      gtk_tree_view_set_headers_visible(g_TextureBrowser.m_treeViewTree, FALSE );
 -      g_TextureBrowser.m_treeViewTree.connect( "row-activated", (GCallback) TreeView_onRowActivated, NULL );
 +      gtk_tree_view_set_headers_visible(textureBrowser.m_treeViewTree, FALSE );
 +      textureBrowser.m_treeViewTree.connect( "row-activated", (GCallback) TreeView_onRowActivated, NULL );
  
        auto renderer = ui::CellRendererText(ui::New);
 -      gtk_tree_view_insert_column_with_attributes(g_TextureBrowser.m_treeViewTree, -1, "", renderer, "text", 0, NULL );
 +      gtk_tree_view_insert_column_with_attributes(textureBrowser.m_treeViewTree, -1, "", renderer, "text", 0, NULL );
  
        TextureBrowser_constructTreeStore();
  }
@@@ -1808,22 -1732,20 +1806,22 @@@ gboolean TreeViewTags_onButtonPressed( 
  }
  
  void TextureBrowser_createTreeViewTags(){
 -      g_TextureBrowser.m_treeViewTags = ui::TreeView(ui::New);
 -      gtk_tree_view_set_enable_search(g_TextureBrowser.m_treeViewTags, FALSE );
 +      TextureBrowser &textureBrowser = GlobalTextureBrowser();
 +      textureBrowser.m_treeViewTags = ui::TreeView(ui::New);
 +      gtk_tree_view_set_enable_search(textureBrowser.m_treeViewTags, FALSE );
  
 -      g_TextureBrowser.m_treeViewTags.connect( "button-press-event", (GCallback)TreeViewTags_onButtonPressed, NULL );
 +      textureBrowser.m_treeViewTags.connect( "button-press-event", (GCallback)TreeViewTags_onButtonPressed, NULL );
  
 -      gtk_tree_view_set_headers_visible(g_TextureBrowser.m_treeViewTags, FALSE );
 +      gtk_tree_view_set_headers_visible(textureBrowser.m_treeViewTags, FALSE );
  
        auto renderer = ui::CellRendererText(ui::New);
 -      gtk_tree_view_insert_column_with_attributes(g_TextureBrowser.m_treeViewTags, -1, "", renderer, "text", 0, NULL );
 +      gtk_tree_view_insert_column_with_attributes(textureBrowser.m_treeViewTags, -1, "", renderer, "text", 0, NULL );
  
        TextureBrowser_constructTreeStoreTags();
  }
  
  ui::MenuItem TextureBrowser_constructViewMenu( ui::Menu menu ){
 +      TextureBrowser &textureBrowser = GlobalTextureBrowser();
        ui::MenuItem textures_menu_item = ui::MenuItem(new_sub_menu_item_with_mnemonic( "_View" ));
  
        if ( g_Layout_enableDetachableMenus.m_value ) {
        create_menu_item_with_mnemonic( menu, "Show All", "ShowAllTextures" );
  
        // we always want to show shaders but don't want a "Show Shaders" menu for doom3 and .wad file games
 -      if ( g_pGameDescription->mGameType == "doom3" || !string_empty( g_pGameDescription->getKeyValue( "show_wads" ) ) ) {
 -              g_TextureBrowser.m_showShaders = true;
 +      if ( g_pGameDescription->mGameType == "doom3" || TextureBrowser_showWads() ) {
 +              textureBrowser.m_showShaders = true;
        }
        else
        {
        if ( g_pGameDescription->mGameType != "doom3" && string_empty( g_pGameDescription->getKeyValue( "show_wads" ) ) ) {
                create_check_menu_item_with_mnemonic( menu, "Shaders Only", "ToggleShowShaderlistOnly" );
        }
 -      if ( g_TextureBrowser.m_tags ) {
 +      if ( textureBrowser.m_tags ) {
                create_menu_item_with_mnemonic( menu, "Show Untagged", "ShowUntagged" );
        }
  
  
        if ( string_empty( g_pGameDescription->getKeyValue( "show_wads" ) ) ) {
                menu_separator( menu );
 -              g_TextureBrowser.m_shader_info_item = ui::Widget(create_menu_item_with_mnemonic( menu, "Shader Info", "ShaderInfo"  ));
 -              gtk_widget_set_sensitive( g_TextureBrowser.m_shader_info_item, FALSE );
 +              textureBrowser.m_shader_info_item = ui::Widget(create_menu_item_with_mnemonic( menu, "Shader Info", "ShaderInfo"  ));
 +              gtk_widget_set_sensitive( textureBrowser.m_shader_info_item, FALSE );
        }
  
  
@@@ -1902,7 -1824,7 +1900,7 @@@ ui::MenuItem TextureBrowser_constructTa
        return textures_menu_item;
  }
  
 -gboolean TextureBrowser_tagMoveHelper( ui::TreeModel model, ui::TreePath path, GtkTreeIter iter, GSList** selected ){
 +gboolean TextureBrowser_tagMoveHelper( ui::TreeModel model, ui::TreePath path, GtkTreeIter* iter, GSList** selected ){
        g_assert( selected != NULL );
  
      auto rowref = gtk_tree_row_reference_new( model, path );
@@@ -1915,9 -1837,8 +1913,9 @@@ void TextureBrowser_assignTags()
        GSList* selected = NULL;
        GSList* node;
        gchar* tag_assigned;
 +      TextureBrowser &textureBrowser = GlobalTextureBrowser();
  
 -    auto selection = gtk_tree_view_get_selection(g_TextureBrowser.m_available_tree );
 +      auto selection = gtk_tree_view_get_selection(textureBrowser.m_available_tree );
  
        gtk_tree_selection_selected_foreach( selection, (GtkTreeSelectionForeachFunc)TextureBrowser_tagMoveHelper, &selected );
  
                        if ( path ) {
                                GtkTreeIter iter;
  
 -                              if ( gtk_tree_model_get_iter(g_TextureBrowser.m_available_store, &iter, path ) ) {
 -                                      gtk_tree_model_get(g_TextureBrowser.m_available_store, &iter, TAG_COLUMN, &tag_assigned, -1 );
 -                                      if ( !TagBuilder.CheckShaderTag( g_TextureBrowser.shader.c_str() ) ) {
 +                              if ( gtk_tree_model_get_iter(textureBrowser.m_available_store, &iter, path ) ) {
 +                                      gtk_tree_model_get(textureBrowser.m_available_store, &iter, TAG_COLUMN, &tag_assigned, -1 );
 +                                      if ( !TagBuilder.CheckShaderTag( textureBrowser.shader.c_str() ) ) {
                                                // create a custom shader/texture entry
 -                                              IShader* ishader = QERApp_Shader_ForName( g_TextureBrowser.shader.c_str() );
 +                                              IShader* ishader = QERApp_Shader_ForName( textureBrowser.shader.c_str() );
                                                CopiedString filename = ishader->getShaderFileName();
  
                                                if ( filename.empty() ) {
                                                        // it's a texture
 -                                                      TagBuilder.AddShaderNode( g_TextureBrowser.shader.c_str(), CUSTOM, TEXTURE );
 +                                                      TagBuilder.AddShaderNode( textureBrowser.shader.c_str(), CUSTOM, TEXTURE );
                                                }
                                                else {
                                                        // it's a shader
 -                                                      TagBuilder.AddShaderNode( g_TextureBrowser.shader.c_str(), CUSTOM, SHADER );
 +                                                      TagBuilder.AddShaderNode( textureBrowser.shader.c_str(), CUSTOM, SHADER );
                                                }
                                                ishader->DecRef();
                                        }
 -                                      TagBuilder.AddShaderTag( g_TextureBrowser.shader.c_str(), (char*)tag_assigned, TAG );
 +                                      TagBuilder.AddShaderTag( textureBrowser.shader.c_str(), (char*)tag_assigned, TAG );
  
 -                                      gtk_list_store_remove( g_TextureBrowser.m_available_store, &iter );
 -                                      g_TextureBrowser.m_assigned_store.append(TAG_COLUMN, tag_assigned);
 +                                      gtk_list_store_remove( textureBrowser.m_available_store, &iter );
 +                                      textureBrowser.m_assigned_store.append(TAG_COLUMN, tag_assigned);
                                }
                        }
                }
@@@ -1966,9 -1887,8 +1964,9 @@@ void TextureBrowser_removeTags()
        GSList* selected = NULL;
        GSList* node;
        gchar* tag;
 +      TextureBrowser &textureBrowser = GlobalTextureBrowser();
  
 -    auto selection = gtk_tree_view_get_selection(g_TextureBrowser.m_assigned_tree );
 +      auto selection = gtk_tree_view_get_selection(textureBrowser.m_assigned_tree );
  
        gtk_tree_selection_selected_foreach( selection, (GtkTreeSelectionForeachFunc)TextureBrowser_tagMoveHelper, &selected );
  
                        if ( path ) {
                                GtkTreeIter iter;
  
 -                              if ( gtk_tree_model_get_iter(g_TextureBrowser.m_assigned_store, &iter, path ) ) {
 -                                      gtk_tree_model_get(g_TextureBrowser.m_assigned_store, &iter, TAG_COLUMN, &tag, -1 );
 -                                      TagBuilder.DeleteShaderTag( g_TextureBrowser.shader.c_str(), tag );
 -                                      gtk_list_store_remove( g_TextureBrowser.m_assigned_store, &iter );
 +                              if ( gtk_tree_model_get_iter(textureBrowser.m_assigned_store, &iter, path ) ) {
 +                                      gtk_tree_model_get(textureBrowser.m_assigned_store, &iter, TAG_COLUMN, &tag, -1 );
 +                                      TagBuilder.DeleteShaderTag( textureBrowser.shader.c_str(), tag );
 +                                      gtk_list_store_remove( textureBrowser.m_assigned_store, &iter );
                                }
                        }
                }
                g_slist_foreach( selected, (GFunc)gtk_tree_row_reference_free, NULL );
  
                // Update the "available tags list"
 -              BuildStoreAvailableTags( g_TextureBrowser.m_available_store, g_TextureBrowser.m_assigned_store, g_TextureBrowser.m_all_tags, &g_TextureBrowser );
 +              BuildStoreAvailableTags( textureBrowser.m_available_store, textureBrowser.m_assigned_store, textureBrowser.m_all_tags, &textureBrowser );
  
                // Save changes
                TagBuilder.SaveXmlDoc();
  }
  
  void TextureBrowser_buildTagList(){
 -      g_TextureBrowser.m_all_tags_list.clear();
 +      TextureBrowser &textureBrowser = GlobalTextureBrowser();
 +      textureBrowser.m_all_tags_list.clear();
  
        std::set<CopiedString>::iterator iter;
  
 -      for ( iter = g_TextureBrowser.m_all_tags.begin(); iter != g_TextureBrowser.m_all_tags.end(); ++iter )
 +      for ( iter = textureBrowser.m_all_tags.begin(); iter != textureBrowser.m_all_tags.end(); ++iter )
        {
 -              g_TextureBrowser.m_all_tags_list.append(TAG_COLUMN, (*iter).c_str());
 +              textureBrowser.m_all_tags_list.append(TAG_COLUMN, (*iter).c_str());
        }
  }
  
@@@ -2017,9 -1936,8 +2015,9 @@@ void TextureBrowser_searchTags()
        gchar* tag;
        char buffer[256];
        char tags_searched[256];
 +      TextureBrowser &textureBrowser = GlobalTextureBrowser();
  
 -    auto selection = gtk_tree_view_get_selection(g_TextureBrowser.m_treeViewTags );
 +      auto selection = gtk_tree_view_get_selection(textureBrowser.m_treeViewTags );
  
        gtk_tree_selection_selected_foreach( selection, (GtkTreeSelectionForeachFunc)TextureBrowser_tagMoveHelper, &selected );
  
                        if ( path ) {
                                GtkTreeIter iter;
  
 -                              if ( gtk_tree_model_get_iter(g_TextureBrowser.m_all_tags_list, &iter, path ) ) {
 -                                      gtk_tree_model_get(g_TextureBrowser.m_all_tags_list, &iter, TAG_COLUMN, &tag, -1 );
 +                              if ( gtk_tree_model_get_iter(textureBrowser.m_all_tags_list, &iter, path ) ) {
 +                                      gtk_tree_model_get(textureBrowser.m_all_tags_list, &iter, TAG_COLUMN, &tag, -1 );
  
                                        strcat( buffer, tag );
                                        strcat( tags_searched, tag );
  
                g_slist_foreach( selected, (GFunc)gtk_tree_row_reference_free, NULL );
  
 -              g_TextureBrowser.m_found_shaders.clear(); // delete old list
 -              TagBuilder.TagSearch( buffer, g_TextureBrowser.m_found_shaders );
 +              textureBrowser.m_found_shaders.clear(); // delete old list
 +              TagBuilder.TagSearch( buffer, textureBrowser.m_found_shaders );
  
 -              if ( !g_TextureBrowser.m_found_shaders.empty() ) { // found something
 -                      size_t shaders_found = g_TextureBrowser.m_found_shaders.size();
 +              if ( !textureBrowser.m_found_shaders.empty() ) { // found something
 +                      size_t shaders_found = textureBrowser.m_found_shaders.size();
  
                        globalOutputStream() << "Found " << (unsigned int)shaders_found << " textures and shaders with " << tags_searched << "\n";
                        ScopeDisableScreenUpdates disableScreenUpdates( "Searching...", "Loading Textures" );
  
                        std::set<CopiedString>::iterator iter;
  
 -                      for ( iter = g_TextureBrowser.m_found_shaders.begin(); iter != g_TextureBrowser.m_found_shaders.end(); iter++ )
 +                      for ( iter = textureBrowser.m_found_shaders.begin(); iter != textureBrowser.m_found_shaders.end(); iter++ )
                        {
                                std::string path = ( *iter ).c_str();
                                size_t pos = path.find_last_of( "/", path.size() );
                                TextureDirectory_loadTexture( path.c_str(), name.c_str() );
                        }
                }
 -              g_TextureBrowser.m_searchedTags = true;
 +              textureBrowser.m_searchedTags = true;
                g_TextureBrowser_currentDirectory = tags_searched;
  
 -              g_TextureBrowser.m_nTotalHeight = 0;
 -              TextureBrowser_setOriginY( g_TextureBrowser, 0 );
 -              TextureBrowser_heightChanged( g_TextureBrowser );
 +              textureBrowser.m_nTotalHeight = 0;
 +              TextureBrowser_setOriginY( textureBrowser, 0 );
 +              TextureBrowser_heightChanged( textureBrowser );
                TextureBrowser_updateTitle();
        }
        g_slist_free( selected );
  }
  
  void TextureBrowser_toggleSearchButton(){
 -      gint page = gtk_notebook_get_current_page( GTK_NOTEBOOK( g_TextureBrowser.m_tag_notebook ) );
 +      TextureBrowser &textureBrowser = GlobalTextureBrowser();
 +      gint page = gtk_notebook_get_current_page( GTK_NOTEBOOK( textureBrowser.m_tag_notebook ) );
  
        if ( page == 0 ) { // tag page
 -              gtk_widget_show_all( g_TextureBrowser.m_search_button );
 +              gtk_widget_show_all( textureBrowser.m_search_button );
        }
        else {
 -              g_TextureBrowser.m_search_button.hide();
 +              textureBrowser.m_search_button.hide();
        }
  }
  
  void TextureBrowser_constructTagNotebook(){
 -      g_TextureBrowser.m_tag_notebook = ui::Widget::from(gtk_notebook_new());
 +      TextureBrowser &textureBrowser = GlobalTextureBrowser();
 +      textureBrowser.m_tag_notebook = ui::Widget::from(gtk_notebook_new());
        ui::Widget labelTags = ui::Label( "Tags" );
        ui::Widget labelTextures = ui::Label( "Textures" );
  
 -      gtk_notebook_append_page( GTK_NOTEBOOK( g_TextureBrowser.m_tag_notebook ), g_TextureBrowser.m_scr_win_tree, labelTextures );
 -      gtk_notebook_append_page( GTK_NOTEBOOK( g_TextureBrowser.m_tag_notebook ), g_TextureBrowser.m_scr_win_tags, labelTags );
 +      gtk_notebook_append_page( GTK_NOTEBOOK( textureBrowser.m_tag_notebook ), textureBrowser.m_scr_win_tree, labelTextures );
 +      gtk_notebook_append_page( GTK_NOTEBOOK( textureBrowser.m_tag_notebook ), textureBrowser.m_scr_win_tags, labelTags );
  
 -      g_TextureBrowser.m_tag_notebook.connect( "switch-page", G_CALLBACK( TextureBrowser_toggleSearchButton ), NULL );
 +      textureBrowser.m_tag_notebook.connect( "switch-page", G_CALLBACK( TextureBrowser_toggleSearchButton ), NULL );
  
 -      gtk_widget_show_all( g_TextureBrowser.m_tag_notebook );
 +      gtk_widget_show_all( textureBrowser.m_tag_notebook );
  }
  
  void TextureBrowser_constructSearchButton(){
        auto image = ui::Widget::from(gtk_image_new_from_stock( GTK_STOCK_FIND, GTK_ICON_SIZE_SMALL_TOOLBAR ));
 -      g_TextureBrowser.m_search_button = ui::Button(ui::New);
 -      g_TextureBrowser.m_search_button.connect( "clicked", G_CALLBACK( TextureBrowser_searchTags ), NULL );
 -      gtk_widget_set_tooltip_text(g_TextureBrowser.m_search_button, "Search with selected tags");
 -      g_TextureBrowser.m_search_button.add(image);
 +      TextureBrowser &textureBrowser = GlobalTextureBrowser();
 +      textureBrowser.m_search_button = ui::Button(ui::New);
 +      textureBrowser.m_search_button.connect( "clicked", G_CALLBACK( TextureBrowser_searchTags ), NULL );
 +      gtk_widget_set_tooltip_text(textureBrowser.m_search_button, "Search with selected tags");
 +      textureBrowser.m_search_button.add(image);
  }
  
  void TextureBrowser_checkTagFile(){
        const char SHADERTAG_FILE[] = "shadertags.xml";
        CopiedString default_filename, rc_filename;
        StringOutputStream stream( 256 );
 +      TextureBrowser &textureBrowser = GlobalTextureBrowser();
  
        stream << LocalRcPath_get();
        stream << SHADERTAG_FILE;
        rc_filename = stream.c_str();
  
        if ( file_exists( rc_filename.c_str() ) ) {
 -              g_TextureBrowser.m_tags = TagBuilder.OpenXmlDoc( rc_filename.c_str() );
 +              textureBrowser.m_tags = TagBuilder.OpenXmlDoc( rc_filename.c_str() );
  
 -              if ( g_TextureBrowser.m_tags ) {
 +              if ( textureBrowser.m_tags ) {
                        globalOutputStream() << "Loading tag file " << rc_filename.c_str() << ".\n";
                }
        }
                default_filename = stream.c_str();
  
                if ( file_exists( default_filename.c_str() ) ) {
 -                      g_TextureBrowser.m_tags = TagBuilder.OpenXmlDoc( default_filename.c_str(), rc_filename.c_str() );
 +                      textureBrowser.m_tags = TagBuilder.OpenXmlDoc( default_filename.c_str(), rc_filename.c_str() );
  
 -                      if ( g_TextureBrowser.m_tags ) {
 +                      if ( textureBrowser.m_tags ) {
                                globalOutputStream() << "Loading default tag file " << default_filename.c_str() << ".\n";
                        }
                }
@@@ -2161,56 -2075,24 +2159,56 @@@ void TextureBrowser_SetNotex()
        IShader* shadernotex = QERApp_Shader_ForName( DEFAULT_SHADERNOTEX_NAME );
  
        g_notex = notex->getTexture()->name;
 +
        g_shadernotex = shadernotex->getTexture()->name;
  
        notex->DecRef();
        shadernotex->DecRef();
  }
  
 +static bool isGLWidgetConstructed = false;
 +static bool isWindowConstructed = false;
 +
 +void TextureBrowser_constructGLWidget(){
 +      TextureBrowser &textureBrowser = GlobalTextureBrowser();
 +      textureBrowser.m_gl_widget = glwidget_new( FALSE );
 +      g_object_ref( textureBrowser.m_gl_widget._handle );
 +
 +      gtk_widget_set_events( textureBrowser.m_gl_widget, GDK_DESTROY | GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK );
 +      gtk_widget_set_can_focus( textureBrowser.m_gl_widget, true );
 +
 +      textureBrowser.m_sizeHandler = textureBrowser.m_gl_widget.connect( "size_allocate", G_CALLBACK( TextureBrowser_size_allocate ), &textureBrowser );
 +      textureBrowser.m_exposeHandler = textureBrowser.m_gl_widget.on_render( G_CALLBACK( TextureBrowser_expose ), &textureBrowser );
 +
 +      textureBrowser.m_gl_widget.connect( "button_press_event", G_CALLBACK( TextureBrowser_button_press ), &textureBrowser );
 +      textureBrowser.m_gl_widget.connect( "button_release_event", G_CALLBACK( TextureBrowser_button_release ), &textureBrowser );
 +      textureBrowser.m_gl_widget.connect( "motion_notify_event", G_CALLBACK( TextureBrowser_motion ), &textureBrowser );
 +      textureBrowser.m_gl_widget.connect( "scroll_event", G_CALLBACK( TextureBrowser_scroll ), &textureBrowser );
 +
 +#ifdef WORKAROUND_MACOS_GTK2_GLWIDGET
 +      textureBrowser.m_hframe.pack_start( textureBrowser.m_gl_widget, TRUE, TRUE, 0 );
 +#else // !WORKAROUND_MACOS_GTK2_GLWIDGET
 +      textureBrowser.m_frame.pack_start( textureBrowser.m_gl_widget, TRUE, TRUE, 0 );
 +#endif // !WORKAROUND_MACOS_GTK2_GLWIDGET
 +
 +      textureBrowser.m_gl_widget.show();
 +
 +      isGLWidgetConstructed = true;
 +}
 +
  ui::Widget TextureBrowser_constructWindow( ui::Window toplevel ){
        // The gl_widget and the tag assignment frame should be packed into a GtkVPaned with the slider
        // position stored in local.pref. gtk_paned_get_position() and gtk_paned_set_position() don't
        // seem to work in gtk 2.4 and the arrow buttons don't handle GTK_FILL, so here's another thing
        // for the "once-the-gtk-libs-are-updated-TODO-list" :x
 +      TextureBrowser &textureBrowser = GlobalTextureBrowser();
  
        TextureBrowser_checkTagFile();
        TextureBrowser_SetNotex();
  
 -      GlobalShaderSystem().setActiveShadersChangedNotify( ReferenceCaller<TextureBrowser, void(), TextureBrowser_activeShadersChanged>( g_TextureBrowser ) );
 +      GlobalShaderSystem().setActiveShadersChangedNotify( ReferenceCaller<TextureBrowser, void(), TextureBrowser_activeShadersChanged>( textureBrowser ) );
  
 -      g_TextureBrowser.m_parent = toplevel;
 +      textureBrowser.m_parent = toplevel;
  
        auto table = ui::Table(3, 3, FALSE);
        auto vbox = ui::VBox(FALSE, 0);
                menu_bar.show();
        }
        { // Texture TreeView
 -              g_TextureBrowser.m_scr_win_tree = ui::ScrolledWindow(ui::New);
 -              gtk_container_set_border_width( GTK_CONTAINER( g_TextureBrowser.m_scr_win_tree ), 0 );
 +              textureBrowser.m_scr_win_tree = ui::ScrolledWindow(ui::New);
 +              gtk_container_set_border_width( GTK_CONTAINER( textureBrowser.m_scr_win_tree ), 0 );
  
                // vertical only scrolling for treeview
 -              gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( g_TextureBrowser.m_scr_win_tree ), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS );
 +              gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( textureBrowser.m_scr_win_tree ), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS );
  
 -              g_TextureBrowser.m_scr_win_tree.show();
 +              textureBrowser.m_scr_win_tree.show();
  
                TextureBrowser_createTreeViewTree();
  
 -              gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW( g_TextureBrowser.m_scr_win_tree ), g_TextureBrowser.m_treeViewTree  );
 -              g_TextureBrowser.m_treeViewTree.show();
 +              gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW( textureBrowser.m_scr_win_tree ), textureBrowser.m_treeViewTree  );
 +              textureBrowser.m_treeViewTree.show();
        }
        { // gl_widget scrollbar
                auto w = ui::Widget::from(gtk_vscrollbar_new( ui::Adjustment( 0,0,0,1,1,0 ) ));
                table.attach(w, {2, 3, 1, 2}, {GTK_SHRINK, GTK_FILL});
                w.show();
 -              g_TextureBrowser.m_texture_scroll = w;
 +              textureBrowser.m_texture_scroll = w;
  
 -              auto vadjustment = ui::Adjustment::from(gtk_range_get_adjustment( GTK_RANGE( g_TextureBrowser.m_texture_scroll ) ));
 -              vadjustment.connect( "value_changed", G_CALLBACK( TextureBrowser_verticalScroll ), &g_TextureBrowser );
 +              auto vadjustment = ui::Adjustment::from(gtk_range_get_adjustment( GTK_RANGE( textureBrowser.m_texture_scroll ) ));
 +              vadjustment.connect( "value_changed", G_CALLBACK( TextureBrowser_verticalScroll ), &textureBrowser );
  
 -              g_TextureBrowser.m_texture_scroll.visible(g_TextureBrowser.m_showTextureScrollbar);
 +              textureBrowser.m_texture_scroll.visible(textureBrowser.m_showTextureScrollbar);
        }
        { // gl_widget
 -              g_TextureBrowser.m_gl_widget = glwidget_new( FALSE );
 -              g_object_ref( g_TextureBrowser.m_gl_widget._handle );
 +#ifdef WORKAROUND_MACOS_GTK2_GLWIDGET
 +              textureBrowser.m_vframe = ui::VBox( FALSE, 0 );
 +              table.attach(textureBrowser.m_vframe, {1, 2, 1, 2});
  
 -              gtk_widget_set_events( g_TextureBrowser.m_gl_widget, GDK_DESTROY | GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK );
 -              gtk_widget_set_can_focus( g_TextureBrowser.m_gl_widget, true );
 +              textureBrowser.m_vfiller = ui::VBox( FALSE, 0 );
 +              textureBrowser.m_vframe.pack_start( textureBrowser.m_vfiller, FALSE, FALSE, 0 );
  
 -              table.attach(g_TextureBrowser.m_gl_widget, {1, 2, 1, 2});
 -              g_TextureBrowser.m_gl_widget.show();
 +              textureBrowser.m_hframe = ui::HBox( FALSE, 0 );
 +              textureBrowser.m_vframe.pack_start( textureBrowser.m_hframe, TRUE, TRUE, 0 );
  
 -              g_TextureBrowser.m_sizeHandler = g_TextureBrowser.m_gl_widget.connect( "size_allocate", G_CALLBACK( TextureBrowser_size_allocate ), &g_TextureBrowser );
 -              g_TextureBrowser.m_exposeHandler = g_TextureBrowser.m_gl_widget.on_render( G_CALLBACK( TextureBrowser_expose ), &g_TextureBrowser );
 +              textureBrowser.m_hfiller = ui::HBox( FALSE, 0 );
 +              textureBrowser.m_hframe.pack_start( textureBrowser.m_hfiller, FALSE, FALSE, 0 );
  
 -              g_TextureBrowser.m_gl_widget.connect( "button_press_event", G_CALLBACK( TextureBrowser_button_press ), &g_TextureBrowser );
 -              g_TextureBrowser.m_gl_widget.connect( "button_release_event", G_CALLBACK( TextureBrowser_button_release ), &g_TextureBrowser );
 -              g_TextureBrowser.m_gl_widget.connect( "motion_notify_event", G_CALLBACK( TextureBrowser_motion ), &g_TextureBrowser );
 -              g_TextureBrowser.m_gl_widget.connect( "scroll_event", G_CALLBACK( TextureBrowser_scroll ), &g_TextureBrowser );
 +              textureBrowser.m_vframe.show();
 +              textureBrowser.m_vfiller.show();
 +              textureBrowser.m_hframe.show(),
 +              textureBrowser.m_hfiller.show();
 +#else // !WORKAROUND_MACOS_GTK2_GLWIDGET
 +              textureBrowser.m_frame = ui::VBox( FALSE, 0 );
 +              table.attach(textureBrowser.m_frame, {1, 2, 1, 2});
 +              textureBrowser.m_frame.show();
 +#endif // !WORKAROUND_MACOS_GTK2_GLWIDGET
 +
 +              TextureBrowser_constructGLWidget();
        }
  
        // tag stuff
 -      if ( g_TextureBrowser.m_tags ) {
 +      if ( textureBrowser.m_tags ) {
                { // fill tag GtkListStore
 -                      g_TextureBrowser.m_all_tags_list = ui::ListStore::from(gtk_list_store_new( N_COLUMNS, G_TYPE_STRING ));
 -            auto sortable = GTK_TREE_SORTABLE( g_TextureBrowser.m_all_tags_list );
 +                      textureBrowser.m_all_tags_list = ui::ListStore::from(gtk_list_store_new( N_COLUMNS, G_TYPE_STRING ));
 +            auto sortable = GTK_TREE_SORTABLE( textureBrowser.m_all_tags_list );
                        gtk_tree_sortable_set_sort_column_id( sortable, TAG_COLUMN, GTK_SORT_ASCENDING );
  
 -                      TagBuilder.GetAllTags( g_TextureBrowser.m_all_tags );
 +                      TagBuilder.GetAllTags( textureBrowser.m_all_tags );
                        TextureBrowser_buildTagList();
                }
                { // tag menu bar
                        gtk_menu_shell_append( GTK_MENU_SHELL( menu_bar ), tags_item );
                }
                { // Tag TreeView
 -                      g_TextureBrowser.m_scr_win_tags = ui::ScrolledWindow(ui::New);
 -                      gtk_container_set_border_width( GTK_CONTAINER( g_TextureBrowser.m_scr_win_tags ), 0 );
 +                      textureBrowser.m_scr_win_tags = ui::ScrolledWindow(ui::New);
 +                      gtk_container_set_border_width( GTK_CONTAINER( textureBrowser.m_scr_win_tags ), 0 );
  
                        // vertical only scrolling for treeview
 -                      gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( g_TextureBrowser.m_scr_win_tags ), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS );
 +                      gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( textureBrowser.m_scr_win_tags ), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS );
  
                        TextureBrowser_createTreeViewTags();
  
 -            auto selection = gtk_tree_view_get_selection(g_TextureBrowser.m_treeViewTags );
 +            auto selection = gtk_tree_view_get_selection(textureBrowser.m_treeViewTags );
                        gtk_tree_selection_set_mode( selection, GTK_SELECTION_MULTIPLE );
  
 -                      gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW( g_TextureBrowser.m_scr_win_tags ), g_TextureBrowser.m_treeViewTags  );
 -                      g_TextureBrowser.m_treeViewTags.show();
 +                      gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW( textureBrowser.m_scr_win_tags ), textureBrowser.m_treeViewTags  );
 +                      textureBrowser.m_treeViewTags.show();
                }
                { // Texture/Tag notebook
                        TextureBrowser_constructTagNotebook();
 -                      vbox.pack_start( g_TextureBrowser.m_tag_notebook, TRUE, TRUE, 0 );
 +                      vbox.pack_start( textureBrowser.m_tag_notebook, TRUE, TRUE, 0 );
                }
                { // Tag search button
                        TextureBrowser_constructSearchButton();
 -                      vbox.pack_end(g_TextureBrowser.m_search_button, FALSE, FALSE, 0);
 +                      vbox.pack_end(textureBrowser.m_search_button, FALSE, FALSE, 0);
                }
                auto frame_table = ui::Table(3, 3, FALSE);
                { // Tag frame
  
 -                      g_TextureBrowser.m_tag_frame = ui::Frame( "Tag assignment" );
 -                      gtk_frame_set_label_align( GTK_FRAME( g_TextureBrowser.m_tag_frame ), 0.5, 0.5 );
 -                      gtk_frame_set_shadow_type( GTK_FRAME( g_TextureBrowser.m_tag_frame ), GTK_SHADOW_NONE );
 +                      textureBrowser.m_tag_frame = ui::Frame( "Tag assignment" );
 +                      gtk_frame_set_label_align( GTK_FRAME( textureBrowser.m_tag_frame ), 0.5, 0.5 );
 +                      gtk_frame_set_shadow_type( GTK_FRAME( textureBrowser.m_tag_frame ), GTK_SHADOW_NONE );
  
 -                      table.attach(g_TextureBrowser.m_tag_frame, {1, 3, 2, 3}, {GTK_FILL, GTK_SHRINK});
 +                      table.attach(textureBrowser.m_tag_frame, {1, 3, 2, 3}, {GTK_FILL, GTK_SHRINK});
  
                        frame_table.show();
  
 -                      g_TextureBrowser.m_tag_frame.add(frame_table);
 +                      textureBrowser.m_tag_frame.add(frame_table);
                }
                { // assigned tag list
                        ui::Widget scrolled_win = ui::ScrolledWindow(ui::New);
                        gtk_container_set_border_width( GTK_CONTAINER( scrolled_win ), 0 );
                        gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scrolled_win ), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS );
  
 -                      g_TextureBrowser.m_assigned_store = ui::ListStore::from(gtk_list_store_new( N_COLUMNS, G_TYPE_STRING ));
 +                      textureBrowser.m_assigned_store = ui::ListStore::from(gtk_list_store_new( N_COLUMNS, G_TYPE_STRING ));
  
 -            auto sortable = GTK_TREE_SORTABLE( g_TextureBrowser.m_assigned_store );
 +            auto sortable = GTK_TREE_SORTABLE( textureBrowser.m_assigned_store );
                        gtk_tree_sortable_set_sort_column_id( sortable, TAG_COLUMN, GTK_SORT_ASCENDING );
  
                        auto renderer = ui::CellRendererText(ui::New);
  
 -                      g_TextureBrowser.m_assigned_tree = ui::TreeView(ui::TreeModel::from(g_TextureBrowser.m_assigned_store._handle));
 -                      g_TextureBrowser.m_assigned_store.unref();
 -                      g_TextureBrowser.m_assigned_tree.connect( "row-activated", (GCallback) TextureBrowser_removeTags, NULL );
 -                      gtk_tree_view_set_headers_visible(g_TextureBrowser.m_assigned_tree, FALSE );
 +                      textureBrowser.m_assigned_tree = ui::TreeView(ui::TreeModel::from(textureBrowser.m_assigned_store._handle));
 +                      textureBrowser.m_assigned_store.unref();
 +                      textureBrowser.m_assigned_tree.connect( "row-activated", (GCallback) TextureBrowser_removeTags, NULL );
 +                      gtk_tree_view_set_headers_visible(textureBrowser.m_assigned_tree, FALSE );
  
 -            auto selection = gtk_tree_view_get_selection(g_TextureBrowser.m_assigned_tree );
 +            auto selection = gtk_tree_view_get_selection(textureBrowser.m_assigned_tree );
                        gtk_tree_selection_set_mode( selection, GTK_SELECTION_MULTIPLE );
  
              auto column = ui::TreeViewColumn( "", renderer, {{"text", TAG_COLUMN}} );
 -                      gtk_tree_view_append_column(g_TextureBrowser.m_assigned_tree, column );
 -                      g_TextureBrowser.m_assigned_tree.show();
 +                      gtk_tree_view_append_column(textureBrowser.m_assigned_tree, column );
 +                      textureBrowser.m_assigned_tree.show();
  
                        scrolled_win.show();
 -                      gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW( scrolled_win ), g_TextureBrowser.m_assigned_tree  );
 +                      gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW( scrolled_win ), textureBrowser.m_assigned_tree  );
  
                        frame_table.attach(scrolled_win, {0, 1, 1, 3}, {GTK_FILL, GTK_FILL});
                }
                        gtk_container_set_border_width( GTK_CONTAINER( scrolled_win ), 0 );
                        gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scrolled_win ), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS );
  
 -                      g_TextureBrowser.m_available_store = ui::ListStore::from(gtk_list_store_new( N_COLUMNS, G_TYPE_STRING ));
 -            auto sortable = GTK_TREE_SORTABLE( g_TextureBrowser.m_available_store );
 +                      textureBrowser.m_available_store = ui::ListStore::from(gtk_list_store_new( N_COLUMNS, G_TYPE_STRING ));
 +            auto sortable = GTK_TREE_SORTABLE( textureBrowser.m_available_store );
                        gtk_tree_sortable_set_sort_column_id( sortable, TAG_COLUMN, GTK_SORT_ASCENDING );
  
                        auto renderer = ui::CellRendererText(ui::New);
  
 -                      g_TextureBrowser.m_available_tree = ui::TreeView(ui::TreeModel::from(g_TextureBrowser.m_available_store._handle));
 -                      g_TextureBrowser.m_available_store.unref();
 -                      g_TextureBrowser.m_available_tree.connect( "row-activated", (GCallback) TextureBrowser_assignTags, NULL );
 -                      gtk_tree_view_set_headers_visible(g_TextureBrowser.m_available_tree, FALSE );
 +                      textureBrowser.m_available_tree = ui::TreeView(ui::TreeModel::from(textureBrowser.m_available_store._handle));
 +                      textureBrowser.m_available_store.unref();
 +                      textureBrowser.m_available_tree.connect( "row-activated", (GCallback) TextureBrowser_assignTags, NULL );
 +                      gtk_tree_view_set_headers_visible(textureBrowser.m_available_tree, FALSE );
  
 -            auto selection = gtk_tree_view_get_selection(g_TextureBrowser.m_available_tree );
 +            auto selection = gtk_tree_view_get_selection(textureBrowser.m_available_tree );
                        gtk_tree_selection_set_mode( selection, GTK_SELECTION_MULTIPLE );
  
              auto column = ui::TreeViewColumn( "", renderer, {{"text", TAG_COLUMN}} );
 -                      gtk_tree_view_append_column(g_TextureBrowser.m_available_tree, column );
 -                      g_TextureBrowser.m_available_tree.show();
 +                      gtk_tree_view_append_column(textureBrowser.m_available_tree, column );
 +                      textureBrowser.m_available_tree.show();
  
                        scrolled_win.show();
 -                      gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW( scrolled_win ), g_TextureBrowser.m_available_tree  );
 +                      gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW( scrolled_win ), textureBrowser.m_available_tree  );
  
                        frame_table.attach(scrolled_win, {2, 3, 1, 3}, {GTK_FILL, GTK_FILL});
                }
                }
        }
        else { // no tag support, show the texture tree only
 -              vbox.pack_start( g_TextureBrowser.m_scr_win_tree, TRUE, TRUE, 0 );
 +              vbox.pack_start( textureBrowser.m_scr_win_tree, TRUE, TRUE, 0 );
        }
  
        // TODO do we need this?
        //gtk_container_set_focus_chain(GTK_CONTAINER(hbox_table), NULL);
  
 +      isWindowConstructed = true;
 +
        return table;
  }
  
 +void TextureBrowser_destroyGLWidget(){
 +      TextureBrowser &textureBrowser = GlobalTextureBrowser();
 +      if ( isGLWidgetConstructed )
 +      {
 +              g_signal_handler_disconnect( G_OBJECT( textureBrowser.m_gl_widget ), textureBrowser.m_sizeHandler );
 +              g_signal_handler_disconnect( G_OBJECT( textureBrowser.m_gl_widget ), textureBrowser.m_exposeHandler );
 +
 +#ifdef WORKAROUND_MACOS_GTK2_GLWIDGET
 +              textureBrowser.m_hframe.remove( textureBrowser.m_gl_widget );
 +#else // !WORKAROUND_MACOS_GTK2_GLWIDGET
 +              textureBrowser.m_frame.remove( textureBrowser.m_gl_widget );
 +#endif // !WORKAROUND_MACOS_GTK2_GLWIDGET
 +
 +              textureBrowser.m_gl_widget.unref();
 +
 +              isGLWidgetConstructed = false;
 +      }
 +}
 +
  void TextureBrowser_destroyWindow(){
        GlobalShaderSystem().setActiveShadersChangedNotify( Callback<void()>() );
  
 -      g_signal_handler_disconnect( G_OBJECT( g_TextureBrowser.m_gl_widget ), g_TextureBrowser.m_sizeHandler );
 -      g_signal_handler_disconnect( G_OBJECT( g_TextureBrowser.m_gl_widget ), g_TextureBrowser.m_exposeHandler );
 +      TextureBrowser_destroyGLWidget();
 +}
 +
 +#ifdef WORKAROUND_MACOS_GTK2_GLWIDGET
 +/* workaround for gtkglext on gtk 2 issue: OpenGL texture viewport being drawn over the other pages */
 +/* this is very ugly: force the resizing of the viewport to a single bottom line by forcing the
 + * resizing of the gl widget by expanding some empty boxes, so the widget area size is reduced
 + * while covered by another page, so the texture viewport is still rendered over the other page
 + * but does not annoy the user that much because it's just a line on the bottom that may even
 + * be printed over existing bottom frame or very close to it. */
 +void TextureBrowser_showGLWidget(){
 +      TextureBrowser &textureBrowser = GlobalTextureBrowser();
 +      if ( isWindowConstructed && isGLWidgetConstructed )
 +      {
 +              textureBrowser.m_vframe.set_child_packing( textureBrowser.m_vfiller, FALSE, FALSE, 0, ui::Packing::START );
 +              textureBrowser.m_vframe.set_child_packing( textureBrowser.m_hframe, TRUE, TRUE, 0, ui::Packing::START );
 +              textureBrowser.m_vframe.set_child_packing( textureBrowser.m_hfiller, FALSE, FALSE, 0, ui::Packing::START );
 +              textureBrowser.m_vframe.set_child_packing( textureBrowser.m_gl_widget, TRUE, TRUE, 0, ui::Packing::START );
  
 -      g_TextureBrowser.m_gl_widget.unref();
 +              textureBrowser.m_gl_widget.show();
 +}
  }
  
 +void TextureBrowser_hideGLWidget(){
 +      TextureBrowser &textureBrowser = GlobalTextureBrowser();
 +      if ( isWindowConstructed && isGLWidgetConstructed )
 +      {
 +              textureBrowser.m_vframe.set_child_packing( textureBrowser.m_vfiller, TRUE, TRUE, 0, ui::Packing::START);
 +              textureBrowser.m_vframe.set_child_packing( textureBrowser.m_hframe, FALSE, FALSE, 0, ui::Packing::END );
 +              textureBrowser.m_vframe.set_child_packing( textureBrowser.m_hfiller, TRUE, TRUE, 0, ui::Packing::START);
 +              textureBrowser.m_vframe.set_child_packing( textureBrowser.m_gl_widget, FALSE, FALSE, 0, ui::Packing::END );
 +
 +              // The hack needs the GL widget to not be hidden to work,
 +              // so resizing it triggers the redraw of it with the new size.
 +              // GlobalTextureBrowser().m_gl_widget.hide();
 +
 +              // Trigger the redraw.
 +              TextureBrowser_redraw( &GlobalTextureBrowser() );
 +              ui::process();
 +      }
 +}
 +#endif // WORKAROUND_MACOS_GTK2_GLWIDGET
 +
  const Vector3& TextureBrowser_getBackgroundColour( TextureBrowser& textureBrowser ){
        return textureBrowser.color_textureback;
  }
@@@ -2524,7 -2340,7 +2522,7 @@@ void TextureBrowser_selectionHelper( ui
  }
  
  void TextureBrowser_shaderInfo(){
 -      const char* name = TextureBrowser_GetSelectedShader( g_TextureBrowser );
 +      const char* name = TextureBrowser_GetSelectedShader( GlobalTextureBrowser() );
        IShader* shader = QERApp_Shader_ForName( name );
  
        DoShaderInfoDlg( name, shader->getShaderFileName(), "Shader Info" );
  
  void TextureBrowser_addTag(){
        CopiedString tag;
 +      TextureBrowser &textureBrowser = GlobalTextureBrowser();
  
        EMessageBoxReturn result = DoShaderTagDlg( &tag, "Add shader tag" );
  
        if ( result == eIDOK && !tag.empty() ) {
                GtkTreeIter iter;
 -              g_TextureBrowser.m_all_tags.insert( tag.c_str() );
 -              gtk_list_store_append( g_TextureBrowser.m_available_store, &iter );
 -              gtk_list_store_set( g_TextureBrowser.m_available_store, &iter, TAG_COLUMN, tag.c_str(), -1 );
 +              textureBrowser.m_all_tags.insert( tag.c_str() );
 +              gtk_list_store_append( textureBrowser.m_available_store, &iter );
 +              gtk_list_store_set( textureBrowser.m_available_store, &iter, TAG_COLUMN, tag.c_str(), -1 );
  
                // Select the currently added tag in the available list
 -        auto selection = gtk_tree_view_get_selection(g_TextureBrowser.m_available_tree );
 +        auto selection = gtk_tree_view_get_selection(textureBrowser.m_available_tree );
                gtk_tree_selection_select_iter( selection, &iter );
  
 -              g_TextureBrowser.m_all_tags_list.append(TAG_COLUMN, tag.c_str());
 +              textureBrowser.m_all_tags_list.append(TAG_COLUMN, tag.c_str());
        }
  }
  
@@@ -2561,9 -2376,8 +2559,9 @@@ void TextureBrowser_renameTag()
         */
  
        GSList* selected = NULL;
 +      TextureBrowser &textureBrowser = GlobalTextureBrowser();
  
 -    auto selection = gtk_tree_view_get_selection(g_TextureBrowser.m_treeViewTags );
 +      auto selection = gtk_tree_view_get_selection(textureBrowser.m_treeViewTags );
        gtk_tree_selection_selected_foreach( selection, GtkTreeSelectionForeachFunc( TextureBrowser_selectionHelper ), &selected );
  
        if ( g_slist_length( selected ) == 1 ) { // we only rename a single tag
                        gchar* rowTag;
                        gchar* oldTag = (char*)selected->data;
  
 -                      bool row = gtk_tree_model_get_iter_first(g_TextureBrowser.m_all_tags_list, &iterList ) != 0;
 +                      bool row = gtk_tree_model_get_iter_first(textureBrowser.m_all_tags_list, &iterList ) != 0;
  
                        while ( row )
                        {
 -                              gtk_tree_model_get(g_TextureBrowser.m_all_tags_list, &iterList, TAG_COLUMN, &rowTag, -1 );
 +                              gtk_tree_model_get(textureBrowser.m_all_tags_list, &iterList, TAG_COLUMN, &rowTag, -1 );
  
                                if ( strcmp( rowTag, oldTag ) == 0 ) {
 -                                      gtk_list_store_set( g_TextureBrowser.m_all_tags_list, &iterList, TAG_COLUMN, newTag.c_str(), -1 );
 +                                      gtk_list_store_set( textureBrowser.m_all_tags_list, &iterList, TAG_COLUMN, newTag.c_str(), -1 );
                                }
 -                              row = gtk_tree_model_iter_next(g_TextureBrowser.m_all_tags_list, &iterList ) != 0;
 +                              row = gtk_tree_model_iter_next(textureBrowser.m_all_tags_list, &iterList ) != 0;
                        }
  
                        TagBuilder.RenameShaderTag( oldTag, newTag.c_str() );
  
 -                      g_TextureBrowser.m_all_tags.erase( (CopiedString)oldTag );
 -                      g_TextureBrowser.m_all_tags.insert( newTag );
 +                      textureBrowser.m_all_tags.erase( (CopiedString)oldTag );
 +                      textureBrowser.m_all_tags.insert( newTag );
  
 -                      BuildStoreAssignedTags( g_TextureBrowser.m_assigned_store, g_TextureBrowser.shader.c_str(), &g_TextureBrowser );
 -                      BuildStoreAvailableTags( g_TextureBrowser.m_available_store, g_TextureBrowser.m_assigned_store, g_TextureBrowser.m_all_tags, &g_TextureBrowser );
 +                      BuildStoreAssignedTags( textureBrowser.m_assigned_store, textureBrowser.shader.c_str(), &textureBrowser );
 +                      BuildStoreAvailableTags( textureBrowser.m_available_store, textureBrowser.m_assigned_store, textureBrowser.m_all_tags, &textureBrowser );
                }
        }
        else
        {
 -              ui::alert( g_TextureBrowser.m_parent, "Select a single tag for renaming." );
 +              ui::alert( textureBrowser.m_parent, "Select a single tag for renaming." );
        }
  }
  
  void TextureBrowser_deleteTag(){
        GSList* selected = NULL;
 +      TextureBrowser &textureBrowser = GlobalTextureBrowser();
  
 -    auto selection = gtk_tree_view_get_selection(g_TextureBrowser.m_treeViewTags );
 +      auto selection = gtk_tree_view_get_selection(textureBrowser.m_treeViewTags );
        gtk_tree_selection_selected_foreach( selection, GtkTreeSelectionForeachFunc( TextureBrowser_selectionHelper ), &selected );
  
        if ( g_slist_length( selected ) == 1 ) { // we only delete a single tag
 -              auto result = ui::alert( g_TextureBrowser.m_parent, "Are you sure you want to delete the selected tag?", "Delete Tag", ui::alert_type::YESNO, ui::alert_icon::Question );
 +              auto result = ui::alert( textureBrowser.m_parent, "Are you sure you want to delete the selected tag?", "Delete Tag", ui::alert_type::YESNO, ui::alert_icon::Question );
  
                if ( result == ui::alert_response::YES ) {
                        GtkTreeIter iterSelected;
  
                        gchar* tagSelected = (char*)selected->data;
  
 -                      bool row = gtk_tree_model_get_iter_first(g_TextureBrowser.m_all_tags_list, &iterSelected ) != 0;
 +                      bool row = gtk_tree_model_get_iter_first(textureBrowser.m_all_tags_list, &iterSelected ) != 0;
  
                        while ( row )
                        {
 -                              gtk_tree_model_get(g_TextureBrowser.m_all_tags_list, &iterSelected, TAG_COLUMN, &rowTag, -1 );
 +                              gtk_tree_model_get(textureBrowser.m_all_tags_list, &iterSelected, TAG_COLUMN, &rowTag, -1 );
  
                                if ( strcmp( rowTag, tagSelected ) == 0 ) {
 -                                      gtk_list_store_remove( g_TextureBrowser.m_all_tags_list, &iterSelected );
 +                                      gtk_list_store_remove( textureBrowser.m_all_tags_list, &iterSelected );
                                        break;
                                }
 -                              row = gtk_tree_model_iter_next(g_TextureBrowser.m_all_tags_list, &iterSelected ) != 0;
 +                              row = gtk_tree_model_iter_next(textureBrowser.m_all_tags_list, &iterSelected ) != 0;
                        }
  
                        TagBuilder.DeleteTag( tagSelected );
 -                      g_TextureBrowser.m_all_tags.erase( (CopiedString)tagSelected );
 +                      textureBrowser.m_all_tags.erase( (CopiedString)tagSelected );
  
 -                      BuildStoreAssignedTags( g_TextureBrowser.m_assigned_store, g_TextureBrowser.shader.c_str(), &g_TextureBrowser );
 -                      BuildStoreAvailableTags( g_TextureBrowser.m_available_store, g_TextureBrowser.m_assigned_store, g_TextureBrowser.m_all_tags, &g_TextureBrowser );
 +                      BuildStoreAssignedTags( textureBrowser.m_assigned_store, textureBrowser.shader.c_str(), &textureBrowser );
 +                      BuildStoreAvailableTags( textureBrowser.m_available_store, textureBrowser.m_assigned_store, textureBrowser.m_all_tags, &textureBrowser );
                }
        }
        else {
 -              ui::alert( g_TextureBrowser.m_parent, "Select a single tag for deletion." );
 +              ui::alert( textureBrowser.m_parent, "Select a single tag for deletion." );
        }
  }
  
  void TextureBrowser_copyTag(){
 -      g_TextureBrowser.m_copied_tags.clear();
 -      TagBuilder.GetShaderTags( g_TextureBrowser.shader.c_str(), g_TextureBrowser.m_copied_tags );
 +      TextureBrowser &textureBrowser = GlobalTextureBrowser();
 +      textureBrowser.m_copied_tags.clear();
 +      TagBuilder.GetShaderTags( textureBrowser.shader.c_str(), textureBrowser.m_copied_tags );
  }
  
  void TextureBrowser_pasteTag(){
 -      IShader* ishader = QERApp_Shader_ForName( g_TextureBrowser.shader.c_str() );
 -      CopiedString shader = g_TextureBrowser.shader.c_str();
 +      TextureBrowser &textureBrowser = GlobalTextureBrowser();
 +      IShader* ishader = QERApp_Shader_ForName( textureBrowser.shader.c_str() );
 +      CopiedString shader = textureBrowser.shader.c_str();
  
        if ( !TagBuilder.CheckShaderTag( shader.c_str() ) ) {
                CopiedString shaderFile = ishader->getShaderFileName();
                        TagBuilder.AddShaderNode( shader.c_str(), CUSTOM, SHADER );
                }
  
 -              for ( size_t i = 0; i < g_TextureBrowser.m_copied_tags.size(); ++i )
 +              for ( size_t i = 0; i < textureBrowser.m_copied_tags.size(); ++i )
                {
 -                      TagBuilder.AddShaderTag( shader.c_str(), g_TextureBrowser.m_copied_tags[i].c_str(), TAG );
 +                      TagBuilder.AddShaderTag( shader.c_str(), textureBrowser.m_copied_tags[i].c_str(), TAG );
                }
        }
        else
        {
 -              for ( size_t i = 0; i < g_TextureBrowser.m_copied_tags.size(); ++i )
 +              for ( size_t i = 0; i < textureBrowser.m_copied_tags.size(); ++i )
                {
 -                      if ( !TagBuilder.CheckShaderTag( shader.c_str(), g_TextureBrowser.m_copied_tags[i].c_str() ) ) {
 +                      if ( !TagBuilder.CheckShaderTag( shader.c_str(), textureBrowser.m_copied_tags[i].c_str() ) ) {
                                // the tag doesn't exist - let's add it
 -                              TagBuilder.AddShaderTag( shader.c_str(), g_TextureBrowser.m_copied_tags[i].c_str(), TAG );
 +                              TagBuilder.AddShaderTag( shader.c_str(), textureBrowser.m_copied_tags[i].c_str(), TAG );
                        }
                }
        }
        ishader->DecRef();
  
        TagBuilder.SaveXmlDoc();
 -      BuildStoreAssignedTags( g_TextureBrowser.m_assigned_store, shader.c_str(), &g_TextureBrowser );
 -      BuildStoreAvailableTags( g_TextureBrowser.m_available_store, g_TextureBrowser.m_assigned_store, g_TextureBrowser.m_all_tags, &g_TextureBrowser );
 +      BuildStoreAssignedTags( textureBrowser.m_assigned_store, shader.c_str(), &textureBrowser );
 +      BuildStoreAvailableTags( textureBrowser.m_available_store, textureBrowser.m_assigned_store, textureBrowser.m_all_tags, &textureBrowser );
  }
  
  void TextureBrowser_RefreshShaders(){
 +      TextureBrowser &textureBrowser = GlobalTextureBrowser();
        ScopeDisableScreenUpdates disableScreenUpdates( "Processing...", "Loading Shaders" );
        GlobalShaderSystem().refresh();
        UpdateAllWindows();
  }
  
  void TextureBrowser_ToggleShowShaders(){
 -      g_TextureBrowser.m_showShaders ^= 1;
 -      g_TextureBrowser.m_showshaders_item.update();
 -      TextureBrowser_queueDraw( g_TextureBrowser );
 +      GlobalTextureBrowser().m_showShaders ^= 1;
 +      GlobalTextureBrowser().m_showshaders_item.update();
 +      TextureBrowser_queueDraw( GlobalTextureBrowser() );
  }
  
  void TextureBrowser_ToggleShowShaderListOnly(){
        g_TextureBrowser_shaderlistOnly ^= 1;
 -      g_TextureBrowser.m_showshaderlistonly_item.update();
 +      GlobalTextureBrowser().m_showshaderlistonly_item.update();
  
        TextureBrowser_constructTreeStore();
  }
  
  void TextureBrowser_showAll(){
        g_TextureBrowser_currentDirectory = "";
 -      g_TextureBrowser.m_searchedTags = false;
 -      TextureBrowser_heightChanged( g_TextureBrowser );
 +      GlobalTextureBrowser().m_searchedTags = false;
 +      TextureBrowser_heightChanged( GlobalTextureBrowser() );
        TextureBrowser_updateTitle();
  }
  
  void TextureBrowser_showUntagged(){
 -      auto result = ui::alert( g_TextureBrowser.m_parent, "WARNING! This function might need a lot of memory and time. Are you sure you want to use it?", "Show Untagged", ui::alert_type::YESNO, ui::alert_icon::Warning );
 +      TextureBrowser &textureBrowser = GlobalTextureBrowser();
 +      auto result = ui::alert( textureBrowser.m_parent, "WARNING! This function might need a lot of memory and time. Are you sure you want to use it?", "Show Untagged", ui::alert_type::YESNO, ui::alert_icon::Warning );
  
        if ( result == ui::alert_response::YES ) {
 -              g_TextureBrowser.m_found_shaders.clear();
 -              TagBuilder.GetUntagged( g_TextureBrowser.m_found_shaders );
 +              textureBrowser.m_found_shaders.clear();
 +              TagBuilder.GetUntagged( textureBrowser.m_found_shaders );
                std::set<CopiedString>::iterator iter;
  
                ScopeDisableScreenUpdates disableScreenUpdates( "Searching untagged textures...", "Loading Textures" );
  
 -              for ( iter = g_TextureBrowser.m_found_shaders.begin(); iter != g_TextureBrowser.m_found_shaders.end(); iter++ )
 +              for ( iter = textureBrowser.m_found_shaders.begin(); iter != textureBrowser.m_found_shaders.end(); iter++ )
                {
                        std::string path = ( *iter ).c_str();
                        size_t pos = path.find_last_of( "/", path.size() );
  
                g_TextureBrowser_currentDirectory = "Untagged";
                TextureBrowser_queueDraw( GlobalTextureBrowser() );
 -              TextureBrowser_heightChanged( g_TextureBrowser );
 +              TextureBrowser_heightChanged( textureBrowser );
                TextureBrowser_updateTitle();
        }
  }
@@@ -2844,7 -2653,7 +2842,7 @@@ struct TextureScale 
  
  struct UniformTextureSize {
        static void Export(const TextureBrowser &self, const Callback<void(int)> &returnz) {
 -              returnz(g_TextureBrowser.m_uniformTextureSize);
 +              returnz(GlobalTextureBrowser().m_uniformTextureSize);
        }
  
        static void Import(TextureBrowser &self, int value) {
  
  struct UniformTextureMinSize {
        static void Export(const TextureBrowser &self, const Callback<void(int)> &returnz) {
 -              returnz(g_TextureBrowser.m_uniformTextureMinSize);
 +              returnz(GlobalTextureBrowser().m_uniformTextureMinSize);
        }
  
        static void Import(TextureBrowser &self, int value) {
@@@ -2881,7 -2690,7 +2879,7 @@@ void TextureBrowser_constructPreference
        page.appendSpinner( "Thumbnails Min Size", GlobalTextureBrowser().m_uniformTextureMinSize, GlobalTextureBrowser().m_uniformTextureMinSize, 16, 8192 );
        page.appendEntry( "Mousewheel Increment", GlobalTextureBrowser().m_mouseWheelScrollIncrement );
        {
 -              const char* startup_shaders[] = { "None", TextureBrowser_getComonShadersName() };
 +              const char* startup_shaders[] = { "None", TextureBrowser_getCommonShadersName() };
                page.appendCombo( "Load Shaders at Startup", reinterpret_cast<int&>( GlobalTextureBrowser().m_startupShaders ), STRING_ARRAY_RANGE( startup_shaders ) );
        }
  }
@@@ -2903,8 -2712,6 +2901,8 @@@ void TextureBrowser_registerPreferences
  void TextureClipboard_textureSelected( const char* shader );
  
  void TextureBrowser_Construct(){
 +      TextureBrowser &textureBrowser = GlobalTextureBrowser();
 +
        GlobalCommands_insert( "ShaderInfo", makeCallbackF(TextureBrowser_shaderInfo) );
        GlobalCommands_insert( "ShowUntagged", makeCallbackF(TextureBrowser_showUntagged) );
        GlobalCommands_insert( "AddTag", makeCallbackF(TextureBrowser_addTag) );
        GlobalCommands_insert( "CopyTag", makeCallbackF(TextureBrowser_copyTag) );
        GlobalCommands_insert( "PasteTag", makeCallbackF(TextureBrowser_pasteTag) );
        GlobalCommands_insert( "RefreshShaders", makeCallbackF(VFS_Refresh) );
 -      GlobalToggles_insert( "ShowInUse", makeCallbackF(TextureBrowser_ToggleHideUnused), ToggleItem::AddCallbackCaller( g_TextureBrowser.m_hideunused_item ), Accelerator( 'U' ) );
 +      GlobalToggles_insert( "ShowInUse", makeCallbackF(TextureBrowser_ToggleHideUnused), ToggleItem::AddCallbackCaller( textureBrowser.m_hideunused_item ), Accelerator( 'U' ) );
        GlobalCommands_insert( "ShowAllTextures", makeCallbackF(TextureBrowser_showAll), Accelerator( 'A', (GdkModifierType)GDK_CONTROL_MASK ) );
        GlobalCommands_insert( "ToggleTextures", makeCallbackF(TextureBrowser_toggleShow), Accelerator( 'T' ) );
 -      GlobalToggles_insert( "ToggleShowShaders", makeCallbackF(TextureBrowser_ToggleShowShaders), ToggleItem::AddCallbackCaller( g_TextureBrowser.m_showshaders_item ) );
 -      GlobalToggles_insert( "ToggleShowShaderlistOnly", makeCallbackF(TextureBrowser_ToggleShowShaderListOnly), ToggleItem::AddCallbackCaller( g_TextureBrowser.m_showshaderlistonly_item ) );
 -      GlobalToggles_insert( "FixedSize", makeCallbackF(TextureBrowser_FixedSize), ToggleItem::AddCallbackCaller( g_TextureBrowser.m_fixedsize_item ) );
 -      GlobalToggles_insert( "FilterMissing", makeCallbackF(TextureBrowser_FilterMissing), ToggleItem::AddCallbackCaller( g_TextureBrowser.m_filternotex_item ) );
 -      GlobalToggles_insert( "FilterFallback", makeCallbackF(TextureBrowser_FilterFallback), ToggleItem::AddCallbackCaller( g_TextureBrowser.m_hidenotex_item ) );
 -      GlobalToggles_insert( "EnableAlpha", makeCallbackF(TextureBrowser_EnableAlpha), ToggleItem::AddCallbackCaller( g_TextureBrowser.m_enablealpha_item ) );
 -
 -      GlobalPreferenceSystem().registerPreference( "TextureScale", make_property_string<TextureScale>(g_TextureBrowser) );
 -      GlobalPreferenceSystem().registerPreference( "UniformTextureSize", make_property_string<UniformTextureSize>(g_TextureBrowser) );
 -      GlobalPreferenceSystem().registerPreference( "UniformTextureMinSize", make_property_string<UniformTextureMinSize>(g_TextureBrowser) );
 -      GlobalPreferenceSystem().registerPreference( "TextureScrollbar", make_property_string<TextureBrowser_ShowScrollbar>(GlobalTextureBrowser()));
 -      GlobalPreferenceSystem().registerPreference( "ShowShaders", make_property_string( GlobalTextureBrowser().m_showShaders ) );
 +      GlobalToggles_insert( "ToggleShowShaders", makeCallbackF(TextureBrowser_ToggleShowShaders), ToggleItem::AddCallbackCaller( textureBrowser.m_showshaders_item ) );
 +      GlobalToggles_insert( "ToggleShowShaderlistOnly", makeCallbackF(TextureBrowser_ToggleShowShaderListOnly), ToggleItem::AddCallbackCaller( textureBrowser.m_showshaderlistonly_item ) );
 +      GlobalToggles_insert( "FixedSize", makeCallbackF(TextureBrowser_FixedSize), ToggleItem::AddCallbackCaller( textureBrowser.m_fixedsize_item ) );
 +      GlobalToggles_insert( "FilterMissing", makeCallbackF(TextureBrowser_FilterMissing), ToggleItem::AddCallbackCaller( textureBrowser.m_filternotex_item ) );
 +      GlobalToggles_insert( "FilterFallback", makeCallbackF(TextureBrowser_FilterFallback), ToggleItem::AddCallbackCaller( textureBrowser.m_hidenotex_item ) );
 +      GlobalToggles_insert( "EnableAlpha", makeCallbackF(TextureBrowser_EnableAlpha), ToggleItem::AddCallbackCaller( textureBrowser.m_enablealpha_item ) );
 +
 +      GlobalPreferenceSystem().registerPreference( "TextureScale", make_property_string<TextureScale>(textureBrowser) );
 +      GlobalPreferenceSystem().registerPreference( "UniformTextureSize", make_property_string<UniformTextureSize>(textureBrowser) );
 +      GlobalPreferenceSystem().registerPreference( "UniformTextureMinSize", make_property_string<UniformTextureMinSize>(textureBrowser) );
 +      GlobalPreferenceSystem().registerPreference( "TextureScrollbar", make_property_string<TextureBrowser_ShowScrollbar>(textureBrowser));
 +      GlobalPreferenceSystem().registerPreference( "ShowShaders", make_property_string( textureBrowser.m_showShaders ) );
        GlobalPreferenceSystem().registerPreference( "ShowShaderlistOnly", make_property_string( g_TextureBrowser_shaderlistOnly ) );
        GlobalPreferenceSystem().registerPreference( "FixedSize", make_property_string( g_TextureBrowser_fixedSize ) );
        GlobalPreferenceSystem().registerPreference( "FilterMissing", make_property_string( g_TextureBrowser_filterMissing ) );
        GlobalPreferenceSystem().registerPreference( "EnableAlpha", make_property_string( g_TextureBrowser_enableAlpha ) );
 -      GlobalPreferenceSystem().registerPreference( "LoadShaders", make_property_string( reinterpret_cast<int&>( GlobalTextureBrowser().m_startupShaders ) ) );
 -      GlobalPreferenceSystem().registerPreference( "WheelMouseInc", make_property_string( GlobalTextureBrowser().m_mouseWheelScrollIncrement ) );
 -      GlobalPreferenceSystem().registerPreference( "SI_Colors0", make_property_string( GlobalTextureBrowser().color_textureback ) );
 +      GlobalPreferenceSystem().registerPreference( "LoadShaders", make_property_string( reinterpret_cast<int&>( textureBrowser.m_startupShaders ) ) );
 +      GlobalPreferenceSystem().registerPreference( "WheelMouseInc", make_property_string( textureBrowser.m_mouseWheelScrollIncrement ) );
 +      GlobalPreferenceSystem().registerPreference( "SI_Colors0", make_property_string( textureBrowser.color_textureback ) );
  
 -      g_TextureBrowser.shader = texdef_name_default();
 +      textureBrowser.shader = texdef_name_default();
  
 -      Textures_setModeChangedNotify( ReferenceCaller<TextureBrowser, void(), TextureBrowser_queueDraw>( g_TextureBrowser ) );
 +      Textures_setModeChangedNotify( ReferenceCaller<TextureBrowser, void(), TextureBrowser_queueDraw>( textureBrowser ) );
  
        TextureBrowser_registerPreferencesPage();
  
@@@ -2952,9 -2759,3 +2950,9 @@@ void TextureBrowser_Destroy()
  
        Textures_setModeChangedNotify( Callback<void()>() );
  }
 +
 +#if WORKAROUND_WINDOWS_GTK2_GLWIDGET
 +ui::GLArea TextureBrowser_getGLWidget(){
 +      return GlobalTextureBrowser().m_gl_widget;
 +}
 +#endif // WORKAROUND_WINDOWS_GTK2_GLWIDGET
index db3a46bb6f0e6ca5a30f26a758408dc5c2cf6547,33583126e0c4ffbc8a72c4cf97205c5880842217..55d358f0e69b65c9d5aa859bcb5036f12beb3d98
@@@ -68,14 -68,19 +68,19 @@@ void IncDrawVerts()
  
        }
        else if ( numBSPDrawVerts > numBSPDrawVertsBuffer ) {
+               bspDrawVert_t *newBspDrawVerts;
                numBSPDrawVertsBuffer *= 3; // multiply by 1.5
                numBSPDrawVertsBuffer /= 2;
  
-               bspDrawVerts = realloc( bspDrawVerts, sizeof( bspDrawVert_t ) * numBSPDrawVertsBuffer );
+               newBspDrawVerts = realloc( bspDrawVerts, sizeof( bspDrawVert_t ) * numBSPDrawVertsBuffer );
  
-               if ( !bspDrawVerts ) {
+               if ( !newBspDrawVerts ) {
+                       free (bspDrawVerts);
                        Error( "realloc() failed (IncDrawVerts)" );
                }
+               bspDrawVerts = newBspDrawVerts;
        }
  
        memset( bspDrawVerts + ( numBSPDrawVerts - 1 ), 0, sizeof( bspDrawVert_t ) );
@@@ -89,7 -94,9 +94,7 @@@ void SetDrawVerts( int n )
        numBSPDrawVerts = n;
        numBSPDrawVertsBuffer = numBSPDrawVerts;
  
 -      bspDrawVerts = safe_malloc_info( sizeof( bspDrawVert_t ) * numBSPDrawVertsBuffer, "IncDrawVerts" );
 -
 -      memset( bspDrawVerts, 0, n * sizeof( bspDrawVert_t ) );
 +      bspDrawVerts = safe_malloc0_info( sizeof( bspDrawVert_t ) * numBSPDrawVertsBuffer, "IncDrawVerts" );
  }
  
  int numBSPDrawSurfacesBuffer = 0;
@@@ -100,7 -107,9 +105,7 @@@ void SetDrawSurfacesBuffer()
  
        numBSPDrawSurfacesBuffer = MAX_MAP_DRAW_SURFS;
  
 -      bspDrawSurfaces = safe_malloc_info( sizeof( bspDrawSurface_t ) * numBSPDrawSurfacesBuffer, "IncDrawSurfaces" );
 -
 -      memset( bspDrawSurfaces, 0, MAX_MAP_DRAW_SURFS * sizeof( bspDrawSurface_t ) );
 +      bspDrawSurfaces = safe_malloc0_info( sizeof( bspDrawSurface_t ) * numBSPDrawSurfacesBuffer, "IncDrawSurfaces" );
  }
  
  void SetDrawSurfaces( int n ){
        numBSPDrawSurfaces = n;
        numBSPDrawSurfacesBuffer = numBSPDrawSurfaces;
  
 -      bspDrawSurfaces = safe_malloc_info( sizeof( bspDrawSurface_t ) * numBSPDrawSurfacesBuffer, "IncDrawSurfaces" );
 -
 -      memset( bspDrawSurfaces, 0, n * sizeof( bspDrawSurface_t ) );
 +      bspDrawSurfaces = safe_malloc0_info( sizeof( bspDrawSurface_t ) * numBSPDrawSurfacesBuffer, "IncDrawSurfaces" );
  }
  
  void BSPFilesCleanup(){
@@@ -339,16 -350,14 +344,16 @@@ int CopyLump_Allocate( bspHeader_t *hea
  void AddLump( FILE *file, bspHeader_t *header, int lumpNum, const void *data, int length ){
        bspLump_t   *lump;
  
 -
        /* add lump to bsp file header */
        lump = &header->lumps[ lumpNum ];
        lump->offset = LittleLong( ftell( file ) );
        lump->length = LittleLong( length );
  
        /* write lump to file */
 -      SafeWrite( file, data, ( length + 3 ) & ~3 );
 +      SafeWrite( file, data, length );
 +
 +      /* write padding zeros */
 +      SafeWrite( file, (const byte[3]){ 0, 0, 0 }, ( ( length + 3 ) & ~3 ) - length );
  }
  
  
@@@ -527,7 -536,8 +532,7 @@@ epair_t *ParseEPair( void )
  
  
        /* allocate and clear new epair */
 -      e = safe_malloc( sizeof( epair_t ) );
 -      memset( e, 0, sizeof( epair_t ) );
 +      e = safe_malloc0( sizeof( epair_t ) );
  
        /* handle key */
        if ( strlen( token ) >= ( MAX_KEY - 1 ) ) {
@@@ -642,9 -652,6 +647,9 @@@ if (nocmdline
  
        for ( i = beginArgs; i < endArgs; ++i )
        {
 +              if ( argv[i] == NULL ) {
 +                      continue;
 +              }
                if ( outpos != sentinel && i != beginArgs ) {
                        *outpos++ = ' ';
                }
index 18d1f0a4c236650d2de4e718fe58ca581efdde24,478819e7a3abcccd4ac1e8f7d6ea9f943c0b5c62..7858116d84a41a71ed58a26f100a2101f0f97b8e
@@@ -185,33 -185,16 +185,33 @@@ static void RadClipWindingEpsilon( radW
        }
  
        /* error check */
-       if ( front->numVerts > maxPoints || front->numVerts > maxPoints ) {
+       if ( front->numVerts > maxPoints ) {
                Error( "RadClipWindingEpsilon: points exceeded estimate" );
        }
-       if ( front->numVerts > MAX_POINTS_ON_WINDING || front->numVerts > MAX_POINTS_ON_WINDING ) {
+       if ( front->numVerts > MAX_POINTS_ON_WINDING ) {
                Error( "RadClipWindingEpsilon: MAX_POINTS_ON_WINDING" );
        }
  }
  
  
  
 +/*
 +   Modulo1IfNegative()
 +   Previously the bias computation was doing:
 +
 +      while ( f < 0.0f ) {
 +         f += 1.0f;
 +      }
 +
 +   That may end in infinite loop in some case.
 +   It may also be slower because of useless loops.
 +   I don't know what that computation is for.
 +   -- illwieckz
 +*/
 +float Modulo1IfNegative( float f ){
 +      return f < 0.0f ? f - floor( f ) : f;
 +}
 +
  
  
  /*
   */
  
  qboolean RadSampleImage( byte *pixels, int width, int height, float st[ 2 ], float color[ 4 ] ){
 -      float sto[ 2 ];
        int x, y;
  
 -
        /* clear color first */
        color[ 0 ] = color[ 1 ] = color[ 2 ] = color[ 3 ] = 255;
  
                return qfalse;
        }
  
 -      /* bias st */
 -      sto[ 0 ] = st[ 0 ];
 -      while ( sto[ 0 ] < 0.0f )
 -              sto[ 0 ] += 1.0f;
 -      sto[ 1 ] = st[ 1 ];
 -      while ( sto[ 1 ] < 0.0f )
 -              sto[ 1 ] += 1.0f;
 -
        /* get offsets */
 -      x = ( (float) width * sto[ 0 ] ) + 0.5f;
 +      x = ( (float) width * Modulo1IfNegative( st[ 0 ] ) ) + 0.5f;
        x %= width;
 -      y = ( (float) height * sto[ 1 ] )  + 0.5f;
 +      y = ( (float) height * Modulo1IfNegative( st[ 1 ] ) ) + 0.5f;
        y %= height;
  
        /* get pixel */
@@@ -295,7 -288,7 +295,7 @@@ static void RadSample( int lightmapNum
                        /* multiply by texture color */
                        if ( !RadSampleImage( si->lightImage->pixels, si->lightImage->width, si->lightImage->height, rw->verts[ samples ].st, textureColor ) ) {
                                VectorCopy( si->averageColor, textureColor );
-                               textureColor[ 4 ] = 255.0f;
+                               textureColor[ 3 ] = 255.0f;
                        }
                        avgcolor = ( textureColor[ 0 ] + textureColor[ 1 ] + textureColor[ 2 ] ) / 3;
                        for ( i = 0; i < 3; i++ )
                                                /* multiply by texture color */
                                                if ( !RadSampleImage( si->lightImage->pixels, si->lightImage->width, si->lightImage->height, st, textureColor ) ) {
                                                        VectorCopy( si->averageColor, textureColor );
-                                                       textureColor[ 4 ] = 255;
+                                                       textureColor[ 3 ] = 255;
                                                }
                                                avgcolor = ( textureColor[ 0 ] + textureColor[ 1 ] + textureColor[ 2 ] ) / 3;
                                                for ( l = 0; l < 3; l++ ){
@@@ -543,7 -536,8 +543,7 @@@ static void RadSubdivideDiffuseLight( i
        }
  
        /* create a light */
 -      light = safe_malloc( sizeof( *light ) );
 -      memset( light, 0, sizeof( *light ) );
 +      light = safe_malloc0( sizeof( *light ) );
  
        /* attach it */
        ThreadLock();
                /* optionally create a point splashsplash light for first pass */
                if ( original && si->backsplashFraction > 0 ) {
                        /* allocate a new point light */
 -                      splash = safe_malloc( sizeof( *splash ) );
 -                      memset( splash, 0, sizeof( *splash ) );
 +                      splash = safe_malloc0( sizeof( *splash ) );
                        splash->next = lights;
                        lights = splash;
  
index 7afb86a46633852d911973fa5fed0a48f3ce854d,ea36b921f8bd6a41b75be713a64286de5ae7019c..3c08c8b60d13c1223ba795bdf08a556121300bf1
@@@ -67,8 -67,6 +67,8 @@@ void WriteTGA24( char *filename, byte *
  
        /* allocate a buffer and set it up */
        buffer = safe_malloc( width * height * 3 + 18 );
 +      /* we may also use safe_malloc0 on the whole instead,
 +       * this would just be a bit slower */
        memset( buffer, 0, 18 );
        buffer[ 2 ] = 2;
        buffer[ 12 ] = width & 255;
@@@ -155,7 -153,7 +155,7 @@@ void ExportLightmaps( void )
  
  int ExportLightmapsMain( int argc, char **argv ){
        /* arg checking */
 -      if ( argc < 1 ) {
 +      if ( argc < 2 ) {
                Sys_Printf( "Usage: q3map -export [-v] <mapname>\n" );
                return 0;
        }
@@@ -190,7 -188,7 +190,7 @@@ int ImportLightmapsMain( int argc, cha
  
  
        /* arg checking */
 -      if ( argc < 1 ) {
 +      if ( argc < 2 ) {
                Sys_Printf( "Usage: q3map -import [-v] <mapname>\n" );
                return 0;
        }
@@@ -828,7 -826,8 +828,7 @@@ qboolean AddSurfaceToRawLightmap( int n
        /* for planar surfaces, create lightmap vectors for st->xyz conversion */
        if ( VectorLength( ds->lightmapVecs[ 2 ] ) || 1 ) {  /* ydnar: can't remember what exactly i was thinking here... */
                /* allocate space for the vectors */
 -              lm->vecs = safe_malloc( 3 * sizeof( vec3_t ) );
 -              memset( lm->vecs, 0, 3 * sizeof( vec3_t ) );
 +              lm->vecs = safe_malloc0( 3 * sizeof( vec3_t ) );
                VectorCopy( ds->lightmapVecs[ 2 ], lm->vecs[ 2 ] );
  
                /* project stepped lightmap blocks and subtract to get planevecs */
@@@ -998,15 -997,18 +998,15 @@@ void SetupSurfaceLightmaps( void )
        /* allocate a list of surface clusters */
        numSurfaceClusters = 0;
        maxSurfaceClusters = numBSPLeafSurfaces;
 -      surfaceClusters = safe_malloc( maxSurfaceClusters * sizeof( *surfaceClusters ) );
 -      memset( surfaceClusters, 0, maxSurfaceClusters * sizeof( *surfaceClusters ) );
 +      surfaceClusters = safe_malloc0( maxSurfaceClusters * sizeof( *surfaceClusters ) );
  
        /* allocate a list for per-surface info */
 -      surfaceInfos = safe_malloc( numBSPDrawSurfaces * sizeof( *surfaceInfos ) );
 -      memset( surfaceInfos, 0, numBSPDrawSurfaces * sizeof( *surfaceInfos ) );
 +      surfaceInfos = safe_malloc0( numBSPDrawSurfaces * sizeof( *surfaceInfos ) );
        for ( i = 0; i < numBSPDrawSurfaces; i++ )
                surfaceInfos[ i ].childSurfaceNum = -1;
  
        /* allocate a list of surface indexes to be sorted */
 -      sortSurfaces = safe_malloc( numBSPDrawSurfaces * sizeof( int ) );
 -      memset( sortSurfaces, 0, numBSPDrawSurfaces * sizeof( int ) );
 +      sortSurfaces = safe_malloc0( numBSPDrawSurfaces * sizeof( int ) );
  
        /* walk each model in the bsp */
        for ( i = 0; i < numBSPModels; i++ )
  
        /* allocate a list of surfaces that would go into raw lightmaps */
        numLightSurfaces = 0;
 -      lightSurfaces = safe_malloc( numSurfsLightmapped * sizeof( int ) );
 -      memset( lightSurfaces, 0, numSurfsLightmapped * sizeof( int ) );
 +      lightSurfaces = safe_malloc0( numSurfsLightmapped * sizeof( int ) );
  
        /* allocate a list of raw lightmaps */
        numRawSuperLuxels = 0;
        numRawLightmaps = 0;
 -      rawLightmaps = safe_malloc( numSurfsLightmapped * sizeof( *rawLightmaps ) );
 -      memset( rawLightmaps, 0, numSurfsLightmapped * sizeof( *rawLightmaps ) );
 +      rawLightmaps = safe_malloc0( numSurfsLightmapped * sizeof( *rawLightmaps ) );
  
        /* walk the list of sorted surfaces */
        for ( i = 0; i < numBSPDrawSurfaces; i++ )
        /* allocate vertex luxel storage */
        for ( k = 0; k < MAX_LIGHTMAPS; k++ )
        {
 -              vertexLuxels[ k ] = safe_malloc( numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );
 -              memset( vertexLuxels[ k ], 0, numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );
 -              radVertexLuxels[ k ] = safe_malloc( numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );
 -              memset( radVertexLuxels[ k ], 0, numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );
 +              vertexLuxels[ k ] = safe_malloc0( numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );
 +              radVertexLuxels[ k ] = safe_malloc0( numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );
        }
  
        /* emit some stats */
@@@ -1973,10 -1979,13 +1973,10 @@@ static void SetupOutLightmap( rawLightm
        olm->numShaders = 0;
  
        /* allocate buffers */
 -      olm->lightBits = safe_malloc( ( olm->customWidth * olm->customHeight / 8 ) + 8 );
 -      memset( olm->lightBits, 0, ( olm->customWidth * olm->customHeight / 8 ) + 8 );
 -      olm->bspLightBytes = safe_malloc( olm->customWidth * olm->customHeight * 3 );
 -      memset( olm->bspLightBytes, 0, olm->customWidth * olm->customHeight * 3 );
 +      olm->lightBits = safe_malloc0( ( olm->customWidth * olm->customHeight / 8 ) + 8 );
 +      olm->bspLightBytes = safe_malloc0( olm->customWidth * olm->customHeight * 3 );
        if ( deluxemap ) {
 -              olm->bspDirBytes = safe_malloc( olm->customWidth * olm->customHeight * 3 );
 -              memset( olm->bspDirBytes, 0, olm->customWidth * olm->customHeight * 3 );
 +              olm->bspDirBytes = safe_malloc0( olm->customWidth * olm->customHeight * 3 );
        }
  }
  
@@@ -1998,6 -2007,7 +1998,6 @@@ static void FindOutLightmaps( rawLightm
        qboolean ok;
        int xIncrement, yIncrement;
  
 -
        /* set default lightmap number (-3 = LIGHTMAP_BY_VERTEX) */
        for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
                lm->outLightmapNums[ lightmapNum ] = -3;
                        /* allocate LIGHTMAP_RESERVE_COUNT new output lightmaps */
                        numOutLightmaps += LIGHTMAP_RESERVE_COUNT;
                        olm = safe_malloc( numOutLightmaps * sizeof( outLightmap_t ) );
+                       if ( !olm ){
+                               Error( "FindOutLightmaps: Failed to allocate memory.\n" );
+                       }
                        if ( outLightmaps != NULL && numOutLightmaps > LIGHTMAP_RESERVE_COUNT ) {
                                memcpy( olm, outLightmaps, ( numOutLightmaps - LIGHTMAP_RESERVE_COUNT ) * sizeof( outLightmap_t ) );
                                free( outLightmaps );
@@@ -2474,7 -2488,7 +2478,7 @@@ void FillOutLightmap( outLightmap_t *ol
     stores the surface lightmaps into the bsp as byte rgb triplets
   */
  
 -void StoreSurfaceLightmaps( qboolean fastAllocate ){
 +void StoreSurfaceLightmaps( qboolean fastAllocate, qboolean storeForReal ){
        int i, j, k, x, y, lx, ly, sx, sy, *cluster, mappedSamples;
        int style, size, lightmapNum, lightmapNum2;
        float               *normal, *luxel, *bspLuxel, *bspLuxel2, *radLuxel, samples, occludedSamples;
                        /* allocate bsp luxel storage */
                        if ( lm->bspLuxels[ lightmapNum ] == NULL ) {
                                size = lm->w * lm->h * BSP_LUXEL_SIZE * sizeof( float );
 -                              lm->bspLuxels[ lightmapNum ] = safe_malloc( size );
 -                              memset( lm->bspLuxels[ lightmapNum ], 0, size );
 +                              lm->bspLuxels[ lightmapNum ] = safe_malloc0( size );
                        }
  
                        /* allocate radiosity lightmap storage */
           collapse non-unique lightmaps
           ----------------------------------------------------------------- */
  
 -      if ( noCollapse == qfalse && deluxemap == qfalse ) {
 +      if ( storeForReal && noCollapse == qfalse && deluxemap == qfalse ) {
                /* note it */
                Sys_FPrintf( SYS_VRB, "collapsing..." );
  
           allocate output lightmaps
           ----------------------------------------------------------------- */
  
 -      /* note it */
 -      Sys_FPrintf( SYS_VRB, "allocating..." );
 +      if ( storeForReal ) {
 +              /* note it */
 +              Sys_FPrintf( SYS_VRB, "allocating..." );
  
 -      /* kill all existing output lightmaps */
 -      if ( outLightmaps != NULL ) {
 -              for ( i = 0; i < numOutLightmaps; i++ )
 -              {
 -                      free( outLightmaps[ i ].lightBits );
 -                      free( outLightmaps[ i ].bspLightBytes );
 +              /* kill all existing output lightmaps */
 +              if ( outLightmaps != NULL ) {
 +                      for ( i = 0; i < numOutLightmaps; i++ )
 +                      {
 +                              free( outLightmaps[ i ].lightBits );
 +                              free( outLightmaps[ i ].bspLightBytes );
 +                      }
 +                      free( outLightmaps );
 +                      outLightmaps = NULL;
                }
 -              free( outLightmaps );
 -              outLightmaps = NULL;
 -      }
 -
 -      numLightmapShaders = 0;
 -      numOutLightmaps = 0;
 -      numBSPLightmaps = 0;
 -      numExtLightmaps = 0;
  
 -      /* find output lightmap */
 -      for ( i = 0; i < numRawLightmaps; i++ )
 -      {
 -              lm = &rawLightmaps[ sortLightmaps[ i ] ];
 -              FindOutLightmaps( lm, fastAllocate );
 -      }
 +              numLightmapShaders = 0;
 +              numOutLightmaps = 0;
 +              numBSPLightmaps = 0;
 +              numExtLightmaps = 0;
  
 -      /* set output numbers in twinned lightmaps */
 -      for ( i = 0; i < numRawLightmaps; i++ )
 -      {
 -              /* get lightmap */
 -              lm = &rawLightmaps[ sortLightmaps[ i ] ];
 +              /* find output lightmap */
 +              for ( i = 0; i < numRawLightmaps; i++ )
 +              {
 +                      lm = &rawLightmaps[ sortLightmaps[ i ] ];
 +                      FindOutLightmaps( lm, fastAllocate );
 +              }
  
 -              /* walk lightmaps */
 -              for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
 +              /* set output numbers in twinned lightmaps */
 +              for ( i = 0; i < numRawLightmaps; i++ )
                {
 -                      /* get twin */
 -                      lm2 = lm->twins[ lightmapNum ];
 -                      if ( lm2 == NULL ) {
 -                              continue;
 -                      }
 -                      lightmapNum2 = lm->twinNums[ lightmapNum ];
 +                      /* get lightmap */
 +                      lm = &rawLightmaps[ sortLightmaps[ i ] ];
  
 -                      /* find output lightmap from twin */
 -                      lm->outLightmapNums[ lightmapNum ] = lm2->outLightmapNums[ lightmapNum2 ];
 -                      lm->lightmapX[ lightmapNum ] = lm2->lightmapX[ lightmapNum2 ];
 -                      lm->lightmapY[ lightmapNum ] = lm2->lightmapY[ lightmapNum2 ];
 +                      /* walk lightmaps */
 +                      for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
 +                      {
 +                              /* get twin */
 +                              lm2 = lm->twins[ lightmapNum ];
 +                              if ( lm2 == NULL ) {
 +                                      continue;
 +                              }
 +                              lightmapNum2 = lm->twinNums[ lightmapNum ];
 +
 +                              /* find output lightmap from twin */
 +                              lm->outLightmapNums[ lightmapNum ] = lm2->outLightmapNums[ lightmapNum2 ];
 +                              lm->lightmapX[ lightmapNum ] = lm2->lightmapX[ lightmapNum2 ];
 +                              lm->lightmapY[ lightmapNum ] = lm2->lightmapY[ lightmapNum2 ];
 +                      }
                }
        }
  
           store output lightmaps
           ----------------------------------------------------------------- */
  
 -      /* note it */
 -      Sys_FPrintf( SYS_VRB, "storing..." );
 -
 -      /* count the bsp lightmaps and allocate space */
 -      if ( bspLightBytes != NULL ) {
 -              free( bspLightBytes );
 -      }
 -      if ( numBSPLightmaps == 0 || externalLightmaps ) {
 -              numBSPLightBytes = 0;
 -              bspLightBytes = NULL;
 -      }
 -      else
 -      {
 -              numBSPLightBytes = ( numBSPLightmaps * game->lightmapSize * game->lightmapSize * 3 );
 -              bspLightBytes = safe_malloc( numBSPLightBytes );
 -              memset( bspLightBytes, 0, numBSPLightBytes );
 -      }
 -
 -      /* walk the list of output lightmaps */
 -      for ( i = 0; i < numOutLightmaps; i++ )
 -      {
 -              /* get output lightmap */
 -              olm = &outLightmaps[ i ];
 +      if ( storeForReal ) {
 +              /* note it */
 +              Sys_FPrintf( SYS_VRB, "storing..." );
  
 -              /* fill output lightmap */
 -              if ( lightmapFill ) {
 -                      FillOutLightmap( olm );
 +              /* count the bsp lightmaps and allocate space */
 +              if ( bspLightBytes != NULL ) {
 +                      free( bspLightBytes );
 +              }
 +              if ( numBSPLightmaps == 0 || externalLightmaps ) {
 +                      numBSPLightBytes = 0;
 +                      bspLightBytes = NULL;
 +              }
 +              else
 +              {
 +                      numBSPLightBytes = ( numBSPLightmaps * game->lightmapSize * game->lightmapSize * 3 );
 +                      bspLightBytes = safe_malloc0( numBSPLightBytes );
                }
  
 -              /* is this a valid bsp lightmap? */
 -              if ( olm->lightmapNum >= 0 && !externalLightmaps ) {
 -                      /* copy lighting data */
 -                      lb = bspLightBytes + ( olm->lightmapNum * game->lightmapSize * game->lightmapSize * 3 );
 -                      memcpy( lb, olm->bspLightBytes, game->lightmapSize * game->lightmapSize * 3 );
 +              /* walk the list of output lightmaps */
 +              for ( i = 0; i < numOutLightmaps; i++ )
 +              {
 +                      /* get output lightmap */
 +                      olm = &outLightmaps[ i ];
  
 -                      /* copy direction data */
 -                      if ( deluxemap ) {
 -                              lb = bspLightBytes + ( ( olm->lightmapNum + 1 ) * game->lightmapSize * game->lightmapSize * 3 );
 -                              memcpy( lb, olm->bspDirBytes, game->lightmapSize * game->lightmapSize * 3 );
 +                      /* fill output lightmap */
 +                      if ( lightmapFill ) {
 +                              FillOutLightmap( olm );
                        }
 -              }
  
 -              /* external lightmap? */
 -              if ( olm->lightmapNum < 0 || olm->extLightmapNum >= 0 || externalLightmaps ) {
 -                      /* make a directory for the lightmaps */
 -                      Q_mkdir( dirname );
 +                      /* is this a valid bsp lightmap? */
 +                      if ( olm->lightmapNum >= 0 && !externalLightmaps ) {
 +                              /* copy lighting data */
 +                              lb = bspLightBytes + ( olm->lightmapNum * game->lightmapSize * game->lightmapSize * 3 );
 +                              memcpy( lb, olm->bspLightBytes, game->lightmapSize * game->lightmapSize * 3 );
  
 -                      /* set external lightmap number */
 -                      olm->extLightmapNum = numExtLightmaps;
 +                              /* copy direction data */
 +                              if ( deluxemap ) {
 +                                      lb = bspLightBytes + ( ( olm->lightmapNum + 1 ) * game->lightmapSize * game->lightmapSize * 3 );
 +                                      memcpy( lb, olm->bspDirBytes, game->lightmapSize * game->lightmapSize * 3 );
 +                              }
 +                      }
 +
 +                      /* external lightmap? */
 +                      if ( olm->lightmapNum < 0 || olm->extLightmapNum >= 0 || externalLightmaps ) {
 +                              /* make a directory for the lightmaps */
 +                              Q_mkdir( dirname );
  
 -                      /* write lightmap */
 -                      sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, numExtLightmaps );
 -                      Sys_FPrintf( SYS_VRB, "\nwriting %s", filename );
 -                      WriteTGA24( filename, olm->bspLightBytes, olm->customWidth, olm->customHeight, qtrue );
 -                      numExtLightmaps++;
 +                              /* set external lightmap number */
 +                              olm->extLightmapNum = numExtLightmaps;
  
 -                      /* write deluxemap */
 -                      if ( deluxemap ) {
 +                              /* write lightmap */
                                sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, numExtLightmaps );
                                Sys_FPrintf( SYS_VRB, "\nwriting %s", filename );
 -                              WriteTGA24( filename, olm->bspDirBytes, olm->customWidth, olm->customHeight, qtrue );
 +                              WriteTGA24( filename, olm->bspLightBytes, olm->customWidth, olm->customHeight, qtrue );
                                numExtLightmaps++;
  
 -                              if ( debugDeluxemap ) {
 -                                      olm->extLightmapNum++;
 +                              /* write deluxemap */
 +                              if ( deluxemap ) {
 +                                      sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, numExtLightmaps );
 +                                      Sys_FPrintf( SYS_VRB, "\nwriting %s", filename );
 +                                      WriteTGA24( filename, olm->bspDirBytes, olm->customWidth, olm->customHeight, qtrue );
 +                                      numExtLightmaps++;
 +
 +                                      if ( debugDeluxemap ) {
 +                                              olm->extLightmapNum++;
 +                                      }
                                }
                        }
                }
 -      }
 -
 -      if ( numExtLightmaps > 0 ) {
 -              Sys_FPrintf( SYS_VRB, "\n" );
 -      }
  
 -      /* delete unused external lightmaps */
 -      for ( i = numExtLightmaps; i; i++ )
 -      {
 -              /* determine if file exists */
 -              sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, i );
 -              if ( !FileExists( filename ) ) {
 -                      break;
 +              if ( numExtLightmaps > 0 ) {
 +                      Sys_FPrintf( SYS_VRB, "\n" );
                }
  
 -              /* delete it */
 -              remove( filename );
 +              /* delete unused external lightmaps */
 +              for ( i = numExtLightmaps; i; i++ )
 +              {
 +                      /* determine if file exists */
 +                      sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, i );
 +                      if ( !FileExists( filename ) ) {
 +                              break;
 +                      }
 +
 +                      /* delete it */
 +                      remove( filename );
 +              }
        }
  
        /* -----------------------------------------------------------------
           project the lightmaps onto the bsp surfaces
           ----------------------------------------------------------------- */
  
 -      /* note it */
 -      Sys_FPrintf( SYS_VRB, "projecting..." );
 +      if ( storeForReal ) {
 +              /* note it */
 +              Sys_FPrintf( SYS_VRB, "projecting..." );
  
 -      /* walk the list of surfaces */
 -      for ( i = 0; i < numBSPDrawSurfaces; i++ )
 -      {
 -              /* get the surface and info */
 -              ds = &bspDrawSurfaces[ i ];
 -              info = &surfaceInfos[ i ];
 -              lm = info->lm;
 -              olm = NULL;
 -
 -              /* handle surfaces with identical parent */
 -              if ( info->parentSurfaceNum >= 0 ) {
 -                      /* preserve original data and get parent */
 -                      parent = &bspDrawSurfaces[ info->parentSurfaceNum ];
 -                      memcpy( &dsTemp, ds, sizeof( *ds ) );
 -
 -                      /* overwrite child with parent data */
 -                      memcpy( ds, parent, sizeof( *ds ) );
 -
 -                      /* restore key parts */
 -                      ds->fogNum = dsTemp.fogNum;
 -                      ds->firstVert = dsTemp.firstVert;
 -                      ds->firstIndex = dsTemp.firstIndex;
 -                      memcpy( ds->lightmapVecs, dsTemp.lightmapVecs, sizeof( dsTemp.lightmapVecs ) );
 -
 -                      /* set vertex data */
 -                      dv = &bspDrawVerts[ ds->firstVert ];
 -                      dvParent = &bspDrawVerts[ parent->firstVert ];
 -                      for ( j = 0; j < ds->numVerts; j++ )
 -                      {
 -                              memcpy( dv[ j ].lightmap, dvParent[ j ].lightmap, sizeof( dv[ j ].lightmap ) );
 -                              memcpy( dv[ j ].color, dvParent[ j ].color, sizeof( dv[ j ].color ) );
 -                      }
 +              /* walk the list of surfaces */
 +              for ( i = 0; i < numBSPDrawSurfaces; i++ )
 +              {
 +                      /* get the surface and info */
 +                      ds = &bspDrawSurfaces[ i ];
 +                      info = &surfaceInfos[ i ];
 +                      lm = info->lm;
 +                      olm = NULL;
  
 -                      /* skip the rest */
 -                      continue;
 -              }
 +                      /* handle surfaces with identical parent */
 +                      if ( info->parentSurfaceNum >= 0 ) {
 +                              /* preserve original data and get parent */
 +                              parent = &bspDrawSurfaces[ info->parentSurfaceNum ];
 +                              memcpy( &dsTemp, ds, sizeof( *ds ) );
  
 -              /* handle vertex lit or approximated surfaces */
 -              else if ( lm == NULL || lm->outLightmapNums[ 0 ] < 0 ) {
 -                      for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
 -                      {
 -                              ds->lightmapNum[ lightmapNum ] = -3;
 -                              ds->lightmapStyles[ lightmapNum ] = ds->vertexStyles[ lightmapNum ];
 -                      }
 -              }
 +                              /* overwrite child with parent data */
 +                              memcpy( ds, parent, sizeof( *ds ) );
  
 -              /* handle lightmapped surfaces */
 -              else
 -              {
 -                      /* walk lightmaps */
 -                      for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
 -                      {
 -                              /* set style */
 -                              ds->lightmapStyles[ lightmapNum ] = lm->styles[ lightmapNum ];
 +                              /* restore key parts */
 +                              ds->fogNum = dsTemp.fogNum;
 +                              ds->firstVert = dsTemp.firstVert;
 +                              ds->firstIndex = dsTemp.firstIndex;
 +                              memcpy( ds->lightmapVecs, dsTemp.lightmapVecs, sizeof( dsTemp.lightmapVecs ) );
  
 -                              /* handle unused style */
 -                              if ( lm->styles[ lightmapNum ] == LS_NONE || lm->outLightmapNums[ lightmapNum ] < 0 ) {
 +                              /* set vertex data */
 +                              dv = &bspDrawVerts[ ds->firstVert ];
 +                              dvParent = &bspDrawVerts[ parent->firstVert ];
 +                              for ( j = 0; j < ds->numVerts; j++ )
 +                              {
 +                                      memcpy( dv[ j ].lightmap, dvParent[ j ].lightmap, sizeof( dv[ j ].lightmap ) );
 +                                      memcpy( dv[ j ].color, dvParent[ j ].color, sizeof( dv[ j ].color ) );
 +                              }
 +
 +                              /* skip the rest */
 +                              continue;
 +                      }
 +
 +                      /* handle vertex lit or approximated surfaces */
 +                      else if ( lm == NULL || lm->outLightmapNums[ 0 ] < 0 ) {
 +                              for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
 +                              {
                                        ds->lightmapNum[ lightmapNum ] = -3;
 -                                      continue;
 +                                      ds->lightmapStyles[ lightmapNum ] = ds->vertexStyles[ lightmapNum ];
                                }
 +                      }
  
 -                              /* get output lightmap */
 -                              olm = &outLightmaps[ lm->outLightmapNums[ lightmapNum ] ];
 +                      /* handle lightmapped surfaces */
 +                      else
 +                      {
 +                              /* walk lightmaps */
 +                              for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
 +                              {
 +                                      /* set style */
 +                                      ds->lightmapStyles[ lightmapNum ] = lm->styles[ lightmapNum ];
  
 -                              /* set bsp lightmap number */
 -                              ds->lightmapNum[ lightmapNum ] = olm->lightmapNum;
 +                                      /* handle unused style */
 +                                      if ( lm->styles[ lightmapNum ] == LS_NONE || lm->outLightmapNums[ lightmapNum ] < 0 ) {
 +                                              ds->lightmapNum[ lightmapNum ] = -3;
 +                                              continue;
 +                                      }
  
 -                              /* deluxemap debugging makes the deluxemap visible */
 -                              if ( deluxemap && debugDeluxemap && lightmapNum == 0 ) {
 -                                      ds->lightmapNum[ lightmapNum ]++;
 -                              }
 +                                      /* get output lightmap */
 +                                      olm = &outLightmaps[ lm->outLightmapNums[ lightmapNum ] ];
  
 -                              /* calc lightmap origin in texture space */
 -                              lmx = (float) lm->lightmapX[ lightmapNum ] / (float) olm->customWidth;
 -                              lmy = (float) lm->lightmapY[ lightmapNum ] / (float) olm->customHeight;
 +                                      /* set bsp lightmap number */
 +                                      ds->lightmapNum[ lightmapNum ] = olm->lightmapNum;
  
 -                              /* calc lightmap st coords */
 -                              dv = &bspDrawVerts[ ds->firstVert ];
 -                              ydv = &yDrawVerts[ ds->firstVert ];
 -                              for ( j = 0; j < ds->numVerts; j++ )
 -                              {
 -                                      if ( lm->solid[ lightmapNum ] ) {
 -                                              dv[ j ].lightmap[ lightmapNum ][ 0 ] = lmx + ( 0.5f / (float) olm->customWidth );
 -                                              dv[ j ].lightmap[ lightmapNum ][ 1 ] = lmy + ( 0.5f / (float) olm->customWidth );
 +                                      /* deluxemap debugging makes the deluxemap visible */
 +                                      if ( deluxemap && debugDeluxemap && lightmapNum == 0 ) {
 +                                              ds->lightmapNum[ lightmapNum ]++;
                                        }
 -                                      else
 +
 +                                      /* calc lightmap origin in texture space */
 +                                      lmx = (float) lm->lightmapX[ lightmapNum ] / (float) olm->customWidth;
 +                                      lmy = (float) lm->lightmapY[ lightmapNum ] / (float) olm->customHeight;
 +
 +                                      /* calc lightmap st coords */
 +                                      dv = &bspDrawVerts[ ds->firstVert ];
 +                                      ydv = &yDrawVerts[ ds->firstVert ];
 +                                      for ( j = 0; j < ds->numVerts; j++ )
                                        {
 -                                              dv[ j ].lightmap[ lightmapNum ][ 0 ] = lmx + ( ydv[ j ].lightmap[ 0 ][ 0 ] / ( superSample * olm->customWidth ) );
 -                                              dv[ j ].lightmap[ lightmapNum ][ 1 ] = lmy + ( ydv[ j ].lightmap[ 0 ][ 1 ] / ( superSample * olm->customHeight ) );
 +                                              if ( lm->solid[ lightmapNum ] ) {
 +                                                      dv[ j ].lightmap[ lightmapNum ][ 0 ] = lmx + ( 0.5f / (float) olm->customWidth );
 +                                                      dv[ j ].lightmap[ lightmapNum ][ 1 ] = lmy + ( 0.5f / (float) olm->customWidth );
 +                                              }
 +                                              else
 +                                              {
 +                                                      dv[ j ].lightmap[ lightmapNum ][ 0 ] = lmx + ( ydv[ j ].lightmap[ 0 ][ 0 ] / ( superSample * olm->customWidth ) );
 +                                                      dv[ j ].lightmap[ lightmapNum ][ 1 ] = lmy + ( ydv[ j ].lightmap[ 0 ][ 1 ] / ( superSample * olm->customHeight ) );
 +                                              }
                                        }
                                }
                        }
 -              }
  
 -              /* store vertex colors */
 -              dv = &bspDrawVerts[ ds->firstVert ];
 -              for ( j = 0; j < ds->numVerts; j++ )
 -              {
 -                      /* walk lightmaps */
 -                      for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
 +                      /* store vertex colors */
 +                      dv = &bspDrawVerts[ ds->firstVert ];
 +                      for ( j = 0; j < ds->numVerts; j++ )
                        {
 -                              /* handle unused style */
 -                              if ( ds->vertexStyles[ lightmapNum ] == LS_NONE ) {
 -                                      VectorClear( color );
 -                              }
 -                              else
 +                              /* walk lightmaps */
 +                              for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
                                {
 -                                      /* get vertex color */
 -                                      luxel = VERTEX_LUXEL( lightmapNum, ds->firstVert + j );
 -                                      VectorCopy( luxel, color );
 +                                      /* handle unused style */
 +                                      if ( ds->vertexStyles[ lightmapNum ] == LS_NONE ) {
 +                                              VectorClear( color );
 +                                      }
 +                                      else
 +                                      {
 +                                              /* get vertex color */
 +                                              luxel = VERTEX_LUXEL( lightmapNum, ds->firstVert + j );
 +                                              VectorCopy( luxel, color );
  
 -                                      /* set minimum light */
 -                                      if ( lightmapNum == 0 ) {
 -                                              for ( k = 0; k < 3; k++ )
 -                                                      if ( color[ k ] < minVertexLight[ k ] ) {
 -                                                              color[ k ] = minVertexLight[ k ];
 -                                                      }
 +                                              /* set minimum light */
 +                                              if ( lightmapNum == 0 ) {
 +                                                      for ( k = 0; k < 3; k++ )
 +                                                              if ( color[ k ] < minVertexLight[ k ] ) {
 +                                                                      color[ k ] = minVertexLight[ k ];
 +                                                              }
 +                                              }
                                        }
 -                              }
  
 -                              /* store to bytes */
 -                              if ( !info->si->noVertexLight ) {
 -                                      ColorToBytes( color, dv[ j ].color[ lightmapNum ], info->si->vertexScale );
 +                                      /* store to bytes */
 +                                      if ( !info->si->noVertexLight ) {
 +                                              ColorToBytes( color, dv[ j ].color[ lightmapNum ], info->si->vertexScale );
 +                                      }
                                }
                        }
 -              }
 -
 -              /* surfaces with styled lightmaps and a style marker get a custom generated shader (fixme: make this work with external lightmaps) */
 -              if ( olm != NULL && lm != NULL && lm->styles[ 1 ] != LS_NONE && game->load != LoadRBSPFile ) { //%      info->si->styleMarker > 0 )
 -                      qboolean dfEqual;
 -                      char key[ 32 ], styleStage[ 512 ], styleStages[ 4096 ], rgbGen[ 128 ], alphaGen[ 128 ];
 -
  
 -                      /* setup */
 -                      sprintf( styleStages, "\n\t// Q3Map2 custom lightstyle stage(s)\n" );
 -                      dv = &bspDrawVerts[ ds->firstVert ];
 -
 -                      /* depthFunc equal? */
 -                      if ( info->si->styleMarker == 2 || info->si->implicitMap == IM_MASKED ) {
 -                              dfEqual = qtrue;
 -                      }
 -                      else{
 -                              dfEqual = qfalse;
 -                      }
 +                      /* surfaces with styled lightmaps and a style marker get a custom generated shader (fixme: make this work with external lightmaps) */
 +                      if ( olm != NULL && lm != NULL && lm->styles[ 1 ] != LS_NONE && game->load != LoadRBSPFile ) { //%      info->si->styleMarker > 0 )
 +                              qboolean dfEqual;
 +                              char key[ 32 ], styleStage[ 512 ], styleStages[ 4096 ], rgbGen[ 128 ], alphaGen[ 128 ];
  
 -                      /* generate stages for styled lightmaps */
 -                      for ( lightmapNum = 1; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
 -                      {
 -                              /* early out */
 -                              style = lm->styles[ lightmapNum ];
 -                              if ( style == LS_NONE || lm->outLightmapNums[ lightmapNum ] < 0 ) {
 -                                      continue;
 -                              }
  
 -                              /* get output lightmap */
 -                              olm = &outLightmaps[ lm->outLightmapNums[ lightmapNum ] ];
 +                              /* setup */
 +                              sprintf( styleStages, "\n\t// Q3Map2 custom lightstyle stage(s)\n" );
 +                              dv = &bspDrawVerts[ ds->firstVert ];
  
 -                              /* lightmap name */
 -                              if ( lm->outLightmapNums[ lightmapNum ] == lm->outLightmapNums[ 0 ] ) {
 -                                      strcpy( lightmapName, "$lightmap" );
 +                              /* depthFunc equal? */
 +                              if ( info->si->styleMarker == 2 || info->si->implicitMap == IM_MASKED ) {
 +                                      dfEqual = qtrue;
                                }
                                else{
 -                                      sprintf( lightmapName, "maps/%s/" EXTERNAL_LIGHTMAP, mapName, olm->extLightmapNum );
 +                                      dfEqual = qfalse;
                                }
  
 -                              /* get rgbgen string */
 -                              if ( rgbGenValues[ style ] == NULL ) {
 -                                      sprintf( key, "_style%drgbgen", style );
 -                                      rgbGenValues[ style ] = ValueForKey( &entities[ 0 ], key );
 -                                      if ( rgbGenValues[ style ][ 0 ] == '\0' ) {
 -                                              rgbGenValues[ style ] = "wave noise 0.5 1 0 5.37";
 +                              /* generate stages for styled lightmaps */
 +                              for ( lightmapNum = 1; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
 +                              {
 +                                      /* early out */
 +                                      style = lm->styles[ lightmapNum ];
 +                                      if ( style == LS_NONE || lm->outLightmapNums[ lightmapNum ] < 0 ) {
 +                                              continue;
 +                                      }
 +
 +                                      /* get output lightmap */
 +                                      olm = &outLightmaps[ lm->outLightmapNums[ lightmapNum ] ];
 +
 +                                      /* lightmap name */
 +                                      if ( lm->outLightmapNums[ lightmapNum ] == lm->outLightmapNums[ 0 ] ) {
 +                                              strcpy( lightmapName, "$lightmap" );
 +                                      }
 +                                      else{
 +                                              sprintf( lightmapName, "maps/%s/" EXTERNAL_LIGHTMAP, mapName, olm->extLightmapNum );
 +                                      }
 +
 +                                      /* get rgbgen string */
 +                                      if ( rgbGenValues[ style ] == NULL ) {
 +                                              sprintf( key, "_style%drgbgen", style );
 +                                              rgbGenValues[ style ] = ValueForKey( &entities[ 0 ], key );
 +                                              if ( rgbGenValues[ style ][ 0 ] == '\0' ) {
 +                                                      rgbGenValues[ style ] = "wave noise 0.5 1 0 5.37";
 +                                              }
                                        }
 -                              }
 -                              rgbGen[ 0 ] = '\0';
 -                              if ( rgbGenValues[ style ][ 0 ] != '\0' ) {
 -                                      sprintf( rgbGen, "\t\trgbGen %s // style %d\n", rgbGenValues[ style ], style );
 -                              }
 -                              else{
                                        rgbGen[ 0 ] = '\0';
 -                              }
 +                                      if ( rgbGenValues[ style ][ 0 ] != '\0' ) {
 +                                              sprintf( rgbGen, "\t\trgbGen %s // style %d\n", rgbGenValues[ style ], style );
 +                                      }
 +                                      else{
 +                                              rgbGen[ 0 ] = '\0';
 +                                      }
  
 -                              /* get alphagen string */
 -                              if ( alphaGenValues[ style ] == NULL ) {
 -                                      sprintf( key, "_style%dalphagen", style );
 -                                      alphaGenValues[ style ] = ValueForKey( &entities[ 0 ], key );
 -                              }
 -                              if ( alphaGenValues[ style ][ 0 ] != '\0' ) {
 -                                      sprintf( alphaGen, "\t\talphaGen %s // style %d\n", alphaGenValues[ style ], style );
 -                              }
 -                              else{
 -                                      alphaGen[ 0 ] = '\0';
 -                              }
 +                                      /* get alphagen string */
 +                                      if ( alphaGenValues[ style ] == NULL ) {
 +                                              sprintf( key, "_style%dalphagen", style );
 +                                              alphaGenValues[ style ] = ValueForKey( &entities[ 0 ], key );
 +                                      }
 +                                      if ( alphaGenValues[ style ][ 0 ] != '\0' ) {
 +                                              sprintf( alphaGen, "\t\talphaGen %s // style %d\n", alphaGenValues[ style ], style );
 +                                      }
 +                                      else{
 +                                              alphaGen[ 0 ] = '\0';
 +                                      }
  
 -                              /* calculate st offset */
 -                              lmx = dv[ 0 ].lightmap[ lightmapNum ][ 0 ] - dv[ 0 ].lightmap[ 0 ][ 0 ];
 -                              lmy = dv[ 0 ].lightmap[ lightmapNum ][ 1 ] - dv[ 0 ].lightmap[ 0 ][ 1 ];
 -
 -                              /* create additional stage */
 -                              if ( lmx == 0.0f && lmy == 0.0f ) {
 -                                      sprintf( styleStage,    "\t{\n"
 -                                                                                      "\t\tmap %s\n"                                      /* lightmap */
 -                                                                                      "\t\tblendFunc GL_SRC_ALPHA GL_ONE\n"
 -                                                                                      "%s"                                                /* depthFunc equal */
 -                                                                                      "%s"                                                /* rgbGen */
 -                                                                                      "%s"                                                /* alphaGen */
 -                                                                                      "\t\ttcGen lightmap\n"
 -                                                                                      "\t}\n",
 -                                                       lightmapName,
 -                                                       ( dfEqual ? "\t\tdepthFunc equal\n" : "" ),
 -                                                       rgbGen,
 -                                                       alphaGen );
 +                                      /* calculate st offset */
 +                                      lmx = dv[ 0 ].lightmap[ lightmapNum ][ 0 ] - dv[ 0 ].lightmap[ 0 ][ 0 ];
 +                                      lmy = dv[ 0 ].lightmap[ lightmapNum ][ 1 ] - dv[ 0 ].lightmap[ 0 ][ 1 ];
 +
 +                                      /* create additional stage */
 +                                      if ( lmx == 0.0f && lmy == 0.0f ) {
 +                                              sprintf( styleStage,    "\t{\n"
 +                                                                                              "\t\tmap %s\n"                                      /* lightmap */
 +                                                                                              "\t\tblendFunc GL_SRC_ALPHA GL_ONE\n"
 +                                                                                              "%s"                                                /* depthFunc equal */
 +                                                                                              "%s"                                                /* rgbGen */
 +                                                                                              "%s"                                                /* alphaGen */
 +                                                                                              "\t\ttcGen lightmap\n"
 +                                                                                              "\t}\n",
 +                                                               lightmapName,
 +                                                               ( dfEqual ? "\t\tdepthFunc equal\n" : "" ),
 +                                                               rgbGen,
 +                                                               alphaGen );
 +                                      }
 +                                      else
 +                                      {
 +                                              sprintf( styleStage,    "\t{\n"
 +                                                                                              "\t\tmap %s\n"                                      /* lightmap */
 +                                                                                              "\t\tblendFunc GL_SRC_ALPHA GL_ONE\n"
 +                                                                                              "%s"                                                /* depthFunc equal */
 +                                                                                              "%s"                                                /* rgbGen */
 +                                                                                              "%s"                                                /* alphaGen */
 +                                                                                              "\t\ttcGen lightmap\n"
 +                                                                                              "\t\ttcMod transform 1 0 0 1 %1.5f %1.5f\n"         /* st offset */
 +                                                                                              "\t}\n",
 +                                                               lightmapName,
 +                                                               ( dfEqual ? "\t\tdepthFunc equal\n" : "" ),
 +                                                               rgbGen,
 +                                                               alphaGen,
 +                                                               lmx, lmy );
 +
 +                                      }
 +
 +                                      /* concatenate */
 +                                      strcat( styleStages, styleStage );
                                }
 -                              else
 -                              {
 -                                      sprintf( styleStage,    "\t{\n"
 -                                                                                      "\t\tmap %s\n"                                      /* lightmap */
 -                                                                                      "\t\tblendFunc GL_SRC_ALPHA GL_ONE\n"
 -                                                                                      "%s"                                                /* depthFunc equal */
 -                                                                                      "%s"                                                /* rgbGen */
 -                                                                                      "%s"                                                /* alphaGen */
 -                                                                                      "\t\ttcGen lightmap\n"
 -                                                                                      "\t\ttcMod transform 1 0 0 1 %1.5f %1.5f\n"         /* st offset */
 -                                                                                      "\t}\n",
 -                                                       lightmapName,
 -                                                       ( dfEqual ? "\t\tdepthFunc equal\n" : "" ),
 -                                                       rgbGen,
 -                                                       alphaGen,
 -                                                       lmx, lmy );
  
 +                              /* create custom shader */
 +                              if ( info->si->styleMarker == 2 ) {
 +                                      csi = CustomShader( info->si, "q3map_styleMarker2", styleStages );
 +                              }
 +                              else{
 +                                      csi = CustomShader( info->si, "q3map_styleMarker", styleStages );
                                }
  
 -                              /* concatenate */
 -                              strcat( styleStages, styleStage );
 -                      }
 +                              /* emit remap command */
 +                              //%     EmitVertexRemapShader( csi->shader, info->si->shader );
  
 -                      /* create custom shader */
 -                      if ( info->si->styleMarker == 2 ) {
 -                              csi = CustomShader( info->si, "q3map_styleMarker2", styleStages );
 -                      }
 -                      else{
 -                              csi = CustomShader( info->si, "q3map_styleMarker", styleStages );
 +                              /* store it */
 +                              //%     Sys_Printf( "Emitting: %s (%d", csi->shader, strlen( csi->shader ) );
 +                              ds->shaderNum = EmitShader( csi->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
 +                              //%     Sys_Printf( ")\n" );
                        }
  
 -                      /* emit remap command */
 -                      //%     EmitVertexRemapShader( csi->shader, info->si->shader );
 -
 -                      /* store it */
 -                      //%     Sys_Printf( "Emitting: %s (%d", csi->shader, strlen( csi->shader ) );
 -                      ds->shaderNum = EmitShader( csi->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
 -                      //%     Sys_Printf( ")\n" );
 -              }
 -
 -              /* devise a custom shader for this surface (fixme: make this work with light styles) */
 -              else if ( olm != NULL && lm != NULL && !externalLightmaps &&
 -                                ( olm->customWidth != game->lightmapSize || olm->customHeight != game->lightmapSize ) ) {
 -                      /* get output lightmap */
 -                      olm = &outLightmaps[ lm->outLightmapNums[ 0 ] ];
 +                      /* devise a custom shader for this surface (fixme: make this work with light styles) */
 +                      else if ( olm != NULL && lm != NULL && !externalLightmaps &&
 +                                        ( olm->customWidth != game->lightmapSize || olm->customHeight != game->lightmapSize ) ) {
 +                              /* get output lightmap */
 +                              olm = &outLightmaps[ lm->outLightmapNums[ 0 ] ];
  
 -                      /* do some name mangling */
 -                      sprintf( lightmapName, "maps/%s/" EXTERNAL_LIGHTMAP, mapName, olm->extLightmapNum );
 +                              /* do some name mangling */
 +                              sprintf( lightmapName, "maps/%s/" EXTERNAL_LIGHTMAP, mapName, olm->extLightmapNum );
  
 -                      /* create custom shader */
 -                      csi = CustomShader( info->si, "$lightmap", lightmapName );
 +                              /* create custom shader */
 +                              csi = CustomShader( info->si, "$lightmap", lightmapName );
  
 -                      /* store it */
 -                      //%     Sys_Printf( "Emitting: %s (%d", csi->shader, strlen( csi->shader ) );
 -                      ds->shaderNum = EmitShader( csi->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
 -                      //%     Sys_Printf( ")\n" );
 -              }
 +                              /* store it */
 +                              //%     Sys_Printf( "Emitting: %s (%d", csi->shader, strlen( csi->shader ) );
 +                              ds->shaderNum = EmitShader( csi->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
 +                              //%     Sys_Printf( ")\n" );
 +                      }
  
 -              /* use the normal plain-jane shader */
 -              else{
 -                      ds->shaderNum = EmitShader( info->si->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
 +                      /* use the normal plain-jane shader */
 +                      else{
 +                              ds->shaderNum = EmitShader( info->si->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
 +                      }
                }
        }
  
                                 ? 0
                                 : (float) numUsed / (float) numStored;
  
 -      /* print stats */
 -      Sys_Printf( "%9d luxels used\n", numUsed );
 -      Sys_Printf( "%9d luxels stored (%3.2f percent efficiency)\n", numStored, efficiency * 100.0f );
 -      Sys_Printf( "%9d solid surface lightmaps\n", numSolidLightmaps );
 -      Sys_Printf( "%9d identical surface lightmaps, using %d luxels\n", numTwins, numTwinLuxels );
 -      Sys_Printf( "%9d vertex forced surfaces\n", numSurfsVertexForced );
 -      Sys_Printf( "%9d vertex approximated surfaces\n", numSurfsVertexApproximated );
 -      Sys_Printf( "%9d BSP lightmaps\n", numBSPLightmaps );
 -      Sys_Printf( "%9d total lightmaps\n", numOutLightmaps );
 -      Sys_Printf( "%9d unique lightmap/shader combinations\n", numLightmapShaders );
 -
 -      /* write map shader file */
 -      WriteMapShaderFile();
 +      if ( storeForReal ) {
 +              /* print stats */
 +              Sys_Printf( "%9d luxels used\n", numUsed );
 +              Sys_Printf( "%9d luxels stored (%3.2f percent efficiency)\n", numStored, efficiency * 100.0f );
 +              Sys_Printf( "%9d solid surface lightmaps\n", numSolidLightmaps );
 +              Sys_Printf( "%9d identical surface lightmaps, using %d luxels\n", numTwins, numTwinLuxels );
 +              Sys_Printf( "%9d vertex forced surfaces\n", numSurfsVertexForced );
 +              Sys_Printf( "%9d vertex approximated surfaces\n", numSurfsVertexApproximated );
 +              Sys_Printf( "%9d BSP lightmaps\n", numBSPLightmaps );
 +              Sys_Printf( "%9d total lightmaps\n", numOutLightmaps );
 +              Sys_Printf( "%9d unique lightmap/shader combinations\n", numLightmapShaders );
 +
 +              /* write map shader file */
 +              WriteMapShaderFile();
 +      }
  }
index 7f0582e249820c4513110f4a6574273dd1423515,24a69d846c09101c4f9cca01af704e8a29863599..e48d6a7be774da211fa9ac086e72c3ebc7cb89b9
     ------------------------------------------------------------------------------- */
  
  /* platform-specific */
 -#if GDEF_OS_LINUX || GDEF_OS_MACOS
 -      #define Q_UNIX
 -#endif
 -
 -#ifdef Q_UNIX
 +#if GDEF_OS_POSIX
        #include <unistd.h>
        #include <pwd.h>
        #include <limits.h>
@@@ -62,6 -66,8 +62,6 @@@
  
  
  /* general */
 -#include "version.h"            /* ttimo: might want to guard that if built outside of the GtkRadiant tree */
 -
  #include "cmdlib.h"
  #include "mathlib.h"
  #include "md5lib.h"
  
     ------------------------------------------------------------------------------- */
  
 -#define MAC_STATIC_HACK         0
 -#if GDEF_OS_MACOS && MAC_STATIC_HACK
 -      #define MAC_STATIC          static
 -#else
 -      #define MAC_STATIC
 -#endif
 -
 -#if 1
        #if GDEF_OS_WINDOWS
                #define Q_stricmp           stricmp
                #define Q_strncasecmp       strnicmp
                #define Q_stricmp           strcasecmp
                #define Q_strncasecmp       strncasecmp
        #endif
 +
 +// hack to declare and define in the same file
 +#ifdef MAIN_C
 +      #define Q_EXTERN
 +      #define Q_ASSIGN( a )   = a
 +#else
 +      #define Q_EXTERN extern
 +      #define Q_ASSIGN( a )
  #endif
  
  /* macro version */
  /* general */
  #define MAX_QPATH               64
  
 -#define MAX_IMAGES              512
 +#define MAX_IMAGES              2048
  #define DEFAULT_IMAGE           "*default"
  
 -#define MAX_MODELS              512
 +#define MAX_MODELS              2048
  
  #define DEF_BACKSPLASH_FRACTION 0.05f   /* 5% backsplash by default */
  #define DEF_BACKSPLASH_DISTANCE 23
  #define C_DETAIL                0x08000000  /* THIS MUST BE THE SAME AS IN RADIANT! */
  
  
 +/* new tex surface flags, like Smokin'Guns */
 +#define TEX_SURF_METAL             0x00001000
 +#define TEX_SURF_WOOD              0x00080000
 +#define TEX_SURF_CLOTH             0x00100000
 +#define TEX_SURF_DIRT              0x00200000
 +#define TEX_SURF_GLASS             0x00400000
 +#define TEX_SURF_PLANT             0x00800000
 +#define TEX_SURF_SAND              0x01000000
 +#define TEX_SURF_SNOW              0x02000000
 +#define TEX_SURF_STONE             0x04000000
 +#define TEX_SURF_WATER             0x08000000
 +#define TEX_SURF_GRASS             0x10000000
 +#define TEX_SURF_BREAKABLE         0x20000000
 +
 +
  /* shadow flags */
  #define WORLDSPAWN_CAST_SHADOWS 1
  #define WORLDSPAWN_RECV_SHADOWS 1
  #define HINT_PRIORITY           1000        /* ydnar: force hint splits first and antiportal/areaportal splits last */
  #define ANTIPORTAL_PRIORITY     -1000
  #define AREAPORTAL_PRIORITY     -1000
 -#define DETAIL_PRIORITY     -3000
 +#define DETAIL_PRIORITY         -3000
  
  #define PSIDE_FRONT             1
  #define PSIDE_BACK              2
  #define RAD_LUXEL_SIZE          3
  #define SUPER_LUXEL_SIZE        4
  #define SUPER_FLAG_SIZE         4
 -#define FLAG_FORCE_SUBSAMPLING 1
 +#define FLAG_FORCE_SUBSAMPLING  1
  #define FLAG_ALREADY_SUBSAMPLED 2
  #define SUPER_ORIGIN_SIZE       3
  #define SUPER_NORMAL_SIZE       4
@@@ -560,13 -551,6 +560,13 @@@ typedef enu
  }
  miniMapMode_t;
  
 +typedef enum
 +{
 +      MINIMAP_SIDECAR_NONE,
 +      MINIMAP_SIDECAR_UNVANQUISHED
 +}
 +miniMapSidecarFormat_t;
 +
  typedef struct game_s
  {
        char                *arg;                           /* -game matches this */
        int maxLMSurfaceVerts;                              /* default maximum meta surface verts */
        int maxSurfaceVerts;                                /* default maximum surface verts */
        int maxSurfaceIndexes;                              /* default maximum surface indexes (tris * 3) */
 +      qboolean texFile;                                   /* enable per shader prefix surface flags and .tex file */
        qboolean emitFlares;                                /* when true, emit flare surfaces */
        char                *flareShader;                   /* default flare shader (MUST BE SET) */
        qboolean wolfLight;                                 /* when true, lights work like wolf q3map  */
        qboolean miniMapKeepAspect;                         /* minimap keep aspect ratio by letterboxing */
        miniMapMode_t miniMapMode;                          /* minimap mode */
        char                *miniMapNameFormat;             /* minimap name format */
 +      miniMapSidecarFormat_t miniMapSidecarFormat;        /* minimap sidecar format */
        char                *bspIdent;                      /* 4-letter bsp file prefix */
        int bspVersion;                                     /* bsp version to use */
        qboolean lumpSwap;                                  /* cod-style len/ofs order */
@@@ -810,7 -792,7 +810,7 @@@ typedef struct shaderInfo_
        sun_t               *sun;                           /* ydnar */
  
        vec3_t color;                                       /* normalized color */
-       vec3_t averageColor;
+       vec4_t averageColor;
        byte lightStyle;
  
        /* vortex: per-surface floodlight */
@@@ -848,7 -830,7 +848,7 @@@ typedef struct face_
        struct face_s       *next;
        int planenum;
        int priority;
 -      //qboolean                      checked;
 +      //qboolean checked;
        int compileFlags;
        winding_t           *w;
  }
@@@ -1024,7 -1006,7 +1024,7 @@@ typedef enu
  }
  surfaceType_t;
  
 -char            *surfaceTypes[ NUM_SURFACE_TYPES ]
 +Q_EXTERN char *surfaceTypes[ NUM_SURFACE_TYPES ]
  #ifndef MAIN_C
  ;
  #else
@@@ -1490,7 -1472,7 +1490,7 @@@ typedef struct rawLightmap_
        float                   *bspLuxels[ MAX_LIGHTMAPS ];
        float                   *radLuxels[ MAX_LIGHTMAPS ];
        float                   *superLuxels[ MAX_LIGHTMAPS ];
 -      unsigned char               *superFlags;
 +      unsigned char           *superFlags;
        float                   *superOrigins;
        float                   *superNormals;
        int                     *superClusters;
@@@ -1837,7 -1819,6 +1837,7 @@@ void                        RadFreeLigh
  
  /* light_ydnar.c */
  void                        ColorToBytes( const float *color, byte *colorBytes, float scale );
 +void                        ColorToBytesNonZero( const float *color, byte *colorBytes, float scale );
  void                        SmoothNormals( void );
  
  void                        MapRawLightmap( int num );
@@@ -1878,7 -1859,7 +1878,7 @@@ int                         ImportLight
  
  void                        SetupSurfaceLightmaps( void );
  void                        StitchSurfaceLightmaps( void );
 -void                        StoreSurfaceLightmaps( qboolean fastAllocate );
 +void                        StoreSurfaceLightmaps( qboolean fastAllocate, qboolean storeForReal );
  
  
  /* exportents.c */
@@@ -1935,11 -1916,6 +1935,11 @@@ void                        PartialLoad
  void                        WriteBSPFile( const char *filename );
  void                        PrintBSPFileSizes( void );
  
 +void                        WriteTexFile( char *name );
 +void                        LoadSurfaceFlags( char *filename );
 +int                         GetSurfaceParm( const char *tex );
 +void                        RestoreSurfaceFlags( char *filename );
 +
  epair_t                     *ParseEPair( void );
  void                        ParseEntities( void );
  void                        UnparseEntities( void );
@@@ -1975,6 -1951,14 +1975,6 @@@ void                        WriteRBSPFi
  
     ------------------------------------------------------------------------------- */
  
 -#ifdef MAIN_C
 -      #define Q_EXTERN
 -      #define Q_ASSIGN( a )   = a
 -#else
 -      #define Q_EXTERN extern
 -      #define Q_ASSIGN( a )
 -#endif
 -
  /* game support */
  Q_EXTERN game_t games[]
  #ifndef MAIN_C
        =
        {
                                                                #include "game_quake3.h"
 +      ,
 +                                                              #include "game_nexuiz.h" /* must be after game_quake3.h as they share defines! */
 +      ,
 +                                                              #include "game_oa.h" /* must be after game_quake3.h as they share defines! */
 +      ,
 +                                                              #include "game_q3rally.h" /* must be after game_quake3.h as they share defines! */
        ,
                                                                #include "game_quakelive.h" /* must be after game_quake3.h as they share defines! */
        ,
 -                                                              #include "game_nexuiz.h" /* must be after game_quake3.h as they share defines! */
 +                                                              #include "game_reaction.h" /* must be after game_quake3.h */
        ,
 -                                                              #include "game_xonotic.h" /* must be after game_quake3.h as they share defines! */
 +                                                              #include "game_smokinguns.h" /* must be after game_quake3.h */
        ,
                                                                #include "game_tremulous.h" /*LinuxManMikeC: must be after game_quake3.h, depends on #define's set in it */
        ,
                                                                #include "game_unvanquished.h" /* must be after game_tremulous.h as they share defines! */
 +      ,
 +                                                              #include "game_wop.h" /* must be after game_quake3.h as they share defines! */
 +      ,
 +                                                              #include "game_xonotic.h" /* must be after game_quake3.h as they share defines! */
        ,
                                                                #include "game_tenebrae.h"
        ,
        ,
                                                                #include "game_qfusion.h"   /* qfusion game */
        ,
 -                                                              #include "game_reaction.h" /* must be after game_quake3.h */
 +                                                              #include "game_warsow.h" /* must be after game_qfusion.h as they share defines! */
 +      ,
 +                                                              #include "game_warfork.h" /* must be after game_qfusion.h as they share defines! */
        ,
 -                                                              #include "game_darkplaces.h"    /* vortex: darkplaces q1 engine */
 +                                                              #include "game_darkplaces.h" /* darkplaces q1 engine */
        ,
 -                                                              #include "game_dq.h"    /* vortex: deluxe quake game ( darkplaces q1 engine) */
 +                                                              #include "game_dq.h" /* deluxe quake game ( darkplaces q1 engine) */
        ,
                                                                #include "game_prophecy.h"  /* vortex: prophecy game ( darkplaces q1 engine) */
        ,
@@@ -2064,6 -2036,7 +2064,6 @@@ Q_EXTERN qboolean doingBSP Q_ASSIGN( qf
  
  /* commandline arguments */
  Q_EXTERN qboolean nocmdline Q_ASSIGN( qfalse );
 -Q_EXTERN qboolean verbose;
  Q_EXTERN qboolean verboseEntities Q_ASSIGN( qfalse );
  Q_EXTERN qboolean force Q_ASSIGN( qfalse );
  Q_EXTERN qboolean infoMode Q_ASSIGN( qfalse );
@@@ -2082,8 -2055,8 +2082,8 @@@ Q_EXTERN qboolean nofog Q_ASSIGN( qfals
  Q_EXTERN qboolean noHint Q_ASSIGN( qfalse );                        /* ydnar */
  Q_EXTERN qboolean renameModelShaders Q_ASSIGN( qfalse );            /* ydnar */
  Q_EXTERN qboolean skyFixHack Q_ASSIGN( qfalse );                    /* ydnar */
 -Q_EXTERN qboolean bspAlternateSplitWeights Q_ASSIGN( qfalse );                      /* 27 */
 -Q_EXTERN qboolean deepBSP Q_ASSIGN( qfalse );                   /* div0 */
 +Q_EXTERN qboolean bspAlternateSplitWeights Q_ASSIGN( qfalse );      /* 27 */
 +Q_EXTERN qboolean deepBSP Q_ASSIGN( qfalse );                       /* div0 */
  Q_EXTERN qboolean maxAreaFaceSurface Q_ASSIGN( qfalse );                    /* divVerent */
  
  Q_EXTERN int patchSubdivisions Q_ASSIGN( 8 );                       /* ydnar: -patchmeta subdivisions */
@@@ -2580,7 -2553,7 +2580,7 @@@ Q_EXTERN int allocatedBSPBrushSides Q_A
  Q_EXTERN bspBrushSide_t*    bspBrushSides Q_ASSIGN( NULL );
  
  Q_EXTERN int numBSPLightBytes Q_ASSIGN( 0 );
 -Q_EXTERN byte               *bspLightBytes Q_ASSIGN( NULL );
 +Q_EXTERN byte *bspLightBytes Q_ASSIGN( NULL );
  
  //%   Q_EXTERN int                            numBSPGridPoints Q_ASSIGN( 0 );
  //%   Q_EXTERN byte                           *bspGridPoints Q_ASSIGN( NULL );
@@@ -2592,11 -2565,11 +2592,11 @@@ Q_EXTERN int numBSPVisBytes Q_ASSIGN( 
  Q_EXTERN byte bspVisBytes[ MAX_MAP_VISIBILITY ];
  
  Q_EXTERN int numBSPDrawVerts Q_ASSIGN( 0 );
 -Q_EXTERN bspDrawVert_t          *bspDrawVerts Q_ASSIGN( NULL );
 +Q_EXTERN bspDrawVert_t *bspDrawVerts Q_ASSIGN( NULL );
  
  Q_EXTERN int numBSPDrawIndexes Q_ASSIGN( 0 );
  Q_EXTERN int allocatedBSPDrawIndexes Q_ASSIGN( 0 );
 -Q_EXTERN int                *bspDrawIndexes Q_ASSIGN( NULL );
 +Q_EXTERN int *bspDrawIndexes Q_ASSIGN( NULL );
  
  Q_EXTERN int numBSPDrawSurfaces Q_ASSIGN( 0 );
  Q_EXTERN bspDrawSurface_t   *bspDrawSurfaces Q_ASSIGN( NULL );
@@@ -2607,45 -2580,27 +2607,45 @@@ Q_EXTERN bspFog_t bspFogs[ MAX_MAP_FOG
  Q_EXTERN int numBSPAds Q_ASSIGN( 0 );
  Q_EXTERN bspAdvertisement_t bspAds[ MAX_MAP_ADVERTISEMENTS ];
  
 -#define AUTOEXPAND_BY_REALLOC( ptr, reqitem, allocated, def ) \
 +// Used for tex file support, Smokin'Guns globals
 +Q_EXTERN qboolean compile_map;
 +
 +#define _AUTOEXPAND_BY_REALLOC( ptr, reqitem, allocated, def, fillWithZeros ) \
        do \
        { \
 +              int prevAllocated = allocated; \
                if ( reqitem >= allocated )     \
                { \
                        if ( allocated == 0 ) { \
 -                              allocated = def; } \
 +                              allocated = def; \
 +                      } \
                        while ( reqitem >= allocated && allocated )     \
 +                      { \
                                allocated *= 2; \
 +                      } \
                        if ( !allocated || allocated > 2147483647 / (int)sizeof( *ptr ) ) \
                        { \
 -                              Error( # ptr " over 2 GB" ); \
 +                              Error( #ptr " over 2 GB" ); \
                        } \
                        ptr = realloc( ptr, sizeof( *ptr ) * allocated ); \
                        if ( !ptr ) { \
 -                              Error( # ptr " out of memory" ); } \
 +                              Error( #ptr " out of memory" ); \
 +                      } \
 +                      if ( fillWithZeros ) \
 +                      { \
 +                              memset( ptr + ( sizeof( *ptr ) * prevAllocated ), 0 , sizeof( *ptr ) * ( allocated - prevAllocated ) ); \
 +                      } \
                } \
        } \
        while ( 0 )
  
 -#define AUTOEXPAND_BY_REALLOC_BSP( suffix, def ) AUTOEXPAND_BY_REALLOC( bsp ## suffix, numBSP ## suffix, allocatedBSP ## suffix, def )
 +#define AUTOEXPAND_BY_REALLOC( ptr, reqitem, allocated, def ) _AUTOEXPAND_BY_REALLOC( ptr, reqitem, allocated, def, qfalse )
 +
 +#define AUTOEXPAND_BY_REALLOC0( ptr, reqitem, allocated, def ) _AUTOEXPAND_BY_REALLOC( ptr, reqitem, allocated, def, qtrue )
 +
 +#define AUTOEXPAND_BY_REALLOC_BSP( suffix, def ) AUTOEXPAND_BY_REALLOC( bsp##suffix, numBSP##suffix, allocatedBSP##suffix, def )
 +
 +#define AUTOEXPAND_BY_REALLOC0_BSP( suffix, def ) AUTOEXPAND_BY_REALLOC0( bsp##suffix, numBSP##suffix, allocatedBSP##suffix, def )
  
  #define Image_LinearFloatFromsRGBFloat( c ) ( ( ( c ) <= 0.04045f ) ? ( c ) * ( 1.0f / 12.92f ) : (float)pow( ( ( c ) + 0.055f ) * ( 1.0f / 1.055f ), 2.4f ) )
  #define Image_sRGBFloatFromLinearFloat( c ) ( ( ( c ) < 0.0031308f ) ? ( c ) * 12.92f : 1.055f * (float)pow( ( c ), 1.0f / 2.4f ) - 0.055f )
index 22c7b9b22beea97f82c1bbef746ce5a8d1c8392e,10b2b414fcf70181aaec69e0e10a3ead9ad1ddd8..cfa0db86047362e2777b73bf949bf9e1c1c60e2f
@@@ -811,10 -811,12 +811,12 @@@ static void LoadShaderImages( shaderInf
        if ( VectorLength( si->color ) <= 0.0f ) {
                ColorNormalize( color, si->color );
                VectorScale( color, ( 1.0f / count ), si->averageColor );
+               si->averageColor[ 3 ] = color[ 3 ] / count;
        }
        else
        {
                VectorCopy( si->color, si->averageColor );
+               si->averageColor[ 3 ] = 1.0f;
        }
  }
  
@@@ -1274,7 -1276,8 +1276,7 @@@ static void ParseShaderFile( const cha
                        else if ( !Q_stricmp( token, "sun" ) /* sof2 */ || !Q_stricmp( token, "q3map_sun" ) || !Q_stricmp( token, "q3map_sunExt" ) ) {
                                float a, b;
                                sun_t       *sun;
 -                              qboolean ext;
 -
 +                              qboolean ext = qfalse;
  
                                /* ydnar: extended sun directive? */
                                if ( !Q_stricmp( token, "q3map_sunext" ) ) {
                                }
  
                                /* allocate sun */
 -                              sun = safe_malloc( sizeof( *sun ) );
 -                              memset( sun, 0, sizeof( *sun ) );
 +                              sun = safe_malloc0( sizeof( *sun ) );
  
                                /* set style */
                                sun->style = si->lightStyle;
                                        surfaceModel_t  *model;
  
                                        /* allocate new model and attach it */
 -                                      model = safe_malloc( sizeof( *model ) );
 -                                      memset( model, 0, sizeof( *model ) );
 +                                      model = safe_malloc0( sizeof( *model ) );
                                        model->next = si->surfaceModel;
                                        si->surfaceModel = model;
  
  
  
                                        /* allocate new foliage struct and attach it */
 -                                      foliage = safe_malloc( sizeof( *foliage ) );
 -                                      memset( foliage, 0, sizeof( *foliage ) );
 +                                      foliage = safe_malloc0( sizeof( *foliage ) );
                                        foliage->next = si->foliage;
                                        si->foliage = foliage;
  
                                        alpha = ( !Q_stricmp( token, "q3map_alphaGen" ) || !Q_stricmp( token, "q3map_alphaMod" ) ) ? 1 : 0;
  
                                        /* allocate new colormod */
 -                                      cm = safe_malloc( sizeof( *cm ) );
 -                                      memset( cm, 0, sizeof( *cm ) );
 +                                      cm = safe_malloc0( sizeof( *cm ) );
  
                                        /* attach to shader */
                                        if ( si->colorMod == NULL ) {
index 2cd6f0374e8b2aea6189facca07a1dcaf7ae7e7b,e189d0648af3f618ceb2818f47bf6d408aeeac1e..d7af5374fa7859bd9516d52521d8de86a06c99f9
@@@ -656,7 -656,6 +656,7 @@@ void FanFaceSurface( mapDrawSurface_t *
  
        /* add a new vertex at the beginning of the surface */
        verts = safe_malloc( ( ds->numVerts + 1 ) * sizeof( bspDrawVert_t ) );
 +      /* beware to only zero the new vertexi at the beginning, nor more! */
        memset( verts, 0, sizeof( bspDrawVert_t ) );
        memcpy( &verts[ 1 ], ds->verts, ds->numVerts * sizeof( bspDrawVert_t ) );
        free( ds->verts );
@@@ -962,7 -961,8 +962,8 @@@ void MakeEntityMetaTriangles( entity_t 
  
  typedef struct edge_s
  {
-       vec3_t origin, edge;
+       vec3_t origin;
+       vec4_t edge;
        vec_t length, kingpinLength;
        int kingpin;
        vec4_t plane;
@@@ -1202,11 -1202,13 +1203,11 @@@ void SmoothMetaTriangles( void )
        Sys_FPrintf( SYS_VRB, "--- SmoothMetaTriangles ---\n" );
  
        /* allocate shade angle table */
 -      shadeAngles = safe_malloc( numMetaVerts * sizeof( float ) );
 -      memset( shadeAngles, 0, numMetaVerts * sizeof( float ) );
 +      shadeAngles = safe_malloc0( numMetaVerts * sizeof( float ) );
  
        /* allocate smoothed table */
        cs = ( numMetaVerts / 8 ) + 1;
 -      smoothed = safe_malloc( cs );
 -      memset( smoothed, 0, cs );
 +      smoothed = safe_malloc0( cs );
  
        /* set default shade angle */
        defaultShadeAngle = DEG2RAD( npDegrees );