10 Oct 2011

This commit is contained in:
g-cont 2011-10-10 00:00:00 +04:00 committed by Alibek Omarov
parent 95af1226ef
commit 0ccdeddcea
56 changed files with 1508 additions and 955 deletions

View File

@ -11,7 +11,7 @@ Render: remove cvar gl_texturebits
Render: allow 16-bit color mode when decktop has same
Render: rename "vid_gamma" to "gamma", make backward compatibility with GoldSource config
Sound: get support for automatic ambient sounds like in Quake
Sound: add cvar "s_combine" that trying to combine mutilpe channels with same sounds into one
Sound: add cvar "s_combine_channels" that trying to combine mutilpe channels with same sounds into one
Engine: add "secure" option support for both liblist.gam and gameinfo.txt
Engine: fix bug determine current directory
Server: fix bug when some sound messages can't be sended to client (e.g. not vised map)
@ -39,7 +39,15 @@ Engine: fix Host_Error issues
Network: add IPX and IPX_BROADCAST for backward compatibility with GoldSrc
Engine: do revision for 'allow_studio_scale' cvar in trace code
GameUI: added support for Steam backgrounds
GameUI: hide input symbols for "password" field in "create server" menu page
GameUI: hide input symbols for "password" field in "create server" menu page
Client: initial implementation of NetAPI
Render: clear decals code. Add transparent rendering for 'glass' decals
GameUI: added new function into menu interface called a pfnProcessImage, added new argument for pfnPIC_Load.
GameUI: fix loading flipped Steam background images
Client: remove gravity for R_Implosion effect
Sound: add SND_MoveMouth16 for support 16-bit sounds lip-sync
Engine: fix potentially crash during parsing titles.txt when file is empty
Engine: increase MAX_VALUE field up to 2048 characters
build 1662

View File

@ -6,110 +6,6 @@
--------------------Configuration: cl_dll - Win32 Release--------------------
</h3>
<h3>Command Lines</h3>
Creating temporary file "C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP1399.tmp" with contents
[
/nologo /MT /W3 /GX /O2 /I "..\utils\vgui\include" /I "..\engine" /I "..\common" /I "..\pm_shared" /I "..\dlls" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "CLIENT_DLL" /D "CLIENT_WEAPONS" /Fp"..\temp\cl_dll\!release/cl_dll.pch" /YX /Fo"..\temp\cl_dll\!release/" /Fd"..\temp\cl_dll\!release/" /FD /c
"D:\Xash3D\src_main\cl_dll\vgui_ServerBrowser.cpp"
]
Creating command line "cl.exe @"C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP1399.tmp""
Creating temporary file "C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP139A.tmp" with contents
[
kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib winmm.lib ../utils/vgui/lib/win32_vc6/vgui.lib wsock32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"..\temp\cl_dll\!release/client.pdb" /machine:I386 /out:"..\temp\cl_dll\!release/client.dll" /implib:"..\temp\cl_dll\!release/client.lib"
"\Xash3D\src_main\temp\cl_dll\!release\crossbow.obj"
"\Xash3D\src_main\temp\cl_dll\!release\crowbar.obj"
"\Xash3D\src_main\temp\cl_dll\!release\egon.obj"
"\Xash3D\src_main\temp\cl_dll\!release\ev_hldm.obj"
"\Xash3D\src_main\temp\cl_dll\!release\gauss.obj"
"\Xash3D\src_main\temp\cl_dll\!release\handgrenade.obj"
"\Xash3D\src_main\temp\cl_dll\!release\hl_baseentity.obj"
"\Xash3D\src_main\temp\cl_dll\!release\hl_events.obj"
"\Xash3D\src_main\temp\cl_dll\!release\hl_objects.obj"
"\Xash3D\src_main\temp\cl_dll\!release\hl_weapons.obj"
"\Xash3D\src_main\temp\cl_dll\!release\hl_wpn_glock.obj"
"\Xash3D\src_main\temp\cl_dll\!release\hornetgun.obj"
"\Xash3D\src_main\temp\cl_dll\!release\mp5.obj"
"\Xash3D\src_main\temp\cl_dll\!release\python.obj"
"\Xash3D\src_main\temp\cl_dll\!release\rpg.obj"
"\Xash3D\src_main\temp\cl_dll\!release\satchel.obj"
"\Xash3D\src_main\temp\cl_dll\!release\shotgun.obj"
"\Xash3D\src_main\temp\cl_dll\!release\squeakgrenade.obj"
"\Xash3D\src_main\temp\cl_dll\!release\tripmine.obj"
"\Xash3D\src_main\temp\cl_dll\!release\vgui_scrollbar2.obj"
"\Xash3D\src_main\temp\cl_dll\!release\vgui_slider2.obj"
"\Xash3D\src_main\temp\cl_dll\!release\voice_banmgr.obj"
"\Xash3D\src_main\temp\cl_dll\!release\voice_status.obj"
"\Xash3D\src_main\temp\cl_dll\!release\ammo.obj"
"\Xash3D\src_main\temp\cl_dll\!release\ammo_secondary.obj"
"\Xash3D\src_main\temp\cl_dll\!release\ammohistory.obj"
"\Xash3D\src_main\temp\cl_dll\!release\battery.obj"
"\Xash3D\src_main\temp\cl_dll\!release\cdll_int.obj"
"\Xash3D\src_main\temp\cl_dll\!release\com_weapons.obj"
"\Xash3D\src_main\temp\cl_dll\!release\death.obj"
"\Xash3D\src_main\temp\cl_dll\!release\demo.obj"
"\Xash3D\src_main\temp\cl_dll\!release\entity.obj"
"\Xash3D\src_main\temp\cl_dll\!release\ev_common.obj"
"\Xash3D\src_main\temp\cl_dll\!release\events.obj"
"\Xash3D\src_main\temp\cl_dll\!release\flashlight.obj"
"\Xash3D\src_main\temp\cl_dll\!release\GameStudioModelRenderer.obj"
"\Xash3D\src_main\temp\cl_dll\!release\geiger.obj"
"\Xash3D\src_main\temp\cl_dll\!release\health.obj"
"\Xash3D\src_main\temp\cl_dll\!release\hud.obj"
"\Xash3D\src_main\temp\cl_dll\!release\hud_msg.obj"
"\Xash3D\src_main\temp\cl_dll\!release\hud_redraw.obj"
"\Xash3D\src_main\temp\cl_dll\!release\hud_servers.obj"
"\Xash3D\src_main\temp\cl_dll\!release\hud_spectator.obj"
"\Xash3D\src_main\temp\cl_dll\!release\hud_update.obj"
"\Xash3D\src_main\temp\cl_dll\!release\in_camera.obj"
"\Xash3D\src_main\temp\cl_dll\!release\input.obj"
"\Xash3D\src_main\temp\cl_dll\!release\inputw32.obj"
"\Xash3D\src_main\temp\cl_dll\!release\menu.obj"
"\Xash3D\src_main\temp\cl_dll\!release\message.obj"
"\Xash3D\src_main\temp\cl_dll\!release\parsemsg.obj"
"\Xash3D\src_main\temp\cl_dll\!release\pm_debug.obj"
"\Xash3D\src_main\temp\cl_dll\!release\pm_math.obj"
"\Xash3D\src_main\temp\cl_dll\!release\pm_shared.obj"
"\Xash3D\src_main\temp\cl_dll\!release\saytext.obj"
"\Xash3D\src_main\temp\cl_dll\!release\status_icons.obj"
"\Xash3D\src_main\temp\cl_dll\!release\statusbar.obj"
"\Xash3D\src_main\temp\cl_dll\!release\studio_util.obj"
"\Xash3D\src_main\temp\cl_dll\!release\StudioModelRenderer.obj"
"\Xash3D\src_main\temp\cl_dll\!release\text_message.obj"
"\Xash3D\src_main\temp\cl_dll\!release\train.obj"
"\Xash3D\src_main\temp\cl_dll\!release\tri.obj"
"\Xash3D\src_main\temp\cl_dll\!release\util.obj"
"\Xash3D\src_main\temp\cl_dll\!release\vgui_checkbutton2.obj"
"\Xash3D\src_main\temp\cl_dll\!release\vgui_ClassMenu.obj"
"\Xash3D\src_main\temp\cl_dll\!release\vgui_ConsolePanel.obj"
"\Xash3D\src_main\temp\cl_dll\!release\vgui_ControlConfigPanel.obj"
"\Xash3D\src_main\temp\cl_dll\!release\vgui_CustomObjects.obj"
"\Xash3D\src_main\temp\cl_dll\!release\vgui_grid.obj"
"\Xash3D\src_main\temp\cl_dll\!release\vgui_helpers.obj"
"\Xash3D\src_main\temp\cl_dll\!release\vgui_int.obj"
"\Xash3D\src_main\temp\cl_dll\!release\vgui_listbox.obj"
"\Xash3D\src_main\temp\cl_dll\!release\vgui_loadtga.obj"
"\Xash3D\src_main\temp\cl_dll\!release\vgui_MOTDWindow.obj"
"\Xash3D\src_main\temp\cl_dll\!release\vgui_SchemeManager.obj"
"\Xash3D\src_main\temp\cl_dll\!release\vgui_ScorePanel.obj"
"\Xash3D\src_main\temp\cl_dll\!release\vgui_ServerBrowser.obj"
"\Xash3D\src_main\temp\cl_dll\!release\vgui_SpectatorPanel.obj"
"\Xash3D\src_main\temp\cl_dll\!release\vgui_TeamFortressViewport.obj"
"\Xash3D\src_main\temp\cl_dll\!release\vgui_teammenu.obj"
"\Xash3D\src_main\temp\cl_dll\!release\view.obj"
]
Creating command line "link.exe @"C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP139A.tmp""
Creating temporary file "C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP139B.bat" with contents
[
@echo off
copy \Xash3D\src_main\temp\cl_dll\!release\client.dll "D:\Xash3D\valve\cl_dlls\client.dll"
]
Creating command line ""C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP139B.bat""
Compiling...
vgui_ServerBrowser.cpp
Linking...
Creating library ..\temp\cl_dll\!release/client.lib and object ..\temp\cl_dll\!release/client.exp
<h3>Output Window</h3>
Performing Custom Build Step on \Xash3D\src_main\temp\cl_dll\!release\client.dll
‘ª®¯¨à®¢ ­® ä ©«®¢: 1.

View File

@ -206,7 +206,7 @@ int UTIL_FindEntityInMap(char * name, float * origin, float * angle)
{
int n,found = 0;
char keyname[256];
char token[1024];
char token[2048];
cl_entity_t * pEnt = gEngfuncs.GetEntityByIndex( 0 ); // get world model

View File

@ -6,15 +6,6 @@
--------------------Configuration: hl - Win32 Release--------------------
</h3>
<h3>Command Lines</h3>
Creating temporary file "C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP614.bat" with contents
[
@echo off
copy \Xash3D\src_main\temp\dlls\!release\hl.dll "D:\Xash3D\valve\dlls\hl.dll"
]
Creating command line ""C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP614.bat""
<h3>Output Window</h3>
Performing Custom Build Step on \Xash3D\src_main\temp\dlls\!release\hl.dll
‘ª®¯¨à®¢ ­® ä ©«®¢: 1.

View File

@ -298,7 +298,7 @@ void CL_WriteDemoHeader( const char *name )
cls.lastoutgoingcommand = -1; // we don't have a backed up cmd history yet
cls.nextcmdtime = host.realtime; // we can send a cmd right away
// FIXME: current demo implementation is completely wrong
// UNDONE: current demo implementation is completely wrong
// it's support only uncompressed demos at he moment
Cvar_SetFloat( "cl_nodelta", 1.0f );
}
@ -482,7 +482,6 @@ void CL_StopRecord( void )
cls.demoname[0] = '\0';
menu.globals->demoname[0] = '\0';
// FIXME: current demo implementation is completely wrong
// it's support only uncompressed demos at he moment
// enable delta-compression here at end of the demo record
Cvar_SetFloat( "cl_nodelta", 0.0f );

454
engine/client/cl_events.c Normal file
View File

@ -0,0 +1,454 @@
/*
cl_events.c - client-side event system implementation
Copyright (C) 2011 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "common.h"
#include "client.h"
#include "event_flags.h"
#include "net_encode.h"
/*
===============
CL_ResetEvent
===============
*/
void CL_ResetEvent( event_info_t *ei )
{
Q_memset( ei, 0, sizeof( *ei ));
}
/*
=============
CL_SetEventIndex
=============
*/
void CL_SetEventIndex( const char *szEvName, int ev_index )
{
cl_user_event_t *ev;
int i;
if( !szEvName || !*szEvName )
return; // ignore blank names
// search event by name to link with
for( i = 0; i < MAX_EVENTS; i++ )
{
ev = clgame.events[i];
if( !ev ) break;
if( !Q_stricmp( ev->name, szEvName ))
{
ev->index = ev_index;
return;
}
}
}
/*
=============
CL_EventIndex
=============
*/
word CL_EventIndex( const char *name )
{
int i;
if( !name || !name[0] )
return 0;
for( i = 1; i < MAX_EVENTS && cl.event_precache[i][0]; i++ )
{
if( !Q_stricmp( cl.event_precache[i], name ))
return i;
}
return 0;
}
/*
=============
CL_RegisterEvent
=============
*/
void CL_RegisterEvent( int lastnum, const char *szEvName, pfnEventHook func )
{
cl_user_event_t *ev;
if( lastnum == MAX_EVENTS )
{
MsgDev( D_ERROR, "CL_RegisterEvent: MAX_EVENTS hit!\n" );
return;
}
// clear existing or allocate new one
if( !clgame.events[lastnum] )
clgame.events[lastnum] = Mem_Alloc( cls.mempool, sizeof( cl_user_event_t ));
else Q_memset( clgame.events[lastnum], 0, sizeof( cl_user_event_t ));
ev = clgame.events[lastnum];
// NOTE: ev->index will be set later
Q_strncpy( ev->name, szEvName, CS_SIZE );
ev->func = func;
}
/*
=============
CL_FireEvent
=============
*/
qboolean CL_FireEvent( event_info_t *ei )
{
cl_user_event_t *ev;
const char *name;
int i, idx;
if( !ei || !ei->index )
return false;
// get the func pointer
for( i = 0; i < MAX_EVENTS; i++ )
{
ev = clgame.events[i];
if( !ev )
{
idx = bound( 1, ei->index, MAX_EVENTS );
MsgDev( D_ERROR, "CL_FireEvent: %s not precached\n", cl.event_precache[idx] );
break;
}
if( ev->index == ei->index )
{
if( ev->func )
{
ev->func( &ei->args );
return true;
}
name = cl.event_precache[ei->index];
MsgDev( D_ERROR, "CL_FireEvent: %s not hooked\n", name );
break;
}
}
return false;
}
/*
=============
CL_FireEvents
called right before draw frame
=============
*/
void CL_FireEvents( void )
{
int i;
event_state_t *es;
event_info_t *ei;
qboolean success;
es = &cl.events;
for( i = 0; i < MAX_EVENT_QUEUE; i++ )
{
ei = &es->ei[i];
if( ei->index == 0 )
continue;
// delayed event!
if( ei->fire_time && ( ei->fire_time > cl.time ))
continue;
success = CL_FireEvent( ei );
// zero out the remaining fields
CL_ResetEvent( ei );
}
}
/*
=============
CL_FindEvent
find first empty event
=============
*/
event_info_t *CL_FindEmptyEvent( void )
{
int i;
event_state_t *es;
event_info_t *ei;
es = &cl.events;
// look for first slot where index is != 0
for( i = 0; i < MAX_EVENT_QUEUE; i++ )
{
ei = &es->ei[i];
if( ei->index != 0 )
continue;
return ei;
}
// no slots available
return NULL;
}
/*
=============
CL_FindEvent
replace only unreliable events
=============
*/
event_info_t *CL_FindUnreliableEvent( void )
{
event_state_t *es;
event_info_t *ei;
int i;
es = &cl.events;
for ( i = 0; i < MAX_EVENT_QUEUE; i++ )
{
ei = &es->ei[i];
if( ei->index != 0 )
{
// it's reliable, so skip it
if( ei->flags & FEV_RELIABLE )
continue;
}
return ei;
}
// this should never happen
return NULL;
}
/*
=============
CL_QueueEvent
=============
*/
void CL_QueueEvent( int flags, int index, float delay, event_args_t *args )
{
qboolean unreliable = (flags & FEV_RELIABLE) ? false : true;
event_info_t *ei;
// find a normal slot
ei = CL_FindEmptyEvent();
if( !ei && unreliable )
return;
// okay, so find any old unreliable slot
if( !ei )
{
ei = CL_FindUnreliableEvent();
if( !ei ) return;
}
ei->index = index;
ei->fire_time = delay ? (cl.time + delay) : 0.0f;
ei->flags = flags;
ei->args = *args;
}
/*
=============
CL_ParseReliableEvent
=============
*/
void CL_ParseReliableEvent( sizebuf_t *msg )
{
int event_index;
event_args_t nullargs, args;
float delay = 0.0f;
cl_entity_t *pEnt;
Q_memset( &nullargs, 0, sizeof( nullargs ));
event_index = BF_ReadUBitLong( msg, MAX_EVENT_BITS );
if( BF_ReadOneBit( msg ))
delay = (float)BF_ReadWord( msg ) * (1.0f / 100.0f);
// reliable events not use delta-compression just null-compression
MSG_ReadDeltaEvent( msg, &nullargs, &args );
if(( pEnt = CL_GetEntityByIndex( args.entindex )) != NULL )
{
if( VectorIsNull( args.origin ))
VectorCopy( pEnt->curstate.origin, args.origin );
if( VectorIsNull( args.angles ))
VectorCopy( pEnt->curstate.angles, args.angles );
if( VectorIsNull( args.velocity ))
VectorCopy( pEnt->curstate.velocity, args.velocity );
}
CL_QueueEvent( FEV_RELIABLE|FEV_SERVER, event_index, delay, &args );
}
/*
=============
CL_ParseEvent
=============
*/
void CL_ParseEvent( sizebuf_t *msg )
{
int event_index;
int i, num_events;
int packet_ent;
event_args_t nullargs, args;
qboolean has_update;
entity_state_t *state;
cl_entity_t *pEnt;
float delay;
Q_memset( &nullargs, 0, sizeof( nullargs ));
num_events = BF_ReadUBitLong( msg, 5 );
// parse events queue
for( i = 0 ; i < num_events; i++ )
{
event_index = BF_ReadUBitLong( msg, MAX_EVENT_BITS );
has_update = false;
if( BF_ReadOneBit( msg ))
{
packet_ent = BF_ReadUBitLong( msg, MAX_ENTITY_BITS );
if( BF_ReadOneBit( msg ))
{
MSG_ReadDeltaEvent( msg, &nullargs, &args );
has_update = true;
}
}
else packet_ent = -1;
if( packet_ent != -1 )
state = &cls.packet_entities[(cl.frame.first_entity+packet_ent)%cls.num_client_entities];
else state = NULL;
// it's a client. Override some params
if( args.entindex >= 1 && args.entindex <= cl.maxclients )
{
if(( args.entindex - 1 ) == cl.playernum )
{
// get the predicted angles
VectorCopy( cl.refdef.cl_viewangles, args.angles );
VectorCopy( cl.frame.local.client.origin, args.origin );
VectorCopy( cl.frame.local.client.velocity, args.velocity );
}
else if( state )
{
// restore viewangles from angles
args.angles[PITCH] = -state->angles[PITCH] * 3;
args.angles[YAW] = state->angles[YAW];
args.angles[ROLL] = 0; // no roll
}
}
else if( state )
{
if( VectorIsNull( args.origin ))
VectorCopy( state->origin, args.origin );
if( VectorIsNull( args.angles ))
VectorCopy( state->angles, args.angles );
if( VectorIsNull( args.velocity ))
VectorCopy( state->velocity, args.velocity );
}
else if(( pEnt = CL_GetEntityByIndex( args.entindex )) != NULL )
{
if( VectorIsNull( args.origin ))
VectorCopy( pEnt->curstate.origin, args.origin );
if( VectorIsNull( args.angles ))
VectorCopy( pEnt->curstate.angles, args.angles );
if( VectorIsNull( args.velocity ))
VectorCopy( pEnt->curstate.velocity, args.velocity );
}
if( BF_ReadOneBit( msg ))
delay = (float)BF_ReadWord( msg ) * (1.0f / 100.0f);
else delay = 0.0f;
// g-cont. should we need find the event with same index?
CL_QueueEvent( 0, event_index, delay, &args );
}
}
/*
=============
CL_PlaybackEvent
=============
*/
void CL_PlaybackEvent( int flags, const edict_t *pInvoker, word eventindex, float delay, float *origin,
float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 )
{
event_args_t args;
int invokerIndex = 0;
// first check event for out of bounds
if( eventindex < 1 || eventindex > MAX_EVENTS )
{
MsgDev( D_ERROR, "CL_PlaybackEvent: invalid eventindex %i\n", eventindex );
return;
}
// check event for precached
if( !CL_EventIndex( cl.event_precache[eventindex] ))
{
MsgDev( D_ERROR, "CL_PlaybackEvent: event %i was not precached\n", eventindex );
return;
}
flags |= FEV_CLIENT; // it's a client event
flags &= ~(FEV_NOTHOST|FEV_HOSTONLY|FEV_GLOBAL);
if( delay < 0.0f ) delay = 0.0f; // fixup negative delays
invokerIndex = cl.playernum + 1; // only local client can issue client events
args.flags = 0;
args.entindex = invokerIndex;
// UNDONE: restore checks when predicting will be done
// if( !angles || VectorIsNull( angles ))
VectorCopy( cl.refdef.cl_viewangles, args.angles );
// if( !origin || VectorIsNull( origin ))
VectorCopy( cl.frame.local.client.origin, args.origin );
VectorCopy( cl.frame.local.client.velocity, args.velocity );
args.ducking = cl.frame.local.playerstate.usehull;
args.fparam1 = fparam1;
args.fparam2 = fparam2;
args.iparam1 = iparam1;
args.iparam2 = iparam2;
args.bparam1 = bparam1;
args.bparam2 = bparam2;
CL_QueueEvent( flags, eventindex, delay, &args );
}

