Merge remote-tracking branch 'upstream/master' into merge-from-upstream-2023-02-16
This commit is contained in:
commit
604bd702d4
|
@ -23,17 +23,20 @@ jobs:
|
||||||
# targetos: linux
|
# targetos: linux
|
||||||
# targetarch: aarch64
|
# targetarch: aarch64
|
||||||
|
|
||||||
# - os: ubuntu-18.04
|
# - os: ubuntu-18.04
|
||||||
# targetos: android
|
# targetos: android
|
||||||
# targetarch: 32
|
# targetarch: 32
|
||||||
# - os: ubuntu-18.04
|
# - os: ubuntu-18.04
|
||||||
# targetos: android
|
# targetos: android
|
||||||
# targetarch: 64
|
# targetarch: 64
|
||||||
|
|
||||||
# - os: ubuntu-18.04
|
# - os: ubuntu-18.04
|
||||||
# targetos: motomagx
|
# targetos: motomagx
|
||||||
# targetarch: armv6
|
# targetarch: armv6
|
||||||
|
|
||||||
|
- os: ubuntu-20.04
|
||||||
|
targetos: nswitch
|
||||||
|
targetarch: arm64
|
||||||
- os: windows-latest
|
- os: windows-latest
|
||||||
targetos: win32
|
targetos: win32
|
||||||
targetarch: amd64
|
targetarch: amd64
|
||||||
|
@ -41,7 +44,7 @@ jobs:
|
||||||
targetos: win32
|
targetos: win32
|
||||||
targetarch: i386
|
targetarch: i386
|
||||||
env:
|
env:
|
||||||
SDL_VERSION: 2.0.14
|
SDL_VERSION: 2.26.2
|
||||||
VULKAN_SDK_VERSION: 1.2.176.1
|
VULKAN_SDK_VERSION: 1.2.176.1
|
||||||
GH_CPU_ARCH: ${{ matrix.targetarch }}
|
GH_CPU_ARCH: ${{ matrix.targetarch }}
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
@ -49,25 +52,42 @@ jobs:
|
||||||
UPLOADTOOL_ISPRERELEASE: true
|
UPLOADTOOL_ISPRERELEASE: true
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
- name: Checkout xash-extras
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
repository: FWGS/xash-extras
|
|
||||||
path: xash-extras
|
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: bash scripts/gha/deps_${{ matrix.targetos }}.sh
|
run: bash scripts/gha/deps_${{ matrix.targetos }}.sh
|
||||||
|
|
||||||
- name: Build engine
|
- name: Build engine
|
||||||
run: bash scripts/gha/build_${{ matrix.targetos }}.sh
|
run: bash scripts/gha/build_${{ matrix.targetos }}.sh
|
||||||
|
|
||||||
- name: Upload engine (prereleases)
|
- name: Upload engine (prereleases)
|
||||||
run: bash scripts/continious_upload.sh artifacts/*
|
run: bash scripts/continious_upload.sh artifacts/*
|
||||||
- name: Upload engine (artifacts)
|
- name: Upload engine (artifacts)
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: artifact-${{ matrix.targetos }}-${{ matrix.targetarch }}
|
name: artifact-${{ matrix.targetos }}-${{ matrix.targetarch }}
|
||||||
path: artifacts/*
|
path: artifacts/*
|
||||||
|
flatpak:
|
||||||
|
name: "Flatpak"
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- app: su.xash.Engine.Compat.i386
|
||||||
|
container:
|
||||||
|
image: bilelmoussaoui/flatpak-github-actions:freedesktop-22.08
|
||||||
|
options: --privileged
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
UPLOADTOOL_ISPRERELEASE: true
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
- name: Build flatpak (Compat.i386)
|
||||||
|
uses: FWGS/flatpak-github-actions/flatpak-builder@v5
|
||||||
|
with:
|
||||||
|
bundle: ${{ matrix.app }}.flatpak
|
||||||
|
manifest-path: scripts/flatpak/${{ matrix.app }}.yml
|
||||||
|
- name: Upload engine (prereleases)
|
||||||
|
run: bash scripts/continious_upload.sh ${{ matrix.app }}.flatpak
|
||||||
|
|
|
@ -338,3 +338,4 @@ core
|
||||||
*.code-workspace
|
*.code-workspace
|
||||||
.history/*
|
.history/*
|
||||||
.cache/*
|
.cache/*
|
||||||
|
enc_temp_folder/
|
||||||
|
|
|
@ -1,16 +1,21 @@
|
||||||
[submodule "mainui"]
|
[submodule "mainui"]
|
||||||
path = mainui
|
path = 3rdparty/mainui
|
||||||
url = https://github.com/zgdump/mainui_cpp
|
url = https://github.com/FWGS/mainui_cpp
|
||||||
branch = vk_menu
|
|
||||||
[submodule "ref_gl/nanogl"]
|
[submodule "ref_gl/nanogl"]
|
||||||
path = ref_gl/nanogl
|
path = 3rdparty/nanogl
|
||||||
url = https://github.com/FWGS/nanogl
|
url = https://github.com/FWGS/nanogl
|
||||||
[submodule "ref_gl/gl-wes-v2"]
|
[submodule "ref_gl/gl-wes-v2"]
|
||||||
path = ref_gl/gl-wes-v2
|
path = 3rdparty/gl-wes-v2
|
||||||
url = https://github.com/FWGS/gl-wes-v2
|
url = https://github.com/FWGS/gl-wes-v2
|
||||||
[submodule "ref_gl/gl4es"]
|
[submodule "ref_gl/gl4es"]
|
||||||
path = ref_gl/gl4es
|
path = 3rdparty/gl4es/gl4es
|
||||||
url = https://github.com/ptitSeb/gl4es
|
url = https://github.com/ptitSeb/gl4es
|
||||||
[submodule "vgui_support"]
|
[submodule "vgui_support"]
|
||||||
path = vgui_support
|
path = 3rdparty/vgui_support
|
||||||
url = https://github.com/FWGS/vgui_support
|
url = https://github.com/FWGS/vgui_support
|
||||||
|
[submodule "opus"]
|
||||||
|
path = 3rdparty/opus/opus
|
||||||
|
url = https://github.com/xiph/opus
|
||||||
|
[submodule "3rdparty/xash-extras"]
|
||||||
|
path = 3rdparty/extras/xash-extras
|
||||||
|
url = https://github.com/FWGS/xash-extras
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
#! /usr/bin/env python
|
||||||
|
# encoding: utf-8
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
def options(opt):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def configure(conf):
|
||||||
|
if not conf.path.find_dir('xash-extras'):
|
||||||
|
conf.fatal('Can\'t find xash-extras submodule.')
|
||||||
|
return
|
||||||
|
|
||||||
|
conf.load('zip')
|
||||||
|
|
||||||
|
def build(bld):
|
||||||
|
srcdir = bld.path.find_dir('xash-extras')
|
||||||
|
|
||||||
|
if bld.env.DEST_OS in ['android']:
|
||||||
|
install_path = bld.env.PREFIX
|
||||||
|
else:
|
||||||
|
install_path = os.path.join(bld.env.SHAREDIR, bld.env.GAMEDIR)
|
||||||
|
|
||||||
|
bld(features='zip',
|
||||||
|
name = 'extras.pk3',
|
||||||
|
files = srcdir.ant_glob('**/*'),
|
||||||
|
relative_to = srcdir,
|
||||||
|
compresslevel = 0,
|
||||||
|
install_path = install_path)
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 9aba4527435b1beda97ca8d8a5f1937cd0088c57
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 0be6803f816b5cc3a9f7b990f3d19449559eb0bd
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 277be116c1fce0c0344ab41359aeadfa7f023b93
|
|
@ -0,0 +1,24 @@
|
||||||
|
#! /usr/bin/env python
|
||||||
|
# encoding: utf-8
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
def options(opt):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def configure(conf):
|
||||||
|
if not conf.path.find_dir('gl4es') or not conf.path.find_dir('gl4es/src'):
|
||||||
|
conf.fatal('Can\'t find gl4es submodule. Run `git submodule update --init --recursive`.')
|
||||||
|
return
|
||||||
|
|
||||||
|
def build(bld):
|
||||||
|
gl4es_srcdir = bld.path.find_node('gl4es/src')
|
||||||
|
|
||||||
|
bld.stlib(source = gl4es_srcdir.ant_glob(['gl/*.c', 'gl/*/*.c', 'glx/hardext.c']),
|
||||||
|
target = 'gl4es',
|
||||||
|
features = 'c',
|
||||||
|
includes = ['gl4es/src', 'gl4es/src/gl', 'gl4es/src/glx', 'gl4es/include'],
|
||||||
|
defines = ['NOX11', 'NO_GBM', 'NO_INIT_CONSTRUCTOR', 'DEFAULT_ES=2', 'NOEGL', 'EXTERNAL_GETPROCADDRESS=GL4ES_GetProcAddress', 'NO_LOADER', 'STATICLIB'],
|
||||||
|
cflags = ['-w', '-fvisibility=hidden', '-std=gnu99'],
|
||||||
|
subsystem = bld.env.MSVC_SUBSYSTEM,
|
||||||
|
export_includes = '.')
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 2f615a74802e665014cddaf766e4edc2bac24a55
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 5f2892a37e70e8baaccecfba84be424d2bd29aa7
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 997fdf54e781ae1c04dee42018f35388a04fe483
|
|
@ -0,0 +1,40 @@
|
||||||
|
#! /usr/bin/env python
|
||||||
|
# encoding: utf-8
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
def options(opt):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def configure(conf):
|
||||||
|
if not conf.path.find_dir('opus') or not conf.path.find_dir('opus/src'):
|
||||||
|
conf.fatal('Can\'t find opus submodule. Run `git submodule update --init --recursive`.')
|
||||||
|
return
|
||||||
|
|
||||||
|
# TODO: ARM/x86 intrinsics detection
|
||||||
|
# TODO: maybe call autotools/cmake/meson instead?
|
||||||
|
|
||||||
|
def build(bld):
|
||||||
|
sources = bld.path.ant_glob([
|
||||||
|
'opus/src/*.c',
|
||||||
|
'opus/celt/*.c',
|
||||||
|
'opus/silk/*.c',
|
||||||
|
'opus/silk/float/*.c'
|
||||||
|
], excl = [
|
||||||
|
'opus/src/repacketizer_demo.c',
|
||||||
|
'opus/src/opus_demo.c',
|
||||||
|
'opus/src/opus_compare.c',
|
||||||
|
'opus/celt/opus_custom_demo.c'
|
||||||
|
])
|
||||||
|
includes = ['opus/include/', 'opus/celt/', 'opus/silk/', 'opus/silk/float/']
|
||||||
|
defines = ['USE_ALLOCA', 'OPUS_BUILD', 'FLOAT_APPROX', 'PACKAGE_VERSION="1.3.1"', 'CUSTOM_MODES']
|
||||||
|
|
||||||
|
bld.stlib(
|
||||||
|
source = sources,
|
||||||
|
target = 'opus',
|
||||||
|
features = 'c',
|
||||||
|
includes = includes,
|
||||||
|
defines = defines,
|
||||||
|
subsystem = bld.env.MSVC_SUBSYSTEM,
|
||||||
|
export_includes = ['opus/include/']
|
||||||
|
)
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 63c134f188e7c0891927f5a4149f4444b43b0be8
|
|
@ -0,0 +1,17 @@
|
||||||
|
# Bug-compatibility in Xash3D FWGS
|
||||||
|
|
||||||
|
Xash3D FWGS has special mode for games that rely on original engine bugs.
|
||||||
|
|
||||||
|
In this mode, we emulate the behaviour of selected functions that may help running mods relying on engine bugs, but enabling them by default may break majority of other games.
|
||||||
|
|
||||||
|
At this time, we only have implemented GoldSrc bug-compatibility. It can be enabled with `-bugcomp` command line switch.
|
||||||
|
|
||||||
|
## GoldSrc bug-compatibility
|
||||||
|
|
||||||
|
### Emulated bugs
|
||||||
|
|
||||||
|
* `pfnPEntityOfEntIndex` in GoldSrc returns NULL for last player due to incorrect player index comparison
|
||||||
|
|
||||||
|
### Games and mods that require this
|
||||||
|
|
||||||
|
* Counter-Strike: Condition Zero - Deleted Scenes
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Cross-compiling for Windows with Wine
|
||||||
|
|
||||||
|
This can be useful to test engine in Wine without using virtual machines or dual-booting to Windows.
|
||||||
|
|
||||||
|
0. Clone and install https://github.com/mstorsjo/msvc-wine (you can skip CMake part)
|
||||||
|
1. Set environment variable MSVC_WINE_PATH to the path to installed MSVC toolchain
|
||||||
|
2. Pre-load wine: `wineserver -k; wineserver -p; wine64 wineboot`
|
||||||
|
3. Run `./waf configure -T <build-type> --enable-wine-msvc --sdl2=../SDL2_VC`. Configuration step will take more time than usual.
|
||||||
|
4. .. other typical steps to build from console ...
|
|
@ -0,0 +1,150 @@
|
||||||
|
# There are few new commands availiable in xash3d fork:
|
||||||
|
|
||||||
|
## Commands:
|
||||||
|
### ent_create
|
||||||
|
Create entity with specified classname and key/values
|
||||||
|
|
||||||
|
`ent_create <classname> <key> <value> <key> <value> ...`
|
||||||
|
|
||||||
|
for example:
|
||||||
|
|
||||||
|
`ent_create monster_zombie targetname zomb1`
|
||||||
|
|
||||||
|
after creating entity, ent_last_xxx cvars are set to new entity and ent_last_cb called, look at ent_getvars description
|
||||||
|
|
||||||
|
### ent_fire
|
||||||
|
|
||||||
|
Make some actions on entity
|
||||||
|
|
||||||
|
`ent_fire <pattern> <command> <args>`
|
||||||
|
Availiavle commands:
|
||||||
|
* Set fields (Only set entity field, does not call any functions):
|
||||||
|
* health
|
||||||
|
* gravity
|
||||||
|
* movetype
|
||||||
|
* solid
|
||||||
|
* rendermode
|
||||||
|
* rendercolor (vector)
|
||||||
|
* renderfx
|
||||||
|
* renderamt
|
||||||
|
* hullmin (vector)
|
||||||
|
* hullmax (vector)
|
||||||
|
* Actions
|
||||||
|
* rename: set entity targetname
|
||||||
|
* settarget: set entity target (only targetnames)
|
||||||
|
* setmodel: set entity model (does not update)
|
||||||
|
* set: set key/value by server library
|
||||||
|
* See game FGD to get list.
|
||||||
|
* command takes two arguments
|
||||||
|
* touch: touch entity by current player.
|
||||||
|
* use: use entity by current player.
|
||||||
|
* movehere: place entity in player fov.
|
||||||
|
* drop2floor: place entity to nearest floor surface
|
||||||
|
* moveup: move entity to 25 units up
|
||||||
|
* moveup (value): move by y axis relatively to specified value
|
||||||
|
* Flags (Set/clear specified flag bit, arg is bit number):
|
||||||
|
* setflag
|
||||||
|
* clearflag
|
||||||
|
* setspawnflag
|
||||||
|
* clearspawnflag
|
||||||
|
|
||||||
|
### ent_info
|
||||||
|
Print information about entity by identificator
|
||||||
|
|
||||||
|
`ent_info <identificator>`
|
||||||
|
|
||||||
|
### ent_getvars
|
||||||
|
Set client cvars containing entity information (useful for [[Scripting]]) and call ent_last_cb
|
||||||
|
|
||||||
|
`ent_getvars <identificator>`
|
||||||
|
|
||||||
|
These cvars are set:
|
||||||
|
```
|
||||||
|
ent_last_name
|
||||||
|
ent_last_num
|
||||||
|
ent_last_inst
|
||||||
|
ent_last_origin
|
||||||
|
ent_last_class
|
||||||
|
```
|
||||||
|
|
||||||
|
### ent_list
|
||||||
|
Print short information about antities, filtered by pattern
|
||||||
|
|
||||||
|
`ent_list <pattern>`
|
||||||
|
|
||||||
|
## Syntax description
|
||||||
|
|
||||||
|
### \<identificator\>
|
||||||
|
|
||||||
|
* !cross: entity under aim
|
||||||
|
* Instance code: !\<number\>_\<seria\l>
|
||||||
|
* set by ent_getvars command
|
||||||
|
* Entity index
|
||||||
|
* targetname pattern
|
||||||
|
|
||||||
|
### \<pattern\>
|
||||||
|
|
||||||
|
Pattern is like identificator, but may filter many entities by classname
|
||||||
|
|
||||||
|
### (vector)
|
||||||
|
|
||||||
|
used by ent_fire command. vector means three float values, entered without quotes
|
||||||
|
|
||||||
|
### key/value
|
||||||
|
|
||||||
|
All entities parameters may be set by specifiing key and value strings.
|
||||||
|
|
||||||
|
Originally, this mechanizm is used in map/bsp format, but it can be used in enttools too.
|
||||||
|
|
||||||
|
Keys and values are passed to server library and processed by entity keyvalue function, setting edict and entity owns parameters.
|
||||||
|
|
||||||
|
If value contains spaces, it must be put in quotes:
|
||||||
|
|
||||||
|
`ent_fire !cross set origin "0 0 0"`
|
||||||
|
|
||||||
|
## Using with scripting
|
||||||
|
|
||||||
|
ent_create and ent_getvars commands are setting cvars on client
|
||||||
|
|
||||||
|
It can be used with ent_last_cb alias that is executed after setting cvars.
|
||||||
|
|
||||||
|
Simple example:
|
||||||
|
|
||||||
|
```
|
||||||
|
ent_create weapon_c4
|
||||||
|
alias ent_last_cb "ent_fire \$ent_last_inst use"
|
||||||
|
```
|
||||||
|
|
||||||
|
Use weapon_c4 after creating it.
|
||||||
|
|
||||||
|
Note that you cannot use many dfferent callbacks at the same time.
|
||||||
|
|
||||||
|
You can set entity name by by pattern and create special script, contatning all callbacks.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
example.cfg
|
||||||
|
```
|
||||||
|
alias ent_last_cb exec entity_cb.cfg
|
||||||
|
ent create \<class\> targetname my_ent1_$name
|
||||||
|
ent_create \<class\> targetname my_ent2_$name
|
||||||
|
```
|
||||||
|
entity_cb.cfg
|
||||||
|
```
|
||||||
|
if $ent_last_name == my_ent1_$name
|
||||||
|
:(ent1 actions)
|
||||||
|
if $ent_last_name == my_ent2_$name
|
||||||
|
:(ent2 actions)
|
||||||
|
```
|
||||||
|
Note that scripting cannot be blocking. You cannot wait for server answer and continue. But you can use small scripts, connected with ent_last_cb command. The best usage is user interaction. You can add touch buttons to screen or call user command menu actions by callbacks.
|
||||||
|
## Server side
|
||||||
|
|
||||||
|
To enable entity tools on server, set sv_enttools_enable to 1
|
||||||
|
|
||||||
|
To change maximum number of entities, touched by ent_fire, change sv_enttools_maxfire to required number.
|
||||||
|
|
||||||
|
To enable actions on players, set sv_enttools_players to 1.
|
||||||
|
|
||||||
|
To enable entity tools for player by nickname, set sv_enttools_godplayer to nickname. Useful to temporary enable from rcon.
|
||||||
|
|
||||||
|
To prevent crash on some actions, set host_mapdesign_fatal to 0
|
|
@ -0,0 +1,8 @@
|
||||||
|
# Expanded structures that used by engine and mods
|
||||||
|
To make porting and developing mods on 64-bit platforms less painful, we decided to expand size of several structures.
|
||||||
|
This information important in case you are using codebase like XashXT, Paranoia 2: Savior and want to compile your mod for platform with 64-bit pointer size: you should replace old definitions with new ones, otherwise your mod will not work with Xash3D FWGS (typically, it's just crashing when starting map).
|
||||||
|
| Structure name | Locates in file | Original size on 64-bit | Current size on 64-bit |
|
||||||
|
|----------------|-----------------|-------------------------|------------------------|
|
||||||
|
|`mfaceinfo_t` | `common/com_model.h` | 176 bytes | 304 bytes |
|
||||||
|
|`decal_s` | `common/com_model.h` | 72 bytes | 88 bytes |
|
||||||
|
|`mextrasurf_t` | `common/com_model.h` | 376 bytes | 504 bytes |
|
|
@ -31,11 +31,14 @@ Issue #0. Inconsistency between ABI and Q_buildarch.\
|
||||||
Resolution: Change Q_buildarch return value to use Debian-styled architectures list: https://www.debian.org/ports/, which includes a special naming for big/little-endian and hard/soft-float ARM.
|
Resolution: Change Q_buildarch return value to use Debian-styled architectures list: https://www.debian.org/ports/, which includes a special naming for big/little-endian and hard/soft-float ARM.
|
||||||
|
|
||||||
Issue #1: Build-system integration.\
|
Issue #1: Build-system integration.\
|
||||||
Resolution: implemented as [LibraryNaming.cmake](https://github.com/FWGS/hlsdk-xash3d/blob/master/cmake/LibraryNaming.cmake) and [library_naming.py](https://github.com/FWGS/hlsdk-xash3d/blob/master/scripts/waifulib/library_naming.py) extensions, see
|
Resolution: implemented as [LibraryNaming.cmake](https://github.com/FWGS/hlsdk-portable/blob/master/cmake/LibraryNaming.cmake) and [library_naming.py](https://github.com/FWGS/hlsdk-portable/blob/master/scripts/waifulib/library_naming.py) extensions, see
|
||||||
|
|
||||||
Issue #2(related to #0): Which ARM flavours we actually need to handle?\
|
Issue #2(related to #0): Which ARM flavours we actually need to handle?\
|
||||||
Resolution: Little-endian only, as there is no known big-endian ARM platforms in the wild.
|
Resolution: Little-endian only, as there is no known big-endian ARM platforms in the wild.
|
||||||
Architecture is coded this way:
|
Architecture is coded this way:
|
||||||
* ```armvxy```, where `x` is ARM instruction set level and `y` is hard-float ABI presence: `hf` where hard float ABI used, otherwise `l`.
|
* ```armvxy```, where `x` is ARM instruction set level and `y` is hard-float ABI presence: `hf` where hard float ABI used, otherwise `l`.
|
||||||
|
|
||||||
|
Issue #3: Some mods (like The Specialists, Tyrian, ...) already apply suffixes _i386, _i686 to the gamedll path:\
|
||||||
|
Resolution: On x86 on **Win/Lin/Mac**, don't change anything. Otherwise, strip the _i?86 part and follow the usual scheme.
|
||||||
|
|
||||||
See discussion: https://github.com/FWGS/xash3d-fwgs/issues/39
|
See discussion: https://github.com/FWGS/xash3d-fwgs/issues/39
|
||||||
|
|
|
@ -127,6 +127,9 @@ Official github repository - https://github.com/unknownworlds/NS
|
||||||
## Overturn
|
## Overturn
|
||||||
Available in mod archive on ModDB - https://www.moddb.com/mods/overturn
|
Available in mod archive on ModDB - https://www.moddb.com/mods/overturn
|
||||||
|
|
||||||
|
## Oz Deathmatch
|
||||||
|
Mirrored on github - https://github.com/nekonomicon/OZDM
|
||||||
|
|
||||||
## Spirit of Half-Life
|
## Spirit of Half-Life
|
||||||
[Logic&Trick's](https://github.com/LogicAndTrick) mirror - https://files.logic-and-trick.com/#/Half-Life/Mods/Spirit%20of%20Half-Life
|
[Logic&Trick's](https://github.com/LogicAndTrick) mirror - https://files.logic-and-trick.com/#/Half-Life/Mods/Spirit%20of%20Half-Life
|
||||||
|
|
||||||
|
|
17
README.md
17
README.md
|
@ -58,19 +58,22 @@ Read more about Xash3D on ModDB: https://www.moddb.com/engines/xash3d-engine
|
||||||
* Mobility API: allows better game integration on mobile devices(vibration, touch controls)
|
* Mobility API: allows better game integration on mobile devices(vibration, touch controls)
|
||||||
* Different input methods: touch, gamepad and classic mouse & keyboard.
|
* Different input methods: touch, gamepad and classic mouse & keyboard.
|
||||||
* TrueType font rendering, as a part of mainui_cpp.
|
* TrueType font rendering, as a part of mainui_cpp.
|
||||||
* Multiple renderers support: OpenGL, GLESv1, GLESv2, Software
|
* Multiple renderers support: OpenGL, GLESv1, GLESv2, Software.
|
||||||
|
* Voice support.
|
||||||
|
* External filesystem module like in GoldSrc engine.
|
||||||
|
* External vgui support module.
|
||||||
|
* PNG image format support.
|
||||||
* A set of small improvements, without broken compatibility.
|
* A set of small improvements, without broken compatibility.
|
||||||
|
|
||||||
## Planned fork features
|
## Planned fork features
|
||||||
* Virtual Reality support and game API
|
* Virtual Reality support and game API.
|
||||||
* Voice support
|
* Vulkan renderer.
|
||||||
* Vulkan renderer
|
|
||||||
|
|
||||||
## Installation & Running
|
## Installation & Running
|
||||||
0) Get Xash3D FWGS binaries: you can use [testing](https://github.com/FWGS/xash3d-fwgs/releases/tag/continuous) build or you can compile engine from source code.
|
0) Get Xash3D FWGS binaries: you can use [testing](https://github.com/FWGS/xash3d-fwgs/releases/tag/continuous) build or you can compile engine from source code.
|
||||||
1) Copy engine binaries to some directory.
|
1) Copy engine binaries to some directory.
|
||||||
2) Copy `valve` directory from [Half-Life](https://store.steampowered.com/app/70/HalfLife/) to directory with engine binaries.
|
2) Copy `valve` directory from [Half-Life](https://store.steampowered.com/app/70/HalfLife/) to directory with engine binaries.
|
||||||
If your CPU is NOT x86 compatible or you're running 64-bit version of the engine, you may want to compile [Half-Life SDK](https://github.com/FWGS/hlsdk-xash3d).
|
If your CPU is NOT x86 compatible or you're running 64-bit version of the engine, you may want to compile [Half-Life SDK](https://github.com/FWGS/hlsdk-portable).
|
||||||
This repository contains our fork of HLSDK and restored source code for some of the mods. Not all of them, of course.
|
This repository contains our fork of HLSDK and restored source code for some of the mods. Not all of them, of course.
|
||||||
You still needed to copy `valve` directory as all game resources located there.
|
You still needed to copy `valve` directory as all game resources located there.
|
||||||
3) Run the main executable (`xash3d.exe` or AppImage).
|
3) Run the main executable (`xash3d.exe` or AppImage).
|
||||||
|
@ -89,10 +92,10 @@ NOTE: NEVER USE GitHub's ZIP ARCHIVES. GitHub doesn't include external dependenc
|
||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
If your CPU is x86 compatible, we are building 32-bit code by default. This was dont for keeping compatibility with Steam releases of Half-Life and based on it's engine games.
|
If your CPU is x86 compatible, we are building 32-bit code by default. This was done to maintain compatibility with Steam releases of Half-Life and based on it's engine games.
|
||||||
Even if Xash3D FWGS does support targetting 64-bit, you can't load games without recompiling them from source code!
|
Even if Xash3D FWGS does support targetting 64-bit, you can't load games without recompiling them from source code!
|
||||||
|
|
||||||
If your CPU is NOT x86 compatible or you decided build 64-bit version of engine, you may want to compile [Half-Life SDK](https://github.com/FWGS/hlsdk-xash3d).
|
If your CPU is NOT x86 compatible or you decided build 64-bit version of engine, you may want to compile [Half-Life SDK](https://github.com/FWGS/hlsdk-portable).
|
||||||
This repository contains our fork of HLSDK and restored source code for some of the mods. Not all of them, of course.
|
This repository contains our fork of HLSDK and restored source code for some of the mods. Not all of them, of course.
|
||||||
|
|
||||||
#### Windows (Visual Studio)
|
#### Windows (Visual Studio)
|
||||||
|
|
|
@ -29,12 +29,6 @@ GNU General Public License for more details.
|
||||||
#define SOUND_OPENSLES 2
|
#define SOUND_OPENSLES 2
|
||||||
#define SOUND_ALSA 3
|
#define SOUND_ALSA 3
|
||||||
|
|
||||||
// crash handler (XASH_CRASHHANDLER)
|
|
||||||
#define CRASHHANDLER_NULL 0
|
|
||||||
#define CRASHHANDLER_UCONTEXT 1
|
|
||||||
#define CRASHHANDLER_DBGHELP 2
|
|
||||||
#define CRASHHANDLER_WIN32 3
|
|
||||||
|
|
||||||
// input (XASH_INPUT)
|
// input (XASH_INPUT)
|
||||||
#define INPUT_NULL 0
|
#define INPUT_NULL 0
|
||||||
#define INPUT_SDL 1
|
#define INPUT_SDL 1
|
||||||
|
@ -53,6 +47,7 @@ GNU General Public License for more details.
|
||||||
#define MSGBOX_SDL 1
|
#define MSGBOX_SDL 1
|
||||||
#define MSGBOX_ANDROID 2
|
#define MSGBOX_ANDROID 2
|
||||||
#define MSGBOX_WIN32 3
|
#define MSGBOX_WIN32 3
|
||||||
|
#define MSGBOX_NSWITCH 4
|
||||||
|
|
||||||
|
|
||||||
// library loading (XASH_LIB)
|
// library loading (XASH_LIB)
|
||||||
|
|
|
@ -61,23 +61,27 @@ BRUSH MODELS
|
||||||
#define LS_UNUSED 0xFE
|
#define LS_UNUSED 0xFE
|
||||||
#define LS_NONE 0xFF
|
#define LS_NONE 0xFF
|
||||||
|
|
||||||
|
#define MAX_MAP_CLIPNODES_HLBSP 32767
|
||||||
|
#define MAX_MAP_CLIPNODES_BSP2 524288
|
||||||
|
|
||||||
// these limis not using by modelloader but only for displaying 'mapstats' correctly
|
// these limis not using by modelloader but only for displaying 'mapstats' correctly
|
||||||
#ifdef SUPPORT_BSP2_FORMAT
|
#ifdef SUPPORT_BSP2_FORMAT
|
||||||
#define MAX_MAP_MODELS 2048 // embedded models
|
#define MAX_MAP_MODELS 2048 // embedded models
|
||||||
#define MAX_MAP_ENTSTRING 0x200000 // 2 Mb should be enough
|
#define MAX_MAP_ENTSTRING 0x200000 // 2 Mb should be enough
|
||||||
#define MAX_MAP_PLANES 131072 // can be increased without problems
|
#define MAX_MAP_PLANES 131072 // can be increased without problems
|
||||||
#define MAX_MAP_NODES 262144 // can be increased without problems
|
#define MAX_MAP_NODES 262144 // can be increased without problems
|
||||||
#define MAX_MAP_CLIPNODES 524288 // can be increased without problems
|
#define MAX_MAP_CLIPNODES MAX_MAP_CLIPNODES_BSP2 // can be increased without problems
|
||||||
#define MAX_MAP_LEAFS 131072 // CRITICAL STUFF to run ad_sepulcher!!!
|
#define MAX_MAP_LEAFS 131072 // CRITICAL STUFF to run ad_sepulcher!!!
|
||||||
#define MAX_MAP_VERTS 524288 // can be increased without problems
|
#define MAX_MAP_VERTS 524288 // can be increased without problems
|
||||||
#define MAX_MAP_FACES 262144 // can be increased without problems
|
#define MAX_MAP_FACES 262144 // can be increased without problems
|
||||||
#define MAX_MAP_MARKSURFACES 524288 // can be increased without problems
|
#define MAX_MAP_MARKSURFACES 524288 // can be increased without problems
|
||||||
#else
|
#else
|
||||||
#define MAX_MAP_MODELS 768 // embedded models
|
// increased to match PrimeXT compilers
|
||||||
|
#define MAX_MAP_MODELS 1024 // embedded models
|
||||||
#define MAX_MAP_ENTSTRING 0x100000 // 1 Mb 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_PLANES 65536 // can be increased without problems
|
||||||
#define MAX_MAP_NODES 32767 // because negative shorts are leafs
|
#define MAX_MAP_NODES 32767 // because negative shorts are leafs
|
||||||
#define MAX_MAP_CLIPNODES 32767 // because negative shorts are contents
|
#define MAX_MAP_CLIPNODES MAX_MAP_CLIPNODES_HLBSP // because negative shorts are contents
|
||||||
#define MAX_MAP_LEAFS 32767 // signed short limit
|
#define MAX_MAP_LEAFS 32767 // signed short limit
|
||||||
#define MAX_MAP_VERTS 65535 // unsigned short limit
|
#define MAX_MAP_VERTS 65535 // unsigned short limit
|
||||||
#define MAX_MAP_FACES 65535 // unsigned short limit
|
#define MAX_MAP_FACES 65535 // unsigned short limit
|
||||||
|
|
|
@ -49,6 +49,7 @@ typedef enum
|
||||||
IL_DDS_HARDWARE = BIT(4), // DXT compression is support
|
IL_DDS_HARDWARE = BIT(4), // DXT compression is support
|
||||||
IL_LOAD_DECAL = BIT(5), // special mode for load gradient decals
|
IL_LOAD_DECAL = BIT(5), // special mode for load gradient decals
|
||||||
IL_OVERVIEW = BIT(6), // overview required some unque operations
|
IL_OVERVIEW = BIT(6), // overview required some unque operations
|
||||||
|
IL_LOAD_PLAYER_DECAL = BIT(7), // special mode for player decals
|
||||||
} ilFlags_t;
|
} ilFlags_t;
|
||||||
|
|
||||||
// goes into rgbdata_t->encode
|
// goes into rgbdata_t->encode
|
||||||
|
|
|
@ -105,7 +105,7 @@ typedef struct
|
||||||
|
|
||||||
vec3_t mins, maxs; // terrain bounds (fill by user)
|
vec3_t mins, maxs; // terrain bounds (fill by user)
|
||||||
|
|
||||||
int reserved[32]; // just for future expansions or mod-makers
|
intptr_t reserved[32]; // just for future expansions or mod-makers
|
||||||
} mfaceinfo_t;
|
} mfaceinfo_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -174,7 +174,7 @@ struct decal_s
|
||||||
// Xash3D specific
|
// Xash3D specific
|
||||||
vec3_t position; // location of the decal center in world space.
|
vec3_t position; // location of the decal center in world space.
|
||||||
glpoly_t *polys; // precomputed decal vertices
|
glpoly_t *polys; // precomputed decal vertices
|
||||||
int reserved[4]; // just for future expansions or mod-makers
|
intptr_t reserved[4]; // just for future expansions or mod-makers
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct mleaf_s
|
typedef struct mleaf_s
|
||||||
|
@ -228,7 +228,7 @@ typedef struct mextrasurf_s
|
||||||
unsigned short numverts; // world->vertexes[]
|
unsigned short numverts; // world->vertexes[]
|
||||||
int firstvertex; // fisrt look up in tr.tbn_vectors[], then acess to world->vertexes[]
|
int firstvertex; // fisrt look up in tr.tbn_vectors[], then acess to world->vertexes[]
|
||||||
|
|
||||||
int reserved[32]; // just for future expansions or mod-makers
|
intptr_t reserved[32]; // just for future expansions or mod-makers
|
||||||
} mextrasurf_t;
|
} mextrasurf_t;
|
||||||
|
|
||||||
struct msurface_s
|
struct msurface_s
|
||||||
|
|
|
@ -47,7 +47,9 @@ SETUP BACKENDS DEFINITIONS
|
||||||
#endif // XASH_TIMER
|
#endif // XASH_TIMER
|
||||||
|
|
||||||
#ifndef XASH_MESSAGEBOX
|
#ifndef XASH_MESSAGEBOX
|
||||||
|
#if !XASH_NSWITCH // SDL2 messageboxes not available
|
||||||
#define XASH_MESSAGEBOX MSGBOX_SDL
|
#define XASH_MESSAGEBOX MSGBOX_SDL
|
||||||
|
#endif
|
||||||
#endif // XASH_MESSAGEBOX
|
#endif // XASH_MESSAGEBOX
|
||||||
#endif
|
#endif
|
||||||
#elif XASH_ANDROID
|
#elif XASH_ANDROID
|
||||||
|
@ -105,22 +107,13 @@ SETUP BACKENDS DEFINITIONS
|
||||||
#ifndef XASH_MESSAGEBOX
|
#ifndef XASH_MESSAGEBOX
|
||||||
#if XASH_WIN32
|
#if XASH_WIN32
|
||||||
#define XASH_MESSAGEBOX MSGBOX_WIN32
|
#define XASH_MESSAGEBOX MSGBOX_WIN32
|
||||||
|
#elif XASH_NSWITCH
|
||||||
|
#define XASH_MESSAGEBOX MSGBOX_NSWITCH
|
||||||
#else // !XASH_WIN32
|
#else // !XASH_WIN32
|
||||||
#define XASH_MESSAGEBOX MSGBOX_STDERR
|
#define XASH_MESSAGEBOX MSGBOX_STDERR
|
||||||
#endif // !XASH_WIN32
|
#endif // !XASH_WIN32
|
||||||
#endif // XASH_MESSAGEBOX
|
#endif // XASH_MESSAGEBOX
|
||||||
|
|
||||||
//
|
|
||||||
// select crashhandler based on defines
|
|
||||||
//
|
|
||||||
#ifndef XASH_CRASHHANDLER
|
|
||||||
#if XASH_WIN32 && defined(DBGHELP)
|
|
||||||
#define XASH_CRASHHANDLER CRASHHANDLER_DBGHELP
|
|
||||||
#elif XASH_LINUX || XASH_BSD
|
|
||||||
#define XASH_CRASHHANDLER CRASHHANDLER_UCONTEXT
|
|
||||||
#endif // !(XASH_LINUX || XASH_BSD || XASH_WIN32)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// no timer - no xash
|
// no timer - no xash
|
||||||
//
|
//
|
||||||
|
@ -157,10 +150,6 @@ SETUP BACKENDS DEFINITIONS
|
||||||
#define XASH_INPUT INPUT_NULL
|
#define XASH_INPUT INPUT_NULL
|
||||||
#endif // XASH_INPUT
|
#endif // XASH_INPUT
|
||||||
|
|
||||||
#ifndef XASH_CRASHHANDLER
|
|
||||||
#define XASH_CRASHHANDLER CRASHHANDLER_NULL
|
|
||||||
#endif // XASH_CRASHHANDLER
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=========================================================================
|
=========================================================================
|
||||||
|
|
||||||
|
@ -169,25 +158,41 @@ Default build-depended cvar and constant values
|
||||||
=========================================================================
|
=========================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if XASH_MOBILE_PLATFORM
|
// Platform overrides
|
||||||
|
#if XASH_NSWITCH
|
||||||
|
#define DEFAULT_TOUCH_ENABLE "0"
|
||||||
|
#define DEFAULT_M_IGNORE "1"
|
||||||
|
#define DEFAULT_MODE_WIDTH 1280
|
||||||
|
#define DEFAULT_MODE_HEIGHT 720
|
||||||
|
#define DEFAULT_ALLOWCONSOLE 1
|
||||||
|
#elif XASH_MOBILE_PLATFORM
|
||||||
#define DEFAULT_TOUCH_ENABLE "1"
|
#define DEFAULT_TOUCH_ENABLE "1"
|
||||||
#define DEFAULT_M_IGNORE "1"
|
#define DEFAULT_M_IGNORE "1"
|
||||||
#else // !XASH_MOBILE_PLATFORM
|
#endif // !XASH_MOBILE_PLATFORM && !XASH_NSWITCH
|
||||||
#define DEFAULT_TOUCH_ENABLE "0"
|
|
||||||
#define DEFAULT_M_IGNORE "0"
|
|
||||||
#endif // !XASH_MOBILE_PLATFORM
|
|
||||||
|
|
||||||
#if XASH_ANDROID || XASH_IOS || XASH_EMSCRIPTEN
|
#if XASH_ANDROID || XASH_IOS || XASH_EMSCRIPTEN
|
||||||
#define XASH_INTERNAL_GAMELIBS
|
// this means that libraries are provided with engine, but not in game data
|
||||||
// this means that libraries are provided with engine, but not in game data
|
// You need add library loading code to library.c when adding new platform
|
||||||
// You need add library loading code to library.c when adding new platform
|
#define XASH_INTERNAL_GAMELIBS
|
||||||
#endif // XASH_ANDROID || XASH_IOS || XASH_EMSCRIPTEN
|
#endif // XASH_ANDROID || XASH_IOS || XASH_EMSCRIPTEN
|
||||||
|
|
||||||
// allow override for developer/debug builds
|
// Defaults
|
||||||
|
#ifndef DEFAULT_TOUCH_ENABLE
|
||||||
|
#define DEFAULT_TOUCH_ENABLE "0"
|
||||||
|
#endif // DEFAULT_TOUCH_ENABLE
|
||||||
|
|
||||||
|
#ifndef DEFAULT_M_IGNORE
|
||||||
|
#define DEFAULT_M_IGNORE "0"
|
||||||
|
#endif // DEFAULT_M_IGNORE
|
||||||
|
|
||||||
#ifndef DEFAULT_DEV
|
#ifndef DEFAULT_DEV
|
||||||
#define DEFAULT_DEV 0
|
#define DEFAULT_DEV 0
|
||||||
#endif // DEFAULT_DEV
|
#endif // DEFAULT_DEV
|
||||||
|
|
||||||
|
#ifndef DEFAULT_ALLOWCONSOLE
|
||||||
|
#define DEFAULT_ALLOWCONSOLE 0
|
||||||
|
#endif // DEFAULT_ALLOWCONSOLE
|
||||||
|
|
||||||
#ifndef DEFAULT_FULLSCREEN
|
#ifndef DEFAULT_FULLSCREEN
|
||||||
#define DEFAULT_FULLSCREEN 1
|
#define DEFAULT_FULLSCREEN 1
|
||||||
#endif // DEFAULT_FULLSCREEN
|
#endif // DEFAULT_FULLSCREEN
|
||||||
|
|
|
@ -16,22 +16,61 @@
|
||||||
#ifndef NETADR_H
|
#ifndef NETADR_H
|
||||||
#define NETADR_H
|
#define NETADR_H
|
||||||
|
|
||||||
|
#include "build.h"
|
||||||
|
#include STDINT_H
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
NA_UNUSED,
|
NA_UNUSED = 0,
|
||||||
NA_LOOPBACK,
|
NA_LOOPBACK,
|
||||||
NA_BROADCAST,
|
NA_BROADCAST,
|
||||||
NA_IP,
|
NA_IP,
|
||||||
NA_IPX,
|
NA_IPX,
|
||||||
NA_BROADCAST_IPX
|
NA_BROADCAST_IPX,
|
||||||
|
NA_IP6,
|
||||||
|
NA_MULTICAST_IP6, // all nodes multicast
|
||||||
} netadrtype_t;
|
} netadrtype_t;
|
||||||
|
|
||||||
|
// Original structure:
|
||||||
|
// typedef struct netadr_s
|
||||||
|
// {
|
||||||
|
// netadrtype_t type;
|
||||||
|
// unsigned char ip[4];
|
||||||
|
// unsigned char ipx[10];
|
||||||
|
// unsigned short port;
|
||||||
|
// } netadr_t;
|
||||||
|
|
||||||
|
#pragma pack( push, 1 )
|
||||||
typedef struct netadr_s
|
typedef struct netadr_s
|
||||||
{
|
{
|
||||||
netadrtype_t type;
|
union
|
||||||
unsigned char ip[4];
|
{
|
||||||
unsigned char ipx[10];
|
struct
|
||||||
unsigned short port;
|
{
|
||||||
|
uint32_t type;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint8_t ip[4];
|
||||||
|
uint32_t ip4;
|
||||||
|
};
|
||||||
|
uint8_t ipx[10];
|
||||||
|
};
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
#if XASH_LITTLE_ENDIAN
|
||||||
|
uint16_t type6;
|
||||||
|
uint8_t ip6[16];
|
||||||
|
#elif XASH_BIG_ENDIAN
|
||||||
|
uint8_t ip6_0[2];
|
||||||
|
uint16_t type6;
|
||||||
|
uint8_t ip6_2[14];
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
};
|
||||||
|
uint16_t port;
|
||||||
} netadr_t;
|
} netadr_t;
|
||||||
|
#pragma pack( pop )
|
||||||
|
|
||||||
|
STATIC_ASSERT( sizeof( netadr_t ) == 20, "invalid netadr_t size" );
|
||||||
|
|
||||||
#endif//NETADR_H
|
#endif//NETADR_H
|
||||||
|
|
|
@ -39,16 +39,16 @@ GNU General Public License for more details.
|
||||||
|
|
||||||
#if XASH_POSIX
|
#if XASH_POSIX
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#if XASH_NSWITCH
|
||||||
|
#define SOLDER_LIBDL_COMPAT
|
||||||
|
#include <solder.h>
|
||||||
|
#else
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
|
||||||
#define PATH_SPLITTER "/"
|
|
||||||
#define HAVE_DUP
|
#define HAVE_DUP
|
||||||
|
|
||||||
#define O_BINARY 0
|
#define O_BINARY 0
|
||||||
|
#endif
|
||||||
#define O_TEXT 0
|
#define O_TEXT 0
|
||||||
#define _mkdir( x ) mkdir( x, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH )
|
#define _mkdir( x ) mkdir( x, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH )
|
||||||
#elif XASH_DOS4GW
|
|
||||||
#define PATH_SPLITTER "\\"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef void* HANDLE;
|
typedef void* HANDLE;
|
||||||
|
@ -59,7 +59,6 @@ GNU General Public License for more details.
|
||||||
int x, y;
|
int x, y;
|
||||||
} POINT;
|
} POINT;
|
||||||
#else // WIN32
|
#else // WIN32
|
||||||
#define PATH_SPLITTER "\\"
|
|
||||||
#ifdef __MINGW32__
|
#ifdef __MINGW32__
|
||||||
#define _inline static inline
|
#define _inline static inline
|
||||||
#define FORCEINLINE inline __attribute__((always_inline))
|
#define FORCEINLINE inline __attribute__((always_inline))
|
||||||
|
|
|
@ -162,7 +162,7 @@ struct ref_viewpass_s;
|
||||||
typedef struct render_api_s
|
typedef struct render_api_s
|
||||||
{
|
{
|
||||||
// Get renderer info (doesn't changes engine state at all)
|
// Get renderer info (doesn't changes engine state at all)
|
||||||
int (*RenderGetParm)( int parm, int arg ); // generic
|
intptr_t (*RenderGetParm)( int parm, int arg ); // generic
|
||||||
void (*GetDetailScaleForTexture)( int texture, float *xScale, float *yScale );
|
void (*GetDetailScaleForTexture)( int texture, float *xScale, float *yScale );
|
||||||
void (*GetExtraParmsForTexture)( int texture, byte *red, byte *green, byte *blue, byte *alpha );
|
void (*GetExtraParmsForTexture)( int texture, byte *red, byte *green, byte *blue, byte *alpha );
|
||||||
lightstyle_t* (*GetLightStyle)( int number );
|
lightstyle_t* (*GetLightStyle)( int number );
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
synctype.h -- shared synctype_t definition
|
||||||
|
Copyright (C) 1996-1997 Id Software, Inc.
|
||||||
|
Copyright (C) 2023 Alibek Omarov
|
||||||
|
|
||||||
|
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 2
|
||||||
|
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.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
#ifndef SYNCTYPE_H
|
||||||
|
#define SYNCTYPE_H
|
||||||
|
typedef enum {ST_SYNC=0, ST_RAND } synctype_t;
|
||||||
|
#endif
|
|
@ -4,12 +4,17 @@
|
||||||
|
|
||||||
#include "build.h"
|
#include "build.h"
|
||||||
|
|
||||||
|
#if XASH_IRIX
|
||||||
|
#include <port.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#if XASH_WIN32
|
#if XASH_WIN32
|
||||||
#include <wchar.h> // off_t
|
#include <wchar.h> // off_t
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
|
|
||||||
#include <sys/types.h> // off_t
|
#include <sys/types.h> // off_t
|
||||||
#include STDINT_H
|
#include STDINT_H
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
typedef unsigned char byte;
|
typedef unsigned char byte;
|
||||||
typedef int sound_t;
|
typedef int sound_t;
|
||||||
|
@ -22,7 +27,12 @@ typedef byte rgba_t[4]; // unsigned byte colorpack
|
||||||
typedef byte rgb_t[3]; // unsigned byte colorpack
|
typedef byte rgb_t[3]; // unsigned byte colorpack
|
||||||
typedef vec_t matrix3x4[3][4];
|
typedef vec_t matrix3x4[3][4];
|
||||||
typedef vec_t matrix4x4[4][4];
|
typedef vec_t matrix4x4[4][4];
|
||||||
|
|
||||||
|
#if XASH_64BIT
|
||||||
typedef uint32_t poolhandle_t;
|
typedef uint32_t poolhandle_t;
|
||||||
|
#else
|
||||||
|
typedef void* poolhandle_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
#undef true
|
#undef true
|
||||||
#undef false
|
#undef false
|
||||||
|
@ -103,6 +113,11 @@ typedef uint64_t longtime_t;
|
||||||
#define likely(x) (x)
|
#define likely(x) (x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined( static_assert ) // C11 static_assert
|
||||||
|
#define STATIC_ASSERT static_assert
|
||||||
|
#else
|
||||||
|
#define STATIC_ASSERT( x, y ) extern int _static_assert_##__LINE__[( x ) ? 1 : -1]
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef XASH_BIG_ENDIAN
|
#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 LittleLong(x) (((int)(((x)&255)<<24)) + ((int)((((x)>>8)&255)<<16)) + ((int)(((x)>>16)&255)<<8) + (((x) >> 24)&255))
|
||||||
|
|
|
@ -16,6 +16,10 @@
|
||||||
#ifndef ALIAS_H
|
#ifndef ALIAS_H
|
||||||
#define ALIAS_H
|
#define ALIAS_H
|
||||||
|
|
||||||
|
#include "build.h"
|
||||||
|
#include STDINT_H
|
||||||
|
#include "synctype.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
==============================================================================
|
==============================================================================
|
||||||
|
|
||||||
|
@ -39,16 +43,6 @@ Alias models are position independent, so the cache manager can move them.
|
||||||
#define ALIAS_TRACER2 0x0040 // orange split trail + rotate
|
#define ALIAS_TRACER2 0x0040 // orange split trail + rotate
|
||||||
#define ALIAS_TRACER3 0x0080 // purple trail
|
#define ALIAS_TRACER3 0x0080 // purple trail
|
||||||
|
|
||||||
// must match definition in sprite.h
|
|
||||||
#ifndef SYNCTYPE_T
|
|
||||||
#define SYNCTYPE_T
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
ST_SYNC = 0,
|
|
||||||
ST_RAND
|
|
||||||
} synctype_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
ALIAS_SINGLE = 0,
|
ALIAS_SINGLE = 0,
|
||||||
|
@ -63,36 +57,42 @@ typedef enum
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
int ident;
|
int32_t ident;
|
||||||
int version;
|
int32_t version;
|
||||||
vec3_t scale;
|
vec3_t scale;
|
||||||
vec3_t scale_origin;
|
vec3_t scale_origin;
|
||||||
float boundingradius;
|
float boundingradius;
|
||||||
vec3_t eyeposition;
|
vec3_t eyeposition;
|
||||||
int numskins;
|
int32_t numskins;
|
||||||
int skinwidth;
|
int32_t skinwidth;
|
||||||
int skinheight;
|
int32_t skinheight;
|
||||||
int numverts;
|
int32_t numverts;
|
||||||
int numtris;
|
int32_t numtris;
|
||||||
int numframes;
|
int32_t numframes;
|
||||||
synctype_t synctype;
|
uint32_t synctype; // was synctype_t
|
||||||
int flags;
|
int32_t flags;
|
||||||
float size;
|
float size;
|
||||||
} daliashdr_t;
|
} daliashdr_t;
|
||||||
|
|
||||||
|
STATIC_ASSERT( sizeof( daliashdr_t ) == 84, "invalid daliashdr_t size" );
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
int onseam;
|
int32_t onseam;
|
||||||
int s;
|
int32_t s;
|
||||||
int t;
|
int32_t t;
|
||||||
} stvert_t;
|
} stvert_t;
|
||||||
|
|
||||||
|
STATIC_ASSERT( sizeof( stvert_t ) == 12, "invalid stvert_t size" );
|
||||||
|
|
||||||
typedef struct dtriangle_s
|
typedef struct dtriangle_s
|
||||||
{
|
{
|
||||||
int facesfront;
|
int32_t facesfront;
|
||||||
int vertindex[3];
|
int32_t vertindex[3];
|
||||||
} dtriangle_t;
|
} dtriangle_t;
|
||||||
|
|
||||||
|
STATIC_ASSERT( sizeof( dtriangle_t ) == 16, "invalid dtriangle_t size" );
|
||||||
|
|
||||||
#define DT_FACES_FRONT 0x0010
|
#define DT_FACES_FRONT 0x0010
|
||||||
#define ALIAS_ONSEAM 0x0020
|
#define ALIAS_ONSEAM 0x0020
|
||||||
|
|
||||||
|
@ -103,36 +103,50 @@ typedef struct
|
||||||
char name[16]; // frame name from grabbing
|
char name[16]; // frame name from grabbing
|
||||||
} daliasframe_t;
|
} daliasframe_t;
|
||||||
|
|
||||||
|
STATIC_ASSERT( sizeof( daliasframe_t ) == 24, "invalid daliasframe_t size" );
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
int numframes;
|
int32_t numframes;
|
||||||
trivertex_t bboxmin; // lightnormal isn't used
|
trivertex_t bboxmin; // lightnormal isn't used
|
||||||
trivertex_t bboxmax; // lightnormal isn't used
|
trivertex_t bboxmax; // lightnormal isn't used
|
||||||
} daliasgroup_t;
|
} daliasgroup_t;
|
||||||
|
|
||||||
|
STATIC_ASSERT( sizeof( daliasgroup_t ) == 12, "invalid daliasgrou_t size" );
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
int numskins;
|
int32_t numskins;
|
||||||
} daliasskingroup_t;
|
} daliasskingroup_t;
|
||||||
|
|
||||||
|
STATIC_ASSERT( sizeof( daliasskingroup_t ) == 4, "invalid daliasskingroup_t size" );
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
float interval;
|
float interval;
|
||||||
} daliasinterval_t;
|
} daliasinterval_t;
|
||||||
|
|
||||||
|
STATIC_ASSERT( sizeof( daliasinterval_t ) == 4, "invalid daliasinterval_t size" );
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
float interval;
|
float interval;
|
||||||
} daliasskininterval_t;
|
} daliasskininterval_t;
|
||||||
|
|
||||||
|
STATIC_ASSERT( sizeof( daliasskininterval_t ) == 4, "invalid daliasskininterval_t size" );
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
aliasframetype_t type;
|
uint32_t type; // was aliasframetype_t
|
||||||
} daliasframetype_t;
|
} daliasframetype_t;
|
||||||
|
|
||||||
|
STATIC_ASSERT( sizeof( daliasframetype_t ) == 4, "invalid daliasframetype_t size" );
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
aliasskintype_t type;
|
uint32_t type; // was aliasskintype_t
|
||||||
} daliasskintype_t;
|
} daliasskintype_t;
|
||||||
|
|
||||||
|
STATIC_ASSERT( sizeof( daliasskintype_t ) == 4, "invalid daliasskintype_t size" );
|
||||||
|
|
||||||
#endif//ALIAS_H
|
#endif//ALIAS_H
|
||||||
|
|
|
@ -25,70 +25,6 @@ GNU General Public License for more details.
|
||||||
#define MSG_COUNT 32 // last 32 messages parsed
|
#define MSG_COUNT 32 // last 32 messages parsed
|
||||||
#define MSG_MASK (MSG_COUNT - 1)
|
#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",
|
|
||||||
"svc_exec",
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
int command;
|
int command;
|
||||||
|
|
|
@ -518,14 +518,26 @@ CL_ReadDemoCmdHeader
|
||||||
read the demo command
|
read the demo command
|
||||||
=================
|
=================
|
||||||
*/
|
*/
|
||||||
void CL_ReadDemoCmdHeader( byte *cmd, float *dt )
|
qboolean CL_ReadDemoCmdHeader( byte *cmd, float *dt )
|
||||||
{
|
{
|
||||||
// read the command
|
// read the command
|
||||||
|
// HACKHACK: skip NOPs
|
||||||
|
do
|
||||||
|
{
|
||||||
FS_Read( cls.demofile, cmd, sizeof( byte ));
|
FS_Read( cls.demofile, cmd, sizeof( byte ));
|
||||||
Assert( *cmd >= 1 && *cmd <= dem_lastcmd );
|
} while( *cmd == dem_unknown );
|
||||||
|
|
||||||
|
if( *cmd > dem_lastcmd )
|
||||||
|
{
|
||||||
|
Con_Printf( S_ERROR "Demo cmd %d > %d, file offset = %d\n", *cmd, dem_lastcmd, (int)FS_Tell( cls.demofile ));
|
||||||
|
CL_DemoCompleted();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// read the timestamp
|
// read the timestamp
|
||||||
FS_Read( cls.demofile, dt, sizeof( float ));
|
FS_Read( cls.demofile, dt, sizeof( float ));
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -913,7 +925,8 @@ qboolean CL_DemoReadMessage( byte *buffer, size_t *length )
|
||||||
if( !cls.demofile ) break;
|
if( !cls.demofile ) break;
|
||||||
curpos = FS_Tell( cls.demofile );
|
curpos = FS_Tell( cls.demofile );
|
||||||
|
|
||||||
CL_ReadDemoCmdHeader( &cmd, &demo.timestamp );
|
if( !CL_ReadDemoCmdHeader( &cmd, &demo.timestamp ))
|
||||||
|
return false;
|
||||||
|
|
||||||
fElapsedTime = CL_GetDemoPlaybackClock() - demo.starttime;
|
fElapsedTime = CL_GetDemoPlaybackClock() - demo.starttime;
|
||||||
if( !cls.timedemo ) bSkipMessage = ((demo.timestamp - cl_serverframetime()) >= fElapsedTime) ? true : false;
|
if( !cls.timedemo ) bSkipMessage = ((demo.timestamp - cl_serverframetime()) >= fElapsedTime) ? true : false;
|
||||||
|
@ -1408,7 +1421,7 @@ void CL_PlayDemo_f( void )
|
||||||
|
|
||||||
if( Cmd_Argc() < 2 )
|
if( Cmd_Argc() < 2 )
|
||||||
{
|
{
|
||||||
Con_Printf( S_USAGE "playdemo <demoname>\n" );
|
Con_Printf( S_USAGE "%s <demoname>\n", Cmd_Argv( 0 ));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1535,12 +1548,6 @@ timedemo <demoname>
|
||||||
*/
|
*/
|
||||||
void CL_TimeDemo_f( void )
|
void CL_TimeDemo_f( void )
|
||||||
{
|
{
|
||||||
if( Cmd_Argc() != 2 )
|
|
||||||
{
|
|
||||||
Con_Printf( S_USAGE "timedemo <demoname>\n" );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CL_PlayDemo_f ();
|
CL_PlayDemo_f ();
|
||||||
|
|
||||||
// cls.td_starttime will be grabbed at the second frame of the demo, so
|
// cls.td_starttime will be grabbed at the second frame of the demo, so
|
||||||
|
|
|
@ -1111,9 +1111,13 @@ R_ParticleExplosion2
|
||||||
void GAME_EXPORT R_ParticleExplosion2( const vec3_t org, int colorStart, int colorLength )
|
void GAME_EXPORT R_ParticleExplosion2( const vec3_t org, int colorStart, int colorLength )
|
||||||
{
|
{
|
||||||
int i, j;
|
int i, j;
|
||||||
int colorMod = 0;
|
int colorMod = 0, packedColor;
|
||||||
particle_t *p;
|
particle_t *p;
|
||||||
|
|
||||||
|
if( FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
|
||||||
|
packedColor = 255; // use old code for blob particles
|
||||||
|
else packedColor = 0;
|
||||||
|
|
||||||
for( i = 0; i < 512; i++ )
|
for( i = 0; i < 512; i++ )
|
||||||
{
|
{
|
||||||
p = R_AllocParticle( NULL );
|
p = R_AllocParticle( NULL );
|
||||||
|
@ -1121,7 +1125,7 @@ void GAME_EXPORT R_ParticleExplosion2( const vec3_t org, int colorStart, int col
|
||||||
|
|
||||||
p->die = cl.time + 0.3f;
|
p->die = cl.time + 0.3f;
|
||||||
p->color = colorStart + ( colorMod % colorLength );
|
p->color = colorStart + ( colorMod % colorLength );
|
||||||
p->packedColor = 255; // use old code for blob particles
|
p->packedColor = packedColor;
|
||||||
colorMod++;
|
colorMod++;
|
||||||
|
|
||||||
p->type = pt_blob;
|
p->type = pt_blob;
|
||||||
|
@ -1143,15 +1147,19 @@ R_BlobExplosion
|
||||||
void GAME_EXPORT R_BlobExplosion( const vec3_t org )
|
void GAME_EXPORT R_BlobExplosion( const vec3_t org )
|
||||||
{
|
{
|
||||||
particle_t *p;
|
particle_t *p;
|
||||||
int i, j;
|
int i, j, packedColor;
|
||||||
|
|
||||||
|
if( FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
|
||||||
|
packedColor = 255; // use old code for blob particles
|
||||||
|
else packedColor = 0;
|
||||||
|
|
||||||
for( i = 0; i < 1024; i++ )
|
for( i = 0; i < 1024; i++ )
|
||||||
{
|
{
|
||||||
p = R_AllocParticle( NULL );
|
p = R_AllocParticle( NULL );
|
||||||
if( !p ) return;
|
if( !p ) return;
|
||||||
|
|
||||||
p->die = cl.time + COM_RandomFloat( 2.0f, 2.4f );
|
p->die = cl.time + COM_RandomFloat( 1.0f, 1.4f );
|
||||||
p->packedColor = 255; // use old code for blob particles
|
p->packedColor = packedColor;
|
||||||
|
|
||||||
if( i & 1 )
|
if( i & 1 )
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,338 @@
|
||||||
|
/*
|
||||||
|
cl_font.c - bare bones engine font manager
|
||||||
|
Copyright (C) 2023 Alibek Omarov
|
||||||
|
|
||||||
|
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 "filesystem.h"
|
||||||
|
#include "client.h"
|
||||||
|
#include "qfont.h"
|
||||||
|
|
||||||
|
qboolean CL_FixedFont( cl_font_t *font )
|
||||||
|
{
|
||||||
|
return font && font->valid && font->type == FONT_FIXED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int CL_LoadFontTexture( const char *fontname, uint texFlags, int *width )
|
||||||
|
{
|
||||||
|
int font_width;
|
||||||
|
int tex;
|
||||||
|
|
||||||
|
if( !g_fsapi.FileExists( fontname, false ))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
tex = ref.dllFuncs.GL_LoadTexture( fontname, NULL, 0, texFlags );
|
||||||
|
if( !tex )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
font_width = REF_GET_PARM( PARM_TEX_WIDTH, tex );
|
||||||
|
if( !font_width )
|
||||||
|
{
|
||||||
|
ref.dllFuncs.GL_FreeTexture( tex );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*width = font_width;
|
||||||
|
return tex;
|
||||||
|
}
|
||||||
|
|
||||||
|
qboolean Con_LoadFixedWidthFont( const char *fontname, cl_font_t *font, float scale, int rendermode, uint texFlags )
|
||||||
|
{
|
||||||
|
int font_width, i;
|
||||||
|
|
||||||
|
if( font->valid )
|
||||||
|
return true; // already loaded
|
||||||
|
|
||||||
|
font->hFontTexture = CL_LoadFontTexture( fontname, texFlags, &font_width );
|
||||||
|
if( !font->hFontTexture )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
font->type = FONT_FIXED;
|
||||||
|
font->valid = true;
|
||||||
|
font->scale = scale;
|
||||||
|
font->nearest = FBitSet( texFlags, TF_NEAREST );
|
||||||
|
font->rendermode = rendermode;
|
||||||
|
font->charHeight = Q_rint( font_width / 16 * scale );
|
||||||
|
|
||||||
|
for( i = 0; i < ARRAYSIZE( font->fontRc ); i++ )
|
||||||
|
{
|
||||||
|
font->fontRc[i].left = ( i * font_width / 16 ) % font_width;
|
||||||
|
font->fontRc[i].right = font->fontRc[i].left + font_width / 16;
|
||||||
|
font->fontRc[i].top = ( i / 16 ) * ( font_width / 16 );
|
||||||
|
font->fontRc[i].bottom = font->fontRc[i].top + font_width / 16;
|
||||||
|
|
||||||
|
font->charWidths[i] = Q_rint( font_width / 16 * scale );
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
qboolean Con_LoadVariableWidthFont( const char *fontname, cl_font_t *font, float scale, int rendermode, uint texFlags )
|
||||||
|
{
|
||||||
|
fs_offset_t length;
|
||||||
|
qfont_t src;
|
||||||
|
byte *pfile;
|
||||||
|
int font_width, i;
|
||||||
|
|
||||||
|
if( font->valid )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
pfile = g_fsapi.LoadFile( fontname, &length, false );
|
||||||
|
if( !pfile )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( length < sizeof( src ))
|
||||||
|
{
|
||||||
|
Mem_Free( pfile );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy( &src, pfile, sizeof( src ));
|
||||||
|
Mem_Free( pfile );
|
||||||
|
|
||||||
|
font->hFontTexture = CL_LoadFontTexture( fontname, texFlags, &font_width );
|
||||||
|
if( !font->hFontTexture )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
font->type = FONT_VARIABLE;
|
||||||
|
font->valid = true;
|
||||||
|
font->scale = scale;
|
||||||
|
font->nearest = FBitSet( texFlags, TF_NEAREST );
|
||||||
|
font->rendermode = rendermode;
|
||||||
|
font->charHeight = Q_rint( src.rowheight * scale );
|
||||||
|
|
||||||
|
for( i = 0; i < ARRAYSIZE( font->fontRc ); i++ )
|
||||||
|
{
|
||||||
|
const charinfo *ci = &src.fontinfo[i];
|
||||||
|
|
||||||
|
font->fontRc[i].left = (word)ci->startoffset % font_width;
|
||||||
|
font->fontRc[i].right = font->fontRc[i].left + ci->charwidth;
|
||||||
|
font->fontRc[i].top = (word)ci->startoffset / font_width;
|
||||||
|
font->fontRc[i].bottom = font->fontRc[i].top + src.rowheight;
|
||||||
|
|
||||||
|
font->charWidths[i] = Q_rint( src.fontinfo[i].charwidth * scale );
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CL_FreeFont( cl_font_t *font )
|
||||||
|
{
|
||||||
|
if( !font || !font->valid )
|
||||||
|
return;
|
||||||
|
|
||||||
|
ref.dllFuncs.GL_FreeTexture( font->hFontTexture );
|
||||||
|
memset( font, 0, sizeof( *font ));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int CL_CalcTabStop( const cl_font_t *font, int x )
|
||||||
|
{
|
||||||
|
int space = font->charWidths[' '];
|
||||||
|
int tab = space * 6; // 6 spaces
|
||||||
|
int stop = tab - x % tab;
|
||||||
|
|
||||||
|
if( stop < space )
|
||||||
|
return tab * 2 - x % tab; // select next
|
||||||
|
|
||||||
|
return stop;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CL_DrawCharacter( float x, float y, int number, rgba_t color, cl_font_t *font, int flags )
|
||||||
|
{
|
||||||
|
wrect_t *rc;
|
||||||
|
float w, h;
|
||||||
|
float s1, t1, s2, t2, half = 0.5f;
|
||||||
|
int texw, texh;
|
||||||
|
|
||||||
|
if( !font || !font->valid || y < -font->charHeight )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// check if printable
|
||||||
|
if( number <= 32 )
|
||||||
|
{
|
||||||
|
if( number == ' ' )
|
||||||
|
return font->charWidths[' '];
|
||||||
|
else if( number == '\t' )
|
||||||
|
return CL_CalcTabStop( font, x );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( FBitSet( flags, FONT_DRAW_UTF8 ))
|
||||||
|
number = Con_UtfProcessChar( number & 255 );
|
||||||
|
else number &= 255;
|
||||||
|
|
||||||
|
if( !number || !font->charWidths[number])
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
R_GetTextureParms( &texw, &texh, font->hFontTexture );
|
||||||
|
if( !texw || !texh )
|
||||||
|
return font->charWidths[number];
|
||||||
|
|
||||||
|
rc = &font->fontRc[number];
|
||||||
|
if( font->nearest || font->scale <= 1.0f )
|
||||||
|
half = 0;
|
||||||
|
|
||||||
|
s1 = ((float)rc->left + half ) / texw;
|
||||||
|
t1 = ((float)rc->top + half ) / texh;
|
||||||
|
s2 = ((float)rc->right - half ) / texw;
|
||||||
|
t2 = ((float)rc->bottom - half ) / texh;
|
||||||
|
w = ( rc->right - rc->left ) * font->scale;
|
||||||
|
h = ( rc->bottom - rc->top ) * font->scale;
|
||||||
|
|
||||||
|
if( FBitSet( flags, FONT_DRAW_HUD ))
|
||||||
|
SPR_AdjustSize( &x, &y, &w, &h );
|
||||||
|
|
||||||
|
if( !FBitSet( flags, FONT_DRAW_NORENDERMODE ))
|
||||||
|
ref.dllFuncs.GL_SetRenderMode( font->rendermode );
|
||||||
|
|
||||||
|
// don't apply color to fixed fonts it's already colored
|
||||||
|
if( font->type != FONT_FIXED || REF_GET_PARM( PARM_TEX_GLFORMAT, font->hFontTexture ) == 0x8045 ) // GL_LUMINANCE8_ALPHA8
|
||||||
|
ref.dllFuncs.Color4ub( color[0], color[1], color[2], color[3] );
|
||||||
|
else ref.dllFuncs.Color4ub( 255, 255, 255, color[3] );
|
||||||
|
ref.dllFuncs.R_DrawStretchPic( x, y, w, h, s1, t1, s2, t2, font->hFontTexture );
|
||||||
|
|
||||||
|
return font->charWidths[number];
|
||||||
|
}
|
||||||
|
|
||||||
|
int CL_DrawString( float x, float y, const char *s, rgba_t color, cl_font_t *font, int flags )
|
||||||
|
{
|
||||||
|
rgba_t current_color;
|
||||||
|
int draw_len = 0;
|
||||||
|
|
||||||
|
if( !font || !font->valid )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if( FBitSet( flags, FONT_DRAW_UTF8 ))
|
||||||
|
Con_UtfProcessChar( 0 ); // clear utf state
|
||||||
|
|
||||||
|
if( !FBitSet( flags, FONT_DRAW_NORENDERMODE ))
|
||||||
|
ref.dllFuncs.GL_SetRenderMode( font->rendermode );
|
||||||
|
|
||||||
|
Vector4Copy( color, current_color );
|
||||||
|
|
||||||
|
while( *s )
|
||||||
|
{
|
||||||
|
if( *s == '\n' )
|
||||||
|
{
|
||||||
|
s++;
|
||||||
|
|
||||||
|
if( !*s )
|
||||||
|
break;
|
||||||
|
|
||||||
|
// some client functions ignore newlines
|
||||||
|
if( !FBitSet( flags, FONT_DRAW_NOLF ))
|
||||||
|
{
|
||||||
|
draw_len = 0;
|
||||||
|
y += font->charHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( FBitSet( flags, FONT_DRAW_RESETCOLORONLF ))
|
||||||
|
Vector4Copy( color, current_color );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( IsColorString( s ))
|
||||||
|
{
|
||||||
|
// don't copy alpha
|
||||||
|
if( !FBitSet( flags, FONT_DRAW_FORCECOL ))
|
||||||
|
VectorCopy( g_color_table[ColorIndex(*( s + 1 ))], current_color );
|
||||||
|
|
||||||
|
s += 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip setting rendermode, it was changed for this string already
|
||||||
|
draw_len += CL_DrawCharacter( x + draw_len, y, (byte)*s, current_color, font, flags | FONT_DRAW_NORENDERMODE );
|
||||||
|
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return draw_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CL_DrawCharacterLen( cl_font_t *font, int number, int *width, int *height )
|
||||||
|
{
|
||||||
|
if( !font || !font->valid ) return;
|
||||||
|
if( width )
|
||||||
|
{
|
||||||
|
if( number == '\t' )
|
||||||
|
*width = CL_CalcTabStop( font, 0 ); // at least return max tabstop
|
||||||
|
else *width = font->charWidths[number & 255];
|
||||||
|
}
|
||||||
|
if( height ) *height = font->charHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CL_DrawStringLen( cl_font_t *font, const char *s, int *width, int *height, int flags )
|
||||||
|
{
|
||||||
|
int draw_len = 0;
|
||||||
|
|
||||||
|
if( !font || !font->valid )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( height )
|
||||||
|
*height = font->charHeight;
|
||||||
|
|
||||||
|
if( width )
|
||||||
|
*width = 0;
|
||||||
|
|
||||||
|
if( !COM_CheckString( s ))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( FBitSet( flags, FONT_DRAW_UTF8 ))
|
||||||
|
Con_UtfProcessChar( 0 ); // reset utf state
|
||||||
|
|
||||||
|
while( *s )
|
||||||
|
{
|
||||||
|
int number;
|
||||||
|
|
||||||
|
if( *s == '\n' )
|
||||||
|
{
|
||||||
|
// BUG: no check for end string here
|
||||||
|
// but high chances somebody's relying on this
|
||||||
|
s++;
|
||||||
|
draw_len = 0;
|
||||||
|
if( !FBitSet( flags, FONT_DRAW_NOLF ))
|
||||||
|
{
|
||||||
|
if( height )
|
||||||
|
*height += font->charHeight;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if( *s == '\t' )
|
||||||
|
{
|
||||||
|
draw_len += CL_CalcTabStop( font, 0 ); // at least return max tabstop
|
||||||
|
s++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( IsColorString( s ))
|
||||||
|
{
|
||||||
|
s += 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( FBitSet( flags, FONT_DRAW_UTF8 ))
|
||||||
|
number = Con_UtfProcessChar( (byte)*s );
|
||||||
|
else number = (byte)*s;
|
||||||
|
|
||||||
|
if( number )
|
||||||
|
{
|
||||||
|
draw_len += font->charWidths[number];
|
||||||
|
|
||||||
|
if( draw_len > *width )
|
||||||
|
*width = draw_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
}
|
|
@ -534,7 +534,7 @@ void CL_ComputePlayerOrigin( cl_entity_t *ent )
|
||||||
vec3_t origin;
|
vec3_t origin;
|
||||||
vec3_t angles;
|
vec3_t angles;
|
||||||
|
|
||||||
if( !ent->player || ent->index == ( cl.playernum + 1 ))
|
if( !ent->player )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if( cl_nointerp->value > 0.f )
|
if( cl_nointerp->value > 0.f )
|
||||||
|
@ -1094,6 +1094,9 @@ void CL_LinkPlayers( frame_t *frame )
|
||||||
|
|
||||||
if ( i == cl.playernum )
|
if ( i == cl.playernum )
|
||||||
{
|
{
|
||||||
|
// using interpolation only for local player angles
|
||||||
|
CL_ComputePlayerOrigin( ent );
|
||||||
|
|
||||||
if( cls.demoplayback == DEMO_QUAKE1 )
|
if( cls.demoplayback == DEMO_QUAKE1 )
|
||||||
VectorLerp( ent->prevstate.origin, cl.lerpFrac, ent->curstate.origin, cl.simorg );
|
VectorLerp( ent->prevstate.origin, cl.lerpFrac, ent->curstate.origin, cl.simorg );
|
||||||
VectorCopy( cl.simorg, ent->origin );
|
VectorCopy( cl.simorg, ent->origin );
|
||||||
|
|
|
@ -147,21 +147,6 @@ qboolean CL_IsThirdPerson( void )
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
====================
|
|
||||||
CL_GetPlayerInfo
|
|
||||||
|
|
||||||
get player info by render request
|
|
||||||
====================
|
|
||||||
*/
|
|
||||||
player_info_t *CL_GetPlayerInfo( int playerIndex )
|
|
||||||
{
|
|
||||||
if( playerIndex < 0 || playerIndex >= cl.maxclients )
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return &cl.players[playerIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
====================
|
====================
|
||||||
CL_CreatePlaylist
|
CL_CreatePlaylist
|
||||||
|
@ -249,22 +234,6 @@ void CL_InitCDAudio( const char *filename )
|
||||||
Mem_Free( afile );
|
Mem_Free( afile );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
====================
|
|
||||||
CL_PointContents
|
|
||||||
|
|
||||||
Return contents for point
|
|
||||||
====================
|
|
||||||
*/
|
|
||||||
int CL_PointContents( const vec3_t p )
|
|
||||||
{
|
|
||||||
int cont = PM_PointContents( clgame.pmove, p );
|
|
||||||
|
|
||||||
if( cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN )
|
|
||||||
cont = CONTENTS_WATER;
|
|
||||||
return cont;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=============
|
=============
|
||||||
CL_AdjustXPos
|
CL_AdjustXPos
|
||||||
|
@ -337,9 +306,7 @@ print centerscreen message
|
||||||
*/
|
*/
|
||||||
void CL_CenterPrint( const char *text, float y )
|
void CL_CenterPrint( const char *text, float y )
|
||||||
{
|
{
|
||||||
int length = 0;
|
cl_font_t *font = Con_GetCurFont();
|
||||||
int width = 0;
|
|
||||||
char *s;
|
|
||||||
|
|
||||||
if( !COM_CheckString( text ))
|
if( !COM_CheckString( text ))
|
||||||
return;
|
return;
|
||||||
|
@ -348,24 +315,13 @@ void CL_CenterPrint( const char *text, float y )
|
||||||
clgame.centerPrint.totalWidth = 0;
|
clgame.centerPrint.totalWidth = 0;
|
||||||
clgame.centerPrint.time = cl.mtime[0]; // allow pause for centerprint
|
clgame.centerPrint.time = cl.mtime[0]; // allow pause for centerprint
|
||||||
Q_strncpy( clgame.centerPrint.message, text, sizeof( clgame.centerPrint.message ));
|
Q_strncpy( clgame.centerPrint.message, text, sizeof( clgame.centerPrint.message ));
|
||||||
s = clgame.centerPrint.message;
|
|
||||||
|
|
||||||
// count the number of lines for centering
|
CL_DrawStringLen( font,
|
||||||
while( *s )
|
clgame.centerPrint.message,
|
||||||
{
|
&clgame.centerPrint.totalWidth,
|
||||||
if( *s == '\n' )
|
&clgame.centerPrint.totalHeight,
|
||||||
{
|
FONT_DRAW_HUD | FONT_DRAW_UTF8 );
|
||||||
clgame.centerPrint.lines++;
|
|
||||||
if( width > clgame.centerPrint.totalWidth )
|
|
||||||
clgame.centerPrint.totalWidth = width;
|
|
||||||
width = 0;
|
|
||||||
}
|
|
||||||
else width += clgame.scrInfo.charWidths[*s];
|
|
||||||
s++;
|
|
||||||
length++;
|
|
||||||
}
|
|
||||||
|
|
||||||
clgame.centerPrint.totalHeight = ( clgame.centerPrint.lines * clgame.scrInfo.iCharHeight );
|
|
||||||
clgame.centerPrint.y = CL_AdjustYPos( y, clgame.centerPrint.totalHeight );
|
clgame.centerPrint.y = CL_AdjustYPos( y, clgame.centerPrint.totalHeight );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,102 +332,43 @@ SPR_AdjustSize
|
||||||
draw hudsprite routine
|
draw hudsprite routine
|
||||||
====================
|
====================
|
||||||
*/
|
*/
|
||||||
static void SPR_AdjustSize( float *x, float *y, float *w, float *h )
|
void SPR_AdjustSize( float *x, float *y, float *w, float *h )
|
||||||
{
|
{
|
||||||
float xscale, yscale;
|
float xscale, yscale;
|
||||||
|
|
||||||
|
if( refState.width == clgame.scrInfo.iWidth && refState.height == clgame.scrInfo.iHeight )
|
||||||
|
return;
|
||||||
|
|
||||||
// scale for screen sizes
|
// scale for screen sizes
|
||||||
xscale = refState.width / (float)clgame.scrInfo.iWidth;
|
xscale = refState.width / (float)clgame.scrInfo.iWidth;
|
||||||
yscale = refState.height / (float)clgame.scrInfo.iHeight;
|
yscale = refState.height / (float)clgame.scrInfo.iHeight;
|
||||||
|
|
||||||
if( x ) *x *= xscale;
|
*x *= xscale;
|
||||||
if( y ) *y *= yscale;
|
*y *= yscale;
|
||||||
if( w ) *w *= xscale;
|
*w *= xscale;
|
||||||
if( h ) *h *= yscale;
|
*h *= yscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
void SPR_AdjustTexCoords( float width, float height, float *s1, float *t1, float *s2, float *t2 )
|
||||||
====================
|
|
||||||
SPR_AdjustSize
|
|
||||||
|
|
||||||
draw hudsprite routine
|
|
||||||
====================
|
|
||||||
*/
|
|
||||||
static void SPR_AdjustSizei( int *x, int *y, int *w, int *h )
|
|
||||||
{
|
{
|
||||||
float xscale, yscale;
|
if( refState.width != clgame.scrInfo.iWidth )
|
||||||
|
|
||||||
// scale for screen sizes
|
|
||||||
xscale = refState.width / (float)clgame.scrInfo.iWidth;
|
|
||||||
yscale = refState.height / (float)clgame.scrInfo.iHeight;
|
|
||||||
|
|
||||||
if( x ) *x *= xscale;
|
|
||||||
if( y ) *y *= yscale;
|
|
||||||
if( w ) *w *= xscale;
|
|
||||||
if( h ) *h *= yscale;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
====================
|
|
||||||
PictAdjustSize
|
|
||||||
|
|
||||||
draw hudsprite routine
|
|
||||||
====================
|
|
||||||
*/
|
|
||||||
void PicAdjustSize( float *x, float *y, float *w, float *h )
|
|
||||||
{
|
|
||||||
if( !clgame.ds.adjust_size ) return;
|
|
||||||
|
|
||||||
SPR_AdjustSize( x, y, w, h );
|
|
||||||
}
|
|
||||||
|
|
||||||
static qboolean SPR_Scissor( float *x, float *y, float *width, float *height, float *u0, float *v0, float *u1, float *v1 )
|
|
||||||
{
|
|
||||||
float dudx, dvdy;
|
|
||||||
|
|
||||||
// clip sub rect to sprite
|
|
||||||
if(( width == 0 ) || ( height == 0 ))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if( *x + *width <= clgame.ds.scissor_x )
|
|
||||||
return false;
|
|
||||||
if( *x >= clgame.ds.scissor_x + clgame.ds.scissor_width )
|
|
||||||
return false;
|
|
||||||
if( *y + *height <= clgame.ds.scissor_y )
|
|
||||||
return false;
|
|
||||||
if( *y >= clgame.ds.scissor_y + clgame.ds.scissor_height )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
dudx = (*u1 - *u0) / *width;
|
|
||||||
dvdy = (*v1 - *v0) / *height;
|
|
||||||
|
|
||||||
if( *x < clgame.ds.scissor_x )
|
|
||||||
{
|
{
|
||||||
*u0 += (clgame.ds.scissor_x - *x) * dudx;
|
// align to texel if scaling
|
||||||
*width -= clgame.ds.scissor_x - *x;
|
*s1 += 0.5f;
|
||||||
*x = clgame.ds.scissor_x;
|
*s2 -= 0.5f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( *x + *width > clgame.ds.scissor_x + clgame.ds.scissor_width )
|
if( refState.height != clgame.scrInfo.iHeight )
|
||||||
{
|
{
|
||||||
*u1 -= (*x + *width - (clgame.ds.scissor_x + clgame.ds.scissor_width)) * dudx;
|
// align to texel if scaling
|
||||||
*width = clgame.ds.scissor_x + clgame.ds.scissor_width - *x;
|
*t1 += 0.5f;
|
||||||
|
*t2 -= 0.5f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( *y < clgame.ds.scissor_y )
|
*s1 /= width;
|
||||||
{
|
*t1 /= height;
|
||||||
*v0 += (clgame.ds.scissor_y - *y) * dvdy;
|
*s2 /= width;
|
||||||
*height -= clgame.ds.scissor_y - *y;
|
*t2 /= height;
|
||||||
*y = clgame.ds.scissor_y;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( *y + *height > clgame.ds.scissor_y + clgame.ds.scissor_height )
|
|
||||||
{
|
|
||||||
*v1 -= (*y + *height - (clgame.ds.scissor_y + clgame.ds.scissor_height)) * dvdy;
|
|
||||||
*height = clgame.ds.scissor_y + clgame.ds.scissor_height - *y;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -499,9 +396,7 @@ static void SPR_DrawGeneric( int frame, float x, float y, float width, float hei
|
||||||
|
|
||||||
if( prc )
|
if( prc )
|
||||||
{
|
{
|
||||||
wrect_t rc;
|
wrect_t rc = *prc;
|
||||||
|
|
||||||
rc = *prc;
|
|
||||||
|
|
||||||
// Sigh! some stupid modmakers set wrong rectangles in hud.txt
|
// Sigh! some stupid modmakers set wrong rectangles in hud.txt
|
||||||
if( rc.left <= 0 || rc.left >= width ) rc.left = 0;
|
if( rc.left <= 0 || rc.left >= width ) rc.left = 0;
|
||||||
|
@ -509,11 +404,13 @@ static void SPR_DrawGeneric( int frame, float x, float y, float width, float hei
|
||||||
if( rc.right <= 0 || rc.right > width ) rc.right = width;
|
if( rc.right <= 0 || rc.right > width ) rc.right = width;
|
||||||
if( rc.bottom <= 0 || rc.bottom > height ) rc.bottom = height;
|
if( rc.bottom <= 0 || rc.bottom > height ) rc.bottom = height;
|
||||||
|
|
||||||
|
s1 = rc.left;
|
||||||
|
t1 = rc.top;
|
||||||
|
s2 = rc.right;
|
||||||
|
t2 = rc.bottom;
|
||||||
|
|
||||||
// calc user-defined rectangle
|
// calc user-defined rectangle
|
||||||
s1 = (float)rc.left / width;
|
SPR_AdjustTexCoords( width, height, &s1, &t1, &s2, &t2 );
|
||||||
t1 = (float)rc.top / height;
|
|
||||||
s2 = (float)rc.right / width;
|
|
||||||
t2 = (float)rc.bottom / height;
|
|
||||||
width = rc.right - rc.left;
|
width = rc.right - rc.left;
|
||||||
height = rc.bottom - rc.top;
|
height = rc.bottom - rc.top;
|
||||||
}
|
}
|
||||||
|
@ -524,7 +421,7 @@ static void SPR_DrawGeneric( int frame, float x, float y, float width, float hei
|
||||||
}
|
}
|
||||||
|
|
||||||
// pass scissor test if supposed
|
// pass scissor test if supposed
|
||||||
if( clgame.ds.scissor_test && !SPR_Scissor( &x, &y, &width, &height, &s1, &t1, &s2, &t2 ))
|
if( !CL_Scissor( &clgame.ds.scissor, &x, &y, &width, &height, &s1, &t1, &s2, &t2 ))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// scale for screen sizes
|
// scale for screen sizes
|
||||||
|
@ -543,6 +440,7 @@ called each frame
|
||||||
*/
|
*/
|
||||||
void CL_DrawCenterPrint( void )
|
void CL_DrawCenterPrint( void )
|
||||||
{
|
{
|
||||||
|
cl_font_t *font = Con_GetCurFont();
|
||||||
char *pText;
|
char *pText;
|
||||||
int i, j, x, y;
|
int i, j, x, y;
|
||||||
int width, lineLength;
|
int width, lineLength;
|
||||||
|
@ -562,8 +460,10 @@ void CL_DrawCenterPrint( void )
|
||||||
y = clgame.centerPrint.y; // start y
|
y = clgame.centerPrint.y; // start y
|
||||||
colorDefault = g_color_table[7];
|
colorDefault = g_color_table[7];
|
||||||
pText = clgame.centerPrint.message;
|
pText = clgame.centerPrint.message;
|
||||||
Con_DrawCharacterLen( 0, NULL, &charHeight );
|
|
||||||
|
|
||||||
|
CL_DrawCharacterLen( font, 0, NULL, &charHeight );
|
||||||
|
|
||||||
|
ref.dllFuncs.GL_SetRenderMode( font->rendermode );
|
||||||
for( i = 0; i < clgame.centerPrint.lines; i++ )
|
for( i = 0; i < clgame.centerPrint.lines; i++ )
|
||||||
{
|
{
|
||||||
lineLength = 0;
|
lineLength = 0;
|
||||||
|
@ -573,7 +473,7 @@ void CL_DrawCenterPrint( void )
|
||||||
{
|
{
|
||||||
byte c = *pText;
|
byte c = *pText;
|
||||||
line[lineLength] = c;
|
line[lineLength] = c;
|
||||||
Con_DrawCharacterLen( c, &charWidth, NULL );
|
CL_DrawCharacterLen( font, c, &charWidth, NULL );
|
||||||
width += charWidth;
|
width += charWidth;
|
||||||
lineLength++;
|
lineLength++;
|
||||||
pText++;
|
pText++;
|
||||||
|
@ -590,12 +490,47 @@ void CL_DrawCenterPrint( void )
|
||||||
for( j = 0; j < lineLength; j++ )
|
for( j = 0; j < lineLength; j++ )
|
||||||
{
|
{
|
||||||
if( x >= 0 && y >= 0 && x <= refState.width )
|
if( x >= 0 && y >= 0 && x <= refState.width )
|
||||||
x += Con_DrawCharacter( x, y, line[j], colorDefault );
|
x += CL_DrawCharacter( x, y, line[j], colorDefault, font, FONT_DRAW_UTF8 | FONT_DRAW_HUD | FONT_DRAW_NORENDERMODE );
|
||||||
}
|
}
|
||||||
y += charHeight;
|
y += charHeight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int V_FadeAlpha( screenfade_t *sf )
|
||||||
|
{
|
||||||
|
int alpha;
|
||||||
|
|
||||||
|
if( cl.time > sf->fadeReset && cl.time > sf->fadeEnd )
|
||||||
|
{
|
||||||
|
if( !FBitSet( sf->fadeFlags, FFADE_STAYOUT ))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( FBitSet( sf->fadeFlags, FFADE_STAYOUT ))
|
||||||
|
{
|
||||||
|
alpha = sf->fadealpha;
|
||||||
|
if( FBitSet( sf->fadeFlags, FFADE_OUT ) && sf->fadeTotalEnd > cl.time )
|
||||||
|
{
|
||||||
|
alpha += sf->fadeSpeed * ( sf->fadeTotalEnd - cl.time );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sf->fadeEnd = cl.time + 0.1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
alpha = sf->fadeSpeed * ( sf->fadeEnd - cl.time );
|
||||||
|
if( FBitSet( sf->fadeFlags, FFADE_OUT ))
|
||||||
|
{
|
||||||
|
alpha += sf->fadealpha;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
alpha = bound( 0, alpha, sf->fadealpha );
|
||||||
|
|
||||||
|
return alpha;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=============
|
=============
|
||||||
CL_DrawScreenFade
|
CL_DrawScreenFade
|
||||||
|
@ -607,41 +542,29 @@ can be modulated
|
||||||
void CL_DrawScreenFade( void )
|
void CL_DrawScreenFade( void )
|
||||||
{
|
{
|
||||||
screenfade_t *sf = &clgame.fade;
|
screenfade_t *sf = &clgame.fade;
|
||||||
int iFadeAlpha, testFlags;
|
int alpha;
|
||||||
|
|
||||||
// keep pushing reset time out indefinitely
|
alpha = V_FadeAlpha( sf );
|
||||||
if( sf->fadeFlags & FFADE_STAYOUT )
|
|
||||||
sf->fadeReset = cl.time + 0.1f;
|
|
||||||
|
|
||||||
if( sf->fadeReset == 0.0f && sf->fadeEnd == 0.0f )
|
if( !alpha )
|
||||||
return; // inactive
|
|
||||||
|
|
||||||
// all done?
|
|
||||||
if(( cl.time > sf->fadeReset ) && ( cl.time > sf->fadeEnd ))
|
|
||||||
{
|
|
||||||
memset( &clgame.fade, 0, sizeof( clgame.fade ));
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
testFlags = (sf->fadeFlags & ~FFADE_MODULATE);
|
if( FBitSet( sf->fadeFlags, FFADE_MODULATE ))
|
||||||
|
|
||||||
// fading...
|
|
||||||
if( testFlags == FFADE_STAYOUT )
|
|
||||||
{
|
{
|
||||||
iFadeAlpha = sf->fadealpha;
|
ref.dllFuncs.GL_SetRenderMode( kRenderScreenFadeModulate );
|
||||||
|
|
||||||
|
ref.dllFuncs.Color4ub(
|
||||||
|
(uint16_t)( sf->fader * alpha + ( 255 - alpha ) * 255 ) >> 8,
|
||||||
|
(uint16_t)( sf->fadeg * alpha + ( 255 - alpha ) * 255 ) >> 8,
|
||||||
|
(uint16_t)( sf->fadeb * alpha + ( 255 - alpha ) * 255 ) >> 8,
|
||||||
|
255 );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
iFadeAlpha = sf->fadeSpeed * ( sf->fadeEnd - cl.time );
|
ref.dllFuncs.GL_SetRenderMode( kRenderTransTexture );
|
||||||
if( sf->fadeFlags & FFADE_OUT ) iFadeAlpha += sf->fadealpha;
|
ref.dllFuncs.Color4ub( sf->fader, sf->fadeg, sf->fadeb, alpha );
|
||||||
iFadeAlpha = bound( 0, iFadeAlpha, sf->fadealpha );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ref.dllFuncs.Color4ub( sf->fader, sf->fadeg, sf->fadeb, iFadeAlpha );
|
|
||||||
|
|
||||||
if( sf->fadeFlags & FFADE_MODULATE )
|
|
||||||
ref.dllFuncs.GL_SetRenderMode( kRenderTransAdd );
|
|
||||||
else ref.dllFuncs.GL_SetRenderMode( kRenderTransTexture );
|
|
||||||
ref.dllFuncs.R_DrawStretchPic( 0, 0, refState.width, refState.height, 0, 0, 1, 1,
|
ref.dllFuncs.R_DrawStretchPic( 0, 0, refState.width, refState.height, 0, 0, 1, 1,
|
||||||
R_GetBuiltinTexture( REF_WHITE_TEXTURE ));
|
R_GetBuiltinTexture( REF_WHITE_TEXTURE ));
|
||||||
ref.dllFuncs.Color4ub( 255, 255, 255, 255 );
|
ref.dllFuncs.Color4ub( 255, 255, 255, 255 );
|
||||||
|
@ -853,6 +776,92 @@ const char *CL_SoundFromIndex( int index )
|
||||||
return sfx->name;
|
return sfx->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
CL_EnableScissor
|
||||||
|
|
||||||
|
enable scissor test
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void CL_EnableScissor( scissor_state_t *scissor, int x, int y, int width, int height )
|
||||||
|
{
|
||||||
|
scissor->x = x;
|
||||||
|
scissor->y = y;
|
||||||
|
scissor->width = width;
|
||||||
|
scissor->height = height;
|
||||||
|
scissor->test = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
CL_DisableScissor
|
||||||
|
|
||||||
|
disable scissor test
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void CL_DisableScissor( scissor_state_t *scissor )
|
||||||
|
{
|
||||||
|
scissor->test = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
CL_Scissor
|
||||||
|
|
||||||
|
perform common scissor test
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
qboolean CL_Scissor( const scissor_state_t *scissor, float *x, float *y, float *width, float *height, float *u0, float *v0, float *u1, float *v1 )
|
||||||
|
{
|
||||||
|
float dudx, dvdy;
|
||||||
|
|
||||||
|
if( !scissor->test )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// clip sub rect to sprite
|
||||||
|
if( *width == 0 || *height == 0 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( *x + *width <= scissor->x )
|
||||||
|
return false;
|
||||||
|
if( *x >= scissor->x + scissor->width )
|
||||||
|
return false;
|
||||||
|
if( *y + *height <= scissor->y )
|
||||||
|
return false;
|
||||||
|
if( *y >= scissor->y + scissor->height )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
dudx = (*u1 - *u0) / *width;
|
||||||
|
dvdy = (*v1 - *v0) / *height;
|
||||||
|
|
||||||
|
if( *x < scissor->x )
|
||||||
|
{
|
||||||
|
*u0 += (scissor->x - *x) * dudx;
|
||||||
|
*width -= scissor->x - *x;
|
||||||
|
*x = scissor->x;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( *x + *width > scissor->x + scissor->width )
|
||||||
|
{
|
||||||
|
*u1 -= (*x + *width - (scissor->x + scissor->width)) * dudx;
|
||||||
|
*width = scissor->x + scissor->width - *x;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( *y < scissor->y )
|
||||||
|
{
|
||||||
|
*v0 += (scissor->y - *y) * dvdy;
|
||||||
|
*height -= scissor->y - *y;
|
||||||
|
*y = scissor->y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( *y + *height > scissor->y + scissor->height )
|
||||||
|
{
|
||||||
|
*v1 -= (*y + *height - (scissor->y + scissor->height)) * dvdy;
|
||||||
|
*height = scissor->y + scissor->height - *y;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=========
|
=========
|
||||||
SPR_EnableScissor
|
SPR_EnableScissor
|
||||||
|
@ -867,11 +876,7 @@ static void GAME_EXPORT SPR_EnableScissor( int x, int y, int width, int height )
|
||||||
width = bound( 0, width, clgame.scrInfo.iWidth - x );
|
width = bound( 0, width, clgame.scrInfo.iWidth - x );
|
||||||
height = bound( 0, height, clgame.scrInfo.iHeight - y );
|
height = bound( 0, height, clgame.scrInfo.iHeight - y );
|
||||||
|
|
||||||
clgame.ds.scissor_x = x;
|
CL_EnableScissor( &clgame.ds.scissor, x, y, width, height );
|
||||||
clgame.ds.scissor_width = width;
|
|
||||||
clgame.ds.scissor_y = y;
|
|
||||||
clgame.ds.scissor_height = height;
|
|
||||||
clgame.ds.scissor_test = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -882,11 +887,7 @@ SPR_DisableScissor
|
||||||
*/
|
*/
|
||||||
static void GAME_EXPORT SPR_DisableScissor( void )
|
static void GAME_EXPORT SPR_DisableScissor( void )
|
||||||
{
|
{
|
||||||
clgame.ds.scissor_x = 0;
|
CL_DisableScissor( &clgame.ds.scissor );
|
||||||
clgame.ds.scissor_width = 0;
|
|
||||||
clgame.ds.scissor_y = 0;
|
|
||||||
clgame.ds.scissor_height = 0;
|
|
||||||
clgame.ds.scissor_test = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -956,28 +957,21 @@ CL_DrawLoading
|
||||||
draw loading progress bar
|
draw loading progress bar
|
||||||
=============
|
=============
|
||||||
*/
|
*/
|
||||||
static void CL_DrawLoadingOrPaused( qboolean paused, float percent )
|
static void CL_DrawLoadingOrPaused( int tex )
|
||||||
{
|
{
|
||||||
int x, y, width, height, right;
|
float x, y, width, height;
|
||||||
|
int iWidth, iHeight;
|
||||||
|
|
||||||
R_GetTextureParms( &width, &height, paused ? cls.pauseIcon : cls.loadingBar );
|
R_GetTextureParms( &iWidth, &iHeight, tex );
|
||||||
x = ( clgame.scrInfo.iWidth - width ) >> 1;
|
x = ( clgame.scrInfo.iWidth - iWidth ) / 2.0f;
|
||||||
y = ( clgame.scrInfo.iHeight - height) >> 1;
|
y = ( clgame.scrInfo.iHeight - iHeight ) / 2.0f;
|
||||||
|
width = iWidth;
|
||||||
|
height = iHeight;
|
||||||
|
|
||||||
SPR_AdjustSizei( &x, &y, &width, &height );
|
SPR_AdjustSize( &x, &y, &width, &height );
|
||||||
|
|
||||||
if( !paused )
|
|
||||||
{
|
|
||||||
ref.dllFuncs.Color4ub( 255, 255, 255, 255 );
|
ref.dllFuncs.Color4ub( 255, 255, 255, 255 );
|
||||||
ref.dllFuncs.GL_SetRenderMode( kRenderTransTexture );
|
ref.dllFuncs.GL_SetRenderMode( kRenderTransTexture );
|
||||||
ref.dllFuncs.R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, cls.loadingBar );
|
ref.dllFuncs.R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, tex );
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ref.dllFuncs.Color4ub( 255, 255, 255, 255 );
|
|
||||||
ref.dllFuncs.GL_SetRenderMode( kRenderTransTexture );
|
|
||||||
ref.dllFuncs.R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, cls.pauseIcon );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CL_DrawHUD( int state )
|
void CL_DrawHUD( int state )
|
||||||
|
@ -1003,15 +997,15 @@ void CL_DrawHUD( int state )
|
||||||
CL_DrawCrosshair ();
|
CL_DrawCrosshair ();
|
||||||
CL_DrawCenterPrint ();
|
CL_DrawCenterPrint ();
|
||||||
clgame.dllFuncs.pfnRedraw( cl.time, cl.intermission );
|
clgame.dllFuncs.pfnRedraw( cl.time, cl.intermission );
|
||||||
CL_DrawLoadingOrPaused( true, 0.0f );
|
CL_DrawLoadingOrPaused( cls.pauseIcon );
|
||||||
break;
|
break;
|
||||||
case CL_LOADING:
|
case CL_LOADING:
|
||||||
CL_DrawLoadingOrPaused( false, scr_loading->value );
|
CL_DrawLoadingOrPaused( cls.loadingBar );
|
||||||
break;
|
break;
|
||||||
case CL_CHANGELEVEL:
|
case CL_CHANGELEVEL:
|
||||||
if( cls.draw_changelevel )
|
if( cls.draw_changelevel )
|
||||||
{
|
{
|
||||||
CL_DrawLoadingOrPaused( false, 100.0f );
|
CL_DrawLoadingOrPaused( cls.loadingBar );
|
||||||
cls.draw_changelevel = false;
|
cls.draw_changelevel = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1177,6 +1171,7 @@ static qboolean CL_LoadHudSprite( const char *szSpriteName, model_t *m_pSprite,
|
||||||
// it's hud sprite, make difference names to prevent free shared textures
|
// it's hud sprite, make difference names to prevent free shared textures
|
||||||
if( type == SPR_CLIENT || type == SPR_HUDSPRITE )
|
if( type == SPR_CLIENT || type == SPR_HUDSPRITE )
|
||||||
SetBits( m_pSprite->flags, MODEL_CLIENT );
|
SetBits( m_pSprite->flags, MODEL_CLIENT );
|
||||||
|
|
||||||
m_pSprite->numtexinfo = texFlags; // store texFlags into numtexinfo
|
m_pSprite->numtexinfo = texFlags; // store texFlags into numtexinfo
|
||||||
|
|
||||||
if( !FS_FileExists( szSpriteName, false ) )
|
if( !FS_FileExists( szSpriteName, false ) )
|
||||||
|
@ -1624,6 +1619,14 @@ int GAME_EXPORT CL_GetScreenInfo( SCREENINFO *pscrinfo )
|
||||||
{
|
{
|
||||||
float scale_factor = hud_scale->value;
|
float scale_factor = hud_scale->value;
|
||||||
|
|
||||||
|
if( FBitSet( hud_fontscale->flags, FCVAR_CHANGED ))
|
||||||
|
{
|
||||||
|
CL_FreeFont( &cls.creditsFont );
|
||||||
|
SCR_LoadCreditsFont();
|
||||||
|
|
||||||
|
ClearBits( hud_fontscale->flags, FCVAR_CHANGED );
|
||||||
|
}
|
||||||
|
|
||||||
// setup screen info
|
// setup screen info
|
||||||
clgame.scrInfo.iSize = sizeof( clgame.scrInfo );
|
clgame.scrInfo.iSize = sizeof( clgame.scrInfo );
|
||||||
clgame.scrInfo.iFlags = SCRINFO_SCREENFLASH;
|
clgame.scrInfo.iFlags = SCRINFO_SCREENFLASH;
|
||||||
|
@ -1742,7 +1745,8 @@ static int GAME_EXPORT pfnClientCmd( const char *szCmdString )
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// will exec later
|
// will exec later
|
||||||
Q_strncat( host.deferred_cmd, va( "%s\n", szCmdString ), sizeof( host.deferred_cmd ));
|
Q_strncat( host.deferred_cmd, szCmdString, sizeof( host.deferred_cmd ));
|
||||||
|
Q_strncat( host.deferred_cmd, "\n", sizeof( host.deferred_cmd ));
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -1867,24 +1871,13 @@ returns drawed chachter width (in real screen pixels)
|
||||||
*/
|
*/
|
||||||
static int GAME_EXPORT pfnDrawCharacter( int x, int y, int number, int r, int g, int b )
|
static int GAME_EXPORT pfnDrawCharacter( int x, int y, int number, int r, int g, int b )
|
||||||
{
|
{
|
||||||
if( !cls.creditsFont.valid )
|
rgba_t color = { r, g, b, 255 };
|
||||||
return 0;
|
int flags = FONT_DRAW_HUD;
|
||||||
|
|
||||||
if( hud_utf8->value )
|
if( hud_utf8->value )
|
||||||
number = Con_UtfProcessChar( number );
|
flags |= FONT_DRAW_UTF8;
|
||||||
|
|
||||||
number &= 255;
|
return CL_DrawCharacter( x, y, number, color, &cls.creditsFont, flags );
|
||||||
|
|
||||||
if( number < 32 ) return 0;
|
|
||||||
if( y < -clgame.scrInfo.iCharHeight )
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
clgame.ds.adjust_size = true;
|
|
||||||
pfnPIC_Set( cls.creditsFont.hFontTexture, r, g, b, 255 );
|
|
||||||
pfnPIC_DrawAdditive( x, y, -1, -1, &cls.creditsFont.fontRc[number] );
|
|
||||||
clgame.ds.adjust_size = false;
|
|
||||||
|
|
||||||
return clgame.scrInfo.charWidths[number];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1896,20 +1889,12 @@ drawing string like a console string
|
||||||
*/
|
*/
|
||||||
int GAME_EXPORT pfnDrawConsoleString( int x, int y, char *string )
|
int GAME_EXPORT pfnDrawConsoleString( int x, int y, char *string )
|
||||||
{
|
{
|
||||||
int drawLen;
|
cl_font_t *font = Con_GetFont( con_fontsize->value );
|
||||||
|
rgba_t color;
|
||||||
|
Vector4Copy( clgame.ds.textColor, color );
|
||||||
|
Vector4Set( clgame.ds.textColor, 255, 255, 255, 255 );
|
||||||
|
|
||||||
if( !COM_CheckString( string ))
|
return x + CL_DrawString( x, y, string, color, font, FONT_DRAW_UTF8 | FONT_DRAW_HUD );
|
||||||
return 0; // silent ignore
|
|
||||||
Con_SetFont( con_fontsize->value );
|
|
||||||
|
|
||||||
clgame.ds.adjust_size = true;
|
|
||||||
drawLen = Con_DrawString( x, y, string, clgame.ds.textColor );
|
|
||||||
MakeRGBA( clgame.ds.textColor, 255, 255, 255, 255 );
|
|
||||||
clgame.ds.adjust_size = false;
|
|
||||||
|
|
||||||
Con_RestoreFont();
|
|
||||||
|
|
||||||
return (x + drawLen); // exclude color prexfixes
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1937,9 +1922,10 @@ compute string length in screen pixels
|
||||||
*/
|
*/
|
||||||
void GAME_EXPORT pfnDrawConsoleStringLen( const char *pText, int *length, int *height )
|
void GAME_EXPORT pfnDrawConsoleStringLen( const char *pText, int *length, int *height )
|
||||||
{
|
{
|
||||||
Con_SetFont( con_fontsize->value );
|
cl_font_t *font = Con_GetFont( con_fontsize->value );
|
||||||
Con_DrawStringLen( pText, length, height );
|
|
||||||
Con_RestoreFont();
|
if( height ) *height = font->charHeight;
|
||||||
|
CL_DrawStringLen( font, pText, length, NULL, FONT_DRAW_UTF8 | FONT_DRAW_HUD );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1951,7 +1937,14 @@ prints directly into console (can skip notify)
|
||||||
*/
|
*/
|
||||||
static void GAME_EXPORT pfnConsolePrint( const char *string )
|
static void GAME_EXPORT pfnConsolePrint( const char *string )
|
||||||
{
|
{
|
||||||
|
if( !COM_CheckString( string ))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// WON GoldSrc behavior
|
||||||
|
if( string[0] != 1 )
|
||||||
Con_Printf( "%s", string );
|
Con_Printf( "%s", string );
|
||||||
|
else
|
||||||
|
Con_NPrintf( 0, "%s", string + 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2199,45 +2192,14 @@ pfnPointContents
|
||||||
|
|
||||||
=============
|
=============
|
||||||
*/
|
*/
|
||||||
static int GAME_EXPORT pfnPointContents( const float *p, int *truecontents )
|
int GAME_EXPORT PM_CL_PointContents( const float *p, int *truecontents )
|
||||||
{
|
{
|
||||||
int cont, truecont;
|
return PM_PointContentsPmove( clgame.pmove, p, truecontents );
|
||||||
|
|
||||||
truecont = cont = PM_PointContents( clgame.pmove, p );
|
|
||||||
if( truecontents ) *truecontents = truecont;
|
|
||||||
|
|
||||||
if( cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN )
|
|
||||||
cont = CONTENTS_WATER;
|
|
||||||
return cont;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
pmtrace_t *PM_CL_TraceLine( float *start, float *end, int flags, int usehull, int ignore_pe )
|
||||||
=============
|
|
||||||
pfnTraceLine
|
|
||||||
|
|
||||||
=============
|
|
||||||
*/
|
|
||||||
static pmtrace_t *pfnTraceLine( float *start, float *end, int flags, int usehull, int ignore_pe )
|
|
||||||
{
|
{
|
||||||
static pmtrace_t tr;
|
return PM_TraceLine( clgame.pmove, start, end, flags, usehull, ignore_pe );
|
||||||
int old_usehull;
|
|
||||||
|
|
||||||
old_usehull = clgame.pmove->usehull;
|
|
||||||
clgame.pmove->usehull = usehull;
|
|
||||||
|
|
||||||
switch( flags )
|
|
||||||
{
|
|
||||||
case PM_TRACELINE_PHYSENTSONLY:
|
|
||||||
tr = PM_PlayerTraceExt( clgame.pmove, start, end, 0, clgame.pmove->numphysent, clgame.pmove->physents, ignore_pe, NULL );
|
|
||||||
break;
|
|
||||||
case PM_TRACELINE_ANYVISIBLE:
|
|
||||||
tr = PM_PlayerTraceExt( clgame.pmove, start, end, 0, clgame.pmove->numvisent, clgame.pmove->visents, ignore_pe, NULL );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
clgame.pmove->usehull = old_usehull;
|
|
||||||
|
|
||||||
return &tr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void GAME_EXPORT pfnPlaySoundByNameAtLocation( char *szSound, float volume, float *origin )
|
static void GAME_EXPORT pfnPlaySoundByNameAtLocation( char *szSound, float volume, float *origin )
|
||||||
|
@ -2484,7 +2446,6 @@ pfnSetTraceHull
|
||||||
void GAME_EXPORT CL_SetTraceHull( int hull )
|
void GAME_EXPORT CL_SetTraceHull( int hull )
|
||||||
{
|
{
|
||||||
clgame.pmove->usehull = bound( 0, hull, 3 );
|
clgame.pmove->usehull = bound( 0, hull, 3 );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2513,19 +2474,13 @@ void GAME_EXPORT CL_PlayerTraceExt( float *start, float *end, int traceFlags, in
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=============
|
=============
|
||||||
pfnTraceTexture
|
CL_TraceTexture
|
||||||
|
|
||||||
=============
|
=============
|
||||||
*/
|
*/
|
||||||
static const char *pfnTraceTexture( int ground, float *vstart, float *vend )
|
const char * GAME_EXPORT PM_CL_TraceTexture( int ground, float *vstart, float *vend )
|
||||||
{
|
{
|
||||||
physent_t *pe;
|
return PM_TraceTexture( clgame.pmove, ground, vstart, vend );
|
||||||
|
|
||||||
if( ground < 0 || ground >= clgame.pmove->numphysent )
|
|
||||||
return NULL; // bad ground
|
|
||||||
|
|
||||||
pe = &clgame.pmove->physents[ground];
|
|
||||||
return PM_TraceTexture( pe, vstart, vend );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2536,13 +2491,7 @@ pfnTraceSurface
|
||||||
*/
|
*/
|
||||||
struct msurface_s *pfnTraceSurface( int ground, float *vstart, float *vend )
|
struct msurface_s *pfnTraceSurface( int ground, float *vstart, float *vend )
|
||||||
{
|
{
|
||||||
physent_t *pe;
|
return PM_TraceSurfacePmove( clgame.pmove, ground, vstart, vend );
|
||||||
|
|
||||||
if( ground < 0 || ground >= clgame.pmove->numphysent )
|
|
||||||
return NULL; // bad ground
|
|
||||||
|
|
||||||
pe = &clgame.pmove->physents[ground];
|
|
||||||
return PM_TraceSurface( pe, vstart, vend );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2633,7 +2582,10 @@ static const char *pfnGetLevelName( void )
|
||||||
{
|
{
|
||||||
static char mapname[64];
|
static char mapname[64];
|
||||||
|
|
||||||
if( cls.state >= ca_connected )
|
// a1ba: don't return maps/.bsp if no map is loaded yet
|
||||||
|
// in GoldSrc this is handled by cl.levelname field but we don't have it
|
||||||
|
// so emulate this behavior here
|
||||||
|
if( cls.state >= ca_connected && COM_CheckStringEmpty( clgame.mapname ))
|
||||||
Q_snprintf( mapname, sizeof( mapname ), "maps/%s.bsp", clgame.mapname );
|
Q_snprintf( mapname, sizeof( mapname ), "maps/%s.bsp", clgame.mapname );
|
||||||
else mapname[0] = '\0'; // not in game
|
else mapname[0] = '\0'; // not in game
|
||||||
|
|
||||||
|
@ -2899,23 +2851,7 @@ pfnVGUI2DrawCharacter
|
||||||
*/
|
*/
|
||||||
static int GAME_EXPORT pfnVGUI2DrawCharacter( int x, int y, int number, unsigned int font )
|
static int GAME_EXPORT pfnVGUI2DrawCharacter( int x, int y, int number, unsigned int font )
|
||||||
{
|
{
|
||||||
if( !cls.creditsFont.valid )
|
return pfnDrawCharacter( x, y, number, 255, 255, 255 );
|
||||||
return 0;
|
|
||||||
|
|
||||||
number &= 255;
|
|
||||||
|
|
||||||
number = Con_UtfProcessChar( number );
|
|
||||||
|
|
||||||
if( number < 32 ) return 0;
|
|
||||||
if( y < -clgame.scrInfo.iCharHeight )
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
clgame.ds.adjust_size = true;
|
|
||||||
gameui.ds.gl_texturenum = cls.creditsFont.hFontTexture;
|
|
||||||
pfnPIC_DrawAdditive( x, y, -1, -1, &cls.creditsFont.fontRc[number] );
|
|
||||||
clgame.ds.adjust_size = false;
|
|
||||||
|
|
||||||
return clgame.scrInfo.charWidths[number];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2926,9 +2862,6 @@ pfnVGUI2DrawCharacterAdditive
|
||||||
*/
|
*/
|
||||||
static int GAME_EXPORT pfnVGUI2DrawCharacterAdditive( int x, int y, int ch, int r, int g, int b, unsigned int font )
|
static int GAME_EXPORT pfnVGUI2DrawCharacterAdditive( int x, int y, int ch, int r, int g, int b, unsigned int font )
|
||||||
{
|
{
|
||||||
if( !hud_utf8->value )
|
|
||||||
ch = Con_UtfProcessChar( ch );
|
|
||||||
|
|
||||||
return pfnDrawCharacter( x, y, ch, r, g, b );
|
return pfnDrawCharacter( x, y, ch, r, g, b );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2940,16 +2873,13 @@ pfnDrawString
|
||||||
*/
|
*/
|
||||||
static int GAME_EXPORT pfnDrawString( int x, int y, const char *str, int r, int g, int b )
|
static int GAME_EXPORT pfnDrawString( int x, int y, const char *str, int r, int g, int b )
|
||||||
{
|
{
|
||||||
int iWidth = 0;
|
rgba_t color = { r, g, b, 255 };
|
||||||
Con_UtfProcessChar(0);
|
int flags = FONT_DRAW_HUD | FONT_DRAW_NOLF;
|
||||||
|
|
||||||
// draw the string until we hit the null character or a newline character
|
if( hud_utf8->value )
|
||||||
for ( ; *str != 0 && *str != '\n'; str++ )
|
SetBits( flags, FONT_DRAW_UTF8 );
|
||||||
{
|
|
||||||
iWidth += pfnVGUI2DrawCharacterAdditive( x + iWidth, y, (unsigned char)*str, r, g, b, 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
return iWidth;
|
return CL_DrawString( x, y, str, color, &cls.creditsFont, flags );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2960,11 +2890,18 @@ pfnDrawStringReverse
|
||||||
*/
|
*/
|
||||||
static int GAME_EXPORT pfnDrawStringReverse( int x, int y, const char *str, int r, int g, int b )
|
static int GAME_EXPORT pfnDrawStringReverse( int x, int y, const char *str, int r, int g, int b )
|
||||||
{
|
{
|
||||||
// find the end of the string
|
rgba_t color = { r, g, b, 255 };
|
||||||
char *szIt;
|
int flags = FONT_DRAW_HUD | FONT_DRAW_NOLF;
|
||||||
for( szIt = (char*)str; *szIt != 0; szIt++ )
|
int width;
|
||||||
x -= clgame.scrInfo.charWidths[ (unsigned char) *szIt ];
|
|
||||||
return pfnDrawString( x, y, str, r, g, b );
|
if( hud_utf8->value )
|
||||||
|
SetBits( flags, FONT_DRAW_UTF8 );
|
||||||
|
|
||||||
|
CL_DrawStringLen( &cls.creditsFont, str, &width, NULL, flags );
|
||||||
|
|
||||||
|
x -= width;
|
||||||
|
|
||||||
|
return CL_DrawString( x, y, str, color, &cls.creditsFont, flags );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -3368,7 +3305,7 @@ void GAME_EXPORT NetAPI_SendRequest( int context, int request, int flags, double
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( remote_address->type >= NA_IPX )
|
if( remote_address->type != NA_IPX && remote_address->type != NA_BROADCAST_IPX )
|
||||||
return; // IPX no longer support
|
return; // IPX no longer support
|
||||||
|
|
||||||
// find a free request
|
// find a free request
|
||||||
|
@ -3409,9 +3346,12 @@ void GAME_EXPORT NetAPI_SendRequest( int context, int request, int flags, double
|
||||||
|
|
||||||
if( request == NETAPI_REQUEST_SERVERLIST )
|
if( request == NETAPI_REQUEST_SERVERLIST )
|
||||||
{
|
{
|
||||||
char fullquery[512] = "1\xFF" "0.0.0.0:0\0" "\\gamedir\\";
|
char fullquery[512];
|
||||||
|
size_t len;
|
||||||
|
|
||||||
// make sure what port is specified
|
len = CL_BuildMasterServerScanRequest( fullquery, sizeof( fullquery ), false );
|
||||||
|
|
||||||
|
// make sure that port is specified
|
||||||
if( !nr->resp.remote_address.port )
|
if( !nr->resp.remote_address.port )
|
||||||
nr->resp.remote_address.port = MSG_BigShort( PORT_MASTER );
|
nr->resp.remote_address.port = MSG_BigShort( PORT_MASTER );
|
||||||
|
|
||||||
|
@ -3439,7 +3379,7 @@ void GAME_EXPORT NetAPI_CancelRequest( int context )
|
||||||
{
|
{
|
||||||
net_request_t *nr;
|
net_request_t *nr;
|
||||||
int i;
|
int i;
|
||||||
|
;
|
||||||
// find a specified request
|
// find a specified request
|
||||||
for( i = 0; i < MAX_REQUESTS; i++ )
|
for( i = 0; i < MAX_REQUESTS; i++ )
|
||||||
{
|
{
|
||||||
|
@ -3717,7 +3657,7 @@ static event_api_t gEventApi =
|
||||||
CL_WeaponAnim,
|
CL_WeaponAnim,
|
||||||
pfnPrecacheEvent,
|
pfnPrecacheEvent,
|
||||||
CL_PlaybackEvent,
|
CL_PlaybackEvent,
|
||||||
pfnTraceTexture,
|
PM_CL_TraceTexture,
|
||||||
pfnStopAllSounds,
|
pfnStopAllSounds,
|
||||||
pfnKillEvents,
|
pfnKillEvents,
|
||||||
CL_PlayerTraceExt, // Xash3D added
|
CL_PlayerTraceExt, // Xash3D added
|
||||||
|
@ -3822,9 +3762,9 @@ static cl_enginefunc_t gEngfuncs =
|
||||||
pfnGetClientTime,
|
pfnGetClientTime,
|
||||||
pfnCalcShake,
|
pfnCalcShake,
|
||||||
pfnApplyShake,
|
pfnApplyShake,
|
||||||
pfnPointContents,
|
PM_CL_PointContents,
|
||||||
CL_WaterEntity,
|
CL_WaterEntity,
|
||||||
pfnTraceLine,
|
PM_CL_TraceLine,
|
||||||
CL_LoadModel,
|
CL_LoadModel,
|
||||||
CL_AddEntity,
|
CL_AddEntity,
|
||||||
CL_GetSpritePointer,
|
CL_GetSpritePointer,
|
||||||
|
@ -3917,6 +3857,9 @@ void CL_UnloadProgs( void )
|
||||||
if( Q_stricmp( GI->gamefolder, "hlfx" ) || GI->version != 0.5f )
|
if( Q_stricmp( GI->gamefolder, "hlfx" ) || GI->version != 0.5f )
|
||||||
clgame.dllFuncs.pfnShutdown();
|
clgame.dllFuncs.pfnShutdown();
|
||||||
|
|
||||||
|
if( GI->internal_vgui_support )
|
||||||
|
VGui_Shutdown();
|
||||||
|
|
||||||
Cvar_FullSet( "cl_background", "0", FCVAR_READ_ONLY );
|
Cvar_FullSet( "cl_background", "0", FCVAR_READ_ONLY );
|
||||||
Cvar_FullSet( "host_clientloaded", "0", FCVAR_READ_ONLY );
|
Cvar_FullSet( "host_clientloaded", "0", FCVAR_READ_ONLY );
|
||||||
|
|
||||||
|
@ -3945,10 +3888,6 @@ qboolean CL_LoadProgs( const char *name )
|
||||||
clgame.mempool = Mem_AllocPool( "Client Edicts Zone" );
|
clgame.mempool = Mem_AllocPool( "Client Edicts Zone" );
|
||||||
clgame.entities = NULL;
|
clgame.entities = NULL;
|
||||||
|
|
||||||
// NOTE: important stuff!
|
|
||||||
// vgui must startup BEFORE loading client.dll to avoid get error ERROR_NOACESS
|
|
||||||
// during LoadLibrary
|
|
||||||
VGui_Startup( name, gameui.globals->scrWidth, gameui.globals->scrHeight );
|
|
||||||
|
|
||||||
// a1ba: we need to check if client.dll has direct dependency on SDL2
|
// a1ba: we need to check if client.dll has direct dependency on SDL2
|
||||||
// and if so, disable relative mouse mode
|
// and if so, disable relative mouse mode
|
||||||
|
@ -3967,8 +3906,29 @@ qboolean CL_LoadProgs( const char *name )
|
||||||
clgame.client_dll_uses_sdl = true;
|
clgame.client_dll_uses_sdl = true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// NOTE: important stuff!
|
||||||
|
// vgui must startup BEFORE loading client.dll to avoid get error ERROR_NOACESS
|
||||||
|
// during LoadLibrary
|
||||||
|
if( !GI->internal_vgui_support && VGui_LoadProgs( NULL ))
|
||||||
|
{
|
||||||
|
VGui_Startup( refState.width, refState.height );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// we failed to load vgui_support, but let's probe client.dll for support anyway
|
||||||
|
GI->internal_vgui_support = true;
|
||||||
|
}
|
||||||
|
|
||||||
clgame.hInstance = COM_LoadLibrary( name, false, false );
|
clgame.hInstance = COM_LoadLibrary( name, false, false );
|
||||||
if( !clgame.hInstance ) return false;
|
|
||||||
|
if( !clgame.hInstance )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// delayed vgui initialization for internal support
|
||||||
|
if( GI->internal_vgui_support && VGui_LoadProgs( clgame.hInstance ))
|
||||||
|
{
|
||||||
|
VGui_Startup( refState.width, refState.height );
|
||||||
|
}
|
||||||
|
|
||||||
// clear exports
|
// clear exports
|
||||||
for( func = cdll_exports; func && func->name; func++ )
|
for( func = cdll_exports; func && func->name; func++ )
|
||||||
|
|
|
@ -422,54 +422,6 @@ static void UI_ConvertGameInfo( GAMEINFO *out, gameinfo_t *in )
|
||||||
out->flags |= GFL_RENDER_PICBUTTON_TEXT;
|
out->flags |= GFL_RENDER_PICBUTTON_TEXT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static qboolean PIC_Scissor( float *x, float *y, float *width, float *height, float *u0, float *v0, float *u1, float *v1 )
|
|
||||||
{
|
|
||||||
float dudx, dvdy;
|
|
||||||
|
|
||||||
// clip sub rect to sprite
|
|
||||||
if(( width == 0 ) || ( height == 0 ))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if( *x + *width <= gameui.ds.scissor_x )
|
|
||||||
return false;
|
|
||||||
if( *x >= gameui.ds.scissor_x + gameui.ds.scissor_width )
|
|
||||||
return false;
|
|
||||||
if( *y + *height <= gameui.ds.scissor_y )
|
|
||||||
return false;
|
|
||||||
if( *y >= gameui.ds.scissor_y + gameui.ds.scissor_height )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
dudx = (*u1 - *u0) / *width;
|
|
||||||
dvdy = (*v1 - *v0) / *height;
|
|
||||||
|
|
||||||
if( *x < gameui.ds.scissor_x )
|
|
||||||
{
|
|
||||||
*u0 += (gameui.ds.scissor_x - *x) * dudx;
|
|
||||||
*width -= gameui.ds.scissor_x - *x;
|
|
||||||
*x = gameui.ds.scissor_x;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( *x + *width > gameui.ds.scissor_x + gameui.ds.scissor_width )
|
|
||||||
{
|
|
||||||
*u1 -= (*x + *width - (gameui.ds.scissor_x + gameui.ds.scissor_width)) * dudx;
|
|
||||||
*width = gameui.ds.scissor_x + gameui.ds.scissor_width - *x;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( *y < gameui.ds.scissor_y )
|
|
||||||
{
|
|
||||||
*v0 += (gameui.ds.scissor_y - *y) * dvdy;
|
|
||||||
*height -= gameui.ds.scissor_y - *y;
|
|
||||||
*y = gameui.ds.scissor_y;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( *y + *height > gameui.ds.scissor_y + gameui.ds.scissor_height )
|
|
||||||
{
|
|
||||||
*v1 -= (*y + *height - (gameui.ds.scissor_y + gameui.ds.scissor_height)) * dvdy;
|
|
||||||
*height = gameui.ds.scissor_y + gameui.ds.scissor_height - *y;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
====================
|
====================
|
||||||
PIC_DrawGeneric
|
PIC_DrawGeneric
|
||||||
|
@ -488,10 +440,10 @@ static void PIC_DrawGeneric( float x, float y, float width, float height, const
|
||||||
if( prc )
|
if( prc )
|
||||||
{
|
{
|
||||||
// calc user-defined rectangle
|
// calc user-defined rectangle
|
||||||
s1 = (float)prc->left / (float)w;
|
s1 = prc->left / (float)w;
|
||||||
t1 = (float)prc->top / (float)h;
|
t1 = prc->top / (float)h;
|
||||||
s2 = (float)prc->right / (float)w;
|
s2 = prc->right / (float)w;
|
||||||
t2 = (float)prc->bottom / (float)h;
|
t2 = prc->bottom / (float)h;
|
||||||
|
|
||||||
if( width == -1 && height == -1 )
|
if( width == -1 && height == -1 )
|
||||||
{
|
{
|
||||||
|
@ -512,10 +464,9 @@ static void PIC_DrawGeneric( float x, float y, float width, float height, const
|
||||||
}
|
}
|
||||||
|
|
||||||
// pass scissor test if supposed
|
// pass scissor test if supposed
|
||||||
if( gameui.ds.scissor_test && !PIC_Scissor( &x, &y, &width, &height, &s1, &t1, &s2, &t2 ))
|
if( !CL_Scissor( &gameui.ds.scissor, &x, &y, &width, &height, &s1, &t1, &s2, &t2 ))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
PicAdjustSize( &x, &y, &width, &height );
|
|
||||||
ref.dllFuncs.R_DrawStretchPic( x, y, width, height, s1, t1, s2, t2, gameui.ds.gl_texturenum );
|
ref.dllFuncs.R_DrawStretchPic( x, y, width, height, s1, t1, s2, t2, gameui.ds.gl_texturenum );
|
||||||
ref.dllFuncs.Color4ub( 255, 255, 255, 255 );
|
ref.dllFuncs.Color4ub( 255, 255, 255, 255 );
|
||||||
}
|
}
|
||||||
|
@ -660,11 +611,7 @@ static void GAME_EXPORT pfnPIC_EnableScissor( int x, int y, int width, int heigh
|
||||||
width = bound( 0, width, gameui.globals->scrWidth - x );
|
width = bound( 0, width, gameui.globals->scrWidth - x );
|
||||||
height = bound( 0, height, gameui.globals->scrHeight - y );
|
height = bound( 0, height, gameui.globals->scrHeight - y );
|
||||||
|
|
||||||
gameui.ds.scissor_x = x;
|
CL_EnableScissor( &gameui.ds.scissor, x, y, width, height );
|
||||||
gameui.ds.scissor_width = width;
|
|
||||||
gameui.ds.scissor_y = y;
|
|
||||||
gameui.ds.scissor_height = height;
|
|
||||||
gameui.ds.scissor_test = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -675,11 +622,7 @@ pfnPIC_DisableScissor
|
||||||
*/
|
*/
|
||||||
static void GAME_EXPORT pfnPIC_DisableScissor( void )
|
static void GAME_EXPORT pfnPIC_DisableScissor( void )
|
||||||
{
|
{
|
||||||
gameui.ds.scissor_x = 0;
|
CL_DisableScissor( &gameui.ds.scissor );
|
||||||
gameui.ds.scissor_width = 0;
|
|
||||||
gameui.ds.scissor_y = 0;
|
|
||||||
gameui.ds.scissor_height = 0;
|
|
||||||
gameui.ds.scissor_test = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -767,7 +710,7 @@ static void GAME_EXPORT pfnDrawCharacter( int ix, int iy, int iwidth, int iheigh
|
||||||
t2 = t1 + size;
|
t2 = t1 + size;
|
||||||
|
|
||||||
// pass scissor test if supposed
|
// pass scissor test if supposed
|
||||||
if( gameui.ds.scissor_test && !PIC_Scissor( &x, &y, &width, &height, &s1, &t1, &s2, &t2 ))
|
if( !CL_Scissor( &gameui.ds.scissor, &x, &y, &width, &height, &s1, &t1, &s2, &t2 ))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ref.dllFuncs.GL_SetRenderMode( kRenderTransTexture );
|
ref.dllFuncs.GL_SetRenderMode( kRenderTransTexture );
|
||||||
|
@ -1264,6 +1207,7 @@ static ui_extendedfuncs_t gExtendedfuncs =
|
||||||
Sys_DoubleTime,
|
Sys_DoubleTime,
|
||||||
pfnParseFileSafe,
|
pfnParseFileSafe,
|
||||||
NET_AdrToString,
|
NET_AdrToString,
|
||||||
|
NET_CompareAdrSort,
|
||||||
R_GetRenderDevice
|
R_GetRenderDevice
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -22,12 +22,13 @@ GNU General Public License for more details.
|
||||||
#include "vgui_draw.h"
|
#include "vgui_draw.h"
|
||||||
#include "library.h"
|
#include "library.h"
|
||||||
#include "vid_common.h"
|
#include "vid_common.h"
|
||||||
|
#include "pm_local.h"
|
||||||
|
|
||||||
#define MAX_TOTAL_CMDS 32
|
#define MAX_TOTAL_CMDS 32
|
||||||
#define MAX_CMD_BUFFER 8000
|
#define MAX_CMD_BUFFER 8000
|
||||||
#define CONNECTION_PROBLEM_TIME 15.0 // 15 seconds
|
#define CONNECTION_PROBLEM_TIME 15.0 // 15 seconds
|
||||||
#define CL_CONNECTION_RETRIES 10
|
#define CL_CONNECTION_RETRIES 10
|
||||||
#define CL_TEST_RETRIES_NORESPONCE 2
|
#define CL_TEST_RETRIES_NORESPONCE 3
|
||||||
#define CL_TEST_RETRIES 5
|
#define CL_TEST_RETRIES 5
|
||||||
|
|
||||||
CVAR_DEFINE_AUTO( mp_decals, "300", FCVAR_ARCHIVE, "decals limit in multiplayer" );
|
CVAR_DEFINE_AUTO( mp_decals, "300", FCVAR_ARCHIVE, "decals limit in multiplayer" );
|
||||||
|
@ -38,8 +39,8 @@ CVAR_DEFINE_AUTO( cl_allow_upload, "1", FCVAR_ARCHIVE, "allow to uploading resou
|
||||||
CVAR_DEFINE_AUTO( cl_download_ingame, "1", FCVAR_ARCHIVE, "allow to downloading resources while client is active" );
|
CVAR_DEFINE_AUTO( cl_download_ingame, "1", FCVAR_ARCHIVE, "allow to downloading resources while client is active" );
|
||||||
CVAR_DEFINE_AUTO( cl_logofile, "lambda", FCVAR_ARCHIVE, "player logo name" );
|
CVAR_DEFINE_AUTO( cl_logofile, "lambda", FCVAR_ARCHIVE, "player logo name" );
|
||||||
CVAR_DEFINE_AUTO( cl_logocolor, "orange", FCVAR_ARCHIVE, "player logo color" );
|
CVAR_DEFINE_AUTO( cl_logocolor, "orange", FCVAR_ARCHIVE, "player logo color" );
|
||||||
|
CVAR_DEFINE_AUTO( cl_logoext, "bmp", FCVAR_ARCHIVE, "temporary cvar to tell engine which logo must be packed" );
|
||||||
CVAR_DEFINE_AUTO( cl_test_bandwidth, "1", FCVAR_ARCHIVE, "test network bandwith before connection" );
|
CVAR_DEFINE_AUTO( cl_test_bandwidth, "1", FCVAR_ARCHIVE, "test network bandwith before connection" );
|
||||||
convar_t *rcon_client_password;
|
|
||||||
convar_t *rcon_address;
|
convar_t *rcon_address;
|
||||||
convar_t *cl_timeout;
|
convar_t *cl_timeout;
|
||||||
convar_t *cl_nopred;
|
convar_t *cl_nopred;
|
||||||
|
@ -56,6 +57,7 @@ convar_t *cl_nosmooth;
|
||||||
convar_t *cl_smoothtime;
|
convar_t *cl_smoothtime;
|
||||||
convar_t *cl_clockreset;
|
convar_t *cl_clockreset;
|
||||||
convar_t *cl_fixtimerate;
|
convar_t *cl_fixtimerate;
|
||||||
|
convar_t *hud_fontscale;
|
||||||
convar_t *hud_scale;
|
convar_t *hud_scale;
|
||||||
convar_t *cl_solid_players;
|
convar_t *cl_solid_players;
|
||||||
convar_t *cl_draw_beams;
|
convar_t *cl_draw_beams;
|
||||||
|
@ -241,11 +243,6 @@ void CL_SignonReply( void )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float CL_LerpInterval( void )
|
|
||||||
{
|
|
||||||
return Q_max( cl_interp->value, 1.f / cl_updaterate->value );
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
===============
|
===============
|
||||||
CL_LerpPoint
|
CL_LerpPoint
|
||||||
|
@ -256,55 +253,26 @@ should be put at.
|
||||||
*/
|
*/
|
||||||
static float CL_LerpPoint( void )
|
static float CL_LerpPoint( void )
|
||||||
{
|
{
|
||||||
float frac = 1.0f;
|
double f = cl_serverframetime();
|
||||||
float server_frametime = cl_serverframetime();
|
double frac;
|
||||||
|
|
||||||
if( server_frametime == 0.0f || cls.timedemo )
|
if( f == 0.0 || cls.timedemo )
|
||||||
{
|
{
|
||||||
|
double fgap = cl_clientframetime();
|
||||||
cl.time = cl.mtime[0];
|
cl.time = cl.mtime[0];
|
||||||
|
|
||||||
|
// maybe don't need for Xash demos
|
||||||
|
if( cls.demoplayback )
|
||||||
|
cl.oldtime = cl.mtime[0] - fgap;
|
||||||
|
|
||||||
return 1.0f;
|
return 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( server_frametime > 0.1f )
|
if( cl_interp->value <= 0.001 )
|
||||||
{
|
return 1.0f;
|
||||||
// dropped packet, or start of demo
|
|
||||||
cl.mtime[1] = cl.mtime[0] - 0.1f;
|
frac = ( cl.time - cl.mtime[0] ) / cl_interp->value;
|
||||||
server_frametime = 0.1f;
|
|
||||||
}
|
|
||||||
#if 0
|
|
||||||
/*
|
|
||||||
g-cont: this code more suitable for singleplayer
|
|
||||||
NOTE in multiplayer causes significant framerate stutter/jitter and
|
|
||||||
occuring frames with zero time delta and even with negative time delta.
|
|
||||||
game becomes more twitchy and as if without interpolation.
|
|
||||||
*/
|
|
||||||
frac = (cl.time - cl.mtime[1]) / f;
|
|
||||||
if( frac < 0.0f )
|
|
||||||
{
|
|
||||||
if( frac < -0.01f )
|
|
||||||
cl.time = cl.mtime[1];
|
|
||||||
frac = 0.0f;
|
|
||||||
}
|
|
||||||
else if( frac > 1.0f )
|
|
||||||
{
|
|
||||||
if( frac > 1.01f )
|
|
||||||
cl.time = cl.mtime[0];
|
|
||||||
frac = 1.0f;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
// for multiplayer
|
|
||||||
if( cl_interp->value > 0.001f )
|
|
||||||
{
|
|
||||||
// manual lerp value (goldsrc mode)
|
|
||||||
float td = Q_max( 0.f, cl.time - cl.mtime[0] );
|
|
||||||
frac = td / CL_LerpInterval();
|
|
||||||
}
|
|
||||||
else if( server_frametime > 0.001f )
|
|
||||||
{
|
|
||||||
// automatic lerp (classic mode)
|
|
||||||
frac = ( cl.time - cl.mtime[1] ) / server_frametime;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return frac;
|
return frac;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,7 +314,7 @@ Validate interpolation cvars, calc interpolation window
|
||||||
void CL_ComputeClientInterpolationAmount( usercmd_t *cmd )
|
void CL_ComputeClientInterpolationAmount( usercmd_t *cmd )
|
||||||
{
|
{
|
||||||
const float epsilon = 0.001f; // to avoid float invalid comparision
|
const float epsilon = 0.001f; // to avoid float invalid comparision
|
||||||
float min_interp = MIN_EX_INTERP;
|
float min_interp;
|
||||||
float max_interp = MAX_EX_INTERP;
|
float max_interp = MAX_EX_INTERP;
|
||||||
float interpolation_time;
|
float interpolation_time;
|
||||||
|
|
||||||
|
@ -366,7 +334,7 @@ void CL_ComputeClientInterpolationAmount( usercmd_t *cmd )
|
||||||
max_interp = 0.2f;
|
max_interp = 0.2f;
|
||||||
|
|
||||||
min_interp = 1.0f / cl_updaterate->value;
|
min_interp = 1.0f / cl_updaterate->value;
|
||||||
interpolation_time = CL_LerpInterval( );
|
interpolation_time = cl_interp->value * 1000.0;
|
||||||
|
|
||||||
if( (cl_interp->value + epsilon) < min_interp )
|
if( (cl_interp->value + epsilon) < min_interp )
|
||||||
{
|
{
|
||||||
|
@ -622,7 +590,7 @@ CL_CreateCmd
|
||||||
*/
|
*/
|
||||||
void CL_CreateCmd( void )
|
void CL_CreateCmd( void )
|
||||||
{
|
{
|
||||||
usercmd_t cmd;
|
usercmd_t nullcmd, *cmd;
|
||||||
runcmd_t *pcmd;
|
runcmd_t *pcmd;
|
||||||
vec3_t angles;
|
vec3_t angles;
|
||||||
qboolean active;
|
qboolean active;
|
||||||
|
@ -635,7 +603,6 @@ void CL_CreateCmd( void )
|
||||||
// store viewangles in case it's will be freeze
|
// store viewangles in case it's will be freeze
|
||||||
VectorCopy( cl.viewangles, angles );
|
VectorCopy( cl.viewangles, angles );
|
||||||
ms = bound( 1, host.frametime * 1000, 255 );
|
ms = bound( 1, host.frametime * 1000, 255 );
|
||||||
memset( &cmd, 0, sizeof( cmd ));
|
|
||||||
input_override = 0;
|
input_override = 0;
|
||||||
|
|
||||||
CL_SetSolidEntities();
|
CL_SetSolidEntities();
|
||||||
|
@ -654,12 +621,18 @@ void CL_CreateCmd( void )
|
||||||
pcmd->receivedtime = -1.0;
|
pcmd->receivedtime = -1.0;
|
||||||
pcmd->heldback = false;
|
pcmd->heldback = false;
|
||||||
pcmd->sendsize = 0;
|
pcmd->sendsize = 0;
|
||||||
|
cmd = &pcmd->cmd;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memset( &nullcmd, 0, sizeof( nullcmd ));
|
||||||
|
cmd = &nullcmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
active = (( cls.signon == SIGNONS ) && !cl.paused && !cls.demoplayback );
|
active = (( cls.signon == SIGNONS ) && !cl.paused && !cls.demoplayback );
|
||||||
Platform_PreCreateMove();
|
Platform_PreCreateMove();
|
||||||
clgame.dllFuncs.CL_CreateMove( host.frametime, &pcmd->cmd, active );
|
clgame.dllFuncs.CL_CreateMove( host.frametime, cmd, active );
|
||||||
IN_EngineAppendMove( host.frametime, &pcmd->cmd, active );
|
IN_EngineAppendMove( host.frametime, cmd, active );
|
||||||
|
|
||||||
CL_PopPMStates();
|
CL_PopPMStates();
|
||||||
|
|
||||||
|
@ -736,15 +709,22 @@ void CL_WritePacket( void )
|
||||||
|
|
||||||
CL_ComputePacketLoss ();
|
CL_ComputePacketLoss ();
|
||||||
|
|
||||||
|
memset( data, 0, sizeof( data ));
|
||||||
MSG_Init( &buf, "ClientData", data, sizeof( data ));
|
MSG_Init( &buf, "ClientData", data, sizeof( data ));
|
||||||
|
|
||||||
// Determine number of backup commands to send along
|
// Determine number of backup commands to send along
|
||||||
numbackup = bound( 0, cl_cmdbackup->value, MAX_BACKUP_COMMANDS );
|
numbackup = bound( 0, cl_cmdbackup->value, cls.legacymode ? MAX_LEGACY_BACKUP_CMDS : MAX_BACKUP_COMMANDS );
|
||||||
if( cls.state == ca_connected ) numbackup = 0;
|
if( cls.state == ca_connected ) numbackup = 0;
|
||||||
|
|
||||||
// clamp cmdrate
|
// clamp cmdrate
|
||||||
if( cl_cmdrate->value < 0.0f ) Cvar_SetValue( "cl_cmdrate", 0.0f );
|
if( cl_cmdrate->value < 10.0f )
|
||||||
else if( cl_cmdrate->value > 100.0f ) Cvar_SetValue( "cl_cmdrate", 100.0f );
|
{
|
||||||
|
Cvar_SetValue( "cl_cmdrate", 10.0f );
|
||||||
|
}
|
||||||
|
else if( cl_cmdrate->value > 100.0f )
|
||||||
|
{
|
||||||
|
Cvar_SetValue( "cl_cmdrate", 100.0f );
|
||||||
|
}
|
||||||
|
|
||||||
// Check to see if we can actually send this command
|
// Check to see if we can actually send this command
|
||||||
|
|
||||||
|
@ -774,6 +754,7 @@ void CL_WritePacket( void )
|
||||||
if(( host.realtime - cls.netchan.last_received ) > CONNECTION_PROBLEM_TIME )
|
if(( host.realtime - cls.netchan.last_received ) > CONNECTION_PROBLEM_TIME )
|
||||||
{
|
{
|
||||||
Con_NPrintf( 1, "^3Warning:^1 Connection Problem^7\n" );
|
Con_NPrintf( 1, "^3Warning:^1 Connection Problem^7\n" );
|
||||||
|
Con_NPrintf( 2, "^1Auto-disconnect in %.1f seconds^7", cl_timeout->value - ( host.realtime - cls.netchan.last_received ));
|
||||||
cl.validsequence = 0;
|
cl.validsequence = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -813,12 +794,13 @@ void CL_WritePacket( void )
|
||||||
newcmds = ( cls.netchan.outgoing_sequence - cls.lastoutgoingcommand );
|
newcmds = ( cls.netchan.outgoing_sequence - cls.lastoutgoingcommand );
|
||||||
|
|
||||||
// put an upper/lower bound on this
|
// put an upper/lower bound on this
|
||||||
newcmds = bound( 0, newcmds, cls.legacymode?MAX_LEGACY_TOTAL_CMDS:MAX_TOTAL_CMDS );
|
newcmds = bound( 0, newcmds, cls.legacymode ? MAX_LEGACY_TOTAL_CMDS: MAX_TOTAL_CMDS );
|
||||||
if( cls.state == ca_connected ) newcmds = 0;
|
if( cls.state == ca_connected ) newcmds = 0;
|
||||||
|
|
||||||
MSG_WriteByte( &buf, newcmds );
|
MSG_WriteByte( &buf, newcmds );
|
||||||
|
|
||||||
numcmds = newcmds + numbackup;
|
numcmds = newcmds + numbackup;
|
||||||
|
|
||||||
from = -1;
|
from = -1;
|
||||||
|
|
||||||
for( i = numcmds - 1; i >= 0; i-- )
|
for( i = numcmds - 1; i >= 0; i-- )
|
||||||
|
@ -864,6 +846,9 @@ void CL_WritePacket( void )
|
||||||
cl.commands[cls.netchan.outgoing_sequence & CL_UPDATE_MASK].sendsize = MSG_GetNumBytesWritten( &buf );
|
cl.commands[cls.netchan.outgoing_sequence & CL_UPDATE_MASK].sendsize = MSG_GetNumBytesWritten( &buf );
|
||||||
cl.commands[cls.netchan.outgoing_sequence & CL_UPDATE_MASK].heldback = false;
|
cl.commands[cls.netchan.outgoing_sequence & CL_UPDATE_MASK].heldback = false;
|
||||||
|
|
||||||
|
// send voice data to the server
|
||||||
|
CL_AddVoiceToDatagram();
|
||||||
|
|
||||||
// composite the rest of the datagram..
|
// composite the rest of the datagram..
|
||||||
if( MSG_GetNumBitsWritten( &cls.datagram ) <= MSG_GetNumBitsLeft( &buf ))
|
if( MSG_GetNumBitsWritten( &cls.datagram ) <= MSG_GetNumBitsLeft( &buf ))
|
||||||
MSG_WriteBits( &buf, MSG_GetData( &cls.datagram ), MSG_GetNumBitsWritten( &cls.datagram ));
|
MSG_WriteBits( &buf, MSG_GetData( &cls.datagram ), MSG_GetNumBitsWritten( &cls.datagram ));
|
||||||
|
@ -1041,6 +1026,9 @@ void CL_SendConnectPacket( void )
|
||||||
input_devices = IN_CollectInputDevices();
|
input_devices = IN_CollectInputDevices();
|
||||||
IN_LockInputDevices( true );
|
IN_LockInputDevices( true );
|
||||||
|
|
||||||
|
Cvar_SetCheatState();
|
||||||
|
Cvar_FullSet( "sv_cheats", "0", FCVAR_READ_ONLY | FCVAR_SERVER );
|
||||||
|
|
||||||
Info_SetValueForKey( protinfo, "d", va( "%d", input_devices ), sizeof( protinfo ) );
|
Info_SetValueForKey( protinfo, "d", va( "%d", input_devices ), sizeof( protinfo ) );
|
||||||
Info_SetValueForKey( protinfo, "v", XASH_VERSION, sizeof( protinfo ) );
|
Info_SetValueForKey( protinfo, "v", XASH_VERSION, sizeof( protinfo ) );
|
||||||
Info_SetValueForKey( protinfo, "b", va( "%d", Q_buildnum() ), sizeof( protinfo ) );
|
Info_SetValueForKey( protinfo, "b", va( "%d", Q_buildnum() ), sizeof( protinfo ) );
|
||||||
|
@ -1097,6 +1085,7 @@ void CL_CheckForResend( void )
|
||||||
{
|
{
|
||||||
netadr_t adr;
|
netadr_t adr;
|
||||||
int res;
|
int res;
|
||||||
|
qboolean bandwidthTest;
|
||||||
|
|
||||||
if( cls.internetservers_wait )
|
if( cls.internetservers_wait )
|
||||||
CL_InternetServers_f();
|
CL_InternetServers_f();
|
||||||
|
@ -1161,14 +1150,18 @@ void CL_CheckForResend( void )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bandwidthTest = !cls.legacymode && cl_test_bandwidth.value;
|
||||||
cls.serveradr = adr;
|
cls.serveradr = adr;
|
||||||
cls.max_fragment_size = Q_max( FRAGMENT_MAX_SIZE, cls.max_fragment_size >> Q_min( 1, cls.connect_retry ));
|
cls.max_fragment_size = Q_min( FRAGMENT_MAX_SIZE, cls.max_fragment_size / (cls.connect_retry + 1));
|
||||||
cls.connect_time = host.realtime; // for retransmit requests
|
cls.connect_time = host.realtime; // for retransmit requests
|
||||||
cls.connect_retry++;
|
cls.connect_retry++;
|
||||||
|
|
||||||
|
if( bandwidthTest )
|
||||||
|
Con_Printf( "Connecting to %s... [retry #%i, max fragment size %i]\n", cls.servername, cls.connect_retry, cls.max_fragment_size );
|
||||||
|
else
|
||||||
Con_Printf( "Connecting to %s... [retry #%i]\n", cls.servername, cls.connect_retry );
|
Con_Printf( "Connecting to %s... [retry #%i]\n", cls.servername, cls.connect_retry );
|
||||||
|
|
||||||
if( !cls.legacymode && cl_test_bandwidth.value )
|
if( bandwidthTest )
|
||||||
Netchan_OutOfBandPrint( NS_CLIENT, adr, "bandwidth %i %i\n", PROTOCOL_VERSION, cls.max_fragment_size );
|
Netchan_OutOfBandPrint( NS_CLIENT, adr, "bandwidth %i %i\n", PROTOCOL_VERSION, cls.max_fragment_size );
|
||||||
else
|
else
|
||||||
Netchan_OutOfBandPrint( NS_CLIENT, adr, "getchallenge\n" );
|
Netchan_OutOfBandPrint( NS_CLIENT, adr, "getchallenge\n" );
|
||||||
|
@ -1201,14 +1194,20 @@ void CL_CreateResourceList( void )
|
||||||
|
|
||||||
HPAK_FlushHostQueue();
|
HPAK_FlushHostQueue();
|
||||||
cl.num_resources = 0;
|
cl.num_resources = 0;
|
||||||
|
|
||||||
Q_snprintf( szFileName, sizeof( szFileName ), "logos/remapped.bmp" );
|
|
||||||
memset( rgucMD5_hash, 0, sizeof( rgucMD5_hash ));
|
memset( rgucMD5_hash, 0, sizeof( rgucMD5_hash ));
|
||||||
|
|
||||||
|
// sanitize cvar value
|
||||||
|
if( Q_strcmp( cl_logoext.string, "bmp" ) &&
|
||||||
|
Q_strcmp( cl_logoext.string, "png" ))
|
||||||
|
Cvar_DirectSet( &cl_logoext, "bmp" );
|
||||||
|
|
||||||
|
Q_snprintf( szFileName, sizeof( szFileName ),
|
||||||
|
"logos/remapped.%s", cl_logoext.string );
|
||||||
fp = FS_Open( szFileName, "rb", true );
|
fp = FS_Open( szFileName, "rb", true );
|
||||||
|
|
||||||
if( fp )
|
if( !fp )
|
||||||
{
|
return;
|
||||||
|
|
||||||
MD5_HashFile( rgucMD5_hash, szFileName, NULL );
|
MD5_HashFile( rgucMD5_hash, szFileName, NULL );
|
||||||
nSize = FS_FileLength( fp );
|
nSize = FS_FileLength( fp );
|
||||||
|
|
||||||
|
@ -1223,8 +1222,8 @@ void CL_CreateResourceList( void )
|
||||||
HPAK_AddLump( false, CUSTOM_RES_PATH, pNewResource, NULL, fp );
|
HPAK_AddLump( false, CUSTOM_RES_PATH, pNewResource, NULL, fp );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FS_Close( fp );
|
FS_Close( fp );
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1287,7 +1286,7 @@ void CL_Rcon_f( void )
|
||||||
string command;
|
string command;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if( !COM_CheckString( rcon_client_password->string ))
|
if( !COM_CheckString( rcon_password.string ))
|
||||||
{
|
{
|
||||||
Con_Printf( "You must set 'rcon_password' before issuing an rcon command.\n" );
|
Con_Printf( "You must set 'rcon_password' before issuing an rcon command.\n" );
|
||||||
return;
|
return;
|
||||||
|
@ -1302,7 +1301,7 @@ void CL_Rcon_f( void )
|
||||||
NET_Config( true, false ); // allow remote
|
NET_Config( true, false ); // allow remote
|
||||||
|
|
||||||
Q_strcat( message, "rcon " );
|
Q_strcat( message, "rcon " );
|
||||||
Q_strcat( message, rcon_client_password->string );
|
Q_strcat( message, rcon_password.string );
|
||||||
Q_strcat( message, " " );
|
Q_strcat( message, " " );
|
||||||
|
|
||||||
for( i = 1; i < Cmd_Argc(); i++ )
|
for( i = 1; i < Cmd_Argc(); i++ )
|
||||||
|
@ -1351,7 +1350,7 @@ void CL_ClearState( void )
|
||||||
CL_ClearEffects ();
|
CL_ClearEffects ();
|
||||||
CL_FreeEdicts ();
|
CL_FreeEdicts ();
|
||||||
|
|
||||||
CL_ClearPhysEnts ();
|
PM_ClearPhysEnts( clgame.pmove );
|
||||||
NetAPI_CancelAllRequests();
|
NetAPI_CancelAllRequests();
|
||||||
|
|
||||||
// wipe the entire cl structure
|
// wipe the entire cl structure
|
||||||
|
@ -1359,6 +1358,7 @@ void CL_ClearState( void )
|
||||||
MSG_Clear( &cls.netchan.message );
|
MSG_Clear( &cls.netchan.message );
|
||||||
memset( &clgame.fade, 0, sizeof( clgame.fade ));
|
memset( &clgame.fade, 0, sizeof( clgame.fade ));
|
||||||
memset( &clgame.shake, 0, sizeof( clgame.shake ));
|
memset( &clgame.shake, 0, sizeof( clgame.shake ));
|
||||||
|
clgame.mapname[0] = '\0';
|
||||||
Cvar_FullSet( "cl_background", "0", FCVAR_READ_ONLY );
|
Cvar_FullSet( "cl_background", "0", FCVAR_READ_ONLY );
|
||||||
cl.maxclients = 1; // allow to drawing player in menu
|
cl.maxclients = 1; // allow to drawing player in menu
|
||||||
cl.mtime[0] = cl.mtime[1] = 1.0f; // because level starts from 1.0f second
|
cl.mtime[0] = cl.mtime[1] = 1.0f; // because level starts from 1.0f second
|
||||||
|
@ -1500,6 +1500,7 @@ void CL_Disconnect( void )
|
||||||
cls.connect_time = 0;
|
cls.connect_time = 0;
|
||||||
cls.changedemo = false;
|
cls.changedemo = false;
|
||||||
cls.max_fragment_size = FRAGMENT_MAX_SIZE; // reset fragment size
|
cls.max_fragment_size = FRAGMENT_MAX_SIZE; // reset fragment size
|
||||||
|
Voice_Disconnect();
|
||||||
CL_Stop_f();
|
CL_Stop_f();
|
||||||
|
|
||||||
// send a disconnect message to the server
|
// send a disconnect message to the server
|
||||||
|
@ -1567,11 +1568,38 @@ void CL_LocalServers_f( void )
|
||||||
// send a broadcast packet
|
// send a broadcast packet
|
||||||
adr.type = NA_BROADCAST;
|
adr.type = NA_BROADCAST;
|
||||||
adr.port = MSG_BigShort( PORT_SERVER );
|
adr.port = MSG_BigShort( PORT_SERVER );
|
||||||
|
Netchan_OutOfBandPrint( NS_CLIENT, adr, "info %i", PROTOCOL_VERSION );
|
||||||
|
|
||||||
|
adr.type = NA_MULTICAST_IP6;
|
||||||
Netchan_OutOfBandPrint( NS_CLIENT, adr, "info %i", PROTOCOL_VERSION );
|
Netchan_OutOfBandPrint( NS_CLIENT, adr, "info %i", PROTOCOL_VERSION );
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MS_SCAN_REQUEST "1\xFF" "0.0.0.0:0\0"
|
/*
|
||||||
|
=================
|
||||||
|
CL_BuildMasterServerScanRequest
|
||||||
|
=================
|
||||||
|
*/
|
||||||
|
size_t CL_BuildMasterServerScanRequest( char *buf, size_t size, qboolean nat )
|
||||||
|
{
|
||||||
|
size_t remaining;
|
||||||
|
char *info;
|
||||||
|
|
||||||
|
if( unlikely( size < sizeof( MS_SCAN_REQUEST )))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
Q_strncpy( buf, MS_SCAN_REQUEST, size );
|
||||||
|
|
||||||
|
info = buf + sizeof( MS_SCAN_REQUEST ) - 1;
|
||||||
|
remaining = size - sizeof( MS_SCAN_REQUEST );
|
||||||
|
|
||||||
|
info[0] = 0;
|
||||||
|
|
||||||
|
Info_SetValueForKey( info, "gamedir", GI->gamefolder, remaining );
|
||||||
|
Info_SetValueForKey( info, "clver", XASH_VERSION, remaining ); // let master know about client version
|
||||||
|
Info_SetValueForKey( info, "nat", nat ? "1" : "0", remaining );
|
||||||
|
|
||||||
|
return sizeof( MS_SCAN_REQUEST ) + Q_strlen( info );
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=================
|
=================
|
||||||
|
@ -1580,18 +1608,17 @@ CL_InternetServers_f
|
||||||
*/
|
*/
|
||||||
void CL_InternetServers_f( void )
|
void CL_InternetServers_f( void )
|
||||||
{
|
{
|
||||||
char fullquery[512] = MS_SCAN_REQUEST;
|
char fullquery[512];
|
||||||
char *info = fullquery + sizeof( MS_SCAN_REQUEST ) - 1;
|
size_t len;
|
||||||
const size_t remaining = sizeof( fullquery ) - sizeof( MS_SCAN_REQUEST );
|
qboolean nat = cl_nat->value != 0.0f;
|
||||||
|
|
||||||
|
len = CL_BuildMasterServerScanRequest( fullquery, sizeof( fullquery ), nat );
|
||||||
|
|
||||||
|
Con_Printf( "Scanning for servers on the internet area...\n" );
|
||||||
|
|
||||||
NET_Config( true, true ); // allow remote
|
NET_Config( true, true ); // allow remote
|
||||||
|
|
||||||
Con_Printf( "Scanning for servers on the internet area...\n" );
|
cls.internetservers_wait = NET_SendToMasters( NS_CLIENT, len, fullquery );
|
||||||
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 );
|
|
||||||
|
|
||||||
cls.internetservers_wait = NET_SendToMasters( NS_CLIENT, sizeof( MS_SCAN_REQUEST ) + Q_strlen( info ), fullquery );
|
|
||||||
cls.internetservers_pending = true;
|
cls.internetservers_pending = true;
|
||||||
|
|
||||||
if( !cls.internetservers_wait )
|
if( !cls.internetservers_wait )
|
||||||
|
@ -1625,6 +1652,8 @@ void CL_Reconnect_f( void )
|
||||||
|
|
||||||
if( COM_CheckString( cls.servername ))
|
if( COM_CheckString( cls.servername ))
|
||||||
{
|
{
|
||||||
|
qboolean legacy = cls.legacymode;
|
||||||
|
|
||||||
if( cls.state >= ca_connected )
|
if( cls.state >= ca_connected )
|
||||||
CL_Disconnect();
|
CL_Disconnect();
|
||||||
|
|
||||||
|
@ -1632,6 +1661,7 @@ void CL_Reconnect_f( void )
|
||||||
cls.demonum = cls.movienum = -1; // not in the demo loop now
|
cls.demonum = cls.movienum = -1; // not in the demo loop now
|
||||||
cls.state = ca_connecting;
|
cls.state = ca_connecting;
|
||||||
cls.signon = 0;
|
cls.signon = 0;
|
||||||
|
cls.legacymode = legacy; // don't change protocol
|
||||||
|
|
||||||
Con_Printf( "reconnecting...\n" );
|
Con_Printf( "reconnecting...\n" );
|
||||||
}
|
}
|
||||||
|
@ -1713,16 +1743,23 @@ void CL_ParseStatusMessage( netadr_t from, sizebuf_t *msg )
|
||||||
static char infostring[MAX_INFO_STRING+8];
|
static char infostring[MAX_INFO_STRING+8];
|
||||||
char *s = MSG_ReadString( msg );
|
char *s = MSG_ReadString( msg );
|
||||||
int i;
|
int i;
|
||||||
|
const char *magic = ": wrong version\n";
|
||||||
|
size_t len = Q_strlen( s ), magiclen = Q_strlen( magic );
|
||||||
|
|
||||||
CL_FixupColorStringsForInfoString( s, infostring );
|
if( len >= magiclen && !Q_strcmp( s + len - magiclen, magic ))
|
||||||
|
|
||||||
if( Q_strstr( infostring, "wrong version" ) )
|
|
||||||
{
|
{
|
||||||
Netchan_OutOfBandPrint( NS_CLIENT, from, "info %i", PROTOCOL_LEGACY_VERSION );
|
Netchan_OutOfBandPrint( NS_CLIENT, from, "info %i", PROTOCOL_LEGACY_VERSION );
|
||||||
Con_Printf( "^1Server^7: %s, Info: %s\n", NET_AdrToString( from ), infostring );
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( !Info_IsValid( s ))
|
||||||
|
{
|
||||||
|
Con_Printf( "^1Server^7: %s, invalid infostring\n", NET_AdrToString( from ));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CL_FixupColorStringsForInfoString( s, infostring );
|
||||||
|
|
||||||
if( !COM_CheckString( Info_ValueForKey( infostring, "gamedir" )))
|
if( !COM_CheckString( Info_ValueForKey( infostring, "gamedir" )))
|
||||||
{
|
{
|
||||||
Con_Printf( "^1Server^7: %s, Info: %s\n", NET_AdrToString( from ), infostring );
|
Con_Printf( "^1Server^7: %s, Info: %s\n", NET_AdrToString( from ), infostring );
|
||||||
|
@ -1732,11 +1769,13 @@ void CL_ParseStatusMessage( netadr_t from, sizebuf_t *msg )
|
||||||
if( !COM_CheckString( Info_ValueForKey( infostring, "p" )))
|
if( !COM_CheckString( Info_ValueForKey( infostring, "p" )))
|
||||||
{
|
{
|
||||||
Info_SetValueForKey( infostring, "legacy", "1", sizeof( infostring ) );
|
Info_SetValueForKey( infostring, "legacy", "1", sizeof( infostring ) );
|
||||||
Con_Print("Legacy: ");
|
Con_Printf( "^3Server^7: %s, Game: %s\n", NET_AdrToString( from ), Info_ValueForKey( infostring, "gamedir" ));
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// more info about servers
|
// more info about servers
|
||||||
Con_Printf( "^2Server^7: %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 );
|
UI_AddServerToList( from, infostring );
|
||||||
}
|
}
|
||||||
|
@ -2095,6 +2134,12 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
|
||||||
}
|
}
|
||||||
else if( !Q_strcmp( c, "f" ))
|
else if( !Q_strcmp( c, "f" ))
|
||||||
{
|
{
|
||||||
|
if( !NET_IsMasterAdr( from ))
|
||||||
|
{
|
||||||
|
Con_Printf( S_WARN "unexpected server list packet from %s\n", NET_AdrToString( from ));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// serverlist got from masterserver
|
// serverlist got from masterserver
|
||||||
while( MSG_GetNumBitsLeft( msg ) > 8 )
|
while( MSG_GetNumBitsLeft( msg ) > 8 )
|
||||||
{
|
{
|
||||||
|
@ -2405,11 +2450,18 @@ void CL_ProcessFile( qboolean successfully_received, const char *filename )
|
||||||
{
|
{
|
||||||
if( filename[0] != '!' )
|
if( filename[0] != '!' )
|
||||||
Con_Printf( "processing %s\n", filename );
|
Con_Printf( "processing %s\n", filename );
|
||||||
|
|
||||||
|
if( !Q_strnicmp( filename, "downloaded/", 11 ))
|
||||||
|
{
|
||||||
|
// skip "downloaded/" part to avoid mismatch with needed resources list
|
||||||
|
filename += 11;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if( !successfully_received )
|
else if( !successfully_received )
|
||||||
{
|
{
|
||||||
Con_Printf( S_ERROR "server failed to transmit file '%s'\n", CL_CleanFileName( filename ));
|
Con_Printf( S_ERROR "server failed to transmit file '%s'\n", CL_CleanFileName( filename ));
|
||||||
}
|
}
|
||||||
|
|
||||||
if( cls.legacymode )
|
if( cls.legacymode )
|
||||||
{
|
{
|
||||||
if( host.downloadcount > 0 )
|
if( host.downloadcount > 0 )
|
||||||
|
@ -2806,8 +2858,11 @@ void CL_InitLocal( void )
|
||||||
Cvar_RegisterVariable( &cl_download_ingame );
|
Cvar_RegisterVariable( &cl_download_ingame );
|
||||||
Cvar_RegisterVariable( &cl_logofile );
|
Cvar_RegisterVariable( &cl_logofile );
|
||||||
Cvar_RegisterVariable( &cl_logocolor );
|
Cvar_RegisterVariable( &cl_logocolor );
|
||||||
|
Cvar_RegisterVariable( &cl_logoext );
|
||||||
Cvar_RegisterVariable( &cl_test_bandwidth );
|
Cvar_RegisterVariable( &cl_test_bandwidth );
|
||||||
|
|
||||||
|
Voice_RegisterCvars();
|
||||||
|
|
||||||
// register our variables
|
// register our variables
|
||||||
cl_crosshair = Cvar_Get( "crosshair", "1", FCVAR_ARCHIVE, "show weapon chrosshair" );
|
cl_crosshair = Cvar_Get( "crosshair", "1", FCVAR_ARCHIVE, "show weapon chrosshair" );
|
||||||
cl_nodelta = Cvar_Get ("cl_nodelta", "0", 0, "disable delta-compression for server messages" );
|
cl_nodelta = Cvar_Get ("cl_nodelta", "0", 0, "disable delta-compression for server messages" );
|
||||||
|
@ -2818,7 +2873,6 @@ void CL_InitLocal( void )
|
||||||
cl_charset = Cvar_Get( "cl_charset", "utf-8", FCVAR_ARCHIVE, "1-byte charset to use (iconv style)" );
|
cl_charset = Cvar_Get( "cl_charset", "utf-8", FCVAR_ARCHIVE, "1-byte charset to use (iconv style)" );
|
||||||
hud_utf8 = Cvar_Get( "hud_utf8", "0", FCVAR_ARCHIVE, "Use utf-8 encoding for hud text" );
|
hud_utf8 = Cvar_Get( "hud_utf8", "0", FCVAR_ARCHIVE, "Use utf-8 encoding for hud text" );
|
||||||
|
|
||||||
rcon_client_password = Cvar_Get( "rcon_password", "", FCVAR_PRIVILEGED, "remote control client password" );
|
|
||||||
rcon_address = Cvar_Get( "rcon_address", "", FCVAR_PRIVILEGED, "remote control address" );
|
rcon_address = Cvar_Get( "rcon_address", "", FCVAR_PRIVILEGED, "remote control address" );
|
||||||
|
|
||||||
cl_trace_messages = Cvar_Get( "cl_trace_messages", "0", FCVAR_ARCHIVE|FCVAR_CHEAT, "enable message names tracing (good for developers)");
|
cl_trace_messages = Cvar_Get( "cl_trace_messages", "0", FCVAR_ARCHIVE|FCVAR_CHEAT, "enable message names tracing (good for developers)");
|
||||||
|
@ -2842,9 +2896,9 @@ void CL_InitLocal( void )
|
||||||
|
|
||||||
cl_nosmooth = Cvar_Get( "cl_nosmooth", "0", FCVAR_ARCHIVE, "disable smooth up stair climbing" );
|
cl_nosmooth = Cvar_Get( "cl_nosmooth", "0", FCVAR_ARCHIVE, "disable smooth up stair climbing" );
|
||||||
cl_nointerp = Cvar_Get( "cl_nointerp", "0", FCVAR_CLIENTDLL, "disable interpolation of entities and players" );
|
cl_nointerp = Cvar_Get( "cl_nointerp", "0", FCVAR_CLIENTDLL, "disable interpolation of entities and players" );
|
||||||
cl_smoothtime = Cvar_Get( "cl_smoothtime", "0", FCVAR_ARCHIVE, "time to smooth up" );
|
cl_smoothtime = Cvar_Get( "cl_smoothtime", "0.1", FCVAR_ARCHIVE, "time to smooth up" );
|
||||||
cl_cmdbackup = Cvar_Get( "cl_cmdbackup", "10", FCVAR_ARCHIVE, "how many additional history commands are sent" );
|
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_cmdrate = Cvar_Get( "cl_cmdrate", "60", FCVAR_ARCHIVE, "Max number of command packets sent to server per second" );
|
||||||
cl_draw_particles = Cvar_Get( "r_drawparticles", "1", FCVAR_CHEAT, "render particles" );
|
cl_draw_particles = Cvar_Get( "r_drawparticles", "1", FCVAR_CHEAT, "render particles" );
|
||||||
cl_draw_tracers = Cvar_Get( "r_drawtracers", "1", FCVAR_CHEAT, "render tracers" );
|
cl_draw_tracers = Cvar_Get( "r_drawtracers", "1", FCVAR_CHEAT, "render tracers" );
|
||||||
cl_draw_beams = Cvar_Get( "r_drawbeams", "1", FCVAR_CHEAT, "render beams" );
|
cl_draw_beams = Cvar_Get( "r_drawbeams", "1", FCVAR_CHEAT, "render beams" );
|
||||||
|
@ -2853,6 +2907,7 @@ void CL_InitLocal( void )
|
||||||
cl_bmodelinterp = Cvar_Get( "cl_bmodelinterp", "1", FCVAR_ARCHIVE, "enable bmodel interpolation" );
|
cl_bmodelinterp = Cvar_Get( "cl_bmodelinterp", "1", FCVAR_ARCHIVE, "enable bmodel interpolation" );
|
||||||
cl_clockreset = Cvar_Get( "cl_clockreset", "0.1", FCVAR_ARCHIVE, "frametime delta maximum value before reset" );
|
cl_clockreset = Cvar_Get( "cl_clockreset", "0.1", FCVAR_ARCHIVE, "frametime delta maximum value before reset" );
|
||||||
cl_fixtimerate = Cvar_Get( "cl_fixtimerate", "7.5", FCVAR_ARCHIVE, "time in msec to client clock adjusting" );
|
cl_fixtimerate = Cvar_Get( "cl_fixtimerate", "7.5", FCVAR_ARCHIVE, "time in msec to client clock adjusting" );
|
||||||
|
hud_fontscale = Cvar_Get( "hud_fontscale", "1.0", FCVAR_ARCHIVE|FCVAR_LATCH, "scale hud font texture" );
|
||||||
hud_scale = Cvar_Get( "hud_scale", "0", FCVAR_ARCHIVE|FCVAR_LATCH, "scale hud at current resolution" );
|
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" );
|
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" );
|
cl_showevents = Cvar_Get( "cl_showevents", "0", FCVAR_ARCHIVE, "show events playback" );
|
||||||
|
@ -2874,6 +2929,12 @@ void CL_InitLocal( void )
|
||||||
Cmd_AddCommand ("god", NULL, "enable godmode" );
|
Cmd_AddCommand ("god", NULL, "enable godmode" );
|
||||||
Cmd_AddCommand ("fov", NULL, "set client field of view" );
|
Cmd_AddCommand ("fov", NULL, "set client field of view" );
|
||||||
|
|
||||||
|
Cmd_AddRestrictedCommand ("ent_list", NULL, "list entities on server" );
|
||||||
|
Cmd_AddRestrictedCommand ("ent_fire", NULL, "fire entity command (be careful)" );
|
||||||
|
Cmd_AddRestrictedCommand ("ent_info", NULL, "dump entity information" );
|
||||||
|
Cmd_AddRestrictedCommand ("ent_create", NULL, "create entity with specified values (be careful)" );
|
||||||
|
Cmd_AddRestrictedCommand ("ent_getvars", NULL, "put parameters of specified entities to client's' ent_last_* cvars" );
|
||||||
|
|
||||||
// register our commands
|
// register our commands
|
||||||
Cmd_AddCommand ("pause", NULL, "pause the game (if the server allows pausing)" );
|
Cmd_AddCommand ("pause", NULL, "pause the game (if the server allows pausing)" );
|
||||||
Cmd_AddCommand ("localservers", CL_LocalServers_f, "collect info about local servers" );
|
Cmd_AddCommand ("localservers", CL_LocalServers_f, "collect info about local servers" );
|
||||||
|
@ -2940,12 +3001,12 @@ void CL_AdjustClock( void )
|
||||||
if( fabs( cl.timedelta ) >= 0.001f )
|
if( fabs( cl.timedelta ) >= 0.001f )
|
||||||
{
|
{
|
||||||
double msec, adjust;
|
double msec, adjust;
|
||||||
float sign;
|
double sign;
|
||||||
|
|
||||||
msec = ( cl.timedelta * 1000.0f );
|
msec = ( cl.timedelta * 1000.0 );
|
||||||
sign = ( msec < 0 ) ? 1.0f : -1.0f;
|
sign = ( msec < 0 ) ? 1.0 : -1.0;
|
||||||
msec = fabs( msec );
|
msec = Q_min( cl_fixtimerate->value, fabs( msec ));
|
||||||
adjust = sign * ( cl_fixtimerate->value / 1000.0f );
|
adjust = sign * ( msec / 1000.0 );
|
||||||
|
|
||||||
if( fabs( adjust ) < fabs( cl.timedelta ))
|
if( fabs( adjust ) < fabs( cl.timedelta ))
|
||||||
{
|
{
|
||||||
|
@ -3009,8 +3070,8 @@ void Host_ClientFrame( void )
|
||||||
// a new portion updates from server
|
// a new portion updates from server
|
||||||
CL_RedoPrediction ();
|
CL_RedoPrediction ();
|
||||||
|
|
||||||
// TODO: implement
|
// update voice
|
||||||
// Voice_Idle( host.frametime );
|
Voice_Idle( host.frametime );
|
||||||
|
|
||||||
// emit visible entities
|
// emit visible entities
|
||||||
CL_EmitEntities ();
|
CL_EmitEntities ();
|
||||||
|
@ -3030,9 +3091,6 @@ void Host_ClientFrame( void )
|
||||||
// catch changes video settings
|
// catch changes video settings
|
||||||
VID_CheckChanges();
|
VID_CheckChanges();
|
||||||
|
|
||||||
// process VGUI
|
|
||||||
VGui_RunFrame ();
|
|
||||||
|
|
||||||
// update the screen
|
// update the screen
|
||||||
SCR_UpdateScreen ();
|
SCR_UpdateScreen ();
|
||||||
|
|
||||||
|
@ -3064,6 +3122,7 @@ void CL_Init( void )
|
||||||
|
|
||||||
VID_Init(); // init video
|
VID_Init(); // init video
|
||||||
S_Init(); // init sound
|
S_Init(); // init sound
|
||||||
|
Voice_Init( VOICE_DEFAULT_CODEC, 3 ); // init voice
|
||||||
|
|
||||||
// unreliable buffer. unsed for unreliable commands and voice stream
|
// unreliable buffer. unsed for unreliable commands and voice stream
|
||||||
MSG_Init( &cls.datagram, "cls.datagram", cls.datagram_buf, sizeof( cls.datagram_buf ));
|
MSG_Init( &cls.datagram, "cls.datagram", cls.datagram_buf, sizeof( cls.datagram_buf ));
|
||||||
|
@ -3107,6 +3166,8 @@ void CL_Shutdown( void )
|
||||||
CL_UnloadProgs ();
|
CL_UnloadProgs ();
|
||||||
cls.initialized = false;
|
cls.initialized = false;
|
||||||
|
|
||||||
|
// for client-side VGUI support we use other order
|
||||||
|
if( !GI->internal_vgui_support )
|
||||||
VGui_Shutdown();
|
VGui_Shutdown();
|
||||||
|
|
||||||
FS_Delete( "demoheader.tmp" ); // remove tmp file
|
FS_Delete( "demoheader.tmp" ); // remove tmp file
|
||||||
|
|
|
@ -25,6 +25,9 @@ mobile_engfuncs_t *gMobileEngfuncs;
|
||||||
convar_t *vibration_length;
|
convar_t *vibration_length;
|
||||||
convar_t *vibration_enable;
|
convar_t *vibration_enable;
|
||||||
|
|
||||||
|
static cl_font_t g_scaled_font;
|
||||||
|
static float g_font_scale;
|
||||||
|
|
||||||
static void pfnVibrate( float life, char flags )
|
static void pfnVibrate( float life, char flags )
|
||||||
{
|
{
|
||||||
if( !vibration_enable->value )
|
if( !vibration_enable->value )
|
||||||
|
@ -60,28 +63,28 @@ static void pfnEnableTextInput( int enable )
|
||||||
|
|
||||||
static int pfnDrawScaledCharacter( int x, int y, int number, int r, int g, int b, float scale )
|
static int pfnDrawScaledCharacter( int x, int y, int number, int r, int g, int b, float scale )
|
||||||
{
|
{
|
||||||
int width = clgame.scrInfo.charWidths[number] * scale * hud_scale->value;
|
// this call is very ineffective and possibly broken!
|
||||||
int height = clgame.scrInfo.iCharHeight * scale * hud_scale->value;
|
rgba_t color = { r, g, b, 255 };
|
||||||
|
int flags = FONT_DRAW_HUD;
|
||||||
|
|
||||||
if( !cls.creditsFont.valid )
|
if( hud_utf8->value )
|
||||||
return 0;
|
SetBits( flags, FONT_DRAW_UTF8 );
|
||||||
|
|
||||||
x *= hud_scale->value;
|
if( fabs( g_font_scale - scale ) > 0.1f ||
|
||||||
y *= hud_scale->value;
|
g_scaled_font.hFontTexture != cls.creditsFont.hFontTexture )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
number &= 255;
|
g_scaled_font = cls.creditsFont;
|
||||||
number = Con_UtfProcessChar( number );
|
g_scaled_font.scale *= scale;
|
||||||
|
g_scaled_font.charHeight *= scale;
|
||||||
|
for( i = 0; i < ARRAYSIZE( g_scaled_font.charWidths ); i++ )
|
||||||
|
g_scaled_font.charWidths[i] *= scale;
|
||||||
|
|
||||||
if( number < 32 )
|
g_font_scale = scale;
|
||||||
return 0;
|
}
|
||||||
|
|
||||||
if( y < -height )
|
return CL_DrawCharacter( x, y, number, color, &g_scaled_font, flags );
|
||||||
return 0;
|
|
||||||
|
|
||||||
pfnPIC_Set( cls.creditsFont.hFontTexture, r, g, b, 255 );
|
|
||||||
pfnPIC_DrawAdditive( x, y, width, height, &cls.creditsFont.fontRc[number] );
|
|
||||||
|
|
||||||
return width;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *pfnGetNativeObject( const char *obj )
|
static void *pfnGetNativeObject( const char *obj )
|
||||||
|
|
|
@ -281,7 +281,10 @@ static void NetGraph_DrawTimes( wrect_t rect, int x, int w )
|
||||||
|
|
||||||
for( j = start; j < h; j++ )
|
for( j = start; j < h; j++ )
|
||||||
{
|
{
|
||||||
NetGraph_DrawRect( &fill, netcolors[NETGRAPH_NET_COLORS + j + extrap_point] );
|
int color = NETGRAPH_NET_COLORS + j + extrap_point;
|
||||||
|
color = Q_min( color, ARRAYSIZE( netcolors ) - 1 );
|
||||||
|
|
||||||
|
NetGraph_DrawRect( &fill, netcolors[color] );
|
||||||
fill.top--;
|
fill.top--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -297,7 +300,10 @@ static void NetGraph_DrawTimes( wrect_t rect, int x, int w )
|
||||||
|
|
||||||
for( j = 0; j < h; j++ )
|
for( j = 0; j < h; j++ )
|
||||||
{
|
{
|
||||||
NetGraph_DrawRect( &fill, netcolors[NETGRAPH_NET_COLORS + j + oldh] );
|
int color = NETGRAPH_NET_COLORS + j + oldh;
|
||||||
|
color = Q_min( color, ARRAYSIZE( netcolors ) - 1 );
|
||||||
|
|
||||||
|
NetGraph_DrawRect( &fill, netcolors[color] );
|
||||||
fill.top--;
|
fill.top--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -358,6 +364,7 @@ NetGraph_DrawTextFields
|
||||||
static void NetGraph_DrawTextFields( int x, int y, int w, wrect_t rect, int count, float avg, int packet_loss, int packet_choke, int graphtype )
|
static void NetGraph_DrawTextFields( int x, int y, int w, wrect_t rect, int count, float avg, int packet_loss, int packet_choke, int graphtype )
|
||||||
{
|
{
|
||||||
static int lastout;
|
static int lastout;
|
||||||
|
cl_font_t *font = Con_GetFont( 0 );
|
||||||
rgba_t colors = { 0.9 * 255, 0.9 * 255, 0.7 * 255, 255 };
|
rgba_t colors = { 0.9 * 255, 0.9 * 255, 0.7 * 255, 255 };
|
||||||
int ptx = Q_max( x + w - NETGRAPH_LERP_HEIGHT - 1, 1 );
|
int ptx = Q_max( x + w - NETGRAPH_LERP_HEIGHT - 1, 1 );
|
||||||
int pty = Q_max( rect.top + rect.bottom - NETGRAPH_LERP_HEIGHT - 3, 1 );
|
int pty = Q_max( rect.top + rect.bottom - NETGRAPH_LERP_HEIGHT - 3, 1 );
|
||||||
|
@ -379,16 +386,17 @@ static void NetGraph_DrawTextFields( int x, int y, int w, wrect_t rect, int coun
|
||||||
|
|
||||||
// move rolling average
|
// move rolling average
|
||||||
framerate = FRAMERATE_AVG_FRAC * host.frametime + ( 1.0f - FRAMERATE_AVG_FRAC ) * framerate;
|
framerate = FRAMERATE_AVG_FRAC * host.frametime + ( 1.0f - FRAMERATE_AVG_FRAC ) * framerate;
|
||||||
Con_SetFont( 0 );
|
|
||||||
|
ref.dllFuncs.GL_SetRenderMode( font->rendermode );
|
||||||
|
|
||||||
if( framerate > 0.0f )
|
if( framerate > 0.0f )
|
||||||
{
|
{
|
||||||
y -= net_graphheight->value;
|
y -= net_graphheight->value;
|
||||||
|
|
||||||
Con_DrawString( x, y, va( "%.1f fps" , 1.0f / framerate ), colors );
|
CL_DrawString( x, y, va( "%.1f fps" , 1.0f / framerate ), colors, font, FONT_DRAW_NORENDERMODE );
|
||||||
|
|
||||||
if( avg > 1.0f )
|
if( avg > 1.0f )
|
||||||
Con_DrawString( x + 75, y, va( "%i ms" , (int)avg ), colors );
|
CL_DrawString( x + 75, y, va( "%i ms" , (int)avg ), colors, font, FONT_DRAW_NORENDERMODE );
|
||||||
|
|
||||||
y += 15;
|
y += 15;
|
||||||
|
|
||||||
|
@ -396,10 +404,10 @@ static void NetGraph_DrawTextFields( int x, int y, int w, wrect_t rect, int coun
|
||||||
if( !out ) out = lastout;
|
if( !out ) out = lastout;
|
||||||
else lastout = out;
|
else lastout = out;
|
||||||
|
|
||||||
Con_DrawString( x, y, va( "in : %i %.2f kb/s", netstat_graph[j].msgbytes, cls.netchan.flow[FLOW_INCOMING].avgkbytespersec ), colors );
|
CL_DrawString( x, y, va( "in : %i %.2f kb/s", netstat_graph[j].msgbytes, cls.netchan.flow[FLOW_INCOMING].avgkbytespersec ), colors, font, FONT_DRAW_NORENDERMODE );
|
||||||
y += 15;
|
y += 15;
|
||||||
|
|
||||||
Con_DrawString( x, y, va( "out: %i %.2f kb/s", out, cls.netchan.flow[FLOW_OUTGOING].avgkbytespersec ), colors );
|
CL_DrawString( x, y, va( "out: %i %.2f kb/s", out, cls.netchan.flow[FLOW_OUTGOING].avgkbytespersec ), colors, font, FONT_DRAW_NORENDERMODE );
|
||||||
y += 15;
|
y += 15;
|
||||||
|
|
||||||
if( graphtype > 2 )
|
if( graphtype > 2 )
|
||||||
|
@ -407,16 +415,14 @@ static void NetGraph_DrawTextFields( int x, int y, int w, wrect_t rect, int coun
|
||||||
int loss = (int)(( packet_loss + PACKETLOSS_AVG_FRAC ) - 0.01f );
|
int loss = (int)(( packet_loss + PACKETLOSS_AVG_FRAC ) - 0.01f );
|
||||||
int choke = (int)(( packet_choke + PACKETCHOKE_AVG_FRAC ) - 0.01f );
|
int choke = (int)(( packet_choke + PACKETCHOKE_AVG_FRAC ) - 0.01f );
|
||||||
|
|
||||||
Con_DrawString( x, y, va( "loss: %i choke: %i", loss, choke ), colors );
|
CL_DrawString( x, y, va( "loss: %i choke: %i", loss, choke ), colors, font, FONT_DRAW_NORENDERMODE );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( graphtype < 3 )
|
if( graphtype < 3 )
|
||||||
Con_DrawString( ptx, pty, va( "%i/s", (int)cl_cmdrate->value ), colors );
|
CL_DrawString( ptx, pty, va( "%i/s", (int)cl_cmdrate->value ), colors, font, FONT_DRAW_NORENDERMODE );
|
||||||
|
|
||||||
Con_DrawString( ptx, last_y, va( "%i/s" , (int)cl_updaterate->value ), colors );
|
CL_DrawString( ptx, last_y, va( "%i/s" , (int)cl_updaterate->value ), colors, font, FONT_DRAW_NORENDERMODE );
|
||||||
|
|
||||||
Con_RestoreFont();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -843,54 +843,74 @@ void CL_ParseFileTransferFailed( sizebuf_t *msg )
|
||||||
CL_ParseServerData
|
CL_ParseServerData
|
||||||
==================
|
==================
|
||||||
*/
|
*/
|
||||||
void CL_ParseServerData( sizebuf_t *msg )
|
void CL_ParseServerData( sizebuf_t *msg, qboolean legacy )
|
||||||
{
|
{
|
||||||
char gamefolder[MAX_QPATH];
|
char gamefolder[MAX_QPATH];
|
||||||
qboolean background;
|
qboolean background;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
Con_Reportf( "Serverdata packet received.\n" );
|
Con_Reportf( "%s packet received.\n", legacy ? "Legacy serverdata" : "Serverdata" );
|
||||||
cls.timestart = Sys_DoubleTime();
|
|
||||||
|
|
||||||
|
cls.timestart = Sys_DoubleTime();
|
||||||
cls.demowaiting = false; // server is changed
|
cls.demowaiting = false; // server is changed
|
||||||
|
|
||||||
// wipe the client_t struct
|
// wipe the client_t struct
|
||||||
if( !cls.changelevel && !cls.changedemo )
|
if( !cls.changelevel && !cls.changedemo )
|
||||||
CL_ClearState ();
|
CL_ClearState ();
|
||||||
|
|
||||||
|
// Re-init hud video, especially if we changed game directories
|
||||||
|
clgame.dllFuncs.pfnVidInit();
|
||||||
|
|
||||||
cls.state = ca_connected;
|
cls.state = ca_connected;
|
||||||
|
|
||||||
// parse protocol version number
|
// parse protocol version number
|
||||||
i = MSG_ReadLong( msg );
|
i = MSG_ReadLong( msg );
|
||||||
|
|
||||||
|
if( legacy )
|
||||||
|
{
|
||||||
|
if( i != PROTOCOL_LEGACY_VERSION )
|
||||||
|
Host_Error( "Server use invalid protocol (%i should be %i)\n", i, PROTOCOL_LEGACY_VERSION );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if( i != PROTOCOL_VERSION )
|
if( i != PROTOCOL_VERSION )
|
||||||
Host_Error( "Server use invalid protocol (%i should be %i)\n", i, PROTOCOL_VERSION );
|
Host_Error( "Server use invalid protocol (%i should be %i)\n", i, PROTOCOL_VERSION );
|
||||||
|
}
|
||||||
|
|
||||||
cl.servercount = MSG_ReadLong( msg );
|
cl.servercount = MSG_ReadLong( msg );
|
||||||
cl.checksum = MSG_ReadLong( msg );
|
cl.checksum = MSG_ReadLong( msg );
|
||||||
cl.playernum = MSG_ReadByte( msg );
|
cl.playernum = MSG_ReadByte( msg );
|
||||||
cl.maxclients = MSG_ReadByte( msg );
|
cl.maxclients = MSG_ReadByte( msg );
|
||||||
clgame.maxEntities = MSG_ReadWord( msg );
|
clgame.maxEntities = MSG_ReadWord( msg );
|
||||||
|
if( legacy )
|
||||||
|
{
|
||||||
|
clgame.maxEntities = bound( MIN_LEGACY_EDICTS, clgame.maxEntities, MAX_LEGACY_EDICTS );
|
||||||
|
clgame.maxModels = 512; // ???
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
clgame.maxEntities = bound( MIN_EDICTS, clgame.maxEntities, MAX_EDICTS );
|
clgame.maxEntities = bound( MIN_EDICTS, clgame.maxEntities, MAX_EDICTS );
|
||||||
clgame.maxModels = MSG_ReadWord( msg );
|
clgame.maxModels = MSG_ReadWord( msg );
|
||||||
Q_strncpy( clgame.mapname, MSG_ReadString( msg ), MAX_STRING );
|
}
|
||||||
Q_strncpy( clgame.maptitle, MSG_ReadString( msg ), MAX_STRING );
|
Q_strncpy( clgame.mapname, MSG_ReadString( msg ), sizeof( clgame.mapname ));
|
||||||
|
Q_strncpy( clgame.maptitle, MSG_ReadString( msg ), sizeof( clgame.maptitle ));
|
||||||
background = MSG_ReadOneBit( msg );
|
background = MSG_ReadOneBit( msg );
|
||||||
Q_strncpy( gamefolder, MSG_ReadString( msg ), MAX_QPATH );
|
Q_strncpy( gamefolder, MSG_ReadString( msg ), sizeof( gamefolder ));
|
||||||
host.features = (uint)MSG_ReadLong( msg );
|
host.features = (uint)MSG_ReadLong( msg );
|
||||||
|
|
||||||
|
if( !legacy )
|
||||||
|
{
|
||||||
// receive the player hulls
|
// receive the player hulls
|
||||||
for( i = 0; i < MAX_MAP_HULLS * 3; i++ )
|
for( i = 0; i < MAX_MAP_HULLS * 3; i++ )
|
||||||
{
|
{
|
||||||
host.player_mins[i/3][i%3] = MSG_ReadChar( msg );
|
host.player_mins[i/3][i%3] = MSG_ReadChar( msg );
|
||||||
host.player_maxs[i/3][i%3] = MSG_ReadChar( msg );
|
host.player_maxs[i/3][i%3] = MSG_ReadChar( msg );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if( clgame.maxModels > MAX_MODELS )
|
if( clgame.maxModels > MAX_MODELS )
|
||||||
Con_Printf( S_WARN "server model limit is above client model limit %i > %i\n", clgame.maxModels, MAX_MODELS );
|
Con_Printf( S_WARN "server model limit is above client model limit %i > %i\n", clgame.maxModels, MAX_MODELS );
|
||||||
|
|
||||||
// Re-init hud video, especially if we changed game directories
|
|
||||||
clgame.dllFuncs.pfnVidInit();
|
|
||||||
|
|
||||||
if( Con_FixedFont( ))
|
if( Con_FixedFont( ))
|
||||||
{
|
{
|
||||||
// seperate the printfs so the server message can have a color
|
// seperate the printfs so the server message can have a color
|
||||||
|
@ -914,11 +934,7 @@ void CL_ParseServerData( sizebuf_t *msg )
|
||||||
|
|
||||||
// set the background state
|
// set the background state
|
||||||
if( cls.demoplayback && ( cls.demonum != -1 ))
|
if( cls.demoplayback && ( cls.demonum != -1 ))
|
||||||
{
|
|
||||||
// re-init mouse
|
|
||||||
host.mouse_visible = false;
|
|
||||||
cl.background = true;
|
cl.background = true;
|
||||||
}
|
|
||||||
else cl.background = background;
|
else cl.background = background;
|
||||||
|
|
||||||
if( cl.background ) // tell the game parts about background state
|
if( cl.background ) // tell the game parts about background state
|
||||||
|
@ -965,8 +981,11 @@ void CL_ParseServerData( sizebuf_t *msg )
|
||||||
COM_ClearCustomizationList( &cl.players[i].customdata, true );
|
COM_ClearCustomizationList( &cl.players[i].customdata, true );
|
||||||
CL_CreateCustomizationList();
|
CL_CreateCustomizationList();
|
||||||
|
|
||||||
|
if( !legacy )
|
||||||
|
{
|
||||||
// request resources from server
|
// request resources from server
|
||||||
CL_ServerCommand( true, "sendres %i\n", cl.servercount );
|
CL_ServerCommand( true, "sendres %i\n", cl.servercount );
|
||||||
|
}
|
||||||
|
|
||||||
memset( &clgame.movevars, 0, sizeof( clgame.movevars ));
|
memset( &clgame.movevars, 0, sizeof( clgame.movevars ));
|
||||||
memset( &clgame.oldmovevars, 0, sizeof( clgame.oldmovevars ));
|
memset( &clgame.oldmovevars, 0, sizeof( clgame.oldmovevars ));
|
||||||
|
@ -1141,7 +1160,7 @@ void CL_ParseClientData( sizebuf_t *msg )
|
||||||
CL_ParseBaseline
|
CL_ParseBaseline
|
||||||
==================
|
==================
|
||||||
*/
|
*/
|
||||||
void CL_ParseBaseline( sizebuf_t *msg )
|
void CL_ParseBaseline( sizebuf_t *msg, qboolean legacy )
|
||||||
{
|
{
|
||||||
int i, newnum;
|
int i, newnum;
|
||||||
entity_state_t nullstate;
|
entity_state_t nullstate;
|
||||||
|
@ -1153,9 +1172,16 @@ void CL_ParseBaseline( sizebuf_t *msg )
|
||||||
memset( &nullstate, 0, sizeof( nullstate ));
|
memset( &nullstate, 0, sizeof( nullstate ));
|
||||||
|
|
||||||
while( 1 )
|
while( 1 )
|
||||||
|
{
|
||||||
|
if( legacy )
|
||||||
|
{
|
||||||
|
newnum = MSG_ReadWord( msg );
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
newnum = MSG_ReadUBitLong( msg, MAX_ENTITY_BITS );
|
newnum = MSG_ReadUBitLong( msg, MAX_ENTITY_BITS );
|
||||||
if( newnum == LAST_EDICT ) break; // end of baselines
|
if( newnum == LAST_EDICT ) break; // end of baselines
|
||||||
|
}
|
||||||
player = CL_IsPlayerIndex( newnum );
|
player = CL_IsPlayerIndex( newnum );
|
||||||
|
|
||||||
if( newnum >= clgame.maxEntities )
|
if( newnum >= clgame.maxEntities )
|
||||||
|
@ -1166,8 +1192,15 @@ void CL_ParseBaseline( sizebuf_t *msg )
|
||||||
ent->index = newnum;
|
ent->index = newnum;
|
||||||
|
|
||||||
MSG_ReadDeltaEntity( msg, &ent->prevstate, &ent->baseline, newnum, player, 1.0f );
|
MSG_ReadDeltaEntity( msg, &ent->prevstate, &ent->baseline, newnum, player, 1.0f );
|
||||||
|
|
||||||
|
if( legacy )
|
||||||
|
{
|
||||||
|
break; // only one baseline allowed in legacy protocol
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( !legacy )
|
||||||
|
{
|
||||||
cl.instanced_baseline_count = MSG_ReadUBitLong( msg, 6 );
|
cl.instanced_baseline_count = MSG_ReadUBitLong( msg, 6 );
|
||||||
|
|
||||||
for( i = 0; i < cl.instanced_baseline_count; i++ )
|
for( i = 0; i < cl.instanced_baseline_count; i++ )
|
||||||
|
@ -1175,6 +1208,7 @@ void CL_ParseBaseline( sizebuf_t *msg )
|
||||||
newnum = MSG_ReadUBitLong( msg, MAX_ENTITY_BITS );
|
newnum = MSG_ReadUBitLong( msg, MAX_ENTITY_BITS );
|
||||||
MSG_ReadDeltaEntity( msg, &nullstate, &cl.instanced_baseline[i], newnum, false, 1.0f );
|
MSG_ReadDeltaEntity( msg, &nullstate, &cl.instanced_baseline[i], newnum, false, 1.0f );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1321,7 +1355,7 @@ CL_UpdateUserinfo
|
||||||
collect userinfo from all players
|
collect userinfo from all players
|
||||||
================
|
================
|
||||||
*/
|
*/
|
||||||
void CL_UpdateUserinfo( sizebuf_t *msg )
|
void CL_UpdateUserinfo( sizebuf_t *msg, qboolean legacy )
|
||||||
{
|
{
|
||||||
int slot, id;
|
int slot, id;
|
||||||
qboolean active;
|
qboolean active;
|
||||||
|
@ -1332,6 +1366,7 @@ void CL_UpdateUserinfo( sizebuf_t *msg )
|
||||||
if( slot >= MAX_CLIENTS )
|
if( slot >= MAX_CLIENTS )
|
||||||
Host_Error( "CL_ParseServerMessage: svc_updateuserinfo >= MAX_CLIENTS\n" );
|
Host_Error( "CL_ParseServerMessage: svc_updateuserinfo >= MAX_CLIENTS\n" );
|
||||||
|
|
||||||
|
if( !legacy )
|
||||||
id = MSG_ReadLong( msg ); // unique user ID
|
id = MSG_ReadLong( msg ); // unique user ID
|
||||||
player = &cl.players[slot];
|
player = &cl.players[slot];
|
||||||
active = MSG_ReadOneBit( msg ) ? true : false;
|
active = MSG_ReadOneBit( msg ) ? true : false;
|
||||||
|
@ -1344,11 +1379,17 @@ void CL_UpdateUserinfo( sizebuf_t *msg )
|
||||||
player->topcolor = Q_atoi( Info_ValueForKey( player->userinfo, "topcolor" ));
|
player->topcolor = Q_atoi( Info_ValueForKey( player->userinfo, "topcolor" ));
|
||||||
player->bottomcolor = Q_atoi( Info_ValueForKey( player->userinfo, "bottomcolor" ));
|
player->bottomcolor = Q_atoi( Info_ValueForKey( player->userinfo, "bottomcolor" ));
|
||||||
player->spectator = Q_atoi( Info_ValueForKey( player->userinfo, "*hltv" ));
|
player->spectator = Q_atoi( Info_ValueForKey( player->userinfo, "*hltv" ));
|
||||||
|
if( !legacy )
|
||||||
MSG_ReadBytes( msg, player->hashedcdkey, sizeof( player->hashedcdkey ));
|
MSG_ReadBytes( msg, player->hashedcdkey, sizeof( player->hashedcdkey ));
|
||||||
|
|
||||||
if( slot == cl.playernum ) memcpy( &gameui.playerinfo, player, sizeof( player_info_t ));
|
if( slot == cl.playernum ) memcpy( &gameui.playerinfo, player, sizeof( player_info_t ));
|
||||||
}
|
}
|
||||||
else memset( player, 0, sizeof( *player ));
|
else
|
||||||
|
{
|
||||||
|
COM_ClearCustomizationList( &player->customdata, true );
|
||||||
|
|
||||||
|
memset( player, 0, sizeof( *player ));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1680,7 +1721,10 @@ CL_ParseVoiceInit
|
||||||
*/
|
*/
|
||||||
void CL_ParseVoiceInit( sizebuf_t *msg )
|
void CL_ParseVoiceInit( sizebuf_t *msg )
|
||||||
{
|
{
|
||||||
// TODO: ???
|
char *pszCodec = MSG_ReadString( msg );
|
||||||
|
int quality = MSG_ReadByte( msg );
|
||||||
|
|
||||||
|
Voice_Init( pszCodec, quality );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1691,7 +1735,31 @@ CL_ParseVoiceData
|
||||||
*/
|
*/
|
||||||
void CL_ParseVoiceData( sizebuf_t *msg )
|
void CL_ParseVoiceData( sizebuf_t *msg )
|
||||||
{
|
{
|
||||||
// TODO: ???
|
int size, idx, frames;
|
||||||
|
byte received[8192];
|
||||||
|
|
||||||
|
idx = MSG_ReadByte( msg ) + 1;
|
||||||
|
|
||||||
|
frames = MSG_ReadByte( msg );
|
||||||
|
|
||||||
|
size = MSG_ReadShort( msg );
|
||||||
|
size = Q_min( size, sizeof( received ));
|
||||||
|
|
||||||
|
MSG_ReadBytes( msg, received, size );
|
||||||
|
|
||||||
|
if ( idx <= 0 || idx > cl.maxclients )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// must notify through as both local player and normal client
|
||||||
|
if( idx == cl.playernum + 1 )
|
||||||
|
Voice_StatusAck( &voice.local, VOICE_LOOPBACK_INDEX );
|
||||||
|
|
||||||
|
Voice_StatusAck( &voice.players_status[idx], idx );
|
||||||
|
|
||||||
|
if ( !size )
|
||||||
|
return;
|
||||||
|
|
||||||
|
Voice_AddIncomingData( idx, received, size, frames );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1807,7 +1875,7 @@ void CL_ParseScreenFade( sizebuf_t *msg )
|
||||||
duration = (float)MSG_ReadWord( msg );
|
duration = (float)MSG_ReadWord( msg );
|
||||||
holdTime = (float)MSG_ReadWord( msg );
|
holdTime = (float)MSG_ReadWord( msg );
|
||||||
sf->fadeFlags = MSG_ReadShort( msg );
|
sf->fadeFlags = MSG_ReadShort( msg );
|
||||||
flScale = ( sf->fadeFlags & FFADE_LONGFADE ) ? (1.0f / 256.0f) : (1.0f / 4096.0f);
|
flScale = FBitSet( sf->fadeFlags, FFADE_LONGFADE ) ? (1.0f / 256.0f) : (1.0f / 4096.0f);
|
||||||
|
|
||||||
sf->fader = MSG_ReadByte( msg );
|
sf->fader = MSG_ReadByte( msg );
|
||||||
sf->fadeg = MSG_ReadByte( msg );
|
sf->fadeg = MSG_ReadByte( msg );
|
||||||
|
@ -1820,7 +1888,7 @@ void CL_ParseScreenFade( sizebuf_t *msg )
|
||||||
// calc fade speed
|
// calc fade speed
|
||||||
if( duration > 0 )
|
if( duration > 0 )
|
||||||
{
|
{
|
||||||
if( sf->fadeFlags & FFADE_OUT )
|
if( FBitSet( sf->fadeFlags, FFADE_OUT ))
|
||||||
{
|
{
|
||||||
if( sf->fadeEnd )
|
if( sf->fadeEnd )
|
||||||
{
|
{
|
||||||
|
@ -1828,6 +1896,7 @@ void CL_ParseScreenFade( sizebuf_t *msg )
|
||||||
}
|
}
|
||||||
|
|
||||||
sf->fadeEnd += cl.time;
|
sf->fadeEnd += cl.time;
|
||||||
|
sf->fadeTotalEnd = sf->fadeEnd;
|
||||||
sf->fadeReset += sf->fadeEnd;
|
sf->fadeReset += sf->fadeEnd;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -2201,13 +2270,13 @@ void CL_ParseServerMessage( sizebuf_t *msg, qboolean normal_message )
|
||||||
break;
|
break;
|
||||||
case svc_serverdata:
|
case svc_serverdata:
|
||||||
Cbuf_Execute(); // make sure any stuffed commands are done
|
Cbuf_Execute(); // make sure any stuffed commands are done
|
||||||
CL_ParseServerData( msg );
|
CL_ParseServerData( msg, false );
|
||||||
break;
|
break;
|
||||||
case svc_lightstyle:
|
case svc_lightstyle:
|
||||||
CL_ParseLightStyle( msg );
|
CL_ParseLightStyle( msg );
|
||||||
break;
|
break;
|
||||||
case svc_updateuserinfo:
|
case svc_updateuserinfo:
|
||||||
CL_UpdateUserinfo( msg );
|
CL_UpdateUserinfo( msg, false );
|
||||||
break;
|
break;
|
||||||
case svc_deltatable:
|
case svc_deltatable:
|
||||||
Delta_ParseTableField( msg );
|
Delta_ParseTableField( msg );
|
||||||
|
@ -2237,7 +2306,7 @@ void CL_ParseServerMessage( sizebuf_t *msg, qboolean normal_message )
|
||||||
cl.frames[cl.parsecountmod].graphdata.event += MSG_GetNumBytesRead( msg ) - bufStart;
|
cl.frames[cl.parsecountmod].graphdata.event += MSG_GetNumBytesRead( msg ) - bufStart;
|
||||||
break;
|
break;
|
||||||
case svc_spawnbaseline:
|
case svc_spawnbaseline:
|
||||||
CL_ParseBaseline( msg );
|
CL_ParseBaseline( msg, false );
|
||||||
break;
|
break;
|
||||||
case svc_temp_entity:
|
case svc_temp_entity:
|
||||||
CL_ParseTempEntity( msg );
|
CL_ParseTempEntity( msg );
|
||||||
|
@ -2335,6 +2404,7 @@ void CL_ParseServerMessage( sizebuf_t *msg, qboolean normal_message )
|
||||||
break;
|
break;
|
||||||
case svc_voicedata:
|
case svc_voicedata:
|
||||||
CL_ParseVoiceData( msg );
|
CL_ParseVoiceData( msg );
|
||||||
|
cl.frames[cl.parsecountmod].graphdata.voicebytes += MSG_GetNumBytesRead( msg ) - bufStart;
|
||||||
break;
|
break;
|
||||||
case svc_resourcelocation:
|
case svc_resourcelocation:
|
||||||
CL_ParseResLocation( msg );
|
CL_ParseResLocation( msg );
|
||||||
|
@ -2373,160 +2443,6 @@ void CL_ParseServerMessage( sizebuf_t *msg, qboolean normal_message )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
==================
|
|
||||||
CL_ParseBaseline
|
|
||||||
==================
|
|
||||||
*/
|
|
||||||
void CL_LegacyParseBaseline( sizebuf_t *msg )
|
|
||||||
{
|
|
||||||
int i, newnum;
|
|
||||||
qboolean player;
|
|
||||||
cl_entity_t *ent;
|
|
||||||
|
|
||||||
Delta_InitClient (); // finalize client delta's
|
|
||||||
|
|
||||||
newnum = MSG_ReadWord( msg );
|
|
||||||
player = CL_IsPlayerIndex( newnum );
|
|
||||||
|
|
||||||
if( newnum >= clgame.maxEntities )
|
|
||||||
Host_Error( "CL_AllocEdict: no free edicts\n" );
|
|
||||||
|
|
||||||
ent = CL_EDICT_NUM( newnum );
|
|
||||||
memset( &ent->prevstate, 0, sizeof( ent->prevstate ));
|
|
||||||
ent->index = newnum;
|
|
||||||
|
|
||||||
MSG_ReadDeltaEntity( msg, &ent->prevstate, &ent->baseline, newnum, player, 1.0f );
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
==================
|
|
||||||
CL_ParseServerData
|
|
||||||
==================
|
|
||||||
*/
|
|
||||||
void CL_ParseLegacyServerData( sizebuf_t *msg )
|
|
||||||
{
|
|
||||||
string gamefolder;
|
|
||||||
qboolean background;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
Con_Reportf( "Legacy serverdata packet received.\n" );
|
|
||||||
|
|
||||||
cls.timestart = Sys_DoubleTime();
|
|
||||||
|
|
||||||
cls.demowaiting = false; // server is changed
|
|
||||||
//clgame.load_sequence++; // now all hud sprites are invalid
|
|
||||||
|
|
||||||
// wipe the client_t struct
|
|
||||||
if( !cls.changelevel && !cls.changedemo )
|
|
||||||
CL_ClearState ();
|
|
||||||
cls.state = ca_connected;
|
|
||||||
|
|
||||||
// parse protocol version number
|
|
||||||
i = MSG_ReadLong( msg );
|
|
||||||
//cls.serverProtocol = i;
|
|
||||||
|
|
||||||
if( i != 48 )
|
|
||||||
Host_Error( "Server uses invalid protocol (%i should be %i)\n", i, PROTOCOL_VERSION );
|
|
||||||
|
|
||||||
cl.servercount = MSG_ReadLong( msg );
|
|
||||||
cl.checksum = MSG_ReadLong( msg );
|
|
||||||
cl.playernum = MSG_ReadByte( msg );
|
|
||||||
cl.maxclients = MSG_ReadByte( msg );
|
|
||||||
clgame.maxEntities = MSG_ReadWord( msg );
|
|
||||||
clgame.maxEntities = bound( 30, clgame.maxEntities, 4096 );
|
|
||||||
clgame.maxModels = 512;
|
|
||||||
Q_strncpy( clgame.mapname, MSG_ReadString( msg ), MAX_STRING );
|
|
||||||
Q_strncpy( clgame.maptitle, MSG_ReadString( msg ), MAX_STRING );
|
|
||||||
background = MSG_ReadOneBit( msg );
|
|
||||||
Q_strncpy( gamefolder, MSG_ReadString( msg ), MAX_STRING );
|
|
||||||
host.features = (uint)MSG_ReadLong( msg );
|
|
||||||
|
|
||||||
// Re-init hud video, especially if we changed game directories
|
|
||||||
clgame.dllFuncs.pfnVidInit();
|
|
||||||
|
|
||||||
if( Con_FixedFont( ))
|
|
||||||
{
|
|
||||||
// seperate the printfs so the server message can have a color
|
|
||||||
Con_Print( "\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n" );
|
|
||||||
Con_Print( va( "%c%s\n\n", 2, clgame.maptitle ));
|
|
||||||
}
|
|
||||||
|
|
||||||
// multiplayer game?
|
|
||||||
if( cl.maxclients > 1 )
|
|
||||||
{
|
|
||||||
// allow console in multiplayer games
|
|
||||||
host.allow_console = true;
|
|
||||||
|
|
||||||
// loading user settings
|
|
||||||
CSCR_LoadDefaultCVars( "user.scr" );
|
|
||||||
|
|
||||||
if( r_decals->value > mp_decals.value )
|
|
||||||
Cvar_SetValue( "r_decals", mp_decals.value );
|
|
||||||
}
|
|
||||||
else Cvar_Reset( "r_decals" );
|
|
||||||
|
|
||||||
// set the background state
|
|
||||||
if( cls.demoplayback && ( cls.demonum != -1 ))
|
|
||||||
{
|
|
||||||
// re-init mouse
|
|
||||||
host.mouse_visible = false;
|
|
||||||
cl.background = true;
|
|
||||||
}
|
|
||||||
else cl.background = background;
|
|
||||||
|
|
||||||
if( cl.background ) // tell the game parts about background state
|
|
||||||
Cvar_FullSet( "cl_background", "1", FCVAR_READ_ONLY );
|
|
||||||
else Cvar_FullSet( "cl_background", "0", FCVAR_READ_ONLY );
|
|
||||||
|
|
||||||
if( !cls.changelevel )
|
|
||||||
{
|
|
||||||
// continue playing if we are changing level
|
|
||||||
S_StopBackgroundTrack ();
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !cls.changedemo )
|
|
||||||
UI_SetActiveMenu( cl.background );
|
|
||||||
else if( !cls.demoplayback )
|
|
||||||
Key_SetKeyDest( key_menu );
|
|
||||||
|
|
||||||
// don't reset cursor in background mode
|
|
||||||
if( cl.background )
|
|
||||||
IN_MouseRestorePos();
|
|
||||||
|
|
||||||
// will be changed later
|
|
||||||
cl.viewentity = cl.playernum + 1;
|
|
||||||
gameui.globals->maxClients = cl.maxclients;
|
|
||||||
Q_strncpy( gameui.globals->maptitle, clgame.maptitle, sizeof( gameui.globals->maptitle ));
|
|
||||||
|
|
||||||
if( !cls.changelevel && !cls.changedemo )
|
|
||||||
CL_InitEdicts (); // re-arrange edicts
|
|
||||||
|
|
||||||
// get splash name
|
|
||||||
if( cls.demoplayback && ( cls.demonum != -1 ))
|
|
||||||
Cvar_Set( "cl_levelshot_name", va( "levelshots/%s_%s", cls.demoname, refState.wideScreen ? "16x9" : "4x3" ));
|
|
||||||
else Cvar_Set( "cl_levelshot_name", va( "levelshots/%s_%s", clgame.mapname, refState.wideScreen ? "16x9" : "4x3" ));
|
|
||||||
Cvar_SetValue( "scr_loading", 0.0f ); // reset progress bar
|
|
||||||
|
|
||||||
if(( cl_allow_levelshots->value && !cls.changelevel ) || cl.background )
|
|
||||||
{
|
|
||||||
if( !FS_FileExists( va( "%s.bmp", cl_levelshot_name->string ), true ))
|
|
||||||
Cvar_Set( "cl_levelshot_name", "*black" ); // render a black screen
|
|
||||||
cls.scrshot_request = scrshot_plaque; // request levelshot even if exist (check filetime)
|
|
||||||
}
|
|
||||||
|
|
||||||
for( i = 0; i < MAX_CLIENTS; i++ )
|
|
||||||
COM_ClearCustomizationList( &cl.players[i].customdata, true );
|
|
||||||
CL_CreateCustomizationList();
|
|
||||||
|
|
||||||
memset( &clgame.movevars, 0, sizeof( clgame.movevars ));
|
|
||||||
memset( &clgame.oldmovevars, 0, sizeof( clgame.oldmovevars ));
|
|
||||||
memset( &clgame.centerPrint, 0, sizeof( clgame.centerPrint ));
|
|
||||||
cl.video_prepped = false;
|
|
||||||
cl.audio_prepped = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
==================
|
==================
|
||||||
CL_ParseStaticEntity
|
CL_ParseStaticEntity
|
||||||
|
@ -2602,8 +2518,6 @@ void CL_LegacyParseStaticEntity( sizebuf_t *msg )
|
||||||
R_AddEfrags( ent ); // add link
|
R_AddEfrags( ent ); // add link
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void CL_LegacyParseSoundPacket( sizebuf_t *msg, qboolean is_ambient )
|
void CL_LegacyParseSoundPacket( sizebuf_t *msg, qboolean is_ambient )
|
||||||
{
|
{
|
||||||
vec3_t pos;
|
vec3_t pos;
|
||||||
|
@ -2735,36 +2649,6 @@ void CL_LegacyPrecacheEvent( sizebuf_t *msg )
|
||||||
CL_SetEventIndex( cl.event_precache[eventIndex], eventIndex );
|
CL_SetEventIndex( cl.event_precache[eventIndex], eventIndex );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CL_LegacyUpdateUserinfo( sizebuf_t *msg )
|
|
||||||
{
|
|
||||||
int slot, id = 0;
|
|
||||||
qboolean active;
|
|
||||||
player_info_t *player;
|
|
||||||
|
|
||||||
slot = MSG_ReadUBitLong( msg, MAX_CLIENT_BITS );
|
|
||||||
|
|
||||||
if( slot >= MAX_CLIENTS )
|
|
||||||
Host_Error( "CL_ParseServerMessage: svc_updateuserinfo >= MAX_CLIENTS\n" );
|
|
||||||
|
|
||||||
//id = MSG_ReadLong( msg ); // unique user ID
|
|
||||||
player = &cl.players[slot];
|
|
||||||
active = MSG_ReadOneBit( msg ) ? true : false;
|
|
||||||
|
|
||||||
if( active )
|
|
||||||
{
|
|
||||||
Q_strncpy( player->userinfo, MSG_ReadString( msg ), sizeof( player->userinfo ));
|
|
||||||
Q_strncpy( player->name, Info_ValueForKey( player->userinfo, "name" ), sizeof( player->name ));
|
|
||||||
Q_strncpy( player->model, Info_ValueForKey( player->userinfo, "model" ), sizeof( player->model ));
|
|
||||||
player->topcolor = Q_atoi( Info_ValueForKey( player->userinfo, "topcolor" ));
|
|
||||||
player->bottomcolor = Q_atoi( Info_ValueForKey( player->userinfo, "bottomcolor" ));
|
|
||||||
player->spectator = Q_atoi( Info_ValueForKey( player->userinfo, "*hltv" ));
|
|
||||||
//MSG_ReadBytes( msg, player->hashedcdkey, sizeof( player->hashedcdkey ));
|
|
||||||
|
|
||||||
if( slot == cl.playernum ) memcpy( &gameui.playerinfo, player, sizeof( player_info_t ));
|
|
||||||
}
|
|
||||||
else memset( player, 0, sizeof( *player ));
|
|
||||||
}
|
|
||||||
#if XASH_LOW_MEMORY == 0
|
#if XASH_LOW_MEMORY == 0
|
||||||
#define MAX_LEGACY_RESOURCES 2048
|
#define MAX_LEGACY_RESOURCES 2048
|
||||||
#elif XASH_LOW_MEMORY == 2
|
#elif XASH_LOW_MEMORY == 2
|
||||||
|
@ -2968,13 +2852,13 @@ void CL_ParseLegacyServerMessage( sizebuf_t *msg, qboolean normal_message )
|
||||||
break;
|
break;
|
||||||
case svc_serverdata:
|
case svc_serverdata:
|
||||||
Cbuf_Execute(); // make sure any stuffed commands are done
|
Cbuf_Execute(); // make sure any stuffed commands are done
|
||||||
CL_ParseLegacyServerData( msg );
|
CL_ParseServerData( msg, true );
|
||||||
break;
|
break;
|
||||||
case svc_lightstyle:
|
case svc_lightstyle:
|
||||||
CL_ParseLightStyle( msg );
|
CL_ParseLightStyle( msg );
|
||||||
break;
|
break;
|
||||||
case svc_updateuserinfo:
|
case svc_updateuserinfo:
|
||||||
CL_LegacyUpdateUserinfo( msg );
|
CL_UpdateUserinfo( msg, true );
|
||||||
break;
|
break;
|
||||||
case svc_deltatable:
|
case svc_deltatable:
|
||||||
Delta_ParseTableField( msg );
|
Delta_ParseTableField( msg );
|
||||||
|
@ -3004,7 +2888,7 @@ void CL_ParseLegacyServerMessage( sizebuf_t *msg, qboolean normal_message )
|
||||||
cl.frames[cl.parsecountmod].graphdata.event += MSG_GetNumBytesRead( msg ) - bufStart;
|
cl.frames[cl.parsecountmod].graphdata.event += MSG_GetNumBytesRead( msg ) - bufStart;
|
||||||
break;
|
break;
|
||||||
case svc_spawnbaseline:
|
case svc_spawnbaseline:
|
||||||
CL_LegacyParseBaseline( msg );
|
CL_ParseBaseline( msg, true );
|
||||||
break;
|
break;
|
||||||
case svc_temp_entity:
|
case svc_temp_entity:
|
||||||
CL_ParseTempEntity( msg );
|
CL_ParseTempEntity( msg );
|
||||||
|
@ -3024,7 +2908,6 @@ void CL_ParseLegacyServerMessage( sizebuf_t *msg, qboolean normal_message )
|
||||||
break;
|
break;
|
||||||
case svc_legacy_modelindex:
|
case svc_legacy_modelindex:
|
||||||
CL_LegacyPrecacheModel( msg );
|
CL_LegacyPrecacheModel( msg );
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case svc_legacy_soundindex:
|
case svc_legacy_soundindex:
|
||||||
CL_LegacyPrecacheSound( msg );
|
CL_LegacyPrecacheSound( msg );
|
||||||
|
@ -3040,7 +2923,6 @@ void CL_ParseLegacyServerMessage( sizebuf_t *msg, qboolean normal_message )
|
||||||
CL_ParseRestore( msg );
|
CL_ParseRestore( msg );
|
||||||
break;
|
break;
|
||||||
case svc_legacy_eventindex:
|
case svc_legacy_eventindex:
|
||||||
//CL_ParseFinaleCutscene( msg, 3 );
|
|
||||||
CL_LegacyPrecacheEvent(msg);
|
CL_LegacyPrecacheEvent(msg);
|
||||||
break;
|
break;
|
||||||
case svc_weaponanim:
|
case svc_weaponanim:
|
||||||
|
@ -3117,12 +2999,6 @@ void CL_ParseLegacyServerMessage( sizebuf_t *msg, qboolean normal_message )
|
||||||
case svc_director:
|
case svc_director:
|
||||||
CL_ParseDirector( msg );
|
CL_ParseDirector( msg );
|
||||||
break;
|
break;
|
||||||
case svc_voiceinit:
|
|
||||||
CL_ParseVoiceInit( msg );
|
|
||||||
break;
|
|
||||||
case svc_voicedata:
|
|
||||||
CL_ParseVoiceData( msg );
|
|
||||||
break;
|
|
||||||
case svc_resourcelocation:
|
case svc_resourcelocation:
|
||||||
CL_ParseResLocation( msg );
|
CL_ParseResLocation( msg );
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -26,20 +26,6 @@ GNU General Public License for more details.
|
||||||
#define MIN_PREDICTION_EPSILON 0.5f // complain if error is > this and we have cl_showerror set
|
#define MIN_PREDICTION_EPSILON 0.5f // complain if error is > this and we have cl_showerror set
|
||||||
#define MAX_PREDICTION_ERROR 64.0f // above this is assumed to be a teleport, don't smooth, etc.
|
#define MAX_PREDICTION_ERROR 64.0f // above this is assumed to be a teleport, don't smooth, etc.
|
||||||
|
|
||||||
/*
|
|
||||||
=============
|
|
||||||
CL_ClearPhysEnts
|
|
||||||
|
|
||||||
=============
|
|
||||||
*/
|
|
||||||
void CL_ClearPhysEnts( void )
|
|
||||||
{
|
|
||||||
clgame.pmove->numtouch = 0;
|
|
||||||
clgame.pmove->numvisent = 0;
|
|
||||||
clgame.pmove->nummoveent = 0;
|
|
||||||
clgame.pmove->numphysent = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=============
|
=============
|
||||||
CL_PushPMStates
|
CL_PushPMStates
|
||||||
|
@ -208,7 +194,7 @@ check for instant movement in case
|
||||||
we don't want interpolate this
|
we don't want interpolate this
|
||||||
==================
|
==================
|
||||||
*/
|
*/
|
||||||
qboolean CL_PlayerTeleported( local_state_t *from, local_state_t *to )
|
static qboolean CL_PlayerTeleported( local_state_t *from, local_state_t *to )
|
||||||
{
|
{
|
||||||
int len, maxlen;
|
int len, maxlen;
|
||||||
vec3_t delta;
|
vec3_t delta;
|
||||||
|
@ -713,33 +699,7 @@ static int GAME_EXPORT pfnTestPlayerPosition( float *pos, pmtrace_t *ptrace )
|
||||||
|
|
||||||
static void GAME_EXPORT pfnStuckTouch( int hitent, pmtrace_t *tr )
|
static void GAME_EXPORT pfnStuckTouch( int hitent, pmtrace_t *tr )
|
||||||
{
|
{
|
||||||
int i;
|
PM_StuckTouch( clgame.pmove, hitent, tr );
|
||||||
|
|
||||||
for( i = 0; i < clgame.pmove->numtouch; i++ )
|
|
||||||
{
|
|
||||||
if( clgame.pmove->touchindex[i].ent == hitent )
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( clgame.pmove->numtouch >= MAX_PHYSENTS )
|
|
||||||
return;
|
|
||||||
|
|
||||||
VectorCopy( clgame.pmove->velocity, tr->deltavelocity );
|
|
||||||
tr->ent = hitent;
|
|
||||||
|
|
||||||
clgame.pmove->touchindex[clgame.pmove->numtouch++] = *tr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int GAME_EXPORT pfnPointContents( float *p, int *truecontents )
|
|
||||||
{
|
|
||||||
int cont, truecont;
|
|
||||||
|
|
||||||
truecont = cont = PM_PointContents( clgame.pmove, p );
|
|
||||||
if( truecontents ) *truecontents = truecont;
|
|
||||||
|
|
||||||
if( cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN )
|
|
||||||
cont = CONTENTS_WATER;
|
|
||||||
return cont;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int GAME_EXPORT pfnTruePointContents( float *p )
|
static int GAME_EXPORT pfnTruePointContents( float *p )
|
||||||
|
@ -747,101 +707,19 @@ static int GAME_EXPORT pfnTruePointContents( float *p )
|
||||||
return PM_TruePointContents( clgame.pmove, p );
|
return PM_TruePointContents( clgame.pmove, p );
|
||||||
}
|
}
|
||||||
|
|
||||||
static int GAME_EXPORT pfnHullPointContents( struct hull_s *hull, int num, float *p )
|
|
||||||
{
|
|
||||||
return PM_HullPointContents( hull, num, p );
|
|
||||||
}
|
|
||||||
|
|
||||||
static pmtrace_t GAME_EXPORT pfnPlayerTrace( float *start, float *end, int traceFlags, int ignore_pe )
|
static pmtrace_t GAME_EXPORT pfnPlayerTrace( float *start, float *end, int traceFlags, int ignore_pe )
|
||||||
{
|
{
|
||||||
return PM_PlayerTraceExt( clgame.pmove, start, end, traceFlags, clgame.pmove->numphysent, clgame.pmove->physents, ignore_pe, NULL );
|
return PM_PlayerTraceExt( clgame.pmove, start, end, traceFlags, clgame.pmove->numphysent, clgame.pmove->physents, ignore_pe, NULL );
|
||||||
}
|
}
|
||||||
|
|
||||||
pmtrace_t *PM_TraceLine( float *start, float *end, int flags, int usehull, int ignore_pe )
|
static void *pfnHullForBsp( physent_t *pe, float *offset )
|
||||||
{
|
|
||||||
static pmtrace_t tr;
|
|
||||||
int old_usehull;
|
|
||||||
|
|
||||||
old_usehull = clgame.pmove->usehull;
|
|
||||||
clgame.pmove->usehull = usehull;
|
|
||||||
|
|
||||||
switch( flags )
|
|
||||||
{
|
|
||||||
case PM_TRACELINE_PHYSENTSONLY:
|
|
||||||
tr = PM_PlayerTraceExt( clgame.pmove, start, end, 0, clgame.pmove->numphysent, clgame.pmove->physents, ignore_pe, NULL );
|
|
||||||
break;
|
|
||||||
case PM_TRACELINE_ANYVISIBLE:
|
|
||||||
tr = PM_PlayerTraceExt( clgame.pmove, start, end, 0, clgame.pmove->numvisent, clgame.pmove->visents, ignore_pe, NULL );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
clgame.pmove->usehull = old_usehull;
|
|
||||||
|
|
||||||
return &tr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static hull_t *pfnHullForBsp( physent_t *pe, float *offset )
|
|
||||||
{
|
{
|
||||||
return PM_HullForBsp( pe, clgame.pmove, offset );
|
return PM_HullForBsp( pe, clgame.pmove, offset );
|
||||||
}
|
}
|
||||||
|
|
||||||
static float GAME_EXPORT pfnTraceModel( physent_t *pe, float *start, float *end, trace_t *trace )
|
static float GAME_EXPORT pfnTraceModel( physent_t *pe, float *start, float *end, trace_t *trace )
|
||||||
{
|
{
|
||||||
int old_usehull;
|
return PM_TraceModel( clgame.pmove, pe, start, end, trace );
|
||||||
vec3_t start_l, end_l;
|
|
||||||
vec3_t offset, temp;
|
|
||||||
qboolean rotated;
|
|
||||||
matrix4x4 matrix;
|
|
||||||
hull_t *hull;
|
|
||||||
|
|
||||||
PM_InitTrace( trace, end );
|
|
||||||
|
|
||||||
old_usehull = clgame.pmove->usehull;
|
|
||||||
clgame.pmove->usehull = 2;
|
|
||||||
|
|
||||||
hull = PM_HullForBsp( pe, clgame.pmove, offset );
|
|
||||||
|
|
||||||
clgame.pmove->usehull = old_usehull;
|
|
||||||
|
|
||||||
if( pe->solid == SOLID_BSP && !VectorIsNull( pe->angles ))
|
|
||||||
rotated = true;
|
|
||||||
else rotated = false;
|
|
||||||
|
|
||||||
if( rotated )
|
|
||||||
{
|
|
||||||
Matrix4x4_CreateFromEntity( matrix, pe->angles, offset, 1.0f );
|
|
||||||
Matrix4x4_VectorITransform( matrix, start, start_l );
|
|
||||||
Matrix4x4_VectorITransform( matrix, end, end_l );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
VectorSubtract( start, offset, start_l );
|
|
||||||
VectorSubtract( end, offset, end_l );
|
|
||||||
}
|
|
||||||
|
|
||||||
PM_RecursiveHullCheck( hull, hull->firstclipnode, 0, 1, start_l, end_l, (pmtrace_t *)trace );
|
|
||||||
trace->ent = NULL;
|
|
||||||
|
|
||||||
if( rotated )
|
|
||||||
{
|
|
||||||
VectorCopy( trace->plane.normal, temp );
|
|
||||||
Matrix4x4_TransformPositivePlane( matrix, temp, trace->plane.dist, trace->plane.normal, &trace->plane.dist );
|
|
||||||
}
|
|
||||||
|
|
||||||
VectorLerp( start, trace->fraction, end, trace->endpos );
|
|
||||||
|
|
||||||
return trace->fraction;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *pfnTraceTexture( int ground, float *vstart, float *vend )
|
|
||||||
{
|
|
||||||
physent_t *pe;
|
|
||||||
|
|
||||||
if( ground < 0 || ground >= clgame.pmove->numphysent )
|
|
||||||
return NULL; // bad ground
|
|
||||||
|
|
||||||
pe = &clgame.pmove->physents[ground];
|
|
||||||
return PM_TraceTexture( pe, vstart, vend );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void GAME_EXPORT pfnPlaySound( int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch )
|
static void GAME_EXPORT pfnPlaySound( int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch )
|
||||||
|
@ -870,25 +748,7 @@ static int GAME_EXPORT pfnTestPlayerPositionEx( float *pos, pmtrace_t *ptrace, p
|
||||||
|
|
||||||
static pmtrace_t *pfnTraceLineEx( float *start, float *end, int flags, int usehull, pfnIgnore pmFilter )
|
static pmtrace_t *pfnTraceLineEx( float *start, float *end, int flags, int usehull, pfnIgnore pmFilter )
|
||||||
{
|
{
|
||||||
static pmtrace_t tr;
|
return PM_TraceLineEx( clgame.pmove, start, end, flags, usehull, pmFilter );
|
||||||
int old_usehull;
|
|
||||||
|
|
||||||
old_usehull = clgame.pmove->usehull;
|
|
||||||
clgame.pmove->usehull = usehull;
|
|
||||||
|
|
||||||
switch( flags )
|
|
||||||
{
|
|
||||||
case PM_TRACELINE_PHYSENTSONLY:
|
|
||||||
tr = PM_PlayerTraceExt( clgame.pmove, start, end, 0, clgame.pmove->numphysent, clgame.pmove->physents, -1, pmFilter );
|
|
||||||
break;
|
|
||||||
case PM_TRACELINE_ANYVISIBLE:
|
|
||||||
tr = PM_PlayerTraceExt( clgame.pmove, start, end, 0, clgame.pmove->numvisent, clgame.pmove->visents, -1, pmFilter );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
clgame.pmove->usehull = old_usehull;
|
|
||||||
|
|
||||||
return &tr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -928,23 +788,23 @@ void CL_InitClientMove( void )
|
||||||
clgame.pmove->Con_Printf = Con_Printf;
|
clgame.pmove->Con_Printf = Con_Printf;
|
||||||
clgame.pmove->Sys_FloatTime = Sys_DoubleTime;
|
clgame.pmove->Sys_FloatTime = Sys_DoubleTime;
|
||||||
clgame.pmove->PM_StuckTouch = pfnStuckTouch;
|
clgame.pmove->PM_StuckTouch = pfnStuckTouch;
|
||||||
clgame.pmove->PM_PointContents = pfnPointContents;
|
clgame.pmove->PM_PointContents = (void*)PM_CL_PointContents;
|
||||||
clgame.pmove->PM_TruePointContents = pfnTruePointContents;
|
clgame.pmove->PM_TruePointContents = pfnTruePointContents;
|
||||||
clgame.pmove->PM_HullPointContents = pfnHullPointContents;
|
clgame.pmove->PM_HullPointContents = (void*)PM_HullPointContents;
|
||||||
clgame.pmove->PM_PlayerTrace = pfnPlayerTrace;
|
clgame.pmove->PM_PlayerTrace = pfnPlayerTrace;
|
||||||
clgame.pmove->PM_TraceLine = PM_TraceLine;
|
clgame.pmove->PM_TraceLine = PM_CL_TraceLine;
|
||||||
clgame.pmove->RandomLong = COM_RandomLong;
|
clgame.pmove->RandomLong = COM_RandomLong;
|
||||||
clgame.pmove->RandomFloat = COM_RandomFloat;
|
clgame.pmove->RandomFloat = COM_RandomFloat;
|
||||||
clgame.pmove->PM_GetModelType = pfnGetModelType;
|
clgame.pmove->PM_GetModelType = pfnGetModelType;
|
||||||
clgame.pmove->PM_GetModelBounds = pfnGetModelBounds;
|
clgame.pmove->PM_GetModelBounds = pfnGetModelBounds;
|
||||||
clgame.pmove->PM_HullForBsp = (void*)pfnHullForBsp;
|
clgame.pmove->PM_HullForBsp = pfnHullForBsp;
|
||||||
clgame.pmove->PM_TraceModel = pfnTraceModel;
|
clgame.pmove->PM_TraceModel = pfnTraceModel;
|
||||||
clgame.pmove->COM_FileSize = COM_FileSize;
|
clgame.pmove->COM_FileSize = COM_FileSize;
|
||||||
clgame.pmove->COM_LoadFile = COM_LoadFile;
|
clgame.pmove->COM_LoadFile = COM_LoadFile;
|
||||||
clgame.pmove->COM_FreeFile = COM_FreeFile;
|
clgame.pmove->COM_FreeFile = COM_FreeFile;
|
||||||
clgame.pmove->memfgets = COM_MemFgets;
|
clgame.pmove->memfgets = COM_MemFgets;
|
||||||
clgame.pmove->PM_PlaySound = pfnPlaySound;
|
clgame.pmove->PM_PlaySound = pfnPlaySound;
|
||||||
clgame.pmove->PM_TraceTexture = pfnTraceTexture;
|
clgame.pmove->PM_TraceTexture = PM_CL_TraceTexture;
|
||||||
clgame.pmove->PM_PlaybackEventFull = pfnPlaybackEventFull;
|
clgame.pmove->PM_PlaybackEventFull = pfnPlaybackEventFull;
|
||||||
clgame.pmove->PM_PlayerTraceEx = pfnPlayerTraceEx;
|
clgame.pmove->PM_PlayerTraceEx = pfnPlayerTraceEx;
|
||||||
clgame.pmove->PM_TestPlayerPositionEx = pfnTestPlayerPositionEx;
|
clgame.pmove->PM_TestPlayerPositionEx = pfnTestPlayerPositionEx;
|
||||||
|
@ -955,21 +815,10 @@ void CL_InitClientMove( void )
|
||||||
clgame.dllFuncs.pfnPlayerMoveInit( clgame.pmove );
|
clgame.dllFuncs.pfnPlayerMoveInit( clgame.pmove );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PM_CheckMovingGround( clientdata_t *cd, entity_state_t *state, float frametime )
|
static void CL_SetupPMove( playermove_t *pmove, const local_state_t *from, const usercmd_t *ucmd, qboolean runfuncs, double time )
|
||||||
{
|
{
|
||||||
if(!( cd->flags & FL_BASEVELOCITY ))
|
const entity_state_t *ps;
|
||||||
{
|
const clientdata_t *cd;
|
||||||
// apply momentum (add in half of the previous frame of velocity first)
|
|
||||||
VectorMA( cd->velocity, 1.0f + (frametime * 0.5f), state->basevelocity, cd->velocity );
|
|
||||||
VectorClear( state->basevelocity );
|
|
||||||
}
|
|
||||||
cd->flags &= ~FL_BASEVELOCITY;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CL_SetupPMove( playermove_t *pmove, local_state_t *from, usercmd_t *ucmd, qboolean runfuncs, double time )
|
|
||||||
{
|
|
||||||
entity_state_t *ps;
|
|
||||||
clientdata_t *cd;
|
|
||||||
|
|
||||||
ps = &from->playerstate;
|
ps = &from->playerstate;
|
||||||
cd = &from->client;
|
cd = &from->client;
|
||||||
|
@ -986,13 +835,13 @@ void CL_SetupPMove( playermove_t *pmove, local_state_t *from, usercmd_t *ucmd, q
|
||||||
VectorCopy( ps->basevelocity, pmove->basevelocity );
|
VectorCopy( ps->basevelocity, pmove->basevelocity );
|
||||||
VectorCopy( cd->view_ofs, pmove->view_ofs );
|
VectorCopy( cd->view_ofs, pmove->view_ofs );
|
||||||
VectorClear( pmove->movedir );
|
VectorClear( pmove->movedir );
|
||||||
pmove->flDuckTime = cd->flDuckTime;
|
pmove->flDuckTime = (float)cd->flDuckTime;
|
||||||
pmove->bInDuck = cd->bInDuck;
|
pmove->bInDuck = cd->bInDuck;
|
||||||
pmove->usehull = ps->usehull;
|
pmove->usehull = ps->usehull;
|
||||||
pmove->flTimeStepSound = cd->flTimeStepSound;
|
pmove->flTimeStepSound = cd->flTimeStepSound;
|
||||||
pmove->iStepLeft = ps->iStepLeft;
|
pmove->iStepLeft = ps->iStepLeft;
|
||||||
pmove->flFallVelocity = ps->flFallVelocity;
|
pmove->flFallVelocity = ps->flFallVelocity;
|
||||||
pmove->flSwimTime = cd->flSwimTime;
|
pmove->flSwimTime = (float)cd->flSwimTime;
|
||||||
VectorCopy( cd->punchangle, pmove->punchangle );
|
VectorCopy( cd->punchangle, pmove->punchangle );
|
||||||
pmove->flNextPrimaryAttack = 0.0f; // not used by PM_ code
|
pmove->flNextPrimaryAttack = 0.0f; // not used by PM_ code
|
||||||
pmove->effects = ps->effects;
|
pmove->effects = ps->effects;
|
||||||
|
@ -1000,7 +849,7 @@ void CL_SetupPMove( playermove_t *pmove, local_state_t *from, usercmd_t *ucmd, q
|
||||||
pmove->gravity = ps->gravity;
|
pmove->gravity = ps->gravity;
|
||||||
pmove->friction = ps->friction;
|
pmove->friction = ps->friction;
|
||||||
pmove->oldbuttons = ps->oldbuttons;
|
pmove->oldbuttons = ps->oldbuttons;
|
||||||
pmove->waterjumptime = cd->waterjumptime;
|
pmove->waterjumptime = (float)cd->waterjumptime;
|
||||||
pmove->dead = (cl.local.health <= 0);
|
pmove->dead = (cl.local.health <= 0);
|
||||||
pmove->deadflag = cd->deadflag;
|
pmove->deadflag = cd->deadflag;
|
||||||
pmove->spectator = (cls.spectator != 0);
|
pmove->spectator = (cls.spectator != 0);
|
||||||
|
@ -1027,7 +876,7 @@ void CL_SetupPMove( playermove_t *pmove, local_state_t *from, usercmd_t *ucmd, q
|
||||||
Q_strncpy( pmove->physinfo, cls.physinfo, MAX_INFO_STRING );
|
Q_strncpy( pmove->physinfo, cls.physinfo, MAX_INFO_STRING );
|
||||||
}
|
}
|
||||||
|
|
||||||
void CL_FinishPMove( playermove_t *pmove, local_state_t *to )
|
const void CL_FinishPMove( const playermove_t *pmove, local_state_t *to )
|
||||||
{
|
{
|
||||||
entity_state_t *ps;
|
entity_state_t *ps;
|
||||||
clientdata_t *cd;
|
clientdata_t *cd;
|
||||||
|
@ -1038,7 +887,7 @@ void CL_FinishPMove( playermove_t *pmove, local_state_t *to )
|
||||||
cd->flags = pmove->flags;
|
cd->flags = pmove->flags;
|
||||||
cd->bInDuck = pmove->bInDuck;
|
cd->bInDuck = pmove->bInDuck;
|
||||||
cd->flTimeStepSound = pmove->flTimeStepSound;
|
cd->flTimeStepSound = pmove->flTimeStepSound;
|
||||||
cd->flDuckTime = pmove->flDuckTime;
|
cd->flDuckTime = (int)pmove->flDuckTime;
|
||||||
cd->flSwimTime = (int)pmove->flSwimTime;
|
cd->flSwimTime = (int)pmove->flSwimTime;
|
||||||
cd->waterjumptime = (int)pmove->waterjumptime;
|
cd->waterjumptime = (int)pmove->waterjumptime;
|
||||||
cd->watertype = pmove->watertype;
|
cd->watertype = pmove->watertype;
|
||||||
|
@ -1051,7 +900,7 @@ void CL_FinishPMove( playermove_t *pmove, local_state_t *to )
|
||||||
VectorCopy( pmove->angles, ps->angles );
|
VectorCopy( pmove->angles, ps->angles );
|
||||||
VectorCopy( pmove->basevelocity, ps->basevelocity );
|
VectorCopy( pmove->basevelocity, ps->basevelocity );
|
||||||
VectorCopy( pmove->punchangle, cd->punchangle );
|
VectorCopy( pmove->punchangle, cd->punchangle );
|
||||||
ps->oldbuttons = pmove->cmd.buttons;
|
ps->oldbuttons = (uint)pmove->cmd.buttons;
|
||||||
ps->friction = pmove->friction;
|
ps->friction = pmove->friction;
|
||||||
ps->movetype = pmove->movetype;
|
ps->movetype = pmove->movetype;
|
||||||
ps->onground = pmove->onground;
|
ps->onground = pmove->onground;
|
||||||
|
@ -1159,13 +1008,9 @@ void CL_PredictMovement( qboolean repredicting )
|
||||||
{
|
{
|
||||||
runcmd_t *to_cmd = NULL, *from_cmd;
|
runcmd_t *to_cmd = NULL, *from_cmd;
|
||||||
local_state_t *from = NULL, *to = NULL;
|
local_state_t *from = NULL, *to = NULL;
|
||||||
uint current_command;
|
|
||||||
uint current_command_mod;
|
|
||||||
frame_t *frame = NULL;
|
frame_t *frame = NULL;
|
||||||
uint i, stoppoint;
|
uint i, stoppoint;
|
||||||
qboolean runfuncs;
|
|
||||||
double f = 1.0;
|
double f = 1.0;
|
||||||
cl_entity_t *ent;
|
|
||||||
double time;
|
double time;
|
||||||
|
|
||||||
if( cls.state != ca_active || cls.spectator )
|
if( cls.state != ca_active || cls.spectator )
|
||||||
|
@ -1176,7 +1021,7 @@ void CL_PredictMovement( qboolean repredicting )
|
||||||
|
|
||||||
CL_SetUpPlayerPrediction( false, false );
|
CL_SetUpPlayerPrediction( false, false );
|
||||||
|
|
||||||
if( cls.state != ca_active || !cl.validsequence )
|
if( !cl.validsequence )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(( cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged ) >= CL_UPDATE_MASK )
|
if(( cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged ) >= CL_UPDATE_MASK )
|
||||||
|
@ -1217,6 +1062,10 @@ void CL_PredictMovement( qboolean repredicting )
|
||||||
|
|
||||||
for( i = 1; i < CL_UPDATE_MASK && cls.netchan.incoming_acknowledged + i < cls.netchan.outgoing_sequence + stoppoint; i++ )
|
for( i = 1; i < CL_UPDATE_MASK && cls.netchan.incoming_acknowledged + i < cls.netchan.outgoing_sequence + stoppoint; i++ )
|
||||||
{
|
{
|
||||||
|
uint current_command;
|
||||||
|
uint current_command_mod;
|
||||||
|
qboolean runfuncs;
|
||||||
|
|
||||||
current_command = cls.netchan.incoming_acknowledged + i;
|
current_command = cls.netchan.incoming_acknowledged + i;
|
||||||
current_command_mod = current_command & CL_UPDATE_MASK;
|
current_command_mod = current_command & CL_UPDATE_MASK;
|
||||||
|
|
||||||
|
@ -1293,7 +1142,7 @@ void CL_PredictMovement( qboolean repredicting )
|
||||||
|
|
||||||
if( FBitSet( to->client.flags, FL_ONGROUND ))
|
if( FBitSet( to->client.flags, FL_ONGROUND ))
|
||||||
{
|
{
|
||||||
ent = CL_GetEntityByIndex( cl.local.lastground );
|
cl_entity_t *ent = CL_GetEntityByIndex( cl.local.lastground );
|
||||||
cl.local.onground = cl.local.lastground;
|
cl.local.onground = cl.local.lastground;
|
||||||
cl.local.moving = false;
|
cl.local.moving = false;
|
||||||
|
|
||||||
|
@ -1315,7 +1164,7 @@ void CL_PredictMovement( qboolean repredicting )
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cl.local.onground = -1;
|
cl.local.onground = -1;
|
||||||
cl.local.moving = 0;
|
cl.local.moving = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( cls.correction_time > 0 && !cl_nosmooth->value && cl_smoothtime->value )
|
if( cls.correction_time > 0 && !cl_nosmooth->value && cl_smoothtime->value )
|
||||||
|
|
|
@ -237,10 +237,6 @@ static void CL_ParseQuakeServerInfo( sizebuf_t *msg )
|
||||||
}
|
}
|
||||||
else Cvar_Reset( "r_decals" );
|
else Cvar_Reset( "r_decals" );
|
||||||
|
|
||||||
// re-init mouse
|
|
||||||
if( cl.background )
|
|
||||||
host.mouse_visible = false;
|
|
||||||
|
|
||||||
if( cl.background ) // tell the game parts about background state
|
if( cl.background ) // tell the game parts about background state
|
||||||
Cvar_FullSet( "cl_background", "1", FCVAR_READ_ONLY );
|
Cvar_FullSet( "cl_background", "1", FCVAR_READ_ONLY );
|
||||||
else Cvar_FullSet( "cl_background", "0", FCVAR_READ_ONLY );
|
else Cvar_FullSet( "cl_background", "0", FCVAR_READ_ONLY );
|
||||||
|
|
|
@ -133,7 +133,7 @@ const char *CL_GenericHandle( int fileindex )
|
||||||
return cl.files_precache[fileindex];
|
return cl.files_precache[fileindex];
|
||||||
}
|
}
|
||||||
|
|
||||||
int CL_RenderGetParm( const int parm, const int arg, const qboolean checkRef )
|
intptr_t CL_RenderGetParm( const int parm, const int arg, const qboolean checkRef )
|
||||||
{
|
{
|
||||||
switch( parm )
|
switch( parm )
|
||||||
{
|
{
|
||||||
|
@ -161,9 +161,9 @@ int CL_RenderGetParm( const int parm, const int arg, const qboolean checkRef )
|
||||||
case PARM_WATER_ALPHA:
|
case PARM_WATER_ALPHA:
|
||||||
return FBitSet( world.flags, FWORLD_WATERALPHA );
|
return FBitSet( world.flags, FWORLD_WATERALPHA );
|
||||||
case PARM_DELUXEDATA:
|
case PARM_DELUXEDATA:
|
||||||
return *(int *)&world.deluxedata;
|
return (intptr_t)world.deluxedata;
|
||||||
case PARM_SHADOWDATA:
|
case PARM_SHADOWDATA:
|
||||||
return *(int *)&world.shadowdata;
|
return (intptr_t)world.shadowdata;
|
||||||
default:
|
default:
|
||||||
// indicates call from client.dll
|
// indicates call from client.dll
|
||||||
if( checkRef )
|
if( checkRef )
|
||||||
|
@ -204,7 +204,7 @@ int CL_RenderGetParm( const int parm, const int arg, const qboolean checkRef )
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pfnRenderGetParm( int parm, int arg )
|
static intptr_t pfnRenderGetParm( int parm, int arg )
|
||||||
{
|
{
|
||||||
return CL_RenderGetParm( parm, arg, true );
|
return CL_RenderGetParm( parm, arg, true );
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,8 +150,7 @@ same as r_speeds but for network channel
|
||||||
void SCR_NetSpeeds( void )
|
void SCR_NetSpeeds( void )
|
||||||
{
|
{
|
||||||
static char msg[MAX_SYSPATH];
|
static char msg[MAX_SYSPATH];
|
||||||
int x, y, height;
|
int x, y;
|
||||||
char *p, *start, *end;
|
|
||||||
float time = cl.mtime[0];
|
float time = cl.mtime[0];
|
||||||
static int min_svfps = 100;
|
static int min_svfps = 100;
|
||||||
static int max_svfps = 0;
|
static int max_svfps = 0;
|
||||||
|
@ -160,6 +159,7 @@ void SCR_NetSpeeds( void )
|
||||||
static int max_clfps = 0;
|
static int max_clfps = 0;
|
||||||
int cur_clfps = 0;
|
int cur_clfps = 0;
|
||||||
rgba_t color;
|
rgba_t color;
|
||||||
|
cl_font_t *font = Con_GetCurFont();
|
||||||
|
|
||||||
if( !host.allow_console )
|
if( !host.allow_console )
|
||||||
return;
|
return;
|
||||||
|
@ -196,25 +196,11 @@ void SCR_NetSpeeds( void )
|
||||||
Q_memprint( cls.netchan.total_sended )
|
Q_memprint( cls.netchan.total_sended )
|
||||||
);
|
);
|
||||||
|
|
||||||
x = refState.width - 320;
|
x = refState.width - 320 * font->scale;
|
||||||
y = 384;
|
y = 384;
|
||||||
|
|
||||||
Con_DrawStringLen( NULL, NULL, &height );
|
|
||||||
MakeRGBA( color, 255, 255, 255, 255 );
|
MakeRGBA( color, 255, 255, 255, 255 );
|
||||||
|
CL_DrawString( x, y, msg, color, font, FONT_DRAW_RESETCOLORONLF );
|
||||||
p = start = msg;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
end = Q_strchr( p, '\n' );
|
|
||||||
if( end ) msg[end-start] = '\0';
|
|
||||||
|
|
||||||
Con_DrawString( x, y, p, color );
|
|
||||||
y += height;
|
|
||||||
|
|
||||||
if( end ) p = end + 1;
|
|
||||||
else break;
|
|
||||||
} while( 1 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -231,31 +217,15 @@ void SCR_RSpeeds( void )
|
||||||
|
|
||||||
if( ref.dllFuncs.R_SpeedsMessage( msg, sizeof( msg )))
|
if( ref.dllFuncs.R_SpeedsMessage( msg, sizeof( msg )))
|
||||||
{
|
{
|
||||||
int x, y, height;
|
int x, y;
|
||||||
char *p, *start, *end;
|
|
||||||
rgba_t color;
|
rgba_t color;
|
||||||
|
cl_font_t *font = Con_GetCurFont();
|
||||||
|
|
||||||
x = refState.width - 340;
|
x = refState.width - 340 * font->scale;
|
||||||
y = 64;
|
y = 64;
|
||||||
|
|
||||||
Con_DrawStringLen( NULL, NULL, &height );
|
|
||||||
MakeRGBA( color, 255, 255, 255, 255 );
|
MakeRGBA( color, 255, 255, 255, 255 );
|
||||||
|
CL_DrawString( x, y, msg, color, font, FONT_DRAW_RESETCOLORONLF );
|
||||||
p = start = msg;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
end = Q_strchr( p, '\n' );
|
|
||||||
if( end ) msg[end-start] = '\0';
|
|
||||||
|
|
||||||
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 );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -577,77 +547,6 @@ void SCR_UpdateScreen( void )
|
||||||
V_PostRender();
|
V_PostRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
qboolean SCR_LoadFixedWidthFont( const char *fontname )
|
|
||||||
{
|
|
||||||
int i, fontWidth;
|
|
||||||
|
|
||||||
if( cls.creditsFont.valid )
|
|
||||||
return true; // already loaded
|
|
||||||
|
|
||||||
if( !FS_FileExists( fontname, false ))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
cls.creditsFont.hFontTexture = ref.dllFuncs.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;
|
|
||||||
cls.creditsFont.valid = true;
|
|
||||||
|
|
||||||
// build fixed rectangles
|
|
||||||
for( i = 0; i < 256; i++ )
|
|
||||||
{
|
|
||||||
cls.creditsFont.fontRc[i].left = (i * (fontWidth / 16)) % fontWidth;
|
|
||||||
cls.creditsFont.fontRc[i].right = cls.creditsFont.fontRc[i].left + fontWidth / 16;
|
|
||||||
cls.creditsFont.fontRc[i].top = (i / 16) * (fontWidth / 16);
|
|
||||||
cls.creditsFont.fontRc[i].bottom = cls.creditsFont.fontRc[i].top + fontWidth / 16;
|
|
||||||
cls.creditsFont.charWidths[i] = clgame.scrInfo.charWidths[i] = fontWidth / 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
qboolean SCR_LoadVariableWidthFont( const char *fontname )
|
|
||||||
{
|
|
||||||
int i, fontWidth;
|
|
||||||
byte *buffer;
|
|
||||||
fs_offset_t length;
|
|
||||||
qfont_t *src;
|
|
||||||
|
|
||||||
if( cls.creditsFont.valid )
|
|
||||||
return true; // already loaded
|
|
||||||
|
|
||||||
if( !FS_FileExists( fontname, false ))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
cls.creditsFont.hFontTexture = ref.dllFuncs.GL_LoadTexture( fontname, NULL, 0, TF_IMAGE );
|
|
||||||
R_GetTextureParms( &fontWidth, NULL, cls.creditsFont.hFontTexture );
|
|
||||||
|
|
||||||
// half-life font with variable chars witdh
|
|
||||||
buffer = FS_LoadFile( fontname, &length, false );
|
|
||||||
|
|
||||||
// setup creditsfont
|
|
||||||
if( buffer && length >= sizeof( qfont_t ))
|
|
||||||
{
|
|
||||||
src = (qfont_t *)buffer;
|
|
||||||
cls.creditsFont.charHeight = clgame.scrInfo.iCharHeight = src->rowheight;
|
|
||||||
cls.creditsFont.type = FONT_VARIABLE;
|
|
||||||
|
|
||||||
// build rectangles
|
|
||||||
for( i = 0; i < 256; i++ )
|
|
||||||
{
|
|
||||||
cls.creditsFont.fontRc[i].left = (word)src->fontinfo[i].startoffset % fontWidth;
|
|
||||||
cls.creditsFont.fontRc[i].right = cls.creditsFont.fontRc[i].left + src->fontinfo[i].charwidth;
|
|
||||||
cls.creditsFont.fontRc[i].top = (word)src->fontinfo[i].startoffset / fontWidth;
|
|
||||||
cls.creditsFont.fontRc[i].bottom = cls.creditsFont.fontRc[i].top + src->rowheight;
|
|
||||||
cls.creditsFont.charWidths[i] = clgame.scrInfo.charWidths[i] = src->fontinfo[i].charwidth;
|
|
||||||
}
|
|
||||||
cls.creditsFont.valid = true;
|
|
||||||
}
|
|
||||||
if( buffer ) Mem_Free( buffer );
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
================
|
================
|
||||||
SCR_LoadCreditsFont
|
SCR_LoadCreditsFont
|
||||||
|
@ -657,22 +556,41 @@ INTERNAL RESOURCE
|
||||||
*/
|
*/
|
||||||
void SCR_LoadCreditsFont( void )
|
void SCR_LoadCreditsFont( void )
|
||||||
{
|
{
|
||||||
const char *path = "gfx/creditsfont.fnt";
|
cl_font_t *const font = &cls.creditsFont;
|
||||||
dword crc;
|
qboolean success = false;
|
||||||
|
float scale = hud_fontscale->value;
|
||||||
|
dword crc = 0;
|
||||||
|
|
||||||
// replace default gfx.wad textures by current charset's font
|
// replace default gfx.wad textures by current charset's font
|
||||||
if( !CRC32_File( &crc, "gfx.wad" ) || crc == 0x49eb9f16 )
|
if( !CRC32_File( &crc, "gfx.wad" ) || crc == 0x49eb9f16 )
|
||||||
{
|
{
|
||||||
const char *path2 = va("creditsfont_%s.fnt", Cvar_VariableString( "con_charset" ) );
|
string charsetFnt;
|
||||||
if( FS_FileExists( path2, false ) )
|
|
||||||
path = path2;
|
if( Q_snprintf( charsetFnt, sizeof( charsetFnt ),
|
||||||
|
"creditsfont_%s.fnt", Cvar_VariableString( "con_charset" )) > 0 )
|
||||||
|
{
|
||||||
|
if( FS_FileExists( charsetFnt, false ))
|
||||||
|
success = Con_LoadVariableWidthFont( charsetFnt, font, scale, kRenderTransAdd, TF_FONT );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !SCR_LoadVariableWidthFont( path ))
|
if( !success )
|
||||||
|
success = Con_LoadVariableWidthFont( "gfx/creditsfont.fnt", font, scale, kRenderTransAdd, TF_FONT );
|
||||||
|
|
||||||
|
if( !success )
|
||||||
|
success = Con_LoadFixedWidthFont( "gfx/conchars", font, scale, kRenderTransAdd, TF_FONT );
|
||||||
|
|
||||||
|
// copy font size for client.dll
|
||||||
|
if( success )
|
||||||
{
|
{
|
||||||
if( !SCR_LoadFixedWidthFont( "gfx/conchars" ))
|
int i;
|
||||||
Con_DPrintf( S_ERROR "failed to load HUD font\n" );
|
|
||||||
|
clgame.scrInfo.iCharHeight = cls.creditsFont.charHeight;
|
||||||
|
|
||||||
|
for( i = 0; i < ARRAYSIZE( cls.creditsFont.charWidths ); i++ )
|
||||||
|
clgame.scrInfo.charWidths[i] = cls.creditsFont.charWidths[i];
|
||||||
}
|
}
|
||||||
|
else Con_DPrintf( S_ERROR "failed to load HUD font\n" );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -780,7 +698,6 @@ SCR_VidInit
|
||||||
*/
|
*/
|
||||||
void SCR_VidInit( void )
|
void SCR_VidInit( void )
|
||||||
{
|
{
|
||||||
string libpath;
|
|
||||||
if( !ref.initialized ) // don't call VidInit too soon
|
if( !ref.initialized ) // don't call VidInit too soon
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -795,8 +712,11 @@ void SCR_VidInit( void )
|
||||||
gameui.globals->scrHeight = refState.height;
|
gameui.globals->scrHeight = refState.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
COM_GetCommonLibraryPath( LIBRARY_CLIENT, libpath, sizeof( libpath ));
|
// notify vgui about screen size change
|
||||||
VGui_Startup( libpath, refState.width, refState.height );
|
if( clgame.hInstance )
|
||||||
|
{
|
||||||
|
VGui_Startup( refState.width, refState.height );
|
||||||
|
}
|
||||||
|
|
||||||
CL_ClearSpriteTextures(); // now all hud sprites are invalid
|
CL_ClearSpriteTextures(); // now all hud sprites are invalid
|
||||||
|
|
||||||
|
@ -827,7 +747,7 @@ void SCR_Init( void )
|
||||||
v_dark = Cvar_Get( "v_dark", "0", 0, "starts level from dark screen" );
|
v_dark = Cvar_Get( "v_dark", "0", 0, "starts level from dark screen" );
|
||||||
scr_viewsize = Cvar_Get( "viewsize", "120", FCVAR_ARCHIVE, "screen size" );
|
scr_viewsize = Cvar_Get( "viewsize", "120", FCVAR_ARCHIVE, "screen size" );
|
||||||
net_speeds = Cvar_Get( "net_speeds", "0", FCVAR_ARCHIVE, "show network packets" );
|
net_speeds = Cvar_Get( "net_speeds", "0", FCVAR_ARCHIVE, "show network packets" );
|
||||||
cl_showfps = Cvar_Get( "cl_showfps", "1", FCVAR_ARCHIVE, "show client fps" );
|
cl_showfps = Cvar_Get( "cl_showfps", "0", FCVAR_ARCHIVE, "show client fps" );
|
||||||
cl_showpos = Cvar_Get( "cl_showpos", "0", FCVAR_ARCHIVE, "show local player position and velocity" );
|
cl_showpos = Cvar_Get( "cl_showpos", "0", FCVAR_ARCHIVE, "show local player position and velocity" );
|
||||||
|
|
||||||
// register our commands
|
// register our commands
|
||||||
|
|
|
@ -1037,7 +1037,7 @@ void GAME_EXPORT R_BreakModel( const vec3_t pos, const vec3_t size, const vec3_t
|
||||||
vecSpot[1] = pos[1] + COM_RandomFloat( -0.5f, 0.5f ) * size[1];
|
vecSpot[1] = pos[1] + COM_RandomFloat( -0.5f, 0.5f ) * size[1];
|
||||||
vecSpot[2] = pos[2] + COM_RandomFloat( -0.5f, 0.5f ) * size[2];
|
vecSpot[2] = pos[2] + COM_RandomFloat( -0.5f, 0.5f ) * size[2];
|
||||||
|
|
||||||
if( CL_PointContents( vecSpot ) != CONTENTS_SOLID )
|
if( PM_CL_PointContents( vecSpot, NULL ) != CONTENTS_SOLID )
|
||||||
break; // valid spot
|
break; // valid spot
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1974,6 +1974,9 @@ void CL_ParseTempEntity( sizebuf_t *msg )
|
||||||
pos[1] = MSG_ReadCoord( &buf );
|
pos[1] = MSG_ReadCoord( &buf );
|
||||||
pos[2] = MSG_ReadCoord( &buf );
|
pos[2] = MSG_ReadCoord( &buf );
|
||||||
R_BlobExplosion( pos );
|
R_BlobExplosion( pos );
|
||||||
|
|
||||||
|
hSound = S_RegisterSound( cl_explode_sounds[0] );
|
||||||
|
S_StartSound( pos, -1, CHAN_AUTO, hSound, VOL_NORM, 1.0f, PITCH_NORM, 0 );
|
||||||
break;
|
break;
|
||||||
case TE_SMOKE:
|
case TE_SMOKE:
|
||||||
pos[0] = MSG_ReadCoord( &buf );
|
pos[0] = MSG_ReadCoord( &buf );
|
||||||
|
@ -2027,7 +2030,7 @@ void CL_ParseTempEntity( sizebuf_t *msg )
|
||||||
dl->decay = 300;
|
dl->decay = 300;
|
||||||
|
|
||||||
hSound = S_RegisterSound( cl_explode_sounds[0] );
|
hSound = S_RegisterSound( cl_explode_sounds[0] );
|
||||||
S_StartSound( pos, 0, CHAN_STATIC, hSound, VOL_NORM, 0.6f, PITCH_NORM, 0 );
|
S_StartSound( pos, -1, CHAN_AUTO, hSound, VOL_NORM, 0.6f, PITCH_NORM, 0 );
|
||||||
break;
|
break;
|
||||||
case TE_BSPDECAL:
|
case TE_BSPDECAL:
|
||||||
case TE_DECAL:
|
case TE_DECAL:
|
||||||
|
@ -2928,7 +2931,13 @@ void CL_PlayerDecal( int playernum, int customIndex, int entityIndex, float *pos
|
||||||
{
|
{
|
||||||
if( !pCust->nUserData1 )
|
if( !pCust->nUserData1 )
|
||||||
{
|
{
|
||||||
|
int sprayTextureIndex;
|
||||||
const char *decalname = va( "player%dlogo%d", playernum, customIndex );
|
const char *decalname = va( "player%dlogo%d", playernum, customIndex );
|
||||||
|
sprayTextureIndex = ref.dllFuncs.GL_FindTexture( decalname );
|
||||||
|
if( sprayTextureIndex != 0 )
|
||||||
|
{
|
||||||
|
ref.dllFuncs.GL_FreeTexture( sprayTextureIndex );
|
||||||
|
}
|
||||||
pCust->nUserData1 = GL_LoadTextureInternal( decalname, pCust->pInfo, TF_DECAL );
|
pCust->nUserData1 = GL_LoadTextureInternal( decalname, pCust->pInfo, TF_DECAL );
|
||||||
}
|
}
|
||||||
textureIndex = pCust->nUserData1;
|
textureIndex = pCust->nUserData1;
|
||||||
|
|
|
@ -209,7 +209,7 @@ qboolean SCR_PlayCinematic( const char *arg )
|
||||||
|
|
||||||
if( FS_FileExists( arg, false ) && !fullpath )
|
if( FS_FileExists( arg, false ) && !fullpath )
|
||||||
{
|
{
|
||||||
Con_Printf( S_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", arg );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -286,9 +286,6 @@ qboolean V_PreRender( void )
|
||||||
if( !ref.initialized )
|
if( !ref.initialized )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if( host.status == HOST_NOFOCUS )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if( host.status == HOST_SLEEP )
|
if( host.status == HOST_SLEEP )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ GNU General Public License for more details.
|
||||||
#include "net_api.h"
|
#include "net_api.h"
|
||||||
#include "world.h"
|
#include "world.h"
|
||||||
#include "ref_common.h"
|
#include "ref_common.h"
|
||||||
|
#include "voice.h"
|
||||||
|
|
||||||
// client sprite types
|
// client sprite types
|
||||||
#define SPR_CLIENT 0 // client sprite for temp-entities or user-textures
|
#define SPR_CLIENT 0 // client sprite for temp-entities or user-textures
|
||||||
|
@ -107,7 +108,6 @@ extern int CL_UPDATE_BACKUP;
|
||||||
#define MIN_UPDATERATE 10.0f
|
#define MIN_UPDATERATE 10.0f
|
||||||
#define MAX_UPDATERATE 102.0f
|
#define MAX_UPDATERATE 102.0f
|
||||||
|
|
||||||
#define MIN_EX_INTERP 0.005f
|
|
||||||
#define MAX_EX_INTERP 0.1f
|
#define MAX_EX_INTERP 0.1f
|
||||||
|
|
||||||
#define CL_MIN_RESEND_TIME 1.5f // mininum time gap (in seconds) before a subsequent connection request is sent.
|
#define CL_MIN_RESEND_TIME 1.5f // mininum time gap (in seconds) before a subsequent connection request is sent.
|
||||||
|
@ -138,7 +138,7 @@ typedef struct
|
||||||
int light_level;
|
int light_level;
|
||||||
int waterlevel;
|
int waterlevel;
|
||||||
int usehull;
|
int usehull;
|
||||||
int moving;
|
qboolean moving;
|
||||||
int pushmsec;
|
int pushmsec;
|
||||||
int weapons;
|
int weapons;
|
||||||
float maxspeed;
|
float maxspeed;
|
||||||
|
@ -210,7 +210,7 @@ typedef struct
|
||||||
// a lerp point for other data
|
// a lerp point for other data
|
||||||
double oldtime; // previous cl.time, time-oldtime is used
|
double oldtime; // previous cl.time, time-oldtime is used
|
||||||
// to decay light values and smooth step ups
|
// to decay light values and smooth step ups
|
||||||
float timedelta; // floating delta between two updates
|
double timedelta; // floating delta between two updates
|
||||||
|
|
||||||
char serverinfo[MAX_SERVERINFO_STRING];
|
char serverinfo[MAX_SERVERINFO_STRING];
|
||||||
player_info_t players[MAX_CLIENTS]; // collected info about all other players include himself
|
player_info_t players[MAX_CLIENTS]; // collected info about all other players include himself
|
||||||
|
@ -321,29 +321,43 @@ typedef struct
|
||||||
#define FONT_FIXED 0
|
#define FONT_FIXED 0
|
||||||
#define FONT_VARIABLE 1
|
#define FONT_VARIABLE 1
|
||||||
|
|
||||||
|
#define FONT_DRAW_HUD BIT( 0 ) // pass to drawing function to apply hud_scale
|
||||||
|
#define FONT_DRAW_UTF8 BIT( 1 ) // call UtfProcessChar
|
||||||
|
#define FONT_DRAW_FORCECOL BIT( 2 ) // ignore colorcodes
|
||||||
|
#define FONT_DRAW_NORENDERMODE BIT( 3 ) // ignore font's default rendermode
|
||||||
|
#define FONT_DRAW_NOLF BIT( 4 ) // ignore \n
|
||||||
|
#define FONT_DRAW_RESETCOLORONLF BIT( 5 ) // yet another flag to simulate consecutive Con_DrawString calls...
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
int hFontTexture; // handle to texture
|
int hFontTexture; // handle to texture
|
||||||
wrect_t fontRc[256]; // rectangles
|
wrect_t fontRc[256]; // tex coords
|
||||||
byte charWidths[256];
|
float scale; // scale factor
|
||||||
int charHeight;
|
byte charWidths[256]; // scaled widths
|
||||||
int type;
|
int charHeight; // scaled height
|
||||||
|
int type; // fixed width font or variable
|
||||||
|
int rendermode; // default rendermode
|
||||||
|
qboolean nearest; // nearest filtering enabled
|
||||||
qboolean valid; // all rectangles are valid
|
qboolean valid; // all rectangles are valid
|
||||||
} cl_font_t;
|
} cl_font_t;
|
||||||
|
|
||||||
|
typedef struct scissor_state_s
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
qboolean test;
|
||||||
|
} scissor_state_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
// scissor test
|
||||||
|
scissor_state_t scissor;
|
||||||
|
|
||||||
// temp handle
|
// temp handle
|
||||||
const model_t *pSprite; // pointer to current SpriteTexture
|
const model_t *pSprite; // pointer to current SpriteTexture
|
||||||
|
|
||||||
// scissor test
|
|
||||||
int scissor_x;
|
|
||||||
int scissor_y;
|
|
||||||
int scissor_width;
|
|
||||||
int scissor_height;
|
|
||||||
qboolean scissor_test;
|
|
||||||
qboolean adjust_size; // allow to adjust scale for fonts
|
|
||||||
|
|
||||||
int renderMode; // override kRenderMode from TriAPI
|
int renderMode; // override kRenderMode from TriAPI
|
||||||
TRICULLSTYLE cullMode; // override CULL FACE from TriAPI
|
TRICULLSTYLE cullMode; // override CULL FACE from TriAPI
|
||||||
|
|
||||||
|
@ -370,14 +384,10 @@ typedef struct cl_predicted_player_s
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
int gl_texturenum; // this is a real texnum
|
|
||||||
|
|
||||||
// scissor test
|
// scissor test
|
||||||
int scissor_x;
|
scissor_state_t scissor;
|
||||||
int scissor_y;
|
|
||||||
int scissor_width;
|
int gl_texturenum; // this is a real texnum
|
||||||
int scissor_height;
|
|
||||||
qboolean scissor_test;
|
|
||||||
|
|
||||||
// holds text color
|
// holds text color
|
||||||
rgba_t textColor;
|
rgba_t textColor;
|
||||||
|
@ -671,6 +681,7 @@ extern convar_t *cl_levelshot_name;
|
||||||
extern convar_t *cl_draw_beams;
|
extern convar_t *cl_draw_beams;
|
||||||
extern convar_t *cl_clockreset;
|
extern convar_t *cl_clockreset;
|
||||||
extern convar_t *cl_fixtimerate;
|
extern convar_t *cl_fixtimerate;
|
||||||
|
extern convar_t *hud_fontscale;
|
||||||
extern convar_t *hud_scale;
|
extern convar_t *hud_scale;
|
||||||
extern convar_t *gl_showtextures;
|
extern convar_t *gl_showtextures;
|
||||||
extern convar_t *cl_bmodelinterp;
|
extern convar_t *cl_bmodelinterp;
|
||||||
|
@ -753,6 +764,7 @@ int CL_IsDevOverviewMode( void );
|
||||||
void CL_PingServers_f( void );
|
void CL_PingServers_f( void );
|
||||||
void CL_SignonReply( void );
|
void CL_SignonReply( void );
|
||||||
void CL_ClearState( void );
|
void CL_ClearState( void );
|
||||||
|
size_t CL_BuildMasterServerScanRequest( char *buf, size_t size, qboolean nat );
|
||||||
|
|
||||||
//
|
//
|
||||||
// cl_demo.c
|
// cl_demo.c
|
||||||
|
@ -794,6 +806,19 @@ void CL_ResetEvent( event_info_t *ei );
|
||||||
word CL_EventIndex( const char *name );
|
word CL_EventIndex( const char *name );
|
||||||
void CL_FireEvents( void );
|
void CL_FireEvents( void );
|
||||||
|
|
||||||
|
//
|
||||||
|
// cl_font.c
|
||||||
|
//
|
||||||
|
qboolean CL_FixedFont( cl_font_t *font );
|
||||||
|
qboolean Con_LoadFixedWidthFont( const char *fontname, cl_font_t *font, float scale, int rendermode, uint texFlags );
|
||||||
|
qboolean Con_LoadVariableWidthFont( const char *fontname, cl_font_t *font, float scale, int rendermode, uint texFlags );
|
||||||
|
void CL_FreeFont( cl_font_t *font );
|
||||||
|
int CL_DrawCharacter( float x, float y, int number, rgba_t color, cl_font_t *font, int flags );
|
||||||
|
int CL_DrawString( float x, float y, const char *s, rgba_t color, cl_font_t *font, int flags );
|
||||||
|
void CL_DrawCharacterLen( cl_font_t *font, int number, int *width, int *height );
|
||||||
|
void CL_DrawStringLen( cl_font_t *font, const char *s, int *width, int *height, int flags );
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// cl_game.c
|
// cl_game.c
|
||||||
//
|
//
|
||||||
|
@ -823,11 +848,15 @@ model_t *CL_LoadClientSprite( const char *filename );
|
||||||
model_t *CL_LoadModel( const char *modelname, int *index );
|
model_t *CL_LoadModel( const char *modelname, int *index );
|
||||||
HSPRITE EXPORT pfnSPR_Load( const char *szPicName );
|
HSPRITE EXPORT pfnSPR_Load( const char *szPicName );
|
||||||
HSPRITE pfnSPR_LoadExt( const char *szPicName, uint texFlags );
|
HSPRITE pfnSPR_LoadExt( const char *szPicName, uint texFlags );
|
||||||
void PicAdjustSize( float *x, float *y, float *w, float *h );
|
void SPR_AdjustSize( float *x, float *y, float *w, float *h );
|
||||||
|
void SPR_AdjustTexCoords( float width, float height, float *s1, float *t1, float *s2, float *t2 );
|
||||||
int CL_GetScreenInfo( SCREENINFO *pscrinfo );
|
int CL_GetScreenInfo( SCREENINFO *pscrinfo );
|
||||||
void CL_FillRGBA( int x, int y, int width, int height, int r, int g, int b, int a );
|
void CL_FillRGBA( int x, int y, int width, int height, int r, int g, int b, int a );
|
||||||
void CL_PlayerTrace( float *start, float *end, int traceFlags, int ignore_pe, pmtrace_t *tr );
|
void CL_PlayerTrace( float *start, float *end, int traceFlags, int ignore_pe, pmtrace_t *tr );
|
||||||
void CL_PlayerTraceExt( float *start, float *end, int traceFlags, int (*pfnIgnore)( physent_t *pe ), pmtrace_t *tr );
|
void CL_PlayerTraceExt( float *start, float *end, int traceFlags, int (*pfnIgnore)( physent_t *pe ), pmtrace_t *tr );
|
||||||
|
pmtrace_t *PM_CL_TraceLine( float *start, float *end, int flags, int usehull, int ignore_pe );
|
||||||
|
const char *PM_CL_TraceTexture( int ground, float *vstart, float *vend );
|
||||||
|
int PM_CL_PointContents( const float *p, int *truecontents );
|
||||||
void CL_SetTraceHull( int hull );
|
void CL_SetTraceHull( int hull );
|
||||||
void CL_GetMousePosition( int *mx, int *my ); // TODO: move to input
|
void CL_GetMousePosition( int *mx, int *my ); // TODO: move to input
|
||||||
cl_entity_t* CL_GetViewModel( void );
|
cl_entity_t* CL_GetViewModel( void );
|
||||||
|
@ -835,6 +864,9 @@ void pfnGetScreenFade( struct screenfade_s *fade );
|
||||||
physent_t *pfnGetPhysent( int idx );
|
physent_t *pfnGetPhysent( int idx );
|
||||||
struct msurface_s *pfnTraceSurface( int ground, float *vstart, float *vend );
|
struct msurface_s *pfnTraceSurface( int ground, float *vstart, float *vend );
|
||||||
movevars_t *pfnGetMoveVars( void );
|
movevars_t *pfnGetMoveVars( void );
|
||||||
|
void CL_EnableScissor( scissor_state_t *scissor, int x, int y, int width, int height );
|
||||||
|
void CL_DisableScissor( scissor_state_t *scissor );
|
||||||
|
qboolean CL_Scissor( const scissor_state_t *scissor, float *x, float *y, float *width, float *height, float *u0, float *v0, float *u1, float *v1 );
|
||||||
|
|
||||||
_inline cl_entity_t *CL_EDICT_NUM( int n )
|
_inline cl_entity_t *CL_EDICT_NUM( int n )
|
||||||
{
|
{
|
||||||
|
@ -910,10 +942,8 @@ void CL_PredictMovement( qboolean repredicting );
|
||||||
void CL_CheckPredictionError( void );
|
void CL_CheckPredictionError( void );
|
||||||
qboolean CL_IsPredicted( void );
|
qboolean CL_IsPredicted( void );
|
||||||
int CL_TruePointContents( const vec3_t p );
|
int CL_TruePointContents( const vec3_t p );
|
||||||
int CL_PointContents( const vec3_t p );
|
|
||||||
int CL_WaterEntity( const float *rgflPos );
|
int CL_WaterEntity( const float *rgflPos );
|
||||||
cl_entity_t *CL_GetWaterEntity( const float *rgflPos );
|
cl_entity_t *CL_GetWaterEntity( const float *rgflPos );
|
||||||
void CL_SetupPMove( playermove_t *pmove, local_state_t *from, usercmd_t *ucmd, qboolean runfuncs, double time );
|
|
||||||
int CL_TestLine( const vec3_t start, const vec3_t end, int flags );
|
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_VisTraceLine( vec3_t start, vec3_t end, int flags );
|
||||||
pmtrace_t CL_TraceLine( vec3_t start, vec3_t end, int flags );
|
pmtrace_t CL_TraceLine( vec3_t start, vec3_t end, int flags );
|
||||||
|
@ -922,7 +952,6 @@ void CL_PopTraceBounds( void );
|
||||||
void CL_MoveSpectatorCamera( void );
|
void CL_MoveSpectatorCamera( void );
|
||||||
void CL_SetLastUpdate( void );
|
void CL_SetLastUpdate( void );
|
||||||
void CL_RedoPrediction( void );
|
void CL_RedoPrediction( void );
|
||||||
void CL_ClearPhysEnts( void );
|
|
||||||
void CL_PushPMStates( void );
|
void CL_PushPMStates( void );
|
||||||
void CL_PopPMStates( void );
|
void CL_PopPMStates( void );
|
||||||
void CL_SetUpPlayerPrediction( int dopred, int bIncludeLocalClient );
|
void CL_SetUpPlayerPrediction( int dopred, int bIncludeLocalClient );
|
||||||
|
@ -963,7 +992,7 @@ void CL_ClearAllRemaps( void );
|
||||||
// cl_render.c
|
// cl_render.c
|
||||||
//
|
//
|
||||||
qboolean R_InitRenderAPI( void );
|
qboolean R_InitRenderAPI( void );
|
||||||
int CL_RenderGetParm( const int parm, const int arg, const qboolean checkRef );
|
intptr_t CL_RenderGetParm( const int parm, const int arg, const qboolean checkRef );
|
||||||
lightstyle_t *CL_GetLightStyle( int number );
|
lightstyle_t *CL_GetLightStyle( int number );
|
||||||
int R_FatPVS( const vec3_t org, float radius, byte *visbuffer, qboolean merge, qboolean fullvis );
|
int R_FatPVS( const vec3_t org, float radius, byte *visbuffer, qboolean merge, qboolean fullvis );
|
||||||
const ref_overview_t *GL_GetOverviewParms( void );
|
const ref_overview_t *GL_GetOverviewParms( void );
|
||||||
|
@ -1027,13 +1056,13 @@ int Con_UtfProcessChar( int in );
|
||||||
int Con_UtfProcessCharForce( int in );
|
int Con_UtfProcessCharForce( int in );
|
||||||
int Con_UtfMoveLeft( char *str, int pos );
|
int Con_UtfMoveLeft( char *str, int pos );
|
||||||
int Con_UtfMoveRight( char *str, int pos, int length );
|
int Con_UtfMoveRight( char *str, int pos, int length );
|
||||||
void Con_DrawStringLen( const char *pText, int *length, int *height );
|
|
||||||
int Con_DrawString( int x, int y, const char *string, rgba_t setColor );
|
|
||||||
int Con_DrawCharacter( int x, int y, int number, rgba_t color );
|
|
||||||
void Con_DrawCharacterLen( int number, int *width, int *height );
|
|
||||||
void Con_DefaultColor( int r, int g, int b );
|
void Con_DefaultColor( int r, int g, int b );
|
||||||
void Con_InvalidateFonts( void );
|
void Con_InvalidateFonts( void );
|
||||||
void Con_SetFont( int fontNum );
|
cl_font_t *Con_GetCurFont( void );
|
||||||
|
cl_font_t *Con_GetFont( int num );
|
||||||
|
void Con_DrawCharacterLen( int number, int *width, int *height );
|
||||||
|
int Con_DrawString( int x, int y, const char *string, rgba_t setColor ); // legacy, use cl_font.c
|
||||||
|
void GAME_EXPORT Con_DrawStringLen( const char *pText, int *length, int *height ); // legacy, use cl_font.c
|
||||||
void Con_CharEvent( int key );
|
void Con_CharEvent( int key );
|
||||||
void Con_RestoreFont( void );
|
void Con_RestoreFont( void );
|
||||||
void Key_Console( int key );
|
void Key_Console( int key );
|
||||||
|
|
|
@ -116,7 +116,7 @@ typedef struct
|
||||||
|
|
||||||
// console fonts
|
// console fonts
|
||||||
cl_font_t chars[CON_NUMFONTS];// fonts.wad/font1.fnt
|
cl_font_t chars[CON_NUMFONTS];// fonts.wad/font1.fnt
|
||||||
cl_font_t *curFont, *lastUsedFont;
|
cl_font_t *curFont;
|
||||||
|
|
||||||
// console input
|
// console input
|
||||||
field_t input;
|
field_t input;
|
||||||
|
@ -555,89 +555,9 @@ Con_FixedFont
|
||||||
*/
|
*/
|
||||||
qboolean Con_FixedFont( void )
|
qboolean Con_FixedFont( void )
|
||||||
{
|
{
|
||||||
if( con.curFont && con.curFont->valid && con.curFont->type == FONT_FIXED )
|
return CL_FixedFont( con.curFont );
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static qboolean Con_LoadFixedWidthFont( const char *fontname, cl_font_t *font )
|
|
||||||
{
|
|
||||||
int i, fontWidth;
|
|
||||||
|
|
||||||
if( font->valid )
|
|
||||||
return true; // already loaded
|
|
||||||
|
|
||||||
if( !FS_FileExists( fontname, false ))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// keep source to print directly into conback image
|
|
||||||
font->hFontTexture = ref.dllFuncs.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 * con_fontscale->value;
|
|
||||||
font->type = FONT_FIXED;
|
|
||||||
|
|
||||||
// build fixed rectangles
|
|
||||||
for( i = 0; i < 256; i++ )
|
|
||||||
{
|
|
||||||
font->fontRc[i].left = (i * (fontWidth / 16)) % fontWidth;
|
|
||||||
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 * con_fontscale->value;
|
|
||||||
}
|
|
||||||
font->valid = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static qboolean Con_LoadVariableWidthFont( const char *fontname, cl_font_t *font )
|
|
||||||
{
|
|
||||||
int i, fontWidth;
|
|
||||||
byte *buffer;
|
|
||||||
fs_offset_t length;
|
|
||||||
qfont_t *src;
|
|
||||||
|
|
||||||
if( font->valid )
|
|
||||||
return true; // already loaded
|
|
||||||
|
|
||||||
if( !FS_FileExists( fontname, false ))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
font->hFontTexture = ref.dllFuncs.GL_LoadTexture( fontname, NULL, 0, TF_FONT|TF_NEAREST );
|
|
||||||
R_GetTextureParms( &fontWidth, NULL, font->hFontTexture );
|
|
||||||
|
|
||||||
// setup consolefont
|
|
||||||
if( font->hFontTexture && fontWidth != 0 )
|
|
||||||
{
|
|
||||||
// half-life font with variable chars witdh
|
|
||||||
buffer = FS_LoadFile( fontname, &length, false );
|
|
||||||
|
|
||||||
if( buffer && length >= sizeof( qfont_t ))
|
|
||||||
{
|
|
||||||
src = (qfont_t *)buffer;
|
|
||||||
font->charHeight = src->rowheight * con_fontscale->value;
|
|
||||||
font->type = FONT_VARIABLE;
|
|
||||||
|
|
||||||
// build rectangles
|
|
||||||
for( i = 0; i < 256; i++ )
|
|
||||||
{
|
|
||||||
font->fontRc[i].left = (word)src->fontinfo[i].startoffset % fontWidth;
|
|
||||||
font->fontRc[i].right = font->fontRc[i].left + src->fontinfo[i].charwidth;
|
|
||||||
font->fontRc[i].top = (word)src->fontinfo[i].startoffset / fontWidth;
|
|
||||||
font->fontRc[i].bottom = font->fontRc[i].top + src->rowheight;
|
|
||||||
font->charWidths[i] = src->fontinfo[i].charwidth * con_fontscale->value;
|
|
||||||
}
|
|
||||||
font->valid = true;
|
|
||||||
}
|
|
||||||
if( buffer ) Mem_Free( buffer );
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
================
|
================
|
||||||
|
@ -648,32 +568,46 @@ INTERNAL RESOURCE
|
||||||
*/
|
*/
|
||||||
static void Con_LoadConsoleFont( int fontNumber, cl_font_t *font )
|
static void Con_LoadConsoleFont( int fontNumber, cl_font_t *font )
|
||||||
{
|
{
|
||||||
const char *path = NULL;
|
qboolean success = false;
|
||||||
dword crc = 0;
|
float scale = con_fontscale->value;
|
||||||
|
|
||||||
if( font->valid ) return; // already loaded
|
if( font->valid )
|
||||||
|
return; // already loaded
|
||||||
|
|
||||||
|
// loading conchars
|
||||||
|
if( Sys_CheckParm( "-oldfont" ))
|
||||||
|
{
|
||||||
|
success = Con_LoadVariableWidthFont( "gfx/conchars.fnt", font, scale, kRenderTransTexture, TF_FONT|TF_NEAREST );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string path;
|
||||||
|
dword crc = 0;
|
||||||
|
|
||||||
// replace default fonts.wad textures by current charset's font
|
// replace default fonts.wad textures by current charset's font
|
||||||
if( !CRC32_File( &crc, "fonts.wad" ) || crc == 0x3c0a0029 )
|
if( !CRC32_File( &crc, "fonts.wad" ) || crc == 0x3c0a0029 )
|
||||||
{
|
{
|
||||||
const char *path2 = va("font%i_%s.fnt", fontNumber, Cvar_VariableString( "con_charset" ) );
|
if( Q_snprintf( path, sizeof( path ),
|
||||||
if( FS_FileExists( path2, false ) )
|
"font%i_%s.fnt", fontNumber, Cvar_VariableString( "con_charset" )) > 0 )
|
||||||
path = path2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// loading conchars
|
|
||||||
if( Sys_CheckParm( "-oldfont" ))
|
|
||||||
Con_LoadVariableWidthFont( "gfx/conchars.fnt", font );
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
if( !path )
|
success = Con_LoadVariableWidthFont( path, font, scale, kRenderTransTexture, TF_FONT|TF_NEAREST );
|
||||||
path = va( "fonts/font%i", fontNumber );
|
}
|
||||||
|
|
||||||
Con_LoadVariableWidthFont( path, font );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( !success )
|
||||||
|
{
|
||||||
|
Q_snprintf( path, sizeof( path ), "fonts/font%i", fontNumber );
|
||||||
|
success = Con_LoadVariableWidthFont( path, font, scale, kRenderTransTexture, TF_FONT|TF_NEAREST );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !success )
|
||||||
|
{
|
||||||
// quake fixed font as fallback
|
// quake fixed font as fallback
|
||||||
if( !font->valid ) Con_LoadFixedWidthFont( "gfx/conchars", font );
|
// keep source to print directly into conback image
|
||||||
|
if( !Con_LoadFixedWidthFont( "gfx/conchars", font, scale, kRenderTransTexture, TF_FONT|TF_KEEP_SOURCE ))
|
||||||
|
Con_DPrintf( S_ERROR "failed to load console font\n" );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -702,7 +636,7 @@ static void Con_LoadConchars( void )
|
||||||
fontSize = CON_NUMFONTS - 1;
|
fontSize = CON_NUMFONTS - 1;
|
||||||
|
|
||||||
// sets the current font
|
// sets the current font
|
||||||
con.lastUsedFont = con.curFont = &con.chars[fontSize];
|
con.curFont = &con.chars[fontSize];
|
||||||
}
|
}
|
||||||
|
|
||||||
// CP1251 table
|
// CP1251 table
|
||||||
|
@ -875,129 +809,25 @@ static void Con_DrawCharToConback( int num, const byte *conchars, byte *dest )
|
||||||
|
|
||||||
/*
|
/*
|
||||||
====================
|
====================
|
||||||
Con_TextAdjustSize
|
Con_GetFont
|
||||||
|
|
||||||
draw charcters routine
|
|
||||||
====================
|
====================
|
||||||
*/
|
*/
|
||||||
static void Con_TextAdjustSize( int *x, int *y, int *w, int *h )
|
cl_font_t *Con_GetFont( int num )
|
||||||
{
|
{
|
||||||
float xscale, yscale;
|
num = bound( 0, num, CON_NUMFONTS - 1 );
|
||||||
|
return &con.chars[num];
|
||||||
if( !x && !y && !w && !h ) return;
|
|
||||||
|
|
||||||
// scale for screen sizes
|
|
||||||
xscale = (float)refState.width / (float)clgame.scrInfo.iWidth;
|
|
||||||
yscale = (float)refState.height / (float)clgame.scrInfo.iHeight;
|
|
||||||
|
|
||||||
if( x ) *x *= xscale;
|
|
||||||
if( y ) *y *= yscale;
|
|
||||||
if( w ) *w *= xscale;
|
|
||||||
if( h ) *h *= yscale;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
====================
|
====================
|
||||||
Con_DrawGenericChar
|
Con_GetCurFont
|
||||||
|
|
||||||
draw console single character
|
|
||||||
====================
|
====================
|
||||||
*/
|
*/
|
||||||
static int Con_DrawGenericChar( int x, int y, int number, rgba_t color )
|
cl_font_t *Con_GetCurFont( void )
|
||||||
{
|
{
|
||||||
int width, height;
|
return con.curFont;
|
||||||
float s1, t1, s2, t2;
|
|
||||||
wrect_t *rc;
|
|
||||||
|
|
||||||
number &= 255;
|
|
||||||
|
|
||||||
if( !con.curFont || !con.curFont->valid )
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
number = Con_UtfProcessChar(number);
|
|
||||||
if( !number )
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if( y < -con.curFont->charHeight )
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
rc = &con.curFont->fontRc[number];
|
|
||||||
R_GetTextureParms( &width, &height, con.curFont->hFontTexture );
|
|
||||||
|
|
||||||
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 || REF_GET_PARM( PARM_TEX_GLFORMAT, con.curFont->hFontTexture ) == 0x8045 ) // GL_LUMINANCE8_ALPHA8
|
|
||||||
ref.dllFuncs.Color4ub( color[0], color[1], color[2], color[3] );
|
|
||||||
else ref.dllFuncs.Color4ub( 255, 255, 255, color[3] );
|
|
||||||
|
|
||||||
// calc rectangle
|
|
||||||
s1 = (float)rc->left / width;
|
|
||||||
t1 = (float)rc->top / height;
|
|
||||||
s2 = (float)rc->right / width;
|
|
||||||
t2 = (float)rc->bottom / height;
|
|
||||||
width = ( rc->right - rc->left ) * con_fontscale->value;
|
|
||||||
height = ( rc->bottom - rc->top ) * con_fontscale->value;
|
|
||||||
|
|
||||||
if( clgame.ds.adjust_size )
|
|
||||||
Con_TextAdjustSize( &x, &y, &width, &height );
|
|
||||||
ref.dllFuncs.R_DrawStretchPic( x, y, width, height, s1, t1, s2, t2, con.curFont->hFontTexture );
|
|
||||||
ref.dllFuncs.Color4ub( 255, 255, 255, 255 ); // don't forget reset color
|
|
||||||
|
|
||||||
return con.curFont->charWidths[number];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
====================
|
|
||||||
Con_SetFont
|
|
||||||
|
|
||||||
choose font size
|
|
||||||
====================
|
|
||||||
*/
|
|
||||||
void Con_SetFont( int fontNum )
|
|
||||||
{
|
|
||||||
fontNum = bound( 0, fontNum, CON_NUMFONTS - 1 );
|
|
||||||
con.curFont = &con.chars[fontNum];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
====================
|
|
||||||
Con_RestoreFont
|
|
||||||
|
|
||||||
restore auto-selected console font
|
|
||||||
(that based on screen resolution)
|
|
||||||
====================
|
|
||||||
*/
|
|
||||||
void Con_RestoreFont( void )
|
|
||||||
{
|
|
||||||
con.curFont = con.lastUsedFont;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
====================
|
|
||||||
Con_DrawCharacter
|
|
||||||
|
|
||||||
client version of routine
|
|
||||||
====================
|
|
||||||
*/
|
|
||||||
int Con_DrawCharacter( int x, int y, int number, rgba_t color )
|
|
||||||
{
|
|
||||||
ref.dllFuncs.GL_SetRenderMode( kRenderTransTexture );
|
|
||||||
return Con_DrawGenericChar( x, y, number, color );
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
====================
|
|
||||||
Con_DrawCharacterLen
|
|
||||||
|
|
||||||
returns character sizes in screen pixels
|
|
||||||
====================
|
|
||||||
*/
|
|
||||||
void Con_DrawCharacterLen( int number, int *width, int *height )
|
|
||||||
{
|
|
||||||
if( width && con.curFont ) *width = con.curFont->charWidths[number];
|
|
||||||
if( height && con.curFont ) *height = con.curFont->charHeight;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1009,105 +839,7 @@ compute string width and height in screen pixels
|
||||||
*/
|
*/
|
||||||
void GAME_EXPORT Con_DrawStringLen( const char *pText, int *length, int *height )
|
void GAME_EXPORT Con_DrawStringLen( const char *pText, int *length, int *height )
|
||||||
{
|
{
|
||||||
int curLength = 0;
|
return CL_DrawStringLen( con.curFont, pText, length, height, FONT_DRAW_UTF8 );
|
||||||
|
|
||||||
if( !con.curFont )
|
|
||||||
return;
|
|
||||||
if( height )
|
|
||||||
*height = con.curFont->charHeight;
|
|
||||||
if (!length)
|
|
||||||
return;
|
|
||||||
|
|
||||||
*length = 0;
|
|
||||||
|
|
||||||
while( *pText )
|
|
||||||
{
|
|
||||||
byte c = *pText;
|
|
||||||
|
|
||||||
if( *pText == '\n' )
|
|
||||||
{
|
|
||||||
pText++;
|
|
||||||
curLength = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// skip color strings they are not drawing
|
|
||||||
if( IsColorString( pText ))
|
|
||||||
{
|
|
||||||
pText += 2;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Convert to unicode
|
|
||||||
c = Con_UtfProcessChar( c );
|
|
||||||
|
|
||||||
if( c )
|
|
||||||
curLength += con.curFont->charWidths[c];
|
|
||||||
|
|
||||||
pText++;
|
|
||||||
|
|
||||||
if( curLength > *length )
|
|
||||||
*length = curLength;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
==================
|
|
||||||
Con_DrawString
|
|
||||||
|
|
||||||
Draws a multi-colored string, optionally forcing
|
|
||||||
to a fixed color.
|
|
||||||
==================
|
|
||||||
*/
|
|
||||||
int Con_DrawGenericString( int x, int y, const char *string, rgba_t setColor, qboolean forceColor, int hideChar )
|
|
||||||
{
|
|
||||||
rgba_t color;
|
|
||||||
int drawLen = 0;
|
|
||||||
int numDraws = 0;
|
|
||||||
const char *s;
|
|
||||||
|
|
||||||
if( !con.curFont ) return 0; // no font set
|
|
||||||
|
|
||||||
Con_UtfProcessChar( 0 );
|
|
||||||
|
|
||||||
// draw the colored text
|
|
||||||
memcpy( color, setColor, sizeof( color ));
|
|
||||||
s = string;
|
|
||||||
|
|
||||||
while( *s )
|
|
||||||
{
|
|
||||||
if( *s == '\n' )
|
|
||||||
{
|
|
||||||
s++;
|
|
||||||
if( !*s ) break; // at end the string
|
|
||||||
drawLen = 0; // begin new row
|
|
||||||
y += con.curFont->charHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( IsColorString( s ))
|
|
||||||
{
|
|
||||||
if( !forceColor )
|
|
||||||
{
|
|
||||||
memcpy( color, g_color_table[ColorIndex(*(s+1))], sizeof( color ));
|
|
||||||
color[3] = setColor[3];
|
|
||||||
}
|
|
||||||
|
|
||||||
s += 2;
|
|
||||||
numDraws++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// hide char for overstrike mode
|
|
||||||
if( hideChar == numDraws )
|
|
||||||
drawLen += con.curFont->charWidths[*s];
|
|
||||||
else drawLen += Con_DrawCharacter( x + drawLen, y, *s, color );
|
|
||||||
|
|
||||||
numDraws++;
|
|
||||||
s++;
|
|
||||||
}
|
|
||||||
|
|
||||||
ref.dllFuncs.Color4ub( 255, 255, 255, 255 );
|
|
||||||
return drawLen;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1119,10 +851,9 @@ client version of routine
|
||||||
*/
|
*/
|
||||||
int Con_DrawString( int x, int y, const char *string, rgba_t setColor )
|
int Con_DrawString( int x, int y, const char *string, rgba_t setColor )
|
||||||
{
|
{
|
||||||
return Con_DrawGenericString( x, y, string, setColor, false, -1 );
|
return CL_DrawString( x, y, string, setColor, con.curFont, FONT_DRAW_UTF8 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
================
|
================
|
||||||
Con_Init
|
Con_Init
|
||||||
|
@ -1499,7 +1230,7 @@ void Field_KeyDownEvent( field_t *edit, int key )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( key == K_BACKSPACE )
|
if( key == K_BACKSPACE || key == K_X_BUTTON )
|
||||||
{
|
{
|
||||||
if( edit->cursor > 0 )
|
if( edit->cursor > 0 )
|
||||||
{
|
{
|
||||||
|
@ -1511,7 +1242,7 @@ void Field_KeyDownEvent( field_t *edit, int key )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( key == K_RIGHTARROW )
|
if( key == K_RIGHTARROW || key == K_DPAD_RIGHT )
|
||||||
{
|
{
|
||||||
if( edit->cursor < len ) edit->cursor = Con_UtfMoveRight( edit->buffer, edit->cursor, edit->widthInChars );
|
if( edit->cursor < len ) edit->cursor = Con_UtfMoveRight( edit->buffer, edit->cursor, edit->widthInChars );
|
||||||
if( edit->cursor >= edit->scroll + edit->widthInChars && edit->cursor <= len )
|
if( edit->cursor >= edit->scroll + edit->widthInChars && edit->cursor <= len )
|
||||||
|
@ -1519,7 +1250,7 @@ void Field_KeyDownEvent( field_t *edit, int key )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( key == K_LEFTARROW )
|
if( key == K_LEFTARROW || key == K_DPAD_LEFT )
|
||||||
{
|
{
|
||||||
if( edit->cursor > 0 ) edit->cursor = Con_UtfMoveLeft( edit->buffer, edit->cursor );
|
if( edit->cursor > 0 ) edit->cursor = Con_UtfMoveLeft( edit->buffer, edit->cursor );
|
||||||
if( edit->cursor < edit->scroll ) edit->scroll--;
|
if( edit->cursor < edit->scroll ) edit->scroll--;
|
||||||
|
@ -1614,7 +1345,7 @@ Field_DrawInputLine
|
||||||
void Field_DrawInputLine( int x, int y, field_t *edit )
|
void Field_DrawInputLine( int x, int y, field_t *edit )
|
||||||
{
|
{
|
||||||
int len, cursorChar;
|
int len, cursorChar;
|
||||||
int drawLen, hideChar = -1;
|
int drawLen;
|
||||||
int prestep, curPos;
|
int prestep, curPos;
|
||||||
char str[MAX_SYSPATH];
|
char str[MAX_SYSPATH];
|
||||||
byte *colorDefault;
|
byte *colorDefault;
|
||||||
|
@ -1651,35 +1382,23 @@ void Field_DrawInputLine( int x, int y, field_t *edit )
|
||||||
// save char for overstrike
|
// save char for overstrike
|
||||||
cursorChar = str[edit->cursor - prestep];
|
cursorChar = str[edit->cursor - prestep];
|
||||||
|
|
||||||
if( host.key_overstrike && cursorChar && !((int)( host.realtime * 4 ) & 1 ))
|
|
||||||
hideChar = edit->cursor - prestep; // skip this char
|
|
||||||
|
|
||||||
// draw it
|
// draw it
|
||||||
Con_DrawGenericString( x, y, str, colorDefault, false, hideChar );
|
CL_DrawString( x, y, str, colorDefault, con.curFont, FONT_DRAW_UTF8 );
|
||||||
|
|
||||||
// draw the cursor
|
// draw the cursor
|
||||||
if((int)( host.realtime * 4 ) & 1 ) return; // off blink
|
if((int)( host.realtime * 4 ) & 1 ) return; // off blink
|
||||||
|
|
||||||
// calc cursor position
|
// calc cursor position
|
||||||
str[edit->cursor - prestep] = 0;
|
str[edit->cursor - prestep] = 0;
|
||||||
Con_DrawStringLen( str, &curPos, NULL );
|
CL_DrawStringLen( con.curFont, str, &curPos, NULL, FONT_DRAW_UTF8 );
|
||||||
Con_UtfProcessChar( 0 );
|
|
||||||
|
|
||||||
if( host.key_overstrike && cursorChar )
|
if( host.key_overstrike )
|
||||||
{
|
{
|
||||||
// overstrike cursor
|
CL_DrawCharacter( x + curPos, y, '|', colorDefault, con.curFont, 0 );
|
||||||
#if 0
|
|
||||||
pglEnable( GL_BLEND );
|
|
||||||
pglDisable( GL_ALPHA_TEST );
|
|
||||||
pglBlendFunc( GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA );
|
|
||||||
pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
|
|
||||||
#endif
|
|
||||||
Con_DrawGenericChar( x + curPos, y, cursorChar, colorDefault );
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Con_UtfProcessChar( 0 );
|
CL_DrawCharacter( x + curPos, y, '_', colorDefault, con.curFont, 0 );
|
||||||
Con_DrawCharacter( x + curPos, y, '_', colorDefault );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1828,8 +1547,8 @@ void Key_Console( int key )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// enter finishes the line
|
// enter or A finish the line
|
||||||
if( key == K_ENTER || key == K_KP_ENTER )
|
if( key == K_ENTER || key == K_KP_ENTER || key == K_A_BUTTON )
|
||||||
{
|
{
|
||||||
// backslash text are commands, else chat
|
// backslash text are commands, else chat
|
||||||
if( con.input.buffer[0] == '\\' || con.input.buffer[0] == '/' )
|
if( con.input.buffer[0] == '\\' || con.input.buffer[0] == '/' )
|
||||||
|
@ -1856,7 +1575,7 @@ void Key_Console( int key )
|
||||||
}
|
}
|
||||||
|
|
||||||
// command completion
|
// command completion
|
||||||
if( key == K_TAB )
|
if( key == K_TAB || key == K_L2_BUTTON )
|
||||||
{
|
{
|
||||||
Con_CompleteCommand( &con.input );
|
Con_CompleteCommand( &con.input );
|
||||||
Con_Bottom();
|
Con_Bottom();
|
||||||
|
@ -1919,6 +1638,23 @@ void Key_Console( int key )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// enable the OSK with button press
|
||||||
|
if( key == K_Y_BUTTON )
|
||||||
|
{
|
||||||
|
Key_EnableTextInput( true, true );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// exit the console by pressing MINUS on NSwitch
|
||||||
|
// or both Back(Select)/Start buttons for everyone else
|
||||||
|
if( key == K_BACK_BUTTON || key == K_START_BUTTON )
|
||||||
|
{
|
||||||
|
if( cls.state == ca_active && !cl.background )
|
||||||
|
Key_SetKeyDest( key_game );
|
||||||
|
else UI_SetActiveMenu( true );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// pass to the normal editline routine
|
// pass to the normal editline routine
|
||||||
Field_KeyDownEvent( &con.input, key );
|
Field_KeyDownEvent( &con.input, key );
|
||||||
}
|
}
|
||||||
|
@ -1934,14 +1670,14 @@ void Key_Message( int key )
|
||||||
{
|
{
|
||||||
char buffer[MAX_SYSPATH];
|
char buffer[MAX_SYSPATH];
|
||||||
|
|
||||||
if( key == K_ESCAPE )
|
if( key == K_ESCAPE || key == K_BACK_BUTTON )
|
||||||
{
|
{
|
||||||
Key_SetKeyDest( key_game );
|
Key_SetKeyDest( key_game );
|
||||||
Con_ClearField( &con.chat );
|
Con_ClearField( &con.chat );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( key == K_ENTER || key == K_KP_ENTER )
|
if( key == K_ENTER || key == K_KP_ENTER || key == K_A_BUTTON )
|
||||||
{
|
{
|
||||||
if( con.chat.buffer[0] && cls.state == ca_active )
|
if( con.chat.buffer[0] && cls.state == ca_active )
|
||||||
{
|
{
|
||||||
|
@ -1983,7 +1719,7 @@ void Con_DrawInput( int lines )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
y = lines - ( con.curFont->charHeight * 2 );
|
y = lines - ( con.curFont->charHeight * 2 );
|
||||||
Con_DrawCharacter( con.curFont->charWidths[' '], y, ']', g_color_table[7] );
|
CL_DrawCharacter( con.curFont->charWidths[' '], y, ']', g_color_table[7], con.curFont, 0 );
|
||||||
Field_DrawInputLine( con.curFont->charWidths[' ']*2, y, &con.input );
|
Field_DrawInputLine( con.curFont->charWidths[' ']*2, y, &con.input );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2051,7 +1787,7 @@ void Con_DrawDebug( void )
|
||||||
timeStart = Sys_DoubleTime();
|
timeStart = Sys_DoubleTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !host_developer.value || Cvar_VariableInteger( "cl_background" ) || Cvar_VariableInteger( "sv_background" ))
|
if( !host.allow_console || Cvar_VariableInteger( "cl_background" ) || Cvar_VariableInteger( "sv_background" ))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if( con.draw_notify && !Con_Visible( ))
|
if( con.draw_notify && !Con_Visible( ))
|
||||||
|
@ -2077,7 +1813,7 @@ void Con_DrawNotify( void )
|
||||||
|
|
||||||
x = con.curFont->charWidths[' ']; // offset one space at left screen side
|
x = con.curFont->charWidths[' ']; // offset one space at left screen side
|
||||||
|
|
||||||
if( host_developer.value && ( !Cvar_VariableInteger( "cl_background" ) && !Cvar_VariableInteger( "sv_background" )))
|
if( host.allow_console && ( !Cvar_VariableInteger( "cl_background" ) && !Cvar_VariableInteger( "sv_background" )))
|
||||||
{
|
{
|
||||||
for( i = CON_LINES_COUNT - con.num_times; i < CON_LINES_COUNT; i++ )
|
for( i = CON_LINES_COUNT - con.num_times; i < CON_LINES_COUNT; i++ )
|
||||||
{
|
{
|
||||||
|
@ -2128,7 +1864,11 @@ int Con_DrawConsoleLine( int y, int lineno )
|
||||||
return 0; // this string will be shown only at notify
|
return 0; // this string will be shown only at notify
|
||||||
|
|
||||||
if( y >= con.curFont->charHeight )
|
if( y >= con.curFont->charHeight )
|
||||||
Con_DrawGenericString( con.curFont->charWidths[' '], y, li->start, g_color_table[7], false, -1 );
|
{
|
||||||
|
float x = con.curFont->charWidths[' '];
|
||||||
|
|
||||||
|
CL_DrawString( x, y, li->start, g_color_table[7], con.curFont, FONT_DRAW_UTF8 );
|
||||||
|
}
|
||||||
|
|
||||||
return con.curFont->charHeight;
|
return con.curFont->charHeight;
|
||||||
}
|
}
|
||||||
|
@ -2195,17 +1935,15 @@ void Con_DrawSolidConsole( int lines )
|
||||||
// draw current version
|
// draw current version
|
||||||
memcpy( color, g_color_table[7], sizeof( color ));
|
memcpy( color, g_color_table[7], sizeof( color ));
|
||||||
|
|
||||||
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( ));
|
Q_snprintf( curbuild, MAX_STRING, XASH_ENGINE_NAME " %i/" XASH_VERSION " (%s-%s build %i)", PROTOCOL_VERSION, Q_buildos(), Q_buildarch(), Q_buildnum( ));
|
||||||
|
|
||||||
Con_DrawStringLen( curbuild, &stringLen, &charH );
|
Con_DrawStringLen( curbuild, &stringLen, &charH );
|
||||||
start = refState.width - stringLen;
|
|
||||||
stringLen = Con_StringLength( curbuild );
|
|
||||||
|
|
||||||
|
start = refState.width - stringLen;
|
||||||
fraction = lines / (float)refState.height;
|
fraction = lines / (float)refState.height;
|
||||||
color[3] = Q_min( fraction * 2.0f, 1.0f ) * 255; // fadeout version number
|
color[3] = Q_min( fraction * 2.0f, 1.0f ) * 255; // fadeout version number
|
||||||
|
|
||||||
for( i = 0; i < stringLen; i++ )
|
Con_DrawString( start, 0, curbuild, color );
|
||||||
width += Con_DrawCharacter( start + width, 0, curbuild[i], color );
|
|
||||||
|
|
||||||
// draw the text
|
// draw the text
|
||||||
if( CON_LINES_COUNT > 0 )
|
if( CON_LINES_COUNT > 0 )
|
||||||
|
@ -2222,7 +1960,7 @@ void Con_DrawSolidConsole( int lines )
|
||||||
|
|
||||||
// draw red arrows to show the buffer is backscrolled
|
// draw red arrows to show the buffer is backscrolled
|
||||||
for( x = 0; x < con.linewidth; x += 4 )
|
for( x = 0; x < con.linewidth; x += 4 )
|
||||||
Con_DrawCharacter(( x + 1 ) * start, y, '^', g_color_table[1] );
|
CL_DrawCharacter( ( x + 1 ) * start, y, '^', g_color_table[1], con.curFont, 0 );
|
||||||
y -= con.curFont->charHeight;
|
y -= con.curFont->charHeight;
|
||||||
}
|
}
|
||||||
x = lastline;
|
x = lastline;
|
||||||
|
@ -2325,7 +2063,7 @@ void Con_DrawVersion( void )
|
||||||
{
|
{
|
||||||
// draws the current build
|
// draws the current build
|
||||||
byte *color = g_color_table[7];
|
byte *color = g_color_table[7];
|
||||||
int i, stringLen, width = 0, charH = 0;
|
int stringLen, charH = 0;
|
||||||
int start, height = refState.height;
|
int start, height = refState.height;
|
||||||
qboolean draw_version = false;
|
qboolean draw_version = false;
|
||||||
string curbuild;
|
string curbuild;
|
||||||
|
@ -2348,16 +2086,15 @@ void Con_DrawVersion( void )
|
||||||
host.force_draw_version = false;
|
host.force_draw_version = false;
|
||||||
|
|
||||||
if( host.force_draw_version || draw_version )
|
if( host.force_draw_version || draw_version )
|
||||||
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( ));
|
Q_snprintf( curbuild, MAX_STRING, XASH_ENGINE_NAME " v%i/" XASH_VERSION " (%s-%s build %i)", PROTOCOL_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( ));
|
else Q_snprintf( curbuild, MAX_STRING, "v%i/" XASH_VERSION " (%s-%s build %i)", PROTOCOL_VERSION, Q_buildos(), Q_buildarch(), Q_buildnum( ));
|
||||||
|
|
||||||
Con_DrawStringLen( curbuild, &stringLen, &charH );
|
Con_DrawStringLen( curbuild, &stringLen, &charH );
|
||||||
start = refState.width - stringLen * 1.05f;
|
start = refState.width - stringLen * 1.05f;
|
||||||
stringLen = Con_StringLength( curbuild );
|
stringLen = Con_StringLength( curbuild );
|
||||||
height -= charH * 1.05f;
|
height -= charH * 1.05f;
|
||||||
|
|
||||||
for( i = 0; i < stringLen; i++ )
|
Con_DrawString( start, height, curbuild, color );
|
||||||
width += Con_DrawCharacter( start + width, height, curbuild[i], color );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2400,25 +2137,32 @@ void Con_RunConsole( void )
|
||||||
if( FBitSet( con_charset->flags, FCVAR_CHANGED ) ||
|
if( FBitSet( con_charset->flags, FCVAR_CHANGED ) ||
|
||||||
FBitSet( con_fontscale->flags, FCVAR_CHANGED ) ||
|
FBitSet( con_fontscale->flags, FCVAR_CHANGED ) ||
|
||||||
FBitSet( con_fontnum->flags, FCVAR_CHANGED ) ||
|
FBitSet( con_fontnum->flags, FCVAR_CHANGED ) ||
|
||||||
FBitSet( cl_charset->flags, FCVAR_CHANGED ) )
|
FBitSet( cl_charset->flags, FCVAR_CHANGED ))
|
||||||
{
|
{
|
||||||
// update codepage parameters
|
// update codepage parameters
|
||||||
g_codepage = 0;
|
if( !Q_stricmp( con_charset->string, "cp1251" ))
|
||||||
if( !Q_stricmp( con_charset->string, "cp1251" ) )
|
{
|
||||||
g_codepage = 1251;
|
g_codepage = 1251;
|
||||||
else if( !Q_stricmp( con_charset->string, "cp1252" ) )
|
}
|
||||||
|
else if( !Q_stricmp( con_charset->string, "cp1252" ))
|
||||||
|
{
|
||||||
g_codepage = 1252;
|
g_codepage = 1252;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Con_Printf( S_WARN "Unknown charset %s, defaulting to cp1252", con_charset->string );
|
||||||
|
|
||||||
|
Cvar_DirectSet( con_charset, "cp1252" );
|
||||||
|
g_codepage = 1252;
|
||||||
|
}
|
||||||
|
|
||||||
g_utf8 = !Q_stricmp( cl_charset->string, "utf-8" );
|
g_utf8 = !Q_stricmp( cl_charset->string, "utf-8" );
|
||||||
Con_InvalidateFonts();
|
Con_InvalidateFonts();
|
||||||
Con_LoadConchars();
|
Con_LoadConchars();
|
||||||
cls.creditsFont.valid = false;
|
|
||||||
SCR_LoadCreditsFont();
|
|
||||||
ClearBits( con_charset->flags, FCVAR_CHANGED );
|
ClearBits( con_charset->flags, FCVAR_CHANGED );
|
||||||
ClearBits( con_fontnum->flags, FCVAR_CHANGED );
|
ClearBits( con_fontnum->flags, FCVAR_CHANGED );
|
||||||
ClearBits( con_fontscale->flags, FCVAR_CHANGED );
|
ClearBits( con_fontscale->flags, FCVAR_CHANGED );
|
||||||
ClearBits( cl_charset->flags, FCVAR_CHANGED );
|
ClearBits( cl_charset->flags, FCVAR_CHANGED );
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2553,8 +2297,10 @@ Con_InvalidateFonts
|
||||||
*/
|
*/
|
||||||
void Con_InvalidateFonts( void )
|
void Con_InvalidateFonts( void )
|
||||||
{
|
{
|
||||||
memset( con.chars, 0, sizeof( con.chars ));
|
int i;
|
||||||
con.curFont = con.lastUsedFont = NULL;
|
for( i = 0; i < ARRAYSIZE( con.chars ); i++ )
|
||||||
|
CL_FreeFont( &con.chars[i] );
|
||||||
|
con.curFont = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -244,7 +244,7 @@ void Joy_AxisMotionEvent( byte axis, short value )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Joy_KnownAxisMotionEvent( joyaxesmap[axis], value );
|
Joy_KnownAxisMotionEvent( joyaxesmap[axis], value );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Joy_KnownAxisMotionEvent( engineAxis_t engineAxis, short value )
|
void Joy_KnownAxisMotionEvent( engineAxis_t engineAxis, short value )
|
||||||
|
|
|
@ -151,7 +151,6 @@ convar_t *touch_exp_mult;
|
||||||
convar_t *touch_grid_enable;
|
convar_t *touch_grid_enable;
|
||||||
convar_t *touch_grid_count;
|
convar_t *touch_grid_count;
|
||||||
convar_t *touch_config_file;
|
convar_t *touch_config_file;
|
||||||
convar_t *touch_enable;
|
|
||||||
convar_t *touch_in_menu;
|
convar_t *touch_in_menu;
|
||||||
convar_t *touch_joy_radius;
|
convar_t *touch_joy_radius;
|
||||||
convar_t *touch_dpad_radius;
|
convar_t *touch_dpad_radius;
|
||||||
|
@ -162,7 +161,9 @@ convar_t *touch_highlight_b;
|
||||||
convar_t *touch_highlight_a;
|
convar_t *touch_highlight_a;
|
||||||
convar_t *touch_precise_amount;
|
convar_t *touch_precise_amount;
|
||||||
convar_t *touch_joy_texture;
|
convar_t *touch_joy_texture;
|
||||||
convar_t *touch_emulate;
|
|
||||||
|
CVAR_DEFINE_AUTO( touch_enable, DEFAULT_TOUCH_ENABLE, FCVAR_ARCHIVE | FCVAR_FILTERABLE, "enable touch controls" );
|
||||||
|
CVAR_DEFINE_AUTO( touch_emulate, "0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "emulate touch with mouse" );
|
||||||
|
|
||||||
// code looks smaller with it
|
// code looks smaller with it
|
||||||
#define B(x) (button->x)
|
#define B(x) (button->x)
|
||||||
|
@ -216,36 +217,29 @@ static inline int Touch_ExportButtonToConfig( file_t *f, touch_button_t *button,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=================
|
=================
|
||||||
Touch_WriteConfig
|
Touch_DumpConfig
|
||||||
|
|
||||||
save current touch configuration
|
Dump config to file
|
||||||
=================
|
=================
|
||||||
*/
|
*/
|
||||||
void Touch_WriteConfig( void )
|
qboolean Touch_DumpConfig( const char *name, const char *profilename )
|
||||||
{
|
{
|
||||||
file_t *f;
|
file_t *f;
|
||||||
string newconfigfile, oldconfigfile;
|
|
||||||
|
|
||||||
if( !touch.list_user.first )
|
|
||||||
return;
|
|
||||||
|
|
||||||
if( Sys_CheckParm( "-nowriteconfig" ) || !touch.configchanged || !touch.config_loaded )
|
|
||||||
return;
|
|
||||||
|
|
||||||
Con_DPrintf( "Touch_WriteConfig(): %s\n", touch_config_file->string );
|
|
||||||
|
|
||||||
Q_snprintf( newconfigfile, sizeof( newconfigfile ), "%s.new", touch_config_file->string );
|
|
||||||
Q_snprintf( oldconfigfile, sizeof( oldconfigfile ), "%s.bak", touch_config_file->string );
|
|
||||||
|
|
||||||
f = FS_Open( newconfigfile, "w", true );
|
|
||||||
if( f )
|
|
||||||
{
|
|
||||||
touch_button_t *button;
|
touch_button_t *button;
|
||||||
|
|
||||||
|
f = FS_Open( name, "w", true );
|
||||||
|
|
||||||
|
if( !f )
|
||||||
|
{
|
||||||
|
Con_Printf( S_ERROR "Couldn't write %s.\n", name );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
FS_Printf( f, "//=======================================================================\n");
|
FS_Printf( f, "//=======================================================================\n");
|
||||||
FS_Printf( f, "//\tCopyright FWGS & XashXT group %s (c)\n", Q_timestamp( TIME_YEAR_ONLY ));
|
FS_Printf( f, "//\tCopyright FWGS & XashXT group %s (c)\n", Q_timestamp( TIME_YEAR_ONLY ));
|
||||||
FS_Printf( f, "//\t\t\ttouchscreen config\n" );
|
FS_Printf( f, "//\t\t\ttouchscreen config\n" );
|
||||||
FS_Printf( f, "//=======================================================================\n" );
|
FS_Printf( f, "//=======================================================================\n" );
|
||||||
FS_Printf( f, "\ntouch_config_file \"%s\"\n", touch_config_file->string );
|
FS_Printf( f, "\ntouch_config_file \"%s\"\n", profilename );
|
||||||
FS_Printf( f, "\n// touch cvars\n" );
|
FS_Printf( f, "\n// touch cvars\n" );
|
||||||
FS_Printf( f, "\n// sensitivity settings\n" );
|
FS_Printf( f, "\n// sensitivity settings\n" );
|
||||||
FS_Printf( f, "touch_pitch \"%f\"\n", touch_pitch->value );
|
FS_Printf( f, "touch_pitch \"%f\"\n", touch_pitch->value );
|
||||||
|
@ -286,12 +280,40 @@ void Touch_WriteConfig( void )
|
||||||
|
|
||||||
FS_Close( f );
|
FS_Close( f );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=================
|
||||||
|
Touch_WriteConfig
|
||||||
|
|
||||||
|
save current touch configuration
|
||||||
|
=================
|
||||||
|
*/
|
||||||
|
void Touch_WriteConfig( void )
|
||||||
|
{
|
||||||
|
file_t *f;
|
||||||
|
string newconfigfile, oldconfigfile;
|
||||||
|
|
||||||
|
if( !touch.list_user.first )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( Sys_CheckParm( "-nowriteconfig" ) || !touch.configchanged || !touch.config_loaded )
|
||||||
|
return;
|
||||||
|
|
||||||
|
Con_DPrintf( "Touch_WriteConfig(): %s\n", touch_config_file->string );
|
||||||
|
|
||||||
|
Q_snprintf( newconfigfile, sizeof( newconfigfile ), "%s.new", touch_config_file->string );
|
||||||
|
Q_snprintf( oldconfigfile, sizeof( oldconfigfile ), "%s.bak", touch_config_file->string );
|
||||||
|
|
||||||
|
if( Touch_DumpConfig( newconfigfile, touch_config_file->string ))
|
||||||
|
{
|
||||||
FS_Delete( oldconfigfile );
|
FS_Delete( oldconfigfile );
|
||||||
FS_Rename( touch_config_file->string, oldconfigfile );
|
FS_Rename( touch_config_file->string, oldconfigfile );
|
||||||
|
|
||||||
FS_Delete( touch_config_file->string );
|
FS_Delete( touch_config_file->string );
|
||||||
FS_Rename( newconfigfile, touch_config_file->string );
|
FS_Rename( newconfigfile, touch_config_file->string );
|
||||||
}
|
}
|
||||||
else Con_Printf( S_ERROR "Couldn't write %s.\n", touch_config_file->string );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -303,8 +325,8 @@ export current touch configuration into profile
|
||||||
*/
|
*/
|
||||||
static void Touch_ExportConfig_f( void )
|
static void Touch_ExportConfig_f( void )
|
||||||
{
|
{
|
||||||
file_t *f;
|
|
||||||
const char *name;
|
const char *name;
|
||||||
|
string profilename, profilebase;
|
||||||
|
|
||||||
if( Cmd_Argc() != 2 )
|
if( Cmd_Argc() != 2 )
|
||||||
{
|
{
|
||||||
|
@ -316,65 +338,15 @@ static void Touch_ExportConfig_f( void )
|
||||||
|
|
||||||
name = Cmd_Argv( 1 );
|
name = Cmd_Argv( 1 );
|
||||||
|
|
||||||
Con_Reportf( "Exporting config to %s\n", name );
|
if( Q_strstr( name, "touch_presets/" ))
|
||||||
f = FS_Open( name, "w", true );
|
|
||||||
if( f )
|
|
||||||
{
|
|
||||||
string profilename, profilebase;
|
|
||||||
touch_button_t *button;
|
|
||||||
|
|
||||||
if( Q_strstr( name, "touch_presets/" ) )
|
|
||||||
{
|
{
|
||||||
COM_FileBase( name, profilebase );
|
COM_FileBase( name, profilebase );
|
||||||
Q_snprintf( profilename, sizeof( profilebase ), "touch_profiles/%s (copy).cfg", profilebase );
|
Q_snprintf( profilename, sizeof( profilebase ), "touch_profiles/%s (copy).cfg", profilebase );
|
||||||
}
|
}
|
||||||
else Q_strncpy( profilename, name, sizeof( profilename ));
|
else Q_strncpy( profilename, name, sizeof( profilename ));
|
||||||
FS_Printf( f, "//=======================================================================\n");
|
|
||||||
FS_Printf( f, "//\tCopyright FWGS & XashXT group %s (c)\n", Q_timestamp( TIME_YEAR_ONLY ));
|
|
||||||
FS_Printf( f, "//\t\t\ttouchscreen preset\n" );
|
|
||||||
FS_Printf( f, "//=======================================================================\n" );
|
|
||||||
FS_Printf( f, "\ntouch_config_file \"%s\"\n", profilename );
|
|
||||||
FS_Printf( f, "\n// touch cvars\n" );
|
|
||||||
FS_Printf( f, "\n// sensitivity settings\n" );
|
|
||||||
FS_Printf( f, "touch_pitch \"%f\"\n", touch_pitch->value );
|
|
||||||
FS_Printf( f, "touch_yaw \"%f\"\n", touch_yaw->value );
|
|
||||||
FS_Printf( f, "touch_forwardzone \"%f\"\n", touch_forwardzone->value );
|
|
||||||
FS_Printf( f, "touch_sidezone \"%f\"\n", touch_sidezone->value );
|
|
||||||
FS_Printf( f, "touch_nonlinear_look \"%d\"\n", CVAR_TO_BOOL(touch_nonlinear_look) );
|
|
||||||
FS_Printf( f, "touch_pow_factor \"%f\"\n", touch_pow_factor->value );
|
|
||||||
FS_Printf( f, "touch_pow_mult \"%f\"\n", touch_pow_mult->value );
|
|
||||||
FS_Printf( f, "touch_exp_mult \"%f\"\n", touch_exp_mult->value );
|
|
||||||
FS_Printf( f, "\n// grid settings\n" );
|
|
||||||
FS_Printf( f, "touch_grid_count \"%d\"\n", (int)touch_grid_count->value );
|
|
||||||
FS_Printf( f, "touch_grid_enable \"%d\"\n", CVAR_TO_BOOL(touch_grid_enable) );
|
|
||||||
FS_Printf( f, "\n// global overstroke (width, r, g, b, a)\n" );
|
|
||||||
FS_Printf( f, "touch_set_stroke %d %d %d %d %d\n", touch.swidth, touch.scolor[0], touch.scolor[1], touch.scolor[2], touch.scolor[3] );
|
|
||||||
FS_Printf( f, "\n// highlight when pressed\n" );
|
|
||||||
FS_Printf( f, "touch_highlight_r \"%f\"\n", touch_highlight_r->value );
|
|
||||||
FS_Printf( f, "touch_highlight_g \"%f\"\n", touch_highlight_g->value );
|
|
||||||
FS_Printf( f, "touch_highlight_b \"%f\"\n", touch_highlight_b->value );
|
|
||||||
FS_Printf( f, "touch_highlight_a \"%f\"\n", touch_highlight_a->value );
|
|
||||||
FS_Printf( f, "\n// _joy and _dpad options\n" );
|
|
||||||
FS_Printf( f, "touch_dpad_radius \"%f\"\n", touch_dpad_radius->value );
|
|
||||||
FS_Printf( f, "touch_joy_radius \"%f\"\n", touch_joy_radius->value );
|
|
||||||
FS_Printf( f, "\n// how much slowdown when Precise Look button pressed\n" );
|
|
||||||
FS_Printf( f, "touch_precise_amount \"%f\"\n", touch_precise_amount->value );
|
|
||||||
FS_Printf( f, "\n// enable/disable move indicator\n" );
|
|
||||||
FS_Printf( f, "touch_move_indicator \"%f\"\n", touch_move_indicator->value );
|
|
||||||
|
|
||||||
FS_Printf( f, "\n// reset menu state when execing config\n" );
|
Con_Reportf( "Exporting config to \"%s\", profile name \"%s\"\n", name, profilename );
|
||||||
FS_Printf( f, "touch_setclientonly 0\n" );
|
Touch_DumpConfig( name, profilename );
|
||||||
FS_Printf( f, "\n// touch buttons\n" );
|
|
||||||
FS_Printf( f, "touch_removeall\n" );
|
|
||||||
for( button = touch.list_user.first; button; button = button->next )
|
|
||||||
{
|
|
||||||
Touch_ExportButtonToConfig( f, button, true );
|
|
||||||
}
|
|
||||||
FS_Printf( f, "\n// round button coordinates to grid\n" );
|
|
||||||
FS_Printf( f, "touch_roundall\n" );
|
|
||||||
FS_Close( f );
|
|
||||||
}
|
|
||||||
else Con_Printf( S_ERROR "Couldn't write %s.\n", name );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -497,8 +469,8 @@ static touch_button_t *Touch_FindFirst( touchbuttonlist_t *list, const char *nam
|
||||||
|
|
||||||
void Touch_SetClientOnly( byte state )
|
void Touch_SetClientOnly( byte state )
|
||||||
{
|
{
|
||||||
|
// TODO: fix clash with vgui cursors
|
||||||
touch.clientonly = state;
|
touch.clientonly = state;
|
||||||
host.mouse_visible = state;
|
|
||||||
|
|
||||||
touch.move_finger = touch.look_finger = -1;
|
touch.move_finger = touch.look_finger = -1;
|
||||||
touch.forward = touch.side = 0;
|
touch.forward = touch.side = 0;
|
||||||
|
@ -994,7 +966,7 @@ static void Touch_InitEditor( void )
|
||||||
|
|
||||||
Touch_ClearList( &touch.list_edit );
|
Touch_ClearList( &touch.list_edit );
|
||||||
|
|
||||||
temp = Touch_AddButton( &touch.list_edit, "close", "touch_default/edit_close.tga", "touch_disableedit", 0, y, x, y + 0.1f, color, true );
|
temp = Touch_AddButton( &touch.list_edit, "close", "touch_default/edit_close", "touch_disableedit", 0, y, x, y + 0.1f, color, true );
|
||||||
SetBits( temp->flags, TOUCH_FL_NOEDIT );
|
SetBits( temp->flags, TOUCH_FL_NOEDIT );
|
||||||
|
|
||||||
temp = Touch_AddButton( &touch.list_edit, "close", "#Close and save", "", x, y, x + 0.2f, y + 0.1f, color, true );
|
temp = Touch_AddButton( &touch.list_edit, "close", "#Close and save", "", x, y, x + 0.2f, y + 0.1f, color, true );
|
||||||
|
@ -1002,7 +974,7 @@ static void Touch_InitEditor( void )
|
||||||
|
|
||||||
y += 0.2f;
|
y += 0.2f;
|
||||||
|
|
||||||
temp = Touch_AddButton( &touch.list_edit, "cancel", "touch_default/edit_reset.tga", "touch_reloadconfig", 0, y, x, y + 0.1f, color, true );
|
temp = Touch_AddButton( &touch.list_edit, "cancel", "touch_default/edit_reset", "touch_reloadconfig", 0, y, x, y + 0.1f, color, true );
|
||||||
SetBits( temp->flags, TOUCH_FL_NOEDIT );
|
SetBits( temp->flags, TOUCH_FL_NOEDIT );
|
||||||
|
|
||||||
temp = Touch_AddButton( &touch.list_edit, "close", "#Cancel and reset", "", x, y, x + 0.2f, y + 0.1f, color, true );
|
temp = Touch_AddButton( &touch.list_edit, "close", "#Cancel and reset", "", x, y, x + 0.2f, y + 0.1f, color, true );
|
||||||
|
@ -1010,7 +982,7 @@ static void Touch_InitEditor( void )
|
||||||
|
|
||||||
y += 0.2f;
|
y += 0.2f;
|
||||||
|
|
||||||
touch.hidebutton = Touch_AddButton( &touch.list_edit, "showhide", "touch_default/edit_hide.tga", "touch_toggleselection", 0, y, x, y + 0.1f, color, true );
|
touch.hidebutton = Touch_AddButton( &touch.list_edit, "showhide", "touch_default/edit_hide", "touch_toggleselection", 0, y, x, y + 0.1f, color, true );
|
||||||
SetBits( touch.hidebutton->flags, TOUCH_FL_HIDE | TOUCH_FL_NOEDIT );
|
SetBits( touch.hidebutton->flags, TOUCH_FL_HIDE | TOUCH_FL_NOEDIT );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1038,24 +1010,24 @@ void Touch_Init( void )
|
||||||
MakeRGBA( color, 255, 255, 255, 255 );
|
MakeRGBA( color, 255, 255, 255, 255 );
|
||||||
Touch_AddDefaultButton( "look", "", "_look", 0.500000, 0.000000, 1.000000, 1, color, 0, 0, 0 );
|
Touch_AddDefaultButton( "look", "", "_look", 0.500000, 0.000000, 1.000000, 1, color, 0, 0, 0 );
|
||||||
Touch_AddDefaultButton( "move", "", "_move", 0.000000, 0.000000, 0.500000, 1, color, 0, 0, 0 );
|
Touch_AddDefaultButton( "move", "", "_move", 0.000000, 0.000000, 0.500000, 1, color, 0, 0, 0 );
|
||||||
Touch_AddDefaultButton( "invnext", "touch_default/next_weap.tga", "invnext", 0.000000, 0.530200, 0.120000, 0.757428, color, 2, 1, 0 );
|
Touch_AddDefaultButton( "invnext", "touch_default/next_weap", "invnext", 0.000000, 0.530200, 0.120000, 0.757428, color, 2, 1, 0 );
|
||||||
Touch_AddDefaultButton( "invprev", "touch_default/prev_weap.tga", "invprev", 0.000000, 0.075743, 0.120000, 0.302971, color, 2, 1, 0 );
|
Touch_AddDefaultButton( "invprev", "touch_default/prev_weap", "invprev", 0.000000, 0.075743, 0.120000, 0.302971, color, 2, 1, 0 );
|
||||||
Touch_AddDefaultButton( "use", "touch_default/use.tga", "+use", 0.880000, 0.454457, 1.000000, 0.681685, color, 2, 1, 0 );
|
Touch_AddDefaultButton( "use", "touch_default/use", "+use", 0.880000, 0.454457, 1.000000, 0.681685, color, 2, 1, 0 );
|
||||||
Touch_AddDefaultButton( "jump", "touch_default/jump.tga", "+jump", 0.880000, 0.227228, 1.000000, 0.454457, color, 2, 1, 0 );
|
Touch_AddDefaultButton( "jump", "touch_default/jump", "+jump", 0.880000, 0.227228, 1.000000, 0.454457, color, 2, 1, 0 );
|
||||||
Touch_AddDefaultButton( "attack", "touch_default/shoot.tga", "+attack", 0.760000, 0.530200, 0.880000, 0.757428, color, 2, 1, 0 );
|
Touch_AddDefaultButton( "attack", "touch_default/shoot", "+attack", 0.760000, 0.530200, 0.880000, 0.757428, color, 2, 1, 0 );
|
||||||
Touch_AddDefaultButton( "attack2", "touch_default/shoot_alt.tga", "+attack2", 0.760000, 0.302971, 0.880000, 0.530200, color, 2, 1, 0 );
|
Touch_AddDefaultButton( "attack2", "touch_default/shoot_alt", "+attack2", 0.760000, 0.302971, 0.880000, 0.530200, color, 2, 1, 0 );
|
||||||
Touch_AddDefaultButton( "loadquick", "touch_default/load.tga", "loadquick", 0.760000, 0.000000, 0.840000, 0.151486, color, 2, 1, 16 );
|
Touch_AddDefaultButton( "loadquick", "touch_default/load", "loadquick", 0.680000, 0.000000, 0.760000, 0.151486, color, 2, 1, 16 );
|
||||||
Touch_AddDefaultButton( "savequick", "touch_default/save.tga", "savequick", 0.840000, 0.000000, 0.920000, 0.151486, color, 2, 1, 16 );
|
Touch_AddDefaultButton( "savequick", "touch_default/save", "savequick", 0.760000, 0.000000, 0.840000, 0.151486, color, 2, 1, 16 );
|
||||||
Touch_AddDefaultButton( "messagemode", "touch_default/keyboard.tga", "messagemode", 0.840000, 0.000000, 0.920000, 0.151486, color, 2, 1, 8 );
|
Touch_AddDefaultButton( "messagemode", "touch_default/keyboard", "messagemode", 0.760000, 0.000000, 0.840000, 0.151486, color, 2, 1, 8 );
|
||||||
Touch_AddDefaultButton( "reload", "touch_default/reload.tga", "+reload", 0.000000, 0.302971, 0.120000, 0.530200, color, 2, 1, 0 );
|
Touch_AddDefaultButton( "reload", "touch_default/reload", "+reload", 0.000000, 0.302971, 0.120000, 0.530200, color, 2, 1, 0 );
|
||||||
Touch_AddDefaultButton( "flashlight", "touch_default/flash_light_filled.tga", "impulse 100", 0.920000, 0.000000, 1.000000, 0.151486, color, 2, 1, 0 );
|
Touch_AddDefaultButton( "flashlight", "touch_default/flash_light_filled", "impulse 100", 0.920000, 0.000000, 1.000000, 0.151486, color, 2, 1, 0 );
|
||||||
Touch_AddDefaultButton( "scores", "touch_default/map.tga", "+showscores", 0.760000, 0.000000, 0.840000, 0.151486, color, 2, 1, 8 );
|
Touch_AddDefaultButton( "scores", "touch_default/map", "+showscores", 0.680000, 0.000000, 0.760000, 0.151486, color, 2, 1, 8 );
|
||||||
Touch_AddDefaultButton( "show_numbers", "touch_default/show_weapons.tga", "exec touch_default/numbers.cfg", 0.440000, 0.833171, 0.520000, 0.984656, color, 2, 1, 0 );
|
Touch_AddDefaultButton( "show_numbers", "touch_default/show_weapons", "exec touch_default/numbers.cfg", 0.440000, 0.833171, 0.520000, 0.984656, color, 2, 1, 0 );
|
||||||
Touch_AddDefaultButton( "duck", "touch_default/crouch.tga", "+duck", 0.880000, 0.757428, 1.000000, 0.984656, color, 2, 1, 0 );
|
Touch_AddDefaultButton( "duck", "touch_default/crouch", "+duck", 0.880000, 0.757428, 1.000000, 0.984656, color, 2, 1, 0 );
|
||||||
Touch_AddDefaultButton( "tduck", "touch_default/tduck.tga", ";+duck", 0.560000, 0.833171, 0.620000, 0.946785, color, 2, 1, 0 );
|
Touch_AddDefaultButton( "tduck", "touch_default/tduck", ";+duck", 0.560000, 0.833171, 0.620000, 0.946785, color, 2, 1, 0 );
|
||||||
Touch_AddDefaultButton( "edit", "touch_default/settings.tga", "touch_enableedit", 0.420000, 0.000000, 0.500000, 0.151486, color, 2, 1, 32 );
|
Touch_AddDefaultButton( "edit", "touch_default/settings", "touch_enableedit", 0.420000, 0.000000, 0.500000, 0.151486, color, 2, 1, 32 );
|
||||||
Touch_AddDefaultButton( "menu", "touch_default/menu.tga", "escape", 0.000000, 0.833171, 0.080000, 0.984656, color, 2, 1, 0 );
|
Touch_AddDefaultButton( "menu", "touch_default/menu", "escape", 0.000000, 0.833171, 0.080000, 0.984656, color, 2, 1, 0 );
|
||||||
|
Touch_AddDefaultButton( "spray", "touch_default/spray", "impulse 201", 0.840000, 0.000000, 0.920000, 0.151486, color, 2, 1, 0 );
|
||||||
|
|
||||||
Cmd_AddCommand( "touch_addbutton", Touch_AddButton_f, "add native touch button" );
|
Cmd_AddCommand( "touch_addbutton", Touch_AddButton_f, "add native touch button" );
|
||||||
Cmd_AddCommand( "touch_removebutton", IN_TouchRemoveButton_f, "remove native touch button" );
|
Cmd_AddCommand( "touch_removebutton", IN_TouchRemoveButton_f, "remove native touch button" );
|
||||||
|
@ -1106,14 +1078,19 @@ void Touch_Init( void )
|
||||||
touch_dpad_radius = Cvar_Get( "touch_dpad_radius", "1.0", FCVAR_FILTERABLE, "dpad radius multiplier" );
|
touch_dpad_radius = Cvar_Get( "touch_dpad_radius", "1.0", FCVAR_FILTERABLE, "dpad radius multiplier" );
|
||||||
touch_joy_radius = Cvar_Get( "touch_joy_radius", "1.0", FCVAR_FILTERABLE, "joy radius multiplier" );
|
touch_joy_radius = Cvar_Get( "touch_joy_radius", "1.0", FCVAR_FILTERABLE, "joy radius multiplier" );
|
||||||
touch_move_indicator = Cvar_Get( "touch_move_indicator", "0.0", FCVAR_FILTERABLE, "indicate move events (0 to disable)" );
|
touch_move_indicator = Cvar_Get( "touch_move_indicator", "0.0", FCVAR_FILTERABLE, "indicate move events (0 to disable)" );
|
||||||
touch_joy_texture = Cvar_Get( "touch_joy_texture", "touch_default/joy.tga", FCVAR_FILTERABLE, "texture for move indicator");
|
touch_joy_texture = Cvar_Get( "touch_joy_texture", "touch_default/joy", FCVAR_FILTERABLE, "texture for move indicator");
|
||||||
|
|
||||||
// input devices cvar
|
// input devices cvar
|
||||||
touch_enable = Cvar_Get( "touch_enable", DEFAULT_TOUCH_ENABLE, FCVAR_ARCHIVE | FCVAR_FILTERABLE, "enable touch controls" );
|
Cvar_RegisterVariable( &touch_enable );
|
||||||
touch_emulate = Cvar_Get( "touch_emulate", "0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "emulate touch with mouse" );
|
Cvar_RegisterVariable( &touch_emulate );
|
||||||
|
|
||||||
/// TODO: touch sdl platform
|
// TODO: touch platform
|
||||||
// SDL_SetHint( SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH, "1" );
|
#if SDL_VERSION_ATLEAST( 2, 0, 10 )
|
||||||
|
SDL_SetHint( SDL_HINT_MOUSE_TOUCH_EVENTS, "0" );
|
||||||
|
SDL_SetHint( SDL_HINT_TOUCH_MOUSE_EVENTS, "0" );
|
||||||
|
#else
|
||||||
|
SDL_SetHint( SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH, "1" );
|
||||||
|
#endif
|
||||||
|
|
||||||
touch.initialized = true;
|
touch.initialized = true;
|
||||||
}
|
}
|
||||||
|
@ -1133,8 +1110,14 @@ static void Touch_InitConfig( void )
|
||||||
/// TODO: hud font
|
/// TODO: hud font
|
||||||
//pfnGetScreenInfo( NULL ); //HACK: update hud screen parameters like iHeight
|
//pfnGetScreenInfo( NULL ); //HACK: update hud screen parameters like iHeight
|
||||||
if( FS_FileExists( touch_config_file->string, true ) )
|
if( FS_FileExists( touch_config_file->string, true ) )
|
||||||
|
{
|
||||||
Cbuf_AddText( va( "exec \"%s\"\n", touch_config_file->string ) );
|
Cbuf_AddText( va( "exec \"%s\"\n", touch_config_file->string ) );
|
||||||
else Touch_LoadDefaults_f( );
|
Cbuf_Execute();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Touch_LoadDefaults_f();
|
||||||
|
}
|
||||||
|
|
||||||
Touch_InitEditor();
|
Touch_InitEditor();
|
||||||
touch.joytexture = ref.dllFuncs.GL_LoadTexture( touch_joy_texture->string, NULL, 0, TF_NOMIPMAP );
|
touch.joytexture = ref.dllFuncs.GL_LoadTexture( touch_joy_texture->string, NULL, 0, TF_NOMIPMAP );
|
||||||
|
@ -1372,7 +1355,7 @@ void Touch_Draw( void )
|
||||||
{
|
{
|
||||||
touch_button_t *button;
|
touch_button_t *button;
|
||||||
|
|
||||||
if( !touch.initialized || (!CVAR_TO_BOOL(touch_enable) && !touch.clientonly) )
|
if( !touch.initialized || ( !touch_enable.value && !touch.clientonly ))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Touch_InitConfig();
|
Touch_InitConfig();
|
||||||
|
@ -1515,9 +1498,9 @@ static void Touch_EditMove( touchEventType type, int fingerID, float x, float y,
|
||||||
touch.hidebutton->flags &= ~TOUCH_FL_HIDE;
|
touch.hidebutton->flags &= ~TOUCH_FL_HIDE;
|
||||||
|
|
||||||
if( FBitSet( button->flags, TOUCH_FL_HIDE ))
|
if( FBitSet( button->flags, TOUCH_FL_HIDE ))
|
||||||
Q_strcpy( touch.hidebutton->texturefile, "touch_default/edit_show.tga" );
|
Q_strcpy( touch.hidebutton->texturefile, "touch_default/edit_show" );
|
||||||
else
|
else
|
||||||
Q_strcpy( touch.hidebutton->texturefile, "touch_default/edit_hide.tga" );
|
Q_strcpy( touch.hidebutton->texturefile, "touch_default/edit_hide" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( type == event_motion ) // shutdown button move
|
if( type == event_motion ) // shutdown button move
|
||||||
|
@ -1966,14 +1949,14 @@ static int Touch_ControlsEvent( touchEventType type, int fingerID, float x, floa
|
||||||
|
|
||||||
int IN_TouchEvent( touchEventType type, int fingerID, float x, float y, float dx, float dy )
|
int IN_TouchEvent( touchEventType type, int fingerID, float x, float y, float dx, float dy )
|
||||||
{
|
{
|
||||||
|
|
||||||
// simulate menu mouse click
|
// simulate menu mouse click
|
||||||
if( cls.key_dest != key_game && !CVAR_TO_BOOL(touch_in_menu) )
|
if( cls.key_dest != key_game && !CVAR_TO_BOOL( touch_in_menu ))
|
||||||
{
|
{
|
||||||
touch.move_finger = touch.resize_finger = touch.look_finger = -1;
|
touch.move_finger = touch.resize_finger = touch.look_finger = -1;
|
||||||
// Hack for keyboard, hope it help
|
// Hack for keyboard, hope it help
|
||||||
if( cls.key_dest == key_console || cls.key_dest == key_message )
|
if( cls.key_dest == key_console || cls.key_dest == key_message )
|
||||||
{
|
{
|
||||||
|
if ( type == event_down ) // don't pop it again on event_up
|
||||||
Key_EnableTextInput( true, true );
|
Key_EnableTextInput( true, true );
|
||||||
if( cls.key_dest == key_console )
|
if( cls.key_dest == key_console )
|
||||||
{
|
{
|
||||||
|
@ -2011,25 +1994,20 @@ int IN_TouchEvent( touchEventType type, int fingerID, float x, float y, float dx
|
||||||
{
|
{
|
||||||
VGui_MouseMove( TO_SCRN_X(x), TO_SCRN_Y(y) );
|
VGui_MouseMove( TO_SCRN_X(x), TO_SCRN_Y(y) );
|
||||||
|
|
||||||
if( type != event_motion )
|
switch( type )
|
||||||
VGui_KeyEvent( K_MOUSE1, type == event_down ? 1 : 0 );
|
|
||||||
|
|
||||||
// allow scoreboard scroll
|
|
||||||
if( host.mouse_visible && type == event_motion )
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !touch.initialized || (!CVAR_TO_BOOL(touch_enable) && !touch.clientonly) )
|
|
||||||
{
|
{
|
||||||
#if 0
|
case event_down:
|
||||||
if( type == event_down )
|
VGui_MouseEvent( K_MOUSE1, 1 );
|
||||||
Key_Event( K_MOUSE1, true );
|
break;
|
||||||
if( type == event_up )
|
case event_up:
|
||||||
Key_Event( K_MOUSE1, false );
|
VGui_MouseEvent( K_MOUSE1, 0 );
|
||||||
Android_AddMove( dx * (float)refState.width, dy * (float)refState.height );
|
break;
|
||||||
#endif
|
default: break;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !touch.initialized || ( !touch_enable.value && !touch.clientonly ))
|
||||||
|
return 0;
|
||||||
|
|
||||||
if( clgame.dllFuncs.pfnTouchEvent && clgame.dllFuncs.pfnTouchEvent( type, fingerID, x, y, dx, dy ) )
|
if( clgame.dllFuncs.pfnTouchEvent && clgame.dllFuncs.pfnTouchEvent( type, fingerID, x, y, dx, dy ) )
|
||||||
return true;
|
return true;
|
||||||
|
@ -2048,35 +2026,65 @@ void Touch_GetMove( float *forward, float *side, float *yaw, float *pitch )
|
||||||
|
|
||||||
void Touch_KeyEvent( int key, int down )
|
void Touch_KeyEvent( int key, int down )
|
||||||
{
|
{
|
||||||
int xi, yi;
|
|
||||||
float x, y;
|
|
||||||
static float lx, ly;
|
static float lx, ly;
|
||||||
|
static int kidNamedFinger = -1;
|
||||||
|
touchEventType event;
|
||||||
|
float x, y;
|
||||||
|
int finger, xi, yi;
|
||||||
|
|
||||||
if( !CVAR_TO_BOOL(touch_emulate) )
|
if( !touch_emulate.value )
|
||||||
{
|
{
|
||||||
if( CVAR_TO_BOOL(touch_enable) )
|
if( touch_enable.value )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if( !touch.clientonly )
|
if( !touch.clientonly )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Platform_GetMousePos( &xi, &yi );
|
if( !key )
|
||||||
|
|
||||||
x = xi/SCR_W;
|
|
||||||
y = yi/SCR_H;
|
|
||||||
|
|
||||||
if( cls.key_dest == key_menu && down < 2 && key == K_MOUSE1 )
|
|
||||||
{
|
{
|
||||||
UI_MouseMove( xi, yi );
|
if( kidNamedFinger < 0 )
|
||||||
UI_KeyEvent( key, down );
|
return;
|
||||||
|
|
||||||
|
finger = kidNamedFinger;
|
||||||
|
event = event_motion;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
finger = key == K_MOUSE1 ? 0 : 1;
|
||||||
|
if( down )
|
||||||
|
{
|
||||||
|
event = event_down;
|
||||||
|
kidNamedFinger = finger;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
event = event_up;
|
||||||
|
kidNamedFinger = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( down == 1 )
|
// don't deactivate mouse in game
|
||||||
Touch_ControlsEvent( event_down, key == K_MOUSE1?0:1, x, y, 0, 0 );
|
// checking a case when mouse and touchscreen
|
||||||
else
|
// can be used simultaneously
|
||||||
Touch_ControlsEvent( down? event_motion: event_up, key == K_MOUSE1?0:1, x, y, x-lx, y-ly );
|
Platform_SetCursorType( dc_arrow );
|
||||||
lx = x, ly = y;
|
Platform_GetMousePos( &xi, &yi );
|
||||||
|
|
||||||
|
x = xi / SCR_W;
|
||||||
|
y = yi / SCR_H;
|
||||||
|
|
||||||
|
Con_DPrintf( "event %d %.2f %.2f %.2f %.2f\n",
|
||||||
|
event, x, y, x - lx, y - ly );
|
||||||
|
|
||||||
|
IN_TouchEvent( event, finger, x, y, x - lx, y - ly );
|
||||||
|
|
||||||
|
lx = x;
|
||||||
|
ly = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
qboolean Touch_WantVisibleCursor( void )
|
||||||
|
{
|
||||||
|
return ( touch_enable.value && touch_emulate.value ) || touch.clientonly;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Touch_Shutdown( void )
|
void Touch_Shutdown( void )
|
||||||
|
|
|
@ -47,8 +47,6 @@ convar_t *cl_backspeed;
|
||||||
convar_t *look_filter;
|
convar_t *look_filter;
|
||||||
convar_t *m_rawinput;
|
convar_t *m_rawinput;
|
||||||
|
|
||||||
static qboolean s_bRawInput, s_bMouseGrab;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
================
|
================
|
||||||
IN_CollectInputDevices
|
IN_CollectInputDevices
|
||||||
|
@ -63,7 +61,7 @@ uint IN_CollectInputDevices( void )
|
||||||
if( !m_ignore->value ) // no way to check is mouse connected, so use cvar only
|
if( !m_ignore->value ) // no way to check is mouse connected, so use cvar only
|
||||||
ret |= INPUT_DEVICE_MOUSE;
|
ret |= INPUT_DEVICE_MOUSE;
|
||||||
|
|
||||||
if( CVAR_TO_BOOL(touch_enable) )
|
if( touch_enable.value )
|
||||||
ret |= INPUT_DEVICE_TOUCH;
|
ret |= INPUT_DEVICE_TOUCH;
|
||||||
|
|
||||||
if( Joy_IsActive() ) // connected or enabled
|
if( Joy_IsActive() ) // connected or enabled
|
||||||
|
@ -94,13 +92,13 @@ void IN_LockInputDevices( qboolean lock )
|
||||||
{
|
{
|
||||||
SetBits( m_ignore->flags, FCVAR_READ_ONLY );
|
SetBits( m_ignore->flags, FCVAR_READ_ONLY );
|
||||||
SetBits( joy_enable->flags, FCVAR_READ_ONLY );
|
SetBits( joy_enable->flags, FCVAR_READ_ONLY );
|
||||||
SetBits( touch_enable->flags, FCVAR_READ_ONLY );
|
SetBits( touch_enable.flags, FCVAR_READ_ONLY );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ClearBits( m_ignore->flags, FCVAR_READ_ONLY );
|
ClearBits( m_ignore->flags, FCVAR_READ_ONLY );
|
||||||
ClearBits( joy_enable->flags, FCVAR_READ_ONLY );
|
ClearBits( joy_enable->flags, FCVAR_READ_ONLY );
|
||||||
ClearBits( touch_enable->flags, FCVAR_READ_ONLY );
|
ClearBits( touch_enable.flags, FCVAR_READ_ONLY );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,19 +171,15 @@ Called when key_dest is changed
|
||||||
*/
|
*/
|
||||||
void IN_ToggleClientMouse( int newstate, int oldstate )
|
void IN_ToggleClientMouse( int newstate, int oldstate )
|
||||||
{
|
{
|
||||||
if( newstate == oldstate ) return;
|
if( newstate == oldstate )
|
||||||
|
return;
|
||||||
|
|
||||||
if( oldstate == key_game )
|
// since SetCursorType controls cursor visibility
|
||||||
|
// execute it first, and then check mouse grab state
|
||||||
|
if( newstate == key_menu || newstate == key_console || newstate == key_message )
|
||||||
{
|
{
|
||||||
IN_DeactivateMouse();
|
Platform_SetCursorType( dc_arrow );
|
||||||
}
|
|
||||||
else if( newstate == key_game )
|
|
||||||
{
|
|
||||||
IN_ActivateMouse();
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ( newstate == key_menu || newstate == key_console || newstate == key_message ) && ( !CL_IsBackgroundMap() || CL_IsBackgroundDemo( )))
|
|
||||||
{
|
|
||||||
#if XASH_ANDROID
|
#if XASH_ANDROID
|
||||||
Android_ShowMouse( true );
|
Android_ShowMouse( true );
|
||||||
#endif
|
#endif
|
||||||
|
@ -195,6 +189,8 @@ void IN_ToggleClientMouse( int newstate, int oldstate )
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Platform_SetCursorType( dc_none );
|
||||||
|
|
||||||
#if XASH_ANDROID
|
#if XASH_ANDROID
|
||||||
Android_ShowMouse( false );
|
Android_ShowMouse( false );
|
||||||
#endif
|
#endif
|
||||||
|
@ -202,10 +198,21 @@ void IN_ToggleClientMouse( int newstate, int oldstate )
|
||||||
Evdev_SetGrab( true );
|
Evdev_SetGrab( true );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( oldstate == key_game )
|
||||||
|
{
|
||||||
|
IN_DeactivateMouse();
|
||||||
|
}
|
||||||
|
else if( newstate == key_game )
|
||||||
|
{
|
||||||
|
IN_ActivateMouse();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IN_CheckMouseState( qboolean active )
|
void IN_CheckMouseState( qboolean active )
|
||||||
{
|
{
|
||||||
|
static qboolean s_bRawInput, s_bMouseGrab;
|
||||||
|
|
||||||
#if XASH_WIN32
|
#if XASH_WIN32
|
||||||
qboolean useRawInput = CVAR_TO_BOOL( m_rawinput ) && clgame.client_dll_uses_sdl || clgame.dllFuncs.pfnLookEvent;
|
qboolean useRawInput = CVAR_TO_BOOL( m_rawinput ) && clgame.client_dll_uses_sdl || clgame.dllFuncs.pfnLookEvent;
|
||||||
#else
|
#else
|
||||||
|
@ -308,25 +315,25 @@ IN_MouseMove
|
||||||
*/
|
*/
|
||||||
void IN_MouseMove( void )
|
void IN_MouseMove( void )
|
||||||
{
|
{
|
||||||
POINT current_pos;
|
int x, y;
|
||||||
|
|
||||||
if( !in_mouseinitialized )
|
if( !in_mouseinitialized )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if( touch_emulate.value )
|
||||||
|
{
|
||||||
|
// touch emulation overrides all input
|
||||||
|
Touch_KeyEvent( 0, 0 );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// find mouse movement
|
// find mouse movement
|
||||||
Platform_GetMousePos( ¤t_pos.x, ¤t_pos.y );
|
Platform_GetMousePos( &x, &y );
|
||||||
|
|
||||||
VGui_MouseMove( current_pos.x, current_pos.y );
|
VGui_MouseMove( x, y );
|
||||||
|
|
||||||
// HACKHACK: show cursor in UI, as mainui doesn't call
|
|
||||||
// platform-dependent SetCursor anymore
|
|
||||||
#if XASH_SDL
|
|
||||||
if( UI_IsVisible() )
|
|
||||||
SDL_ShowCursor( SDL_TRUE );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// if the menu is visible, move the menu cursor
|
// if the menu is visible, move the menu cursor
|
||||||
UI_MouseMove( current_pos.x, current_pos.y );
|
UI_MouseMove( x, y );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -336,8 +343,6 @@ IN_MouseEvent
|
||||||
*/
|
*/
|
||||||
void IN_MouseEvent( int key, int down )
|
void IN_MouseEvent( int key, int down )
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
if( !in_mouseinitialized )
|
if( !in_mouseinitialized )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -345,10 +350,15 @@ void IN_MouseEvent( int key, int down )
|
||||||
SetBits( in_mstate, BIT( key ));
|
SetBits( in_mstate, BIT( key ));
|
||||||
else ClearBits( in_mstate, BIT( key ));
|
else ClearBits( in_mstate, BIT( key ));
|
||||||
|
|
||||||
if( cls.key_dest == key_game )
|
// touch emulation overrides all input
|
||||||
|
if( touch_emulate.value )
|
||||||
|
{
|
||||||
|
Touch_KeyEvent( K_MOUSE1 + key, down );
|
||||||
|
}
|
||||||
|
else if( cls.key_dest == key_game )
|
||||||
{
|
{
|
||||||
// perform button actions
|
// perform button actions
|
||||||
VGui_KeyEvent( K_MOUSE1 + key, down );
|
VGui_MouseEvent( K_MOUSE1 + key, down );
|
||||||
|
|
||||||
// don't do Key_Event here
|
// don't do Key_Event here
|
||||||
// client may override IN_MouseEvent
|
// client may override IN_MouseEvent
|
||||||
|
@ -363,6 +373,23 @@ void IN_MouseEvent( int key, int down )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
==============
|
||||||
|
IN_MWheelEvent
|
||||||
|
|
||||||
|
direction is negative for wheel down, otherwise wheel up
|
||||||
|
==============
|
||||||
|
*/
|
||||||
|
void IN_MWheelEvent( int y )
|
||||||
|
{
|
||||||
|
int b = y > 0 ? K_MWHEELUP : K_MWHEELDOWN;
|
||||||
|
|
||||||
|
VGui_MWheelEvent( y );
|
||||||
|
|
||||||
|
Key_Event( b, true );
|
||||||
|
Key_Event( b, false );
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
===========
|
===========
|
||||||
IN_Shutdown
|
IN_Shutdown
|
||||||
|
|
|
@ -34,6 +34,7 @@ void IN_Init( void );
|
||||||
void Host_InputFrame( void );
|
void Host_InputFrame( void );
|
||||||
void IN_Shutdown( void );
|
void IN_Shutdown( void );
|
||||||
void IN_MouseEvent( int key, int down );
|
void IN_MouseEvent( int key, int down );
|
||||||
|
void IN_MWheelEvent( int direction );
|
||||||
void IN_ActivateMouse( void );
|
void IN_ActivateMouse( void );
|
||||||
void IN_DeactivateMouse( void );
|
void IN_DeactivateMouse( void );
|
||||||
void IN_MouseSavePos( void );
|
void IN_MouseSavePos( void );
|
||||||
|
@ -57,8 +58,8 @@ typedef enum
|
||||||
event_motion
|
event_motion
|
||||||
} touchEventType;
|
} touchEventType;
|
||||||
|
|
||||||
extern convar_t *touch_enable;
|
extern convar_t touch_enable;
|
||||||
extern convar_t *touch_emulate;
|
extern convar_t touch_emulate;
|
||||||
|
|
||||||
void Touch_Draw( void );
|
void Touch_Draw( void );
|
||||||
void Touch_SetClientOnly( byte state );
|
void Touch_SetClientOnly( byte state );
|
||||||
|
@ -73,6 +74,7 @@ void Touch_GetMove( float * forward, float *side, float *yaw, float *pitch );
|
||||||
void Touch_ResetDefaultButtons( void );
|
void Touch_ResetDefaultButtons( void );
|
||||||
int IN_TouchEvent( touchEventType type, int fingerID, float x, float y, float dx, float dy );
|
int IN_TouchEvent( touchEventType type, int fingerID, float x, float y, float dx, float dy );
|
||||||
void Touch_KeyEvent( int key, int down );
|
void Touch_KeyEvent( int key, int down );
|
||||||
|
qboolean Touch_WantVisibleCursor( void );
|
||||||
|
|
||||||
//
|
//
|
||||||
// in_joy.c
|
// in_joy.c
|
||||||
|
|
|
@ -104,9 +104,9 @@ keyname_t keynames[] =
|
||||||
{"B_BUTTON", K_B_BUTTON, "+use"},
|
{"B_BUTTON", K_B_BUTTON, "+use"},
|
||||||
{"X_BUTTON", K_X_BUTTON, "+reload"},
|
{"X_BUTTON", K_X_BUTTON, "+reload"},
|
||||||
{"Y_BUTTON", K_Y_BUTTON, "impulse 100"}, // Flashlight
|
{"Y_BUTTON", K_Y_BUTTON, "impulse 100"}, // Flashlight
|
||||||
{"BACK", K_BACK_BUTTON, "cancelselect"}, // Menu
|
{"BACK", K_BACK_BUTTON, "pause"}, // Menu
|
||||||
{"MODE", K_MODE_BUTTON, ""},
|
{"MODE", K_MODE_BUTTON, ""},
|
||||||
{"START", K_START_BUTTON, "pause"},
|
{"START", K_START_BUTTON, "escape"},
|
||||||
{"STICK1", K_LSTICK, "+speed"},
|
{"STICK1", K_LSTICK, "+speed"},
|
||||||
{"STICK2", K_RSTICK, "+duck"},
|
{"STICK2", K_RSTICK, "+duck"},
|
||||||
{"L1_BUTTON", K_L1_BUTTON, "+duck"},
|
{"L1_BUTTON", K_L1_BUTTON, "+duck"},
|
||||||
|
@ -123,13 +123,13 @@ keyname_t keynames[] =
|
||||||
{"JOY4" , K_JOY4 , ""},
|
{"JOY4" , K_JOY4 , ""},
|
||||||
{"C_BUTTON", K_C_BUTTON, ""},
|
{"C_BUTTON", K_C_BUTTON, ""},
|
||||||
{"Z_BUTTON", K_Z_BUTTON, ""},
|
{"Z_BUTTON", K_Z_BUTTON, ""},
|
||||||
{"AUX20", K_AUX20, ""}, // generic
|
{"MISC_BUTTON", K_MISC_BUTTON, ""},
|
||||||
{"AUX21", K_AUX21, ""},
|
{"PADDLE1", K_PADDLE1_BUTTON, ""},
|
||||||
{"AUX22", K_AUX22, ""},
|
{"PADDLE2", K_PADDLE2_BUTTON, ""},
|
||||||
{"AUX23", K_AUX23, ""},
|
{"PADDLE3", K_PADDLE3_BUTTON, ""},
|
||||||
{"AUX24", K_AUX24, ""},
|
{"PADDLE4", K_PADDLE4_BUTTON, ""},
|
||||||
{"AUX25", K_AUX25, ""},
|
{"TOUCHPAD", K_TOUCHPAD, ""},
|
||||||
{"AUX26", K_AUX26, ""},
|
{"AUX26", K_AUX26, ""}, // generic
|
||||||
{"AUX27", K_AUX27, ""},
|
{"AUX27", K_AUX27, ""},
|
||||||
{"AUX28", K_AUX28, ""},
|
{"AUX28", K_AUX28, ""},
|
||||||
{"AUX29", K_AUX29, ""},
|
{"AUX29", K_AUX29, ""},
|
||||||
|
@ -374,7 +374,7 @@ void Key_Unbindall_f( void )
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for( i = 0; i < 256; i++ )
|
for( i = 0; i < ARRAYSIZE( keys ); i++ )
|
||||||
{
|
{
|
||||||
if( keys[i].binding )
|
if( keys[i].binding )
|
||||||
Key_SetBinding( i, "" );
|
Key_SetBinding( i, "" );
|
||||||
|
@ -382,6 +382,7 @@ void Key_Unbindall_f( void )
|
||||||
|
|
||||||
// set some defaults
|
// set some defaults
|
||||||
Key_SetBinding( K_ESCAPE, "escape" );
|
Key_SetBinding( K_ESCAPE, "escape" );
|
||||||
|
Key_SetBinding( K_START_BUTTON, "escape" );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -395,7 +396,7 @@ void Key_Reset_f( void )
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
// clear all keys first
|
// clear all keys first
|
||||||
for( i = 0; i < 256; i++ )
|
for( i = 0; i < ARRAYSIZE( keys ); i++ )
|
||||||
{
|
{
|
||||||
if( keys[i].binding )
|
if( keys[i].binding )
|
||||||
Key_SetBinding( i, "" );
|
Key_SetBinding( i, "" );
|
||||||
|
@ -712,7 +713,6 @@ void GAME_EXPORT Key_Event( int key, int down )
|
||||||
}
|
}
|
||||||
|
|
||||||
VGui_KeyEvent( key, down );
|
VGui_KeyEvent( key, down );
|
||||||
Touch_KeyEvent( key, down );
|
|
||||||
|
|
||||||
// console key is hardcoded, so the user can never unbind it
|
// console key is hardcoded, so the user can never unbind it
|
||||||
if( key == '`' || key == '~' )
|
if( key == '`' || key == '~' )
|
||||||
|
@ -842,7 +842,9 @@ void GAME_EXPORT Key_SetKeyDest( int key_dest )
|
||||||
cls.key_dest = key_menu;
|
cls.key_dest = key_menu;
|
||||||
break;
|
break;
|
||||||
case key_console:
|
case key_console:
|
||||||
|
#if !XASH_NSWITCH // if we don't disable this, pops up the keyboard during load
|
||||||
Key_EnableTextInput( true, false );
|
Key_EnableTextInput( true, false );
|
||||||
|
#endif
|
||||||
cls.key_dest = key_console;
|
cls.key_dest = key_console;
|
||||||
break;
|
break;
|
||||||
case key_message:
|
case key_message:
|
||||||
|
@ -1149,7 +1151,7 @@ Draw button with symbol on it
|
||||||
*/
|
*/
|
||||||
static void OSK_DrawSymbolButton( int symb, float x, float y, float width, float height )
|
static void OSK_DrawSymbolButton( int symb, float x, float y, float width, float height )
|
||||||
{
|
{
|
||||||
char str[] = {symb & 255, 0};
|
cl_font_t *font = Con_GetCurFont();
|
||||||
byte color[] = { 255, 255, 255, 255 };
|
byte color[] = { 255, 255, 255, 255 };
|
||||||
int x1 = x * refState.width,
|
int x1 = x * refState.width,
|
||||||
y1 = y * refState.height,
|
y1 = y * refState.height,
|
||||||
|
@ -1157,14 +1159,15 @@ static void OSK_DrawSymbolButton( int symb, float x, float y, float width, float
|
||||||
h = height * refState.height;
|
h = height * refState.height;
|
||||||
|
|
||||||
if( symb == osk.curbutton.val )
|
if( symb == osk.curbutton.val )
|
||||||
{
|
|
||||||
ref.dllFuncs.FillRGBABlend( x1, y1, w, h, 255, 160, 0, 100 );
|
ref.dllFuncs.FillRGBABlend( x1, y1, w, h, 255, 160, 0, 100 );
|
||||||
}
|
|
||||||
|
|
||||||
if( !symb || symb == ' ' || (symb >= OSK_TAB && symb < OSK_SPECKEY_LAST ) )
|
if( !symb || symb == ' ' || (symb >= OSK_TAB && symb < OSK_SPECKEY_LAST ) )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Con_DrawCharacter( x1 + 1, y1, symb, color );
|
CL_DrawCharacter(
|
||||||
|
x1 + width * 0.4 * refState.width,
|
||||||
|
y1 + height * 0.4 * refState.height,
|
||||||
|
symb, color, font, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1178,7 +1181,11 @@ static void OSK_DrawSpecialButton( const char *name, float x, float y, float wid
|
||||||
{
|
{
|
||||||
byte color[] = { 0, 255, 0, 255 };
|
byte color[] = { 0, 255, 0, 255 };
|
||||||
|
|
||||||
Con_DrawString( x * refState.width, y * refState.height, name, color );
|
Con_DrawString(
|
||||||
|
x * refState.width + width * 0.4 * refState.width,
|
||||||
|
y * refState.height + height * 0.4 * refState.height,
|
||||||
|
name,
|
||||||
|
color );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -56,12 +56,11 @@ void GL_RenderFrame( const ref_viewpass_t *rvp )
|
||||||
|
|
||||||
VectorCopy( rvp->vieworigin, refState.vieworg );
|
VectorCopy( rvp->vieworigin, refState.vieworg );
|
||||||
VectorCopy( rvp->viewangles, refState.viewangles );
|
VectorCopy( rvp->viewangles, refState.viewangles );
|
||||||
AngleVectors( refState.viewangles, refState.vforward, refState.vright, refState.vup );
|
|
||||||
|
|
||||||
ref.dllFuncs.GL_RenderFrame( rvp );
|
ref.dllFuncs.GL_RenderFrame( rvp );
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pfnEngineGetParm( int parm, int arg )
|
static intptr_t pfnEngineGetParm( int parm, int arg )
|
||||||
{
|
{
|
||||||
return CL_RenderGetParm( parm, arg, false ); // prevent recursion
|
return CL_RenderGetParm( parm, arg, false ); // prevent recursion
|
||||||
}
|
}
|
||||||
|
@ -152,7 +151,7 @@ static player_info_t *pfnPlayerInfo( int index )
|
||||||
if( index == -1 ) // special index for menu
|
if( index == -1 ) // special index for menu
|
||||||
return &gameui.playerinfo;
|
return &gameui.playerinfo;
|
||||||
|
|
||||||
if( index < 0 || index > cl.maxclients )
|
if( index < 0 || index >= cl.maxclients )
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return &cl.players[index];
|
return &cl.players[index];
|
||||||
|
@ -280,9 +279,6 @@ static ref_api_t gEngfuncs =
|
||||||
Mod_PointInLeaf,
|
Mod_PointInLeaf,
|
||||||
Mod_CreatePolygonsForHull,
|
Mod_CreatePolygonsForHull,
|
||||||
|
|
||||||
R_StudioSlerpBones,
|
|
||||||
R_StudioCalcBoneQuaternion,
|
|
||||||
R_StudioCalcBonePosition,
|
|
||||||
R_StudioGetAnim,
|
R_StudioGetAnim,
|
||||||
pfnStudioEvent,
|
pfnStudioEvent,
|
||||||
|
|
||||||
|
@ -360,7 +356,7 @@ static ref_api_t gEngfuncs =
|
||||||
|
|
||||||
pfnGetPhysent,
|
pfnGetPhysent,
|
||||||
pfnTraceSurface,
|
pfnTraceSurface,
|
||||||
PM_TraceLine,
|
PM_CL_TraceLine,
|
||||||
CL_VisTraceLine,
|
CL_VisTraceLine,
|
||||||
CL_TraceLine,
|
CL_TraceLine,
|
||||||
pfnGetMoveVars,
|
pfnGetMoveVars,
|
||||||
|
|
|
@ -14,6 +14,7 @@ GNU General Public License for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "client.h"
|
||||||
#include "sound.h"
|
#include "sound.h"
|
||||||
|
|
||||||
// during registration it is possible to have more sounds
|
// during registration it is possible to have more sounds
|
||||||
|
@ -28,7 +29,6 @@ static sfx_t s_knownSfx[MAX_SFX];
|
||||||
static sfx_t *s_sfxHashList[MAX_SFX_HASH];
|
static sfx_t *s_sfxHashList[MAX_SFX_HASH];
|
||||||
static string s_sentenceImmediateName; // keep dummy sentence name
|
static string s_sentenceImmediateName; // keep dummy sentence name
|
||||||
qboolean s_registering = false;
|
qboolean s_registering = false;
|
||||||
int s_registration_sequence = 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=================
|
=================
|
||||||
|
@ -199,7 +199,7 @@ sfx_t *S_FindName( const char *pname, int *pfInCache )
|
||||||
*pfInCache = ( sfx->cache != NULL ) ? true : false;
|
*pfInCache = ( sfx->cache != NULL ) ? true : false;
|
||||||
}
|
}
|
||||||
// prolonge registration
|
// prolonge registration
|
||||||
sfx->servercount = s_registration_sequence;
|
sfx->servercount = cl.servercount;
|
||||||
return sfx;
|
return sfx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -219,7 +219,7 @@ sfx_t *S_FindName( const char *pname, int *pfInCache )
|
||||||
memset( sfx, 0, sizeof( *sfx ));
|
memset( sfx, 0, sizeof( *sfx ));
|
||||||
if( pfInCache ) *pfInCache = false;
|
if( pfInCache ) *pfInCache = false;
|
||||||
Q_strncpy( sfx->name, name, MAX_STRING );
|
Q_strncpy( sfx->name, name, MAX_STRING );
|
||||||
sfx->servercount = s_registration_sequence;
|
sfx->servercount = cl.servercount;
|
||||||
sfx->hashValue = COM_HashKey( sfx->name, MAX_SFX_HASH );
|
sfx->hashValue = COM_HashKey( sfx->name, MAX_SFX_HASH );
|
||||||
|
|
||||||
// link it in
|
// link it in
|
||||||
|
@ -273,7 +273,6 @@ void S_BeginRegistration( void )
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
s_registration_sequence++;
|
|
||||||
snd_ambient = false;
|
snd_ambient = false;
|
||||||
|
|
||||||
// check for automatic ambient sounds
|
// check for automatic ambient sounds
|
||||||
|
@ -309,7 +308,7 @@ void S_EndRegistration( void )
|
||||||
if( !sfx->name[0] || !Q_stricmp( sfx->name, "*default" ))
|
if( !sfx->name[0] || !Q_stricmp( sfx->name, "*default" ))
|
||||||
continue; // don't release default sound
|
continue; // don't release default sound
|
||||||
|
|
||||||
if( sfx->servercount != s_registration_sequence )
|
if( sfx->servercount != cl.servercount )
|
||||||
S_FreeSound( sfx ); // don't need this sound
|
S_FreeSound( sfx ); // don't need this sound
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,7 +348,7 @@ sound_t S_RegisterSound( const char *name )
|
||||||
sfx = S_FindName( name, NULL );
|
sfx = S_FindName( name, NULL );
|
||||||
if( !sfx ) return -1;
|
if( !sfx ) return -1;
|
||||||
|
|
||||||
sfx->servercount = s_registration_sequence;
|
sfx->servercount = cl.servercount;
|
||||||
if( !s_registering ) S_LoadSound( sfx );
|
if( !s_registering ) S_LoadSound( sfx );
|
||||||
|
|
||||||
return sfx - s_knownSfx;
|
return sfx - s_knownSfx;
|
||||||
|
|
|
@ -533,8 +533,6 @@ void S_StartSound( const vec3_t pos, int ent, int chan, sound_t handle, float fv
|
||||||
// spatialize
|
// spatialize
|
||||||
memset( target_chan, 0, sizeof( *target_chan ));
|
memset( target_chan, 0, sizeof( *target_chan ));
|
||||||
|
|
||||||
pitch *= (sys_timescale.value + 1) / 2;
|
|
||||||
|
|
||||||
VectorCopy( pos, target_chan->origin );
|
VectorCopy( pos, target_chan->origin );
|
||||||
target_chan->staticsound = ( ent == 0 ) ? true : false;
|
target_chan->staticsound = ( ent == 0 ) ? true : false;
|
||||||
target_chan->use_loop = (flags & SND_STOP_LOOPING) ? false : true;
|
target_chan->use_loop = (flags & SND_STOP_LOOPING) ? false : true;
|
||||||
|
@ -1129,7 +1127,7 @@ static uint S_RawSamplesStereo( portable_samplepair_t *rawsamples, uint rawend,
|
||||||
S_RawEntSamples
|
S_RawEntSamples
|
||||||
===================
|
===================
|
||||||
*/
|
*/
|
||||||
static void S_RawEntSamples( int entnum, uint samples, uint rate, word width, word channels, const byte *data, int snd_vol )
|
void S_RawEntSamples( int entnum, uint samples, uint rate, word width, word channels, const byte *data, int snd_vol )
|
||||||
{
|
{
|
||||||
rawchan_t *ch;
|
rawchan_t *ch;
|
||||||
|
|
||||||
|
@ -1289,6 +1287,9 @@ static void S_FreeIdleRawChannels( void )
|
||||||
if( ch->s_rawend >= paintedtime )
|
if( ch->s_rawend >= paintedtime )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if ( ch->entnum > 0 )
|
||||||
|
SND_ForceCloseMouth( ch->entnum );
|
||||||
|
|
||||||
if(( paintedtime - ch->s_rawend ) / SOUND_DMA_SPEED >= S_RAW_SOUND_IDLE_SEC )
|
if(( paintedtime - ch->s_rawend ) / SOUND_DMA_SPEED >= S_RAW_SOUND_IDLE_SEC )
|
||||||
{
|
{
|
||||||
raw_channels[i] = NULL;
|
raw_channels[i] = NULL;
|
||||||
|
@ -1850,7 +1851,7 @@ S_SoundInfo_f
|
||||||
*/
|
*/
|
||||||
void S_SoundInfo_f( void )
|
void S_SoundInfo_f( void )
|
||||||
{
|
{
|
||||||
Con_Printf( "Audio: DirectSound\n" );
|
Con_Printf( "Audio backend: %s\n", dma.backendName );
|
||||||
Con_Printf( "%5d channel(s)\n", 2 );
|
Con_Printf( "%5d channel(s)\n", 2 );
|
||||||
Con_Printf( "%5d samples\n", dma.samples );
|
Con_Printf( "%5d samples\n", dma.samples );
|
||||||
Con_Printf( "%5d bits/sample\n", 16 );
|
Con_Printf( "%5d bits/sample\n", 16 );
|
||||||
|
@ -1860,6 +1861,33 @@ void S_SoundInfo_f( void )
|
||||||
S_PrintBackgroundTrackState ();
|
S_PrintBackgroundTrackState ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=================
|
||||||
|
S_VoiceRecordStart_f
|
||||||
|
=================
|
||||||
|
*/
|
||||||
|
void S_VoiceRecordStart_f( void )
|
||||||
|
{
|
||||||
|
if( cls.state != ca_active || cls.legacymode )
|
||||||
|
return;
|
||||||
|
|
||||||
|
Voice_RecordStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=================
|
||||||
|
S_VoiceRecordStop_f
|
||||||
|
=================
|
||||||
|
*/
|
||||||
|
void S_VoiceRecordStop_f( void )
|
||||||
|
{
|
||||||
|
if( cls.state != ca_active || !Voice_IsRecording() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
CL_AddVoiceToDatagram();
|
||||||
|
Voice_RecordStop();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
================
|
================
|
||||||
S_Init
|
S_Init
|
||||||
|
@ -1894,11 +1922,12 @@ qboolean S_Init( void )
|
||||||
Cmd_AddCommand( "soundlist", S_SoundList_f, "display loaded sounds" );
|
Cmd_AddCommand( "soundlist", S_SoundList_f, "display loaded sounds" );
|
||||||
Cmd_AddCommand( "s_info", S_SoundInfo_f, "print sound system information" );
|
Cmd_AddCommand( "s_info", S_SoundInfo_f, "print sound system information" );
|
||||||
Cmd_AddCommand( "s_fade", S_SoundFade_f, "fade all sounds then stop all" );
|
Cmd_AddCommand( "s_fade", S_SoundFade_f, "fade all sounds then stop all" );
|
||||||
Cmd_AddCommand( "+voicerecord", Cmd_Null_f, "start voice recording (non-implemented)" );
|
Cmd_AddCommand( "+voicerecord", S_VoiceRecordStart_f, "start voice recording" );
|
||||||
Cmd_AddCommand( "-voicerecord", Cmd_Null_f, "stop voice recording (non-implemented)" );
|
Cmd_AddCommand( "-voicerecord", S_VoiceRecordStop_f, "stop voice recording" );
|
||||||
Cmd_AddCommand( "spk", S_SayReliable_f, "reliable play a specified sententce" );
|
Cmd_AddCommand( "spk", S_SayReliable_f, "reliable play a specified sententce" );
|
||||||
Cmd_AddCommand( "speak", S_Say_f, "playing a specified sententce" );
|
Cmd_AddCommand( "speak", S_Say_f, "playing a specified sententce" );
|
||||||
|
|
||||||
|
dma.backendName = "None";
|
||||||
if( !SNDDMA_Init( ) )
|
if( !SNDDMA_Init( ) )
|
||||||
{
|
{
|
||||||
Con_Printf( "Audio: sound system can't be initialized\n" );
|
Con_Printf( "Audio: sound system can't be initialized\n" );
|
||||||
|
|
|
@ -619,7 +619,9 @@ void MIX_MixChannelsToPaintbuffer( int endtime, int rate, int outputRate )
|
||||||
ch->pitch = VOX_ModifyPitch( ch, ch->basePitch * 0.01f );
|
ch->pitch = VOX_ModifyPitch( ch, ch->basePitch * 0.01f );
|
||||||
else ch->pitch = ch->basePitch * 0.01f;
|
else ch->pitch = ch->basePitch * 0.01f;
|
||||||
|
|
||||||
if( CL_GetEntityByIndex( ch->entnum ) && ( ch->entchannel == CHAN_VOICE ))
|
ch->pitch *= ( sys_timescale.value + 1 ) / 2;
|
||||||
|
|
||||||
|
if( CL_GetEntityByIndex( ch->entnum ) && ( ch->entchannel == CHAN_VOICE || ch->entchannel == CHAN_STREAM ))
|
||||||
{
|
{
|
||||||
if( pSource->width == 1 )
|
if( pSource->width == 1 )
|
||||||
SND_MoveMouth8( ch, pSource, sampleCount );
|
SND_MoveMouth8( ch, pSource, sampleCount );
|
||||||
|
@ -895,43 +897,13 @@ void S_MixUpsample( int sampleCount, int filtertype )
|
||||||
ppaint->ifilter++;
|
ppaint->ifilter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MIX_MixStreamBuffer( int end )
|
|
||||||
{
|
|
||||||
portable_samplepair_t *pbuf;
|
|
||||||
rawchan_t *ch;
|
|
||||||
|
|
||||||
pbuf = MIX_GetPFrontFromIPaint( ISTREAMBUFFER );
|
|
||||||
ch = S_FindRawChannel( S_RAW_SOUND_BACKGROUNDTRACK, false );
|
|
||||||
|
|
||||||
// clear the paint buffer
|
|
||||||
if( s_listener.paused || !ch || ch->s_rawend < paintedtime )
|
|
||||||
{
|
|
||||||
memset( pbuf, 0, (end - paintedtime) * sizeof( portable_samplepair_t ));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int i, stop;
|
|
||||||
|
|
||||||
// copy from the streaming sound source
|
|
||||||
stop = (end < ch->s_rawend) ? end : ch->s_rawend;
|
|
||||||
|
|
||||||
for( i = paintedtime; i < stop; i++ )
|
|
||||||
{
|
|
||||||
pbuf[i-paintedtime].left = ( ch->rawsamples[i & ( ch->max_samples - 1 )].left * ch->leftvol ) >> 8;
|
|
||||||
pbuf[i-paintedtime].right = ( ch->rawsamples[i & ( ch->max_samples - 1 )].right * ch->rightvol ) >> 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
for( ; i < end; i++ )
|
|
||||||
pbuf[i-paintedtime].left = pbuf[i-paintedtime].right = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MIX_MixRawSamplesBuffer( int end )
|
void MIX_MixRawSamplesBuffer( int end )
|
||||||
{
|
{
|
||||||
portable_samplepair_t *pbuf;
|
portable_samplepair_t *pbuf, *roombuf, *streambuf;
|
||||||
uint i, j, stop;
|
uint i, j, stop;
|
||||||
|
|
||||||
pbuf = MIX_GetCurrentPaintbufferPtr()->pbuf;
|
roombuf = MIX_GetPFrontFromIPaint( IROOMBUFFER );
|
||||||
|
streambuf = MIX_GetPFrontFromIPaint( ISTREAMBUFFER );
|
||||||
|
|
||||||
if( s_listener.paused ) return;
|
if( s_listener.paused ) return;
|
||||||
|
|
||||||
|
@ -940,15 +912,18 @@ void MIX_MixRawSamplesBuffer( int end )
|
||||||
{
|
{
|
||||||
// copy from the streaming sound source
|
// copy from the streaming sound source
|
||||||
rawchan_t *ch = raw_channels[i];
|
rawchan_t *ch = raw_channels[i];
|
||||||
|
qboolean stream;
|
||||||
|
|
||||||
// background track should be mixing into another buffer
|
if( !ch )
|
||||||
if( !ch || ch->entnum == S_RAW_SOUND_BACKGROUNDTRACK )
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// not audible
|
// not audible
|
||||||
if( !ch->leftvol && !ch->rightvol )
|
if( !ch->leftvol && !ch->rightvol )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
stream = ch->entnum == S_RAW_SOUND_BACKGROUNDTRACK || CL_IsPlayerIndex( ch->entnum );
|
||||||
|
pbuf = stream ? streambuf : roombuf;
|
||||||
|
|
||||||
stop = (end < ch->s_rawend) ? end : ch->s_rawend;
|
stop = (end < ch->s_rawend) ? end : ch->s_rawend;
|
||||||
|
|
||||||
for( j = paintedtime; j < stop; j++ )
|
for( j = paintedtime; j < stop; j++ )
|
||||||
|
@ -956,6 +931,9 @@ void MIX_MixRawSamplesBuffer( int end )
|
||||||
pbuf[j-paintedtime].left += ( ch->rawsamples[j & ( ch->max_samples - 1 )].left * ch->leftvol ) >> 8;
|
pbuf[j-paintedtime].left += ( ch->rawsamples[j & ( ch->max_samples - 1 )].left * ch->leftvol ) >> 8;
|
||||||
pbuf[j-paintedtime].right += ( ch->rawsamples[j & ( ch->max_samples - 1 )].right * ch->rightvol ) >> 8;
|
pbuf[j-paintedtime].right += ( ch->rawsamples[j & ( ch->max_samples - 1 )].right * ch->rightvol ) >> 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( ch->entnum > 0 )
|
||||||
|
SND_MoveMouthRaw( ch, &ch->rawsamples[paintedtime & ( ch->max_samples - 1 )], stop - paintedtime );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -965,9 +943,6 @@ void MIX_MixRawSamplesBuffer( int end )
|
||||||
// caller also remixes all into final IPAINTBUFFER output.
|
// caller also remixes all into final IPAINTBUFFER output.
|
||||||
void MIX_UpsampleAllPaintbuffers( int end, int count )
|
void MIX_UpsampleAllPaintbuffers( int end, int count )
|
||||||
{
|
{
|
||||||
// process stream buffer
|
|
||||||
MIX_MixStreamBuffer( end );
|
|
||||||
|
|
||||||
// 11khz sounds are mixed into 3 buffers based on distance from listener, and facing direction
|
// 11khz sounds are mixed into 3 buffers based on distance from listener, and facing direction
|
||||||
// These buffers are facing, facingaway, room
|
// These buffers are facing, facingaway, room
|
||||||
// These 3 mixed buffers are then each upsampled to 22khz.
|
// These 3 mixed buffers are then each upsampled to 22khz.
|
||||||
|
@ -1009,7 +984,6 @@ void MIX_UpsampleAllPaintbuffers( int end, int count )
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// mix raw samples from the video streams
|
// mix raw samples from the video streams
|
||||||
MIX_SetCurrentPaintbuffer( IROOMBUFFER );
|
|
||||||
MIX_MixRawSamplesBuffer( end );
|
MIX_MixRawSamplesBuffer( end );
|
||||||
|
|
||||||
MIX_DeactivateAllPaintbuffers();
|
MIX_DeactivateAllPaintbuffers();
|
||||||
|
|
|
@ -24,17 +24,7 @@ void SND_InitMouth( int entnum, int entchannel )
|
||||||
{
|
{
|
||||||
if(( entchannel == CHAN_VOICE || entchannel == CHAN_STREAM ) && entnum > 0 )
|
if(( entchannel == CHAN_VOICE || entchannel == CHAN_STREAM ) && entnum > 0 )
|
||||||
{
|
{
|
||||||
cl_entity_t *clientEntity;
|
SND_ForceInitMouth( entnum );
|
||||||
|
|
||||||
// init mouth movement vars
|
|
||||||
clientEntity = CL_GetEntityByIndex( entnum );
|
|
||||||
|
|
||||||
if( clientEntity )
|
|
||||||
{
|
|
||||||
clientEntity->mouth.mouthopen = 0;
|
|
||||||
clientEntity->mouth.sndcount = 0;
|
|
||||||
clientEntity->mouth.sndavg = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,15 +32,7 @@ void SND_CloseMouth( channel_t *ch )
|
||||||
{
|
{
|
||||||
if( ch->entchannel == CHAN_VOICE || ch->entchannel == CHAN_STREAM )
|
if( ch->entchannel == CHAN_VOICE || ch->entchannel == CHAN_STREAM )
|
||||||
{
|
{
|
||||||
cl_entity_t *clientEntity;
|
SND_ForceCloseMouth( ch->entnum );
|
||||||
|
|
||||||
clientEntity = CL_GetEntityByIndex( ch->entnum );
|
|
||||||
|
|
||||||
if( clientEntity )
|
|
||||||
{
|
|
||||||
// shut mouth
|
|
||||||
clientEntity->mouth.mouthopen = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,3 +132,68 @@ void SND_MoveMouth16( channel_t *ch, wavdata_t *pSource, int count )
|
||||||
pMouth->sndcount = 0;
|
pMouth->sndcount = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SND_ForceInitMouth( int entnum )
|
||||||
|
{
|
||||||
|
cl_entity_t *clientEntity;
|
||||||
|
|
||||||
|
clientEntity = CL_GetEntityByIndex( entnum );
|
||||||
|
|
||||||
|
if( clientEntity )
|
||||||
|
{
|
||||||
|
clientEntity->mouth.mouthopen = 0;
|
||||||
|
clientEntity->mouth.sndavg = 0;
|
||||||
|
clientEntity->mouth.sndcount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SND_ForceCloseMouth( int entnum )
|
||||||
|
{
|
||||||
|
cl_entity_t *clientEntity;
|
||||||
|
|
||||||
|
clientEntity = CL_GetEntityByIndex( entnum );
|
||||||
|
|
||||||
|
if( clientEntity )
|
||||||
|
clientEntity->mouth.mouthopen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SND_MoveMouthRaw( rawchan_t *ch, portable_samplepair_t *pData, int count )
|
||||||
|
{
|
||||||
|
cl_entity_t *clientEntity;
|
||||||
|
mouth_t *pMouth = NULL;
|
||||||
|
int savg, data;
|
||||||
|
int scount = 0;
|
||||||
|
uint i;
|
||||||
|
|
||||||
|
clientEntity = CL_GetEntityByIndex( ch->entnum );
|
||||||
|
if( !clientEntity ) return;
|
||||||
|
|
||||||
|
pMouth = &clientEntity->mouth;
|
||||||
|
|
||||||
|
if( pData == NULL )
|
||||||
|
return;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
scount = pMouth->sndcount;
|
||||||
|
savg = 0;
|
||||||
|
|
||||||
|
while ( i < count && scount < CAVGSAMPLES )
|
||||||
|
{
|
||||||
|
data = pData[i].left; // mono sound anyway
|
||||||
|
data = ( bound( -32767, data, 0x7ffe ) >> 8 );
|
||||||
|
savg += abs( data );
|
||||||
|
|
||||||
|
i += 80 + ( (byte)data & 0x1F );
|
||||||
|
scount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
pMouth->sndavg += savg;
|
||||||
|
pMouth->sndcount = (byte)scount;
|
||||||
|
|
||||||
|
if ( pMouth->sndcount >= CAVGSAMPLES )
|
||||||
|
{
|
||||||
|
pMouth->mouthopen = pMouth->sndavg / CAVGSAMPLES;
|
||||||
|
pMouth->sndavg = 0;
|
||||||
|
pMouth->sndcount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -117,6 +117,7 @@ typedef struct
|
||||||
int samplepos; // in mono samples
|
int samplepos; // in mono samples
|
||||||
byte *buffer;
|
byte *buffer;
|
||||||
qboolean initialized; // sound engine is active
|
qboolean initialized; // sound engine is active
|
||||||
|
const char *backendName;
|
||||||
} dma_t;
|
} dma_t;
|
||||||
|
|
||||||
#include "vox.h"
|
#include "vox.h"
|
||||||
|
@ -202,7 +203,7 @@ typedef struct
|
||||||
|
|
||||||
#define MAX_DYNAMIC_CHANNELS (60 + NUM_AMBIENTS)
|
#define MAX_DYNAMIC_CHANNELS (60 + NUM_AMBIENTS)
|
||||||
#define MAX_CHANNELS (256 + MAX_DYNAMIC_CHANNELS) // Scourge Of Armagon has too many static sounds on hip2m4.bsp
|
#define MAX_CHANNELS (256 + MAX_DYNAMIC_CHANNELS) // Scourge Of Armagon has too many static sounds on hip2m4.bsp
|
||||||
#define MAX_RAW_CHANNELS 16
|
#define MAX_RAW_CHANNELS 48
|
||||||
#define MAX_RAW_SAMPLES 8192
|
#define MAX_RAW_SAMPLES 8192
|
||||||
|
|
||||||
extern sound_t ambient_sfx[NUM_AMBIENTS];
|
extern sound_t ambient_sfx[NUM_AMBIENTS];
|
||||||
|
@ -271,6 +272,7 @@ int S_GetCurrentStaticSounds( soundlist_t *pout, int size );
|
||||||
int S_GetCurrentDynamicSounds( soundlist_t *pout, int size );
|
int S_GetCurrentDynamicSounds( soundlist_t *pout, int size );
|
||||||
sfx_t *S_GetSfxByHandle( sound_t handle );
|
sfx_t *S_GetSfxByHandle( sound_t handle );
|
||||||
rawchan_t *S_FindRawChannel( int entnum, qboolean create );
|
rawchan_t *S_FindRawChannel( int entnum, qboolean create );
|
||||||
|
void S_RawEntSamples( int entnum, uint samples, uint rate, word width, word channels, const byte *data, int snd_vol );
|
||||||
void S_RawSamples( uint samples, uint rate, word width, word channels, const byte *data, int entnum );
|
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_StopSound( int entnum, int channel, const char *soundname );
|
||||||
void S_UpdateFrame( struct ref_viewpass_s *rvp );
|
void S_UpdateFrame( struct ref_viewpass_s *rvp );
|
||||||
|
@ -283,9 +285,12 @@ void S_FreeSounds( void );
|
||||||
// s_mouth.c
|
// s_mouth.c
|
||||||
//
|
//
|
||||||
void SND_InitMouth( int entnum, int entchannel );
|
void SND_InitMouth( int entnum, int entchannel );
|
||||||
|
void SND_ForceInitMouth( int entnum );
|
||||||
void SND_MoveMouth8( channel_t *ch, wavdata_t *pSource, int count );
|
void SND_MoveMouth8( channel_t *ch, wavdata_t *pSource, int count );
|
||||||
void SND_MoveMouth16( channel_t *ch, wavdata_t *pSource, int count );
|
void SND_MoveMouth16( channel_t *ch, wavdata_t *pSource, int count );
|
||||||
|
void SND_MoveMouthRaw( rawchan_t *ch, portable_samplepair_t *pData, int count );
|
||||||
void SND_CloseMouth( channel_t *ch );
|
void SND_CloseMouth( channel_t *ch );
|
||||||
|
void SND_ForceCloseMouth( int entnum );
|
||||||
|
|
||||||
//
|
//
|
||||||
// s_stream.c
|
// s_stream.c
|
||||||
|
|
|
@ -23,53 +23,28 @@ GNU General Public License for more details.
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
|
|
||||||
static enum VGUI_KeyCode s_pVirtualKeyTrans[256];
|
CVAR_DEFINE_AUTO( vgui_utf8, "0", FCVAR_ARCHIVE, "enable utf-8 support for vgui text" );
|
||||||
static VGUI_DefaultCursor s_currentCursor;
|
|
||||||
static HINSTANCE s_pVGuiSupport; // vgui_support library
|
|
||||||
static convar_t *vgui_utf8 = NULL;
|
|
||||||
|
|
||||||
void GAME_EXPORT *VGUI_EngineMalloc(size_t size)
|
static void GAME_EXPORT *VGUI_EngineMalloc( size_t size );
|
||||||
|
static void GAME_EXPORT VGUI_GetMousePos( int *, int * );
|
||||||
|
static void GAME_EXPORT VGUI_CursorSelect( VGUI_DefaultCursor );
|
||||||
|
static byte GAME_EXPORT VGUI_GetColor( int, int );
|
||||||
|
static int GAME_EXPORT VGUI_UtfProcessChar( int in );
|
||||||
|
static qboolean GAME_EXPORT VGUI_IsInGame( void );
|
||||||
|
|
||||||
|
static struct
|
||||||
{
|
{
|
||||||
return Z_Malloc( size );
|
qboolean initialized;
|
||||||
}
|
vguiapi_t dllFuncs;
|
||||||
|
VGUI_DefaultCursor cursor;
|
||||||
|
|
||||||
qboolean GAME_EXPORT VGUI_IsInGame( void )
|
HINSTANCE hInstance;
|
||||||
{
|
|
||||||
return cls.state == ca_active && cls.key_dest == key_game;
|
enum VGUI_KeyCode virtualKeyTrans[256];
|
||||||
}
|
} vgui =
|
||||||
|
|
||||||
void GAME_EXPORT VGUI_GetMousePos( int *_x, int *_y )
|
|
||||||
{
|
|
||||||
float xscale = (float)refState.width / (float)clgame.scrInfo.iWidth;
|
|
||||||
float yscale = (float)refState.height / (float)clgame.scrInfo.iHeight;
|
|
||||||
int x, y;
|
|
||||||
|
|
||||||
Platform_GetMousePos( &x, &y );
|
|
||||||
*_x = x / xscale, *_y = y / yscale;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GAME_EXPORT VGUI_CursorSelect( VGUI_DefaultCursor cursor )
|
|
||||||
{
|
|
||||||
Platform_SetCursorType( cursor );
|
|
||||||
s_currentCursor = cursor;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte GAME_EXPORT VGUI_GetColor( int i, int j)
|
|
||||||
{
|
|
||||||
return g_color_table[i][j];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Define and initialize vgui API
|
|
||||||
int GAME_EXPORT VGUI_UtfProcessChar( int in )
|
|
||||||
{
|
|
||||||
if( CVAR_TO_BOOL( vgui_utf8 ))
|
|
||||||
return Con_UtfProcessCharForce( in );
|
|
||||||
else
|
|
||||||
return in;
|
|
||||||
}
|
|
||||||
|
|
||||||
vguiapi_t vgui =
|
|
||||||
{
|
{
|
||||||
|
false,
|
||||||
|
{
|
||||||
false, // Not initialized yet
|
false, // Not initialized yet
|
||||||
NULL, // VGUI_DrawInit,
|
NULL, // VGUI_DrawInit,
|
||||||
NULL, // VGUI_DrawShutdown,
|
NULL, // VGUI_DrawShutdown,
|
||||||
|
@ -88,28 +63,61 @@ vguiapi_t vgui =
|
||||||
VGUI_CursorSelect,
|
VGUI_CursorSelect,
|
||||||
VGUI_GetColor,
|
VGUI_GetColor,
|
||||||
VGUI_IsInGame,
|
VGUI_IsInGame,
|
||||||
NULL,
|
Key_EnableTextInput,
|
||||||
VGUI_GetMousePos,
|
VGUI_GetMousePos,
|
||||||
VGUI_UtfProcessChar,
|
VGUI_UtfProcessChar,
|
||||||
Platform_GetClipboardText,
|
Platform_GetClipboardText,
|
||||||
Platform_SetClipboardText,
|
Platform_SetClipboardText,
|
||||||
Platform_GetKeyModifiers,
|
Platform_GetKeyModifiers,
|
||||||
NULL,
|
},
|
||||||
NULL,
|
-1
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void GAME_EXPORT *VGUI_EngineMalloc( size_t size )
|
||||||
|
{
|
||||||
|
return Z_Malloc( size );
|
||||||
|
}
|
||||||
|
|
||||||
|
static qboolean GAME_EXPORT VGUI_IsInGame( void )
|
||||||
|
{
|
||||||
|
return cls.state == ca_active && cls.key_dest == key_game;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GAME_EXPORT VGUI_GetMousePos( int *_x, int *_y )
|
||||||
|
{
|
||||||
|
float xscale = (float)refState.width / (float)clgame.scrInfo.iWidth;
|
||||||
|
float yscale = (float)refState.height / (float)clgame.scrInfo.iHeight;
|
||||||
|
int x, y;
|
||||||
|
|
||||||
|
Platform_GetMousePos( &x, &y );
|
||||||
|
*_x = x / xscale;
|
||||||
|
*_y = y / yscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GAME_EXPORT VGUI_CursorSelect( VGUI_DefaultCursor cursor )
|
||||||
|
{
|
||||||
|
if( vgui.cursor != cursor )
|
||||||
|
Platform_SetCursorType( cursor );
|
||||||
|
}
|
||||||
|
|
||||||
|
static byte GAME_EXPORT VGUI_GetColor( int i, int j )
|
||||||
|
{
|
||||||
|
return g_color_table[i][j];
|
||||||
|
}
|
||||||
|
|
||||||
|
static int GAME_EXPORT VGUI_UtfProcessChar( int in )
|
||||||
|
{
|
||||||
|
if( vgui_utf8.value )
|
||||||
|
return Con_UtfProcessCharForce( in );
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
qboolean VGui_IsActive( void )
|
qboolean VGui_IsActive( void )
|
||||||
{
|
{
|
||||||
return vgui.initialized;
|
return vgui.initialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VGui_FillAPIFromRef( vguiapi_t *to, const ref_interface_t *from )
|
static void VGui_FillAPIFromRef( vguiapi_t *to, const ref_interface_t *from )
|
||||||
{
|
{
|
||||||
to->DrawInit = from->VGUI_DrawInit;
|
to->DrawInit = from->VGUI_DrawInit;
|
||||||
to->DrawShutdown = from->VGUI_DrawShutdown;
|
to->DrawShutdown = from->VGUI_DrawShutdown;
|
||||||
|
@ -126,137 +134,86 @@ void VGui_FillAPIFromRef( vguiapi_t *to, const ref_interface_t *from )
|
||||||
to->GenerateTexture = from->VGUI_GenerateTexture;
|
to->GenerateTexture = from->VGUI_GenerateTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VGui_RegisterCvars( void )
|
||||||
|
{
|
||||||
|
Cvar_RegisterVariable( &vgui_utf8 );
|
||||||
|
}
|
||||||
|
|
||||||
|
qboolean VGui_LoadProgs( HINSTANCE hInstance )
|
||||||
|
{
|
||||||
|
void (*F)( vguiapi_t* );
|
||||||
|
qboolean client = hInstance != NULL;
|
||||||
|
|
||||||
|
// not loading interface from client.dll, load vgui_support.dll instead
|
||||||
|
if( !client )
|
||||||
|
{
|
||||||
|
string vguiloader, vguilib;
|
||||||
|
|
||||||
|
// HACKHACK: try to load path from custom path
|
||||||
|
// to support having different versions of VGUI
|
||||||
|
if( Sys_GetParmFromCmdLine( "-vguilib", vguilib ) && !COM_LoadLibrary( vguilib, false, false ))
|
||||||
|
{
|
||||||
|
Con_Reportf( S_WARN "VGUI preloading failed. Default library will be used! Reason: %s", COM_GetLibraryError());
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !Sys_GetParmFromCmdLine( "-vguiloader", vguiloader ))
|
||||||
|
{
|
||||||
|
Q_strncpy( vguiloader, VGUI_SUPPORT_DLL, sizeof( vguiloader ));
|
||||||
|
}
|
||||||
|
|
||||||
|
hInstance = vgui.hInstance = COM_LoadLibrary( vguiloader, false, false );
|
||||||
|
|
||||||
|
if( !vgui.hInstance )
|
||||||
|
{
|
||||||
|
if( FS_FileExists( vguiloader, false ))
|
||||||
|
Con_Reportf( S_ERROR "Failed to load vgui_support library: %s\n", COM_GetLibraryError() );
|
||||||
|
else Con_Reportf( "vgui_support: not found\n" );
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// try legacy API first
|
||||||
|
F = COM_GetProcAddress( hInstance, client ? "InitVGUISupportAPI" : "InitAPI" );
|
||||||
|
|
||||||
|
if( F )
|
||||||
|
{
|
||||||
|
VGui_FillAPIFromRef( &vgui.dllFuncs, &ref.dllFuncs );
|
||||||
|
F( &vgui.dllFuncs );
|
||||||
|
|
||||||
|
vgui.initialized = vgui.dllFuncs.initialized = true;
|
||||||
|
Con_Reportf( "vgui_support: initialized legacy API in %s module\n", client ? "client" : "support" );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Con_Reportf( S_ERROR "Failed to find VGUI support API entry point in %s module\n", client ? "client" : "support" );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
================
|
================
|
||||||
VGui_Startup
|
VGui_Startup
|
||||||
|
|
||||||
Load vgui_support library and call VGui_Startup
|
|
||||||
================
|
================
|
||||||
*/
|
*/
|
||||||
void VGui_Startup( const char *clientlib, int width, int height )
|
void VGui_Startup( int width, int height )
|
||||||
{
|
{
|
||||||
static qboolean failed = false;
|
// vgui not initialized from both support and client modules, skip
|
||||||
|
if( !vgui.initialized )
|
||||||
void (*F) ( vguiapi_t * );
|
|
||||||
char vguiloader[256];
|
|
||||||
char vguilib[256];
|
|
||||||
|
|
||||||
vguiloader[0] = vguilib[0] = '\0';
|
|
||||||
|
|
||||||
if( failed )
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if( !vgui.initialized )
|
height = Q_max( 480, height );
|
||||||
{
|
|
||||||
vgui_utf8 = Cvar_Get( "vgui_utf8", "0", FCVAR_ARCHIVE, "enable utf-8 support for vgui text" );
|
|
||||||
|
|
||||||
VGui_FillAPIFromRef( &vgui, &ref.dllFuncs );
|
if( width <= 640 ) width = 640;
|
||||||
|
else if( width <= 800 ) width = 800;
|
||||||
|
else if( width <= 1024 ) width = 1024;
|
||||||
|
else if( width <= 1152 ) width = 1152;
|
||||||
|
else if( width <= 1280 ) width = 1280;
|
||||||
|
else if( width <= 1600 ) width = 1600;
|
||||||
|
|
||||||
s_pVGuiSupport = COM_LoadLibrary( clientlib, false, false );
|
if( vgui.dllFuncs.Startup )
|
||||||
|
vgui.dllFuncs.Startup( width, height );
|
||||||
if( s_pVGuiSupport )
|
|
||||||
{
|
|
||||||
F = COM_GetProcAddress( s_pVGuiSupport, "InitVGUISupportAPI" );
|
|
||||||
if( F )
|
|
||||||
{
|
|
||||||
F( &vgui );
|
|
||||||
vgui.initialized = true;
|
|
||||||
Con_Reportf( "vgui_support: found internal client support\n" );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
COM_FreeLibrary( s_pVGuiSupport );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !vgui.initialized )
|
|
||||||
{
|
|
||||||
// HACKHACK: load vgui with correct path first if specified.
|
|
||||||
// it will be reused while resolving vgui support and client deps
|
|
||||||
if( Sys_GetParmFromCmdLine( "-vguilib", vguilib ))
|
|
||||||
{
|
|
||||||
if( Q_strstr( vguilib, ".dll" ))
|
|
||||||
Q_strncpy( vguiloader, "vgui_support.dll", 256 );
|
|
||||||
else
|
|
||||||
Q_strncpy( vguiloader, VGUI_SUPPORT_DLL, 256 );
|
|
||||||
|
|
||||||
if( !COM_LoadLibrary( vguilib, false, false ))
|
|
||||||
Con_Reportf( S_WARN "VGUI preloading failed. Default library will be used! Reason: %s\n", COM_GetLibraryError() );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( Q_strstr( clientlib, ".dll" ))
|
|
||||||
Q_strncpy( vguiloader, "vgui_support.dll", 256 );
|
|
||||||
|
|
||||||
if( !vguiloader[0] && !Sys_GetParmFromCmdLine( "-vguiloader", vguiloader ))
|
|
||||||
Q_strncpy( vguiloader, VGUI_SUPPORT_DLL, 256 );
|
|
||||||
|
|
||||||
s_pVGuiSupport = COM_LoadLibrary( vguiloader, false, false );
|
|
||||||
|
|
||||||
if( !s_pVGuiSupport )
|
|
||||||
{
|
|
||||||
s_pVGuiSupport = COM_LoadLibrary( va( "../%s", vguiloader ), false, false );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !s_pVGuiSupport )
|
|
||||||
{
|
|
||||||
if( FS_FileExists( vguiloader, false ))
|
|
||||||
{
|
|
||||||
Con_Reportf( S_ERROR "Failed to load vgui_support library: %s\n", COM_GetLibraryError() );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Con_Reportf( "vgui_support: not found\n" );
|
|
||||||
}
|
|
||||||
failed = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
F = COM_GetProcAddress( s_pVGuiSupport, "InitAPI" );
|
|
||||||
if( F )
|
|
||||||
{
|
|
||||||
F( &vgui );
|
|
||||||
vgui.initialized = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Con_Reportf( S_ERROR "Failed to find vgui_support library entry point!\n" );
|
|
||||||
failed = true;
|
|
||||||
COM_FreeLibrary( s_pVGuiSupport );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( height < 480 )
|
|
||||||
height = 480;
|
|
||||||
|
|
||||||
if( width <= 640 )
|
|
||||||
width = 640;
|
|
||||||
else if( width <= 800 )
|
|
||||||
width = 800;
|
|
||||||
else if( width <= 1024 )
|
|
||||||
width = 1024;
|
|
||||||
else if( width <= 1152 )
|
|
||||||
width = 1152;
|
|
||||||
else if( width <= 1280 )
|
|
||||||
width = 1280;
|
|
||||||
else if( width <= 1600 )
|
|
||||||
width = 1600;
|
|
||||||
#ifdef XASH_DLL_LOADER
|
|
||||||
else if ( Q_strstr( vguiloader, ".dll" ) )
|
|
||||||
width = 1600;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
if( vgui.initialized )
|
|
||||||
{
|
|
||||||
//host.mouse_visible = true;
|
|
||||||
vgui.Startup( width, height );
|
|
||||||
}
|
|
||||||
else if ( COM_CheckString( clientlib ) )
|
|
||||||
{
|
|
||||||
failed = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -270,214 +227,223 @@ Unload vgui_support library and call VGui_Shutdown
|
||||||
*/
|
*/
|
||||||
void VGui_Shutdown( void )
|
void VGui_Shutdown( void )
|
||||||
{
|
{
|
||||||
if( vgui.Shutdown )
|
if( vgui.dllFuncs.Shutdown )
|
||||||
vgui.Shutdown();
|
vgui.dllFuncs.Shutdown();
|
||||||
|
|
||||||
if( s_pVGuiSupport )
|
if( vgui.hInstance )
|
||||||
COM_FreeLibrary( s_pVGuiSupport );
|
COM_FreeLibrary( vgui.hInstance );
|
||||||
s_pVGuiSupport = NULL;
|
|
||||||
|
|
||||||
|
vgui.hInstance = NULL;
|
||||||
vgui.initialized = false;
|
vgui.initialized = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void VGUI_InitKeyTranslationTable( void )
|
static void VGUI_InitKeyTranslationTable( void )
|
||||||
{
|
{
|
||||||
static qboolean bInitted = false;
|
static qboolean initialized = false;
|
||||||
|
|
||||||
if( bInitted )
|
if( initialized ) return;
|
||||||
return;
|
|
||||||
bInitted = true;
|
initialized = true;
|
||||||
|
|
||||||
// set virtual key translation table
|
// set virtual key translation table
|
||||||
memset( s_pVirtualKeyTrans, -1, sizeof( s_pVirtualKeyTrans ) );
|
memset( vgui.virtualKeyTrans, -1, sizeof( vgui.virtualKeyTrans ) );
|
||||||
|
|
||||||
s_pVirtualKeyTrans['0'] = KEY_0;
|
// TODO: engine keys are not enough here!
|
||||||
s_pVirtualKeyTrans['1'] = KEY_1;
|
// make crossplatform way to pass SDL keys here
|
||||||
s_pVirtualKeyTrans['2'] = KEY_2;
|
|
||||||
s_pVirtualKeyTrans['3'] = KEY_3;
|
|
||||||
s_pVirtualKeyTrans['4'] = KEY_4;
|
|
||||||
s_pVirtualKeyTrans['5'] = KEY_5;
|
|
||||||
s_pVirtualKeyTrans['6'] = KEY_6;
|
|
||||||
s_pVirtualKeyTrans['7'] = KEY_7;
|
|
||||||
s_pVirtualKeyTrans['8'] = KEY_8;
|
|
||||||
s_pVirtualKeyTrans['9'] = KEY_9;
|
|
||||||
s_pVirtualKeyTrans['A'] = s_pVirtualKeyTrans['a'] = KEY_A;
|
|
||||||
s_pVirtualKeyTrans['B'] = s_pVirtualKeyTrans['b'] = KEY_B;
|
|
||||||
s_pVirtualKeyTrans['C'] = s_pVirtualKeyTrans['c'] = KEY_C;
|
|
||||||
s_pVirtualKeyTrans['D'] = s_pVirtualKeyTrans['d'] = KEY_D;
|
|
||||||
s_pVirtualKeyTrans['E'] = s_pVirtualKeyTrans['e'] = KEY_E;
|
|
||||||
s_pVirtualKeyTrans['F'] = s_pVirtualKeyTrans['f'] = KEY_F;
|
|
||||||
s_pVirtualKeyTrans['G'] = s_pVirtualKeyTrans['g'] = KEY_G;
|
|
||||||
s_pVirtualKeyTrans['H'] = s_pVirtualKeyTrans['h'] = KEY_H;
|
|
||||||
s_pVirtualKeyTrans['I'] = s_pVirtualKeyTrans['i'] = KEY_I;
|
|
||||||
s_pVirtualKeyTrans['J'] = s_pVirtualKeyTrans['j'] = KEY_J;
|
|
||||||
s_pVirtualKeyTrans['K'] = s_pVirtualKeyTrans['k'] = KEY_K;
|
|
||||||
s_pVirtualKeyTrans['L'] = s_pVirtualKeyTrans['l'] = KEY_L;
|
|
||||||
s_pVirtualKeyTrans['M'] = s_pVirtualKeyTrans['m'] = KEY_M;
|
|
||||||
s_pVirtualKeyTrans['N'] = s_pVirtualKeyTrans['n'] = KEY_N;
|
|
||||||
s_pVirtualKeyTrans['O'] = s_pVirtualKeyTrans['o'] = KEY_O;
|
|
||||||
s_pVirtualKeyTrans['P'] = s_pVirtualKeyTrans['p'] = KEY_P;
|
|
||||||
s_pVirtualKeyTrans['Q'] = s_pVirtualKeyTrans['q'] = KEY_Q;
|
|
||||||
s_pVirtualKeyTrans['R'] = s_pVirtualKeyTrans['r'] = KEY_R;
|
|
||||||
s_pVirtualKeyTrans['S'] = s_pVirtualKeyTrans['s'] = KEY_S;
|
|
||||||
s_pVirtualKeyTrans['T'] = s_pVirtualKeyTrans['t'] = KEY_T;
|
|
||||||
s_pVirtualKeyTrans['U'] = s_pVirtualKeyTrans['u'] = KEY_U;
|
|
||||||
s_pVirtualKeyTrans['V'] = s_pVirtualKeyTrans['v'] = KEY_V;
|
|
||||||
s_pVirtualKeyTrans['W'] = s_pVirtualKeyTrans['w'] = KEY_W;
|
|
||||||
s_pVirtualKeyTrans['X'] = s_pVirtualKeyTrans['x'] = KEY_X;
|
|
||||||
s_pVirtualKeyTrans['Y'] = s_pVirtualKeyTrans['y'] = KEY_Y;
|
|
||||||
s_pVirtualKeyTrans['Z'] = s_pVirtualKeyTrans['z'] = KEY_Z;
|
|
||||||
|
|
||||||
s_pVirtualKeyTrans[K_KP_5 - 5] = KEY_PAD_0;
|
vgui.virtualKeyTrans['0'] = KEY_0;
|
||||||
s_pVirtualKeyTrans[K_KP_5 - 4] = KEY_PAD_1;
|
vgui.virtualKeyTrans['1'] = KEY_1;
|
||||||
s_pVirtualKeyTrans[K_KP_5 - 3] = KEY_PAD_2;
|
vgui.virtualKeyTrans['2'] = KEY_2;
|
||||||
s_pVirtualKeyTrans[K_KP_5 - 2] = KEY_PAD_3;
|
vgui.virtualKeyTrans['3'] = KEY_3;
|
||||||
s_pVirtualKeyTrans[K_KP_5 - 1] = KEY_PAD_4;
|
vgui.virtualKeyTrans['4'] = KEY_4;
|
||||||
s_pVirtualKeyTrans[K_KP_5 - 0] = KEY_PAD_5;
|
vgui.virtualKeyTrans['5'] = KEY_5;
|
||||||
s_pVirtualKeyTrans[K_KP_5 + 1] = KEY_PAD_6;
|
vgui.virtualKeyTrans['6'] = KEY_6;
|
||||||
s_pVirtualKeyTrans[K_KP_5 + 2] = KEY_PAD_7;
|
vgui.virtualKeyTrans['7'] = KEY_7;
|
||||||
s_pVirtualKeyTrans[K_KP_5 + 3] = KEY_PAD_8;
|
vgui.virtualKeyTrans['8'] = KEY_8;
|
||||||
s_pVirtualKeyTrans[K_KP_5 + 4] = KEY_PAD_9;
|
vgui.virtualKeyTrans['9'] = KEY_9;
|
||||||
s_pVirtualKeyTrans[K_KP_SLASH] = KEY_PAD_DIVIDE;
|
vgui.virtualKeyTrans['A'] = vgui.virtualKeyTrans['a'] = KEY_A;
|
||||||
s_pVirtualKeyTrans['*'] = KEY_PAD_MULTIPLY;
|
vgui.virtualKeyTrans['B'] = vgui.virtualKeyTrans['b'] = KEY_B;
|
||||||
s_pVirtualKeyTrans[K_KP_MINUS] = KEY_PAD_MINUS;
|
vgui.virtualKeyTrans['C'] = vgui.virtualKeyTrans['c'] = KEY_C;
|
||||||
s_pVirtualKeyTrans[K_KP_PLUS] = KEY_PAD_PLUS;
|
vgui.virtualKeyTrans['D'] = vgui.virtualKeyTrans['d'] = KEY_D;
|
||||||
s_pVirtualKeyTrans[K_KP_ENTER] = KEY_PAD_ENTER;
|
vgui.virtualKeyTrans['E'] = vgui.virtualKeyTrans['e'] = KEY_E;
|
||||||
//s_pVirtualKeyTrans[K_KP_DECIMAL] = KEY_PAD_DECIMAL;
|
vgui.virtualKeyTrans['F'] = vgui.virtualKeyTrans['f'] = KEY_F;
|
||||||
s_pVirtualKeyTrans['['] = KEY_LBRACKET;
|
vgui.virtualKeyTrans['G'] = vgui.virtualKeyTrans['g'] = KEY_G;
|
||||||
s_pVirtualKeyTrans[']'] = KEY_RBRACKET;
|
vgui.virtualKeyTrans['H'] = vgui.virtualKeyTrans['h'] = KEY_H;
|
||||||
s_pVirtualKeyTrans[';'] = KEY_SEMICOLON;
|
vgui.virtualKeyTrans['I'] = vgui.virtualKeyTrans['i'] = KEY_I;
|
||||||
s_pVirtualKeyTrans['\''] = KEY_APOSTROPHE;
|
vgui.virtualKeyTrans['J'] = vgui.virtualKeyTrans['j'] = KEY_J;
|
||||||
s_pVirtualKeyTrans['`'] = KEY_BACKQUOTE;
|
vgui.virtualKeyTrans['K'] = vgui.virtualKeyTrans['k'] = KEY_K;
|
||||||
s_pVirtualKeyTrans[','] = KEY_COMMA;
|
vgui.virtualKeyTrans['L'] = vgui.virtualKeyTrans['l'] = KEY_L;
|
||||||
s_pVirtualKeyTrans['.'] = KEY_PERIOD;
|
vgui.virtualKeyTrans['M'] = vgui.virtualKeyTrans['m'] = KEY_M;
|
||||||
s_pVirtualKeyTrans[K_KP_SLASH] = KEY_SLASH;
|
vgui.virtualKeyTrans['N'] = vgui.virtualKeyTrans['n'] = KEY_N;
|
||||||
s_pVirtualKeyTrans['\\'] = KEY_BACKSLASH;
|
vgui.virtualKeyTrans['O'] = vgui.virtualKeyTrans['o'] = KEY_O;
|
||||||
s_pVirtualKeyTrans['-'] = KEY_MINUS;
|
vgui.virtualKeyTrans['P'] = vgui.virtualKeyTrans['p'] = KEY_P;
|
||||||
s_pVirtualKeyTrans['='] = KEY_EQUAL;
|
vgui.virtualKeyTrans['Q'] = vgui.virtualKeyTrans['q'] = KEY_Q;
|
||||||
s_pVirtualKeyTrans[K_ENTER] = KEY_ENTER;
|
vgui.virtualKeyTrans['R'] = vgui.virtualKeyTrans['r'] = KEY_R;
|
||||||
s_pVirtualKeyTrans[K_SPACE] = KEY_SPACE;
|
vgui.virtualKeyTrans['S'] = vgui.virtualKeyTrans['s'] = KEY_S;
|
||||||
s_pVirtualKeyTrans[K_BACKSPACE] = KEY_BACKSPACE;
|
vgui.virtualKeyTrans['T'] = vgui.virtualKeyTrans['t'] = KEY_T;
|
||||||
s_pVirtualKeyTrans[K_TAB] = KEY_TAB;
|
vgui.virtualKeyTrans['U'] = vgui.virtualKeyTrans['u'] = KEY_U;
|
||||||
s_pVirtualKeyTrans[K_CAPSLOCK] = KEY_CAPSLOCK;
|
vgui.virtualKeyTrans['V'] = vgui.virtualKeyTrans['v'] = KEY_V;
|
||||||
s_pVirtualKeyTrans[K_KP_NUMLOCK] = KEY_NUMLOCK;
|
vgui.virtualKeyTrans['W'] = vgui.virtualKeyTrans['w'] = KEY_W;
|
||||||
s_pVirtualKeyTrans[K_ESCAPE] = KEY_ESCAPE;
|
vgui.virtualKeyTrans['X'] = vgui.virtualKeyTrans['x'] = KEY_X;
|
||||||
//s_pVirtualKeyTrans[K_KP_SCROLLLOCK] = KEY_SCROLLLOCK;
|
vgui.virtualKeyTrans['Y'] = vgui.virtualKeyTrans['y'] = KEY_Y;
|
||||||
s_pVirtualKeyTrans[K_INS] = KEY_INSERT;
|
vgui.virtualKeyTrans['Z'] = vgui.virtualKeyTrans['z'] = KEY_Z;
|
||||||
s_pVirtualKeyTrans[K_DEL] = KEY_DELETE;
|
|
||||||
s_pVirtualKeyTrans[K_HOME] = KEY_HOME;
|
vgui.virtualKeyTrans[K_KP_5 - 5] = KEY_PAD_0;
|
||||||
s_pVirtualKeyTrans[K_END] = KEY_END;
|
vgui.virtualKeyTrans[K_KP_5 - 4] = KEY_PAD_1;
|
||||||
s_pVirtualKeyTrans[K_PGUP] = KEY_PAGEUP;
|
vgui.virtualKeyTrans[K_KP_5 - 3] = KEY_PAD_2;
|
||||||
s_pVirtualKeyTrans[K_PGDN] = KEY_PAGEDOWN;
|
vgui.virtualKeyTrans[K_KP_5 - 2] = KEY_PAD_3;
|
||||||
s_pVirtualKeyTrans[K_PAUSE] = KEY_BREAK;
|
vgui.virtualKeyTrans[K_KP_5 - 1] = KEY_PAD_4;
|
||||||
//s_pVirtualKeyTrans[K_SHIFT] = KEY_RSHIFT;
|
vgui.virtualKeyTrans[K_KP_5 - 0] = KEY_PAD_5;
|
||||||
s_pVirtualKeyTrans[K_SHIFT] = KEY_LSHIFT; // SHIFT -> left SHIFT
|
vgui.virtualKeyTrans[K_KP_5 + 1] = KEY_PAD_6;
|
||||||
//s_pVirtualKeyTrans[SDLK_RALT] = KEY_RALT;
|
vgui.virtualKeyTrans[K_KP_5 + 2] = KEY_PAD_7;
|
||||||
s_pVirtualKeyTrans[K_ALT] = KEY_LALT; // ALT -> left ALT
|
vgui.virtualKeyTrans[K_KP_5 + 3] = KEY_PAD_8;
|
||||||
//s_pVirtualKeyTrans[SDLK_RCTRL] = KEY_RCONTROL;
|
vgui.virtualKeyTrans[K_KP_5 + 4] = KEY_PAD_9;
|
||||||
s_pVirtualKeyTrans[K_CTRL] = KEY_LCONTROL; // CTRL -> left CTRL
|
vgui.virtualKeyTrans[K_KP_SLASH] = KEY_PAD_DIVIDE;
|
||||||
s_pVirtualKeyTrans[K_WIN] = KEY_LWIN;
|
vgui.virtualKeyTrans['*'] = KEY_PAD_MULTIPLY;
|
||||||
//s_pVirtualKeyTrans[SDLK_APPLICATION] = KEY_RWIN;
|
vgui.virtualKeyTrans[K_KP_MINUS] = KEY_PAD_MINUS;
|
||||||
//s_pVirtualKeyTrans[K_WIN] = KEY_APP;
|
vgui.virtualKeyTrans[K_KP_PLUS] = KEY_PAD_PLUS;
|
||||||
s_pVirtualKeyTrans[K_UPARROW] = KEY_UP;
|
vgui.virtualKeyTrans[K_KP_ENTER] = KEY_PAD_ENTER;
|
||||||
s_pVirtualKeyTrans[K_LEFTARROW] = KEY_LEFT;
|
vgui.virtualKeyTrans[K_KP_NUMLOCK] = KEY_NUMLOCK;
|
||||||
s_pVirtualKeyTrans[K_DOWNARROW] = KEY_DOWN;
|
vgui.virtualKeyTrans['['] = KEY_LBRACKET;
|
||||||
s_pVirtualKeyTrans[K_RIGHTARROW] = KEY_RIGHT;
|
vgui.virtualKeyTrans[']'] = KEY_RBRACKET;
|
||||||
s_pVirtualKeyTrans[K_F1] = KEY_F1;
|
vgui.virtualKeyTrans[';'] = KEY_SEMICOLON;
|
||||||
s_pVirtualKeyTrans[K_F2] = KEY_F2;
|
vgui.virtualKeyTrans['`'] = KEY_BACKQUOTE;
|
||||||
s_pVirtualKeyTrans[K_F3] = KEY_F3;
|
vgui.virtualKeyTrans[','] = KEY_COMMA;
|
||||||
s_pVirtualKeyTrans[K_F4] = KEY_F4;
|
vgui.virtualKeyTrans['.'] = KEY_PERIOD;
|
||||||
s_pVirtualKeyTrans[K_F5] = KEY_F5;
|
vgui.virtualKeyTrans['-'] = KEY_MINUS;
|
||||||
s_pVirtualKeyTrans[K_F6] = KEY_F6;
|
vgui.virtualKeyTrans['='] = KEY_EQUAL;
|
||||||
s_pVirtualKeyTrans[K_F7] = KEY_F7;
|
vgui.virtualKeyTrans['/'] = KEY_SLASH;
|
||||||
s_pVirtualKeyTrans[K_F8] = KEY_F8;
|
vgui.virtualKeyTrans['\\'] = KEY_BACKSLASH;
|
||||||
s_pVirtualKeyTrans[K_F9] = KEY_F9;
|
vgui.virtualKeyTrans['\''] = KEY_APOSTROPHE;
|
||||||
s_pVirtualKeyTrans[K_F10] = KEY_F10;
|
vgui.virtualKeyTrans[K_TAB] = KEY_TAB;
|
||||||
s_pVirtualKeyTrans[K_F11] = KEY_F11;
|
vgui.virtualKeyTrans[K_ENTER] = KEY_ENTER;
|
||||||
s_pVirtualKeyTrans[K_F12] = KEY_F12;
|
vgui.virtualKeyTrans[K_SPACE] = KEY_SPACE;
|
||||||
|
vgui.virtualKeyTrans[K_CAPSLOCK] = KEY_CAPSLOCK;
|
||||||
|
vgui.virtualKeyTrans[K_BACKSPACE] = KEY_BACKSPACE;
|
||||||
|
vgui.virtualKeyTrans[K_ESCAPE] = KEY_ESCAPE;
|
||||||
|
vgui.virtualKeyTrans[K_INS] = KEY_INSERT;
|
||||||
|
vgui.virtualKeyTrans[K_DEL] = KEY_DELETE;
|
||||||
|
vgui.virtualKeyTrans[K_HOME] = KEY_HOME;
|
||||||
|
vgui.virtualKeyTrans[K_END] = KEY_END;
|
||||||
|
vgui.virtualKeyTrans[K_PGUP] = KEY_PAGEUP;
|
||||||
|
vgui.virtualKeyTrans[K_PGDN] = KEY_PAGEDOWN;
|
||||||
|
vgui.virtualKeyTrans[K_PAUSE] = KEY_BREAK;
|
||||||
|
vgui.virtualKeyTrans[K_SHIFT] = KEY_LSHIFT; // SHIFT -> left SHIFT
|
||||||
|
vgui.virtualKeyTrans[K_ALT] = KEY_LALT; // ALT -> left ALT
|
||||||
|
vgui.virtualKeyTrans[K_CTRL] = KEY_LCONTROL; // CTRL -> left CTRL
|
||||||
|
vgui.virtualKeyTrans[K_WIN] = KEY_LWIN;
|
||||||
|
vgui.virtualKeyTrans[K_UPARROW] = KEY_UP;
|
||||||
|
vgui.virtualKeyTrans[K_LEFTARROW] = KEY_LEFT;
|
||||||
|
vgui.virtualKeyTrans[K_DOWNARROW] = KEY_DOWN;
|
||||||
|
vgui.virtualKeyTrans[K_RIGHTARROW] = KEY_RIGHT;
|
||||||
|
vgui.virtualKeyTrans[K_F1] = KEY_F1;
|
||||||
|
vgui.virtualKeyTrans[K_F2] = KEY_F2;
|
||||||
|
vgui.virtualKeyTrans[K_F3] = KEY_F3;
|
||||||
|
vgui.virtualKeyTrans[K_F4] = KEY_F4;
|
||||||
|
vgui.virtualKeyTrans[K_F5] = KEY_F5;
|
||||||
|
vgui.virtualKeyTrans[K_F6] = KEY_F6;
|
||||||
|
vgui.virtualKeyTrans[K_F7] = KEY_F7;
|
||||||
|
vgui.virtualKeyTrans[K_F8] = KEY_F8;
|
||||||
|
vgui.virtualKeyTrans[K_F9] = KEY_F9;
|
||||||
|
vgui.virtualKeyTrans[K_F10] = KEY_F10;
|
||||||
|
vgui.virtualKeyTrans[K_F11] = KEY_F11;
|
||||||
|
vgui.virtualKeyTrans[K_F12] = KEY_F12;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum VGUI_KeyCode VGUI_MapKey( int keyCode )
|
static enum VGUI_KeyCode VGUI_MapKey( int keyCode )
|
||||||
{
|
{
|
||||||
VGUI_InitKeyTranslationTable();
|
VGUI_InitKeyTranslationTable();
|
||||||
|
|
||||||
if( keyCode < 0 || keyCode >= (int)sizeof( s_pVirtualKeyTrans ) / (int)sizeof( s_pVirtualKeyTrans[0] ))
|
if( keyCode >= 0 && keyCode < ARRAYSIZE( vgui.virtualKeyTrans ))
|
||||||
{
|
return vgui.virtualKeyTrans[keyCode];
|
||||||
//Assert( false );
|
|
||||||
return (enum VGUI_KeyCode)-1;
|
return (enum VGUI_KeyCode)-1;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return s_pVirtualKeyTrans[keyCode];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VGui_KeyEvent( int key, int down )
|
void VGui_MouseEvent( int key, int clicks )
|
||||||
{
|
{
|
||||||
if( !vgui.initialized )
|
enum VGUI_MouseAction mact;
|
||||||
|
enum VGUI_MouseCode code;
|
||||||
|
|
||||||
|
if( !vgui.dllFuncs.Mouse )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch( key )
|
switch( key )
|
||||||
{
|
{
|
||||||
case K_MOUSE1:
|
case K_MOUSE1: code = MOUSE_LEFT; break;
|
||||||
if( down && host.mouse_visible ) {
|
case K_MOUSE2: code = MOUSE_RIGHT; break;
|
||||||
Key_EnableTextInput(true, false);
|
case K_MOUSE3: code = MOUSE_MIDDLE; break;
|
||||||
}
|
default: return;
|
||||||
vgui.Mouse( down ? MA_PRESSED : MA_RELEASED, MOUSE_LEFT );
|
|
||||||
return;
|
|
||||||
case K_MOUSE2:
|
|
||||||
vgui.Mouse( down ? MA_PRESSED : MA_RELEASED, MOUSE_RIGHT );
|
|
||||||
return;
|
|
||||||
case K_MOUSE3:
|
|
||||||
vgui.Mouse( down ? MA_PRESSED : MA_RELEASED, MOUSE_MIDDLE );
|
|
||||||
return;
|
|
||||||
case K_MWHEELDOWN:
|
|
||||||
vgui.Mouse( MA_WHEEL, 1 );
|
|
||||||
return;
|
|
||||||
case K_MWHEELUP:
|
|
||||||
vgui.Mouse( MA_WHEEL, -1 );
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( down == 2 )
|
if( clicks >= 2 )
|
||||||
vgui.Key( KA_TYPED, VGUI_MapKey( key ) );
|
mact = MA_DOUBLE;
|
||||||
|
else if( clicks == 1 )
|
||||||
|
mact = MA_PRESSED;
|
||||||
else
|
else
|
||||||
vgui.Key( down?KA_PRESSED:KA_RELEASED, VGUI_MapKey( key ) );
|
mact = MA_RELEASED;
|
||||||
//Msg("VGui_KeyEvent %d %d %d\n", key, VGUI_MapKey( key ), down );
|
|
||||||
|
vgui.dllFuncs.Mouse( mact, code );
|
||||||
|
}
|
||||||
|
|
||||||
|
void VGui_MWheelEvent( int y )
|
||||||
|
{
|
||||||
|
if( !vgui.dllFuncs.Mouse )
|
||||||
|
return;
|
||||||
|
|
||||||
|
vgui.dllFuncs.Mouse( MA_WHEEL, y );
|
||||||
|
}
|
||||||
|
|
||||||
|
void VGui_KeyEvent( int key, int down )
|
||||||
|
{
|
||||||
|
enum VGUI_KeyCode code;
|
||||||
|
|
||||||
|
if( !vgui.dllFuncs.Key )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(( code = VGUI_MapKey( key )) < 0 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( down )
|
||||||
|
{
|
||||||
|
vgui.dllFuncs.Key( KA_PRESSED, code );
|
||||||
|
vgui.dllFuncs.Key( KA_TYPED, code );
|
||||||
|
}
|
||||||
|
else vgui.dllFuncs.Key( KA_RELEASED, code );
|
||||||
}
|
}
|
||||||
|
|
||||||
void VGui_MouseMove( int x, int y )
|
void VGui_MouseMove( int x, int y )
|
||||||
{
|
{
|
||||||
|
if( vgui.dllFuncs.MouseMove )
|
||||||
|
{
|
||||||
float xscale = (float)refState.width / (float)clgame.scrInfo.iWidth;
|
float xscale = (float)refState.width / (float)clgame.scrInfo.iWidth;
|
||||||
float yscale = (float)refState.height / (float)clgame.scrInfo.iHeight;
|
float yscale = (float)refState.height / (float)clgame.scrInfo.iHeight;
|
||||||
if( vgui.initialized )
|
vgui.dllFuncs.MouseMove( x / xscale, y / yscale );
|
||||||
vgui.MouseMove( x / xscale, y / yscale );
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VGui_Paint( void )
|
void VGui_Paint( void )
|
||||||
{
|
{
|
||||||
if( vgui.initialized )
|
if( vgui.dllFuncs.Paint )
|
||||||
vgui.Paint();
|
vgui.dllFuncs.Paint();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VGui_RunFrame( void )
|
void VGui_UpdateInternalCursorState( VGUI_DefaultCursor cursorType )
|
||||||
{
|
{
|
||||||
//stub
|
vgui.cursor = cursorType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void *GAME_EXPORT VGui_GetPanel( void )
|
void *GAME_EXPORT VGui_GetPanel( void )
|
||||||
{
|
{
|
||||||
if( vgui.initialized )
|
if( vgui.dllFuncs.GetPanel )
|
||||||
return vgui.GetPanel();
|
return vgui.dllFuncs.GetPanel();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VGui_ReportTextInput( const char *text )
|
void VGui_ReportTextInput( const char *text )
|
||||||
{
|
{
|
||||||
if ( vgui.initialized )
|
if( vgui.dllFuncs.TextInput )
|
||||||
vgui.TextInput( text );
|
vgui.dllFuncs.TextInput( text );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,25 +16,22 @@ GNU General Public License for more details.
|
||||||
#ifndef VGUI_DRAW_H
|
#ifndef VGUI_DRAW_H
|
||||||
#define VGUI_DRAW_H
|
#define VGUI_DRAW_H
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "port.h"
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// vgui_draw.c
|
// vgui_draw.c
|
||||||
//
|
//
|
||||||
void VGui_Startup( const char *clientlib, int width, int height );
|
void VGui_RegisterCvars( void );
|
||||||
|
qboolean VGui_LoadProgs( HINSTANCE hInstance );
|
||||||
|
void VGui_Startup( int width, int height );
|
||||||
void VGui_Shutdown( void );
|
void VGui_Shutdown( void );
|
||||||
void VGui_Paint( void );
|
void VGui_Paint( void );
|
||||||
void VGui_RunFrame( void );
|
void VGui_RunFrame( void );
|
||||||
|
void VGui_MouseEvent( int key, int clicks );
|
||||||
|
void VGui_MWheelEvent( int y );
|
||||||
void VGui_KeyEvent( int key, int down );
|
void VGui_KeyEvent( int key, int down );
|
||||||
void VGui_MouseMove( int x, int y );
|
void VGui_MouseMove( int x, int y );
|
||||||
qboolean VGui_IsActive( void );
|
qboolean VGui_IsActive( void );
|
||||||
void *VGui_GetPanel( void );
|
void *VGui_GetPanel( void );
|
||||||
void VGui_ReportTextInput( const char *text );
|
void VGui_ReportTextInput( const char *text );
|
||||||
#ifdef __cplusplus
|
void VGui_UpdateInternalCursorState( VGUI_DefaultCursor cursorType );
|
||||||
}
|
|
||||||
#endif
|
#endif // VGUI_DRAW_H
|
||||||
#endif//VGUI_DRAW_H
|
|
||||||
|
|
|
@ -21,7 +21,6 @@ GNU General Public License for more details.
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
|
|
||||||
#define WINDOW_NAME XASH_ENGINE_NAME " Window" // Half-Life
|
#define WINDOW_NAME XASH_ENGINE_NAME " Window" // Half-Life
|
||||||
convar_t *vid_displayfrequency;
|
|
||||||
convar_t *vid_fullscreen;
|
convar_t *vid_fullscreen;
|
||||||
convar_t *vid_mode;
|
convar_t *vid_mode;
|
||||||
convar_t *vid_brightness;
|
convar_t *vid_brightness;
|
||||||
|
@ -67,19 +66,30 @@ void VID_InitDefaultResolution( void )
|
||||||
R_SaveVideoMode
|
R_SaveVideoMode
|
||||||
=================
|
=================
|
||||||
*/
|
*/
|
||||||
void R_SaveVideoMode( int w, int h , int render_w, int render_h )
|
void R_SaveVideoMode( int w, int h, int render_w, int render_h )
|
||||||
{
|
{
|
||||||
|
if( !w || !h || !render_w || !render_h )
|
||||||
|
{
|
||||||
|
host.renderinfo_changed = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
host.window_center_x = w / 2;
|
host.window_center_x = w / 2;
|
||||||
host.window_center_y = h / 2;
|
host.window_center_y = h / 2;
|
||||||
|
|
||||||
Cvar_SetValue( "width", w );
|
Cvar_SetValue( "width", w );
|
||||||
Cvar_SetValue( "height", h );
|
Cvar_SetValue( "height", h );
|
||||||
|
|
||||||
|
// immediately drop changed state or we may trigger
|
||||||
|
// video subsystem to reapply settings
|
||||||
|
host.renderinfo_changed = false;
|
||||||
|
|
||||||
|
if( refState.width == render_w && refState.height == render_h )
|
||||||
|
return;
|
||||||
|
|
||||||
refState.width = render_w;
|
refState.width = render_w;
|
||||||
refState.height = render_h;
|
refState.height = render_h;
|
||||||
|
|
||||||
host.renderinfo_changed = false;
|
|
||||||
|
|
||||||
// check for 4:3 or 5:4
|
// check for 4:3 or 5:4
|
||||||
if( render_w * 3 != render_h * 4 && render_w * 4 != render_h * 5 )
|
if( render_w * 3 != render_h * 4 && render_w * 4 != render_h * 5 )
|
||||||
refState.wideScreen = true;
|
refState.wideScreen = true;
|
||||||
|
@ -176,12 +186,11 @@ void VID_Init( void )
|
||||||
Cvar_Get( "width", "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "screen width" );
|
Cvar_Get( "width", "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "screen width" );
|
||||||
Cvar_Get( "height", "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "screen height" );
|
Cvar_Get( "height", "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "screen height" );
|
||||||
|
|
||||||
window_xpos = Cvar_Get( "_window_xpos", "130", FCVAR_RENDERINFO, "window position by horizontal" );
|
window_xpos = Cvar_Get( "_window_xpos", "-1", FCVAR_RENDERINFO, "window position by horizontal" );
|
||||||
window_ypos = Cvar_Get( "_window_ypos", "48", FCVAR_RENDERINFO, "window position by vertical" );
|
window_ypos = Cvar_Get( "_window_ypos", "-1", FCVAR_RENDERINFO, "window position by vertical" );
|
||||||
|
|
||||||
vid_gamma = Cvar_Get( "gamma", "2.5", FCVAR_ARCHIVE, "gamma amount" );
|
vid_gamma = Cvar_Get( "gamma", "2.5", FCVAR_ARCHIVE, "gamma amount" );
|
||||||
vid_brightness = Cvar_Get( "brightness", "0.0", FCVAR_ARCHIVE, "brightness factor" );
|
vid_brightness = Cvar_Get( "brightness", "0.0", FCVAR_ARCHIVE, "brightness factor" );
|
||||||
vid_displayfrequency = Cvar_Get ( "vid_displayfrequency", "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "fullscreen refresh rate" );
|
|
||||||
vid_fullscreen = Cvar_Get( "fullscreen", "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "enable fullscreen mode" );
|
vid_fullscreen = Cvar_Get( "fullscreen", "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "enable fullscreen mode" );
|
||||||
vid_mode = Cvar_Get( "vid_mode", "0", FCVAR_RENDERINFO, "current video mode index (used just for storage)" );
|
vid_mode = Cvar_Get( "vid_mode", "0", FCVAR_RENDERINFO, "current video mode index (used just for storage)" );
|
||||||
vid_highdpi = Cvar_Get( "vid_highdpi", "1", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "enable High-DPI mode" );
|
vid_highdpi = Cvar_Get( "vid_highdpi", "1", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "enable High-DPI mode" );
|
||||||
|
|
|
@ -29,7 +29,6 @@ extern glwstate_t glw_state;
|
||||||
#define VID_MIN_WIDTH 320
|
#define VID_MIN_WIDTH 320
|
||||||
|
|
||||||
extern convar_t *vid_fullscreen;
|
extern convar_t *vid_fullscreen;
|
||||||
extern convar_t *vid_displayfrequency;
|
|
||||||
extern convar_t *vid_highdpi;
|
extern convar_t *vid_highdpi;
|
||||||
extern convar_t *vid_rotate;
|
extern convar_t *vid_rotate;
|
||||||
extern convar_t *vid_scale;
|
extern convar_t *vid_scale;
|
||||||
|
|
|
@ -0,0 +1,633 @@
|
||||||
|
/*
|
||||||
|
voice.c - voice chat implementation
|
||||||
|
Copyright (C) 2022 Velaron
|
||||||
|
Copyright (C) 2022 SNMetamorph
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CUSTOM_MODES 1 // required to correctly link with Opus Custom
|
||||||
|
#include <opus_custom.h>
|
||||||
|
#include "common.h"
|
||||||
|
#include "client.h"
|
||||||
|
#include "voice.h"
|
||||||
|
|
||||||
|
voice_state_t voice = { 0 };
|
||||||
|
|
||||||
|
CVAR_DEFINE_AUTO( voice_enable, "1", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "enable voice chat" );
|
||||||
|
CVAR_DEFINE_AUTO( voice_loopback, "0", FCVAR_PRIVILEGED, "loopback voice back to the speaker" );
|
||||||
|
CVAR_DEFINE_AUTO( voice_scale, "1.0", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "incoming voice volume scale" );
|
||||||
|
CVAR_DEFINE_AUTO( voice_avggain, "0.5", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "automatic voice gain control (average)" );
|
||||||
|
CVAR_DEFINE_AUTO( voice_maxgain, "5.0", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "automatic voice gain control (maximum)" );
|
||||||
|
CVAR_DEFINE_AUTO( voice_inputfromfile, "0", FCVAR_PRIVILEGED, "input voice from voice_input.wav" );
|
||||||
|
|
||||||
|
static void Voice_ApplyGainAdjust( int16_t *samples, int count );
|
||||||
|
|
||||||
|
/*
|
||||||
|
===============================================================================
|
||||||
|
|
||||||
|
OPUS INTEGRATION
|
||||||
|
|
||||||
|
===============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
=========================
|
||||||
|
Voice_InitOpusDecoder
|
||||||
|
|
||||||
|
=========================
|
||||||
|
*/
|
||||||
|
static qboolean Voice_InitOpusDecoder( void )
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
voice.width = sizeof( opus_int16 );
|
||||||
|
voice.samplerate = VOICE_OPUS_CUSTOM_SAMPLERATE;
|
||||||
|
voice.frame_size = VOICE_OPUS_CUSTOM_FRAME_SIZE;
|
||||||
|
|
||||||
|
voice.custom_mode = opus_custom_mode_create( SOUND_44k, voice.frame_size, &err );
|
||||||
|
if( !voice.custom_mode )
|
||||||
|
{
|
||||||
|
Con_Printf( S_ERROR "Can't create Opus Custom mode: %s\n", opus_strerror( err ));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
voice.decoder = opus_custom_decoder_create( voice.custom_mode, VOICE_PCM_CHANNELS, &err );
|
||||||
|
if( !voice.decoder )
|
||||||
|
{
|
||||||
|
Con_Printf( S_ERROR "Can't create Opus encoder: %s\n", opus_strerror( err ));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=========================
|
||||||
|
Voice_InitOpusEncoder
|
||||||
|
|
||||||
|
=========================
|
||||||
|
*/
|
||||||
|
static qboolean Voice_InitOpusEncoder( int quality )
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
voice.encoder = opus_custom_encoder_create( voice.custom_mode, VOICE_PCM_CHANNELS, &err );
|
||||||
|
if( !voice.encoder )
|
||||||
|
{
|
||||||
|
Con_Printf( S_ERROR "Can't create Opus encoder: %s\n", opus_strerror( err ));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch( quality )
|
||||||
|
{
|
||||||
|
case 1: // 6 kbps
|
||||||
|
opus_custom_encoder_ctl( voice.encoder, OPUS_SET_BITRATE( 6000 ));
|
||||||
|
break;
|
||||||
|
case 2: // 12 kbps
|
||||||
|
opus_custom_encoder_ctl( voice.encoder, OPUS_SET_BITRATE( 12000 ));
|
||||||
|
break;
|
||||||
|
case 4: // 64 kbps
|
||||||
|
opus_custom_encoder_ctl( voice.encoder, OPUS_SET_BITRATE( 64000 ));
|
||||||
|
break;
|
||||||
|
case 5: // 96 kbps
|
||||||
|
opus_custom_encoder_ctl( voice.encoder, OPUS_SET_BITRATE( 96000 ));
|
||||||
|
break;
|
||||||
|
default: // 36 kbps
|
||||||
|
opus_custom_encoder_ctl( voice.encoder, OPUS_SET_BITRATE( 36000 ));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=========================
|
||||||
|
Voice_ShutdownOpusDecoder
|
||||||
|
|
||||||
|
=========================
|
||||||
|
*/
|
||||||
|
static void Voice_ShutdownOpusDecoder( void )
|
||||||
|
{
|
||||||
|
if( voice.decoder )
|
||||||
|
{
|
||||||
|
opus_custom_decoder_destroy( voice.decoder );
|
||||||
|
voice.decoder = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=========================
|
||||||
|
Voice_ShutdownOpusEncoder
|
||||||
|
|
||||||
|
=========================
|
||||||
|
*/
|
||||||
|
static void Voice_ShutdownOpusEncoder( void )
|
||||||
|
{
|
||||||
|
if( voice.encoder )
|
||||||
|
{
|
||||||
|
opus_custom_encoder_destroy( voice.encoder );
|
||||||
|
voice.encoder = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( voice.custom_mode )
|
||||||
|
{
|
||||||
|
opus_custom_mode_destroy( voice.custom_mode );
|
||||||
|
voice.custom_mode = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=========================
|
||||||
|
Voice_GetOpusCompressedData
|
||||||
|
|
||||||
|
=========================
|
||||||
|
*/
|
||||||
|
static uint Voice_GetOpusCompressedData( byte *out, uint maxsize, uint *frames )
|
||||||
|
{
|
||||||
|
uint ofs = 0, size = 0;
|
||||||
|
uint frame_size_bytes = voice.frame_size * voice.width;
|
||||||
|
|
||||||
|
if( voice.input_file )
|
||||||
|
{
|
||||||
|
uint numbytes;
|
||||||
|
double updateInterval, curtime = Sys_DoubleTime();
|
||||||
|
|
||||||
|
updateInterval = curtime - voice.start_time;
|
||||||
|
voice.start_time = curtime;
|
||||||
|
|
||||||
|
numbytes = updateInterval * voice.samplerate * voice.width * VOICE_PCM_CHANNELS;
|
||||||
|
numbytes = Q_min( numbytes, voice.input_file->size - voice.input_file_pos );
|
||||||
|
numbytes = Q_min( numbytes, sizeof( voice.input_buffer ) - voice.input_buffer_pos );
|
||||||
|
|
||||||
|
memcpy( voice.input_buffer + voice.input_buffer_pos, voice.input_file->buffer + voice.input_file_pos, numbytes );
|
||||||
|
voice.input_buffer_pos += numbytes;
|
||||||
|
voice.input_file_pos += numbytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !voice.input_file )
|
||||||
|
VoiceCapture_Lock( true );
|
||||||
|
|
||||||
|
for( ofs = 0; voice.input_buffer_pos - ofs >= frame_size_bytes && ofs <= voice.input_buffer_pos; ofs += frame_size_bytes )
|
||||||
|
{
|
||||||
|
int bytes;
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
if( !voice.input_file )
|
||||||
|
{
|
||||||
|
// adjust gain before encoding, but only for input from voice
|
||||||
|
Voice_ApplyGainAdjust((opus_int16*)(voice.input_buffer + ofs), voice.frame_size);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bytes = opus_custom_encode( voice.encoder, (const opus_int16 *)( voice.input_buffer + ofs ),
|
||||||
|
voice.frame_size, out + size + sizeof( uint16_t ), maxsize );
|
||||||
|
|
||||||
|
if( bytes > 0 )
|
||||||
|
{
|
||||||
|
// write compressed frame size
|
||||||
|
*((uint16_t *)&out[size]) = bytes;
|
||||||
|
|
||||||
|
size += bytes + sizeof( uint16_t );
|
||||||
|
maxsize -= bytes + sizeof( uint16_t );
|
||||||
|
|
||||||
|
(*frames)++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Con_Printf( S_ERROR "%s: failed to encode frame: %s\n", __func__, opus_strerror( bytes ));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// did we compress anything? update counters
|
||||||
|
if( ofs )
|
||||||
|
{
|
||||||
|
fs_offset_t remaining = voice.input_buffer_pos - ofs;
|
||||||
|
|
||||||
|
// move remaining samples to the beginning of buffer
|
||||||
|
memmove( voice.input_buffer, voice.input_buffer + ofs, remaining );
|
||||||
|
|
||||||
|
voice.input_buffer_pos = remaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !voice.input_file )
|
||||||
|
VoiceCapture_Lock( false );
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
===============================================================================
|
||||||
|
|
||||||
|
VOICE CHAT INTEGRATION
|
||||||
|
|
||||||
|
===============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
=========================
|
||||||
|
Voice_ApplyGainAdjust
|
||||||
|
|
||||||
|
=========================
|
||||||
|
*/
|
||||||
|
static void Voice_ApplyGainAdjust( int16_t *samples, int count )
|
||||||
|
{
|
||||||
|
float gain, modifiedMax;
|
||||||
|
int average, adjustedSample, blockOffset = 0;
|
||||||
|
|
||||||
|
for( ;; )
|
||||||
|
{
|
||||||
|
int i, localMax = 0, localSum = 0;
|
||||||
|
int blockSize = Q_min( count - ( blockOffset + voice.autogain.block_size ), voice.autogain.block_size );
|
||||||
|
|
||||||
|
if( blockSize < 1 )
|
||||||
|
break;
|
||||||
|
|
||||||
|
for( i = 0; i < blockSize; ++i )
|
||||||
|
{
|
||||||
|
int sample = samples[blockOffset + i];
|
||||||
|
int absSample = abs( sample );
|
||||||
|
|
||||||
|
if( absSample > localMax )
|
||||||
|
localMax = absSample;
|
||||||
|
|
||||||
|
localSum += absSample;
|
||||||
|
|
||||||
|
gain = voice.autogain.current_gain + i * voice.autogain.gain_multiplier;
|
||||||
|
adjustedSample = Q_min( SHRT_MAX, Q_max(( int )( sample * gain ), SHRT_MIN ));
|
||||||
|
samples[blockOffset + i] = adjustedSample;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( blockOffset % voice.autogain.block_size == 0 )
|
||||||
|
{
|
||||||
|
average = localSum / blockSize;
|
||||||
|
modifiedMax = average + ( localMax - average ) * voice_avggain.value;
|
||||||
|
|
||||||
|
voice.autogain.current_gain = voice.autogain.next_gain * voice_scale.value;
|
||||||
|
voice.autogain.next_gain = Q_min( (float)SHRT_MAX / modifiedMax, voice_maxgain.value ) * voice_scale.value;
|
||||||
|
voice.autogain.gain_multiplier = ( voice.autogain.next_gain - voice.autogain.current_gain ) / ( voice.autogain.block_size - 1 );
|
||||||
|
}
|
||||||
|
blockOffset += blockSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=========================
|
||||||
|
Voice_Status
|
||||||
|
|
||||||
|
Notify user dll aboit voice transmission
|
||||||
|
=========================
|
||||||
|
*/
|
||||||
|
static void Voice_Status( int entindex, qboolean bTalking )
|
||||||
|
{
|
||||||
|
if( cls.state == ca_active && clgame.dllFuncs.pfnVoiceStatus )
|
||||||
|
clgame.dllFuncs.pfnVoiceStatus( entindex, bTalking );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=========================
|
||||||
|
Voice_StatusTimeout
|
||||||
|
|
||||||
|
Waits few milliseconds and if there was no
|
||||||
|
voice transmission, sends notification
|
||||||
|
=========================
|
||||||
|
*/
|
||||||
|
static void Voice_StatusTimeout( voice_status_t *status, int entindex, double frametime )
|
||||||
|
{
|
||||||
|
if( status->talking_ack )
|
||||||
|
{
|
||||||
|
status->talking_timeout += frametime;
|
||||||
|
if( status->talking_timeout > 0.2 )
|
||||||
|
{
|
||||||
|
status->talking_ack = false;
|
||||||
|
Voice_Status( entindex, false );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=========================
|
||||||
|
Voice_StatusAck
|
||||||
|
|
||||||
|
Sends notification to user dll and
|
||||||
|
zeroes timeouts for this client
|
||||||
|
=========================
|
||||||
|
*/
|
||||||
|
void Voice_StatusAck( voice_status_t *status, int playerIndex )
|
||||||
|
{
|
||||||
|
if( !status->talking_ack )
|
||||||
|
Voice_Status( playerIndex, true );
|
||||||
|
|
||||||
|
status->talking_ack = true;
|
||||||
|
status->talking_timeout = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=========================
|
||||||
|
Voice_IsRecording
|
||||||
|
|
||||||
|
=========================
|
||||||
|
*/
|
||||||
|
qboolean Voice_IsRecording( void )
|
||||||
|
{
|
||||||
|
return voice.is_recording;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=========================
|
||||||
|
Voice_RecordStop
|
||||||
|
|
||||||
|
=========================
|
||||||
|
*/
|
||||||
|
void Voice_RecordStop( void )
|
||||||
|
{
|
||||||
|
if( voice.input_file )
|
||||||
|
{
|
||||||
|
FS_FreeSound( voice.input_file );
|
||||||
|
voice.input_file = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
VoiceCapture_Activate( false );
|
||||||
|
voice.is_recording = false;
|
||||||
|
|
||||||
|
Voice_Status( VOICE_LOCALCLIENT_INDEX, false );
|
||||||
|
|
||||||
|
voice.input_buffer_pos = 0;
|
||||||
|
memset( voice.input_buffer, 0, sizeof( voice.input_buffer ));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=========================
|
||||||
|
Voice_RecordStart
|
||||||
|
|
||||||
|
=========================
|
||||||
|
*/
|
||||||
|
void Voice_RecordStart( void )
|
||||||
|
{
|
||||||
|
Voice_RecordStop();
|
||||||
|
|
||||||
|
if( voice_inputfromfile.value )
|
||||||
|
{
|
||||||
|
voice.input_file = FS_LoadSound( "voice_input.wav", NULL, 0 );
|
||||||
|
|
||||||
|
if( voice.input_file )
|
||||||
|
{
|
||||||
|
Sound_Process( &voice.input_file, voice.samplerate, voice.width, SOUND_RESAMPLE );
|
||||||
|
voice.input_file_pos = 0;
|
||||||
|
|
||||||
|
voice.start_time = Sys_DoubleTime();
|
||||||
|
voice.is_recording = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FS_FreeSound( voice.input_file );
|
||||||
|
voice.input_file = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !Voice_IsRecording() )
|
||||||
|
voice.is_recording = VoiceCapture_Activate( true );
|
||||||
|
|
||||||
|
if( Voice_IsRecording() )
|
||||||
|
Voice_Status( VOICE_LOCALCLIENT_INDEX, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=========================
|
||||||
|
Voice_Disconnect
|
||||||
|
|
||||||
|
We're disconnected from server
|
||||||
|
stop recording and notify user dlls
|
||||||
|
=========================
|
||||||
|
*/
|
||||||
|
void Voice_Disconnect( void )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
Voice_RecordStop();
|
||||||
|
|
||||||
|
if( voice.local.talking_ack )
|
||||||
|
{
|
||||||
|
Voice_Status( VOICE_LOOPBACK_INDEX, false );
|
||||||
|
voice.local.talking_ack = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for( i = 0; i < MAX_CLIENTS; i++ )
|
||||||
|
{
|
||||||
|
if( voice.players_status[i].talking_ack )
|
||||||
|
{
|
||||||
|
Voice_Status( i, false );
|
||||||
|
voice.players_status[i].talking_ack = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=========================
|
||||||
|
Voice_StartChannel
|
||||||
|
|
||||||
|
Feed the decoded data to engine sound subsystem
|
||||||
|
=========================
|
||||||
|
*/
|
||||||
|
static void Voice_StartChannel( uint samples, byte *data, int entnum )
|
||||||
|
{
|
||||||
|
SND_ForceInitMouth( entnum );
|
||||||
|
S_RawEntSamples( entnum, samples, voice.samplerate, voice.width, VOICE_PCM_CHANNELS, data, 255 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=========================
|
||||||
|
Voice_AddIncomingData
|
||||||
|
|
||||||
|
Received encoded voice data, decode it
|
||||||
|
=========================
|
||||||
|
*/
|
||||||
|
void Voice_AddIncomingData( int ent, const byte *data, uint size, uint frames )
|
||||||
|
{
|
||||||
|
int samples = 0;
|
||||||
|
int ofs = 0;
|
||||||
|
|
||||||
|
if( !voice.decoder )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// decode frame by frame
|
||||||
|
for( ;; )
|
||||||
|
{
|
||||||
|
int frame_samples;
|
||||||
|
uint16_t compressed_size;
|
||||||
|
|
||||||
|
// no compressed size mark
|
||||||
|
if( ofs + sizeof( uint16_t ) > size )
|
||||||
|
break;
|
||||||
|
|
||||||
|
compressed_size = *(const uint16_t *)(data + ofs);
|
||||||
|
ofs += sizeof( uint16_t );
|
||||||
|
|
||||||
|
// no frame data
|
||||||
|
if( ofs + compressed_size > size )
|
||||||
|
break;
|
||||||
|
|
||||||
|
frame_samples = opus_custom_decode( voice.decoder, data + ofs, compressed_size,
|
||||||
|
(opus_int16*)voice.decompress_buffer + samples, voice.frame_size );
|
||||||
|
|
||||||
|
ofs += compressed_size;
|
||||||
|
samples += frame_samples;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( samples > 0 )
|
||||||
|
Voice_StartChannel( samples, voice.decompress_buffer, ent );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=========================
|
||||||
|
CL_AddVoiceToDatagram
|
||||||
|
|
||||||
|
Encode our voice data and send it to server
|
||||||
|
=========================
|
||||||
|
*/
|
||||||
|
void CL_AddVoiceToDatagram( void )
|
||||||
|
{
|
||||||
|
uint size, frames = 0;
|
||||||
|
|
||||||
|
if( cls.state != ca_active || !Voice_IsRecording() || !voice.encoder )
|
||||||
|
return;
|
||||||
|
|
||||||
|
size = Voice_GetOpusCompressedData( voice.output_buffer, sizeof( voice.output_buffer ), &frames );
|
||||||
|
|
||||||
|
if( size > 0 && MSG_GetNumBytesLeft( &cls.datagram ) >= size + 32 )
|
||||||
|
{
|
||||||
|
MSG_BeginClientCmd( &cls.datagram, clc_voicedata );
|
||||||
|
MSG_WriteByte( &cls.datagram, voice_loopback.value != 0 );
|
||||||
|
MSG_WriteByte( &cls.datagram, frames );
|
||||||
|
MSG_WriteShort( &cls.datagram, size );
|
||||||
|
MSG_WriteBytes( &cls.datagram, voice.output_buffer, size );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=========================
|
||||||
|
Voice_RegisterCvars
|
||||||
|
|
||||||
|
Register voice related cvars and commands
|
||||||
|
=========================
|
||||||
|
*/
|
||||||
|
void Voice_RegisterCvars( void )
|
||||||
|
{
|
||||||
|
Cvar_RegisterVariable( &voice_enable );
|
||||||
|
Cvar_RegisterVariable( &voice_loopback );
|
||||||
|
Cvar_RegisterVariable( &voice_scale );
|
||||||
|
Cvar_RegisterVariable( &voice_avggain );
|
||||||
|
Cvar_RegisterVariable( &voice_maxgain );
|
||||||
|
Cvar_RegisterVariable( &voice_inputfromfile );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=========================
|
||||||
|
Voice_Shutdown
|
||||||
|
|
||||||
|
Completely shutdown the voice subsystem
|
||||||
|
=========================
|
||||||
|
*/
|
||||||
|
static void Voice_Shutdown( void )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
Voice_RecordStop();
|
||||||
|
Voice_ShutdownOpusEncoder();
|
||||||
|
Voice_ShutdownOpusDecoder();
|
||||||
|
VoiceCapture_Shutdown();
|
||||||
|
|
||||||
|
if( voice.local.talking_ack )
|
||||||
|
Voice_Status( VOICE_LOOPBACK_INDEX, false );
|
||||||
|
|
||||||
|
for( i = 0; i < MAX_CLIENTS; i++ )
|
||||||
|
{
|
||||||
|
if( voice.players_status[i].talking_ack )
|
||||||
|
Voice_Status( i, false );
|
||||||
|
}
|
||||||
|
|
||||||
|
memset( &voice, 0, sizeof( voice ));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=========================
|
||||||
|
Voice_Idle
|
||||||
|
|
||||||
|
Run timeout for all clients
|
||||||
|
=========================
|
||||||
|
*/
|
||||||
|
void Voice_Idle( double frametime )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if( FBitSet( voice_enable.flags, FCVAR_CHANGED ) && !voice_enable.value )
|
||||||
|
{
|
||||||
|
Voice_Shutdown();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update local player status first
|
||||||
|
Voice_StatusTimeout( &voice.local, VOICE_LOOPBACK_INDEX, frametime );
|
||||||
|
|
||||||
|
for( i = 0; i < MAX_CLIENTS; i++ )
|
||||||
|
Voice_StatusTimeout( &voice.players_status[i], i, frametime );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=========================
|
||||||
|
Voice_Init
|
||||||
|
|
||||||
|
Initialize the voice subsystem
|
||||||
|
=========================
|
||||||
|
*/
|
||||||
|
qboolean Voice_Init( const char *pszCodecName, int quality )
|
||||||
|
{
|
||||||
|
if( !voice_enable.value )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( Q_strcmp( pszCodecName, VOICE_OPUS_CUSTOM_CODEC ))
|
||||||
|
{
|
||||||
|
Con_Printf( S_ERROR "Server requested unsupported codec: %s\n", pszCodecName );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// reinitialize only if codec parameters are different
|
||||||
|
if( Q_strcmp( voice.codec, pszCodecName ) && voice.quality != quality )
|
||||||
|
Voice_Shutdown();
|
||||||
|
|
||||||
|
voice.autogain.block_size = 128;
|
||||||
|
|
||||||
|
if( !Voice_InitOpusDecoder( ))
|
||||||
|
{
|
||||||
|
// no reason to init encoder and open audio device
|
||||||
|
// if we can't hear other players
|
||||||
|
Con_Printf( S_ERROR "Voice chat disabled.\n" );
|
||||||
|
Voice_Shutdown();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we can hear others players, so it's fine to fail now
|
||||||
|
voice.initialized = true;
|
||||||
|
Q_strncpy( voice.codec, pszCodecName, sizeof( voice.codec ));
|
||||||
|
|
||||||
|
if( !Voice_InitOpusEncoder( quality ))
|
||||||
|
{
|
||||||
|
Con_Printf( S_WARN "Other players will not be able to hear you.\n" );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
voice.quality = quality;
|
||||||
|
|
||||||
|
if( !VoiceCapture_Init( ))
|
||||||
|
Con_Printf( S_WARN "No microphone is available.\n" );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -0,0 +1,104 @@
|
||||||
|
/*
|
||||||
|
voice.h - voice chat implementation
|
||||||
|
Copyright (C) 2022 Velaron
|
||||||
|
Copyright (C) 2022 SNMetamorph
|
||||||
|
|
||||||
|
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 VOICE_H
|
||||||
|
#define VOICE_H
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "protocol.h" // MAX_CLIENTS
|
||||||
|
#include "sound.h"
|
||||||
|
|
||||||
|
typedef struct OpusCustomEncoder OpusCustomEncoder;
|
||||||
|
typedef struct OpusCustomDecoder OpusCustomDecoder;
|
||||||
|
typedef struct OpusCustomMode OpusCustomMode;
|
||||||
|
|
||||||
|
#define VOICE_LOOPBACK_INDEX (-2)
|
||||||
|
#define VOICE_LOCALCLIENT_INDEX (-1)
|
||||||
|
|
||||||
|
#define VOICE_PCM_CHANNELS 1 // always mono
|
||||||
|
|
||||||
|
// never change these parameters when using opuscustom
|
||||||
|
#define VOICE_OPUS_CUSTOM_SAMPLERATE SOUND_44k
|
||||||
|
// must follow opus custom requirements
|
||||||
|
// also be divisible with MAX_RAW_SAMPLES
|
||||||
|
#define VOICE_OPUS_CUSTOM_FRAME_SIZE 1024
|
||||||
|
#define VOICE_OPUS_CUSTOM_CODEC "opus_custom_44k_512"
|
||||||
|
|
||||||
|
// a1ba: do not change, we don't have any re-encoding support now
|
||||||
|
#define VOICE_DEFAULT_CODEC VOICE_OPUS_CUSTOM_CODEC
|
||||||
|
|
||||||
|
typedef struct voice_status_s
|
||||||
|
{
|
||||||
|
qboolean talking_ack;
|
||||||
|
double talking_timeout;
|
||||||
|
} voice_status_t;
|
||||||
|
|
||||||
|
typedef struct voice_state_s
|
||||||
|
{
|
||||||
|
string codec;
|
||||||
|
int quality;
|
||||||
|
|
||||||
|
qboolean initialized;
|
||||||
|
qboolean is_recording;
|
||||||
|
double start_time;
|
||||||
|
|
||||||
|
voice_status_t local;
|
||||||
|
voice_status_t players_status[MAX_CLIENTS];
|
||||||
|
|
||||||
|
// opus stuff
|
||||||
|
OpusCustomMode *custom_mode;
|
||||||
|
OpusCustomEncoder *encoder;
|
||||||
|
OpusCustomDecoder *decoder;
|
||||||
|
|
||||||
|
// audio info
|
||||||
|
uint width;
|
||||||
|
uint samplerate;
|
||||||
|
uint frame_size; // in samples
|
||||||
|
|
||||||
|
// buffers
|
||||||
|
byte input_buffer[MAX_RAW_SAMPLES];
|
||||||
|
byte output_buffer[MAX_RAW_SAMPLES];
|
||||||
|
byte decompress_buffer[MAX_RAW_SAMPLES];
|
||||||
|
fs_offset_t input_buffer_pos; // in bytes
|
||||||
|
|
||||||
|
// input from file
|
||||||
|
wavdata_t *input_file;
|
||||||
|
fs_offset_t input_file_pos; // in bytes
|
||||||
|
|
||||||
|
// automatic gain control
|
||||||
|
struct {
|
||||||
|
int block_size;
|
||||||
|
float current_gain;
|
||||||
|
float next_gain;
|
||||||
|
float gain_multiplier;
|
||||||
|
} autogain;
|
||||||
|
} voice_state_t;
|
||||||
|
|
||||||
|
extern voice_state_t voice;
|
||||||
|
|
||||||
|
void CL_AddVoiceToDatagram( void );
|
||||||
|
|
||||||
|
void Voice_RegisterCvars( void );
|
||||||
|
qboolean Voice_Init( const char *pszCodecName, int quality );
|
||||||
|
void Voice_Idle( double frametime );
|
||||||
|
qboolean Voice_IsRecording( void );
|
||||||
|
void Voice_RecordStop( void );
|
||||||
|
void Voice_RecordStart( void );
|
||||||
|
void Voice_Disconnect( void );
|
||||||
|
void Voice_AddIncomingData( int ent, const byte *data, uint size, uint frames );
|
||||||
|
void Voice_StatusAck( voice_status_t *status, int playerIndex );
|
||||||
|
|
||||||
|
#endif // VOICE_H
|
|
@ -984,7 +984,7 @@ static void Cmd_ExecuteStringWithPrivilegeCheck( const char *text, qboolean isPr
|
||||||
cmd_condlevel = 0;
|
cmd_condlevel = 0;
|
||||||
|
|
||||||
// cvar value substitution
|
// cvar value substitution
|
||||||
if( CVAR_TO_BOOL( cmd_scripting ))
|
if( CVAR_TO_BOOL( cmd_scripting ) && isPrivileged )
|
||||||
{
|
{
|
||||||
while( *text )
|
while( *text )
|
||||||
{
|
{
|
||||||
|
@ -1171,17 +1171,21 @@ void Cmd_List_f( void )
|
||||||
{
|
{
|
||||||
cmd_t *cmd;
|
cmd_t *cmd;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
const char *match;
|
size_t matchlen = 0;
|
||||||
|
const char *match = NULL;
|
||||||
|
|
||||||
if( Cmd_Argc() > 1 ) match = Cmd_Argv( 1 );
|
if( Cmd_Argc() > 1 )
|
||||||
else match = NULL;
|
{
|
||||||
|
match = Cmd_Argv( 1 );
|
||||||
|
matchlen = Q_strlen( match );
|
||||||
|
}
|
||||||
|
|
||||||
for( cmd = cmd_functions; cmd; cmd = cmd->next )
|
for( cmd = cmd_functions; cmd; cmd = cmd->next )
|
||||||
{
|
{
|
||||||
if( cmd->name[0] == '@' )
|
if( cmd->name[0] == '@' )
|
||||||
continue; // never show system cmds
|
continue; // never show system cmds
|
||||||
|
|
||||||
if( match && !Q_stricmpext( match, cmd->name ))
|
if( match && !Q_strnicmpext( match, cmd->name, matchlen ))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Con_Printf( " %-*s ^3%s^7\n", 32, cmd->name, cmd->desc );
|
Con_Printf( " %-*s ^3%s^7\n", 32, cmd->name, cmd->desc );
|
||||||
|
@ -1391,8 +1395,8 @@ void Cmd_Init( void )
|
||||||
#endif // XASH_DEDICATED
|
#endif // XASH_DEDICATED
|
||||||
Cmd_AddRestrictedCommand( "alias", Cmd_Alias_f, "create a script function. Without arguments show the list of all alias" );
|
Cmd_AddRestrictedCommand( "alias", Cmd_Alias_f, "create a script function. Without arguments show the list of all alias" );
|
||||||
Cmd_AddRestrictedCommand( "unalias", Cmd_UnAlias_f, "remove a script function" );
|
Cmd_AddRestrictedCommand( "unalias", Cmd_UnAlias_f, "remove a script function" );
|
||||||
Cmd_AddCommand( "if", Cmd_If_f, "compare and set condition bits" );
|
Cmd_AddRestrictedCommand( "if", Cmd_If_f, "compare and set condition bits" );
|
||||||
Cmd_AddCommand( "else", Cmd_Else_f, "invert condition bit" );
|
Cmd_AddRestrictedCommand( "else", Cmd_Else_f, "invert condition bit" );
|
||||||
|
|
||||||
#if defined(XASH_HASHED_VARS)
|
#if defined(XASH_HASHED_VARS)
|
||||||
Cmd_AddCommand( "basecmd_stats", BaseCmd_Stats_f, "print info about basecmd usage" );
|
Cmd_AddCommand( "basecmd_stats", BaseCmd_Stats_f, "print info about basecmd usage" );
|
||||||
|
|
|
@ -21,6 +21,7 @@ GNU General Public License for more details.
|
||||||
#define S_WARN "^3Warning:^7 "
|
#define S_WARN "^3Warning:^7 "
|
||||||
#define S_ERROR "^1Error:^7 "
|
#define S_ERROR "^1Error:^7 "
|
||||||
#define S_USAGE "Usage: "
|
#define S_USAGE "Usage: "
|
||||||
|
#define S_USAGE_INDENT " "
|
||||||
|
|
||||||
#define S_OPENGL_NOTE "^2OpenGL Note:^7 "
|
#define S_OPENGL_NOTE "^2OpenGL Note:^7 "
|
||||||
#define S_OPENGL_WARN "^3OpenGL Warning:^7 "
|
#define S_OPENGL_WARN "^3OpenGL Warning:^7 "
|
||||||
|
|
|
@ -159,13 +159,13 @@ extern convar_t *scr_download;
|
||||||
extern convar_t *cmd_scripting;
|
extern convar_t *cmd_scripting;
|
||||||
extern convar_t *sv_maxclients;
|
extern convar_t *sv_maxclients;
|
||||||
extern convar_t *cl_allow_levelshots;
|
extern convar_t *cl_allow_levelshots;
|
||||||
extern convar_t *vid_displayfrequency;
|
|
||||||
extern convar_t host_developer;
|
extern convar_t host_developer;
|
||||||
extern convar_t *host_limitlocal;
|
extern convar_t *host_limitlocal;
|
||||||
extern convar_t *host_framerate;
|
extern convar_t *host_framerate;
|
||||||
extern convar_t *host_maxfps;
|
extern convar_t *host_maxfps;
|
||||||
extern convar_t sys_timescale;
|
extern convar_t sys_timescale;
|
||||||
extern convar_t cl_filterstuffcmd;
|
extern convar_t cl_filterstuffcmd;
|
||||||
|
extern convar_t rcon_password;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
==============================================================
|
==============================================================
|
||||||
|
@ -307,6 +307,16 @@ typedef struct
|
||||||
float scale; // curstate.scale
|
float scale; // curstate.scale
|
||||||
} tentlist_t;
|
} tentlist_t;
|
||||||
|
|
||||||
|
typedef enum bugcomp_e
|
||||||
|
{
|
||||||
|
// default mode, we assume that user dlls are not relying on engine bugs
|
||||||
|
BUGCOMP_OFF,
|
||||||
|
|
||||||
|
// GoldSrc mode, user dlls are relying on GoldSrc specific bugs
|
||||||
|
// but fixing them may break regular Xash games
|
||||||
|
BUGCOMP_GOLDSRC,
|
||||||
|
} bugcomp_t;
|
||||||
|
|
||||||
typedef struct host_parm_s
|
typedef struct host_parm_s
|
||||||
{
|
{
|
||||||
HINSTANCE hInst;
|
HINSTANCE hInst;
|
||||||
|
@ -348,14 +358,13 @@ typedef struct host_parm_s
|
||||||
qboolean allow_cheats; // this host will allow cheating
|
qboolean allow_cheats; // this host will allow cheating
|
||||||
qboolean con_showalways; // show console always (developer and dedicated)
|
qboolean con_showalways; // show console always (developer and dedicated)
|
||||||
qboolean change_game; // initialize when game is changed
|
qboolean change_game; // initialize when game is changed
|
||||||
qboolean mouse_visible; // vgui override cursor control
|
qboolean mouse_visible; // vgui override cursor control (never change outside Platform_SetCursorType!)
|
||||||
qboolean shutdown_issued; // engine is shutting down
|
qboolean shutdown_issued; // engine is shutting down
|
||||||
qboolean force_draw_version; // used when fraps is loaded
|
qboolean force_draw_version; // used when fraps is loaded
|
||||||
float force_draw_version_time;
|
float force_draw_version_time;
|
||||||
qboolean apply_game_config; // when true apply only to game cvars and ignore all other commands
|
qboolean apply_game_config; // when true apply only to game cvars and ignore all other commands
|
||||||
qboolean apply_opengl_config;// when true apply only to opengl cvars and ignore all other commands
|
qboolean apply_opengl_config;// when true apply only to opengl cvars and ignore all other commands
|
||||||
qboolean config_executed; // a bit who indicated was config.cfg already executed e.g. from valve.rc
|
qboolean config_executed; // a bit who indicated was config.cfg already executed e.g. from valve.rc
|
||||||
int sv_cvars_restored; // count of restored server cvars
|
|
||||||
qboolean crashed; // set to true if crashed
|
qboolean crashed; // set to true if crashed
|
||||||
qboolean daemonized;
|
qboolean daemonized;
|
||||||
qboolean enabledll;
|
qboolean enabledll;
|
||||||
|
@ -381,6 +390,14 @@ typedef struct host_parm_s
|
||||||
struct decallist_s *decalList; // used for keep decals, when renderer is restarted or changed
|
struct decallist_s *decalList; // used for keep decals, when renderer is restarted or changed
|
||||||
int numdecals;
|
int numdecals;
|
||||||
|
|
||||||
|
// bug compatibility level, for very "special" games
|
||||||
|
bugcomp_t bugcomp;
|
||||||
|
|
||||||
|
// measure time to first frame
|
||||||
|
double starttime;
|
||||||
|
|
||||||
|
// count of sleeps can be inserted between frames
|
||||||
|
double pureframetime;
|
||||||
} host_parm_t;
|
} host_parm_t;
|
||||||
|
|
||||||
extern host_parm_t host;
|
extern host_parm_t host;
|
||||||
|
@ -726,7 +743,6 @@ char *CL_Userinfo( void );
|
||||||
void CL_LegacyUpdateInfo( void );
|
void CL_LegacyUpdateInfo( void );
|
||||||
void CL_CharEvent( int key );
|
void CL_CharEvent( int key );
|
||||||
qboolean CL_DisableVisibility( void );
|
qboolean CL_DisableVisibility( void );
|
||||||
int CL_PointContents( const vec3_t point );
|
|
||||||
byte *COM_LoadFile( const char *filename, int usehunk, int *pLength );
|
byte *COM_LoadFile( const char *filename, int usehunk, int *pLength );
|
||||||
int CL_GetDemoComment( const char *demoname, char *comment );
|
int CL_GetDemoComment( const char *demoname, char *comment );
|
||||||
void COM_AddAppDirectoryToSearchPath( const char *pszBaseDir, const char *appName );
|
void COM_AddAppDirectoryToSearchPath( const char *pszBaseDir, const char *appName );
|
||||||
|
@ -735,7 +751,6 @@ struct cmd_s *Cmd_GetFirstFunctionHandle( void );
|
||||||
struct cmd_s *Cmd_GetNextFunctionHandle( struct cmd_s *cmd );
|
struct cmd_s *Cmd_GetNextFunctionHandle( struct cmd_s *cmd );
|
||||||
struct cmdalias_s *Cmd_AliasGetList( void );
|
struct cmdalias_s *Cmd_AliasGetList( void );
|
||||||
const char *Cmd_GetName( struct cmd_s *cmd );
|
const 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_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, int 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 SV_CreateDecal( sizebuf_t *msg, const float *origin, int decalIndex, int entityIndex, int modelIndex, int flags, float scale );
|
||||||
|
@ -748,7 +763,6 @@ void R_ClearAllDecals( void );
|
||||||
void CL_ClearStaticEntities( void );
|
void CL_ClearStaticEntities( void );
|
||||||
qboolean S_StreamGetCurrentState( char *currentTrack, char *loopTrack, int *position );
|
qboolean S_StreamGetCurrentState( char *currentTrack, char *loopTrack, int *position );
|
||||||
struct cl_entity_s *CL_GetEntityByIndex( int index );
|
struct cl_entity_s *CL_GetEntityByIndex( int index );
|
||||||
struct player_info_s *CL_GetPlayerInfo( int playerIndex );
|
|
||||||
void CL_ServerCommand( qboolean reliable, const char *fmt, ... ) _format( 2 );
|
void CL_ServerCommand( qboolean reliable, const char *fmt, ... ) _format( 2 );
|
||||||
void CL_HudMessage( const char *pMessage );
|
void CL_HudMessage( const char *pMessage );
|
||||||
const char *CL_MsgInfo( int cmd );
|
const char *CL_MsgInfo( int cmd );
|
||||||
|
@ -856,6 +870,7 @@ void GAME_EXPORT ID_SetCustomClientID( const char *id );
|
||||||
void NET_InitMasters( void );
|
void NET_InitMasters( void );
|
||||||
void NET_SaveMasters( void );
|
void NET_SaveMasters( void );
|
||||||
qboolean NET_SendToMasters( netsrc_t sock, size_t len, const void *data );
|
qboolean NET_SendToMasters( netsrc_t sock, size_t len, const void *data );
|
||||||
|
qboolean NET_IsMasterAdr( netadr_t adr );
|
||||||
|
|
||||||
#ifdef REF_DLL
|
#ifdef REF_DLL
|
||||||
#error "common.h in ref_dll"
|
#error "common.h in ref_dll"
|
||||||
|
|
|
@ -82,6 +82,7 @@ int Cmd_ListMaps( search_t *t, char *lastmapname, size_t len )
|
||||||
{
|
{
|
||||||
dheader_t *header;
|
dheader_t *header;
|
||||||
dextrahdr_t *hdrext;
|
dextrahdr_t *hdrext;
|
||||||
|
dlump_t entities;
|
||||||
|
|
||||||
memset( buf, 0, sizeof( buf ));
|
memset( buf, 0, sizeof( buf ));
|
||||||
FS_Read( f, buf, sizeof( buf ));
|
FS_Read( f, buf, sizeof( buf ));
|
||||||
|
@ -89,10 +90,10 @@ int Cmd_ListMaps( search_t *t, char *lastmapname, size_t len )
|
||||||
ver = header->version;
|
ver = header->version;
|
||||||
|
|
||||||
// check all the lumps and some other errors
|
// check all the lumps and some other errors
|
||||||
if( Mod_TestBmodelLumps( t->filenames[i], buf, true ))
|
if( Mod_TestBmodelLumps( f, t->filenames[i], buf, true, &entities ))
|
||||||
{
|
{
|
||||||
lumpofs = header->lumps[LUMP_ENTITIES].fileofs;
|
lumpofs = entities.fileofs;
|
||||||
lumplen = header->lumps[LUMP_ENTITIES].filelen;
|
lumplen = entities.filelen;
|
||||||
ver = header->version;
|
ver = header->version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -368,7 +369,7 @@ qboolean Cmd_GetSavesList( const char *s, char *completedname, int length )
|
||||||
string matchbuf;
|
string matchbuf;
|
||||||
int i, numsaves;
|
int i, numsaves;
|
||||||
|
|
||||||
t = FS_Search( va( "%s%s*.sav", DEFAULT_SAVE_DIRECTORY, s ), true, true ); // lookup only in gamedir
|
t = FS_Search( va( DEFAULT_SAVE_DIRECTORY "%s*.sav", s ), true, true ); // lookup only in gamedir
|
||||||
if( !t ) return false;
|
if( !t ) return false;
|
||||||
|
|
||||||
COM_FileBase( t->filenames[0], matchbuf );
|
COM_FileBase( t->filenames[0], matchbuf );
|
||||||
|
@ -904,21 +905,22 @@ qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
|
||||||
{
|
{
|
||||||
int num_spawnpoints = 0;
|
int num_spawnpoints = 0;
|
||||||
dheader_t *header;
|
dheader_t *header;
|
||||||
|
dlump_t entities;
|
||||||
|
|
||||||
memset( buf, 0, MAX_SYSPATH );
|
memset( buf, 0, MAX_SYSPATH );
|
||||||
FS_Read( f, buf, MAX_SYSPATH );
|
FS_Read( f, buf, MAX_SYSPATH );
|
||||||
header = (dheader_t *)buf;
|
header = (dheader_t *)buf;
|
||||||
|
|
||||||
// check all the lumps and some other errors
|
// check all the lumps and some other errors
|
||||||
if( !Mod_TestBmodelLumps( t->filenames[i], buf, true ))
|
if( !Mod_TestBmodelLumps( f, t->filenames[i], buf, true, &entities ))
|
||||||
{
|
{
|
||||||
FS_Close( f );
|
FS_Close( f );
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// after call Mod_TestBmodelLumps we gurantee what map is valid
|
// after call Mod_TestBmodelLumps we gurantee what map is valid
|
||||||
lumpofs = header->lumps[LUMP_ENTITIES].fileofs;
|
lumpofs = entities.fileofs;
|
||||||
lumplen = header->lumps[LUMP_ENTITIES].filelen;
|
lumplen = entities.filelen;
|
||||||
|
|
||||||
Q_strncpy( entfilename, t->filenames[i], sizeof( entfilename ));
|
Q_strncpy( entfilename, t->filenames[i], sizeof( entfilename ));
|
||||||
COM_StripExtension( entfilename );
|
COM_StripExtension( entfilename );
|
||||||
|
@ -1324,8 +1326,9 @@ static void Cmd_WriteHelp(const char *name, const char *unused, const char *desc
|
||||||
{
|
{
|
||||||
int length;
|
int length;
|
||||||
|
|
||||||
if( !desc || !Q_strcmp( desc, "" ))
|
if( !COM_CheckString( desc ))
|
||||||
return; // ignore fantom cmds
|
return; // ignore fantom cmds
|
||||||
|
|
||||||
if( name[0] == '+' || name[0] == '-' )
|
if( name[0] == '+' || name[0] == '-' )
|
||||||
return; // key bindings
|
return; // key bindings
|
||||||
|
|
||||||
|
@ -1354,7 +1357,6 @@ void Host_FinalizeConfig( file_t *f, const char *config )
|
||||||
FS_Close( f );
|
FS_Close( f );
|
||||||
FS_Delete( backup );
|
FS_Delete( backup );
|
||||||
FS_Rename( config, backup );
|
FS_Rename( config, backup );
|
||||||
FS_Delete( config );
|
|
||||||
FS_Rename( newcfg, config );
|
FS_Rename( newcfg, config );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,9 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
*/
|
*/
|
||||||
|
#ifndef _GNU_SOURCE
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
|
@ -23,9 +25,9 @@ Sys_Crash
|
||||||
Crash handler, called from system
|
Crash handler, called from system
|
||||||
================
|
================
|
||||||
*/
|
*/
|
||||||
#if XASH_CRASHHANDLER == CRASHHANDLER_DBGHELP || XASH_CRASHHANDLER == CRASHHANDLER_WIN32
|
#if XASH_WIN32
|
||||||
|
|
||||||
#if XASH_CRASHHANDLER == CRASHHANDLER_DBGHELP
|
#if DBGHELP
|
||||||
|
|
||||||
#pragma comment( lib, "dbghelp" )
|
#pragma comment( lib, "dbghelp" )
|
||||||
|
|
||||||
|
@ -187,7 +189,7 @@ static void Sys_StackTrace( PEXCEPTION_POINTERS pInfo )
|
||||||
|
|
||||||
SymCleanup( process );
|
SymCleanup( process );
|
||||||
}
|
}
|
||||||
#endif /* XASH_CRASHHANDLER == CRASHHANDLER_DBGHELP */
|
#endif /* DBGHELP */
|
||||||
|
|
||||||
LPTOP_LEVEL_EXCEPTION_FILTER oldFilter;
|
LPTOP_LEVEL_EXCEPTION_FILTER oldFilter;
|
||||||
static long _stdcall Sys_Crash( PEXCEPTION_POINTERS pInfo )
|
static long _stdcall Sys_Crash( PEXCEPTION_POINTERS pInfo )
|
||||||
|
@ -198,7 +200,7 @@ static long _stdcall Sys_Crash( PEXCEPTION_POINTERS pInfo )
|
||||||
// check to avoid recursive call
|
// check to avoid recursive call
|
||||||
host.crashed = true;
|
host.crashed = true;
|
||||||
|
|
||||||
#if XASH_CRASHHANDLER == CRASHHANDLER_DBGHELP
|
#if DBGHELP
|
||||||
Sys_StackTrace( pInfo );
|
Sys_StackTrace( pInfo );
|
||||||
#else
|
#else
|
||||||
Sys_Warn( "Sys_Crash: call %p at address %p", pInfo->ExceptionRecord->ExceptionAddress, pInfo->ExceptionRecord->ExceptionCode );
|
Sys_Warn( "Sys_Crash: call %p at address %p", pInfo->ExceptionRecord->ExceptionAddress, pInfo->ExceptionRecord->ExceptionCode );
|
||||||
|
@ -237,21 +239,21 @@ void Sys_RestoreCrashHandler( void )
|
||||||
if( oldFilter ) SetUnhandledExceptionFilter( oldFilter );
|
if( oldFilter ) SetUnhandledExceptionFilter( oldFilter );
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif XASH_CRASHHANDLER == CRASHHANDLER_UCONTEXT
|
#elif XASH_FREEBSD || XASH_NETBSD || XASH_OPENBSD || XASH_ANDROID || XASH_LINUX
|
||||||
// Posix signal handler
|
// Posix signal handler
|
||||||
|
|
||||||
#include "library.h"
|
|
||||||
|
|
||||||
#if XASH_FREEBSD || XASH_NETBSD || XASH_OPENBSD || XASH_ANDROID || XASH_LINUX
|
|
||||||
#define HAVE_UCONTEXT_H 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_UCONTEXT_H
|
|
||||||
#include <ucontext.h>
|
#include <ucontext.h>
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
#include "library.h"
|
||||||
|
|
||||||
|
#define STACK_BACKTRACE_STR "Stack backtrace:\n"
|
||||||
|
#define STACK_DUMP_STR "Stack dump:\n"
|
||||||
|
|
||||||
|
#define STACK_BACKTRACE_STR_LEN ( sizeof( STACK_BACKTRACE_STR ) - 1 )
|
||||||
|
#define STACK_DUMP_STR_LEN ( sizeof( STACK_DUMP_STR ) - 1 )
|
||||||
|
#define ALIGN( x, y ) (((uintptr_t) ( x ) + (( y ) - 1 )) & ~(( y ) - 1 ))
|
||||||
|
|
||||||
|
static struct sigaction oldFilter;
|
||||||
|
|
||||||
#ifdef XASH_DYNAMIC_DLADDR
|
#ifdef XASH_DYNAMIC_DLADDR
|
||||||
static int d_dladdr( void *sym, Dl_info *info )
|
static int d_dladdr( void *sym, Dl_info *info )
|
||||||
|
@ -282,28 +284,18 @@ static int Sys_PrintFrame( char *buf, int len, int i, void *addr )
|
||||||
if( dlinfo.dli_sname )
|
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
|
(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 "Stack backtrace:\n"
|
|
||||||
#define STACK_DUMP_STR "Stack dump:\n"
|
|
||||||
|
|
||||||
#define STACK_BACKTRACE_STR_LEN (sizeof( STACK_BACKTRACE_STR ) - 1)
|
|
||||||
#define STACK_DUMP_STR_LEN (sizeof( STACK_DUMP_STR ) - 1)
|
|
||||||
#define ALIGN( x, y ) (((uintptr_t) (x) + ((y)-1)) & ~((y)-1))
|
|
||||||
|
|
||||||
static void Sys_Crash( int signal, siginfo_t *si, void *context)
|
static void Sys_Crash( int signal, siginfo_t *si, void *context)
|
||||||
{
|
{
|
||||||
void *pc = NULL, **bp = NULL, **sp = NULL; // this must be set for every OS!
|
void *pc = NULL, **bp = NULL, **sp = NULL; // this must be set for every OS!
|
||||||
char message[8192];
|
char message[8192];
|
||||||
int len, logfd, i = 0;
|
int len, logfd, i = 0;
|
||||||
size_t pagesize;
|
|
||||||
|
|
||||||
#if XASH_OPENBSD
|
#if XASH_OPENBSD
|
||||||
struct sigcontext *ucontext = (struct sigcontext*)context;
|
struct sigcontext *ucontext = (struct sigcontext*)context;
|
||||||
|
@ -358,10 +350,10 @@ static void Sys_Crash( int signal, siginfo_t *si, void *context)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// safe actions first, stack and memory may be corrupted
|
// safe actions first, stack and memory may be corrupted
|
||||||
len = Q_snprintf( message, sizeof( message ), "Ver: %s %s (build %i-%s, %s-%s)\n",
|
len = Q_snprintf( message, sizeof( message ), "Ver: " XASH_ENGINE_NAME " " XASH_VERSION " (build %i-%s, %s-%s)\n",
|
||||||
XASH_ENGINE_NAME, XASH_VERSION, Q_buildnum(), Q_buildcommit(), Q_buildos(), Q_buildarch() );
|
Q_buildnum(), Q_buildcommit(), Q_buildos(), Q_buildarch() );
|
||||||
|
|
||||||
#if !XASH_BSD
|
#if !XASH_FREEBSD && !XASH_NETBSD && !XASH_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 );
|
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
|
#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 );
|
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 );
|
||||||
|
@ -380,6 +372,7 @@ static void Sys_Crash( int signal, siginfo_t *si, void *context)
|
||||||
if( pc && bp && sp )
|
if( pc && bp && sp )
|
||||||
{
|
{
|
||||||
size_t pagesize = sysconf( _SC_PAGESIZE );
|
size_t pagesize = sysconf( _SC_PAGESIZE );
|
||||||
|
|
||||||
// try to print backtrace
|
// try to print backtrace
|
||||||
write( STDERR_FILENO, STACK_BACKTRACE_STR, STACK_BACKTRACE_STR_LEN );
|
write( STDERR_FILENO, STACK_BACKTRACE_STR, STACK_BACKTRACE_STR_LEN );
|
||||||
write( logfd, STACK_BACKTRACE_STR, STACK_BACKTRACE_STR_LEN );
|
write( logfd, STACK_BACKTRACE_STR, STACK_BACKTRACE_STR_LEN );
|
||||||
|
@ -447,7 +440,7 @@ static void Sys_Crash( int signal, siginfo_t *si, void *context)
|
||||||
|
|
||||||
void Sys_SetupCrashHandler( void )
|
void Sys_SetupCrashHandler( void )
|
||||||
{
|
{
|
||||||
struct sigaction act;
|
struct sigaction act = { 0 };
|
||||||
act.sa_sigaction = Sys_Crash;
|
act.sa_sigaction = Sys_Crash;
|
||||||
act.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
act.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
||||||
sigaction( SIGSEGV, &act, &oldFilter );
|
sigaction( SIGSEGV, &act, &oldFilter );
|
||||||
|
@ -464,7 +457,7 @@ void Sys_RestoreCrashHandler( void )
|
||||||
sigaction( SIGILL, &oldFilter, NULL );
|
sigaction( SIGILL, &oldFilter, NULL );
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif XASH_CRASHHANDLER == CRASHHANDLER_NULL
|
#else
|
||||||
|
|
||||||
void Sys_SetupCrashHandler( void )
|
void Sys_SetupCrashHandler( void )
|
||||||
{
|
{
|
||||||
|
|
|
@ -17,9 +17,23 @@ GNU General Public License for more details.
|
||||||
#include "custom.h"
|
#include "custom.h"
|
||||||
#include "ref_common.h"
|
#include "ref_common.h"
|
||||||
|
|
||||||
qboolean CustomDecal_Validate( void *raw, int nFileSize )
|
static rgbdata_t *CustomDecal_LoadImage( const char *path, void *raw, int size )
|
||||||
{
|
{
|
||||||
rgbdata_t *test = FS_LoadImage( "#logo.bmp", raw, nFileSize );
|
const char *testname;
|
||||||
|
|
||||||
|
// this way we limit file types
|
||||||
|
if( !Q_stricmp( COM_FileExtension( path ), "png" ))
|
||||||
|
testname = "#logo.png";
|
||||||
|
else testname = "#logo.bmp";
|
||||||
|
|
||||||
|
Image_SetForceFlags( IL_LOAD_PLAYER_DECAL );
|
||||||
|
|
||||||
|
return FS_LoadImage( testname, raw, size );
|
||||||
|
}
|
||||||
|
|
||||||
|
static qboolean CustomDecal_Validate( const char *path, void *raw, int nFileSize )
|
||||||
|
{
|
||||||
|
rgbdata_t *test = CustomDecal_LoadImage( path, raw, nFileSize );
|
||||||
|
|
||||||
if( test )
|
if( test )
|
||||||
{
|
{
|
||||||
|
@ -97,21 +111,25 @@ qboolean COM_CreateCustomization( customization_t *pListHead, resource_t *pResou
|
||||||
{
|
{
|
||||||
pCust->resource.playernum = playernumber;
|
pCust->resource.playernum = playernumber;
|
||||||
|
|
||||||
if( CustomDecal_Validate( pCust->pBuffer, pResource->nDownloadSize ))
|
if( CustomDecal_Validate( pResource->szFileName, pCust->pBuffer, pResource->nDownloadSize ))
|
||||||
{
|
{
|
||||||
if( !FBitSet( flags, FCUST_IGNOREINIT ))
|
if( !FBitSet( flags, FCUST_IGNOREINIT ))
|
||||||
{
|
{
|
||||||
if( pResource->nDownloadSize >= (1 * 1024) && pResource->nDownloadSize <= ( 16 * 1024 ))
|
if( pResource->nDownloadSize >= (1 * 1024) && pResource->nDownloadSize <= ( 128 * 1024 ))
|
||||||
{
|
{
|
||||||
pCust->bTranslated = true;
|
pCust->bTranslated = true;
|
||||||
pCust->nUserData1 = 0;
|
pCust->nUserData1 = 0;
|
||||||
pCust->nUserData2 = 1;
|
pCust->nUserData2 = 1;
|
||||||
|
|
||||||
if( !FBitSet( flags, FCUST_WIPEDATA ))
|
if( !FBitSet( flags, FCUST_WIPEDATA ))
|
||||||
pCust->pInfo = FS_LoadImage( "#logo.bmp", pCust->pBuffer, pCust->resource.nDownloadSize );
|
pCust->pInfo = CustomDecal_LoadImage( pResource->szFileName, pCust->pBuffer, pCust->resource.nDownloadSize );
|
||||||
else pCust->pInfo = NULL;
|
else pCust->pInfo = NULL;
|
||||||
if( nLumps ) *nLumps = 1;
|
if( nLumps ) *nLumps = 1;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Con_Printf( S_WARN "Ignoring custom decal \"%s\": wrong size (%i bytes)\n", pResource->szFileName, pResource->nDownloadSize );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,30 @@ GNU General Public License for more details.
|
||||||
convar_t *cvar_vars = NULL; // head of list
|
convar_t *cvar_vars = NULL; // head of list
|
||||||
convar_t *cmd_scripting;
|
convar_t *cmd_scripting;
|
||||||
|
|
||||||
CVAR_DEFINE_AUTO( cl_filterstuffcmd, "0", FCVAR_ARCHIVE | FCVAR_PRIVILEGED, "filter commands coming from server" );
|
#ifdef HACKS_RELATED_HLMODS
|
||||||
|
typedef struct cvar_filter_quirks_s
|
||||||
|
{
|
||||||
|
const char *gamedir; // gamedir to enable for
|
||||||
|
const char *cvars; // list of cvars should be excluded from filter
|
||||||
|
} cvar_filter_quirks_t;
|
||||||
|
|
||||||
|
static cvar_filter_quirks_t cvar_filter_quirks[] =
|
||||||
|
{
|
||||||
|
// EXAMPLE:
|
||||||
|
//{
|
||||||
|
// "valve",
|
||||||
|
// "test;test1;test100"
|
||||||
|
//},
|
||||||
|
{
|
||||||
|
"ricochet",
|
||||||
|
"r_drawviewmodel",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static cvar_filter_quirks_t *cvar_active_filter_quirks = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CVAR_DEFINE_AUTO( cl_filterstuffcmd, "1", FCVAR_ARCHIVE | FCVAR_PRIVILEGED, "filter commands coming from server" );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
============
|
============
|
||||||
|
@ -220,6 +243,24 @@ const char *Cvar_ValidateString( convar_t *var, const char *value )
|
||||||
return pszValue;
|
return pszValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
============
|
||||||
|
Cvar_ValidateVarName
|
||||||
|
============
|
||||||
|
*/
|
||||||
|
static qboolean Cvar_ValidateVarName( const char *s, qboolean isvalue )
|
||||||
|
{
|
||||||
|
if( !s )
|
||||||
|
return false;
|
||||||
|
if( Q_strchr( s, '\\' ) && !isvalue )
|
||||||
|
return false;
|
||||||
|
if( Q_strchr( s, '\"' ))
|
||||||
|
return false;
|
||||||
|
if( Q_strchr( s, ';' ) && !isvalue )
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
============
|
============
|
||||||
Cvar_UnlinkVar
|
Cvar_UnlinkVar
|
||||||
|
@ -368,7 +409,7 @@ convar_t *Cvar_Get( const char *name, const char *value, int flags, const char *
|
||||||
// which executed from the config file. So we don't need to
|
// which executed from the config file. So we don't need to
|
||||||
// change value here: we *already* have actual value from config.
|
// change value here: we *already* have actual value from config.
|
||||||
// in other cases we need to rewrite them
|
// in other cases we need to rewrite them
|
||||||
if( Q_strcmp( var->desc, "" ))
|
if( COM_CheckStringEmpty( var->desc ))
|
||||||
{
|
{
|
||||||
// directly set value
|
// directly set value
|
||||||
freestring( var->string );
|
freestring( var->string );
|
||||||
|
@ -495,6 +536,113 @@ void Cvar_RegisterVariable( convar_t *var )
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
============
|
||||||
|
Cvar_Set2
|
||||||
|
============
|
||||||
|
*/
|
||||||
|
static convar_t *Cvar_Set2( const char *var_name, const char *value )
|
||||||
|
{
|
||||||
|
convar_t *var;
|
||||||
|
const char *pszValue;
|
||||||
|
qboolean dll_variable = false;
|
||||||
|
qboolean force = false;
|
||||||
|
|
||||||
|
if( !Cvar_ValidateVarName( var_name, false ))
|
||||||
|
{
|
||||||
|
Con_DPrintf( S_ERROR "Invalid cvar name string: %s\n", var_name );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
var = Cvar_FindVar( var_name );
|
||||||
|
if( !var )
|
||||||
|
{
|
||||||
|
// if cvar not found, create it
|
||||||
|
return Cvar_Get( var_name, value, FCVAR_USER_CREATED, NULL );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( !Cmd_CurrentCommandIsPrivileged( ))
|
||||||
|
{
|
||||||
|
if( FBitSet( var->flags, FCVAR_PRIVILEGED ))
|
||||||
|
{
|
||||||
|
Con_Printf( "%s is priveleged.\n", var->name );
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( cl_filterstuffcmd.value > 0.0f && FBitSet( var->flags, FCVAR_FILTERABLE ))
|
||||||
|
{
|
||||||
|
Con_Printf( "%s is filterable.\n", var->name );
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// use this check to prevent acessing for unexisting fields
|
||||||
|
// for cvar_t: latched_string, description, etc
|
||||||
|
dll_variable = FBitSet( var->flags, FCVAR_EXTDLL );
|
||||||
|
|
||||||
|
// check value
|
||||||
|
if( !value )
|
||||||
|
{
|
||||||
|
if( !FBitSet( var->flags, FCVAR_EXTENDED|FCVAR_ALLOCATED ))
|
||||||
|
{
|
||||||
|
Con_Printf( "%s has no default value and can't be reset.\n", var->name );
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( dll_variable )
|
||||||
|
value = "0";
|
||||||
|
else
|
||||||
|
value = var->def_string; // reset to default value
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !Q_strcmp( value, var->string ))
|
||||||
|
return var;
|
||||||
|
|
||||||
|
// any latched values not allowed for game cvars
|
||||||
|
if( dll_variable )
|
||||||
|
force = true;
|
||||||
|
|
||||||
|
if( !force )
|
||||||
|
{
|
||||||
|
if( FBitSet( var->flags, FCVAR_READ_ONLY ))
|
||||||
|
{
|
||||||
|
Con_Printf( "%s is read-only.\n", var->name );
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( FBitSet( var->flags, FCVAR_CHEAT ) && !host.allow_cheats )
|
||||||
|
{
|
||||||
|
Con_Printf( "%s is cheat protected.\n", var->name );
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
|
// just tell user about deferred changes
|
||||||
|
if( FBitSet( var->flags, FCVAR_LATCH ) && ( SV_Active() || CL_Active( )))
|
||||||
|
Con_Printf( "%s will be changed upon restarting.\n", var->name );
|
||||||
|
}
|
||||||
|
|
||||||
|
pszValue = Cvar_ValidateString( var, value );
|
||||||
|
|
||||||
|
// nothing to change
|
||||||
|
if( !Q_strcmp( pszValue, var->string ))
|
||||||
|
return var;
|
||||||
|
|
||||||
|
// fill it cls.userinfo, svs.serverinfo
|
||||||
|
if( !Cvar_UpdateInfo( var, pszValue, true ))
|
||||||
|
return var;
|
||||||
|
|
||||||
|
// and finally changed the cvar itself
|
||||||
|
freestring( var->string );
|
||||||
|
var->string = copystring( pszValue );
|
||||||
|
var->value = Q_atof( var->string );
|
||||||
|
|
||||||
|
// tell engine about changes
|
||||||
|
Cvar_Changed( var );
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
============
|
============
|
||||||
Cvar_DirectSet
|
Cvar_DirectSet
|
||||||
|
@ -777,6 +925,39 @@ static qboolean Cvar_ShouldSetCvar( convar_t *v, qboolean isPrivileged )
|
||||||
if( cl_filterstuffcmd.value <= 0.0f )
|
if( cl_filterstuffcmd.value <= 0.0f )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
#ifdef HACKS_RELATED_HLMODS
|
||||||
|
// check if game-specific filter exceptions should be applied
|
||||||
|
// TODO: for cmd exceptions, make generic function
|
||||||
|
if( cvar_active_filter_quirks )
|
||||||
|
{
|
||||||
|
const char *cur, *next;
|
||||||
|
|
||||||
|
cur = cvar_active_filter_quirks->cvars;
|
||||||
|
next = Q_strchr( cur, ';' );
|
||||||
|
|
||||||
|
// TODO: implement Q_strchrnul
|
||||||
|
while( cur && *cur )
|
||||||
|
{
|
||||||
|
size_t len = next ? next - cur : Q_strlen( cur );
|
||||||
|
|
||||||
|
// found, quit
|
||||||
|
if( !Q_strnicmp( cur, v->name, len ))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if( next )
|
||||||
|
{
|
||||||
|
cur = next + 1;
|
||||||
|
next = Q_strchr( cur, ';' );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// stop
|
||||||
|
cur = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if( FBitSet( v->flags, FCVAR_FILTERABLE ))
|
if( FBitSet( v->flags, FCVAR_FILTERABLE ))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -840,8 +1021,6 @@ qboolean Cvar_CommandWithPrivilegeCheck( convar_t *v, qboolean isPrivileged )
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Cvar_DirectSet( v, Cmd_Argv( 1 ));
|
Cvar_DirectSet( v, Cmd_Argv( 1 ));
|
||||||
if( host.apply_game_config )
|
|
||||||
host.sv_cvars_restored++;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -887,6 +1066,40 @@ void Cvar_Toggle_f( void )
|
||||||
Cvar_Set( Cmd_Argv( 1 ), va( "%i", v ));
|
Cvar_Set( Cmd_Argv( 1 ), va( "%i", v ));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
============
|
||||||
|
Cvar_Set_f
|
||||||
|
|
||||||
|
Allows setting and defining of arbitrary cvars from console, even if they
|
||||||
|
weren't declared in C code.
|
||||||
|
============
|
||||||
|
*/
|
||||||
|
void Cvar_Set_f( void )
|
||||||
|
{
|
||||||
|
int i, c, l = 0, len;
|
||||||
|
char combined[MAX_CMD_TOKENS];
|
||||||
|
|
||||||
|
c = Cmd_Argc();
|
||||||
|
if( c < 3 )
|
||||||
|
{
|
||||||
|
Msg( S_USAGE "set <variable> <value>\n" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
combined[0] = 0;
|
||||||
|
|
||||||
|
for( i = 2; i < c; i++ )
|
||||||
|
{
|
||||||
|
len = Q_strlen( Cmd_Argv(i) + 1 );
|
||||||
|
if( l + len >= MAX_CMD_TOKENS - 2 )
|
||||||
|
break;
|
||||||
|
Q_strcat( combined, Cmd_Argv( i ));
|
||||||
|
if( i != c-1 ) Q_strcat( combined, " " );
|
||||||
|
l += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cvar_Set2( Cmd_Argv( 1 ), combined );
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
============
|
============
|
||||||
Cvar_SetGL_f
|
Cvar_SetGL_f
|
||||||
|
@ -934,16 +1147,20 @@ void Cvar_List_f( void )
|
||||||
const char *match = NULL;
|
const char *match = NULL;
|
||||||
char *value;
|
char *value;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
size_t matchlen = 0;
|
||||||
|
|
||||||
if( Cmd_Argc() > 1 )
|
if( Cmd_Argc() > 1 )
|
||||||
|
{
|
||||||
match = Cmd_Argv( 1 );
|
match = Cmd_Argv( 1 );
|
||||||
|
matchlen = Q_strlen( match );
|
||||||
|
}
|
||||||
|
|
||||||
for( var = cvar_vars; var; var = var->next )
|
for( var = cvar_vars; var; var = var->next )
|
||||||
{
|
{
|
||||||
if( var->name[0] == '@' )
|
if( var->name[0] == '@' )
|
||||||
continue; // never shows system cvars
|
continue; // never shows system cvars
|
||||||
|
|
||||||
if( match && !Q_stricmpext( match, var->name ))
|
if( match && !Q_strnicmpext( match, var->name, matchlen ))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( Q_colorstr( var->string ))
|
if( Q_colorstr( var->string ))
|
||||||
|
@ -994,16 +1211,37 @@ Reads in all archived cvars
|
||||||
void Cvar_Init( void )
|
void Cvar_Init( void )
|
||||||
{
|
{
|
||||||
cvar_vars = NULL;
|
cvar_vars = NULL;
|
||||||
|
cvar_active_filter_quirks = NULL;
|
||||||
cmd_scripting = Cvar_Get( "cmd_scripting", "0", FCVAR_ARCHIVE|FCVAR_PRIVILEGED, "enable simple condition checking and variable operations" );
|
cmd_scripting = Cvar_Get( "cmd_scripting", "0", FCVAR_ARCHIVE|FCVAR_PRIVILEGED, "enable simple condition checking and variable operations" );
|
||||||
Cvar_RegisterVariable (&host_developer); // early registering for dev
|
Cvar_RegisterVariable( &host_developer ); // early registering for dev
|
||||||
Cvar_RegisterVariable( &cl_filterstuffcmd );
|
Cvar_RegisterVariable( &cl_filterstuffcmd );
|
||||||
|
|
||||||
Cmd_AddRestrictedCommand( "setgl", Cvar_SetGL_f, "change the value of a opengl variable" ); // OBSOLETE
|
Cmd_AddRestrictedCommand( "setgl", Cvar_SetGL_f, "change the value of a opengl variable" ); // OBSOLETE
|
||||||
Cmd_AddRestrictedCommand( "toggle", Cvar_Toggle_f, "toggles a console variable's values (use for more info)" );
|
Cmd_AddRestrictedCommand( "toggle", Cvar_Toggle_f, "toggles a console variable's values (use for more info)" );
|
||||||
Cmd_AddRestrictedCommand( "reset", Cvar_Reset_f, "reset any type variable to initial value" );
|
Cmd_AddRestrictedCommand( "reset", Cvar_Reset_f, "reset any type variable to initial value" );
|
||||||
|
Cmd_AddCommand( "set", Cvar_Set_f, "create or change the value of a console variable" );
|
||||||
Cmd_AddCommand( "cvarlist", Cvar_List_f, "display all console variables beginning with the specified prefix" );
|
Cmd_AddCommand( "cvarlist", Cvar_List_f, "display all console variables beginning with the specified prefix" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
============
|
||||||
|
Cvar_PostFSInit
|
||||||
|
|
||||||
|
============
|
||||||
|
*/
|
||||||
|
void Cvar_PostFSInit( void )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for( i = 0; i < ARRAYSIZE( cvar_filter_quirks ); i++ )
|
||||||
|
{
|
||||||
|
if( !Q_stricmp( cvar_filter_quirks[i].gamedir, GI->gamefolder ))
|
||||||
|
{
|
||||||
|
cvar_active_filter_quirks = &cvar_filter_quirks[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if XASH_ENGINE_TESTS
|
#if XASH_ENGINE_TESTS
|
||||||
#include "tests.h"
|
#include "tests.h"
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,7 @@ typedef struct convar_s
|
||||||
#define FCVAR_VIDRESTART (1<<20) // recreate the window is cvar with this flag was changed
|
#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_TEMPORARY (1<<21) // these cvars holds their values and can be unlink in any time
|
||||||
#define FCVAR_MOVEVARS (1<<22) // this cvar is a part of movevars_t struct that shared between client and server
|
#define FCVAR_MOVEVARS (1<<22) // this cvar is a part of movevars_t struct that shared between client and server
|
||||||
|
#define FCVAR_USER_CREATED (1<<23) // created by a set command (dll's used)
|
||||||
|
|
||||||
#define CVAR_DEFINE( cv, cvname, cvstr, cvflags, cvdesc ) \
|
#define CVAR_DEFINE( cv, cvname, cvstr, cvflags, cvdesc ) \
|
||||||
convar_t cv = { (char*)cvname, (char*)cvstr, cvflags, 0.0f, (void *)CVAR_SENTINEL, (char*)cvdesc, NULL }
|
convar_t cv = { (char*)cvname, (char*)cvstr, cvflags, 0.0f, (void *)CVAR_SENTINEL, (char*)cvdesc, NULL }
|
||||||
|
@ -77,6 +78,7 @@ void Cvar_Reset( const char *var_name );
|
||||||
void Cvar_SetCheatState( void );
|
void Cvar_SetCheatState( void );
|
||||||
qboolean Cvar_CommandWithPrivilegeCheck( convar_t *v, qboolean isPrivileged );
|
qboolean Cvar_CommandWithPrivilegeCheck( convar_t *v, qboolean isPrivileged );
|
||||||
void Cvar_Init( void );
|
void Cvar_Init( void );
|
||||||
|
void Cvar_PostFSInit( void );
|
||||||
void Cvar_Unlink( int group );
|
void Cvar_Unlink( int group );
|
||||||
|
|
||||||
#endif//CVAR_H
|
#endif//CVAR_H
|
||||||
|
|
|
@ -19,74 +19,6 @@ GNU General Public License for more details.
|
||||||
|
|
||||||
ref_globals_t refState;
|
ref_globals_t refState;
|
||||||
|
|
||||||
const char *svc_strings[256] =
|
|
||||||
{
|
|
||||||
"svc_bad",
|
|
||||||
"svc_nop",
|
|
||||||
"svc_disconnect",
|
|
||||||
"svc_changing",
|
|
||||||
"svc_version",
|
|
||||||
"svc_setview",
|
|
||||||
"svc_sound",
|
|
||||||
"svc_time",
|
|
||||||
"svc_print",
|
|
||||||
"svc_stufftext",
|
|
||||||
"svc_setangle",
|
|
||||||
"svc_serverdata",
|
|
||||||
"svc_lightstyle",
|
|
||||||
"svc_updateuserinfo",
|
|
||||||
"svc_deltatable",
|
|
||||||
"svc_clientdata",
|
|
||||||
"svc_stopsound",
|
|
||||||
"svc_updatepings",
|
|
||||||
"svc_particle",
|
|
||||||
"svc_restoresound",
|
|
||||||
"svc_spawnstatic",
|
|
||||||
"svc_event_reliable",
|
|
||||||
"svc_spawnbaseline",
|
|
||||||
"svc_temp_entity",
|
|
||||||
"svc_setpause",
|
|
||||||
"svc_signonnum",
|
|
||||||
"svc_centerprint",
|
|
||||||
"svc_event",
|
|
||||||
"svc_soundindex",
|
|
||||||
"svc_ambientsound",
|
|
||||||
"svc_intermission",
|
|
||||||
"svc_modelindex",
|
|
||||||
"svc_cdtrack",
|
|
||||||
"svc_serverinfo",
|
|
||||||
"svc_eventindex",
|
|
||||||
"svc_weaponanim",
|
|
||||||
"svc_bspdecal",
|
|
||||||
"svc_roomtype",
|
|
||||||
"svc_addangle",
|
|
||||||
"svc_usermessage",
|
|
||||||
"svc_packetentities",
|
|
||||||
"svc_deltapacketentities",
|
|
||||||
"svc_chokecount",
|
|
||||||
"svc_resourcelist",
|
|
||||||
"svc_deltamovevars",
|
|
||||||
"svc_customization",
|
|
||||||
"svc_unused46",
|
|
||||||
"svc_crosshairangle",
|
|
||||||
"svc_soundfade",
|
|
||||||
"svc_unused49",
|
|
||||||
"svc_unused50",
|
|
||||||
"svc_director",
|
|
||||||
"svc_studiodecal",
|
|
||||||
"svc_unused53",
|
|
||||||
"svc_unused54",
|
|
||||||
"svc_unused55",
|
|
||||||
"svc_unused56",
|
|
||||||
"svc_querycvarvalue",
|
|
||||||
"svc_querycvarvalue2",
|
|
||||||
"svc_exec",
|
|
||||||
"svc_unused60",
|
|
||||||
"svc_unused61",
|
|
||||||
"svc_unused62",
|
|
||||||
"svc_unused63",
|
|
||||||
};
|
|
||||||
|
|
||||||
void CL_ProcessFile( qboolean successfully_received, const char *filename )
|
void CL_ProcessFile( qboolean successfully_received, const char *filename )
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -325,4 +257,9 @@ void CL_Crashed( void )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CL_HudMessage( const char *pMessage )
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#endif // XASH_DEDICATED
|
#endif // XASH_DEDICATED
|
||||||
|
|
|
@ -74,7 +74,7 @@ void Sys_PrintUsage( void )
|
||||||
#if XASH_MESSAGEBOX == MSGBOX_STDERR
|
#if XASH_MESSAGEBOX == MSGBOX_STDERR
|
||||||
"\n" // dirty hack to not have Xash Error: Usage: on same line
|
"\n" // dirty hack to not have Xash Error: Usage: on same line
|
||||||
#endif // XASH_MESSAGEBOX == MSGBOX_STDERR
|
#endif // XASH_MESSAGEBOX == MSGBOX_STDERR
|
||||||
"Usage:\n"
|
S_USAGE "\n"
|
||||||
#if !XASH_MOBILE_PLATFORM
|
#if !XASH_MOBILE_PLATFORM
|
||||||
#if XASH_WIN32
|
#if XASH_WIN32
|
||||||
O("<xash>.exe [options] [+command1] [+command2 arg]","")
|
O("<xash>.exe [options] [+command1] [+command2 arg]","")
|
||||||
|
@ -151,6 +151,8 @@ void Sys_PrintUsage( void )
|
||||||
O("-clientlib <path>","override client DLL path")
|
O("-clientlib <path>","override client DLL path")
|
||||||
#endif
|
#endif
|
||||||
O("-rodir <path> ","set read-only base directory, experimental")
|
O("-rodir <path> ","set read-only base directory, experimental")
|
||||||
|
O("-bugcomp ","enable precise bug compatibility. Will break games that don't require it")
|
||||||
|
O(" ","Refer to engine documentation for more info")
|
||||||
|
|
||||||
O("-ip <ip> ","set custom ip")
|
O("-ip <ip> ","set custom ip")
|
||||||
O("-port <port> ","set custom host port")
|
O("-port <port> ","set custom host port")
|
||||||
|
@ -267,36 +269,35 @@ void Host_AbortCurrentFrame( void )
|
||||||
|
|
||||||
/*
|
/*
|
||||||
==================
|
==================
|
||||||
Host_CheckSleep
|
Host_CalcSleep
|
||||||
==================
|
==================
|
||||||
*/
|
*/
|
||||||
void Host_CheckSleep( void )
|
static int Host_CalcSleep( void )
|
||||||
{
|
{
|
||||||
int sleeptime = host_sleeptime->value;
|
#ifndef XASH_DEDICATED
|
||||||
|
// never sleep in timedemo for benchmarking purposes
|
||||||
|
// also don't sleep with vsync for less lag
|
||||||
|
if( CL_IsTimeDemo( ) || CVAR_TO_BOOL( gl_vsync ))
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
if( Host_IsDedicated() )
|
if( Host_IsDedicated() )
|
||||||
{
|
{
|
||||||
// let the dedicated server some sleep
|
// let the dedicated server some sleep
|
||||||
Sys_Sleep( sleeptime );
|
return host_sleeptime->value;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
switch( host.status )
|
||||||
{
|
{
|
||||||
if( host.status == HOST_NOFOCUS )
|
case HOST_NOFOCUS:
|
||||||
{
|
if( SV_Active() && CL_IsInGame())
|
||||||
if( SV_Active() && CL_IsInGame( ))
|
return host_sleeptime->value;
|
||||||
Sys_Sleep( sleeptime ); // listenserver
|
// fallthrough
|
||||||
else Sys_Sleep( 20 ); // sleep 20 ms otherwise
|
case HOST_SLEEP:
|
||||||
}
|
return 20;
|
||||||
else if( host.status == HOST_SLEEP )
|
|
||||||
{
|
|
||||||
// completely sleep in minimized state
|
|
||||||
Sys_Sleep( 20 );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Sys_Sleep( sleeptime );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return host_sleeptime->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Host_NewInstance( const char *name, const char *finalmsg )
|
void Host_NewInstance( const char *name, const char *finalmsg )
|
||||||
|
@ -344,7 +345,7 @@ void Host_ChangeGame_f( void )
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const char *arg1 = va( "%s%s", (host.type == HOST_NORMAL) ? "" : "#", Cmd_Argv( 1 ));
|
const char *arg1 = va( "%s", Cmd_Argv( 1 ));
|
||||||
const char *arg2 = va( "change game to '%s'", FI->games[i]->title );
|
const char *arg2 = va( "change game to '%s'", FI->games[i]->title );
|
||||||
|
|
||||||
Host_NewInstance( arg1, arg2 );
|
Host_NewInstance( arg1, arg2 );
|
||||||
|
@ -595,25 +596,17 @@ double Host_CalcFPS( void )
|
||||||
}
|
}
|
||||||
else if( Host_IsLocalGame( ))
|
else if( Host_IsLocalGame( ))
|
||||||
{
|
{
|
||||||
|
if( !CVAR_TO_BOOL( gl_vsync ))
|
||||||
fps = host_maxfps->value;
|
fps = host_maxfps->value;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
if( !CVAR_TO_BOOL( gl_vsync ))
|
||||||
{
|
{
|
||||||
fps = host_maxfps->value;
|
fps = host_maxfps->value;
|
||||||
if( fps == 0.0 ) fps = MAX_FPS;
|
if( fps == 0.0 ) fps = MAX_FPS;
|
||||||
fps = bound( MIN_FPS, fps, MAX_FPS );
|
fps = bound( MIN_FPS, fps, MAX_FPS );
|
||||||
}
|
}
|
||||||
|
|
||||||
// probably left part of this condition is redundant :-)
|
|
||||||
if( host.type != HOST_DEDICATED && Host_IsLocalGame( ) && !CL_IsTimeDemo( ))
|
|
||||||
{
|
|
||||||
// ajdust fps for vertical synchronization
|
|
||||||
if( CVAR_TO_BOOL( gl_vsync ))
|
|
||||||
{
|
|
||||||
if( vid_displayfrequency->value != 0.0f )
|
|
||||||
fps = vid_displayfrequency->value;
|
|
||||||
else fps = 60.0; // default
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -630,27 +623,53 @@ Returns false if the time is too short to run a frame
|
||||||
qboolean Host_FilterTime( float time )
|
qboolean Host_FilterTime( float time )
|
||||||
{
|
{
|
||||||
static double oldtime;
|
static double oldtime;
|
||||||
double fps;
|
double fps, scale = sys_timescale.value;
|
||||||
double scale = sys_timescale.value;
|
|
||||||
|
|
||||||
host.realtime += time * scale;
|
host.realtime += time * scale;
|
||||||
fps = Host_CalcFPS( );
|
fps = Host_CalcFPS();
|
||||||
|
|
||||||
// clamp the fps in multiplayer games
|
// clamp the fps in multiplayer games
|
||||||
if( fps != 0.0 )
|
if( fps != 0.0 )
|
||||||
{
|
{
|
||||||
|
static int sleeps;
|
||||||
|
double targetframetime;
|
||||||
|
int sleeptime = Host_CalcSleep();
|
||||||
|
|
||||||
// limit fps to withing tolerable range
|
// limit fps to withing tolerable range
|
||||||
fps = bound( MIN_FPS, fps, MAX_FPS );
|
fps = bound( MIN_FPS, fps, MAX_FPS );
|
||||||
|
|
||||||
if( Host_IsDedicated() )
|
if( Host_IsDedicated( ))
|
||||||
|
targetframetime = ( 1.0 / ( fps + 1.0 ));
|
||||||
|
else targetframetime = ( 1.0 / fps );
|
||||||
|
|
||||||
|
if(( host.realtime - oldtime ) < targetframetime * scale )
|
||||||
{
|
{
|
||||||
if(( host.realtime - oldtime ) < ( 1.0 / ( fps + 1.0 )) * scale)
|
if( sleeptime > 0 && sleeps > 0 )
|
||||||
|
{
|
||||||
|
Sys_Sleep( sleeptime );
|
||||||
|
sleeps--;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( sleeptime > 0 && sleeps <= 0 )
|
||||||
|
{
|
||||||
|
if( host.status == HOST_FRAME )
|
||||||
|
{
|
||||||
|
// give few sleeps this frame with small margin
|
||||||
|
double targetsleeptime = targetframetime - host.pureframetime * 2;
|
||||||
|
|
||||||
|
// don't sleep if we can't keep up with the framerate
|
||||||
|
if( targetsleeptime > 0 )
|
||||||
|
sleeps = targetsleeptime / ( sleeptime * 0.001 );
|
||||||
|
else sleeps = 0;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(( host.realtime - oldtime ) < ( 1.0 / fps ) * scale )
|
// always sleep at least once in minimized/nofocus state
|
||||||
return false;
|
sleeps = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -673,12 +692,17 @@ Host_Frame
|
||||||
*/
|
*/
|
||||||
void Host_Frame( float time )
|
void Host_Frame( float time )
|
||||||
{
|
{
|
||||||
Host_CheckSleep();
|
double t1, t2;
|
||||||
|
|
||||||
// decide the simulation time
|
// decide the simulation time
|
||||||
if( !Host_FilterTime( time ))
|
if( !Host_FilterTime( time ))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
t1 = Sys_DoubleTime();
|
||||||
|
|
||||||
|
if( host.framecount == 0 )
|
||||||
|
Con_DPrintf( "Time to first frame: %.3f seconds\n", t1 - host.starttime );
|
||||||
|
|
||||||
Host_InputFrame (); // input frame
|
Host_InputFrame (); // input frame
|
||||||
Host_ClientBegin (); // begin client
|
Host_ClientBegin (); // begin client
|
||||||
Host_GetCommands (); // dedicated in
|
Host_GetCommands (); // dedicated in
|
||||||
|
@ -686,6 +710,10 @@ void Host_Frame( float time )
|
||||||
Host_ClientFrame (); // client frame
|
Host_ClientFrame (); // client frame
|
||||||
HTTP_Run(); // both server and client
|
HTTP_Run(); // both server and client
|
||||||
|
|
||||||
|
t2 = Sys_DoubleTime();
|
||||||
|
|
||||||
|
host.pureframetime = t2 - t1;
|
||||||
|
|
||||||
host.framecount++;
|
host.framecount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -701,15 +729,6 @@ void GAME_EXPORT Host_Error( const char *error, ... )
|
||||||
static qboolean recursive = false;
|
static qboolean recursive = false;
|
||||||
va_list argptr;
|
va_list argptr;
|
||||||
|
|
||||||
if( host.mouse_visible && !CL_IsInMenu( ))
|
|
||||||
{
|
|
||||||
// hide VGUI mouse
|
|
||||||
#ifdef XASH_SDL
|
|
||||||
SDL_ShowCursor( 0 );
|
|
||||||
#endif
|
|
||||||
host.mouse_visible = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
va_start( argptr, error );
|
va_start( argptr, error );
|
||||||
Q_vsprintf( hosterror1, error, argptr );
|
Q_vsprintf( hosterror1, error, argptr );
|
||||||
va_end( argptr );
|
va_end( argptr );
|
||||||
|
@ -820,18 +839,15 @@ static void Host_RunTests( int stage )
|
||||||
{
|
{
|
||||||
case 0: // early engine load
|
case 0: // early engine load
|
||||||
memset( &tests_stats, 0, sizeof( tests_stats ));
|
memset( &tests_stats, 0, sizeof( tests_stats ));
|
||||||
Test_RunLibCommon();
|
TEST_LIST_0;
|
||||||
Test_RunCommon();
|
|
||||||
Test_RunCmd();
|
|
||||||
Test_RunCvar();
|
|
||||||
#if !XASH_DEDICATED
|
#if !XASH_DEDICATED
|
||||||
Test_RunCon();
|
TEST_LIST_0_CLIENT;
|
||||||
#endif /* XASH_DEDICATED */
|
#endif /* XASH_DEDICATED */
|
||||||
break;
|
break;
|
||||||
case 1: // after FS load
|
case 1: // after FS load
|
||||||
Test_RunImagelib();
|
TEST_LIST_1;
|
||||||
#if !XASH_DEDICATED
|
#if !XASH_DEDICATED
|
||||||
Test_RunVOX();
|
TEST_LIST_1_CLIENT;
|
||||||
#endif
|
#endif
|
||||||
Msg( "Done! %d passed, %d failed\n", tests_stats.passed, tests_stats.failed );
|
Msg( "Done! %d passed, %d failed\n", tests_stats.passed, tests_stats.failed );
|
||||||
Sys_Quit();
|
Sys_Quit();
|
||||||
|
@ -878,9 +894,11 @@ void Host_InitCommon( int argc, char **argv, const char *progname, qboolean bCha
|
||||||
|
|
||||||
host.mempool = Mem_AllocPool( "Zone Engine" );
|
host.mempool = Mem_AllocPool( "Zone Engine" );
|
||||||
|
|
||||||
|
host.allow_console = DEFAULT_ALLOWCONSOLE;
|
||||||
|
|
||||||
// HACKHACK: Quake console is always allowed
|
// HACKHACK: Quake console is always allowed
|
||||||
// TODO: determine if we are running QWrap more reliable
|
// TODO: determine if we are running QWrap more reliable
|
||||||
if( Sys_CheckParm( "-console" ) || !Q_stricmp( SI.exeName, "quake" ))
|
if( !host.allow_console && ( Sys_CheckParm( "-console" ) || !Q_stricmp( SI.exeName, "quake" )))
|
||||||
host.allow_console = true;
|
host.allow_console = true;
|
||||||
|
|
||||||
if( Sys_CheckParm( "-dev" ))
|
if( Sys_CheckParm( "-dev" ))
|
||||||
|
@ -941,6 +959,13 @@ void Host_InitCommon( int argc, char **argv, const char *progname, qboolean bCha
|
||||||
// member console allowing
|
// member console allowing
|
||||||
host.allow_console_init = host.allow_console;
|
host.allow_console_init = host.allow_console;
|
||||||
|
|
||||||
|
if( Sys_CheckParm( "-bugcomp" ))
|
||||||
|
{
|
||||||
|
// add argument check here when we add other levels
|
||||||
|
// of bugcompatibility
|
||||||
|
host.bugcomp = BUGCOMP_GOLDSRC;
|
||||||
|
}
|
||||||
|
|
||||||
// timeBeginPeriod( 1 ); // a1ba: Do we need this?
|
// timeBeginPeriod( 1 ); // a1ba: Do we need this?
|
||||||
|
|
||||||
// NOTE: this message couldn't be passed into game console but it doesn't matter
|
// NOTE: this message couldn't be passed into game console but it doesn't matter
|
||||||
|
@ -983,22 +1008,22 @@ void Host_InitCommon( int argc, char **argv, const char *progname, qboolean bCha
|
||||||
|
|
||||||
if( COM_CheckString( baseDir ) )
|
if( COM_CheckString( baseDir ) )
|
||||||
{
|
{
|
||||||
Q_strncpy( host.rootdir, baseDir, sizeof(host.rootdir) );
|
Q_strncpy( host.rootdir, baseDir, sizeof( host.rootdir ));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#if TARGET_OS_IOS
|
#if TARGET_OS_IOS
|
||||||
const char *IOS_GetDocsDir();
|
const char *IOS_GetDocsDir();
|
||||||
Q_strncpy( host.rootdir, IOS_GetDocsDir(), sizeof(host.rootdir) );
|
Q_strncpy( host.rootdir, IOS_GetDocsDir(), sizeof(host.rootdir) );
|
||||||
#elif XASH_SDL == 2
|
#elif (XASH_SDL == 2) && !XASH_NSWITCH // GetBasePath not impl'd in switch-sdl2
|
||||||
char *szBasePath;
|
char *szBasePath;
|
||||||
|
|
||||||
if( !( szBasePath = SDL_GetBasePath() ) )
|
if( !( szBasePath = SDL_GetBasePath() ) )
|
||||||
Sys_Error( "couldn't determine current directory: %s", SDL_GetError() );
|
Sys_Error( "couldn't determine current directory: %s", SDL_GetError() );
|
||||||
Q_strncpy( host.rootdir, szBasePath, sizeof( host.rootdir ) );
|
Q_strncpy( host.rootdir, szBasePath, sizeof( host.rootdir ));
|
||||||
SDL_free( szBasePath );
|
SDL_free( szBasePath );
|
||||||
#else
|
#else
|
||||||
if( !getcwd( host.rootdir, sizeof(host.rootdir) ) )
|
if( !getcwd( host.rootdir, sizeof( host.rootdir )))
|
||||||
{
|
{
|
||||||
Sys_Error( "couldn't determine current directory: %s", strerror( errno ) );
|
Sys_Error( "couldn't determine current directory: %s", strerror( errno ) );
|
||||||
host.rootdir[0] = 0;
|
host.rootdir[0] = 0;
|
||||||
|
@ -1006,6 +1031,10 @@ void Host_InitCommon( int argc, char **argv, const char *progname, qboolean bCha
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if XASH_WIN32
|
||||||
|
COM_FixSlashes( host.rootdir );
|
||||||
|
#endif
|
||||||
|
|
||||||
len = Q_strlen( host.rootdir );
|
len = Q_strlen( host.rootdir );
|
||||||
|
|
||||||
if( len && host.rootdir[len - 1] == '/' )
|
if( len && host.rootdir[len - 1] == '/' )
|
||||||
|
@ -1022,6 +1051,10 @@ void Host_InitCommon( int argc, char **argv, const char *progname, qboolean bCha
|
||||||
Q_strncpy( host.rodir, roDir, sizeof( host.rodir ));
|
Q_strncpy( host.rodir, roDir, sizeof( host.rodir ));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if XASH_WIN32
|
||||||
|
COM_FixSlashes( host.rootdir );
|
||||||
|
#endif
|
||||||
|
|
||||||
len = Q_strlen( host.rodir );
|
len = Q_strlen( host.rodir );
|
||||||
|
|
||||||
if( len && host.rodir[len - 1] == '/' )
|
if( len && host.rodir[len - 1] == '/' )
|
||||||
|
@ -1044,6 +1077,12 @@ void Host_InitCommon( int argc, char **argv, const char *progname, qboolean bCha
|
||||||
|
|
||||||
Sys_InitLog();
|
Sys_InitLog();
|
||||||
|
|
||||||
|
// print bugcompatibility level here, after log was initialized
|
||||||
|
if( host.bugcomp == BUGCOMP_GOLDSRC )
|
||||||
|
{
|
||||||
|
Con_Printf( "^3BUGCOMP^7: GoldSrc bug-compatibility enabled\n" );
|
||||||
|
}
|
||||||
|
|
||||||
Cmd_AddCommand( "exec", Host_Exec_f, "execute a script file" );
|
Cmd_AddCommand( "exec", Host_Exec_f, "execute a script file" );
|
||||||
Cmd_AddCommand( "memlist", Host_MemStats_f, "prints memory pool information" );
|
Cmd_AddCommand( "memlist", Host_MemStats_f, "prints memory pool information" );
|
||||||
Cmd_AddRestrictedCommand( "userconfigd", Host_Userconfigd_f, "execute all scripts from userconfig.d" );
|
Cmd_AddRestrictedCommand( "userconfigd", Host_Userconfigd_f, "execute all scripts from userconfig.d" );
|
||||||
|
@ -1057,6 +1096,7 @@ void Host_InitCommon( int argc, char **argv, const char *progname, qboolean bCha
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
FS_LoadGameInfo( NULL );
|
FS_LoadGameInfo( NULL );
|
||||||
|
Cvar_PostFSInit();
|
||||||
|
|
||||||
if( FS_FileExists( va( "%s.rc", SI.basedirName ), false ))
|
if( FS_FileExists( va( "%s.rc", SI.basedirName ), false ))
|
||||||
Q_strncpy( SI.rcName, SI.basedirName, sizeof( SI.rcName )); // e.g. valve.rc
|
Q_strncpy( SI.rcName, SI.basedirName, sizeof( SI.rcName )); // e.g. valve.rc
|
||||||
|
@ -1102,6 +1142,8 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
|
||||||
{
|
{
|
||||||
static double oldtime, newtime;
|
static double oldtime, newtime;
|
||||||
|
|
||||||
|
host.starttime = Sys_DoubleTime();
|
||||||
|
|
||||||
pChangeGame = func; // may be NULL
|
pChangeGame = func; // may be NULL
|
||||||
|
|
||||||
Host_InitCommon( argc, argv, progname, bChangeGame );
|
Host_InitCommon( argc, argv, progname, bChangeGame );
|
||||||
|
@ -1126,7 +1168,7 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
|
||||||
|
|
||||||
build = Cvar_Get( "buildnum", va( "%i", Q_buildnum_compat()), FCVAR_READ_ONLY, "returns a current build number" );
|
build = Cvar_Get( "buildnum", va( "%i", Q_buildnum_compat()), FCVAR_READ_ONLY, "returns a current build number" );
|
||||||
ver = Cvar_Get( "ver", va( "%i/%s (hw build %i)", PROTOCOL_VERSION, XASH_COMPAT_VERSION, Q_buildnum_compat()), FCVAR_READ_ONLY, "shows an engine version" );
|
ver = Cvar_Get( "ver", va( "%i/%s (hw build %i)", PROTOCOL_VERSION, XASH_COMPAT_VERSION, Q_buildnum_compat()), FCVAR_READ_ONLY, "shows an engine version" );
|
||||||
Cvar_Get( "host_ver", va( "%i %s %s %s %s", Q_buildnum(), XASH_VERSION, Q_buildos(), Q_buildarch(), Q_buildcommit() ), FCVAR_READ_ONLY, "detailed info about this build" );
|
Cvar_Get( "host_ver", va( "%i " XASH_VERSION " %s %s %s", Q_buildnum(), Q_buildos(), Q_buildarch(), Q_buildcommit() ), FCVAR_READ_ONLY, "detailed info about this build" );
|
||||||
Cvar_Get( "host_lowmemorymode", va( "%i", XASH_LOW_MEMORY ), FCVAR_READ_ONLY, "indicates if engine compiled for low RAM consumption (0 - normal, 1 - low engine limits, 2 - low protocol limits)" );
|
Cvar_Get( "host_lowmemorymode", va( "%i", XASH_LOW_MEMORY ), FCVAR_READ_ONLY, "indicates if engine compiled for low RAM consumption (0 - normal, 1 - low engine limits, 2 - low protocol limits)" );
|
||||||
|
|
||||||
Mod_Init();
|
Mod_Init();
|
||||||
|
@ -1195,11 +1237,17 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
|
||||||
|
|
||||||
oldtime = Sys_DoubleTime() - 0.1;
|
oldtime = Sys_DoubleTime() - 0.1;
|
||||||
|
|
||||||
if( Host_IsDedicated() && GameState->nextstate == STATE_RUNFRAME )
|
if( Host_IsDedicated( ))
|
||||||
{
|
{
|
||||||
|
// in dedicated server input system can't set HOST_FRAME status
|
||||||
|
// so set it here as we're finished initializing
|
||||||
|
host.status = HOST_FRAME;
|
||||||
|
|
||||||
|
if( GameState->nextstate == STATE_RUNFRAME )
|
||||||
|
Con_Printf( "Type 'map <mapname>' to start game... (TAB-autocomplete is working too)\n" );
|
||||||
|
|
||||||
// execute server.cfg after commandline
|
// execute server.cfg after commandline
|
||||||
// so we have a chance to set servercfgfile
|
// so we have a chance to set servercfgfile
|
||||||
Con_Printf( "Type 'map <mapname>' to start game... (TAB-autocomplete is working too)\n" );
|
|
||||||
Cbuf_AddText( va( "exec %s\n", Cvar_VariableString( "servercfgfile" )));
|
Cbuf_AddText( va( "exec %s\n", Cvar_VariableString( "servercfgfile" )));
|
||||||
Cbuf_Execute();
|
Cbuf_Execute();
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,8 @@ GNU General Public License for more details.
|
||||||
#include "hpak.h"
|
#include "hpak.h"
|
||||||
|
|
||||||
#define HPAK_MAX_ENTRIES 0x8000
|
#define HPAK_MAX_ENTRIES 0x8000
|
||||||
#define HPAK_MIN_SIZE (1 * 1024)
|
#define HPAK_ENTRY_MIN_SIZE (512)
|
||||||
#define HPAK_MAX_SIZE (128 * 1024)
|
#define HPAK_ENTRY_MAX_SIZE (128 * 1024)
|
||||||
|
|
||||||
typedef struct hash_pack_queue_s
|
typedef struct hash_pack_queue_s
|
||||||
{
|
{
|
||||||
|
@ -49,6 +49,18 @@ const char *HPAK_TypeFromIndex( int type )
|
||||||
return "?";
|
return "?";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void HPAK_ResourceToCompat( dresource_t *dest, resource_t *src )
|
||||||
|
{
|
||||||
|
memcpy( dest, src, sizeof( *dest ));
|
||||||
|
dest->pNext = dest->pPrev = 0xDEADBEEF;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void HPAK_ResourceFromCompat( resource_t *dest, dresource_t *src )
|
||||||
|
{
|
||||||
|
memcpy( dest, src, sizeof( *src ));
|
||||||
|
dest->pNext = dest->pPrev = (void*)0xDEADBEEF;
|
||||||
|
}
|
||||||
|
|
||||||
static void HPAK_AddToQueue( const char *name, resource_t *pResource, void *data, file_t *f )
|
static void HPAK_AddToQueue( const char *name, resource_t *pResource, void *data, file_t *f )
|
||||||
{
|
{
|
||||||
hash_pack_queue_t *p;
|
hash_pack_queue_t *p;
|
||||||
|
@ -89,6 +101,7 @@ void HPAK_CreatePak( const char *filename, resource_t *pResource, byte *pData, f
|
||||||
byte md5[16];
|
byte md5[16];
|
||||||
file_t *fout;
|
file_t *fout;
|
||||||
MD5Context_t ctx;
|
MD5Context_t ctx;
|
||||||
|
dresource_t dresource;
|
||||||
|
|
||||||
if( !COM_CheckString( filename ))
|
if( !COM_CheckString( filename ))
|
||||||
return;
|
return;
|
||||||
|
@ -101,7 +114,7 @@ void HPAK_CreatePak( const char *filename, resource_t *pResource, byte *pData, f
|
||||||
|
|
||||||
Con_Printf( "creating HPAK %s.\n", pakname );
|
Con_Printf( "creating HPAK %s.\n", pakname );
|
||||||
|
|
||||||
fout = FS_Open( pakname, "wb", false );
|
fout = FS_Open( pakname, "wb", true );
|
||||||
if( !fout )
|
if( !fout )
|
||||||
{
|
{
|
||||||
Con_DPrintf( S_ERROR "HPAK_CreatePak: can't write %s.\n", pakname );
|
Con_DPrintf( S_ERROR "HPAK_CreatePak: can't write %s.\n", pakname );
|
||||||
|
@ -145,7 +158,7 @@ void HPAK_CreatePak( const char *filename, resource_t *pResource, byte *pData, f
|
||||||
|
|
||||||
hash_pack_info.count = 1;
|
hash_pack_info.count = 1;
|
||||||
hash_pack_info.entries = Z_Malloc( sizeof( hpak_lump_t ));
|
hash_pack_info.entries = Z_Malloc( sizeof( hpak_lump_t ));
|
||||||
hash_pack_info.entries[0].resource = *pResource;
|
HPAK_ResourceToCompat( &hash_pack_info.entries[0].resource, pResource );
|
||||||
hash_pack_info.entries[0].filepos = FS_Tell( fout );
|
hash_pack_info.entries[0].filepos = FS_Tell( fout );
|
||||||
hash_pack_info.entries[0].disksize = pResource->nDownloadSize;
|
hash_pack_info.entries[0].disksize = pResource->nDownloadSize;
|
||||||
|
|
||||||
|
@ -181,7 +194,7 @@ static qboolean HPAK_FindResource( hpak_info_t *hpk, byte *hash, resource_t *pRe
|
||||||
if( !memcmp( hpk->entries[i].resource.rgucMD5_hash, hash, 16 ))
|
if( !memcmp( hpk->entries[i].resource.rgucMD5_hash, hash, 16 ))
|
||||||
{
|
{
|
||||||
if( pResource )
|
if( pResource )
|
||||||
*pResource = hpk->entries[i].resource;
|
HPAK_ResourceFromCompat( pResource, &hpk->entries[i].resource );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -203,7 +216,7 @@ void HPAK_AddLump( qboolean bUseQueue, const char *name, resource_t *pResource,
|
||||||
if( pData == NULL && pFile == NULL )
|
if( pData == NULL && pFile == NULL )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if( pResource->nDownloadSize < HPAK_MIN_SIZE || pResource->nDownloadSize > HPAK_MAX_SIZE )
|
if( pResource->nDownloadSize < HPAK_ENTRY_MIN_SIZE || pResource->nDownloadSize > HPAK_ENTRY_MAX_SIZE )
|
||||||
{
|
{
|
||||||
Con_Printf( S_ERROR "%s: invalid size %s\n", name, Q_pretifymem( pResource->nDownloadSize, 2 ));
|
Con_Printf( S_ERROR "%s: invalid size %s\n", name, Q_pretifymem( pResource->nDownloadSize, 2 ));
|
||||||
return;
|
return;
|
||||||
|
@ -213,7 +226,7 @@ void HPAK_AddLump( qboolean bUseQueue, const char *name, resource_t *pResource,
|
||||||
memset( &ctx, 0, sizeof( MD5Context_t ));
|
memset( &ctx, 0, sizeof( MD5Context_t ));
|
||||||
MD5Init( &ctx );
|
MD5Init( &ctx );
|
||||||
|
|
||||||
if( pData == NULL )
|
if( !pData )
|
||||||
{
|
{
|
||||||
byte *temp;
|
byte *temp;
|
||||||
|
|
||||||
|
@ -247,7 +260,7 @@ void HPAK_AddLump( qboolean bUseQueue, const char *name, resource_t *pResource,
|
||||||
Q_strncpy( srcname, name, sizeof( srcname ));
|
Q_strncpy( srcname, name, sizeof( srcname ));
|
||||||
COM_ReplaceExtension( srcname, ".hpk" );
|
COM_ReplaceExtension( srcname, ".hpk" );
|
||||||
|
|
||||||
file_src = FS_Open( srcname, "rb", false );
|
file_src = FS_Open( srcname, "rb", true );
|
||||||
|
|
||||||
if( !file_src )
|
if( !file_src )
|
||||||
{
|
{
|
||||||
|
@ -259,7 +272,7 @@ void HPAK_AddLump( qboolean bUseQueue, const char *name, resource_t *pResource,
|
||||||
Q_strncpy( dstname, srcname, sizeof( dstname ));
|
Q_strncpy( dstname, srcname, sizeof( dstname ));
|
||||||
COM_ReplaceExtension( dstname, ".hp2" );
|
COM_ReplaceExtension( dstname, ".hp2" );
|
||||||
|
|
||||||
file_dst = FS_Open( dstname, "wb", false );
|
file_dst = FS_Open( dstname, "wb", true );
|
||||||
|
|
||||||
if( !file_dst )
|
if( !file_dst )
|
||||||
{
|
{
|
||||||
|
@ -312,11 +325,12 @@ void HPAK_AddLump( qboolean bUseQueue, const char *name, resource_t *pResource,
|
||||||
// make a new container
|
// make a new container
|
||||||
dstpak.count = srcpak.count + 1;
|
dstpak.count = srcpak.count + 1;
|
||||||
dstpak.entries = Z_Malloc( sizeof( hpak_lump_t ) * dstpak.count );
|
dstpak.entries = Z_Malloc( sizeof( hpak_lump_t ) * dstpak.count );
|
||||||
memcpy( dstpak.entries, srcpak.entries, srcpak.count );
|
memcpy( dstpak.entries, srcpak.entries, sizeof( hpak_lump_t ) * srcpak.count );
|
||||||
|
|
||||||
|
// check is there are entry with same hash
|
||||||
for( i = 0; i < srcpak.count; i++ )
|
for( i = 0; i < srcpak.count; i++ )
|
||||||
{
|
{
|
||||||
if( memcmp( md5, srcpak.entries[i].resource.rgucMD5_hash, 16 ))
|
if( memcmp( md5, srcpak.entries[i].resource.rgucMD5_hash, 16 ) == 0 )
|
||||||
{
|
{
|
||||||
pCurrentEntry = &dstpak.entries[i];
|
pCurrentEntry = &dstpak.entries[i];
|
||||||
|
|
||||||
|
@ -330,12 +344,14 @@ void HPAK_AddLump( qboolean bUseQueue, const char *name, resource_t *pResource,
|
||||||
|
|
||||||
memset( pCurrentEntry, 0, sizeof( hpak_lump_t ));
|
memset( pCurrentEntry, 0, sizeof( hpak_lump_t ));
|
||||||
FS_Seek( file_dst, hash_pack_header.infotableofs, SEEK_SET );
|
FS_Seek( file_dst, hash_pack_header.infotableofs, SEEK_SET );
|
||||||
pCurrentEntry->resource = *pResource;
|
HPAK_ResourceToCompat( &pCurrentEntry->resource, pResource );
|
||||||
pCurrentEntry->filepos = FS_Tell( file_dst );
|
pCurrentEntry->filepos = FS_Tell( file_dst );
|
||||||
pCurrentEntry->disksize = pResource->nDownloadSize;
|
pCurrentEntry->disksize = pResource->nDownloadSize;
|
||||||
|
|
||||||
if( !pData ) FS_FileCopy( file_dst, file_src, pCurrentEntry->disksize );
|
if( !pData )
|
||||||
else FS_Write( file_dst, pData, pCurrentEntry->disksize );
|
FS_FileCopy( file_dst, pFile, pCurrentEntry->disksize );
|
||||||
|
else
|
||||||
|
FS_Write( file_dst, pData, pCurrentEntry->disksize );
|
||||||
|
|
||||||
hash_pack_header.infotableofs = FS_Tell( file_dst );
|
hash_pack_header.infotableofs = FS_Tell( file_dst );
|
||||||
FS_Write( file_dst, &dstpak.count, sizeof( dstpak.count ));
|
FS_Write( file_dst, &dstpak.count, sizeof( dstpak.count ));
|
||||||
|
@ -370,7 +386,7 @@ static qboolean HPAK_Validate( const char *filename, qboolean quiet )
|
||||||
int i, num_lumps;
|
int i, num_lumps;
|
||||||
MD5Context_t MD5_Hash;
|
MD5Context_t MD5_Hash;
|
||||||
string pakname;
|
string pakname;
|
||||||
resource_t *pRes;
|
dresource_t *pRes;
|
||||||
byte md5[16];
|
byte md5[16];
|
||||||
|
|
||||||
if( quiet ) HPAK_FlushHostQueue();
|
if( quiet ) HPAK_FlushHostQueue();
|
||||||
|
@ -382,7 +398,7 @@ static qboolean HPAK_Validate( const char *filename, qboolean quiet )
|
||||||
Q_strncpy( pakname, filename, sizeof( pakname ));
|
Q_strncpy( pakname, filename, sizeof( pakname ));
|
||||||
COM_ReplaceExtension( pakname, ".hpk" );
|
COM_ReplaceExtension( pakname, ".hpk" );
|
||||||
|
|
||||||
f = FS_Open( pakname, "rb", false );
|
f = FS_Open( pakname, "rb", true );
|
||||||
if( !f )
|
if( !f )
|
||||||
{
|
{
|
||||||
Con_DPrintf( S_ERROR "Couldn't find %s.\n", pakname );
|
Con_DPrintf( S_ERROR "Couldn't find %s.\n", pakname );
|
||||||
|
@ -418,7 +434,7 @@ static qboolean HPAK_Validate( const char *filename, qboolean quiet )
|
||||||
|
|
||||||
for( i = 0; i < num_lumps; i++ )
|
for( i = 0; i < num_lumps; i++ )
|
||||||
{
|
{
|
||||||
if( dataDir[i].disksize < 1 || dataDir[i].disksize > 131071 )
|
if( dataDir[i].disksize < HPAK_ENTRY_MIN_SIZE || dataDir[i].disksize > HPAK_ENTRY_MAX_SIZE )
|
||||||
{
|
{
|
||||||
// odd max size
|
// odd max size
|
||||||
Con_DPrintf( S_ERROR "HPAK_ValidatePak: lump %i has invalid size %s\n", i, Q_pretifymem( dataDir[i].disksize, 2 ));
|
Con_DPrintf( S_ERROR "HPAK_ValidatePak: lump %i has invalid size %s\n", i, Q_pretifymem( dataDir[i].disksize, 2 ));
|
||||||
|
@ -499,7 +515,7 @@ void HPAK_CheckSize( const char *filename )
|
||||||
Q_strncpy( pakname, filename, sizeof( pakname ));
|
Q_strncpy( pakname, filename, sizeof( pakname ));
|
||||||
COM_ReplaceExtension( pakname, ".hpk" );
|
COM_ReplaceExtension( pakname, ".hpk" );
|
||||||
|
|
||||||
if( FS_FileSize( pakname, false ) > ( maxsize * 1000000 ))
|
if( FS_FileSize( pakname, false ) > ( maxsize * 1048576 ))
|
||||||
{
|
{
|
||||||
Con_Printf( "Server: Size of %s > %f MB, deleting.\n", filename, hpk_maxsize->value );
|
Con_Printf( "Server: Size of %s > %f MB, deleting.\n", filename, hpk_maxsize->value );
|
||||||
Log_Printf( "Server: Size of %s > %f MB, deleting.\n", filename, hpk_maxsize->value );
|
Log_Printf( "Server: Size of %s > %f MB, deleting.\n", filename, hpk_maxsize->value );
|
||||||
|
@ -532,7 +548,7 @@ qboolean HPAK_ResourceForHash( const char *filename, byte *hash, resource_t *pRe
|
||||||
Q_strncpy( pakname, filename, sizeof( pakname ));
|
Q_strncpy( pakname, filename, sizeof( pakname ));
|
||||||
COM_ReplaceExtension( pakname, ".hpk" );
|
COM_ReplaceExtension( pakname, ".hpk" );
|
||||||
|
|
||||||
f = FS_Open( pakname, "rb", false );
|
f = FS_Open( pakname, "rb", true );
|
||||||
if( !f ) return false;
|
if( !f ) return false;
|
||||||
|
|
||||||
FS_Read( f, &header, sizeof( header ));
|
FS_Read( f, &header, sizeof( header ));
|
||||||
|
@ -580,7 +596,7 @@ static qboolean HPAK_ResourceForIndex( const char *filename, int index, resource
|
||||||
Q_strncpy( pakname, filename, sizeof( pakname ));
|
Q_strncpy( pakname, filename, sizeof( pakname ));
|
||||||
COM_ReplaceExtension( pakname, ".hpk" );
|
COM_ReplaceExtension( pakname, ".hpk" );
|
||||||
|
|
||||||
f = FS_Open( pakname, "rb", false );
|
f = FS_Open( pakname, "rb", true );
|
||||||
if( !f )
|
if( !f )
|
||||||
{
|
{
|
||||||
Con_DPrintf( S_ERROR "couldn't open %s.\n", pakname );
|
Con_DPrintf( S_ERROR "couldn't open %s.\n", pakname );
|
||||||
|
@ -621,7 +637,7 @@ static qboolean HPAK_ResourceForIndex( const char *filename, int index, resource
|
||||||
|
|
||||||
directory.entries = Z_Malloc( sizeof( hpak_lump_t ) * directory.count );
|
directory.entries = Z_Malloc( sizeof( hpak_lump_t ) * directory.count );
|
||||||
FS_Read( f, directory.entries, sizeof( hpak_lump_t ) * directory.count );
|
FS_Read( f, directory.entries, sizeof( hpak_lump_t ) * directory.count );
|
||||||
*pResource = directory.entries[index-1].resource;
|
HPAK_ResourceFromCompat( pResource, &directory.entries[index-1].resource );
|
||||||
Z_Free( directory.entries );
|
Z_Free( directory.entries );
|
||||||
FS_Close( f );
|
FS_Close( f );
|
||||||
|
|
||||||
|
@ -647,7 +663,7 @@ qboolean HPAK_GetDataPointer( const char *filename, resource_t *pResource, byte
|
||||||
|
|
||||||
for( p = gp_hpak_queue; p != NULL; p = p->next )
|
for( p = gp_hpak_queue; p != NULL; p = p->next )
|
||||||
{
|
{
|
||||||
if( !Q_stricmp(p->name, filename ) && !memcmp( p->resource.rgucMD5_hash, pResource->rgucMD5_hash, 16 ))
|
if( !Q_stricmp( p->name, filename ) && !memcmp( p->resource.rgucMD5_hash, pResource->rgucMD5_hash, 16 ))
|
||||||
{
|
{
|
||||||
if( buffer )
|
if( buffer )
|
||||||
{
|
{
|
||||||
|
@ -666,7 +682,7 @@ qboolean HPAK_GetDataPointer( const char *filename, resource_t *pResource, byte
|
||||||
Q_strncpy( pakname, filename, sizeof( pakname ));
|
Q_strncpy( pakname, filename, sizeof( pakname ));
|
||||||
COM_ReplaceExtension( pakname, ".hpk" );
|
COM_ReplaceExtension( pakname, ".hpk" );
|
||||||
|
|
||||||
f = FS_Open( pakname, "rb", false );
|
f = FS_Open( pakname, "rb", true );
|
||||||
if( !f ) return false;
|
if( !f ) return false;
|
||||||
|
|
||||||
FS_Read( f, &header, sizeof( header ));
|
FS_Read( f, &header, sizeof( header ));
|
||||||
|
@ -702,11 +718,13 @@ qboolean HPAK_GetDataPointer( const char *filename, resource_t *pResource, byte
|
||||||
{
|
{
|
||||||
entry = &directory.entries[i];
|
entry = &directory.entries[i];
|
||||||
|
|
||||||
if( !memcmp( entry->resource.rgucMD5_hash, pResource->rgucMD5_hash, 16 ))
|
if( entry->filepos > 0 &&
|
||||||
|
entry->disksize > 0 &&
|
||||||
|
!memcmp( entry->resource.rgucMD5_hash, pResource->rgucMD5_hash, 16 ))
|
||||||
{
|
{
|
||||||
FS_Seek( f, entry->filepos, SEEK_SET );
|
FS_Seek( f, entry->filepos, SEEK_SET );
|
||||||
|
|
||||||
if( buffer && entry->disksize > 0 )
|
if( buffer )
|
||||||
{
|
{
|
||||||
tmpbuf = Z_Malloc( entry->disksize );
|
tmpbuf = Z_Malloc( entry->disksize );
|
||||||
FS_Read( f, tmpbuf, entry->disksize );
|
FS_Read( f, tmpbuf, entry->disksize );
|
||||||
|
@ -747,7 +765,7 @@ void HPAK_RemoveLump( const char *name, resource_t *pResource )
|
||||||
Q_strncpy( read_path, name, sizeof( read_path ));
|
Q_strncpy( read_path, name, sizeof( read_path ));
|
||||||
COM_ReplaceExtension( read_path, ".hpk" );
|
COM_ReplaceExtension( read_path, ".hpk" );
|
||||||
|
|
||||||
file_src = FS_Open( read_path, "rb", false );
|
file_src = FS_Open( read_path, "rb", true );
|
||||||
if( !file_src )
|
if( !file_src )
|
||||||
{
|
{
|
||||||
Con_DPrintf( S_ERROR "%s couldn't open.\n", read_path );
|
Con_DPrintf( S_ERROR "%s couldn't open.\n", read_path );
|
||||||
|
@ -756,7 +774,7 @@ void HPAK_RemoveLump( const char *name, resource_t *pResource )
|
||||||
|
|
||||||
Q_strncpy( save_path, read_path, sizeof( save_path ));
|
Q_strncpy( save_path, read_path, sizeof( save_path ));
|
||||||
COM_ReplaceExtension( save_path, ".hp2" );
|
COM_ReplaceExtension( save_path, ".hp2" );
|
||||||
file_dst = FS_Open( save_path, "wb", false );
|
file_dst = FS_Open( save_path, "wb", true );
|
||||||
|
|
||||||
if( !file_dst )
|
if( !file_dst )
|
||||||
{
|
{
|
||||||
|
@ -877,7 +895,7 @@ void HPAK_List_f( void )
|
||||||
COM_ReplaceExtension( pakname, ".hpk" );
|
COM_ReplaceExtension( pakname, ".hpk" );
|
||||||
Con_Printf( "Contents for %s.\n", pakname );
|
Con_Printf( "Contents for %s.\n", pakname );
|
||||||
|
|
||||||
f = FS_Open( pakname, "rb", false );
|
f = FS_Open( pakname, "rb", true );
|
||||||
if( !f )
|
if( !f )
|
||||||
{
|
{
|
||||||
Con_DPrintf( S_ERROR "couldn't open %s.\n", pakname );
|
Con_DPrintf( S_ERROR "couldn't open %s.\n", pakname );
|
||||||
|
@ -968,7 +986,7 @@ void HPAK_Extract_f( void )
|
||||||
COM_ReplaceExtension( pakname, ".hpk" );
|
COM_ReplaceExtension( pakname, ".hpk" );
|
||||||
Con_Printf( "Contents for %s.\n", pakname );
|
Con_Printf( "Contents for %s.\n", pakname );
|
||||||
|
|
||||||
f = FS_Open( pakname, "rb", false );
|
f = FS_Open( pakname, "rb", true );
|
||||||
if( !f )
|
if( !f )
|
||||||
{
|
{
|
||||||
Con_DPrintf( S_ERROR "couldn't open %s.\n", pakname );
|
Con_DPrintf( S_ERROR "couldn't open %s.\n", pakname );
|
||||||
|
@ -1020,7 +1038,7 @@ void HPAK_Extract_f( void )
|
||||||
|
|
||||||
Con_Printf( "Extracting %i: %10s %s %s\n", nCurrent + 1, type, size, lumpname );
|
Con_Printf( "Extracting %i: %10s %s %s\n", nCurrent + 1, type, size, lumpname );
|
||||||
|
|
||||||
if( entry->disksize <= 0 || entry->disksize >= HPAK_MAX_SIZE )
|
if( entry->disksize < HPAK_ENTRY_MIN_SIZE || entry->disksize > HPAK_ENTRY_MAX_SIZE )
|
||||||
{
|
{
|
||||||
Con_DPrintf( S_WARN "Unable to extract data, size invalid: %s\n", Q_memprint( entry->disksize ));
|
Con_DPrintf( S_WARN "Unable to extract data, size invalid: %s\n", Q_memprint( entry->disksize ));
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -37,6 +37,35 @@ infotable dlumpinfo_t[dwadinfo_t->numlumps]
|
||||||
#define IDHPAKHEADER (('K'<<24)+('A'<<16)+('P'<<8)+'H') // little-endian "HPAK"
|
#define IDHPAKHEADER (('K'<<24)+('A'<<16)+('P'<<8)+'H') // little-endian "HPAK"
|
||||||
#define IDHPAK_VERSION 1
|
#define IDHPAK_VERSION 1
|
||||||
|
|
||||||
|
// a1ba: because Valve for some reason writes resource_t to file
|
||||||
|
// I had to make it crossplatform version
|
||||||
|
#pragma pack( push, 8 )
|
||||||
|
typedef struct dresource_s
|
||||||
|
{
|
||||||
|
char szFileName[64]; /* 0 64 */
|
||||||
|
/* --- cacheline 1 boundary (64 bytes) --- */
|
||||||
|
resourcetype_t type; /* 64 4 */
|
||||||
|
int nIndex; /* 68 4 */
|
||||||
|
int nDownloadSize; /* 72 4 */
|
||||||
|
unsigned char ucFlags; /* 76 1 */
|
||||||
|
unsigned char rgucMD5_hash[16]; /* 77 16 */
|
||||||
|
unsigned char playernum; /* 93 1 */
|
||||||
|
unsigned char rguc_reserved[32]; /* 94 32 */
|
||||||
|
|
||||||
|
/* XXX 2 bytes hole, try to pack */
|
||||||
|
|
||||||
|
/* --- cacheline 2 boundary (128 bytes) --- */
|
||||||
|
uint32_t pNext; /* 128 4 */
|
||||||
|
uint32_t pPrev; /* 132 4 */
|
||||||
|
|
||||||
|
/* size: 136, cachelines: 3, members: 10 */
|
||||||
|
/* sum members: 134, holes: 1, sum holes: 2 */
|
||||||
|
/* last cacheline: 8 bytes */
|
||||||
|
} dresource_t;
|
||||||
|
#pragma pack( pop )
|
||||||
|
|
||||||
|
STATIC_ASSERT( sizeof( dresource_t ) == 136, "invalid dresource_t size, HPAKs won't be compatible (no custom logo in multiplayer!)" );
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
int ident; // should be equal HPAK
|
int ident; // should be equal HPAK
|
||||||
|
@ -46,7 +75,7 @@ typedef struct
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
resource_t resource;
|
dresource_t resource;
|
||||||
int filepos;
|
int filepos;
|
||||||
int disksize;
|
int disksize;
|
||||||
} hpak_lump_t;
|
} hpak_lump_t;
|
||||||
|
|
|
@ -91,7 +91,7 @@ typedef struct imglib_s
|
||||||
// global parms
|
// global parms
|
||||||
rgba_t fogParams; // some water textures has info about underwater fog
|
rgba_t fogParams; // some water textures has info about underwater fog
|
||||||
|
|
||||||
image_hint_t hint; // hint for some loaders
|
int hint; // hint for some loaders
|
||||||
byte *tempbuffer; // for convert operations
|
byte *tempbuffer; // for convert operations
|
||||||
int cmd_flags; // global imglib flags
|
int cmd_flags; // global imglib flags
|
||||||
int force_flags; // override cmd_flags
|
int force_flags; // override cmd_flags
|
||||||
|
@ -103,6 +103,8 @@ typedef struct imglib_s
|
||||||
#define IMAGE_MAXHEIGHT 8192
|
#define IMAGE_MAXHEIGHT 8192
|
||||||
#define LUMP_MAXWIDTH 1024 // WorldCraft limits
|
#define LUMP_MAXWIDTH 1024 // WorldCraft limits
|
||||||
#define LUMP_MAXHEIGHT 1024
|
#define LUMP_MAXHEIGHT 1024
|
||||||
|
#define PLDECAL_MAXWIDTH 512
|
||||||
|
#define PLDECAL_MAXHEIGHT 512
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
@ -171,7 +173,6 @@ rgbdata_t *Image_Quantize( rgbdata_t *pic );
|
||||||
// img_utils.c
|
// img_utils.c
|
||||||
//
|
//
|
||||||
void Image_Reset( void );
|
void Image_Reset( void );
|
||||||
rgbdata_t *ImagePack( void );
|
|
||||||
byte *Image_Copy( size_t size );
|
byte *Image_Copy( size_t size );
|
||||||
void Image_CopyParms( rgbdata_t *src );
|
void Image_CopyParms( rgbdata_t *src );
|
||||||
qboolean Image_ValidSize( const char *name );
|
qboolean Image_ValidSize( const char *name );
|
||||||
|
|
|
@ -25,7 +25,7 @@ Image_LoadBMP
|
||||||
qboolean Image_LoadBMP( const char *name, const byte *buffer, fs_offset_t filesize )
|
qboolean Image_LoadBMP( const char *name, const byte *buffer, fs_offset_t filesize )
|
||||||
{
|
{
|
||||||
byte *buf_p, *pixbuf;
|
byte *buf_p, *pixbuf;
|
||||||
rgba_t palette[256];
|
rgba_t palette[256] = { 0 };
|
||||||
int i, columns, column, rows, row, bpp = 1;
|
int i, columns, column, rows, row, bpp = 1;
|
||||||
int cbPalBytes = 0, padSize = 0, bps = 0;
|
int cbPalBytes = 0, padSize = 0, bps = 0;
|
||||||
int reflectivity[3] = { 0, 0, 0 };
|
int reflectivity[3] = { 0, 0, 0 };
|
||||||
|
@ -68,10 +68,13 @@ qboolean Image_LoadBMP( const char *name, const byte *buffer, fs_offset_t filesi
|
||||||
|
|
||||||
// bogus compression? Only non-compressed supported.
|
// bogus compression? Only non-compressed supported.
|
||||||
if( bhdr.compression != BI_RGB )
|
if( bhdr.compression != BI_RGB )
|
||||||
|
{
|
||||||
|
if( bhdr.bitsPerPixel != 32 || bhdr.compression != BI_BITFIELDS )
|
||||||
{
|
{
|
||||||
Con_DPrintf( S_ERROR "Image_LoadBMP: only uncompressed BMP files supported (%s)\n", name );
|
Con_DPrintf( S_ERROR "Image_LoadBMP: only uncompressed BMP files supported (%s)\n", name );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
image.width = columns = bhdr.width;
|
image.width = columns = bhdr.width;
|
||||||
image.height = rows = abs( bhdr.height );
|
image.height = rows = abs( bhdr.height );
|
||||||
|
@ -174,7 +177,7 @@ qboolean Image_LoadBMP( const char *name, const byte *buffer, fs_offset_t filesi
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
estimatedSize = ( buf_p - buffer ) + ( image.width + padSize ) * image.height * ( bhdr.bitsPerPixel >> 3 );
|
estimatedSize = ( buf_p - buffer ) + image.width * image.height * ( bhdr.bitsPerPixel >> 3 );
|
||||||
if( filesize < estimatedSize )
|
if( filesize < estimatedSize )
|
||||||
{
|
{
|
||||||
if( image.palette )
|
if( image.palette )
|
||||||
|
|
|
@ -25,7 +25,12 @@ GNU General Public License for more details.
|
||||||
#define BI_FILE_HEADER_SIZE 14
|
#define BI_FILE_HEADER_SIZE 14
|
||||||
#define BI_SIZE 40 // size of bitmap info header.
|
#define BI_SIZE 40 // size of bitmap info header.
|
||||||
#if !defined(BI_RGB)
|
#if !defined(BI_RGB)
|
||||||
#define BI_RGB 0 // uncompressed RGB bitmap(defined in wingdi.h)
|
#define BI_RGB 0 // uncompressed RGB bitmap (defined in wingdi.h)
|
||||||
|
#define BI_RLE8 1
|
||||||
|
#define BI_RLE4 2
|
||||||
|
#define BI_BITFIELDS 3
|
||||||
|
#define BI_JPEG 4
|
||||||
|
#define BI_PNG 5
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#pragma pack( push, 1 )
|
#pragma pack( push, 1 )
|
||||||
|
|
|
@ -110,20 +110,21 @@ void Image_Reset( void )
|
||||||
image.size = 0;
|
image.size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
rgbdata_t *ImagePack( void )
|
static rgbdata_t *ImagePack( void )
|
||||||
{
|
{
|
||||||
rgbdata_t *pack = Mem_Calloc( host.imagepool, sizeof( rgbdata_t ));
|
rgbdata_t *pack;
|
||||||
|
|
||||||
// clear any force flags
|
// clear any force flags
|
||||||
image.force_flags = 0;
|
image.force_flags = 0;
|
||||||
|
|
||||||
if( image.cubemap && image.num_sides != 6 )
|
if( image.cubemap && image.num_sides != 6 )
|
||||||
{
|
{
|
||||||
// this never be happens, just in case
|
// this never can happen, just in case
|
||||||
FS_FreeImage( pack );
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pack = Mem_Calloc( host.imagepool, sizeof( *pack ));
|
||||||
|
|
||||||
if( image.cubemap )
|
if( image.cubemap )
|
||||||
{
|
{
|
||||||
image.flags |= IMAGE_CUBEMAP;
|
image.flags |= IMAGE_CUBEMAP;
|
||||||
|
@ -163,7 +164,7 @@ FS_AddSideToPack
|
||||||
|
|
||||||
================
|
================
|
||||||
*/
|
*/
|
||||||
qboolean FS_AddSideToPack( const char *name, int adjust_flags )
|
static qboolean FS_AddSideToPack( int adjust_flags )
|
||||||
{
|
{
|
||||||
byte *out, *flipped;
|
byte *out, *flipped;
|
||||||
qboolean resampled = false;
|
qboolean resampled = false;
|
||||||
|
@ -203,6 +204,88 @@ qboolean FS_AddSideToPack( const char *name, int adjust_flags )
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const loadpixformat_t *Image_GetLoadFormatForExtension( const char *ext )
|
||||||
|
{
|
||||||
|
const loadpixformat_t *format;
|
||||||
|
|
||||||
|
if( !COM_CheckStringEmpty( ext ))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for( format = image.loadformats; format->formatstring; format++ )
|
||||||
|
{
|
||||||
|
if( !Q_stricmp( ext, format->ext ))
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static qboolean Image_ProbeLoadBuffer_( const loadpixformat_t *fmt, const char *name, const byte *buf, size_t size, int override_hint )
|
||||||
|
{
|
||||||
|
if( override_hint > 0 )
|
||||||
|
image.hint = override_hint;
|
||||||
|
else image.hint = fmt->hint;
|
||||||
|
|
||||||
|
return fmt->loadfunc( name, buf, size );
|
||||||
|
}
|
||||||
|
|
||||||
|
static qboolean Image_ProbeLoadBuffer( const loadpixformat_t *fmt, const char *name, const byte *buf, size_t size, int override_hint )
|
||||||
|
{
|
||||||
|
if( size <= 0 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// bruteforce all loaders
|
||||||
|
if( !fmt )
|
||||||
|
{
|
||||||
|
for( fmt = image.loadformats; fmt->formatstring; fmt++ )
|
||||||
|
{
|
||||||
|
if( Image_ProbeLoadBuffer_( fmt, name, buf, size, override_hint ))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Image_ProbeLoadBuffer_( fmt, name, buf, size, override_hint );
|
||||||
|
}
|
||||||
|
|
||||||
|
static qboolean Image_ProbeLoad_( const loadpixformat_t *fmt, const char *name, const char *suffix, int override_hint )
|
||||||
|
{
|
||||||
|
qboolean success = false;
|
||||||
|
fs_offset_t filesize;
|
||||||
|
string path;
|
||||||
|
byte *f;
|
||||||
|
|
||||||
|
Q_snprintf( path, sizeof( path ), fmt->formatstring, name, suffix, fmt->ext );
|
||||||
|
f = FS_LoadFile( path, &filesize, false );
|
||||||
|
|
||||||
|
if( f )
|
||||||
|
{
|
||||||
|
success = Image_ProbeLoadBuffer( fmt, path, f, filesize, override_hint );
|
||||||
|
|
||||||
|
Mem_Free( f );
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
static qboolean Image_ProbeLoad( const loadpixformat_t *fmt, const char *name, const char *suffix, int override_hint )
|
||||||
|
{
|
||||||
|
if( !fmt )
|
||||||
|
{
|
||||||
|
// bruteforce all formats to allow implicit extension
|
||||||
|
for( fmt = image.loadformats; fmt->formatstring; fmt++ )
|
||||||
|
{
|
||||||
|
if( Image_ProbeLoad_( fmt, name, suffix, override_hint ))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Image_ProbeLoad_( fmt, name, suffix, override_hint );
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
================
|
================
|
||||||
FS_LoadImage
|
FS_LoadImage
|
||||||
|
@ -213,87 +296,35 @@ loading and unpack to rgba any known image
|
||||||
rgbdata_t *FS_LoadImage( const char *filename, const byte *buffer, size_t size )
|
rgbdata_t *FS_LoadImage( const char *filename, const byte *buffer, size_t size )
|
||||||
{
|
{
|
||||||
const char *ext = COM_FileExtension( filename );
|
const char *ext = COM_FileExtension( filename );
|
||||||
string path, loadname, sidename;
|
string loadname;
|
||||||
qboolean anyformat = true;
|
|
||||||
int i;
|
int i;
|
||||||
fs_offset_t filesize = 0;
|
const loadpixformat_t *extfmt;
|
||||||
const loadpixformat_t *format;
|
|
||||||
const cubepack_t *cmap;
|
const cubepack_t *cmap;
|
||||||
byte *f;
|
|
||||||
|
|
||||||
Q_strncpy( loadname, filename, sizeof( loadname ));
|
Q_strncpy( loadname, filename, sizeof( loadname ));
|
||||||
Image_Reset(); // clear old image
|
Image_Reset(); // clear old image
|
||||||
|
|
||||||
if( Q_stricmp( ext, "" ))
|
|
||||||
{
|
|
||||||
// we needs to compare file extension with list of supported formats
|
// we needs to compare file extension with list of supported formats
|
||||||
// and be sure what is real extension, not a filename with dot
|
// and be sure what is real extension, not a filename with dot
|
||||||
for( format = image.loadformats; format && format->formatstring; format++ )
|
if(( extfmt = Image_GetLoadFormatForExtension( ext )))
|
||||||
{
|
|
||||||
if( !Q_stricmp( format->ext, ext ))
|
|
||||||
{
|
|
||||||
COM_StripExtension( loadname );
|
COM_StripExtension( loadname );
|
||||||
anyformat = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// special mode: skip any checks, load file from buffer
|
// special mode: skip any checks, load file from buffer
|
||||||
if( filename[0] == '#' && buffer && size )
|
if( filename[0] == '#' && buffer && size )
|
||||||
goto load_internal;
|
goto load_internal;
|
||||||
|
|
||||||
// now try all the formats in the selected list
|
if( Image_ProbeLoad( extfmt, loadname, "", -1 ))
|
||||||
for( format = image.loadformats; format && format->formatstring; format++)
|
return ImagePack();
|
||||||
{
|
|
||||||
if( anyformat || !Q_stricmp( ext, format->ext ))
|
|
||||||
{
|
|
||||||
Q_sprintf( path, format->formatstring, loadname, "", format->ext );
|
|
||||||
image.hint = format->hint;
|
|
||||||
f = FS_LoadFile( path, &filesize, false );
|
|
||||||
|
|
||||||
if( f && filesize > 0 )
|
|
||||||
{
|
|
||||||
if( format->loadfunc( path, f, filesize ))
|
|
||||||
{
|
|
||||||
Mem_Free( f ); // release buffer
|
|
||||||
return ImagePack(); // loaded
|
|
||||||
}
|
|
||||||
else Mem_Free( f ); // release buffer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check all cubemap sides with package suffix
|
// check all cubemap sides with package suffix
|
||||||
for( cmap = load_cubemap; cmap && cmap->type; cmap++ )
|
for( cmap = load_cubemap; cmap && cmap->type; cmap++ )
|
||||||
{
|
{
|
||||||
for( i = 0; i < 6; i++ )
|
for( i = 0; i < 6; i++ )
|
||||||
{
|
{
|
||||||
// for support mixed cubemaps e.g. sky_ft.bmp, sky_rt.tga
|
if( Image_ProbeLoad( extfmt, loadname, cmap->type[i].suf, cmap->type[i].hint ) &&
|
||||||
// NOTE: all loaders must keep sides in one format for all
|
FS_AddSideToPack( cmap->type[i].flags )) // process flags to flip some sides
|
||||||
for( format = image.loadformats; format && format->formatstring; format++ )
|
|
||||||
{
|
{
|
||||||
if( anyformat || !Q_stricmp( ext, format->ext ))
|
break;
|
||||||
{
|
|
||||||
Q_sprintf( path, format->formatstring, loadname, cmap->type[i].suf, format->ext );
|
|
||||||
image.hint = (image_hint_t)cmap->type[i].hint; // side hint
|
|
||||||
|
|
||||||
f = FS_LoadFile( path, &filesize, false );
|
|
||||||
if( f && filesize > 0 )
|
|
||||||
{
|
|
||||||
// this name will be used only for tell user about problems
|
|
||||||
if( format->loadfunc( path, f, filesize ))
|
|
||||||
{
|
|
||||||
Q_snprintf( sidename, sizeof( sidename ), "%s%s.%s", loadname, cmap->type[i].suf, format->ext );
|
|
||||||
if( FS_AddSideToPack( sidename, cmap->type[i].flags )) // process flags to flip some sides
|
|
||||||
{
|
|
||||||
Mem_Free( f );
|
|
||||||
break; // loaded
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Mem_Free( f );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( image.num_sides != i + 1 ) // check side
|
if( image.num_sides != i + 1 ) // check side
|
||||||
|
@ -323,20 +354,13 @@ rgbdata_t *FS_LoadImage( const char *filename, const byte *buffer, size_t size )
|
||||||
return ImagePack(); // all done
|
return ImagePack(); // all done
|
||||||
|
|
||||||
load_internal:
|
load_internal:
|
||||||
for( format = image.loadformats; format && format->formatstring; format++ )
|
if( buffer && size )
|
||||||
{
|
{
|
||||||
if( anyformat || !Q_stricmp( ext, format->ext ))
|
if( Image_ProbeLoadBuffer( extfmt, loadname, buffer, size, -1 ))
|
||||||
{
|
return ImagePack();
|
||||||
image.hint = format->hint;
|
|
||||||
if( buffer && size > 0 )
|
|
||||||
{
|
|
||||||
if( format->loadfunc( loadname, buffer, size ))
|
|
||||||
return ImagePack(); // loaded
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( filename[0] != '#' )
|
if( loadname[0] != '#' )
|
||||||
Con_Reportf( S_WARN "FS_LoadImage: couldn't load \"%s\"\n", loadname );
|
Con_Reportf( S_WARN "FS_LoadImage: couldn't load \"%s\"\n", loadname );
|
||||||
|
|
||||||
// clear any force flags
|
// clear any force flags
|
||||||
|
@ -345,6 +369,8 @@ load_internal:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
================
|
================
|
||||||
Image_Save
|
Image_Save
|
||||||
|
@ -355,7 +381,7 @@ writes image as any known format
|
||||||
qboolean FS_SaveImage( const char *filename, rgbdata_t *pix )
|
qboolean FS_SaveImage( const char *filename, rgbdata_t *pix )
|
||||||
{
|
{
|
||||||
const char *ext = COM_FileExtension( filename );
|
const char *ext = COM_FileExtension( filename );
|
||||||
qboolean anyformat = !Q_stricmp( ext, "" ) ? true : false;
|
qboolean anyformat = !COM_CheckStringEmpty( ext );
|
||||||
string path, savename;
|
string path, savename;
|
||||||
const savepixformat_t *format;
|
const savepixformat_t *format;
|
||||||
|
|
||||||
|
|
|
@ -20,12 +20,17 @@ GNU General Public License for more details.
|
||||||
|
|
||||||
#if defined(XASH_NO_NETWORK)
|
#if defined(XASH_NO_NETWORK)
|
||||||
#include "platform/stub/net_stub.h"
|
#include "platform/stub/net_stub.h"
|
||||||
|
#elif XASH_NSWITCH
|
||||||
|
// our ntohl is here
|
||||||
|
#include <arpa/inet.h>
|
||||||
#elif !XASH_WIN32
|
#elif !XASH_WIN32
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const char png_sign[] = {0x89, 'P', 'N', 'G', '\r', '\n', 0x1a, '\n'};
|
static const char png_sign[] = {0x89, 'P', 'N', 'G', '\r', '\n', 0x1a, '\n'};
|
||||||
static const char ihdr_sign[] = {'I', 'H', 'D', 'R'};
|
static const char ihdr_sign[] = {'I', 'H', 'D', 'R'};
|
||||||
|
static const char trns_sign[] = {'t', 'R', 'N', 'S'};
|
||||||
|
static const char plte_sign[] = {'P', 'L', 'T', 'E'};
|
||||||
static const char idat_sign[] = {'I', 'D', 'A', 'T'};
|
static const char idat_sign[] = {'I', 'D', 'A', 'T'};
|
||||||
static const char iend_sign[] = {'I', 'E', 'N', 'D'};
|
static const char iend_sign[] = {'I', 'E', 'N', 'D'};
|
||||||
static const int iend_crc32 = 0xAE426082;
|
static const int iend_crc32 = 0xAE426082;
|
||||||
|
@ -39,9 +44,10 @@ qboolean Image_LoadPNG( const char *name, const byte *buffer, fs_offset_t filesi
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
short p, a, b, c, pa, pb, pc;
|
short p, a, b, c, pa, pb, pc;
|
||||||
byte *buf_p, *pixbuf, *raw, *prior, *idat_buf = NULL, *uncompressed_buffer = NULL, *rowend;
|
byte *buf_p, *pixbuf, *raw, *prior, *idat_buf = NULL, *uncompressed_buffer = NULL;
|
||||||
uint chunk_len, crc32, crc32_check, oldsize = 0, newsize = 0, rowsize;
|
byte *pallete = NULL, *trns = NULL;
|
||||||
uint uncompressed_size, pixel_size, i, y, filter_type, chunk_sign;
|
uint chunk_len, trns_len, plte_len, crc32, crc32_check, oldsize = 0, newsize = 0, rowsize;
|
||||||
|
uint uncompressed_size, pixel_size, pixel_count, i, y, filter_type, chunk_sign, r_alpha, g_alpha, b_alpha;
|
||||||
qboolean has_iend_chunk = false;
|
qboolean has_iend_chunk = false;
|
||||||
z_stream stream = {0};
|
z_stream stream = {0};
|
||||||
png_t png_hdr;
|
png_t png_hdr;
|
||||||
|
@ -67,7 +73,7 @@ qboolean Image_LoadPNG( const char *name, const byte *buffer, fs_offset_t filesi
|
||||||
// check IHDR chunk length (valid value - 13)
|
// check IHDR chunk length (valid value - 13)
|
||||||
if( png_hdr.ihdr_len != sizeof( png_ihdr_t ) )
|
if( png_hdr.ihdr_len != sizeof( png_ihdr_t ) )
|
||||||
{
|
{
|
||||||
Con_DPrintf( S_ERROR "Image_LoadPNG: Invalid IHDR chunk size (%s)\n", name );
|
Con_DPrintf( S_ERROR "Image_LoadPNG: Invalid IHDR chunk size %u (%s)\n", png_hdr.ihdr_len, name );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,36 +85,43 @@ qboolean Image_LoadPNG( const char *name, const byte *buffer, fs_offset_t filesi
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert image width and height to little endian
|
// convert image width and height to little endian
|
||||||
png_hdr.ihdr_chunk.height = ntohl( png_hdr.ihdr_chunk.height );
|
image.height = png_hdr.ihdr_chunk.height = ntohl( png_hdr.ihdr_chunk.height );
|
||||||
png_hdr.ihdr_chunk.width = ntohl( png_hdr.ihdr_chunk.width );
|
image.width = png_hdr.ihdr_chunk.width = ntohl( png_hdr.ihdr_chunk.width );
|
||||||
|
|
||||||
if( png_hdr.ihdr_chunk.height == 0 || png_hdr.ihdr_chunk.width == 0 )
|
if( png_hdr.ihdr_chunk.height == 0 || png_hdr.ihdr_chunk.width == 0 )
|
||||||
{
|
{
|
||||||
Con_DPrintf( S_ERROR "Image_LoadPNG: Invalid image size %dx%d (%s)\n", png_hdr.ihdr_chunk.width, png_hdr.ihdr_chunk.height, name );
|
Con_DPrintf( S_ERROR "Image_LoadPNG: Invalid image size %ux%u (%s)\n", png_hdr.ihdr_chunk.width, png_hdr.ihdr_chunk.height, name );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( !Image_ValidSize( name ))
|
||||||
|
return false;
|
||||||
|
|
||||||
if( png_hdr.ihdr_chunk.bitdepth != 8 )
|
if( png_hdr.ihdr_chunk.bitdepth != 8 )
|
||||||
{
|
{
|
||||||
Con_DPrintf( S_WARN "Image_LoadPNG: Only 8-bit images is supported (%s)\n", name );
|
Con_DPrintf( S_WARN "Image_LoadPNG: Only 8-bit images is supported (%s)\n", name );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( png_hdr.ihdr_chunk.colortype != PNG_CT_RGB && png_hdr.ihdr_chunk.colortype != PNG_CT_RGBA )
|
if( !( png_hdr.ihdr_chunk.colortype == PNG_CT_RGB
|
||||||
|
|| png_hdr.ihdr_chunk.colortype == PNG_CT_RGBA
|
||||||
|
|| png_hdr.ihdr_chunk.colortype == PNG_CT_GREY
|
||||||
|
|| png_hdr.ihdr_chunk.colortype == PNG_CT_ALPHA
|
||||||
|
|| png_hdr.ihdr_chunk.colortype == PNG_CT_PALLETE ) )
|
||||||
{
|
{
|
||||||
Con_DPrintf( S_WARN "Image_LoadPNG: Only 8-bit RGB and RGBA images is supported (%s)\n", name );
|
Con_DPrintf( S_WARN "Image_LoadPNG: Unknown color type %u (%s)\n", png_hdr.ihdr_chunk.colortype, name );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( png_hdr.ihdr_chunk.compression > 0 )
|
if( png_hdr.ihdr_chunk.compression > 0 )
|
||||||
{
|
{
|
||||||
Con_DPrintf( S_ERROR "Image_LoadPNG: Unknown compression method (%s)\n", name );
|
Con_DPrintf( S_ERROR "Image_LoadPNG: Unknown compression method %u (%s)\n", png_hdr.ihdr_chunk.compression, name );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( png_hdr.ihdr_chunk.filter > 0 )
|
if( png_hdr.ihdr_chunk.filter > 0 )
|
||||||
{
|
{
|
||||||
Con_DPrintf( S_ERROR "Image_LoadPNG: Unknown filter type (%s)\n", name );
|
Con_DPrintf( S_ERROR "Image_LoadPNG: Unknown filter type %u (%s)\n", png_hdr.ihdr_chunk.filter, name );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +133,7 @@ qboolean Image_LoadPNG( const char *name, const byte *buffer, fs_offset_t filesi
|
||||||
|
|
||||||
if( png_hdr.ihdr_chunk.interlace > 0 )
|
if( png_hdr.ihdr_chunk.interlace > 0 )
|
||||||
{
|
{
|
||||||
Con_DPrintf( S_ERROR "Image_LoadPNG: Unknown interlacing type (%s)\n", name );
|
Con_DPrintf( S_ERROR "Image_LoadPNG: Unknown interlacing type %u (%s)\n", png_hdr.ihdr_chunk.interlace, name );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,15 +164,34 @@ qboolean Image_LoadPNG( const char *name, const byte *buffer, fs_offset_t filesi
|
||||||
if( chunk_len > INT_MAX )
|
if( chunk_len > INT_MAX )
|
||||||
{
|
{
|
||||||
Con_DPrintf( S_ERROR "Image_LoadPNG: Found chunk with wrong size (%s)\n", name );
|
Con_DPrintf( S_ERROR "Image_LoadPNG: Found chunk with wrong size (%s)\n", name );
|
||||||
Mem_Free( idat_buf );
|
if( idat_buf ) Mem_Free( idat_buf );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( chunk_len > filesize - ( buf_p - buffer ))
|
||||||
|
{
|
||||||
|
Con_DPrintf( S_ERROR "Image_LoadPNG: Found chunk with size past file size (%s)\n", name );
|
||||||
|
if( idat_buf ) Mem_Free( idat_buf );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// move pointer
|
// move pointer
|
||||||
buf_p += sizeof( chunk_sign );
|
buf_p += sizeof( chunk_len );
|
||||||
|
|
||||||
|
// find transparency
|
||||||
|
if( !memcmp( buf_p, trns_sign, sizeof( trns_sign ) ) )
|
||||||
|
{
|
||||||
|
trns = buf_p + sizeof( trns_sign );
|
||||||
|
trns_len = chunk_len;
|
||||||
|
}
|
||||||
|
// find pallete for indexed image
|
||||||
|
else if( !memcmp( buf_p, plte_sign, sizeof( plte_sign ) ) )
|
||||||
|
{
|
||||||
|
pallete = buf_p + sizeof( plte_sign );
|
||||||
|
plte_len = chunk_len / 3;
|
||||||
|
}
|
||||||
// get all IDAT chunks data
|
// get all IDAT chunks data
|
||||||
if( !memcmp( buf_p, idat_sign, sizeof( idat_sign ) ) )
|
else if( !memcmp( buf_p, idat_sign, sizeof( idat_sign ) ) )
|
||||||
{
|
{
|
||||||
newsize = oldsize + chunk_len;
|
newsize = oldsize + chunk_len;
|
||||||
idat_buf = (byte *)Mem_Realloc( host.imagepool, idat_buf, newsize );
|
idat_buf = (byte *)Mem_Realloc( host.imagepool, idat_buf, newsize );
|
||||||
|
@ -185,7 +217,7 @@ qboolean Image_LoadPNG( const char *name, const byte *buffer, fs_offset_t filesi
|
||||||
if( ntohl( crc32 ) != crc32_check )
|
if( ntohl( crc32 ) != crc32_check )
|
||||||
{
|
{
|
||||||
Con_DPrintf( S_ERROR "Image_LoadPNG: Found chunk with wrong CRC32 sum (%s)\n", name );
|
Con_DPrintf( S_ERROR "Image_LoadPNG: Found chunk with wrong CRC32 sum (%s)\n", name );
|
||||||
Mem_Free( idat_buf );
|
if( idat_buf ) Mem_Free( idat_buf );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,6 +225,19 @@ qboolean Image_LoadPNG( const char *name, const byte *buffer, fs_offset_t filesi
|
||||||
buf_p += sizeof( crc32 );
|
buf_p += sizeof( crc32 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( oldsize == 0 )
|
||||||
|
{
|
||||||
|
Con_DPrintf( S_ERROR "Image_LoadPNG: Couldn't find IDAT chunks (%s)\n", name );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( png_hdr.ihdr_chunk.colortype == PNG_CT_PALLETE && !pallete )
|
||||||
|
{
|
||||||
|
Con_DPrintf( S_ERROR "Image_LoadPNG: PLTE chunk not found (%s)\n", name );
|
||||||
|
Mem_Free( idat_buf );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if( !has_iend_chunk )
|
if( !has_iend_chunk )
|
||||||
{
|
{
|
||||||
Con_DPrintf( S_ERROR "Image_LoadPNG: IEND chunk not found (%s)\n", name );
|
Con_DPrintf( S_ERROR "Image_LoadPNG: IEND chunk not found (%s)\n", name );
|
||||||
|
@ -202,19 +247,20 @@ qboolean Image_LoadPNG( const char *name, const byte *buffer, fs_offset_t filesi
|
||||||
|
|
||||||
if( chunk_len != 0 )
|
if( chunk_len != 0 )
|
||||||
{
|
{
|
||||||
Con_DPrintf( S_ERROR "Image_LoadPNG: IEND chunk has wrong size (%s)\n", name );
|
Con_DPrintf( S_ERROR "Image_LoadPNG: IEND chunk has wrong size %u (%s)\n", chunk_len, name );
|
||||||
Mem_Free( idat_buf );
|
Mem_Free( idat_buf );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( oldsize == 0 )
|
|
||||||
{
|
|
||||||
Con_DPrintf( S_ERROR "Image_LoadPNG: Couldn't find IDAT chunks (%s)\n", name );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch( png_hdr.ihdr_chunk.colortype )
|
switch( png_hdr.ihdr_chunk.colortype )
|
||||||
{
|
{
|
||||||
|
case PNG_CT_GREY:
|
||||||
|
case PNG_CT_PALLETE:
|
||||||
|
pixel_size = 1;
|
||||||
|
break;
|
||||||
|
case PNG_CT_ALPHA:
|
||||||
|
pixel_size = 2;
|
||||||
|
break;
|
||||||
case PNG_CT_RGB:
|
case PNG_CT_RGB:
|
||||||
pixel_size = 3;
|
pixel_size = 3;
|
||||||
break;
|
break;
|
||||||
|
@ -228,12 +274,13 @@ qboolean Image_LoadPNG( const char *name, const byte *buffer, fs_offset_t filesi
|
||||||
}
|
}
|
||||||
|
|
||||||
image.type = PF_RGBA_32; // always exctracted to 32-bit buffer
|
image.type = PF_RGBA_32; // always exctracted to 32-bit buffer
|
||||||
image.width = png_hdr.ihdr_chunk.width;
|
pixel_count = image.height * image.width;
|
||||||
image.height = png_hdr.ihdr_chunk.height;
|
image.size = pixel_count * 4;
|
||||||
image.size = image.height * image.width * 4;
|
|
||||||
|
if( png_hdr.ihdr_chunk.colortype & PNG_CT_RGB )
|
||||||
image.flags |= IMAGE_HAS_COLOR;
|
image.flags |= IMAGE_HAS_COLOR;
|
||||||
|
|
||||||
if( png_hdr.ihdr_chunk.colortype == PNG_CT_RGBA )
|
if( trns || ( png_hdr.ihdr_chunk.colortype & PNG_CT_ALPHA ) )
|
||||||
image.flags |= IMAGE_HAS_ALPHA;
|
image.flags |= IMAGE_HAS_ALPHA;
|
||||||
|
|
||||||
image.depth = 1;
|
image.depth = 1;
|
||||||
|
@ -275,7 +322,7 @@ qboolean Image_LoadPNG( const char *name, const byte *buffer, fs_offset_t filesi
|
||||||
|
|
||||||
raw = uncompressed_buffer;
|
raw = uncompressed_buffer;
|
||||||
|
|
||||||
if( png_hdr.ihdr_chunk.colortype == PNG_CT_RGB )
|
if( png_hdr.ihdr_chunk.colortype != PNG_CT_RGBA )
|
||||||
prior = pixbuf = raw;
|
prior = pixbuf = raw;
|
||||||
|
|
||||||
filter_type = *raw++;
|
filter_type = *raw++;
|
||||||
|
@ -377,23 +424,83 @@ qboolean Image_LoadPNG( const char *name, const byte *buffer, fs_offset_t filesi
|
||||||
prior = pixbuf;
|
prior = pixbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert RGB-to-RGBA
|
|
||||||
if( png_hdr.ihdr_chunk.colortype == PNG_CT_RGB )
|
|
||||||
{
|
|
||||||
pixbuf = image.rgba;
|
pixbuf = image.rgba;
|
||||||
raw = uncompressed_buffer;
|
raw = uncompressed_buffer;
|
||||||
|
|
||||||
for( y = 0; y < image.height; y++ )
|
switch( png_hdr.ihdr_chunk.colortype )
|
||||||
{
|
{
|
||||||
rowend = raw + rowsize;
|
case PNG_CT_RGB:
|
||||||
for( ; raw < rowend; raw += pixel_size )
|
if( trns )
|
||||||
|
{
|
||||||
|
r_alpha = trns[0] << 8 | trns[1];
|
||||||
|
g_alpha = trns[2] << 8 | trns[3];
|
||||||
|
b_alpha = trns[4] << 8 | trns[5];
|
||||||
|
}
|
||||||
|
|
||||||
|
for( y = 0; y < pixel_count; y++, raw += pixel_size )
|
||||||
{
|
{
|
||||||
*pixbuf++ = raw[0];
|
*pixbuf++ = raw[0];
|
||||||
*pixbuf++ = raw[1];
|
*pixbuf++ = raw[1];
|
||||||
*pixbuf++ = raw[2];
|
*pixbuf++ = raw[2];
|
||||||
|
|
||||||
|
if( trns && r_alpha == raw[0]
|
||||||
|
&& g_alpha == raw[1]
|
||||||
|
&& b_alpha == raw[2] )
|
||||||
|
*pixbuf++ = 0;
|
||||||
|
else
|
||||||
|
*pixbuf++ = 0xFF;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PNG_CT_GREY:
|
||||||
|
if( trns )
|
||||||
|
r_alpha = trns[0] << 8 | trns[1];
|
||||||
|
|
||||||
|
for( y = 0; y < pixel_count; y++, raw += pixel_size )
|
||||||
|
{
|
||||||
|
*pixbuf++ = raw[0];
|
||||||
|
*pixbuf++ = raw[0];
|
||||||
|
*pixbuf++ = raw[0];
|
||||||
|
|
||||||
|
if( trns && r_alpha == raw[0] )
|
||||||
|
*pixbuf++ = 0;
|
||||||
|
else
|
||||||
|
*pixbuf++ = 0xFF;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PNG_CT_ALPHA:
|
||||||
|
for( y = 0; y < pixel_count; y++, raw += pixel_size )
|
||||||
|
{
|
||||||
|
*pixbuf++ = raw[0];
|
||||||
|
*pixbuf++ = raw[0];
|
||||||
|
*pixbuf++ = raw[0];
|
||||||
|
*pixbuf++ = raw[1];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PNG_CT_PALLETE:
|
||||||
|
for( y = 0; y < pixel_count; y++, raw += pixel_size )
|
||||||
|
{
|
||||||
|
if( raw[0] < plte_len )
|
||||||
|
{
|
||||||
|
*pixbuf++ = pallete[3 * raw[0] + 0];
|
||||||
|
*pixbuf++ = pallete[3 * raw[0] + 1];
|
||||||
|
*pixbuf++ = pallete[3 * raw[0] + 2];
|
||||||
|
|
||||||
|
if( trns && raw[0] < trns_len )
|
||||||
|
*pixbuf++ = trns[raw[0]];
|
||||||
|
else
|
||||||
|
*pixbuf++ = 0xFF;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*pixbuf++ = 0;
|
||||||
|
*pixbuf++ = 0;
|
||||||
|
*pixbuf++ = 0;
|
||||||
*pixbuf++ = 0xFF;
|
*pixbuf++ = 0xFF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mem_Free( uncompressed_buffer );
|
Mem_Free( uncompressed_buffer );
|
||||||
|
|
|
@ -25,8 +25,8 @@ GNU General Public License for more details.
|
||||||
enum png_colortype
|
enum png_colortype
|
||||||
{
|
{
|
||||||
PNG_CT_GREY,
|
PNG_CT_GREY,
|
||||||
PNG_CT_PALLETE = BIT(0),
|
|
||||||
PNG_CT_RGB = BIT(1),
|
PNG_CT_RGB = BIT(1),
|
||||||
|
PNG_CT_PALLETE = (PNG_CT_RGB|BIT(0)),
|
||||||
PNG_CT_ALPHA = BIT(2),
|
PNG_CT_ALPHA = BIT(2),
|
||||||
PNG_CT_RGBA = (PNG_CT_RGB|PNG_CT_ALPHA)
|
PNG_CT_RGBA = (PNG_CT_RGB|PNG_CT_ALPHA)
|
||||||
};
|
};
|
||||||
|
|
|
@ -408,7 +408,7 @@ void learn( void )
|
||||||
if( rad ) alterneigh( rad, j, r, g, b ); // alter neighbours
|
if( rad ) alterneigh( rad, j, r, g, b ); // alter neighbours
|
||||||
|
|
||||||
p += step;
|
p += step;
|
||||||
if( p >= lim ) p -= lengthcount;
|
while( p >= lim ) p -= lengthcount;
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
|
|
|
@ -237,7 +237,16 @@ void Image_AddCmdFlags( uint flags )
|
||||||
|
|
||||||
qboolean Image_ValidSize( const char *name )
|
qboolean Image_ValidSize( const char *name )
|
||||||
{
|
{
|
||||||
if( image.width > IMAGE_MAXWIDTH || image.height > IMAGE_MAXHEIGHT || image.width <= 0 || image.height <= 0 )
|
int max_width = IMAGE_MAXWIDTH;
|
||||||
|
int max_height = IMAGE_MAXHEIGHT;
|
||||||
|
|
||||||
|
if( Image_CheckFlag( IL_LOAD_PLAYER_DECAL ))
|
||||||
|
{
|
||||||
|
max_width = PLDECAL_MAXWIDTH;
|
||||||
|
max_height = PLDECAL_MAXHEIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( image.width > max_width || image.height > max_height || image.width <= 0 || image.height <= 0 )
|
||||||
{
|
{
|
||||||
Con_DPrintf( S_ERROR "Image: (%s) dims out of range [%dx%d]\n", name, image.width, image.height );
|
Con_DPrintf( S_ERROR "Image: (%s) dims out of range [%dx%d]\n", name, image.width, image.height );
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -311,6 +311,9 @@ qboolean Image_LoadLMP( const char *name, const byte *buffer, fs_offset_t filesi
|
||||||
{
|
{
|
||||||
int numcolors;
|
int numcolors;
|
||||||
|
|
||||||
|
// HACKHACK: console background image shouldn't be transparent
|
||||||
|
if( !Q_stristr( name, "conback" ))
|
||||||
|
{
|
||||||
for( i = 0; i < pixels; i++ )
|
for( i = 0; i < pixels; i++ )
|
||||||
{
|
{
|
||||||
if( fin[i] == 255 )
|
if( fin[i] == 255 )
|
||||||
|
@ -320,6 +323,7 @@ qboolean Image_LoadLMP( const char *name, const byte *buffer, fs_offset_t filesi
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
pal = fin + pixels;
|
pal = fin + pixels;
|
||||||
numcolors = *(short *)pal;
|
numcolors = *(short *)pal;
|
||||||
if( numcolors != 256 ) pal = NULL; // corrupted lump ?
|
if( numcolors != 256 ) pal = NULL; // corrupted lump ?
|
||||||
|
|
|
@ -0,0 +1,391 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "ipv6text.h"
|
||||||
|
#include "xash3d_types.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#ifndef snprintf
|
||||||
|
#define snprintf _snprintf
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void IPv6IPToString( char *pszOutText, const unsigned char *ip )
|
||||||
|
{
|
||||||
|
// Find the longest run of consecutive zero quads.
|
||||||
|
// If there's a tie, we want the leftmost one.
|
||||||
|
int idxLongestRunStart = -1;
|
||||||
|
int nLongestRun = 1; // It must be at least 2 quads in a row, a single 0 must not be compressed
|
||||||
|
int nCurrentRun = 0, idxQuad;
|
||||||
|
char *p;
|
||||||
|
qboolean bNeedColon;
|
||||||
|
|
||||||
|
for ( idxQuad = 0 ; idxQuad < 8 ; ++idxQuad )
|
||||||
|
{
|
||||||
|
// Zero
|
||||||
|
if ( ip[idxQuad*2] || ip[idxQuad*2 + 1] )
|
||||||
|
{
|
||||||
|
// Terminate run
|
||||||
|
nCurrentRun = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Extend (or begin) run
|
||||||
|
++nCurrentRun;
|
||||||
|
|
||||||
|
// Longer than previously found run?
|
||||||
|
if ( nCurrentRun > nLongestRun )
|
||||||
|
{
|
||||||
|
nLongestRun = nCurrentRun;
|
||||||
|
idxLongestRunStart = idxQuad - nCurrentRun + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print the quads
|
||||||
|
p = pszOutText;
|
||||||
|
idxQuad = 0;
|
||||||
|
bNeedColon = false;
|
||||||
|
while ( idxQuad < 8 )
|
||||||
|
{
|
||||||
|
// Run of compressed zeros?
|
||||||
|
if ( idxQuad == idxLongestRunStart )
|
||||||
|
{
|
||||||
|
*(p++) = ':';
|
||||||
|
*(p++) = ':';
|
||||||
|
bNeedColon = false;
|
||||||
|
idxQuad += nLongestRun;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Lowercase hex digits, with leading zeros omitted
|
||||||
|
static const char hexdigits[] = "0123456789abcdef";
|
||||||
|
unsigned quad;
|
||||||
|
|
||||||
|
// Colon to separate from previous, unless
|
||||||
|
// we are first or immediately follow compressed zero "::"
|
||||||
|
if ( bNeedColon )
|
||||||
|
*(p++) = ':';
|
||||||
|
|
||||||
|
// Next quad should should print a separator
|
||||||
|
bNeedColon = true;
|
||||||
|
|
||||||
|
// Assemble 16-bit quad value from the two bytes
|
||||||
|
quad = ( (unsigned)ip[idxQuad*2] << 8U ) | ip[idxQuad*2 + 1];
|
||||||
|
|
||||||
|
// Manually do the hex number formatting.
|
||||||
|
if ( quad >= 0x0010 )
|
||||||
|
{
|
||||||
|
if ( quad >= 0x0100 )
|
||||||
|
{
|
||||||
|
if ( quad >= 0x1000 )
|
||||||
|
*(p++) = hexdigits[ quad >> 12U ];
|
||||||
|
*(p++) = hexdigits[ ( quad >> 8U ) & 0xf ];
|
||||||
|
}
|
||||||
|
*(p++) = hexdigits[ ( quad >> 4U ) & 0xf ];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Least significant digit, which is always printed
|
||||||
|
*(p++) = hexdigits[ quad & 0xf ];
|
||||||
|
|
||||||
|
// On to the next one
|
||||||
|
++idxQuad;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// String terminator
|
||||||
|
*p = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
void IPv6AddrToString( char *pszOutText, const unsigned char *ip, uint16_t port, uint32_t scope )
|
||||||
|
{
|
||||||
|
char *p = pszOutText;
|
||||||
|
|
||||||
|
// Open bracket
|
||||||
|
*(p++) = '[';
|
||||||
|
|
||||||
|
// Print in the IP
|
||||||
|
IPv6IPToString( p, ip );
|
||||||
|
|
||||||
|
// Find the end of the string
|
||||||
|
while (*p)
|
||||||
|
++p;
|
||||||
|
|
||||||
|
if ( scope )
|
||||||
|
{
|
||||||
|
// And now the scope. Max 32-digit scope number is 10 digits
|
||||||
|
snprintf( p, 12, "%%%d", scope );
|
||||||
|
|
||||||
|
// Find the end of the string
|
||||||
|
while (*p)
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
|
||||||
|
// And now the rest. Max 16-digit port number is 6 digits
|
||||||
|
snprintf( p, 8, "]:%u", (unsigned int)port );
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int ParseIPv6Addr_HexDigitVal( char c )
|
||||||
|
{
|
||||||
|
if ( c >= '0' && c <= '9' ) return c - '0';
|
||||||
|
if ( c >= 'a' && c <= 'f' ) return c - ('a' - 0xa);
|
||||||
|
if ( c >= 'A' && c <= 'F' ) return c - ('A' - 0xa);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
static inline int ParseIPv6Addr_DecimalDigitVal( char c )
|
||||||
|
{
|
||||||
|
if ( c >= '0' && c <= '9' ) return c - '0';
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
static bool ParseIPv6Addr_IsSpace( char c )
|
||||||
|
{
|
||||||
|
// Newlines don't count, intentionally
|
||||||
|
return c == ' ' || c == '\t';
|
||||||
|
}
|
||||||
|
bool ParseIPv6Addr( const char *pszText, unsigned char *pOutIP, int *pOutPort, uint32_t *pOutScope )
|
||||||
|
{
|
||||||
|
unsigned char *d, *pZeroFill, *pEndIP;
|
||||||
|
const char *s;
|
||||||
|
qboolean bQuadMustFollow;
|
||||||
|
int nPort;
|
||||||
|
|
||||||
|
while ( ParseIPv6Addr_IsSpace( *pszText ) )
|
||||||
|
++pszText;
|
||||||
|
s = pszText;
|
||||||
|
|
||||||
|
// Skip opening bracket, if present
|
||||||
|
if ( *s == '[' )
|
||||||
|
{
|
||||||
|
++s;
|
||||||
|
while ( ParseIPv6Addr_IsSpace( *s ) )
|
||||||
|
++s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special case for leading "::"
|
||||||
|
bQuadMustFollow = true;
|
||||||
|
d = pOutIP;
|
||||||
|
pZeroFill = NULL;
|
||||||
|
pEndIP = pOutIP + 16;
|
||||||
|
if ( s[0] == ':' && s[1] == ':' )
|
||||||
|
{
|
||||||
|
pZeroFill = d;
|
||||||
|
s += 2;
|
||||||
|
bQuadMustFollow = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse quads until we get to the end
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
// Next thing must be a quad, or end of input. Is it a quad?
|
||||||
|
int quadDigit = ParseIPv6Addr_HexDigitVal( *s );
|
||||||
|
int quad;
|
||||||
|
if ( quadDigit < 0 )
|
||||||
|
{
|
||||||
|
if ( bQuadMustFollow )
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No room for more quads?
|
||||||
|
if ( d >= pEndIP )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
++s;
|
||||||
|
quad = quadDigit;
|
||||||
|
|
||||||
|
// Now parse up to three additional characters
|
||||||
|
quadDigit = ParseIPv6Addr_HexDigitVal( *s );
|
||||||
|
if ( quadDigit >= 0 )
|
||||||
|
{
|
||||||
|
quad = ( quad << 4 ) | quadDigit;
|
||||||
|
++s;
|
||||||
|
|
||||||
|
quadDigit = ParseIPv6Addr_HexDigitVal( *s );
|
||||||
|
if ( quadDigit >= 0 )
|
||||||
|
{
|
||||||
|
quad = ( quad << 4 ) | quadDigit;
|
||||||
|
++s;
|
||||||
|
|
||||||
|
quadDigit = ParseIPv6Addr_HexDigitVal( *s );
|
||||||
|
if ( quadDigit >= 0 )
|
||||||
|
{
|
||||||
|
quad = ( quad << 4 ) | quadDigit;
|
||||||
|
++s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stash it in the next slot, ignoring for now the issue
|
||||||
|
// of compressed zeros
|
||||||
|
*(d++) = (unsigned char)( quad >> 8 );
|
||||||
|
*(d++) = (unsigned char)quad;
|
||||||
|
|
||||||
|
// Only valid character for the IP portion is a colon.
|
||||||
|
// Anything else ends the IP portion
|
||||||
|
if ( *s != ':' )
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Compressed zeros?
|
||||||
|
if ( s[1] == ':' )
|
||||||
|
{
|
||||||
|
|
||||||
|
// Eat '::'
|
||||||
|
s += 2;
|
||||||
|
|
||||||
|
// Can only have one range of compressed zeros
|
||||||
|
if ( pZeroFill )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Remember where to insert the compressed zeros
|
||||||
|
pZeroFill = d;
|
||||||
|
|
||||||
|
// An IP can end with '::'
|
||||||
|
bQuadMustFollow = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If they have filed the entire IP with no compressed zeros,
|
||||||
|
// then this is unambiguously a port number. That's not
|
||||||
|
// necessarily the best style, but it *is* unambiguous
|
||||||
|
// what it should mean, so let's allow it. If there
|
||||||
|
// are compressed zeros, then this is ambiguous, and we will
|
||||||
|
// always interpret it as a quad.
|
||||||
|
if ( !pZeroFill && d >= pEndIP )
|
||||||
|
break; // leave ':' as next character, for below
|
||||||
|
|
||||||
|
// Eat ':'
|
||||||
|
++s;
|
||||||
|
|
||||||
|
// A single colon must be followed by another quad
|
||||||
|
bQuadMustFollow = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// End of the IP. Do we have compressed zeros?
|
||||||
|
if ( pZeroFill )
|
||||||
|
{
|
||||||
|
// How many zeros do we need to fill?
|
||||||
|
intptr_t nZeros = pEndIP - d;
|
||||||
|
if ( nZeros <= 0 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Shift the quads after the bytes to the end
|
||||||
|
memmove( pZeroFill+nZeros, pZeroFill, d-pZeroFill );
|
||||||
|
|
||||||
|
// And now fill the zeros
|
||||||
|
memset( pZeroFill, 0, nZeros );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No compressed zeros. Just make sure we filled the IP exactly
|
||||||
|
if ( d != pEndIP )
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( *s == '%' )
|
||||||
|
{
|
||||||
|
// Parse scope number
|
||||||
|
uint32_t unScope = 0;
|
||||||
|
int nScopeDigit;
|
||||||
|
|
||||||
|
++s;
|
||||||
|
|
||||||
|
nScopeDigit = ParseIPv6Addr_DecimalDigitVal( *s );
|
||||||
|
if ( nScopeDigit < 0 )
|
||||||
|
return false;
|
||||||
|
unScope = (uint32_t)nScopeDigit;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
++s;
|
||||||
|
if ( *s == '\0' || *s == ']' || ParseIPv6Addr_IsSpace( *s ) )
|
||||||
|
break;
|
||||||
|
nScopeDigit = ParseIPv6Addr_DecimalDigitVal( *s );
|
||||||
|
if ( nScopeDigit < 0 )
|
||||||
|
return false;
|
||||||
|
unScope = unScope * 10 + nScopeDigit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( pOutScope )
|
||||||
|
*pOutScope = unScope;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( pOutScope )
|
||||||
|
*pOutScope = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we started with a bracket, then the next character MUST be a bracket.
|
||||||
|
// (And this is the only circumstance in which a closing bracket would be legal)
|
||||||
|
if ( *pszText == '[' )
|
||||||
|
{
|
||||||
|
while ( ParseIPv6Addr_IsSpace( *s ) )
|
||||||
|
++s;
|
||||||
|
if ( *s != ']' )
|
||||||
|
return false;
|
||||||
|
++s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we are definitely at the end of the IP. Do we have a port?
|
||||||
|
// We support all of the syntaxes mentioned in RFC5952 section 6 other
|
||||||
|
// than the ambiguous case
|
||||||
|
if ( *s == ':' || *s == '#' || *s == '.' || *s == 'p' || *s == 'P' )
|
||||||
|
{
|
||||||
|
++s;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while ( ParseIPv6Addr_IsSpace( *s ) )
|
||||||
|
++s;
|
||||||
|
if ( *s == '\0' )
|
||||||
|
{
|
||||||
|
// Parsed IP without port OK
|
||||||
|
if ( pOutPort )
|
||||||
|
*pOutPort = -1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( strncmp( s, "port", 4 ) == 0 )
|
||||||
|
{
|
||||||
|
s += 4;
|
||||||
|
while ( ParseIPv6Addr_IsSpace( *s ) )
|
||||||
|
++s;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Extra stuff after the IP which isn't whitespace or a port
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have a port. If they didn't ask for it, that's considered a parse failure.
|
||||||
|
if ( !pOutPort )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Parse port number
|
||||||
|
nPort = ParseIPv6Addr_DecimalDigitVal( *s );
|
||||||
|
if ( nPort < 0 )
|
||||||
|
return false;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
int portDigit;
|
||||||
|
|
||||||
|
++s;
|
||||||
|
if ( *s == '\0' || ParseIPv6Addr_IsSpace( *s ) )
|
||||||
|
break;
|
||||||
|
portDigit = ParseIPv6Addr_DecimalDigitVal( *s );
|
||||||
|
if ( portDigit < 0 )
|
||||||
|
return false;
|
||||||
|
nPort = nPort * 10 + portDigit;
|
||||||
|
if ( nPort > 0xffff )
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Consume trailing whitespace; confirm nothing else in the input
|
||||||
|
while ( ParseIPv6Addr_IsSpace( *s ) )
|
||||||
|
++s;
|
||||||
|
if ( *s != '\0' )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*pOutPort = nPort;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
/// Standalone plain C utilities for parsing and printing IPv6 addresses
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
/// Max length of an IPv6 string, with scope, WITHOUT port number, including \0':
|
||||||
|
/// 0123:4567:89ab:cdef:0123:4567:89ab:cdef%4294967295
|
||||||
|
#define k_ncchMaxIPV6AddrStringWithoutPort 51
|
||||||
|
|
||||||
|
/// Max number of bytes output by IPv6AddrToString, including '\0':
|
||||||
|
/// [0123:4567:89ab:cdef:0123:4567:89ab:cdef%4294967295]:12345
|
||||||
|
/// There are other strings that are acceptable to ParseIPv6Addr
|
||||||
|
/// that are longer than this, but this is the longest canonical
|
||||||
|
/// string.
|
||||||
|
#define k_ncchMaxIPV6AddrStringWithPort 59
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Format an IPv6 address to the canonical form according to RFC5952.
|
||||||
|
/// The address should be 16 bytes (e.g. same as in6_addr::s6_addr).
|
||||||
|
/// Your buffer MUST be at least k_ncchMaxIPV6AddrStringWithoutPort bytes.
|
||||||
|
extern void IPv6IPToString( char *pszOutText, const unsigned char *ip );
|
||||||
|
|
||||||
|
/// Format IPv6 IP and port to string. This uses the recommended
|
||||||
|
/// bracket notation, eg [1234::1]:12345. Your buffer must be
|
||||||
|
/// at least k_ncchMaxIPV6AddrStringWithPort bytes.
|
||||||
|
extern void IPv6AddrToString( char *pszOutText, const unsigned char *ip, uint16_t port, uint32_t scope );
|
||||||
|
|
||||||
|
/// Parse IPv6 address string. Returns true if parsed OK. Returns false
|
||||||
|
/// if input cannot be parsed, or if input specifies a port but pOutPort is NULL.
|
||||||
|
/// If input does not specify a port, and pOutPort is non-NULL, then *pOutPort is
|
||||||
|
/// set to -1.
|
||||||
|
///
|
||||||
|
/// Parsing is tolerant of any unambiguous IPv6 representation, the input
|
||||||
|
/// need not be the canonical RFC5952 representation.
|
||||||
|
///
|
||||||
|
/// IPv6 zones are not supported.
|
||||||
|
///
|
||||||
|
/// Leading and trailing whitespace is OK around the entire string,
|
||||||
|
/// but not internal whitespace. The different methods for separating the
|
||||||
|
/// port in RFC5952 are supported section 6, except the ambiguous case
|
||||||
|
/// of a colon to separate the port, when the IP contains a double-colon.
|
||||||
|
/// Brackets around an IP are OK, even if there is no port.
|
||||||
|
///
|
||||||
|
/// Address must point to a 16-byte buffer (e.g. same as in6_addr::s6_addr)
|
||||||
|
/// Port is returned in host byte order.
|
||||||
|
extern bool ParseIPv6Addr( const char *pszText, unsigned char *pOutIP, int *pOutPort, uint32_t *pOutScope );
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -35,7 +35,9 @@ __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define E_GAME "XASH3D_GAME" // default env dir to start from
|
#define E_GAME "XASH3D_GAME" // default env dir to start from
|
||||||
#define GAME_PATH "valve" // default dir to start from
|
#ifndef XASH_GAMEDIR
|
||||||
|
#define XASH_GAMEDIR "valve"
|
||||||
|
#endif
|
||||||
|
|
||||||
static char szGameDir[128]; // safe place to keep gamedir
|
static char szGameDir[128]; // safe place to keep gamedir
|
||||||
static int szArgc;
|
static int szArgc;
|
||||||
|
@ -56,7 +58,7 @@ _inline int Sys_Start( void )
|
||||||
const char *game = getenv( E_GAME );
|
const char *game = getenv( E_GAME );
|
||||||
|
|
||||||
if( !game )
|
if( !game )
|
||||||
game = GAME_PATH;
|
game = XASH_GAMEDIR;
|
||||||
|
|
||||||
Q_strncpy( szGameDir, game, sizeof( szGameDir ));
|
Q_strncpy( szGameDir, game, sizeof( szGameDir ));
|
||||||
#if XASH_EMSCRIPTEN
|
#if XASH_EMSCRIPTEN
|
||||||
|
|
|
@ -65,7 +65,7 @@ void *COM_FunctionFromName_SR( void *hInstance, const char *pName )
|
||||||
|
|
||||||
if( f ) return f;
|
if( f ) return f;
|
||||||
}
|
}
|
||||||
#elif XASH_MSVC
|
#elif _MSC_VER
|
||||||
// TODO: COM_ConvertToLocalPlatform doesn't support MSVC yet
|
// TODO: COM_ConvertToLocalPlatform doesn't support MSVC yet
|
||||||
// also custom loader strips always MSVC mangling, so Win32
|
// also custom loader strips always MSVC mangling, so Win32
|
||||||
// platforms already use platform-neutral names
|
// platforms already use platform-neutral names
|
||||||
|
@ -158,6 +158,22 @@ static void COM_GenerateClientLibraryPath( const char *name, char *out, size_t s
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
==============
|
||||||
|
COM_StripIntelSuffix
|
||||||
|
|
||||||
|
Some modders use _i?86 suffix in game library name
|
||||||
|
So strip it to follow library naming for non-Intel CPUs
|
||||||
|
==============
|
||||||
|
*/
|
||||||
|
static void COM_StripIntelSuffix( char *out )
|
||||||
|
{
|
||||||
|
char *suffix = Q_strrchr( out, '_' );
|
||||||
|
|
||||||
|
if( suffix && Q_stricmpext( "_i?86", suffix ))
|
||||||
|
*suffix = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
==============
|
==============
|
||||||
COM_GenerateServerLibraryPath
|
COM_GenerateServerLibraryPath
|
||||||
|
@ -193,6 +209,7 @@ static void COM_GenerateServerLibraryPath( char *out, size_t size )
|
||||||
|
|
||||||
ext = COM_FileExtension( dllpath );
|
ext = COM_FileExtension( dllpath );
|
||||||
COM_StripExtension( dllpath );
|
COM_StripExtension( dllpath );
|
||||||
|
COM_StripIntelSuffix( dllpath );
|
||||||
|
|
||||||
COM_GenerateCommonLibraryName( dllpath, ext, out, size );
|
COM_GenerateCommonLibraryName( dllpath, ext, out, size );
|
||||||
#endif
|
#endif
|
||||||
|
@ -234,7 +251,7 @@ void COM_GetCommonLibraryPath( ECommonLibraryType eLibType, char *out, size_t si
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ASSERT( true );
|
ASSERT( 0 );
|
||||||
out[0] = 0;
|
out[0] = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ typedef struct master_s
|
||||||
qboolean sent;
|
qboolean sent;
|
||||||
qboolean save;
|
qboolean save;
|
||||||
string address;
|
string address;
|
||||||
|
netadr_t adr; // temporary, rewritten after each send
|
||||||
} master_t;
|
} master_t;
|
||||||
|
|
||||||
struct masterlist_s
|
struct masterlist_s
|
||||||
|
@ -44,31 +45,32 @@ qboolean NET_SendToMasters( netsrc_t sock, size_t len, const void *data )
|
||||||
|
|
||||||
for( list = ml.list; list; list = list->next )
|
for( list = ml.list; list; list = list->next )
|
||||||
{
|
{
|
||||||
netadr_t adr;
|
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
if( list->sent )
|
if( list->sent )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
res = NET_StringToAdrNB( list->address, &adr );
|
res = NET_StringToAdrNB( list->address, &list->adr );
|
||||||
|
|
||||||
if( !res )
|
if( !res )
|
||||||
{
|
{
|
||||||
Con_Reportf( "Can't resolve adr: %s\n", list->address );
|
Con_Reportf( "Can't resolve adr: %s\n", list->address );
|
||||||
list->sent = true;
|
list->sent = true;
|
||||||
|
list->adr.type = NA_UNUSED;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( res == 2 )
|
if( res == 2 )
|
||||||
{
|
{
|
||||||
list->sent = false;
|
list->sent = false;
|
||||||
|
list->adr.type = NA_UNUSED;
|
||||||
wait = true;
|
wait = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
list->sent = true;
|
list->sent = true;
|
||||||
|
|
||||||
NET_SendPacket( sock, len, data, adr );
|
NET_SendPacket( sock, len, data, list->adr );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !wait )
|
if( !wait )
|
||||||
|
@ -85,6 +87,25 @@ qboolean NET_SendToMasters( netsrc_t sock, size_t len, const void *data )
|
||||||
return wait;
|
return wait;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
========================
|
||||||
|
NET_IsMasterAdr
|
||||||
|
|
||||||
|
========================
|
||||||
|
*/
|
||||||
|
qboolean NET_IsMasterAdr( netadr_t adr )
|
||||||
|
{
|
||||||
|
master_t *master;
|
||||||
|
|
||||||
|
for( master = ml.list; master; master = master->next )
|
||||||
|
{
|
||||||
|
if( NET_CompareAdr( adr, master->adr ))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
========================
|
========================
|
||||||
NET_AddMaster
|
NET_AddMaster
|
||||||
|
@ -107,6 +128,7 @@ static void NET_AddMaster( const char *addr, qboolean save )
|
||||||
master->sent = false;
|
master->sent = false;
|
||||||
master->save = save;
|
master->save = save;
|
||||||
master->next = NULL;
|
master->next = NULL;
|
||||||
|
master->adr.type = NA_UNUSED;
|
||||||
|
|
||||||
// link in
|
// link in
|
||||||
if( last )
|
if( last )
|
||||||
|
@ -161,7 +183,10 @@ static void NET_ListMasters_f( void )
|
||||||
|
|
||||||
for( i = 1, list = ml.list; list; i++, list = list->next )
|
for( i = 1, list = ml.list; list; i++, list = list->next )
|
||||||
{
|
{
|
||||||
Msg( "%d\t%s\n", i, list->address );
|
Msg( "%d\t%s", i, list->address );
|
||||||
|
if( list->adr.type != NA_UNUSED )
|
||||||
|
Msg( "\t%s\n", NET_AdrToString( list->adr ));
|
||||||
|
else Msg( "\n" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -134,6 +134,7 @@ typedef struct
|
||||||
int lightmap_samples; // samples per lightmap (1 or 3)
|
int lightmap_samples; // samples per lightmap (1 or 3)
|
||||||
int version; // model version
|
int version; // model version
|
||||||
qboolean isworld;
|
qboolean isworld;
|
||||||
|
qboolean isbsp30ext;
|
||||||
} dbspmodel_t;
|
} dbspmodel_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -159,6 +160,7 @@ typedef struct
|
||||||
#define LUMP_SAVESTATS BIT( 0 )
|
#define LUMP_SAVESTATS BIT( 0 )
|
||||||
#define LUMP_TESTONLY BIT( 1 )
|
#define LUMP_TESTONLY BIT( 1 )
|
||||||
#define LUMP_SILENT BIT( 2 )
|
#define LUMP_SILENT BIT( 2 )
|
||||||
|
#define LUMP_BSP30EXT BIT( 3 ) // extra marker for Mod_LoadLump
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
@ -251,13 +253,12 @@ static void Mod_LoadLump( const byte *in, mlumpinfo_t *info, mlumpstat_t *stat,
|
||||||
// always use alternate entrysize for BSP2
|
// always use alternate entrysize for BSP2
|
||||||
real_entrysize = info->entrysize32;
|
real_entrysize = info->entrysize32;
|
||||||
}
|
}
|
||||||
else if( info->lumpnumber == LUMP_CLIPNODES && version != Q1BSP_VERSION )
|
else if( version == HLBSP_VERSION && FBitSet( flags, LUMP_BSP30EXT ) && info->lumpnumber == LUMP_CLIPNODES )
|
||||||
{
|
{
|
||||||
// never run this check for BSP29 because Arguire QBSP 'broken' clipnodes!
|
// if this map is bsp30ext, try to guess extended clipnodes
|
||||||
if(( l->filelen % info->entrysize ) || ( l->filelen / info->entrysize ) >= MAX_MAP_CLIPNODES )
|
if((( l->filelen % info->entrysize ) || ( l->filelen / info->entrysize32 ) >= MAX_MAP_CLIPNODES_HLBSP ))
|
||||||
{
|
{
|
||||||
real_entrysize = info->entrysize32;
|
real_entrysize = info->entrysize32;
|
||||||
SetBits( flags, LUMP_SILENT ); // shut up warning
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -434,9 +435,9 @@ void Mod_PrintWorldStats_f( void )
|
||||||
Con_Printf( "Lighting: %s\n", FBitSet( w->flags, MODEL_COLORED_LIGHTING ) ? "colored" : "monochrome" );
|
Con_Printf( "Lighting: %s\n", FBitSet( w->flags, MODEL_COLORED_LIGHTING ) ? "colored" : "monochrome" );
|
||||||
Con_Printf( "World total leafs: %d\n", worldmodel->numleafs + 1 );
|
Con_Printf( "World total leafs: %d\n", worldmodel->numleafs + 1 );
|
||||||
Con_Printf( "original name: ^1%s\n", worldmodel->name );
|
Con_Printf( "original name: ^1%s\n", worldmodel->name );
|
||||||
Con_Printf( "internal name: %s\n", (world.message[0]) ? va( "^2%s", world.message ) : "none" );
|
Con_Printf( "internal name: ^2%s\n", world.message[0] ? world.message : "none" );
|
||||||
Con_Printf( "map compiler: %s\n", (world.compiler[0]) ? va( "^3%s", world.compiler ) : "unknown" );
|
Con_Printf( "map compiler: ^3%s\n", world.compiler[0] ? world.compiler : "unknown" );
|
||||||
Con_Printf( "map editor: %s\n", (world.generator[0]) ? va( "^2%s", world.generator ) : "unknown" );
|
Con_Printf( "map editor: ^2%s\n", world.generator[0] ? world.generator : "unknown" );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2578,7 +2579,7 @@ static void Mod_LoadClipnodes( dbspmodel_t *bmod )
|
||||||
|
|
||||||
bmod->clipnodes_out = out = (dclipnode32_t *)Mem_Malloc( loadmodel->mempool, bmod->numclipnodes * sizeof( *out ));
|
bmod->clipnodes_out = out = (dclipnode32_t *)Mem_Malloc( loadmodel->mempool, bmod->numclipnodes * sizeof( *out ));
|
||||||
|
|
||||||
if(( bmod->version == QBSP2_VERSION ) || ( bmod->version == HLBSP_VERSION && bmod->numclipnodes >= MAX_MAP_CLIPNODES ))
|
if(( bmod->version == QBSP2_VERSION ) || ( bmod->version == HLBSP_VERSION && bmod->isbsp30ext && bmod->numclipnodes >= MAX_MAP_CLIPNODES_HLBSP ))
|
||||||
{
|
{
|
||||||
dclipnode32_t *in = bmod->clipnodes32;
|
dclipnode32_t *in = bmod->clipnodes32;
|
||||||
|
|
||||||
|
@ -2738,33 +2739,14 @@ static void Mod_LoadLighting( dbspmodel_t *bmod )
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=================
|
=================
|
||||||
Mod_LumpLooksLikePlanes
|
Mod_LumpLooksLikeEntities
|
||||||
|
|
||||||
=================
|
=================
|
||||||
*/
|
*/
|
||||||
static qboolean Mod_LumpLooksLikePlanes( const byte *in, dlump_t *lump, qboolean fast )
|
static int Mod_LumpLooksLikeEntities( const char *lump, const size_t lumplen )
|
||||||
{
|
{
|
||||||
int numplanes, i;
|
// look for "classname" string
|
||||||
const dplane_t *planes;
|
return Q_memmem( lump, lumplen, "\"classname\"", sizeof( "\"classname\"" ) - 1 ) != NULL ? 1 : 0;
|
||||||
|
|
||||||
if( lump->filelen < sizeof( dplane_t ) &&
|
|
||||||
lump->filelen % sizeof( dplane_t ) != 0 )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if( fast )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
numplanes = lump->filelen / sizeof( dplane_t );
|
|
||||||
planes = (const dplane_t*)(in + lump->fileofs);
|
|
||||||
|
|
||||||
for( i = 0; i < numplanes; i++ )
|
|
||||||
{
|
|
||||||
// planes can only be from 0 to 5: PLANE_X, Y, Z and PLANE_ANYX, Y and Z
|
|
||||||
if( planes[i].type < 0 || planes[i].type > 5 )
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2776,12 +2758,13 @@ loading and processing bmodel
|
||||||
*/
|
*/
|
||||||
qboolean Mod_LoadBmodelLumps( const byte *mod_base, qboolean isworld )
|
qboolean Mod_LoadBmodelLumps( const byte *mod_base, qboolean isworld )
|
||||||
{
|
{
|
||||||
dheader_t *header = (dheader_t *)mod_base;
|
const dheader_t *header = (const dheader_t *)mod_base;
|
||||||
dextrahdr_t *extrahdr = (dextrahdr_t *)((byte *)mod_base + sizeof( dheader_t ));
|
const dextrahdr_t *extrahdr = (const dextrahdr_t *)(mod_base + sizeof( dheader_t ));
|
||||||
dbspmodel_t *bmod = &srcmodel;
|
dbspmodel_t *bmod = &srcmodel;
|
||||||
model_t *mod = loadmodel;
|
model_t *mod = loadmodel;
|
||||||
char wadvalue[2048];
|
char wadvalue[2048];
|
||||||
int i;
|
size_t len = 0;
|
||||||
|
int i, ret, flags = 0;
|
||||||
|
|
||||||
// always reset the intermediate struct
|
// always reset the intermediate struct
|
||||||
memset( bmod, 0, sizeof( dbspmodel_t ));
|
memset( bmod, 0, sizeof( dbspmodel_t ));
|
||||||
|
@ -2799,9 +2782,26 @@ qboolean Mod_LoadBmodelLumps( const byte *mod_base, qboolean isworld )
|
||||||
#endif
|
#endif
|
||||||
switch( header->version )
|
switch( header->version )
|
||||||
{
|
{
|
||||||
case Q1BSP_VERSION:
|
|
||||||
case HLBSP_VERSION:
|
case HLBSP_VERSION:
|
||||||
|
if( extrahdr->id == IDEXTRAHEADER )
|
||||||
|
{
|
||||||
|
SetBits( flags, LUMP_BSP30EXT );
|
||||||
|
}
|
||||||
|
// only relevant for half-life maps
|
||||||
|
else if( !Mod_LumpLooksLikeEntities( mod_base + header->lumps[LUMP_ENTITIES].fileofs, header->lumps[LUMP_ENTITIES].filelen ) &&
|
||||||
|
Mod_LumpLooksLikeEntities( mod_base + header->lumps[LUMP_PLANES].fileofs, header->lumps[LUMP_PLANES].filelen ))
|
||||||
|
{
|
||||||
|
// blue-shift swapped lumps
|
||||||
|
srclumps[0].lumpnumber = LUMP_PLANES;
|
||||||
|
srclumps[1].lumpnumber = LUMP_ENTITIES;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// intended fallthrough
|
||||||
|
case Q1BSP_VERSION:
|
||||||
case QBSP2_VERSION:
|
case QBSP2_VERSION:
|
||||||
|
// everything else
|
||||||
|
srclumps[0].lumpnumber = LUMP_ENTITIES;
|
||||||
|
srclumps[1].lumpnumber = LUMP_PLANES;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Con_Printf( S_ERROR "%s has wrong version number (%i should be %i)\n", loadmodel->name, header->version, HLBSP_VERSION );
|
Con_Printf( S_ERROR "%s has wrong version number (%i should be %i)\n", loadmodel->name, header->version, HLBSP_VERSION );
|
||||||
|
@ -2810,40 +2810,21 @@ qboolean Mod_LoadBmodelLumps( const byte *mod_base, qboolean isworld )
|
||||||
}
|
}
|
||||||
|
|
||||||
bmod->version = header->version; // share up global
|
bmod->version = header->version; // share up global
|
||||||
if( isworld ) world.flags = 0; // clear world settings
|
if( isworld )
|
||||||
|
{
|
||||||
|
world.flags = 0; // clear world settings
|
||||||
|
SetBits( flags, LUMP_SAVESTATS|LUMP_SILENT );
|
||||||
|
}
|
||||||
bmod->isworld = isworld;
|
bmod->isworld = isworld;
|
||||||
|
bmod->isbsp30ext = FBitSet( flags, LUMP_BSP30EXT );
|
||||||
if( header->version == HLBSP_VERSION )
|
|
||||||
{
|
|
||||||
// only relevant for half-life maps
|
|
||||||
if( !Mod_LumpLooksLikePlanes( mod_base, &header->lumps[LUMP_PLANES], false ) &&
|
|
||||||
Mod_LumpLooksLikePlanes( mod_base, &header->lumps[LUMP_ENTITIES], false ))
|
|
||||||
{
|
|
||||||
// blue-shift swapped lumps
|
|
||||||
srclumps[0].lumpnumber = LUMP_PLANES;
|
|
||||||
srclumps[1].lumpnumber = LUMP_ENTITIES;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// everything else
|
|
||||||
srclumps[0].lumpnumber = LUMP_ENTITIES;
|
|
||||||
srclumps[1].lumpnumber = LUMP_PLANES;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// everything else
|
|
||||||
srclumps[0].lumpnumber = LUMP_ENTITIES;
|
|
||||||
srclumps[1].lumpnumber = LUMP_PLANES;
|
|
||||||
}
|
|
||||||
|
|
||||||
// loading base lumps
|
// loading base lumps
|
||||||
for( i = 0; i < ARRAYSIZE( srclumps ); i++ )
|
for( i = 0; i < ARRAYSIZE( srclumps ); i++ )
|
||||||
Mod_LoadLump( mod_base, &srclumps[i], &worldstats[i], isworld ? (LUMP_SAVESTATS|LUMP_SILENT) : 0 );
|
Mod_LoadLump( mod_base, &srclumps[i], &worldstats[i], flags );
|
||||||
|
|
||||||
// loading extralumps
|
// loading extralumps
|
||||||
for( i = 0; i < ARRAYSIZE( extlumps ); i++ )
|
for( i = 0; i < ARRAYSIZE( extlumps ); i++ )
|
||||||
Mod_LoadLump( mod_base, &extlumps[i], &worldstats[ARRAYSIZE( srclumps ) + i], isworld ? (LUMP_SAVESTATS|LUMP_SILENT) : 0 );
|
Mod_LoadLump( mod_base, &extlumps[i], &worldstats[ARRAYSIZE( srclumps ) + i], flags );
|
||||||
|
|
||||||
if( !bmod->isworld && loadstat.numerrors )
|
if( !bmod->isworld && loadstat.numerrors )
|
||||||
{
|
{
|
||||||
|
@ -2888,7 +2869,13 @@ qboolean Mod_LoadBmodelLumps( const byte *mod_base, qboolean isworld )
|
||||||
{
|
{
|
||||||
if( !bmod->wadlist.wadusage[i] )
|
if( !bmod->wadlist.wadusage[i] )
|
||||||
continue;
|
continue;
|
||||||
Q_strncat( wadvalue, va( "%s.wad; ", bmod->wadlist.wadnames[i] ), sizeof( wadvalue ));
|
ret = Q_snprintf( &wadvalue[len], sizeof( wadvalue ), "%s.wad; ", bmod->wadlist.wadnames[i] );
|
||||||
|
if( ret == -1 )
|
||||||
|
{
|
||||||
|
Con_DPrintf( S_WARN "Too many wad files for output!\n" );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
len += ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( COM_CheckString( wadvalue ))
|
if( COM_CheckString( wadvalue ))
|
||||||
|
@ -2900,16 +2887,45 @@ qboolean Mod_LoadBmodelLumps( const byte *mod_base, qboolean isworld )
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int Mod_LumpLooksLikeEntitiesFile( file_t *f, const dlump_t *l, int flags, const char *msg )
|
||||||
|
{
|
||||||
|
char *buf;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if( FS_Seek( f, l->fileofs, SEEK_SET ) < 0 )
|
||||||
|
{
|
||||||
|
if( !FBitSet( flags, LUMP_SILENT ))
|
||||||
|
Con_DPrintf( S_ERROR "map ^2%s^7 %s lump past end of file\n", loadstat.name, msg );
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = Z_Malloc( l->filelen + 1 );
|
||||||
|
if( FS_Read( f, buf, l->filelen ) != l->filelen )
|
||||||
|
{
|
||||||
|
if( !FBitSet( flags, LUMP_SILENT ))
|
||||||
|
Con_DPrintf( S_ERROR "can't read %s lump of map ^2%s^7", msg, loadstat.name );
|
||||||
|
Z_Free( buf );
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = Mod_LumpLooksLikeEntities( buf, l->filelen );
|
||||||
|
|
||||||
|
Z_Free( buf );
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=================
|
=================
|
||||||
Mod_TestBmodelLumps
|
Mod_TestBmodelLumps
|
||||||
|
|
||||||
check for possible errors
|
check for possible errors
|
||||||
|
return real entities lump (for bshift swapped lumps)
|
||||||
=================
|
=================
|
||||||
*/
|
*/
|
||||||
qboolean Mod_TestBmodelLumps( const char *name, const byte *mod_base, qboolean silent )
|
qboolean Mod_TestBmodelLumps( file_t *f, const char *name, const byte *mod_base, qboolean silent, dlump_t *entities )
|
||||||
{
|
{
|
||||||
dheader_t *header = (dheader_t *)mod_base;
|
const dheader_t *header = (const dheader_t *)mod_base;
|
||||||
|
const dextrahdr_t *extrahdr = (const dextrahdr_t *)( mod_base + sizeof( dheader_t ));
|
||||||
int i, flags = LUMP_TESTONLY;
|
int i, flags = LUMP_TESTONLY;
|
||||||
|
|
||||||
// always reset the intermediate struct
|
// always reset the intermediate struct
|
||||||
|
@ -2917,7 +2933,8 @@ qboolean Mod_TestBmodelLumps( const char *name, const byte *mod_base, qboolean s
|
||||||
|
|
||||||
// store the name to correct show errors and warnings
|
// store the name to correct show errors and warnings
|
||||||
Q_strncpy( loadstat.name, name, sizeof( loadstat.name ));
|
Q_strncpy( loadstat.name, name, sizeof( loadstat.name ));
|
||||||
if( silent ) SetBits( flags, LUMP_SILENT );
|
if( silent )
|
||||||
|
SetBits( flags, LUMP_SILENT );
|
||||||
|
|
||||||
#ifndef SUPPORT_BSP2_FORMAT
|
#ifndef SUPPORT_BSP2_FORMAT
|
||||||
if( header->version == QBSP2_VERSION )
|
if( header->version == QBSP2_VERSION )
|
||||||
|
@ -2927,11 +2944,42 @@ qboolean Mod_TestBmodelLumps( const char *name, const byte *mod_base, qboolean s
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
switch( header->version )
|
switch( header->version )
|
||||||
{
|
{
|
||||||
case Q1BSP_VERSION:
|
|
||||||
case HLBSP_VERSION:
|
case HLBSP_VERSION:
|
||||||
|
if( extrahdr->id == IDEXTRAHEADER )
|
||||||
|
{
|
||||||
|
SetBits( flags, LUMP_BSP30EXT );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// only relevant for half-life maps
|
||||||
|
int ret = Mod_LumpLooksLikeEntitiesFile( f, &header->lumps[LUMP_ENTITIES], flags, "entities" );
|
||||||
|
if( ret < 0 ) return false;
|
||||||
|
if( !ret )
|
||||||
|
{
|
||||||
|
ret = Mod_LumpLooksLikeEntitiesFile( f, &header->lumps[LUMP_PLANES], flags, "planes" );
|
||||||
|
if( ret < 0 ) return false;
|
||||||
|
if( ret )
|
||||||
|
{
|
||||||
|
// blue-shift swapped lumps
|
||||||
|
*entities = header->lumps[LUMP_PLANES];
|
||||||
|
|
||||||
|
srclumps[0].lumpnumber = LUMP_PLANES;
|
||||||
|
srclumps[1].lumpnumber = LUMP_ENTITIES;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// intended fallthrough
|
||||||
|
case Q1BSP_VERSION:
|
||||||
case QBSP2_VERSION:
|
case QBSP2_VERSION:
|
||||||
|
// everything else
|
||||||
|
*entities = header->lumps[LUMP_ENTITIES];
|
||||||
|
|
||||||
|
srclumps[0].lumpnumber = LUMP_ENTITIES;
|
||||||
|
srclumps[1].lumpnumber = LUMP_PLANES;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// don't early out: let me analyze errors
|
// don't early out: let me analyze errors
|
||||||
|
@ -2941,30 +2989,6 @@ qboolean Mod_TestBmodelLumps( const char *name, const byte *mod_base, qboolean s
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( header->version == HLBSP_VERSION )
|
|
||||||
{
|
|
||||||
// only relevant for half-life maps
|
|
||||||
if( Mod_LumpLooksLikePlanes( mod_base, &header->lumps[LUMP_ENTITIES], true ) &&
|
|
||||||
!Mod_LumpLooksLikePlanes( mod_base, &header->lumps[LUMP_PLANES], true ))
|
|
||||||
{
|
|
||||||
// blue-shift swapped lumps
|
|
||||||
srclumps[0].lumpnumber = LUMP_PLANES;
|
|
||||||
srclumps[1].lumpnumber = LUMP_ENTITIES;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// everything else
|
|
||||||
srclumps[0].lumpnumber = LUMP_ENTITIES;
|
|
||||||
srclumps[1].lumpnumber = LUMP_PLANES;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// everything else
|
|
||||||
srclumps[0].lumpnumber = LUMP_ENTITIES;
|
|
||||||
srclumps[1].lumpnumber = LUMP_PLANES;
|
|
||||||
}
|
|
||||||
|
|
||||||
// loading base lumps
|
// loading base lumps
|
||||||
for( i = 0; i < ARRAYSIZE( srclumps ); i++ )
|
for( i = 0; i < ARRAYSIZE( srclumps ); i++ )
|
||||||
Mod_LoadLump( mod_base, &srclumps[i], &worldstats[i], flags );
|
Mod_LoadLump( mod_base, &srclumps[i], &worldstats[i], flags );
|
||||||
|
|
|
@ -148,7 +148,7 @@ void Mod_FreeUnused( void );
|
||||||
// mod_bmodel.c
|
// mod_bmodel.c
|
||||||
//
|
//
|
||||||
void Mod_LoadBrushModel( model_t *mod, const void *buffer, qboolean *loaded );
|
void Mod_LoadBrushModel( model_t *mod, const void *buffer, qboolean *loaded );
|
||||||
qboolean Mod_TestBmodelLumps( const char *name, const byte *mod_base, qboolean silent );
|
qboolean Mod_TestBmodelLumps( file_t *f, const char *name, const byte *mod_base, qboolean silent, dlump_t *entities );
|
||||||
qboolean Mod_HeadnodeVisible( mnode_t *node, const byte *visbits, int *lastleaf );
|
qboolean Mod_HeadnodeVisible( mnode_t *node, const byte *visbits, int *lastleaf );
|
||||||
int Mod_FatPVS( const vec3_t org, float radius, byte *visbuffer, int visbytes, qboolean merge, qboolean fullvis );
|
int Mod_FatPVS( const vec3_t org, float radius, byte *visbuffer, int visbytes, qboolean merge, qboolean fullvis );
|
||||||
qboolean Mod_BoxVisible( const vec3_t mins, const vec3_t maxs, const byte *visbits );
|
qboolean Mod_BoxVisible( const vec3_t mins, const vec3_t maxs, const byte *visbits );
|
||||||
|
@ -182,9 +182,6 @@ qboolean Mod_GetStudioBounds( const char *name, vec3_t mins, vec3_t maxs );
|
||||||
void Mod_StudioGetAttachment( const edict_t *e, int iAttachment, float *org, float *ang );
|
void Mod_StudioGetAttachment( const edict_t *e, int iAttachment, float *org, float *ang );
|
||||||
void Mod_GetBonePosition( const edict_t *e, int iBone, float *org, float *ang );
|
void Mod_GetBonePosition( const edict_t *e, int iBone, float *org, float *ang );
|
||||||
hull_t *Mod_HullForStudio( model_t *m, float frame, int seq, vec3_t ang, vec3_t org, vec3_t size, byte *pcnt, byte *pbl, int *hitboxes, edict_t *ed );
|
hull_t *Mod_HullForStudio( model_t *m, float frame, int seq, vec3_t ang, vec3_t org, vec3_t size, byte *pcnt, byte *pbl, int *hitboxes, edict_t *ed );
|
||||||
void R_StudioSlerpBones( int numbones, vec4_t q1[], float pos1[][3], vec4_t q2[], float pos2[][3], float s );
|
|
||||||
void R_StudioCalcBoneQuaternion( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, vec4_t q );
|
|
||||||
void R_StudioCalcBonePosition( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, vec3_t adj, vec3_t pos );
|
|
||||||
void *R_StudioGetAnim( studiohdr_t *m_pStudioHeader, model_t *m_pSubModel, mstudioseqdesc_t *pseqdesc );
|
void *R_StudioGetAnim( studiohdr_t *m_pStudioHeader, model_t *m_pSubModel, mstudioseqdesc_t *pseqdesc );
|
||||||
void Mod_StudioComputeBounds( void *buffer, vec3_t mins, vec3_t maxs, qboolean ignore_sequences );
|
void Mod_StudioComputeBounds( void *buffer, vec3_t mins, vec3_t maxs, qboolean ignore_sequences );
|
||||||
int Mod_HitgroupForStudioHull( int index );
|
int Mod_HitgroupForStudioHull( int index );
|
||||||
|
|
|
@ -116,7 +116,7 @@ void Mod_ClearStudioCache( void )
|
||||||
AddToStudioCache
|
AddToStudioCache
|
||||||
====================
|
====================
|
||||||
*/
|
*/
|
||||||
void Mod_AddToStudioCache( float frame, int sequence, vec3_t angles, vec3_t origin, vec3_t size, byte *pcontroller, byte *pblending, model_t *model, hull_t *hull, int numhitboxes )
|
static void Mod_AddToStudioCache( float frame, int sequence, vec3_t angles, vec3_t origin, vec3_t size, byte *pcontroller, byte *pblending, model_t *model, hull_t *hull, int numhitboxes )
|
||||||
{
|
{
|
||||||
mstudiocache_t *pCache;
|
mstudiocache_t *pCache;
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ void Mod_AddToStudioCache( float frame, int sequence, vec3_t angles, vec3_t orig
|
||||||
CheckStudioCache
|
CheckStudioCache
|
||||||
====================
|
====================
|
||||||
*/
|
*/
|
||||||
mstudiocache_t *Mod_CheckStudioCache( model_t *model, float frame, int sequence, vec3_t angles, vec3_t origin, vec3_t size, byte *controller, byte *blending )
|
static mstudiocache_t *Mod_CheckStudioCache( model_t *model, float frame, int sequence, vec3_t angles, vec3_t origin, vec3_t size, byte *controller, byte *blending )
|
||||||
{
|
{
|
||||||
mstudiocache_t *pCached;
|
mstudiocache_t *pCached;
|
||||||
int i;
|
int i;
|
||||||
|
@ -204,7 +204,7 @@ mstudiocache_t *Mod_CheckStudioCache( model_t *model, float frame, int sequence,
|
||||||
SetStudioHullPlane
|
SetStudioHullPlane
|
||||||
====================
|
====================
|
||||||
*/
|
*/
|
||||||
void Mod_SetStudioHullPlane( int planenum, int bone, int axis, float offset, const vec3_t size )
|
static void Mod_SetStudioHullPlane( int planenum, int bone, int axis, float offset, const vec3_t size )
|
||||||
{
|
{
|
||||||
mplane_t *pl = &studio_planes[planenum];
|
mplane_t *pl = &studio_planes[planenum];
|
||||||
|
|
||||||
|
@ -397,196 +397,6 @@ static void Mod_StudioCalcRotations( int boneused[], int numbones, const byte *p
|
||||||
if( pseqdesc->motiontype & STUDIO_Z ) pos[pseqdesc->motionbone][2] = 0.0f;
|
if( pseqdesc->motiontype & STUDIO_Z ) pos[pseqdesc->motionbone][2] = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
====================
|
|
||||||
StudioCalcBoneQuaternion
|
|
||||||
|
|
||||||
====================
|
|
||||||
*/
|
|
||||||
void R_StudioCalcBoneQuaternion( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, vec4_t q )
|
|
||||||
{
|
|
||||||
vec3_t angles1;
|
|
||||||
vec3_t angles2;
|
|
||||||
int j, k;
|
|
||||||
|
|
||||||
for( j = 0; j < 3; j++ )
|
|
||||||
{
|
|
||||||
if( !panim || panim->offset[j+3] == 0 )
|
|
||||||
{
|
|
||||||
angles2[j] = angles1[j] = pbone->value[j+3]; // default;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mstudioanimvalue_t *panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j+3]);
|
|
||||||
|
|
||||||
k = frame;
|
|
||||||
|
|
||||||
// debug
|
|
||||||
if( panimvalue->num.total < panimvalue->num.valid )
|
|
||||||
k = 0;
|
|
||||||
|
|
||||||
// find span of values that includes the frame we want
|
|
||||||
while( panimvalue->num.total <= k )
|
|
||||||
{
|
|
||||||
k -= panimvalue->num.total;
|
|
||||||
panimvalue += panimvalue->num.valid + 1;
|
|
||||||
|
|
||||||
// debug
|
|
||||||
if( panimvalue->num.total < panimvalue->num.valid )
|
|
||||||
k = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// bah, missing blend!
|
|
||||||
if( panimvalue->num.valid > k )
|
|
||||||
{
|
|
||||||
angles1[j] = panimvalue[k+1].value;
|
|
||||||
|
|
||||||
if( panimvalue->num.valid > k + 1 )
|
|
||||||
{
|
|
||||||
angles2[j] = panimvalue[k+2].value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if( panimvalue->num.total > k + 1 )
|
|
||||||
angles2[j] = angles1[j];
|
|
||||||
else angles2[j] = panimvalue[panimvalue->num.valid+2].value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
angles1[j] = panimvalue[panimvalue->num.valid].value;
|
|
||||||
if( panimvalue->num.total > k + 1 )
|
|
||||||
angles2[j] = angles1[j];
|
|
||||||
else angles2[j] = panimvalue[panimvalue->num.valid+2].value;
|
|
||||||
}
|
|
||||||
|
|
||||||
angles1[j] = pbone->value[j+3] + angles1[j] * pbone->scale[j+3];
|
|
||||||
angles2[j] = pbone->value[j+3] + angles2[j] * pbone->scale[j+3];
|
|
||||||
}
|
|
||||||
|
|
||||||
if( pbone->bonecontroller[j+3] != -1 && adj != NULL )
|
|
||||||
{
|
|
||||||
angles1[j] += adj[pbone->bonecontroller[j+3]];
|
|
||||||
angles2[j] += adj[pbone->bonecontroller[j+3]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !VectorCompare( angles1, angles2 ))
|
|
||||||
{
|
|
||||||
vec4_t q1, q2;
|
|
||||||
|
|
||||||
AngleQuaternion( angles1, q1, true );
|
|
||||||
AngleQuaternion( angles2, q2, true );
|
|
||||||
QuaternionSlerp( q1, q2, s, q );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AngleQuaternion( angles1, q, true );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
====================
|
|
||||||
StudioCalcBonePosition
|
|
||||||
|
|
||||||
====================
|
|
||||||
*/
|
|
||||||
void R_StudioCalcBonePosition( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, vec3_t pos )
|
|
||||||
{
|
|
||||||
vec3_t origin1;
|
|
||||||
vec3_t origin2;
|
|
||||||
int j, k;
|
|
||||||
|
|
||||||
for( j = 0; j < 3; j++ )
|
|
||||||
{
|
|
||||||
if( !panim || panim->offset[j] == 0 )
|
|
||||||
{
|
|
||||||
origin2[j] = origin1[j] = pbone->value[j]; // default;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mstudioanimvalue_t *panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j]);
|
|
||||||
|
|
||||||
k = frame;
|
|
||||||
|
|
||||||
// debug
|
|
||||||
if( panimvalue->num.total < panimvalue->num.valid )
|
|
||||||
k = 0;
|
|
||||||
|
|
||||||
// find span of values that includes the frame we want
|
|
||||||
while( panimvalue->num.total <= k )
|
|
||||||
{
|
|
||||||
k -= panimvalue->num.total;
|
|
||||||
panimvalue += panimvalue->num.valid + 1;
|
|
||||||
|
|
||||||
// debug
|
|
||||||
if( panimvalue->num.total < panimvalue->num.valid )
|
|
||||||
k = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// bah, missing blend!
|
|
||||||
if( panimvalue->num.valid > k )
|
|
||||||
{
|
|
||||||
origin1[j] = panimvalue[k+1].value;
|
|
||||||
|
|
||||||
if( panimvalue->num.valid > k + 1 )
|
|
||||||
{
|
|
||||||
origin2[j] = panimvalue[k+2].value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if( panimvalue->num.total > k + 1 )
|
|
||||||
origin2[j] = origin1[j];
|
|
||||||
else origin2[j] = panimvalue[panimvalue->num.valid+2].value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
origin1[j] = panimvalue[panimvalue->num.valid].value;
|
|
||||||
if( panimvalue->num.total > k + 1 )
|
|
||||||
origin2[j] = origin1[j];
|
|
||||||
else origin2[j] = panimvalue[panimvalue->num.valid+2].value;
|
|
||||||
}
|
|
||||||
|
|
||||||
origin1[j] = pbone->value[j] + origin1[j] * pbone->scale[j];
|
|
||||||
origin2[j] = pbone->value[j] + origin2[j] * pbone->scale[j];
|
|
||||||
}
|
|
||||||
|
|
||||||
if( pbone->bonecontroller[j] != -1 && adj != NULL )
|
|
||||||
{
|
|
||||||
origin1[j] += adj[pbone->bonecontroller[j]];
|
|
||||||
origin2[j] += adj[pbone->bonecontroller[j]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !VectorCompare( origin1, origin2 ))
|
|
||||||
{
|
|
||||||
VectorLerp( origin1, s, origin2, pos );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
VectorCopy( origin1, pos );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
====================
|
|
||||||
StudioSlerpBones
|
|
||||||
|
|
||||||
====================
|
|
||||||
*/
|
|
||||||
void R_StudioSlerpBones( int numbones, vec4_t q1[], float pos1[][3], vec4_t q2[], float pos2[][3], float s )
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
s = bound( 0.0f, s, 1.0f );
|
|
||||||
|
|
||||||
for( i = 0; i < numbones; i++ )
|
|
||||||
{
|
|
||||||
QuaternionSlerp( q1[i], q2[i], s, q1[i] );
|
|
||||||
VectorLerp( pos1[i], s, pos2[i], pos1[i] );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
====================
|
====================
|
||||||
|
@ -823,7 +633,7 @@ int Mod_HitgroupForStudioHull( int index )
|
||||||
StudioBoundVertex
|
StudioBoundVertex
|
||||||
====================
|
====================
|
||||||
*/
|
*/
|
||||||
void Mod_StudioBoundVertex( vec3_t mins, vec3_t maxs, int *numverts, const vec3_t vertex )
|
static void Mod_StudioBoundVertex( vec3_t mins, vec3_t maxs, int *numverts, const vec3_t vertex )
|
||||||
{
|
{
|
||||||
if((*numverts) == 0 )
|
if((*numverts) == 0 )
|
||||||
ClearBounds( mins, maxs );
|
ClearBounds( mins, maxs );
|
||||||
|
@ -837,7 +647,7 @@ void Mod_StudioBoundVertex( vec3_t mins, vec3_t maxs, int *numverts, const vec3_
|
||||||
StudioAccumulateBoneVerts
|
StudioAccumulateBoneVerts
|
||||||
====================
|
====================
|
||||||
*/
|
*/
|
||||||
void Mod_StudioAccumulateBoneVerts( vec3_t mins, vec3_t maxs, int *numverts, vec3_t bone_mins, vec3_t bone_maxs, int *numbones )
|
static void Mod_StudioAccumulateBoneVerts( vec3_t mins, vec3_t maxs, int *numverts, vec3_t bone_mins, vec3_t bone_maxs, int *numbones )
|
||||||
{
|
{
|
||||||
vec3_t delta;
|
vec3_t delta;
|
||||||
vec3_t point;
|
vec3_t point;
|
||||||
|
@ -1009,7 +819,7 @@ static int Mod_StudioBodyVariations( model_t *mod )
|
||||||
R_StudioLoadHeader
|
R_StudioLoadHeader
|
||||||
=================
|
=================
|
||||||
*/
|
*/
|
||||||
studiohdr_t *R_StudioLoadHeader( model_t *mod, const void *buffer )
|
static studiohdr_t *R_StudioLoadHeader( model_t *mod, const void *buffer )
|
||||||
{
|
{
|
||||||
byte *pin;
|
byte *pin;
|
||||||
studiohdr_t *phdr;
|
studiohdr_t *phdr;
|
||||||
|
|
|
@ -17,7 +17,6 @@ GNU General Public License for more details.
|
||||||
#include "protocol.h"
|
#include "protocol.h"
|
||||||
#include "net_buffer.h"
|
#include "net_buffer.h"
|
||||||
#include "xash3d_mathlib.h"
|
#include "xash3d_mathlib.h"
|
||||||
|
|
||||||
//#define DEBUG_NET_MESSAGES_SEND
|
//#define DEBUG_NET_MESSAGES_SEND
|
||||||
//#define DEBUG_NET_MESSAGES_READ
|
//#define DEBUG_NET_MESSAGES_READ
|
||||||
|
|
||||||
|
@ -26,11 +25,69 @@ GNU General Public License for more details.
|
||||||
// gives a 33% speedup in WriteUBitLong.
|
// gives a 33% speedup in WriteUBitLong.
|
||||||
static dword BitWriteMasks[32][33];
|
static dword BitWriteMasks[32][33];
|
||||||
static dword ExtraMasks[32];
|
static dword ExtraMasks[32];
|
||||||
|
const char *svc_strings[svc_lastmsg+1] =
|
||||||
unsigned short MSG_BigShort( unsigned short swap )
|
|
||||||
{
|
{
|
||||||
return (swap >> 8)|(swap << 8);
|
"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",
|
||||||
|
"svc_exec",
|
||||||
|
};
|
||||||
|
|
||||||
void MSG_InitMasks( void )
|
void MSG_InitMasks( void )
|
||||||
{
|
{
|
||||||
|
|
|
@ -63,7 +63,15 @@ void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove );
|
||||||
_inline int MSG_TellBit( sizebuf_t *sb ) { return sb->iCurBit; }
|
_inline int MSG_TellBit( sizebuf_t *sb ) { return sb->iCurBit; }
|
||||||
_inline const char *MSG_GetName( sizebuf_t *sb ) { return sb->pDebugName; }
|
_inline const char *MSG_GetName( sizebuf_t *sb ) { return sb->pDebugName; }
|
||||||
qboolean MSG_CheckOverflow( sizebuf_t *sb );
|
qboolean MSG_CheckOverflow( sizebuf_t *sb );
|
||||||
unsigned short MSG_BigShort( unsigned short swap );
|
|
||||||
|
#if XASH_BIG_ENDIAN
|
||||||
|
#define MSG_BigShort( x ) ( x )
|
||||||
|
#else
|
||||||
|
static inline uint16_t MSG_BigShort( const uint16_t x )
|
||||||
|
{
|
||||||
|
return (x >> 8) | (x << 8);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// init writing
|
// init writing
|
||||||
void MSG_StartWriting( sizebuf_t *sb, void *pData, int nBytes, int iStartBit, int nBits );
|
void MSG_StartWriting( sizebuf_t *sb, void *pData, int nBytes, int iStartBit, int nBits );
|
||||||
|
|
|
@ -414,6 +414,7 @@ void Netchan_ClearFragbufs( fragbuf_t **ppbuf )
|
||||||
while( buf )
|
while( buf )
|
||||||
{
|
{
|
||||||
n = buf->next;
|
n = buf->next;
|
||||||
|
Mem_Free( buf->frag_message_buf );
|
||||||
Mem_Free( buf );
|
Mem_Free( buf );
|
||||||
buf = n;
|
buf = n;
|
||||||
}
|
}
|
||||||
|
@ -535,12 +536,13 @@ Netchan_AllocFragbuf
|
||||||
|
|
||||||
==============================
|
==============================
|
||||||
*/
|
*/
|
||||||
fragbuf_t *Netchan_AllocFragbuf( void )
|
fragbuf_t *Netchan_AllocFragbuf( int fragment_size )
|
||||||
{
|
{
|
||||||
fragbuf_t *buf;
|
fragbuf_t *buf;
|
||||||
|
|
||||||
buf = (fragbuf_t *)Mem_Calloc( net_mempool, sizeof( fragbuf_t ));
|
buf = (fragbuf_t *)Mem_Calloc( net_mempool, sizeof( fragbuf_t ));
|
||||||
MSG_Init( &buf->frag_message, "Frag Message", buf->frag_message_buf, sizeof( buf->frag_message_buf ));
|
buf->frag_message_buf = (byte *)Mem_Calloc( net_mempool, fragment_size );
|
||||||
|
MSG_Init( &buf->frag_message, "Frag Message", buf->frag_message_buf, fragment_size );
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
@ -736,7 +738,7 @@ static void Netchan_CreateFragments_( netchan_t *chan, sizebuf_t *msg )
|
||||||
bytes = Q_min( remaining, chunksize );
|
bytes = Q_min( remaining, chunksize );
|
||||||
remaining -= bytes;
|
remaining -= bytes;
|
||||||
|
|
||||||
buf = Netchan_AllocFragbuf();
|
buf = Netchan_AllocFragbuf( bytes );
|
||||||
buf->bufferid = bufferid++;
|
buf->bufferid = bufferid++;
|
||||||
|
|
||||||
// Copy in data
|
// Copy in data
|
||||||
|
@ -803,7 +805,7 @@ fragbuf_t *Netchan_FindBufferById( fragbuf_t **pplist, int id, qboolean allocate
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
// create new entry
|
// create new entry
|
||||||
pnewbuf = Netchan_AllocFragbuf();
|
pnewbuf = Netchan_AllocFragbuf( NET_MAX_FRAGMENT );
|
||||||
pnewbuf->bufferid = id;
|
pnewbuf->bufferid = id;
|
||||||
Netchan_AddBufferToList( pplist, pnewbuf );
|
Netchan_AddBufferToList( pplist, pnewbuf );
|
||||||
|
|
||||||
|
@ -894,7 +896,7 @@ void Netchan_CreateFileFragmentsFromBuffer( netchan_t *chan, const char *filenam
|
||||||
{
|
{
|
||||||
send = Q_min( remaining, chunksize );
|
send = Q_min( remaining, chunksize );
|
||||||
|
|
||||||
buf = Netchan_AllocFragbuf();
|
buf = Netchan_AllocFragbuf( send );
|
||||||
buf->bufferid = bufferid++;
|
buf->bufferid = bufferid++;
|
||||||
|
|
||||||
// copy in data
|
// copy in data
|
||||||
|
@ -978,8 +980,12 @@ int Netchan_CreateFileFragments( netchan_t *chan, const char *filename )
|
||||||
if( compressedFileTime >= fileTime )
|
if( compressedFileTime >= fileTime )
|
||||||
{
|
{
|
||||||
// if compressed file already created and newer than source
|
// if compressed file already created and newer than source
|
||||||
if( FS_FileSize( compressedfilename, false ) != -1 )
|
fs_offset_t compressedSize = FS_FileSize( compressedfilename, false );
|
||||||
|
if( compressedSize != -1 )
|
||||||
|
{
|
||||||
bCompressed = true;
|
bCompressed = true;
|
||||||
|
filesize = compressedSize;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1009,7 +1015,7 @@ int Netchan_CreateFileFragments( netchan_t *chan, const char *filename )
|
||||||
{
|
{
|
||||||
send = Q_min( remaining, chunksize );
|
send = Q_min( remaining, chunksize );
|
||||||
|
|
||||||
buf = Netchan_AllocFragbuf();
|
buf = Netchan_AllocFragbuf( send );
|
||||||
buf->bufferid = bufferid++;
|
buf->bufferid = bufferid++;
|
||||||
|
|
||||||
// copy in data
|
// copy in data
|
||||||
|
@ -1188,6 +1194,13 @@ qboolean Netchan_CopyFileFragments( netchan_t *chan, sizebuf_t *msg )
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( filename[0] != '!' )
|
||||||
|
{
|
||||||
|
string temp_filename;
|
||||||
|
Q_snprintf( temp_filename, sizeof( temp_filename ), "downloaded/%s", filename );
|
||||||
|
Q_strncpy( filename, temp_filename, sizeof( filename ));
|
||||||
|
}
|
||||||
|
|
||||||
Q_strncpy( chan->incomingfilename, filename, sizeof( chan->incomingfilename ));
|
Q_strncpy( chan->incomingfilename, filename, sizeof( chan->incomingfilename ));
|
||||||
|
|
||||||
if( filename[0] != '!' && FS_FileExists( filename, false ))
|
if( filename[0] != '!' && FS_FileExists( filename, false ))
|
||||||
|
@ -1576,6 +1589,7 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memset( send_buf, 0, sizeof( send_buf ));
|
||||||
MSG_Init( &send, "NetSend", send_buf, sizeof( send_buf ));
|
MSG_Init( &send, "NetSend", send_buf, sizeof( send_buf ));
|
||||||
|
|
||||||
// prepare the packet header
|
// prepare the packet header
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue