Compare commits

...
Author SHA1 Message Date
Alibek Omarov bb734456f6 engine: client: avi: use typeof() to declare function pointers to ffmpeg API 2026-04-09 09:52:52 +05:00
Alibek Omarov a219ca7371 ci: upgrade ffmpeg binary to 8.1 2026-04-09 09:20:25 +05:00
OlegandAlibek Omarov c3b5e43a7a engine: client: avi: bump FFMPEG symbols 2026-04-09 09:14:04 +05:00
Alibek Omarov e7597d2e84 Merge branch 'theevolk-feature-soundapi' of github.com:ShadowOfEVolk/xash3d-fwgs 2026-04-08 17:18:03 +05:00
TheEVolk 386ca1b9bb engine: client: make sound api const 2026-04-08 14:27:24 +03:00
TheEVolk da3960c4f0 engine: client: move bitflag definitions to sound_api 2026-04-08 14:15:16 +03:00
TheEVolk cd85762b09 engine: client: fix arm builds 2026-04-08 14:11:44 +03:00
TheEVolk d92b3a730c engine: client: adapt sound api to snd globals 2026-04-08 14:02:10 +03:00
Alibek Omarov ffa53f14e5 engine: platform: sdl2: implement continuous background recalibration for gyroscope 2026-04-08 11:31:01 +05:00
Alibek Omarov b8bd906832 engine: menu_int: fix a typo 2026-04-08 11:19:13 +05:00
Alibek Omarov 1c73d8d6f4 engine: client: add joy_debug, tool that visualizes gamepad input 2026-04-08 11:13:07 +05:00
Alibek Omarov 2c3fdb5eee engine: client: in_joy: clear gyro data after each FinalizeMove, only take data when calibration status is set to calibrated 2026-04-08 10:30:32 +05:00
Alibek Omarov 4bbe52e3b4 engine: client: in_joy: fix engine-level axis rebinding 2026-04-08 10:22:12 +05:00
Alibek Omarov 2d241ed96b engine: platform: sdl2: fix calibraion never ending if it was failed, lower sample count requirements to 50%, fix gyro when using PS5 controller over Bluetooth 2026-04-08 10:22:12 +05:00
Alibek Omarov ba4bce06b1 engine: platform: sdl2: swap pitch and yaw gamepads axis, following the fix in 626a7eb9108376a68c2fd140e1b5942c64ea1e66 2026-04-08 10:22:12 +05:00
Владислав Суховanda1batross f7e933aea1 engine: client: add gyroscope aiming support
refactor: standardize input functions to use (pitch, yaw) parameter order
2026-04-08 10:22:12 +05:00
Alibek Omarov dbcf77c9a9 engine: cleanup, disallow exec for multiplayer non-TFC games 2026-04-08 08:22:01 +05:00
w_sh1tandAlibek Omarov 8a9aa2da6c engine: common: add wildcard support for exec command, add amount of frames to wait in wait command 2026-04-08 08:05:42 +05:00
Alibek Omarov 0e8143aefc ref: gl: remove duplicate line from if-else branches in R_MarkLeaves 2026-04-08 08:05:00 +05:00
TheEVolk 4345e9e6a6 Merge remote-tracking branch 'upstream/master' into theevolk-feature-soundapi 2026-04-07 18:35:39 +03:00
Alibek Omarov e7fa45d5ca ref: gl: fix masked textures with VBO 2026-04-06 11:12:09 +05:00
Alibek Omarov abda0a07c2 ref: gl: cache worldmodel pointer instead of accessing it through gp_cl pointer 2026-04-06 11:07:08 +05:00
Alibek Omarov 9d22827395 ref: gl: reorganize checks in R_CullSurface 2026-04-06 11:04:33 +05:00
Alibek Omarov 7b665b3763 ref: gl: track max height of a dynamic lightmap 2026-04-06 10:04:15 +05:00
Alibek Omarov 58692f397a ref: gl: reorganize R_CheckLightMap to exit early for dlighted surfaces 2026-04-06 09:40:19 +05:00
Alibek Omarov 2253fcc955 ref: gl: skip redundant positions in LM_AllocBlock 2026-04-06 09:05:47 +05:00
Alibek Omarov cbbae0c9bf ref: gl: simplify backface culling checks in frustum class 2026-04-06 08:25:45 +05:00
Alibek Omarov ef513f27ac engine: simplify node recursion functions, do not fetch both children at once if only one is used 2026-04-06 08:16:51 +05:00
Alibek Omarov e8ae48fd3d ref: simplify node recursion functions, do not fetch both children at once if only one is used 2026-04-06 08:16:20 +05:00
Alibek Omarov 434e508186 engine: client: reserve some free space in channel_t and rawchan_t 2026-04-06 07:27:50 +05:00
Alibek Omarov 4a2b3e89b4 engine: client: disable NET_EXT_SPLITSIZE in local game, for slightly better performance 2026-04-06 07:14:06 +05:00
Alibek Omarov 6c3f8c7ec5 engine: mod_bmodel: allow nearest on quake skybox 2026-04-06 06:55:52 +05:00
Alibek Omarov 3fffe061d5 engine: client: switch to dynamically allocating vox words, freeing up 320 Kb of memory 2026-04-06 06:55:27 +05:00
Alibek Omarov 729c985eaf engine: client: consolidate dma, s_listener and bunch of separate sound globals into one snd global struct. Replace bit fields with bit flags in preparation for SoundAPI
Remove s_combine_sounds, it never worked great and was disabled by default.
2026-04-06 06:00:48 +05:00
Alibek Omarov 75fb6c5f34 engine: add Mem_Free2 that takes a pointer to pointer and then sets it to NULL 2026-04-06 05:14:33 +05:00
Alibek Omarov 8bc9b1865a engine: client: allow custom paths in cdaudio.txt 2026-04-05 07:03:46 +05:00
Alibek Omarov d6993c47d6 engine: mod_bmodel: do not try to load visibility if there is none, like for external bmodels 2026-04-05 07:03:46 +05:00
Alibek Omarov b8792e4084 filesystem: set qwrap as falldir for Quake games 2026-04-05 07:03:46 +05:00
Alibek Omarov 2234dd48bc engine: client: soundlib: use unsigned int in GetLittleLong to fix ubsan error 2026-04-05 07:03:46 +05:00
Alibek Omarov c8693e1e89 engine: common: fix char array underflow, on Q_strlen() - 1 2026-04-05 07:03:46 +05:00
Alibek Omarov 3ace4a61d2 ref: gl: fix harmless NULL pointer dereference in alias model loading code 2026-04-05 07:03:46 +05:00
Alibek Omarov bd3f865cf7 engine: mod_bmodel: only look for BSPX lumps if BSPX header was found 2026-04-05 07:03:46 +05:00
Alibek Omarov b68e71abfd engine: net_chan: explicitly convert qboolean to uint before right shift to 31 bits 2026-04-05 07:03:46 +05:00
Alibek Omarov 6179bef160 engine: fix possible buffer overflow when looking for BSPX header 2026-04-05 07:03:46 +05:00
Alibek Omarov 983427ebb3 engine: client: allow coloring fixed font text 2026-04-05 07:03:46 +05:00
Alibek Omarov 1b2ab34745 engine: client: keep TF_NEAREST enabled for console font, if HUD font failed to load 2026-04-05 07:03:46 +05:00
Alibek Omarov 2713f03ec2 filesystem: fix Quake gamedir check if pak0.pak is written in uppercase, omitting caseinsensitive FS emulation as is VFS is not enabled at this stage 2026-04-05 07:03:46 +05:00
Alibek Omarov 238083c174 engine: client: move common server message handlers to CL_ParseCommonMessage and only HL specific ones to CL_ParseCommonHLMessage (previously CL_ParseCommonDLLMessage) 2026-04-05 07:03:46 +05:00
Alibek Omarov 78de3ee6d9 engine: client: initialize cl_textmessage at compile-time 2026-04-05 07:03:46 +05:00
Alibek Omarov 695081e079 3rdparty: library_suffix: update 2026-04-05 07:03:46 +05:00
TheEVolk 2c5e2e1ded engine: client: remove sound_t definition from sound.h 2026-04-04 18:30:14 +03:00
TheEVolk d151c48d1f engine: client: fix api issues 2026-04-04 17:47:54 +03:00
TheEVolk 35998bce81 engine: client: add sound api 2026-04-04 16:08:31 +03:00
Alibek Omarov a10520ca9e engine: host: add message when native game libraries weren't found but libraries for x86 windows, linux or macos were, telling that the mod probably require custom logic code 2026-04-04 17:37:48 +05:00
Alibek Omarov cb4a03ded2 engine: platform: add Platform_LibraryExists and implement it for iOS and generally for everything else with FS_FileExists 2026-04-04 17:37:48 +05:00
Alibek Omarov 31a0d17de5 3rdparty: mainui: update 2026-04-04 17:36:21 +05:00
Alibek Omarov 5f765a35b9 ref: gl: show more detailed Host_Error instead of ASSERT in R_GetTexture 2026-04-04 17:36:05 +05:00
Alibek Omarov 5606346cc1 scripts: waifulib: xcompile: add Android NDK 30 2026-04-04 17:34:31 +05:00
Alibek Omarov 6faee8fd89 scripts: ios: call mkdir -p to not error out if the directory already exists (thanks, @ksagaming) 2026-04-04 17:34:07 +05:00
Alibek Omarov 255c9bcaed 3rdparty: mainui: update 2026-04-03 09:27:33 +05:00
Alibek Omarov 25a3fdbcec 3rdparty: mainui: update 2026-04-03 09:20:28 +05:00
Alibek Omarov 8e450d869b engine: common: add host.default_gamedir containing gamedir passed to us from game launcher 2026-04-03 04:09:25 +05:00
Alibek Omarov e8ef7ad60c engine: server: throw Host_Error when game tries to call precache model with invalid argument, like GoldSrc 2026-04-03 01:43:23 +05:00
Alibek Omarov 216eedcdcd ref: gl: better wording about backface culling goldsrc bug [skip ci] 2026-04-03 01:28:04 +05:00
Alibek Omarov fd55716633 ref: gl: change backface culling only if it wasn't disabled by mod developer beforehand 2026-04-03 01:23:55 +05:00
Alibek Omarov 0b920be381 engine: client: delay freeing up the sound channel when it becomes inaudible 2026-04-03 00:03:52 +05:00
Alibek Omarov e6dfccb6ba engine: reorganize common.h header 2026-04-02 20:45:00 +05:00
Alibek Omarov 3129081050 engine: fix a typo USING_ASAN -> USE_ASAN 2026-04-02 02:16:50 +05:00
Alibek Omarov 00dac928c9 ref: replace checking PARM_QUAKE_COMPATIBLE with direct check of feature flag set 2026-04-02 02:13:27 +05:00
Alibek Omarov 3726256514 engine: simplify IsQuakeCompatible by enforcing QUAKE_COMPATIBLE feature flag when Quake demo starts 2026-04-02 02:11:40 +05:00
Alibek Omarov 5eb43505cb engine: platform: try to fix build on 32-bit arm in debug builds (r7 is used by frame pointer, so we push it into stack before using for a syscall) 2026-04-02 02:02:59 +05:00
74 changed files with 2025 additions and 1495 deletions
+1 -1
View File
@@ -69,7 +69,7 @@ jobs:
targetarch: amd64 targetarch: amd64
env: env:
SDL_VERSION: 2.32.10 SDL_VERSION: 2.32.10
FFMPEG_VERSION: 7.1 FFMPEG_VERSION: 8.1
GH_CPU_ARCH: ${{ matrix.targetarch }} GH_CPU_ARCH: ${{ matrix.targetarch }}
GH_CPU_OS: ${{ matrix.targetos }} GH_CPU_OS: ${{ matrix.targetos }}
GH_CROSSCOMPILING: ${{ matrix.cross }} GH_CROSSCOMPILING: ${{ matrix.cross }}
+2 -2
View File
@@ -612,9 +612,9 @@ static inline mnode_t *node_child( const mnode_t *n, int side, const model_t *mo
} }
} }
return n->children_[side]; return n->children_[side ? 1 : 0];
#else #else
return n->children_[side]; return n->children_[side ? 1 : 0];
#endif #endif
} }
+185
View File
@@ -0,0 +1,185 @@
/*
sound_api.h - Xash3D extension for client sound interface
Copyright (C) 2026 Xash3D FWGS Developers
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>
*/
#ifndef SOUND_API_H
#define SOUND_API_H
#include "xash3d_types.h"
// Experimental implementation, backward compatibility is not guaranteed.
#define CL_SOUND_INTERFACE_VERSION 1
#define FL_VOXWORD_IN_CACHE BIT( 0 ) // if set, it was loaded prior and shouldn't be freed
#define FL_CHAN_USE_LOOP BIT( 0 ) // don't loop default and local sounds
#define FL_CHAN_STATIC_SOUND BIT( 1 ) // use origin instead of fetching entnum's origin
#define FL_CHAN_LOCAL_SOUND BIT( 2 ) // it's a local menu sound (not looped, not paused)
#define FL_CHAN_SENTENCE_FINISHED BIT( 4 ) // if set, finished playing sentence
#define FL_CHAN_FINISHED BIT( 5 ) // if set, finished playing single word
typedef int sound_t;
typedef struct portable_samplepair_s
{
int left;
int right;
} portable_samplepair_t;
typedef struct sfx_s
{
char name[MAX_QPATH];
wavdata_t *cache;
int servercount;
uint hashValue;
struct sfx_s *hashNext;
} sfx_t;
typedef struct voxword_s
{
sfx_t *sfx;
uint16_t volume; // volume percent
uint16_t pitch; // pitch shift percent (keep large for extra chipmunk fun)
uint8_t timecompress; // percent of skipped data (speeds up playback without pitch shift)
uint8_t start; // percent at which playback starts
uint8_t end; // percent at which playback ends
uint8_t flags;
} voxword_t;
typedef struct channel_s
{
char name[16]; // keep sentence name
sfx_t *sfx; // sfx number
vec3_t origin; // only use if fixed_origin is set
float dist_mult; // distance multiplier (attenuation/clipK)
int entchannel; // sound channel (CHAN_STREAM, CHAN_VOICE, etc.)
uint flags;
short entnum; // entity soundsource
short master_vol; // 0-255 master volume
short leftvol; // 0-255 left volume
short rightvol; // 0-255 right volume
short basePitch; // base pitch percent (100% is normal pitch playback)
byte word_index;
// HACKHACK: count when this channel became inaudible
// to not free it when it could be respatialized soon
#define MAX_CHANNEL_INAUDIBLE_TIME 0.1f
float inauduble_free_time;
double sample;
double forced_end;
wavdata_t *data;
voxword_t *words; // dynamically allocated, (num_words + 1) entries, null sfx terminates
uintptr_t engine_reserved[8]; // only for engine developers
uintptr_t game_reserved[8]; // free space for game developers
} channel_t;
typedef struct rawchan_s
{
short entnum;
short master_vol;
short leftvol; // 0-255 left volume
short rightvol; // 0-255 right volume
float dist_mult; // distance multiplier (attenuation/clipK)
vec3_t origin; // only use if fixed_origin is set
volatile uint s_rawend;
float oldtime; // catch time jumps
uintptr_t engine_reserved[8]; // only for engine developers
uintptr_t game_reserved[8]; // free space for game developers
size_t max_samples; // buffer length
portable_samplepair_t rawsamples[]; // variable sized
} rawchan_t;
typedef struct snd_format_s
{
uint speed;
byte width;
byte channels;
} snd_format_t;
typedef struct snd_globals_s
{
// dma
const char *backend_name;
byte *buffer;
snd_format_t format;
qboolean initialized; // sound engine is active
int samples; // mono samples in buffer
int samplepos; // in mono samples
int paintedtime; // total samples that have been mixed at speed
int soundtime; // total samples that have been played out to hardware at dma speed
// listener (client, camera, etc)
vec3_t origin;
vec3_t forward, right, up;
int entnum;
qboolean streaming; // playing AVI-file
qboolean stream_paused; // pause only background track
// SoundAPI shared pointers
channel_t *const channels;
int max_channels;
int total_channels;
rawchan_t **const raw_channels;
int max_raw_channels;
sound_t ambient_sfx[NUM_AMBIENTS];
qboolean have_ambient_sfx;
} snd_globals_t;
// API from engine to client (client calls these)
typedef struct sound_api_s
{
qboolean (*CL_GetEntitySpatialization)( channel_t *ch );
sfx_t* (*S_GetSfxByHandle)( sound_t handle );
} sound_api_t;
// Callbacks from client to engine (engine calls these when custom sound is active)
typedef struct sound_interface_s
{
int version;
qboolean (*pfnS_Init)( snd_globals_t *globals );
void (*pfnS_Shutdown)( void );
void (*pfnS_UpdateSound)( void );
/* Full paint: endtime (sample pairs), dma buffer, paintedtime in/out. Client does mix + transfer to dma.buffer. */
void (*pfnS_PaintChannels)( int endtime );
void (*pfnS_UpdateChannel)( int ch_idx, const channel_t *ch, sound_t handle ); // ch=NULL -> channel freed
void (*pfnS_UpdateRawChannel)( int raw_idx, rawchan_t *ch ); // ch=NULL -> channel freed
void (*pfnS_Spatialize)( channel_t *ch );
void (*pfnS_FreeSound)( sfx_t *sfx, sound_t handle );
} sound_interface_t;
#endif // SOUND_API_H
+8
View File
@@ -23,6 +23,12 @@ struct mstudioevent_s;
struct engine_studio_api_s; struct engine_studio_api_s;
struct r_studio_interface_s; struct r_studio_interface_s;
struct sound_api_s;
struct sound_interface_s;
typedef struct sound_api_s sound_api_t;
typedef struct sound_interface_s sound_interface_t;
// NOTE: ordering is important! // NOTE: ordering is important!
typedef struct cldll_func_s typedef struct cldll_func_s
{ {
@@ -74,6 +80,8 @@ typedef struct cldll_func_s
int (*pfnTouchEvent)( int type, int fingerID, float x, float y, float dx, float dy ); int (*pfnTouchEvent)( int type, int fingerID, float x, float y, float dx, float dy );
void (*pfnMoveEvent)( float forwardmove, float sidemove ); void (*pfnMoveEvent)( float forwardmove, float sidemove );
void (*pfnLookEvent)( float relyaw, float relpitch ); void (*pfnLookEvent)( float relyaw, float relpitch );
// Sound API
int (*pfnGetSoundInterface)( int version, const sound_api_t *api, sound_interface_t *callback );
} cldll_func_t; } cldll_func_t;
#endif//CDLL_EXP_H #endif//CDLL_EXP_H
+6 -6
View File
@@ -255,9 +255,9 @@ static void AVI_StreamAudio( movie_state_t *Avi )
rawchan_t *ch = NULL; rawchan_t *ch = NULL;
// keep the same semantics, when S_RAW_SOUND_SOUNDTRACK doesn't play if S_StartStreaming wasn't enabled // keep the same semantics, when S_RAW_SOUND_SOUNDTRACK doesn't play if S_StartStreaming wasn't enabled
qboolean disable_stream = Avi->entnum == S_RAW_SOUND_SOUNDTRACK ? !s_listener.streaming : false; qboolean disable_stream = Avi->entnum == S_RAW_SOUND_SOUNDTRACK ? !snd.streaming : false;
if( !dma.initialized || disable_stream || cl.paused || !Avi->cached_audio ) if( !snd.initialized || disable_stream || cl.paused || !Avi->cached_audio )
return; return;
ch = S_FindRawChannel( Avi->entnum, true ); ch = S_FindRawChannel( Avi->entnum, true );
@@ -268,14 +268,14 @@ static void AVI_StreamAudio( movie_state_t *Avi )
ch->master_vol = Avi->volume; ch->master_vol = Avi->volume;
ch->dist_mult = (Avi->attn / SND_CLIP_DISTANCE); ch->dist_mult = (Avi->attn / SND_CLIP_DISTANCE);
if( ch->s_rawend < soundtime ) if( ch->s_rawend < snd.soundtime )
ch->s_rawend = soundtime; ch->s_rawend = snd.soundtime;
while( ch->s_rawend < soundtime + ch->max_samples ) while( ch->s_rawend < snd.soundtime + ch->max_samples )
{ {
size_t copy; size_t copy;
buffer_samples = ch->max_samples - (ch->s_rawend - soundtime); buffer_samples = ch->max_samples - (ch->s_rawend - snd.soundtime);
file_samples = buffer_samples * ((float)Avi->rate / SOUND_DMA_SPEED); file_samples = buffer_samples * ((float)Avi->rate / SOUND_DMA_SPEED);
if( file_samples <= 1 ) return; // no more samples need if( file_samples <= 1 ) return; // no more samples need
+73 -5
View File
@@ -26,16 +26,82 @@ GNU General Public License for more details.
#if XASH_FFMPEG_DLOPEN #if XASH_FFMPEG_DLOPEN
// using typeof gives more resilience to function declaration changes
// but it's only available in GCC and standardized in C23
#if defined(__GNUC__) || __STDC_VERSION__ >= 202311L
#define SUPPORTED_AVU_VERSION_MAJOR LIBAVUTIL_VERSION_MAJOR
#define SUPPORTED_AVF_VERSION_MAJOR LIBAVFORMAT_VERSION_MAJOR
#define SUPPORTED_AVC_VERSION_MAJOR LIBAVCODEC_VERSION_MAJOR
#define SUPPORTED_SWR_VERSION_MAJOR LIBSWRESAMPLE_VERSION_MAJOR
#define SUPPORTED_SWS_VERSION_MAJOR LIBSWSCALE_VERSION_MAJOR
#define F( func ) \
typedef typeof( func ) func##_t; \
func##_t *p##func
// libavutil
F( avutil_version );
F( av_frame_alloc );
F( av_frame_free );
F( av_frame_ref );
F( av_frame_unref );
F( av_strerror );
F( av_free );
F( av_get_bytes_per_sample );
F( av_get_media_type_string );
F( av_image_alloc );
// libavformat
F( avformat_version );
F( av_find_best_stream );
F( av_read_frame );
F( av_seek_frame );
F( avformat_close_input );
F( avformat_find_stream_info );
F( avformat_open_input );
// libavcodec
F( avcodec_version );
F( av_packet_alloc );
F( av_packet_free );
F( av_packet_unref );
F( avcodec_alloc_context3 );
F( avcodec_find_decoder );
F( avcodec_flush_buffers );
F( avcodec_free_context );
F( avcodec_open2 );
F( avcodec_parameters_to_context );
F( avcodec_receive_frame );
F( avcodec_send_packet );
// libswresample
F( swresample_version );
F( swr_alloc_set_opts2 );
F( swr_convert );
F( swr_free );
F( swr_init );
// libswscale
F( swscale_version );
F( sws_freeContext );
F( sws_getContext );
F( sws_scale );
#undef F
#else // !defined(__GNUC__) && __STDC_VERSION__ < 202311L
// the following symbols were taken from ffmpeg public headers // the following symbols were taken from ffmpeg public headers
// on each major ffmpeg uprgade, they must be validated // on each major ffmpeg uprgade, they must be validated
// ffmpeg guarantees API and ABI compatibility between major versions // ffmpeg guarantees API and ABI compatibility between major versions
// so complain if this gets compiled against unsupported yet version // so complain if this gets compiled against unsupported yet version
// the same check will be done in runtime to ensure compatibility // the same check will be done in runtime to ensure compatibility
#define SUPPORTED_AVU_VERSION_MAJOR 59 #define SUPPORTED_AVU_VERSION_MAJOR 60
#define SUPPORTED_AVF_VERSION_MAJOR 61 #define SUPPORTED_AVF_VERSION_MAJOR 62
#define SUPPORTED_AVC_VERSION_MAJOR 61 #define SUPPORTED_AVC_VERSION_MAJOR 62
#define SUPPORTED_SWR_VERSION_MAJOR 5 #define SUPPORTED_SWR_VERSION_MAJOR 6
#define SUPPORTED_SWS_VERSION_MAJOR 8 #define SUPPORTED_SWS_VERSION_MAJOR 9
#if SUPPORTED_AVU_VERSION_MAJOR != LIBAVUTIL_VERSION_MAJOR #if SUPPORTED_AVU_VERSION_MAJOR != LIBAVUTIL_VERSION_MAJOR
#error "unsupported libavutil version" #error "unsupported libavutil version"
@@ -105,6 +171,8 @@ void (*psws_freeContext)( struct SwsContext *swsContext );
struct SwsContext *(*psws_getContext)( int srcW, int srcH, enum AVPixelFormat srcFormat, int dstW, int dstH, enum AVPixelFormat dstFormat, int flags, SwsFilter *srcFilter, SwsFilter *dstFilter, const double *param ); struct SwsContext *(*psws_getContext)( int srcW, int srcH, enum AVPixelFormat srcFormat, int dstW, int dstH, enum AVPixelFormat dstFormat, int flags, SwsFilter *srcFilter, SwsFilter *dstFilter, const double *param );
int (*psws_scale)( struct SwsContext *c, const uint8_t *const srcSlice[], const int srcStride[], int srcSliceY, int srcSliceH, uint8_t *const dst[], const int dstStride[] ); int (*psws_scale)( struct SwsContext *c, const uint8_t *const srcSlice[], const int srcStride[], int srcSliceY, int srcSliceH, uint8_t *const dst[], const int dstStride[] );
#endif // defined(__GNUC__) || __STDC_VERSION__ >= 202311L
#else // !XASH_FFMPEG_DLOPEN #else // !XASH_FFMPEG_DLOPEN
#define SUPPORTED_AVU_VERSION_MAJOR LIBAVUTIL_VERSION_MAJOR #define SUPPORTED_AVU_VERSION_MAJOR LIBAVUTIL_VERSION_MAJOR
+1 -5
View File
@@ -70,11 +70,7 @@ void CL_SetFontRendermode( cl_font_t *font )
void CL_SetFontColor( cl_font_t *font, const rgba_t color ) void CL_SetFontColor( cl_font_t *font, const rgba_t color )
{ {
// don't apply color to fixed fonts it's already colored ref.dllFuncs.Color4ub( color[0], color[1], color[2], color[3] );
if( font->type != FONT_FIXED || REF_GET_PARM( PARM_TEX_GLFORMAT, font->hFontTexture ) == 0x8045 ) // GL_LUMINANCE8_ALPHA8
ref.dllFuncs.Color4ub( color[0], color[1], color[2], color[3] );
else
ref.dllFuncs.Color4ub( 255, 255, 255, color[3] );
} }
qboolean Con_LoadFixedWidthFont( const char *fontname, cl_font_t *font, float scale, convar_t *rendermode, uint texFlags ) qboolean Con_LoadFixedWidthFont( const char *fontname, cl_font_t *font, float scale, convar_t *rendermode, uint texFlags )
+1 -1
View File
@@ -1381,7 +1381,7 @@ qboolean CL_GetEntitySpatialization( channel_t *ch )
if( ch->entnum == 0 ) if( ch->entnum == 0 )
{ {
ch->staticsound = true; SetBits( ch->flags, FL_CHAN_STATIC_SOUND );
return true; // static sound return true; // static sound
} }
+34 -80
View File
@@ -37,11 +37,20 @@ GNU General Public License for more details.
#include "platform/platform.h" #include "platform/platform.h"
#define MAX_LINELENGTH 80 #define MAX_LINELENGTH 80
#define MAX_TEXTCHANNELS 8 // must be power of two (GoldSrc uses 4 channels) #define TEXT_MSGNAME "TextMessage"
#define TEXT_MSGNAME "TextMessage%i"
static char cl_textbuffer[MAX_TEXTCHANNELS][2048]; static char cl_textbuffer[MAX_TEXTCHANNELS][2048];
static client_textmessage_t cl_textmessage[MAX_TEXTCHANNELS]; client_textmessage_t cl_textmessage[MAX_TEXTCHANNELS] =
{
{ .pName = "TextMessage0", .pMessage = cl_textbuffer[0] },
{ .pName = "TextMessage1", .pMessage = cl_textbuffer[1] },
{ .pName = "TextMessage2", .pMessage = cl_textbuffer[2] },
{ .pName = "TextMessage3", .pMessage = cl_textbuffer[3] },
{ .pName = "TextMessage4", .pMessage = cl_textbuffer[4] },
{ .pName = "TextMessage5", .pMessage = cl_textbuffer[5] },
{ .pName = "TextMessage6", .pMessage = cl_textbuffer[6] },
{ .pName = "TextMessage7", .pMessage = cl_textbuffer[7] },
};
static const dllfunc_t cdll_exports[] = static const dllfunc_t cdll_exports[] =
{ {
@@ -96,6 +105,7 @@ static const dllfunc_t cdll_new_exports[] = // allowed only in SDK 2.3 and high
{ "IN_ClientTouchEvent", (void **)&clgame.dllFuncs.pfnTouchEvent}, // Xash3D FWGS ext { "IN_ClientTouchEvent", (void **)&clgame.dllFuncs.pfnTouchEvent}, // Xash3D FWGS ext
{ "IN_ClientMoveEvent", (void **)&clgame.dllFuncs.pfnMoveEvent}, // Xash3D FWGS ext { "IN_ClientMoveEvent", (void **)&clgame.dllFuncs.pfnMoveEvent}, // Xash3D FWGS ext
{ "IN_ClientLookEvent", (void **)&clgame.dllFuncs.pfnLookEvent}, // Xash3D FWGS ext { "IN_ClientLookEvent", (void **)&clgame.dllFuncs.pfnLookEvent}, // Xash3D FWGS ext
{ "HUD_GetSoundInterface", (void **)&clgame.dllFuncs.pfnGetSoundInterface }, // Xash3D ext
}; };
static void pfnSPR_DrawHoles( int frame, int x, int y, const wrect_t *prc ); static void pfnSPR_DrawHoles( int frame, int x, int y, const wrect_t *prc );
@@ -179,7 +189,13 @@ static void CL_InitCDAudio( const char *filename )
while(( pfile = COM_ParseFile( pfile, token, sizeof( token ))) != NULL ) while(( pfile = COM_ParseFile( pfile, token, sizeof( token ))) != NULL )
{ {
if( !Q_stricmp( token, "blank" )) if( !Q_stricmp( token, "blank" ))
{
clgame.cdtracks[c][0] = '\0'; clgame.cdtracks[c][0] = '\0';
}
else if( token[0] == '/' ) // allow custom path
{
Q_strncpy( clgame.cdtracks[c], &token[1], sizeof( clgame.cdtracks[c] ));
}
else else
{ {
Q_snprintf( clgame.cdtracks[c], sizeof( clgame.cdtracks[c] ), Q_snprintf( clgame.cdtracks[c], sizeof( clgame.cdtracks[c] ),
@@ -560,31 +576,18 @@ and hold them into permament memory pool
*/ */
static void CL_InitTitles( const char *filename ) static void CL_InitTitles( const char *filename )
{ {
fs_offset_t fileSize;
byte *pMemFile;
int i;
// initialize text messages (game_text)
for( i = 0; i < MAX_TEXTCHANNELS; i++ )
{
char name[MAX_VA_STRING];
Q_snprintf( name, sizeof( name ), TEXT_MSGNAME, i );
cl_textmessage[i].pName = copystringpool( clgame.mempool, name );
cl_textmessage[i].pMessage = cl_textbuffer[i];
}
// clear out any old data that's sitting around. // clear out any old data that's sitting around.
if( clgame.titles ) Mem_Free( clgame.titles ); Mem_Free( clgame.titles );
clgame.titles = NULL; clgame.titles = NULL;
clgame.numTitles = 0; clgame.numTitles = 0;
pMemFile = FS_LoadFile( filename, &fileSize, false ); fs_offset_t fileSize = 0;
if( !pMemFile ) return; char *pMemFile = (char *)FS_LoadFile( filename, &fileSize, false );
if( !pMemFile )
return;
clgame.titles = CL_TextMessageParse( clgame.mempool, (char *)pMemFile, fileSize, &clgame.numTitles ); clgame.titles = CL_TextMessageParse( clgame.mempool, pMemFile, fileSize, &clgame.numTitles );
Mem_Free( pMemFile ); Mem_Free( pMemFile );
} }
@@ -653,54 +656,6 @@ void CL_ParseTextMessage( sizebuf_t *msg )
CL_HudMessage( text->pName ); CL_HudMessage( text->pName );
} }
/*
================
CL_ParseFinaleCutscene
show display finale or cutscene message
================
*/
void CL_ParseFinaleCutscene( sizebuf_t *msg, int level )
{
static int msgindex = 0;
client_textmessage_t *text;
int channel;
cl.intermission = level;
channel = msgindex;
msgindex = (msgindex + 1) & (MAX_TEXTCHANNELS - 1);
// grab message channel
text = &cl_textmessage[channel];
// NOTE: svc_finale and svc_cutscene has a
// predefined settings like Quake-style
text->x = -1.0f;
text->y = 0.15f;
text->effect = 2; // scan out effect
text->r1 = 245;
text->g1 = 245;
text->b1 = 245;
text->a1 = 0; // unused
text->r2 = 0;
text->g2 = 0;
text->b2 = 0;
text->a2 = 0;
text->fadein = 0.15f;
text->fadeout = 0.0f;
text->holdtime = 99999.0f;
text->fxtime = 0.0f;
// to prevent grab too long messages
Q_strncpy( (char *)text->pMessage, MSG_ReadString( msg ), 2048 );
if( *text->pMessage == '\0' )
return; // no real text
CL_HudMessage( text->pName );
}
/* /*
==================== ====================
CL_GetMaxlients CL_GetMaxlients
@@ -1974,13 +1929,12 @@ client_textmessage_t *CL_TextMessageGet( const char *pName )
int i; int i;
// first check internal messages // first check internal messages
for( i = 0; i < MAX_TEXTCHANNELS; i++ ) if( Q_strlen( pName ) == sizeof( TEXT_MSGNAME ) // including the digit
&& !Q_strncmp( pName, TEXT_MSGNAME, sizeof( TEXT_MSGNAME ) - 1 ))
{ {
char name[MAX_VA_STRING]; i = pName[sizeof( TEXT_MSGNAME ) - 1] - '0';
Q_snprintf( name, sizeof( name ), TEXT_MSGNAME, i ); if( i >= 0 && i < MAX_TEXTCHANNELS )
if( !Q_strcmp( pName, name ))
return cl_textmessage + i; return cl_textmessage + i;
} }
@@ -4095,14 +4049,14 @@ qboolean CL_LoadProgs( const char *name )
CL_InitCDAudio( "media/cdaudio.txt" ); CL_InitCDAudio( "media/cdaudio.txt" );
CL_InitTitles( "titles.txt" ); CL_InitTitles( "titles.txt" );
CL_InitParticles (); CL_InitParticles( );
CL_InitViewBeams (); CL_InitViewBeams( );
CL_InitTempEnts (); CL_InitTempEnts( );
if( !R_InitRenderAPI()) // Xash3D extension if( !R_InitRenderAPI( )) // Xash3D extension
Con_Reportf( S_WARN "%s: couldn't get render API\n", __func__ ); Con_Reportf( S_WARN "%s: couldn't get render API\n", __func__ );
if( !Mobile_Init() ) // Xash3D FWGS extension: mobile interface if( !Mobile_Init( )) // Xash3D FWGS extension: mobile interface
Con_Reportf( S_WARN "%s: couldn't get mobility API\n", __func__ ); Con_Reportf( S_WARN "%s: couldn't get mobility API\n", __func__ );
CL_InitEdicts( cl.maxclients ); // initailize local player and world CL_InitEdicts( cl.maxclients ); // initailize local player and world
+4 -3
View File
@@ -1174,7 +1174,7 @@ static void CL_SendConnectPacket( connprotocol_t proto, int challenge )
else else
{ {
const char *qport = Cvar_VariableString( "net_qport" ); const char *qport = Cvar_VariableString( "net_qport" );
int extensions = NET_EXT_SPLITSIZE; int extensions = Host_IsLocalGame() ? 0 : NET_EXT_SPLITSIZE;
string key; string key;
ID_GetMD5ForAddress( key, adr, sizeof( key )); ID_GetMD5ForAddress( key, adr, sizeof( key ));
@@ -3678,8 +3678,6 @@ void CL_Init( void )
CL_InitLocal(); CL_InitLocal();
VID_Init(); // init video VID_Init(); // init video
S_Init(); // init sound
Voice_Init( VOICE_DEFAULT_CODEC, 3, true ); // init voice (do not open the device)
// unreliable buffer. unsed for unreliable commands and voice stream // unreliable buffer. unsed for unreliable commands and voice stream
MSG_Init( &cls.datagram, "cls.datagram", cls.datagram_buf, sizeof( cls.datagram_buf )); MSG_Init( &cls.datagram, "cls.datagram", cls.datagram_buf, sizeof( cls.datagram_buf ));
@@ -3689,6 +3687,9 @@ void CL_Init( void )
if( !CL_LoadProgs( libpath )) if( !CL_LoadProgs( libpath ))
Host_Error( "can't initialize %s: %s\n", libpath, COM_GetLibraryError( )); Host_Error( "can't initialize %s: %s\n", libpath, COM_GetLibraryError( ));
S_Init(); // init sound
Voice_Init( VOICE_DEFAULT_CODEC, 3, true ); // init voice (do not open the device)
ID_Init(); ID_Init();
SteamBroker_Init(); SteamBroker_Init();
+209 -141
View File
@@ -42,7 +42,7 @@ CL_ParseViewEntity
================== ==================
*/ */
void CL_ParseViewEntity( sizebuf_t *msg ) static void CL_ParseViewEntity( sizebuf_t *msg )
{ {
cl.viewentity = MSG_ReadWord( msg ); cl.viewentity = MSG_ReadWord( msg );
@@ -161,7 +161,7 @@ CL_ParseSignon
================== ==================
*/ */
void CL_ParseSignon( sizebuf_t *msg, connprotocol_t proto ) static void CL_ParseSignon( sizebuf_t *msg, connprotocol_t proto )
{ {
int i = MSG_ReadByte( msg ); int i = MSG_ReadByte( msg );
@@ -209,7 +209,7 @@ CL_ParseParticles
================== ==================
*/ */
void CL_ParseParticles( sizebuf_t *msg, connprotocol_t proto ) static void CL_ParseParticles( sizebuf_t *msg, connprotocol_t proto )
{ {
vec3_t org, dir; vec3_t org, dir;
int i, count, color; int i, count, color;
@@ -362,7 +362,7 @@ CL_ParseSoundFade
================== ==================
*/ */
void CL_ParseSoundFade( sizebuf_t *msg ) static void CL_ParseSoundFade( sizebuf_t *msg )
{ {
int fade_percent = MSG_ReadByte( msg ); int fade_percent = MSG_ReadByte( msg );
int hold_time = MSG_ReadByte( msg ); int hold_time = MSG_ReadByte( msg );
@@ -616,7 +616,7 @@ CL_ParseCustomization
================== ==================
*/ */
void CL_ParseCustomization( sizebuf_t *msg ) static void CL_ParseCustomization( sizebuf_t *msg )
{ {
customization_t *pExistingCustomization; customization_t *pExistingCustomization;
customization_t *pList; customization_t *pList;
@@ -704,7 +704,7 @@ CL_ParseResourceRequest
================== ==================
*/ */
void CL_ParseResourceRequest( sizebuf_t *msg ) static void CL_ParseResourceRequest( sizebuf_t *msg )
{ {
byte buffer[MAX_INIT_MSG]; byte buffer[MAX_INIT_MSG];
int i, arg, nStartIndex; int i, arg, nStartIndex;
@@ -776,7 +776,7 @@ CL_ParseFileTransferFailed
================== ==================
*/ */
void CL_ParseFileTransferFailed( sizebuf_t *msg ) static void CL_ParseFileTransferFailed( sizebuf_t *msg )
{ {
const char *name = MSG_ReadString( msg ); const char *name = MSG_ReadString( msg );
@@ -796,7 +796,7 @@ void CL_ParseFileTransferFailed( sizebuf_t *msg )
CL_ParseServerData CL_ParseServerData
================== ==================
*/ */
void CL_ParseServerData( sizebuf_t *msg, connprotocol_t proto ) static void CL_ParseServerData( sizebuf_t *msg, connprotocol_t proto )
{ {
char gamefolder[MAX_QPATH]; char gamefolder[MAX_QPATH];
string mapfile; string mapfile;
@@ -1234,7 +1234,7 @@ void CL_ParseBaseline( sizebuf_t *msg, connprotocol_t proto )
CL_ParseLightStyle CL_ParseLightStyle
================ ================
*/ */
void CL_ParseLightStyle( sizebuf_t *msg, connprotocol_t proto ) static void CL_ParseLightStyle( sizebuf_t *msg, connprotocol_t proto )
{ {
int style; int style;
const char *s; const char *s;
@@ -1255,7 +1255,7 @@ CL_ParseSetAngle
set the view angle to this absolute value set the view angle to this absolute value
================ ================
*/ */
void CL_ParseSetAngle( sizebuf_t *msg ) static void CL_ParseSetAngle( sizebuf_t *msg )
{ {
MSG_ReadVec3Angles( msg, cl.viewangles ); MSG_ReadVec3Angles( msg, cl.viewangles );
} }
@@ -1267,7 +1267,7 @@ CL_ParseAddAngle
add the view angle yaw add the view angle yaw
================ ================
*/ */
void CL_ParseAddAngle( sizebuf_t *msg ) static void CL_ParseAddAngle( sizebuf_t *msg )
{ {
pred_viewangle_t *a; pred_viewangle_t *a;
float delta_yaw; float delta_yaw;
@@ -1296,7 +1296,7 @@ CL_ParseCrosshairAngle
offset crosshair angles offset crosshair angles
================ ================
*/ */
void CL_ParseCrosshairAngle( sizebuf_t *msg ) static void CL_ParseCrosshairAngle( sizebuf_t *msg )
{ {
cl.crosshairangle[0] = MSG_ReadChar( msg ) * 0.2f; cl.crosshairangle[0] = MSG_ReadChar( msg ) * 0.2f;
cl.crosshairangle[1] = MSG_ReadChar( msg ) * 0.2f; cl.crosshairangle[1] = MSG_ReadChar( msg ) * 0.2f;
@@ -1310,7 +1310,7 @@ CL_ParseRestore
reading decals, etc. reading decals, etc.
================ ================
*/ */
void CL_ParseRestore( sizebuf_t *msg ) static void CL_ParseRestore( sizebuf_t *msg )
{ {
string filename; string filename;
int i, mapCount; int i, mapCount;
@@ -1337,7 +1337,7 @@ CL_RegisterUserMessage
register new user message or update existing register new user message or update existing
================ ================
*/ */
void CL_RegisterUserMessage( sizebuf_t *msg, connprotocol_t proto ) static void CL_RegisterUserMessage( sizebuf_t *msg, connprotocol_t proto )
{ {
char *pszName; char *pszName;
char szName[17]; char szName[17];
@@ -1375,7 +1375,7 @@ CL_UpdateUserinfo
collect userinfo from all players collect userinfo from all players
================ ================
*/ */
void CL_UpdateUserinfo( sizebuf_t *msg, connprotocol_t proto ) static void CL_UpdateUserinfo( sizebuf_t *msg, connprotocol_t proto )
{ {
int slot, id; int slot, id;
qboolean active; qboolean active;
@@ -1898,7 +1898,7 @@ CL_ParseVoiceInit
================== ==================
*/ */
void CL_ParseVoiceInit( sizebuf_t *msg ) static void CL_ParseVoiceInit( sizebuf_t *msg )
{ {
char *pszCodec = MSG_ReadString( msg ); char *pszCodec = MSG_ReadString( msg );
int quality = MSG_ReadByte( msg ); int quality = MSG_ReadByte( msg );
@@ -1912,7 +1912,7 @@ CL_ParseVoiceData
================== ==================
*/ */
void CL_ParseVoiceData( sizebuf_t *msg, connprotocol_t proto ) static void CL_ParseVoiceData( sizebuf_t *msg, connprotocol_t proto )
{ {
int size, idx, frames = 0; int size, idx, frames = 0;
byte received[VOICE_MAX_DATA_SIZE]; byte received[VOICE_MAX_DATA_SIZE];
@@ -1962,7 +1962,7 @@ CL_ParseResLocation
================== ==================
*/ */
void CL_ParseResLocation( sizebuf_t *msg ) static void CL_ParseResLocation( sizebuf_t *msg )
{ {
char *data = MSG_ReadString( msg ); char *data = MSG_ReadString( msg );
char token[256]; char token[256];
@@ -1991,7 +1991,7 @@ sended from game.dll
normal client ignores any of HLTV messages normal client ignores any of HLTV messages
============== ==============
*/ */
void CL_ParseHLTV( sizebuf_t *msg ) static void CL_ParseHLTV( sizebuf_t *msg )
{ {
switch( MSG_ReadByte( msg )) switch( MSG_ReadByte( msg ))
{ {
@@ -2025,7 +2025,7 @@ spectator message (director)
sended from game.dll sended from game.dll
============== ==============
*/ */
void CL_ParseDirector( sizebuf_t *msg ) static void CL_ParseDirector( sizebuf_t *msg )
{ {
int iSize = MSG_ReadByte( msg ); int iSize = MSG_ReadByte( msg );
byte pbuf[256]; byte pbuf[256];
@@ -2119,7 +2119,7 @@ Find the client cvar value
and sent it back to the server and sent it back to the server
============== ==============
*/ */
void CL_ParseCvarValue( sizebuf_t *msg, const qboolean ext, const connprotocol_t proto ) static void CL_ParseCvarValue( sizebuf_t *msg, const qboolean ext, const connprotocol_t proto )
{ {
const char *cvarName, *response = NULL; const char *cvarName, *response = NULL;
convar_t *cvar; convar_t *cvar;
@@ -2181,7 +2181,7 @@ CL_ParseExec
Exec map/class specific configs Exec map/class specific configs
============== ==============
*/ */
void CL_ParseExec( sizebuf_t *msg ) static void CL_ParseExec( sizebuf_t *msg )
{ {
qboolean is_class; qboolean is_class;
int class_idx; int class_idx;
@@ -2357,25 +2357,150 @@ ACTION MESSAGES
*/ */
/* /*
============ ================
CL_ParseCommonDLLMessage CL_ParseFinaleCutscene
parse a message which structure is enforced by DLL compatibility show display finale or cutscene message
it should always be the same regardless of protocol used ================
*/
static void CL_ParseFinaleCutscene( sizebuf_t *msg, int level )
{
static int msgindex = 0;
client_textmessage_t *text;
int channel;
cl.intermission = level;
channel = msgindex;
msgindex = (msgindex + 1) & (MAX_TEXTCHANNELS - 1);
// grab message channel
text = &cl_textmessage[channel];
// NOTE: svc_finale and svc_cutscene has a
// predefined settings like Quake-style
text->x = -1.0f;
text->y = 0.15f;
text->effect = 2; // scan out effect
text->r1 = 245;
text->g1 = 245;
text->b1 = 245;
text->a1 = 0; // unused
text->r2 = 0;
text->g2 = 0;
text->b2 = 0;
text->a2 = 0;
text->fadein = 0.15f;
text->fadeout = 0.0f;
text->holdtime = 99999.0f;
text->fxtime = 0.0f;
// to prevent grab too long messages
Q_strncpy( (char *)text->pMessage, MSG_ReadString( msg ), 2048 );
if( *text->pMessage == '\0' )
return; // no real text
CL_HudMessage( text->pName );
}
/*
============
CL_ParseCommonMessage
parse a message which is the same across all supported protocols
============ ============
*/ */
qboolean CL_ParseCommonDLLMessage( sizebuf_t *msg, connprotocol_t proto, int svc_num, int startoffset ) qboolean CL_ParseCommonMessage( sizebuf_t *msg, connprotocol_t proto, int svc_num, int startoffset )
{ {
int param1, param2; switch( svc_num )
{
case svc_nop:
break;
case svc_setview:
CL_ParseViewEntity( msg );
break;
case svc_lightstyle:
CL_ParseLightStyle( msg, proto );
break;
case svc_intermission:
cl.intermission = 1;
break;
case svc_finale:
CL_ParseFinaleCutscene( msg, 2 );
break;
case svc_cutscene:
CL_ParseFinaleCutscene( msg, 3 );
break;
default:
return false;
}
return true;
}
/*
============
CL_ParseCommonHLMessage
parse a message which structure is enforced by DLL compatibility
it should always be the same regardless of HL-based protocol used
============
*/
qboolean CL_ParseCommonHLMessage( sizebuf_t *msg, connprotocol_t proto, int svc_num, int startoffset )
{
const char *s;
int param1, param2;
switch( svc_num ) switch( svc_num )
{ {
case svc_bad:
Host_Error( "svc_bad\n" );
break;
case svc_time:
CL_ParseServerTime( msg, proto );
break;
case svc_print:
Con_Printf( "%s", MSG_ReadString( msg ));
break;
case svc_stufftext:
s = MSG_ReadString( msg );
if( cl_trace_stufftext.value )
{
size_t len = Q_strlen( s );
Con_Printf( "Stufftext: %s%c", s, len && s[len-1] == '\n' ? '\0' : '\n' );
}
#ifdef HACKS_RELATED_HLMODS
// disable Cry Of Fear antisave protection
if( !Q_strnicmp( s, "disconnect", 10 ) && cls.signon != SIGNONS )
break; // too early
#endif
Cbuf_AddFilteredText( s );
break;
case svc_setangle:
CL_ParseSetAngle( msg );
break;
case svc_serverdata:
Cbuf_Execute(); // make sure any stuffed commands are done
CL_ParseServerData( msg, proto );
break;
case svc_updateuserinfo:
CL_UpdateUserinfo( msg, proto );
break;
case svc_particle:
CL_ParseParticles( msg, proto );
break;
case svc_temp_entity: case svc_temp_entity:
CL_ParseTempEntity( msg, proto ); // need protocol because message header differs CL_ParseTempEntity( msg, proto ); // need protocol because message header differs
cl.frames[cl.parsecountmod].graphdata.tentities += MSG_GetNumBytesRead( msg ) - startoffset; cl.frames[cl.parsecountmod].graphdata.tentities += MSG_GetNumBytesRead( msg ) - startoffset;
break; break;
case svc_intermission: case svc_signonnum:
cl.intermission = 1; CL_ParseSignon( msg, proto );
break;
case svc_centerprint:
CL_CenterPrint( MSG_ReadString( msg ), 0.25f );
break; break;
case svc_cdtrack: case svc_cdtrack:
param1 = MSG_ReadByte( msg ); param1 = MSG_ReadByte( msg );
@@ -2384,6 +2509,9 @@ qboolean CL_ParseCommonDLLMessage( sizebuf_t *msg, connprotocol_t proto, int svc
param2 = bound( 1, param2, MAX_CDTRACKS ); // loopnum param2 = bound( 1, param2, MAX_CDTRACKS ); // loopnum
S_StartBackgroundTrack( clgame.cdtracks[param1-1], clgame.cdtracks[param2-1], 0, false ); S_StartBackgroundTrack( clgame.cdtracks[param1-1], clgame.cdtracks[param2-1], 0, false );
break; break;
case svc_restore:
CL_ParseRestore( msg );
break;
case svc_weaponanim: case svc_weaponanim:
param1 = MSG_ReadByte( msg ); // iAnim param1 = MSG_ReadByte( msg ); // iAnim
param2 = MSG_ReadByte( msg ); // body param2 = MSG_ReadByte( msg ); // body
@@ -2393,9 +2521,56 @@ qboolean CL_ParseCommonDLLMessage( sizebuf_t *msg, connprotocol_t proto, int svc
param1 = MSG_ReadShort( msg ); param1 = MSG_ReadShort( msg );
Cvar_SetValue( "room_type", param1 ); Cvar_SetValue( "room_type", param1 );
break; break;
case svc_addangle:
CL_ParseAddAngle( msg );
break;
case svc_usermessage:
CL_RegisterUserMessage( msg, proto );
break;
case svc_choke:
cl.frames[cls.netchan.incoming_sequence & CL_UPDATE_MASK].choked = true;
cl.frames[cls.netchan.incoming_sequence & CL_UPDATE_MASK].receivedtime = -2.0;
break;
case svc_resourcerequest:
CL_ParseResourceRequest( msg );
break;
case svc_customization:
CL_ParseCustomization( msg );
break;
case svc_crosshairangle:
CL_ParseCrosshairAngle( msg );
break;
case svc_soundfade:
CL_ParseSoundFade( msg );
break;
case svc_filetxferfailed:
CL_ParseFileTransferFailed( msg );
break;
case svc_hltv:
CL_ParseHLTV( msg );
break;
case svc_director: case svc_director:
CL_ParseDirector( msg ); CL_ParseDirector( msg );
break; break;
case svc_voiceinit:
CL_ParseVoiceInit( msg );
break;
case svc_voicedata:
CL_ParseVoiceData( msg, proto );
cl.frames[cl.parsecountmod].graphdata.voicebytes += MSG_GetNumBytesRead( msg ) - startoffset;
break;
case svc_resourcelocation:
CL_ParseResLocation( msg );
break;
case svc_querycvarvalue:
CL_ParseCvarValue( msg, false, proto );
break;
case svc_querycvarvalue2:
CL_ParseCvarValue( msg, true, proto );
break;
case svc_exec:
CL_ParseExec( msg );
break;
default: default:
return false; return false;
} }
@@ -2415,7 +2590,6 @@ void CL_ParseServerMessage( sizebuf_t *msg )
size_t bufStart, playerbytes; size_t bufStart, playerbytes;
int cmd; int cmd;
int old_background; int old_background;
const char *s;
// parse the message // parse the message
while( 1 ) while( 1 )
@@ -2438,18 +2612,15 @@ void CL_ParseServerMessage( sizebuf_t *msg )
// record command for debugging spew on parse problem // record command for debugging spew on parse problem
CL_Parse_RecordCommand( cmd, bufStart ); CL_Parse_RecordCommand( cmd, bufStart );
if( CL_ParseCommonDLLMessage( msg, PROTO_CURRENT, cmd, bufStart )) if( CL_ParseCommonMessage( msg, PROTO_CURRENT, cmd, bufStart ))
continue;
if( CL_ParseCommonHLMessage( msg, PROTO_CURRENT, cmd, bufStart ))
continue; continue;
// other commands // other commands
switch( cmd ) switch( cmd )
{ {
case svc_bad:
Host_Error( "svc_bad\n" );
break;
case svc_nop:
// this does nothing
break;
case svc_disconnect: case svc_disconnect:
CL_Drop (); CL_Drop ();
Host_AbortCurrentFrame (); Host_AbortCurrentFrame ();
@@ -2497,48 +2668,10 @@ void CL_ParseServerMessage( sizebuf_t *msg )
cls.connect_retry = 0; cls.connect_retry = 0;
} }
break; break;
case svc_setview:
CL_ParseViewEntity( msg );
break;
case svc_sound: case svc_sound:
CL_ParseSoundPacket( msg, false ); CL_ParseSoundPacket( msg, false );
cl.frames[cl.parsecountmod].graphdata.sound += MSG_GetNumBytesRead( msg ) - bufStart; cl.frames[cl.parsecountmod].graphdata.sound += MSG_GetNumBytesRead( msg ) - bufStart;
break; break;
case svc_time:
CL_ParseServerTime( msg, PROTO_CURRENT );
break;
case svc_print:
Con_Printf( "%s", MSG_ReadString( msg ));
break;
case svc_stufftext:
s = MSG_ReadString( msg );
if( cl_trace_stufftext.value )
{
size_t len = Q_strlen( s );
Con_Printf( "Stufftext: %s%c", s, len && s[len-1] == '\n' ? '\0' : '\n' );
}
#ifdef HACKS_RELATED_HLMODS
// disable Cry Of Fear antisave protection
if( !Q_strnicmp( s, "disconnect", 10 ) && cls.signon != SIGNONS )
break; // too early
#endif
Cbuf_AddFilteredText( s );
break;
case svc_setangle:
CL_ParseSetAngle( msg );
break;
case svc_serverdata:
Cbuf_Execute(); // make sure any stuffed commands are done
CL_ParseServerData( msg, PROTO_CURRENT );
break;
case svc_lightstyle:
CL_ParseLightStyle( msg, PROTO_CURRENT );
break;
case svc_updateuserinfo:
CL_UpdateUserinfo( msg, PROTO_CURRENT );
break;
case svc_deltatable: case svc_deltatable:
Delta_ParseTableField( msg ); Delta_ParseTableField( msg );
break; break;
@@ -2552,9 +2685,6 @@ void CL_ParseServerMessage( sizebuf_t *msg )
case svc_pings: case svc_pings:
CL_UpdateUserPings( msg ); CL_UpdateUserPings( msg );
break; break;
case svc_particle:
CL_ParseParticles( msg, PROTO_CURRENT );
break;
case svc_restoresound: case svc_restoresound:
CL_ParseSoundPacket( msg, true ); CL_ParseSoundPacket( msg, true );
cl.frames[cl.parsecountmod].graphdata.sound += MSG_GetNumBytesRead( msg ) - bufStart; cl.frames[cl.parsecountmod].graphdata.sound += MSG_GetNumBytesRead( msg ) - bufStart;
@@ -2572,30 +2702,9 @@ void CL_ParseServerMessage( sizebuf_t *msg )
case svc_setpause: case svc_setpause:
cl.paused = ( MSG_ReadOneBit( msg ) != 0 ); cl.paused = ( MSG_ReadOneBit( msg ) != 0 );
break; break;
case svc_signonnum:
CL_ParseSignon( msg, PROTO_CURRENT );
break;
case svc_centerprint:
CL_CenterPrint( MSG_ReadString( msg ), 0.25f );
break;
case svc_finale:
CL_ParseFinaleCutscene( msg, 2 );
break;
case svc_restore:
CL_ParseRestore( msg );
break;
case svc_cutscene:
CL_ParseFinaleCutscene( msg, 3 );
break;
case svc_bspdecal: case svc_bspdecal:
CL_ParseStaticDecal( msg ); CL_ParseStaticDecal( msg );
break; break;
case svc_addangle:
CL_ParseAddAngle( msg );
break;
case svc_usermessage:
CL_RegisterUserMessage( msg, PROTO_CURRENT );
break;
case svc_packetentities: case svc_packetentities:
playerbytes = CL_ParsePacketEntities( msg, false, PROTO_CURRENT ); playerbytes = CL_ParsePacketEntities( msg, false, PROTO_CURRENT );
cl.frames[cl.parsecountmod].graphdata.players += playerbytes; cl.frames[cl.parsecountmod].graphdata.players += playerbytes;
@@ -2606,53 +2715,12 @@ void CL_ParseServerMessage( sizebuf_t *msg )
cl.frames[cl.parsecountmod].graphdata.players += playerbytes; cl.frames[cl.parsecountmod].graphdata.players += playerbytes;
cl.frames[cl.parsecountmod].graphdata.entities += MSG_GetNumBytesRead( msg ) - bufStart - playerbytes; cl.frames[cl.parsecountmod].graphdata.entities += MSG_GetNumBytesRead( msg ) - bufStart - playerbytes;
break; break;
case svc_choke:
cl.frames[cls.netchan.incoming_sequence & CL_UPDATE_MASK].choked = true;
cl.frames[cls.netchan.incoming_sequence & CL_UPDATE_MASK].receivedtime = -2.0;
break;
case svc_resourcelist: case svc_resourcelist:
CL_ParseResourceList( msg, PROTO_CURRENT ); CL_ParseResourceList( msg, PROTO_CURRENT );
break; break;
case svc_deltamovevars: case svc_deltamovevars:
CL_ParseMovevars( msg ); CL_ParseMovevars( msg );
break; break;
case svc_resourcerequest:
CL_ParseResourceRequest( msg );
break;
case svc_customization:
CL_ParseCustomization( msg );
break;
case svc_crosshairangle:
CL_ParseCrosshairAngle( msg );
break;
case svc_soundfade:
CL_ParseSoundFade( msg );
break;
case svc_filetxferfailed:
CL_ParseFileTransferFailed( msg );
break;
case svc_hltv:
CL_ParseHLTV( msg );
break;
case svc_voiceinit:
CL_ParseVoiceInit( msg );
break;
case svc_voicedata:
CL_ParseVoiceData( msg, PROTO_CURRENT );
cl.frames[cl.parsecountmod].graphdata.voicebytes += MSG_GetNumBytesRead( msg ) - bufStart;
break;
case svc_resourcelocation:
CL_ParseResLocation( msg );
break;
case svc_querycvarvalue:
CL_ParseCvarValue( msg, false, PROTO_CURRENT );
break;
case svc_querycvarvalue2:
CL_ParseCvarValue( msg, true, PROTO_CURRENT );
break;
case svc_exec:
CL_ParseExec( msg );
break;
default: default:
CL_ParseUserMessage( msg, cmd, PROTO_CURRENT ); CL_ParseUserMessage( msg, cmd, PROTO_CURRENT );
cl.frames[cl.parsecountmod].graphdata.usr += MSG_GetNumBytesRead( msg ) - bufStart; cl.frames[cl.parsecountmod].graphdata.usr += MSG_GetNumBytesRead( msg ) - bufStart;
+10 -111
View File
@@ -569,22 +569,15 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg )
// record command for debugging spew on parse problem // record command for debugging spew on parse problem
CL_Parse_RecordCommand( cmd, bufStart ); CL_Parse_RecordCommand( cmd, bufStart );
if( CL_ParseCommonDLLMessage( msg, PROTO_GOLDSRC, cmd, bufStart )) if( CL_ParseCommonMessage( msg, PROTO_GOLDSRC, cmd, bufStart ))
continue;
if( CL_ParseCommonHLMessage( msg, PROTO_GOLDSRC, cmd, bufStart ))
continue; continue;
// other commands // other commands
switch( cmd ) switch( cmd )
{ {
case svc_bad:
Host_Error( "svc_bad\n" );
break;
case svc_nop:
case svc_spawnstatic:
case svc_goldsrc_damage:
case svc_goldsrc_killedmonster:
case svc_goldsrc_foundsecret:
// this does nothing
break;
case svc_disconnect: case svc_disconnect:
s = MSG_ReadString( msg ); s = MSG_ReadString( msg );
if( !COM_StringEmpty( s )) if( !COM_StringEmpty( s ))
@@ -603,47 +596,10 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg )
if( param1 != PROTOCOL_GOLDSRC_VERSION ) if( param1 != PROTOCOL_GOLDSRC_VERSION )
Host_Error( "Server use invalid protocol (%i should be %i)\n", param1, PROTOCOL_GOLDSRC_VERSION ); Host_Error( "Server use invalid protocol (%i should be %i)\n", param1, PROTOCOL_GOLDSRC_VERSION );
break; break;
case svc_setview:
CL_ParseViewEntity( msg );
break;
case svc_sound: case svc_sound:
CL_ParseSoundPacketGS( msg ); CL_ParseSoundPacketGS( msg );
cl.frames[cl.parsecountmod].graphdata.sound += MSG_GetNumBytesRead( msg ) - bufStart; cl.frames[cl.parsecountmod].graphdata.sound += MSG_GetNumBytesRead( msg ) - bufStart;
break; break;
case svc_time:
CL_ParseServerTime( msg, PROTO_GOLDSRC );
break;
case svc_print:
Con_Printf( "%s", MSG_ReadString( msg ));
break;
case svc_stufftext:
s = MSG_ReadString( msg );
if( cl_trace_stufftext.value )
{
size_t len = Q_strlen( s );
Con_Printf( "Stufftext: %s%c", s, len && s[len-1] == '\n' ? '\0' : '\n' );
}
#ifdef HACKS_RELATED_HLMODS
// disable Cry Of Fear antisave protection
if( !Q_strnicmp( s, "disconnect", 10 ) && cls.signon != SIGNONS )
break; // too early
#endif
Cbuf_AddFilteredText( s );
break;
case svc_setangle:
CL_ParseSetAngle( msg );
break;
case svc_serverdata:
Cbuf_Execute(); // make sure any stuffed commands are done
CL_ParseServerData( msg, PROTO_GOLDSRC );
break;
case svc_lightstyle:
CL_ParseLightStyle( msg, PROTO_GOLDSRC );
break;
case svc_updateuserinfo:
CL_UpdateUserinfo( msg, PROTO_GOLDSRC );
break;
case svc_deltatable: case svc_deltatable:
Delta_ParseTableField_GS( msg ); Delta_ParseTableField_GS( msg );
break; break;
@@ -663,8 +619,9 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg )
CL_UpdateUserPings( msg ); CL_UpdateUserPings( msg );
MSG_EndBitWriting( msg ); MSG_EndBitWriting( msg );
break; break;
case svc_particle: case svc_goldsrc_damage:
CL_ParseParticles( msg, PROTO_GOLDSRC ); case svc_spawnstatic:
// this does nothing
break; break;
case svc_event_reliable: case svc_event_reliable:
MSG_StartBitWriting( msg ); MSG_StartBitWriting( msg );
@@ -680,35 +637,18 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg )
case svc_setpause: case svc_setpause:
cl.paused = ( MSG_ReadByte( msg ) != 0 ); cl.paused = ( MSG_ReadByte( msg ) != 0 );
break; break;
case svc_signonnum: case svc_goldsrc_killedmonster:
CL_ParseSignon( msg, PROTO_GOLDSRC ); case svc_goldsrc_foundsecret:
break; // this does nothing
case svc_centerprint:
CL_CenterPrint( MSG_ReadString( msg ), 0.25f );
break; break;
case svc_goldsrc_spawnstaticsound: case svc_goldsrc_spawnstaticsound:
CL_ParseSpawnStaticSound( msg ); CL_ParseSpawnStaticSound( msg );
break; break;
case svc_finale:
CL_ParseFinaleCutscene( msg, 2 );
break;
case svc_restore:
CL_ParseRestore( msg );
break;
case svc_cutscene:
CL_ParseFinaleCutscene( msg, 3 );
break;
case svc_goldsrc_decalname: case svc_goldsrc_decalname:
param1 = MSG_ReadByte( msg ); param1 = MSG_ReadByte( msg );
s = MSG_ReadString( msg ); s = MSG_ReadString( msg );
Q_strncpy( host.draw_decals[param1], s, sizeof( host.draw_decals[param1] )); Q_strncpy( host.draw_decals[param1], s, sizeof( host.draw_decals[param1] ));
break; break;
case svc_addangle:
CL_ParseAddAngle( msg );
break;
case svc_usermessage:
CL_RegisterUserMessage( msg, PROTO_GOLDSRC );
break;
case svc_packetentities: case svc_packetentities:
playerbytes = CL_ParsePacketEntitiesGS( msg, false ); playerbytes = CL_ParsePacketEntitiesGS( msg, false );
cl.frames[cl.parsecountmod].graphdata.players += playerbytes; cl.frames[cl.parsecountmod].graphdata.players += playerbytes;
@@ -719,10 +659,6 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg )
cl.frames[cl.parsecountmod].graphdata.players += playerbytes; cl.frames[cl.parsecountmod].graphdata.players += playerbytes;
cl.frames[cl.parsecountmod].graphdata.entities += MSG_GetNumBytesRead( msg ) - bufStart - playerbytes; cl.frames[cl.parsecountmod].graphdata.entities += MSG_GetNumBytesRead( msg ) - bufStart - playerbytes;
break; break;
case svc_choke:
cl.frames[cls.netchan.incoming_sequence & CL_UPDATE_MASK].choked = true;
cl.frames[cls.netchan.incoming_sequence & CL_UPDATE_MASK].receivedtime = -2.0;
break;
case svc_resourcelist: case svc_resourcelist:
MSG_StartBitWriting( msg ); MSG_StartBitWriting( msg );
CL_ParseResourceList( msg, PROTO_GOLDSRC ); CL_ParseResourceList( msg, PROTO_GOLDSRC );
@@ -731,34 +667,6 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg )
case svc_deltamovevars: case svc_deltamovevars:
CL_ParseNewMovevars( msg ); CL_ParseNewMovevars( msg );
break; break;
case svc_resourcerequest:
CL_ParseResourceRequest( msg );
break;
case svc_customization:
CL_ParseCustomization( msg );
break;
case svc_crosshairangle:
CL_ParseCrosshairAngle( msg );
break;
case svc_soundfade:
CL_ParseSoundFade( msg );
break;
case svc_filetxferfailed:
CL_ParseFileTransferFailed( msg );
break;
case svc_hltv:
CL_ParseHLTV( msg );
break;
case svc_voiceinit:
CL_ParseVoiceInit( msg );
break;
case svc_voicedata:
CL_ParseVoiceData( msg, PROTO_GOLDSRC );
cl.frames[cl.parsecountmod].graphdata.voicebytes += MSG_GetNumBytesRead( msg ) - bufStart;
break;
case svc_resourcelocation:
CL_ParseResLocation( msg );
break;
case svc_goldsrc_sendextrainfo: case svc_goldsrc_sendextrainfo:
CL_ParseExtraInfo( msg ); CL_ParseExtraInfo( msg );
break; break;
@@ -768,15 +676,6 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg )
Con_Reportf( S_ERROR "%s: svc_goldsrc_timescale: implement me!\n", __func__ ); Con_Reportf( S_ERROR "%s: svc_goldsrc_timescale: implement me!\n", __func__ );
MSG_ReadFloat( msg ); MSG_ReadFloat( msg );
break; break;
case svc_querycvarvalue:
CL_ParseCvarValue( msg, false, PROTO_GOLDSRC );
break;
case svc_querycvarvalue2:
CL_ParseCvarValue( msg, true, PROTO_GOLDSRC );
break;
case svc_exec:
CL_ParseExec( msg );
break;
default: default:
CL_ParseUserMessage( msg, cmd, PROTO_GOLDSRC ); CL_ParseUserMessage( msg, cmd, PROTO_GOLDSRC );
cl.frames[cl.parsecountmod].graphdata.usr += MSG_GetNumBytesRead( msg ) - bufStart; cl.frames[cl.parsecountmod].graphdata.usr += MSG_GetNumBytesRead( msg ) - bufStart;
+7 -22
View File
@@ -213,6 +213,7 @@ static void CL_ParseQuakeServerInfo( sizebuf_t *msg )
clgame.maxEntities = bound( 600, clgame.maxEntities, MAX_EDICTS ); clgame.maxEntities = bound( 600, clgame.maxEntities, MAX_EDICTS );
clgame.maxModels = MAX_MODELS; clgame.maxModels = MAX_MODELS;
Q_strncpy( clgame.maptitle, MSG_ReadString( msg ), sizeof( clgame.maptitle )); Q_strncpy( clgame.maptitle, MSG_ReadString( msg ), sizeof( clgame.maptitle ));
Host_ValidateEngineFeatures( ENGINE_FEATURES_MASK, ENGINE_QUAKE_COMPATIBLE );
// Re-init hud video, especially if we changed game directories // Re-init hud video, especially if we changed game directories
clgame.dllFuncs.pfnVidInit(); clgame.dllFuncs.pfnVidInit();
@@ -929,12 +930,12 @@ void CL_ParseQuakeMessage( sizebuf_t *msg )
// record command for debugging spew on parse problem // record command for debugging spew on parse problem
CL_Parse_RecordCommand( cmd, bufStart ); CL_Parse_RecordCommand( cmd, bufStart );
if( CL_ParseCommonMessage( msg, PROTO_QUAKE, cmd, bufStart ))
continue;
// other commands // other commands
switch( cmd ) switch( cmd )
{ {
case svc_nop:
// this does nothing
break;
case svc_disconnect: case svc_disconnect:
CL_DemoCompleted (); CL_DemoCompleted ();
break; break;
@@ -946,9 +947,6 @@ void CL_ParseQuakeMessage( sizebuf_t *msg )
if( param1 != PROTOCOL_VERSION_QUAKE ) if( param1 != PROTOCOL_VERSION_QUAKE )
Host_Error( "Server is protocol %i instead of %i\n", param1, PROTOCOL_VERSION_QUAKE ); Host_Error( "Server is protocol %i instead of %i\n", param1, PROTOCOL_VERSION_QUAKE );
break; break;
case svc_setview:
CL_ParseViewEntity( msg );
break;
case svc_sound: case svc_sound:
CL_ParseQuakeSound( msg ); CL_ParseQuakeSound( msg );
cl.frames[cl.parsecountmod].graphdata.sound += MSG_GetNumBytesRead( msg ) - bufStart; cl.frames[cl.parsecountmod].graphdata.sound += MSG_GetNumBytesRead( msg ) - bufStart;
@@ -973,9 +971,6 @@ void CL_ParseQuakeMessage( sizebuf_t *msg )
Cbuf_Execute(); // make sure any stuffed commands are done Cbuf_Execute(); // make sure any stuffed commands are done
CL_ParseQuakeServerInfo( msg ); CL_ParseQuakeServerInfo( msg );
break; break;
case svc_lightstyle:
CL_ParseLightStyle( msg, PROTO_QUAKE );
break;
case svc_updatename: case svc_updatename:
param1 = MSG_ReadByte( msg ); param1 = MSG_ReadByte( msg );
Q_strncpy( cl.players[param1].name, MSG_ReadString( msg ), sizeof( cl.players[0].name )); Q_strncpy( cl.players[param1].name, MSG_ReadString( msg ), sizeof( cl.players[0].name ));
@@ -1028,8 +1023,7 @@ void CL_ParseQuakeMessage( sizebuf_t *msg )
CL_ParseQuakeSignon( msg ); CL_ParseQuakeSignon( msg );
break; break;
case svc_centerprint: case svc_centerprint:
str = MSG_ReadString( msg ); CL_HudMessage( MSG_ReadString( msg ));
CL_DispatchUserMessage( "HudText", Q_strlen( str ) + 1, (void *)str );
break; break;
case svc_killedmonster: case svc_killedmonster:
CL_DispatchQuakeMessage( "KillMonster" ); // just an event CL_DispatchQuakeMessage( "KillMonster" ); // just an event
@@ -1040,12 +1034,6 @@ void CL_ParseQuakeMessage( sizebuf_t *msg )
case svc_spawnstaticsound: case svc_spawnstaticsound:
CL_ParseQuakeStaticSound( msg ); CL_ParseQuakeStaticSound( msg );
break; break;
case svc_intermission:
cl.intermission = 1;
break;
case svc_finale:
CL_ParseFinaleCutscene( msg, 2 );
break;
case svc_cdtrack: case svc_cdtrack:
param1 = MSG_ReadByte( msg ); param1 = MSG_ReadByte( msg );
param1 = bound( 0, param1, MAX_CDTRACKS - 1 ); // tracknum param1 = bound( 0, param1, MAX_CDTRACKS - 1 ); // tracknum
@@ -1058,15 +1046,12 @@ void CL_ParseQuakeMessage( sizebuf_t *msg )
case svc_sellscreen: case svc_sellscreen:
Cmd_ExecuteString( "help" ); // open quake menu Cmd_ExecuteString( "help" ); // open quake menu
break; break;
case svc_cutscene: case svc_showlmp:
CL_ParseFinaleCutscene( msg, 3 ); CL_ParseNehahraShowLMP( msg );
break; break;
case svc_hidelmp: case svc_hidelmp:
CL_ParseNehahraHideLMP( msg ); CL_ParseNehahraHideLMP( msg );
break; break;
case svc_showlmp:
CL_ParseNehahraShowLMP( msg );
break;
case svc_skybox: case svc_skybox:
Q_strncpy( clgame.movevars.skyName, MSG_ReadString( msg ), sizeof( clgame.movevars.skyName )); Q_strncpy( clgame.movevars.skyName, MSG_ReadString( msg ), sizeof( clgame.movevars.skyName ));
break; break;
+1 -1
View File
@@ -744,7 +744,7 @@ void SCR_LoadCreditsFont( void )
success = Con_LoadVariableWidthFont( "gfx/creditsfont.fnt", font, scale, &hud_fontrender, TF_FONT ); success = Con_LoadVariableWidthFont( "gfx/creditsfont.fnt", font, scale, &hud_fontrender, TF_FONT );
if( !success ) if( !success )
success = Con_LoadFixedWidthFont( "gfx/conchars", font, scale, &hud_fontrender, TF_FONT ); success = Con_LoadFixedWidthFont( "gfx/conchars", font, scale, &hud_fontrender, TF_FONT|TF_NEAREST );
// copy font size for client.dll // copy font size for client.dll
if( success ) if( success )
+1
View File
@@ -535,6 +535,7 @@ void V_PostRender( void )
SCR_DrawEnts(); SCR_DrawEnts();
SCR_DrawNetGraph(); SCR_DrawNetGraph();
SCR_DrawUserCmd(); SCR_DrawUserCmd();
Joy_DrawDebug();
SV_DrawOrthoTriangles(); SV_DrawOrthoTriangles();
CL_DrawDemoRecording(); CL_DrawDemoRecording();
CL_DrawHUD( CL_CHANGELEVEL ); CL_DrawHUD( CL_CHANGELEVEL );
+20 -33
View File
@@ -26,6 +26,7 @@ GNU General Public License for more details.
#include "pm_defs.h" #include "pm_defs.h"
#include "ref_params.h" #include "ref_params.h"
#include "render_api.h" #include "render_api.h"
#include "sound_api.h"
#include "cdll_exp.h" #include "cdll_exp.h"
#include "screenfade.h" #include "screenfade.h"
#include "protocol.h" #include "protocol.h"
@@ -36,11 +37,6 @@ GNU General Public License for more details.
#include "voice.h" #include "voice.h"
#include "q_client.h" #include "q_client.h"
// client sprite types
#define SPR_CLIENT 0 // client sprite for temp-entities or user-textures
#define SPR_HUDSPRITE 1 // hud sprite
#define SPR_MAPSPRITE 2 // contain overview.bmp that diced into frames 128x128
//============================================================================= //=============================================================================
typedef struct netbandwithgraph_s typedef struct netbandwithgraph_s
{ {
@@ -111,6 +107,8 @@ extern int CL_UPDATE_BACKUP;
#define MAX_EX_INTERP 0.1f #define MAX_EX_INTERP 0.1f
#define MAX_TEXTCHANNELS 8 // must be power of two (GoldSrc uses 4 channels)
#define CL_MIN_RESEND_TIME 1.5f // mininum time gap (in seconds) before a subsequent connection request is sent. #define CL_MIN_RESEND_TIME 1.5f // mininum time gap (in seconds) before a subsequent connection request is sent.
#define CL_MAX_RESEND_TIME 20.0f // max time. The cvar cl_resend is bounded by these. #define CL_MAX_RESEND_TIME 20.0f // max time. The cvar cl_resend is bounded by these.
@@ -310,6 +308,14 @@ typedef enum
CL_CHANGELEVEL, // draw 'loading' during changelevel CL_CHANGELEVEL, // draw 'loading' during changelevel
} scrstate_t; } scrstate_t;
// client sprite types
enum
{
SPR_CLIENT = 0, // client sprite for temp-entities or user-textures
SPR_HUDSPRITE, // hud sprite
SPR_MAPSPRITE, // contain overview.bmp that diced into frames 128x128
};
typedef struct typedef struct
{ {
char name[32]; char name[32];
@@ -449,6 +455,7 @@ typedef struct
void *hInstance; // pointer to client.dll void *hInstance; // pointer to client.dll
cldll_func_t dllFuncs; // dll exported funcs cldll_func_t dllFuncs; // dll exported funcs
render_interface_t drawFuncs; // custom renderer support render_interface_t drawFuncs; // custom renderer support
sound_interface_t soundFuncs; // custom sound support
poolhandle_t mempool; // client edicts pool poolhandle_t mempool; // client edicts pool
string mapname; // map name string mapname; // map name
string maptitle; // display map title string maptitle; // display map title
@@ -731,10 +738,7 @@ extern convar_t cl_fixmodelinterpolationartifacts;
//============================================================================= //=============================================================================
void CL_SetLightstyle( int style, const char* s, float f ); extern client_textmessage_t cl_textmessage[MAX_TEXTCHANNELS];
void CL_DecayLights( void );
dlight_t *CL_GetDynamicLight( int number );
dlight_t *CL_GetEntityLight( int number );
//================================================= //=================================================
@@ -853,6 +857,7 @@ void CL_FreeEdicts( void );
void CL_ClearWorld( void ); void CL_ClearWorld( void );
void CL_DrawCenterPrint( void ); void CL_DrawCenterPrint( void );
void CL_ClearSpriteTextures( void ); void CL_ClearSpriteTextures( void );
void CL_HudMessage( const char *pMessage );
void CL_CenterPrint( const char *text, float y ); void CL_CenterPrint( const char *text, float y );
client_textmessage_t *CL_TextMessageGet( const char *pName ); client_textmessage_t *CL_TextMessageGet( const char *pName );
void NetAPI_CancelAllRequests( void ); void NetAPI_CancelAllRequests( void );
@@ -923,45 +928,23 @@ static inline cl_entity_t *CL_GetLocalPlayer( void )
// //
// cl_parse.c // cl_parse.c
// //
void CL_ParseSetAngle( sizebuf_t *msg );
void CL_ParseServerData( sizebuf_t *msg, connprotocol_t proto );
void CL_ParseLightStyle( sizebuf_t *msg, connprotocol_t proto );
void CL_UpdateUserinfo( sizebuf_t *msg, connprotocol_t proto );
void CL_ParseResource( sizebuf_t *msg ); void CL_ParseResource( sizebuf_t *msg );
void CL_ParseClientData( sizebuf_t *msg, connprotocol_t proto ); void CL_ParseClientData( sizebuf_t *msg, connprotocol_t proto );
void CL_UpdateUserPings( sizebuf_t *msg ); void CL_UpdateUserPings( sizebuf_t *msg );
void CL_ParseParticles( sizebuf_t *msg, connprotocol_t proto );
void CL_ParseBaseline( sizebuf_t *msg, connprotocol_t proto ); void CL_ParseBaseline( sizebuf_t *msg, connprotocol_t proto );
void CL_ParseSignon( sizebuf_t *msg, connprotocol_t proto );
void CL_ParseRestore( sizebuf_t *msg );
void CL_ParseStaticDecal( sizebuf_t *msg ); void CL_ParseStaticDecal( sizebuf_t *msg );
void CL_ParseAddAngle( sizebuf_t *msg );
void CL_RegisterUserMessage( sizebuf_t *msg, connprotocol_t proto );
void CL_ParseResourceList( sizebuf_t *msg, connprotocol_t proto ); void CL_ParseResourceList( sizebuf_t *msg, connprotocol_t proto );
void CL_ParseMovevars( sizebuf_t *msg ); void CL_ParseMovevars( sizebuf_t *msg );
void CL_ParseResourceRequest( sizebuf_t *msg );
void CL_ParseCustomization( sizebuf_t *msg );
void CL_ParseCrosshairAngle( sizebuf_t *msg );
void CL_ParseSoundFade( sizebuf_t *msg );
void CL_ParseFileTransferFailed( sizebuf_t *msg );
void CL_ParseHLTV( sizebuf_t *msg );
void CL_ParseDirector( sizebuf_t *msg );
void CL_ParseVoiceInit( sizebuf_t *msg );
void CL_ParseVoiceData( sizebuf_t *msg, connprotocol_t proto );
void CL_ParseResLocation( sizebuf_t *msg );
void CL_ParseCvarValue( sizebuf_t *msg, const qboolean ext, const connprotocol_t proto );
void CL_ParseServerMessage( sizebuf_t *msg ); void CL_ParseServerMessage( sizebuf_t *msg );
qboolean CL_ParseCommonDLLMessage( sizebuf_t *msg, connprotocol_t proto, int svc_num, int startoffset ); qboolean CL_ParseCommonMessage( sizebuf_t *msg, connprotocol_t proto, int svc_num, int startoffset );
qboolean CL_ParseCommonHLMessage( sizebuf_t *msg, connprotocol_t proto, int svc_num, int startoffset );
void CL_ParseTempEntity( sizebuf_t *msg, connprotocol_t proto ); void CL_ParseTempEntity( sizebuf_t *msg, connprotocol_t proto );
qboolean CL_DispatchUserMessage( const char *pszName, int iSize, void *pbuf ); qboolean CL_DispatchUserMessage( const char *pszName, int iSize, void *pbuf );
qboolean CL_RequestMissingResources( void ); qboolean CL_RequestMissingResources( void );
void CL_RegisterResources( sizebuf_t *msg, connprotocol_t proto ); void CL_RegisterResources( sizebuf_t *msg, connprotocol_t proto );
void CL_ParseViewEntity( sizebuf_t *msg );
void CL_ParseServerTime( sizebuf_t *msg, connprotocol_t proto ); void CL_ParseServerTime( sizebuf_t *msg, connprotocol_t proto );
void CL_ParseUserMessage( sizebuf_t *msg, int svc_num, connprotocol_t proto ); void CL_ParseUserMessage( sizebuf_t *msg, int svc_num, connprotocol_t proto );
void CL_ParseFinaleCutscene( sizebuf_t *msg, int level );
void CL_ParseTextMessage( sizebuf_t *msg ); void CL_ParseTextMessage( sizebuf_t *msg );
void CL_ParseExec( sizebuf_t *msg );
void CL_BatchResourceRequest( qboolean initialize ); void CL_BatchResourceRequest( qboolean initialize );
int CL_EstimateNeededResources( void ); int CL_EstimateNeededResources( void );
@@ -1083,6 +1066,10 @@ void R_AddEfrags( cl_entity_t *ent );
// cl_tent.c // cl_tent.c
// //
struct particle_s; struct particle_s;
void CL_SetLightstyle( int style, const char* s, float f );
void CL_DecayLights( void );
dlight_t *CL_GetDynamicLight( int number );
dlight_t *CL_GetEntityLight( int number );
void CL_WeaponAnim( int iAnim, int body ); void CL_WeaponAnim( int iAnim, int body );
void CL_ClearEffects( void ); void CL_ClearEffects( void );
void CL_ClearEfrags( void ); void CL_ClearEfrags( void );
+1 -1
View File
@@ -1573,7 +1573,7 @@ void Key_Console( int key )
} }
// command completion // command completion
if( key == K_TAB || key == K_L2_BUTTON ) if( key == K_TAB || key == K_L2_BUTTON || key == K_LTRIGGER )
{ {
Con_CompleteCommand( &con.input, true ); Con_CompleteCommand( &con.input, true );
Con_Bottom(); Con_Bottom();
+215 -8
View File
@@ -24,8 +24,6 @@ GNU General Public License for more details.
#define SHRT_MAX 0x7FFF #define SHRT_MAX 0x7FFF
#endif #endif
#define MAX_AXES JOY_AXIS_NULL
// index - axis num come from event // index - axis num come from event
// value - inner axis // value - inner axis
static engineAxis_t joyaxesmap[MAX_AXES] = static engineAxis_t joyaxesmap[MAX_AXES] =
@@ -42,7 +40,9 @@ static struct joy_axis_s
{ {
short val; short val;
short prevval; short prevval;
short rawval; // value before deadzone zeroing, for debug display
} joyaxis[MAX_AXES] = { 0 }; } joyaxis[MAX_AXES] = { 0 };
static qboolean joy_initialized; static qboolean joy_initialized;
static CVAR_DEFINE_AUTO( joy_pitch, "100.0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "joystick pitch sensitivity" ); static CVAR_DEFINE_AUTO( joy_pitch, "100.0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "joystick pitch sensitivity" );
@@ -62,6 +62,15 @@ static CVAR_DEFINE_AUTO( joy_axis_binding, "sfpyrl", FCVAR_ARCHIVE | FCVAR_FILTE
CVAR_DEFINE_AUTO( joy_enable, "1", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "enable joystick" ); CVAR_DEFINE_AUTO( joy_enable, "1", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "enable joystick" );
static CVAR_DEFINE_AUTO( joy_have_gyro, "0", FCVAR_READ_ONLY, "tells whether current active gamepad has gyroscope or not" ); static CVAR_DEFINE_AUTO( joy_have_gyro, "0", FCVAR_READ_ONLY, "tells whether current active gamepad has gyroscope or not" );
static CVAR_DEFINE_AUTO( joy_calibrated, "0", FCVAR_READ_ONLY, "tells whether current active gamepad gyroscope has been calibrated or not" ); static CVAR_DEFINE_AUTO( joy_calibrated, "0", FCVAR_READ_ONLY, "tells whether current active gamepad gyroscope has been calibrated or not" );
static CVAR_DEFINE_AUTO( joy_gyro_pitch, "1.0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "gyroscope sensitivity for looking up and down" );
static CVAR_DEFINE_AUTO( joy_gyro_yaw, "1.0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "gyroscope sensitivity for turning left and right" );
static CVAR_DEFINE_AUTO( joy_gyro_roll, "0.0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "gyroscope sensitivity when tilting the device sideways" );
static CVAR_DEFINE_AUTO( joy_debug, "0", 0, "visualize gamepad axes and buttons" );
// stores the latest instantaneous gyroscope rotation rates (in rad/s) from platform input
static vec3_t joy_gyro_speed;
// last non-zero gyro speed, retained for debug display after joy_gyro_speed is cleared
static vec3_t joy_gyro_speed_display;
/* /*
============ ============
@@ -228,6 +237,8 @@ static void Joy_ProcessStick( const engineAxis_t engineAxis, short value )
break; break;
} }
joyaxis[engineAxis].rawval = value;
if( value < deadzone && value > -deadzone ) if( value < deadzone && value > -deadzone )
value = 0; // caught new event in deadzone, fill it with zero(no motion) value = 0; // caught new event in deadzone, fill it with zero(no motion)
@@ -257,7 +268,12 @@ Axis events
*/ */
void Joy_AxisMotionEvent( engineAxis_t engineAxis, short value ) void Joy_AxisMotionEvent( engineAxis_t engineAxis, short value )
{ {
if( engineAxis >= JOY_AXIS_NULL ) if( engineAxis >= MAX_AXES )
return;
engineAxis = joyaxesmap[engineAxis];
if( engineAxis >= MAX_AXES )
return; return;
if( value == joyaxis[engineAxis].val ) if( value == joyaxis[engineAxis].val )
@@ -278,7 +294,8 @@ Gyroscope events
*/ */
void Joy_GyroEvent( vec3_t data ) void Joy_GyroEvent( vec3_t data )
{ {
VectorCopy( data, joy_gyro_speed );
VectorCopy( data, joy_gyro_speed_display );
} }
/* /*
@@ -290,7 +307,7 @@ Append movement from axis. Called everyframe
*/ */
void Joy_FinalizeMove( float *fw, float *side, float *dpitch, float *dyaw ) void Joy_FinalizeMove( float *fw, float *side, float *dpitch, float *dyaw )
{ {
if( !Joy_IsActive() ) if( !Joy_IsActive( ))
return; return;
if( FBitSet( joy_axis_binding.flags, FCVAR_CHANGED ) ) if( FBitSet( joy_axis_binding.flags, FCVAR_CHANGED ) )
@@ -308,7 +325,7 @@ void Joy_FinalizeMove( float *fw, float *side, float *dpitch, float *dyaw )
case 'p': joyaxesmap[i] = JOY_AXIS_PITCH; break; case 'p': joyaxesmap[i] = JOY_AXIS_PITCH; break;
case 'r': joyaxesmap[i] = JOY_AXIS_RT; break; case 'r': joyaxesmap[i] = JOY_AXIS_RT; break;
case 'l': joyaxesmap[i] = JOY_AXIS_LT; break; case 'l': joyaxesmap[i] = JOY_AXIS_LT; break;
default : joyaxesmap[i] = JOY_AXIS_NULL; break; default : joyaxesmap[i] = MAX_AXES; break;
} }
} }
@@ -317,8 +334,193 @@ void Joy_FinalizeMove( float *fw, float *side, float *dpitch, float *dyaw )
*fw -= joy_forward.value * (float)joyaxis[JOY_AXIS_FWD ].val/(float)SHRT_MAX; // must be form -1.0 to 1.0 *fw -= joy_forward.value * (float)joyaxis[JOY_AXIS_FWD ].val/(float)SHRT_MAX; // must be form -1.0 to 1.0
*side += joy_side.value * (float)joyaxis[JOY_AXIS_SIDE].val/(float)SHRT_MAX; *side += joy_side.value * (float)joyaxis[JOY_AXIS_SIDE].val/(float)SHRT_MAX;
*dpitch -= joy_pitch.value * (float)joyaxis[JOY_AXIS_PITCH].val/(float)SHRT_MAX * host.realframetime; *dpitch += joy_pitch.value * (float)joyaxis[JOY_AXIS_PITCH].val/(float)SHRT_MAX * host.realframetime;
*dyaw += joy_yaw.value * (float)joyaxis[JOY_AXIS_YAW ].val/(float)SHRT_MAX * host.realframetime; *dyaw -= joy_yaw.value * (float)joyaxis[JOY_AXIS_YAW ].val/(float)SHRT_MAX * host.realframetime;
if( joy_have_gyro.value && (int)joy_calibrated.value == JOY_CALIBRATED )
{
float pitch_speed = joy_gyro_speed[0] * ( 180.0f / M_PI );
float yaw_speed = joy_gyro_speed[1] * ( 180.0f / M_PI );
float roll_speed = joy_gyro_speed[2] * ( 180.0f / M_PI );
*dpitch -= joy_gyro_pitch.value * pitch_speed * host.realframetime;
*dyaw += joy_gyro_yaw.value * yaw_speed * host.realframetime;
*dyaw += joy_gyro_roll.value * roll_speed * host.realframetime;
}
VectorClear( joy_gyro_speed );
}
/*
=============
Joy_DrawDebug
Draw gamepad axes and buttons for debugging (joy_debug 1)
=============
*/
void Joy_DrawDebug( void )
{
static const int buttons[] =
{
K_A_BUTTON, K_B_BUTTON, K_X_BUTTON, K_Y_BUTTON, 0,
K_L1_BUTTON, K_R1_BUTTON, 0,
K_L2_BUTTON, K_R2_BUTTON, 0,
K_BACK_BUTTON, K_MODE_BUTTON, K_START_BUTTON, 0,
K_LSTICK, K_RSTICK, 0,
// simulated buttons
K_DPAD_UP, K_DPAD_DOWN, K_DPAD_LEFT, K_DPAD_RIGHT, 0,
K_LTRIGGER, K_RTRIGGER, 0,
// additional buttons
K_C_BUTTON, K_Z_BUTTON, K_MISC_BUTTON, 0,
K_PADDLE1_BUTTON, K_PADDLE2_BUTTON, K_PADDLE3_BUTTON, K_PADDLE4_BUTTON, 0
};
static const char *const axisnames[MAX_AXES] = { "SIDE", "FWD", "PITCH", "YAW", "RT", "LT" };
// deadzone for sticks, threshold for triggers
static const convar_t *const axis_threshold[MAX_AXES] =
{
&joy_side_deadzone,
&joy_forward_deadzone,
&joy_pitch_deadzone,
&joy_yaw_deadzone,
&joy_rt_threshold,
&joy_lt_threshold,
};
cl_font_t *font = Con_GetCurFont();
if( !joy_debug.value || !Joy_IsActive( ))
return;
float x = 8;
float y = 100;
const float bar_w = 100;
const float halfbar_w = bar_w * 0.5f;
const float bar_h = font->charHeight - 2;
const float center = x + halfbar_w;
const rgba_t bar_backcolor = { 40, 40, 40, 180 };
const rgba_t bar_fillcolor = { 100, 200, 100, 200 };
// draw axes as labeled bars
for( int i = 0; i < MAX_AXES; i++ )
{
qboolean is_trigger = ( i >= JOY_AXIS_RT );
float fval = (float)joyaxis[i].val / SHRT_MAX;
float fprev = (float)joyaxis[i].prevval / SHRT_MAX;
float fthreshold = axis_threshold[i]->value / SHRT_MAX;
CL_DrawString( x, y, axisnames[i], g_color_table[7], font, 0 );
y += font->charHeight;
// background
ref.dllFuncs.FillRGBA( kRenderTransTexture, x, y, bar_w, bar_h, bar_backcolor[0], bar_backcolor[1], bar_backcolor[2], bar_backcolor[3] );
if( is_trigger )
{
// fill bar from the left for triggers
float filled = fval * bar_w;
if( filled > 0 )
ref.dllFuncs.FillRGBA( kRenderTransTexture, x, y, filled, bar_h, bar_fillcolor[0], bar_fillcolor[1], bar_fillcolor[2], bar_fillcolor[3] );
// fill threshold with red, and yellow edge marker
float thresh_x = x + fthreshold * bar_w;
ref.dllFuncs.FillRGBA( kRenderTransTexture, x, y, thresh_x - x, bar_h, 180, 40, 40, 120 );
ref.dllFuncs.FillRGBA( kRenderTransTexture, thresh_x, y, 1, bar_h, 255, 200, 0, 220 );
// prevval marker
float prev_x = x + fprev * bar_w;
ref.dllFuncs.FillRGBA( kRenderTransTexture, prev_x, y, 1, bar_h, 200, 200, 200, 180 );
}
else
{
// for sticks bar is filled from the center
float filled = fval * halfbar_w;
ref.dllFuncs.FillRGBA( kRenderTransTexture, center + Q_min( 0, filled ), y, fabs( filled ), bar_h, bar_fillcolor[0], bar_fillcolor[1], bar_fillcolor[2], bar_fillcolor[3] );
// fill deadzone with red, and yellow edge marker
float thresh_x = fthreshold * halfbar_w;
ref.dllFuncs.FillRGBA( kRenderTransTexture, center - thresh_x, y, thresh_x * 2, bar_h, 180, 40, 40, 120 );
ref.dllFuncs.FillRGBA( kRenderTransTexture, center + thresh_x, y, 1, bar_h, 255, 200, 0, 220 );
ref.dllFuncs.FillRGBA( kRenderTransTexture, center - thresh_x, y, 1, bar_h, 255, 200, 0, 220 );
// mark the center
ref.dllFuncs.FillRGBA( kRenderTransTexture, center, y, 1, bar_h, 180, 180, 180, 220 );
// now draw the actual value
float raw_x = center + ((float)joyaxis[i].rawval / SHRT_MAX * halfbar_w );
ref.dllFuncs.FillRGBA( kRenderTransTexture, raw_x, y, 1, bar_h, 255, 255, 100, 200 );
// prevval marker
float prev_x = center + fprev * halfbar_w;
ref.dllFuncs.FillRGBA( kRenderTransTexture, prev_x, y, 1, bar_h, 200, 200, 200, 180 );
}
y += bar_h + 2;
}
// draw gyro if available
if( joy_have_gyro.value )
{
static const char *gyronames[3] = { "GYRO P", "GYRO Y", "GYRO R" };
for( int i = 0; i < 3; i++ )
{
// clamp to +-5 rad/s for display
float fval = joy_gyro_speed_display[i] / 5.0f;
fval = bound( -1.0f, fval, 1.0f );
CL_DrawString( x, y, gyronames[i], g_color_table[7], font, 0 );
y += font->charHeight;
// background
ref.dllFuncs.FillRGBA( kRenderTransTexture, x, y, bar_w, bar_h, bar_backcolor[0], bar_backcolor[1], bar_backcolor[2], bar_backcolor[3] );
// for gyro bar is filled from the center
float filled = fval * halfbar_w;
ref.dllFuncs.FillRGBA( kRenderTransTexture, center + Q_min( 0, filled ), y, fabs( filled ), bar_h, bar_fillcolor[0], bar_fillcolor[1], bar_fillcolor[2], bar_fillcolor[3] );
// mark the center
ref.dllFuncs.FillRGBA( kRenderTransTexture, center, y, 1, bar_h, 180, 180, 180, 220 );
// gyro doesn't have deadzones or prevval like axes
y += bar_h + 2;
}
}
// draw buttons in a row
y += 4;
x = 8;
for( int i = 0; i < ARRAYSIZE( buttons ); i++ )
{
if( !buttons[i] )
{
x = 8;
y += font->charHeight;
continue;
}
qboolean pressed = Key_IsDown( buttons[i] );
int btn_w = 0;
rgba_t color;
string name;
Q_strncpy( name, Key_KeynumToString( buttons[i] ), sizeof( name ));
char *p = Q_strstr( name, "_BUTTON" );
if( p )
*p = 0;
MakeRGBA( color, pressed ? 0 : 255, pressed ? 255 : 0, 0, 255 );
CL_DrawString( x, y, name, color, font, 0 );
CL_DrawStringLen( font, name, &btn_w, NULL, 0 );
x += btn_w + 6;
}
} }
static void Joy_CalibrateGyro_f( void ) static void Joy_CalibrateGyro_f( void )
@@ -367,6 +569,11 @@ void Joy_Init( void )
Cvar_RegisterVariable( &joy_calibrated ); Cvar_RegisterVariable( &joy_calibrated );
Cvar_RegisterVariable( &joy_enable ); Cvar_RegisterVariable( &joy_enable );
Cvar_RegisterVariable( &joy_gyro_pitch );
Cvar_RegisterVariable( &joy_gyro_yaw );
Cvar_RegisterVariable( &joy_gyro_roll );
Cvar_RegisterVariable( &joy_debug );
// renamed from -nojoy to -noenginejoy to not conflict with // renamed from -nojoy to -noenginejoy to not conflict with
// client.dll's joystick support // client.dll's joystick support
if( Sys_CheckParm( "-noenginejoy" )) if( Sys_CheckParm( "-noenginejoy" ))
+2 -2
View File
@@ -2189,12 +2189,12 @@ int IN_TouchEvent( touchEventType type, int fingerID, float x, float y, float dx
return Touch_ControlsEvent( type, fingerID, x, y, dx, dy ); return Touch_ControlsEvent( type, fingerID, x, y, dx, dy );
} }
void Touch_GetMove( float *forward, float *side, float *yaw, float *pitch ) void Touch_GetMove( float *forward, float *side, float *pitch, float *yaw )
{ {
*forward += touch.forward; *forward += touch.forward;
*side += touch.side; *side += touch.side;
*yaw += touch.yaw;
*pitch += touch.pitch; *pitch += touch.pitch;
*yaw += touch.yaw;
touch.yaw = touch.pitch = 0; touch.yaw = touch.pitch = 0;
} }
+2 -2
View File
@@ -560,8 +560,8 @@ static void IN_CollectInput( float *forward, float *side, float *pitch, float *y
#endif #endif
} }
Joy_FinalizeMove( forward, side, yaw, pitch ); Joy_FinalizeMove( forward, side, pitch, yaw );
Touch_GetMove( forward, side, yaw, pitch ); Touch_GetMove( forward, side, pitch, yaw );
if( look_filter.value ) if( look_filter.value )
{ {
+4 -3
View File
@@ -71,7 +71,7 @@ static inline void Touch_AddDefaultButton( const char *name, const char *texture
static inline void Touch_WriteConfig( void ) { } static inline void Touch_WriteConfig( void ) { }
static inline void Touch_Init( void ) { } static inline void Touch_Init( void ) { }
static inline void Touch_Shutdown( void ) { } static inline void Touch_Shutdown( void ) { }
static inline void Touch_GetMove( float * forward, float *side, float *yaw, float *pitch ) { } static inline void Touch_GetMove( float * forward, float *side, float *pitch, float *yaw ) { }
static inline void Touch_ResetDefaultButtons( void ) { } static inline void Touch_ResetDefaultButtons( void ) { }
static inline int IN_TouchEvent( touchEventType type, int fingerID, float x, float y, float dx, float dy ) { return 0; } static inline int IN_TouchEvent( touchEventType type, int fingerID, float x, float y, float dx, float dy ) { return 0; }
static inline void Touch_KeyEvent( int key, int down ) { } static inline void Touch_KeyEvent( int key, int down ) { }
@@ -87,7 +87,7 @@ void Touch_AddDefaultButton( const char *name, const char *texturefile, const ch
void Touch_WriteConfig( void ); void Touch_WriteConfig( void );
void Touch_Init( void ); void Touch_Init( void );
void Touch_Shutdown( void ); void Touch_Shutdown( void );
void Touch_GetMove( float * forward, float *side, float *yaw, float *pitch ); void Touch_GetMove( float * forward, float *side, float *pitch, float *yaw );
void Touch_ResetDefaultButtons( void ); void Touch_ResetDefaultButtons( void );
int IN_TouchEvent( touchEventType type, int fingerID, float x, float y, float dx, float dy ); int IN_TouchEvent( touchEventType type, int fingerID, float x, float y, float dx, float dy );
void Touch_KeyEvent( int key, int down ); void Touch_KeyEvent( int key, int down );
@@ -119,7 +119,7 @@ typedef enum engineAxis_e
JOY_AXIS_YAW, JOY_AXIS_YAW,
JOY_AXIS_RT, JOY_AXIS_RT,
JOY_AXIS_LT, JOY_AXIS_LT,
JOY_AXIS_NULL MAX_AXES,
} engineAxis_t; } engineAxis_t;
typedef enum joy_calibration_state_s typedef enum joy_calibration_state_s
@@ -136,6 +136,7 @@ void Joy_SetCalibrationState( joy_calibration_state_t state );
void Joy_AxisMotionEvent( engineAxis_t engineAxis, short value ); void Joy_AxisMotionEvent( engineAxis_t engineAxis, short value );
void Joy_GyroEvent( vec3_t data ); void Joy_GyroEvent( vec3_t data );
void Joy_FinalizeMove( float *fw, float *side, float *dpitch, float *dyaw ); void Joy_FinalizeMove( float *fw, float *side, float *dpitch, float *dyaw );
void Joy_DrawDebug( void );
void Joy_Init( void ); void Joy_Init( void );
void Joy_Shutdown( void ); void Joy_Shutdown( void );
+15 -8
View File
@@ -152,7 +152,7 @@ sfx_t *S_FindName( const char *pname, qboolean *pfInCache )
uint i, hash; uint i, hash;
string name; string name;
if( COM_StringEmptyOrNULL( pname ) || !dma.initialized ) if( COM_StringEmptyOrNULL( pname ) || !snd.initialized )
return NULL; return NULL;
if( Q_strlen( pname ) >= sizeof( sfx->name )) if( Q_strlen( pname ) >= sizeof( sfx->name ))
@@ -232,6 +232,12 @@ void S_FreeSound( sfx_t *sfx )
prev = &hashSfx->hashNext; prev = &hashSfx->hashNext;
} }
if( clgame.soundFuncs.pfnS_FreeSound )
{
clgame.soundFuncs.pfnS_FreeSound( sfx, sfx - s_knownSfx );
return;
}
if( sfx->cache ) if( sfx->cache )
FS_FreeSound( sfx->cache ); FS_FreeSound( sfx->cache );
memset( sfx, 0, sizeof( *sfx )); memset( sfx, 0, sizeof( *sfx ));
@@ -247,7 +253,7 @@ void S_BeginRegistration( void )
{ {
int i; int i;
snd_ambient = false; snd.have_ambient_sfx = false;
// check for automatic ambient sounds // check for automatic ambient sounds
for( i = 0; i < NUM_AMBIENTS; i++ ) for( i = 0; i < NUM_AMBIENTS; i++ )
@@ -255,8 +261,9 @@ void S_BeginRegistration( void )
if( !GI->ambientsound[i][0] ) if( !GI->ambientsound[i][0] )
continue; // empty slot continue; // empty slot
ambient_sfx[i] = S_RegisterSound( GI->ambientsound[i] ); snd.ambient_sfx[i] = S_RegisterSound( GI->ambientsound[i] );
if( ambient_sfx[i] ) snd_ambient = true; // allow auto-ambients if( snd.ambient_sfx[i] )
snd.have_ambient_sfx = true; // allow auto-ambients
} }
s_registering = true; s_registering = true;
@@ -273,7 +280,7 @@ void S_EndRegistration( void )
sfx_t *sfx; sfx_t *sfx;
int i; int i;
if( !s_registering || !dma.initialized ) if( !s_registering || !snd.initialized )
return; return;
// free any sounds not from this registration sequence // free any sounds not from this registration sequence
@@ -306,7 +313,7 @@ sound_t S_RegisterSound( const char *name )
{ {
sfx_t *sfx; sfx_t *sfx;
if( COM_StringEmptyOrNULL( name ) || !dma.initialized ) if( COM_StringEmptyOrNULL( name ) || !snd.initialized )
return -1; return -1;
if( S_TestSoundChar( name, '!' )) if( S_TestSoundChar( name, '!' ))
@@ -330,7 +337,7 @@ sound_t S_RegisterSound( const char *name )
sfx_t *S_GetSfxByHandle( sound_t handle ) sfx_t *S_GetSfxByHandle( sound_t handle )
{ {
if( !dma.initialized ) if( !snd.initialized )
return NULL; return NULL;
// create new sfx // create new sfx
@@ -369,7 +376,7 @@ void S_FreeSounds( void )
sfx_t *sfx; sfx_t *sfx;
int i; int i;
if( !dma.initialized ) if( !snd.initialized )
return; return;
// stop all sounds // stop all sounds
+322 -265
View File
File diff suppressed because it is too large Load Diff
+45 -38
View File
@@ -120,7 +120,7 @@ static void S_MixAudio( portable_samplepair_t *pbuf, const int *pvol, const void
static int S_AdjustNumSamples( channel_t *chan, int num_samples, double rate, double timecompress_rate ) static int S_AdjustNumSamples( channel_t *chan, int num_samples, double rate, double timecompress_rate )
{ {
if( chan->finished ) if( FBitSet( chan->flags, FL_CHAN_FINISHED ))
return 0; return 0;
// if channel is set to end at specific sample, // if channel is set to end at specific sample,
@@ -132,7 +132,7 @@ static int S_AdjustNumSamples( channel_t *chan, int num_samples, double rate, do
if( end_sample >= chan->forced_end ) if( end_sample >= chan->forced_end )
{ {
chan->finished = true; SetBits( chan->flags, FL_CHAN_FINISHED );
return floor(( chan->forced_end - chan->sample ) / ( rate * timecompress_rate )); return floor(( chan->forced_end - chan->sample ) / ( rate * timecompress_rate ));
} }
} }
@@ -153,7 +153,7 @@ static int S_MixChannelToBuffer( portable_samplepair_t *pbuf, channel_t *chan, i
// timecompress at 100% is skipping the entire sfx, so mark as finished and exit // timecompress at 100% is skipping the entire sfx, so mark as finished and exit
if( timecompress >= 100 ) if( timecompress >= 100 )
{ {
chan->finished = true; SetBits( chan->flags, FL_CHAN_FINISHED );
return 0; return 0;
} }
@@ -173,7 +173,7 @@ static int S_MixChannelToBuffer( portable_samplepair_t *pbuf, channel_t *chan, i
// get sample pointer and also amount of samples available // get sample pointer and also amount of samples available
const void *audio = NULL; const void *audio = NULL;
int available = S_RetrieveAudioSamples( chan->sfx->cache, &audio, chan->sample, request_num_samples, chan->use_loop ); int available = S_RetrieveAudioSamples( chan->sfx->cache, &audio, chan->sample, request_num_samples, FBitSet( chan->flags, FL_CHAN_USE_LOOP ));
// no samples available, exit // no samples available, exit
if( !available ) if( !available )
@@ -196,7 +196,7 @@ static int S_MixChannelToBuffer( portable_samplepair_t *pbuf, channel_t *chan, i
// samples couldn't be retrieved, mark as finished // samples couldn't be retrieved, mark as finished
if( num_samples > 0 ) if( num_samples > 0 )
chan->finished = true; SetBits( chan->flags, FL_CHAN_FINISHED );
// total amount of samples mixed // total amount of samples mixed
return offset - initial_offset; return offset - initial_offset;
@@ -206,10 +206,10 @@ static int VOX_MixChannelToBuffer( portable_samplepair_t *pbuf, channel_t *chan,
{ {
int offset = 0; int offset = 0;
if( chan->sentence_finished ) if( FBitSet( chan->flags, FL_CHAN_SENTENCE_FINISHED ))
return 0; return 0;
while( num_samples > 0 && !chan->sentence_finished ) while( num_samples > 0 && !FBitSet( chan->flags, FL_CHAN_SENTENCE_FINISHED ))
{ {
int outputCount = S_MixChannelToBuffer( pbuf, chan, num_samples, out_rate, pitch, offset, chan->words[chan->word_index].timecompress ); int outputCount = S_MixChannelToBuffer( pbuf, chan, num_samples, out_rate, pitch, offset, chan->words[chan->word_index].timecompress );
@@ -217,13 +217,13 @@ static int VOX_MixChannelToBuffer( portable_samplepair_t *pbuf, channel_t *chan,
num_samples -= outputCount; num_samples -= outputCount;
// if we finished load a next word // if we finished load a next word
if( chan->finished ) if( FBitSet( chan->flags, FL_CHAN_FINISHED ))
{ {
VOX_FreeWord( chan ); VOX_FreeWord( chan );
chan->word_index++; chan->word_index++;
VOX_LoadWord( chan ); VOX_LoadWord( chan );
if( !chan->sentence_finished ) if( !FBitSet( chan->flags, FL_CHAN_SENTENCE_FINISHED ))
chan->sfx = chan->words[chan->word_index].sfx; chan->sfx = chan->words[chan->word_index].sfx;
} }
} }
@@ -235,7 +235,7 @@ static int S_MixNormalChannels( portable_samplepair_t *dst, int end, int rate )
{ {
const qboolean local = Host_IsLocalGame(); const qboolean local = Host_IsLocalGame();
const qboolean ingame = CL_IsInGame(); const qboolean ingame = CL_IsInGame();
const int num_samples = ( end - paintedtime ) / ( SOUND_DMA_SPEED / rate ); const int num_samples = ( end - snd.paintedtime ) / ( SOUND_DMA_SPEED / rate );
// FWGS feature: make everybody sound like chipmunks when we're going fast // FWGS feature: make everybody sound like chipmunks when we're going fast
const float pitch_mult = ( sys_timescale.value + 1 ) / 2; const float pitch_mult = ( sys_timescale.value + 1 ) / 2;
@@ -248,25 +248,25 @@ static int S_MixNormalChannels( portable_samplepair_t *dst, int end, int rate )
if( cl.background && cls.key_dest == key_console ) if( cl.background && cls.key_dest == key_console )
return num_mixed_channels; // no sounds in console with background map return num_mixed_channels; // no sounds in console with background map
for( int i = 0; i < total_channels; i++ ) for( int i = 0; i < snd.total_channels; i++ )
{ {
channel_t *ch = &channels[i]; channel_t *ch = &snd.channels[i];
if( !ch->sfx ) if( !ch->sfx )
continue; continue;
if( !cl.background ) if( !cl.background )
{ {
if( cls.key_dest == key_console && ch->localsound ) if( cls.key_dest == key_console && FBitSet( ch->flags, FL_CHAN_LOCAL_SOUND ))
{ {
// play, playvol // play, playvol
} }
else if(( cls.key_dest == key_menu || cl.paused ) && !ch->localsound && local ) else if(( cls.key_dest == key_menu || cl.paused ) && !FBitSet( ch->flags, FL_CHAN_LOCAL_SOUND ) && local )
{ {
// play only local sounds, keep pause for other // play only local sounds, keep pause for other
continue; continue;
} }
else if( cls.key_dest != key_menu && !ingame && !ch->staticsound ) else if( cls.key_dest != key_menu && !ingame && !FBitSet( ch->flags, FL_CHAN_STATIC_SOUND ))
{ {
// play only ambient sounds, keep pause for other // play only ambient sounds, keep pause for other
continue; continue;
@@ -285,12 +285,19 @@ static int S_MixNormalChannels( portable_samplepair_t *dst, int end, int rate )
// if it's also not looping, free it // if it's also not looping, free it
if( ch->leftvol < 8 && ch->rightvol < 8 ) if( ch->leftvol < 8 && ch->rightvol < 8 )
{ {
if( !FBitSet( sc->flags, SOUND_LOOPED ) || !ch->use_loop ) if( !FBitSet( sc->flags, SOUND_LOOPED ) || !FBitSet( ch->flags, FL_CHAN_USE_LOOP ))
S_FreeChannel( ch ); {
if( ch->inauduble_free_time == 0.0f )
ch->inauduble_free_time = host.realtime + MAX_CHANNEL_INAUDIBLE_TIME;
else if( ch->inauduble_free_time > host.realtime )
S_FreeChannel( ch );
}
continue; continue;
} }
ch->inauduble_free_time = 0.0f;
if( rate != sc->rate ) if( rate != sc->rate )
continue; continue;
@@ -301,9 +308,9 @@ static int S_MixNormalChannels( portable_samplepair_t *dst, int end, int rate )
if( ent != NULL ) if( ent != NULL )
{ {
if( sc->width == 1 ) if( sc->width == 1 )
SND_MoveMouth8( &ent->mouth, ch->sample, sc, num_samples, ch->use_loop ); SND_MoveMouth8( &ent->mouth, ch->sample, sc, num_samples, FBitSet( ch->flags, FL_CHAN_USE_LOOP ));
else else
SND_MoveMouth16( &ent->mouth, ch->sample, sc, num_samples, ch->use_loop ); SND_MoveMouth16( &ent->mouth, ch->sample, sc, num_samples, FBitSet( ch->flags, FL_CHAN_USE_LOOP ));
} }
} }
@@ -311,18 +318,18 @@ static int S_MixNormalChannels( portable_samplepair_t *dst, int end, int rate )
num_mixed_channels++; num_mixed_channels++;
if( ch->is_sentence ) if( ch->words )
{ {
VOX_MixChannelToBuffer( dst, ch, num_samples, rate, pitch ); VOX_MixChannelToBuffer( dst, ch, num_samples, rate, pitch );
if( ch->sentence_finished ) if( FBitSet( ch->flags, FL_CHAN_SENTENCE_FINISHED ))
S_FreeChannel( ch ); S_FreeChannel( ch );
} }
else else
{ {
S_MixChannelToBuffer( dst, ch, num_samples, rate, pitch, 0, 0 ); S_MixChannelToBuffer( dst, ch, num_samples, rate, pitch, 0, 0 );
if( ch->finished ) if( FBitSet( ch->flags, FL_CHAN_FINISHED ))
S_FreeChannel( ch ); S_FreeChannel( ch );
} }
} }
@@ -368,7 +375,7 @@ static int S_MixNormalChannelsToRoombuffer( int end, int count )
// until there is no real usecase, let's keep it simple // until there is no real usecase, let's keep it simple
int num_mixed_channels = S_MixNormalChannels( roombuffer, end, SOUND_11k ); int num_mixed_channels = S_MixNormalChannels( roombuffer, end, SOUND_11k );
if( dma.format.speed >= SOUND_22k ) if( snd.format.speed >= SOUND_22k )
{ {
if( num_mixed_channels > 0 ) if( num_mixed_channels > 0 )
S_UpsampleBuffer( roombuffer, count / ( SOUND_22k / SOUND_11k )); S_UpsampleBuffer( roombuffer, count / ( SOUND_22k / SOUND_11k ));
@@ -376,7 +383,7 @@ static int S_MixNormalChannelsToRoombuffer( int end, int count )
num_mixed_channels += S_MixNormalChannels( roombuffer, end, SOUND_22k ); num_mixed_channels += S_MixNormalChannels( roombuffer, end, SOUND_22k );
} }
if( dma.format.speed >= SOUND_44k ) if( snd.format.speed >= SOUND_44k )
{ {
if( num_mixed_channels > 0 ) if( num_mixed_channels > 0 )
S_UpsampleBuffer( roombuffer, count / ( SOUND_44k / SOUND_22k )); S_UpsampleBuffer( roombuffer, count / ( SOUND_44k / SOUND_22k ));
@@ -395,10 +402,10 @@ static int S_MixRawChannels( int end )
return 0; return 0;
// paint in the raw channels // paint in the raw channels
for( size_t i = 0; i < ARRAYSIZE( raw_channels ); i++ ) for( size_t i = 0; i < snd.max_raw_channels; i++ )
{ {
// copy from the streaming sound source // copy from the streaming sound source
rawchan_t *ch = raw_channels[i]; rawchan_t *ch = snd.raw_channels[i];
if( !ch ) if( !ch )
continue; continue;
@@ -427,7 +434,7 @@ static int S_MixRawChannels( int end )
uint stop = (end < ch->s_rawend) ? end : ch->s_rawend; uint stop = (end < ch->s_rawend) ? end : ch->s_rawend;
const uint mask = ch->max_samples - 1; const uint mask = ch->max_samples - 1;
for( size_t i = 0, j = paintedtime; j < stop; i++, j++ ) for( size_t i = 0, j = snd.paintedtime; j < stop; i++, j++ )
{ {
pbuf[i].left += ( ch->rawsamples[j & mask].left * ch->leftvol ) >> 8; pbuf[i].left += ( ch->rawsamples[j & mask].left * ch->leftvol ) >> 8;
pbuf[i].right += ( ch->rawsamples[j & mask].right * ch->rightvol ) >> 8; pbuf[i].right += ( ch->rawsamples[j & mask].right * ch->rightvol ) >> 8;
@@ -436,8 +443,8 @@ static int S_MixRawChannels( int end )
if( ch->entnum > 0 ) if( ch->entnum > 0 )
{ {
cl_entity_t *ent = CL_GetEntityByIndex( ch->entnum ); cl_entity_t *ent = CL_GetEntityByIndex( ch->entnum );
int pos = paintedtime & ( ch->max_samples - 1 ); int pos = snd.paintedtime & ( ch->max_samples - 1 );
int count = bound( 0, ch->max_samples - pos, stop - paintedtime ); int count = bound( 0, ch->max_samples - pos, stop - snd.paintedtime );
if( ent ) if( ent )
SND_MoveMouthRaw( &ent->mouth, &ch->rawsamples[pos], count ); SND_MoveMouthRaw( &ent->mouth, &ch->rawsamples[pos], count );
@@ -479,8 +486,8 @@ static void S_WriteLinearBlastStereo16( short *snd_out, const int *snd_p, size_t
static void S_TransferPaintBuffer( const portable_samplepair_t *src, int endtime ) static void S_TransferPaintBuffer( const portable_samplepair_t *src, int endtime )
{ {
const int *snd_p = (const int *)src; const int *snd_p = (const int *)src;
const int sampleMask = ((dma.samples >> 1) - 1); const int sampleMask = ((snd.samples >> 1) - 1);
int lpaintedtime = paintedtime; int lpaintedtime = snd.paintedtime;
SNDDMA_BeginPainting (); SNDDMA_BeginPainting ();
@@ -489,9 +496,9 @@ static void S_TransferPaintBuffer( const portable_samplepair_t *src, int endtime
// handle recirculating buffer issues // handle recirculating buffer issues
int lpos = lpaintedtime & sampleMask; int lpos = lpaintedtime & sampleMask;
short *snd_out = (short *)dma.buffer + (lpos << 1); short *snd_out = (short *)snd.buffer + (lpos << 1);
int snd_linear_count = (dma.samples>>1) - lpos; int snd_linear_count = (snd.samples>>1) - lpos;
if( lpaintedtime + snd_linear_count > endtime ) if( lpaintedtime + snd_linear_count > endtime )
snd_linear_count = endtime - lpaintedtime; snd_linear_count = endtime - lpaintedtime;
@@ -519,14 +526,14 @@ void S_PaintChannels( int endtime )
{ {
int gain = S_GetMasterVolume() * 256; int gain = S_GetMasterVolume() * 256;
while( paintedtime < endtime ) while( snd.paintedtime < endtime )
{ {
// if paintbuffer is smaller than DMA buffer // if paintbuffer is smaller than DMA buffer
int end = endtime; int end = endtime;
if( end - paintedtime > PAINTBUFFER_SIZE ) if( end - snd.paintedtime > PAINTBUFFER_SIZE )
end = paintedtime + PAINTBUFFER_SIZE; end = snd.paintedtime + PAINTBUFFER_SIZE;
const int num_samples = end - paintedtime; const int num_samples = end - snd.paintedtime;
S_ClearBuffers( num_samples ); S_ClearBuffers( num_samples );
@@ -543,6 +550,6 @@ void S_PaintChannels( int endtime )
// transfer out according to DMA format // transfer out according to DMA format
S_TransferPaintBuffer( paintbuffer, end ); S_TransferPaintBuffer( paintbuffer, end );
paintedtime = end; snd.paintedtime = end;
} }
} }
+14 -14
View File
@@ -92,7 +92,7 @@ void S_StartBackgroundTrack( const char *introTrack, const char *mainTrack, int
{ {
S_StopBackgroundTrack(); S_StopBackgroundTrack();
if( !dma.initialized ) return; if( !snd.initialized ) return;
// check for special symbols // check for special symbols
if( introTrack && *introTrack == '*' ) if( introTrack && *introTrack == '*' )
@@ -132,9 +132,9 @@ S_StopBackgroundTrack
*/ */
void S_StopBackgroundTrack( void ) void S_StopBackgroundTrack( void )
{ {
s_listener.stream_paused = false; snd.stream_paused = false;
if( !dma.initialized ) return; if( !snd.initialized ) return;
if( !s_bgTrack.stream ) return; if( !s_bgTrack.stream ) return;
FS_FreeStream( s_bgTrack.stream ); FS_FreeStream( s_bgTrack.stream );
@@ -149,7 +149,7 @@ S_StreamSetPause
*/ */
void S_StreamSetPause( int pause ) void S_StreamSetPause( int pause )
{ {
s_listener.stream_paused = pause; snd.stream_paused = pause;
} }
/* /*
@@ -197,11 +197,11 @@ void S_StreamBackgroundTrack( void )
int r, fileBytes; int r, fileBytes;
rawchan_t *ch = NULL; rawchan_t *ch = NULL;
if( !dma.initialized || !s_bgTrack.stream || s_listener.streaming ) if( !snd.initialized || !s_bgTrack.stream || snd.streaming )
return; return;
// don't bother playing anything if musicvolume is 0 // don't bother playing anything if musicvolume is 0
if( !s_musicvolume.value || cl.paused || s_listener.stream_paused ) if( !s_musicvolume.value || cl.paused || snd.stream_paused )
return; return;
if( !cl.background ) if( !cl.background )
@@ -218,14 +218,14 @@ void S_StreamBackgroundTrack( void )
Assert( ch != NULL ); Assert( ch != NULL );
// see how many samples should be copied into the raw buffer // see how many samples should be copied into the raw buffer
if( ch->s_rawend < soundtime ) if( ch->s_rawend < snd.soundtime )
ch->s_rawend = soundtime; ch->s_rawend = snd.soundtime;
while( ch->s_rawend < soundtime + ch->max_samples ) while( ch->s_rawend < snd.soundtime + ch->max_samples )
{ {
const stream_t *info = s_bgTrack.stream; const stream_t *info = s_bgTrack.stream;
bufferSamples = ch->max_samples - (ch->s_rawend - soundtime); bufferSamples = ch->max_samples - (ch->s_rawend - snd.soundtime);
// decide how much data needs to be read from the file // decide how much data needs to be read from the file
fileSamples = bufferSamples * ((float)info->rate / SOUND_DMA_SPEED ); fileSamples = bufferSamples * ((float)info->rate / SOUND_DMA_SPEED );
@@ -283,9 +283,9 @@ S_StartStreaming
*/ */
void S_StartStreaming( void ) void S_StartStreaming( void )
{ {
if( !dma.initialized ) return; if( !snd.initialized ) return;
// begin streaming movie soundtrack // begin streaming movie soundtrack
s_listener.streaming = true; snd.streaming = true;
} }
/* /*
@@ -295,6 +295,6 @@ S_StopStreaming
*/ */
void S_StopStreaming( void ) void S_StopStreaming( void )
{ {
if( !dma.initialized ) return; if( !snd.initialized ) return;
s_listener.streaming = false; snd.streaming = false;
} }
+38 -25
View File
@@ -140,7 +140,7 @@ static void S_TrimStartEndTimes( channel_t *ch, wavdata_t *wav, int start, int e
void VOX_LoadWord( channel_t *ch ) void VOX_LoadWord( channel_t *ch )
{ {
ch->sentence_finished = true; SetBits( ch->flags, FL_CHAN_SENTENCE_FINISHED );
if( ch->word_index < 0 || ch->word_index >= CVOXWORDMAX ) if( ch->word_index < 0 || ch->word_index >= CVOXWORDMAX )
return; return;
@@ -155,7 +155,7 @@ void VOX_LoadWord( channel_t *ch )
if( !data ) if( !data )
return; return;
ch->sentence_finished = false; ClearBits( ch->flags, FL_CHAN_SENTENCE_FINISHED );
ch->data = data; ch->data = data;
int start = word->start; int start = word->start;
@@ -171,7 +171,7 @@ void VOX_FreeWord( channel_t *ch )
{ {
// TODO: don't set random fields to zero lol, was memset before // TODO: don't set random fields to zero lol, was memset before
ch->sample = ch->forced_end = 0.0; ch->sample = ch->forced_end = 0.0;
ch->finished = false; ClearBits( ch->flags, FL_CHAN_FINISHED );
ch->data = NULL; ch->data = NULL;
if( ch->word_index < 0 || ch->word_index >= CVOXWORDMAX ) if( ch->word_index < 0 || ch->word_index >= CVOXWORDMAX )
@@ -179,7 +179,7 @@ void VOX_FreeWord( channel_t *ch )
voxword_t *word = &ch->words[ch->word_index]; voxword_t *word = &ch->words[ch->word_index];
if( !word->sfx || word->in_cache ) if( !word->sfx || FBitSet( word->flags, FL_VOXWORD_IN_CACHE ))
return; return;
FS_FreeSound( word->sfx->cache ); FS_FreeSound( word->sfx->cache );
@@ -191,7 +191,7 @@ void VOX_SetChanVol( channel_t *ch )
{ {
voxword_t *word; voxword_t *word;
if( !ch->is_sentence || ch->sentence_finished ) if( !ch->words || FBitSet( ch->flags, FL_CHAN_SENTENCE_FINISHED ))
return; return;
word = &ch->words[ch->word_index]; word = &ch->words[ch->word_index];
@@ -207,7 +207,7 @@ float VOX_ModifyPitch( channel_t *ch, float pitch )
{ {
voxword_t *word; voxword_t *word;
if( !ch->is_sentence || ch->sentence_finished ) if( !ch->words || FBitSet( ch->flags, FL_CHAN_SENTENCE_FINISHED ))
return pitch; return pitch;
word = &ch->words[ch->word_index]; word = &ch->words[ch->word_index];
@@ -356,10 +356,7 @@ static void VOX_MakeDefaultWordParams( voxword_t *voxword )
*voxword = (voxword_t) { *voxword = (voxword_t) {
.volume = 100, .volume = 100,
.pitch = 100, .pitch = 100,
.start = 0,
.end = 100, .end = 100,
.timecompress = 0,
.in_cache = false,
}; };
} }
@@ -416,19 +413,24 @@ static qboolean VOX_ParseWordParams( char *psz, voxword_t *pvoxword, voxword_t *
i = Q_atoi( sznum ); i = Q_atoi( sznum );
switch( command ) switch( command )
{ {
case 'e': pvoxword->end = i; break; case 'e':
case 'p': pvoxword->pitch = i; break; pvoxword->end = bound( 0, i, 100 );
case 's': pvoxword->start = i; break; break;
case 't': pvoxword->timecompress = i; break; case 'p':
case 'v': pvoxword->volume = i; break; pvoxword->pitch = bound( 0, i, UINT16_MAX );
break;
case 's':
pvoxword->start = bound( 0, i, 100 );
break;
case 't':
pvoxword->timecompress = bound( 0, i, 100 );
break;
case 'v':
pvoxword->volume = bound( 0, i, UINT16_MAX );
break;
} }
} }
// validate some of the parameters
pvoxword->start = bound( 0, pvoxword->start, 100 );
pvoxword->end = bound( 0, pvoxword->end, 100 );
pvoxword->timecompress = bound( 0, pvoxword->timecompress, 100 );
// no actual word but new defaults // no actual word but new defaults
if( Q_strlen( pszsave ) == 0 ) if( Q_strlen( pszsave ) == 0 )
{ {
@@ -447,10 +449,18 @@ void VOX_LoadSound( channel_t *ch, const char *pszin )
int i, j; int i, j;
int num_words; int num_words;
voxword_t default_voxword; voxword_t default_voxword;
voxword_t words_buf[CVOXWORDMAX + 1]; // local scratch: parsed words + null terminator
if( !pszin ) if( !pszin )
return; return;
// free any existing words from a previous sentence on this channel
if( ch->words )
{
VOX_FreeWord( ch );
Mem_Free2( &ch->words );
}
psz = VOX_LookupString( pszin ); psz = VOX_LookupString( pszin );
if( !psz ) if( !psz )
@@ -478,12 +488,13 @@ void VOX_LoadSound( channel_t *ch, const char *pszin )
num_words = VOX_ParseString( buffer, rgpparseword ); num_words = VOX_ParseString( buffer, rgpparseword );
VOX_MakeDefaultWordParams( &default_voxword ); VOX_MakeDefaultWordParams( &default_voxword );
memset( words_buf, 0, sizeof( words_buf ));
for( i = 0, j = 0; i < num_words; i++ ) for( i = 0, j = 0; i < num_words; i++ )
{ {
char pathbuffer[MAX_SYSPATH]; char pathbuffer[MAX_SYSPATH];
if( !VOX_ParseWordParams( rgpparseword[i], &ch->words[j], &default_voxword )) if( !VOX_ParseWordParams( rgpparseword[i], &words_buf[j], &default_voxword ))
continue; continue;
if( Q_snprintf( pathbuffer, sizeof( pathbuffer ), "%s%s", szpath, rgpparseword[i] ) < 0 ) if( Q_snprintf( pathbuffer, sizeof( pathbuffer ), "%s%s", szpath, rgpparseword[i] ) < 0 )
@@ -493,17 +504,19 @@ void VOX_LoadSound( channel_t *ch, const char *pszin )
} }
qboolean in_cache = false; qboolean in_cache = false;
ch->words[j].sfx = S_FindName( pathbuffer, &in_cache ); words_buf[j].sfx = S_FindName( pathbuffer, &in_cache );
ch->words[j].in_cache = in_cache; if( in_cache )
SetBits( words_buf[j].flags, FL_VOXWORD_IN_CACHE );
j++; j++;
} }
ch->words[j].sfx = NULL; // words_buf[j].sfx is already NULL from the memset — null terminator
ch->words = Mem_Malloc( sndpool, ( j + 1 ) * sizeof( voxword_t ));
memcpy( ch->words, words_buf, ( j + 1 ) * sizeof( voxword_t ));
ch->sfx = ch->words[0].sfx; ch->sfx = ch->words[0].sfx;
ch->word_index = 0; ch->word_index = 0;
ch->is_sentence = true;
VOX_LoadWord( ch ); VOX_LoadWord( ch );
} }
+3 -109
View File
@@ -19,6 +19,7 @@ GNU General Public License for more details.
extern poolhandle_t sndpool; extern poolhandle_t sndpool;
#include "xash3d_mathlib.h" #include "xash3d_mathlib.h"
#include "sound_api.h"
// sound engine rate defines // sound engine rate defines
#define SOUND_11k 11025 // 11khz sample rate #define SOUND_11k 11025 // 11khz sample rate
@@ -38,105 +39,6 @@ extern poolhandle_t sndpool;
#define CLIP16( x ) bound( SHRT_MIN + 8, x, SHRT_MAX - 8 ) #define CLIP16( x ) bound( SHRT_MIN + 8, x, SHRT_MAX - 8 )
typedef struct
{
int left;
int right;
} portable_samplepair_t;
typedef struct sfx_s
{
char name[MAX_QPATH];
wavdata_t *cache;
int servercount;
uint hashValue;
struct sfx_s *hashNext;
} sfx_t;
typedef struct voxword_s
{
sfx_t *sfx;
uint16_t volume; // volume percent
uint16_t pitch; // pitch shift percent (keep large for extra chipmunk fun)
uint16_t timecompress; // percent of skipped data (speeds up playback without pitch shift)
uint16_t start : 7; // percent at which playback starts
uint16_t end : 7; // percent at which playback ends
uint16_t in_cache : 1; // if set to 1, it was loaded prior and shouldn't be freed
} voxword_t;
typedef struct snd_format_s
{
uint speed;
byte width;
byte channels;
} snd_format_t;
typedef struct
{
snd_format_t format;
int samples; // mono samples in buffer
int samplepos; // in mono samples
qboolean initialized; // sound engine is active
byte *buffer;
const char *backendName;
} dma_t;
typedef struct rawchan_s
{
int entnum;
int master_vol;
int leftvol; // 0-255 left volume
int rightvol; // 0-255 right volume
float dist_mult; // distance multiplier (attenuation/clipK)
vec3_t origin; // only use if fixed_origin is set
volatile uint s_rawend;
float oldtime; // catch time jumps
size_t max_samples; // buffer length
portable_samplepair_t rawsamples[]; // variable sized
} rawchan_t;
typedef struct channel_s
{
char name[16]; // keep sentence name
sfx_t *sfx; // sfx number
int leftvol; // 0-255 left volume
int rightvol; // 0-255 right volume
int entnum; // entity soundsource
int entchannel; // sound channel (CHAN_STREAM, CHAN_VOICE, etc.)
vec3_t origin; // only use if fixed_origin is set
float dist_mult; // distance multiplier (attenuation/clipK)
int master_vol; // 0-255 master volume
byte use_loop : 1; // don't loop default and local sounds
byte staticsound : 1; // use origin instead of fetching entnum's origin
byte localsound : 1; // it's a local menu sound (not looped, not paused)
byte is_sentence : 1; // bit indicating vox sentence
byte sentence_finished : 1; // if set, finished playing sentence
byte finished : 1; // if set, finished playing single word
byte word_index;
short basePitch; // base pitch percent (100% is normal pitch playback)
voxword_t words[CVOXWORDMAX];
double sample;
double forced_end;
wavdata_t *data;
} channel_t;
typedef struct
{
vec3_t origin; // simorg + view_ofs
vec3_t forward;
vec3_t right;
vec3_t up;
int entnum;
qboolean streaming; // playing AVI-file
qboolean stream_paused; // pause only background track
} listener_t;
typedef int sound_t;
//==================================================================== //====================================================================
#define MAX_DYNAMIC_CHANNELS (60 + NUM_AMBIENTS) #define MAX_DYNAMIC_CHANNELS (60 + NUM_AMBIENTS)
@@ -145,16 +47,8 @@ typedef int sound_t;
#define MAX_RAW_SAMPLES 16384 #define MAX_RAW_SAMPLES 16384
#define SND_CLIP_DISTANCE 1000.0f #define SND_CLIP_DISTANCE 1000.0f
extern sound_t ambient_sfx[NUM_AMBIENTS]; extern int idsp_room;
extern qboolean snd_ambient; extern snd_globals_t snd;
extern channel_t channels[MAX_CHANNELS];
extern rawchan_t *raw_channels[MAX_RAW_CHANNELS];
extern int total_channels;
extern int paintedtime;
extern int soundtime;
extern listener_t s_listener;
extern int idsp_room;
extern dma_t dma;
extern convar_t s_musicvolume; extern convar_t s_musicvolume;
extern convar_t s_lerping; extern convar_t s_lerping;
+5 -5
View File
@@ -51,12 +51,12 @@ GetLittleLong
*/ */
static int GetLittleLong( void ) static int GetLittleLong( void )
{ {
int val = 0; uint val = 0;
val += (*(iff_dataPtr+0) << 0); val += ((uint)*(iff_dataPtr+0) << 0);
val += (*(iff_dataPtr+1) << 8); val += ((uint)*(iff_dataPtr+1) << 8);
val += (*(iff_dataPtr+2) <<16); val += ((uint)*(iff_dataPtr+2) <<16);
val += (*(iff_dataPtr+3) <<24); val += ((uint)*(iff_dataPtr+3) <<24);
iff_dataPtr += 4; iff_dataPtr += 4;
return val; return val;
+114 -47
View File
@@ -28,7 +28,7 @@ typedef struct
int cursize; int cursize;
} cmdbuf_t; } cmdbuf_t;
static qboolean cmd_wait; static int cmd_wait;
static cmdbuf_t cmd_text; static cmdbuf_t cmd_text;
static cmdbuf_t filteredcmd_text; static cmdbuf_t filteredcmd_text;
static cmdalias_t *cmd_alias; static cmdalias_t *cmd_alias;
@@ -56,6 +56,7 @@ void Cbuf_Clear( void )
{ {
memset( &cmd_text, 0, sizeof( cmd_text )); memset( &cmd_text, 0, sizeof( cmd_text ));
memset( &filteredcmd_text, 0, sizeof( filteredcmd_text )); memset( &filteredcmd_text, 0, sizeof( filteredcmd_text ));
cmd_wait = 0;
} }
/* /*
@@ -174,6 +175,12 @@ static void Cbuf_ExecuteCommandsFromBuffer( cmdbuf_t *buf, qboolean isPrivileged
while( buf->cursize ) while( buf->cursize )
{ {
if( cmd_wait > 0 )
{
cmd_wait--;
break;
}
// limit amount of commands that can be issued // limit amount of commands that can be issued
if( cmdsToExecute >= 0 ) if( cmdsToExecute >= 0 )
{ {
@@ -238,14 +245,6 @@ static void Cbuf_ExecuteCommandsFromBuffer( cmdbuf_t *buf, qboolean isPrivileged
// execute the command line // execute the command line
Cmd_ExecuteStringWithPrivilegeCheck( line, isPrivileged ); Cmd_ExecuteStringWithPrivilegeCheck( line, isPrivileged );
if( cmd_wait )
{
// skip out while text still remains in buffer,
// leaving it for next frame
cmd_wait = false;
break;
}
} }
} }
@@ -367,7 +366,13 @@ bind g "cmd use rocket ; +attack ; wait ; -attack ; cmd use blaster"
*/ */
static void Cmd_Wait_f( void ) static void Cmd_Wait_f( void )
{ {
cmd_wait = true; int frame = 1;
if( Cmd_Argc() > 1 )
{
frame = Q_atoi( Cmd_Argv( 1 ) );
frame = Q_max( 1, frame );
}
cmd_wait = frame;
} }
/* /*
@@ -1234,26 +1239,60 @@ static void Cmd_MakePrivileged_f( void )
/* /*
=============== ===============
Cmd_Exec_f Cmd_ExecScript
=============== ===============
*/ */
static void Cmd_Exec_f( void ) static void Cmd_ExecScript( const char *filename )
{ {
string cfgpath;
byte *f; byte *f;
fs_offset_t len; fs_offset_t len;
if( Cmd_Argc() != 2 ) f = FS_LoadFile( filename, &len, false );
if( !f )
{ {
Con_Printf( S_USAGE "exec <filename>\n" ); Con_Reportf( "couldn't exec %s\n", filename );
return; return;
} }
Q_strncpy( cfgpath, Cmd_Argv( 1 ), sizeof( cfgpath )); // len is fs_offset_t, which can be larger than size_t
COM_DefaultExtension( cfgpath, ".cfg", sizeof( cfgpath )); // append as default if( len >= SIZE_MAX )
{
Con_Reportf( "%s: %s is too long\n", __func__, filename );
Mem_Free( f );
return;
}
#ifndef XASH_DEDICATED if( f[len - 1] != '\n' )
if( !Cmd_CurrentCommandIsPrivileged() && !Q_stricmp( GI->gamefolder, "tfc" )) {
Cbuf_InsertTextLen( f, len, len + 1 );
Cbuf_InsertTextLen( "\n", 1, 1 );
}
else Cbuf_InsertTextLen( f, len, len );
Mem_Free( f );
}
/*
===============
Cmd_UnprivilegedExec_f
===============
*/
static void Cmd_UnprivilegedExec_f( void )
{
string cfgpath;
qboolean allow = false;
if( Cmd_Argc() != 2 )
return;
Q_strncpy( cfgpath, Cmd_Argv( 1 ), sizeof( cfgpath ));
COM_DefaultExtension( cfgpath, ".cfg", sizeof( cfgpath ));
if( SV_GetMaxClients() == 1 )
allow = true;
#if !XASH_DEDICATED
if( !allow && !Q_stricmp( GI->gamefolder, "tfc" ))
{ {
const char *const unprivileged_whitelist[] = const char *const unprivileged_whitelist[] =
{ {
@@ -1278,48 +1317,75 @@ static void Cmd_Exec_f( void )
break; break;
} }
} }
}
#endif
if( !allow ) if( allow )
Cmd_ExecScript( cfgpath );
else
Con_Printf( "exec %s: not privileged or in whitelist\n", cfgpath );
}
/*
===============
Cmd_Exec_f
===============
*/
static void Cmd_Exec_f( void )
{
string cfgpath;
// early exit for stuffcmd
if( !Cmd_CurrentCommandIsPrivileged())
{
Cmd_UnprivilegedExec_f();
return;
}
if( Cmd_Argc() != 2 )
{
Con_Printf( S_USAGE "exec <PATTERN>\n"
"PATTERN single file or wildcard pattern to match\n"
"Wildcards: * matches any characters, ? matches single character\n"
"Example: file.cfg - single file.cfg\n"
"\tdirectory/* - all .cfg files in directory\n"
"\tdirectory/???.cfg - all .cfg files in directory with 3 character names\n" );
return;
}
Q_strncpy( cfgpath, Cmd_Argv( 1 ), sizeof( cfgpath ));
COM_DefaultExtension( cfgpath, ".cfg", sizeof( cfgpath ));
if( Q_strpbrk( cfgpath, "*?" ))
{
search_t *search = FS_Search( cfgpath, true, false );
if( !search || !search->numfilenames )
{ {
Con_Printf( "exec %s: not privileged or in whitelist\n", cfgpath ); Con_Printf( "couldn't exec %s\n", Cmd_Argv( 1 ));
if( search ) Mem_Free( search );
return; return;
} }
Con_Printf( "execing %d file%s from " S_GREEN "%s" S_DEFAULT "\n",
search->numfilenames, search->numfilenames > 1 ? "s" : "", Cmd_Argv( 1 ));
for( int i = 0; i < search->numfilenames; i++ )
Cmd_ExecScript( search->filenames[i] );
Mem_Free( search );
return;
} }
#endif // XASH_DEDICATED
// don't execute game.cfg in singleplayer // don't execute game.cfg in singleplayer
if( SV_GetMaxClients() == 1 && !Q_stricmp( "game.cfg", cfgpath )) if( SV_GetMaxClients() == 1 && !Q_stricmp( "game.cfg", cfgpath ))
return; return;
f = FS_LoadFile( cfgpath, &len, false );
if( !f )
{
Con_Reportf( "couldn't exec %s\n", Cmd_Argv( 1 ));
return;
}
// len is fs_offset_t, which can be larger than size_t
if( len >= SIZE_MAX )
{
Con_Reportf( "%s: %s is too long\n", __func__, Cmd_Argv( 1 ));
return;
}
if( !Q_stricmp( "config.cfg", cfgpath )) if( !Q_stricmp( "config.cfg", cfgpath ))
host.config_executed = true; host.config_executed = true;
Con_Printf( "execing " S_GREEN "%s" S_DEFAULT "\n", Cmd_Argv( 1 )); Con_Printf( "execing " S_GREEN "%s" S_DEFAULT "\n", Cmd_Argv( 1 ));
// adds \n at end of the file Cmd_ExecScript( cfgpath );
// FS_LoadFile always null terminates
if( f[len - 1] != '\n' )
{
Cbuf_InsertTextLen( f, len, len + 1 );
Cbuf_InsertTextLen( "\n", 1, 1 );
}
else Cbuf_InsertTextLen( f, len, len );
Mem_Free( f );
} }
/* /*
@@ -1388,13 +1454,14 @@ void Cmd_Init( void )
cmd_pool = Mem_AllocPool( "Console Commands" ); cmd_pool = Mem_AllocPool( "Console Commands" );
cmd_functions = NULL; cmd_functions = NULL;
cmd_condition = 0; cmd_condition = 0;
cmd_wait = 0;
cmd_alias = NULL; cmd_alias = NULL;
cmd_args = NULL; cmd_args = NULL;
cmd_argc = 0; cmd_argc = 0;
// register our commands // register our commands
Cmd_AddCommand( "echo", Cmd_Echo_f, "print a message to the console (useful in scripts)" ); Cmd_AddCommand( "echo", Cmd_Echo_f, "print a message to the console (useful in scripts)" );
Cmd_AddCommand( "wait", Cmd_Wait_f, "make script execution wait for some rendered frames" ); Cmd_AddRestrictedCommand( "wait", Cmd_Wait_f, "make script execution wait for some rendered frames" );
Cmd_AddRestrictedCommand( "cmdlist", Cmd_List_f, "display all console commands beginning with the specified prefix" ); Cmd_AddRestrictedCommand( "cmdlist", Cmd_List_f, "display all console commands beginning with the specified prefix" );
Cmd_AddRestrictedCommand( "stuffcmds", Cmd_StuffCmds_f, "execute commandline parameters (must be present in .rc script)" ); Cmd_AddRestrictedCommand( "stuffcmds", Cmd_StuffCmds_f, "execute commandline parameters (must be present in .rc script)" );
Cmd_AddRestrictedCommand( "apropos", Cmd_Apropos_f, "lists all console variables/commands/aliases containing the specified string in the name or description" ); Cmd_AddRestrictedCommand( "apropos", Cmd_Apropos_f, "lists all console variables/commands/aliases containing the specified string in the name or description" );
+1 -1
View File
@@ -961,7 +961,7 @@ static void Test_LZSS( void )
}; };
const char decompressed[] = "Do you like what you see?"; const char decompressed[] = "Do you like what you see?";
#ifdef USING_ASAN #ifdef USE_ASAN
ASAN_POISON_MEMORY_REGION( poison1, sizeof( poison1 )); ASAN_POISON_MEMORY_REGION( poison1, sizeof( poison1 ));
ASAN_POISON_MEMORY_REGION( poison2, sizeof( poison2 )); ASAN_POISON_MEMORY_REGION( poison2, sizeof( poison2 ));
ASAN_POISON_MEMORY_REGION( poison3, sizeof( poison3 )); ASAN_POISON_MEMORY_REGION( poison3, sizeof( poison3 ));
+51 -53
View File
@@ -16,42 +16,48 @@ GNU General Public License for more details.
#ifndef COMMON_H #ifndef COMMON_H
#define COMMON_H #define COMMON_H
#ifdef __cplusplus
extern "C" {
#endif
/*
===================================================================================================================================
Legend:
INTERNAL RESOURCE - function contain hardcoded path to resource that engine required (optional in most cases)
OBSOLETE, UNUSED - this function no longer used and leaved here for keep binary compatibility
TODO - some functionality not impemented but planned
FIXME - code doesn't working properly in some rare cases
HACKHACK - unexpected behavior on some input params (or something like)
BUGBUG - code doesn't working properly in most cases!
TESTTEST - this code may be unstable and needs to be more tested
g-cont: - notes from engine author
XASH SPECIFIC - sort of hack that works only in Xash3D not in GoldSrc
===================================================================================================================================
*/
#include "port.h"
#include "backends.h"
#include "defaults.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> // rand, adbs #include <stdlib.h> // rand, adbs
#include <stdarg.h> // va #include <stdarg.h> // va
#include "build.h"
#if !XASH_WIN32 #if !XASH_WIN32
#include <stddef.h> // size_t #include <stddef.h> // size_t
#else #else
#include <sys/types.h> // off_t #include <sys/types.h> // off_t
#endif #endif
#include "port.h"
#include "backends.h"
#include "defaults.h"
#include "library_suffix.h" #include "library_suffix.h"
#include "enginefeatures.h"
#include "system.h"
#include "com_model.h"
#include "com_strings.h"
#include "crtlib.h"
#include "cvar.h"
#include "con_nprint.h"
#include "crclib.h"
#include "ref_api.h"
#include "com_image.h"
/*
===================================================================================================================================
Legend:
INTERNAL RESOURCE - function contain hardcoded path to resource that engine required (optional in most cases)
OBSOLETE, UNUSED - this function no longer used and leaved here for keep binary compatibility
TODO - some functionality not impemented but planned
FIXME - code doesn't working properly in some rare cases
HACKHACK - unexpected behavior on some input params (or something like)
BUGBUG - code doesn't working properly in most cases!
TESTTEST - this code may be unstable and needs to be more tested
g-cont: - notes from engine author
XASH SPECIFIC - sort of hack that works only in Xash3D not in GoldSrc
===================================================================================================================================
*/
// configuration // configuration
@@ -60,21 +66,19 @@ XASH SPECIFIC - sort of hack that works only in Xash3D not in GoldSrc
// //
#if XASH_TIMER == TIMER_NULL #if XASH_TIMER == TIMER_NULL
#error "Please select timer backend" #error "Please select timer backend"
#endif #endif // XASH_TIMER == TIMER_NULL
#if !XASH_DEDICATED #if !XASH_DEDICATED
#if XASH_VIDEO == VIDEO_NULL #if XASH_VIDEO == VIDEO_NULL
#error "Please select video backend" #error "Please select video backend"
#endif #endif // XASH_VIDEO == VIDEO_NULL
#endif #endif // !XASH_DEDICATED
#ifndef XASH_SDL #ifndef XASH_SDL
#if XASH_TIMER == TIMER_SDL || XASH_VIDEO == VIDEO_SDL || XASH_SOUND == SOUND_SDL || XASH_INPUT == INPUT_SDL
#if XASH_TIMER == TIMER_SDL || XASH_VIDEO == VIDEO_SDL || XASH_SOUND == SOUND_SDL || XASH_INPUT == INPUT_SDL #error "SDL backends without XASH_SDL not allowed"
#error "SDL backends without XASH_SDL not allowed" #endif // XASH_TIMER == TIMER_SDL || XASH_VIDEO == VIDEO_SDL || XASH_SOUND == SOUND_SDL || XASH_INPUT == INPUT_SDL
#endif #endif // XASH_SDL
#endif
#define HACKS_RELATED_HLMODS // some HL-mods works differently under Xash and can't be fixed without some hacks at least at current time #define HACKS_RELATED_HLMODS // some HL-mods works differently under Xash and can't be fixed without some hacks at least at current time
@@ -97,19 +101,6 @@ typedef enum instance_e
#define Host_IsDedicated() ( host.type == HOST_DEDICATED ) #define Host_IsDedicated() ( host.type == HOST_DEDICATED )
#endif #endif
#include "system.h"
#include "com_model.h"
#include "com_strings.h"
#include "crtlib.h"
#define FSCALLBACK_OVERRIDE_OPEN
#define FSCALLBACK_OVERRIDE_LOADFILE
#define FSCALLBACK_OVERRIDE_MALLOC_LIKE
#include "fscallback.h"
#include "cvar.h"
#include "con_nprint.h"
#include "crclib.h"
#include "ref_api.h"
// PERFORMANCE INFO // PERFORMANCE INFO
#define MIN_FPS 20.0f // host minimum fps value for maxfps. #define MIN_FPS 20.0f // host minimum fps value for maxfps.
#define MAX_FPS_SOFT 200.0f // soft limit for maxfps. #define MAX_FPS_SOFT 200.0f // soft limit for maxfps.
@@ -351,6 +342,9 @@ typedef struct host_parm_s
string gamedll; string gamedll;
string clientlib; string clientlib;
string menulib; string menulib;
// default game directory, passed to us from game launcher
string default_gamedir;
} host_parm_t; } host_parm_t;
extern host_parm_t host; extern host_parm_t host;
@@ -387,6 +381,10 @@ void Mem_Stats_f( void );
#define Mem_Calloc( pool, size ) _Mem_Alloc( pool, size, true, __FILE__, __LINE__ ) #define Mem_Calloc( pool, size ) _Mem_Alloc( pool, size, true, __FILE__, __LINE__ )
#define Mem_Realloc( pool, ptr, size ) _Mem_Realloc( pool, ptr, size, true, __FILE__, __LINE__ ) #define Mem_Realloc( pool, ptr, size ) _Mem_Realloc( pool, ptr, size, true, __FILE__, __LINE__ )
#define Mem_Free( mem ) _Mem_Free( mem, __FILE__, __LINE__ ) #define Mem_Free( mem ) _Mem_Free( mem, __FILE__, __LINE__ )
#define Mem_Free2( ptr ) { \
_Mem_Free( *ptr, __FILE__, __LINE__ ); \
*ptr = NULL; }
#define Mem_AllocPool( name ) _Mem_AllocPool( name, __FILE__, __LINE__ ) #define Mem_AllocPool( name ) _Mem_AllocPool( name, __FILE__, __LINE__ )
#define Mem_FreePool( pool ) _Mem_FreePool( pool, __FILE__, __LINE__ ) #define Mem_FreePool( pool ) _Mem_FreePool( pool, __FILE__, __LINE__ )
#define Mem_EmptyPool( pool ) _Mem_EmptyPool( pool, __FILE__, __LINE__ ) #define Mem_EmptyPool( pool ) _Mem_EmptyPool( pool, __FILE__, __LINE__ )
@@ -396,7 +394,7 @@ void Mem_Stats_f( void );
// //
// filesystem_engine.c // filesystem_engine.c
// //
void FS_Init( const char *basedir ); void FS_Init( void );
void FS_Shutdown( void ); void FS_Shutdown( void );
void *FS_GetNativeObject( const char *obj ); void *FS_GetNativeObject( const char *obj );
int FS_Close( file_t *file ); int FS_Close( file_t *file );
@@ -480,7 +478,6 @@ void Cmd_Escape( char *newCommand, const char *oldCommand, int len );
// //
// imagelib // imagelib
// //
#include "com_image.h"
void Image_Setup( void ); void Image_Setup( void );
void Image_Init( void ); void Image_Init( void );
@@ -564,7 +561,11 @@ qboolean Sound_SupportedFileFormat( const char *fileext );
// //
typedef void( *pfnChangeGame )( const char *progname ); typedef void( *pfnChangeGame )( const char *progname );
qboolean Host_IsQuakeCompatible( void ); static inline qboolean Host_IsQuakeCompatible( void )
{
return FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ) ? true : false;
}
void Host_ShutdownWithReason( const char *reason ); void Host_ShutdownWithReason( const char *reason );
int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGame, pfnChangeGame func ); int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGame, pfnChangeGame func );
void Host_EndGame( qboolean abort, const char *message, ... ) FORMAT_CHECK( 2 ); void Host_EndGame( qboolean abort, const char *message, ... ) FORMAT_CHECK( 2 );
@@ -934,7 +935,4 @@ void SoundList_Shutdown( void );
#error "common.h in ref_dll" #error "common.h in ref_dll"
#endif #endif
#ifdef __cplusplus
}
#endif
#endif//COMMON_H #endif//COMMON_H
+3
View File
@@ -1199,6 +1199,9 @@ void Con_CompleteCommand( field_t *field, qboolean print_suggestions )
// setup the completion field // setup the completion field
con.completionField = field; con.completionField = field;
if( COM_StringEmpty( con.completionField->buffer ))
return;
// only look at the first token for completion purposes // only look at the first token for completion purposes
Cmd_TokenizeString( con.completionField->buffer ); Cmd_TokenizeString( con.completionField->buffer );
+3 -3
View File
@@ -328,7 +328,7 @@ static qboolean FS_DetermineReadOnlyRootDirectory( char *out, size_t size )
FS_Init FS_Init
================ ================
*/ */
void FS_Init( const char *basedir ) void FS_Init( void )
{ {
string gamedir; string gamedir;
char rodir[MAX_OSPATH], rootdir[MAX_OSPATH]; char rodir[MAX_OSPATH], rootdir[MAX_OSPATH];
@@ -352,7 +352,7 @@ void FS_Init( const char *basedir )
if( env ) if( env )
Q_strncpy( gamedir, env, sizeof( gamedir )); Q_strncpy( gamedir, env, sizeof( gamedir ));
else else
Q_strncpy( gamedir, basedir, sizeof( gamedir )); // gamedir == basedir Q_strncpy( gamedir, host.default_gamedir, sizeof( gamedir )); // gamedir == basedir
} }
FS_LoadProgs(); FS_LoadProgs();
@@ -364,7 +364,7 @@ void FS_Init( const char *basedir )
// and this better be reworked at some point // and this better be reworked at some point
g_fsapi.SetCurrentDirectory( rootdir ); g_fsapi.SetCurrentDirectory( rootdir );
if( !g_fsapi.InitStdio( true, rootdir, basedir, gamedir, rodir )) if( !g_fsapi.InitStdio( true, rootdir, host.default_gamedir, gamedir, rodir ))
{ {
Sys_Error( "Can't init filesystem_stdio!\n" ); Sys_Error( "Can't init filesystem_stdio!\n" );
return; return;
+118 -23
View File
@@ -36,6 +36,8 @@ GNU General Public License for more details.
#include "enginefeatures.h" #include "enginefeatures.h"
#include "render_api.h" // decallist_t #include "render_api.h" // decallist_t
#include "tests.h" #include "tests.h"
#include "library.h"
#include "platform/platform.h"
host_parm_t host; // host parms host_parm_t host; // host parms
static jmp_buf return_from_main_buf; static jmp_buf return_from_main_buf;
@@ -296,27 +298,6 @@ void Host_ValidateEngineFeatures( uint32_t mask, uint32_t features )
host.features = features; host.features = features;
} }
/*
==============
Host_IsQuakeCompatible
==============
*/
qboolean Host_IsQuakeCompatible( void )
{
// feature set
if( FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
return true;
#if !XASH_DEDICATED
// quake demo playing
if( cls.demoplayback == DEMO_QUAKE1 )
return true;
#endif // XASH_DEDICATED
return false;
}
/* /*
================ ================
Host_EndGame Host_EndGame
@@ -882,6 +863,118 @@ static void Host_DetermineExecutableName( char *out, size_t size )
#endif #endif
} }
static qboolean Host_CollectX86Libraries( ECommonLibraryType lib_type,
const char *win_path, const char *lin_path, const char *osx_path,
char *found, size_t found_size )
{
string native_path;
qboolean has_any = false;
found[0] = 0;
COM_GetCommonLibraryPath( lib_type, native_path, sizeof( native_path ));
if( Platform_LibraryExists( native_path, true ))
return 0;
#if !( XASH_WIN32 && XASH_X86 )
if( !COM_StringEmpty( win_path ) && FS_FileExists( win_path, true ))
{
Q_strncat( found, "Windows (x86)", found_size );
has_any = true;
}
#endif
#if !( XASH_LINUX && !XASH_ANDROID && XASH_X86 )
if( !COM_StringEmpty( lin_path ) && FS_FileExists( lin_path, true ))
{
if( has_any )
Q_strncat( found, ", ", found_size );
Q_strncat( found, "GNU/Linux (x86)", found_size );
has_any = true;
}
#endif
#if !( XASH_APPLE && XASH_X86 )
if( !COM_StringEmpty( osx_path ) && FS_FileExists( osx_path, true ))
{
if( has_any )
Q_strncat( found, ", ", found_size );
Q_strncat( found, "macOS (x86)", found_size );
has_any = true;
}
#endif
return has_any;
}
static void Host_CheckGameLibraries( void )
{
// on Android, game libraries are loaded from APKs and are invisible to FS_FileExists,
// so the check cannot work there; iOS is handled via Platform_LibraryExists -> IOS_LibraryExists
#if !defined( XASH_INTERNAL_GAMELIBS ) && !XASH_ANDROID
struct
{
const char *name;
ECommonLibraryType type;
const char *override; // host.gamedll / host.clientlib / host.menulib
} libs[3] = {
{ "client", LIBRARY_CLIENT, host.clientlib },
{ "server", LIBRARY_SERVER, host.gamedll },
{ "menu", LIBRARY_GAMEUI, host.menulib },
};
char details[MAX_VA_STRING];
details[0] = 0;
for( int i = 0; i < ARRAYSIZE( libs ); i++ )
{
string found;
qboolean ret;
// if the user explicitly set a library path, trust them and skip the check
if( !COM_StringEmpty( libs[i].override ))
continue;
if( libs[i].type == LIBRARY_SERVER )
{
// missing server library is only critical when singleplayer is available
// mirrors silent mode in SV_InitGame
if( GI->gamemode != GAME_SINGLEPLAYER_ONLY )
continue;
ret = Host_CollectX86Libraries( libs[i].type,
GI->game_dll, GI->game_dll_linux, GI->game_dll_osx,
found, sizeof( found ));
}
else
{
string win, lin, osx;
Q_snprintf( win, sizeof( win ), "%s/%s.dll", GI->dll_path, libs[i].name );
Q_snprintf( lin, sizeof( lin ), "%s/%s.so", GI->dll_path, libs[i].name );
Q_snprintf( osx, sizeof( osx ), "%s/%s.dylib", GI->dll_path, libs[i].name );
ret = Host_CollectX86Libraries( libs[i].type,
win, lin, osx, found, sizeof( found ));
}
if( ret )
{
size_t len = Q_strlen( details );
Q_snprintf( details + len, sizeof( details ) - len, "- %s: %s\n", libs[i].name, found );
}
}
if( COM_StringEmpty( details ))
return;
Sys_Warn( "No native game libraries found for current platform (%s-%s),\n"
"but found libraries for other platforms:\n"
"%s"
"The game may fail to load or work incorrectly.\n"
"Consider using a mod version built for this platform.",
Q_buildos(), Q_buildarch(), details );
#endif // XASH_INTERNAL_GAMELIBS
}
/* /*
================= =================
Host_InitCommon Host_InitCommon
@@ -913,6 +1006,7 @@ static void Host_InitCommon( int argc, char **argv, const char *progname, qboole
host.config_executed = false; host.config_executed = false;
host.status = HOST_INIT; // initialzation started host.status = HOST_INIT; // initialzation started
host.type = HOST_DEDICATED; // predict state host.type = HOST_DEDICATED; // predict state
Q_strncpy( host.default_gamedir, basedir, sizeof( host.default_gamedir ));
#ifndef XASH_DEDICATED #ifndef XASH_DEDICATED
if( !Sys_CheckParm( "-dedicated" )) if( !Sys_CheckParm( "-dedicated" ))
@@ -985,8 +1079,8 @@ static void Host_InitCommon( int argc, char **argv, const char *progname, qboole
#if XASH_DEDICATED #if XASH_DEDICATED
Platform_SetupSigtermHandling(); Platform_SetupSigtermHandling();
#endif #endif
Platform_Init( Host_IsDedicated( ) || developer >= DEV_EXTENDED, basedir ); Platform_Init( Host_IsDedicated( ) || developer >= DEV_EXTENDED );
FS_Init( basedir ); FS_Init();
// print current developer level to simplify processing users feedback // print current developer level to simplify processing users feedback
if( developer > 0 ) if( developer > 0 )
@@ -1018,6 +1112,7 @@ static void Host_InitCommon( int argc, char **argv, const char *progname, qboole
#endif #endif
FS_LoadGameInfo(); FS_LoadGameInfo();
Host_CheckGameLibraries();
Cvar_PostFSInit(); Cvar_PostFSInit();
Image_CheckPaletteQ1 (); Image_CheckPaletteQ1 ();
+12 -5
View File
@@ -2587,7 +2587,7 @@ static void Mod_InitSkyClouds( model_t *mod, const mip_t *mt, texture_t *tx, qbo
r_temp.palette = NULL; r_temp.palette = NULL;
// load it in // load it in
solidskyTexture = GL_LoadTextureInternal( "solid_sky", &r_temp, TF_NOMIPMAP ); solidskyTexture = GL_LoadTextureInternal( "solid_sky", &r_temp, TF_NOMIPMAP | TF_ALLOW_NEAREST );
for( i = 0; i < r_sky->width >> 1; i++ ) for( i = 0; i < r_sky->width >> 1; i++ )
{ {
@@ -2610,7 +2610,7 @@ static void Mod_InitSkyClouds( model_t *mod, const mip_t *mt, texture_t *tx, qbo
r_temp.flags = IMAGE_HAS_COLOR|IMAGE_HAS_ALPHA; r_temp.flags = IMAGE_HAS_COLOR|IMAGE_HAS_ALPHA;
// load it in // load it in
alphaskyTexture = GL_LoadTextureInternal( "alpha_sky", &r_temp, TF_NOMIPMAP ); alphaskyTexture = GL_LoadTextureInternal( "alpha_sky", &r_temp, TF_NOMIPMAP | TF_ALLOW_NEAREST );
// clean up // clean up
FS_FreeImage( r_sky ); FS_FreeImage( r_sky );
@@ -3599,6 +3599,10 @@ Mod_LoadVisibility
*/ */
static void Mod_LoadVisibility( model_t *mod, dbspmodel_t *bmod ) static void Mod_LoadVisibility( model_t *mod, dbspmodel_t *bmod )
{ {
// external bmodels have no visibility
if( !bmod->visdata || !bmod->visdatasize )
return;
mod->visdata = Mem_Malloc( mod->mempool, bmod->visdatasize ); mod->visdata = Mem_Malloc( mod->mempool, bmod->visdatasize );
memcpy( mod->visdata, bmod->visdata, bmod->visdatasize ); memcpy( mod->visdata, bmod->visdata, bmod->visdatasize );
} }
@@ -3793,7 +3797,7 @@ static fs_offset_t Mod_FindBSPX( const byte *mod_base, size_t bufferlen )
max_offset = ALIGN( max_offset, 4 ); // force 32-bit boundary max_offset = ALIGN( max_offset, 4 ); // force 32-bit boundary
if( max_offset > bufferlen ) if( max_offset + sizeof( dbspx_hdr_t ) > bufferlen )
return -1; return -1;
bspx_header = (const dbspx_hdr_t *)( mod_base + max_offset ); bspx_header = (const dbspx_hdr_t *)( mod_base + max_offset );
@@ -3878,8 +3882,11 @@ static qboolean Mod_LoadBmodelLumps( model_t *mod, byte *mod_base, size_t buffer
Mod_LoadLump( mod_base, &extlumps[i], &worldstats[stat_index], flags, LOADLUMP_BSP30EXT, NULL ); Mod_LoadLump( mod_base, &extlumps[i], &worldstats[stat_index], flags, LOADLUMP_BSP30EXT, NULL );
// loading bspx lumps // loading bspx lumps
for( i = 0; i < ARRAYSIZE( bspxlumps ); i++, stat_index++ ) if( bspx_header_offset >= 0 )
Mod_LoadLump( mod_base, &bspxlumps[i], &worldstats[stat_index], flags, LOADLUMP_BSPX, mod_base + bspx_header_offset ); {
for( i = 0; i < ARRAYSIZE( bspxlumps ); i++, stat_index++ )
Mod_LoadLump( mod_base, &bspxlumps[i], &worldstats[stat_index], flags, LOADLUMP_BSPX, mod_base + bspx_header_offset );
}
if( !bmod->isworld ) // a1ba: why world excluded here? if( !bmod->isworld ) // a1ba: why world excluded here?
{ {
+1 -1
View File
@@ -1658,7 +1658,7 @@ void Netchan_TransmitBits( netchan_t *chan, int length, const byte *data )
MSG_Init( &send, "NetSend", send_buf, sizeof( send_buf )); MSG_Init( &send, "NetSend", send_buf, sizeof( send_buf ));
// prepare the packet header // prepare the packet header
w1 = chan->outgoing_sequence | (send_reliable << 31); w1 = chan->outgoing_sequence | (((uint)send_reliable ) << 31);
w2 = chan->incoming_sequence | (chan->incoming_reliable_sequence << 31); w2 = chan->incoming_sequence | (chan->incoming_reliable_sequence << 31);
send_reliable_fragment = false; send_reliable_fragment = false;
+8 -14
View File
@@ -112,7 +112,6 @@ msurface_t *PM_RecursiveSurfCheck( model_t *mod, mnode_t *node, vec3_t p1, vec3_
int i, side; int i, side;
msurface_t *surf; msurface_t *surf;
vec3_t mid; vec3_t mid;
mnode_t *children[2];
int numsurfaces, firstsurface; int numsurfaces, firstsurface;
loc0: loc0:
@@ -122,17 +121,15 @@ loc0:
t1 = PlaneDiff( p1, node->plane ); t1 = PlaneDiff( p1, node->plane );
t2 = PlaneDiff( p2, node->plane ); t2 = PlaneDiff( p2, node->plane );
node_children( children, node, mod );
if( t1 >= -FRAC_EPSILON && t2 >= -FRAC_EPSILON ) if( t1 >= -FRAC_EPSILON && t2 >= -FRAC_EPSILON )
{ {
node = children[0]; node = node_child( node, 0, mod );
goto loc0; goto loc0;
} }
if( t1 < FRAC_EPSILON && t2 < FRAC_EPSILON ) if( t1 < FRAC_EPSILON && t2 < FRAC_EPSILON )
{ {
node = children[1]; node = node_child( node, 1, mod );
goto loc0; goto loc0;
} }
@@ -142,7 +139,7 @@ loc0:
VectorLerp( p1, frac, p2, mid ); VectorLerp( p1, frac, p2, mid );
if(( surf = PM_RecursiveSurfCheck( mod, children[side], p1, mid )) != NULL ) if(( surf = PM_RecursiveSurfCheck( mod, node_child( node, side, mod ), p1, mid )) != NULL )
return surf; return surf;
// walk through real faces // walk through real faces
@@ -179,7 +176,7 @@ loc0:
return NULL; // through the fence return NULL; // through the fence
} }
return PM_RecursiveSurfCheck( mod, children[side^1], mid, p2 ); return PM_RecursiveSurfCheck( mod, node_child( node, side^1, mod ), mid, p2 );
} }
/* /*
@@ -234,7 +231,6 @@ static int PM_TestLine_r( model_t *mod, mnode_t *node, vec_t p1f, vec_t p2f, con
float frac, midf; float frac, midf;
int i, r, side; int i, r, side;
vec3_t mid; vec3_t mid;
mnode_t *children[2];
int numsurfaces, firstsurface; int numsurfaces, firstsurface;
loc0: loc0:
@@ -252,17 +248,15 @@ loc0:
front = PlaneDiff( start, node->plane ); front = PlaneDiff( start, node->plane );
back = PlaneDiff( stop, node->plane ); back = PlaneDiff( stop, node->plane );
node_children( children, node, mod );
if( front >= -FRAC_EPSILON && back >= -FRAC_EPSILON ) if( front >= -FRAC_EPSILON && back >= -FRAC_EPSILON )
{ {
node = children[0]; node = node_child( node, 0, mod );
goto loc0; goto loc0;
} }
if( front < FRAC_EPSILON && back < FRAC_EPSILON ) if( front < FRAC_EPSILON && back < FRAC_EPSILON )
{ {
node = children[1]; node = node_child( node, 1, mod );
goto loc0; goto loc0;
} }
@@ -273,7 +267,7 @@ loc0:
VectorLerp( start, frac, stop, mid ); VectorLerp( start, frac, stop, mid );
midf = p1f + ( p2f - p1f ) * frac; midf = p1f + ( p2f - p1f ) * frac;
r = PM_TestLine_r( mod, children[side], p1f, midf, start, mid, trace ); r = PM_TestLine_r( mod, node_child( node, side, mod ), p1f, midf, start, mid, trace );
if( r != CONTENTS_EMPTY ) if( r != CONTENTS_EMPTY )
{ {
@@ -322,7 +316,7 @@ loc0:
return contents; return contents;
} }
return PM_TestLine_r( mod, children[!side], midf, p2f, mid, stop, trace ); return PM_TestLine_r( mod, node_child( node, !side, mod ), midf, p2f, mid, stop, trace );
} }
int PM_TestLineExt( playermove_t *pmove, physent_t *ents, int numents, const vec3_t start, const vec3_t end, int flags ) int PM_TestLineExt( playermove_t *pmove, physent_t *ents, int numents, const vec3_t start, const vec3_t end, int flags )
+3
View File
@@ -84,6 +84,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define K_JOY3 205 #define K_JOY3 205
#define K_JOY4 206 #define K_JOY4 206
#define K_LTRIGGER K_JOY1
#define K_RTRIGGER K_JOY2
// //
// aux keys are for multi-buttoned joysticks to generate so they can use // aux keys are for multi-buttoned joysticks to generate so they can use
// the normal binding process // the normal binding process
+1 -1
View File
@@ -222,7 +222,7 @@ typedef struct ui_extendedfuncs_s {
// new mods info // new mods info
gameinfo2_t *(*pfnGetGameInfo)( int gi_version ); // might return NULL if gi_version is unsupported gameinfo2_t *(*pfnGetGameInfo)( int gi_version ); // might return NULL if gi_version is unsupported
gameinfo2_t *(*pfnGetModInfo)( int gi_version, int mod_index ); // continiously call it until it returns null gameinfo2_t *(*pfnGetModInfo)( int gi_version, int mod_index ); // continuously call it until it returns null
// returns 1 if cvar has read-only flag // returns 1 if cvar has read-only flag
// or -1 if cvar not found // or -1 if cvar not found
-3
View File
@@ -21,9 +21,6 @@
#include <sys/stat.h> #include <sys/stat.h>
#include "dlfcn.h" #include "dlfcn.h"
#ifndef XASH_GAMEDIR
#define XASH_GAMEDIR "valve" // !!! Replace with your default (base) game directory !!!
#endif
#define XASHLIB "@rpath/libxash.dylib" #define XASHLIB "@rpath/libxash.dylib"
+52 -32
View File
@@ -13,63 +13,83 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
*/ */
#include <string.h> #include <string.h>
#include <unistd.h>
#include <SDL.h> #include <SDL.h>
#include <dlfcn.h>
#include <sys/stat.h>
#include "crtlib.h" #include "crtlib.h"
#include "fscallback.h"
#include "library.h" #include "library.h"
#include "platform/ios/lib_ios.h" #include "platform/ios/lib_ios.h"
#include <dlfcn.h> #include "common.h"
#define EXT_LENGTH 5 const char *g_szLibrarySuffix;
static void *IOS_LoadLibraryInternal( const char *dllname ) static void *IOS_LoadLibraryInternal( const char *dllname )
{ {
void *pHandle; void *pHandle;
string errorstring = "";
char path[MAX_SYSPATH]; char path[MAX_SYSPATH];
Q_snprintf( path, MAX_SYSPATH, "%s%s", SDL_GetBasePath(), dllname ); Q_snprintf( path, sizeof( path ), "%s%s", SDL_GetBasePath(), dllname );
pHandle = dlopen( path, RTLD_LAZY ); pHandle = dlopen( path, RTLD_LAZY );
if( !pHandle ) if( !pHandle )
{ COM_PushLibraryError(dlerror( ));
COM_PushLibraryError(errorstring);
COM_PushLibraryError(dlerror());
}
return pHandle; return pHandle;
} }
const char *g_szLibrarySuffix;
static qboolean IOS_LibraryExistsInternal( const char *name )
{
struct stat buf;
char path[MAX_SYSPATH];
Q_snprintf( path, sizeof( path ), "%s%s", SDL_GetBasePath(), name );
return stat( path, &buf ) == 0;
}
static const char *IOS_GetLibraryPostfix( void )
{
if( g_szLibrarySuffix )
return g_szLibrarySuffix;
return Q_strcmp( host.default_gamedir, FS_Gamedir( )) ? FS_Gamedir( ) : "";
}
static void IOS_PrepareGameLibraryPath( const char *dllname, char *out, size_t outsize )
{
string strippedname;
Q_strncpy( strippedname, dllname, sizeof( strippedname ));
COM_StripExtension( strippedname );
Q_snprintf( out, outsize, "%s_%s.dylib", strippedname, IOS_GetLibraryPostfix( ));
}
void *IOS_LoadLibrary( const char *dllname ) void *IOS_LoadLibrary( const char *dllname )
{ {
//Immediately load if the library is filesystem_stdio.dylib or we will crash when accessing gamedir // filesystem_stdio is a special case, as engine won't work correctly without it
if ( !Q_strcmp( dllname, "filesystem_stdio.dylib" ) ) // but it's always located at known path
{ if( !Q_strcmp( dllname, "filesystem_stdio.dylib" ))
return IOS_LoadLibraryInternal( dllname ); return IOS_LoadLibraryInternal( dllname );
}
string name; string name;
string strippedname;
const char *postfix = g_szLibrarySuffix;
char *pHandle; char *pHandle;
if( !postfix ) IOS_PrepareGameLibraryPath( dllname, name, sizeof( name ));
{
if ( Q_strcmp(FS_Gamedir(), "valve" ) )
{
postfix = FS_Gamedir( );
}
else postfix = "";
}
Q_strncpy( strippedname, dllname, sizeof( strippedname ) );
COM_StripExtension(strippedname);
Q_snprintf( name, MAX_STRING, "%s_%s.dylib", strippedname, postfix );
pHandle = IOS_LoadLibraryInternal( name ); pHandle = IOS_LoadLibraryInternal( name );
if( pHandle ) if( !pHandle )
return pHandle; pHandle = IOS_LoadLibraryInternal( dllname );
return IOS_LoadLibraryInternal( dllname ); return pHandle;
}
qboolean IOS_LibraryExists( const char *dllname )
{
string name;
IOS_PrepareGameLibraryPath( dllname, name, sizeof( name ));
return IOS_LibraryExistsInternal( name ) || IOS_LibraryExistsInternal( dllname );
} }
+1
View File
@@ -20,6 +20,7 @@ GNU General Public License for more details.
#define Platform_POSIX_LoadLibrary( x ) IOS_LoadLibrary(( x )) #define Platform_POSIX_LoadLibrary( x ) IOS_LoadLibrary(( x ))
void *IOS_LoadLibrary( const char *dllname ); void *IOS_LoadLibrary( const char *dllname );
qboolean IOS_LibraryExists( const char *name );
#endif // IOS_LIB_H #endif // IOS_LIB_H
#endif // TARGET_OS_IPHONE #endif // TARGET_OS_IPHONE
+31 -31
View File
@@ -105,8 +105,8 @@ qboolean SNDDMA_Init( void )
return false; return false;
} }
dma.format.speed = SOUND_DMA_SPEED; snd.format.speed = SOUND_DMA_SPEED;
r = dma.format.speed; r = snd.format.speed;
if( ( err = snd_pcm_hw_params_set_rate_near( s_alsa.pcm_handle, s_alsa.hw_params, &r, &dir ) ) < 0 ) if( ( err = snd_pcm_hw_params_set_rate_near( s_alsa.pcm_handle, s_alsa.hw_params, &r, &dir ) ) < 0 )
{ {
@@ -121,14 +121,14 @@ qboolean SNDDMA_Init( void )
if( dir != 0 ) if( dir != 0 )
{ {
Con_Printf( "ALSA: rate %d not supported, using %d\n", SOUND_DMA_SPEED, r ); Con_Printf( "ALSA: rate %d not supported, using %d\n", SOUND_DMA_SPEED, r );
dma.format.speed = r; snd.format.speed = r;
dir = 0; dir = 0;
} }
} }
dma.format.channels = 2; snd.format.channels = 2;
if( ( err = snd_pcm_hw_params_set_channels(s_alsa.pcm_handle, s_alsa.hw_params, dma.format.channels ) ) < 0 ) if( ( err = snd_pcm_hw_params_set_channels(s_alsa.pcm_handle, s_alsa.hw_params, snd.format.channels ) ) < 0 )
{ {
Con_Printf( "ALSA: cannot set channels %d(%s)\n", 2, snd_strerror( err ) ); Con_Printf( "ALSA: cannot set channels %d(%s)\n", 2, snd_strerror( err ) );
snd_pcm_hw_params_free( s_alsa.hw_params ); snd_pcm_hw_params_free( s_alsa.hw_params );
@@ -162,7 +162,7 @@ qboolean SNDDMA_Init( void )
} }
else else
{ {
// if period is NPOT it cannot be used as dma.samples in Xash3D // if period is NPOT it cannot be used as snd.samples in Xash3D
// and need more space to send buffer partially // and need more space to send buffer partially
samples = 1; samples = 1;
while( samples < p * 4 ) while( samples < p * 4 )
@@ -184,15 +184,15 @@ qboolean SNDDMA_Init( void )
return false; return false;
} }
dma.buffer = Mem_Calloc( sndpool, samples * 2 ); //allocate pcm frame buffer snd.buffer = Mem_Calloc( sndpool, samples * 2 ); //allocate pcm frame buffer
dma.samplepos = 0; snd.samplepos = 0;
dma.samples = samples; snd.samples = samples;
dma.format.width = 2; snd.format.width = 2;
dma.initialized = 1; snd.initialized = 1;
dma.backendName = "ALSA"; snd.backend_name = "ALSA";
snd_pcm_prepare( s_alsa.pcm_handle ); snd_pcm_prepare( s_alsa.pcm_handle );
snd_pcm_writei( s_alsa.pcm_handle, dma.buffer, 2 * s_alsa.period_size ); snd_pcm_writei( s_alsa.pcm_handle, snd.buffer, 2 * s_alsa.period_size );
snd_pcm_start( s_alsa.pcm_handle ); snd_pcm_start( s_alsa.pcm_handle );
return true; return true;
@@ -208,14 +208,14 @@ Closes the ALSA pcm device and frees the dma buffer.
void SNDDMA_Shutdown(void) void SNDDMA_Shutdown(void)
{ {
Con_Printf( "Shutting down audio.\n" ); Con_Printf( "Shutting down audio.\n" );
dma.initialized = false; snd.initialized = false;
if( dma.buffer ) if( snd.buffer )
{ {
snd_pcm_drop( s_alsa.pcm_handle ); snd_pcm_drop( s_alsa.pcm_handle );
snd_pcm_close( s_alsa.pcm_handle ); snd_pcm_close( s_alsa.pcm_handle );
Mem_Free( dma.buffer ); Mem_Free( snd.buffer );
dma.buffer = NULL; snd.buffer = NULL;
} }
} }
@@ -240,38 +240,38 @@ void SNDDMA_Submit( void )
while( avail >= s_alsa.period_size ) while( avail >= s_alsa.period_size )
{ {
int size = dma.samples << 1; int size = snd.samples << 1;
int pos = dma.samplepos << 1; int pos = snd.samplepos << 1;
unsigned long len = s_alsa.period_size * 4; unsigned long len = s_alsa.period_size * 4;
int wrapped = pos + len - size; int wrapped = pos + len - size;
int w; int w;
if( wrapped < 0 ) if( wrapped < 0 )
{ {
w = snd_pcm_writei( s_alsa.pcm_handle, dma.buffer + pos, len / 4 ); w = snd_pcm_writei( s_alsa.pcm_handle, snd.buffer + pos, len / 4 );
if( w < 0 ) if( w < 0 )
{ {
snd_pcm_prepare(s_alsa.pcm_handle); snd_pcm_prepare(s_alsa.pcm_handle);
return; return;
} }
dma.samplepos += len >> 1; snd.samplepos += len >> 1;
} }
else else
{ {
int remaining = size - pos; int remaining = size - pos;
w = snd_pcm_writei( s_alsa.pcm_handle, dma.buffer + pos, remaining / 4 ); w = snd_pcm_writei( s_alsa.pcm_handle, snd.buffer + pos, remaining / 4 );
if( w < 0 ) if( w < 0 )
{ {
snd_pcm_prepare(s_alsa.pcm_handle); snd_pcm_prepare(s_alsa.pcm_handle);
return; return;
} }
w = snd_pcm_writei( s_alsa.pcm_handle, dma.buffer, wrapped / 4 ); w = snd_pcm_writei( s_alsa.pcm_handle, snd.buffer, wrapped / 4 );
if( w < 0 ) if( w < 0 )
{ {
snd_pcm_prepare(s_alsa.pcm_handle); snd_pcm_prepare(s_alsa.pcm_handle);
return; return;
} }
dma.samplepos = wrapped >> 1; snd.samplepos = wrapped >> 1;
} }
avail = snd_pcm_avail_update( s_alsa.pcm_handle ); avail = snd_pcm_avail_update( s_alsa.pcm_handle );
@@ -282,11 +282,11 @@ void SNDDMA_Submit( void )
int s, w, frames; int s, w, frames;
void *start; void *start;
if( !dma.buffer ) if( !snd.buffer )
return; return;
s = dma.samplepos * 2; s = snd.samplepos * 2;
start = (void *)&dma.buffer[s]; start = (void *)&snd.buffer[s];
frames = s_alsa.period_size / 2; frames = s_alsa.period_size / 2;
// write to card // write to card
if( ( w = snd_pcm_writei( s_alsa.pcm_handle, start, frames ) ) < 0) if( ( w = snd_pcm_writei( s_alsa.pcm_handle, start, frames ) ) < 0)
@@ -296,10 +296,10 @@ void SNDDMA_Submit( void )
return; return;
} }
dma.samplepos += w * 2; // mark progress snd.samplepos += w * 2; // mark progress
if(dma.samplepos >= dma.samples) if(snd.samplepos >= snd.samples)
dma.samplepos = 0; // wrap buffer snd.samplepos = 0; // wrap buffer
} }
} }
@@ -324,7 +324,7 @@ between a deactivate and an activate.
*/ */
void SNDDMA_Activate( qboolean active ) void SNDDMA_Activate( qboolean active )
{ {
if( !dma.initialized ) if( !snd.initialized )
return; return;
s_alsa.paused = !active; s_alsa.paused = !active;
+6 -1
View File
@@ -66,10 +66,15 @@ qboolean Platform_DebuggerPresent( void )
tracer_pid = (const byte*)Q_strstr( buf, TracerPid ); tracer_pid = (const byte*)Q_strstr( buf, TracerPid );
if( !tracer_pid ) if( !tracer_pid )
return false; return false;
//printf( "%s\n", tracer_pid ); //printf( "%s\n", tracer_pid );
while( *tracer_pid < '0' || *tracer_pid > '9' )
while(( *tracer_pid < '0' ) || ( *tracer_pid > '9' ))
{
if( *tracer_pid++ == '\n' ) if( *tracer_pid++ == '\n' )
return false; return false;
}
//printf( "%s\n", tracer_pid ); //printf( "%s\n", tracer_pid );
return !!Q_atoi( (const char*)tracer_pid ); return !!Q_atoi( (const char*)tracer_pid );
} }
+24 -5
View File
@@ -18,6 +18,8 @@ GNU General Public License for more details.
#define PLATFORM_H #define PLATFORM_H
#include <errno.h> #include <errno.h>
#define FSCALLBACK_OVERRIDE_MALLOC_LIKE
#include "fscallback.h"
#include "common.h" #include "common.h"
#include "system.h" #include "system.h"
#include "defaults.h" #include "defaults.h"
@@ -43,6 +45,7 @@ qboolean Platform_DebuggerPresent( void );
int IOS_GetArgs( char ***argv ); int IOS_GetArgs( char ***argv );
const char *IOS_GetDocsDir( void ); const char *IOS_GetDocsDir( void );
void IOS_LaunchDialog( void ); void IOS_LaunchDialog( void );
#include "platform/ios/lib_ios.h"
#endif // TARGET_OS_IOS #endif // TARGET_OS_IOS
#if XASH_WIN32 || XASH_LINUX #if XASH_WIN32 || XASH_LINUX
@@ -58,7 +61,7 @@ char *Posix_Input( void );
#endif #endif
#if XASH_SDL #if XASH_SDL
void SDLash_Init( const char *basedir ); void SDLash_Init( void );
void SDLash_Shutdown( void ); void SDLash_Shutdown( void );
void SDLash_NanoSleep( int nsec ); void SDLash_NanoSleep( int nsec );
#endif #endif
@@ -111,7 +114,7 @@ void Linux_SetTimer( float time );
int Linux_GetProcessID( void ); int Linux_GetProcessID( void );
#endif #endif
static inline void Platform_Init( qboolean con_showalways, const char *basedir ) static inline void Platform_Init( qboolean con_showalways )
{ {
#if XASH_POSIX #if XASH_POSIX
// daemonize as early as possible, because we need to close our file descriptors // daemonize as early as possible, because we need to close our file descriptors
@@ -119,7 +122,7 @@ static inline void Platform_Init( qboolean con_showalways, const char *basedir )
#endif #endif
#if XASH_SDL #if XASH_SDL
SDLash_Init( basedir ); SDLash_Init( );
#endif #endif
#if XASH_ANDROID #if XASH_ANDROID
@@ -207,6 +210,18 @@ static inline void Sys_RestoreCrashHandler( void )
} }
#endif #endif
static inline qboolean Platform_LibraryExists( const char *name, qboolean gamedironly )
{
#if XASH_IOS
return IOS_LibraryExists( name );
#elif XASH_ANDROID
// sorry, unimplemented
return false;
#else
return g_fsapi.FileExists( name, gamedironly );
#endif
}
/* /*
============================================================================== ==============================================================================
@@ -389,14 +404,16 @@ qboolean VoiceCapture_Lock( qboolean lock );
pid_t raise_tid = Linux_GetProcessID(); \ pid_t raise_tid = Linux_GetProcessID(); \
int raise_sig = (x); \ int raise_sig = (x); \
__asm__ volatile ( \ __asm__ volatile ( \
"push {r7}\n\t" \
"mov r7,#268\n\t" \ "mov r7,#268\n\t" \
"mov r0,%0\n\t" \ "mov r0,%0\n\t" \
"mov r1,%1\n\t" \ "mov r1,%1\n\t" \
"mov r2,%2\n\t" \ "mov r2,%2\n\t" \
"svc 0\n\t" \ "svc 0\n\t" \
"pop {r7}\n\t" \
: \ : \
: "r"(raise_pid), "r"(raise_tid), "r"(raise_sig) \ : "r"(raise_pid), "r"(raise_tid), "r"(raise_sig) \
: "r0", "r1", "r2", "r7", "memory" \ : "r0", "r1", "r2", "memory" \
); \ ); \
} while( 0 ) } while( 0 )
#define INLINE_NANOSLEEP1() do \ #define INLINE_NANOSLEEP1() do \
@@ -404,13 +421,15 @@ qboolean VoiceCapture_Lock( qboolean lock );
struct timespec ns_t1 = {1, 0}; \ struct timespec ns_t1 = {1, 0}; \
struct timespec ns_t2 = {0, 0}; \ struct timespec ns_t2 = {0, 0}; \
__asm__ volatile ( \ __asm__ volatile ( \
"push {r7}\n\t" \
"mov r7,#162\n\t" \ "mov r7,#162\n\t" \
"mov r0,%0\n\t" \ "mov r0,%0\n\t" \
"mov r1,%1\n\t" \ "mov r1,%1\n\t" \
"svc 0\n\t" \ "svc 0\n\t" \
"pop {r7}\n\t" \
: \ : \
: "r"(&ns_t1), "r"(&ns_t2) \ : "r"(&ns_t1), "r"(&ns_t2) \
: "r0", "r1", "r7", "memory" \ : "r0", "r1", "memory" \
); \ ); \
} while( 0 ) } while( 0 )
#elif XASH_LINUX && XASH_ARM && XASH_64BIT #elif XASH_LINUX && XASH_ARM && XASH_64BIT
+24 -24
View File
@@ -46,38 +46,38 @@ static char sdl_backend_name[32];
static void SDL_SoundCallback( void *userdata, Uint8 *stream, int len ) static void SDL_SoundCallback( void *userdata, Uint8 *stream, int len )
{ {
const int size = dma.samples << 1; const int size = snd.samples << 1;
int pos; int pos;
int wrapped; int wrapped;
if( !dma.buffer ) if( !snd.buffer )
{ {
memset( stream, 0, len ); memset( stream, 0, len );
return; return;
} }
pos = dma.samplepos << 1; pos = snd.samplepos << 1;
if( pos >= size ) if( pos >= size )
pos = dma.samplepos = 0; pos = snd.samplepos = 0;
wrapped = pos + len - size; wrapped = pos + len - size;
if( wrapped < 0 ) if( wrapped < 0 )
{ {
memcpy( stream, dma.buffer + pos, len ); memcpy( stream, snd.buffer + pos, len );
dma.samplepos += len >> 1; snd.samplepos += len >> 1;
} }
else else
{ {
int remaining = size - pos; int remaining = size - pos;
memcpy( stream, dma.buffer + pos, remaining ); memcpy( stream, snd.buffer + pos, remaining );
memcpy( stream + remaining, dma.buffer, wrapped ); memcpy( stream + remaining, snd.buffer, wrapped );
dma.samplepos = wrapped >> 1; snd.samplepos = wrapped >> 1;
} }
if( dma.samplepos >= size ) if( snd.samplepos >= size )
dma.samplepos = 0; snd.samplepos = 0;
} }
/* /*
@@ -131,20 +131,20 @@ qboolean SNDDMA_Init( void )
goto fail; goto fail;
} }
dma.format.speed = obtained.freq; snd.format.speed = obtained.freq;
dma.format.channels = obtained.channels; snd.format.channels = obtained.channels;
dma.format.width = 2; snd.format.width = 2;
samplecount = s_samplecount.value; samplecount = s_samplecount.value;
if( !samplecount ) if( !samplecount )
samplecount = 0x8000; samplecount = 0x8000;
dma.samples = samplecount * obtained.channels; snd.samples = samplecount * obtained.channels;
dma.buffer = Mem_Calloc( sndpool, dma.samples * 2 ); snd.buffer = Mem_Calloc( sndpool, snd.samples * 2 );
dma.samplepos = 0; snd.samplepos = 0;
Con_Printf( "Using SDL audio driver: %s @ %d Hz\n", SDL_GetCurrentAudioDriver( ), obtained.freq ); Con_Printf( "Using SDL audio driver: %s @ %d Hz\n", SDL_GetCurrentAudioDriver( ), obtained.freq );
Q_snprintf( sdl_backend_name, sizeof( sdl_backend_name ), "SDL" ); Q_snprintf( sdl_backend_name, sizeof( sdl_backend_name ), "SDL" );
dma.initialized = true; snd.initialized = true;
dma.backendName = sdl_backend_name; snd.backend_name = sdl_backend_name;
SNDDMA_Activate( true ); SNDDMA_Activate( true );
@@ -191,7 +191,7 @@ Reset the sound device for exiting
void SNDDMA_Shutdown( void ) void SNDDMA_Shutdown( void )
{ {
Con_Printf( "Shutting down audio.\n" ); Con_Printf( "Shutting down audio.\n" );
dma.initialized = false; snd.initialized = false;
if( sdl_dev ) if( sdl_dev )
{ {
@@ -203,10 +203,10 @@ void SNDDMA_Shutdown( void )
if( SDL_WasInit( SDL_INIT_AUDIO )) if( SDL_WasInit( SDL_INIT_AUDIO ))
SDL_QuitSubSystem( SDL_INIT_AUDIO ); SDL_QuitSubSystem( SDL_INIT_AUDIO );
if( dma.buffer ) if( snd.buffer )
{ {
Mem_Free( dma.buffer ); Mem_Free( snd.buffer );
dma.buffer = NULL; snd.buffer = NULL;
} }
} }
@@ -220,7 +220,7 @@ between a deactivate and an activate.
*/ */
void SNDDMA_Activate( qboolean active ) void SNDDMA_Activate( qboolean active )
{ {
if( !dma.initialized ) if( !snd.initialized )
return; return;
SDL_PauseAudioDevice( sdl_dev, !active ); SDL_PauseAudioDevice( sdl_dev, !active );
+70 -30
View File
@@ -41,8 +41,8 @@ static const engineAxis_t g_axis_mapping[] =
{ {
JOY_AXIS_SIDE, // SDL_CONTROLLER_AXIS_LEFTX, JOY_AXIS_SIDE, // SDL_CONTROLLER_AXIS_LEFTX,
JOY_AXIS_FWD, // SDL_CONTROLLER_AXIS_LEFTY, JOY_AXIS_FWD, // SDL_CONTROLLER_AXIS_LEFTY,
JOY_AXIS_PITCH, // SDL_CONTROLLER_AXIS_RIGHTX, JOY_AXIS_YAW, // SDL_CONTROLLER_AXIS_RIGHTX,
JOY_AXIS_YAW, // SDL_CONTROLLER_AXIS_RIGHTY, JOY_AXIS_PITCH, // SDL_CONTROLLER_AXIS_RIGHTY,
JOY_AXIS_LT, // SDL_CONTROLLER_AXIS_TRIGGERLEFT, JOY_AXIS_LT, // SDL_CONTROLLER_AXIS_TRIGGERLEFT,
JOY_AXIS_RT, // SDL_CONTROLLER_AXIS_TRIGGERRIGHT, JOY_AXIS_RT, // SDL_CONTROLLER_AXIS_TRIGGERRIGHT,
}; };
@@ -52,14 +52,16 @@ static SDL_GameController *g_current_gamepad;
static SDL_GameController **g_gamepads; static SDL_GameController **g_gamepads;
static size_t g_num_gamepads; static size_t g_num_gamepads;
#define CALIBRATION_TIME 10.0f #define CALIBRATION_TIME 5.0f
static struct static struct
{ {
float time; float time;
vec3_t data; vec3_t data;
vec3_t calibrated_values; vec3_t calibrated_values;
int samples; float data_rate;
int samples;
qboolean continuous; // true after first successful calibration
} gyrocal; } gyrocal;
static void SDLash_RestartCalibration( void ) static void SDLash_RestartCalibration( void )
@@ -70,35 +72,69 @@ static void SDLash_RestartCalibration( void )
gyrocal.time = host.realtime + CALIBRATION_TIME; gyrocal.time = host.realtime + CALIBRATION_TIME;
Con_Printf( "Starting gyroscope calibration...\n" ); #if SDL_VERSION_ATLEAST( 2, 0, 16 )
gyrocal.data_rate = SDL_GameControllerGetSensorDataRate( g_current_gamepad, SDL_SENSOR_GYRO );
#endif
if( !gyrocal.data_rate )
gyrocal.data_rate = 10.0f;
Con_Printf( S_NOTE "Starting gyroscope calibration at %g data rate for %g seconds...\n", gyrocal.data_rate, CALIBRATION_TIME );
} }
static void SDLash_FinalizeCalibration( void ) static void SDLash_FinalizeCalibration( void )
{ {
float data_rate = 10.0f; // let's say we're polling at 10Hz? int min_samples = Q_rint( CALIBRATION_TIME * gyrocal.data_rate * 0.5f );
int min_samples;
#if SDL_VERSION_ATLEAST( 2, 0, 16 )
data_rate = SDL_GameControllerGetSensorDataRate( g_current_gamepad, SDL_SENSOR_GYRO );
if( !data_rate )
data_rate = 10.0f;
#endif
min_samples = Q_rint( CALIBRATION_TIME * data_rate * 0.75f );
// we waited for few seconds and got too few samples // we waited for few seconds and got too few samples
if( gyrocal.samples <= min_samples ) if( gyrocal.samples <= min_samples )
{ {
Joy_SetCalibrationState( JOY_FAILED_TO_CALIBRATE ); if( !gyrocal.continuous )
return; {
Joy_SetCalibrationState( JOY_FAILED_TO_CALIBRATE );
Con_Printf( S_ERROR "Calibration failed, got samples %d < %d\n", gyrocal.samples, min_samples );
gyrocal.time = 0.0f;
return;
}
// Con_Reportf( S_WARN "Continuous calibration: too few samples (%d < %d), retrying\n", gyrocal.samples, min_samples );
}
else
{
VectorScale( gyrocal.data, 1.0f / gyrocal.samples, gyrocal.calibrated_values );
Joy_SetCalibrationState( JOY_CALIBRATED );
if( !gyrocal.continuous )
Con_Printf( "Calibration done. Result: %f %f %f at %d samples\n", gyrocal.calibrated_values[0], gyrocal.calibrated_values[1], gyrocal.calibrated_values[2], gyrocal.samples );
// else
// Con_Reportf( "Continuous calibration done. Result: %f %f %f at %d samples\n", gyrocal.calibrated_values[0], gyrocal.calibrated_values[1], gyrocal.calibrated_values[2], gyrocal.samples );
gyrocal.continuous = true;
} }
VectorScale( gyrocal.data, 1.0f / gyrocal.samples, gyrocal.calibrated_values ); // schedule next calibration window
Joy_SetCalibrationState( JOY_CALIBRATED ); VectorClear( gyrocal.data );
gyrocal.samples = 0;
gyrocal.time = host.realtime + CALIBRATION_TIME;
}
Con_Printf( "Calibration done. Result: %f %f %f\n", gyrocal.calibrated_values[0], gyrocal.calibrated_values[1], gyrocal.calibrated_values[2] ); static void SDLash_AccumulateCalibrationData( vec3_t data )
{
// for continuous background calibration only listen for noise
// by comparing it with calibrated values
//
// for first calibration this might be hurtful as device might
// output offset data
if( gyrocal.continuous )
{
vec3_t calibrated;
VectorSubtract( data, gyrocal.calibrated_values, calibrated );
gyrocal.time = 0.0f; if( VectorLength( calibrated ) > 0.1f )
return;
}
VectorAdd( gyrocal.data, data, gyrocal.data );
gyrocal.samples++;
if( !gyrocal.continuous )
Joy_SetCalibrationState( JOY_CALIBRATING );
} }
static void SDLash_GameControllerAddMappings( const char *name ) static void SDLash_GameControllerAddMappings( const char *name )
@@ -125,7 +161,8 @@ static void SDLash_SetActiveGameController( SDL_JoystickID id )
#if SDL_VERSION_ATLEAST( 2, 0, 14 ) #if SDL_VERSION_ATLEAST( 2, 0, 14 )
// going to change active controller, disable gyro events in old // going to change active controller, disable gyro events in old
SDL_GameControllerSetSensorEnabled( g_current_gamepad, SDL_SENSOR_GYRO, SDL_FALSE ); if( g_current_gamepad )
SDL_GameControllerSetSensorEnabled( g_current_gamepad, SDL_SENSOR_GYRO, SDL_FALSE );
#endif // SDL_VERSION_ATLEAST( 2, 0, 14 ) #endif // SDL_VERSION_ATLEAST( 2, 0, 14 )
g_current_gamepad_id = id; g_current_gamepad_id = id;
@@ -243,12 +280,12 @@ static void SDLash_GameControllerSensorUpdate( SDL_ControllerSensorEvent sensor
{ {
if( host.realtime > gyrocal.time ) if( host.realtime > gyrocal.time )
SDLash_FinalizeCalibration(); SDLash_FinalizeCalibration();
else
SDLash_AccumulateCalibrationData( sensor.data );
VectorAdd( gyrocal.data, sensor.data, gyrocal.data ); // block gyro events only during initial calibration
gyrocal.samples++; if( !gyrocal.continuous )
return;
Joy_SetCalibrationState( JOY_CALIBRATING );
return;
} }
VectorSubtract( sensor.data, gyrocal.calibrated_values, data ); VectorSubtract( sensor.data, gyrocal.calibrated_values, data );
@@ -335,6 +372,9 @@ int Platform_JoyInit( void )
{ {
int count, numJoysticks, i; int count, numJoysticks, i;
SDL_SetHint( SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1" );
SDL_SetHint( SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1" );
Con_Reportf( "Joystick: SDL GameController API\n" ); Con_Reportf( "Joystick: SDL GameController API\n" );
if( SDL_WasInit( SDL_INIT_GAMECONTROLLER ) != SDL_INIT_GAMECONTROLLER && if( SDL_WasInit( SDL_INIT_GAMECONTROLLER ) != SDL_INIT_GAMECONTROLLER &&
SDL_InitSubSystem( SDL_INIT_GAMECONTROLLER )) SDL_InitSubSystem( SDL_INIT_GAMECONTROLLER ))
+24 -24
View File
@@ -39,32 +39,32 @@ static char sdl_backend_name[32];
static void SDL_SoundCallback( void *userdata, Uint8 *stream, int len ) static void SDL_SoundCallback( void *userdata, Uint8 *stream, int len )
{ {
const int size = dma.samples << 1; const int size = snd.samples << 1;
int pos; int pos;
int wrapped; int wrapped;
pos = dma.samplepos << 1; pos = snd.samplepos << 1;
if( pos >= size ) if( pos >= size )
pos = dma.samplepos = 0; pos = snd.samplepos = 0;
wrapped = pos + len - size; wrapped = pos + len - size;
if( wrapped < 0 ) if( wrapped < 0 )
{ {
memcpy( stream, dma.buffer + pos, len ); memcpy( stream, snd.buffer + pos, len );
dma.samplepos += len >> 1; snd.samplepos += len >> 1;
} }
else else
{ {
int remaining = size - pos; int remaining = size - pos;
memcpy( stream, dma.buffer + pos, remaining ); memcpy( stream, snd.buffer + pos, remaining );
memcpy( stream + remaining, dma.buffer, wrapped ); memcpy( stream + remaining, snd.buffer, wrapped );
dma.samplepos = wrapped >> 1; snd.samplepos = wrapped >> 1;
} }
if( dma.samplepos >= size ) if( snd.samplepos >= size )
dma.samplepos = 0; snd.samplepos = 0;
} }
/* /*
@@ -148,22 +148,22 @@ qboolean SNDDMA_Init( void )
goto fail; goto fail;
} }
dma.format.speed = obtained.freq; snd.format.speed = obtained.freq;
dma.format.channels = obtained.channels; snd.format.channels = obtained.channels;
dma.format.width = 2; snd.format.width = 2;
samplecount = s_samplecount.value; samplecount = s_samplecount.value;
if( !samplecount ) if( !samplecount )
samplecount = 0x8000; samplecount = 0x8000;
dma.samples = samplecount * obtained.channels; snd.samples = samplecount * obtained.channels;
dma.buffer = Mem_Calloc( sndpool, dma.samples * 2 ); snd.buffer = Mem_Calloc( sndpool, snd.samples * 2 );
dma.samplepos = 0; snd.samplepos = 0;
sdl_format = obtained.format; sdl_format = obtained.format;
Con_Printf( "Using SDL audio driver: %s @ %d Hz\n", SDL_GetCurrentAudioDriver( ), obtained.freq ); Con_Printf( "Using SDL audio driver: %s @ %d Hz\n", SDL_GetCurrentAudioDriver( ), obtained.freq );
Q_snprintf( sdl_backend_name, sizeof( sdl_backend_name ), "SDL (%s)", SDL_GetCurrentAudioDriver( )); Q_snprintf( sdl_backend_name, sizeof( sdl_backend_name ), "SDL (%s)", SDL_GetCurrentAudioDriver( ));
dma.initialized = true; snd.initialized = true;
dma.backendName = sdl_backend_name; snd.backend_name = sdl_backend_name;
SNDDMA_Activate( true ); SNDDMA_Activate( true );
@@ -179,7 +179,7 @@ fail:
============== ==============
SNDDMA_BeginPainting SNDDMA_BeginPainting
Makes sure dma.buffer is valid Makes sure snd.buffer is valid
=============== ===============
*/ */
void SNDDMA_BeginPainting( void ) void SNDDMA_BeginPainting( void )
@@ -210,7 +210,7 @@ Reset the sound device for exiting
void SNDDMA_Shutdown( void ) void SNDDMA_Shutdown( void )
{ {
Con_Printf( "Shutting down audio.\n" ); Con_Printf( "Shutting down audio.\n" );
dma.initialized = false; snd.initialized = false;
if( sdl_dev ) if( sdl_dev )
{ {
@@ -221,10 +221,10 @@ void SNDDMA_Shutdown( void )
SDL_QuitSubSystem( SDL_INIT_AUDIO ); SDL_QuitSubSystem( SDL_INIT_AUDIO );
if( dma.buffer ) if( snd.buffer )
{ {
Mem_Free( dma.buffer ); Mem_Free( snd.buffer );
dma.buffer = NULL; snd.buffer = NULL;
} }
} }
@@ -238,7 +238,7 @@ between a deactivate and an activate.
*/ */
void SNDDMA_Activate( qboolean active ) void SNDDMA_Activate( qboolean active )
{ {
if( !dma.initialized ) if( !snd.initialized )
return; return;
SDL_PauseAudioDevice( sdl_dev, !active ); SDL_PauseAudioDevice( sdl_dev, !active );
+6 -3
View File
@@ -79,20 +79,23 @@ static void SDLCALL SDLash_LogOutputFunction( void *userdata, int category, SDL_
case SDL_LOG_PRIORITY_INFO: case SDL_LOG_PRIORITY_INFO:
str = S_NOTE; str = S_NOTE;
break; break;
default:
str = "";
break;
} }
Con_Reportf( "%s" S_BLUE "SDL" S_DEFAULT ": [%s] %s\n", str, SDLash_CategoryToString( category ), message ); Con_Reportf( "%s" S_BLUE "SDL" S_DEFAULT ": [%s] %s\n", str, SDLash_CategoryToString( category ), message );
} }
void SDLash_Init( const char *basedir ) void SDLash_Init( void )
{ {
#if XASH_APPLE #if XASH_IOS
char *path = SDL_GetBasePath(); char *path = SDL_GetBasePath();
if( path != NULL ) if( path != NULL )
{ {
char buf[MAX_VA_STRING]; char buf[MAX_VA_STRING];
Q_snprintf( buf, sizeof( buf ), "%s%s/extras.pk3", path, basedir ); Q_snprintf( buf, sizeof( buf ), "%s%s/extras.pk3", path, host.default_gamedir );
setenv( "XASH3D_EXTRAS_PAK1", buf, true ); setenv( "XASH3D_EXTRAS_PAK1", buf, true );
} }
#endif #endif
+23 -23
View File
@@ -28,35 +28,35 @@ static char sdl_backend_name[32];
static void SDLash_OutputCallback( void *userdata, SDL_AudioStream *stream, int additional_amount, int len ) static void SDLash_OutputCallback( void *userdata, SDL_AudioStream *stream, int additional_amount, int len )
{ {
const int size = dma.samples << 1; const int size = snd.samples << 1;
int pos; int pos;
int wrapped; int wrapped;
(void)userdata; (void)userdata;
(void)additional_amount; (void)additional_amount;
pos = dma.samplepos << 1; pos = snd.samplepos << 1;
if( pos >= size ) if( pos >= size )
pos = dma.samplepos = 0; pos = snd.samplepos = 0;
wrapped = pos + len - size; wrapped = pos + len - size;
if( wrapped < 0 ) if( wrapped < 0 )
{ {
SDL_PutAudioStreamData( stream, dma.buffer + pos, len ); SDL_PutAudioStreamData( stream, snd.buffer + pos, len );
dma.samplepos += len >> 1; snd.samplepos += len >> 1;
} }
else else
{ {
int remaining = size - pos; int remaining = size - pos;
SDL_PutAudioStreamData( stream, dma.buffer + pos, remaining ); SDL_PutAudioStreamData( stream, snd.buffer + pos, remaining );
SDL_PutAudioStreamData( stream, dma.buffer, wrapped ); SDL_PutAudioStreamData( stream, snd.buffer, wrapped );
dma.samplepos = wrapped >> 1; snd.samplepos = wrapped >> 1;
} }
if( dma.samplepos >= size ) if( snd.samplepos >= size )
dma.samplepos = 0; snd.samplepos = 0;
} }
/* /*
@@ -122,18 +122,18 @@ qboolean SNDDMA_Init( void )
return false; return false;
} }
dma.format.speed = SOUND_DMA_SPEED; snd.format.speed = SOUND_DMA_SPEED;
dma.format.channels = 2; snd.format.channels = 2;
dma.format.width = 2; snd.format.width = 2;
int samplecount = s_samplecount.value; int samplecount = s_samplecount.value;
if( !samplecount ) if( !samplecount )
samplecount = 0x8000; samplecount = 0x8000;
dma.samples = samplecount * dma.format.channels; snd.samples = samplecount * snd.format.channels;
dma.buffer = Mem_Calloc( sndpool, dma.samples * dma.format.width ); snd.buffer = Mem_Calloc( sndpool, snd.samples * snd.format.width );
dma.samplepos = 0; snd.samplepos = 0;
dma.initialized = true; snd.initialized = true;
Q_snprintf( sdl_backend_name, sizeof( sdl_backend_name ), "SDL3 (%s)", SDL_GetCurrentAudioDriver( )); Q_snprintf( sdl_backend_name, sizeof( sdl_backend_name ), "SDL3 (%s)", SDL_GetCurrentAudioDriver( ));
dma.backendName = sdl_backend_name; snd.backend_name = sdl_backend_name;
Con_Printf( "Using audio driver: %s @ %d Hz\n", sdl_backend_name, SOUND_DMA_SPEED ); Con_Printf( "Using audio driver: %s @ %d Hz\n", sdl_backend_name, SOUND_DMA_SPEED );
@@ -178,7 +178,7 @@ Reset the sound device for exiting
void SNDDMA_Shutdown( void ) void SNDDMA_Shutdown( void )
{ {
Con_Printf( "Shutting down audio.\n" ); Con_Printf( "Shutting down audio.\n" );
dma.initialized = false; snd.initialized = false;
if( out_stream ) if( out_stream )
{ {
@@ -189,10 +189,10 @@ void SNDDMA_Shutdown( void )
SDL_QuitSubSystem( SDL_INIT_AUDIO ); SDL_QuitSubSystem( SDL_INIT_AUDIO );
if( dma.buffer ) if( snd.buffer )
{ {
Mem_Free( dma.buffer ); Mem_Free( snd.buffer );
dma.buffer = NULL; snd.buffer = NULL;
} }
} }
@@ -206,7 +206,7 @@ between a deactivate and an activate.
*/ */
void SNDDMA_Activate( qboolean active ) void SNDDMA_Activate( qboolean active )
{ {
if( !dma.initialized ) if( !snd.initialized )
return; return;
if( active ) if( active )
+5 -6
View File
@@ -30,8 +30,6 @@ so it can unlock and free the data block after it has been played.
======================================================================= =======================================================================
*/ */
dma_t dma;
void S_Activate( qboolean active ) void S_Activate( qboolean active )
{ {
} }
@@ -86,11 +84,12 @@ Reset the sound device for exiting
void SNDDMA_Shutdown( void ) void SNDDMA_Shutdown( void )
{ {
Con_Printf("Shutting down audio.\n"); Con_Printf("Shutting down audio.\n");
dma.initialized = false; snd.initialized = false;
if (dma.buffer) { if( snd.buffer )
Z_Free(dma.buffer); {
dma.buffer = NULL; Mem_Free( snd.buffer );
snd.buffer = NULL;
} }
} }
+6
View File
@@ -1284,6 +1284,12 @@ static int GAME_EXPORT pfnPrecacheModel( const char *s )
qboolean optional = false; qboolean optional = false;
int i; int i;
if( COM_StringEmptyOrNULL( s ))
{
Host_Error( "%s: NULL pointer or empty string as model name\n", __func__ );
return 0;
}
if( *s == '!' ) if( *s == '!' )
{ {
optional = true; optional = true;
+3 -6
View File
@@ -1518,7 +1518,6 @@ static qboolean SV_RecursiveLightPoint( model_t *model, mnode_t *node, const vec
float front, back, frac; float front, back, frac;
int i, side; int i, side;
vec3_t mid; vec3_t mid;
mnode_t *children[2];
int numsurfaces, firstsurface; int numsurfaces, firstsurface;
// didn't hit anything // didn't hit anything
@@ -1529,18 +1528,16 @@ static qboolean SV_RecursiveLightPoint( model_t *model, mnode_t *node, const vec
front = PlaneDiff( start, node->plane ); front = PlaneDiff( start, node->plane );
back = PlaneDiff( end, node->plane ); back = PlaneDiff( end, node->plane );
node_children( children, node, model );
side = front < 0.0f; side = front < 0.0f;
if(( back < 0.0f ) == side ) if(( back < 0.0f ) == side )
return SV_RecursiveLightPoint( model, children[side], start, end, point_color ); return SV_RecursiveLightPoint( model, node_child( node, side, model ), start, end, point_color );
frac = front / ( front - back ); frac = front / ( front - back );
VectorLerp( start, frac, end, mid ); VectorLerp( start, frac, end, mid );
// co down front side // co down front side
if( SV_RecursiveLightPoint( model, children[side], start, mid, point_color )) if( SV_RecursiveLightPoint( model, node_child( node, side, model ), start, mid, point_color ))
return true; // hit something return true; // hit something
if(( back < 0.0f ) == side ) if(( back < 0.0f ) == side )
@@ -1602,7 +1599,7 @@ static qboolean SV_RecursiveLightPoint( model_t *model, mnode_t *node, const vec
} }
// go down back side // go down back side
return SV_RecursiveLightPoint( model, children[!side], mid, end, point_color ); return SV_RecursiveLightPoint( model, node_child( node, !side, model ), mid, end, point_color );
} }
/* /*
+15 -13
View File
@@ -747,6 +747,7 @@ static void FS_InitGameInfo( gameinfo_t *GameInfo, const char *gamedir, qboolean
if( quake ) if( quake )
{ {
Q_strncpy( GameInfo->basedir, "id1", sizeof( GameInfo->basedir )); Q_strncpy( GameInfo->basedir, "id1", sizeof( GameInfo->basedir ));
Q_strncpy( GameInfo->falldir, "qwrap", sizeof( GameInfo->falldir ));
Q_strncpy( GameInfo->title, gamedir, sizeof( GameInfo->title )); Q_strncpy( GameInfo->title, gamedir, sizeof( GameInfo->title ));
Q_strncpy( GameInfo->startmap, "start", sizeof( GameInfo->startmap )); Q_strncpy( GameInfo->startmap, "start", sizeof( GameInfo->startmap ));
Q_strncpy( GameInfo->dll_path, "bin", sizeof( GameInfo->dll_path )); Q_strncpy( GameInfo->dll_path, "bin", sizeof( GameInfo->dll_path ));
@@ -1123,27 +1124,28 @@ static qboolean FS_CheckForQuakeGameDir( const char *gamedir )
{ {
// if directory contain quake.rc or progs.dat it's 100% quake gamedir // if directory contain quake.rc or progs.dat it's 100% quake gamedir
// quake mods probably always archived, so check pak0.pak too // quake mods probably always archived, so check pak0.pak too
const char *files[] = { "progs.dat", "quake.rc" }; const char *files[] = { "pak0.pak", "PAK0.PAK", "progs.dat", "quake.rc" };
char buf[MAX_SYSPATH];
int i; int i;
// try to read pak0.pak first, most quake mods are archived
if( Q_snprintf( buf, sizeof( buf ), "%s/pak0.pak", gamedir ) > 0 )
{
if( FS_SysFileExists( buf ))
{
if( FS_CheckForQuakePak( buf, files, sizeof( files ) / sizeof( files[0] )))
return true;
}
}
// search it in the filesystem // search it in the filesystem
for( i = 0; i < sizeof( files ) / sizeof( files[0] ); i++ ) for( i = 0; i < sizeof( files ) / sizeof( files[0] ); i++ )
{ {
char buf[MAX_SYSPATH];
if( Q_snprintf( buf, sizeof( buf ), "%s/%s", gamedir, files[i] ) > 0 ) if( Q_snprintf( buf, sizeof( buf ), "%s/%s", gamedir, files[i] ) > 0 )
{ {
if( FS_SysFileExists( buf )) if( !FS_SysFileExists( buf ))
continue;
if( !Q_stricmp( COM_FileExtension( buf ), "pak" ))
{
if( FS_CheckForQuakePak( buf, &files[2], sizeof( files ) / sizeof( files[0] ) - 2 ))
return true;
}
else
{
return true; return true;
}
} }
} }
-3
View File
@@ -27,9 +27,6 @@ extern fs_globals_t *FI;
#define FS_Gamedir() GI->gamefolder #define FS_Gamedir() GI->gamefolder
#define FS_Title() GI->title #define FS_Title() GI->title
#define FS_InitStdio (*g_fsapi.InitStdio)
#define FS_ShutdownStdio (*g_fsapi.ShutdownStdio)
// search path utils // search path utils
#define FS_Rescan (*g_fsapi.Rescan) #define FS_Rescan (*g_fsapi.Rescan)
#define FS_ClearSearchPath (*g_fsapi.ClearSearchPath) #define FS_ClearSearchPath (*g_fsapi.ClearSearchPath)
+1 -4
View File
@@ -337,7 +337,6 @@ Mod_CreateSkinData
static rgbdata_t *Mod_CreateSkinData( model_t *mod, const byte *data, int width, int height ) static rgbdata_t *Mod_CreateSkinData( model_t *mod, const byte *data, int width, int height )
{ {
static rgbdata_t skin; static rgbdata_t skin;
char name[MAX_QPATH];
int i; int i;
skin.width = width; skin.width = width;
@@ -363,10 +362,8 @@ static rgbdata_t *Mod_CreateSkinData( model_t *mod, const byte *data, int width,
} }
} }
COM_FileBase( mod->name, name, sizeof( name ));
// for alias models only player can have remap textures // for alias models only player can have remap textures
if( mod != NULL && !Q_stricmp( name, "player" )) if( mod != NULL && !Q_stricmp( mod->name, "player" ))
{ {
texture_t *tx = NULL; texture_t *tx = NULL;
int i, size; int i, size;
+1 -1
View File
@@ -86,7 +86,7 @@ static qboolean Mod_LooksLikeWaterTexture( const char *name )
if(( name[0] == '*' && Q_stricmp( name, REF_DEFAULT_TEXTURE )) || name[0] == '!' ) if(( name[0] == '*' && Q_stricmp( name, REF_DEFAULT_TEXTURE )) || name[0] == '!' )
return true; return true;
if( !ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE )) if( !FBitSet( gp_host->features, ENGINE_QUAKE_COMPATIBLE ))
{ {
if( !Q_strncmp( name, "water", 5 ) || !Q_strnicmp( name, "laser", 5 )) if( !Q_strncmp( name, "water", 5 ) || !Q_strnicmp( name, "laser", 5 ))
return true; return true;
+20 -33
View File
@@ -67,20 +67,20 @@ int R_CullSurface( const msurface_t *surf, const gl_frustum_t *frustum, uint cli
{ {
cl_entity_t *e = RI.currententity; cl_entity_t *e = RI.currententity;
if( !e || !surf || !surf->texinfo || !surf->texinfo->texture ) if( surf->visframe != tr.framecount && e == CL_GetEntityByIndex( 0 ))
return CULL_OTHER;
if( r_nocull.value )
return CULL_VISIBLE;
// world surfaces can be culled by vis frame too
if( e == CL_GetEntityByIndex( 0 ) && surf->visframe != tr.framecount )
return CULL_VISFRAME; return CULL_VISFRAME;
// only static ents can be culled by frustum if( unlikely( !surf->texinfo || !surf->texinfo->texture ))
if( !R_StaticEntity( e )) frustum = NULL; return CULL_OTHER;
if( !VectorIsNull( surf->plane->normal )) if( unlikely( r_nocull.value ))
return CULL_VISIBLE;
// only static ents can be culled by frustum
if( !R_StaticEntity( e ))
frustum = NULL;
if( glState.faceCull != GL_NONE && !VectorIsNull( surf->plane->normal ))
{ {
float dist; float dist;
@@ -95,35 +95,22 @@ int R_CullSurface( const msurface_t *surf, const gl_frustum_t *frustum, uint cli
} }
else dist = PlaneDiff( tr.modelorg, surf->plane ); else dist = PlaneDiff( tr.modelorg, surf->plane );
if( FBitSet( surf->flags, SURF_PLANEBACK ))
dist = -dist;
if( glState.faceCull == GL_FRONT ) if( glState.faceCull == GL_FRONT )
{ {
if( FBitSet( surf->flags, SURF_PLANEBACK )) if( dist <= BACKFACE_EPSILON )
{ return CULL_BACKSIDE;
if( dist >= -BACKFACE_EPSILON )
return CULL_BACKSIDE; // wrong side
}
else
{
if( dist <= BACKFACE_EPSILON )
return CULL_BACKSIDE; // wrong side
}
} }
else if( glState.faceCull == GL_BACK ) else // if( glState.faceCull == GL_BACK )
{ {
if( FBitSet( surf->flags, SURF_PLANEBACK )) if( dist >= -BACKFACE_EPSILON )
{ return CULL_BACKSIDE;
if( dist <= BACKFACE_EPSILON )
return CULL_BACKSIDE; // wrong side
}
else
{
if( dist >= -BACKFACE_EPSILON )
return CULL_BACKSIDE; // wrong side
}
} }
} }
if( frustum && GL_FrustumCullBox( frustum, surf->info->mins, surf->info->maxs, clipflags )) if( frustum && clipflags && GL_FrustumCullBox( frustum, surf->info->mins, surf->info->maxs, clipflags ))
return CULL_FRUSTUM; return CULL_FRUSTUM;
return CULL_VISIBLE; return CULL_VISIBLE;
+6 -18
View File
@@ -697,11 +697,8 @@ static void R_DecalNodeSurfaces( model_t *model, mnode_t *node, decalinfo_t *dec
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
static void R_DecalNode( model_t *model, mnode_t *node, decalinfo_t *decalinfo ) static void R_DecalNode( model_t *model, mnode_t *node, decalinfo_t *decalinfo )
{ {
mplane_t *splitplane; mplane_t *splitplane;
float dist; float dist;
mnode_t *children[2];
Assert( node != NULL );
if( node->contents < 0 ) if( node->contents < 0 )
{ {
@@ -711,31 +708,22 @@ static void R_DecalNode( model_t *model, mnode_t *node, decalinfo_t *decalinfo )
splitplane = node->plane; splitplane = node->plane;
dist = DotProduct( decalinfo->m_Position, splitplane->normal ) - splitplane->dist; dist = DotProduct( decalinfo->m_Position, splitplane->normal ) - splitplane->dist;
node_children( children, node, model );
// This is arbitrarily set to 10 right now. In an ideal world we'd have the
// exact surface but we don't so, this tells me which planes are "sort of
// close" to the gunshot -- the gunshot is actually 4 units in front of the
// wall (see dlls\weapons.cpp). We also need to check to see if the decal
// actually intersects the texture space of the surface, as this method tags
// parallel surfaces in the same node always.
// JAY: This still tags faces that aren't correct at edges because we don't
// have a surface normal
if( dist > decalinfo->m_Size ) if( dist > decalinfo->m_Size )
{ {
R_DecalNode( model, children[0], decalinfo ); R_DecalNode( model, node_child( node, 0, model ), decalinfo );
} }
else if( dist < -decalinfo->m_Size ) else if( dist < -decalinfo->m_Size )
{ {
R_DecalNode( model, children[1], decalinfo ); R_DecalNode( model, node_child( node, 1, model ), decalinfo );
} }
else else
{ {
if( dist < DECAL_DISTANCE && dist > -DECAL_DISTANCE ) if( dist < DECAL_DISTANCE && dist > -DECAL_DISTANCE )
R_DecalNodeSurfaces( model, node, decalinfo ); R_DecalNodeSurfaces( model, node, decalinfo );
R_DecalNode( model, children[0], decalinfo ); R_DecalNode( model, node_child( node, 0, model ), decalinfo );
R_DecalNode( model, children[1], decalinfo ); R_DecalNode( model, node_child( node, 1, model ), decalinfo );
} }
} }
+8 -10
View File
@@ -99,15 +99,14 @@ void GL_FrustumInitOrtho( gl_frustum_t *out, float xLeft, float xRight, float yT
// cull methods // cull methods
qboolean GL_FrustumCullBox( const gl_frustum_t *out, const vec3_t mins, const vec3_t maxs, int userClipFlags ) qboolean GL_FrustumCullBox( const gl_frustum_t *out, const vec3_t mins, const vec3_t maxs, int userClipFlags )
{ {
int iClipFlags; int iClipFlags = userClipFlags != 0 ? userClipFlags : out->clipFlags;
int i, bit; int i, bit;
if( r_nocull.value ) if( unlikely( r_nocull.value ))
return false; return false;
if( userClipFlags != 0 ) if( !iClipFlags )
iClipFlags = userClipFlags; return false;
else iClipFlags = out->clipFlags;
for( i = FRUSTUM_PLANES, bit = 1; i > 0; i--, bit <<= 1 ) for( i = FRUSTUM_PLANES, bit = 1; i > 0; i--, bit <<= 1 )
{ {
@@ -160,15 +159,14 @@ qboolean GL_FrustumCullBox( const gl_frustum_t *out, const vec3_t mins, const ve
qboolean GL_FrustumCullSphere( const gl_frustum_t *out, const vec3_t center, float radius, int userClipFlags ) qboolean GL_FrustumCullSphere( const gl_frustum_t *out, const vec3_t center, float radius, int userClipFlags )
{ {
int iClipFlags; int iClipFlags = userClipFlags != 0 ? userClipFlags : out->clipFlags;
int i, bit; int i, bit;
if( r_nocull.value ) if( unlikely( r_nocull.value ))
return false; return false;
if( userClipFlags != 0 ) if( !iClipFlags )
iClipFlags = userClipFlags; return false;
else iClipFlags = out->clipFlags;
for( i = FRUSTUM_PLANES, bit = 1; i > 0; i--, bit <<= 1 ) for( i = FRUSTUM_PLANES, bit = 1; i > 0; i--, bit <<= 1 )
{ {
+7 -2
View File
@@ -46,7 +46,12 @@ acess to array elem
*/ */
gl_texture_t *R_GetTexture( unsigned int texnum ) gl_texture_t *R_GetTexture( unsigned int texnum )
{ {
Assert( texnum < MAX_TEXTURES ); if( texnum >= MAX_TEXTURES )
{
gEngfuncs.Host_Error( "%s: texnum (%d) >= MAX_TEXTURES (%d)", __func__, texnum, MAX_TEXTURES );
texnum = 0;
}
return &gl_textures[texnum]; return &gl_textures[texnum];
} }
@@ -837,7 +842,7 @@ static byte *GL_ApplyFilter( const byte *source, int width, int height )
byte *out = (byte *)source; byte *out = (byte *)source;
int i; int i;
if( ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE ) || glConfig.max_multisamples > 1 ) if( FBitSet( gp_host->features, ENGINE_QUAKE_COMPATIBLE ) || glConfig.max_multisamples > 1 )
return in; return in;
for( i = 0; source && i < width * height; i++, in += 4 ) for( i = 0; source && i < width * height; i++, in += 4 )
+2 -1
View File
@@ -249,6 +249,7 @@ typedef struct
vec3_t modelorg; // relative to viewpoint vec3_t modelorg; // relative to viewpoint
// get from engine // get from engine
model_t *worldmodel;
world_static_t *world; world_static_t *world;
cl_entity_t *entities; cl_entity_t *entities;
movevars_t *movevars; movevars_t *movevars;
@@ -770,7 +771,7 @@ static inline int GL_MaxTextureUnits( void )
return Q_min( glConfig.max_texture_units, MAX_TEXTURE_UNITS ); return Q_min( glConfig.max_texture_units, MAX_TEXTURE_UNITS );
} }
#define WORLDMODEL (gp_cl->models[1]) #define WORLDMODEL (tr.worldmodel)
// //
// renderer cvars // renderer cvars
+11 -14
View File
@@ -105,7 +105,6 @@ void R_MarkLights( const dlight_t *light, int bit, const mnode_t *node )
const float maxdist = light->radius * light->radius; const float maxdist = light->radius * light->radius;
float dist; float dist;
int i; int i;
mnode_t *children[2];
int firstsurface, numsurfaces; int firstsurface, numsurfaces;
start: start:
@@ -115,25 +114,25 @@ start:
dist = PlaneDiff( light->origin, node->plane ); dist = PlaneDiff( light->origin, node->plane );
node_children( children, node, RI.currentmodel );
if( dist > virtual_radius ) if( dist > virtual_radius )
{ {
node = children[0]; node = node_child( node, 0, RI.currentmodel );
goto start; goto start;
} }
if( dist < -virtual_radius ) if( dist < -virtual_radius )
{ {
node = children[1]; node = node_child( node, 1, RI.currentmodel );
goto start; goto start;
} }
const float dist_sq = dist * dist;
// mark the polygons // mark the polygons
firstsurface = node_firstsurface( node, RI.currentmodel ); firstsurface = node_firstsurface( node, RI.currentmodel );
numsurfaces = node_numsurfaces( node, RI.currentmodel ); numsurfaces = node_numsurfaces( node, RI.currentmodel );
for( i = 0; i < numsurfaces; i++ ) for( i = 0; i < numsurfaces && dist_sq < maxdist; i++ )
{ {
vec3_t impact; vec3_t impact;
float s, t, l; float s, t, l;
@@ -160,7 +159,7 @@ start:
t = bound( 0, t, info->lightextents[1] ); t = bound( 0, t, info->lightextents[1] );
t = l - t; t = l - t;
if( s * s + t * t + dist * dist >= maxdist ) if( s * s + t * t + dist_sq >= maxdist )
continue; continue;
if( surf->dlightframe != tr.dlightframecount ) if( surf->dlightframe != tr.dlightframecount )
@@ -171,8 +170,8 @@ start:
else surf->dlightbits |= bit; else surf->dlightbits |= bit;
} }
R_MarkLights( light, bit, children[0] ); R_MarkLights( light, bit, node_child( node, 0, RI.currentmodel ));
R_MarkLights( light, bit, children[1] ); R_MarkLights( light, bit, node_child( node, 1, RI.currentmodel ));
} }
/* /*
@@ -236,7 +235,6 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f,
mtexinfo_t *tex; mtexinfo_t *tex;
matrix3x4 tbn; matrix3x4 tbn;
vec3_t mid; vec3_t mid;
mnode_t *children[2];
int firstsurface, numsurfaces; int firstsurface, numsurfaces;
// didn't hit anything // didn't hit anything
@@ -246,7 +244,6 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f,
return false; return false;
} }
node_children( children, node, model );
firstsurface = node_firstsurface( node, model ); firstsurface = node_firstsurface( node, model );
numsurfaces = node_numsurfaces( node, model ); numsurfaces = node_numsurfaces( node, model );
@@ -256,7 +253,7 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f,
side = front < 0; side = front < 0;
if(( back < 0 ) == side ) if(( back < 0 ) == side )
return R_RecursiveLightPoint( model, children[side], p1f, p2f, cv, start, end ); return R_RecursiveLightPoint( model, node_child( node, side, model ), p1f, p2f, cv, start, end );
frac = front / ( front - back ); frac = front / ( front - back );
@@ -264,7 +261,7 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f,
midf = p1f + ( p2f - p1f ) * frac; midf = p1f + ( p2f - p1f ) * frac;
// co down front side // co down front side
if( R_RecursiveLightPoint( model, children[side], p1f, midf, cv, start, mid )) if( R_RecursiveLightPoint( model, node_child( node, side, model ), p1f, midf, cv, start, mid ))
return true; // hit something return true; // hit something
if(( back < 0 ) == side ) if(( back < 0 ) == side )
@@ -366,7 +363,7 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f,
} }
// go down back side // go down back side
return R_RecursiveLightPoint( model, children[!side], midf, p2f, cv, mid, end ); return R_RecursiveLightPoint( model, node_child( node, !side, model ), midf, p2f, cv, mid, end );
} }
/* /*
+11 -12
View File
@@ -345,7 +345,7 @@ void R_SetupFrustum( void )
{ {
const ref_overview_t *ov = gEngfuncs.GetOverviewParms(); const ref_overview_t *ov = gEngfuncs.GetOverviewParms();
if( RP_NORMALPASS() && ( ENGINE_GET_PARM( PARM_WATER_LEVEL ) >= 3 ) && ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE )) if( RP_NORMALPASS() && FBitSet( gp_host->features, ENGINE_QUAKE_COMPATIBLE ) && ( ENGINE_GET_PARM( PARM_WATER_LEVEL ) >= 3 ))
{ {
RI.fov_x = atan( tan( DEG2RAD( RI.fov_x ) / 2 ) * ( 0.97f + sin( gp_cl->time * 1.5f ) * 0.03f )) * 2 / (M_PI_F / 180.0f); RI.fov_x = atan( tan( DEG2RAD( RI.fov_x ) / 2 ) * ( 0.97f + sin( gp_cl->time * 1.5f ) * 0.03f )) * 2 / (M_PI_F / 180.0f);
RI.fov_y = atan( tan( DEG2RAD( RI.fov_y ) / 2 ) * ( 1.03f - sin( gp_cl->time * 1.5f ) * 0.03f )) * 2 / (M_PI_F / 180.0f); RI.fov_y = atan( tan( DEG2RAD( RI.fov_y ) / 2 ) * ( 1.03f - sin( gp_cl->time * 1.5f ) * 0.03f )) * 2 / (M_PI_F / 180.0f);
@@ -617,7 +617,6 @@ watertexture to grab fog values from it
static gl_texture_t *R_RecursiveFindWaterTexture( const mnode_t *node, const mnode_t *ignore, qboolean down ) static gl_texture_t *R_RecursiveFindWaterTexture( const mnode_t *node, const mnode_t *ignore, qboolean down )
{ {
gl_texture_t *tex = NULL; gl_texture_t *tex = NULL;
mnode_t *children[2];
// assure the initial node is not null // assure the initial node is not null
// we could check it here, but we would rather check it // we could check it here, but we would rather check it
@@ -655,18 +654,20 @@ static gl_texture_t *R_RecursiveFindWaterTexture( const mnode_t *node, const mno
// this is a regular node // this is a regular node
// traverse children // traverse children
node_children( children, node, WORLDMODEL ); mnode_t *child = node_child( node, 0, WORLDMODEL );
if( children[0] && ( children[0] != ignore )) if( child && ( child != ignore ))
{ {
tex = R_RecursiveFindWaterTexture( children[0], node, true ); tex = R_RecursiveFindWaterTexture( child, node, true );
if( tex ) return tex; if( tex ) return tex;
} }
if( children[1] && ( children[1] != ignore )) child = node_child( node, 1, WORLDMODEL );
if( child && ( child != ignore ))
{ {
tex = R_RecursiveFindWaterTexture( children[1], node, true ); tex = R_RecursiveFindWaterTexture( child, node, true );
if( tex ) return tex; if( tex ) return tex;
} }
// for down recursion, return immediately // for down recursion, return immediately
@@ -696,7 +697,7 @@ static void R_CheckFog( void )
int i, cnt, count; int i, cnt, count;
// quake global fog // quake global fog
if( ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE )) if( FBitSet( gp_host->features, ENGINE_QUAKE_COMPATIBLE ))
{ {
if( !tr.movevars->fog_settings ) if( !tr.movevars->fog_settings )
{ {
@@ -824,9 +825,7 @@ void R_DrawFog( void )
return; return;
pglEnable( GL_FOG ); pglEnable( GL_FOG );
if( ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE )) pglFogi( GL_FOG_MODE, FBitSet( gp_host->features, ENGINE_QUAKE_COMPATIBLE ) ? GL_EXP2 : GL_EXP );
pglFogi( GL_FOG_MODE, GL_EXP2 );
else pglFogi( GL_FOG_MODE, GL_EXP );
pglFogf( GL_FOG_DENSITY, RI.fogDensity ); pglFogf( GL_FOG_DENSITY, RI.fogDensity );
pglFogfv( GL_FOG_COLOR, RI.fogColor ); pglFogfv( GL_FOG_COLOR, RI.fogColor );
pglHint( GL_FOG_HINT, GL_NICEST ); pglHint( GL_FOG_HINT, GL_NICEST );
+2
View File
@@ -108,6 +108,8 @@ void R_NewMap( void )
texture_t *tx; texture_t *tx;
int i; int i;
tr.worldmodel = gp_cl->models[1];
R_ClearDecals(); // clear all level decals R_ClearDecals(); // clear all level decals
R_StudioResetPlayerModels(); R_StudioResetPlayerModels();
+82 -109
View File
@@ -20,6 +20,7 @@ GNU General Public License for more details.
typedef struct typedef struct
{ {
int allocated[BLOCK_SIZE_MAX]; int allocated[BLOCK_SIZE_MAX];
int max_height; // maximum height currently in use in the block
int current_lightmap_texture; int current_lightmap_texture;
msurface_t *dynamic_surfaces; msurface_t *dynamic_surfaces;
msurface_t *lightmap_surfaces[MAX_LIGHTMAPS]; msurface_t *lightmap_surfaces[MAX_LIGHTMAPS];
@@ -653,6 +654,7 @@ static void R_SetCacheState( msurface_t *surf )
static void LM_InitBlock( void ) static void LM_InitBlock( void )
{ {
memset( gl_lms.allocated, 0, sizeof( gl_lms.allocated )); memset( gl_lms.allocated, 0, sizeof( gl_lms.allocated ));
gl_lms.max_height = 0;
} }
static int LM_AllocBlock( int w, int h, int *x, int *y ) static int LM_AllocBlock( int w, int h, int *x, int *y )
@@ -662,7 +664,7 @@ static int LM_AllocBlock( int w, int h, int *x, int *y )
best = BLOCK_SIZE; best = BLOCK_SIZE;
for( i = 0; i < BLOCK_SIZE - w; i++ ) for( i = 0; i < BLOCK_SIZE - w; )
{ {
best2 = 0; best2 = 0;
@@ -679,6 +681,14 @@ static int LM_AllocBlock( int w, int h, int *x, int *y )
// this is a valid spot // this is a valid spot
*x = i; *x = i;
*y = best = best2; *y = best = best2;
if( best == 0 )
break; // height 0 is optimal, can't do better
i++;
}
else
{
// allocated[i+j] was too tall — no position in [i, i+j] can work
i += j + 1;
} }
} }
@@ -688,20 +698,15 @@ static int LM_AllocBlock( int w, int h, int *x, int *y )
for( i = 0; i < w; i++ ) for( i = 0; i < w; i++ )
gl_lms.allocated[*x + i] = best + h; gl_lms.allocated[*x + i] = best + h;
if( best + h > gl_lms.max_height )
gl_lms.max_height = best + h;
return true; return true;
} }
static void LM_UploadDynamicBlock( void ) static void LM_UploadDynamicBlock( void )
{ {
int height = 0, i; pglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, BLOCK_SIZE, gl_lms.max_height, GL_RGBA, GL_UNSIGNED_BYTE, gl_lms.lightmap_buffer );
for( i = 0; i < BLOCK_SIZE; i++ )
{
if( gl_lms.allocated[i] > height )
height = gl_lms.allocated[i];
}
pglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, BLOCK_SIZE, height, GL_RGBA, GL_UNSIGNED_BYTE, gl_lms.lightmap_buffer );
} }
static void LM_UploadBlock( qboolean dynamic ) static void LM_UploadBlock( qboolean dynamic )
@@ -888,7 +893,7 @@ static void DrawGLPoly( glpoly2_t *p, float xScale, float yScale )
float flRate, flAngle, sy, cy; float flRate, flAngle, sy, cy;
gl_texture_t *texture; gl_texture_t *texture;
if( e == CL_GetEntityByIndex( 0 ) && ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE )) if( e == CL_GetEntityByIndex( 0 ) && FBitSet( gp_host->features, ENGINE_QUAKE_COMPATIBLE ))
{ {
// same as doom speed // same as doom speed
flConveyorSpeed = -35.0f; flConveyorSpeed = -35.0f;
@@ -1290,70 +1295,59 @@ static void R_RenderDecalsForSurface( msurface_t *fa, int cull_type )
static qboolean R_CheckLightMap( msurface_t *fa ) static qboolean R_CheckLightMap( msurface_t *fa )
{ {
qboolean is_dynamic = false;
int maps; int maps;
// check for lightmap modification if( unlikely( !r_dynamic->value ))
return false;
if( fa->dlightframe == tr.framecount )
return true; // dlighted surfaces are always dynamic
// check for light styles
for( maps = 0; maps < MAXLIGHTMAPS && fa->styles[maps] != 255; maps++ ) for( maps = 0; maps < MAXLIGHTMAPS && fa->styles[maps] != 255; maps++ )
{ {
if( tr.lightstylevalue[fa->styles[maps]] != fa->cached_light[maps] ) if( tr.lightstylevalue[fa->styles[maps]] == fa->cached_light[maps] )
goto dynamic; continue;
}
// dynamic this frame or dynamic previously
if( fa->dlightframe == tr.framecount )
{
dynamic:
// NOTE: at this point we have only valid textures
if( r_dynamic->value )
is_dynamic = true;
}
if( is_dynamic )
{
const int style = fa->styles[maps]; const int style = fa->styles[maps];
if( maps < MAXLIGHTMAPS && ( style >= 32 || style == 0 || style == 20 ) && fa->dlightframe != tr.framecount ) // flickering light styles can go to dynamic chain
{ if( !( style >= 32 || style == 0 || style == 20 ))
byte temp[132*132*4]; return true;
mextrasurf_t *info = fa->info;
int sample_size;
int smax, tmax;
sample_size = gEngfuncs.Mod_SampleSizeForFace( fa ); byte temp[132*132*4];
smax = ( info->lightextents[0] / sample_size ) + 1; mextrasurf_t *info = fa->info;
tmax = ( info->lightextents[1] / sample_size ) + 1; int sample_size = gEngfuncs.Mod_SampleSizeForFace( fa );
int smax = ( info->lightextents[0] / sample_size ) + 1;
int tmax = ( info->lightextents[1] / sample_size ) + 1;
if( smax < 132 && tmax < 132 ) if( smax < 132 && tmax < 132 )
R_BuildLightMap( fa, temp, smax * 4, true ); R_BuildLightMap( fa, temp, smax * 4, true );
else
{
smax = Q_min( smax, 132 );
tmax = Q_min( tmax, 132 );
memset( temp, 255, sizeof( temp ));
//Host_MapDesignError( "%s: bad surface extents: %d %d", __func__, fa->extents[0], fa->extents[1] );
}
R_SetCacheState( fa );
#if XASH_WES
GL_Bind( XASH_TEXTURE1, tr.lightmapTextures[fa->lightmaptexturenum] );
pglTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE );
#else
GL_Bind( XASH_TEXTURE0, tr.lightmapTextures[fa->lightmaptexturenum] );
#endif
pglTexSubImage2D( GL_TEXTURE_2D, 0, fa->light_s, fa->light_t, smax, tmax, GL_RGBA, GL_UNSIGNED_BYTE, temp );
#if XASH_WES
GL_SelectTexture( XASH_TEXTURE0 );
#endif
}
else else
return true; // add to dynamic chain {
smax = Q_min( smax, 132 );
tmax = Q_min( tmax, 132 );
memset( temp, 255, sizeof( temp ));
//Host_MapDesignError( "%s: bad surface extents: %d %d", __func__, fa->extents[0], fa->extents[1] );
}
R_SetCacheState( fa );
#if XASH_WES
GL_Bind( XASH_TEXTURE1, tr.lightmapTextures[fa->lightmaptexturenum] );
pglTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE );
#else
GL_Bind( XASH_TEXTURE0, tr.lightmapTextures[fa->lightmaptexturenum] );
#endif
pglTexSubImage2D( GL_TEXTURE_2D, 0, fa->light_s, fa->light_t, smax, tmax, GL_RGBA, GL_UNSIGNED_BYTE, temp );
#if XASH_WES
GL_SelectTexture( XASH_TEXTURE0 );
#endif
return false;
} }
return false; // updated return false; // no change
} }
static void R_RenderLightmapForSurface( msurface_t *fa ) static void R_RenderLightmapForSurface( msurface_t *fa )
@@ -1461,7 +1455,7 @@ static void R_DrawTextureChains( void )
continue; // draw translucent water later continue; // draw translucent water later
} }
if( ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE ) && FBitSet( s->flags, SURF_TRANSPARENT )) if( FBitSet( gp_host->features, ENGINE_QUAKE_COMPATIBLE ) && FBitSet( s->flags, SURF_TRANSPARENT ))
{ {
R_AddToSeparatePass( &draw_alpha_surfaces, i ); R_AddToSeparatePass( &draw_alpha_surfaces, i );
continue; // draw transparent surfaces later continue; // draw transparent surfaces later
@@ -1642,7 +1636,7 @@ static void R_SetRenderMode( cl_entity_t *e )
case kRenderTransAlpha: case kRenderTransAlpha:
pglEnable( GL_ALPHA_TEST ); pglEnable( GL_ALPHA_TEST );
pglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); pglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
if( ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE )) if( FBitSet( gp_host->features, ENGINE_QUAKE_COMPATIBLE ))
{ {
pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
pglColor4f( 1.0f, 1.0f, 1.0f, tr.blend ); pglColor4f( 1.0f, 1.0f, 1.0f, tr.blend );
@@ -1667,7 +1661,7 @@ static void R_SetRenderMode( cl_entity_t *e )
static int R_SortBrushModelSurfaces( cl_entity_t *e, model_t *clmodel, vec3_t mins ) static int R_SortBrushModelSurfaces( cl_entity_t *e, model_t *clmodel, vec3_t mins )
{ {
qboolean quake_compatible = ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE ); qboolean quake_compatible = FBitSet( gp_host->features, ENGINE_QUAKE_COMPATIBLE ) ? true : false;
int num_sorted = 0; int num_sorted = 0;
for( int i = 0; i < clmodel->nummodelsurfaces; i++ ) for( int i = 0; i < clmodel->nummodelsurfaces; i++ )
@@ -1766,7 +1760,7 @@ void R_DrawBrushModel( cl_entity_t *e )
VectorSubtract( RI.cullorigin, e->origin, tr.modelorg ); VectorSubtract( RI.cullorigin, e->origin, tr.modelorg );
} }
if( ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE ) && FBitSet( clmodel->flags, MODEL_TRANSPARENT )) if( FBitSet( gp_host->features, ENGINE_QUAKE_COMPATIBLE ) && FBitSet( clmodel->flags, MODEL_TRANSPARENT ))
e->curstate.rendermode = kRenderTransAlpha; e->curstate.rendermode = kRenderTransAlpha;
e->visframe = tr.realframecount; // visible e->visframe = tr.realframecount; // visible
@@ -2091,7 +2085,7 @@ void R_GenerateVBO( void )
if( surf->lightmaptexturenum != k ) if( surf->lightmaptexturenum != k )
continue; continue;
if( surf->flags & ( SURF_DRAWSKY | SURF_DRAWTURB | SURF_CONVEYOR | SURF_DRAWTURB_QUADS ) ) if( surf->flags & ( SURF_DRAWSKY | SURF_DRAWTURB | SURF_CONVEYOR | SURF_DRAWTURB_QUADS | SURF_TRANSPARENT ) )
continue; continue;
if( R_TextureAnimation( surf ) != world->textures[j] ) if( R_TextureAnimation( surf ) != world->textures[j] )
@@ -2162,7 +2156,7 @@ void R_GenerateVBO( void )
if( surf->lightmaptexturenum != k ) if( surf->lightmaptexturenum != k )
continue; continue;
if( surf->flags & ( SURF_DRAWSKY | SURF_DRAWTURB | SURF_CONVEYOR | SURF_DRAWTURB_QUADS ) ) if( surf->flags & ( SURF_DRAWSKY | SURF_DRAWTURB | SURF_CONVEYOR | SURF_DRAWTURB_QUADS | SURF_TRANSPARENT ) )
continue; continue;
if( R_TextureAnimation( surf ) != world->textures[j] ) if( R_TextureAnimation( surf ) != world->textures[j] )
@@ -3403,14 +3397,6 @@ R_RecursiveWorldNode
*/ */
static void R_RecursiveWorldNode( mnode_t *node, uint clipflags ) static void R_RecursiveWorldNode( mnode_t *node, uint clipflags )
{ {
int i, clipped;
msurface_t *surf, **mark;
mleaf_t *pleaf;
int c, side;
float dot;
mnode_t *children[2];
int numsurfaces, firstsurface;
loc0: loc0:
if( node->contents == CONTENTS_SOLID ) if( node->contents == CONTENTS_SOLID )
return; // hit a solid leaf return; // hit a solid leaf
@@ -3420,14 +3406,14 @@ loc0:
if( clipflags && !r_nocull.value ) if( clipflags && !r_nocull.value )
{ {
for( i = 0; i < 6; i++ ) for( int i = 0; i < 6; i++ )
{ {
const mplane_t *p = &RI.frustum.planes[i]; const mplane_t *p = &RI.frustum.planes[i];
if( !FBitSet( clipflags, BIT( i ))) if( !FBitSet( clipflags, BIT( i )))
continue; continue;
clipped = BOX_ON_PLANE_SIDE( node->minmaxs, node->minmaxs + 3, p ); int clipped = BOX_ON_PLANE_SIDE( node->minmaxs, node->minmaxs + 3, p );
if( clipped == 2 ) return; if( clipped == 2 ) return;
if( clipped == 1 ) ClearBits( clipflags, BIT( i )); if( clipped == 1 ) ClearBits( clipflags, BIT( i ));
} }
@@ -3436,19 +3422,11 @@ loc0:
// if a leaf node, draw stuff // if a leaf node, draw stuff
if( node->contents < 0 ) if( node->contents < 0 )
{ {
pleaf = (mleaf_t *)node; mleaf_t *pleaf = (mleaf_t *)node;
msurface_t **mark = pleaf->firstmarksurface;
mark = pleaf->firstmarksurface; for( int i = 0; i < pleaf->nummarksurfaces; i++ )
c = pleaf->nummarksurfaces; mark[i]->visframe = tr.framecount;
if( c )
{
do
{
(*mark)->visframe = tr.framecount;
mark++;
} while( --c );
}
// deal with model fragments in this leaf // deal with model fragments in this leaf
if( pleaf->efrags ) if( pleaf->efrags )
@@ -3461,19 +3439,20 @@ loc0:
// node is just a decision point, so go down the apropriate sides // node is just a decision point, so go down the apropriate sides
// find which side of the node we are on // find which side of the node we are on
dot = PlaneDiff( tr.modelorg, node->plane ); float dot = PlaneDiff( tr.modelorg, node->plane );
side = (dot >= 0.0f) ? 0 : 1; int side = (dot >= 0.0f) ? 0 : 1;
// recurse down the children, front side first // recurse down the children, front side first
node_children( children, node, WORLDMODEL ); R_RecursiveWorldNode( node_child( node, side, WORLDMODEL ), clipflags );
R_RecursiveWorldNode( children[side], clipflags );
firstsurface = node_firstsurface( node, WORLDMODEL ); int firstsurface = node_firstsurface( node, WORLDMODEL );
numsurfaces = node_numsurfaces( node, WORLDMODEL ); int numsurfaces = node_numsurfaces( node, WORLDMODEL );
// draw stuff // draw stuff
for( c = numsurfaces, surf = WORLDMODEL->surfaces + firstsurface; c; c--, surf++ ) for( int i = firstsurface; i < firstsurface + numsurfaces; i++ )
{ {
msurface_t *surf = &WORLDMODEL->surfaces[i];
if( R_CullSurface( surf, &RI.frustum, clipflags )) if( R_CullSurface( surf, &RI.frustum, clipflags ))
continue; continue;
@@ -3491,7 +3470,7 @@ loc0:
} }
// recurse down the back side // recurse down the back side
node = children[!side]; node = node_child( node, !side, WORLDMODEL );
goto loc0; goto loc0;
} }
@@ -3567,7 +3546,6 @@ static void R_DrawWorldTopView( mnode_t *node, uint clipflags )
do do
{ {
mnode_t *children[2];
int numsurfaces, firstsurface; int numsurfaces, firstsurface;
if( node->contents == CONTENTS_SOLID ) if( node->contents == CONTENTS_SOLID )
@@ -3625,9 +3603,8 @@ static void R_DrawWorldTopView( mnode_t *node, uint clipflags )
} }
// recurse down both children, we don't care the order... // recurse down both children, we don't care the order...
node_children( children, node, WORLDMODEL ); R_DrawWorldTopView( node_child( node, 0, WORLDMODEL ), clipflags );
R_DrawWorldTopView( children[0], clipflags ); node = node_child( node, 1, WORLDMODEL );
node = children[1];
} while( node ); } while( node );
} }
@@ -3728,15 +3705,11 @@ void R_MarkLeaves( void )
{ {
// merge two leafs that can be a crossed-line contents // merge two leafs that can be a crossed-line contents
if( RI.viewleaf->contents == CONTENTS_EMPTY ) if( RI.viewleaf->contents == CONTENTS_EMPTY )
{
VectorSet( test, RI.pvsorigin[0], RI.pvsorigin[1], RI.pvsorigin[2] - 16.0f ); VectorSet( test, RI.pvsorigin[0], RI.pvsorigin[1], RI.pvsorigin[2] - 16.0f );
leaf = gEngfuncs.Mod_PointInLeaf( test, WORLDMODEL->nodes );
}
else else
{
VectorSet( test, RI.pvsorigin[0], RI.pvsorigin[1], RI.pvsorigin[2] + 16.0f ); VectorSet( test, RI.pvsorigin[0], RI.pvsorigin[1], RI.pvsorigin[2] + 16.0f );
leaf = gEngfuncs.Mod_PointInLeaf( test, WORLDMODEL->nodes );
} leaf = gEngfuncs.Mod_PointInLeaf( test, WORLDMODEL->nodes );
if(( leaf->contents != CONTENTS_SOLID ) && ( RI.viewleaf != leaf )) if(( leaf->contents != CONTENTS_SOLID ) && ( RI.viewleaf != leaf ))
force = true; force = true;
+17 -8
View File
@@ -2340,15 +2340,24 @@ static void R_StudioDrawPoints( void )
pstudionorms = (vec3_t *)((byte *)m_pStudioHeader + m_pSubModel->normindex); pstudionorms = (vec3_t *)((byte *)m_pStudioHeader + m_pSubModel->normindex);
// backface culling for left-handed weapons // backface culling for left-handed weapons
if( R_AllowFlipViewModel( RI.currententity )) //
// there is a bug in GoldSrc that sets backface culling to GL_FRONT
// but doesn't enable OpenGL GL_CULL_FACE. This allows mod developers to disable
// backface culling through TriAPI call
//
// see https://github.com/FWGS/xash3d-fwgs/issues/2517
if( glState.faceCull != GL_NONE )
{ {
tr.fFlipViewModel = true; if( R_AllowFlipViewModel( RI.currententity ))
GL_Cull( GL_NONE ); {
} tr.fFlipViewModel = true;
else GL_Cull( GL_NONE );
{ }
tr.fFlipViewModel = false; else
GL_Cull( GL_FRONT ); {
tr.fFlipViewModel = false;
GL_Cull( GL_FRONT );
}
} }
for( j = 0; j < m_pSubModel->nummesh; j++ ) for( j = 0; j < m_pSubModel->nummesh; j++ )
+4 -6
View File
@@ -359,7 +359,7 @@ void R_DrawSolidClippedSubmodelPolygons( model_t *pmodel, mnode_t *topnode )
for( i = 0; i < numsurfaces; i++, psurf++ ) for( i = 0; i < numsurfaces; i++, psurf++ )
{ {
if( FBitSet( psurf->flags, SURF_DRAWTURB ) && !ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE )) if( FBitSet( psurf->flags, SURF_DRAWTURB ) && !FBitSet( gp_host->features, ENGINE_QUAKE_COMPATIBLE ))
{ {
if( psurf->plane->type != PLANE_Z && !FBitSet( RI.currententity->curstate.effects, EF_WATERSIDES )) if( psurf->plane->type != PLANE_Z && !FBitSet( RI.currententity->curstate.effects, EF_WATERSIDES ))
continue; continue;
@@ -441,7 +441,7 @@ void R_DrawSubmodelPolygons( model_t *pmodel, int clipflags, mnode_t *topnode )
for( i = 0; i < numsurfaces; i++, psurf++ ) for( i = 0; i < numsurfaces; i++, psurf++ )
{ {
if( FBitSet( psurf->flags, SURF_DRAWTURB ) && !ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE )) if( FBitSet( psurf->flags, SURF_DRAWTURB ) && !FBitSet( gp_host->features, ENGINE_QUAKE_COMPATIBLE ))
{ {
if( psurf->plane->type != PLANE_Z && !FBitSet( RI.currententity->curstate.effects, EF_WATERSIDES )) if( psurf->plane->type != PLANE_Z && !FBitSet( RI.currententity->curstate.effects, EF_WATERSIDES ))
continue; continue;
@@ -559,7 +559,6 @@ static void R_RecursiveWorldNode( mnode_t *node, int clipflags )
} }
else else
{ {
mnode_t *children[2];
int firstsurface; int firstsurface;
// node is just a decision point, so go down the apropriate sides // node is just a decision point, so go down the apropriate sides
@@ -589,8 +588,7 @@ static void R_RecursiveWorldNode( mnode_t *node, int clipflags )
side = 1; side = 1;
// recurse down the children, front side first // recurse down the children, front side first
node_children( children, node, WORLDMODEL ); R_RecursiveWorldNode( node_child( node, side, WORLDMODEL ), clipflags );
R_RecursiveWorldNode( children[side], clipflags );
// draw stuff // draw stuff
c = node_numsurfaces( node, WORLDMODEL ); c = node_numsurfaces( node, WORLDMODEL );
@@ -634,7 +632,7 @@ static void R_RecursiveWorldNode( mnode_t *node, int clipflags )
} }
// recurse down the back side // recurse down the back side
R_RecursiveWorldNode( children[!side], clipflags ); R_RecursiveWorldNode( node_child( node, !side, WORLDMODEL ), clipflags );
} }
} }
+5 -17
View File
@@ -705,10 +705,7 @@ static void R_DecalNodeSurfaces( model_t *model, mnode_t *node, decalinfo_t *dec
static void R_DecalNode( model_t *model, mnode_t *node, decalinfo_t *decalinfo ) static void R_DecalNode( model_t *model, mnode_t *node, decalinfo_t *decalinfo )
{ {
mplane_t *splitplane; mplane_t *splitplane;
float dist; float dist;
mnode_t *children[2];
Assert( node != NULL );
if( node->contents < 0 ) if( node->contents < 0 )
{ {
@@ -718,31 +715,22 @@ static void R_DecalNode( model_t *model, mnode_t *node, decalinfo_t *decalinfo )
splitplane = node->plane; splitplane = node->plane;
dist = DotProduct( decalinfo->m_Position, splitplane->normal ) - splitplane->dist; dist = DotProduct( decalinfo->m_Position, splitplane->normal ) - splitplane->dist;
node_children( children, node, model );
// This is arbitrarily set to 10 right now. In an ideal world we'd have the
// exact surface but we don't so, this tells me which planes are "sort of
// close" to the gunshot -- the gunshot is actually 4 units in front of the
// wall (see dlls\weapons.cpp). We also need to check to see if the decal
// actually intersects the texture space of the surface, as this method tags
// parallel surfaces in the same node always.
// JAY: This still tags faces that aren't correct at edges because we don't
// have a surface normal
if( dist > decalinfo->m_Size ) if( dist > decalinfo->m_Size )
{ {
R_DecalNode( model, children[0], decalinfo ); R_DecalNode( model, node_child( node, 0, model ), decalinfo );
} }
else if( dist < -decalinfo->m_Size ) else if( dist < -decalinfo->m_Size )
{ {
R_DecalNode( model, children[1], decalinfo ); R_DecalNode( model, node_child( node, 1, model ), decalinfo );
} }
else else
{ {
if( dist < DECAL_DISTANCE && dist > -DECAL_DISTANCE ) if( dist < DECAL_DISTANCE && dist > -DECAL_DISTANCE )
R_DecalNodeSurfaces( model, node, decalinfo ); R_DecalNodeSurfaces( model, node, decalinfo );
R_DecalNode( model, children[0], decalinfo ); R_DecalNode( model, node_child( node, 0, model ), decalinfo );
R_DecalNode( model, children[1], decalinfo ); R_DecalNode( model, node_child( node, 1, model ), decalinfo );
} }
} }
+7 -11
View File
@@ -107,7 +107,6 @@ void R_MarkLights( dlight_t *light, int bit, mnode_t *node )
float dist; float dist;
msurface_t *surf; msurface_t *surf;
int i; int i;
mnode_t *children[2];
int firstsurface, numsurfaces; int firstsurface, numsurfaces;
if( !node || node->contents < 0 ) if( !node || node->contents < 0 )
@@ -115,18 +114,17 @@ void R_MarkLights( dlight_t *light, int bit, mnode_t *node )
dist = PlaneDiff( light->origin, node->plane ); dist = PlaneDiff( light->origin, node->plane );
node_children( children, node, RI.currentmodel );
firstsurface = node_firstsurface( node, RI.currentmodel ); firstsurface = node_firstsurface( node, RI.currentmodel );
numsurfaces = node_numsurfaces( node, RI.currentmodel ); numsurfaces = node_numsurfaces( node, RI.currentmodel );
if( dist > light->radius ) if( dist > light->radius )
{ {
R_MarkLights( light, bit, children[0] ); R_MarkLights( light, bit, node_child( node, 0, RI.currentmodel ));
return; return;
} }
if( dist < -light->radius ) if( dist < -light->radius )
{ {
R_MarkLights( light, bit, children[1] ); R_MarkLights( light, bit, node_child( node, 1, RI.currentmodel ));
return; return;
} }
@@ -146,8 +144,8 @@ void R_MarkLights( dlight_t *light, int bit, mnode_t *node )
surf->dlightbits |= bit; surf->dlightbits |= bit;
} }
R_MarkLights( light, bit, children[0] ); R_MarkLights( light, bit, node_child( node, 0, RI.currentmodel ));
R_MarkLights( light, bit, children[1] ); R_MarkLights( light, bit, node_child( node, 1, RI.currentmodel ));
} }
/* /*
@@ -207,7 +205,6 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f,
msurface_t *surf; msurface_t *surf;
matrix3x4 tbn; matrix3x4 tbn;
vec3_t mid; vec3_t mid;
mnode_t *children[2];
int firstsurface, numsurfaces; int firstsurface, numsurfaces;
// didn't hit anything // didn't hit anything
@@ -217,7 +214,6 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f,
return false; return false;
} }
node_children( children, node, model );
firstsurface = node_firstsurface( node, model ); firstsurface = node_firstsurface( node, model );
numsurfaces = node_numsurfaces( node, model ); numsurfaces = node_numsurfaces( node, model );
@@ -227,7 +223,7 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f,
side = front < 0; side = front < 0;
if(( back < 0 ) == side ) if(( back < 0 ) == side )
return R_RecursiveLightPoint( model, children[side], p1f, p2f, cv, start, end ); return R_RecursiveLightPoint( model, node_child( node, side, model ), p1f, p2f, cv, start, end );
frac = front / ( front - back ); frac = front / ( front - back );
@@ -235,7 +231,7 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f,
midf = p1f + ( p2f - p1f ) * frac; midf = p1f + ( p2f - p1f ) * frac;
// co down front side // co down front side
if( R_RecursiveLightPoint( model, children[side], p1f, midf, cv, start, mid )) if( R_RecursiveLightPoint( model, node_child( node, side, model ), p1f, midf, cv, start, mid ))
return true; // hit something return true; // hit something
if(( back < 0 ) == side ) if(( back < 0 ) == side )
@@ -337,7 +333,7 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f,
} }
// go down back side // go down back side
return R_RecursiveLightPoint( model, children[!side], midf, p2f, cv, mid, end ); return R_RecursiveLightPoint( model, node_child( node, !side, model ), midf, p2f, cv, mid, end );
} }
/* /*
+1 -1
View File
@@ -12,7 +12,7 @@ else
git clone --recursive https://github.com/FWGS/hlsdk-portable -b "$1" "$MODPATH" git clone --recursive https://github.com/FWGS/hlsdk-portable -b "$1" "$MODPATH"
fi fi
mkdir ../../build/ios || exit 1 mkdir -p ../../build/ios || exit 1
IOSDIR=$(realpath ../../build/ios) IOSDIR=$(realpath ../../build/ios)
cd "$MODPATH" || exit 1 cd "$MODPATH" || exit 1
+2 -1
View File
@@ -20,7 +20,7 @@ import os
import sys import sys
ANDROID_NDK_ENVVARS = ['ANDROID_NDK_HOME', 'ANDROID_NDK'] ANDROID_NDK_ENVVARS = ['ANDROID_NDK_HOME', 'ANDROID_NDK']
ANDROID_NDK_SUPPORTED = [10, 19, 20, 23, 25, 27, 28, 29] ANDROID_NDK_SUPPORTED = [10, 19, 20, 23, 25, 27, 28, 29, 30]
ANDROID_NDK_HARDFP_MAX = 11 # latest version that supports hardfp ANDROID_NDK_HARDFP_MAX = 11 # latest version that supports hardfp
ANDROID_NDK_GCC_MAX = 17 # latest NDK that ships with GCC ANDROID_NDK_GCC_MAX = 17 # latest NDK that ships with GCC
ANDROID_NDK_UNIFIED_SYSROOT_MIN = 15 ANDROID_NDK_UNIFIED_SYSROOT_MIN = 15
@@ -35,6 +35,7 @@ ANDROID_NDK_API_MIN = {
27: 19, 27: 19,
28: 21, 28: 21,
29: 21, 29: 21,
30: 21,
} # minimal API level ndk revision supports } # minimal API level ndk revision supports
ANDROID_STPCPY_API_MIN = 21 # stpcpy() introduced in SDK 21 ANDROID_STPCPY_API_MIN = 21 # stpcpy() introduced in SDK 21