View File

@ -881,28 +881,27 @@ void CL_AddEntities( void )
//
// sound engine implementation
//
qboolean CL_GetEntitySpatialization( int entnum, vec3_t origin, vec3_t velocity )
qboolean CL_GetEntitySpatialization( int entnum, vec3_t origin )
{
cl_entity_t *ent;
qboolean valid_origin;
ASSERT( origin != NULL );
valid_origin = VectorIsNull( origin ) ? false : true;
ent = CL_GetEntityByIndex( entnum );
// entity is not present on the client but has valid origin
if( !ent || !ent->index ) return valid_origin;
// setup origin and velocity
if( origin ) VectorCopy( ent->curstate.origin, origin );
if( velocity ) VectorCopy( ent->curstate.velocity, velocity );
// entity is present on the client but out of PVS
if( ent->curstate.messagenum != cl.parsecount )
return false;
// if a brush model, offset the origin
if( origin && Mod_GetType( ent->curstate.modelindex ) == mod_brush )
{
vec3_t mins, maxs, midPoint;
// setup origin
VectorAverage( ent->curstate.mins, ent->curstate.maxs, origin );
VectorAdd( origin, ent->curstate.origin, origin );
Mod_GetBounds( ent->curstate.modelindex, mins, maxs );
VectorAverage( mins, maxs, midPoint );
VectorAdd( origin, midPoint, origin );
}
return true;
}

View File

