]> git.rm.cloudns.org Git - xonotic/netradiant.git/commitdiff
Merge commit '37bef590b1d2161b16b2bd33349fc8b56af60920' into master-merge
authorThomas Debesse <dev@illwieckz.net>
Tue, 21 Jun 2022 02:01:17 +0000 (04:01 +0200)
committerThomas Debesse <dev@illwieckz.net>
Tue, 21 Jun 2022 02:01:17 +0000 (04:01 +0200)
14 files changed:
1  2 
Makefile
libs/picomodel/picointernal.c
radiant/console.cpp
radiant/mainframe.cpp
radiant/preferences.cpp
radiant/texwindow.cpp
radiant/watchbsp.cpp
tools/heretic2/common/cmdlib.c
tools/quake3/common/vfs.h
tools/quake3/q3map2/light_bounce.c
tools/quake3/q3map2/light_ydnar.c
tools/quake3/q3map2/surface.c
tools/quake3/q3map2/surface_meta.c
tools/quake3/q3map2/tjunction.c

diff --cc Makefile
Simple merge
Simple merge
index abb1def4655cb9fcb0c62ad3afbfdc2236dae0b7,ea837329831319bb94c23af6f0840d847e3e85ba..489f8d61f4773dcae99d991ffab2c7d6d7236ed8
@@@ -154,95 -150,76 +157,97 @@@ std::size_t __attribute__((optimize("O0
  }
  };
  
 -std::size_t Sys_Print( int level, const char* buf, std::size_t length ){
 -      bool contains_newline = std::find( buf, buf + length, '\n' ) != buf + length;
+ //#pragma GCC pop_options
 +// This function is meant to be used with gtk_idle_add. It will free its argument.
 +static gboolean Gtk_Idle_Print( gpointer data ){
 +      Gtk_Idle_Print_Data *args = reinterpret_cast<Gtk_Idle_Print_Data *>(data);
 +      g_assert(g_console);
  
-       auto buffer = gtk_text_view_get_buffer( g_console );
 -      if ( level == SYS_ERR ) {
 -              Sys_LogFile( true );
 -      }
 -
 -      if ( g_hLogFile != 0 ) {
 -              fwrite( buf, 1, length, g_hLogFile );
 -              if ( contains_newline ) {
 -                      fflush( g_hLogFile );
 -              }
 -      }
 -
 -      if ( level != SYS_NOCON ) {
 -              if ( g_console ) {
+                       auto buffer = gtk_text_view_get_buffer( g_console );
  
-       GtkTextIter iter;
-       gtk_text_buffer_get_end_iter( buffer, &iter );
+                       GtkTextIter iter;
+                       gtk_text_buffer_get_end_iter( buffer, &iter );
  
-       static auto end = gtk_text_buffer_create_mark( buffer, "end", &iter, FALSE );
+                       static auto end = gtk_text_buffer_create_mark( buffer, "end", &iter, FALSE );
  
-       const GdkColor yellow = { 0, 0xb0ff, 0xb0ff, 0x0000 };
-       const GdkColor red = { 0, 0xffff, 0x0000, 0x0000 };
+                       const GdkColor yellow = { 0, 0xb0ff, 0xb0ff, 0x0000 };
+                       const GdkColor red = { 0, 0xffff, 0x0000, 0x0000 };
  
-       static auto error_tag = gtk_text_buffer_create_tag( buffer, "red_foreground", "foreground-gdk", &red, NULL );
-       static auto warning_tag = gtk_text_buffer_create_tag( buffer, "yellow_foreground", "foreground-gdk", &yellow, NULL );
-       static auto standard_tag = gtk_text_buffer_create_tag( buffer, "black_foreground", NULL );
-       GtkTextTag* tag;
+                       static auto error_tag = gtk_text_buffer_create_tag( buffer, "red_foreground", "foreground-gdk", &red, NULL );
+                       static auto warning_tag = gtk_text_buffer_create_tag( buffer, "yellow_foreground", "foreground-gdk", &yellow, NULL );
+                       static auto standard_tag = gtk_text_buffer_create_tag( buffer, "black_foreground", NULL );
+                       GtkTextTag* tag;
 -                      switch ( level )
 +      switch ( args->level )
-       {
-       case SYS_WRN:
-               tag = warning_tag;
-               break;
-       case SYS_ERR:
-               tag = error_tag;
-               break;
-       case SYS_STD:
-       case SYS_VRB:
-       default:
-               tag = standard_tag;
-               break;
-       }
-       {
-               GtkTextBufferOutputStream textBuffer( buffer, &iter, tag );
-               if ( !globalCharacterSet().isUTF8() ) {
-                       BufferedTextOutputStream<GtkTextBufferOutputStream> buffered( textBuffer );
+                       {
+                       case SYS_WRN:
+                               tag = warning_tag;
+                               break;
+                       case SYS_ERR:
+                               tag = error_tag;
+                               break;
+                       case SYS_STD:
+                       case SYS_VRB:
+                       default:
+                               tag = standard_tag;
+                               break;
+                       }
 -
+                       {
+                               GtkTextBufferOutputStream textBuffer( buffer, &iter, tag );
+                               if ( !globalCharacterSet().isUTF8() ) {
+                                       BufferedTextOutputStream<GtkTextBufferOutputStream> buffered( textBuffer );
 -                                      buffered << StringRange( buf, buf + length );
 +                      buffered << StringRange( args->buf, args->buf + args->length );
-               }
-               else
-               {
+                               }
+                               else
+                               {
 -                                      textBuffer << StringRange( buf, buf + length );
 +                      textBuffer << StringRange( args->buf, args->buf + args->length );
-               }
-       }
+                               }
+                       }
  
-       // update console widget immediatly if we're doing something time-consuming
+                       // update console widget immediatly if we're doing something time-consuming
 -                      if ( contains_newline ) {
 +      if ( args->contains_newline ) {
-               gtk_text_view_scroll_mark_onscreen( g_console, end );
+                               gtk_text_view_scroll_mark_onscreen( g_console, end );
  
-               if ( !ScreenUpdates_Enabled() && gtk_widget_get_realized( g_console ) ) {
-                       ScreenUpdates_process();
-               }
-       }
+                               if ( !ScreenUpdates_Enabled() && gtk_widget_get_realized( g_console ) ) {
+                                       ScreenUpdates_process();
+                               }
+                       }
 +
 +      free( args->buf );
 +      free( args );
 +
 +      return FALSE; // call this once, not repeatedly
- }
+               }
 +
 +// Print logs to the in-game console and/or to the log file.
 +// This function is thread safe.
 +std::size_t Sys_Print( int level, const char* buf, std::size_t length ){
 +      bool contains_newline = std::find( buf, buf + length, '\n' ) != buf + length;
 +
 +      if ( level == SYS_ERR ) {
 +              Sys_EnableLogFile( true );
        }
 +
 +      if ( g_hLogFile != 0 ) {
 +              // prevent parallel write
 +              static std::mutex log_file_mutex;
 +              std::lock_guard<std::mutex> guard(log_file_mutex);
 +
 +              fwrite( buf, 1, length, g_hLogFile );
 +              if ( contains_newline ) {
 +                      fflush( g_hLogFile );
 +              }
 +      }
 +
 +      if ( level != SYS_NOCON && g_console ) {
 +              auto data = reinterpret_cast<Gtk_Idle_Print_Data *>( malloc( sizeof(struct Gtk_Idle_Print_Data) ) );
 +              if (data != nullptr) {
 +                      *data = { level, g_strndup(buf, length), length, contains_newline };
 +                      gdk_threads_add_idle(Gtk_Idle_Print, (gpointer)data);
 +              }
 +      }
 +
        return length;
  }
  
Simple merge
Simple merge
index 75ce075616d11fd680908eb8963155cf99ae282e,416d31789184d02b77e4c610fdbd282296918f86..34a31b1efb008b84d9d77aba657a7b3fe955d8a9
@@@ -1758,19 -1681,19 +1758,20 @@@ void TextureBrowser_constructTreeStore(
        TextureGroups groups = TextureGroups_constructTreeView();
        auto store = ui::TreeStore::from(gtk_tree_store_new( 1, G_TYPE_STRING ));
        TextureGroups_constructTreeModel( groups, store );
+       std::set<CopiedString>::iterator iter;
  
 -      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;
+       //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 ) );
  }
Simple merge
index 244452272c09a2e81c2ab024db56e89ef327db4a,0000000000000000000000000000000000000000..9852623b02176d7e6ba0dca593febd90ec38bdac
mode 100644,000000..100644
--- /dev/null
@@@ -1,1181 -1,0 +1,1181 @@@
-    printf(buf);
 +/*
 +   Copyright (C) 1999-2007 id Software, Inc. and contributors.
 +   For a list of contributors, see the accompanying CONTRIBUTORS file.
 +
 +   This file is part of GtkRadiant.
 +
 +   GtkRadiant is free software; you can redistribute it and/or modify
 +   it under the terms of the GNU General Public License as published by
 +   the Free Software Foundation; either version 2 of the License, or
 +   (at your option) any later version.
 +
 +   GtkRadiant is distributed in the hope that it will be useful,
 +   but WITHOUT ANY WARRANTY; without even the implied warranty of
 +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +   GNU General Public License for more details.
 +
 +   You should have received a copy of the GNU General Public License
 +   along with GtkRadiant; if not, write to the Free Software
 +   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 + */
 +
 +// Nurail: Swiped from quake3/common
 +
 +#include "cmdlib.h"
 +#include "globaldefs.h"
 +#include "mathlib.h"
 +#include "inout.h"
 +#include <sys/types.h>
 +#include <sys/stat.h>
 +
 +#if GDEF_OS_WINDOWS
 +#include <direct.h>
 +#include <windows.h>
 +#elif GDEF_OS_NEXT
 +#include <libc.h>
 +#else // OTHER OSES
 +#include <unistd.h>
 +#endif // OTHER OSES
 +
 +#if !GDEF_OS_WINDOWS
 +#define strlwr strlower
 +#endif // !GDEF_OS_WINDOWS
 +
 +#define BASEDIRNAME "h"
 +#define PATHSEPERATOR '/'
 +
 +extern qboolean verbose;
 +
 +qboolean g_dokeypress = false;
 +
 +qboolean g_nomkdir = false;
 +
 +void *safe_malloc( size_t size ){
 +      void *p;
 +
 +      p = malloc( size );
 +      if ( !p ) {
 +              Error( "safe_malloc failed on allocation of %i bytes", size );
 +      }
 +
 +      return p;
 +}
 +
 +void *safe_malloc_info( size_t size, char* info ){
 +      void *p;
 +
 +      p = malloc( size );
 +      if ( !p ) {
 +              Error( "%s: safe_malloc failed on allocation of %i bytes", info, size );
 +      }
 +
 +      return p;
 +}
 +
 +void *SafeMalloc( size_t n, char *desc ){
 +      void *p;
 +
 +      if ( ( p = malloc( n ) ) == NULL ) {
 +              Error( "Failed to allocate %d bytes for '%s'.\n", n, desc );
 +      }
 +      memset( p, 0, n );
 +      return p;
 +}
 +
 +// set these before calling CheckParm
 +int myargc;
 +char **myargv;
 +
 +char com_token[1024];
 +qboolean com_eof;
 +
 +qboolean archive;
 +char archivedir[1024];
 +
 +
 +/*
 +   ===================
 +   ExpandWildcards
 +
 +   Mimic unix command line expansion
 +   ===================
 + */
 +#define MAX_EX_ARGC 1024
 +
 +int ex_argc;
 +char    *ex_argv[MAX_EX_ARGC];
 +
 +#if GDEF_OS_WINDOWS
 +#include "io.h"
 +void ExpandWildcards( int *argc, char ***argv ){
 +      struct _finddata_t fileinfo;
 +      int handle;
 +      int i;
 +      char filename[1024];
 +      char filebase[1024];
 +      char    *path;
 +
 +      ex_argc = 0;
 +      for ( i = 0 ; i < *argc ; i++ )
 +      {
 +              path = ( *argv )[i];
 +              if ( path[0] == '-'
 +                       || ( !strstr( path, "*" ) && !strstr( path, "?" ) ) ) {
 +                      ex_argv[ex_argc++] = path;
 +                      continue;
 +              }
 +
 +              handle = _findfirst( path, &fileinfo );
 +              if ( handle == -1 ) {
 +                      return;
 +              }
 +
 +              ExtractFilePath( path, filebase );
 +
 +              do
 +              {
 +                      sprintf( filename, "%s%s", filebase, fileinfo.name );
 +                      ex_argv[ex_argc++] = copystring( filename );
 +              } while ( _findnext( handle, &fileinfo ) != -1 );
 +
 +              _findclose( handle );
 +      }
 +
 +      *argc = ex_argc;
 +      *argv = ex_argv;
 +}
 +#else // !GDEF_OS_WINDOWS
 +void ExpandWildcards( int *argc, char ***argv ){
 +}
 +#endif // !GDEF_OS_WINDOWS
 +
 +/*
 +
 +   qdir will hold the path up to the quake directory, including the slash
 +
 +   f:\quake\
 +   /raid/quake/
 +
 +   gamedir will hold qdir + the game directory (id1, id2, etc)
 +
 + */
 +
 +char qdir[1024];
 +char gamedir[1024];
 +char writedir[1024];
 +
 +void SetQdirFromPath( const char *path ){
 +      char temp[1024];
 +      const char  *c;
 +      const char *sep;
 +      int len, count;
 +
 +      if ( !( path[0] == '/' || path[0] == '\\' || path[1] == ':' ) ) { // path is partial
 +              Q_getwd( temp );
 +              strcat( temp, path );
 +              path = temp;
 +      }
 +
 +      // search for "quake2" in path
 +
 +      len = strlen( BASEDIRNAME );
 +      for ( c = path + strlen( path ) - 1 ; c != path ; c-- )
 +      {
 +              int i;
 +
 +              if ( !Q_strncasecmp( c, BASEDIRNAME, len ) ) {
 +                      //
 +                      //strncpy (qdir, path, c+len+2-path);
 +                      // the +2 assumes a 2 or 3 following quake which is not the
 +                      // case with a retail install
 +                      // so we need to add up how much to the next separator
 +                      sep = c + len;
 +                      count = 1;
 +                      while ( *sep && *sep != '/' && *sep != '\\' )
 +                      {
 +                              sep++;
 +                              count++;
 +                      }
 +                      strncpy( qdir, path, c + len + count - path );
 +                      Sys_Printf( "qdir: %s\n", qdir );
 +                      for ( i = 0; i < strlen( qdir ); i++ )
 +                      {
 +                              if ( qdir[i] == '\\' ) {
 +                                      qdir[i] = '/';
 +                              }
 +                      }
 +
 +                      c += len + count;
 +                      while ( *c )
 +                      {
 +                              if ( *c == '/' || *c == '\\' ) {
 +                                      strncpy( gamedir, path, c + 1 - path );
 +
 +                                      for ( i = 0; i < strlen( gamedir ); i++ )
 +                                      {
 +                                              if ( gamedir[i] == '\\' ) {
 +                                                      gamedir[i] = '/';
 +                                              }
 +                                      }
 +
 +                                      Sys_Printf( "gamedir: %s\n", gamedir );
 +
 +                                      if ( !writedir[0] ) {
 +                                              strcpy( writedir, gamedir );
 +                                      }
 +                                      else if ( writedir[strlen( writedir ) - 1] != '/' ) {
 +                                              writedir[strlen( writedir )] = '/';
 +                                              writedir[strlen( writedir ) + 1] = 0;
 +                                      }
 +
 +                                      return;
 +                              }
 +                              c++;
 +                      }
 +                      Error( "No gamedir in %s", path );
 +                      return;
 +              }
 +      }
 +      Error( "SetQdirFromPath: no '%s' in %s", BASEDIRNAME, path );
 +}
 +
 +char *ExpandArg( const char *path ){
 +      static char full[1024];
 +
 +      if ( path[0] != '/' && path[0] != '\\' && path[1] != ':' ) {
 +              Q_getwd( full );
 +              strcat( full, path );
 +      }
 +      else{
 +              strcpy( full, path );
 +      }
 +      return full;
 +}
 +
 +char *ExpandPath( const char *path ){
 +      static char full[1024];
 +      if ( !qdir ) {
 +              Error( "ExpandPath called without qdir set" );
 +      }
 +      if ( path[0] == '/' || path[0] == '\\' || path[1] == ':' ) {
 +              strcpy( full, path );
 +              return full;
 +      }
 +      sprintf( full, "%s%s", qdir, path );
 +      return full;
 +}
 +
 +char *ExpandGamePath( const char *path ){
 +      static char full[1024];
 +      if ( !qdir ) {
 +              Error( "ExpandGamePath called without qdir set" );
 +      }
 +      if ( path[0] == '/' || path[0] == '\\' || path[1] == ':' ) {
 +              strcpy( full, path );
 +              return full;
 +      }
 +      sprintf( full, "%s%s", gamedir, path );
 +      return full;
 +}
 +
 +char *ExpandPathAndArchive( const char *path ){
 +      char    *expanded;
 +      char archivename[1024];
 +
 +      expanded = ExpandPath( path );
 +
 +      if ( archive ) {
 +              sprintf( archivename, "%s/%s", archivedir, path );
 +              QCopyFile( expanded, archivename );
 +      }
 +      return expanded;
 +}
 +
 +
 +char *copystring( const char *s ){
 +      char    *b;
 +      b = safe_malloc( strlen( s ) + 1 );
 +      strcpy( b, s );
 +      return b;
 +}
 +
 +
 +
 +/*
 +   ================
 +   I_FloatTime
 +   ================
 + */
 +double I_FloatTime( void ){
 +      time_t t;
 +
 +      time( &t );
 +
 +      return t;
 +#if 0
 +// more precise, less portable
 +      struct timeval tp;
 +      struct timezone tzp;
 +      static int secbase;
 +
 +      gettimeofday( &tp, &tzp );
 +
 +      if ( !secbase ) {
 +              secbase = tp.tv_sec;
 +              return tp.tv_usec / 1000000.0;
 +      }
 +
 +      return ( tp.tv_sec - secbase ) + tp.tv_usec / 1000000.0;
 +#endif
 +}
 +
 +void Q_getwd( char *out ){
 +      int i = 0;
 +
 +#if GDEF_OS_WINDOWS
 +      _getcwd( out, 256 );
 +      strcat( out, "\\" );
 +#else // !GDEF_OS_WINDOWS
 +      // Gef: Changed from getwd() to getcwd() to avoid potential buffer overflow
 +      getcwd( out, 256 );
 +      strcat( out, "/" );
 +#endif // !GDEF_OS_WINDOWS
 +      while ( out[i] != 0 )
 +      {
 +              if ( out[i] == '\\' ) {
 +                      out[i] = '/';
 +              }
 +              i++;
 +      }
 +}
 +
 +
 +void Q_mkdir( const char *path ){
 +#if GDEF_OS_WINDOWS
 +      if ( _mkdir( path ) != -1 ) {
 +              return;
 +      }
 +#else // !GDEF_OS_WINDOWS
 +      if ( mkdir( path, 0777 ) != -1 ) {
 +              return;
 +      }
 +#endif // !GDEF_OS_WINDOWS
 +      if ( errno != EEXIST ) {
 +              Error( "mkdir %s: %s",path, strerror( errno ) );
 +      }
 +}
 +
 +/*
 +   ============
 +   FileTime
 +
 +   returns -1 if not present
 +   ============
 + */
 +int FileTime( const char *path ){
 +      struct  stat buf;
 +
 +      if ( stat( path,&buf ) == -1 ) {
 +              return -1;
 +      }
 +
 +      return buf.st_mtime;
 +}
 +
 +
 +
 +/*
 +   ==============
 +   COM_Parse
 +
 +   Parse a token out of a string
 +   ==============
 + */
 +char *COM_Parse( char *data ){
 +      int c;
 +      int len;
 +
 +      len = 0;
 +      com_token[0] = 0;
 +
 +      if ( !data ) {
 +              return NULL;
 +      }
 +
 +// skip whitespace
 +skipwhite:
 +      while ( ( c = *data ) <= ' ' )
 +      {
 +              if ( c == 0 ) {
 +                      com_eof = true;
 +                      return NULL;            // end of file;
 +              }
 +              data++;
 +      }
 +
 +// skip // comments
 +      if ( c == '/' && data[1] == '/' ) {
 +              while ( *data && *data != '\n' )
 +                      data++;
 +              goto skipwhite;
 +      }
 +
 +
 +// handle quoted strings specially
 +      if ( c == '\"' ) {
 +              data++;
 +              do
 +              {
 +                      c = *data++;
 +                      if ( c == '\"' ) {
 +                              com_token[len] = 0;
 +                              return data;
 +                      }
 +                      com_token[len] = c;
 +                      len++;
 +              } while ( 1 );
 +      }
 +
 +// parse single characters
 +      if ( c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ':' ) {
 +              com_token[len] = c;
 +              len++;
 +              com_token[len] = 0;
 +              return data + 1;
 +      }
 +
 +// parse a regular word
 +      do
 +      {
 +              com_token[len] = c;
 +              data++;
 +              len++;
 +              c = *data;
 +              if ( c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ':' ) {
 +                      break;
 +              }
 +      } while ( c > 32 );
 +
 +      com_token[len] = 0;
 +      return data;
 +}
 +
 +int Q_strncasecmp( const char *s1, const char *s2, int n ){
 +      int c1, c2;
 +
 +      do
 +      {
 +              c1 = *s1++;
 +              c2 = *s2++;
 +
 +              if ( !n-- ) {
 +                      return 0;       // strings are equal until end point
 +
 +              }
 +              if ( c1 != c2 ) {
 +                      if ( c1 >= 'a' && c1 <= 'z' ) {
 +                              c1 -= ( 'a' - 'A' );
 +                      }
 +                      if ( c2 >= 'a' && c2 <= 'z' ) {
 +                              c2 -= ( 'a' - 'A' );
 +                      }
 +                      if ( c1 != c2 ) {
 +                              return -1;      // strings not equal
 +                      }
 +              }
 +      } while ( c1 );
 +
 +      return 0;       // strings are equal
 +}
 +
 +int Q_stricmp( const char *s1, const char *s2 ){
 +      return Q_strncasecmp( s1, s2, 99999 );
 +}
 +
 +int Q_strcasecmp( const char *s1, const char *s2 ){
 +      return Q_strncasecmp( s1, s2, 99999 );
 +}
 +
 +// May be already defined with some compilers on Windows
 +#ifndef strupr
 +char *strupr (char *start)
 +{
 +      char    *in;
 +      in = start;
 +      while (*in)
 +      {
 +              *in = toupper(*in);
 +              in++;
 +      }
 +      return start;
 +}
 +#endif
 +
 +char *strlower( char *start ){
 +      char    *in;
 +      in = start;
 +      while ( *in )
 +      {
 +              *in = tolower( *in );
 +              in++;
 +      }
 +      return start;
 +}
 +
 +
 +/*
 +   =============================================================================
 +
 +                        MISC FUNCTIONS
 +
 +   =============================================================================
 + */
 +
 +
 +/*
 +   =================
 +   CheckParm
 +
 +   Checks for the given parameter in the program's command line arguments
 +   Returns the argument number (1 to argc-1) or 0 if not present
 +   =================
 + */
 +int CheckParm( const char *check ){
 +      int i;
 +
 +      for ( i = 1; i < myargc; i++ )
 +      {
 +              if ( !Q_stricmp( check, myargv[i] ) ) {
 +                      return i;
 +              }
 +      }
 +
 +      return 0;
 +}
 +
 +
 +
 +/*
 +   ================
 +   Q_filelength
 +   ================
 + */
 +int Q_filelength( FILE *f ){
 +      int pos;
 +      int end;
 +
 +      pos = ftell( f );
 +      fseek( f, 0, SEEK_END );
 +      end = ftell( f );
 +      fseek( f, pos, SEEK_SET );
 +
 +      return end;
 +}
 +
 +
 +FILE *SafeOpenWrite( const char *filename ){
 +      FILE    *f;
 +
 +      f = fopen( filename, "wb" );
 +
 +      if ( !f ) {
 +              Error( "Error opening %s: %s",filename,strerror( errno ) );
 +      }
 +
 +      return f;
 +}
 +
 +FILE *SafeOpenRead( const char *filename ){
 +      FILE    *f;
 +
 +      f = fopen( filename, "rb" );
 +
 +      if ( !f ) {
 +              Error( "Error opening %s: %s",filename,strerror( errno ) );
 +      }
 +
 +      return f;
 +}
 +
 +
 +void SafeRead( FILE *f, void *buffer, int count ){
 +      if ( fread( buffer, 1, count, f ) != (size_t)count ) {
 +              Error( "File read failure" );
 +      }
 +}
 +
 +
 +void SafeWrite( FILE *f, const void *buffer, int count ){
 +      if ( fwrite( buffer, 1, count, f ) != (size_t)count ) {
 +              Error( "File write failure" );
 +      }
 +}
 +
 +
 +/*
 +   ==============
 +   FileExists
 +   ==============
 + */
 +qboolean    FileExists( const char *filename ){
 +      FILE    *f;
 +
 +      f = fopen( filename, "r" );
 +      if ( !f ) {
 +              return false;
 +      }
 +      fclose( f );
 +      return true;
 +}
 +
 +/*
 +   ==============
 +   LoadFile
 +   ==============
 + */
 +int    LoadFile( const char *filename, void **bufferptr ){
 +      FILE    *f;
 +      int length;
 +      void    *buffer;
 +
 +      f = SafeOpenRead( filename );
 +      length = Q_filelength( f );
 +      buffer = safe_malloc( length + 1 );
 +      ( (char *)buffer )[length] = 0;
 +      SafeRead( f, buffer, length );
 +      fclose( f );
 +
 +      *bufferptr = buffer;
 +      return length;
 +}
 +
 +
 +/*
 +   ==============
 +   LoadFileBlock
 +   -
 +   rounds up memory allocation to 4K boundry
 +   -
 +   ==============
 + */
 +int    LoadFileBlock( const char *filename, void **bufferptr ){
 +      FILE    *f;
 +      int length, nBlock, nAllocSize;
 +      void    *buffer;
 +
 +      f = SafeOpenRead( filename );
 +      length = Q_filelength( f );
 +      nAllocSize = length;
 +      nBlock = nAllocSize % MEM_BLOCKSIZE;
 +      if ( nBlock > 0 ) {
 +              nAllocSize += MEM_BLOCKSIZE - nBlock;
 +      }
 +      buffer = safe_malloc( nAllocSize + 1 );
 +      memset( buffer, 0, nAllocSize + 1 );
 +      SafeRead( f, buffer, length );
 +      fclose( f );
 +
 +      *bufferptr = buffer;
 +      return length;
 +}
 +
 +
 +/*
 +   ==============
 +   TryLoadFile
 +
 +   Allows failure
 +   ==============
 + */
 +int    TryLoadFile( const char *filename, void **bufferptr ){
 +      FILE    *f;
 +      int length;
 +      void    *buffer;
 +
 +      *bufferptr = NULL;
 +
 +      f = fopen( filename, "rb" );
 +      if ( !f ) {
 +              return -1;
 +      }
 +      length = Q_filelength( f );
 +      buffer = safe_malloc( length + 1 );
 +      ( (char *)buffer )[length] = 0;
 +      SafeRead( f, buffer, length );
 +      fclose( f );
 +
 +      *bufferptr = buffer;
 +      return length;
 +}
 +
 +
 +/*
 +   ==============
 +   SaveFile
 +   ==============
 + */
 +void    SaveFile( const char *filename, const void *buffer, int count ){
 +      FILE    *f;
 +
 +      f = SafeOpenWrite( filename );
 +      SafeWrite( f, buffer, count );
 +      fclose( f );
 +}
 +
 +
 +
 +void DefaultExtension( char *path, const char *extension ){
 +      char    *src;
 +//
 +// if path doesnt have a .EXT, append extension
 +// (extension should include the .)
 +//
 +      src = path + strlen( path ) - 1;
 +
 +      while ( *src != '/' && *src != '\\' && src != path )
 +      {
 +              if ( *src == '.' ) {
 +                      return;                 // it has an extension
 +              }
 +              src--;
 +      }
 +
 +      strcat( path, extension );
 +}
 +
 +
 +void DefaultPath( char *path, const char *basepath ){
 +      char temp[128];
 +
 +      if ( path[ 0 ] == '/' || path[ 0 ] == '\\' ) {
 +              return;                   // absolute path location
 +      }
 +      strcpy( temp,path );
 +      strcpy( path,basepath );
 +      strcat( path,temp );
 +}
 +
 +
 +void    StripFilename( char *path ){
 +      int length;
 +
 +      length = strlen( path ) - 1;
 +      while ( length > 0 && path[length] != '/' && path[ length ] != '\\' )
 +              length--;
 +      path[length] = 0;
 +}
 +
 +void    StripExtension( char *path ){
 +      int length;
 +
 +      length = strlen( path ) - 1;
 +      while ( length > 0 && path[length] != '.' )
 +      {
 +              length--;
 +              if ( path[length] == '/' || path[ length ] == '\\' ) {
 +                      return;     // no extension
 +              }
 +      }
 +      if ( length ) {
 +              path[length] = 0;
 +      }
 +}
 +
 +
 +/*
 +   ====================
 +   Extract file parts
 +   ====================
 + */
 +
 +// FIXME: should include the slash, otherwise
 +// backing to an empty path will be wrong when appending a slash
 +void ExtractFilePath( const char *path, char *dest ){
 +      const char    *src;
 +
 +      src = path + strlen( path ) - 1;
 +
 +//
 +// back up until a \ or the start
 +//
 +      while ( src != path && *( src - 1 ) != '\\' && *( src - 1 ) != '/' )
 +              src--;
 +
 +      memcpy( dest, path, src - path );
 +      dest[src - path] = 0;
 +}
 +
 +void ExtractFileBase( const char *path, char *dest ){
 +      const char    *src;
 +
 +      src = path + strlen( path ) - 1;
 +
 +//
 +// back up until a \ or the start
 +//
 +      while ( src != path && *( src - 1 ) != '/' && *( src - 1 ) != '\\' )
 +              src--;
 +
 +      while ( *src && *src != '.' )
 +      {
 +              *dest++ = *src++;
 +      }
 +      *dest = 0;
 +}
 +
 +void ExtractFileExtension( const char *path, char *dest ){
 +      const char    *src;
 +
 +      src = path + strlen( path ) - 1;
 +
 +//
 +// back up until a . or the start
 +//
 +      while ( src != path && *( src - 1 ) != '.' )
 +              src--;
 +      if ( src == path ) {
 +              *dest = 0;  // no extension
 +              return;
 +      }
 +
 +      strcpy( dest,src );
 +}
 +
 +
 +/*
 +   ==============
 +   ParseNum / ParseHex
 +   ==============
 + */
 +int ParseHex( const char *hex ){
 +      const char    *str;
 +      int num;
 +
 +      num = 0;
 +      str = hex;
 +
 +      while ( *str )
 +      {
 +              num <<= 4;
 +              if ( *str >= '0' && *str <= '9' ) {
 +                      num += *str - '0';
 +              }
 +              else if ( *str >= 'a' && *str <= 'f' ) {
 +                      num += 10 + *str - 'a';
 +              }
 +              else if ( *str >= 'A' && *str <= 'F' ) {
 +                      num += 10 + *str - 'A';
 +              }
 +              else{
 +                      Error( "Bad hex number: %s",hex );
 +              }
 +              str++;
 +      }
 +
 +      return num;
 +}
 +
 +
 +int ParseNum( const char *str ){
 +      if ( str[0] == '$' ) {
 +              return ParseHex( str + 1 );
 +      }
 +      if ( str[0] == '0' && str[1] == 'x' ) {
 +              return ParseHex( str + 2 );
 +      }
 +      return atol( str );
 +}
 +/*
 +   // all output ends up through here
 +   void FPrintf (int flag, char *buf)
 +   {
++   printf( "%s", buf );
 +
 +   }
 +
 +   void Sys_FPrintf (int flag, const char *format, ...)
 +   {
 +   char out_buffer[4096];
 +    va_list argptr;
 +
 +   if ((flag == SYS_VRB) && (verbose == false))
 +    return;
 +
 +   va_start (argptr, format);
 +    vsprintf (out_buffer, format, argptr);
 +    va_end (argptr);
 +
 +   FPrintf (flag, out_buffer);
 +   }
 +
 +   void Sys_Printf (const char *format, ...)
 +   {
 +   char out_buffer[4096];
 +    va_list argptr;
 +
 +   va_start (argptr, format);
 +    vsprintf (out_buffer, format, argptr);
 +    va_end (argptr);
 +
 +   FPrintf (SYS_STD, out_buffer);
 +   }
 +
 +   //=================
 +   //Error
 +   //
 +   //For abnormal program terminations
 +   //=================
 +
 +   void Error( const char *error, ...)
 +   {
 +   char out_buffer[4096];
 +   char tmp[4096];
 +    va_list argptr;
 +
 +    va_start (argptr,error);
 +    vsprintf (tmp, error, argptr);
 +    va_end (argptr);
 +
 +   sprintf( out_buffer, "************ ERROR ************\n%s\n", tmp );
 +
 +   FPrintf( SYS_ERR, out_buffer );
 +
 +    exit (1);
 +   }
 +
 + */
 +
 +/*
 +   ============================================================================
 +
 +                    BYTE ORDER FUNCTIONS
 +
 +   ============================================================================
 + */
 +
 +#if GDEF_ARCH_ENDIAN_BIG
 +
 +short   LittleShort( short l ){
 +      byte b1,b2;
 +
 +      b1 = l & 255;
 +      b2 = ( l >> 8 ) & 255;
 +
 +      return ( b1 << 8 ) + b2;
 +}
 +
 +short   BigShort( short l ){
 +      return l;
 +}
 +
 +
 +int    LittleLong( int l ){
 +      byte b1,b2,b3,b4;
 +
 +      b1 = l & 255;
 +      b2 = ( l >> 8 ) & 255;
 +      b3 = ( l >> 16 ) & 255;
 +      b4 = ( l >> 24 ) & 255;
 +
 +      return ( (int)b1 << 24 ) + ( (int)b2 << 16 ) + ( (int)b3 << 8 ) + b4;
 +}
 +
 +int    BigLong( int l ){
 +      return l;
 +}
 +
 +
 +float   LittleFloat( float l ){
 +      union {byte b[4]; float f; } in, out;
 +
 +      in.f = l;
 +      out.b[0] = in.b[3];
 +      out.b[1] = in.b[2];
 +      out.b[2] = in.b[1];
 +      out.b[3] = in.b[0];
 +
 +      return out.f;
 +}
 +
 +float   BigFloat( float l ){
 +      return l;
 +}
 +
 +
 +#else // !GDEF_ARCH_ENDIAN_BIG
 +
 +
 +short   BigShort( short l ){
 +      byte b1,b2;
 +
 +      b1 = l & 255;
 +      b2 = ( l >> 8 ) & 255;
 +
 +      return ( b1 << 8 ) + b2;
 +}
 +
 +short   LittleShort( short l ){
 +      return l;
 +}
 +
 +
 +int    BigLong( int l ){
 +      byte b1,b2,b3,b4;
 +
 +      b1 = l & 255;
 +      b2 = ( l >> 8 ) & 255;
 +      b3 = ( l >> 16 ) & 255;
 +      b4 = ( l >> 24 ) & 255;
 +
 +      return ( (int)b1 << 24 ) + ( (int)b2 << 16 ) + ( (int)b3 << 8 ) + b4;
 +}
 +
 +int    LittleLong( int l ){
 +      return l;
 +}
 +
 +float   BigFloat( float l ){
 +      union {byte b[4]; float f; } in, out;
 +
 +      in.f = l;
 +      out.b[0] = in.b[3];
 +      out.b[1] = in.b[2];
 +      out.b[2] = in.b[1];
 +      out.b[3] = in.b[0];
 +
 +      return out.f;
 +}
 +
 +float   LittleFloat( float l ){
 +      return l;
 +}
 +
 +#endif // ! GDEF_ARCH_ENDIAN_BIG
 +
 +
 +//=======================================================
 +
 +
 +// FIXME: byte swap?
 +
 +// this is a 16 bit, non-reflected CRC using the polynomial 0x1021
 +// and the initial and final xor values shown below...  in other words, the
 +// CCITT standard CRC used by XMODEM
 +
 +#define CRC_INIT_VALUE  0xffff
 +#define CRC_XOR_VALUE   0x0000
 +
 +static unsigned short crctable[256] =
 +{
 +      0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
 +      0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
 +      0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
 +      0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
 +      0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
 +      0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
 +      0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
 +      0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
 +      0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
 +      0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
 +      0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
 +      0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
 +      0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
 +      0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
 +      0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
 +      0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
 +      0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
 +      0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
 +      0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
 +      0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
 +      0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
 +      0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
 +      0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
 +      0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
 +      0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
 +      0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
 +      0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
 +      0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
 +      0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
 +      0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
 +      0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
 +      0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
 +};
 +
 +void CRC_Init( unsigned short *crcvalue ){
 +      *crcvalue = CRC_INIT_VALUE;
 +}
 +
 +void CRC_ProcessByte( unsigned short *crcvalue, byte data ){
 +      *crcvalue = ( *crcvalue << 8 ) ^ crctable[( *crcvalue >> 8 ) ^ data];
 +}
 +
 +unsigned short CRC_Value( unsigned short crcvalue ){
 +      return crcvalue ^ CRC_XOR_VALUE;
 +}
 +//=============================================================================
 +
 +/*
 +   ============
 +   CreatePath
 +   ============
 + */
 +void    CreatePath( const char *path ){
 +      const char  *ofs;
 +      char c;
 +      char dir[1024];
 +
 +#if GDEF_OS_WINDOWS
 +      int olddrive = -1;
 +
 +      if ( path[1] == ':' ) {
 +              olddrive = _getdrive();
 +              _chdrive( toupper( path[0] ) - 'A' + 1 );
 +      }
 +#endif // !GDEF_OS_WINDOWS
 +
 +      if ( path[1] == ':' ) {
 +              path += 2;
 +      }
 +
 +      for ( ofs = path + 1 ; *ofs ; ofs++ )
 +      {
 +              c = *ofs;
 +              if ( c == '/' || c == '\\' ) { // create the directory
 +                      memcpy( dir, path, ofs - path );
 +                      dir[ ofs - path ] = 0;
 +                      Q_mkdir( dir );
 +              }
 +      }
 +
 +#if GDEF_OS_WINDOWS
 +      if ( olddrive != -1 ) {
 +              _chdrive( olddrive );
 +      }
 +#endif // !GDEF_OS_WINDOWS
 +}
 +
 +
 +/*
 +   ============
 +   QCopyFile
 +
 +   Used to archive source files
 +   ============
 + */
 +void QCopyFile( const char *from, const char *to ){
 +      void    *buffer;
 +      int length;
 +
 +      length = LoadFile( from, &buffer );
 +      CreatePath( to );
 +      SaveFile( to, buffer, length );
 +      free( buffer );
 +}
 +
 +void Sys_Sleep( int n ){
 +#if GDEF_OS_WINDOWS
 +      Sleep( n );
 +#else // !GDEF_OS_WINDOWS
 +      usleep( n * 1000 );
 +#endif // !GDEF_OS_WINDOWS
 +}
index 14d6b4a6a06c8983b4a5c26aa1996d99a20fc1fe,efa4257d04cbd7899be8c73807b57b73d416c9cd..15dd5e3b41f427965ed6a425ab6041904c870c92
  
  // to get PATH_MAX
  #include <stdio.h>
 -#if GDEF_OS_LINUX || GDEF_OS_MACOS
 -#include <dirent.h>
 -#include <unistd.h>
 -#else
 +
 +#if GDEF_OS_WINDOWS
  #include <wtypes.h>
  #include <io.h>
+ #ifndef R_OK
+ #define R_OK 04
+ #endif
  #define S_ISDIR( mode ) ( mode & _S_IFDIR )
 +#else // !GDEF_OS_WINDOWS
 +#include <dirent.h>
 +#include <unistd.h>
 +#endif // !GDEF_OS_WINDOWS
 +
 +#ifndef PATH_MAX
  #define PATH_MAX 260
 +#endif // PATH_MAX
 +
 +// PATH_MAX
 +#if defined( __FreeBSD__ )
 +#include <sys/syslimits.h>
  #endif
  
 -#define VFS_MAXDIRS 64
 +// Multiple pakpaths with many pk3dirs can lead
 +// to high list of VFS directories
 +#define VFS_MAXDIRS 256
  
  void vfsInitDirectory( const char *path );
  void vfsShutdown();
index 7858116d84a41a71ed58a26f100a2101f0f97b8e,acf2eacd3ce4af54d09239f04ee93cf19b1ebce8..e738429008fbb6362e93ddf9e194419b14fd3e91
@@@ -586,10 -580,11 +586,10 @@@ static void RadSubdivideDiffuseLight( i
                VectorMA( light->origin, 1.0f, light->normal, light->origin );
                light->dist = DotProduct( light->origin, normal );
  
-               /* optionally create a point splashsplash light for first pass */
+               /* optionally create a point backsplash 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;
  
Simple merge
Simple merge
Simple merge
Simple merge