mirror of
https://github.com/FWGS/xash3d-fwgs.git
synced 2026-08-05 19:45:05 +08:00
Compare commits
1 Commits
continuous
...
apidocs
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
03a9d08053 |
@@ -1,10 +1,10 @@
|
||||
task:
|
||||
name: freebsd-14-amd64
|
||||
freebsd_instance:
|
||||
image_family: freebsd-14-2
|
||||
image_family: freebsd-14-0
|
||||
setup_script:
|
||||
- pkg update
|
||||
- pkg install -y pkgconf git sdl2 python fontconfig libvorbis opusfile bzip2
|
||||
- pkg install -y pkgconf git sdl2 python fontconfig opus
|
||||
- git submodule update --init --recursive
|
||||
test_script:
|
||||
- ./scripts/cirrus/build_freebsd.sh dedicated
|
||||
@@ -16,7 +16,7 @@ task:
|
||||
image_family: freebsd-15-0-snap
|
||||
setup_script:
|
||||
- pkg update
|
||||
- pkg install -y pkgconf git sdl2 python fontconfig libvorbis opusfile bzip2
|
||||
- pkg install -y pkgconf git sdl2 python fontconfig opus
|
||||
- git submodule update --init --recursive
|
||||
test_script:
|
||||
- ./scripts/cirrus/build_freebsd.sh dedicated
|
||||
|
||||
2
.github/workflows/c-cpp.yml
vendored
2
.github/workflows/c-cpp.yml
vendored
@@ -67,9 +67,7 @@ jobs:
|
||||
targetarch: amd64
|
||||
env:
|
||||
SDL_VERSION: 2.30.11
|
||||
FFMPEG_VERSION: 7.1
|
||||
GH_CPU_ARCH: ${{ matrix.targetarch }}
|
||||
GH_CPU_OS: ${{ matrix.targetos }}
|
||||
GH_CROSSCOMPILING: ${{ matrix.cross }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
|
||||
1
3rdparty/extras/wscript
vendored
1
3rdparty/extras/wscript
vendored
@@ -25,4 +25,5 @@ def build(bld):
|
||||
name = 'extras.pk3',
|
||||
files = srcdir.ant_glob('**/*'),
|
||||
relative_to = srcdir,
|
||||
compresslevel = 0,
|
||||
install_path = install_path)
|
||||
|
||||
2
3rdparty/mainui
vendored
2
3rdparty/mainui
vendored
Submodule 3rdparty/mainui updated: 695ea1be2e...734a6d1ca2
5
Documentation/api/README.md
Normal file
5
Documentation/api/README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# Welcome to the GoldSource API docs
|
||||
|
||||
This documentation is an attempt on explaining inner workings of Valve's Half-Life (R) engine, also known as GoldSource, from programmer's perspective. A deep knowledge of Quake (NQ, QW and Q2) engines is required.
|
||||
|
||||
Everything discussed here is it's author assumption based on studying Xash3D source code and reverse engineering Half-Life mods. Xash3D API extensions is out of scope of this document and will be explained separately.
|
||||
20
Documentation/api/client/01-init.md
Normal file
20
Documentation/api/client/01-init.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# Initializing client.dll
|
||||
|
||||
`client.dll` has got multiple ways of initialization during it's life but we will go through the simplest and the most common route here.
|
||||
|
||||
Here we expect that reader has knowledge of loading dynamic shared objects on their platform. On Windows it's done through `LoadLibrary`/`GetProcAddress`/`FreeLibrary` functions, on POSIX-complaint systems it's done through `dlopen`/`dlsym`/`dlclose` functions.
|
||||
|
||||
## client.dll lifetime
|
||||
|
||||
`client.dll` is expected to be loaded during client initialization and unloaded on client shutdown. Essentially, in non-dedicated builds, it always exists during the engine lifetime. Judging by the API, it might look like `client.dll` might be safely unloaded and loaded again, for example for implementing classic `Change Game` functionality from WON versions of Half-Life, but in practice it's nearly impossible to do this clean in standard and portable manner. If you want to implement changing games, consider using `execv`-like functions.
|
||||
|
||||
## client.dll exported functions
|
||||
|
||||
The first thing you should do, is to acquire pointers to all exported functions, which you can find in the next chapter. Some of them are optional, and might not present in the `client.dll`, and will be labeled as such.
|
||||
|
||||
## client.dll initialization process
|
||||
|
||||
1. The first function you call is `Initialize` function, which lets `client.dll` to store a copy of an engine API functions.
|
||||
2. Since SDK 2.0, `client.dll` have player movement code in it, which you must initialize through `HUD_PlayerMoveInit` function. `client.dll` might want to override player hulls, which can be grabbed with `HUD_GetHullBounds` function.
|
||||
3. HUD functionality must be started up with `HUD_Init` function and can be de-initialized with `HUD_Shutdown` export function.
|
||||
4. And finally, SDK 2.1 brings studio model renderer, which has separate set of API functions, which must be initialized with `HUD_GetStudioModelInterface` function.
|
||||
286
Documentation/api/client/02-exports.md
Normal file
286
Documentation/api/client/02-exports.md
Normal file
@@ -0,0 +1,286 @@
|
||||
# List of client.dll exported functions
|
||||
|
||||
### `int Initialize( cl_enginefuncs_t *enginefuncs, int version )`
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This function is only called once.
|
||||
|
||||
Called after loading DLL and exports engine API to the `client.dll`.
|
||||
* `enginefuncs` must be set to a pointer to a struct filled with engine function pointers, it will be described in next chapters.
|
||||
* `version` must be always set to `7`. (HLSDK 1.0 uses version `6`, and is binary incompatible with `7`).
|
||||
Return value: `0` on error, otherwise success.
|
||||
|
||||
### `void HUD_PlayerMoveInit( struct playermove_s *ppmove, int server )`
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This function is only called once.
|
||||
|
||||
Called on player movement prediction initialization, before HUD. In GoldSrc, engine only runs prediction loop, the players physics are implemented in `client.dll`.
|
||||
* `ppmove` must be set to a pointer to a client instance of player movement structure, which also exports it's own API and will be discussed in the next chapters.
|
||||
* `server` must be always set to `0` on client side.
|
||||
This function is called only once.
|
||||
|
||||
### `void HUD_Init( void )`
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This function is only called once.
|
||||
|
||||
Called to initialize the HUD. At this moment engine should be ready to register new commands, console variables and user messages. No rendering or loading graphics done at this moment.
|
||||
|
||||
### `int HUD_GetStudioModelInterface( int version, struct r_studio_interface_s **ppinterface, struct engine_studio_api_s *pstudio )`
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This function is only called once.
|
||||
|
||||
This function is called after initializing HUD and exports studio model interface to the `client.dll`.
|
||||
* `version` must be always set to `1`.
|
||||
* `ppinterface` will be set by `client.dll` to a pointer to `r_studio_interface_s` structure.
|
||||
* `pstudio` must be set to a pointer to `engine_studio_api_s` structure. The studio model interface will be discussed in the next chapters.
|
||||
Return value: `0` on error, otherwise success.
|
||||
|
||||
### `void HUD_Shutdown( void )`
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This function is only called once.
|
||||
|
||||
Called at client shutdown.
|
||||
|
||||
### `int HUD_GetHullBounds( int hull, vec3_t mins, vec3_t maxs )`
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This function is only called once.
|
||||
|
||||
Called by the engine after `HUD_PlayerMoveInit` to let `client.dll` override hull bounds used for in player movement prediction.
|
||||
|
||||
* `hull` is the hull index (0: player standing, 1: player crouched, 2: point hull, 3: large hull).
|
||||
* `mins` will contain hull mins.
|
||||
* `maxs` will contain hull maxs.
|
||||
Return value: if 0, don't override this hull and stop reading, non-zero means hull is valid _and_ there is more.
|
||||
|
||||
> [!NOTE]
|
||||
> This function is broken in most implementations. It might return non-zero value, but don't write anything to the `mins` and `maxs` vectors, so be prepared to have some default values.
|
||||
|
||||
### `int HUD_VidInit( void )`
|
||||
|
||||
Called when client receives `svc_serverdata` message. It is called before any parsing of that message is done, thus the state is preserved from the previous connection. It lets `client.dll` to re-initialize graphics, if required. At this point, engine is expected to have video subsystem running, but no rendering is done here.
|
||||
|
||||
### `int HUD_Redraw( float flTime, int intermission )`
|
||||
|
||||
Called each frame to redraw the HUD. Only 2D is drawn here.
|
||||
* `flTime` must be set to `cl.time`, i.e. synchronized with server.
|
||||
* `intermission` must be set to `1` during intermission (set through `svc_intermission` message), otherwise it's set to `0`.
|
||||
Return value: ignored.
|
||||
|
||||
### `void HUD_Reset( void )`
|
||||
|
||||
Called on demo recording or playback start and stop.
|
||||
|
||||
### `int HUD_UpdateClientData( client_data_t *cdata, float flTime )`
|
||||
|
||||
Called each frame after taking input.
|
||||
* `cdata` contains pointer to `client_data_t` structure, populated by engine.
|
||||
* `flTime` must be set to `cl.time`, i.e. synchronized with server.
|
||||
Return value: if non-zero, will override engine viewangles and FOV value.
|
||||
|
||||
### `void HUD_PlayerMove( struct playermove_s *pmove, int server )`
|
||||
|
||||
When prediction is enabled, use this function to run player movement prediction. Note that this correlates to QW/Q2's prediction mechanism. It does not include weapon prediction.
|
||||
|
||||
* `pmove` is a pointer to playermove object
|
||||
* `server` must be always set to `0`
|
||||
|
||||
### `char HUD_PlayerMoveTexture( char *name )`
|
||||
|
||||
Not used in the engine.
|
||||
|
||||
### `int HUD_ConnectionlessPacket( const netadr_t *from, const char *args, char *response_buffer, int *response_buffer_size )`
|
||||
|
||||
Called by the engine on unknown connectionless packets. Lets `client.dll` and `server.dll` have custom query protocol.
|
||||
|
||||
* `from` is set to network address where this packet is coming from.
|
||||
* `args` raw network buffer, minus the connectionless packet header (0xFFFFFFFF).
|
||||
* `response_buffer` set by `client.dll` if there is a response.
|
||||
* `response_buffer_size` is initialized by the engine with buffer maximum size. Set by `client.dll` if there is a response.
|
||||
Return value: non-zero if handled.
|
||||
|
||||
### `void HUD_Frame( double time )`
|
||||
|
||||
Called each frame after sending command to the remote server. No rendering is normally done in this function.
|
||||
|
||||
* `time` is the local delta time between previous and this frame (i.e. `host.frametime`)
|
||||
|
||||
### `void HUD_PostRunCmd( struct local_state_s *from, struct local_state_s *to, usercmd_t *cmd, int runfuncs, double time, unsigned int random_seed )`
|
||||
|
||||
Always called after `HUD_PlayerMove`, even if movement prediction is disabled. Used for weapon prediction stuff.
|
||||
|
||||
* `from` is a pointer to `local_state_s` object of the previous predicted frame
|
||||
* `to` is a pointer to `local_state_s` object of this current frame
|
||||
* `cmd` is current user command
|
||||
* `runfuncs` is set to `1` if this frame was never predicted before, and to `0` if it is being predicted again
|
||||
* `random_seed` is set to `incoming_acknowledged` plus number of predicted frames starting with `1`. This way it's synchronized between client and server.
|
||||
|
||||
### `int HUD_Key_Event( int down, int key, const char *current_binding )`
|
||||
|
||||
Called on keyboard event.
|
||||
|
||||
* `down` is set to `1` if key is being pressed or set to `0` on being released.
|
||||
* `key` is set to the key number. The key IDs are predefined.
|
||||
* `current_binding` is set to a null-terminated string with commands bound to this key
|
||||
Return value: `0` if `client.dll` wants engine to ignore that key.
|
||||
|
||||
### `int HUD_AddEntity( int type, struct cl_entity_s *ent, const char *modelname )`
|
||||
|
||||
Called before adding entity to the rendering list.
|
||||
|
||||
* `type` is set to an entity type, see `entity_state_t::entityType`
|
||||
* `ent` is a pointer to `cl_entity_t` object.
|
||||
* `modelname` is a null-terminated string with that entity model name.
|
||||
Return value: `0` if `client.dll` wants engine to not draw this entity.
|
||||
|
||||
### `void HUD_CreateEntities( void )`
|
||||
|
||||
Called each frame after all network entities (including players) are linked to let `client.dll` spawn client-side entities.
|
||||
|
||||
### `void HUD_StudioEvent( const struct mstudioevent_s *event, const struct cl_entity_s *ent )`
|
||||
|
||||
Studio models have events tied to the frame, on which engine calls this function.
|
||||
|
||||
* `event` is a pointer to a studio event object
|
||||
* `ent` is a pointer to a client entity object
|
||||
|
||||
### `void HUD_TxferLocalOverrides( struct entity_state_s *state, const struct clientdata_s *client )`
|
||||
|
||||
When client processes entity updates, for local client it might be truncated, don't have enough precision, miss some critical info, so engine calls this function as `client.dll` might choose to use client data came from `svc_clientdata` message. Note that it is called on raw, non-interpolated networked entity state.
|
||||
|
||||
* `state` is a pointer to the local client entity state coming from the network
|
||||
* `client` is a pointer to local client data object
|
||||
|
||||
### `void HUD_ProcessPlayerState( struct entity_state_s *dst, const struct entity_state_s *src )`
|
||||
|
||||
When client processes entity updates, it calls this function for player entities as `client.dll` might want to override some data or fill the missing parts, but usually it just copies from `src` to `dst`.
|
||||
|
||||
* `src` is a target pointer to the player entity data (stored in frames, for example)
|
||||
* `dst` is a source pointer to the player entity data coming from network
|
||||
|
||||
### `void HUD_TxferPredictionData( struct entity_state_s *ps, const struct entity_state_s *pps, struct clientdata_s *pcd, const struct clientdata_s *ppcd, struct weapon_data_s *wd, const weapon_data_s *pwd )`
|
||||
|
||||
When client receives `svc_clientdata` message, this function is called before any parsing is done, so that the `client.dll` fills in data from prediction.
|
||||
|
||||
* `ps`, `pcd`, `wd` are pointers to current network frame data.
|
||||
* `pps`, `ppcd`, `pwd` are pointers to predicted frame data.
|
||||
|
||||
### `void HUD_TempEntUpdate( double frametime, double client_time, double cl_gravity, TEMPENTITY **ppTempEntFree, TEMPENTITY **ppTempEntActive, int ( *AddVisibleEntity )( cl_entity_t *pEntity ), void ( *TempEntPlaySound)( TEMPENTITY *pTemp, float damp ))`
|
||||
|
||||
Called each frame after network entities are processed and after `HUD_CreateEntities`, to let `client.dll` process temporary entities logic.
|
||||
|
||||
* `frametime` is the delta between `cl.time` and `cl.oldtime`, i.e. server time.
|
||||
* `client_time` is `cl.time`
|
||||
* `gravity` is the synchronized gravity value from the server
|
||||
* `ppTempEntFree` is a pointer to the head of linked list of free temp entities
|
||||
* `ppTempEntActive` is a pointer to the head of linked list of active temp entities
|
||||
* `AddVisibleEntity` is a pointer to function that lets `client.dll` add this entity to the rendering list.
|
||||
* `TempEntPlaySound` is a pointer to function that's called by `client.dll` when temp entity needs to play predefined hit sound. The `damp` argument of this argument only makes sound to NOT play, if it's zero or negative.
|
||||
|
||||
### `void HUD_DrawNormalTriangles( void )`
|
||||
|
||||
Called each rendering frame to let `client.dll` draw custom solid triangles through TriAPI or direct OpenGL calls.
|
||||
|
||||
### `void HUD_DrawTransparentTriangles( void )`
|
||||
|
||||
Called each rendering frame to let `client.dll` draw custom transparent triangles through TriAPI or direct OpenGL calls.
|
||||
|
||||
### `struct cl_entity_s *HUD_GetUserEntity( int index )`
|
||||
|
||||
Called by engine when beam start/end indices are negative, thus allowing attaching beams to a temporary or client-only entity.
|
||||
|
||||
* `index` is the fixed up entity index, as beam start/end indices encode real entity index in low 12 bits (i.e. `beament_start & 0xFFF`).
|
||||
|
||||
### `void Demo_ReadBuffer( int size, unsigned char *buffer )`
|
||||
|
||||
Called by engine on demo playback, if `client.dll` saved some custom data on demo recording prior.
|
||||
|
||||
* `size` is the size of buffer in bytes
|
||||
* `buffer` is the pointer to custom data stored by `client.dll` in demo
|
||||
|
||||
### `void CAM_Think( void )`
|
||||
|
||||
Called each frame before rendering starts to let `client.dll` run custom camera logic, like advanced thirdperson follow camera for example.
|
||||
|
||||
### `int CL_IsThirdPerson( void )`
|
||||
|
||||
Returns non-zero value if camera is in thirdperson mode, lets engine figure out whether add local client entity to the rendering list or not.
|
||||
|
||||
### `void CL_CameraOffset( vec3_t offset )`
|
||||
|
||||
Not used in the engine.
|
||||
|
||||
### `void CL_CreateMove( float frametime, usercmd_t *cmd, int active )`
|
||||
|
||||
Called when `usercmd_t` is being created to let `client.dll` record user commands before they are being sent over the network.
|
||||
|
||||
* `frametime` is the delta time between previous and current frames.
|
||||
* `cmd` is the pointer to `usercmd_t` object, where player's intentions and impulses are added.
|
||||
* `active` is set to `1` when client is finished signing on to the server (as movement commands are being sent even if client is not fully spawned yet).
|
||||
|
||||
### `void IN_ActivateMouse( void )`
|
||||
|
||||
Called from similarly named NQ/QW function.
|
||||
|
||||
### `void IN_DeactivateMouse( void )`
|
||||
|
||||
Called from similarly named NQ/QW function.
|
||||
|
||||
### `void IN_MouseEvent( int mstate )`
|
||||
|
||||
Called from similarly named NQ/QW function.
|
||||
|
||||
### `void IN_Accumulate( void )`
|
||||
|
||||
Called from similarly named NQ/QW function.
|
||||
|
||||
### `void IN_ClearStates( void )`
|
||||
|
||||
Called from similarly named NQ/QW function.
|
||||
|
||||
### `void V_CalcRefdef( struct ref_params_s *params )`
|
||||
|
||||
Called each frame before rendering starts. This is close to the similarly named function found in NQ/QW and lets `client.dll` to run custom view logic.
|
||||
|
||||
* `params` is the refdef parameters object. It is also used as return value and might request from the engine to not draw anything (by `onlyClientDraws` field) or to run this multiple times (by `nextview` field)
|
||||
|
||||
### `kbutton_t *KB_Find( const char *name )`
|
||||
|
||||
Called by engine to find extra keys and their state.
|
||||
|
||||
Only few are really used by the engine:
|
||||
* `in_mlook` for mouse look
|
||||
* `in_jlook` for joystick look
|
||||
* `in_graph` for net_graph toggle
|
||||
|
||||
Return value: returns pointer to `kbutton_t` if found. `kbutton_t` structure matches the same structure that can be found in NQ and QW.
|
||||
|
||||
### `void HUD_DirectorMessage( int size, void *buf )`
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This function is optional.
|
||||
|
||||
Called to notify `client.dll` about an `svc_director` message. This feature is used for HLTV, though mods use it to spawn text messages or execute commands (bypassing `svc_stufftext` filter in old `client.dll`) but `svc_director` message structure isn't enforced by engine, so it in theory mods might modify it for their own needs.
|
||||
|
||||
* `size` is the size of the payload
|
||||
* `buf` raw `svc_director` payload
|
||||
|
||||
### `void HUD_VoiceStatus( int entindex, qboolean talking )`
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This function is optional.
|
||||
|
||||
Called to notify `client.dll` about a client status of using voice chat.
|
||||
* `entindex` an entity index (client index plus one, because zero is always world). When set to -1, notifies `client.dll` about local client recording. When set to -2, notifies `client.dll` about a loopback (i.e. local client's voice message was sent to server and received back)
|
||||
* `talking` if true, this client is talking
|
||||
|
||||
### `void HUD_ChatInputPosition( int *x, int *y )`
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This function is optional.
|
||||
|
||||
When called, returns desired X and Y positions of chat box.
|
||||
9
Documentation/api/client/README.md
Normal file
9
Documentation/api/client/README.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# What is client.dll in GoldSource?
|
||||
|
||||
One of technical differences a programmer working with Quake engine might notice is the client.dll file. Historically, it appeared somewhere in between Alpha 0.52 and NetTest1 development and judging by Half-Life SDK 1.0 was meant to handle HUD rendering. The time moved forward, SDK 2.0 finalized `client.dll` API at version 7, added an in-game UI, custom input processing, player movement and weapon prediction, very basic rendering through TriAPI. SDK 2.1 added ability to re-define studio model rendering, and so on.
|
||||
|
||||
It somewhat resembles `cgame` module from Quake 3, but more crudely designed and sometimes feels like an afterthought, considering how many engine internal structures it exposes and the main point of incompatibilities with mods, which these days sometimes use `client.dll` as a way to inject custom rendering into the game.
|
||||
|
||||
In this document I will try to go through each step, letting you, dear reader, implement your own GoldSrc compatible API in your Quake fork, targetting vanilla Half-Life `client.dll` from latest update, which at the time of writing, is 25-th anniversary update.
|
||||
|
||||
Despite that we call it `client.dll`, since SDK 2.4 (unofficial naming, it's the first SDK Valve published on GitHub) it is considered portable and only has SDL2 and VGUI libraries in it's external dependences. It's only called this way to avoid possible misunderstandings with engine developers, who might interpret client as `cl_` prefixed part of Quake engine.
|
||||
120
Documentation/api/client/xx-structs.md
Normal file
120
Documentation/api/client/xx-structs.md
Normal file
@@ -0,0 +1,120 @@
|
||||
# `client.dll` shared structs and enums
|
||||
|
||||
GoldSource exposes a lot of structs to `client.dll`. Some of them are specific to `client.dll` and only used for passing data between engine and client, some of them are used in the engine everywhere, but still exposed in the public SDK. However, many mods rely on internal structs as well, and I will try to shed light on them as well.
|
||||
|
||||
When implementing them in C, consider the default to 32-bit systems alignment of 4 bytes and ILP32 data type model.
|
||||
|
||||
This file won't have API structs, for that, there should be separate chapters.
|
||||
|
||||
## Enums
|
||||
|
||||
### Entity types enum
|
||||
|
||||
This enum has no real name.
|
||||
|
||||
| Value | Description |
|
||||
|-------|-----------------|
|
||||
| `0` | Normal entities |
|
||||
| `1` | Players |
|
||||
| `2` | Temp entities |
|
||||
| `3` | Beams |
|
||||
| `4` | Fragmented entities. |
|
||||
|
||||
### edict->solid
|
||||
|
||||
It matches QuakeWorld definition.
|
||||
|
||||
## `client_data_t`
|
||||
|
||||
Used only to pass data to `client.dll` through `HUD_UpdateClientData`.
|
||||
|
||||
| Type | Name | Description |
|
||||
|----------|---------------|--------------------------------------------------------------|
|
||||
| `vec3_t` | `origin` | Local client origin. Cannot be changed by `client.dll` here. |
|
||||
| `vec3_t` | `viewangles` | Local client viewangles. This and next fields can be changed by `client.dll` |
|
||||
| `int` | `iWeaponBits` | Bit vector of weapons held by client. |
|
||||
| `float` | `fov` | Local client's field of view. |
|
||||
|
||||
## `netadr_t`
|
||||
|
||||
Matches Quake-2 structure with the similar name.
|
||||
|
||||
## `local_state_t`
|
||||
|
||||
Only consists of another structs. All of these structs are used to store prediction data, so one `local_state_t` for each predicted frame.
|
||||
|
||||
| Type | Name | Description |
|
||||
|---------------------|---------------|--------------------------------------|
|
||||
| `entity_state_t` | `playerstate` | Contains local player's entity state |
|
||||
| `clientdata_t` | `client` | Additional information about local client. _Do not get confused with `client_data_t`, note the underscore._ |
|
||||
| `weapon_data_t[64]` | `weapondata` | Array of 64 predictable weapons. |
|
||||
|
||||
## `entity_state_t`
|
||||
|
||||
This structure is similar to the one that can be found in QW, but contains much more data, though most of these fields are not used by the engine, but might be used by mods.
|
||||
|
||||
| Type | Name | Description |
|
||||
|-------------|----------------|------------------------------------------------------|
|
||||
| `int` | `entityType` | Entity type (see entity type enum above) |
|
||||
| `int` | `number` | Index of this entity on the server |
|
||||
| `float` | `msg_time` | Server time at which this entity had been updated |
|
||||
| `int` | `messagenum` | `parsecount` at which this entity had been updated |
|
||||
| `vec3_t` | `origin` | Non-interpolated entity position |
|
||||
| `vec3_t` | `angles` | Non-interpolated entity angles |
|
||||
| `int` | `modelindex` | Server model index |
|
||||
| `int` | `sequence` | Model animation sequence |
|
||||
| `int` | `frame` | Model animation frame |
|
||||
| `int` | `colormap` | Texture's top and bottom colors, like Quake |
|
||||
| `short` | `skin` | Texture number |
|
||||
| `short` | `solid` | `edict->solid` enum |
|
||||
| `int` | `effects` | Bitmask of entity effects |
|
||||
| `float` | `scale` | Entity scale value |
|
||||
| `byte` | `eflags` | |
|
||||
| `int` | `eflags` | |
|
||||
| `int` | `eflags` | |
|
||||
| `color24` | `eflags` | |
|
||||
| `int` | `eflags` | |
|
||||
| `int` | `eflags` | |
|
||||
| `float` | `eflags` | |
|
||||
| `float` | `eflags` | |
|
||||
| `int` | `eflags` | |
|
||||
| `byte[4]` | `eflags` | |
|
||||
| `byte[4]` | `eflags` | |
|
||||
| `vec3_t` | `eflags` | |
|
||||
| `vec3_t` | `eflags` | |
|
||||
| `vec3_t` | `eflags` | |
|
||||
| `vec3_t` | `maxs` | |
|
||||
| `int` | `eflags` | |
|
||||
| `int` | `eflags` | |
|
||||
| `float` | `eflags` | |
|
||||
| `float` | `eflags` | |
|
||||
| `int` | `eflags` | |
|
||||
| `int` | `eflags` | |
|
||||
| `int` | `eflags` | |
|
||||
| `qboolean` | `eflags` | |
|
||||
| `int` | `eflags` | |
|
||||
| `int` | `eflags` | |
|
||||
| `vec3_t` | `eflags` | |
|
||||
| `int` | `eflags` | |
|
||||
| `int` | `eflags` | |
|
||||
| `int` | `eflags` | |
|
||||
| `int` | `eflags` | |
|
||||
| `float` | `eflags` | |
|
||||
| `float` | `eflags` | |
|
||||
| `int` | `eflags` | |
|
||||
| `vec3_t` | `eflags` | |
|
||||
| `vec3_t` | `eflags` | |
|
||||
| `float` | `eflags` | |
|
||||
| `float` | `eflags` | |
|
||||
| `int` | `iuser1` | Few more extra fields for mods |
|
||||
| `int` | `iuser2` | |
|
||||
| `int` | `iuser3` | |
|
||||
| `int` | `iuser4` | |
|
||||
| `float` | `fuser1` | |
|
||||
| `float` | `fuser2` | |
|
||||
| `float` | `fuser3` | |
|
||||
| `float` | `fuser4` | |
|
||||
| `vec3_t` | `vuser1` | |
|
||||
| `vec3_t` | `vuser2` | |
|
||||
| `vec3_t` | `vuser3` | |
|
||||
| `vec3_t` | `vuser4` | |
|
||||
File diff suppressed because it is too large
Load Diff
@@ -50,8 +50,4 @@ GNU General Public License for more details.
|
||||
#define LIB_WIN32 2
|
||||
#define LIB_STATIC 3
|
||||
|
||||
// movies (XASH_AVI)
|
||||
#define AVI_NULL 0
|
||||
#define AVI_FFMPEG 1
|
||||
|
||||
#endif /* BACKENDS_H */
|
||||
|
||||
@@ -78,6 +78,7 @@ SETUP BACKENDS DEFINITIONS
|
||||
// usually only 10-20 fds availiable
|
||||
#define XASH_REDUCE_FD
|
||||
#endif
|
||||
|
||||
#endif // XASH_DEDICATED
|
||||
|
||||
//
|
||||
@@ -104,17 +105,6 @@ SETUP BACKENDS DEFINITIONS
|
||||
#endif // !XASH_WIN32
|
||||
#endif
|
||||
|
||||
//
|
||||
// determine movie playback backend
|
||||
//
|
||||
#ifndef XASH_AVI
|
||||
#if HAVE_FFMPEG
|
||||
#define XASH_AVI AVI_FFMPEG
|
||||
#else
|
||||
#define XASH_AVI AVI_NULL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef XASH_STATIC_LIBS
|
||||
#define XASH_LIB LIB_STATIC
|
||||
#define XASH_INTERNAL_GAMELIBS
|
||||
|
||||
@@ -157,23 +157,6 @@ typedef struct decallist_s
|
||||
modelstate_t studio_state; // studio decals only
|
||||
} decallist_t;
|
||||
|
||||
enum movie_parms_e
|
||||
{
|
||||
AVI_PARM_LAST = 0, // marker for SetParm to end parse parsing arguments
|
||||
AVI_RENDER_TEXNUM, // (int) sets texture to draw into, if 0 will draw to screen
|
||||
AVI_RENDER_X, // (int) when set to screen, sets position where to draw
|
||||
AVI_RENDER_Y,
|
||||
AVI_RENDER_W, // (int) sets texture or screen width
|
||||
AVI_RENDER_H, // set to -1 to draw full screen
|
||||
AVI_REWIND, // no argument, rewind playback to the beginning
|
||||
AVI_ENTNUM, // (int) entity number, -1 for no spatialization
|
||||
AVI_VOLUME, // (int) volume from 0 to 255
|
||||
AVI_ATTN, // (float) attenuation value
|
||||
AVI_PAUSE, // no argument, pauses playback
|
||||
AVI_RESUME, // no argument, resumes playback
|
||||
};
|
||||
|
||||
struct movie_state_s;
|
||||
struct ref_viewpass_s;
|
||||
|
||||
typedef struct render_api_s
|
||||
@@ -210,16 +193,16 @@ typedef struct render_api_s
|
||||
void (*R_EntityRemoveDecals)( struct model_s *mod ); // remove all the decals from specified entity (BSP only)
|
||||
|
||||
// AVIkit support
|
||||
struct movie_state_s *(*AVI_LoadVideo)( const char *filename, qboolean load_audio );
|
||||
qboolean (*AVI_GetVideoInfo)( struct movie_state_s *Avi, int *xres, int *yres, float *duration ); // a1ba: changed longs to int
|
||||
int (*AVI_GetVideoFrameNumber)( struct movie_state_s *Avi, float time );
|
||||
byte *(*AVI_GetVideoFrame)( struct movie_state_s *Avi, int frame );
|
||||
void *(*AVI_LoadVideo)( const char *filename, qboolean load_audio );
|
||||
int (*AVI_GetVideoInfo)( void *Avi, int *xres, int *yres, float *duration ); // a1ba: changed longs to int
|
||||
int (*AVI_GetVideoFrameNumber)( void *Avi, float time );
|
||||
byte *(*AVI_GetVideoFrame)( void *Avi, int frame );
|
||||
void (*AVI_UploadRawFrame)( int texture, int cols, int rows, int width, int height, const byte *data );
|
||||
void (*AVI_FreeVideo)( struct movie_state_s *Avi );
|
||||
qboolean (*AVI_IsActive)( struct movie_state_s *Avi );
|
||||
void (*AVI_StreamSound)( struct movie_state_s *Avi, int entnum, float fvol, float attn, float synctime );
|
||||
qboolean (*AVI_Think)( struct movie_state_s *Avi );
|
||||
qboolean (*AVI_SetParm)( struct movie_state_s *Avi, enum movie_parms_e parm, ... );
|
||||
void (*AVI_FreeVideo)( void *Avi );
|
||||
int (*AVI_IsActive)( void *Avi );
|
||||
void (*AVI_StreamSound)( void *Avi, int entnum, float fvol, float attn, float synctime );
|
||||
void (*AVI_Reserved0)( void ); // for potential interface expansion without broken compatibility
|
||||
void (*AVI_Reserved1)( void );
|
||||
|
||||
// glState related calls (must use this instead of normal gl-calls to prevent de-synchornize local states between engine and the client)
|
||||
void (*GL_Bind)( int tmu, unsigned int texnum );
|
||||
|
||||
@@ -16,17 +16,19 @@
|
||||
#include STDINT_H
|
||||
#include <assert.h>
|
||||
|
||||
typedef uint8_t byte;
|
||||
typedef float vec_t;
|
||||
typedef vec_t vec2_t[2];
|
||||
typedef vec_t vec3_t[3];
|
||||
typedef vec_t vec4_t[4];
|
||||
typedef vec_t quat_t[4];
|
||||
typedef byte rgba_t[4]; // unsigned byte colorpack
|
||||
typedef byte rgb_t[3]; // unsigned byte colorpack
|
||||
typedef vec_t matrix3x4[3][4];
|
||||
typedef vec_t matrix4x4[4][4];
|
||||
typedef uint32_t poolhandle_t;
|
||||
typedef unsigned char byte;
|
||||
typedef int sound_t;
|
||||
typedef float vec_t;
|
||||
typedef vec_t vec2_t[2];
|
||||
typedef vec_t vec3_t[3];
|
||||
typedef vec_t vec4_t[4];
|
||||
typedef vec_t quat_t[4];
|
||||
typedef byte rgba_t[4]; // unsigned byte colorpack
|
||||
typedef byte rgb_t[3]; // unsigned byte colorpack
|
||||
typedef vec_t matrix3x4[3][4];
|
||||
typedef vec_t matrix4x4[4][4];
|
||||
|
||||
typedef uint32_t poolhandle_t;
|
||||
|
||||
#undef true
|
||||
#undef false
|
||||
@@ -37,10 +39,18 @@ typedef enum { false, true } qboolean;
|
||||
typedef int qboolean;
|
||||
#endif
|
||||
|
||||
#define MAX_STRING 256 // generic string
|
||||
#define MAX_VA_STRING 1024 // compatibility macro
|
||||
#define MAX_SYSPATH 1024 // system filepath
|
||||
#define MAX_MODS 512 // environment games that engine can keep visible
|
||||
typedef uint64_t longtime_t;
|
||||
|
||||
#define MAX_STRING 256 // generic string
|
||||
#define MAX_INFO_STRING 256 // infostrings are transmitted across network
|
||||
#define MAX_SERVERINFO_STRING 512 // server handles too many settings. expand to 1024?
|
||||
#define MAX_LOCALINFO_STRING 32768 // localinfo used on server and not sended to the clients
|
||||
#define MAX_SYSPATH 1024 // system filepath
|
||||
#define MAX_VA_STRING 1024 // string length returned by va()
|
||||
#define MAX_PRINT_MSG 8192 // how many symbols can handle single call of Con_Printf or Con_DPrintf
|
||||
#define MAX_TOKEN 2048 // parse token length
|
||||
#define MAX_MODS 512 // environment games that engine can keep visible
|
||||
#define MAX_USERMSG_LENGTH 2048 // don't modify it's relies on a client-side definitions
|
||||
|
||||
#define BIT( n ) ( 1U << ( n ))
|
||||
#define BIT64( n ) ( 1ULL << ( n ))
|
||||
@@ -199,16 +209,35 @@ _inline float LittleFloat( float f )
|
||||
#endif
|
||||
|
||||
|
||||
typedef unsigned int dword;
|
||||
typedef unsigned int uint;
|
||||
typedef char string[MAX_STRING];
|
||||
typedef off_t fs_offset_t;
|
||||
typedef unsigned int dword;
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned long ulong;
|
||||
typedef char string[MAX_STRING];
|
||||
typedef struct file_s file_t; // normal file
|
||||
typedef struct stream_s stream_t; // sound stream for background music playing
|
||||
typedef off_t fs_offset_t;
|
||||
#if XASH_WIN32
|
||||
typedef int fs_size_t; // return type of _read, _write funcs
|
||||
typedef int fs_size_t; // return type of _read, _write funcs
|
||||
#else /* !XASH_WIN32 */
|
||||
typedef ssize_t fs_size_t;
|
||||
typedef ssize_t fs_size_t;
|
||||
#endif /* !XASH_WIN32 */
|
||||
|
||||
typedef struct dllfunc_s
|
||||
{
|
||||
const char *name;
|
||||
void **func;
|
||||
} dllfunc_t;
|
||||
|
||||
typedef struct dll_info_s
|
||||
{
|
||||
const char *name; // name of library
|
||||
const dllfunc_t *fcts; // list of dll exports
|
||||
const size_t num_fcts;
|
||||
qboolean crash; // crash if dll not found
|
||||
void *link; // hinstance of loading library
|
||||
} dll_info_t;
|
||||
|
||||
typedef void (*setpair_t)( const char *key, const void *value, const void *buffer, void *numpairs );
|
||||
typedef void *(*pfnCreateInterface_t)( const char *, int * );
|
||||
|
||||
// config strings are a general means of communication from
|
||||
|
||||
@@ -18,11 +18,12 @@ GNU General Public License for more details.
|
||||
//
|
||||
// avikit.c
|
||||
//
|
||||
typedef struct movie_state_s movie_state_t;
|
||||
typedef struct movie_state_s movie_state_t;
|
||||
int AVI_GetVideoFrameNumber( movie_state_t *Avi, float time );
|
||||
byte *AVI_GetVideoFrame( movie_state_t *Avi, int frame );
|
||||
qboolean AVI_GetVideoInfo( movie_state_t *Avi, int *xres, int *yres, float *duration );
|
||||
qboolean AVI_HaveAudioTrack( const movie_state_t *Avi );
|
||||
qboolean AVI_GetAudioInfo( movie_state_t *Avi, wavdata_t *snd_info );
|
||||
int AVI_GetAudioChunk( movie_state_t *Avi, char *audiodata, int offset, int length );
|
||||
void AVI_OpenVideo( movie_state_t *Avi, const char *filename, qboolean load_audio, int quiet );
|
||||
movie_state_t *AVI_LoadVideo( const char *filename, qboolean load_audio );
|
||||
int AVI_TimeToSoundPosition( movie_state_t *Avi, int time );
|
||||
@@ -33,7 +34,4 @@ movie_state_t *AVI_GetState( int num );
|
||||
qboolean AVI_Initailize( void );
|
||||
void AVI_Shutdown( void );
|
||||
|
||||
qboolean AVI_SetParm( movie_state_t *Avi, enum movie_parms_e parm, ... );
|
||||
qboolean AVI_Think( movie_state_t *Avi );
|
||||
|
||||
#endif // AVI_H
|
||||
|
||||
@@ -1,761 +0,0 @@
|
||||
/*
|
||||
avi_ffmpreg.c - playing AVI files (ffmpeg backend)
|
||||
Copyright (C) FTEQW developers (for plugins/avplug/avdecode.c)
|
||||
Copyright (C) Sam Lantinga (for tests/testffmpeg.c)
|
||||
Copyright (C) 2023-2024 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 "defaults.h"
|
||||
#include "common.h"
|
||||
#include "client.h"
|
||||
|
||||
static qboolean avi_initialized;
|
||||
static poolhandle_t avi_mempool;
|
||||
|
||||
#if XASH_AVI == AVI_FFMPEG
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavutil/imgutils.h>
|
||||
#include <libswscale/swscale.h>
|
||||
#include <libswresample/swresample.h>
|
||||
|
||||
struct movie_state_s
|
||||
{
|
||||
// ffmpeg contexts
|
||||
AVFormatContext *fmt_ctx;
|
||||
AVCodecContext *video_ctx;
|
||||
AVCodecContext *audio_ctx;
|
||||
struct SwsContext *sws_ctx;
|
||||
struct SwrContext *swr_ctx;
|
||||
|
||||
AVPacket *pkt;
|
||||
AVFrame *aframe;
|
||||
AVFrame *vframe;
|
||||
AVFrame *vframe_copy;
|
||||
|
||||
int64_t first_time;
|
||||
int64_t last_time;
|
||||
|
||||
// video stream
|
||||
byte *dst;
|
||||
double duration;
|
||||
int video_stream;
|
||||
int xres;
|
||||
int yres;
|
||||
int dst_linesize;
|
||||
enum AVPixelFormat pix_fmt;
|
||||
|
||||
// rendering video parameters
|
||||
int x, y, w, h; // passed to R_DrawStretchRaw
|
||||
int texture; // passed to R_UploadStretchRaw
|
||||
|
||||
// audio stream
|
||||
int audio_stream;
|
||||
int channels;
|
||||
int rate;
|
||||
enum AVSampleFormat s_fmt;
|
||||
|
||||
byte *cached_audio;
|
||||
size_t cached_audio_buf_len; // absolute size of cached_audio array
|
||||
size_t cached_audio_len; // how many data in bytes we have in cached_audio array
|
||||
size_t cached_audio_pos; // how far we've read into cached_audio array
|
||||
|
||||
// rendering audio parameters
|
||||
float attn;
|
||||
int16_t entnum; // MAX_ENTITY_BITS is 13
|
||||
byte volume;
|
||||
byte active : 1;
|
||||
byte quiet : 1;
|
||||
byte paused : 1;
|
||||
};
|
||||
|
||||
qboolean AVI_SetParm( movie_state_t *Avi, enum movie_parms_e parm, ... )
|
||||
{
|
||||
qboolean ret = true;
|
||||
va_list va;
|
||||
va_start( va, parm );
|
||||
|
||||
while( parm != AVI_PARM_LAST )
|
||||
{
|
||||
float fval;
|
||||
int val;
|
||||
|
||||
switch( parm )
|
||||
{
|
||||
case AVI_RENDER_TEXNUM:
|
||||
Avi->texture = va_arg( va, int );
|
||||
break;
|
||||
case AVI_RENDER_X:
|
||||
Avi->x = va_arg( va, int );
|
||||
break;
|
||||
case AVI_RENDER_Y:
|
||||
Avi->y = va_arg( va, int );
|
||||
break;
|
||||
case AVI_RENDER_W:
|
||||
Avi->w = va_arg( va, int );
|
||||
break;
|
||||
case AVI_RENDER_H:
|
||||
Avi->h = va_arg( va, int );
|
||||
break;
|
||||
case AVI_REWIND:
|
||||
if( Avi->audio_ctx )
|
||||
avcodec_flush_buffers( Avi->audio_ctx );
|
||||
avcodec_flush_buffers( Avi->video_ctx );
|
||||
Avi->cached_audio_len = Avi->cached_audio_pos = 0;
|
||||
Avi->last_time = -1;
|
||||
Avi->first_time = 0;
|
||||
av_seek_frame( Avi->fmt_ctx, -1, 0, AVSEEK_FLAG_FRAME | AVSEEK_FLAG_BACKWARD );
|
||||
break;
|
||||
case AVI_ENTNUM:
|
||||
val = va_arg( va, int );
|
||||
Avi->entnum = bound( 0, val, MAX_EDICTS );
|
||||
break;
|
||||
case AVI_VOLUME:
|
||||
val = va_arg( va, int );
|
||||
Avi->volume = bound( 0, val, 255 );
|
||||
break;
|
||||
case AVI_ATTN:
|
||||
fval = va_arg( va, double );
|
||||
Avi->attn = Q_max( 0.0f, fval );
|
||||
break;
|
||||
case AVI_PAUSE:
|
||||
Avi->paused = true;
|
||||
break;
|
||||
case AVI_RESUME:
|
||||
Avi->paused = false;
|
||||
break;
|
||||
default:
|
||||
ret = false;
|
||||
}
|
||||
|
||||
parm = va_arg( va, enum movie_parms_e );
|
||||
}
|
||||
|
||||
va_end( va );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void AVI_SpewError( qboolean quiet, const char *fmt, ... ) FORMAT_CHECK( 2 );
|
||||
static void AVI_SpewError( qboolean quiet, const char *fmt, ... )
|
||||
{
|
||||
char buf[MAX_VA_STRING];
|
||||
va_list va;
|
||||
|
||||
if( quiet )
|
||||
return;
|
||||
|
||||
va_start( va, fmt );
|
||||
Q_vsnprintf( buf, sizeof( buf ), fmt, va );
|
||||
va_end( va );
|
||||
|
||||
Con_Printf( S_ERROR "%s", buf );
|
||||
}
|
||||
|
||||
static void AVI_SpewAvError( qboolean quiet, const char *func, int numerr )
|
||||
{
|
||||
if( !quiet )
|
||||
Con_Printf( S_ERROR "%s: %s (%d)\n", func, av_err2str( numerr ), numerr );
|
||||
}
|
||||
|
||||
static int AVI_OpenCodecContext( AVCodecContext **dst_dec_ctx, AVFormatContext *fmt_ctx, enum AVMediaType type, qboolean quiet )
|
||||
{
|
||||
const AVCodec *dec;
|
||||
AVCodecContext *dec_ctx;
|
||||
AVStream *st;
|
||||
int idx, ret;
|
||||
|
||||
if(( ret = av_find_best_stream( fmt_ctx, type, -1, -1, NULL, 0 )) < 0 )
|
||||
{
|
||||
AVI_SpewAvError( quiet, "av_find_best_stream", ret );
|
||||
return ret;
|
||||
}
|
||||
|
||||
idx = ret;
|
||||
st = fmt_ctx->streams[idx];
|
||||
|
||||
if( !( dec = avcodec_find_decoder( st->codecpar->codec_id )))
|
||||
{
|
||||
AVI_SpewError( quiet, S_ERROR "Failed to find %s codec\n", av_get_media_type_string( type ));
|
||||
return AVERROR( EINVAL );
|
||||
}
|
||||
|
||||
if( !( dec_ctx = avcodec_alloc_context3( dec )))
|
||||
{
|
||||
AVI_SpewError( quiet, S_ERROR "Failed to allocate %s codec context", dec->name );
|
||||
return AVERROR( ENOMEM );
|
||||
}
|
||||
|
||||
if(( ret = avcodec_parameters_to_context( dec_ctx, st->codecpar )) < 0 )
|
||||
{
|
||||
AVI_SpewAvError( quiet, "avcodec_parameters_to_context", ret );
|
||||
avcodec_free_context( &dec_ctx );
|
||||
return ret;
|
||||
}
|
||||
|
||||
dec_ctx->pkt_timebase = st->time_base;
|
||||
|
||||
if(( ret = avcodec_open2( dec_ctx, dec, NULL )) < 0 )
|
||||
{
|
||||
AVI_SpewAvError( quiet, "avcodec_open2", ret );
|
||||
|
||||
avcodec_free_context( &dec_ctx );
|
||||
return ret;
|
||||
}
|
||||
|
||||
*dst_dec_ctx = dec_ctx;
|
||||
return idx; // always positive
|
||||
}
|
||||
|
||||
int AVI_GetVideoFrameNumber( movie_state_t *Avi, float time )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AVI_TimeToSoundPosition( movie_state_t *Avi, int time )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
qboolean AVI_GetVideoInfo( movie_state_t *Avi, int *xres, int *yres, float *duration )
|
||||
{
|
||||
if( !Avi->active )
|
||||
return false;
|
||||
|
||||
if( xres )
|
||||
*xres = Avi->xres;
|
||||
|
||||
if( yres )
|
||||
*yres = Avi->yres;
|
||||
|
||||
if( duration )
|
||||
*duration = Avi->duration;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
qboolean AVI_HaveAudioTrack( const movie_state_t *Avi )
|
||||
{
|
||||
return Avi ? Avi->active && Avi->audio_ctx : false;
|
||||
}
|
||||
|
||||
// just let it compile, bruh!
|
||||
byte *AVI_GetVideoFrame( movie_state_t *Avi, int target )
|
||||
{
|
||||
return Avi->dst;
|
||||
}
|
||||
|
||||
static void AVI_StreamAudio( movie_state_t *Avi )
|
||||
{
|
||||
int buffer_samples, file_samples, file_bytes;
|
||||
rawchan_t *ch = NULL;
|
||||
|
||||
// keep the same semantics, when S_RAW_SOUND_SOUNDTRACK doesn't play if S_StartStreaming wasn't enabled
|
||||
qboolean disable_stream = Avi->entnum == S_RAW_SOUND_SOUNDTRACK ? !s_listener.streaming : false;
|
||||
|
||||
if( !dma.initialized || disable_stream || s_listener.paused || !Avi->cached_audio )
|
||||
return;
|
||||
|
||||
ch = S_FindRawChannel( Avi->entnum, true );
|
||||
|
||||
if( !ch )
|
||||
return;
|
||||
|
||||
ch->master_vol = Avi->volume;
|
||||
ch->dist_mult = (Avi->attn / SND_CLIP_DISTANCE);
|
||||
|
||||
if( ch->s_rawend < soundtime )
|
||||
ch->s_rawend = soundtime;
|
||||
|
||||
while( ch->s_rawend < soundtime + ch->max_samples )
|
||||
{
|
||||
size_t copy;
|
||||
|
||||
buffer_samples = ch->max_samples - (ch->s_rawend - soundtime);
|
||||
|
||||
file_samples = buffer_samples * ((float)Avi->rate / SOUND_DMA_SPEED);
|
||||
if( file_samples <= 1 ) return; // no more samples need
|
||||
|
||||
file_bytes = file_samples * av_get_bytes_per_sample( Avi->s_fmt ) * Avi->channels;
|
||||
|
||||
if( file_bytes > ch->max_samples )
|
||||
{
|
||||
file_bytes = ch->max_samples;
|
||||
file_samples = file_bytes / ( av_get_bytes_per_sample( Avi->s_fmt ) * Avi->channels );
|
||||
}
|
||||
|
||||
copy = Q_min( file_bytes, Q_max( Avi->cached_audio_len - Avi->cached_audio_pos, 0 ));
|
||||
|
||||
if( !copy )
|
||||
break;
|
||||
|
||||
if( file_bytes > copy )
|
||||
{
|
||||
file_bytes = copy;
|
||||
file_samples = file_bytes / ( av_get_bytes_per_sample( Avi->s_fmt ) * Avi->channels );
|
||||
}
|
||||
|
||||
ch->s_rawend = S_RawSamplesStereo( ch->rawsamples, ch->s_rawend, ch->max_samples, file_samples, Avi->rate, av_get_bytes_per_sample( Avi->s_fmt ), Avi->channels, Avi->cached_audio + Avi->cached_audio_pos );
|
||||
Avi->cached_audio_pos += copy;
|
||||
}
|
||||
}
|
||||
|
||||
static void AVI_HandleAudio( movie_state_t *Avi, const AVFrame *frame )
|
||||
{
|
||||
int samples = frame->nb_samples;
|
||||
size_t len = samples * av_get_bytes_per_sample( Avi->s_fmt ) * Avi->channels;
|
||||
int outsamples;
|
||||
uint8_t *ptr;
|
||||
|
||||
// allocate data
|
||||
if( !Avi->cached_audio )
|
||||
{
|
||||
Avi->cached_audio_buf_len = len;
|
||||
Avi->cached_audio_pos = 0;
|
||||
Avi->cached_audio_len = 0;
|
||||
Avi->cached_audio = Mem_Malloc( avi_mempool, len );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( Avi->cached_audio_pos )
|
||||
{
|
||||
// Con_Printf( "%s: erasing old data of size %d\n", __func__, Avi->cached_audio_pos );
|
||||
Avi->cached_audio_len -= Avi->cached_audio_pos;
|
||||
memmove( Avi->cached_audio, Avi->cached_audio + Avi->cached_audio_pos, Avi->cached_audio_len );
|
||||
Avi->cached_audio_pos = 0;
|
||||
}
|
||||
|
||||
if( len + Avi->cached_audio_len > Avi->cached_audio_buf_len )
|
||||
{
|
||||
// Con_Printf( "%s: resizing old buffer of size %d to size %d\n", __func__, Avi->cached_audio_buf_len, len + Avi->cached_audio_buf_len );
|
||||
Avi->cached_audio_buf_len = len + Avi->cached_audio_len;
|
||||
Avi->cached_audio = Mem_Realloc( avi_mempool, Avi->cached_audio, Avi->cached_audio_buf_len );
|
||||
}
|
||||
}
|
||||
|
||||
ptr = Avi->cached_audio + Avi->cached_audio_len;
|
||||
outsamples = swr_convert( Avi->swr_ctx, &ptr, samples, (void *)frame->data, samples );
|
||||
Avi->cached_audio_len += outsamples * av_get_bytes_per_sample( Avi->s_fmt ) * Avi->channels;
|
||||
|
||||
// Con_Printf( "%s: got audio chunk of size %d samples\n", __func__, outsamples );
|
||||
}
|
||||
|
||||
qboolean AVI_Think( movie_state_t *Avi )
|
||||
{
|
||||
qboolean decoded = false;
|
||||
qboolean flushing = false;
|
||||
qboolean redraw = false;
|
||||
const double timebase = (double)Avi->video_ctx->pkt_timebase.den / Avi->video_ctx->pkt_timebase.num;
|
||||
int64_t curtime = round( Platform_DoubleTime() * timebase );
|
||||
|
||||
if( !Avi->first_time ) // always remember at which timestamp we started playing
|
||||
Avi->first_time = curtime;
|
||||
|
||||
if( Avi->paused )
|
||||
{
|
||||
// FIXME: there might be a better way to do this
|
||||
Avi->last_time = curtime;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Con_NPrintf( 1, "cached_audio_buf_len = %zu", Avi->cached_audio_buf_len );
|
||||
|
||||
while( 1 ) // try to get multiple decoded frames to keep up when we're running at low fps
|
||||
{
|
||||
int res;
|
||||
|
||||
AVI_StreamAudio( Avi ); // always flush audio buffers
|
||||
|
||||
// recalc time so we always play last possible frame
|
||||
curtime = round( Platform_DoubleTime() * timebase );
|
||||
|
||||
if( Avi->last_time > curtime )
|
||||
break;
|
||||
|
||||
if(( res = av_read_frame( Avi->fmt_ctx, Avi->pkt )) >= 0 )
|
||||
{
|
||||
if( Avi->pkt->stream_index == Avi->audio_stream )
|
||||
{
|
||||
res = avcodec_send_packet( Avi->audio_ctx, Avi->pkt );
|
||||
if( res < 0 )
|
||||
AVI_SpewAvError( Avi->quiet, "avcodec_send_packet (audio)", res );
|
||||
}
|
||||
else if( Avi->pkt->stream_index == Avi->video_stream )
|
||||
{
|
||||
res = avcodec_send_packet( Avi->video_ctx, Avi->pkt );
|
||||
if( res < 0 )
|
||||
AVI_SpewAvError( Avi->quiet, "avcodec_send_packet (video)", res );
|
||||
}
|
||||
av_packet_unref( Avi->pkt );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( res != AVERROR_EOF )
|
||||
AVI_SpewAvError( Avi->quiet, "av_read_frame", res );
|
||||
|
||||
if( Avi->audio_ctx )
|
||||
avcodec_flush_buffers( Avi->audio_ctx );
|
||||
|
||||
avcodec_flush_buffers( Avi->video_ctx );
|
||||
flushing = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if( Avi->audio_ctx )
|
||||
{
|
||||
while( avcodec_receive_frame( Avi->audio_ctx, Avi->aframe ) == 0 )
|
||||
{
|
||||
AVI_HandleAudio( Avi, Avi->aframe );
|
||||
decoded = true;
|
||||
}
|
||||
}
|
||||
|
||||
while( avcodec_receive_frame( Avi->video_ctx, Avi->vframe ) == 0 )
|
||||
{
|
||||
Avi->last_time = Avi->first_time + Avi->vframe->best_effort_timestamp;
|
||||
decoded = true;
|
||||
|
||||
if( FBitSet( Avi->vframe->flags, AV_FRAME_FLAG_CORRUPT|AV_FRAME_FLAG_DISCARD ))
|
||||
continue;
|
||||
|
||||
if( Avi->vframe->decode_error_flags != 0 )
|
||||
continue;
|
||||
|
||||
av_frame_unref( Avi->vframe_copy );
|
||||
if( av_frame_ref( Avi->vframe_copy, Avi->vframe ) == 0 )
|
||||
redraw = true;
|
||||
}
|
||||
}
|
||||
|
||||
if( redraw )
|
||||
{
|
||||
sws_scale( Avi->sws_ctx, (void*)Avi->vframe_copy->data, Avi->vframe_copy->linesize, 0, Avi->video_ctx->height,
|
||||
&Avi->dst, &Avi->dst_linesize );
|
||||
av_frame_unref( Avi->vframe_copy );
|
||||
}
|
||||
|
||||
if( Avi->texture == 0 )
|
||||
{
|
||||
int w = Avi->w >= 0 ? Avi->w : refState.width;
|
||||
int h = Avi->h >= 0 ? Avi->h : refState.height;
|
||||
|
||||
ref.dllFuncs.R_DrawStretchRaw( Avi->x, Avi->y, w, h, Avi->xres, Avi->yres, Avi->dst, redraw );
|
||||
}
|
||||
else if( redraw && Avi->texture > 0 )
|
||||
ref.dllFuncs.AVI_UploadRawFrame( Avi->texture, Avi->xres, Avi->yres, Avi->w, Avi->h, Avi->dst );
|
||||
|
||||
if( flushing && !decoded )
|
||||
return false; // probably hit an EOF
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AVI_OpenVideo( movie_state_t *Avi, const char *filename, qboolean load_audio, int quiet )
|
||||
{
|
||||
byte *dst[4];
|
||||
int dst_linesize[4];
|
||||
int ret;
|
||||
|
||||
if( Avi->active )
|
||||
AVI_CloseVideo( Avi );
|
||||
|
||||
if( !filename || !avi_initialized )
|
||||
return;
|
||||
|
||||
Avi->active = false;
|
||||
Avi->quiet = quiet;
|
||||
Avi->video_ctx = Avi->audio_ctx = NULL;
|
||||
Avi->fmt_ctx = NULL;
|
||||
|
||||
if(( ret = avformat_open_input( &Avi->fmt_ctx, filename, NULL, NULL )) < 0 )
|
||||
{
|
||||
AVI_SpewAvError( quiet, "avformat_open_input", ret );
|
||||
return;
|
||||
}
|
||||
|
||||
if(( ret = avformat_find_stream_info( Avi->fmt_ctx, NULL )) < 0 )
|
||||
{
|
||||
AVI_SpewAvError( quiet, "avformat_find_stream_info", ret );
|
||||
return;
|
||||
}
|
||||
|
||||
if( !( Avi->pkt = av_packet_alloc( )))
|
||||
{
|
||||
AVI_SpewAvError( quiet, "av_packet_alloc", 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
if( !( Avi->vframe = av_frame_alloc( )))
|
||||
{
|
||||
AVI_SpewAvError( quiet, "av_frame_alloc (video)", 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
if( !( Avi->vframe_copy = av_frame_alloc( )))
|
||||
{
|
||||
AVI_SpewAvError( quiet, "av_frame_alloc (video)", 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Avi->video_stream = AVI_OpenCodecContext( &Avi->video_ctx, Avi->fmt_ctx, AVMEDIA_TYPE_VIDEO, quiet );
|
||||
|
||||
if( Avi->video_stream < 0 )
|
||||
return;
|
||||
|
||||
Avi->xres = Avi->video_ctx->width;
|
||||
Avi->yres = Avi->video_ctx->height;
|
||||
Avi->pix_fmt = Avi->video_ctx->pix_fmt;
|
||||
Avi->duration = Avi->fmt_ctx->duration / (double)AV_TIME_BASE;
|
||||
Avi->entnum = S_RAW_SOUND_SOUNDTRACK;
|
||||
Avi->attn = ATTN_NONE;
|
||||
Avi->volume = 255;
|
||||
|
||||
if( !( Avi->sws_ctx = sws_getContext( Avi->xres, Avi->yres, Avi->pix_fmt,
|
||||
Avi->xres, Avi->yres, AV_PIX_FMT_BGR0, SWS_POINT, NULL, NULL, NULL )))
|
||||
{
|
||||
AVI_SpewAvError( quiet, "sws_getContext", 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
if(( ret = av_image_alloc( dst, dst_linesize, Avi->xres, Avi->yres, AV_PIX_FMT_BGR0, 1 )) < 0 )
|
||||
{
|
||||
AVI_SpewAvError( quiet, "av_image_alloc", ret );
|
||||
return;
|
||||
}
|
||||
|
||||
Avi->dst = dst[0];
|
||||
Avi->dst_linesize = dst_linesize[0];
|
||||
|
||||
if( load_audio )
|
||||
{
|
||||
if( !( Avi->aframe = av_frame_alloc( )))
|
||||
{
|
||||
AVI_SpewAvError( quiet, "av_frame_alloc (audio)", 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
Avi->audio_stream = AVI_OpenCodecContext( &Avi->audio_ctx, Avi->fmt_ctx, AVMEDIA_TYPE_AUDIO, quiet );
|
||||
|
||||
// audio stream was requested but it wasn't found
|
||||
if( Avi->audio_stream < 0 )
|
||||
return;
|
||||
|
||||
Avi->channels = Q_min( Avi->audio_ctx->ch_layout.nb_channels, 2 );
|
||||
if( Avi->audio_ctx->sample_fmt == AV_SAMPLE_FMT_U8 || Avi->audio_ctx->sample_fmt == AV_SAMPLE_FMT_U8P )
|
||||
Avi->s_fmt = AV_SAMPLE_FMT_U8;
|
||||
else Avi->s_fmt = AV_SAMPLE_FMT_S16;
|
||||
Avi->rate = Avi->audio_ctx->sample_rate;
|
||||
|
||||
if(( ret = swr_alloc_set_opts2( &Avi->swr_ctx, &Avi->audio_ctx->ch_layout, Avi->s_fmt, Avi->rate,
|
||||
&Avi->audio_ctx->ch_layout, Avi->audio_ctx->sample_fmt, Avi->audio_ctx->sample_rate, 0, 0 )) < 0 )
|
||||
{
|
||||
AVI_SpewAvError( quiet, "swr_alloc_set_opts2", ret );
|
||||
return;
|
||||
}
|
||||
|
||||
if(( ret = swr_init( Avi->swr_ctx )) < 0 )
|
||||
{
|
||||
AVI_SpewAvError( quiet, "swr_init", ret );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Avi->active = true;
|
||||
}
|
||||
|
||||
void AVI_CloseVideo( movie_state_t *Avi )
|
||||
{
|
||||
if( Avi->active )
|
||||
{
|
||||
if( Avi->cached_audio )
|
||||
Mem_Free( Avi->cached_audio );
|
||||
|
||||
swr_free( &Avi->swr_ctx );
|
||||
avcodec_free_context( &Avi->audio_ctx );
|
||||
av_frame_free( &Avi->aframe );
|
||||
|
||||
av_free( Avi->dst );
|
||||
sws_freeContext( Avi->sws_ctx );
|
||||
avcodec_free_context( &Avi->video_ctx );
|
||||
av_frame_free( &Avi->vframe );
|
||||
av_frame_free( &Avi->vframe_copy );
|
||||
|
||||
av_packet_free( &Avi->pkt );
|
||||
|
||||
avformat_close_input( &Avi->fmt_ctx );
|
||||
}
|
||||
|
||||
memset( Avi, 0, sizeof( *Avi ));
|
||||
}
|
||||
|
||||
static void AVI_PrintFFmpegVersion( void )
|
||||
{
|
||||
uint ver;
|
||||
|
||||
// print version we're compiled with and which version we're running with
|
||||
ver = avutil_version();
|
||||
Con_Reportf( "AVI: %s (runtime %d.%d.%d)\n", LIBAVUTIL_IDENT, AV_VERSION_MAJOR( ver ), AV_VERSION_MINOR( ver ), AV_VERSION_MICRO( ver ));
|
||||
|
||||
ver = avformat_version();
|
||||
Con_Reportf( "AVI: %s (runtime %d.%d.%d)\n", LIBAVFORMAT_IDENT, AV_VERSION_MAJOR( ver ), AV_VERSION_MINOR( ver ), AV_VERSION_MICRO( ver ));
|
||||
|
||||
ver = avformat_version();
|
||||
Con_Reportf( "AVI: %s (runtime %d.%d.%d)\n", LIBAVCODEC_IDENT, AV_VERSION_MAJOR( ver ), AV_VERSION_MINOR( ver ), AV_VERSION_MICRO( ver ));
|
||||
|
||||
ver = swscale_version();
|
||||
Con_Reportf( "AVI: %s (runtime %d.%d.%d)\n", LIBSWSCALE_IDENT, AV_VERSION_MAJOR( ver ), AV_VERSION_MINOR( ver ), AV_VERSION_MICRO( ver ));
|
||||
|
||||
ver = swresample_version();
|
||||
Con_Reportf( "AVI: %s (runtime %d.%d.%d)\n", LIBSWRESAMPLE_IDENT, AV_VERSION_MAJOR( ver ), AV_VERSION_MINOR( ver ), AV_VERSION_MICRO( ver ));
|
||||
}
|
||||
#else
|
||||
struct movie_state_s
|
||||
{
|
||||
qboolean active;
|
||||
};
|
||||
|
||||
int AVI_GetVideoFrameNumber( movie_state_t *Avi, float time )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
byte *AVI_GetVideoFrame( movie_state_t *Avi, int frame )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
qboolean AVI_GetVideoInfo( movie_state_t *Avi, int *xres, int *yres, float *duration )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
qboolean AVI_HaveAudioTrack( const movie_state_t *Avi )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void AVI_OpenVideo( movie_state_t *Avi, const char *filename, qboolean load_audio, int quiet )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
int AVI_TimeToSoundPosition( movie_state_t *Avi, int time )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AVI_CloseVideo( movie_state_t *Avi )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
qboolean AVI_Think( movie_state_t *Avi )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
qboolean AVI_SetParm( movie_state_t *Avi, enum movie_parms_e parm, ... )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static void AVI_PrintFFmpegVersion( void )
|
||||
{
|
||||
|
||||
}
|
||||
#endif // XASH_AVI == AVI_NULL
|
||||
|
||||
static movie_state_t avi[2];
|
||||
movie_state_t *AVI_GetState( int num )
|
||||
{
|
||||
return &avi[num];
|
||||
}
|
||||
|
||||
qboolean AVI_IsActive( movie_state_t *Avi )
|
||||
{
|
||||
return Avi ? Avi->active : false;
|
||||
}
|
||||
|
||||
qboolean AVI_Initailize( void )
|
||||
{
|
||||
if( XASH_AVI == AVI_NULL )
|
||||
{
|
||||
Con_Printf( "AVI: Not supported\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( Sys_CheckParm( "-noavi" ))
|
||||
{
|
||||
Con_Printf( "AVI: Disabled\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
AVI_PrintFFmpegVersion();
|
||||
|
||||
avi_initialized = true;
|
||||
avi_mempool = Mem_AllocPool( "AVI Zone" );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void AVI_Shutdown( void )
|
||||
{
|
||||
Mem_FreePool( &avi_mempool );
|
||||
avi_initialized = XASH_AVI != AVI_NULL;
|
||||
}
|
||||
|
||||
movie_state_t *AVI_LoadVideo( const char *filename, qboolean load_audio )
|
||||
{
|
||||
movie_state_t *Avi;
|
||||
string path;
|
||||
const char *fullpath;
|
||||
|
||||
// fast reject
|
||||
if( !avi_initialized )
|
||||
return NULL;
|
||||
|
||||
// open cinematic
|
||||
Q_snprintf( path, sizeof( path ), "media/%s", filename );
|
||||
COM_DefaultExtension( path, ".avi", sizeof( path ));
|
||||
fullpath = FS_GetDiskPath( path, false );
|
||||
|
||||
if( FS_FileExists( path, false ) && !fullpath )
|
||||
{
|
||||
Con_Printf( "Couldn't load %s from packfile. Please extract it\n", path );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Avi = Mem_Calloc( avi_mempool, sizeof( movie_state_t ));
|
||||
AVI_OpenVideo( Avi, fullpath, load_audio, false );
|
||||
|
||||
if( !AVI_IsActive( Avi ))
|
||||
{
|
||||
AVI_FreeVideo( Avi ); // something bad happens
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// all done
|
||||
return Avi;
|
||||
}
|
||||
|
||||
void AVI_FreeVideo( movie_state_t *Avi )
|
||||
{
|
||||
if( !Avi )
|
||||
return;
|
||||
|
||||
AVI_CloseVideo( Avi );
|
||||
|
||||
if( Mem_IsAllocatedExt( avi_mempool, Avi ))
|
||||
Mem_Free( Avi );
|
||||
}
|
||||
90
engine/client/avi/avi_stub.c
Normal file
90
engine/client/avi/avi_stub.c
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
avi_stub.c - playing AVI files (stub)
|
||||
Copyright (C) 2018 a1batross
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "build.h"
|
||||
#if !XASH_WIN32
|
||||
#include "common.h"
|
||||
|
||||
int AVI_GetVideoFrameNumber( movie_state_t *Avi, float time )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
byte *AVI_GetVideoFrame( movie_state_t *Avi, int frame )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
qboolean AVI_GetVideoInfo( movie_state_t *Avi, int *xres, int *yres, float *duration )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
qboolean AVI_GetAudioInfo( movie_state_t *Avi, wavdata_t *snd_info )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int AVI_GetAudioChunk( movie_state_t *Avi, char *audiodata, int offset, int length )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AVI_OpenVideo( movie_state_t *Avi, const char *filename, qboolean load_audio, int quiet )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
movie_state_t *AVI_LoadVideo( const char *filename, qboolean load_audio )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int AVI_TimeToSoundPosition( movie_state_t *Avi, int time )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AVI_CloseVideo( movie_state_t *Avi )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
qboolean AVI_IsActive( movie_state_t *Avi )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void AVI_FreeVideo( movie_state_t *Avi )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
movie_state_t *AVI_GetState( int num )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
qboolean AVI_Initailize( void )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void AVI_Shutdown( void )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
#endif // WIN32
|
||||
732
engine/client/avi/avi_win.c
Normal file
732
engine/client/avi/avi_win.c
Normal file
@@ -0,0 +1,732 @@
|
||||
/*
|
||||
avi_win.c - playing AVI files (based on original AVIKit code, Win32 version)
|
||||
Copyright (c) 2003-2004, Ruari O'Sullivan
|
||||
Copyright (C) 2010 Uncle Mike
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "build.h"
|
||||
#if XASH_WIN32
|
||||
#include "common.h"
|
||||
#include "client.h"
|
||||
#include <vfw.h> // video for windows
|
||||
|
||||
// msvfw32.dll exports
|
||||
static HDRAWDIB (_stdcall *pDrawDibOpen)( void );
|
||||
static BOOL (_stdcall *pDrawDibClose)( HDRAWDIB hdd );
|
||||
static BOOL (_stdcall *pDrawDibDraw)( HDRAWDIB, HDC, int, int, int, int, LPBITMAPINFOHEADER, void*, int, int, int, int, uint );
|
||||
|
||||
static dllfunc_t msvfw_funcs[] =
|
||||
{
|
||||
{ "DrawDibOpen", (void **) &pDrawDibOpen },
|
||||
{ "DrawDibDraw", (void **) &pDrawDibDraw },
|
||||
{ "DrawDibClose", (void **) &pDrawDibClose },
|
||||
};
|
||||
|
||||
dll_info_t msvfw_dll = { "msvfw32.dll", msvfw_funcs, ARRAYSIZE( msvfw_funcs ), false };
|
||||
|
||||
// msacm32.dll exports
|
||||
static MMRESULT (_stdcall *pacmStreamOpen)( LPHACMSTREAM, HACMDRIVER, LPWAVEFORMATEX, LPWAVEFORMATEX, LPWAVEFILTER, DWORD, DWORD, DWORD );
|
||||
static MMRESULT (_stdcall *pacmStreamPrepareHeader)( HACMSTREAM, LPACMSTREAMHEADER, DWORD );
|
||||
static MMRESULT (_stdcall *pacmStreamUnprepareHeader)( HACMSTREAM, LPACMSTREAMHEADER, DWORD );
|
||||
static MMRESULT (_stdcall *pacmStreamConvert)( HACMSTREAM, LPACMSTREAMHEADER, DWORD );
|
||||
static MMRESULT (_stdcall *pacmStreamSize)( HACMSTREAM, DWORD, LPDWORD, DWORD );
|
||||
static MMRESULT (_stdcall *pacmStreamClose)( HACMSTREAM, DWORD );
|
||||
|
||||
static dllfunc_t msacm_funcs[] =
|
||||
{
|
||||
{ "acmStreamOpen", (void **) &pacmStreamOpen },
|
||||
{ "acmStreamPrepareHeader", (void **) &pacmStreamPrepareHeader },
|
||||
{ "acmStreamUnprepareHeader", (void **) &pacmStreamUnprepareHeader },
|
||||
{ "acmStreamConvert", (void **) &pacmStreamConvert },
|
||||
{ "acmStreamSize", (void **) &pacmStreamSize },
|
||||
{ "acmStreamClose", (void **) &pacmStreamClose },
|
||||
};
|
||||
|
||||
dll_info_t msacm_dll = { "msacm32.dll", msacm_funcs, ARRAYSIZE( msacm_funcs ), false };
|
||||
|
||||
// avifil32.dll exports
|
||||
static int (_stdcall *pAVIStreamInfo)( PAVISTREAM pavi, AVISTREAMINFO *psi, LONG lSize );
|
||||
static int (_stdcall *pAVIStreamRead)( PAVISTREAM pavi, LONG lStart, LONG lSamples, void *lpBuffer, LONG cbBuffer, LONG *plBytes, LONG *plSamples );
|
||||
static PGETFRAME (_stdcall *pAVIStreamGetFrameOpen)( PAVISTREAM pavi, LPBITMAPINFOHEADER lpbiWanted );
|
||||
static int (_stdcall *pAVIStreamTimeToSample)( PAVISTREAM pavi, LONG lTime );
|
||||
static void* (_stdcall *pAVIStreamGetFrame)( PGETFRAME pg, LONG lPos );
|
||||
static int (_stdcall *pAVIStreamGetFrameClose)( PGETFRAME pg );
|
||||
static dword (_stdcall *pAVIStreamRelease)( PAVISTREAM pavi );
|
||||
static int (_stdcall *pAVIFileOpenW)( PAVIFILE *ppfile, LPCWSTR szFile, UINT uMode, LPCLSID lpHandler );
|
||||
static int (_stdcall *pAVIFileGetStream)( PAVIFILE pfile, PAVISTREAM *ppavi, DWORD fccType, LONG lParam );
|
||||
static int (_stdcall *pAVIStreamReadFormat)( PAVISTREAM pavi, LONG lPos,LPVOID lpFormat, LONG *lpcbFormat );
|
||||
static int (_stdcall *pAVIStreamStart)( PAVISTREAM pavi );
|
||||
static dword (_stdcall *pAVIFileRelease)( PAVIFILE pfile );
|
||||
static void (_stdcall *pAVIFileInit)( void );
|
||||
static void (_stdcall *pAVIFileExit)( void );
|
||||
|
||||
static dllfunc_t avifile_funcs[] =
|
||||
{
|
||||
{ "AVIFileExit", (void **) &pAVIFileExit },
|
||||
{ "AVIFileGetStream", (void **) &pAVIFileGetStream },
|
||||
{ "AVIFileInit", (void **) &pAVIFileInit },
|
||||
{ "AVIFileOpenW", (void **) &pAVIFileOpenW },
|
||||
{ "AVIFileRelease", (void **) &pAVIFileRelease },
|
||||
{ "AVIStreamGetFrame", (void **) &pAVIStreamGetFrame },
|
||||
{ "AVIStreamGetFrameClose", (void **) &pAVIStreamGetFrameClose },
|
||||
{ "AVIStreamGetFrameOpen", (void **) &pAVIStreamGetFrameOpen },
|
||||
{ "AVIStreamInfoA", (void **) &pAVIStreamInfo },
|
||||
{ "AVIStreamRead", (void **) &pAVIStreamRead },
|
||||
{ "AVIStreamReadFormat", (void **) &pAVIStreamReadFormat },
|
||||
{ "AVIStreamRelease", (void **) &pAVIStreamRelease },
|
||||
{ "AVIStreamStart", (void **) &pAVIStreamStart },
|
||||
{ "AVIStreamTimeToSample", (void **) &pAVIStreamTimeToSample },
|
||||
};
|
||||
|
||||
dll_info_t avifile_dll = { "avifil32.dll", avifile_funcs, ARRAYSIZE( avifile_funcs ), false };
|
||||
|
||||
typedef struct movie_state_s
|
||||
{
|
||||
qboolean active;
|
||||
qboolean quiet; // ignore error messages
|
||||
|
||||
PAVIFILE pfile; // avi file pointer
|
||||
PAVISTREAM video_stream; // video stream pointer
|
||||
PGETFRAME video_getframe; // pointer to getframe object for video stream
|
||||
int video_frames; // total frames
|
||||
int video_xres; // video stream resolution
|
||||
int video_yres;
|
||||
float video_fps; // video stream fps
|
||||
|
||||
PAVISTREAM audio_stream; // audio stream pointer
|
||||
WAVEFORMAT *audio_header; // audio stream header
|
||||
int audio_header_size; // WAVEFORMAT is returned for PCM data; WAVEFORMATEX for others
|
||||
int audio_codec; // WAVE_FORMAT_PCM is oldstyle: anything else needs conversion
|
||||
int audio_length; // in converted samples
|
||||
int audio_bytes_per_sample; // guess.
|
||||
|
||||
// compressed audio specific data
|
||||
dword cpa_blockalign; // block size to read
|
||||
HACMSTREAM cpa_conversion_stream;
|
||||
ACMSTREAMHEADER cpa_conversion_header;
|
||||
byte *cpa_srcbuffer; // maintained buffer for raw data
|
||||
byte *cpa_dstbuffer;
|
||||
|
||||
dword cpa_blocknum; // current block
|
||||
dword cpa_blockpos; // read position in current block
|
||||
dword cpa_blockoffset; // corresponding offset in bytes in the output stream
|
||||
|
||||
// for additional unpack Ms-RLE codecs etc
|
||||
HDC hDC; // compatible DC
|
||||
HDRAWDIB hDD; // DrawDib handler
|
||||
HBITMAP hBitmap; // for DIB conversions
|
||||
byte *pframe_data; // converted framedata
|
||||
} movie_state_t;
|
||||
|
||||
static qboolean avi_initialized = false;
|
||||
static movie_state_t avi[2];
|
||||
|
||||
// Converts a compressed audio stream into uncompressed PCM.
|
||||
qboolean AVI_ACMConvertAudio( movie_state_t *Avi )
|
||||
{
|
||||
WAVEFORMATEX dest_header, *sh, *dh;
|
||||
AVISTREAMINFO stream_info;
|
||||
dword dest_length;
|
||||
short bits;
|
||||
|
||||
// WMA codecs, both versions - they simply don't work.
|
||||
if( Avi->audio_header->wFormatTag == 0x160 || Avi->audio_header->wFormatTag == 0x161 )
|
||||
{
|
||||
if( !Avi->quiet )
|
||||
Con_Reportf( S_ERROR "ACM does not support this audio codec.\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// get audio stream info to work with
|
||||
pAVIStreamInfo( Avi->audio_stream, &stream_info, sizeof( stream_info ));
|
||||
|
||||
if( Avi->audio_header_size < sizeof( WAVEFORMATEX ))
|
||||
{
|
||||
if( !Avi->quiet )
|
||||
Con_Reportf( S_ERROR "ACM failed to open conversion stream.\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
sh = (WAVEFORMATEX *)Avi->audio_header;
|
||||
bits = 16; // predict state
|
||||
|
||||
// how much of this is actually required?
|
||||
dest_header.wFormatTag = WAVE_FORMAT_PCM; // yay
|
||||
dest_header.wBitsPerSample = bits; // 16bit
|
||||
dest_header.nChannels = sh->nChannels;
|
||||
dest_header.nSamplesPerSec = sh->nSamplesPerSec; // take straight from the source stream
|
||||
dest_header.nAvgBytesPerSec = (bits >> 3) * sh->nChannels * sh->nSamplesPerSec;
|
||||
dest_header.nBlockAlign = (bits >> 3) * sh->nChannels;
|
||||
dest_header.cbSize = 0; // no more data.
|
||||
|
||||
dh = &dest_header;
|
||||
|
||||
// open the stream
|
||||
if( pacmStreamOpen( &Avi->cpa_conversion_stream, NULL, sh, dh, NULL, 0, 0, 0 ) != MMSYSERR_NOERROR )
|
||||
{
|
||||
// try with 8 bit destination instead
|
||||
bits = 8;
|
||||
|
||||
dest_header.wBitsPerSample = bits; // 8bit
|
||||
dest_header.nAvgBytesPerSec = ( bits >> 3 ) * sh->nChannels * sh->nSamplesPerSec;
|
||||
dest_header.nBlockAlign = ( bits >> 3 ) * sh->nChannels; // 1 sample at a time
|
||||
|
||||
if( pacmStreamOpen( &Avi->cpa_conversion_stream, NULL, sh, dh, NULL, 0, 0, 0 ) != MMSYSERR_NOERROR )
|
||||
{
|
||||
if( !Avi->quiet )
|
||||
Con_Reportf( S_ERROR "ACM failed to open conversion stream.\n" );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Avi->cpa_blockalign = sh->nBlockAlign;
|
||||
dest_length = 0;
|
||||
|
||||
// mp3 specific fix
|
||||
if( sh->wFormatTag == 0x55 )
|
||||
{
|
||||
LPMPEGLAYER3WAVEFORMAT k;
|
||||
|
||||
k = (LPMPEGLAYER3WAVEFORMAT)sh;
|
||||
Avi->cpa_blockalign = k->nBlockSize;
|
||||
}
|
||||
|
||||
// get the size of the output buffer for streaming the compressed audio
|
||||
if( pacmStreamSize( Avi->cpa_conversion_stream, Avi->cpa_blockalign, &dest_length, ACM_STREAMSIZEF_SOURCE ) != MMSYSERR_NOERROR )
|
||||
{
|
||||
if( !Avi->quiet )
|
||||
Con_Reportf( S_ERROR "Couldn't get ACM conversion stream size.\n" );
|
||||
pacmStreamClose( Avi->cpa_conversion_stream, 0 );
|
||||
return false;
|
||||
}
|
||||
|
||||
Avi->cpa_srcbuffer = (byte *)Mem_Malloc( cls.mempool, Avi->cpa_blockalign );
|
||||
Avi->cpa_dstbuffer = (byte *)Mem_Malloc( cls.mempool, dest_length ); // maintained buffer for raw data
|
||||
|
||||
// prep the headers!
|
||||
Avi->cpa_conversion_header.cbStruct = sizeof( ACMSTREAMHEADER );
|
||||
Avi->cpa_conversion_header.fdwStatus = 0;
|
||||
Avi->cpa_conversion_header.dwUser = 0; // no user data
|
||||
Avi->cpa_conversion_header.pbSrc = Avi->cpa_srcbuffer; // source buffer
|
||||
Avi->cpa_conversion_header.cbSrcLength = Avi->cpa_blockalign; // source buffer size
|
||||
Avi->cpa_conversion_header.cbSrcLengthUsed = 0;
|
||||
Avi->cpa_conversion_header.dwSrcUser = 0; // no user data
|
||||
Avi->cpa_conversion_header.pbDst = Avi->cpa_dstbuffer; // dest buffer
|
||||
Avi->cpa_conversion_header.cbDstLength = dest_length; // dest buffer size
|
||||
Avi->cpa_conversion_header.cbDstLengthUsed = 0;
|
||||
Avi->cpa_conversion_header.dwDstUser = 0; // no user data
|
||||
|
||||
if( pacmStreamPrepareHeader( Avi->cpa_conversion_stream, &Avi->cpa_conversion_header, 0 ) != MMSYSERR_NOERROR )
|
||||
{
|
||||
if( !Avi->quiet )
|
||||
Con_Reportf( S_ERROR "couldn't prepare stream headers.\n" );
|
||||
pacmStreamClose( Avi->cpa_conversion_stream, 0 );
|
||||
return false;
|
||||
}
|
||||
|
||||
Avi->cpa_blocknum = 0; // start at 0.
|
||||
Avi->cpa_blockpos = 0;
|
||||
Avi->cpa_blockoffset = 0;
|
||||
|
||||
pAVIStreamRead( Avi->audio_stream, Avi->cpa_blocknum * Avi->cpa_blockalign, Avi->cpa_blockalign, Avi->cpa_srcbuffer, Avi->cpa_blockalign, NULL, NULL );
|
||||
pacmStreamConvert( Avi->cpa_conversion_stream, &Avi->cpa_conversion_header, ACM_STREAMCONVERTF_BLOCKALIGN|ACM_STREAMCONVERTF_START );
|
||||
|
||||
// convert first chunk twice. it often fails the first time. BLACK MAGIC.
|
||||
pAVIStreamRead( Avi->audio_stream, Avi->cpa_blocknum * Avi->cpa_blockalign, Avi->cpa_blockalign, Avi->cpa_srcbuffer, Avi->cpa_blockalign, NULL, NULL );
|
||||
pacmStreamConvert( Avi->cpa_conversion_stream, &Avi->cpa_conversion_header, ACM_STREAMCONVERTF_BLOCKALIGN );
|
||||
|
||||
Avi->audio_bytes_per_sample = (bits >> 3 ) * Avi->audio_header->nChannels;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
qboolean AVI_GetVideoInfo( movie_state_t *Avi, int *xres, int *yres, float *duration )
|
||||
{
|
||||
if( !Avi->active )
|
||||
return false;
|
||||
|
||||
if( xres != NULL )
|
||||
*xres = Avi->video_xres;
|
||||
|
||||
if( yres != NULL )
|
||||
*yres = Avi->video_yres;
|
||||
|
||||
if( duration != NULL )
|
||||
*duration = (float)Avi->video_frames / Avi->video_fps;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// returns a unique frame identifier
|
||||
int AVI_GetVideoFrameNumber( movie_state_t *Avi, float time )
|
||||
{
|
||||
if( !Avi->active )
|
||||
return 0;
|
||||
|
||||
return (time * Avi->video_fps);
|
||||
}
|
||||
|
||||
int AVI_TimeToSoundPosition( movie_state_t *Avi, int time )
|
||||
{
|
||||
if( !Avi->active || !Avi->audio_stream )
|
||||
return 0;
|
||||
|
||||
// UNDONE: what about compressed audio?
|
||||
return pAVIStreamTimeToSample( Avi->audio_stream, time ) * Avi->audio_bytes_per_sample;
|
||||
}
|
||||
|
||||
// gets the raw frame data
|
||||
byte *AVI_GetVideoFrame( movie_state_t *Avi, int frame )
|
||||
{
|
||||
LPBITMAPINFOHEADER frame_info;
|
||||
byte *frame_raw;
|
||||
|
||||
if( !Avi->active ) return NULL;
|
||||
|
||||
if( frame >= Avi->video_frames )
|
||||
frame = Avi->video_frames - 1;
|
||||
|
||||
frame_info = (LPBITMAPINFOHEADER)pAVIStreamGetFrame( Avi->video_getframe, frame );
|
||||
frame_raw = (byte *)frame_info + frame_info->biSize + frame_info->biClrUsed * sizeof( RGBQUAD );
|
||||
pDrawDibDraw( Avi->hDD, Avi->hDC, 0, 0, Avi->video_xres, Avi->video_yres, frame_info, frame_raw, 0, 0, Avi->video_xres, Avi->video_yres, 0 );
|
||||
|
||||
return Avi->pframe_data;
|
||||
}
|
||||
|
||||
qboolean AVI_GetAudioInfo( movie_state_t *Avi, wavdata_t *snd_info )
|
||||
{
|
||||
if( !Avi->active || Avi->audio_stream == NULL || snd_info == NULL )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
snd_info->rate = Avi->audio_header->nSamplesPerSec;
|
||||
snd_info->channels = Avi->audio_header->nChannels;
|
||||
|
||||
if( Avi->audio_codec == WAVE_FORMAT_PCM ) // uncompressed audio!
|
||||
snd_info->width = ( Avi->audio_bytes_per_sample > Avi->audio_header->nChannels ) ? 2 : 1;
|
||||
else snd_info->width = 2; // assume compressed audio is always 16 bit
|
||||
|
||||
snd_info->size = snd_info->rate * snd_info->width * snd_info->channels;
|
||||
snd_info->loopStart = 0; // using loopStart as streampos
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// sync the current audio read to a specific offset
|
||||
qboolean AVI_SeekPosition( movie_state_t *Avi, dword offset )
|
||||
{
|
||||
int breaker;
|
||||
|
||||
if( offset < Avi->cpa_blockoffset ) // well, shit. we can't seek backwards... restart
|
||||
{
|
||||
if( Avi->cpa_blockoffset - offset < 500000 )
|
||||
return false; // don't bother if it's gonna catch up soon
|
||||
|
||||
Avi->cpa_blocknum = 0; // start at 0, eh.
|
||||
Avi->cpa_blockpos = 0;
|
||||
Avi->cpa_blockoffset = 0;
|
||||
|
||||
pAVIStreamRead( Avi->audio_stream, Avi->cpa_blocknum * Avi->cpa_blockalign, Avi->cpa_blockalign, Avi->cpa_srcbuffer, Avi->cpa_blockalign, NULL, NULL );
|
||||
pacmStreamConvert( Avi->cpa_conversion_stream, &Avi->cpa_conversion_header, ACM_STREAMCONVERTF_BLOCKALIGN|ACM_STREAMCONVERTF_START );
|
||||
|
||||
// convert first chunk twice. it often fails the first time. BLACK MAGIC.
|
||||
pAVIStreamRead( Avi->audio_stream, Avi->cpa_blocknum * Avi->cpa_blockalign, Avi->cpa_blockalign, Avi->cpa_srcbuffer, Avi->cpa_blockalign, NULL, NULL );
|
||||
pacmStreamConvert( Avi->cpa_conversion_stream, &Avi->cpa_conversion_header, ACM_STREAMCONVERTF_BLOCKALIGN );
|
||||
}
|
||||
|
||||
// now then: seek forwards to the required block
|
||||
breaker = 30; // maximum zero blocks: anti-freeze protection
|
||||
|
||||
while( Avi->cpa_blockoffset + Avi->cpa_conversion_header.cbDstLengthUsed < offset )
|
||||
{
|
||||
Avi->cpa_blocknum++;
|
||||
Avi->cpa_blockoffset += Avi->cpa_conversion_header.cbDstLengthUsed;
|
||||
|
||||
pAVIStreamRead( Avi->audio_stream, Avi->cpa_blocknum * Avi->cpa_blockalign, Avi->cpa_blockalign, Avi->cpa_srcbuffer, Avi->cpa_blockalign, NULL, NULL );
|
||||
pacmStreamConvert( Avi->cpa_conversion_stream, &Avi->cpa_conversion_header, ACM_STREAMCONVERTF_BLOCKALIGN );
|
||||
|
||||
if( Avi->cpa_conversion_header.cbDstLengthUsed == 0 )
|
||||
breaker--;
|
||||
else breaker = 30;
|
||||
|
||||
if( breaker <= 0 )
|
||||
return false;
|
||||
|
||||
Avi->cpa_blockpos = 0;
|
||||
}
|
||||
|
||||
// seek to the right position inside the block
|
||||
Avi->cpa_blockpos = offset - Avi->cpa_blockoffset;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// get a chunk of audio from the stream (in bytes)
|
||||
int AVI_GetAudioChunk( movie_state_t *Avi, char *audiodata, int offset, int length )
|
||||
{
|
||||
int result = 0;
|
||||
int i;
|
||||
|
||||
// zero data past the end of the file
|
||||
if( offset + length > Avi->audio_length )
|
||||
{
|
||||
if( offset <= Avi->audio_length )
|
||||
{
|
||||
int remaining_length = Avi->audio_length - offset;
|
||||
|
||||
AVI_GetAudioChunk( Avi, audiodata, offset, remaining_length );
|
||||
|
||||
for( i = remaining_length; i < length; i++ )
|
||||
audiodata[i] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we out of soundtrack, just zeroing buffer
|
||||
for( i = 0; i < length; i++ )
|
||||
audiodata[i] = 0;
|
||||
|
||||
// return length;
|
||||
}
|
||||
}
|
||||
|
||||
// uncompressed audio!
|
||||
if( Avi->audio_codec == WAVE_FORMAT_PCM )
|
||||
{
|
||||
// very simple - read straight out
|
||||
pAVIStreamRead( Avi->audio_stream, offset / Avi->audio_bytes_per_sample, length / Avi->audio_bytes_per_sample, audiodata, length, &result, NULL );
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
// compressed audio!
|
||||
result = 0;
|
||||
|
||||
// seek to correct chunk and all that stuff
|
||||
if( !AVI_SeekPosition( Avi, offset ))
|
||||
return 0; // don't continue if we're waiting for the play pointer to catch up
|
||||
|
||||
while( length > 0 )
|
||||
{
|
||||
int blockread = Avi->cpa_conversion_header.cbDstLengthUsed - Avi->cpa_blockpos;
|
||||
|
||||
if( blockread <= 0 ) // read next
|
||||
{
|
||||
Avi->cpa_blocknum++;
|
||||
Avi->cpa_blockoffset += Avi->cpa_conversion_header.cbDstLengthUsed;
|
||||
|
||||
pAVIStreamRead( Avi->audio_stream, Avi->cpa_blocknum * Avi->cpa_blockalign, Avi->cpa_blockalign, Avi->cpa_srcbuffer, Avi->cpa_blockalign, NULL, NULL );
|
||||
pacmStreamConvert( Avi->cpa_conversion_stream, &Avi->cpa_conversion_header, ACM_STREAMCONVERTF_BLOCKALIGN );
|
||||
|
||||
Avi->cpa_blockpos = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if( blockread > length )
|
||||
blockread = length;
|
||||
|
||||
// copy the data
|
||||
memcpy( audiodata + result, (void *)( Avi->cpa_dstbuffer + Avi->cpa_blockpos ), blockread );
|
||||
|
||||
Avi->cpa_blockpos += blockread;
|
||||
result += blockread;
|
||||
length -= blockread;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
void AVI_CloseVideo( movie_state_t *Avi )
|
||||
{
|
||||
if( Avi->active )
|
||||
{
|
||||
pAVIStreamGetFrameClose( Avi->video_getframe );
|
||||
|
||||
if( Avi->audio_stream != NULL )
|
||||
{
|
||||
pAVIStreamRelease( Avi->audio_stream );
|
||||
Mem_Free( Avi->audio_header );
|
||||
|
||||
if( Avi->audio_codec != WAVE_FORMAT_PCM )
|
||||
{
|
||||
pacmStreamUnprepareHeader( Avi->cpa_conversion_stream, &Avi->cpa_conversion_header, 0 );
|
||||
pacmStreamClose( Avi->cpa_conversion_stream, 0 );
|
||||
Mem_Free( Avi->cpa_srcbuffer );
|
||||
Mem_Free( Avi->cpa_dstbuffer );
|
||||
}
|
||||
}
|
||||
|
||||
pAVIStreamRelease( Avi->video_stream );
|
||||
|
||||
DeleteObject( Avi->hBitmap );
|
||||
pDrawDibClose( Avi->hDD );
|
||||
DeleteDC( Avi->hDC );
|
||||
}
|
||||
|
||||
memset( Avi, 0, sizeof( movie_state_t ));
|
||||
}
|
||||
|
||||
void AVI_OpenVideo( movie_state_t *Avi, const char *filename, qboolean load_audio, int quiet )
|
||||
{
|
||||
BITMAPINFOHEADER bmih;
|
||||
AVISTREAMINFO stream_info;
|
||||
int opened_streams = 0;
|
||||
LONG hr;
|
||||
wchar_t pathBuffer[MAX_PATH];
|
||||
|
||||
// default state: non-working.
|
||||
Avi->active = false;
|
||||
Avi->quiet = quiet;
|
||||
|
||||
// can't load Video For Windows :-(
|
||||
if( !avi_initialized ) return;
|
||||
|
||||
// convert to wide char
|
||||
if( MultiByteToWideChar( CP_UTF8, 0, filename, -1, pathBuffer, ARRAYSIZE( pathBuffer )) <= 0 )
|
||||
{
|
||||
Con_DPrintf( S_ERROR "filename buffer limit exceeded\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
// load the AVI
|
||||
hr = pAVIFileOpenW( &Avi->pfile, pathBuffer, OF_SHARE_DENY_WRITE, 0L );
|
||||
|
||||
if( hr != 0 ) // error opening AVI:
|
||||
{
|
||||
switch( hr )
|
||||
{
|
||||
case AVIERR_BADFORMAT:
|
||||
if( !Avi->quiet )
|
||||
Con_DPrintf( S_ERROR "corrupt file or unknown format.\n" );
|
||||
break;
|
||||
case AVIERR_MEMORY:
|
||||
if( !Avi->quiet )
|
||||
Con_DPrintf( S_ERROR "insufficient memory to open file.\n" );
|
||||
break;
|
||||
case AVIERR_FILEREAD:
|
||||
if( !Avi->quiet )
|
||||
Con_DPrintf( S_ERROR "disk error reading file.\n" );
|
||||
break;
|
||||
case AVIERR_FILEOPEN:
|
||||
if( !Avi->quiet )
|
||||
Con_DPrintf( S_ERROR "disk error opening file.\n" );
|
||||
break;
|
||||
case REGDB_E_CLASSNOTREG:
|
||||
default:
|
||||
if( !Avi->quiet )
|
||||
Con_DPrintf( S_ERROR "no handler found (or file not found).\n" );
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Avi->video_stream = Avi->audio_stream = NULL;
|
||||
|
||||
// open the streams until a stream is not available.
|
||||
while( 1 )
|
||||
{
|
||||
PAVISTREAM stream = NULL;
|
||||
|
||||
if( pAVIFileGetStream( Avi->pfile, &stream, 0L, opened_streams++ ) != AVIERR_OK )
|
||||
break;
|
||||
|
||||
if( stream == NULL )
|
||||
break;
|
||||
|
||||
pAVIStreamInfo( stream, &stream_info, sizeof( stream_info ));
|
||||
|
||||
if( stream_info.fccType == streamtypeVIDEO && Avi->video_stream == NULL )
|
||||
{
|
||||
Avi->video_stream = stream;
|
||||
Avi->video_frames = stream_info.dwLength;
|
||||
Avi->video_xres = stream_info.rcFrame.right - stream_info.rcFrame.left;
|
||||
Avi->video_yres = stream_info.rcFrame.bottom - stream_info.rcFrame.top;
|
||||
Avi->video_fps = (float)stream_info.dwRate / (float)stream_info.dwScale;
|
||||
}
|
||||
else if( stream_info.fccType == streamtypeAUDIO && Avi->audio_stream == NULL && load_audio )
|
||||
{
|
||||
int size;
|
||||
|
||||
Avi->audio_stream = stream;
|
||||
|
||||
// read the audio header
|
||||
pAVIStreamReadFormat( Avi->audio_stream, pAVIStreamStart( Avi->audio_stream ), 0, &size );
|
||||
|
||||
Avi->audio_header = (WAVEFORMAT *)Mem_Malloc( cls.mempool, size );
|
||||
pAVIStreamReadFormat( Avi->audio_stream, pAVIStreamStart( Avi->audio_stream ), Avi->audio_header, &size );
|
||||
Avi->audio_header_size = size;
|
||||
Avi->audio_codec = Avi->audio_header->wFormatTag;
|
||||
|
||||
// length of converted audio in samples
|
||||
Avi->audio_length = (int)((float)stream_info.dwLength / Avi->audio_header->nAvgBytesPerSec );
|
||||
Avi->audio_length *= Avi->audio_header->nSamplesPerSec;
|
||||
|
||||
if( Avi->audio_codec != WAVE_FORMAT_PCM )
|
||||
{
|
||||
if( !AVI_ACMConvertAudio( Avi ))
|
||||
{
|
||||
Mem_Free( Avi->audio_header );
|
||||
Avi->audio_stream = NULL;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else Avi->audio_bytes_per_sample = Avi->audio_header->nBlockAlign;
|
||||
Avi->audio_length *= Avi->audio_bytes_per_sample;
|
||||
}
|
||||
else
|
||||
{
|
||||
pAVIStreamRelease( stream );
|
||||
}
|
||||
}
|
||||
|
||||
// display error message-stream not found.
|
||||
if( Avi->video_stream == NULL )
|
||||
{
|
||||
if( Avi->pfile ) // if file is open, close it
|
||||
pAVIFileRelease( Avi->pfile );
|
||||
if( !Avi->quiet )
|
||||
Con_DPrintf( S_ERROR "couldn't find a valid video stream.\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
pAVIFileRelease( Avi->pfile ); // release the file
|
||||
Avi->video_getframe = pAVIStreamGetFrameOpen( Avi->video_stream, NULL ); // open the frame getter
|
||||
|
||||
if( Avi->video_getframe == NULL )
|
||||
{
|
||||
if( !Avi->quiet )
|
||||
Con_DPrintf( S_ERROR "error attempting to read video frames.\n" );
|
||||
return; // couldn't open frame getter.
|
||||
}
|
||||
|
||||
bmih.biSize = sizeof( BITMAPINFOHEADER );
|
||||
bmih.biPlanes = 1;
|
||||
bmih.biBitCount = 32;
|
||||
bmih.biCompression = BI_RGB;
|
||||
bmih.biWidth = Avi->video_xres;
|
||||
bmih.biHeight = -Avi->video_yres; // invert height to flip image upside down
|
||||
|
||||
Avi->hDC = CreateCompatibleDC( 0 );
|
||||
Avi->hDD = pDrawDibOpen();
|
||||
Avi->hBitmap = CreateDIBSection( Avi->hDC, (BITMAPINFO*)(&bmih), DIB_RGB_COLORS, (void**)(&Avi->pframe_data), NULL, 0 );
|
||||
SelectObject( Avi->hDC, Avi->hBitmap );
|
||||
|
||||
Avi->active = true; // done
|
||||
}
|
||||
|
||||
qboolean AVI_IsActive( movie_state_t *Avi )
|
||||
{
|
||||
if( Avi != NULL )
|
||||
return Avi->active;
|
||||
return false;
|
||||
}
|
||||
|
||||
movie_state_t *AVI_GetState( int num )
|
||||
{
|
||||
return &avi[num];
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
AVIKit user interface
|
||||
|
||||
=============
|
||||
*/
|
||||
movie_state_t *AVI_LoadVideo( const char *filename, qboolean load_audio )
|
||||
{
|
||||
movie_state_t *Avi;
|
||||
string path;
|
||||
const char *fullpath;
|
||||
|
||||
// fast reject
|
||||
if( !avi_initialized )
|
||||
return NULL;
|
||||
|
||||
// open cinematic
|
||||
Q_snprintf( path, sizeof( path ), "media/%s", filename );
|
||||
COM_DefaultExtension( path, ".avi", sizeof( path ));
|
||||
fullpath = FS_GetDiskPath( path, false );
|
||||
|
||||
if( FS_FileExists( path, false ) && !fullpath )
|
||||
{
|
||||
Con_Printf( "Couldn't load %s from packfile. Please extract it\n", path );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Avi = Mem_Malloc( cls.mempool, sizeof( movie_state_t ));
|
||||
AVI_OpenVideo( Avi, fullpath, load_audio, false );
|
||||
|
||||
if( !AVI_IsActive( Avi ))
|
||||
{
|
||||
AVI_FreeVideo( Avi ); // something bad happens
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// all done
|
||||
return Avi;
|
||||
}
|
||||
|
||||
void AVI_FreeVideo( movie_state_t *state )
|
||||
{
|
||||
if( !state ) return;
|
||||
|
||||
if( Mem_IsAllocatedExt( cls.mempool, state ))
|
||||
{
|
||||
AVI_CloseVideo( state );
|
||||
Mem_Free( state );
|
||||
}
|
||||
}
|
||||
|
||||
qboolean AVI_Initailize( void )
|
||||
{
|
||||
if( Sys_CheckParm( "-noavi" ))
|
||||
{
|
||||
Con_Printf( "AVI: Disabled\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !Sys_LoadLibrary( &avifile_dll ))
|
||||
return false;
|
||||
|
||||
if( !Sys_LoadLibrary( &msvfw_dll ))
|
||||
{
|
||||
Sys_FreeLibrary( &avifile_dll );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !Sys_LoadLibrary( &msacm_dll ))
|
||||
{
|
||||
Sys_FreeLibrary( &avifile_dll );
|
||||
Sys_FreeLibrary( &msvfw_dll );
|
||||
return false;
|
||||
}
|
||||
|
||||
avi_initialized = true;
|
||||
pAVIFileInit();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AVI_Shutdown( void )
|
||||
{
|
||||
if( !avi_initialized ) return;
|
||||
|
||||
pAVIFileExit();
|
||||
|
||||
Sys_FreeLibrary( &avifile_dll );
|
||||
Sys_FreeLibrary( &msvfw_dll );
|
||||
Sys_FreeLibrary( &msacm_dll );
|
||||
avi_initialized = false;
|
||||
}
|
||||
#endif // _WIN32
|
||||
@@ -42,8 +42,7 @@ void CL_PlayVideo_f( void )
|
||||
switch( Cmd_Argc( ))
|
||||
{
|
||||
case 2: // simple user version
|
||||
Q_snprintf( path, sizeof( path ), "media/%s", Cmd_Argv( 1 ));
|
||||
COM_DefaultExtension( path, ".avi", sizeof( path ));
|
||||
Q_snprintf( path, sizeof( path ), "media/%s.avi", Cmd_Argv( 1 ));
|
||||
SCR_PlayCinematic( path );
|
||||
break;
|
||||
case 3: // sequenced cinematics used this
|
||||
|
||||
@@ -373,7 +373,7 @@ CL_WriteDemoUserMessage
|
||||
Dumps the user message (demoaction)
|
||||
====================
|
||||
*/
|
||||
void GAME_EXPORT CL_WriteDemoUserMessage( int size, byte *buffer )
|
||||
void CL_WriteDemoUserMessage( const byte *buffer, size_t size )
|
||||
{
|
||||
if( !cls.demorecording || cls.demowaiting )
|
||||
return;
|
||||
|
||||
@@ -2229,3 +2229,4 @@ void CL_ThinkParticle( double frametime, particle_t *p )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -556,7 +556,7 @@ static void CL_InitTitles( const char *filename )
|
||||
|
||||
Q_snprintf( name, sizeof( name ), TEXT_MSGNAME, i );
|
||||
|
||||
cl_textmessage[i].pName = copystringpool( clgame.mempool, name );
|
||||
cl_textmessage[i].pName = _copystring( clgame.mempool, name, __FILE__, __LINE__ );
|
||||
cl_textmessage[i].pMessage = cl_textbuffer[i];
|
||||
}
|
||||
|
||||
@@ -3348,6 +3348,28 @@ DemoApi implementation
|
||||
|
||||
=================
|
||||
*/
|
||||
/*
|
||||
=================
|
||||
Demo_IsRecording
|
||||
|
||||
=================
|
||||
*/
|
||||
static int GAME_EXPORT Demo_IsRecording( void )
|
||||
{
|
||||
return cls.demorecording;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Demo_IsPlayingback
|
||||
|
||||
=================
|
||||
*/
|
||||
static int GAME_EXPORT Demo_IsPlayingback( void )
|
||||
{
|
||||
return cls.demoplayback;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Demo_IsTimeDemo
|
||||
@@ -3359,6 +3381,17 @@ static int GAME_EXPORT Demo_IsTimeDemo( void )
|
||||
return cls.timedemo;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Demo_WriteBuffer
|
||||
|
||||
=================
|
||||
*/
|
||||
static void GAME_EXPORT Demo_WriteBuffer( int size, byte *buffer )
|
||||
{
|
||||
CL_WriteDemoUserMessage( buffer, size );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
NetworkApi implementation
|
||||
@@ -3544,6 +3577,28 @@ static int GAME_EXPORT NetAPI_CompareAdr( netadr_t *a, netadr_t *b )
|
||||
return NET_CompareAdr( *a, *b );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
NetAPI_StringToAdr
|
||||
|
||||
=================
|
||||
*/
|
||||
static int GAME_EXPORT NetAPI_StringToAdr( char *s, netadr_t *a )
|
||||
{
|
||||
return NET_StringToAdr( s, a );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
NetAPI_ValueForKey
|
||||
|
||||
=================
|
||||
*/
|
||||
static const char * GAME_EXPORT NetAPI_ValueForKey( const char *s, const char *key )
|
||||
{
|
||||
return Info_ValueForKey( s, key );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
NetAPI_RemoveKey
|
||||
@@ -3740,10 +3795,10 @@ static event_api_t gEventApi =
|
||||
|
||||
static demo_api_t gDemoApi =
|
||||
{
|
||||
(void *)CL_IsRecordDemo,
|
||||
(void *)CL_IsPlaybackDemo,
|
||||
Demo_IsRecording,
|
||||
Demo_IsPlayingback,
|
||||
Demo_IsTimeDemo,
|
||||
CL_WriteDemoUserMessage,
|
||||
Demo_WriteBuffer,
|
||||
};
|
||||
|
||||
net_api_t gNetApi =
|
||||
@@ -3755,8 +3810,8 @@ net_api_t gNetApi =
|
||||
NetAPI_CancelAllRequests,
|
||||
NetAPI_AdrToString,
|
||||
NetAPI_CompareAdr,
|
||||
(void *)NET_StringToAdr,
|
||||
Info_ValueForKey,
|
||||
NetAPI_StringToAdr,
|
||||
NetAPI_ValueForKey,
|
||||
NetAPI_RemoveKey,
|
||||
NetAPI_SetValueForKey,
|
||||
};
|
||||
|
||||
@@ -302,11 +302,14 @@ void UI_ConnectionProgress_ParseServerInfo( const char *server )
|
||||
|
||||
static void GAME_EXPORT UI_DrawLogo( const char *filename, float x, float y, float width, float height )
|
||||
{
|
||||
static float cin_time;
|
||||
static int last_frame = -1;
|
||||
byte *cin_data = NULL;
|
||||
movie_state_t *cin_state;
|
||||
int cin_frame;
|
||||
qboolean redraw = false;
|
||||
|
||||
if( !gameui.drawLogo )
|
||||
return;
|
||||
|
||||
if( !gameui.drawLogo ) return;
|
||||
cin_state = AVI_GetState( CIN_LOGO );
|
||||
|
||||
if( !AVI_IsActive( cin_state ))
|
||||
@@ -333,25 +336,37 @@ static void GAME_EXPORT UI_DrawLogo( const char *filename, float x, float y, flo
|
||||
gameui.drawLogo = false;
|
||||
return;
|
||||
}
|
||||
|
||||
cin_time = 0.0f;
|
||||
last_frame = -1;
|
||||
}
|
||||
|
||||
if( width <= 0 || height <= 0 )
|
||||
{
|
||||
// precache call, don't draw
|
||||
cin_time = 0.0f;
|
||||
last_frame = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
AVI_SetParm( cin_state,
|
||||
AVI_RENDER_TEXNUM, 0,
|
||||
AVI_RENDER_X, (int)x,
|
||||
AVI_RENDER_Y, (int)y,
|
||||
AVI_RENDER_W, (int)width,
|
||||
AVI_RENDER_H, (int)height,
|
||||
AVI_PARM_LAST );
|
||||
// advances cinematic time (ignores maxfps and host_framerate settings)
|
||||
cin_time += host.realframetime;
|
||||
|
||||
// restarts the cinematic
|
||||
if( cin_time > gameui.logo_length )
|
||||
cin_time = 0.0f;
|
||||
|
||||
// read the next frame
|
||||
if( !AVI_Think( cin_state ))
|
||||
AVI_SetParm( cin_state, AVI_REWIND, AVI_PARM_LAST );
|
||||
cin_frame = AVI_GetVideoFrameNumber( cin_state, cin_time );
|
||||
|
||||
if( cin_frame != last_frame )
|
||||
{
|
||||
cin_data = AVI_GetVideoFrame( cin_state, cin_frame );
|
||||
last_frame = cin_frame;
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
ref.dllFuncs.R_DrawStretchRaw( x, y, width, height, gameui.logo_xres, gameui.logo_yres, cin_data, redraw );
|
||||
}
|
||||
|
||||
static int GAME_EXPORT UI_GetLogoWidth( void )
|
||||
|
||||
@@ -76,7 +76,6 @@ static CVAR_DEFINE_AUTO( cl_upmax, "1200", FCVAR_ARCHIVE, "max allowed incoming
|
||||
|
||||
CVAR_DEFINE_AUTO( cl_lw, "1", FCVAR_ARCHIVE|FCVAR_USERINFO, "enable client weapon predicting" );
|
||||
CVAR_DEFINE_AUTO( cl_charset, "utf-8", FCVAR_ARCHIVE, "1-byte charset to use (iconv style)" );
|
||||
CVAR_DEFINE_AUTO( cl_trace_consistency, "0", FCVAR_ARCHIVE, "enable consistency info tracing (good for developers)" );
|
||||
CVAR_DEFINE_AUTO( cl_trace_stufftext, "0", FCVAR_ARCHIVE, "enable stufftext (server-to-client console commands) tracing (good for developers)" );
|
||||
CVAR_DEFINE_AUTO( cl_trace_messages, "0", FCVAR_ARCHIVE|FCVAR_CHEAT, "enable message names tracing (good for developers)" );
|
||||
CVAR_DEFINE_AUTO( cl_trace_events, "0", FCVAR_ARCHIVE|FCVAR_CHEAT, "enable events tracing (good for developers)" );
|
||||
@@ -718,20 +717,11 @@ static void CL_WritePacket( void )
|
||||
int numbackup, maxbackup, maxcmds;
|
||||
const connprotocol_t proto = cls.legacymode;
|
||||
|
||||
// FIXME: on Xash protocol we don't send move commands until ca_active
|
||||
// to prevent outgoing_command outrun incoming_acknowledged
|
||||
// which is fatal for some buggy mods like TFC
|
||||
//
|
||||
// ... but GoldSrc don't have (real) ca_validate state, so we consider
|
||||
// ca_validate the same as ca_active, otherwise we don't pass validation
|
||||
// of server-side mods like ReAuthCheck
|
||||
const connstate_t min_state = proto == PROTO_GOLDSRC ? ca_validate : ca_active;
|
||||
|
||||
// don't send anything if playing back a demo
|
||||
if( cls.demoplayback || cls.state < ca_connected || cls.state == ca_cinematic )
|
||||
return;
|
||||
|
||||
if( cls.state < min_state )
|
||||
if( cls.state <= ca_connected )
|
||||
{
|
||||
Netchan_TransmitBits( &cls.netchan, 0, "" );
|
||||
return;
|
||||
@@ -1598,9 +1588,6 @@ void CL_SetupNetchanForProtocol( connprotocol_t proto )
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if( !Host_IsLocalClient( ))
|
||||
SetBits( flags, NETCHAN_USE_LZSS );
|
||||
|
||||
cls.extensions = Q_atoi( Info_ValueForKey( Cmd_Argv( 1 ), "ext" ));
|
||||
|
||||
if( FBitSet( cls.extensions, NET_EXT_SPLITSIZE ))
|
||||
@@ -3394,7 +3381,6 @@ static void CL_InitLocal( void )
|
||||
|
||||
Cvar_RegisterVariable( &rcon_address );
|
||||
|
||||
Cvar_RegisterVariable( &cl_trace_consistency );
|
||||
Cvar_RegisterVariable( &cl_trace_stufftext );
|
||||
Cvar_RegisterVariable( &cl_trace_messages );
|
||||
Cvar_RegisterVariable( &cl_trace_events );
|
||||
@@ -3666,8 +3652,6 @@ void CL_Init( void )
|
||||
if( !CL_LoadProgs( libpath ))
|
||||
Host_Error( "can't initialize %s: %s\n", libpath, COM_GetLibraryError( ));
|
||||
|
||||
ID_Init();
|
||||
|
||||
cls.build_num = 0;
|
||||
cls.initialized = true;
|
||||
cl.maxclients = 1; // allow to drawing player in menu
|
||||
|
||||
@@ -1614,23 +1614,6 @@ void CL_UpdateUserPings( sizebuf_t *msg )
|
||||
}
|
||||
}
|
||||
|
||||
static const char *CL_CheckTypeToString( int check_type )
|
||||
{
|
||||
// renamed so they have same width and look better in console output
|
||||
switch( check_type )
|
||||
{
|
||||
case force_exactfile:
|
||||
return "exactfile";
|
||||
case force_model_samebounds:
|
||||
return "samebounds";
|
||||
case force_model_specifybounds:
|
||||
return "specbounds";
|
||||
case force_model_specifybounds_if_avail:
|
||||
return "specbounds2";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
static void CL_SendConsistencyInfo( sizebuf_t *msg, connprotocol_t proto )
|
||||
{
|
||||
qboolean user_changed_diskfile;
|
||||
@@ -1896,9 +1879,6 @@ static void CL_ParseConsistencyInfo( sizebuf_t *msg, connprotocol_t proto )
|
||||
return;
|
||||
}
|
||||
|
||||
if( cl_trace_consistency.value )
|
||||
Con_Printf( "Server wants consistency of the following resources:\n" );
|
||||
|
||||
skip_crc_change = NULL;
|
||||
lastcheck = 0;
|
||||
|
||||
@@ -1930,7 +1910,7 @@ static void CL_ParseConsistencyInfo( sizebuf_t *msg, connprotocol_t proto )
|
||||
pc = &cl.consistency_list[cl.num_consistency];
|
||||
cl.num_consistency++;
|
||||
|
||||
memset( pc, 0, sizeof( *pc ));
|
||||
memset( pc, 0, sizeof( consistency_t ));
|
||||
pc->filename = pResource->szFileName;
|
||||
pc->issound = (pResource->type == t_sound);
|
||||
pc->orig_index = delta;
|
||||
@@ -1943,9 +1923,6 @@ static void CL_ParseConsistencyInfo( sizebuf_t *msg, connprotocol_t proto )
|
||||
pc->check_type = pResource->rguc_reserved[0];
|
||||
}
|
||||
|
||||
if( cl_trace_consistency.value )
|
||||
Con_Printf( "%s\t%s\t%s\n", COM_ResourceTypeFromIndex( pResource->type ), CL_CheckTypeToString( pc->check_type ), pc->filename );
|
||||
|
||||
skip_crc_change = pResource;
|
||||
lastcheck = delta;
|
||||
}
|
||||
|
||||
@@ -91,11 +91,11 @@ static void CL_ParseNewMovevars( sizebuf_t *msg )
|
||||
|
||||
typedef struct delta_header_t
|
||||
{
|
||||
qboolean remove;
|
||||
qboolean custom;
|
||||
qboolean instanced;
|
||||
uint16_t instanced_baseline_index;
|
||||
uint16_t offset;
|
||||
qboolean remove : 1;
|
||||
qboolean custom : 1;
|
||||
qboolean instanced : 1;
|
||||
uint instanced_baseline_index : 6;
|
||||
uint offset : 6;
|
||||
} delta_header_t;
|
||||
|
||||
static int CL_ParseDeltaHeader( sizebuf_t *msg, qboolean delta, int oldnum, struct delta_header_t *hdr )
|
||||
@@ -160,47 +160,33 @@ static int CL_GetEntityDelta( const struct delta_header_t *hdr, int entnum )
|
||||
return DT_ENTITY_STATE_T;
|
||||
}
|
||||
|
||||
static int CL_FlushEntityPacketGS( frame_t *frame, sizebuf_t *msg )
|
||||
static void CL_FlushEntityPacketGS( frame_t *frame, sizebuf_t *msg )
|
||||
{
|
||||
int playerbytes = 0, numbase = 0;
|
||||
|
||||
frame->valid = false;
|
||||
cl.validsequence = 0; // can't render a frame
|
||||
|
||||
// read it all but ignore it
|
||||
while( 1 )
|
||||
{
|
||||
int newnum, bufstart;
|
||||
int num = 0;
|
||||
entity_state_t from = { 0 }, to;
|
||||
delta_header_t hdr;
|
||||
qboolean player;
|
||||
|
||||
if( MSG_ReadWord( msg ) != 0 )
|
||||
{
|
||||
MSG_SeekToBit( msg, -16, SEEK_CUR );
|
||||
numbase = newnum = CL_ParseDeltaHeader( msg, true, numbase, &hdr );
|
||||
num = CL_ParseDeltaHeader( msg, false, num, &hdr );
|
||||
}
|
||||
else break;
|
||||
|
||||
if( MSG_CheckOverflow( msg ))
|
||||
Host_Error( "%s: overflow\n", __func__ );
|
||||
|
||||
player = CL_IsPlayerIndex( newnum );
|
||||
bufstart = MSG_GetNumBytesRead( msg );
|
||||
|
||||
if( hdr.remove )
|
||||
continue;
|
||||
|
||||
Delta_ReadGSFields( msg, CL_GetEntityDelta( &hdr, newnum ), &from, &to, cl.mtime[0] );
|
||||
|
||||
if( player )
|
||||
playerbytes += MSG_GetNumBytesRead( msg ) - bufstart;
|
||||
Delta_ReadGSFields( msg, CL_GetEntityDelta( &hdr, num ), &from, &to, cl.mtime[0] );
|
||||
}
|
||||
|
||||
if( MSG_CheckOverflow( msg ))
|
||||
Host_Error( "%s: overflow\n", __func__ );
|
||||
|
||||
return playerbytes;
|
||||
}
|
||||
|
||||
static void CL_DeltaEntityGS( const delta_header_t *hdr, sizebuf_t *msg, frame_t *frame, int newnum, const entity_state_t *from )
|
||||
@@ -217,7 +203,7 @@ static void CL_DeltaEntityGS( const delta_header_t *hdr, sizebuf_t *msg, frame_t
|
||||
if(( newnum < 0 ) || ( newnum >= clgame.maxEntities ))
|
||||
{
|
||||
Con_DPrintf( S_ERROR "CL_DeltaEntity: invalid newnum: %d\n", newnum );
|
||||
Host_Error( "%s: bad delta entity number: %i\n", __func__, newnum );
|
||||
Host_Error( "%s: bad delta entity number: %i", __func__, newnum );
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -281,7 +267,7 @@ static void CL_CopyPacketEntity( frame_t *frame, int num, const entity_state_t *
|
||||
static int CL_ParsePacketEntitiesGS( sizebuf_t *msg, qboolean delta )
|
||||
{
|
||||
frame_t *frame, *oldframe;
|
||||
int oldindex, oldnum, numbase = 0;
|
||||
int oldindex, newnum, oldnum, numbase = 0;
|
||||
entity_state_t *oldent;
|
||||
int count;
|
||||
int playerbytes = 0;
|
||||
@@ -328,7 +314,7 @@ static int CL_ParsePacketEntitiesGS( sizebuf_t *msg, qboolean delta )
|
||||
// read it all but ignore it
|
||||
while( 1 )
|
||||
{
|
||||
int bufstart, newnum;
|
||||
int bufstart;
|
||||
qboolean player;
|
||||
delta_header_t hdr;
|
||||
int val = MSG_ReadWord( msg );
|
||||
|
||||
@@ -233,11 +233,6 @@ static intptr_t pfnRenderGetParm( int parm, int arg )
|
||||
return CL_RenderGetParm( parm, arg, true );
|
||||
}
|
||||
|
||||
static void pfnAVI_StreamSound( movie_state_t *avi, int entnum, float fvol, float attn, float synctime )
|
||||
{
|
||||
return; // stub, use AVI_SetParm and AVI_Think to stream AVI sound
|
||||
}
|
||||
|
||||
static render_api_t gRenderAPI =
|
||||
{
|
||||
pfnRenderGetParm, // GL_RenderGetParm,
|
||||
@@ -263,16 +258,16 @@ static render_api_t gRenderAPI =
|
||||
NULL, // DrawSingleDecal,
|
||||
NULL, // R_DecalSetupVerts,
|
||||
NULL, // R_EntityRemoveDecals,
|
||||
AVI_LoadVideo,
|
||||
AVI_GetVideoInfo,
|
||||
AVI_GetVideoFrameNumber,
|
||||
AVI_GetVideoFrame,
|
||||
(void*)AVI_LoadVideo,
|
||||
(void*)AVI_GetVideoInfo,
|
||||
(void*)AVI_GetVideoFrameNumber,
|
||||
(void*)AVI_GetVideoFrame,
|
||||
NULL, // R_UploadStretchRaw,
|
||||
AVI_FreeVideo,
|
||||
AVI_IsActive,
|
||||
pfnAVI_StreamSound,
|
||||
AVI_Think,
|
||||
AVI_SetParm,
|
||||
(void*)AVI_FreeVideo,
|
||||
(void*)AVI_IsActive,
|
||||
S_StreamAviSamples,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL, // GL_Bind,
|
||||
NULL, // GL_SelectTexture,
|
||||
NULL, // GL_LoadTexMatrixExt,
|
||||
|
||||
@@ -24,6 +24,11 @@ AVI PLAYING
|
||||
=================================================================
|
||||
*/
|
||||
|
||||
static int xres, yres;
|
||||
static float video_duration;
|
||||
static float cin_time;
|
||||
static int cin_frame;
|
||||
static wavdata_t cin_audio;
|
||||
static movie_state_t *cin_state;
|
||||
|
||||
/*
|
||||
@@ -83,17 +88,7 @@ void SCR_CheckStartupVids( void )
|
||||
char *pfile;
|
||||
string token;
|
||||
|
||||
#if 0
|
||||
if( host_developer.value )
|
||||
{
|
||||
// don't run movies where we in developer-mode
|
||||
cls.movienum = -1;
|
||||
CL_CheckStartupDemos();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if( Sys_CheckParm( "-nointro" ) || cls.demonum != -1 || GameState->nextstate != STATE_RUNFRAME )
|
||||
if( Sys_CheckParm( "-nointro" ) || host_developer.value || cls.demonum != -1 || GameState->nextstate != STATE_RUNFRAME )
|
||||
{
|
||||
// don't run movies where we in developer-mode
|
||||
cls.movienum = -1;
|
||||
@@ -152,9 +147,23 @@ void SCR_RunCinematic( void )
|
||||
Key_SetKeyDest( key_menu );
|
||||
S_StopStreaming();
|
||||
cls.movienum = -1;
|
||||
cin_time = 0.0f;
|
||||
cls.signon = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// advances cinematic time (ignores maxfps and host_framerate settings)
|
||||
cin_time += host.realframetime;
|
||||
|
||||
// stop the video after it finishes
|
||||
if( cin_time > video_duration + 0.1f )
|
||||
{
|
||||
SCR_NextMovie( );
|
||||
return;
|
||||
}
|
||||
|
||||
// read the next frame
|
||||
cin_frame = AVI_GetVideoFrameNumber( cin_state, cin_time );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -167,11 +176,21 @@ should be skipped
|
||||
*/
|
||||
qboolean SCR_DrawCinematic( void )
|
||||
{
|
||||
if( !ref.initialized )
|
||||
static int last_frame = -1;
|
||||
qboolean redraw = false;
|
||||
byte *frame = NULL;
|
||||
|
||||
if( !ref.initialized || cin_time <= 0.0f )
|
||||
return false;
|
||||
|
||||
if( !AVI_Think( cin_state ))
|
||||
return SCR_NextMovie();
|
||||
if( cin_frame != last_frame )
|
||||
{
|
||||
frame = AVI_GetVideoFrame( cin_state, cin_frame );
|
||||
last_frame = cin_frame;
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
ref.dllFuncs.R_DrawStretchRaw( 0, 0, refState.width, refState.height, xres, yres, frame, redraw );
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -200,28 +219,45 @@ qboolean SCR_PlayCinematic( const char *arg )
|
||||
return false;
|
||||
}
|
||||
|
||||
if( AVI_HaveAudioTrack( cin_state ))
|
||||
if( !( AVI_GetVideoInfo( cin_state, &xres, &yres, &video_duration ))) // couldn't open this at all.
|
||||
{
|
||||
AVI_CloseVideo( cin_state );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( AVI_GetAudioInfo( cin_state, &cin_audio ))
|
||||
{
|
||||
// begin streaming
|
||||
S_StopAllSounds( true );
|
||||
S_StartStreaming();
|
||||
}
|
||||
|
||||
AVI_SetParm( cin_state,
|
||||
AVI_RENDER_X, 0,
|
||||
AVI_RENDER_Y, 0,
|
||||
AVI_RENDER_W, -1,
|
||||
AVI_RENDER_H, -1,
|
||||
AVI_PARM_LAST );
|
||||
|
||||
UI_SetActiveMenu( false );
|
||||
cls.state = ca_cinematic;
|
||||
Con_FastClose();
|
||||
cin_time = 0.0f;
|
||||
cls.signon = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int SCR_GetAudioChunk( char *rawdata, int length )
|
||||
{
|
||||
int r;
|
||||
|
||||
r = AVI_GetAudioChunk( cin_state, rawdata, cin_audio.loopStart, length );
|
||||
cin_audio.loopStart += r; // advance play position
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
wavdata_t *SCR_GetMovieInfo( void )
|
||||
{
|
||||
if( AVI_IsActive( cin_state ))
|
||||
return &cin_audio;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
SCR_StopCinematic
|
||||
@@ -234,6 +270,7 @@ void SCR_StopCinematic( void )
|
||||
|
||||
AVI_CloseVideo( cin_state );
|
||||
S_StopStreaming();
|
||||
cin_time = 0.0f;
|
||||
|
||||
cls.state = ca_disconnected;
|
||||
cls.signon = 0;
|
||||
|
||||
@@ -688,7 +688,6 @@ extern convar_t r_showtextures;
|
||||
extern convar_t cl_bmodelinterp;
|
||||
extern convar_t cl_lw; // local weapons
|
||||
extern convar_t cl_charset;
|
||||
extern convar_t cl_trace_consistency;
|
||||
extern convar_t cl_trace_stufftext;
|
||||
extern convar_t cl_trace_messages;
|
||||
extern convar_t cl_trace_events;
|
||||
@@ -768,7 +767,7 @@ void CL_StartupDemoHeader( void );
|
||||
void CL_DrawDemoRecording( void );
|
||||
void CL_WriteDemoUserCmd( int cmdnumber );
|
||||
void CL_WriteDemoMessage( qboolean startup, int start, sizebuf_t *msg );
|
||||
void CL_WriteDemoUserMessage( int size, byte *buffer );
|
||||
void CL_WriteDemoUserMessage( const byte *buffer, size_t size );
|
||||
qboolean CL_DemoReadMessage( byte *buffer, size_t *length );
|
||||
void CL_DemoInterpolateAngles( void );
|
||||
void CL_CheckStartupDemos( void );
|
||||
@@ -1120,7 +1119,7 @@ void Con_PageUp( int lines );
|
||||
//
|
||||
// s_main.c
|
||||
//
|
||||
typedef int sound_t;
|
||||
void S_StreamAviSamples( void *Avi, int entnum, float fvol, float attn, float synctime );
|
||||
void S_StartBackgroundTrack( const char *intro, const char *loop, int position, qboolean fullpath );
|
||||
void S_StopBackgroundTrack( void );
|
||||
void S_StreamSetPause( int pause );
|
||||
@@ -1209,13 +1208,6 @@ void Key_EnableTextInput( qboolean enable, qboolean force );
|
||||
int Key_ToUpper( int key );
|
||||
void OSK_Draw( void );
|
||||
|
||||
//
|
||||
// identification.c
|
||||
//
|
||||
void ID_Init( void );
|
||||
const char *ID_GetMD5( void );
|
||||
void GAME_EXPORT ID_SetCustomClientID( const char *id );
|
||||
|
||||
extern rgba_t g_color_table[8];
|
||||
extern triangleapi_t gTriApi;
|
||||
extern net_api_t gNetApi;
|
||||
|
||||
@@ -902,10 +902,9 @@ static void Touch_AddButton_f( void )
|
||||
rgba_t color;
|
||||
int argc = Cmd_Argc( );
|
||||
touch_button_t *button = NULL;
|
||||
const char *name, *command;
|
||||
const char *name, *texture, *command;
|
||||
float x1, y1, x2, y2;
|
||||
qboolean privileged = Cmd_CurrentCommandIsPrivileged();
|
||||
string texture;
|
||||
|
||||
if( argc < 4 )
|
||||
{
|
||||
@@ -914,18 +913,9 @@ static void Touch_AddButton_f( void )
|
||||
}
|
||||
|
||||
name = Cmd_Argv( 1 );
|
||||
Q_strncpy( texture, Cmd_Argv( 2 ), sizeof( texture ));
|
||||
texture = Cmd_Argv( 2 );
|
||||
command = Cmd_Argv( 3 );
|
||||
|
||||
// HACKHACK: old engine specifically used .tga for touch buttons
|
||||
// and because new engine extras.pk3 don't have .tga textures
|
||||
// (which instead were converted to .png) strip extension to let
|
||||
// to let imagelib choose better format
|
||||
//
|
||||
// Remove this when old engine migration would be done
|
||||
if( Q_stricmp( COM_FileExtension( texture ), "tga" ))
|
||||
COM_StripExtension( texture );
|
||||
|
||||
if( argc < 8 )
|
||||
{
|
||||
x1 = y1 = 0.4f;
|
||||
|
||||
@@ -51,7 +51,7 @@ static const keyname_t keynames[] =
|
||||
{"CTRL", K_CTRL, "+attack" },
|
||||
{"SHIFT", K_SHIFT, "+speed" },
|
||||
{"CAPSLOCK", K_CAPSLOCK, "" },
|
||||
{"SCROLLOCK", K_SCROLLLOCK, "" },
|
||||
{"SCROLLOCK", K_SCROLLOCK, "" },
|
||||
{"F1", K_F1, "cmd help" },
|
||||
{"F2", K_F2, "menu_savegame" },
|
||||
{"F3", K_F3, "menu_loadgame" },
|
||||
@@ -215,7 +215,7 @@ const char *Key_KeynumToString( int keynum )
|
||||
return "<OUT OF RANGE>";
|
||||
|
||||
// check for printable ascii (don't use quote)
|
||||
if( keynum > 32 && keynum < 127 && keynum != '"' && keynum != ';' && keynum != K_SCROLLLOCK )
|
||||
if( keynum > 32 && keynum < 127 && keynum != '"' && keynum != ';' && keynum != K_SCROLLOCK )
|
||||
{
|
||||
tinystr[0] = keynum;
|
||||
tinystr[1] = 0;
|
||||
@@ -861,9 +861,7 @@ void GAME_EXPORT Key_ClearStates( void )
|
||||
|
||||
for( i = 0; i < 256; i++ )
|
||||
{
|
||||
if( i >= K_MOUSE1 && i <= K_MOUSE5 )
|
||||
IN_MouseEvent( i - K_MOUSE1, false );
|
||||
else
|
||||
if( keys[i].down && i < K_MOUSE1 && i > K_MOUSE5 )
|
||||
Key_Event( i, false );
|
||||
|
||||
keys[i].down = 0;
|
||||
@@ -871,6 +869,9 @@ void GAME_EXPORT Key_ClearStates( void )
|
||||
keys[i].gamedown = 0;
|
||||
}
|
||||
|
||||
for( i = K_MOUSE1; i < K_MOUSE5; i++ ) // from K_MOUSE1 to K_MOUSE5
|
||||
IN_MouseEvent( i - K_MOUSE1, false );
|
||||
|
||||
if( clgame.hInstance )
|
||||
clgame.dllFuncs.IN_ClearStates();
|
||||
}
|
||||
|
||||
@@ -312,7 +312,7 @@ static int DLY_Init( int idelay, float delay )
|
||||
|
||||
cur = &rgsxdly[idelay];
|
||||
cur->cdelaysamplesmax = ((int)(delay * idsp_dma_speed) << sxhires) + 1;
|
||||
cur->lpdelayline = (int *)Mem_Calloc( sndpool, cur->cdelaysamplesmax * sizeof( int ));
|
||||
cur->lpdelayline = (int *)Z_Calloc( cur->cdelaysamplesmax * sizeof( int ));
|
||||
cur->xfade = 0;
|
||||
|
||||
// init modulation
|
||||
|
||||
@@ -107,18 +107,17 @@ S_CreateDefaultSound
|
||||
*/
|
||||
static wavdata_t *S_CreateDefaultSound( void )
|
||||
{
|
||||
wavdata_t *sc;
|
||||
uint samples = SOUND_DMA_SPEED;
|
||||
uint channels = 1;
|
||||
uint width = 2;
|
||||
size_t size = samples * width * channels;
|
||||
wavdata_t *sc;
|
||||
|
||||
sc = Mem_Calloc( sndpool, sizeof( wavdata_t ) + size );
|
||||
sc->width = width;
|
||||
sc->channels = channels;
|
||||
sc = Mem_Calloc( sndpool, sizeof( wavdata_t ));
|
||||
|
||||
sc->width = 2;
|
||||
sc->channels = 1;
|
||||
sc->loopStart = 0;
|
||||
sc->rate = SOUND_DMA_SPEED;
|
||||
sc->samples = samples;
|
||||
sc->size = size;
|
||||
sc->samples = SOUND_DMA_SPEED;
|
||||
sc->size = sc->samples * sc->width * sc->channels;
|
||||
sc->buffer = Mem_Calloc( sndpool, sc->size );
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ GNU General Public License for more details.
|
||||
#include "pm_local.h"
|
||||
#include "platform/platform.h"
|
||||
|
||||
#define SND_CLIP_DISTANCE 1000.0f
|
||||
|
||||
dma_t dma;
|
||||
poolhandle_t sndpool;
|
||||
static soundfade_t soundfade;
|
||||
@@ -1109,7 +1111,7 @@ rawchan_t *S_FindRawChannel( int entnum, qboolean create )
|
||||
S_RawSamplesStereo
|
||||
===================
|
||||
*/
|
||||
uint S_RawSamplesStereo( portable_samplepair_t *rawsamples, uint rawend, uint max_samples, uint samples, uint rate, word width, word channels, const byte *data )
|
||||
static uint S_RawSamplesStereo( portable_samplepair_t *rawsamples, uint rawend, uint max_samples, uint samples, uint rate, word width, word channels, const byte *data )
|
||||
{
|
||||
uint fracstep, samplefrac;
|
||||
uint src, dst;
|
||||
@@ -1191,6 +1193,100 @@ void S_RawEntSamples( int entnum, uint samples, uint rate, word width, word chan
|
||||
ch->leftvol = ch->rightvol = snd_vol;
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
S_RawSamples
|
||||
===================
|
||||
*/
|
||||
void S_RawSamples( uint samples, uint rate, word width, word channels, const byte *data, int entnum )
|
||||
{
|
||||
int snd_vol = 128;
|
||||
|
||||
if( entnum < 0 ) snd_vol = 256; // bg track or movie track
|
||||
|
||||
S_RawEntSamples( entnum, samples, rate, width, channels, data, snd_vol );
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
S_PositionedRawSamples
|
||||
===================
|
||||
*/
|
||||
void S_StreamAviSamples( void *Avi, int entnum, float fvol, float attn, float synctime )
|
||||
{
|
||||
int bufferSamples;
|
||||
int fileSamples;
|
||||
byte raw[MAX_RAW_SAMPLES];
|
||||
float duration = 0.0f;
|
||||
int r, fileBytes;
|
||||
rawchan_t *ch = NULL;
|
||||
|
||||
if( !dma.initialized || s_listener.paused || !CL_IsInGame( ))
|
||||
return;
|
||||
|
||||
if( entnum < 0 || entnum >= GI->max_edicts )
|
||||
return;
|
||||
|
||||
if( !( ch = S_FindRawChannel( entnum, true )))
|
||||
return;
|
||||
|
||||
if( ch->sound_info.rate == 0 )
|
||||
{
|
||||
if( !AVI_GetAudioInfo( Avi, &ch->sound_info ))
|
||||
return; // no audiotrack
|
||||
}
|
||||
|
||||
ch->master_vol = bound( 0, fvol * 255, 255 );
|
||||
ch->dist_mult = (attn / SND_CLIP_DISTANCE);
|
||||
|
||||
// see how many samples should be copied into the raw buffer
|
||||
if( ch->s_rawend < soundtime )
|
||||
ch->s_rawend = soundtime;
|
||||
|
||||
// position is changed, synchronization is lost etc
|
||||
if( fabs( ch->oldtime - synctime ) > s_mixahead.value )
|
||||
ch->sound_info.loopStart = AVI_TimeToSoundPosition( Avi, synctime * 1000 );
|
||||
ch->oldtime = synctime; // keep actual time
|
||||
|
||||
while( ch->s_rawend < soundtime + ch->max_samples )
|
||||
{
|
||||
wavdata_t *info = &ch->sound_info;
|
||||
|
||||
bufferSamples = ch->max_samples - (ch->s_rawend - soundtime);
|
||||
|
||||
// decide how much data needs to be read from the file
|
||||
fileSamples = bufferSamples * ((float)info->rate / SOUND_DMA_SPEED );
|
||||
if( fileSamples <= 1 ) return; // no more samples need
|
||||
|
||||
// our max buffer size
|
||||
fileBytes = fileSamples * ( info->width * info->channels );
|
||||
|
||||
if( fileBytes > sizeof( raw ))
|
||||
{
|
||||
fileBytes = sizeof( raw );
|
||||
fileSamples = fileBytes / ( info->width * info->channels );
|
||||
}
|
||||
|
||||
// read audio stream
|
||||
r = AVI_GetAudioChunk( Avi, raw, info->loopStart, fileBytes );
|
||||
info->loopStart += r; // advance play position
|
||||
|
||||
if( r < fileBytes )
|
||||
{
|
||||
fileBytes = r;
|
||||
fileSamples = r / ( info->width * info->channels );
|
||||
}
|
||||
|
||||
if( r > 0 )
|
||||
{
|
||||
// add to raw buffer
|
||||
ch->s_rawend = S_RawSamplesStereo( ch->rawsamples, ch->s_rawend, ch->max_samples,
|
||||
fileSamples, info->rate, info->width, info->channels, raw );
|
||||
}
|
||||
else break; // no more samples for this frame
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
S_FreeIdleRawChannels
|
||||
@@ -1594,6 +1690,7 @@ void SND_UpdateSound( void )
|
||||
}
|
||||
|
||||
S_StreamBackgroundTrack ();
|
||||
S_StreamSoundTrack ();
|
||||
|
||||
// mix some sound
|
||||
S_UpdateChannels ();
|
||||
@@ -1857,15 +1954,14 @@ qboolean S_Init( void )
|
||||
Cmd_AddCommand( "spk", S_SayReliable_f, "reliable play a specified sententce" );
|
||||
Cmd_AddCommand( "speak", S_Say_f, "playing a specified sententce" );
|
||||
|
||||
sndpool = Mem_AllocPool( "Sound Zone" );
|
||||
dma.backendName = "None";
|
||||
if( !SNDDMA_Init( ))
|
||||
if( !SNDDMA_Init( ) )
|
||||
{
|
||||
Con_Printf( "Audio: sound system can't be initialized\n" );
|
||||
Mem_FreePool( &sndpool );
|
||||
return false;
|
||||
}
|
||||
|
||||
sndpool = Mem_AllocPool( "Sound Zone" );
|
||||
soundtime = 0;
|
||||
paintedtime = 0;
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ GNU General Public License for more details.
|
||||
#include "common.h"
|
||||
#include "sound.h"
|
||||
#include "client.h"
|
||||
#include "soundlib.h"
|
||||
|
||||
static bg_track_t s_bgTrack;
|
||||
static musicfade_t musicfade; // controlled by game dlls
|
||||
@@ -213,7 +212,7 @@ void S_StreamBackgroundTrack( void )
|
||||
|
||||
while( ch->s_rawend < soundtime + ch->max_samples )
|
||||
{
|
||||
const stream_t *info = s_bgTrack.stream;
|
||||
wavdata_t *info = FS_StreamInfo( s_bgTrack.stream );
|
||||
|
||||
bufferSamples = ch->max_samples - (ch->s_rawend - soundtime);
|
||||
|
||||
@@ -242,7 +241,7 @@ void S_StreamBackgroundTrack( void )
|
||||
if( r > 0 )
|
||||
{
|
||||
// add to raw buffer
|
||||
S_RawEntSamples( S_RAW_SOUND_BACKGROUNDTRACK, fileSamples, info->rate, info->width, info->channels, raw, 255 );
|
||||
S_RawSamples( fileSamples, info->rate, info->width, info->channels, raw, S_RAW_SOUND_BACKGROUNDTRACK );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -287,3 +286,66 @@ void S_StopStreaming( void )
|
||||
if( !dma.initialized ) return;
|
||||
s_listener.streaming = false;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
S_StreamSoundTrack
|
||||
=================
|
||||
*/
|
||||
void S_StreamSoundTrack( void )
|
||||
{
|
||||
int bufferSamples;
|
||||
int fileSamples;
|
||||
byte raw[MAX_RAW_SAMPLES];
|
||||
int r, fileBytes;
|
||||
rawchan_t *ch = NULL;
|
||||
|
||||
if( !dma.initialized || !s_listener.streaming || s_listener.paused )
|
||||
return;
|
||||
|
||||
ch = S_FindRawChannel( S_RAW_SOUND_SOUNDTRACK, true );
|
||||
|
||||
Assert( ch != NULL );
|
||||
|
||||
// see how many samples should be copied into the raw buffer
|
||||
if( ch->s_rawend < soundtime )
|
||||
ch->s_rawend = soundtime;
|
||||
|
||||
while( ch->s_rawend < soundtime + ch->max_samples )
|
||||
{
|
||||
wavdata_t *info = SCR_GetMovieInfo();
|
||||
|
||||
if( !info ) break; // bad soundtrack?
|
||||
|
||||
bufferSamples = ch->max_samples - (ch->s_rawend - soundtime);
|
||||
|
||||
// decide how much data needs to be read from the file
|
||||
fileSamples = bufferSamples * ((float)info->rate / SOUND_DMA_SPEED );
|
||||
if( fileSamples <= 1 ) return; // no more samples need
|
||||
|
||||
// our max buffer size
|
||||
fileBytes = fileSamples * ( info->width * info->channels );
|
||||
|
||||
if( fileBytes > sizeof( raw ))
|
||||
{
|
||||
fileBytes = sizeof( raw );
|
||||
fileSamples = fileBytes / ( info->width * info->channels );
|
||||
}
|
||||
|
||||
// read audio stream
|
||||
r = SCR_GetAudioChunk( raw, fileBytes );
|
||||
|
||||
if( r < fileBytes )
|
||||
{
|
||||
fileBytes = r;
|
||||
fileSamples = r / ( info->width * info->channels );
|
||||
}
|
||||
|
||||
if( r > 0 )
|
||||
{
|
||||
// add to raw buffer
|
||||
S_RawSamples( fileSamples, info->rate, info->width, info->channels, raw, S_RAW_SOUND_SOUNDTRACK );
|
||||
}
|
||||
else break; // no more samples for this frame
|
||||
}
|
||||
}
|
||||
|
||||
@@ -557,7 +557,7 @@ static void VOX_ReadSentenceFile_( byte *buf, fs_offset_t size )
|
||||
int index = cszrawsentences;
|
||||
int size = strlen( name ) + strlen( value ) + 2;
|
||||
|
||||
rgpszrawsentence[index] = Mem_Malloc( sndpool, size );
|
||||
rgpszrawsentence[index] = Mem_Malloc( host.mempool, size );
|
||||
memcpy( rgpszrawsentence[index], name, size );
|
||||
rgpszrawsentence[index][size - 1] = 0;
|
||||
cszrawsentences++;
|
||||
|
||||
@@ -114,6 +114,7 @@ typedef struct rawchan_s
|
||||
vec3_t origin; // only use if fixed_origin is set
|
||||
volatile uint s_rawend;
|
||||
float oldtime; // catch time jumps
|
||||
wavdata_t sound_info; // advance play position
|
||||
size_t max_samples; // buffer length
|
||||
portable_samplepair_t rawsamples[]; // variable sized
|
||||
} rawchan_t;
|
||||
@@ -170,15 +171,12 @@ typedef struct
|
||||
int source; // may be game, menu, etc
|
||||
} bg_track_t;
|
||||
|
||||
typedef int sound_t;
|
||||
|
||||
//====================================================================
|
||||
|
||||
#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_RAW_CHANNELS 48
|
||||
#define MAX_RAW_SAMPLES 16384
|
||||
#define SND_CLIP_DISTANCE 1000.0f
|
||||
#define MAX_RAW_SAMPLES 8192
|
||||
|
||||
extern sound_t ambient_sfx[NUM_AMBIENTS];
|
||||
extern qboolean snd_ambient;
|
||||
@@ -244,8 +242,8 @@ int S_GetCurrentStaticSounds( soundlist_t *pout, int size );
|
||||
int S_GetCurrentDynamicSounds( soundlist_t *pout, int size );
|
||||
sfx_t *S_GetSfxByHandle( sound_t handle );
|
||||
rawchan_t *S_FindRawChannel( int entnum, qboolean create );
|
||||
uint S_RawSamplesStereo( portable_samplepair_t *rawsamples, uint rawend, uint max_samples, uint samples, uint rate, word width, word channels, const byte *data );
|
||||
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_StopSound( int entnum, int channel, const char *soundname );
|
||||
void S_UpdateFrame( struct ref_viewpass_s *rvp );
|
||||
void S_StopAllSounds( qboolean ambient );
|
||||
@@ -265,6 +263,7 @@ void SND_ForceCloseMouth( int entnum );
|
||||
//
|
||||
// s_stream.c
|
||||
//
|
||||
void S_StreamSoundTrack( void );
|
||||
void S_StreamBackgroundTrack( void );
|
||||
void S_PrintBackgroundTrackState( void );
|
||||
void S_FadeMusicVolume( float fadePercent );
|
||||
|
||||
@@ -29,20 +29,17 @@ static void Sound_Reset( void )
|
||||
|
||||
static MALLOC_LIKE( FS_FreeSound, 1 ) wavdata_t *SoundPack( void )
|
||||
{
|
||||
wavdata_t *pack = Mem_Malloc( host.soundpool, sizeof( *pack ) + sound.size );
|
||||
wavdata_t *pack = Mem_Calloc( host.soundpool, sizeof( wavdata_t ));
|
||||
|
||||
pack->buffer = sound.wav;
|
||||
pack->width = sound.width;
|
||||
pack->rate = sound.rate;
|
||||
pack->type = sound.type;
|
||||
pack->size = sound.size;
|
||||
pack->loopStart = sound.loopstart;
|
||||
pack->samples = sound.samples;
|
||||
pack->type = sound.type;
|
||||
pack->flags = sound.flags;
|
||||
pack->rate = sound.rate;
|
||||
pack->width = sound.width;
|
||||
pack->channels = sound.channels;
|
||||
memcpy( pack->buffer, sound.wav, sound.size );
|
||||
|
||||
Mem_Free( sound.wav );
|
||||
sound.wav = NULL;
|
||||
pack->flags = sound.flags;
|
||||
|
||||
return pack;
|
||||
}
|
||||
@@ -135,6 +132,7 @@ free WAV buffer
|
||||
void FS_FreeSound( wavdata_t *pack )
|
||||
{
|
||||
if( !pack ) return;
|
||||
if( pack->buffer ) Mem_Free( pack->buffer );
|
||||
Mem_Free( pack );
|
||||
}
|
||||
|
||||
@@ -201,6 +199,33 @@ stream_t *FS_OpenStream( const char *filename )
|
||||
return stream;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
FS_StreamInfo
|
||||
|
||||
get basic stream info
|
||||
================
|
||||
*/
|
||||
wavdata_t *FS_StreamInfo( stream_t *stream )
|
||||
{
|
||||
static wavdata_t info;
|
||||
|
||||
if( !stream ) return NULL;
|
||||
|
||||
// fill structure
|
||||
info.loopStart = 0;
|
||||
info.rate = stream->rate;
|
||||
info.width = stream->width;
|
||||
info.channels = stream->channels;
|
||||
info.flags = SOUND_STREAM;
|
||||
info.size = stream->size;
|
||||
info.buffer = NULL;
|
||||
info.samples = 0; // not actual for streams
|
||||
info.type = stream->type;
|
||||
|
||||
return &info;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
FS_ReadStream
|
||||
|
||||
@@ -17,7 +17,7 @@ GNU General Public License for more details.
|
||||
#include "base_cmd.h"
|
||||
#include "cdll_int.h"
|
||||
|
||||
#define HASH_SIZE 64 // 64 * 4 * 4 == 1024 bytes
|
||||
#define HASH_SIZE 128 // 128 * 4 * 4 == 2048 bytes
|
||||
|
||||
typedef struct base_command_hashmap_s base_command_hashmap_t;
|
||||
|
||||
@@ -26,11 +26,10 @@ struct base_command_hashmap_s
|
||||
base_command_t *basecmd; // base command: cvar, alias or command
|
||||
base_command_hashmap_t *next;
|
||||
base_command_type_e type; // type for faster searching
|
||||
char name[]; // key for searching
|
||||
char name[1]; // key for searching
|
||||
};
|
||||
|
||||
static base_command_hashmap_t *hashed_cmds[HASH_SIZE];
|
||||
static poolhandle_t basecmd_pool;
|
||||
|
||||
#define BaseCmd_HashKey( x ) COM_HashKey( name, HASH_SIZE )
|
||||
|
||||
@@ -43,27 +42,11 @@ Find base command in bucket
|
||||
*/
|
||||
static base_command_hashmap_t *BaseCmd_FindInBucket( base_command_hashmap_t *bucket, base_command_type_e type, const char *name )
|
||||
{
|
||||
base_command_hashmap_t *i;
|
||||
base_command_hashmap_t *i = bucket;
|
||||
for( ; i && ( i->type != type || Q_stricmp( name, i->name ) ); // filter out
|
||||
i = i->next );
|
||||
|
||||
for( i = bucket; i != NULL; i = i->next )
|
||||
{
|
||||
int cmp;
|
||||
|
||||
if( i->type != type )
|
||||
continue;
|
||||
|
||||
cmp = Q_stricmp( i->name, name );
|
||||
|
||||
if( cmp < 0 )
|
||||
continue;
|
||||
|
||||
if( cmp > 0 )
|
||||
break;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -107,31 +90,27 @@ void BaseCmd_FindAll( const char *name, base_command_t **cmd, base_command_t **a
|
||||
base_command_hashmap_t *base = BaseCmd_GetBucket( name );
|
||||
base_command_hashmap_t *i = base;
|
||||
|
||||
ASSERT( cmd && alias && cvar );
|
||||
|
||||
*cmd = *alias = *cvar = NULL;
|
||||
|
||||
for( ; i; i = i->next )
|
||||
{
|
||||
int cmp = Q_stricmp( i->name, name );
|
||||
|
||||
if( cmp < 0 )
|
||||
continue;
|
||||
|
||||
if( cmp > 0 )
|
||||
break;
|
||||
|
||||
switch( i->type )
|
||||
if( !Q_stricmp( i->name, name ) )
|
||||
{
|
||||
case HM_CMD:
|
||||
*cmd = i->basecmd;
|
||||
break;
|
||||
case HM_CMDALIAS:
|
||||
*alias = i->basecmd;
|
||||
break;
|
||||
case HM_CVAR:
|
||||
*cvar = i->basecmd;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
switch( i->type )
|
||||
{
|
||||
case HM_CMD:
|
||||
*cmd = i->basecmd;
|
||||
break;
|
||||
case HM_CMDALIAS:
|
||||
*alias = i->basecmd;
|
||||
break;
|
||||
case HM_CVAR:
|
||||
*cvar = i->basecmd;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -149,14 +128,14 @@ void BaseCmd_Insert( base_command_type_e type, base_command_t *basecmd, const ch
|
||||
uint hash = BaseCmd_HashKey( name );
|
||||
size_t len = Q_strlen( name );
|
||||
|
||||
elem = Mem_Malloc( basecmd_pool, sizeof( base_command_hashmap_t ) + len + 1 );
|
||||
elem = Z_Malloc( sizeof( base_command_hashmap_t ) + len );
|
||||
elem->basecmd = basecmd;
|
||||
elem->type = type;
|
||||
Q_strncpy( elem->name, name, len + 1 );
|
||||
|
||||
// link the variable in alphanumerical order
|
||||
for( cur = NULL, find = hashed_cmds[hash];
|
||||
find && Q_stricmp( find->name, elem->name ) < 0;
|
||||
find && Q_strcmp( find->name, elem->name ) < 0;
|
||||
cur = find, find = find->next );
|
||||
|
||||
if( cur ) cur->next = elem;
|
||||
@@ -177,23 +156,9 @@ void BaseCmd_Remove( base_command_type_e type, const char *name )
|
||||
uint hash = BaseCmd_HashKey( name );
|
||||
base_command_hashmap_t *i, *prev;
|
||||
|
||||
for( prev = NULL, i = hashed_cmds[hash]; i != NULL; prev = i, i = i->next )
|
||||
{
|
||||
int cmp;
|
||||
|
||||
if( i->type != type )
|
||||
continue;
|
||||
|
||||
cmp = Q_stricmp( i->name, name );
|
||||
|
||||
if( cmp < 0 )
|
||||
continue;
|
||||
|
||||
if( cmp > 0 )
|
||||
i = NULL;
|
||||
|
||||
break;
|
||||
}
|
||||
for( prev = NULL, i = hashed_cmds[hash]; i &&
|
||||
( Q_strcmp( i->name, name ) || i->type != type); // filter out
|
||||
prev = i, i = i->next );
|
||||
|
||||
if( !i )
|
||||
{
|
||||
@@ -218,15 +183,9 @@ initialize base command hashmap system
|
||||
*/
|
||||
void BaseCmd_Init( void )
|
||||
{
|
||||
basecmd_pool = Mem_AllocPool( "BaseCmd" );
|
||||
memset( hashed_cmds, 0, sizeof( hashed_cmds ) );
|
||||
}
|
||||
|
||||
void BaseCmd_Shutdown( void )
|
||||
{
|
||||
Mem_FreePool( &basecmd_pool );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
BaseCmd_Stats_f
|
||||
|
||||
@@ -32,7 +32,6 @@ typedef enum base_command_type
|
||||
typedef void base_command_t;
|
||||
|
||||
void BaseCmd_Init( void );
|
||||
void BaseCmd_Shutdown( void );
|
||||
base_command_t *BaseCmd_Find( base_command_type_e type, const char *name );
|
||||
void BaseCmd_FindAll( const char *name,
|
||||
base_command_t **cmd, base_command_t **alias, base_command_t **cvar );
|
||||
|
||||
@@ -46,7 +46,6 @@ static cmdalias_t *cmd_alias;
|
||||
static uint cmd_condition;
|
||||
static int cmd_condlevel;
|
||||
static qboolean cmd_currentCommandIsPrivileged;
|
||||
static poolhandle_t cmd_pool;
|
||||
|
||||
static void Cmd_ExecuteStringWithPrivilegeCheck( const char *text, qboolean isPrivileged );
|
||||
|
||||
@@ -433,7 +432,7 @@ static void Cmd_Alias_f( void )
|
||||
{
|
||||
if( !Q_strcmp( s, a->name ))
|
||||
{
|
||||
Mem_Free( a->value );
|
||||
Z_Free( a->value );
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -442,7 +441,7 @@ static void Cmd_Alias_f( void )
|
||||
{
|
||||
cmdalias_t *cur, *prev;
|
||||
|
||||
a = Mem_Malloc( cmd_pool, sizeof( cmdalias_t ));
|
||||
a = Z_Malloc( sizeof( cmdalias_t ));
|
||||
|
||||
Q_strncpy( a->name, s, sizeof( a->name ));
|
||||
|
||||
@@ -470,7 +469,7 @@ static void Cmd_Alias_f( void )
|
||||
}
|
||||
|
||||
Q_strncat( cmd, "\n", sizeof( cmd ));
|
||||
a->value = copystringpool( cmd_pool, cmd );
|
||||
a->value = copystring( cmd );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -530,7 +529,7 @@ struct cmd_s
|
||||
char *name;
|
||||
xcommand_t function;
|
||||
int flags;
|
||||
char desc[];
|
||||
char *desc;
|
||||
};
|
||||
|
||||
static int cmd_argc;
|
||||
@@ -637,7 +636,7 @@ void Cmd_TokenizeString( const char *text )
|
||||
|
||||
// clear the args from the last string
|
||||
for( i = 0; i < cmd_argc; i++ )
|
||||
Mem_Free( cmd_argv[i] );
|
||||
Z_Free( cmd_argv[i] );
|
||||
|
||||
cmd_argc = 0; // clear previous args
|
||||
cmd_args = NULL;
|
||||
@@ -671,7 +670,7 @@ void Cmd_TokenizeString( const char *text )
|
||||
|
||||
if( cmd_argc < MAX_CMD_TOKENS )
|
||||
{
|
||||
cmd_argv[cmd_argc] = copystringpool( cmd_pool, cmd_token );
|
||||
cmd_argv[cmd_argc] = copystring( cmd_token );
|
||||
cmd_argc++;
|
||||
}
|
||||
}
|
||||
@@ -684,8 +683,7 @@ Cmd_AddCommandEx
|
||||
*/
|
||||
int Cmd_AddCommandEx( const char *cmd_name, xcommand_t function, const char *cmd_desc, int iFlags, const char *funcname )
|
||||
{
|
||||
cmd_t *cmd, *cur, *prev;
|
||||
size_t desc_len;
|
||||
cmd_t *cmd, *cur, *prev;
|
||||
|
||||
if( !COM_CheckString( cmd_name ))
|
||||
{
|
||||
@@ -709,8 +707,8 @@ int Cmd_AddCommandEx( const char *cmd_name, xcommand_t function, const char *cmd
|
||||
// unfortunately, we lose original command this way
|
||||
if( FBitSet( cmd->flags, CMD_OVERRIDABLE ))
|
||||
{
|
||||
desc_len = Q_strlen( cmd->desc ) + 1;
|
||||
Q_strncpy( cmd->desc, cmd_desc, desc_len );
|
||||
Mem_Free( cmd->desc );
|
||||
cmd->desc = copystring( cmd_desc );
|
||||
cmd->function = function;
|
||||
cmd->flags = iFlags;
|
||||
|
||||
@@ -725,10 +723,9 @@ int Cmd_AddCommandEx( const char *cmd_name, xcommand_t function, const char *cmd
|
||||
}
|
||||
|
||||
// use a small malloc to avoid zone fragmentation
|
||||
desc_len = Q_strlen( cmd_desc ) + 1;
|
||||
cmd = Mem_Malloc( cmd_pool, sizeof( cmd_t ) + desc_len );
|
||||
cmd->name = copystringpool( cmd_pool, cmd_name );
|
||||
Q_strncpy( cmd->desc, cmd_desc, desc_len );
|
||||
cmd = Z_Malloc( sizeof( cmd_t ) );
|
||||
cmd->name = copystring( cmd_name );
|
||||
cmd->desc = copystring( cmd_desc );
|
||||
cmd->function = function;
|
||||
cmd->flags = iFlags;
|
||||
|
||||
@@ -775,6 +772,9 @@ void GAME_EXPORT Cmd_RemoveCommand( const char *cmd_name )
|
||||
if( cmd->name )
|
||||
Mem_Free( cmd->name );
|
||||
|
||||
if( cmd->desc )
|
||||
Mem_Free( cmd->desc );
|
||||
|
||||
Mem_Free( cmd );
|
||||
return;
|
||||
}
|
||||
@@ -1202,6 +1202,7 @@ void Cmd_Unlink( int group )
|
||||
*prev = cmd->next;
|
||||
|
||||
if( cmd->name ) Mem_Free( cmd->name );
|
||||
if( cmd->desc ) Mem_Free( cmd->desc );
|
||||
|
||||
Mem_Free( cmd );
|
||||
count++;
|
||||
@@ -1339,7 +1340,6 @@ Cmd_Init
|
||||
*/
|
||||
void Cmd_Init( void )
|
||||
{
|
||||
cmd_pool = Mem_AllocPool( "Console Commands" );
|
||||
cmd_functions = NULL;
|
||||
cmd_condition = 0;
|
||||
cmd_alias = NULL;
|
||||
@@ -1366,11 +1366,6 @@ void Cmd_Init( void )
|
||||
#endif
|
||||
}
|
||||
|
||||
void Cmd_Shutdown( void )
|
||||
{
|
||||
Mem_FreePool( &cmd_pool );
|
||||
}
|
||||
|
||||
#if XASH_ENGINE_TESTS
|
||||
#include "tests.h"
|
||||
|
||||
|
||||
@@ -108,14 +108,14 @@ typedef enum
|
||||
#include "com_model.h"
|
||||
#include "com_strings.h"
|
||||
#include "crtlib.h"
|
||||
#define FSCALLBACK_OVERRIDE_OPEN
|
||||
#define FSCALLBACK_OVERRIDE_LOADFILE
|
||||
#define FSCALLBACK_OVERRIDE_MALLOC_LIKE
|
||||
#include "fscallback.h"
|
||||
#include "cvar.h"
|
||||
#include "con_nprint.h"
|
||||
#include "crclib.h"
|
||||
#include "ref_api.h"
|
||||
#define FSCALLBACK_OVERRIDE_OPEN
|
||||
#define FSCALLBACK_OVERRIDE_LOADFILE
|
||||
#define FSCALLBACK_OVERRIDE_MALLOC_LIKE
|
||||
#include "fscallback.h"
|
||||
|
||||
// PERFORMANCE INFO
|
||||
#define MIN_FPS 20.0f // host minimum fps value for maxfps.
|
||||
@@ -146,11 +146,6 @@ typedef enum
|
||||
#define MAX_STATIC_ENTITIES 32 // static entities that moved on the client when level is spawn
|
||||
#endif
|
||||
|
||||
#define MAX_SERVERINFO_STRING 512 // server handles too many settings. expand to 1024?
|
||||
#define MAX_PRINT_MSG 8192 // how many symbols can handle single call of Con_Printf or Con_DPrintf
|
||||
#define MAX_TOKEN 2048 // parse token length
|
||||
#define MAX_USERMSG_LENGTH 2048 // don't modify it's relies on a client-side definitions
|
||||
|
||||
#define GameState (&host.game)
|
||||
|
||||
#define FORCE_DRAW_VERSION_TIME 5.0 // draw version for 5 seconds
|
||||
@@ -437,7 +432,6 @@ int Cmd_Argc( void );
|
||||
const char *Cmd_Args( void ) RETURNS_NONNULL;
|
||||
const char *Cmd_Argv( int arg ) RETURNS_NONNULL;
|
||||
void Cmd_Init( void );
|
||||
void Cmd_Shutdown( void );
|
||||
void Cmd_Unlink( int group );
|
||||
int Cmd_AddCommandEx( const char *cmd_name, xcommand_t function, const char *cmd_desc, int flags, const char *funcname );
|
||||
|
||||
@@ -519,27 +513,27 @@ typedef enum
|
||||
|
||||
typedef struct
|
||||
{
|
||||
size_t size; // for bounds checking
|
||||
word rate; // num samples per second (e.g. 11025 - 11 khz)
|
||||
byte width; // resolution - bum bits divided by 8 (8 bit is 1, 16 bit is 2)
|
||||
byte channels; // num channels (1 - mono, 2 - stereo)
|
||||
uint loopStart; // offset at this point sound will be looping while playing more than only once
|
||||
uint samples; // total samplecount in wav
|
||||
uint type; // compression type
|
||||
uint flags; // misc sound flags
|
||||
word rate; // num samples per second (e.g. 11025 - 11 khz)
|
||||
byte width; // resolution - bum bits divided by 8 (8 bit is 1, 16 bit is 2)
|
||||
byte channels; // num channels (1 - mono, 2 - stereo)
|
||||
byte buffer[]; // sound buffer
|
||||
byte *buffer; // sound buffer
|
||||
size_t size; // for bounds checking
|
||||
} wavdata_t;
|
||||
|
||||
//
|
||||
// soundlib
|
||||
//
|
||||
typedef struct stream_s stream_t;
|
||||
void Sound_Init( void );
|
||||
void Sound_Shutdown( void );
|
||||
void FS_FreeSound( wavdata_t *pack );
|
||||
void FS_FreeStream( stream_t *stream );
|
||||
wavdata_t *FS_LoadSound( const char *filename, const byte *buffer, size_t size ) MALLOC_LIKE( FS_FreeSound, 1 ) WARN_UNUSED_RESULT;
|
||||
stream_t *FS_OpenStream( const char *filename ) MALLOC_LIKE( FS_FreeStream, 1 ) WARN_UNUSED_RESULT;
|
||||
wavdata_t *FS_StreamInfo( stream_t *stream );
|
||||
int FS_ReadStream( stream_t *stream, int bytes, void *buffer );
|
||||
int FS_SetStreamPos( stream_t *stream, int newpos );
|
||||
int FS_GetStreamPos( stream_t *stream );
|
||||
@@ -634,7 +628,6 @@ int pfnNumberOfEntities( void );
|
||||
int pfnIsInGame( void );
|
||||
float pfnTime( void );
|
||||
#define copystring( s ) _copystring( host.mempool, s, __FILE__, __LINE__ )
|
||||
#define copystringpool( pool, s ) _copystring( pool, s, __FILE__, __LINE__ )
|
||||
#define SV_CopyString( s ) _copystring( svgame.stringspool, s, __FILE__, __LINE__ )
|
||||
#define freestring( s ) if( s != NULL ) { Mem_Free( s ); s = NULL; }
|
||||
char *_copystring( poolhandle_t mempool, const char *s, const char *filename, int fileline );
|
||||
@@ -685,7 +678,6 @@ int CSCR_WriteGameCVars( file_t *cfg, const char *scriptfilename );
|
||||
//
|
||||
// hpak.c
|
||||
//
|
||||
const char *COM_ResourceTypeFromIndex( int index );
|
||||
void HPAK_Init( void );
|
||||
qboolean HPAK_GetDataPointer( const char *filename, struct resource_s *pRes, byte **buffer, int *size );
|
||||
qboolean HPAK_ResourceForHash( const char *filename, byte *hash, struct resource_s *pRes );
|
||||
@@ -784,6 +776,8 @@ void SCR_Init( void );
|
||||
void SCR_UpdateScreen( void );
|
||||
void SCR_BeginLoadingPlaque( qboolean is_background );
|
||||
void SCR_CheckStartupVids( void );
|
||||
int SCR_GetAudioChunk( char *rawdata, int length );
|
||||
wavdata_t *SCR_GetMovieInfo( void );
|
||||
void SCR_Shutdown( void );
|
||||
void Con_Print( const char *txt );
|
||||
void Con_NPrintf( int idx, const char *fmt, ... ) FORMAT_CHECK( 2 );
|
||||
@@ -873,6 +867,13 @@ void V_CheckGamma( void );
|
||||
void V_CheckGammaEnd( void );
|
||||
intptr_t V_GetGammaPtr( int parm );
|
||||
|
||||
//
|
||||
// identification.c
|
||||
//
|
||||
void ID_Init( void );
|
||||
const char *ID_GetMD5( void );
|
||||
void GAME_EXPORT ID_SetCustomClientID( const char *id );
|
||||
|
||||
//
|
||||
// masterlist.c
|
||||
//
|
||||
|
||||
@@ -19,7 +19,6 @@ GNU General Public License for more details.
|
||||
#include "eiface.h" // ARRAYSIZE
|
||||
|
||||
static convar_t *cvar_vars = NULL; // head of list
|
||||
static poolhandle_t cvar_pool;
|
||||
CVAR_DEFINE_AUTO( cmd_scripting, "0", FCVAR_ARCHIVE|FCVAR_PRIVILEGED, "enable simple condition checking and variable operations" );
|
||||
|
||||
typedef struct cvar_filter_quirks_s
|
||||
@@ -433,7 +432,7 @@ convar_t *Cvar_Get( const char *name, const char *value, int flags, const char *
|
||||
{
|
||||
// directly set value
|
||||
freestring( var->string );
|
||||
var->string = copystringpool( cvar_pool, value );
|
||||
var->string = copystring( value );
|
||||
var->value = Q_atof( var->string );
|
||||
SetBits( var->flags, flags );
|
||||
|
||||
@@ -453,18 +452,18 @@ convar_t *Cvar_Get( const char *name, const char *value, int flags, const char *
|
||||
Con_Reportf( "%s change description from %s to %s\n", var->name, var->desc, var_desc );
|
||||
// update description if needs
|
||||
freestring( var->desc );
|
||||
var->desc = copystringpool( cvar_pool, var_desc );
|
||||
var->desc = copystring( var_desc );
|
||||
}
|
||||
|
||||
return var;
|
||||
}
|
||||
|
||||
// allocate a new cvar
|
||||
var = Mem_Malloc( cvar_pool, sizeof( *var ));
|
||||
var->name = copystringpool( cvar_pool, name );
|
||||
var->string = copystringpool( cvar_pool, value );
|
||||
var->def_string = copystringpool( cvar_pool, value );
|
||||
var->desc = copystringpool( cvar_pool, var_desc );
|
||||
var = Z_Malloc( sizeof( *var ));
|
||||
var->name = copystring( name );
|
||||
var->string = copystring( value );
|
||||
var->def_string = copystring( value );
|
||||
var->desc = copystring( var_desc );
|
||||
var->value = Q_atof( var->string );
|
||||
var->flags = flags|FCVAR_ALLOCATED;
|
||||
|
||||
@@ -550,7 +549,7 @@ void Cvar_RegisterVariable( convar_t *var )
|
||||
if( FBitSet( var->flags, FCVAR_EXTENDED ))
|
||||
var->def_string = var->string; // just swap pointers
|
||||
|
||||
var->string = copystringpool( cvar_pool, var->string );
|
||||
var->string = copystring( var->string );
|
||||
var->value = Q_atof( var->string );
|
||||
|
||||
// find the supposed position in chain (alphanumerical order)
|
||||
@@ -680,7 +679,7 @@ static convar_t *Cvar_Set2( const char *var_name, const char *value )
|
||||
|
||||
// and finally changed the cvar itself
|
||||
freestring( var->string );
|
||||
var->string = copystringpool( cvar_pool, pszValue );
|
||||
var->string = copystring( pszValue );
|
||||
var->value = Q_atof( var->string );
|
||||
|
||||
// tell engine about changes
|
||||
@@ -739,7 +738,7 @@ void GAME_EXPORT Cvar_DirectSet( convar_t *var, const char *value )
|
||||
|
||||
// and finally changed the cvar itself
|
||||
freestring( var->string );
|
||||
var->string = copystringpool( cvar_pool, pszValue );
|
||||
var->string = copystring( pszValue );
|
||||
var->value = Q_atof( var->string );
|
||||
|
||||
// tell engine about changes
|
||||
@@ -782,7 +781,7 @@ void Cvar_FullSet( const char *var_name, const char *value, int flags )
|
||||
}
|
||||
|
||||
freestring( var->string );
|
||||
var->string = copystringpool( cvar_pool, value );
|
||||
var->string = copystring( value );
|
||||
var->value = Q_atof( var->string );
|
||||
SetBits( var->flags, flags );
|
||||
|
||||
@@ -1190,7 +1189,6 @@ static void Cvar_List_f( void )
|
||||
for( var = cvar_vars; var; var = var->next )
|
||||
{
|
||||
char value[MAX_VA_STRING];
|
||||
char *p;
|
||||
|
||||
if( var->name[0] == '@' )
|
||||
continue; // never shows system cvars
|
||||
@@ -1198,9 +1196,7 @@ static void Cvar_List_f( void )
|
||||
if( match && !Q_strnicmpext( match, var->name, matchlen ))
|
||||
continue;
|
||||
|
||||
p = Q_strchr( var->string, '^' );
|
||||
|
||||
if( IsColorString( p ))
|
||||
if( Q_colorstr( var->string ))
|
||||
Q_snprintf( value, sizeof( value ), "\"%s\"", var->string );
|
||||
else Q_snprintf( value, sizeof( value ), "\"^2%s^7\"", var->string );
|
||||
|
||||
@@ -1261,7 +1257,7 @@ pending_cvar_t *Cvar_PrepareToUnlink( int group )
|
||||
continue;
|
||||
|
||||
namelen = Q_strlen( cv->name ) + 1;
|
||||
p = Mem_Malloc( cvar_pool, sizeof( *list ) + namelen );
|
||||
p = Mem_Malloc( host.mempool, sizeof( *list ) + namelen );
|
||||
p->next = NULL;
|
||||
p->cv_cur = cv;
|
||||
p->cv_next = cv->next;
|
||||
@@ -1337,7 +1333,6 @@ Reads in all archived cvars
|
||||
*/
|
||||
void Cvar_Init( void )
|
||||
{
|
||||
cvar_pool = Mem_AllocPool( "Console Variables" );
|
||||
cvar_vars = NULL;
|
||||
cvar_active_filter_quirks = NULL;
|
||||
Cvar_RegisterVariable( &cmd_scripting );
|
||||
@@ -1350,11 +1345,6 @@ void Cvar_Init( void )
|
||||
Cmd_AddCommand( "cvarlist", Cvar_List_f, "display all console variables beginning with the specified prefix" );
|
||||
}
|
||||
|
||||
void Cvar_Shutdown( void )
|
||||
{
|
||||
Mem_FreePool( &cvar_pool );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cvar_PostFSInit
|
||||
|
||||
@@ -30,8 +30,6 @@ typedef struct pending_cvar_s
|
||||
char cv_name[];
|
||||
} pending_cvar_t;
|
||||
|
||||
typedef void (*setpair_t)( const char *key, const void *value, const void *buffer, void *numpairs );
|
||||
|
||||
cvar_t *Cvar_GetList( void );
|
||||
#define Cvar_FindVar( name ) Cvar_FindVarExt( name, 0 )
|
||||
convar_t *Cvar_FindVarExt( const char *var_name, int ignore_group );
|
||||
@@ -54,7 +52,6 @@ void Cvar_Reset( const char *var_name );
|
||||
void Cvar_SetCheatState( void );
|
||||
qboolean Cvar_CommandWithPrivilegeCheck( convar_t *v, qboolean isPrivileged );
|
||||
void Cvar_Init( void );
|
||||
void Cvar_Shutdown( void );
|
||||
void Cvar_PostFSInit( void );
|
||||
void Cvar_Unlink( int group );
|
||||
|
||||
|
||||
@@ -183,23 +183,14 @@ static qboolean FS_DetermineRootDirectory( char *out, size_t size )
|
||||
#elif XASH_PSVITA
|
||||
if( PSVita_GetBasePath( out, size ))
|
||||
return true;
|
||||
Sys_Error( "couldn't find %s data directory", XASH_ENGINE_NAME );
|
||||
Sys_Error( "couldn't find Xash3D data directory" );
|
||||
return false;
|
||||
#elif ( XASH_SDL == 2 ) && !XASH_NSWITCH // GetBasePath not impl'd in switch-sdl2
|
||||
path = SDL_GetBasePath();
|
||||
|
||||
#if XASH_APPLE
|
||||
if( path != NULL && Q_stristr( path, ".app" ))
|
||||
{
|
||||
SDL_free((void *)path );
|
||||
path = SDL_GetPrefPath( NULL, XASH_ENGINE_NAME );
|
||||
}
|
||||
#endif
|
||||
|
||||
if( path != NULL )
|
||||
{
|
||||
Q_strncpy( out, path, size );
|
||||
SDL_free((void *)path );
|
||||
SDL_free(( void *)path );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1131,7 +1131,7 @@ static void Host_InitCommon( int argc, char **argv, const char *progname, qboole
|
||||
#if XASH_DEDICATED
|
||||
Platform_SetupSigtermHandling();
|
||||
#endif
|
||||
Platform_Init( Host_IsDedicated( ) || developer >= DEV_EXTENDED, basedir );
|
||||
Platform_Init( Host_IsDedicated( ) || developer >= DEV_EXTENDED );
|
||||
FS_Init( basedir );
|
||||
|
||||
Sys_InitLog();
|
||||
@@ -1256,6 +1256,7 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
|
||||
CL_Init();
|
||||
|
||||
HTTP_Init();
|
||||
ID_Init();
|
||||
SoundList_Init();
|
||||
|
||||
if( Host_IsDedicated( ))
|
||||
@@ -1399,10 +1400,6 @@ void Host_ShutdownWithReason( const char *reason )
|
||||
Host_FreeCommon();
|
||||
Platform_Shutdown();
|
||||
|
||||
BaseCmd_Shutdown();
|
||||
Cmd_Shutdown();
|
||||
Cvar_Shutdown();
|
||||
|
||||
// must be last, console uses this
|
||||
Mem_FreePool( &host.mempool );
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ static void HPAK_MaxSize_f( void )
|
||||
Con_Printf( S_ERROR "hpk_maxsize is deprecated, use hpk_max_size\n" );
|
||||
}
|
||||
|
||||
const char *COM_ResourceTypeFromIndex( int type )
|
||||
static const char *HPAK_TypeFromIndex( int type )
|
||||
{
|
||||
switch( type )
|
||||
{
|
||||
@@ -461,7 +461,7 @@ static qboolean HPAK_Validate( const char *filename, qboolean quiet, qboolean de
|
||||
|
||||
if( !quiet )
|
||||
{
|
||||
Con_Printf( "%i: %s %s %s: ", i, COM_ResourceTypeFromIndex( pRes->type ),
|
||||
Con_Printf( "%i: %s %s %s: ", i, HPAK_TypeFromIndex( pRes->type ),
|
||||
Q_pretifymem( pRes->nDownloadSize, 2 ), pRes->szFileName );
|
||||
}
|
||||
|
||||
@@ -942,7 +942,7 @@ static void HPAK_List_f( void )
|
||||
{
|
||||
entry = &directory.entries[nCurrent];
|
||||
COM_FileBase( entry->resource.szFileName, lumpname, sizeof( lumpname ));
|
||||
type = COM_ResourceTypeFromIndex( entry->resource.type );
|
||||
type = HPAK_TypeFromIndex( entry->resource.type );
|
||||
size = Q_memprint( entry->resource.nDownloadSize );
|
||||
|
||||
Con_Printf( "%i: %10s %s %s\n : %s\n", nCurrent + 1, type, size, lumpname, MD5_Print( entry->resource.rgucMD5_hash ));
|
||||
@@ -1037,7 +1037,7 @@ static void HPAK_Extract_f( void )
|
||||
continue;
|
||||
|
||||
COM_FileBase( entry->resource.szFileName, lumpname, sizeof( lumpname ) );
|
||||
type = COM_ResourceTypeFromIndex( entry->resource.type );
|
||||
type = HPAK_TypeFromIndex( entry->resource.type );
|
||||
size = Q_memprint( entry->resource.nDownloadSize );
|
||||
|
||||
Con_Printf( "Extracting %i: %10s %s %s\n", nCurrent + 1, type, size, lumpname );
|
||||
|
||||
@@ -632,7 +632,7 @@ void ID_Init( void )
|
||||
#elif XASH_WIN32
|
||||
{
|
||||
CHAR szBuf[MAX_PATH];
|
||||
ID_GetKeyData( HKEY_CURRENT_USER, "Software\\"XASH_ENGINE_NAME"\\", "xash_id", szBuf, MAX_PATH );
|
||||
ID_GetKeyData( HKEY_CURRENT_USER, "Software\\Xash3D\\", "xash_id", szBuf, MAX_PATH );
|
||||
|
||||
sscanf(szBuf, "%016"PRIX64, &id);
|
||||
id ^= SYSTEM_XOR_MASK;
|
||||
@@ -686,7 +686,7 @@ void ID_Init( void )
|
||||
{
|
||||
CHAR Buf[MAX_PATH];
|
||||
sprintf( Buf, "%016"PRIX64, id^SYSTEM_XOR_MASK );
|
||||
ID_SetKeyData( HKEY_CURRENT_USER, "Software\\"XASH_ENGINE_NAME"\\", REG_SZ, "xash_id", Buf, Q_strlen(Buf) );
|
||||
ID_SetKeyData( HKEY_CURRENT_USER, "Software\\Xash3D\\", REG_SZ, "xash_id", Buf, Q_strlen(Buf) );
|
||||
}
|
||||
#else
|
||||
{
|
||||
@@ -28,20 +28,12 @@ Image_LoadPAL
|
||||
qboolean Image_LoadPAL( const char *name, const byte *buffer, fs_offset_t filesize )
|
||||
{
|
||||
int rendermode = LUMP_NORMAL;
|
||||
byte pal[768];
|
||||
|
||||
if( filesize > sizeof( pal ))
|
||||
if( filesize != 768 )
|
||||
{
|
||||
Con_DPrintf( S_ERROR "%s: (%s) have invalid size (%li should be less or equal than %d)\n", __func__, name, (long)filesize, sizeof( pal ));
|
||||
Con_DPrintf( S_ERROR "%s: (%s) have invalid size (%li should be %d)\n", __func__, name, (long)filesize, 768 );
|
||||
return false;
|
||||
}
|
||||
else if( filesize < sizeof( pal ) && buffer != NULL )
|
||||
{
|
||||
// palette might be truncated, fill it with zeros
|
||||
memset( pal, 0, sizeof( pal ));
|
||||
memcpy( pal, buffer, filesize );
|
||||
buffer = pal;
|
||||
}
|
||||
|
||||
if( name[0] == '#' )
|
||||
{
|
||||
|
||||
@@ -482,7 +482,7 @@ static int Mod_LoadTextureFromWadList( wadlist_t *list, const char *name, rgbdat
|
||||
return -1;
|
||||
}
|
||||
|
||||
static fs_offset_t Mod_CalculateMipTexSize( const mip_t *mt, qboolean palette )
|
||||
static fs_offset_t Mod_CalculateMipTexSize( mip_t *mt, qboolean palette )
|
||||
{
|
||||
if( !mt )
|
||||
return 0;
|
||||
@@ -2359,7 +2359,7 @@ static qboolean Mod_SearchForTextureReplacement( char *out, size_t size, const c
|
||||
return false;
|
||||
}
|
||||
|
||||
static void Mod_InitSkyClouds( model_t *mod, const mip_t *mt, texture_t *tx, qboolean custom_palette )
|
||||
static void Mod_InitSkyClouds( model_t *mod, mip_t *mt, texture_t *tx, qboolean custom_palette )
|
||||
{
|
||||
#if !XASH_DEDICATED
|
||||
rgbdata_t r_temp, *r_sky;
|
||||
@@ -2516,6 +2516,9 @@ done:
|
||||
|
||||
static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureIndex )
|
||||
{
|
||||
texture_t *texture = NULL;
|
||||
mip_t *mipTex = NULL;
|
||||
qboolean usesCustomPalette = false;
|
||||
uint32_t txFlags = 0;
|
||||
char texpath[MAX_VA_STRING];
|
||||
char safemtname[16]; // only for external textures
|
||||
@@ -2523,10 +2526,12 @@ static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureInd
|
||||
|
||||
// don't load texture data on dedicated server, as there is no renderer.
|
||||
// but count the wadusage for automatic precache
|
||||
texture_t *texture = mod->textures[textureIndex];
|
||||
const mip_t *mipTex = Mod_GetMipTexForTexture( bmod, textureIndex );
|
||||
const qboolean usesCustomPalette = Mod_CalcMipTexUsesCustomPalette( mod, bmod, textureIndex );
|
||||
const qboolean iswater = Mod_LooksLikeWaterTexture( mipTex->name );
|
||||
//
|
||||
// FIXME: for ENGINE_IMPROVED_LINETRACE we need to load textures on server too
|
||||
// but there is no facility for this yet
|
||||
texture = mod->textures[textureIndex];
|
||||
mipTex = Mod_GetMipTexForTexture( bmod, textureIndex );
|
||||
usesCustomPalette = Mod_CalcMipTexUsesCustomPalette( mod, bmod, textureIndex );
|
||||
|
||||
// check for multi-layered sky texture (quake1 specific)
|
||||
if( bmod->isworld && Q_strncmp( mipTex->name, "sky", 3 ) == 0 && ( mipTex->width / mipTex->height ) == 2 )
|
||||
@@ -2535,13 +2540,11 @@ static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureInd
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: for ENGINE_IMPROVED_LINETRACE we need to load textures on server too
|
||||
// but there is no facility for this yet
|
||||
if( FBitSet( host.features, ENGINE_IMPROVED_LINETRACE ) && mipTex->name[0] == '{' )
|
||||
SetBits( txFlags, TF_KEEP_SOURCE ); // Paranoia2 texture alpha-tracing
|
||||
|
||||
// check if this is water to keep the source texture and expand it to RGBA (so ripple effect works)
|
||||
if( iswater )
|
||||
if( Mod_LooksLikeWaterTexture( mipTex->name ))
|
||||
SetBits( txFlags, TF_KEEP_SOURCE | TF_EXPAND_SOURCE );
|
||||
|
||||
// Texture loading order:
|
||||
@@ -2606,13 +2609,8 @@ static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureInd
|
||||
texture->gl_texturenum = R_GetBuiltinTexture( REF_DEFAULT_TEXTURE );
|
||||
}
|
||||
|
||||
texture->fb_texturenum = 0;
|
||||
|
||||
// Check for luma texture
|
||||
// a1ba: ignore for water because fb_texturenum will be used to store ripple texture
|
||||
if( iswater )
|
||||
return;
|
||||
|
||||
texture->fb_texturenum = 0;
|
||||
if( load_external ) // external textures will not have TF_HAS_LUMA flag because it set only from WAD images loader
|
||||
{
|
||||
if( Mod_SearchForTextureReplacement( texpath, sizeof( texpath ), mod->name, safemtname, "_luma" ))
|
||||
|
||||
@@ -868,7 +868,7 @@ void Mod_LoadStudioModel( model_t *mod, const void *buffer, qboolean *loaded )
|
||||
mod->type = mod_studio;
|
||||
|
||||
phdr = R_StudioLoadHeader( mod, buffer );
|
||||
if( !phdr || phdr->length < sizeof( studiohdr_t )) // garbage value in length
|
||||
if( !phdr )
|
||||
return; // bad model
|
||||
|
||||
#if !XASH_DEDICATED
|
||||
|
||||
@@ -258,7 +258,7 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
|
||||
{
|
||||
char tempname[MAX_QPATH];
|
||||
fs_offset_t length = 0;
|
||||
qboolean loaded, loaded2 = false;
|
||||
qboolean loaded;
|
||||
byte *buf;
|
||||
model_info_t *p;
|
||||
|
||||
@@ -279,7 +279,7 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
|
||||
|
||||
buf = FS_LoadFile( tempname, &length, false );
|
||||
|
||||
if( !buf || length < sizeof( uint ))
|
||||
if( !buf )
|
||||
{
|
||||
memset( mod, 0, sizeof( model_t ));
|
||||
|
||||
@@ -329,12 +329,11 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
|
||||
// let the server.dll load custom data
|
||||
svgame.physFuncs.Mod_ProcessUserData( mod, true, buf );
|
||||
}
|
||||
loaded2 = true;
|
||||
}
|
||||
#if !XASH_DEDICATED
|
||||
else
|
||||
{
|
||||
loaded2 = ref.dllFuncs.Mod_ProcessRenderData( mod, true, buf );
|
||||
loaded = ref.dllFuncs.Mod_ProcessRenderData( mod, true, buf );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -346,7 +345,7 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
|
||||
hdr->pposeverts = NULL;
|
||||
}
|
||||
|
||||
if( !loaded || !loaded2 )
|
||||
if( !loaded )
|
||||
{
|
||||
Mod_FreeModel( mod );
|
||||
Mem_Free( buf );
|
||||
@@ -611,41 +610,3 @@ void Mod_NeedCRC( const char *name, qboolean needCRC )
|
||||
if( needCRC ) SetBits( p->flags, FCRC_SHOULD_CHECKSUM );
|
||||
else ClearBits( p->flags, FCRC_SHOULD_CHECKSUM );
|
||||
}
|
||||
|
||||
#if XASH_ENGINE_TESTS
|
||||
|
||||
static const uint8_t *fuzz_data;
|
||||
static size_t fuzz_size;
|
||||
|
||||
static byte *Fuzz_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly )
|
||||
{
|
||||
byte *buf = Mem_Malloc( host.mempool, fuzz_size );
|
||||
memcpy( buf, fuzz_data, fuzz_size );
|
||||
*filesizeptr = fuzz_size;
|
||||
return buf;
|
||||
}
|
||||
|
||||
int EXPORT Fuzz_Mod_LoadModel( const uint8_t *Data, size_t Size );
|
||||
int EXPORT Fuzz_Mod_LoadModel( const uint8_t *Data, size_t Size )
|
||||
{
|
||||
model_t mod = { .name = "test", .needload = NL_NEEDS_LOADED };
|
||||
|
||||
Memory_Init();
|
||||
|
||||
host.type = HOST_DEDICATED;
|
||||
host.mempool = Mem_AllocPool( "fuzzing pool" );
|
||||
fuzz_data = Data;
|
||||
fuzz_size = Size;
|
||||
refState.draw_surfaces = NULL;
|
||||
|
||||
g_fsapi.LoadFile = Fuzz_LoadFile;
|
||||
|
||||
if( Mod_LoadModel( &mod, false ) && mod.mempool )
|
||||
Mem_FreePool( &mod.mempool );
|
||||
|
||||
Mem_FreePool( &host.mempool );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // XASH_ENGINE_TESTS
|
||||
|
||||
@@ -18,177 +18,11 @@ GNU General Public License for more details.
|
||||
#include "net_buffer.h"
|
||||
#include "xash3d_mathlib.h"
|
||||
|
||||
static const uint32_t BitWriteMasks[32][32] =
|
||||
{ {
|
||||
0xfffffffe, 0xfffffffc, 0xfffffff8, 0xfffffff0, 0xffffffe0, 0xffffffc0, 0xffffff80, 0xffffff00,
|
||||
0xfffffe00, 0xfffffc00, 0xfffff800, 0xfffff000, 0xffffe000, 0xffffc000, 0xffff8000, 0xffff0000,
|
||||
0xfffe0000, 0xfffc0000, 0xfff80000, 0xfff00000, 0xffe00000, 0xffc00000, 0xff800000, 0xff000000,
|
||||
0xfe000000, 0xfc000000, 0xf8000000, 0xf0000000, 0xe0000000, 0xc0000000, 0x80000000, 0x00000000,
|
||||
}, {
|
||||
0xfffffffd, 0xfffffff9, 0xfffffff1, 0xffffffe1, 0xffffffc1, 0xffffff81, 0xffffff01, 0xfffffe01,
|
||||
0xfffffc01, 0xfffff801, 0xfffff001, 0xffffe001, 0xffffc001, 0xffff8001, 0xffff0001, 0xfffe0001,
|
||||
0xfffc0001, 0xfff80001, 0xfff00001, 0xffe00001, 0xffc00001, 0xff800001, 0xff000001, 0xfe000001,
|
||||
0xfc000001, 0xf8000001, 0xf0000001, 0xe0000001, 0xc0000001, 0x80000001, 0x00000001, 0x00000001,
|
||||
}, {
|
||||
0xfffffffb, 0xfffffff3, 0xffffffe3, 0xffffffc3, 0xffffff83, 0xffffff03, 0xfffffe03, 0xfffffc03,
|
||||
0xfffff803, 0xfffff003, 0xffffe003, 0xffffc003, 0xffff8003, 0xffff0003, 0xfffe0003, 0xfffc0003,
|
||||
0xfff80003, 0xfff00003, 0xffe00003, 0xffc00003, 0xff800003, 0xff000003, 0xfe000003, 0xfc000003,
|
||||
0xf8000003, 0xf0000003, 0xe0000003, 0xc0000003, 0x80000003, 0x00000003, 0x00000003, 0x00000003,
|
||||
}, {
|
||||
0xfffffff7, 0xffffffe7, 0xffffffc7, 0xffffff87, 0xffffff07, 0xfffffe07, 0xfffffc07, 0xfffff807,
|
||||
0xfffff007, 0xffffe007, 0xffffc007, 0xffff8007, 0xffff0007, 0xfffe0007, 0xfffc0007, 0xfff80007,
|
||||
0xfff00007, 0xffe00007, 0xffc00007, 0xff800007, 0xff000007, 0xfe000007, 0xfc000007, 0xf8000007,
|
||||
0xf0000007, 0xe0000007, 0xc0000007, 0x80000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007,
|
||||
}, {
|
||||
0xffffffef, 0xffffffcf, 0xffffff8f, 0xffffff0f, 0xfffffe0f, 0xfffffc0f, 0xfffff80f, 0xfffff00f,
|
||||
0xffffe00f, 0xffffc00f, 0xffff800f, 0xffff000f, 0xfffe000f, 0xfffc000f, 0xfff8000f, 0xfff0000f,
|
||||
0xffe0000f, 0xffc0000f, 0xff80000f, 0xff00000f, 0xfe00000f, 0xfc00000f, 0xf800000f, 0xf000000f,
|
||||
0xe000000f, 0xc000000f, 0x8000000f, 0x0000000f, 0x0000000f, 0x0000000f, 0x0000000f, 0x0000000f,
|
||||
}, {
|
||||
0xffffffdf, 0xffffff9f, 0xffffff1f, 0xfffffe1f, 0xfffffc1f, 0xfffff81f, 0xfffff01f, 0xffffe01f,
|
||||
0xffffc01f, 0xffff801f, 0xffff001f, 0xfffe001f, 0xfffc001f, 0xfff8001f, 0xfff0001f, 0xffe0001f,
|
||||
0xffc0001f, 0xff80001f, 0xff00001f, 0xfe00001f, 0xfc00001f, 0xf800001f, 0xf000001f, 0xe000001f,
|
||||
0xc000001f, 0x8000001f, 0x0000001f, 0x0000001f, 0x0000001f, 0x0000001f, 0x0000001f, 0x0000001f,
|
||||
}, {
|
||||
0xffffffbf, 0xffffff3f, 0xfffffe3f, 0xfffffc3f, 0xfffff83f, 0xfffff03f, 0xffffe03f, 0xffffc03f,
|
||||
0xffff803f, 0xffff003f, 0xfffe003f, 0xfffc003f, 0xfff8003f, 0xfff0003f, 0xffe0003f, 0xffc0003f,
|
||||
0xff80003f, 0xff00003f, 0xfe00003f, 0xfc00003f, 0xf800003f, 0xf000003f, 0xe000003f, 0xc000003f,
|
||||
0x8000003f, 0x0000003f, 0x0000003f, 0x0000003f, 0x0000003f, 0x0000003f, 0x0000003f, 0x0000003f,
|
||||
}, {
|
||||
0xffffff7f, 0xfffffe7f, 0xfffffc7f, 0xfffff87f, 0xfffff07f, 0xffffe07f, 0xffffc07f, 0xffff807f,
|
||||
0xffff007f, 0xfffe007f, 0xfffc007f, 0xfff8007f, 0xfff0007f, 0xffe0007f, 0xffc0007f, 0xff80007f,
|
||||
0xff00007f, 0xfe00007f, 0xfc00007f, 0xf800007f, 0xf000007f, 0xe000007f, 0xc000007f, 0x8000007f,
|
||||
0x0000007f, 0x0000007f, 0x0000007f, 0x0000007f, 0x0000007f, 0x0000007f, 0x0000007f, 0x0000007f,
|
||||
}, {
|
||||
0xfffffeff, 0xfffffcff, 0xfffff8ff, 0xfffff0ff, 0xffffe0ff, 0xffffc0ff, 0xffff80ff, 0xffff00ff,
|
||||
0xfffe00ff, 0xfffc00ff, 0xfff800ff, 0xfff000ff, 0xffe000ff, 0xffc000ff, 0xff8000ff, 0xff0000ff,
|
||||
0xfe0000ff, 0xfc0000ff, 0xf80000ff, 0xf00000ff, 0xe00000ff, 0xc00000ff, 0x800000ff, 0x000000ff,
|
||||
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
|
||||
}, {
|
||||
0xfffffdff, 0xfffff9ff, 0xfffff1ff, 0xffffe1ff, 0xffffc1ff, 0xffff81ff, 0xffff01ff, 0xfffe01ff,
|
||||
0xfffc01ff, 0xfff801ff, 0xfff001ff, 0xffe001ff, 0xffc001ff, 0xff8001ff, 0xff0001ff, 0xfe0001ff,
|
||||
0xfc0001ff, 0xf80001ff, 0xf00001ff, 0xe00001ff, 0xc00001ff, 0x800001ff, 0x000001ff, 0x000001ff,
|
||||
0x000001ff, 0x000001ff, 0x000001ff, 0x000001ff, 0x000001ff, 0x000001ff, 0x000001ff, 0x000001ff,
|
||||
}, {
|
||||
0xfffffbff, 0xfffff3ff, 0xffffe3ff, 0xffffc3ff, 0xffff83ff, 0xffff03ff, 0xfffe03ff, 0xfffc03ff,
|
||||
0xfff803ff, 0xfff003ff, 0xffe003ff, 0xffc003ff, 0xff8003ff, 0xff0003ff, 0xfe0003ff, 0xfc0003ff,
|
||||
0xf80003ff, 0xf00003ff, 0xe00003ff, 0xc00003ff, 0x800003ff, 0x000003ff, 0x000003ff, 0x000003ff,
|
||||
0x000003ff, 0x000003ff, 0x000003ff, 0x000003ff, 0x000003ff, 0x000003ff, 0x000003ff, 0x000003ff,
|
||||
}, {
|
||||
0xfffff7ff, 0xffffe7ff, 0xffffc7ff, 0xffff87ff, 0xffff07ff, 0xfffe07ff, 0xfffc07ff, 0xfff807ff,
|
||||
0xfff007ff, 0xffe007ff, 0xffc007ff, 0xff8007ff, 0xff0007ff, 0xfe0007ff, 0xfc0007ff, 0xf80007ff,
|
||||
0xf00007ff, 0xe00007ff, 0xc00007ff, 0x800007ff, 0x000007ff, 0x000007ff, 0x000007ff, 0x000007ff,
|
||||
0x000007ff, 0x000007ff, 0x000007ff, 0x000007ff, 0x000007ff, 0x000007ff, 0x000007ff, 0x000007ff,
|
||||
}, {
|
||||
0xffffefff, 0xffffcfff, 0xffff8fff, 0xffff0fff, 0xfffe0fff, 0xfffc0fff, 0xfff80fff, 0xfff00fff,
|
||||
0xffe00fff, 0xffc00fff, 0xff800fff, 0xff000fff, 0xfe000fff, 0xfc000fff, 0xf8000fff, 0xf0000fff,
|
||||
0xe0000fff, 0xc0000fff, 0x80000fff, 0x00000fff, 0x00000fff, 0x00000fff, 0x00000fff, 0x00000fff,
|
||||
0x00000fff, 0x00000fff, 0x00000fff, 0x00000fff, 0x00000fff, 0x00000fff, 0x00000fff, 0x00000fff,
|
||||
}, {
|
||||
0xffffdfff, 0xffff9fff, 0xffff1fff, 0xfffe1fff, 0xfffc1fff, 0xfff81fff, 0xfff01fff, 0xffe01fff,
|
||||
0xffc01fff, 0xff801fff, 0xff001fff, 0xfe001fff, 0xfc001fff, 0xf8001fff, 0xf0001fff, 0xe0001fff,
|
||||
0xc0001fff, 0x80001fff, 0x00001fff, 0x00001fff, 0x00001fff, 0x00001fff, 0x00001fff, 0x00001fff,
|
||||
0x00001fff, 0x00001fff, 0x00001fff, 0x00001fff, 0x00001fff, 0x00001fff, 0x00001fff, 0x00001fff,
|
||||
}, {
|
||||
0xffffbfff, 0xffff3fff, 0xfffe3fff, 0xfffc3fff, 0xfff83fff, 0xfff03fff, 0xffe03fff, 0xffc03fff,
|
||||
0xff803fff, 0xff003fff, 0xfe003fff, 0xfc003fff, 0xf8003fff, 0xf0003fff, 0xe0003fff, 0xc0003fff,
|
||||
0x80003fff, 0x00003fff, 0x00003fff, 0x00003fff, 0x00003fff, 0x00003fff, 0x00003fff, 0x00003fff,
|
||||
0x00003fff, 0x00003fff, 0x00003fff, 0x00003fff, 0x00003fff, 0x00003fff, 0x00003fff, 0x00003fff,
|
||||
}, {
|
||||
0xffff7fff, 0xfffe7fff, 0xfffc7fff, 0xfff87fff, 0xfff07fff, 0xffe07fff, 0xffc07fff, 0xff807fff,
|
||||
0xff007fff, 0xfe007fff, 0xfc007fff, 0xf8007fff, 0xf0007fff, 0xe0007fff, 0xc0007fff, 0x80007fff,
|
||||
0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff,
|
||||
0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff,
|
||||
}, {
|
||||
0xfffeffff, 0xfffcffff, 0xfff8ffff, 0xfff0ffff, 0xffe0ffff, 0xffc0ffff, 0xff80ffff, 0xff00ffff,
|
||||
0xfe00ffff, 0xfc00ffff, 0xf800ffff, 0xf000ffff, 0xe000ffff, 0xc000ffff, 0x8000ffff, 0x0000ffff,
|
||||
0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff,
|
||||
0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff,
|
||||
}, {
|
||||
0xfffdffff, 0xfff9ffff, 0xfff1ffff, 0xffe1ffff, 0xffc1ffff, 0xff81ffff, 0xff01ffff, 0xfe01ffff,
|
||||
0xfc01ffff, 0xf801ffff, 0xf001ffff, 0xe001ffff, 0xc001ffff, 0x8001ffff, 0x0001ffff, 0x0001ffff,
|
||||
0x0001ffff, 0x0001ffff, 0x0001ffff, 0x0001ffff, 0x0001ffff, 0x0001ffff, 0x0001ffff, 0x0001ffff,
|
||||
0x0001ffff, 0x0001ffff, 0x0001ffff, 0x0001ffff, 0x0001ffff, 0x0001ffff, 0x0001ffff, 0x0001ffff,
|
||||
}, {
|
||||
0xfffbffff, 0xfff3ffff, 0xffe3ffff, 0xffc3ffff, 0xff83ffff, 0xff03ffff, 0xfe03ffff, 0xfc03ffff,
|
||||
0xf803ffff, 0xf003ffff, 0xe003ffff, 0xc003ffff, 0x8003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff,
|
||||
0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff,
|
||||
0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff,
|
||||
}, {
|
||||
0xfff7ffff, 0xffe7ffff, 0xffc7ffff, 0xff87ffff, 0xff07ffff, 0xfe07ffff, 0xfc07ffff, 0xf807ffff,
|
||||
0xf007ffff, 0xe007ffff, 0xc007ffff, 0x8007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff,
|
||||
0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff,
|
||||
0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff,
|
||||
}, {
|
||||
0xffefffff, 0xffcfffff, 0xff8fffff, 0xff0fffff, 0xfe0fffff, 0xfc0fffff, 0xf80fffff, 0xf00fffff,
|
||||
0xe00fffff, 0xc00fffff, 0x800fffff, 0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff,
|
||||
0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff,
|
||||
0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff,
|
||||
}, {
|
||||
0xffdfffff, 0xff9fffff, 0xff1fffff, 0xfe1fffff, 0xfc1fffff, 0xf81fffff, 0xf01fffff, 0xe01fffff,
|
||||
0xc01fffff, 0x801fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff,
|
||||
0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff,
|
||||
0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff,
|
||||
}, {
|
||||
0xffbfffff, 0xff3fffff, 0xfe3fffff, 0xfc3fffff, 0xf83fffff, 0xf03fffff, 0xe03fffff, 0xc03fffff,
|
||||
0x803fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff,
|
||||
0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff,
|
||||
0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff,
|
||||
}, {
|
||||
0xff7fffff, 0xfe7fffff, 0xfc7fffff, 0xf87fffff, 0xf07fffff, 0xe07fffff, 0xc07fffff, 0x807fffff,
|
||||
0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff,
|
||||
0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff,
|
||||
0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff,
|
||||
}, {
|
||||
0xfeffffff, 0xfcffffff, 0xf8ffffff, 0xf0ffffff, 0xe0ffffff, 0xc0ffffff, 0x80ffffff, 0x00ffffff,
|
||||
0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff,
|
||||
0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff,
|
||||
0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff,
|
||||
}, {
|
||||
0xfdffffff, 0xf9ffffff, 0xf1ffffff, 0xe1ffffff, 0xc1ffffff, 0x81ffffff, 0x01ffffff, 0x01ffffff,
|
||||
0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
|
||||
0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
|
||||
0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
|
||||
}, {
|
||||
0xfbffffff, 0xf3ffffff, 0xe3ffffff, 0xc3ffffff, 0x83ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff,
|
||||
0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff,
|
||||
0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff,
|
||||
0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff,
|
||||
}, {
|
||||
0xf7ffffff, 0xe7ffffff, 0xc7ffffff, 0x87ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff,
|
||||
0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff,
|
||||
0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff,
|
||||
0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff,
|
||||
}, {
|
||||
0xefffffff, 0xcfffffff, 0x8fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff,
|
||||
0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff,
|
||||
0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff,
|
||||
0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff,
|
||||
}, {
|
||||
0xdfffffff, 0x9fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff,
|
||||
0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff,
|
||||
0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff,
|
||||
0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff,
|
||||
}, {
|
||||
0xbfffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff,
|
||||
0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff,
|
||||
0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff,
|
||||
0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff,
|
||||
}, {
|
||||
0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff,
|
||||
0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff,
|
||||
0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff,
|
||||
0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff,
|
||||
} };
|
||||
|
||||
static const uint32_t ExtraMasks[32] =
|
||||
{
|
||||
0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
|
||||
0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff,
|
||||
0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
|
||||
0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
|
||||
};
|
||||
|
||||
// precalculated bit masks for WriteUBitLong.
|
||||
// Using these tables instead of doing the calculations
|
||||
// gives a 33% speedup in WriteUBitLong.
|
||||
static uint32_t BitWriteMasks[32][33];
|
||||
static uint32_t ExtraMasks[32];
|
||||
const char *const svc_strings[svc_lastmsg+1] =
|
||||
{
|
||||
"svc_bad",
|
||||
@@ -298,41 +132,65 @@ const char *const svc_quake_strings[svc_lastmsg+1] =
|
||||
[svc_fog] = "svc_quake_fog",
|
||||
};
|
||||
|
||||
void MSG_InitMasks( void )
|
||||
{
|
||||
uint startbit, endbit;
|
||||
uint maskBit, nBitsLeft;
|
||||
|
||||
for( startbit = 0; startbit < 32; startbit++ )
|
||||
{
|
||||
for( nBitsLeft = 0; nBitsLeft < 33; nBitsLeft++ )
|
||||
{
|
||||
endbit = startbit + nBitsLeft;
|
||||
|
||||
BitWriteMasks[startbit][nBitsLeft] = (uint)BIT( startbit ) - 1;
|
||||
if( endbit < 32 ) BitWriteMasks[startbit][nBitsLeft] |= ~((uint)BIT( endbit ) - 1 );
|
||||
}
|
||||
}
|
||||
|
||||
for( maskBit = 0; maskBit < 32; maskBit++ )
|
||||
ExtraMasks[maskBit] = (uint)BIT( maskBit ) - 1;
|
||||
}
|
||||
|
||||
void MSG_WriteUBitLong( sizebuf_t *sb, uint curData, int numbits )
|
||||
{
|
||||
int nBitsLeft = numbits;
|
||||
int iCurBit = sb->iCurBit;
|
||||
uint iDWord = iCurBit >> 5; // Mask in a dword.
|
||||
uint32_t iCurBitMasked;
|
||||
int nBitsWritten;
|
||||
|
||||
Assert( numbits >= 1 && numbits <= 32 );
|
||||
Assert( numbits >= 0 && numbits <= 32 );
|
||||
|
||||
// bounds checking..
|
||||
if( MSG_Overflow( sb, numbits ))
|
||||
if(( sb->iCurBit + numbits ) > sb->nDataBits )
|
||||
{
|
||||
sb->bOverflow = true;
|
||||
sb->iCurBit = sb->nDataBits;
|
||||
return;
|
||||
}
|
||||
|
||||
iCurBitMasked = iCurBit & 31;
|
||||
((uint32_t *)sb->pData)[iDWord] &= BitWriteMasks[iCurBitMasked][nBitsLeft-1];
|
||||
((uint32_t *)sb->pData)[iDWord] |= curData << iCurBitMasked;
|
||||
|
||||
// did it span a dword?
|
||||
nBitsWritten = 32 - iCurBitMasked;
|
||||
|
||||
if( nBitsWritten < nBitsLeft )
|
||||
else
|
||||
{
|
||||
nBitsLeft -= nBitsWritten;
|
||||
iCurBit += nBitsWritten;
|
||||
curData >>= nBitsWritten;
|
||||
int nBitsLeft = numbits;
|
||||
int iCurBit = sb->iCurBit;
|
||||
uint iDWord = iCurBit >> 5; // Mask in a dword.
|
||||
uint32_t iCurBitMasked;
|
||||
int nBitsWritten;
|
||||
|
||||
Assert(( iDWord * 4 + sizeof( int )) <= (uint)MSG_GetMaxBytes( sb ));
|
||||
|
||||
iCurBitMasked = iCurBit & 31;
|
||||
((uint32_t *)sb->pData)[iDWord+1] &= BitWriteMasks[iCurBitMasked][nBitsLeft-1];
|
||||
((uint32_t *)sb->pData)[iDWord+1] |= curData << iCurBitMasked;
|
||||
((uint32_t *)sb->pData)[iDWord] &= BitWriteMasks[iCurBitMasked][nBitsLeft];
|
||||
((uint32_t *)sb->pData)[iDWord] |= curData << iCurBitMasked;
|
||||
|
||||
// did it span a dword?
|
||||
nBitsWritten = 32 - iCurBitMasked;
|
||||
|
||||
if( nBitsWritten < nBitsLeft )
|
||||
{
|
||||
nBitsLeft -= nBitsWritten;
|
||||
iCurBit += nBitsWritten;
|
||||
curData >>= nBitsWritten;
|
||||
|
||||
iCurBitMasked = iCurBit & 31;
|
||||
((uint32_t *)sb->pData)[iDWord+1] &= BitWriteMasks[iCurBitMasked][nBitsLeft];
|
||||
((uint32_t *)sb->pData)[iDWord+1] |= curData << iCurBitMasked;
|
||||
}
|
||||
sb->iCurBit += numbits;
|
||||
}
|
||||
sb->iCurBit += numbits;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -380,7 +238,7 @@ qboolean MSG_WriteBits( sizebuf_t *sb, const void *pData, int nBits )
|
||||
int nBitsLeft = nBits;
|
||||
|
||||
// get output dword-aligned.
|
||||
while((( uintptr_t )pOut & 3 ) != 0 && nBitsLeft >= 8 )
|
||||
while((( uint32_t )pOut & 3 ) != 0 && nBitsLeft >= 8 )
|
||||
{
|
||||
MSG_WriteUBitLong( sb, *pOut, 8 );
|
||||
|
||||
@@ -417,14 +275,16 @@ qboolean MSG_WriteBits( sizebuf_t *sb, const void *pData, int nBits )
|
||||
|
||||
void MSG_WriteBitAngle( sizebuf_t *sb, float fAngle, int numbits )
|
||||
{
|
||||
const uint shift = ( 1 << numbits );
|
||||
const uint mask = shift - 1;
|
||||
uint mask, shift;
|
||||
int d;
|
||||
|
||||
// clamp the angle before receiving
|
||||
fAngle = fmod( fAngle, 360.0f );
|
||||
if( fAngle < 0 ) fAngle += 360.0f;
|
||||
|
||||
shift = ( 1 << numbits );
|
||||
mask = shift - 1;
|
||||
|
||||
d = (int)(( fAngle * shift ) / 360.0f );
|
||||
d &= mask;
|
||||
|
||||
@@ -578,8 +438,9 @@ uint MSG_ReadUBitLong( sizebuf_t *sb, int numbits )
|
||||
return 0; // end of message
|
||||
}
|
||||
|
||||
if( MSG_Overflow( sb, numbits ))
|
||||
if(( sb->iCurBit + numbits ) > sb->nDataBits )
|
||||
{
|
||||
sb->bOverflow = true;
|
||||
sb->iCurBit = sb->nDataBits;
|
||||
return 0;
|
||||
}
|
||||
@@ -652,9 +513,13 @@ qboolean MSG_ReadBits( sizebuf_t *sb, void *pOutData, int nBits )
|
||||
|
||||
float MSG_ReadBitAngle( sizebuf_t *sb, int numbits )
|
||||
{
|
||||
float shift = (float)( 1 << numbits );
|
||||
int i = MSG_ReadUBitLong( sb, numbits );
|
||||
float fReturn = (float)i * ( 360.0f / shift );
|
||||
float fReturn, shift;
|
||||
int i;
|
||||
|
||||
shift = (float)( 1 << numbits );
|
||||
|
||||
i = MSG_ReadUBitLong( sb, numbits );
|
||||
fReturn = (float)i * ( 360.0f / shift );
|
||||
|
||||
// clamp the finale angle
|
||||
if( fReturn < -180.0f ) fReturn += 360.0f;
|
||||
@@ -666,11 +531,11 @@ float MSG_ReadBitAngle( sizebuf_t *sb, int numbits )
|
||||
// Append numbits least significant bits from data to the current bit stream
|
||||
int MSG_ReadSBitLong( sizebuf_t *sb, int numbits )
|
||||
{
|
||||
int r;
|
||||
int r, sign;
|
||||
|
||||
if( sb->iAlternateSign )
|
||||
{
|
||||
int sign = MSG_ReadOneBit( sb );
|
||||
sign = MSG_ReadOneBit( sb );
|
||||
r = MSG_ReadUBitLong( sb, numbits - 1 );
|
||||
|
||||
if( sign )
|
||||
@@ -679,7 +544,9 @@ int MSG_ReadSBitLong( sizebuf_t *sb, int numbits )
|
||||
else
|
||||
{
|
||||
r = MSG_ReadUBitLong( sb, numbits - 1 );
|
||||
if( MSG_ReadOneBit( sb ))
|
||||
sign = MSG_ReadOneBit( sb );
|
||||
|
||||
if( sign )
|
||||
r = -( BIT( numbits - 1 ) - r );
|
||||
}
|
||||
|
||||
@@ -800,12 +667,12 @@ qboolean MSG_ReadBytes( sizebuf_t *sb, void *pOut, int nBytes )
|
||||
static char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine )
|
||||
{
|
||||
static char string[4096];
|
||||
int l = 0;
|
||||
int l = 0, c;
|
||||
|
||||
do
|
||||
{
|
||||
// use MSG_ReadByte so -1 is out of bounds
|
||||
int c = MSG_ReadByte( sb );
|
||||
c = MSG_ReadByte( sb );
|
||||
|
||||
if( c == 0 ) break;
|
||||
else if( bLine && c == '\n' )
|
||||
@@ -998,6 +865,8 @@ static void Test_Buffer_ExciseBits( void )
|
||||
|
||||
void Test_RunBuffer( void )
|
||||
{
|
||||
MSG_InitMasks();
|
||||
|
||||
TRUN( Test_Buffer_BitByte( ));
|
||||
TRUN( Test_Buffer_Write( ));
|
||||
TRUN( Test_Buffer_Read( ));
|
||||
|
||||
@@ -193,6 +193,7 @@ static inline void MSG_StartBitWriting( sizebuf_t *sb )
|
||||
sb->iAlternateSign++;
|
||||
}
|
||||
|
||||
void MSG_InitMasks( void ); // called once at startup engine
|
||||
void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove );
|
||||
|
||||
// Bit-write functions
|
||||
|
||||
@@ -272,6 +272,8 @@ void Netchan_Init( void )
|
||||
Cvar_FullSet( net_qport.name, buf, net_qport.flags );
|
||||
|
||||
net_mempool = Mem_AllocPool( "Network Pool" );
|
||||
|
||||
MSG_InitMasks(); // initialize bit-masks
|
||||
}
|
||||
|
||||
void Netchan_Shutdown( void )
|
||||
@@ -341,7 +343,6 @@ void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport, voi
|
||||
chan->split = FBitSet( flags, NETCHAN_USE_LEGACY_SPLIT ) ? true : false;
|
||||
chan->use_munge = FBitSet( flags, NETCHAN_USE_MUNGE ) ? true : false;
|
||||
chan->use_bz2 = FBitSet( flags, NETCHAN_USE_BZIP2 ) ? true : false;
|
||||
chan->use_lzss = FBitSet( flags, NETCHAN_USE_LZSS ) ? true : false;
|
||||
chan->gs_netchan = FBitSet( flags, NETCHAN_GOLDSRC ) ? true : false;
|
||||
|
||||
MSG_Init( &chan->message, "NetData", chan->message_buf, sizeof( chan->message_buf ));
|
||||
@@ -767,7 +768,7 @@ static void Netchan_CreateFragments_( netchan_t *chan, sizebuf_t *msg )
|
||||
Host_Error( "%s: BZ2 compression is not supported for server", __func__ );
|
||||
#endif
|
||||
}
|
||||
else if( chan->use_lzss && !LZSS_IsCompressed( MSG_GetData( msg ), MSG_GetMaxBytes( msg )))
|
||||
else if( !chan->use_bz2 && !LZSS_IsCompressed( MSG_GetData( msg ), MSG_GetMaxBytes( msg )))
|
||||
{
|
||||
uint uCompressedSize = 0;
|
||||
uint uSourceSize = MSG_GetNumBytesWritten( msg );
|
||||
@@ -1174,7 +1175,7 @@ qboolean Netchan_CopyNormalFragments( netchan_t *chan, sizebuf_t *msg, size_t *l
|
||||
p = n;
|
||||
}
|
||||
|
||||
if( chan->use_bz2 && !memcmp( MSG_GetData( msg ), "BZ2", 4 ))
|
||||
if( chan->use_bz2 && !memcmp( MSG_GetData( msg ), "BZ2", 4 ) )
|
||||
{
|
||||
#if !XASH_DEDICATED
|
||||
byte buf[0x10000];
|
||||
@@ -1195,7 +1196,7 @@ qboolean Netchan_CopyNormalFragments( netchan_t *chan, sizebuf_t *msg, size_t *l
|
||||
Host_Error( "%s: BZ2 compression is not supported for server\n", __func__ );
|
||||
#endif
|
||||
}
|
||||
else if( chan->use_lzss && LZSS_IsCompressed( MSG_GetData( msg ), size ))
|
||||
else if( !chan->use_bz2 && LZSS_IsCompressed( MSG_GetData( msg ), size ))
|
||||
{
|
||||
uint uDecompressedLen = LZSS_GetActualSize( MSG_GetData( msg ), size );
|
||||
byte buf[NET_MAX_MESSAGE];
|
||||
@@ -1346,7 +1347,7 @@ qboolean Netchan_CopyFileFragments( netchan_t *chan, sizebuf_t *msg )
|
||||
Host_Error( "%s: BZ2 compression is not supported for server", __func__ );
|
||||
#endif
|
||||
}
|
||||
else if( chan->use_lzss && LZSS_IsCompressed( buffer, nsize + 1 ))
|
||||
else if( LZSS_IsCompressed( buffer, nsize + 1 ))
|
||||
{
|
||||
byte *uncompressedBuffer;
|
||||
|
||||
|
||||
@@ -2282,6 +2282,10 @@ void Test_RunDelta( void )
|
||||
char buffer[4096] = { 0 };
|
||||
const double timebase = 123.123;
|
||||
|
||||
// a1ba: netbuffer bitmasks are initialized in netchan for some reason
|
||||
// initialize it ourselves just in case
|
||||
MSG_InitMasks(); // initialize bit-masks
|
||||
|
||||
Delta_AddField( dt, "dt_string", DT_STRING, 1, 1.0f, 1.0f );
|
||||
Delta_AddField( dt, "dt_timewindow_big", DT_TIMEWINDOW_BIG, 24, 1000.f, 1.0f );
|
||||
Delta_AddField( dt, "dt_timewindow_8", DT_TIMEWINDOW_8, 8, 1.0f, 1.0f );
|
||||
|
||||
@@ -505,14 +505,11 @@ static int HTTP_FileDecompress( httpfile_t *file )
|
||||
|
||||
if( zlib_result == Z_OK || zlib_result == Z_STREAM_END )
|
||||
{
|
||||
g_fsapi.WriteFile( name, data_out, decompressed_len );
|
||||
HTTP_FreeFile( file, false );
|
||||
Mem_Free( data_in );
|
||||
}
|
||||
else HTTP_FreeFile( file, true );
|
||||
|
||||
Mem_Free( data_in );
|
||||
Mem_Free( data_out );
|
||||
|
||||
g_fsapi.WriteFile( name, data_out, decompressed_len );
|
||||
HTTP_FreeFile( file, false );
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -214,7 +214,6 @@ typedef enum netchan_flags_e
|
||||
NETCHAN_USE_MUNGE = BIT( 1 ),
|
||||
NETCHAN_USE_BZIP2 = BIT( 2 ),
|
||||
NETCHAN_GOLDSRC = BIT( 3 ),
|
||||
NETCHAN_USE_LZSS = BIT( 4 ), // mutually exclusive with bzip2
|
||||
} netchan_flags_t;
|
||||
|
||||
// Network Connection Channel
|
||||
@@ -286,7 +285,6 @@ typedef struct netchan_s
|
||||
qboolean split;
|
||||
qboolean use_munge;
|
||||
qboolean use_bz2;
|
||||
qboolean use_lzss;
|
||||
qboolean gs_netchan;
|
||||
} netchan_t;
|
||||
|
||||
|
||||
@@ -89,6 +89,16 @@ void Sound_Shutdown( void )
|
||||
Mem_FreePool( &host.soundpool );
|
||||
}
|
||||
|
||||
static byte *Sound_Copy( size_t size )
|
||||
{
|
||||
byte *out;
|
||||
|
||||
out = Mem_Realloc( host.soundpool, sound.tempbuffer, size );
|
||||
sound.tempbuffer = NULL;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
uint GAME_EXPORT Sound_GetApproxWavePlayLen( const char *filepath )
|
||||
{
|
||||
string name;
|
||||
@@ -368,7 +378,6 @@ static qboolean Sound_ResampleInternal( wavdata_t *sc, int outrate, int outwidth
|
||||
const int inwidth = sc->width;
|
||||
const int inchannels = sc->channels;
|
||||
const int incount = sc->samples;
|
||||
const int insize = sc->size;
|
||||
qboolean handled = false;
|
||||
double stepscale;
|
||||
double t1, t2;
|
||||
@@ -422,30 +431,22 @@ static qboolean Sound_ResampleInternal( wavdata_t *sc, int outrate, int outwidth
|
||||
else // upsample case, w/ interpolation
|
||||
handled = Sound_ConvertUpsample( sc, inwidth, inchannels, incount, outwidth, outchannels, outcount, stepscale );
|
||||
|
||||
if( !handled )
|
||||
{
|
||||
// restore previously changed data
|
||||
sc->rate = inrate;
|
||||
sc->width = inwidth;
|
||||
sc->channels = inchannels;
|
||||
sc->samples = incount;
|
||||
sc->size = insize;
|
||||
t2 = Sys_DoubleTime();
|
||||
|
||||
if( handled )
|
||||
{
|
||||
if( t2 - t1 > 0.01f ) // critical, report to mod developer
|
||||
Con_Printf( S_WARN "%s: from [%d bit %d Hz %dch] to [%d bit %d Hz %dch] (took %.3fs)\n", __func__, inwidth * 8, inrate, inchannels, outwidth * 8, outrate, outchannels, t2 - t1 );
|
||||
else
|
||||
Con_Reportf( "%s: from [%d bit %d Hz %dch] to [%d bit %d Hz %dch] (took %.3fs)\n", __func__, inwidth * 8, inrate, inchannels, outwidth * 8, outrate, outchannels, t2 - t1 );
|
||||
}
|
||||
else
|
||||
Con_Printf( S_ERROR "%s: unsupported from [%d bit %d Hz %dch] to [%d bit %d Hz %dch]\n", __func__, inwidth * 8, inrate, inchannels, outwidth * 8, outrate, outchannels );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
t2 = Sys_DoubleTime();
|
||||
sc->rate = outrate;
|
||||
sc->width = outwidth;
|
||||
|
||||
if( t2 - t1 > 0.01f ) // critical, report to mod developer
|
||||
Con_Printf( S_WARN "%s: from [%d bit %d Hz %dch] to [%d bit %d Hz %dch] (took %.3fs)\n", __func__, inwidth * 8, inrate, inchannels, outwidth * 8, outrate, outchannels, t2 - t1 );
|
||||
else
|
||||
Con_Reportf( "%s: from [%d bit %d Hz %dch] to [%d bit %d Hz %dch] (took %.3fs)\n", __func__, inwidth * 8, inrate, inchannels, outwidth * 8, outrate, outchannels, t2 - t1 );
|
||||
|
||||
return true;
|
||||
return handled;
|
||||
}
|
||||
|
||||
qboolean Sound_Process( wavdata_t **wav, int rate, int width, int channels, uint flags )
|
||||
@@ -463,11 +464,8 @@ qboolean Sound_Process( wavdata_t **wav, int rate, int width, int channels, uint
|
||||
|
||||
if( result )
|
||||
{
|
||||
snd = Mem_Realloc( host.soundpool, snd, sizeof( *snd ) + snd->size );
|
||||
memcpy( snd->buffer, sound.tempbuffer, snd->size );
|
||||
|
||||
Mem_Free( sound.tempbuffer );
|
||||
sound.tempbuffer = NULL;
|
||||
Mem_Free( snd->buffer ); // free original image buffer
|
||||
snd->buffer = Sound_Copy( snd->size ); // unzone buffer
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,15 +41,6 @@ NOTE: never change this structure because all dll descriptions in xash code
|
||||
writes into struct by offsets not names
|
||||
========================================================================
|
||||
*/
|
||||
typedef struct dll_info_s
|
||||
{
|
||||
const char *name; // name of library
|
||||
const dllfunc_t *fcts; // list of dll exports
|
||||
const size_t num_fcts;
|
||||
qboolean crash; // crash if dll not found
|
||||
void *link; // hinstance of loading library
|
||||
} dll_info_t;
|
||||
|
||||
extern int error_on_exit;
|
||||
double Sys_DoubleTime( void );
|
||||
char *Sys_GetClipboardData( void );
|
||||
|
||||
@@ -68,13 +68,7 @@ extern "C" {
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
#if (_MSC_VER >= 1900)
|
||||
#include <stdbool.h>
|
||||
#else
|
||||
#define bool int
|
||||
#define false 0
|
||||
#define true 1
|
||||
#endif
|
||||
|
||||
static int WAI_PREFIX(getModulePath_)(HMODULE module, char* out, int capacity, int* dirname_length)
|
||||
{
|
||||
@@ -249,11 +243,6 @@ int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(WAI_STRINGIZE)
|
||||
#define WAI_STRINGIZE(s)
|
||||
#define WAI_STRINGIZE_(s) #s
|
||||
#endif
|
||||
|
||||
#if defined(__ANDROID__) || defined(ANDROID)
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
@@ -276,20 +265,20 @@ int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
|
||||
|
||||
for (;;)
|
||||
{
|
||||
char buffer[128 + PATH_MAX];
|
||||
uintptr_t low, high;
|
||||
char buffer[PATH_MAX < 1024 ? 1024 : PATH_MAX];
|
||||
uint64_t low, high;
|
||||
char perms[5];
|
||||
uint64_t offset;
|
||||
uint32_t major, minor, inode;
|
||||
char path[PATH_MAX + 1];
|
||||
uint32_t major, minor;
|
||||
char path[PATH_MAX];
|
||||
uint32_t inode;
|
||||
|
||||
if (!fgets(buffer, sizeof(buffer), maps))
|
||||
break;
|
||||
|
||||
if (sscanf(buffer, "%" SCNxPTR "-%" SCNxPTR " %s %" SCNx64 " %x:%x %u %" WAI_STRINGIZE(PATH_MAX) "[^\n]\n", &low, &high, perms, &offset, &major, &minor, &inode, path) == 8)
|
||||
if (sscanf(buffer, "%" PRIx64 "-%" PRIx64 " %s %" PRIx64 " %x:%x %u %s\n", &low, &high, perms, &offset, &major, &minor, &inode, path) == 8)
|
||||
{
|
||||
void* _addr = WAI_RETURN_ADDRESS();
|
||||
uintptr_t addr = (uintptr_t)_addr;
|
||||
uint64_t addr = (uintptr_t)WAI_RETURN_ADDRESS();
|
||||
if (low <= addr && addr <= high)
|
||||
{
|
||||
char* resolved;
|
||||
|
||||
@@ -31,8 +31,7 @@ extern "C" {
|
||||
* @param out destination buffer, optional
|
||||
* @param capacity destination buffer capacity
|
||||
* @param dirname_length optional recipient for the length of the dirname part
|
||||
* of the path. Available only when `capacity` is large enough to retrieve the
|
||||
* path.
|
||||
* of the path.
|
||||
*
|
||||
* @return the length of the executable path on success (without a terminal NUL
|
||||
* character), otherwise `-1`
|
||||
@@ -53,8 +52,7 @@ int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length);
|
||||
* @param out destination buffer, optional
|
||||
* @param capacity destination buffer capacity
|
||||
* @param dirname_length optional recipient for the length of the dirname part
|
||||
* of the path. Available only when `capacity` is large enough to retrieve the
|
||||
* path.
|
||||
* of the path.
|
||||
*
|
||||
* @return the length of the module path on success (without a terminal NUL
|
||||
* character), otherwise `-1`
|
||||
|
||||
@@ -18,7 +18,7 @@ GNU General Public License for more details.
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define MEMHEADER_SENTINEL1 0xA1BAU
|
||||
#define MEMHEADER_SENTINEL1 0xDEADF00DU
|
||||
#define MEMHEADER_SENTINEL2 0xDFU
|
||||
|
||||
#ifdef XASH_CUSTOM_SWAP
|
||||
@@ -51,29 +51,31 @@ static void *Q_realloc( void *mem, size_t size )
|
||||
#define Q_realloc realloc
|
||||
#endif
|
||||
|
||||
// keep this structure as compact as possible while keeping it aligned
|
||||
// on ILP32 it's 24 bytes, which is aligned to 8 byte boundary
|
||||
// on LP64 it's 40 bytes, which is also aligned to 8 byte boundary
|
||||
typedef struct memheader_s
|
||||
{
|
||||
struct memheader_s *next, *prev; // next and previous memheaders in chain belonging to pool
|
||||
const char *filename; // file name and line where Mem_Alloc was called
|
||||
size_t size; // size of the memory after the header (excluding header and sentinel2)
|
||||
poolhandle_t poolptr; // pool this memheader belongs to
|
||||
uint16_t fileline;
|
||||
uint16_t sentinel1; // must be equal to MEMHEADER_SENTINEL1
|
||||
struct memheader_s *next; // next and previous memheaders in chain belonging to pool
|
||||
struct memheader_s *prev;
|
||||
const char *filename; // file name and line where Mem_Alloc was called
|
||||
size_t size; // size of the memory after the header (excluding header and sentinel2)
|
||||
poolhandle_t poolptr; // pool this memheader belongs to
|
||||
int fileline;
|
||||
#if !XASH_64BIT
|
||||
uint32_t pad0; // doesn't have value, only to make Mem_Alloc return aligned addresses on ILP32
|
||||
#endif
|
||||
uint32_t sentinel1; // should always be MEMHEADER_SENTINEL1
|
||||
|
||||
// immediately followed by data, which is followed by a MEMHEADER_SENTINEL2 byte
|
||||
} memheader_t;
|
||||
|
||||
typedef struct mempool_s
|
||||
{
|
||||
struct memheader_s *chain; // chain of individual memory allocations
|
||||
size_t totalsize; // total memory allocated in this pool (inside memheaders)
|
||||
size_t realsize; // total memory allocated in this pool (actual malloc total)
|
||||
size_t lastchecksize; // updated each time the pool is displayed by memlist
|
||||
const char *filename; // file name and line where Mem_AllocPool was called
|
||||
int fileline;
|
||||
char name[64]; // name of the pool
|
||||
struct memheader_s *chain; // chain of individual memory allocations
|
||||
size_t totalsize; // total memory allocated in this pool (inside memheaders)
|
||||
size_t realsize; // total memory allocated in this pool (actual malloc total)
|
||||
size_t lastchecksize; // updated each time the pool is displayed by memlist
|
||||
const char *filename; // file name and line where Mem_AllocPool was called
|
||||
int fileline;
|
||||
char name[64]; // name of the pool
|
||||
} mempool_t;
|
||||
|
||||
static mempool_t *poolchain = NULL; // critical stuff
|
||||
@@ -519,5 +521,4 @@ Memory_Init
|
||||
void Memory_Init( void )
|
||||
{
|
||||
poolchain = NULL; // init mem chain
|
||||
poolcount = 0;
|
||||
}
|
||||
|
||||
300
engine/keydefs.h
300
engine/keydefs.h
@@ -1,164 +1,186 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
/***
|
||||
*
|
||||
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
|
||||
*
|
||||
* This product contains software technology licensed from Id
|
||||
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Use, distribution, and modification of this source code and/or resulting
|
||||
* object code is restricted to non-commercial enhancements to products from
|
||||
* Valve LLC. All other use, distribution, or modification is prohibited
|
||||
* without written permission from Valve LLC.
|
||||
*
|
||||
****/
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
// taken from Quake-2 source code and modified for GoldSrc compatibility
|
||||
#ifndef KEYDEFS_H
|
||||
#define KEYDEFS_H
|
||||
|
||||
//
|
||||
// these are the key numbers that should be passed to Key_Event
|
||||
// normal keys should be passed as lowercased ascii
|
||||
//
|
||||
#define K_TAB 9
|
||||
#define K_ENTER 13
|
||||
#define K_ESCAPE 27
|
||||
#define K_SPACE 32
|
||||
#define K_SCROLLLOCK 70
|
||||
#define K_BACKSPACE 127
|
||||
#define K_UPARROW 128
|
||||
#define K_DOWNARROW 129
|
||||
#define K_LEFTARROW 130
|
||||
#define K_RIGHTARROW 131
|
||||
#define K_ALT 132
|
||||
#define K_CTRL 133
|
||||
#define K_SHIFT 134
|
||||
#define K_F1 135
|
||||
#define K_F2 136
|
||||
#define K_F3 137
|
||||
#define K_F4 138
|
||||
#define K_F5 139
|
||||
#define K_F6 140
|
||||
#define K_F7 141
|
||||
#define K_F8 142
|
||||
#define K_F9 143
|
||||
#define K_F10 144
|
||||
#define K_F11 145
|
||||
#define K_F12 146
|
||||
#define K_INS 147
|
||||
#define K_DEL 148
|
||||
#define K_PGDN 149
|
||||
#define K_PGUP 150
|
||||
#define K_HOME 151
|
||||
#define K_END 152
|
||||
#define K_TAB 9
|
||||
#define K_ENTER 13
|
||||
#define K_ESCAPE 27
|
||||
#define K_SPACE 32
|
||||
#define K_SCROLLOCK 70
|
||||
|
||||
#define K_KP_HOME 160
|
||||
#define K_KP_UPARROW 161
|
||||
#define K_KP_PGUP 162
|
||||
#define K_KP_LEFTARROW 163
|
||||
#define K_KP_5 164
|
||||
// normal keys should be passed as lowercased ascii
|
||||
|
||||
#define K_BACKSPACE 127
|
||||
#define K_UPARROW 128
|
||||
#define K_DOWNARROW 129
|
||||
#define K_LEFTARROW 130
|
||||
#define K_RIGHTARROW 131
|
||||
|
||||
#define K_ALT 132
|
||||
#define K_CTRL 133
|
||||
#define K_SHIFT 134
|
||||
#define K_F1 135
|
||||
#define K_F2 136
|
||||
#define K_F3 137
|
||||
#define K_F4 138
|
||||
#define K_F5 139
|
||||
#define K_F6 140
|
||||
#define K_F7 141
|
||||
#define K_F8 142
|
||||
#define K_F9 143
|
||||
#define K_F10 144
|
||||
#define K_F11 145
|
||||
#define K_F12 146
|
||||
#define K_INS 147
|
||||
#define K_DEL 148
|
||||
#define K_PGDN 149
|
||||
#define K_PGUP 150
|
||||
#define K_HOME 151
|
||||
#define K_END 152
|
||||
|
||||
#define K_KP_HOME 160
|
||||
#define K_KP_UPARROW 161
|
||||
#define K_KP_PGUP 162
|
||||
#define K_KP_LEFTARROW 163
|
||||
#define K_KP_5 164
|
||||
#define K_KP_RIGHTARROW 165
|
||||
#define K_KP_END 166
|
||||
#define K_KP_DOWNARROW 167
|
||||
#define K_KP_PGDN 168
|
||||
#define K_KP_ENTER 169
|
||||
#define K_KP_INS 170
|
||||
#define K_KP_DEL 171
|
||||
#define K_KP_SLASH 172
|
||||
#define K_KP_MINUS 173
|
||||
#define K_KP_PLUS 174
|
||||
#define K_CAPSLOCK 175
|
||||
#define K_KP_MUL 176
|
||||
#define K_WIN 177
|
||||
#define K_KP_NUMLOCK 178
|
||||
#define K_KP_END 166
|
||||
#define K_KP_DOWNARROW 167
|
||||
#define K_KP_PGDN 168
|
||||
#define K_KP_ENTER 169
|
||||
#define K_KP_INS 170
|
||||
#define K_KP_DEL 171
|
||||
#define K_KP_SLASH 172
|
||||
#define K_KP_MINUS 173
|
||||
#define K_KP_PLUS 174
|
||||
#define K_CAPSLOCK 175
|
||||
#define K_KP_MUL 176
|
||||
#define K_WIN 177
|
||||
#define K_KP_NUMLOCK 178
|
||||
|
||||
//
|
||||
// joystick buttons
|
||||
//
|
||||
#define K_JOY1 203
|
||||
#define K_JOY2 204
|
||||
#define K_JOY3 205
|
||||
#define K_JOY4 206
|
||||
#define K_JOY1 203 // LTRIGGER (L2)
|
||||
#define K_JOY2 204 // RTRIGGER (R2)
|
||||
#define K_JOY3 205
|
||||
#define K_JOY4 206
|
||||
|
||||
//
|
||||
// aux keys are for multi-buttoned joysticks to generate so they can use
|
||||
// the normal binding process
|
||||
//
|
||||
#define K_AUX1 207
|
||||
#define K_AUX2 208
|
||||
#define K_AUX3 209
|
||||
#define K_AUX4 210
|
||||
#define K_AUX5 211
|
||||
#define K_AUX6 212
|
||||
#define K_AUX7 213
|
||||
#define K_AUX8 214
|
||||
#define K_AUX9 215
|
||||
#define K_AUX10 216
|
||||
#define K_AUX11 217
|
||||
#define K_AUX12 218
|
||||
#define K_AUX13 219
|
||||
#define K_AUX14 220
|
||||
#define K_AUX15 221
|
||||
#define K_AUX16 222
|
||||
#define K_AUX17 223
|
||||
#define K_AUX18 224
|
||||
#define K_AUX19 225
|
||||
#define K_AUX20 226
|
||||
#define K_AUX21 227
|
||||
#define K_AUX22 228
|
||||
#define K_AUX23 229
|
||||
#define K_AUX24 230
|
||||
#define K_AUX25 231
|
||||
#define K_AUX26 232
|
||||
#define K_AUX27 233
|
||||
#define K_AUX28 234
|
||||
#define K_AUX29 235
|
||||
#define K_AUX30 236
|
||||
#define K_AUX31 237
|
||||
#define K_AUX32 238
|
||||
#define K_AUX1 207
|
||||
#define K_A_BUTTON K_AUX1
|
||||
|
||||
//
|
||||
// button names for game pads
|
||||
//
|
||||
#define K_A_BUTTON K_AUX1
|
||||
#define K_B_BUTTON K_AUX2
|
||||
#define K_X_BUTTON K_AUX3
|
||||
#define K_Y_BUTTON K_AUX4
|
||||
#define K_L1_BUTTON K_AUX5
|
||||
#define K_R1_BUTTON K_AUX6
|
||||
#define K_BACK_BUTTON K_AUX7
|
||||
#define K_MODE_BUTTON K_AUX8
|
||||
#define K_START_BUTTON K_AUX9
|
||||
#define K_LSTICK K_AUX10
|
||||
#define K_RSTICK K_AUX11
|
||||
#define K_L2_BUTTON K_AUX12
|
||||
#define K_R2_BUTTON K_AUX13
|
||||
#define K_C_BUTTON K_AUX14
|
||||
#define K_Z_BUTTON K_AUX15
|
||||
#define K_DPAD_UP K_AUX16
|
||||
#define K_DPAD_DOWN K_AUX17
|
||||
#define K_DPAD_LEFT K_AUX18
|
||||
#define K_DPAD_RIGHT K_AUX19
|
||||
#define K_MISC_BUTTON K_AUX20
|
||||
#define K_PADDLE1_BUTTON K_AUX21
|
||||
#define K_AUX2 208
|
||||
#define K_B_BUTTON K_AUX2
|
||||
|
||||
#define K_AUX3 209
|
||||
#define K_X_BUTTON K_AUX3
|
||||
|
||||
#define K_AUX4 210
|
||||
#define K_Y_BUTTON K_AUX4
|
||||
|
||||
#define K_AUX5 211
|
||||
#define K_L1_BUTTON K_AUX5
|
||||
|
||||
#define K_AUX6 212
|
||||
#define K_R1_BUTTON K_AUX6
|
||||
|
||||
#define K_AUX7 213
|
||||
#define K_BACK_BUTTON K_AUX7
|
||||
|
||||
#define K_AUX8 214
|
||||
#define K_MODE_BUTTON K_AUX8
|
||||
|
||||
#define K_AUX9 215
|
||||
#define K_START_BUTTON K_AUX9
|
||||
|
||||
#define K_AUX10 216
|
||||
#define K_LSTICK K_AUX10
|
||||
|
||||
#define K_AUX11 217
|
||||
#define K_RSTICK K_AUX11
|
||||
|
||||
#define K_AUX12 218
|
||||
#define K_L2_BUTTON K_AUX12
|
||||
|
||||
#define K_AUX13 219
|
||||
#define K_R2_BUTTON K_AUX13
|
||||
|
||||
#define K_AUX14 220
|
||||
#define K_C_BUTTON K_AUX14
|
||||
|
||||
#define K_AUX15 221
|
||||
#define K_Z_BUTTON K_AUX15
|
||||
|
||||
#define K_AUX16 222
|
||||
#define K_DPAD_UP K_AUX16
|
||||
|
||||
#define K_AUX17 223
|
||||
#define K_DPAD_DOWN K_AUX17
|
||||
|
||||
#define K_AUX18 224
|
||||
#define K_DPAD_LEFT K_AUX18
|
||||
|
||||
#define K_AUX19 225
|
||||
#define K_DPAD_RIGHT K_AUX19
|
||||
|
||||
#define K_AUX20 226
|
||||
#define K_MISC_BUTTON K_AUX20 // Xbox Series X share button, PS5 microphone button, Nintendo Switch Pro capture button
|
||||
|
||||
#define K_AUX21 227
|
||||
#define K_PADDLE1_BUTTON K_AUX21 // Xbox Elite paddle P1-P4
|
||||
|
||||
#define K_AUX22 228
|
||||
#define K_PADDLE2_BUTTON K_AUX22
|
||||
|
||||
#define K_AUX23 229
|
||||
#define K_PADDLE3_BUTTON K_AUX23
|
||||
|
||||
#define K_AUX24 230
|
||||
#define K_PADDLE4_BUTTON K_AUX24
|
||||
#define K_TOUCHPAD K_AUX25
|
||||
|
||||
#define K_AUX25 231
|
||||
#define K_TOUCHPAD K_AUX25 // PS4/PS5 touchpad button
|
||||
|
||||
#define K_AUX26 232
|
||||
#define K_AUX27 233
|
||||
#define K_AUX28 234
|
||||
#define K_AUX29 235
|
||||
#define K_AUX30 236
|
||||
#define K_AUX31 237
|
||||
#define K_AUX32 238
|
||||
#define K_MWHEELDOWN 239
|
||||
#define K_MWHEELUP 240
|
||||
|
||||
#define K_PAUSE 255
|
||||
|
||||
//
|
||||
// mouse buttons generate virtual keys
|
||||
//
|
||||
#define K_MWHEELDOWN 239
|
||||
#define K_MWHEELUP 240
|
||||
#define K_MOUSE1 241
|
||||
#define K_MOUSE2 242
|
||||
#define K_MOUSE3 243
|
||||
#define K_MOUSE4 244
|
||||
#define K_MOUSE5 245
|
||||
#define K_MOUSE1 241
|
||||
#define K_MOUSE2 242
|
||||
#define K_MOUSE3 243
|
||||
#define K_MOUSE4 244
|
||||
#define K_MOUSE5 245
|
||||
|
||||
#define K_PAUSE 255
|
||||
#endif//KEYDEFS_H
|
||||
|
||||
@@ -184,7 +184,7 @@ qboolean SNDDMA_Init( void )
|
||||
return false;
|
||||
}
|
||||
|
||||
dma.buffer = Mem_Malloc( sndpool, samples * 2 ); //allocate pcm frame buffer
|
||||
dma.buffer = Z_Malloc( samples * 2 ); //allocate pcm frame buffer
|
||||
dma.samplepos = 0;
|
||||
dma.samples = samples;
|
||||
dma.format.width = 2;
|
||||
|
||||
@@ -55,7 +55,7 @@ char *Posix_Input( void );
|
||||
#endif
|
||||
|
||||
#if XASH_SDL
|
||||
void SDLash_Init( const char *basedir );
|
||||
void SDLash_Init( void );
|
||||
void SDLash_Shutdown( void );
|
||||
#endif
|
||||
|
||||
@@ -104,7 +104,7 @@ void Linux_SetTimer( float time );
|
||||
int Linux_GetProcessID( void );
|
||||
#endif
|
||||
|
||||
static inline void Platform_Init( qboolean con_showalways, const char *basedir )
|
||||
static inline void Platform_Init( qboolean con_showalways )
|
||||
{
|
||||
#if XASH_POSIX
|
||||
// daemonize as early as possible, because we need to close our file descriptors
|
||||
@@ -112,7 +112,7 @@ static inline void Platform_Init( qboolean con_showalways, const char *basedir )
|
||||
#endif
|
||||
|
||||
#if XASH_SDL
|
||||
SDLash_Init( basedir );
|
||||
SDLash_Init( );
|
||||
#endif
|
||||
|
||||
#if XASH_ANDROID
|
||||
|
||||
@@ -265,7 +265,7 @@ static void SDLash_KeyEvent( SDL_KeyboardEvent key )
|
||||
break;
|
||||
}
|
||||
case SDL_SCANCODE_PAUSE: keynum = K_PAUSE; break;
|
||||
case SDL_SCANCODE_SCROLLLOCK: keynum = K_SCROLLLOCK; break;
|
||||
case SDL_SCANCODE_SCROLLLOCK: keynum = K_SCROLLOCK; break;
|
||||
#if SDL_VERSION_ATLEAST( 2, 0, 0 )
|
||||
case SDL_SCANCODE_APPLICATION: keynum = K_WIN; break; // (compose key) ???
|
||||
// don't console spam on known functional buttons, not used in engine
|
||||
|
||||
@@ -175,7 +175,7 @@ qboolean SNDDMA_Init( void )
|
||||
if( !samplecount )
|
||||
samplecount = 0x8000;
|
||||
dma.samples = samplecount * obtained.channels;
|
||||
dma.buffer = Mem_Malloc( sndpool, dma.samples * 2 );
|
||||
dma.buffer = Z_Calloc( dma.samples * 2 );
|
||||
dma.samplepos = 0;
|
||||
|
||||
sdl_format = obtained.format;
|
||||
|
||||
@@ -20,9 +20,9 @@ GNU General Public License for more details.
|
||||
#if XASH_TIMER == TIMER_SDL
|
||||
double Platform_DoubleTime( void )
|
||||
{
|
||||
static Uint64 g_PerformanceFrequency;
|
||||
static Uint64 g_ClockStart;
|
||||
Uint64 CurrentTime;
|
||||
static longtime_t g_PerformanceFrequency;
|
||||
static longtime_t g_ClockStart;
|
||||
longtime_t CurrentTime;
|
||||
|
||||
if( !g_PerformanceFrequency )
|
||||
{
|
||||
@@ -78,19 +78,8 @@ static void SDLCALL SDLash_LogOutputFunction( void *userdata, int category, SDL_
|
||||
}
|
||||
}
|
||||
|
||||
void SDLash_Init( const char *basedir )
|
||||
void SDLash_Init( void )
|
||||
{
|
||||
#if XASH_APPLE
|
||||
char *path = SDL_GetBasePath();
|
||||
if( path != NULL )
|
||||
{
|
||||
char buf[MAX_VA_STRING];
|
||||
|
||||
Q_snprintf( buf, sizeof( buf ), "%s%s/extras.pk3", path, basedir );
|
||||
setenv( "XASH3D_EXTRAS_PAK1", buf, true );
|
||||
}
|
||||
#endif
|
||||
|
||||
SDL_LogSetOutputFunction( SDLash_LogOutputFunction, NULL );
|
||||
|
||||
if( host_developer.value >= 2 )
|
||||
|
||||
@@ -145,7 +145,7 @@ void Wcon_ShowConsole( qboolean show )
|
||||
|
||||
void Wcon_DisableInput( void )
|
||||
{
|
||||
if( host.type != HOST_DEDICATED || !s_wcd.hWnd )
|
||||
if( host.type != HOST_DEDICATED )
|
||||
return;
|
||||
|
||||
s_wcd.inputEnabled = false;
|
||||
@@ -469,9 +469,6 @@ print into window console
|
||||
*/
|
||||
void Wcon_WinPrint( const char *pMsg )
|
||||
{
|
||||
if( !s_wcd.hWnd )
|
||||
return;
|
||||
|
||||
int nLen;
|
||||
if( s_wcd.consoleTextLen )
|
||||
{
|
||||
@@ -518,18 +515,13 @@ void Wcon_CreateConsole( qboolean con_showalways )
|
||||
}
|
||||
|
||||
s_wcd.attached = ( AttachConsole( ATTACH_PARENT_PROCESS ) != 0 );
|
||||
if( s_wcd.attached )
|
||||
{
|
||||
if( s_wcd.attached ) {
|
||||
GetConsoleTitle( &s_wcd.previousTitle, sizeof( s_wcd.previousTitle ));
|
||||
s_wcd.previousCodePage = GetConsoleCP();
|
||||
s_wcd.previousOutputCodePage = GetConsoleOutputCP();
|
||||
}
|
||||
else
|
||||
{
|
||||
if( host.type != HOST_DEDICATED && host_developer.value == DEV_NONE )
|
||||
return; // don't initialize console in case of regular game startup, it's useless anyway
|
||||
else
|
||||
AllocConsole();
|
||||
else {
|
||||
AllocConsole();
|
||||
}
|
||||
|
||||
SetConsoleTitle( s_wcd.title );
|
||||
@@ -578,7 +570,7 @@ register console commands (dedicated only)
|
||||
*/
|
||||
void Wcon_InitConsoleCommands( void )
|
||||
{
|
||||
if( host.type != HOST_DEDICATED || !s_wcd.hWnd )
|
||||
if( host.type != HOST_DEDICATED )
|
||||
return;
|
||||
|
||||
Cmd_AddCommand( "clear", Wcon_Clear_f, "clear console history" );
|
||||
@@ -631,7 +623,7 @@ char *Wcon_Input( void )
|
||||
DWORD eventsCount;
|
||||
static INPUT_RECORD events[1024];
|
||||
|
||||
if( !s_wcd.inputEnabled || !s_wcd.hWnd )
|
||||
if( !s_wcd.inputEnabled )
|
||||
return NULL;
|
||||
|
||||
while( true )
|
||||
@@ -674,7 +666,7 @@ set server status string in console
|
||||
*/
|
||||
void Platform_SetStatus( const char *pStatus )
|
||||
{
|
||||
if( s_wcd.attached || !s_wcd.hWnd )
|
||||
if( s_wcd.attached )
|
||||
return;
|
||||
|
||||
Q_strncpy( s_wcd.statusLine, pStatus, sizeof( s_wcd.statusLine ) - 1 );
|
||||
|
||||
@@ -66,7 +66,6 @@ extern int SV_UPDATE_BACKUP;
|
||||
|
||||
#define MAX_PUSHED_ENTS 256
|
||||
#define MAX_VIEWENTS 128
|
||||
#define MAX_LOCALINFO_STRING 32768 // localinfo used on server and not sended to the clients
|
||||
|
||||
#define MAX_ENT_LEAFS( ext ) (( ext ) ? MAX_ENT_LEAFS_32 : MAX_ENT_LEAFS_16 )
|
||||
|
||||
|
||||
@@ -305,7 +305,6 @@ static void SV_ConnectClient( netadr_t from )
|
||||
int challenge;
|
||||
const char *s;
|
||||
int extensions;
|
||||
uint netchan_flags = 0;
|
||||
|
||||
if( Cmd_Argc() < 5 )
|
||||
{
|
||||
@@ -432,9 +431,7 @@ static void SV_ConnectClient( netadr_t from )
|
||||
newcl->listeners = -1;
|
||||
|
||||
// initailize netchan
|
||||
if( !Host_IsLocalClient( ))
|
||||
SetBits( netchan_flags, NETCHAN_USE_LZSS );
|
||||
Netchan_Setup( NS_SERVER, &newcl->netchan, from, qport, newcl, SV_GetFragmentSize, netchan_flags );
|
||||
Netchan_Setup( NS_SERVER, &newcl->netchan, from, qport, newcl, SV_GetFragmentSize, 0 );
|
||||
MSG_Init( &newcl->datagram, "Datagram", newcl->datagram_buf, sizeof( newcl->datagram_buf )); // datagram buf
|
||||
|
||||
Q_strncpy( newcl->hashedcdkey, Info_ValueForKey( protinfo, "uuid" ), 32 );
|
||||
@@ -453,6 +450,8 @@ static void SV_ConnectClient( netadr_t from )
|
||||
newcl->delta_sequence = -1;
|
||||
newcl->flags = 0;
|
||||
|
||||
|
||||
|
||||
// reset any remaining events
|
||||
memset( &newcl->events, 0, sizeof( newcl->events ));
|
||||
|
||||
@@ -2870,20 +2869,14 @@ static qboolean SV_EntCreate_f( sv_client_t *cl )
|
||||
// XashXT does not implement SV_CreateEntity, use saverestore export
|
||||
if( !ent && svgame.physFuncs.pfnCreateEntitiesInRestoreList )
|
||||
{
|
||||
ENTITYTABLE table = {
|
||||
.classname = classname,
|
||||
.id = -1,
|
||||
.size = 1,
|
||||
.flags = 1337,
|
||||
};
|
||||
|
||||
SAVERESTOREDATA data = {
|
||||
.tableCount = 1,
|
||||
.pTable = &table
|
||||
};
|
||||
|
||||
svgame.physFuncs.pfnCreateEntitiesInRestoreList( &data, table.flags, false );
|
||||
|
||||
SAVERESTOREDATA data = { 0 };
|
||||
ENTITYTABLE table = { 0 };
|
||||
data.tableCount = 1;
|
||||
data.pTable = &table;
|
||||
table.classname = classname;
|
||||
table.id = -1;
|
||||
table.size = 1;
|
||||
svgame.physFuncs.pfnCreateEntitiesInRestoreList( &data, 0, false );
|
||||
ent = table.pent;
|
||||
}
|
||||
|
||||
|
||||
@@ -2279,7 +2279,7 @@ int GAME_EXPORT SV_GetSaveComment( const char *savename, char *comment )
|
||||
|
||||
if( tag == 0x0065 )
|
||||
{
|
||||
Q_strncpy( comment, "<old version "XASH_ENGINE_NAME" unsupported>", MAX_STRING );
|
||||
Q_strncpy( comment, "<old version Xash3D unsupported>", MAX_STRING );
|
||||
FS_Close( f );
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -8,23 +8,6 @@ import os
|
||||
|
||||
top = '.'
|
||||
|
||||
FFMPEG_CHECK_FRAGMENT='''
|
||||
#include <libswresample/swresample.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libswscale/swscale.h>
|
||||
#include <libavutil/avutil.h>
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
swresample_version();
|
||||
avformat_version();
|
||||
avcodec_version();
|
||||
swscale_version();
|
||||
avutil_version();
|
||||
return 0;
|
||||
}
|
||||
'''
|
||||
|
||||
def options(opt):
|
||||
grp = opt.add_option_group('Engine options')
|
||||
|
||||
@@ -52,9 +35,6 @@ def options(opt):
|
||||
grp.add_option('--enable-ffmpeg', action = 'store_true', dest = 'FFMPEG', default = False,
|
||||
help = '') # hidden option, does nothing
|
||||
|
||||
grp.add_option('--enable-ffmpeg', action = 'store_true', dest = 'FFMPEG', default = False,
|
||||
help = 'enable ffmpeg based movie playback')
|
||||
|
||||
opt.load('sdl2')
|
||||
|
||||
def configure(conf):
|
||||
@@ -145,20 +125,6 @@ def configure(conf):
|
||||
|
||||
conf.define('ENGINE_DLL', 1)
|
||||
|
||||
if conf.options.FFMPEG:
|
||||
# add ffmpeg libraries into single uselib package
|
||||
conf.check_cfg(package='libswresample', uselib_store='SWRESAMPLE', args='--cflags --libs')
|
||||
conf.check_cfg(package='libavformat', uselib_store='AVFORMAT', args='--cflags --libs')
|
||||
conf.check_cfg(package='libavcodec', uselib_store='AVCODEC', args='--cflags --libs')
|
||||
conf.check_cfg(package='libswscale', uselib_store='SWSCALE', args='--cflags --libs')
|
||||
conf.check_cfg(package='libavutil', uselib_store='AVUTIL', args='--cflags --libs')
|
||||
|
||||
# validate ffmpeg libs installation
|
||||
conf.check_cc(fragment=FFMPEG_CHECK_FRAGMENT, use='SWRESAMPLE AVCODEC AVFORMAT AVUTIL SWSCALE', msg='Checking for ffmpeg sanity')
|
||||
|
||||
conf.env.FFMPEG = True
|
||||
conf.define('HAVE_FFMPEG', True)
|
||||
|
||||
conf.define_cond('XASH_ENGINE_TESTS', conf.env.ENGINE_TESTS)
|
||||
conf.define_cond('XASH_STATIC_LIBS', conf.env.STATIC_LINKING)
|
||||
conf.define_cond('XASH_CUSTOM_SWAP', conf.options.CUSTOM_SWAP)
|
||||
@@ -219,13 +185,6 @@ def build(bld):
|
||||
libs.append('SDL3' if bld.env.HAVE_SDL3 else 'SDL2')
|
||||
source += bld.path.ant_glob(['platform/sdl/*.c'])
|
||||
|
||||
if bld.get_define('HAVE_FFMPEG'):
|
||||
libs.append('SWRESAMPLE')
|
||||
libs.append('AVCODEC')
|
||||
libs.append('AVFORMAT')
|
||||
libs.append('AVUTIL')
|
||||
libs.append('SWSCALE')
|
||||
|
||||
if bld.env.MAGX:
|
||||
libs.append('MAGX')
|
||||
is_cxx_link = True
|
||||
|
||||
@@ -242,7 +242,7 @@ static byte *FS_LoadAndroidAssetsFile( searchpath_t *search, const char *path, i
|
||||
|
||||
if( filesize ) *filesize = 0;
|
||||
|
||||
asset = AAssetManager_open( search->assets->asset_manager, path, AASSET_MODE_BUFFER );
|
||||
asset = AAssetManager_open( search->assets->asset_manager, path, AASSET_MODE_RANDOM );
|
||||
if( !asset )
|
||||
return NULL;
|
||||
|
||||
|
||||
@@ -49,7 +49,6 @@ GNU General Public License for more details.
|
||||
#include "common/protocol.h"
|
||||
|
||||
#define FILE_COPY_SIZE (1024 * 1024)
|
||||
#define SAVE_AGED_COUNT 2 // the default count of quick and auto saves
|
||||
|
||||
fs_globals_t FI;
|
||||
qboolean fs_ext_path = false; // attempt to read\write from ./ or ../ pathes
|
||||
@@ -448,7 +447,6 @@ FS_ClearSearchPath
|
||||
void FS_ClearSearchPath( void )
|
||||
{
|
||||
searchpath_t *cur, **prev;
|
||||
int i;
|
||||
|
||||
prev = &fs_searchpaths;
|
||||
|
||||
@@ -470,12 +468,6 @@ void FS_ClearSearchPath( void )
|
||||
cur->pfnClose( cur );
|
||||
Mem_Free( cur );
|
||||
}
|
||||
|
||||
for( i = 0; i < FI.numgames; i++ )
|
||||
{
|
||||
if( FI.games[i] )
|
||||
FI.games[i]->added = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -636,11 +628,13 @@ static qboolean FS_WriteGameInfo( const char *filepath, gameinfo_t *GameInfo )
|
||||
if( GameInfo->noskills )
|
||||
FS_Printf( f, "noskills\t\t\"%i\"\n", GameInfo->noskills );
|
||||
|
||||
#define SAVE_AGED_COUNT 2 // the default count of quick and auto saves
|
||||
if( GameInfo->quicksave_aged_count != SAVE_AGED_COUNT )
|
||||
FS_Printf( f, "quicksave_aged_count\t\t%d\n", GameInfo->quicksave_aged_count );
|
||||
|
||||
if( GameInfo->autosave_aged_count != SAVE_AGED_COUNT )
|
||||
FS_Printf( f, "autosave_aged_count\t\t%d\n", GameInfo->autosave_aged_count );
|
||||
#undef SAVE_AGED_COUNT
|
||||
|
||||
// HL25 compatibility
|
||||
if( GameInfo->animated_title )
|
||||
@@ -706,9 +700,6 @@ static void FS_InitGameInfo( gameinfo_t *GameInfo, const char *gamedir, qboolean
|
||||
GameInfo->max_beams = 128;
|
||||
GameInfo->max_particles = 4096;
|
||||
GameInfo->version = 1.0f;
|
||||
|
||||
GameInfo->quicksave_aged_count = SAVE_AGED_COUNT;
|
||||
GameInfo->autosave_aged_count = SAVE_AGED_COUNT;
|
||||
}
|
||||
|
||||
static void FS_ParseGenericGameInfo( gameinfo_t *GameInfo, const char *buf, const qboolean isGameInfo )
|
||||
@@ -1129,7 +1120,7 @@ static qboolean FS_ParseGameInfo( const char *gamedir, gameinfo_t *GameInfo, qbo
|
||||
if( rodir )
|
||||
Q_snprintf( gamedir_path, sizeof( gamedir_path ), "%s/%s", fs_rodir, gamedir );
|
||||
else
|
||||
Q_snprintf( gamedir_path, sizeof( gamedir_path ), "%s", gamedir );
|
||||
Q_snprintf( gamedir_path, sizeof( gamedir_path ), "%s/%s", fs_rootdir, gamedir );
|
||||
|
||||
if( !FS_CheckForXashGameDir( gamedir_path ))
|
||||
{
|
||||
@@ -1199,11 +1190,11 @@ void FS_AddGameHierarchy( const char *dir, uint flags )
|
||||
qboolean isGameDir = flags & FS_GAMEDIR_PATH;
|
||||
char buf[MAX_VA_STRING];
|
||||
|
||||
GI->added = true;
|
||||
|
||||
if( !COM_CheckString( dir ))
|
||||
return;
|
||||
|
||||
Con_Printf( "%s( %s )\n", __func__, dir );
|
||||
|
||||
// add the common game directory
|
||||
|
||||
// recursive gamedirs
|
||||
@@ -1214,21 +1205,12 @@ void FS_AddGameHierarchy( const char *dir, uint flags )
|
||||
{
|
||||
dir = FI.games[i]->gamefolder; // fixup directory case
|
||||
|
||||
if( FI.games[i]->added ) // already added, refusing
|
||||
break;
|
||||
|
||||
// don't add our game directory as base dir to prevent cyclic dependency
|
||||
if( Q_stricmp( FI.games[i]->basedir, GI->gamefolder ))
|
||||
break;
|
||||
|
||||
// don't add directory which basedir is equal to this gamefolder to prevent
|
||||
// endless loop
|
||||
if( Q_stricmp( FI.games[i]->basedir, FI.games[i]->gamefolder ))
|
||||
break;
|
||||
|
||||
Con_Reportf( "%s: adding recursive basedir %s\n", __func__, FI.games[i]->basedir );
|
||||
FI.games[i]->added = true;
|
||||
FS_AddGameHierarchy( FI.games[i]->basedir, flags & (~FS_GAMEDIR_PATH));
|
||||
if( !FI.games[i]->added && Q_stricmp( FI.games[i]->gamefolder, FI.games[i]->basedir ))
|
||||
{
|
||||
FI.games[i]->added = true;
|
||||
FS_AddGameHierarchy( FI.games[i]->basedir, flags & (~FS_GAMEDIR_PATH) );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1285,8 +1267,6 @@ void FS_Rescan( void )
|
||||
FS_AddGameHierarchy( GI->basedir, 0 );
|
||||
if( Q_stricmp( GI->basedir, GI->falldir ) && Q_stricmp( GI->gamefolder, GI->falldir ))
|
||||
FS_AddGameHierarchy( GI->falldir, 0 );
|
||||
|
||||
GI->added = true;
|
||||
FS_AddGameHierarchy( GI->gamefolder, FS_GAMEDIR_PATH );
|
||||
}
|
||||
|
||||
@@ -2242,12 +2222,6 @@ int FS_Close( file_t *file )
|
||||
return EOF;
|
||||
}
|
||||
|
||||
if( file->ztk )
|
||||
{
|
||||
inflateEnd( &file->ztk->zstream );
|
||||
Mem_Free( file->ztk );
|
||||
}
|
||||
|
||||
Mem_Free( file );
|
||||
return 0;
|
||||
}
|
||||
@@ -2353,93 +2327,7 @@ fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize )
|
||||
|
||||
// NOTE: at this point, the read buffer is always empty
|
||||
|
||||
FS_EnsureOpenFile( file ); // FIXME: broken XASH_REDUCE_FD in case of compressed files!
|
||||
|
||||
if( FBitSet( file->flags, FILE_DEFLATED ))
|
||||
{
|
||||
// If the file is compressed, it's more complicated...
|
||||
// We cycle through a few operations until we have read enough data
|
||||
while( buffersize > 0 )
|
||||
{
|
||||
ztoolkit_t *ztk = file->ztk;
|
||||
int error;
|
||||
|
||||
// NOTE: at this point, the read buffer is always empty
|
||||
|
||||
// If "input" is also empty, we need to refill it
|
||||
if( ztk->in_ind == ztk->in_len )
|
||||
{
|
||||
// If we are at the end of the file
|
||||
if( file->position == file->real_length )
|
||||
return done;
|
||||
|
||||
count = (fs_offset_t)( ztk->comp_length - ztk->in_position );
|
||||
if( count > (fs_offset_t)sizeof( ztk->input ))
|
||||
count = (fs_offset_t)sizeof( ztk->input );
|
||||
lseek( file->handle, file->offset + (fs_offset_t)ztk->in_position, SEEK_SET );
|
||||
if( read( file->handle, ztk->input, count ) != count )
|
||||
{
|
||||
Con_Printf( "%s: unexpected end of file\n", __func__ );
|
||||
break;
|
||||
}
|
||||
|
||||
ztk->in_ind = 0;
|
||||
ztk->in_len = count;
|
||||
ztk->in_position += count;
|
||||
}
|
||||
|
||||
ztk->zstream.next_in = &ztk->input[ztk->in_ind];
|
||||
ztk->zstream.avail_in = (unsigned int)( ztk->in_len - ztk->in_ind );
|
||||
|
||||
// Now that we are sure we have compressed data available, we need to determine
|
||||
// if it's better to inflate it in "file->buff" or directly in "buffer"
|
||||
|
||||
// Inflate the data in "file->buff"
|
||||
if( buffersize < sizeof( file->buff ) / 2 )
|
||||
{
|
||||
ztk->zstream.next_out = file->buff;
|
||||
ztk->zstream.avail_out = sizeof( file->buff );
|
||||
}
|
||||
else
|
||||
{
|
||||
ztk->zstream.next_out = &((unsigned char*)buffer)[done];
|
||||
ztk->zstream.avail_out = (unsigned int)buffersize;
|
||||
}
|
||||
|
||||
error = inflate( &ztk->zstream, Z_SYNC_FLUSH );
|
||||
if( error != Z_OK && error != Z_STREAM_END )
|
||||
{
|
||||
Con_Printf( "%s: Can't inflate file (%d)\n", __func__, error );
|
||||
break;
|
||||
}
|
||||
ztk->in_ind = ztk->in_len - ztk->zstream.avail_in;
|
||||
|
||||
if( buffersize < sizeof( file->buff ) / 2 )
|
||||
{
|
||||
file->buff_len = (fs_offset_t)sizeof( file->buff ) - ztk->zstream.avail_out;
|
||||
file->position += file->buff_len;
|
||||
|
||||
// Copy the requested data in "buffer" (as much as we can)
|
||||
count = (fs_offset_t)buffersize > file->buff_len ? file->buff_len : (fs_offset_t)buffersize;
|
||||
memcpy( &((unsigned char*)buffer)[done], file->buff, count );
|
||||
file->buff_ind = count;
|
||||
}
|
||||
else
|
||||
{
|
||||
count = (fs_offset_t)( buffersize - ztk->zstream.avail_out );
|
||||
file->position += count;
|
||||
|
||||
// Purge cached data
|
||||
FS_Purge( file );
|
||||
}
|
||||
|
||||
done += count;
|
||||
buffersize -= count;
|
||||
}
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
FS_EnsureOpenFile( file );
|
||||
// we must take care to not read after the end of the file
|
||||
count = file->real_length - file->position;
|
||||
|
||||
@@ -2655,59 +2543,11 @@ int FS_Seek( file_t *file, fs_offset_t offset, int whence )
|
||||
// Purge cached data
|
||||
FS_Purge( file );
|
||||
|
||||
if( FBitSet( file->flags, FILE_DEFLATED ))
|
||||
{
|
||||
// Seeking in compressed files is more a hack than anything else,
|
||||
// but we need to support it, so here we go.
|
||||
ztoolkit_t *ztk = file->ztk;
|
||||
unsigned char *buffer;
|
||||
fs_offset_t buffersize;
|
||||
|
||||
// If we have to go back in the file, we need to restart from the beginning
|
||||
if( offset <= file->position )
|
||||
{
|
||||
ztk->in_ind = 0;
|
||||
ztk->in_len = 0;
|
||||
ztk->in_position = 0;
|
||||
file->position = 0;
|
||||
if( lseek( file->handle, file->offset, SEEK_SET ) == -1 )
|
||||
Con_Printf("IMPOSSIBLE: couldn't seek in already opened pk3 file.\n");
|
||||
|
||||
// Reset the Zlib stream
|
||||
ztk->zstream.next_in = ztk->input;
|
||||
ztk->zstream.avail_in = 0;
|
||||
inflateReset( &ztk->zstream );
|
||||
}
|
||||
|
||||
// We need a big buffer to force inflating into it directly
|
||||
buffersize = 2 * sizeof( file->buff );
|
||||
buffer = (unsigned char *)Mem_Malloc( fs_mempool, buffersize );
|
||||
|
||||
// Skip all data until we reach the requested offset
|
||||
while( offset > ( file->position - file->buff_len + file->buff_ind ))
|
||||
{
|
||||
fs_offset_t diff = offset - ( file->position - file->buff_len + file->buff_ind );
|
||||
fs_offset_t count;
|
||||
|
||||
count = ( diff > buffersize ) ? buffersize : diff;
|
||||
if( FS_Read( file, buffer, count ) != count )
|
||||
{
|
||||
Mem_Free( buffer );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
Mem_Free( buffer );
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( lseek( file->handle, file->offset + offset, SEEK_SET ) == -1 )
|
||||
return -1;
|
||||
file->position = offset;
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -143,8 +143,6 @@ typedef struct fs_globals_t
|
||||
int numgames;
|
||||
} fs_globals_t;
|
||||
|
||||
typedef struct file_s file_t;
|
||||
|
||||
typedef struct fs_api_t
|
||||
{
|
||||
qboolean (*InitStdio)( qboolean unused_set_to_true, const char *rootdir, const char *basedir, const char *gamedir, const char *rodir );
|
||||
|
||||
@@ -22,7 +22,6 @@ GNU General Public License for more details.
|
||||
#include <stdlib.h>
|
||||
#include "xash3d_types.h"
|
||||
#include "filesystem.h"
|
||||
#include "miniz.h"
|
||||
|
||||
#if XASH_ANDROID
|
||||
#include <android/asset_manager.h>
|
||||
@@ -41,16 +40,6 @@ typedef struct wfile_s wfile_t;
|
||||
typedef struct android_assets_s android_assets_t;
|
||||
|
||||
#define FILE_BUFF_SIZE (2048)
|
||||
#define FILE_DEFLATED BIT( 0 )
|
||||
|
||||
typedef struct ztoolkit_s
|
||||
{
|
||||
z_stream zstream;
|
||||
size_t comp_length;
|
||||
size_t in_ind, in_len;
|
||||
size_t in_position;
|
||||
byte input[FILE_BUFF_SIZE];
|
||||
} ztoolkit_t;
|
||||
|
||||
struct file_s
|
||||
{
|
||||
@@ -61,9 +50,7 @@ struct file_s
|
||||
fs_offset_t real_length; // uncompressed file size (for files opened in "read" mode)
|
||||
fs_offset_t position; // current position in the file
|
||||
fs_offset_t offset; // offset into the package (0 if external file)
|
||||
uint32_t flags;
|
||||
ztoolkit_t *ztk; // if not NULL, all read functions must go through decompression
|
||||
|
||||
|
||||
// contents buffer
|
||||
fs_offset_t buff_ind; // buffer current index
|
||||
fs_offset_t buff_len; // buffer current length
|
||||
|
||||
@@ -92,19 +92,20 @@ struct wfile_s
|
||||
|
||||
typedef struct wadtype_s
|
||||
{
|
||||
char ext[4];
|
||||
signed char type;
|
||||
const char *ext;
|
||||
signed char type;
|
||||
} wadtype_t;
|
||||
|
||||
// associate extension with wad type
|
||||
static const wadtype_t wad_types[] =
|
||||
static const wadtype_t wad_types[7] =
|
||||
{
|
||||
{ "pal", TYP_PALETTE }, // palette
|
||||
{ "dds", TYP_DDSTEX }, // DDS image
|
||||
{ "lmp", TYP_GFXPIC }, // quake1, hl pic
|
||||
{ "fnt", TYP_QFONT }, // hl qfonts
|
||||
{ "mip", TYP_MIPTEX }, // hl/q1 mip
|
||||
{ "txt", TYP_SCRIPT }, // scripts
|
||||
{ "pal", TYP_PALETTE }, // palette
|
||||
{ "dds", TYP_DDSTEX }, // DDS image
|
||||
{ "lmp", TYP_GFXPIC }, // quake1, hl pic
|
||||
{ "fnt", TYP_QFONT }, // hl qfonts
|
||||
{ "mip", TYP_MIPTEX }, // hl/q1 mip
|
||||
{ "txt", TYP_SCRIPT }, // scripts
|
||||
{ NULL, TYP_NONE }
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -116,19 +117,18 @@ Extracts file type from extension
|
||||
*/
|
||||
static signed char W_TypeFromExt( const char *lumpname )
|
||||
{
|
||||
const char *ext = COM_FileExtension( lumpname );
|
||||
int i;
|
||||
const char *ext = COM_FileExtension( lumpname );
|
||||
const wadtype_t *type;
|
||||
|
||||
// we not known about filetype, so match only by filename
|
||||
if( !Q_strcmp( ext, "*" ) || !COM_CheckStringEmpty( ext ))
|
||||
return TYP_ANY;
|
||||
|
||||
for( i = 0; i < sizeof( wad_types ) / sizeof( wad_types[0] ); i++ )
|
||||
for( type = wad_types; type->ext; type++ )
|
||||
{
|
||||
if( !Q_stricmp( ext, wad_types[i].ext ))
|
||||
return wad_types[i].type;
|
||||
if( !Q_stricmp( ext, type->ext ))
|
||||
return type->type;
|
||||
}
|
||||
|
||||
return TYP_NONE;
|
||||
}
|
||||
|
||||
@@ -141,18 +141,17 @@ Convert type to extension
|
||||
*/
|
||||
static const char *W_ExtFromType( signed char lumptype )
|
||||
{
|
||||
int i;
|
||||
const wadtype_t *type;
|
||||
|
||||
// we not known aboyt filetype, so match only by filename
|
||||
if( lumptype == TYP_NONE || lumptype == TYP_ANY )
|
||||
return "";
|
||||
|
||||
for( i = 0; i < sizeof( wad_types ) / sizeof( wad_types[0] ); i++ )
|
||||
for( type = wad_types; type->ext; type++ )
|
||||
{
|
||||
if( lumptype == wad_types[i].type )
|
||||
return wad_types[i].ext;
|
||||
if( lumptype == type->type )
|
||||
return type->ext;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ GNU General Public License for more details.
|
||||
#include "filesystem_internal.h"
|
||||
#include "crtlib.h"
|
||||
#include "common/com_strings.h"
|
||||
#include "miniz.h"
|
||||
|
||||
#define ZIP_HEADER_LF (('K'<<8)+('P')+(0x03<<16)+(0x04<<24))
|
||||
#define ZIP_HEADER_SPANNED ((0x08<<24)+(0x07<<16)+('K'<<8)+'P')
|
||||
@@ -388,43 +389,15 @@ Open a packed file using its package file descriptor
|
||||
static file_t *FS_OpenFile_ZIP( searchpath_t *search, const char *filename, const char *mode, int pack_ind )
|
||||
{
|
||||
zipfile_t *pfile = &search->zip->files[pack_ind];
|
||||
file_t *f = FS_OpenHandle( search, search->zip->handle->handle, pfile->offset, pfile->size );
|
||||
|
||||
if( !f )
|
||||
return NULL;
|
||||
|
||||
if( pfile->flags == ZIP_COMPRESSION_DEFLATED )
|
||||
// compressed files handled in Zip_LoadFile
|
||||
if( pfile->flags != ZIP_COMPRESSION_NO_COMPRESSION )
|
||||
{
|
||||
ztoolkit_t *ztk;
|
||||
|
||||
SetBits( f->flags, FILE_DEFLATED );
|
||||
|
||||
ztk = Mem_Calloc( fs_mempool, sizeof( *ztk ));
|
||||
ztk->comp_length = pfile->compressed_size;
|
||||
ztk->zstream.next_in = ztk->input;
|
||||
ztk->zstream.avail_in = 0;
|
||||
|
||||
if( inflateInit2( &ztk->zstream, -MAX_WBITS ) != Z_OK )
|
||||
{
|
||||
Con_Printf( "%s: inflate init error (file: %s)\n", __func__, filename );
|
||||
FS_Close( f );
|
||||
Mem_Free( ztk );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ztk->zstream.next_out = f->buff;
|
||||
ztk->zstream.avail_out = sizeof( f->buff );
|
||||
|
||||
f->ztk = ztk;
|
||||
}
|
||||
else if( pfile->flags != ZIP_COMPRESSION_NO_COMPRESSION )
|
||||
{
|
||||
Con_Reportf( S_ERROR "%s: %s: file compressed with unknown algorithm.\n", __func__, filename );
|
||||
FS_Close( f );
|
||||
Con_Printf( S_ERROR "%s: can't open compressed file %s\n", __func__, pfile->name );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return f;
|
||||
return FS_OpenHandle( search, search->zip->handle->handle, pfile->offset, pfile->size );
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -33,6 +33,26 @@ void Q_strnlwr( const char *in, char *out, size_t size_out )
|
||||
out[i] = Q_tolower( out[i] );
|
||||
}
|
||||
|
||||
size_t Q_colorstr( const char *string )
|
||||
{
|
||||
const char *p = string;
|
||||
size_t len = 0;
|
||||
|
||||
if( !string )
|
||||
return len;
|
||||
|
||||
while(( p = Q_strchr( p, '^' )))
|
||||
{
|
||||
if( IsColorString( p ))
|
||||
{
|
||||
len += 2;
|
||||
p += 2;
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int Q_atoi_hex( int sign, const char *str )
|
||||
{
|
||||
int c, val = 0;
|
||||
|
||||
@@ -70,6 +70,7 @@ extern const char *g_buildbranch;
|
||||
//
|
||||
void Q_strnlwr( const char *in, char *out, size_t size_out );
|
||||
#define Q_strlen( str ) (( str ) ? strlen(( str )) : 0 )
|
||||
size_t Q_colorstr( const char *string );
|
||||
int Q_atoi_hex( int sign, const char *str );
|
||||
int Q_atoi( const char *str );
|
||||
float Q_atof( const char *str );
|
||||
@@ -107,12 +108,6 @@ int matchpattern_with_separator( const char *in, const char *pattern, qboolean c
|
||||
//
|
||||
// dllhelpers.c
|
||||
//
|
||||
typedef struct dllfunc_s
|
||||
{
|
||||
const char *name;
|
||||
void **func;
|
||||
} dllfunc_t;
|
||||
|
||||
void ClearExports( const dllfunc_t *funcs, size_t num_funcs );
|
||||
qboolean ValidateExports( const dllfunc_t *funcs, size_t num_funcs );
|
||||
|
||||
|
||||
@@ -46,6 +46,17 @@ static int Test_Strnlwr( void )
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Test_Colorstr( void )
|
||||
{
|
||||
if( Q_colorstr( "^1color^2string" ) != 4 )
|
||||
return 1;
|
||||
|
||||
if( Q_colorstr( "colorlessstring" ) != 0 )
|
||||
return 2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Test_FixSlashes( void )
|
||||
{
|
||||
string s = "path\\with\\back\\slashes";
|
||||
@@ -82,6 +93,11 @@ int main( void )
|
||||
if( ret > 0 )
|
||||
return ret + 16;
|
||||
|
||||
ret = Test_Colorstr();
|
||||
|
||||
if( ret > 0 )
|
||||
return ret + 32;
|
||||
|
||||
ret = Test_FixSlashes();
|
||||
|
||||
if( ret > 0 )
|
||||
|
||||
@@ -185,7 +185,7 @@ int BoxOnPlaneSide( const vec3_t emins, const vec3_t emaxs, const mplane_t *p );
|
||||
//
|
||||
static inline void Matrix3x4_LoadIdentity( matrix3x4 m )
|
||||
{
|
||||
memset( m, 0, sizeof( matrix3x4 ));
|
||||
memset( m, 0, sizeof( *m ));
|
||||
m[0][0] = m[1][1] = m[2][2] = 1.0f;
|
||||
}
|
||||
#define Matrix3x4_Copy( out, in ) memcpy( out, in, sizeof( matrix3x4 ))
|
||||
@@ -201,7 +201,7 @@ void Matrix3x4_AnglesFromMatrix( const matrix3x4 in, vec3_t out );
|
||||
|
||||
static inline void Matrix4x4_LoadIdentity( matrix4x4 m )
|
||||
{
|
||||
memset( m, 0, sizeof( matrix4x4 ));
|
||||
memset( m, 0, sizeof( *m ));
|
||||
m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1.0f;
|
||||
}
|
||||
#define Matrix4x4_Copy( out, in ) memcpy( out, in, sizeof( matrix4x4 ))
|
||||
|
||||
@@ -88,13 +88,11 @@ static void Mod_BrushUnloadTextures( model_t *mod )
|
||||
for( i = 0; i < mod->numtextures; i++ )
|
||||
{
|
||||
texture_t *tx = mod->textures[i];
|
||||
if( !tx )
|
||||
if( !tx || tx->gl_texturenum == tr.defaultTexture )
|
||||
continue; // free slot
|
||||
|
||||
if( tx->gl_texturenum != tr.defaultTexture )
|
||||
GL_FreeTexture( tx->gl_texturenum ); // main texture
|
||||
GL_FreeTexture( tx->fb_texturenum ); // luma texture
|
||||
GL_FreeTexture( tx->dt_texturenum ); // detail texture
|
||||
GL_FreeTexture( tx->gl_texturenum ); // main texture
|
||||
GL_FreeTexture( tx->fb_texturenum ); // luma texture
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,35 +122,33 @@ static void Mod_UnloadTextures( model_t *mod )
|
||||
|
||||
static qboolean Mod_ProcessRenderData( model_t *mod, qboolean create, const byte *buf )
|
||||
{
|
||||
qboolean loaded = false;
|
||||
qboolean loaded = true;
|
||||
|
||||
if( create )
|
||||
{
|
||||
switch( mod->type )
|
||||
{
|
||||
case mod_studio:
|
||||
// Mod_LoadStudioModel( mod, buf, loaded );
|
||||
break;
|
||||
case mod_sprite:
|
||||
Mod_LoadSpriteModel( mod, buf, &loaded, mod->numtexinfo );
|
||||
break;
|
||||
case mod_alias:
|
||||
Mod_LoadAliasModel( mod, buf, &loaded );
|
||||
break;
|
||||
case mod_brush:
|
||||
// Mod_LoadBrushModel( mod, buf, loaded );
|
||||
break;
|
||||
default: gEngfuncs.Host_Error( "%s: unsupported type %d\n", __func__, mod->type );
|
||||
}
|
||||
}
|
||||
|
||||
if( loaded && gEngfuncs.drawFuncs->Mod_ProcessUserData )
|
||||
gEngfuncs.drawFuncs->Mod_ProcessUserData( mod, create, buf );
|
||||
|
||||
if( !create )
|
||||
{
|
||||
if( gEngfuncs.drawFuncs->Mod_ProcessUserData )
|
||||
gEngfuncs.drawFuncs->Mod_ProcessUserData( mod, false, buf );
|
||||
Mod_UnloadTextures( mod );
|
||||
return true;
|
||||
}
|
||||
|
||||
switch( mod->type )
|
||||
{
|
||||
case mod_studio:
|
||||
case mod_brush:
|
||||
loaded = true;
|
||||
break;
|
||||
case mod_sprite:
|
||||
Mod_LoadSpriteModel( mod, buf, &loaded, mod->numtexinfo );
|
||||
break;
|
||||
case mod_alias:
|
||||
Mod_LoadAliasModel( mod, buf, &loaded );
|
||||
break;
|
||||
default:
|
||||
gEngfuncs.Host_Error( "%s: unsupported type %d\n", __func__, mod->type );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( gEngfuncs.drawFuncs->Mod_ProcessUserData )
|
||||
gEngfuncs.drawFuncs->Mod_ProcessUserData( mod, true, buf );
|
||||
|
||||
return loaded;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ GNU General Public License for more details.
|
||||
#include "gl_local.h"
|
||||
#include "xash3d_mathlib.h"
|
||||
|
||||
static void GL_FrustumSetPlane( gl_frustum_t *out, int side, const vec3_t vecNormal, float flDist )
|
||||
void GL_FrustumSetPlane( gl_frustum_t *out, int side, const vec3_t vecNormal, float flDist )
|
||||
{
|
||||
Assert( side >= 0 && side < FRUSTUM_PLANES );
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ typedef struct gl_frustum_s
|
||||
|
||||
void GL_FrustumInitProj( gl_frustum_t *out, float flZNear, float flZFar, float flFovX, float flFovY );
|
||||
void GL_FrustumInitOrtho( gl_frustum_t *out, float xLeft, float xRight, float yTop, float yBottom, float flZNear, float flZFar );
|
||||
void GL_FrustumSetPlane( gl_frustum_t *out, int side, const vec3_t vecNormal, float flDist );
|
||||
|
||||
// cull methods
|
||||
qboolean GL_FrustumCullBox( gl_frustum_t *out, const vec3_t mins, const vec3_t maxs, int userClipFlags );
|
||||
|
||||
@@ -2338,6 +2338,7 @@ void R_InitImages( void )
|
||||
// validate cvars
|
||||
R_SetTextureParameters();
|
||||
GL_CreateInternalTextures();
|
||||
R_InitRipples();
|
||||
|
||||
gEngfuncs.Cmd_AddCommand( "texturelist", R_TextureList_f, "display loaded textures list" );
|
||||
}
|
||||
|
||||
@@ -130,6 +130,7 @@ typedef struct gltexture_s
|
||||
float xscale;
|
||||
float yscale;
|
||||
|
||||
int servercount;
|
||||
uint hashValue;
|
||||
struct gltexture_s *nextHash;
|
||||
} gl_texture_t;
|
||||
@@ -437,6 +438,8 @@ void R_DrawWaterSurfaces( void );
|
||||
void R_DrawBrushModel( cl_entity_t *e );
|
||||
void GL_SubdivideSurface( model_t *mod, msurface_t *fa );
|
||||
void GL_BuildPolygonFromSurface( model_t *mod, msurface_t *fa );
|
||||
void DrawGLPoly( glpoly2_t *p, float xScale, float yScale );
|
||||
texture_t *R_TextureAnimation( msurface_t *s );
|
||||
void GL_SetupFogColorForSurfaces( void );
|
||||
void R_DrawAlphaTextureChains( void );
|
||||
void GL_RebuildLightmaps( void );
|
||||
@@ -500,9 +503,10 @@ void R_DrawSkyBox( void );
|
||||
void R_DrawClouds( void );
|
||||
void R_UnloadSkybox( void );
|
||||
void EmitWaterPolys( msurface_t *warp, qboolean reverse, qboolean ripples );
|
||||
void R_InitRipples( void );
|
||||
void R_ResetRipples( void );
|
||||
void R_AnimateRipples( void );
|
||||
qboolean R_UploadRipples( texture_t *image );
|
||||
qboolean R_UploadRipples( const texture_t *image );
|
||||
|
||||
//#include "vid_common.h"
|
||||
|
||||
|
||||
@@ -478,7 +478,7 @@ R_TextureAnimation
|
||||
Returns the proper texture for a given time and surface
|
||||
===============
|
||||
*/
|
||||
static texture_t *R_TextureAnimation( msurface_t *s )
|
||||
texture_t *R_TextureAnimation( msurface_t *s )
|
||||
{
|
||||
texture_t *base = s->texinfo->texture;
|
||||
int count, reletive;
|
||||
@@ -812,7 +812,7 @@ static void R_BuildLightMap( const msurface_t *surf, byte *dest, int stride, qbo
|
||||
DrawGLPoly
|
||||
================
|
||||
*/
|
||||
static void DrawGLPoly( glpoly2_t *p, float xScale, float yScale )
|
||||
void DrawGLPoly( glpoly2_t *p, float xScale, float yScale )
|
||||
{
|
||||
float *v;
|
||||
float sOffset, sy;
|
||||
|
||||
@@ -152,11 +152,11 @@ load sprite model
|
||||
*/
|
||||
void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, uint texFlags )
|
||||
{
|
||||
const dsprite_t *pin;
|
||||
const short *numi = NULL;
|
||||
const byte *pframetype;
|
||||
msprite_t *psprite;
|
||||
int i;
|
||||
const dsprite_t *pin;
|
||||
const short *numi = NULL;
|
||||
const byte *pframetype;
|
||||
msprite_t *psprite;
|
||||
int i;
|
||||
|
||||
pin = buffer;
|
||||
psprite = mod->cache.data;
|
||||
@@ -164,7 +164,7 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
|
||||
if( pin->version == SPRITE_VERSION_Q1 || pin->version == SPRITE_VERSION_32 )
|
||||
numi = NULL;
|
||||
else if( pin->version == SPRITE_VERSION_HL )
|
||||
numi = (const short *)((const byte *)buffer + sizeof( dsprite_hl_t ));
|
||||
numi = (const short *)((const byte*)buffer + sizeof( dsprite_hl_t ));
|
||||
|
||||
r_texFlags = texFlags;
|
||||
sprite_version = pin->version;
|
||||
@@ -179,32 +179,31 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
|
||||
pframetype = ((const byte*)buffer + sizeof( dsprite_q1_t )); // pinq1 + 1
|
||||
gEngfuncs.FS_FreeImage( pal ); // palette installed, no reason to keep this data
|
||||
}
|
||||
else if( *numi <= 256 )
|
||||
else if( *numi == 256 )
|
||||
{
|
||||
const byte *src = (const byte *)(numi+1);
|
||||
rgbdata_t *pal;
|
||||
size_t pal_bytes = *numi * 3;
|
||||
|
||||
// install palette
|
||||
switch( psprite->texFormat )
|
||||
{
|
||||
case SPR_INDEXALPHA:
|
||||
pal = gEngfuncs.FS_LoadImage( "#gradient.pal", src, pal_bytes );
|
||||
pal = gEngfuncs.FS_LoadImage( "#gradient.pal", src, 768 );
|
||||
break;
|
||||
case SPR_ALPHTEST:
|
||||
pal = gEngfuncs.FS_LoadImage( "#masked.pal", src, pal_bytes );
|
||||
pal = gEngfuncs.FS_LoadImage( "#masked.pal", src, 768 );
|
||||
break;
|
||||
default:
|
||||
pal = gEngfuncs.FS_LoadImage( "#normal.pal", src, pal_bytes );
|
||||
pal = gEngfuncs.FS_LoadImage( "#normal.pal", src, 768 );
|
||||
break;
|
||||
}
|
||||
|
||||
pframetype = (const byte *)(src + pal_bytes);
|
||||
pframetype = (const byte *)(src + 768);
|
||||
gEngfuncs.FS_FreeImage( pal ); // palette installed, no reason to keep this data
|
||||
}
|
||||
else
|
||||
{
|
||||
gEngfuncs.Con_DPrintf( S_ERROR "%s has wrong number of palette colors %i (should be less or equal than 256)\n", mod->name, *numi );
|
||||
gEngfuncs.Con_DPrintf( S_ERROR "%s has wrong number of palette colors %i (should be 256)\n", mod->name, *numi );
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -250,31 +249,32 @@ release sprite model and frames
|
||||
*/
|
||||
void Mod_SpriteUnloadTextures( void *data )
|
||||
{
|
||||
msprite_t *psprite = data;
|
||||
int i;
|
||||
msprite_t *psprite;
|
||||
mspritegroup_t *pspritegroup;
|
||||
mspriteframe_t *pspriteframe;
|
||||
int i, j;
|
||||
|
||||
if( !data )
|
||||
return;
|
||||
psprite = data;
|
||||
|
||||
// release all textures
|
||||
for( i = 0; i < psprite->numframes; i++ )
|
||||
if( psprite )
|
||||
{
|
||||
if( !psprite->frames[i].frameptr )
|
||||
continue;
|
||||
|
||||
if( psprite->frames[i].type == SPR_SINGLE )
|
||||
// release all textures
|
||||
for( i = 0; i < psprite->numframes; i++ )
|
||||
{
|
||||
GL_FreeTexture( psprite->frames[i].frameptr->gl_texturenum );
|
||||
}
|
||||
else
|
||||
{
|
||||
mspritegroup_t *pspritegroup = (mspritegroup_t *)psprite->frames[i].frameptr;
|
||||
int j;
|
||||
|
||||
for( j = 0; j < pspritegroup->numframes; j++ )
|
||||
if( psprite->frames[i].type == SPR_SINGLE )
|
||||
{
|
||||
if( pspritegroup->frames[j] )
|
||||
GL_FreeTexture( pspritegroup->frames[j]->gl_texturenum );
|
||||
pspriteframe = psprite->frames[i].frameptr;
|
||||
GL_FreeTexture( pspriteframe->gl_texturenum );
|
||||
}
|
||||
else
|
||||
{
|
||||
pspritegroup = (mspritegroup_t *)psprite->frames[i].frameptr;
|
||||
|
||||
for( j = 0; j < pspritegroup->numframes; j++ )
|
||||
{
|
||||
pspriteframe = pspritegroup->frames[i];
|
||||
GL_FreeTexture( pspriteframe->gl_texturenum );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,6 +79,8 @@ static struct
|
||||
qboolean update;
|
||||
|
||||
uint32_t texture[RIPPLES_TEXSIZE];
|
||||
int gl_texturenum;
|
||||
int rippletexturenum;
|
||||
} g_ripple;
|
||||
|
||||
|
||||
@@ -653,6 +655,22 @@ void R_ResetRipples( void )
|
||||
memset( g_ripple.buf, 0, sizeof( g_ripple.buf ));
|
||||
}
|
||||
|
||||
void R_InitRipples( void )
|
||||
{
|
||||
rgbdata_t pic = { 0 };
|
||||
|
||||
pic.width = pic.height = RIPPLES_CACHEWIDTH;
|
||||
pic.depth = 1;
|
||||
pic.flags = IMAGE_HAS_COLOR;
|
||||
pic.buffer = (byte *)g_ripple.texture;
|
||||
pic.type = PF_RGBA_32;
|
||||
pic.size = sizeof( g_ripple.texture );
|
||||
pic.numMips = 1;
|
||||
memset( pic.buffer, 0, pic.size );
|
||||
|
||||
g_ripple.rippletexturenum = GL_LoadTextureInternal( "*rippletex", &pic, TF_NOMIPMAP|TF_ALLOW_NEAREST );
|
||||
}
|
||||
|
||||
static void R_SwapBufs( void )
|
||||
{
|
||||
short *tempbufp = g_ripple.curbuf;
|
||||
@@ -720,7 +738,7 @@ void R_AnimateRipples( void )
|
||||
R_RunRipplesAnimation( g_ripple.oldbuf, g_ripple.curbuf );
|
||||
}
|
||||
|
||||
qboolean R_UploadRipples( texture_t *image )
|
||||
qboolean R_UploadRipples( const texture_t *image )
|
||||
{
|
||||
const gl_texture_t *glt;
|
||||
const uint32_t *pixels;
|
||||
@@ -741,6 +759,16 @@ qboolean R_UploadRipples( texture_t *image )
|
||||
return false;
|
||||
}
|
||||
|
||||
GL_Bind( XASH_TEXTURE0, g_ripple.rippletexturenum );
|
||||
|
||||
// no updates this frame
|
||||
if( !g_ripple.update && image->gl_texturenum == g_ripple.gl_texturenum )
|
||||
return true;
|
||||
|
||||
g_ripple.gl_texturenum = image->gl_texturenum;
|
||||
|
||||
size = r_ripple.value == 1.0f ? 64 : RIPPLES_CACHEWIDTH;
|
||||
|
||||
// try to preserve aspect ratio
|
||||
width = height = RIPPLES_CACHEWIDTH; // always render at maximum size
|
||||
if( image->width > image->height )
|
||||
@@ -748,32 +776,6 @@ qboolean R_UploadRipples( texture_t *image )
|
||||
else if( image->width < image->height )
|
||||
width = (float)image->width / image->height * height;
|
||||
|
||||
if( !image->fb_texturenum )
|
||||
{
|
||||
rgbdata_t pic = { 0 };
|
||||
string name;
|
||||
Q_snprintf( name, sizeof( name ), "*rippletex_%s", image->name );
|
||||
|
||||
pic.width = width;
|
||||
pic.height = height;
|
||||
pic.depth = 1;
|
||||
pic.flags = IMAGE_HAS_COLOR;
|
||||
pic.buffer = (byte *)g_ripple.texture;
|
||||
pic.type = PF_RGBA_32;
|
||||
pic.size = width * height * 4;
|
||||
pic.numMips = 1;
|
||||
memset( pic.buffer, 0, pic.size );
|
||||
|
||||
image->fb_texturenum = GL_LoadTextureInternal( name, &pic, TF_NOMIPMAP | TF_ALLOW_NEAREST );
|
||||
}
|
||||
|
||||
GL_Bind( XASH_TEXTURE0, image->fb_texturenum );
|
||||
|
||||
// no updates this frame
|
||||
if( !g_ripple.update )
|
||||
return true;
|
||||
|
||||
size = r_ripple.value == 1.0f ? 64 : RIPPLES_CACHEWIDTH;
|
||||
pixels = (const uint32_t *)glt->original->buffer;
|
||||
|
||||
for( y = 0; y < height; y++ )
|
||||
|
||||
@@ -66,33 +66,34 @@ void Mod_UnloadTextures( model_t *mod );
|
||||
|
||||
static qboolean GAME_EXPORT Mod_ProcessRenderData( model_t *mod, qboolean create, const byte *buf )
|
||||
{
|
||||
qboolean loaded = false;
|
||||
qboolean loaded = true;
|
||||
|
||||
if( create )
|
||||
{
|
||||
switch( mod->type )
|
||||
{
|
||||
case mod_studio:
|
||||
// Mod_LoadStudioModel( mod, buf, loaded );
|
||||
break;
|
||||
case mod_sprite:
|
||||
Mod_LoadSpriteModel( mod, buf, &loaded, mod->numtexinfo );
|
||||
break;
|
||||
case mod_alias:
|
||||
// Mod_LoadAliasModel( mod, buf, &loaded );
|
||||
break;
|
||||
case mod_brush:
|
||||
// Mod_LoadBrushModel( mod, buf, loaded );
|
||||
break;
|
||||
|
||||
default: gEngfuncs.Host_Error( "%s: unsupported type %d\n", __func__, mod->type );
|
||||
}
|
||||
}
|
||||
|
||||
if( loaded && gEngfuncs.drawFuncs->Mod_ProcessUserData )
|
||||
gEngfuncs.drawFuncs->Mod_ProcessUserData( mod, create, buf );
|
||||
|
||||
if( !create )
|
||||
{
|
||||
if( gEngfuncs.drawFuncs->Mod_ProcessUserData )
|
||||
gEngfuncs.drawFuncs->Mod_ProcessUserData( mod, false, buf );
|
||||
Mod_UnloadTextures( mod );
|
||||
return true;
|
||||
}
|
||||
|
||||
switch( mod->type )
|
||||
{
|
||||
case mod_studio:
|
||||
case mod_brush:
|
||||
case mod_alias:
|
||||
loaded = true;
|
||||
break;
|
||||
case mod_sprite:
|
||||
Mod_LoadSpriteModel( mod, buf, &loaded, mod->numtexinfo );
|
||||
break;
|
||||
default:
|
||||
gEngfuncs.Host_Error( "%s: unsupported type %d\n", __func__, mod->type );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( gEngfuncs.drawFuncs->Mod_ProcessUserData )
|
||||
gEngfuncs.drawFuncs->Mod_ProcessUserData( mod, true, buf );
|
||||
|
||||
return loaded;
|
||||
}
|
||||
|
||||
@@ -363,6 +363,8 @@ typedef struct image_s
|
||||
pixel_t *pixels[4]; // mip levels
|
||||
pixel_t *alpha_pixels; // mip levels
|
||||
|
||||
|
||||
int servercount;
|
||||
uint hashValue;
|
||||
struct image_s *nextHash;
|
||||
} image_t;
|
||||
|
||||
@@ -165,32 +165,31 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
|
||||
pframetype = ((const byte *)buffer + sizeof( dsprite_q1_t )); // pinq1 + 1
|
||||
gEngfuncs.FS_FreeImage( pal ); // palette installed, no reason to keep this data
|
||||
}
|
||||
else if( *numi <= 256 )
|
||||
else if( *numi == 256 )
|
||||
{
|
||||
const byte *src = (const byte *)(numi+1);
|
||||
rgbdata_t *pal;
|
||||
size_t pal_bytes = *numi * 3;
|
||||
const byte *src = (const byte *)( numi + 1 );
|
||||
rgbdata_t *pal;
|
||||
|
||||
// install palette
|
||||
switch( psprite->texFormat )
|
||||
{
|
||||
case SPR_INDEXALPHA:
|
||||
pal = gEngfuncs.FS_LoadImage( "#gradient.pal", src, pal_bytes );
|
||||
pal = gEngfuncs.FS_LoadImage( "#gradient.pal", src, 768 );
|
||||
break;
|
||||
case SPR_ALPHTEST:
|
||||
pal = gEngfuncs.FS_LoadImage( "#masked.pal", src, pal_bytes );
|
||||
pal = gEngfuncs.FS_LoadImage( "#masked.pal", src, 768 );
|
||||
break;
|
||||
default:
|
||||
pal = gEngfuncs.FS_LoadImage( "#normal.pal", src, pal_bytes );
|
||||
pal = gEngfuncs.FS_LoadImage( "#normal.pal", src, 768 );
|
||||
break;
|
||||
}
|
||||
|
||||
pframetype = (const byte *)(src + pal_bytes);
|
||||
pframetype = (const byte *)( src + 768 );
|
||||
gEngfuncs.FS_FreeImage( pal ); // palette installed, no reason to keep this data
|
||||
}
|
||||
else
|
||||
{
|
||||
gEngfuncs.Con_DPrintf( S_ERROR "%s has wrong number of palette colors %i (should be less or equal than 256)\n", mod->name, *numi );
|
||||
gEngfuncs.Con_DPrintf( S_ERROR "%s has wrong number of palette colors %i (should be 256)\n", mod->name, *numi );
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -238,31 +237,32 @@ release sprite model and frames
|
||||
*/
|
||||
void Mod_SpriteUnloadTextures( void *data )
|
||||
{
|
||||
msprite_t *psprite = data;
|
||||
int i;
|
||||
msprite_t *psprite;
|
||||
mspritegroup_t *pspritegroup;
|
||||
mspriteframe_t *pspriteframe;
|
||||
int i, j;
|
||||
|
||||
if( !data )
|
||||
return;
|
||||
psprite = data;
|
||||
|
||||
// release all textures
|
||||
for( i = 0; i < psprite->numframes; i++ )
|
||||
if( psprite )
|
||||
{
|
||||
if( !psprite->frames[i].frameptr )
|
||||
continue;
|
||||
|
||||
if( psprite->frames[i].type == SPR_SINGLE )
|
||||
// release all textures
|
||||
for( i = 0; i < psprite->numframes; i++ )
|
||||
{
|
||||
GL_FreeTexture( psprite->frames[i].frameptr->gl_texturenum );
|
||||
}
|
||||
else
|
||||
{
|
||||
mspritegroup_t *pspritegroup = (mspritegroup_t *)psprite->frames[i].frameptr;
|
||||
int j;
|
||||
|
||||
for( j = 0; j < pspritegroup->numframes; j++ )
|
||||
if( psprite->frames[i].type == SPR_SINGLE )
|
||||
{
|
||||
if( pspritegroup->frames[j] )
|
||||
GL_FreeTexture( pspritegroup->frames[j]->gl_texturenum );
|
||||
pspriteframe = psprite->frames[i].frameptr;
|
||||
GL_FreeTexture( pspriteframe->gl_texturenum );
|
||||
}
|
||||
else
|
||||
{
|
||||
pspritegroup = (mspritegroup_t *)psprite->frames[i].frameptr;
|
||||
|
||||
for( j = 0; j < pspritegroup->numframes; j++ )
|
||||
{
|
||||
pspriteframe = pspritegroup->frames[i];
|
||||
GL_FreeTexture( pspriteframe->gl_texturenum );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ for i in arm64 armhf riscv64 ppc64el; do
|
||||
CROSS_COMPILE_CC[$i]=${ARCH_TRIPLET[$i]}-gcc
|
||||
CROSS_COMPILE_CXX[$i]=${ARCH_TRIPLET[$i]}-g++
|
||||
done
|
||||
export PKG_CONFIG_PATH=$PWD/ffmpeg/lib/pkgconfig:${ARCH_TRIPLET[$GH_CPU_ARCH]}
|
||||
export PKG_CONFIG_PATH=${ARCH_TRIPLET[$GH_CPU_ARCH]}
|
||||
export CC=${CROSS_COMPILE_CC[$GH_CPU_ARCH]}
|
||||
export CXX=${CROSS_COMPILE_CXX[$GH_CPU_ARCH]}
|
||||
|
||||
@@ -53,21 +53,17 @@ build_engine()
|
||||
cd "$BUILDDIR" || die
|
||||
|
||||
if [ "$ARCH" = "amd64" ]; then # we need enabling 64-bit target only on Intel-compatible CPUs
|
||||
WAF_EXTRA_ARGS="-8"
|
||||
fi
|
||||
|
||||
if [ -d "ffmpeg" ]; then
|
||||
WAF_EXTRA_ARGS+=" --enable-ffmpeg"
|
||||
AMD64="-8"
|
||||
fi
|
||||
|
||||
if [ "$GH_CROSSCOMPILING" != "true" ]; then
|
||||
WAF_EXTRA_ARGS+=" --enable-tests"
|
||||
ENABLE_TESTS="--enable-tests"
|
||||
fi
|
||||
|
||||
if [ "$1" = "dedicated" ]; then
|
||||
./waf configure $WAF_EXTRA_ARGS --enable-lto --enable-bundled-deps -d || die_configure
|
||||
./waf configure $AMD64 $ENABLE_TESTS --enable-lto --enable-bundled-deps -d || die_configure
|
||||
elif [ "$1" = "full" ]; then
|
||||
./waf configure $WAF_EXTRA_ARGS --enable-lto --enable-bundled-deps -s SDL2_linux --enable-stb --enable-utils || die_configure
|
||||
./waf configure $AMD64 $ENABLE_TESTS --enable-lto --enable-bundled-deps -s SDL2_linux --enable-stb --enable-utils || die_configure
|
||||
else
|
||||
die
|
||||
fi
|
||||
@@ -79,13 +75,9 @@ deploy_engine()
|
||||
{
|
||||
cd "$BUILDDIR" || die
|
||||
./waf install --destdir="$APPDIR" || die
|
||||
cp -av SDL2_linux/lib/libSDL2-2.0.so.0 "$APPDIR/"
|
||||
cp SDL2_linux/lib/libSDL2-2.0.so.0 "$APPDIR/"
|
||||
if [ "$GH_CPU_ARCH" = "i386" ]; then
|
||||
cp -av 3rdparty/vgui_support/vgui-dev/lib/vgui.so "$APPDIR/"
|
||||
fi
|
||||
|
||||
if [ -d "ffmpeg" ]; then
|
||||
cp -av ffmpeg/lib/libav* ffmpeg/lib/libsw* "$APPDIR/"
|
||||
cp 3rdparty/vgui_support/vgui-dev/lib/vgui.so "$APPDIR/"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@@ -9,33 +9,23 @@ if [ "$ARCH" = "amd64" ]; then # we need enabling 64-bit target only on Intel-co
|
||||
AMD64="-8"
|
||||
fi
|
||||
|
||||
if [ -d "ffmpeg" ]; then
|
||||
export PKGCONFIG="$PWD/pkgconf/bin/pkgconf.exe"
|
||||
export PKG_CONFIG_PATH="$PWD/ffmpeg/lib/pkgconfig"
|
||||
WAF_EXTRA_ARGS="--enable-ffmpeg"
|
||||
fi
|
||||
|
||||
# NOTE: to build with other version use --msvc_version during configuration
|
||||
# NOTE: sometimes you may need to add WinSDK to %PATH%
|
||||
# NOTE: --enable-msvcdeps only used for CI builds, enabling it non-English versions of MSVC causes useless console spam
|
||||
./waf.bat configure -s "SDL2_VC" -T release --enable-utils --enable-tests --enable-lto --enable-msvcdeps $AMD64 $WAF_EXTRA_ARGS || die_configure
|
||||
./waf.bat configure -s "SDL2_VC" -T release --enable-utils --enable-tests --enable-lto --enable-msvcdeps $AMD64 || die_configure
|
||||
./waf.bat build || die
|
||||
./waf.bat install --destdir=. || die
|
||||
|
||||
if [ "$ARCH" = "i386" ]; then
|
||||
cp -v SDL2_VC/lib/x86/SDL2.dll . # Install SDL2
|
||||
cp -v SDL2_VC/lib/x86/SDL2.pdb .
|
||||
cp SDL2_VC/lib/x86/SDL2.dll . # Install SDL2
|
||||
cp SDL2_VC/lib/x86/SDL2.pdb .
|
||||
elif [ "$ARCH" = "amd64" ]; then
|
||||
cp -v SDL2_VC/lib/x64/SDL2.dll .
|
||||
cp -v SDL2_VC/lib/x64/SDL2.pdb .
|
||||
cp SDL2_VC/lib/x64/SDL2.dll .
|
||||
cp SDL2_VC/lib/x64/SDL2.pdb .
|
||||
else
|
||||
die
|
||||
fi
|
||||
|
||||
if [ -d "ffmpeg" ]; then
|
||||
cp -v ffmpeg/bin/av* ffmpeg/bin/sw* .
|
||||
fi
|
||||
|
||||
WINSDK_LATEST=$(ls -1 "C:/Program Files (x86)/Windows Kits/10/bin" | grep -E '^10' | sort -rV | head -n1)
|
||||
echo "Latest installed Windows SDK is $WINSDK_LATEST"
|
||||
|
||||
|
||||
@@ -70,9 +70,5 @@ if [ -n "${APPIMAGETOOL[$GH_CPU_ARCH]}" ]; then
|
||||
chmod +x appimagetool.AppImage
|
||||
fi
|
||||
|
||||
FFMPEG_ARCHIVE=$(get_ffmpeg_archive)
|
||||
wget https://github.com/FWGS/FFmpeg-Builds/releases/download/latest/$FFMPEG_ARCHIVE.tar.xz -qO- | tar -xJf -
|
||||
mv $FFMPEG_ARCHIVE ffmpeg
|
||||
|
||||
wget "https://github.com/libsdl-org/SDL/releases/download/release-$SDL_VERSION/SDL2-$SDL_VERSION.tar.gz" -qO- | tar -xzf -
|
||||
mv "SDL2-$SDL_VERSION" SDL2_src
|
||||
|
||||
@@ -1,20 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
. scripts/lib.sh
|
||||
|
||||
curl -L http://libsdl.org/release/SDL2-devel-$SDL_VERSION-VC.zip -o SDL2.zip
|
||||
curl -L https://github.com/libsdl-org/SDL/releases/download/release-$SDL_VERSION/SDL2-devel-$SDL_VERSION-VC.zip -o SDL2.zip
|
||||
unzip -q SDL2.zip
|
||||
mv SDL2-$SDL_VERSION SDL2_VC
|
||||
|
||||
curl -L https://github.com/FWGS/potential-meme/releases/download/prebuilts/mingw-w64-x86_64-pkgconf-1.2.3.0-1-any.pkg.tar.zst -o pkgconf.tar.zst
|
||||
7z x pkgconf.tar.zst
|
||||
7z x pkgconf.tar
|
||||
rm pkgconf.tar*
|
||||
mv mingw64 pkgconf
|
||||
|
||||
FFMPEG_ARCHIVE=$(get_ffmpeg_archive)
|
||||
curl -L https://github.com/FWGS/FFmpeg-Builds/releases/download/latest/$FFMPEG_ARCHIVE.zip -o ffmpeg.zip
|
||||
if [ -f ffmpeg.zip ]; then
|
||||
unzip -x ffmpeg.zip
|
||||
mv $FFMPEG_ARCHIVE ffmpeg
|
||||
fi
|
||||
|
||||
@@ -9,27 +9,6 @@ die_configure()
|
||||
die
|
||||
}
|
||||
|
||||
get_ffmpeg_archive()
|
||||
{
|
||||
if [ "$GH_CPU_OS" == "win32" ]; then
|
||||
A=win
|
||||
else
|
||||
A="$GH_CPU_OS"
|
||||
fi
|
||||
|
||||
if [ "$GH_CPU_ARCH" == "amd64" ]; then
|
||||
B=64
|
||||
elif [ "$GH_CPU_ARCH" == "i386" ]; then
|
||||
B=32
|
||||
else
|
||||
B="$GH_CPU_ARCH"
|
||||
fi
|
||||
|
||||
FLAVOR=lgpl-shared-minimal
|
||||
|
||||
echo "ffmpeg-n$FFMPEG_VERSION-latest-$A$B-$FLAVOR-$FFMPEG_VERSION"
|
||||
}
|
||||
|
||||
if [ -n "$TRAVIS_BUILD_DIR" ]; then
|
||||
BUILDDIR=$TRAVIS_BUILD_DIR
|
||||
elif [ -n "$GITHUB_WORKSPACE" ]; then
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user