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;
}