og-openarena-engine/code/sys/sys_main.c
leilei- e8f5ed153c
November stuff
* - s_interrupt - allows sounds to be interrupted by the same sound or entity channel
- new dynamic light calculation for vertex lighting, affecting vertex color (no projected dlight textures)
- rgbGen material for allowing calculation for diffuse, specular, emmissive vertex colors by hex values
- rgbMod shader command allowing new vertex color effects
- removed deprecated R_ParseStageSimple, it never worked as intended

* - r_slowness gone. Use llvmpipe, PCem, or a slow computer instead.

* Spring cleaning of old deprecated/broken post-process GLSL experiments
- r_anime broke in 2015
- r_tvMode - well, shaderglass exists now
- r_motionblur - Bad technique, too much memory
- t_pslettize - slow, relies on shader's lookup of a vector table
- r_film - bad on well-lit maps
- r_retroAA - this broke early too. also looked bad. would rather implement FSAA 4x

* test

* Cool console things
- cl_consoleScale : makes the console more 640x480 sized on any higher res. Also affects notify messages, so you can read chat easier
- cl_consoleColor also affects the line at the bottom. Also new default colors
- If consoleShader can't load (which will happen with some mods), it will fallback to a flat-colored console.
- Generic'd the red/blue team names.  We will not be having missionpack clans.

* SDL2: Clicking the red X now does something: you can leave!!!

If it sucks.... hit da bricks!!
real winners quit

* s_xmp_startPattern - makes the tracker song play a different pattern (for use with sub-songs)

* - fixed xmp playback as xmp explicitly requires a length of the module now. Fixes issue #96
- suppress the warning about non-22khz music, as mods are playing at the mixer's rate always, and this warning regards a much earlier (1999) unstable sound mixer.

* - deprecating r_modelshader because the shader got stale, old, buggy, and amd hates it now
- r_shadeMethod will be something else (and not shader-based)

* - r_lightmapColorNorm : Make normalization of bright luxels an option, default is 1 (q3 behavior).
- r_lightmapColorNorm 0 = no normalization, straight clamp, like Nightdive's vision of Quake2
- r_lightmapColorNorm 2 = experiment: normalize, but add some luminance on while maintaining the hue by normalizing again. This tries to restore more range on fully saturated colors
- dropped SHADER_MAX_VERTEXES back to 1000 because raising it causes various unexpected issues, so dialing it down for now
- raise MAX_IMAGE_ANIMATIONS to 16 because I've got a cool water shader using it and 8 is too choppy

* - Crash fix for older (<=2001) mods by trimming the string shared with ui module, so no overflow for them
- jettisoning old proposed mme particle system that was never ever hooked up properly.
- other small warning cleanup

* Some renderer refactor and cleanup
- r_shadeMethod : 0/1 = q3 behavior, 2 = ue1-ish behavior, 3 = mix of 1 and 2, -1 = one uniform color, 150-666 = a lod range to change between the 3
- r_monolightmaps : refactor - goes to the light data instead of the calculations and images
- removed r_greyscale because this is a data-modifying novelty that would complicate support for loading compressed texture formats. This is better off as a post-process shader
- environment mapping refactor, rewrite and cleanup
- removed a lot of deprecated rgbGens
- removed r_texdump (it never worked)
- remove a few leftover broken postprocess things

* - Internal GLSL brightness shader, so gamma control can work without the glsl/brightness_fp.glsl file when r_ext_vertex_shader is 1 and r_alternateBrightness is 2.
- r_skyTess - an attempt to make the complexity of skydomes an option so it could use less polygons. Has no effect on skyboxes

* - More r_dynamiclight options:
  r_dynamiclight 2 = Slightly additive dynamic light projections, modeled after the PS2 port
  r_dynamiclight 3 = disables dynamic light projections but substitutes them with flashblends (ala GLQuake). If r_monolightmaps are enabled, the flashblends are orange. Viewblends are left out as the sudden duration of the dynamic lights when firing would be harmful.
- Because of these changes, Riva 128 and Permedia 2 owners should be allowed to enjoy dynamic lights
- option to use ReactOS's wspiapi.h header (file not included)
- some makefile changes to allow an option for more Win 4 (95/NT4) compatiblity easier. Compiling with WINFOUR disables curl, uses SDL1, and has some additional workarounds to get it working on Windows 95 (winsock2 still required though)