@ -19,7 +19,6 @@ GNU General Public License for more details.
#include "triangleapi.h"
#include "r_efx.h"
#include "demo_api.h"
#include "event_flags.h"
#include "ivoicetweak.h"
#include "pm_local.h"
#include "cl_tent.h"
@ -1032,314 +1031,6 @@ void CL_LinkUserMessage( char *pszName, const int svc_num, int iSize )
clgame.msg[i].size = iSize;
}
static void CL_RegisterEvent( int lastnum, const char *szEvName, pfnEventHook func )
{
user_event_t *ev;
if( lastnum == MAX_EVENTS )
{
MsgDev( D_ERROR, "CL_RegisterEvent: MAX_EVENTS hit!\n" );
return;
}
ev = clgame.events[lastnum];
// clear existing or allocate new one
if( ev ) Q_memset( ev, 0, sizeof( *ev ));
else ev = clgame.events[lastnum] = Mem_Alloc( cls.mempool, sizeof( *ev ));
Q_strncpy( ev->name, szEvName, CS_SIZE );
ev->func = func;
// ev->index will be set later
}
void CL_SetEventIndex( const char *szEvName, int ev_index )
{
user_event_t *ev;
int i;
if( !szEvName || !*szEvName ) return; // ignore blank names
// search event by name to link with
for( i = 0; i < MAX_EVENTS; i++ )
{
ev = clgame.events[i];
if( !ev ) break;
if( !Q_stricmp( ev->name, szEvName ))
{
ev->index = ev_index;
return;
}
}
}
/*
===============
CL_ResetEvent
===============
*/
void CL_ResetEvent( event_info_t *ei )
{
Q_memset( ei, 0, sizeof( *ei ));
}
/*
=============
CL_EventIndex
=============
*/
word CL_EventIndex( const char *name )
{
int i;
if( !name || !name[0] )
return 0;
for( i = 1; i < MAX_EVENTS && cl.event_precache[i][0]; i++ )
{
if( !Q_stricmp( cl.event_precache[i], name ))
return i;
}
return 0;
}
/*
=============
CL_FireEvent
=============
*/
qboolean CL_FireEvent( event_info_t *ei )
{
user_event_t *ev;
const char *name;
int i, idx;
if( !ei || !ei->index )
return false;
// get the func pointer
for( i = 0; i < MAX_EVENTS; i++ )
{
ev = clgame.events[i];
if( !ev )
{
idx = bound( 1, ei->index, MAX_EVENTS );
MsgDev( D_ERROR, "CL_FireEvent: %s not precached\n", cl.event_precache[idx] );
break;
}
if( ev->index == ei->index )
{
if( ev->func )
{
ev->func( &ei->args );
return true;
}
name = cl.event_precache[ei->index];
MsgDev( D_ERROR, "CL_FireEvent: %s not hooked\n", name );
break;
}
}
return false;
}
/*
=============
CL_FireEvents
called right before draw frame
=============
*/
void CL_FireEvents( void )
{
int i;
event_state_t *es;
event_info_t *ei;
qboolean success;
es = &cl.events;
for( i = 0; i < MAX_EVENT_QUEUE; i++ )
{
ei = &es->ei[i];
if( ei->index == 0 )
continue;
if( cls.state == ca_disconnected )
{
CL_ResetEvent( ei );
continue;
}
// delayed event!
if( ei->fire_time && ( ei->fire_time > cl.time ))
continue;
success = CL_FireEvent( ei );
// zero out the remaining fields
CL_ResetEvent( ei );
}
}
/*
=============
CL_FindEvent
find first empty event
=============
*/
event_info_t *CL_FindEmptyEvent( void )
{
int i;
event_state_t *es;
event_info_t *ei;
es = &cl.events;
// look for first slot where index is != 0
for( i = 0; i < MAX_EVENT_QUEUE; i++ )
{
ei = &es->ei[i];
if( ei->index != 0 )
continue;
return ei;
}
// no slots available
return NULL;
}
/*
=============
CL_FindEvent
replace only unreliable events
=============
*/
event_info_t *CL_FindUnreliableEvent( void )
{
int i;
event_state_t *es;
event_info_t *ei;
es = &cl.events;
for ( i = 0; i < MAX_EVENT_QUEUE; i++ )
{
ei = &es->ei[i];
if( ei->index != 0 )
{
// it's reliable, so skip it
if( ei->flags & FEV_RELIABLE )
continue;
}
return ei;
}
// this should never happen
return NULL;
}
/*
=============
CL_QueueEvent
=============
*/
void CL_QueueEvent( int flags, int index, float delay, event_args_t *args )
{
qboolean unreliable = (flags & FEV_RELIABLE) ? false : true;
event_info_t *ei;
// find a normal slot
ei = CL_FindEmptyEvent();
if( !ei && unreliable )
{
return;
}
// okay, so find any old unreliable slot
if( !ei )
{
ei = CL_FindUnreliableEvent();
if( !ei ) return;
}
ei->index = index;
ei->fire_time = delay ? (cl.time + delay) : 0.0f;
ei->flags = flags;
// copy in args event data
Q_memcpy( &ei->args, args, sizeof( ei->args ));
}
/*
=============
CL_PlaybackEvent
=============
*/
void CL_PlaybackEvent( int flags, const edict_t *pInvoker, word eventindex, float delay, float *origin,
float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 )
{
event_args_t args;
int invokerIndex = 0;
// first check event for out of bounds
if( eventindex < 1 || eventindex > MAX_EVENTS )
{
MsgDev( D_ERROR, "CL_PlaybackEvent: invalid eventindex %i\n", eventindex );
return;
}
// check event for precached
if( !CL_EventIndex( cl.event_precache[eventindex] ))
{
MsgDev( D_ERROR, "CL_PlaybackEvent: event %i was not precached\n", eventindex );
return;
}
flags |= FEV_CLIENT; // it's a client event
flags &= ~(FEV_NOTHOST|FEV_HOSTONLY|FEV_GLOBAL);
if( delay < 0.0f ) delay = 0.0f; // fixup negative delays
invokerIndex = cl.playernum + 1; // only local client can issue client events
args.flags = 0;
args.entindex = invokerIndex;
VectorCopy( origin, args.origin );
VectorCopy( angles, args.angles );
args.fparam1 = fparam1;
args.fparam2 = fparam2;
args.iparam1 = iparam1;
args.iparam2 = iparam2;
args.bparam1 = bparam1;
args.bparam2 = bparam2;
if( flags & FEV_RELIABLE )
{
args.ducking = 0;
VectorClear( args.velocity );
}
else if( invokerIndex )
{
// get up some info from invoker
VectorCopy( cl.data.origin, args.origin );
VectorCopy( cl.data.viewangles, args.angles );
VectorCopy( cl.frame.local.playerstate.velocity, args.velocity );
args.ducking = cl.frame.local.playerstate.usehull;
}
CL_QueueEvent( flags, eventindex, delay, &args );
}
void CL_FreeEntity( cl_entity_t *pEdict )
{
ASSERT( pEdict );
@ -2315,34 +2006,26 @@ pfnHookEvent
*/
static void pfnHookEvent( const char *filename, pfnEventHook pfn )
{
word event_index;
char name[64];
user_event_t *ev;
int i, j;
cl_user_event_t *ev;
int i;
// ignore blank names
if( !filename || !*filename ) return;
if( !filename || !*filename )
return;
for( i = j = 0; i < Q_strlen( filename ); i++ )
{
if( filename[i] == '\\' ) name[j] = '/';
else name[j] = filename[i];
j++;
}
name[j] = '\0';
Q_strncpy( name, filename, sizeof( name ));
COM_FixSlashes( name );
event_index = CL_EventIndex( name );
// second call can change EventFunc
// find an empty slot
for( i = 0; i < MAX_EVENTS; i++ )
{
ev = clgame.events[i];
if( !ev ) break;
if( !Q_stricmp( name, ev->name ))
if( !Q_stricmp( name, ev->name ) && ev->func != NULL )
{
if( ev->func != pfn )
ev->func = pfn;
MsgDev( D_WARN, "CL_HookEvent: %s already hooked!\n" );
return;
}
}
@ -2376,9 +2059,11 @@ static void pfnKillEvents( int entnum, const char *eventname )
{
ei = &es->ei[i];
if( ei->index != eventIndex || ei->entity_index != entnum )
continue;
CL_ResetEvent( ei );
if( ei->index == eventIndex && ei->entity_index == entnum )
{
CL_ResetEvent( ei );
break;
}
}
}
@ -2759,11 +2444,13 @@ PlayerInfo_SetValueForKey
*/
void PlayerInfo_SetValueForKey( const char *key, const char *value )
{
// TODO: implement
cvar_t *var;
// NOTE: Xash3D doesn't have local userinfo. It build when changed from cvars with flag CVAR_USERINFO.
// should we search for cvar here and change it?
MsgDev( D_INFO, "SetInfo: %s %s\n", key, value );
var = (cvar_t *)Cvar_FindVar( key );
if( !var || !(var->flags & CVAR_USERINFO ))
return;
Cvar_DirectSet( var, value );
}
/*
@ -3291,7 +2978,15 @@ NetAPI_InitNetworking
*/
void NetAPI_Status( net_status_t *status )
{
// TODO: implement
ASSERT( status != NULL );
status->connected = NET_IsLocalAddress( cls.netchan.remote_address ) ? false : true;
status->local_address = cls.netchan.remote_address; // FIXME: get local address
status->remote_address = cls.netchan.remote_address;
status->packet_loss = cls.packet_loss / 100; // percent
status->latency = cl.frame.latency;
status->connection_time = cl.time; // FIXME: replace with netchan.first_received
status->rate = cls.netchan.rate;
}
/*
@ -3349,9 +3044,16 @@ void NetAPI_SendRequest( int context, int request, int flags, double timeout, ne
nr->resp.remote_address = *remote_address;
nr->flags = flags;
// send request over the net
Q_snprintf( req, sizeof( req ), "netinfo %i %i %i", PROTOCOL_VERSION, context, request );
Netchan_OutOfBandPrint( NS_CLIENT, nr->resp.remote_address, req );
if( request == NETAPI_REQUEST_SERVERLIST )
{
// UNDONE: build request for master-server
}
else
{
// send request over the net
Q_snprintf( req, sizeof( req ), "netinfo %i %i %i", PROTOCOL_VERSION, context, request );
Netchan_OutOfBandPrint( NS_CLIENT, nr->resp.remote_address, req );
}
}
/*
@ -3450,8 +3152,8 @@ NetAPI_SetValueForKey
*/
void NetAPI_SetValueForKey( char *s, const char *key, const char *value, int maxsize )
{
if( maxsize > MAX_INFO_STRING ) return;
Info_SetValueForKey( s, key, value );
if( key[0] == '*' ) return;
Info_SetValueForStarKey( s, key, value, maxsize );
}

View File

@ -971,6 +971,49 @@ void CL_ParseStatusMessage( netadr_t from, sizebuf_t *msg )
UI_AddServerToList( from, s );
}
/*
=================
CL_ParseNETInfoMessage
Handle a reply from a netinfo
=================
*/
void CL_ParseNETInfoMessage( netadr_t from, sizebuf_t *msg )
{
char *s;
net_request_t *nr;
int context, type;
int i, count = 0;
context = Q_atoi( Cmd_Argv( 1 ));
type = Q_atoi( Cmd_Argv( 2 ));
s = Cmd_Argv( 3 );
// find a request with specified context
for( i = 0; i < MAX_REQUESTS; i++ )
{
nr = &clgame.net_requests[i];
if( nr->resp.context == context && nr->resp.type == type )
{
if( nr->timeout > host.realtime )
{
// setup the answer
nr->resp.response = s;
nr->resp.remote_address = from;
nr->resp.error = NET_SUCCESS;
nr->resp.ping = host.realtime - nr->timesend;
nr->pfnFunc( &nr->resp );
if(!( nr->flags & FNETAPI_MULTIPLE_RESPONSE ))
Q_memset( nr, 0, sizeof( *nr )); // done
}
else Q_memset( nr, 0, sizeof( *nr ));
return;
}
}
}
//===================================================================
/*
@ -1189,6 +1232,11 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
// server responding to a status broadcast
CL_ParseStatusMessage( from, msg );
}
else if( !Q_strcmp( c, "netinfo" ))
{
// server responding to a status broadcast
CL_ParseNETInfoMessage( from, msg );
}
else if( !Q_strcmp( c, "cmd" ))
{
// remote command from gui front end

View File

@ -345,10 +345,9 @@ pfnPIC_Load
=========
*/
static HIMAGE pfnPIC_Load( const char *szPicName, const byte *image_buf, long image_size )
static HIMAGE pfnPIC_Load( const char *szPicName, const byte *image_buf, long image_size, long flags )
{
HIMAGE tx;
int flags = TF_IMAGE;
if( !szPicName || !*szPicName )
{
@ -356,9 +355,8 @@ static HIMAGE pfnPIC_Load( const char *szPicName, const byte *image_buf, long im
return 0;
}
// HACKHACK: keep source for gfx\shell\gamma
if( !glConfig.deviceSupportsGamma && Q_stristr( szPicName, "gamma" ))
flags |= TF_KEEP_RGBDATA;
// add default parms to image
flags |= TF_IMAGE;
host.decal_loading = true;
tx = GL_LoadTexture( szPicName, image_buf, image_size, flags );

View File

@ -16,7 +16,6 @@ GNU General Public License for more details.
#include "common.h"
#include "client.h"
#include "net_encode.h"
#include "event_flags.h"
#include "particledef.h"
#include "gl_local.h"
#include "cl_tent.h"
@ -436,6 +435,12 @@ void CL_ParseStaticDecal( sizebuf_t *msg )
CL_DecalShoot( CL_DecalIndex( decalIndex ), entityIndex, modelIndex, origin, flags );
}
/*
==================
CL_ParseSoundFade
==================
*/
void CL_ParseSoundFade( sizebuf_t *msg )
{
float fadePercent, fadeOutSeconds;
@ -449,31 +454,6 @@ void CL_ParseSoundFade( sizebuf_t *msg )
S_FadeClientVolume( fadePercent, fadeOutSeconds, holdTime, fadeInSeconds );
}
void CL_ParseReliableEvent( sizebuf_t *msg, int flags )
{
int event_index;
event_args_t nullargs, args;
float delay;
Q_memset( &nullargs, 0, sizeof( nullargs ));
event_index = BF_ReadWord( msg ); // read event index
delay = (float)BF_ReadWord( msg ) / 100.0f; // read event delay
MSG_ReadDeltaEvent( msg, &nullargs, &args ); // reliable events not use delta
CL_QueueEvent( flags, event_index, delay, &args );
}
void CL_ParseEvent( sizebuf_t *msg )
{
int i, num_events;
num_events = BF_ReadByte( msg );
// parse events queue
for( i = 0 ; i < num_events; i++ )
CL_ParseReliableEvent( msg, 0 );
}
void CL_ParseCustomization( sizebuf_t *msg )
{
// TODO: ???
@ -1355,7 +1335,7 @@ void CL_ParseServerMessage( sizebuf_t *msg )
CL_ParseEvent( msg );
break;
case svc_event_reliable:
CL_ParseReliableEvent( msg, FEV_RELIABLE );
CL_ParseReliableEvent( msg );
break;
case svc_updateuserinfo:
CL_UpdateUserinfo( msg );

View File

@ -687,7 +687,7 @@ void CL_PredictMovement( void )
if( cls.demoplayback && viewent )
{
// restore viewangles from angles
cl.refdef.cl_viewangles[PITCH] = viewent->angles[PITCH] * 6; // FIXME...
cl.refdef.cl_viewangles[PITCH] = viewent->angles[PITCH] * 6;
cl.refdef.cl_viewangles[YAW] = viewent->angles[YAW];
cl.refdef.cl_viewangles[ROLL] = 0; // roll will be computed in view.cpp
}

View File

@ -23,6 +23,7 @@ GNU General Public License for more details.
#include "gl_local.h"
#include "studio.h"
#include "wadfile.h" // acess decal size
#include "sound.h"
/*
==============================================================
@ -228,7 +229,7 @@ void CL_TEntPlaySound( TEMPENTITY *pTemp, float damp )
else pitch = PITCH_NORM;
handle = S_RegisterSound( soundname );
S_StartSound( pTemp->entity.origin, 0, CHAN_AUTO, handle, fvol, ATTN_NORM, pitch, 0 );
S_StartSound( pTemp->entity.origin, 0, CHAN_STATIC, handle, fvol, ATTN_NORM, pitch, SND_STOP_LOOPING );
}
}
@ -1169,7 +1170,6 @@ void CL_Spray( const vec3_t pos, const vec3_t dir, int modelIndex, int count, in
// more vertical displacement
znoise = noise * 1.5f;
if( znoise > 1 ) znoise = 1;
if( Mod_GetType( modelIndex ) == mod_bad )
@ -1191,6 +1191,7 @@ void CL_Spray( const vec3_t pos, const vec3_t dir, int modelIndex, int count, in
pTemp->entity.curstate.rendermode = renderMode;
pTemp->entity.curstate.renderfx = kRenderFxNoDissipation;
pTemp->entity.curstate.scale = 0.5f;
pTemp->entity.baseline.renderamt = 255;
pTemp->flags |= FTENT_FADEOUT|FTENT_SLOWGRAVITY;
pTemp->fadeSpeed = 2.0f;
@ -1655,14 +1656,52 @@ void CL_PlayerSprites( int client, int modelIndex, int count, int size )
/*
==============
CL_Sprite_WallPuff
CL_FireField
Create a wallpuff
Makes a field of fire
==============
*/
void CL_Sprite_WallPuff( TEMPENTITY *pTemp, float scale )
void CL_FireField( float *org, int radius, int modelIndex, int count, int flags, float life )
{
// TODO: implement
TEMPENTITY *pTemp;
float radius2;
vec3_t dir, m_vecPos;
int i;
for( i = 0; i < count; i++ )
{
dir[0] = Com_RandomFloat( -1.0f, 1.0f );
dir[1] = Com_RandomFloat( -1.0f, 1.0f );
if( flags & TEFIRE_FLAG_PLANAR ) dir[2] = 0.0f;
else dir[2] = Com_RandomFloat( -1.0f, 1.0f );
VectorNormalize( dir );
radius2 = Com_RandomFloat( 0.0f, radius );
VectorMA( org, -radius2, dir, m_vecPos );
pTemp = CL_DefaultSprite( m_vecPos, modelIndex, 0 );
if( !pTemp ) return;
if( flags & TEFIRE_FLAG_ALLFLOAT )
pTemp->entity.baseline.origin[2] = 30; // drift sprite upward
else if( flags & TEFIRE_FLAG_SOMEFLOAT && Com_RandomLong( 0, 1 ))
pTemp->entity.baseline.origin[2] = 30; // drift sprite upward
if( flags & TEFIRE_FLAG_LOOP )
{
pTemp->entity.curstate.framerate = 15;
pTemp->flags |= FTENT_SPRANIMATELOOP;
}
if( flags & TEFIRE_FLAG_ALPHA )
{
pTemp->entity.curstate.rendermode = kRenderTransTexture;
pTemp->entity.curstate.renderamt = 128;
}
pTemp->die += life;
}
}
/*
@ -1674,19 +1713,62 @@ Client version of shotgun shot
*/
void CL_MultiGunshot( const vec3_t org, const vec3_t dir, const vec3_t noise, int count, int decalCount, int *decalIndices )
{
// TODO: implement
pmtrace_t trace;
vec3_t right, up;
vec3_t vecSrc, vecDir, vecEnd;
int i, j, decalIndex;
VectorVectors( dir, right, up );
VectorCopy( org, vecSrc );
for( i = 1; i <= count; i++ )
{
// get circular gaussian spread
float x, y, z;
do {
x = Com_RandomFloat( -0.5f, 0.5f ) + Com_RandomFloat( -0.5f, 0.5f );
y = Com_RandomFloat( -0.5f, 0.5f ) + Com_RandomFloat( -0.5f, 0.5f );
z = x * x + y * y;
} while( z > 1.0f );
for( j = 0; j < 3; j++ )
{
vecDir[j] = dir[i] + x * noise[0] * right[j] + y * noise[1] * up[j];
vecEnd[j] = vecSrc[j] + 2048.0f * vecDir[j];
}
trace = PM_PlayerTrace( clgame.pmove, vecSrc, vecEnd, PM_STUDIO_BOX, 2, -1, NULL );
// paint decals
if( trace.fraction != 1.0f )
{
physent_t *pe;
cl_entity_t *e;
if( trace.ent >= 0 && trace.ent < clgame.pmove->numphysent )
pe = &clgame.pmove->physents[trace.ent];
if( pe && ( pe->solid == SOLID_BSP || pe->movetype == MOVETYPE_PUSHSTEP ))
{
e = CL_GetEntityByIndex( pe->info );
decalIndex = CL_DecalIndex( decalIndices[Com_RandomLong( 0, decalCount-1 )] );
CL_DecalShoot( decalIndex, e->index, 0, trace.endpos, 0 );
}
}
}
}
/*
==============
CL_FireField
CL_Sprite_WallPuff
Makes a field of fire
Create a wallpuff
==============
*/
void CL_FireField( float *org, int radius, int modelIndex, int count, int flags, float life )
void CL_Sprite_WallPuff( TEMPENTITY *pTemp, float scale )
{
// TODO: implement
// UNDONE: g-cont. i'm dont know what this doing
Msg( "CL_Sprite_WallPuff: %g\n", scale );
}
/*
@ -1706,6 +1788,7 @@ void CL_ParseTempEntity( sizebuf_t *msg )
float scale, life, frameRate, vel, random;
float brightness, r, g, b;
vec3_t pos, pos2, ang;
int decalIndices[1]; // just stub
TEMPENTITY *pTemp;
cl_entity_t *pEnt;
dlight_t *dl;
@ -2152,8 +2235,8 @@ void CL_ParseTempEntity( sizebuf_t *msg )
ang[1] = BF_ReadCoord( &buf ) * 0.01f;
ang[2] = 0.0f;
count = BF_ReadByte( &buf );
decalIndex = BF_ReadByte( &buf );
CL_MultiGunshot( pos, pos2, ang, count, 1, &decalIndex );
decalIndices[0] = BF_ReadByte( &buf );
CL_MultiGunshot( pos, pos2, ang, count, 1, decalIndices );
break;
case TE_USERTRACER:
pos[0] = BF_ReadCoord( &buf );

View File

@ -199,7 +199,7 @@ typedef struct
char name[CS_SIZE];
word index; // event index
pfnEventHook func; // user-defined function
} user_event_t;
} cl_user_event_t;
typedef struct
{
@ -239,7 +239,7 @@ typedef struct
typedef struct
{
int gl_texturenum; // this is a real texnum
int gl_texturenum; // this is a real texnum
// scissor test
int scissor_x;
@ -381,7 +381,7 @@ typedef struct
vec3_t player_maxs[4]; // 4 hulls allowed
cl_user_message_t msg[MAX_USER_MESSAGES]; // keep static to avoid fragment memory
user_event_t *events[MAX_EVENTS];
cl_user_event_t *events[MAX_EVENTS];
string cdtracks[MAX_CDTRACKS]; // 32 cd-tracks read from cdaudio.txt
@ -601,6 +601,20 @@ void CL_DeleteDemo_f( void );
void CL_Record_f( void );
void CL_Stop_f( void );
//
// cl_events.c
//
void CL_ParseEvent( sizebuf_t *msg );
void CL_ParseReliableEvent( sizebuf_t *msg );
void CL_SetEventIndex( const char *szEvName, int ev_index );
void CL_QueueEvent( int flags, int index, float delay, event_args_t *args );
void CL_PlaybackEvent( int flags, const edict_t *pInvoker, word eventindex, float delay, float *origin,
float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 );
void CL_RegisterEvent( int lastnum, const char *szEvName, pfnEventHook func );
word CL_EventIndex( const char *name );
void CL_ResetEvent( event_info_t *ei );
void CL_FireEvents( void );
//
// cl_game.c
//
@ -615,7 +629,6 @@ void CL_FreeEdicts( void );
void CL_ClearWorld( void );
void CL_FreeEntity( cl_entity_t *pEdict );
void CL_CenterPrint( const char *text, float y );
void CL_SetEventIndex( const char *szEvName, int ev_index );
void CL_TextMessageParse( byte *pMemFile, int fileSize );
client_textmessage_t *CL_TextMessageGet( const char *pName );
int pfnDecalIndexFromName( const char *szDecalName );
@ -697,8 +710,8 @@ qboolean CL_InitStudioAPI( void );
//
void CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta );
qboolean CL_AddVisibleEntity( cl_entity_t *ent, int entityType );
qboolean CL_GetEntitySpatialization( int ent, vec3_t origin, vec3_t velocity );
void CL_UpdateStudioVars( cl_entity_t *ent, entity_state_t *newstate, qboolean noInterp );
qboolean CL_GetEntitySpatialization( int entnum, vec3_t origin );
void CL_UpdateEntityFields( cl_entity_t *ent );
qboolean CL_IsPlayerIndex( int idx );
@ -721,12 +734,6 @@ void CL_ClearEffects( void );
void CL_TestLights( void );
void CL_DecalShoot( int textureIndex, int entityIndex, int modelIndex, float *pos, int flags );
void CL_PlayerDecal( int textureIndex, int entityIndex, float *pos );
void CL_QueueEvent( int flags, int index, float delay, event_args_t *args );
void CL_PlaybackEvent( int flags, const edict_t *pInvoker, word eventindex, float delay, float *origin,
float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 );
word CL_EventIndex( const char *name );
void CL_ResetEvent( event_info_t *ei );
void CL_FireEvents( void );
void CL_InitParticles( void );
void CL_ClearParticles( void );
void CL_FreeParticles( void );

View File

@ -1099,6 +1099,18 @@ qboolean CL_CullBeam( const vec3_t start, const vec3_t end, qboolean pvsOnly )
vec3_t mins, maxs;
int i;
// support for custom mirror management
if( RI.currententity != NULL )
{
// don't reflect this entity in mirrors
if( RI.currententity->curstate.effects & EF_NOREFLECT && RI.params & RP_MIRRORVIEW )
return true;
// draw only in mirrors
if( RI.currententity->curstate.effects & EF_REFLECTONLY && !( RI.params & RP_MIRRORVIEW ))
return true;
}
for( i = 0; i < 3; i++ )
{
if( start[i] < end[i] )
@ -1561,7 +1573,10 @@ void CL_DrawBeams( int fTrans )
// all params are stored in cl_entity_t
for( i = 0; i < cl.num_custombeams; i++ )
{
cl_entity_t *pBeam = cl_custombeams[i];
cl_entity_t *pBeam;
RI.currententity = pBeam = cl_custombeams[i];
RI.currentmodel = RI.currententity->model;
if( fTrans && pBeam->curstate.renderfx & FBEAM_SOLID )
continue;
@ -1573,6 +1588,9 @@ void CL_DrawBeams( int fTrans )
r_stats.c_view_beams_count++;
}
RI.currententity = NULL;
RI.currentmodel = NULL;
if( !cl_active_beams )
return;

View File

@ -21,6 +21,7 @@ GNU General Public License for more details.
#define DECAL_DISTANCE 4 // too big values produce more clipped polygons
#define MAX_DECALCLIPVERT 32 // produced vertexes of fragmented decal
#define DECAL_CACHEENTRY 256 // MUST BE POWER OF 2 or code below needs to change!
#define DECAL_TRANSPARENT_THRESHOLD 230 // transparent decals draw with GL_MODULATE
// empirically determined constants for minimizing overalpping decals
#define MAX_OVERLAP_DECALS 6
@ -28,87 +29,40 @@ GNU General Public License for more details.
#define FLOAT_TO_SHORT( x ) (short)(x * 32)
#define SHORT_TO_FLOAT( x ) ((float)x * (1.0f/32.0f))
typedef struct
{
vec3_t m_vPos;
vec2_t m_tCoords; // these are the texcoords for the decal itself
vec2_t m_LMCoords; // lightmap texcoords for the decal.
} decalvert_t;
typedef struct
{
qboolean (*pfnInside)( decalvert_t *pVert );
float (*pfnClip)( decalvert_t *one, decalvert_t *two );
} decal_clip_t;
static qboolean Top_Inside( decalvert_t *pVert ){ return pVert->m_tCoords[1] < 1.0f; }
static float Top_Clip( decalvert_t *one, decalvert_t *two ){ return ( 1.0f - one->m_tCoords[1] ) / ( two->m_tCoords[1] - one->m_tCoords[1] ); }
static qboolean Left_Inside( decalvert_t *pVert ){ return pVert->m_tCoords[0] > 0.0f; }
static float Left_Clip( decalvert_t *one, decalvert_t *two ){ return one->m_tCoords[0] / ( one->m_tCoords[0] - two->m_tCoords[0] ); }
static qboolean Right_Inside( decalvert_t *pVert ){ return pVert->m_tCoords[0] < 1.0f; }
static float Right_Clip( decalvert_t *one, decalvert_t *two ){ return ( 1.0f - one->m_tCoords[0] ) / ( two->m_tCoords[0] - one->m_tCoords[0] ); }
static qboolean Bottom_Inside( decalvert_t *pVert ){ return pVert->m_tCoords[1] > 0.0f; }
static float Bottom_Clip( decalvert_t *one, decalvert_t *two ){ return one->m_tCoords[1] / ( one->m_tCoords[1] - two->m_tCoords[1] ); }
// clippanes
static decal_clip_t PlaneTop = { Top_Inside, Top_Clip };
static decal_clip_t PlaneLeft = { Left_Inside, Left_Clip };
static decal_clip_t PlaneRight = { Right_Inside, Right_Clip };
static decal_clip_t PlaneBottom = { Bottom_Inside, Bottom_Clip };
static void Intersect( decal_clip_t clipFunc, decalvert_t *one, decalvert_t *two, decalvert_t *out )
{
float t = clipFunc.pfnClip( one, two );
VectorLerp( one->m_vPos, t, two->m_vPos, out->m_vPos );
Vector2Lerp( one->m_LMCoords, t, two->m_LMCoords, out->m_LMCoords );
Vector2Lerp( one->m_tCoords, t, two->m_tCoords, out->m_tCoords );
}
// clip edges
#define LEFT_EDGE 0
#define RIGHT_EDGE 1
#define TOP_EDGE 2
#define BOTTOM_EDGE 3
// This structure contains the information used to create new decals
typedef struct
{
vec3_t m_Position; // world coordinates of the decal center
vec3_t m_SAxis; // the s axis for the decal in world coordinates
model_t* m_pModel; // the model the decal is going to be applied in
model_t *m_pModel; // the model the decal is going to be applied in
int m_iTexture; // The decal material
int m_Size; // Size of the decal (in world coords)
int m_Flags;
int m_Entity; // Entity the decal is applied to.
float m_scale;
float m_flFadeTime;
float m_flFadeDuration;
int m_decalWidth;
int m_decalHeight;
vec3_t m_Basis[3];
} decalinfo_t;
static decalvert_t g_DecalClipVerts[MAX_DECALCLIPVERT];
static decalvert_t g_DecalClipVerts2[MAX_DECALCLIPVERT];
static byte *r_decalPool; // pool of decal meshes
static float g_DecalClipVerts[MAX_DECALCLIPVERT][VERTEXSIZE];
static float g_DecalClipVerts2[MAX_DECALCLIPVERT][VERTEXSIZE];
static decal_t gDecalPool[MAX_RENDER_DECALS];
static int gDecalCount;
void R_ClearDecals( void )
{
Mem_EmptyPool( r_decalPool );
Q_memset( gDecalPool, 0, sizeof( gDecalPool ));
gDecalCount = 0;
}
// Init the decal pool
void R_InitDecals( void )
{
r_decalPool = Mem_AllocPool( "Decals Mesh Pool" );
R_ClearDecals ();
}
void R_ShutdownDecals( void )
{
Mem_FreePool( &r_decalPool );
}
// unlink pdecal from any surface it's attached to
static void R_DecalUnlink( decal_t *pdecal )
{
@ -142,8 +96,8 @@ static void R_DecalUnlink( decal_t *pdecal )
// Just reuse next decal in list
// A decal that spans multiple surfaces will use multiple decal_t pool entries, as each surface needs
// it's own.
// A decal that spans multiple surfaces will use multiple decal_t pool entries,
// as each surface needs it's own.
static decal_t *R_DecalAlloc( decal_t *pdecal )
{
int limit = MAX_RENDER_DECALS;
@ -249,27 +203,23 @@ void R_SetupDecalTextureSpaceBasis( decal_t *pDecal, msurface_t *surf, int textu
}
// Build the initial list of vertices from the surface verts into the global array, 'verts'.
void R_SetupDecalVertsForMSurface( decal_t *pDecal, msurface_t *surf, vec3_t textureSpaceBasis[3], decalvert_t *pVerts )
void R_SetupDecalVertsForMSurface( decal_t *pDecal, msurface_t *surf, vec3_t textureSpaceBasis[3], float *verts )
{
float *v;
int j;
int i;
v = surf->polys->verts[0];
for( j = 0; j < surf->polys->numverts; j++, v += VERTEXSIZE )
for( i = 0, v = surf->polys->verts[0]; i < surf->polys->numverts; i++, v += VERTEXSIZE, verts += VERTEXSIZE )
{
VectorCopy( v, pVerts[j].m_vPos ); // copy model space coordinates
pVerts[j].m_tCoords[0] = DotProduct( pVerts[j].m_vPos, textureSpaceBasis[0] ) - SHORT_TO_FLOAT( pDecal->dx ) + 0.5f;
pVerts[j].m_tCoords[1] = DotProduct( pVerts[j].m_vPos, textureSpaceBasis[1] ) - SHORT_TO_FLOAT( pDecal->dy ) + 0.5f;
pVerts[j].m_LMCoords[0] = pVerts[j].m_LMCoords[1] = 0.0f;
VectorCopy( v, verts ); // copy model space coordinates
verts[3] = DotProduct( verts, textureSpaceBasis[0] ) - SHORT_TO_FLOAT( pDecal->dx ) + 0.5f;
verts[4] = DotProduct( verts, textureSpaceBasis[1] ) - SHORT_TO_FLOAT( pDecal->dy ) + 0.5f;
verts[5] = verts[6] = 0.0f;
}
}
// Figure out where the decal maps onto the surface.
void R_SetupDecalClip( decalvert_t *pOutVerts, decal_t *pDecal, msurface_t *surf, int texture, vec3_t textureSpaceBasis[3], float decalWorldScale[2] )
void R_SetupDecalClip( decal_t *pDecal, msurface_t *surf, int texture, vec3_t textureSpaceBasis[3], float decalWorldScale[2] )
{
// if ( pOutVerts == NULL )
// pOutVerts = &g_DecalClipVerts[0];
R_SetupDecalTextureSpaceBasis( pDecal, surf, texture, textureSpaceBasis, decalWorldScale );
// Generate texture coordinates for each vertex in decal s,t space
@ -279,64 +229,146 @@ void R_SetupDecalClip( decalvert_t *pOutVerts, decal_t *pDecal, msurface_t *surf
pDecal->dy = FLOAT_TO_SHORT( DotProduct( pDecal->position, textureSpaceBasis[1] ));
}
static int SHClip( decalvert_t *g_DecalClipVerts, int vertCount, decalvert_t *out, decal_clip_t clipFunc )
// Quick and dirty sutherland Hodgman clipper
// Clip polygon to decal in texture space
// JAY: This code is lame, change it later. It does way too much work per frame
// It can be made to recursively call the clipping code and only copy the vertex list once
int R_ClipInside( float *vert, int edge )
{
int j, outCount;
decalvert_t *s, *p;
switch( edge )
{
case LEFT_EDGE:
if( vert[3] > 0.0f )
return 1;
return 0;
case RIGHT_EDGE:
if( vert[3] < 1.0f )
return 1;
return 0;
case TOP_EDGE:
if( vert[4] > 0.0f )
return 1;
return 0;
case BOTTOM_EDGE:
if( vert[4] < 1.0f )
return 1;
return 0;
}
return 0;
}
void R_ClipIntersect( float *one, float *two, float *out, int edge )
{
float t;
// t is the parameter of the line between one and two clipped to the edge
// or the fraction of the clipped point between one & two
// vert[0], vert[1], vert[2] is X, Y, Z
// vert[3] is u
// vert[4] is v
// vert[5] is lightmap u
// vert[6] is lightmap v
if( edge < TOP_EDGE )
{
if( edge == LEFT_EDGE )
{
// left
t = ((one[3] - 0.0f) / (one[3] - two[3]));
out[3] = out[5] = 0.0f;
}
else
{
// right
t = ((one[3] - 1.0f) / (one[3] - two[3]));
out[3] = out[5] = 1.0f;
}
out[4] = one[4] + (two[4] - one[4]) * t;
out[6] = one[6] + (two[6] - one[6]) * t;
}
else
{
if( edge == TOP_EDGE )
{
// top
t = ((one[4] - 0.0f) / (one[4] - two[4]));
out[4] = out[6] = 0.0f;
}
else
{
// bottom
t = ((one[4] - 1.0f) / (one[4] - two[4]));
out[4] = out[6] = 1.0f;
}
out[3] = one[3] + (two[3] - one[3]) * t;
out[5] = one[5] + (two[4] - one[5]) * t;
}
VectorLerp( one, t, two, out );
}
static int SHClip( float *vert, int vertCount, float *out, int edge )
{
int j, outCount;
float *s, *p;
outCount = 0;
s = &g_DecalClipVerts[vertCount - 1];
s = &vert[(vertCount - 1) * VERTEXSIZE];
for( j = 0; j < vertCount; j++ )
for( j = 0; j < vertCount; j++ )
{
p = &g_DecalClipVerts[j];
p = &vert[j * VERTEXSIZE];
if( clipFunc.pfnInside( p ))
if( R_ClipInside( p, edge ))
{
if( clipFunc.pfnInside( s ))
if( R_ClipInside( s, edge ))
{
Q_memcpy( out, p, sizeof( *out ));
// Add a vertex and advance out to next vertex
Q_memcpy( out, p, sizeof( float ) * VERTEXSIZE );
out += VERTEXSIZE;
outCount++;
out++;
}
else
else
{
Intersect( clipFunc, s, p, out );
out++;
R_ClipIntersect( s, p, out, edge );
out += VERTEXSIZE;
outCount++;
Q_memcpy( out, p, sizeof( *out ));
outCount++;
out++;
}
}
else
{
if( clipFunc.pfnInside( s ))
{
Intersect( clipFunc, p, s, out );
out++;
Q_memcpy( out, p, sizeof( float ) * VERTEXSIZE );
out += VERTEXSIZE;
outCount++;
}
}
else
{
if( R_ClipInside( s, edge ))
{
R_ClipIntersect( p, s, out, edge );
out += VERTEXSIZE;
outCount++;
}
}
s = p;
}
return outCount;
}
decalvert_t *R_DoDecalSHClip( decalvert_t *pInVerts, decalvert_t *pOutVerts, decal_t *pDecal, int nStartVerts, int *pVertCount )
float *R_DoDecalSHClip( float *pInVerts, decal_t *pDecal, int nStartVerts, int *pVertCount )
{
int outCount;
if( pOutVerts == NULL )
pOutVerts = &g_DecalClipVerts[0];
float *pOutVerts = g_DecalClipVerts[0];
// clip the polygon to the decal texture space
outCount = SHClip( pInVerts, nStartVerts, &g_DecalClipVerts2[0], PlaneTop );
outCount = SHClip( &g_DecalClipVerts2[0], outCount, &g_DecalClipVerts[0], PlaneLeft );
outCount = SHClip( &g_DecalClipVerts[0], outCount, &g_DecalClipVerts2[0], PlaneRight );
outCount = SHClip( &g_DecalClipVerts2[0], outCount, pOutVerts, PlaneBottom );
outCount = SHClip( pInVerts, nStartVerts, g_DecalClipVerts2[0], LEFT_EDGE );
outCount = SHClip( g_DecalClipVerts2[0], outCount, g_DecalClipVerts[0], RIGHT_EDGE );
outCount = SHClip( g_DecalClipVerts[0], outCount, g_DecalClipVerts2[0], TOP_EDGE );
outCount = SHClip( g_DecalClipVerts2[0], outCount, pOutVerts, BOTTOM_EDGE );
if( outCount )
{
@ -349,16 +381,12 @@ decalvert_t *R_DoDecalSHClip( decalvert_t *pInVerts, decalvert_t *pOutVerts, dec
// should work as well.
if( outCount == 4 )
{
int j, clipped = 0;
decalvert_t *v = pOutVerts;
int j, clipped = 0;
float *v = pOutVerts;
for( j = 0; j < outCount && !clipped; j++, v++ )
for( j = 0; j < outCount && !clipped; j++, v += VERTEXSIZE )
{
float s, t;
s = v->m_tCoords[0];
t = v->m_tCoords[1];
if (( s != 0.0f && s != 1.0f ) || ( t != 0.0f && t != 1.0f ))
if(( v[3] != 0.0f && v[3] != 1.0f ) || ( v[4] != 0.0f && v[4] != 1.0f ))
clipped = 1;
}
@ -370,28 +398,29 @@ decalvert_t *R_DoDecalSHClip( decalvert_t *pInVerts, decalvert_t *pOutVerts, dec
}
*pVertCount = outCount;
return pOutVerts;
}
//-----------------------------------------------------------------------------
// Generate clipped vertex list for decal pdecal projected onto polygon psurf
//-----------------------------------------------------------------------------
decalvert_t *R_DecalVertsClip( decalvert_t *pOutVerts, decal_t *pDecal, msurface_t *surf, int texture, int *pVertCount )
float *R_DecalVertsClip( decal_t *pDecal, msurface_t *surf, int texture, int *pVertCount )
{
float decalWorldScale[2];
vec3_t textureSpaceBasis[3];
// figure out where the decal maps onto the surface.
R_SetupDecalClip( pOutVerts, pDecal, surf, texture, textureSpaceBasis, decalWorldScale );
R_SetupDecalClip( pDecal, surf, texture, textureSpaceBasis, decalWorldScale );
// build the initial list of vertices from the surface verts.
R_SetupDecalVertsForMSurface( pDecal, surf, textureSpaceBasis, g_DecalClipVerts );
R_SetupDecalVertsForMSurface( pDecal, surf, textureSpaceBasis, g_DecalClipVerts[0] );
return R_DoDecalSHClip( g_DecalClipVerts, pOutVerts, pDecal, surf->polys->numverts, pVertCount );
return R_DoDecalSHClip( g_DecalClipVerts[0], pDecal, surf->polys->numverts, pVertCount );
}
// Generate lighting coordinates at each vertex for decal vertices v[] on surface psurf
static void R_DecalVertsLight( decalvert_t *v, msurface_t *surf, int vertCount )
static void R_DecalVertsLight( float *v, msurface_t *surf, int vertCount )
{
float s, t;
mtexinfo_t *tex;
@ -399,31 +428,31 @@ static void R_DecalVertsLight( decalvert_t *v, msurface_t *surf, int vertCount )
tex = surf->texinfo;
for( j = 0; j < vertCount; j++, v++ )
for( j = 0; j < vertCount; j++, v += VERTEXSIZE )
{
// lightmap texture coordinates
s = DotProduct( v->m_vPos, tex->vecs[0] ) + tex->vecs[0][3] - surf->texturemins[0];
s = DotProduct( v, tex->vecs[0] ) + tex->vecs[0][3] - surf->texturemins[0];
s += surf->light_s * LM_SAMPLE_SIZE;
s += LM_SAMPLE_SIZE >> 1;
s /= BLOCK_WIDTH * LM_SAMPLE_SIZE; //fa->texinfo->texture->width;
t = DotProduct( v->m_vPos, tex->vecs[1] ) + tex->vecs[1][3] - surf->texturemins[1];
t = DotProduct( v, tex->vecs[1] ) + tex->vecs[1][3] - surf->texturemins[1];
t += surf->light_t * LM_SAMPLE_SIZE;
t += LM_SAMPLE_SIZE >> 1;
t /= BLOCK_HEIGHT * LM_SAMPLE_SIZE; //fa->texinfo->texture->height;
v->m_LMCoords[0] = s;
v->m_LMCoords[1] = t;
v[5] = s;
v[6] = t;
}
}
static decalvert_t* R_DecalVertsNoclip( decal_t *pdecal, msurface_t *surf, int texture )
static float *R_DecalVertsNoclip( decal_t *pdecal, msurface_t *surf, int texture )
{
decalvert_t *vlist;
int outCount;
float *vlist;
int outCount;
// use the old code for now, and just cache them
vlist = R_DecalVertsClip( NULL, pdecal, surf, texture, &outCount );
vlist = R_DecalVertsClip( pdecal, surf, texture, &outCount );
R_DecalVertsLight( vlist, surf, 4 );
@ -585,7 +614,7 @@ static void R_DecalCreate( decalinfo_t *decalinfo, msurface_t *surf, float x, fl
// check to see if the decal actually intersects the surface
// if not, then remove the decal
R_DecalVertsClip( NULL, pdecal, surf, decalinfo->m_iTexture, &vertCount );
R_DecalVertsClip( pdecal, surf, decalinfo->m_iTexture, &vertCount );
if( !vertCount )
{
@ -820,9 +849,9 @@ void R_DecalShoot( int textureIndex, int entityIndex, int modelIndex, vec3_t pos
// Build the vertex list for a decal on a surface and clip it to the surface.
// This is a template so it can work on world surfaces and dynamic displacement
// triangles the same way.
decalvert_t *R_DecalSetupVerts( decal_t *pDecal, msurface_t *surf, int texture, int *outCount )
float *R_DecalSetupVerts( decal_t *pDecal, msurface_t *surf, int texture, int *outCount )
{
decalvert_t *v;
float *v;
if( pDecal->flags & FDECAL_NOCLIP )
{
@ -831,28 +860,36 @@ decalvert_t *R_DecalSetupVerts( decal_t *pDecal, msurface_t *surf, int texture,
}
else
{
v = R_DecalVertsClip( NULL, pDecal, surf, texture, outCount );
v = R_DecalVertsClip( pDecal, surf, texture, outCount );
if( outCount ) R_DecalVertsLight( v, surf, *outCount );
}
return v;
}
void DrawSingleDecal( decal_t *pDecal, msurface_t *fa )
{
decalvert_t *v;
float *v;
gltexture_t *glt;
int i, numVerts;
v = R_DecalSetupVerts( pDecal, fa, pDecal->texture, &numVerts );
if( !numVerts ) return;
GL_Bind( GL_TEXTURE0, pDecal->texture );
glt = R_GetTexture( pDecal->texture );
// draw transparent decals with GL_MODULATE
if( glt->fogParams[3] > DECAL_TRANSPARENT_THRESHOLD )
pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
else pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
pglBegin( GL_POLYGON );
for( i = 0; i < numVerts; i++, v++ )
for( i = 0; i < numVerts; i++, v += VERTEXSIZE )
{
pglTexCoord2f( v->m_tCoords[0], v->m_tCoords[1] );
pglVertex3fv( v->m_vPos );
pglTexCoord2f( v[3], v[4] );
pglVertex3fv( v );
}
pglEnd();
@ -876,7 +913,6 @@ void DrawSurfaceDecals( msurface_t *fa )
pglEnable( GL_POLYGON_OFFSET_FILL );
pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE ); // try to use GL_MODULATE ?
for( p = fa->pdecals; p; p = p->pnext )
DrawSingleDecal( p, fa );

View File

@ -874,6 +874,12 @@ static void GL_UploadTexture( rgbdata_t *pic, gltexture_t *tex, qboolean subImag
tex->flags &= ~TF_MAKELUMA;
}
if( tex->flags & TF_KEEP_8BIT )
tex->original = FS_CopyImage( pic ); // because current pic will be expanded to rgba
if( tex->flags & TF_KEEP_RGBDATA )
tex->original = pic; // no need to copy
// we need to expand image into RGBA buffer
if( pic->type == PF_INDEXED_24 || pic->type == PF_INDEXED_32 )
img_flags |= IMAGE_FORCE_RGBA;
@ -987,6 +993,7 @@ int GL_LoadTexture( const char *name, const byte *buf, size_t size, int flags )
gltexture_t *tex;
rgbdata_t *pic;
uint i, hash;
uint picFlags = 0;
if( !name || !name[0] || !glw_state.initialized )
return 0;
@ -1015,6 +1022,15 @@ int GL_LoadTexture( const char *name, const byte *buf, size_t size, int flags )
return tex->texnum;
}
if( flags & TF_NOFLIP_TGA )
picFlags |= IL_DONTFLIP_TGA;
if( flags & TF_KEEP_8BIT )
picFlags |= IL_KEEP_8BIT;
// set some image flags
Image_SetForceFlags( picFlags );
pic = FS_LoadImage( name, buf, size );
if( !pic ) return 0; // couldn't loading image
@ -1047,16 +1063,15 @@ int GL_LoadTexture( const char *name, const byte *buf, size_t size, int flags )
GL_UploadTexture( pic, tex, false );
GL_TexFilter( tex, false ); // update texture filter, wrap etc
if( flags & TF_KEEP_RGBDATA )
tex->original = pic;
else FS_FreeImage( pic ); // release source texture
if(!( flags & (TF_KEEP_8BIT|TF_KEEP_RGBDATA)))
FS_FreeImage( pic ); // release source texture
// add to hash table
hash = Com_HashKey( tex->name, TEXTURES_HASH_SIZE );
tex->nextHash = r_texturesHashTable[hash];
r_texturesHashTable[hash] = tex;
// NOTE: always return texnum as index in array or engine will stop work !!!!
// NOTE: always return texnum as index in array or engine will stop work !!!
return i;
}
@ -1159,7 +1174,7 @@ void GL_ProcessTexture( int texnum, float gamma, int topColor, int bottomColor )
ASSERT( texnum > 0 && texnum < MAX_TEXTURES );
image = &r_textures[texnum];
if(!( image->flags & TF_KEEP_RGBDATA ) || !image->original )
if(!( image->flags & (TF_KEEP_RGBDATA|TF_KEEP_8BIT)) || !image->original )
{
MsgDev( D_ERROR, "GL_ProcessTexture: no input data for %s\n", image->name );
return;
@ -1294,7 +1309,7 @@ void GL_FreeTexture( GLenum texnum )
}
// release source
if( image->flags & TF_KEEP_RGBDATA && image->original )
if( image->flags & (TF_KEEP_RGBDATA|TF_KEEP_8BIT) && image->original )
FS_FreeImage( image->original );
pglDeleteTextures( 1, &image->texnum );

View File

@ -73,23 +73,24 @@ typedef enum
typedef enum
{
TF_STATIC = BIT(0), // don't free until Image_FreeUnused()
TF_NOPICMIP = BIT(1), // ignore r_picmip resample rules
TF_UNCOMPRESSED = BIT(2), // don't compress texture in video memory
TF_CUBEMAP = BIT(3), // it's cubemap texture
TF_DEPTHMAP = BIT(4), // custom texture filter used
TF_INTENSITY = BIT(5),
TF_LUMINANCE = BIT(6), // force image to grayscale
TF_SKYSIDE = BIT(7),
TF_CLAMP = BIT(8),
TF_NOMIPMAP = BIT(9),
TF_NEAREST = BIT(10), // disable texfilter
TF_HAS_LUMA = BIT(11), // sets by GL_UploadTexture
TF_MAKELUMA = BIT(12), // create luma from quake texture
TF_NORMALMAP = BIT(13), // is a normalmap
TF_LIGHTMAP = BIT(14), // is a lightmap
TF_FORCE_COLOR = BIT(15), // force upload monochrome textures as RGB (detail textures)
TF_KEEP_RGBDATA = BIT(16), // some images keep source
TF_NEAREST = BIT(0), // disable texfilter
TF_KEEP_RGBDATA = BIT(1), // some images keep source
TF_NOFLIP_TGA = BIT(2), // Steam background completely ignore tga attribute 0x20
TF_KEEP_8BIT = BIT(3), // keep original 8-bit image (if present)
TF_NOPICMIP = BIT(4), // ignore r_picmip resample rules
TF_UNCOMPRESSED = BIT(5), // don't compress texture in video memory
TF_CUBEMAP = BIT(6), // it's cubemap texture
TF_DEPTHMAP = BIT(7), // custom texture filter used
TF_INTENSITY = BIT(8),
TF_LUMINANCE = BIT(9), // force image to grayscale
TF_SKYSIDE = BIT(10),
TF_CLAMP = BIT(11),
TF_NOMIPMAP = BIT(12),
TF_HAS_LUMA = BIT(13), // sets by GL_UploadTexture
TF_MAKELUMA = BIT(14), // create luma from quake texture
TF_NORMALMAP = BIT(15), // is a normalmap
TF_LIGHTMAP = BIT(16), // is a lightmap
TF_FORCE_COLOR = BIT(17), // force upload monochrome textures as RGB (detail textures)
} texFlags_t;
typedef struct gltexture_s
@ -300,8 +301,6 @@ qboolean R_CullSurface( msurface_t *surf, uint clipflags );
//
// gl_decals.c
//
void R_InitDecals( void );
void R_ShutdownDecals( void );
void DrawSurfaceDecals( msurface_t *fa );
void R_ClearDecals( void );

View File

@ -256,8 +256,6 @@ void R_DrawMirrors( void )
r_viewleaf = Mod_PointInLeaf( oldRI.pvsorigin, cl.worldmodel->nodes );
r_viewleaf2 = Mod_PointInLeaf( RI.pvsorigin, cl.worldmodel->nodes );
// FIXME: how to combine two cull origins ?
if( GL_Support( GL_ARB_TEXTURE_NPOT_EXT ))
{
// allow screen size

View File

@ -229,7 +229,7 @@ void R_ScreenToWorld( const vec3_t screen, vec3_t point )
if( !point || !screen )
return;
// FIXME: does we need a full invert here?
// g-cont. does we need a full invert here?
Matrix4x4_Invert_Simple( screenToWorld, RI.worldviewProjectionMatrix );
temp[0] = 2.0f * (screen[0] - RI.viewport[0]) / RI.viewport[2] - 1;
temp[1] = -2.0f * (screen[1] - RI.viewport[1]) / RI.viewport[3] + 1;
@ -859,7 +859,7 @@ static void R_EndGL( void )
R_CheckFog
check for underwater fog
FIXME: this code is wrong, we need to compute fog volumes (as water volumes)
UNDONE: this code is wrong, we need to compute fog volumes (as water volumes)
and get fog params from texture water on a surface.
=============
*/

View File

@ -292,7 +292,6 @@ static void CL_SparkTracerDraw( particle_t *p, float frametime )
static void CL_TracerImplosion( particle_t *p, float frametime )
{
float lifePerc = p->die - cl.time;
float grav = frametime * clgame.movevars.gravity * 0.05f;
float length;
int alpha = 255;
vec3_t delta;
@ -301,7 +300,6 @@ static void CL_TracerImplosion( particle_t *p, float frametime )
length = VectorLength( delta );
if( lifePerc < 0.5f ) alpha = (lifePerc * 2) * 255;
p->vel[2] -= grav; // use slow gravity
CL_DrawTracer( p->org, delta, 1.5f, clgame.palette[p->color], alpha, 0.0f, 0.8f );
VectorMA( p->org, frametime, p->vel, p->org );
@ -1572,7 +1570,7 @@ CL_Implosion
void CL_Implosion( const vec3_t end, float radius, int count, float life )
{
particle_t *p;
float vel;
float vel, radius2;
vec3_t dir, m_vecPos;
int i, colorIndex;
@ -1587,20 +1585,23 @@ void CL_Implosion( const vec3_t end, float radius, int count, float life )
dir[1] = Com_RandomFloat( -1.0f, 1.0f );
dir[2] = Com_RandomFloat( -1.0f, 1.0f );
radius2 = Com_RandomFloat( radius * 0.9f, radius * 1.1f );
VectorNormalize( dir );
VectorMA( end, -radius, dir, m_vecPos );
VectorMA( end, -radius2, dir, m_vecPos );
// velocity based on how far particle has to travel away from org
vel = Com_RandomFloat( radius * 0.5f, radius * 1.5f );
if( life ) vel = (radius2 / life);
else vel = Com_RandomFloat( radius2 * 0.5f, radius2 * 1.5f );
VectorCopy( m_vecPos, p->org );
p->color = colorIndex;
p->ramp = 0.15f; // length based on velocity
p->ramp = (vel / radius2) * 0.1f; // length based on velocity
p->ramp = bound( 0.1f, p->ramp, 1.0f );
VectorScale( dir, vel, p->vel );
// die right when you get there
p->die += ( life != 0.0f ) ? life : ( radius / vel );
p->die += ( life != 0.0f ) ? life : ( radius2 / vel );
}
}

View File

@ -1265,9 +1265,17 @@ void R_StudioSetupChrome( float *pchrome, int bone, vec3_t normal )
if( g_nForceFaceFlags & STUDIO_NF_CHROME )
{
float angle = anglemod( RI.refdef.time * 40 );
RotatePointAroundVector( chromeupvec, tmp, v_left, angle - 180 );
RotatePointAroundVector( chromerightvec, chromeupvec, v_left, 180 + angle );
float angle, sr, cr;
int i;
angle = anglemod( RI.refdef.time * 40 ) * (M_PI * 2.0f / 360.0f);
SinCos( angle, &sr, &cr );
for( i = 0; i < 3; i++ )
{
chromerightvec[i] = (v_left[i] * cr + RI.vup[i] * sr);
chromeupvec[i] = v_left[i] * -sr + RI.vup[i] * cr;
}
}
else
{
@ -1780,7 +1788,7 @@ static void R_StudioDrawPoints( void )
if( g_nForceFaceFlags & STUDIO_NF_CHROME )
{
scale = RI.currententity->curstate.renderamt * (1.0f / 255.0f);
scale = 1.0f + RI.currententity->curstate.renderamt * (1.0f / 255.0f);
for( i = 0; i < m_pSubModel->numnorms; i++ )
Matrix3x4_VectorRotate( g_bonestransform[pnormbone[i]], pstudionorms[i], g_xformnorms[i] );

View File

@ -1665,7 +1665,7 @@ qboolean R_Init( void )
R_InitImages();
R_SpriteInit();
R_StudioInit();
R_InitDecals();
R_ClearDecals();
R_ClearScene();
// initialize screen
@ -1696,7 +1696,6 @@ void R_Shutdown( void )
GL_RemoveCommands();
R_ShutdownImages();
R_ShutdownDecals();
Mem_FreePool( &r_temppool );

View File

@ -20,7 +20,7 @@ GNU General Public License for more details.
#include "ref_params.h"
#define MAX_DUPLICATED_CHANNELS 4 // threshold for identical static channels (probably error)
#define SND_CLIP_DISTANCE 1024.0f
#define SND_CLIP_DISTANCE 1000.0f
dma_t dma;
byte *sndpool;
@ -188,9 +188,7 @@ channel_t *SND_PickDynamicChannel( int entnum, int channel, sfx_t *sfx )
// Never override a streaming sound that is currently playing or
// voice over IP data that is playing or any sound on CHAN_VOICE( acting )
if( ch->sfx && ( ch->entchannel == CHAN_STREAM ))
{
continue;
}
if( channel != CHAN_AUTO && ch->entnum == entnum && ( ch->entchannel == channel || channel == -1 ))
{
@ -371,7 +369,6 @@ void SND_Spatialize( channel_t *ch )
float dist, dot;
float lscale, rscale, scale;
vec3_t source_vec;
sfx_t *snd;
// anything coming from the view entity will allways be full volume
if( S_IsClient( ch->entnum ))
@ -383,12 +380,15 @@ void SND_Spatialize( channel_t *ch )
if( !ch->staticsound )
{
if( !CL_GetEntitySpatialization( ch->entnum, ch->origin, NULL ))
return; // entity not exist on client
if( !CL_GetEntitySpatialization( ch->entnum, ch->origin ))
{
// origin is null and entity not exist on client
ch->leftvol = ch->rightvol = 0;
return;
}
}
// calculate stereo seperation and distance attenuation
snd = ch->sfx;
VectorSubtract( ch->origin, s_listener.origin, source_vec );
dist = VectorNormalizeLength( source_vec ) * ch->dist_mult;
@ -400,11 +400,11 @@ void SND_Spatialize( channel_t *ch )
// add in distance effect
scale = ( 1.0f - dist ) * rscale;
ch->rightvol = (int)( ch->master_vol * scale );
if( ch->rightvol < 0 ) ch->rightvol = 0;
ch->rightvol = bound( 0, ch->rightvol, 255 );
scale = ( 1.0f - dist ) * lscale;
ch->leftvol = (int)( ch->master_vol * scale );
if( ch->leftvol < 0 ) ch->leftvol = 0;
ch->leftvol = bound( 0, ch->leftvol, 255 );
// if playing a word, set volume
VOX_SetChanVol( ch );
@ -591,7 +591,7 @@ void S_AmbientSound( const vec3_t pos, int ent, sound_t handle, float fvol, floa
if( !pos ) pos = origin;
if( ent != 0 ) CL_GetEntitySpatialization( ent, origin, NULL );
if( ent != 0 ) CL_GetEntitySpatialization( ent, origin );
// pick a channel to play on from the static area
ch = SND_PickStaticChannel( ent, sfx, pos );
@ -1103,7 +1103,7 @@ qboolean S_Init( void )
dsp_off = Cvar_Get( "dsp_off", "0", CVAR_ARCHIVE, "set to 1 to disable all dsp processing" );
s_ambient_level = Cvar_Get( "ambient_level", "0.3", 0, "volume of environment noises (water and wind)" );
s_ambient_fade = Cvar_Get( "ambient_fade", "100", 0, "rate of volume fading when client is moving" );
s_combine_sounds = Cvar_Get( "s_combine", "0", CVAR_ARCHIVE, "combine the channels with same sounds" );
s_combine_sounds = Cvar_Get( "s_combine_channels", "1", CVAR_ARCHIVE, "combine the channels with same sounds" );
s_test = Cvar_Get( "s_test", "0", 0, "engine developer cvar for quick testing new features" );
Cmd_AddCommand( "play", S_Play_f, "playing a specified sound file" );

View File

@ -615,8 +615,9 @@ void MIX_MixChannelsToPaintbuffer( int endtime, int rate, int outputRate )
if( CL_GetEntityByIndex( ch->entnum ) && ( ch->entchannel == CHAN_VOICE ))
{
// UNDONE: implement SND_MoveMouth16 too
SND_MoveMouth8( ch, pSource, sampleCount );
if( pSource->width == 1 )
SND_MoveMouth8( ch, pSource, sampleCount );
else SND_MoveMouth16( ch, pSource, sampleCount );
}
// mix channel to all active paintbuffers.

View File

@ -94,6 +94,55 @@ void SND_MoveMouth8( channel_t *ch, wavdata_t *pSource, int count )
pMouth->sndavg += savg;
pMouth->sndcount = (byte)scount;
if( pMouth->sndcount >= CAVGSAMPLES )
{
pMouth->mouthopen = pMouth->sndavg / CAVGSAMPLES;
pMouth->sndavg = 0;
pMouth->sndcount = 0;
}
}
void SND_MoveMouth16( channel_t *ch, wavdata_t *pSource, int count )
{
cl_entity_t *clientEntity;
short *pdata = NULL;
mouth_t *pMouth = NULL;
int savg, data;
int scount, pos = 0;
uint i;
clientEntity = CL_GetEntityByIndex( ch->entnum );
if( !clientEntity ) return;
pMouth = &clientEntity->mouth;
if( ch->isSentence )
{
if( ch->currentWord )
pos = ch->currentWord->sample;
}
else pos = ch->pMixer.sample;
count = S_GetOutputData( pSource, &pdata, pos, count, ch->use_loop );
if( pdata == NULL ) return;
i = 0;
scount = pMouth->sndcount;
savg = 0;
while( i < count && scount < CAVGSAMPLES )
{
data = pdata[i];
data = (bound( -32767, data, 0x7ffe ) >> 8);
savg += abs( data );
i += 80 + ((byte)data & 0x1F);
scount++;
}
pMouth->sndavg += savg;
pMouth->sndcount = (byte)scount;
if( pMouth->sndcount >= CAVGSAMPLES )
{
pMouth->mouthopen = pMouth->sndavg / CAVGSAMPLES;

View File

@ -264,6 +264,7 @@ void S_FreeSounds( void );
//
void SND_InitMouth( int entnum, int entchannel );
void SND_MoveMouth8( channel_t *ch, wavdata_t *pSource, int count );
void SND_MoveMouth16( channel_t *ch, wavdata_t *pSource, int count );
void SND_CloseMouth( channel_t *ch );
//

View File

@ -440,6 +440,7 @@ typedef enum
IL_USE_LERPING = BIT(0), // lerping images during resample
IL_KEEP_8BIT = BIT(1), // don't expand paletted images
IL_ALLOW_OVERWRITE = BIT(2), // allow to overwrite stored images
IL_DONTFLIP_TGA = BIT(3), // Steam background completely ignore tga attribute 0x20 (stupid lammers!)
} ilFlags_t;
// rgbdata output flags
@ -490,9 +491,11 @@ void Image_Init( void );
void Image_Shutdown( void );
rgbdata_t *FS_LoadImage( const char *filename, const byte *buffer, size_t size );
qboolean FS_SaveImage( const char *filename, rgbdata_t *pix );
rgbdata_t *FS_CopyImage( rgbdata_t *in );
void FS_FreeImage( rgbdata_t *pack );
extern const bpc_desc_t PFDesc[]; // image get pixelformat
qboolean Image_Process( rgbdata_t **pix, int width, int height, float gamma, uint flags );
void Image_SetForceFlags( uint flags ); // set image force flags on loading
/*
========================================================================
@ -705,7 +708,6 @@ void CL_CharEvent( int key );
int CL_PointContents( const vec3_t point );
char *COM_ParseFile( char *data, char *token );
byte *COM_LoadFile( const char *filename, int usehunk, int *pLength );
qboolean CL_GetEntitySpatialization( int entnum, vec3_t origin, vec3_t velocity );
void CL_StudioEvent( struct mstudioevent_s *event, struct cl_entity_s *ent );
qboolean CL_GetComment( const char *demoname, char *comment );
void COM_AddAppDirectoryToSearchPath( const char *pszBaseDir, const char *appName );
@ -749,6 +751,7 @@ char *Info_ValueForKey( const char *s, const char *key );
void Info_RemovePrefixedKeys( char *start, char prefix );
qboolean Info_RemoveKey( char *s, const char *key );
qboolean Info_SetValueForKey( char *s, const char *key, const char *value );
qboolean Info_SetValueForStarKey( char *s, const char *key, const char *value, int maxsize );
qboolean Info_Validate( const char *s );
void Info_Print( const char *s );
char *Cvar_Userinfo( void );

View File

@ -118,7 +118,7 @@ qboolean Cmd_GetMapList( const char *s, char *completedname, int length )
{
// if there are entities to parse, a missing message key just
// means there is no title, so clear the message string now
char token[1024];
char token[2048];
message[0] = 0;
pfile = ents;
@ -709,7 +709,7 @@ qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
{
// if there are entities to parse, a missing message key just
// means there is no title, so clear the message string now
char token[1024];
char token[2048];
qboolean worldspawn = true;
Q_strncpy( message, "No Title", MAX_STRING );

View File

@ -94,6 +94,7 @@ typedef struct imglib_s
image_hint_t hint; // hint for some loaders
byte *tempbuffer; // for convert operations
int cmd_flags;
int force_flags; // user-specified force flags
} imglib_t;
/*
@ -283,5 +284,6 @@ byte *Image_Copy( size_t size );
void Image_CopyParms( rgbdata_t *src );
qboolean Image_ValidSize( const char *name );
qboolean Image_LumpValidSize( const char *name );
qboolean Image_CheckFlag( int bit );
#endif//IMAGELIB_H

View File

@ -124,7 +124,7 @@ qboolean Image_LoadBMP( const char *name, const byte *buffer, size_t filesize )
}
}
if( image.cmd_flags & IL_KEEP_8BIT && bhdr.bitsPerPixel == 8 )
if( Image_CheckFlag( IL_KEEP_8BIT ) && bhdr.bitsPerPixel == 8 )
{
pixbuf = image.palette = Mem_Alloc( host.imagepool, 1024 );
image.flags |= IMAGE_HAS_COLOR;
@ -235,7 +235,7 @@ qboolean Image_LoadBMP( const char *name, const byte *buffer, size_t filesize )
blue = palette[palIndex][0];
alpha = palette[palIndex][3];
if( image.cmd_flags & IL_KEEP_8BIT )
if( Image_CheckFlag( IL_KEEP_8BIT ))
{
*pixbuf++ = palIndex;
}
@ -280,7 +280,7 @@ qboolean Image_LoadBMP( const char *name, const byte *buffer, size_t filesize )
Mem_Free( image.rgba );
return false;
}
if(!( image.cmd_flags & IL_KEEP_8BIT ) && ( red != green || green != blue ))
if( !Image_CheckFlag( IL_KEEP_8BIT ) && ( red != green || green != blue ))
image.flags |= IMAGE_HAS_COLOR;
}
buf_p += padSize; // actual only for 4-bit bmps
@ -304,7 +304,7 @@ qboolean Image_SaveBMP( const char *name, rgbdata_t *pix )
int pixel_size;
int i, x, y;
if( FS_FileExists( name, false ) && !(image.cmd_flags & IL_ALLOW_OVERWRITE ))
if( FS_FileExists( name, false ) && !Image_CheckFlag( IL_ALLOW_OVERWRITE ))
return false; // already existed
// bogus parameter check

View File

@ -118,6 +118,9 @@ rgbdata_t *ImagePack( void )
{
rgbdata_t *pack = Mem_Alloc( host.imagepool, sizeof( rgbdata_t ));
// clear any force flags
image.force_flags = 0;
if( image.cubemap && image.num_sides != 6 )
{
// this neved be happens, just in case
@ -339,6 +342,9 @@ load_internal:
else if( filename[0] != '#' )
MsgDev( D_WARN, "FS_LoadImage: couldn't load \"%s\"\n", loadname );
// clear any force flags
image.force_flags = 0;
return NULL;
}
@ -356,7 +362,13 @@ qboolean FS_SaveImage( const char *filename, rgbdata_t *pix )
string path, savename;
const savepixformat_t *format;
if( !pix || !pix->buffer || anyformat ) return false;
if( !pix || !pix->buffer || anyformat )
{
// clear any force flags
image.force_flags = 0;
return false;
}
Q_strncpy( savename, filename, sizeof( savename ));
FS_StripExtension( savename ); // remove extension if needed
@ -371,7 +383,12 @@ qboolean FS_SaveImage( const char *filename, rgbdata_t *pix )
box = skybox_qv1;
else if( pix->flags & IMAGE_CUBEMAP )
box = cubemap_v2;
else return false; // do not happens
else
{
// clear any force flags
image.force_flags = 0;
return false; // do not happens
}
pix->size /= 6; // now set as side size
picBuffer = pix->buffer;
@ -392,6 +409,9 @@ qboolean FS_SaveImage( const char *filename, rgbdata_t *pix )
pix->size = realSize;
pix->buffer = picBuffer;
// clear any force flags
image.force_flags = 0;
return ( i == 6 );
}
}
@ -403,10 +423,19 @@ qboolean FS_SaveImage( const char *filename, rgbdata_t *pix )
if( !Q_stricmp( ext, format->ext ))
{
Q_sprintf( path, format->formatstring, savename, "", format->ext );
if( format->savefunc( path, pix )) return true; // saved
if( format->savefunc( path, pix ))
{
// clear any force flags
image.force_flags = 0;
return true; // saved
}
}
}
}
// clear any force flags
image.force_flags = 0;
return false;
}
@ -426,4 +455,46 @@ void FS_FreeImage( rgbdata_t *pack )
Mem_Free( pack );
}
else MsgDev( D_WARN, "FS_FreeImage: trying to free NULL image\n" );
}
/*
================
FS_CopyImage
make an image copy
================
*/
rgbdata_t *FS_CopyImage( rgbdata_t *in )
{
rgbdata_t *out;
int palSize = 0;
if( !in ) return NULL;
out = Mem_Alloc( host.imagepool, sizeof( rgbdata_t ));
*out = *in;
switch( in->type )
{
case PF_INDEXED_24:
palSize = 768;
break;
case PF_INDEXED_32:
palSize = 1024;
break;
}
if( palSize )
{
out->palette = Mem_Alloc( host.imagepool, palSize );
Q_memcpy( out->palette, in->palette, palSize );
}
if( in->size )
{
out->buffer = Mem_Alloc( host.imagepool, in->size );
Q_memcpy( out->buffer, in->buffer, in->size );
}
return out;
}

View File

@ -126,7 +126,7 @@ qboolean Image_LoadTGA( const char *name, const byte *buffer, size_t filesize )
targa_rgba = image.rgba = Mem_Alloc( host.imagepool, image.size );
// if bit 5 of attributes isn't set, the image has been stored from bottom to top
if( targa_header.attributes & 0x20 )
if( !Image_CheckFlag( IL_DONTFLIP_TGA ) && targa_header.attributes & 0x20 )
{
pixbuf = targa_rgba;
row_inc = 0;
@ -221,7 +221,7 @@ qboolean Image_SaveTGA( const char *name, rgbdata_t *pix )
byte *buffer, *out;
const char *comment = "Generated by Xash ImageLib\0";
if( FS_FileExists( name, false ) && !( image.cmd_flags & IL_ALLOW_OVERWRITE ))
if( FS_FileExists( name, false ) && !Image_CheckFlag( IL_ALLOW_OVERWRITE ))
return false; // already existed
if( pix->flags & IMAGE_HAS_ALPHA )

View File

@ -167,28 +167,40 @@ byte *Image_Copy( size_t size )
/*
=================
Image_NearestPOW
Image_CheckFlag
=================
*/
int Image_NearestPOW( int value, qboolean roundDown )
qboolean Image_CheckFlag( int bit )
{
int n = 1;
if( image.force_flags & bit )
return true;
if( value <= 0 ) return 1;
while( n < value ) n <<= 1;
if( image.cmd_flags & bit )
return true;
if( roundDown )
{
if( n > value ) n >>= 1;
}
return n;
return false;
}
/*
=================
Image_SetForceFlags
=================
*/
void Image_SetForceFlags( uint flags )
{
image.force_flags = flags;
}
/*
=================
Image_RoundDimensions
=================
*/
void Image_RoundDimensions( int *width, int *height )
{
// find nearest power of two, rounding down if desired
*width = Image_NearestPOW( *width, gl_round_down->integer );
*height = Image_NearestPOW( *height, gl_round_down->integer );
*width = NearestPOW( *width, gl_round_down->integer );
*height = NearestPOW( *height, gl_round_down->integer );
}
qboolean Image_ValidSize( const char *name )
@ -871,7 +883,7 @@ Image_Resample
*/
byte *Image_ResampleInternal( const void *indata, int inwidth, int inheight, int outwidth, int outheight, int type, qboolean *resampled )
{
qboolean quality = (image.cmd_flags & IL_USE_LERPING);
qboolean quality = Image_CheckFlag( IL_USE_LERPING );
// nothing to resample ?
if( inwidth == outwidth && inheight == outheight )
@ -915,7 +927,7 @@ Image_Flood
*/
byte *Image_FloodInternal( const byte *indata, int inwidth, int inheight, int outwidth, int outheight, int type, qboolean *resampled )
{
qboolean quality = (image.cmd_flags & IL_USE_LERPING);
qboolean quality = Image_CheckFlag( IL_USE_LERPING );
int samples = PFDesc[type].bpp;
int newsize, x, y, i;
byte *in, *out;
@ -1087,7 +1099,7 @@ qboolean Image_AddIndexedImageToPack( const byte *in, int width, int height )
int mipsize = width * height;
qboolean expand_to_rgba = true;
if( image.cmd_flags & IL_KEEP_8BIT )
if( Image_CheckFlag( IL_KEEP_8BIT ))
expand_to_rgba = false;
else if( host.type == HOST_NORMAL && ( image.flags & ( IMAGE_HAS_LUMA|IMAGE_QUAKESKY )))
expand_to_rgba = false;
@ -1243,10 +1255,16 @@ qboolean Image_Process( rgbdata_t **pix, int width, int height, float gamma, uin
if( !pic || !pic->buffer )
{
MsgDev( D_WARN, "Image_Process: NULL image\n" );
image.force_flags = 0;
return false;
}
if( !flags ) return false; // no operation specfied
if( !flags )
{
// clear any force flags
image.force_flags = 0;
return false; // no operation specfied
}
if( flags & IMAGE_MAKE_LUMA )
{
@ -1282,8 +1300,8 @@ qboolean Image_Process( rgbdata_t **pix, int width, int height, float gamma, uin
if( flags & IMAGE_ROUNDFILLER )
{
// roundfiller always must roundup
w = Image_NearestPOW( w, false );
h = Image_NearestPOW( h, false );
w = NearestPOW( w, false );
h = NearestPOW( h, false );
}
else Image_RoundDimensions( &w, &h );
@ -1313,5 +1331,8 @@ qboolean Image_Process( rgbdata_t **pix, int width, int height, float gamma, uin
}
*pix = pic;
// clear any force flags
image.force_flags = 0;
return result;
}

View File

@ -14,6 +14,7 @@ GNU General Public License for more details.
*/
#include "imagelib.h"
#include "mathlib.h"
#include "wadfile.h"
#include "studio.h"
#include "sprite.h"
@ -474,6 +475,16 @@ qboolean Image_LoadMIP( const char *name, const byte *buffer, size_t filesize )
// grab the fog density
image.fogParams[3] = pal[4*3+0];
}
else if( host.decal_loading )
{
// grab the decal color
image.fogParams[0] = pal[255*3+0];
image.fogParams[1] = pal[255*3+1];
image.fogParams[2] = pal[255*3+2];
// calc the decal reflectivity
image.fogParams[3] = VectorAvg( image.fogParams );
}
image.type = PF_INDEXED_32; // 32-bit palete
return Image_AddIndexedImageToPack( fin, image.width, image.height );

View File

@ -214,10 +214,10 @@ qboolean Info_Validate( const char *s )
return true;
}
qboolean Info_SetValueForKey( char *s, const char *key, const char *value )
qboolean Info_SetValueForStarKey( char *s, const char *key, const char *value, int maxsize )
{
char newi[MAX_INFO_STRING], *v;
int c, maxsize = MAX_INFO_STRING;
char new[1024], *v;
int c;
if( Q_strstr( key, "\\" ) || Q_strstr( value, "\\" ))
{
@ -243,12 +243,24 @@ qboolean Info_SetValueForKey( char *s, const char *key, const char *value )
return false;
}
Info_RemoveKey( s, key );
if( !value || !Q_strlen( value ))
return true; // just clear variable
// this next line is kinda trippy
if( *(v = Info_ValueForKey( s, key )))
{
// key exists, make sure we have enough room for new value, if we don't, don't change it!
if( Q_strlen( value ) - Q_strlen( v ) + Q_strlen( s ) > maxsize )
{
MsgDev( D_ERROR, "SetValueForKey: info string length exceeded\n" );
return false;
}
}
Q_snprintf( newi, sizeof( newi ) - 1, "\\%s\\%s", key, value );
if( Q_strlen( newi ) + Q_strlen( s ) > maxsize )
Info_RemoveKey( s, key );
if( !value || !Q_strlen( value ))
return true; // just clear variable
Q_snprintf( new, sizeof( new ) - 1, "\\%s\\%s", key, value );
if( Q_strlen( new ) + Q_strlen( s ) > maxsize )
{
MsgDev( D_ERROR, "SetValueForKey: info string length exceeded\n" );
return true; // info changed, new value can't saved
@ -256,7 +268,7 @@ qboolean Info_SetValueForKey( char *s, const char *key, const char *value )
// only copy ascii values
s += Q_strlen( s );
v = newi;
v = new;
while( *v )
{
@ -271,6 +283,17 @@ qboolean Info_SetValueForKey( char *s, const char *key, const char *value )
return true;
}
qboolean Info_SetValueForKey( char *s, const char *key, const char *value )
{
if( key[0] == '*' )
{
MsgDev( D_ERROR, "Can't set *keys\n" );
return false;
}
return Info_SetValueForStarKey( s, key, value, MAX_INFO_STRING );
}
static void Cvar_LookupBitInfo( const char *name, const char *string, const char *info, void *unused )
{
Info_SetValueForKey( (char *)info, name, string );

View File

@ -119,23 +119,22 @@ float VectorNormalizeLength2( const vec3_t v, vec3_t out )
out[1] = v[1] * ilength;
out[2] = v[2] * ilength;
}
else out[0] = out[1] = out[2] = 0.0f;
return length;
}
void VectorVectors( vec3_t forward, vec3_t right, vec3_t up )
void VectorVectors( const vec3_t forward, vec3_t right, vec3_t up )
{
float d;
float d;
right[0] = forward[2];
right[1] = -forward[0];
right[2] = forward[1];
d = DotProduct(forward, right);
VectorMA(right, -d, forward, right);
VectorNormalize(right);
CrossProduct(right, forward, up);
d = DotProduct( forward, right );
VectorMA( right, -d, forward, right );
VectorNormalize( right );
CrossProduct( right, forward, up );
}
/*

View File

@ -105,7 +105,7 @@ int SignbitsForPlane( const vec3_t normal );
int NearestPOW( int value, qboolean roundDown );
void SinCos( float radians, float *sine, float *cosine );
float VectorNormalizeLength2( const vec3_t v, vec3_t out );
void VectorVectors( vec3_t forward, vec3_t right, vec3_t up );
void VectorVectors( const vec3_t forward, vec3_t right, vec3_t up );
void VectorAngles( const float *forward, float *angles );
void AngleVectors( const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up );
void VectorsAngles( const vec3_t forward, const vec3_t right, const vec3_t up, vec3_t angles );

View File

@ -774,7 +774,6 @@ void Delta_InitFields( void )
Mem_Free( afile );
// adding some requrid fields fields that user may forget or don't know how to specified
Delta_AddField( "event_t", "flags", DT_INTEGER, 8, 1.0f, 1.0f );
Delta_AddField( "event_t", "velocity[0]", DT_SIGNED | DT_FLOAT, 16, 8.0f, 1.0f );
Delta_AddField( "event_t", "velocity[1]", DT_SIGNED | DT_FLOAT, 16, 8.0f, 1.0f );
Delta_AddField( "event_t", "velocity[2]", DT_SIGNED | DT_FLOAT, 16, 8.0f, 1.0f );
@ -793,7 +792,7 @@ void Delta_Init( void )
dt = Delta_FindStruct( "movevars_t" );
ASSERT( dt != NULL );
if( dt->bInitialized ) return; // specified by user
if( dt->bInitialized ) return; // "movevars_t" already specified by user
// create movevars_t delta internal
Delta_AddField( "movevars_t", "gravity", DT_FLOAT|DT_SIGNED, 16, 8.0f, 1.0f );

View File

@ -589,7 +589,7 @@ static int NET_IPSocket( const char *netInterface, int port )
struct sockaddr_in addr;
dword _true = 1;
MsgDev( D_INFO, "NET_UDPSocket( %s, %i )\n", netInterface, port );
MsgDev( D_NOTE, "NET_UDPSocket( %s, %i )\n", netInterface, port );
if(( net_socket = pSocket( PF_INET, SOCK_DGRAM, IPPROTO_UDP )) == SOCKET_ERROR )
{
@ -681,7 +681,7 @@ static int NET_IPXSocket( int port )
int _true = 1;
int err;
MsgDev( D_INFO, "NET_IPXSocket( %i )\n", port );
MsgDev( D_NOTE, "NET_IPXSocket( %i )\n", port );
if(( net_socket = pSocket( PF_IPX, SOCK_DGRAM, NSPROTO_IPX )) == SOCKET_ERROR )
{

View File

@ -16,7 +16,7 @@ GNU General Public License for more details.
#ifndef PROTOCOL_H
#define PROTOCOL_H
#define PROTOCOL_VERSION 42
#define PROTOCOL_VERSION 43
// server to client
#define svc_bad 0 // immediately crash client when received
@ -100,6 +100,9 @@ GNU General Public License for more details.
#define MAX_SOUND_BITS 11
#define MAX_SOUNDS (1<<MAX_SOUND_BITS) // 11 bits == 2048 sounds
#define MAX_ENTITY_BITS 12
#define MAX_EDICTS (1<<MAX_ENTITY_BITS)// 12 bits = 4096 edicts
#define MAX_CUSTOM 1024 // max custom resources per level
#define MAX_USER_MESSAGES 191 // another 63 messages reserved for engine routines
@ -107,7 +110,6 @@ GNU General Public License for more details.
#define MAX_DLIGHTS 32 // dynamic lights (rendered per one frame)
#define MAX_ELIGHTS 64 // entity only point lights
#define MAX_LIGHTSTYLES 256 // a byte limit, don't modify
#define MAX_EDICTS 4096 // absolute limit, should be enough. (can be up to 32768)
#define MAX_RENDER_DECALS 4096 // max rendering decals per a level
// sound flags

View File

@ -340,6 +340,13 @@ void CL_TextMessageParse( byte *pMemFile, int fileSize )
textHeapSize += Q_strlen( textMessages[i].pMessage ) + 1;
messageSize = ( messageCount * sizeof( client_textmessage_t ));
if(( textHeapSize + nameHeapSize + messageSize ) <= 0 )
{
clgame.titles = NULL;
clgame.numTitles = 0;
return;
}
// must malloc because we need to be able to clear it after initialization
clgame.titles = (client_textmessage_t *)Mem_Alloc( cls.mempool, textHeapSize + nameHeapSize + messageSize );

View File

@ -130,6 +130,10 @@ SOURCE=.\client\cl_demo.c
# End Source File
# Begin Source File
SOURCE=.\client\cl_events.c
# End Source File
# Begin Source File
SOURCE=.\client\cl_frame.c
# End Source File
# Begin Source File

View File

@ -22,6 +22,12 @@ GNU General Public License for more details.
typedef int HIMAGE; // handle to a graphic
// flags for PIC_Load
#define PIC_NEAREST (1<<0) // disable texfilter
#define PIC_KEEP_RGBDATA (1<<1) // some images keep source
#define PIC_NOFLIP_TGA (1<<2) // Steam background completely ignore tga attribute 0x20
#define PIC_KEEP_8BIT (1<<3) // keep original 8-bit image (if present)
typedef struct ui_globalvars_s
{
float time; // unclamped host.realtime
@ -41,7 +47,7 @@ typedef struct ui_globalvars_s
typedef struct ui_enginefuncs_s
{
// image handlers
HIMAGE (*pfnPIC_Load)( const char *szPicName, const byte *ucRawImage, long ulRawImageSize );
HIMAGE (*pfnPIC_Load)( const char *szPicName, const byte *ucRawImage, long ulRawImageSize, long flags );
void (*pfnPIC_Free)( const char *szPicName );
int (*pfnPIC_Width)( HIMAGE hPic );
int (*pfnPIC_Height)( HIMAGE hPic );

View File

@ -529,7 +529,7 @@ void SV_SetMinMaxSize( edict_t *e, const float *min, const float *max );
void SV_CreateDecal( const float *origin, int decalIndex, int entityIndex, int modelIndex, int flags );
void SV_PlaybackEventFull( int flags, const edict_t *pInvoker, word eventindex, float delay, float *origin,
float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 );
void SV_PlaybackEvent( sizebuf_t *msg, event_info_t *info );
void SV_PlaybackReliableEvent( sizebuf_t *msg, word eventindex, float delay, event_args_t *args );
void SV_BaselineForEntity( edict_t *pEdict );
void SV_WriteEntityPatch( const char *filename );
char *SV_ReadEntityScript( const char *filename, int *flags );

View File

@ -17,6 +17,7 @@ GNU General Public License for more details.
#include "const.h"
#include "server.h"
#include "net_encode.h"
#include "net_api.h"
const char *clc_strings[9] =
{
@ -635,15 +636,6 @@ void SV_Info( netadr_t from )
Netchan_OutOfBandPrint( NS_SERVER, from, "info\n%s", string );
}
const char *net_requests[5] =
{
"serverlist",
"ping",
"rules",
"players",
"details",
};
/*
================
SV_BuildNetAnswer
@ -653,7 +645,7 @@ Responds with long info for local and broadcast requests
*/
void SV_BuildNetAnswer( netadr_t from )
{
char string[MAX_INFO_STRING];
char string[MAX_INFO_STRING], answer[512];
int version, context, type;
int i, count = 0;
@ -665,8 +657,56 @@ void SV_BuildNetAnswer( netadr_t from )
context = Q_atoi( Cmd_Argv( 2 ));
type = Q_atoi( Cmd_Argv( 3 ));
Msg( "Receive client request (protocol %i, context %i, type %s\n", version, context, net_requests[type] );
string[0] = '\0';
if( version != PROTOCOL_VERSION )
return;
if( type == NETAPI_REQUEST_PING )
{
Q_snprintf( answer, sizeof( answer ), "netinfo %i %i\n", context, type );
Netchan_OutOfBandPrint( NS_SERVER, from, answer ); // no info string
}
else if( type == NETAPI_REQUEST_RULES )
{
// send serverinfo
Q_snprintf( answer, sizeof( answer ), "netinfo %i %i %s\n", context, type, Cvar_Serverinfo( ));
Netchan_OutOfBandPrint( NS_SERVER, from, answer ); // no info string
}
else if( type == NETAPI_REQUEST_PLAYERS )
{
string[0] = '\0';
for( i = 0; i < sv_maxclients->integer; i++ )
{
if( svs.clients[i].state >= cs_connected )
{
edict_t *ed = svs.clients[i].edict;
float time = host.realtime - svs.clients[i].lastconnect;
Q_strncat( string, va( "%c\\%s\\%i\\%f\\", count, svs.clients[i].name, ed->v.frags, time ), sizeof( string ));
count++;
}
}
// send playernames
Q_snprintf( answer, sizeof( answer ), "netinfo %i %i %s\n", context, type, string );
Netchan_OutOfBandPrint( NS_SERVER, from, answer ); // no info string
}
else if( type == NETAPI_REQUEST_DETAILS )
{
for( i = 0; i < sv_maxclients->integer; i++ )
if( svs.clients[i].state >= cs_connected )
count++;
string[0] = '\0';
Info_SetValueForKey( string, "hostname", hostname->string );
Info_SetValueForKey( string, "gamedir", GI->gamefolder );
Info_SetValueForKey( string, "current", va( "%i", count ));
Info_SetValueForKey( string, "max", va( "%i", sv_maxclients->integer ));
Info_SetValueForKey( string, "map", sv.name );
// send serverinfo
Q_snprintf( answer, sizeof( answer ), "netinfo %i %i %s\n", context, type, string );
Netchan_OutOfBandPrint( NS_SERVER, from, answer ); // no info string
}
}
/*
@ -2111,6 +2151,10 @@ void SV_ExecuteClientMessage( sv_client_t *cl, sizebuf_t *msg )
}
cl->delta_sequence = -1; // no delta unless requested
// set the current client
svs.currentPlayer = cl;
svs.currentPlayerNum = (cl - svs.clients);
// read optional clientCommand strings
while( cl->state != cs_zombie )

View File

@ -738,8 +738,8 @@ void SV_PlayersOnly_f( void )
sv.hostflags = sv.hostflags ^ SVF_PLAYERSONLY;
if(!( sv.hostflags & SVF_PLAYERSONLY ))
SV_BroadcastPrintf( D_INFO, "Resume server physic" );
else SV_BroadcastPrintf( D_INFO, "Freeze server physic" );
SV_BroadcastPrintf( D_INFO, "Resume server physic\n" );
else SV_BroadcastPrintf( D_INFO, "Freeze server physic\n" );
}
void SV_EdictsInfo_f( void )

View File

@ -268,45 +268,116 @@ SV_EmitEvents
*/
static void SV_EmitEvents( sv_client_t *cl, client_frame_t *to, sizebuf_t *msg )
{
int i, ev;
event_state_t *es;
event_info_t *info;
entity_state_t *state;
event_args_t nullargs;
int ev_count = 0;
int c;
int count, ent_index;
int i, j, ev;
Q_memset( &nullargs, 0, sizeof( nullargs ));
es = &cl->events;
// count events
for( ev = 0; ev < MAX_EVENT_QUEUE; ev++ )
{
info = &es->ei[ev];
if( info->index == 0 )
continue;
ev_count++;
if( es->ei[ev].index ) ev_count++;
}
// nothing to send
if( !ev_count ) return;
if( !ev_count ) return; // nothing to send
if( ev_count >= MAX_EVENT_QUEUE )
ev_count = MAX_EVENT_QUEUE - 1;
if( ev_count >= 31 ) ev_count = 31;
for( i = 0; i < MAX_EVENT_QUEUE; i++ )
{
info = &es->ei[i];
if( info->index == 0 )
continue;
ent_index = info->entity_index;
for( j = 0; j < to->num_entities; j++ )
{
state = &svs.packet_entities[(to->first_entity+j)%svs.num_client_entities];
if( state->number == ent_index )
break;
}
if( j >= to->num_entities )
{
// couldn't find
info->packet_index = to->num_entities;
info->args.entindex = ent_index;
}
else
{
info->packet_index = j;
info->args.ducking = 0;
if(!( info->args.flags & FEVENT_ORIGIN ))
VectorClear( info->args.origin );
if(!( info->args.flags & FEVENT_ANGLES ))
VectorClear( info->args.angles );
VectorClear( info->args.velocity );
}
}
BF_WriteByte( msg, svc_event ); // create message
BF_WriteByte( msg, ev_count ); // Up to MAX_EVENT_QUEUE events
BF_WriteUBitLong( msg, ev_count, 5 ); // up to MAX_EVENT_QUEUE events
for( i = c = 0 ; i < MAX_EVENT_QUEUE; i++ )
for( count = i = 0; i < MAX_EVENT_QUEUE; i++ )
{
info = &es->ei[i];
if( info->index == 0 )
{
info->packet_index = -1;
info->entity_index = -1;
continue;
}
// only send if there's room
if ( c < ev_count )
SV_PlaybackEvent( msg, info );
if( count < ev_count )
{
BF_WriteUBitLong( msg, info->index, MAX_EVENT_BITS ); // 1024 events
if( info->packet_index == -1 )
{
BF_WriteOneBit( msg, 0 );
}
else
{
BF_WriteOneBit( msg, 1 );
BF_WriteUBitLong( msg, info->packet_index, MAX_ENTITY_BITS );
if( !memcmp( &nullargs, &info->args, sizeof( event_args_t )))
{
BF_WriteOneBit( msg, 0 );
}
else
{
BF_WriteOneBit( msg, 1 );
MSG_WriteDeltaEvent( msg, &nullargs, &info->args );
}
}
if( info->fire_time )
{
BF_WriteOneBit( msg, 1 );
BF_WriteWord( msg, Q_rint( info->fire_time * 100.0f ));
}
else BF_WriteOneBit( msg, 0 );
}
info->index = 0;
c++;
info->packet_index = -1;
info->entity_index = -1;
count++;
}
}

View File

@ -605,7 +605,7 @@ int SV_MapIsValid( const char *filename, const char *spawn_entity, const char *l
{
// if there are entities to parse, a missing message key just
// means there is no title, so clear the message string now
char token[1024];
char token[2048];
string check_name;
qboolean need_landmark = Q_strlen( landmark_name ) > 0 ? true : false;
@ -795,18 +795,30 @@ void SV_FreeEdicts( void )
}
}
void SV_PlaybackEvent( sizebuf_t *msg, event_info_t *info )
void SV_PlaybackReliableEvent( sizebuf_t *msg, word eventindex, float delay, event_args_t *args )
{
event_args_t nullargs;
ASSERT( msg );
ASSERT( info );
ASSERT( args );
Q_memset( &nullargs, 0, sizeof( nullargs ));
BF_WriteWord( msg, info->index ); // send event index
BF_WriteWord( msg, (int)( info->fire_time * 100.0f )); // send event delay
MSG_WriteDeltaEvent( msg, &nullargs, &info->args ); // reliable events not use delta
BF_WriteByte( msg, svc_event_reliable );
// send event index
BF_WriteUBitLong( msg, eventindex, MAX_EVENT_BITS );
if( delay )
{
// send event delay
BF_WriteOneBit( msg, 1 );
BF_WriteWord( msg, Q_rint( delay * 100.0f ));
}
else BF_WriteOneBit( msg, 0 );
// reliable events not use delta-compression just null-compression
MSG_WriteDeltaEvent( msg, &nullargs, args );
}
const char *SV_ClassName( const edict_t *e )
@ -1761,33 +1773,14 @@ void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float
if( attn != ATTN_NONE ) flags |= SND_ATTENUATION;
if( pitch != PITCH_NORM ) flags |= SND_PITCH;
// ultimate method for detect bsp models with invalid solidity (e.g. func_pushable)
if( Mod_GetType( ent->v.modelindex ) == mod_brush )
{
VectorAverage( ent->v.absmin, ent->v.absmax, origin );
VectorAverage( ent->v.mins, ent->v.maxs, origin );
VectorAdd( origin, ent->v.origin, origin );
if( flags & SND_SPAWNING )
{
msg_dest = MSG_INIT;
}
else
{
if( chan == CHAN_STATIC )
msg_dest = MSG_ALL;
else msg_dest = MSG_PAS_R;
}
}
else
{
VectorAverage( ent->v.mins, ent->v.maxs, origin );
VectorAdd( origin, ent->v.origin, origin );
if( flags & SND_SPAWNING )
{
msg_dest = MSG_INIT;
}
else msg_dest = MSG_PAS_R;
}
if( flags & SND_SPAWNING )
msg_dest = MSG_INIT;
else if( chan == CHAN_STATIC )
msg_dest = MSG_ALL;
else msg_dest = MSG_PAS_R;
// always sending stop sound command
if( flags & SND_STOP ) msg_dest = MSG_ALL;
@ -1845,7 +1838,6 @@ void pfnEmitAmbientSound( edict_t *ent, float *pos, const char *sample, float vo
{
int number = 0, sound_idx;
int msg_dest = MSG_PAS_R;
vec3_t origin;
if( !sample ) return;
@ -1870,24 +1862,8 @@ void pfnEmitAmbientSound( edict_t *ent, float *pos, const char *sample, float vo
msg_dest = MSG_INIT;
else msg_dest = MSG_ALL;
// ultimate method for detect bsp models with invalid solidity (e.g. func_pushable)
if( SV_IsValidEdict( ent ))
{
if( Mod_GetType( ent->v.modelindex ) == mod_brush )
{
VectorAverage( ent->v.absmin, ent->v.absmax, origin );
number = NUM_FOR_EDICT( ent );
}
else
{
VectorAverage( ent->v.mins, ent->v.maxs, origin );
VectorAdd( origin, ent->v.origin, origin );
}
}
else
{
VectorCopy( pos, origin );
}
number = NUM_FOR_EDICT( ent );
// always sending stop sound command
if( flags & SND_STOP ) msg_dest = MSG_ALL;
@ -1929,7 +1905,7 @@ void pfnEmitAmbientSound( edict_t *ent, float *pos, const char *sample, float vo
BF_WriteWord( &sv.multicast, number );
BF_WriteBitVec3Coord( &sv.multicast, pos );
SV_Send( msg_dest, origin, NULL );
SV_Send( msg_dest, pos, NULL );
}
/*
@ -3285,7 +3261,7 @@ pfnRunPlayerMove
*/
void pfnRunPlayerMove( edict_t *pClient, const float *v_angle, float fmove, float smove, float upmove, word buttons, byte impulse, byte msec )
{
sv_client_t *cl;
sv_client_t *cl, *oldcl;
usercmd_t cmd;
uint seed;
@ -3300,6 +3276,11 @@ void pfnRunPlayerMove( edict_t *pClient, const float *v_angle, float fmove, floa
if( !cl->fakeclient )
return; // only fakeclients allows
oldcl = svs.currentPlayer;
svs.currentPlayer = SV_ClientFromEdict( pClient, true );
svs.currentPlayerNum = (svs.currentPlayer - svs.clients);
Q_memset( &cmd, 0, sizeof( cmd ));
if( v_angle ) VectorCopy( v_angle, cmd.viewangles );
cmd.forwardmove = fmove;
@ -3317,6 +3298,9 @@ void pfnRunPlayerMove( edict_t *pClient, const float *v_angle, float fmove, floa
cl->lastcmd = cmd;
cl->lastcmd.buttons = 0; // avoid multiple fires on lag
svs.currentPlayer = oldcl;
svs.currentPlayerNum = (svs.currentPlayer - svs.clients);
}
/*
@ -3466,10 +3450,13 @@ void SV_PlaybackEventFull( int flags, const edict_t *pInvoker, word eventindex,
event_info_t *ei = NULL;
float *viewOrg = NULL;
int j, leafnum, slot, bestslot;
int invokerIndex = 0;
int invokerIndex;
byte *mask = NULL;
vec3_t pvspoint;
if( flags & FEV_CLIENT )
return; // someone stupid joke
// first check event for out of bounds
if( eventindex < 1 || eventindex > MAX_EVENTS )
{
@ -3484,13 +3471,21 @@ void SV_PlaybackEventFull( int flags, const edict_t *pInvoker, word eventindex,
return;
}
args.flags = 0;
if( SV_IsValidEdict( pInvoker ))
args.entindex = NUM_FOR_EDICT( pInvoker );
else args.entindex = 0;
VectorCopy( origin, args.origin );
VectorCopy( angles, args.angles );
Q_memset( &args, 0, sizeof( args ));
if( origin && !VectorIsNull( origin ))
{
VectorCopy( origin, args.origin );
args.flags |= FEVENT_ORIGIN;
}
if( angles && !VectorIsNull( angles ))
{
VectorCopy( angles, args.angles );
args.flags |= FEVENT_ORIGIN;
}
// copy other parms
args.fparam1 = fparam1;
args.fparam2 = fparam2;
args.iparam1 = iparam1;
@ -3498,24 +3493,38 @@ void SV_PlaybackEventFull( int flags, const edict_t *pInvoker, word eventindex,
args.bparam1 = bparam1;
args.bparam2 = bparam2;
if(!( flags & FEV_GLOBAL ))
VectorClear( pvspoint );
if( SV_IsValidEdict( pInvoker ))
{
VectorCopy( pInvoker->v.origin, pvspoint );
args.entindex = invokerIndex = NUM_FOR_EDICT( pInvoker );
// g-cont. allow 'ducking' param for all entities
args.ducking = (pInvoker->v.flags & FL_DUCKING) ? true : false;
// this will be send only for reliable event
if(!( args.flags & FEVENT_ORIGIN ))
VectorCopy( pInvoker->v.origin, args.origin );
// this will be send only for reliable event
if(!( args.flags & FEVENT_ANGLES ))
VectorCopy( pInvoker->v.angles, args.angles );
if( sv_sendvelocity->integer )
VectorCopy( pInvoker->v.velocity, args.velocity );
}
else
{
VectorCopy( args.origin, pvspoint );
args.entindex = 0;
invokerIndex = -1;
}
if(!( flags & FEV_GLOBAL ) && VectorIsNull( pvspoint ))
{
// PVS message - trying to get a pvspoint
// args.origin always have higher priority than invoker->origin
if( !VectorIsNull( args.origin ))
{
VectorCopy( args.origin, pvspoint );
}
else if( SV_IsValidEdict( pInvoker ))
{
VectorCopy( pInvoker->v.origin, pvspoint );
}
else
{
const char *ev_name = sv.event_precache[eventindex];
MsgDev( D_ERROR, "%s: not a FEV_GLOBAL event missing origin. Ignored.\n", ev_name );
return;
}
MsgDev( D_ERROR, "%s: not a FEV_GLOBAL event missing origin. Ignored.\n", sv.event_precache[eventindex] );
return;
}
// check event for some user errors
@ -3525,47 +3534,21 @@ void SV_PlaybackEventFull( int flags, const edict_t *pInvoker, word eventindex,
{
const char *ev_name = sv.event_precache[eventindex];
if( flags & FEV_NOTHOST )
{
MsgDev( D_WARN, "%s: specified FEV_NOTHOST when invoker not a client\n", ev_name );
flags &= ~FEV_NOTHOST;
}
if( flags & FEV_HOSTONLY )
{
MsgDev( D_WARN, "%s: specified FEV_HOSTONLY when invoker not a client\n", ev_name );
// pInvoker isn't a client
flags &= ~(FEV_NOTHOST|FEV_HOSTONLY);
flags &= ~FEV_HOSTONLY;
}
}
}
flags |= FEV_SERVER; // it's a server event!
if( delay < 0.0f ) delay = 0.0f; // fixup negative delays
if( SV_IsValidEdict( pInvoker ))
invokerIndex = NUM_FOR_EDICT( pInvoker );
if( flags & FEV_RELIABLE )
{
VectorClear( args.velocity );
args.ducking = 0;
}
else if( invokerIndex )
{
// get up some info from invoker
if( VectorIsNull( args.origin ))
VectorCopy( pInvoker->v.origin, args.origin );
if( VectorIsNull( args.angles ))
{
if( SV_ClientFromEdict( pInvoker, true ))
VectorCopy( pInvoker->v.v_angle, args.angles );
else VectorCopy( pInvoker->v.angles, args.angles );
}
else if( SV_ClientFromEdict( pInvoker, true ) && VectorCompare( pInvoker->v.angles, args.angles ))
{
// NOTE: if user specified pPlayer->pev->angles
// silently replace it with viewangles, client expected this
VectorCopy( pInvoker->v.v_angle, args.angles );
}
if( sv_sendvelocity->integer ) VectorCopy( pInvoker->v.velocity, args.velocity );
args.ducking = (pInvoker->v.flags & FL_DUCKING) ? true : false;
}
flags |= FEV_SERVER; // it's a server event!
if( delay < 0.0f ) delay = 0.0f; // fixup negative delays
if(!( flags & FEV_GLOBAL ))
{
@ -3582,19 +3565,14 @@ void SV_PlaybackEventFull( int flags, const edict_t *pInvoker, word eventindex,
if( cl->state != cs_spawned || !cl->edict || cl->fakeclient )
continue;
if( flags & FEV_NOTHOST && cl->edict == pInvoker && cl->local_weapons )
continue; // will be played on client side
if( flags & FEV_HOSTONLY && cl->edict != pInvoker )
continue; // sending only to invoker
if( SV_IsValidEdict( pInvoker ) && pInvoker->v.groupinfo && cl->edict->v.groupinfo )
{
if(( !svs.groupop && !(cl->edict->v.groupinfo & pInvoker->v.groupinfo)) || ( svs.groupop == 1 && ( cl->edict->v.groupinfo & pInvoker->v.groupinfo )))
if(( svs.groupop == 0 && (cl->edict->v.groupinfo & pInvoker->v.groupinfo) == 0 )
|| ( svs.groupop == 1 && (cl->edict->v.groupinfo & pInvoker->v.groupinfo) == 1 ))
continue;
}
if( mask && !( flags & FEV_GLOBAL ))
if( mask && SV_IsValidEdict( pInvoker ))
{
int clientnum;
@ -3611,23 +3589,19 @@ void SV_PlaybackEventFull( int flags, const edict_t *pInvoker, word eventindex,
continue;
}
if( flags & FEV_NOTHOST && cl == svs.currentPlayer && cl->local_weapons )
continue; // will be played on client side
if( flags & FEV_HOSTONLY && cl->edict != pInvoker )
continue; // sending only to invoker
// all checks passed, send the event
// reliable event
if( flags & FEV_RELIABLE )
{
event_info_t info;
info.index = eventindex;
info.fire_time = delay;
info.args = args;
info.entity_index = invokerIndex;
info.packet_index = -1;
info.flags = 0; // server ignore flags
// skipping queue, write in reliable datagram
BF_WriteByte( &cl->netchan.message, svc_event_reliable );
SV_PlaybackEvent( &cl->netchan.message, &info );
// skipping queue, write direct into reliable datagram
SV_PlaybackReliableEvent( &cl->netchan.message, eventindex, delay, &args );
continue;
}
@ -3635,27 +3609,50 @@ void SV_PlaybackEventFull( int flags, const edict_t *pInvoker, word eventindex,
es = &cl->events;
bestslot = -1;
for( j = 0; j < MAX_EVENT_QUEUE; j++ )
if( flags & FEV_UPDATE )
{
ei = &es->ei[j];
if( ei->index == 0 )
for( j = 0; j < MAX_EVENT_QUEUE; j++ )
{
// found an empty slot
bestslot = j;
break;
ei = &es->ei[j];
if( ei->index == eventindex && invokerIndex != -1 && invokerIndex == ei->entity_index )
{
bestslot = j;
break;
}
}
}
if( bestslot == -1 )
{
for( j = 0; j < MAX_EVENT_QUEUE; j++ )
{
ei = &es->ei[j];
if( ei->index == 0 )
{
// found an empty slot
bestslot = j;
break;
}
}
// g-cont. probably this code never calls (and not needs)
if( bestslot != -1 && j == MAX_EVENT_QUEUE )
{
ei = &es->ei[bestslot];
}
}
// no slot found for this player, oh well
if( bestslot == -1 ) continue;
// add event to queue
ei->index = eventindex;
ei->fire_time = delay;
ei->args = args;
ei->entity_index = invokerIndex;
ei->packet_index = -1;
ei->flags = 0; // server ignore flags
ei->flags = flags;
ei->args = args;
}
}
@ -4335,7 +4332,7 @@ qboolean SV_ParseEdict( char **pfile, edict_t *ent )
KeyValueData pkvd[256]; // per one entity
int i, numpairs = 0;
const char *classname = NULL;
char token[1024];
char token[2048];
// go through all the dictionary pairs
while( 1 )
@ -4447,7 +4444,7 @@ parsing textual entity definitions out of an ent file.
*/
void SV_LoadFromFile( char *entities )
{
string token;
char token[2048];
int inhibited, spawned;
qboolean create_world = true;
edict_t *ent;

View File

@ -361,6 +361,7 @@ void SV_ReadPackets( void )
{
cl->lastmessage = host.realtime; // don't timeout
SV_ExecuteClientMessage( cl, &net_message );
svgame.globals->frametime = host.frametime;
}
}
@ -632,9 +633,9 @@ void SV_Init( void )
SV_InitOperatorCommands();
Cvar_Get ("skill", "1", CVAR_LATCH, "game skill level" );
Cvar_Get ("deathmatch", "0", CVAR_LATCH|CVAR_SERVERNOTIFY, "displays deathmatch state" );
Cvar_Get ("teamplay", "0", CVAR_LATCH|CVAR_SERVERNOTIFY, "displays teamplay state" );
Cvar_Get ("coop", "0", CVAR_LATCH|CVAR_SERVERNOTIFY, "displays cooperative state" );
Cvar_Get ("deathmatch", "0", CVAR_LATCH|CVAR_SERVERINFO, "displays deathmatch state" );
Cvar_Get ("teamplay", "0", CVAR_LATCH|CVAR_SERVERINFO, "displays teamplay state" );
Cvar_Get ("coop", "0", CVAR_LATCH|CVAR_SERVERINFO, "displays cooperative state" );
Cvar_Get ("protocol", va( "%i", PROTOCOL_VERSION ), CVAR_INIT, "displays server protocol version" );
Cvar_Get ("defaultmap", "", CVAR_SERVERNOTIFY, "holds the multiplayer mapname" );
Cvar_Get ("showtriggers", "0", CVAR_LATCH, "debug cvar shows triggers" );
@ -672,7 +673,7 @@ void SV_Init( void )
rcon_password = Cvar_Get( "rcon_password", "", 0, "remote connect password" );
sv_stepsize = Cvar_Get( "sv_stepsize", "18", CVAR_ARCHIVE|CVAR_PHYSICINFO, "how high you can step up" );
sv_newunit = Cvar_Get( "sv_newunit", "0", 0, "sets to 1 while new unit is loading" );
hostname = Cvar_Get( "hostname", "unnamed", CVAR_SERVERINFO|CVAR_SERVERNOTIFY|CVAR_ARCHIVE, "host name" );
hostname = Cvar_Get( "hostname", "unnamed", CVAR_SERVERNOTIFY|CVAR_SERVERNOTIFY|CVAR_ARCHIVE, "host name" );
timeout = Cvar_Get( "timeout", "125", CVAR_SERVERNOTIFY, "connection timeout" );
zombietime = Cvar_Get( "zombietime", "2", CVAR_SERVERNOTIFY, "timeout for clients-zombie (who died but not respawned)" );
sv_pausable = Cvar_Get( "pausable", "1", CVAR_SERVERNOTIFY, "allow players to pause or not" );

View File

@ -1710,7 +1710,6 @@ void SV_Physics( void )
if( sv_skyspeed->value )
{
// evaluate sky rotation.
// FIXME: ignore this feature in multiplayer to save traffic?
float skyAngle = sv_skyangle->value + sv_skyspeed->value * host.frametime;
Cvar_SetFloat( "sv_skyangle", anglemod( skyAngle ));
}

View File

@ -17,6 +17,7 @@ GNU General Public License for more details.
#include "server.h"
#include "const.h"
#include "pm_local.h"
#include "event_flags.h"
static qboolean has_update = false;
@ -382,6 +383,9 @@ static void pfnPlaybackEventFull( int flags, int clientindex, word eventindex, f
ent = EDICT_NUM( clientindex + 1 );
if( !SV_IsValidEdict( ent )) return;
if( host.type == HOST_DEDICATED )
flags |= FEV_NOTHOST; // no local clients for dedicated server
SV_PlaybackEventFull( flags, ent, eventindex,
delay, origin, angles,
fparam1, fparam2,
@ -971,8 +975,6 @@ void SV_PostRunCmd( sv_client_t *cl )
svgame.dllFuncs.pfnSpectatorThink( clent );
else svgame.dllFuncs.pfnPlayerPostThink( clent );
// restore frametime
svgame.globals->time = sv.time + host.frametime;
svgame.globals->frametime = host.frametime;
svgame.dllFuncs.pfnCmdEnd( cl->edict );
}

View File

@ -129,8 +129,8 @@ hull_t *SV_HullForEntity( edict_t *ent, int hullNumber, vec3_t mins, vec3_t maxs
if( model && ( ent->v.solid == SOLID_BSP || ent->v.skin == CONTENTS_LADDER ))
{
// explicit hulls in the BSP model
if( ent->v.movetype != MOVETYPE_PUSH )
Host_Error( "SOLID_BSP without MOVETYPE_PUSH\n" );
if( ent->v.movetype != MOVETYPE_PUSH && ent->v.movetype != MOVETYPE_PUSHSTEP )
Host_Error( "SOLID_BSP without MOVETYPE_PUSH or MOVETYPE_PUSHSTEP\n" );
if( model->type != mod_brush )
Host_Error( "MOVETYPE_PUSH with a non bsp model\n" );

View File

@ -396,7 +396,7 @@ void UI_LoadBackgroundImage( void )
{
bimage_t &bimage = uiStatic.m_SteamBackground[y][x];
sprintf(filename, "resource/background/800_%d_%c_loading.tga", y + 1, 'a' + x);
bimage.hImage = PIC_Load( filename );
bimage.hImage = PIC_Load( filename, PIC_NOFLIP_TGA );
bimage.width = PIC_Width( bimage.hImage );
bimage.height = PIC_Height( bimage.hImage );

View File

@ -39,14 +39,14 @@ GNU General Public License for more details.
#define GetLogoHeight (*g_engfuncs.pfnGetLogoHeight)
#define GetLogoLength (*g_engfuncs.pfnGetLogoLength)
inline HIMAGE PIC_Load( const char *szPicName )
inline HIMAGE PIC_Load( const char *szPicName, long flags = 0 )
{
return g_engfuncs.pfnPIC_Load( szPicName, NULL, 0 );
return g_engfuncs.pfnPIC_Load( szPicName, NULL, 0, flags );
}
inline HIMAGE PIC_Load( const char *szPicName, const byte *ucRawImage, long ulRawImageSize )
inline HIMAGE PIC_Load( const char *szPicName, const byte *ucRawImage, long ulRawImageSize, long flags = 0 )
{
return g_engfuncs.pfnPIC_Load( szPicName, ucRawImage, ulRawImageSize );
return g_engfuncs.pfnPIC_Load( szPicName, ucRawImage, ulRawImageSize, flags );
}
#define PIC_Free (*g_engfuncs.pfnPIC_Free)
@ -173,6 +173,7 @@ inline void TextMessageSetColor( int r, int g, int b, int alpha = 255 )
#define DrawConsoleString (*g_engfuncs.pfnDrawConsoleString)
#define GetConsoleStringSize (*g_engfuncs.pfnDrawConsoleStringLen)
#define ConsoleSetColor (*g_engfuncs.pfnSetConsoleDefaultColor)
#define PIC_SetFlags (*g_engfuncs.pfnPIC_SetFlags)
#define RANDOM_LONG (*g_engfuncs.pfnRandomLong)
#define RANDOM_FLOAT (*g_engfuncs.pfnRandomFloat)

View File

@ -200,7 +200,7 @@ static void UI_VidOptions_Init( void )
{
memset( &uiVidOptions, 0, sizeof( uiVidOptions_t ));
uiVidOptions.hTestImage = PIC_Load( ART_GAMMA );
uiVidOptions.hTestImage = PIC_Load( ART_GAMMA, PIC_KEEP_RGBDATA );
uiVidOptions.menu.vidInitFunc = UI_VidOptions_Init;