From 58af049d5f1815d045da0f5221dbcd03319b518d Mon Sep 17 00:00:00 2001 From: Richard Allen Date: Mon, 11 Jul 2011 19:05:03 +0000 Subject: [PATCH] Updating to IOQ3 svn 2064, vbos-glsl-17 and various fixes. --- reaction/Makefile | 3 +- reaction/code/SDL12/include/SDL_opengl.h | 46 +- reaction/code/asm/matha.s | 2 +- reaction/code/asm/qasm.h | 2 +- reaction/code/asm/snd_mixa.s | 2 +- reaction/code/botlib/be_ai_move.c | 2 +- reaction/code/botlib/l_precomp.c | 2 +- reaction/code/cgame/cg_info.c | 2 +- reaction/code/cgame/cg_syscalls.c | 2 +- reaction/code/cgame/cg_weapons.c | 2 +- reaction/code/client/cl_avi.c | 6 +- reaction/code/client/cl_cgame.c | 19 +- reaction/code/client/cl_cin.c | 10 +- reaction/code/client/cl_console.c | 23 +- reaction/code/client/cl_curl.c | 6 +- reaction/code/client/cl_input.c | 86 +- reaction/code/client/cl_keys.c | 20 +- reaction/code/client/cl_main.c | 289 +-- reaction/code/client/cl_parse.c | 16 +- reaction/code/client/cl_scrn.c | 14 +- reaction/code/client/cl_ui.c | 14 +- reaction/code/client/client.h | 20 +- reaction/code/client/snd_codec.c | 158 +- reaction/code/client/snd_codec_ogg.c | 6 +- reaction/code/client/snd_codec_wav.c | 6 +- reaction/code/client/snd_dma.c | 11 +- reaction/code/client/snd_local.h | 1 + reaction/code/client/snd_main.c | 4 +- reaction/code/client/snd_mem.c | 8 +- reaction/code/client/snd_openal.c | 37 +- reaction/code/client/snd_wavelet.c | 2 - reaction/code/game/bg_lib.c | 22 +- reaction/code/game/bg_lib.h | 1 + reaction/code/game/bg_misc.c | 8 +- reaction/code/game/g_bot.c | 2 +- reaction/code/game/g_client.c | 6 +- reaction/code/game/g_cmds.c | 2 +- reaction/code/game/g_main.c | 6 +- reaction/code/jpeg-8c/jconfig.h | 3 +- reaction/code/null/null_client.c | 16 +- reaction/code/q3_ui/ui_atoms.c | 11 +- reaction/code/q3_ui/ui_credits.c | 6 - reaction/code/q3_ui/ui_demo2.c | 2 +- reaction/code/q3_ui/ui_playermodel.c | 5 + reaction/code/q3_ui/ui_splevel.c | 2 +- reaction/code/q3_ui/ui_startserver.c | 2 +- reaction/code/q3_ui/ui_video.c | 42 +- reaction/code/qcommon/cm_polylib.c | 4 +- reaction/code/qcommon/cmd.c | 2 +- reaction/code/qcommon/common.c | 129 +- reaction/code/qcommon/cvar.c | 6 +- reaction/code/qcommon/files.c | 891 +++++--- reaction/code/qcommon/huffman.c | 4 +- reaction/code/qcommon/msg.c | 4 +- reaction/code/qcommon/net_ip.c | 8 +- reaction/code/qcommon/q_math.c | 12 +- reaction/code/qcommon/q_platform.h | 13 +- reaction/code/qcommon/q_shared.c | 93 +- reaction/code/qcommon/q_shared.h | 80 +- reaction/code/qcommon/qcommon.h | 36 +- reaction/code/qcommon/qfiles.h | 2 +- reaction/code/qcommon/vm.c | 115 +- reaction/code/qcommon/vm_interpreted.c | 260 +-- reaction/code/qcommon/vm_local.h | 12 +- reaction/code/qcommon/vm_powerpc.c | 19 +- reaction/code/qcommon/vm_powerpc_asm.c | 3 - reaction/code/qcommon/vm_sparc.c | 50 +- reaction/code/qcommon/vm_x86.c | 2131 ++++++++++++------- reaction/code/qcommon/vm_x86_64.c | 482 ++--- reaction/code/qcommon/vm_x86_64_assembler.c | 127 +- reaction/code/renderer/qgl.h | 1 + reaction/code/renderer/tr_animation.c | 12 +- reaction/code/renderer/tr_backend.c | 84 +- reaction/code/renderer/tr_bsp.c | 66 +- reaction/code/renderer/tr_cmds.c | 23 +- reaction/code/renderer/tr_extramath.c | 26 + reaction/code/renderer/tr_extramath.h | 17 + reaction/code/renderer/tr_flares.c | 1 + reaction/code/renderer/tr_glsl.c | 824 ++++--- reaction/code/renderer/tr_image.c | 99 +- reaction/code/renderer/tr_image_bmp.c | 20 +- reaction/code/renderer/tr_image_jpg.c | 13 +- reaction/code/renderer/tr_image_tga.c | 26 +- reaction/code/renderer/tr_init.c | 52 +- reaction/code/renderer/tr_light.c | 6 +- reaction/code/renderer/tr_local.h | 248 ++- reaction/code/renderer/tr_main.c | 673 +++++- reaction/code/renderer/tr_marks.c | 1 + reaction/code/renderer/tr_mesh.c | 19 +- reaction/code/renderer/tr_model.c | 477 +++-- reaction/code/renderer/tr_public.h | 2 +- reaction/code/renderer/tr_scene.c | 21 +- reaction/code/renderer/tr_shade.c | 993 +++++---- reaction/code/renderer/tr_shade_calc.c | 30 +- reaction/code/renderer/tr_shader.c | 186 +- reaction/code/renderer/tr_sky.c | 43 +- reaction/code/renderer/tr_surface.c | 24 +- reaction/code/renderer/tr_types.h | 3 + reaction/code/renderer/tr_world.c | 224 +- reaction/code/sdl/sdl_glimp.c | 5 +- reaction/code/sdl/sdl_input.c | 27 +- reaction/code/server/server.h | 2 + reaction/code/server/sv_bot.c | 2 +- reaction/code/server/sv_ccmds.c | 2 +- reaction/code/server/sv_client.c | 6 +- reaction/code/server/sv_game.c | 14 +- reaction/code/server/sv_init.c | 12 +- reaction/code/server/sv_main.c | 11 +- reaction/code/server/sv_net_chan.c | 2 +- reaction/code/server/sv_snapshot.c | 4 +- reaction/code/sys/con_win32.c | 2 +- reaction/code/sys/sys_main.c | 40 +- reaction/code/sys/sys_unix.c | 46 +- reaction/code/sys/sys_win32.c | 76 +- reaction/code/tools/asm/cmdlib.c | 10 +- reaction/code/tools/asm/q3asm.c | 8 +- reaction/code/tools/lcc/cpp/include.c | 8 +- reaction/code/tools/lcc/cpp/tokens.c | 13 +- reaction/code/tools/lcc/doc/4.html | 2 +- reaction/code/tools/lcc/etc/lcc.c | 68 +- reaction/code/tools/lcc/lburg/gram.c | 258 ++- reaction/code/ui/ui_players.c | 2 +- 122 files changed, 6387 insertions(+), 3887 deletions(-) diff --git a/reaction/Makefile b/reaction/Makefile index cbb2ce42..3adaf0f4 100644 --- a/reaction/Makefile +++ b/reaction/Makefile @@ -183,7 +183,7 @@ CGDIR=$(MOUNT_DIR)/cgame BLIBDIR=$(MOUNT_DIR)/botlib NDIR=$(MOUNT_DIR)/null UIDIR=$(MOUNT_DIR)/ui -Q3UIDIR=$(MOUNT_DIR)/q3_ui +Q3UIDIR=$(MOUNT_DIR)/ui JPDIR=$(MOUNT_DIR)/jpeg-8c SPEEXDIR=$(MOUNT_DIR)/libspeex ZDIR=$(MOUNT_DIR)/zlib @@ -1442,6 +1442,7 @@ Q3OBJ = \ $(B)/client/tr_vbo.o \ $(B)/client/tr_fbo.o \ $(B)/client/tr_postprocess.o \ + $(B)/client/tr_model_iqm.o \ \ $(B)/client/sdl_gamma.o \ $(B)/client/sdl_input.o \ diff --git a/reaction/code/SDL12/include/SDL_opengl.h b/reaction/code/SDL12/include/SDL_opengl.h index 7966bebc..b204f1bb 100644 --- a/reaction/code/SDL12/include/SDL_opengl.h +++ b/reaction/code/SDL12/include/SDL_opengl.h @@ -65,34 +65,34 @@ extern "C" { #endif /* -** Copyright (c) 2007-2010 The Khronos Group Inc. +** License Applicability. Except to the extent portions of this file are +** made subject to an alternative license as permitted in the SGI Free +** Software License B, Version 1.1 (the "License"), the contents of this +** file are subject only to the provisions of the License. You may not use +** this file except in compliance with the License. You may obtain a copy +** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600 +** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at: ** -** Permission is hereby granted, free of charge, to any person obtaining a -** copy of this software and/or associated documentation files (the -** "Materials"), to deal in the Materials without restriction, including -** without limitation the rights to use, copy, modify, merge, publish, -** distribute, sublicense, and/or sell copies of the Materials, and to -** permit persons to whom the Materials are furnished to do so, subject to -** the following conditions: +** http://oss.sgi.com/projects/FreeB ** -** The above copyright notice and this permission notice shall be included -** in all copies or substantial portions of the Materials. +** Note that, as provided in the License, the Software is distributed on an +** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS +** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND +** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A +** PARTICULAR PURPOSE, AND NON-INFRINGEMENT. ** -** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +** Original Code. The Original Code is: OpenGL Sample Implementation, +** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics, +** Inc. The Original Code is Copyright (c) 1991-2004 Silicon Graphics, Inc. +** Copyright in any portions created by third parties is as indicated +** elsewhere herein. All Rights Reserved. +** +** Additional Notice Provisions: This software was created using the +** OpenGL(R) version 1.2.1 Sample Implementation published by SGI, but has +** not been independently verified as being compliant with the OpenGL(R) +** version 1.2.1 Specification. */ -/* Header file version number, required by OpenGL ABI for Linux */ -/* glext.h last updated $Date: 2010-12-09 02:15:08 -0800 (Thu, 09 Dec 2010) $ */ -/* Current version at http://www.opengl.org/registry/ */ -#define GL_GLEXT_VERSION 67 -/* Function declaration macros - to move into glplatform.h */ - #if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) #define WIN32_LEAN_AND_MEAN 1 #include diff --git a/reaction/code/asm/matha.s b/reaction/code/asm/matha.s index e4770d37..88974d30 100644 --- a/reaction/code/asm/matha.s +++ b/reaction/code/asm/matha.s @@ -15,7 +15,7 @@ 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 Foobar; if not, write to the Free Software +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 =========================================================================== */ diff --git a/reaction/code/asm/qasm.h b/reaction/code/asm/qasm.h index f38acb50..777a3230 100644 --- a/reaction/code/asm/qasm.h +++ b/reaction/code/asm/qasm.h @@ -28,7 +28,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA .section .note.GNU-stack,"",@progbits #endif -#ifdef __ELF__ +#if defined(__ELF__) || defined(__WIN64__) #define C(label) label #else #define C(label) _##label diff --git a/reaction/code/asm/snd_mixa.s b/reaction/code/asm/snd_mixa.s index 4c6be5b7..7c3bf6b2 100644 --- a/reaction/code/asm/snd_mixa.s +++ b/reaction/code/asm/snd_mixa.s @@ -15,7 +15,7 @@ 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 Foobar; if not, write to the Free Software +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 =========================================================================== */ diff --git a/reaction/code/botlib/be_ai_move.c b/reaction/code/botlib/be_ai_move.c index 8ee4ad96..294fc257 100644 --- a/reaction/code/botlib/be_ai_move.c +++ b/reaction/code/botlib/be_ai_move.c @@ -3509,7 +3509,7 @@ void BotResetLastAvoidReach(int movestate) if (latesttime) { ms->avoidreachtimes[latest] = 0; - if (ms->avoidreachtries[i] > 0) ms->avoidreachtries[latest]--; + if (ms->avoidreachtries[latest] > 0) ms->avoidreachtries[latest]--; } //end if } //end of the function BotResetLastAvoidReach //=========================================================================== diff --git a/reaction/code/botlib/l_precomp.c b/reaction/code/botlib/l_precomp.c index 4257594e..f560f2bb 100644 --- a/reaction/code/botlib/l_precomp.c +++ b/reaction/code/botlib/l_precomp.c @@ -271,7 +271,7 @@ token_t *PC_CopyToken(token_t *token) #ifdef BSPC Error("out of token space\n"); #else - Com_Error(ERR_FATAL, "out of token space\n"); + Com_Error(ERR_FATAL, "out of token space"); #endif return NULL; } //end if diff --git a/reaction/code/cgame/cg_info.c b/reaction/code/cgame/cg_info.c index 30445395..4b2cec80 100644 --- a/reaction/code/cgame/cg_info.c +++ b/reaction/code/cgame/cg_info.c @@ -185,7 +185,7 @@ void CG_LoadingClient(int clientNum) if (loadingPlayerIconCount < MAX_LOADING_PLAYER_ICONS) { Q_strncpyz(model, Info_ValueForKey(info, "model"), sizeof(model)); - skin = Q_strrchr(model, '/'); + skin = strrchr(model, '/'); if (skin) { *skin++ = '\0'; } else { diff --git a/reaction/code/cgame/cg_syscalls.c b/reaction/code/cgame/cg_syscalls.c index 98ed883a..d5e7791c 100644 --- a/reaction/code/cgame/cg_syscalls.c +++ b/reaction/code/cgame/cg_syscalls.c @@ -32,7 +32,7 @@ #include "cg_local.h" -static int (QDECL * syscall) (int arg, ...) = (int (QDECL *) (int, ...)) -1; +static intptr_t (QDECL *syscall)( intptr_t arg, ... ) = (intptr_t (QDECL *)( intptr_t, ...))-1; Q_EXPORT void dllEntry( intptr_t (QDECL *syscallptr)( intptr_t arg,... ) ) { syscall = syscallptr; diff --git a/reaction/code/cgame/cg_weapons.c b/reaction/code/cgame/cg_weapons.c index b07b3e88..1dec42e3 100644 --- a/reaction/code/cgame/cg_weapons.c +++ b/reaction/code/cgame/cg_weapons.c @@ -251,7 +251,7 @@ * */ void COM_StripExtensionInPlace(char *name) { - char* ext = Q_strrchr(name, '.'); + char* ext = strrchr(name, '.'); if (ext) *ext = 0; } diff --git a/reaction/code/client/cl_avi.c b/reaction/code/client/cl_avi.c index dd7bd9bc..3b0d7751 100644 --- a/reaction/code/client/cl_avi.c +++ b/reaction/code/client/cl_avi.c @@ -82,7 +82,7 @@ SafeFS_Write static ID_INLINE void SafeFS_Write( const void *buffer, int len, fileHandle_t f ) { if( FS_Write( buffer, len, f ) < len ) - Com_Error( ERR_DROP, "Failed to write avi file\n" ); + Com_Error( ERR_DROP, "Failed to write avi file" ); } /* @@ -142,7 +142,7 @@ static ID_INLINE void START_CHUNK( const char *s ) { if( afd.chunkStackTop == MAX_RIFF_CHUNKS ) { - Com_Error( ERR_DROP, "ERROR: Top of chunkstack breached\n" ); + Com_Error( ERR_DROP, "ERROR: Top of chunkstack breached" ); } afd.chunkStack[ afd.chunkStackTop ] = bufIndex; @@ -162,7 +162,7 @@ static ID_INLINE void END_CHUNK( void ) if( afd.chunkStackTop <= 0 ) { - Com_Error( ERR_DROP, "ERROR: Bottom of chunkstack breached\n" ); + Com_Error( ERR_DROP, "ERROR: Bottom of chunkstack breached" ); } afd.chunkStackTop--; diff --git a/reaction/code/client/cl_cgame.c b/reaction/code/client/cl_cgame.c index 4ed218b9..d9184827 100644 --- a/reaction/code/client/cl_cgame.c +++ b/reaction/code/client/cl_cgame.c @@ -300,7 +300,7 @@ rescan: if ( argc >= 2 ) Com_Error( ERR_SERVERDISCONNECT, "Server disconnected - %s", Cmd_Argv( 1 ) ); else - Com_Error( ERR_SERVERDISCONNECT, "Server disconnected\n" ); + Com_Error( ERR_SERVERDISCONNECT, "Server disconnected" ); } if ( !strcmp( cmd, "bcs0" ) ) { @@ -559,6 +559,7 @@ intptr_t CL_CgameSystemCalls( intptr_t *args ) { return re.RegisterShaderNoMip( VMA(1) ); case CG_R_REGISTERFONT: re.RegisterFont( VMA(1), args[2], VMA(3)); + return 0; case CG_R_CLEARSCENE: re.ClearScene(); return 0; @@ -670,7 +671,7 @@ intptr_t CL_CgameSystemCalls( intptr_t *args ) { case CG_REAL_TIME: return Com_RealTime( VMA(1) ); case CG_SNAPVECTOR: - Sys_SnapVector( VMA(1) ); + Q_SnapVector(VMA(1)); return 0; case CG_CIN_PLAYCINEMATIC: @@ -757,7 +758,7 @@ void CL_InitCGame( void ) { if ( !cgvm ) { Com_Error( ERR_DROP, "VM_Create on cgame failed" ); } - cls.state = CA_LOADING; + clc.state = CA_LOADING; // init for this gamestate // use the lastExecutedServerCommand instead of the serverCommandSequence @@ -770,7 +771,7 @@ void CL_InitCGame( void ) { // we will send a usercmd this frame, which // will cause the server to send us the first snapshot - cls.state = CA_PRIMED; + clc.state = CA_PRIMED; t2 = Sys_Milliseconds(); @@ -908,7 +909,7 @@ void CL_FirstSnapshot( void ) { if ( cl.snap.snapFlags & SNAPFLAG_NOT_ACTIVE ) { return; } - cls.state = CA_ACTIVE; + clc.state = CA_ACTIVE; // set the timedelta so we are exactly on this first frame cl.serverTimeDelta = cl.snap.serverTime - cls.realtime; @@ -979,8 +980,8 @@ CL_SetCGameTime */ void CL_SetCGameTime( void ) { // getting a valid frame message ends the connection process - if ( cls.state != CA_ACTIVE ) { - if ( cls.state != CA_PRIMED ) { + if ( clc.state != CA_ACTIVE ) { + if ( clc.state != CA_PRIMED ) { return; } if ( clc.demoplaying ) { @@ -996,7 +997,7 @@ void CL_SetCGameTime( void ) { cl.newSnapshots = qfalse; CL_FirstSnapshot(); } - if ( cls.state != CA_ACTIVE ) { + if ( clc.state != CA_ACTIVE ) { return; } } @@ -1109,7 +1110,7 @@ void CL_SetCGameTime( void ) { // feed another messag, which should change // the contents of cl.snap CL_ReadDemoMessage(); - if ( cls.state != CA_ACTIVE ) { + if ( clc.state != CA_ACTIVE ) { return; // end of demo } } diff --git a/reaction/code/client/cl_cin.c b/reaction/code/client/cl_cin.c index 3bb20cce..54e72b4b 100644 --- a/reaction/code/client/cl_cin.c +++ b/reaction/code/client/cl_cin.c @@ -1281,7 +1281,7 @@ static void RoQShutdown( void ) { } if (cinTable[currentHandle].alterGameState) { - cls.state = CA_DISCONNECTED; + clc.state = CA_DISCONNECTED; // we can't just do a vstr nextmap, because // if we are aborting the intro cinematic with // a devmap command, nextmap would be valid by @@ -1314,7 +1314,7 @@ e_status CIN_StopCinematic(int handle) { } if (cinTable[currentHandle].alterGameState) { - if ( cls.state != CA_CINEMATIC ) { + if ( clc.state != CA_CINEMATIC ) { return cinTable[currentHandle].status; } } @@ -1355,7 +1355,7 @@ e_status CIN_RunCinematic (int handle) currentHandle = handle; if (cinTable[currentHandle].alterGameState) { - if ( cls.state != CA_CINEMATIC ) { + if ( clc.state != CA_CINEMATIC ) { return cinTable[currentHandle].status; } } @@ -1479,7 +1479,7 @@ int CIN_PlayCinematic( const char *arg, int x, int y, int w, int h, int systemBi Com_DPrintf("trFMV::play(), playing %s\n", arg); if (cinTable[currentHandle].alterGameState) { - cls.state = CA_CINEMATIC; + clc.state = CA_CINEMATIC; } Con_Close(); @@ -1614,7 +1614,7 @@ void CL_PlayCinematic_f(void) { int bits = CIN_system; Com_DPrintf("CL_PlayCinematic_f\n"); - if (cls.state == CA_CINEMATIC) { + if (clc.state == CA_CINEMATIC) { SCR_StopCinematic(); } diff --git a/reaction/code/client/cl_console.c b/reaction/code/client/cl_console.c index 196b5911..26317bee 100644 --- a/reaction/code/client/cl_console.c +++ b/reaction/code/client/cl_console.c @@ -72,7 +72,7 @@ Con_ToggleConsole_f */ void Con_ToggleConsole_f (void) { // Can't toggle the console when it's the only thing available - if ( cls.state == CA_DISCONNECTED && Key_GetCatcher( ) == KEYCATCH_CONSOLE ) { + if ( clc.state == CA_DISCONNECTED && Key_GetCatcher( ) == KEYCATCH_CONSOLE ) { return; } @@ -343,6 +343,21 @@ void Con_Init (void) { Cmd_SetCommandCompletionFunc( "condump", Cmd_CompleteTxtName ); } +/* +================ +Con_Shutdown +================ +*/ +void Con_Shutdown(void) +{ + Cmd_RemoveCommand("toggleconsole"); + Cmd_RemoveCommand("messagemode"); + Cmd_RemoveCommand("messagemode2"); + Cmd_RemoveCommand("messagemode3"); + Cmd_RemoveCommand("messagemode4"); + Cmd_RemoveCommand("clear"); + Cmd_RemoveCommand("condump"); +} /* =============== @@ -487,7 +502,7 @@ Draw the editline after a ] prompt void Con_DrawInput (void) { int y; - if ( cls.state != CA_DISCONNECTED && !(Key_GetCatcher( ) & KEYCATCH_CONSOLE ) ) { + if ( clc.state != CA_DISCONNECTED && !(Key_GetCatcher( ) & KEYCATCH_CONSOLE ) ) { return; } @@ -704,7 +719,7 @@ void Con_DrawConsole( void ) { Con_CheckResize (); // if disconnected, render console full screen - if ( cls.state == CA_DISCONNECTED ) { + if ( clc.state == CA_DISCONNECTED ) { if ( !( Key_GetCatcher( ) & (KEYCATCH_UI | KEYCATCH_CGAME)) ) { Con_DrawSolidConsole( 1.0 ); return; @@ -715,7 +730,7 @@ void Con_DrawConsole( void ) { Con_DrawSolidConsole( con.displayFrac ); } else { // draw notify lines - if ( cls.state == CA_ACTIVE ) { + if ( clc.state == CA_ACTIVE ) { Con_DrawNotify (); } } diff --git a/reaction/code/client/cl_curl.c b/reaction/code/client/cl_curl.c index 170e97b9..16a73b66 100644 --- a/reaction/code/client/cl_curl.c +++ b/reaction/code/client/cl_curl.c @@ -251,13 +251,13 @@ void CL_cURL_BeginDownload( const char *localName, const char *remoteURL ) clc.downloadCURL = qcurl_easy_init(); if(!clc.downloadCURL) { Com_Error(ERR_DROP, "CL_cURL_BeginDownload: qcurl_easy_init() " - "failed\n"); + "failed"); return; } clc.download = FS_SV_FOpenFileWrite(clc.downloadTempName); if(!clc.download) { Com_Error(ERR_DROP, "CL_cURL_BeginDownload: failed to open " - "%s for writing\n", clc.downloadTempName); + "%s for writing", clc.downloadTempName); return; } qcurl_easy_setopt(clc.downloadCURL, CURLOPT_WRITEDATA, clc.download); @@ -284,7 +284,7 @@ void CL_cURL_BeginDownload( const char *localName, const char *remoteURL ) qcurl_easy_cleanup(clc.downloadCURL); clc.downloadCURL = NULL; Com_Error(ERR_DROP, "CL_cURL_BeginDownload: qcurl_multi_init() " - "failed\n"); + "failed"); return; } qcurl_multi_add_handle(clc.downloadCURLM, clc.downloadCURL); diff --git a/reaction/code/client/cl_input.c b/reaction/code/client/cl_input.c index 898a7b5a..60c26be4 100644 --- a/reaction/code/client/cl_input.c +++ b/reaction/code/client/cl_input.c @@ -640,7 +640,7 @@ void CL_CreateNewCommands( void ) { int cmdNum; // no need to create usercmds until we have a gamestate - if ( cls.state < CA_PRIMED ) { + if ( clc.state < CA_PRIMED ) { return; } @@ -677,7 +677,7 @@ qboolean CL_ReadyToSendPacket( void ) { int delta; // don't send anything if playing back a demo - if ( clc.demoplaying || cls.state == CA_CINEMATIC ) { + if ( clc.demoplaying || clc.state == CA_CINEMATIC ) { return qfalse; } @@ -689,8 +689,8 @@ qboolean CL_ReadyToSendPacket( void ) { // if we don't have a valid gamestate yet, only send // one packet a second - if ( cls.state != CA_ACTIVE && - cls.state != CA_PRIMED && + if ( clc.state != CA_ACTIVE && + clc.state != CA_PRIMED && !*clc.downloadTempName && cls.realtime - clc.lastPacketSentTime < 1000 ) { return qfalse; @@ -754,7 +754,7 @@ void CL_WritePacket( void ) { int count, key; // don't send anything if playing back a demo - if ( clc.demoplaying || cls.state == CA_CINEMATIC ) { + if ( clc.demoplaying || clc.state == CA_CINEMATIC ) { return; } @@ -949,7 +949,7 @@ Called every frame to builds and sends a command packet to the server. */ void CL_SendCmd( void ) { // don't send any message if not connected - if ( cls.state < CA_CONNECTED ) { + if ( clc.state < CA_CONNECTED ) { return; } @@ -1047,3 +1047,77 @@ void CL_InitInput( void ) { cl_nodelta = Cvar_Get ("cl_nodelta", "0", 0); cl_debugMove = Cvar_Get ("cl_debugMove", "0", 0); } + +/* +============ +CL_ShutdownInput +============ +*/ +void CL_ShutdownInput(void) +{ + Cmd_RemoveCommand("centerview"); + + Cmd_RemoveCommand("+moveup"); + Cmd_RemoveCommand("-moveup"); + Cmd_RemoveCommand("+movedown"); + Cmd_RemoveCommand("-movedown"); + Cmd_RemoveCommand("+left"); + Cmd_RemoveCommand("-left"); + Cmd_RemoveCommand("+right"); + Cmd_RemoveCommand("-right"); + Cmd_RemoveCommand("+forward"); + Cmd_RemoveCommand("-forward"); + Cmd_RemoveCommand("+back"); + Cmd_RemoveCommand("-back"); + Cmd_RemoveCommand("+lookup"); + Cmd_RemoveCommand("-lookup"); + Cmd_RemoveCommand("+lookdown"); + Cmd_RemoveCommand("-lookdown"); + Cmd_RemoveCommand("+strafe"); + Cmd_RemoveCommand("-strafe"); + Cmd_RemoveCommand("+moveleft"); + Cmd_RemoveCommand("-moveleft"); + Cmd_RemoveCommand("+moveright"); + Cmd_RemoveCommand("-moveright"); + Cmd_RemoveCommand("+speed"); + Cmd_RemoveCommand("-speed"); + Cmd_RemoveCommand("+attack"); + Cmd_RemoveCommand("-attack"); + Cmd_RemoveCommand("+button0"); + Cmd_RemoveCommand("-button0"); + Cmd_RemoveCommand("+button1"); + Cmd_RemoveCommand("-button1"); + Cmd_RemoveCommand("+button2"); + Cmd_RemoveCommand("-button2"); + Cmd_RemoveCommand("+button3"); + Cmd_RemoveCommand("-button3"); + Cmd_RemoveCommand("+button4"); + Cmd_RemoveCommand("-button4"); + Cmd_RemoveCommand("+button5"); + Cmd_RemoveCommand("-button5"); + Cmd_RemoveCommand("+button6"); + Cmd_RemoveCommand("-button6"); + Cmd_RemoveCommand("+button7"); + Cmd_RemoveCommand("-button7"); + Cmd_RemoveCommand("+button8"); + Cmd_RemoveCommand("-button8"); + Cmd_RemoveCommand("+button9"); + Cmd_RemoveCommand("-button9"); + Cmd_RemoveCommand("+button10"); + Cmd_RemoveCommand("-button10"); + Cmd_RemoveCommand("+button11"); + Cmd_RemoveCommand("-button11"); + Cmd_RemoveCommand("+button12"); + Cmd_RemoveCommand("-button12"); + Cmd_RemoveCommand("+button13"); + Cmd_RemoveCommand("-button13"); + Cmd_RemoveCommand("+button14"); + Cmd_RemoveCommand("-button14"); + Cmd_RemoveCommand("+mlook"); + Cmd_RemoveCommand("-mlook"); + +#ifdef USE_VOIP + Cmd_RemoveCommand("+voiprecord"); + Cmd_RemoveCommand("-voiprecord"); +#endif +} diff --git a/reaction/code/client/cl_keys.c b/reaction/code/client/cl_keys.c index d9bd1364..8438fa11 100644 --- a/reaction/code/client/cl_keys.c +++ b/reaction/code/client/cl_keys.c @@ -586,7 +586,7 @@ void Console_Key (int key) { // enter finishes the line if ( key == K_ENTER || key == K_KP_ENTER ) { // if not in the game explicitly prepend a slash if needed - if ( cls.state != CA_ACTIVE && + if ( clc.state != CA_ACTIVE && g_consoleField.buffer[0] && g_consoleField.buffer[0] != '\\' && g_consoleField.buffer[0] != '/' ) { @@ -625,7 +625,7 @@ void Console_Key (int key) { CL_SaveConsoleHistory( ); - if ( cls.state == CA_DISCONNECTED ) { + if ( clc.state == CA_DISCONNECTED ) { SCR_UpdateScreen (); // force an update, because the command } // may take some time return; @@ -731,7 +731,7 @@ void Message_Key( int key ) { if ( key == K_ENTER || key == K_KP_ENTER ) { - if ( chatField.buffer[0] && cls.state == CA_ACTIVE ) { + if ( chatField.buffer[0] && clc.state == CA_ACTIVE ) { if (chat_playerNum != -1 ) Com_sprintf( buffer, sizeof( buffer ), "tell %i \"%s\"\n", chat_playerNum, chatField.buffer ); @@ -1196,7 +1196,7 @@ void CL_KeyDownEvent( int key, unsigned time ) // keys can still be used for bound actions if ( ( key < 128 || key == K_MOUSE1 ) && - ( clc.demoplaying || cls.state == CA_CINEMATIC ) && Key_GetCatcher( ) == 0 ) { + ( clc.demoplaying || clc.state == CA_CINEMATIC ) && Key_GetCatcher( ) == 0 ) { if (Cvar_VariableValue ("com_cameraMode") == 0) { Cvar_Set ("nextdemo",""); @@ -1220,10 +1220,10 @@ void CL_KeyDownEvent( int key, unsigned time ) } if ( !( Key_GetCatcher( ) & KEYCATCH_UI ) ) { - if ( cls.state == CA_ACTIVE && !clc.demoplaying ) { + if ( clc.state == CA_ACTIVE && !clc.demoplaying ) { VM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_INGAME ); } - else if ( cls.state != CA_DISCONNECTED ) { + else if ( clc.state != CA_DISCONNECTED ) { CL_Disconnect_f(); S_StopAllSounds(); VM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_MAIN ); @@ -1248,7 +1248,7 @@ void CL_KeyDownEvent( int key, unsigned time ) } } else if ( Key_GetCatcher( ) & KEYCATCH_MESSAGE ) { Message_Key( key ); - } else if ( cls.state == CA_DISCONNECTED ) { + } else if ( clc.state == CA_DISCONNECTED ) { Console_Key( key ); } else { // send the bound action @@ -1269,7 +1269,7 @@ void CL_KeyUpEvent( int key, unsigned time ) keys[key].repeats = 0; keys[key].down = qfalse; if (key != K_SCROLLOCK && key != K_KP_NUMLOCK && key != K_CAPSLOCK) - anykeydown--; + anykeydown--; if (anykeydown < 0) { anykeydown = 0; @@ -1285,7 +1285,7 @@ void CL_KeyUpEvent( int key, unsigned time ) // console mode and menu mode, to keep the character from continuing // an action started before a mode switch. // - if( cls.state != CA_DISCONNECTED ) + if( clc.state != CA_DISCONNECTED ) CL_ParseBinding( key, qfalse, time ); if ( Key_GetCatcher( ) & KEYCATCH_UI && uivm ) { @@ -1336,7 +1336,7 @@ void CL_CharEvent( int key ) { { Field_CharEvent( &chatField, key ); } - else if ( cls.state == CA_DISCONNECTED ) + else if ( clc.state == CA_DISCONNECTED ) { Field_CharEvent( &g_consoleField, key ); } diff --git a/reaction/code/client/cl_main.c b/reaction/code/client/cl_main.c index a7aae74b..47cbf454 100644 --- a/reaction/code/client/cl_main.c +++ b/reaction/code/client/cl_main.c @@ -231,7 +231,7 @@ void CL_Voip_f( void ) const char *cmd = Cmd_Argv(1); const char *reason = NULL; - if (cls.state != CA_ACTIVE) + if (clc.state != CA_ACTIVE) reason = "Not connected to a server"; else if (!clc.speexInitialized) reason = "Speex not initialized"; @@ -329,7 +329,7 @@ void CL_CaptureVoip(void) if (cl_voipSend->modified) { qboolean dontCapture = qfalse; - if (cls.state != CA_ACTIVE) + if (clc.state != CA_ACTIVE) dontCapture = qtrue; // not connected to a server. else if (!cl_connectedToVoipServer) dontCapture = qtrue; // server doesn't support VoIP. @@ -623,7 +623,7 @@ void CL_Record_f( void ) { return; } - if ( cls.state != CA_ACTIVE ) { + if ( clc.state != CA_ACTIVE ) { Com_Printf ("You must be in a level to record.\n"); return; } @@ -932,7 +932,7 @@ static void CL_CompleteDemoName( char *args, int argNum ) { char demoExt[ 16 ]; - Com_sprintf( demoExt, sizeof( demoExt ), ".dm_%d", PROTOCOL_VERSION ); + Com_sprintf(demoExt, sizeof(demoExt), ".%s%d", DEMOEXT, com_protocol->integer); Field_CompleteFilename( "demos", demoExt, qtrue, qtrue ); } } @@ -966,7 +966,7 @@ void CL_PlayDemo_f( void ) { CL_Disconnect( qtrue ); // check for an extension .DEMOEXT_?? (?? is protocol) - ext_test = Q_strrchr(arg, '.'); + ext_test = strrchr(arg, '.'); if(ext_test && !Q_stricmpn(ext_test + 1, DEMOEXT, ARRAY_LEN(DEMOEXT) - 1)) { @@ -1009,12 +1009,12 @@ void CL_PlayDemo_f( void ) { Con_Close(); - cls.state = CA_CONNECTED; + clc.state = CA_CONNECTED; clc.demoplaying = qtrue; - Q_strncpyz( cls.servername, Cmd_Argv(1), sizeof( cls.servername ) ); + Q_strncpyz( clc.servername, Cmd_Argv(1), sizeof( clc.servername ) ); // read demo messages until connected - while ( cls.state >= CA_CONNECTED && cls.state < CA_PRIMED ) { + while ( clc.state >= CA_CONNECTED && clc.state < CA_PRIMED ) { CL_ReadDemoMessage(); } // don't get the first snapshot this frame, to prevent the long @@ -1022,6 +1022,7 @@ void CL_PlayDemo_f( void ) { clc.firstDemoFrameSkipped = qfalse; } + /* ==================== CL_StartDemoLoop @@ -1067,7 +1068,13 @@ void CL_NextDemo( void ) { CL_ShutdownAll ===================== */ -void CL_ShutdownAll(void) { +void CL_ShutdownAll(qboolean shutdownRef) +{ + if(CL_VideoRecording()) + CL_CloseAVI(); + + if(clc.demorecording) + CL_StopRecord_f(); #ifdef USE_CURL CL_cURL_Shutdown(); @@ -1080,9 +1087,10 @@ void CL_ShutdownAll(void) { CL_ShutdownUI(); // shutdown the renderer - if ( re.Shutdown ) { - re.Shutdown( qfalse ); // don't destroy window or context - } + if(shutdownRef) + CL_ShutdownRef(); + else if(re.Shutdown) + re.Shutdown(qfalse); // don't destroy window or context cls.uiStarted = qfalse; cls.cgameStarted = qfalse; @@ -1092,17 +1100,15 @@ void CL_ShutdownAll(void) { /* ================= -CL_FlushMemory +CL_ClearMemory -Called by CL_MapLoading, CL_Connect_f, CL_PlayDemo_f, and CL_ParseGamestate the only -ways a client gets into a game -Also called by Com_Error +Called by Com_GameRestart ================= */ -void CL_FlushMemory( void ) { - +void CL_ClearMemory(qboolean shutdownRef) +{ // shutdown all the client stuff - CL_ShutdownAll(); + CL_ShutdownAll(shutdownRef); // if not running a server clear the whole hunk if ( !com_sv_running->integer ) { @@ -1115,8 +1121,21 @@ void CL_FlushMemory( void ) { // clear all the client data on the hunk Hunk_ClearToMark(); } +} - CL_StartHunkUsers( qfalse ); +/* +================= +CL_FlushMemory + +Called by CL_MapLoading, CL_Connect_f, CL_PlayDemo_f, and CL_ParseGamestate the only +ways a client gets into a game +Also called by Com_Error +================= +*/ +void CL_FlushMemory(void) +{ + CL_ClearMemory(qfalse); + CL_StartHunkUsers(qfalse); } /* @@ -1130,7 +1149,7 @@ memory on the hunk from cgame, ui, and renderer */ void CL_MapLoading( void ) { if ( com_dedicated->integer ) { - cls.state = CA_DISCONNECTED; + clc.state = CA_DISCONNECTED; Key_SetCatcher( KEYCATCH_CONSOLE ); return; } @@ -1143,8 +1162,8 @@ void CL_MapLoading( void ) { Key_SetCatcher( 0 ); // if we are already connected to the local host, stay connected - if ( cls.state >= CA_CONNECTED && !Q_stricmp( cls.servername, "localhost" ) ) { - cls.state = CA_CONNECTED; // so the connect screen is drawn + if ( clc.state >= CA_CONNECTED && !Q_stricmp( clc.servername, "localhost" ) ) { + clc.state = CA_CONNECTED; // so the connect screen is drawn Com_Memset( cls.updateInfoString, 0, sizeof( cls.updateInfoString ) ); Com_Memset( clc.serverMessage, 0, sizeof( clc.serverMessage ) ); Com_Memset( &cl.gameState, 0, sizeof( cl.gameState ) ); @@ -1154,12 +1173,12 @@ void CL_MapLoading( void ) { // clear nextmap so the cinematic shutdown doesn't execute it Cvar_Set( "nextmap", "" ); CL_Disconnect( qtrue ); - Q_strncpyz( cls.servername, "localhost", sizeof(cls.servername) ); - cls.state = CA_CHALLENGING; // so the connect screen is drawn + Q_strncpyz( clc.servername, "localhost", sizeof(clc.servername) ); + clc.state = CA_CHALLENGING; // so the connect screen is drawn Key_SetCatcher( 0 ); SCR_UpdateScreen(); clc.connectTime = -RETRANSMIT_TIMEOUT; - NET_StringToAdr( cls.servername, &clc.serverAddress, NA_UNSPEC); + NET_StringToAdr( clc.servername, &clc.serverAddress, NA_UNSPEC); // we don't need a challenge on the localhost CL_CheckForResend(); @@ -1202,6 +1221,16 @@ static void CL_UpdateGUID( const char *prefix, int prefix_len ) prefix, prefix_len ) ); } +static void CL_OldGame(void) +{ + if(cls.oldGameSet) + { + // change back to previous fs_game + cls.oldGameSet = qfalse; + Cvar_Set("fs_game", cls.oldGame); + Com_GameRestart(0, qtrue); + } +} /* ===================== @@ -1276,7 +1305,7 @@ void CL_Disconnect( qboolean showMainMenu ) { // send a disconnect message to the server // send it a few times in case one is dropped - if ( cls.state >= CA_CONNECTED ) { + if ( clc.state >= CA_CONNECTED ) { CL_AddReliableCommand("disconnect", qtrue); CL_WritePacket(); CL_WritePacket(); @@ -1291,7 +1320,7 @@ void CL_Disconnect( qboolean showMainMenu ) { // wipe the client connection Com_Memset( &clc, 0, sizeof( clc ) ); - cls.state = CA_DISCONNECTED; + clc.state = CA_DISCONNECTED; // allow cheats locally Cvar_Set( "sv_cheats", "1" ); @@ -1310,7 +1339,9 @@ void CL_Disconnect( qboolean showMainMenu ) { SCR_UpdateScreen( ); CL_CloseAVI( ); } + CL_UpdateGUID( NULL, 0 ); + CL_OldGame(); } @@ -1333,7 +1364,7 @@ void CL_ForwardCommandToServer( const char *string ) { return; } - if ( clc.demoplaying || cls.state < CA_CONNECTED || cmd[0] == '+' ) { + if ( clc.demoplaying || clc.state < CA_CONNECTED || cmd[0] == '+' ) { Com_Printf ("Unknown command \"%s" S_COLOR_WHITE "\"\n", cmd); return; } @@ -1476,7 +1507,7 @@ CL_ForwardToServer_f ================== */ void CL_ForwardToServer_f( void ) { - if ( cls.state != CA_ACTIVE || clc.demoplaying ) { + if ( clc.state != CA_ACTIVE || clc.demoplaying ) { Com_Printf ("Not connected to a server.\n"); return; } @@ -1495,7 +1526,7 @@ CL_Disconnect_f void CL_Disconnect_f( void ) { SCR_StopCinematic(); Cvar_Set("ui_singlePlayerActive", "0"); - if ( cls.state != CA_DISCONNECTED && cls.state != CA_CINEMATIC ) { + if ( clc.state != CA_DISCONNECTED && clc.state != CA_CINEMATIC ) { Com_Error (ERR_DISCONNECT, "Disconnected from server"); } } @@ -1508,12 +1539,12 @@ CL_Reconnect_f ================ */ void CL_Reconnect_f( void ) { - if ( !strlen( cls.servername ) || !strcmp( cls.servername, "localhost" ) ) { + if ( !strlen( clc.servername ) || !strcmp( clc.servername, "localhost" ) ) { Com_Printf( "Can't reconnect to localhost.\n" ); return; } Cvar_Set("ui_singlePlayerActive", "0"); - Cbuf_AddText( va("connect %s\n", cls.servername ) ); + Cbuf_AddText( va("connect %s\n", clc.servername ) ); } /* @@ -1567,11 +1598,11 @@ void CL_Connect_f( void ) { CL_Disconnect( qtrue ); Con_Close(); - Q_strncpyz( cls.servername, server, sizeof(cls.servername) ); + Q_strncpyz( clc.servername, server, sizeof(clc.servername) ); - if (!NET_StringToAdr(cls.servername, &clc.serverAddress, family) ) { + if (!NET_StringToAdr(clc.servername, &clc.serverAddress, family) ) { Com_Printf ("Bad server address\n"); - cls.state = CA_DISCONNECTED; + clc.state = CA_DISCONNECTED; return; } if (clc.serverAddress.port == 0) { @@ -1580,7 +1611,7 @@ void CL_Connect_f( void ) { serverString = NET_AdrToStringwPort(clc.serverAddress); - Com_Printf( "%s resolved to %s\n", cls.servername, serverString); + Com_Printf( "%s resolved to %s\n", clc.servername, serverString); if( cl_guidServerUniq->integer ) CL_UpdateGUID( serverString, strlen( serverString ) ); @@ -1590,10 +1621,10 @@ void CL_Connect_f( void ) { // if we aren't playing on a lan, we need to authenticate // with the cd key if(NET_IsLocalAddress(clc.serverAddress)) - cls.state = CA_CHALLENGING; + clc.state = CA_CHALLENGING; else { - cls.state = CA_CONNECTING; + clc.state = CA_CONNECTING; // Set a client challenge number that ideally is mirrored back by the server. clc.challenge = ((rand() << 16) ^ rand()) ^ Com_Milliseconds(); @@ -1658,7 +1689,7 @@ void CL_Rcon_f( void ) { // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=543 Q_strcat (message, MAX_RCON_MESSAGE, Cmd_Cmd()+5); - if ( cls.state >= CA_CONNECTED ) { + if ( clc.state >= CA_CONNECTED ) { to = clc.netchan.remoteAddress; } else { if (!strlen(rconAddress->string)) { @@ -1722,49 +1753,55 @@ void CL_Vid_Restart_f( void ) { // don't let them loop during the restart S_StopAllSounds(); - // shutdown the UI - CL_ShutdownUI(); - // shutdown the CGame - CL_ShutdownCGame(); - // shutdown the renderer and clear the renderer interface - CL_ShutdownRef(); - // client is no longer pure untill new checksums are sent - CL_ResetPureClientAtServer(); - // clear pak references - FS_ClearPakReferences( FS_UI_REF | FS_CGAME_REF ); - // reinitialize the filesystem if the game directory or checksum has changed - FS_ConditionalRestart( clc.checksumFeed ); - cls.rendererStarted = qfalse; - cls.uiStarted = qfalse; - cls.cgameStarted = qfalse; - cls.soundRegistered = qfalse; + if(!FS_ConditionalRestart(clc.checksumFeed, qtrue)) + { + // if not running a server clear the whole hunk + if(com_sv_running->integer) + { + // clear all the client data on the hunk + Hunk_ClearToMark(); + } + else + { + // clear the whole hunk + Hunk_Clear(); + } + + // shutdown the UI + CL_ShutdownUI(); + // shutdown the CGame + CL_ShutdownCGame(); + // shutdown the renderer and clear the renderer interface + CL_ShutdownRef(); + // client is no longer pure untill new checksums are sent + CL_ResetPureClientAtServer(); + // clear pak references + FS_ClearPakReferences( FS_UI_REF | FS_CGAME_REF ); + // reinitialize the filesystem if the game directory or checksum has changed - // unpause so the cgame definately gets a snapshot and renders a frame - Cvar_Set( "cl_paused", "0" ); + cls.rendererStarted = qfalse; + cls.uiStarted = qfalse; + cls.cgameStarted = qfalse; + cls.soundRegistered = qfalse; - // if not running a server clear the whole hunk - if ( !com_sv_running->integer ) { - // clear the whole hunk - Hunk_Clear(); - } - else { - // clear all the client data on the hunk - Hunk_ClearToMark(); - } + // unpause so the cgame definately gets a snapshot and renders a frame + Cvar_Set("cl_paused", "0"); - // initialize the renderer interface - CL_InitRef(); + // initialize the renderer interface + CL_InitRef(); - // startup all the client stuff - CL_StartHunkUsers( qfalse ); + // startup all the client stuff + CL_StartHunkUsers(qfalse); - // start the cgame if connected - if ( cls.state > CA_CONNECTED && cls.state != CA_CINEMATIC ) { - cls.cgameStarted = qtrue; - CL_InitCGame(); - // send pure checksums - CL_SendPureChecksums(); + // start the cgame if connected + if(clc.state > CA_CONNECTED && clc.state != CA_CINEMATIC) + { + cls.cgameStarted = qtrue; + CL_InitCGame(); + // send pure checksums + CL_SendPureChecksums(); + } } } @@ -1775,10 +1812,10 @@ CL_Snd_Restart Restart the sound subsystem ================= */ -void CL_Snd_Restart(void) +void CL_Snd_Shutdown(void) { S_Shutdown(); - S_Init(); + cls.soundStarted = qfalse; } /* @@ -1792,7 +1829,8 @@ handles will be invalid */ void CL_Snd_Restart_f(void) { - CL_Snd_Restart(); + CL_Snd_Shutdown(); + // sound will be reinitialized by vid_restart CL_Vid_Restart_f(); } @@ -1824,7 +1862,7 @@ void CL_Configstrings_f( void ) { int i; int ofs; - if ( cls.state != CA_ACTIVE ) { + if ( clc.state != CA_ACTIVE ) { Com_Printf( "Not connected to a server.\n"); return; } @@ -1845,8 +1883,8 @@ CL_Clientinfo_f */ void CL_Clientinfo_f( void ) { Com_Printf( "--------- Client Information ---------\n" ); - Com_Printf( "state: %i\n", cls.state ); - Com_Printf( "Server: %s\n", cls.servername ); + Com_Printf( "state: %i\n", clc.state ); + Com_Printf( "Server: %s\n", clc.servername ); Com_Printf ("User info settings:\n"); Info_Print( Cvar_InfoString( CVAR_USERINFO ) ); Com_Printf( "--------------------------------------\n" ); @@ -1896,14 +1934,14 @@ void CL_DownloadsComplete( void ) { } // let the client game init and load data - cls.state = CA_LOADING; + clc.state = CA_LOADING; // Pump the loop, this may change gamestate! Com_EventLoop(); // if the gamestate was changed by calling Com_EventLoop // then we loaded everything already and we don't want to do it again. - if ( cls.state != CA_LOADING ) { + if ( clc.state != CA_LOADING ) { return; } @@ -2089,7 +2127,7 @@ void CL_InitDownloads(void) { if ( *clc.downloadList ) { // if autodownloading is not enabled on the server - cls.state = CA_CONNECTED; + clc.state = CA_CONNECTED; *clc.downloadTempName = *clc.downloadName = 0; Cvar_Set( "cl_downloadName", "" ); @@ -2121,7 +2159,7 @@ void CL_CheckForResend( void ) { } // resend if we haven't gotten a reply yet - if ( cls.state != CA_CONNECTING && cls.state != CA_CHALLENGING ) { + if ( clc.state != CA_CONNECTING && clc.state != CA_CHALLENGING ) { return; } @@ -2133,7 +2171,7 @@ void CL_CheckForResend( void ) { clc.connectPacketCount++; - switch ( cls.state ) { + switch ( clc.state ) { case CA_CONNECTING: // requesting a challenge .. IPv6 users always get in as authorize server supports no ipv6. #ifndef STANDALONE @@ -2175,7 +2213,7 @@ void CL_CheckForResend( void ) { break; default: - Com_Error( ERR_FATAL, "CL_CheckForResend: bad cls.state" ); + Com_Error( ERR_FATAL, "CL_CheckForResend: bad clc.state" ); } } @@ -2190,7 +2228,7 @@ to the client so it doesn't have to wait for the full timeout period. =================== */ void CL_DisconnectPacket( netadr_t from ) { - if ( cls.state < CA_AUTHORIZING ) { + if ( clc.state < CA_AUTHORIZING ) { return; } @@ -2408,7 +2446,7 @@ void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) { // challenge from the server we are connecting to if (!Q_stricmp(c, "challengeResponse")) { - if (cls.state != CA_CONNECTING) + if (clc.state != CA_CONNECTING) { Com_DPrintf("Unwanted challenge response received. Ignored.\n"); return; @@ -2431,7 +2469,7 @@ void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) { // start sending challenge response instead of challenge request packets clc.challenge = atoi(Cmd_Argv(1)); - cls.state = CA_CHALLENGING; + clc.state = CA_CHALLENGING; clc.connectPacketCount = 0; clc.connectTime = -99999; @@ -2444,11 +2482,11 @@ void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) { // server connection if ( !Q_stricmp(c, "connectResponse") ) { - if ( cls.state >= CA_CONNECTED ) { + if ( clc.state >= CA_CONNECTED ) { Com_Printf ("Dup connect received. Ignored.\n"); return; } - if ( cls.state != CA_CHALLENGING ) { + if ( clc.state != CA_CHALLENGING ) { Com_Printf ("connectResponse packet while not connecting. Ignored.\n"); return; } @@ -2457,7 +2495,7 @@ void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) { return; } Netchan_Setup (NS_CLIENT, &clc.netchan, from, Cvar_VariableValue( "net_qport" ) ); - cls.state = CA_CONNECTED; + clc.state = CA_CONNECTED; clc.lastPacketSentTime = -9999; // send first packet immediately return; } @@ -2540,7 +2578,7 @@ void CL_PacketEvent( netadr_t from, msg_t *msg ) { return; } - if ( cls.state < CA_CONNECTED ) { + if ( clc.state < CA_CONNECTED ) { return; // can't be a valid sequenced packet } @@ -2594,7 +2632,7 @@ void CL_CheckTimeout( void ) { // check timeout // if ( ( !CL_CheckPaused() || !sv_paused->integer ) - && cls.state >= CA_CONNECTED && cls.state != CA_CINEMATIC + && clc.state >= CA_CONNECTED && clc.state != CA_CINEMATIC && cls.realtime - clc.lastPacketTime > cl_timeout->value*1000) { if (++cl.timeoutcount > 5) { // timeoutcount saves debugger Com_Printf ("\nServer connection timed out.\n"); @@ -2633,7 +2671,7 @@ CL_CheckUserinfo */ void CL_CheckUserinfo( void ) { // don't add reliable commands when not yet connected - if(cls.state < CA_CHALLENGING) + if(clc.state < CA_CONNECTED) return; // don't overflow the reliable command buffer when paused @@ -2664,7 +2702,7 @@ void CL_Frame ( int msec ) { if(clc.downloadCURLM) { CL_cURL_PerformDownload(); // we can't process frames normally when in disconnected - // download mode since the ui vm expects cls.state to be + // download mode since the ui vm expects clc.state to be // CA_CONNECTED if(clc.cURLDisconnected) { cls.realFrametime = msec; @@ -2683,7 +2721,7 @@ void CL_Frame ( int msec ) { // bring up the cd error dialog if needed cls.cddialog = qfalse; VM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_NEED_CD ); - } else if ( cls.state == CA_DISCONNECTED && !( Key_GetCatcher( ) & KEYCATCH_UI ) + } else if ( clc.state == CA_DISCONNECTED && !( Key_GetCatcher( ) & KEYCATCH_UI ) && !com_sv_running->integer && uivm ) { // if disconnected, bring up the menu S_StopAllSounds(); @@ -2693,7 +2731,7 @@ void CL_Frame ( int msec ) { // if recording an avi, lock to a fixed fps if ( CL_VideoRecording( ) && cl_aviFrameRate->integer && msec) { // save the current screen - if ( cls.state == CA_ACTIVE || cl_forceavidemo->integer) { + if ( clc.state == CA_ACTIVE || cl_forceavidemo->integer) { CL_TakeVideoFrame( ); // fixed time for next frame' @@ -2705,7 +2743,7 @@ void CL_Frame ( int msec ) { } if( cl_autoRecordDemo->integer ) { - if( cls.state == CA_ACTIVE && !clc.demorecording && !clc.demoplaying ) { + if( clc.state == CA_ACTIVE && !clc.demorecording && !clc.demoplaying ) { // If not recording a demo, and we should be, start one qtime_t now; char *nowString; @@ -2722,7 +2760,7 @@ void CL_Frame ( int msec ) { now.tm_min, now.tm_sec ); - Q_strncpyz( serverName, cls.servername, MAX_OSPATH ); + Q_strncpyz( serverName, clc.servername, MAX_OSPATH ); // Replace the ":" in the address as it is not a valid // file name character p = strstr( serverName, ":" ); @@ -2736,7 +2774,7 @@ void CL_Frame ( int msec ) { Cbuf_ExecuteText( EXEC_NOW, va( "record %s-%s-%s", nowString, serverName, mapName ) ); } - else if( cls.state != CA_ACTIVE && clc.demorecording ) { + else if( clc.state != CA_ACTIVE && clc.demorecording ) { // Recording, but not CA_ACTIVE, so stop recording CL_StopRecord_f( ); } @@ -3117,9 +3155,12 @@ void CL_Init( void ) { Con_Init (); - CL_ClearState (); - - cls.state = CA_DISCONNECTED; // no longer CA_UNINITIALIZED + if(!com_fullyInitialized) + { + CL_ClearState(); + clc.state = CA_DISCONNECTED; // no longer CA_UNINITIALIZED + cls.oldGameSet = qfalse; + } cls.realtime = 0; @@ -3332,7 +3373,8 @@ CL_Shutdown =============== */ -void CL_Shutdown( char *finalmsg ) { +void CL_Shutdown(char *finalmsg, qboolean disconnect) +{ static qboolean recursive = qfalse; // check whether the client is running at all. @@ -3347,16 +3389,15 @@ void CL_Shutdown( char *finalmsg ) { } recursive = qtrue; - CL_Disconnect( qtrue ); - - S_Shutdown(); - CL_ShutdownRef(); + if(disconnect) + CL_Disconnect(qtrue); - CL_ShutdownUI(); + CL_ClearMemory(qtrue); + CL_Snd_Shutdown(); Cmd_RemoveCommand ("cmd"); Cmd_RemoveCommand ("configstrings"); - Cmd_RemoveCommand ("userinfo"); + Cmd_RemoveCommand ("clientinfo"); Cmd_RemoveCommand ("snd_restart"); Cmd_RemoveCommand ("vid_restart"); Cmd_RemoveCommand ("disconnect"); @@ -3365,15 +3406,22 @@ void CL_Shutdown( char *finalmsg ) { Cmd_RemoveCommand ("cinematic"); Cmd_RemoveCommand ("stoprecord"); Cmd_RemoveCommand ("connect"); + Cmd_RemoveCommand ("reconnect"); Cmd_RemoveCommand ("localservers"); Cmd_RemoveCommand ("globalservers"); Cmd_RemoveCommand ("rcon"); Cmd_RemoveCommand ("ping"); Cmd_RemoveCommand ("serverstatus"); Cmd_RemoveCommand ("showip"); + Cmd_RemoveCommand ("fs_openedList"); + Cmd_RemoveCommand ("fs_referencedList"); Cmd_RemoveCommand ("model"); Cmd_RemoveCommand ("video"); Cmd_RemoveCommand ("stopvideo"); + Cmd_RemoveCommand ("minimize"); + + CL_ShutdownInput(); + Con_Shutdown(); Cvar_Set( "cl_running", "0" ); @@ -3399,6 +3447,8 @@ static void CL_SetServerInfo(serverInfo_t *server, const char *info, int ping) { server->minPing = atoi(Info_ValueForKey(info, "minping")); server->maxPing = atoi(Info_ValueForKey(info, "maxping")); server->punkbuster = atoi(Info_ValueForKey(info, "punkbuster")); + server->g_humanplayers = atoi(Info_ValueForKey(info, "g_humanplayers")); + server->g_needpass = atoi(Info_ValueForKey(info, "g_needpass")); } server->ping = ping; } @@ -3517,6 +3567,8 @@ void CL_ServerInfoPacket( netadr_t from, msg_t *msg ) { cls.localServers[i].gameType = 0; cls.localServers[i].netType = from.type; cls.localServers[i].punkbuster = 0; + cls.localServers[i].g_humanplayers = 0; + cls.localServers[i].g_needpass = 0; Q_strncpyz( info, MSG_ReadString( msg ), MAX_INFO_STRING ); if (strlen(info)) { @@ -3812,17 +3864,14 @@ void CL_GlobalServers_f( void ) { if(v4enabled) { - Com_sprintf(command, sizeof(command), "getserversExt %s %s ipv6", + Com_sprintf(command, sizeof(command), "getserversExt %s %s", cl_gamename->string, Cmd_Argv(2)); } else { - Com_sprintf(command, sizeof(command), "getserversExt %s %s", + Com_sprintf(command, sizeof(command), "getserversExt %s %s ipv6", cl_gamename->string, Cmd_Argv(2)); } - - // TODO: test if we only have an IPv6 connection. If it's the case, - // request IPv6 servers only by appending " ipv6" to the command } else Com_sprintf(command, sizeof(command), "getservers %s", Cmd_Argv(2)); @@ -4162,7 +4211,7 @@ void CL_ServerStatus_f(void) { if ( argc != 2 && argc != 3 ) { - if (cls.state != CA_ACTIVE || clc.demoplaying) + if (clc.state != CA_ACTIVE || clc.demoplaying) { Com_Printf ("Not connected to a server.\n"); Com_Printf( "usage: serverstatus [-4|-6] server\n"); diff --git a/reaction/code/client/cl_parse.c b/reaction/code/client/cl_parse.c index 646fa818..b75b2d3a 100644 --- a/reaction/code/client/cl_parse.c +++ b/reaction/code/client/cl_parse.c @@ -265,7 +265,7 @@ void CL_ParseSnapshot( msg_t *msg ) { if(len > sizeof(newSnap.areamask)) { - Com_Error (ERR_DROP,"CL_ParseSnapshot: Invalid size %d for areamask.", len); + Com_Error (ERR_DROP,"CL_ParseSnapshot: Invalid size %d for areamask", len); return; } @@ -463,6 +463,7 @@ void CL_ParseGamestate( msg_t *msg ) { entityState_t nullstate; int cmd; char *s; + char oldGame[MAX_QPATH]; Con_Close(); @@ -518,6 +519,9 @@ void CL_ParseGamestate( msg_t *msg ) { // read the checksum feed clc.checksumFeed = MSG_ReadLong( msg ); + // save old gamedir + Cvar_VariableStringBuffer("fs_game", oldGame, sizeof(oldGame)); + // parse useful values out of CS_SERVERINFO CL_ParseServerInfo(); @@ -529,7 +533,11 @@ void CL_ParseGamestate( msg_t *msg ) { CL_StopRecord_f(); // reinitialize the filesystem if the game directory has changed - FS_ConditionalRestart( clc.checksumFeed ); + if(FS_ConditionalRestart(clc.checksumFeed, qfalse) && !cls.oldGameSet) + { + cls.oldGameSet = qtrue; + Q_strncpyz(cls.oldGame, oldGame, sizeof(cls.oldGame)); + } // This used to call CL_StartHunkUsers, but now we enter the download state before loading the // cgame @@ -580,7 +588,7 @@ void CL_ParseDownload ( msg_t *msg ) { size = MSG_ReadShort ( msg ); if (size < 0 || size > sizeof(data)) { - Com_Error(ERR_DROP, "CL_ParseDownload: Invalid size %d for download chunk.", size); + Com_Error(ERR_DROP, "CL_ParseDownload: Invalid size %d for download chunk", size); return; } @@ -885,7 +893,7 @@ void CL_ParseServerMessage( msg_t *msg ) { // other commands switch ( cmd ) { default: - Com_Error (ERR_DROP,"CL_ParseServerMessage: Illegible server message\n"); + Com_Error (ERR_DROP,"CL_ParseServerMessage: Illegible server message"); break; case svc_nop: break; diff --git a/reaction/code/client/cl_scrn.c b/reaction/code/client/cl_scrn.c index ec545bc0..40d64638 100644 --- a/reaction/code/client/cl_scrn.c +++ b/reaction/code/client/cl_scrn.c @@ -360,7 +360,7 @@ void SCR_DrawVoipMeter( void ) { return; // player doesn't want to show meter at all. else if (!cl_voipSend->integer) return; // not recording at the moment. - else if (cls.state != CA_ACTIVE) + else if (clc.state != CA_ACTIVE) return; // not connected to a server. else if (!cl_connectedToVoipServer) return; // server doesn't support VoIP. @@ -480,11 +480,15 @@ This will be called twice if rendering in stereo mode ================== */ void SCR_DrawScreenField( stereoFrame_t stereoFrame ) { + qboolean uiFullscreen; + re.BeginFrame( stereoFrame ); + uiFullscreen = (uivm && VM_Call( uivm, UI_IS_FULLSCREEN )); + // wide aspect ratio screens need to have the sides cleared // unless they are displaying game renderings - if ( cls.state != CA_ACTIVE && cls.state != CA_CINEMATIC ) { + if ( uiFullscreen || (clc.state != CA_ACTIVE && clc.state != CA_CINEMATIC) ) { if ( cls.glconfig.vidWidth * 480 > cls.glconfig.vidHeight * 640 ) { re.SetColor( g_color_table[0] ); re.DrawStretchPic( 0, 0, cls.glconfig.vidWidth, cls.glconfig.vidHeight, 0, 0, 0, 0, cls.whiteShader ); @@ -494,10 +498,10 @@ void SCR_DrawScreenField( stereoFrame_t stereoFrame ) { // if the menu is going to cover the entire screen, we // don't need to render anything under it - if ( uivm && !VM_Call( uivm, UI_IS_FULLSCREEN )) { - switch( cls.state ) { + if ( uivm && !uiFullscreen ) { + switch( clc.state ) { default: - Com_Error( ERR_FATAL, "SCR_DrawScreenField: bad cls.state" ); + Com_Error( ERR_FATAL, "SCR_DrawScreenField: bad clc.state" ); break; case CA_CINEMATIC: SCR_DrawCinematic(); diff --git a/reaction/code/client/cl_ui.c b/reaction/code/client/cl_ui.c index 13bc6eaf..9ad9d2f5 100644 --- a/reaction/code/client/cl_ui.c +++ b/reaction/code/client/cl_ui.c @@ -35,8 +35,8 @@ GetClientState */ static void GetClientState( uiClientState_t *state ) { state->connectPacketCount = clc.connectPacketCount; - state->connState = cls.state; - Q_strncpyz( state->servername, cls.servername, sizeof( state->servername ) ); + state->connState = clc.state; + Q_strncpyz( state->servername, clc.servername, sizeof( state->servername ) ); Q_strncpyz( state->updateInfoString, cls.updateInfoString, sizeof( state->updateInfoString ) ); Q_strncpyz( state->messageString, clc.serverMessage, sizeof( state->messageString ) ); state->clientNum = cl.snap.ps.clientNum; @@ -298,6 +298,8 @@ static void LAN_GetServerInfo( int source, int n, char *buf, int buflen ) { Info_SetValueForKey( info, "nettype", va("%i",server->netType)); Info_SetValueForKey( info, "addr", NET_AdrToStringwPort(server->adr)); Info_SetValueForKey( info, "punkbuster", va("%i", server->punkbuster)); + Info_SetValueForKey( info, "g_needpass", va("%i", server->g_needpass)); + Info_SetValueForKey( info, "g_humanplayers", va("%i", server->g_humanplayers)); Q_strncpyz(buf, info, buflen); } else { if (buf) { @@ -1114,7 +1116,7 @@ void CL_InitUI( void ) { if (v == UI_OLD_API_VERSION) { // Com_Printf(S_COLOR_YELLOW "WARNING: loading old Quake III Arena User Interface version %d\n", v ); // init for this gamestate - VM_Call( uivm, UI_INIT, (cls.state >= CA_AUTHORIZING && cls.state < CA_ACTIVE)); + VM_Call( uivm, UI_INIT, (clc.state >= CA_AUTHORIZING && clc.state < CA_ACTIVE)); } else if (v != UI_API_VERSION) { Com_Error( ERR_DROP, "User Interface is version %d, expected %d", v, UI_API_VERSION ); @@ -1122,12 +1124,8 @@ void CL_InitUI( void ) { } else { // init for this gamestate - VM_Call( uivm, UI_INIT, (cls.state >= CA_AUTHORIZING && cls.state < CA_ACTIVE) ); + VM_Call( uivm, UI_INIT, (clc.state >= CA_AUTHORIZING && clc.state < CA_ACTIVE) ); } - - // reset any CVAR_CHEAT cvars registered by ui - if ( !clc.demoplaying && !cl_connectedToCheatServer ) - Cvar_SetCheatState(); } #ifndef STANDALONE diff --git a/reaction/code/client/client.h b/reaction/code/client/client.h index 3758e6fa..533696fd 100644 --- a/reaction/code/client/client.h +++ b/reaction/code/client/client.h @@ -162,10 +162,13 @@ demo through a file. typedef struct { + connstate_t state; // connection status + int clientNum; int lastPacketSentTime; // for retransmits during connection int lastPacketTime; // for timeouts + char servername[MAX_OSPATH]; // name of server from original connect (used by reconnect) netadr_t serverAddress; int connectTime; // for connection retransmits int connectPacketCount; // for display on connection dialog @@ -296,15 +299,13 @@ typedef struct { int ping; qboolean visible; int punkbuster; + int g_humanplayers; + int g_needpass; } serverInfo_t; typedef struct { - connstate_t state; // connection status - qboolean cddialog; // bring up the cd needed dialog next frame - char servername[MAX_OSPATH]; // name of server from original connect (used by reconnect) - // when the server clears the hunk, all of these must be restarted qboolean rendererStarted; qboolean soundStarted; @@ -331,6 +332,9 @@ typedef struct { serverInfo_t favoriteServers[MAX_OTHER_SERVERS]; int pingUpdateSource; // source currently pinging or updating + + char oldGame[MAX_QPATH]; + qboolean oldGameSet; // update server info netadr_t updateServer; @@ -440,8 +444,6 @@ extern cvar_t *cl_voip; // void CL_Init (void); -void CL_FlushMemory(void); -void CL_ShutdownAll(void); void CL_AddReliableCommand(const char *cmd, qboolean isDisconnectCmd); void CL_StartHunkUsers( qboolean rendererOnly ); @@ -489,7 +491,8 @@ extern kbutton_t in_speed; extern kbutton_t in_voiprecord; #endif -void CL_InitInput (void); +void CL_InitInput(void); +void CL_ShutdownInput(void); void CL_SendCmd (void); void CL_ClearState (void); void CL_ReadPackets (void); @@ -533,7 +536,8 @@ qboolean CL_UpdateVisiblePings_f( int source ); void Con_DrawCharacter (int cx, int line, int num); void Con_CheckResize (void); -void Con_Init (void); +void Con_Init(void); +void Con_Shutdown(void); void Con_Clear_f (void); void Con_ToggleConsole_f (void); void Con_DrawNotify (void); diff --git a/reaction/code/client/snd_codec.c b/reaction/code/client/snd_codec.c index 0483e8df..ddddb71a 100644 --- a/reaction/code/client/snd_codec.c +++ b/reaction/code/client/snd_codec.c @@ -28,71 +28,90 @@ static snd_codec_t *codecs; /* ================= -S_FileExtension +S_CodecGetSound + +Opens/loads a sound, tries codec based on the sound's file extension +then tries all supported codecs. ================= */ -static char *S_FileExtension(const char *fni) +static void *S_CodecGetSound(const char *filename, snd_info_t *info) { - // we should search from the ending to the last '/' + snd_codec_t *codec; + snd_codec_t *orgCodec = NULL; + qboolean orgNameFailed = qfalse; + char localName[ MAX_QPATH ]; + const char *ext; + char altName[ MAX_QPATH ]; + void *rtn = NULL; - char *fn = (char *) fni + strlen(fni) - 1; - char *eptr = NULL; + Q_strncpyz(localName, filename, MAX_QPATH); - while(*fn != '/' && fn != fni) + ext = COM_GetExtension(localName); + + if( *ext ) { - if(*fn == '.') + // Look for the correct loader and use it + for( codec = codecs; codec; codec = codec->next ) { - eptr = fn; - break; - } - fn--; - } - - return eptr; -} - -/* -================= -S_FindCodecForFile - -Select an appropriate codec for a file based on its extension -================= -*/ -static snd_codec_t *S_FindCodecForFile(const char *filename) -{ - char *ext = S_FileExtension(filename); - snd_codec_t *codec = codecs; - - if(!ext) - { - // No extension - auto-detect - while(codec) - { - char fn[MAX_QPATH]; - - // there is no extension so we do not need to subtract 4 chars - Q_strncpyz(fn, filename, MAX_QPATH); - COM_DefaultExtension(fn, MAX_QPATH, codec->ext); - - // Check it exists - if(FS_ReadFile(fn, NULL) != -1) - return codec; - - // Nope. Next! - codec = codec->next; + if( !Q_stricmp( ext, codec->ext ) ) + { + // Load + if( info ) + rtn = codec->load(localName, info); + else + rtn = codec->open(localName); + break; + } } - // Nothin' - return NULL; + // A loader was found + if( codec ) + { + if( !rtn ) + { + // Loader failed, most likely because the file isn't there; + // try again without the extension + orgNameFailed = qtrue; + orgCodec = codec; + COM_StripExtension( filename, localName, MAX_QPATH ); + } + else + { + // Something loaded + return rtn; + } + } } - while(codec) + // Try and find a suitable match using all + // the sound codecs supported + for( codec = codecs; codec; codec = codec->next ) { - if(!Q_stricmp(ext, codec->ext)) - return codec; - codec = codec->next; + if( codec == orgCodec ) + continue; + + Com_sprintf( altName, sizeof (altName), "%s.%s", localName, codec->ext ); + + // Load + if( info ) + rtn = codec->load(altName, info); + else + rtn = codec->open(altName); + + if( rtn ) + { + if( orgNameFailed ) + { + Com_DPrintf(S_COLOR_YELLOW "WARNING: %s not present, using %s instead\n", + filename, altName ); + } + + return rtn; + } } + Com_Printf(S_COLOR_YELLOW "WARNING: Failed to %s sound %s!\n", info ? "load" : "open", filename); + return NULL; } @@ -104,10 +123,13 @@ S_CodecInit void S_CodecInit() { codecs = NULL; - S_CodecRegister(&wav_codec); + #ifdef USE_CODEC_VORBIS S_CodecRegister(&ogg_codec); #endif + +// Register wav codec last so that it is always tried first when a file extension was not found + S_CodecRegister(&wav_codec); } /* @@ -138,20 +160,7 @@ S_CodecLoad */ void *S_CodecLoad(const char *filename, snd_info_t *info) { - snd_codec_t *codec; - char fn[MAX_QPATH]; - - codec = S_FindCodecForFile(filename); - if(!codec) - { - Com_Printf("Unknown extension for %s\n", filename); - return NULL; - } - - strncpy(fn, filename, sizeof(fn)); - COM_DefaultExtension(fn, sizeof(fn), codec->ext); - - return codec->load(fn, info); + return S_CodecGetSound(filename, info); } /* @@ -161,20 +170,7 @@ S_CodecOpenStream */ snd_stream_t *S_CodecOpenStream(const char *filename) { - snd_codec_t *codec; - char fn[MAX_QPATH]; - - codec = S_FindCodecForFile(filename); - if(!codec) - { - Com_Printf("Unknown extension for %s\n", filename); - return NULL; - } - - strncpy(fn, filename, sizeof(fn)); - COM_DefaultExtension(fn, sizeof(fn), codec->ext); - - return codec->open(fn); + return S_CodecGetSound(filename, NULL); } void S_CodecCloseStream(snd_stream_t *stream) @@ -205,7 +201,7 @@ snd_stream_t *S_CodecUtilOpen(const char *filename, snd_codec_t *codec) length = FS_FOpenFileRead(filename, &hnd, qtrue); if(!hnd) { - Com_Printf("Can't read sound file %s\n", filename); + Com_DPrintf("Can't read sound file %s\n", filename); return NULL; } diff --git a/reaction/code/client/snd_codec_ogg.c b/reaction/code/client/snd_codec_ogg.c index 7459ba08..c424649f 100644 --- a/reaction/code/client/snd_codec_ogg.c +++ b/reaction/code/client/snd_codec_ogg.c @@ -41,7 +41,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // Q3 OGG codec snd_codec_t ogg_codec = { - ".ogg", + "ogg", S_OGG_CodecLoad, S_OGG_CodecOpenStream, S_OGG_CodecReadStream, @@ -450,7 +450,7 @@ void *S_OGG_CodecLoad(const char *filename, snd_info_t *info) // allocate a buffer // this buffer must be free-ed by the caller of this function - buffer = Z_Malloc(info->size); + buffer = Hunk_AllocateTempMemory(info->size); if(!buffer) { S_OGG_CodecCloseStream(stream); @@ -464,7 +464,7 @@ void *S_OGG_CodecLoad(const char *filename, snd_info_t *info) // we don't even have read a single byte if(bytesRead <= 0) { - Z_Free(buffer); + Hunk_FreeTempMemory(buffer); S_OGG_CodecCloseStream(stream); return NULL; diff --git a/reaction/code/client/snd_codec_wav.c b/reaction/code/client/snd_codec_wav.c index c0b2e2e2..e5a08ae9 100644 --- a/reaction/code/client/snd_codec_wav.c +++ b/reaction/code/client/snd_codec_wav.c @@ -183,7 +183,7 @@ static qboolean S_ReadRIFFHeader(fileHandle_t file, snd_info_t *info) // WAV codec snd_codec_t wav_codec = { - ".wav", + "wav", S_WAV_CodecLoad, S_WAV_CodecOpenStream, S_WAV_CodecReadStream, @@ -205,8 +205,6 @@ void *S_WAV_CodecLoad(const char *filename, snd_info_t *info) FS_FOpenFileRead(filename, &file, qtrue); if(!file) { - Com_Printf( S_COLOR_RED "ERROR: Could not open \"%s\"\n", - filename); return NULL; } @@ -220,7 +218,7 @@ void *S_WAV_CodecLoad(const char *filename, snd_info_t *info) } // Allocate some memory - buffer = Z_Malloc(info->size); + buffer = Hunk_AllocateTempMemory(info->size); if(!buffer) { FS_FCloseFile(file); diff --git a/reaction/code/client/snd_dma.c b/reaction/code/client/snd_dma.c index 428d1d4d..45cef4c6 100644 --- a/reaction/code/client/snd_dma.c +++ b/reaction/code/client/snd_dma.c @@ -259,10 +259,10 @@ static sfx_t *S_FindName( const char *name ) { sfx_t *sfx; if (!name) { - Com_Error (ERR_FATAL, "S_FindName: NULL\n"); + Com_Error (ERR_FATAL, "S_FindName: NULL"); } if (!name[0]) { - Com_Error (ERR_FATAL, "S_FindName: empty name\n"); + Com_Error (ERR_FATAL, "S_FindName: empty name"); } if (strlen(name) >= MAX_QPATH) { @@ -391,9 +391,8 @@ void S_Base_BeginRegistration( void ) { if (s_numSfx == 0) { SND_setup(); - s_numSfx = 0; - Com_Memset( s_knownSfx, 0, sizeof( s_knownSfx ) ); - Com_Memset(sfxHash, 0, sizeof(sfx_t *)*LOOP_HASH); + Com_Memset(s_knownSfx, '\0', sizeof(s_knownSfx)); + Com_Memset(sfxHash, '\0', sizeof(sfx_t *) * LOOP_HASH); S_Base_RegisterSound("sound/feedback/hit.wav", qfalse); // changed to a sound in baseq3 } @@ -1467,8 +1466,10 @@ void S_Base_Shutdown( void ) { } SNDDMA_Shutdown(); + SND_shutdown(); s_soundStarted = 0; + s_numSfx = 0; Cmd_RemoveCommand("s_info"); } diff --git a/reaction/code/client/snd_local.h b/reaction/code/client/snd_local.h index 775e5764..dbdcc334 100644 --- a/reaction/code/client/snd_local.h +++ b/reaction/code/client/snd_local.h @@ -202,6 +202,7 @@ qboolean S_LoadSound( sfx_t *sfx ); void SND_free(sndBuffer *v); sndBuffer* SND_malloc( void ); void SND_setup( void ); +void SND_shutdown(void); void S_PaintChannels(int endtime); diff --git a/reaction/code/client/snd_main.c b/reaction/code/client/snd_main.c index 90c6b14f..441f8c3c 100644 --- a/reaction/code/client/snd_main.c +++ b/reaction/code/client/snd_main.c @@ -16,7 +16,7 @@ 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 Foobar; if not, write to the Free Software +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 =========================================================================== */ @@ -509,7 +509,7 @@ void S_Init( void ) if( started ) { if( !S_ValidSoundInterface( &si ) ) { - Com_Error( ERR_FATAL, "Sound interface invalid." ); + Com_Error( ERR_FATAL, "Sound interface invalid" ); } S_SoundInfo( ); diff --git a/reaction/code/client/snd_mem.c b/reaction/code/client/snd_mem.c index 8c3f98e7..ee40a750 100644 --- a/reaction/code/client/snd_mem.c +++ b/reaction/code/client/snd_mem.c @@ -100,6 +100,12 @@ void SND_setup(void) { Com_Printf("Sound memory manager started\n"); } +void SND_shutdown(void) +{ + free(sfxScratchBuffer); + free(buffer); +} + /* ================ ResampleSfx @@ -255,7 +261,7 @@ qboolean S_LoadSound( sfx_t *sfx ) } Hunk_FreeTempMemory(samples); - Z_Free(data); + Hunk_FreeTempMemory(data); return qtrue; } diff --git a/reaction/code/client/snd_openal.c b/reaction/code/client/snd_openal.c index 5a1d6d82..7b2e799c 100644 --- a/reaction/code/client/snd_openal.c +++ b/reaction/code/client/snd_openal.c @@ -258,7 +258,7 @@ static qboolean alBuffersInitialised = qfalse; // Sound effect storage, data structures #define MAX_SFX 4096 static alSfx_t knownSfx[MAX_SFX]; -static int numSfx = 0; +static sfxHandle_t numSfx = 0; static sfxHandle_t default_sfx; @@ -337,7 +337,7 @@ S_AL_BufferUseDefault static void S_AL_BufferUseDefault(sfxHandle_t sfx) { if(sfx == default_sfx) - Com_Error(ERR_FATAL, "Can't load default sound effect %s\n", knownSfx[sfx].filename); + Com_Error(ERR_FATAL, "Can't load default sound effect %s", knownSfx[sfx].filename); Com_Printf( S_COLOR_YELLOW "WARNING: Using default sound for %s\n", knownSfx[sfx].filename); knownSfx[sfx].isDefault = qtrue; @@ -442,7 +442,7 @@ static void S_AL_BufferLoad(sfxHandle_t sfx, qboolean cache) if (!cache) { // Don't create AL cache - Z_Free(data); + Hunk_FreeTempMemory(data); return; } @@ -454,7 +454,7 @@ static void S_AL_BufferLoad(sfxHandle_t sfx, qboolean cache) if((error = qalGetError()) != AL_NO_ERROR) { S_AL_BufferUseDefault(sfx); - Z_Free(data); + Hunk_FreeTempMemory(data); Com_Printf( S_COLOR_RED "ERROR: Can't create a sound buffer for %s - %s\n", curSfx->filename, S_AL_ErrorMsg(error)); return; @@ -479,7 +479,7 @@ static void S_AL_BufferLoad(sfxHandle_t sfx, qboolean cache) if( !S_AL_BufferEvict( ) ) { S_AL_BufferUseDefault(sfx); - Z_Free(data); + Hunk_FreeTempMemory(data); Com_Printf( S_COLOR_RED "ERROR: Out of memory loading %s\n", curSfx->filename); return; } @@ -493,7 +493,7 @@ static void S_AL_BufferLoad(sfxHandle_t sfx, qboolean cache) if(error != AL_NO_ERROR) { S_AL_BufferUseDefault(sfx); - Z_Free(data); + Hunk_FreeTempMemory(data); Com_Printf( S_COLOR_RED "ERROR: Can't fill sound buffer for %s - %s\n", curSfx->filename, S_AL_ErrorMsg(error)); return; @@ -502,7 +502,7 @@ static void S_AL_BufferLoad(sfxHandle_t sfx, qboolean cache) curSfx->info = info; // Free the memory - Z_Free(data); + Hunk_FreeTempMemory(data); // Woo! curSfx->inMemory = qtrue; @@ -570,7 +570,7 @@ void S_AL_BufferShutdown( void ) S_AL_BufferUnload(i); // Clear the tables - memset(knownSfx, 0, sizeof(knownSfx)); + numSfx = 0; // All undone alBuffersInitialised = qfalse; @@ -2568,6 +2568,8 @@ S_AL_BeginRegistration static void S_AL_BeginRegistration( void ) { + if(!numSfx) + S_AL_BufferInit(); } /* @@ -3129,6 +3131,7 @@ qboolean S_AL_Init( soundInterface_t *si ) if(inputdevice && !*inputdevice) inputdevice = NULL; + // Device enumeration support enumeration_all_ext = qalcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT"); enumeration_ext = qalcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT"); @@ -3143,17 +3146,16 @@ qboolean S_AL_Init( soundInterface_t *si ) // get all available devices + the default device name. if(enumeration_ext) { - devicelist = qalcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER); + devicelist = qalcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER); defaultdevice = qalcGetString(NULL, ALC_DEFAULT_ALL_DEVICES_SPECIFIER); } - else - { - // We don't have ALC_ENUMERATE_ALL_EXT but normal enumeration. - devicelist = qalcGetString(NULL, ALC_DEVICE_SPECIFIER); - defaultdevice = qalcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER); - enumeration_ext = qtrue; - } - + else + { + // We don't have ALC_ENUMERATE_ALL_EXT but normal enumeration. + devicelist = qalcGetString(NULL, ALC_DEVICE_SPECIFIER); + defaultdevice = qalcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER); + enumeration_ext = qtrue; + } #ifdef _WIN32 // check whether the default device is generic hardware. If it is, change to @@ -3213,7 +3215,6 @@ qboolean S_AL_Init( soundInterface_t *si ) qalDopplerFactor( s_alDopplerFactor->value ); qalDopplerVelocity( s_alDopplerSpeed->value ); - #ifdef USE_VOIP // !!! FIXME: some of these alcCaptureOpenDevice() values should be cvars. // !!! FIXME: add support for capture device enumeration. diff --git a/reaction/code/client/snd_wavelet.c b/reaction/code/client/snd_wavelet.c index 41b5723a..9940b4f9 100644 --- a/reaction/code/client/snd_wavelet.c +++ b/reaction/code/client/snd_wavelet.c @@ -22,8 +22,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "snd_local.h" -long myftol( float f ); - #define C0 0.4829629131445341 #define C1 0.8365163037378079 #define C2 0.2241438680420134 diff --git a/reaction/code/game/bg_lib.c b/reaction/code/game/bg_lib.c index c84a41bf..4be9f839 100644 --- a/reaction/code/game/bg_lib.c +++ b/reaction/code/game/bg_lib.c @@ -240,6 +240,24 @@ char *strchr( const char *string, int c ) { return (char *)0; } +char *strrchr(const char *string, int c) +{ + const char *found = 0; + + while(*string) + { + if(*string == c) + found = string; + + string++; + } + + if(c) + return (char *) found; + else + return (char *) string; +} + char *strstr( const char *string, const char *strCharSet ) { while ( *string ) { int i; @@ -1502,8 +1520,8 @@ static int dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c ); #define DP_C_LDOUBLE 4 #define char_to_int(p) (p - '0') -#define MAX(p,q) ((p >= q) ? p : q) -#define MIN(p,q) ((p <= q) ? p : q) +//#define MAX(p,q) ((p >= q) ? p : q) +//#define MIN(p,q) ((p <= q) ? p : q) static int dopr (char *buffer, size_t maxlen, const char *format, va_list args) { diff --git a/reaction/code/game/bg_lib.h b/reaction/code/game/bg_lib.h index 6f29d18d..eb32e385 100644 --- a/reaction/code/game/bg_lib.h +++ b/reaction/code/game/bg_lib.h @@ -88,6 +88,7 @@ char *strcat( char *strDestination, const char *strSource ); char *strcpy( char *strDestination, const char *strSource ); int strcmp( const char *string1, const char *string2 ); char *strchr( const char *string, int c ); +char *strrchr(const char *string, int c); char *strstr( const char *string, const char *strCharSet ); char *strncpy( char *strDest, const char *strSource, size_t count ); char *strtok( char *s, const char *delim); diff --git a/reaction/code/game/bg_misc.c b/reaction/code/game/bg_misc.c index d02ce9db..f84a86af 100644 --- a/reaction/code/game/bg_misc.c +++ b/reaction/code/game/bg_misc.c @@ -1618,7 +1618,7 @@ int GetMaterialFromFlag(int flag) char *p, *out = s; if (!s) return NULL; - if ((p = Q_strrchr(s, '/')) != NULL) + if ((p = strrchr(s, '/')) != NULL) { *p=0; out=va("%s", s); @@ -1634,7 +1634,7 @@ int GetMaterialFromFlag(int flag) return NULL; if (!*s) return va(""); - if ((p = Q_strrchr(s, '/')) != NULL) + if ((p = strrchr(s, '/')) != NULL) return p+1; return va("default"); } */ @@ -1648,7 +1648,7 @@ char *modelFromStr(char *s) if (!s) return NULL; strncpy(buffer, s, sizeof(buffer)); - if ((p = Q_strrchr(buffer, '/')) != NULL) + if ((p = strrchr(buffer, '/')) != NULL) *p = '\0'; return buffer; } @@ -1664,7 +1664,7 @@ char *skinFromStr(char *s) if (!*s) return buffer; strncpy(buffer, s, 128); - if ((p = Q_strrchr(buffer, '/')) != NULL) + if ((p = strrchr(buffer, '/')) != NULL) return p+1; strcpy(buffer, "default"); return buffer; diff --git a/reaction/code/game/g_bot.c b/reaction/code/game/g_bot.c index 64f10a59..17a75fa6 100644 --- a/reaction/code/game/g_bot.c +++ b/reaction/code/game/g_bot.c @@ -236,7 +236,7 @@ static void PlayerIntroSound(const char *modelAndSkin) char *skin; Q_strncpyz(model, modelAndSkin, sizeof(model)); - skin = Q_strrchr(model, '/'); + skin = strrchr(model, '/'); if (skin) { *skin++ = '\0'; } else { diff --git a/reaction/code/game/g_client.c b/reaction/code/game/g_client.c index f675ec87..21a0eb02 100644 --- a/reaction/code/game/g_client.c +++ b/reaction/code/game/g_client.c @@ -1092,7 +1092,7 @@ void ClientUserinfoChanged(int clientNum) if (g_gametype.integer >= GT_TEAM) { if (client->sess.savedTeam == TEAM_RED) { Q_strncpyz(model2, g_RQ3_team1model.string, sizeof(model)); - skin2 = Q_strrchr(model2, '/'); + skin2 = strrchr(model2, '/'); if (skin2) { *skin2++ = '\0'; } else { @@ -1107,7 +1107,7 @@ void ClientUserinfoChanged(int clientNum) } } else { Q_strncpyz(model2, g_RQ3_team2model.string, sizeof(model)); - skin2 = Q_strrchr(model2, '/'); + skin2 = strrchr(model2, '/'); if (skin2) { *skin2++ = '\0'; } else { @@ -1123,7 +1123,7 @@ void ClientUserinfoChanged(int clientNum) } } else { Q_strncpyz(model2, model, sizeof(model)); - skin2 = Q_strrchr(model2, '/'); + skin2 = strrchr(model2, '/'); if (skin2) { *skin2++ = '\0'; } else { diff --git a/reaction/code/game/g_cmds.c b/reaction/code/game/g_cmds.c index 9b290dc7..290a2059 100644 --- a/reaction/code/game/g_cmds.c +++ b/reaction/code/game/g_cmds.c @@ -1232,7 +1232,7 @@ void SetTeam(gentity_t * ent, char *s) ent->client->sess.sub = TEAM_FREE; } // they go to the end of the line for tournements - if (team == TEAM_SPECTATOR) { + if (team == TEAM_SPECTATOR && oldTeam != team) { client->sess.spectatorTime = level.time; } // JBravo: not messing with spec system in TP during teamswitches diff --git a/reaction/code/game/g_main.c b/reaction/code/game/g_main.c index 1dc228d9..dba6d549 100644 --- a/reaction/code/game/g_main.c +++ b/reaction/code/game/g_main.c @@ -1442,10 +1442,10 @@ void G_InitGame(int levelTime, int randomSeed, int restart) //Slicer: Default Radio Gender according to MODEL gender Q_strncpyz(model, g_RQ3_team1model.string, sizeof(model)); Q_strncpyz(model2, g_RQ3_team2model.string, sizeof(model)); - s = Q_strrchr(model, '/'); + s = strrchr(model, '/'); if (s) *s++ = '\0'; - s = Q_strrchr(model2, '/'); + s = strrchr(model2, '/'); if (s) *s++ = '\0'; @@ -3194,7 +3194,7 @@ int RQ3_ParseBlock(int tag_type, char *tag, int *cur_pos, char *buf, int len) if (RQ3_GetWord(buf, cur_pos, word_buff, len) != TOKEN_TAG) { G_Printf("RQ3 config system: found model/skin name: %s\n", word_buff); Com_sprintf(model, sizeof(model), "%s", word_buff); - skin = Q_strrchr(word_buff, '/'); + skin = strrchr(word_buff, '/'); if (skin) { *skin++ = '\0'; } else { diff --git a/reaction/code/jpeg-8c/jconfig.h b/reaction/code/jpeg-8c/jconfig.h index 87a2bcc5..248d6d0f 100644 --- a/reaction/code/jpeg-8c/jconfig.h +++ b/reaction/code/jpeg-8c/jconfig.h @@ -31,9 +31,8 @@ typedef unsigned char boolean; #endif /* #undef RIGHT_SHIFT_IS_UNSIGNED */ -// Makro - the code didn't compile in VC++ 2008 Express #ifdef _MSC_VER -#define INLINE __forceinline +#define INLINE __inline #else #define INLINE __inline__ #endif diff --git a/reaction/code/null/null_client.c b/reaction/code/null/null_client.c index 66ead8a2..386cf076 100644 --- a/reaction/code/null/null_client.c +++ b/reaction/code/null/null_client.c @@ -25,7 +25,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA cvar_t *cl_shownet; -void CL_Shutdown( char *finalmsg ) { +void CL_Shutdown(char *finalmsg, qboolean disconnect) +{ } void CL_Init( void ) { @@ -79,16 +80,23 @@ void CL_InitKeyCommands( void ) { void CL_CDDialog( void ) { } -void CL_FlushMemory( void ) { +void CL_FlushMemory(void) +{ +} + +void CL_ShutdownAll(qboolean shutdownRef) +{ } void CL_StartHunkUsers( qboolean rendererOnly ) { } -void CL_Snd_Restart(void) +void CL_InitRef(void) { } -void CL_ShutdownAll(void) {} +void CL_Snd_Shutdown(void) +{ +} qboolean CL_CDKeyValidate( const char *key, const char *checksum ) { return qtrue; } diff --git a/reaction/code/q3_ui/ui_atoms.c b/reaction/code/q3_ui/ui_atoms.c index c798bdd6..753f75a5 100644 --- a/reaction/code/q3_ui/ui_atoms.c +++ b/reaction/code/q3_ui/ui_atoms.c @@ -879,10 +879,10 @@ void UI_MouseEvent( int dx, int dy ) // update mouse screen position uis.cursorx += dx; - if (uis.cursorx < 0) - uis.cursorx = 0; - else if (uis.cursorx > SCREEN_WIDTH) - uis.cursorx = SCREEN_WIDTH; + if (uis.cursorx < -uis.bias) + uis.cursorx = -uis.bias; + else if (uis.cursorx > SCREEN_WIDTH+uis.bias) + uis.cursorx = SCREEN_WIDTH+uis.bias; uis.cursory += dy; if (uis.cursory < 0) @@ -995,6 +995,9 @@ UI_ConsoleCommand qboolean UI_ConsoleCommand( int realTime ) { char *cmd; + uis.frametime = realTime - uis.realtime; + uis.realtime = realTime; + cmd = UI_Argv( 0 ); // ensure minimum menu data is available diff --git a/reaction/code/q3_ui/ui_credits.c b/reaction/code/q3_ui/ui_credits.c index 7baee618..db6f536a 100644 --- a/reaction/code/q3_ui/ui_credits.c +++ b/reaction/code/q3_ui/ui_credits.c @@ -166,12 +166,6 @@ UI_CreditMenu =============== */ void UI_CreditMenu( void ) { - /* This UI_FillRect() hack will blank the borders if you're in widescreen, - so you get a completely black background instead of stripes from the - previous frame on each side of the credits.. */ - const float black[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; - UI_FillRect(0 - uis.bias, 0, (640.0f / uis.xscale) * 2.0f, 480.0f / uis.yscale, black); - memset( &s_credits, 0 ,sizeof(s_credits) ); s_credits.menu.draw = UI_CreditMenu_Draw; diff --git a/reaction/code/q3_ui/ui_demo2.c b/reaction/code/q3_ui/ui_demo2.c index a3810bba..6e522d8f 100644 --- a/reaction/code/q3_ui/ui_demo2.c +++ b/reaction/code/q3_ui/ui_demo2.c @@ -223,7 +223,7 @@ static void Demos_MenuInit( void ) { s_demos.list.generic.y = 130; s_demos.list.width = 16; s_demos.list.height = 14; - Com_sprintf(extension, sizeof(extension), "dm_%d", (int)trap_Cvar_VariableValue( "protocol" ) ); + Com_sprintf(extension, sizeof(extension), ".%s%d", DEMOEXT, (int) trap_Cvar_VariableValue("protocol")); s_demos.list.numitems = trap_FS_GetFileList( "demos", extension, s_demos.names, NAMEBUFSIZE ); s_demos.list.itemnames = (const char **)s_demos.demolist; s_demos.list.columns = 3; diff --git a/reaction/code/q3_ui/ui_playermodel.c b/reaction/code/q3_ui/ui_playermodel.c index e2471498..a2b2eff4 100644 --- a/reaction/code/q3_ui/ui_playermodel.c +++ b/reaction/code/q3_ui/ui_playermodel.c @@ -469,6 +469,11 @@ static void PlayerModel_SetMenuItems( void ) // model trap_Cvar_VariableStringBuffer( "model", s_playermodel.modelskin, 64 ); + // use default skin if none is set + if (!strchr(s_playermodel.modelskin, '/')) { + Q_strcat(s_playermodel.modelskin, 64, "/default"); + } + // find model in our list for (i=0; i "4:3") + for( i = 0; knownRatios[i][0]; i++ ) { + if( !Q_stricmp( str, knownRatios[i][0] ) ) { + Q_strncpyz( str, knownRatios[i][1], sizeof( str ) ); + break; + } + } + // add ratio to list if it is new // establish res/ratio relationship for( i = 0; ratioBuf[i][0]; i++ ) @@ -445,23 +453,11 @@ static void GraphicsOptions_GetAspectRatios( void ) Q_strncpyz( ratioBuf[i], str, sizeof(ratioBuf[i]) ); ratioToRes[i] = r; } - resToRatio[r] = i; - } - - // prepare itemlist pointer array - // rename common ratios ("1.33:1" -> "4:3") - for( r = 0; ratioBuf[r][0]; r++ ) - { - for( i = 0; knownRatios[i][0]; i++ ) - { - if( !Q_stricmp( ratioBuf[r], knownRatios[i][0] ) ) - { - Q_strncpyz( ratioBuf[r], knownRatios[i][1], sizeof(ratioBuf[r]) ); - break; - } - } - ratios[r] = ratioBuf[r]; + + ratios[r] = ratioBuf[r]; + resToRatio[r] = i; } + ratios[r] = NULL; } @@ -683,9 +679,11 @@ static void GraphicsOptions_ApplyChanges( void *unused, int notification ) trap_Cvar_SetValue( "r_mode", s_graphicsoptions.mode.curvalue ); trap_Cvar_SetValue( "r_fullscreen", s_graphicsoptions.fs.curvalue ); - trap_Cvar_SetValue( "r_colorbits", 0 ); - trap_Cvar_SetValue( "r_depthbits", 0 ); - trap_Cvar_SetValue( "r_stencilbits", 0 ); + + trap_Cvar_Reset("r_colorbits"); + trap_Cvar_Reset("r_depthbits"); + trap_Cvar_Reset("r_stencilbits"); + trap_Cvar_SetValue( "r_vertexLight", s_graphicsoptions.lighting.curvalue ); if ( s_graphicsoptions.geometry.curvalue == 2 ) diff --git a/reaction/code/qcommon/cm_polylib.c b/reaction/code/qcommon/cm_polylib.c index f4d6ce85..500b1df1 100644 --- a/reaction/code/qcommon/cm_polylib.c +++ b/reaction/code/qcommon/cm_polylib.c @@ -272,11 +272,11 @@ CopyWinding */ winding_t *CopyWinding (winding_t *w) { - unsigned long size; + intptr_t size; winding_t *c; c = AllocWinding (w->numpoints); - size = (long)((winding_t *)0)->p[w->numpoints]; + size = (intptr_t) ((winding_t *)0)->p[w->numpoints]; Com_Memcpy (c, w, size); return c; } diff --git a/reaction/code/qcommon/cmd.c b/reaction/code/qcommon/cmd.c index 15c2d891..6f7c36f0 100644 --- a/reaction/code/qcommon/cmd.c +++ b/reaction/code/qcommon/cmd.c @@ -686,7 +686,7 @@ void Cmd_RemoveCommandSafe( const char *cmd_name ) if( cmd->function ) { Com_Error( ERR_DROP, "Restricted source tried to remove " - "system command \"%s\"\n", cmd_name ); + "system command \"%s\"", cmd_name ); return; } diff --git a/reaction/code/qcommon/common.c b/reaction/code/qcommon/common.c index 7d0b7e9b..764a60b2 100644 --- a/reaction/code/qcommon/common.c +++ b/reaction/code/qcommon/common.c @@ -90,6 +90,14 @@ cvar_t *com_basegame; cvar_t *com_homepath; cvar_t *com_busyWait; +#if idx64 + int (*Q_VMftol)(void); +#elif id386 + long (QDECL *Q_ftol)(float f); + int (QDECL *Q_VMftol)(void); + void (QDECL *Q_SnapVector)(vec3_t vec); +#endif + // com_speeds times int time_game; int time_frontend; // renderer frontend time @@ -330,7 +338,7 @@ void QDECL Com_Error( int code, const char *fmt, ... ) { longjmp (abortframe, -1); } else { VM_Forced_Unload_Start(); - CL_Shutdown (va("Client fatal crashed: %s", com_errorMessage)); + CL_Shutdown (va("Client fatal crashed: %s", com_errorMessage), qtrue); SV_Shutdown (va("Server fatal crashed: %s", com_errorMessage)); VM_Forced_Unload_Done(); } @@ -354,8 +362,14 @@ void Com_Quit_f( void ) { // don't try to shutdown if we are in a recursive error char *p = Cmd_Args( ); if ( !com_errorEntered ) { + // Some VMs might execute "quit" command directly, + // which would trigger an unload of active VM error. + // Sys_Quit will kill this process anyways, so + // a corrupt call stack makes no difference + VM_Forced_Unload_Start(); SV_Shutdown (p[0] ? p : "Server quit"); - CL_Shutdown (p[0] ? p : "Client quit"); + CL_Shutdown (p[0] ? p : "Client quit", qtrue); + VM_Forced_Unload_Done(); Com_Shutdown (); FS_Shutdown(qtrue); } @@ -461,13 +475,13 @@ void Com_StartupVariable( const char *match ) { } s = Cmd_Argv(1); - + if(!match || !strcmp(s, match)) { if(Cvar_Flags(s) == CVAR_NONEXISTENT) Cvar_Get(s, Cmd_Argv(2), CVAR_USER_CREATED); else - Cvar_Set( s, Cmd_Argv(2) ); + Cvar_Set2(s, Cmd_Argv(2), qfalse); } } } @@ -1054,12 +1068,12 @@ void Z_CheckHeap( void ) { break; // all blocks have been hit } if ( (byte *)block + block->size != (byte *)block->next) - Com_Error( ERR_FATAL, "Z_CheckHeap: block size does not touch the next block\n" ); + Com_Error( ERR_FATAL, "Z_CheckHeap: block size does not touch the next block" ); if ( block->next->prev != block) { - Com_Error( ERR_FATAL, "Z_CheckHeap: next block doesn't have proper back link\n" ); + Com_Error( ERR_FATAL, "Z_CheckHeap: next block doesn't have proper back link" ); } if ( !block->tag && !block->next->tag ) { - Com_Error( ERR_FATAL, "Z_CheckHeap: two consecutive free blocks\n" ); + Com_Error( ERR_FATAL, "Z_CheckHeap: two consecutive free blocks" ); } } } @@ -1870,7 +1884,7 @@ void Hunk_Trash( void ) { return; #ifdef _DEBUG - Com_Error(ERR_DROP, "hunk trashed\n"); + Com_Error(ERR_DROP, "hunk trashed"); return; #endif @@ -2378,34 +2392,47 @@ Change to a new mod properly with cleaning up cvars before switching. ================== */ -void Com_GameRestart(int checksumFeed, qboolean clientRestart) +void Com_GameRestart(int checksumFeed, qboolean disconnect) { // make sure no recursion can be triggered if(!com_gameRestarting && com_fullyInitialized) { - com_gameRestarting = qtrue; + int clWasRunning; + + com_gameRestarting = qtrue; + clWasRunning = com_cl_running->integer; - if(clientRestart) - { - CL_Disconnect(qfalse); - CL_ShutdownAll(); - } - // Kill server if we have one if(com_sv_running->integer) SV_Shutdown("Game directory changed"); + if(clWasRunning) + { + if(disconnect) + CL_Disconnect(qfalse); + + CL_Shutdown("Game directory changed", disconnect); + } + FS_Restart(checksumFeed); // Clean out any user and VM created cvars Cvar_Restart(qtrue); Com_ExecuteCfg(); - - // Restart sound subsystem so old handles are flushed - CL_Snd_Restart(); - if(clientRestart) + if(disconnect) + { + // We don't want to change any network settings if gamedir + // change was triggered by a connect to server because the + // new network settings might make the connection fail. + NET_Restart_f(); + } + + if(clWasRunning) + { + CL_Init(); CL_StartHunkUsers(qfalse); + } com_gameRestarting = qfalse; } @@ -2421,7 +2448,16 @@ Expose possibility to change current running mod to the user void Com_GameRestart_f(void) { - Cvar_Set("fs_game", Cmd_Argv(1)); + if(!FS_FilenameCompare(Cmd_Argv(1), com_basegame->string)) + { + // This is the standard base game. Servers and clients should + // use "" and not the standard basegame name because this messes + // up pak file negotiation and lots of other stuff + + Cvar_Set("fs_game", ""); + } + else + Cvar_Set("fs_game", Cmd_Argv(1)); Com_GameRestart(0, qtrue); } @@ -2565,6 +2601,53 @@ static void Com_DetectAltivec(void) } } +/* +================= +Com_DetectSSE +Find out whether we have SSE support for Q_ftol function +================= +*/ + +#if id386 || idx64 + +static void Com_DetectSSE(void) +{ +#if !idx64 + cpuFeatures_t feat; + + feat = Sys_GetProcessorFeatures(); + + if(feat & CF_SSE) + { + if(feat & CF_SSE2) + Q_SnapVector = qsnapvectorsse; + else + Q_SnapVector = qsnapvectorx87; + + Q_ftol = qftolsse; +#endif + Q_VMftol = qvmftolsse; + + Com_Printf("Have SSE support\n"); +#if !idx64 + } + else + { + Q_ftol = qftolx87; + Q_VMftol = qvmftolx87; + Q_SnapVector = qsnapvectorx87; + + Com_Printf("No SSE support on this machine\n"); + } +#endif +} + +#else + +#define Com_DetectSSE() + +#endif + /* ================= Com_InitRand @@ -2615,6 +2698,8 @@ void Com_Init( char *commandLine ) { // Swap_Init (); Cbuf_Init (); + Com_DetectSSE(); + // override anything from the config files with command line args Com_StartupVariable( NULL ); @@ -2634,7 +2719,6 @@ void Com_Init( char *commandLine ) { if(!com_basegame->string[0]) Cvar_ForceReset("com_basegame"); - // Com_StartupVariable( FS_InitFilesystem (); Com_InitJournaling(); @@ -2704,6 +2788,7 @@ void Com_Init( char *commandLine ) { com_maxfpsMinimized = Cvar_Get( "com_maxfpsMinimized", "0", CVAR_ARCHIVE ); com_abnormalExit = Cvar_Get( "com_abnormalExit", "0", CVAR_ROM ); com_busyWait = Cvar_Get("com_busyWait", "0", CVAR_ARCHIVE); + Cvar_Get("com_errorMessage", "", CVAR_ROM | CVAR_NORESTART); com_introPlayed = Cvar_Get( "com_introplayed", "0", CVAR_ARCHIVE); diff --git a/reaction/code/qcommon/cvar.c b/reaction/code/qcommon/cvar.c index fa4c00ce..68f25070 100644 --- a/reaction/code/qcommon/cvar.c +++ b/reaction/code/qcommon/cvar.c @@ -35,8 +35,6 @@ int cvar_numIndexes; #define FILE_HASH_SIZE 256 static cvar_t *hashTable[FILE_HASH_SIZE]; -cvar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force); - /* ================ return a hash value for the filename @@ -635,10 +633,10 @@ void Cvar_SetSafe( const char *var_name, const char *value ) { if( value ) Com_Error( ERR_DROP, "Restricted source tried to set " - "\"%s\" to \"%s\"\n", var_name, value ); + "\"%s\" to \"%s\"", var_name, value ); else Com_Error( ERR_DROP, "Restricted source tried to " - "modify \"%s\"\n", var_name ); + "modify \"%s\"", var_name ); return; } Cvar_Set( var_name, value ); diff --git a/reaction/code/qcommon/files.c b/reaction/code/qcommon/files.c index 6609ef2c..21475099 100644 --- a/reaction/code/qcommon/files.c +++ b/reaction/code/qcommon/files.c @@ -215,6 +215,7 @@ typedef struct fileInPack_s { } fileInPack_t; typedef struct { + char pakPathname[MAX_OSPATH]; // c:\quake3\baseq3 char pakFilename[MAX_OSPATH]; // c:\quake3\baseq3\pak0.pk3 char pakBasename[MAX_OSPATH]; // pak0 char pakGamename[MAX_OSPATH]; // baseq3 @@ -230,6 +231,7 @@ typedef struct { typedef struct { char path[MAX_OSPATH]; // c:\quake3 + char fullpath[MAX_OSPATH]; // c:\quake3\baseq3 char gamedir[MAX_OSPATH]; // baseq3 } directory_t; @@ -393,7 +395,7 @@ static fileHandle_t FS_HandleForFile(void) { } static FILE *FS_FileForHandle( fileHandle_t f ) { - if ( f < 0 || f > MAX_FILE_HANDLES ) { + if ( f < 1 || f > MAX_FILE_HANDLES ) { Com_Error( ERR_DROP, "FS_FileForHandle: out of range" ); } if (fsh[f].zipFile == qtrue) { @@ -413,6 +415,25 @@ void FS_ForceFlush( fileHandle_t f ) { setvbuf( file, NULL, _IONBF, 0 ); } +/* +================ +FS_fplength +================ +*/ + +long FS_fplength(FILE *h) +{ + long pos; + long end; + + pos = ftell(h); + fseek(h, 0, SEEK_END); + end = ftell(h); + fseek(h, pos, SEEK_SET); + + return end; +} + /* ================ FS_filelength @@ -422,18 +443,16 @@ it will return the size of the pak file, not the expected size of the file. ================ */ -int FS_filelength( fileHandle_t f ) { - int pos; - int end; - FILE* h; +long FS_filelength(fileHandle_t f) +{ + FILE *h; h = FS_FileForHandle(f); - pos = ftell (h); - fseek (h, 0, SEEK_END); - end = ftell (h); - fseek (h, pos, SEEK_SET); - - return end; + + if(h == NULL) + return -1; + else + return FS_fplength(h); } /* @@ -517,7 +536,7 @@ qboolean FS_CreatePath (char *OSPath) { // create the directory *ofs = 0; if (!Sys_Mkdir (path)) { - Com_Error( ERR_FATAL, "FS_CreatePath: failed to create path \"%s\"\n", + Com_Error( ERR_FATAL, "FS_CreatePath: failed to create path \"%s\"", path ); } *ofs = PATH_SEP; @@ -541,7 +560,7 @@ static void FS_CheckFilenameIsNotExecutable( const char *filename, if( !Q_stricmp( COM_GetExtension( filename ), DLL_EXT ) ) { Com_Error( ERR_FATAL, "%s: Not allowed to manipulate '%s' due " - "to %s extension\n", function, filename, DLL_EXT ); + "to %s extension", function, filename, DLL_EXT ); } } @@ -570,6 +589,28 @@ void FS_HomeRemove( const char *homePath ) { fs_gamedir, homePath ) ); } +/* +================ +FS_FileInPathExists + +Tests if path and file exists +================ +*/ +qboolean FS_FileInPathExists(const char *testpath) +{ + FILE *filep; + + filep = fopen(testpath, "rb"); + + if(filep) + { + fclose(filep); + return qtrue; + } + + return qfalse; +} + /* ================ FS_FileExists @@ -580,19 +621,9 @@ search the paths. This is to determine if opening a file to write NOTE TTimo: this goes with FS_FOpenFileWrite for opening the file afterwards ================ */ -qboolean FS_FileExists( const char *file ) +qboolean FS_FileExists(const char *file) { - FILE *f; - char *testpath; - - testpath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, file ); - - f = fopen( testpath, "rb" ); - if (f) { - fclose( f ); - return qtrue; - } - return qfalse; + return FS_FileInPathExists(FS_BuildOSPath(fs_homepath->string, fs_gamedir, file)); } /* @@ -604,18 +635,12 @@ Tests if the file exists */ qboolean FS_SV_FileExists( const char *file ) { - FILE *f; char *testpath; testpath = FS_BuildOSPath( fs_homepath->string, file, ""); testpath[strlen(testpath)-1] = '\0'; - f = fopen( testpath, "rb" ); - if (f) { - fclose( f ); - return qtrue; - } - return qfalse; + return FS_FileInPathExists(testpath); } @@ -630,7 +655,7 @@ fileHandle_t FS_SV_FOpenFileWrite( const char *filename ) { fileHandle_t f; if ( !fs_searchpaths ) { - Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + Com_Error( ERR_FATAL, "Filesystem call made without initialization" ); } ospath = FS_BuildOSPath( fs_homepath->string, filename, "" ); @@ -669,12 +694,13 @@ Search for a file somewhere below the home path then base path in that order =========== */ -int FS_SV_FOpenFileRead( const char *filename, fileHandle_t *fp ) { +long FS_SV_FOpenFileRead(const char *filename, fileHandle_t *fp) +{ char *ospath; fileHandle_t f = 0; if ( !fs_searchpaths ) { - Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + Com_Error( ERR_FATAL, "Filesystem call made without initialization" ); } f = FS_HandleForFile(); @@ -739,7 +765,7 @@ void FS_SV_Rename( const char *from, const char *to ) { char *from_ospath, *to_ospath; if ( !fs_searchpaths ) { - Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + Com_Error( ERR_FATAL, "Filesystem call made without initialization" ); } // don't let sound stutter @@ -771,7 +797,7 @@ void FS_Rename( const char *from, const char *to ) { char *from_ospath, *to_ospath; if ( !fs_searchpaths ) { - Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + Com_Error( ERR_FATAL, "Filesystem call made without initialization" ); } // don't let sound stutter @@ -801,7 +827,7 @@ on files returned by FS_FOpenFile... */ void FS_FCloseFile( fileHandle_t f ) { if ( !fs_searchpaths ) { - Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + Com_Error( ERR_FATAL, "Filesystem call made without initialization" ); } if (fsh[f].zipFile == qtrue) { @@ -831,7 +857,7 @@ fileHandle_t FS_FOpenFileWrite( const char *filename ) { fileHandle_t f; if ( !fs_searchpaths ) { - Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + Com_Error( ERR_FATAL, "Filesystem call made without initialization" ); } f = FS_HandleForFile(); @@ -874,7 +900,7 @@ fileHandle_t FS_FOpenFileAppend( const char *filename ) { fileHandle_t f; if ( !fs_searchpaths ) { - Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + Com_Error( ERR_FATAL, "Filesystem call made without initialization" ); } f = FS_HandleForFile(); @@ -917,7 +943,7 @@ fileHandle_t FS_FCreateOpenPipeFile( const char *filename ) { fileHandle_t f; if ( !fs_searchpaths ) { - Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + Com_Error( ERR_FATAL, "Filesystem call made without initialization" ); } f = FS_HandleForFile(); @@ -1022,7 +1048,7 @@ qboolean FS_IsDemoExt(const char *filename, int namelen) char *ext_test; int index, protocol; - ext_test = Q_strrchr(filename, '.'); + ext_test = strrchr(filename, '.'); if(ext_test && !Q_stricmpn(ext_test + 1, DEMOEXT, ARRAY_LEN(DEMOEXT) - 1)) { protocol = atoi(ext_test + ARRAY_LEN(DEMOEXT)); @@ -1040,6 +1066,256 @@ qboolean FS_IsDemoExt(const char *filename, int namelen) return qfalse; } +/* +=========== +FS_FOpenFileReadDir + +Tries opening file "filename" in searchpath "search" +Returns filesize and an open FILE pointer. +=========== +*/ +extern qboolean com_fullyInitialized; + +long FS_FOpenFileReadDir(const char *filename, searchpath_t *search, fileHandle_t *file, qboolean uniqueFILE) +{ + long hash; + pack_t *pak; + fileInPack_t *pakFile; + directory_t *dir; + char *netpath; + FILE *filep; + int len; + + if(filename == NULL) + Com_Error(ERR_FATAL, "FS_FOpenFileRead: NULL 'filename' parameter passed"); + + // qpaths are not supposed to have a leading slash + if(filename[0] == '/' || filename[0] == '\\') + filename++; + + // make absolutely sure that it can't back up the path. + // The searchpaths do guarantee that something will always + // be prepended, so we don't need to worry about "c:" or "//limbo" + if(strstr(filename, ".." ) || strstr(filename, "::")) + { + if(file == NULL) + return qfalse; + + *file = 0; + return -1; + } + + // make sure the q3key file is only readable by the quake3.exe at initialization + // any other time the key should only be accessed in memory using the provided functions + if(com_fullyInitialized && strstr(filename, "q3key")) + { + if(file == NULL) + return qfalse; + + *file = 0; + return -1; + } + + if(file == NULL) + { + // just wants to see if file is there + + // is the element a pak file? + if(search->pack) + { + hash = FS_HashFileName(filename, search->pack->hashSize); + + if(search->pack->hashTable[hash]) + { + // look through all the pak file elements + pak = search->pack; + pakFile = pak->hashTable[hash]; + + do + { + // case and separator insensitive comparisons + if(!FS_FilenameCompare(pakFile->name, filename)) + { + // found it! + if(pakFile->len) + return pakFile->len; + else + { + // It's not nice, but legacy code depends + // on positive value if file exists no matter + // what size + return 1; + } + } + + pakFile = pakFile->next; + } while(pakFile != NULL); + } + } + else if(search->dir) + { + dir = search->dir; + + netpath = FS_BuildOSPath(dir->path, dir->gamedir, filename); + filep = fopen (netpath, "rb"); + + if(filep) + { + len = FS_fplength(filep); + fclose(filep); + + if(len) + return len; + else + return 1; + } + } + + return 0; + } + + *file = FS_HandleForFile(); + fsh[*file].handleFiles.unique = uniqueFILE; + + // is the element a pak file? + if(search->pack) + { + hash = FS_HashFileName(filename, search->pack->hashSize); + + if(search->pack->hashTable[hash]) + { + // disregard if it doesn't match one of the allowed pure pak files + if(!FS_PakIsPure(search->pack)) + { + *file = 0; + return -1; + } + + // look through all the pak file elements + pak = search->pack; + pakFile = pak->hashTable[hash]; + + do + { + // case and separator insensitive comparisons + if(!FS_FilenameCompare(pakFile->name, filename)) + { + // found it! + + // mark the pak as having been referenced and mark specifics on cgame and ui + // shaders, txt, arena files by themselves do not count as a reference as + // these are loaded from all pk3s + // from every pk3 file.. + len = strlen(filename); + + if (!(pak->referenced & FS_GENERAL_REF)) + { + if(!FS_IsExt(filename, ".shader", len) && + !FS_IsExt(filename, ".txt", len) && + !FS_IsExt(filename, ".cfg", len) && + !FS_IsExt(filename, ".config", len) && + !FS_IsExt(filename, ".bot", len) && + !FS_IsExt(filename, ".arena", len) && + !FS_IsExt(filename, ".menu", len) && + !strstr(filename, "levelshots")) + { + pak->referenced |= FS_GENERAL_REF; + } + } + + if(strstr(filename, "qagame.qvm")) + pak->referenced |= FS_QAGAME_REF; + if(strstr(filename, "cgame.qvm")) + pak->referenced |= FS_CGAME_REF; + if(strstr(filename, "ui.qvm")) + pak->referenced |= FS_UI_REF; + + if(uniqueFILE) + { + // open a new file on the pakfile + fsh[*file].handleFiles.file.z = unzOpen(pak->pakFilename); + + if(fsh[*file].handleFiles.file.z == NULL) + Com_Error(ERR_FATAL, "Couldn't open %s", pak->pakFilename); + } + else + fsh[*file].handleFiles.file.z = pak->handle; + + Q_strncpyz(fsh[*file].name, filename, sizeof(fsh[*file].name)); + fsh[*file].zipFile = qtrue; + + // set the file position in the zip file (also sets the current file info) + unzSetOffset(fsh[*file].handleFiles.file.z, pakFile->pos); + + // open the file in the zip + unzOpenCurrentFile(fsh[*file].handleFiles.file.z); + fsh[*file].zipFilePos = pakFile->pos; + + if(fs_debug->integer) + { + Com_Printf("FS_FOpenFileRead: %s (found in '%s')\n", + filename, pak->pakFilename); + } + + return pakFile->len; + } + + pakFile = pakFile->next; + } while(pakFile != NULL); + } + } + else if(search->dir) + { + // check a file in the directory tree + + // if we are running restricted, the only files we + // will allow to come from the directory are .cfg files + len = strlen(filename); + // FIXME TTimo I'm not sure about the fs_numServerPaks test + // if you are using FS_ReadFile to find out if a file exists, + // this test can make the search fail although the file is in the directory + // I had the problem on https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=8 + // turned out I used FS_FileExists instead + if(fs_numServerPaks) + { + if(!FS_IsExt(filename, ".cfg", len) && // for config files + !FS_IsExt(filename, ".menu", len) && // menu files + !FS_IsExt(filename, ".game", len) && // menu files + !FS_IsExt(filename, ".cfg", len) && // for journal files + !FS_IsDemoExt(filename, len)) // demos + { + *file = 0; + return -1; + } + } + + dir = search->dir; + + netpath = FS_BuildOSPath(dir->path, dir->gamedir, filename); + filep = fopen(netpath, "rb"); + + if (filep == NULL) + { + *file = 0; + return -1; + } + + Q_strncpyz(fsh[*file].name, filename, sizeof(fsh[*file].name)); + fsh[*file].zipFile = qfalse; + + if(fs_debug->integer) + { + Com_Printf("FS_FOpenFileRead: %s (found in '%s/%s')\n", filename, + dir->path, dir->gamedir); + } + + fsh[*file].handleFiles.file.o = filep; + return FS_fplength(filep); + } + + return -1; +} + /* =========== FS_FOpenFileRead @@ -1050,240 +1326,134 @@ Used for streaming data out of either a separate file or a ZIP file. =========== */ -extern qboolean com_fullyInitialized; +long FS_FOpenFileRead(const char *filename, fileHandle_t *file, qboolean uniqueFILE) +{ + searchpath_t *search; + long len; -int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueFILE ) { - searchpath_t *search; - char *netpath; - pack_t *pak; - fileInPack_t *pakFile; - directory_t *dir; - long hash; - FILE *temp; - int l; - char demoExt[16]; + if(!fs_searchpaths) + Com_Error(ERR_FATAL, "Filesystem call made without initialization"); - hash = 0; - - if ( !fs_searchpaths ) { - Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); - } - - if ( file == NULL ) { - // just wants to see if file is there - for ( search = fs_searchpaths ; search ; search = search->next ) { - // - if ( search->pack ) { - hash = FS_HashFileName(filename, search->pack->hashSize); - } - // is the element a pak file? - if ( search->pack && search->pack->hashTable[hash] ) { - // look through all the pak file elements - pak = search->pack; - pakFile = pak->hashTable[hash]; - do { - // case and separator insensitive comparisons - if ( !FS_FilenameCompare( pakFile->name, filename ) ) { - // found it! - return qtrue; - } - pakFile = pakFile->next; - } while(pakFile != NULL); - } else if ( search->dir ) { - dir = search->dir; - - netpath = FS_BuildOSPath( dir->path, dir->gamedir, filename ); - temp = fopen (netpath, "rb"); - if ( !temp ) { - continue; - } - fclose(temp); - return qtrue; - } - } - return qfalse; - } - - if ( !filename ) { - Com_Error( ERR_FATAL, "FS_FOpenFileRead: NULL 'filename' parameter passed\n" ); - } - - Com_sprintf (demoExt, sizeof(demoExt), ".dm_%d",PROTOCOL_VERSION ); - // qpaths are not supposed to have a leading slash - if ( filename[0] == '/' || filename[0] == '\\' ) { - filename++; - } - - // make absolutely sure that it can't back up the path. - // The searchpaths do guarantee that something will always - // be prepended, so we don't need to worry about "c:" or "//limbo" - if ( strstr( filename, ".." ) || strstr( filename, "::" ) ) { - *file = 0; - return -1; - } - - // make sure the q3key file is only readable by the quake3.exe at initialization - // any other time the key should only be accessed in memory using the provided functions - if( com_fullyInitialized && strstr( filename, "q3key" ) ) { - *file = 0; - return -1; - } - - // - // search through the path, one element at a time - // - - *file = FS_HandleForFile(); - fsh[*file].handleFiles.unique = uniqueFILE; - - for ( search = fs_searchpaths ; search ; search = search->next ) { - // - if ( search->pack ) { - hash = FS_HashFileName(filename, search->pack->hashSize); - } - // is the element a pak file? - if ( search->pack && search->pack->hashTable[hash] ) { - // disregard if it doesn't match one of the allowed pure pak files - if ( !FS_PakIsPure(search->pack) ) { - continue; - } - - // look through all the pak file elements - pak = search->pack; - pakFile = pak->hashTable[hash]; - do { - // case and separator insensitive comparisons - if ( !FS_FilenameCompare( pakFile->name, filename ) ) { - // found it! - - // mark the pak as having been referenced and mark specifics on cgame and ui - // shaders, txt, arena files by themselves do not count as a reference as - // these are loaded from all pk3s - // from every pk3 file.. - l = strlen( filename ); - if ( !(pak->referenced & FS_GENERAL_REF)) { - if ( Q_stricmp(filename + l - 7, ".shader") != 0 && - Q_stricmp(filename + l - 4, ".txt") != 0 && - Q_stricmp(filename + l - 4, ".cfg") != 0 && - Q_stricmp(filename + l - 7, ".config") != 0 && - strstr(filename, "levelshots") == NULL && - Q_stricmp(filename + l - 4, ".bot") != 0 && - Q_stricmp(filename + l - 6, ".arena") != 0 && - Q_stricmp(filename + l - 5, ".menu") != 0) { - pak->referenced |= FS_GENERAL_REF; - } - } - - if (!(pak->referenced & FS_QAGAME_REF) && strstr(filename, "qagame.qvm")) { - pak->referenced |= FS_QAGAME_REF; - } - if (!(pak->referenced & FS_CGAME_REF) && strstr(filename, "cgame.qvm")) { - pak->referenced |= FS_CGAME_REF; - } - if (!(pak->referenced & FS_UI_REF) && strstr(filename, "ui.qvm")) { - pak->referenced |= FS_UI_REF; - } - - if ( uniqueFILE ) { - // open a new file on the pakfile - fsh[*file].handleFiles.file.z = unzOpen (pak->pakFilename); - if (fsh[*file].handleFiles.file.z == NULL) { - Com_Error (ERR_FATAL, "Couldn't open %s", pak->pakFilename); - } - } else { - fsh[*file].handleFiles.file.z = pak->handle; - } - Q_strncpyz( fsh[*file].name, filename, sizeof( fsh[*file].name ) ); - fsh[*file].zipFile = qtrue; - // set the file position in the zip file (also sets the current file info) - unzSetOffset(fsh[*file].handleFiles.file.z, pakFile->pos); - // open the file in the zip - unzOpenCurrentFile( fsh[*file].handleFiles.file.z ); - fsh[*file].zipFilePos = pakFile->pos; - - if ( fs_debug->integer ) { - Com_Printf( "FS_FOpenFileRead: %s (found in '%s')\n", - filename, pak->pakFilename ); - } - return pakFile->len; - } - pakFile = pakFile->next; - } while(pakFile != NULL); - } else if ( search->dir ) { - // check a file in the directory tree - - // if we are running restricted, the only files we - // will allow to come from the directory are .cfg files - l = strlen( filename ); - // FIXME TTimo I'm not sure about the fs_numServerPaks test - // if you are using FS_ReadFile to find out if a file exists, - // this test can make the search fail although the file is in the directory - // I had the problem on https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=8 - // turned out I used FS_FileExists instead - if ( fs_numServerPaks ) { - - if ( Q_stricmp( filename + l - 4, ".cfg" ) // for config files - && Q_stricmp( filename + l - 5, ".menu" ) // menu files - && Q_stricmp( filename + l - 5, ".game" ) // menu files - && Q_stricmp( filename + l - strlen(demoExt), demoExt ) // menu files - && Q_stricmp( filename + l - 4, ".dat" ) ) { // for journal files - continue; - } - } - - dir = search->dir; - - netpath = FS_BuildOSPath( dir->path, dir->gamedir, filename ); - fsh[*file].handleFiles.file.o = fopen (netpath, "rb"); - if ( !fsh[*file].handleFiles.file.o ) { - continue; - } - - Q_strncpyz( fsh[*file].name, filename, sizeof( fsh[*file].name ) ); - fsh[*file].zipFile = qfalse; - if ( fs_debug->integer ) { - Com_Printf( "FS_FOpenFileRead: %s (found in '%s/%s')\n", filename, - dir->path, dir->gamedir ); - } - - return FS_filelength (*file); - } + for(search = fs_searchpaths; search; search = search->next) + { + len = FS_FOpenFileReadDir(filename, search, file, uniqueFILE); + + if(file == NULL) + { + if(len > 0) + return len; + } + else + { + if(len >= 0 && *file) + return len; + } + } #ifdef FS_MISSING - if (missingFiles) { + if(missingFiles) fprintf(missingFiles, "%s\n", filename); - } #endif - *file = 0; + + if(file) + *file = 0; + return -1; } +/* +================= +FS_FindVM -char *FS_FindDll( const char *filename ) { - searchpath_t *search; - directory_t *dir; +Find a suitable VM file in search path order. - if ( !fs_searchpaths ) { - Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); - } +In each searchpath try: + - open DLL file if DLL loading enabled + - open QVM file - for ( search = fs_searchpaths ; search ; search = search->next ) { - if ( search->dir ) { - FILE *f; - char *netpath; +Enable search for DLL by setting enableDll to FSVM_ENABLEDLL +write found DLL or QVM to "found" and return VMI_NATIVE if DLL, VMI_COMPILED if QVM +Return the searchpath in "startSearch". +================= +*/ + +vmInterpret_t FS_FindVM(void **startSearch, char *found, int foundlen, const char *name, int enableDll) +{ + searchpath_t *search, *lastSearch; + directory_t *dir; + pack_t *pack; + char dllName[MAX_OSPATH], qvmName[MAX_OSPATH]; + char *netpath; + + if(!fs_searchpaths) + Com_Error(ERR_FATAL, "Filesystem call made without initialization"); + + if(enableDll) + Com_sprintf(dllName, sizeof(dllName), "%s" ARCH_STRING DLL_EXT, name); + + Com_sprintf(qvmName, sizeof(dllName), "vm/%s.qvm", name); + + lastSearch = *startSearch; + if(*startSearch == NULL) + search = fs_searchpaths; + else + search = lastSearch->next; + + while(search) + { + if(search->dir && !fs_numServerPaks) + { dir = search->dir; - netpath = FS_BuildOSPath( dir->path, dir->gamedir, filename ); - f = fopen( netpath, "rb" ); - if (f) { - fclose( f ); - return netpath; + + if(enableDll) + { + netpath = FS_BuildOSPath(dir->path, dir->gamedir, dllName); + + if(FS_FileInPathExists(netpath)) + { + Q_strncpyz(found, netpath, foundlen); + *startSearch = search; + + return VMI_NATIVE; + } + } + + if(FS_FOpenFileReadDir(qvmName, search, NULL, qfalse) > 0) + { + *startSearch = search; + return VMI_COMPILED; } } + else if(search->pack) + { + pack = search->pack; + + if(lastSearch && lastSearch->pack) + { + // make sure we only try loading one VM file per game dir + // i.e. if VM from pak7.pk3 fails we won't try one from pak6.pk3 + + if(!FS_FilenameCompare(lastSearch->pack->pakPathname, pack->pakPathname)) + { + search = search->next; + continue; + } + } + + if(FS_FOpenFileReadDir(qvmName, search, NULL, qfalse) > 0) + { + *startSearch = search; + + return VMI_COMPILED; + } + } + + search = search->next; } - return NULL; + return -1; } /* @@ -1295,7 +1465,7 @@ Properly handles partial reads */ int FS_Read2( void *buffer, int len, fileHandle_t f ) { if ( !fs_searchpaths ) { - Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + Com_Error( ERR_FATAL, "Filesystem call made without initialization" ); } if ( !f ) { @@ -1319,7 +1489,7 @@ int FS_Read( void *buffer, int len, fileHandle_t f ) { int tries; if ( !fs_searchpaths ) { - Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + Com_Error( ERR_FATAL, "Filesystem call made without initialization" ); } if ( !f ) { @@ -1373,7 +1543,7 @@ int FS_Write( const void *buffer, int len, fileHandle_t h ) { FILE *f; if ( !fs_searchpaths ) { - Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + Com_Error( ERR_FATAL, "Filesystem call made without initialization" ); } if ( !h ) { @@ -1434,7 +1604,7 @@ int FS_Seek( fileHandle_t f, long offset, int origin ) { int _origin; if ( !fs_searchpaths ) { - Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + Com_Error( ERR_FATAL, "Filesystem call made without initialization" ); return -1; } @@ -1452,7 +1622,7 @@ int FS_Seek( fileHandle_t f, long offset, int origin ) { if( offset < 0 || origin == FS_SEEK_END ) { Com_Error( ERR_FATAL, "Negative offsets and FS_SEEK_END not implemented " - "for FS_Seek on pk3 file contents\n" ); + "for FS_Seek on pk3 file contents" ); return -1; } @@ -1472,7 +1642,7 @@ int FS_Seek( fileHandle_t f, long offset, int origin ) { break; default: - Com_Error( ERR_FATAL, "Bad origin in FS_Seek\n" ); + Com_Error( ERR_FATAL, "Bad origin in FS_Seek" ); return -1; break; } @@ -1491,7 +1661,7 @@ int FS_Seek( fileHandle_t f, long offset, int origin ) { break; default: _origin = SEEK_CUR; - Com_Error( ERR_FATAL, "Bad origin in FS_Seek\n" ); + Com_Error( ERR_FATAL, "Bad origin in FS_Seek" ); break; } @@ -1515,11 +1685,11 @@ int FS_FileIsInPAK(const char *filename, int *pChecksum ) { long hash = 0; if ( !fs_searchpaths ) { - Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + Com_Error( ERR_FATAL, "Filesystem call made without initialization" ); } if ( !filename ) { - Com_Error( ERR_FATAL, "FS_FOpenFileRead: NULL 'filename' parameter passed\n" ); + Com_Error( ERR_FATAL, "FS_FOpenFileRead: NULL 'filename' parameter passed" ); } // qpaths are not supposed to have a leading slash @@ -1570,24 +1740,27 @@ int FS_FileIsInPAK(const char *filename, int *pChecksum ) { /* ============ -FS_ReadFile +FS_ReadFileDir Filename are relative to the quake search path a null buffer will just return the file length without loading +If searchPath is non-NULL search only in that specific search path ============ */ -int FS_ReadFile( const char *qpath, void **buffer ) { +long FS_ReadFileDir(const char *qpath, void *searchPath, void **buffer) +{ fileHandle_t h; + searchpath_t *search; byte* buf; qboolean isConfig; - int len; + long len; if ( !fs_searchpaths ) { - Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + Com_Error( ERR_FATAL, "Filesystem call made without initialization" ); } if ( !qpath || !qpath[0] ) { - Com_Error( ERR_FATAL, "FS_ReadFile with empty name\n" ); + Com_Error( ERR_FATAL, "FS_ReadFile with empty name" ); } buf = NULL; // quiet compiler warning @@ -1637,8 +1810,19 @@ int FS_ReadFile( const char *qpath, void **buffer ) { isConfig = qfalse; } - // look for it in the filesystem or pack files - len = FS_FOpenFileRead( qpath, &h, qfalse ); + search = searchPath; + + if(search == NULL) + { + // look for it in the filesystem or pack files + len = FS_FOpenFileRead(qpath, &h, qfalse); + } + else + { + // look for it in a specific search path only + len = FS_FOpenFileReadDir(qpath, search, &h, qfalse); + } + if ( h == 0 ) { if ( buffer ) { *buffer = NULL; @@ -1685,6 +1869,19 @@ int FS_ReadFile( const char *qpath, void **buffer ) { return len; } +/* +============ +FS_ReadFile + +Filename are relative to the quake search path +a null buffer will just return the file length without loading +============ +*/ +long FS_ReadFile(const char *qpath, void **buffer) +{ + return FS_ReadFileDir(qpath, NULL, buffer); +} + /* ============= FS_FreeFile @@ -1692,7 +1889,7 @@ FS_FreeFile */ void FS_FreeFile( void *buffer ) { if ( !fs_searchpaths ) { - Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + Com_Error( ERR_FATAL, "Filesystem call made without initialization" ); } if ( !buffer ) { Com_Error( ERR_FATAL, "FS_FreeFile( NULL )" ); @@ -1718,7 +1915,7 @@ void FS_WriteFile( const char *qpath, const void *buffer, int size ) { fileHandle_t f; if ( !fs_searchpaths ) { - Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + Com_Error( ERR_FATAL, "Filesystem call made without initialization" ); } if ( !qpath || !buffer ) { @@ -1975,7 +2172,7 @@ char **FS_ListFilteredFiles( const char *path, const char *extension, char *filt char zpath[MAX_ZPATH]; if ( !fs_searchpaths ) { - Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + Com_Error( ERR_FATAL, "Filesystem call made without initialization" ); } if ( !path ) { @@ -2106,7 +2303,7 @@ void FS_FreeFileList( char **list ) { int i; if ( !fs_searchpaths ) { - Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + Com_Error( ERR_FATAL, "Filesystem call made without initialization" ); } if ( !list ) { @@ -2539,6 +2736,33 @@ void FS_TouchFile_f( void ) { } } +/* +============ +FS_Which +============ +*/ + +qboolean FS_Which(const char *filename, void *searchPath) +{ + searchpath_t *search = searchPath; + + if(FS_FOpenFileReadDir(filename, search, NULL, qfalse) > 0) + { + if(search->pack) + { + Com_Printf("File \"%s\" found in \"%s\"\n", filename, search->pack->pakFilename); + return qtrue; + } + else if(search->dir) + { + Com_Printf( "File \"%s\" found at \"%s\"\n", filename, search->dir->fullpath); + return qtrue; + } + } + + return qfalse; +} + /* ============ FS_Which_f @@ -2546,16 +2770,8 @@ FS_Which_f */ void FS_Which_f( void ) { searchpath_t *search; - char *netpath; - pack_t *pak; - fileInPack_t *pakFile; - directory_t *dir; - long hash; - FILE *temp; - char *filename; - char buf[ MAX_OSPATH ]; + char *filename; - hash = 0; filename = Cmd_Argv(1); if ( !filename[0] ) { @@ -2569,40 +2785,13 @@ void FS_Which_f( void ) { } // just wants to see if file is there - for ( search = fs_searchpaths ; search ; search = search->next ) { - if ( search->pack ) { - hash = FS_HashFileName(filename, search->pack->hashSize); - } - // is the element a pak file? - if ( search->pack && search->pack->hashTable[hash] ) { - // look through all the pak file elements - pak = search->pack; - pakFile = pak->hashTable[hash]; - do { - // case and separator insensitive comparisons - if ( !FS_FilenameCompare( pakFile->name, filename ) ) { - // found it! - Com_Printf( "File \"%s\" found in \"%s\"\n", filename, pak->pakFilename ); - return; - } - pakFile = pakFile->next; - } while(pakFile != NULL); - } else if ( search->dir ) { - dir = search->dir; - - netpath = FS_BuildOSPath( dir->path, dir->gamedir, filename ); - temp = fopen (netpath, "rb"); - if ( !temp ) { - continue; - } - fclose(temp); - Com_sprintf( buf, sizeof( buf ), "%s/%s", dir->path, dir->gamedir ); - FS_ReplaceSeparators( buf ); - Com_Printf( "File \"%s\" found at \"%s\"\n", filename, buf ); + for(search = fs_searchpaths; search; search = search->next) + { + if(FS_Which(filename, search)) return; - } } - Com_Printf( "File not found: \"%s\"\n", filename ); + + Com_Printf("File not found: \"%s\"\n", filename); return; } @@ -2632,7 +2821,7 @@ void FS_AddGameDirectory( const char *path, const char *dir ) { int i; searchpath_t *search; pack_t *pak; - char *pakfile; + char curpath[MAX_OSPATH + 1], *pakfile; int numfiles; char **pakfiles; @@ -2645,22 +2834,11 @@ void FS_AddGameDirectory( const char *path, const char *dir ) { Q_strncpyz( fs_gamedir, dir, sizeof( fs_gamedir ) ); - // - // add the directory to the search path - // - search = Z_Malloc (sizeof(searchpath_t)); - search->dir = Z_Malloc( sizeof( *search->dir ) ); - - Q_strncpyz( search->dir->path, path, sizeof( search->dir->path ) ); - Q_strncpyz( search->dir->gamedir, dir, sizeof( search->dir->gamedir ) ); - search->next = fs_searchpaths; - fs_searchpaths = search; - // find all pak files in this directory - pakfile = FS_BuildOSPath( path, dir, "" ); - pakfile[ strlen(pakfile) - 1 ] = 0; // strip the trailing slash + Q_strncpyz(curpath, FS_BuildOSPath(path, dir, ""), sizeof(curpath)); + curpath[strlen(curpath) - 1] = '\0'; // strip the trailing slash - pakfiles = Sys_ListFiles( pakfile, ".pk3", NULL, &numfiles, qfalse ); + pakfiles = Sys_ListFiles(curpath, ".pk3", NULL, &numfiles, qfalse); qsort( pakfiles, numfiles, sizeof(char*), paksort ); @@ -2668,8 +2846,10 @@ void FS_AddGameDirectory( const char *path, const char *dir ) { pakfile = FS_BuildOSPath( path, dir, pakfiles[i] ); if ( ( pak = FS_LoadZipFile( pakfile, pakfiles[i] ) ) == 0 ) continue; + + Q_strncpyz(pak->pakPathname, curpath, sizeof(pak->pakPathname)); // store the game name for downloading - strcpy(pak->pakGamename, dir); + Q_strncpyz(pak->pakGamename, dir, sizeof(pak->pakGamename)); fs_packFiles += pak->numfiles; @@ -2681,6 +2861,19 @@ void FS_AddGameDirectory( const char *path, const char *dir ) { // done Sys_FreeFileList( pakfiles ); + + // + // add the directory to the search path + // + search = Z_Malloc (sizeof(searchpath_t)); + search->dir = Z_Malloc( sizeof( *search->dir ) ); + + Q_strncpyz(search->dir->path, path, sizeof(search->dir->path)); + Q_strncpyz(search->dir->fullpath, curpath, sizeof(search->dir->fullpath)); + Q_strncpyz(search->dir->gamedir, dir, sizeof(search->dir->gamedir)); + + search->next = fs_searchpaths; + fs_searchpaths = search; } /* @@ -2766,7 +2959,7 @@ qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring ) { // never autodownload any of the id paks if(FS_idPak(fs_serverReferencedPakNames[i], BASEGAME, NUM_ID_PAKS) #ifndef STANDALONE - || FS_idPak(fs_serverReferencedPakNames[i], BASETA, NUM_TA_PAKS) + || FS_idPak(fs_serverReferencedPakNames[i], BASETA, NUM_TA_PAKS) #endif ) { @@ -3054,7 +3247,6 @@ Q3 media pak0.pk3, you'll want to remove this by defining STANDALONE in q_shared.h =================== */ -/* JBravo - Not static void FS_CheckPak0( void ) { searchpath_t *path; @@ -3239,7 +3431,6 @@ static void FS_CheckPak0( void ) Com_Error(ERR_FATAL, "%s", errorText); } } -*/ #endif /* @@ -3601,15 +3792,18 @@ void FS_InitFilesystem( void ) { // we have to specially handle this, because normal command // line variable sets don't happen until after the filesystem // has already been initialized - Com_StartupVariable( "fs_basepath" ); - Com_StartupVariable( "fs_homepath" ); - Com_StartupVariable( "fs_game" ); + Com_StartupVariable("fs_basepath"); + Com_StartupVariable("fs_homepath"); + Com_StartupVariable("fs_game"); + + if(!FS_FilenameCompare(Cvar_VariableString("fs_game"), com_basegame->string)) + Cvar_Set("fs_game", ""); // try to start up normally FS_Startup(com_basegame->string); #ifndef STANDALONE -// FS_CheckPak0( ); + FS_CheckPak0( ); #endif // if we can't find default.cfg, assume that the paths are @@ -3644,7 +3838,7 @@ void FS_Restart( int checksumFeed ) { FS_Startup(com_basegame->string); #ifndef STANDALONE -// FS_CheckPak0( ); + FS_CheckPak0( ); #endif // if we can't find default.cfg, assume that the paths are @@ -3660,7 +3854,7 @@ void FS_Restart( int checksumFeed ) { lastValidBase[0] = '\0'; lastValidGame[0] = '\0'; FS_Restart(checksumFeed); - Com_Error( ERR_DROP, "Invalid game folder\n" ); + Com_Error( ERR_DROP, "Invalid game folder" ); return; } Com_Error( ERR_FATAL, "Couldn't load default.cfg" ); @@ -3684,19 +3878,16 @@ FS_ConditionalRestart restart if necessary ================= */ -qboolean FS_ConditionalRestart(int checksumFeed) +qboolean FS_ConditionalRestart(int checksumFeed, qboolean disconnect) { if(fs_gamedirvar->modified) { - Com_GameRestart(checksumFeed, qfalse); + Com_GameRestart(checksumFeed, disconnect); return qtrue; } else if(checksumFeed != fs_checksumFeed) - { FS_Restart(checksumFeed); - return qtrue; - } return qfalse; } @@ -3803,7 +3994,7 @@ void FS_FilenameCompletion( const char *dir, const char *ext, const char *FS_GetCurrentGameDir(void) { if(fs_gamedirvar->string[0]) - return fs_gamedirvar->string; + return fs_gamedirvar->string; - return com_basegame->string; + return com_basegame->string; } diff --git a/reaction/code/qcommon/huffman.c b/reaction/code/qcommon/huffman.c index 2ff4ae50..8a5fa507 100644 --- a/reaction/code/qcommon/huffman.c +++ b/reaction/code/qcommon/huffman.c @@ -273,7 +273,7 @@ int Huff_Receive (node_t *node, int *ch, byte *fin) { } if (!node) { return 0; -// Com_Error(ERR_DROP, "Illegal tree!\n"); +// Com_Error(ERR_DROP, "Illegal tree!"); } return (*ch = node->symbol); } @@ -291,7 +291,7 @@ void Huff_offsetReceive (node_t *node, int *ch, byte *fin, int *offset) { if (!node) { *ch = 0; return; -// Com_Error(ERR_DROP, "Illegal tree!\n"); +// Com_Error(ERR_DROP, "Illegal tree!"); } *ch = node->symbol; *offset = bloc; diff --git a/reaction/code/qcommon/msg.c b/reaction/code/qcommon/msg.c index cf60aec1..9916b1b3 100644 --- a/reaction/code/qcommon/msg.c +++ b/reaction/code/qcommon/msg.c @@ -155,7 +155,7 @@ void MSG_WriteBits( msg_t *msg, int value, int bits ) { msg->cursize += 4; msg->bit += 32; } else { - Com_Error(ERR_DROP, "can't read %d bits\n", bits); + Com_Error(ERR_DROP, "can't read %d bits", bits); } } else { // fp = fopen("c:\\netchan.bin", "a"); @@ -213,7 +213,7 @@ int MSG_ReadBits( msg_t *msg, int bits ) { msg->readcount += 4; msg->bit += 32; } else { - Com_Error(ERR_DROP, "can't read %d bits\n", bits); + Com_Error(ERR_DROP, "can't read %d bits", bits); } } else { nbits = 0; diff --git a/reaction/code/qcommon/net_ip.c b/reaction/code/qcommon/net_ip.c index fe5c8da6..f6f45a25 100644 --- a/reaction/code/qcommon/net_ip.c +++ b/reaction/code/qcommon/net_ip.c @@ -63,11 +63,11 @@ static qboolean winsockInitialized = qfalse; # define _BSD_SOCKLEN_T_ # endif -# include +# include # include # include # include -# include +# include # include # include # include @@ -1290,6 +1290,8 @@ static void NET_GetLocalAddress(void) { struct ifaddrs *ifap, *search; + numIP = 0; + if(getifaddrs(&ifap)) Com_Printf("NET_GetLocalAddress: Unable to get list of network interfaces: %s\n", NET_ErrorString()); else @@ -1312,6 +1314,8 @@ static void NET_GetLocalAddress( void ) { struct addrinfo hint; struct addrinfo *res = NULL; + numIP = 0; + if(gethostname( hostname, 256 ) == SOCKET_ERROR) return; diff --git a/reaction/code/qcommon/q_math.c b/reaction/code/qcommon/q_math.c index 97e6efbc..40d8c36a 100644 --- a/reaction/code/qcommon/q_math.c +++ b/reaction/code/qcommon/q_math.c @@ -829,10 +829,12 @@ vec_t VectorNormalize( vec3_t v ) { float length, ilength; length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; - length = sqrt (length); if ( length ) { - ilength = 1/length; + /* writing it this way allows gcc to recognize that rsqrt can be used */ + ilength = 1/(float)sqrt (length); + /* sqrt(length) = length * (1 / sqrt(length)) */ + length *= ilength; v[0] *= ilength; v[1] *= ilength; v[2] *= ilength; @@ -845,11 +847,13 @@ vec_t VectorNormalize2( const vec3_t v, vec3_t out) { float length, ilength; length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; - length = sqrt (length); if (length) { - ilength = 1/length; + /* writing it this way allows gcc to recognize that rsqrt can be used */ + ilength = 1/(float)sqrt (length); + /* sqrt(length) = length * (1 / sqrt(length)) */ + length *= ilength; out[0] = v[0]*ilength; out[1] = v[1]*ilength; out[2] = v[2]*ilength; diff --git a/reaction/code/qcommon/q_platform.h b/reaction/code/qcommon/q_platform.h index 1be979ad..4477673d 100644 --- a/reaction/code/qcommon/q_platform.h +++ b/reaction/code/qcommon/q_platform.h @@ -24,6 +24,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define __Q_PLATFORM_H // this is for determining if we have an asm version of a C function +#define idx64 0 + #ifdef Q3_VM #define id386 0 @@ -76,6 +78,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #if defined(_WIN64) || defined(__WIN64__) +#undef idx64 +#define idx64 1 + #undef QDECL #define QDECL __cdecl @@ -85,7 +90,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define OS_STRING "win_mingw64" #endif -#define ID_INLINE inline +#define ID_INLINE __inline #define PATH_SEP '\\' #if defined( __WIN64__ ) @@ -144,6 +149,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define ARCH_STRING "i386" #define Q3_LITTLE_ENDIAN #elif defined __x86_64__ +#undef idx64 +#define idx64 1 #define ARCH_STRING "x86_64" #define Q3_LITTLE_ENDIAN #endif @@ -170,6 +177,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #if defined __i386__ #define ARCH_STRING "i386" #elif defined __x86_64__ +#undef idx64 +#define idx64 1 #define ARCH_STRING "x86_64" #elif defined __powerpc64__ #define ARCH_STRING "ppc64" @@ -232,6 +241,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #ifdef __i386__ #define ARCH_STRING "i386" #elif defined __amd64__ +#undef idx64 +#define idx64 1 #define ARCH_STRING "amd64" #elif defined __axp__ #define ARCH_STRING "alpha" diff --git a/reaction/code/qcommon/q_shared.c b/reaction/code/qcommon/q_shared.c index 36261335..2cae73df 100644 --- a/reaction/code/qcommon/q_shared.c +++ b/reaction/code/qcommon/q_shared.c @@ -58,20 +58,13 @@ char *COM_SkipPath (char *pathname) COM_GetExtension ============ */ -const char *COM_GetExtension( const char *name ) { - int length, i; - - length = strlen(name)-1; - i = length; - - while (name[i] != '.') - { - i--; - if (name[i] == '/' || i == 0) - return ""; // no extension - } - - return &name[i+1]; +const char *COM_GetExtension( const char *name ) +{ + const char *dot = strrchr(name, '.'), *slash; + if (dot && (!(slash = strrchr(name, '/')) || slash < dot)) + return dot + 1; + else + return ""; } @@ -80,47 +73,31 @@ const char *COM_GetExtension( const char *name ) { COM_StripExtension ============ */ -void COM_StripExtension( const char *in, char *out, int destsize ) { - int length; - - Q_strncpyz(out, in, destsize); - - length = strlen(out)-1; - while (length > 0 && out[length] != '.') - { - length--; - if (out[length] == '/') - return; // no extension - } - if (length) - out[length] = 0; +void COM_StripExtension( const char *in, char *out, int destsize ) +{ + const char *dot = strrchr(in, '.'), *slash; + if (dot && (!(slash = strrchr(in, '/')) || slash < dot)) + Q_strncpyz(out, in, (destsize < dot-in+1 ? destsize : dot-in+1)); + else + Q_strncpyz(out, in, destsize); } /* ================== COM_DefaultExtension + +if path doesn't have an extension, then append + the specified one (which should include the .) ================== */ -void COM_DefaultExtension (char *path, int maxSize, const char *extension ) { - char oldPath[MAX_QPATH]; - char *src; - -// -// if path doesn't have a .EXT, append extension -// (extension should include the .) -// - src = path + strlen(path) - 1; - - while (*src != '/' && src != path) { - if ( *src == '.' ) { - return; // it has an extension - } - src--; - } - - Q_strncpyz( oldPath, path, sizeof( oldPath ) ); - Com_sprintf( path, maxSize, "%s%s", oldPath, extension ); +void COM_DefaultExtension( char *path, int maxSize, const char *extension ) +{ + const char *dot = strrchr(path, '.'), *slash; + if (dot && (!(slash = strrchr(path, '/')) || slash < dot)) + return; + else + Q_strcat(path, maxSize, extension); } /* @@ -683,26 +660,6 @@ int Q_isalpha( int c ) return ( 0 ); } -char* Q_strrchr( const char* string, int c ) -{ - char cc = c; - char *s; - char *sp=(char *)0; - - s = (char*)string; - - while (*s) - { - if (*s == cc) - sp = s; - s++; - } - if (cc == 0) - sp = s; - - return sp; -} - qboolean Q_isanumber( const char *s ) { char *p; @@ -972,7 +929,7 @@ void QDECL Com_sprintf(char *dest, int size, const char *fmt, ...) va_end (argptr); if(len >= size) - Com_Printf("Com_sprintf: Output length %d too short, require %d bytes.\n", size, len); + Com_Printf("Com_sprintf: Output length %d too short, require %d bytes.\n", size, len + 1); } /* diff --git a/reaction/code/qcommon/q_shared.h b/reaction/code/qcommon/q_shared.h index b582e7cb..91a01e49 100644 --- a/reaction/code/qcommon/q_shared.h +++ b/reaction/code/qcommon/q_shared.h @@ -34,6 +34,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define GAMENAME_FOR_MASTER "Reaction" // must NOT contain whitespaces #define HEARTBEAT_FOR_MASTER GAMENAME_FOR_MASTER #define FLATLINE_FOR_MASTER GAMENAME_FOR_MASTER "dead" + #define HOMEPATH_NAME_UNIX ".Reaction" + #define HOMEPATH_NAME_WIN "Reaction" + #define HOMEPATH_NAME_MACOSX HOMEPATH_NAME_WIN #else #define PRODUCT_NAME "Reaction" #define BASEGAME "Boomstick" @@ -42,12 +45,15 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define GAMENAME_FOR_MASTER "Reaction" #define HEARTBEAT_FOR_MASTER "Reaction-1" #define FLATLINE_FOR_MASTER HEARTBEAT_FOR_MASTER + #define HOMEPATH_NAME_UNIX ".Reaction" + #define HOMEPATH_NAME_WIN "Reaction" + #define HOMEPATH_NAME_MACOSX HOMEPATH_NAME_WIN #endif #define BASETA "missionpack" #ifdef _MSC_VER - #define PRODUCT_VERSION "1.35" + #define PRODUCT_VERSION "1.36" #endif #define Q3_VERSION PRODUCT_NAME " " PRODUCT_VERSION @@ -55,6 +61,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define MAX_TEAMNAME 32 #define MAX_MASTER_SERVERS 5 // number of supported master servers +#define DEMOEXT "dm_" // standard demo extension + #ifdef _MSC_VER #pragma warning(disable : 4018) // signed/unsigned mismatch @@ -175,8 +183,10 @@ typedef int sfxHandle_t; typedef int fileHandle_t; typedef int clipHandle_t; -#define PAD(x,y) (((x)+(y)-1) & ~((y)-1)) -#define PADLEN(x,y) (PAD((x), (y)) - (x)) +#define PAD(base, alignment) (((base)+(alignment)-1) & ~((alignment)-1)) +#define PADLEN(base, alignment) (PAD((base), (alignment)) - (base)) + +#define PADP(base, alignment) ((void *) PAD((intptr_t) (base), (alignment))) #ifdef __GNUC__ #define QALIGN(x) __attribute__((aligned(x))) @@ -420,6 +430,58 @@ extern vec3_t axisDefault[3]; #define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask) +int Q_isnan(float x); + +#if idx64 + extern long qftolsse(float f); + extern int qvmftolsse(void); + extern void qsnapvectorsse(vec3_t vec); + + #define Q_ftol qftolsse + #define Q_SnapVector qsnapvectorsse + + extern int (*Q_VMftol)(void); +#elif id386 + extern long QDECL qftolx87(float f); + extern long QDECL qftolsse(float f); + extern int QDECL qvmftolx87(void); + extern int QDECL qvmftolsse(void); + extern void QDECL qsnapvectorx87(vec3_t vec); + extern void QDECL qsnapvectorsse(vec3_t vec); + + extern long (QDECL *Q_ftol)(float f); + extern int (QDECL *Q_VMftol)(void); + extern void (QDECL *Q_SnapVector)(vec3_t vec); +#else + #define Q_ftol(f) lrintf((f)) + #define Q_SnapVector(vec)\ + do\ + {\ + vec3_t *temp = (vec);\ + \ + (*temp)[0] = round((*temp)[0]);\ + (*temp)[1] = round((*temp)[1]);\ + (*temp)[2] = round((*temp)[2]);\ + } while(0) +#endif +/* +// if your system does not have lrintf() and round() you can try this block. Please also open a bug report at bugzilla.icculus.org +// or write a mail to the ioq3 mailing list. +#else + #define Q_ftol(v) ((long) (v)) + #define Q_round(v) do { if((v) < 0) (v) -= 0.5f; else (v) += 0.5f; (v) = Q_ftol((v)); } while(0) + #define Q_SnapVector(vec) \ + do\ + {\ + vec3_t *temp = (vec);\ + \ + Q_round((*temp)[0]);\ + Q_round((*temp)[1]);\ + Q_round((*temp)[2]);\ + } while(0) +#endif +*/ + #if idppc static ID_INLINE float Q_rsqrt( float number ) { @@ -494,6 +556,8 @@ typedef struct { #define VectorSet(v, x, y, z) ((v)[0]=(x), (v)[1]=(y), (v)[2]=(z)) #define Vector4Copy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3]) +#define Byte4Copy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3]) + //Makro - for the UI #define Vector2Copy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1]) #define Vector2MA(v,s,b,o) ((o)[0]=(v)[0]+(b)[0]*(s),(o)[1]=(v)[1]+(b)[1]*(s)) @@ -650,7 +714,6 @@ void MatrixMultiply(float in1[3][3], float in2[3][3], float out[3][3]); void AngleVectors( const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); void PerpendicularVector( vec3_t dst, const vec3_t src ); int ReflectVectorByte( vec3_t dir, vec3_t plane ); -int Q_isnan( float x ); // Makro - added void ChangeRefSystem(vec3_t in, vec3_t neworg, vec3_t newaxis[], vec3_t out); @@ -661,6 +724,14 @@ void ChangeAngleRefSystem(vec3_t in, vec3_t newaxis[], vec3_t out); #define is_digit(c) ((unsigned)to_digit(c) <= 9) #define to_digit(c) ((c) - '0') +#ifndef MAX +#define MAX(x,y) ((x)>(y)?(x):(y)) +#endif + +#ifndef MIN +#define MIN(x,y) ((x)<(y)?(x):(y)) +#endif + //============================================= float Com_Clamp( float min, float max, float value ); @@ -747,7 +818,6 @@ int Q_strncmp (const char *s1, const char *s2, int n); int Q_stricmpn (const char *s1, const char *s2, int n); char *Q_strlwr( char *s1 ); char *Q_strupr( char *s1 ); -char *Q_strrchr( const char* string, int c ); const char *Q_stristr( const char *s, const char *find); // buffer size safe library replacements diff --git a/reaction/code/qcommon/qcommon.h b/reaction/code/qcommon/qcommon.h index 300d536f..67b6aa13 100644 --- a/reaction/code/qcommon/qcommon.h +++ b/reaction/code/qcommon/qcommon.h @@ -242,9 +242,6 @@ PROTOCOL ============================================================== */ -// Makro - this wasn't defined anywhere... -#define DEMOEXT "dm" - #define PROTOCOL_VERSION 68 // 1.31 - 67 @@ -507,6 +504,9 @@ void Cvar_Update( vmCvar_t *vmCvar ); void Cvar_Set( const char *var_name, const char *value ); // will create the variable with no flags if it doesn't exist +cvar_t *Cvar_Set2(const char *var_name, const char *value, qboolean force); +// same as Cvar_Set, but allows more control over setting of cvar + void Cvar_SetSafe( const char *var_name, const char *value ); // sometimes we set variables from an untrusted source: fail if flags & CVAR_PROTECTED @@ -600,7 +600,7 @@ qboolean FS_Initialized( void ); void FS_InitFilesystem ( void ); void FS_Shutdown( qboolean closemfp ); -qboolean FS_ConditionalRestart( int checksumFeed ); +qboolean FS_ConditionalRestart(int checksumFeed, qboolean disconnect); void FS_Restart( int checksumFeed ); // shutdown and restart the filesystem so changes to fs_gamedir can take effect @@ -617,7 +617,7 @@ qboolean FS_FileExists( const char *file ); qboolean FS_CreatePath (char *OSPath); -char *FS_FindDll( const char *filename ); +vmInterpret_t FS_FindVM(void **startSearch, char *found, int foundlen, const char *name, int enableDll); char *FS_BuildOSPath( const char *base, const char *game, const char *qpath ); qboolean FS_CompareZipChecksum(const char *zipfile); @@ -633,9 +633,9 @@ fileHandle_t FS_FCreateOpenPipeFile( const char *filename ); // will properly create any needed paths and deal with seperater character issues fileHandle_t FS_SV_FOpenFileWrite( const char *filename ); -int FS_SV_FOpenFileRead( const char *filename, fileHandle_t *fp ); +long FS_SV_FOpenFileRead( const char *filename, fileHandle_t *fp ); void FS_SV_Rename( const char *from, const char *to ); -int FS_FOpenFileRead( const char *qpath, fileHandle_t *file, qboolean uniqueFILE ); +long FS_FOpenFileRead( const char *qpath, fileHandle_t *file, qboolean uniqueFILE ); // if uniqueFILE is true, then a new FILE will be fopened even if the file // is found in an already open pak file. If uniqueFILE is false, you must call // FS_FCloseFile instead of fclose, otherwise the pak FILE would be improperly closed @@ -654,7 +654,8 @@ int FS_Read( void *buffer, int len, fileHandle_t f ); void FS_FCloseFile( fileHandle_t f ); // note: you can't just fclose from another DLL, due to MS libc issues -int FS_ReadFile( const char *qpath, void **buffer ); +long FS_ReadFileDir(const char *qpath, void *searchPath, void **buffer); +long FS_ReadFile(const char *qpath, void **buffer); // returns the length of the file // a null buffer will just return the file length without loading // as a quick check for existance. -1 length == not present @@ -671,7 +672,7 @@ void FS_FreeFile( void *buffer ); void FS_WriteFile( const char *qpath, const void *buffer, int size ); // writes a complete file, creating any subdirectories needed -int FS_filelength( fileHandle_t f ); +long FS_filelength(fileHandle_t f); // doesn't work for files that are opened from a pack file int FS_FTell( fileHandle_t f ); @@ -729,6 +730,7 @@ void FS_FilenameCompletion( const char *dir, const char *ext, qboolean stripExt, void(*callback)(const char *s), qboolean allowNonPureFilesOnDisk ); const char *FS_GetCurrentGameDir(void); +qboolean FS_Which(const char *filename, void *searchPath); /* ============================================================== @@ -814,7 +816,7 @@ void QDECL Com_Printf( const char *fmt, ... ) __attribute__ ((format (printf, void QDECL Com_DPrintf( const char *fmt, ... ) __attribute__ ((format (printf, 1, 2))); void QDECL Com_Error( int code, const char *fmt, ... ) __attribute__ ((format (printf, 2, 3))); void Com_Quit_f( void ); -void Com_GameRestart(int checksumFeed, qboolean clientRestart); +void Com_GameRestart(int checksumFeed, qboolean disconnect); int Com_Milliseconds( void ); // will be journaled properly unsigned Com_BlockChecksum( const void *buffer, int length ); @@ -869,6 +871,7 @@ extern int time_backend; // renderer backend time extern int com_frameTime; extern qboolean com_errorEntered; +extern qboolean com_fullyInitialized; extern fileHandle_t com_journalFile; extern fileHandle_t com_journalDataFile; @@ -958,7 +961,7 @@ void CL_InitKeyCommands( void ); void CL_Init( void ); void CL_Disconnect( qboolean showMainMenu ); -void CL_Shutdown( char *finalmsg ); +void CL_Shutdown(char *finalmsg, qboolean disconnect); void CL_Frame( int msec ); qboolean CL_GameCommand( void ); void CL_KeyEvent (int key, qboolean down, unsigned time); @@ -988,16 +991,19 @@ void CL_ForwardCommandToServer( const char *string ); void CL_CDDialog( void ); // bring up the "need a cd to play" dialog -void CL_ShutdownAll( void ); -// shutdown all the client stuff - void CL_FlushMemory( void ); // dump all memory on an error +void CL_ShutdownAll(qboolean shutdownRef); +// shutdown client + +void CL_InitRef(void); +// initialize renderer interface + void CL_StartHunkUsers( qboolean rendererOnly ); // start all the client stuff using the hunk -void CL_Snd_Restart(void); +void CL_Snd_Shutdown(void); // Restart sound subsystem void Key_KeynameCompletion( void(*callback)(const char *s) ); diff --git a/reaction/code/qcommon/qfiles.h b/reaction/code/qcommon/qfiles.h index 8a596041..cc4ba816 100644 --- a/reaction/code/qcommon/qfiles.h +++ b/reaction/code/qcommon/qfiles.h @@ -35,7 +35,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #endif // surface geometry should not exceed these limits -#define SHADER_MAX_VERTEXES 1000 +#define SHADER_MAX_VERTEXES 4225 #define SHADER_MAX_INDEXES (6*SHADER_MAX_VERTEXES) #define SHADER_MAX_TRIANGLES (SHADER_MAX_INDEXES / 3) diff --git a/reaction/code/qcommon/vm.c b/reaction/code/qcommon/vm.c index d3fb85bc..292824d0 100644 --- a/reaction/code/qcommon/vm.c +++ b/reaction/code/qcommon/vm.c @@ -377,15 +377,20 @@ vmHeader_t *VM_LoadQVM( vm_t *vm, qboolean alloc ) { // load the image Com_sprintf( filename, sizeof(filename), "vm/%s.qvm", vm->name ); Com_Printf( "Loading vm file %s...\n", filename ); - length = FS_ReadFile( filename, &header.v ); + + length = FS_ReadFileDir(filename, vm->searchPath, &header.v); + if ( !header.h ) { Com_Printf( "Failed.\n" ); VM_Free( vm ); + + Com_Printf(S_COLOR_YELLOW "Warning: Couldn't open VM file %s\n", filename); + return NULL; } // show where the qvm was loaded from - Cmd_ExecuteString( va( "which %s\n", filename ) ); + FS_Which(filename, vm->searchPath); if( LittleLong( header.h->vmMagic ) == VM_MAGIC_VER2 ) { Com_Printf( "...which has vmMagic VM_MAGIC_VER2\n" ); @@ -400,9 +405,13 @@ vmHeader_t *VM_LoadQVM( vm_t *vm, qboolean alloc ) { || header.h->bssLength < 0 || header.h->dataLength < 0 || header.h->litLength < 0 - || header.h->codeLength <= 0 ) { - VM_Free( vm ); - Com_Error( ERR_FATAL, "%s has bad header", filename ); + || header.h->codeLength <= 0 ) + { + VM_Free(vm); + FS_FreeFile(header.v); + + Com_Printf(S_COLOR_YELLOW "Warning: %s has bad header\n", filename); + return NULL; } } else if( LittleLong( header.h->vmMagic ) == VM_MAGIC ) { // byte swap the header @@ -415,14 +424,21 @@ vmHeader_t *VM_LoadQVM( vm_t *vm, qboolean alloc ) { if ( header.h->bssLength < 0 || header.h->dataLength < 0 || header.h->litLength < 0 - || header.h->codeLength <= 0 ) { - VM_Free( vm ); - Com_Error( ERR_FATAL, "%s has bad header", filename ); + || header.h->codeLength <= 0 ) + { + VM_Free(vm); + FS_FreeFile(header.v); + + Com_Printf(S_COLOR_YELLOW "Warning: %s has bad header\n", filename); + return NULL; } } else { VM_Free( vm ); - Com_Error( ERR_FATAL, "%s does not have a recognisable " - "magic number in its header", filename ); + FS_FreeFile(header.v); + + Com_Printf(S_COLOR_YELLOW "Warning: %s does not have a recognisable " + "magic number in its header\n", filename); + return NULL; } // round up to next power of 2 so all data operations can @@ -502,7 +518,7 @@ vm_t *VM_Restart( vm_t *vm ) { Com_Printf( "VM_Restart()\n" ); if( !( header = VM_LoadQVM( vm, qfalse ) ) ) { - Com_Error( ERR_DROP, "VM_Restart failed.\n" ); + Com_Error( ERR_DROP, "VM_Restart failed" ); return NULL; } @@ -524,7 +540,9 @@ vm_t *VM_Create( const char *module, intptr_t (*systemCalls)(intptr_t *), vmInterpret_t interpret ) { vm_t *vm; vmHeader_t *header; - int i, remaining; + int i, remaining, retval; + char filename[MAX_OSPATH]; + void *startSearch = NULL; if ( !module || !module[0] || !systemCalls ) { Com_Error( ERR_FATAL, "VM_Create: bad parms" ); @@ -553,29 +571,45 @@ vm_t *VM_Create( const char *module, intptr_t (*systemCalls)(intptr_t *), vm = &vmTable[i]; - Q_strncpyz( vm->name, module, sizeof( vm->name ) ); - vm->systemCall = systemCalls; + Q_strncpyz(vm->name, module, sizeof(vm->name)); - if ( interpret == VMI_NATIVE ) { - // try to load as a system dll - Com_Printf( "Loading dll file %s.\n", vm->name ); - vm->dllHandle = Sys_LoadDll( module, &vm->entryPoint, VM_DllSyscall ); - if ( vm->dllHandle ) { - return vm; + do + { + retval = FS_FindVM(&startSearch, filename, sizeof(filename), module, (interpret == VMI_NATIVE)); + + if(retval == VMI_NATIVE) + { + Com_Printf("Try loading dll file %s\n", filename); + + vm->dllHandle = Sys_LoadDll(filename, &vm->entryPoint, VM_DllSyscall); + + if(vm->dllHandle) + { + vm->systemCall = systemCalls; + return vm; + } + + Com_Printf("Failed loading dll, trying next\n"); } + else if(retval == VMI_COMPILED) + { + vm->searchPath = startSearch; + if((header = VM_LoadQVM(vm, qtrue))) + break; - Com_Printf( "Failed to load dll, looking for qvm.\n" ); - interpret = VMI_COMPILED; - } - - // load the image - if( !( header = VM_LoadQVM( vm, qtrue ) ) ) { + // VM_Free overwrites the name on failed load + Q_strncpyz(vm->name, module, sizeof(vm->name)); + } + } while(retval >= 0); + + if(retval < 0) return NULL; - } + + vm->systemCall = systemCalls; // allocate space for the jump targets, which will be filled in by the compile/prep functions vm->instructionCount = header->instructionCount; - vm->instructionPointers = Hunk_Alloc( vm->instructionCount*4, h_high ); + vm->instructionPointers = Hunk_Alloc(vm->instructionCount * sizeof(*vm->instructionPointers), h_high); // copy or compile the instructions vm->codeLength = header->codeLength; @@ -588,7 +622,8 @@ vm_t *VM_Create( const char *module, intptr_t (*systemCalls)(intptr_t *), interpret = VMI_BYTECODE; } #else - if ( interpret >= VMI_COMPILED ) { + if(interpret != VMI_BYTECODE) + { vm->compiled = qtrue; VM_Compile( vm, header ); } @@ -914,3 +949,25 @@ void VM_LogSyscalls( int *args ) { fprintf(f, "%i: %p (%i) = %i %i %i %i\n", callnum, (void*)(args - (int *)currentVM->dataBase), args[0], args[1], args[2], args[3], args[4] ); } + +/* +================= +VM_BlockCopy +Executes a block copy operation within currentVM data space +================= +*/ + +void VM_BlockCopy(unsigned int dest, unsigned int src, size_t n) +{ + unsigned int dataMask = currentVM->dataMask; + + if ((dest & dataMask) != dest + || (src & dataMask) != src + || ((dest + n) & dataMask) != dest + n + || ((src + n) & dataMask) != src + n) + { + Com_Error(ERR_DROP, "OP_BLOCK_COPY out of range!"); + } + + Com_Memcpy(currentVM->dataBase + dest, currentVM->dataBase + src, n); +} diff --git a/reaction/code/qcommon/vm_interpreted.c b/reaction/code/qcommon/vm_interpreted.c index abe24729..7ff0e16a 100644 --- a/reaction/code/qcommon/vm_interpreted.c +++ b/reaction/code/qcommon/vm_interpreted.c @@ -192,9 +192,8 @@ void VM_PrepareInterpreter( vm_t *vm, vmHeader_t *header ) { op = (int)code[ byte_pc ]; codeBase[int_pc] = op; - if ( byte_pc > header->codeLength ) { - Com_Error( ERR_FATAL, "VM_PrepareInterpreter: pc > header->codeLength" ); - } + if(byte_pc > header->codeLength) + Com_Error(ERR_DROP, "VM_PrepareInterpreter: pc > header->codeLength"); byte_pc++; int_pc++; @@ -265,6 +264,9 @@ void VM_PrepareInterpreter( vm_t *vm, vmHeader_t *header ) { case OP_LEF: case OP_GTF: case OP_GEF: + if(codeBase[int_pc] < 0 || codeBase[int_pc] > vm->instructionCount) + Com_Error(ERR_DROP, "VM_PrepareInterpreter: Jump to invalid instruction number"); + // codeBase[pc] is the instruction index. Convert that into an offset into //the int-aligned codeBase[] by the lookup table. codeBase[int_pc] = vm->instructionPointers[codeBase[int_pc]]; @@ -312,11 +314,12 @@ locals from sp ============== */ -#define DEBUGSTR va("%s%i", VM_Indent(vm), opStack-stack ) +#define DEBUGSTR va("%s%i", VM_Indent(vm), opStackOfs) int VM_CallInterpreted( vm_t *vm, int *args ) { - int stack[OPSTACK_SIZE]; - int *opStack; + byte stack[OPSTACK_SIZE + 15]; + register int *opStack; + register uint8_t opStackOfs; int programCounter; int programStack; int stackOnEntry; @@ -345,10 +348,6 @@ int VM_CallInterpreted( vm_t *vm, int *args ) { codeImage = (int *)vm->codeBase; dataMask = vm->dataMask; - // leave a free spot at start of stack so - // that as long as opStack is valid, opStack-1 will - // not corrupt anything - opStack = stack; programCounter = 0; programStack -= 48; @@ -368,6 +367,13 @@ int VM_CallInterpreted( vm_t *vm, int *args ) { VM_Debug(0); + // leave a free spot at start of stack so + // that as long as opStack is valid, opStack-1 will + // not corrupt anything + opStack = PADP(stack, 16); + *opStack = 0xDEADBEEF; + opStackOfs = 0; + // vm_debugLevel=2; // main interpreter loop, will exit when a LEAVE instruction // grabs the -1 program counter @@ -379,27 +385,23 @@ int VM_CallInterpreted( vm_t *vm, int *args ) { // unsigned int r2; nextInstruction: - r0 = ((int *)opStack)[0]; - r1 = ((int *)opStack)[-1]; + r0 = opStack[opStackOfs]; + r1 = opStack[(uint8_t) (opStackOfs - 1)]; nextInstruction2: #ifdef DEBUG_VM if ( (unsigned)programCounter >= vm->codeLength ) { Com_Error( ERR_DROP, "VM pc out of range" ); - } - - if ( opStack < stack ) { - Com_Error( ERR_DROP, "VM opStack underflow" ); - } - if ( opStack >= stack+OPSTACK_SIZE ) { - Com_Error( ERR_DROP, "VM opStack overflow" ); + return 0; } if ( programStack <= vm->stackBottom ) { Com_Error( ERR_DROP, "VM stack overflow" ); + return 0; } if ( programStack & 3 ) { Com_Error( ERR_DROP, "VM program stack misaligned" ); + return 0; } if ( vm_debugLevel > 1 ) { @@ -413,79 +415,67 @@ nextInstruction2: #ifdef DEBUG_VM default: Com_Error( ERR_DROP, "Bad VM instruction" ); // this should be scanned on load! + return 0; #endif case OP_BREAK: vm->breakCount++; goto nextInstruction2; case OP_CONST: - opStack++; + opStackOfs++; r1 = r0; - r0 = *opStack = r2; + r0 = opStack[opStackOfs] = r2; programCounter += 1; goto nextInstruction2; case OP_LOCAL: - opStack++; + opStackOfs++; r1 = r0; - r0 = *opStack = r2+programStack; + r0 = opStack[opStackOfs] = r2+programStack; programCounter += 1; goto nextInstruction2; case OP_LOAD4: #ifdef DEBUG_VM - if ( *opStack & 3 ) { + if(opStack[opStackOfs] & 3) + { Com_Error( ERR_DROP, "OP_LOAD4 misaligned" ); + return 0; } #endif - r0 = *opStack = *(int *)&image[ r0&dataMask&~3 ]; + r0 = opStack[opStackOfs] = *(int *) &image[r0 & dataMask & ~3 ]; goto nextInstruction2; case OP_LOAD2: - r0 = *opStack = *(unsigned short *)&image[ r0&dataMask&~1 ]; + r0 = opStack[opStackOfs] = *(unsigned short *)&image[ r0&dataMask&~1 ]; goto nextInstruction2; case OP_LOAD1: - r0 = *opStack = image[ r0&dataMask ]; + r0 = opStack[opStackOfs] = image[ r0&dataMask ]; goto nextInstruction2; case OP_STORE4: *(int *)&image[ r1&(dataMask & ~3) ] = r0; - opStack -= 2; + opStackOfs -= 2; goto nextInstruction; case OP_STORE2: *(short *)&image[ r1&(dataMask & ~1) ] = r0; - opStack -= 2; + opStackOfs -= 2; goto nextInstruction; case OP_STORE1: image[ r1&dataMask ] = r0; - opStack -= 2; + opStackOfs -= 2; goto nextInstruction; case OP_ARG: // single byte offset from programStack *(int *)&image[ (codeImage[programCounter] + programStack)&dataMask&~3 ] = r0; - opStack--; + opStackOfs--; programCounter += 1; goto nextInstruction; case OP_BLOCK_COPY: - { - int *src, *dest; - int count, srci, desti; - - count = r2; - // MrE: copy range check - srci = r0 & dataMask; - desti = r1 & dataMask; - count = ((srci + count) & dataMask) - srci; - count = ((desti + count) & dataMask) - desti; - - src = (int *)&image[ srci ]; - dest = (int *)&image[ desti ]; - - memcpy(dest, src, count); - programCounter += 1; - opStack -= 2; - } + VM_BlockCopy(r1, r0, r2); + programCounter += 1; + opStackOfs -= 2; goto nextInstruction; case OP_CALL: @@ -494,7 +484,7 @@ nextInstruction2: // jump to the location on the stack programCounter = r0; - opStack--; + opStackOfs--; if ( programCounter < 0 ) { // system call int r; @@ -539,8 +529,8 @@ nextInstruction2: #endif // save return value - opStack++; - *opStack = r; + opStackOfs++; + opStack[opStackOfs] = r; programCounter = *(int *)&image[ programStack ]; // vm->callLevel = temp; #ifdef DEBUG_VM @@ -550,6 +540,7 @@ nextInstruction2: #endif } else if ( (unsigned)programCounter >= vm->instructionCount ) { Com_Error( ERR_DROP, "VM program counter out of range in OP_CALL" ); + return 0; } else { programCounter = vm->instructionPointers[ programCounter ]; } @@ -557,10 +548,10 @@ nextInstruction2: // push and pop are only needed for discarded or bad function return values case OP_PUSH: - opStack++; + opStackOfs++; goto nextInstruction; case OP_POP: - opStack--; + opStackOfs--; goto nextInstruction; case OP_ENTER: @@ -607,6 +598,7 @@ nextInstruction2: goto done; } else if ( (unsigned)programCounter >= vm->codeLength ) { Com_Error( ERR_DROP, "VM program counter out of range in OP_LEAVE" ); + return 0; } goto nextInstruction; @@ -618,15 +610,18 @@ nextInstruction2: case OP_JUMP: if ( (unsigned)r0 >= vm->instructionCount ) + { Com_Error( ERR_DROP, "VM program counter out of range in OP_JUMP" ); + return 0; + } programCounter = vm->instructionPointers[ r0 ]; - opStack--; + opStackOfs--; goto nextInstruction; case OP_EQ: - opStack -= 2; + opStackOfs -= 2; if ( r1 == r0 ) { programCounter = r2; //vm->instructionPointers[r2]; goto nextInstruction; @@ -636,7 +631,7 @@ nextInstruction2: } case OP_NE: - opStack -= 2; + opStackOfs -= 2; if ( r1 != r0 ) { programCounter = r2; //vm->instructionPointers[r2]; goto nextInstruction; @@ -646,7 +641,7 @@ nextInstruction2: } case OP_LTI: - opStack -= 2; + opStackOfs -= 2; if ( r1 < r0 ) { programCounter = r2; //vm->instructionPointers[r2]; goto nextInstruction; @@ -656,7 +651,7 @@ nextInstruction2: } case OP_LEI: - opStack -= 2; + opStackOfs -= 2; if ( r1 <= r0 ) { programCounter = r2; //vm->instructionPointers[r2]; goto nextInstruction; @@ -666,7 +661,7 @@ nextInstruction2: } case OP_GTI: - opStack -= 2; + opStackOfs -= 2; if ( r1 > r0 ) { programCounter = r2; //vm->instructionPointers[r2]; goto nextInstruction; @@ -676,7 +671,7 @@ nextInstruction2: } case OP_GEI: - opStack -= 2; + opStackOfs -= 2; if ( r1 >= r0 ) { programCounter = r2; //vm->instructionPointers[r2]; goto nextInstruction; @@ -686,7 +681,7 @@ nextInstruction2: } case OP_LTU: - opStack -= 2; + opStackOfs -= 2; if ( ((unsigned)r1) < ((unsigned)r0) ) { programCounter = r2; //vm->instructionPointers[r2]; goto nextInstruction; @@ -696,7 +691,7 @@ nextInstruction2: } case OP_LEU: - opStack -= 2; + opStackOfs -= 2; if ( ((unsigned)r1) <= ((unsigned)r0) ) { programCounter = r2; //vm->instructionPointers[r2]; goto nextInstruction; @@ -706,7 +701,7 @@ nextInstruction2: } case OP_GTU: - opStack -= 2; + opStackOfs -= 2; if ( ((unsigned)r1) > ((unsigned)r0) ) { programCounter = r2; //vm->instructionPointers[r2]; goto nextInstruction; @@ -716,7 +711,7 @@ nextInstruction2: } case OP_GEU: - opStack -= 2; + opStackOfs -= 2; if ( ((unsigned)r1) >= ((unsigned)r0) ) { programCounter = r2; //vm->instructionPointers[r2]; goto nextInstruction; @@ -726,68 +721,74 @@ nextInstruction2: } case OP_EQF: - if ( ((float *)opStack)[-1] == *(float *)opStack ) { + opStackOfs -= 2; + + if(((float *) opStack)[(uint8_t) (opStackOfs + 1)] == ((float *) opStack)[(uint8_t) (opStackOfs + 2)]) + { programCounter = r2; //vm->instructionPointers[r2]; - opStack -= 2; goto nextInstruction; } else { programCounter += 1; - opStack -= 2; goto nextInstruction; } case OP_NEF: - if ( ((float *)opStack)[-1] != *(float *)opStack ) { + opStackOfs -= 2; + + if(((float *) opStack)[(uint8_t) (opStackOfs + 1)] != ((float *) opStack)[(uint8_t) (opStackOfs + 2)]) + { programCounter = r2; //vm->instructionPointers[r2]; - opStack -= 2; goto nextInstruction; } else { programCounter += 1; - opStack -= 2; goto nextInstruction; } case OP_LTF: - if ( ((float *)opStack)[-1] < *(float *)opStack ) { + opStackOfs -= 2; + + if(((float *) opStack)[(uint8_t) (opStackOfs + 1)] < ((float *) opStack)[(uint8_t) (opStackOfs + 2)]) + { programCounter = r2; //vm->instructionPointers[r2]; - opStack -= 2; goto nextInstruction; } else { programCounter += 1; - opStack -= 2; goto nextInstruction; } case OP_LEF: - if ( ((float *)opStack)[-1] <= *(float *)opStack ) { + opStackOfs -= 2; + + if(((float *) opStack)[(uint8_t) ((uint8_t) (opStackOfs + 1))] <= ((float *) opStack)[(uint8_t) ((uint8_t) (opStackOfs + 2))]) + { programCounter = r2; //vm->instructionPointers[r2]; - opStack -= 2; goto nextInstruction; } else { programCounter += 1; - opStack -= 2; goto nextInstruction; } case OP_GTF: - if ( ((float *)opStack)[-1] > *(float *)opStack ) { + opStackOfs -= 2; + + if(((float *) opStack)[(uint8_t) (opStackOfs + 1)] > ((float *) opStack)[(uint8_t) (opStackOfs + 2)]) + { programCounter = r2; //vm->instructionPointers[r2]; - opStack -= 2; goto nextInstruction; } else { programCounter += 1; - opStack -= 2; goto nextInstruction; } case OP_GEF: - if ( ((float *)opStack)[-1] >= *(float *)opStack ) { + opStackOfs -= 2; + + if(((float *) opStack)[(uint8_t) (opStackOfs + 1)] >= ((float *) opStack)[(uint8_t) (opStackOfs + 2)]) + { programCounter = r2; //vm->instructionPointers[r2]; - opStack -= 2; goto nextInstruction; } else { programCounter += 1; - opStack -= 2; goto nextInstruction; } @@ -795,101 +796,101 @@ nextInstruction2: //=================================================================== case OP_NEGI: - *opStack = -r0; + opStack[opStackOfs] = -r0; goto nextInstruction; case OP_ADD: - opStack[-1] = r1 + r0; - opStack--; + opStackOfs--; + opStack[opStackOfs] = r1 + r0; goto nextInstruction; case OP_SUB: - opStack[-1] = r1 - r0; - opStack--; + opStackOfs--; + opStack[opStackOfs] = r1 - r0; goto nextInstruction; case OP_DIVI: - opStack[-1] = r1 / r0; - opStack--; + opStackOfs--; + opStack[opStackOfs] = r1 / r0; goto nextInstruction; case OP_DIVU: - opStack[-1] = ((unsigned)r1) / ((unsigned)r0); - opStack--; + opStackOfs--; + opStack[opStackOfs] = ((unsigned) r1) / ((unsigned) r0); goto nextInstruction; case OP_MODI: - opStack[-1] = r1 % r0; - opStack--; + opStackOfs--; + opStack[opStackOfs] = r1 % r0; goto nextInstruction; case OP_MODU: - opStack[-1] = ((unsigned)r1) % (unsigned)r0; - opStack--; + opStackOfs--; + opStack[opStackOfs] = ((unsigned) r1) % ((unsigned) r0); goto nextInstruction; case OP_MULI: - opStack[-1] = r1 * r0; - opStack--; + opStackOfs--; + opStack[opStackOfs] = r1 * r0; goto nextInstruction; case OP_MULU: - opStack[-1] = ((unsigned)r1) * ((unsigned)r0); - opStack--; + opStackOfs--; + opStack[opStackOfs] = ((unsigned) r1) * ((unsigned) r0); goto nextInstruction; case OP_BAND: - opStack[-1] = ((unsigned)r1) & ((unsigned)r0); - opStack--; + opStackOfs--; + opStack[opStackOfs] = ((unsigned) r1) & ((unsigned) r0); goto nextInstruction; case OP_BOR: - opStack[-1] = ((unsigned)r1) | ((unsigned)r0); - opStack--; + opStackOfs--; + opStack[opStackOfs] = ((unsigned) r1) | ((unsigned) r0); goto nextInstruction; case OP_BXOR: - opStack[-1] = ((unsigned)r1) ^ ((unsigned)r0); - opStack--; + opStackOfs--; + opStack[opStackOfs] = ((unsigned) r1) ^ ((unsigned) r0); goto nextInstruction; case OP_BCOM: - *opStack = ~ ((unsigned)r0); + opStack[opStackOfs] = ~((unsigned) r0); goto nextInstruction; case OP_LSH: - opStack[-1] = r1 << r0; - opStack--; + opStackOfs--; + opStack[opStackOfs] = r1 << r0; goto nextInstruction; case OP_RSHI: - opStack[-1] = r1 >> r0; - opStack--; + opStackOfs--; + opStack[opStackOfs] = r1 >> r0; goto nextInstruction; case OP_RSHU: - opStack[-1] = ((unsigned)r1) >> r0; - opStack--; + opStackOfs--; + opStack[opStackOfs] = ((unsigned) r1) >> r0; goto nextInstruction; case OP_NEGF: - *(float *)opStack = -*(float *)opStack; + ((float *) opStack)[opStackOfs] = -((float *) opStack)[opStackOfs]; goto nextInstruction; case OP_ADDF: - *(float *)(opStack-1) = *(float *)(opStack-1) + *(float *)opStack; - opStack--; + opStackOfs--; + ((float *) opStack)[opStackOfs] = ((float *) opStack)[opStackOfs] + ((float *) opStack)[(uint8_t) (opStackOfs + 1)]; goto nextInstruction; case OP_SUBF: - *(float *)(opStack-1) = *(float *)(opStack-1) - *(float *)opStack; - opStack--; + opStackOfs--; + ((float *) opStack)[opStackOfs] = ((float *) opStack)[opStackOfs] - ((float *) opStack)[(uint8_t) (opStackOfs + 1)]; goto nextInstruction; case OP_DIVF: - *(float *)(opStack-1) = *(float *)(opStack-1) / *(float *)opStack; - opStack--; + opStackOfs--; + ((float *) opStack)[opStackOfs] = ((float *) opStack)[opStackOfs] / ((float *) opStack)[(uint8_t) (opStackOfs + 1)]; goto nextInstruction; case OP_MULF: - *(float *)(opStack-1) = *(float *)(opStack-1) * *(float *)opStack; - opStack--; + opStackOfs--; + ((float *) opStack)[opStackOfs] = ((float *) opStack)[opStackOfs] * ((float *) opStack)[(uint8_t) (opStackOfs + 1)]; goto nextInstruction; case OP_CVIF: - *(float *)opStack = (float)*opStack; + ((float *) opStack)[opStackOfs] = (float) opStack[opStackOfs]; goto nextInstruction; case OP_CVFI: - *opStack = (int) *(float *)opStack; + opStack[opStackOfs] = Q_ftol(((float *) opStack)[opStackOfs]); goto nextInstruction; case OP_SEX8: - *opStack = (signed char)*opStack; + opStack[opStackOfs] = (signed char) opStack[opStackOfs]; goto nextInstruction; case OP_SEX16: - *opStack = (short)*opStack; + opStack[opStackOfs] = (short) opStack[opStackOfs]; goto nextInstruction; } } @@ -897,12 +898,11 @@ nextInstruction2: done: vm->currentlyInterpreting = qfalse; - if ( opStack != &stack[1] ) { - Com_Error( ERR_DROP, "Interpreter error: opStack = %ld", (long int) (opStack - stack) ); - } + if (opStackOfs != 1 || *opStack != 0xDEADBEEF) + Com_Error(ERR_DROP, "Interpreter error: opStack[0] = %X, opStackOfs = %d", opStack[0], opStackOfs); vm->programStack = stackOnEntry; // return the result - return *opStack; + return opStack[opStackOfs]; } diff --git a/reaction/code/qcommon/vm_local.h b/reaction/code/qcommon/vm_local.h index f6db7017..aa14e672 100644 --- a/reaction/code/qcommon/vm_local.h +++ b/reaction/code/qcommon/vm_local.h @@ -22,7 +22,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "q_shared.h" #include "qcommon.h" -#define OPSTACK_SIZE 256 +// don't change, this is hardcoded into x86 VMs, opStack protection relies +// on this +#define OPSTACK_SIZE 1024 #define OPSTACK_MASK (OPSTACK_SIZE-1) // don't change @@ -139,7 +141,8 @@ struct vm_s { //------------------------------------ - char name[MAX_QPATH]; + char name[MAX_QPATH]; + void *searchPath; // hint for FS_ReadFileDir() // for dynamic linked modules void *dllHandle; @@ -151,9 +154,10 @@ struct vm_s { qboolean compiled; byte *codeBase; + int entryOfs; int codeLength; - int *instructionPointers; + intptr_t *instructionPointers; int instructionCount; byte *dataBase; @@ -186,3 +190,5 @@ vmSymbol_t *VM_ValueToFunctionSymbol( vm_t *vm, int value ); int VM_SymbolToValue( vm_t *vm, const char *symbol ); const char *VM_ValueToSymbol( vm_t *vm, int value ); void VM_LogSyscalls( int *args ); + +void VM_BlockCopy(unsigned int dest, unsigned int src, size_t n); diff --git a/reaction/code/qcommon/vm_powerpc.c b/reaction/code/qcommon/vm_powerpc.c index c18e679b..eb66c5ad 100644 --- a/reaction/code/qcommon/vm_powerpc.c +++ b/reaction/code/qcommon/vm_powerpc.c @@ -47,7 +47,7 @@ static clock_t time_total_vm = 0; /* exit() won't be called but use it because it is marked with noreturn */ #define DIE( reason ) \ do { \ - Com_Error(ERR_DROP, "vm_powerpc compiler error: " reason "\n"); \ + Com_Error(ERR_DROP, "vm_powerpc compiler error: " reason); \ exit(1); \ } while(0) @@ -389,23 +389,6 @@ VM_AsmCall( int callSyscallInvNum, int callProgramStack ) return ret; } -static void -VM_BlockCopy( unsigned int dest, unsigned int src, unsigned int count ) -{ - unsigned dataMask = currentVM->dataMask; - - if ( (dest & dataMask) != dest - || (src & dataMask) != src - || ((dest+count) & dataMask) != dest + count - || ((src+count) & dataMask) != src + count) - { - DIE( "OP_BLOCK_COPY out of range!"); - } - - memcpy( currentVM->dataBase+dest, currentVM->dataBase+src, count ); -} - - /* * code-block descriptors */ diff --git a/reaction/code/qcommon/vm_powerpc_asm.c b/reaction/code/qcommon/vm_powerpc_asm.c index 340da178..70159259 100644 --- a/reaction/code/qcommon/vm_powerpc_asm.c +++ b/reaction/code/qcommon/vm_powerpc_asm.c @@ -65,7 +65,6 @@ struct powerpc_opcode }; static const struct powerpc_opcode powerpc_opcodes[]; -static const int powerpc_num_opcodes; #define PPC_OPCODE_PPC 1 #define PPC_OPCODE_POWER 2 @@ -112,7 +111,6 @@ struct powerpc_operand }; static const struct powerpc_operand powerpc_operands[]; -static const unsigned int num_powerpc_operands; #define PPC_OPERAND_SIGNED (0x1) #define PPC_OPERAND_SIGNOPT (0x2) @@ -390,7 +388,6 @@ static const struct powerpc_operand powerpc_operands[] = }; -static const unsigned int num_powerpc_operands = ARRAY_LEN (powerpc_operands); /* The functions used to insert and extract complicated operands. */ diff --git a/reaction/code/qcommon/vm_sparc.c b/reaction/code/qcommon/vm_sparc.c index 4018216b..5756dc18 100644 --- a/reaction/code/qcommon/vm_sparc.c +++ b/reaction/code/qcommon/vm_sparc.c @@ -36,7 +36,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA /* exit() won't be called but use it because it is marked with noreturn */ #define DIE( reason ) \ do { \ - Com_Error(ERR_DROP, "vm_sparc compiler error: " reason "\n"); \ + Com_Error(ERR_DROP, "vm_sparc compiler error: " reason); \ exit(1); \ } while(0) @@ -511,6 +511,7 @@ typedef struct VM_Data { int (*AsmCall)(int, int); void (*BlockCopy)(unsigned int, unsigned int, unsigned int); unsigned int *iPointers; + void (*ErrJump)(void); unsigned int data[0]; } vm_data_t; @@ -698,11 +699,20 @@ static void dst_insn_append(struct func_info * const fp) fp->insn_index = 0; } -static void jump_insn_append(struct func_info * const fp, enum sparc_iname iname, int dest) +static void ErrJump(void) +{ + Com_Error(ERR_DROP, "program tried to execute code outside VM\n"); + exit(1); +} + +static void jump_insn_append(vm_t *vm, struct func_info * const fp, enum sparc_iname iname, int dest) { struct jump_insn *jp = Z_Malloc(sizeof(*jp)); struct dst_insn *dp; + if (dest < 0 || dest >= vm->instructionCount) + ErrJump(); + dp = dst_new(fp, 2, jp, 0); jp->jump_iname = iname; @@ -734,10 +744,10 @@ static void end_emit(struct func_info * const fp) dst_insn_append(fp); } -static void emit_jump(struct func_info * const fp, enum sparc_iname iname, int dest) +static void emit_jump(vm_t *vm, struct func_info * const fp, enum sparc_iname iname, int dest) { end_emit(fp); - jump_insn_append(fp, iname, dest); + jump_insn_append(vm, fp, iname, dest); } static void analyze_function(struct func_info * const fp) @@ -860,7 +870,7 @@ do { int saved_i_count = (fp)->saved_icount; \ (fp)->saved_icount = saved_i_count; \ } while (0) -static void compile_one_insn(struct func_info * const fp, struct src_insn *sp) +static void compile_one_insn(vm_t *vm, struct func_info * const fp, struct src_insn *sp) { start_emit(fp, sp->i_count); @@ -928,11 +938,17 @@ static void compile_one_insn(struct func_info * const fp, struct src_insn *sp) case OP_JUMP: if (fp->cached_const) { EMIT_FALSE_CONST(fp); - emit_jump(fp, BA, fp->cached_const->arg.i); + emit_jump(vm, fp, BA, fp->cached_const->arg.i); } else { MAYBE_EMIT_CONST(fp); - in(LDLI, rVMDATA, VM_Data_Offset(iPointers), rTMP); + in(SETHI, vm->instructionCount >> 10, rTMP); + in(ORI, rTMP, vm->instructionCount & 0x3ff, rTMP); + in(SUBCC, rTMP, rFIRST(fp), G0); + in(BLEU, +4*5); + in(LDLI, rVMDATA, VM_Data_Offset(ErrJump), rTMP); + in(SLLI, rFIRST(fp), 2, rFIRST(fp)); + in(LDLI, rVMDATA, VM_Data_Offset(iPointers), rTMP); in(LDL, rTMP, rFIRST(fp), rTMP); in(JMPL, rTMP, G0, G0); in(NOP); @@ -943,7 +959,7 @@ static void compile_one_insn(struct func_info * const fp, struct src_insn *sp) if (fp->cached_const) { EMIT_FALSE_CONST(fp); if (fp->cached_const->arg.si >= 0) { - emit_jump(fp, CALL, fp->cached_const->arg.i); + emit_jump(vm, fp, CALL, fp->cached_const->arg.i); } else { in(LDLI, rVMDATA, VM_Data_Offset(CallThunk), rTMP); in(LDLI, rVMDATA, VM_Data_Offset(AsmCall), O3); @@ -959,6 +975,11 @@ static void compile_one_insn(struct func_info * const fp, struct src_insn *sp) in(NOP); /* normal call */ + in(SETHI, vm->instructionCount >> 10, rTMP); + in(ORI, rTMP, vm->instructionCount & 0x3ff, rTMP); + in(SUBCC, rTMP, rFIRST(fp), G0); + in(BLEU, +4*9); + in(LDLI, rVMDATA, VM_Data_Offset(ErrJump), rTMP); in(LDLI, rVMDATA, VM_Data_Offset(iPointers), O5); in(SLLI, rFIRST(fp), 2, rFIRST(fp)); in(LDL, O5, rFIRST(fp), rTMP); @@ -1124,7 +1145,7 @@ static void compile_one_insn(struct func_info * const fp, struct src_insn *sp) case OP_GTU: iname = BGU; break; case OP_LEU: iname = BLEU; break; } - emit_jump(fp, iname, sp->arg.i); + emit_jump(vm, fp, iname, sp->arg.i); POP_GPR(fp); POP_GPR(fp); break; @@ -1297,7 +1318,7 @@ static void compile_one_insn(struct func_info * const fp, struct src_insn *sp) case OP_GTF: iname = FBG; break; case OP_LEF: iname = FBLE; break; } - emit_jump(fp, iname, sp->arg.i); + emit_jump(vm, fp, iname, sp->arg.i); POP_FPR(fp); POP_FPR(fp); break; @@ -1344,7 +1365,7 @@ static void free_source_insns(struct func_info * const fp) } } -static void compile_function(struct func_info * const fp) +static void compile_function(vm_t *vm, struct func_info * const fp) { struct src_insn *sp; @@ -1359,7 +1380,7 @@ static void compile_function(struct func_info * const fp) sp = fp->first; while ((sp = sp->next) != NULL) - compile_one_insn(fp, sp); + compile_one_insn(vm, fp, sp); free_source_insns(fp); } @@ -1478,6 +1499,7 @@ static void sparc_compute_code(vm_t *vm, struct func_info * const fp) data->iPointers = (unsigned int *) vm->instructionPointers; data->dataLength = VM_Data_Offset(data[fp->data_num]); data->codeLength = (code_now - code_begin) * sizeof(unsigned int); + data->ErrJump = ErrJump; #if 0 { @@ -1564,7 +1586,7 @@ void VM_Compile(vm_t *vm, vmHeader_t *header) if (op == OP_ENTER) { if (fi.first->next) - compile_function(&fi); + compile_function(vm, &fi); fi.first->next = NULL; fi.last = fi.first; fi.has_call = fi.need_float_tmp = 0; @@ -1592,7 +1614,7 @@ void VM_Compile(vm_t *vm, vmHeader_t *header) fi.last->next = sp; fi.last = sp; } - compile_function(&fi); + compile_function(vm, &fi); Z_Free(fi.first); diff --git a/reaction/code/qcommon/vm_x86.c b/reaction/code/qcommon/vm_x86.c index 32a5a9a7..aa63d048 100644 --- a/reaction/code/qcommon/vm_x86.c +++ b/reaction/code/qcommon/vm_x86.c @@ -22,6 +22,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // vm_x86.c -- load time compiler and execution environment for x86 #include "vm_local.h" + #ifdef _WIN32 #include #endif @@ -44,207 +45,70 @@ static void VM_Destroy_Compiled(vm_t* self); /* - eax scratch - ebx scratch - ecx scratch (required for shifts) - edx scratch (required for divisions) - esi program stack - edi opstack + eax scratch + ebx/bl opStack offset + ecx scratch (required for shifts) + edx scratch (required for divisions) + esi program stack + edi opStack base +x86_64: + r8 vm->instructionPointers + r9 vm->dataBase */ #define VMFREE_BUFFERS() do {Z_Free(buf); Z_Free(jused);} while(0) static byte *buf = NULL; static byte *jused = NULL; +static int jusedSize = 0; static int compiledOfs = 0; static byte *code = NULL; static int pc = 0; -static int *instructionPointers = NULL; - #define FTOL_PTR -#ifdef _MSC_VER - -#if defined( FTOL_PTR ) -int _ftol( float ); -static int ftolPtr = (int)_ftol; -#endif - -#else // _MSC_VER - -#if defined( FTOL_PTR ) - -int qftol( void ); -int qftol027F( void ); -int qftol037F( void ); -int qftol0E7F( void ); -int qftol0F7F( void ); - - -static int ftolPtr = (int)qftol0F7F; -#endif // FTOL_PTR - -#endif - -void AsmCall(void); -static void (*const asmCallPtr)(void) = AsmCall; - - -static int callMask = 0; - static int instruction, pass; static int lastConst = 0; static int oc0, oc1, pop0, pop1; +static int jlabel; typedef enum { LAST_COMMAND_NONE = 0, - LAST_COMMAND_MOV_EDI_EAX, - LAST_COMMAND_SUB_DI_4, - LAST_COMMAND_SUB_DI_8, + LAST_COMMAND_MOV_STACK_EAX, + LAST_COMMAND_SUB_BL_1, + LAST_COMMAND_SUB_BL_2, } ELastCommand; +typedef enum +{ + VM_JMP_VIOLATION = 0, + VM_BLOCK_COPY = 1 +} ESysCallType; + static ELastCommand LastCommand; -/* -================= -AsmCall -================= -*/ -#ifdef _MSC_VER -__declspec( naked ) void AsmCall( void ) { -int programStack; -int *opStack; -int syscallNum; -vm_t* savedVM; - -__asm { - mov eax, dword ptr [edi] - sub edi, 4 - test eax,eax - jl systemCall - // calling another vm function - shl eax,2 - add eax, dword ptr [instructionPointers] - call dword ptr [eax] - mov eax, dword ptr [edi] - and eax, [callMask] - ret -systemCall: - - // convert negative num to system call number - // and store right before the first arg - not eax - - push ebp - mov ebp, esp - sub esp, __LOCAL_SIZE - - mov dword ptr syscallNum, eax // so C code can get at it - mov dword ptr programStack, esi // so C code can get at it - mov dword ptr opStack, edi - - push ecx - push esi // we may call recursively, so the - push edi // statics aren't guaranteed to be around -} - - savedVM = currentVM; - - // save the stack to allow recursive VM entry - currentVM->programStack = programStack - 4; - *(int *)((byte *)currentVM->dataBase + programStack + 4) = syscallNum; -//VM_LogSyscalls( (int *)((byte *)currentVM->dataBase + programStack + 4) ); - *(opStack+1) = currentVM->systemCall( (int *)((byte *)currentVM->dataBase + programStack + 4) ); - - currentVM = savedVM; - -_asm { - pop edi - pop esi - pop ecx - add edi, 4 // we added the return value - - mov esp, ebp - pop ebp - - ret -} - -} - -#else //!_MSC_VER - -#if defined(__MINGW32__) || defined(MACOS_X) // _ is prepended to compiled symbols -#define CMANGVAR(sym) "_"#sym -#define CMANGFUNC(sym) "_"#sym -#elif defined(__ICC) && (__ICC >= 1000) -#define CMANGVAR(sym) #sym".0" -#define CMANGFUNC(sym) #sym -#else -#define CMANGVAR(sym) #sym -#define CMANGFUNC(sym) #sym -#endif - -static void __attribute__((cdecl, used)) CallAsmCall(int const syscallNum, - int const programStack, int* const opStack) +static int iss8(int32_t v) { - vm_t *const vm = currentVM; - intptr_t *const data = (intptr_t*)(vm->dataBase + programStack + 4); - - // save the stack to allow recursive VM entry - vm->programStack = programStack - 4; - *data = syscallNum; - opStack[1] = vm->systemCall(data); - - currentVM = vm; + return (SCHAR_MIN <= v && v <= SCHAR_MAX); } -__asm__( - ".text\n\t" - ".p2align 4,,15\n\t" -#if defined __ELF__ - ".type " CMANGFUNC(AsmCall) ", @function\n" +#if 0 +static int isu8(uint32_t v) +{ + return (v <= UCHAR_MAX); +} #endif - CMANGFUNC(AsmCall) ":\n\t" - "movl (%edi), %eax\n\t" - "subl $4, %edi\n\t" - "testl %eax, %eax\n\t" - "jl 0f\n\t" - "shll $2, %eax\n\t" - "addl " CMANGVAR(instructionPointers) ", %eax\n\t" - "call *(%eax)\n\t" - "movl (%edi), %eax\n\t" - "andl " CMANGVAR(callMask) ", %eax\n\t" - "ret\n" - "0:\n\t" // system call - "notl %eax\n\t" - "pushl %ebp\n\t" - "movl %esp, %ebp\n\t" - "andl $-16, %esp\n\t" // align the stack so engine can use sse - "pushl %ecx\n\t" - "pushl %edi\n\t" // opStack - "pushl %esi\n\t" // programStack - "pushl %eax\n\t" // syscallNum - "call " CMANGFUNC(CallAsmCall) "\n\t" - "addl $12, %esp\n\t" - "popl %ecx\n\t" - "movl %ebp, %esp\n\t" - "popl %ebp\n\t" - "addl $4, %edi\n\t" - "ret\n\t" -#if defined __ELF__ - ".size " CMANGFUNC(AsmCall)", .-" CMANGFUNC(AsmCall) -#endif -); -#endif +static int NextConstant4(void) +{ + return (code[pc] | (code[pc+1]<<8) | (code[pc+2]<<16) | (code[pc+3]<<24)); +} static int Constant4( void ) { int v; - v = code[pc] | (code[pc+1]<<8) | (code[pc+2]<<16) | (code[pc+3]<<24); + v = NextConstant4(); pc += 4; return v; } @@ -265,18 +129,32 @@ static void Emit1( int v ) LastCommand = LAST_COMMAND_NONE; } -#if 0 -static void Emit2( int v ) { - Emit1( v & 255 ); - Emit1( ( v >> 8 ) & 255 ); +static void Emit2(int v) +{ + Emit1(v & 255); + Emit1((v >> 8) & 255); } -#endif -static void Emit4( int v ) { - Emit1( v & 255 ); - Emit1( ( v >> 8 ) & 255 ); - Emit1( ( v >> 16 ) & 255 ); - Emit1( ( v >> 24 ) & 255 ); + +static void Emit4(int v) +{ + Emit1(v & 0xFF); + Emit1((v >> 8) & 0xFF); + Emit1((v >> 16) & 0xFF); + Emit1((v >> 24) & 0xFF); +} + +static void EmitPtr(void *ptr) +{ + intptr_t v = (intptr_t) ptr; + + Emit4(v); +#if idx64 + Emit1((v >> 32) & 0xFF); + Emit1((v >> 40) & 0xFF); + Emit1((v >> 48) & 0xFF); + Emit1((v >> 56) & 0xFF); +#endif } static int Hex( int c ) { @@ -312,23 +190,46 @@ static void EmitString( const char *string ) { string += 3; } } +static void EmitRexString(byte rex, const char *string) +{ +#if idx64 + if(rex) + Emit1(rex); +#endif + + EmitString(string); +} +#define MASK_REG(modrm, mask) \ + EmitString("81"); \ + EmitString((modrm)); \ + Emit4((mask)) + +// add bl, bytes +#define STACK_PUSH(bytes) \ + EmitString("80 C3"); \ + Emit1(bytes) + +// sub bl, bytes +#define STACK_POP(bytes) \ + EmitString("80 EB"); \ + Emit1(bytes) static void EmitCommand(ELastCommand command) { switch(command) { - case LAST_COMMAND_MOV_EDI_EAX: - EmitString( "89 07" ); // mov dword ptr [edi], eax + case LAST_COMMAND_MOV_STACK_EAX: + EmitString("89 04 9F"); // mov dword ptr [edi + ebx * 4], eax break; - case LAST_COMMAND_SUB_DI_4: - EmitString( "83 EF 04" ); // sub edi, 4 + case LAST_COMMAND_SUB_BL_1: + STACK_POP(1); // sub bl, 1 break; - case LAST_COMMAND_SUB_DI_8: - EmitString( "83 EF 08" ); // sub edi, 8 + case LAST_COMMAND_SUB_BL_2: + STACK_POP(2); // sub bl, 2 break; default: break; @@ -336,106 +237,864 @@ static void EmitCommand(ELastCommand command) LastCommand = command; } -static void EmitAddEDI4(vm_t *vm) { - if (LastCommand == LAST_COMMAND_SUB_DI_4 && jused[instruction-1] == 0) - { // sub di,4 - compiledOfs -= 3; - vm->instructionPointers[ instruction-1 ] = compiledOfs; - return; - } - if (LastCommand == LAST_COMMAND_SUB_DI_8 && jused[instruction-1] == 0) - { // sub di,8 - compiledOfs -= 3; - vm->instructionPointers[ instruction-1 ] = compiledOfs; - EmitString( "83 EF 04" ); // sub edi,4 - return; - } - EmitString( "83 C7 04" ); // add edi,4 -} - -static void EmitMovEAXEDI(vm_t *vm) { - if (LastCommand == LAST_COMMAND_MOV_EDI_EAX) - { // mov [edi], eax - compiledOfs -= 2; - vm->instructionPointers[ instruction-1 ] = compiledOfs; - return; - } - if (pop1 == OP_DIVI || pop1 == OP_DIVU || pop1 == OP_MULI || pop1 == OP_MULU || - pop1 == OP_STORE4 || pop1 == OP_STORE2 || pop1 == OP_STORE1 ) - { - return; - } - if (pop1 == OP_CONST && buf[compiledOfs-6] == 0xC7 && buf[compiledOfs-5] == 0x07 ) - { // mov edi, 0x123456 - compiledOfs -= 6; - vm->instructionPointers[ instruction-1 ] = compiledOfs; - EmitString( "B8" ); // mov eax, 0x12345678 - Emit4( lastConst ); - return; - } - EmitString( "8B 07" ); // mov eax, dword ptr [edi] -} - -qboolean EmitMovEBXEDI(vm_t *vm, int andit) { - if (LastCommand == LAST_COMMAND_MOV_EDI_EAX) - { // mov [edi], eax - compiledOfs -= 2; - vm->instructionPointers[ instruction-1 ] = compiledOfs; - EmitString( "8B D8"); // mov bx, eax - return qfalse; - } - if (pop1 == OP_DIVI || pop1 == OP_DIVU || pop1 == OP_MULI || pop1 == OP_MULU || - pop1 == OP_STORE4 || pop1 == OP_STORE2 || pop1 == OP_STORE1 ) - { - EmitString( "8B D8"); // mov bx, eax - return qfalse; - } - if (pop1 == OP_CONST && buf[compiledOfs-6] == 0xC7 && buf[compiledOfs-5] == 0x07 ) - { // mov edi, 0x123456 - compiledOfs -= 6; - vm->instructionPointers[ instruction-1 ] = compiledOfs; - EmitString( "BB" ); // mov ebx, 0x12345678 - if (andit) { - Emit4( lastConst & andit ); - } else { - Emit4( lastConst ); +static void EmitPushStack(vm_t *vm) +{ + if (!jlabel) + { + if(LastCommand == LAST_COMMAND_SUB_BL_1) + { // sub bl, 1 + compiledOfs -= 3; + vm->instructionPointers[instruction - 1] = compiledOfs; + return; + } + if(LastCommand == LAST_COMMAND_SUB_BL_2) + { // sub bl, 2 + compiledOfs -= 3; + vm->instructionPointers[instruction - 1] = compiledOfs; + STACK_POP(1); // sub bl, 1 + return; } - return qtrue; } - EmitString( "8B 1F" ); // mov ebx, dword ptr [edi] - return qfalse; + STACK_PUSH(1); // add bl, 1 +} + +static void EmitMovEAXStack(vm_t *vm, int andit) +{ + if(!jlabel) + { + if(LastCommand == LAST_COMMAND_MOV_STACK_EAX) + { // mov [edi + ebx * 4], eax + compiledOfs -= 3; + vm->instructionPointers[instruction - 1] = compiledOfs; + } + else if(pop1 == OP_CONST && buf[compiledOfs-7] == 0xC7 && buf[compiledOfs-6] == 0x04 && buf[compiledOfs - 5] == 0x9F) + { // mov [edi + ebx * 4], 0x12345678 + compiledOfs -= 7; + vm->instructionPointers[instruction - 1] = compiledOfs; + EmitString("B8"); // mov eax, 0x12345678 + + if(andit) + Emit4(lastConst & andit); + else + Emit4(lastConst); + + return; + } + else if(pop1 != OP_DIVI && pop1 != OP_DIVU && pop1 != OP_MULI && pop1 != OP_MULU && + pop1 != OP_STORE4 && pop1 != OP_STORE2 && pop1 != OP_STORE1) + { + EmitString("8B 04 9F"); // mov eax, dword ptr [edi + ebx * 4] + } + } + else + EmitString("8B 04 9F"); // mov eax, dword ptr [edi + ebx * 4] + + if(andit) + { + EmitString("25"); // and eax, 0x12345678 + Emit4(andit); + } +} + +void EmitMovECXStack(vm_t *vm) +{ + if(!jlabel) + { + if(LastCommand == LAST_COMMAND_MOV_STACK_EAX) // mov [edi + ebx * 4], eax + { + compiledOfs -= 3; + vm->instructionPointers[instruction - 1] = compiledOfs; + EmitString("89 C1"); // mov ecx, eax + return; + } + if(pop1 == OP_DIVI || pop1 == OP_DIVU || pop1 == OP_MULI || pop1 == OP_MULU || + pop1 == OP_STORE4 || pop1 == OP_STORE2 || pop1 == OP_STORE1) + { + EmitString("89 C1"); // mov ecx, eax + return; + } + } + + EmitString("8B 0C 9F"); // mov ecx, dword ptr [edi + ebx * 4] +} + + +void EmitMovEDXStack(vm_t *vm, int andit) +{ + if(!jlabel) + { + if(LastCommand == LAST_COMMAND_MOV_STACK_EAX) + { // mov dword ptr [edi + ebx * 4], eax + compiledOfs -= 3; + vm->instructionPointers[instruction - 1] = compiledOfs; + + EmitString("8B D0"); // mov edx, eax + } + else if(pop1 == OP_DIVI || pop1 == OP_DIVU || pop1 == OP_MULI || pop1 == OP_MULU || + pop1 == OP_STORE4 || pop1 == OP_STORE2 || pop1 == OP_STORE1) + { + EmitString("8B D0"); // mov edx, eax + } + else if(pop1 == OP_CONST && buf[compiledOfs-7] == 0xC7 && buf[compiledOfs-6] == 0x07 && buf[compiledOfs - 5] == 0x9F) + { // mov dword ptr [edi + ebx * 4], 0x12345678 + compiledOfs -= 7; + vm->instructionPointers[instruction - 1] = compiledOfs; + EmitString("BA"); // mov edx, 0x12345678 + + if(andit) + Emit4(lastConst & andit); + else + Emit4(lastConst); + + return; + } + else + EmitString("8B 14 9F"); // mov edx, dword ptr [edi + ebx * 4] + + } + else + EmitString("8B 14 9F"); // mov edx, dword ptr [edi + ebx * 4] + + if(andit) + MASK_REG("E2", andit); // and edx, 0x12345678 } #define JUSED(x) \ do { \ - if (x < 0 || x >= jusedSize) { \ - VMFREE_BUFFERS(); \ + if (x < 0 || x >= vm->instructionCount) { \ + VMFREE_BUFFERS(); \ Com_Error( ERR_DROP, \ "VM_CompileX86: jump target out of range at offset %d", pc ); \ } \ jused[x] = 1; \ } while(0) +#define SET_JMPOFS(x) do { buf[(x)] = compiledOfs - ((x) + 1); } while(0) + + +/* +================= +ErrJump +Error handler for jump/call to invalid instruction number +================= +*/ + +static void ErrJump(void) +{ + Com_Error(ERR_DROP, "program tried to execute code outside VM"); + exit(1); +} + +/* +================= +DoSyscall +Uses asm to retrieve arguments from registers to work around different calling conventions +================= +*/ + +#if defined(_MSC_VER) && idx64 + +extern void qsyscall64(void); +extern uint8_t qvmcall64(int *programStack, int *opStack, intptr_t *instructionPointers, byte *dataBase); + +// Microsoft does not support inline assembler on x64 platforms. Meh. +void DoSyscall(int syscallNum, int programStack, int *opStackBase, uint8_t opStackOfs, intptr_t arg) +{ +#else +static void DoSyscall(void) +{ + int syscallNum; + int programStack; + int *opStackBase; + uint8_t opStackOfs; + intptr_t arg; +#endif + + vm_t *savedVM; + +#if defined(_MSC_VER) + #if !idx64 + __asm + { + mov dword ptr syscallNum, eax + mov dword ptr programStack, esi + mov byte ptr opStackOfs, bl + mov dword ptr opStackBase, edi + mov dword ptr arg, ecx + } + #endif +#else + __asm__ volatile( + "" + : "=a" (syscallNum), "=S" (programStack), "=D" (opStackBase), "=b" (opStackOfs), + "=c" (arg) + ); +#endif + + // save currentVM so as to allow for recursive VM entry + savedVM = currentVM; + // modify VM stack pointer for recursive VM entry + currentVM->programStack = programStack - 4; + + if(syscallNum < 0) + { + int *data; +#if idx64 + int index; + intptr_t args[11]; +#endif + + data = (int *) (savedVM->dataBase + programStack + 4); + +#if idx64 + args[0] = ~syscallNum; + for(index = 1; index < ARRAY_LEN(args); index++) + args[index] = data[index]; + + opStackBase[opStackOfs + 1] = savedVM->systemCall(args); +#else + data[0] = ~syscallNum; + opStackBase[opStackOfs + 1] = savedVM->systemCall(data); +#endif + } + else + { + switch(syscallNum) + { + case VM_JMP_VIOLATION: + ErrJump(); + break; + case VM_BLOCK_COPY: + if(opStackOfs < 1) + Com_Error(ERR_DROP, "VM_BLOCK_COPY failed due to corrupted opStack"); + + VM_BlockCopy(opStackBase[(opStackOfs - 1)], opStackBase[opStackOfs], arg); + break; + default: + Com_Error(ERR_DROP, "Unknown VM operation %d", syscallNum); + break; + } + } + + currentVM = savedVM; +} + +/* +================= +EmitCallRel +Relative call to vm->codeBase + callOfs +================= +*/ + +void EmitCallRel(vm_t *vm, int callOfs) +{ + EmitString("E8"); // call 0x12345678 + Emit4(callOfs - compiledOfs - 4); +} + +/* +================= +EmitCallDoSyscall +Call to DoSyscall() +================= +*/ + +int EmitCallDoSyscall(vm_t *vm) +{ + // use edx register to store DoSyscall address +#if defined(_MSC_VER) && idx64 + EmitRexString(0x48, "BA"); // mov edx, qsyscall64 + EmitPtr(qsyscall64); +#else + EmitRexString(0x48, "BA"); // mov edx, DoSyscall + EmitPtr(DoSyscall); +#endif + + // Push important registers to stack as we can't really make + // any assumptions about calling conventions. + EmitString("51"); // push ebx + EmitString("56"); // push esi + EmitString("57"); // push edi +#if idx64 + EmitRexString(0x41, "50"); // push r8 + EmitRexString(0x41, "51"); // push r9 +#endif + + // align the stack pointer to a 16-byte-boundary + EmitString("55"); // push ebp + EmitRexString(0x48, "89 E5"); // mov ebp, esp + EmitRexString(0x48, "83 E4 F0"); // and esp, 0xFFFFFFF0 + + // call the syscall wrapper function DoSyscall() + + EmitString("FF D2"); // call edx + + // reset the stack pointer to its previous value + EmitRexString(0x48, "89 EC"); // mov esp, ebp + EmitString("5D"); // pop ebp + +#if idx64 + EmitRexString(0x41, "59"); // pop r9 + EmitRexString(0x41, "58"); // pop r8 +#endif + EmitString("5F"); // pop edi + EmitString("5E"); // pop esi + EmitString("59"); // pop ebx + + EmitString("C3"); // ret + + return compiledOfs; +} + +/* +================= +EmitCallErrJump +Emit the code that triggers execution of the jump violation handler +================= +*/ + +static void EmitCallErrJump(vm_t *vm, int sysCallOfs) +{ + EmitString("B8"); // mov eax, 0x12345678 + Emit4(VM_JMP_VIOLATION); + + EmitCallRel(vm, sysCallOfs); +} + +/* +================= +EmitCallProcedure +VM OP_CALL procedure for call destinations obtained at runtime +================= +*/ + +int EmitCallProcedure(vm_t *vm, int sysCallOfs) +{ + int jmpSystemCall, jmpBadAddr; + int retval; + + EmitString("8B 04 9F"); // mov eax, dword ptr [edi + ebx * 4] + STACK_POP(1); // sub bl, 1 + EmitString("85 C0"); // test eax, eax + + // Jump to syscall code, 1 byte offset should suffice + EmitString("7C"); // jl systemCall + jmpSystemCall = compiledOfs++; + + /************ Call inside VM ************/ + + EmitString("81 F8"); // cmp eax, vm->instructionCount + Emit4(vm->instructionCount); + + // Error jump if invalid jump target + EmitString("73"); // jae badAddr + jmpBadAddr = compiledOfs++; + +#if idx64 + EmitRexString(0x49, "FF 14 C0"); // call qword ptr [r8 + eax * 8] +#else + EmitString("FF 14 85"); // call dword ptr [vm->instructionPointers + eax * 4] + Emit4((intptr_t) vm->instructionPointers); +#endif + EmitString("8B 04 9F"); // mov eax, dword ptr [edi + ebx * 4] + EmitString("C3"); // ret + + // badAddr: + SET_JMPOFS(jmpBadAddr); + EmitCallErrJump(vm, sysCallOfs); + + /************ System Call ************/ + + // systemCall: + SET_JMPOFS(jmpSystemCall); + retval = compiledOfs; + + EmitCallRel(vm, sysCallOfs); + + // have opStack reg point at return value + STACK_PUSH(1); // add bl, 1 + EmitString("C3"); // ret + + return retval; +} + +/* +================= +EmitJumpIns +Jump to constant instruction number +================= +*/ + +void EmitJumpIns(vm_t *vm, const char *jmpop, int cdest) +{ + JUSED(cdest); + + EmitString(jmpop); // j??? 0x12345678 + + // we only know all the jump addresses in the third pass + if(pass == 2) + Emit4(vm->instructionPointers[cdest] - compiledOfs - 4); + else + compiledOfs += 4; +} + +/* +================= +EmitCallIns +Call to constant instruction number +================= +*/ + +void EmitCallIns(vm_t *vm, int cdest) +{ + JUSED(cdest); + + EmitString("E8"); // call 0x12345678 + + // we only know all the jump addresses in the third pass + if(pass == 2) + Emit4(vm->instructionPointers[cdest] - compiledOfs - 4); + else + compiledOfs += 4; +} + +/* +================= +EmitCallConst +Call to constant instruction number or syscall +================= +*/ + +void EmitCallConst(vm_t *vm, int cdest, int callProcOfsSyscall) +{ + if(cdest < 0) + { + EmitString("B8"); // mov eax, cdest + Emit4(cdest); + + EmitCallRel(vm, callProcOfsSyscall); + } + else + EmitCallIns(vm, cdest); +} + +/* +================= +EmitBranchConditions +Emits x86 branch condition as given in op +================= +*/ +void EmitBranchConditions(vm_t *vm, int op) +{ + switch(op) + { + case OP_EQ: + EmitJumpIns(vm, "0F 84", Constant4()); // je 0x12345678 + break; + case OP_NE: + EmitJumpIns(vm, "0F 85", Constant4()); // jne 0x12345678 + break; + case OP_LTI: + EmitJumpIns(vm, "0F 8C", Constant4()); // jl 0x12345678 + break; + case OP_LEI: + EmitJumpIns(vm, "0F 8E", Constant4()); // jle 0x12345678 + break; + case OP_GTI: + EmitJumpIns(vm, "0F 8F", Constant4()); // jg 0x12345678 + break; + case OP_GEI: + EmitJumpIns(vm, "0F 8D", Constant4()); // jge 0x12345678 + break; + case OP_LTU: + EmitJumpIns(vm, "0F 82", Constant4()); // jb 0x12345678 + break; + case OP_LEU: + EmitJumpIns(vm, "0F 86", Constant4()); // jbe 0x12345678 + break; + case OP_GTU: + EmitJumpIns(vm, "0F 87", Constant4()); // ja 0x12345678 + break; + case OP_GEU: + EmitJumpIns(vm, "0F 83", Constant4()); // jae 0x12345678 + break; + } +} + + +/* +================= +ConstOptimize +Constant values for immediately following instructions may be translated to immediate values +instead of opStack operations, which will save expensive operations on memory +================= +*/ + +qboolean ConstOptimize(vm_t *vm, int callProcOfsSyscall) +{ + int v; + int op1; + + // we can safely perform optimizations only in case if + // we are 100% sure that next instruction is not a jump label + if (vm->jumpTableTargets && !jused[instruction]) + op1 = code[pc+4]; + else + return qfalse; + + switch ( op1 ) { + + case OP_LOAD4: + EmitPushStack(vm); +#if idx64 + EmitRexString(0x41, "8B 81"); // mov eax, dword ptr [r9 + 0x12345678] + Emit4(Constant4() & vm->dataMask); +#else + EmitString("B8"); // mov eax, 0x12345678 + EmitPtr(vm->dataBase + (Constant4() & vm->dataMask)); + EmitString("8B 00"); // mov eax, dword ptr [eax] +#endif + EmitCommand(LAST_COMMAND_MOV_STACK_EAX); // mov dword ptr [edi + ebx * 4], eax + + pc++; // OP_LOAD4 + instruction += 1; + return qtrue; + + case OP_LOAD2: + EmitPushStack(vm); +#if idx64 + EmitRexString(0x41, "0F B7 81"); // movzx eax, word ptr [r9 + 0x12345678] + Emit4(Constant4() & vm->dataMask); +#else + EmitString("B8"); // mov eax, 0x12345678 + EmitPtr(vm->dataBase + (Constant4() & vm->dataMask)); + EmitString("0F B7 00"); // movzx eax, word ptr [eax] +#endif + EmitCommand(LAST_COMMAND_MOV_STACK_EAX); // mov dword ptr [edi + ebx * 4], eax + + pc++; // OP_LOAD2 + instruction += 1; + return qtrue; + + case OP_LOAD1: + EmitPushStack(vm); +#if idx64 + EmitRexString(0x41, "0F B6 81"); // movzx eax, byte ptr [r9 + 0x12345678] + Emit4(Constant4() & vm->dataMask); +#else + EmitString("B8"); // mov eax, 0x12345678 + EmitPtr(vm->dataBase + (Constant4() & vm->dataMask)); + EmitString("0F B6 00"); // movzx eax, byte ptr [eax] +#endif + EmitCommand(LAST_COMMAND_MOV_STACK_EAX); // mov dword ptr [edi + ebx * 4], eax + + pc++; // OP_LOAD1 + instruction += 1; + return qtrue; + + case OP_STORE4: + EmitMovEAXStack(vm, (vm->dataMask & ~3)); +#if idx64 + EmitRexString(0x41, "C7 04 01"); // mov dword ptr [r9 + eax], 0x12345678 + Emit4(Constant4()); +#else + EmitString("C7 80"); // mov dword ptr [eax + 0x12345678], 0x12345678 + Emit4((intptr_t) vm->dataBase); + Emit4(Constant4()); +#endif + EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1 + pc++; // OP_STORE4 + instruction += 1; + return qtrue; + + case OP_STORE2: + EmitMovEAXStack(vm, (vm->dataMask & ~1)); +#if idx64 + Emit1(0x66); // mov word ptr [r9 + eax], 0x1234 + EmitRexString(0x41, "C7 04 01"); + Emit2(Constant4()); +#else + EmitString("66 C7 80"); // mov word ptr [eax + 0x12345678], 0x1234 + Emit4((intptr_t) vm->dataBase); + Emit2(Constant4()); +#endif + EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1 + + pc++; // OP_STORE2 + instruction += 1; + return qtrue; + + case OP_STORE1: + EmitMovEAXStack(vm, vm->dataMask); +#if idx64 + EmitRexString(0x41, "C6 04 01"); // mov byte [r9 + eax], 0x12 + Emit1(Constant4()); +#else + EmitString("C6 80"); // mov byte ptr [eax + 0x12345678], 0x12 + Emit4((intptr_t) vm->dataBase); + Emit1(Constant4()); +#endif + EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1 + + pc++; // OP_STORE1 + instruction += 1; + return qtrue; + + case OP_ADD: + v = Constant4(); + + EmitMovEAXStack(vm, 0); + if(iss8(v)) + { + EmitString("83 C0"); // add eax, 0x7F + Emit1(v); + } + else + { + EmitString("05"); // add eax, 0x12345678 + Emit4(v); + } + EmitCommand(LAST_COMMAND_MOV_STACK_EAX); + + pc++; // OP_ADD + instruction += 1; + return qtrue; + + case OP_SUB: + v = Constant4(); + + EmitMovEAXStack(vm, 0); + if(iss8(v)) + { + EmitString("83 E8"); // sub eax, 0x7F + Emit1(v); + } + else + { + EmitString("2D"); // sub eax, 0x12345678 + Emit4(v); + } + EmitCommand(LAST_COMMAND_MOV_STACK_EAX); + + pc++; // OP_SUB + instruction += 1; + return qtrue; + + case OP_MULI: + v = Constant4(); + + EmitMovEAXStack(vm, 0); + if(iss8(v)) + { + EmitString("6B C0"); // imul eax, 0x7F + Emit1(v); + } + else + { + EmitString("69 C0"); // imul eax, 0x12345678 + Emit4(v); + } + EmitCommand(LAST_COMMAND_MOV_STACK_EAX); + pc++; // OP_MULI + instruction += 1; + + return qtrue; + + case OP_LSH: + v = NextConstant4(); + if(v < 0 || v > 31) + break; + + EmitMovEAXStack(vm, 0); + EmitString("C1 E0"); // shl eax, 0x12 + Emit1(v); + EmitCommand(LAST_COMMAND_MOV_STACK_EAX); + + pc += 5; // CONST + OP_LSH + instruction += 1; + return qtrue; + + case OP_RSHI: + v = NextConstant4(); + if(v < 0 || v > 31) + break; + + EmitMovEAXStack(vm, 0); + EmitString("C1 F8"); // sar eax, 0x12 + Emit1(v); + EmitCommand(LAST_COMMAND_MOV_STACK_EAX); + + pc += 5; // CONST + OP_RSHI + instruction += 1; + return qtrue; + + case OP_RSHU: + v = NextConstant4(); + if(v < 0 || v > 31) + break; + + EmitMovEAXStack(vm, 0); + EmitString("C1 E8"); // shr eax, 0x12 + Emit1(v); + EmitCommand(LAST_COMMAND_MOV_STACK_EAX); + + pc += 5; // CONST + OP_RSHU + instruction += 1; + return qtrue; + + case OP_BAND: + v = Constant4(); + + EmitMovEAXStack(vm, 0); + if(iss8(v)) + { + EmitString("83 E0"); // and eax, 0x7F + Emit1(v); + } + else + { + EmitString("25"); // and eax, 0x12345678 + Emit4(v); + } + EmitCommand(LAST_COMMAND_MOV_STACK_EAX); + + pc += 1; // OP_BAND + instruction += 1; + return qtrue; + + case OP_BOR: + v = Constant4(); + + EmitMovEAXStack(vm, 0); + if(iss8(v)) + { + EmitString("83 C8"); // or eax, 0x7F + Emit1(v); + } + else + { + EmitString("0D"); // or eax, 0x12345678 + Emit4(v); + } + EmitCommand(LAST_COMMAND_MOV_STACK_EAX); + + pc += 1; // OP_BOR + instruction += 1; + return qtrue; + + case OP_BXOR: + v = Constant4(); + + EmitMovEAXStack(vm, 0); + if(iss8(v)) + { + EmitString("83 F0"); // xor eax, 0x7F + Emit1(v); + } + else + { + EmitString("35"); // xor eax, 0x12345678 + Emit4(v); + } + EmitCommand(LAST_COMMAND_MOV_STACK_EAX); + + pc += 1; // OP_BXOR + instruction += 1; + return qtrue; + + case OP_EQ: + case OP_NE: + case OP_LTI: + case OP_LEI: + case OP_GTI: + case OP_GEI: + case OP_LTU: + case OP_LEU: + case OP_GTU: + case OP_GEU: + EmitMovEAXStack(vm, 0); + EmitCommand(LAST_COMMAND_SUB_BL_1); + EmitString("3D"); // cmp eax, 0x12345678 + Emit4(Constant4()); + + pc++; // OP_* + EmitBranchConditions(vm, op1); + instruction++; + + return qtrue; + + case OP_EQF: + case OP_NEF: + if(NextConstant4()) + break; + pc += 5; // CONST + OP_EQF|OP_NEF + + EmitMovEAXStack(vm, 0); + EmitCommand(LAST_COMMAND_SUB_BL_1); + // floating point hack :) + EmitString("25"); // and eax, 0x7FFFFFFF + Emit4(0x7FFFFFFF); + if(op1 == OP_EQF) + EmitJumpIns(vm, "0F 84", Constant4()); // jz 0x12345678 + else + EmitJumpIns(vm, "0F 85", Constant4()); // jnz 0x12345678 + + instruction += 1; + return qtrue; + + + case OP_JUMP: + EmitJumpIns(vm, "E9", Constant4()); // jmp 0x12345678 + + pc += 1; // OP_JUMP + instruction += 1; + return qtrue; + + case OP_CALL: + v = Constant4(); + EmitCallConst(vm, v, callProcOfsSyscall); + + pc += 1; // OP_CALL + instruction += 1; + return qtrue; + + default: + break; + } + + return qfalse; +} + /* ================= VM_Compile ================= */ -void VM_Compile( vm_t *vm, vmHeader_t *header ) { +void VM_Compile(vm_t *vm, vmHeader_t *header) +{ int op; int maxLength; int v; int i; - qboolean opt; - int jusedSize = header->instructionCount + 2; + int callProcOfsSyscall, callProcOfs, callDoSyscallOfs; + + jusedSize = header->instructionCount + 2; // allocate a very large temp buffer, we will shrink it later - maxLength = header->codeLength * 8; + maxLength = header->codeLength * 8 + 64; buf = Z_Malloc(maxLength); jused = Z_Malloc(jusedSize); + code = Z_Malloc(header->codeLength+32); Com_Memset(jused, 0, jusedSize); + Com_Memset(buf, 0, maxLength); + + // copy code in larger buffer and put some zeros at the end + // so we can safely look ahead for a few instructions in it + // without a chance to get false-positive because of some garbage bytes + Com_Memset(code, 0, header->codeLength+32); + Com_Memcpy(code, (byte *)header + header->codeOffset, header->codeLength ); // ensure that the optimisation pass knows about all the jump // table targets @@ -443,7 +1102,15 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { jused[ *(int *)(vm->jumpTableTargets + ( i * sizeof( int ) ) ) ] = 1; } - for(pass=0;pass<2;pass++) { + // Start buffer with x86-VM specific procedures + compiledOfs = 0; + + callDoSyscallOfs = compiledOfs; + callProcOfs = EmitCallDoSyscall(vm); + callProcOfsSyscall = EmitCallProcedure(vm, callDoSyscallOfs); + vm->entryOfs = compiledOfs; + + for(pass=0; pass < 3; pass++) { oc0 = -23423; oc1 = -234354; pop0 = -43435; @@ -452,8 +1119,8 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { // translate all instructions pc = 0; instruction = 0; - code = (byte *)header + header->codeOffset; - compiledOfs = 0; + //code = (byte *)header + header->codeOffset; + compiledOfs = vm->entryOfs; LastCommand = LAST_COMMAND_NONE; @@ -466,6 +1133,12 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { } vm->instructionPointers[ instruction ] = compiledOfs; + + if ( !vm->jumpTableTargets ) + jlabel = 1; + else + jlabel = jused[ instruction ]; + instruction++; if(pc > header->codeLength) @@ -480,607 +1153,491 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { case 0: break; case OP_BREAK: - EmitString( "CC" ); // int 3 + EmitString("CC"); // int 3 break; case OP_ENTER: - EmitString( "81 EE" ); // sub esi, 0x12345678 - Emit4( Constant4() ); + EmitString("81 EE"); // sub esi, 0x12345678 + Emit4(Constant4()); break; case OP_CONST: - if (code[pc+4] == OP_LOAD4) { - EmitAddEDI4(vm); - EmitString( "BB" ); // mov ebx, 0x12345678 - Emit4( (Constant4()&vm->dataMask) + (int)vm->dataBase); - EmitString( "8B 03" ); // mov eax, dword ptr [ebx] - EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax - pc++; // OP_LOAD4 - instruction += 1; + if(ConstOptimize(vm, callProcOfsSyscall)) break; - } - if (code[pc+4] == OP_LOAD2) { - EmitAddEDI4(vm); - EmitString( "BB" ); // mov ebx, 0x12345678 - Emit4( (Constant4()&vm->dataMask) + (int)vm->dataBase); - EmitString( "0F B7 03" ); // movzx eax, word ptr [ebx] - EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax - pc++; // OP_LOAD4 - instruction += 1; - break; - } - if (code[pc+4] == OP_LOAD1) { - EmitAddEDI4(vm); - EmitString( "BB" ); // mov ebx, 0x12345678 - Emit4( (Constant4()&vm->dataMask) + (int)vm->dataBase); - EmitString( "0F B6 03" ); // movzx eax, byte ptr [ebx] - EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax - pc++; // OP_LOAD4 - instruction += 1; - break; - } - if (code[pc+4] == OP_STORE4) { - opt = EmitMovEBXEDI(vm, (vm->dataMask & ~3)); - EmitString( "B8" ); // mov eax, 0x12345678 - Emit4( Constant4() ); -// if (!opt) { -// EmitString( "81 E3" ); // and ebx, 0x12345678 -// Emit4( vm->dataMask & ~3 ); -// } - EmitString( "89 83" ); // mov dword ptr [ebx+0x12345678], eax - Emit4( (int)vm->dataBase ); - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - pc++; // OP_STORE4 - instruction += 1; - break; - } - if (code[pc+4] == OP_STORE2) { - opt = EmitMovEBXEDI(vm, (vm->dataMask & ~1)); - EmitString( "B8" ); // mov eax, 0x12345678 - Emit4( Constant4() ); -// if (!opt) { -// EmitString( "81 E3" ); // and ebx, 0x12345678 -// Emit4( vm->dataMask & ~1 ); -// } - EmitString( "66 89 83" ); // mov word ptr [ebx+0x12345678], eax - Emit4( (int)vm->dataBase ); - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - pc++; // OP_STORE4 - instruction += 1; - break; - } - if (code[pc+4] == OP_STORE1) { - opt = EmitMovEBXEDI(vm, vm->dataMask); - EmitString( "B8" ); // mov eax, 0x12345678 - Emit4( Constant4() ); -// if (!opt) { -// EmitString( "81 E3" ); // and ebx, 0x12345678 -// Emit4( vm->dataMask ); -// } - EmitString( "88 83" ); // mov byte ptr [ebx+0x12345678], eax - Emit4( (int)vm->dataBase ); - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - pc++; // OP_STORE4 - instruction += 1; - break; - } - if (code[pc+4] == OP_ADD) { - EmitString( "81 07" ); // add dword ptr [edi], 0x1234567 - Emit4( Constant4() ); - pc++; // OP_ADD - instruction += 1; - break; - } - if (code[pc+4] == OP_SUB) { - EmitString( "81 2F" ); // sub dword ptr [edi], 0x1234567 - Emit4( Constant4() ); - pc++; // OP_ADD - instruction += 1; - break; - } - EmitAddEDI4(vm); - EmitString( "C7 07" ); // mov dword ptr [edi], 0x12345678 + + EmitPushStack(vm); + EmitString("C7 04 9F"); // mov dword ptr [edi + ebx * 4], 0x12345678 lastConst = Constant4(); - Emit4( lastConst ); - if (code[pc] == OP_JUMP) { + + Emit4(lastConst); + if(code[pc] == OP_JUMP) JUSED(lastConst); - } + break; case OP_LOCAL: - EmitAddEDI4(vm); - EmitString( "8D 86" ); // lea eax, [0x12345678 + esi] + EmitPushStack(vm); + EmitString("8D 86"); // lea eax, [0x12345678 + esi] oc0 = oc1; oc1 = Constant4(); - Emit4( oc1 ); - EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax + Emit4(oc1); + EmitCommand(LAST_COMMAND_MOV_STACK_EAX); // mov dword ptr [edi + ebx * 4], eax break; case OP_ARG: - EmitMovEAXEDI(vm); // mov eax,dword ptr [edi] - EmitString( "89 86" ); // mov dword ptr [esi+database],eax - // FIXME: range check - Emit4( Constant1() + (int)vm->dataBase ); - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 + EmitMovEAXStack(vm, 0); // mov eax, dword ptr [edi + ebx * 4] + EmitString("8B D6"); // mov edx, esi + EmitString("81 C2"); // add edx, 0x12345678 + Emit4((Constant1() & 0xFF)); + MASK_REG("E2", vm->dataMask); // and edx, 0x12345678 +#if idx64 + EmitRexString(0x41, "89 04 11"); // mov dword ptr [r9 + edx], eax +#else + EmitString("89 82"); // mov dword ptr [edx + 0x12345678], eax + Emit4((intptr_t) vm->dataBase); +#endif + EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1 break; case OP_CALL: - EmitString( "C7 86" ); // mov dword ptr [esi+database],0x12345678 - Emit4( (int)vm->dataBase ); - Emit4( pc ); - EmitString( "FF 15" ); // call asmCallPtr - Emit4( (int)&asmCallPtr ); + EmitCallRel(vm, callProcOfs); break; case OP_PUSH: - EmitAddEDI4(vm); + EmitPushStack(vm); break; case OP_POP: - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 + EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1 break; case OP_LEAVE: v = Constant4(); - EmitString( "81 C6" ); // add esi, 0x12345678 - Emit4( v ); - EmitString( "C3" ); // ret + EmitString("81 C6"); // add esi, 0x12345678 + Emit4(v); + EmitString("C3"); // ret break; case OP_LOAD4: - if (code[pc] == OP_CONST && code[pc+5] == OP_ADD && code[pc+6] == OP_STORE4) { - if (oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) { - compiledOfs -= 11; - vm->instructionPointers[ instruction-1 ] = compiledOfs; + if (code[pc] == OP_CONST && code[pc+5] == OP_ADD && code[pc+6] == OP_STORE4) + { + if(oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) + { + compiledOfs -= 12; + vm->instructionPointers[instruction - 1] = compiledOfs; } - pc++; // OP_CONST + + pc++; // OP_CONST v = Constant4(); - EmitMovEBXEDI(vm, vm->dataMask); - if (v == 1 && oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) { - EmitString( "FF 83"); // inc dword ptr [ebx + 0x12345678] - Emit4( (int)vm->dataBase ); - } else { - EmitString( "8B 83" ); // mov eax, dword ptr [ebx + 0x12345678] - Emit4( (int)vm->dataBase ); - EmitString( "05" ); // add eax, const - Emit4( v ); - if (oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) { - EmitString( "89 83" ); // mov dword ptr [ebx+0x12345678], eax - Emit4( (int)vm->dataBase ); - } else { - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - EmitString( "8B 1F" ); // mov ebx, dword ptr [edi] - EmitString( "89 83" ); // mov dword ptr [ebx+0x12345678], eax - Emit4( (int)vm->dataBase ); + + EmitMovEDXStack(vm, vm->dataMask); + if(v == 1 && oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) + { +#if idx64 + EmitRexString(0x41, "FF 04 11"); // inc dword ptr [r9 + edx] +#else + EmitString("FF 82"); // inc dword ptr [edx + 0x12345678] + Emit4((intptr_t) vm->dataBase); +#endif + } + else + { +#if idx64 + EmitRexString(0x41, "8B 04 11"); // mov eax, dword ptr [r9 + edx] +#else + EmitString("8B 82"); // mov eax, dword ptr [edx + 0x12345678] + Emit4((intptr_t) vm->dataBase); +#endif + EmitString("05"); // add eax, v + Emit4(v); + + if (oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) + { +#if idx64 + EmitRexString(0x41, "89 04 11"); // mov dword ptr [r9 + edx], eax +#else + EmitString("89 82"); // mov dword ptr [edx + 0x12345678], eax + Emit4((intptr_t) vm->dataBase); +#endif + } + else + { + EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1 + EmitString("8B 14 9F"); // mov edx, dword ptr [edi + ebx * 4] + MASK_REG("E2", vm->dataMask); // and edx, 0x12345678 +#if idx64 + EmitRexString(0x41, "89 04 11"); // mov dword ptr [r9 + edx], eax +#else + EmitString("89 82"); // mov dword ptr [edx + 0x12345678], eax + Emit4((intptr_t) vm->dataBase); +#endif } } - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 + + EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1 pc++; // OP_ADD pc++; // OP_STORE instruction += 3; break; } - if (code[pc] == OP_CONST && code[pc+5] == OP_SUB && code[pc+6] == OP_STORE4) { - if (oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) { - compiledOfs -= 11; - vm->instructionPointers[ instruction-1 ] = compiledOfs; + if(code[pc] == OP_CONST && code[pc+5] == OP_SUB && code[pc+6] == OP_STORE4) + { + if(oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) + { + compiledOfs -= 12; + vm->instructionPointers[instruction - 1] = compiledOfs; } - EmitMovEBXEDI(vm, vm->dataMask); - EmitString( "8B 83" ); // mov eax, dword ptr [ebx + 0x12345678] - Emit4( (int)vm->dataBase ); - pc++; // OP_CONST + + pc++; // OP_CONST v = Constant4(); - if (v == 1 && oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) { - EmitString( "FF 8B"); // dec dword ptr [ebx + 0x12345678] - Emit4( (int)vm->dataBase ); - } else { - EmitString( "2D" ); // sub eax, const - Emit4( v ); - if (oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) { - EmitString( "89 83" ); // mov dword ptr [ebx+0x12345678], eax - Emit4( (int)vm->dataBase ); - } else { - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - EmitString( "8B 1F" ); // mov ebx, dword ptr [edi] - EmitString( "89 83" ); // mov dword ptr [ebx+0x12345678], eax - Emit4( (int)vm->dataBase ); + + EmitMovEDXStack(vm, vm->dataMask); + if(v == 1 && oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) + { +#if idx64 + EmitRexString(0x41, "FF 0C 11"); // dec dword ptr [r9 + edx] +#else + EmitString("FF 8A"); // dec dword ptr [edx + 0x12345678] + Emit4((intptr_t) vm->dataBase); +#endif + } + else + { +#if idx64 + EmitRexString(0x41, "8B 04 11"); // mov eax, dword ptr [r9 + edx] +#else + EmitString("8B 82"); // mov eax, dword ptr [edx + 0x12345678] + Emit4((intptr_t) vm->dataBase); +#endif + EmitString("2D"); // sub eax, v + Emit4(v); + + if(oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) + { +#if idx64 + EmitRexString(0x41, "89 04 11"); // mov dword ptr [r9 + edx], eax +#else + EmitString("89 82"); // mov dword ptr [edx + 0x12345678], eax + Emit4((intptr_t) vm->dataBase); +#endif + } + else + { + EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1 + EmitString("8B 14 9F"); // mov edx, dword ptr [edi + ebx * 4] + MASK_REG("E2", vm->dataMask); // and edx, 0x12345678 +#if idx64 + EmitRexString(0x41, "89 04 11"); // mov dword ptr [r9 + edx], eax +#else + EmitString("89 82"); // mov dword ptr [edx + 0x12345678], eax + Emit4((intptr_t) vm->dataBase); +#endif } } - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 + EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1 pc++; // OP_SUB pc++; // OP_STORE instruction += 3; break; } - if (buf[compiledOfs-2] == 0x89 && buf[compiledOfs-1] == 0x07) { - compiledOfs -= 2; - vm->instructionPointers[ instruction-1 ] = compiledOfs; - EmitString( "8B 80"); // mov eax, dword ptr [eax + 0x1234567] - Emit4( (int)vm->dataBase ); - EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax + if(buf[compiledOfs - 3] == 0x89 && buf[compiledOfs - 2] == 0x04 && buf[compiledOfs - 1] == 0x9F) + { + compiledOfs -= 3; + vm->instructionPointers[instruction - 1] = compiledOfs; + MASK_REG("E0", vm->dataMask); // and eax, 0x12345678 +#if idx64 + EmitRexString(0x41, "8B 04 01"); // mov eax, dword ptr [r9 + eax] +#else + EmitString("8B 80"); // mov eax, dword ptr [eax + 0x1234567] + Emit4((intptr_t) vm->dataBase); +#endif + EmitCommand(LAST_COMMAND_MOV_STACK_EAX); // mov dword ptr [edi + ebx * 4], eax break; } - EmitMovEBXEDI(vm, vm->dataMask); - EmitString( "8B 83" ); // mov eax, dword ptr [ebx + 0x12345678] - Emit4( (int)vm->dataBase ); - EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax + + EmitMovEAXStack(vm, vm->dataMask); +#if idx64 + EmitRexString(0x41, "8B 04 01"); // mov eax, dword ptr [r9 + eax] +#else + EmitString("8B 80"); // mov eax, dword ptr [eax + 0x12345678] + Emit4((intptr_t) vm->dataBase); +#endif + EmitCommand(LAST_COMMAND_MOV_STACK_EAX); // mov dword ptr [edi + ebx * 4], eax break; case OP_LOAD2: - EmitMovEBXEDI(vm, vm->dataMask); - EmitString( "0F B7 83" ); // movzx eax, word ptr [ebx + 0x12345678] - Emit4( (int)vm->dataBase ); - EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax + EmitMovEAXStack(vm, vm->dataMask); +#if idx64 + EmitRexString(0x41, "0F B7 04 01"); // movzx eax, word ptr [r9 + eax] +#else + EmitString("0F B7 80"); // movzx eax, word ptr [eax + 0x12345678] + Emit4((intptr_t) vm->dataBase); +#endif + EmitCommand(LAST_COMMAND_MOV_STACK_EAX); // mov dword ptr [edi + ebx * 4], eax break; case OP_LOAD1: - EmitMovEBXEDI(vm, vm->dataMask); - EmitString( "0F B6 83" ); // movzx eax, byte ptr [ebx + 0x12345678] - Emit4( (int)vm->dataBase ); - EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax + EmitMovEAXStack(vm, vm->dataMask); +#if idx64 + EmitRexString(0x41, "0F B6 04 01"); // movzx eax, byte ptr [r9 + eax] +#else + EmitString("0F B6 80"); // movzx eax, byte ptr [eax + 0x12345678] + Emit4((intptr_t) vm->dataBase); +#endif + EmitCommand(LAST_COMMAND_MOV_STACK_EAX); // mov dword ptr [edi + ebx * 4], eax break; case OP_STORE4: - EmitMovEAXEDI(vm); - EmitString( "8B 5F FC" ); // mov ebx, dword ptr [edi-4] -// if (pop1 != OP_CALL) { -// EmitString( "81 E3" ); // and ebx, 0x12345678 -// Emit4( vm->dataMask & ~3 ); -// } - EmitString( "89 83" ); // mov dword ptr [ebx+0x12345678], eax - Emit4( (int)vm->dataBase ); - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 + EmitMovEAXStack(vm, 0); + EmitString("8B 54 9F FC"); // mov edx, dword ptr -4[edi + ebx * 4] + MASK_REG("E2", vm->dataMask & ~3); // and edx, 0x12345678 +#if idx64 + EmitRexString(0x41, "89 04 11"); // mov dword ptr [r9 + edx], eax +#else + EmitString("89 82"); // mov dword ptr [edx + 0x12345678], eax + Emit4((intptr_t) vm->dataBase); +#endif + EmitCommand(LAST_COMMAND_SUB_BL_2); // sub bl, 2 break; case OP_STORE2: - EmitMovEAXEDI(vm); - EmitString( "8B 5F FC" ); // mov ebx, dword ptr [edi-4] -// EmitString( "81 E3" ); // and ebx, 0x12345678 -// Emit4( vm->dataMask & ~1 ); - EmitString( "66 89 83" ); // mov word ptr [ebx+0x12345678], eax - Emit4( (int)vm->dataBase ); - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 + EmitMovEAXStack(vm, 0); + EmitString("8B 54 9F FC"); // mov edx, dword ptr -4[edi + ebx * 4] + MASK_REG("E2", vm->dataMask & ~1); // and edx, 0x12345678 +#if idx64 + Emit1(0x66); // mov word ptr [r9 + edx], eax + EmitRexString(0x41, "89 04 11"); +#else + EmitString("66 89 82"); // mov word ptr [edx + 0x12345678], eax + Emit4((intptr_t) vm->dataBase); +#endif + EmitCommand(LAST_COMMAND_SUB_BL_2); // sub bl, 2 break; case OP_STORE1: - EmitMovEAXEDI(vm); - EmitString( "8B 5F FC" ); // mov ebx, dword ptr [edi-4] -// EmitString( "81 E3" ); // and ebx, 0x12345678 -// Emit4( vm->dataMask ); - EmitString( "88 83" ); // mov byte ptr [ebx+0x12345678], eax - Emit4( (int)vm->dataBase ); - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 + EmitMovEAXStack(vm, 0); + EmitString("8B 54 9F FC"); // mov edx, dword ptr -4[edi + ebx * 4] + MASK_REG("E2", vm->dataMask); // and edx, 0x12345678 +#if idx64 + EmitRexString(0x41, "88 04 11"); // mov byte ptr [r9 + edx], eax +#else + EmitString("88 82"); // mov byte ptr [edx + 0x12345678], eax + Emit4((intptr_t) vm->dataBase); +#endif + EmitCommand(LAST_COMMAND_SUB_BL_2); // sub bl, 2 break; case OP_EQ: - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4] - EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8] - EmitString( "75 06" ); // jne +6 - EmitString( "FF 25" ); // jmp [0x12345678] - v = Constant4(); - JUSED(v); - Emit4( (int)vm->instructionPointers + v*4 ); - break; case OP_NE: - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4] - EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8] - EmitString( "74 06" ); // je +6 - EmitString( "FF 25" ); // jmp [0x12345678] - v = Constant4(); - JUSED(v); - Emit4( (int)vm->instructionPointers + v*4 ); - break; case OP_LTI: - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4] - EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8] - EmitString( "7D 06" ); // jnl +6 - EmitString( "FF 25" ); // jmp [0x12345678] - v = Constant4(); - JUSED(v); - Emit4( (int)vm->instructionPointers + v*4 ); - break; case OP_LEI: - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4] - EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8] - EmitString( "7F 06" ); // jnle +6 - EmitString( "FF 25" ); // jmp [0x12345678] - v = Constant4(); - JUSED(v); - Emit4( (int)vm->instructionPointers + v*4 ); - break; case OP_GTI: - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4] - EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8] - EmitString( "7E 06" ); // jng +6 - EmitString( "FF 25" ); // jmp [0x12345678] - v = Constant4(); - JUSED(v); - Emit4( (int)vm->instructionPointers + v*4 ); - break; case OP_GEI: - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4] - EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8] - EmitString( "7C 06" ); // jnge +6 - EmitString( "FF 25" ); // jmp [0x12345678] - v = Constant4(); - JUSED(v); - Emit4( (int)vm->instructionPointers + v*4 ); - break; case OP_LTU: - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4] - EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8] - EmitString( "73 06" ); // jnb +6 - EmitString( "FF 25" ); // jmp [0x12345678] - v = Constant4(); - JUSED(v); - Emit4( (int)vm->instructionPointers + v*4 ); - break; case OP_LEU: - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4] - EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8] - EmitString( "77 06" ); // jnbe +6 - EmitString( "FF 25" ); // jmp [0x12345678] - v = Constant4(); - JUSED(v); - Emit4( (int)vm->instructionPointers + v*4 ); - break; case OP_GTU: - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4] - EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8] - EmitString( "76 06" ); // jna +6 - EmitString( "FF 25" ); // jmp [0x12345678] - v = Constant4(); - JUSED(v); - Emit4( (int)vm->instructionPointers + v*4 ); - break; case OP_GEU: - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4] - EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8] - EmitString( "72 06" ); // jnae +6 - EmitString( "FF 25" ); // jmp [0x12345678] - v = Constant4(); - JUSED(v); - Emit4( (int)vm->instructionPointers + v*4 ); - break; + EmitMovEAXStack(vm, 0); + EmitCommand(LAST_COMMAND_SUB_BL_2); // sub bl, 2 + EmitString("39 44 9F 04"); // cmp eax, dword ptr 4[edi + ebx * 4] + + EmitBranchConditions(vm, op); + break; case OP_EQF: - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - EmitString( "D9 47 04" ); // fld dword ptr [edi+4] - EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8] - EmitString( "DF E0" ); // fnstsw ax - EmitString( "F6 C4 40" ); // test ah,0x40 - EmitString( "74 06" ); // je +6 - EmitString( "FF 25" ); // jmp [0x12345678] - v = Constant4(); - JUSED(v); - Emit4( (int)vm->instructionPointers + v*4 ); - break; case OP_NEF: - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - EmitString( "D9 47 04" ); // fld dword ptr [edi+4] - EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8] - EmitString( "DF E0" ); // fnstsw ax - EmitString( "F6 C4 40" ); // test ah,0x40 - EmitString( "75 06" ); // jne +6 - EmitString( "FF 25" ); // jmp [0x12345678] - v = Constant4(); - JUSED(v); - Emit4( (int)vm->instructionPointers + v*4 ); - break; case OP_LTF: - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - EmitString( "D9 47 04" ); // fld dword ptr [edi+4] - EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8] - EmitString( "DF E0" ); // fnstsw ax - EmitString( "F6 C4 01" ); // test ah,0x01 - EmitString( "74 06" ); // je +6 - EmitString( "FF 25" ); // jmp [0x12345678] - v = Constant4(); - JUSED(v); - Emit4( (int)vm->instructionPointers + v*4 ); - break; case OP_LEF: - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - EmitString( "D9 47 04" ); // fld dword ptr [edi+4] - EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8] - EmitString( "DF E0" ); // fnstsw ax - EmitString( "F6 C4 41" ); // test ah,0x41 - EmitString( "74 06" ); // je +6 - EmitString( "FF 25" ); // jmp [0x12345678] - v = Constant4(); - JUSED(v); - Emit4( (int)vm->instructionPointers + v*4 ); - break; case OP_GTF: - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - EmitString( "D9 47 04" ); // fld dword ptr [edi+4] - EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8] - EmitString( "DF E0" ); // fnstsw ax - EmitString( "F6 C4 41" ); // test ah,0x41 - EmitString( "75 06" ); // jne +6 - EmitString( "FF 25" ); // jmp [0x12345678] - v = Constant4(); - JUSED(v); - Emit4( (int)vm->instructionPointers + v*4 ); - break; case OP_GEF: - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - EmitString( "D9 47 04" ); // fld dword ptr [edi+4] - EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8] - EmitString( "DF E0" ); // fnstsw ax - EmitString( "F6 C4 01" ); // test ah,0x01 - EmitString( "75 06" ); // jne +6 - EmitString( "FF 25" ); // jmp [0x12345678] - v = Constant4(); - JUSED(v); - Emit4( (int)vm->instructionPointers + v*4 ); - break; + EmitCommand(LAST_COMMAND_SUB_BL_2); // sub bl, 2 + EmitString("D9 44 9F 04"); // fld dword ptr 4[edi + ebx * 4] + EmitString("D8 5C 9F 08"); // fcomp dword ptr 8[edi + ebx * 4] + EmitString("DF E0"); // fnstsw ax + + switch(op) + { + case OP_EQF: + EmitString("F6 C4 40"); // test ah,0x40 + EmitJumpIns(vm, "0F 85", Constant4()); // jne 0x12345678 + break; + case OP_NEF: + EmitString("F6 C4 40"); // test ah,0x40 + EmitJumpIns(vm, "0F 84", Constant4()); // je 0x12345678 + break; + case OP_LTF: + EmitString("F6 C4 01"); // test ah,0x01 + EmitJumpIns(vm, "0F 85", Constant4()); // jne 0x12345678 + break; + case OP_LEF: + EmitString("F6 C4 41"); // test ah,0x41 + EmitJumpIns(vm, "0F 85", Constant4()); // jne 0x12345678 + break; + case OP_GTF: + EmitString("F6 C4 41"); // test ah,0x41 + EmitJumpIns(vm, "0F 84", Constant4()); // je 0x12345678 + break; + case OP_GEF: + EmitString("F6 C4 01"); // test ah,0x01 + EmitJumpIns(vm, "0F 84", Constant4()); // je 0x12345678 + break; + } + break; case OP_NEGI: - EmitString( "F7 1F" ); // neg dword ptr [edi] + EmitMovEAXStack(vm, 0); + EmitString("F7 D8"); // neg eax + EmitCommand(LAST_COMMAND_MOV_STACK_EAX); break; case OP_ADD: - EmitMovEAXEDI(vm); // mov eax, dword ptr [edi] - EmitString( "01 47 FC" ); // add dword ptr [edi-4],eax - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 + EmitMovEAXStack(vm, 0); // mov eax, dword ptr [edi + ebx * 4] + EmitString("01 44 9F FC"); // add dword ptr -4[edi + ebx * 4], eax + EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1 break; case OP_SUB: - EmitMovEAXEDI(vm); // mov eax, dword ptr [edi] - EmitString( "29 47 FC" ); // sub dword ptr [edi-4],eax - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 + EmitMovEAXStack(vm, 0); // mov eax, dword ptr [edi + ebx * 4] + EmitString("29 44 9F FC"); // sub dword ptr -4[edi + ebx * 4], eax + EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1 break; case OP_DIVI: - EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4] - EmitString( "99" ); // cdq - EmitString( "F7 3F" ); // idiv dword ptr [edi] - EmitString( "89 47 FC" ); // mov dword ptr [edi-4],eax - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 + EmitString("8B 44 9F FC"); // mov eax,dword ptr -4[edi + ebx * 4] + EmitString("99"); // cdq + EmitString("F7 3C 9F"); // idiv dword ptr [edi + ebx * 4] + EmitString("89 44 9F FC"); // mov dword ptr -4[edi + ebx * 4],eax + EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1 break; case OP_DIVU: - EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4] - EmitString( "33 D2" ); // xor edx, edx - EmitString( "F7 37" ); // div dword ptr [edi] - EmitString( "89 47 FC" ); // mov dword ptr [edi-4],eax - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 + EmitString("8B 44 9F FC"); // mov eax,dword ptr -4[edi + ebx * 4] + EmitString("33 D2"); // xor edx, edx + EmitString("F7 34 9F"); // div dword ptr [edi + ebx * 4] + EmitString("89 44 9F FC"); // mov dword ptr -4[edi + ebx * 4],eax + EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1 break; case OP_MODI: - EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4] - EmitString( "99" ); // cdq - EmitString( "F7 3F" ); // idiv dword ptr [edi] - EmitString( "89 57 FC" ); // mov dword ptr [edi-4],edx - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 + EmitString("8B 44 9F FC"); // mov eax,dword ptr -4[edi + ebx * 4] + EmitString("99" ); // cdq + EmitString("F7 3C 9F"); // idiv dword ptr [edi + ebx * 4] + EmitString("89 54 9F FC"); // mov dword ptr -4[edi + ebx * 4],edx + EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1 break; case OP_MODU: - EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4] - EmitString( "33 D2" ); // xor edx, edx - EmitString( "F7 37" ); // div dword ptr [edi] - EmitString( "89 57 FC" ); // mov dword ptr [edi-4],edx - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 + EmitString("8B 44 9F FC"); // mov eax,dword ptr -4[edi + ebx * 4] + EmitString("33 D2"); // xor edx, edx + EmitString("F7 34 9F"); // div dword ptr [edi + ebx * 4] + EmitString("89 54 9F FC"); // mov dword ptr -4[edi + ebx * 4],edx + EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1 break; case OP_MULI: - EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4] - EmitString( "F7 2F" ); // imul dword ptr [edi] - EmitString( "89 47 FC" ); // mov dword ptr [edi-4],eax - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 + EmitString("8B 44 9F FC"); // mov eax,dword ptr -4[edi + ebx * 4] + EmitString("F7 2C 9F"); // imul dword ptr [edi + ebx * 4] + EmitString("89 44 9F FC"); // mov dword ptr -4[edi + ebx * 4],eax + EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1 break; case OP_MULU: - EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4] - EmitString( "F7 27" ); // mul dword ptr [edi] - EmitString( "89 47 FC" ); // mov dword ptr [edi-4],eax - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 + EmitString("8B 44 9F FC"); // mov eax,dword ptr -4[edi + ebx * 4] + EmitString("F7 24 9F"); // mul dword ptr [edi + ebx * 4] + EmitString("89 44 9F FC"); // mov dword ptr -4[edi + ebx * 4],eax + EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1 break; case OP_BAND: - EmitMovEAXEDI(vm); // mov eax, dword ptr [edi] - EmitString( "21 47 FC" ); // and dword ptr [edi-4],eax - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 + EmitMovEAXStack(vm, 0); // mov eax, dword ptr [edi + ebx * 4] + EmitString("21 44 9F FC"); // and dword ptr -4[edi + ebx * 4],eax + EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1 break; case OP_BOR: - EmitMovEAXEDI(vm); // mov eax, dword ptr [edi] - EmitString( "09 47 FC" ); // or dword ptr [edi-4],eax - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 + EmitMovEAXStack(vm, 0); // mov eax, dword ptr [edi + ebx * 4] + EmitString("09 44 9F FC"); // or dword ptr -4[edi + ebx * 4],eax + EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1 break; case OP_BXOR: - EmitMovEAXEDI(vm); // mov eax, dword ptr [edi] - EmitString( "31 47 FC" ); // xor dword ptr [edi-4],eax - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 + EmitMovEAXStack(vm, 0); // mov eax, dword ptr [edi + ebx * 4] + EmitString("31 44 9F FC"); // xor dword ptr -4[edi + ebx * 4],eax + EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1 break; case OP_BCOM: - EmitString( "F7 17" ); // not dword ptr [edi] + EmitString("F7 14 9F"); // not dword ptr [edi + ebx * 4] break; case OP_LSH: - EmitString( "8B 0F" ); // mov ecx, dword ptr [edi] - EmitString( "D3 67 FC" ); // shl dword ptr [edi-4], cl - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 + EmitMovECXStack(vm); + EmitString("D3 64 9F FC"); // shl dword ptr -4[edi + ebx * 4], cl + EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1 break; case OP_RSHI: - EmitString( "8B 0F" ); // mov ecx, dword ptr [edi] - EmitString( "D3 7F FC" ); // sar dword ptr [edi-4], cl - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 + EmitMovECXStack(vm); + EmitString("D3 7C 9F FC"); // sar dword ptr -4[edi + ebx * 4], cl + EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1 break; case OP_RSHU: - EmitString( "8B 0F" ); // mov ecx, dword ptr [edi] - EmitString( "D3 6F FC" ); // shr dword ptr [edi-4], cl - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 + EmitMovECXStack(vm); + EmitString("D3 6C 9F FC"); // shr dword ptr -4[edi + ebx * 4], cl + EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1 break; case OP_NEGF: - EmitString( "D9 07" ); // fld dword ptr [edi] - EmitString( "D9 E0" ); // fchs - EmitString( "D9 1F" ); // fstp dword ptr [edi] + EmitString("D9 04 9F"); // fld dword ptr [edi + ebx * 4] + EmitString("D9 E0"); // fchs + EmitString("D9 1C 9F"); // fstp dword ptr [edi + ebx * 4] break; case OP_ADDF: - EmitString( "D9 47 FC" ); // fld dword ptr [edi-4] - EmitString( "D8 07" ); // fadd dword ptr [edi] - EmitString( "D9 5F FC" ); // fstp dword ptr [edi-4] - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 + EmitString("D9 44 9F FC"); // fld dword ptr -4[edi + ebx * 4] + EmitString("D8 04 9F"); // fadd dword ptr [edi + ebx * 4] + EmitString("D9 5C 9F FC"); // fstp dword ptr -4[edi + ebx * 4] + EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1 break; case OP_SUBF: - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - EmitString( "D9 07" ); // fld dword ptr [edi] - EmitString( "D8 67 04" ); // fsub dword ptr [edi+4] - EmitString( "D9 1F" ); // fstp dword ptr [edi] + EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1 + EmitString("D9 04 9F"); // fld dword ptr [edi + ebx * 4] + EmitString("D8 64 9F 04"); // fsub dword ptr 4[edi + ebx * 4] + EmitString("D9 1C 9F"); // fstp dword ptr [edi + ebx * 4] break; case OP_DIVF: - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - EmitString( "D9 07" ); // fld dword ptr [edi] - EmitString( "D8 77 04" ); // fdiv dword ptr [edi+4] - EmitString( "D9 1F" ); // fstp dword ptr [edi] + EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1 + EmitString("D9 04 9F"); // fld dword ptr [edi + ebx * 4] + EmitString("D8 74 9F 04"); // fdiv dword ptr 4[edi + ebx * 4] + EmitString("D9 1C 9F"); // fstp dword ptr [edi + ebx * 4] break; case OP_MULF: - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - EmitString( "D9 07" ); // fld dword ptr [edi] - EmitString( "D8 4f 04" ); // fmul dword ptr [edi+4] - EmitString( "D9 1F" ); // fstp dword ptr [edi] + EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1 + EmitString("D9 04 9F"); // fld dword ptr [edi + ebx * 4] + EmitString("D8 4C 9F 04"); // fmul dword ptr 4[edi + ebx * 4] + EmitString("D9 1C 9F"); // fstp dword ptr [edi + ebx * 4] break; case OP_CVIF: - EmitString( "DB 07" ); // fild dword ptr [edi] - EmitString( "D9 1F" ); // fstp dword ptr [edi] + EmitString("DB 04 9F"); // fild dword ptr [edi + ebx * 4] + EmitString("D9 1C 9F"); // fstp dword ptr [edi + ebx * 4] break; case OP_CVFI: #ifndef FTOL_PTR // WHENHELLISFROZENOVER // not IEEE complient, but simple and fast - EmitString( "D9 07" ); // fld dword ptr [edi] - EmitString( "DB 1F" ); // fistp dword ptr [edi] + EmitString("D9 04 9F"); // fld dword ptr [edi + ebx * 4] + EmitString("DB 1C 9F"); // fistp dword ptr [edi + ebx * 4] #else // FTOL_PTR // call the library conversion function - EmitString( "D9 07" ); // fld dword ptr [edi] - EmitString( "FF 15" ); // call ftolPtr - Emit4( (int)&ftolPtr ); - EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax + EmitRexString(0x48, "BA"); // mov edx, Q_VMftol + EmitPtr(Q_VMftol); + EmitRexString(0x48, "FF D2"); // call edx + EmitCommand(LAST_COMMAND_MOV_STACK_EAX); // mov dword ptr [edi + ebx * 4], eax #endif break; case OP_SEX8: - EmitString( "0F BE 07" ); // movsx eax, byte ptr [edi] - EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax + EmitString("0F BE 04 9F"); // movsx eax, byte ptr [edi + ebx * 4] + EmitCommand(LAST_COMMAND_MOV_STACK_EAX); // mov dword ptr [edi + ebx * 4], eax break; case OP_SEX16: - EmitString( "0F BF 07" ); // movsx eax, word ptr [edi] - EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax + EmitString("0F BF 04 9F"); // movsx eax, word ptr [edi + ebx * 4] + EmitCommand(LAST_COMMAND_MOV_STACK_EAX); // mov dword ptr [edi + ebx * 4], eax break; case OP_BLOCK_COPY: - // FIXME: range check - EmitString( "56" ); // push esi - EmitString( "57" ); // push edi - EmitString( "8B 37" ); // mov esi,[edi] - EmitString( "8B 7F FC" ); // mov edi,[edi-4] - EmitString( "B9" ); // mov ecx,0x12345678 - Emit4( Constant4() >> 2 ); - EmitString( "B8" ); // mov eax, datamask - Emit4( vm->dataMask ); - EmitString( "BB" ); // mov ebx, database - Emit4( (int)vm->dataBase ); - EmitString( "23 F0" ); // and esi, eax - EmitString( "03 F3" ); // add esi, ebx - EmitString( "23 F8" ); // and edi, eax - EmitString( "03 FB" ); // add edi, ebx - EmitString( "F3 A5" ); // rep movsd - EmitString( "5F" ); // pop edi - EmitString( "5E" ); // pop esi - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 + EmitString("B8"); // mov eax, 0x12345678 + Emit4(VM_BLOCK_COPY); + EmitString("B9"); // mov ecx, 0x12345678 + Emit4(Constant4()); + + EmitCallRel(vm, callDoSyscallOfs); + + EmitCommand(LAST_COMMAND_SUB_BL_2); // sub bl, 2 break; case OP_JUMP: - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - EmitString( "8B 47 04" ); // mov eax,dword ptr [edi+4] - // FIXME: range check - EmitString( "FF 24 85" ); // jmp dword ptr [instructionPointers + eax * 4] - Emit4( (int)vm->instructionPointers ); + EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1 + EmitString("8B 44 9F 04"); // mov eax, dword ptr 4[edi + ebx * 4] + EmitString("81 F8"); // cmp eax, vm->instructionCount + Emit4(vm->instructionCount); +#if idx64 + EmitString("73 04"); // jae +4 + EmitRexString(0x49, "FF 24 C0"); // jmp qword ptr [r8 + eax * 8] +#else + EmitString("73 07"); // jae +7 + EmitString("FF 24 85"); // jmp dword ptr [instructionPointers + eax * 4] + Emit4((intptr_t) vm->instructionPointers); +#endif + EmitCallErrJump(vm, callDoSyscallOfs); break; default: VMFREE_BUFFERS(); @@ -1091,7 +1648,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { } } - // copy to an exact size buffer on the hunk + // copy to an exact sized buffer with the appropriate permission bits vm->codeLength = compiledOfs; #ifdef VM_X86_MMAP vm->codeBase = mmap(NULL, compiledOfs, PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); @@ -1104,6 +1661,8 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { Com_Error(ERR_FATAL, "VM_CompileX86: VirtualAlloc failed"); #else vm->codeBase = malloc(compiledOfs); + if(!vm->codeBase) + Com_Error(ERR_FATAL, "VM_CompileX86: malloc failed"); #endif Com_Memcpy( vm->codeBase, buf, compiledOfs ); @@ -1121,6 +1680,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { } #endif + Z_Free( code ); Z_Free( buf ); Z_Free( jused ); Com_Printf( "VM file %s compiled to %i bytes of code\n", vm->name, compiledOfs ); @@ -1129,7 +1689,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { // offset all the instruction pointers for the new location for ( i = 0 ; i < header->instructionCount ; i++ ) { - vm->instructionPointers[i] += (int)vm->codeBase; + vm->instructionPointers[i] += (intptr_t) vm->codeBase; } } @@ -1151,28 +1711,24 @@ VM_CallCompiled This function is called directly by the generated code ============== */ -int VM_CallCompiled( vm_t *vm, int *args ) { - int stack[1024]; - int programCounter; - int programStack; - int stackOnEntry; - byte *image; - void *opStack; - int *oldInstructionPointers; - oldInstructionPointers = instructionPointers; +int VM_CallCompiled(vm_t *vm, int *args) +{ + byte stack[OPSTACK_SIZE + 15]; + void *entryPoint; + int programCounter; + int programStack, stackOnEntry; + byte *image; + int *opStack; + int opStackOfs; currentVM = vm; - instructionPointers = vm->instructionPointers; // interpret the code vm->currentlyInterpreting = qtrue; - callMask = vm->dataMask; - // we might be called recursively, so this might not be the very top - programStack = vm->programStack; - stackOnEntry = programStack; + programStack = stackOnEntry = vm->programStack; // set up the stack frame image = vm->dataBase; @@ -1195,50 +1751,67 @@ int VM_CallCompiled( vm_t *vm, int *args ) { *(int *)&image[ programStack ] = -1; // will terminate the loop on return // off we go into generated code... - opStack = &stack; + entryPoint = vm->codeBase + vm->entryOfs; + opStack = PADP(stack, 16); + *opStack = 0xDEADBEEF; + opStackOfs = 0; - { #ifdef _MSC_VER - void *entryPoint = vm->codeBase; + #if idx64 + opStackOfs = qvmcall64(&programStack, opStack, vm->instructionPointers, vm->dataBase); + #else + __asm + { + pushad - __asm { - pushad - mov esi, programStack - mov edi, opStack - call entryPoint - mov programStack, esi - mov opStack, edi - popad - } + mov esi, dword ptr programStack + mov edi, dword ptr opStack + mov ebx, dword ptr opStackOfs + + call entryPoint + + mov dword ptr opStackOfs, ebx + mov dword ptr opStack, edi + mov dword ptr programStack, esi + + popad + } + #endif +#elif idx64 + __asm__ volatile( + "movq %5, %%rax\r\n" + "movq %3, %%r8\r\n" + "movq %4, %%r9\r\n" + "push %%r15\r\n" + "push %%r14\r\n" + "push %%r13\r\n" + "push %%r12\r\n" + "callq *%%rax\r\n" + "pop %%r12\r\n" + "pop %%r13\r\n" + "pop %%r14\r\n" + "pop %%r15\r\n" + : "+S" (programStack), "+D" (opStack), "+b" (opStackOfs) + : "g" (vm->instructionPointers), "g" (vm->dataBase), "g" (entryPoint) + : "cc", "memory", "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11" + ); #else - /* These registers are used as scratch registers and are destroyed after the - * call. Do not use clobber, so they can be used as input for the asm. */ - unsigned eax; - unsigned ebx; - unsigned ecx; - unsigned edx; - - __asm__ volatile( - "call *%6" - : "+S" (programStack), "+D" (opStack), - "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) - : "mr" (vm->codeBase) - : "cc", "memory" - ); + __asm__ volatile( + "calll *%3\r\n" + : "+S" (programStack), "+D" (opStack), "+b" (opStackOfs) + : "g" (entryPoint) + : "cc", "memory", "%eax", "%ecx", "%edx" + ); #endif - } - if ( opStack != &stack[1] ) { - Com_Error( ERR_DROP, "opStack corrupted in compiled code" ); - } - if ( programStack != stackOnEntry - 48 ) { - Com_Error( ERR_DROP, "programStack corrupted in compiled code" ); + if(opStackOfs != 1 || *opStack != 0xDEADBEEF) + { + Com_Error(ERR_DROP, "opStack corrupted in compiled code"); } + if(programStack != stackOnEntry - 48) + Com_Error(ERR_DROP, "programStack corrupted in compiled code"); vm->programStack = stackOnEntry; - // in case we were recursively called by another vm - instructionPointers = oldInstructionPointers; - - return *(int *)opStack; + return opStack[opStackOfs]; } diff --git a/reaction/code/qcommon/vm_x86_64.c b/reaction/code/qcommon/vm_x86_64.c index 789416cb..27d946f8 100644 --- a/reaction/code/qcommon/vm_x86_64.c +++ b/reaction/code/qcommon/vm_x86_64.c @@ -70,22 +70,23 @@ static void VM_Destroy_Compiled(vm_t* self); | +- r8 - eax scratch - ebx scratch - ecx scratch (required for shifts) - edx scratch (required for divisions) - rsi stack pointer (opStack) - rdi program frame pointer (programStack) - r8 pointer data (vm->dataBase) - r10 start of generated code + eax scratch + rbx/bl opStack offset + ecx scratch (required for shifts) + edx scratch (required for divisions) + rsi scratch + rdi program frame pointer (programStack) + r8 pointer data (vm->dataBase) + r9 opStack base (opStack) + r10 start of generated code */ -static int64_t CROSSCALL callAsmCall(int64_t callProgramStack, int64_t callSyscallNum) +static intptr_t CROSSCALL callAsmCall(intptr_t callProgramStack, int64_t callSyscallNum) { vm_t *savedVM; - int64_t ret = 0x77; - int64_t args[11]; + intptr_t ret = 0x77; + intptr_t args[11]; // int iargs[11]; int i; @@ -238,18 +239,41 @@ void emit(const char* fmt, ...) assemble_line(line, strlen(line)); } +#ifdef DEBUG_VM +#define RANGECHECK(reg, bytes) \ + emit("movl %%" #reg ", %%ecx"); \ + emit("andl $0x%x, %%ecx", vm->dataMask &~(bytes-1)); \ + emit("cmpl %%" #reg ", %%ecx"); \ + emit("jz rc_ok_i_%08x", instruction); \ + emit("movq $%"PRIu64", %%rax", (intptr_t) memviolation); \ + emit("callq *%%rax"); \ + emit("rc_ok_i_%08x:", instruction) +#elif 1 +// check is too expensive, so just confine memory access +#define RANGECHECK(reg, bytes) \ + emit("andl $0x%x, %%" #reg, vm->dataMask &~(bytes-1)) +#else +#define RANGECHECK(reg, bytes) +#endif + +#define STACK_PUSH(bytes) \ + emit("addb $0x%x, %%bl", bytes >> 2); \ + +#define STACK_POP(bytes) \ + emit("subb $0x%x, %%bl", bytes >> 2); \ + #define CHECK_INSTR_REG(reg) \ emit("cmpl $%u, %%"#reg, header->instructionCount); \ emit("jb jmp_ok_i_%08x", instruction); \ - emit("movq $%"PRIu64", %%rax", (uint64_t)jmpviolation); \ + emit("movq $%"PRIu64", %%rax", (intptr_t)jmpviolation); \ emit("callq *%%rax"); \ - emit("jmp_ok_i_%08x:", instruction); + emit("jmp_ok_i_%08x:", instruction) #define PREPARE_JMP(reg) \ - CHECK_INSTR_REG(reg) \ - emit("movq $%"PRIu64", %%rbx", (uint64_t)vm->instructionPointers); \ - emit("movl (%%rbx, %%rax, 4), %%eax"); \ - emit("addq %%r10, %%rax"); + CHECK_INSTR_REG(reg); \ + emit("movq $%"PRIu64", %%rsi", (intptr_t)vm->instructionPointers); \ + emit("movl (%%rsi, %%rax, 8), %%eax"); \ + emit("addq %%r10, %%rax") #define CHECK_INSTR(nr) \ do { if(nr < 0 || nr >= header->instructionCount) { \ @@ -258,10 +282,10 @@ void emit(const char* fmt, ...) "%s: jump target 0x%x out of range at offset %d", __func__, nr, pc ); \ } } while(0) -#define JMPIARG \ +#define JMPIARG() \ CHECK_INSTR(iarg); \ emit("movq $%"PRIu64", %%rax", vm->codeBase+vm->instructionPointers[iarg]); \ - emit("jmpq *%%rax"); + emit("jmpq *%%rax") #define CONST_OPTIMIZE #ifdef CONST_OPTIMIZE @@ -270,8 +294,8 @@ void emit(const char* fmt, ...) { \ got_const = 0; \ vm->instructionPointers[instruction-1] = assembler_get_code_size(); \ - emit("addq $4, %%rsi"); \ - emit("movl $%d, 0(%%rsi)", const_value); \ + STACK_PUSH(4); \ + emit("movl $%d, (%%r9, %%rbx, 4)", const_value); \ } #else #define MAYBE_EMIT_CONST() @@ -280,90 +304,73 @@ void emit(const char* fmt, ...) // integer compare and jump #define IJ(op) \ MAYBE_EMIT_CONST(); \ - emit("subq $8, %%rsi"); \ - emit("movl 4(%%rsi), %%eax"); \ - emit("cmpl 8(%%rsi), %%eax"); \ + STACK_POP(8); \ + emit("movl 4(%%r9, %%rbx, 4), %%eax"); \ + emit("cmpl 8(%%r9, %%rbx, 4), %%eax"); \ emit(op " i_%08x", instruction+1); \ - JMPIARG \ - neednilabel = 1; + JMPIARG(); \ + neednilabel = 1 #ifdef USE_X87 #define FJ(bits, op) \ MAYBE_EMIT_CONST(); \ - emit("subq $8, %%rsi");\ - emit("flds 4(%%rsi)");\ - emit("fcomps 8(%%rsi)");\ + STACK_POP(8); \ + emit("flds 4(%%r9, %%rbx, 4)");\ + emit("fcomps 8(%%r9, %%rbx, 4)");\ emit("fnstsw %%ax");\ emit("testb $" #bits ", %%ah");\ emit(op " i_%08x", instruction+1);\ - JMPIARG \ - neednilabel = 1; + JMPIARG(); \ + neednilabel = 1 #define XJ(x) #else #define FJ(x, y) #define XJ(op) \ MAYBE_EMIT_CONST(); \ - emit("subq $8, %%rsi");\ - emit("movss 4(%%rsi), %%xmm0");\ - emit("ucomiss 8(%%rsi), %%xmm0");\ + STACK_POP(8); \ + emit("movss 4(%%r9, %%rbx, 4), %%xmm0");\ + emit("ucomiss 8(%%r9, %%rbx, 4), %%xmm0");\ emit("jp i_%08x", instruction+1);\ emit(op " i_%08x", instruction+1);\ - JMPIARG \ - neednilabel = 1; + JMPIARG(); \ + neednilabel = 1 #endif #define SIMPLE(op) \ MAYBE_EMIT_CONST(); \ - emit("subq $4, %%rsi"); \ - emit("movl 4(%%rsi), %%eax"); \ - emit(op " %%eax, 0(%%rsi)"); + emit("movl (%%r9, %%rbx, 4), %%eax"); \ + STACK_POP(4); \ + emit(op " %%eax, (%%r9, %%rbx, 4)") #ifdef USE_X87 #define FSIMPLE(op) \ MAYBE_EMIT_CONST(); \ - emit("subq $4, %%rsi"); \ - emit("flds 0(%%rsi)"); \ - emit(op " 4(%%rsi)"); \ - emit("fstps 0(%%rsi)"); + STACK_POP(4); \ + emit("flds (%%r9, %%rbx, 4)"); \ + emit(op " 4(%%r9, %%rbx, 4)"); \ + emit("fstps (%%r9, %%rbx, 4)") #define XSIMPLE(op) #else #define FSIMPLE(op) #define XSIMPLE(op) \ MAYBE_EMIT_CONST(); \ - emit("subq $4, %%rsi"); \ - emit("movss 0(%%rsi), %%xmm0"); \ - emit(op " 4(%%rsi), %%xmm0"); \ - emit("movss %%xmm0, 0(%%rsi)"); + STACK_POP(4); \ + emit("movss (%%r9, %%rbx, 4), %%xmm0"); \ + emit(op " 4(%%r9, %%rbx, 4), %%xmm0"); \ + emit("movss %%xmm0, (%%r9, %%rbx, 4)") #endif #define SHIFT(op) \ MAYBE_EMIT_CONST(); \ - emit("subq $4, %%rsi"); \ - emit("movl 4(%%rsi), %%ecx"); \ - emit("movl 0(%%rsi), %%eax"); \ + STACK_POP(4); \ + emit("movl 4(%%r9, %%rbx, 4), %%ecx"); \ + emit("movl (%%r9, %%rbx, 4), %%eax"); \ emit(op " %%cl, %%eax"); \ - emit("movl %%eax, 0(%%rsi)"); - -#ifdef DEBUG_VM -#define RANGECHECK(reg, bytes) \ - emit("movl %%" #reg ", %%ecx"); \ - emit("andl $0x%x, %%ecx", vm->dataMask &~(bytes-1)); \ - emit("cmpl %%" #reg ", %%ecx"); \ - emit("jz rc_ok_i_%08x", instruction); \ - emit("movq $%"PRIu64", %%rax", (uint64_t)memviolation); \ - emit("callq *%%rax"); \ - emit("rc_ok_i_%08x:", instruction); -#elif 1 -// check is too expensive, so just confine memory access -#define RANGECHECK(reg, bytes) \ - emit("andl $0x%x, %%" #reg, vm->dataMask &~(bytes-1)); -#else -#define RANGECHECK(reg, bytes) -#endif + emit("movl %%eax, (%%r9, %%rbx, 4)") #ifdef DEBUG_VM #define NOTIMPL(x) \ - do { Com_Error(ERR_DROP, "instruction not implemented: %s\n", opnames[x]); } while(0) + do { Com_Error(ERR_DROP, "instruction not implemented: %s", opnames[x]); } while(0) #else #define NOTIMPL(x) \ do { Com_Printf(S_COLOR_RED "instruction not implemented: %x\n", x); vm->compiled = qfalse; return; } while(0) @@ -374,37 +381,28 @@ static void* getentrypoint(vm_t* vm) return vm->codeBase; } -static void CROSSCALL block_copy_vm(unsigned dest, unsigned src, unsigned count) -{ - unsigned dataMask = currentVM->dataMask; - - if ((dest & dataMask) != dest - || (src & dataMask) != src - || ((dest+count) & dataMask) != dest + count - || ((src+count) & dataMask) != src + count) - { - Com_Error(ERR_DROP, "OP_BLOCK_COPY out of range!\n"); - } - - memcpy(currentVM->dataBase+dest, currentVM->dataBase+src, count); -} - static void CROSSCALL eop(void) { - Com_Error(ERR_DROP, "end of program reached without return!\n"); + Com_Error(ERR_DROP, "End of program reached without return!"); exit(1); } static void CROSSCALL jmpviolation(void) { - Com_Error(ERR_DROP, "program tried to execute code outside VM\n"); + Com_Error(ERR_DROP, "Program tried to execute code outside VM"); exit(1); } #ifdef DEBUG_VM static void CROSSCALL memviolation(void) { - Com_Error(ERR_DROP, "program tried to access memory outside VM\n"); + Com_Error(ERR_DROP, "Program tried to access memory outside VM, or unaligned memory access"); + exit(1); +} + +static void CROSSCALL opstackviolation(void) +{ + Com_Error(ERR_DROP, "Program corrupted the VM opStack"); exit(1); } #endif @@ -535,23 +533,24 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { break; case OP_CALL: RANGECHECK(edi, 4); - emit("movl $%d, 0(%%r8, %%rdi, 1)", instruction+1); // save next instruction + emit("movl $%d, (%%r8, %%rdi, 1)", instruction+1); // save next instruction + if(got_const) { - if ((int)const_value < 0) - goto emit_do_syscall; - - CHECK_INSTR(const_value); - emit("movq $%"PRIu64", %%rax", vm->codeBase+vm->instructionPointers[const_value]); - emit("callq *%%rax"); - got_const = 0; - break; + if ((int) const_value >= 0) + { + CHECK_INSTR(const_value); + emit("movq $%"PRIu64", %%rax", vm->codeBase+vm->instructionPointers[const_value]); + emit("callq *%%rax"); + got_const = 0; + break; + } } else { MAYBE_EMIT_CONST(); - emit("movl 0(%%rsi), %%eax"); // get instr from stack - emit("subq $4, %%rsi"); + emit("movl (%%r9, %%rbx, 4), %%eax"); // get instr from stack + STACK_POP(4); emit("orl %%eax, %%eax"); emit("jl callSyscall%d", instruction); @@ -562,48 +561,45 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { emit("jmp i_%08x", instruction+1); emit("callSyscall%d:", instruction); } -emit_do_syscall: -// emit("fnsave 4(%%rsi)"); - emit("push %%rsi"); + +// emit("fnsave 4(%%r9, %%rsi, 1)"); emit("push %%rdi"); emit("push %%r8"); emit("push %%r9"); emit("push %%r10"); - emit("movq %%rsp, %%rbx"); // we need to align the stack pointer - emit("subq $8, %%rbx"); // | - emit("andq $127, %%rbx"); // | - emit("subq %%rbx, %%rsp"); // <-+ - emit("push %%rbx"); + emit("movq %%rsp, %%rsi"); // we need to align the stack pointer + emit("subq $8, %%rsi"); // | + emit("andq $127, %%rsi"); // | + emit("subq %%rsi, %%rsp"); // <-+ + emit("push %%rsi"); if(got_const) { got_const = 0; emit("movq $%u, %%rsi", -1-const_value); // second argument in rsi } else { - emit("negl %%eax"); // convert to actual number - emit("decl %%eax"); + emit("notl %%eax"); // convert to actual number // first argument already in rdi emit("movq %%rax, %%rsi"); // second argument in rsi } - emit("movq $%"PRIu64", %%rax", (uint64_t)callAsmCall); + emit("movq $%"PRIu64", %%rax", (intptr_t) callAsmCall); emit("callq *%%rax"); - emit("pop %%rbx"); - emit("addq %%rbx, %%rsp"); + emit("pop %%rsi"); + emit("addq %%rsi, %%rsp"); emit("pop %%r10"); emit("pop %%r9"); emit("pop %%r8"); emit("pop %%rdi"); - emit("pop %%rsi"); -// emit("frstor 4(%%rsi)"); - emit("addq $4, %%rsi"); - emit("movl %%eax, (%%rsi)"); // store return value +// emit("frstor 4(%%r9, %%rsi, 1)"); + STACK_PUSH(4); + emit("movl %%eax, (%%r9, %%rbx, 4)"); // store return value neednilabel = 1; break; case OP_PUSH: MAYBE_EMIT_CONST(); - emit("addq $4, %%rsi"); + STACK_PUSH(4); break; case OP_POP: MAYBE_EMIT_CONST(); - emit("subq $4, %%rsi"); + STACK_POP(4); break; case OP_CONST: MAYBE_EMIT_CONST(); @@ -611,25 +607,25 @@ emit_do_syscall: got_const = 1; const_value = iarg; #else - emit("addq $4, %%rsi"); - emit("movl $%d, 0(%%rsi)", iarg); + STACK_PUSH(4); + emit("movl $%d, (%%r9, %%rbx, 4)", iarg); #endif break; case OP_LOCAL: MAYBE_EMIT_CONST(); - emit("movl %%edi, %%ebx"); - emit("addl $%d,%%ebx", iarg); - emit("addq $4, %%rsi"); - emit("movl %%ebx, 0(%%rsi)"); + emit("movl %%edi, %%esi"); + emit("addl $%d,%%esi", iarg); + STACK_PUSH(4); + emit("movl %%esi, (%%r9, %%rbx, 4)"); break; case OP_JUMP: if(got_const) { iarg = const_value; got_const = 0; - JMPIARG; + JMPIARG(); } else { - emit("movl 0(%%rsi), %%eax"); // get instr from stack - emit("subq $4, %%rsi"); + emit("movl (%%r9, %%rbx, 4), %%eax"); // get instr from stack + STACK_POP(4); PREPARE_JMP(eax); emit("jmp *%%rax"); @@ -673,13 +669,13 @@ emit_do_syscall: FJ(0x40, "jnz"); #ifndef USE_X87 MAYBE_EMIT_CONST(); - emit("subq $8, %%rsi"); - emit("movss 4(%%rsi), %%xmm0"); - emit("ucomiss 8(%%rsi), %%xmm0"); + STACK_POP(8); + emit("movss 4(%%r9, %%rbx, 4), %%xmm0"); + emit("ucomiss 8(%%r9, %%rbx, 4), %%xmm0"); emit("jp dojump_i_%08x", instruction); emit("jz i_%08x", instruction+1); emit("dojump_i_%08x:", instruction); - JMPIARG + JMPIARG(); neednilabel = 1; #endif break; @@ -701,105 +697,103 @@ emit_do_syscall: break; case OP_LOAD1: MAYBE_EMIT_CONST(); - emit("movl 0(%%rsi), %%eax"); // get value from stack + emit("movl (%%r9, %%rbx, 4), %%eax"); // get value from stack RANGECHECK(eax, 1); - emit("movb 0(%%r8, %%rax, 1), %%al"); // deref into eax + emit("movb (%%r8, %%rax, 1), %%al"); // deref into eax emit("andq $255, %%rax"); - emit("movl %%eax, 0(%%rsi)"); // store on stack + emit("movl %%eax, (%%r9, %%rbx, 4)"); // store on stack break; case OP_LOAD2: MAYBE_EMIT_CONST(); - emit("movl 0(%%rsi), %%eax"); // get value from stack + emit("movl (%%r9, %%rbx, 4), %%eax"); // get value from stack RANGECHECK(eax, 2); - emit("movw 0(%%r8, %%rax, 1), %%ax"); // deref into eax - emit("movl %%eax, 0(%%rsi)"); // store on stack + emit("movw (%%r8, %%rax, 1), %%ax"); // deref into eax + emit("movl %%eax, (%%r9, %%rbx, 4)"); // store on stack break; case OP_LOAD4: MAYBE_EMIT_CONST(); - emit("movl 0(%%rsi), %%eax"); // get value from stack + emit("movl (%%r9, %%rbx, 4), %%eax"); // get value from stack RANGECHECK(eax, 4); // not a pointer!? - emit("movl 0(%%r8, %%rax, 1), %%eax"); // deref into eax - emit("movl %%eax, 0(%%rsi)"); // store on stack + emit("movl (%%r8, %%rax, 1), %%eax"); // deref into eax + emit("movl %%eax, (%%r9, %%rbx, 4)"); // store on stack break; case OP_STORE1: MAYBE_EMIT_CONST(); - emit("movl 0(%%rsi), %%eax"); // get value from stack + emit("movl (%%r9, %%rbx, 4), %%eax"); // get value from stack + STACK_POP(8); emit("andq $255, %%rax"); - emit("movl -4(%%rsi), %%ebx"); // get pointer from stack - RANGECHECK(ebx, 1); - emit("movb %%al, 0(%%r8, %%rbx, 1)"); // store in memory - emit("subq $8, %%rsi"); + emit("movl 4(%%r9, %%rbx, 4), %%esi"); // get pointer from stack + RANGECHECK(esi, 1); + emit("movb %%al, (%%r8, %%rsi, 1)"); // store in memory break; case OP_STORE2: MAYBE_EMIT_CONST(); - emit("movl 0(%%rsi), %%eax"); // get value from stack - emit("movl -4(%%rsi), %%ebx"); // get pointer from stack - RANGECHECK(ebx, 2); - emit("movw %%ax, 0(%%r8, %%rbx, 1)"); // store in memory - emit("subq $8, %%rsi"); + emit("movl (%%r9, %%rbx, 4), %%eax"); // get value from stack + STACK_POP(8); + emit("movl 4(%%r9, %%rbx, 4), %%esi"); // get pointer from stack + RANGECHECK(esi, 2); + emit("movw %%ax, (%%r8, %%rsi, 1)"); // store in memory break; case OP_STORE4: MAYBE_EMIT_CONST(); - emit("movl -4(%%rsi), %%ebx"); // get pointer from stack - RANGECHECK(ebx, 4); - emit("movl 0(%%rsi), %%ecx"); // get value from stack - emit("movl %%ecx, 0(%%r8, %%rbx, 1)"); // store in memory - emit("subq $8, %%rsi"); + emit("movl (%%r9, %%rbx, 4), %%eax"); // get value from stack + STACK_POP(8); + emit("movl 4(%%r9, %%rbx, 4), %%esi"); // get pointer from stack + RANGECHECK(esi, 4); + emit("movl %%eax, (%%r8, %%rsi, 1)"); // store in memory break; case OP_ARG: MAYBE_EMIT_CONST(); - emit("subq $4, %%rsi"); - emit("movl 4(%%rsi), %%eax"); // get value from stack - emit("movl $0x%hx, %%ebx", barg); - emit("addl %%edi, %%ebx"); - RANGECHECK(ebx, 4); - emit("movl %%eax, 0(%%r8,%%rbx, 1)"); // store in args space + emit("movl (%%r9, %%rbx, 4), %%eax"); // get value from stack + STACK_POP(4); + emit("movl $0x%hx, %%esi", barg); + emit("addl %%edi, %%esi"); + RANGECHECK(esi, 4); + emit("movl %%eax, (%%r8,%%rsi, 1)"); // store in args space break; case OP_BLOCK_COPY: MAYBE_EMIT_CONST(); - emit("subq $8, %%rsi"); - emit("push %%rsi"); + STACK_POP(8); emit("push %%rdi"); emit("push %%r8"); emit("push %%r9"); emit("push %%r10"); - emit("movq %%rsp, %%rbx"); // we need to align the stack pointer - emit("subq $8, %%rbx"); // | - emit("andq $127, %%rbx"); // | - emit("subq %%rbx, %%rsp"); // <-+ - emit("push %%rbx"); - emit("movl 4(%%rsi), %%edi"); // 1st argument dest - emit("movl 8(%%rsi), %%esi"); // 2nd argument src + emit("movq %%rsp, %%rsi"); // we need to align the stack pointer + emit("subq $8, %%rsi"); // | + emit("andq $127, %%rsi"); // | + emit("subq %%rsi, %%rsp"); // <-+ + emit("push %%rsi"); + emit("movl 4(%%r9, %%rbx, 4), %%edi"); // 1st argument dest + emit("movl 8(%%r9, %%rbx, 4), %%rsi"); // 2nd argument src emit("movl $%d, %%edx", iarg); // 3rd argument count - emit("movq $%"PRIu64", %%rax", (uint64_t)block_copy_vm); + emit("movq $%"PRIu64", %%rax", (intptr_t) VM_BlockCopy); emit("callq *%%rax"); - emit("pop %%rbx"); - emit("addq %%rbx, %%rsp"); + emit("pop %%rsi"); + emit("addq %%rsi, %%rsp"); emit("pop %%r10"); emit("pop %%r9"); emit("pop %%r8"); emit("pop %%rdi"); - emit("pop %%rsi"); break; case OP_SEX8: MAYBE_EMIT_CONST(); - emit("movw 0(%%rsi), %%ax"); + emit("movw (%%r9, %%rbx, 4), %%ax"); emit("andq $255, %%rax"); emit("cbw"); emit("cwde"); - emit("movl %%eax, 0(%%rsi)"); + emit("movl %%eax, (%%r9, %%rbx, 4)"); break; case OP_SEX16: MAYBE_EMIT_CONST(); - emit("movw 0(%%rsi), %%ax"); + emit("movw (%%r9, %%rbx, 4), %%ax"); emit("cwde"); - emit("movl %%eax, 0(%%rsi)"); + emit("movl %%eax, (%%r9, %%rbx, 4)"); break; case OP_NEGI: MAYBE_EMIT_CONST(); - emit("negl 0(%%rsi)"); + emit("negl (%%r9, %%rbx, 4)"); break; case OP_ADD: SIMPLE("addl"); @@ -809,50 +803,50 @@ emit_do_syscall: break; case OP_DIVI: MAYBE_EMIT_CONST(); - emit("subq $4, %%rsi"); - emit("movl 0(%%rsi), %%eax"); + STACK_POP(4); + emit("movl (%%r9, %%rbx, 4), %%eax"); emit("cdq"); - emit("idivl 4(%%rsi)"); - emit("movl %%eax, 0(%%rsi)"); + emit("idivl 4(%%r9, %%rbx, 4)"); + emit("movl %%eax, (%%r9, %%rbx, 4)"); break; case OP_DIVU: MAYBE_EMIT_CONST(); - emit("subq $4, %%rsi"); - emit("movl 0(%%rsi), %%eax"); + STACK_POP(4); + emit("movl (%%r9, %%rbx, 4), %%eax"); emit("xorq %%rdx, %%rdx"); - emit("divl 4(%%rsi)"); - emit("movl %%eax, 0(%%rsi)"); + emit("divl 4(%%r9, %%rbx, 4)"); + emit("movl %%eax, (%%r9, %%rbx, 4)"); break; case OP_MODI: MAYBE_EMIT_CONST(); - emit("subq $4, %%rsi"); - emit("movl 0(%%rsi), %%eax"); + STACK_POP(4); + emit("movl (%%r9, %%rbx, 4), %%eax"); emit("xorl %%edx, %%edx"); emit("cdq"); - emit("idivl 4(%%rsi)"); - emit("movl %%edx, 0(%%rsi)"); + emit("idivl 4(%%r9, %%rbx, 4)"); + emit("movl %%edx, (%%r9, %%rbx, 4)"); break; case OP_MODU: MAYBE_EMIT_CONST(); - emit("subq $4, %%rsi"); - emit("movl 0(%%rsi), %%eax"); + STACK_POP(4); + emit("movl (%%r9, %%rbx, 4), %%eax"); emit("xorl %%edx, %%edx"); - emit("divl 4(%%rsi)"); - emit("movl %%edx, 0(%%rsi)"); + emit("divl 4(%%r9, %%rbx, 4)"); + emit("movl %%edx, (%%r9, %%rbx, 4)"); break; case OP_MULI: MAYBE_EMIT_CONST(); - emit("subq $4, %%rsi"); - emit("movl 0(%%rsi), %%eax"); - emit("imull 4(%%rsi)"); - emit("movl %%eax, 0(%%rsi)"); + STACK_POP(4); + emit("movl (%%r9, %%rbx, 4), %%eax"); + emit("imull 4(%%r9, %%rbx, 4)"); + emit("movl %%eax, (%%r9, %%rbx, 4)"); break; case OP_MULU: MAYBE_EMIT_CONST(); - emit("subq $4, %%rsi"); - emit("movl 0(%%rsi), %%eax"); - emit("mull 4(%%rsi)"); - emit("movl %%eax, 0(%%rsi)"); + STACK_POP(4); + emit("movl (%%r9, %%rbx, 4), %%eax"); + emit("mull 4(%%r9, %%rbx, 4)"); + emit("movl %%eax, (%%r9, %%rbx, 4)"); break; case OP_BAND: SIMPLE("andl"); @@ -865,7 +859,7 @@ emit_do_syscall: break; case OP_BCOM: MAYBE_EMIT_CONST(); - emit("notl 0(%%rsi)"); + emit("notl (%%r9, %%rbx, 4)"); break; case OP_LSH: SHIFT("shl"); @@ -879,12 +873,12 @@ emit_do_syscall: case OP_NEGF: MAYBE_EMIT_CONST(); #ifdef USE_X87 - emit("flds 0(%%rsi)"); + emit("flds (%%r9, %%rbx, 4)"); emit("fchs"); - emit("fstps 0(%%rsi)"); + emit("fstps (%%r9, %%rbx, 4)"); #else emit("movl $0x80000000, %%eax"); - emit("xorl %%eax, 0(%%rsi)"); + emit("xorl %%eax, (%%r9, %%rbx, 4)"); #endif break; case OP_ADDF: @@ -906,27 +900,27 @@ emit_do_syscall: case OP_CVIF: MAYBE_EMIT_CONST(); #ifdef USE_X87 - emit("filds 0(%%rsi)"); - emit("fstps 0(%%rsi)"); + emit("filds (%%r9, %%rbx, 4)"); + emit("fstps (%%r9, %%rbx, 4)"); #else - emit("movl 0(%%rsi), %%eax"); + emit("movl (%%r9, %%rbx, 4), %%eax"); emit("cvtsi2ss %%eax, %%xmm0"); - emit("movss %%xmm0, 0(%%rsi)"); + emit("movss %%xmm0, (%%r9, %%rbx, 4)"); #endif break; case OP_CVFI: MAYBE_EMIT_CONST(); #ifdef USE_X87 - emit("flds 0(%%rsi)"); - emit("fnstcw 4(%%rsi)"); - emit("movw $0x0F7F, 8(%%rsi)"); // round toward zero - emit("fldcw 8(%%rsi)"); - emit("fistpl 0(%%rsi)"); - emit("fldcw 4(%%rsi)"); + emit("flds (%%r9, %%rbx, 4)"); + emit("fnstcw 4(%%r9, %%rbx, 4)"); + emit("movw $0x0F7F, 8(%%r9, %%rbx, 4)"); // round toward zero + emit("fldcw 8(%%r9, %%rbx, 4)"); + emit("fistpl (%%r9, %%rbx, 4)"); + emit("fldcw 4(%%r9, %%rbx, 4)"); #else - emit("movss 0(%%rsi), %%xmm0"); + emit("movss (%%r9, %%rbx, 4), %%xmm0"); emit("cvttss2si %%xmm0, %%eax"); - emit("movl %%eax, 0(%%rsi)"); + emit("movl %%eax, (%%r9, %%rbx, 4)"); #endif break; default: @@ -940,10 +934,10 @@ emit_do_syscall: if(got_const) { VM_FREEBUFFERS(vm); - Com_Error(ERR_DROP, "leftover const\n"); + Com_Error(ERR_DROP, "leftover const"); } - emit("movq $%"PRIu64", %%rax", (uint64_t)eop); + emit("movq $%"PRIu64", %%rax", (intptr_t) eop); emit("callq *%%rax"); } // pass loop @@ -1020,17 +1014,19 @@ This function is called directly by the generated code static char* memData; #endif -int VM_CallCompiled( vm_t *vm, int *args ) { +int VM_CallCompiled(vm_t *vm, int *args) +{ + int stack[OPSTACK_SIZE + 15]; int programCounter; int programStack; int stackOnEntry; + long opStackRet; byte *image; void *entryPoint; - void *opStack; - int stack[1024] = { 0xDEADBEEF }; + int *opStack; currentVM = vm; - + // Com_Printf("entering %s level %d, call %d, arg1 = 0x%x\n", vm->name, vm->callLevel, args[0], args[1]); // interpret the code @@ -1067,32 +1063,40 @@ int VM_CallCompiled( vm_t *vm, int *args ) { // off we go into generated code... entryPoint = getentrypoint(vm); - opStack = &stack; + opStack = PADP(stack, 16); + + *opStack = 0xDEADBEEF; + opStackRet = 0; __asm__ __volatile__ ( - " movq %5,%%rsi \r\n" \ - " movl %4,%%edi \r\n" \ + " movq %4,%%r8 \r\n" \ + " movq %3,%%r9 \r\n" \ " movq %2,%%r10 \r\n" \ - " movq %3,%%r8 \r\n" \ + " push %%r15 \r\n" \ + " push %%r14 \r\n" \ + " push %%r13 \r\n" \ + " push %%r12 \r\n" \ " subq $24, %%rsp # fix alignment as call pushes one value \r\n" \ " callq *%%r10 \r\n" \ - " addq $24, %%rsp \r\n" \ - " movl %%edi, %0 \r\n" \ - " movq %%rsi, %1 \r\n" \ - : "=m" (programStack), "=m" (opStack) - : "m" (entryPoint), "m" (vm->dataBase), "m" (programStack), "m" (opStack) - : "%rsi", "%rdi", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r10", "%r15", "%xmm0" + " addq $24, %%rsp \r\n" \ + " pop %%r12 \r\n" \ + " pop %%r13 \r\n" \ + " pop %%r14 \r\n" \ + " pop %%r15 \r\n" + : "+D" (programStack), "+b" (opStackRet) + : "g" (entryPoint), "g" (opStack), "g" (vm->dataBase), "g" (programStack) + : "%rsi", "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%xmm0" ); - if ( opStack != &stack[1] ) { - Com_Error( ERR_DROP, "opStack corrupted in compiled code (offset %"PRId64")\n", (int64_t) ((void *) &stack[1] - opStack)); - } + if(opStackRet != 1 || *opStack != 0xDEADBEEF) + Com_Error(ERR_DROP, "opStack corrupted in compiled code (offset %ld)", opStackRet); + if ( programStack != stackOnEntry - 48 ) { - Com_Error( ERR_DROP, "programStack corrupted in compiled code\n" ); + Com_Error( ERR_DROP, "programStack corrupted in compiled code" ); } // Com_Printf("exiting %s level %d\n", vm->name, vm->callLevel); vm->programStack = stackOnEntry; - return *(int *)opStack; + return stack[1]; } diff --git a/reaction/code/qcommon/vm_x86_64_assembler.c b/reaction/code/qcommon/vm_x86_64_assembler.c index c939dadc..d9ca0d20 100644 --- a/reaction/code/qcommon/vm_x86_64_assembler.c +++ b/reaction/code/qcommon/vm_x86_64_assembler.c @@ -43,9 +43,6 @@ static const char* cur_line; static FILE* fout; -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#define MAX(a,b) ((a) > (b) ? (a) : (b)) - #define crap(fmt, args...) do { \ _crap(__FUNCTION__, fmt, ##args); \ } while(0) @@ -161,6 +158,7 @@ typedef enum { R_R15 = 0x0F | R_64, R_AL = R_EAX | R_8, R_AX = R_EAX | R_16, + R_BL = R_EBX | R_8, R_CL = R_ECX | R_8, R_XMM0 = 0x00 | R_XMM, R_MGP = 0x0F, // mask for general purpose registers @@ -216,6 +214,32 @@ typedef struct { u8 rcode; // opcode for reg/mem } opparam_t; +static opparam_t params_add = { subcode: 0, rmcode: 0x01, }; +static opparam_t params_or = { subcode: 1, rmcode: 0x09, }; +static opparam_t params_and = { subcode: 4, rmcode: 0x21, }; +static opparam_t params_sub = { subcode: 5, rmcode: 0x29, }; +static opparam_t params_xor = { subcode: 6, rmcode: 0x31, }; +static opparam_t params_cmp = { subcode: 7, rmcode: 0x39, mrcode: 0x3b, }; +static opparam_t params_dec = { subcode: 1, rcode: 0xff, rcode8: 0xfe, }; +static opparam_t params_sar = { subcode: 7, rcode: 0xd3, rcode8: 0xd2, }; +static opparam_t params_shl = { subcode: 4, rcode: 0xd3, rcode8: 0xd2, }; +static opparam_t params_shr = { subcode: 5, rcode: 0xd3, rcode8: 0xd2, }; +static opparam_t params_idiv = { subcode: 7, rcode: 0xf7, rcode8: 0xf6, }; +static opparam_t params_div = { subcode: 6, rcode: 0xf7, rcode8: 0xf6, }; +static opparam_t params_imul = { subcode: 5, rcode: 0xf7, rcode8: 0xf6, }; +static opparam_t params_mul = { subcode: 4, rcode: 0xf7, rcode8: 0xf6, }; +static opparam_t params_neg = { subcode: 3, rcode: 0xf7, rcode8: 0xf6, }; +static opparam_t params_not = { subcode: 2, rcode: 0xf7, rcode8: 0xf6, }; + +static opparam_t params_cvtsi2ss = { xmmprefix: 0xf3, rmcode: 0x2a }; +static opparam_t params_cvttss2si = { xmmprefix: 0xf3, rmcode: 0x2c }; +static opparam_t params_addss = { xmmprefix: 0xf3, mrcode: 0x58 }; +static opparam_t params_divss = { xmmprefix: 0xf3, mrcode: 0x5e }; +static opparam_t params_movss = { xmmprefix: 0xf3, mrcode: 0x10, rmcode: 0x11 }; +static opparam_t params_mulss = { xmmprefix: 0xf3, mrcode: 0x59 }; +static opparam_t params_subss = { xmmprefix: 0xf3, mrcode: 0x5c }; +static opparam_t params_ucomiss = { mrcode: 0x2e }; + /* ************************* */ static unsigned hashkey(const char *string, unsigned len) { @@ -317,34 +341,34 @@ static const char* argtype2str(argtype_t t) /* ************************* */ -static inline int iss8(u64 v) +static inline int iss8(int64_t v) { - return (llabs(v) <= 0x80); //llabs instead of labs required for __WIN64 + return (SCHAR_MIN <= v && v <= SCHAR_MAX); } static inline int isu8(u64 v) { - return (v <= 0xff); + return (v <= UCHAR_MAX); } -static inline int iss16(u64 v) +static inline int iss16(int64_t v) { - return (llabs(v) <= 0x8000); + return (SHRT_MIN <= v && v <= SHRT_MAX); } static inline int isu16(u64 v) { - return (v <= 0xffff); + return (v <= USHRT_MAX); } -static inline int iss32(u64 v) +static inline int iss32(int64_t v) { - return (llabs(v) <= 0x80000000); + return (INT_MIN <= v && v <= INT_MAX); } static inline int isu32(u64 v) { - return (v <= 0xffffffff); + return (v <= UINT_MAX); } static void emit_opsingle(const char* mnemonic, arg_t arg1, arg_t arg2, void* data) @@ -598,7 +622,7 @@ static void emit_mov(const char* mnemonic, arg_t arg1, arg_t arg2, void* data) if(arg2.v.reg & R_8) { - if(!isu8(arg1.v.imm)) + if(!iss8(arg1.v.imm)) crap("value too large for 8bit register"); op = 0xb0; @@ -714,19 +738,23 @@ static void emit_subaddand(const char* mnemonic, arg_t arg1, arg_t arg2, void* d } compute_rexmodrmsib(&rex, &modrm, &sib, &arg1, &arg2); - modrm |= params->subcode << 3; if(rex) emit1(rex); -#if 0 - if(isu8(arg1.v.imm)) + + if(arg2.v.reg & R_8) + { + emit1(0x80); // sub reg8/mem8, imm8 + emit1(modrm); + emit1(arg1.v.imm & 0xFF); + } + else if(iss8(arg1.v.imm)) { emit1(0x83); // sub reg/mem, imm8 emit1(modrm); - emit1(arg1.v.imm&0xFF); + emit1(arg1.v.imm & 0xFF); } else -#endif { emit1(0x81); // sub reg/mem, imm32 emit1(modrm); @@ -896,42 +924,19 @@ static void emit_twobyte(const char* mnemonic, arg_t arg1, arg_t arg2, void* dat CRAP_INVALID_ARGS; } -static opparam_t params_add = { subcode: 0, rmcode: 0x01, }; -static opparam_t params_or = { subcode: 1, rmcode: 0x09, }; -static opparam_t params_and = { subcode: 4, rmcode: 0x21, }; -static opparam_t params_sub = { subcode: 5, rmcode: 0x29, }; -static opparam_t params_xor = { subcode: 6, rmcode: 0x31, }; -static opparam_t params_cmp = { subcode: 7, rmcode: 0x39, mrcode: 0x3b, }; -static opparam_t params_dec = { subcode: 1, rcode: 0xff, rcode8: 0xfe, }; -static opparam_t params_sar = { subcode: 7, rcode: 0xd3, rcode8: 0xd2, }; -static opparam_t params_shl = { subcode: 4, rcode: 0xd3, rcode8: 0xd2, }; -static opparam_t params_shr = { subcode: 5, rcode: 0xd3, rcode8: 0xd2, }; -static opparam_t params_idiv = { subcode: 7, rcode: 0xf7, rcode8: 0xf6, }; -static opparam_t params_div = { subcode: 6, rcode: 0xf7, rcode8: 0xf6, }; -static opparam_t params_imul = { subcode: 5, rcode: 0xf7, rcode8: 0xf6, }; -static opparam_t params_mul = { subcode: 4, rcode: 0xf7, rcode8: 0xf6, }; -static opparam_t params_neg = { subcode: 3, rcode: 0xf7, rcode8: 0xf6, }; -static opparam_t params_not = { subcode: 2, rcode: 0xf7, rcode8: 0xf6, }; - -static opparam_t params_cvtsi2ss = { xmmprefix: 0xf3, rmcode: 0x2a }; -static opparam_t params_cvttss2si = { xmmprefix: 0xf3, rmcode: 0x2c }; -static opparam_t params_addss = { xmmprefix: 0xf3, mrcode: 0x58 }; -static opparam_t params_divss = { xmmprefix: 0xf3, mrcode: 0x5e }; -static opparam_t params_movss = { xmmprefix: 0xf3, mrcode: 0x10, rmcode: 0x11 }; -static opparam_t params_mulss = { xmmprefix: 0xf3, mrcode: 0x59 }; -static opparam_t params_subss = { xmmprefix: 0xf3, mrcode: 0x5c }; -static opparam_t params_ucomiss = { mrcode: 0x2e }; - static int ops_sorted = 0; static op_t ops[] = { + { "addb", emit_subaddand, ¶ms_add }, { "addl", emit_subaddand, ¶ms_add }, { "addq", emit_subaddand, ¶ms_add }, { "addss", emit_twobyte, ¶ms_addss }, + { "andb", emit_subaddand, ¶ms_and }, { "andl", emit_subaddand, ¶ms_and }, { "andq", emit_subaddand, ¶ms_and }, { "callq", emit_call, NULL }, { "cbw", emit_opsingle16, (void*)0x98 }, { "cdq", emit_opsingle, (void*)0x99 }, + { "cmpb", emit_subaddand, ¶ms_cmp }, { "cmpl", emit_subaddand, ¶ms_cmp }, { "cmpq", emit_subaddand, ¶ms_cmp }, { "cvtsi2ss", emit_twobyte, ¶ms_cvtsi2ss }, @@ -977,18 +982,21 @@ static op_t ops[] = { { "nop", emit_opsingle, (void*)0x90 }, { "notl", emit_op_rm, ¶ms_not }, { "notq", emit_op_rm, ¶ms_not }, - { "or", emit_subaddand, ¶ms_or }, + { "orb", emit_subaddand, ¶ms_or }, { "orl", emit_subaddand, ¶ms_or }, + { "orq", emit_subaddand, ¶ms_or }, { "pop", emit_opreg, (void*)0x58 }, { "push", emit_opreg, (void*)0x50 }, { "ret", emit_opsingle, (void*)0xc3 }, { "sarl", emit_op_rm_cl, ¶ms_sar }, { "shl", emit_op_rm_cl, ¶ms_shl }, { "shrl", emit_op_rm_cl, ¶ms_shr }, + { "subb", emit_subaddand, ¶ms_sub }, { "subl", emit_subaddand, ¶ms_sub }, { "subq", emit_subaddand, ¶ms_sub }, { "subss", emit_twobyte, ¶ms_subss }, { "ucomiss", emit_twobyte, ¶ms_ucomiss }, + { "xorb", emit_subaddand, ¶ms_xor }, { "xorl", emit_subaddand, ¶ms_xor }, { "xorq", emit_subaddand, ¶ms_xor }, { NULL, NULL, NULL } @@ -1013,27 +1021,24 @@ static op_t* getop(const char* n) } #else - unsigned m, t, b; + unsigned int m, t, b; int r; t = ARRAY_LEN(ops)-1; - b = 0; - while(b <= t) + r = m = -1; + + do { - m = ((t-b)>>1) + b; - if((r = strcmp(ops[m].mnemonic, n)) == 0) - { - return &ops[m]; - } - else if(r < 0) - { + if(r < 0) b = m + 1; - } else - { t = m - 1; - } - } + + m = ((t - b) >> 1) + b; + + if((r = strcmp(ops[m].mnemonic, n)) == 0) + return &ops[m]; + } while(b <= t && t); #endif return NULL; @@ -1050,6 +1055,10 @@ static reg_t parsereg(const char* str) { return R_AX; } + if(*s == 'b' && s[1] == 'l' && !s[2]) + { + return R_BL; + } if(*s == 'c' && s[1] == 'l' && !s[2]) { return R_CL; diff --git a/reaction/code/renderer/qgl.h b/reaction/code/renderer/qgl.h index 53d92df3..21a65ac1 100644 --- a/reaction/code/renderer/qgl.h +++ b/reaction/code/renderer/qgl.h @@ -85,6 +85,7 @@ extern void (APIENTRY * qglUniform1iARB) (GLint location, GLint v0); extern void (APIENTRY * qglUniform2iARB) (GLint location, GLint v0, GLint v1); extern void (APIENTRY * qglUniform3iARB) (GLint location, GLint v0, GLint v1, GLint v2); extern void (APIENTRY * qglUniform4iARB) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +extern void (APIENTRY * qglUniform1fvARB) (GLint location, GLsizei count, const GLfloat * value); extern void (APIENTRY * qglUniform2fvARB) (GLint location, GLsizei count, const GLfloat * value); extern void (APIENTRY * qglUniform3fvARB) (GLint location, GLsizei count, const GLfloat * value); extern void (APIENTRY * qglUniform4fvARB) (GLint location, GLsizei count, const GLfloat * value); diff --git a/reaction/code/renderer/tr_animation.c b/reaction/code/renderer/tr_animation.c index 8f424569..794111c6 100644 --- a/reaction/code/renderer/tr_animation.c +++ b/reaction/code/renderer/tr_animation.c @@ -45,13 +45,13 @@ void R_AddAnimSurfaces( trRefEntity_t *ent ) { shader_t *shader; int i; - header = (md4Header_t *) tr.currentModel->md4; + header = (md4Header_t *) tr.currentModel->modelData; lod = (md4LOD_t *)( (byte *)header + header->ofsLODs ); surface = (md4Surface_t *)( (byte *)lod + lod->ofsSurfaces ); for ( i = 0 ; i < lod->numSurfaces ; i++ ) { shader = R_GetShaderByHandle( surface->shaderIndex ); - R_AddDrawSurf( (void *)surface, shader, 0 /*fogNum*/, qfalse ); + R_AddDrawSurf( (void *)surface, shader, 0 /*fogNum*/, qfalse, qfalse ); surface = (md4Surface_t *)( (byte *)surface + surface->ofsEnd ); } } @@ -326,7 +326,7 @@ void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) { int cull; qboolean personalModel; - header = (mdrHeader_t *) tr.currentModel->md4; + header = (mdrHeader_t *) tr.currentModel->modelData; personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal; @@ -420,7 +420,7 @@ void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) { && !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) ) && shader->sort == SS_OPAQUE ) { - R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, qfalse ); + R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, qfalse, qfalse ); } // projection shadows work fine with personal models @@ -429,11 +429,11 @@ void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) { && (ent->e.renderfx & RF_SHADOW_PLANE ) && shader->sort == SS_OPAQUE ) { - R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse ); + R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse, qfalse ); } if (!personalModel) - R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse ); + R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse, qfalse ); surface = (mdrSurface_t *)( (byte *)surface + surface->ofsEnd ); } diff --git a/reaction/code/renderer/tr_backend.c b/reaction/code/renderer/tr_backend.c index aaa335d5..8db7025a 100644 --- a/reaction/code/renderer/tr_backend.c +++ b/reaction/code/renderer/tr_backend.c @@ -60,6 +60,30 @@ void GL_Bind( image_t *image ) { } } +/* +** GL_BindCubemap +*/ +void GL_BindCubemap( image_t *image ) { + int texnum; + + if ( !image ) { + ri.Printf( PRINT_WARNING, "GL_Bind: NULL image\n" ); + texnum = tr.defaultImage->texnum; + } else { + texnum = image->texnum; + } + + if ( r_nobind->integer && tr.dlightImage ) { // performance evaluation option + texnum = tr.dlightImage->texnum; + } + + if ( glState.currenttextures[glState.currenttmu] != texnum ) { + image->frameUsed = tr.frameCount; + glState.currenttextures[glState.currenttmu] = texnum; + qglBindTexture (GL_TEXTURE_CUBE_MAP, texnum); + } +} + /* ** GL_SelectTexture */ @@ -176,7 +200,7 @@ void GL_Cull( int cullType ) { if ( cullType == CT_BACK_SIDED ) { - if ( backEnd.viewParms.isMirror ) + if ( backEnd.viewParms.isMirror && !backEnd.viewParms.isShadowmap) { qglCullFace( GL_FRONT ); } @@ -187,7 +211,7 @@ void GL_Cull( int cullType ) { } else { - if ( backEnd.viewParms.isMirror ) + if ( backEnd.viewParms.isMirror && !backEnd.viewParms.isShadowmap) { qglCullFace( GL_BACK ); } @@ -227,7 +251,7 @@ void GL_TexEnv( int env ) qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD ); break; default: - ri.Error( ERR_DROP, "GL_TexEnv: invalid env '%d' passed\n", env ); + ri.Error( ERR_DROP, "GL_TexEnv: invalid env '%d' passed", env ); break; } } @@ -302,7 +326,7 @@ void GL_State( unsigned long stateBits ) break; default: srcFactor = GL_ONE; // to get warning to shut up - ri.Error( ERR_DROP, "GL_State: invalid src blend state bits\n" ); + ri.Error( ERR_DROP, "GL_State: invalid src blend state bits" ); break; } @@ -334,7 +358,7 @@ void GL_State( unsigned long stateBits ) break; default: dstFactor = GL_ONE; // to get warning to shut up - ri.Error( ERR_DROP, "GL_State: invalid dst blend state bits\n" ); + ri.Error( ERR_DROP, "GL_State: invalid dst blend state bits" ); break; } @@ -552,6 +576,14 @@ void RB_BeginDrawingView (void) { qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); // FIXME: get color of sky #endif } + + // clear to white for shadow maps + if (backEnd.viewParms.isShadowmap) + { + clearBits |= GL_COLOR_BUFFER_BIT; + qglClearColor( 1.0f, 1.0f, 1.0f, 1.0f ); + } + qglClear( clearBits ); if ( ( backEnd.refdef.rdflags & RDF_HYPERSPACE ) ) @@ -615,6 +647,7 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { int fogNum, oldFogNum; int entityNum, oldEntityNum; int dlighted, oldDlighted; + int pshadowed, oldPshadowed; qboolean depthRange, oldDepthRange, isCrosshair, wasCrosshair; int i; drawSurf_t *drawSurf; @@ -640,6 +673,7 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { oldDepthRange = qfalse; wasCrosshair = qfalse; oldDlighted = qfalse; + oldPshadowed = qfalse; oldSort = -1; depthRange = qfalse; depth[0] = 0.f; @@ -654,13 +688,13 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { continue; } oldSort = drawSurf->sort; - R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted ); + R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted, &pshadowed ); // // change the tess parameters if needed // a "entityMergable" shader is a shader that can have surfaces from seperate // entities merged into a single batch, like smoke and blood puff sprites - if (shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted + if (shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted || pshadowed != oldPshadowed || ( entityNum != oldEntityNum && !shader->entityMergable ) ) { if (oldShader != NULL) { RB_EndSurface(); @@ -670,6 +704,7 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { oldShader = shader; oldFogNum = fogNum; oldDlighted = dlighted; + oldPshadowed = pshadowed; } // @@ -771,7 +806,7 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { { viewParms_t temp = backEnd.viewParms; - R_SetupProjection(&temp, r_znear->value, qfalse); + R_SetupProjection(&temp, r_znear->value, 0, qfalse); GL_SetProjectionMatrix( temp.projectionMatrix ); } @@ -1406,6 +1441,34 @@ const void *RB_SwapBuffers( const void *data ) { return (const void *)(cmd + 1); } +/* +============= +RB_CapShadowMap + +============= +*/ +const void *RB_CapShadowMap(const void *data) +{ + const capShadowmapCommand_t *cmd = data; + + if (cmd->map != -1) + { + GL_SelectTexture(0); + if (cmd->cubeSide != -1) + { + GL_BindCubemap(tr.shadowCubemaps[cmd->map]); + qglCopyTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cmd->cubeSide, 0, GL_RGBA8, backEnd.refdef.x, glConfig.vidHeight - ( backEnd.refdef.y + 256 ), 256, 256, 0); + } + else + { + GL_Bind(tr.pshadowMaps[cmd->map]); + qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, backEnd.refdef.x, glConfig.vidHeight - ( backEnd.refdef.y + 256 ), 256, 256, 0); + } + } + + return (const void *)(cmd + 1); +} + /* ==================== RB_ExecuteRenderCommands @@ -1426,6 +1489,8 @@ void RB_ExecuteRenderCommands( const void *data ) { } while ( 1 ) { + data = PADP(data, sizeof(void *)); + switch ( *(const int *)data ) { case RC_SET_COLOR: data = RB_SetColor( data ); @@ -1454,6 +1519,9 @@ void RB_ExecuteRenderCommands( const void *data ) { case RC_CLEARDEPTH: data = RB_ClearDepth(data); break; + case RC_CAPSHADOWMAP: + data = RB_CapShadowMap(data); + break; case RC_END_OF_LIST: default: // stop rendering on this thread diff --git a/reaction/code/renderer/tr_bsp.c b/reaction/code/renderer/tr_bsp.c index 6438cfd7..618b3bfc 100644 --- a/reaction/code/renderer/tr_bsp.c +++ b/reaction/code/renderer/tr_bsp.c @@ -275,7 +275,10 @@ static void R_LoadLightmaps( lump_t *l ) { // create all the lightmaps numLightmaps = len / (LIGHTMAP_SIZE * LIGHTMAP_SIZE * 3); - numLightmaps >>= (tr.worldDeluxeMapping ? 1 : 0); + if (tr.worldDeluxeMapping) + { + numLightmaps >>= 1; + } if(numLightmaps == 1) { @@ -369,7 +372,6 @@ static void R_LoadLightmaps( lump_t *l ) { } } } - } tr.fatLightmap = R_CreateImage(va("_fatlightmap%d", 0), fatbuffer, tr.fatLightmapSize, tr.fatLightmapSize, qfalse, qfalse, GL_CLAMP_TO_EDGE ); @@ -1795,13 +1797,10 @@ static void R_CreateWorldVBO(void) // create arrays - s_worldData.numVerts = numVerts; - s_worldData.verts = verts = ri.Hunk_Alloc(numVerts * sizeof(srfVert_t), h_low); + verts = ri.Hunk_AllocateTempMemory(numVerts * sizeof(srfVert_t)); //optimizedVerts = ri.Hunk_AllocateTempMemory(numVerts * sizeof(srfVert_t)); - s_worldData.numTriangles = numTriangles; - s_worldData.triangles = triangles = ri.Hunk_Alloc(numTriangles * sizeof(srfTriangle_t), h_low); - + triangles = ri.Hunk_AllocateTempMemory(numTriangles * sizeof(srfTriangle_t)); // presort surfaces surfacesSorted = ri.Malloc(numSurfaces * sizeof(*surfacesSorted)); @@ -1950,23 +1949,9 @@ static void R_CreateWorldVBO(void) } } -#if 0 - numVerts = OptimizeVertices(numVerts, verts, numTriangles, triangles, optimizedVerts, CompareWorldVert); - if(c_redundantVertexes) - { - ri.Printf(PRINT_DEVELOPER, - "...removed %i redundant vertices from staticWorldMesh %i ( %s, %i verts %i tris )\n", - c_redundantVertexes, vboSurfaces.currentElements, shader->name, numVerts, numTriangles); - } - - s_worldData.vbo = R_CreateVBO2(va("bspModelMesh_vertices %i", 0), numVerts, optimizedVerts, - ATTR_POSITION | ATTR_TEXCOORD | ATTR_LIGHTCOORD | ATTR_TANGENT | ATTR_BITANGENT | - ATTR_NORMAL | ATTR_COLOR | GLCS_LIGHTCOLOR | ATTR_LIGHTDIRECTION); -#else s_worldData.vbo = R_CreateVBO2(va("staticBspModel0_VBO %i", 0), numVerts, verts, ATTR_POSITION | ATTR_TEXCOORD | ATTR_LIGHTCOORD | ATTR_TANGENT | ATTR_BITANGENT | ATTR_NORMAL | ATTR_COLOR, VBO_USAGE_STATIC); -#endif s_worldData.ibo = R_CreateIBO2(va("staticBspModel0_IBO %i", 0), numTriangles, triangles, VBO_USAGE_STATIC); @@ -2011,42 +1996,11 @@ static void R_CreateWorldVBO(void) startTime = ri.Milliseconds(); - // Tr3B: FIXME move this to somewhere else? -#if CALC_REDUNDANT_SHADOWVERTS - s_worldData.redundantVertsCalculationNeeded = 0; - for(i = 0; i < s_worldData.numLights; i++) - { - light = &s_worldData.lights[i]; - - if((r_precomputedLighting->integer || r_vertexLighting->integer) && !light->noRadiosity) - continue; - - s_worldData.redundantVertsCalculationNeeded++; - } - - if(s_worldData.redundantVertsCalculationNeeded) - { - ri.Printf(PRINT_ALL, "...calculating redundant world vertices ( %i verts )\n", numVerts); - - s_worldData.redundantLightVerts = ri.Hunk_Alloc(numVerts * sizeof(int), h_low); - BuildRedundantIndices(numVerts, verts, s_worldData.redundantLightVerts, CompareLightVert); - - s_worldData.redundantShadowVerts = ri.Hunk_Alloc(numVerts * sizeof(int), h_low); - BuildRedundantIndices(numVerts, verts, s_worldData.redundantShadowVerts, CompareShadowVert); - - s_worldData.redundantShadowAlphaTestVerts = ri.Hunk_Alloc(numVerts * sizeof(int), h_low); - BuildRedundantIndices(numVerts, verts, s_worldData.redundantShadowAlphaTestVerts, CompareShadowVertAlphaTest); - } - - endTime = ri.Milliseconds(); - ri.Printf(PRINT_ALL, "redundant world vertices calculation time = %5.2f seconds\n", (endTime - startTime) / 1000.0); -#endif - ri.Free(surfacesSorted); - //ri.Hunk_FreeTempMemory(triangles); + ri.Hunk_FreeTempMemory(triangles); //ri.Hunk_FreeTempMemory(optimizedVerts); - //ri.Hunk_FreeTempMemory(verts); + ri.Hunk_FreeTempMemory(verts); } @@ -2088,6 +2042,7 @@ static void R_LoadSurfaces( lump_t *surfs, lump_t *verts, lump_t *indexLump ) { s_worldData.numsurfaces = count; s_worldData.surfacesViewCount = ri.Hunk_Alloc ( count * sizeof(*s_worldData.surfacesViewCount), h_low ); s_worldData.surfacesDlightBits = ri.Hunk_Alloc ( count * sizeof(*s_worldData.surfacesDlightBits), h_low ); + s_worldData.surfacesPshadowBits = ri.Hunk_Alloc ( count * sizeof(*s_worldData.surfacesPshadowBits), h_low ); //s_worldData.numWorldSurfaces = count; // Two passes, allocate surfaces first, then load them full of data @@ -2147,7 +2102,7 @@ static void R_LoadSurfaces( lump_t *surfs, lump_t *verts, lump_t *indexLump ) { { srfSurfaceFace_t *surface = (srfSurfaceFace_t *)out->data; - out->cullinfo.type = CULLINFO_PLANE; // | CULLINFO_BOX; + out->cullinfo.type = CULLINFO_PLANE | CULLINFO_BOX; VectorCopy(surface->bounds[0], out->cullinfo.bounds[0]); VectorCopy(surface->bounds[1], out->cullinfo.bounds[1]); out->cullinfo.plane = surface->plane; @@ -3163,3 +3118,4 @@ void RE_LoadWorldMap( const char *name ) { } + diff --git a/reaction/code/renderer/tr_cmds.c b/reaction/code/renderer/tr_cmds.c index 23a7e827..a7bce0ea 100644 --- a/reaction/code/renderer/tr_cmds.c +++ b/reaction/code/renderer/tr_cmds.c @@ -202,6 +202,7 @@ void *R_GetCommandBuffer( int bytes ) { renderCommandList_t *cmdList; cmdList = &backEndData[tr.smpFrame]->commands; + bytes = PAD(bytes, sizeof(void *)); // always leave room for the end of list command if ( cmdList->used + bytes + 4 > MAX_RENDER_COMMANDS ) { @@ -241,6 +242,26 @@ void R_AddDrawSurfCmd( drawSurf_t *drawSurfs, int numDrawSurfs ) { } +/* +============= +R_AddCapShadowmapCmd + +============= +*/ +void R_AddCapShadowmapCmd( int map, int cubeSide ) { + capShadowmapCommand_t *cmd; + + cmd = R_GetCommandBuffer( sizeof( *cmd ) ); + if ( !cmd ) { + return; + } + cmd->commandId = RC_CAPSHADOWMAP; + + cmd->map = map; + cmd->cubeSide = cubeSide; +} + + /* ============= RE_SetColor @@ -417,7 +438,7 @@ void RE_BeginFrame( stereoFrame_t stereoFrame ) { R_SyncRenderThread(); if ((err = qglGetError()) != GL_NO_ERROR) - ri.Error(ERR_FATAL, "RE_BeginFrame() - glGetError() failed (0x%x)!\n", err); + ri.Error(ERR_FATAL, "RE_BeginFrame() - glGetError() failed (0x%x)!", err); } if (glConfig.stereoEnabled) { diff --git a/reaction/code/renderer/tr_extramath.c b/reaction/code/renderer/tr_extramath.c index 6e3f1afa..074e09f5 100644 --- a/reaction/code/renderer/tr_extramath.c +++ b/reaction/code/renderer/tr_extramath.c @@ -123,3 +123,29 @@ void VectorLerp( vec3_t a, vec3_t b, float lerp, vec3_t c) c[1] = a[1] * (1.0f - lerp) + b[1] * lerp; c[2] = a[2] * (1.0f - lerp) + b[2] * lerp; } + +qboolean SpheresIntersect(vec3_t origin1, float radius1, vec3_t origin2, float radius2) +{ + float radiusSum = radius1 + radius2; + vec3_t diff; + + VectorSubtract(origin1, origin2, diff); + + if (DotProduct(diff, diff) <= radiusSum * radiusSum) + { + return qtrue; + } + + return qfalse; +} + +void BoundingSphereOfSpheres(vec3_t origin1, float radius1, vec3_t origin2, float radius2, vec3_t origin3, float *radius3) +{ + vec3_t diff; + + VectorScale(origin1, 0.5f, origin3); + VectorMA(origin3, 0.5f, origin2, origin3); + + VectorSubtract(origin1, origin2, diff); + *radius3 = VectorLength(diff) * 0.5 + MAX(radius1, radius2); +} diff --git a/reaction/code/renderer/tr_extramath.h b/reaction/code/renderer/tr_extramath.h index 29ae44c1..ef591363 100644 --- a/reaction/code/renderer/tr_extramath.h +++ b/reaction/code/renderer/tr_extramath.h @@ -41,6 +41,8 @@ void Matrix16Ortho( float left, float right, float bottom, float top, float znea #define DotProduct4(a,b) ((a)[0]*(b)[0] + (a)[1]*(b)[1] + (a)[2]*(b)[2] + (a)[3]*(b)[3]) #define VectorScale4(a,b,c) ((c)[0]=(a)[0]*(b),(c)[1]=(a)[1]*(b),(c)[2]=(a)[2]*(b),(c)[3]=(a)[3]*(b)) +#define VectorCopy5(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3],(b)[4]=(a)[4]) + static ID_INLINE int VectorCompare4(const vec4_t v1, const vec4_t v2) { if(v1[0] != v2[0] || v1[1] != v2[1] || v1[2] != v2[2] || v1[3] != v2[3]) @@ -50,8 +52,23 @@ static ID_INLINE int VectorCompare4(const vec4_t v1, const vec4_t v2) return 1; } +static ID_INLINE int VectorCompare5(const vec5_t v1, const vec5_t v2) +{ + if(v1[0] != v2[0] || v1[1] != v2[1] || v1[2] != v2[2] || v1[3] != v2[3] || v1[4] != v2[4]) + { + return 0; + } + return 1; +} + void VectorLerp( vec3_t a, vec3_t b, float lerp, vec3_t c); + +qboolean SpheresIntersect(vec3_t origin1, float radius1, vec3_t origin2, float radius2); +void BoundingSphereOfSpheres(vec3_t origin1, float radius1, vec3_t origin2, float radius2, vec3_t origin3, float *radius3); + +#ifndef SGN #define SGN(x) (((x) >= 0) ? !!(x) : -1) +#endif #endif diff --git a/reaction/code/renderer/tr_flares.c b/reaction/code/renderer/tr_flares.c index aa556b0a..96b36aa9 100644 --- a/reaction/code/renderer/tr_flares.c +++ b/reaction/code/renderer/tr_flares.c @@ -528,3 +528,4 @@ void RB_RenderFlares (void) { } + diff --git a/reaction/code/renderer/tr_glsl.c b/reaction/code/renderer/tr_glsl.c index 138e50f8..3c2bfad2 100644 --- a/reaction/code/renderer/tr_glsl.c +++ b/reaction/code/renderer/tr_glsl.c @@ -31,119 +31,104 @@ static const char *fallbackGenericShader_vp = "r_Color;\r\n\r\n#if defined(USE_VERTEX_ANIMATION)\r\nattribute vec4 attr_Po" "sition2;\r\nattribute vec3 attr_Normal2;\r\n#endif\r\n\r\nuniform mat4 u_" "DiffuseTexMatrix;\r\nuniform vec3 u_ViewOrigin;\r\n\r\n#if defined(USE_TC" -"GEN)\r\nuniform int u_TCGen0;\r\nuniform vec4 u_TCGen0Vector0;\r\nunif" -"orm vec4 u_TCGen0Vector1;\r\n#endif\r\n\r\n#if defined(USE_FOG)\r\nunifor" +"GEN)\r\nuniform int u_TCGen0;\r\nuniform vec3 u_TCGen0Vector0;\r\nunif" +"orm vec3 u_TCGen0Vector1;\r\n#endif\r\n\r\n#if defined(USE_FOG)\r\nunifor" "m vec4 u_FogDistance;\r\nuniform vec4 u_FogDepth;\r\nuniform float u_F" "ogEyeT;\r\nuniform int u_FogAdjustColors;\r\n#endif\r\n\r\n#if defined(U" -"SE_DEFORM_VERTEXES)\r\nuniform int u_DeformGen;\r\nuniform vec4 u_Defo" -"rmWave;\r\nuniform vec3 u_DeformBulge;\r\nuniform float u_DeformSpread;" -"\r\n#endif\r\n\r\nuniform float u_Time;\r\n\r\nuniform mat4 u_ModelViewP" -"rojectionMatrix;\r\nuniform vec4 u_Color;\r\n\r\n#if defined(USE_RGBAGEN)" -"\r\nuniform int u_ColorGen;\r\nuniform int u_AlphaGen;\r\nuniform vec" -"3 u_AmbientLight;\r\nuniform vec3 u_DirectedLight;\r\nuniform vec4 u_" -"LightOrigin;\r\nuniform float u_PortalRange;\r\n#endif\r\n\r\n#if defined(" -"USE_VERTEX_ANIMATION)\r\nuniform float u_VertexLerp;\r\n#endif\r\n\r\nvary" -"ing vec2 var_DiffuseTex;\r\nvarying vec2 var_LightTex;\r\nvarying vec4 " -" var_Color;\r\n\r\n#if defined(USE_DEFORM_VERTEXES)\r\nfloat triangle(floa" -"t x)\r\n{\r\n\treturn max(1.0 - abs(x), 0);\r\n}\r\n\r\nfloat sawtooth(floa" -"t x)\r\n{\r\n\treturn x - floor(x);\r\n}\r\n\r\nvec4 DeformPosition(const v" -"ec4 pos, const vec3 normal, const vec2 st)\r\n{\r\n\tvec4 deformed = pos;\r" -"\n\r\n\tif (u_DeformGen == DGEN_WAVE_SIN)\r\n\t{\r\n\t\tfloat off = (pos.x " -"+ pos.y + pos.z) * u_DeformSpread;\r\n\t\tfloat scale = u_DeformWave.x + s" -"in((off + u_DeformWave.z + (u_Time * u_DeformWave.w)) * 2.0 * M_PI) * u_Def" -"ormWave.y;\r\n\t\tvec3 offset = normal * scale;\r\n\r\n\t\tdeformed.xyz += " -"offset;\r\n\t}\r\n\telse if (u_DeformGen == DGEN_WAVE_SQUARE)\r\n\t{\r\n\t" -"\tfloat off = (pos.x + pos.y + pos.z) * u_DeformSpread;\r\n\t\tfloat scale " -"= u_DeformWave.x + sign(sin((off + u_DeformWave.z + (u_Time * u_DeformWave" -".w)) * 2.0 * M_PI)) * u_DeformWave.y;\r\n\t\tvec3 offset = normal * scale;" -"\r\n\r\n\t\tdeformed.xyz += offset;\r\n\t}\r\n\telse if (u_DeformGen == DGE" -"N_WAVE_TRIANGLE)\r\n\t{\r\n\t\tfloat off = (pos.x + pos.y + pos.z) * u_Defo" -"rmSpread;\r\n\t\tfloat scale = u_DeformWave.x + triangle(off + u_DeformWav" -"e.z + (u_Time * u_DeformWave.w)) * u_DeformWave.y;\r\n\t\tvec3 offset = nor" -"mal * scale;\r\n\r\n\t\tdeformed.xyz += offset;\r\n\t}\r\n\telse if (u_Defo" -"rmGen == DGEN_WAVE_SAWTOOTH)\r\n\t{\r\n\t\tfloat off = (pos.x + pos.y + pos" -".z) * u_DeformSpread;\r\n\t\tfloat scale = u_DeformWave.x + sawtooth(off +" -" u_DeformWave.z + (u_Time * u_DeformWave.w)) * u_DeformWave.y;\r\n\t\tvec3 " -"offset = normal * scale;\r\n\r\n\t\tdeformed.xyz += offset;\r\n\t}\r\n\tels" -"e if (u_DeformGen == DGEN_WAVE_INVERSE_SAWTOOTH)\r\n\t{\r\n\t\tfloat off = " -"(pos.x + pos.y + pos.z) * u_DeformSpread;\r\n\t\tfloat scale = u_DeformWave" -".x + (1.0 - sawtooth(off + u_DeformWave.z + (u_Time * u_DeformWave.w))) * u" -"_DeformWave.y;\r\n\t\tvec3 offset = normal * scale;\r\n\r\n\t\tdeformed.xyz" -" += offset;\r\n\t}\r\n\telse if (u_DeformGen == DGEN_BULGE)\r\n\t{\r\n\t\tf" -"loat bulgeWidth = u_DeformBulge.x;\r\n\t\tfloat bulgeHeight = u_DeformBulge" -".y;\r\n\t\tfloat bulgeSpeed = u_DeformBulge.z;\r\n\r\n\t\tfloat now = u_Tim" -"e * bulgeSpeed;\r\n\r\n\t\tfloat off = (M_PI * 0.25) * st.x * bulgeWidth + " -"now;\r\n\t\tfloat scale = sin(off) * bulgeHeight;\r\n\t\tvec3 offset = norm" -"al * scale;\r\n\r\n\t\tdeformed.xyz += offset;\r\n\t}\r\n\r\n\treturn defor" -"med;\r\n}\r\n#endif\r\n\r\n#if defined(USE_TCGEN)\r\nvec2 GenTexCoords(int " -"TCGen, vec4 position, vec3 normal, vec4 TCGenVector0, vec4 TCGenVector1)\r" -"\n{\r\n\tvec2 tex = vec2(0.0);\r\n\r\n\tif (TCGen == TCGEN_LIGHTMAP)\r\n\t{" -"\r\n\t\ttex = attr_TexCoord1.st;\r\n\t}\r\n\telse if (TCGen == TCGEN_TEXTUR" -"E)\r\n\t{\r\n\t\ttex = attr_TexCoord0.st;\r\n\t}\r\n\telse if (TCGen == TCG" -"EN_ENVIRONMENT_MAPPED)\r\n\t{\r\n\t\tvec3 viewer = normalize(u_ViewOrigin -" -" position.xyz);\r\n\r\n\t\tfloat d = dot(normal, viewer);\r\n\r\n\t\tvec3 r" -"eflected = normal * 2.0 * d - viewer;\r\n\r\n\t\ttex.s = 0.5 + reflected.y " -"* 0.5;\r\n\t\ttex.t = 0.5 - reflected.z * 0.5;\r\n\t}\r\n\telse if (TCGen =" -"= TCGEN_VECTOR)\r\n\t{\r\n\t\ttex.s = dot(position.xyz, TCGenVector0.xyz);" -"\r\n\t\ttex.t = dot(position.xyz, TCGenVector1.xyz);\r\n\t}\r\n\t\r\n\tretu" -"rn tex;\r\n}\r\n#endif\r\n\r\nvoid main()\r\n{\r\n#if defined(USE_VERTEX_AN" -"IMATION)\r\n\tvec4 position = mix(attr_Position, attr_Position2, u_VertexLe" -"rp);\r\n\tvec3 normal = normalize(mix(attr_Normal, attr_Normal2, u_VertexLe" -"rp));\r\n#else\r\n\tvec4 position = attr_Position;\r\n\tvec3 normal = attr_" -"Normal;\r\n#endif\r\n\r\n#if defined(USE_DEFORM_VERTEXES)\r\n\tposition = D" -"eformPosition(position, normal, attr_TexCoord0.st);\r\n#endif\r\n\r\n\tgl_P" -"osition = u_ModelViewProjectionMatrix * position;\r\n\r\n\r\n\tvec4 tex = v" -"ec4(1.0, 1.0, 1.0, 0.0);\r\n\r\n#if defined(USE_TCGEN)\r\n\ttex.st = GenTex" -"Coords(u_TCGen0, position, normal, u_TCGen0Vector0, u_TCGen0Vector1);\r\n#e" -"lse\r\n\ttex.st = attr_TexCoord0.st;\r\n#endif\r\n \r\n\tvar_DiffuseTex " -"= (u_DiffuseTexMatrix * tex).st;\r\n\r\n\tvar_DiffuseTex.s += sin(((positio" -"n.x + position.z) * 1.0 / 128.0 * 0.125 + u_DiffuseTexMatrix[3][1]) * 2.0 *" -" M_PI) * u_DiffuseTexMatrix[3][0];\r\n\tvar_DiffuseTex.t += sin((position.y" -" * 1.0 / 128.0 * 0.125 + u_DiffuseTexMatrix[3][1]) * 2.0 * M_PI) * u_Diffus" -"eTexMatrix[3][0];\r\n\r\n\tvar_LightTex = attr_TexCoord1.st;\r\n\t\r\n\tvar" -"_Color = u_Color;\r\n\r\n#if defined(USE_RGBAGEN)\r\n\tif (u_ColorGen == CG" -"EN_LIGHTING_DIFFUSE)\r\n\t{\r\n\t\t// when CGEN_LIGHTING_DIFFUSE, u_LightOr" -"igin is always at infinity, ie directional\r\n\t\tfloat incoming = max(dot(" -"normal, u_LightOrigin.xyz), 0.0);\r\n\r\n\t\tvar_Color.rgb = min(u_Directed" -"Light * incoming + u_AmbientLight, 1.0);\r\n\t}\r\n\telse if (u_ColorGen ==" -" CGEN_EXACT_VERTEX)\r\n\t{\r\n\t\tvar_Color.rgb = attr_Color.rgb;\r\n\t}\r" -"\n\telse if (u_ColorGen == CGEN_VERTEX)\r\n\t{\r\n\t\tvar_Color.rgb *= attr" -"_Color.rgb;\r\n\t}\r\n\telse if (u_ColorGen == CGEN_ONE_MINUS_VERTEX)\r\n\t" -"{\r\n\t\tvar_Color.rgb *= (vec3(1.0) - attr_Color.rgb);\r\n\t}\r\n\r\n\tif " -"(u_AlphaGen == AGEN_LIGHTING_SPECULAR)\r\n\t{\r\n\t\tvec3 lightDir = normal" -"ize(vec3(-960.0, -1980.0, 96.0) - position.xyz);\r\n\t\tvec3 viewer = norma" -"lize(u_ViewOrigin - position.xyz);\r\n\t\tvec3 halfangle = normalize(lightD" -"ir + viewer);\r\n\t\t\r\n\t\tvar_Color.a = pow(max(dot(normal, halfangle), " -"0.0), 8.0);\r\n\t}\r\n\telse if (u_AlphaGen == AGEN_VERTEX)\r\n\t{\r\n\t\tv" -"ar_Color.a = attr_Color.a;\r\n\t}\r\n\telse if (u_AlphaGen == AGEN_ONE_MINU" -"S_VERTEX)\r\n\t{\r\n\t\tvar_Color.a = 1.0 - attr_Color.a;\r\n\t}\r\n\telse " -"if (u_AlphaGen == AGEN_PORTAL)\r\n\t{\r\n\t\tfloat alpha = length(position." -"xyz - u_ViewOrigin) / u_PortalRange;\r\n\r\n\t\tvar_Color.a = min(alpha, 1." -"0);\r\n\t}\r\n\telse if (u_AlphaGen == AGEN_FRESNEL)\r\n\t{\r\n\t\tvec3 vie" -"wer = normalize(u_ViewOrigin - position.xyz);\r\n\t\t\r\n\t\tvar_Color.a = " -"dot(viewer, normal);\r\n\t}\r\n#endif\r\n\r\n#if defined (USE_FOG)\r\n\tif " -"(u_FogAdjustColors != ACFF_NONE) \r\n\t{\r\n\t\tfloat s = max(dot(position." -"xyz, u_FogDistance.xyz) + u_FogDistance.a, 0.0);\r\n\t\tfloat t = max(dot(p" -"osition.xyz, u_FogDepth.xyz) + u_FogDepth.a, 0.0);\r\n\t\t\r\n\t\tif (t >= " -"1.0)\r\n\t\t{\r\n\t\t\ts *= t / (t - min(u_FogEyeT, 0.0));\r\n\t\t}\r\n\t\t" -"\r\n\t\ts = 1.0 - sqrt(min(s * 8.0, 1.0));\r\n\t\r\n\t\tif (u_FogAdjustColo" -"rs == ACFF_MODULATE_RGB)\r\n\t\t{\r\n\t\t\tvar_Color.xyz *= s;\r\n\t\t}\r\n" -"\t\telse if (u_FogAdjustColors == ACFF_MODULATE_ALPHA)\r\n\t\t{\r\n\t\t\tva" -"r_Color.a *= s;\r\n\t\t}\r\n\t\telse if (u_FogAdjustColors == ACFF_MODULATE" -"_RGBA)\r\n\t\t{\r\n\t\t\tvar_Color *= s;\r\n\t\t}\r\n\t}\r\n#endif\r\n}\r\n"; +"SE_DEFORM_VERTEXES)\r\nuniform int u_DeformGen;\r\nuniform float u_Defo" +"rmParams[5];\r\n#endif\r\n\r\nuniform float u_Time;\r\n\r\nuniform mat4 " +"u_ModelViewProjectionMatrix;\r\nuniform vec4 u_Color;\r\n\r\n#if defined(" +"USE_RGBAGEN)\r\nuniform int u_ColorGen;\r\nuniform int u_AlphaGen;\r" +"\nuniform vec3 u_AmbientLight;\r\nuniform vec3 u_DirectedLight;\r\nunif" +"orm vec4 u_LightOrigin;\r\nuniform float u_PortalRange;\r\n#endif\r\n\r" +"\n#if defined(USE_VERTEX_ANIMATION)\r\nuniform float u_VertexLerp;\r\n#end" +"if\r\n\r\nvarying vec2 var_DiffuseTex;\r\nvarying vec2 var_LightTex;\r" +"\nvarying vec4 var_Color;\r\n\r\nvec2 DoTexMatrix(vec2 st, vec3 position," +" mat4 texMatrix)\r\n{\r\n\tfloat amplitude = texMatrix[3][0];\r\n\tfloat ph" +"ase = texMatrix[3][1];\r\n\tvec2 st2 = (texMatrix * vec4(st, 1.0, 0.0)).st;" +"\r\n\r\n\tvec3 offsetPos = position.xyz / 1024.0;\r\n\toffsetPos.x += offse" +"tPos.z;\r\n\r\n\tvec2 texOffset = sin((offsetPos.xy + vec2(phase)) * 2.0 * " +"M_PI);\r\n\t\r\n\treturn st2 + texOffset * amplitude;\r\n}\r\n\r\n#if defin" +"ed(USE_DEFORM_VERTEXES)\r\nfloat triangle(float x)\r\n{\r\n\treturn max(1.0" +" - abs(x), 0);\r\n}\r\n\r\nfloat sawtooth(float x)\r\n{\r\n\treturn x - flo" +"or(x);\r\n}\r\n\r\nvec4 DeformPosition(const vec4 pos, const vec3 normal, c" +"onst vec2 st)\r\n{\r\n\tfloat base = u_DeformParams[0];\r\n\tfloat amp" +"litude = u_DeformParams[1];\r\n\tfloat phase = u_DeformParams[2];\r\n\t" +"float frequency = u_DeformParams[3];\r\n\tfloat spread = u_DeformParams[" +"4];\r\n\t\r\n\tif (u_DeformGen == DGEN_BULGE)\r\n\t{\r\n\t\tphase *= M_PI *" +" 0.25 * st.x;\r\n\t}\r\n\telse // if (u_DeformGen <= DGEN_WAVE_INVERSE_SAWT" +"OOTH)\r\n\t{\r\n\t\tphase += (pos.x + pos.y + pos.z) * spread;\r\n\t}\r\n\r" +"\n\tfloat value = phase + (u_Time * frequency);\r\n\tfloat func;\r\n\r\n\ti" +"f (u_DeformGen == DGEN_WAVE_SIN)\r\n\t{\r\n\t\tfunc = sin(value * 2.0 * M_P" +"I);\r\n\t}\r\n\telse if (u_DeformGen == DGEN_WAVE_SQUARE)\r\n\t{\r\n\t\tfun" +"c = sign(sin(value * 2.0 * M_PI));\r\n\t}\r\n\telse if (u_DeformGen == DGEN" +"_WAVE_TRIANGLE)\r\n\t{\r\n\t\tfunc = triangle(value);\r\n\t}\r\n\telse if (" +"u_DeformGen == DGEN_WAVE_SAWTOOTH)\r\n\t{\r\n\t\tfunc = sawtooth(value);\r" +"\n\t}\r\n\telse if (u_DeformGen == DGEN_WAVE_INVERSE_SAWTOOTH)\r\n\t{\r\n\t" +"\tfunc = (1.0 - sawtooth(value));\r\n\t}\r\n\telse if (u_DeformGen == DGEN_" +"BULGE)\r\n\t{\r\n\t\tfunc = sin(value);\r\n\t}\r\n\t\r\n\tvec4 deformed = p" +"os;\r\n\tdeformed.xyz += normal * (base + func * amplitude);\r\n\r\n\tretur" +"n deformed;\r\n}\r\n#endif\r\n\r\n#if defined(USE_TCGEN)\r\nvec2 GenTexCoor" +"ds(int TCGen, vec4 position, vec3 normal, vec3 TCGenVector0, vec3 TCGenVect" +"or1)\r\n{\r\n\tvec2 tex = attr_TexCoord0.st;\r\n\r\n\tif (TCGen == TCGEN_LI" +"GHTMAP)\r\n\t{\r\n\t\ttex = attr_TexCoord1.st;\r\n\t}\r\n\telse if (TCGen =" +"= TCGEN_ENVIRONMENT_MAPPED)\r\n\t{\r\n\t\tvec3 viewer = normalize(u_ViewOri" +"gin - position.xyz);\r\n\t\tvec3 reflected = normal * 2.0 * dot(normal, vie" +"wer) - viewer;\r\n\r\n\t\ttex.s = 0.5 + reflected.y * 0.5;\r\n\t\ttex.t = 0" +".5 - reflected.z * 0.5;\r\n\t}\r\n\telse if (TCGen == TCGEN_VECTOR)\r\n\t{" +"\r\n\t\ttex.s = dot(position.xyz, TCGenVector0);\r\n\t\ttex.t = dot(positio" +"n.xyz, TCGenVector1);\r\n\t}\r\n\t\r\n\treturn tex;\r\n}\r\n#endif\r\n\r\nv" +"oid main()\r\n{\r\n#if defined(USE_VERTEX_ANIMATION)\r\n\tvec4 position = m" +"ix(attr_Position, attr_Position2, u_VertexLerp);\r\n\tvec3 normal = normali" +"ze(mix(attr_Normal, attr_Normal2, u_VertexLerp));\r\n#else\r\n\tvec4 positi" +"on = attr_Position;\r\n\tvec3 normal = attr_Normal;\r\n#endif\r\n\r\n#if de" +"fined(USE_DEFORM_VERTEXES)\r\n\tposition = DeformPosition(position, normal," +" attr_TexCoord0.st);\r\n#endif\r\n\r\n\tgl_Position = u_ModelViewProjection" +"Matrix * position;\r\n\r\n#if defined(USE_TCGEN)\r\n\tvec2 tex = GenTexCoor" +"ds(u_TCGen0, position, normal, u_TCGen0Vector0, u_TCGen0Vector1);\r\n#else" +"\r\n\tvec2 tex = attr_TexCoord0.st;\r\n#endif\r\n\tvar_DiffuseTex = DoTexMa" +"trix(tex, position.xyz, u_DiffuseTexMatrix);\r\n\r\n\tvar_LightTex = attr_T" +"exCoord1.st;\r\n\t\r\n\tvar_Color = u_Color;\r\n\r\n#if defined(USE_RGBAGEN" +")\r\n\tif (u_ColorGen == CGEN_LIGHTING_DIFFUSE)\r\n\t{\r\n\t\tfloat incomin" +"g = max(dot(normal, u_LightOrigin.xyz), 0.0);\r\n\r\n\t\tvar_Color.rgb = mi" +"n(u_DirectedLight * incoming + u_AmbientLight, 1.0);\r\n\t}\r\n\telse if (u" +"_ColorGen == CGEN_EXACT_VERTEX)\r\n\t{\r\n\t\tvar_Color.rgb = attr_Color.rg" +"b;\r\n\t}\r\n\telse if (u_ColorGen == CGEN_VERTEX)\r\n\t{\r\n\t\tvar_Color." +"rgb *= attr_Color.rgb;\r\n\t}\r\n\telse if (u_ColorGen == CGEN_ONE_MINUS_VE" +"RTEX)\r\n\t{\r\n\t\tvar_Color.rgb *= (vec3(1.0) - attr_Color.rgb);\r\n\t}\r" +"\n\r\n\tif (u_AlphaGen == AGEN_LIGHTING_SPECULAR)\r\n\t{\r\n\t\tvec3 lightD" +"ir = normalize(vec3(-960.0, -1980.0, 96.0) - position.xyz);\r\n\t\tvec3 vie" +"wer = normalize(u_ViewOrigin - position.xyz);\r\n\t\tvec3 halfangle = norma" +"lize(lightDir + viewer);\r\n\t\t\r\n\t\tvar_Color.a = pow(max(dot(normal, h" +"alfangle), 0.0), 8.0);\r\n\t}\r\n\telse if (u_AlphaGen == AGEN_VERTEX)\r\n" +"\t{\r\n\t\tvar_Color.a = attr_Color.a;\r\n\t}\r\n\telse if (u_AlphaGen == A" +"GEN_ONE_MINUS_VERTEX)\r\n\t{\r\n\t\tvar_Color.a = 1.0 - attr_Color.a;\r\n\t" +"}\r\n\telse if (u_AlphaGen == AGEN_PORTAL)\r\n\t{\r\n\t\tfloat alpha = leng" +"th(position.xyz - u_ViewOrigin) / u_PortalRange;\r\n\r\n\t\tvar_Color.a = m" +"in(alpha, 1.0);\r\n\t}\r\n\telse if (u_AlphaGen == AGEN_FRESNEL)\r\n\t{\r\n" +"\t\tvec3 viewer = normalize(u_ViewOrigin - position.xyz);\r\n\t\t\r\n\t\tva" +"r_Color.a = dot(viewer, normal);\r\n\t}\r\n#endif\r\n\r\n#if defined (USE_F" +"OG)\r\n\tfloat s = dot(position.xyz, u_FogDistance.xyz) + u_FogDistance.w;" +"\r\n\tfloat t = dot(position.xyz, u_FogDepth.xyz) + u_FogDepth.w;\r\n\t\r\n" +"\tif (t >= 1.0)\r\n\t{\r\n\t\ts *= t / (t - min(u_FogEyeT, 0.0));\r\n\t}\r" +"\n\telse\r\n\t{\r\n\t\ts *= max(t + sign(u_FogEyeT), 0.0);\r\n\t}\r\n\t\r\n" +"\ts = 1.0 - sqrt(clamp(s * 8.0, 0.0, 1.0));\r\n\r\n\tif (u_FogAdjustColors " +"== ACFF_MODULATE_RGB)\r\n\t{\r\n\t\tvar_Color.rgb *= s;\r\n\t}\r\n\telse if" +" (u_FogAdjustColors == ACFF_MODULATE_ALPHA)\r\n\t{\r\n\t\tvar_Color.a *= s;" +"\r\n\t}\r\n\telse if (u_FogAdjustColors == ACFF_MODULATE_RGBA)\r\n\t{\r\n\t" +"\tvar_Color *= s;\r\n\t}\r\n#endif\r\n}\r\n"; static const char *fallbackGenericShader_fp = "uniform sampler2D u_DiffuseMap;\r\nuniform sampler2D u_LightMap;\r\nuniform" " int u_Texture1Env;\r\n\r\nvarying vec2 var_DiffuseTex;\r\nvaryi" "ng vec2 var_LightTex;\r\nvarying vec4 var_Color;\r\n\r\n\r\nvoid " -"main()\r\n{\r\n\tvec4 color;\r\n\r\n\tif (u_Texture1Env != 2)\r\n\t{\r\n\t" -"\tcolor = texture2D(u_DiffuseMap, var_DiffuseTex);\r\n\t}\r\n\r\n\tif (u_Te" -"xture1Env != 0)\r\n\t{\r\n\t\tvec4 color2 = texture2D(u_LightMap, var_Light" -"Tex);\r\n\r\n\t\tif (u_Texture1Env == GL_MODULATE)\r\n\t\t{\r\n\t\t\tcolor " -"*= color2;\r\n\t\t}\r\n\t\t\telse if (u_Texture1Env == GL_ADD)\r\n\t\t{\r\n" -"\t\t\tcolor += color2;\r\n\t\t}\r\n\t\t\telse // if (u_Texture1Env == GL_RE" -"PLACE)\r\n\t\t{\r\n\t\t\tcolor = color2;\r\n\t\t}\r\n\t}\r\n\r\n\tcolor *= " -"var_Color;\r\n\r\n\tgl_FragColor = color;\r\n}\r\n"; +"main()\r\n{\r\n\tvec4 color = texture2D(u_DiffuseMap, var_DiffuseTex);\r\n" +"\r\n#if defined(USE_LIGHTMAP)\r\n\tvec4 color2 = texture2D(u_LightMap, va" +"r_LightTex);\r\n\r\n\tif (u_Texture1Env == TEXENV_MODULATE)\r\n\t{\r\n\t\tc" +"olor *= color2;\r\n\t}\r\n\telse if (u_Texture1Env == TEXENV_ADD)\r\n\t{\r" +"\n\t\tcolor += color2;\r\n\t}\r\n\telse if (u_Texture1Env == TEXENV_REPLACE" +")\r\n\t{\r\n\t\tcolor = color2;\r\n\t}\r\n#endif\r\n\r\n\tgl_FragColor = co" +"lor * var_Color;\r\n}\r\n"; static const char *fallbackTextureColorShader_vp = "#version 120\r\n\r\nattribute vec4 attr_Position;\r\nattribute vec4 attr_Te" @@ -163,112 +148,81 @@ static const char *fallbackFogPassShader_vp = "ute vec4 attr_Position2;\r\nattribute vec3 attr_Normal2;\r\n//#endif\r\n" "\r\nuniform vec4 u_FogDistance;\r\nuniform vec4 u_FogDepth;\r\nunifor" "m float u_FogEyeT;\r\n\r\n//#if defined(USE_DEFORM_VERTEXES)\r\nuniform i" -"nt u_DeformGen;\r\nuniform vec4 u_DeformWave;\r\nuniform vec3 u_D" -"eformBulge;\r\nuniform float u_DeformSpread;\r\n//#endif\r\n\r\nuniform f" -"loat u_Time;\r\nuniform vec4 u_Color;\r\nuniform mat4 u_ModelViewPr" -"ojectionMatrix;\r\n\r\n//#if defined(USE_VERTEX_ANIMATION)\r\nuniform float" -" u_VertexLerp;\r\n//#endif\r\n\r\nvarying vec4 var_Color;\r\n\r\n//#if" -" defined(USE_DEFORM_VERTEXES)\r\nfloat triangle(float x)\r\n{\r\n\treturn m" -"ax(1.0 - abs(x), 0);\r\n}\r\n\r\nfloat sawtooth(float x)\r\n{\r\n\treturn x" -" - floor(x);\r\n}\r\n\r\nvec4 DeformPosition(const vec4 pos, const vec3 nor" -"mal, const vec2 st)\r\n{\r\n\tvec4 deformed = pos;\r\n\r\n\tif (u_DeformGen" -" == DGEN_WAVE_SIN)\r\n\t{\r\n\t\tfloat off = (pos.x + pos.y + pos.z) * u_De" -"formSpread;\r\n\t\tfloat scale = u_DeformWave.x + sin((off + u_DeformWave." -"z + (u_Time * u_DeformWave.w)) * 2.0 * M_PI) * u_DeformWave.y;\r\n\t\tvec3 " -"offset = normal * scale;\r\n\r\n\t\tdeformed.xyz += offset;\r\n\t}\r\n\tels" -"e if (u_DeformGen == DGEN_WAVE_SQUARE)\r\n\t{\r\n\t\tfloat off = (pos.x + p" -"os.y + pos.z) * u_DeformSpread;\r\n\t\tfloat scale = u_DeformWave.x + sign" -"(sin((off + u_DeformWave.z + (u_Time * u_DeformWave.w)) * 2.0 * M_PI)) * u_" -"DeformWave.y;\r\n\t\tvec3 offset = normal * scale;\r\n\r\n\t\tdeformed.xyz " -"+= offset;\r\n\t}\r\n\telse if (u_DeformGen == DGEN_WAVE_TRIANGLE)\r\n\t{\r" -"\n\t\tfloat off = (pos.x + pos.y + pos.z) * u_DeformSpread;\r\n\t\tfloat sc" -"ale = u_DeformWave.x + triangle(off + u_DeformWave.z + (u_Time * u_DeformW" -"ave.w)) * u_DeformWave.y;\r\n\t\tvec3 offset = normal * scale;\r\n\r\n\t\td" -"eformed.xyz += offset;\r\n\t}\r\n\telse if (u_DeformGen == DGEN_WAVE_SAWTOO" -"TH)\r\n\t{\r\n\t\tfloat off = (pos.x + pos.y + pos.z) * u_DeformSpread;\r\n" -"\t\tfloat scale = u_DeformWave.x + sawtooth(off + u_DeformWave.z + (u_Time" -" * u_DeformWave.w)) * u_DeformWave.y;\r\n\t\tvec3 offset = normal * scale;" -"\r\n\r\n\t\tdeformed.xyz += offset;\r\n\t}\r\n\telse if (u_DeformGen == DGE" -"N_WAVE_INVERSE_SAWTOOTH)\r\n\t{\r\n\t\tfloat off = (pos.x + pos.y + pos.z) " -"* u_DeformSpread;\r\n\t\tfloat scale = u_DeformWave.x + (1.0 - sawtooth(off" -" + u_DeformWave.z + (u_Time * u_DeformWave.w))) * u_DeformWave.y;\r\n\t\tve" -"c3 offset = normal * scale;\r\n\r\n\t\tdeformed.xyz += offset;\r\n\t}\r\n\t" -"else if (u_DeformGen == DGEN_BULGE)\r\n\t{\r\n\t\tfloat bulgeWidth = u_Defo" -"rmBulge.x;\r\n\t\tfloat bulgeHeight = u_DeformBulge.y;\r\n\t\tfloat bulgeSp" -"eed = u_DeformBulge.z;\r\n\r\n\t\tfloat now = u_Time * bulgeSpeed;\r\n\r\n" -"\t\tfloat off = (M_PI * 0.25) * st.x * bulgeWidth + now;\r\n\t\tfloat scale" -" = sin(off) * bulgeHeight;\r\n\t\tvec3 offset = normal * scale;\r\n\r\n\t\t" -"deformed.xyz += offset;\r\n\t}\r\n\r\n\treturn deformed;\r\n}\r\n//#endif\r" -"\n\r\n\r\nvoid\tmain()\r\n{\r\n\tvec4 position;\r\n\tvec3 normal;\r\n\r\n//" -"#if defined(USE_VERTEX_ANIMATION)\r\n\tif (u_VertexLerp > 0.0)\r\n\t{\r\n\t" -"\tposition = mix(attr_Position, attr_Position2, u_VertexLerp);\r\n\t\tnorma" -"l = normalize(mix(attr_Normal, attr_Normal2, u_VertexLerp));\r\n\t}\r\n\tel" -"se\r\n//#endif\r\n\t{\r\n\t\tposition = attr_Position;\r\n\t\tnormal = attr" -"_Normal;\r\n\t}\r\n\r\n//#if defined(USE_DEFORM_VERTEXES)\r\n\tposition = D" -"eformPosition(position, normal, attr_TexCoord0.st);\r\n//#endif\r\n\r\n\tgl" -"_Position = u_ModelViewProjectionMatrix * position;\r\n\r\n\tfloat s = max(" -"dot(position.xyz, u_FogDistance.xyz) + u_FogDistance.a, 0.0);\r\n\tfloat t " -"= max(dot(position.xyz, u_FogDepth.xyz) + u_FogDepth.a, 0.0);\r\n\t\r\n\tif" -" (t >= 1.0)\r\n\t{\r\n\t\ts *= t / (t - min(u_FogEyeT, 0.0));\r\n\t}\r\n\t" -"\r\n\ts = sqrt(min(s * 8.0, 1.0));\r\n\t\r\n\tvar_Color.xyz = u_Color.xyz;" -"\r\n\tvar_Color.a = u_Color.a * s;\r\n}\r\n"; +"nt u_DeformGen;\r\nuniform float u_DeformParams[5];\r\n//#endif\r\n\r" +"\nuniform float u_Time;\r\nuniform vec4 u_Color;\r\nuniform mat4 u_" +"ModelViewProjectionMatrix;\r\n\r\n//#if defined(USE_VERTEX_ANIMATION)\r\nun" +"iform float u_VertexLerp;\r\n//#endif\r\n\r\nvarying vec4 var_Color;\r" +"\nvarying float var_Scale;\r\n\r\n\r\nfloat triangle(float x)\r\n{\r\n\tr" +"eturn max(1.0 - abs(x), 0);\r\n}\r\n\r\nfloat sawtooth(float x)\r\n{\r\n\tr" +"eturn x - floor(x);\r\n}\r\n\r\nvec4 DeformPosition(const vec4 pos, const v" +"ec3 normal, const vec2 st)\r\n{\r\n\tif (u_DeformGen == 0)\r\n\t{\r\n\t\tre" +"turn pos;\r\n\t}\r\n\r\n\tfloat base = u_DeformParams[0];\r\n\tfloat a" +"mplitude = u_DeformParams[1];\r\n\tfloat phase = u_DeformParams[2];\r\n" +"\tfloat frequency = u_DeformParams[3];\r\n\tfloat spread = u_DeformParam" +"s[4];\r\n\t\t\r\n\tif (u_DeformGen <= DGEN_WAVE_INVERSE_SAWTOOTH)\r\n\t{\r" +"\n\t\tphase += (pos.x + pos.y + pos.z) * spread;\r\n\t}\r\n\telse if (u_Def" +"ormGen == DGEN_BULGE)\r\n\t{\r\n\t\tphase *= M_PI * 0.25 * st.x;\r\n\t}\r\n" +"\r\n\tfloat value = phase + (u_Time * frequency);\r\n\tfloat func;\r\n\r\n" +"\tif (u_DeformGen == DGEN_WAVE_SIN)\r\n\t{\r\n\t\tfunc = sin(value * 2.0 * " +"M_PI);\r\n\t}\r\n\telse if (u_DeformGen == DGEN_WAVE_SQUARE)\r\n\t{\r\n\t\t" +"func = sign(sin(value * 2.0 * M_PI));\r\n\t}\r\n\telse if (u_DeformGen == D" +"GEN_WAVE_TRIANGLE)\r\n\t{\r\n\t\tfunc = triangle(value);\r\n\t}\r\n\telse i" +"f (u_DeformGen == DGEN_WAVE_SAWTOOTH)\r\n\t{\r\n\t\tfunc = sawtooth(value);" +"\r\n\t}\r\n\telse if (u_DeformGen == DGEN_WAVE_INVERSE_SAWTOOTH)\r\n\t{\r\n" +"\t\tfunc = (1.0 - sawtooth(value));\r\n\t}\r\n\telse if (u_DeformGen == DGE" +"N_BULGE)\r\n\t{\r\n\t\tfunc = sin(value);\r\n\t}\r\n\r\n\tvec4 deformed = p" +"os;\r\n\tdeformed.xyz += normal * (base + func * amplitude);\r\n\r\n\tretur" +"n deformed;\r\n\r\n}\r\n\r\nvoid main()\r\n{\r\n\tvec4 position = mix(attr_" +"Position, attr_Position2, u_VertexLerp);\r\n\tvec3 normal = normalize(mix(a" +"ttr_Normal, attr_Normal2, u_VertexLerp));\r\n\r\n\tposition = DeformPositio" +"n(position, normal, attr_TexCoord0.st);\r\n\r\n\tgl_Position = u_ModelViewP" +"rojectionMatrix * position;\r\n\r\n\tfloat s = dot(position.xyz, u_FogDista" +"nce.xyz) + u_FogDistance.w;\r\n\tfloat t = dot(position.xyz, u_FogDepth.xyz" +") + u_FogDepth.w;\r\n\r\n\tif (t >= 1.0)\r\n\t{\r\n\t\ts *= t / (t - min(u_" +"FogEyeT, 0.0));\r\n\t}\r\n\telse\r\n\t{\r\n\t\ts *= max(t + sign(u_FogEyeT)" +", 0.0);\r\n\t}\r\n\t\r\n\tvar_Color = u_Color;\r\n\tvar_Scale = clamp(s * 8" +".0, 0.0, 1.0);\r\n}\r\n"; static const char *fallbackFogPassShader_fp = -"varying vec4 var_Color;\r\n\r\n\r\nvoid main()\r\n{\r\n\tgl_FragColor = var" -"_Color;\r\n}\r\n"; +"varying vec4 var_Color;\r\n\r\nvarying float var_Scale;\r\n\r\nvoid main()" +"\r\n{\r\n\tgl_FragColor = var_Color;\r\n\tgl_FragColor.a *= sqrt(var_Scale)" +";\r\n}\r\n"; static const char *fallbackDlightallShader_vp = "attribute vec4 attr_Position;\r\nattribute vec4 attr_TexCoord0;\r\nattribut" -"e vec3 attr_Normal;\r\n\r\nattribute vec4 attr_Position2;\r\nattribute vec3" -" attr_Normal2;\r\n\r\nuniform vec4 u_DlightInfo;\r\n\r\nuniform int u_" -"DeformGen;\r\nuniform vec4 u_DeformWave;\r\nuniform vec3 u_DeformBulge;" -"\r\nuniform float u_DeformSpread;\r\n\r\nuniform float u_Time;\r\nuniform" -" vec4 u_Color;\r\nuniform mat4 u_ModelViewProjectionMatrix;\r\n\r\nunif" -"orm float u_VertexLerp;\r\n\r\nvarying vec2 var_Tex1;\r\nvarying vec4 " -"var_Color;\r\n\r\nfloat triangle(float x)\r\n{\r\n\treturn max(1.0 - abs(x)" -", 0);\r\n}\r\n\r\nfloat sawtooth(float x)\r\n{\r\n\treturn x - floor(x);\r" -"\n}\r\n\r\nvec4 DeformPosition(const vec4 pos, const vec3 normal, const vec" -"2 st)\r\n{\r\n\tvec4 deformed = pos;\r\n\r\n\tif (u_DeformGen == DGEN_WAVE_" -"SIN)\r\n\t{\r\n\t\tfloat off = (pos.x + pos.y + pos.z) * u_DeformSpread;\r" -"\n\t\tfloat scale = u_DeformWave.x + sin((off + u_DeformWave.z + (u_Time *" -" u_DeformWave.w)) * 2.0 * M_PI) * u_DeformWave.y;\r\n\t\tvec3 offset = norm" -"al * scale;\r\n\r\n\t\tdeformed.xyz += offset;\r\n\t}\r\n\telse if (u_Defor" -"mGen == DGEN_WAVE_SQUARE)\r\n\t{\r\n\t\tfloat off = (pos.x + pos.y + pos.z)" -" * u_DeformSpread;\r\n\t\tfloat scale = u_DeformWave.x + sign(sin((off + u" -"_DeformWave.z + (u_Time * u_DeformWave.w)) * 2.0 * M_PI)) * u_DeformWave.y;" -"\r\n\t\tvec3 offset = normal * scale;\r\n\r\n\t\tdeformed.xyz += offset;\r" -"\n\t}\r\n\telse if (u_DeformGen == DGEN_WAVE_TRIANGLE)\r\n\t{\r\n\t\tfloat " -"off = (pos.x + pos.y + pos.z) * u_DeformSpread;\r\n\t\tfloat scale = u_Defo" -"rmWave.x + triangle(off + u_DeformWave.z + (u_Time * u_DeformWave.w)) * u_" -"DeformWave.y;\r\n\t\tvec3 offset = normal * scale;\r\n\r\n\t\tdeformed.xyz " -"+= offset;\r\n\t}\r\n\telse if (u_DeformGen == DGEN_WAVE_SAWTOOTH)\r\n\t{\r" -"\n\t\tfloat off = (pos.x + pos.y + pos.z) * u_DeformSpread;\r\n\t\tfloat sc" -"ale = u_DeformWave.x + sawtooth(off + u_DeformWave.z + (u_Time * u_DeformW" -"ave.w)) * u_DeformWave.y;\r\n\t\tvec3 offset = normal * scale;\r\n\r\n\t\td" -"eformed.xyz += offset;\r\n\t}\r\n\telse if (u_DeformGen == DGEN_WAVE_INVERS" -"E_SAWTOOTH)\r\n\t{\r\n\t\tfloat off = (pos.x + pos.y + pos.z) * u_DeformSpr" -"ead;\r\n\t\tfloat scale = u_DeformWave.x + (1.0 - sawtooth(off + u_DeformWa" -"ve.z + (u_Time * u_DeformWave.w))) * u_DeformWave.y;\r\n\t\tvec3 offset = n" -"ormal * scale;\r\n\r\n\t\tdeformed.xyz += offset;\r\n\t}\r\n\telse if (u_De" -"formGen == DGEN_BULGE)\r\n\t{\r\n\t\tfloat bulgeWidth = u_DeformBulge.x;\r" -"\n\t\tfloat bulgeHeight = u_DeformBulge.y;\r\n\t\tfloat bulgeSpeed = u_Defo" -"rmBulge.z;\r\n\r\n\t\tfloat now = u_Time * bulgeSpeed;\r\n\r\n\t\tfloat off" -" = (M_PI * 0.25) * st.x * bulgeWidth + now;\r\n\t\tfloat scale = sin(off) *" -" bulgeHeight;\r\n\t\tvec3 offset = normal * scale;\r\n\r\n\t\tdeformed.xyz " -"+= offset;\r\n\t}\r\n\r\n\treturn deformed;\r\n}\r\n\r\n\r\nvoid main()\r\n" -"{\r\n\tvec4 position = mix(attr_Position, attr_Position2, u_VertexLerp);\r" -"\n\tvec3 normal = normalize(mix(attr_Normal, attr_Normal2, u_VertexLerp));" -"\r\n\r\n\tposition = DeformPosition(position, normal, attr_TexCoord0.st);\r" -"\n\r\n\tgl_Position = u_ModelViewProjectionMatrix * position;\r\n\t\r\n\tve" -"c2 tex = vec2(0);\r\n\t\r\n\tvec3 dist = u_DlightInfo.xyz - position.xyz;\t" -"\r\n\tfloat dlightmod = 0;\r\n\r\n\tif (dot(dist, normal) > 0)\r\n\t{\r\n\t" -"\tfloat diffz = abs(dist.z);\r\n\t\tfloat radius = 1.0 / u_DlightInfo.a;\r" -"\n \r\n\t\tif (diffz <= radius)\r\n\t\t{\r\n\t\t\ttex = vec2(0.5) + dist" -".xy * u_DlightInfo.a;\r\n\r\n\t\t\tif (diffz < radius * 0.5)\r\n\t\t\t{\r\n" -"\t\t\t\tdlightmod = 1.0;\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\tdli" -"ghtmod = 2.0 * (radius - diffz) * u_DlightInfo.a;\r\n\t\t\t}\r\n\t\t}\r\n\t" -"}\r\n\r\n\tvar_Tex1 = tex;\r\n\tvar_Color.rgb = u_Color.rgb * dlightmod;\r" -"\n\tvar_Color.a = u_Color.a;\r\n}\r\n"; +"e vec3 attr_Normal;\r\n\r\nuniform vec4 u_DlightInfo;\r\n\r\nuniform int " +" u_DeformGen;\r\nuniform float u_DeformParams[5];\r\n\r\nuniform float " +"u_Time;\r\nuniform vec4 u_Color;\r\nuniform mat4 u_ModelViewProjectionM" +"atrix;\r\n\r\nvarying vec2 var_Tex1;\r\nvarying vec4 var_Color;\r\n\r\n" +"float triangle(float x)\r\n{\r\n\treturn max(1.0 - abs(x), 0);\r\n}\r\n\r\n" +"float sawtooth(float x)\r\n{\r\n\treturn x - floor(x);\r\n}\r\n\r\nvec4 Def" +"ormPosition(const vec4 pos, const vec3 normal, const vec2 st)\r\n{\r\n\tif " +"(u_DeformGen == 0)\r\n\t{\r\n\t\treturn pos;\r\n\t}\r\n\r\n\tfloat base = " +" u_DeformParams[0];\r\n\tfloat amplitude = u_DeformParams[1];\r\n\tfloat" +" phase = u_DeformParams[2];\r\n\tfloat frequency = u_DeformParams[3];\r" +"\n\tfloat spread = u_DeformParams[4];\r\n\t\t\r\n\tif (u_DeformGen <= DG" +"EN_WAVE_INVERSE_SAWTOOTH)\r\n\t{\r\n\t\tphase += (pos.x + pos.y + pos.z) * " +"spread;\r\n\t}\r\n\telse if (u_DeformGen == DGEN_BULGE)\r\n\t{\r\n\t\tphase" +" *= M_PI * 0.25 * st.x;\r\n\t}\r\n\r\n\tfloat value = phase + (u_Time * fre" +"quency);\r\n\tfloat func;\r\n\r\n\tif (u_DeformGen == DGEN_WAVE_SIN)\r\n\t{" +"\r\n\t\tfunc = sin(value * 2.0 * M_PI);\r\n\t}\r\n\telse if (u_DeformGen ==" +" DGEN_WAVE_SQUARE)\r\n\t{\r\n\t\tfunc = sign(sin(value * 2.0 * M_PI));\r\n" +"\t}\r\n\telse if (u_DeformGen == DGEN_WAVE_TRIANGLE)\r\n\t{\r\n\t\tfunc = t" +"riangle(value);\r\n\t}\r\n\telse if (u_DeformGen == DGEN_WAVE_SAWTOOTH)\r\n" +"\t{\r\n\t\tfunc = sawtooth(value);\r\n\t}\r\n\telse if (u_DeformGen == DGEN" +"_WAVE_INVERSE_SAWTOOTH)\r\n\t{\r\n\t\tfunc = (1.0 - sawtooth(value));\r\n\t" +"}\r\n\telse if (u_DeformGen == DGEN_BULGE)\r\n\t{\r\n\t\tfunc = sin(value);" +"\r\n\t}\r\n\r\n\tvec4 deformed = pos;\r\n\tdeformed.xyz += normal * (base +" +" func * amplitude);\r\n\r\n\treturn deformed;\r\n\r\n}\r\n\r\nvoid main()\r" +"\n{\r\n\tvec4 position = attr_Position;\r\n\tvec3 normal = attr_Normal;\r\n" +"\r\n\tposition = DeformPosition(position, normal, attr_TexCoord0.st);\r\n\r" +"\n\tgl_Position = u_ModelViewProjectionMatrix * position;\r\n\t\t\r\n\tvec3" +" dist = u_DlightInfo.xyz - position.xyz;\t\r\n\r\n\tfloat diffz = abs(dist." +"z);\r\n\tfloat radius = 1.0 / u_DlightInfo.a;\r\n\r\n\tvec2 tex = vec2(0.5)" +" + dist.xy * u_DlightInfo.a;\r\n\tfloat dlightmod = max(sign(dot(dist, norm" +"al)), 0.0);\r\n\tdlightmod *= clamp(2.0 * (radius - diffz) * u_DlightInfo.a" +", 0.0, 1.0);\r\n\r\n\tvar_Tex1 = tex;\r\n\tvar_Color = u_Color;\r\n\tvar_Co" +"lor.rgb *= dlightmod;\r\n}\r\n"; static const char *fallbackDlightallShader_fp = "uniform sampler2D u_DiffuseMap;\r\n\r\nvarying vec2 var_Tex1;\r\nvaryi" @@ -291,106 +245,212 @@ static const char *fallbackLightallShader_vp = ";\r\n\r\nvarying vec3 var_Position;\r\nvarying vec3 var_Normal;\r\n\r\n" "#if defined(USE_NORMALMAP)\r\nvarying vec3 var_Tangent;\r\nvarying vec3 " " var_Bitangent;\r\n#endif\r\n\r\nvec2 DoTexMatrix(vec2 st, vec3 position, m" -"at4 texMatrix)\r\n{\r\n\tvec4 st2 = vec4(st, 1, 0);\r\n\t\r\n\tst2.st = (te" -"xMatrix * st2).st;\r\n\r\n\tvec2 texOffset;\r\n\tvec3 offsetPos = position." -"xyz / 1024.0;\r\n\toffsetPos.x += offsetPos.z;\r\n\r\n\ttexOffset = sin((of" -"fsetPos.xy + vec2(texMatrix[3][1])) * 2.0 * M_PI);\r\n\t\r\n\treturn st2.st" -" + texOffset * texMatrix[3][0];\r\n}\r\n\r\nvoid main()\r\n{\r\n#if defined" -"(USE_VERTEX_ANIMATION)\r\n\tvec4 position = mix(attr_Position, attr_Positi" -"on2, u_VertexLerp);\r\n\tvec3 normal = normalize(mix(attr_Normal, att" -"r_Normal2, u_VertexLerp));\r\n #if defined(USE_NORMALMAP)\r\n\tvec3 tan" -"gent = normalize(mix(attr_Tangent, attr_Tangent2, u_VertexLerp));\r\n" -"\tvec3 bitangent = normalize(mix(attr_Bitangent, attr_Bitangent2, u_VertexL" -"erp));\r\n #endif\r\n#else\r\n\tvec4 position = attr_Position;\r\n\tvec3 " -"normal = attr_Normal;\r\n #if defined(USE_NORMALMAP)\r\n vec3 ta" -"ngent = attr_Tangent;\r\n vec3 bitangent = attr_Bitangent;\r\n #e" -"ndif\r\n#endif\r\n\r\n\tgl_Position = u_ModelViewProjectionMatrix * positio" -"n;\r\n\r\n#if defined(TCGEN_ENVIRONMENT)\r\n\t{\r\n\t\tvec2 tex;\r\n\t\tvec" -"3 viewer = normalize(u_ViewOrigin - position.xyz);\r\n\r\n\t\tfloat d = dot" -"(normal, viewer);\r\n\r\n\t\tvec3 reflected = normal * 2.0 * d - viewer;\r" -"\n\r\n\t\ttex.s = 0.5 + reflected.y * 0.5;\r\n\t\ttex.t = 0.5 - reflected.z" -" * 0.5;\r\n\t\t\r\n\t\tvar_DiffuseTex = DoTexMatrix(tex, position.xyz, u_Di" -"ffuseTexMatrix);\r\n\t}\r\n#else\r\n\tvar_DiffuseTex = DoTexMatrix(attr_Tex" -"Coord0.st, position.xyz, u_DiffuseTexMatrix);\r\n#endif\r\n\r\n\r\n\tvar_Li" -"ghtTex = attr_TexCoord1.st;\r\n\r\n#if defined(USE_MODELMATRIX)\r\n\tvar_Po" -"sition = (u_ModelMatrix * position).xyz;\r\n\tvar_Normal = (u_ModelMatr" -"ix * vec4(normal, 0.0)).xyz;\r\n\r\n #if defined(USE_NORMALMAP)\r\n\tvar_T" -"angent = (u_ModelMatrix * vec4(tangent, 0.0)).xyz;\r\n\tvar_Bitangent = (" -"u_ModelMatrix * vec4(bitangent, 0.0)).xyz;\r\n #endif\r\n#else\r\n\tvar_Po" -"sition = position.xyz;\r\n\tvar_Normal = normal;\r\n\r\n #if defined(U" -"SE_NORMALMAP)\r\n\tvar_Tangent = tangent;\r\n\tvar_Bitangent = bitangent;" -"\r\n #endif\r\n#endif\r\n}\r\n"; +"at4 texMatrix)\r\n{\r\n\tvec2 st2 = (texMatrix * vec4(st, 1, 0)).st;\r\n\r" +"\n\tvec3 offsetPos = position.xyz / 1024.0;\r\n\toffsetPos.x += offsetPos.z" +";\r\n\r\n\tvec2 texOffset = sin((offsetPos.xy + vec2(texMatrix[3][1])) * 2." +"0 * M_PI);\r\n\t\r\n\treturn st2 + texOffset * texMatrix[3][0];\r\n}\r\n\r" +"\nvoid main()\r\n{\r\n#if defined(USE_VERTEX_ANIMATION)\r\n\tvec4 position " +" = mix(attr_Position, attr_Position2, u_VertexLerp);\r\n\tvec3 normal = " +"normalize(mix(attr_Normal, attr_Normal2, u_VertexLerp));\r\n #if def" +"ined(USE_NORMALMAP)\r\n\tvec3 tangent = normalize(mix(attr_Tangent, att" +"r_Tangent2, u_VertexLerp));\r\n\tvec3 bitangent = normalize(mix(attr_Bita" +"ngent, attr_Bitangent2, u_VertexLerp));\r\n #endif\r\n#else\r\n\tvec4 posi" +"tion = attr_Position;\r\n\tvec3 normal = attr_Normal;\r\n #if defined(" +"USE_NORMALMAP)\r\n vec3 tangent = attr_Tangent;\r\n vec3 bi" +"tangent = attr_Bitangent;\r\n #endif\r\n#endif\r\n\r\n\tgl_Position = u_Mo" +"delViewProjectionMatrix * position;\r\n\r\n#if defined(TCGEN_ENVIRONMENT)\r" +"\n\tvec2 tex;\r\n\tvec3 viewer = normalize(u_ViewOrigin - position.xyz);\r" +"\n\tvec3 reflected = normal * 2.0 * dot(normal, viewer) - viewer;\r\n\r\n\t" +"tex.s = 0.5 + reflected.y * 0.5;\r\n\ttex.t = 0.5 - reflected.z * 0.5;\r\n#" +"else\r\n\tvec2 tex = attr_TexCoord0.st;\r\n#endif\r\n\r\n\tvar_DiffuseTex =" +" DoTexMatrix(tex, position.xyz, u_DiffuseTexMatrix);\r\n\r\n\tvar_LightTex " +"= attr_TexCoord1.st;\r\n\r\n#if defined(USE_MODELMATRIX)\r\n\tvar_Position " +" = (u_ModelMatrix * position).xyz;\r\n\tvar_Normal = (u_ModelMatrix * ve" +"c4(normal, 0.0)).xyz;\r\n\r\n #if defined(USE_NORMALMAP)\r\n\tvar_Tangent " +" = (u_ModelMatrix * vec4(tangent, 0.0)).xyz;\r\n\tvar_Bitangent = (u_Model" +"Matrix * vec4(bitangent, 0.0)).xyz;\r\n #endif\r\n#else\r\n\tvar_Position " +" = position.xyz;\r\n\tvar_Normal = normal;\r\n\r\n #if defined(USE_NORM" +"ALMAP)\r\n\tvar_Tangent = tangent;\r\n\tvar_Bitangent = bitangent;\r\n #" +"endif\r\n#endif\r\n}\r\n"; static const char *fallbackLightallShader_fp = "uniform sampler2D u_DiffuseMap;\r\n\r\n#if defined(USE_LIGHTMAP)\r\nuniform" " sampler2D u_LightMap;\r\n#endif\r\n\r\n#if defined(USE_NORMALMAP)\r\nunifo" "rm sampler2D u_NormalMap;\r\n#endif\r\n\r\n#if defined(USE_DELUXEMAP)\r\nun" "iform sampler2D u_DeluxeMap;\r\n#endif\r\n\r\n#if defined(USE_SPECULARMAP)" -"\r\nuniform sampler2D u_SpecularMap;\r\n#endif\r\n\r\nuniform vec3 u_V" -"iewOrigin;\r\nuniform vec4 u_Color;\r\n\r\n#if !defined(USE_LIGHTMAP)" -"\r\nuniform vec3 u_DirectedLight;\r\nuniform vec3 u_AmbientLight;" -"\r\nuniform vec4 u_LightOrigin;\r\nuniform float u_LightScaleSqr;" -"\r\n#endif\r\n\r\nvarying vec2 var_DiffuseTex;\r\nvarying vec2 va" -"r_LightTex;\r\n\r\nvarying vec3 var_Position;\r\n\r\n#if defined(USE_N" -"ORMALMAP)\r\nvarying vec3 var_Tangent;\r\nvarying vec3 var_Bitang" -"ent;\r\n#endif\r\n\r\nvarying vec3 var_Normal;\r\n\r\n\r\nfloat RayInt" -"ersectDisplaceMap(vec2 dp, vec2 ds, sampler2D normalMap)\r\n{\r\n\tconst in" -"t linearSearchSteps = 5;\r\n\tconst int binarySearchSteps = 5;\r\n\r\n\tflo" -"at depthStep = 1.0 / float(linearSearchSteps);\r\n\r\n\t// current size of " -"search window\r\n\tfloat size = depthStep;\r\n\r\n\t// current depth positi" -"on\r\n\tfloat depth = 0.0;\r\n\r\n\t// best match found (starts with last p" -"osition 1.0)\r\n\tfloat bestDepth = 1.0;\r\n\r\n\t// search front to back f" -"or first point inside object\r\n\tfor(int i = 0; i < linearSearchSteps - 1;" -" ++i)\r\n\t{\r\n\t\tdepth += size;\r\n\t\t\r\n\t\tvec4 t = texture2D(normal" -"Map, dp + ds * depth);\r\n\r\n\t\tif(bestDepth > 0.996)\t\t// if no depth f" -"ound yet\r\n\t\t\tif(depth >= t.w)\r\n\t\t\t\tbestDepth = depth;\t// store " -"best depth\r\n\t}\r\n\r\n\tdepth = bestDepth;\r\n\t\r\n\t// recurse around " -"first point (depth) for closest match\r\n\tfor(int i = 0; i < binarySearchS" -"teps; ++i)\r\n\t{\r\n\t\tsize *= 0.5;\r\n\r\n\t\tvec4 t = texture2D(normalM" -"ap, dp + ds * depth);\r\n\t\t\r\n\t\tif(depth >= t.w)\r\n\t\t{\r\n\t\t\tbes" -"tDepth = depth;\r\n\t\t\tdepth -= 2.0 * size;\r\n\t\t}\r\n\r\n\t\tdepth += " -"size;\r\n\t}\r\n\r\n\treturn bestDepth;\r\n}\r\n\r\nvoid main()\r\n{\r\n#if" -" defined(USE_LIGHTMAP)\r\n\tvec4 light = texture2D(u_LightMap, var_LightTex" -");\r\n #if defined(USE_DELUXEMAP)\r\n\tvec4 deluxe = texture2D(u_DeluxeMap" -", var_LightTex);\r\n\tvec3 worldLight = normalize(2.0 * deluxe.xyz - vec3(1" -".0));\r\n #else\r\n\tvec3 worldLight = normalize(var_Normal);\r\n #endif" -"\r\n#else\r\n\tvec3 worldLight = u_LightOrigin.xyz - (var_Position * u_Ligh" -"tOrigin.w);\r\n #if defined(USE_INVSQRLIGHT)\r\n\tfloat intensity = 1.0f /" -" dot(worldLight, worldLight);\r\n #else\r\n\tfloat intensity = clamp((1.0 " -"- dot(worldLight, worldLight) * u_LightScaleSqr) * 1.07, 0.0, 1.0);\r\n #e" -"ndif\t\r\n\tworldLight = normalize(worldLight);\r\n\tvec3 directedLight = u" -"_DirectedLight * intensity;\r\n\tvec3 ambientLight = u_AmbientLight; \r\n" -"#endif\r\n\r\n\tvec3 SampleToView = normalize(u_ViewOrigin - var_Position);" -"\r\n\tvec2 texOffset = vec2(0.0);\r\n\r\n#if defined(USE_NORMALMAP)\r\n\tma" -"t3 tangentToWorld = mat3(var_Tangent.xyz, var_Bitangent.xyz, var_Normal.xyz" -");\r\n\r\n #if defined(USE_PARALLAXMAP)\r\n\tvec3 offsetDir = normalize(Sa" -"mpleToView * tangentToWorld);\r\n #if 0\r\n\tfloat dist = 0.02 * texture" -"2D(u_NormalMap, var_DiffuseTex).w - (0.02 / 2.0);\r\n #else\r\n\toffsetD" -"ir.xy *= 0.02 / offsetDir.z;\r\n\tfloat dist = RayIntersectDisplaceMap(var_" -"NormalTex, offsetDir.xy, u_NormalMap);\r\n #endif\t\r\n\ttexOffset = off" -"setDir.xy * dist;\r\n #endif\r\n \r\n\tvec3 normal = texture2D(u_NormalMa" -"p, var_DiffuseTex + texOffset).xyz;\r\n\tvec3 worldNormal = normalize(tange" -"ntToWorld * (2.0 * normal.xyz - vec3(1.0)));\r\n#else\r\n\tvec3 worldNormal" -" = normalize(var_Normal);\r\n#endif\r\n\r\n\tvec4 diffuse = texture2D(u_Dif" -"fuseMap, var_DiffuseTex + texOffset) * u_Color;\r\n\r\n#if defined(USE_LIGH" -"TMAP)\r\n\tdiffuse.rgb *= light.rgb;\r\n #if defined(USE_DELUXEMAP)\r\n " -" #if defined(USE_NORMALMAP)\r\n #if defined(r_normalAmbient)\r\n " -" diffuse.rgb *= mix(max(dot(worldNormal, worldLight), 0.0), normal.z, r_no" -"rmalAmbient);\r\n #else\r\n diffuse.rgb *= max(dot(worldNormal," -" worldLight), 0.0);\r\n #endif\r\n #endif\r\n #else\r\n #if def" -"ined(USE_NORMALMAP)\r\n #if defined(r_normalAmbient)\r\n diffus" -"e.rgb *= mix(1.0, normal.z, r_normalAmbient);\r\n #endif\r\n #endif" -"\r\n #endif\r\n#else\r\n #if defined(USE_NORMALMAP) && defined(r_normalAm" -"bient)\r\n ambientLight *= normal.z;\r\n #endif\r\n\tdiffuse.rgb *=" -" min(directedLight * max(dot(worldNormal, worldLight), 0.0) + ambientLight," -" 1.0);\r\n#endif\r\n\r\n\tgl_FragColor = diffuse;\r\n\r\n#if defined(USE_SP" -"ECULARMAP)\r\n\tvec4 specular = texture2D(u_SpecularMap, var_DiffuseTex + t" -"exOffset);\r\n\tvec3 halfAngle = normalize(worldLight + SampleToView);\r\n" -"\r\n #if defined(USE_LIGHTMAP)\r\n\tspecular.rgb *= light.rgb;\r\n #else" -"\r\n\tspecular.rgb *= directedLight;\r\n #endif\r\n\r\n\tspecular.rgb *= p" -"ow(max(dot(worldNormal, halfAngle), 0.0), 255 * specular.a);\r\n\r\n\tgl_Fr" -"agColor.rgb += specular.rgb;\r\n#endif\r\n}\r\n"; +"\r\nuniform sampler2D u_SpecularMap;\r\n#endif\r\n\r\n#if defined(USE_SHADO" +"WMAP)\r\nuniform samplerCube u_ShadowMap;\r\n#endif\r\n\r\nuniform vec3 " +" u_ViewOrigin;\r\nuniform vec4 u_Color;\r\n\r\n#if defined(USE_LIGHT_" +"VECTOR)\r\nuniform vec3 u_DirectedLight;\r\nuniform vec3 u_Ambien" +"tLight;\r\nuniform vec4 u_LightOrigin;\r\nuniform float u_LightRad" +"ius;\r\n#endif\r\n\r\n#if defined(USE_SPECULARMAP)\r\nuniform float u_S" +"pecularReflectance;\r\n#endif\r\n\r\nvarying vec2 var_DiffuseTex;\r\nv" +"arying vec2 var_LightTex;\r\n\r\nvarying vec3 var_Position;\r\n\r" +"\n#if defined(USE_NORMALMAP)\r\nvarying vec3 var_Tangent;\r\nvarying v" +"ec3 var_Bitangent;\r\n#endif\r\n\r\nvarying vec3 var_Normal;\r\n" +"\r\n\r\nfloat RayIntersectDisplaceMap(vec2 dp, vec2 ds, sampler2D normalMap" +")\r\n{\r\n\tconst int linearSearchSteps = 5;\r\n\tconst int binarySearchSte" +"ps = 5;\r\n\r\n\tfloat depthStep = 1.0 / float(linearSearchSteps);\r\n\r\n" +"\t// current size of search window\r\n\tfloat size = depthStep;\r\n\r\n\t//" +" current depth position\r\n\tfloat depth = 0.0;\r\n\r\n\t// best match foun" +"d (starts with last position 1.0)\r\n\tfloat bestDepth = 1.0;\r\n\r\n\t// s" +"earch front to back for first point inside object\r\n\tfor(int i = 0; i < l" +"inearSearchSteps - 1; ++i)\r\n\t{\r\n\t\tdepth += size;\r\n\t\t\r\n\t\tvec4" +" t = texture2D(normalMap, dp + ds * depth);\r\n\r\n\t\tif(bestDepth > 0.996" +")\t\t// if no depth found yet\r\n\t\t\tif(depth >= t.w)\r\n\t\t\t\tbestDept" +"h = depth;\t// store best depth\r\n\t}\r\n\r\n\tdepth = bestDepth;\r\n\t\r" +"\n\t// recurse around first point (depth) for closest match\r\n\tfor(int i " +"= 0; i < binarySearchSteps; ++i)\r\n\t{\r\n\t\tsize *= 0.5;\r\n\r\n\t\tvec4" +" t = texture2D(normalMap, dp + ds * depth);\r\n\t\t\r\n\t\tif(depth >= t.w)" +"\r\n\t\t{\r\n\t\t\tbestDepth = depth;\r\n\t\t\tdepth -= 2.0 * size;\r\n\t\t" +"}\r\n\r\n\t\tdepth += size;\r\n\t}\r\n\r\n\treturn bestDepth;\r\n}\r\n\r\nv" +"oid main()\r\n{\r\n#if defined(USE_LIGHTMAP)\r\n\tvec3 directedLight = text" +"ure2D(u_LightMap, var_LightTex).rgb;\r\n #if defined(USE_DELUXEMAP)\r\n\tv" +"ec3 worldLight = 2.0 * texture2D(u_DeluxeMap, var_LightTex).xyz - vec3(1.0)" +";\r\n #endif\r\n#endif\r\n\r\n#if defined(USE_LIGHT_VECTOR)\r\n\tvec3 worl" +"dLight = u_LightOrigin.xyz - (var_Position * u_LightOrigin.w);\t\r\n #if d" +"efined(USE_INVSQRLIGHT)\r\n\tfloat intensity = 1.0 / dot(worldLight, worldL" +"ight);\r\n #else\r\n\tfloat intensity = clamp((1.0 - dot(worldLight, world" +"Light) / (u_LightRadius * u_LightRadius)) * 1.07, 0.0, 1.0);\r\n #endif\r" +"\n #if defined(USE_SHADOWMAP)\r\n \tvec3 dist3 = textureCube(u_ShadowMap," +" worldLight).rgb;\r\n\tfloat dist = dot(dist3, vec3(1.0 / (256.0 * 256.0), " +"1.0 / 256.0, 1.0)) * u_LightRadius;\r\n\r\n\tintensity *= max(sign(dist - l" +"ength(worldLight)), 0.0);\r\n #endif\r\n\tvec3 directedLight = u_DirectedL" +"ight * intensity;\r\n\tvec3 ambientLight = u_AmbientLight;\r\n#endif\r\n\r" +"\n#if !(defined(USE_LIGHTMAP) && defined(USE_DELUXEMAP)) && !defined(USE_LI" +"GHT_VECTOR)\r\n\tvec3 worldLight = var_Normal;\r\n#endif\r\n\r\n\tvec3 Samp" +"leToView = normalize(u_ViewOrigin - var_Position);\r\n\tvec2 texOffset = ve" +"c2(0.0);\r\n\r\n#if defined(USE_NORMALMAP)\r\n\tmat3 tangentToWorld = mat3(" +"var_Tangent.xyz, var_Bitangent.xyz, var_Normal.xyz);\r\n\r\n #if defined(U" +"SE_PARALLAXMAP)\r\n\tvec3 offsetDir = normalize(SampleToView * tangentToWor" +"ld);\r\n #if 0\r\n\tfloat dist = 0.02 * texture2D(u_NormalMap, var_Diffu" +"seTex).w - (0.02 / 2.0);\r\n #else\r\n\toffsetDir.xy *= 0.05 / offsetDir" +".z;\r\n\tfloat dist = RayIntersectDisplaceMap(var_DiffuseTex, offsetDir.xy," +" u_NormalMap);\r\n #endif\t\r\n\ttexOffset = offsetDir.xy * dist;\r\n #" +"endif\r\n \r\n\tvec3 normal = texture2D(u_NormalMap, var_DiffuseTex + texO" +"ffset).xyz;\r\n\tvec3 worldNormal = tangentToWorld * (2.0 * normal.xyz - ve" +"c3(1.0));\r\n#else\r\n\tvec3 worldNormal = var_Normal;\r\n#endif\r\n\r\n\tv" +"ec4 diffuse = texture2D(u_DiffuseMap, var_DiffuseTex + texOffset) * u_Color" +";\r\n\t\r\n\tworldNormal = normalize(worldNormal);\r\n\tworldLight = normal" +"ize(worldLight);\r\n\r\n#if defined(USE_LIGHTMAP) && defined(USE_DELUXEMAP)" +"\r\n\tdirectedLight /= max(dot(normalize(var_Normal), worldLight), 0.004);" +"\r\n#endif\r\n\r\n#if (defined(USE_LIGHTMAP) && defined(USE_DELUXEMAP)) || " +"defined(USE_LIGHT_VECTOR)\r\n\tfloat NL = max(dot(worldNormal, worldLight)" +", 0.0);\r\n#else\r\n\tfloat NL = 1.0;\r\n#endif\r\n\t\t\r\n#if defined(US" +"E_SPECULARMAP)\r\n\tvec4 specular = texture2D(u_SpecularMap, var_DiffuseTex" +" + texOffset);\r\n\tfloat shininess = specular.a * 255 + 1.0;\r\n\tfloat fz" +"ero = u_SpecularReflectance;\r\n\r\n\tvec3 halfAngle = normalize(worldLight" +" + SampleToView);\r\n\r\n\tfloat EH = max(dot(SampleToView, halfAngle), " +"0.0);\r\n\tfloat NE = max(dot(worldNormal, SampleToView), 0.0);\r\n\tfloat" +" NH = max(dot(worldNormal, halfAngle), 0.0);\r\n\r\n\tfloat factor = 0." +"1248582 * shininess + 0.2691817;\r\n\tfloat fspec = fzero + (1.0 - fzero) *" +" pow(1.0 - EH, 5);\r\n\r\n #if defined(USE_LIGHTMAP)\r\n\tdiffuse.rgb *= m" +"in(NL * (1.0 - fzero), 1.0) * directedLight;\r\n #endif\r\n #if defined(U" +"SE_LIGHT_VECTOR)\r\n\tdiffuse.rgb *= min(directedLight * NL * (1.0 - fzero)" +" + ambientLight, 1.0);\r\n #endif\r\n\tspecular.rgb *= min(factor * fspec " +"* pow(NH, shininess) / max(NL, NE), 1.0);\r\n #if defined(USE_LIGHTMAP) ||" +" defined(USE_LIGHT_VECTOR)\r\n\tspecular.rgb *= min(directedLight, 1.0);\r" +"\n #endif\r\n#else\r\n #if defined(USE_LIGHTMAP)\r\n #if defined(USE_D" +"ELUXEMAP)\r\n\tdiffuse.rgb *= directedLight * NL;\r\n #else\r\n\tdiffuse" +".rgb *= directedLight;\r\n #endif\r\n #endif\r\n #if defined(USE_LIGHT" +"_VECTOR)\r\n\tdiffuse.rgb *= min(directedLight * NL + ambientLight, 1.0);\r" +"\n #endif\r\n#endif\r\n\r\n\tgl_FragColor = diffuse;\r\n\r\n#if defined(US" +"E_SPECULARMAP)\r\n\tgl_FragColor.rgb += specular.rgb;\r\n#endif\r\n}\r\n"; +static const char *fallbackShadowfillShader_vp = +"attribute vec4 attr_Position;\r\nattribute vec3 attr_Normal;\r\nattribute" +" vec4 attr_TexCoord0;\r\n\r\n//#if defined(USE_VERTEX_ANIMATION)\r\nattrib" +"ute vec4 attr_Position2;\r\nattribute vec3 attr_Normal2;\r\n//#endif\r\n" +"\r\n//#if defined(USE_DEFORM_VERTEXES)\r\nuniform int u_DeformGen;\r\nu" +"niform float u_DeformParams[5];\r\n//#endif\r\n\r\nuniform float u_Tim" +"e;\r\nuniform mat4 u_ModelViewProjectionMatrix;\r\n\r\nuniform mat4 u_" +"ModelMatrix;\r\n\r\n//#if defined(USE_VERTEX_ANIMATION)\r\nuniform float " +"u_VertexLerp;\r\n//#endif\r\n\r\nvarying vec3 var_Position;\r\n\r\nfloat" +" triangle(float x)\r\n{\r\n\treturn max(1.0 - abs(x), 0);\r\n}\r\n\r\nfloat" +" sawtooth(float x)\r\n{\r\n\treturn x - floor(x);\r\n}\r\n\r\nvec4 DeformPo" +"sition(const vec4 pos, const vec3 normal, const vec2 st)\r\n{\r\n\tif (u_De" +"formGen == 0)\r\n\t{\r\n\t\treturn pos;\r\n\t}\r\n\r\n\tfloat base = u" +"_DeformParams[0];\r\n\tfloat amplitude = u_DeformParams[1];\r\n\tfloat phas" +"e = u_DeformParams[2];\r\n\tfloat frequency = u_DeformParams[3];\r\n\tf" +"loat spread = u_DeformParams[4];\r\n\t\t\r\n\tif (u_DeformGen <= DGEN_WA" +"VE_INVERSE_SAWTOOTH)\r\n\t{\r\n\t\tphase += (pos.x + pos.y + pos.z) * sprea" +"d;\r\n\t}\r\n\telse if (u_DeformGen == DGEN_BULGE)\r\n\t{\r\n\t\tphase *= M" +"_PI * 0.25 * st.x;\r\n\t}\r\n\r\n\tfloat value = phase + (u_Time * frequenc" +"y);\r\n\tfloat func;\r\n\r\n\tif (u_DeformGen == DGEN_WAVE_SIN)\r\n\t{\r\n" +"\t\tfunc = sin(value * 2.0 * M_PI);\r\n\t}\r\n\telse if (u_DeformGen == DGE" +"N_WAVE_SQUARE)\r\n\t{\r\n\t\tfunc = sign(sin(value * 2.0 * M_PI));\r\n\t}\r" +"\n\telse if (u_DeformGen == DGEN_WAVE_TRIANGLE)\r\n\t{\r\n\t\tfunc = triang" +"le(value);\r\n\t}\r\n\telse if (u_DeformGen == DGEN_WAVE_SAWTOOTH)\r\n\t{\r" +"\n\t\tfunc = sawtooth(value);\r\n\t}\r\n\telse if (u_DeformGen == DGEN_WAVE" +"_INVERSE_SAWTOOTH)\r\n\t{\r\n\t\tfunc = (1.0 - sawtooth(value));\r\n\t}\r\n" +"\telse if (u_DeformGen == DGEN_BULGE)\r\n\t{\r\n\t\tfunc = sin(value);\r\n" +"\t}\r\n\r\n\tvec4 deformed = pos;\r\n\tdeformed.xyz += normal * (base + fun" +"c * amplitude);\r\n\r\n\treturn deformed;\r\n\r\n}\r\n\r\n\r\nvoid main()\r" +"\n{\r\n\tvec4 position = mix(attr_Position, attr_Position2, u_VertexLerp);" +"\r\n\tvec3 normal = normalize(mix(attr_Normal, attr_Normal2, u_VertexLerp))" +";\r\n\r\n\tposition = DeformPosition(position, normal, attr_TexCoord0.st);" +"\r\n\r\n\tgl_Position = u_ModelViewProjectionMatrix * position;\r\n\t\r\n\t" +"var_Position = (u_ModelMatrix * position).xyz;\r\n}\r\n"; + +static const char *fallbackShadowfillShader_fp = +"uniform vec4 u_LightOrigin;\r\nuniform float u_LightRadius;\r\n\r\nvarying" +" vec3 var_Position;\r\n\r\nvoid main()\r\n{\r\n\tfloat depth = length(u_Li" +"ghtOrigin.xyz - var_Position) / u_LightRadius;\r\n#if 0\r\n\t// 32 bit prec" +"ision\r\n\tconst vec4 bitSh = vec4( 256 * 256 * 256, 256 * 256, 2" +"56, 1);\r\n\tconst vec4 bitMsk = vec4( 0, 1.0 / 256." +"0, 1.0 / 256.0, 1.0 / 256.0);\r\n\t\r\n\tvec4 comp;\r\n\tcomp = depth * bit" +"Sh;\r\n\tcomp.xyz = fract(comp.xyz);\r\n\tcomp -= comp.xxyz * bitMsk;\r\n\t" +"gl_FragColor = comp;\r\n#endif\r\n\r\n#if 1\r\n\t// 24 bit precision\r\n\tc" +"onst vec3 bitSh = vec3( 256 * 256, 256, 1);\r\n\tconst ve" +"c3 bitMsk = vec3( 0, 1.0 / 256.0, 1.0 / 256.0);\r\n\t\r\n\tvec3 comp" +";\r\n\tcomp = depth * bitSh;\r\n\tcomp.xy = fract(comp.xy);\r\n\tcomp -= co" +"mp.xxy * bitMsk;\r\n\tgl_FragColor = vec4(comp, 1.0);\r\n#endif\r\n\r\n#if " +"0\r\n\t// 8 bit precision\r\n\tgl_FragColor = vec4(depth, depth, depth, 1);" +"\r\n#endif\r\n}\r\n"; + +static const char *fallbackPshadowShader_vp = +"attribute vec4 attr_Position;\r\nattribute vec3 attr_Normal;\r\n\r\nuniform" +" mat4 u_ModelViewProjectionMatrix;\r\nvarying vec3 var_Position;\r\nvar" +"ying vec3 var_Normal;\r\n\r\n\r\nvoid main()\r\n{\r\n\tvec4 position = a" +"ttr_Position;\r\n\r\n\tgl_Position = u_ModelViewProjectionMatrix * position" +";\r\n\r\n\tvar_Position = position.xyz;\r\n\tvar_Normal = attr_Normal;" +"\r\n}\r\n"; + +static const char *fallbackPshadowShader_fp = +"uniform sampler2D u_ShadowMap;\r\n\r\nuniform vec3 u_LightForward;\r\n" +"uniform vec3 u_LightUp;\r\nuniform vec3 u_LightRight;\r\nuniform " +"vec4 u_LightOrigin;\r\nuniform float u_LightRadius;\r\nvarying vec" +"3 var_Position;\r\nvarying vec3 var_Normal;\r\n\r\nfloat sampleDi" +"stMap(sampler2D texMap, vec2 uv, float scale)\r\n{\r\n\tvec3 distv = textur" +"e2D(texMap, uv).xyz;\r\n\treturn dot(distv, vec3(1.0 / (256.0 * 256.0), 1.0" +" / 256.0, 1.0)) * scale;\r\n}\r\n\r\nvoid main()\r\n{\r\n\tvec2 st;\r\n\t\r" +"\n\tvec3 lightToPos = u_LightOrigin.xyz - var_Position;\r\n\t\r\n\tst.s = d" +"ot(u_LightUp, lightToPos);\r\n\tst.t = dot(u_LightRight, lightToPos);\t\r\n" +"\t\r\n\tst = st * 0.5 + vec2(0.5);\r\n\r\n#if defined(USE_SOLID_PSHADOWS)\r" +"\n\tfloat intensity = max(sign(u_LightRadius - length(lightToPos)), 0.0);\r" +"\n#else\r\n\tfloat intensity = clamp((1.0 - dot(lightToPos, lightToPos) / (" +"u_LightRadius * u_LightRadius)) * 2.0, 0.0, 1.0);\r\n#endif\r\n\t\r\n\tfloa" +"t lightDist = length(lightToPos);\r\n\tfloat dist;\r\n\r\n#if defined(USE_D" +"ISCARD)\r\n\tif (dot(u_LightForward, lightToPos) <= 0.0)\r\n\t{\r\n\t\tdisc" +"ard;\r\n\t}\r\n\r\n\tif (dot(var_Normal, lightToPos) <= 0.0)\r\n\t{\r\n\t\t" +"discard;\r\n\t}\r\n#else\r\n\tintensity *= max(sign(dot(u_LightForward, lig" +"htToPos)), 0.0);\r\n\tintensity *= max(sign(dot(var_Normal, lightToPos)), 0" +".0);\r\n#endif\r\n\t\r\n#if defined(USE_PCF)\r\n\tfloat part;\r\n\t\r\n\tdi" +"st = sampleDistMap(u_ShadowMap, st + vec2(-1.0/256.0, -1.0/256.0), u_LightR" +"adius);\r\n\tpart = max(sign(lightDist - dist), 0.0);\r\n\r\n\tdist = samp" +"leDistMap(u_ShadowMap, st + vec2( 1.0/256.0, -1.0/256.0), u_LightRadius);\r" +"\n\tpart += max(sign(lightDist - dist), 0.0);\r\n\r\n\tdist = sampleDistMap" +"(u_ShadowMap, st + vec2(-1.0/256.0, 1.0/256.0), u_LightRadius);\r\n\tpart " +"+= max(sign(lightDist - dist), 0.0);\r\n\r\n\tdist = sampleDistMap(u_Shadow" +"Map, st + vec2( 1.0/256.0, 1.0/256.0), u_LightRadius);\r\n\tpart += max(si" +"gn(lightDist - dist), 0.0);\r\n\r\n #if defined(USE_DISCARD)\r\n\tif (part " +"<= 0.0)\r\n\t{\r\n\t\tdiscard;\r\n\t}\r\n #endif\r\n\r\n\tintensity *= part" +" * 0.25;\r\n#else\r\n\tdist = sampleDistMap(u_ShadowMap, st, u_LightRadius)" +";\r\n\r\n #if defined(USE_DISCARD)\r\n\tif (lightDist - dist <= 0.0)\r\n\t{" +"\r\n\t\tdiscard;\r\n\t}\r\n #endif\r\n\t\t\t\r\n\t//intensity *= max(sign(2" +"54.0 / 255.0 - dist / u_LightRadius), 0.0);\r\n\tintensity *= max(sign(ligh" +"tDist - dist), 0.0);\r\n#endif\r\n\t\t\r\n\tgl_FragColor.rgb = vec3(0);\r\n" +"\tgl_FragColor.a = clamp(intensity, 0.0, 0.75);\r\n}\r\n"; static void GLSL_PrintInfoLog(GLhandleARB object, qboolean developerOnly) { @@ -531,14 +591,12 @@ static int GLSL_CompileGPUShader(GLhandleARB program, GLhandleARB *prevShader, c "#define TCGEN_ENVIRONMENT_MAPPED %i\n" "#define TCGEN_FOG %i\n" "#define TCGEN_VECTOR %i\n" - "#define TCGEN_DLIGHT %i\n" "#endif\n", TCGEN_LIGHTMAP, TCGEN_TEXTURE, TCGEN_ENVIRONMENT_MAPPED, TCGEN_FOG, - TCGEN_VECTOR, - TCGEN_DLIGHT)); + TCGEN_VECTOR)); Q_strcat(bufferExtra, sizeof(bufferExtra), va("#ifndef colorGen_t\n" @@ -599,9 +657,9 @@ static int GLSL_CompileGPUShader(GLhandleARB program, GLhandleARB *prevShader, c Q_strcat(bufferExtra, sizeof(bufferExtra), va("#ifndef texenv_t\n" "#define texenv_t\n" - "#define GL_MODULATE %i\n" - "#define GL_ADD %i\n" - "#define GL_REPLACE %i\n" + "#define TEXENV_MODULATE %i\n" + "#define TEXENV_ADD %i\n" + "#define TEXENV_REPLACE %i\n" "#endif\n", GL_MODULATE, GL_ADD, @@ -983,6 +1041,9 @@ void GLSL_FinishGPUShader(shaderProgram_t *program) case GLSL_FLOAT: size += sizeof(GLfloat); break; + case GLSL_FLOAT5: + size += sizeof(vec_t) * 5; + break; case GLSL_VEC2: size += sizeof(vec_t) * 2; break; @@ -1131,6 +1192,33 @@ void GLSL_SetUniformVec4(shaderProgram_t *program, int uniformNum, const vec4_t qglUniform4fARB(uniforms[uniformNum], v[0], v[1], v[2], v[3]); } +void GLSL_SetUniformFloat5(shaderProgram_t *program, int uniformNum, const vec5_t v) +{ + GLint *uniforms = program->uniforms; + vec_t *compare = (float *)(program->uniformBuffer + program->uniformBufferOffsets[uniformNum]); + + if (uniforms[uniformNum] == -1) + { + ri.Printf( PRINT_ALL, "well shit.\n"); + return; + } + + if (program->uniformTypes[uniformNum] != GLSL_FLOAT5) + { + ri.Printf( PRINT_WARNING, "GLSL_SetUniformFloat5: wrong type for uniform %i in program %s\n", uniformNum, program->name); + return; + } + + if (VectorCompare5(v, compare)) + { + return; + } + + VectorCopy5(v, compare); + + qglUniform1fvARB(uniforms[uniformNum], 5, v); +} + void GLSL_SetUniformMatrix16(shaderProgram_t *program, int uniformNum, const matrix_t matrix) { GLint *uniforms = program->uniforms; @@ -1203,6 +1291,7 @@ void GLSL_InitGPUShaders(void) int i; char extradefines[1024]; int attribs; + int numShaders = 0; ri.Printf(PRINT_ALL, "------- GLSL_InitGPUShaders -------\n"); @@ -1229,14 +1318,13 @@ void GLSL_InitGPUShaders(void) } if (i & GENERICDEF_USE_FOG) - { Q_strcat(extradefines, 1024, "#define USE_FOG\n"); - } if (i & GENERICDEF_USE_RGBAGEN) - { Q_strcat(extradefines, 1024, "#define USE_RGBAGEN\n"); - } + + if (i & GENERICDEF_USE_LIGHTMAP) + Q_strcat(extradefines, 1024, "#define USE_LIGHTMAP\n"); if (!GLSL_InitGPUShader(&tr.genericShader[i], "generic", attribs, qtrue, extradefines, qtrue, fallbackGenericShader_vp, fallbackGenericShader_fp, GENERIC_UNIFORM_COUNT)) { @@ -1254,8 +1342,8 @@ void GLSL_InitGPUShaders(void) if (i & GENERICDEF_USE_TCGEN) { GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_TCGEN0, "u_TCGen0", GLSL_INT); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_TCGEN0VECTOR0, "u_TCGen0Vector0", GLSL_VEC4); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_TCGEN0VECTOR1, "u_TCGen0Vector1", GLSL_VEC4); + GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_TCGEN0VECTOR0, "u_TCGen0Vector0", GLSL_VEC3); + GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_TCGEN0VECTOR1, "u_TCGen0Vector1", GLSL_VEC3); } if (i & GENERICDEF_USE_FOG) @@ -1269,9 +1357,7 @@ void GLSL_InitGPUShaders(void) if (i & GENERICDEF_USE_DEFORM_VERTEXES) { GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_DEFORMGEN, "u_DeformGen", GLSL_INT); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_DEFORMWAVE, "u_DeformWave", GLSL_VEC4); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_DEFORMBULGE, "u_DeformBulge", GLSL_VEC3); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_DEFORMSPREAD, "u_DeformSpread", GLSL_FLOAT); + GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_DEFORMPARAMS, "u_DeformParams", GLSL_FLOAT5); } GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_TIME, "u_Time", GLSL_FLOAT); @@ -1299,6 +1385,8 @@ void GLSL_InitGPUShaders(void) GLSL_SetUniformInt(&tr.genericShader[i], GENERIC_UNIFORM_DIFFUSEMAP, TB_DIFFUSEMAP); GLSL_SetUniformInt(&tr.genericShader[i], GENERIC_UNIFORM_LIGHTMAP, TB_LIGHTMAP); qglUseProgramObjectARB(0); + + numShaders++; } @@ -1319,6 +1407,8 @@ void GLSL_InitGPUShaders(void) GLSL_SetUniformInt(&tr.textureColorShader, TEXTURECOLOR_UNIFORM_DIFFUSEMAP, TB_DIFFUSEMAP); qglUseProgramObjectARB(0); + numShaders++; + attribs = ATTR_POSITION | ATTR_POSITION2 | ATTR_NORMAL | ATTR_NORMAL2 | ATTR_TEXCOORD; @@ -1331,9 +1421,7 @@ void GLSL_InitGPUShaders(void) GLSL_AddUniform(&tr.fogShader, FOGPASS_UNIFORM_FOGDEPTH, "u_FogDepth", GLSL_VEC4); GLSL_AddUniform(&tr.fogShader, FOGPASS_UNIFORM_FOGEYET, "u_FogEyeT", GLSL_FLOAT); GLSL_AddUniform(&tr.fogShader, FOGPASS_UNIFORM_DEFORMGEN, "u_DeformGen", GLSL_INT); - GLSL_AddUniform(&tr.fogShader, FOGPASS_UNIFORM_DEFORMWAVE, "u_DeformWave", GLSL_VEC4); - GLSL_AddUniform(&tr.fogShader, FOGPASS_UNIFORM_DEFORMBULGE, "u_DeformBulge", GLSL_VEC3); - GLSL_AddUniform(&tr.fogShader, FOGPASS_UNIFORM_DEFORMSPREAD, "u_DeformSpread", GLSL_FLOAT); + GLSL_AddUniform(&tr.fogShader, FOGPASS_UNIFORM_DEFORMPARAMS, "u_DeformParams", GLSL_FLOAT5); GLSL_AddUniform(&tr.fogShader, FOGPASS_UNIFORM_TIME, "u_Time", GLSL_FLOAT); GLSL_AddUniform(&tr.fogShader, FOGPASS_UNIFORM_COLOR, "u_Color", GLSL_VEC4); GLSL_AddUniform(&tr.fogShader, FOGPASS_UNIFORM_MODELVIEWPROJECTIONMATRIX, "u_ModelViewProjectionMatrix", GLSL_MAT16); @@ -1341,8 +1429,10 @@ void GLSL_InitGPUShaders(void) GLSL_FinishGPUShader(&tr.fogShader); + numShaders++; - attribs = ATTR_POSITION | ATTR_POSITION2 | ATTR_NORMAL | ATTR_NORMAL2 | ATTR_TEXCOORD; + + attribs = ATTR_POSITION | ATTR_NORMAL | ATTR_TEXCOORD; if (!GLSL_InitGPUShader(&tr.dlightallShader, "dlight", attribs, qtrue, NULL, qtrue, fallbackDlightallShader_vp, fallbackDlightallShader_fp, DLIGHT_UNIFORM_COUNT)) { @@ -1351,13 +1441,10 @@ void GLSL_InitGPUShaders(void) GLSL_AddUniform(&tr.dlightallShader, DLIGHT_UNIFORM_DLIGHTINFO, "u_DlightInfo", GLSL_VEC4); GLSL_AddUniform(&tr.dlightallShader, DLIGHT_UNIFORM_DEFORMGEN, "u_DeformGen", GLSL_INT); - GLSL_AddUniform(&tr.dlightallShader, DLIGHT_UNIFORM_DEFORMWAVE, "u_DeformWave", GLSL_VEC4); - GLSL_AddUniform(&tr.dlightallShader, DLIGHT_UNIFORM_DEFORMBULGE, "u_DeformBulge", GLSL_VEC3); - GLSL_AddUniform(&tr.dlightallShader, DLIGHT_UNIFORM_DEFORMSPREAD, "u_DeformSpread", GLSL_FLOAT); + GLSL_AddUniform(&tr.dlightallShader, DLIGHT_UNIFORM_DEFORMPARAMS, "u_DeformParams", GLSL_FLOAT5); GLSL_AddUniform(&tr.dlightallShader, DLIGHT_UNIFORM_TIME, "u_Time", GLSL_FLOAT); GLSL_AddUniform(&tr.dlightallShader, DLIGHT_UNIFORM_COLOR, "u_Color", GLSL_VEC4); GLSL_AddUniform(&tr.dlightallShader, DLIGHT_UNIFORM_MODELVIEWPROJECTIONMATRIX, "u_ModelViewProjectionMatrix", GLSL_MAT16); - GLSL_AddUniform(&tr.dlightallShader, DLIGHT_UNIFORM_VERTEXLERP, "u_VertexLerp", GLSL_FLOAT); GLSL_FinishGPUShader(&tr.dlightallShader); @@ -1365,6 +1452,9 @@ void GLSL_InitGPUShaders(void) GLSL_SetUniformInt(&tr.dlightallShader, DLIGHT_UNIFORM_DIFFUSEMAP, TB_DIFFUSEMAP); qglUseProgramObjectARB(0); + numShaders++; + + for (i = 0; i < LIGHTDEF_COUNT; i++) { // skip impossible combos @@ -1377,18 +1467,35 @@ void GLSL_InitGPUShaders(void) if ((i & LIGHTDEF_USE_LIGHTMAP) && (i & LIGHTDEF_ENTITY)) continue; + if ((i & LIGHTDEF_USE_DELUXEMAP) && (i & LIGHTDEF_ENTITY)) + continue; + + if ((i & LIGHTDEF_USE_LIGHTMAP) && (i & LIGHTDEF_USE_LIGHT_VECTOR)) + continue; + + if ((i & LIGHTDEF_USE_DELUXEMAP) && (i & LIGHTDEF_USE_LIGHT_VECTOR)) + continue; + attribs = ATTR_POSITION | ATTR_TEXCOORD | ATTR_NORMAL; extradefines[0] = '\0'; if (r_normalAmbient->value > 0.003f) Q_strcat(extradefines, 1024, va("#define r_normalAmbient %f\n", r_normalAmbient->value)); + if (r_dlightShadows->integer) + Q_strcat(extradefines, 1024, "#define USE_SHADOWMAP\n"); + if (i & LIGHTDEF_USE_LIGHTMAP) { Q_strcat(extradefines, 1024, "#define USE_LIGHTMAP\n"); attribs |= ATTR_LIGHTCOORD; } + if (i & LIGHTDEF_USE_LIGHT_VECTOR) + { + Q_strcat(extradefines, 1024, "#define USE_LIGHT_VECTOR\n"); + } + if (i & LIGHTDEF_USE_NORMALMAP && r_normalMapping->integer) { Q_strcat(extradefines, 1024, "#define USE_NORMALMAP\n"); @@ -1435,11 +1542,14 @@ void GLSL_InitGPUShaders(void) GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_NORMALMAP, "u_NormalMap", GLSL_INT); GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_DELUXEMAP, "u_DeluxeMap", GLSL_INT); GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_SPECULARMAP, "u_SpecularMap", GLSL_INT); + GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_SHADOWMAP, "u_ShadowMap", GLSL_INT); GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_AMBIENTLIGHT, "u_AmbientLight", GLSL_VEC3); GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_DIRECTEDLIGHT, "u_DirectedLight", GLSL_VEC3); GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_LIGHTORIGIN, "u_LightOrigin", GLSL_VEC4); - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_LIGHTSCALESQR, "u_LightScaleSqr", GLSL_FLOAT); + GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_LIGHTRADIUS, "u_LightRadius", GLSL_FLOAT); + + GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_SPECULARREFLECTANCE, "u_SpecularReflectance", GLSL_FLOAT); GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_COLOR, "u_Color", GLSL_VEC4); GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_VERTEXLERP, "u_VertexLerp", GLSL_FLOAT); @@ -1452,12 +1562,64 @@ void GLSL_InitGPUShaders(void) GLSL_SetUniformInt(&tr.lightallShader[i], GENERIC_UNIFORM_NORMALMAP, TB_NORMALMAP); GLSL_SetUniformInt(&tr.lightallShader[i], GENERIC_UNIFORM_DELUXEMAP, TB_DELUXEMAP); GLSL_SetUniformInt(&tr.lightallShader[i], GENERIC_UNIFORM_SPECULARMAP, TB_SPECULARMAP); + GLSL_SetUniformInt(&tr.lightallShader[i], GENERIC_UNIFORM_SHADOWMAP, TB_SHADOWMAP); qglUseProgramObjectARB(0); + + numShaders++; } + + attribs = ATTR_POSITION | ATTR_POSITION2 | ATTR_NORMAL | ATTR_NORMAL2 | ATTR_TEXCOORD; + + if (!GLSL_InitGPUShader(&tr.shadowmapShader, "shadowfill", attribs, qtrue, NULL, qtrue, fallbackShadowfillShader_vp, fallbackShadowfillShader_fp, GENERIC_UNIFORM_COUNT)) + { + ri.Error(ERR_FATAL, "Could not load depth shader!\n"); + } + + GLSL_AddUniform(&tr.shadowmapShader, GENERIC_UNIFORM_DEFORMGEN, "u_DeformGen", GLSL_INT); + GLSL_AddUniform(&tr.shadowmapShader, GENERIC_UNIFORM_DEFORMPARAMS, "u_DeformParams", GLSL_FLOAT5); + GLSL_AddUniform(&tr.shadowmapShader, GENERIC_UNIFORM_TIME, "u_Time", GLSL_FLOAT); + GLSL_AddUniform(&tr.shadowmapShader, GENERIC_UNIFORM_MODELVIEWPROJECTIONMATRIX, "u_ModelViewProjectionMatrix", GLSL_MAT16); + GLSL_AddUniform(&tr.shadowmapShader, GENERIC_UNIFORM_MODELMATRIX, "u_ModelMatrix", GLSL_MAT16); + GLSL_AddUniform(&tr.shadowmapShader, GENERIC_UNIFORM_VERTEXLERP, "u_VertexLerp", GLSL_FLOAT); + + GLSL_AddUniform(&tr.shadowmapShader, GENERIC_UNIFORM_LIGHTORIGIN, "u_LightOrigin", GLSL_VEC4); + GLSL_AddUniform(&tr.shadowmapShader, GENERIC_UNIFORM_LIGHTRADIUS, "u_LightRadius", GLSL_FLOAT); + + GLSL_FinishGPUShader(&tr.shadowmapShader); + + numShaders++; + + + attribs = ATTR_POSITION | ATTR_NORMAL; + extradefines[0] = '\0'; + + Q_strcat(extradefines, 1024, "#define USE_PCF\n#define USE_DISCARD"); + + if (!GLSL_InitGPUShader(&tr.pshadowShader, "pshadow", attribs, qtrue, extradefines, qtrue, fallbackPshadowShader_vp, fallbackPshadowShader_fp, PSHADOW_UNIFORM_COUNT)) + { + ri.Error(ERR_FATAL, "Could not load pshadow shader!\n"); + } + + GLSL_AddUniform(&tr.pshadowShader, PSHADOW_UNIFORM_MODELVIEWPROJECTIONMATRIX, "u_ModelViewProjectionMatrix", GLSL_MAT16); + GLSL_AddUniform(&tr.pshadowShader, PSHADOW_UNIFORM_LIGHTFORWARD, "u_LightForward", GLSL_VEC3); + GLSL_AddUniform(&tr.pshadowShader, PSHADOW_UNIFORM_LIGHTUP, "u_LightUp", GLSL_VEC3); + GLSL_AddUniform(&tr.pshadowShader, PSHADOW_UNIFORM_LIGHTRIGHT, "u_LightRight", GLSL_VEC3); + GLSL_AddUniform(&tr.pshadowShader, PSHADOW_UNIFORM_LIGHTORIGIN, "u_LightOrigin", GLSL_VEC4); + GLSL_AddUniform(&tr.pshadowShader, PSHADOW_UNIFORM_LIGHTRADIUS, "u_LightRadius", GLSL_FLOAT); + + GLSL_FinishGPUShader(&tr.pshadowShader); + + qglUseProgramObjectARB(tr.pshadowShader.program); + GLSL_SetUniformInt(&tr.pshadowShader, PSHADOW_UNIFORM_SHADOWMAP, TB_DIFFUSEMAP); + qglUseProgramObjectARB(0); + + numShaders++; + + endTime = ri.Milliseconds(); - ri.Printf(PRINT_ALL, "GLSL shaders load time = %5.2f seconds\n", (endTime - startTime) / 1000.0); + ri.Printf(PRINT_ALL, "loaded %i GLSL shaders in %5.2f seconds\n", numShaders, (endTime - startTime) / 1000.0); } void GLSL_ShutdownGPUShaders(void) @@ -1492,6 +1654,9 @@ void GLSL_ShutdownGPUShaders(void) { GLSL_DeleteGPUShader(&tr.lightallShader[i]); } + + GLSL_DeleteGPUShader(&tr.shadowmapShader); + GLSL_DeleteGPUShader(&tr.pshadowShader); glState.currentProgram = 0; qglUseProgramObjectARB(0); @@ -1810,11 +1975,16 @@ shaderProgram_t *GLSL_GetGenericShaderProgram(int stage) shaderStage_t *pStage = tess.xstages[stage]; int shaderAttribs = 0; - if ( tess.fogNum && pStage->adjustColorsForFog) + if (tess.fogNum && pStage->adjustColorsForFog) { shaderAttribs |= GENERICDEF_USE_FOG; } + if (pStage->bundle[1].image[0] && tess.shader->multitextureEnv) + { + shaderAttribs |= GENERICDEF_USE_LIGHTMAP; + } + switch (pStage->rgbGen) { case CGEN_EXACT_VERTEX: @@ -1845,7 +2015,7 @@ shaderProgram_t *GLSL_GetGenericShaderProgram(int stage) shaderAttribs |= GENERICDEF_USE_TCGEN; } - if (!ShaderRequiresCPUDeforms(tess.shader)) + if (tess.shader->numDeforms && !ShaderRequiresCPUDeforms(tess.shader)) { shaderAttribs |= GENERICDEF_USE_DEFORM_VERTEXES; } diff --git a/reaction/code/renderer/tr_image.c b/reaction/code/renderer/tr_image.c index 27359872..50f195f7 100644 --- a/reaction/code/renderer/tr_image.c +++ b/reaction/code/renderer/tr_image.c @@ -784,7 +784,7 @@ done: if ( resampledBuffer != 0 ) ri.Hunk_FreeTempMemory( resampledBuffer ); } - + static image_t *R_AllocImage(const char* name, int width, int height, qboolean mipmap, qboolean allowPicmip, int glWrapClampMode) { image_t *image; @@ -809,7 +809,7 @@ static image_t *R_AllocImage(const char* name, int width, int height, qboolean m return image; } - + /* ================ R_CreateImage @@ -820,20 +820,21 @@ Makro - except maybe for render targets at some point in the near future... ================ */ -image_t *R_CreateImage( const char *name, const byte *pic, int width, int height, - qboolean mipmap, qboolean allowPicmip, int glWrapClampMode ) { +image_t *R_CreateImage2( const char *name, const byte *pic, int width, int height, + qboolean mipmap, qboolean allowPicmip, int glWrapClampMode, qboolean cube ) { image_t *image; qboolean isLightmap = qfalse; + long hash; if (strlen(name) >= MAX_QPATH ) { - ri.Error (ERR_DROP, "R_CreateImage: \"%s\" is too long\n", name); + ri.Error (ERR_DROP, "R_CreateImage: \"%s\" is too long", name); } if ( !strncmp( name, "*lightmap", 9 ) ) { isLightmap = qtrue; } if ( tr.numImages == MAX_DRAWIMAGES ) { - ri.Error( ERR_DROP, "R_CreateImage: MAX_DRAWIMAGES hit\n"); + ri.Error( ERR_DROP, "R_CreateImage: MAX_DRAWIMAGES hit"); } image = R_AllocImage(name, width, height, mipmap, allowPicmip, glWrapClampMode); @@ -849,18 +850,41 @@ image_t *R_CreateImage( const char *name, const byte *pic, int width, int height GL_SelectTexture( image->TMU ); } - GL_Bind(image); + if (cube) + { + GL_BindCubemap(image); + qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - Upload32( (unsigned *)pic, image->width, image->height, - image->mipmap, - allowPicmip, - isLightmap, - &image->internalFormat, - &image->uploadWidth, - &image->uploadHeight ); + qglTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic); + qglTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic); + qglTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic); + qglTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic); + qglTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic); + qglTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glWrapClampMode ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glWrapClampMode ); + image->internalFormat = GL_RGBA8; + image->uploadWidth = width; + image->uploadHeight = height; + } + else + { + GL_Bind(image); + + Upload32( (unsigned *)pic, image->width, image->height, + image->mipmap, + allowPicmip, + isLightmap, + &image->internalFormat, + &image->uploadWidth, + &image->uploadHeight ); + + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glWrapClampMode ); + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glWrapClampMode ); + } qglBindTexture( GL_TEXTURE_2D, 0 ); @@ -871,6 +895,18 @@ image_t *R_CreateImage( const char *name, const byte *pic, int width, int height return image; } +image_t *R_CreateImage( const char *name, const byte *pic, int width, int height, + qboolean mipmap, qboolean allowPicmip, int glWrapClampMode ) +{ + return R_CreateImage2( name, pic, width, height, mipmap, allowPicmip, glWrapClampMode, qfalse); +} + +image_t *R_CreateCubeImage( const char *name, const byte *pic, int width, int height, + qboolean mipmap, qboolean allowPicmip, int glWrapClampMode ) +{ + return R_CreateImage2( name, pic, width, height, mipmap, allowPicmip, glWrapClampMode, qtrue); +} + //=================================================================== typedef struct @@ -891,8 +927,7 @@ static imageExtToLoaderMap_t imageLoaders[ ] = { "bmp", R_LoadBMP } }; -static int numImageLoaders = sizeof( imageLoaders ) / - sizeof( imageLoaders[ 0 ] ); +static int numImageLoaders = ARRAY_LEN( imageLoaders ); /* ================= @@ -905,9 +940,11 @@ Loads any of the supported image types into a cannonical void R_LoadImage( const char *name, byte **pic, int *width, int *height ) { qboolean orgNameFailed = qfalse; + int orgLoader = -1; int i; char localName[ MAX_QPATH ]; const char *ext; + char *altName; *pic = NULL; *width = 0; @@ -938,6 +975,7 @@ void R_LoadImage( const char *name, byte **pic, int *width, int *height ) // Loader failed, most likely because the file isn't there; // try again without the extension orgNameFailed = qtrue; + orgLoader = i; COM_StripExtension( name, localName, MAX_QPATH ); } else @@ -952,7 +990,10 @@ void R_LoadImage( const char *name, byte **pic, int *width, int *height ) // the image formats supported for( i = 0; i < numImageLoaders; i++ ) { - char *altName = va( "%s.%s", localName, imageLoaders[ i ].ext ); + if (i == orgLoader) + continue; + + altName = va( "%s.%s", localName, imageLoaders[ i ].ext ); // Load imageLoaders[ i ].ImageLoader( altName, pic, width, height ); @@ -1208,7 +1249,24 @@ void R_CreateBuiltinImages( void ) { Com_Memset( data, 255, sizeof( data ) ); tr.whiteImage = R_CreateImage("*white", (byte *)data, 8, 8, qfalse, qfalse, GL_REPEAT ); - // black image, for no specular + if (glRefConfig.vertexBufferObject && r_arb_vertex_buffer_object->integer + && glRefConfig.glsl && r_arb_shader_objects->integer) + { + if (r_dlightShadows->integer) + { + for( x = 0; x < MAX_DLIGHTS; x++) + { + tr.shadowCubemaps[x] = R_CreateCubeImage(va("*shadowcubemap%i", x), (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE, qfalse, qfalse, GL_CLAMP_TO_EDGE ); + } + } + + for( x = 0; x < MAX_DRAWN_PSHADOWS; x++) + { + tr.pshadowMaps[x] = R_CreateImage(va("*shadowmap%i", x), (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE, qfalse, qfalse, GL_CLAMP_TO_EDGE ); + } + } + + // black image for (x=0 ; x end) - ri.Error( ERR_DROP, "LoadBMP: header too short (%s)\n", name ); + ri.Error( ERR_DROP, "LoadBMP: header too short (%s)", name ); Com_Memcpy( bmpHeader.palette, buf_p, sizeof( bmpHeader.palette ) ); buf_p += sizeof(bmpHeader.palette); @@ -124,26 +124,26 @@ void R_LoadBMP( const char *name, byte **pic, int *width, int *height ) if (buffer.b + bmpHeader.bitmapDataOffset > end) { - ri.Error( ERR_DROP, "LoadBMP: invalid offset value in header (%s)\n", name ); + ri.Error( ERR_DROP, "LoadBMP: invalid offset value in header (%s)", name ); } buf_p = buffer.b + bmpHeader.bitmapDataOffset; if ( bmpHeader.id[0] != 'B' && bmpHeader.id[1] != 'M' ) { - ri.Error( ERR_DROP, "LoadBMP: only Windows-style BMP files supported (%s)\n", name ); + ri.Error( ERR_DROP, "LoadBMP: only Windows-style BMP files supported (%s)", name ); } if ( bmpHeader.fileSize != length ) { - ri.Error( ERR_DROP, "LoadBMP: header size does not match file size (%u vs. %u) (%s)\n", bmpHeader.fileSize, length, name ); + ri.Error( ERR_DROP, "LoadBMP: header size does not match file size (%u vs. %u) (%s)", bmpHeader.fileSize, length, name ); } if ( bmpHeader.compression != 0 ) { - ri.Error( ERR_DROP, "LoadBMP: only uncompressed BMP files supported (%s)\n", name ); + ri.Error( ERR_DROP, "LoadBMP: only uncompressed BMP files supported (%s)", name ); } if ( bmpHeader.bitsPerPixel < 8 ) { - ri.Error( ERR_DROP, "LoadBMP: monochrome and 4-bit BMP files not supported (%s)\n", name ); + ri.Error( ERR_DROP, "LoadBMP: monochrome and 4-bit BMP files not supported (%s)", name ); } switch ( bmpHeader.bitsPerPixel ) @@ -154,7 +154,7 @@ void R_LoadBMP( const char *name, byte **pic, int *width, int *height ) case 32: break; default: - ri.Error( ERR_DROP, "LoadBMP: illegal pixel_size '%hu' in file '%s'\n", bmpHeader.bitsPerPixel, name ); + ri.Error( ERR_DROP, "LoadBMP: illegal pixel_size '%hu' in file '%s'", bmpHeader.bitsPerPixel, name ); break; } @@ -167,11 +167,11 @@ void R_LoadBMP( const char *name, byte **pic, int *width, int *height ) if(columns <= 0 || !rows || numPixels > 0x1FFFFFFF // 4*1FFFFFFF == 0x7FFFFFFC < 0x7FFFFFFF || ((numPixels * 4) / columns) / 4 != rows) { - ri.Error (ERR_DROP, "LoadBMP: %s has an invalid image size\n", name); + ri.Error (ERR_DROP, "LoadBMP: %s has an invalid image size", name); } if(buf_p + numPixels*bmpHeader.bitsPerPixel/8 > end) { - ri.Error (ERR_DROP, "LoadBMP: file truncated (%s)\n", name); + ri.Error (ERR_DROP, "LoadBMP: file truncated (%s)", name); } if ( width ) diff --git a/reaction/code/renderer/tr_image_jpg.c b/reaction/code/renderer/tr_image_jpg.c index a7a19172..028be6d9 100644 --- a/reaction/code/renderer/tr_image_jpg.c +++ b/reaction/code/renderer/tr_image_jpg.c @@ -51,7 +51,7 @@ static void R_JPGErrorExit(j_common_ptr cinfo) /* Let the memory manager delete any temp files before we die */ jpeg_destroy(cinfo); - ri.Error(ERR_FATAL, "%s\n", buffer); + ri.Error(ERR_FATAL, "%s", buffer); } static void R_JPGOutputMessage(j_common_ptr cinfo) @@ -138,10 +138,9 @@ void R_LoadJPG(const char *filename, unsigned char **pic, int *width, int *heigh /* Step 4: set parameters for decompression */ /* - * Make sure it always converts images to RGB color space. This will - * automatically convert 8-bit greyscale images to RGB as well. - */ - + * Make sure it always converts images to RGB color space. This will + * automatically convert 8-bit greyscale images to RGB as well. + */ cinfo.out_color_space = JCS_RGB; /* Step 5: Start decompressor */ @@ -170,7 +169,7 @@ void R_LoadJPG(const char *filename, unsigned char **pic, int *width, int *heigh ri.FS_FreeFile (fbuffer.v); jpeg_destroy_decompress(&cinfo); - ri.Error(ERR_DROP, "LoadJPG: %s has an invalid image format: %dx%d*4=%d, components: %d\n", filename, + ri.Error(ERR_DROP, "LoadJPG: %s has an invalid image format: %dx%d*4=%d, components: %d", filename, cinfo.output_width, cinfo.output_height, pixelcount * 4, cinfo.output_components); } @@ -299,7 +298,7 @@ empty_output_buffer (j_compress_ptr cinfo) jpeg_destroy_compress(cinfo); // Make crash fatal or we would probably leak memory. - ri.Error(ERR_FATAL, "Output buffer for encoded JPEG image has insufficient size of %d bytes\n", + ri.Error(ERR_FATAL, "Output buffer for encoded JPEG image has insufficient size of %d bytes", dest->size); return FALSE; diff --git a/reaction/code/renderer/tr_image_tga.c b/reaction/code/renderer/tr_image_tga.c index e66e60de..5eebde29 100644 --- a/reaction/code/renderer/tr_image_tga.c +++ b/reaction/code/renderer/tr_image_tga.c @@ -70,7 +70,7 @@ void R_LoadTGA ( const char *name, byte **pic, int *width, int *height) if(length < 18) { - ri.Error( ERR_DROP, "LoadTGA: header too short (%s)\n", name ); + ri.Error( ERR_DROP, "LoadTGA: header too short (%s)", name ); } buf_p = buffer.b; @@ -103,17 +103,17 @@ void R_LoadTGA ( const char *name, byte **pic, int *width, int *height) && targa_header.image_type!=10 && targa_header.image_type != 3 ) { - ri.Error (ERR_DROP, "LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n"); + ri.Error (ERR_DROP, "LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported"); } if ( targa_header.colormap_type != 0 ) { - ri.Error( ERR_DROP, "LoadTGA: colormaps not supported\n" ); + ri.Error( ERR_DROP, "LoadTGA: colormaps not supported" ); } if ( ( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 ) && targa_header.image_type != 3 ) { - ri.Error (ERR_DROP, "LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n"); + ri.Error (ERR_DROP, "LoadTGA: Only 32 or 24 bit images supported (no colormaps)"); } columns = targa_header.width; @@ -122,7 +122,7 @@ void R_LoadTGA ( const char *name, byte **pic, int *width, int *height) if(!columns || !rows || numPixels > 0x7FFFFFFF || numPixels / columns / 4 != rows) { - ri.Error (ERR_DROP, "LoadTGA: %s has an invalid image size\n", name); + ri.Error (ERR_DROP, "LoadTGA: %s has an invalid image size", name); } @@ -131,7 +131,7 @@ void R_LoadTGA ( const char *name, byte **pic, int *width, int *height) if (targa_header.id_length != 0) { if (buf_p + targa_header.id_length > end) - ri.Error( ERR_DROP, "LoadTGA: header too short (%s)\n", name ); + ri.Error( ERR_DROP, "LoadTGA: header too short (%s)", name ); buf_p += targa_header.id_length; // skip TARGA image comment } @@ -140,7 +140,7 @@ void R_LoadTGA ( const char *name, byte **pic, int *width, int *height) { if(buf_p + columns*rows*targa_header.pixel_size/8 > end) { - ri.Error (ERR_DROP, "LoadTGA: file truncated (%s)\n", name); + ri.Error (ERR_DROP, "LoadTGA: file truncated (%s)", name); } // Uncompressed RGB or gray scale image @@ -183,7 +183,7 @@ void R_LoadTGA ( const char *name, byte **pic, int *width, int *height) *pixbuf++ = alphabyte; break; default: - ri.Error( ERR_DROP, "LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name ); + ri.Error( ERR_DROP, "LoadTGA: illegal pixel_size '%d' in file '%s'", targa_header.pixel_size, name ); break; } } @@ -201,12 +201,12 @@ void R_LoadTGA ( const char *name, byte **pic, int *width, int *height) pixbuf = targa_rgba + row*columns*4; for(column=0; column end) - ri.Error (ERR_DROP, "LoadTGA: file truncated (%s)\n", name); + ri.Error (ERR_DROP, "LoadTGA: file truncated (%s)", name); packetHeader= *buf_p++; packetSize = 1 + (packetHeader & 0x7f); if (packetHeader & 0x80) { // run-length packet if(buf_p + targa_header.pixel_size/8 > end) - ri.Error (ERR_DROP, "LoadTGA: file truncated (%s)\n", name); + ri.Error (ERR_DROP, "LoadTGA: file truncated (%s)", name); switch (targa_header.pixel_size) { case 24: blue = *buf_p++; @@ -221,7 +221,7 @@ void R_LoadTGA ( const char *name, byte **pic, int *width, int *height) alphabyte = *buf_p++; break; default: - ri.Error( ERR_DROP, "LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name ); + ri.Error( ERR_DROP, "LoadTGA: illegal pixel_size '%d' in file '%s'", targa_header.pixel_size, name ); break; } @@ -244,7 +244,7 @@ void R_LoadTGA ( const char *name, byte **pic, int *width, int *height) else { // non run-length packet if(buf_p + targa_header.pixel_size/8*packetSize > end) - ri.Error (ERR_DROP, "LoadTGA: file truncated (%s)\n", name); + ri.Error (ERR_DROP, "LoadTGA: file truncated (%s)", name); for(j=0;jcaptureBuffer, packAlign); - + cBuf = PADP(cmd->captureBuffer, packAlign); + qglReadPixels(0, 0, cmd->width, cmd->height, GL_RGB, GL_UNSIGNED_BYTE, cBuf); @@ -826,13 +830,13 @@ const void *RB_TakeVideoFrameCmd( const void *data ) { byte *lineend, *memend; byte *srcptr, *destptr; - + srcptr = cBuf; destptr = cmd->encodeBuffer; memend = srcptr + memcount; - // swap R and B and remove line paddings - while(srcptr < memend) + // swap R and B and remove line paddings + while(srcptr < memend) { lineend = srcptr + linelen; while(srcptr < lineend) @@ -1094,6 +1098,9 @@ void R_Register( void ) r_deluxeMapping = ri.Cvar_Get( "r_deluxeMapping", "1", CVAR_ARCHIVE | CVAR_LATCH ); r_parallaxMapping = ri.Cvar_Get( "r_parallaxMapping", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_normalAmbient = ri.Cvar_Get( "r_normalAmbient", "0", CVAR_ARCHIVE | CVAR_LATCH ); + r_dlightShadows = ri.Cvar_Get( "r_dlightShadows", "0", CVAR_ARCHIVE | CVAR_LATCH ); + r_pshadowDist = ri.Cvar_Get( "r_pshadowDist", "128", CVAR_ARCHIVE ); + r_recalcMD3Normals = ri.Cvar_Get( "r_recalcMD3Normals", "0", CVAR_ARCHIVE | CVAR_LATCH ); // // temporary latched variables that can only change over a restart @@ -1307,7 +1314,8 @@ void R_Init( void ) { InitOpenGL(); - if (glRefConfig.glsl) + if (glRefConfig.vertexBufferObject && r_arb_vertex_buffer_object->integer + && glRefConfig.glsl && r_arb_shader_objects->integer) { GLSL_InitGPUShaders(); } @@ -1315,7 +1323,7 @@ void R_Init( void ) { R_InitImages(); R_InitFBOs(); - if (glRefConfig.vertexBufferObject) + if (glRefConfig.vertexBufferObject && r_arb_vertex_buffer_object->integer) { R_InitVBOs(); } diff --git a/reaction/code/renderer/tr_light.c b/reaction/code/renderer/tr_light.c index dc78fe06..e1f91492 100644 --- a/reaction/code/renderer/tr_light.c +++ b/reaction/code/renderer/tr_light.c @@ -365,9 +365,9 @@ void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ) { } // save out the byte packet version - ((byte *)&ent->ambientLightInt)[0] = myftol( ent->ambientLight[0] ); - ((byte *)&ent->ambientLightInt)[1] = myftol( ent->ambientLight[1] ); - ((byte *)&ent->ambientLightInt)[2] = myftol( ent->ambientLight[2] ); + ((byte *)&ent->ambientLightInt)[0] = Q_ftol(ent->ambientLight[0]); + ((byte *)&ent->ambientLightInt)[1] = Q_ftol(ent->ambientLight[1]); + ((byte *)&ent->ambientLightInt)[2] = Q_ftol(ent->ambientLight[2]); ((byte *)&ent->ambientLightInt)[3] = 0xff; // transform the direction to local space diff --git a/reaction/code/renderer/tr_local.h b/reaction/code/renderer/tr_local.h index a1a9321e..3eb7aed8 100644 --- a/reaction/code/renderer/tr_local.h +++ b/reaction/code/renderer/tr_local.h @@ -30,21 +30,15 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "tr_public.h" #include "tr_extramath.h" #include "qgl.h" +#include "iqm.h" #define GL_INDEX_TYPE GL_UNSIGNED_INT typedef unsigned int glIndex_t; -// fast float to int conversion -#if id386 && !defined(__GNUC__) -long myftol( float f ); -#else -#define myftol(x) ((int)(x)) -#endif - #define BUFFER_OFFSET(i) ((char *)NULL + (i)) #ifndef ARRAY_SIZE -# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) +# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) #endif // everything that is needed by the backend needs @@ -52,20 +46,21 @@ long myftol( float f ); // parallel on a dual cpu machine #define SMP_FRAMES 2 -// 12 bits +// 14 bits +// can't be increased without changing bit packing for drawsurfs // see QSORT_SHADERNUM_SHIFT -#define MAX_SHADERS 16384 +#define SHADERNUM_BITS 14 +#define MAX_SHADERS (1<index] + int index; // model = tr.models[model->index] - int dataSize; // just for listing purposes - bmodel_t *bmodel; // only if type == MOD_BRUSH + int dataSize; // just for listing purposes + bmodel_t *bmodel; // only if type == MOD_BRUSH mdvModel_t *mdv[MD3_MAX_LODS]; // only if type == MOD_MESH - void *md4; // only if type == (MOD_MD4 | MOD_MDR) + void *modelData; // only if type == (MOD_MD4 | MOD_MDR | MOD_IQM) int numLods; } model_t; @@ -1424,21 +1489,32 @@ compared quickly during the qsorting process the bits are allocated as follows: -21 - 31 : sorted shader index -11 - 20 : entity index -2 - 6 : fog index -//2 : used to be clipped flag REMOVED - 03.21.00 rad 0 - 1 : dlightmap index +//2 : used to be clipped flag REMOVED - 03.21.00 rad +2 - 6 : fog index +11 - 20 : entity index +21 - 31 : sorted shader index TTimo - 1.32 +0-1 : dlightmap index +2-6 : fog index +7-16 : entity index +17-30 : sorted shader index + + SmileTheory - for pshadows 17-31 : sorted shader index 7-16 : entity index 2-6 : fog index -0-1 : dlightmap index +1 : pshadow flag +0 : dlight flag */ -#define QSORT_SHADERNUM_SHIFT 17 +#define QSORT_FOGNUM_SHIFT 2 #define QSORT_ENTITYNUM_SHIFT 7 -#define QSORT_FOGNUM_SHIFT 2 +#define QSORT_SHADERNUM_SHIFT (QSORT_ENTITYNUM_SHIFT+GENTITYNUM_BITS) +#if (QSORT_SHADERNUM_SHIFT+SHADERNUM_BITS) > 32 + #error "Need to update sorting, too many bits." +#endif +#define QSORT_PSHADOW_SHIFT 1 extern int gl_filter_min, gl_filter_max; @@ -1620,6 +1696,8 @@ typedef struct { image_t *whiteImage; // full of 0xff image_t *blackImage; // full of 0x000000ff image_t *identityLightImage; // full of tr.identityLightByte + image_t *shadowCubemaps[MAX_DLIGHTS]; + image_t *pshadowMaps[MAX_DRAWN_PSHADOWS]; shader_t *defaultShader; shader_t *shadowShader; @@ -1652,6 +1730,8 @@ typedef struct { shaderProgram_t fogShader; shaderProgram_t dlightallShader; shaderProgram_t lightallShader[LIGHTDEF_COUNT]; + shaderProgram_t shadowmapShader; + shaderProgram_t pshadowShader; // ----------------------------------------- @@ -1854,6 +1934,9 @@ extern cvar_t *r_specularMapping; extern cvar_t *r_deluxeMapping; extern cvar_t *r_parallaxMapping; extern cvar_t *r_normalAmbient; +extern cvar_t *r_dlightShadows; +extern cvar_t *r_pshadowDist; +extern cvar_t *r_recalcMD3Normals; extern cvar_t *r_greyscale; @@ -1881,6 +1964,8 @@ void R_NoiseInit( void ); void R_SwapBuffers( int ); void R_RenderView( viewParms_t *parms ); +void R_RenderDlightCubemaps(const refdef_t *fd); +void R_RenderPshadowMaps(const refdef_t *fd); void R_AddMD3Surfaces( trRefEntity_t *e ); void R_AddNullModelSurfaces( trRefEntity_t *e ); @@ -1891,9 +1976,10 @@ void R_AddLightningBoltSurfaces( trRefEntity_t *e ); void R_AddPolygonSurfaces( void ); void R_DecomposeSort( unsigned sort, int *entityNum, shader_t **shader, - int *fogNum, int *dlightMap ); + int *fogNum, int *dlightMap, int *pshadowMap ); -void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, int fogIndex, int dlightMap ); +void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, + int fogIndex, int dlightMap, int pshadowMap ); void R_CalcTangentSpace(vec3_t tangent, vec3_t bitangent, vec3_t normal, const vec3_t v0, const vec3_t v1, const vec3_t v2, const vec2_t t0, const vec2_t t1, const vec2_t t2); @@ -1912,13 +1998,14 @@ int R_CullPointAndRadiusEx( const vec3_t origin, float radius, const cplane_t* f int R_CullPointAndRadius( const vec3_t origin, float radius ); int R_CullLocalPointAndRadius( const vec3_t origin, float radius ); -void R_SetupProjection(viewParms_t *dest, float zProj, qboolean computeFrustum); +void R_SetupProjection(viewParms_t *dest, float zProj, float zFar, qboolean computeFrustum); void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms, orientationr_t *or ); /* ** GL wrapper/helper functions */ void GL_Bind( image_t *image ); +void GL_BindCubemap( image_t *image ); void GL_BindToTMU( image_t *image, int tmu ); void GL_SetDefaultState (void); void GL_SelectTexture( int unit ); @@ -2091,6 +2178,7 @@ typedef struct shaderCommands_s int fogNum; int dlightBits; // or together of all vertexDlightBits + int pshadowBits; int firstIndex; int numIndexes; @@ -2284,6 +2372,7 @@ void GLSL_SetNumUniforms(shaderProgram_t *program, int numUniforms); void GLSL_SetUniformName(shaderProgram_t *program, int uniformNum, const char *name); void GLSL_SetUniformInt(shaderProgram_t *program, int uniformNum, GLint value); void GLSL_SetUniformFloat(shaderProgram_t *program, int uniformNum, GLfloat value); +void GLSL_SetUniformFloat5(shaderProgram_t *program, int uniformNum, const vec5_t v); void GLSL_SetUniformVec2(shaderProgram_t *program, int uniformNum, const vec2_t v); void GLSL_SetUniformVec3(shaderProgram_t *program, int uniformNum, const vec3_t v); void GLSL_SetUniformVec4(shaderProgram_t *program, int uniformNum, const vec4_t v); @@ -2344,6 +2433,12 @@ void RB_SurfaceAnim( md4Surface_t *surfType ); void R_MDRAddAnimSurfaces( trRefEntity_t *ent ); void RB_MDRSurfaceAnim( md4Surface_t *surface ); #endif +qboolean R_LoadIQM (model_t *mod, void *buffer, int filesize, const char *name ); +void R_AddIQMSurfaces( trRefEntity_t *ent ); +void RB_IQMSurfaceAnim( surfaceType_t *surface ); +int R_IQMLerpTag( orientation_t *tag, iqmData_t *data, + int startFrame, int endFrame, + float frac, const char *tagName ); /* ============================================================= @@ -2498,6 +2593,12 @@ typedef struct int commandId; } clearDepthCommand_t; +typedef struct { + int commandId; + int map; + int cubeSide; +} capShadowmapCommand_t; + typedef enum { RC_END_OF_LIST, RC_SET_COLOR, @@ -2508,7 +2609,8 @@ typedef enum { RC_SCREENSHOT, RC_VIDEOFRAME, RC_COLORMASK, - RC_CLEARDEPTH + RC_CLEARDEPTH, + RC_CAPSHADOWMAP } renderCommand_t; @@ -2528,6 +2630,7 @@ typedef struct { trRefEntity_t entities[MAX_ENTITIES]; srfPoly_t *polys;//[MAX_POLYS]; polyVert_t *polyVerts;//[MAX_POLYVERTS]; + pshadow_t pshadows[MAX_CALC_PSHADOWS]; renderCommandList_t commands; } backEndData_t; @@ -2550,6 +2653,7 @@ void R_ShutdownCommandBuffers( void ); void R_SyncRenderThread( void ); void R_AddDrawSurfCmd( drawSurf_t *drawSurfs, int numDrawSurfs ); +void R_AddCapShadowmapCmd( int dlight, int cubeSide ); void RE_SetColor( const float *rgba ); void RE_StretchPic ( float x, float y, float w, float h, diff --git a/reaction/code/renderer/tr_main.c b/reaction/code/renderer/tr_main.c index 085788f6..fc5133d1 100644 --- a/reaction/code/renderer/tr_main.c +++ b/reaction/code/renderer/tr_main.c @@ -177,9 +177,16 @@ void R_CalcTangentSpace(vec3_t tangent, vec3_t bitangent, vec3_t normal, VectorNormalize(bitangent); // compute the face normal based on vertex points - VectorSubtract(v2, v0, u); - VectorSubtract(v1, v0, v); - CrossProduct(u, v, faceNormal); + if ( normal[0] == 0.0f && normal[1] == 0.0f && normal[2] == 0.0f ) + { + VectorSubtract(v2, v0, u); + VectorSubtract(v1, v0, v); + CrossProduct(u, v, faceNormal); + } + else + { + VectorCopy(normal, faceNormal); + } VectorNormalize(faceNormal); @@ -1061,7 +1068,7 @@ Set up the culling frustum planes for the current view using the results we got the projection matrix. ================= */ -void R_SetupFrustum (viewParms_t *dest, float xmin, float xmax, float ymax, float zProj, float stereoSep) +void R_SetupFrustum (viewParms_t *dest, float xmin, float xmax, float ymax, float zProj, float zFar, float stereoSep) { vec3_t ofsorigin; float oppleg, adjleg, length; @@ -1114,6 +1121,18 @@ void R_SetupFrustum (viewParms_t *dest, float xmin, float xmax, float ymax, floa dest->frustum[i].dist = DotProduct (ofsorigin, dest->frustum[i].normal); SetPlaneSignbits( &dest->frustum[i] ); } + + if (zFar != 0.0f) + { + vec3_t farpoint; + + VectorMA(ofsorigin, zFar, dest->or.axis[0], farpoint); + VectorScale(dest->or.axis[0], -1.0f, dest->frustum[4].normal); + + dest->frustum[4].type = PLANE_NON_AXIAL; + dest->frustum[4].dist = DotProduct (farpoint, dest->frustum[4].normal); + SetPlaneSignbits( &dest->frustum[4] ); + } } /* @@ -1121,7 +1140,7 @@ void R_SetupFrustum (viewParms_t *dest, float xmin, float xmax, float ymax, floa R_SetupProjection =============== */ -void R_SetupProjection(viewParms_t *dest, float zProj, qboolean computeFrustum) +void R_SetupProjection(viewParms_t *dest, float zProj, float zFar, qboolean computeFrustum) { float xmin, xmax, ymin, ymax; float width, height, stereoSep = r_stereoSeparation->value; @@ -1167,7 +1186,7 @@ void R_SetupProjection(viewParms_t *dest, float zProj, qboolean computeFrustum) // Now that we have all the data for the projection matrix we can also setup the view frustum. if(computeFrustum) - R_SetupFrustum(dest, xmin, xmax, ymax, zProj, stereoSep); + R_SetupFrustum(dest, xmin, xmax, ymax, zProj, zFar, stereoSep); } /* @@ -1182,7 +1201,8 @@ void R_SetupProjectionZ(viewParms_t *dest) float zNear, zFar, depth; zNear = r_znear->value; - zFar = dest->zFar; + zFar = dest->zFar; + depth = zFar - zNear; dest->projectionMatrix[2] = 0; @@ -1502,6 +1522,7 @@ static qboolean SurfIsOffscreen( const drawSurf_t *drawSurf, vec4_t clipDest[128 shader_t *shader; int fogNum; int dlighted; + int pshadowed; vec4_t clip, eye; int i; unsigned int pointOr = 0; @@ -1513,7 +1534,7 @@ static qboolean SurfIsOffscreen( const drawSurf_t *drawSurf, vec4_t clipDest[128 R_RotateForViewer(); - R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted ); + R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted, &pshadowed ); RB_BeginSurface( shader, fogNum ); rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); @@ -1750,7 +1771,7 @@ R_AddDrawSurf ================= */ void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, - int fogIndex, int dlightMap ) { + int fogIndex, int dlightMap, int pshadowMap ) { int index; // instead of checking for overflow, we just mask the index @@ -1759,7 +1780,8 @@ void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, // the sort data is packed into a single 32 bit value so it can be // compared quickly during the qsorting process tr.refdef.drawSurfs[index].sort = (shader->sortedIndex << QSORT_SHADERNUM_SHIFT) - | tr.shiftedEntityNum | ( fogIndex << QSORT_FOGNUM_SHIFT ) | (int)dlightMap; + | tr.shiftedEntityNum | ( fogIndex << QSORT_FOGNUM_SHIFT ) + | ((int)pshadowMap << QSORT_PSHADOW_SHIFT) | (int)dlightMap; tr.refdef.drawSurfs[index].surface = surface; tr.refdef.numDrawSurfs++; } @@ -1770,11 +1792,12 @@ R_DecomposeSort ================= */ void R_DecomposeSort( unsigned sort, int *entityNum, shader_t **shader, - int *fogNum, int *dlightMap ) { + int *fogNum, int *dlightMap, int *pshadowMap ) { *fogNum = ( sort >> QSORT_FOGNUM_SHIFT ) & 31; *shader = tr.sortedShaders[ ( sort >> QSORT_SHADERNUM_SHIFT ) & (MAX_SHADERS-1) ]; *entityNum = ( sort >> QSORT_ENTITYNUM_SHIFT ) & (MAX_GENTITIES-1); - *dlightMap = sort & 3; + *pshadowMap = (sort & 2) >> 1; + *dlightMap = sort & 1; } /* @@ -1787,6 +1810,7 @@ void R_SortDrawSurfs( drawSurf_t *drawSurfs, int numDrawSurfs ) { int fogNum; int entityNum; int dlighted; + int pshadowed; int i; // it is possible for some views to not have any surfaces @@ -1808,123 +1832,134 @@ void R_SortDrawSurfs( drawSurf_t *drawSurfs, int numDrawSurfs ) { // check for any pass through drawing, which // may cause another view to be rendered first - for ( i = 0 ; i < numDrawSurfs ; i++ ) { - R_DecomposeSort( (drawSurfs+i)->sort, &entityNum, &shader, &fogNum, &dlighted ); + if (!tr.viewParms.isShadowmap) + { + for ( i = 0 ; i < numDrawSurfs ; i++ ) { + R_DecomposeSort( (drawSurfs+i)->sort, &entityNum, &shader, &fogNum, &dlighted, &pshadowed ); - if ( shader->sort > SS_PORTAL ) { - break; - } - - // no shader should ever have this sort type - if ( shader->sort == SS_BAD ) { - ri.Error (ERR_DROP, "Shader '%s'with sort == SS_BAD", shader->name ); - } - - // if the mirror was completely clipped away, we may need to check another surface - if ( R_MirrorViewBySurface( (drawSurfs+i), entityNum) ) { - // this is a debug option to see exactly what is being mirrored - if ( r_portalOnly->integer ) { - return; + if ( shader->sort > SS_PORTAL ) { + break; + } + + // no shader should ever have this sort type + if ( shader->sort == SS_BAD ) { + ri.Error (ERR_DROP, "Shader '%s'with sort == SS_BAD", shader->name ); + } + + // if the mirror was completely clipped away, we may need to check another surface + if ( R_MirrorViewBySurface( (drawSurfs+i), entityNum) ) { + // this is a debug option to see exactly what is being mirrored + if ( r_portalOnly->integer ) { + return; + } + break; // only one mirror view at a time } - break; // only one mirror view at a time } } R_AddDrawSurfCmd( drawSurfs, numDrawSurfs ); } +static void R_AddEntitySurface (int entityNum) +{ + trRefEntity_t *ent; + shader_t *shader; + + tr.currentEntityNum = entityNum; + + ent = tr.currentEntity = &tr.refdef.entities[tr.currentEntityNum]; + + ent->needDlights = qfalse; + + // preshift the value we are going to OR into the drawsurf sort + tr.shiftedEntityNum = tr.currentEntityNum << QSORT_ENTITYNUM_SHIFT; + + // + // the weapon model must be handled special -- + // we don't want the hacked weapon position showing in + // mirrors, because the true body position will already be drawn + // + if ( (ent->e.renderfx & RF_FIRST_PERSON) && (tr.viewParms.isPortal || tr.viewParms.isShadowmap)) { + return; + } + + // simple generated models, like sprites and beams, are not culled + switch ( ent->e.reType ) { + case RT_PORTALSURFACE: + break; // don't draw anything + case RT_SPRITE: + case RT_BEAM: + case RT_LIGHTNING: + case RT_RAIL_CORE: + case RT_RAIL_RINGS: + // self blood sprites, talk balloons, etc should not be drawn in the primary + // view. We can't just do this check for all entities, because md3 + // entities may still want to cast shadows from them + if ( (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal) { + return; + } + shader = R_GetShaderByHandle( ent->e.customShader ); + R_AddDrawSurf( &entitySurface, shader, R_SpriteFogNum( ent ), 0, 0 ); + break; + + case RT_MODEL: + // we must set up parts of tr.or for model culling + R_RotateForEntity( ent, &tr.viewParms, &tr.or ); + + tr.currentModel = R_GetModelByHandle( ent->e.hModel ); + if (!tr.currentModel) { + R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0, 0 ); + } else { + switch ( tr.currentModel->type ) { + case MOD_MESH: + R_AddMD3Surfaces( ent ); + break; + case MOD_MD4: + R_AddAnimSurfaces( ent ); + break; +#ifdef RAVENMD4 + case MOD_MDR: + R_MDRAddAnimSurfaces( ent ); + break; +#endif + case MOD_IQM: + R_AddIQMSurfaces( ent ); + break; + case MOD_BRUSH: + R_AddBrushModelSurfaces( ent ); + break; + case MOD_BAD: // null model axis + if ( (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal) { + break; + } + shader = R_GetShaderByHandle( ent->e.customShader ); + R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0, 0 ); + break; + default: + ri.Error( ERR_DROP, "R_AddEntitySurfaces: Bad modeltype" ); + break; + } + } + break; + default: + ri.Error( ERR_DROP, "R_AddEntitySurfaces: Bad reType" ); + } +} + /* ============= R_AddEntitySurfaces ============= */ void R_AddEntitySurfaces (void) { - trRefEntity_t *ent; - shader_t *shader; + int i; if ( !r_drawentities->integer ) { return; } - for ( tr.currentEntityNum = 0; - tr.currentEntityNum < tr.refdef.num_entities; - tr.currentEntityNum++ ) { - ent = tr.currentEntity = &tr.refdef.entities[tr.currentEntityNum]; - - ent->needDlights = qfalse; - - // preshift the value we are going to OR into the drawsurf sort - tr.shiftedEntityNum = tr.currentEntityNum << QSORT_ENTITYNUM_SHIFT; - - // - // the weapon model must be handled special -- - // we don't want the hacked weapon position showing in - // mirrors, because the true body position will already be drawn - // - if ( (ent->e.renderfx & RF_FIRST_PERSON) && tr.viewParms.isPortal) { - continue; - } - - // simple generated models, like sprites and beams, are not culled - switch ( ent->e.reType ) { - case RT_PORTALSURFACE: - break; // don't draw anything - case RT_SPRITE: - case RT_BEAM: - case RT_LIGHTNING: - case RT_RAIL_CORE: - case RT_RAIL_RINGS: - // self blood sprites, talk balloons, etc should not be drawn in the primary - // view. We can't just do this check for all entities, because md3 - // entities may still want to cast shadows from them - if ( (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal) { - continue; - } - shader = R_GetShaderByHandle( ent->e.customShader ); - R_AddDrawSurf( &entitySurface, shader, R_SpriteFogNum( ent ), 0 ); - break; - - case RT_MODEL: - // we must set up parts of tr.or for model culling - R_RotateForEntity( ent, &tr.viewParms, &tr.or ); - - tr.currentModel = R_GetModelByHandle( ent->e.hModel ); - if (!tr.currentModel) { - R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0 ); - } else { - switch ( tr.currentModel->type ) { - case MOD_MESH: - R_AddMD3Surfaces( ent ); - break; - case MOD_MD4: - R_AddAnimSurfaces( ent ); - break; -#ifdef RAVENMD4 - case MOD_MDR: - R_MDRAddAnimSurfaces( ent ); - break; -#endif - case MOD_BRUSH: - R_AddBrushModelSurfaces( ent ); - break; - case MOD_BAD: // null model axis - if ( (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal) { - break; - } - shader = R_GetShaderByHandle( ent->e.customShader ); - R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0 ); - break; - default: - ri.Error( ERR_DROP, "R_AddEntitySurfaces: Bad modeltype" ); - break; - } - } - break; - default: - ri.Error( ERR_DROP, "R_AddEntitySurfaces: Bad reType" ); - } - } - + for ( i = 0; i < tr.refdef.num_entities; i++) + R_AddEntitySurface(i); } @@ -1945,7 +1980,8 @@ void R_GenerateDrawSurfs( void ) { // matrix for lod calculation // dynamically compute far clip plane distance - R_SetFarClip(); + if (!tr.viewParms.isShadowmap) + R_SetFarClip(); // we know the size of the clipping volume. Now set the rest of the projection matrix. R_SetupProjectionZ (&tr.viewParms); @@ -2036,7 +2072,7 @@ void R_RenderView (viewParms_t *parms) { // set viewParms.world R_RotateForViewer (); - R_SetupProjection(&tr.viewParms, r_zproj->value, qtrue); + R_SetupProjection(&tr.viewParms, r_zproj->value, tr.viewParms.zFar, qtrue); R_GenerateDrawSurfs(); @@ -2047,5 +2083,418 @@ void R_RenderView (viewParms_t *parms) { } +void R_RenderDlightCubemaps(const refdef_t *fd) +{ + int i; + + for (i = 0; i < tr.refdef.num_dlights; i++) + { + viewParms_t shadowParms; + int j; + + // use previous frame to determine visible dlights + if ((1 << i) & tr.refdef.dlightMask) + continue; + + Com_Memset( &shadowParms, 0, sizeof( shadowParms ) ); + + shadowParms.viewportX = tr.refdef.x; + shadowParms.viewportY = glConfig.vidHeight - ( tr.refdef.y + 256 ); + shadowParms.viewportWidth = 256; + shadowParms.viewportHeight = 256; + shadowParms.isPortal = qfalse; + shadowParms.isMirror = qtrue; // because it is + + shadowParms.fovX = 90; + shadowParms.fovY = 90; + + shadowParms.isShadowmap = qtrue; + shadowParms.zFar = tr.refdef.dlights[i].radius; + + VectorCopy( tr.refdef.dlights[i].origin, shadowParms.or.origin ); + + for (j = 0; j < 6; j++) + { + switch(j) + { + case 0: + // -X + VectorSet( shadowParms.or.axis[0], -1, 0, 0); + VectorSet( shadowParms.or.axis[1], 0, 0, -1); + VectorSet( shadowParms.or.axis[2], 0, 1, 0); + break; + case 1: + // +X + VectorSet( shadowParms.or.axis[0], 1, 0, 0); + VectorSet( shadowParms.or.axis[1], 0, 0, 1); + VectorSet( shadowParms.or.axis[2], 0, 1, 0); + break; + case 2: + // -Y + VectorSet( shadowParms.or.axis[0], 0, -1, 0); + VectorSet( shadowParms.or.axis[1], 1, 0, 0); + VectorSet( shadowParms.or.axis[2], 0, 0, -1); + break; + case 3: + // +Y + VectorSet( shadowParms.or.axis[0], 0, 1, 0); + VectorSet( shadowParms.or.axis[1], 1, 0, 0); + VectorSet( shadowParms.or.axis[2], 0, 0, 1); + break; + case 4: + // -Z + VectorSet( shadowParms.or.axis[0], 0, 0, -1); + VectorSet( shadowParms.or.axis[1], 1, 0, 0); + VectorSet( shadowParms.or.axis[2], 0, 1, 0); + break; + case 5: + // +Z + VectorSet( shadowParms.or.axis[0], 0, 0, 1); + VectorSet( shadowParms.or.axis[1], -1, 0, 0); + VectorSet( shadowParms.or.axis[2], 0, 1, 0); + break; + } + + R_RenderView(&shadowParms); + R_AddCapShadowmapCmd( i, j ); + } + } +} + + +void R_RenderPshadowMaps(const refdef_t *fd) +{ + viewParms_t shadowParms; + int i; + + // first, make a list of shadows + for ( i = 0; i < tr.refdef.num_entities; i++) + { + trRefEntity_t *ent = &tr.refdef.entities[i]; + + if((ent->e.renderfx & (RF_FIRST_PERSON | RF_NOSHADOW))) + continue; + + //if((ent->e.renderfx & RF_THIRD_PERSON)) + //continue; + + if (ent->e.reType == RT_MODEL) + { + model_t *model = R_GetModelByHandle( ent->e.hModel ); + pshadow_t shadow; + float radius = 0.0f; + float scale = 1.0f; + vec3_t diff; + int j; + + if (!model) + continue; + + if (ent->e.nonNormalizedAxes) + { + scale = VectorLength( ent->e.axis[0] ); + } + + switch (model->type) + { + case MOD_MESH: + { + mdvFrame_t *frame = &model->mdv[0]->frames[ent->e.frame]; + + radius = frame->radius * scale; + } + break; + + case MOD_MD4: + { + // FIXME: actually calculate the radius and bounds, this is a horrible hack + radius = r_pshadowDist->value / 2.0f; + } + break; +#ifdef RAVENMD4 + case MOD_MDR: + { + // FIXME: never actually tested this + mdrHeader_t *header = model->modelData; + int frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] ); + mdrFrame_t *frame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame); + + radius = frame->radius; + } + break; +#endif + case MOD_IQM: + { + // FIXME: never actually tested this + iqmData_t *data = model->modelData; + vec3_t diag; + float *framebounds; + + framebounds = data->bounds + 6*ent->e.frame; + VectorSubtract( framebounds+3, framebounds, diag ); + radius = 0.5f * VectorLength( diag ); + } + break; + + default: + break; + } + + if (!radius) + continue; + + // Cull entities that are behind the viewer by more than lightRadius + VectorSubtract(ent->e.origin, fd->vieworg, diff); + if (DotProduct(diff, fd->viewaxis[0]) < -r_pshadowDist->value) + continue; + + memset(&shadow, 0, sizeof(shadow)); + + shadow.numEntities = 1; + shadow.entityNums[0] = i; + shadow.viewRadius = radius; + shadow.lightRadius = r_pshadowDist->value; + VectorCopy(ent->e.origin, shadow.viewOrigin); + shadow.sort = DotProduct(diff, diff) / (radius * radius); + VectorCopy(ent->e.origin, shadow.entityOrigins[0]); + shadow.entityRadiuses[0] = radius; + + for (j = 0; j < MAX_CALC_PSHADOWS; j++) + { + pshadow_t swap; + + if (j + 1 > tr.refdef.num_pshadows) + { + tr.refdef.num_pshadows = j + 1; + tr.refdef.pshadows[j] = shadow; + break; + } + + // sort shadows by distance from camera divided by radius + // FIXME: sort better + if (tr.refdef.pshadows[j].sort <= shadow.sort) + continue; + + swap = tr.refdef.pshadows[j]; + tr.refdef.pshadows[j] = shadow; + shadow = swap; + } + } + } + + // next, merge touching pshadows + for ( i = 0; i < tr.refdef.num_pshadows; i++) + { + pshadow_t *ps1 = &tr.refdef.pshadows[i]; + int j; + + for (j = i + 1; j < tr.refdef.num_pshadows; j++) + { + pshadow_t *ps2 = &tr.refdef.pshadows[j]; + int k; + qboolean touch; + + if (ps1->numEntities == 8) + break; + + touch = qfalse; + if (SpheresIntersect(ps1->viewOrigin, ps1->viewRadius, ps2->viewOrigin, ps2->viewRadius)) + { + for (k = 0; k < ps1->numEntities; k++) + { + if (SpheresIntersect(ps1->entityOrigins[k], ps1->entityRadiuses[k], ps2->viewOrigin, ps2->viewRadius)) + { + touch = qtrue; + break; + } + } + } + + if (touch) + { + vec3_t newOrigin; + float newRadius; + + BoundingSphereOfSpheres(ps1->viewOrigin, ps1->viewRadius, ps2->viewOrigin, ps2->viewRadius, newOrigin, &newRadius); + VectorCopy(newOrigin, ps1->viewOrigin); + ps1->viewRadius = newRadius; + + ps1->entityNums[ps1->numEntities] = ps2->entityNums[0]; + VectorCopy(ps2->viewOrigin, ps1->entityOrigins[ps1->numEntities]); + ps1->entityRadiuses[ps1->numEntities] = ps2->viewRadius; + + ps1->numEntities++; + + for (k = j; k < tr.refdef.num_pshadows - 1; k++) + { + tr.refdef.pshadows[k] = tr.refdef.pshadows[k + 1]; + } + + j--; + tr.refdef.num_pshadows--; + } + } + } + + // cap number of drawn pshadows + if (tr.refdef.num_pshadows > MAX_DRAWN_PSHADOWS) + { + tr.refdef.num_pshadows = MAX_DRAWN_PSHADOWS; + } + + // next, fill up the rest of the shadow info + for ( i = 0; i < tr.refdef.num_pshadows; i++) + { + trRefEntity_t fakeEnt; + pshadow_t *shadow = &tr.refdef.pshadows[i]; + vec3_t right; + vec3_t lightDir; + +#if 0 + VectorSet(lightDir, 0.57735, 0.57735, 0.57735); +#else + // light a fake entity to determine light direction + memset(&fakeEnt, 0, sizeof(fakeEnt)); + VectorCopy(shadow->viewOrigin, fakeEnt.e.origin); + R_SetupEntityLighting( &tr.refdef, &fakeEnt); + VectorCopy(fakeEnt.lightDir, lightDir); +#endif + + if (shadow->viewRadius * 3.0f > shadow->lightRadius) + { + shadow->lightRadius = shadow->viewRadius * 3.0f; + } + + VectorMA(shadow->viewOrigin, shadow->viewRadius, lightDir, shadow->lightOrigin); + + // make up a projection, spin doesn't matter + VectorScale(lightDir, -1.0f, shadow->lightViewAxis[0]); + VectorSet(right, 0, 0, -1); + + if ( abs(DotProduct(right, shadow->lightViewAxis[0])) > 0.9f ) + { + VectorSet(right, -1, 0, 0); + } + + CrossProduct(shadow->lightViewAxis[0], right, shadow->lightViewAxis[1]); + VectorNormalize(shadow->lightViewAxis[1]); + CrossProduct(shadow->lightViewAxis[0], shadow->lightViewAxis[1], shadow->lightViewAxis[2]); + + VectorCopy(shadow->lightViewAxis[0], shadow->cullPlane.normal); + shadow->cullPlane.dist = DotProduct(shadow->cullPlane.normal, shadow->lightOrigin); + shadow->cullPlane.type = PLANE_NON_AXIAL; + SetPlaneSignbits(&shadow->cullPlane); + } + + // next, render shadowmaps + for ( i = 0; i < tr.refdef.num_pshadows; i++) + { + int firstDrawSurf; + pshadow_t *shadow = &tr.refdef.pshadows[i]; + int j; + + Com_Memset( &shadowParms, 0, sizeof( shadowParms ) ); + + shadowParms.viewportX = tr.refdef.x; + shadowParms.viewportY = glConfig.vidHeight - ( tr.refdef.y + 256 ); + shadowParms.viewportWidth = 256; + shadowParms.viewportHeight = 256; + shadowParms.isPortal = qfalse; + shadowParms.isMirror = qfalse; + + shadowParms.fovX = 90; + shadowParms.fovY = 90; + + shadowParms.isShadowmap = qtrue; + + shadowParms.zFar = shadow->lightRadius; + + VectorCopy(shadow->lightOrigin, shadowParms.or.origin); + + VectorCopy(shadow->lightViewAxis[0], shadowParms.or.axis[0]); + VectorCopy(shadow->lightViewAxis[1], shadowParms.or.axis[1]); + VectorCopy(shadow->lightViewAxis[2], shadowParms.or.axis[2]); + + { + tr.viewCount++; + + tr.viewParms = shadowParms; + tr.viewParms.frameSceneNum = tr.frameSceneNum; + tr.viewParms.frameCount = tr.frameCount; + + firstDrawSurf = tr.refdef.numDrawSurfs; + + tr.viewCount++; + + // set viewParms.world + R_RotateForViewer (); + + { + float xmin, xmax, ymin, ymax, znear, zfar; + viewParms_t *dest = &tr.viewParms; + vec3_t pop; + + xmin = ymin = -shadow->viewRadius; + xmax = ymax = shadow->viewRadius; + znear = 0; + zfar = shadow->lightRadius; + + dest->projectionMatrix[0] = 2 / (xmax - xmin); + dest->projectionMatrix[4] = 0; + dest->projectionMatrix[8] = (xmax + xmin) / (xmax - xmin); + dest->projectionMatrix[12] =0; + + dest->projectionMatrix[1] = 0; + dest->projectionMatrix[5] = 2 / (ymax - ymin); + dest->projectionMatrix[9] = ( ymax + ymin ) / (ymax - ymin); // normally 0 + dest->projectionMatrix[13] = 0; + + dest->projectionMatrix[2] = 0; + dest->projectionMatrix[6] = 0; + dest->projectionMatrix[10] = 2 / (zfar - znear); + dest->projectionMatrix[14] = 0; + + dest->projectionMatrix[3] = 0; + dest->projectionMatrix[7] = 0; + dest->projectionMatrix[11] = 0; + dest->projectionMatrix[15] = 1; + + VectorScale(dest->or.axis[1], 1.0f, dest->frustum[0].normal); + VectorMA(dest->or.origin, -shadow->viewRadius, dest->frustum[0].normal, pop); + dest->frustum[0].dist = DotProduct(pop, dest->frustum[0].normal); + + VectorScale(dest->or.axis[1], -1.0f, dest->frustum[1].normal); + VectorMA(dest->or.origin, -shadow->viewRadius, dest->frustum[1].normal, pop); + dest->frustum[1].dist = DotProduct(pop, dest->frustum[1].normal); + + VectorScale(dest->or.axis[2], 1.0f, dest->frustum[2].normal); + VectorMA(dest->or.origin, -shadow->viewRadius, dest->frustum[2].normal, pop); + dest->frustum[2].dist = DotProduct(pop, dest->frustum[2].normal); + + VectorScale(dest->or.axis[2], -1.0f, dest->frustum[3].normal); + VectorMA(dest->or.origin, -shadow->viewRadius, dest->frustum[3].normal, pop); + dest->frustum[3].dist = DotProduct(pop, dest->frustum[3].normal); + + VectorScale(dest->or.axis[0], -1.0f, dest->frustum[4].normal); + VectorMA(dest->or.origin, -shadow->lightRadius, dest->frustum[4].normal, pop); + dest->frustum[4].dist = DotProduct(pop, dest->frustum[4].normal); + + for (j = 0; j < 5; j++) + { + dest->frustum[j].type = PLANE_NON_AXIAL; + SetPlaneSignbits (&dest->frustum[j]); + } + } + + for (j = 0; j < shadow->numEntities; j++) + { + R_AddEntitySurface(shadow->entityNums[j]); + } + + R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, tr.refdef.numDrawSurfs - firstDrawSurf ); + R_AddCapShadowmapCmd( i, -1 ); + } + } +} diff --git a/reaction/code/renderer/tr_marks.c b/reaction/code/renderer/tr_marks.c index b74e0722..b3c6c846 100644 --- a/reaction/code/renderer/tr_marks.c +++ b/reaction/code/renderer/tr_marks.c @@ -457,3 +457,4 @@ int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projectio } + diff --git a/reaction/code/renderer/tr_mesh.c b/reaction/code/renderer/tr_mesh.c index 3d5e37e0..5d0fb25e 100644 --- a/reaction/code/renderer/tr_mesh.c +++ b/reaction/code/renderer/tr_mesh.c @@ -185,12 +185,10 @@ int R_ComputeLOD( trRefEntity_t *ent ) { // and use that as a criteria for selecting LOD #ifdef RAVENMD4 - // This is an MDR model. - - if(tr.currentModel->md4) + if(tr.currentModel->type == MOD_MDR) { int frameSize; - mdr = (mdrHeader_t *) tr.currentModel->md4; + mdr = (mdrHeader_t *) tr.currentModel->modelData; frameSize = (size_t) (&((mdrFrame_t *)0)->bones[mdr->numBones]); mdrframe = (mdrFrame_t *) ((byte *) mdr + mdr->ofsFrames + frameSize * ent->e.frame); @@ -221,7 +219,7 @@ int R_ComputeLOD( trRefEntity_t *ent ) { } flod *= tr.currentModel->numLods; - lod = myftol( flod ); + lod = Q_ftol(flod); if ( lod < 0 ) { @@ -297,7 +295,7 @@ void R_AddMD3Surfaces( trRefEntity_t *ent ) { qboolean personalModel; // don't add third_person objects if not in a portal - personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal; + personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !(tr.viewParms.isPortal || tr.viewParms.isShadowmap); if ( ent->e.renderfx & RF_WRAP_FRAMES ) { ent->e.frame %= tr.currentModel->mdv[0]->numFrames; @@ -396,7 +394,7 @@ void R_AddMD3Surfaces( trRefEntity_t *ent ) { // don't add third_person objects if not viewing through a portal if(!personalModel) { - R_AddDrawSurf((void *)vboSurface, shader, fogNum, qfalse ); + R_AddDrawSurf((void *)vboSurface, shader, fogNum, qfalse, qfalse ); } } else @@ -409,7 +407,7 @@ void R_AddMD3Surfaces( trRefEntity_t *ent ) { && fogNum == 0 && !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) ) && shader->sort == SS_OPAQUE ) { - R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, qfalse ); + R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, qfalse, qfalse ); } // projection shadows work fine with personal models @@ -417,12 +415,12 @@ void R_AddMD3Surfaces( trRefEntity_t *ent ) { && fogNum == 0 && (ent->e.renderfx & RF_SHADOW_PLANE ) && shader->sort == SS_OPAQUE ) { - R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse ); + R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse, qfalse ); } // don't add third_person objects if not viewing through a portal if ( !personalModel ) { - R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse ); + R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse, qfalse ); } } @@ -432,3 +430,4 @@ void R_AddMD3Surfaces( trRefEntity_t *ent ) { } + diff --git a/reaction/code/renderer/tr_model.c b/reaction/code/renderer/tr_model.c index 6424f6b1..784b9134 100644 --- a/reaction/code/renderer/tr_model.c +++ b/reaction/code/renderer/tr_model.c @@ -25,13 +25,195 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define LL(x) x=LittleLong(x) -static qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, int bufferSize, const char *modName ); -static qboolean R_LoadMD4 (model_t *mod, void *buffer, const char *name ); +static qboolean R_LoadMD3(model_t *mod, int lod, void *buffer, int bufferSize, const char *modName); +static qboolean R_LoadMD4(model_t *mod, void *buffer, const char *name ); #ifdef RAVENMD4 -static qboolean R_LoadMDR (model_t *mod, void *buffer, int filesize, const char *name ); +static qboolean R_LoadMDR(model_t *mod, void *buffer, int filesize, const char *name ); #endif -model_t *loadmodel; +/* +==================== +R_RegisterMD3 +==================== +*/ +qhandle_t R_RegisterMD3(const char *name, model_t *mod) +{ + union { + unsigned *u; + void *v; + } buf; + int size; + int lod; + int ident; + qboolean loaded = qfalse; + int numLoaded; + char filename[MAX_QPATH], namebuf[MAX_QPATH+20]; + char *fext, defex[] = "md3"; + + numLoaded = 0; + + strcpy(filename, name); + + fext = strchr(filename, '.'); + if(!fext) + fext = defex; + else + { + *fext = '\0'; + fext++; + } + + for (lod = MD3_MAX_LODS - 1 ; lod >= 0 ; lod--) + { + if(lod) + Com_sprintf(namebuf, sizeof(namebuf), "%s_%d.%s", filename, lod, fext); + else + Com_sprintf(namebuf, sizeof(namebuf), "%s.%s", filename, fext); + + size = ri.FS_ReadFile( namebuf, &buf.v ); + if(!buf.u) + continue; + + ident = LittleLong(* (unsigned *) buf.u); + if (ident == MD4_IDENT) + loaded = R_LoadMD4(mod, buf.u, name); + else + { + if (ident == MD3_IDENT) + loaded = R_LoadMD3(mod, lod, buf.u, size, name); + else + ri.Printf(PRINT_WARNING,"R_RegisterMD3: unknown fileid for %s\n", name); + } + + ri.FS_FreeFile(buf.v); + + if(loaded) + { + mod->numLods++; + numLoaded++; + } + else + break; + } + + if(numLoaded) + { + // duplicate into higher lod spots that weren't + // loaded, in case the user changes r_lodbias on the fly + for(lod--; lod >= 0; lod--) + { + mod->numLods++; + mod->mdv[lod] = mod->mdv[lod + 1]; + } + + return mod->index; + } + +#ifdef _DEBUG + ri.Printf(PRINT_WARNING,"R_RegisterMD3: couldn't load %s\n", name); +#endif + + mod->type = MOD_BAD; + return 0; +} + +#ifdef RAVENMD4 +/* +==================== +R_RegisterMDR +==================== +*/ +qhandle_t R_RegisterMDR(const char *name, model_t *mod) +{ + union { + unsigned *u; + void *v; + } buf; + int ident; + qboolean loaded = qfalse; + int filesize; + + filesize = ri.FS_ReadFile(name, (void **) &buf.v); + if(!buf.u) + { + mod->type = MOD_BAD; + return 0; + } + + ident = LittleLong(*(unsigned *)buf.u); + if(ident == MDR_IDENT) + loaded = R_LoadMDR(mod, buf.u, filesize, name); + + ri.FS_FreeFile (buf.v); + + if(!loaded) + { + ri.Printf(PRINT_WARNING,"R_RegisterMDR: couldn't load mdr file %s\n", name); + mod->type = MOD_BAD; + return 0; + } + + return mod->index; +} +#endif + +/* +==================== +R_RegisterIQM +==================== +*/ +qhandle_t R_RegisterIQM(const char *name, model_t *mod) +{ + union { + unsigned *u; + void *v; + } buf; + qboolean loaded = qfalse; + int filesize; + + filesize = ri.FS_ReadFile(name, (void **) &buf.v); + if(!buf.u) + { + mod->type = MOD_BAD; + return 0; + } + + loaded = R_LoadIQM(mod, buf.u, filesize, name); + + ri.FS_FreeFile (buf.v); + + if(!loaded) + { + ri.Printf(PRINT_WARNING,"R_RegisterIQM: couldn't load iqm file %s\n", name); + mod->type = MOD_BAD; + return 0; + } + + return mod->index; +} + + +typedef struct +{ + char *ext; + qhandle_t (*ModelLoader)( const char *, model_t * ); +} modelExtToLoaderMap_t; + +// Note that the ordering indicates the order of preference used +// when there are multiple models of different formats available +static modelExtToLoaderMap_t modelLoaders[ ] = +{ + { "iqm", R_RegisterIQM }, +#ifdef RAVENMD4 + { "mdr", R_RegisterMDR }, +#endif + { "md4", R_RegisterMD3 }, + { "md3", R_RegisterMD3 } +}; + +static int numModelLoaders = ARRAY_LEN(modelLoaders); + +//=============================================================================== /* ** R_GetModelByHandle @@ -83,16 +265,13 @@ asked for again. */ qhandle_t RE_RegisterModel( const char *name ) { model_t *mod; - union { - unsigned *u; - void *v; - } buf; - int lod; - int ident; - qboolean loaded = qfalse; qhandle_t hModel; - int numLoaded; - char *fext, defex[] = "md3", filename[MAX_QPATH], namebuf[MAX_QPATH+20]; + qboolean orgNameFailed = qfalse; + int orgLoader = -1; + int i; + char localName[ MAX_QPATH ]; + const char *ext; + char altName[ MAX_QPATH ]; if ( !name || !name[0] ) { ri.Printf( PRINT_ALL, "RE_RegisterModel: NULL name\n" ); @@ -131,127 +310,75 @@ qhandle_t RE_RegisterModel( const char *name ) { // make sure the render thread is stopped R_SyncRenderThread(); + mod->type = MOD_BAD; mod->numLods = 0; // // load the files // - numLoaded = 0; + Q_strncpyz( localName, name, MAX_QPATH ); - strcpy(filename, name); + ext = COM_GetExtension( localName ); - fext = strchr(filename, '.'); - if(!fext) - fext = defex; - else + if( *ext ) { - *fext = '\0'; - fext++; - } - -#ifdef RAVENMD4 - if(!Q_stricmp(fext, "mdr")) - { - int filesize; - - filesize = ri.FS_ReadFile(name, (void **) &buf.v); - if(!buf.u) + // Look for the correct loader and use it + for( i = 0; i < numModelLoaders; i++ ) { - ri.Printf (PRINT_WARNING,"RE_RegisterModel: couldn't load %s\n", name); - mod->type = MOD_BAD; - return 0; - } - - ident = LittleLong(*(unsigned *)buf.u); - if(ident == MDR_IDENT) - loaded = R_LoadMDR(mod, buf.u, filesize, name); - - ri.FS_FreeFile (buf.v); - - if(!loaded) - { - ri.Printf(PRINT_WARNING,"RE_RegisterModel: couldn't load mdr file %s\n", name); - mod->type = MOD_BAD; - return 0; - } - - return mod->index; - } -#endif - - fext = defex; - - for ( lod = MD3_MAX_LODS - 1 ; lod >= 0 ; lod-- ) { - int bufferSize; - - if ( lod ) - Com_sprintf(namebuf, sizeof(namebuf), "%s_%d.%s", filename, lod, fext); - else - Com_sprintf(namebuf, sizeof(namebuf), "%s.%s", filename, fext); - - bufferSize = ri.FS_ReadFile( namebuf, &buf.v ); - if ( !buf.u ) { - continue; - } - - loadmodel = mod; - - ident = LittleLong(*(unsigned *)buf.u); - if ( ident == MD4_IDENT ) { - loaded = R_LoadMD4( mod, buf.u, name ); - } else { - if ( ident != MD3_IDENT ) { - ri.Printf (PRINT_WARNING,"RE_RegisterModel: unknown fileid for %s\n", name); - goto fail; - } - - loaded = R_LoadMD3( mod, lod, buf.u, bufferSize, name ); - } - - ri.FS_FreeFile (buf.v); - - if ( !loaded ) { - if ( lod == 0 ) { - goto fail; - } else { + if( !Q_stricmp( ext, modelLoaders[ i ].ext ) ) + { + // Load + hModel = modelLoaders[ i ].ModelLoader( localName, mod ); break; } - } else { - mod->numLods++; - numLoaded++; - // if we have a valid model and are biased - // so that we won't see any higher detail ones, - // stop loading them -// if ( lod <= r_lodbias->integer ) { -// break; -// } + } + + // A loader was found + if( i < numModelLoaders ) + { + if( !hModel ) + { + // Loader failed, most likely because the file isn't there; + // try again without the extension + orgNameFailed = qtrue; + orgLoader = i; + COM_StripExtension( name, localName, MAX_QPATH ); + } + else + { + // Something loaded + return mod->index; + } } } - if ( numLoaded ) { - // duplicate into higher lod spots that weren't - // loaded, in case the user changes r_lodbias on the fly - for ( lod-- ; lod >= 0 ; lod-- ) { - mod->numLods++; - mod->mdv[lod] = mod->mdv[lod+1]; + // Try and find a suitable match using all + // the model formats supported + for( i = 0; i < numModelLoaders; i++ ) + { + if (i == orgLoader) + continue; + + Com_sprintf( altName, sizeof (altName), "%s.%s", localName, modelLoaders[ i ].ext ); + + // Load + hModel = modelLoaders[ i ].ModelLoader( altName, mod ); + + if( hModel ) + { + if( orgNameFailed ) + { + ri.Printf( PRINT_DEVELOPER, "WARNING: %s not present, using %s instead\n", + name, altName ); + } + + break; } - - return mod->index; } -#ifdef _DEBUG - else { - ri.Printf (PRINT_WARNING,"RE_RegisterModel: couldn't load %s\n", name); - } -#endif -fail: - // we still keep the model_t around, so if the model name is asked for - // again, we won't bother scanning the filesystem - mod->type = MOD_BAD; - return 0; + return hModel; } - /* ================= R_LoadMD3 @@ -377,13 +504,15 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, if(md3Surf->numVerts > SHADER_MAX_VERTEXES) { - ri.Error(ERR_DROP, "R_LoadMD3: %s has more than %i verts on a surface (%i)", + ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has more than %i verts on a surface (%i)", modName, SHADER_MAX_VERTEXES, md3Surf->numVerts); + return qfalse; } if(md3Surf->numTriangles * 3 > SHADER_MAX_INDEXES) { - ri.Error(ERR_DROP, "R_LoadMD3: %s has more than %i triangles on a surface (%i)", + ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has more than %i triangles on a surface (%i)", modName, SHADER_MAX_INDEXES / 3, md3Surf->numTriangles); + return qfalse; } // change to surface identifier @@ -447,16 +576,13 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, md3xyz = (md3XyzNormal_t *) ((byte *) md3Surf + md3Surf->ofsXyzNormals); for(j = 0; j < md3Surf->numVerts * md3Surf->numFrames; j++, md3xyz++, v++) { -#if 0 unsigned lat, lng; unsigned short normal; -#endif v->xyz[0] = LittleShort(md3xyz->xyz[0]) * MD3_XYZ_SCALE; v->xyz[1] = LittleShort(md3xyz->xyz[1]) * MD3_XYZ_SCALE; v->xyz[2] = LittleShort(md3xyz->xyz[2]) * MD3_XYZ_SCALE; -#if 0 normal = LittleShort(md3xyz->normal); lat = ( normal >> 8 ) & 0xff; @@ -471,7 +597,6 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, v->normal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; v->normal[1] = tr.sinTable[lat] * tr.sinTable[lng]; v->normal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; -#endif } // swap all the ST @@ -496,7 +621,8 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, { VectorClear(v->tangent); VectorClear(v->bitangent); - VectorClear(v->normal); + if (r_recalcMD3Normals->integer) + VectorClear(v->normal); } for(f = 0; f < mdvModel->numFrames; f++) @@ -511,6 +637,9 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, t1 = surf->st[tri->indexes[1]].st; t2 = surf->st[tri->indexes[2]].st; + if (!r_recalcMD3Normals->integer) + VectorCopy(v->normal, normal); + #if 1 R_CalcTangentSpace(tangent, bitangent, normal, v0, v1, v2, t0, t1, t2); #else @@ -528,8 +657,11 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, v = surf->verts[surf->numVerts * f + tri->indexes[k]].bitangent; VectorAdd(v, bitangent, v); - v = surf->verts[surf->numVerts * f + tri->indexes[k]].normal; - VectorAdd(v, normal, v); + if (r_recalcMD3Normals->integer) + { + v = surf->verts[surf->numVerts * f + tri->indexes[k]].normal; + VectorAdd(v, normal, v); + } } } } @@ -653,7 +785,7 @@ static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char { int i, j, k, l; mdrHeader_t *pinmodel, *mdr; - mdrFrame_t *frame; + mdrFrame_t *frame; mdrLOD_t *lod, *curlod; mdrSurface_t *surf, *cursurf; mdrTriangle_t *tri, *curtri; @@ -705,7 +837,7 @@ static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char } mod->dataSize += size; - mod->md4 = mdr = ri.Hunk_Alloc( size, h_low ); + mod->modelData = mdr = ri.Hunk_Alloc( size, h_low ); // Copy all the values over from the file and fix endian issues in the process, if necessary. @@ -849,13 +981,13 @@ static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char // now do the checks that may fail. if ( surf->numVerts > SHADER_MAX_VERTEXES ) { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i verts on a surface (%i)", + ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i verts on a surface (%i).\n", mod_name, SHADER_MAX_VERTEXES, surf->numVerts ); return qfalse; } if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i triangles on a surface (%i)", + ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i triangles on a surface (%i).\n", mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles ); return qfalse; } @@ -1014,7 +1146,7 @@ static qboolean R_LoadMD4( model_t *mod, void *buffer, const char *mod_name ) { mod->type = MOD_MD4; size = LittleLong(pinmodel->ofsEnd); mod->dataSize += size; - md4 = mod->md4 = ri.Hunk_Alloc( size, h_low ); + mod->modelData = md4 = ri.Hunk_Alloc( size, h_low ); Com_Memcpy(md4, buffer, size); @@ -1064,12 +1196,14 @@ static qboolean R_LoadMD4( model_t *mod, void *buffer, const char *mod_name ) { LL(surf->ofsEnd); if ( surf->numVerts > SHADER_MAX_VERTEXES ) { - ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i verts on a surface (%i)", + ri.Printf(PRINT_WARNING, "R_LoadMD4: %s has more than %i verts on a surface (%i).\n", mod_name, SHADER_MAX_VERTEXES, surf->numVerts ); + return qfalse; } if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) { - ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i triangles on a surface (%i)", + ri.Printf(PRINT_WARNING, "R_LoadMD4: %s has more than %i triangles on a surface (%i).\n", mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles ); + return qfalse; } // change to surface identifier @@ -1269,7 +1403,7 @@ void R_GetAnimTag( mdrHeader_t *mod, int framenum, const char *tagName, md3Tag_t // uncompressed model... // - frameSize = (long)( &((mdrFrame_t *)0)->bones[ mod->numBones ] ); + frameSize = (intptr_t)( &((mdrFrame_t *)0)->bones[ mod->numBones ] ); frame = (mdrFrame_t *)((byte *)mod + mod->ofsFrames + framenum * frameSize ); for (j = 0; j < 3; j++) @@ -1311,16 +1445,20 @@ int R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFram if ( !model->mdv[0] ) { #ifdef RAVENMD4 - if(model->md4) + if(model->type == MOD_MDR) { start = &start_space; end = &end_space; - R_GetAnimTag((mdrHeader_t *) model->md4, startFrame, tagName, start); - R_GetAnimTag((mdrHeader_t *) model->md4, endFrame, tagName, end); + R_GetAnimTag((mdrHeader_t *) model->modelData, startFrame, tagName, start); + R_GetAnimTag((mdrHeader_t *) model->modelData, endFrame, tagName, end); } else #endif - { + if( model->type == MOD_IQM ) { + return R_IQMLerpTag( tag, model->modelData, + startFrame, endFrame, + frac, tagName ); + } else { AxisClear( tag->axis ); VectorClear( tag->origin ); @@ -1362,29 +1500,62 @@ R_ModelBounds */ void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ) { model_t *model; - mdvModel_t *mdvModel; - mdvFrame_t *frame; model = R_GetModelByHandle( handle ); - if ( model->bmodel ) { + if(model->type == MOD_BRUSH) { VectorCopy( model->bmodel->bounds[0], mins ); VectorCopy( model->bmodel->bounds[1], maxs ); + return; + } else if (model->type == MOD_MESH) { + mdvModel_t *header; + mdvFrame_t *frame; + + header = model->mdv[0]; + frame = header->frames; + + VectorCopy( frame->bounds[0], mins ); + VectorCopy( frame->bounds[1], maxs ); + + return; + } else if (model->type == MOD_MD4) { + md4Header_t *header; + md4Frame_t *frame; + + header = (md4Header_t *)model->modelData; + frame = (md4Frame_t *) ((byte *)header + header->ofsFrames); + + VectorCopy( frame->bounds[0], mins ); + VectorCopy( frame->bounds[1], maxs ); + + return; +#ifdef RAVENMD4 + } else if (model->type == MOD_MDR) { + mdrHeader_t *header; + mdrFrame_t *frame; + + header = (mdrHeader_t *)model->modelData; + frame = (mdrFrame_t *) ((byte *)header + header->ofsFrames); + + VectorCopy( frame->bounds[0], mins ); + VectorCopy( frame->bounds[1], maxs ); + + return; +#endif + } else if(model->type == MOD_IQM) { + iqmData_t *iqmData; + + iqmData = model->modelData; + + if(iqmData->bounds) + { + VectorCopy(iqmData->bounds, mins); + VectorCopy(iqmData->bounds + 3, maxs); + return; + } } - if ( !model->mdv[0] ) { - VectorClear( mins ); - VectorClear( maxs ); - return; - } - - mdvModel = model->mdv[0]; - - frame = mdvModel->frames; - - VectorCopy( frame->bounds[0], mins ); - VectorCopy( frame->bounds[1], maxs ); + VectorClear( mins ); + VectorClear( maxs ); } - - diff --git a/reaction/code/renderer/tr_public.h b/reaction/code/renderer/tr_public.h index c6846a97..38c49ec1 100644 --- a/reaction/code/renderer/tr_public.h +++ b/reaction/code/renderer/tr_public.h @@ -147,7 +147,7 @@ typedef struct { // a -1 return means the file does not exist // NULL can be passed for buf to just determine existance int (*FS_FileIsInPAK)( const char *name, int *pCheckSum ); - int (*FS_ReadFile)( const char *name, void **buf ); + long (*FS_ReadFile)( const char *name, void **buf ); void (*FS_FreeFile)( void *buf ); char ** (*FS_ListFiles)( const char *name, const char *extension, int *numfilesfound ); void (*FS_FreeFileList)( char **filelist ); diff --git a/reaction/code/renderer/tr_scene.c b/reaction/code/renderer/tr_scene.c index 0cda7115..14105603 100644 --- a/reaction/code/renderer/tr_scene.c +++ b/reaction/code/renderer/tr_scene.c @@ -108,7 +108,7 @@ void R_AddPolygonSurfaces( void ) { for ( i = 0, poly = tr.refdef.polys; i < tr.refdef.numPolys ; i++, poly++ ) { sh = R_GetShaderByHandle( poly->hShader ); - R_AddDrawSurf( ( void * )poly, sh, poly->fogIndex & fogMask, qfalse ); + R_AddDrawSurf( ( void * )poly, sh, poly->fogIndex & fogMask, qfalse, qfalse ); } } @@ -384,6 +384,9 @@ void RE_RenderScene( const refdef_t *fd ) { tr.refdef.numPolys = r_numpolys - r_firstScenePoly; tr.refdef.polys = &backEndData[tr.smpFrame]->polys[r_firstScenePoly]; + tr.refdef.num_pshadows = 0; + tr.refdef.pshadows = &backEndData[tr.smpFrame]->pshadows[0]; + // turn off dynamic lighting globally by clearing all the // dlights if it needs to be disabled or if vertex lighting is enabled if ( r_dynamiclight->integer == 0 || @@ -400,6 +403,22 @@ void RE_RenderScene( const refdef_t *fd ) { tr.frameSceneNum++; tr.sceneCount++; + // SmileTheory: playing with shadow mapping + if (!( fd->rdflags & RDF_NOWORLDMODEL ) && tr.refdef.num_dlights && r_dlightShadows->integer + && glRefConfig.vertexBufferObject && r_arb_vertex_buffer_object->integer + && glRefConfig.glsl && r_arb_shader_objects->integer) + { + R_RenderDlightCubemaps(fd); + } + + /* playing with more shadows */ + if(!( fd->rdflags & RDF_NOWORLDMODEL ) && r_shadows->integer == 4 + && glRefConfig.vertexBufferObject && r_arb_vertex_buffer_object->integer + && glRefConfig.glsl && r_arb_shader_objects->integer) + { + R_RenderPshadowMaps(fd); + } + // setup view parms for the initial view // // set up viewport diff --git a/reaction/code/renderer/tr_shade.c b/reaction/code/renderer/tr_shade.c index f6b3c08b..15fe74b6 100644 --- a/reaction/code/renderer/tr_shade.c +++ b/reaction/code/renderer/tr_shade.c @@ -261,7 +261,7 @@ static void R_BindAnimatedImageToTMU( textureBundle_t *bundle, int tmu ) { // it is necessary to do this messy calc to make sure animations line up // exactly with waveforms of the same frequency - index = myftol( tess.shaderTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE ); + index = Q_ftol(tess.shaderTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE); index >>= FUNCTABLE_SIZE2; if ( index < 0 ) { @@ -399,6 +399,7 @@ void RB_BeginSurface( shader_t *shader, int fogNum ) { tess.shader = state; tess.fogNum = fogNum; tess.dlightBits = 0; // will be OR'd in by surface functions + tess.pshadowBits = 0; // will be OR'd in by surface functions tess.xstages = state->stages; tess.numPasses = state->numUnfoggedPasses; tess.currentStageIteratorFunc = state->optimalStageIteratorFunc; @@ -408,6 +409,11 @@ void RB_BeginSurface( shader_t *shader, int fogNum ) { if (tess.shader->clampTime && tess.shaderTime >= tess.shader->clampTime) { tess.shaderTime = tess.shader->clampTime; } + + if (backEnd.viewParms.isShadowmap) + { + tess.currentStageIteratorFunc = RB_StageIteratorGenericVBO; + } } @@ -1042,9 +1048,9 @@ static void ProjectDlightTexture_scalar( void ) { } } clipBits[i] = clip; - colors[0] = myftol(floatColor[0] * modulate); - colors[1] = myftol(floatColor[1] * modulate); - colors[2] = myftol(floatColor[2] * modulate); + colors[0] = Q_ftol(floatColor[0] * modulate); + colors[1] = Q_ftol(floatColor[1] * modulate); + colors[2] = Q_ftol(floatColor[2] * modulate); colors[3] = 255; } @@ -1101,16 +1107,22 @@ static void ProjectDlightTexture( void ) { ProjectDlightTexture_scalar(); } +static void ComputeDeformValues(int *deformGen, vec5_t deformParams); + static void ProjectDlightTextureVBOGLSL( void ) { int l; vec3_t origin; float scale; float radius; + int deformGen; + vec5_t deformParams; if ( !backEnd.refdef.num_dlights ) { return; } + ComputeDeformValues(&deformGen, deformParams); + for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) { dlight_t *dl; shaderProgram_t *sp; @@ -1135,46 +1147,11 @@ static void ProjectDlightTextureVBOGLSL( void ) { GLSL_SetUniformFloat(sp, DLIGHT_UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); - // u_DeformGen - if(!ShaderRequiresCPUDeforms(tess.shader)) + GLSL_SetUniformInt(sp, DLIGHT_UNIFORM_DEFORMGEN, deformGen); + if (deformGen != DGEN_NONE) { - deformStage_t *ds; - - // only support the first one - ds = &tess.shader->deforms[0]; - - switch (ds->deformation) - { - case DEFORM_WAVE: - GLSL_SetUniformInt(sp, DLIGHT_UNIFORM_DEFORMGEN, ds->deformationWave.func); - { - vec4_t v; - waveForm_t *wf = &ds->deformationWave; - VectorSet4(v, wf->base, wf->amplitude, wf->phase, wf->frequency); - GLSL_SetUniformVec4(sp, DLIGHT_UNIFORM_DEFORMWAVE, v); - } - GLSL_SetUniformFloat(sp, DLIGHT_UNIFORM_DEFORMSPREAD, ds->deformationSpread); - GLSL_SetUniformFloat(sp, DLIGHT_UNIFORM_TIME, tess.shaderTime); - break; - - case DEFORM_BULGE: - GLSL_SetUniformInt(sp, DLIGHT_UNIFORM_DEFORMGEN, DGEN_BULGE); - { - vec3_t v; - VectorSet(v, ds->bulgeWidth, ds->bulgeHeight, ds->bulgeSpeed); - GLSL_SetUniformVec3(sp, DLIGHT_UNIFORM_DEFORMBULGE, v); - } - GLSL_SetUniformFloat(sp, DLIGHT_UNIFORM_TIME, tess.shaderTime); - break; - - default: - GLSL_SetUniformInt(sp, DLIGHT_UNIFORM_DEFORMGEN, DGEN_NONE); - break; - } - } - else - { - GLSL_SetUniformInt(sp, DLIGHT_UNIFORM_DEFORMGEN, DGEN_NONE); + GLSL_SetUniformFloat5(sp, DLIGHT_UNIFORM_DEFORMPARAMS, deformParams); + GLSL_SetUniformFloat(sp, DLIGHT_UNIFORM_TIME, tess.shaderTime); } vector[0] = dl->color[0]; @@ -1215,7 +1192,82 @@ static void ProjectDlightTextureVBOGLSL( void ) { } -static void ComputeHelperColor( shaderStage_t *pStage, vec4_t color); +static qboolean ComputeHelperColor( shaderStage_t *pStage, vec4_t color); + +static void ComputeFogValues(vec4_t fogDistanceVector, vec4_t fogDepthVector, float *eyeT) +{ + // from RB_CalcFogTexCoords() + fog_t *fog; + vec3_t local; + + if (!tess.fogNum) + return; + + fog = tr.world->fogs + tess.fogNum; + + VectorSubtract( backEnd.or.origin, backEnd.viewParms.or.origin, local ); + fogDistanceVector[0] = -backEnd.or.modelMatrix[2]; + fogDistanceVector[1] = -backEnd.or.modelMatrix[6]; + fogDistanceVector[2] = -backEnd.or.modelMatrix[10]; + fogDistanceVector[3] = DotProduct( local, backEnd.viewParms.or.axis[0] ); + + // scale the fog vectors based on the fog's thickness + VectorScale4(fogDistanceVector, fog->tcScale, fogDistanceVector); + + // rotate the gradient vector for this orientation + if ( fog->hasSurface ) { + fogDepthVector[0] = fog->surface[0] * backEnd.or.axis[0][0] + + fog->surface[1] * backEnd.or.axis[0][1] + fog->surface[2] * backEnd.or.axis[0][2]; + fogDepthVector[1] = fog->surface[0] * backEnd.or.axis[1][0] + + fog->surface[1] * backEnd.or.axis[1][1] + fog->surface[2] * backEnd.or.axis[1][2]; + fogDepthVector[2] = fog->surface[0] * backEnd.or.axis[2][0] + + fog->surface[1] * backEnd.or.axis[2][1] + fog->surface[2] * backEnd.or.axis[2][2]; + fogDepthVector[3] = -fog->surface[3] + DotProduct( backEnd.or.origin, fog->surface ); + + *eyeT = DotProduct( backEnd.or.viewOrigin, fogDepthVector ) + fogDepthVector[3]; + } else { + *eyeT = 1; // non-surface fog always has eye inside + } +} + +static void ComputeDeformValues(int *deformGen, vec5_t deformParams) +{ + // u_DeformGen + *deformGen = DGEN_NONE; + if(!ShaderRequiresCPUDeforms(tess.shader)) + { + deformStage_t *ds; + + // only support the first one + ds = &tess.shader->deforms[0]; + + switch (ds->deformation) + { + case DEFORM_WAVE: + *deformGen = ds->deformationWave.func; + + deformParams[0] = ds->deformationWave.base; + deformParams[1] = ds->deformationWave.amplitude; + deformParams[2] = ds->deformationWave.phase; + deformParams[3] = ds->deformationWave.frequency; + deformParams[4] = ds->deformationSpread; + break; + + case DEFORM_BULGE: + *deformGen = DGEN_BULGE; + + deformParams[0] = 0; + deformParams[1] = ds->bulgeHeight; // amplitude + deformParams[2] = ds->bulgeWidth; // phase + deformParams[3] = ds->bulgeSpeed; // frequency + deformParams[4] = 0; + break; + + default: + break; + } + } +} static void ForwardDlightVBOGLSL( void ) { int l; @@ -1224,12 +1276,10 @@ static void ForwardDlightVBOGLSL( void ) { float radius; int deformGen; - vec4_t deformWave; - vec3_t deformBulge; - float deformSpread; + vec5_t deformParams; vec4_t fogDistanceVector, fogDepthVector = {0, 0, 0, 0}; - float eyeT; + float eyeT = 0; shaderCommands_t *input = &tess; shaderStage_t *pStage = tess.xstages[0]; @@ -1238,74 +1288,15 @@ static void ForwardDlightVBOGLSL( void ) { return; } - // u_DeformGen - deformGen = DGEN_NONE; - if(!ShaderRequiresCPUDeforms(input->shader)) - { - deformStage_t *ds; + ComputeDeformValues(&deformGen, deformParams); - // only support the first one - ds = &input->shader->deforms[0]; - - switch (ds->deformation) - { - case DEFORM_WAVE: - deformGen = ds->deformationWave.func; - { - waveForm_t *wf = &ds->deformationWave; - - VectorSet4(deformWave, wf->base, wf->amplitude, wf->phase, wf->frequency); - } - deformSpread = ds->deformationSpread; - break; - - case DEFORM_BULGE: - deformGen = DGEN_BULGE; - VectorSet(deformBulge, ds->bulgeWidth, ds->bulgeHeight, ds->bulgeSpeed); - break; - - default: - break; - } - } - - if ( input->fogNum ) { - fog_t *fog; - vec3_t local; - - fog = tr.world->fogs + tess.fogNum; - - VectorSubtract( backEnd.or.origin, backEnd.viewParms.or.origin, local ); - fogDistanceVector[0] = -backEnd.or.modelMatrix[2]; - fogDistanceVector[1] = -backEnd.or.modelMatrix[6]; - fogDistanceVector[2] = -backEnd.or.modelMatrix[10]; - fogDistanceVector[3] = DotProduct( local, backEnd.viewParms.or.axis[0] ); - - // scale the fog vectors based on the fog's thickness - VectorScale4(fogDistanceVector, fog->tcScale, fogDistanceVector); - - // rotate the gradient vector for this orientation - if ( fog->hasSurface ) { - fogDepthVector[0] = fog->surface[0] * backEnd.or.axis[0][0] + - fog->surface[1] * backEnd.or.axis[0][1] + fog->surface[2] * backEnd.or.axis[0][2]; - fogDepthVector[1] = fog->surface[0] * backEnd.or.axis[1][0] + - fog->surface[1] * backEnd.or.axis[1][1] + fog->surface[2] * backEnd.or.axis[1][2]; - fogDepthVector[2] = fog->surface[0] * backEnd.or.axis[2][0] + - fog->surface[1] * backEnd.or.axis[2][1] + fog->surface[2] * backEnd.or.axis[2][2]; - fogDepthVector[3] = -fog->surface[3] + DotProduct( backEnd.or.origin, fog->surface ); - - eyeT = DotProduct( backEnd.or.viewOrigin, fogDepthVector ) + fogDepthVector[3]; - } else { - eyeT = 1; // non-surface fog always has eye inside - } - } + ComputeFogValues(fogDistanceVector, fogDepthVector, &eyeT); for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) { dlight_t *dl; shaderProgram_t *sp; vec4_t vector; - - qboolean setcolor; + matrix_t matrix; if ( !( tess.dlightBits & ( 1 << l ) ) ) { continue; // this surface definately doesn't have any of this light @@ -1318,7 +1309,12 @@ static void ForwardDlightVBOGLSL( void ) { //if (pStage->glslShaderGroup == tr.lightallShader) { - sp = &tr.lightallShader[pStage->glslShaderIndex & ~(LIGHTDEF_USE_LIGHTMAP | LIGHTDEF_USE_DELUXEMAP)]; + int index = pStage->glslShaderIndex; + + index &= ~(LIGHTDEF_USE_LIGHTMAP | LIGHTDEF_USE_DELUXEMAP); + index |= LIGHTDEF_USE_LIGHT_VECTOR; + + sp = &tr.lightallShader[index]; } backEnd.pc.c_lightallDraws++; @@ -1329,63 +1325,27 @@ static void ForwardDlightVBOGLSL( void ) { GLSL_SetUniformVec3(sp, GENERIC_UNIFORM_VIEWORIGIN, backEnd.or.viewOrigin); GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); - + GLSL_SetUniformInt(sp, GENERIC_UNIFORM_DEFORMGEN, deformGen); - switch(deformGen) + if (deformGen != DGEN_NONE) { - case DGEN_WAVE_SIN: - case DGEN_WAVE_SQUARE: - case DGEN_WAVE_TRIANGLE: - case DGEN_WAVE_SAWTOOTH: - case DGEN_WAVE_INVERSE_SAWTOOTH: - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_DEFORMWAVE, deformWave); - GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_DEFORMSPREAD, deformSpread); - GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_TIME, tess.shaderTime); - break; - case DGEN_BULGE: - GLSL_SetUniformVec3(sp, GENERIC_UNIFORM_DEFORMBULGE, deformBulge); - GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_TIME, tess.shaderTime); - break; - default: - break; + GLSL_SetUniformFloat5(sp, GENERIC_UNIFORM_DEFORMPARAMS, deformParams); + GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_TIME, tess.shaderTime); } if ( input->fogNum ) { GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_FOGDISTANCE, fogDistanceVector); GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_FOGDEPTH, fogDepthVector); GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_FOGEYET, eyeT); + GLSL_SetUniformInt(sp, GENERIC_UNIFORM_FOGADJUSTCOLORS, pStage->adjustColorsForFog); } - - switch (pStage->rgbGen) + else { - case CGEN_EXACT_VERTEX: - case CGEN_LIGHTING_DIFFUSE: - break; - default: - setcolor = qtrue; + GLSL_SetUniformInt(sp, GENERIC_UNIFORM_FOGADJUSTCOLORS, 0); } - switch (pStage->alphaGen) - { - case AGEN_LIGHTING_SPECULAR: - case AGEN_VERTEX: - case AGEN_ONE_MINUS_VERTEX: - case AGEN_PORTAL: - case AGEN_FRESNEL: - break; - default: - setcolor = qtrue; - } - - if (setcolor) - { - vec4_t color; - - VectorSet4(color, 1.0f, 1.0f, 1.0f, 1.0f); - - ComputeHelperColor (pStage, color); - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_COLOR, color); - } + if (ComputeHelperColor(pStage, vector)) + GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_COLOR, vector); if (pStage->alphaGen == AGEN_PORTAL) { @@ -1395,15 +1355,6 @@ static void ForwardDlightVBOGLSL( void ) { GLSL_SetUniformInt(sp, GENERIC_UNIFORM_COLORGEN, pStage->rgbGen); GLSL_SetUniformInt(sp, GENERIC_UNIFORM_ALPHAGEN, pStage->alphaGen); - if ( input->fogNum ) - { - GLSL_SetUniformInt(sp, GENERIC_UNIFORM_FOGADJUSTCOLORS, pStage->adjustColorsForFog); - } - else - { - GLSL_SetUniformInt(sp, GENERIC_UNIFORM_FOGADJUSTCOLORS, 0); - } - GLSL_SetUniformVec3(sp, GENERIC_UNIFORM_DIRECTEDLIGHT, dl->color); VectorSet(vector, 0, 0, 0); @@ -1413,48 +1364,47 @@ static void ForwardDlightVBOGLSL( void ) { vector[3] = 1.0f; GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_LIGHTORIGIN, vector); - GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_LIGHTSCALESQR, scale * scale); + GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_LIGHTRADIUS, radius); + + GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_SPECULARREFLECTANCE, pStage->specularReflectance); // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light // where they aren't rendered GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); + Matrix16Identity(matrix); + GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_MODELMATRIX, matrix); + + if (pStage->bundle[TB_DIFFUSEMAP].image[0]) + R_BindAnimatedImageToTMU( &pStage->bundle[TB_DIFFUSEMAP], TB_DIFFUSEMAP); + + if (pStage->bundle[TB_NORMALMAP].image[0]) + R_BindAnimatedImageToTMU( &pStage->bundle[TB_NORMALMAP], TB_NORMALMAP); + + if (pStage->bundle[TB_SPECULARMAP].image[0]) + R_BindAnimatedImageToTMU( &pStage->bundle[TB_SPECULARMAP], TB_SPECULARMAP); + + if (r_dlightShadows->integer) { - matrix_t matrix; + GL_SelectTexture(TB_SHADOWMAP); + GL_BindCubemap(tr.shadowCubemaps[l]); + GL_SelectTexture(0); + } - Matrix16Identity(matrix); - GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_MODELMATRIX, matrix); + ComputeTexMatrix( pStage, TB_DIFFUSEMAP, matrix ); + GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_DIFFUSETEXMATRIX, matrix); - if (pStage->bundle[TB_DIFFUSEMAP].image[0]) - R_BindAnimatedImageToTMU( &pStage->bundle[TB_DIFFUSEMAP], TB_DIFFUSEMAP); + // + // draw + // - if (pStage->bundle[TB_NORMALMAP].image[0]) - R_BindAnimatedImageToTMU( &pStage->bundle[TB_NORMALMAP], TB_NORMALMAP); - - if (pStage->bundle[TB_SPECULARMAP].image[0]) - R_BindAnimatedImageToTMU( &pStage->bundle[TB_SPECULARMAP], TB_SPECULARMAP); - - ComputeTexMatrix( pStage, TB_DIFFUSEMAP, matrix ); - GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_DIFFUSETEXMATRIX, matrix); - - //ComputeTexMatrix( pStage, TB_NORMALMAP, matrix ); - //GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_NORMALTEXMATRIX, matrix); - - //ComputeTexMatrix( pStage, TB_SPECULARMAP, matrix ); - //GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_SPECULARTEXMATRIX, matrix); - - // - // draw - // - - if (input->multiDrawPrimitives) - { - R_DrawMultiElementsVBO(input->multiDrawPrimitives, (const GLvoid **)input->multiDrawFirstIndex, input->multiDrawNumIndexes); - } - else - { - R_DrawElementsVBO(input->numIndexes, input->firstIndex); - } + if (input->multiDrawPrimitives) + { + R_DrawMultiElementsVBO(input->multiDrawPrimitives, (const GLvoid **)input->multiDrawFirstIndex, input->multiDrawNumIndexes); + } + else + { + R_DrawElementsVBO(input->numIndexes, input->firstIndex); } backEnd.pc.c_totalIndexes += tess.numIndexes; @@ -1463,6 +1413,83 @@ static void ForwardDlightVBOGLSL( void ) { } +static void ProjectPshadowVBOGLSL( void ) { + int l; + vec3_t origin; + float scale; + float radius; + + int deformGen; + vec5_t deformParams; + + shaderCommands_t *input = &tess; + + if ( !backEnd.refdef.num_pshadows ) { + return; + } + + ComputeDeformValues(&deformGen, deformParams); + + for ( l = 0 ; l < backEnd.refdef.num_pshadows ; l++ ) { + pshadow_t *ps; + shaderProgram_t *sp; + vec4_t vector; + + if ( !( tess.pshadowBits & ( 1 << l ) ) ) { + continue; // this surface definately doesn't have any of this shadow + } + + ps = &backEnd.refdef.pshadows[l]; + VectorCopy( ps->lightOrigin, origin ); + radius = ps->lightRadius; + scale = 1.0f / radius; + + sp = &tr.pshadowShader; + + GLSL_BindProgram(sp); + + GLSL_SetUniformMatrix16(sp, PSHADOW_UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); + + VectorCopy(origin, vector); + vector[3] = 1.0f; + GLSL_SetUniformVec4(sp, PSHADOW_UNIFORM_LIGHTORIGIN, vector); + + VectorScale(ps->lightViewAxis[0], -1.0f / ps->viewRadius, vector); + GLSL_SetUniformVec3(sp, PSHADOW_UNIFORM_LIGHTFORWARD, vector); + + VectorScale(ps->lightViewAxis[1], 1.0f / ps->viewRadius, vector); + GLSL_SetUniformVec3(sp, PSHADOW_UNIFORM_LIGHTUP, vector); + + VectorScale(ps->lightViewAxis[2], -1.0f / ps->viewRadius, vector); + GLSL_SetUniformVec3(sp, PSHADOW_UNIFORM_LIGHTRIGHT, vector); + + GLSL_SetUniformFloat(sp, PSHADOW_UNIFORM_LIGHTRADIUS, radius); + + // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light + // where they aren't rendered + GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL ); + + GL_BindToTMU( tr.pshadowMaps[l], TB_DIFFUSEMAP ); + + // + // draw + // + + if (input->multiDrawPrimitives) + { + R_DrawMultiElementsVBO(input->multiDrawPrimitives, (const GLvoid **)input->multiDrawFirstIndex, input->multiDrawNumIndexes); + } + else + { + R_DrawElementsVBO(input->numIndexes, input->firstIndex); + } + + backEnd.pc.c_totalIndexes += tess.numIndexes; + //backEnd.pc.c_dlightIndexes += tess.numIndexes; + } +} + + /* =================== RB_FogPass @@ -1508,12 +1535,16 @@ Blends a fog texture on top of everything else */ static void RB_FogPassVBOGLSL( void ) { fog_t *fog; - vec3_t local; vec4_t color; vec4_t fogDistanceVector, fogDepthVector = {0, 0, 0, 0}; - float eyeT; + float eyeT = 0; shaderProgram_t *sp = &tr.fogShader; + int deformGen; + vec5_t deformParams; + + ComputeDeformValues(&deformGen, deformParams); + backEnd.pc.c_fogDraws++; GLSL_BindProgram(sp); @@ -1524,46 +1555,11 @@ static void RB_FogPassVBOGLSL( void ) { GLSL_SetUniformFloat(sp, FOGPASS_UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); - // u_DeformGen - if(!ShaderRequiresCPUDeforms(tess.shader)) + GLSL_SetUniformInt(sp, FOGPASS_UNIFORM_DEFORMGEN, deformGen); + if (deformGen != DGEN_NONE) { - deformStage_t *ds; - - // only support the first one - ds = &tess.shader->deforms[0]; - - switch (ds->deformation) - { - case DEFORM_WAVE: - GLSL_SetUniformInt(sp, FOGPASS_UNIFORM_DEFORMGEN, ds->deformationWave.func); - { - vec4_t v; - waveForm_t *wf = &ds->deformationWave; - VectorSet4(v, wf->base, wf->amplitude, wf->phase, wf->frequency); - GLSL_SetUniformVec4(sp, FOGPASS_UNIFORM_DEFORMWAVE, v); - } - GLSL_SetUniformFloat(sp, FOGPASS_UNIFORM_DEFORMSPREAD, ds->deformationSpread); - GLSL_SetUniformFloat(sp, FOGPASS_UNIFORM_TIME, tess.shaderTime); - break; - - case DEFORM_BULGE: - GLSL_SetUniformInt(sp, FOGPASS_UNIFORM_DEFORMGEN, DGEN_BULGE); - { - vec3_t v; - VectorSet(v, ds->bulgeWidth, ds->bulgeHeight, ds->bulgeSpeed); - GLSL_SetUniformVec3(sp, FOGPASS_UNIFORM_DEFORMBULGE, v); - } - GLSL_SetUniformFloat(sp, FOGPASS_UNIFORM_TIME, tess.shaderTime); - break; - - default: - GLSL_SetUniformInt(sp, FOGPASS_UNIFORM_DEFORMGEN, DGEN_NONE); - break; - } - } - else - { - GLSL_SetUniformInt(sp, FOGPASS_UNIFORM_DEFORMGEN, DGEN_NONE); + GLSL_SetUniformFloat5(sp, FOGPASS_UNIFORM_DEFORMPARAMS, deformParams); + GLSL_SetUniformFloat(sp, FOGPASS_UNIFORM_TIME, tess.shaderTime); } color[0] = ((unsigned char *)(&fog->colorInt))[0] / 255.0f; @@ -1572,35 +1568,7 @@ static void RB_FogPassVBOGLSL( void ) { color[3] = ((unsigned char *)(&fog->colorInt))[3] / 255.0f; GLSL_SetUniformVec4(sp, FOGPASS_UNIFORM_COLOR, color); - // from RB_CalcFogTexCoords() - VectorSubtract( backEnd.or.origin, backEnd.viewParms.or.origin, local ); - fogDistanceVector[0] = -backEnd.or.modelMatrix[2]; - fogDistanceVector[1] = -backEnd.or.modelMatrix[6]; - fogDistanceVector[2] = -backEnd.or.modelMatrix[10]; - fogDistanceVector[3] = DotProduct( local, backEnd.viewParms.or.axis[0] ); - - // scale the fog vectors based on the fog's thickness - fogDistanceVector[0] *= fog->tcScale; - fogDistanceVector[1] *= fog->tcScale; - fogDistanceVector[2] *= fog->tcScale; - fogDistanceVector[3] *= fog->tcScale; - - // rotate the gradient vector for this orientation - if ( fog->hasSurface ) { - fogDepthVector[0] = fog->surface[0] * backEnd.or.axis[0][0] + - fog->surface[1] * backEnd.or.axis[0][1] + fog->surface[2] * backEnd.or.axis[0][2]; - fogDepthVector[1] = fog->surface[0] * backEnd.or.axis[1][0] + - fog->surface[1] * backEnd.or.axis[1][1] + fog->surface[2] * backEnd.or.axis[1][2]; - fogDepthVector[2] = fog->surface[0] * backEnd.or.axis[2][0] + - fog->surface[1] * backEnd.or.axis[2][1] + fog->surface[2] * backEnd.or.axis[2][2]; - fogDepthVector[3] = -fog->surface[3] + DotProduct( backEnd.or.origin, fog->surface ); - - eyeT = DotProduct( backEnd.or.viewOrigin, fogDepthVector ) + fogDepthVector[3]; - } else { - eyeT = 1; // non-surface fog always has eye inside - } - - fogDistanceVector[3] += 1.0/512; + ComputeFogValues(fogDistanceVector, fogDepthVector, &eyeT); GLSL_SetUniformVec4(sp, FOGPASS_UNIFORM_FOGDISTANCE, fogDistanceVector); GLSL_SetUniformVec4(sp, FOGPASS_UNIFORM_FOGDEPTH, fogDepthVector); @@ -1843,43 +1811,43 @@ static void ComputeColors( shaderStage_t *pStage ) } } -static void ComputeHelperColor( shaderStage_t *pStage, vec4_t color) +static qboolean ComputeHelperColor( shaderStage_t *pStage, vec4_t color) { + qboolean set = qfalse; + + color[0] = + color[1] = + color[2] = + color[3] = 1.0f; + // // rgbGen // switch ( pStage->rgbGen ) { case CGEN_IDENTITY: - color[0] = 1.0f; - color[1] = 1.0f; - color[2] = 1.0f; - color[3] = 1.0f; + set = qtrue; break; case CGEN_IDENTITY_LIGHTING: - color[0] = tr.identityLight; - color[1] = tr.identityLight; - color[2] = tr.identityLight; + color[0] = + color[1] = + color[2] = color[3] = tr.identityLight; // FIXME: Code was like this in quake 3, is this a bug? - break; - case CGEN_LIGHTING_DIFFUSE: - // Done entirely in vertex program - break; - case CGEN_EXACT_VERTEX: - // Done entirely in vertex program + set = qtrue; break; case CGEN_CONST: color[0] = pStage->constantColor[0] / 255.0f; color[1] = pStage->constantColor[1] / 255.0f; color[2] = pStage->constantColor[2] / 255.0f; color[3] = pStage->constantColor[3] / 255.0f; + set = qtrue; break; case CGEN_VERTEX: case CGEN_ONE_MINUS_VERTEX: - color[0] = tr.identityLight; - color[1] = tr.identityLight; + color[0] = + color[1] = color[2] = tr.identityLight; - color[3] = 1.0f; + set = qtrue; break; case CGEN_FOG: { @@ -1892,6 +1860,7 @@ static void ComputeHelperColor( shaderStage_t *pStage, vec4_t color) color[2] = ((unsigned char *)(&fog->colorInt))[2] / 255.0f; color[3] = ((unsigned char *)(&fog->colorInt))[3] / 255.0f; } + set = qtrue; break; case CGEN_WAVEFORM: { @@ -1912,11 +1881,11 @@ static void ComputeHelperColor( shaderStage_t *pStage, vec4_t color) glow = 1; } - color[0] = glow; - color[1] = glow; + color[0] = + color[1] = color[2] = glow; - color[3] = 1.0f; } + set = qtrue; break; case CGEN_ENTITY: if (backEnd.currentEntity) @@ -1926,13 +1895,7 @@ static void ComputeHelperColor( shaderStage_t *pStage, vec4_t color) color[2] = ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[2] / 255.0f; color[3] = ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[3] / 255.0f; } - else // FIXME: does original quake3 black out vertex colors like this? - { - color[0] = 0.0f; - color[1] = 0.0f; - color[2] = 0.0f; - color[3] = 0.0f; - } + set = qtrue; break; case CGEN_ONE_MINUS_ENTITY: if (backEnd.currentEntity) @@ -1942,15 +1905,11 @@ static void ComputeHelperColor( shaderStage_t *pStage, vec4_t color) color[2] = 1.0f - ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[2] / 255.0f; color[3] = 1.0f - ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[3] / 255.0f; } - else // FIXME: does original quake3 black out vertex colors like this? - { - color[0] = 0.0f; - color[1] = 0.0f; - color[2] = 0.0f; - color[3] = 0.0f; - } + set = qtrue; break; - default: + case CGEN_LIGHTING_DIFFUSE: + case CGEN_EXACT_VERTEX: + case CGEN_BAD: break; } @@ -1959,60 +1918,48 @@ static void ComputeHelperColor( shaderStage_t *pStage, vec4_t color) // switch ( pStage->alphaGen ) { - case AGEN_SKIP: - break; - case AGEN_IDENTITY: - if ( pStage->rgbGen != CGEN_IDENTITY ) { - if ( ( pStage->rgbGen == CGEN_VERTEX && tr.identityLight != 1 ) || - pStage->rgbGen != CGEN_VERTEX ) { - color[3] = 1.0f; - } - } - break; - case AGEN_CONST: - if ( pStage->rgbGen != CGEN_CONST ) { + case AGEN_SKIP: + set = qtrue; + break; + case AGEN_IDENTITY: + color[3] = 1.0f; + set = qtrue; + break; + case AGEN_CONST: color[3] = pStage->constantColor[3] / 255.0f; - } - break; - case AGEN_WAVEFORM: - // From RB_CalcWaveAlpha - { - float glow; - waveForm_t *wf = &pStage->alphaWave; - glow = EvalWaveFormClamped( wf ); - color[3] = glow; - } - break; - case AGEN_LIGHTING_SPECULAR: - // Done entirely in vertex program - // RB_CalcSpecularAlpha( ( unsigned char * ) tess.svars.colors ); - break; - case AGEN_ENTITY: - //RB_CalcAlphaFromEntity( ( unsigned char * ) tess.svars.colors ); - if (backEnd.currentEntity) - { - color[3] = ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[3] / 255.0f; - } - break; - case AGEN_ONE_MINUS_ENTITY: - //RB_CalcAlphaFromOneMinusEntity( ( unsigned char * ) tess.svars.colors ); - if (backEnd.currentEntity) - { - color[3] = 1.0f - ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[3] / 255.0f; - } - break; - case AGEN_VERTEX: - // Done entirely in vertex program - break; - case AGEN_ONE_MINUS_VERTEX: - // Done entirely in vertex program - break; - case AGEN_PORTAL: - // Done entirely in vertex program - break; - case AGEN_FRESNEL: - // Done entirely in vertex program - break; + set = qtrue; + break; + case AGEN_WAVEFORM: + // From RB_CalcWaveAlpha + { + float glow; + waveForm_t *wf = &pStage->alphaWave; + glow = EvalWaveFormClamped( wf ); + color[3] = glow; + } + set = qtrue; + break; + case AGEN_ENTITY: + if (backEnd.currentEntity) + { + color[3] = ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[3] / 255.0f; + } + set = qtrue; + break; + case AGEN_ONE_MINUS_ENTITY: + if (backEnd.currentEntity) + { + color[3] = 1.0f - ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[3] / 255.0f; + } + set = qtrue; + break; + case AGEN_LIGHTING_SPECULAR: + case AGEN_VERTEX: + case AGEN_ONE_MINUS_VERTEX: + case AGEN_PORTAL: + case AGEN_FRESNEL: + // Done entirely in vertex program + break; } // @@ -2034,6 +1981,7 @@ static void ComputeHelperColor( shaderStage_t *pStage, vec4_t color) } #endif + return set; } /* @@ -2462,7 +2410,7 @@ static void ComputeTexCoords( shaderStage_t *pStage ) { break; default: - ri.Error( ERR_DROP, "ERROR: unknown texmod '%d' in shader '%s'\n", pStage->bundle[b].texMods[tm].type, tess.shader->name ); + ri.Error( ERR_DROP, "ERROR: unknown texmod '%d' in shader '%s'", pStage->bundle[b].texMods[tm].type, tess.shader->name ); break; } } @@ -2641,7 +2589,7 @@ static void RB_IterateStagesGenericVBO( shaderCommands_t *input ) } } - +#if 0 static void DrawMultitexturedVBOGLSL( shaderProgram_t *sp, shaderCommands_t *input, int stage ) { shaderStage_t *pStage; matrix_t matrix; @@ -2687,6 +2635,7 @@ static void DrawMultitexturedVBOGLSL( shaderProgram_t *sp, shaderCommands_t *inp R_DrawElementsVBO(input->numIndexes, input->firstIndex); } } +#endif static unsigned int RB_CalcShaderVertexAttribs( shaderCommands_t *input ) { @@ -2711,81 +2660,20 @@ static void RB_IterateStagesGenericVBOGLSL( shaderCommands_t *input ) { int stage; matrix_t matrix; - - int deformGen; - vec4_t deformWave; - vec3_t deformBulge; - float deformSpread; vec4_t fogDistanceVector, fogDepthVector = {0, 0, 0, 0}; - float eyeT; - - // u_DeformGen - deformGen = DGEN_NONE; - if(!ShaderRequiresCPUDeforms(input->shader)) - { - deformStage_t *ds; + float eyeT = 0; - // only support the first one - ds = &input->shader->deforms[0]; + int deformGen; + vec5_t deformParams; - switch (ds->deformation) - { - case DEFORM_WAVE: - deformGen = ds->deformationWave.func; - { - waveForm_t *wf = &ds->deformationWave; + ComputeDeformValues(&deformGen, deformParams); - VectorSet4(deformWave, wf->base, wf->amplitude, wf->phase, wf->frequency); - } - deformSpread = ds->deformationSpread; - break; - - case DEFORM_BULGE: - deformGen = DGEN_BULGE; - VectorSet(deformBulge, ds->bulgeWidth, ds->bulgeHeight, ds->bulgeSpeed); - break; - - default: - break; - } - } - - if ( input->fogNum ) { - fog_t *fog; - vec3_t local; - - fog = tr.world->fogs + tess.fogNum; - - VectorSubtract( backEnd.or.origin, backEnd.viewParms.or.origin, local ); - fogDistanceVector[0] = -backEnd.or.modelMatrix[2]; - fogDistanceVector[1] = -backEnd.or.modelMatrix[6]; - fogDistanceVector[2] = -backEnd.or.modelMatrix[10]; - fogDistanceVector[3] = DotProduct( local, backEnd.viewParms.or.axis[0] ); - - // scale the fog vectors based on the fog's thickness - VectorScale4(fogDistanceVector, fog->tcScale, fogDistanceVector); - - // rotate the gradient vector for this orientation - if ( fog->hasSurface ) { - fogDepthVector[0] = fog->surface[0] * backEnd.or.axis[0][0] + - fog->surface[1] * backEnd.or.axis[0][1] + fog->surface[2] * backEnd.or.axis[0][2]; - fogDepthVector[1] = fog->surface[0] * backEnd.or.axis[1][0] + - fog->surface[1] * backEnd.or.axis[1][1] + fog->surface[2] * backEnd.or.axis[1][2]; - fogDepthVector[2] = fog->surface[0] * backEnd.or.axis[2][0] + - fog->surface[1] * backEnd.or.axis[2][1] + fog->surface[2] * backEnd.or.axis[2][2]; - fogDepthVector[3] = -fog->surface[3] + DotProduct( backEnd.or.origin, fog->surface ); - - eyeT = DotProduct( backEnd.or.viewOrigin, fogDepthVector ) + fogDepthVector[3]; - } else { - eyeT = 1; // non-surface fog always has eye inside - } - } + ComputeFogValues(fogDistanceVector, fogDepthVector, &eyeT); for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ ) { shaderStage_t *pStage = input->xstages[stage]; - qboolean setcolor = qfalse; shaderProgram_t *sp; if ( !pStage ) @@ -2795,7 +2683,12 @@ static void RB_IterateStagesGenericVBOGLSL( shaderCommands_t *input ) if (pStage->glslShaderGroup) { - sp = &pStage->glslShaderGroup[pStage->glslShaderIndex]; + int index = pStage->glslShaderIndex; + if (r_lightmap->integer && index & LIGHTDEF_USE_LIGHTMAP) + { + index = LIGHTDEF_USE_LIGHTMAP; + } + sp = &pStage->glslShaderGroup[index]; if (pStage->glslShaderGroup == tr.lightallShader) { @@ -2817,23 +2710,10 @@ static void RB_IterateStagesGenericVBOGLSL( shaderCommands_t *input ) GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); GLSL_SetUniformInt(sp, GENERIC_UNIFORM_DEFORMGEN, deformGen); - switch(deformGen) + if (deformGen != DGEN_NONE) { - case DGEN_WAVE_SIN: - case DGEN_WAVE_SQUARE: - case DGEN_WAVE_TRIANGLE: - case DGEN_WAVE_SAWTOOTH: - case DGEN_WAVE_INVERSE_SAWTOOTH: - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_DEFORMWAVE, deformWave); - GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_DEFORMSPREAD, deformSpread); - GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_TIME, tess.shaderTime); - break; - case DGEN_BULGE: - GLSL_SetUniformVec3(sp, GENERIC_UNIFORM_DEFORMBULGE, deformBulge); - GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_TIME, tess.shaderTime); - break; - default: - break; + GLSL_SetUniformFloat5(sp, GENERIC_UNIFORM_DEFORMPARAMS, deformParams); + GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_TIME, tess.shaderTime); } if ( input->fogNum ) { @@ -2844,37 +2724,14 @@ static void RB_IterateStagesGenericVBOGLSL( shaderCommands_t *input ) GL_State( pStage->stateBits ); - switch (pStage->rgbGen) - { - case CGEN_EXACT_VERTEX: - case CGEN_LIGHTING_DIFFUSE: - break; - default: - setcolor = qtrue; - } - - switch (pStage->alphaGen) - { - case AGEN_LIGHTING_SPECULAR: - case AGEN_VERTEX: - case AGEN_ONE_MINUS_VERTEX: - case AGEN_PORTAL: - case AGEN_FRESNEL: - break; - default: - setcolor = qtrue; - } - - if (setcolor) { vec4_t color; - VectorSet4(color, 1.0f, 1.0f, 1.0f, 1.0f); - - ComputeHelperColor (pStage, color); - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_COLOR, color); + if (ComputeHelperColor(pStage, color)) + GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_COLOR, color); } + if (pStage->rgbGen == CGEN_LIGHTING_DIFFUSE) { vec4_t vec; @@ -2888,6 +2745,8 @@ static void RB_IterateStagesGenericVBOGLSL( shaderCommands_t *input ) VectorCopy(backEnd.currentEntity->lightDir, vec); vec[3] = 0.0f; GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_LIGHTORIGIN, vec); + + GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_LIGHTRADIUS, 999999.0f); } if (pStage->alphaGen == AGEN_PORTAL) @@ -2907,6 +2766,24 @@ static void RB_IterateStagesGenericVBOGLSL( shaderCommands_t *input ) GLSL_SetUniformInt(sp, GENERIC_UNIFORM_FOGADJUSTCOLORS, 0); } + ComputeTexMatrix( pStage, TB_DIFFUSEMAP, matrix ); + GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_DIFFUSETEXMATRIX, matrix); + + GLSL_SetUniformInt(sp, GENERIC_UNIFORM_TCGEN0, pStage->bundle[0].tcGen); + if (pStage->bundle[0].tcGen == TCGEN_VECTOR) + { + vec3_t vec; + + VectorCopy(pStage->bundle[0].tcGenVectors[0], vec); + GLSL_SetUniformVec3(sp, GENERIC_UNIFORM_TCGEN0VECTOR0, vec); + VectorCopy(pStage->bundle[0].tcGenVectors[1], vec); + GLSL_SetUniformVec3(sp, GENERIC_UNIFORM_TCGEN0VECTOR1, vec); + } + + GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_MODELMATRIX, backEnd.or.transformMatrix); + + GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_SPECULARREFLECTANCE, pStage->specularReflectance); + // // do multitexture // @@ -2914,71 +2791,130 @@ static void RB_IterateStagesGenericVBOGLSL( shaderCommands_t *input ) { int i; - GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_MODELMATRIX, backEnd.or.transformMatrix); - - for (i = 0; i < NUM_TEXTURE_BUNDLES; i++) + if (r_lightmap->integer && pStage->bundle[TB_LIGHTMAP].image[0]) { - if (pStage->bundle[i].image[0]) + for (i = 0; i < NUM_TEXTURE_BUNDLES; i++) { - R_BindAnimatedImageToTMU( &pStage->bundle[i], i); + if (i == TB_LIGHTMAP) + { + R_BindAnimatedImageToTMU( &pStage->bundle[i], i); + } + else if (pStage->bundle[i].image[0]) + { + GL_BindToTMU( tr.whiteImage, i); + } } } - - ComputeTexMatrix( pStage, TB_DIFFUSEMAP, matrix ); - GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_DIFFUSETEXMATRIX, matrix); - - //ComputeTexMatrix( pStage, TB_NORMALMAP, matrix ); - //GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_NORMALTEXMATRIX, matrix); - - //ComputeTexMatrix( pStage, TB_SPECULARMAP, matrix ); - //GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_SPECULARTEXMATRIX, matrix); - - // - // draw - // - - if (input->multiDrawPrimitives) - { - R_DrawMultiElementsVBO(input->multiDrawPrimitives, (const GLvoid **)input->multiDrawFirstIndex, input->multiDrawNumIndexes); - } else { - R_DrawElementsVBO(input->numIndexes, input->firstIndex); + for (i = 0; i < NUM_TEXTURE_BUNDLES; i++) + { + if (pStage->bundle[i].image[0]) + { + R_BindAnimatedImageToTMU( &pStage->bundle[i], i); + } + } } } else if ( pStage->bundle[1].image[0] != 0 ) { - DrawMultitexturedVBOGLSL( sp, input, stage ); + R_BindAnimatedImageToTMU( &pStage->bundle[0], 0 ); + + // + // lightmap/secondary pass + // + if ( r_lightmap->integer ) { + GLSL_SetUniformInt(sp, GENERIC_UNIFORM_TEXTURE1ENV, GL_REPLACE); + } else { + GLSL_SetUniformInt(sp, GENERIC_UNIFORM_TEXTURE1ENV, tess.shader->multitextureEnv); + } + + R_BindAnimatedImageToTMU( &pStage->bundle[1], 1 ); } else { - GLSL_SetUniformInt(sp, GENERIC_UNIFORM_TCGEN0, pStage->bundle[0].tcGen); - if (pStage->bundle[0].tcGen == TCGEN_VECTOR) - { - vec4_t vector; - - VectorCopy(pStage->bundle[0].tcGenVectors[0], vector); - vector[3] = 0.0f; - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_TCGEN0VECTOR0, vector); - VectorCopy(pStage->bundle[0].tcGenVectors[1], vector); - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_TCGEN0VECTOR1, vector); - } - - ComputeTexMatrix( pStage, 0, matrix ); - GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_DIFFUSETEXMATRIX, matrix); - // // set state // if ( pStage->bundle[0].vertexLightmap && ( (r_vertexLight->integer && !r_uiFullScreen->integer) || glConfig.hardwareType == GLHW_PERMEDIA2 ) && r_lightmap->integer ) { - GL_Bind( tr.whiteImage ); + GL_BindToTMU( tr.whiteImage, 0 ); } else - R_BindAnimatedImage( &pStage->bundle[0] ); + R_BindAnimatedImageToTMU( &pStage->bundle[0], 0 ); GLSL_SetUniformInt(sp, GENERIC_UNIFORM_TEXTURE1ENV, 0); + } + // + // draw + // + if (input->multiDrawPrimitives) + { + R_DrawMultiElementsVBO(input->multiDrawPrimitives, (const GLvoid **)input->multiDrawFirstIndex, input->multiDrawNumIndexes); + } + else + { + R_DrawElementsVBO(input->numIndexes, input->firstIndex); + } + + // allow skipping out to show just lightmaps during development + if ( r_lightmap->integer && ( pStage->bundle[0].isLightmap || pStage->bundle[1].isLightmap || pStage->bundle[0].vertexLightmap ) ) + { + break; + } + } +} + + +static void RB_RenderShadowmap( shaderCommands_t *input ) +{ + int deformGen; + vec5_t deformParams; + + ComputeDeformValues(&deformGen, deformParams); + + { + shaderProgram_t *sp = &tr.shadowmapShader; + + vec4_t vector; + + GLSL_BindProgram(sp); + + GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); + + if (backEnd.currentEntity && backEnd.currentEntity != &tr.worldEntity) + { + GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_MODELMATRIX, backEnd.or.transformMatrix); + } + else + { + matrix_t matrix; + Matrix16Identity(matrix); + GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_MODELMATRIX, matrix); + } + + GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); + + GLSL_SetUniformInt(sp, GENERIC_UNIFORM_DEFORMGEN, deformGen); + if (deformGen != DGEN_NONE) + { + GLSL_SetUniformFloat5(sp, GENERIC_UNIFORM_DEFORMPARAMS, deformParams); + GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_TIME, tess.shaderTime); + } + + VectorCopy(backEnd.viewParms.or.origin, vector); + vector[3] = 1.0f; + GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_LIGHTORIGIN, vector); + GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_LIGHTRADIUS, backEnd.viewParms.zFar); + + GL_State( 0 ); + + // + // do multitexture + // + //if ( pStage->glslShaderGroup ) + { // // draw // @@ -2992,12 +2928,6 @@ static void RB_IterateStagesGenericVBOGLSL( shaderCommands_t *input ) R_DrawElementsVBO(input->numIndexes, input->firstIndex); } } - - // allow skipping out to show just lightmaps during development - if ( r_lightmap->integer && ( pStage->bundle[0].isLightmap || pStage->bundle[1].isLightmap || pStage->bundle[0].vertexLightmap ) ) - { - break; - } } } @@ -3183,6 +3113,26 @@ void RB_StageIteratorGenericVBO( void ) } + // + // render shadowmap if in shadowmap mode + // + if (backEnd.viewParms.isShadowmap) + { + if ( glRefConfig.glsl && r_arb_shader_objects->integer && input->shader->sort == SS_OPAQUE ) + { + RB_RenderShadowmap( input ); + } + // + // reset polygon offset + // + if ( input->shader->polygonOffset ) + { + qglDisable( GL_POLYGON_OFFSET_FILL ); + } + + return; + } + // // call shader function // @@ -3195,6 +3145,18 @@ void RB_StageIteratorGenericVBO( void ) RB_IterateStagesGenericVBO( input ); } + // + // pshadows! + // + if ( tess.pshadowBits && tess.shader->sort <= SS_OPAQUE + && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) ) { + if (glRefConfig.glsl && r_arb_shader_objects->integer) + { + ProjectPshadowVBOGLSL(); + } + } + + // // now do any dynamic lighting needed // @@ -3507,3 +3469,4 @@ void RB_EndSurface( void ) { } + diff --git a/reaction/code/renderer/tr_shade_calc.c b/reaction/code/renderer/tr_shade_calc.c index 984556d8..897696de 100644 --- a/reaction/code/renderer/tr_shade_calc.c +++ b/reaction/code/renderer/tr_shade_calc.c @@ -27,7 +27,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #endif -#define WAVEVALUE( table, base, amplitude, phase, freq ) ((base) + table[ myftol( ( ( (phase) + tess.shaderTime * (freq) ) * FUNCTABLE_SIZE ) ) & FUNCTABLE_MASK ] * (amplitude)) +#define WAVEVALUE( table, base, amplitude, phase, freq ) ((base) + table[ Q_ftol( ( ( (phase) + tess.shaderTime * (freq) ) * FUNCTABLE_SIZE ) ) & FUNCTABLE_MASK ] * (amplitude)) static float *TableForFunc( genFunc_t func ) { @@ -48,7 +48,7 @@ static float *TableForFunc( genFunc_t func ) break; } - ri.Error( ERR_DROP, "TableForFunc called with invalid function '%d' in shader '%s'\n", func, tess.shader->name ); + ri.Error( ERR_DROP, "TableForFunc called with invalid function '%d' in shader '%s'", func, tess.shader->name ); return NULL; } @@ -728,7 +728,7 @@ void RB_CalcWaveColor( const waveForm_t *wf, unsigned char *dstColors ) glow = 1; } - v = myftol( 255 * glow ); + v = Q_ftol(255 * glow); color[0] = color[1] = color[2] = v; color[3] = 255; v = *(int *)color; @@ -1121,23 +1121,6 @@ void RB_CalcRotateTexMatrix( float degsPerSecond, float *matrix ) RB_CalcTransformTexMatrix( &tmi, matrix ); } - - - - - - -#if id386 && !defined(__GNUC__) - -long myftol( float f ) { - static int tmp; - __asm fld f - __asm fistp tmp - __asm mov eax, tmp -} - -#endif - /* ** RB_CalcSpecularAlpha ** @@ -1300,19 +1283,19 @@ static void RB_CalcDiffuseColor_scalar( unsigned char *colors ) *(int *)&colors[i*4] = ambientLightInt; continue; } - j = myftol( ambientLight[0] + incoming * directedLight[0] ); + j = Q_ftol(ambientLight[0] + incoming * directedLight[0]); if ( j > 255 ) { j = 255; } colors[i*4+0] = j; - j = myftol( ambientLight[1] + incoming * directedLight[1] ); + j = Q_ftol(ambientLight[1] + incoming * directedLight[1]); if ( j > 255 ) { j = 255; } colors[i*4+1] = j; - j = myftol( ambientLight[2] + incoming * directedLight[2] ); + j = Q_ftol(ambientLight[2] + incoming * directedLight[2]); if ( j > 255 ) { j = 255; } @@ -1335,3 +1318,4 @@ void RB_CalcDiffuseColor( unsigned char *colors ) } + diff --git a/reaction/code/renderer/tr_shader.c b/reaction/code/renderer/tr_shader.c index df8cf40a..ecc35dbe 100644 --- a/reaction/code/renderer/tr_shader.c +++ b/reaction/code/renderer/tr_shader.c @@ -363,7 +363,7 @@ static void ParseTexMod( char *_text, shaderStage_t *stage ) texModInfo_t *tmi; if ( stage->bundle[0].numTexMods == TR_MAX_TEXMODS ) { - ri.Error( ERR_DROP, "ERROR: too many tcMod stages in shader '%s'\n", shader.name ); + ri.Error( ERR_DROP, "ERROR: too many tcMod stages in shader '%s'", shader.name ); return; } @@ -842,6 +842,7 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) else if(!Q_stricmp(token, "specularMap")) { stage->type = ST_SPECULARMAP; + stage->specularReflectance = 0.04f; } else { @@ -850,6 +851,19 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) } } // + // specularReflectance + // + else if (!Q_stricmp(token, "specularreflectance")) + { + token = COM_ParseExt(text, qfalse); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing parameter for specular reflectance in shader '%s'\n", shader.name ); + continue; + } + stage->specularReflectance = atof( token ); + } + // // rgbGen // else if ( !Q_stricmp( token, "rgbGen" ) ) @@ -1845,9 +1859,14 @@ static void ComputeVertexAttribs(void) break; } - if (pStage->glslShaderGroup) + if (pStage->glslShaderGroup == tr.lightallShader) { - shader.vertexAttribs |= ATTR_NORMAL | ATTR_BITANGENT | ATTR_TANGENT; + shader.vertexAttribs |= ATTR_NORMAL; + + if (pStage->glslShaderIndex & LIGHTDEF_USE_NORMALMAP) + { + shader.vertexAttribs |= ATTR_BITANGENT | ATTR_TANGENT; + } } for (i = 0; i < NUM_TEXTURE_BUNDLES; i++) @@ -1881,7 +1900,7 @@ static void ComputeVertexAttribs(void) case CGEN_ONE_MINUS_VERTEX: shader.vertexAttribs |= ATTR_COLOR; break; - + case CGEN_LIGHTING_DIFFUSE: shader.vertexAttribs |= ATTR_NORMAL; break; @@ -2107,12 +2126,13 @@ static void CollapseStagesToLightall(shaderStage_t *diffuse, { //ri.Printf(PRINT_ALL, ", specularmap %s", specular->bundle[0].image[0]->imgName); diffuse->bundle[TB_SPECULARMAP] = specular->bundle[0]; + diffuse->specularReflectance = specular->specularReflectance; defs |= LIGHTDEF_USE_SPECULARMAP; } if (!isWorld) { - defs |= LIGHTDEF_ENTITY; + defs |= LIGHTDEF_ENTITY | LIGHTDEF_USE_LIGHT_VECTOR; } if (environment) @@ -2138,6 +2158,31 @@ static qboolean CollapseStagesToGLSL(void) skip = qtrue; } + if (!skip) + { + // if 2+ stages and first stage is lightmap, switch them + // this makes it easier for the later bits to process + if (stages[0].active && stages[0].bundle[0].isLightmap && stages[1].active) + { + int blendBits = stages[1].stateBits & ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS ); + + if (blendBits == (GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO) + || blendBits == (GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR)) + { + int stateBits0 = stages[0].stateBits; + int stateBits1 = stages[1].stateBits; + shaderStage_t swapStage; + + swapStage = stages[0]; + stages[0] = stages[1]; + stages[1] = swapStage; + + stages[0].stateBits = stateBits0; + stages[1].stateBits = stateBits1; + } + } + } + if (!skip) { // scan for shaders that aren't supported @@ -2148,7 +2193,7 @@ static qboolean CollapseStagesToGLSL(void) if (!pStage->active) continue; - if (pStage->bundle[0].isLightmap && i != 0) + if (pStage->bundle[0].isLightmap) { int blendBits = pStage->stateBits & ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS ); @@ -2156,6 +2201,7 @@ static qboolean CollapseStagesToGLSL(void) && blendBits != (GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR)) { skip = qtrue; + break; } } @@ -2198,19 +2244,21 @@ static qboolean CollapseStagesToGLSL(void) if (!skip) { - qboolean processedColormap = qfalse; - for (i = 0; i < MAX_SHADER_STAGES; i++) { shaderStage_t *pStage = &stages[i]; shaderStage_t *diffuse, *normal, *specular, *lightmap; - qboolean parallax, environment; - int stateBits; + qboolean parallax, environment, world; if (!pStage->active) continue; - if (pStage->type != ST_COLORMAP) // same as diffusemap and lightmap + // skip normal and specular maps + if (pStage->type != ST_COLORMAP) + continue; + + // skip lightmaps + if (pStage->bundle[0].isLightmap) continue; diffuse = NULL; @@ -2219,15 +2267,7 @@ static qboolean CollapseStagesToGLSL(void) specular = NULL; lightmap = NULL; - if (pStage->bundle[0].isLightmap) - { - // stop processing if we've already done all the previous colormaps - if (processedColormap) - break; - - lightmap = pStage; - } - + // find matching normal, specular, and lightmap for this diffuse stage for (j = i + 1; j < MAX_SHADER_STAGES; j++) { shaderStage_t *pStage2 = &stages[j]; @@ -2235,66 +2275,43 @@ static qboolean CollapseStagesToGLSL(void) if (!pStage2->active) continue; - if (pStage2->type == ST_NORMALMAP && !normal) + switch(pStage2->type) { - normal = pStage2; - continue; - } - - if (pStage2->type == ST_NORMALPARALLAXMAP && !normal) - { - normal = pStage2; - parallax = qtrue; - continue; - } - - if (pStage2->type == ST_SPECULARMAP && !specular) - { - specular = pStage2; - continue; - } - - if (pStage2->type != ST_COLORMAP) // same as diffusemap and lightmap - continue; - - // stop if - // - we hit another diffusemap after a lightmap - // - we hit the lightmap - if (lightmap) - { - if (pStage2->bundle[0].isLightmap) - { - // wtf? two lightmaps in one shader? - ri.Printf(PRINT_WARNING, "Found two lightmap passes in shader %s\n", shader.name); + case ST_NORMALMAP: + if (!normal) + { + normal = pStage2; + } break; - } - diffuse = pStage2; - break; - } - else if (pStage2->bundle[0].isLightmap) - { - lightmap = pStage2; - break; + case ST_NORMALPARALLAXMAP: + if (!normal) + { + normal = pStage2; + parallax = qtrue; + } + break; + + case ST_SPECULARMAP: + if (!specular) + { + specular = pStage2; + } + break; + + case ST_COLORMAP: + if (pStage2->bundle[0].isLightmap) + { + lightmap = pStage2; + } + break; + + default: + break; } } - if (lightmap == pStage) - { - // after light map - - // deal with two lightmap stages problem - if (!diffuse) - break; - - stateBits = lightmap->stateBits; - } - else - { - // before light map - diffuse = pStage; - stateBits = diffuse->stateBits; - } + diffuse = pStage; environment = qfalse; if (diffuse->bundle[0].tcGen == TCGEN_ENVIRONMENT_MAPPED) @@ -2302,21 +2319,13 @@ static qboolean CollapseStagesToGLSL(void) environment = qtrue; } + world = qtrue; if (diffuse->rgbGen == CGEN_LIGHTING_DIFFUSE) { - CollapseStagesToLightall(diffuse, normal, specular, NULL, qfalse, parallax, environment); - } - else if (lightmap) - { - CollapseStagesToLightall(diffuse, normal, specular, lightmap, qtrue, parallax, environment); + world = qfalse; } - processedColormap = qtrue; - - diffuse->stateBits = stateBits; - - if (lightmap == pStage) - break; + CollapseStagesToLightall(diffuse, normal, specular, lightmap, world, parallax, environment); } // deactivate lightmap stages @@ -2400,6 +2409,8 @@ static void FixRenderCommandList( int newShader ) { const void *curCmd = cmdList->cmds; while ( 1 ) { + curCmd = PADP(curCmd, sizeof(void *)); + switch ( *(const int *)curCmd ) { case RC_SET_COLOR: { @@ -2421,15 +2432,16 @@ static void FixRenderCommandList( int newShader ) { int fogNum; int entityNum; int dlightMap; + int pshadowMap; int sortedIndex; const drawSurfsCommand_t *ds_cmd = (const drawSurfsCommand_t *)curCmd; for( i = 0, drawSurf = ds_cmd->drawSurfs; i < ds_cmd->numDrawSurfs; i++, drawSurf++ ) { - R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlightMap ); + R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlightMap, &pshadowMap ); sortedIndex = (( drawSurf->sort >> QSORT_SHADERNUM_SHIFT ) & (MAX_SHADERS-1)); if( sortedIndex >= newShader ) { sortedIndex++; - drawSurf->sort = (sortedIndex << QSORT_SHADERNUM_SHIFT) | entityNum | ( fogNum << QSORT_FOGNUM_SHIFT ) | (int)dlightMap; + drawSurf->sort = (sortedIndex << QSORT_SHADERNUM_SHIFT) | entityNum | ( fogNum << QSORT_FOGNUM_SHIFT ) | ( (int)pshadowMap << QSORT_PSHADOW_SHIFT) | (int)dlightMap; } } curCmd = (const void *)(ds_cmd + 1); diff --git a/reaction/code/renderer/tr_sky.c b/reaction/code/renderer/tr_sky.c index c76d3c88..9f56adf2 100644 --- a/reaction/code/renderer/tr_sky.c +++ b/reaction/code/renderer/tr_sky.c @@ -387,15 +387,16 @@ static void DrawSkySide( struct image_s *image, const int mins[2], const int max static void DrawSkySideVBO( struct image_s *image, const int mins[2], const int maxs[2] ) { int s, t; - //int firstVertex = tess.numVertexes; + int firstVertex = tess.numVertexes; //int firstIndex = tess.numIndexes; vec4_t color; - tess.numVertexes = 0; - tess.numIndexes = 0; - tess.firstIndex = 0; + //tess.numVertexes = 0; + //tess.numIndexes = 0; + tess.firstIndex = tess.numIndexes; GL_Bind( image ); + GL_Cull( CT_TWO_SIDED ); for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t <= maxs[1]+HALF_SKY_SUBDIVISIONS; t++ ) { @@ -427,13 +428,13 @@ static void DrawSkySideVBO( struct image_s *image, const int mins[2], const int ri.Error(ERR_DROP, "SHADER_MAX_INDEXES hit in DrawSkySideVBO()\n"); } - tess.indexes[tess.numIndexes++] = s + t * (maxs[0] - mins[0] + 1); - tess.indexes[tess.numIndexes++] = s + (t + 1) * (maxs[0] - mins[0] + 1); - tess.indexes[tess.numIndexes++] = (s + 1) + t * (maxs[0] - mins[0] + 1); + tess.indexes[tess.numIndexes++] = s + t * (maxs[0] - mins[0] + 1) + firstVertex; + tess.indexes[tess.numIndexes++] = s + (t + 1) * (maxs[0] - mins[0] + 1) + firstVertex; + tess.indexes[tess.numIndexes++] = (s + 1) + t * (maxs[0] - mins[0] + 1) + firstVertex; - tess.indexes[tess.numIndexes++] = (s + 1) + t * (maxs[0] - mins[0] + 1); - tess.indexes[tess.numIndexes++] = s + (t + 1) * (maxs[0] - mins[0] + 1); - tess.indexes[tess.numIndexes++] = (s + 1) + (t + 1) * (maxs[0] - mins[0] + 1); + tess.indexes[tess.numIndexes++] = (s + 1) + t * (maxs[0] - mins[0] + 1) + firstVertex; + tess.indexes[tess.numIndexes++] = s + (t + 1) * (maxs[0] - mins[0] + 1) + firstVertex; + tess.indexes[tess.numIndexes++] = (s + 1) + (t + 1) * (maxs[0] - mins[0] + 1) + firstVertex; } } @@ -449,8 +450,8 @@ static void DrawSkySideVBO( struct image_s *image, const int mins[2], const int GLSL_SetUniformMatrix16(sp, TEXTURECOLOR_UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - color[0] = tr.identityLight; - color[1] = tr.identityLight; + color[0] = + color[1] = color[2] = tr.identityLight; color[3] = 1.0f; GLSL_SetUniformVec4(sp, TEXTURECOLOR_UNIFORM_COLOR, color); @@ -459,17 +460,18 @@ static void DrawSkySideVBO( struct image_s *image, const int mins[2], const int { qglEnableClientState( GL_VERTEX_ARRAY ); qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); + qglDisableClientState( GL_COLOR_ARRAY ); qglVertexPointer(3, GL_FLOAT, glState.currentVBO->stride_xyz, BUFFER_OFFSET(glState.currentVBO->ofs_xyz)); qglTexCoordPointer( 2, GL_FLOAT, glState.currentVBO->stride_st, BUFFER_OFFSET(glState.currentVBO->ofs_st) ); } - qglDrawElements(GL_TRIANGLES, tess.numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET(tess.firstIndex)); + qglDrawElements(GL_TRIANGLES, tess.numIndexes - tess.firstIndex, GL_INDEX_TYPE, BUFFER_OFFSET(tess.firstIndex * sizeof(GL_INDEX_TYPE))); //R_BindNullVBO(); //R_BindNullIBO(); - tess.numIndexes = 0; - tess.numVertexes = 0; + tess.numIndexes = tess.firstIndex; + tess.numVertexes = firstVertex; tess.firstIndex = 0; } @@ -574,7 +576,7 @@ static void FillCloudySkySide( const int mins[2], const int maxs[2], qboolean ad if ( tess.numVertexes >= SHADER_MAX_VERTEXES ) { - ri.Error( ERR_DROP, "SHADER_MAX_VERTEXES hit in FillCloudySkySide()\n" ); + ri.Error( ERR_DROP, "SHADER_MAX_VERTEXES hit in FillCloudySkySide()" ); } } } @@ -652,10 +654,10 @@ static void FillCloudBox( const shader_t *shader, int stage ) continue; } - sky_mins_subd[0] = myftol( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ); - sky_mins_subd[1] = myftol( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ); - sky_maxs_subd[0] = myftol( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ); - sky_maxs_subd[1] = myftol( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ); + sky_mins_subd[0] = Q_ftol(sky_mins[0][i] * HALF_SKY_SUBDIVISIONS); + sky_mins_subd[1] = Q_ftol(sky_mins[1][i] * HALF_SKY_SUBDIVISIONS); + sky_maxs_subd[0] = Q_ftol(sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS); + sky_maxs_subd[1] = Q_ftol(sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS); if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS ) sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS; @@ -976,3 +978,4 @@ void RB_StageIteratorSky( void ) { } + diff --git a/reaction/code/renderer/tr_surface.c b/reaction/code/renderer/tr_surface.c index e17d48af..0a87dd2a 100644 --- a/reaction/code/renderer/tr_surface.c +++ b/reaction/code/renderer/tr_surface.c @@ -333,7 +333,7 @@ static void RB_SurfacePolychain( srfPoly_t *p ) { tess.numVertexes = numv; } -static void RB_SurfaceHelper( int numVerts, srfVert_t *verts, int numTriangles, srfTriangle_t *triangles, int dlightBits) +static void RB_SurfaceHelper( int numVerts, srfVert_t *verts, int numTriangles, srfTriangle_t *triangles, int dlightBits, int pshadowBits) { int i; srfTriangle_t *tri; @@ -396,11 +396,12 @@ static void RB_SurfaceHelper( int numVerts, srfVert_t *verts, int numTriangles, #endif tess.dlightBits |= dlightBits; + tess.pshadowBits |= pshadowBits; tess.numVertexes += numVerts; } -static qboolean RB_SurfaceHelperVBO(VBO_t *vbo, IBO_t *ibo, int numVerts, int numIndexes, int firstIndex, int dlightBits, qboolean shaderCheck) +static qboolean RB_SurfaceHelperVBO(VBO_t *vbo, IBO_t *ibo, int numVerts, int numIndexes, int firstIndex, int dlightBits, int pshadowBits, qboolean shaderCheck) { if( glRefConfig.vertexBufferObject && r_arb_vertex_buffer_object->integer && vbo && ibo) { @@ -415,6 +416,7 @@ static qboolean RB_SurfaceHelperVBO(VBO_t *vbo, IBO_t *ibo, int numVerts, int nu RB_CheckVBOandIBO(vbo, ibo); tess.dlightBits |= dlightBits; + tess.pshadowBits |= pshadowBits; // merge this into any existing multidraw primitives mergeForward = -1; @@ -501,12 +503,12 @@ RB_SurfaceTriangles ============= */ static void RB_SurfaceTriangles( srfTriangles_t *srf ) { - if( RB_SurfaceHelperVBO (srf->vbo, srf->ibo, srf->numVerts, srf->numTriangles * 3, srf->firstIndex, srf->dlightBits[backEnd.smpFrame], qtrue ) ) + if( RB_SurfaceHelperVBO (srf->vbo, srf->ibo, srf->numVerts, srf->numTriangles * 3, srf->firstIndex, srf->dlightBits[backEnd.smpFrame], srf->pshadowBits[backEnd.smpFrame], qtrue ) ) { return; } - RB_SurfaceHelper(srf->numVerts, srf->verts, srf->numTriangles, srf->triangles, srf->dlightBits[backEnd.smpFrame]); + RB_SurfaceHelper(srf->numVerts, srf->verts, srf->numTriangles, srf->triangles, srf->dlightBits[backEnd.smpFrame], srf->pshadowBits[backEnd.smpFrame]); } @@ -1218,7 +1220,6 @@ static void RB_SurfaceMesh(mdvSurface_t *surface) { indexes = surface->numTriangles * 3; Bob = tess.numIndexes; Doug = tess.numVertexes; - for (j = 0 ; j < surface->numTriangles ; j++) { tess.indexes[Bob + j*3 + 0] = Doug + triangles[j].indexes[0]; tess.indexes[Bob + j*3 + 1] = Doug + triangles[j].indexes[1]; @@ -1246,12 +1247,12 @@ RB_SurfaceFace ============== */ static void RB_SurfaceFace( srfSurfaceFace_t *srf ) { - if( RB_SurfaceHelperVBO (srf->vbo, srf->ibo, srf->numVerts, srf->numTriangles * 3, srf->firstIndex, srf->dlightBits[backEnd.smpFrame], qtrue ) ) + if( RB_SurfaceHelperVBO (srf->vbo, srf->ibo, srf->numVerts, srf->numTriangles * 3, srf->firstIndex, srf->dlightBits[backEnd.smpFrame], srf->pshadowBits[backEnd.smpFrame], qtrue ) ) { return; } - RB_SurfaceHelper(srf->numVerts, srf->verts, srf->numTriangles, srf->triangles, srf->dlightBits[backEnd.smpFrame]); + RB_SurfaceHelper(srf->numVerts, srf->verts, srf->numTriangles, srf->triangles, srf->dlightBits[backEnd.smpFrame], srf->pshadowBits[backEnd.smpFrame]); } @@ -1307,10 +1308,11 @@ static void RB_SurfaceGrid( srfGridMesh_t *srf ) { int lodWidth, lodHeight; int numVertexes; int dlightBits; + int pshadowBits; //int *vDlightBits; qboolean needsNormal; - if( RB_SurfaceHelperVBO (srf->vbo, srf->ibo, srf->numVerts, srf->numTriangles * 3, srf->firstIndex, srf->dlightBits[backEnd.smpFrame], qtrue ) ) + if( RB_SurfaceHelperVBO (srf->vbo, srf->ibo, srf->numVerts, srf->numTriangles * 3, srf->firstIndex, srf->dlightBits[backEnd.smpFrame], srf->pshadowBits[backEnd.smpFrame], qtrue ) ) { return; } @@ -1318,6 +1320,9 @@ static void RB_SurfaceGrid( srfGridMesh_t *srf ) { dlightBits = srf->dlightBits[backEnd.smpFrame]; tess.dlightBits |= dlightBits; + pshadowBits = srf->pshadowBits[backEnd.smpFrame]; + tess.pshadowBits |= pshadowBits; + // determine the allowable discrepance lodError = LodErrorForVolume( srf->lodOrigin, srf->lodRadius ); @@ -1537,7 +1542,7 @@ static void RB_SurfaceFlare(srfFlare_t *surf) static void RB_SurfaceVBOMesh(srfVBOMesh_t * srf) { - RB_SurfaceHelperVBO (srf->vbo, srf->ibo, srf->numVerts, srf->numIndexes, srf->firstIndex, srf->dlightBits[backEnd.smpFrame], qfalse ); + RB_SurfaceHelperVBO (srf->vbo, srf->ibo, srf->numVerts, srf->numIndexes, srf->firstIndex, srf->dlightBits[backEnd.smpFrame], srf->pshadowBits[backEnd.smpFrame], qfalse ); } void RB_SurfaceVBOMDVMesh(srfVBOMDVMesh_t * surface) @@ -1608,6 +1613,7 @@ void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])( void *) = { #ifdef RAVENMD4 (void(*)(void*))RB_MDRSurfaceAnim, // SF_MDR, #endif + (void(*)(void*))RB_IQMSurfaceAnim, // SF_IQM, (void(*)(void*))RB_SurfaceFlare, // SF_FLARE, (void(*)(void*))RB_SurfaceEntity, // SF_ENTITY (void(*)(void*))RB_SurfaceDisplayList, // SF_DISPLAY_LIST diff --git a/reaction/code/renderer/tr_types.h b/reaction/code/renderer/tr_types.h index 37778d04..93bbd6fe 100644 --- a/reaction/code/renderer/tr_types.h +++ b/reaction/code/renderer/tr_types.h @@ -27,6 +27,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define MAX_DLIGHTS 32 // can't be increased, because bit flags are used on surfaces #define MAX_ENTITIES 1023 // can't be increased without changing drawsurf bit packing +#define MAX_CALC_PSHADOWS 64 +#define MAX_DRAWN_PSHADOWS 16 // do not increase past 32, because bit flags are used on surfaces + // renderfx flags #define RF_MINLIGHT 0x0001 // allways have some light (viewmodel, some items) #define RF_THIRD_PERSON 0x0002 // don't draw through eyes, only mirrors (player bodies, chat sprites) diff --git a/reaction/code/renderer/tr_world.c b/reaction/code/renderer/tr_world.c index 443718c9..a1f4f930 100644 --- a/reaction/code/renderer/tr_world.c +++ b/reaction/code/renderer/tr_world.c @@ -40,22 +40,38 @@ static qboolean R_CullSurface( msurface_t *surf ) { { // Only true for SF_FACE, so treat like its own function float d; + cullType_t ct; if ( !r_facePlaneCull->integer ) { return qfalse; } - if (surf->shader->cullType == CT_TWO_SIDED) + ct = surf->shader->cullType; + + if (ct == CT_TWO_SIDED) { return qfalse; } + // shadowmaps draw back surfaces + if ( tr.viewParms.isShadowmap ) + { + if (ct == CT_FRONT_SIDED) + { + ct = CT_BACK_SIDED; + } + else + { + ct = CT_FRONT_SIDED; + } + } + d = DotProduct (tr.or.viewOrigin, surf->cullinfo.plane.normal); // don't cull exactly on the plane, because there are levels of rounding // through the BSP, ICD, and hardware that may cause pixel gaps if an // epsilon isn't allowed here - if ( surf->shader->cullType == CT_FRONT_SIDED ) { + if ( ct == CT_FRONT_SIDED ) { if ( d < surf->cullinfo.plane.dist - 8 ) { return qtrue; } @@ -143,7 +159,8 @@ static int R_DlightSurface( msurface_t *surf, int dlightBits ) { } } } - else if ( surf->cullinfo.type & CULLINFO_BOX ) + + if ( surf->cullinfo.type & CULLINFO_BOX ) { for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) { if ( ! ( dlightBits & ( 1 << i ) ) ) { @@ -162,6 +179,21 @@ static int R_DlightSurface( msurface_t *surf, int dlightBits ) { } } + if ( surf->cullinfo.type & CULLINFO_SPHERE ) + { + for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) { + if ( ! ( dlightBits & ( 1 << i ) ) ) { + continue; + } + dl = &tr.refdef.dlights[i]; + if (!SpheresIntersect(dl->origin, dl->radius, surf->cullinfo.localOrigin, surf->cullinfo.radius)) + { + // dlight doesn't reach the bounds + dlightBits &= ~( 1 << i ); + } + } + } + if ( *surf->data == SF_FACE ) { ((srfSurfaceFace_t *)surf->data)->dlightBits[ tr.smpFrame ] = dlightBits; } else if ( *surf->data == SF_GRID ) { @@ -181,12 +213,97 @@ static int R_DlightSurface( msurface_t *surf, int dlightBits ) { return dlightBits; } + +/* +==================== +R_PshadowSurface + +Just like R_DlightSurface, cull any we can +==================== +*/ +static int R_PshadowSurface( msurface_t *surf, int pshadowBits ) { + float d; + int i; + pshadow_t *ps; + + if ( surf->cullinfo.type & CULLINFO_PLANE ) + { + int i; + for ( i = 0 ; i < tr.refdef.num_pshadows ; i++ ) { + if ( ! ( pshadowBits & ( 1 << i ) ) ) { + continue; + } + ps = &tr.refdef.pshadows[i]; + d = DotProduct( ps->lightOrigin, surf->cullinfo.plane.normal ) - surf->cullinfo.plane.dist; + if ( d < -ps->lightRadius || d > ps->lightRadius ) { + // pshadow doesn't reach the plane + pshadowBits &= ~( 1 << i ); + } + } + } + + if ( surf->cullinfo.type & CULLINFO_BOX ) + { + for ( i = 0 ; i < tr.refdef.num_pshadows ; i++ ) { + if ( ! ( pshadowBits & ( 1 << i ) ) ) { + continue; + } + ps = &tr.refdef.pshadows[i]; + if ( ps->lightOrigin[0] - ps->lightRadius > surf->cullinfo.bounds[1][0] + || ps->lightOrigin[0] + ps->lightRadius < surf->cullinfo.bounds[0][0] + || ps->lightOrigin[1] - ps->lightRadius > surf->cullinfo.bounds[1][1] + || ps->lightOrigin[1] + ps->lightRadius < surf->cullinfo.bounds[0][1] + || ps->lightOrigin[2] - ps->lightRadius > surf->cullinfo.bounds[1][2] + || ps->lightOrigin[2] + ps->lightRadius < surf->cullinfo.bounds[0][2] + || BoxOnPlaneSide(surf->cullinfo.bounds[0], surf->cullinfo.bounds[1], &ps->cullPlane) == 2 ) { + // pshadow doesn't reach the bounds + pshadowBits &= ~( 1 << i ); + } + } + } + + if ( surf->cullinfo.type & CULLINFO_SPHERE ) + { + for ( i = 0 ; i < tr.refdef.num_pshadows ; i++ ) { + if ( ! ( pshadowBits & ( 1 << i ) ) ) { + continue; + } + ps = &tr.refdef.pshadows[i]; + if (!SpheresIntersect(ps->viewOrigin, ps->viewRadius, surf->cullinfo.localOrigin, surf->cullinfo.radius) + || DotProduct( surf->cullinfo.localOrigin, ps->cullPlane.normal ) - ps->cullPlane.dist < -surf->cullinfo.radius) + { + // pshadow doesn't reach the bounds + pshadowBits &= ~( 1 << i ); + } + } + } + + if ( *surf->data == SF_FACE ) { + ((srfSurfaceFace_t *)surf->data)->pshadowBits[ tr.smpFrame ] = pshadowBits; + } else if ( *surf->data == SF_GRID ) { + ((srfGridMesh_t *)surf->data)->pshadowBits[ tr.smpFrame ] = pshadowBits; + } else if ( *surf->data == SF_TRIANGLES ) { + ((srfTriangles_t *)surf->data)->pshadowBits[ tr.smpFrame ] = pshadowBits; + } else if ( *surf->data == SF_VBO_MESH ) { + ((srfVBOMesh_t *)surf->data)->pshadowBits[ tr.smpFrame ] = pshadowBits; + } else { + pshadowBits = 0; + } + + if ( pshadowBits ) { + //tr.pc.c_dlightSurfaces++; + } + + return pshadowBits; +} + + /* ====================== R_AddWorldSurface ====================== */ -static void R_AddWorldSurface( msurface_t *surf, int dlightBits ) { +static void R_AddWorldSurface( msurface_t *surf, int dlightBits, int pshadowBits ) { // FIXME: bmodel fog? // try to cull before dlighting or adding @@ -200,7 +317,13 @@ static void R_AddWorldSurface( msurface_t *surf, int dlightBits ) { dlightBits = ( dlightBits != 0 ); } - R_AddDrawSurf( surf->data, surf->shader, surf->fogIndex, dlightBits ); + // check for pshadows + /*if ( pshadowBits ) */{ + pshadowBits = R_PshadowSurface( surf, pshadowBits); + pshadowBits = ( pshadowBits != 0 ); + } + + R_AddDrawSurf( surf->data, surf->shader, surf->fogIndex, dlightBits, pshadowBits ); } /* @@ -240,7 +363,7 @@ void R_AddBrushModelSurfaces ( trRefEntity_t *ent ) { if (tr.world->surfacesViewCount[surf] != tr.viewCount) { tr.world->surfacesViewCount[surf] = tr.viewCount; - R_AddWorldSurface( tr.world->surfaces + surf, tr.currentEntity->needDlights ); + R_AddWorldSurface( tr.world->surfaces + surf, tr.currentEntity->needDlights, 0 ); } } } @@ -260,10 +383,11 @@ void R_AddBrushModelSurfaces ( trRefEntity_t *ent ) { R_RecursiveWorldNode ================ */ -static void R_RecursiveWorldNode( mnode_t *node, int planeBits, int dlightBits ) { +static void R_RecursiveWorldNode( mnode_t *node, int planeBits, int dlightBits, int pshadowBits ) { do { int newDlights[2]; + unsigned int newPShadows[2]; // if the node wasn't marked as potentially visible, exit if (node->visCounts[tr.visIndex] != tr.visCounts[tr.visIndex]) { @@ -316,6 +440,15 @@ static void R_RecursiveWorldNode( mnode_t *node, int planeBits, int dlightBits ) } } + if ( planeBits & 16 ) { + r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[4]); + if (r == 2) { + return; // culled + } + if ( r == 1 ) { + planeBits &= ~16; // all descendants will also be in front + } + } } if ( node->contents != -1 ) { @@ -349,12 +482,36 @@ static void R_RecursiveWorldNode( mnode_t *node, int planeBits, int dlightBits ) } } + newPShadows[0] = 0; + newPShadows[1] = 0; + if ( pshadowBits ) { + int i; + + for ( i = 0 ; i < tr.refdef.num_pshadows ; i++ ) { + pshadow_t *shadow; + float dist; + + if ( pshadowBits & ( 1 << i ) ) { + shadow = &tr.refdef.pshadows[i]; + dist = DotProduct( shadow->lightOrigin, node->plane->normal ) - node->plane->dist; + + if ( dist > -shadow->lightRadius ) { + newPShadows[0] |= ( 1 << i ); + } + if ( dist < shadow->lightRadius ) { + newPShadows[1] |= ( 1 << i ); + } + } + } + } + // recurse down the children, front side first - R_RecursiveWorldNode (node->children[0], planeBits, newDlights[0] ); + R_RecursiveWorldNode (node->children[0], planeBits, newDlights[0], newPShadows[0] ); // tail recurse node = node->children[1]; dlightBits = newDlights[1]; + pshadowBits = newPShadows[1]; } while ( 1 ); { @@ -397,13 +554,31 @@ static void R_RecursiveWorldNode( mnode_t *node, int planeBits, int dlightBits ) surf = *view; if (surf < 0) { - tr.world->mergedSurfacesViewCount[-surf - 1] = tr.viewCount; - tr.world->mergedSurfacesDlightBits[-surf - 1] = dlightBits; + if (tr.world->mergedSurfacesViewCount[-surf - 1] != tr.viewCount) + { + tr.world->mergedSurfacesViewCount[-surf - 1] = tr.viewCount; + tr.world->mergedSurfacesDlightBits[-surf - 1] = dlightBits; + tr.world->mergedSurfacesPshadowBits[-surf - 1] = pshadowBits; + } + else + { + tr.world->mergedSurfacesDlightBits[-surf - 1] |= dlightBits; + tr.world->mergedSurfacesPshadowBits[-surf - 1] |= pshadowBits; + } } else { - tr.world->surfacesViewCount[surf] = tr.viewCount; - tr.world->surfacesDlightBits[surf] = dlightBits; + if (tr.world->surfacesViewCount[surf] != tr.viewCount) + { + tr.world->surfacesViewCount[surf] = tr.viewCount; + tr.world->surfacesDlightBits[surf] = dlightBits; + tr.world->surfacesPshadowBits[surf] = pshadowBits; + } + else + { + tr.world->surfacesDlightBits[surf] |= dlightBits; + tr.world->surfacesPshadowBits[surf] |= pshadowBits; + } } view++; } @@ -607,18 +782,34 @@ void R_AddWorldSurfaces (void) { if ( tr.refdef.num_dlights > 32 ) { tr.refdef.num_dlights = 32 ; } - R_RecursiveWorldNode( tr.world->nodes, 15, ( 1 << tr.refdef.num_dlights ) - 1 ); + + if ( tr.refdef.num_pshadows > 32 ) { + tr.refdef.num_pshadows = 32 ; + } + + if ( tr.viewParms.isShadowmap) + { + R_RecursiveWorldNode( tr.world->nodes, 31, ( 1 << tr.refdef.num_dlights ) - 1, 0 ); + } + else + { + R_RecursiveWorldNode( tr.world->nodes, 15, ( 1 << tr.refdef.num_dlights ) - 1, ( 1 << tr.refdef.num_pshadows ) - 1 ); + } // now add all the potentially visible surfaces + // also mask invisible dlights for next frame { int i; + tr.refdef.dlightMask = 0; + for (i = 0; i < tr.world->numWorldSurfaces; i++) { if (tr.world->surfacesViewCount[i] != tr.viewCount) continue; - R_AddWorldSurface( tr.world->surfaces + i, tr.world->surfacesDlightBits[i] ); + R_AddWorldSurface( tr.world->surfaces + i, tr.world->surfacesDlightBits[i], tr.world->surfacesPshadowBits[i] ); + tr.refdef.dlightMask |= tr.world->surfacesDlightBits[i]; } for (i = 0; i < tr.world->numMergedSurfaces; i++) @@ -626,7 +817,10 @@ void R_AddWorldSurfaces (void) { if (tr.world->mergedSurfacesViewCount[i] != tr.viewCount) continue; - R_AddWorldSurface( tr.world->mergedSurfaces + i, tr.world->mergedSurfacesDlightBits[i] ); + R_AddWorldSurface( tr.world->mergedSurfaces + i, tr.world->mergedSurfacesDlightBits[i], tr.world->mergedSurfacesPshadowBits[i] ); + tr.refdef.dlightMask |= tr.world->mergedSurfacesDlightBits[i]; } + + tr.refdef.dlightMask = ~tr.refdef.dlightMask; } } diff --git a/reaction/code/sdl/sdl_glimp.c b/reaction/code/sdl/sdl_glimp.c index a1a4e5ba..c5876275 100644 --- a/reaction/code/sdl/sdl_glimp.c +++ b/reaction/code/sdl/sdl_glimp.c @@ -180,6 +180,7 @@ void (APIENTRY * qglUniform1iARB) (GLint location, GLint v0); void (APIENTRY * qglUniform2iARB) (GLint location, GLint v0, GLint v1); void (APIENTRY * qglUniform3iARB) (GLint location, GLint v0, GLint v1, GLint v2); void (APIENTRY * qglUniform4iARB) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +void (APIENTRY * qglUniform1fvARB) (GLint location, GLsizei count, const GLfloat * value); void (APIENTRY * qglUniform2fvARB) (GLint location, GLsizei count, const GLfloat * value); void (APIENTRY * qglUniform3fvARB) (GLint location, GLsizei count, const GLfloat * value); void (APIENTRY * qglUniform4fvARB) (GLint location, GLsizei count, const GLfloat * value); @@ -975,6 +976,7 @@ static void GLimp_InitExtensions( void ) qglUniform2iARB = NULL; qglUniform3iARB = NULL; qglUniform4iARB = NULL; + qglUniform1fvARB = NULL; qglUniform2fvARB = NULL; qglUniform3fvARB = NULL; qglUniform4fvARB = NULL; @@ -1014,6 +1016,7 @@ static void GLimp_InitExtensions( void ) qglUniform2iARB = (PFNGLUNIFORM2IARBPROC) SDL_GL_GetProcAddress("glUniform2iARB"); qglUniform3iARB = (PFNGLUNIFORM3IARBPROC) SDL_GL_GetProcAddress("glUniform3iARB"); qglUniform4iARB = (PFNGLUNIFORM4IARBPROC) SDL_GL_GetProcAddress("glUniform4iARB"); + qglUniform1fvARB = (PFNGLUNIFORM1FVARBPROC) SDL_GL_GetProcAddress("glUniform1fvARB"); qglUniform2fvARB = (PFNGLUNIFORM2FVARBPROC) SDL_GL_GetProcAddress("glUniform2fvARB"); qglUniform3fvARB = (PFNGLUNIFORM3FVARBPROC) SDL_GL_GetProcAddress("glUniform3fvARB"); qglUniform4fvARB = (PFNGLUNIFORM4FVARBPROC) SDL_GL_GetProcAddress("glUniform4fvARB"); @@ -1231,7 +1234,7 @@ void GLimp_Init( void ) } // Nothing worked, give up - ri.Error( ERR_FATAL, "GLimp_Init() - could not load OpenGL subsystem\n" ); + ri.Error( ERR_FATAL, "GLimp_Init() - could not load OpenGL subsystem" ); success: // This values force the UI to disable driver selection diff --git a/reaction/code/sdl/sdl_input.c b/reaction/code/sdl/sdl_input.c index 156bc93b..e89a9b31 100644 --- a/reaction/code/sdl/sdl_input.c +++ b/reaction/code/sdl/sdl_input.c @@ -576,6 +576,7 @@ static void IN_InitJoystick( void ) { int i = 0; int total = 0; + char buf[16384] = ""; if (stick != NULL) SDL_JoystickClose(stick); @@ -583,11 +584,6 @@ static void IN_InitJoystick( void ) stick = NULL; memset(&stick_state, '\0', sizeof (stick_state)); - if( !in_joystick->integer ) { - Com_DPrintf( "Joystick is not active.\n" ); - return; - } - if (!SDL_WasInit(SDL_INIT_JOYSTICK)) { Com_DPrintf("Calling SDL_Init(SDL_INIT_JOYSTICK)...\n"); @@ -601,8 +597,21 @@ static void IN_InitJoystick( void ) total = SDL_NumJoysticks(); Com_DPrintf("%d possible joysticks\n", total); + + // Print list and build cvar to allow ui to select joystick. for (i = 0; i < total; i++) - Com_DPrintf("[%d] %s\n", i, SDL_JoystickName(i)); + { + Q_strcat(buf, sizeof(buf), SDL_JoystickName(i)); + Q_strcat(buf, sizeof(buf), "\n"); + } + + Cvar_Get( "in_availableJoysticks", buf, CVAR_ROM ); + + if( !in_joystick->integer ) { + Com_DPrintf( "Joystick is not active.\n" ); + SDL_QuitSubSystem(SDL_INIT_JOYSTICK); + return; + } in_joystickNo = Cvar_Get( "in_joystickNo", "0", CVAR_ARCHIVE ); if( in_joystickNo->integer < 0 || in_joystickNo->integer >= total ) @@ -964,7 +973,7 @@ void IN_Frame( void ) IN_ProcessEvents( ); // If not DISCONNECTED (main menu) or ACTIVE (in game), we're loading - loading = !!( cls.state != CA_DISCONNECTED && cls.state != CA_ACTIVE ); + loading = !!( clc.state != CA_DISCONNECTED && clc.state != CA_ACTIVE ); if( !r_fullscreen->integer && ( Key_GetCatcher( ) & KEYCATCH_CONSOLE ) ) { @@ -1017,7 +1026,7 @@ void IN_Init( void ) if( !SDL_WasInit( SDL_INIT_VIDEO ) ) { - Com_Error( ERR_FATAL, "IN_Init called before SDL_Init( SDL_INIT_VIDEO )\n" ); + Com_Error( ERR_FATAL, "IN_Init called before SDL_Init( SDL_INIT_VIDEO )" ); return; } @@ -1031,7 +1040,7 @@ void IN_Init( void ) in_joystick = Cvar_Get( "in_joystick", "0", CVAR_ARCHIVE|CVAR_LATCH ); in_joystickDebug = Cvar_Get( "in_joystickDebug", "0", CVAR_TEMP ); - in_joystickThreshold = Cvar_Get( "in_joystickThreshold", "0.15", CVAR_ARCHIVE ); + in_joystickThreshold = Cvar_Get( "joy_threshold", "0.15", CVAR_ARCHIVE ); #ifdef MACOS_X_ACCELERATION_HACK in_disablemacosxmouseaccel = Cvar_Get( "in_disablemacosxmouseaccel", "1", CVAR_ARCHIVE ); diff --git a/reaction/code/server/server.h b/reaction/code/server/server.h index c8e0a8ca..a8ecc6c9 100644 --- a/reaction/code/server/server.h +++ b/reaction/code/server/server.h @@ -274,7 +274,9 @@ extern cvar_t *sv_gametype; extern cvar_t *sv_pure; extern cvar_t *sv_floodProtect; extern cvar_t *sv_lanForceRate; +#ifndef STANDALONE extern cvar_t *sv_strictAuth; +#endif extern cvar_t *sv_banFile; extern cvar_t *sv_heartbeat; extern cvar_t *sv_flatline; diff --git a/reaction/code/server/sv_bot.c b/reaction/code/server/sv_bot.c index 8583f866..704387d3 100644 --- a/reaction/code/server/sv_bot.c +++ b/reaction/code/server/sv_bot.c @@ -304,7 +304,7 @@ BotImport_HunkAlloc */ static void *BotImport_HunkAlloc( int size ) { if( Hunk_CheckMark() ) { - Com_Error( ERR_DROP, "SV_Bot_HunkAlloc: Alloc with marks already set\n" ); + Com_Error( ERR_DROP, "SV_Bot_HunkAlloc: Alloc with marks already set" ); } return Hunk_Alloc( size, h_high ); } diff --git a/reaction/code/server/sv_ccmds.c b/reaction/code/server/sv_ccmds.c index 7684138d..8ddb94dc 100644 --- a/reaction/code/server/sv_ccmds.c +++ b/reaction/code/server/sv_ccmds.c @@ -1220,7 +1220,7 @@ static void SV_DumpUser_f( void ) { } if ( Cmd_Argc() != 2 ) { - Com_Printf ("Usage: info \n"); + Com_Printf ("Usage: dumpuser \n"); return; } diff --git a/reaction/code/server/sv_client.c b/reaction/code/server/sv_client.c index f4ebe60f..32cafee1 100644 --- a/reaction/code/server/sv_client.c +++ b/reaction/code/server/sv_client.c @@ -459,7 +459,7 @@ void SV_DirectConnect( netadr_t from ) { newcl = &svs.clients[sv_maxclients->integer - 1]; } else { - Com_Error( ERR_FATAL, "server is full on local connect\n" ); + Com_Error( ERR_FATAL, "server is full on local connect" ); return; } } @@ -864,7 +864,7 @@ void SV_WriteDownloadToClient( client_t *cl , msg_t *msg ) // Chop off filename extension. Com_sprintf(pakbuf, sizeof(pakbuf), "%s", cl->downloadName); - pakptr = Q_strrchr(pakbuf, '.'); + pakptr = strrchr(pakbuf, '.'); if(pakptr) { @@ -1537,7 +1537,7 @@ static qboolean SV_ClientCommand( client_t *cl, msg_t *msg ) { // the command, we will stop processing the rest of the packet, // including the usercmd. This causes flooders to lag themselves // but not other people - // We don't do this when the client hasn't been active yet since its + // We don't do this when the client hasn't been active yet since it's // normal to spam a lot of commands when downloading if ( !com_cl_running->integer && cl->state >= CS_ACTIVE && diff --git a/reaction/code/server/sv_game.c b/reaction/code/server/sv_game.c index 3f09033d..2909a3b7 100644 --- a/reaction/code/server/sv_game.c +++ b/reaction/code/server/sv_game.c @@ -27,14 +27,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA botlib_export_t *botlib_export; -void SV_GameError( const char *string ) { - Com_Error( ERR_DROP, "%s", string ); -} - -void SV_GamePrint( const char *string ) { - Com_Printf( "%s", string ); -} - // these functions must be used instead of pointer arithmetic, because // the game allocates gentities with private information after the server shared part int SV_NumForGentity( sharedEntity_t *ent ) { @@ -434,7 +426,7 @@ intptr_t SV_GameSystemCalls( intptr_t *args ) { case G_REAL_TIME: return Com_RealTime( VMA(1) ); case G_SNAPVECTOR: - Sys_SnapVector( VMA(1) ); + Q_SnapVector(VMA(1)); return 0; //==================================== @@ -542,7 +534,7 @@ intptr_t SV_GameSystemCalls( intptr_t *args ) { case BOTLIB_EA_ACTION: botlib_export->ea.EA_Action( args[1], args[2] ); - break; + return 0; case BOTLIB_EA_GESTURE: botlib_export->ea.EA_Gesture( args[1] ); return 0; @@ -848,7 +840,7 @@ intptr_t SV_GameSystemCalls( intptr_t *args ) { default: Com_Error( ERR_DROP, "Bad game system trap: %ld", (long int) args[0] ); } - return -1; + return 0; } /* diff --git a/reaction/code/server/sv_init.c b/reaction/code/server/sv_init.c index 39b06a09..14f4dac6 100644 --- a/reaction/code/server/sv_init.c +++ b/reaction/code/server/sv_init.c @@ -108,7 +108,7 @@ void SV_SetConfigstring (int index, const char *val) { client_t *client; if ( index < 0 || index >= MAX_CONFIGSTRINGS ) { - Com_Error (ERR_DROP, "SV_SetConfigstring: bad index %i\n", index); + Com_Error (ERR_DROP, "SV_SetConfigstring: bad index %i", index); } if ( !val ) { @@ -156,7 +156,7 @@ void SV_GetConfigstring( int index, char *buffer, int bufferSize ) { Com_Error( ERR_DROP, "SV_GetConfigstring: bufferSize == %i", bufferSize ); } if ( index < 0 || index >= MAX_CONFIGSTRINGS ) { - Com_Error (ERR_DROP, "SV_GetConfigstring: bad index %i\n", index); + Com_Error (ERR_DROP, "SV_GetConfigstring: bad index %i", index); } if ( !sv.configstrings[index] ) { buffer[0] = 0; @@ -175,7 +175,7 @@ SV_SetUserinfo */ void SV_SetUserinfo( int index, const char *val ) { if ( index < 0 || index >= sv_maxclients->integer ) { - Com_Error (ERR_DROP, "SV_SetUserinfo: bad index %i\n", index); + Com_Error (ERR_DROP, "SV_SetUserinfo: bad index %i", index); } if ( !val ) { @@ -199,7 +199,7 @@ void SV_GetUserinfo( int index, char *buffer, int bufferSize ) { Com_Error( ERR_DROP, "SV_GetUserinfo: bufferSize == %i", bufferSize ); } if ( index < 0 || index >= sv_maxclients->integer ) { - Com_Error (ERR_DROP, "SV_GetUserinfo: bad index %i\n", index); + Com_Error (ERR_DROP, "SV_GetUserinfo: bad index %i", index); } Q_strncpyz( buffer, svs.clients[ index ].userinfo, bufferSize ); } @@ -417,7 +417,7 @@ void SV_SpawnServer( char *server, qboolean killBots ) { CL_MapLoading(); // make sure all the client stuff is unloaded - CL_ShutdownAll(); + CL_ShutdownAll(qfalse); // clear the whole hunk because we're (re)loading the server Hunk_Clear(); @@ -681,7 +681,9 @@ void SV_Init (void) sv_killserver = Cvar_Get ("sv_killserver", "0", 0); sv_mapChecksum = Cvar_Get ("sv_mapChecksum", "", CVAR_ROM); sv_lanForceRate = Cvar_Get ("sv_lanForceRate", "1", CVAR_ARCHIVE ); +#ifndef STANDALONE sv_strictAuth = Cvar_Get ("sv_strictAuth", "1", CVAR_ARCHIVE ); +#endif sv_banFile = Cvar_Get("sv_banFile", "serverbans.dat", CVAR_ARCHIVE); sv_heartbeat = Cvar_Get("sv_heartbeat", HEARTBEAT_FOR_MASTER, CVAR_INIT); sv_flatline = Cvar_Get("sv_flatline", FLATLINE_FOR_MASTER, CVAR_INIT); diff --git a/reaction/code/server/sv_main.c b/reaction/code/server/sv_main.c index e35ec676..1fd85fc0 100644 --- a/reaction/code/server/sv_main.c +++ b/reaction/code/server/sv_main.c @@ -56,7 +56,9 @@ cvar_t *sv_gametype; cvar_t *sv_pure; cvar_t *sv_floodProtect; cvar_t *sv_lanForceRate; // dedicated 1 (LAN) server forces local client rates to 99999 (bug #491) +#ifndef STANDALONE cvar_t *sv_strictAuth; +#endif cvar_t *sv_banFile; cvar_t *sv_heartbeat; // Heartbeat string that is sent to the master cvar_t *sv_flatline; // If the master server supports it we can send a flatline @@ -606,7 +608,7 @@ if a user is interested in a server to do a full status ================ */ void SVC_Info( netadr_t from ) { - int i, count; + int i, count, humans; char *gamedir; char infostring[MAX_INFO_STRING]; @@ -625,10 +627,13 @@ void SVC_Info( netadr_t from ) { return; // don't count privateclients - count = 0; + count = humans = 0; for ( i = sv_privateClients->integer ; i < sv_maxclients->integer ; i++ ) { if ( svs.clients[i].state >= CS_CONNECTED ) { count++; + if (svs.clients[i].netchan.remoteAddress.type != NA_BOT) { + humans++; + } } } @@ -642,10 +647,12 @@ void SVC_Info( netadr_t from ) { Info_SetValueForKey( infostring, "hostname", sv_hostname->string ); Info_SetValueForKey( infostring, "mapname", sv_mapname->string ); Info_SetValueForKey( infostring, "clients", va("%i", count) ); + Info_SetValueForKey(infostring, "g_humanplayers", va("%i", humans)); Info_SetValueForKey( infostring, "sv_maxclients", va("%i", sv_maxclients->integer - sv_privateClients->integer ) ); Info_SetValueForKey( infostring, "gametype", va("%i", sv_gametype->integer ) ); Info_SetValueForKey( infostring, "pure", va("%i", sv_pure->integer ) ); + Info_SetValueForKey(infostring, "g_needpass", va("%d", Cvar_VariableIntegerValue("g_needpass"))); #ifdef USE_VOIP if (sv_voip->integer) { diff --git a/reaction/code/server/sv_net_chan.c b/reaction/code/server/sv_net_chan.c index 5b2f5004..e83f4380 100644 --- a/reaction/code/server/sv_net_chan.c +++ b/reaction/code/server/sv_net_chan.c @@ -139,7 +139,7 @@ void SV_Netchan_TransmitNextFragment( client_t *client ) { { // make sure the netchan queue has been properly initialized (you never know) if ((!client->netchan_end_queue) && (client->state >= CS_CONNECTED)) { - Com_Error(ERR_DROP, "netchan queue is not properly initialized in SV_Netchan_TransmitNextFragment\n"); + Com_Error(ERR_DROP, "netchan queue is not properly initialized in SV_Netchan_TransmitNextFragment"); } // the last fragment was transmitted, check wether we have queued messages if (client->netchan_start_queue) { diff --git a/reaction/code/server/sv_snapshot.c b/reaction/code/server/sv_snapshot.c index 33c61bcd..a2e987d7 100644 --- a/reaction/code/server/sv_snapshot.c +++ b/reaction/code/server/sv_snapshot.c @@ -350,7 +350,7 @@ static void SV_AddEntitiesVisibleFromPoint( vec3_t origin, clientSnapshot_t *fra // entities can be flagged to be sent to a given mask of clients if ( ent->r.svFlags & SVF_CLIENTMASK ) { if (frame->ps.clientNum >= 32) - Com_Error( ERR_DROP, "SVF_CLIENTMASK: clientNum >= 32\n" ); + Com_Error( ERR_DROP, "SVF_CLIENTMASK: clientNum >= 32" ); if (~ent->r.singleClient & (1 << frame->ps.clientNum)) continue; } @@ -412,7 +412,7 @@ static void SV_AddEntitiesVisibleFromPoint( vec3_t origin, clientSnapshot_t *fra // add it SV_AddEntToSnapshot( svEnt, ent, eNums ); - // if its a portal entity, add everything visible from its camera position + // if it's a portal entity, add everything visible from its camera position if ( ent->r.svFlags & SVF_PORTAL ) { if ( ent->s.generic1 ) { vec3_t dir; diff --git a/reaction/code/sys/con_win32.c b/reaction/code/sys/con_win32.c index 83d2eb1a..94ca0b51 100644 --- a/reaction/code/sys/con_win32.c +++ b/reaction/code/sys/con_win32.c @@ -225,7 +225,7 @@ void CON_Init( void ) GetConsoleScreenBufferInfo( qconsole_hout, &info ); qconsole_attrib = info.wAttributes; - SetConsoleTitle("Reaction Dedicated Server Console"); + SetConsoleTitle(CLIENT_WINDOW_TITLE " Dedicated Server Console"); // make cursor invisible GetConsoleCursorInfo( qconsole_hout, &qconsole_orig_cursorinfo ); diff --git a/reaction/code/sys/sys_main.c b/reaction/code/sys/sys_main.c index c30bbf65..1cced2ac 100644 --- a/reaction/code/sys/sys_main.c +++ b/reaction/code/sys/sys_main.c @@ -351,7 +351,7 @@ void Sys_Error( const char *error, ... ) Q_vsnprintf (string, sizeof(string), error, argptr); va_end (argptr); - CL_Shutdown( string ); + CL_Shutdown(string, qtrue); Sys_ErrorDialog( string ); Sys_Exit( 3 ); @@ -412,35 +412,23 @@ void Sys_UnloadDll( void *dllHandle ) Sys_LoadDll Used to load a development dll instead of a virtual machine -#1 look in fs_homepath -#2 look in fs_basepath ================= */ -void *Sys_LoadDll( const char *name, - intptr_t (**entryPoint)(int, ...), - intptr_t (*systemcalls)(intptr_t, ...) ) +void *Sys_LoadDll(const char *name, + intptr_t (QDECL **entryPoint)(int, ...), + intptr_t (*systemcalls)(intptr_t, ...)) { - void *libHandle; - void (*dllEntry)( intptr_t (*syscallptr)(intptr_t, ...) ); - char fname[MAX_OSPATH]; - char *netpath; + void *libHandle; + void (*dllEntry)(intptr_t (*syscallptr)(intptr_t, ...)); - assert( name ); + assert(name); - Com_sprintf(fname, sizeof(fname), "%s" ARCH_STRING DLL_EXT, name); + Com_Printf( "Loading DLL file: %s\n", name); + libHandle = Sys_LoadLibrary(name); - netpath = FS_FindDll(fname); - - if(!netpath) { - Com_Printf( "Sys_LoadDll(%s) could not find it\n", fname ); - return NULL; - } - - Com_Printf( "Loading DLL file: %s\n", netpath); - libHandle = Sys_LoadLibrary(netpath); - - if(!libHandle) { - Com_Printf( "Sys_LoadDll(%s) failed:\n\"%s\"\n", netpath, Sys_LibraryError() ); + if(!libHandle) + { + Com_Printf("Sys_LoadDll(%s) failed:\n\"%s\"\n", name, Sys_LibraryError()); return NULL; } @@ -510,9 +498,9 @@ void Sys_SigHandler( int signal ) { signalcaught = qtrue; #ifndef DEDICATED - CL_Shutdown( va( "Received signal %d", signal ) ); + CL_Shutdown(va("Received signal %d", signal), qtrue); #endif - SV_Shutdown( va( "Received signal %d", signal ) ); + SV_Shutdown(va("Received signal %d", signal) ); } if( signal == SIGTERM || signal == SIGINT ) diff --git a/reaction/code/sys/sys_unix.c b/reaction/code/sys/sys_unix.c index d942e0fc..8ac43f3b 100644 --- a/reaction/code/sys/sys_unix.c +++ b/reaction/code/sys/sys_unix.c @@ -36,6 +36,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include #include #include +#include qboolean stdinIsATTY; @@ -58,17 +59,17 @@ char *Sys_DefaultHomePath(void) Com_sprintf(homePath, sizeof(homePath), "%s%c", p, PATH_SEP); #ifdef MACOS_X Q_strcat(homePath, sizeof(homePath), - "Library/Application Support/Reaction"); + "Library/Application Support/"); if(com_homepath->string[0]) Q_strcat(homePath, sizeof(homePath), com_homepath->string); else - Q_strcat(homePath, sizeof(homePath), "Reaction"); + Q_strcat(homePath, sizeof(homePath), HOMEPATH_NAME_MACOSX); #else if(com_homepath->string[0]) Q_strcat(homePath, sizeof(homePath), com_homepath->string); else - Q_strcat(homePath, sizeof(homePath), ".Reaction"); + Q_strcat(homePath, sizeof(homePath), HOMEPATH_NAME_UNIX); #endif } } @@ -125,31 +126,6 @@ int Sys_Milliseconds (void) return curtime; } -#if !id386 -/* -================== -fastftol -================== -*/ -long fastftol( float f ) -{ - return (long)f; -} - -/* -================== -Sys_SnapVector -================== -*/ -void Sys_SnapVector( float *v ) -{ - v[0] = rint(v[0]); - v[1] = rint(v[1]); - v[2] = rint(v[2]); -} -#endif - - /* ================== Sys_RandomBytes @@ -254,10 +230,10 @@ Sys_Mkfifo */ FILE *Sys_Mkfifo( const char *ospath ) { - FILE *fifo; - int result; - int fn; - struct stat buf; + FILE *fifo; + int result; + int fn; + struct stat buf; // if file already exists AND is a pipefile, remove it if( !stat( ospath, &buf ) && S_ISFIFO( buf.st_mode ) ) @@ -756,6 +732,12 @@ void Sys_GLimpInit( void ) // NOP } +void Sys_SetFloatEnv(void) +{ + // rounding towards 0 + fesetround(FE_TOWARDZERO); +} + /* ============== Sys_PlatformInit diff --git a/reaction/code/sys/sys_win32.c b/reaction/code/sys/sys_win32.c index 362d33a1..4c60c0a5 100644 --- a/reaction/code/sys/sys_win32.c +++ b/reaction/code/sys/sys_win32.c @@ -37,6 +37,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include #include #include +#include // Used to determine where to store user-specific files static char homePath[ MAX_OSPATH ] = { 0 }; @@ -45,15 +46,39 @@ static char homePath[ MAX_OSPATH ] = { 0 }; static UINT timerResolution = 0; #endif -#ifdef __WIN64__ -void Sys_SnapVector( float *v ) -{ - v[0] = rint(v[0]); - v[1] = rint(v[1]); - v[2] = rint(v[2]); -} +/* +================ +Sys_SetFPUCW +Set FPU control word to default value +================ +*/ + +#ifndef _RC_CHOP +// mingw doesn't seem to have these defined :( + + #define _MCW_EM 0x0008001fU + #define _MCW_RC 0x00000300U + #define _MCW_PC 0x00030000U + #define _RC_CHOP 0x00000300U + #define _PC_53 0x00010000U + + unsigned int _controlfp(unsigned int new, unsigned int mask); #endif +#define FPUCWMASK1 (_MCW_RC | _MCW_EM) +#define FPUCW (_RC_CHOP | _MCW_EM | _PC_53) + +#if idx64 +#define FPUCWMASK (FPUCWMASK1) +#else +#define FPUCWMASK (FPUCWMASK1 | _MCW_PC) +#endif + +void Sys_SetFloatEnv(void) +{ + _controlfp(FPUCW, FPUCWMASK); +} + /* ================ Sys_DefaultHomePath @@ -94,7 +119,7 @@ char *Sys_DefaultHomePath( void ) if(com_homepath->string[0]) Q_strcat(homePath, sizeof(homePath), com_homepath->string); else - Q_strcat(homePath, sizeof(homePath), "Reaction"); + Q_strcat(homePath, sizeof(homePath), HOMEPATH_NAME_WIN); FreeLibrary(shfolder); } @@ -140,34 +165,6 @@ int Sys_Milliseconds (void) return sys_curtime; } -#ifndef __GNUC__ //see snapvectora.s -/* -================ -Sys_SnapVector -================ -*/ -void Sys_SnapVector( float *v ) -{ - int i; - float f; - - f = *v; - __asm fld f; - __asm fistp i; - *v = i; - v++; - f = *v; - __asm fld f; - __asm fistp i; - *v = i; - v++; - f = *v; - __asm fld f; - __asm fistp i; - *v = i; -} -#endif - /* ================ Sys_RandomBytes @@ -719,9 +716,12 @@ void Sys_PlatformInit( void ) { #ifndef DEDICATED TIMECAPS ptc; - const char *SDL_VIDEODRIVER = getenv( "SDL_VIDEODRIVER" ); +#endif + Sys_SetFloatEnv(); + +#ifndef DEDICATED if( SDL_VIDEODRIVER ) { Com_Printf( "SDL_VIDEODRIVER is externally set to \"%s\", " @@ -773,7 +773,7 @@ set/unset environment variables (empty value removes it) void Sys_SetEnv(const char *name, const char *value) { if(value) - _putenv(va("%s=%s", name, value)); + _putenv(va("%s=%s", name, value)); else _putenv(va("%s=", name)); } diff --git a/reaction/code/tools/asm/cmdlib.c b/reaction/code/tools/asm/cmdlib.c index de2610d4..d130d8df 100644 --- a/reaction/code/tools/asm/cmdlib.c +++ b/reaction/code/tools/asm/cmdlib.c @@ -63,7 +63,7 @@ char *ex_argv[MAX_EX_ARGC]; void ExpandWildcards( int *argc, char ***argv ) { struct _finddata_t fileinfo; - int handle; + intptr_t handle; int i; char filename[1024]; char filebase[1024]; @@ -185,7 +185,7 @@ void _printf( const char *format, ... ) { vsprintf (text, format, argptr); va_end (argptr); - printf(text); + printf("%s", text); #ifdef WIN32 if (!lookedForServer) { @@ -396,10 +396,12 @@ void Q_getwd (char *out) int i = 0; #ifdef WIN32 - _getcwd (out, 256); + if (_getcwd (out, 256) == NULL) + strcpy(out, "."); /* shrug */ strcat (out, "\\"); #else - getcwd (out, 256); + if (getcwd (out, 256) == NULL) + strcpy(out, "."); /* shrug */ strcat (out, "/"); #endif diff --git a/reaction/code/tools/asm/q3asm.c b/reaction/code/tools/asm/q3asm.c index fdf7afcb..d57bbc0c 100644 --- a/reaction/code/tools/asm/q3asm.c +++ b/reaction/code/tools/asm/q3asm.c @@ -386,8 +386,12 @@ static void sort_symbols () symbol_t *s; symbol_t **symlist; + if(!symbols) + return; + //crumb("sort_symbols: Constructing symlist array\n"); for (elems = 0, s = symbols; s; s = s->next, elems++) /* nop */ ; + symlist = malloc(elems * sizeof(symbol_t*)); for (i = 0, s = symbols; s; s = s->next, i++) { @@ -489,10 +493,10 @@ static void CodeError( char *fmt, ... ) { errorCount++; - report( "%s:%i ", currentFileName, currentFileLine ); + fprintf( stderr, "%s:%i ", currentFileName, currentFileLine ); va_start( argptr,fmt ); - vprintf( fmt,argptr ); + vfprintf( stderr, fmt, argptr ); va_end( argptr ); } diff --git a/reaction/code/tools/lcc/cpp/include.c b/reaction/code/tools/lcc/cpp/include.c index 1bb88475..331a0b4f 100644 --- a/reaction/code/tools/lcc/cpp/include.c +++ b/reaction/code/tools/lcc/cpp/include.c @@ -40,7 +40,7 @@ doinclude(Tokenrow *trp) { char fname[256], iname[256]; Includelist *ip; - int angled, len, fd, i; + int angled, len, wlen, fd, i; trp->tp += 1; if (trp->tp>=trp->lp) @@ -92,9 +92,9 @@ doinclude(Tokenrow *trp) break; } if ( Mflag>1 || (!angled&&Mflag==1) ) { - write(1,objname,strlen(objname)); - write(1,iname,strlen(iname)); - write(1,"\n",1); + wlen = write(1,objname,strlen(objname)); + wlen = write(1,iname,strlen(iname)); + wlen = write(1,"\n",1); } if (fd >= 0) { if (++incdepth > 10) diff --git a/reaction/code/tools/lcc/cpp/tokens.c b/reaction/code/tools/lcc/cpp/tokens.c index 147569bf..ad9f2f7c 100644 --- a/reaction/code/tools/lcc/cpp/tokens.c +++ b/reaction/code/tools/lcc/cpp/tokens.c @@ -267,7 +267,7 @@ peektokens(Tokenrow *trp, char *str) if (str) fprintf(stderr, "%s ", str); if (tpbp || tp>trp->lp) - fprintf(stderr, "(tp offset %d) ", tp-trp->bp); + fprintf(stderr, "(tp offset %ld) ", (long int) (tp - trp->bp)); for (tp=trp->bp; tplp && tpbp+32; tp++) { if (tp->type!=NL) { int c = tp->t[tp->len]; @@ -290,7 +290,7 @@ void puttokens(Tokenrow *trp) { Token *tp; - int len; + int len, wlen; uchar *p; if (verbose) @@ -305,15 +305,15 @@ puttokens(Tokenrow *trp) } if (len>OBS/2) { /* handle giant token */ if (wbp > wbuf) - write(1, wbuf, wbp-wbuf); - write(1, (char *)p, len); + wlen = write(1, wbuf, wbp-wbuf); + wlen = write(1, (char *)p, len); wbp = wbuf; } else { memcpy(wbp, p, len); wbp += len; } if (wbp >= &wbuf[OBS]) { - write(1, wbuf, OBS); + wlen = write(1, wbuf, OBS); if (wbp > &wbuf[OBS]) memcpy(wbuf, wbuf+OBS, wbp - &wbuf[OBS]); wbp -= OBS; @@ -327,8 +327,9 @@ puttokens(Tokenrow *trp) void flushout(void) { + int wlen; if (wbp>wbuf) { - write(1, wbuf, wbp-wbuf); + wlen = write(1, wbuf, wbp-wbuf); wbp = wbuf; } } diff --git a/reaction/code/tools/lcc/doc/4.html b/reaction/code/tools/lcc/doc/4.html index a2e1213f..c36f280b 100644 --- a/reaction/code/tools/lcc/doc/4.html +++ b/reaction/code/tools/lcc/doc/4.html @@ -523,7 +523,7 @@ signed integer. Conversions that widen unsigned integers zero-extend; those that signed integers sign-extend.

The front end composes conversions between types T1 and T2 -by widening T1 to it's "supertype", if necessary, converting +by widening T1 to its "supertype", if necessary, converting that result to T2's supertype, then narrowing the result to T2, if necessary. The following table lists the supertypes; omitted entries are their own supertypes.

diff --git a/reaction/code/tools/lcc/etc/lcc.c b/reaction/code/tools/lcc/etc/lcc.c index 13ed690b..a1688525 100644 --- a/reaction/code/tools/lcc/etc/lcc.c +++ b/reaction/code/tools/lcc/etc/lcc.c @@ -217,14 +217,74 @@ char *basename(char *name) { #ifdef WIN32 #include + +static char *escapeDoubleQuotes(const char *string) { + int stringLength = strlen(string); + int bufferSize = stringLength + 1; + int i, j; + char *newString; + + if (string == NULL) + return NULL; + + for (i = 0; i < stringLength; i++) { + if (string[i] == '"') + bufferSize++; + } + + newString = (char*)malloc(bufferSize); + + if (newString == NULL) + return NULL; + + for (i = 0, j = 0; i < stringLength; i++) { + if (string[i] == '"') + newString[j++] = '\\'; + + newString[j++] = string[i]; + } + + newString[j] = '\0'; + + return newString; +} + +static int spawn(const char *cmdname, char **argv) { + int argc = 0; + char **newArgv = argv; + int i; + intptr_t exitStatus; + + // _spawnvp removes double quotes from arguments, so we + // have to escape them manually + while (*newArgv++ != NULL) + argc++; + + newArgv = (char **)malloc(sizeof(char*) * (argc + 1)); + + for (i = 0; i < argc; i++) + newArgv[i] = escapeDoubleQuotes(argv[i]); + + newArgv[argc] = NULL; + + exitStatus = _spawnvp(_P_WAIT, cmdname, (const char *const *)newArgv); + + for (i = 0; i < argc; i++) + free(newArgv[i]); + + free(newArgv); + return exitStatus; +} + #else + #define _P_WAIT 0 #ifndef __sun extern int fork(void); #endif extern int wait(int *); -static int _spawnvp(int mode, const char *cmdname, char *argv[]) { +static int spawn(const char *cmdname, char **argv) { int pid, n, status; switch (pid = fork()) { @@ -292,11 +352,7 @@ static int callsys(char **av) { fprintf(stderr, "\n"); } if (verbose < 2) -#ifndef WIN32 - status = _spawnvp(_P_WAIT, executable, argv); -#else - status = _spawnvp(_P_WAIT, executable, (const char* const*)argv); -#endif + status = spawn(executable, argv); if (status == -1) { fprintf(stderr, "%s: ", progname); perror(argv[0]); diff --git a/reaction/code/tools/lcc/lburg/gram.c b/reaction/code/tools/lcc/lburg/gram.c index 4757f2bb..f9bc2739 100644 --- a/reaction/code/tools/lcc/lburg/gram.c +++ b/reaction/code/tools/lcc/lburg/gram.c @@ -2,23 +2,20 @@ static const char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93"; #endif -#include -#include - #define YYBYACC 1 #define YYMAJOR 1 #define YYMINOR 9 -#define YYPATCH 20070509 +#define YYPATCH 20101229 -#define YYEMPTY (-1) -#define yyclearin (yychar = YYEMPTY) -#define yyerrok (yyerrflag = 0) -#define YYRECOVERING (yyerrflag != 0) +#define YYEMPTY (-1) +#define yyclearin (yychar = YYEMPTY) +#define yyerrok (yyerrflag = 0) +#define YYRECOVERING() (yyerrflag != 0) -extern int yyparse(void); - -static int yygrowstack(void); #define YYPREFIX "yy" + +#define YYPURE 0 + #line 2 "code/tools/lcc/lburg/gram.y" #include #include "lburg.h" @@ -26,12 +23,46 @@ static char rcsid[] = "$Id: gram.y 145 2001-10-17 21:53:10Z timo $"; /*lint -e616 -e527 -e652 -esym(552,yynerrs) -esym(563,yynewstate,yyerrlab) */ static int yylineno = 0; #line 8 "code/tools/lcc/lburg/gram.y" +#ifdef YYSTYPE +#undef YYSTYPE_IS_DECLARED +#define YYSTYPE_IS_DECLARED 1 +#endif +#ifndef YYSTYPE_IS_DECLARED +#define YYSTYPE_IS_DECLARED 1 typedef union { int n; char *string; Tree tree; } YYSTYPE; -#line 35 "y.tab.c" +#endif /* !YYSTYPE_IS_DECLARED */ +#line 38 "y.tab.c" +/* compatibility with bison */ +#ifdef YYPARSE_PARAM +/* compatibility with FreeBSD */ +# ifdef YYPARSE_PARAM_TYPE +# define YYPARSE_DECL() yyparse(YYPARSE_PARAM_TYPE YYPARSE_PARAM) +# else +# define YYPARSE_DECL() yyparse(void *YYPARSE_PARAM) +# endif +#else +# define YYPARSE_DECL() yyparse(void) +#endif + +/* Parameters sent to lex. */ +#ifdef YYLEX_PARAM +# define YYLEX_DECL() yylex(void *YYLEX_PARAM) +# define YYLEX yylex(YYLEX_PARAM) +#else +# define YYLEX_DECL() yylex(void) +# define YYLEX yylex() +#endif + +/* Parameters sent to yyerror. */ +#define YYERROR_DECL() yyerror(const char *s) +#define YYERROR_CALL(msg) yyerror(msg) + +extern int YYPARSE_DECL(); + #define TERMINAL 257 #define START 258 #define PPERCENT 259 @@ -40,40 +71,40 @@ typedef union { #define CODE 262 #define INT 263 #define YYERRCODE 256 -short yylhs[] = { -1, +static const short yylhs[] = { -1, 0, 0, 4, 4, 6, 6, 6, 6, 7, 7, 5, 5, 5, 5, 1, 3, 3, 3, 2, }; -short yylen[] = { 2, +static const short yylen[] = { 2, 3, 1, 0, 2, 3, 3, 1, 2, 0, 4, 0, 7, 2, 3, 1, 1, 4, 6, 1, }; -short yydefred[] = { 3, +static const short yydefred[] = { 3, 0, 0, 0, 9, 0, 11, 7, 4, 8, 0, 15, 0, 0, 0, 5, 6, 0, 13, 0, 0, 14, 0, 10, 0, 0, 0, 0, 0, 19, 0, 17, 0, 12, 0, 18, }; -short yydgoto[] = { 1, +static const short yydgoto[] = { 1, 12, 30, 25, 2, 13, 8, 10, }; -short yysindex[] = { 0, +static const short yysindex[] = { 0, 0, -4, -2, 0, -250, 0, 0, 0, 0, -9, 0, 1, -10, -49, 0, 0, 3, 0, -44, -248, 0, -244, 0, -22, -242, -244, -245, -37, 0, 10, 0, -244, 0, -20, 0, }; -short yyrindex[] = { 0, +static const short yyrindex[] = { 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -short yygindex[] = { 0, +static const short yygindex[] = { 0, 11, 0, -23, 0, 0, 0, 0, }; #define YYTABLESIZE 255 -short yytable[] = { 18, +static const short yytable[] = { 18, 15, 16, 28, 31, 16, 7, 32, 9, 34, 11, 16, 20, 21, 22, 23, 24, 29, 26, 27, 33, 35, 2, 1, 19, 0, 0, 0, 0, 0, 0, @@ -101,7 +132,7 @@ short yytable[] = { 18, 0, 0, 0, 0, 0, 17, 0, 0, 0, 11, 14, 3, 4, 5, 6, }; -short yycheck[] = { 10, +static const short yycheck[] = { 10, 10, 41, 26, 41, 44, 10, 44, 10, 32, 260, 10, 61, 10, 58, 263, 260, 262, 40, 261, 10, 41, 0, 0, 13, -1, -1, -1, -1, -1, -1, @@ -135,7 +166,8 @@ short yycheck[] = { 10, #endif #define YYMAXTOKEN 263 #if YYDEBUG -char *yyname[] = { +static const char *yyname[] = { + "end-of-file",0,0,0,0,0,0,0,0,0,"'\\n'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,"'('","')'",0,0,"','",0,0,0,0,0,0,0,0,0,0,0,0,0,"':'",0,0, "'='",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -145,7 +177,7 @@ char *yyname[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, "TERMINAL","START","PPERCENT","ID","TEMPLATE","CODE","INT", }; -char *yyrule[] = { +static const char *yyrule[] = { "$accept : spec", "spec : decls PPERCENT rules", "spec : decls", @@ -166,12 +198,9 @@ char *yyrule[] = { "tree : ID '(' tree ')'", "tree : ID '(' tree ',' tree ')'", "cost : CODE", + }; #endif -#if YYDEBUG -#include -#endif - /* define the initial stack-sizes */ #ifdef YYSTACKSIZE #undef YYMAXDEPTH @@ -189,18 +218,22 @@ char *yyrule[] = { int yydebug; int yynerrs; + +typedef struct { + unsigned stacksize; + short *s_base; + short *s_mark; + short *s_last; + YYSTYPE *l_base; + YYSTYPE *l_mark; +} YYSTACKDATA; int yyerrflag; int yychar; -short *yyssp; -YYSTYPE *yyvsp; YYSTYPE yyval; YYSTYPE yylval; /* variables for the parser stack */ -static short *yyss; -static short *yysslim; -static YYSTYPE *yyvs; -static int yystacksize; +static YYSTACKDATA yystack; #line 60 "code/tools/lcc/lburg/gram.y" #include #include @@ -345,53 +378,72 @@ void yywarn(char *fmt, ...) { fprintf(stderr, "warning: "); vfprintf(stderr, fmt, ap); } -#line 349 "y.tab.c" +#line 381 "y.tab.c" + +#if YYDEBUG +#include /* needed for printf */ +#endif + +#include /* needed for malloc, etc */ +#include /* needed for memset */ + /* allocate initial stack or double stack size, up to YYMAXDEPTH */ -static int yygrowstack(void) +static int yygrowstack(YYSTACKDATA *data) { - int newsize, i; + int i; + unsigned newsize; short *newss; YYSTYPE *newvs; - if ((newsize = yystacksize) == 0) + if ((newsize = data->stacksize) == 0) newsize = YYINITSTACKSIZE; else if (newsize >= YYMAXDEPTH) return -1; else if ((newsize *= 2) > YYMAXDEPTH) newsize = YYMAXDEPTH; - i = yyssp - yyss; - newss = (yyss != 0) - ? (short *)realloc(yyss, newsize * sizeof(*newss)) - : (short *)malloc(newsize * sizeof(*newss)); + i = data->s_mark - data->s_base; + newss = (short *)realloc(data->s_base, newsize * sizeof(*newss)); if (newss == 0) return -1; - yyss = newss; - yyssp = newss + i; - newvs = (yyvs != 0) - ? (YYSTYPE *)realloc(yyvs, newsize * sizeof(*newvs)) - : (YYSTYPE *)malloc(newsize * sizeof(*newvs)); + data->s_base = newss; + data->s_mark = newss + i; + + newvs = (YYSTYPE *)realloc(data->l_base, newsize * sizeof(*newvs)); if (newvs == 0) return -1; - yyvs = newvs; - yyvsp = newvs + i; - yystacksize = newsize; - yysslim = yyss + newsize - 1; + data->l_base = newvs; + data->l_mark = newvs + i; + + data->stacksize = newsize; + data->s_last = data->s_base + newsize - 1; return 0; } -#define YYABORT goto yyabort +#if YYPURE || defined(YY_NO_LEAKS) +static void yyfreestack(YYSTACKDATA *data) +{ + free(data->s_base); + free(data->l_base); + memset(data, 0, sizeof(*data)); +} +#else +#define yyfreestack(data) /* nothing */ +#endif + +#define YYABORT goto yyabort #define YYREJECT goto yyabort #define YYACCEPT goto yyaccept -#define YYERROR goto yyerrlab +#define YYERROR goto yyerrlab + int -yyparse(void) +YYPARSE_DECL() { - register int yym, yyn, yystate; + int yym, yyn, yystate; #if YYDEBUG - register const char *yys; + const char *yys; if ((yys = getenv("YYDEBUG")) != 0) { @@ -404,17 +456,23 @@ yyparse(void) yynerrs = 0; yyerrflag = 0; yychar = YYEMPTY; + yystate = 0; - if (yyss == NULL && yygrowstack()) goto yyoverflow; - yyssp = yyss; - yyvsp = yyvs; - *yyssp = yystate = 0; +#if YYPURE + memset(&yystack, 0, sizeof(yystack)); +#endif + + if (yystack.s_base == NULL && yygrowstack(&yystack)) goto yyoverflow; + yystack.s_mark = yystack.s_base; + yystack.l_mark = yystack.l_base; + yystate = 0; + *yystack.s_mark = 0; yyloop: if ((yyn = yydefred[yystate]) != 0) goto yyreduce; if (yychar < 0) { - if ((yychar = yylex()) < 0) yychar = 0; + if ((yychar = YYLEX) < 0) yychar = 0; #if YYDEBUG if (yydebug) { @@ -434,12 +492,13 @@ yyloop: printf("%sdebug: state %d, shifting to state %d\n", YYPREFIX, yystate, yytable[yyn]); #endif - if (yyssp >= yysslim && yygrowstack()) + if (yystack.s_mark >= yystack.s_last && yygrowstack(&yystack)) { goto yyoverflow; } - *++yyssp = yystate = yytable[yyn]; - *++yyvsp = yylval; + yystate = yytable[yyn]; + *++yystack.s_mark = yytable[yyn]; + *++yystack.l_mark = yylval; yychar = YYEMPTY; if (yyerrflag > 0) --yyerrflag; goto yyloop; @@ -454,9 +513,7 @@ yyloop: yyerror("syntax error"); -#ifdef lint goto yyerrlab; -#endif yyerrlab: ++yynerrs; @@ -467,20 +524,21 @@ yyinrecovery: yyerrflag = 3; for (;;) { - if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 && + if ((yyn = yysindex[*yystack.s_mark]) && (yyn += YYERRCODE) >= 0 && yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) { #if YYDEBUG if (yydebug) printf("%sdebug: state %d, error recovery shifting\ - to state %d\n", YYPREFIX, *yyssp, yytable[yyn]); + to state %d\n", YYPREFIX, *yystack.s_mark, yytable[yyn]); #endif - if (yyssp >= yysslim && yygrowstack()) + if (yystack.s_mark >= yystack.s_last && yygrowstack(&yystack)) { goto yyoverflow; } - *++yyssp = yystate = yytable[yyn]; - *++yyvsp = yylval; + yystate = yytable[yyn]; + *++yystack.s_mark = yytable[yyn]; + *++yystack.l_mark = yylval; goto yyloop; } else @@ -488,11 +546,11 @@ yyinrecovery: #if YYDEBUG if (yydebug) printf("%sdebug: error recovery discarding state %d\n", - YYPREFIX, *yyssp); + YYPREFIX, *yystack.s_mark); #endif - if (yyssp <= yyss) goto yyabort; - --yyssp; - --yyvsp; + if (yystack.s_mark <= yystack.s_base) goto yyabort; + --yystack.s_mark; + --yystack.l_mark; } } } @@ -521,67 +579,67 @@ yyreduce: #endif yym = yylen[yyn]; if (yym) - yyval = yyvsp[1-yym]; + yyval = yystack.l_mark[1-yym]; else memset(&yyval, 0, sizeof yyval); switch (yyn) { case 1: #line 22 "code/tools/lcc/lburg/gram.y" -{ yylineno = 0; } + { yylineno = 0; } break; case 2: #line 23 "code/tools/lcc/lburg/gram.y" -{ yylineno = 0; } + { yylineno = 0; } break; case 6: #line 31 "code/tools/lcc/lburg/gram.y" -{ - if (nonterm(yyvsp[-1].string)->number != 1) + { + if (nonterm(yystack.l_mark[-1].string)->number != 1) yyerror("redeclaration of the start symbol\n"); } break; case 8: #line 36 "code/tools/lcc/lburg/gram.y" -{ yyerrok; } + { yyerrok; } break; case 10: #line 40 "code/tools/lcc/lburg/gram.y" -{ term(yyvsp[-2].string, yyvsp[0].n); } + { term(yystack.l_mark[-2].string, yystack.l_mark[0].n); } break; case 12: #line 44 "code/tools/lcc/lburg/gram.y" -{ rule(yyvsp[-5].string, yyvsp[-3].tree, yyvsp[-2].string, yyvsp[-1].string); } + { rule(yystack.l_mark[-5].string, yystack.l_mark[-3].tree, yystack.l_mark[-2].string, yystack.l_mark[-1].string); } break; case 14: #line 46 "code/tools/lcc/lburg/gram.y" -{ yyerrok; } + { yyerrok; } break; case 15: #line 49 "code/tools/lcc/lburg/gram.y" -{ nonterm(yyval.string = yyvsp[0].string); } + { nonterm(yyval.string = yystack.l_mark[0].string); } break; case 16: #line 52 "code/tools/lcc/lburg/gram.y" -{ yyval.tree = tree(yyvsp[0].string, 0, 0); } + { yyval.tree = tree(yystack.l_mark[0].string, 0, 0); } break; case 17: #line 53 "code/tools/lcc/lburg/gram.y" -{ yyval.tree = tree(yyvsp[-3].string, yyvsp[-1].tree, 0); } + { yyval.tree = tree(yystack.l_mark[-3].string, yystack.l_mark[-1].tree, 0); } break; case 18: #line 54 "code/tools/lcc/lburg/gram.y" -{ yyval.tree = tree(yyvsp[-5].string, yyvsp[-3].tree, yyvsp[-1].tree); } + { yyval.tree = tree(yystack.l_mark[-5].string, yystack.l_mark[-3].tree, yystack.l_mark[-1].tree); } break; case 19: #line 57 "code/tools/lcc/lburg/gram.y" -{ if (*yyvsp[0].string == 0) yyval.string = "0"; } + { if (*yystack.l_mark[0].string == 0) yyval.string = "0"; } break; -#line 581 "y.tab.c" +#line 638 "y.tab.c" } - yyssp -= yym; - yystate = *yyssp; - yyvsp -= yym; + yystack.s_mark -= yym; + yystate = *yystack.s_mark; + yystack.l_mark -= yym; yym = yylhs[yyn]; if (yystate == 0 && yym == 0) { @@ -591,11 +649,11 @@ break; state %d\n", YYPREFIX, YYFINAL); #endif yystate = YYFINAL; - *++yyssp = YYFINAL; - *++yyvsp = yyval; + *++yystack.s_mark = YYFINAL; + *++yystack.l_mark = yyval; if (yychar < 0) { - if ((yychar = yylex()) < 0) yychar = 0; + if ((yychar = YYLEX) < 0) yychar = 0; #if YYDEBUG if (yydebug) { @@ -618,22 +676,24 @@ break; #if YYDEBUG if (yydebug) printf("%sdebug: after reduction, shifting from state %d \ -to state %d\n", YYPREFIX, *yyssp, yystate); +to state %d\n", YYPREFIX, *yystack.s_mark, yystate); #endif - if (yyssp >= yysslim && yygrowstack()) + if (yystack.s_mark >= yystack.s_last && yygrowstack(&yystack)) { goto yyoverflow; } - *++yyssp = yystate; - *++yyvsp = yyval; + *++yystack.s_mark = (short) yystate; + *++yystack.l_mark = yyval; goto yyloop; yyoverflow: yyerror("yacc stack overflow"); yyabort: + yyfreestack(&yystack); return (1); yyaccept: + yyfreestack(&yystack); return (0); } diff --git a/reaction/code/ui/ui_players.c b/reaction/code/ui/ui_players.c index b6d80d4e..302a5d49 100644 --- a/reaction/code/ui/ui_players.c +++ b/reaction/code/ui/ui_players.c @@ -58,7 +58,7 @@ sfxHandle_t weaponChangeSound; * */ void COM_StripExtensionInPlace(char *name) { - char* ext = Q_strrchr(name, '.'); + char* ext = strrchr(name, '.'); if (ext) *ext = 0; }