* - fixed a fog modulation regression stemming from a rgbMod case returning and not breaking. whoops
- little warning cleanup wrt flashblend

* Sun stuff
- r_drawSun is now default 1 (was 0), because...
- sunShader key - allows sky shaders to explicitly define a shader to use for the sun. In addition to that, a flare type number and a size multiplier number can follow for a little more customization. Partially inspired by RTCW's sunshader key, which only dealt with the image (and never finished their lens flare reflections)
- Suns with a portal on screen won't cancel out the sun or its flare
- If no sun flare is specified, don't draw a sun flare at all. should be one less unnecessary depth read
- r_drawSun 2 is the old 'always show sun' behavior
- sun shader now correctly orientated
- drawing the sun uses a quadstamp
- some 'low end video' alternative shader loading that current does not work. May revert
- ifdefing out shademethod LOD for fixing later

* - GetViewPosition builtin for cgame to allow stuff like text drawn over entities
- MDR physics: allows MDR bones to move independently of model by a defined file on bone numbers, their type, etc. (like hair and flags), but broken (currently ifdef'd out)
- ifdef'd out IQM support as that's broken, we aren't using it, and only other whole games are using it
- Removed attempt at r_lowEndVideo

* - Model fog fix
- Suppressing redundant sound warnings to developer print
- Preliminary DDS texture loading
- Dropping renderergl1 and renderergl2 as they're unsupported, redundant, stale code with none of the new improvements, and we don't use modularized renderers. Still having these files in the tree implies we use them and that can bring confusion.

* - Cgame entity glow renderer hookup
- R_ShowImages: Adjust for overbright
- a tribute to Rebecca Heineman and Jennell Jaquays

* RB_UVcolor: casting as gcc 14 hates this line
makefile - because gcc 14 is fussier, i'll do this wrt VMA for now.
2025-11-23 02:38:33 -05:00

679 lines
13 KiB
C

/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include <signal.h>
#include <stdlib.h>
#include <limits.h>
#include <sys/types.h>
#include <stdarg.h>
#include <stdio.h>
#include <sys/stat.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#ifndef DEDICATED
#ifdef USE_LOCAL_HEADERS
# include "SDL.h"
# include "SDL_cpuinfo.h"
#else
# include <SDL.h>
# include <SDL_cpuinfo.h>
#endif
#endif
#include "sys_local.h"
#include "sys_loadlib.h"
#include "../qcommon/q_shared.h"
#include "../qcommon/qcommon.h"
static char binaryPath[ MAX_OSPATH ] = { 0 };
static char installPath[ MAX_OSPATH ] = { 0 };
/*
=================
Sys_SetBinaryPath
=================
*/
void Sys_SetBinaryPath(const char *path)
{
Q_strncpyz(binaryPath, path, sizeof(binaryPath));
}
/*
=================
Sys_BinaryPath
=================
*/
char *Sys_BinaryPath(void)
{
return binaryPath;
}
/*
=================
Sys_SetDefaultInstallPath
=================
*/
void Sys_SetDefaultInstallPath(const char *path)
{
Q_strncpyz(installPath, path, sizeof(installPath));
}
/*
=================
Sys_DefaultInstallPath
=================
*/
char *Sys_DefaultInstallPath(void)
{
if (*installPath)
return installPath;
else
return Sys_Cwd();
}
/*
=================
Sys_DefaultAppPath
=================
*/
char *Sys_DefaultAppPath(void)
{
return Sys_BinaryPath();
}
/*
=================
Sys_In_Restart_f
Restart the input subsystem
=================
*/
void Sys_In_Restart_f( void )
{
IN_Restart( );
}
/*
=================
Sys_ConsoleInput
Handle new console input
=================
*/
char *Sys_ConsoleInput(void)
{
return CON_Input( );
}
#ifdef DEDICATED
# define PID_FILENAME PRODUCT_NAME "_server.pid"
#else
# define PID_FILENAME PRODUCT_NAME ".pid"
#endif
/*
=================
Sys_PIDFileName
=================
*/
static char *Sys_PIDFileName( void )
{
const char *homePath = Sys_DefaultHomePath( );
if( *homePath != '\0' )
return va( "%s/%s", homePath, PID_FILENAME );
return NULL;
}
/*
=================
Sys_WritePIDFile
Return qtrue if there is an existing stale PID file
=================
*/
qboolean Sys_WritePIDFile( void )
{
char *pidFile = Sys_PIDFileName( );
FILE *f;
qboolean stale = qfalse;
#ifdef WINFOUR
// leilei - workaround to avoid crashes on WinNT4/W9X
if ( pidFiles )
return qfalse;
#endif
if( pidFile == NULL )
return qfalse;
// First, check if the pid file is already there
if( ( f = fopen( pidFile, "r" ) ) != NULL )
{
char pidBuffer[ 64 ] = { 0 };
int pid;
pid = fread( pidBuffer, sizeof( char ), sizeof( pidBuffer ) - 1, f );
fclose( f );
if(pid > 0)
{
pid = atoi( pidBuffer );
if( !Sys_PIDIsRunning( pid ) )
stale = qtrue;
}
else
stale = qtrue;
}
if( ( f = fopen( pidFile, "w" ) ) != NULL )
{
fprintf( f, "%d", Sys_PID( ) );
fclose( f );
}
else
Com_Printf( S_COLOR_YELLOW "Couldn't write %s.\n", pidFile );
return stale;
}
/*
=================
Sys_Exit
Single exit point (regular exit or in case of error)
=================
*/
static __attribute__ ((noreturn)) void Sys_Exit( int exitCode )
{
CON_Shutdown( );
#ifndef DEDICATED
SDL_Quit( );
#endif
if( exitCode < 2 )
{
// Normal exit
char *pidFile = Sys_PIDFileName( );
if( pidFile != NULL )
remove( pidFile );
}
Sys_PlatformExit( );
exit( exitCode );
}
/*
=================
Sys_Quit
=================
*/
void Sys_Quit( void )
{
Sys_Exit( 0 );
}
/*
=================
Sys_GetProcessorFeatures
=================
*/
cpuFeatures_t Sys_GetProcessorFeatures( void )
{
cpuFeatures_t features = 0;
#ifndef DEDICATED
if( SDL_HasRDTSC( ) ) features |= CF_RDTSC;
if( SDL_HasMMX( ) ) features |= CF_MMX;
#if SDL_MAJOR_VERSION != 2
if( SDL_HasMMXExt( ) ) features |= CF_MMX_EXT;
#endif
if( SDL_Has3DNow( ) ) features |= CF_3DNOW;
#if SDL_MAJOR_VERSION != 2
if( SDL_Has3DNowExt( ) ) features |= CF_3DNOW_EXT;
#endif
if( SDL_HasSSE( ) ) features |= CF_SSE;
if( SDL_HasSSE2( ) ) features |= CF_SSE2;
if( SDL_HasAltiVec( ) ) features |= CF_ALTIVEC;
#endif
return features;
}
/*
=================
Sys_Init
=================
*/
void Sys_Init(void)
{
Cmd_AddCommand( "in_restart", Sys_In_Restart_f );
Cvar_Set( "arch", OS_STRING " " ARCH_STRING );
Cvar_Set( "username", Sys_GetCurrentUser( ) );
}
/*
=================
Sys_AnsiColorPrint
Transform Q3 colour codes to ANSI escape sequences
=================
*/
void Sys_AnsiColorPrint( const char *msg )
{
static char buffer[ MAXPRINTMSG ];
int length = 0;
static int q3ToAnsi[ 8 ] =
{
30, // COLOR_BLACK
31, // COLOR_RED
32, // COLOR_GREEN
33, // COLOR_YELLOW
34, // COLOR_BLUE
36, // COLOR_CYAN
35, // COLOR_MAGENTA
0 // COLOR_WHITE
};
while( *msg )
{
if( Q_IsColorString( msg ) || *msg == '\n' )
{
// First empty the buffer
if( length > 0 )
{
buffer[ length ] = '\0';
fputs( buffer, stderr );
length = 0;
}
if( *msg == '\n' )
{
// Issue a reset and then the newline
fputs( "\033[0m\n", stderr );
msg++;
}
else
{
// Print the color code
Com_sprintf( buffer, sizeof( buffer ), "\033[%dm",
q3ToAnsi[ ColorIndex( *( msg + 1 ) ) ] );
fputs( buffer, stderr );
msg += 2;
}
}
else
{
if( length >= MAXPRINTMSG - 1 )
break;
buffer[ length ] = *msg;
length++;
msg++;
}
}
// Empty anything still left in the buffer
if( length > 0 )
{
buffer[ length ] = '\0';
fputs( buffer, stderr );
}
}
#if defined( _WIN32 ) && defined( USE_CONSOLE_WINDOW )
void Conbuf_AppendText( const char *pMsg );// leilei - console restoration
#endif
/*
=================
Sys_Print
=================
*/
void Sys_Print( const char *msg )
{
#if defined( _WIN32 ) && defined( USE_CONSOLE_WINDOW )
Conbuf_AppendText (msg); // leilei - console restoration
#endif
CON_LogWrite( msg );
CON_Print( msg );
}
/*
=================
Sys_Error
=================
*/
void Sys_Error( const char *error, ... )
{
va_list argptr;
char string[1024];
va_start (argptr,error);
Q_vsnprintf (string, sizeof(string), error, argptr);
va_end (argptr);
Sys_ErrorDialog( string );
Sys_Exit( 3 );
}
#if 0
/*
=================
Sys_Warn
=================
*/
static __attribute__ ((format (printf, 1, 2))) void Sys_Warn( char *warning, ... )
{
va_list argptr;
char string[1024];
va_start (argptr,warning);
Q_vsnprintf (string, sizeof(string), warning, argptr);
va_end (argptr);
CON_Print( va( "Warning: %s", string ) );
}
#endif
/*
============
Sys_FileTime
returns -1 if not present
============
*/
int Sys_FileTime( char *path )
{
struct stat buf;
if (stat (path,&buf) == -1)
return -1;
return buf.st_mtime;
}
/*
=================
Sys_UnloadDll
=================
*/
void Sys_UnloadDll( void *dllHandle )
{
if( !dllHandle )
{
Com_Printf("Sys_UnloadDll(NULL)\n");
return;
}
Sys_UnloadLibrary(dllHandle);
}
/*
=================
Sys_LoadDll
First try to load library name from system library path,
from executable path, then fs_basepath.
=================
*/
void *Sys_LoadDll(const char *name, qboolean useSystemLib)
{
void *dllhandle;
if(useSystemLib)
Com_Printf("Trying to load \"%s\"...\n", name);
if(!useSystemLib || !(dllhandle = Sys_LoadLibrary(name)))
{
const char *topDir;
char libPath[MAX_OSPATH];
topDir = Sys_BinaryPath();
if(!*topDir)
topDir = ".";
Com_Printf("Trying to load \"%s\" from \"%s\"...\n", name, topDir);
Com_sprintf(libPath, sizeof(libPath), "%s%c%s", topDir, PATH_SEP, name);
if(!(dllhandle = Sys_LoadLibrary(libPath)))
{
const char *basePath = Cvar_VariableString("fs_basepath");
if(!basePath || !*basePath)
basePath = ".";
if(FS_FilenameCompare(topDir, basePath))
{
Com_Printf("Trying to load \"%s\" from \"%s\"...\n", name, basePath);
Com_sprintf(libPath, sizeof(libPath), "%s%c%s", basePath, PATH_SEP, name);
dllhandle = Sys_LoadLibrary(libPath);
}
if(!dllhandle)
Com_Printf("Loading \"%s\" failed\n", name);
}
}
return dllhandle;
}
/*
=================
Sys_LoadGameDll
Used to load a development dll instead of a virtual machine
=================
*/
void *Sys_LoadGameDll(const char *name,
intptr_t (QDECL **entryPoint)(int, ...),
intptr_t (*systemcalls)(intptr_t, ...))
{
void *libHandle;
void (*dllEntry)(intptr_t (*syscallptr)(intptr_t, ...));
assert(name);
Com_Printf( "Loading DLL file: %s\n", name);
libHandle = Sys_LoadLibrary(name);
if(!libHandle)
{
Com_Printf("Sys_LoadGameDll(%s) failed:\n\"%s\"\n", name, Sys_LibraryError());
return NULL;
}
dllEntry = Sys_LoadFunction( libHandle, "dllEntry" );
*entryPoint = Sys_LoadFunction( libHandle, "vmMain" );
if ( !*entryPoint || !dllEntry )
{
Com_Printf ( "Sys_LoadGameDll(%s) failed to find vmMain function:\n\"%s\" !\n", name, Sys_LibraryError( ) );
Sys_UnloadLibrary(libHandle);
return NULL;
}
Com_Printf ( "Sys_LoadGameDll(%s) found vmMain function at %p\n", name, *entryPoint );
dllEntry( systemcalls );
return libHandle;
}
/*
=================
Sys_ParseArgs
=================
*/
void Sys_ParseArgs( int argc, char **argv )
{
if( argc == 2 )
{
if( !strcmp( argv[1], "--version" ) ||
!strcmp( argv[1], "-v" ) )
{
const char* date = __DATE__;
#ifdef DEDICATED
fprintf( stdout, Q3_VERSION " dedicated server (%s)\n", date );
#else
fprintf( stdout, Q3_VERSION " client (%s)\n", date );
#endif
Sys_Exit( 0 );
}
}
}
#ifndef DEFAULT_BASEDIR
# ifdef MACOS_X
# define DEFAULT_BASEDIR Sys_StripAppBundle(Sys_BinaryPath())
# else
# define DEFAULT_BASEDIR Sys_BinaryPath()
# endif
#endif
/*
=================
Sys_SigHandler
=================
*/
void Sys_SigHandler( int signal )
{
static qboolean signalcaught = qfalse;
if( signalcaught )
{
fprintf( stderr, "DOUBLE SIGNAL FAULT: Received signal %d, exiting...\n",
signal );
}
else
{
signalcaught = qtrue;
VM_Forced_Unload_Start();
#ifndef DEDICATED
CL_Shutdown(va("Received signal %d", signal), qtrue, qtrue);
#endif
SV_Shutdown(va("Received signal %d", signal) );
VM_Forced_Unload_Done();
}
if( signal == SIGTERM || signal == SIGINT )
Sys_Exit( 1 );
else
Sys_Exit( 2 );
}
/*
=================
main
=================
*/
int main( int argc, char **argv )
{
int i;
char commandLine[ MAX_STRING_CHARS ] = { 0 };
#ifndef DEDICATED
// SDL version check
// Compile time
# if !SDL_VERSION_ATLEAST(MINSDL_MAJOR,MINSDL_MINOR,MINSDL_PATCH)
# error A more recent version of SDL is required
# endif
// Run time
#if SDL_MAJOR_VERSION == 2
SDL_version ver[1];
SDL_GetVersion( ver );
#else
const SDL_version *ver = SDL_Linked_Version( );
#endif
#define MINSDL_VERSION \
XSTRING(MINSDL_MAJOR) "." \
XSTRING(MINSDL_MINOR) "." \
XSTRING(MINSDL_PATCH)
if( SDL_VERSIONNUM( ver->major, ver->minor, ver->patch ) <
SDL_VERSIONNUM( MINSDL_MAJOR, MINSDL_MINOR, MINSDL_PATCH ) )
{
Sys_Dialog( DT_ERROR, va( "SDL version " MINSDL_VERSION " or greater is required, "
"but only version %d.%d.%d was found. You may be able to obtain a more recent copy "
"from http://www.libsdl.org/.", ver->major, ver->minor, ver->patch ), "SDL Library Too Old" );
Sys_Exit( 1 );
}
#endif
Sys_PlatformInit( );
// Set the initial time base
Sys_Milliseconds( );
Sys_ParseArgs( argc, argv );
Sys_SetBinaryPath( Sys_Dirname( argv[ 0 ] ) );
Sys_SetDefaultInstallPath( DEFAULT_BASEDIR );
// Concatenate the command line for passing to Com_Init
for( i = 1; i < argc; i++ )
{
const qboolean containsSpaces = strchr(argv[i], ' ') != NULL;
if (containsSpaces)
Q_strcat( commandLine, sizeof( commandLine ), "\"" );
Q_strcat( commandLine, sizeof( commandLine ), argv[ i ] );
if (containsSpaces)
Q_strcat( commandLine, sizeof( commandLine ), "\"" );
Q_strcat( commandLine, sizeof( commandLine ), " " );
}
Com_Init( commandLine );
NET_Init( );
CON_Init( );
signal( SIGILL, Sys_SigHandler );
signal( SIGFPE, Sys_SigHandler );
signal( SIGSEGV, Sys_SigHandler );
signal( SIGTERM, Sys_SigHandler );
signal( SIGINT, Sys_SigHandler );
while( 1 )
{
IN_Frame( qfalse ); // youurayy input lag fix
Com_Frame( );
}
return 0;
}