Merge branch 'master' into resource

This commit is contained in:
mittorn 2019-01-30 13:38:36 +00:00 committed by GitHub
commit 8b30a7631d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
222 changed files with 13798 additions and 8154 deletions

13
.gitignore vendored
View file

@ -6,6 +6,7 @@
# Other
*.save
# Qt Creator for some reason creates *.user.$version files, so exclude it too
*.user*
*~
@ -47,7 +48,6 @@ Network Trash Folder
Temporary Items
.apdisk
### CMake ###
CMakeCache.txt
CMakeFiles
@ -307,7 +307,18 @@ build-*
# Android
*.apk
*.config
*.creator
*.includes
*.files
# Waf
build_current
.waf-*
waf-*/
waf3-*/
.lock-waf*
*.lastbuildstate
*.unsuccessfulbuild
__pycache__
*.pyc

6
.gitmodules vendored Normal file
View file

@ -0,0 +1,6 @@
[submodule "mainui"]
path = mainui
url = https://github.com/FWGS/mainui_cpp
[submodule "vgui_support/miniutl"]
path = vgui_support/miniutl
url = https://github.com/FWGS/miniutl

48
.travis.yml Normal file
View file

@ -0,0 +1,48 @@
language: c
cache: ccache
compiler: gcc
sudo: false
addons:
apt:
packages:
- mingw-w64-i686-dev
- binutils-mingw-w64-i686
- gcc-mingw-w64-i686
- g++-mingw-w64-i686
- p7zip-full
- gcc-multilib
- g++-multilib
- libx11-dev:i386
- libxext-dev:i386
- x11-utils
- libgl1-mesa-dev
- libasound-dev
- zlib1g:i386
- libstdc++6:i386
- libfuse2:i386
env:
global:
- SDL_VERSION=2.0.8
git:
depth: 50
submodules: true
jdk:
- oraclejdk8
matrix:
include:
- os: linux
dist: xenial
- os: osx
before_script:
- sh scripts/travis_common_deps.sh
- sh scripts/travis_${TRAVIS_OS_NAME}_deps.sh
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then export ANDROID_HOME=$PWD/android-sdk-linux; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then export PATH=${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools:$PWD/android-ndk; fi
script:
- sh scripts/build_${TRAVIS_OS_NAME}_engine.sh
# - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sh scripts/build_android_engine.sh; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sh scripts/build_mingw_engine.sh; fi
after_script:
- cd ${TRAVIS_BUILD_DIR}
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ccache --show-stats > ccache_stats.log; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sh scripts/travis-deploy.sh newengine Xash3DFWGS-i386.AppImage xash3d-mingw.7z ccache_stats.log; fi

25
common/boneinfo.h Normal file
View file

@ -0,0 +1,25 @@
/*
boneinfo.h - structure that send delta-compressed bones across network
Copyright (C) 2018 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#ifndef BONEINFO_H
#define BONEINFO_H
typedef struct
{
vec3_t angles;
vec3_t origin;
} boneinfo_t;
#endif//BONEINFO_H

View file

@ -74,7 +74,7 @@ BRUSH MODELS
#define MAX_MAP_MARKSURFACES 524288 // can be increased without problems
#else
#define MAX_MAP_MODELS 768 // embedded models
#define MAX_MAP_ENTSTRING 0x80000 // 512 kB should be enough
#define MAX_MAP_ENTSTRING 0x100000 // 1 Mb should be enough
#define MAX_MAP_PLANES 65536 // can be increased without problems
#define MAX_MAP_NODES 32767 // because negative shorts are leafs
#define MAX_MAP_CLIPNODES 32767 // because negative shorts are contents
@ -117,14 +117,14 @@ BRUSH MODELS
#define LUMP_FACEINFO 1 // landscape and lightmap resolution info
#define LUMP_CUBEMAPS 2 // cubemap description
#define LUMP_VERTNORMALS 3 // phong shaded vertex normals
#define LUMP_VERTEX_LIGHT 4 // contain compressed light cubes per empty leafs
#define LUMP_LEAF_LIGHTING 4 // store vertex lighting for statics
#define LUMP_WORLDLIGHTS 5 // list of all the virtual and real lights (used to relight models in-game)
#define LUMP_COLLISION 6 // physics engine collision hull dump
#define LUMP_AINODEGRAPH 7 // node graph that stored into the bsp
#define LUMP_COLLISION 6 // physics engine collision hull dump (userdata)
#define LUMP_AINODEGRAPH 7 // node graph that stored into the bsp (userdata)
#define LUMP_SHADOWMAP 8 // contains shadow map for direct light
#define LUMP_UNUSED1 9 // one lump reserved for me
#define LUMP_UNUSED2 10 // one lump reserved for me
#define LUMP_UNUSED3 11 // one lump reserved for me
#define LUMP_VERTEX_LIGHT 9 // store vertex lighting for statics
#define LUMP_UNUSED0 10 // one lump reserved for me
#define LUMP_UNUSED1 11 // one lump reserved for me
#define EXTRA_LUMPS 12 // count of the extra lumps
// texture flags
@ -132,6 +132,7 @@ BRUSH MODELS
#define TEX_WORLD_LUXELS BIT( 1 ) // alternative lightmap matrix will be used (luxels per world units instead of luxels per texels)
#define TEX_AXIAL_LUXELS BIT( 2 ) // force world luxels to axial positive scales
#define TEX_EXTRA_LIGHTMAP BIT( 3 ) // bsp31 legacy - using 8 texels per luxel instead of 16 texels per luxel
#define TEX_SCROLL BIT( 6 ) // Doom special FX
// ambient sound types
enum

View file

@ -166,6 +166,7 @@ struct decal_s
// Xash3D specific
vec3_t position; // location of the decal center in world space.
glpoly_t *polys; // precomputed decal vertices
int reserved[4]; // just for future expansions or mod-makers
};
typedef struct mleaf_s
@ -366,7 +367,7 @@ typedef struct player_info_s
int userid; // User id on server
char userinfo[MAX_INFO_STRING]; // User info string
char name[MAX_SCOREBOARDNAME]; // Name (extracted from userinfo)
int spectator; // Spectator or not, unused
int spectator; // Spectator or not, unused (frags for quake demo playback)
int ping;
int packet_loss;

View file

@ -21,7 +21,7 @@ GNU General Public License for more details.
/*
===================================================================
SETUP BACKENDS DEFINATIONS
SETUP BACKENDS DEFINITIONS
===================================================================
*/

View file

@ -51,6 +51,8 @@ typedef struct event_api_s
struct pmtrace_s *( *EV_VisTraceLine )( float *start, float *end, int flags );
struct physent_s *( *EV_GetVisent )( int idx );
int ( *EV_TestLine)( const vec3_t start, const vec3_t end, int flags );
void ( *EV_PushTraceBounds)( int hullnum, const float *mins, const float *maxs );
void ( *EV_PopTraceBounds)( void );
} event_api_t;
#endif//EVENT_API_H

View file

@ -17,6 +17,7 @@ GNU General Public License for more details.
#define GAMEINFO_H
#define GFL_NOMODELS (1<<0)
#define GFL_NOSKILLS (1<<1)
/*
========================================================================

View file

@ -28,6 +28,9 @@
// kill the request hook after receiving the first response
#define FNETAPI_MULTIPLE_RESPONSE ( 1<<0 )
struct net_response_s;
typedef void (*net_api_response_func_t) ( struct net_response_s *response );
#define NET_SUCCESS ( 0 )
#define NET_ERROR_TIMEOUT ( 1<<0 )
#define NET_ERROR_PROTO_UNSUPPORTED ( 1<<1 )
@ -58,8 +61,6 @@ typedef struct net_response_s
void *response;
} net_response_t;
typedef void (*net_api_response_func_t) ( net_response_t *response );
typedef struct net_status_s
{
// Connected to remote server? 1 == yes, 0 otherwise
@ -83,12 +84,12 @@ typedef struct net_api_s
// APIs
void (*InitNetworking)( void );
void (*Status )( struct net_status_s *status );
void (*SendRequest)( int context, int request, int flags, double timeout, netadr_t *remote_address, net_api_response_func_t response );
void (*SendRequest)( int context, int request, int flags, double timeout, struct netadr_s *remote_address, net_api_response_func_t response );
void (*CancelRequest)( int context );
void (*CancelAllRequests)( void );
char *(*AdrToString)( netadr_t *a );
int ( *CompareAdr)( netadr_t *a, netadr_t *b );
int ( *StringToAdr)( char *s, netadr_t *a );
char *(*AdrToString)( struct netadr_s *a );
int ( *CompareAdr)( struct netadr_s *a, struct netadr_s *b );
int ( *StringToAdr)( char *s, struct netadr_s *a );
const char *(*ValueForKey)( const char *s, const char *key );
void (*RemoveKey)( char *s, const char *key );
void (*SetValueForKey)( char *s, const char *key, const char *value, int maxsize );

View file

@ -67,15 +67,16 @@ GNU General Public License for more details.
#define SERVERDLL "libserver" POSTFIX "." OS_LIB_EXT
#define GAMEPATH "/sdcard/xash"
#else
#define MENUDLL "libxashmenu" ARCH_SUFFIX "." OS_LIB_EXT
#define CLIENTDLL "client" ARCH_SUFFIX "." OS_LIB_EXT
#define MENUDLL "libmenu" ARCH_SUFFIX "." OS_LIB_EXT
#define CLIENTDLL "client" ARCH_SUFFIX "." OS_LIB_EXT
#endif
#define VGUI_SUPPORT_DLL "libvgui_support." OS_LIB_EXT
// Windows-specific
#define __cdecl
#define __stdcall
#define __stdcall
#define _inline static inline
#define O_BINARY 0 // O_BINARY is Windows extension
#define O_TEXT 0 // O_TEXT is Windows extension
@ -118,6 +119,7 @@ GNU General Public License for more details.
#define strncasecmp _strnicmp
#define open _open
#define read _read
#define alloca _alloca
// shut-up compiler warnings
#pragma warning(disable : 4244) // MIPS

View file

@ -40,7 +40,7 @@ GNU General Public License for more details.
#define PARM_TEX_MIPCOUNT 15 // count of mipmaps (0 - autogenerated, 1 - disabled of mipmapping)
#define PARM_BSP2_SUPPORTED 16 // tell custom renderer what engine is support BSP2 in this build
#define PARM_SKY_SPHERE 17 // sky is quake sphere ?
//reserved
#define PARAM_GAMEPAUSED 18 // game is paused
#define PARM_MAP_HAS_DELUXE 19 // map has deluxedata
#define PARM_MAX_ENTITIES 20
#define PARM_WIDESCREEN 21
@ -74,12 +74,13 @@ enum
typedef enum
{
TF_COLORMAP = 0, // just for tabulate source
TF_NEAREST = (1<<0), // disable texfilter
TF_KEEP_SOURCE = (1<<1), // some images keep source
TF_NOFLIP_TGA = (1<<2), // Steam background completely ignore tga attribute 0x20
TF_EXPAND_SOURCE = (1<<3), // Don't keep source as 8-bit expand to RGBA
TF_TEXTURE_2D_ARRAY = (1<<4), // this is 2D texture array (multi-layers)
TF_TEXTURE_RECTANGLE= (1<<5), // this is GL_TEXTURE_RECTANGLE
TF_ALLOW_EMBOSS = (1<<4), // Allow emboss-mapping for this image
TF_RECTANGLE = (1<<5), // this is GL_TEXTURE_RECTANGLE
TF_CUBEMAP = (1<<6), // it's cubemap texture
TF_DEPTHMAP = (1<<7), // custom texture filter used
TF_QUAKEPAL = (1<<8), // image has an quake1 palette
@ -92,11 +93,11 @@ typedef enum
TF_NORMALMAP = (1<<15), // is a normalmap
TF_HAS_ALPHA = (1<<16), // image has alpha (used only for GL_CreateTexture)
TF_FORCE_COLOR = (1<<17), // force upload monochrome textures as RGB (detail textures)
TF_TEXTURE_1D = (1<<18), // this is GL_TEXTURE_1D
// reserved
TF_BORDER = (1<<19), // zero clamp for projected textures
TF_TEXTURE_3D = (1<<20), // this is GL_TEXTURE_3D
TF_ATLAS_PAGE = (1<<21), // bit who indicate lightmap page or deluxemap page
// reserved
TF_ALPHACONTRAST = (1<<22), // special texture mode for A2C
// reserved
// reserved
TF_IMG_UPLOADED = (1<<25), // this is set for first time when called glTexImage, otherwise it will be call glTexSubImage
@ -185,16 +186,16 @@ typedef struct render_api_s
void (*R_EntityRemoveDecals)( struct model_s *mod ); // remove all the decals from specified entity (BSP only)
// AVIkit support
void *(*AVI_LoadVideo)( const char *filename );
void *(*AVI_LoadVideo)( const char *filename, qboolean load_audio );
int (*AVI_GetVideoInfo)( void *Avi, long *xres, long *yres, float *duration );
long (*AVI_GetVideoFrameNumber)( void *Avi, float time );
byte *(*AVI_GetVideoFrame)( void *Avi, long frame );
void (*AVI_UploadRawFrame)( int texture, int cols, int rows, int width, int height, const byte *data );
void (*AVI_FreeVideo)( void *Avi );
int (*AVI_IsActive)( void *Avi );
void (*AVI_StreamSound)( void *Avi, int entnum, float fvol, float attn, float synctime );
void (*AVI_Reserved0)( void ); // for potential interface expansion without broken compatibility
void (*AVI_Reserved1)( void );
void (*AVI_Reserved2)( void );
// glState related calls (must use this instead of normal gl-calls to prevent de-synchornize local states between engine and the client)
void (*GL_Bind)( int tmu, unsigned int texnum );
@ -206,20 +207,20 @@ typedef struct render_api_s
void (*GL_TextureTarget)( unsigned int target ); // change texture unit mode without bind texture
void (*GL_TexCoordArrayMode)( unsigned int texmode );
void* (*GL_GetProcAddress)( const char *name );
void (*GL_UpdateTexSize)( int texnum, int width, int height, int depth ); // recalc statistics
void (*GL_Reserved0)( void ); // for potential interface expansion without broken compatibility
void (*GL_Reserved1)( void );
void (*GL_Reserved2)( void );
// Misc renderer functions
void (*GL_DrawParticles)( const struct ref_viewpass_s *rvp, qboolean trans_pass, float frametime );
void (*EnvShot)( const float *vieworg, const char *name, qboolean skyshot, int shotsize ); // store skybox into gfx\env folder
int (*SPR_LoadExt)( const char *szPicName, unsigned int texFlags ); // extended version of SPR_Load
colorVec (*LightVec)( const float *start, const float *end, float *lightspot );
colorVec (*LightVec)( const float *start, const float *end, float *lightspot, float *lightvec );
struct mstudiotex_s *( *StudioGetTexture )( struct cl_entity_s *e );
const struct ref_overview_s *( *GetOverviewParms )( void );
const char *( *GetFileByIndex )( int fileindex );
void (*R_Reserved1)( void ); // for potential interface expansion without broken compatibility
void (*R_Reserved2)( void );
void (*R_Reserved0)( void ); // for potential interface expansion without broken compatibility
void (*R_Reserved1)( void );
// static allocations
void *(*pfnMemAlloc)( size_t cb, const char *filename, const int fileline );

View file

@ -55,17 +55,6 @@ infotable dlumpinfo_t[dwadinfo_t->numlumps]
#define TYP_COLORMAP2 69 // old stuff. build palette from LBM file (not used)
#define TYP_QFONT 70 // half-life font (qfont_t)
// dlumpinfo_t->img_type
#define IMG_DIFFUSE 0 // same as default pad1 always equal 0
#define IMG_ALPHAMASK 1 // alpha-channel that stored separate as luminance texture
#define IMG_NORMALMAP 2 // indexed normalmap
#define IMG_GLOSSMAP 3 // luminance or color specularity map
#define IMG_GLOSSPOWER 4 // gloss power map (each value is a specular pow)
#define IMG_HEIGHTMAP 5 // heightmap (for parallax occlusion mapping or source of normalmap)
#define IMG_LUMA 6 // luma or glow texture with self-illuminated parts
#define IMG_DECAL_ALPHA 7 // it's a decal texture (last color in palette is base color, and other colors his graduations)
#define IMG_DECAL_COLOR 8 // decal without alpha-channel uses base, like 127 127 127 as transparent color
/*
========================================================================

View file

@ -0,0 +1,3 @@
// Add predefined macros for your project here. For example:
// #define THE_ANSWER 42
#define XASH_SDL

View file

@ -0,0 +1 @@
[General]

View file

@ -0,0 +1,218 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.5.2, 2018-10-21T21:41:59. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
<value type="QByteArray">{e98eea9b-9ef7-4df9-8f97-1e67893b8b3b}</value>
</data>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
<value type="int">0</value>
</data>
<data>
<variable>ProjectExplorer.Project.EditorSettings</variable>
<valuemap type="QVariantMap">
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
<value type="QString" key="language">Cpp</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
</valuemap>
</valuemap>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
<value type="QString" key="language">QmlJS</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
</valuemap>
</valuemap>
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
<value type="int" key="EditorConfiguration.IndentSize">4</value>
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
<value type="int" key="EditorConfiguration.TabSize">8</value>
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.PluginSettings</variable>
<valuemap type="QVariantMap"/>
</data>
<data>
<variable>ProjectExplorer.Project.Target.0</variable>
<valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{cc7c1b7f-457b-4e71-9eeb-5e67c737c51a}</value>
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/a1ba/projects/xash/xash3d-fwgs</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProcessStep.Arguments">configure --vgui=vgui-dev --win-style-install --prefix=/home/a1ba/projects/builtXash</value>
<value type="QString" key="ProjectExplorer.ProcessStep.Command">./waf</value>
<value type="QString" key="ProjectExplorer.ProcessStep.WorkingDirectory">%{buildDir}</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Особый</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.ProcessStep</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets"/>
<value type="bool" key="GenericProjectManager.GenericMakeStep.Clean">false</value>
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments">build -j5 -v</value>
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeCommand">./waf</value>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Сборка</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Сборка</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
<value type="QString">clean</value>
</valuelist>
<value type="bool" key="GenericProjectManager.GenericMakeStep.Clean">true</value>
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments"></value>
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeCommand">./waf</value>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Сборка</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Очистка</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges">
<value type="QString">PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig</value>
</valuelist>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">По умолчанию</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">По умолчанию</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProcessStep.Arguments">install</value>
<value type="QString" key="ProjectExplorer.ProcessStep.Command">./waf</value>
<value type="QString" key="ProjectExplorer.ProcessStep.WorkingDirectory">%{buildDir}</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Особый</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.ProcessStep</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Установка</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Локальная установка</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
<value type="bool" key="Analyzer.QmlProfiler.AggregateTraces">false</value>
<value type="bool" key="Analyzer.QmlProfiler.FlushEnabled">false</value>
<value type="uint" key="Analyzer.QmlProfiler.FlushInterval">1000</value>
<value type="QString" key="Analyzer.QmlProfiler.LastTraceFile"></value>
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
<value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
<value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
<value type="int">0</value>
<value type="int">1</value>
<value type="int">2</value>
<value type="int">3</value>
<value type="int">4</value>
<value type="int">5</value>
<value type="int">6</value>
<value type="int">7</value>
<value type="int">8</value>
<value type="int">9</value>
<value type="int">10</value>
<value type="int">11</value>
<value type="int">12</value>
<value type="int">13</value>
<value type="int">14</value>
</valuelist>
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes">
<value type="QString">LD_LIBRARY_PATH=/home/a1ba/projects/builtXash</value>
</valuelist>
<value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Arguments">-dev 5</value>
<value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Executable">/home/a1ba/projects/builtXash/xash3d</value>
<value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.WorkingDirectory">/home/a1ba/projects/builtXash</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Запуск /home/a1ba/projects/builtXash/xash3d</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.TargetCount</variable>
<value type="int">1</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
<value type="int">18</value>
</data>
<data>
<variable>Version</variable>
<value type="int">18</value>
</data>
</qtcreator>

View file

@ -0,0 +1,397 @@
common/backends.h
common/beamdef.h
common/boneinfo.h
common/bspfile.h
common/cl_entity.h
common/com_model.h
common/con_nprint.h
common/const.h
common/cvardef.h
common/defaults.h
common/demo_api.h
common/dlight.h
common/enginefeatures.h
common/entity_state.h
common/entity_types.h
common/event_api.h
common/event_args.h
common/event_flags.h
common/gameinfo.h
common/hltv.h
common/ivoicetweak.h
common/kbutton.h
common/lightstyle.h
common/mathlib.h
common/net_api.h
common/netadr.h
common/particledef.h
common/pmtrace.h
common/port.h
common/qfont.h
common/r_efx.h
common/r_studioint.h
common/ref_params.h
common/render_api.h
common/screenfade.h
common/studio_event.h
common/triangleapi.h
common/usercmd.h
common/wadfile.h
common/weaponinfo.h
common/wrect.h
common/xash3d_types.h
engine/alias.h
engine/anorms.h
engine/cdll_exp.h
engine/cdll_int.h
engine/client/avi/avi.h
engine/client/avi/avi_stub.c
engine/client/avi/avi_win.c
engine/client/cl_cmds.c
engine/client/cl_custom.c
engine/client/cl_debug.c
engine/client/cl_demo.c
engine/client/cl_events.c
engine/client/cl_frame.c
engine/client/cl_game.c
engine/client/cl_gameui.c
engine/client/cl_main.c
engine/client/cl_mobile.c
engine/client/cl_netgraph.c
engine/client/cl_parse.c
engine/client/cl_pmove.c
engine/client/cl_qparse.c
engine/client/cl_remap.c
engine/client/cl_scrn.c
engine/client/cl_tent.c
engine/client/cl_tent.h
engine/client/cl_video.c
engine/client/cl_view.c
engine/client/client.h
engine/client/console.c
engine/client/gl_alias.c
engine/client/gl_backend.c
engine/client/gl_beams.c
engine/client/gl_cull.c
engine/client/gl_decals.c
engine/client/gl_draw.c
engine/client/gl_export.h
engine/client/gl_frustum.c
engine/client/gl_frustum.h
engine/client/gl_image.c
engine/client/gl_local.h
engine/client/gl_refrag.c
engine/client/gl_rlight.c
engine/client/gl_rmain.c
engine/client/gl_rmath.c
engine/client/gl_rmisc.c
engine/client/gl_rpart.c
engine/client/gl_rsurf.c
engine/client/gl_sprite.c
engine/client/gl_studio.c
engine/client/gl_warp.c
engine/client/in_evdev.c
engine/client/in_joy.c
engine/client/in_touch.c
engine/client/input.c
engine/client/input.h
engine/client/keys.c
engine/client/mod_dbghulls.c
engine/client/s_dsp.c
engine/client/s_load.c
engine/client/s_main.c
engine/client/s_mix.c
engine/client/s_mouth.c
engine/client/s_stream.c
engine/client/s_utils.c
engine/client/s_vox.c
engine/client/sound.h
engine/client/titles.c
engine/client/vgui/vgui_draw.c
engine/client/vgui/vgui_draw.h
engine/client/vgui/vgui_main.h
engine/client/vid_common.c
engine/client/vid_common.h
engine/client/vox.h
engine/common/base_cmd.c
engine/common/base_cmd.h
engine/common/build.c
engine/common/cfgscript.c
engine/common/cmd.c
engine/common/com_strings.h
engine/common/common.c
engine/common/common.h
engine/common/con_utils.c
engine/common/crashhandler.c
engine/common/crclib.c
engine/common/crtlib.c
engine/common/crtlib.h
engine/common/custom.c
engine/common/cvar.c
engine/common/cvar.h
engine/common/dedicated.c
engine/common/filesystem.c
engine/common/filesystem.h
engine/common/gamma.c
engine/common/host.c
engine/common/host_state.c
engine/common/hpak.c
engine/common/identification.c
engine/common/imagelib/imagelib.h
engine/common/imagelib/img_bmp.c
engine/common/imagelib/img_dds.c
engine/common/imagelib/img_main.c
engine/common/imagelib/img_quant.c
engine/common/imagelib/img_tga.c
engine/common/imagelib/img_utils.c
engine/common/imagelib/img_wad.c
engine/common/infostring.c
engine/common/launcher.c
engine/common/lib_common.c
engine/common/library.h
engine/common/masterlist.c
engine/common/mathlib.c
engine/common/mathlib.h
engine/common/matrixlib.c
engine/common/mod_bmodel.c
engine/common/mod_local.h
engine/common/mod_studio.c
engine/common/model.c
engine/common/net_buffer.c
engine/common/net_buffer.h
engine/common/net_chan.c
engine/common/net_encode.c
engine/common/net_encode.h
engine/common/net_ws.c
engine/common/net_ws.h
engine/common/netchan.h
engine/common/pm_debug.c
engine/common/pm_local.h
engine/common/pm_surface.c
engine/common/pm_trace.c
engine/common/protocol.h
engine/common/sequence.c
engine/common/soundlib/libmpg/dct36.c
engine/common/soundlib/libmpg/dct64.c
engine/common/soundlib/libmpg/fmt123.h
engine/common/soundlib/libmpg/format.c
engine/common/soundlib/libmpg/frame.c
engine/common/soundlib/libmpg/frame.h
engine/common/soundlib/libmpg/getbits.h
engine/common/soundlib/libmpg/huffman.h
engine/common/soundlib/libmpg/index.c
engine/common/soundlib/libmpg/index.h
engine/common/soundlib/libmpg/layer3.c
engine/common/soundlib/libmpg/libmpg.c
engine/common/soundlib/libmpg/libmpg.h
engine/common/soundlib/libmpg/mpeghead.h
engine/common/soundlib/libmpg/mpg123.c
engine/common/soundlib/libmpg/mpg123.h
engine/common/soundlib/libmpg/parse.c
engine/common/soundlib/libmpg/reader.c
engine/common/soundlib/libmpg/reader.h
engine/common/soundlib/libmpg/sample.h
engine/common/soundlib/libmpg/synth.c
engine/common/soundlib/libmpg/synth.h
engine/common/soundlib/libmpg/tabinit.c
engine/common/soundlib/snd_main.c
engine/common/soundlib/snd_mp3.c
engine/common/soundlib/snd_utils.c
engine/common/soundlib/snd_wav.c
engine/common/soundlib/soundlib.h
engine/common/sys_con.c
engine/common/system.c
engine/common/system.h
engine/common/world.c
engine/common/world.h
engine/common/zone.c
engine/custom.h
engine/customentity.h
engine/edict.h
engine/eiface.h
engine/keydefs.h
engine/menu_int.h
engine/mobility_int.h
engine/physint.h
engine/platform/android/lib_android.c
engine/platform/android/lib_android.h
engine/platform/apple/lib_ios.c
engine/platform/apple/lib_ios.h
engine/platform/emscripten/lib_em.c
engine/platform/emscripten/lib_em.h
engine/platform/platform.h
engine/platform/posix/lib_posix.c
engine/platform/sdl/events.c
engine/platform/sdl/events.h
engine/platform/sdl/in_sdl.c
engine/platform/sdl/s_sdl.c
engine/platform/sdl/vid_sdl.c
engine/platform/win32/con_win.c
engine/platform/win32/lib_win.c
engine/progdefs.h
engine/sequence.h
engine/server/server.h
engine/server/sv_client.c
engine/server/sv_cmds.c
engine/server/sv_custom.c
engine/server/sv_frame.c
engine/server/sv_game.c
engine/server/sv_init.c
engine/server/sv_log.c
engine/server/sv_main.c
engine/server/sv_move.c
engine/server/sv_phys.c
engine/server/sv_pmove.c
engine/server/sv_save.c
engine/server/sv_world.c
engine/shake.h
engine/sprite.h
engine/studio.h
engine/vgui_api.h
engine/warpsin.h
engine/wscript
game_launch/game.cpp
game_launch/game.rc
game_launch/wscript
mainui/Android.mk
mainui/BMPUtils.h
mainui/BaseMenu.cpp
mainui/BaseMenu.h
mainui/Btns.cpp
mainui/BtnsBMPTable.h
mainui/CFGScript.cpp
mainui/CFGScript.h
mainui/Color.cpp
mainui/Color.h
mainui/Coord.h
mainui/EngineCallback.cpp
mainui/EventSystem.cpp
mainui/EventSystem.h
mainui/MenuStrings.cpp
mainui/MenuStrings.h
mainui/Primitive.h
mainui/Scissor.cpp
mainui/Scissor.h
mainui/Utils.cpp
mainui/Utils.h
mainui/controls/Action.cpp
mainui/controls/Action.h
mainui/controls/BackgroundBitmap.cpp
mainui/controls/BackgroundBitmap.h
mainui/controls/BaseClientWindow.cpp
mainui/controls/BaseClientWindow.h
mainui/controls/BaseItem.cpp
mainui/controls/BaseItem.h
mainui/controls/BaseWindow.cpp
mainui/controls/BaseWindow.h
mainui/controls/Bitmap.cpp
mainui/controls/Bitmap.h
mainui/controls/CheckBox.cpp
mainui/controls/CheckBox.h
mainui/controls/Editable.cpp
mainui/controls/Editable.h
mainui/controls/Field.cpp
mainui/controls/Field.h
mainui/controls/Framework.cpp
mainui/controls/Framework.h
mainui/controls/ItemsHolder.cpp
mainui/controls/ItemsHolder.h
mainui/controls/MessageBox.cpp
mainui/controls/MessageBox.h
mainui/controls/PicButton.cpp
mainui/controls/PicButton.h
mainui/controls/PlayerModelView.cpp
mainui/controls/PlayerModelView.h
mainui/controls/ProgressBar.cpp
mainui/controls/ProgressBar.h
mainui/controls/ScrollView.cpp
mainui/controls/ScrollView.h
mainui/controls/Slider.cpp
mainui/controls/Slider.h
mainui/controls/SpinControl.cpp
mainui/controls/SpinControl.h
mainui/controls/Switch.cpp
mainui/controls/Switch.h
mainui/controls/TabView.cpp
mainui/controls/TabView.h
mainui/controls/Table.cpp
mainui/controls/Table.h
mainui/controls/YesNoMessageBox.cpp
mainui/controls/YesNoMessageBox.h
mainui/enginecallback_menu.h
mainui/extdll_menu.h
mainui/font/BaseFontBackend.cpp
mainui/font/BaseFontBackend.h
mainui/font/BitmapFont.cpp
mainui/font/BitmapFont.h
mainui/font/FontManager.cpp
mainui/font/FontManager.h
mainui/font/FontRenderer.h
mainui/font/FreeTypeFont.cpp
mainui/font/FreeTypeFont.h
mainui/font/StbFont.cpp
mainui/font/StbFont.h
mainui/font/WinAPIFont.cpp
mainui/font/WinAPIFont.h
mainui/font/stb_truetype.h
mainui/legacy/menu_playdemo.cpp
mainui/legacy/menu_playrec.cpp
mainui/legacy/menu_recdemo.cpp
mainui/menufont.h
mainui/menus/AdvancedControls.cpp
mainui/menus/Audio.cpp
mainui/menus/Configuration.cpp
mainui/menus/ConnectionProgress.cpp
mainui/menus/ConnectionProgress.h
mainui/menus/ConnectionWarning.cpp
mainui/menus/ConnectionWarning.h
mainui/menus/Controls.cpp
mainui/menus/CreateGame.cpp
mainui/menus/Credits.cpp
mainui/menus/CustomGame.cpp
mainui/menus/FileDialog.cpp
mainui/menus/GameOptions.cpp
mainui/menus/Gamepad.cpp
mainui/menus/InputDevices.cpp
mainui/menus/LoadGame.cpp
mainui/menus/Main.cpp
mainui/menus/Multiplayer.cpp
mainui/menus/NewGame.cpp
mainui/menus/PlayerIntroduceDialog.cpp
mainui/menus/PlayerIntroduceDialog.h
mainui/menus/PlayerSetup.cpp
mainui/menus/SaveLoad.cpp
mainui/menus/ServerBrowser.cpp
mainui/menus/Touch.cpp
mainui/menus/TouchButtons.cpp
mainui/menus/TouchEdit.cpp
mainui/menus/TouchOptions.cpp
mainui/menus/Video.cpp
mainui/menus/VideoModes.cpp
mainui/menus/VideoOptions.cpp
mainui/menus/Zoo.cpp
mainui/menus/dynamic/ScriptMenu.cpp
mainui/model/BaseArrayModel.h
mainui/model/BaseModel.h
mainui/model/StringArrayModel.h
mainui/udll_int.cpp
mainui/utl/unicode_strtools.cpp
mainui/utl/unicode_strtools.h
mainui/utl/utlmemory.h
mainui/utl/utlrbtree.h
mainui/utl/utlvector.h
mainui/wscript
pm_shared/pm_defs.h
pm_shared/pm_info.h
pm_shared/pm_movevars.h
vgui_support/utlmemory.h
vgui_support/utlrbtree.h
vgui_support/utlvector.h
vgui_support/vgui_clip.cpp
vgui_support/vgui_font.cpp
vgui_support/vgui_input.cpp
vgui_support/vgui_int.cpp
vgui_support/vgui_main.h
vgui_support/vgui_surf.cpp
vgui_support/wscript
wscript

View file

@ -0,0 +1,19 @@
engine
engine/client
engine/client/avi
engine/client/vgui
engine/common
engine/common/imagelib
engine/common/soundlib
engine/common/soundlib/libmpg
engine/server
mainui
mainui/controls
mainui/font
mainui/menus
mainui/model
mainui/utl
pm_shared
vgui_support
common
/usr/include/SDL2

View file

@ -15,17 +15,13 @@ GNU General Public License for more details.
#ifndef CDLL_EXP_H
#define CDLL_EXP_H
typedef struct r_studio_interface_s r_studio_interface_t;
typedef struct engine_studio_api_s engine_studio_api_t;
typedef struct mstudioevent_s mstudioevent_t;
typedef struct local_state_s local_state_t;
typedef struct playermove_s playermove_t;
typedef struct tempent_s tempent_t;
typedef struct physent_s physent_t;
typedef struct pmtrace_s pmtrace_t;
typedef struct usercmd_s usercmd_t;
typedef struct netadr_s netadr_t;
struct tempent_s;
struct usercmd_s;
struct physent_s;
struct playermove_s;
struct mstudioevent_s;
struct engine_studio_api_s;
struct r_studio_interface_s;
// NOTE: ordering is important!
typedef struct cldll_func_s
@ -36,15 +32,15 @@ typedef struct cldll_func_s
int (*pfnRedraw)( float flTime, int intermission );
int (*pfnUpdateClientData)( client_data_t *cdata, float flTime );
void (*pfnReset)( void );
void (*pfnPlayerMove)( playermove_t *ppmove, int server );
void (*pfnPlayerMoveInit)( playermove_t *ppmove );
void (*pfnPlayerMove)( struct playermove_s *ppmove, int server );
void (*pfnPlayerMoveInit)( struct playermove_s *ppmove );
char (*pfnPlayerMoveTexture)( char *name );
void (*IN_ActivateMouse)( void );
void (*IN_DeactivateMouse)( void );
void (*IN_MouseEvent)( int mstate );
void (*IN_ClearStates)( void );
void (*IN_Accumulate)( void );
void (*CL_CreateMove)( float frametime, usercmd_t *cmd, int active );
void (*CL_CreateMove)( float frametime, struct usercmd_s *cmd, int active );
int (*CL_IsThirdPerson)( void );
void (*CL_CameraOffset)( float *ofs ); // unused
void *(*KB_Find)( const char *name );
@ -54,26 +50,26 @@ typedef struct cldll_func_s
void (*pfnCreateEntities)( void );
void (*pfnDrawNormalTriangles)( void );
void (*pfnDrawTransparentTriangles)( void );
void (*pfnStudioEvent)( const mstudioevent_t *event, const cl_entity_t *entity );
void (*pfnPostRunCmd)( local_state_t *from, local_state_t *to, usercmd_t *cmd, int runfuncs, double time, unsigned int random_seed );
void (*pfnStudioEvent)( const struct mstudioevent_s *event, const cl_entity_t *entity );
void (*pfnPostRunCmd)( struct local_state_s *from, struct local_state_s *to, usercmd_t *cmd, int runfuncs, double time, unsigned int random_seed );
void (*pfnShutdown)( void );
void (*pfnTxferLocalOverrides)( entity_state_t *state, const clientdata_t *client );
void (*pfnProcessPlayerState)( entity_state_t *dst, const entity_state_t *src );
void (*pfnTxferPredictionData)( entity_state_t *ps, const entity_state_t *pps, clientdata_t *pcd, const clientdata_t *ppcd, weapon_data_t *wd, const weapon_data_t *pwd );
void (*pfnDemo_ReadBuffer)( int size, byte *buffer );
int (*pfnConnectionlessPacket)( const netadr_t *net_from, const char *args, char *buffer, int *size );
int (*pfnConnectionlessPacket)( const struct netadr_s *net_from, const char *args, char *buffer, int *size );
int (*pfnGetHullBounds)( int hullnumber, float *mins, float *maxs );
void (*pfnFrame)( double time );
int (*pfnKey_Event)( int eventcode, int keynum, const char *pszCurrentBinding );
void (*pfnTempEntUpdate)( double frametime, double client_time, double cl_gravity, tempent_t **ppTempEntFree, tempent_t **ppTempEntActive, int ( *Callback_AddVisibleEntity )( cl_entity_t *pEntity ), void ( *Callback_TempEntPlaySound )( tempent_t *pTemp, float damp ));
void (*pfnTempEntUpdate)( double frametime, double client_time, double cl_gravity, struct tempent_s **ppTempEntFree, struct tempent_s **ppTempEntActive, int ( *Callback_AddVisibleEntity )( cl_entity_t *pEntity ), void ( *Callback_TempEntPlaySound )( struct tempent_s *pTemp, float damp ));
cl_entity_t *(*pfnGetUserEntity)( int index );
void (*pfnVoiceStatus)( int entindex, qboolean bTalking );
void (*pfnDirectorMessage)( int iSize, void *pbuf );
int (*pfnGetStudioModelInterface)( int version, r_studio_interface_t **ppinterface, engine_studio_api_t *pstudio );
int (*pfnGetStudioModelInterface)( int version, struct r_studio_interface_s **ppinterface, struct engine_studio_api_s *pstudio );
void (*pfnChatInputPosition)( int *x, int *y );
// Xash3D extension
int (*pfnGetRenderInterface)( int version, render_api_t *renderfuncs, render_interface_t *callback );
void (*pfnClipMoveToEntity)( physent_t *pe, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, pmtrace_t *tr );
void (*pfnClipMoveToEntity)( struct physent_s *pe, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, struct pmtrace_s *tr );
// Xash3D FWGS extension
int (*pfnTouchEvent)( int type, int fingerID, float x, float y, float dx, float dy );
void (*pfnMoveEvent)( float forwardmove, float sidemove );

View file

@ -212,6 +212,7 @@ typedef struct cl_enginefuncs_s
float (*pfnRandomFloat)( float flLow, float flHigh );
int (*pfnRandomLong)( int lLow, int lHigh );
void (*pfnHookEvent)( const char *name, void ( *pfnEvent )( struct event_args_s *args ));
int (*Con_IsVisible) ();
const char *(*pfnGetGameDirectory)( void );
struct cvar_s *(*pfnGetCvarPointer)( const char *szName );

View file

@ -18,7 +18,7 @@ GNU General Public License for more details.
//
// avikit.c
//
typedef struct movie_state_s movie_state_t;
typedef struct movie_state_s movie_state_t;
long AVI_GetVideoFrameNumber( movie_state_t *Avi, float time );
byte *AVI_GetVideoFrame( movie_state_t *Avi, long frame );
qboolean AVI_GetVideoInfo( movie_state_t *Avi, long *xres, long *yres, float *duration );
@ -26,7 +26,8 @@ qboolean AVI_GetAudioInfo( movie_state_t *Avi, wavdata_t *snd_info );
long AVI_GetAudioChunk( movie_state_t *Avi, char *audiodata, long offset, long length );
void AVI_OpenVideo( movie_state_t *Avi, const char *filename, qboolean load_audio, int quiet );
movie_state_t *AVI_LoadVideo( const char *filename, qboolean load_audio );
movie_state_t *AVI_LoadVideoNoSound( const char *filename );
long AVI_TimeToSoundPosition( movie_state_t *Avi, long time );
long AVI_GetVideoFrameCount( movie_state_t *Avi );
void AVI_CloseVideo( movie_state_t *Avi );
qboolean AVI_IsActive( movie_state_t *Avi );
void AVI_FreeVideo( movie_state_t *Avi );

View file

@ -51,9 +51,14 @@ movie_state_t *AVI_LoadVideo( const char *filename, qboolean load_audio )
return NULL;
}
movie_state_t *AVI_LoadVideoNoSound( const char *filename )
long AVI_TimeToSoundPosition( movie_state_t *Avi, long time )
{
return NULL;
return 0;
}
long AVI_GetVideoFrameCount( movie_state_t *Avi )
{
return 0;
}
void AVI_CloseVideo( movie_state_t *Avi )

View file

@ -59,6 +59,7 @@ dll_info_t msacm_dll = { "msacm32.dll", msacm_funcs, false };
static int (_stdcall *pAVIStreamInfo)( PAVISTREAM pavi, AVISTREAMINFO *psi, LONG lSize );
static int (_stdcall *pAVIStreamRead)( PAVISTREAM pavi, LONG lStart, LONG lSamples, void *lpBuffer, LONG cbBuffer, LONG *plBytes, LONG *plSamples );
static PGETFRAME (_stdcall *pAVIStreamGetFrameOpen)( PAVISTREAM pavi, LPBITMAPINFOHEADER lpbiWanted );
static long (_stdcall *pAVIStreamTimeToSample)( PAVISTREAM pavi, LONG lTime );
static void* (_stdcall *pAVIStreamGetFrame)( PGETFRAME pg, LONG lPos );
static int (_stdcall *pAVIStreamGetFrameClose)( PGETFRAME pg );
static dword (_stdcall *pAVIStreamRelease)( PAVISTREAM pavi );
@ -85,6 +86,7 @@ static dllfunc_t avifile_funcs[] =
{ "AVIStreamReadFormat", (void **) &pAVIStreamReadFormat },
{ "AVIStreamRelease", (void **) &pAVIStreamRelease },
{ "AVIStreamStart", (void **) &pAVIStreamStart },
{ "AVIStreamTimeToSample", (void **) &pAVIStreamTimeToSample },
{ NULL, NULL }
};
@ -142,7 +144,8 @@ qboolean AVI_ACMConvertAudio( movie_state_t *Avi )
// WMA codecs, both versions - they simply don't work.
if( Avi->audio_header->wFormatTag == 0x160 || Avi->audio_header->wFormatTag == 0x161 )
{
if( !Avi->quiet ) MsgDev( D_ERROR, "ACM does not support this audio codec.\n" );
if( !Avi->quiet )
Con_Reportf( S_ERROR "ACM does not support this audio codec.\n" );
return false;
}
@ -151,7 +154,8 @@ qboolean AVI_ACMConvertAudio( movie_state_t *Avi )
if( Avi->audio_header_size < sizeof( WAVEFORMATEX ))
{
if( !Avi->quiet ) MsgDev( D_ERROR, "ACM failed to open conversion stream.\n" );
if( !Avi->quiet )
Con_Reportf( S_ERROR "ACM failed to open conversion stream.\n" );
return false;
}
@ -181,7 +185,8 @@ qboolean AVI_ACMConvertAudio( movie_state_t *Avi )
if( pacmStreamOpen( &Avi->cpa_conversion_stream, NULL, sh, dh, NULL, 0, 0, 0 ) != MMSYSERR_NOERROR )
{
if( !Avi->quiet ) MsgDev( D_ERROR, "ACM failed to open conversion stream.\n" );
if( !Avi->quiet )
Con_Reportf( S_ERROR "ACM failed to open conversion stream.\n" );
return false;
}
}
@ -201,13 +206,14 @@ qboolean AVI_ACMConvertAudio( movie_state_t *Avi )
// get the size of the output buffer for streaming the compressed audio
if( pacmStreamSize( Avi->cpa_conversion_stream, Avi->cpa_blockalign, &dest_length, ACM_STREAMSIZEF_SOURCE ) != MMSYSERR_NOERROR )
{
if( !Avi->quiet ) MsgDev( D_ERROR, "Couldn't get ACM conversion stream size.\n" );
if( !Avi->quiet )
Con_Reportf( S_ERROR "Couldn't get ACM conversion stream size.\n" );
pacmStreamClose( Avi->cpa_conversion_stream, 0 );
return false;
}
Avi->cpa_srcbuffer = (byte *)Mem_Alloc( cls.mempool, Avi->cpa_blockalign );
Avi->cpa_dstbuffer = (byte *)Mem_Alloc( cls.mempool, dest_length ); // maintained buffer for raw data
Avi->cpa_srcbuffer = (byte *)Mem_Malloc( cls.mempool, Avi->cpa_blockalign );
Avi->cpa_dstbuffer = (byte *)Mem_Malloc( cls.mempool, dest_length ); // maintained buffer for raw data
// prep the headers!
Avi->cpa_conversion_header.cbStruct = sizeof( ACMSTREAMHEADER );
@ -224,7 +230,8 @@ qboolean AVI_ACMConvertAudio( movie_state_t *Avi )
if( pacmStreamPrepareHeader( Avi->cpa_conversion_stream, &Avi->cpa_conversion_header, 0 ) != MMSYSERR_NOERROR )
{
if( !Avi->quiet ) MsgDev( D_ERROR, "couldn't prep headers.\n" );
if( !Avi->quiet )
Con_Reportf( S_ERROR "couldn't prepare stream headers.\n" );
pacmStreamClose( Avi->cpa_conversion_stream, 0 );
return false;
}
@ -271,6 +278,23 @@ long AVI_GetVideoFrameNumber( movie_state_t *Avi, float time )
return (time * Avi->video_fps);
}
long AVI_GetVideoFrameCount( movie_state_t *Avi )
{
if( !Avi->active )
return 0;
return Avi->video_frames;
}
long AVI_TimeToSoundPosition( movie_state_t *Avi, long time )
{
if( !Avi->active || !Avi->audio_stream )
return 0;
// UNDONE: what about compressed audio?
return pAVIStreamTimeToSample( Avi->audio_stream, time ) * Avi->audio_bytes_per_sample;
}
// gets the raw frame data
byte *AVI_GetVideoFrame( movie_state_t *Avi, long frame )
{
@ -378,8 +402,11 @@ long AVI_GetAudioChunk( movie_state_t *Avi, char *audiodata, long offset, long l
}
else
{
// we out of soundtrack, just zeroing buffer
for( i = 0; i < length; i++ )
audiodata[i] = 0;
return length;
}
}
@ -482,20 +509,25 @@ void AVI_OpenVideo( movie_state_t *Avi, const char *filename, qboolean load_audi
switch( hr )
{
case AVIERR_BADFORMAT:
if( !Avi->quiet ) MsgDev( D_ERROR, "corrupt file or unknown format.\n" );
if( !Avi->quiet )
Con_DPrintf( S_ERROR "corrupt file or unknown format.\n" );
break;
case AVIERR_MEMORY:
if( !Avi->quiet ) MsgDev( D_ERROR, "insufficient memory to open file.\n" );
if( !Avi->quiet )
Con_DPrintf( S_ERROR "insufficient memory to open file.\n" );
break;
case AVIERR_FILEREAD:
if( !Avi->quiet ) MsgDev( D_ERROR, "disk error reading file.\n" );
if( !Avi->quiet )
Con_DPrintf( S_ERROR "disk error reading file.\n" );
break;
case AVIERR_FILEOPEN:
if( !Avi->quiet ) MsgDev( D_ERROR, "disk error opening file.\n" );
if( !Avi->quiet )
Con_DPrintf( S_ERROR "disk error opening file.\n" );
break;
case REGDB_E_CLASSNOTREG:
default:
if( !Avi->quiet ) MsgDev( D_ERROR, "no handler found (or file not found).\n" );
if( !Avi->quiet )
Con_DPrintf( S_ERROR "no handler found (or file not found).\n" );
break;
}
return;
@ -533,7 +565,7 @@ void AVI_OpenVideo( movie_state_t *Avi, const char *filename, qboolean load_audi
// read the audio header
pAVIStreamReadFormat( Avi->audio_stream, pAVIStreamStart( Avi->audio_stream ), 0, &size );
Avi->audio_header = (WAVEFORMAT *)Mem_Alloc( cls.mempool, size );
Avi->audio_header = (WAVEFORMAT *)Mem_Malloc( cls.mempool, size );
pAVIStreamReadFormat( Avi->audio_stream, pAVIStreamStart( Avi->audio_stream ), Avi->audio_header, &size );
Avi->audio_header_size = size;
Avi->audio_codec = Avi->audio_header->wFormatTag;
@ -565,7 +597,8 @@ void AVI_OpenVideo( movie_state_t *Avi, const char *filename, qboolean load_audi
{
if( Avi->pfile ) // if file is open, close it
pAVIFileRelease( Avi->pfile );
if( !Avi->quiet ) MsgDev( D_ERROR, "couldn't find a valid video stream.\n" );
if( !Avi->quiet )
Con_DPrintf( S_ERROR "couldn't find a valid video stream.\n" );
return;
}
@ -574,7 +607,8 @@ void AVI_OpenVideo( movie_state_t *Avi, const char *filename, qboolean load_audi
if( Avi->video_getframe == NULL )
{
if( !Avi->quiet ) MsgDev( D_ERROR, "error attempting to read video frames.\n" );
if( !Avi->quiet )
Con_DPrintf( S_ERROR "error attempting to read video frames.\n" );
return; // couldn't open frame getter.
}
@ -619,10 +653,7 @@ movie_state_t *AVI_LoadVideo( const char *filename, qboolean load_audio )
// fast reject
if( !avi_initialized )
{
MsgDev( D_ERROR, "AVI_LoadVideo: movie support is disabled\n" );
return NULL;
}
// open cinematic
Q_snprintf( path, sizeof( path ), "media/%s", filename );
@ -631,11 +662,11 @@ movie_state_t *AVI_LoadVideo( const char *filename, qboolean load_audio )
if( FS_FileExists( path, false ) && !fullpath )
{
MsgDev( D_ERROR, "AVI_LoadVideo: Couldn't load %s from packfile. Please extract it\n", path );
Con_Printf( "Couldn't load %s from packfile. Please extract it\n", path );
return NULL;
}
Avi = Mem_Alloc( cls.mempool, sizeof( movie_state_t ));
Avi = Mem_Malloc( cls.mempool, sizeof( movie_state_t ));
AVI_OpenVideo( Avi, fullpath, load_audio, false );
if( !AVI_IsActive( Avi ))
@ -648,11 +679,6 @@ movie_state_t *AVI_LoadVideo( const char *filename, qboolean load_audio )
return Avi;
}
movie_state_t *AVI_LoadVideoNoSound( const char *filename )
{
return AVI_LoadVideo( filename, false );
}
void AVI_FreeVideo( movie_state_t *state )
{
if( !state ) return;
@ -668,34 +694,28 @@ qboolean AVI_Initailize( void )
{
if( Sys_CheckParm( "-noavi" ))
{
MsgDev( D_INFO, "AVI: Disabled\n" );
Con_Printf( "AVI: Disabled\n" );
return false;
}
if( !Sys_LoadLibrary( &avifile_dll ))
{
MsgDev( D_ERROR, "AVI_Initailize: failed\n" );
return false;
}
if( !Sys_LoadLibrary( &msvfw_dll ))
{
MsgDev( D_ERROR, "AVI_Initailize: failed\n" );
Sys_FreeLibrary( &avifile_dll );
return false;
}
if( !Sys_LoadLibrary( &msacm_dll ))
{
MsgDev( D_ERROR, "AVI_Initailize: failed\n" );
Sys_FreeLibrary( &avifile_dll );
Sys_FreeLibrary( &msvfw_dll );
return false;
}
pAVIFileInit();
avi_initialized = true;
MsgDev( D_NOTE, "AVI_Initailize: done\n" );
pAVIFileInit();
return true;
}

View file

@ -152,7 +152,7 @@ qboolean CL_ScreenshotGetName( int lastnum, char *filename )
if( lastnum < 0 || lastnum > 9999 )
{
MsgDev( D_ERROR, "unable to write screenshot\n" );
Con_Printf( S_ERROR "unable to write screenshot\n" );
return false;
}
@ -180,7 +180,7 @@ qboolean CL_SnapshotGetName( int lastnum, char *filename )
if( lastnum < 0 || lastnum > 9999 )
{
MsgDev( D_ERROR, "unable to write snapshot\n" );
Con_Printf( S_ERROR "unable to write snapshot\n" );
FS_AllowDirectPaths( false );
return false;
}
@ -345,7 +345,7 @@ void CL_LevelShot_f( void )
if( cls.demoplayback && ( cls.demonum != -1 ))
{
Q_sprintf( cls.shotname, "levelshots/%s_%s.bmp", cls.demoname, glState.wideScreen ? "16x9" : "4x3" );
Q_snprintf( filename, sizeof( filename ), "demos/%s.dem", cls.demoname );
Q_snprintf( filename, sizeof( filename ), "%s.dem", cls.demoname );
// make sure what levelshot is newer than demo
ft1 = FS_FileTime( filename, false );
@ -385,25 +385,6 @@ void CL_SaveShot_f( void )
cls.scrshot_action = scrshot_savegame; // build new frame for saveshot
}
/*
==================
CL_DemoShot_f
mini-pic in playdemo menu
==================
*/
void CL_DemoShot_f( void )
{
if( Cmd_Argc() < 2 )
{
Con_Printf( S_USAGE "demoshot <demoname>\n" );
return;
}
Q_sprintf( cls.shotname, "demos/%s.bmp", Cmd_Argv( 1 ));
cls.scrshot_action = scrshot_demoshot; // build new frame for demoshot
}
/*
==============
CL_DeleteDemo_f
@ -424,9 +405,8 @@ void CL_DeleteDemo_f( void )
return;
}
// delete save and saveshot
FS_Delete( va( "demos/%s.dem", Cmd_Argv( 1 )));
FS_Delete( va( "demos/%s.bmp", Cmd_Argv( 1 )));
// delete demo
FS_Delete( va( "%s.dem", Cmd_Argv( 1 )));
}
/*

View file

@ -44,19 +44,19 @@ qboolean CL_CheckFile( sizebuf_t *msg, resource_t *pResource )
if( !COM_IsSafeFileToDownload( filepath ))
{
MsgDev( D_REPORT, "refusing to download %s\n", filepath );
Con_Reportf( "refusing to download %s\n", filepath );
return true;
}
if( !cl_allow_download.value )
{
MsgDev( D_REPORT, "Download refused, cl_allow_download is 0\n" );
Con_Reportf( "Download refused, cl_allow_download is 0\n" );
return true;
}
if( cls.state == ca_active && !cl_download_ingame.value )
{
MsgDev( D_REPORT, "In-game download refused...\n" );
Con_Reportf( "In-game download refused...\n" );
return true;
}
@ -66,7 +66,7 @@ qboolean CL_CheckFile( sizebuf_t *msg, resource_t *pResource )
if( cls.demoplayback )
{
MsgDev( D_WARN, "file %s missing during demo playback.\n", filepath );
Con_Reportf( S_WARN "file %s missing during demo playback.\n", filepath );
return true;
}
@ -81,7 +81,7 @@ void CL_AddToResourceList( resource_t *pResource, resource_t *pList )
{
if( pResource->pPrev != NULL || pResource->pNext != NULL )
{
MsgDev( D_ERROR, "Resource already linked\n" );
Con_Reportf( S_ERROR "Resource already linked\n" );
return;
}
@ -112,7 +112,7 @@ void CL_MoveToOnHandList( resource_t *pResource )
{
if( !pResource )
{
MsgDev( D_REPORT, "Null resource passed to CL_MoveToOnHandList\n" );
Con_Reportf( "Null resource passed to CL_MoveToOnHandList\n" );
return;
}

242
engine/client/cl_debug.c Normal file
View file

@ -0,0 +1,242 @@
/*
cl_debug.c - server message debugging
Copyright (C) 2018 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "common.h"
#include "client.h"
#include "net_encode.h"
#include "particledef.h"
#include "gl_local.h"
#include "cl_tent.h"
#include "shake.h"
#include "hltv.h"
#include "input.h"
#define MSG_COUNT 32 // last 32 messages parsed
#define MSG_MASK (MSG_COUNT - 1)
const char *svc_strings[svc_lastmsg+1] =
{
"svc_bad",
"svc_nop",
"svc_disconnect",
"svc_event",
"svc_changing",
"svc_setview",
"svc_sound",
"svc_time",
"svc_print",
"svc_stufftext",
"svc_setangle",
"svc_serverdata",
"svc_lightstyle",
"svc_updateuserinfo",
"svc_deltatable",
"svc_clientdata",
"svc_resource",
"svc_pings",
"svc_particle",
"svc_restoresound",
"svc_spawnstatic",
"svc_event_reliable",
"svc_spawnbaseline",
"svc_temp_entity",
"svc_setpause",
"svc_signonnum",
"svc_centerprint",
"svc_unused27",
"svc_unused28",
"svc_unused29",
"svc_intermission",
"svc_finale",
"svc_cdtrack",
"svc_restore",
"svc_cutscene",
"svc_weaponanim",
"svc_bspdecal",
"svc_roomtype",
"svc_addangle",
"svc_usermessage",
"svc_packetentities",
"svc_deltapacketentities",
"svc_choke",
"svc_resourcelist",
"svc_deltamovevars",
"svc_resourcerequest",
"svc_customization",
"svc_crosshairangle",
"svc_soundfade",
"svc_filetxferfailed",
"svc_hltv",
"svc_director",
"svc_voiceinit",
"svc_voicedata",
"svc_deltapacketbones",
"svc_unused55",
"svc_resourcelocation",
"svc_querycvarvalue",
"svc_querycvarvalue2",
};
typedef struct
{
int command;
int starting_offset;
int frame_number;
} oldcmd_t;
typedef struct
{
oldcmd_t oldcmd[MSG_COUNT];
int currentcmd;
qboolean parsing;
} msg_debug_t;
static msg_debug_t cls_message_debug;
const char *CL_MsgInfo( int cmd )
{
static string sz;
Q_strcpy( sz, "???" );
if( cmd >= 0 && cmd <= svc_lastmsg )
{
// get engine message name
Q_strncpy( sz, svc_strings[cmd], sizeof( sz ));
}
else if( cmd > svc_lastmsg && cmd <= ( svc_lastmsg + MAX_USER_MESSAGES ))
{
int i;
for( i = 0; i < MAX_USER_MESSAGES; i++ )
{
if( clgame.msg[i].number == cmd )
{
Q_strncpy( sz, clgame.msg[i].name, sizeof( sz ));
break;
}
}
}
return sz;
}
/*
=====================
CL_Parse_Debug
enable message debugging
=====================
*/
void CL_Parse_Debug( qboolean enable )
{
cls_message_debug.parsing = enable;
}
/*
=====================
CL_Parse_RecordCommand
record new message params into debug buffer
=====================
*/
void CL_Parse_RecordCommand( int cmd, int startoffset )
{
int slot;
if( cmd == svc_nop ) return;
slot = ( cls_message_debug.currentcmd++ & MSG_MASK );
cls_message_debug.oldcmd[slot].command = cmd;
cls_message_debug.oldcmd[slot].starting_offset = startoffset;
cls_message_debug.oldcmd[slot].frame_number = host.framecount;
}
/*
=====================
CL_ResetFrame
=====================
*/
void CL_ResetFrame( frame_t *frame )
{
memset( &frame->graphdata, 0, sizeof( netbandwidthgraph_t ));
frame->receivedtime = host.realtime;
frame->valid = true;
frame->choked = false;
frame->latency = 0.0;
frame->time = cl.mtime[0];
}
/*
=====================
CL_WriteErrorMessage
write net_message into buffer.dat for debugging
=====================
*/
static void CL_WriteErrorMessage( int current_count, sizebuf_t *msg )
{
const char *buffer_file = "buffer.dat";
file_t *fp;
fp = FS_Open( buffer_file, "wb", false );
if( !fp ) return;
FS_Write( fp, &cls.starting_count, sizeof( int ));
FS_Write( fp, &current_count, sizeof( int ));
FS_Write( fp, MSG_GetData( msg ), MSG_GetMaxBytes( msg ));
FS_Close( fp );
Con_Printf( "Wrote erroneous message to %s\n", buffer_file );
}
/*
=====================
CL_WriteMessageHistory
list last 32 messages for debugging net troubleshooting
=====================
*/
void CL_WriteMessageHistory( void )
{
oldcmd_t *old, *failcommand;
sizebuf_t *msg = &net_message;
int i, thecmd;
if( !cls.initialized || cls.state == ca_disconnected )
return;
if( !cls_message_debug.parsing )
return;
Con_Printf( "Last %i messages parsed.\n", MSG_COUNT );
// finish here
thecmd = cls_message_debug.currentcmd - 1;
thecmd -= ( MSG_COUNT - 1 ); // back up to here
for( i = 0; i < MSG_COUNT - 1; i++ )
{
thecmd &= MSG_MASK;
old = &cls_message_debug.oldcmd[thecmd];
Con_Printf( "%i %04i %s\n", old->frame_number, old->starting_offset, CL_MsgInfo( old->command ));
thecmd++;
}
failcommand = &cls_message_debug.oldcmd[thecmd];
Con_Printf( "BAD: %3i:%s\n", MSG_GetNumBytesRead( msg ) - 1, CL_MsgInfo( failcommand->command ));
if( host_developer.value >= DEV_EXTENDED )
CL_WriteErrorMessage( MSG_GetNumBytesRead( msg ) - 1, msg );
cls_message_debug.parsing = false;
}

View file

@ -126,7 +126,7 @@ void CL_StartupDemoHeader( void )
if( !cls.demoheader )
{
MsgDev( D_ERROR, "couldn't open temporary header file.\n" );
Con_DPrintf( S_ERROR "couldn't open temporary header file.\n" );
return;
}
@ -349,9 +349,9 @@ Write demo header
*/
void CL_WriteDemoHeader( const char *name )
{
long copysize;
long savepos;
long curpos;
int copysize;
int savepos;
int curpos;
Con_Printf( "recording to %s.\n", name );
cls.demofile = FS_Open( name, "wb", false );
@ -359,7 +359,7 @@ void CL_WriteDemoHeader( const char *name )
if( !cls.demofile )
{
MsgDev( D_ERROR, "couldn't open %s.\n", name );
Con_Printf( S_ERROR "couldn't open %s.\n", name );
return;
}
@ -380,7 +380,7 @@ void CL_WriteDemoHeader( const char *name )
FS_Write( cls.demofile, &demo.header, sizeof( demo.header ));
demo.directory.numentries = 2;
demo.directory.entries = Mem_Alloc( cls.mempool, sizeof( demoentry_t ) * demo.directory.numentries );
demo.directory.entries = Mem_Calloc( cls.mempool, sizeof( demoentry_t ) * demo.directory.numentries );
// DIRECTORY ENTRY # 0
demo.entry = &demo.directory.entries[0]; // only one here.
@ -489,7 +489,7 @@ void CL_DrawDemoRecording( void )
{
char string[64];
rgba_t color = { 255, 255, 255, 255 };
long pos;
int pos;
int len;
if(!( host_developer.value && cls.demorecording ))
@ -497,10 +497,10 @@ void CL_DrawDemoRecording( void )
pos = FS_Tell( cls.demofile );
Q_snprintf( string, sizeof( string ), "^1RECORDING:^7 %s: %s time: %02d:%02d", cls.demoname,
Q_memprint( pos ), (int)(cls.demotime / 60.0f ), (int)fmod( cls.demotime, 60.0f ));
Q_memprint( pos ), (int)(cls.demotime / 60.0f ), (int)fmod( cls.demotime, 60.0f ));
Con_DrawStringLen( string, &len, NULL );
Con_DrawString(( glState.width - len ) >> 1, glState.height >> 2, string, color );
Con_DrawString(( glState.width - len ) >> 1, glState.height >> 4, string, color );
}
/*
@ -626,6 +626,49 @@ void CL_ReadDemoSequence( qboolean discard )
cls.netchan.last_reliable_sequence = last_reliable_sequence;
}
/*
=================
CL_DemoStartPlayback
=================
*/
void CL_DemoStartPlayback( int mode )
{
if( cls.changedemo )
{
S_StopAllSounds( true );
SCR_BeginLoadingPlaque( false );
CL_ClearState ();
CL_InitEdicts (); // re-arrange edicts
}
else
{
// NOTE: at this point demo is still valid
CL_Disconnect();
Host_ShutdownServer();
Con_FastClose();
UI_SetActiveMenu( false );
}
cls.demoplayback = mode;
cls.state = ca_connected;
cl.background = (cls.demonum != -1) ? true : false;
cls.spectator = false;
cls.signon = 0;
demo.starttime = CL_GetDemoPlaybackClock(); // for determining whether to read another message
Netchan_Setup( NS_CLIENT, &cls.netchan, net_from, Cvar_VariableInteger( "net_qport" ), NULL, CL_GetFragmentSize );
memset( demo.cmds, 0, sizeof( demo.cmds ));
demo.angle_position = 1;
demo.framecount = 0;
cls.lastoutgoingcommand = -1;
cls.nextcmdtime = host.realtime;
cl.last_command_ack = -1;
}
/*
=================
CL_DemoAborted
@ -657,7 +700,7 @@ void CL_DemoCompleted( void )
CL_StopPlayback();
if( !CL_NextDemo() && host_developer.value <= DEV_NONE )
if( !CL_NextDemo() && !cls.changedemo )
UI_SetActiveMenu( true );
Cvar_SetValue( "v_dark", 0.0f );
@ -705,14 +748,14 @@ qboolean CL_ReadRawNetworkData( byte *buffer, size_t *length )
if( msglen < 0 )
{
MsgDev( D_ERROR, "Demo message length < 0\n" );
Con_Reportf( S_ERROR "Demo message length < 0\n" );
CL_DemoCompleted();
return false;
}
if( msglen > MAX_INIT_MSG )
{
MsgDev( D_ERROR, "Demo message %i > %i\n", msglen, MAX_INIT_MSG );
Con_Reportf( S_ERROR "Demo message %i > %i\n", msglen, MAX_INIT_MSG );
CL_DemoCompleted();
return false;
}
@ -721,12 +764,14 @@ qboolean CL_ReadRawNetworkData( byte *buffer, size_t *length )
{
if( FS_Read( cls.demofile, buffer, msglen ) != msglen )
{
MsgDev( D_ERROR, "Error reading demo message data\n" );
Con_Reportf( S_ERROR "Error reading demo message data\n" );
CL_DemoCompleted();
return false;
}
}
cls.netchan.last_received = host.realtime;
cls.netchan.total_received += msglen;
*length = msglen;
if( cls.state != ca_active )
@ -735,6 +780,99 @@ qboolean CL_ReadRawNetworkData( byte *buffer, size_t *length )
return true;
}
/*
=================
CL_DemoReadMessageQuake
reads demo data and write it to client
=================
*/
qboolean CL_DemoReadMessageQuake( byte *buffer, size_t *length )
{
vec3_t viewangles;
int msglen = 0;
demoangle_t *a;
*length = 0; // assume we fail
// decide if it is time to grab the next message
if( cls.signon == SIGNONS ) // allways grab until fully connected
{
if( cls.timedemo )
{
if( host.framecount == cls.td_lastframe )
return false; // already read this frame's message
cls.td_lastframe = host.framecount;
// if this is the second frame, grab the real td_starttime
// so the bogus time on the first frame doesn't count
if( host.framecount == cls.td_startframe + 1 )
cls.td_starttime = host.realtime;
}
else if( cl.time <= cl.mtime[0] )
{
// don't need another message yet
return false;
}
}
// get the next message
FS_Read( cls.demofile, &msglen, sizeof( int ));
FS_Read( cls.demofile, &viewangles[0], sizeof( float ));
FS_Read( cls.demofile, &viewangles[1], sizeof( float ));
FS_Read( cls.demofile, &viewangles[2], sizeof( float ));
cls.netchan.incoming_sequence++;
demo.timestamp = cl.mtime[0];
cl.skip_interp = false;
// make sure what interp info contain angles from different frames
// or lerping will stop working
if( demo.lasttime != demo.timestamp )
{
// select entry into circular buffer
demo.angle_position = (demo.angle_position + 1) & ANGLE_MASK;
a = &demo.cmds[demo.angle_position];
// record update
a->starttime = demo.timestamp;
VectorCopy( viewangles, a->viewangles );
demo.lasttime = demo.timestamp;
}
if( msglen < 0 )
{
Con_Reportf( S_ERROR "Demo message length < 0\n" );
CL_DemoCompleted();
return false;
}
if( msglen > MAX_INIT_MSG )
{
Con_Reportf( S_ERROR "Demo message %i > %i\n", msglen, MAX_INIT_MSG );
CL_DemoCompleted();
return false;
}
if( msglen > 0 )
{
if( FS_Read( cls.demofile, buffer, msglen ) != msglen )
{
Con_Reportf( S_ERROR "Error reading demo message data\n" );
CL_DemoCompleted();
return false;
}
}
cls.netchan.last_received = host.realtime;
cls.netchan.total_received += msglen;
*length = msglen;
if( cls.state != ca_active )
Cbuf_Execute();
return true;
}
/*
=================
CL_DemoReadMessage
@ -754,7 +892,6 @@ qboolean CL_DemoReadMessage( byte *buffer, size_t *length )
if( !cls.demofile )
{
MsgDev( D_ERROR, "tried to read a demo message with no demo file\n" );
CL_DemoCompleted();
return false;
}
@ -765,6 +902,9 @@ qboolean CL_DemoReadMessage( byte *buffer, size_t *length )
return false; // paused
}
if( cls.demoplayback == DEMO_QUAKE1 )
return CL_DemoReadMessageQuake( buffer, length );
do
{
qboolean bSkipMessage = false;
@ -812,7 +952,7 @@ qboolean CL_DemoReadMessage( byte *buffer, size_t *length )
return false; // header is ended, skip frame
case dem_userdata:
FS_Read( cls.demofile, &size, sizeof( int ));
userbuf = Mem_Alloc( cls.mempool, size );
userbuf = Mem_Malloc( cls.mempool, size );
FS_Read( cls.demofile, userbuf, size );
if( clgame.hInstance )
@ -915,14 +1055,26 @@ but viewangles interpolate here
*/
void CL_DemoInterpolateAngles( void )
{
float curtime = (CL_GetDemoPlaybackClock() - demo.starttime) - host.frametime;
demoangle_t *prev = NULL, *next = NULL;
float frac = 0.0f;
float curtime;
if( curtime > demo.timestamp )
curtime = demo.timestamp; // don't run too far
if( cls.demoplayback == DEMO_QUAKE1 )
{
// manually select next & prev states
next = &demo.cmds[(demo.angle_position - 0) & ANGLE_MASK];
prev = &demo.cmds[(demo.angle_position - 1) & ANGLE_MASK];
if( cl.skip_interp ) *prev = *next; // camera was teleported
frac = cl.lerpFrac;
}
else
{
curtime = (CL_GetDemoPlaybackClock() - demo.starttime) - host.frametime;
if( curtime > demo.timestamp )
curtime = demo.timestamp; // don't run too far
CL_DemoFindInterpolatedViewAngles( curtime, &frac, &prev, &next );
CL_DemoFindInterpolatedViewAngles( curtime, &frac, &prev, &next );
}
if( prev && next )
{
@ -933,7 +1085,8 @@ void CL_DemoInterpolateAngles( void )
QuaternionSlerp( q2, q1, frac, q );
QuaternionAngle( q, cl.viewangles );
}
else VectorCopy( cl.cmd->viewangles, cl.viewangles );
else if( cl.cmd != NULL )
VectorCopy( cl.cmd->viewangles, cl.viewangles );
}
/*
@ -976,7 +1129,8 @@ void CL_StopPlayback( void )
cls.demofile = NULL;
cls.olddemonum = Q_max( -1, cls.demonum - 1 );
Mem_Free( demo.directory.entries );
if( demo.directory.entries != NULL )
Mem_Free( demo.directory.entries );
cls.td_lastframe = host.framecount;
demo.directory.numentries = 0;
demo.directory.entries = NULL;
@ -999,6 +1153,7 @@ void CL_StopPlayback( void )
// let game known about demo state
Cvar_FullSet( "cl_background", "0", FCVAR_READ_ONLY );
cls.state = ca_disconnected;
cls.set_lastdemo = false;
S_StopBackgroundTrack();
cls.connect_time = 0;
cls.demonum = -1;
@ -1110,16 +1265,45 @@ qboolean CL_NextDemo( void )
return true;
}
/*
==================
CL_CheckStartupDemos
queue demos loop after movie playing
==================
*/
void CL_CheckStartupDemos( void )
{
if( !cls.demos_pending )
return; // no demos in loop
if( cls.movienum != -1 )
return; // wait until movies finished
if( GameState->nextstate != STATE_RUNFRAME || cls.demoplayback )
{
// commandline override
cls.demos_pending = false;
cls.demonum = -1;
return;
}
// run demos loop in background mode
Cvar_SetValue( "v_dark", 1.0f );
cls.demos_pending = false;
cls.demonum = 0;
CL_NextDemo ();
}
/*
==================
CL_DemoGetName
==================
*/
void CL_DemoGetName( int lastnum, char *filename )
static void CL_DemoGetName( int lastnum, char *filename )
{
int a, b, c, d;
if( !filename ) return;
if( lastnum < 0 || lastnum > 9999 )
{
// bound
@ -1148,8 +1332,8 @@ Begins recording a demo from the current position
*/
void CL_Record_f( void )
{
string demoname, demopath;
const char *name;
string demoname, demopath, demoshot;
int n;
if( Cmd_Argc() == 1 )
@ -1190,7 +1374,7 @@ void CL_Record_f( void )
for( n = 0; n < 10000; n++ )
{
CL_DemoGetName( n, demoname );
if( !FS_FileExists( va( "demos/%s.dem", demoname ), true ))
if( !FS_FileExists( va( "%s.dem", demoname ), true ))
break;
}
@ -1203,18 +1387,12 @@ void CL_Record_f( void )
else Q_strncpy( demoname, name, sizeof( demoname ));
// open the demo file
Q_sprintf( demopath, "demos/%s.dem", demoname );
Q_sprintf( demoshot, "demos/%s.bmp", demoname );
// unload previous image from memory (it's will be overwritten)
GL_FreeImage( demoshot );
Q_sprintf( demopath, "%s.dem", demoname );
// make sure what old demo is removed
if( FS_FileExists( demopath, false )) FS_Delete( demopath );
if( FS_FileExists( demoshot, false )) FS_Delete( demoshot );
if( FS_FileExists( demopath, false ))
FS_Delete( demopath );
// write demoshot for preview
Cbuf_AddText( va( "demoshot \"%s\"\n", demoname ));
Q_strncpy( cls.demoname, demoname, sizeof( cls.demoname ));
Q_strncpy( gameui.globals->demoname, demoname, sizeof( gameui.globals->demoname ));
@ -1230,11 +1408,11 @@ playdemo <demoname>
*/
void CL_PlayDemo_f( void )
{
string filename;
string demoname;
int i;
char filename[MAX_QPATH];
char demoname[MAX_QPATH];
int i, ident;
if( Cmd_Argc() != 2 )
if( Cmd_Argc() < 2 )
{
Con_Printf( S_USAGE "playdemo <demoname>\n" );
return;
@ -1251,12 +1429,21 @@ void CL_PlayDemo_f( void )
return;
}
Q_strncpy( demoname, Cmd_Argv( 1 ), sizeof( demoname ) - 1 );
Q_snprintf( filename, sizeof( filename ), "demos/%s.dem", demoname );
Q_strncpy( demoname, Cmd_Argv( 1 ), sizeof( demoname ));
COM_StripExtension( demoname );
Q_snprintf( filename, sizeof( filename ), "%s.dem", demoname );
// hidden parameter
if( Cmd_Argc() > 2 )
cls.set_lastdemo = Q_atoi( Cmd_Argv( 2 ));
// member last demo
if( cls.set_lastdemo )
Cvar_Set( "lastdemo", demoname );
if( !FS_FileExists( filename, true ))
{
MsgDev( D_ERROR, "couldn't open %s\n", filename );
Con_Printf( S_ERROR "couldn't open %s\n", filename );
CL_DemoAborted();
return;
}
@ -1265,12 +1452,34 @@ void CL_PlayDemo_f( void )
Q_strncpy( cls.demoname, demoname, sizeof( cls.demoname ));
Q_strncpy( gameui.globals->demoname, demoname, sizeof( gameui.globals->demoname ));
// read in the m_DemoHeader
FS_Read( cls.demofile, &ident, sizeof( int ));
FS_Seek( cls.demofile, 0, SEEK_SET ); // rewind back to start
cls.forcetrack = 0;
// check for quake demos
if( ident != IDEMOHEADER )
{
int c, neg = false;
demo.header.host_fps = host_maxfps->value;
while(( c = FS_Getc( cls.demofile )) != '\n' )
{
if( c == '-' ) neg = true;
else cls.forcetrack = cls.forcetrack * 10 + (c - '0');
}
if( neg ) cls.forcetrack = -cls.forcetrack;
CL_DemoStartPlayback( DEMO_QUAKE1 );
return; // quake demo is started
}
// read in the demo header
FS_Read( cls.demofile, &demo.header, sizeof( demoheader_t ));
if( demo.header.id != IDEMOHEADER )
{
MsgDev( D_ERROR, "%s is not a demo file\n", filename );
Con_Printf( S_ERROR "%s is not a demo file\n", demoname );
CL_DemoAborted();
return;
}
@ -1278,10 +1487,10 @@ void CL_PlayDemo_f( void )
if( demo.header.net_protocol != PROTOCOL_VERSION || demo.header.dem_protocol != DEMO_PROTOCOL )
{
if( demo.header.dem_protocol != DEMO_PROTOCOL )
MsgDev( D_ERROR, "playdemo: demo protocol outdated (%i should be %i)\n", demo.header.dem_protocol, DEMO_PROTOCOL );
Con_Printf( S_ERROR "playdemo: demo protocol outdated (%i should be %i)\n", demo.header.dem_protocol, DEMO_PROTOCOL );
if( demo.header.net_protocol != PROTOCOL_VERSION )
MsgDev( D_ERROR, "playdemo: net protocol outdated (%i should be %i)\n", demo.header.net_protocol, PROTOCOL_VERSION );
Con_Printf( S_ERROR "playdemo: net protocol outdated (%i should be %i)\n", demo.header.net_protocol, PROTOCOL_VERSION );
CL_DemoAborted();
return;
}
@ -1292,31 +1501,13 @@ void CL_PlayDemo_f( void )
if( demo.directory.numentries < 1 || demo.directory.numentries > 1024 )
{
MsgDev( D_ERROR, "demo had bogus # of directory entries: %i\n", demo.directory.numentries );
Con_Printf( S_ERROR "demo had bogus # of directory entries: %i\n", demo.directory.numentries );
CL_DemoAborted();
return;
}
if( cls.changedemo )
{
S_StopAllSounds( true );
SCR_BeginLoadingPlaque( false );
CL_ClearState ();
CL_InitEdicts (); // re-arrange edicts
}
else
{
// NOTE: at this point demo is still valid
CL_Disconnect();
Host_ShutdownServer();
Con_FastClose();
UI_SetActiveMenu( false );
}
// allocate demo entries
demo.directory.entries = Mem_Alloc( cls.mempool, sizeof( demoentry_t ) * demo.directory.numentries );
demo.directory.entries = Mem_Malloc( cls.mempool, sizeof( demoentry_t ) * demo.directory.numentries );
for( i = 0; i < demo.directory.numentries; i++ )
{
@ -1328,22 +1519,7 @@ void CL_PlayDemo_f( void )
FS_Seek( cls.demofile, demo.entry->offset, SEEK_SET );
cls.demoplayback = true;
cls.state = ca_connected;
cl.background = (cls.demonum != -1) ? true : false;
cls.spectator = false;
cls.signon = 0;
demo.starttime = CL_GetDemoPlaybackClock(); // for determining whether to read another message
Netchan_Setup( NS_CLIENT, &cls.netchan, net_from, Cvar_VariableInteger( "net_qport" ), NULL, CL_GetFragmentSize );
memset( demo.cmds, 0, sizeof( demo.cmds ));
demo.angle_position = 1;
demo.framecount = 0;
cls.lastoutgoingcommand = -1;
cls.nextcmdtime = host.realtime;
cl.last_command_ack = -1;
CL_DemoStartPlayback( DEMO_XASH3D );
// g-cont. is this need?
Q_strncpy( cls.servername, demoname, sizeof( cls.servername ));
@ -1394,7 +1570,7 @@ void CL_StartDemos_f( void )
c = Cmd_Argc() - 1;
if( c > MAX_DEMOS )
{
MsgDev( D_WARN, "Host_StartDemos: max %i demos in demoloop\n", MAX_DEMOS );
Con_DPrintf( S_WARN "Host_StartDemos: max %i demos in demoloop\n", MAX_DEMOS );
c = MAX_DEMOS;
}
@ -1402,15 +1578,7 @@ void CL_StartDemos_f( void )
for( i = 1; i < c + 1; i++ )
Q_strncpy( cls.demos[i-1], Cmd_Argv( i ), sizeof( cls.demos[0] ));
if( !SV_Active() && !cls.demoplayback )
{
// run demos loop in background mode
Cvar_SetValue( "v_dark", 1.0f );
cls.demonum = 0;
CL_NextDemo ();
}
else cls.demonum = -1;
cls.demos_pending = true;
}
/*
@ -1428,17 +1596,15 @@ void CL_Demos_f( void )
return;
}
// demos loop are not running
if( cls.olddemonum == -1 )
return;
cls.demonum = cls.olddemonum;
if( cls.demonum == -1 )
cls.demonum = 0;
// run demos loop in background mode
if( !SV_Active() && !cls.demoplayback )
{
// run demos loop in background mode
cls.changedemo = true;
CL_NextDemo ();
}
}

View file

@ -157,14 +157,11 @@ void CL_RegisterEvent( int lastnum, const char *szEvName, pfnEventHook func )
cl_user_event_t *ev;
if( lastnum == MAX_EVENTS )
{
MsgDev( D_ERROR, "CL_RegisterEvent: MAX_EVENTS hit!\n" );
return;
}
// clear existing or allocate new one
if( !clgame.events[lastnum] )
clgame.events[lastnum] = Mem_Alloc( cls.mempool, sizeof( cl_user_event_t ));
clgame.events[lastnum] = Mem_Calloc( cls.mempool, sizeof( cl_user_event_t ));
else memset( clgame.events[lastnum], 0, sizeof( cl_user_event_t ));
ev = clgame.events[lastnum];
@ -197,7 +194,7 @@ qboolean CL_FireEvent( event_info_t *ei, int slot )
if( !ev )
{
idx = bound( 1, ei->index, ( MAX_EVENTS - 1 ));
MsgDev( D_ERROR, "CL_FireEvent: %s not precached\n", cl.event_precache[idx] );
Con_Reportf( S_ERROR "CL_FireEvent: %s not precached\n", cl.event_precache[idx] );
break;
}
@ -211,7 +208,7 @@ qboolean CL_FireEvent( event_info_t *ei, int slot )
}
name = cl.event_precache[ei->index];
MsgDev( D_ERROR, "CL_FireEvent: %s not hooked\n", name );
Con_Reportf( S_ERROR "CL_FireEvent: %s not hooked\n", name );
break;
}
}
@ -396,7 +393,7 @@ void CL_ParseEvent( sizebuf_t *msg )
event_index = MSG_ReadUBitLong( msg, MAX_EVENT_BITS );
if( MSG_ReadOneBit( msg ))
packet_index = MSG_ReadUBitLong( msg, MAX_ENTITY_BITS );
packet_index = MSG_ReadUBitLong( msg, cls.legacymode ? MAX_LEGACY_ENTITY_BITS : MAX_ENTITY_BITS );
else packet_index = -1;
if( MSG_ReadOneBit( msg ))
@ -439,10 +436,6 @@ void CL_ParseEvent( sizebuf_t *msg )
if( args.entindex > 0 && args.entindex <= cl.maxclients )
args.angles[PITCH] /= -3.0f;
}
else
{
MsgDev( D_WARN, "CL_ParseEvent: Received non-packet entity index 0 for event\n" );
}
}
// Place event on queue
@ -462,28 +455,25 @@ void CL_PlaybackEvent( int flags, const edict_t *pInvoker, word eventindex, floa
{
event_args_t args;
if( flags & FEV_SERVER )
{
MsgDev( D_WARN, "CL_PlaybackEvent: event with FEV_SERVER flag!\n" );
if( FBitSet( flags, FEV_SERVER ))
return;
}
// first check event for out of bounds
if( eventindex < 1 || eventindex > MAX_EVENTS )
{
MsgDev( D_ERROR, "CL_PlaybackEvent: invalid eventindex %i\n", eventindex );
Con_DPrintf( S_ERROR "CL_PlaybackEvent: invalid eventindex %i\n", eventindex );
return;
}
// check event for precached
if( !CL_EventIndex( cl.event_precache[eventindex] ))
{
MsgDev( D_ERROR, "CL_PlaybackEvent: event %i was not precached\n", eventindex );
Con_DPrintf( S_ERROR "CL_PlaybackEvent: event %i was not precached\n", eventindex );
return;
}
flags |= FEV_CLIENT; // it's a client event
flags &= ~(FEV_NOTHOST|FEV_HOSTONLY|FEV_GLOBAL);
SetBits( flags, FEV_CLIENT ); // it's a client event
ClearBits( flags, FEV_NOTHOST|FEV_HOSTONLY|FEV_GLOBAL );
if( delay < 0.0f ) delay = 0.0f; // fixup negative delays
memset( &args, 0, sizeof( args ));

View file

@ -96,7 +96,7 @@ we don't want interpolate this
*/
qboolean CL_EntityTeleported( cl_entity_t *ent )
{
int len, maxlen;
float len, maxlen;
vec3_t delta;
VectorSubtract( ent->curstate.origin, ent->prevstate.origin, delta );
@ -270,8 +270,8 @@ void CL_ProcessEntityUpdate( cl_entity_t *ent )
ent->model = CL_ModelHandle( ent->curstate.modelindex );
ent->index = ent->curstate.number;
// g-cont. make sure what it's no broke XashXT physics
COM_NormalizeAngles( ent->curstate.angles );
if( FBitSet( ent->curstate.entityType, ENTITY_NORMAL ))
COM_NormalizeAngles( ent->curstate.angles );
parametric = CL_ParametricMove( ent );
@ -410,8 +410,19 @@ int CL_InterpolateModel( cl_entity_t *e )
if( cls.timedemo || !e->model )
return 1;
if( fabs( cl_serverframetime() - cl_clientframetime()) < 0.0001f )
return 1; // interpolation disabled
if( cls.demoplayback == DEMO_QUAKE1 )
{
// quake lerping is easy
VectorLerp( e->prevstate.origin, cl.lerpFrac, e->curstate.origin, e->origin );
AngleQuaternion( e->prevstate.angles, q1, false );
AngleQuaternion( e->curstate.angles, q2, false );
QuaternionSlerp( q1, q2, cl.lerpFrac, q );
QuaternionAngle( q, e->angles );
return 1;
}
if( cl.maxclients <= 1 )
return 1;
if( e->model->type == mod_brush && !cl_bmodelinterp->value )
return 1;
@ -419,7 +430,6 @@ int CL_InterpolateModel( cl_entity_t *e )
if( cl.local.moving && cl.local.onground == e->index )
return 1;
// t = cl.time - cl_serverframetime();
t = cl.time - cl_interp->value;
CL_FindInterpolationUpdates( e, t, &ph0, &ph1 );
@ -478,12 +488,24 @@ interpolate non-local clients
void CL_ComputePlayerOrigin( cl_entity_t *ent )
{
float targettime;
vec4_t q, q1, q2;
vec3_t origin;
vec3_t angles;
if( !ent->player || ent->index == ( cl.playernum + 1 ))
return;
if( cls.demoplayback == DEMO_QUAKE1 )
{
// quake lerping is easy
VectorLerp( ent->prevstate.origin, cl.lerpFrac, ent->curstate.origin, ent->origin );
AngleQuaternion( ent->prevstate.angles, q1, false );
AngleQuaternion( ent->curstate.angles, q2, false );
QuaternionSlerp( q1, q2, cl.lerpFrac, q );
QuaternionAngle( q, ent->angles );
return;
}
targettime = cl.time - cl_interp->value;
CL_PureOrigin( ent, targettime, origin, angles );
@ -603,13 +625,13 @@ void CL_FlushEntityPacket( sizebuf_t *msg )
// read it all, but ignore it
while( 1 )
{
newnum = MSG_ReadUBitLong( msg, MAX_VISIBLE_PACKET_BITS );
newnum = MSG_ReadUBitLong( msg, MAX_ENTITY_BITS );
if( newnum == LAST_EDICT ) break; // done
if( MSG_CheckOverflow( msg ))
Host_Error( "CL_FlushEntityPacket: overflow\n" );
MSG_ReadDeltaEntity( msg, &from, &to, newnum, CL_IsPlayerIndex( newnum ), cl.mtime[0] );
MSG_ReadDeltaEntity( msg, &from, &to, newnum, CL_IsPlayerIndex( newnum ) ? DELTA_PLAYER : DELTA_ENTITY, cl.mtime[0] );
}
}
@ -626,17 +648,18 @@ void CL_DeltaEntity( sizebuf_t *msg, frame_t *frame, int newnum, entity_state_t
entity_state_t *state;
qboolean newent = (old) ? false : true;
int pack = frame->num_entities;
qboolean player = CL_IsPlayerIndex( newnum );
int delta_type = DELTA_ENTITY;
qboolean alive = true;
// alloc next slot to store update
state = &cls.packet_entities[cls.next_client_entities % cls.num_client_entities];
if( CL_IsPlayerIndex( newnum )) delta_type = DELTA_PLAYER;
if(( newnum < 0 ) || ( newnum >= clgame.maxEntities ))
{
MsgDev( D_ERROR, "CL_DeltaEntity: invalid newnum: %d\n", newnum );
Con_DPrintf( S_ERROR "CL_DeltaEntity: invalid newnum: %d\n", newnum );
if( has_update )
MSG_ReadDeltaEntity( msg, old, state, newnum, player, cl.mtime[0] );
MSG_ReadDeltaEntity( msg, old, state, newnum, delta_type, cl.mtime[0] );
return;
}
@ -645,7 +668,7 @@ void CL_DeltaEntity( sizebuf_t *msg, frame_t *frame, int newnum, entity_state_t
if( newent ) old = &ent->baseline;
if( has_update )
alive = MSG_ReadDeltaEntity( msg, old, state, newnum, player, cl.mtime[0] );
alive = MSG_ReadDeltaEntity( msg, old, state, newnum, delta_type, cl.mtime[0] );
else memcpy( state, old, sizeof( entity_state_t ));
if( !alive )
@ -698,7 +721,10 @@ int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
CL_WriteDemoJumpTime();
// sentinel count. save it for debug checking
count = ( MSG_ReadUBitLong( msg, MAX_VISIBLE_PACKET_BITS ) + 1 );
if( cls.legacymode )
count = MSG_ReadWord( msg );
else count = MSG_ReadUBitLong( msg, MAX_VISIBLE_PACKET_BITS ) + 1;
newframe = &cl.frames[cl.parsecountmod];
// allocate parse entities
@ -733,7 +759,6 @@ int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
if(( cls.next_client_entities - oldframe->first_entity ) > ( cls.num_client_entities - NUM_PACKET_ENTITIES ))
{
MsgDev( D_NOTE, "CL_ParsePacketEntities: delta frame is too old (flush)\n");
Con_NPrintf( 2, "^3Warning:^1 delta frame is too old^7\n" );
CL_FlushEntityPacket( msg );
return playerbytes;
@ -773,9 +798,19 @@ int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
while( 1 )
{
newnum = MSG_ReadUBitLong( msg, MAX_ENTITY_BITS );
if( newnum == LAST_EDICT ) break; // end of packet entities
int lastedict;
if( cls.legacymode )
{
newnum = MSG_ReadWord( msg );
lastedict = 0;
}
else
{
newnum = MSG_ReadUBitLong( msg, MAX_ENTITY_BITS );
lastedict = LAST_EDICT;
}
if( newnum == lastedict ) break; // end of packet entities
if( MSG_CheckOverflow( msg ))
Host_Error( "CL_ParsePacketEntities: overflow\n" );
player = CL_IsPlayerIndex( newnum );
@ -846,7 +881,7 @@ int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
}
if( newframe->num_entities != count && newframe->num_entities != 0 )
MsgDev( D_WARN, "CL_Parse%sPacketEntities: (%i should be %i)\n", delta ? "Delta" : "", newframe->num_entities, count );
Con_Reportf( S_WARN "CL_Parse%sPacketEntities: (%i should be %i)\n", delta ? "Delta" : "", newframe->num_entities, count );
if( !newframe->valid )
return playerbytes; // frame is not valid but message was parsed
@ -942,7 +977,7 @@ void CL_LinkCustomEntity( cl_entity_t *ent, entity_state_t *state )
ent->curstate.movetype = state->modelindex; // !!!
if( ent->model->type != mod_sprite )
MsgDev( D_WARN, "bad model on beam ( %s )\n", ent->model->name );
Con_Reportf( S_WARN "bad model on beam ( %s )\n", ent->model->name );
ent->latched.prevsequence = ent->curstate.sequence;
VectorCopy( ent->origin, ent->latched.prevorigin );
@ -989,9 +1024,12 @@ void CL_LinkPlayers( frame_t *frame )
if( i == cl.playernum )
{
VectorCopy( state->origin, ent->origin );
VectorCopy( state->origin, ent->prevstate.origin );
VectorCopy( state->origin, ent->curstate.origin );
if( cls.demoplayback != DEMO_QUAKE1 )
{
VectorCopy( state->origin, ent->origin );
VectorCopy( state->origin, ent->prevstate.origin );
VectorCopy( state->origin, ent->curstate.origin );
}
VectorCopy( ent->curstate.angles, ent->angles );
}
@ -1007,6 +1045,8 @@ void CL_LinkPlayers( frame_t *frame )
if ( i == cl.playernum )
{
if( cls.demoplayback == DEMO_QUAKE1 )
VectorLerp( ent->prevstate.origin, cl.lerpFrac, ent->curstate.origin, cl.simorg );
VectorCopy( cl.simorg, ent->origin );
}
else
@ -1041,6 +1081,7 @@ void CL_LinkPacketEntities( frame_t *frame )
cl_entity_t *ent;
entity_state_t *state;
qboolean parametric;
qboolean interpolate;
int i;
for( i = 0; i < frame->num_entities; i++ )
@ -1059,22 +1100,21 @@ void CL_LinkPacketEntities( frame_t *frame )
if( !ent )
{
MsgDev( D_ERROR, "CL_LinkPacketEntity: bad entity %i\n", state->number );
Con_Reportf( S_ERROR "CL_LinkPacketEntity: bad entity %i\n", state->number );
continue;
}
ent->curstate = *state;
// XASH SPECIFIC
if( ent->curstate.rendermode == kRenderNormal && ent->curstate.renderfx == kRenderFxNone )
ent->curstate.renderamt = 255.0f;
// animtime must keep an actual
ent->curstate.animtime = state->animtime;
ent->curstate.frame = state->frame;
interpolate = false;
if( !ent->model ) continue;
if( ent->curstate.rendermode == kRenderNormal )
{
// auto 'solid' faces
if( FBitSet( ent->model->flags, MODEL_TRANSPARENT ) && FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
if( FBitSet( ent->model->flags, MODEL_TRANSPARENT ) && Host_IsQuakeCompatible( ))
{
ent->curstate.rendermode = kRenderTransAlpha;
ent->curstate.renderamt = 255;
@ -1095,7 +1135,9 @@ void CL_LinkPacketEntities( frame_t *frame )
#ifdef STUDIO_INTERPOLATION_FIX
if( ent->lastmove >= cl.time )
VectorCopy( ent->curstate.origin, ent->latched.prevorigin );
ent->curstate.movetype = MOVETYPE_STEP;
if( FBitSet( host.features, ENGINE_COMPUTE_STUDIO_LERP ))
interpolate = true;
else ent->curstate.movetype = MOVETYPE_STEP;
#else
if( ent->lastmove >= cl.time )
{
@ -1148,7 +1190,7 @@ void CL_LinkPacketEntities( frame_t *frame )
if( ent->model->type == mod_studio )
{
if( ent->curstate.movetype == MOVETYPE_STEP && FBitSet( host.features, ENGINE_COMPUTE_STUDIO_LERP ))
if( interpolate && FBitSet( host.features, ENGINE_COMPUTE_STUDIO_LERP ))
R_StudioLerpMovement( ent, cl.time, ent->origin, ent->angles );
}
}
@ -1166,6 +1208,10 @@ void CL_LinkPacketEntities( frame_t *frame )
ent->curstate.rendercolor.r = ent->curstate.rendercolor.g = ent->curstate.rendercolor.b = 255;
}
// XASH SPECIFIC
if( ent->curstate.rendermode == kRenderNormal && ent->curstate.renderfx == kRenderFxNone )
ent->curstate.renderamt = 255.0f;
if( ent->curstate.aiment != 0 && ent->curstate.movetype != MOVETYPE_COMPOUND )
ent->curstate.movetype = MOVETYPE_FOLLOW;
@ -1226,6 +1272,12 @@ void CL_EmitEntities( void )
if( !cl.frames[cl.parsecountmod].valid )
return;
// animate lightestyles
CL_RunLightStyles ();
// decay dynamic lights
CL_DecayLights ();
// compute last interpolation amount
CL_UpdateFrameLerp ();
@ -1313,8 +1365,25 @@ qboolean CL_GetEntitySpatialization( channel_t *ch )
qboolean CL_GetMovieSpatialization( rawchan_t *ch )
{
// UNDONE
return false;
cl_entity_t *ent;
qboolean valid_origin;
valid_origin = VectorIsNull( ch->origin ) ? false : true;
ent = CL_GetEntityByIndex( ch->entnum );
// entity is not present on the client but has valid origin
if( !ent || !ent->index || ent->curstate.messagenum == 0 )
return valid_origin;
// setup origin
VectorAverage( ent->curstate.mins, ent->curstate.maxs, ch->origin );
VectorAdd( ch->origin, ent->curstate.origin, ch->origin );
// setup radius
if( ent->model != NULL && ent->model->radius ) ch->radius = ent->model->radius;
else ch->radius = RadiusFromBounds( ent->curstate.mins, ent->curstate.maxs );
return true;
}
void CL_ExtraUpdate( void )

View file

@ -29,9 +29,7 @@ GNU General Public License for more details.
#include "library.h"
#include "vgui_draw.h"
#include "sound.h" // SND_STOP_LOOPING
#ifdef XASH_SDL
#include <SDL.h>
#endif
#include "platform/platform.h"
#define MAX_LINELENGTH 80
#define MAX_TEXTCHANNELS 8 // must be power of two (GoldSrc uses 4 channels)
@ -243,7 +241,7 @@ void CL_InitCDAudio( const char *filename )
if( ++c > MAX_CDTRACKS - 1 )
{
MsgDev( D_WARN, "CD_Init: too many tracks %i in %s\n", MAX_CDTRACKS, filename );
Con_Reportf( S_WARN "CD_Init: too many tracks %i in %s\n", MAX_CDTRACKS, filename );
break;
}
}
@ -832,14 +830,14 @@ const char *CL_SoundFromIndex( int index )
if( !hSound )
{
MsgDev( D_ERROR, "CL_SoundFromIndex: invalid sound index %i\n", index );
Con_DPrintf( S_ERROR "CL_SoundFromIndex: invalid sound index %i\n", index );
return NULL;
}
sfx = S_GetSfxByHandle( hSound );
if( !sfx )
{
MsgDev( D_ERROR, "CL_SoundFromIndex: bad sfx for index %i\n", index );
Con_DPrintf( S_ERROR "CL_SoundFromIndex: bad sfx for index %i\n", index );
return NULL;
}
@ -1065,7 +1063,7 @@ void CL_LinkUserMessage( char *pszName, const int svc_num, int iSize )
for( i = 0; i < MAX_USER_MESSAGES && clgame.msg[i].name[0]; i++ )
{
// NOTE: no check for DispatchFunc, check only name
if( !Q_strcmp( clgame.msg[i].name, pszName ))
if( !Q_stricmp( clgame.msg[i].name, pszName ))
{
clgame.msg[i].number = svc_num;
clgame.msg[i].size = iSize;
@ -1115,16 +1113,16 @@ void CL_InitEdicts( void )
CL_UPDATE_BACKUP = ( cl.maxclients == 1 ) ? SINGLEPLAYER_BACKUP : MULTIPLAYER_BACKUP;
cls.num_client_entities = CL_UPDATE_BACKUP * NUM_PACKET_ENTITIES;
cls.packet_entities = Z_Realloc( cls.packet_entities, sizeof( entity_state_t ) * cls.num_client_entities );
clgame.entities = Mem_Alloc( clgame.mempool, sizeof( cl_entity_t ) * clgame.maxEntities );
clgame.static_entities = Mem_Alloc( clgame.mempool, sizeof( cl_entity_t ) * MAX_STATIC_ENTITIES );
cls.packet_entities = Mem_Realloc( clgame.mempool, cls.packet_entities, sizeof( entity_state_t ) * cls.num_client_entities );
clgame.entities = Mem_Calloc( clgame.mempool, sizeof( cl_entity_t ) * clgame.maxEntities );
clgame.static_entities = Mem_Calloc( clgame.mempool, sizeof( cl_entity_t ) * MAX_STATIC_ENTITIES );
clgame.numStatics = 0;
if(( clgame.maxRemapInfos - 1 ) != clgame.maxEntities )
{
CL_ClearAllRemaps (); // purge old remap info
clgame.maxRemapInfos = clgame.maxEntities + 1;
clgame.remap_info = (remap_info_t **)Mem_Alloc( clgame.mempool, sizeof( remap_info_t* ) * clgame.maxRemapInfos );
clgame.remap_info = (remap_info_t **)Mem_Calloc( clgame.mempool, sizeof( remap_info_t* ) * clgame.maxRemapInfos );
}
if( clgame.drawFuncs.R_ProcessEntData != NULL )
@ -1217,6 +1215,7 @@ static qboolean CL_LoadHudSprite( const char *szSpriteName, model_t *m_pSprite,
}
else
{
Con_Reportf( S_ERROR "%s couldn't load\n", szSpriteName );
Mod_UnloadSpriteModel( m_pSprite );
return false;
}
@ -1258,7 +1257,7 @@ static model_t *CL_LoadSpriteModel( const char *filename, uint type, uint texFla
if( !COM_CheckString( filename ))
{
MsgDev( D_ERROR, "CL_LoadSpriteModel: bad name!\n" );
Con_Reportf( S_ERROR "CL_LoadSpriteModel: bad name!\n" );
return NULL;
}
@ -1535,7 +1534,7 @@ static client_sprite_t *pfnSPR_GetList( char *psz, int *piCount )
Q_strncpy( pEntry->szListName, psz, sizeof( pEntry->szListName ));
// name, res, pic, x, y, w, h
pEntry->pList = Mem_Alloc( cls.mempool, sizeof( client_sprite_t ) * numSprites );
pEntry->pList = Mem_Calloc( cls.mempool, sizeof( client_sprite_t ) * numSprites );
for( index = 0; index < numSprites; index++ )
{
@ -1584,12 +1583,14 @@ CL_FillRGBA
*/
void CL_FillRGBA( int x, int y, int w, int h, int r, int g, int b, int a )
{
float _x = x, _y = y, _w = w, _h = h;
r = bound( 0, r, 255 );
g = bound( 0, g, 255 );
b = bound( 0, b, 255 );
a = bound( 0, a, 255 );
SPR_AdjustSize( (float *)&x, (float *)&y, (float *)&w, (float *)&h );
SPR_AdjustSize( &_x, &_y, &_w, &_h );
pglDisable( GL_TEXTURE_2D );
pglEnable( GL_BLEND );
@ -1598,10 +1599,10 @@ void CL_FillRGBA( int x, int y, int w, int h, int r, int g, int b, int a )
pglColor4f( r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f );
pglBegin( GL_QUADS );
pglVertex2f( x, y );
pglVertex2f( x + w, y );
pglVertex2f( x + w, y + h );
pglVertex2f( x, y + h );
pglVertex2f( _x, _y );
pglVertex2f( _x + _w, _y );
pglVertex2f( _x + _w, _y + _h );
pglVertex2f( _x, _y + _h );
pglEnd ();
pglColor3f( 1.0f, 1.0f, 1.0f );
@ -1682,7 +1683,7 @@ static int pfnHookUserMsg( const char *pszName, pfnUserMsgHook pfn )
for( i = 0; i < MAX_USER_MESSAGES && clgame.msg[i].name[0]; i++ )
{
// see if already hooked
if( !Q_strcmp( clgame.msg[i].name, pszName ))
if( !Q_stricmp( clgame.msg[i].name, pszName ))
return 1;
}
@ -1709,7 +1710,7 @@ static int pfnServerCmd( const char *szCmdString )
{
string buf;
if( !szCmdString || !szCmdString[0] )
if( !COM_CheckString( szCmdString ))
return 0;
// just like the client typed "cmd xxxxx" at the console
@ -1727,11 +1728,20 @@ pfnClientCmd
*/
static int pfnClientCmd( const char *szCmdString )
{
if( !szCmdString || !szCmdString[0] )
if( !COM_CheckString( szCmdString ))
return 0;
Cbuf_AddText( szCmdString );
Cbuf_AddText( "\n" );
if( cls.initialized )
{
Cbuf_AddText( szCmdString );
Cbuf_AddText( "\n" );
}
else
{
// will exec later
Q_strncat( host.deferred_cmd, va( "%s\n", szCmdString ), sizeof( host.deferred_cmd ));
}
return 1;
}
@ -1790,12 +1800,8 @@ static void pfnPlaySoundByIndex( int iSound, float volume )
// make sure what we in-bounds
iSound = bound( 0, iSound, MAX_SOUNDS );
hSound = cl.sound_index[iSound];
if( !hSound ) return;
if( !hSound )
{
MsgDev( D_ERROR, "CL_PlaySoundByIndex: invalid sound handle %i\n", iSound );
return;
}
S_StartSound( NULL, cl.viewentity, CHAN_ITEM, hSound, volume, ATTN_NORM, PITCH_NORM, SND_STOP_LOOPING );
}
@ -1866,7 +1872,8 @@ int pfnDrawConsoleString( int x, int y, char *string )
{
int drawLen;
if( !string || !*string ) return 0; // silent ignore
if( !COM_CheckString( string ))
return 0; // silent ignore
Con_SetFont( con_fontsize->value );
clgame.ds.adjust_size = true;
@ -1942,7 +1949,21 @@ GetWindowCenterX
*/
static int pfnGetWindowCenterX( void )
{
return host.window_center_x;
int x = 0;
#ifdef _WIN32
if( m_ignore->value )
{
POINT pos;
GetCursorPos( &pos );
return pos.x;
}
#endif
#ifdef XASH_SDL
SDL_GetWindowPosition( host.hWnd, &x, NULL );
#endif
return host.window_center_x + x;
}
/*
@ -1953,7 +1974,21 @@ GetWindowCenterY
*/
static int pfnGetWindowCenterY( void )
{
return host.window_center_y;
int y = 0;
#ifdef _WIN32
if( m_ignore->value )
{
POINT pos;
GetCursorPos( &pos );
return pos.y;
}
#endif
#ifdef XASH_SDL
SDL_GetWindowPosition( host.hWnd, NULL, &y );
#endif
return host.window_center_y + y;
}
/*
@ -2014,22 +2049,6 @@ static float pfnGetClientMaxspeed( void )
return cl.local.maxspeed;
}
/*
=============
CL_GetMousePosition
=============
*/
void CL_GetMousePosition( int *mx, int *my )
{
#ifdef XASH_SDL
SDL_GetMouseState( mx, my );
#else
if( mx ) *mx = 0;
if( my ) *my = 0;
#endif
}
/*
=============
pfnIsNoClipping
@ -2239,7 +2258,7 @@ static void pfnHookEvent( const char *filename, pfnEventHook pfn )
if( !Q_stricmp( name, ev->name ) && ev->func != NULL )
{
MsgDev( D_WARN, "CL_HookEvent: %s already hooked!\n", name );
Con_Reportf( S_WARN "CL_HookEvent: %s already hooked!\n", name );
return;
}
}
@ -2720,7 +2739,7 @@ pfnServerCmdUnreliable
*/
int pfnServerCmdUnreliable( char *szCmdString )
{
if( !szCmdString || !szCmdString[0] )
if( !COM_CheckString( szCmdString ))
return 0;
MSG_BeginClientCmd( &cls.datagram, clc_stringcmd );
@ -2740,20 +2759,7 @@ void pfnGetMousePos( struct tagPOINT *ppt )
if( !ppt )
return;
CL_GetMousePosition( &ppt->x, &ppt->y );
}
/*
=============
pfnSetMousePos
=============
*/
void pfnSetMousePos( int mx, int my )
{
#ifdef XASH_SDL
SDL_WarpMouseInWindow( host.hWnd, mx, my );
#endif
Platform_GetMousePos( &ppt->x, &ppt->y );
}
/*
@ -2992,12 +2998,14 @@ pfnFillRGBABlend
*/
void GAME_EXPORT CL_FillRGBABlend( int x, int y, int w, int h, int r, int g, int b, int a )
{
float _x = x, _y = y, _w = w, _h = h;
r = bound( 0, r, 255 );
g = bound( 0, g, 255 );
b = bound( 0, b, 255 );
a = bound( 0, a, 255 );
SPR_AdjustSize( (float *)&x, (float *)&y, (float *)&w, (float *)&h );
SPR_AdjustSize( &_x, &_y, &_w, &_h );
pglDisable( GL_TEXTURE_2D );
pglEnable( GL_BLEND );
@ -3006,10 +3014,10 @@ void GAME_EXPORT CL_FillRGBABlend( int x, int y, int w, int h, int r, int g, int
pglColor4f( r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f );
pglBegin( GL_QUADS );
pglVertex2f( x, y );
pglVertex2f( x + w, y );
pglVertex2f( x + w, y + h );
pglVertex2f( x, y + h );
pglVertex2f( _x, _y );
pglVertex2f( _x + _w, _y );
pglVertex2f( _x + _w, _y + _h );
pglVertex2f( _x, _y + _h );
pglEnd ();
pglColor3f( 1.0f, 1.0f, 1.0f );
@ -3525,7 +3533,7 @@ void NetAPI_SendRequest( int context, int request, int flags, double timeout, ne
if( !response )
{
MsgDev( D_ERROR, "Net_SendRequest: no callbcak specified for request with context %i!\n", context );
Con_DPrintf( S_ERROR "Net_SendRequest: no callbcak specified for request with context %i!\n", context );
return;
}
@ -3908,6 +3916,8 @@ static event_api_t gEventApi =
CL_VisTraceLine,
pfnGetVisent,
CL_TestLine,
CL_PushTraceBounds,
CL_PopTraceBounds,
};
static demo_api_t gDemoApi =
@ -3993,7 +4003,7 @@ static cl_enginefunc_t gEngfuncs =
pfnGetClientMaxspeed,
COM_CheckParm,
Key_Event,
CL_GetMousePosition,
Platform_GetMousePos,
pfnIsNoClipping,
CL_GetLocalPlayer,
pfnGetViewModel,
@ -4043,7 +4053,7 @@ static cl_enginefunc_t gEngfuncs =
pfnGetPlayerForTrackerID,
pfnServerCmdUnreliable,
pfnGetMousePos,
pfnSetMousePos,
Platform_SetMousePos,
pfnSetMouseEnable,
Cvar_GetList,
(void*)Cmd_GetFirstFunctionHandle,
@ -4139,7 +4149,7 @@ qboolean CL_LoadProgs( const char *name )
// trying to get single export
if(( GetClientAPI = (void *)COM_GetProcAddress( clgame.hInstance, "GetClientAPI" )) != NULL )
{
MsgDev( D_NOTE, "CL_LoadProgs: found single callback export\n" );
Con_Reportf( "CL_LoadProgs: found single callback export\n" );
// trying to fill interface now
GetClientAPI( &clgame.dllFuncs );
@ -4164,7 +4174,7 @@ qboolean CL_LoadProgs( const char *name )
// functions are cleared before all the extensions are evaluated
if(( *func->func = (void *)COM_GetProcAddress( clgame.hInstance, func->name )) == NULL )
{
MsgDev( D_NOTE, "CL_LoadProgs: failed to get address of %s proc\n", func->name );
Con_Reportf( "CL_LoadProgs: failed to get address of %s proc\n", func->name );
if( critical_exports )
{
@ -4191,13 +4201,13 @@ qboolean CL_LoadProgs( const char *name )
// functions are cleared before all the extensions are evaluated
// NOTE: new exports can be missed without stop the engine
if(( *func->func = (void *)COM_GetProcAddress( clgame.hInstance, func->name )) == NULL )
MsgDev( D_NOTE, "CL_LoadProgs: failed to get address of %s proc\n", func->name );
Con_Reportf( "CL_LoadProgs: failed to get address of %s proc\n", func->name );
}
if( !clgame.dllFuncs.pfnInitialize( &gEngfuncs, CLDLL_INTERFACE_VERSION ))
{
COM_FreeLibrary( clgame.hInstance );
MsgDev( D_NOTE, "CL_LoadProgs: can't init client API\n" );
Con_Reportf( "CL_LoadProgs: can't init client API\n" );
clgame.hInstance = NULL;
return false;
}

View file

@ -31,6 +31,19 @@ void UI_UpdateMenu( float realtime )
{
if( !gameui.hInstance ) return;
// if some deferred cmds is waiting
if( UI_IsVisible() && COM_CheckString( host.deferred_cmd ))
{
Cbuf_AddText( host.deferred_cmd );
host.deferred_cmd[0] = '\0';
Cbuf_Execute();
return;
}
// don't show menu while level is loaded
if( GameState->nextstate != STATE_RUNFRAME && !GameState->loadGame )
return;
// menu time (not paused, not clamped)
gameui.globals->time = host.realtime;
gameui.globals->frametime = host.realframetime;
@ -148,7 +161,7 @@ static void UI_DrawLogo( const char *filename, float x, float y, float width, fl
if( FS_FileExists( path, false ) && !fullpath )
{
MsgDev( D_ERROR, "Couldn't load %s from packfile. Please extract it\n", path );
Con_Printf( S_ERROR "Couldn't load %s from packfile. Please extract it\n", path );
gameui.drawLogo = false;
return;
}
@ -249,6 +262,8 @@ static void UI_ConvertGameInfo( GAMEINFO *out, gameinfo_t *in )
if( in->nomodels )
out->flags |= GFL_NOMODELS;
if( in->noskills )
out->flags |= GFL_NOSKILLS;
}
static qboolean PIC_Scissor( float *x, float *y, float *width, float *height, float *u0, float *v0, float *u1, float *v1 )
@ -361,13 +376,13 @@ pfnPIC_Load
=========
*/
static HIMAGE pfnPIC_Load( const char *szPicName, const byte *image_buf, long image_size, long flags )
static HIMAGE pfnPIC_Load( const char *szPicName, const byte *image_buf, int image_size, int flags )
{
HIMAGE tx;
if( !szPicName || !*szPicName )
{
MsgDev( D_ERROR, "CL_LoadImage: bad name!\n" );
Con_Reportf( S_ERROR "CL_LoadImage: bad name!\n" );
return 0;
}
@ -375,7 +390,7 @@ static HIMAGE pfnPIC_Load( const char *szPicName, const byte *image_buf, long im
SetBits( flags, TF_IMAGE );
Image_SetForceFlags( IL_LOAD_DECAL ); // allow decal images for menu
tx = GL_LoadTexture( szPicName, image_buf, image_size, flags, NULL );
tx = GL_LoadTexture( szPicName, image_buf, image_size, flags );
Image_ClearForceFlags();
return tx;
@ -700,15 +715,19 @@ for drawing playermodel previews
*/
static void pfnRenderScene( const ref_viewpass_t *rvp )
{
ref_viewpass_t copy;
// to avoid division by zero
if( !rvp || rvp->fov_x <= 0.0f || rvp->fov_y <= 0.0f )
return;
copy = *rvp;
// don't allow special modes from menu
((ref_viewpass_t *)&rvp)->flags = 0;
copy.flags = 0;
R_Set2DMode( false );
R_RenderFrame( rvp );
R_RenderFrame( &copy );
R_Set2DMode( true );
R_PopScene();
}
@ -785,7 +804,7 @@ pfnMemAlloc
*/
static void *pfnMemAlloc( size_t cb, const char *filename, const int fileline )
{
return _Mem_Alloc( gameui.mempool, cb, filename, fileline );
return _Mem_Alloc( gameui.mempool, cb, true, filename, fileline );
}
/*
@ -886,7 +905,7 @@ int pfnCheckGameDll( void )
COM_FreeLibrary( hInst ); // don't increase linker's reference counter
return true;
}
MsgDev( D_WARN, "Could not load server library:\n%s", COM_GetLibraryError() );
Con_Reportf( S_WARN "Could not load server library:\n%s", COM_GetLibraryError() );
return false;
}
@ -1080,7 +1099,7 @@ qboolean UI_LoadProgs( void )
if(( GetMenuAPI = (MENUAPI)COM_GetProcAddress( gameui.hInstance, "GetMenuAPI" )) == NULL )
{
COM_FreeLibrary( gameui.hInstance );
MsgDev( D_NOTE, "UI_LoadProgs: can't init menu API\n" );
Con_Reportf( "UI_LoadProgs: can't init menu API\n" );
gameui.hInstance = NULL;
return false;
}
@ -1088,21 +1107,6 @@ qboolean UI_LoadProgs( void )
gameui.use_text_api = false;
if( ( GiveTextApi = (UITEXTAPI)COM_GetProcAddress( gameui.hInstance, "GiveTextAPI" ) ) )
{
MsgDev( D_NOTE, "UI_LoadProgs: extended Text API initialized\n" );
// make local copy of engfuncs to prevent overwrite it with user dll
memcpy( &gpTextfuncs, &gTextfuncs, sizeof( gpTextfuncs ));
if( GiveTextApi( &gpTextfuncs ) )
gameui.use_text_api = true;
}
pfnAddTouchButtonToList = (ADDTOUCHBUTTONTOLIST)COM_GetProcAddress( gameui.hInstance, "AddTouchButtonToList" );
if( pfnAddTouchButtonToList )
{
MsgDev( D_NOTE, "UI_LoadProgs: AddTouchButtonToList call found\n" );
}
// make local copy of engfuncs to prevent overwrite it with user dll
memcpy( &gpEngfuncs, &gEngfuncs, sizeof( gpEngfuncs ));
@ -1111,18 +1115,33 @@ qboolean UI_LoadProgs( void )
if( !GetMenuAPI( &gameui.dllFuncs, &gpEngfuncs, gameui.globals ))
{
COM_FreeLibrary( gameui.hInstance );
MsgDev( D_NOTE, "UI_LoadProgs: can't init menu API\n" );
Con_Reportf( "UI_LoadProgs: can't init menu API\n" );
Mem_FreePool( &gameui.mempool );
gameui.hInstance = NULL;
return false;
}
if( ( GiveTextApi = (UITEXTAPI)COM_GetProcAddress( gameui.hInstance, "GiveTextAPI" ) ) )
{
Con_Reportf( "UI_LoadProgs: extended Text API initialized\n" );
// make local copy of engfuncs to prevent overwrite it with user dll
memcpy( &gpTextfuncs, &gTextfuncs, sizeof( gpTextfuncs ));
if( GiveTextApi( &gpTextfuncs ) )
gameui.use_text_api = true;
}
pfnAddTouchButtonToList = (ADDTOUCHBUTTONTOLIST)COM_GetProcAddress( gameui.hInstance, "AddTouchButtonToList" );
if( pfnAddTouchButtonToList )
{
Con_Reportf( "UI_LoadProgs: AddTouchButtonToList call found\n" );
}
Cvar_FullSet( "host_gameuiloaded", "1", FCVAR_READ_ONLY );
// setup gameinfo
for( i = 0; i < SI.numgames; i++ )
{
gameui.modsInfo[i] = Mem_Alloc( gameui.mempool, sizeof( GAMEINFO ));
gameui.modsInfo[i] = Mem_Calloc( gameui.mempool, sizeof( GAMEINFO ));
UI_ConvertGameInfo( gameui.modsInfo[i], SI.games[i] );
}

View file

@ -83,6 +83,8 @@ client_t cl;
client_static_t cls;
clgame_static_t clgame;
void CL_InternetServers_f( void );
//======================================================================
int CL_Active( void )
{
@ -213,7 +215,7 @@ An svc_signonnum has been received, perform a client side setup
void CL_SignonReply( void )
{
// g-cont. my favorite message :-)
Con_DPrintf( "CL_SignonReply: %i\n", cls.signon );
Con_Reportf( "CL_SignonReply: %i\n", cls.signon );
switch( cls.signon )
{
@ -247,14 +249,31 @@ static float CL_LerpPoint( void )
if( f == 0.0f || cls.timedemo )
{
cl.time = cl.mtime[0];
// g-cont. probably this is redundant
if( cls.demoplayback )
cl.oldtime = cl.mtime[0] - cl_clientframetime();
return 1.0f;
}
if( f > 0.1f )
{
// dropped packet, or start of demo
cl.mtime[1] = cl.mtime[0] - 0.1f;
f = 0.1f;
}
#if 1
frac = (cl.time - cl.mtime[1]) / f;
if( frac < 0.0f )
{
if( frac < -0.01 )
cl.time = cl.mtime[1];
frac = 0.0f;
}
else if( frac > 1.0f )
{
if( frac > 1.01 )
cl.time = cl.mtime[0];
frac = 1.0f;
}
#else
if( cl_interp->value > 0.001f )
{
// manual lerp value (goldsrc mode)
@ -265,7 +284,7 @@ static float CL_LerpPoint( void )
// automatic lerp (classic mode)
frac = ( cl.time - cl.mtime[1] ) / f;
}
#endif
return frac;
}
@ -888,16 +907,10 @@ void CL_BeginUpload_f( void )
name = Cmd_Argv( 1 );
if( !COM_CheckString( name ))
{
MsgDev( D_ERROR, "upload without filename\n" );
return;
}
if( !cl_allow_upload.value )
{
MsgDev( D_WARN, "ingoring decal upload ( cl_allow_upload is 0 )\n" );
return;
}
if( Q_strlen( name ) != 36 || Q_strnicmp( name, "!MD5", 4 ))
{
@ -912,7 +925,7 @@ void CL_BeginUpload_f( void )
{
if( memcmp( md5, custResource.rgucMD5_hash, 16 ))
{
MsgDev( D_REPORT, "Bogus data retrieved from %s, attempting to delete entry\n", CUSTOM_RES_PATH );
Con_Reportf( "Bogus data retrieved from %s, attempting to delete entry\n", CUSTOM_RES_PATH );
HPAK_RemoveLump( CUSTOM_RES_PATH, &custResource );
return;
}
@ -929,26 +942,22 @@ void CL_BeginUpload_f( void )
if( memcmp( custResource.rgucMD5_hash, md5, 16 ))
{
MsgDev( D_REPORT, "HPAK_AddLump called with bogus lump, md5 mismatch\n" );
MsgDev( D_REPORT, "Purported: %s\n", MD5_Print( custResource.rgucMD5_hash ) );
MsgDev( D_REPORT, "Actual : %s\n", MD5_Print( md5 ) );
MsgDev( D_REPORT, "Removing conflicting lump\n" );
Con_Reportf( "HPAK_AddLump called with bogus lump, md5 mismatch\n" );
Con_Reportf( "Purported: %s\n", MD5_Print( custResource.rgucMD5_hash ) );
Con_Reportf( "Actual : %s\n", MD5_Print( md5 ) );
Con_Reportf( "Removing conflicting lump\n" );
HPAK_RemoveLump( CUSTOM_RES_PATH, &custResource );
return;
}
}
}
if( buf && size )
if( buf && size > 0 )
{
Netchan_CreateFileFragmentsFromBuffer( &cls.netchan, name, buf, size );
Netchan_FragSend( &cls.netchan );
Mem_Free( buf );
}
else
{
MsgDev( D_REPORT, "ingoring customization upload, couldn't find decal locally\n" );
}
}
/*
@ -1003,10 +1012,40 @@ void CL_SendConnectPacket( void )
key = ID_GetMD5();
memset( protinfo, 0, sizeof( protinfo ));
Info_SetValueForKey( protinfo, "uuid", key, sizeof( protinfo ));
Info_SetValueForKey( protinfo, "qport", qport, sizeof( protinfo ));
Netchan_OutOfBandPrint( NS_CLIENT, adr, "connect %i %i \"%s\" \"%s\"\n", PROTOCOL_VERSION, cls.challenge, protinfo, cls.userinfo );
if( cls.legacymode )
{
// set related userinfo keys
if( cl_dlmax->value >= 40000 || cl_dlmax->value < 100 )
Cvar_FullSet( "cl_maxpacket", "1400", FCVAR_USERINFO );
else
Cvar_FullSet( "cl_maxpacket", cl_dlmax->string, FCVAR_USERINFO );
Cvar_FullSet( "cl_maxpayload", "1000", FCVAR_USERINFO );
/// TODO: add input devices list
//Info_SetValueForKey( protinfo, "d", va( "%d", input_devices ), sizeof( protinfo ) );
Info_SetValueForKey( protinfo, "v", XASH_VERSION, sizeof( protinfo ) );
Info_SetValueForKey( protinfo, "b", va( "%d", Q_buildnum() ), sizeof( protinfo ) );
Info_SetValueForKey( protinfo, "o", Q_buildos(), sizeof( protinfo ) );
Info_SetValueForKey( protinfo, "a", Q_buildarch(), sizeof( protinfo ) );
Info_SetValueForKey( protinfo, "i", ID_GetMD5(), sizeof( protinfo ) );
Netchan_OutOfBandPrint( NS_CLIENT, adr, "connect %i %i %i \"%s\" 2 \"%s\"\n",
PROTOCOL_LEGACY_VERSION, Q_atoi( qport ), cls.challenge, cls.userinfo, protinfo );
Con_Printf( "Trying to connect by legacy protocol\n" );
}
else
{
// remove useless userinfo keys
Cvar_FullSet( "cl_maxpacket", "0", 0 );
Cvar_FullSet( "cl_maxpayload", "1000", 0 );
Info_SetValueForKey( protinfo, "uuid", key, sizeof( protinfo ));
Info_SetValueForKey( protinfo, "qport", qport, sizeof( protinfo ));
Netchan_OutOfBandPrint( NS_CLIENT, adr, "connect %i %i \"%s\" \"%s\"\n", PROTOCOL_VERSION, cls.challenge, protinfo, cls.userinfo );
Con_Printf( "Trying to connect by modern protocol\n" );
}
cls.timestart = Sys_DoubleTime();
}
@ -1020,6 +1059,10 @@ Resend a connect message if the last one has timed out
void CL_CheckForResend( void )
{
netadr_t adr;
int res;
if( cls.internetservers_wait )
CL_InternetServers_f();
// if the local server is running and we aren't then connect
if( cls.state == ca_disconnected && SV_Active( ))
@ -1044,17 +1087,24 @@ void CL_CheckForResend( void )
if(( host.realtime - cls.connect_time ) < cl_resend.value )
return;
if( !NET_StringToAdr( cls.servername, &adr ))
res = NET_StringToAdrNB( cls.servername, &adr );
if( !res )
{
MsgDev( D_ERROR, "CL_CheckForResend: bad server address\n" );
CL_Disconnect();
return;
}
if( res == 2 )
{
cls.connect_time = MAX_HEARTBEAT;
return;
}
// only retry so many times before failure.
if( cls.connect_retry >= CL_CONNECTION_RETRIES )
{
MsgDev( D_ERROR, "CL_CheckForResend: couldn't connected\n" );
Con_DPrintf( S_ERROR "CL_CheckForResend: couldn't connected\n" );
CL_Disconnect();
return;
}
@ -1078,9 +1128,10 @@ void CL_CheckForResend( void )
Con_Printf( "Connecting to %s... [retry #%i]\n", cls.servername, cls.connect_retry );
if( cl_test_bandwidth.value )
if( !cls.legacymode && cl_test_bandwidth.value )
Netchan_OutOfBandPrint( NS_CLIENT, adr, "bandwidth %i %i\n", PROTOCOL_VERSION, cls.max_fragment_size );
else Netchan_OutOfBandPrint( NS_CLIENT, adr, "getchallenge\n" );
else
Netchan_OutOfBandPrint( NS_CLIENT, adr, "getchallenge\n" );
}
resource_t *CL_AddResource( resourcetype_t type, const char *name, int size, qboolean bFatalIfMissing, int index )
@ -1145,8 +1196,14 @@ CL_Connect_f
void CL_Connect_f( void )
{
string server;
qboolean legacyconnect = false;
if( Cmd_Argc() != 2 )
// hidden hint to connect by using legacy protocol
if( Cmd_Argc() == 3 )
{
legacyconnect = !Q_strcmp( Cmd_Argv( 2 ), "legacy" );
}
else if( Cmd_Argc() != 2 )
{
Con_Printf( S_USAGE "connect <server>\n" );
return;
@ -1166,6 +1223,7 @@ void CL_Connect_f( void )
Key_SetKeyDest( key_console );
cls.state = ca_connecting;
cls.legacymode = legacyconnect;
Q_strncpy( cls.servername, server, sizeof( cls.servername ));
cls.connect_time = MAX_HEARTBEAT; // CL_CheckForResend() will fire immediately
cls.max_fragment_size = FRAGMENT_MAX_SIZE; // guess a we can establish connection with maximum fragment size
@ -1317,6 +1375,19 @@ void CL_Reconnect( qboolean setup_netchan )
if( setup_netchan )
{
Netchan_Setup( NS_CLIENT, &cls.netchan, net_from, Cvar_VariableInteger( "net_qport" ), NULL, CL_GetFragmentSize );
if( cls.legacymode )
{
unsigned int extensions = Q_atoi( Cmd_Argv( 1 ) );
if( extensions & NET_EXT_SPLIT )
{
// only enable incoming split for legacy mode
cls.netchan.split = true;
Con_Reportf( "^2NET_EXT_SPLIT enabled^7 (packet sizes is %d/%d)\n", (int)cl_dlmax->value, 65536 );
}
}
}
else
{
@ -1351,6 +1422,8 @@ This is also called on Host_Error, so it shouldn't cause any errors
*/
void CL_Disconnect( void )
{
cls.legacymode = false;
if( cls.state == ca_disconnected )
return;
@ -1370,6 +1443,7 @@ void CL_Disconnect( void )
Netchan_Clear( &cls.netchan );
cls.state = ca_disconnected;
cls.set_lastdemo = false;
cls.connect_retry = 0;
cls.signon = 0;
@ -1424,6 +1498,8 @@ void CL_LocalServers_f( void )
Netchan_OutOfBandPrint( NS_CLIENT, adr, "info %i", PROTOCOL_VERSION );
}
#define MS_SCAN_REQUEST "1\xFF" "0.0.0.0:0\0"
/*
=================
CL_InternetServers_f
@ -1431,23 +1507,27 @@ CL_InternetServers_f
*/
void CL_InternetServers_f( void )
{
netadr_t adr;
char fullquery[512] = "1\xFF" "0.0.0.0:0\0" "\\gamedir\\";
char fullquery[512] = MS_SCAN_REQUEST;
char *info = fullquery + sizeof( MS_SCAN_REQUEST ) - 1;
const size_t remaining = sizeof( fullquery ) - sizeof( MS_SCAN_REQUEST );
Con_Printf( "Scanning for servers on the internet area...\n" );
NET_Config( true ); // allow remote
if( !NET_StringToAdr( MASTERSERVER_ADR, &adr ) )
MsgDev( D_ERROR, "Can't resolve adr: %s\n", MASTERSERVER_ADR );
Con_Printf( "Scanning for servers on the internet area...\n" );
Info_SetValueForKey( info, "gamedir", GI->gamefolder, remaining );
Info_SetValueForKey( info, "clver", XASH_VERSION, remaining ); // let master know about client version
// Info_SetValueForKey( info, "nat", cl_nat->string, remaining );
Q_strcpy( &fullquery[22], GI->gamefolder );
cls.internetservers_wait = NET_SendToMasters( NS_CLIENT, sizeof( MS_SCAN_REQUEST ) + Q_strlen( info ), fullquery );
cls.internetservers_pending = true;
NET_SendPacket( NS_CLIENT, Q_strlen( GI->gamefolder ) + 23, fullquery, adr );
// now we clearing the vgui request
if( clgame.master_request != NULL )
memset( clgame.master_request, 0, sizeof( net_request_t ));
clgame.request_type = NET_REQUEST_GAMEUI;
if( !cls.internetservers_wait )
{
// now we clearing the vgui request
if( clgame.master_request != NULL )
memset( clgame.master_request, 0, sizeof( net_request_t ));
clgame.request_type = NET_REQUEST_GAMEUI;
}
}
/*
@ -1562,11 +1642,21 @@ void CL_ParseStatusMessage( netadr_t from, sizebuf_t *msg )
CL_FixupColorStringsForInfoString( s, infostring );
if( Q_strstr( infostring, "wrong version" ) )
{
Netchan_OutOfBandPrint( NS_CLIENT, from, "info %i", PROTOCOL_LEGACY_VERSION );
Con_Printf( "^1Server^7: %s, Info: %s\n", NET_AdrToString( from ), infostring );
return;
}
if( !COM_CheckString( Info_ValueForKey( infostring, "gamedir" )))
return; // unsupported proto
{
Con_Printf( "^1Server^7: %s, Info: %s\n", NET_AdrToString( from ), infostring );
return; // unsupported proto
}
// more info about servers
Con_Printf( "Server: %s, Game: %s\n", NET_AdrToString( from ), Info_ValueForKey( infostring, "gamedir" ));
Con_Printf( "^2Server^7: %s, Game: %s\n", NET_AdrToString( from ), Info_ValueForKey( infostring, "gamedir" ));
UI_AddServerToList( from, infostring );
}
@ -1719,14 +1809,14 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
Cmd_TokenizeString( args );
c = Cmd_Argv( 0 );
MsgDev( D_NOTE, "CL_ConnectionlessPacket: %s : %s\n", NET_AdrToString( from ), c );
Con_Reportf( "CL_ConnectionlessPacket: %s : %s\n", NET_AdrToString( from ), c );
// server connection
if( !Q_strcmp( c, "client_connect" ))
{
if( cls.state == ca_connected )
{
MsgDev( D_ERROR, "dup connect received. ignored\n");
Con_DPrintf( S_ERROR "dup connect received. ignored\n");
return;
}
@ -1764,6 +1854,14 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
// print command from somewhere
Con_Printf( "%s", MSG_ReadString( msg ));
}
else if( !Q_strcmp( c, "errormsg" ))
{
args = MSG_ReadString( msg );
if( !Q_strcmp( args, "Server uses protocol version 48.\n" ))
{
cls.legacyserver = from;
}
}
else if( !Q_strcmp( c, "testpacket" ))
{
byte recv_buf[NET_MAX_FRAGMENT];
@ -1784,7 +1882,6 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
}
// if we waiting more than cl_timeout or packet was trashed
Msg( "got testpacket, size mismatched %d should be %d\n", MSG_GetMaxBytes( msg ), cls.max_fragment_size );
cls.connect_time = MAX_HEARTBEAT;
return; // just wait for a next responce
}
@ -1798,7 +1895,8 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
if( crcValue == crcValue2 )
{
// packet was sucessfully delivered, adjust the fragment size and get challenge
Msg( "CRC 0x%08x is matched, get challenge, fragment size %d\n", crcValue, cls.max_fragment_size );
Con_DPrintf( "CRC %x is matched, get challenge, fragment size %d\n", crcValue, cls.max_fragment_size );
Netchan_OutOfBandPrint( NS_CLIENT, from, "getchallenge\n" );
Cvar_SetValue( "cl_dlmax", cls.max_fragment_size );
cls.connect_time = host.realtime;
@ -1816,6 +1914,7 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
}
Msg( "got testpacket, CRC mismatched 0x%08x should be 0x%08x, trying next fragment size %d\n", crcValue2, crcValue, cls.max_fragment_size >> 1 );
// trying the next size of packet
cls.connect_time = MAX_HEARTBEAT;
}
@ -1842,6 +1941,12 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
// a disconnect message from the server, which will happen if the server
// dropped the connection but it is still getting packets from us
CL_Disconnect_f();
if( NET_CompareAdr( from, cls.legacyserver ))
{
Cbuf_AddText( va( "connect %s legacy\n", NET_AdrToString( from )));
memset( &cls.legacyserver, 0, sizeof( cls.legacyserver ));
}
}
else if( !Q_strcmp( c, "f" ))
{
@ -1907,13 +2012,19 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
Netchan_OutOfBandPrint( NS_CLIENT, servadr, "info %i", PROTOCOL_VERSION );
}
}
if( cls.internetservers_pending )
{
Cbuf_AddText( "menu_resetping\n" ); // TODO: New Menu API
cls.internetservers_pending = false;
}
}
else if( clgame.dllFuncs.pfnConnectionlessPacket( &from, args, buf, &len ))
{
// user out of band message (must be handled in CL_ConnectionlessPacket)
if( len > 0 ) Netchan_OutOfBand( NS_SERVER, from, len, buf );
}
else MsgDev( D_ERROR, "bad connectionless packet from %s:\n%s\n", NET_AdrToString( from ), args );
else Con_DPrintf( S_ERROR "bad connectionless packet from %s:\n%s\n", NET_AdrToString( from ), args );
}
/*
@ -1948,6 +2059,11 @@ void CL_ReadNetMessage( void )
while( CL_GetMessage( net_message_buffer, &curSize ))
{
if( cls.legacymode && *((int *)&net_message_buffer) == 0xFFFFFFFE )
// Will rewrite existing packet by merged
if( !NetSplit_GetLong( &cls.netchan.netsplit, &net_from, net_message_buffer, &curSize ) )
continue;
MSG_Init( &net_message, "ServerData", net_message_buffer, curSize );
// check for connectionless packet (0xffffffff) first
@ -1962,21 +2078,25 @@ void CL_ReadNetMessage( void )
if( !cls.demoplayback && MSG_GetMaxBytes( &net_message ) < 8 )
{
MsgDev( D_WARN, "%s: runt packet\n", NET_AdrToString( net_from ));
Con_Printf( S_WARN "CL_ReadPackets: %s:runt packet\n", NET_AdrToString( net_from ));
continue;
}
// packet from server
if( !cls.demoplayback && !NET_CompareAdr( net_from, cls.netchan.remote_address ))
{
MsgDev( D_ERROR, "CL_ReadPackets: %s:sequenced packet without connection\n", NET_AdrToString( net_from ));
Con_DPrintf( S_ERROR "CL_ReadPackets: %s:sequenced packet without connection\n", NET_AdrToString( net_from ));
continue;
}
if( !cls.demoplayback && !Netchan_Process( &cls.netchan, &net_message ))
continue; // wasn't accepted for some reason
CL_ParseServerMessage( &net_message, true );
// run special handler for quake demos
if( cls.demoplayback == DEMO_QUAKE1 )
CL_ParseQuakeMessage( &net_message, true );
else if( cls.legacymode ) CL_ParseLegacyServerMessage( &net_message, true );
else CL_ParseServerMessage( &net_message, true );
cl.send_reply = true;
}
@ -2019,7 +2139,7 @@ void CL_ReadPackets( void )
// decide the simulation time
cl.oldtime = cl.time;
if( !cls.demoplayback && !cl.paused )
if( cls.demoplayback != DEMO_XASH3D && !cl.paused )
cl.time += host.frametime;
// demo time
@ -2034,13 +2154,11 @@ void CL_ReadPackets( void )
if( cl.maxclients > 1 && cls.state == ca_active && !host_developer.value )
Cvar_SetCheatState();
#endif
// singleplayer never has connection timeout
if( NET_IsLocalAddress( cls.netchan.remote_address ))
return;
// hot precache and downloading resources
if( cls.signon == SIGNONS && cl.lastresourcecheck < host.realtime )
{
double checktime = Host_IsLocalGame() ? 0.1 : 1.0;
if( !cls.dl.custom && cl.resourcesneeded.pNext != &cl.resourcesneeded )
{
// check resource for downloading and precache
@ -2048,9 +2166,14 @@ void CL_ReadPackets( void )
CL_BatchResourceRequest( false );
cls.dl.custom = true;
}
cl.lastresourcecheck = host.realtime + 5.0f; // don't checking too often
cl.lastresourcecheck = host.realtime + checktime;
}
// singleplayer never has connection timeout
if( NET_IsLocalAddress( cls.netchan.remote_address ))
return;
// if in the debugger last frame, don't timeout
if( host.frametime > 5.0f ) cls.netchan.last_received = Sys_DoubleTime();
@ -2359,7 +2482,7 @@ qboolean CL_PrecacheResources( void )
if( cl.models[pRes->nIndex] == NULL )
{
MsgDev( D_ERROR, "submodel %s not found\n", pRes->szFileName );
Con_Printf( S_ERROR "submodel %s not found\n", pRes->szFileName );
if( FBitSet( pRes->ucFlags, RES_FATALIFMISSING ))
{
@ -2386,6 +2509,7 @@ qboolean CL_PrecacheResources( void )
{
if( FBitSet( pRes->ucFlags, RES_WASMISSING ))
{
Con_Printf( S_ERROR "%s%s couldn't load\n", DEFAULT_SOUNDPATH, pRes->szFileName );
cl.sound_precache[pRes->nIndex][0] = 0;
cl.sound_index[pRes->nIndex] = 0;
}
@ -2450,7 +2574,6 @@ qboolean CL_PrecacheResources( void )
CL_SetEventIndex( cl.event_precache[pRes->nIndex], pRes->nIndex );
break;
default:
MsgDev( D_REPORT, "unknown resource type\n" );
break;
}
@ -2558,9 +2681,13 @@ void CL_InitLocal( void )
Cvar_Get( "team", "", FCVAR_USERINFO, "player team" );
Cvar_Get( "skin", "", FCVAR_USERINFO, "player skin" );
// legacy mode cvars (need this to add it to userinfo)
Cvar_Get( "cl_maxpacket", "0", 0, "legacy server compatibility" );
Cvar_Get( "cl_maxpayload", "1000", 0, "legacy server compatibility" );
cl_showfps = Cvar_Get( "cl_showfps", "1", FCVAR_ARCHIVE, "show client fps" );
cl_nosmooth = Cvar_Get( "cl_nosmooth", "0", FCVAR_ARCHIVE, "disable smooth up stair climbing and interpolate position in multiplayer" );
cl_smoothtime = Cvar_Get( "cl_smoothtime", "0.1", FCVAR_ARCHIVE, "time to smooth up" );
cl_smoothtime = Cvar_Get( "cl_smoothtime", "0", FCVAR_ARCHIVE, "time to smooth up" );
cl_cmdbackup = Cvar_Get( "cl_cmdbackup", "10", FCVAR_ARCHIVE, "how many additional history commands are sent" );
cl_cmdrate = Cvar_Get( "cl_cmdrate", "30", FCVAR_ARCHIVE, "Max number of command packets sent to server per second" );
cl_draw_particles = Cvar_Get( "r_drawparticles", "1", FCVAR_CHEAT, "render particles" );
@ -2574,6 +2701,7 @@ void CL_InitLocal( void )
hud_scale = Cvar_Get( "hud_scale", "0", FCVAR_ARCHIVE|FCVAR_LATCH, "scale hud at current resolution" );
Cvar_Get( "cl_background", "0", FCVAR_READ_ONLY, "indicate what background map is running" );
cl_showevents = Cvar_Get( "cl_showevents", "0", FCVAR_ARCHIVE, "show events playback" );
Cvar_Get( "lastdemo", "", FCVAR_ARCHIVE, "last played demo" );
// these two added to shut up CS 1.5 about 'unknown' commands
Cvar_Get( "lightgamma", "1", FCVAR_ARCHIVE, "ambient lighting level (legacy, unused)" );
@ -2605,7 +2733,7 @@ void CL_InitLocal( void )
Cmd_AddCommand ("record", CL_Record_f, "record a demo" );
Cmd_AddCommand ("playdemo", CL_PlayDemo_f, "play a demo" );
Cmd_AddCommand ("timedemo", CL_TimeDemo_f, "demo benchmark" );
Cmd_AddCommand ("killdemo", CL_DeleteDemo_f, "delete a specified demo file and demoshot" );
Cmd_AddCommand ("killdemo", CL_DeleteDemo_f, "delete a specified demo file" );
Cmd_AddCommand ("startdemos", CL_StartDemos_f, "start playing back the selected demos sequentially" );
Cmd_AddCommand ("demos", CL_Demos_f, "restart looping demos defined by the last startdemos command" );
Cmd_AddCommand ("movie", CL_PlayVideo_f, "play a movie" );
@ -2627,12 +2755,13 @@ void CL_InitLocal( void )
Cmd_AddCommand ("skyshot", CL_SkyShot_f, "takes a six-sides envmap (skybox) shot with specified name" );
Cmd_AddCommand ("levelshot", CL_LevelShot_f, "same as \"screenshot\", used for create plaque images" );
Cmd_AddCommand ("saveshot", CL_SaveShot_f, "used for create save previews with LoadGame menu" );
Cmd_AddCommand ("demoshot", CL_DemoShot_f, "used for create demo previews with PlayDemo menu" );
Cmd_AddCommand ("connect", CL_Connect_f, "connect to a server by hostname" );
Cmd_AddCommand ("reconnect", CL_Reconnect_f, "reconnect to current level" );
Cmd_AddCommand ("rcon", CL_Rcon_f, "sends a command to the server console (rcon_password and rcon_address required)" );
Cmd_AddCommand ("precache", CL_LegacyPrecache_f, "legacy server compatibility" );
}
//============================================================================
@ -2753,12 +2882,6 @@ void Host_ClientFrame( void )
// update audio
SND_UpdateSound ();
// animate lightestyles
CL_RunLightStyles ();
// decay dynamic lights
CL_DecayLights ();
// play avi-files
SCR_RunCinematic ();
@ -2787,6 +2910,7 @@ void CL_Init( void )
MSG_Init( &cls.datagram, "cls.datagram", cls.datagram_buf, sizeof( cls.datagram_buf ));
IN_TouchInit();
Con_LoadHistory();
if( !CL_LoadProgs( va( "%s/%s", GI->dll_path, SI.clientlib)))
Host_Error( "can't initialize %s: %s\n", SI.clientlib, COM_GetLibraryError() );

View file

@ -21,10 +21,7 @@ GNU General Public License for more details.
#include "library.h"
#include "gl_local.h"
#include "input.h"
#if defined(__ANDROID__)
#include "platform/android/android-main.h"
#endif
#include "platform/platform.h"
mobile_engfuncs_t *gMobileEngfuncs;
@ -38,23 +35,21 @@ static void pfnVibrate( float life, char flags )
if( life < 0.0f )
{
MsgDev( D_WARN, "Negative vibrate time: %f\n", life );
Con_Reportf( S_WARN "Negative vibrate time: %f\n", life );
return;
}
//MsgDev( D_NOTE, "Vibrate: %f %d\n", life, flags );
//Con_Reportf( "Vibrate: %f %d\n", life, flags );
// here goes platform-specific backends
#ifdef __ANDROID__
Android_Vibrate( life * vibration_length->value, flags );
#endif
Platform_Vibrate( life * vibration_length->value, flags );
}
static void Vibrate_f()
{
if( Cmd_Argc() != 2 )
{
Msg( "Usage: vibrate <time>\n" );
Msg( S_USAGE "vibrate <time>\n" );
return;
}
@ -97,13 +92,8 @@ static void *pfnGetNativeObject( const char *obj )
if( !obj )
return NULL;
// Backend should handle NULL
// Backend should consider that obj is case-sensitive
#ifdef __ANDROID__
return Android_GetNativeObject( obj );
#else
return NULL;
#endif
return Platform_GetNativeObject( obj );
}
static mobile_engfuncs_t gpMobileEngfuncs =

File diff suppressed because it is too large Load diff

View file

@ -48,17 +48,10 @@ CL_PushPMStates
*/
void CL_PushPMStates( void )
{
if( clgame.pushed )
{
MsgDev( D_ERROR, "PushPMStates: stack overflow\n");
}
else
{
clgame.oldphyscount = clgame.pmove->numphysent;
clgame.oldviscount = clgame.pmove->numvisent;
clgame.pushed = true;
}
if( clgame.pushed ) return;
clgame.oldphyscount = clgame.pmove->numphysent;
clgame.oldviscount = clgame.pmove->numvisent;
clgame.pushed = true;
}
/*
@ -69,16 +62,35 @@ CL_PopPMStates
*/
void CL_PopPMStates( void )
{
if( clgame.pushed )
{
clgame.pmove->numphysent = clgame.oldphyscount;
clgame.pmove->numvisent = clgame.oldviscount;
clgame.pushed = false;
}
else
{
MsgDev( D_ERROR, "PopPMStates: stack underflow\n");
}
if( !clgame.pushed ) return;
clgame.pmove->numphysent = clgame.oldphyscount;
clgame.pmove->numvisent = clgame.oldviscount;
clgame.pushed = false;
}
/*
=============
CL_PushTraceBounds
=============
*/
void CL_PushTraceBounds( int hullnum, const float *mins, const float *maxs )
{
hullnum = bound( 0, hullnum, 3 );
VectorCopy( mins, clgame.pmove->player_mins[hullnum] );
VectorCopy( maxs, clgame.pmove->player_maxs[hullnum] );
}
/*
=============
CL_PopTraceBounds
=============
*/
void CL_PopTraceBounds( void )
{
memcpy( clgame.pmove->player_mins, host.player_mins, sizeof( host.player_mins ));
memcpy( clgame.pmove->player_maxs, host.player_maxs, sizeof( host.player_maxs ));
}
/*
@ -90,6 +102,10 @@ qboolean CL_IsPredicted( void )
{
if( cl_nopred->value || cl.intermission )
return false;
// never predict the quake demos
if( cls.demoplayback == DEMO_QUAKE1 )
return false;
return true;
}
@ -456,9 +472,6 @@ void CL_AddLinksToPmove( frame_t *frame )
if( VectorIsNull( state->mins ) && VectorIsNull( state->maxs ))
continue;
if ( !model->hulls[1].lastclipnode && model->type != mod_studio )
continue;
if( state->solid == SOLID_NOT && state->skin < CONTENTS_EMPTY )
{
if( clgame.pmove->nummoveent >= MAX_MOVEENTS )
@ -470,6 +483,9 @@ void CL_AddLinksToPmove( frame_t *frame )
}
else
{
if( !model->hulls[1].lastclipnode && model->type != mod_studio )
continue;
// reserve slots for all the clients
if( clgame.pmove->numphysent >= ( MAX_PHYSENTS - cl.maxclients ))
continue;
@ -765,10 +781,7 @@ static void pfnStuckTouch( int hitent, pmtrace_t *tr )
}
if( clgame.pmove->numtouch >= MAX_PHYSENTS )
{
MsgDev( D_ERROR, "PM_StuckTouch: MAX_TOUCHENTS limit exceeded\n" );
return;
}
VectorCopy( clgame.pmove->velocity, tr->deltavelocity );
tr->ent = hitent;
@ -966,7 +979,7 @@ void CL_InitClientMove( void )
for( i = 0; i < MAX_MAP_HULLS; i++ )
{
if( clgame.dllFuncs.pfnGetHullBounds( i, host.player_mins[i], host.player_maxs[i] ))
MsgDev( D_NOTE, "CL: hull%i, player_mins: %g %g %g, player_maxs: %g %g %g\n", i,
Con_Reportf( "CL: hull%i, player_mins: %g %g %g, player_maxs: %g %g %g\n", i,
host.player_mins[i][0], host.player_mins[i][1], host.player_mins[i][2],
host.player_maxs[i][0], host.player_maxs[i][1], host.player_maxs[i][2] );
}
@ -1226,7 +1239,7 @@ void CL_PredictMovement( qboolean repredicting )
if( cls.state != ca_active || cls.spectator )
return;
if( cls.demoplayback && cl.cmd != NULL && !repredicting )
if( cls.demoplayback && !repredicting )
CL_DemoInterpolateAngles();
CL_SetUpPlayerPrediction( false, false );
@ -1315,7 +1328,7 @@ void CL_PredictMovement( qboolean repredicting )
cl.local.onground = frame->playerstate[cl.playernum].onground;
else cl.local.onground = -1;
if( !repredicting || !cl_lw->value )
if( !repredicting || !CVAR_TO_BOOL( cl_lw ))
cl.local.viewmodel = to->client.viewmodel;
cl.local.repredicting = false;
cl.local.moving = false;
@ -1345,7 +1358,7 @@ void CL_PredictMovement( qboolean repredicting )
cl.local.waterlevel = to->client.waterlevel;
cl.local.usehull = to->playerstate.usehull;
if( !repredicting || !cl_lw->value )
if( !repredicting || !CVAR_TO_BOOL( cl_lw ))
cl.local.viewmodel = to->client.viewmodel;
if( FBitSet( to->client.flags, FL_ONGROUND ))

1133
engine/client/cl_qparse.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -78,7 +78,9 @@ byte *CL_CreateRawTextureFromPixels( texture_t *tx, size_t *size, int topcolor,
// fill header
if( !pin.name[0] ) Q_strncpy( pin.name, "#raw_remap_image.mdl", sizeof( pin.name ));
pin.flags = STUDIO_NF_COLORMAP; // just in case :-)
pin.index = (int)(tx + 1); // pointer to pixels
//pin.index = (int)(tx + 1); // pointer to pixels
// no more pointer-to-int-to-pointer casts
Image_SetMDLPointer( (byte*)((texture_t *)tx + 1) );
pin.width = tx->width;
pin.height = tx->height;
@ -99,10 +101,11 @@ Dupliacte texture with remap pixels
*/
void CL_DuplicateTexture( mstudiotexture_t *ptexture, int topcolor, int bottomcolor )
{
gltexture_t *glt;
gl_texture_t *glt;
texture_t *tx = NULL;
char texname[128];
int i, size, index;
int i, index;
size_t size;
byte paletteBackup[768];
byte *raw, *pal;
@ -126,7 +129,7 @@ void CL_DuplicateTexture( mstudiotexture_t *ptexture, int topcolor, int bottomco
memcpy( paletteBackup, pal, 768 );
raw = CL_CreateRawTextureFromPixels( tx, &size, topcolor, bottomcolor );
ptexture->index = GL_LoadTexture( texname, raw, size, TF_FORCE_COLOR, NULL ); // do copy
ptexture->index = GL_LoadTexture( texname, raw, size, TF_FORCE_COLOR ); // do copy
// restore original palette
memcpy( pal, paletteBackup, 768 );
@ -141,11 +144,12 @@ Update texture top and bottom colors
*/
void CL_UpdateStudioTexture( mstudiotexture_t *ptexture, int topcolor, int bottomcolor )
{
gltexture_t *glt;
gl_texture_t *glt;
rgbdata_t *pic;
texture_t *tx = NULL;
char texname[128], name[128], mdlname[128];
int i, size, index;
int i, index;
size_t size;
byte paletteBackup[768];
byte *raw, *pal;
@ -179,11 +183,11 @@ void CL_UpdateStudioTexture( mstudiotexture_t *ptexture, int topcolor, int botto
pic = FS_LoadImage( glt->name, raw, size );
if( !pic )
{
MsgDev( D_ERROR, "Couldn't update texture %s\n", glt->name );
Con_DPrintf( S_ERROR "Couldn't update texture %s\n", glt->name );
return;
}
index = GL_LoadTextureInternal( glt->name, pic, 0, true );
index = GL_UpdateTextureInternal( glt->name, pic, 0 );
FS_FreeImage( pic );
// restore original palette
@ -213,7 +217,7 @@ void CL_UpdateAliasTexture( unsigned short *texture, int skinnum, int topcolor,
if( *texture == 0 )
{
Q_snprintf( texname, sizeof( texname ), "%s:remap%i", RI.currentmodel->name, skinnum );
Q_snprintf( texname, sizeof( texname ), "%s:remap%i_%i", RI.currentmodel->name, skinnum, RI.currententity->index );
skin.width = tx->width;
skin.height = tx->height;
skin.depth = skin.numMips = 1;
@ -224,7 +228,7 @@ void CL_UpdateAliasTexture( unsigned short *texture, int skinnum, int topcolor,
skin.buffer = (byte *)(tx + 1);
skin.palette = skin.buffer + skin.size;
pic = FS_CopyImage( &skin ); // because GL_LoadTextureInternal will freed a rgbdata_t at end
*texture = GL_LoadTextureInternal( texname, pic, TF_KEEP_SOURCE, false );
*texture = GL_LoadTextureInternal( texname, pic, TF_KEEP_SOURCE );
}
// and now we can remap with internal routines
@ -288,7 +292,7 @@ void CL_AllocRemapInfo( int topcolor, int bottomcolor )
// e.g. playermodel 'barney' with playermodel 'gordon'
if( clgame.remap_info[i] ) CL_FreeRemapInfo( clgame.remap_info[i] ); // free old info
size = sizeof( remap_info_t ) + ( sizeof( mstudiotexture_t ) * phdr->numtextures );
info = clgame.remap_info[i] = Mem_Alloc( clgame.mempool, size );
info = clgame.remap_info[i] = Mem_Calloc( clgame.mempool, size );
info->ptexture = (mstudiotexture_t *)(info + 1); // textures are immediately comes after remap_info
}
else
@ -325,7 +329,7 @@ void CL_AllocRemapInfo( int topcolor, int bottomcolor )
// this code catches studiomodel change with another studiomodel with remap textures
// e.g. playermodel 'barney' with playermodel 'gordon'
if( clgame.remap_info[i] ) CL_FreeRemapInfo( clgame.remap_info[i] ); // free old info
info = clgame.remap_info[i] = Mem_Alloc( clgame.mempool, sizeof( remap_info_t ));
info = clgame.remap_info[i] = Mem_Calloc( clgame.mempool, sizeof( remap_info_t ));
}
else
{

View file

@ -176,7 +176,7 @@ SCR_RSpeeds
*/
void SCR_RSpeeds( void )
{
char msg[MAX_SYSPATH];
char msg[2048];
if( !host.allow_console )
return;
@ -202,6 +202,9 @@ void SCR_RSpeeds( void )
Con_DrawString( x, y, p, color );
y += height;
// handle '\n\n'
if( *p == '\n' )
y += height;
if( end ) p = end + 1;
else break;
} while( 1 );
@ -252,7 +255,6 @@ void SCR_MakeScreenShot( void )
iRet = VID_ScreenShot( cls.shotname, VID_LEVELSHOT );
break;
case scrshot_savegame:
case scrshot_demoshot:
iRet = VID_ScreenShot( cls.shotname, VID_MINISHOT );
break;
case scrshot_envshot:
@ -273,9 +275,9 @@ void SCR_MakeScreenShot( void )
{
// snapshots don't writes message about image
if( cls.scrshot_action != scrshot_snapshot )
MsgDev( D_REPORT, "Write %s\n", cls.shotname );
Con_Reportf( "Write %s\n", cls.shotname );
}
else MsgDev( D_ERROR, "Unable to write %s\n", cls.shotname );
else Con_Printf( S_ERROR "Unable to write %s\n", cls.shotname );
cls.envshot_vieworg = NULL;
cls.scrshot_action = scrshot_inactive;
@ -293,7 +295,7 @@ void SCR_DrawPlaque( void )
{
if(( cl_allow_levelshots->value && !cls.changelevel ) || cl.background )
{
int levelshot = GL_LoadTexture( cl_levelshot_name->string, NULL, 0, TF_IMAGE, NULL );
int levelshot = GL_LoadTexture( cl_levelshot_name->string, NULL, 0, TF_IMAGE );
GL_SetRenderMode( kRenderNormal );
R_DrawStretchPic( 0, 0, glState.width, glState.height, 0, 0, 1, 1, levelshot );
if( !cl.background ) CL_DrawHUD( CL_LOADING );
@ -408,10 +410,10 @@ void SCR_TileClear( void )
if( clear.y2 <= clear.y1 )
return; // nothing disturbed
top = RI.viewport[1];
bottom = top + RI.viewport[3] - 1;
left = RI.viewport[0];
right = left + RI.viewport[2] - 1;
top = clgame.viewport[1];
bottom = top + clgame.viewport[3] - 1;
left = clgame.viewport[0];
right = left + clgame.viewport[2] - 1;
if( clear.y1 < top )
{
@ -493,7 +495,7 @@ qboolean SCR_LoadFixedWidthFont( const char *fontname )
if( !FS_FileExists( fontname, false ))
return false;
cls.creditsFont.hFontTexture = GL_LoadTexture( fontname, NULL, 0, TF_IMAGE|TF_KEEP_SOURCE, NULL );
cls.creditsFont.hFontTexture = GL_LoadTexture( fontname, NULL, 0, TF_IMAGE|TF_KEEP_SOURCE );
R_GetTextureParms( &fontWidth, NULL, cls.creditsFont.hFontTexture );
cls.creditsFont.charHeight = clgame.scrInfo.iCharHeight = fontWidth / 16;
cls.creditsFont.type = FONT_FIXED;
@ -525,7 +527,7 @@ qboolean SCR_LoadVariableWidthFont( const char *fontname )
if( !FS_FileExists( fontname, false ))
return false;
cls.creditsFont.hFontTexture = GL_LoadTexture( fontname, NULL, 0, TF_IMAGE, NULL );
cls.creditsFont.hFontTexture = GL_LoadTexture( fontname, NULL, 0, TF_IMAGE );
R_GetTextureParms( &fontWidth, NULL, cls.creditsFont.hFontTexture );
// half-life font with variable chars witdh
@ -577,7 +579,7 @@ void SCR_LoadCreditsFont( void )
if( !SCR_LoadVariableWidthFont( path ))
{
if( !SCR_LoadFixedWidthFont( "gfx/conchars" ))
MsgDev( D_ERROR, "failed to load HUD font\n" );
Con_DPrintf( S_ERROR "failed to load HUD font\n" );
}
}
@ -594,8 +596,8 @@ void SCR_InstallParticlePalette( void )
int i;
// first check 'palette.lmp' then 'palette.pal'
pic = FS_LoadImage( "gfx/palette.lmp", NULL, 0 );
if( !pic ) pic = FS_LoadImage( "gfx/palette.pal", NULL, 0 );
pic = FS_LoadImage( DEFAULT_INTERNAL_PALETTE, NULL, 0 );
if( !pic ) pic = FS_LoadImage( DEFAULT_EXTERNAL_PALETTE, NULL, 0 );
// NOTE: imagelib required this fakebuffer for loading internal palette
if( !pic ) pic = FS_LoadImage( "#valve.pal", (byte *)&i, 768 );
@ -612,13 +614,13 @@ void SCR_InstallParticlePalette( void )
}
else
{
// someone deleted internal palette from code...
for( i = 0; i < 256; i++ )
{
clgame.palette[i].r = i;
clgame.palette[i].g = i;
clgame.palette[i].b = i;
}
MsgDev( D_WARN, "CL_InstallParticlePalette: failed. Force to grayscale\n" );
}
}
@ -634,24 +636,24 @@ void SCR_RegisterTextures( void )
// register gfx.wad images
if( FS_FileExists( "gfx/paused.lmp", false ))
cls.pauseIcon = GL_LoadTexture( "gfx/paused.lmp", NULL, 0, TF_IMAGE, NULL );
cls.pauseIcon = GL_LoadTexture( "gfx/paused.lmp", NULL, 0, TF_IMAGE );
else if( FS_FileExists( "gfx/pause.lmp", false ))
cls.pauseIcon = GL_LoadTexture( "gfx/pause.lmp", NULL, 0, TF_IMAGE, NULL );
cls.pauseIcon = GL_LoadTexture( "gfx/pause.lmp", NULL, 0, TF_IMAGE );
if( FS_FileExists( "gfx/lambda.lmp", false ))
{
if( cl_allow_levelshots->value )
cls.loadingBar = GL_LoadTexture( "gfx/lambda.lmp", NULL, 0, TF_IMAGE|TF_LUMINANCE, NULL );
else cls.loadingBar = GL_LoadTexture( "gfx/lambda.lmp", NULL, 0, TF_IMAGE, NULL );
cls.loadingBar = GL_LoadTexture( "gfx/lambda.lmp", NULL, 0, TF_IMAGE|TF_LUMINANCE );
else cls.loadingBar = GL_LoadTexture( "gfx/lambda.lmp", NULL, 0, TF_IMAGE );
}
else if( FS_FileExists( "gfx/loading.lmp", false ))
{
if( cl_allow_levelshots->value )
cls.loadingBar = GL_LoadTexture( "gfx/loading.lmp", NULL, 0, TF_IMAGE|TF_LUMINANCE, NULL );
else cls.loadingBar = GL_LoadTexture( "gfx/loading.lmp", NULL, 0, TF_IMAGE, NULL );
cls.loadingBar = GL_LoadTexture( "gfx/loading.lmp", NULL, 0, TF_IMAGE|TF_LUMINANCE );
else cls.loadingBar = GL_LoadTexture( "gfx/loading.lmp", NULL, 0, TF_IMAGE );
}
cls.tileImage = GL_LoadTexture( "gfx/backtile.lmp", NULL, 0, TF_NOMIPMAP, NULL );
cls.tileImage = GL_LoadTexture( "gfx/backtile.lmp", NULL, 0, TF_NOMIPMAP );
}
/*
@ -718,7 +720,6 @@ void SCR_Init( void )
{
if( scr_init ) return;
MsgDev( D_NOTE, "SCR_Init()\n" );
scr_centertime = Cvar_Get( "scr_centertime", "2.5", 0, "centerprint hold time" );
cl_levelshot_name = Cvar_Get( "cl_levelshot_name", "*black", 0, "contains path to current levelshot" );
cl_allow_levelshots = Cvar_Get( "allow_levelshots", "0", FCVAR_ARCHIVE, "allow engine to use indivdual levelshots instead of 'loading' image" );
@ -732,6 +733,7 @@ void SCR_Init( void )
// register our commands
Cmd_AddCommand( "timerefresh", SCR_TimeRefresh_f, "turn quickly and print rendering statistcs" );
Cmd_AddCommand( "skyname", CL_SetSky_f, "set new skybox by basename" );
Cmd_AddCommand( "loadsky", CL_SetSky_f, "set new skybox by basename" );
Cmd_AddCommand( "viewpos", SCR_Viewpos_f, "prints current player origin" );
Cmd_AddCommand( "sizeup", SCR_SizeUp_f, "screen size up to 10 points" );
Cmd_AddCommand( "sizedown", SCR_SizeDown_f, "screen size down to 10 points" );
@ -742,12 +744,12 @@ void SCR_Init( void )
host.allow_console = true; // we need console, because menu is missing
}
SCR_VidInit();
SCR_LoadCreditsFont ();
SCR_InstallParticlePalette ();
SCR_RegisterTextures ();
SCR_InstallParticlePalette ();
SCR_InitCinematic();
CL_InitNetgraph();
SCR_VidInit();
if( host.allow_console && Sys_CheckParm( "-toconsole" ))
Cbuf_AddText( "toggleconsole\n" );
@ -760,7 +762,6 @@ void SCR_Shutdown( void )
{
if( !scr_init ) return;
MsgDev( D_NOTE, "SCR_Shutdown()\n" );
Cmd_RemoveCommand( "timerefresh" );
Cmd_RemoveCommand( "skyname" );
Cmd_RemoveCommand( "viewpos" );

View file

@ -127,7 +127,7 @@ void CL_AddClientResource( const char *filename, int type )
if( p != &cl.resourcesneeded )
return; // already in list?
pResource = Mem_Alloc( cls.mempool, sizeof( resource_t ));
pResource = Mem_Calloc( cls.mempool, sizeof( resource_t ));
Q_strncpy( pResource->szFileName, filename, sizeof( pResource->szFileName ));
pResource->type = type;
@ -151,7 +151,7 @@ void CL_AddClientResources( void )
int i;
// don't request resources from localhost or in quake-compatibility mode
if( cl.maxclients <= 1 || FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
if( cl.maxclients <= 1 || Host_IsQuakeCompatible( ))
return;
// check sprites first
@ -325,7 +325,7 @@ CL_InitTempents
*/
void CL_InitTempEnts( void )
{
cl_tempents = Mem_Alloc( cls.mempool, sizeof( TEMPENTITY ) * GI->max_tents );
cl_tempents = Mem_Calloc( cls.mempool, sizeof( TEMPENTITY ) * GI->max_tents );
CL_ClearTempEnts();
// load tempent sprites (glowshell, muzzleflashes etc)
@ -593,7 +593,7 @@ TEMPENTITY *CL_TempEntAlloc( const vec3_t org, model_t *pmodel )
if( !cl_free_tents )
{
MsgDev( D_INFO, "Overflow %d temporary ents!\n", GI->max_tents );
Con_DPrintf( "Overflow %d temporary ents!\n", GI->max_tents );
return NULL;
}
@ -633,7 +633,7 @@ TEMPENTITY *CL_TempEntAllocHigh( const vec3_t org, model_t *pmodel )
{
// didn't find anything? The tent list is either full of high-priority tents
// or all tents in the list are still due to live for > 10 seconds.
MsgDev( D_INFO, "Couldn't alloc a high priority TENT!\n" );
Con_DPrintf( "Couldn't alloc a high priority TENT!\n" );
return NULL;
}
@ -870,10 +870,7 @@ void R_AttachTentToPlayer( int client, int modelIndex, float zoffset, float life
model_t *pModel;
if( client <= 0 || client > cl.maxclients )
{
MsgDev( D_ERROR, "Bad client %i in AttachTentToPlayer()!\n", client );
return;
}
pClient = CL_GetEntityByIndex( client );
@ -926,10 +923,7 @@ void R_KillAttachedTents( int client )
int i;
if( client <= 0 || client > cl.maxclients )
{
MsgDev( D_ERROR, "Bad client %i in KillAttachedTents()!\n", client );
return;
}
for( i = 0; i < GI->max_tents; i++ )
{
@ -1282,7 +1276,7 @@ TEMPENTITY *R_DefaultSprite( const vec3_t pos, int spriteIndex, float framerate
if(( psprite = CL_ModelHandle( spriteIndex )) == NULL || psprite->type != mod_sprite )
{
MsgDev( D_INFO, "No Sprite %d!\n", spriteIndex );
Con_Reportf( "No Sprite %d!\n", spriteIndex );
return NULL;
}
@ -1339,7 +1333,7 @@ TEMPENTITY *R_TempSprite( vec3_t pos, const vec3_t dir, float scale, int modelIn
if(( pmodel = CL_ModelHandle( modelIndex )) == NULL )
{
MsgDev( D_ERROR, "No model %d!\n", modelIndex );
Con_Reportf( S_ERROR "No model %d!\n", modelIndex );
return NULL;
}
@ -1446,7 +1440,7 @@ void R_Spray( const vec3_t pos, const vec3_t dir, int modelIndex, int count, int
if(( pmodel = CL_ModelHandle( modelIndex )) == NULL )
{
MsgDev( D_INFO, "No model %d!\n", modelIndex );
Con_Reportf( "No model %d!\n", modelIndex );
return;
}
@ -1577,7 +1571,7 @@ void R_FunnelSprite( const vec3_t org, int modelIndex, int reverse )
if(( pmodel = CL_ModelHandle( modelIndex )) == NULL )
{
MsgDev( D_ERROR, "no model %d!\n", modelIndex );
Con_Reportf( S_ERROR "no model %d!\n", modelIndex );
return;
}
@ -1823,10 +1817,7 @@ void R_PlayerSprites( int client, int modelIndex, int count, int size )
pEnt = CL_GetEntityByIndex( client );
if( !pEnt || !pEnt->player )
{
MsgDev( D_INFO, "Bad ent %i in R_PlayerSprites()!\n", client );
return;
}
vel = 128;
@ -2033,7 +2024,7 @@ void CL_ParseTempEntity( sizebuf_t *msg )
{
sizebuf_t buf;
byte pbuf[256];
int iSize = MSG_ReadWord( msg );
int iSize;
int type, color, count, flags;
int decalIndex, modelIndex, entityIndex;
float scale, life, frameRate, vel, random;
@ -2044,6 +2035,10 @@ void CL_ParseTempEntity( sizebuf_t *msg )
cl_entity_t *pEnt;
dlight_t *dl;
if( cls.legacymode )
iSize = MSG_ReadByte( msg );
else iSize = MSG_ReadWord( msg );
decalIndex = modelIndex = entityIndex = 0;
// parse user message into buffer
@ -2511,12 +2506,13 @@ void CL_ParseTempEntity( sizebuf_t *msg )
R_UserTracerParticle( pos, pos2, life, color, scale, 0, NULL );
break;
default:
MsgDev( D_ERROR, "ParseTempEntity: illegible TE message %i\n", type );
Con_DPrintf( S_ERROR "ParseTempEntity: illegible TE message %i\n", type );
break;
}
// throw warning
if( MSG_CheckOverflow( &buf )) MsgDev( D_WARN, "ParseTempEntity: overflow TE message\n" );
if( MSG_CheckOverflow( &buf ))
Con_DPrintf( S_WARN "ParseTempEntity: overflow TE message\n" );
}
@ -2573,7 +2569,8 @@ void CL_SetLightstyle( int style, const char *s, float f )
break;
}
}
MsgDev( D_REPORT, "Lightstyle %i (%s), interp %s\n", style, ls->pattern, ls->interp ? "Yes" : "No" );
Con_Reportf( "Lightstyle %i (%s), interp %s\n", style, ls->pattern, ls->interp ? "Yes" : "No" );
}
/*
@ -2808,7 +2805,7 @@ void CL_AddEntityEffects( cl_entity_t *ent )
if( FBitSet( ent->curstate.effects, EF_DIMLIGHT ))
{
if( ent->player && !FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
if( ent->player && !Host_IsQuakeCompatible( ))
{
CL_UpdateFlashlight( ent );
}
@ -2845,7 +2842,7 @@ void CL_AddEntityEffects( cl_entity_t *ent )
}
// studio models are handle muzzleflashes difference
if( FBitSet( ent->curstate.effects, EF_MUZZLEFLASH ) && ent->model->type == mod_alias )
if( FBitSet( ent->curstate.effects, EF_MUZZLEFLASH ) && Mod_AliasExtradata( ent->model ))
{
dlight_t *dl = CL_AllocDlight( ent->index );
vec3_t fv;
@ -2871,6 +2868,7 @@ these effects will be enable by flag in model header
*/
void CL_AddModelEffects( cl_entity_t *ent )
{
vec3_t neworigin;
vec3_t oldorigin;
if( !ent->model ) return;
@ -2883,23 +2881,33 @@ void CL_AddModelEffects( cl_entity_t *ent )
default: return;
}
VectorCopy( ent->prevstate.origin, oldorigin );
if( cls.demoplayback == DEMO_QUAKE1 )
{
VectorCopy( ent->baseline.vuser1, oldorigin );
VectorCopy( ent->origin, ent->baseline.vuser1 );
VectorCopy( ent->origin, neworigin );
}
else
{
VectorCopy( ent->prevstate.origin, oldorigin );
VectorCopy( ent->curstate.origin, neworigin );
}
// NOTE: this completely over control about angles and don't broke interpolation
if( FBitSet( ent->model->flags, STUDIO_ROTATE ))
ent->angles[1] = anglemod( 100.0f * cl.time );
if( FBitSet( ent->model->flags, STUDIO_GIB ))
R_RocketTrail( oldorigin, ent->curstate.origin, 2 );
R_RocketTrail( oldorigin, neworigin, 2 );
if( FBitSet( ent->model->flags, STUDIO_ZOMGIB ))
R_RocketTrail( oldorigin, ent->curstate.origin, 4 );
R_RocketTrail( oldorigin, neworigin, 4 );
if( FBitSet( ent->model->flags, STUDIO_TRACER ))
R_RocketTrail( oldorigin, ent->curstate.origin, 3 );
R_RocketTrail( oldorigin, neworigin, 3 );
if( FBitSet( ent->model->flags, STUDIO_TRACER2 ))
R_RocketTrail( oldorigin, ent->curstate.origin, 5 );
R_RocketTrail( oldorigin, neworigin, 5 );
if( FBitSet( ent->model->flags, STUDIO_ROCKET ))
{
@ -2915,14 +2923,14 @@ void CL_AddModelEffects( cl_entity_t *ent )
dl->die = cl.time + 0.01f;
R_RocketTrail( oldorigin, ent->curstate.origin, 0 );
R_RocketTrail( oldorigin, neworigin, 0 );
}
if( FBitSet( ent->model->flags, STUDIO_GRENADE ))
R_RocketTrail( oldorigin, ent->curstate.origin, 1 );
R_RocketTrail( oldorigin, neworigin, 1 );
if( FBitSet( ent->model->flags, STUDIO_TRACER3 ))
R_RocketTrail( oldorigin, ent->curstate.origin, 6 );
R_RocketTrail( oldorigin, neworigin, 6 );
}
/*
@ -3014,7 +3022,7 @@ void CL_PlayerDecal( int playernum, int customIndex, int entityIndex, float *pos
if( !pCust->nUserData1 && pCust->pInfo != NULL )
{
const char *decalname = va( "player%dlogo%d", playernum, customIndex );
pCust->nUserData1 = GL_LoadTextureInternal( decalname, pCust->pInfo, TF_DECAL, false );
pCust->nUserData1 = GL_LoadTextureInternal( decalname, pCust->pInfo, TF_DECAL );
}
textureIndex = pCust->nUserData1;
}
@ -3060,7 +3068,7 @@ int CL_DecalIndex( int id )
if( cl.decal_index[id] == 0 )
{
Image_SetForceFlags( IL_LOAD_DECAL );
cl.decal_index[id] = GL_LoadTexture( host.draw_decals[id], NULL, 0, TF_DECAL, NULL );
cl.decal_index[id] = GL_LoadTexture( host.draw_decals[id], NULL, 0, TF_DECAL );
Image_ClearForceFlags();
}

View file

@ -48,6 +48,7 @@ qboolean SCR_NextMovie( void )
{
S_StopAllSounds( true );
SCR_StopCinematic();
CL_CheckStartupDemos();
return false; // don't play movies
}
@ -56,6 +57,7 @@ qboolean SCR_NextMovie( void )
S_StopAllSounds( true );
SCR_StopCinematic();
cls.movienum = -1;
CL_CheckStartupDemos();
return false;
}
@ -90,6 +92,7 @@ void SCR_CheckStartupVids( void )
{
// don't run movies where we in developer-mode
cls.movienum = -1;
CL_CheckStartupDemos();
return;
}
@ -206,7 +209,7 @@ qboolean SCR_PlayCinematic( const char *arg )
if( FS_FileExists( arg, false ) && !fullpath )
{
MsgDev( D_ERROR, "Couldn't load %s from packfile. Please extract it\n", path );
Con_Printf( S_ERROR "Couldn't load %s from packfile. Please extract it\n", path );
return false;
}
@ -232,13 +235,14 @@ qboolean SCR_PlayCinematic( const char *arg )
UI_SetActiveMenu( false );
cls.state = ca_cinematic;
Con_FastClose();
cin_time = 0.0f;
cls.signon = 0;
return true;
}
long SCR_GetAudioChunk( char *rawdata, long length )
int SCR_GetAudioChunk( char *rawdata, int length )
{
int r;

View file

@ -19,6 +19,7 @@ GNU General Public License for more details.
#include "entity_types.h"
#include "gl_local.h"
#include "vgui_draw.h"
#include "sound.h"
/*
===============
@ -143,7 +144,7 @@ void V_SetRefParams( ref_params_t *fd )
fd->demoplayback = cls.demoplayback;
fd->hardware = 1; // OpenGL
if( cl.first_frame )
if( cl.first_frame || cl.skip_interp )
{
cl.first_frame = false; // now can be unlocked
fd->smoothing = true; // NOTE: currently this used to prevent ugly un-duck effect while level is changed
@ -286,7 +287,7 @@ qboolean V_PreRender( void )
{
if(( host.realtime - cls.disable_screen ) > cl_timeout->value )
{
MsgDev( D_ERROR, "V_PreRender: loading plaque timed out\n" );
Con_Reportf( "V_PreRender: loading plaque timed out\n" );
cls.disable_screen = 0.0f;
}
return false;
@ -334,6 +335,7 @@ void V_RenderView( void )
}
R_RenderFrame( &rvp );
S_UpdateFrame( &rvp );
viewnum++;
} while( rp.nextView );
@ -382,6 +384,7 @@ void V_PostRender( void )
CL_DrawDemoRecording();
CL_DrawHUD( CL_CHANGELEVEL );
R_ShowTextures();
R_ShowTree();
Con_DrawConsole();
UI_UpdateMenu( host.realtime );
Con_DrawVersion();

View file

@ -53,6 +53,13 @@ GNU General Public License for more details.
typedef int sound_t;
typedef enum
{
DEMO_INACTIVE = 0,
DEMO_XASH3D,
DEMO_QUAKE1
} demo_mode;
//=============================================================================
typedef struct netbandwithgraph_s
{
@ -214,6 +221,7 @@ typedef struct
qboolean background; // not real game, just a background
qboolean first_frame; // first rendering frame
qboolean proxy_redirect; // spectator stuff
qboolean skip_interp; // skip interpolation this frame
uint checksum; // for catching cheater maps
@ -312,7 +320,6 @@ typedef enum
scrshot_snapshot, // in-game snapshot
scrshot_plaque, // levelshot
scrshot_savegame, // saveshot
scrshot_demoshot, // for demos preview
scrshot_envshot, // cubemap view
scrshot_skyshot, // skybox view
scrshot_mapshot // overview layer
@ -541,8 +548,8 @@ typedef struct
ui_globalvars_t *globals;
qboolean drawLogo; // set to TRUE if logo.avi missed or corrupted
long logo_xres;
long logo_yres;
int logo_xres;
int logo_yres;
float logo_length;
qboolean use_text_api;
@ -595,6 +602,7 @@ typedef struct
float packet_loss;
double packet_loss_recalc_time;
int starting_count; // message num readed bits
float nextcmdtime; // when can we send the next command packet?
int lastoutgoingcommand; // sequence number of last outgoing command
@ -603,6 +611,7 @@ typedef struct
int td_lastframe; // to meter out one message a frame
int td_startframe; // host_framecount at start
double td_starttime; // realtime at second frame of timedemo
int forcetrack; // -1 = use normal cd track
// game images
int pauseIcon; // draw 'paused' when game in-pause
@ -632,7 +641,8 @@ typedef struct
// demo loop control
int demonum; // -1 = don't play demos
int olddemonum; // restore playing
string demos[MAX_DEMOS]; // when not playing
char demos[MAX_DEMOS][MAX_QPATH]; // when not playing
qboolean demos_pending;
// movie playlist
int movienum;
@ -645,9 +655,14 @@ typedef struct
qboolean timedemo;
string demoname; // for demo looping
double demotime; // recording time
qboolean set_lastdemo; // store name of last played demo into the cvar
file_t *demofile;
file_t *demoheader; // contain demo startup info in case we record a demo on this level
qboolean internetservers_wait; // internetservers is waiting for dns request
qboolean internetservers_pending; // internetservers is waiting for dns request
qboolean legacymode; // one-way 48 protocol compatibility
netadr_t legacyserver;
} client_static_t;
#ifdef __cplusplus
@ -730,7 +745,6 @@ void CL_PlayCDTrack_f( void );
void CL_EnvShot_f( void );
void CL_SkyShot_f( void );
void CL_SaveShot_f( void );
void CL_DemoShot_f( void );
void CL_LevelShot_f( void );
void CL_SetSky_f( void );
void SCR_Viewpos_f( void );
@ -745,6 +759,15 @@ void CL_RemoveFromResourceList( resource_t *pResource );
void CL_MoveToOnHandList( resource_t *pResource );
void CL_ClearResourceLists( void );
//
// cl_debug.c
//
void CL_Parse_Debug( qboolean enable );
void CL_Parse_RecordCommand( int cmd, int startoffset );
void CL_ResetFrame( frame_t *frame );
void CL_WriteMessageHistory( void );
const char *CL_MsgInfo( int cmd );
//
// cl_main.c
//
@ -772,8 +795,10 @@ void CL_WriteDemoMessage( qboolean startup, int start, sizebuf_t *msg );
void CL_WriteDemoUserMessage( const byte *buffer, size_t size );
qboolean CL_DemoReadMessage( byte *buffer, size_t *length );
void CL_DemoInterpolateAngles( void );
void CL_CheckStartupDemos( void );
void CL_WriteDemoJumpTime( void );
void CL_CloseDemoHeader( void );
void CL_DemoCompleted( void );
void CL_StopPlayback( void );
void CL_StopRecord( void );
void CL_PlayDemo_f( void );
@ -783,7 +808,6 @@ void CL_Demos_f( void );
void CL_DeleteDemo_f( void );
void CL_Record_f( void );
void CL_Stop_f( void );
void CL_FreeDemo( void );
//
// cl_events.c
@ -851,11 +875,16 @@ _inline cl_entity_t *CL_EDICT_NUM( int n )
// cl_parse.c
//
void CL_ParseServerMessage( sizebuf_t *msg, qboolean normal_message );
void CL_ParseLegacyServerMessage( sizebuf_t *msg, qboolean normal_message );
void CL_LegacyPrecache_f( void );
void CL_ParseTempEntity( sizebuf_t *msg );
void CL_StartResourceDownloading( const char *pszMessage, qboolean bCustom );
qboolean CL_DispatchUserMessage( const char *pszName, int iSize, void *pbuf );
qboolean CL_RequestMissingResources( void );
void CL_RegisterResources ( sizebuf_t *msg );
void CL_ParseViewEntity( sizebuf_t *msg );
void CL_ParseServerTime( sizebuf_t *msg );
//
// cl_scrn.c
@ -907,6 +936,8 @@ void CL_SetupPMove( playermove_t *pmove, local_state_t *from, usercmd_t *ucmd, q
int CL_TestLine( const vec3_t start, const vec3_t end, int flags );
pmtrace_t *CL_VisTraceLine( vec3_t start, vec3_t end, int flags );
pmtrace_t CL_TraceLine( vec3_t start, vec3_t end, int flags );
void CL_PushTraceBounds( int hullnum, const float *mins, const float *maxs );
void CL_PopTraceBounds( void );
void CL_MoveSpectatorCamera( void );
void CL_SetLastUpdate( void );
void CL_RedoPrediction( void );
@ -915,6 +946,11 @@ void CL_PushPMStates( void );
void CL_PopPMStates( void );
void CL_SetUpPlayerPrediction( int dopred, int bIncludeLocalClient );
//
// cl_qparse.c
//
void CL_ParseQuakeMessage( sizebuf_t *msg, qboolean normal_message );
//
// cl_studio.c
//
@ -923,15 +959,16 @@ void CL_InitStudioAPI( void );
//
// cl_frame.c
//
typedef struct channel_s channel_t;
typedef struct rawchan_s rawchan_t;
struct channel_s;
struct rawchan_s;
int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta );
qboolean CL_AddVisibleEntity( cl_entity_t *ent, int entityType );
void CL_ResetLatchedVars( cl_entity_t *ent, qboolean full_reset );
qboolean CL_GetEntitySpatialization( channel_t *ch );
qboolean CL_GetMovieSpatialization( rawchan_t *ch );
qboolean CL_GetEntitySpatialization( struct channel_s *ch );
qboolean CL_GetMovieSpatialization( struct rawchan_s *ch );
void CL_ProcessPlayerState( int playerindex, entity_state_t *state );
void CL_ComputePlayerOrigin( cl_entity_t *clent );
void CL_UpdateEntityFields( cl_entity_t *ent );
void CL_ProcessPacket( frame_t *frame );
void CL_MoveThirdpersonCamera( void );
qboolean CL_IsPlayerIndex( int idx );
void CL_SetIdealPitch( void );
@ -950,7 +987,7 @@ void CL_ClearAllRemaps( void );
//
// cl_tent.c
//
typedef struct particle_s particle_t;
struct particle_s;
int CL_AddEntity( int entityType, cl_entity_t *pEnt );
void CL_WeaponAnim( int iAnim, int body );
void CL_ClearEffects( void );
@ -960,7 +997,7 @@ void CL_DrawParticlesExternal( const ref_viewpass_t *rvp, qboolean trans_pass, f
void CL_FireCustomDecal( int textureIndex, int entityIndex, int modelIndex, float *pos, int flags, float scale );
void CL_DecalShoot( int textureIndex, int entityIndex, int modelIndex, float *pos, int flags );
void CL_PlayerDecal( int playerIndex, int textureIndex, int entityIndex, float *pos );
void R_FreeDeadParticles( particle_t **ppparticles );
void R_FreeDeadParticles( struct particle_s **ppparticles );
void CL_AddClientResource( const char *filename, int type );
void CL_AddClientResources( void );
int CL_FxBlend( cl_entity_t *e );
@ -1019,12 +1056,14 @@ void Con_Bottom( void );
void Con_Top( void );
void Con_PageDown( int lines );
void Con_PageUp( int lines );
void Con_LoadHistory( void );
//
// s_main.c
//
void S_StreamRawSamples( int samples, int rate, int width, int channels, const byte *data );
void S_StartBackgroundTrack( const char *intro, const char *loop, long position, qboolean fullpath );
void S_StreamAviSamples( void *Avi, int entnum, float fvol, float attn, float synctime );
void S_StartBackgroundTrack( const char *intro, const char *loop, int position, qboolean fullpath );
void S_StopBackgroundTrack( void );
void S_StreamSetPause( int pause );
void S_StartStreaming( void );

View file

@ -37,7 +37,6 @@ static qboolean g_utf8 = false;
#define COLOR_DEFAULT '7'
#define CON_HISTORY 64
#define MAX_DBG_NOTIFY 128
#define CON_MAXCMDS 4096 // auto-complete intermediate list
#define CON_NUMFONTS 3 // maxfonts
#define CON_LINES( i ) (con.lines[(con.lines_first + (i)) % con.maxlines])
@ -60,14 +59,6 @@ rgba_t g_color_table[8] =
{ 240, 180, 24, 255 }, // default color (can be changed by user)
};
typedef struct
{
string buffer;
int cursor;
int scroll;
int widthInChars;
} field_t;
typedef struct
{
string szNotify;
@ -123,21 +114,15 @@ typedef struct
field_t historyLines[CON_HISTORY];
int historyLine; // the line being displayed from history buffer will be <= nextHistoryLine
int nextHistoryLine; // the last line in the history buffer, not masked
field_t backup;
notify_t notify[MAX_DBG_NOTIFY]; // for Con_NXPrintf
qboolean draw_notify; // true if we have NXPrint message
// console auto-complete
string shortestMatch;
field_t *completionField; // con.input or dedicated server fake field-line
const char *completionString;
const char *completionBuffer;
char *cmds[CON_MAXCMDS];
int matchCount;
} console_t;
static console_t con;
void Con_ClearField( field_t *edit );
void Field_CharEvent( field_t *edit, int ch );
/*
@ -193,18 +178,6 @@ void Con_ClearNotify( void )
CON_LINES( i ).addtime = 0.0;
}
/*
================
Con_ClearField
================
*/
void Con_ClearField( field_t *edit )
{
memset( edit->buffer, 0, MAX_STRING );
edit->cursor = 0;
edit->scroll = 0;
}
/*
================
Con_ClearTyping
@ -217,13 +190,7 @@ void Con_ClearTyping( void )
Con_ClearField( &con.input );
con.input.widthInChars = con.linewidth;
// free the old autocomplete list
for( i = 0; i < con.matchCount; i++ )
{
freestring( con.cmds[i] );
}
con.matchCount = 0;
Cmd_AutoCompleteClear();
}
/*
@ -474,7 +441,7 @@ void Con_CheckResize( void )
int i, width;
if( con.curFont && con.curFont->hFontTexture )
charWidth = con.curFont->charWidths['M'] - 1;
charWidth = con.curFont->charWidths['O'] - 1;
width = ( glState.width / charWidth ) - 2;
if( !glw_state.initialized ) width = (640 / 5);
@ -565,12 +532,12 @@ static qboolean Con_LoadFixedWidthFont( const char *fontname, cl_font_t *font )
return false;
// keep source to print directly into conback image
font->hFontTexture = GL_LoadTexture( fontname, NULL, 0, TF_FONT|TF_KEEP_SOURCE, NULL );
font->hFontTexture = GL_LoadTexture( fontname, NULL, 0, TF_FONT|TF_KEEP_SOURCE );
R_GetTextureParms( &fontWidth, NULL, font->hFontTexture );
if( font->hFontTexture && fontWidth != 0 )
{
font->charHeight = fontWidth / 16;
font->charHeight = fontWidth / 16 * con_fontscale->value;
font->type = FONT_FIXED;
// build fixed rectangles
@ -580,7 +547,7 @@ static qboolean Con_LoadFixedWidthFont( const char *fontname, cl_font_t *font )
font->fontRc[i].right = font->fontRc[i].left + fontWidth / 16;
font->fontRc[i].top = (i / 16) * (fontWidth / 16);
font->fontRc[i].bottom = font->fontRc[i].top + fontWidth / 16;
font->charWidths[i] = fontWidth / 16;
font->charWidths[i] = fontWidth / 16 * con_fontscale->value;
}
font->valid = true;
}
@ -601,7 +568,7 @@ static qboolean Con_LoadVariableWidthFont( const char *fontname, cl_font_t *font
if( !FS_FileExists( fontname, false ))
return false;
font->hFontTexture = GL_LoadTexture( fontname, NULL, 0, TF_FONT|TF_NEAREST, NULL );
font->hFontTexture = GL_LoadTexture( fontname, NULL, 0, TF_FONT|TF_NEAREST );
R_GetTextureParms( &fontWidth, NULL, font->hFontTexture );
// setup consolefont
@ -894,9 +861,10 @@ draw console single character
*/
static int Con_DrawGenericChar( int x, int y, int number, rgba_t color )
{
int width, height;
float s1, t1, s2, t2;
wrect_t *rc;
int width, height;
float s1, t1, s2, t2;
gl_texture_t *glt;
wrect_t *rc;
number &= 255;
@ -904,14 +872,24 @@ static int Con_DrawGenericChar( int x, int y, int number, rgba_t color )
return 0;
number = Con_UtfProcessChar(number);
if( number < 32 )
if( !number )
return 0;
if( y < -con.curFont->charHeight )
return 0;
rc = &con.curFont->fontRc[number];
glt = R_GetTexture( con.curFont->hFontTexture );
width = glt->srcWidth;
height = glt->srcHeight;
pglColor4ubv( color );
if( !width || !height )
return con.curFont->charWidths[number];
// don't apply color to fixed fonts it's already colored
if( con.curFont->type != FONT_FIXED || glt->format == GL_LUMINANCE8_ALPHA8 )
pglColor4ubv( color );
else pglColor4ub( 255, 255, 255, color[3] );
R_GetTextureParms( &width, &height, con.curFont->hFontTexture );
// calc rectangle
@ -1102,6 +1080,61 @@ int Con_DrawString( int x, int y, const char *string, rgba_t setColor )
return Con_DrawGenericString( x, y, string, setColor, false, -1 );
}
void Con_LoadHistory( void )
{
const char *aFile = FS_LoadFile( "console_history.txt", NULL, true );
const char *pLine = aFile, *pFile = aFile;
int i;
if( !aFile )
return;
while( true )
{
if( !*pFile )
break;
if( *pFile == '\n')
{
int len = pFile - pLine + 1;
if( len > 255 ) len = 255;
Con_ClearField( &con.historyLines[con.nextHistoryLine] );
field_t *f = &con.historyLines[con.nextHistoryLine % CON_HISTORY];
f->widthInChars = con.linewidth;
f->cursor = len - 1;
Q_strncpy( f->buffer, pLine, len);
con.nextHistoryLine++;
pLine = pFile + 1;
}
pFile++;
}
for( i = con.nextHistoryLine; i < CON_HISTORY; i++ )
{
Con_ClearField( &con.historyLines[i] );
con.historyLines[i].widthInChars = con.linewidth;
}
con.historyLine = con.nextHistoryLine;
}
void Con_SaveHistory( void )
{
int historyStart = con.nextHistoryLine - CON_HISTORY;
int i;
file_t *f;
if( historyStart < 0 )
historyStart = 0;
f = FS_Open("console_history.txt", "w", true );
for( i = historyStart; i < con.nextHistoryLine; i++ )
FS_Printf( f, "%s\n", con.historyLines[i % CON_HISTORY].buffer );
FS_Close(f);
}
/*
================
Con_Init
@ -1124,9 +1157,9 @@ void Con_Init( void )
// init the console buffer
con.bufsize = CON_TEXTSIZE;
con.buffer = (char *)Z_Malloc( con.bufsize );
con.buffer = (char *)Z_Calloc( con.bufsize );
con.maxlines = CON_MAXLINES;
con.lines = (con_lineinfo_t *)Z_Malloc( con.maxlines * sizeof( *con.lines ));
con.lines = (con_lineinfo_t *)Z_Calloc( con.maxlines * sizeof( *con.lines ));
con.lines_first = con.lines_count = 0;
con.num_times = CON_TIMES; // default as 4
@ -1138,12 +1171,6 @@ void Con_Init( void )
Con_ClearField( &con.chat );
con.chat.widthInChars = con.linewidth;
for( i = 0; i < CON_HISTORY; i++ )
{
Con_ClearField( &con.historyLines[i] );
con.historyLines[i].widthInChars = con.linewidth;
}
Cmd_AddCommand( "toggleconsole", Con_ToggleConsole_f, "opens or closes the console" );
Cmd_AddCommand( "con_color", Con_SetColor_f, "set a custom console color" );
Cmd_AddCommand( "clear", Con_Clear_f, "clear console history" );
@ -1152,7 +1179,7 @@ void Con_Init( void )
Cmd_AddCommand( "contimes", Con_SetTimes_f, "change number of console overlay lines (4-64)" );
con.initialized = true;
MsgDev( D_INFO, "Console initialized.\n" );
Con_Printf( "Console initialized.\n" );
}
/*
@ -1172,6 +1199,7 @@ void Con_Shutdown( void )
con.buffer = NULL;
con.lines = NULL;
Con_SaveHistory();
}
/*
@ -1368,216 +1396,15 @@ EDIT FIELDS
=============================================================================
*/
/*
===============
Con_AddCommandToList
===============
================
Con_ClearField
================
*/
static void Con_AddCommandToList( const char *s, const char *unused1, const char *unused2, void *unused3 )
void Con_ClearField( field_t *edit )
{
if( *s == '@' ) return; // never show system cvars or cmds
if( con.matchCount >= CON_MAXCMDS ) return; // list is full
if( Q_strnicmp( s, con.completionString, Q_strlen( con.completionString )))
return; // no match
con.cmds[con.matchCount++] = copystring( s );
}
/*
=================
Con_SortCmds
=================
*/
static int Con_SortCmds( const char **arg1, const char **arg2 )
{
return Q_stricmp( *arg1, *arg2 );
}
/*
===============
Con_PrintCmdMatches
===============
*/
static void Con_PrintCmdMatches( const char *s, const char *unused1, const char *m, void *unused2 )
{
if( !Q_strnicmp( s, con.shortestMatch, Q_strlen( con.shortestMatch )))
{
if( COM_CheckString( m )) Con_Printf( " %s ^3\"%s\"\n", s, m );
else Con_Printf( " %s\n", s ); // variable or command without description
}
}
/*
===============
Con_PrintCvarMatches
===============
*/
static void Con_PrintCvarMatches( const char *s, const char *value, const char *m, void *unused2 )
{
if( !Q_strnicmp( s, con.shortestMatch, Q_strlen( con.shortestMatch )))
{
if( COM_CheckString( m )) Con_Printf( " %s (%s) ^3\"%s\"\n", s, value, m );
else Con_Printf( " %s (%s)\n", s, value ); // variable or command without description
}
}
/*
===============
Con_ConcatRemaining
===============
*/
static void Con_ConcatRemaining( const char *src, const char *start )
{
const char *arg;
int i;
arg = Q_strstr( src, start );
if( !arg )
{
for( i = 1; i < Cmd_Argc(); i++ )
{
Q_strncat( con.completionField->buffer, " ", sizeof( con.completionField->buffer ));
arg = Cmd_Argv( i );
while( *arg )
{
if( *arg == ' ' )
{
Q_strncat( con.completionField->buffer, "\"", sizeof( con.completionField->buffer ));
break;
}
arg++;
}
Q_strncat( con.completionField->buffer, Cmd_Argv( i ), sizeof( con.completionField->buffer ));
if( *arg == ' ' ) Q_strncat( con.completionField->buffer, "\"", sizeof( con.completionField->buffer ));
}
return;
}
arg += Q_strlen( start );
Q_strncat( con.completionField->buffer, arg, sizeof( con.completionField->buffer ));
}
/*
===============
Con_CompleteCommand
perform Tab expansion
===============
*/
void Con_CompleteCommand( field_t *field )
{
field_t temp;
string filename;
qboolean nextcmd;
int i;
// setup the completion field
con.completionField = field;
// only look at the first token for completion purposes
Cmd_TokenizeString( con.completionField->buffer );
nextcmd = ( con.completionField->buffer[Q_strlen( con.completionField->buffer ) - 1] == ' ' ) ? true : false;
con.completionString = Cmd_Argv( 0 );
con.completionBuffer = Cmd_Argv( 1 );
// skip backslash
while( *con.completionString && ( *con.completionString == '\\' || *con.completionString == '/' ))
con.completionString++;
// skip backslash
while( *con.completionBuffer && ( *con.completionBuffer == '\\' || *con.completionBuffer == '/' ))
con.completionBuffer++;
if( !Q_strlen( con.completionString ))
return;
// free the old autocomplete list
for( i = 0; i < con.matchCount; i++ )
{
if( con.cmds[i] != NULL )
{
Mem_Free( con.cmds[i] );
con.cmds[i] = NULL;
}
}
con.matchCount = 0;
con.shortestMatch[0] = 0;
// find matching commands and variables
Cmd_LookupCmds( NULL, NULL, Con_AddCommandToList );
Cvar_LookupVars( 0, NULL, NULL, Con_AddCommandToList );
if( !con.matchCount ) return; // no matches
memcpy( &temp, con.completionField, sizeof( field_t ));
// autocomplete second arg
if(( Cmd_Argc() == 2 ) || (( Cmd_Argc() == 1 ) && nextcmd ))
{
if( !Q_strlen( con.completionBuffer ))
return;
if( Cmd_AutocompleteName( con.completionBuffer, filename, sizeof( filename )))
{
Q_sprintf( con.completionField->buffer, "%s %s", Cmd_Argv( 0 ), filename );
con.completionField->cursor = Q_strlen( con.completionField->buffer );
}
// don't adjusting cursor pos if we nothing found
return;
}
else if( Cmd_Argc() >= 3 )
{
// disable autocomplete for all next args
return;
}
if( con.matchCount == 1 )
{
Q_sprintf( con.completionField->buffer, "\\%s", con.cmds[0] );
if( Cmd_Argc() == 1 ) Q_strncat( con.completionField->buffer, " ", sizeof( con.completionField->buffer ));
else Con_ConcatRemaining( temp.buffer, con.completionString );
con.completionField->cursor = Q_strlen( con.completionField->buffer );
}
else
{
char *first, *last;
int len = 0;
qsort( con.cmds, con.matchCount, sizeof( char* ), Con_SortCmds );
// find the number of matching characters between the first and
// the last element in the list and copy it
first = con.cmds[0];
last = con.cmds[con.matchCount-1];
while( *first && *last && Q_tolower( *first ) == Q_tolower( *last ))
{
first++;
last++;
con.shortestMatch[len] = con.cmds[0][len];
len++;
}
con.shortestMatch[len] = 0;
// multiple matches, complete to shortest
Q_sprintf( con.completionField->buffer, "\\%s", con.shortestMatch );
con.completionField->cursor = Q_strlen( con.completionField->buffer );
Con_ConcatRemaining( temp.buffer, con.completionString );
Con_Printf( "]%s\n", con.completionField->buffer );
// run through again, printing matches
Cmd_LookupCmds( NULL, NULL, Con_PrintCmdMatches );
Cvar_LookupVars( 0, NULL, NULL, Con_PrintCvarMatches );
}
memset(edit->buffer, 0, MAX_STRING);
edit->cursor = 0;
edit->scroll = 0;
}
/*
@ -1865,6 +1692,7 @@ void Key_Console( int key )
Con_ClearField( &con.input );
con.input.widthInChars = con.linewidth;
Con_Bottom();
if( cls.state == ca_disconnected )
{
@ -1878,12 +1706,15 @@ void Key_Console( int key )
if( key == K_TAB )
{
Con_CompleteCommand( &con.input );
Con_Bottom();
return;
}
// command history (ctrl-p ctrl-n for unix style)
if(( key == K_MWHEELUP && Key_IsDown( K_SHIFT )) || ( key == K_UPARROW ) || (( Q_tolower(key) == 'p' ) && Key_IsDown( K_CTRL )))
{
if( con.historyLine == con.nextHistoryLine )
con.backup = con.input;
if( con.nextHistoryLine - con.historyLine < CON_HISTORY && con.historyLine > 0 )
con.historyLine--;
con.input = con.historyLines[con.historyLine % CON_HISTORY];
@ -1892,9 +1723,13 @@ void Key_Console( int key )
if(( key == K_MWHEELDOWN && Key_IsDown( K_SHIFT )) || ( key == K_DOWNARROW ) || (( Q_tolower(key) == 'n' ) && Key_IsDown( K_CTRL )))
{
if( con.historyLine == con.nextHistoryLine ) return;
con.historyLine++;
con.input = con.historyLines[con.historyLine % CON_HISTORY];
if( con.historyLine >= con.nextHistoryLine - 1 )
con.input = con.backup;
else
{
con.historyLine++;
con.input = con.historyLines[con.historyLine % CON_HISTORY];
}
return;
}
@ -2201,7 +2036,7 @@ void Con_DrawSolidConsole( int lines )
// draw the background
GL_SetRenderMode( kRenderNormal );
pglColor4ub( 255, 255, 255, 255 ); // to prevent grab color from screenfade
R_DrawStretchPic( 0, lines - glState.height, glState.width, glState.height, 0, 0, 1, 1, con.background );
R_DrawStretchPic( 0, lines - glState.width * 3 / 4, glState.width, glState.width * 3 / 4, 0, 0, 1, 1, con.background );
if( !con.curFont || !host.allow_console )
return; // nothing to draw
@ -2215,7 +2050,9 @@ void Con_DrawSolidConsole( int lines )
memcpy( color, g_color_table[7], sizeof( color ));
Q_snprintf( curbuild, MAX_STRING, "%s %i/%s (hw build %i)", XASH_ENGINE_NAME, PROTOCOL_VERSION, XASH_VERSION, Q_buildnum( ));
Q_snprintf( curbuild, MAX_STRING, "%s %i/%s (%s-%s build %i)", XASH_ENGINE_NAME, PROTOCOL_VERSION, XASH_VERSION, Q_buildos(), Q_buildarch(), Q_buildnum( ));
Con_DrawStringLen( curbuild, &stringLen, &charH );
start = glState.width - stringLen;
stringLen = Con_StringLength( curbuild );
@ -2364,9 +2201,13 @@ void Con_DrawVersion( void )
return;
}
if( host.force_draw_version_time > host.realtime )
host.force_draw_version = false;
if( host.force_draw_version || draw_version )
Q_snprintf( curbuild, MAX_STRING, "%s v%i/%s (build %i)", XASH_ENGINE_NAME, PROTOCOL_VERSION, XASH_VERSION, Q_buildnum( ));
else Q_snprintf( curbuild, MAX_STRING, "v%i/%s (build %i)", PROTOCOL_VERSION, XASH_VERSION, Q_buildnum( ));
Q_snprintf( curbuild, MAX_STRING, "%s v%i/%s (%s-%s build %i)", XASH_ENGINE_NAME, PROTOCOL_VERSION, XASH_VERSION, Q_buildos(), Q_buildarch(), Q_buildnum( ));
else Q_snprintf( curbuild, MAX_STRING, "v%i/%s (%s-%s build %i)", PROTOCOL_VERSION, XASH_VERSION, Q_buildos(), Q_buildarch(), Q_buildnum( ));
Con_DrawStringLen( curbuild, &stringLen, &charH );
start = glState.width - stringLen * 1.05f;
stringLen = Con_StringLength( curbuild );
@ -2481,28 +2322,28 @@ void Con_VidInit( void )
{
// trying to load truecolor image first
if( FS_FileExists( "gfx/shell/conback.bmp", false ) || FS_FileExists( "gfx/shell/conback.tga", false ))
con.background = GL_LoadTexture( "gfx/shell/conback", NULL, 0, TF_IMAGE, NULL );
con.background = GL_LoadTexture( "gfx/shell/conback", NULL, 0, TF_IMAGE );
if( !con.background )
{
if( FS_FileExists( "cached/conback640", false ))
con.background = GL_LoadTexture( "cached/conback640", NULL, 0, TF_IMAGE, NULL );
con.background = GL_LoadTexture( "cached/conback640", NULL, 0, TF_IMAGE );
else if( FS_FileExists( "cached/conback", false ))
con.background = GL_LoadTexture( "cached/conback", NULL, 0, TF_IMAGE, NULL );
con.background = GL_LoadTexture( "cached/conback", NULL, 0, TF_IMAGE );
}
}
else
{
// trying to load truecolor image first
if( FS_FileExists( "gfx/shell/loading.bmp", false ) || FS_FileExists( "gfx/shell/loading.tga", false ))
con.background = GL_LoadTexture( "gfx/shell/loading", NULL, 0, TF_IMAGE, NULL );
con.background = GL_LoadTexture( "gfx/shell/loading", NULL, 0, TF_IMAGE );
if( !con.background )
{
if( FS_FileExists( "cached/loading640", false ))
con.background = GL_LoadTexture( "cached/loading640", NULL, 0, TF_IMAGE, NULL );
con.background = GL_LoadTexture( "cached/loading640", NULL, 0, TF_IMAGE );
else if( FS_FileExists( "cached/loading", false ))
con.background = GL_LoadTexture( "cached/loading", NULL, 0, TF_IMAGE, NULL );
con.background = GL_LoadTexture( "cached/loading", NULL, 0, TF_IMAGE );
}
}
@ -2511,7 +2352,7 @@ void Con_VidInit( void )
{
qboolean draw_to_console = false;
int length = 0;
gltexture_t *chars;
gl_texture_t *chars;
// NOTE: only these games want to draw build number into console background
if( !Q_stricmp( FS_Gamedir(), "id1" ))
@ -2537,13 +2378,13 @@ void Con_VidInit( void )
y = Q_strlen( ver );
for( x = 0; x < y; x++ )
Con_DrawCharToConback( ver[x], chars->original->buffer, dest + (x << 3));
con.background = GL_LoadTexture( "#gfx/conback.lmp", (byte *)cb, length, TF_IMAGE, NULL );
con.background = GL_LoadTexture( "#gfx/conback.lmp", (byte *)cb, length, TF_IMAGE );
}
if( cb ) Mem_Free( cb );
}
if( !con.background ) // trying the load unmodified conback
con.background = GL_LoadTexture( "gfx/conback.lmp", NULL, 0, TF_IMAGE, NULL );
con.background = GL_LoadTexture( "gfx/conback.lmp", NULL, 0, TF_IMAGE );
}
// missed console image will be replaced as gray background like X-Ray or Crysis
@ -2563,32 +2404,6 @@ void Con_InvalidateFonts( void )
con.curFont = con.lastUsedFont = NULL;
}
/*
=========
Cmd_AutoComplete
NOTE: input string must be equal or longer than MAX_STRING
=========
*/
void Cmd_AutoComplete( char *complete_string )
{
field_t input;
if( !complete_string || !*complete_string )
return;
// setup input
Q_strncpy( input.buffer, complete_string, sizeof( input.buffer ));
input.cursor = input.scroll = 0;
Con_CompleteCommand( &input );
// setup output
if( input.buffer[0] == '\\' || input.buffer[0] == '/' )
Q_strncpy( complete_string, input.buffer + 1, sizeof( input.buffer ));
else Q_strncpy( complete_string, input.buffer, sizeof( input.buffer ));
}
/*
=========
Con_FastClose

View file

@ -318,10 +318,10 @@ void GL_MakeAliasModelDisplayLists( model_t *m )
// save the data out
m_pAliasHeader->poseverts = g_numorder;
m_pAliasHeader->commands = Mem_Alloc( m->mempool, g_numcommands * 4 );
m_pAliasHeader->commands = Mem_Malloc( m->mempool, g_numcommands * 4 );
memcpy( m_pAliasHeader->commands, g_commands, g_numcommands * 4 );
m_pAliasHeader->posedata = Mem_Alloc( m->mempool, m_pAliasHeader->numposes * m_pAliasHeader->poseverts * sizeof( trivertex_t ));
m_pAliasHeader->posedata = Mem_Malloc( m->mempool, m_pAliasHeader->numposes * m_pAliasHeader->poseverts * sizeof( trivertex_t ));
verts = m_pAliasHeader->posedata;
for( i = 0; i < m_pAliasHeader->numposes; i++ )
@ -433,12 +433,15 @@ rgbdata_t *Mod_CreateSkinData( model_t *mod, byte *data, int width, int height )
skin.palette = (byte *)&clgame.palette;
skin.size = width * height;
for( i = 0; i < skin.width * skin.height; i++ )
if( !Image_CustomPalette() )
{
if( data[i] > 224 && data[i] != 255 )
for( i = 0; i < skin.width * skin.height; i++ )
{
SetBits( skin.flags, IMAGE_HAS_LUMA );
break;
if( data[i] > 224 && data[i] != 255 )
{
SetBits( skin.flags, IMAGE_HAS_LUMA );
break;
}
}
}
@ -453,7 +456,7 @@ rgbdata_t *Mod_CreateSkinData( model_t *mod, byte *data, int width, int height )
i = mod->numtextures;
mod->textures = (texture_t **)Mem_Realloc( mod->mempool, mod->textures, ( i + 1 ) * sizeof( texture_t* ));
size = width * height + 768;
tx = Mem_Alloc( mod->mempool, sizeof( *tx ) + size );
tx = Mem_Calloc( mod->mempool, sizeof( *tx ) + size );
mod->textures[i] = tx;
Q_strncpy( tx->name, "DM_Skin", sizeof( tx->name ));
@ -478,16 +481,19 @@ rgbdata_t *Mod_CreateSkinData( model_t *mod, byte *data, int width, int height )
void *Mod_LoadSingleSkin( daliasskintype_t *pskintype, int skinnum, int size )
{
string name, lumaname;
string checkname;
rgbdata_t *pic;
Q_snprintf( name, sizeof( name ), "%s:frame%i", loadmodel->name, skinnum );
Q_snprintf( lumaname, sizeof( lumaname ), "%s:luma%i", loadmodel->name, skinnum );
pic = Mod_CreateSkinData( loadmodel, (byte *)(pskintype + 1), m_pAliasHeader->skinwidth, m_pAliasHeader->skinheight );
Q_snprintf( checkname, sizeof( checkname ), "%s_%i.tga", loadmodel->name, skinnum );
if( !FS_FileExists( checkname, false ) || ( pic = FS_LoadImage( checkname, NULL, 0 )) == NULL )
pic = Mod_CreateSkinData( loadmodel, (byte *)(pskintype + 1), m_pAliasHeader->skinwidth, m_pAliasHeader->skinheight );
m_pAliasHeader->gl_texturenum[skinnum][0] =
m_pAliasHeader->gl_texturenum[skinnum][1] =
m_pAliasHeader->gl_texturenum[skinnum][2] =
m_pAliasHeader->gl_texturenum[skinnum][3] = GL_LoadTextureInternal( name, pic, 0, false );
m_pAliasHeader->gl_texturenum[skinnum][3] = GL_LoadTextureInternal( name, pic, 0 );
FS_FreeImage( pic );
if( R_GetTexture( m_pAliasHeader->gl_texturenum[skinnum][0] )->flags & TF_HAS_LUMA )
@ -496,7 +502,7 @@ void *Mod_LoadSingleSkin( daliasskintype_t *pskintype, int skinnum, int size )
m_pAliasHeader->fb_texturenum[skinnum][0] =
m_pAliasHeader->fb_texturenum[skinnum][1] =
m_pAliasHeader->fb_texturenum[skinnum][2] =
m_pAliasHeader->fb_texturenum[skinnum][3] = GL_LoadTextureInternal( lumaname, pic, TF_MAKELUMA, false );
m_pAliasHeader->fb_texturenum[skinnum][3] = GL_LoadTextureInternal( lumaname, pic, TF_MAKELUMA );
FS_FreeImage( pic );
}
@ -521,14 +527,14 @@ void *Mod_LoadGroupSkin( daliasskintype_t *pskintype, int skinnum, int size )
{
Q_snprintf( name, sizeof( name ), "%s_%i_%i", loadmodel->name, skinnum, i );
pic = Mod_CreateSkinData( loadmodel, (byte *)(pskintype), m_pAliasHeader->skinwidth, m_pAliasHeader->skinheight );
m_pAliasHeader->gl_texturenum[skinnum][i & 3] = GL_LoadTextureInternal( name, pic, 0, false );
m_pAliasHeader->gl_texturenum[skinnum][i & 3] = GL_LoadTextureInternal( name, pic, 0 );
FS_FreeImage( pic );
if( R_GetTexture( m_pAliasHeader->gl_texturenum[skinnum][i & 3] )->flags & TF_HAS_LUMA )
{
Q_snprintf( lumaname, sizeof( lumaname ), "%s_%i_%i_luma", loadmodel->name, skinnum, i );
pic = Mod_CreateSkinData( NULL, (byte *)(pskintype), m_pAliasHeader->skinwidth, m_pAliasHeader->skinheight );
m_pAliasHeader->fb_texturenum[skinnum][i & 3] = GL_LoadTextureInternal( lumaname, pic, TF_MAKELUMA, false );
m_pAliasHeader->fb_texturenum[skinnum][i & 3] = GL_LoadTextureInternal( lumaname, pic, TF_MAKELUMA );
FS_FreeImage( pic );
}
@ -618,10 +624,9 @@ void Mod_LoadAliasModel( model_t *mod, const void *buffer, qboolean *loaded )
daliashdr_t *pinmodel;
stvert_t *pinstverts;
dtriangle_t *pintriangles;
int numframes, size;
daliasframetype_t *pframetype;
daliasskintype_t *pskintype;
int i, j;
int i, j, size;
if( loaded ) *loaded = false;
pinmodel = (daliashdr_t *)buffer;
@ -629,17 +634,20 @@ void Mod_LoadAliasModel( model_t *mod, const void *buffer, qboolean *loaded )
if( i != ALIAS_VERSION )
{
MsgDev( D_ERROR, "%s has wrong version number (%i should be %i)\n", mod->name, i, ALIAS_VERSION );
Con_DPrintf( S_ERROR "%s has wrong version number (%i should be %i)\n", mod->name, i, ALIAS_VERSION );
return;
}
if( pinmodel->numverts <= 0 || pinmodel->numtris <= 0 || pinmodel->numframes <= 0 )
return; // how to possible is make that?
mod->mempool = Mem_AllocPool( va( "^2%s^7", mod->name ));
// allocate space for a working header, plus all the data except the frames,
// skin and group info
size = sizeof( aliashdr_t ) + (pinmodel->numframes - 1) * sizeof( maliasframedesc_t );
m_pAliasHeader = Mem_Alloc( mod->mempool, size );
m_pAliasHeader = Mem_Calloc( mod->mempool, size );
mod->flags = pinmodel->flags; // share effects flags
// endian-adjust and copy the data, starting with the alias model header
@ -648,33 +656,12 @@ void Mod_LoadAliasModel( model_t *mod, const void *buffer, qboolean *loaded )
m_pAliasHeader->skinwidth = pinmodel->skinwidth;
m_pAliasHeader->skinheight = pinmodel->skinheight;
m_pAliasHeader->numverts = pinmodel->numverts;
if( m_pAliasHeader->numverts <= 0 )
{
MsgDev( D_ERROR, "model %s has no vertices\n", mod->name );
return;
}
m_pAliasHeader->numtris = pinmodel->numtris;
m_pAliasHeader->numframes = pinmodel->numframes;
if( m_pAliasHeader->numverts > MAXALIASVERTS )
{
MsgDev( D_ERROR, "model %s has too many vertices\n", mod->name );
return;
}
m_pAliasHeader->numtris = pinmodel->numtris;
if( m_pAliasHeader->numtris <= 0 )
{
MsgDev( D_ERROR, "model %s has no triangles\n", mod->name );
return;
}
m_pAliasHeader->numframes = pinmodel->numframes;
numframes = m_pAliasHeader->numframes;
if( numframes < 1 )
{
MsgDev( D_ERROR, "Mod_LoadAliasModel: Invalid # of frames: %d\n", numframes );
Con_DPrintf( S_ERROR "model %s has too many vertices\n", mod->name );
return;
}
@ -718,7 +705,7 @@ void Mod_LoadAliasModel( model_t *mod, const void *buffer, qboolean *loaded )
pframetype = (daliasframetype_t *)&pintriangles[m_pAliasHeader->numtris];
g_posenum = 0;
for( i = 0; i < numframes; i++ )
for( i = 0; i < m_pAliasHeader->numframes; i++ )
{
aliasframetype_t frametype = pframetype->type;
@ -863,40 +850,44 @@ void R_AliasDynamicLight( cl_entity_t *ent, alight_t *plight )
VectorScale( lightDir, 2048.0f, vecEnd );
VectorAdd( vecEnd, vecSrc, vecEnd );
light = R_LightVec( vecSrc, vecEnd, g_alias.lightspot );
light = R_LightVec( vecSrc, vecEnd, g_alias.lightspot, g_alias.lightvec );
VectorScale( lightDir, 2048.0f, vecEnd );
VectorAdd( vecEnd, vecSrc, vecEnd );
if( VectorIsNull( g_alias.lightvec ))
{
vecSrc[0] -= 16.0f;
vecSrc[1] -= 16.0f;
vecEnd[0] -= 16.0f;
vecEnd[1] -= 16.0f;
vecSrc[0] -= 16.0f;
vecSrc[1] -= 16.0f;
vecEnd[0] -= 16.0f;
vecEnd[1] -= 16.0f;
gcolor = R_LightVec( vecSrc, vecEnd, NULL, NULL );
grad[0] = ( gcolor.r + gcolor.g + gcolor.b ) / 768.0f;
gcolor = R_LightVec( vecSrc, vecEnd, NULL );
grad[0] = ( gcolor.r + gcolor.g + gcolor.b ) / 768.0f;
vecSrc[0] += 32.0f;
vecEnd[0] += 32.0f;
vecSrc[0] += 32.0f;
vecEnd[0] += 32.0f;
gcolor = R_LightVec( vecSrc, vecEnd, NULL, NULL );
grad[1] = ( gcolor.r + gcolor.g + gcolor.b ) / 768.0f;
gcolor = R_LightVec( vecSrc, vecEnd, NULL );
grad[1] = ( gcolor.r + gcolor.g + gcolor.b ) / 768.0f;
vecSrc[1] += 32.0f;
vecEnd[1] += 32.0f;
vecSrc[1] += 32.0f;
vecEnd[1] += 32.0f;
gcolor = R_LightVec( vecSrc, vecEnd, NULL, NULL );
grad[2] = ( gcolor.r + gcolor.g + gcolor.b ) / 768.0f;
gcolor = R_LightVec( vecSrc, vecEnd, NULL );
grad[2] = ( gcolor.r + gcolor.g + gcolor.b ) / 768.0f;
vecSrc[0] -= 32.0f;
vecEnd[0] -= 32.0f;
vecSrc[0] -= 32.0f;
vecEnd[0] -= 32.0f;
gcolor = R_LightVec( vecSrc, vecEnd, NULL, NULL );
grad[3] = ( gcolor.r + gcolor.g + gcolor.b ) / 768.0f;
gcolor = R_LightVec( vecSrc, vecEnd, NULL );
grad[3] = ( gcolor.r + gcolor.g + gcolor.b ) / 768.0f;
lightDir[0] = grad[0] - grad[1] - grad[2] + grad[3];
lightDir[1] = grad[1] + grad[0] - grad[2] - grad[3];
VectorNormalize( lightDir );
lightDir[0] = grad[0] - grad[1] - grad[2] + grad[3];
lightDir[1] = grad[1] + grad[0] - grad[2] - grad[3];
VectorNormalize( lightDir );
}
else
{
VectorCopy( g_alias.lightvec, lightDir );
}
}
VectorSet( finalLight, light.r, light.g, light.b );
@ -1189,15 +1180,18 @@ void R_AliasLerpMovement( cl_entity_t *e )
if( g_alias.interpolate && ( g_alias.time < e->curstate.animtime + 1.0f ) && ( e->curstate.animtime != e->latched.prevanimtime ))
f = ( g_alias.time - e->curstate.animtime ) / ( e->curstate.animtime - e->latched.prevanimtime );
if( cls.demoplayback == DEMO_QUAKE1 )
f = f + 1.0f;
g_alias.lerpfrac = bound( 0.0f, f, 1.0f );
if( e->player || e->curstate.movetype != MOVETYPE_STEP )
return; // monsters only
// Con_Printf( "%4.2f %.2f %.2f\n", f, e->curstate.animtime, g_studio.time );
// Con_Printf( "%4.2f %.2f %.2f\n", f, e->curstate.animtime, g_alias.time );
VectorLerp( e->latched.prevorigin, f, e->curstate.origin, e->origin );
if( !VectorCompare( e->curstate.angles, e->latched.prevangles ))
if( !VectorCompareEpsilon( e->curstate.angles, e->latched.prevangles, ON_EPSILON ))
{
vec4_t q, q1, q2;
@ -1236,7 +1230,7 @@ void R_SetupAliasFrame( cl_entity_t *e, aliashdr_t *paliashdr )
else if( newframe >= paliashdr->numframes )
{
if( newframe > paliashdr->numframes )
MsgDev( D_WARN, "R_GetAliasFrame: no such frame %d (%s)\n", newframe, e->model->name );
Con_Reportf( S_WARN "R_GetAliasFrame: no such frame %d (%s)\n", newframe, e->model->name );
newframe = paliashdr->numframes - 1;
}
@ -1313,6 +1307,8 @@ static void R_AliasDrawLightTrace( cl_entity_t *e )
{
if( r_drawentities->value == 7 )
{
vec3_t origin;
pglDisable( GL_TEXTURE_2D );
pglDisable( GL_DEPTH_TEST );
@ -1322,6 +1318,13 @@ static void R_AliasDrawLightTrace( cl_entity_t *e )
pglVertex3fv( g_alias.lightspot );
pglEnd();
pglBegin( GL_LINES );
pglColor3f( 0, 0.5, 1 );
VectorMA( g_alias.lightspot, -64.0f, g_alias.lightvec, origin );
pglVertex3fv( g_alias.lightspot );
pglVertex3fv( origin );
pglEnd();
pglPointSize( 5.0f );
pglColor3f( 1, 0, 0 );
pglBegin( GL_POINTS );
@ -1429,11 +1432,16 @@ void R_DrawAliasModel( cl_entity_t *e )
R_AliasSetRemapColors( topcolor, bottomcolor );
}
pglTranslatef( m_pAliasHeader->scale_origin[0], m_pAliasHeader->scale_origin[1], m_pAliasHeader->scale_origin[2] );
if( tr.fFlipViewModel )
{
pglTranslatef( m_pAliasHeader->scale_origin[0], -m_pAliasHeader->scale_origin[1], m_pAliasHeader->scale_origin[2] );
pglScalef( m_pAliasHeader->scale[0], -m_pAliasHeader->scale[1], m_pAliasHeader->scale[2] );
else pglScalef( m_pAliasHeader->scale[0], m_pAliasHeader->scale[1], m_pAliasHeader->scale[2] );
}
else
{
pglTranslatef( m_pAliasHeader->scale_origin[0], m_pAliasHeader->scale_origin[1], m_pAliasHeader->scale_origin[2] );
pglScalef( m_pAliasHeader->scale[0], m_pAliasHeader->scale[1], m_pAliasHeader->scale[2] );
}
anim = (int)(g_alias.time * 10) & 3;
skin = bound( 0, RI.currententity->curstate.skin, m_pAliasHeader->numskins - 1 );
@ -1443,7 +1451,17 @@ void R_DrawAliasModel( cl_entity_t *e )
GL_Bind( XASH_TEXTURE0, tr.whiteTexture );
else if( pinfo != NULL && pinfo->textures[skin] != 0 )
GL_Bind( XASH_TEXTURE0, pinfo->textures[skin] ); // FIXME: allow remapping for skingroups someday
else GL_Bind( XASH_TEXTURE0, m_pAliasHeader->gl_texturenum[skin][anim] );
else
{
GL_Bind( XASH_TEXTURE0, m_pAliasHeader->gl_texturenum[skin][anim] );
if( FBitSet( R_GetTexture( m_pAliasHeader->gl_texturenum[skin][anim] )->flags, TF_HAS_ALPHA ))
{
pglEnable( GL_ALPHA_TEST );
pglAlphaFunc( GL_GREATER, 0.0f );
tr.blend = 1.0f;
}
}
pglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
@ -1470,6 +1488,8 @@ void R_DrawAliasModel( cl_entity_t *e )
R_AliasDrawLightTrace( e );
pglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
pglAlphaFunc( GL_GREATER, DEFAULT_ALPHATEST );
pglDisable( GL_ALPHA_TEST );
if( r_shadows.value )
{

View file

@ -43,6 +43,25 @@ qboolean R_SpeedsMessage( char *out, size_t size )
return true;
}
/*
==============
R_Speeds_Printf
helper to print into r_speeds message
==============
*/
void R_Speeds_Printf( const char *msg, ... )
{
va_list argptr;
char text[2048];
va_start( argptr, msg );
Q_vsprintf( text, msg, argptr );
va_end( argptr );
Q_strncat( r_speeds_msg, text, sizeof( r_speeds_msg ));
}
/*
==============
GL_BackendStartFrame
@ -60,9 +79,17 @@ GL_BackendEndFrame
*/
void GL_BackendEndFrame( void )
{
mleaf_t *curleaf;
if( r_speeds->value <= 0 || !RI.drawWorld )
return;
if( !RI.viewleaf )
curleaf = cl.worldmodel->leafs;
else curleaf = RI.viewleaf;
R_Speeds_Printf( "Renderer: ^1Engine^7\n\n" );
switch( (int)r_speeds->value )
{
case 1:
@ -70,8 +97,8 @@ void GL_BackendEndFrame( void )
r_stats.c_world_polys, r_stats.c_alias_polys, r_stats.c_studio_polys, r_stats.c_sprite_polys );
break;
case 2:
Q_snprintf( r_speeds_msg, sizeof( r_speeds_msg ), "visible leafs:\n%3i leafs\ncurrent leaf %3i",
r_stats.c_world_leafs, Mod_PointInLeaf( RI.pvsorigin, cl.worldmodel->nodes ) - cl.worldmodel->leafs );
R_Speeds_Printf( "visible leafs:\n%3i leafs\ncurrent leaf %3i\n", r_stats.c_world_leafs, curleaf - cl.worldmodel->leafs );
R_Speeds_Printf( "ReciusiveWorldNode: %3lf secs\nDrawTextureChains %lf\n", r_stats.t_world_node, r_stats.t_world_draw );
break;
case 3:
Q_snprintf( r_speeds_msg, sizeof( r_speeds_msg ), "%3i alias models drawn\n%3i studio models drawn\n%3i sprites drawn",
@ -158,7 +185,7 @@ void GL_SelectTexture( GLint tmu )
if( tmu >= GL_MaxTextureUnits( ))
{
MsgDev( D_ERROR, "GL_SelectTexture: bad tmu state %i\n", tmu );
Con_Reportf( S_ERROR "GL_SelectTexture: bad tmu state %i\n", tmu );
return;
}
@ -222,6 +249,7 @@ GL_CleanupAllTextureUnits
*/
void GL_CleanupAllTextureUnits( void )
{
if( !glw_state.initialized ) return;
// force to cleanup all the units
GL_SelectTexture( GL_MaxTextureUnits() - 1 );
GL_CleanUpTextureUnits( 0 );
@ -250,7 +278,7 @@ void GL_TextureTarget( uint target )
{
if( glState.activeTMU < 0 || glState.activeTMU >= GL_MaxTextureUnits( ))
{
MsgDev( D_ERROR, "GL_TextureTarget: bad tmu state %i\n", glState.activeTMU );
Con_Reportf( S_ERROR "GL_TextureTarget: bad tmu state %i\n", glState.activeTMU );
return;
}
@ -463,14 +491,14 @@ qboolean VID_ScreenShot( const char *filename, int shot_type )
int width = 0, height = 0;
qboolean result;
r_shot = Mem_Alloc( r_temppool, sizeof( rgbdata_t ));
r_shot = Mem_Calloc( r_temppool, sizeof( rgbdata_t ));
r_shot->width = (glState.width + 3) & ~3;
r_shot->height = (glState.height + 3) & ~3;
r_shot->flags = IMAGE_HAS_COLOR;
r_shot->type = PF_RGB_24;
r_shot->size = r_shot->width * r_shot->height * PFDesc[r_shot->type].bpp;
r_shot->palette = NULL;
r_shot->buffer = Mem_Alloc( r_temppool, r_shot->size );
r_shot->buffer = Mem_Malloc( r_temppool, r_shot->size );
// get screen frame
pglReadPixels( 0, 0, r_shot->width, r_shot->height, GL_RGB, GL_UNSIGNED_BYTE, r_shot->buffer );
@ -508,7 +536,7 @@ qboolean VID_ScreenShot( const char *filename, int shot_type )
break;
}
Image_Process( &r_shot, width, height, flags, NULL );
Image_Process( &r_shot, width, height, flags, 0.0f );
// write image
result = FS_SaveImage( filename, r_shot );
@ -546,10 +574,10 @@ qboolean VID_CubemapShot( const char *base, uint size, const float *vieworg, qbo
RI.params |= RP_ENVVIEW; // do not render non-bmodel entities
// alloc space
temp = Mem_Alloc( r_temppool, size * size * 3 );
buffer = Mem_Alloc( r_temppool, size * size * 3 * 6 );
r_shot = Mem_Alloc( r_temppool, sizeof( rgbdata_t ));
r_side = Mem_Alloc( r_temppool, sizeof( rgbdata_t ));
temp = Mem_Malloc( r_temppool, size * size * 3 );
buffer = Mem_Malloc( r_temppool, size * size * 3 * 6 );
r_shot = Mem_Calloc( r_temppool, sizeof( rgbdata_t ));
r_side = Mem_Calloc( r_temppool, sizeof( rgbdata_t ));
// use client vieworg
if( !vieworg ) vieworg = RI.vieworg;
@ -568,7 +596,7 @@ qboolean VID_CubemapShot( const char *base, uint size, const float *vieworg, qbo
{
R_DrawCubemapView( vieworg, r_envMapInfo[i].angles, size );
flags = r_envMapInfo[i].flags;
}
}
pglReadPixels( 0, 0, size, size, GL_RGB, GL_UNSIGNED_BYTE, temp );
r_side->flags = IMAGE_HAS_COLOR;
@ -577,7 +605,7 @@ qboolean VID_CubemapShot( const char *base, uint size, const float *vieworg, qbo
r_side->size = r_side->width * r_side->height * 3;
r_side->buffer = temp;
if( flags ) Image_Process( &r_side, 0, 0, flags, NULL );
if( flags ) Image_Process( &r_side, 0, 0, flags, 0.0f );
memcpy( buffer + (size * size * 3 * i), r_side->buffer, size * size * 3 );
}
@ -617,7 +645,7 @@ was there. This is used to test for texture thrashing.
*/
void R_ShowTextures( void )
{
gltexture_t *image;
gl_texture_t *image;
float x, y, w, h;
int total, start, end;
int i, j, k, base_w, base_h;
@ -626,7 +654,7 @@ void R_ShowTextures( void )
static qboolean showHelp = true;
string shortname;
if( !gl_showtextures->value )
if( !CVAR_TO_BOOL( gl_showtextures ))
return;
if( showHelp )
@ -719,3 +747,95 @@ rebuild_page:
CL_DrawCenterPrint ();
pglFinish();
}
#define POINT_SIZE 16.0f
#define NODE_INTERVAL_X(x) (x * 16.0f)
#define NODE_INTERVAL_Y(x) (x * 16.0f)
void R_DrawLeafNode( float x, float y, float scale )
{
float downScale = scale * 0.25f;// * POINT_SIZE;
R_DrawStretchPic( x - downScale * 0.5f, y - downScale * 0.5f, downScale, downScale, 0, 0, 1, 1, tr.particleTexture );
}
void R_DrawNodeConnection( float x, float y, float x2, float y2 )
{
pglBegin( GL_LINES );
pglVertex2f( x, y );
pglVertex2f( x2, y2 );
pglEnd();
}
void R_ShowTree_r( mnode_t *node, float x, float y, float scale, int shownodes )
{
float downScale = scale * 0.8f;
downScale = Q_max( downScale, 1.0f );
if( !node ) return;
tr.recursion_level++;
if( node->contents < 0 )
{
mleaf_t *leaf = (mleaf_t *)node;
if( tr.recursion_level > tr.max_recursion )
tr.max_recursion = tr.recursion_level;
if( shownodes == 1 )
{
if( cl.worldmodel->leafs == leaf )
pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
else if( RI.viewleaf && RI.viewleaf == leaf )
pglColor4f( 1.0f, 0.0f, 0.0f, 1.0f );
else pglColor4f( 0.0f, 1.0f, 0.0f, 1.0f );
R_DrawLeafNode( x, y, scale );
}
tr.recursion_level--;
return;
}
if( shownodes == 1 )
{
pglColor4f( 0.0f, 0.0f, 1.0f, 1.0f );
R_DrawLeafNode( x, y, scale );
}
else if( shownodes == 2 )
{
R_DrawNodeConnection( x, y, x - scale, y + scale );
R_DrawNodeConnection( x, y, x + scale, y + scale );
}
R_ShowTree_r( node->children[1], x - scale, y + scale, downScale, shownodes );
R_ShowTree_r( node->children[0], x + scale, y + scale, downScale, shownodes );
tr.recursion_level--;
}
void R_ShowTree( void )
{
float x = (float)((glState.width - (int)POINT_SIZE) >> 1);
float y = NODE_INTERVAL_Y(1.0);
if( !cl.worldmodel || !CVAR_TO_BOOL( r_showtree ))
return;
tr.recursion_level = 0;
pglEnable( GL_BLEND );
pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
pglLineWidth( 2.0f );
pglColor3f( 1, 0.7f, 0 );
pglDisable( GL_TEXTURE_2D );
R_ShowTree_r( cl.worldmodel->nodes, x, y, tr.max_recursion * 3.5f, 2 );
pglEnable( GL_TEXTURE_2D );
pglLineWidth( 1.0f );
R_ShowTree_r( cl.worldmodel->nodes, x, y, tr.max_recursion * 3.5f, 1 );
Con_NPrintf( 0, "max recursion %d\n", tr.max_recursion );
}

View file

@ -266,7 +266,7 @@ static qboolean R_BeamComputePoint( int beamEnt, vec3_t pt )
if( !ent )
{
MsgDev( D_ERROR, "R_BeamComputePoint: invalid entity %i\n", BEAMENT_ENTITY( beamEnt ));
Con_DPrintf( S_ERROR "R_BeamComputePoint: invalid entity %i\n", BEAMENT_ENTITY( beamEnt ));
VectorClear( pt );
return false;
}
@ -418,8 +418,6 @@ static void R_DrawSegs( vec3_t source, vec3_t delta, float width, float scale, f
div = 1.0f / (segments - 1);
length *= 0.01f;
// UNDONE: Expose texture length scale factor to control "fuzziness"
vStep = length * div; // Texture length texels per space pixel
// Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture)
@ -432,29 +430,21 @@ static void R_DrawSegs( vec3_t source, vec3_t delta, float width, float scale, f
segments = 16;
div = 1.0f / ( segments - 1 );
}
scale *= 100.0f;
length = segments * 0.1f;
}
else
{
scale *= length;
scale *= length * 2.0;
}
// Iterator to resample noise waveform (it needs to be generated in powers of 2)
noiseStep = (int)((float)( NOISE_DIVISIONS - 1 ) * div * 65536.0f );
if( FBitSet( flags, FBEAM_SINENOISE ))
noiseIndex = 0;
else
noiseIndex = noiseStep;
brightness = 1.0f;
noiseIndex = 0;
if( FBitSet( flags, FBEAM_SHADEIN ))
{
brightness = 0;
}
// Choose two vectors that are perpendicular to the beam
R_BeamComputePerpendicular( delta, perp1 );
@ -472,20 +462,6 @@ static void R_DrawSegs( vec3_t source, vec3_t delta, float width, float scale, f
fraction = i * div;
if( FBitSet( flags, FBEAM_SHADEIN ) && FBitSet( flags, FBEAM_SHADEOUT ))
{
if( fraction < 0.5f ) brightness = 2.0f * fraction;
else brightness = 2.0f * ( 1.0f - fraction );
}
else if( FBitSet( flags, FBEAM_SHADEIN ))
{
brightness = fraction;
}
else if( FBitSet( flags, FBEAM_SHADEOUT ))
{
brightness = 1.0f - fraction;
}
VectorMA( source, fraction, delta, nextSeg.pos );
// distort using noise
@ -553,6 +529,20 @@ static void R_DrawSegs( vec3_t source, vec3_t delta, float width, float scale, f
curSeg = nextSeg;
segs_drawn++;
if( FBitSet( flags, FBEAM_SHADEIN ) && FBitSet( flags, FBEAM_SHADEOUT ))
{
if( fraction < 0.5f ) brightness = fraction;
else brightness = ( 1.0f - fraction );
}
else if( FBitSet( flags, FBEAM_SHADEIN ))
{
brightness = fraction;
}
else if( FBitSet( flags, FBEAM_SHADEOUT ))
{
brightness = 1.0f - fraction;
}
if( segs_drawn == total_segs )
{
// draw the last segment
@ -1332,7 +1322,7 @@ CL_InitViewBeams
*/
void CL_InitViewBeams( void )
{
cl_viewbeams = Mem_Alloc( cls.mempool, sizeof( BEAM ) * GI->max_beams );
cl_viewbeams = Mem_Calloc( cls.mempool, sizeof( BEAM ) * GI->max_beams );
CL_ClearViewBeams();
}
@ -1381,7 +1371,7 @@ void CL_AddCustomBeam( cl_entity_t *pEnvBeam )
{
if( tr.draw_list->num_beam_entities >= MAX_VISIBLE_PACKET )
{
MsgDev( D_ERROR, "Too many custom beams %d!\n", tr.draw_list->num_beam_entities );
Con_Printf( S_ERROR "Too many beams %d!\n", tr.draw_list->num_beam_entities );
return;
}
@ -1496,7 +1486,7 @@ void CL_DrawBeams( int fTrans )
BEAM *pPrev = NULL;
int i, flags;
if( !cl_draw_beams->value )
if( !CVAR_TO_BOOL( cl_draw_beams ))
return;
pglShadeModel( GL_SMOOTH );
@ -1875,7 +1865,6 @@ void CL_ParseViewBeam( sizebuf_t *msg, int beamType )
R_BeamEnts( startEnt, endEnt, modelIndex, life, width, noise, a, speed, startFrame, frameRate, r, g, b );
break;
case TE_BEAM:
MsgDev( D_ERROR, "TE_BEAM is obsolete\n" );
break;
case TE_BEAMSPRITE:
start[0] = MSG_ReadCoord( msg );
@ -1901,14 +1890,14 @@ void CL_ParseViewBeam( sizebuf_t *msg, int beamType )
startFrame = MSG_ReadByte( msg );
frameRate = (float)(MSG_ReadByte( msg ));
life = (float)(MSG_ReadByte( msg ) * 0.1f);
width = (float)(MSG_ReadByte( msg ) * 0.1f);
noise = (float)(MSG_ReadByte( msg ) * 0.01f);
width = (float)(MSG_ReadByte( msg ));
noise = (float)(MSG_ReadByte( msg ) * 0.1f);
r = (float)MSG_ReadByte( msg ) / 255.0f;
g = (float)MSG_ReadByte( msg ) / 255.0f;
b = (float)MSG_ReadByte( msg ) / 255.0f;
a = (float)MSG_ReadByte( msg ) / 255.0f;
speed = (float)MSG_ReadByte( msg );
R_BeamCirclePoints( beamType, start, end, modelIndex, life, width, noise, a, speed / 10.0f, startFrame, frameRate, r, g, b );
speed = (float)(MSG_ReadByte( msg ) / 0.1f);
R_BeamCirclePoints( beamType, start, end, modelIndex, life, width, noise, a, speed, startFrame, frameRate, r, g, b );
break;
case TE_BEAMFOLLOW:
startEnt = MSG_ReadShort( msg );
@ -1938,7 +1927,6 @@ void CL_ParseViewBeam( sizebuf_t *msg, int beamType )
R_BeamRing( startEnt, endEnt, modelIndex, life, width, noise, a, speed, startFrame, frameRate, r, g, b );
break;
case TE_BEAMHOSE:
MsgDev( D_ERROR, "TE_BEAMHOSE is obsolete\n" );
break;
case TE_KILLBEAM:
startEnt = MSG_ReadShort( msg );
@ -2015,7 +2003,7 @@ void CL_ReadLineFile_f( void )
count++;
if( !R_BeamPoints( p1, p2, modelIndex, 99999, 2, 0, 255, 0, 0, 0, 255.0f, 0.0f, 0.0f ))
if( !R_BeamPoints( p1, p2, modelIndex, 0, 2, 0, 255, 0, 0, 0, 255.0f, 0.0f, 0.0f ))
{
if( !model || model->type != mod_sprite )
Con_Printf( S_ERROR "failed to load \"%s\"!\n", DEFAULT_LASERBEAM_PATH );

View file

@ -524,7 +524,7 @@ glpoly_t *R_DecalCreatePoly( decalinfo_t *decalinfo, decal_t *pdecal, msurface_t
if( !lnumverts ) return NULL; // probably this never happens
// allocate glpoly
poly = Mem_Alloc( com_studiocache, sizeof( glpoly_t ) + ( lnumverts - 4 ) * VERTEXSIZE * sizeof( float ));
poly = Mem_Calloc( com_studiocache, sizeof( glpoly_t ) + ( lnumverts - 4 ) * VERTEXSIZE * sizeof( float ));
poly->next = pdecal->polys;
poly->flags = surf->flags;
pdecal->polys = poly;
@ -577,11 +577,7 @@ static void R_DecalCreate( decalinfo_t *decalinfo, msurface_t *surf, float x, fl
decal_t *pdecal, *pold;
int count, vertCount;
if( !surf )
{
MsgDev( D_ERROR, "psurface NULL in R_DecalCreate!\n" );
return;
}
if( !surf ) return; // ???
pold = R_DecalIntersect( decalinfo, surf, &count );
if( count < MAX_OVERLAP_DECALS ) pold = NULL;
@ -763,7 +759,7 @@ void R_DecalShoot( int textureIndex, int entityIndex, int modelIndex, vec3_t pos
if( textureIndex <= 0 || textureIndex >= MAX_TEXTURES )
{
MsgDev( D_ERROR, "Decal has invalid texture!\n" );
Con_Printf( S_ERROR "Decal has invalid texture!\n" );
return;
}
@ -783,7 +779,7 @@ void R_DecalShoot( int textureIndex, int entityIndex, int modelIndex, vec3_t pos
if( model->type != mod_brush )
{
MsgDev( D_ERROR, "Decals must hit mod_brush!\n" );
Con_Printf( S_ERROR "Decals must hit mod_brush!\n" );
return;
}
@ -988,7 +984,6 @@ void DrawSurfaceDecals( msurface_t *fa, qboolean single, qboolean reverse )
}
}
pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
if( reverse && e->curstate.rendermode == kRenderTransTexture )
@ -1224,10 +1219,7 @@ void R_DecalRemoveAll( int textureIndex )
int i;
if( textureIndex < 0 || textureIndex >= MAX_TEXTURES )
{
MsgDev( D_ERROR, "Decal has invalid texture!\n" );
return;
}
return; // out of bounds
for( i = 0; i < gDecalCount; i++ )
{

View file

@ -24,7 +24,7 @@ R_GetImageParms
*/
void R_GetTextureParms( int *w, int *h, int texnum )
{
gltexture_t *glt;
gl_texture_t *glt;
glt = R_GetTexture( texnum );
if( w ) *w = glt->srcWidth;
@ -94,7 +94,7 @@ refresh window.
void R_DrawTileClear( int x, int y, int w, int h )
{
float tw, th;
gltexture_t *glt;
gl_texture_t *glt;
GL_SetRenderMode( kRenderNormal );
pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
@ -124,7 +124,7 @@ R_DrawStretchRaw
void R_DrawStretchRaw( float x, float y, float w, float h, int cols, int rows, const byte *data, qboolean dirty )
{
byte *raw = NULL;
gltexture_t *tex;
gl_texture_t *tex;
if( !GL_Support( GL_ARB_TEXTURE_NPOT_EXT ))
{
@ -196,7 +196,7 @@ R_UploadStretchRaw
void R_UploadStretchRaw( int texture, int cols, int rows, int width, int height, const byte *data )
{
byte *raw = NULL;
gltexture_t *tex;
gl_texture_t *tex;
if( !GL_Support( GL_ARB_TEXTURE_NPOT_EXT ))
{

View file

@ -148,6 +148,7 @@ typedef float GLmatrix[16];
#define GL_2_BYTES 0x1407
#define GL_3_BYTES 0x1408
#define GL_4_BYTES 0x1409
#define GL_HALF_FLOAT_ARB 0x140B
#define GL_VERTEX_ARRAY 0x8074
#define GL_NORMAL_ARRAY 0x8075
@ -390,6 +391,7 @@ typedef float GLmatrix[16];
#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
#define GL_COMPRESSED_RED_GREEN_RGTC2_EXT 0x8DBD
#define GL_COMPRESSED_ALPHA_ARB 0x84E9
#define GL_COMPRESSED_LUMINANCE_ARB 0x84EA
#define GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB

File diff suppressed because it is too large Load diff

View file

@ -38,6 +38,7 @@ extern byte *r_temppool;
#define SHADEDOT_QUANT 16 // precalculated dot products for quantized angles
#define SHADE_LAMBERT 1.495f
#define DEFAULT_ALPHATEST 0.0f
// refparams
#define RP_NONE 0
@ -92,7 +93,7 @@ typedef struct gltexture_s
int servercount;
uint hashValue;
struct gltexture_s *nextHash;
} gltexture_t;
} gl_texture_t;
typedef struct
{
@ -201,6 +202,10 @@ typedef struct
qboolean fResetVis;
qboolean fFlipViewModel;
// tree visualization stuff
int recursion_level;
int max_recursion;
byte visbytes[(MAX_MAP_LEAFS+7)/8]; // member custom PVS
int lightstylevalue[MAX_LIGHTSTYLES]; // value 0 - 65536
int block_size; // lightmap blocksize
@ -228,6 +233,8 @@ typedef struct
uint c_particle_count;
uint c_client_ents; // entities that moved to client
double t_world_node;
double t_world_draw;
} ref_speeds_t;
extern ref_speeds_t r_stats;
@ -235,8 +242,6 @@ extern ref_instance_t RI;
extern ref_globals_t tr;
extern float gldepthmin, gldepthmax;
extern mleaf_t *r_viewleaf, *r_oldviewleaf;
extern mleaf_t *r_viewleaf2, *r_oldviewleaf2;
extern dlight_t cl_dlights[MAX_DLIGHTS];
extern dlight_t cl_elights[MAX_ELIGHTS];
#define r_numEntities (tr.draw_list->num_solid_entities + tr.draw_list->num_trans_entities)
@ -267,6 +272,7 @@ void GL_SetRenderMode( int mode );
void GL_TextureTarget( uint target );
void GL_Cull( GLenum cull );
void R_ShowTextures( void );
void R_ShowTree( void );
//
// gl_cull.c
@ -293,20 +299,28 @@ void R_Set2DMode( qboolean enable );
void R_DrawTileClear( int x, int y, int w, int h );
void R_UploadStretchRaw( int texture, int cols, int rows, int width, int height, const byte *data );
//
// gl_drawhulls.c
//
void R_DrawWorldHull( void );
void R_DrawModelHull( void );
//
// gl_image.c
//
void R_SetTextureParameters( void );
gltexture_t *R_GetTexture( GLenum texnum );
int GL_LoadTexture( const char *name, const byte *buf, size_t size, int flags, imgfilter_t *filter );
int GL_LoadTextureArray( const char **names, int flags, imgfilter_t *filter );
int GL_LoadTextureInternal( const char *name, rgbdata_t *pic, texFlags_t flags, qboolean update );
gl_texture_t *R_GetTexture( GLenum texnum );
#define GL_LoadTextureInternal( name, pic, flags ) GL_LoadTextureFromBuffer( name, pic, flags, false )
#define GL_UpdateTextureInternal( name, pic, flags ) GL_LoadTextureFromBuffer( name, pic, flags, true )
int GL_LoadTexture( const char *name, const byte *buf, size_t size, int flags );
int GL_LoadTextureArray( const char **names, int flags );
int GL_LoadTextureFromBuffer( const char *name, rgbdata_t *pic, texFlags_t flags, qboolean update );
byte *GL_ResampleTexture( const byte *source, int in_w, int in_h, int out_w, int out_h, qboolean isNormalMap );
int GL_CreateTexture( const char *name, int width, int height, const void *buffer, texFlags_t flags );
int GL_CreateTextureArray( const char *name, int width, int height, int depth, const void *buffer, texFlags_t flags );
void GL_ProcessTexture( int texnum, float gamma, int topColor, int bottomColor );
void GL_ApplyTextureParams( gltexture_t *tex );
void R_FreeImage( gltexture_t *image );
void GL_UpdateTexSize( int texnum, int width, int height, int depth );
void GL_ApplyTextureParams( gl_texture_t *tex );
int GL_FindTexture( const char *name );
void GL_FreeTexture( GLenum texnum );
void GL_FreeImage( const char *name );
@ -328,8 +342,7 @@ void R_PushDlights( void );
void R_AnimateLight( void );
void R_GetLightSpot( vec3_t lightspot );
void R_MarkLights( dlight_t *light, int bit, mnode_t *node );
void R_LightForPoint( const vec3_t point, color24 *ambientLight, qboolean invLight, qboolean useAmbient, float radius );
colorVec R_LightVec( const vec3_t start, const vec3_t end, vec3_t lightspot );
colorVec R_LightVec( const vec3_t start, const vec3_t end, vec3_t lightspot, vec3_t lightvec );
int R_CountSurfaceDlights( msurface_t *surf );
colorVec R_LightPoint( const vec3_t p0 );
int R_CountDlights( void );
@ -376,8 +389,7 @@ void Matrix4x4_CreateModelview( matrix4x4 out );
//
// gl_rmisc.
//
void R_ParseTexFilters( const char *filename );
imgfilter_t *R_FindTexFilter( const char *texname );
void R_ClearStaticEntities( void );
//
// gl_rsurf.c
@ -417,6 +429,7 @@ float CL_GetStudioEstimatedFrame( cl_entity_t *ent );
int R_GetEntityRenderMode( cl_entity_t *ent );
void R_DrawStudioModel( cl_entity_t *e );
player_info_t *pfnPlayerInfo( int index );
void R_GatherPlayerLight( void );
//
// gl_alias.c
@ -444,7 +457,7 @@ void EmitWaterPolys( msurface_t *warp, qboolean reverse );
qboolean R_Init( void );
void R_Shutdown( void );
void VID_CheckChanges( void );
int GL_LoadTexture( const char *name, const byte *buf, size_t size, int flags, imgfilter_t *filter );
int GL_LoadTexture( const char *name, const byte *buf, size_t size, int flags );
void GL_FreeImage( const char *name );
qboolean VID_ScreenShot( const char *filename, int shot_type );
qboolean VID_CubemapShot( const char *base, uint size, const float *vieworg, qboolean skyshot );
@ -508,7 +521,6 @@ enum
GL_ARB_DEPTH_FLOAT_EXT,
GL_ARB_SEAMLESS_CUBEMAP,
GL_EXT_GPU_SHADER4, // shaders only
GL_ARB_TEXTURE_RG,
GL_DEPTH_TEXTURE,
GL_DEBUG_OUTPUT,
GL_EXTCOUNT, // must be last
@ -597,17 +609,20 @@ typedef struct
typedef enum
{
SAFE_NO,
SAFE_NOACC,
SAFE_NODEPTH,
SAFE_NOATTRIB,
SAFE_DONTCARE
SAFE_NO = 0,
SAFE_NOMSAA, // skip msaa
SAFE_NOACC, // don't set acceleration flag
SAFE_NOSTENCIL, // don't set stencil bits
SAFE_NOALPHA, // don't set alpha bits
SAFE_NODEPTH, // don't set depth bits
SAFE_NOCOLOR, // don't set color bits
SAFE_DONTCARE // ignore everything, let SDL/EGL decide
} safe_context_t;
typedef struct
{
void* context; // handle to GL rendering context
safe_context_t safe;
int safe;
int desktopBitsPixel;
int desktopWidth;
@ -629,8 +644,10 @@ extern convar_t *gl_extensions;
extern convar_t *gl_check_errors;
extern convar_t *gl_texture_lodbias;
extern convar_t *gl_texture_nearest;
extern convar_t *gl_wgl_msaa_samples;
extern convar_t *gl_lightmap_nearest;
extern convar_t *gl_keeptjunctions;
extern convar_t *gl_emboss_scale;
extern convar_t *gl_round_down;
extern convar_t *gl_detailscale;
extern convar_t *gl_wireframe;
@ -642,10 +659,10 @@ extern convar_t *gl_test; // cvar to testify new effects
extern convar_t *gl_msaa;
extern convar_t *gl_stencilbits;
extern convar_t *r_speeds;
extern convar_t *r_fullbright;
extern convar_t *r_norefresh;
extern convar_t *r_showtree; // build graph of visible hull
extern convar_t *r_lighting_extended;
extern convar_t *r_lighting_modulate;
extern convar_t *r_lighting_ambient;

View file

@ -81,7 +81,6 @@ R_SplitEntityOnNode
static void R_SplitEntityOnNode( mnode_t *node )
{
efrag_t *ef;
mplane_t *splitplane;
mleaf_t *leaf;
int sides;
@ -100,7 +99,7 @@ static void R_SplitEntityOnNode( mnode_t *node )
ef = clgame.free_efrags;
if( !ef )
{
MsgDev( D_ERROR, "too many efrags!\n" );
Con_Printf( S_ERROR "too many efrags!\n" );
return; // no free fragments...
}
@ -120,8 +119,7 @@ static void R_SplitEntityOnNode( mnode_t *node )
}
// NODE_MIXED
splitplane = node->plane;
sides = BOX_ON_PLANE_SIDE( r_emins, r_emaxs, splitplane );
sides = BOX_ON_PLANE_SIDE( r_emins, r_emaxs, node->plane );
if( sides == 3 )
{
@ -142,6 +140,8 @@ R_AddEfrags
*/
void R_AddEfrags( cl_entity_t *ent )
{
matrix3x4 transform;
vec3_t outmins, outmaxs;
int i;
if( !ent->model )
@ -151,10 +151,14 @@ void R_AddEfrags( cl_entity_t *ent )
lastlink = &ent->efrag;
r_pefragtopnode = NULL;
// handle entity rotation for right bbox expanding
Matrix3x4_CreateFromEntity( transform, ent->angles, vec3_origin, 1.0f );
Matrix3x4_TransformAABB( transform, ent->model->mins, ent->model->maxs, outmins, outmaxs );
for( i = 0; i < 3; i++ )
{
r_emins[i] = ent->origin[i] + ent->model->mins[i];
r_emaxs[i] = ent->origin[i] + ent->model->maxs[i];
r_emins[i] = ent->origin[i] + outmins[i];
r_emaxs[i] = ent->origin[i] + outmaxs[i];
}
R_SplitEntityOnNode( cl.worldmodel->nodes );
@ -191,6 +195,7 @@ void R_StoreEfrags( efrag_t **ppefrag, int framecount )
if( CL_AddVisibleEntity( pent, ET_FRAGMENTED ))
{
// mark that we've recorded this entity for this frame
pent->curstate.messagenum = cl.parsecount;
pent->visframe = framecount;
}
}
@ -198,7 +203,6 @@ void R_StoreEfrags( efrag_t **ppefrag, int framecount )
ppefrag = &pefrag->leafnext;
break;
default:
Host_Error( "R_StoreEfrags: bad entity type %d\n", clmodel->type );
break;
}
}

View file

@ -49,7 +49,7 @@ void CL_RunLightStyles( void )
// 'm' is normal light, 'a' is no light, 'z' is double bright
for( i = 0, ls = cl.lightstyles; i < MAX_LIGHTSTYLES; i++, ls++ )
{
if( r_fullbright->value || !cl.worldmodel->lightdata )
if( !cl.worldmodel->lightdata )
{
tr.lightstylevalue[i] = 256 * 256;
continue;
@ -74,7 +74,7 @@ void CL_RunLightStyles( void )
tr.lightstylevalue[i] = ls->map[0] * 22 * scale;
continue;
}
else if( !ls->interp || !cl_lightstyle_lerping->value )
else if( !ls->interp || !CVAR_TO_BOOL( cl_lightstyle_lerping ))
{
tr.lightstylevalue[i] = ls->map[flight%ls->length] * 22 * scale;
continue;
@ -104,7 +104,7 @@ void R_MarkLights( dlight_t *light, int bit, mnode_t *node )
msurface_t *surf;
int i;
if( node->contents < 0 )
if( !node || node->contents < 0 )
return;
dist = PlaneDiff( light->origin, node->plane );
@ -217,6 +217,7 @@ int R_CountSurfaceDlights( msurface_t *surf )
=======================================================================
*/
static vec3_t g_trace_lightspot;
static vec3_t g_trace_lightvec;
static float g_trace_fraction;
/*
@ -230,10 +231,11 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f,
int i, map, side, size;
float ds, dt, s, t;
int sample_size;
color24 *lm, *dm;
mextrasurf_t *info;
msurface_t *surf;
mtexinfo_t *tex;
color24 *lm;
matrix3x4 tbn;
vec3_t mid;
// didn't hit anything
@ -306,6 +308,31 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f,
lm = surf->samples + Q_rint( dt ) * smax + Q_rint( ds );
g_trace_fraction = midf;
size = smax * tmax;
dm = NULL;
if( surf->info->deluxemap )
{
vec3_t faceNormal;
if( FBitSet( surf->flags, SURF_PLANEBACK ))
VectorNegate( surf->plane->normal, faceNormal );
else VectorCopy( surf->plane->normal, faceNormal );
// compute face TBN
#if 1
Vector4Set( tbn[0], surf->info->lmvecs[0][0], surf->info->lmvecs[0][1], surf->info->lmvecs[0][2], 0.0f );
Vector4Set( tbn[1], -surf->info->lmvecs[1][0], -surf->info->lmvecs[1][1], -surf->info->lmvecs[1][2], 0.0f );
Vector4Set( tbn[2], faceNormal[0], faceNormal[1], faceNormal[2], 0.0f );
#else
Vector4Set( tbn[0], surf->info->lmvecs[0][0], -surf->info->lmvecs[1][0], faceNormal[0], 0.0f );
Vector4Set( tbn[1], surf->info->lmvecs[0][1], -surf->info->lmvecs[1][1], faceNormal[1], 0.0f );
Vector4Set( tbn[2], surf->info->lmvecs[0][2], -surf->info->lmvecs[1][2], faceNormal[2], 0.0f );
#endif
VectorNormalize( tbn[0] );
VectorNormalize( tbn[1] );
VectorNormalize( tbn[2] );
dm = surf->info->deluxemap + Q_rint( dt ) * smax + Q_rint( ds );
}
for( map = 0; map < MAXLIGHTMAPS && surf->styles[map] != 255; map++ )
{
@ -324,6 +351,18 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f,
cv->b += LightToTexGamma( lm->b ) * scale;
}
lm += size; // skip to next lightmap
if( dm != NULL )
{
vec3_t srcNormal, lightNormal;
float f = (1.0f / 128.0f);
VectorSet( srcNormal, ((float)dm->r - 128.0f) * f, ((float)dm->g - 128.0f) * f, ((float)dm->b - 128.0f) * f );
Matrix3x4_VectorIRotate( tbn, srcNormal, lightNormal ); // turn to world space
VectorScale( lightNormal, (float)scale * -1.0f, lightNormal ); // turn direction from light
VectorAdd( g_trace_lightvec, lightNormal, g_trace_lightvec );
dm += size; // skip to next deluxmap
}
}
return true;
@ -340,13 +379,14 @@ R_LightVec
check bspmodels to get light from
=================
*/
colorVec R_LightVec( const vec3_t start, const vec3_t end, vec3_t lspot )
colorVec R_LightVecInternal( const vec3_t start, const vec3_t end, vec3_t lspot, vec3_t lvec )
{
float last_fraction;
int i, maxEnts = 1;
colorVec light, cv;
if( lspot ) VectorClear( lspot );
if( lvec ) VectorClear( lvec );
if( cl.worldmodel && cl.worldmodel->lightdata )
{
@ -354,7 +394,7 @@ colorVec R_LightVec( const vec3_t start, const vec3_t end, vec3_t lspot )
last_fraction = 1.0f;
// get light from bmodels too
if( r_lighting_extended->value )
if( CVAR_TO_BOOL( r_lighting_extended ))
maxEnts = clgame.pmove->numphysent;
// check all the bsp-models
@ -383,6 +423,7 @@ colorVec R_LightVec( const vec3_t start, const vec3_t end, vec3_t lspot )
}
VectorClear( g_trace_lightspot );
VectorClear( g_trace_lightvec );
g_trace_fraction = 1.0f;
if( !R_RecursiveLightPoint( pe->model, pnodes, 0.0f, 1.0f, &cv, start_l, end_l ))
@ -391,10 +432,14 @@ colorVec R_LightVec( const vec3_t start, const vec3_t end, vec3_t lspot )
if( g_trace_fraction < last_fraction )
{
if( lspot ) VectorCopy( g_trace_lightspot, lspot );
if( lvec ) VectorNormalize2( g_trace_lightvec, lvec );
light.r = Q_min(( cv.r >> 7 ), 255 );
light.g = Q_min(( cv.g >> 7 ), 255 );
light.b = Q_min(( cv.b >> 7 ), 255 );
last_fraction = g_trace_fraction;
if(( light.r + light.g + light.b ) != 0 )
break; // we get light now
}
}
}
@ -407,6 +452,27 @@ colorVec R_LightVec( const vec3_t start, const vec3_t end, vec3_t lspot )
return light;
}
/*
=================
R_LightVec
check bspmodels to get light from
=================
*/
colorVec R_LightVec( const vec3_t start, const vec3_t end, vec3_t lspot, vec3_t lvec )
{
colorVec light = R_LightVecInternal( start, end, lspot, lvec );
if( CVAR_TO_BOOL( r_lighting_extended ) && lspot != NULL && lvec != NULL )
{
// trying to get light from ceiling (but ignore gradient analyze)
if(( light.r + light.g + light.b ) == 0 )
return R_LightVecInternal( end, start, lspot, lvec );
}
return light;
}
/*
=================
R_LightPoint
@ -420,5 +486,5 @@ colorVec R_LightPoint( const vec3_t p0 )
VectorSet( p1, p0[0], p0[1], p0[2] - 2048.0f );
return R_LightVec( p0, p1, NULL );
return R_LightVec( p0, p1, NULL, NULL );
}

View file

@ -21,11 +21,10 @@ GNU General Public License for more details.
#include "beamdef.h"
#include "particledef.h"
#include "entity_types.h"
#include "platform/platform.h"
#define IsLiquidContents( cnt ) ( cnt == CONTENTS_WATER || cnt == CONTENTS_SLIME || cnt == CONTENTS_LAVA )
msurface_t *r_debug_surface;
const char *r_debug_hitbox;
float gldepthmin, gldepthmax;
ref_instance_t RI;
@ -207,7 +206,7 @@ void R_PushScene( void )
/*
===============
R_PushScene
R_PopScene
===============
*/
void R_PopScene( void )
@ -242,10 +241,10 @@ qboolean R_AddEntity( struct cl_entity_s *clent, int type )
if( !clent || !clent->model )
return false; // if set to invisible, skip
if( clent->curstate.effects & EF_NODRAW )
if( FBitSet( clent->curstate.effects, EF_NODRAW ))
return false; // done
if( clent->curstate.rendermode != kRenderNormal && CL_FxBlend( clent ) <= 0 )
if( !R_ModelOpaque( clent->curstate.rendermode ) && CL_FxBlend( clent ) <= 0 )
return true; // invisible
if( type == ET_FRAGMENTED )
@ -541,7 +540,7 @@ void R_SetupGL( qboolean set_gl_state )
pglMatrixMode( GL_MODELVIEW );
GL_LoadMatrix( RI.worldviewMatrix );
if( RI.params & RP_CLIPPLANE )
if( FBitSet( RI.params, RP_CLIPPLANE ))
{
GLdouble clip[4];
mplane_t *p = &RI.clipPlane;
@ -581,9 +580,9 @@ using to find source waterleaf with
watertexture to grab fog values from it
=============
*/
static gltexture_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 )
{
gltexture_t *tex = NULL;
gl_texture_t *tex = NULL;
// assure the initial node is not null
// we could check it here, but we would rather check it
@ -656,17 +655,25 @@ from underwater leaf (idea: XaeroX)
static void R_CheckFog( void )
{
cl_entity_t *ent;
gltexture_t *tex;
gl_texture_t *tex;
int i, cnt, count;
// quake global fog
if( clgame.movevars.fog_settings != 0 && FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
if( Host_IsQuakeCompatible( ))
{
if( !clgame.movevars.fog_settings )
{
if( pglIsEnabled( GL_FOG ))
pglDisable( GL_FOG );
RI.fogEnabled = false;
return;
}
// quake-style global fog
RI.fogColor[0] = ((clgame.movevars.fog_settings & 0xFF000000) >> 24) / 255.0f;
RI.fogColor[1] = ((clgame.movevars.fog_settings & 0xFF0000) >> 16) / 255.0f;
RI.fogColor[2] = ((clgame.movevars.fog_settings & 0xFF00) >> 8) / 255.0f;
RI.fogDensity = ((clgame.movevars.fog_settings & 0xFF) / 255.0f) * 0.015625f;
RI.fogDensity = ((clgame.movevars.fog_settings & 0xFF) / 255.0f) * 0.01f;
RI.fogStart = RI.fogEnd = 0.0f;
RI.fogColor[3] = 1.0f;
RI.fogCustom = false;
@ -675,15 +682,6 @@ static void R_CheckFog( void )
return;
}
#ifdef HACKS_RELATED_HLMODS
// special condition for Spirit 1.9 that used direct calls of glFog-functions
if(( !RI.fogEnabled && !RI.fogCustom ) && pglIsEnabled( GL_FOG ) && VectorIsNull( RI.fogColor ))
{
// fill the fog color from GL-state machine
pglGetFloatv( GL_FOG_COLOR, RI.fogColor );
RI.fogSkybox = true;
}
#endif
RI.fogEnabled = false;
if( RI.onlyClientDraw || cl.local.waterlevel < 3 || !RI.drawWorld || !RI.viewleaf )
@ -753,6 +751,26 @@ static void R_CheckFog( void )
}
}
/*
=============
R_CheckGLFog
special condition for Spirit 1.9
that used direct calls of glFog-functions
=============
*/
static void R_CheckGLFog( void )
{
#ifdef HACKS_RELATED_HLMODS
if(( !RI.fogEnabled && !RI.fogCustom ) && pglIsEnabled( GL_FOG ) && VectorIsNull( RI.fogColor ))
{
// fill the fog color from GL-state machine
pglGetFloatv( GL_FOG_COLOR, RI.fogColor );
RI.fogSkybox = true;
}
#endif
}
/*
=============
R_DrawFog
@ -764,7 +782,9 @@ void R_DrawFog( void )
if( !RI.fogEnabled ) return;
pglEnable( GL_FOG );
pglFogi( GL_FOG_MODE, GL_EXP );
if( Host_IsQuakeCompatible( ))
pglFogi( GL_FOG_MODE, GL_EXP2 );
else pglFogi( GL_FOG_MODE, GL_EXP );
pglFogf( GL_FOG_DENSITY, RI.fogDensity );
pglFogfv( GL_FOG_COLOR, RI.fogColor );
pglHint( GL_FOG_HINT, GL_NICEST );
@ -940,6 +960,7 @@ void R_RenderScene( void )
R_MarkLeaves();
R_DrawFog ();
R_CheckGLFog();
R_DrawWorld();
R_CheckFog();
@ -977,7 +998,6 @@ qboolean R_DoResetGamma( void )
return false;
case scrshot_plaque:
case scrshot_savegame:
case scrshot_demoshot:
case scrshot_envshot:
case scrshot_skyshot:
case scrshot_mapshot:
@ -1084,8 +1104,13 @@ void R_RenderFrame( const ref_viewpass_t *rvp )
if( gl_finish->value && RI.drawWorld )
pglFinish();
if( glConfig.max_multisamples > 1 )
pglEnable( GL_MULTISAMPLE_ARB );
if( glConfig.max_multisamples > 1 && FBitSet( gl_msaa->flags, FCVAR_CHANGED ))
{
if( CVAR_TO_BOOL( gl_msaa ))
pglEnable( GL_MULTISAMPLE_ARB );
else pglDisable( GL_MULTISAMPLE_ARB );
ClearBits( gl_msaa->flags, FCVAR_CHANGED );
}
// completely override rendering
if( clgame.drawFuncs.GL_RenderFrame != NULL )
@ -1094,6 +1119,7 @@ void R_RenderFrame( const ref_viewpass_t *rvp )
if( clgame.drawFuncs.GL_RenderFrame( rvp ))
{
R_GatherPlayerLight();
tr.realframecount++;
tr.fResetVis = true;
return;
@ -1154,7 +1180,7 @@ void R_DrawCubemapView( const vec3_t origin, const vec3_t angles, int size )
static int GL_RenderGetParm( int parm, int arg )
{
gltexture_t *glt;
gl_texture_t *glt;
switch( parm )
{
@ -1197,6 +1223,8 @@ static int GL_RenderGetParm( int parm, int arg )
return tr.lightmapTextures[arg];
case PARM_SKY_SPHERE:
return FBitSet( world.flags, FWORLD_SKYSPHERE ) && !FBitSet( world.flags, FWORLD_CUSTOM_SKYBOX );
case PARAM_GAMEPAUSED:
return cl.paused;
case PARM_WIDESCREEN:
return glState.wideScreen;
case PARM_FULLSCREEN:
@ -1253,7 +1281,7 @@ static int GL_RenderGetParm( int parm, int arg )
static void R_GetDetailScaleForTexture( int texture, float *xScale, float *yScale )
{
gltexture_t *glt = R_GetTexture( texture );
gl_texture_t *glt = R_GetTexture( texture );
if( xScale ) *xScale = glt->xscale;
if( yScale ) *yScale = glt->yscale;
@ -1261,7 +1289,7 @@ static void R_GetDetailScaleForTexture( int texture, float *xScale, float *yScal
static void R_GetExtraParmsForTexture( int texture, byte *red, byte *green, byte *blue, byte *density )
{
gltexture_t *glt = R_GetTexture( texture );
gl_texture_t *glt = R_GetTexture( texture );
if( red ) *red = glt->fogParams[0];
if( green ) *green = glt->fogParams[1];
@ -1279,16 +1307,13 @@ static void R_EnvShot( const float *vieworg, const char *name, qboolean skyshot,
{
static vec3_t viewPoint;
if( !name )
{
MsgDev( D_ERROR, "R_%sShot: bad name\n", skyshot ? "Sky" : "Env" );
if( !COM_CheckString( name ))
return;
}
if( cls.scrshot_action != scrshot_inactive )
{
if( cls.scrshot_action != scrshot_skyshot && cls.scrshot_action != scrshot_envshot )
MsgDev( D_ERROR, "R_%sShot: subsystem is busy, try later.\n", skyshot ? "Sky" : "Env" );
Con_Printf( S_ERROR "R_%sShot: subsystem is busy, try for next frame.\n", skyshot ? "Sky" : "Env" );
return;
}
@ -1369,16 +1394,6 @@ const byte *GL_TextureData( unsigned int texnum )
return NULL;
}
static int GL_LoadTextureNoFilter( const char *name, const byte *buf, size_t size, int flags )
{
return GL_LoadTexture( name, buf, size, flags, NULL );
}
static int GL_LoadTextureArrayNoFilter( const char **names, int flags )
{
return GL_LoadTextureArray( names, flags, NULL );
}
static const ref_overview_t *GL_GetOverviewParms( void )
{
return &clgame.overView;
@ -1386,7 +1401,7 @@ static const ref_overview_t *GL_GetOverviewParms( void )
static void *R_Mem_Alloc( size_t cb, const char *filename, const int fileline )
{
return _Mem_Alloc( cls.mempool, cb, filename, fileline );
return _Mem_Alloc( cls.mempool, cb, true, filename, fileline );
}
static void R_Mem_Free( void *mem, const char *filename, const int fileline )
@ -1461,22 +1476,22 @@ static render_api_t gRenderAPI =
GL_FindTexture,
GL_TextureName,
GL_TextureData,
GL_LoadTextureNoFilter,
GL_LoadTexture,
GL_CreateTexture,
GL_LoadTextureArrayNoFilter,
GL_LoadTextureArray,
GL_CreateTextureArray,
GL_FreeTexture,
DrawSingleDecal,
R_DecalSetupVerts,
R_EntityRemoveDecals,
(void*)AVI_LoadVideoNoSound,
(void*)AVI_LoadVideo,
(void*)AVI_GetVideoInfo,
(void*)AVI_GetVideoFrameNumber,
(void*)AVI_GetVideoFrame,
R_UploadStretchRaw,
(void*)AVI_FreeVideo,
(void*)AVI_IsActive,
NULL,
S_StreamAviSamples,
NULL,
NULL,
GL_Bind,
@ -1488,7 +1503,7 @@ static render_api_t gRenderAPI =
GL_TextureTarget,
GL_SetTexCoordArrayMode,
GL_GetProcAddress,
NULL,
GL_UpdateTexSize,
NULL,
NULL,
CL_DrawParticlesExternal,
@ -1529,7 +1544,7 @@ qboolean R_InitRenderAPI( void )
{
if( clgame.dllFuncs.pfnGetRenderInterface( CL_RENDER_INTERFACE_VERSION, &gRenderAPI, &clgame.drawFuncs ))
{
MsgDev( D_REPORT, "CL_LoadProgs: ^2initailized extended RenderAPI ^7ver. %i\n", CL_RENDER_INTERFACE_VERSION );
Con_Reportf( "CL_LoadProgs: ^2initailized extended RenderAPI ^7ver. %i\n", CL_RENDER_INTERFACE_VERSION );
return true;
}

View file

@ -27,12 +27,8 @@ float V_CalcFov( float *fov_x, float width, float height )
{
float x, half_fov_y;
if( *fov_x < 1.0f || *fov_x > 170.0f )
{
if( !cls.demoplayback )
MsgDev( D_ERROR, "V_CalcFov: bad fov %g!\n", *fov_x );
*fov_x = 90.0f;
}
if( *fov_x < 1.0f || *fov_x > 179.0f )
*fov_x = 90.0f; // default value
x = width / tan( DEG2RAD( *fov_x ) * 0.5f );
half_fov_y = atan( height / x );

View file

@ -19,207 +19,7 @@ GNU General Public License for more details.
#include "mod_local.h"
#include "shake.h"
typedef struct
{
const char *texname;
const char *detail;
const char material;
int lMin;
int lMax;
} dmaterial_t;
typedef struct
{
char texname[64]; // shortname
imgfilter_t filter;
} dfilter_t;
dfilter_t *tex_filters[MAX_TEXTURES];
int num_texfilters;
// default rules for apply detail textures.
// maybe move this to external script?
static const dmaterial_t detail_table[] =
{
{ "crt", "dt_conc", 'C', 0, 0 }, // concrete
{ "rock", "dt_rock1", 'C', 0, 0 },
{ "conc", "dt_conc", 'C', 0, 0 },
{ "brick", "dt_brick", 'C', 0, 0 },
{ "wall", "dt_brick", 'C', 0, 0 },
{ "city", "dt_conc", 'C', 0, 0 },
{ "crete", "dt_conc", 'C', 0, 0 },
{ "generic", "dt_brick", 'C', 0, 0 },
{ "floor", "dt_conc", 'C', 0, 0 },
{ "metal", "dt_metal%i", 'M', 1, 2 }, // metal
{ "mtl", "dt_metal%i", 'M', 1, 2 },
{ "pipe", "dt_metal%i", 'M', 1, 2 },
{ "elev", "dt_metal%i", 'M', 1, 2 },
{ "sign", "dt_metal%i", 'M', 1, 2 },
{ "barrel", "dt_metal%i", 'M', 1, 2 },
{ "bath", "dt_ssteel1", 'M', 1, 2 },
{ "tech", "dt_ssteel1", 'M', 1, 2 },
{ "refbridge", "dt_metal%i", 'M', 1, 2 },
{ "panel", "dt_ssteel1", 'M', 0, 0 },
{ "brass", "dt_ssteel1", 'M', 0, 0 },
{ "rune", "dt_metal%i", 'M', 1, 2 },
{ "car", "dt_metal%i", 'M', 1, 2 },
{ "circuit", "dt_metal%i", 'M', 1, 2 },
{ "steel", "dt_ssteel1", 'M', 0, 0 },
{ "dirt", "dt_ground%i", 'D', 1, 5 }, // dirt
{ "drt", "dt_ground%i", 'D', 1, 5 },
{ "out", "dt_ground%i", 'D', 1, 5 },
{ "grass", "dt_grass1", 'D', 0, 0 },
{ "mud", "dt_carpet1", 'D', 0, 0 },
{ "vent", "dt_ssteel1", 'V', 1, 4 }, // vent
{ "duct", "dt_ssteel1", 'V', 1, 4 },
{ "tile", "dt_smooth%i", 'T', 1, 2 },
{ "labflr", "dt_smooth%i", 'T', 1, 2 },
{ "bath", "dt_smooth%i", 'T', 1, 2 },
{ "grate", "dt_stone%i", 'G', 1, 4 }, // vent
{ "stone", "dt_stone%i", 'G', 1, 4 },
{ "grt", "dt_stone%i", 'G', 1, 4 },
{ "wiz", "dt_wood%i", 'W', 1, 3 },
{ "wood", "dt_wood%i", 'W', 1, 3 },
{ "wizwood", "dt_wood%i", 'W', 1, 3 },
{ "wd", "dt_wood%i", 'W', 1, 3 },
{ "table", "dt_wood%i", 'W', 1, 3 },
{ "board", "dt_wood%i", 'W', 1, 3 },
{ "chair", "dt_wood%i", 'W', 1, 3 },
{ "brd", "dt_wood%i", 'W', 1, 3 },
{ "carp", "dt_carpet1", 'W', 1, 3 },
{ "book", "dt_wood%i", 'W', 1, 3 },
{ "box", "dt_wood%i", 'W', 1, 3 },
{ "cab", "dt_wood%i", 'W', 1, 3 },
{ "couch", "dt_wood%i", 'W', 1, 3 },
{ "crate", "dt_wood%i", 'W', 1, 3 },
{ "poster", "dt_plaster%i", 'W', 1, 2 },
{ "sheet", "dt_plaster%i", 'W', 1, 2 },
{ "stucco", "dt_plaster%i", 'W', 1, 2 },
{ "comp", "dt_smooth1", 'P', 0, 0 },
{ "cmp", "dt_smooth1", 'P', 0, 0 },
{ "elec", "dt_smooth1", 'P', 0, 0 },
{ "vend", "dt_smooth1", 'P', 0, 0 },
{ "monitor", "dt_smooth1", 'P', 0, 0 },
{ "phone", "dt_smooth1", 'P', 0, 0 },
{ "glass", "dt_ssteel1", 'Y', 0, 0 },
{ "window", "dt_ssteel1", 'Y', 0, 0 },
{ "flesh", "dt_rough1", 'F', 0, 0 },
{ "meat", "dt_rough1", 'F', 0, 0 },
{ "fls", "dt_rough1", 'F', 0, 0 },
{ "ground", "dt_ground%i", 'D', 1, 5 },
{ "gnd", "dt_ground%i", 'D', 1, 5 },
{ "snow", "dt_snow%i", 'O', 1, 2 }, // snow
{ "wswamp", "dt_smooth1", 'W', 0, 0 },
{ NULL, NULL, 0, 0, 0 }
};
static const char *R_DetailTextureForName( const char *name )
{
const dmaterial_t *table;
if( !name || !*name ) return NULL;
if( !Q_strnicmp( name, "sky", 3 ))
return NULL; // never details for sky
// never apply details for liquids
if( !Q_strnicmp( name + 1, "!lava", 5 ))
return NULL;
if( !Q_strnicmp( name + 1, "!slime", 6 ))
return NULL;
if( !Q_strnicmp( name, "!cur_90", 7 ))
return NULL;
if( !Q_strnicmp( name, "!cur_0", 6 ))
return NULL;
if( !Q_strnicmp( name, "!cur_270", 8 ))
return NULL;
if( !Q_strnicmp( name, "!cur_180", 8 ))
return NULL;
if( !Q_strnicmp( name, "!cur_up", 7 ))
return NULL;
if( !Q_strnicmp( name, "!cur_dwn", 8 ))
return NULL;
if( name[0] == '!' )
return NULL;
// never apply details to the special textures
if( !Q_strnicmp( name, "origin", 6 ))
return NULL;
if( !Q_strnicmp( name, "clip", 4 ))
return NULL;
if( !Q_strnicmp( name, "hint", 4 ))
return NULL;
if( !Q_strnicmp( name, "skip", 4 ))
return NULL;
if( !Q_strnicmp( name, "translucent", 11 ))
return NULL;
if( !Q_strnicmp( name, "3dsky", 5 )) // xash-mod support :-)
return NULL;
if( !Q_strnicmp( name, "scroll", 6 ))
return NULL;
if( name[0] == '@' )
return NULL;
// last check ...
if( !Q_strnicmp( name, "null", 4 ))
return NULL;
for( table = detail_table; table && table->texname; table++ )
{
if( Q_stristr( name, table->texname ))
{
if(( table->lMin + table->lMax ) > 0 )
return va( table->detail, COM_RandomLong( table->lMin, table->lMax ));
return table->detail;
}
}
return NULL;
}
void R_CreateDetailTexturesList( const char *filename )
{
file_t *detail_txt = NULL;
float xScale, yScale;
const char *detail_name;
texture_t *tex;
rgbdata_t *pic;
int i;
for( i = 0; i < cl.worldmodel->numtextures; i++ )
{
tex = cl.worldmodel->textures[i];
detail_name = R_DetailTextureForName( tex->name );
if( !detail_name ) continue;
// detailtexture detected
if( detail_name )
{
if( !detail_txt ) detail_txt = FS_Open( filename, "w", false );
if( !detail_txt )
{
MsgDev( D_ERROR, "Can't write %s\n", filename );
break;
}
pic = FS_LoadImage( va( "gfx/detail/%s", detail_name ), NULL, 0 );
if( pic )
{
xScale = (pic->width / (float)tex->width) * gl_detailscale->value;
yScale = (pic->height / (float)tex->height) * gl_detailscale->value;
FS_FreeImage( pic );
}
else xScale = yScale = 10.0f;
// store detailtexture description
FS_Printf( detail_txt, "%s detail/%s %.2f %.2f\n", tex->name, detail_name, xScale, yScale );
}
}
if( detail_txt ) FS_Close( detail_txt );
}
void R_ParseDetailTextures( const char *filename )
static void R_ParseDetailTextures( const char *filename )
{
char *afile, *pfile;
string token, texname;
@ -229,12 +29,6 @@ void R_ParseDetailTextures( const char *filename )
texture_t *tex;
int i;
if( r_detailtextures->value >= 2 && !FS_FileExists( filename, false ))
{
// use built-in generator for detail textures
R_CreateDetailTexturesList( filename );
}
afile = FS_LoadFile( filename, NULL, false );
if( !afile ) return;
@ -292,12 +86,12 @@ void R_ParseDetailTextures( const char *filename )
if( Q_stricmp( tex->name, texname ))
continue;
tex->dt_texturenum = GL_LoadTexture( detail_path, NULL, 0, TF_FORCE_COLOR, NULL );
tex->dt_texturenum = GL_LoadTexture( detail_path, NULL, 0, TF_FORCE_COLOR );
// texture is loaded
if( tex->dt_texturenum )
{
gltexture_t *glt;
gl_texture_t *glt;
glt = R_GetTexture( tex->gl_texturenum );
glt->xscale = xScale;
@ -310,116 +104,6 @@ void R_ParseDetailTextures( const char *filename )
Mem_Free( afile );
}
void R_ParseTexFilters( const char *filename )
{
char *afile, *pfile;
string token, texname;
dfilter_t *tf;
int i;
afile = FS_LoadFile( filename, NULL, false );
if( !afile ) return;
pfile = afile;
// format: 'texturename' 'filtername' 'factor' 'bias' 'blendmode' 'grayscale'
while(( pfile = COM_ParseFile( pfile, token )) != NULL )
{
imgfilter_t filter;
memset( &filter, 0, sizeof( filter ));
Q_strncpy( texname, token, sizeof( texname ));
// parse filter
pfile = COM_ParseFile( pfile, token );
if( !Q_stricmp( token, "blur" ))
filter.filter = BLUR_FILTER;
else if( !Q_stricmp( token, "blur2" ))
filter.filter = BLUR_FILTER2;
else if( !Q_stricmp( token, "edge" ))
filter.filter = EDGE_FILTER;
else if( !Q_stricmp( token, "emboss" ))
filter.filter = EMBOSS_FILTER;
// reading factor
pfile = COM_ParseFile( pfile, token );
filter.factor = Q_atof( token );
// reading bias
pfile = COM_ParseFile( pfile, token );
filter.bias = Q_atof( token );
// reading blendFunc
pfile = COM_ParseFile( pfile, token );
if( !Q_stricmp( token, "modulate" ) || !Q_stricmp( token, "GL_MODULATE" ))
filter.blendFunc = GL_MODULATE;
else if( !Q_stricmp( token, "replace" ) || !Q_stricmp( token, "GL_REPLACE" ))
filter.blendFunc = GL_REPLACE;
else if( !Q_stricmp( token, "add" ) || !Q_stricmp( token, "GL_ADD" ))
filter.blendFunc = GL_ADD;
else if( !Q_stricmp( token, "decal" ) || !Q_stricmp( token, "GL_DECAL" ))
filter.blendFunc = GL_DECAL;
else if( !Q_stricmp( token, "blend" ) || !Q_stricmp( token, "GL_BLEND" ))
filter.blendFunc = GL_BLEND;
else if( !Q_stricmp( token, "add_signed" ) || !Q_stricmp( token, "GL_ADD_SIGNED" ))
filter.blendFunc = GL_ADD_SIGNED;
else MsgDev( D_WARN, "unknown blendFunc '%s' specified for texture '%s'\n", texname, token );
// reading flags
pfile = COM_ParseFile( pfile, token );
filter.flags = Q_atoi( token );
// make sure what factor is not zeroed
if( filter.factor == 0.0f )
{
MsgDev( D_WARN, "texfilter for texture %s has factor 0! Ignored\n", texname );
continue;
}
// check if already existed
for( i = 0; i < num_texfilters; i++ )
{
tf = tex_filters[i];
if( !Q_stricmp( tf->texname, texname ))
{
MsgDev( D_WARN, "texture %s has specified multiple filters! Ignored\n", texname );
break;
}
}
if( i != num_texfilters )
continue; // already specified
// allocate new texfilter
tf = Z_Malloc( sizeof( dfilter_t ));
tex_filters[num_texfilters++] = tf;
Q_strncpy( tf->texname, texname, sizeof( tf->texname ));
tf->filter = filter;
}
MsgDev( D_INFO, "%i texture filters parsed\n", num_texfilters );
Mem_Free( afile );
}
imgfilter_t *R_FindTexFilter( const char *texname )
{
dfilter_t *tf;
int i;
for( i = 0; i < num_texfilters; i++ )
{
tf = tex_filters[i];
if( !Q_stricmp( tf->texname, texname ))
return &tf->filter;
}
return NULL;
}
/*
=======================
R_ClearStaticEntities
@ -451,7 +135,7 @@ void R_NewMap( void )
R_ClearDecals(); // clear all level decals
// upload detailtextures
if( r_detailtextures->value )
if( CVAR_TO_BOOL( r_detailtextures ))
{
string mapname, filepath;
@ -462,12 +146,15 @@ void R_NewMap( void )
R_ParseDetailTextures( filepath );
}
if( v_dark->value )
if( CVAR_TO_BOOL( v_dark ))
{
screenfade_t *sf = &clgame.fade;
float fadetime = 5.0f;
client_textmessage_t *title;
title = CL_TextMessageGet( "GAMETITLE" );
if( Host_IsQuakeCompatible( ))
fadetime = 1.0f;
if( title )
{
@ -475,7 +162,7 @@ void R_NewMap( void )
sf->fadeEnd = title->holdtime + title->fadeout;
sf->fadeReset = title->fadeout;
}
else sf->fadeEnd = sf->fadeReset = 5.0f;
else sf->fadeEnd = sf->fadeReset = fadetime;
sf->fadeFlags = FFADE_IN;
sf->fader = sf->fadeg = sf->fadeb = 0;
@ -492,6 +179,7 @@ void R_NewMap( void )
cl.worldmodel->leafs[i+1].efrags = NULL;
tr.skytexturenum = -1;
tr.max_recursion = 0;
pglDisable( GL_FOG );
// clearing texture chains
@ -502,7 +190,7 @@ void R_NewMap( void )
tx = cl.worldmodel->textures[i];
if( !Q_strncmp( tx->name, "sky", 3 ) && tx->width == 256 && tx->height == 128 )
if( !Q_strncmp( tx->name, "sky", 3 ) && tx->width == ( tx->height * 2 ))
tr.skytexturenum = i;
tx->texturechain = NULL;

View file

@ -128,7 +128,7 @@ void CL_InitParticles( void )
{
int i;
cl_particles = Mem_Alloc( cls.mempool, sizeof( particle_t ) * GI->max_particles );
cl_particles = Mem_Calloc( cls.mempool, sizeof( particle_t ) * GI->max_particles );
CL_ClearParticles ();
// this is used for EF_BRIGHTFIELD
@ -225,7 +225,7 @@ particle_t *R_AllocParticle( void (*callback)( particle_t*, float ))
if( cl_lasttimewarn < host.realtime )
{
// don't spam about overflow
MsgDev( D_ERROR, "Overflow %d particles\n", GI->max_particles );
Con_DPrintf( S_ERROR "Overflow %d particles\n", GI->max_particles );
cl_lasttimewarn = host.realtime + 1.0f;
}
return NULL;
@ -276,7 +276,7 @@ particle_t *R_AllocTracer( const vec3_t org, const vec3_t vel, float life )
if( cl_lasttimewarn < host.realtime )
{
// don't spam about overflow
MsgDev( D_ERROR, "Overflow %d tracers\n", GI->max_particles );
Con_DPrintf( S_ERROR "Overflow %d tracers\n", GI->max_particles );
cl_lasttimewarn = host.realtime + 1.0f;
}
return NULL;
@ -1501,14 +1501,11 @@ void R_UserTracerParticle( float *org, float *vel, float life, int colorIndex, f
particle_t *p;
if( colorIndex < 0 )
{
MsgDev( D_ERROR, "UserTracer with color < 0\n" );
return;
}
if( colorIndex > ARRAYSIZE( gTracerColors ))
{
MsgDev( D_ERROR, "UserTracer with color > %d\n", ARRAYSIZE( gTracerColors ));
Con_Printf( S_ERROR "UserTracer with color > %d\n", ARRAYSIZE( gTracerColors ));
return;
}

View file

@ -151,7 +151,7 @@ static void SubdividePolygon_r( msurface_t *warpface, int numverts, float *verts
ClearBits( warpface->flags, SURF_DRAWTURB_QUADS );
// add a point in the center to help keep warp valid
poly = Mem_Alloc( loadmodel->mempool, sizeof( glpoly_t ) + (numverts - 4) * VERTEXSIZE * sizeof( float ));
poly = Mem_Calloc( loadmodel->mempool, sizeof( glpoly_t ) + (numverts - 4) * VERTEXSIZE * sizeof( float ));
poly->next = warpface->polys;
poly->flags = warpface->flags;
warpface->polys = poly;
@ -208,7 +208,7 @@ void GL_SetupFogColorForSurfaces( void )
return;
if( RI.currententity && RI.currententity->curstate.rendermode == kRenderTransTexture )
{
{
pglFogfv( GL_FOG_COLOR, RI.fogColor );
return;
}
@ -273,20 +273,16 @@ void GL_BuildPolygonFromSurface( model_t *mod, msurface_t *fa )
medge_t *pedges, *r_pedge;
mextrasurf_t *info = fa->info;
float sample_size;
int vertpage;
texture_t *tex;
gltexture_t *glt;
gl_texture_t *glt;
float *vec;
float s, t;
glpoly_t *poly;
// already created
if( !mod || fa->polys ) return;
if( !fa->texinfo || !fa->texinfo->texture )
if( !mod || !fa->texinfo || !fa->texinfo->texture )
return; // bad polygon ?
if( fa->flags & SURF_CONVEYOR && fa->texinfo->texture->gl_texturenum != 0 )
if( FBitSet( fa->flags, SURF_CONVEYOR ) && fa->texinfo->texture->gl_texturenum != 0 )
{
glt = R_GetTexture( fa->texinfo->texture->gl_texturenum );
tex = fa->texinfo->texture;
@ -302,10 +298,13 @@ void GL_BuildPolygonFromSurface( model_t *mod, msurface_t *fa )
// reconstruct the polygon
pedges = mod->edges;
lnumverts = fa->numedges;
vertpage = 0;
// draw texture
poly = Mem_Alloc( mod->mempool, sizeof( glpoly_t ) + ( lnumverts - 4 ) * VERTEXSIZE * sizeof( float ));
// detach if already created, reconstruct again
poly = fa->polys;
fa->polys = NULL;
// quake simple models (healthkits etc) need to be reconstructed their polys because LM coords has changed after the map change
poly = Mem_Realloc( mod->mempool, poly, sizeof( glpoly_t ) + ( lnumverts - 4 ) * VERTEXSIZE * sizeof( float ));
poly->next = fa->polys;
poly->flags = fa->flags;
fa->polys = poly;
@ -340,13 +339,13 @@ void GL_BuildPolygonFromSurface( model_t *mod, msurface_t *fa )
s = DotProduct( vec, info->lmvecs[0] ) + info->lmvecs[0][3];
s -= info->lightmapmins[0];
s += fa->light_s * sample_size;
s += sample_size / 2.0;
s += sample_size * 0.5f;
s /= BLOCK_SIZE * sample_size; //fa->texinfo->texture->width;
t = DotProduct( vec, info->lmvecs[1] ) + info->lmvecs[1][3];
t -= info->lightmapmins[1];
t += fa->light_t * sample_size;
t += sample_size / 2.0;
t += sample_size * 0.5f;
t /= BLOCK_SIZE * sample_size; //fa->texinfo->texture->height;
poly->verts[i][5] = s;
@ -354,7 +353,7 @@ void GL_BuildPolygonFromSurface( model_t *mod, msurface_t *fa )
}
// remove co-linear points - Ed
if( !gl_keeptjunctions->value && !( fa->flags & SURF_UNDERWATER ))
if( !CVAR_TO_BOOL( gl_keeptjunctions ) && !FBitSet( fa->flags, SURF_UNDERWATER ))
{
for( i = 0; i < lnumverts; i++ )
{
@ -438,17 +437,8 @@ texture_t *R_TextureAnimation( msurface_t *s )
{
base = base->anim_next;
if( !base )
{
MsgDev( D_ERROR, "R_TextureAnimation: broken loop\n" );
if( !base || ++count > MOD_FRAMES )
return s->texinfo->texture;
}
if( ++count > MOD_FRAMES )
{
MsgDev( D_ERROR, "R_TextureAnimation: infinite loop\n" );
return s->texinfo->texture;
}
}
return base;
@ -644,7 +634,7 @@ static void LM_UploadBlock( qboolean dynamic )
r_lightmap.size = r_lightmap.width * r_lightmap.height * 4;
r_lightmap.flags = IMAGE_HAS_COLOR;
r_lightmap.buffer = gl_lms.lightmap_buffer;
tr.lightmapTextures[i] = GL_LoadTextureInternal( lmName, &r_lightmap, TF_FONT|TF_ATLAS_PAGE, false );
tr.lightmapTextures[i] = GL_LoadTextureInternal( lmName, &r_lightmap, TF_FONT|TF_ATLAS_PAGE );
if( ++gl_lms.current_lightmap_texture == MAX_LIGHTMAPS )
Host_Error( "AllocBlock: full\n" );
@ -702,9 +692,9 @@ static void R_BuildLightMap( msurface_t *surf, byte *dest, int stride, qboolean
{
for( s = 0; s < smax; s++ )
{
dest[0] = min((bl[0] >> 7), 255 );
dest[1] = min((bl[1] >> 7), 255 );
dest[2] = min((bl[2] >> 7), 255 );
dest[0] = Q_min((bl[0] >> 7), 255 );
dest[1] = Q_min((bl[1] >> 7), 255 );
dest[2] = Q_min((bl[2] >> 7), 255 );
dest[3] = 255;
bl += 3;
@ -733,12 +723,20 @@ void DrawGLPoly( glpoly_t *p, float xScale, float yScale )
if( p->flags & SURF_CONVEYOR )
{
gltexture_t *texture;
float flConveyorSpeed;
float flConveyorSpeed = 0.0f;
float flRate, flAngle;
gl_texture_t *texture;
flConveyorSpeed = (e->curstate.rendercolor.g<<8|e->curstate.rendercolor.b) / 16.0f;
if( e->curstate.rendercolor.r ) flConveyorSpeed = -flConveyorSpeed;
if( Host_IsQuakeCompatible() && RI.currententity == clgame.entities )
{
// same as doom speed
flConveyorSpeed = -35.0f;
}
else
{
flConveyorSpeed = (e->curstate.rendercolor.g<<8|e->curstate.rendercolor.b) / 16.0f;
if( e->curstate.rendercolor.r ) flConveyorSpeed = -flConveyorSpeed;
}
texture = R_GetTexture( glState.currentTextures[glState.activeTMU] );
flRate = abs( flConveyorSpeed ) / (float)texture->srcWidth;
@ -823,7 +821,7 @@ void R_BlendLightmaps( void )
msurface_t *surf, *newsurf = NULL;
int i;
if( r_fullbright->value || !cl.worldmodel->lightdata )
if( CVAR_TO_BOOL( r_fullbright ) || !cl.worldmodel->lightdata )
return;
if( RI.currententity )
@ -844,7 +842,7 @@ void R_BlendLightmaps( void )
GL_SetupFogColorForSurfaces ();
if( !r_lightmap->value )
if( !CVAR_TO_BOOL( r_lightmap ))
pglEnable( GL_BLEND );
else pglDisable( GL_BLEND );
@ -871,7 +869,7 @@ void R_BlendLightmaps( void )
}
// render dynamic lightmaps
if( r_dynamic->value )
if( CVAR_TO_BOOL( r_dynamic ))
{
LM_InitBlock();
@ -1004,7 +1002,7 @@ R_RenderDetails
*/
void R_RenderDetails( void )
{
gltexture_t *glt;
gl_texture_t *glt;
mextrasurf_t *es, *p;
msurface_t *fa;
int i;
@ -1081,7 +1079,7 @@ void R_RenderBrushPoly( msurface_t *fa, int cull_type )
draw_fullbrights = true;
}
if( r_detailtextures->value )
if( CVAR_TO_BOOL( r_detailtextures ))
{
if( pglIsEnabled( GL_FOG ))
{
@ -1124,7 +1122,7 @@ void R_RenderBrushPoly( msurface_t *fa, int cull_type )
DrawSurfaceDecals( fa, true, (cull_type == CULL_BACKSIDE));
}
if( fa->flags & SURF_DRAWTILED )
if( FBitSet( fa->flags, SURF_DRAWTILED ))
return; // no lightmaps anyway
// check for lightmap modification
@ -1231,7 +1229,7 @@ void R_DrawTextureChains( void )
if(( s->flags & SURF_DRAWTURB ) && clgame.movevars.wateralpha < 1.0f )
continue; // draw translucent water later
if( FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ) && FBitSet( s->flags, SURF_TRANSPARENT ))
if( Host_IsQuakeCompatible() && FBitSet( s->flags, SURF_TRANSPARENT ))
{
draw_alpha_surfaces = true;
continue; // draw transparent surfaces later
@ -1294,7 +1292,7 @@ void R_DrawAlphaTextureChains( void )
GL_ResetFogColor();
R_BlendLightmaps();
RI.currententity->curstate.rendermode = kRenderNormal; // restore world rendermode
pglAlphaFunc( GL_GREATER, 0.0f );
pglAlphaFunc( GL_GREATER, DEFAULT_ALPHATEST );
}
/*
@ -1411,7 +1409,7 @@ void R_SetRenderMode( cl_entity_t *e )
case kRenderTransAlpha:
pglEnable( GL_ALPHA_TEST );
pglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
if( FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
if( Host_IsQuakeCompatible( ))
{
pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
pglColor4f( 1.0f, 1.0f, 1.0f, tr.blend );
@ -1481,7 +1479,7 @@ void R_DrawBrushModel( cl_entity_t *e )
if( rotated ) R_RotateForEntity( e );
else R_TranslateForEntity( e );
if( FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ) && FBitSet( clmodel->flags, MODEL_TRANSPARENT ))
if( Host_IsQuakeCompatible() && FBitSet( clmodel->flags, MODEL_TRANSPARENT ))
e->curstate.rendermode = kRenderTransAlpha;
e->visframe = tr.realframecount; // visible
@ -1514,7 +1512,7 @@ void R_DrawBrushModel( cl_entity_t *e )
for( i = 0; i < clmodel->nummodelsurfaces; i++, psurf++ )
{
if( FBitSet( psurf->flags, SURF_DRAWTURB ) && !FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
if( FBitSet( psurf->flags, SURF_DRAWTURB ) && !Host_IsQuakeCompatible( ))
{
if( psurf->plane->type != PLANE_Z && !FBitSet( e->curstate.effects, EF_WATERSIDES ))
continue;
@ -1542,7 +1540,7 @@ void R_DrawBrushModel( cl_entity_t *e )
}
// sort faces if needs
if( !FBitSet( clmodel->flags, MODEL_LIQUID ) && e->curstate.rendermode == kRenderTransTexture && !gl_nosort->value )
if( !FBitSet( clmodel->flags, MODEL_LIQUID ) && e->curstate.rendermode == kRenderTransTexture && !CVAR_TO_BOOL( gl_nosort ))
qsort( world.draw_surfaces, num_sorted, sizeof( sortedface_t ), R_SurfaceCompare );
// draw sorted translucent surfaces
@ -1564,9 +1562,10 @@ void R_DrawBrushModel( cl_entity_t *e )
e->curstate.rendermode = old_rendermode;
pglDisable( GL_ALPHA_TEST );
pglAlphaFunc( GL_GREATER, 0.0f );
pglAlphaFunc( GL_GREATER, DEFAULT_ALPHATEST );
pglDisable( GL_BLEND );
pglDepthMask( GL_TRUE );
R_DrawModelHull(); // draw before restore
R_LoadIdentity(); // restore worldmatrix
}
@ -1589,14 +1588,14 @@ void R_RecursiveWorldNode( mnode_t *node, uint clipflags )
mleaf_t *pleaf;
int c, side;
float dot;
loc0:
if( node->contents == CONTENTS_SOLID )
return; // hit a solid leaf
if( node->visframe != tr.visframecount )
return;
if( clipflags && !r_nocull->value )
if( clipflags && !CVAR_TO_BOOL( r_nocull ))
{
for( i = 0; i < 6; i++ )
{
@ -1665,7 +1664,8 @@ void R_RecursiveWorldNode( mnode_t *node, uint clipflags )
}
// recurse down the back side
R_RecursiveWorldNode( node->children[!side], clipflags );
node = node->children[!side];
goto loc0;
}
/*
@ -1862,6 +1862,8 @@ R_DrawWorld
*/
void R_DrawWorld( void )
{
double start, end;
// paranoia issues: when gl_renderer is "0" we need have something valid for currententity
// to prevent crashing until HeadShield drawing.
RI.currententity = clgame.entities;
@ -1882,10 +1884,15 @@ void R_DrawWorld( void )
R_ClearSkyBox ();
start = Sys_DoubleTime();
if( RI.drawOrtho )
R_DrawWorldTopView( cl.worldmodel->nodes, RI.frustum.clipFlags );
else R_RecursiveWorldNode( cl.worldmodel->nodes, RI.frustum.clipFlags );
end = Sys_DoubleTime();
r_stats.t_world_node = end - start;
start = Sys_DoubleTime();
R_DrawTextureChains();
if( !CL_IsDevOverviewMode( ))
@ -1900,10 +1907,15 @@ void R_DrawWorld( void )
R_DrawSkyBox();
}
end = Sys_DoubleTime();
r_stats.t_world_draw = end - start;
tr.num_draw_decals = 0;
skychain = NULL;
R_DrawTriangleOutlines ();
R_DrawWorldHull();
}
/*
@ -1996,8 +2008,10 @@ void GL_CreateSurfaceLightmap( msurface_t *surf )
mextrasurf_t *info = surf->info;
byte *base;
if( !cl.worldmodel->lightdata ) return;
if( surf->flags & SURF_DRAWTILED )
if( !loadmodel->lightdata )
return;
if( FBitSet( surf->flags, SURF_DRAWTILED ))
return;
sample_size = Mod_SampleSizeForFace( surf );
@ -2163,9 +2177,6 @@ void GL_BuildLightmaps( void )
// now gamma and brightness are valid
ClearBits( vid_brightness->flags, FCVAR_CHANGED );
ClearBits( vid_gamma->flags, FCVAR_CHANGED );
if( !gl_keeptjunctions->value )
MsgDev( D_INFO, "Eliminate %i vertexes\n", nColinElim );
}
void GL_InitRandomTable( void )

View file

@ -69,16 +69,16 @@ static dframetype_t *R_SpriteLoadFrame( model_t *mod, void *pin, mspriteframe_t
if( FBitSet( mod->flags, MODEL_CLIENT )) // it's a HUD sprite
{
Q_snprintf( texname, sizeof( texname ), "#HUD/%s(%s:%i%i).spr", sprite_name, group_suffix, num / 10, num % 10 );
gl_texturenum = GL_LoadTexture( texname, pin, pinframe->width * pinframe->height * bytes, r_texFlags, NULL );
gl_texturenum = GL_LoadTexture( texname, pin, pinframe->width * pinframe->height * bytes, r_texFlags );
}
else
{
Q_snprintf( texname, sizeof( texname ), "#%s(%s:%i%i).spr", sprite_name, group_suffix, num / 10, num % 10 );
gl_texturenum = GL_LoadTexture( texname, pin, pinframe->width * pinframe->height * bytes, r_texFlags, NULL );
gl_texturenum = GL_LoadTexture( texname, pin, pinframe->width * pinframe->height * bytes, r_texFlags );
}
// setup frame description
pspriteframe = Mem_Alloc( mod->mempool, sizeof( mspriteframe_t ));
pspriteframe = Mem_Malloc( mod->mempool, sizeof( mspriteframe_t ));
pspriteframe->width = pinframe->width;
pspriteframe->height = pinframe->height;
pspriteframe->up = pinframe->origin[1];
@ -111,12 +111,12 @@ static dframetype_t *R_SpriteLoadGroup( model_t *mod, void *pin, mspriteframe_t
numframes = pingroup->numframes;
groupsize = sizeof( mspritegroup_t ) + (numframes - 1) * sizeof( pspritegroup->frames[0] );
pspritegroup = Mem_Alloc( mod->mempool, groupsize );
pspritegroup = Mem_Calloc( mod->mempool, groupsize );
pspritegroup->numframes = numframes;
*ppframe = (mspriteframe_t *)pspritegroup;
pin_intervals = (dspriteinterval_t *)(pingroup + 1);
poutintervals = Mem_Alloc( mod->mempool, numframes * sizeof( float ));
poutintervals = Mem_Calloc( mod->mempool, numframes * sizeof( float ));
pspritegroup->intervals = poutintervals;
for( i = 0; i < numframes; i++ )
@ -162,13 +162,13 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
if( pin->ident != IDSPRITEHEADER )
{
MsgDev( D_ERROR, "%s has wrong id (%x should be %x)\n", mod->name, pin->ident, IDSPRITEHEADER );
Con_DPrintf( S_ERROR "%s has wrong id (%x should be %x)\n", mod->name, pin->ident, IDSPRITEHEADER );
return;
}
if( i != SPRITE_VERSION_Q1 && i != SPRITE_VERSION_HL && i != SPRITE_VERSION_32 )
{
MsgDev( D_ERROR, "%s has wrong version number (%i should be %i or %i)\n", mod->name, i, SPRITE_VERSION_Q1, SPRITE_VERSION_HL );
Con_DPrintf( S_ERROR "%s has wrong version number (%i should be %i or %i)\n", mod->name, i, SPRITE_VERSION_Q1, SPRITE_VERSION_HL );
return;
}
@ -179,7 +179,7 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
{
pinq1 = (dsprite_q1_t *)buffer;
size = sizeof( msprite_t ) + ( pinq1->numframes - 1 ) * sizeof( psprite->frames );
psprite = Mem_Alloc( mod->mempool, size );
psprite = Mem_Calloc( mod->mempool, size );
mod->cache.data = psprite; // make link to extradata
psprite->type = pinq1->type;
@ -189,6 +189,11 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
psprite->radius = pinq1->boundingradius;
psprite->synctype = pinq1->synctype;
// LordHavoc: hack to allow sprites to be non-fullbright
for( i = 0; i < MAX_QPATH && mod->name[i]; i++ )
if( mod->name[i] == '!' )
psprite->texFormat = SPR_ALPHTEST;
mod->mins[0] = mod->mins[1] = -pinq1->bounds[0] * 0.5f;
mod->maxs[0] = mod->maxs[1] = pinq1->bounds[0] * 0.5f;
mod->mins[2] = -pinq1->bounds[1] * 0.5f;
@ -199,7 +204,7 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
{
pinhl = (dsprite_hl_t *)buffer;
size = sizeof( msprite_t ) + ( pinhl->numframes - 1 ) * sizeof( psprite->frames );
psprite = Mem_Alloc( mod->mempool, size );
psprite = Mem_Calloc( mod->mempool, size );
mod->cache.data = psprite; // make link to extradata
psprite->type = pinhl->type;
@ -243,7 +248,7 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
// install palette
switch( psprite->texFormat )
{
case SPR_INDEXALPHA:
case SPR_INDEXALPHA:
pal = FS_LoadImage( "#gradient.pal", src, 768 );
break;
case SPR_ALPHTEST:
@ -259,15 +264,12 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
}
else
{
MsgDev( D_ERROR, "%s has wrong number of palette colors %i (should be 256)\n", mod->name, *numi );
Con_DPrintf( S_ERROR "%s has wrong number of palette colors %i (should be 256)\n", mod->name, *numi );
return;
}
if( mod->numframes < 1 )
{
MsgDev( D_ERROR, "%s has invalid # of frames: %d\n", mod->name, mod->numframes );
return;
}
for( i = 0; i < mod->numframes; i++ )
{
@ -336,7 +338,7 @@ void Mod_LoadMapSprite( model_t *mod, const void *buffer, size_t size, qboolean
if( h < MAPSPRITE_SIZE ) h = MAPSPRITE_SIZE;
// resample image if needed
Image_Process( &pix, w, h, IMAGE_FORCE_RGBA|IMAGE_RESAMPLE, NULL );
Image_Process( &pix, w, h, IMAGE_FORCE_RGBA|IMAGE_RESAMPLE, 0.0f );
w = h = MAPSPRITE_SIZE;
@ -347,7 +349,7 @@ void Mod_LoadMapSprite( model_t *mod, const void *buffer, size_t size, qboolean
// determine how many frames we needs
numframes = (pix->width * pix->height) / (w * h);
mod->mempool = Mem_AllocPool( va( "^2%s^7", mod->name ));
psprite = Mem_Alloc( mod->mempool, sizeof( msprite_t ) + ( numframes - 1 ) * sizeof( psprite->frames ));
psprite = Mem_Calloc( mod->mempool, sizeof( msprite_t ) + ( numframes - 1 ) * sizeof( psprite->frames ));
mod->cache.data = psprite; // make link to extradata
psprite->type = SPR_FWD_PARALLEL_ORIENTED;
@ -367,7 +369,7 @@ void Mod_LoadMapSprite( model_t *mod, const void *buffer, size_t size, qboolean
temp.type = pix->type;
temp.flags = pix->flags;
temp.size = w * h * PFDesc[temp.type].bpp;
temp.buffer = Mem_Alloc( r_temppool, temp.size );
temp.buffer = Mem_Malloc( r_temppool, temp.size );
temp.palette = NULL;
// chop the image and upload into video memory
@ -392,7 +394,7 @@ void Mod_LoadMapSprite( model_t *mod, const void *buffer, size_t size, qboolean
// build uinque frame name
Q_snprintf( texname, sizeof( texname ), "#MAP/%s_%i%i.spr", mod->name, i / 10, i % 10 );
psprite->frames[i].frameptr = Mem_Alloc( mod->mempool, sizeof( mspriteframe_t ));
psprite->frames[i].frameptr = Mem_Calloc( mod->mempool, sizeof( mspriteframe_t ));
pspriteframe = psprite->frames[i].frameptr;
pspriteframe->width = w;
pspriteframe->height = h;
@ -400,7 +402,7 @@ void Mod_LoadMapSprite( model_t *mod, const void *buffer, size_t size, qboolean
pspriteframe->left = -( w >> 1 );
pspriteframe->down = ( h >> 1 ) - h;
pspriteframe->right = w + -( w >> 1 );
pspriteframe->gl_texturenum = GL_LoadTextureInternal( texname, &temp, TF_IMAGE, false );
pspriteframe->gl_texturenum = GL_LoadTextureInternal( texname, &temp, TF_IMAGE );
xl += w;
if( xl >= pix->width )
@ -493,7 +495,7 @@ mspriteframe_t *R_GetSpriteFrame( const model_t *pModel, int frame, float yaw )
else if( frame >= psprite->numframes )
{
if( frame > psprite->numframes )
MsgDev( D_WARN, "R_GetSpriteFrame: no such frame %d (%s)\n", frame, pModel->name );
Con_Reportf( S_WARN "R_GetSpriteFrame: no such frame %d (%s)\n", frame, pModel->name );
frame = psprite->numframes - 1;
}
@ -561,7 +563,7 @@ float R_GetSpriteFrameInterpolant( cl_entity_t *ent, mspriteframe_t **oldframe,
}
else if( frame >= psprite->numframes )
{
MsgDev( D_WARN, "R_GetSpriteFrameInterpolant: no such frame %d (%s)\n", frame, ent->model->name );
Con_Reportf( S_WARN "R_GetSpriteFrameInterpolant: no such frame %d (%s)\n", frame, ent->model->name );
frame = psprite->numframes - 1;
}
@ -979,7 +981,7 @@ void R_DrawSpriteModel( cl_entity_t *e )
color2[1] = (float)lightColor.g * ( 1.0f / 255.0f );
color2[2] = (float)lightColor.b * ( 1.0f / 255.0f );
// NOTE: sprites with 'lightmap' looks ugly when alpha func is GL_GREATER 0.0
pglAlphaFunc( GL_GREATER, 0.25f );
pglAlphaFunc( GL_GREATER, 0.5f );
}
if( R_SpriteAllowLerping( e, psprite ))
@ -1073,7 +1075,7 @@ void R_DrawSpriteModel( cl_entity_t *e )
pglColor4f( color2[0], color2[1], color2[2], tr.blend );
GL_Bind( XASH_TEXTURE0, tr.whiteTexture );
R_DrawSpriteQuad( frame, origin, v_right, v_up, scale );
pglAlphaFunc( GL_GREATER, 0.0f );
pglAlphaFunc( GL_GREATER, DEFAULT_ALPHATEST );
pglDepthFunc( GL_LEQUAL );
}

View file

@ -139,7 +139,7 @@ void R_StudioInit( void )
Matrix3x4_LoadIdentity( g_studio.rotationmatrix );
Cvar_RegisterVariable( &r_glowshellfreq );
// g-cont. especially not registered
// g-cont. cvar disabled by Valve
// Cvar_RegisterVariable( &r_shadows );
g_studio.interpolate = true;
@ -560,7 +560,7 @@ void R_StudioLerpMovement( cl_entity_t *e, double time, vec3_t origin, vec3_t an
// Con_Printf( "%4.2f %.2f %.2f\n", f, e->curstate.animtime, g_studio.time );
VectorLerp( e->latched.prevorigin, f, e->curstate.origin, origin );
if( !VectorCompare( e->curstate.angles, e->latched.prevangles ))
if( !VectorCompareEpsilon( e->curstate.angles, e->latched.prevangles, ON_EPSILON ))
{
vec4_t q, q1, q2;
@ -718,6 +718,7 @@ float CL_GetSequenceDuration( cl_entity_t *ent, int sequence )
return 0.1f;
}
/*
====================
StudioFxTransform
@ -794,8 +795,8 @@ void R_StudioCalcBoneAdj( float dadt, float *adj, const byte *pcontroller1, cons
{
if( abs( pcontroller1[i] - pcontroller2[i] ) > 128 )
{
int a = (pcontroller1[j] + 128) % 256;
int b = (pcontroller2[j] + 128) % 256;
int a = (pcontroller1[i] + 128) % 256;
int b = (pcontroller2[i] + 128) % 256;
value = (( a * dadt ) + ( b * ( 1.0f - dadt )) - 128) * (360.0f / 256.0f) + pbonecontroller[j].start;
}
else
@ -1439,7 +1440,7 @@ void R_StudioDynamicLight( cl_entity_t *ent, alight_t *plight )
}
}
if(( light.r + light.g + light.b ) == 0 )
if(( light.r + light.g + light.b ) < 16 ) // TESTTEST
{
colorVec gcolor;
float grad[4];
@ -1447,40 +1448,44 @@ void R_StudioDynamicLight( cl_entity_t *ent, alight_t *plight )
VectorScale( lightDir, 2048.0f, vecEnd );
VectorAdd( vecEnd, vecSrc, vecEnd );
light = R_LightVec( vecSrc, vecEnd, g_studio.lightspot );
light = R_LightVec( vecSrc, vecEnd, g_studio.lightspot, g_studio.lightvec );
VectorScale( lightDir, 2048.0f, vecEnd );
VectorAdd( vecEnd, vecSrc, vecEnd );
if( VectorIsNull( g_studio.lightvec ))
{
vecSrc[0] -= 16.0f;
vecSrc[1] -= 16.0f;
vecEnd[0] -= 16.0f;
vecEnd[1] -= 16.0f;
vecSrc[0] -= 16.0f;
vecSrc[1] -= 16.0f;
vecEnd[0] -= 16.0f;
vecEnd[1] -= 16.0f;
gcolor = R_LightVec( vecSrc, vecEnd, NULL, NULL );
grad[0] = ( gcolor.r + gcolor.g + gcolor.b ) / 768.0f;
gcolor = R_LightVec( vecSrc, vecEnd, NULL );
grad[0] = ( gcolor.r + gcolor.g + gcolor.b ) / 768.0f;
vecSrc[0] += 32.0f;
vecEnd[0] += 32.0f;
vecSrc[0] += 32.0f;
vecEnd[0] += 32.0f;
gcolor = R_LightVec( vecSrc, vecEnd, NULL, NULL );
grad[1] = ( gcolor.r + gcolor.g + gcolor.b ) / 768.0f;
gcolor = R_LightVec( vecSrc, vecEnd, NULL );
grad[1] = ( gcolor.r + gcolor.g + gcolor.b ) / 768.0f;
vecSrc[1] += 32.0f;
vecEnd[1] += 32.0f;
vecSrc[1] += 32.0f;
vecEnd[1] += 32.0f;
gcolor = R_LightVec( vecSrc, vecEnd, NULL, NULL );
grad[2] = ( gcolor.r + gcolor.g + gcolor.b ) / 768.0f;
gcolor = R_LightVec( vecSrc, vecEnd, NULL );
grad[2] = ( gcolor.r + gcolor.g + gcolor.b ) / 768.0f;
vecSrc[0] -= 32.0f;
vecEnd[0] -= 32.0f;
vecSrc[0] -= 32.0f;
vecEnd[0] -= 32.0f;
gcolor = R_LightVec( vecSrc, vecEnd, NULL, NULL );
grad[3] = ( gcolor.r + gcolor.g + gcolor.b ) / 768.0f;
gcolor = R_LightVec( vecSrc, vecEnd, NULL );
grad[3] = ( gcolor.r + gcolor.g + gcolor.b ) / 768.0f;
lightDir[0] = grad[0] - grad[1] - grad[2] + grad[3];
lightDir[1] = grad[1] + grad[0] - grad[2] - grad[3];
VectorNormalize( lightDir );
lightDir[0] = grad[0] - grad[1] - grad[2] + grad[3];
lightDir[1] = grad[1] + grad[0] - grad[2] - grad[3];
VectorNormalize( lightDir );
}
else
{
VectorCopy( g_studio.lightvec, lightDir );
}
}
VectorSet( finalLight, light.r, light.g, light.b );
@ -2172,6 +2177,7 @@ static void R_StudioDrawPoints( void )
pglBlendFunc( GL_ONE, GL_ONE );
pglDepthMask( GL_FALSE );
pglEnable( GL_BLEND );
R_AllowFog( false );
}
else pglBlendFunc( GL_SRC_ALPHA, GL_ONE );
}
@ -2186,13 +2192,14 @@ static void R_StudioDrawPoints( void )
if( FBitSet( g_nFaceFlags, STUDIO_NF_MASKED ))
{
pglAlphaFunc( GL_GREATER, 0.0f );
pglAlphaFunc( GL_GREATER, DEFAULT_ALPHATEST );
pglDisable( GL_ALPHA_TEST );
}
else if( FBitSet( g_nFaceFlags, STUDIO_NF_ADDITIVE ) && R_ModelOpaque( RI.currententity->curstate.rendermode ))
{
pglDepthMask( GL_TRUE );
pglDisable( GL_BLEND );
R_AllowFog( true );
}
r_stats.c_studio_polys += pmesh->numtris;
@ -2290,6 +2297,7 @@ static void R_StudioDrawAbsBBox( void )
TriVertex3fv( p[boxpnt[i][3]] );
}
TriEnd();
TriRenderMode( kRenderNormal );
}
/*
@ -2472,11 +2480,11 @@ check for texture flags
*/
int R_GetEntityRenderMode( cl_entity_t *ent )
{
studiohdr_t *phdr;
int i, opaque, trans;
mstudiotexture_t *ptexture;
cl_entity_t *oldent;
model_t *model;
int i;
studiohdr_t *phdr;
oldent = RI.currententity;
RI.currententity = ent;
@ -2489,21 +2497,27 @@ int R_GetEntityRenderMode( cl_entity_t *ent )
if(( phdr = Mod_StudioExtradata( model )) == NULL )
{
// forcing to choose right sorting type
if(( model && model->type == mod_brush ) && FBitSet( model->flags, MODEL_TRANSPARENT ))
return kRenderTransAlpha;
if( R_ModelOpaque( ent->curstate.rendermode ))
{
// forcing to choose right sorting type
if(( model && model->type == mod_brush ) && FBitSet( model->flags, MODEL_TRANSPARENT ))
return kRenderTransAlpha;
}
return ent->curstate.rendermode;
}
ptexture = (mstudiotexture_t *)((byte *)phdr + phdr->textureindex);
for( i = 0; i < phdr->numtextures; i++, ptexture++ )
for( opaque = trans = i = 0; i < phdr->numtextures; i++, ptexture++ )
{
// g-cont. this is not fully proper but better than was
if( FBitSet( ptexture->flags, STUDIO_NF_ADDITIVE ))
return kRenderTransAdd;
// if( FBitSet( ptexture->flags, STUDIO_NF_MASKED ))
// return kRenderTransAlpha;
// ignore chrome & additive it's just a specular-like effect
if( FBitSet( ptexture->flags, STUDIO_NF_ADDITIVE ) && !FBitSet( ptexture->flags, STUDIO_NF_CHROME ))
trans++;
else opaque++;
}
// if model is more additive than opaque
if( trans > opaque )
return kRenderTransAdd;
return ent->curstate.rendermode;
}
@ -2885,6 +2899,13 @@ void R_StudioRenderFinal( void )
pglVertex3fv( g_studio.lightspot );
pglEnd();
pglBegin( GL_LINES );
pglColor3f( 0, 0.5, 1 );
VectorMA( g_studio.lightspot, -64.0f, g_studio.lightvec, origin );
pglVertex3fv( g_studio.lightspot );
pglVertex3fv( origin );
pglEnd();
pglPointSize( 5.0f );
pglColor3f( 1, 0, 0 );
pglBegin( GL_POINTS );
@ -3390,10 +3411,10 @@ void R_RunViewmodelEvents( void )
/*
=================
R_DrawViewModel
R_GatherPlayerLight
=================
*/
void R_DrawViewModel( void )
void R_GatherPlayerLight( void )
{
cl_entity_t *view = &clgame.viewent;
colorVec c;
@ -3402,6 +3423,18 @@ void R_DrawViewModel( void )
c = R_LightPoint( view->origin );
tr.ignore_lightgamma = false;
cl.local.light_level = (c.r + c.g + c.b) / 3;
}
/*
=================
R_DrawViewModel
=================
*/
void R_DrawViewModel( void )
{
cl_entity_t *view = &clgame.viewent;
R_GatherPlayerLight();
if( r_drawviewmodel->value == 0 )
return;
@ -3467,7 +3500,6 @@ static void R_StudioLoadTexture( model_t *mod, studiohdr_t *phdr, mstudiotexture
size_t size;
int flags = 0;
char texname[128], name[128], mdlname[128];
imgfilter_t *filter = NULL;
texture_t *tx = NULL;
if( ptexture->flags & STUDIO_NF_NORMALMAP )
@ -3483,7 +3515,7 @@ static void R_StudioLoadTexture( model_t *mod, studiohdr_t *phdr, mstudiotexture
i = mod->numtextures;
mod->textures = (texture_t **)Mem_Realloc( mod->mempool, mod->textures, ( i + 1 ) * sizeof( texture_t* ));
size = ptexture->width * ptexture->height + 768;
tx = Mem_Alloc( mod->mempool, sizeof( *tx ) + size );
tx = Mem_Calloc( mod->mempool, sizeof( *tx ) + size );
mod->textures[i] = tx;
// store ranges into anim_min, anim_max etc
@ -3524,15 +3556,12 @@ static void R_StudioLoadTexture( model_t *mod, studiohdr_t *phdr, mstudiotexture
COM_FileBase( ptexture->name, name );
COM_StripExtension( mdlname );
// loading texture filter for studiomodel
if( !FBitSet( ptexture->flags, STUDIO_NF_COLORMAP ))
filter = R_FindTexFilter( va( "%s.mdl/%s", mdlname, name )); // grab texture filter
if( FBitSet( ptexture->flags, STUDIO_NF_NOMIPS ))
SetBits( flags, TF_NOMIPMAP );
// NOTE: replace index with pointer to start of imagebuffer, ImageLib expected it
ptexture->index = (int)((byte *)phdr) + ptexture->index;
//ptexture->index = (int)((byte *)phdr) + ptexture->index;
Image_SetMDLPointer((byte *)phdr + ptexture->index);
size = sizeof( mstudiotexture_t ) + ptexture->width * ptexture->height + 768;
if( FBitSet( host.features, ENGINE_LOAD_DELUXEDATA ) && FBitSet( ptexture->flags, STUDIO_NF_MASKED ))
@ -3540,7 +3569,7 @@ static void R_StudioLoadTexture( model_t *mod, studiohdr_t *phdr, mstudiotexture
// build the texname
Q_snprintf( texname, sizeof( texname ), "#%s/%s.mdl", mdlname, name );
ptexture->index = GL_LoadTexture( texname, (byte *)ptexture, size, flags, filter );
ptexture->index = GL_LoadTexture( texname, (byte *)ptexture, size, flags );
if( !ptexture->index )
{

View file

@ -21,7 +21,7 @@ GNU General Public License for more details.
#define SKYCLOUDS_QUALITY 12
#define MAX_CLIP_VERTS 128 // skybox clip vertices
#define TURBSCALE ( 256.0f / ( M_PI2 ))
static const char* r_skyBoxSuffix[6] = { "rt", "bk", "lf", "ft", "up", "dn" };
const char* r_skyBoxSuffix[6] = { "rt", "bk", "lf", "ft", "up", "dn" };
static const int r_skyTexOrder[6] = { 0, 2, 1, 3, 4, 5 };
static const vec3_t skyclip[6] =
@ -372,6 +372,9 @@ void R_DrawSkyBox( void )
// don't fogging skybox (this fix old Half-Life bug)
if( !RI.fogSkybox ) R_AllowFog( false );
if( RI.fogEnabled )
pglFogf( GL_FOG_DENSITY, RI.fogDensity * 0.5f );
pglDisable( GL_BLEND );
pglDisable( GL_ALPHA_TEST );
pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
@ -395,6 +398,10 @@ void R_DrawSkyBox( void )
if( !RI.fogSkybox )
R_AllowFog( true );
if( RI.fogEnabled )
pglFogf( GL_FOG_DENSITY, RI.fogDensity );
R_LoadIdentity();
}
@ -441,7 +448,7 @@ void R_SetupSky( const char *skyboxname )
Q_snprintf( sidename, sizeof( sidename ), "%s%s", loadname, r_skyBoxSuffix[i] );
else Q_snprintf( sidename, sizeof( sidename ), "%s_%s", loadname, r_skyBoxSuffix[i] );
tr.skyboxTextures[i] = GL_LoadTexture( sidename, NULL, 0, TF_CLAMP|TF_SKY, NULL );
tr.skyboxTextures[i] = GL_LoadTexture( sidename, NULL, 0, TF_CLAMP|TF_SKY );
if( !tr.skyboxTextures[i] ) break;
Con_DPrintf( "%s%s%s", skyboxname, r_skyBoxSuffix[i], i != 5 ? ", " : ". " );
}
@ -672,14 +679,14 @@ void R_InitSkyClouds( mip_t *mt, texture_t *tx, qboolean custom_palette )
// make sure what sky image is valid
if( !r_sky || !r_sky->palette || r_sky->type != PF_INDEXED_32 || r_sky->height == 0 )
{
MsgDev( D_ERROR, "R_InitSky: unable to load sky texture %s\n", tx->name );
Con_Reportf( S_ERROR "R_InitSky: unable to load sky texture %s\n", tx->name );
if( r_sky ) FS_FreeImage( r_sky );
return;
}
// make an average value for the back to avoid
// a fringe on the top level
trans = Mem_Alloc( r_temppool, r_sky->height * r_sky->height * sizeof( *trans ));
trans = Mem_Malloc( r_temppool, r_sky->height * r_sky->height * sizeof( *trans ));
r = g = b = 0;
for( i = 0; i < r_sky->width >> 1; i++ )
@ -711,7 +718,7 @@ void R_InitSkyClouds( mip_t *mt, texture_t *tx, qboolean custom_palette )
r_temp.palette = NULL;
// load it in
tr.solidskyTexture = GL_LoadTextureInternal( "solid_sky", &r_temp, TF_NOMIPMAP, false );
tr.solidskyTexture = GL_LoadTextureInternal( "solid_sky", &r_temp, TF_NOMIPMAP );
for( i = 0; i < r_sky->width >> 1; i++ )
{
@ -734,7 +741,7 @@ void R_InitSkyClouds( mip_t *mt, texture_t *tx, qboolean custom_palette )
r_temp.flags = IMAGE_HAS_COLOR|IMAGE_HAS_ALPHA;
// load it in
tr.alphaskyTexture = GL_LoadTextureInternal( "alpha_sky", &r_temp, TF_NOMIPMAP, false );
tr.alphaskyTexture = GL_LoadTextureInternal( "alpha_sky", &r_temp, TF_NOMIPMAP );
// clean up
FS_FreeImage( r_sky );

View file

@ -172,7 +172,7 @@ void Evdev_OpenDevice ( const char *path )
ret = open( path, O_RDONLY | O_NONBLOCK );
if( ret < 0 )
{
MsgDev( D_ERROR, "Could not open input device %s: %s\n", path, strerror( errno ) );
Con_Reportf( S_ERROR "Could not open input device %s: %s\n", path, strerror( errno ) );
return;
}
Msg( "Input device #%d: %s opened sucessfully\n", evdev.devices, path );
@ -183,7 +183,7 @@ void Evdev_OpenDevice ( const char *path )
void Evdev_OpenDevice_f( void )
{
if( Cmd_Argc() < 2 )
Msg( "Usage: evdev_opendevice <path>\n" );
Msg( S_USAGE "evdev_opendevice <path>\n" );
Evdev_OpenDevice( Cmd_Argv( 1 ) );
}

View file

@ -21,10 +21,7 @@ GNU General Public License for more details.
#include "keydefs.h"
#include "client.h"
#include "gl_local.h"
#if defined(XASH_SDL)
#include "platform/sdl/events.h"
#endif
#include "platform/platform.h"
#ifndef SHRT_MAX
#define SHRT_MAX 0x7FFF
@ -62,28 +59,24 @@ static struct joy_axis_s
short val;
short prevval;
} joyaxis[MAX_AXES] = { 0 };
static qboolean initialized = false, forcedisable = false;
static convar_t *joy_enable;
static qboolean forcedisable = false;
static byte currentbinding; // add posibility to remap keys, to place it in joykeys[]
float IN_TouchDrawText( float x1, float y1, float x2, float y2, const char *s, byte *color, float size );
float IN_TouchDrawCharacter( float x, float y, int number, float size );
convar_t *joy_pitch;
convar_t *joy_yaw;
convar_t *joy_forward;
convar_t *joy_side;
convar_t *joy_found;
convar_t *joy_index;
convar_t *joy_lt_threshold;
convar_t *joy_rt_threshold;
convar_t *joy_side_deadzone;
convar_t *joy_forward_deadzone;
convar_t *joy_side_key_threshold;
convar_t *joy_forward_key_threshold;
convar_t *joy_pitch_deadzone;
convar_t *joy_yaw_deadzone;
convar_t *joy_axis_binding;
static convar_t *joy_enable;
static convar_t *joy_pitch;
static convar_t *joy_yaw;
static convar_t *joy_forward;
static convar_t *joy_side;
static convar_t *joy_found;
static convar_t *joy_index;
static convar_t *joy_lt_threshold;
static convar_t *joy_rt_threshold;
static convar_t *joy_side_deadzone;
static convar_t *joy_forward_deadzone;
static convar_t *joy_side_key_threshold;
static convar_t *joy_forward_key_threshold;
static convar_t *joy_pitch_deadzone;
static convar_t *joy_yaw_deadzone;
static convar_t *joy_axis_binding;
/*
============
@ -92,7 +85,7 @@ Joy_IsActive
*/
qboolean Joy_IsActive( void )
{
return !forcedisable && initialized;
return !forcedisable && joy_found->value;
}
/*
@ -117,7 +110,7 @@ void Joy_HatMotionEvent( int id, byte hat, byte value )
};
int i;
if( !initialized )
if( !joy_found->value )
return;
for( i = 0; i < ARRAYSIZE( keys ); i++ )
@ -155,7 +148,7 @@ void Joy_ProcessTrigger( const engineAxis_t engineAxis, short value )
trigThreshold = joy_lt_threshold->value;
break;
default:
MsgDev( D_ERROR, "Joy_ProcessTrigger: invalid axis = %i", engineAxis );
Con_Reportf( S_ERROR "Joy_ProcessTrigger: invalid axis = %i", engineAxis );
break;
}
@ -226,7 +219,7 @@ void Joy_ProcessStick( const engineAxis_t engineAxis, short value )
case JOY_AXIS_PITCH: deadzone = joy_pitch_deadzone->value; break;
case JOY_AXIS_YAW: deadzone = joy_yaw_deadzone->value; break;
default:
MsgDev( D_ERROR, "Joy_ProcessStick: invalid axis = %i", engineAxis );
Con_Reportf( S_ERROR "Joy_ProcessStick: invalid axis = %i", engineAxis );
break;
}
@ -261,12 +254,12 @@ void Joy_AxisMotionEvent( int id, byte axis, short value )
{
byte engineAxis;
if( !initialized )
if( !joy_found->value )
return;
if( axis >= MAX_AXES )
{
MsgDev( D_INFO, "Only 6 axes is supported\n" );
Con_Reportf( "Only 6 axes is supported\n" );
return;
}
@ -293,7 +286,7 @@ Trackball events. UNDONE
*/
void Joy_BallMotionEvent( int id, byte ball, short xrel, short yrel )
{
//if( !initialized )
//if( !joy_found->value )
// return;
}
@ -306,7 +299,7 @@ Button events
*/
void Joy_ButtonEvent( int id, byte button, byte down )
{
if( !initialized )
if( !joy_found->value )
return;
// generic game button code.
@ -315,7 +308,7 @@ void Joy_ButtonEvent( int id, byte button, byte down )
int origbutton = button;
button = ( button & 31 ) + K_AUX1;
MsgDev( D_INFO, "Only 32 joybuttons is supported, converting %i button ID to %s\n", origbutton, Key_KeynumToString( button ) );
Con_Reportf( "Only 32 joybuttons is supported, converting %i button ID to %s\n", origbutton, Key_KeynumToString( button ) );
}
else button += K_AUX1;
@ -331,7 +324,7 @@ Called when joystick is removed. For future expansion
*/
void Joy_RemoveEvent( int id )
{
if( !forcedisable && initialized && joy_found->value )
if( !forcedisable && joy_found->value )
Cvar_SetValue("joy_found", joy_found->value - 1.0f);
}
@ -347,8 +340,6 @@ void Joy_AddEvent( int id )
if( forcedisable )
return;
initialized = true;
Cvar_SetValue("joy_found", joy_found->value + 1.0f);
}
@ -361,7 +352,7 @@ Append movement from axis. Called everyframe
*/
void Joy_FinalizeMove( float *fw, float *side, float *dpitch, float *dyaw )
{
if( !initialized || !joy_enable->value )
if( !joy_found->value || !joy_enable->value )
return;
if( FBitSet( joy_axis_binding->flags, FCVAR_CHANGED ) )
@ -440,19 +431,7 @@ void Joy_Init( void )
return;
}
#if defined(XASH_SDL)
// SDL can tell us about connected joysticks
Cvar_SetValue( "joy_found", SDLash_JoyInit( joy_index->value ) );
#elif defined(ANDROID)
// Initalized after first Joy_AddEvent
#else
#warning "Any platform must implement platform-dependent JoyInit, start event system. Otherwise no joystick support"
#endif
if( joy_found->value > 0 )
initialized = true;
else
initialized = false;
Cvar_SetValue( "joy_found", Platform_JoyInit( joy_index->value ) );
}
/*
@ -465,8 +444,6 @@ Shutdown joystick code
void Joy_Shutdown( void )
{
Cvar_SetValue( "joy_found", 0 );
initialized = false;
}
#endif // XASH_DEDICATED

View file

@ -24,6 +24,7 @@ GNU General Public License for more details.
#ifdef XASH_SDL
#include <SDL.h>
#endif
#include "platform/platform.h"
typedef enum
{
@ -173,7 +174,7 @@ void IN_TouchWriteConfig( void )
if( Sys_CheckParm( "-nowriteconfig" ) || !touch.configchanged )
return;
MsgDev( D_NOTE, "IN_TouchWriteConfig(): %s\n", touch_config_file->string );
Con_Reportf( "IN_TouchWriteConfig(): %s\n", touch_config_file->string );
Q_snprintf( newconfigfile, 64, "%s.new", touch_config_file->string );
Q_snprintf( oldconfigfile, 64, "%s.bak", touch_config_file->string );
@ -240,7 +241,7 @@ void IN_TouchWriteConfig( void )
FS_Delete( touch_config_file->string );
FS_Rename( newconfigfile, touch_config_file->string );
}
else MsgDev( D_ERROR, "Couldn't write %s.\n", touch_config_file->string );
else Con_Reportf( S_ERROR "Couldn't write %s.\n", touch_config_file->string );
}
void IN_TouchExportConfig_f( void )
@ -250,7 +251,7 @@ void IN_TouchExportConfig_f( void )
if( Cmd_Argc() != 2 )
{
Msg( "Usage: touch_exportconfig <name>\n" );
Msg( S_USAGE "touch_exportconfig <name>\n" );
return;
}
@ -258,7 +259,7 @@ void IN_TouchExportConfig_f( void )
name = Cmd_Argv( 1 );
MsgDev( D_NOTE, "Exporting config to %s\n", name );
Con_Reportf( "Exporting config to %s\n", name );
f = FS_Open( name, "w", true );
if( f )
{
@ -330,7 +331,7 @@ void IN_TouchExportConfig_f( void )
FS_Printf( f, "touch_roundall\n" );
FS_Close( f );
}
else MsgDev( D_ERROR, "Couldn't write %s.\n", name );
else Con_Reportf( S_ERROR "Couldn't write %s.\n", name );
}
void IN_TouchGenetateCode_f( void )
@ -340,7 +341,7 @@ void IN_TouchGenetateCode_f( void )
if( Cmd_Argc() != 1 )
{
Msg( "Usage: touch_generate_code\n" );
Msg( S_USAGE "touch_generate_code\n" );
return;
}
@ -584,7 +585,7 @@ void IN_TouchSetColor_f( void )
IN_TouchSetColor( &touch.list_user, Cmd_Argv(1), color );
return;
}
Msg( "Usage: touch_setcolor <pattern> <r> <g> <b> <a>\n" );
Msg( S_USAGE "touch_setcolor <pattern> <r> <g> <b> <a>\n" );
}
void IN_TouchSetTexture_f( void )
@ -594,7 +595,7 @@ void IN_TouchSetTexture_f( void )
IN_TouchSetTexture( &touch.list_user, Cmd_Argv( 1 ), Cmd_Argv( 2 ) );
return;
}
Msg( "Usage: touch_settexture <name> <file>\n" );
Msg( S_USAGE "touch_settexture <name> <file>\n" );
}
void IN_TouchSetFlags_f( void )
@ -606,7 +607,7 @@ void IN_TouchSetFlags_f( void )
button->flags = Q_atoi( Cmd_Argv( 2 ) );
return;
}
Msg( "Usage: touch_setflags <name> <file>\n" );
Msg( S_USAGE "touch_setflags <name> <file>\n" );
}
void IN_TouchSetCommand_f( void )
@ -616,7 +617,7 @@ void IN_TouchSetCommand_f( void )
IN_TouchSetCommand( &touch.list_user, Cmd_Argv( 1 ), Cmd_Argv( 2 ) );
return;
}
Msg( "Usage: touch_command <name> <command>\n" );
Msg( S_USAGE "touch_command <name> <command>\n" );
}
void IN_TouchReloadConfig_f( void )
{
@ -625,7 +626,7 @@ void IN_TouchReloadConfig_f( void )
touchbutton2_t *IN_TouchAddButton( touchbuttonlist_t *list, const char *name, const char *texture, const char *command, float x1, float y1, float x2, float y2, byte *color )
{
touchbutton2_t *button = Mem_Alloc( touch.mempool, sizeof( touchbutton2_t ) );
touchbutton2_t *button = Mem_Malloc( touch.mempool, sizeof( touchbutton2_t ) );
button->texture = -1;
Q_strncpy( button->texturefile, texture, sizeof( button->texturefile ) );
Q_strncpy( button->name, name, 32 );
@ -779,7 +780,7 @@ void IN_TouchAddButton_f( void )
IN_TouchAddButton( &touch.list_user, Cmd_Argv(1), Cmd_Argv(2), Cmd_Argv(3), 0.4, 0.4, 0.6, 0.6, color );
return;
}
Msg( "Usage: touch_addbutton <name> <texture> <command> [<x1> <y1> <x2> <y2> [ r g b a ] ]\n" );
Msg( S_USAGE "touch_addbutton <name> <texture> <command> [<x1> <y1> <x2> <y2> [ r g b a ] ]\n" );
}
void IN_TouchEnableEdit_f( void )
@ -806,7 +807,7 @@ void IN_TouchDeleteProfile_f( void )
{
if( Cmd_Argc() != 2 )
{
Msg( "Usage: touch_deleteprofile <name>\n" );
Msg( S_USAGE "touch_deleteprofile <name>\n" );
return;
}
@ -822,7 +823,7 @@ void IN_TouchInit( void )
return;
touch.mempool = Mem_AllocPool( "Touch" );
//touch.first = touch.last = NULL;
MsgDev( D_NOTE, "IN_TouchInit()\n");
Con_Reportf( "IN_TouchInit()\n");
touch.move_finger = touch.resize_finger = touch.look_finger = -1;
touch.state = state_none;
touch.showbuttons = true;
@ -907,9 +908,6 @@ void IN_TouchInit( void )
// input devices cvar
touch_enable = Cvar_Get( "touch_enable", DEFAULT_TOUCH_ENABLE, FCVAR_ARCHIVE, "enable touch controls" );
#if defined(XASH_SDL) && defined(__ANDROID__)
SDL_SetHint( SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH, "1" );
#endif
touch.initialized = true;
}
@ -923,11 +921,11 @@ void IN_TouchInitConfig( void )
if( FS_FileExists( touch_config_file->string, true ) )
Cbuf_AddText( va( "exec \"%s\"\n", touch_config_file->string ) );
else IN_TouchLoadDefaults_f( );
touch.closetexture = GL_LoadTexture( "touch_default/edit_close.tga", NULL, 0, TF_NOMIPMAP, NULL );
touch.hidetexture = GL_LoadTexture( "touch_default/edit_hide.tga", NULL, 0, TF_NOMIPMAP, NULL );
touch.showtexture = GL_LoadTexture( "touch_default/edit_show.tga", NULL, 0, TF_NOMIPMAP, NULL );
touch.resettexture = GL_LoadTexture( "touch_default/edit_reset.tga", NULL, 0, TF_NOMIPMAP, NULL );
touch.joytexture = GL_LoadTexture( touch_joy_texture->string, NULL, 0, TF_NOMIPMAP, NULL );
touch.closetexture = GL_LoadTexture( "touch_default/edit_close.tga", NULL, 0, TF_NOMIPMAP );
touch.hidetexture = GL_LoadTexture( "touch_default/edit_hide.tga", NULL, 0, TF_NOMIPMAP );
touch.showtexture = GL_LoadTexture( "touch_default/edit_show.tga", NULL, 0, TF_NOMIPMAP );
touch.resettexture = GL_LoadTexture( "touch_default/edit_reset.tga", NULL, 0, TF_NOMIPMAP );
touch.joytexture = GL_LoadTexture( touch_joy_texture->string, NULL, 0, TF_NOMIPMAP );
touch.configchanged = false;
}
qboolean IN_TouchIsVisible( touchbutton2_t *button )
@ -1115,7 +1113,7 @@ void Touch_DrawButtons( touchbuttonlist_t *list )
{
if( button->texture == -1 )
{
button->texture = GL_LoadTexture( button->texturefile, NULL, 0, TF_NOMIPMAP, NULL );
button->texture = GL_LoadTexture( button->texturefile, NULL, 0, TF_NOMIPMAP );
}
if( B(flags) & TOUCH_FL_DRAW_ADDITIVE )
@ -1260,7 +1258,7 @@ void IN_TouchDraw( void )
if( FBitSet( touch_joy_texture->flags, FCVAR_CHANGED ) )
{
ClearBits( touch_joy_texture->flags, FCVAR_CHANGED );
touch.joytexture = GL_LoadTexture( touch_joy_texture->string, NULL, 0, TF_NOMIPMAP, NULL );
touch.joytexture = GL_LoadTexture( touch_joy_texture->string, NULL, 0, TF_NOMIPMAP );
}
if( touch.move->type == touch_move )
{
@ -1451,7 +1449,7 @@ static qboolean Touch_ButtonPress( touchbuttonlist_t *list, touchEventType type,
//touch.move_finger = button->finger = -1;
for( newbutton = list->first; newbutton; newbutton = newbutton->next )
if( ( newbutton->type == touch_move ) || ( newbutton->type == touch_look ) ) newbutton->finger = -1;
MsgDev( D_NOTE, "Touch: touch_move on look finger %d!\n", fingerID );
Con_Reportf( "Touch: touch_move on look finger %d!\n", fingerID );
continue;
}
touch.move_finger = fingerID;
@ -1490,7 +1488,7 @@ static qboolean Touch_ButtonPress( touchbuttonlist_t *list, touchEventType type,
touch.move_finger = touch.look_finger = -1;
for( newbutton = list->first; newbutton; newbutton = newbutton->next )
if( ( newbutton->type == touch_move ) || ( newbutton->type == touch_look ) ) newbutton->finger = -1;
MsgDev( D_NOTE, "Touch: touch_look on move finger %d!\n", fingerID );
Con_Reportf( "Touch: touch_look on move finger %d!\n", fingerID );
continue;
}
touch.look_finger = fingerID;
@ -1669,7 +1667,7 @@ int IN_TouchEvent( touchEventType type, int fingerID, float x, float y, float dx
Cbuf_AddText( "escape\n" );
}
UI_MouseMove( TO_SCRN_X(x), TO_SCRN_Y(y) );
//MsgDev( D_NOTE, "touch %d %d\n", TO_SCRN_X(x), TO_SCRN_Y(y) );
//Con_Reportf( "touch %d %d\n", TO_SCRN_X(x), TO_SCRN_Y(y) );
if( type == event_down )
Key_Event( K_MOUSE1, true );
if( type == event_up )
@ -1728,7 +1726,7 @@ void IN_TouchKeyEvent( int key, int down )
if( !touch.clientonly )
return;
CL_GetMousePosition( &xi, &yi );
Platform_GetMousePos( &xi, &yi );
x = xi/SCR_W;
y = yi/SCR_H;

View file

@ -27,6 +27,8 @@ GNU General Public License for more details.
#include "windows.h"
#endif
#include "platform/platform.h"
void* in_mousecursor;
qboolean in_mouseactive; // false when not focus app
qboolean in_mouseinitialized;
@ -101,10 +103,8 @@ void IN_MouseSavePos( void )
if( !in_mouseactive )
return;
#ifdef XASH_SDL
SDL_GetMouseState( &in_lastvalidpos.x, &in_lastvalidpos.y );
Platform_GetMousePos( &in_lastvalidpos.x, &in_lastvalidpos.y );
in_mouse_savedpos = true;
#endif
}
/*
@ -119,9 +119,7 @@ void IN_MouseRestorePos( void )
if( !in_mouse_savedpos )
return;
#ifdef XASH_SDL
SDL_WarpMouseInWindow( host.hWnd, in_lastvalidpos.x, in_lastvalidpos.y );
#endif
Platform_SetMousePos( in_lastvalidpos.x, in_lastvalidpos.y );
in_mouse_savedpos = false;
}
@ -152,7 +150,7 @@ void IN_ToggleClientMouse( int newstate, int oldstate )
}
else
{
SDL_WarpMouseInWindow( host.hWnd, host.window_center_x, host.window_center_y );
Platform_SetMousePos( host.window_center_x, host.window_center_y );
SDL_SetWindowGrab( host.hWnd, SDL_TRUE );
if( clgame.dllFuncs.pfnLookEvent )
SDL_SetRelativeMouseMode( SDL_TRUE );
@ -282,9 +280,7 @@ void IN_MouseMove( void )
return;
// find mouse movement
#ifdef XASH_SDL
SDL_GetMouseState( &current_pos.x, &current_pos.y );
#endif
Platform_GetMousePos( &current_pos.x, &current_pos.y );
VGui_MouseMove( current_pos.x, current_pos.y );
@ -321,7 +317,7 @@ void IN_MouseEvent( void )
#if defined( XASH_SDL )
static qboolean ignore; // igonre mouse warp event
int x, y;
SDL_GetMouseState(&x, &y);
Platform_GetMousePos(&x, &y);
if( host.mouse_visible )
SDL_ShowCursor( SDL_TRUE );
else
@ -332,7 +328,7 @@ void IN_MouseEvent( void )
x > host.window_center_x + host.window_center_x / 2 ||
y > host.window_center_y + host.window_center_y / 2 )
{
SDL_WarpMouseInWindow(host.hWnd, host.window_center_x, host.window_center_y);
Platform_SetMousePos( host.window_center_x, host.window_center_y );
ignore = 1; // next mouse event will be mouse warp
return;
}
@ -493,6 +489,47 @@ void IN_JoyAppendMove( usercmd_t *cmd, float forwardmove, float sidemove )
}
}
void IN_CollectInput( float *forward, float *side, float *pitch, float *yaw, qboolean includeMouse, qboolean includeSdlMouse )
{
if( !m_ignore->value || includeMouse )
{
#if XASH_INPUT == INPUT_SDL
if( includeSdlMouse )
{
int x, y;
SDL_GetRelativeMouseState( &x, &y );
*pitch += y * m_pitch->value;
*yaw -= x * m_yaw->value;
}
#endif // INPUT_SDL
#ifdef __ANDROID__
{
float x, y;
Android_MouseMove( &x, &y );
*pitch += y * m_pitch->value;
*yaw -= x * m_yaw->value;
}
#endif // ANDROID
#ifdef USE_EVDEV
IN_EvdevMove( yaw, pitch );
#endif
}
Joy_FinalizeMove( forward, side, yaw, pitch );
IN_TouchMove( forward, side, yaw, pitch );
if( look_filter->value )
{
*pitch = ( inputstate.lastpitch + *pitch ) / 2;
*yaw = ( inputstate.lastyaw + *yaw ) / 2;
inputstate.lastpitch = *pitch;
inputstate.lastyaw = *yaw;
}
}
/*
================
IN_EngineAppendMove
@ -502,7 +539,7 @@ Called from cl_main.c after generating command in client
*/
void IN_EngineAppendMove( float frametime, usercmd_t *cmd, qboolean active )
{
float forward, side, dpitch, dyaw;
float forward, side, pitch, yaw;
if( clgame.dllFuncs.pfnLookEvent )
return;
@ -510,45 +547,18 @@ void IN_EngineAppendMove( float frametime, usercmd_t *cmd, qboolean active )
if( cls.key_dest != key_game || cl.paused || cl.intermission )
return;
forward = side = dpitch = dyaw = 0;
forward = side = pitch = yaw = 0;
if(active)
if( active )
{
float sensitivity = ( (float)RI.fov_x / (float)90.0f );
#if XASH_INPUT == INPUT_SDL
if( m_enginemouse->value && !m_ignore->value )
{
int mouse_x, mouse_y;
SDL_GetRelativeMouseState( &mouse_x, &mouse_y );
RI.viewangles[PITCH] += mouse_y * m_pitch->value * sensitivity;
RI.viewangles[YAW] -= mouse_x * m_yaw->value * sensitivity;
}
#endif
#ifdef __ANDROID__
if( !m_ignore->value )
{
float mouse_x, mouse_y;
Android_MouseMove( &mouse_x, &mouse_y );
RI.viewangles[PITCH] += mouse_y * m_pitch->value * sensitivity;
RI.viewangles[YAW] -= mouse_x * m_yaw->value * sensitivity;
}
#endif
Joy_FinalizeMove( &forward, &side, &dyaw, &dpitch );
IN_TouchMove( &forward, &side, &dyaw, &dpitch );
IN_JoyAppendMove( cmd, forward, side );
#ifdef USE_EVDEV
IN_EvdevMove( &dyaw, &dpitch );
#endif
if( look_filter->value )
{
dpitch = ( inputstate.lastpitch + dpitch ) / 2;
dyaw = ( inputstate.lastyaw + dyaw ) / 2;
inputstate.lastpitch = dpitch;
inputstate.lastyaw = dyaw;
}
RI.viewangles[YAW] += dyaw * sensitivity;
RI.viewangles[PITCH] += dpitch * sensitivity;
IN_CollectInput( &forward, &side, &pitch, &yaw, in_mouseinitialized, m_enginemouse->value );
IN_JoyAppendMove( cmd, forward, side );
RI.viewangles[YAW] += yaw * sensitivity;
RI.viewangles[PITCH] += pitch * sensitivity;
RI.viewangles[PITCH] = bound( -90, RI.viewangles[PITCH], 90 );
}
}
@ -573,37 +583,7 @@ void Host_InputFrame( void )
if( clgame.dllFuncs.pfnLookEvent )
{
int dx, dy;
#ifndef __ANDROID__
if( in_mouseinitialized && !m_ignore->value )
{
SDL_GetRelativeMouseState( &dx, &dy );
pitch += dy * m_pitch->value, yaw -= dx * m_yaw->value; //mouse speed
}
#endif
#ifdef __ANDROID__
if( !m_ignore->value )
{
float mouse_x, mouse_y;
Android_MouseMove( &mouse_x, &mouse_y );
pitch += mouse_y * m_pitch->value, yaw -= mouse_x * m_yaw->value; //mouse speed
}
#endif
Joy_FinalizeMove( &forward, &side, &yaw, &pitch );
IN_TouchMove( &forward, &side, &yaw, &pitch );
#ifdef USE_EVDEV
IN_EvdevMove( &yaw, &pitch );
#endif
if( look_filter->value )
{
pitch = ( inputstate.lastpitch + pitch ) / 2;
yaw = ( inputstate.lastyaw + yaw ) / 2;
inputstate.lastpitch = pitch;
inputstate.lastyaw = yaw;
}
IN_CollectInput( &forward, &side, &pitch, &yaw, in_mouseinitialized, true );
if( cls.key_dest == key_game )
{

View file

@ -87,7 +87,6 @@ enum
JOY_HAT_LEFTUP = JOY_HAT_LEFT | JOY_HAT_UP,
JOY_HAT_LEFTDOWN = JOY_HAT_LEFT | JOY_HAT_DOWN
};
extern convar_t *joy_found;
qboolean Joy_IsActive( void );
void Joy_HatMotionEvent( int id, byte hat, byte value );

View file

@ -17,13 +17,12 @@ GNU General Public License for more details.
#include "input.h"
#include "client.h"
#include "vgui_draw.h"
#ifdef XASH_SDL
#include "platform/sdl/events.h"
#endif // XASH_SDL
#include "platform/platform.h"
typedef struct
{
qboolean down;
qboolean gamedown;
int repeats; // if > 1, it is autorepeating
const char *binding;
} enginekey_t;
@ -52,6 +51,7 @@ keyname_t keynames[] =
{"CTRL", K_CTRL, "+attack" },
{"SHIFT", K_SHIFT, "+speed" },
{"CAPSLOCK", K_CAPSLOCK, "" },
{"SCROLLOCK", K_SCROLLOCK, "" },
{"F1", K_F1, "cmd help" },
{"F2", K_F2, "menu_savegame" },
{"F3", K_F3, "menu_loadgame" },
@ -205,7 +205,7 @@ const char *Key_KeynumToString( int keynum )
if ( keynum < 0 || keynum > 255 ) return "<OUT OF RANGE>";
// check for printable ascii (don't use quote)
if( keynum > 32 && keynum < 127 && keynum != '"' && keynum != ';' )
if( keynum > 32 && keynum < 127 && keynum != '"' && keynum != ';' && keynum != K_SCROLLOCK )
{
tinystr[0] = keynum;
tinystr[1] = 0;
@ -269,16 +269,27 @@ const char *Key_GetBinding( int keynum )
Key_GetKey
===================
*/
int Key_GetKey( const char *binding )
int Key_GetKey( const char *pBinding )
{
int i;
if( !binding ) return -1;
if( !pBinding ) return -1;
for( i = 0; i < 256; i++ )
{
if( keys[i].binding && !Q_stricmp( binding, keys[i].binding ))
return i;
if( !keys[i].binding )
continue;
if( *keys[i].binding == '+' )
{
if( !Q_strnicmp( keys[i].binding + 1, pBinding, Q_strlen( pBinding )))
return i;
}
else
{
if( !Q_strnicmp( keys[i].binding, pBinding, Q_strlen( pBinding )))
return i;
}
}
return -1;
@ -411,8 +422,10 @@ void Key_WriteBindings( file_t *f )
for( i = 0; i < 256; i++ )
{
if( keys[i].binding && keys[i].binding[0] )
FS_Printf( f, "bind %s \"%s\"\n", Key_KeynumToString( i ), keys[i].binding );
if( !COM_CheckString( keys[i].binding ))
continue;
FS_Printf( f, "bind %s \"%s\"\n", Key_KeynumToString( i ), keys[i].binding );
}
}
@ -428,8 +441,10 @@ void Key_Bindlist_f( void )
for( i = 0; i < 256; i++ )
{
if( keys[i].binding && keys[i].binding[0] )
Con_Printf( "%s \"%s\"\n", Key_KeynumToString( i ), keys[i].binding );
if( !COM_CheckString( keys[i].binding ))
continue;
Con_Printf( "%s \"%s\"\n", Key_KeynumToString( i ), keys[i].binding );
}
}
@ -463,18 +478,17 @@ void Key_Init( void )
/*
===================
Key_AddKeyUpCommands
Key_AddKeyCommands
===================
*/
void Key_AddKeyUpCommands( int key, const char *kb )
void Key_AddKeyCommands( int key, const char *kb, qboolean down )
{
int i;
char button[1024], *buttonPtr;
char button[1024];
char *buttonPtr;
char cmd[1024];
qboolean keyevent;
int i;
if( !kb ) return;
keyevent = false;
buttonPtr = button;
for( i = 0; ; i++ )
@ -485,18 +499,15 @@ void Key_AddKeyUpCommands( int key, const char *kb )
if( button[0] == '+' )
{
// button commands add keynum as a parm
Q_sprintf( cmd, "-%s %i\n", button+1, key );
if( down ) Q_sprintf( cmd, "%s %i\n", button, key );
else Q_sprintf( cmd, "-%s %i\n", button + 1, key );
Cbuf_AddText( cmd );
keyevent = true;
}
else
else if( down )
{
if( keyevent )
{
// down-only command
Cbuf_AddText( button );
Cbuf_AddText( "\n" );
}
// down-only command
Cbuf_AddText( button );
Cbuf_AddText( "\n" );
}
buttonPtr = button;
@ -509,6 +520,29 @@ void Key_AddKeyUpCommands( int key, const char *kb )
}
}
/*
===================
Key_IsAllowedAutoRepeat
List of keys that allows auto-repeat
===================
*/
qboolean Key_IsAllowedAutoRepeat( int key )
{
switch( key )
{
case K_BACKSPACE:
case K_PAUSE:
case K_PGUP:
case K_KP_PGUP:
case K_PGDN:
case K_KP_PGDN:
return true;
default:
return false;
}
}
/*
===================
Key_Event
@ -519,30 +553,58 @@ Called by the system for both key up and key down events
void Key_Event( int key, int down )
{
const char *kb;
char cmd[1024];
// key was pressed before engine was run
if( !keys[key].down && !down )
return;
// update auto-repeat status and BUTTON_ANY status
kb = keys[key].binding;
keys[key].down = down;
#ifdef HACKS_RELATED_HLMODS
if(( cls.key_dest == key_game ) && ( cls.state == ca_cinematic ) && ( key != K_ESCAPE || !down ))
{
// only escape passed when cinematic is playing
// HLFX 0.6 bug: crash in vgui3.dll while press +attack during movie playback
return;
}
#endif
// distribute the key down event to the apropriate handler
if( cls.key_dest == key_game && ( down || keys[key].gamedown ))
{
if( !clgame.dllFuncs.pfnKey_Event( down, key, keys[key].binding ))
{
if( keys[key].repeats == 0 && down )
{
keys[key].gamedown = true;
}
if( !down )
{
keys[key].gamedown = false;
keys[key].repeats = 0;
}
return; // handled in client.dll
}
}
// update auto-repeat status
if( down )
{
keys[key].repeats++;
if( key != K_BACKSPACE && key != K_PAUSE && keys[key].repeats > 1 )
if( !Key_IsAllowedAutoRepeat( key ) && keys[key].repeats > 1 )
{
if( cls.key_dest == key_game )
{
// ignore most autorepeats
return;
}
// ignore most autorepeats
return;
}
if( key >= 200 && !kb )
Con_Printf( "%s is unbound.\n", Key_KeynumToString( key ));
}
else
{
keys[key].gamedown = false;
keys[key].repeats = 0;
}
@ -565,13 +627,13 @@ void Key_Event( int key, int down )
switch( cls.key_dest )
{
case key_game:
if( gl_showtextures->value )
if( CVAR_TO_BOOL( gl_showtextures ))
{
// close texture atlas
Cvar_SetValue( "r_showtextures", 0.0f );
return;
}
if( host.mouse_visible && cls.state != ca_cinematic )
else if( host.mouse_visible && cls.state != ca_cinematic )
{
clgame.dllFuncs.pfnKey_Event( down, key, keys[key].binding );
return; // handled in client.dll
@ -588,9 +650,7 @@ void Key_Event( int key, int down )
case key_menu:
UI_KeyEvent( key, true );
return;
default:
MsgDev( D_ERROR, "Key_Event: bad cls.key_dest\n" );
return;
default: return;
}
}
@ -618,72 +678,14 @@ void Key_Event( int key, int down )
// an action started before a mode switch.
if( !down )
{
kb = keys[key].binding;
if( cls.key_dest == key_game && ( key != K_ESCAPE ))
clgame.dllFuncs.pfnKey_Event( down, key, kb );
Key_AddKeyUpCommands( key, kb );
Key_AddKeyCommands( key, kb, down );
return;
}
// distribute the key down event to the apropriate handler
if( cls.key_dest == key_game )
{
if( cls.state == ca_cinematic && ( key != K_ESCAPE || !down ))
{
// only escape passed when cinematic is playing
// HLFX 0.6 bug: crash in vgui3.dll while press +attack during movie playback
return;
}
// send the bound action
kb = keys[key].binding;
if( !clgame.dllFuncs.pfnKey_Event( down, key, keys[key].binding ))
{
// handled in client.dll
}
else if( kb != NULL )
{
if( kb[0] == '+' )
{
int i;
char button[1024], *buttonPtr;
for( i = 0, buttonPtr = button; ; i++ )
{
if( kb[i] == ';' || !kb[i] )
{
*buttonPtr = '\0';
if( button[0] == '+' )
{
Q_sprintf( cmd, "%s %i\n", button, key );
Cbuf_AddText( cmd );
}
else
{
// down-only command
Cbuf_AddText( button );
Cbuf_AddText( "\n" );
}
buttonPtr = button;
while (( kb[i] <= ' ' || kb[i] == ';' ) && kb[i] != 0 )
i++;
}
*buttonPtr++ = kb[i];
if( !kb[i] ) break;
}
}
else
{
// down-only command
Cbuf_AddText( kb );
Cbuf_AddText( "\n" );
}
}
Key_AddKeyCommands( key, kb, down );
}
else if( cls.key_dest == key_console )
{
@ -703,20 +705,10 @@ Key_EnableTextInput
*/
void Key_EnableTextInput( qboolean enable, qboolean force )
{
void (*pfnEnableTextInput)( qboolean enable );
#if XASH_INPUT == INPUT_SDL
pfnEnableTextInput = SDLash_EnableTextInput;
#elif XASH_INPUT == INPUT_ANDROID
pfnEnableTextInput = Android_EnableTextInput;
#else
#error "Here must be a text input for your platform"
return;
#endif
if( enable && ( !host.textmode || force ) )
pfnEnableTextInput( true );
Platform_EnableTextInput( true );
else if( !enable )
pfnEnableTextInput( false );
Platform_EnableTextInput( false );
if( !force )
host.textmode = enable;
@ -774,6 +766,7 @@ void Key_ClearStates( void )
keys[i].down = 0;
keys[i].repeats = 0;
keys[i].gamedown = 0;
}
if( clgame.hInstance )

View file

@ -0,0 +1,778 @@
/*
mod_bmodel.c - loading & handling world and brushmodels
Copyright (C) 2016 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "mod_local.h"
#include "mathlib.h"
#include "world.h"
#include "gl_local.h"
#include "client.h"
#define MAX_CLIPNODE_DEPTH 256 // should never exceeds
#define list_entry( ptr, type, member ) \
((type *)((char *)(ptr) - (size_t)(&((type *)0)->member)))
// iterate over each entry in the list
#define list_for_each_entry( pos, head, member ) \
for( pos = list_entry( (head)->next, winding_t, member ); \
&pos->member != (head); \
pos = list_entry( pos->member.next, winding_t, member ))
// iterate over the list, safe for removal of entries
#define list_for_each_entry_safe( pos, n, head, member ) \
for( pos = list_entry( (head)->next, winding_t, member ), \
n = list_entry( pos->member.next, winding_t, member ); \
&pos->member != (head); \
pos = n, n = list_entry( n->member.next, winding_t, member ))
#define LIST_HEAD_INIT( name ) { &(name), &(name) }
_inline void list_add__( hullnode_t *new, hullnode_t *prev, hullnode_t *next )
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
// add the new entry after the give list entry
_inline void list_add( hullnode_t *newobj, hullnode_t *head )
{
list_add__( newobj, head, head->next );
}
// add the new entry before the given list entry (list is circular)
_inline void list_add_tail( hullnode_t *newobj, hullnode_t *head )
{
list_add__( newobj, head->prev, head );
}
_inline void list_del( hullnode_t *entry )
{
entry->next->prev = entry->prev;
entry->prev->next = entry->next;
}
static winding_t * winding_alloc( uint numpoints )
{
return (winding_t *)malloc( (int)((winding_t *)0)->p[numpoints] );
}
static void free_winding( winding_t *w )
{
// simple sentinel by Carmack
if( *(unsigned *)w == 0xDEADC0DE )
Host_Error( "free_winding: freed a freed winding\n" );
*(unsigned *)w = 0xDEADC0DE;
free( w );
}
static winding_t *winding_copy( winding_t *w )
{
winding_t *neww;
neww = winding_alloc( w->numpoints );
memcpy( neww, w, (int)((winding_t *)0)->p[w->numpoints] );
return neww;
}
static void winding_reverse( winding_t *w )
{
vec3_t point;
int i;
for( i = 0; i < w->numpoints / 2; i++ )
{
VectorCopy( w->p[i], point );
VectorCopy( w->p[w->numpoints - i - 1], w->p[i] );
VectorCopy( point, w->p[w->numpoints - i - 1] );
}
}
/*
* winding_shrink
*
* Takes an over-allocated winding and allocates a new winding with just the
* required number of points. The input winding is freed.
*/
static winding_t *winding_shrink( winding_t *w )
{
winding_t *neww = winding_alloc( w->numpoints );
memcpy( neww, w, (int)((winding_t *)0)->p[w->numpoints] );
free_winding( w );
return neww;
}
/*
====================
winding_for_plane
====================
*/
static winding_t *winding_for_plane( const mplane_t *p )
{
vec3_t org, vright, vup;
int i, axis;
vec_t max, v;
winding_t *w;
// find the major axis
max = -BOGUS_RANGE;
axis = -1;
for( i = 0; i < 3; i++ )
{
v = fabs( p->normal[i] );
if( v > max )
{
axis = i;
max = v;
}
}
VectorClear( vup );
switch( axis )
{
case 0:
case 1:
vup[2] = 1;
break;
case 2:
vup[0] = 1;
break;
default:
Host_Error( "BaseWindingForPlane: no axis found\n" );
return NULL;
}
v = DotProduct( vup, p->normal );
VectorMA( vup, -v, p->normal, vup );
VectorNormalize( vup );
VectorScale( p->normal, p->dist, org );
CrossProduct( vup, p->normal, vright );
VectorScale( vup, BOGUS_RANGE, vup );
VectorScale( vright, BOGUS_RANGE, vright );
// project a really big axis aligned box onto the plane
w = winding_alloc( 4 );
memset( w->p, 0, sizeof( vec3_t ) * 4 );
w->numpoints = 4;
w->plane = p;
VectorSubtract( org, vright, w->p[0] );
VectorAdd( w->p[0], vup, w->p[0] );
VectorAdd( org, vright, w->p[1] );
VectorAdd( w->p[1], vup, w->p[1] );
VectorAdd( org, vright, w->p[2] );
VectorSubtract( w->p[2], vup, w->p[2] );
VectorSubtract( org, vright, w->p[3] );
VectorSubtract( w->p[3], vup, w->p[3] );
return w;
}
/*
* ===========================
* Helper for for the clipping functions
* (winding_clip, winding_split)
* ===========================
*/
static void CalcSides( const winding_t *in, const mplane_t *split, int *sides, vec_t *dists, int counts[3], vec_t epsilon )
{
const vec_t *p;
int i;
counts[0] = counts[1] = counts[2] = 0;
switch( split->type )
{
case PLANE_X:
case PLANE_Y:
case PLANE_Z:
p = in->p[0] + split->type;
for( i = 0; i < in->numpoints; i++, p += 3 )
{
const vec_t dot = *p - split->dist;
dists[i] = dot;
if( dot > epsilon )
sides[i] = SIDE_FRONT;
else if( dot < -epsilon )
sides[i] = SIDE_BACK;
else sides[i] = SIDE_ON;
counts[sides[i]]++;
}
break;
default:
p = in->p[0];
for( i = 0; i < in->numpoints; i++, p += 3 )
{
const vec_t dot = DotProduct( split->normal, p ) - split->dist;
dists[i] = dot;
if( dot > epsilon )
sides[i] = SIDE_FRONT;
else if( dot < -epsilon )
sides[i] = SIDE_BACK;
else sides[i] = SIDE_ON;
counts[sides[i]]++;
}
break;
}
sides[i] = sides[0];
dists[i] = dists[0];
}
static void PushToPlaneAxis( vec_t *v, const mplane_t *p )
{
const int t = p->type % 3;
v[t] = (p->dist - p->normal[(t + 1) % 3] * v[(t + 1) % 3] - p->normal[(t + 2) % 3] * v[(t + 2) % 3]) / p->normal[t];
}
/*
==================
winding_clip
Clips the winding to the plane, returning the new winding on 'side'.
Frees the input winding.
If keepon is true, an exactly on-plane winding will be saved, otherwise
it will be clipped away.
==================
*/
static winding_t *winding_clip( winding_t *in, const mplane_t *split, qboolean keepon, int side, vec_t epsilon )
{
vec_t *dists;
int *sides;
int counts[3];
vec_t dot;
int i, j;
winding_t *neww;
vec_t *p1, *p2, *mid;
int maxpts;
dists = (vec_t *)malloc(( in->numpoints + 1 ) * sizeof( vec_t ));
sides = (int *)malloc(( in->numpoints + 1 ) * sizeof( int ));
CalcSides( in, split, sides, dists, counts, epsilon );
if( keepon && !counts[SIDE_FRONT] && !counts[SIDE_BACK] )
{
neww = in;
goto out_free;
}
if( !counts[side] )
{
free_winding( in );
neww = NULL;
goto out_free;
}
if( !counts[side ^ 1] )
{
neww = in;
goto out_free;
}
maxpts = in->numpoints + 4;
neww = winding_alloc( maxpts );
neww->numpoints = 0;
neww->plane = in->plane;
for( i = 0; i < in->numpoints; i++ )
{
p1 = in->p[i];
if( sides[i] == SIDE_ON )
{
VectorCopy( p1, neww->p[neww->numpoints] );
neww->numpoints++;
continue;
}
if( sides[i] == side )
{
VectorCopy( p1, neww->p[neww->numpoints] );
neww->numpoints++;
}
if( sides[i + 1] == SIDE_ON || sides[i + 1] == sides[i] )
continue;
// generate a split point
p2 = in->p[(i + 1) % in->numpoints];
mid = neww->p[neww->numpoints++];
dot = dists[i] / (dists[i] - dists[i + 1]);
for( j = 0; j < 3; j++ )
{
// avoid round off error when possible
if( in->plane->normal[j] == 1.0 )
mid[j] = in->plane->dist;
else if( in->plane->normal[j] == -1.0 )
mid[j] = -in->plane->dist;
else if( split->normal[j] == 1.0 )
mid[j] = split->dist;
else if( split->normal[j] == -1.0 )
mid[j] = -split->dist;
else mid[j] = p1[j] + dot * (p2[j] - p1[j]);
}
if( in->plane->type < 3 )
PushToPlaneAxis( mid, in->plane );
}
// free the original winding
free_winding( in );
// Shrink the winding back to just what it needs...
neww = winding_shrink(neww);
out_free:
free( dists );
free( sides );
return neww;
}
/*
==================
winding_split
Splits a winding by a plane, producing one or two windings. The
original winding is not damaged or freed. If only on one side, the
returned winding will be the input winding. If on both sides, two
new windings will be created.
==================
*/
static void winding_split( winding_t *in, const mplane_t *split, winding_t **pfront, winding_t **pback )
{
vec_t *dists;
int *sides;
int counts[3];
vec_t dot;
int i, j;
winding_t *front, *back;
vec_t *p1, *p2, *mid;
int maxpts;
dists = (vec_t *)malloc(( in->numpoints + 1 ) * sizeof( vec_t ));
sides = (int *)malloc(( in->numpoints + 1 ) * sizeof( int ));
CalcSides(in, split, sides, dists, counts, 0.04f );
if( !counts[0] && !counts[1] )
{
// winding on the split plane - return copies on both sides
*pfront = winding_copy( in );
*pback = winding_copy( in );
goto out_free;
}
if( !counts[0] )
{
*pfront = NULL;
*pback = in;
goto out_free;
}
if( !counts[1] )
{
*pfront = in;
*pback = NULL;
goto out_free;
}
maxpts = in->numpoints + 4;
front = winding_alloc( maxpts );
front->numpoints = 0;
front->plane = in->plane;
back = winding_alloc( maxpts );
back->numpoints = 0;
back->plane = in->plane;
for( i = 0; i < in->numpoints; i++ )
{
p1 = in->p[i];
if( sides[i] == SIDE_ON )
{
VectorCopy( p1, front->p[front->numpoints] );
VectorCopy( p1, back->p[back->numpoints] );
front->numpoints++;
back->numpoints++;
continue;
}
if( sides[i] == SIDE_FRONT )
{
VectorCopy( p1, front->p[front->numpoints] );
front->numpoints++;
}
else if( sides[i] == SIDE_BACK )
{
VectorCopy( p1, back->p[back->numpoints] );
back->numpoints++;
}
if( sides[i + 1] == SIDE_ON || sides[i + 1] == sides[i] )
continue;
// generate a split point
p2 = in->p[(i + 1) % in->numpoints];
mid = front->p[front->numpoints++];
dot = dists[i] / (dists[i] - dists[i + 1]);
for( j = 0; j < 3; j++ )
{
// avoid round off error when possible
if( in->plane->normal[j] == 1.0 )
mid[j] = in->plane->dist;
else if( in->plane->normal[j] == -1.0 )
mid[j] = -in->plane->dist;
else if( split->normal[j] == 1.0 )
mid[j] = split->dist;
else if( split->normal[j] == -1.0 )
mid[j] = -split->dist;
else mid[j] = p1[j] + dot * (p2[j] - p1[j]);
}
if( in->plane->type < 3 )
PushToPlaneAxis( mid, in->plane );
VectorCopy( mid, back->p[back->numpoints] );
back->numpoints++;
}
*pfront = winding_shrink( front );
*pback = winding_shrink( back );
out_free:
free( dists );
free( sides );
}
/* ------------------------------------------------------------------------- */
/*
* This is a stack of the clipnodes we have traversed
* "sides" indicates which side we went down each time
*/
static mclipnode_t *node_stack[MAX_CLIPNODE_DEPTH];
static int side_stack[MAX_CLIPNODE_DEPTH];
static uint node_stack_depth;
static void push_node( mclipnode_t *node, int side )
{
if( node_stack_depth == MAX_CLIPNODE_DEPTH )
Host_Error( "node stack overflow\n" );
node_stack[node_stack_depth] = node;
side_stack[node_stack_depth] = side;
node_stack_depth++;
}
static void pop_node( void )
{
if( !node_stack_depth )
Host_Error( "node stack underflow\n" );
node_stack_depth--;
}
static void free_hull_polys( hullnode_t *hull_polys )
{
winding_t *w, *next;
list_for_each_entry_safe( w, next, hull_polys, chain )
{
list_del( &w->chain );
free_winding( w );
}
}
static void hull_windings_r( hull_t *hull, mclipnode_t *node, hullnode_t *polys, hull_model_t *model );
static void do_hull_recursion( hull_t *hull, mclipnode_t *node, int side, hullnode_t *polys, hull_model_t *model )
{
winding_t *w, *next;
if( node->children[side] >= 0 )
{
mclipnode_t *child = hull->clipnodes + node->children[side];
push_node( node, side );
hull_windings_r( hull, child, polys, model );
pop_node();
}
else
{
switch( node->children[side] )
{
case CONTENTS_EMPTY:
case CONTENTS_WATER:
case CONTENTS_SLIME:
case CONTENTS_LAVA:
list_for_each_entry_safe( w, next, polys, chain )
{
list_del( &w->chain );
list_add( &w->chain, &model->polys );
}
break;
case CONTENTS_SOLID:
case CONTENTS_SKY:
// throw away polys...
list_for_each_entry_safe( w, next, polys, chain )
{
if( w->pair )
w->pair->pair = NULL;
list_del( &w->chain );
free_winding( w );
model->num_polys--;
}
break;
default:
Host_Error( "bad contents: %i\n", node->children[side] );
break;
}
}
}
static void hull_windings_r( hull_t *hull, mclipnode_t *node, hullnode_t *polys, hull_model_t *model )
{
mplane_t *plane = hull->planes + node->planenum;
hullnode_t frontlist = LIST_HEAD_INIT( frontlist );
hullnode_t backlist = LIST_HEAD_INIT( backlist );
winding_t *w, *next, *front, *back;
int i;
list_for_each_entry_safe( w, next, polys, chain )
{
// PARANIOA - PAIR CHECK
ASSERT( !w->pair || w->pair->pair == w );
list_del( &w->chain );
winding_split( w, plane, &front, &back );
if( front ) list_add( &front->chain, &frontlist );
if( back ) list_add( &back->chain, &backlist );
if( front && back )
{
if( w->pair )
{
// split the paired poly, preserve pairing
winding_t *front2, *back2;
winding_split( w->pair, plane, &front2, &back2 );
front2->pair = front;
front->pair = front2;
back2->pair = back;
back->pair = back2;
list_add( &front2->chain, &w->pair->chain );
list_add( &back2->chain, &w->pair->chain );
list_del( &w->pair->chain );
free_winding( w->pair );
model->num_polys++;
}
else
{
front->pair = NULL;
back->pair = NULL;
}
model->num_polys++;
free_winding( w );
}
}
w = winding_for_plane(plane);
for( i = 0; w && i < node_stack_depth; i++ )
{
mplane_t *p = hull->planes + node_stack[i]->planenum;
w = winding_clip( w, p, false, side_stack[i], 0.00001 );
}
if( w )
{
winding_t *tmp = winding_copy( w );
winding_reverse( tmp );
w->pair = tmp;
tmp->pair = w;
list_add( &w->chain, &frontlist );
list_add( &tmp->chain, &backlist );
// PARANIOA - PAIR CHECK
ASSERT( !w->pair || w->pair->pair == w );
model->num_polys += 2;
}
else
{
Con_Printf( S_WARN "new winding was clipped away!\n" );
}
do_hull_recursion( hull, node, 0, &frontlist, model );
do_hull_recursion( hull, node, 1, &backlist, model );
}
static void remove_paired_polys( hull_model_t *model )
{
winding_t *w, *next;
list_for_each_entry_safe( w, next, &model->polys, chain )
{
if( w->pair )
{
list_del( &w->chain );
free_winding( w );
model->num_polys--;
}
}
}
static void make_hull_windings( hull_t *hull, hull_model_t *model )
{
hullnode_t head = LIST_HEAD_INIT( head );
Con_Reportf( "%i clipnodes...\n", hull->lastclipnode - hull->firstclipnode );
node_stack_depth = 0;
model->num_polys = 0;
if( hull->planes != NULL )
{
hull_windings_r( hull, hull->clipnodes + hull->firstclipnode, &head, model );
remove_paired_polys( model );
}
Con_Reportf( "%i hull polys\n", model->num_polys );
}
void Mod_InitDebugHulls( void )
{
int i;
world.hull_models = Mem_Calloc( loadmodel->mempool, sizeof( hull_model_t ) * loadmodel->numsubmodels );
world.num_hull_models = loadmodel->numsubmodels;
// initialize list
for( i = 0; i < world.num_hull_models; i++ )
{
hullnode_t *poly = &world.hull_models[i].polys;
poly->next = poly;
poly->prev = poly;
}
}
void Mod_CreatePolygonsForHull( int hullnum )
{
model_t *mod = cl.worldmodel;
double start, end;
char name[8];
int i;
if( hullnum < 1 || hullnum > 3 )
return;
Con_Printf( "generating polygons for hull %u...\n", hullnum );
start = Sys_DoubleTime();
// rebuild hulls list
for( i = 0; i < world.num_hull_models; i++ )
{
hull_model_t *model = &world.hull_models[i];
free_hull_polys( &model->polys );
make_hull_windings( &mod->hulls[hullnum], model );
Q_snprintf( name, sizeof( name ), "*%i", i + 1 );
mod = Mod_FindName( name, false );
}
end = Sys_DoubleTime();
Con_Printf( "build time %.3f secs\n", end - start );
}
void Mod_ReleaseHullPolygons( void )
{
int i;
// release ploygons
for( i = 0; i < world.num_hull_models; i++ )
{
hull_model_t *model = &world.hull_models[i];
free_hull_polys( &model->polys );
}
world.num_hull_models = 0;
}
void R_DrawWorldHull( void )
{
hull_model_t *hull = &world.hull_models[0];
winding_t *poly;
int i;
if( FBitSet( r_showhull->flags, FCVAR_CHANGED ))
{
int val = bound( 0, (int)r_showhull->value, 3 );
if( val ) Mod_CreatePolygonsForHull( val );
ClearBits( r_showhull->flags, FCVAR_CHANGED );
}
if( !CVAR_TO_BOOL( r_showhull ))
return;
pglDisable( GL_TEXTURE_2D );
list_for_each_entry( poly, &hull->polys, chain )
{
srand((unsigned int)poly);
pglColor3f( rand() % 256 / 255.0, rand() % 256 / 255.0, rand() % 256 / 255.0 );
pglBegin( GL_POLYGON );
for( i = 0; i < poly->numpoints; i++ )
pglVertex3fv( poly->p[i] );
pglEnd();
}
pglEnable( GL_TEXTURE_2D );
}
void R_DrawModelHull( void )
{
hull_model_t *hull;
winding_t *poly;
int i;
if( !CVAR_TO_BOOL( r_showhull ))
return;
if( !RI.currentmodel || RI.currentmodel->name[0] != '*' )
return;
i = atoi( RI.currentmodel->name + 1 );
if( i < 1 || i >= world.num_hull_models )
return;
hull = &world.hull_models[i];
pglPolygonOffset( 1.0f, 2.0 );
pglEnable( GL_POLYGON_OFFSET_FILL );
pglDisable( GL_TEXTURE_2D );
list_for_each_entry( poly, &hull->polys, chain )
{
srand((unsigned int)poly);
pglColor3f( rand() % 256 / 255.0, rand() % 256 / 255.0, rand() % 256 / 255.0 );
pglBegin( GL_POLYGON );
for( i = 0; i < poly->numpoints; i++ )
pglVertex3fv( poly->p[i] );
pglEnd();
}
pglEnable( GL_TEXTURE_2D );
pglDisable( GL_POLYGON_OFFSET_FILL );
}

View file

@ -33,7 +33,7 @@ GNU General Public License for more details.
#define MAXDLY (STEREODLY + 1)
#define MAXLP 10
#define MAXPRESETS ARRAYSIZE( rgsxpre )
#define MAXPRESETS 29
typedef struct sx_preset_s
{
@ -79,7 +79,7 @@ typedef struct dly_s
int *lpdelayline;
} dly_t;
const sx_preset_t rgsxpre[] =
const sx_preset_t rgsxpre[MAXPRESETS] =
{
// -------reverb-------- -------delay--------
// lp mod size refl rvblp delay feedback dlylp left
@ -193,7 +193,7 @@ void SX_Init( void )
sxmod1cur = sxmod1 = 350 * ( idsp_dma_speed / SOUND_11k );
sxmod2cur = sxmod2 = 450 * ( idsp_dma_speed / SOUND_11k );
dsp_off = Cvar_Get( "dsp_off", "0", 0, "disable DSP processing" );
dsp_off = Cvar_Get( "dsp_off", "0", FCVAR_ARCHIVE, "disable DSP processing" );
roomwater_type = Cvar_Get( "waterroom_type", "14", 0, "water room type" );
room_type = Cvar_Get( "room_type", "0", 0, "current room type preset" );
@ -273,7 +273,7 @@ int DLY_Init( int idelay, float delay )
cur = &rgsxdly[idelay];
cur->cdelaysamplesmax = ((int)(delay * idsp_dma_speed) << sxhires) + 1;
cur->lpdelayline = (int *)Z_Malloc( cur->cdelaysamplesmax * sizeof( int ));
cur->lpdelayline = (int *)Z_Calloc( cur->cdelaysamplesmax * sizeof( int ));
cur->xfade = 0;
// init modulation
@ -609,16 +609,15 @@ int RVB_DoReverbForOneDly( dly_t *dly, const int vlr, const portable_samplepair_
if( dly->xfade || delay || samplepair->left || samplepair->right )
{
// modulate delay rate
if( !dly->mod )
if( !dly->xfade && !dly->modcur && dly->mod )
{
dly->idelayoutputxf = dly->idelayoutput + ((COM_RandomLong( 0, 255 ) * delay) >> 9 );
if( dly->idelayoutputxf >= dly->cdelaysamplesmax )
dly->idelayoutputxf -= dly->cdelaysamplesmax;
dly->xfade = REVERB_XFADE;
//dly->xfade = 32;
}
dly->idelayoutputxf %= dly->cdelaysamplesmax;
if( dly->xfade )
{
samplexf = (dly->lpdelayline[dly->idelayoutputxf] * (REVERB_XFADE - dly->xfade)) / REVERB_XFADE;
@ -819,6 +818,9 @@ void CheckNewDspPresets( void )
idsp_room = roomwater_type->value;
else idsp_room = room_type->value;
// don't pass invalid presets
idsp_room = bound( 0, idsp_room, MAXPRESETS - 1 );
if( FBitSet( hisound->flags, FCVAR_CHANGED ))
{
sxhires = hisound->value;

View file

@ -44,7 +44,7 @@ void S_SoundList_f( void )
for( i = 0, sfx = s_knownSfx; i < s_numSfx; i++, sfx++ )
{
if( !sfx->servercount )
if( !sfx->name[0] )
continue;
sc = sfx->cache;
@ -54,7 +54,9 @@ void S_SoundList_f( void )
if( sc->loopStart >= 0 ) Con_Printf( "L" );
else Con_Printf( " " );
Con_Printf( " (%2db) %s : sound/%s\n", sc->width * 8, Q_memprint( sc->size ), sfx->name );
if( sfx->name[0] == '*' )
Con_Printf( " (%2db) %s : %s\n", sc->width * 8, Q_memprint( sc->size ), sfx->name );
else Con_Printf( " (%2db) %s : %s%s\n", sc->width * 8, Q_memprint( sc->size ), DEFAULT_SOUNDPATH, sfx->name );
totalSfx++;
}
}
@ -104,7 +106,7 @@ static wavdata_t *S_CreateDefaultSound( void )
{
wavdata_t *sc;
sc = Mem_Alloc( sndpool, sizeof( wavdata_t ));
sc = Mem_Calloc( sndpool, sizeof( wavdata_t ));
sc->width = 2;
sc->channels = 1;
@ -112,7 +114,7 @@ static wavdata_t *S_CreateDefaultSound( void )
sc->rate = SOUND_DMA_SPEED;
sc->samples = SOUND_DMA_SPEED;
sc->size = sc->samples * sc->width * sc->channels;
sc->buffer = Mem_Alloc( sndpool, sc->size );
sc->buffer = Mem_Calloc( sndpool, sc->size );
return sc;
}
@ -127,8 +129,15 @@ wavdata_t *S_LoadSound( sfx_t *sfx )
wavdata_t *sc = NULL;
if( !sfx ) return NULL;
if( sfx->cache ) return sfx->cache; // see if still in memory
// see if still in memory
if( sfx->cache )
return sfx->cache;
if( !COM_CheckString( sfx->name ))
return NULL;
// load it from disk
if( Q_stricmp( sfx->name, "*default" ))
{
// load it from disk
@ -169,11 +178,8 @@ sfx_t *S_FindName( const char *pname, int *pfInCache )
if( !COM_CheckString( pname ) || !dma.initialized )
return NULL;
if( Q_strlen( pname ) >= MAX_STRING )
{
MsgDev( D_ERROR, "S_FindSound: sound name too long: %s", pname );
if( Q_strlen( pname ) >= sizeof( sfx->name ))
return NULL;
}
Q_strncpy( name, pname, sizeof( name ));
COM_FixSlashes( name );
@ -202,10 +208,7 @@ sfx_t *S_FindName( const char *pname, int *pfInCache )
if( i == s_numSfx )
{
if( s_numSfx == MAX_SFX )
{
MsgDev( D_ERROR, "S_FindName: MAX_SFX limit exceeded\n" );
return NULL;
}
s_numSfx++;
}
@ -233,7 +236,8 @@ void S_FreeSound( sfx_t *sfx )
sfx_t *hashSfx;
sfx_t **prev;
if( !sfx || !sfx->name[0] ) return;
if( !sfx || !sfx->name[0] )
return;
// de-link it from the hash tree
prev = &s_sfxHashList[sfx->hashValue];
@ -251,7 +255,8 @@ void S_FreeSound( sfx_t *sfx )
prev = &hashSfx->hashNext;
}
if( sfx->cache ) FS_FreeSound( sfx->cache );
if( sfx->cache )
FS_FreeSound( sfx->cache );
memset( sfx, 0, sizeof( *sfx ));
}
@ -266,11 +271,6 @@ void S_BeginRegistration( void )
int i;
s_registration_sequence++;
s_registering = true;
// create unused 0-entry
S_RegisterSound( "*default" );
snd_ambient = false;
// check for automatic ambient sounds
@ -279,11 +279,11 @@ void S_BeginRegistration( void )
if( !GI->ambientsound[i][0] )
continue; // empty slot
if( !ambient_sfx[i] )
MsgDev( D_NOTE, "Loading ambient[%i]: ^2%s^7\n", i, GI->ambientsound[i] );
ambient_sfx[i] = S_RegisterSound( GI->ambientsound[i] );
if( ambient_sfx[i] ) snd_ambient = true; // allow auto-ambients
}
s_registering = true;
}
/*
@ -303,7 +303,9 @@ void S_EndRegistration( void )
// free any sounds not from this registration sequence
for( i = 0, sfx = s_knownSfx; i < s_numSfx; i++, sfx++ )
{
if( !sfx->name[0] ) continue;
if( !sfx->name[0] || !Q_stricmp( sfx->name, "*default" ))
continue; // don't release default sound
if( sfx->servercount != s_registration_sequence )
S_FreeSound( sfx ); // don't need this sound
}
@ -311,7 +313,8 @@ void S_EndRegistration( void )
// load everything in
for( i = 0, sfx = s_knownSfx; i < s_numSfx; i++, sfx++ )
{
if( !sfx->name[0] ) continue;
if( !sfx->name[0] )
continue;
S_LoadSound( sfx );
}
s_registering = false;
@ -351,23 +354,35 @@ sound_t S_RegisterSound( const char *name )
sfx_t *S_GetSfxByHandle( sound_t handle )
{
if( handle == -1 || !dma.initialized )
if( !dma.initialized )
return NULL;
// create new sfx
if( handle == SENTENCE_INDEX )
{
// create new sfx
return S_FindName( s_sentenceImmediateName, NULL );
}
if( handle < 0 || handle >= s_numSfx )
{
MsgDev( D_ERROR, "S_GetSfxByHandle: handle %i out of range (%i)\n", handle, s_numSfx );
return NULL;
}
return &s_knownSfx[handle];
}
/*
=================
S_InitSounds
=================
*/
void S_InitSounds( void )
{
// create unused 0-entry
Q_strncpy( s_knownSfx->name, "*default", MAX_QPATH );
s_knownSfx->hashValue = COM_HashKey( s_knownSfx->name, MAX_SFX_HASH );
s_knownSfx->hashNext = s_sfxHashList[s_knownSfx->hashValue];
s_sfxHashList[s_knownSfx->hashValue] = s_knownSfx;
s_knownSfx->cache = S_CreateDefaultSound();
s_numSfx = 1;
}
/*
=================
S_FreeSounds

View file

@ -19,6 +19,7 @@ GNU General Public License for more details.
#include "con_nprint.h"
#include "gl_local.h"
#include "pm_local.h"
#include "platform/platform.h"
#define SND_CLIP_DISTANCE 1000.0f
@ -275,6 +276,28 @@ void SND_ChannelTraceReset( void )
channels[i].bTraced = false;
}
/*
=================
SND_FStreamIsPlaying
Select a channel from the dynamic channel allocation area. For the given entity,
override any other sound playing on the same channel (see code comments below for
exceptions).
=================
*/
qboolean SND_FStreamIsPlaying( sfx_t *sfx )
{
int ch_idx;
for( ch_idx = NUM_AMBIENTS; ch_idx < MAX_DYNAMIC_CHANNELS; ch_idx++ )
{
if( channels[ch_idx].sfx == sfx )
return true;
}
return false;
}
/*
=================
SND_PickDynamicChannel
@ -296,6 +319,13 @@ channel_t *SND_PickDynamicChannel( int entnum, int channel, sfx_t *sfx, qboolean
life_left = 0x7fffffff;
if( ignore ) *ignore = false;
if( channel == CHAN_STREAM && SND_FStreamIsPlaying( sfx ))
{
if( ignore )
*ignore = true;
return NULL;
}
for( ch_idx = NUM_AMBIENTS; ch_idx < MAX_DYNAMIC_CHANNELS; ch_idx++ )
{
channel_t *ch = &channels[ch_idx];
@ -392,7 +422,7 @@ channel_t *SND_PickStaticChannel( const vec3_t pos, sfx_t *sfx )
// no empty slots, alloc a new static sound channel
if( total_channels == MAX_CHANNELS )
{
MsgDev( D_ERROR, "S_PickStaticChannel: no free channels\n" );
Con_DPrintf( S_ERROR "S_PickStaticChannel: no free channels\n" );
return NULL;
}
@ -896,14 +926,11 @@ void S_StartSound( const vec3_t pos, int ent, int chan, sound_t handle, float fv
// and we didn't find it (it's not playing), go ahead and start it up
}
if( pitch == 0 )
{
MsgDev( D_WARN, "S_StartSound: ( %s ) ignored, called with pitch 0\n", sfx->name );
return;
}
if( !pos ) pos = RI.vieworg;
if( chan == CHAN_STREAM )
SetBits( flags, SND_STOP_LOOPING );
// pick a channel to play on
if( chan == CHAN_STATIC ) target_chan = SND_PickStaticChannel( pos, sfx );
else target_chan = SND_PickDynamicChannel( ent, chan, sfx, &bIgnore );
@ -1024,12 +1051,6 @@ void S_RestoreSound( const vec3_t pos, int ent, int chan, sound_t handle, float
vol = bound( 0, fvol * 255, 255 );
if( pitch <= 1 ) pitch = PITCH_NORM; // Invasion issues
if( pitch == 0 )
{
MsgDev( D_WARN, "S_RestoreSound: ( %s ) ignored, called with pitch 0\n", sfx->name );
return;
}
// pick a channel to play on
if( chan == CHAN_STATIC ) target_chan = SND_PickStaticChannel( pos, sfx );
else target_chan = SND_PickDynamicChannel( ent, chan, sfx, &bIgnore );
@ -1158,12 +1179,6 @@ void S_AmbientSound( const vec3_t pos, int ent, sound_t handle, float fvol, floa
if( flags & SND_STOP ) return;
}
if( pitch == 0 )
{
MsgDev( D_WARN, "S_AmbientSound: ( %s ) ignored, called with pitch 0\n", sfx->name );
return;
}
// pick a channel to play on from the static area
ch = SND_PickStaticChannel( pos, sfx );
if( !ch ) return;
@ -1303,7 +1318,7 @@ int S_GetCurrentDynamicSounds( soundlist_t *pout, int size )
looped = ( channels[i].use_loop && channels[i].sfx->cache->loopStart != -1 );
if( channels[i].entchannel == CHAN_STATIC && looped && !FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
if( channels[i].entchannel == CHAN_STATIC && looped && !Host_IsQuakeCompatible())
continue; // never serialize static looped sounds. It will be restoring in game code
if( channels[i].isSentence && channels[i].name[0] )
@ -1380,7 +1395,13 @@ void S_UpdateAmbientSounds( void )
chan = &channels[ambient_channel];
chan->sfx = S_GetSfxByHandle( ambient_sfx[ambient_channel] );
if( !chan->sfx ) continue;
// ambient is unused
if( !chan->sfx )
{
chan->rightvol = 0;
chan->leftvol = 0;
continue;
}
vol = s_ambient_level->value * leaf->ambient_sound_level[ambient_channel];
if( vol < 0 ) vol = 0;
@ -1459,7 +1480,7 @@ rawchan_t *S_FindRawChannel( int entnum, qboolean create )
if( !raw_channels[best] )
{
raw_samples = MAX_RAW_SAMPLES;
raw_channels[best] = Mem_Alloc( sndpool, sizeof( *ch ) + sizeof( portable_samplepair_t ) * ( raw_samples - 1 ));
raw_channels[best] = Mem_Calloc( sndpool, sizeof( *ch ) + sizeof( portable_samplepair_t ) * ( raw_samples - 1 ));
}
ch = raw_channels[best];
@ -1564,7 +1585,7 @@ S_RawSamples
*/
void S_RawSamples( uint samples, uint rate, word width, word channels, const byte *data, int entnum )
{
int snd_vol;
int snd_vol = 128;
if( entnum < 0 ) snd_vol = 256; // bg track or movie track
if( snd_vol < 0 ) snd_vol = 0; // fixup negative values
@ -1577,9 +1598,17 @@ void S_RawSamples( uint samples, uint rate, word width, word channels, const byt
S_PositionedRawSamples
===================
*/
static void S_PositionedRawSamples( int entnum, float fvol, float attn, uint samples, uint rate, word width, word channels, const byte *data )
void S_StreamAviSamples( void *Avi, int entnum, float fvol, float attn, float synctime )
{
rawchan_t *ch;
int bufferSamples;
int fileSamples;
byte raw[MAX_RAW_SAMPLES];
float duration = 0.0f;
int r, fileBytes;
rawchan_t *ch = NULL;
if( !dma.initialized || s_listener.paused || !CL_IsInGame( ))
return;
if( entnum < 0 || entnum >= GI->max_edicts )
return;
@ -1587,9 +1616,61 @@ static void S_PositionedRawSamples( int entnum, float fvol, float attn, uint sam
if( !( ch = S_FindRawChannel( entnum, true )))
return;
if( ch->sound_info.rate == 0 )
{
if( !AVI_GetAudioInfo( Avi, &ch->sound_info ))
return; // no audiotrack
}
ch->master_vol = bound( 0, fvol * 255, 255 );
ch->dist_mult = (attn / SND_CLIP_DISTANCE);
ch->s_rawend = S_RawSamplesStereo( ch->rawsamples, ch->s_rawend, ch->max_samples, samples, rate, width, channels, data );
// see how many samples should be copied into the raw buffer
if( ch->s_rawend < soundtime )
ch->s_rawend = soundtime;
// position is changed, synchronization is lost etc
if( fabs( ch->oldtime - synctime ) > s_mixahead->value )
ch->sound_info.loopStart = AVI_TimeToSoundPosition( Avi, synctime * 1000 );
ch->oldtime = synctime; // keep actual time
while( ch->s_rawend < soundtime + ch->max_samples )
{
wavdata_t *info = &ch->sound_info;
bufferSamples = ch->max_samples - (ch->s_rawend - soundtime);
// decide how much data needs to be read from the file
fileSamples = bufferSamples * ((float)info->rate / SOUND_DMA_SPEED );
if( fileSamples <= 1 ) return; // no more samples need
// our max buffer size
fileBytes = fileSamples * ( info->width * info->channels );
if( fileBytes > sizeof( raw ))
{
fileBytes = sizeof( raw );
fileSamples = fileBytes / ( info->width * info->channels );
}
// read audio stream
r = AVI_GetAudioChunk( Avi, raw, info->loopStart, fileBytes );
info->loopStart += r; // advance play position
if( r < fileBytes )
{
fileBytes = r;
fileSamples = r / ( info->width * info->channels );
}
if( r > 0 )
{
// add to raw buffer
ch->s_rawend = S_RawSamplesStereo( ch->rawsamples, ch->s_rawend, ch->max_samples,
fileSamples, info->rate, info->width, info->channels, raw );
}
else break; // no more samples for this frame
}
}
/*
@ -1665,6 +1746,7 @@ static void S_ClearRawChannels( void )
if( !ch ) continue;
ch->s_rawend = 0;
ch->oldtime = -1;
}
}
@ -1868,6 +1950,23 @@ void S_ExtraUpdate( void )
S_UpdateChannels ();
}
/*
============
S_UpdateFrame
update listener position
============
*/
void S_UpdateFrame( struct ref_viewpass_s *rvp )
{
if( !FBitSet( rvp->flags, RF_DRAW_WORLD ) || FBitSet( rvp->flags, RF_ONLY_CLIENTDRAW ))
return;
VectorCopy( rvp->vieworigin, s_listener.origin );
AngleVectors( rvp->viewangles, s_listener.forward, s_listener.right, s_listener.up );
s_listener.entnum = rvp->viewentity; // can be camera entity too
}
/*
============
SND_UpdateSound
@ -1892,17 +1991,13 @@ void SND_UpdateSound( void )
// release raw-channels that no longer used more than 10 secs
S_FreeIdleRawChannels();
s_listener.entnum = cl.viewentity; // can be camera entity too
VectorCopy( cl.simvel, s_listener.velocity );
s_listener.frametime = (cl.time - cl.oldtime);
s_listener.waterlevel = cl.local.waterlevel;
s_listener.active = CL_IsInGame();
s_listener.inmenu = CL_IsInMenu();
s_listener.paused = cl.paused;
VectorCopy( RI.vieworg, s_listener.origin );
VectorCopy( cl.simvel, s_listener.velocity );
AngleVectors( RI.viewangles, s_listener.forward, s_listener.right, s_listener.up );
if( cl.worldmodel != NULL )
Mod_FatPVS( s_listener.origin, FATPHS_RADIUS, s_listener.pasbytes, world.visbytes, false, !s_phs->value );
@ -1963,7 +2058,7 @@ void SND_UpdateSound( void )
S_SpatializeRawChannels();
// debugging output
if( s_show->value )
if( CVAR_TO_BOOL( s_show ))
{
info.color[0] = 1.0f;
info.color[1] = 0.6f;
@ -2019,6 +2114,23 @@ void S_Play_f( void )
S_StartLocalSound( Cmd_Argv( 1 ), VOL_NORM, false );
}
void S_Play2_f( void )
{
int i = 1;
if( Cmd_Argc() == 1 )
{
Con_Printf( S_USAGE "play2 <soundfile>\n" );
return;
}
while( i < Cmd_Argc( ))
{
S_StartLocalSound( Cmd_Argv( i ), VOL_NORM, true );
i++;
}
}
void S_PlayVol_f( void )
{
if( Cmd_Argc() == 1 )
@ -2162,7 +2274,7 @@ qboolean S_Init( void )
{
if( Sys_CheckParm( "-nosound" ))
{
MsgDev( D_INFO, "Audio: Disabled\n" );
Con_Printf( "Audio: Disabled\n" );
return false;
}
@ -2173,7 +2285,7 @@ qboolean S_Init( void )
s_lerping = Cvar_Get( "s_lerping", "0", FCVAR_ARCHIVE, "apply interpolation to sound output" );
s_ambient_level = Cvar_Get( "ambient_level", "0.3", FCVAR_ARCHIVE, "volume of environment noises (water and wind)" );
s_ambient_fade = Cvar_Get( "ambient_fade", "1000", FCVAR_ARCHIVE, "rate of volume fading when client is moving" );
s_combine_sounds = Cvar_Get( "s_combine_channels", "1", FCVAR_ARCHIVE, "combine channels with same sounds" );
s_combine_sounds = Cvar_Get( "s_combine_channels", "0", FCVAR_ARCHIVE, "combine channels with same sounds" );
snd_foliage_db_loss = Cvar_Get( "snd_foliage_db_loss", "4", 0, "foliage loss factor" );
snd_gain_max = Cvar_Get( "snd_gain_max", "1", 0, "gain maximal threshold" );
snd_gain_min = Cvar_Get( "snd_gain_min", "0.01", 0, "gain minimal threshold" );
@ -2187,6 +2299,7 @@ qboolean S_Init( void )
s_samplecount = Cvar_Get( "s_samplecount", "0", FCVAR_ARCHIVE, "sample count (0 for default value)" );
Cmd_AddCommand( "play", S_Play_f, "playing a specified sound file" );
Cmd_AddCommand( "play2", S_Play2_f, "playing a group of specified sound files" ); // nehahra stuff
Cmd_AddCommand( "playvol", S_PlayVol_f, "playing a specified sound file with specified volume" );
Cmd_AddCommand( "stopsound", S_StopSound_f, "stop all sounds" );
Cmd_AddCommand( "music", S_Music_f, "starting a background track" );
@ -2200,7 +2313,7 @@ qboolean S_Init( void )
if( !SNDDMA_Init( host.hWnd ))
{
MsgDev( D_INFO, "S_Init: sound system can't be initialized\n" );
Con_Printf( "Audio: sound system can't be initialized\n" );
return false;
}
@ -2215,6 +2328,7 @@ qboolean S_Init( void )
SX_Init ();
S_InitScaletable ();
S_StopAllSounds ( true );
S_InitSounds ();
VOX_Init ();
return true;

View file

@ -71,7 +71,7 @@ float S_GetMusicVolume( void )
S_StartBackgroundTrack
=================
*/
void S_StartBackgroundTrack( const char *introTrack, const char *mainTrack, long position, qboolean fullpath )
void S_StartBackgroundTrack( const char *introTrack, const char *mainTrack, int position, qboolean fullpath )
{
S_StopBackgroundTrack();
@ -84,15 +84,16 @@ void S_StartBackgroundTrack( const char *introTrack, const char *mainTrack, long
if( mainTrack && *mainTrack == '*' )
mainTrack = NULL;
if(( !introTrack || !*introTrack ) && ( !mainTrack || !*mainTrack ))
if( !COM_CheckString( introTrack ) && !COM_CheckString( mainTrack ))
return;
if( !introTrack ) introTrack = mainTrack;
if( !*introTrack ) return;
if( !mainTrack || !*mainTrack ) s_bgTrack.loopName[0] = '\0';
if( !COM_CheckString( mainTrack ))
s_bgTrack.loopName[0] = '\0';
else Q_strncpy( s_bgTrack.loopName, mainTrack, sizeof( s_bgTrack.loopName ));
if( fullpath ) Msg( "MP3:Playing: %s\n", introTrack );
// open stream
s_bgTrack.stream = FS_OpenStream( va( "media/%s", introTrack ));
Q_strncpy( s_bgTrack.current, introTrack, sizeof( s_bgTrack.current ));

View file

@ -478,7 +478,7 @@ void VOX_LoadSound( channel_t *pchan, const char *pszin )
if( Q_strlen( psz ) > sizeof( buffer ) - 1 )
{
MsgDev( D_ERROR, "VOX_LoadSound: sentence is too long %s\n", psz );
Con_Printf( S_ERROR "VOX_LoadSound: sentence is too long %s\n", psz );
return;
}
@ -545,7 +545,7 @@ void VOX_ParseLineCommands( char *pSentenceData, int sentenceIndex )
length = pNext - pSentenceData;
if( tempBufferPos + length > sizeof( tempBuffer ))
{
MsgDev( D_ERROR, "sentence too long!\n" );
Con_Printf( S_ERROR "sentence too long!\n" );
return;
}
@ -606,7 +606,7 @@ void VOX_ReadSentenceFile( const char *psentenceFileName )
{
char c, *pch, *pFileData;
char *pchlast, *pSentenceData;
int fileSize;
size_t fileSize;
// load file
pFileData = (char *)FS_LoadFile( psentenceFileName, &fileSize, false );
@ -617,6 +617,12 @@ void VOX_ReadSentenceFile( const char *psentenceFileName )
while( pch < pchlast )
{
if( g_numSentences >= MAX_SENTENCES )
{
Con_Printf( S_ERROR "VOX_Init: too many sentences specified\n" );
break;
}
// only process this pass on sentences
pSentenceData = NULL;

View file

@ -81,6 +81,8 @@ extern byte *sndpool;
#define S_RAW_SOUND_SOUNDTRACK -1
#define S_RAW_SAMPLES_PRECISION_BITS 14
#define CIN_FRAMETIME (1.0f / 30.0f)
typedef struct
{
int left;
@ -164,6 +166,8 @@ typedef struct rawchan_s
vec3_t origin; // only use if fixed_origin is set
float radius; // radius of this sound effect
volatile uint s_rawend;
wavdata_t sound_info; // advance play position
float oldtime; // catch time jumps
size_t max_samples; // buffer length
portable_samplepair_t rawsamples[1]; // variable sized
} rawchan_t;
@ -233,22 +237,6 @@ typedef struct
int source; // may be game, menu, etc
} bg_track_t;
/*
====================================================================
SYSTEM SPECIFIC FUNCTIONS
====================================================================
*/
// initializes cycling through a DMA buffer and returns information on it
qboolean SNDDMA_Init( void *hInst );
int SNDDMA_GetSoundtime( void );
void SNDDMA_Shutdown( void );
void SNDDMA_BeginPainting( void );
void SNDDMA_Submit( void );
void SNDDMA_LockSound( void );
void SNDDMA_UnlockSound( void );
//====================================================================
#define MAX_DYNAMIC_CHANNELS (60 + NUM_AMBIENTS)
@ -275,6 +263,7 @@ extern convar_t *s_lerping;
extern convar_t *dsp_off;
extern convar_t *s_test; // cvar to testify new effects
extern convar_t *s_samplecount;
extern convar_t *snd_mute_losefocus;
void S_InitScaletable( void );
wavdata_t *S_LoadSound( sfx_t *sfx );
@ -301,6 +290,7 @@ char *S_SkipSoundChar( const char *pch );
sfx_t *S_FindName( const char *name, int *pfInCache );
sound_t S_RegisterSound( const char *name );
void S_FreeSound( sfx_t *sfx );
void S_InitSounds( void );
// s_dsp.c
void SX_Init( void );
@ -316,6 +306,7 @@ void S_Activate( qboolean active );
void S_SoundList_f( void );
void S_SoundInfo_f( void );
struct ref_viewpass_s;
channel_t *SND_PickDynamicChannel( int entnum, int channel, sfx_t *sfx, qboolean *ignore );
channel_t *SND_PickStaticChannel( const vec3_t pos, sfx_t *sfx );
int S_GetCurrentStaticSounds( soundlist_t *pout, int size );
@ -324,6 +315,7 @@ sfx_t *S_GetSfxByHandle( sound_t handle );
rawchan_t *S_FindRawChannel( int entnum, qboolean create );
void S_RawSamples( uint samples, uint rate, word width, word channels, const byte *data, int entnum );
void S_StopSound( int entnum, int channel, const char *soundname );
void S_UpdateFrame( struct ref_viewpass_s *rvp );
uint S_GetRawSamplesLength( int entnum );
void S_ClearRawChannel( int entnum );
void S_StopAllSounds( qboolean ambient );

View file

@ -201,7 +201,7 @@ static int ParseDirective( const char *pText )
}
else
{
MsgDev( D_ERROR, "unknown token: %s\n", pText );
Con_DPrintf( S_ERROR "unknown token: %s\n", pText );
}
return 1;
}
@ -249,7 +249,7 @@ void CL_TextMessageParse( byte *pMemFile, int fileSize )
if( IsEndOfText( trim ))
{
MsgDev( D_ERROR, "TextMessage: unexpected '}' found, line %d\n", lineNumber );
Con_Reportf( "TextMessage: unexpected '}' found, line %d\n", lineNumber );
return;
}
Q_strcpy( currentName, trim );
@ -260,9 +260,9 @@ void CL_TextMessageParse( byte *pMemFile, int fileSize )
int length = Q_strlen( currentName );
// save name on name heap
if( lastNamePos + length > 16384 )
if( lastNamePos + length > 32768 )
{
MsgDev( D_ERROR, "TextMessage: error while parsing!\n" );
Con_Reportf( "TextMessage: error while parsing!\n" );
return;
}
@ -285,7 +285,7 @@ void CL_TextMessageParse( byte *pMemFile, int fileSize )
}
if( IsStartOfText( trim ))
{
MsgDev( D_ERROR, "TextMessage: unexpected '{' found, line %d\n", lineNumber );
Con_Reportf( "TextMessage: unexpected '{' found, line %d\n", lineNumber );
return;
}
break;
@ -296,12 +296,12 @@ void CL_TextMessageParse( byte *pMemFile, int fileSize )
if( messageCount >= MAX_MESSAGES )
{
MsgDev( D_WARN, "Too many messages in titles.txt, max is %d\n", MAX_MESSAGES );
Con_Printf( S_WARN "Too many messages in titles.txt, max is %d\n", MAX_MESSAGES );
break;
}
}
MsgDev( D_NOTE, "TextMessage: parsed %d text messages\n", messageCount );
Con_Reportf( "TextMessage: parsed %d text messages\n", messageCount );
nameHeapSize = lastNamePos;
textHeapSize = 0;
@ -317,7 +317,7 @@ void CL_TextMessageParse( byte *pMemFile, int fileSize )
}
// must malloc because we need to be able to clear it after initialization
clgame.titles = (client_textmessage_t *)Mem_Alloc( cls.mempool, textHeapSize + nameHeapSize + messageSize );
clgame.titles = (client_textmessage_t *)Mem_Calloc( cls.mempool, textHeapSize + nameHeapSize + messageSize );
// copy table over
memcpy( clgame.titles, textMessages, messageSize );
@ -325,21 +325,23 @@ void CL_TextMessageParse( byte *pMemFile, int fileSize )
// copy Name heap
pNameHeap = ((char *)clgame.titles) + messageSize;
memcpy( pNameHeap, nameHeap, nameHeapSize );
nameOffset = pNameHeap - clgame.titles[0].pName;
//nameOffset = pNameHeap - clgame.titles[0].pName; //undefined on amd64
// copy text & fixup pointers
pCurrentText = pNameHeap + nameHeapSize;
for( i = 0; i < messageCount; i++ )
{
clgame.titles[i].pName += nameOffset; // adjust name pointer (parallel buffer)
clgame.titles[i].pName = pNameHeap; // adjust name pointer (parallel buffer)
Q_strcpy( pCurrentText, clgame.titles[i].pMessage ); // copy text over
clgame.titles[i].pMessage = pCurrentText;
pNameHeap += Q_strlen( pNameHeap ) + 1;
pCurrentText += Q_strlen( pCurrentText ) + 1;
}
if(( pCurrentText - (char *)clgame.titles ) != ( textHeapSize + nameHeapSize + messageSize ))
MsgDev( D_ERROR, "TextMessage: overflow text message buffer!\n" );
Con_DPrintf( S_ERROR "TextMessage: overflow text message buffer!\n" );
clgame.numTitles = messageCount;
}

View file

@ -28,6 +28,7 @@ GNU General Public License for more details.
#include <SDL_events.h>
static SDL_Cursor* s_pDefaultCursor[20];
#endif
#include "platform/platform.h"
int g_textures[VGUI_MAX_TEXTURES];
int g_textureId = 0;
@ -81,7 +82,7 @@ void GAME_EXPORT VGUI_GetMousePos( int *_x, int *_y )
float yscale = (float)glState.height / (float)clgame.scrInfo.iHeight;
int x, y;
CL_GetMousePosition( &x, &y );
Platform_GetMousePos( &x, &y );
*_x = x / xscale, *_y = y / yscale;
}
@ -246,7 +247,7 @@ void VGui_Startup( int width, int height )
F( &vgui );
vgui.initialized = true;
VGUI_InitCursors();
MsgDev( D_INFO, "vgui_support: found interal client support\n" );
Con_Reportf( "vgui_support: found interal client support\n" );
}
}
#endif // XASH_INTERNAL_GAMELIBS
@ -261,7 +262,7 @@ void VGui_Startup( int width, int height )
Q_strncpy( vguiloader, VGUI_SUPPORT_DLL, 256 );
if( !COM_LoadLibrary( vguilib, false, false ) )
MsgDev( D_WARN, "VGUI preloading failed. Default library will be used! Reason: %s\n", COM_GetLibraryError());
Con_Reportf( S_WARN "VGUI preloading failed. Default library will be used! Reason: %s\n", COM_GetLibraryError());
}
if( Q_strstr( GI->client_lib, ".dll" ) )
@ -280,9 +281,9 @@ void VGui_Startup( int width, int height )
if( !s_pVGuiSupport )
{
if( FS_FileExists( vguiloader, false ) )
MsgDev( D_ERROR, "Failed to load vgui_support library: %s", COM_GetLibraryError() );
Con_Reportf( S_ERROR "Failed to load vgui_support library: %s", COM_GetLibraryError() );
else
MsgDev( D_INFO, "vgui_support: not found\n" );
Con_Reportf( "vgui_support: not found\n" );
}
else
{
@ -294,7 +295,7 @@ void VGui_Startup( int width, int height )
VGUI_InitCursors();
}
else
MsgDev( D_ERROR, "Failed to find vgui_support library entry point!\n" );
Con_Reportf( S_ERROR "Failed to find vgui_support library entry point!\n" );
}
}
@ -552,7 +553,7 @@ void GAME_EXPORT VGUI_DrawShutdown( void )
for( i = 1; i < g_textureId; i++ )
{
GL_FreeImage( va( "*vgui%i", i ));
GL_FreeTexture( g_textures[i] );
}
}
@ -584,7 +585,7 @@ void GAME_EXPORT VGUI_UploadTexture( int id, const char *buffer, int width, int
if( id <= 0 || id >= VGUI_MAX_TEXTURES )
{
MsgDev( D_ERROR, "VGUI_UploadTexture: bad texture %i. Ignored\n", id );
Con_DPrintf( S_ERROR "VGUI_UploadTexture: bad texture %i. Ignored\n", id );
return;
}
@ -598,8 +599,7 @@ void GAME_EXPORT VGUI_UploadTexture( int id, const char *buffer, int width, int
r_image.flags = IMAGE_HAS_COLOR|IMAGE_HAS_ALPHA;
r_image.buffer = (byte *)buffer;
g_textures[id] = GL_LoadTextureInternal( texName, &r_image, TF_IMAGE, false );
g_iBoundTexture = id;
g_textures[id] = GL_LoadTextureInternal( texName, &r_image, TF_IMAGE );
}
/*
@ -616,7 +616,7 @@ void GAME_EXPORT VGUI_CreateTexture( int id, int width, int height )
if( id <= 0 || id >= VGUI_MAX_TEXTURES )
{
MsgDev( D_ERROR, "VGUI_CreateTexture: bad texture %i. Ignored\n", id );
Con_Reportf( S_ERROR "VGUI_CreateTexture: bad texture %i. Ignored\n", id );
return;
}
@ -630,7 +630,7 @@ void GAME_EXPORT VGUI_CreateTexture( int id, int width, int height )
r_image.flags = IMAGE_HAS_ALPHA;
r_image.buffer = NULL;
g_textures[id] = GL_LoadTextureInternal( texName, &r_image, TF_IMAGE|TF_NEAREST, false );
g_textures[id] = GL_LoadTextureInternal( texName, &r_image, TF_IMAGE|TF_NEAREST );
g_iBoundTexture = id;
}
@ -638,7 +638,7 @@ void GAME_EXPORT VGUI_UploadTextureBlock( int id, int drawX, int drawY, const by
{
if( id <= 0 || id >= VGUI_MAX_TEXTURES || g_textures[id] == 0 || g_textures[id] == tr.whiteTexture )
{
MsgDev( D_ERROR, "VGUI_UploadTextureBlock: bad texture %i. Ignored\n", id );
Con_Reportf( S_ERROR "VGUI_UploadTextureBlock: bad texture %i. Ignored\n", id );
return;
}
@ -698,7 +698,7 @@ returns wide and tall for currently binded texture
*/
void GAME_EXPORT VGUI_GetTextureSizes( int *width, int *height )
{
gltexture_t *glt;
gl_texture_t *glt;
int texnum;
if( g_iBoundTexture )

View file

@ -0,0 +1,118 @@
/*
vgui_main.h - vgui main header
Copyright (C) 2011 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#ifndef VGUI_MAIN_H
#define VGUI_MAIN_H
#include<VGUI.h>
#include<VGUI_App.h>
#include<VGUI_Font.h>
#include<VGUI_Panel.h>
#include<VGUI_Cursor.h>
#include<VGUI_SurfaceBase.h>
#include<VGUI_InputSignal.h>
#include<VGUI_MouseCode.h>
#include<VGUI_KeyCode.h>
using namespace vgui;
struct PaintStack
{
Panel *m_pPanel;
int iTranslateX;
int iTranslateY;
int iScissorLeft;
int iScissorRight;
int iScissorTop;
int iScissorBottom;
};
class CEngineSurface : public SurfaceBase
{
private:
void InitVertex( vpoint_t &vertex, int x, int y, float u, float v );
public:
CEngineSurface( Panel *embeddedPanel );
~CEngineSurface();
public:
// not used in engine instance
virtual bool setFullscreenMode( int wide, int tall, int bpp ) { return false; }
virtual void setWindowedMode( void ) { }
virtual void setTitle( const char *title ) { }
virtual void createPopup( Panel* embeddedPanel ) { }
virtual bool isWithin( int x, int y ) { return true; }
void SetupPaintState( const PaintStack *paintState );
#ifdef NEW_VGUI_DLL
virtual void GetMousePos( int &x, int &y ) { }
#endif
virtual bool hasFocus( void ) { return true; }
protected:
virtual int createNewTextureID( void );
virtual void drawSetColor( int r, int g, int b, int a );
virtual void drawSetTextColor( int r, int g, int b, int a );
virtual void drawFilledRect( int x0, int y0, int x1, int y1 );
virtual void drawOutlinedRect( int x0,int y0,int x1,int y1 );
virtual void drawSetTextFont( Font *font );
virtual void drawSetTextPos( int x, int y );
virtual void drawPrintText( const char* text, int textLen );
virtual void drawSetTextureRGBA( int id, const char* rgba, int wide, int tall );
virtual void drawSetTexture( int id );
virtual void drawTexturedRect( int x0, int y0, int x1, int y1 );
virtual void drawPrintChar( int x, int y, int wide, int tall, float s0, float t0, float s1, float t1, int color[4] );
virtual void addCharToBuffer( const vpoint_t *ul, const vpoint_t *lr, int color[4] );
virtual void setCursor( Cursor* cursor );
virtual void pushMakeCurrent( Panel* panel, bool useInsets );
virtual void popMakeCurrent( Panel* panel );
// not used in engine instance
virtual bool createPlat( void ) { return false; }
virtual bool recreateContext( void ) { return false; }
virtual void enableMouseCapture( bool state ) { }
virtual void invalidate( Panel *panel ) { }
virtual void setAsTopMost( bool state ) { }
virtual void applyChanges( void ) { }
virtual void swapBuffers( void ) { }
virtual void flushBuffer( void );
protected:
int _drawTextPos[2];
int _drawColor[4];
int _drawTextColor[4];
int _translateX, _translateY;
int _currentTexture;
Panel *currentPanel;
};
// initialize VGUI::App as external (part of engine)
class CEngineApp : public App
{
public:
virtual void main( int argc, char* argv[] ) { }
virtual void setCursorPos( int x, int y ); // we need to recompute abs position to window
virtual void getCursorPos( int &x,int &y );
protected:
virtual void platTick(void) { }
};
extern Panel *rootPanel;
extern CEngineSurface *engSurface;
extern CEngineApp *engApp;
//
// vgui_input.cpp
//
void VGUI_InitCursors( void );
void VGUI_CursorSelect( Cursor *cursor );
void VGUI_ActivateCurrentCursor( void );
#endif//VGUI_MAIN_H

View file

@ -19,6 +19,7 @@ GNU General Public License for more details.
#include "mod_local.h"
#include "input.h"
#include "vid_common.h"
#include "platform/platform.h"
#define WINDOW_NAME XASH_ENGINE_NAME " Window" // Half-Life
@ -26,8 +27,10 @@ convar_t *gl_extensions;
convar_t *gl_texture_anisotropy;
convar_t *gl_texture_lodbias;
convar_t *gl_texture_nearest;
convar_t *gl_wgl_msaa_samples;
convar_t *gl_lightmap_nearest;
convar_t *gl_keeptjunctions;
convar_t *gl_emboss_scale;
convar_t *gl_showtextures;
convar_t *gl_detailscale;
convar_t *gl_check_errors;
@ -46,6 +49,7 @@ convar_t *window_ypos;
convar_t *r_speeds;
convar_t *r_fullbright;
convar_t *r_norefresh;
convar_t *r_showtree;
convar_t *r_lighting_extended;
convar_t *r_lighting_modulate;
convar_t *r_lighting_ambient;
@ -124,7 +128,7 @@ void GL_CheckExtension( const char *name, const dllfunc_t *funcs, const char *cv
convar_t *parm = NULL;
const char *extensions_string;
MsgDev( D_NOTE, "GL_CheckExtension: %s ", name );
Con_Reportf( "GL_CheckExtension: %s ", name );
GL_SetExtension( r_ext, true );
if( cvarname )
@ -135,7 +139,7 @@ void GL_CheckExtension( const char *name, const dllfunc_t *funcs, const char *cv
if(( parm && !CVAR_TO_BOOL( parm )) || ( !CVAR_TO_BOOL( gl_extensions ) && r_ext != GL_OPENGL_110 ))
{
MsgDev( D_NOTE, "- disabled\n" );
Con_Reportf( "- disabled\n" );
GL_SetExtension( r_ext, false );
return; // nothing to process at
}
@ -145,7 +149,7 @@ void GL_CheckExtension( const char *name, const dllfunc_t *funcs, const char *cv
if(( name[2] == '_' || name[3] == '_' ) && !Q_strstr( extensions_string, name ))
{
GL_SetExtension( r_ext, false ); // update render info
MsgDev( D_NOTE, "- ^1failed\n" );
Con_Reportf( "- ^1failed\n" );
return;
}
@ -161,8 +165,8 @@ void GL_CheckExtension( const char *name, const dllfunc_t *funcs, const char *cv
}
if( GL_Support( r_ext ))
MsgDev( D_NOTE, "- ^2enabled\n" );
else MsgDev( D_NOTE, "- ^1failed\n" );
Con_Reportf( "- ^2enabled\n" );
else Con_Reportf( "- ^1failed\n" );
}
/*
@ -208,7 +212,7 @@ VID_StartupGamma
void VID_StartupGamma( void )
{
BuildGammaTable( vid_gamma->value, vid_brightness->value );
MsgDev( D_NOTE, "VID_StartupGamma: gamma %g brightness %g\n", vid_gamma->value, vid_brightness->value );
Con_Reportf( "VID_StartupGamma: gamma %g brightness %g\n", vid_gamma->value, vid_brightness->value );
ClearBits( vid_brightness->flags, FCVAR_CHANGED );
ClearBits( vid_gamma->flags, FCVAR_CHANGED );
}
@ -233,12 +237,12 @@ R_SaveVideoMode
*/
void R_SaveVideoMode( int w, int h )
{
host.window_center_x = glState.width / 2;
host.window_center_y = glState.height / 2;
glState.width = w;
glState.height = h;
host.window_center_x = w / 2;
host.window_center_y = h / 2;
Cvar_SetValue( "width", w );
Cvar_SetValue( "height", h );
@ -255,10 +259,14 @@ VID_GetModeString
*/
const char *VID_GetModeString( int vid_mode )
{
vidmode_t *vidmode;
if( vid_mode < 0 || vid_mode > R_MaxVideoModes() )
return NULL;
return R_GetVideoMode( vid_mode ).desc;
if( !( vidmode = R_GetVideoMode( vid_mode ) ) )
return NULL;
return vidmode->desc;
}
/*
@ -324,7 +332,7 @@ static void GL_SetDefaults( void )
pglDisable( GL_BLEND );
pglDisable( GL_ALPHA_TEST );
pglDisable( GL_POLYGON_OFFSET_FILL );
pglAlphaFunc( GL_GREATER, 0.0f );
pglAlphaFunc( GL_GREATER, DEFAULT_ALPHATEST );
pglEnable( GL_TEXTURE_2D );
pglShadeModel( GL_SMOOTH );
pglFrontFace( GL_CCW );
@ -389,12 +397,17 @@ static void VID_Mode_f( void )
{
case 2:
{
vidmode_t vidmode;
vidmode_t *vidmode;
vidmode = R_GetVideoMode( Q_atoi( Cmd_Argv( 1 )) );
if( !vidmode )
{
Con_Print( S_ERROR "unable to set mode, backend returned null" );
return;
}
w = vidmode.width;
h = vidmode.height;
w = vidmode->width;
h = vidmode->height;
break;
}
case 3:
@ -404,7 +417,7 @@ static void VID_Mode_f( void )
break;
}
default:
Msg( "Usage: vid_mode <modenum>|<width height>\n" );
Msg( S_USAGE "vid_mode <modenum>|<width height>\n" );
return;
}
@ -426,6 +439,7 @@ void GL_InitCommands( void )
r_speeds = Cvar_Get( "r_speeds", "0", FCVAR_ARCHIVE, "shows renderer speeds" );
r_fullbright = Cvar_Get( "r_fullbright", "0", FCVAR_CHEAT, "disable lightmaps, get fullbright for entities" );
r_norefresh = Cvar_Get( "r_norefresh", "0", 0, "disable 3D rendering (use with caution)" );
r_showtree = Cvar_Get( "r_showtree", "0", FCVAR_ARCHIVE, "build the graph of visible BSP tree" );
r_lighting_extended = Cvar_Get( "r_lighting_extended", "1", FCVAR_ARCHIVE, "allow to get lighting from world and bmodels" );
r_lighting_modulate = Cvar_Get( "r_lighting_modulate", "0.6", FCVAR_ARCHIVE, "lightstyles modulate scale" );
r_lighting_ambient = Cvar_Get( "r_lighting_ambient", "0.3", FCVAR_ARCHIVE, "map ambient lighting scale" );
@ -452,13 +466,15 @@ void GL_InitCommands( void )
gl_texture_anisotropy = Cvar_Get( "gl_anisotropy", "8", FCVAR_ARCHIVE, "textures anisotropic filter" );
gl_texture_lodbias = Cvar_Get( "gl_texture_lodbias", "0.0", FCVAR_ARCHIVE, "LOD bias for mipmapped textures (perfomance|quality)" );
gl_keeptjunctions = Cvar_Get( "gl_keeptjunctions", "1", FCVAR_ARCHIVE, "removing tjuncs causes blinking pixels" );
gl_emboss_scale = Cvar_Get( "gl_emboss_scale", "0", FCVAR_ARCHIVE|FCVAR_LATCH, "fake bumpmapping scale" );
gl_showtextures = Cvar_Get( "r_showtextures", "0", FCVAR_CHEAT, "show all uploaded textures" );
gl_finish = Cvar_Get( "gl_finish", "0", FCVAR_ARCHIVE, "use glFinish instead of glFlush" );
gl_nosort = Cvar_Get( "gl_nosort", "0", FCVAR_ARCHIVE, "disable sorting of translucent surfaces" );
gl_clear = Cvar_Get( "gl_clear", "0", FCVAR_ARCHIVE, "clearing screen after each frame" );
gl_test = Cvar_Get( "gl_test", "0", 0, "engine developer cvar for quick testing new features" );
gl_wireframe = Cvar_Get( "gl_wireframe", "0", FCVAR_ARCHIVE|FCVAR_SPONLY, "show wireframe overlay" );
gl_msaa = Cvar_Get( "gl_msaa", "0", FCVAR_GLCONFIG, "MSAA samples. Use with caution, engine may fail with some values" );
gl_wgl_msaa_samples = Cvar_Get( "gl_wgl_msaa_samples", "0", FCVAR_GLCONFIG, "samples number for multisample anti-aliasing" );
gl_msaa = Cvar_Get( "gl_msaa", "1", FCVAR_ARCHIVE, "enable or disable multisample anti-aliasing" );
gl_stencilbits = Cvar_Get( "gl_stencilbits", "8", FCVAR_GLCONFIG, "pixelformat stencil bits (0 - auto)" );
gl_round_down = Cvar_Get( "gl_round_down", "2", FCVAR_RENDERINFO, "round texture sizes to nearest POT value" );
// these cvar not used by engine but some mods requires this
@ -551,10 +567,10 @@ qboolean R_Init( void )
GL_SetDefaultState();
// create the window and set up the context
if( !R_Init_OpenGL( ))
if( !R_Init_Video( ))
{
GL_RemoveCommands();
R_Free_OpenGL();
R_Free_Video();
Sys_Error( "Can't initialize video subsystem\nProbably driver was not installed" );
return false;
@ -563,7 +579,6 @@ qboolean R_Init( void )
host.renderinfo_changed = false;
r_temppool = Mem_AllocPool( "Render Zone" );
GL_InitExtensions();
GL_SetDefaults();
R_InitImages();
R_SpriteInit();
@ -605,51 +620,51 @@ void R_Shutdown( void )
Mem_FreePool( &r_temppool );
// shut down OS specific OpenGL stuff like contexts, etc.
R_Free_OpenGL();
R_Free_Video();
}
/*
=================
GL_ErrorString
convert errorcode to string
=================
*/
const char *GL_ErrorString( int err )
{
switch( err )
{
case GL_STACK_OVERFLOW:
return "GL_STACK_OVERFLOW";
case GL_STACK_UNDERFLOW:
return "GL_STACK_UNDERFLOW";
case GL_INVALID_ENUM:
return "GL_INVALID_ENUM";
case GL_INVALID_VALUE:
return "GL_INVALID_VALUE";
case GL_INVALID_OPERATION:
return "GL_INVALID_OPERATION";
case GL_OUT_OF_MEMORY:
return "GL_OUT_OF_MEMORY";
default:
return "UNKNOWN ERROR";
}
}
/*
=================
GL_CheckForErrors
obsolete
=================
*/
void GL_CheckForErrors_( const char *filename, const int fileline )
{
int err;
char *str;
if( !gl_check_errors->value )
if( !CVAR_TO_BOOL( gl_check_errors ))
return;
if(( err = pglGetError( )) == GL_NO_ERROR )
return;
switch( err )
{
case GL_STACK_OVERFLOW:
str = "GL_STACK_OVERFLOW";
break;
case GL_STACK_UNDERFLOW:
str = "GL_STACK_UNDERFLOW";
break;
case GL_INVALID_ENUM:
str = "GL_INVALID_ENUM";
break;
case GL_INVALID_VALUE:
str = "GL_INVALID_VALUE";
break;
case GL_INVALID_OPERATION:
str = "GL_INVALID_OPERATION";
break;
case GL_OUT_OF_MEMORY:
str = "GL_OUT_OF_MEMORY";
break;
default:
str = "UNKNOWN ERROR";
break;
}
Con_Printf( S_OPENGL_ERROR "%s (called at %s:%i)\n", str, filename, fileline );
Con_Printf( S_OPENGL_ERROR "%s (called at %s:%i)\n", GL_ErrorString( err ), filename, fileline );
}

View file

@ -2,6 +2,9 @@
#ifndef VID_COMMON
#define VID_COMMON
#define FCONTEXT_CORE_PROFILE BIT( 0 )
#define FCONTEXT_DEBUG_ARB BIT( 1 )
typedef struct vidmode_s
{
const char *desc;
@ -9,14 +12,6 @@ typedef struct vidmode_s
int height;
} vidmode_t;
typedef enum
{
rserr_ok,
rserr_invalid_fullscreen,
rserr_invalid_mode,
rserr_unknown
} rserr_t;
// minimal recommended resolution
#define VID_MIN_WIDTH 640
#define VID_MIN_HEIGHT 480
@ -27,6 +22,7 @@ typedef enum
qboolean VID_SetMode( void );
#define GL_CheckForErrors() GL_CheckForErrors_( __FILE__, __LINE__ )
void GL_CheckForErrors_( const char *filename, const int fileline );
const char *GL_ErrorString( int err );
void GL_UpdateSwapInterval( void );
qboolean GL_Support( int r_ext );
void VID_CheckChanges( void );
@ -39,23 +35,4 @@ void VID_StartupGamma( void );
void GL_CheckExtension( const char *name, const dllfunc_t *funcs, const char *cvarname, int r_ext );
void GL_SetExtension( int r_ext, int enable );
//
// platform-defined calls
//
void GL_InitExtensions( void );
void VID_RestoreScreenResolution( void );
qboolean VID_CreateWindow( int width, int height, qboolean fullscreen );
void VID_DestroyWindow( void );
qboolean R_Init_OpenGL( void );
void R_Free_OpenGL( void );
void *GL_GetProcAddress( const char *name );
qboolean GL_CreateContext( void );
qboolean GL_UpdateContext( void );
qboolean GL_DeleteContext( void );
int R_MaxVideoModes();
vidmode_t R_GetVideoMode( int num );
rserr_t R_ChangeDisplaySettings( int width, int height, qboolean fullscreen );
void R_ChangeDisplaySettingsFast( int width, int height ); // for fast resizing
qboolean VID_SetMode( void );
#endif // VID_COMMON

View file

@ -18,7 +18,7 @@ GNU General Public License for more details.
#define CVOXWORDMAX 64
#define CVOXZEROSCANMAX 255 // scan up to this many samples for next zero crossing
#define MAX_SENTENCES 2048
#define MAX_SENTENCES 4096
#define SENTENCE_INDEX -99999 // unique sentence index
typedef struct voxword_s

287
engine/common/base_cmd.c Normal file
View file

@ -0,0 +1,287 @@
/*
base_cmd.c - command & cvar hashmap. Insipred by Doom III
Copyright (C) 2016 a1batross
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "common.h"
#include "base_cmd.h"
#include "cdll_int.h"
// TODO: use another hash function, as COM_HashKey depends on string length
#define HASH_SIZE 128 // 128 * 4 * 4 == 2048 bytes
static base_command_hashmap_t *hashed_cmds[HASH_SIZE];
/*
============
BaseCmd_FindInBucket
Find base command in bucket
============
*/
base_command_hashmap_t *BaseCmd_FindInBucket( base_command_hashmap_t *bucket, base_command_type_e type, const char *name )
{
base_command_hashmap_t *i = bucket;
for( ; i && ( i->type != type || Q_stricmp( name, i->name ) ); // filter out
i = i->next );
return i;
}
/*
============
BaseCmd_GetBucket
Get bucket which contain basecmd by given name
============
*/
base_command_hashmap_t *BaseCmd_GetBucket( const char *name )
{
return hashed_cmds[ COM_HashKey( name, HASH_SIZE ) ];
}
/*
============
BaseCmd_Find
Find base command in hashmap
============
*/
base_command_t *BaseCmd_Find( base_command_type_e type, const char *name )
{
base_command_hashmap_t *base = BaseCmd_GetBucket( name );
base_command_hashmap_t *found = BaseCmd_FindInBucket( base, type, name );
if( found )
return found->basecmd;
return NULL;
}
/*
============
BaseCmd_Find
Find every type of base command and write into arguments
============
*/
void BaseCmd_FindAll(const char *name, base_command_t **cmd, base_command_t **alias, base_command_t **cvar)
{
base_command_hashmap_t *base = BaseCmd_GetBucket( name );
base_command_hashmap_t *i = base;
ASSERT( cmd && alias && cvar );
*cmd = *alias = *cvar = NULL;
for( ; i; i = i->next )
{
if( !Q_stricmp( i->name, name ) )
{
switch( i->type )
{
case HM_CMD:
*cmd = i->basecmd;
break;
case HM_CMDALIAS:
*alias = i->basecmd;
break;
case HM_CVAR:
*cvar = i->basecmd;
break;
default: break;
}
}
}
}
/*
============
BaseCmd_Insert
Add new typed base command to hashmap
============
*/
void BaseCmd_Insert( base_command_type_e type, base_command_t *basecmd, const char *name )
{
uint hash = COM_HashKey( name, HASH_SIZE );
base_command_hashmap_t *elem;
elem = Z_Malloc( sizeof( base_command_hashmap_t ) );
elem->basecmd = basecmd;
elem->type = type;
elem->name = name;
elem->next = hashed_cmds[hash];
hashed_cmds[hash] = elem;
}
/*
============
BaseCmd_Replace
Used in case, when basecmd has been registered, but gamedll wants to register it's own
============
*/
qboolean BaseCmd_Replace( base_command_type_e type, base_command_t *basecmd, const char *name )
{
base_command_hashmap_t *i = BaseCmd_GetBucket( name );
for( ; i && ( i->type != type || Q_stricmp( name, i->name ) ) ; // filter out
i = i->next );
if( !i )
{
Con_Reportf( S_ERROR "BaseCmd_Replace: couldn't find %s\n", name);
return false;
}
i->basecmd = basecmd;
i->name = name; // may be freed after
return true;
}
/*
============
BaseCmd_Remove
Remove base command from hashmap
============
*/
void BaseCmd_Remove( base_command_type_e type, const char *name )
{
uint hash = COM_HashKey( name, HASH_SIZE );
base_command_hashmap_t *i, *prev;
for( prev = NULL, i = hashed_cmds[hash]; i &&
( Q_strcmp( i->name, name ) || i->type != type); // filter out
prev = i, i = i->next );
if( !i )
{
Con_Reportf( S_ERROR "Couldn't find %s in buckets\n", name );
return;
}
if( prev )
prev->next = i->next;
else
hashed_cmds[hash] = i->next;
Z_Free( i );
}
/*
============
BaseCmd_Init
initialize base command hashmap system
============
*/
void BaseCmd_Init( void )
{
memset( hashed_cmds, 0, sizeof( hashed_cmds ) );
}
/*
============
BaseCmd_Stats_f
============
*/
void BaseCmd_Stats_f( void )
{
int i, minsize = 99999, maxsize = -1, empty = 0;
for( i = 0; i < HASH_SIZE; i++ )
{
base_command_hashmap_t *hm;
int len = 0;
// count bucket length
for( hm = hashed_cmds[i]; hm; hm = hm->next, len++ );
if( len == 0 )
{
empty++;
continue;
}
if( len < minsize )
minsize = len;
if( len > maxsize )
maxsize = len;
}
Con_Printf( "Base command stats:\n");
Con_Printf( "Bucket minimal length: %d\n", minsize );
Con_Printf( "Bucket maximum length: %d\n", maxsize );
Con_Printf( "Empty buckets: %d\n", empty );
}
static void BaseCmd_CheckCvars( const char *key, const char *value, void *buffer, void *ptr )
{
base_command_t *v = BaseCmd_Find( HM_CVAR, key );
qboolean *invalid = ptr;
if( !v )
{
Con_Printf( "Cvar %s is missing in basecmd\n", key );
*invalid = true;
}
}
/*
============
BaseCmd_Stats_f
testing order matches cbuf execute
============
*/
void BaseCmd_Test_f( void )
{
void *cmd;
cmdalias_t *a;
qboolean invalid = false;
// Cmd_LookupCmds don't allows to check alias, so just iterate
for( a = Cmd_AliasGetList(); a; a = a->next )
{
base_command_t *v = BaseCmd_Find( HM_CMDALIAS, a->name );
if( !v )
{
Con_Printf( "Alias %s is missing in basecmd\n", a->name );
invalid = true;
}
}
for( cmd = Cmd_GetFirstFunctionHandle(); cmd;
cmd = Cmd_GetNextFunctionHandle( cmd ) )
{
base_command_t *v = BaseCmd_Find( HM_CMD, Cmd_GetName( cmd ) );
if( !v )
{
Con_Printf( "Command %s is missing in basecmd\n", Cmd_GetName( cmd ) );
invalid = true;
}
}
Cvar_LookupVars( 0, NULL, &invalid, BaseCmd_CheckCvars );
if( !invalid )
{
Con_Printf( "BaseCmd is valid\n" );
}
}

59
engine/common/base_cmd.h Normal file
View file

@ -0,0 +1,59 @@
/*
base_cmd.h - command & cvar hashmap. Insipred by Doom III
Copyright (C) 2016 a1batross
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#pragma once
#ifndef BASE_CMD_H
#define BASE_CMD_H
// TODO: Find cases when command hashmap works incorrect
// and maybe disable it
#define XASH_HASHED_VARS
#ifdef XASH_HASHED_VARS
typedef enum base_command_type
{
HM_DONTCARE = 0,
HM_CVAR,
HM_CMD,
HM_CMDALIAS
} base_command_type_e;
typedef void base_command_t;
typedef struct base_command_hashmap_s
{
base_command_t *basecmd; // base command: cvar, alias or command
const char *name; // key for searching
base_command_type_e type; // type for faster searching
struct base_command_hashmap_s *next;
} base_command_hashmap_t;
void BaseCmd_Init( void );
base_command_hashmap_t *BaseCmd_GetBucket( const char *name );
base_command_hashmap_t *BaseCmd_FindInBucket( base_command_hashmap_t *bucket, base_command_type_e type, const char *name );
base_command_t *BaseCmd_Find( base_command_type_e type, const char *name );
void BaseCmd_FindAll( const char *name,
base_command_t **cmd, base_command_t **alias, base_command_t **cvar );
void BaseCmd_Insert ( base_command_type_e type, base_command_t *basecmd, const char *name );
qboolean BaseCmd_Replace( base_command_type_e type, base_command_t *basecmd, const char *name ); // only if same name
void BaseCmd_Remove ( base_command_type_e type, const char *name );
void BaseCmd_Stats_f( void ); // to be registered later
void BaseCmd_Test_f( void ); // to be registered later
#endif // XASH_HASHED_VARS
#endif // BASE_CMD_H

View file

@ -48,7 +48,7 @@ int Q_buildnum( void )
return b;
#else
return 3847;
return 4260;
#endif
}
@ -133,9 +133,8 @@ const char *Q_buildcommit( void )
{
#ifdef XASH_BUILD_COMMIT
return XASH_BUILD_COMMIT;
#elif defined(XASH_RELEASE) // don't check it elsewhere to avoid random bugs
return "release";
#else
return "notset";
#endif
}

View file

@ -63,7 +63,7 @@ qboolean CSCR_ExpectString( parserstate_t *ps, const char *pExpect, qboolean ski
}
if( skip ) ps->buf = tmp;
if( error ) MsgDev( D_ERROR, "Syntax error in %s: got \"%s\" instead of \"%s\"\n", ps->filename, ps->token, pExpect );
if( error ) Con_DPrintf( S_ERROR "Syntax error in %s: got \"%s\" instead of \"%s\"\n", ps->filename, ps->token, pExpect );
return false;
}
@ -85,7 +85,7 @@ cvartype_t CSCR_ParseType( parserstate_t *ps )
return i;
}
MsgDev( D_ERROR, "Cannot parse %s: Bad type %s\n", ps->filename, ps->token );
Con_DPrintf( S_ERROR "Cannot parse %s: Bad type %s\n", ps->filename, ps->token );
return T_NONE;
}
@ -181,7 +181,7 @@ qboolean CSCR_ParseHeader( parserstate_t *ps )
if( Q_atof( ps->token ) != 1 )
{
MsgDev( D_ERROR, "File %s has wrong version %s!\n", ps->filename, ps->token );
Con_DPrintf( S_ERROR "File %s has wrong version %s!\n", ps->filename, ps->token );
return false;
}
@ -192,7 +192,7 @@ qboolean CSCR_ParseHeader( parserstate_t *ps )
if( Q_stricmp( ps->token, "INFO_OPTIONS") && Q_stricmp( ps->token, "SERVER_OPTIONS" ))
{
MsgDev( D_ERROR, "DESCRIPTION must be INFO_OPTIONS or SERVER_OPTIONS\n");
Con_DPrintf( S_ERROR "DESCRIPTION must be INFO_OPTIONS or SERVER_OPTIONS\n");
return false;
}
@ -223,13 +223,10 @@ int CSCR_WriteGameCVars( file_t *cfg, const char *scriptfilename )
if( !state.buf || !length )
return 0;
MsgDev( D_INFO, "Reading config script file %s\n", scriptfilename );
Con_DPrintf( "Reading config script file %s\n", scriptfilename );
if( !CSCR_ParseHeader( &state ))
{
MsgDev( D_ERROR, "Failed to parse header!\n" );
goto finish;
}
while( !CSCR_ExpectString( &state, "}", false, false ))
{
@ -258,7 +255,7 @@ int CSCR_WriteGameCVars( file_t *cfg, const char *scriptfilename )
}
if( COM_ParseFile( state.buf, state.token ))
MsgDev( D_ERROR, "Got extra tokens!\n" );
Con_DPrintf( S_ERROR "Got extra tokens!\n" );
else success = true;
finish:
if( !success )
@ -266,8 +263,8 @@ finish:
state.token[sizeof( state.token ) - 1] = 0;
if( start && state.buf )
MsgDev( D_ERROR, "Parse error in %s, byte %d, token %s\n", scriptfilename, (int)( state.buf - start ), state.token );
else MsgDev( D_ERROR, "Parse error in %s, token %s\n", scriptfilename, state.token );
Con_DPrintf( S_ERROR "Parse error in %s, byte %d, token %s\n", scriptfilename, (int)( state.buf - start ), state.token );
else Con_DPrintf( S_ERROR "Parse error in %s, token %s\n", scriptfilename, state.token );
}
if( start ) Mem_Free( start );
@ -296,13 +293,10 @@ int CSCR_LoadDefaultCVars( const char *scriptfilename )
if( !state.buf || !length )
return 0;
MsgDev( D_INFO, "Reading config script file %s\n", scriptfilename );
Con_DPrintf( "Reading config script file %s\n", scriptfilename );
if( !CSCR_ParseHeader( &state ))
{
MsgDev( D_ERROR, "Failed to parse header!\n" );
goto finish;
}
while( !CSCR_ExpectString( &state, "}", false, false ))
{
@ -322,15 +316,15 @@ int CSCR_LoadDefaultCVars( const char *scriptfilename )
}
if( COM_ParseFile( state.buf, state.token ))
MsgDev( D_ERROR, "Got extra tokens!\n" );
Con_DPrintf( S_ERROR "Got extra tokens!\n" );
else success = true;
finish:
if( !success )
{
state.token[sizeof( state.token ) - 1] = 0;
if( start && state.buf )
MsgDev( D_ERROR, "Parse error in %s, byte %d, token %s\n", scriptfilename, (int)( state.buf - start ), state.token );
else MsgDev( D_ERROR, "Parse error in %s, token %s\n", scriptfilename, state.token );
Con_DPrintf( S_ERROR "Parse error in %s, byte %d, token %s\n", scriptfilename, (int)( state.buf - start ), state.token );
else Con_DPrintf( S_ERROR "Parse error in %s, token %s\n", scriptfilename, state.token );
}
if( start ) Mem_Free( start );

View file

@ -16,6 +16,7 @@ GNU General Public License for more details.
#include "common.h"
#include "client.h"
#include "server.h"
#include "base_cmd.h"
#define MAX_CMD_BUFFER 32768
#define MAX_CMD_LINE 2048
@ -100,7 +101,7 @@ void Cbuf_AddText( const char *text )
if(( cmd_text.cursize + l ) >= cmd_text.maxsize )
{
MsgDev( D_WARN, "Cbuf_AddText: overflow\n" );
Con_Reportf( S_WARN "Cbuf_AddText: overflow\n" );
}
else
{
@ -122,7 +123,7 @@ void Cbuf_InsertText( const char *text )
if(( cmd_text.cursize + l ) >= cmd_text.maxsize )
{
MsgDev( D_WARN, "Cbuf_InsertText: overflow\n" );
Con_Reportf( S_WARN "Cbuf_InsertText: overflow\n" );
}
else
{
@ -178,7 +179,7 @@ void Cbuf_Execute( void )
if( i >= ( MAX_CMD_LINE - 1 ))
{
MsgDev( D_ERROR, "Cbuf_Execute: command string owerflow\n" );
Con_DPrintf( S_ERROR "Cbuf_Execute: command string owerflow\n" );
line[0] = 0;
}
else
@ -380,6 +381,10 @@ void Cmd_Alias_f( void )
if( prev ) prev->next = a;
else cmd_alias = a;
a->next = cur;
#if defined( XASH_HASHED_VARS )
BaseCmd_Insert( HM_CMDALIAS, a, a->name );
#endif
}
// copy the rest of the command line
@ -425,6 +430,9 @@ static void Cmd_UnAlias_f ( void )
{
if( !Q_strcmp( s, a->name ))
{
#if defined( XASH_HASHED_VARS )
BaseCmd_Remove( HM_CMDALIAS, a->name );
#endif
if( a == cmd_alias )
cmd_alias = a->next;
if( p ) p->next = a->next;
@ -603,32 +611,40 @@ void Cmd_TokenizeString( char *text )
/*
============
Cmd_AddCommand
Cmd_AddCommandEx
============
*/
void Cmd_AddCommand( const char *cmd_name, xcommand_t function, const char *cmd_desc )
static int Cmd_AddCommandEx( const char *funcname, const char *cmd_name, xcommand_t function,
const char *cmd_desc, int iFlags )
{
cmd_t *cmd, *cur, *prev;
if( !COM_CheckString( cmd_name ))
{
Con_Reportf( S_ERROR "Cmd_AddCommand: NULL name\n" );
return 0;
}
// fail if the command is a variable name
if( Cvar_FindVar( cmd_name ))
{
Con_Printf( S_ERROR "Cmd_AddCommand: %s already defined as a var\n", cmd_name );
return;
Con_DPrintf( S_ERROR "Cmd_AddServerCommand: %s already defined as a var\n", cmd_name );
return 0;
}
// fail if the command already exists
if( Cmd_Exists( cmd_name ))
{
Con_Printf( S_ERROR "Cmd_AddCommand: %s already defined\n", cmd_name );
return;
Con_DPrintf( S_ERROR "Cmd_AddServerCommand: %s already defined\n", cmd_name );
return 0;
}
// use a small malloc to avoid zone fragmentation
cmd = Z_Malloc( sizeof( cmd_t ));
cmd = Z_Malloc( sizeof( cmd_t ) );
cmd->name = copystring( cmd_name );
cmd->desc = copystring( cmd_desc );
cmd->function = function;
cmd->flags = iFlags;
// insert it at the right alphanumeric position
for( prev = NULL, cur = cmd_functions; cur && Q_strcmp( cur->name, cmd_name ) < 0; prev = cur, cur = cur->next );
@ -636,6 +652,33 @@ void Cmd_AddCommand( const char *cmd_name, xcommand_t function, const char *cmd_
if( prev ) prev->next = cmd;
else cmd_functions = cmd;
cmd->next = cur;
#if defined(XASH_HASHED_VARS)
BaseCmd_Insert( HM_CMD, cmd, cmd->name );
#endif
return 1;
}
/*
============
Cmd_AddCommand
============
*/
void Cmd_AddCommand( const char *cmd_name, xcommand_t function, const char *cmd_desc )
{
Cmd_AddCommandEx( __FUNCTION__, cmd_name, function, cmd_desc, 0 );
}
/*
============
Cmd_AddRestrictedCommand
============
*/
void Cmd_AddRestrictedCommand( const char *cmd_name, xcommand_t function, const char *cmd_desc )
{
Cmd_AddCommandEx( __FUNCTION__, cmd_name, function, cmd_desc, CMD_LOCALONLY );
}
/*
@ -645,41 +688,7 @@ Cmd_AddServerCommand
*/
void Cmd_AddServerCommand( const char *cmd_name, xcommand_t function )
{
cmd_t *cmd, *cur, *prev;
if( !cmd_name || !*cmd_name )
{
MsgDev( D_ERROR, "Cmd_AddServerCommand: NULL name\n" );
return;
}
// fail if the command is a variable name
if( Cvar_FindVar( cmd_name ))
{
MsgDev( D_ERROR, "Cmd_AddServerCommand: %s already defined as a var\n", cmd_name );
return;
}
// fail if the command already exists
if( Cmd_Exists( cmd_name ))
{
MsgDev( D_ERROR, "Cmd_AddServerCommand: %s already defined\n", cmd_name );
return;
}
// use a small malloc to avoid zone fragmentation
cmd = Z_Malloc( sizeof( cmd_t ));
cmd->name = copystring( cmd_name );
cmd->desc = copystring( "server command" );
cmd->function = function;
cmd->flags = CMD_SERVERDLL;
// insert it at the right alphanumeric position
for( prev = NULL, cur = cmd_functions; cur && Q_strcmp( cur->name, cmd_name ) < 0; prev = cur, cur = cur->next );
if( prev ) prev->next = cmd;
else cmd_functions = cmd;
cmd->next = cur;
Cmd_AddCommandEx( __FUNCTION__, cmd_name, function, "server command", CMD_SERVERDLL );
}
/*
@ -689,43 +698,7 @@ Cmd_AddClientCommand
*/
int Cmd_AddClientCommand( const char *cmd_name, xcommand_t function )
{
cmd_t *cmd, *cur, *prev;
if( !cmd_name || !*cmd_name )
{
MsgDev( D_ERROR, "Cmd_AddClientCommand: NULL name\n" );
return 0;
}
// fail if the command is a variable name
if( Cvar_FindVar( cmd_name ))
{
MsgDev( D_ERROR, "Cmd_AddClientCommand: %s already defined as a var\n", cmd_name );
return 0;
}
// fail if the command already exists
if( Cmd_Exists( cmd_name ))
{
MsgDev( D_ERROR, "Cmd_AddClientCommand: %s already defined\n", cmd_name );
return 0;
}
// use a small malloc to avoid zone fragmentation
cmd = Z_Malloc( sizeof( cmd_t ));
cmd->name = copystring( cmd_name );
cmd->desc = copystring( "client command" );
cmd->function = function;
cmd->flags = CMD_CLIENTDLL;
// insert it at the right alphanumeric position
for( prev = NULL, cur = cmd_functions; cur && Q_strcmp( cur->name, cmd_name ) < 0; prev = cur, cur = cur->next );
if( prev ) prev->next = cmd;
else cmd_functions = cmd;
cmd->next = cur;
return 1;
return Cmd_AddCommandEx( __FUNCTION__, cmd_name, function, "client command", CMD_CLIENTDLL );
}
/*
@ -735,43 +708,7 @@ Cmd_AddGameUICommand
*/
int Cmd_AddGameUICommand( const char *cmd_name, xcommand_t function )
{
cmd_t *cmd, *cur, *prev;
if( !cmd_name || !*cmd_name )
{
MsgDev( D_ERROR, "Cmd_AddGameUICommand: NULL name\n" );
return 0;
}
// fail if the command is a variable name
if( Cvar_FindVar( cmd_name ))
{
MsgDev( D_ERROR, "Cmd_AddGameUICommand: %s already defined as a var\n", cmd_name );
return 0;
}
// fail if the command already exists
if( Cmd_Exists( cmd_name ))
{
MsgDev( D_ERROR, "Cmd_AddGameUICommand: %s already defined\n", cmd_name );
return 0;
}
// use a small malloc to avoid zone fragmentation
cmd = Z_Malloc( sizeof( cmd_t ));
cmd->name = copystring( cmd_name );
cmd->desc = copystring( "GameUI command" );
cmd->function = function;
cmd->flags = CMD_GAMEUIDLL;
// insert it at the right alphanumeric position
for( prev = NULL, cur = cmd_functions; cur && Q_strcmp( cur->name, cmd_name ) < 0; prev = cur, cur = cur->next );
if( prev ) prev->next = cmd;
else cmd_functions = cmd;
cmd->next = cur;
return 1;
return Cmd_AddCommandEx( __FUNCTION__, cmd_name, function, "gameui command", CMD_GAMEUIDLL );
}
/*
@ -794,6 +731,10 @@ void Cmd_RemoveCommand( const char *cmd_name )
if( !Q_strcmp( cmd_name, cmd->name ))
{
#if defined(XASH_HASHED_VARS)
BaseCmd_Remove( HM_CMD, cmd->name );
#endif
*back = cmd->next;
if( cmd->name )
@ -840,6 +781,9 @@ Cmd_Exists
*/
qboolean Cmd_Exists( const char *cmd_name )
{
#if defined(XASH_HASHED_VARS)
return BaseCmd_Find( HM_CMD, cmd_name ) != NULL;
#else
cmd_t *cmd;
for( cmd = cmd_functions; cmd; cmd = cmd->next )
@ -848,6 +792,7 @@ qboolean Cmd_Exists( const char *cmd_name )
return true;
}
return false;
#endif
}
/*
@ -932,8 +877,9 @@ A complete command line has been parsed, so try to execute it
*/
void Cmd_ExecuteString( char *text )
{
cmd_t *cmd;
cmdalias_t *a;
cmd_t *cmd = NULL;
cmdalias_t *a = NULL;
convar_t *cvar = NULL;
char command[MAX_CMD_LINE];
char *pcmd = command;
int len = 0;
@ -988,9 +934,22 @@ void Cmd_ExecuteString( char *text )
if( !Cmd_Argc( )) return; // no tokens
#if defined(XASH_HASHED_VARS)
BaseCmd_FindAll( cmd_argv[0],
(base_command_t**)&cmd,
(base_command_t**)&a,
(base_command_t**)&cvar );
#endif
if( !host.apply_game_config )
{
// check aliases
if( a ) // already found in basecmd
{
Cbuf_InsertText( a->value );
return;
}
for( a = cmd_alias; a; a = a->next )
{
if( !Q_stricmp( cmd_argv[0], a->name ))
@ -1005,6 +964,12 @@ void Cmd_ExecuteString( char *text )
if( !host.apply_game_config || !Q_strcmp( cmd_argv[0], "exec" ))
{
// check functions
if( cmd && cmd->function ) // already found in basecmd
{
cmd->function();
return;
}
for( cmd = cmd_functions; cmd; cmd = cmd->next )
{
if( !Q_stricmp( cmd_argv[0], cmd->name ) && cmd->function )
@ -1016,24 +981,26 @@ void Cmd_ExecuteString( char *text )
}
// check cvars
if( Cvar_Command( )) return;
if( Cvar_Command( cvar )) return;
if( host.apply_game_config )
return; // don't send nothing to server: we is a server!
#ifndef XASH_DEDICATED
// forward the command line to the server, so the entity DLL can parse it
if( host.type == HOST_NORMAL )
{
#ifndef XASH_DEDICATED
if( cls.state >= ca_connected )
{
Cmd_ForwardToServer();
}
else
#endif
if( text[0] != '@' && host.type == HOST_NORMAL )
{
// commands with leading '@' are hidden system commands
Con_Printf( S_WARN "Unknown command \"%s\"\n", text );
}
else
#endif // XASH_DEDICATED
if( text[0] != '@' && Cvar_VariableInteger( "host_gameloaded" ))
{
// commands with leading '@' are hidden system commands
Con_Printf( S_WARN "Unknown command \"%s\"\n", text );
}
}
}
@ -1147,6 +1114,10 @@ void Cmd_Unlink( int group )
continue;
}
#if defined(XASH_HASHED_VARS)
BaseCmd_Remove( HM_CMD, cmd->name );
#endif
*prev = cmd->next;
if( cmd->name ) Mem_Free( cmd->name );
@ -1197,4 +1168,9 @@ void Cmd_Init( void )
Cmd_AddCommand( "unalias", Cmd_UnAlias_f, "remove a script function" );
Cmd_AddCommand( "if", Cmd_If_f, "compare and set condition bits" );
Cmd_AddCommand( "else", Cmd_Else_f, "invert condition bit" );
#if defined(XASH_HASHED_VARS)
Cmd_AddCommand( "basecmd_stats", BaseCmd_Stats_f, "print info about basecmd usage" );
Cmd_AddCommand( "basecmd_test", BaseCmd_Test_f, "test basecmd" );
#endif
}

View file

@ -41,6 +41,10 @@ GNU General Public License for more details.
// debug beams
#define DEFAULT_LASERBEAM_PATH "sprites/laserbeam.spr"
#define DEFAULT_INTERNAL_PALETTE "gfx/palette.lmp"
#define DEFAULT_EXTERNAL_PALETTE "gfx/palette.pal"
// path to folders where placed all sounds
#define DEFAULT_SOUNDPATH "sound/"

View file

@ -40,12 +40,12 @@ void DBG_AssertFunction( qboolean fExpr, const char* szExpr, const char* szFile,
if( fExpr ) return;
if( szMessage != NULL )
MsgDev( at_error, "ASSERT FAILED:\n %s \n(%s@%d)\n%s\n", szExpr, szFile, szLine, szMessage );
else MsgDev( at_error, "ASSERT FAILED:\n %s \n(%s@%d)\n", szExpr, szFile, szLine );
Con_DPrintf( S_ERROR "ASSERT FAILED:\n %s \n(%s@%d)\n%s\n", szExpr, szFile, szLine, szMessage );
else Con_DPrintf( S_ERROR "ASSERT FAILED:\n %s \n(%s@%d)\n", szExpr, szFile, szLine );
}
#endif // DEBUG
static long idum = 0;
static int idum = 0;
#define MAX_RANDOM_RANGE 0x7FFFFFFFUL
#define IA 16807
@ -58,12 +58,12 @@ static long idum = 0;
#define AM (1.0 / IM)
#define RNMX (1.0 - EPS)
static long lran1( void )
static int lran1( void )
{
static long iy = 0;
static long iv[NTAB];
static int iy = 0;
static int iv[NTAB];
int j;
long k;
int k;
if( idum <= 0 || !iy )
{
@ -100,7 +100,7 @@ static float fran1( void )
return temp;
}
void COM_SetRandomSeed( long lSeed )
void COM_SetRandomSeed( int lSeed )
{
if( lSeed ) idum = lSeed;
else idum = -time( NULL );
@ -769,7 +769,7 @@ COM_CheckString
*/
int COM_CheckString( const char *string )
{
if( !string || (byte)*string <= ' ' )
if( !string || !*string )
return 0;
return 1;
}
@ -1009,7 +1009,7 @@ byte* COM_LoadFileForMe( const char *filename, int *pLength )
{
string name;
byte *file, *pfile;
long iLength;
size_t iLength;
if( !COM_CheckString( filename ))
{
@ -1052,11 +1052,11 @@ byte *COM_LoadFile( const char *filename, int usehunk, int *pLength )
/*
=============
COM_LoadFile
COM_SaveFile
=============
*/
int COM_SaveFile( const char *filename, const void *data, long len )
int COM_SaveFile( const char *filename, const void *data, int len )
{
// check for empty filename
if( !COM_CheckString( filename ))
@ -1222,8 +1222,8 @@ int COM_CompareFileTime( const char *filename1, const char *filename2, int *iCom
if( filename1 && filename2 )
{
long ft1 = FS_FileTime( filename1, false );
long ft2 = FS_FileTime( filename2, false );
int ft1 = FS_FileTime( filename1, false );
int ft2 = FS_FileTime( filename2, false );
// one of files is missing
if( ft1 == -1 || ft2 == -1 )

View file

@ -89,7 +89,7 @@ XASH SPECIFIC - sort of hack that works only in Xash3D not in GoldSrc
#define MAX_SERVERINFO_STRING 512 // server handles too many settings. expand to 1024?
#define MAX_LOCALINFO_STRING 32768 // localinfo used on server and not sended to the clients
#define MAX_SYSPATH 1024 // system filepath
#define MAX_PRINT_MSG 8192 // how many symbols can handle single call of Msg or MsgDev
#define MAX_PRINT_MSG 8192 // how many symbols can handle single call of Con_Printf or Con_DPrintf
#define MAX_TOKEN 2048 // parse token length
#define MAX_MODS 512 // environment games that engine can keep visible
#define MAX_USERMSG_LENGTH 2048 // don't modify it's relies on a client-side definitions
@ -103,6 +103,10 @@ XASH SPECIFIC - sort of hack that works only in Xash3D not in GoldSrc
#define FBitSet( iBitVector, bit ) ((iBitVector) & (bit))
#ifndef __cplusplus
#ifdef NULL
#undef NULL
#endif
#define NULL ((void *)0)
#endif
@ -116,6 +120,37 @@ XASH SPECIFIC - sort of hack that works only in Xash3D not in GoldSrc
#define GAME_EXPORT
#endif
#ifdef XASH_BIG_ENDIAN
#define LittleLong(x) (((int)(((x)&255)<<24)) + ((int)((((x)>>8)&255)<<16)) + ((int)(((x)>>16)&255)<<8) + (((x) >> 24)&255))
#define LittleLongSW(x) (x = LittleLong(x) )
#define LittleShort(x) ((short)( (((short)(x) >> 8) & 255) + (((short)(x) & 255) << 8)))
#define LittleShortSW(x) (x = LittleShort(x) )
_inline float LittleFloat( float f )
{
union
{
float f;
unsigned char b[4];
} dat1, dat2;
dat1.f = f;
dat2.b[0] = dat1.b[3];
dat2.b[1] = dat1.b[2];
dat2.b[2] = dat1.b[1];
dat2.b[3] = dat1.b[0];
return dat2.f;
}
#else
#define LittleLong(x) (x)
#define LittleLongSW(x)
#define LittleShort(x) (x)
#define LittleShortSW(x)
#define LittleFloat(x) (x)
#endif
typedef unsigned int dword;
typedef unsigned int uint;
typedef char string[MAX_STRING];
@ -199,10 +234,13 @@ typedef enum
#define MAX_STATIC_ENTITIES 3096 // static entities that moved on the client when level is spawn
// filesystem flags
#define FS_STATIC_PATH 1 // FS_ClearSearchPath will be ignore this path
#define FS_NOWRITE_PATH 2 // default behavior - last added gamedir set as writedir. This flag disables it
#define FS_GAMEDIR_PATH 4 // just a marker for gamedir path
#define FS_CUSTOM_PATH 8 // custom directory
#define FS_STATIC_PATH ( 1U << 0 ) // FS_ClearSearchPath will be ignore this path
#define FS_NOWRITE_PATH ( 1U << 1 ) // default behavior - last added gamedir set as writedir. This flag disables it
#define FS_GAMEDIR_PATH ( 1U << 2 ) // just a marker for gamedir path
#define FS_CUSTOM_PATH ( 1U << 3 ) // custom directory
#define FS_GAMERODIR_PATH ( 1U << 4 ) // caseinsensitive
#define FS_GAMEDIRONLY_SEARCH_FLAGS ( FS_GAMEDIR_PATH | FS_CUSTOM_PATH | FS_GAMERODIR_PATH )
#define GI SI.GameInfo
#define FS_Gamedir() SI.GameInfo->gamefolder
@ -273,9 +311,11 @@ typedef struct gameinfo_s
int gamemode;
qboolean secure; // prevent to console acess
qboolean nomodels; // don't let player to choose model (use player.mdl always)
qboolean noskills; // disable skill menu selection
char sp_entity[32]; // e.g. info_player_start
char mp_entity[32]; // e.g. info_player_deathmatch
char mp_filter[32]; // filtering multiplayer-maps
char ambientsound[NUM_AMBIENTS][MAX_QPATH]; // quake ambient sounds
@ -287,6 +327,8 @@ typedef struct gameinfo_s
char game_dll_linux[64]; // custom path for game.dll
char game_dll_osx[64]; // custom path for game.dll
char client_lib[64]; // custom name of client library
qboolean added;
} gameinfo_t;
typedef enum
@ -364,6 +406,15 @@ typedef enum
#include "net_ws.h"
// console field
typedef struct
{
string buffer;
int cursor;
int scroll;
int widthInChars;
} field_t;
typedef struct host_redirect_s
{
rdtype_t target;
@ -425,6 +476,7 @@ typedef struct
typedef struct host_parm_s
{
HINSTANCE hInst;
HANDLE hMutex;
host_status_t status; // global host state
game_status_t game; // game manager
@ -435,6 +487,7 @@ typedef struct host_parm_s
string finalmsg; // server shutdown final message
string downloadfile; // filename to be downloading
int downloadcount; // how many files remain to downloading
char deferred_cmd[128]; // deferred commands
host_redirect_t rd; // remote console
// command line parms
@ -483,6 +536,7 @@ typedef struct host_parm_s
qboolean renderinfo_changed;
char rootdir[256]; // member root directory
char rodir[256]; // readonly root
char gamefolder[MAX_QPATH]; // it's a default gamefolder
byte *imagepool; // imagelib mempool
byte *soundpool; // soundlib mempool
@ -510,8 +564,8 @@ void FS_Rescan( void );
void FS_Shutdown( void );
void FS_ClearSearchPath( void );
void FS_AllowDirectPaths( qboolean enable );
void FS_AddGameDirectory( const char *dir, int flags );
void FS_AddGameHierarchy( const char *dir, int flags );
void FS_AddGameDirectory( const char *dir, uint flags );
void FS_AddGameHierarchy( const char *dir, uint flags );
void FS_LoadGameInfo( const char *rootfolder );
void COM_FileBase( const char *in, char *out );
const char *COM_FileExtension( const char *in );
@ -522,9 +576,9 @@ const char *FS_GetDiskPath( const char *name, qboolean gamedironly );
const char *COM_FileWithoutPath( const char *in );
byte *W_LoadLump( wfile_t *wad, const char *lumpname, size_t *lumpsizeptr, const char type );
void W_Close( wfile_t *wad );
byte *FS_LoadFile( const char *path, long *filesizeptr, qboolean gamedironly );
byte *FS_LoadDirectFile( const char *path, long *filesizeptr );
qboolean FS_WriteFile( const char *filename, const void *data, long len );
byte *FS_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly );
byte *FS_LoadDirectFile( const char *path, fs_offset_t *filesizeptr );
qboolean FS_WriteFile( const char *filename, const void *data, fs_offset_t len );
qboolean COM_ParseVector( char **pfile, float *v, size_t size );
void COM_NormalizeAngles( vec3_t angles );
int COM_FileSize( const char *filename );
@ -534,14 +588,14 @@ int COM_CheckString( const char *string );
int COM_CompareFileTime( const char *filename1, const char *filename2, int *iCompare );
search_t *FS_Search( const char *pattern, int caseinsensitive, int gamedironly );
file_t *FS_Open( const char *filepath, const char *mode, qboolean gamedironly );
long FS_Write( file_t *file, const void *data, size_t datasize );
long FS_Read( file_t *file, void *buffer, size_t buffersize );
fs_offset_t FS_Write( file_t *file, const void *data, size_t datasize );
fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize );
int FS_VPrintf( file_t *file, const char *format, va_list ap );
int FS_Seek( file_t *file, long offset, int whence );
int FS_Seek( file_t *file, fs_offset_t offset, int whence );
int FS_Gets( file_t *file, byte *string, size_t bufsize );
int FS_Printf( file_t *file, const char *format, ... ) _format( 2 );
long FS_FileSize( const char *filename, qboolean gamedironly );
long FS_FileTime( const char *filename, qboolean gamedironly );
fs_offset_t FS_FileSize( const char *filename, qboolean gamedironly );
int FS_FileTime( const char *filename, qboolean gamedironly );
int FS_Print( file_t *file, const char *msg );
qboolean FS_Rename( const char *oldname, const char *newname );
int FS_FileExists( const char *filename, int gamedironly );
@ -550,11 +604,11 @@ qboolean FS_FileCopy( file_t *pOutput, file_t *pInput, int fileSize );
qboolean FS_Delete( const char *path );
int FS_UnGetc( file_t *file, byte c );
void COM_StripExtension( char *path );
long FS_Tell( file_t *file );
fs_offset_t FS_Tell( file_t *file );
qboolean FS_Eof( file_t *file );
int FS_Close( file_t *file );
int FS_Getc( file_t *file );
long FS_FileLength( file_t *f );
fs_offset_t FS_FileLength( file_t *f );
/*
========================================================================
@ -566,7 +620,7 @@ NOTE: number at end of pixelformat name it's a total bitscount e.g. PF_RGB_24 ==
========================================================================
*/
#define ImageRAW( type ) (type == PF_RGBA_32 || type == PF_BGRA_32 || type == PF_RGB_24 || type == PF_BGR_24)
#define ImageDXT( type ) (type == PF_DXT1 || type == PF_DXT3 || type == PF_DXT5)
#define ImageDXT( type ) (type == PF_DXT1 || type == PF_DXT3 || type == PF_DXT5 || type == PF_ATI2)
typedef enum
{
@ -580,6 +634,7 @@ typedef enum
PF_DXT1, // s3tc DXT1 format
PF_DXT3, // s3tc DXT3 format
PF_DXT5, // s3tc DXT5 format
PF_ATI2, // latc ATI2N format
PF_TOTALCOUNT, // must be last
} pixformat_t;
@ -637,7 +692,7 @@ typedef enum
IMAGE_ROT_90 = BIT(18), // flip from upper left corner to down right corner
IMAGE_ROT180 = IMAGE_FLIP_X|IMAGE_FLIP_Y,
IMAGE_ROT270 = IMAGE_FLIP_X|IMAGE_FLIP_Y|IMAGE_ROT_90,
// reserved
IMAGE_EMBOSS = BIT(19), // apply emboss mapping
IMAGE_RESAMPLE = BIT(20), // resample image to specified dims
// reserved
// reserved
@ -648,16 +703,6 @@ typedef enum
IMAGE_REMAP = BIT(27), // interpret width and height as top and bottom color
} imgFlags_t;
// ordering is important!
typedef enum
{
BLUR_FILTER = 0,
BLUR_FILTER2,
EDGE_FILTER,
EMBOSS_FILTER,
NUM_FILTERS,
} pixfilter_t;
typedef struct rgbdata_s
{
word width; // image width
@ -673,21 +718,6 @@ typedef struct rgbdata_s
size_t size; // for bounds checking
} rgbdata_t;
// imgfilter processing flags
typedef enum
{
FILTER_GRAYSCALE = BIT(0),
} flFlags_t;
typedef struct imgfilter_s
{
int filter; // pixfilter_t
float factor; // filter factor value
float bias; // filter bias value
flFlags_t flags; // filter additional flags
uint blendFunc; // blending mode
} imgfilter_t;
//
// imagelib
//
@ -699,12 +729,15 @@ qboolean FS_SaveImage( const char *filename, rgbdata_t *pix );
rgbdata_t *FS_CopyImage( rgbdata_t *in );
void FS_FreeImage( rgbdata_t *pack );
extern const bpc_desc_t PFDesc[]; // image get pixelformat
qboolean Image_Process( rgbdata_t **pix, int width, int height, uint flags, imgfilter_t *filter );
qboolean Image_Process( rgbdata_t **pix, int width, int height, uint flags, float bumpscale );
void Image_PaletteHueReplace( byte *palSrc, int newHue, int start, int end, int pal_size );
void Image_PaletteTranslate( byte *palSrc, int top, int bottom, int pal_size );
void Image_SetForceFlags( uint flags ); // set image force flags on loading
size_t Image_DXTGetLinearSize( int type, int width, int height, int depth );
qboolean Image_CustomPalette( void );
void Image_ClearForceFlags( void );
void Image_SetMDLPointer( byte *p );
void Image_CheckPaletteQ1( void );
/*
========================================================================
@ -764,9 +797,9 @@ wavdata_t *FS_LoadSound( const char *filename, const byte *buffer, size_t size )
void FS_FreeSound( wavdata_t *pack );
stream_t *FS_OpenStream( const char *filename );
wavdata_t *FS_StreamInfo( stream_t *stream );
long FS_ReadStream( stream_t *stream, int bytes, void *buffer );
long FS_SetStreamPos( stream_t *stream, long newpos );
long FS_GetStreamPos( stream_t *stream );
int FS_ReadStream( stream_t *stream, int bytes, void *buffer );
int FS_SetStreamPos( stream_t *stream, int newpos );
int FS_GetStreamPos( stream_t *stream );
void FS_FreeStream( stream_t *stream );
qboolean Sound_Process( wavdata_t **wav, int rate, int width, uint flags );
uint Sound_GetApproxWavePlayLen( const char *filepath );
@ -783,8 +816,9 @@ const char *Q_buildcommit( void );
//
// host.c
//
qboolean Host_IsQuakeCompatible( void );
void EXPORT Host_Shutdown( void );
int Host_CompareFileTime( long ft1, long ft2 );
int Host_CompareFileTime( int ft1, int ft2 );
void Host_NewInstance( const char *name, const char *finalmsg );
void Host_EndGame( qboolean abort, const char *message, ... ) _format( 2 );
void Host_AbortCurrentFrame( void );
@ -842,7 +876,7 @@ cvar_t *pfnCvar_RegisterClientVariable( const char *szName, const char *szValue,
cvar_t *pfnCvar_RegisterGameUIVariable( const char *szName, const char *szValue, int flags );
char *COM_MemFgets( byte *pMemFile, int fileSize, int *filePos, char *pBuffer, int bufferSize );
void COM_HexConvert( const char *pszInput, int nInputLength, byte *pOutput );
int COM_SaveFile( const char *filename, const void *data, long len );
int COM_SaveFile( const char *filename, const void *data, int len );
byte* COM_LoadFileForMe( const char *filename, int *pLength );
qboolean COM_IsSafeFileToDownload( const char *filename );
cvar_t *pfnCVarGetPointer( const char *szVarName );
@ -886,10 +920,19 @@ void pfnResetTutorMessageDecayData( void );
==============================================================
*/
#define Z_Malloc( size ) Mem_Alloc( host.mempool, size )
#define Z_Malloc( size ) Mem_Malloc( host.mempool, size )
#define Z_Calloc( size ) Mem_Calloc( host.mempool, size )
#define Z_Realloc( ptr, size ) Mem_Realloc( host.mempool, ptr, size )
#define Z_Free( ptr ) if( ptr != NULL ) Mem_Free( ptr )
//
// con_utils.c
//
qboolean Cmd_AutocompleteName( const char *source, char *buffer, size_t bufsize );
void Con_CompleteCommand( field_t *field );
void Cmd_AutoComplete( char *complete_string );
void Cmd_AutoCompleteClear( void );
//
// crclib.c
//
@ -953,9 +996,9 @@ void Key_EnableTextInput( qboolean enable, qboolean force );
#include "avi/avi.h"
// shared calls
struct physent_s;
typedef struct sv_client_s sv_client_t;
typedef struct sizebuf_s sizebuf_t;
typedef struct physent_s physent_t;
qboolean CL_IsInGame( void );
qboolean CL_IsInMenu( void );
qboolean CL_IsInConsole( void );
@ -963,6 +1006,7 @@ qboolean CL_IsThirdPerson( void );
qboolean CL_IsIntermission( void );
qboolean CL_Initialized( void );
char *CL_Userinfo( void );
void CL_LegacyUpdateInfo( void );
void CL_CharEvent( int key );
qboolean CL_DisableVisibility( void );
int CL_PointContents( const vec3_t point );
@ -977,7 +1021,7 @@ struct cmdalias_s *Cmd_AliasGetList( void );
char *Cmd_GetName( struct cmd_s *cmd );
struct pmtrace_s *PM_TraceLine( float *start, float *end, int flags, int usehull, int ignore_pe );
void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float attn, int flags, int pitch );
void SV_StartMusic( const char *curtrack, const char *looptrack, long position );
void SV_StartMusic( const char *curtrack, const char *looptrack, int position );
void SV_CreateDecal( sizebuf_t *msg, const float *origin, int decalIndex, int entityIndex, int modelIndex, int flags, float scale );
void Log_Printf( const char *fmt, ... ) _format( 1 );
struct sizebuf_s *SV_GetReliableDatagram( void );
@ -998,6 +1042,7 @@ void SV_DrawDebugTriangles( void );
void SV_DrawOrthoTriangles( void );
double CL_GetDemoFramerate( void );
qboolean UI_CreditsActive( void );
void CL_StopPlayback( void );
void CL_ExtraUpdate( void );
int CL_GetMaxClients( void );
int SV_GetMaxClients( void );
@ -1010,8 +1055,8 @@ qboolean SV_Initialized( void );
qboolean CL_LoadProgs( const char *name );
int SV_GetSaveComment( const char *savename, char *comment );
qboolean SV_NewGame( const char *mapName, qboolean loadGame );
void SV_ClipPMoveToEntity( physent_t *pe, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, struct pmtrace_s *tr );
void CL_ClipPMoveToEntity( physent_t *pe, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, struct pmtrace_s *tr );
void SV_ClipPMoveToEntity( struct physent_s *pe, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, struct pmtrace_s *tr );
void CL_ClipPMoveToEntity( struct physent_s *pe, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, struct pmtrace_s *tr );
void CL_Particle( const vec3_t origin, int color, float life, int zpos, int zvel ); // debug thing
void SV_SysError( const char *error_string );
void SV_ShutdownGame( void );
@ -1033,7 +1078,7 @@ void SCR_Init( void );
void SCR_UpdateScreen( void );
void SCR_BeginLoadingPlaque( qboolean is_background );
void SCR_CheckStartupVids( void );
long SCR_GetAudioChunk( char *rawdata, long length );
int SCR_GetAudioChunk( char *rawdata, int length );
wavdata_t *SCR_GetMovieInfo( void );
void SCR_Shutdown( void );
void Con_Print( const char *txt );
@ -1051,9 +1096,7 @@ void Info_WriteVars( file_t *f );
void Info_Print( const char *s );
void Cmd_WriteVariables( file_t *f );
int Cmd_CheckMapsList( int fRefresh );
qboolean Cmd_AutocompleteName( const char *source, char *buffer, size_t bufsize );
void Cmd_AutoComplete( char *complete_string );
void COM_SetRandomSeed( long lSeed );
void COM_SetRandomSeed( int lSeed );
int COM_RandomLong( int lMin, int lMax );
float COM_RandomFloat( float fMin, float fMax );
qboolean LZSS_IsCompressed( const byte *source );
@ -1069,7 +1112,6 @@ void Cmd_Null_f( void );
// soundlib shared exports
qboolean S_Init( void );
void S_Shutdown( void );
void S_Activate( qboolean active );
void S_StopSound( int entnum, int channel, const char *soundname );
int S_GetCurrentStaticSounds( soundlist_t *pout, int size );
void S_StopBackgroundTrack( void );
@ -1095,6 +1137,13 @@ typedef struct sentenceEntry_ sentenceEntry_s;
sequenceEntry_s *Sequence_Get( const char *fileName, const char *entryName );
sentenceEntry_s *Sequence_PickSentence( const char *groupName, int pickMethod, int *picked );
//
// masterlist.c
//
void NET_InitMasters( void );
void NET_SaveMasters( void );
qboolean NET_SendToMasters( netsrc_t sock, size_t len, const void *data );
#ifdef __cplusplus
}
#endif

View file

@ -20,16 +20,32 @@ GNU General Public License for more details.
extern convar_t *con_gamemaps;
#define CON_MAXCMDS 4096 // auto-complete intermediate list
typedef struct autocomplete_list_s
{
const char *name;
qboolean (*func)( const char *s, char *name, int length );
} autocomplete_list_t;
typedef struct
{
// console auto-complete
string shortestMatch;
field_t *completionField; // con.input or dedicated server fake field-line
const char *completionString;
const char *completionBuffer;
char *cmds[CON_MAXCMDS];
int matchCount;
} con_autocomplete_t;
static con_autocomplete_t con;
/*
=======================================================================
FILENAME AUTOCOMPLETION
=======================================================================
*/
/*
@ -102,7 +118,7 @@ qboolean Cmd_GetMapList( const char *s, char *completedname, int length )
if( !ents && lumplen >= 10 )
{
FS_Seek( f, lumpofs, SEEK_SET );
ents = (char *)Mem_Alloc( host.mempool, lumplen + 1 );
ents = (char *)Mem_Calloc( host.mempool, lumplen + 1 );
FS_Read( f, ents, lumplen );
}
@ -191,7 +207,8 @@ qboolean Cmd_GetDemoList( const char *s, char *completedname, int length )
string matchbuf;
int i, numdems;
t = FS_Search( va( "demos/%s*.dem", s ), true, true ); // lookup only in gamedir
// lookup only in gamedir
t = FS_Search( va( "%s*.dem", s ), true, true );
if( !t ) return false;
COM_FileBase( t->filenames[0], matchbuf );
@ -669,7 +686,9 @@ qboolean Cmd_GetCDList( const char *s, char *completedname, int length )
qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
{
qboolean use_filter = false;
byte buf[MAX_SYSPATH];
string mpfilter;
char *buffer;
string result;
int i, size;
@ -677,11 +696,10 @@ qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
file_t *f;
if( FS_FileSize( "maps.lst", onlyingamedir ) > 0 && !fRefresh )
{
MsgDev( D_NOTE, "maps.lst is exist: %s\n", onlyingamedir ? "basedir" : "gamedir" );
return true; // exist
}
// setup mpfilter
Q_snprintf( mpfilter, sizeof( mpfilter ), "maps/%s", GI->mp_filter );
t = FS_Search( "maps/*.bsp", false, onlyingamedir );
if( !t )
@ -694,7 +712,8 @@ qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
return false;
}
buffer = Mem_Alloc( host.mempool, t->numfilenames * 2 * sizeof( result ));
buffer = Mem_Calloc( host.mempool, t->numfilenames * 2 * sizeof( result ));
use_filter = Q_strlen( GI->mp_filter ) ? true : false;
for( i = 0; i < t->numfilenames; i++ )
{
@ -705,6 +724,9 @@ qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
if( Q_stricmp( COM_FileExtension( t->filenames[i] ), "bsp" ))
continue;
if( use_filter && !Q_strnicmp( t->filenames[i], mpfilter, Q_strlen( mpfilter )))
continue;
f = FS_Open( t->filenames[i], "rb", onlyingamedir );
COM_FileBase( t->filenames[i], mapname );
@ -736,7 +758,7 @@ qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
if( !ents && lumplen >= 10 )
{
FS_Seek( f, lumpofs, SEEK_SET );
ents = Z_Malloc( lumplen + 1 );
ents = Z_Calloc( lumplen + 1 );
FS_Read( f, ents, lumplen );
}
@ -762,7 +784,7 @@ qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
else if( !Q_strcmp( token, "classname" ))
{
pfile = COM_ParseFile( pfile, token );
if( !Q_strcmp( token, GI->mp_entity ))
if( !Q_strcmp( token, GI->mp_entity ) || use_filter )
num_spawnpoints++;
}
if( num_spawnpoints ) break; // valid map
@ -810,6 +832,7 @@ int Cmd_CheckMapsList( int fRefresh )
autocomplete_list_t cmd_list[] =
{
{ "map_background", Cmd_GetMapList },
{ "changelevel2", Cmd_GetMapList },
{ "changelevel", Cmd_GetMapList },
{ "playdemo", Cmd_GetDemoList, },
{ "timedemo", Cmd_GetDemoList, },
@ -869,6 +892,268 @@ qboolean Cmd_AutocompleteName( const char *source, char *buffer, size_t bufsize
return false;
}
/*
===============
Con_AddCommandToList
===============
*/
static void Con_AddCommandToList( const char *s, const char *unused1, const char *unused2, void *unused3 )
{
if( *s == '@' ) return; // never show system cvars or cmds
if( con.matchCount >= CON_MAXCMDS ) return; // list is full
if( Q_strnicmp( s, con.completionString, Q_strlen( con.completionString ) ) )
return; // no match
con.cmds[con.matchCount++] = copystring( s );
}
/*
=================
Con_SortCmds
=================
*/
static int Con_SortCmds( const char **arg1, const char **arg2 )
{
return Q_stricmp( *arg1, *arg2 );
}
/*
===============
Con_PrintCmdMatches
===============
*/
static void Con_PrintCmdMatches( const char *s, const char *unused1, const char *m, void *unused2 )
{
if( !Q_strnicmp( s, con.shortestMatch, Q_strlen( con.shortestMatch ) ) )
{
if( COM_CheckString( m ) ) Con_Printf( " %s ^3\"%s\"\n", s, m );
else Con_Printf( " %s\n", s ); // variable or command without description
}
}
/*
===============
Con_PrintCvarMatches
===============
*/
static void Con_PrintCvarMatches( const char *s, const char *value, const char *m, void *unused2 )
{
if( !Q_strnicmp( s, con.shortestMatch, Q_strlen( con.shortestMatch ) ) )
{
if( COM_CheckString( m ) ) Con_Printf( " %s (%s) ^3\"%s\"\n", s, value, m );
else Con_Printf( " %s (%s)\n", s, value ); // variable or command without description
}
}
/*
===============
Con_ConcatRemaining
===============
*/
static void Con_ConcatRemaining( const char *src, const char *start )
{
const char *arg;
int i;
arg = Q_strstr( src, start );
if( !arg )
{
for( i = 1; i < Cmd_Argc(); i++ )
{
Q_strncat( con.completionField->buffer, " ", sizeof( con.completionField->buffer ) );
arg = Cmd_Argv( i );
while( *arg )
{
if( *arg == ' ' )
{
Q_strncat( con.completionField->buffer, "\"", sizeof( con.completionField->buffer ) );
break;
}
arg++;
}
Q_strncat( con.completionField->buffer, Cmd_Argv( i ), sizeof( con.completionField->buffer ) );
if( *arg == ' ' ) Q_strncat( con.completionField->buffer, "\"", sizeof( con.completionField->buffer ) );
}
return;
}
arg += Q_strlen( start );
Q_strncat( con.completionField->buffer, arg, sizeof( con.completionField->buffer ) );
}
/*
===============
Con_CompleteCommand
perform Tab expansion
===============
*/
void Con_CompleteCommand( field_t *field )
{
field_t temp;
string filename;
qboolean nextcmd;
int i;
// setup the completion field
con.completionField = field;
// only look at the first token for completion purposes
Cmd_TokenizeString( con.completionField->buffer );
nextcmd = (con.completionField->buffer[Q_strlen( con.completionField->buffer ) - 1] == ' ') ? true : false;
con.completionString = Cmd_Argv( 0 );
con.completionBuffer = Cmd_Argv( 1 );
// skip backslash
while( *con.completionString && (*con.completionString == '\\' || *con.completionString == '/') )
con.completionString++;
// skip backslash
while( *con.completionBuffer && (*con.completionBuffer == '\\' || *con.completionBuffer == '/') )
con.completionBuffer++;
if( !Q_strlen( con.completionString ) )
return;
// free the old autocomplete list
for( i = 0; i < con.matchCount; i++ )
{
if( con.cmds[i] != NULL )
{
Mem_Free( con.cmds[i] );
con.cmds[i] = NULL;
}
}
con.matchCount = 0;
con.shortestMatch[0] = 0;
// find matching commands and variables
Cmd_LookupCmds( NULL, NULL, Con_AddCommandToList );
Cvar_LookupVars( 0, NULL, NULL, Con_AddCommandToList );
if( !con.matchCount ) return; // no matches
memcpy( &temp, con.completionField, sizeof( field_t ) );
// autocomplete second arg
if( (Cmd_Argc() == 2) || ((Cmd_Argc() == 1) && nextcmd) )
{
if( !Q_strlen( con.completionBuffer ) )
return;
if( Cmd_AutocompleteName( con.completionBuffer, filename, sizeof( filename ) ) )
{
Q_sprintf( con.completionField->buffer, "%s %s", Cmd_Argv( 0 ), filename );
con.completionField->cursor = Q_strlen( con.completionField->buffer );
}
// don't adjusting cursor pos if we nothing found
return;
}
else if( Cmd_Argc() >= 3 )
{
// disable autocomplete for all next args
return;
}
if( con.matchCount == 1 )
{
Q_sprintf( con.completionField->buffer, "\\%s", con.cmds[0] );
if( Cmd_Argc() == 1 ) Q_strncat( con.completionField->buffer, " ", sizeof( con.completionField->buffer ) );
else Con_ConcatRemaining( temp.buffer, con.completionString );
con.completionField->cursor = Q_strlen( con.completionField->buffer );
}
else
{
char *first, *last;
int len = 0;
qsort( con.cmds, con.matchCount, sizeof( char* ), Con_SortCmds );
// find the number of matching characters between the first and
// the last element in the list and copy it
first = con.cmds[0];
last = con.cmds[con.matchCount - 1];
while( *first && *last && Q_tolower( *first ) == Q_tolower( *last ) )
{
first++;
last++;
con.shortestMatch[len] = con.cmds[0][len];
len++;
}
con.shortestMatch[len] = 0;
// multiple matches, complete to shortest
Q_sprintf( con.completionField->buffer, "\\%s", con.shortestMatch );
con.completionField->cursor = Q_strlen( con.completionField->buffer );
Con_ConcatRemaining( temp.buffer, con.completionString );
Con_Printf( "]%s\n", con.completionField->buffer );
// run through again, printing matches
Cmd_LookupCmds( NULL, NULL, Con_PrintCmdMatches );
Cvar_LookupVars( 0, NULL, NULL, Con_PrintCvarMatches );
}
}
/*
=========
Cmd_AutoComplete
NOTE: input string must be equal or longer than MAX_STRING
=========
*/
void Cmd_AutoComplete( char *complete_string )
{
field_t input;
if( !complete_string || !*complete_string )
return;
// setup input
Q_strncpy( input.buffer, complete_string, sizeof( input.buffer ) );
input.cursor = input.scroll = 0;
Con_CompleteCommand( &input );
// setup output
if( input.buffer[0] == '\\' || input.buffer[0] == '/' )
Q_strncpy( complete_string, input.buffer + 1, sizeof( input.buffer ) );
else Q_strncpy( complete_string, input.buffer, sizeof( input.buffer ) );
}
/*
============
Cmd_AutoCompleteClear
============
*/
void Cmd_AutoCompleteClear( void )
{
int i;
// free the old autocomplete list
for( i = 0; i < con.matchCount; i++ )
{
if( con.cmds[i] != NULL )
{
Mem_Free( con.cmds[i] );
con.cmds[i] = NULL;
}
}
con.matchCount = 0;
}
/*
============
Cmd_WriteVariables
@ -907,6 +1192,23 @@ void Cmd_WriteOpenGLVariables( file_t *f )
}
#ifndef XASH_DEDICATED
#define CFG_END(f,x) \
if( FS_Printf( f,"// end of " x "\n" ) >= (int)sizeof( "// end of " x "\n" ) - 2 )\
{ \
FS_Close( f );\
FS_Delete( x ".bak" ); \
FS_Rename( x, x ".bak" ); \
FS_Delete( x ); \
FS_Rename( x ".new", x );\
}\
else\
{\
FS_Close( f );\
Con_Reportf( S_ERROR "could not update " x "\n" );\
}
/*
===============
Host_WriteConfig
@ -920,12 +1222,13 @@ void Host_WriteConfig( void )
kbutton_t *jlook = NULL;
file_t *f;
if( !clgame.hInstance ) return;
if( !clgame.hInstance || Sys_CheckParm( "-nowriteconfig" ) ) return;
MsgDev( D_NOTE, "Host_WriteConfig()\n" );
f = FS_Open( "config.cfg", "w", false );
f = FS_Open( "config.cfg.new", "w", false );
if( f )
{
Con_Reportf( "Host_WriteConfig()\n" );
FS_Printf( f, "//=======================================================================\n");
FS_Printf( f, "//\t\t\tCopyright XashXT Group %s (C)\n", Q_timestamp( TIME_YEAR_ONLY ));
FS_Printf( f, "//\t\t\tconfig.cfg - archive of cvars\n" );
@ -946,13 +1249,14 @@ void Host_WriteConfig( void )
if( jlook && ( jlook->state & 1 ))
FS_Printf( f, "+jlook\n" );
FS_Printf( f, "exec userconfig.cfg" );
FS_Printf( f, "exec userconfig.cfg\n" );
FS_Close( f );
CFG_END( f, "config.cfg" );
}
else MsgDev( D_ERROR, "Couldn't write config.cfg.\n" );
else Con_DPrintf( S_ERROR "Couldn't write config.cfg.\n" );
NET_SaveMasters();
}
#endif
/*
===============
@ -964,23 +1268,34 @@ save serverinfo variables into server.cfg (using for dedicated server too)
void Host_WriteServerConfig( const char *name )
{
file_t *f;
string oldconfigfile, newconfigfile;
Q_snprintf( oldconfigfile, MAX_STRING, "%s.bak", name );
Q_snprintf( newconfigfile, MAX_STRING, "%s.new", name );
SV_InitGameProgs(); // collect user variables
// FIXME: move this out until menu parser is done
CSCR_LoadDefaultCVars( "settings.scr" );
if(( f = FS_Open( name, "w", false )) != NULL )
if(( f = FS_Open( newconfigfile, "w", false )) != NULL )
{
FS_Printf( f, "//=======================================================================\n" );
FS_Printf( f, "//\t\t\tCopyright XashXT Group %s (C)\n", Q_timestamp( TIME_YEAR_ONLY ));
FS_Printf( f, "//\t\tgame.cfg - multiplayer server temporare config\n" );
FS_Printf( f, "//=======================================================================\n" );
Cvar_WriteVariables( f, FCVAR_SERVER );
CSCR_WriteGameCVars( f, "settings.scr" );
FS_Close( f );
FS_Rename( name, oldconfigfile );
FS_Delete( name );
FS_Rename( newconfigfile, name );
FS_Delete( oldconfigfile );
}
else MsgDev( D_ERROR, "Couldn't write %s.\n", name );
else Con_DPrintf( S_ERROR "Couldn't write %s.\n", name );
SV_FreeGameProgs(); // release progs with all variables
}
@ -996,19 +1311,22 @@ void Host_WriteOpenGLConfig( void )
{
file_t *f;
MsgDev( D_NOTE, "Host_WriteGLConfig()\n" );
f = FS_Open( "opengl.cfg", "w", false );
if( Sys_CheckParm( "-nowriteconfig" ) )
return;
f = FS_Open( "opengl.cfg.new", "w", false );
if( f )
{
Con_Reportf( "Host_WriteGLConfig()\n" );
FS_Printf( f, "//=======================================================================\n" );
FS_Printf( f, "//\t\t\tCopyright XashXT Group %s (C)\n", Q_timestamp( TIME_YEAR_ONLY ));
FS_Printf( f, "//\t\t opengl.cfg - archive of opengl extension cvars\n");
FS_Printf( f, "//=======================================================================\n" );
FS_Printf( f, "\n" );
Cmd_WriteOpenGLVariables( f );
FS_Close( f );
CFG_END( f, "opengl.cfg" );
}
else MsgDev( D_ERROR, "can't update opengl.cfg.\n" );
else Con_DPrintf( S_ERROR "can't update opengl.cfg.\n" );
}
/*
@ -1022,19 +1340,23 @@ void Host_WriteVideoConfig( void )
{
file_t *f;
MsgDev( D_NOTE, "Host_WriteVideoConfig()\n" );
f = FS_Open( "video.cfg", "w", false );
if( Sys_CheckParm( "-nowriteconfig" ) )
return;
f = FS_Open( "video.cfg.new", "w", false );
if( f )
{
Con_Reportf( "Host_WriteVideoConfig()\n" );
FS_Printf( f, "//=======================================================================\n" );
FS_Printf( f, "//\t\t\tCopyright XashXT Group %s (C)\n", Q_timestamp( TIME_YEAR_ONLY ));
FS_Printf( f, "//\t\tvideo.cfg - archive of renderer variables\n");
FS_Printf( f, "//=======================================================================\n" );
Cvar_WriteVariables( f, FCVAR_RENDERINFO );
FS_Close( f );
CFG_END( f, "video.cfg" );
}
else MsgDev( D_ERROR, "can't update video.cfg.\n" );
else Con_DPrintf( S_ERROR "can't update video.cfg.\n" );
}
#endif // XASH_DEDICATED
void Key_EnumCmds_f( void )
{

View file

@ -12,6 +12,7 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#define _GNU_SOURCE
#include "common.h"
@ -22,9 +23,6 @@ Sys_Crash
Crash handler, called from system
================
*/
#define DEBUG_BREAK
/// TODO: implement on windows too
#if XASH_CRASHHANDLER == CRASHHANDLER_DBGHELP || XASH_CRASHHANDLER == CRASHHANDLER_WIN32
#if XASH_CRASHHANDLER == CRASHHANDLER_DBGHELP
#pragma comment( lib, "dbghelp" )
@ -186,7 +184,7 @@ LPTOP_LEVEL_EXCEPTION_FILTER oldFilter;
long _stdcall Sys_Crash( PEXCEPTION_POINTERS pInfo )
{
// save config
if( host.state != HOST_CRASHED )
if( host.status != HOST_CRASHED )
{
// check to avoid recursive call
host.crashed = true;
@ -199,9 +197,9 @@ long _stdcall Sys_Crash( PEXCEPTION_POINTERS pInfo )
if( host.type == HOST_NORMAL )
CL_Crashed(); // tell client about crash
else host.state = HOST_CRASHED;
else host.status = HOST_CRASHED;
if( host.developer <= 0 )
if( host_developer.value <= 0 )
{
// no reason to call debugger in release build - just exit
Sys_Quit();
@ -232,139 +230,187 @@ void Sys_RestoreCrashHandler( void )
#elif XASH_CRASHHANDLER == CRASHHANDLER_UCONTEXT
// Posix signal handler
#include "library.h"
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined __ANDROID__
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__ANDROID__) || defined(__linux__)
#define HAVE_UCONTEXT_H 1
#endif
#ifdef HAVE_UCONTEXT_H
#include <ucontext.h>
#endif
#include <signal.h>
#include <sys/mman.h>
int printframe( char *buf, int len, int i, void *addr )
{
Dl_info dlinfo;
if( len <= 0 ) return 0; // overflow
if( len <= 0 )
return 0; // overflow
if( dladdr( addr, &dlinfo ))
{
if( dlinfo.dli_sname )
return Q_snprintf( buf, len, "% 2d: %p <%s+%lu> (%s)\n", i, addr, dlinfo.dli_sname,
return Q_snprintf( buf, len, "%2d: %p <%s+%lu> (%s)\n", i, addr, dlinfo.dli_sname,
(unsigned long)addr - (unsigned long)dlinfo.dli_saddr, dlinfo.dli_fname ); // print symbol, module and address
else
return Q_snprintf( buf, len, "% 2d: %p (%s)\n", i, addr, dlinfo.dli_fname ); // print module and address
return Q_snprintf( buf, len, "%2d: %p (%s)\n", i, addr, dlinfo.dli_fname ); // print module and address
}
else
return Q_snprintf( buf, len, "% 2d: %p\n", i, addr ); // print only address
return Q_snprintf( buf, len, "%2d: %p\n", i, addr ); // print only address
}
struct sigaction oldFilter;
#define STACK_BACKTRACE_STR_LEN 17
#define STACK_BACKTRACE_STR "Stack backtrace:\n"
#define STACK_DUMP_STR_LEN 12
#define STACK_DUMP_STR "Stack dump:\n"
#define ALIGN( x, y ) (((int) (x) + ((y)-1)) & ~((y)-1))
static void Sys_Crash( int signal, siginfo_t *si, void *context)
{
void *trace[32];
void *pc, **bp, **sp; // this must be set for every OS!
char message[8192];
int len, logfd, i = 0;
size_t pagesize;
char message[4096], stackframe[256];
int len, stacklen, logfd, i = 0;
#if defined(__OpenBSD__)
struct sigcontext *ucontext = (struct sigcontext*)context;
#else
ucontext_t *ucontext = (ucontext_t*)context;
#endif
#if defined(__x86_64__)
#if defined(__FreeBSD__)
void *pc = (void*)ucontext->uc_mcontext.mc_rip, **bp = (void**)ucontext->uc_mcontext.mc_rbp, **sp = (void**)ucontext->uc_mcontext.mc_rsp;
pc = (void*)ucontext->uc_mcontext.mc_rip;
bp = (void**)ucontext->uc_mcontext.mc_rbp;
sp = (void**)ucontext->uc_mcontext.mc_rsp;
#elif defined(__NetBSD__)
void *pc = (void*)ucontext->uc_mcontext.__gregs[REG_RIP], **bp = (void**)ucontext->uc_mcontext.__gregs[REG_RBP], **sp = (void**)ucontext->uc_mcontext.__gregs[REG_RSP];
pc = (void*)ucontext->uc_mcontext.__gregs[REG_RIP];
bp = (void**)ucontext->uc_mcontext.__gregs[REG_RBP];
sp = (void**)ucontext->uc_mcontext.__gregs[REG_RSP];
#elif defined(__OpenBSD__)
void *pc = (void*)ucontext->sc_rip, **bp = (void**)ucontext->sc_rbp, **sp = (void**)ucontext->sc_rsp;
pc = (void*)ucontext->sc_rip;
bp = (void**)ucontext->sc_rbp;
sp = (void**)ucontext->sc_rsp;
#else
void *pc = (void*)ucontext->uc_mcontext.gregs[REG_RIP], **bp = (void**)ucontext->uc_mcontext.gregs[REG_RBP], **sp = (void**)ucontext->uc_mcontext.gregs[REG_RSP];
pc = (void*)ucontext->uc_mcontext.gregs[REG_RIP];
bp = (void**)ucontext->uc_mcontext.gregs[REG_RBP];
sp = (void**)ucontext->uc_mcontext.gregs[REG_RSP];
#endif
#elif defined(__i386__)
#if defined(__FreeBSD__)
void *pc = (void*)ucontext->uc_mcontext.mc_eip, **bp = (void**)ucontext->uc_mcontext.mc_ebp, **sp = (void**)ucontext->uc_mcontext.mc_esp;
pc = (void*)ucontext->uc_mcontext.mc_eip;
bp = (void**)ucontext->uc_mcontext.mc_ebp;
sp = (void**)ucontext->uc_mcontext.mc_esp;
#elif defined(__NetBSD__)
void *pc = (void*)ucontext->uc_mcontext.__gregs[REG_EIP], **bp = (void**)ucontext->uc_mcontext.__gregs[REG_EBP], **sp = (void**)ucontext->uc_mcontext.__gregs[REG_ESP];
pc = (void*)ucontext->uc_mcontext.__gregs[REG_EIP];
bp = (void**)ucontext->uc_mcontext.__gregs[REG_EBP];
sp = (void**)ucontext->uc_mcontext.__gregs[REG_ESP];
#elif defined(__OpenBSD__)
void *pc = (void*)ucontext->sc_eip, **bp = (void**)ucontext->sc_ebp, **sp = (void**)ucontext->sc_esp;
pc = (void*)ucontext->sc_eip;
bp = (void**)ucontext->sc_ebp;
sp = (void**)ucontext->sc_esp;
#else
void *pc = (void*)ucontext->uc_mcontext.gregs[REG_EIP], **bp = (void**)ucontext->uc_mcontext.gregs[REG_EBP], **sp = (void**)ucontext->uc_mcontext.gregs[REG_ESP];
pc = (void*)ucontext->uc_mcontext.gregs[REG_EIP];
bp = (void**)ucontext->uc_mcontext.gregs[REG_EBP];
sp = (void**)ucontext->uc_mcontext.gregs[REG_ESP];
#endif
#elif defined(__aarch64__) // arm not tested
void *pc = (void*)ucontext->uc_mcontext.pc, **bp = (void*)ucontext->uc_mcontext.regs[29], **sp = (void*)ucontext->uc_mcontext.sp;
pc = (void*)ucontext->uc_mcontext.pc;
bp = (void*)ucontext->uc_mcontext.regs[29];
sp = (void*)ucontext->uc_mcontext.sp;
#elif defined(__arm__)
void *pc = (void*)ucontext->uc_mcontext.arm_pc, **bp = (void*)ucontext->uc_mcontext.arm_fp, **sp = (void*)ucontext->uc_mcontext.arm_sp;
pc = (void*)ucontext->uc_mcontext.arm_pc;
bp = (void*)ucontext->uc_mcontext.arm_fp;
sp = (void*)ucontext->uc_mcontext.arm_sp;
#else
#error "Unknown arch!!!"
#error "Unknown arch!!!"
#endif
// Safe actions first, stack and memory may be corrupted
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
len = Q_snprintf( message, 4096, "Sys_Crash: signal %d, err %d with code %d at %p\n", signal, si->si_errno, si->si_code, si->si_addr );
#else
len = Q_snprintf( message, 4096, "Sys_Crash: signal %d, err %d with code %d at %p %p\n", signal, si->si_errno, si->si_code, si->si_addr, si->si_ptr );
#endif
write(2, message, len);
// Flush buffers before writing directly to descriptors
// safe actions first, stack and memory may be corrupted
len = Q_snprintf( message, sizeof( message ), "Ver: %s %s (build %i-%s, %s-%s)\n",
XASH_ENGINE_NAME, XASH_VERSION, Q_buildnum(), Q_buildcommit(), Q_buildos(), Q_buildarch() );
#if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__)
len += Q_snprintf( message + len, sizeof( message ) - len, "Crash: signal %d errno %d with code %d at %p %p\n", signal, si->si_errno, si->si_code, si->si_addr, si->si_ptr );
#else
len += Q_snprintf( message + len, sizeof( message ) - len, "Crash: signal %d errno %d with code %d at %p\n", signal, si->si_errno, si->si_code, si->si_addr );
#endif
write( 2, message, len );
// flush buffers before writing directly to descriptors
fflush( stdout );
fflush( stderr );
// Now get log fd and write trace directly to log
// now get log fd and write trace directly to log
logfd = Sys_LogFileNo();
write( logfd, message, len );
write( 2, "Stack backtrace:\n", 17 );
write( logfd, "Stack backtrace:\n", 17 );
strncpy(message + len, "Stack backtrace:\n", 4096 - len);
len += 17;
size_t pagesize = sysconf(_SC_PAGESIZE);
// try to print backtrace
write( 2, STACK_BACKTRACE_STR, STACK_BACKTRACE_STR_LEN );
write( logfd, STACK_BACKTRACE_STR, STACK_BACKTRACE_STR_LEN );
strncpy( message + len, STACK_BACKTRACE_STR, sizeof( message ) - len );
len += STACK_BACKTRACE_STR_LEN;
pagesize = sysconf( _SC_PAGESIZE );
do
{
int line = printframe( message + len, 4096 - len, ++i, pc);
int line = printframe( message + len, sizeof( message ) - len, ++i, pc);
write( 2, message + len, line );
write( logfd, message + len, line );
len += line;
//if( !dladdr(bp,0) ) break; // Only when bp is in module
if( ( mprotect((char *)(((int) bp + (pagesize-1)) & ~(pagesize-1)), pagesize, PROT_READ | PROT_WRITE | PROT_EXEC ) == -1) &&
( mprotect((char *)(((int) bp + (pagesize-1)) & ~(pagesize-1)), pagesize, PROT_READ | PROT_EXEC ) == -1) &&
( mprotect((char *)(((int) bp + (pagesize-1)) & ~(pagesize-1)), pagesize, PROT_READ | PROT_WRITE ) == -1) &&
( mprotect((char *)(((int) bp + (pagesize-1)) & ~(pagesize-1)), pagesize, PROT_READ ) == -1) )
//if( !dladdr(bp,0) ) break; // only when bp is in module
if( ( mprotect( (char *)ALIGN( bp, pagesize ), pagesize, PROT_READ | PROT_WRITE | PROT_EXEC ) == -1) &&
( mprotect( (char *)ALIGN( bp, pagesize ), pagesize, PROT_READ | PROT_EXEC ) == -1) &&
( mprotect( (char *)ALIGN( bp, pagesize ), pagesize, PROT_READ | PROT_WRITE ) == -1) &&
( mprotect( (char *)ALIGN( bp, pagesize ), pagesize, PROT_READ ) == -1) )
break;
if( ( mprotect((char *)(((int) bp[0] + (pagesize-1)) & ~(pagesize-1)), pagesize, PROT_READ | PROT_WRITE | PROT_EXEC ) == -1) &&
( mprotect((char *)(((int) bp[0] + (pagesize-1)) & ~(pagesize-1)), pagesize, PROT_READ | PROT_EXEC ) == -1) &&
( mprotect((char *)(((int) bp[0] + (pagesize-1)) & ~(pagesize-1)), pagesize, PROT_READ | PROT_WRITE ) == -1) &&
( mprotect((char *)(((int) bp[0] + (pagesize-1)) & ~(pagesize-1)), pagesize, PROT_READ ) == -1) )
if( ( mprotect( (char *)ALIGN( bp[0], pagesize ), pagesize, PROT_READ | PROT_WRITE | PROT_EXEC ) == -1) &&
( mprotect( (char *)ALIGN( bp[0], pagesize ), pagesize, PROT_READ | PROT_EXEC ) == -1) &&
( mprotect( (char *)ALIGN( bp[0], pagesize ), pagesize, PROT_READ | PROT_WRITE ) == -1) &&
( mprotect( (char *)ALIGN( bp[0], pagesize ), pagesize, PROT_READ ) == -1) )
break;
pc = bp[1];
bp = (void**)bp[0];
}
while( bp && i < 128 );
// Try to print stack
write( 2, "Stack dump:\n", 12 );
write( logfd, "Stack dump:\n", 12 );
strncpy( message + len, "Stack dump:\n", 4096 - len );
len += 12;
if( ( mprotect((char *)(((int) sp + (pagesize-1)) & ~(pagesize-1)), pagesize, PROT_READ | PROT_WRITE | PROT_EXEC ) != -1) ||
( mprotect((char *)(((int) sp + (pagesize-1)) & ~(pagesize-1)), pagesize, PROT_READ | PROT_EXEC ) != -1) ||
( mprotect((char *)(((int) sp + (pagesize-1)) & ~(pagesize-1)), pagesize, PROT_READ | PROT_WRITE ) != -1) ||
( mprotect((char *)(((int) sp + (pagesize-1)) & ~(pagesize-1)), pagesize, PROT_READ ) != -1) )
// try to print stack
write( 2, STACK_DUMP_STR, STACK_DUMP_STR_LEN );
write( logfd, STACK_DUMP_STR, STACK_DUMP_STR_LEN );
strncpy( message + len, STACK_DUMP_STR, sizeof( message ) - len );
len += STACK_DUMP_STR_LEN;
if( ( mprotect((char *)ALIGN( sp, pagesize ), pagesize, PROT_READ | PROT_WRITE | PROT_EXEC ) != -1) ||
( mprotect((char *)ALIGN( sp, pagesize ), pagesize, PROT_READ | PROT_EXEC ) != -1) ||
( mprotect((char *)ALIGN( sp, pagesize ), pagesize, PROT_READ | PROT_WRITE ) != -1) ||
( mprotect((char *)ALIGN( sp, pagesize ), pagesize, PROT_READ ) != -1) )
{
for( i = 0; i < 32; i++ )
{
int line = printframe( message + len, 4096 - len, i, sp[i] );
int line = printframe( message + len, sizeof( message ) - len, i, sp[i] );
write( 2, message + len, line );
write( logfd, message + len, line );
len += line;
}
// Put MessageBox as Sys_Error
}
// put MessageBox as Sys_Error
Msg( "%s\n", message );
#ifdef XASH_SDL
SDL_SetWindowGrab( host.hWnd, SDL_FALSE );
#endif
MSGBOX( message );
// Log saved, now we can try to save configs and close log correctly, it may crash
// log saved, now we can try to save configs and close log correctly, it may crash
if( host.type == HOST_NORMAL )
CL_Crashed();
host.state = HOST_CRASHED;
host.status = HOST_CRASHED;
host.crashed = true;
Sys_Quit();
@ -375,18 +421,18 @@ void Sys_SetupCrashHandler( void )
struct sigaction act;
act.sa_sigaction = Sys_Crash;
act.sa_flags = SA_SIGINFO | SA_ONSTACK;
sigaction(SIGSEGV, &act, &oldFilter);
sigaction(SIGABRT, &act, &oldFilter);
sigaction(SIGBUS, &act, &oldFilter);
sigaction(SIGILL, &act, &oldFilter);
sigaction( SIGSEGV, &act, &oldFilter );
sigaction( SIGABRT, &act, &oldFilter );
sigaction( SIGBUS, &act, &oldFilter );
sigaction( SIGILL, &act, &oldFilter );
}
void Sys_RestoreCrashHandler( void )
{
sigaction( SIGSEGV, &oldFilter, NULL );
sigaction( SIGABRT, &oldFilter, NULL );
sigaction( SIGBUS, &oldFilter, NULL );
sigaction( SIGILL, &oldFilter, NULL );
sigaction( SIGBUS, &oldFilter, NULL );
sigaction( SIGILL, &oldFilter, NULL );
}
#elif XASH_CRASHHANDLER == CRASHHANDLER_NULL

View file

@ -422,7 +422,7 @@ void MD5Final( byte digest[16], MD5Context_t *ctx )
MD5Transform( ctx->buf, (uint *)ctx->in );
memcpy( digest, ctx->buf, 16 );
memset( ctx, 0, sizeof( ctx )); // in case it's sensitive
memset( ctx, 0, sizeof( *ctx )); // in case it's sensitive
}
// The four core functions

View file

@ -185,7 +185,7 @@ char *_copystring( byte *mempool, const char *s, const char *filename, int filel
if( !s ) return NULL;
if( !mempool ) mempool = host.mempool;
b = _Mem_Alloc( mempool, Q_strlen( s ) + 1, filename, fileline );
b = _Mem_Alloc( mempool, Q_strlen( s ) + 1, false, filename, fileline );
Q_strcpy( b, s );
return b;
@ -575,7 +575,6 @@ int Q_vsnprintf( char *buffer, size_t buffersize, const char *format, va_list ar
__except( EXCEPTION_EXECUTE_HANDLER )
{
Q_strncpy( buffer, "^1sprintf throw exception^7\n", buffersize );
// memset( buffer, 0, buffersize );
result = buffersize;
}
#endif

View file

@ -36,6 +36,7 @@ enum
#define CMD_SERVERDLL BIT( 0 ) // added by server.dll
#define CMD_CLIENTDLL BIT( 1 ) // added by client.dll
#define CMD_GAMEUIDLL BIT( 2 ) // added by GameUI.dll
#define CMD_LOCALONLY BIT( 3 ) // restricted from server commands
typedef void (*xcommand_t)( void );
@ -54,6 +55,7 @@ const char *Cmd_Argv( int arg );
void Cmd_Init( void );
void Cmd_Unlink( int group );
void Cmd_AddCommand( const char *cmd_name, xcommand_t function, const char *cmd_desc );
void Cmd_AddRestrictedCommand( const char *cmd_name, xcommand_t function, const char *cmd_desc );
void Cmd_AddServerCommand( const char *cmd_name, xcommand_t function );
int Cmd_AddClientCommand( const char *cmd_name, xcommand_t function );
int Cmd_AddGameUICommand( const char *cmd_name, xcommand_t function );
@ -113,8 +115,8 @@ char *va( const char *format, ... ) _format( 1 );
// zone.c
//
void Memory_Init( void );
void *_Mem_Realloc( byte *poolptr, void *memptr, size_t size, const char *filename, int fileline );
void *_Mem_Alloc( byte *poolptr, size_t size, const char *filename, int fileline );
void *_Mem_Realloc( byte *poolptr, void *memptr, size_t size, qboolean clear, const char *filename, int fileline );
void *_Mem_Alloc( byte *poolptr, size_t size, qboolean clear, const char *filename, int fileline );
byte *_Mem_AllocPool( const char *name, const char *filename, int fileline );
void _Mem_FreePool( byte **poolptr, const char *filename, int fileline );
void _Mem_EmptyPool( byte *poolptr, const char *filename, int fileline );
@ -124,8 +126,9 @@ qboolean Mem_IsAllocatedExt( byte *poolptr, void *data );
void Mem_PrintList( size_t minallocationsize );
void Mem_PrintStats( void );
#define Mem_Alloc( pool, size ) _Mem_Alloc( pool, size, __FILE__, __LINE__ )
#define Mem_Realloc( pool, ptr, size ) _Mem_Realloc( pool, ptr, size, __FILE__, __LINE__ )
#define Mem_Malloc( pool, size ) _Mem_Alloc( pool, size, false, __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_Free( mem ) _Mem_Free( mem, __FILE__, __LINE__ )
#define Mem_AllocPool( name ) _Mem_AllocPool( name, __FILE__, __LINE__ )
#define Mem_FreePool( pool ) _Mem_FreePool( pool, __FILE__, __LINE__ )

View file

@ -63,12 +63,12 @@ void COM_ClearCustomizationList( customization_t *pHead, qboolean bCleanDecals )
qboolean COM_CreateCustomization( customization_t *pListHead, resource_t *pResource, int playernumber, int flags, customization_t **pOut, int *nLumps )
{
qboolean bError = false;
long checksize = 0;
size_t checksize = 0;
customization_t *pCust;
if( pOut ) *pOut = NULL;
pCust = Z_Malloc( sizeof( customization_t ));
pCust = Z_Calloc( sizeof( customization_t ));
pCust->resource = *pResource;
if( pResource->nDownloadSize <= 0 )

View file

@ -13,8 +13,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include <math.h> // fabs...
#include "common.h"
#include "math.h" // fabs...
#include "base_cmd.h"
convar_t *cvar_vars = NULL; // head of list
convar_t *cmd_scripting;
@ -39,6 +40,10 @@ find the specified variable by name
*/
convar_t *Cvar_FindVarExt( const char *var_name, int ignore_group )
{
// TODO: ignore group for cvar
#if defined(XASH_HASHED_VARS)
return (convar_t *)BaseCmd_Find( HM_CVAR, var_name );
#else
convar_t *var;
if( !var_name )
@ -54,6 +59,7 @@ convar_t *Cvar_FindVarExt( const char *var_name, int ignore_group )
}
return NULL;
#endif
}
/*
@ -115,6 +121,7 @@ static qboolean Cvar_UpdateInfo( convar_t *var, const char *value, qboolean noti
// time to update server copy of userinfo
CL_ServerCommand( true, "setinfo \"%s\" \"%s\"\n", var->name, value );
CL_LegacyUpdateInfo();
}
#endif
}
@ -238,6 +245,10 @@ int Cvar_UnlinkVar( const char *var_name, int group )
continue;
}
#if defined(XASH_HASHED_VARS)
BaseCmd_Remove( HM_CVAR, var->name );
#endif
// unlink variable from list
freestring( var->string );
*prev = var->next;
@ -333,7 +344,7 @@ convar_t *Cvar_Get( const char *name, const char *value, int flags, const char *
// check for command coexisting
if( Cmd_Exists( name ))
{
MsgDev( D_ERROR, "can't register variable '%s', is already defined as command\n", name );
Con_DPrintf( S_ERROR "can't register variable '%s', is already defined as command\n", name );
return NULL;
}
@ -369,7 +380,7 @@ convar_t *Cvar_Get( const char *name, const char *value, int flags, const char *
if( FBitSet( var->flags, FCVAR_ALLOCATED ) && Q_strcmp( var_desc, var->desc ))
{
if( !FBitSet( flags, FCVAR_GLCONFIG ))
MsgDev( D_REPORT, "%s change description from %s to %s\n", var->name, var->desc, var_desc );
Con_Reportf( "%s change description from %s to %s\n", var->name, var->desc, var_desc );
// update description if needs
freestring( var->desc );
var->desc = copystring( var_desc );
@ -400,6 +411,11 @@ convar_t *Cvar_Get( const char *name, const char *value, int flags, const char *
// tell engine about changes
Cvar_Changed( var );
#if defined(XASH_HASHED_VARS)
// add to map
BaseCmd_Insert( HM_CVAR, var, var->name );
#endif
return var;
}
@ -423,7 +439,7 @@ void Cvar_RegisterVariable( convar_t *var )
{
if( !FBitSet( dup->flags, FCVAR_TEMPORARY ))
{
MsgDev( D_ERROR, "can't register variable '%s', is already defined\n", var->name );
Con_DPrintf( S_ERROR "can't register variable '%s', is already defined\n", var->name );
return;
}
@ -434,7 +450,7 @@ void Cvar_RegisterVariable( convar_t *var )
// check for overlap with a command
if( Cmd_Exists( var->name ))
{
MsgDev( D_ERROR, "can't register variable '%s', is already defined as command\n", var->name );
Con_DPrintf( S_ERROR "can't register variable '%s', is already defined as command\n", var->name );
return;
}
@ -463,6 +479,11 @@ void Cvar_RegisterVariable( convar_t *var )
// tell engine about changes
Cvar_Changed( var );
#if defined(XASH_HASHED_VARS)
// add to map
BaseCmd_Insert( HM_CVAR, var, var->name );
#endif
}
/*
@ -482,16 +503,12 @@ void Cvar_DirectSet( convar_t *var, const char *value )
if( CVAR_CHECK_SENTINEL( var ) || ( var->next == NULL && !FBitSet( var->flags, FCVAR_EXTENDED|FCVAR_ALLOCATED )))
{
// need to registering cvar fisrt
MsgDev( D_WARN, "Cvar_DirectSet: called for unregistered cvar '%s'\n", var->name );
Cvar_RegisterVariable( var ); // ok, register it
}
// lookup for registration again
if( var != Cvar_FindVar( var->name ))
{
MsgDev( D_ERROR, "Cvar_DirectSet: couldn't find cvar '%s' in linked list\n", var->name );
return;
}
return; // how this possible?
if( FBitSet( var->flags, FCVAR_READ_ONLY|FCVAR_GLCONFIG ))
{
@ -578,8 +595,7 @@ void Cvar_Set( const char *var_name, const char *value )
if( !var )
{
// there is an error in C code if this happens
if( host.type != HOST_DEDICATED )
MsgDev( D_ERROR, "Cvar_Set: variable '%s' not found\n", var_name );
Con_Printf( "Cvar_Set: variable '%s' not found\n", var_name );
return;
}
@ -657,6 +673,18 @@ const char *Cvar_VariableString( const char *var_name )
return var->string;
}
/*
============
Cvar_Exists
============
*/
qboolean Cvar_Exists( const char *var_name )
{
if( Cvar_FindVar( var_name ))
return true;
return false;
}
/*
============
Cvar_SetCheatState
@ -683,6 +711,26 @@ void Cvar_SetCheatState( void )
}
}
/*
============
Cvar_SetGL
As Cvar_Set, but also flags it as glconfig
============
*/
static void Cvar_SetGL( const char *name, const char *value )
{
convar_t *var = Cvar_FindVar( name );
if( var && !FBitSet( var->flags, FCVAR_GLCONFIG ))
{
Con_Reportf( S_ERROR "Can't set non-GL cvar %s to %s\n", name, value );
return;
}
Cvar_FullSet( name, value, FCVAR_GLCONFIG );
}
/*
============
Cvar_Command
@ -690,19 +738,18 @@ Cvar_Command
Handles variable inspection and changing from the console
============
*/
qboolean Cvar_Command( void )
qboolean Cvar_Command( convar_t *v )
{
convar_t *v;
// special case for setup opengl configuration
if( host.apply_opengl_config )
{
Cvar_FullSet( Cmd_Argv( 0 ), Cmd_Argv( 1 ), FCVAR_GLCONFIG );
Cvar_SetGL( Cmd_Argv( 0 ), Cmd_Argv( 1 ) );
return true;
}
// check variables
v = Cvar_FindVar( Cmd_Argv( 0 ));
if( !v ) // already found in basecmd
v = Cvar_FindVar( Cmd_Argv( 0 ));
if( !v ) return false;
// perform a variable print or set
@ -785,13 +832,15 @@ As Cvar_Set, but also flags it as glconfig
*/
void Cvar_SetGL_f( void )
{
convar_t *var;
if( Cmd_Argc() != 3 )
{
Con_Printf( S_USAGE "setgl <variable> <value>\n" );
return;
}
Cvar_FullSet( Cmd_Argv( 1 ), Cmd_Argv( 2 ), FCVAR_GLCONFIG );
Cvar_SetGL( Cmd_Argv( 1 ), Cmd_Argv( 2 ) );
}
/*
@ -884,7 +933,7 @@ void Cvar_Init( void )
cmd_scripting = Cvar_Get( "cmd_scripting", "0", FCVAR_ARCHIVE, "enable simple condition checking and variable operations" );
Cvar_RegisterVariable (&host_developer); // early registering for dev
Cmd_AddCommand( "setgl", Cvar_SetGL_f, "create or change the value of a opengl variable" ); // OBSOLETE
Cmd_AddCommand( "setgl", Cvar_SetGL_f, "change the value of a opengl variable" ); // OBSOLETE
Cmd_AddCommand( "toggle", Cvar_Toggle_f, "toggles a console variable's values (use for more info)" );
Cmd_AddCommand( "reset", Cvar_Reset_f, "reset any type variable to initial value" );
Cmd_AddCommand( "cvarlist", Cvar_List_f, "display all console variables beginning with the specified prefix" );

View file

@ -43,6 +43,7 @@ typedef struct convar_s
#define FCVAR_ALLOCATED (1<<19) // this convar_t is fully dynamic allocated (include description)
#define FCVAR_VIDRESTART (1<<20) // recreate the window is cvar with this flag was changed
#define FCVAR_TEMPORARY (1<<21) // these cvars holds their values and can be unlink in any time
#define FCVAR_LOCALONLY (1<<22) // can be set only from local buffers
#define CVAR_DEFINE( cv, cvname, cvstr, cvflags, cvdesc ) convar_t cv = { cvname, cvstr, cvflags, 0.0f, (void *)CVAR_SENTINEL, cvdesc }
#define CVAR_DEFINE_AUTO( cv, cvstr, cvflags, cvdesc ) convar_t cv = { #cv, cvstr, cvflags, 0.0f, (void *)CVAR_SENTINEL, cvdesc }
@ -63,9 +64,10 @@ float Cvar_VariableValue( const char *var_name );
int Cvar_VariableInteger( const char *var_name );
const char *Cvar_VariableString( const char *var_name );
void Cvar_WriteVariables( file_t *f, int group );
qboolean Cvar_Exists( const char *var_name );
void Cvar_Reset( const char *var_name );
void Cvar_SetCheatState( void );
qboolean Cvar_Command( void );
qboolean Cvar_Command( convar_t *v );
void Cvar_Init( void );
void Cvar_Unlink( int group );

Some files were not shown because too many files have changed in this diff Show more