mirror of
https://github.com/FWGS/xash3d-fwgs.git
synced 2026-08-05 19:45:05 +08:00
Compare commits
107 Commits
continuous
...
continuous
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
def7bfc5d8 | ||
|
|
6a752a924c | ||
|
|
864c15cf83 | ||
|
|
20d26d467d | ||
|
|
9898948424 | ||
|
|
2320734ec0 | ||
|
|
dcc5756649 | ||
|
|
6256d99345 | ||
|
|
38bea0312c | ||
|
|
35bb66d33a | ||
|
|
05d5a012d4 | ||
|
|
6ca7271006 | ||
|
|
e43ccee77f | ||
|
|
eb0241dac6 | ||
|
|
526ebab062 | ||
|
|
1dd3447cef | ||
|
|
a8ff36aa57 | ||
|
|
866c02802c | ||
|
|
e3bfe5bb81 | ||
|
|
560f5e1f6d | ||
|
|
849ff0f7b5 | ||
|
|
06b14800e1 | ||
|
|
bb7c85fd22 | ||
|
|
37ce62fa6a | ||
|
|
e1b29e2da3 | ||
|
|
b60afd73e9 | ||
|
|
84447a5292 | ||
|
|
fe4ea4aabf | ||
|
|
878822290c | ||
|
|
04ca5d7cb0 | ||
|
|
d46ed40f33 | ||
|
|
82e031205c | ||
|
|
6f5f04a29d | ||
|
|
f9ed578bf1 | ||
|
|
86c84c7de7 | ||
|
|
489c1c9dd5 | ||
|
|
1df6a040ec | ||
|
|
82c2ca53fb | ||
|
|
3ddd1e2448 | ||
|
|
371d619685 | ||
|
|
480f29e96e | ||
|
|
95548053eb | ||
|
|
0daf2c2b4d | ||
|
|
e2d5bea327 | ||
|
|
306a5812a9 | ||
|
|
a3dba64513 | ||
|
|
491ba9bc7d | ||
|
|
1c462df8a2 | ||
|
|
ed975976f8 | ||
|
|
bbf8ab378d | ||
|
|
5383e36af5 | ||
|
|
897fb98b93 | ||
|
|
96e88adfcd | ||
|
|
4dde4047f1 | ||
|
|
905161529f | ||
|
|
044523434d | ||
|
|
da4c4bb76a | ||
|
|
95b3271d68 | ||
|
|
3361a5d760 | ||
|
|
b725d2ece0 | ||
|
|
66bee8b468 | ||
|
|
5e664dc3e9 | ||
|
|
bfdfeb3dc0 | ||
|
|
49248f5e14 | ||
|
|
d03ea4c10a | ||
|
|
780dbd6183 | ||
|
|
50da79f1e0 | ||
|
|
62201900cf | ||
|
|
ae233ac491 | ||
|
|
dd1cb04cb7 | ||
|
|
74869c8f5d | ||
|
|
dd712a0df9 | ||
|
|
bfdb62d31e | ||
|
|
ae7b9eb28d | ||
|
|
c63e13c8f4 | ||
|
|
d3e1407675 | ||
|
|
e2e4728c7c | ||
|
|
dd3583d11a | ||
|
|
e6924844da | ||
|
|
a49db03561 | ||
|
|
84b7b5803b | ||
|
|
c224d39ba7 | ||
|
|
9b24b08df1 | ||
|
|
a37b0e58f1 | ||
|
|
afca422e35 | ||
|
|
3440ddf443 | ||
|
|
6730ed9555 | ||
|
|
fdd3a44fa0 | ||
|
|
241c926076 | ||
|
|
148a9a5a8c | ||
|
|
513984d7fd | ||
|
|
1009795d5c | ||
|
|
e3d2da74db | ||
|
|
ff3a57ae8a | ||
|
|
271a6e2210 | ||
|
|
0d40357b93 | ||
|
|
a9dcdd034c | ||
|
|
7324ff43fc | ||
|
|
d85e7fc2b1 | ||
|
|
d91ecfa3df | ||
|
|
b7a3a02aad | ||
|
|
5aca78951c | ||
|
|
81abae65b5 | ||
|
|
f5f6d9bbe4 | ||
|
|
ef73b55413 | ||
|
|
8334695522 | ||
|
|
d7f416d659 |
14
3rdparty/libbacktrace/wscript
vendored
14
3rdparty/libbacktrace/wscript
vendored
@@ -20,10 +20,10 @@ int main (void) {
|
||||
}'''
|
||||
|
||||
FRAGMENT_GETPAGESIZE='''#include <unistd.h>
|
||||
int main(void) { return getpagesize() }'''
|
||||
int main(void) { return getpagesize(); }'''
|
||||
|
||||
FRAGMENT_GETEXECNAME='''#include <stdlib.h>
|
||||
int main(void) { return getexecname() != 0 }'''
|
||||
int main(void) { return getexecname() != 0; }'''
|
||||
|
||||
FRAGMENT_STRNLEN='''#include <string.h>
|
||||
int main(int argc, char **argv) { return (int)strnlen(argv[0], 10); }'''
|
||||
@@ -120,8 +120,8 @@ def configure(conf):
|
||||
check_frag(FRAGMENT_SYNC, ' __sync extensions', 'HAVE_SYNC_FUNCTIONS'),
|
||||
check_frag(FRAGMENT_GETPAGESIZE, ' getpagesize function', 'HAVE_DECL_GETPAGESIZE'),
|
||||
check_frag(FRAGMENT_STRNLEN, ' strnlen function', 'HAVE_DECL_STRNLEN'),
|
||||
check_frag(FRAGMENT_DL_ITERATE_PHDR % 'link.h', ' dl_iterate_phdr function in link.h', 'HAVE_DL_ITERATE_PHDR', after_tests=['link.h']),
|
||||
check_frag(FRAGMENT_DL_ITERATE_PHDR % 'sys/link.h', ' dl_iterate_phdr function in sys/link.h', 'HAVE_DL_ITERATE_PHDR', after_tests=['sys/link.h']),
|
||||
check_frag(FRAGMENT_DL_ITERATE_PHDR % 'link.h', ' dl_iterate_phdr function in link.h', 'HAVE_DL_ITERATE_PHDR_LINK_H', after_tests=['link.h']),
|
||||
check_frag(FRAGMENT_DL_ITERATE_PHDR % 'sys/link.h', ' dl_iterate_phdr function in sys/link.h', 'HAVE_DL_ITERATE_PHDR_SYS_LINK_H', after_tests=['sys/link.h']),
|
||||
check_frag(FRAGMENT_FCNTL, 'fnctl function', 'HAVE_FCNTL'),
|
||||
check_frag(FRAGMENT_GETEXECNAME, 'getexecname function','HAVE_GETEXECNAME'),
|
||||
check_frag(FRAGMENT_GETIPINFO, '_Unwind_GetIPInfo function', 'HAVE_GETIPINFO'),
|
||||
@@ -137,6 +137,9 @@ def configure(conf):
|
||||
msg='Checking for in parallel'
|
||||
)
|
||||
|
||||
if conf.is_defined('HAVE_DL_ITERATE_PHDR_LINK_H') or conf.is_defined('HAVE_DL_ITERATE_PHDR_SYS_LINK_H'):
|
||||
conf.define('HAVE_DL_ITERATE_PHDR', 1)
|
||||
|
||||
conf.env[DEFKEYS].sort()
|
||||
|
||||
conf.write_config_header()
|
||||
@@ -181,7 +184,8 @@ def build(bld):
|
||||
|
||||
task = bld.stlib(
|
||||
source = ['libbacktrace/' + i for i in sources],
|
||||
target = 'backtrace',
|
||||
# while we're using upstream libbacktrace, sometimes compiler picks up it's own version that isn't built with required options
|
||||
target = 'backtrace_custom',
|
||||
features = 'frandomseed' if bld.env.HAVE_FRANDOM_SEED else '',
|
||||
use = 'EXTRAFLAGS lzma z zstd',
|
||||
includes = '. libbacktrace/',
|
||||
|
||||
2
3rdparty/library_suffix
vendored
2
3rdparty/library_suffix
vendored
Submodule 3rdparty/library_suffix updated: 6e14ae31e8...2cb2a0e120
2
3rdparty/mainui
vendored
2
3rdparty/mainui
vendored
Submodule 3rdparty/mainui updated: af2b5abdde...d262e14d54
@@ -87,6 +87,7 @@ typedef enum
|
||||
IL_LOAD_PLAYER_DECAL = BIT(7), // special mode for player decals
|
||||
IL_KTX2_RAW = BIT(8), // renderer can consume raw KTX2 files (e.g. ref_vk)
|
||||
IL_ALLOW_WAD3_LUMA = BIT(9), // allow usage of luma textures in wad3 (tilde textures)
|
||||
IL_HOST_ENDIAN = BIT(10), // buffer is already in host endian, skip byte-swapping
|
||||
} ilFlags_t;
|
||||
|
||||
// goes into rgbdata_t->encode
|
||||
|
||||
@@ -22,6 +22,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#ifndef QUAKE_CLIENT_H
|
||||
#define QUAKE_CLIENT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "xash3d_types.h"
|
||||
|
||||
// Definitions originally taken from Quake, modified for binary compatibility
|
||||
|
||||
typedef struct usercmd_s
|
||||
|
||||
@@ -243,7 +243,10 @@ typedef int qboolean;
|
||||
#define Swap32Store( x ) ( x = Swap32( x ))
|
||||
#define Swap16Store( x ) ( x = Swap16( x ))
|
||||
|
||||
#ifdef XASH_BIG_ENDIAN
|
||||
#define LittleFourCC( a, b, c, d ) (((uint32_t)( d ) << 24 ) | ((uint32_t)( c ) << 16 ) | ((uint32_t)( b ) << 8 ) | (uint32_t)( a ))
|
||||
#define BigFourCC( a, b, c, d ) (((uint32_t)( a ) << 24 ) | ((uint32_t)( b ) << 16 ) | ((uint32_t)( c ) << 8 ) | (uint32_t)( d ))
|
||||
|
||||
#if XASH_BIG_ENDIAN
|
||||
#define LittleLong( x ) Swap32( x )
|
||||
#define LittleShort( x ) Swap16( x )
|
||||
#define LittleLongSW( x ) Swap32Store( x )
|
||||
@@ -252,6 +255,7 @@ typedef int qboolean;
|
||||
#define BigLong( x ) ( x )
|
||||
#define BigShort( x ) ( x )
|
||||
#define BigFloat( x ) ( x )
|
||||
#define HostFourCC( a, b, c, d ) BigFourCC( a, b, c, d )
|
||||
#else
|
||||
#define LittleLong( x ) ( x )
|
||||
#define LittleShort( x ) ( x )
|
||||
@@ -261,6 +265,7 @@ typedef int qboolean;
|
||||
#define BigLong( x ) Swap32( x )
|
||||
#define BigShort( x ) Swap16( x )
|
||||
#define BigFloat( x ) SwapFloat( x )
|
||||
#define HostFourCC( a, b, c, d ) LittleFourCC( a, b, c, d )
|
||||
#endif
|
||||
|
||||
#endif // XASH_TYPES_H
|
||||
|
||||
@@ -444,13 +444,16 @@ qboolean AVI_Think( movie_state_t *Avi )
|
||||
|
||||
if( Avi->texture == 0 )
|
||||
{
|
||||
int cinTexture = SCR_GetCinematicTexture();
|
||||
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 );
|
||||
if( redraw )
|
||||
ref.dllFuncs.GL_UpdateTexture( cinTexture, Avi->xres, Avi->yres, Avi->xres, Avi->yres, Avi->dst, PF_BGRA_32 );
|
||||
ref.dllFuncs.R_DrawStretchPic( Avi->x, Avi->y, w, h, 0, 0, 1, 1, cinTexture );
|
||||
}
|
||||
else if( redraw && Avi->texture > 0 )
|
||||
ref.dllFuncs.AVI_UploadRawFrame( Avi->texture, Avi->xres, Avi->yres, Avi->w, Avi->h, Avi->dst );
|
||||
ref.dllFuncs.GL_UpdateTexture( Avi->texture, Avi->xres, Avi->yres, Avi->w, Avi->h, Avi->dst, PF_BGRA_32 );
|
||||
|
||||
if( flushing && !decoded )
|
||||
return false; // probably hit an EOF
|
||||
|
||||
@@ -849,6 +849,31 @@ BEAM * GAME_EXPORT R_BeamEnts( int startEnt, int endEnt, int modelIndex, float l
|
||||
return pbeam;
|
||||
}
|
||||
|
||||
static qboolean R_BeamVisible( const vec3_t start, const vec3_t end )
|
||||
{
|
||||
vec3_t mins, maxs;
|
||||
|
||||
for( int i = 0; i < 3; i++ )
|
||||
{
|
||||
if( start[i] < end[i] )
|
||||
{
|
||||
mins[i] = start[i];
|
||||
maxs[i] = end[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
mins[i] = end[i];
|
||||
maxs[i] = start[i];
|
||||
}
|
||||
|
||||
// don't let it be zero sized
|
||||
if( mins[i] == maxs[i] )
|
||||
maxs[i] += 1.0f;
|
||||
}
|
||||
|
||||
return Mod_BoxVisible( mins, maxs, ref.dllFuncs.Mod_GetCurrentVis( ));
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
R_BeamPoints
|
||||
@@ -861,7 +886,7 @@ BEAM * GAME_EXPORT R_BeamPoints( vec3_t start, vec3_t end, int modelIndex, float
|
||||
{
|
||||
BEAM *pbeam;
|
||||
|
||||
if( life != 0 && ref.dllFuncs.R_BeamCull( start, end, true ))
|
||||
if( life != 0 && !R_BeamVisible( start, end ))
|
||||
return NULL;
|
||||
|
||||
pbeam = R_BeamAlloc();
|
||||
@@ -1214,8 +1239,8 @@ particle spray
|
||||
void GAME_EXPORT R_Blood( const vec3_t org, const vec3_t ndir, int pcolor, int speed )
|
||||
{
|
||||
vec3_t pos, dir, vec;
|
||||
float pspeed = speed * 3.0f;
|
||||
int i, j;
|
||||
int pspeed = speed * 3;
|
||||
particle_t *p;
|
||||
|
||||
VectorNormalize2( ndir, dir );
|
||||
@@ -1225,7 +1250,7 @@ void GAME_EXPORT R_Blood( const vec3_t org, const vec3_t ndir, int pcolor, int s
|
||||
VectorAddScalar( org, COM_RandomFloat( -3.0f, 3.0f ), pos );
|
||||
VectorAddScalar( dir, COM_RandomFloat( -0.06f, 0.06f ), vec );
|
||||
|
||||
for( j = 0; j < 7; j++ )
|
||||
for( j = 0; j < 8; j++ )
|
||||
{
|
||||
p = R_AllocParticle( NULL );
|
||||
if( !p ) return;
|
||||
@@ -1237,6 +1262,8 @@ void GAME_EXPORT R_Blood( const vec3_t org, const vec3_t ndir, int pcolor, int s
|
||||
VectorAddScalar( pos, COM_RandomFloat( -1.0f, 1.0f ), p->org );
|
||||
VectorScale( vec, pspeed, p->vel );
|
||||
}
|
||||
|
||||
pspeed -= speed;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1308,10 +1335,7 @@ void GAME_EXPORT R_BloodStream( const vec3_t org, const vec3_t ndir, int pcolor,
|
||||
p->color = pcolor + COM_RandomLong( 0, 9 );
|
||||
p->type = pt_4x_slowgrav;
|
||||
|
||||
p->org[0] = org[0] + COM_RandomFloat( -1.0f, 1.0f );
|
||||
p->org[1] = org[1] + COM_RandomFloat( -1.0f, 1.0f );
|
||||
p->org[2] = org[2] + COM_RandomFloat( -1.0f, 1.0f );
|
||||
|
||||
VectorAddScalar( org, COM_RandomFloat( -1.0f, 1.0f ), p->org );
|
||||
VectorCopy( dir, p->vel );
|
||||
p->vel[2] -= arc;
|
||||
|
||||
|
||||
@@ -17,6 +17,20 @@ GNU General Public License for more details.
|
||||
#include "filesystem.h"
|
||||
#include "client.h"
|
||||
#include "qfont.h"
|
||||
#include "swaplib.h"
|
||||
|
||||
le_struct_begin( charinfo_swap )
|
||||
le_struct_field( charinfo, startoffset )
|
||||
le_struct_field( charinfo, charwidth )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( qfont_swap )
|
||||
le_struct_field( qfont_t, width )
|
||||
le_struct_field( qfont_t, height )
|
||||
le_struct_field( qfont_t, rowcount )
|
||||
le_struct_field( qfont_t, rowheight )
|
||||
le_struct_array_child( qfont_t, fontinfo, charinfo_swap, NUM_GLYPHS )
|
||||
le_struct_end();
|
||||
|
||||
qboolean CL_FixedFont( cl_font_t *font )
|
||||
{
|
||||
@@ -130,6 +144,7 @@ qboolean Con_LoadVariableWidthFont( const char *fontname, cl_font_t *font, float
|
||||
}
|
||||
|
||||
memcpy( &src, pfile, sizeof( src ));
|
||||
le_struct_swap( qfont_swap, &src );
|
||||
Mem_Free( pfile );
|
||||
|
||||
font->hFontTexture = CL_LoadFontTexture( fontname, texFlags, &font_width );
|
||||
|
||||
@@ -981,15 +981,8 @@ qboolean CL_AddVisibleEntity( cl_entity_t *ent, int entityType )
|
||||
if( !draw_player )
|
||||
return false;
|
||||
|
||||
if( entityType == ET_BEAM )
|
||||
{
|
||||
ref.dllFuncs.CL_AddCustomBeam( ent );
|
||||
return true;
|
||||
}
|
||||
else if( !ref.dllFuncs.R_AddEntity( ent, entityType ))
|
||||
{
|
||||
if( !ref.dllFuncs.R_AddEntity( ent, entityType ))
|
||||
return false;
|
||||
}
|
||||
|
||||
// because pTemp->entity.curstate.effects
|
||||
// is already occupied by FTENT_FLICKER
|
||||
|
||||
@@ -1385,6 +1385,10 @@ static void CL_CreateResourceList( void )
|
||||
cl.num_resources = 0;
|
||||
memset( rgucMD5_hash, 0, sizeof( rgucMD5_hash ));
|
||||
|
||||
ClearBits( cl_logofile.flags, FCVAR_CHANGED );
|
||||
ClearBits( cl_logocolor.flags, FCVAR_CHANGED );
|
||||
ClearBits( cl_logoext.flags, FCVAR_CHANGED );
|
||||
|
||||
// sanitize cvar value
|
||||
if( Q_strcmp( cl_logoext.string, "bmp" ) && Q_strcmp( cl_logoext.string, "png" ))
|
||||
Cvar_DirectSet( &cl_logoext, "bmp" );
|
||||
@@ -1400,7 +1404,6 @@ static void CL_CreateResourceList( void )
|
||||
if( !fp )
|
||||
return;
|
||||
|
||||
MD5_HashFile( rgucMD5_hash, szFileName, NULL );
|
||||
nSize = FS_FileLength( fp );
|
||||
|
||||
if( nSize != 0 )
|
||||
@@ -1409,6 +1412,7 @@ static void CL_CreateResourceList( void )
|
||||
|
||||
if( pNewResource )
|
||||
{
|
||||
MD5_HashFile( rgucMD5_hash, szFileName, NULL );
|
||||
SetBits( pNewResource->ucFlags, RES_CUSTOM );
|
||||
memcpy( pNewResource->rgucMD5_hash, rgucMD5_hash, 16 );
|
||||
HPAK_AddLump( false, hpk_custom_file.string, pNewResource, NULL, fp );
|
||||
@@ -1418,6 +1422,42 @@ static void CL_CreateResourceList( void )
|
||||
FS_Close( fp );
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
CL_CheckLogoChanged
|
||||
|
||||
==================
|
||||
*/
|
||||
static void CL_CheckLogoChanged( void )
|
||||
{
|
||||
player_info_t *player;
|
||||
int i;
|
||||
|
||||
if( cls.state != ca_active )
|
||||
return;
|
||||
|
||||
if( !FBitSet( cl_logofile.flags | cl_logocolor.flags | cl_logoext.flags, FCVAR_CHANGED ))
|
||||
return;
|
||||
|
||||
CL_CreateResourceList();
|
||||
|
||||
if( cl.num_resources == 0 )
|
||||
return;
|
||||
|
||||
player = &cl.players[cl.playernum];
|
||||
COM_ClearCustomizationList( &player->customdata, true );
|
||||
|
||||
for( i = 0; i < cl.num_resources; i++ )
|
||||
{
|
||||
resource_t *pResource = &cl.resourcelist[i];
|
||||
|
||||
if( !COM_CreateCustomization( &player->customdata, pResource, cl.playernum, 0, NULL, NULL ))
|
||||
Con_Printf( "Unable to create custom decal\n" );
|
||||
}
|
||||
|
||||
CL_SendResourceList( cl.resourcelist, cl.num_resources );
|
||||
}
|
||||
|
||||
static qboolean CL_StringToProtocol( const char *s, connprotocol_t *proto )
|
||||
{
|
||||
if( !Q_stricmp( s, "current" ) || !Q_strcmp( s, "49" ))
|
||||
@@ -2543,7 +2583,7 @@ static void CL_ServerList( netadr_t from, sizebuf_t *msg )
|
||||
MSG_ReadBytes( msg, servadr.ip, sizeof( servadr.ip )); // 4 bytes for IP
|
||||
NET_NetadrSetType( &servadr, NA_IP );
|
||||
}
|
||||
servadr.port = MSG_ReadShort( msg ); // 2 bytes for Port
|
||||
MSG_ReadBytes( msg, &servadr.port, sizeof( servadr.port )); // 2 bytes for Port, in network byte order
|
||||
|
||||
// list is ends here
|
||||
if( !servadr.port )
|
||||
@@ -3589,6 +3629,9 @@ void Host_ClientBegin( void )
|
||||
// finalize connection process if needs
|
||||
CL_CheckClientState();
|
||||
|
||||
// check if logo cvars changed and re-upload if needed
|
||||
CL_CheckLogoChanged();
|
||||
|
||||
// tell the client.dll about client data
|
||||
CL_UpdateClientData();
|
||||
|
||||
|
||||
360
engine/client/cl_sprite.c
Normal file
360
engine/client/cl_sprite.c
Normal file
@@ -0,0 +1,360 @@
|
||||
/*
|
||||
cl_sprite.c - sprite loading
|
||||
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 "common.h"
|
||||
#include "client.h"
|
||||
#include "sprite.h"
|
||||
#include "ref_common.h"
|
||||
|
||||
static char sprite_name[MAX_QPATH];
|
||||
static char group_suffix[8];
|
||||
static uint r_texFlags = 0;
|
||||
static int sprite_version;
|
||||
|
||||
/*
|
||||
================
|
||||
R_GetSpriteFrame
|
||||
|
||||
assume pModel is valid
|
||||
================
|
||||
*/
|
||||
mspriteframe_t *R_GetSpriteFrame( const model_t *pModel, int frame, float yaw )
|
||||
{
|
||||
msprite_t *psprite;
|
||||
mspritegroup_t *pspritegroup;
|
||||
mspriteframe_t *pspriteframe = NULL;
|
||||
float *pintervals, fullinterval;
|
||||
int i, numframes;
|
||||
float targettime;
|
||||
|
||||
if( !pModel )
|
||||
return NULL;
|
||||
|
||||
psprite = pModel->cache.data;
|
||||
|
||||
if( frame < 0 )
|
||||
{
|
||||
frame = 0;
|
||||
}
|
||||
else if( frame >= psprite->numframes )
|
||||
{
|
||||
if( frame > psprite->numframes )
|
||||
Con_Printf( S_WARN "%s: no such frame %d (%s)\n", __func__, frame, pModel->name );
|
||||
frame = psprite->numframes - 1;
|
||||
}
|
||||
|
||||
if( psprite->frames[frame].type == SPR_SINGLE )
|
||||
{
|
||||
pspriteframe = psprite->frames[frame].frameptr;
|
||||
}
|
||||
else if( psprite->frames[frame].type == SPR_GROUP )
|
||||
{
|
||||
pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr;
|
||||
pintervals = pspritegroup->intervals;
|
||||
numframes = pspritegroup->numframes;
|
||||
fullinterval = pintervals[numframes - 1];
|
||||
|
||||
// when loading in Mod_LoadSpriteGroup, we guaranteed all interval values
|
||||
// are positive, so we don't have to worry about division by zero
|
||||
targettime = cl.time - ((int)( cl.time / fullinterval )) * fullinterval;
|
||||
|
||||
for( i = 0; i < ( numframes - 1 ); i++ )
|
||||
{
|
||||
if( pintervals[i] > targettime )
|
||||
break;
|
||||
}
|
||||
pspriteframe = pspritegroup->frames[i];
|
||||
}
|
||||
else if( psprite->frames[frame].type == FRAME_ANGLED )
|
||||
{
|
||||
int angleframe = (int)( Q_rint(( refState.viewangles[1] - yaw + 45.0f ) / 360 * 8 ) - 4 ) & 7;
|
||||
|
||||
// e.g. doom-style sprite monsters
|
||||
pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr;
|
||||
pspriteframe = pspritegroup->frames[angleframe];
|
||||
}
|
||||
|
||||
return pspriteframe;
|
||||
}
|
||||
|
||||
void R_GetSpriteParms( int *frameWidth, int *frameHeight, int *numFrames, int currentFrame, const model_t *pSprite )
|
||||
{
|
||||
mspriteframe_t *pFrame;
|
||||
|
||||
if( !pSprite || pSprite->type != mod_sprite )
|
||||
return;
|
||||
|
||||
pFrame = R_GetSpriteFrame( pSprite, currentFrame, 0.0f );
|
||||
|
||||
if( frameWidth )
|
||||
*frameWidth = pFrame->width;
|
||||
if( frameHeight )
|
||||
*frameHeight = pFrame->height;
|
||||
if( numFrames )
|
||||
*numFrames = pSprite->numframes;
|
||||
}
|
||||
|
||||
int R_GetSpriteTexture( const model_t *m_pSpriteModel, int frame )
|
||||
{
|
||||
if( !m_pSpriteModel || m_pSpriteModel->type != mod_sprite || !m_pSpriteModel->cache.data )
|
||||
return 0;
|
||||
|
||||
return R_GetSpriteFrame( m_pSpriteModel, frame, 0.0f )->gl_texturenum;
|
||||
}
|
||||
|
||||
static void Mod_SpriteTextureReplacementReport( const char *modelname, int gl_texturenum, const char *foundpath )
|
||||
{
|
||||
if( host_allow_materials.value != 2.0f )
|
||||
return;
|
||||
|
||||
if( gl_texturenum > 0 )
|
||||
Con_Printf( "Looking for %s tex replacement..." S_GREEN "OK (%s)\n", modelname, foundpath );
|
||||
else if( gl_texturenum < 0 )
|
||||
Con_Printf( "Looking for %s tex replacement..." S_YELLOW "MISS (%s)\n", modelname, foundpath );
|
||||
else
|
||||
Con_Printf( "Looking for %s tex replacement..." S_RED "FAIL (%s)\n", modelname, foundpath );
|
||||
}
|
||||
|
||||
static qboolean Mod_SpriteSearchForTextureReplacement( char *out, size_t size, const char *modelname, const char *fmt, ... )
|
||||
{
|
||||
va_list ap;
|
||||
int ret;
|
||||
|
||||
va_start( ap, fmt );
|
||||
ret = Q_vsnprintf( out, size, fmt, ap );
|
||||
va_end( ap );
|
||||
|
||||
if( ret < 0 )
|
||||
{
|
||||
Mod_SpriteTextureReplacementReport( modelname, -1, "overflow" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( FS_FileExists( out, false ))
|
||||
return true;
|
||||
|
||||
Mod_SpriteTextureReplacementReport( modelname, -1, out );
|
||||
return false;
|
||||
}
|
||||
|
||||
static const byte *Mod_SpriteLoadFrame( model_t *mod, const void *pin, mspriteframe_t **ppframe, int num )
|
||||
{
|
||||
dspriteframe_t pinframe;
|
||||
mspriteframe_t *pspriteframe;
|
||||
int gl_texturenum = 0;
|
||||
char texname[128];
|
||||
int bytes = 1;
|
||||
|
||||
memcpy( &pinframe, pin, sizeof( dspriteframe_t ));
|
||||
|
||||
if( sprite_version == SPRITE_VERSION_32 )
|
||||
bytes = 4;
|
||||
|
||||
// build unique frame name
|
||||
if( FBitSet( mod->flags, MODEL_CLIENT )) // it's a HUD sprite
|
||||
{
|
||||
Q_snprintf( texname, sizeof( texname ), "#HUD/%s(%s:%i%i).spr", sprite_name, group_suffix, num / 10, num % 10 );
|
||||
gl_texturenum = ref.dllFuncs.GL_LoadTexture( texname, pin, pinframe.width * pinframe.height * bytes, r_texFlags );
|
||||
}
|
||||
else
|
||||
{
|
||||
// partial HD-textures support
|
||||
if( Mod_AllowMaterials( ))
|
||||
{
|
||||
if( Mod_SpriteSearchForTextureReplacement( texname, sizeof( texname ), sprite_name, "materials/%s/%s%i%i.tga", sprite_name, group_suffix, num / 10, num % 10 ))
|
||||
{
|
||||
gl_texturenum = ref.dllFuncs.GL_LoadTexture( texname, NULL, 0, r_texFlags );
|
||||
Mod_SpriteTextureReplacementReport( sprite_name, gl_texturenum, texname );
|
||||
}
|
||||
}
|
||||
|
||||
if( gl_texturenum == 0 )
|
||||
{
|
||||
Q_snprintf( texname, sizeof( texname ), "#%s(%s:%i%i).spr", sprite_name, group_suffix, num / 10, num % 10 );
|
||||
gl_texturenum = ref.dllFuncs.GL_LoadTexture( texname, pin, pinframe.width * pinframe.height * bytes, r_texFlags );
|
||||
}
|
||||
}
|
||||
|
||||
// setup frame description
|
||||
pspriteframe = Mem_Malloc( mod->mempool, sizeof( mspriteframe_t ));
|
||||
pspriteframe->width = pinframe.width;
|
||||
pspriteframe->height = pinframe.height;
|
||||
pspriteframe->up = pinframe.origin[1];
|
||||
pspriteframe->left = pinframe.origin[0];
|
||||
pspriteframe->down = pinframe.origin[1] - pinframe.height;
|
||||
pspriteframe->right = pinframe.width + pinframe.origin[0];
|
||||
pspriteframe->gl_texturenum = gl_texturenum;
|
||||
*ppframe = pspriteframe;
|
||||
|
||||
return (const byte *)pin + sizeof( dspriteframe_t ) + pinframe.width * pinframe.height * bytes;
|
||||
}
|
||||
|
||||
static const byte *Mod_SpriteLoadGroup( model_t *mod, const void *pin, mspriteframe_t **ppframe, int framenum )
|
||||
{
|
||||
const dspritegroup_t *pingroup;
|
||||
mspritegroup_t *pspritegroup;
|
||||
const dspriteinterval_t *pin_intervals;
|
||||
float *poutintervals;
|
||||
int i, groupsize, numframes;
|
||||
const void *ptemp;
|
||||
|
||||
pingroup = (const dspritegroup_t *)pin;
|
||||
numframes = pingroup->numframes;
|
||||
|
||||
groupsize = sizeof( mspritegroup_t ) + ( numframes - 1 ) * sizeof( pspritegroup->frames[0] );
|
||||
pspritegroup = Mem_Calloc( mod->mempool, groupsize );
|
||||
pspritegroup->numframes = numframes;
|
||||
|
||||
*ppframe = (mspriteframe_t *)pspritegroup;
|
||||
pin_intervals = (const dspriteinterval_t *)( pingroup + 1 );
|
||||
poutintervals = Mem_Calloc( mod->mempool, numframes * sizeof( float ));
|
||||
pspritegroup->intervals = poutintervals;
|
||||
|
||||
for( i = 0; i < numframes; i++ )
|
||||
{
|
||||
*poutintervals = pin_intervals->interval;
|
||||
if( *poutintervals <= 0.0f )
|
||||
*poutintervals = 1.0f; // set error value
|
||||
poutintervals++;
|
||||
pin_intervals++;
|
||||
}
|
||||
|
||||
ptemp = (const void *)pin_intervals;
|
||||
for( i = 0; i < numframes; i++ )
|
||||
{
|
||||
ptemp = Mod_SpriteLoadFrame( mod, ptemp, &pspritegroup->frames[i], framenum * 10 + i );
|
||||
}
|
||||
|
||||
return ptemp;
|
||||
}
|
||||
|
||||
void Mod_SpriteLoadTextures( model_t *mod, const void *buffer )
|
||||
{
|
||||
const dsprite_t *pin = buffer;
|
||||
const short *numi = NULL;
|
||||
const byte *pframetype;
|
||||
msprite_t *psprite = mod->cache.data;
|
||||
int i;
|
||||
|
||||
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 ));
|
||||
|
||||
r_texFlags = mod->numtexinfo;
|
||||
sprite_version = pin->version;
|
||||
Q_strncpy( sprite_name, mod->name, sizeof( sprite_name ));
|
||||
COM_StripExtension( sprite_name );
|
||||
|
||||
if( numi == NULL )
|
||||
{
|
||||
rgbdata_t *pal;
|
||||
|
||||
pal = FS_LoadImage( "#id.pal", (byte *)&i, 768 );
|
||||
pframetype = (const byte *)buffer + sizeof( dsprite_q1_t );
|
||||
FS_FreeImage( pal );
|
||||
}
|
||||
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 = FS_LoadImage( "#gradient.pal", src, pal_bytes );
|
||||
break;
|
||||
case SPR_ALPHTEST:
|
||||
pal = FS_LoadImage( "#masked.pal", src, pal_bytes );
|
||||
break;
|
||||
default:
|
||||
pal = FS_LoadImage( "#texgamma.pal", src, pal_bytes );
|
||||
break;
|
||||
}
|
||||
|
||||
pframetype = (const byte *)( src + pal_bytes );
|
||||
FS_FreeImage( pal );
|
||||
}
|
||||
else
|
||||
{
|
||||
Con_DPrintf( S_ERROR "%s has wrong number of palette colors %i (should be less or equal than 256)\n", mod->name, *numi );
|
||||
return;
|
||||
}
|
||||
|
||||
if( mod->numframes < 1 )
|
||||
return;
|
||||
|
||||
for( i = 0; i < mod->numframes; i++ )
|
||||
{
|
||||
frametype_t frametype;
|
||||
dframetype_t dframetype;
|
||||
|
||||
memcpy( &dframetype, pframetype, sizeof( dframetype ));
|
||||
frametype = dframetype.type;
|
||||
psprite->frames[i].type = (spriteframetype_t)frametype;
|
||||
|
||||
switch( frametype )
|
||||
{
|
||||
case FRAME_SINGLE:
|
||||
Q_strncpy( group_suffix, "frame", sizeof( group_suffix ));
|
||||
pframetype = Mod_SpriteLoadFrame( mod, pframetype + sizeof( dframetype_t ), &psprite->frames[i].frameptr, i );
|
||||
break;
|
||||
case FRAME_GROUP:
|
||||
Q_strncpy( group_suffix, "group", sizeof( group_suffix ));
|
||||
pframetype = Mod_SpriteLoadGroup( mod, pframetype + sizeof( dframetype_t ), &psprite->frames[i].frameptr, i );
|
||||
break;
|
||||
case FRAME_ANGLED:
|
||||
Q_strncpy( group_suffix, "angle", sizeof( group_suffix ));
|
||||
pframetype = Mod_SpriteLoadGroup( mod, pframetype + sizeof( dframetype_t ), &psprite->frames[i].frameptr, i );
|
||||
break;
|
||||
}
|
||||
if( pframetype == NULL )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Mod_SpriteUnloadTextures( void *data )
|
||||
{
|
||||
msprite_t *psprite = data;
|
||||
int i;
|
||||
|
||||
if( !data )
|
||||
return;
|
||||
|
||||
// release all textures
|
||||
for( i = 0; i < psprite->numframes; i++ )
|
||||
{
|
||||
if( !psprite->frames[i].frameptr )
|
||||
continue;
|
||||
|
||||
if( psprite->frames[i].type == SPR_SINGLE )
|
||||
{
|
||||
ref.dllFuncs.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( pspritegroup->frames[j] )
|
||||
ref.dllFuncs.GL_FreeTexture( pspritegroup->frames[j]->gl_texturenum );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ AVI PLAYING
|
||||
*/
|
||||
|
||||
static movie_state_t *cin_state;
|
||||
static int cin_texture;
|
||||
|
||||
/*
|
||||
==================
|
||||
@@ -281,6 +282,12 @@ void SCR_InitCinematic( void )
|
||||
{
|
||||
AVI_Initailize ();
|
||||
cin_state = AVI_GetState( CIN_MAIN );
|
||||
cin_texture = ref.dllFuncs.GL_CreateTexture( "*cintexture", 64, 64, NULL, TF_NOMIPMAP|TF_CLAMP );
|
||||
}
|
||||
|
||||
int SCR_GetCinematicTexture( void )
|
||||
{
|
||||
return cin_texture;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -360,6 +360,29 @@ qboolean V_PreRender( void )
|
||||
|
||||
//============================================================================
|
||||
|
||||
/*
|
||||
====================
|
||||
V_ApplyRefUnderwater
|
||||
|
||||
apply underwater fov effect
|
||||
====================
|
||||
*/
|
||||
static void V_ApplyRefUnderwater( ref_viewpass_t *rvp )
|
||||
{
|
||||
if( !FBitSet( rvp->flags, RF_DRAW_CUBEMAP|RF_DRAW_OVERVIEW ))
|
||||
return;
|
||||
|
||||
if( !FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
|
||||
return;
|
||||
|
||||
if( cl.local.waterlevel < 3 )
|
||||
return;
|
||||
|
||||
rvp->fov_x = atan( tan( DEG2RAD( rvp->fov_x ) / 2 ) * ( 0.97f + sin( cl.time * 1.5f ) * 0.03f )) * 2 / (M_PI_F / 180.0f);
|
||||
rvp->fov_y = atan( tan( DEG2RAD( rvp->fov_y ) / 2 ) * ( 1.03f - sin( cl.time * 1.5f ) * 0.03f )) * 2 / (M_PI_F / 180.0f);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
V_RenderView
|
||||
@@ -389,6 +412,7 @@ void V_RenderView( void )
|
||||
clgame.dllFuncs.pfnCalcRefdef( &rp );
|
||||
V_GetRefParams( &rp, &rvp );
|
||||
V_RefApplyOverview( &rvp );
|
||||
V_ApplyRefUnderwater( &rvp );
|
||||
|
||||
if( viewnum == 0 && FBitSet( rvp.flags, RF_ONLY_CLIENTDRAW ))
|
||||
{
|
||||
|
||||
@@ -761,6 +761,7 @@ void CL_AddToResourceList( resource_t *pResource, resource_t *pList );
|
||||
void CL_RemoveFromResourceList( resource_t *pResource );
|
||||
void CL_MoveToOnHandList( resource_t *pResource );
|
||||
void CL_ClearResourceLists( void );
|
||||
void CL_SendResourceList( const resource_t *list, int count );
|
||||
|
||||
//
|
||||
// cl_debug.c
|
||||
@@ -874,7 +875,6 @@ struct msurface_s *pfnTraceSurface( int ground, float *vstart, float *vend );
|
||||
void CL_EnableScissor( scissor_state_t *scissor, int x, int y, int width, int height );
|
||||
void CL_DisableScissor( scissor_state_t *scissor );
|
||||
qboolean CL_Scissor( const scissor_state_t *scissor, float *x, float *y, float *width, float *height, float *u0, float *v0, float *u1, float *v1 );
|
||||
|
||||
static inline cl_entity_t *CL_EDICT_NUM( int index )
|
||||
{
|
||||
if( unlikely( !clgame.entities )) // not in game yet
|
||||
@@ -972,6 +972,13 @@ void SCR_DrawPos( void );
|
||||
void SCR_DrawEnts( void );
|
||||
void SCR_DrawUserCmd( void );
|
||||
|
||||
//
|
||||
// cl_sprite.c
|
||||
//
|
||||
mspriteframe_t *R_GetSpriteFrame( const model_t *pModel, int frame, float yaw );
|
||||
void R_GetSpriteParms( int *frameWidth, int *frameHeight, int *numFrames, int currentFrame, const model_t *pSprite );
|
||||
int R_GetSpriteTexture( const model_t *m_pSpriteModel, int frame );
|
||||
|
||||
//
|
||||
// cl_netgraph.c
|
||||
//
|
||||
@@ -1209,6 +1216,7 @@ void SteamBroker_TerminateGameConnection( void );
|
||||
// cl_video.c
|
||||
//
|
||||
void SCR_InitCinematic( void );
|
||||
int SCR_GetCinematicTexture( void );
|
||||
void SCR_FreeCinematic( void );
|
||||
qboolean SCR_PlayCinematic( const char *name );
|
||||
qboolean SCR_DrawCinematic( void );
|
||||
@@ -1234,7 +1242,6 @@ void Key_EnumCmds_f( void );
|
||||
void Key_SetKeyDest( int key_dest );
|
||||
void Key_EnableTextInput( qboolean enable, qboolean force );
|
||||
int Key_ToUpper( int key );
|
||||
void OSK_Draw( void );
|
||||
qboolean Cmd_GetKeysList( const char *s, char *completedname, int length, qboolean print_suggestions );
|
||||
|
||||
//
|
||||
|
||||
@@ -23,6 +23,8 @@ GNU General Public License for more details.
|
||||
#include "client.h"
|
||||
#include "const.h"
|
||||
#include "triangleapi.h"
|
||||
#include "r_studioint.h"
|
||||
#include "mod_local.h"
|
||||
#include "r_efx.h"
|
||||
#include "demo_api.h"
|
||||
#include "ivoicetweak.h"
|
||||
@@ -374,13 +376,13 @@ static void SPR_DrawGeneric( int frame, float x, float y, float width, float hei
|
||||
int w, h;
|
||||
|
||||
// assume we get sizes from image
|
||||
ref.dllFuncs.R_GetSpriteParms( &w, &h, NULL, frame, clgame.ds.pSprite );
|
||||
R_GetSpriteParms( &w, &h, NULL, frame, clgame.ds.pSprite );
|
||||
|
||||
width = w;
|
||||
height = h;
|
||||
}
|
||||
|
||||
texnum = ref.dllFuncs.R_GetSpriteTexture( clgame.ds.pSprite, frame );
|
||||
texnum = R_GetSpriteTexture( clgame.ds.pSprite, frame );
|
||||
|
||||
if( prc )
|
||||
{
|
||||
@@ -1424,7 +1426,7 @@ int EXPORT pfnSPR_Frames( HSPRITE hPic )
|
||||
{
|
||||
int numFrames = 0;
|
||||
|
||||
ref.dllFuncs.R_GetSpriteParms( NULL, NULL, &numFrames, 0, CL_GetSpritePointer( hPic ));
|
||||
R_GetSpriteParms( NULL, NULL, &numFrames, 0, CL_GetSpritePointer( hPic ));
|
||||
|
||||
return numFrames;
|
||||
}
|
||||
@@ -1439,7 +1441,7 @@ static int GAME_EXPORT pfnSPR_Height( HSPRITE hPic, int frame )
|
||||
{
|
||||
int sprHeight = 0;
|
||||
|
||||
ref.dllFuncs.R_GetSpriteParms( NULL, &sprHeight, NULL, frame, CL_GetSpritePointer( hPic ));
|
||||
R_GetSpriteParms( NULL, &sprHeight, NULL, frame, CL_GetSpritePointer( hPic ));
|
||||
|
||||
return sprHeight;
|
||||
}
|
||||
@@ -1454,7 +1456,7 @@ static int GAME_EXPORT pfnSPR_Width( HSPRITE hPic, int frame )
|
||||
{
|
||||
int sprWidth = 0;
|
||||
|
||||
ref.dllFuncs.R_GetSpriteParms( &sprWidth, NULL, NULL, frame, CL_GetSpritePointer( hPic ));
|
||||
R_GetSpriteParms( &sprWidth, NULL, NULL, frame, CL_GetSpritePointer( hPic ));
|
||||
|
||||
return sprWidth;
|
||||
}
|
||||
@@ -2173,7 +2175,7 @@ pfnGetViewModel
|
||||
|
||||
=============
|
||||
*/
|
||||
static cl_entity_t* GAME_EXPORT CL_GetViewModel( void )
|
||||
static cl_entity_t *GAME_EXPORT CL_GetViewModel( void )
|
||||
{
|
||||
return &clgame.viewent;
|
||||
}
|
||||
@@ -3324,7 +3326,7 @@ int TriSpriteTexture( model_t *pSpriteModel, int frame )
|
||||
{
|
||||
int gl_texturenum;
|
||||
|
||||
if(( gl_texturenum = ref.dllFuncs.R_GetSpriteTexture( pSpriteModel, frame )) <= 0 )
|
||||
if(( gl_texturenum = R_GetSpriteTexture( pSpriteModel, frame )) <= 0 )
|
||||
return 0;
|
||||
|
||||
ref.dllFuncs.GL_Bind( XASH_TEXTURE0, gl_texturenum );
|
||||
@@ -3929,6 +3931,69 @@ void CL_UnloadProgs( void )
|
||||
memset( &clgame, 0, sizeof( clgame ));
|
||||
}
|
||||
|
||||
static model_t *pfnStudio_Mod_ForName( const char *name, int crash )
|
||||
{
|
||||
return Mod_ForName( name, crash, false );
|
||||
}
|
||||
|
||||
static void *pfnStudio_Mod_Extradata( model_t *mod )
|
||||
{
|
||||
return Mod_StudioExtradata( mod );
|
||||
}
|
||||
|
||||
static void pfnStudio_GetAliasScale( float *x, float *y )
|
||||
{
|
||||
if( x ) *x = 1.0f;
|
||||
if( y ) *y = 1.0f;
|
||||
}
|
||||
|
||||
static float ***pfnStudio_GetAliasTransform( void )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static model_t *pfnStudio_GetChromeSprite( void )
|
||||
{
|
||||
return cl_sprite_shell;
|
||||
}
|
||||
|
||||
static int pfnStudio_IsHardware( void )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static engine_studio_api_t gStudioAPI =
|
||||
{
|
||||
.Mem_Calloc = Mod_Calloc,
|
||||
.Cache_Check = Mod_CacheCheck,
|
||||
.LoadCacheFile = Mod_LoadCacheFile,
|
||||
.Mod_ForName = pfnStudio_Mod_ForName,
|
||||
.Mod_Extradata = pfnStudio_Mod_Extradata,
|
||||
.GetModelByIndex = CL_ModelHandle,
|
||||
.GetCvar = pfnCVarGetPointer,
|
||||
.GetChromeSprite = pfnStudio_GetChromeSprite,
|
||||
.GetAliasScale = pfnStudio_GetAliasScale,
|
||||
.StudioGetAliasTransform = pfnStudio_GetAliasTransform,
|
||||
.GetViewEntity = CL_GetViewModel,
|
||||
.IsHardware = pfnStudio_IsHardware,
|
||||
};
|
||||
|
||||
static void CL_InitStudioAPI( void )
|
||||
{
|
||||
static r_studio_interface_t gDefaultStudioDraw;
|
||||
r_studio_interface_t *pStudioDraw;
|
||||
|
||||
if( !ref.dllFuncs.R_StudioFillAPI( &gStudioAPI, &gDefaultStudioDraw ))
|
||||
return;
|
||||
|
||||
pStudioDraw = &gDefaultStudioDraw;
|
||||
|
||||
if( clgame.dllFuncs.pfnGetStudioModelInterface )
|
||||
clgame.dllFuncs.pfnGetStudioModelInterface( STUDIO_INTERFACE_VERSION, &pStudioDraw, &gStudioAPI );
|
||||
|
||||
ref.dllFuncs.R_StudioSetDrawInterface( pStudioDraw );
|
||||
}
|
||||
|
||||
qboolean CL_LoadProgs( const char *name )
|
||||
{
|
||||
static playermove_t gpMove;
|
||||
@@ -4066,7 +4131,7 @@ qboolean CL_LoadProgs( const char *name )
|
||||
// initialize game
|
||||
clgame.dllFuncs.pfnInit();
|
||||
|
||||
ref.dllFuncs.CL_InitStudioAPI();
|
||||
CL_InitStudioAPI();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -214,6 +214,11 @@ static void pfnAVI_StreamSound( movie_state_t *avi, int entnum, float fvol, floa
|
||||
return; // stub, use AVI_SetParm and AVI_Think to stream AVI sound
|
||||
}
|
||||
|
||||
static void pfnAVI_UploadRawFrame( int texture, int cols, int rows, int width, int height, const byte *data )
|
||||
{
|
||||
ref.dllFuncs.GL_UpdateTexture( texture, cols, rows, width, height, data, PF_BGRA_32 );
|
||||
}
|
||||
|
||||
static render_api_t gRenderAPI =
|
||||
{
|
||||
pfnRenderGetParm, // GL_RenderGetParm,
|
||||
@@ -243,7 +248,7 @@ static render_api_t gRenderAPI =
|
||||
AVI_GetVideoInfo,
|
||||
AVI_GetVideoFrameNumber,
|
||||
AVI_GetVideoFrame,
|
||||
NULL, // R_UploadStretchRaw,
|
||||
pfnAVI_UploadRawFrame, // AVI_UploadRawFrame
|
||||
AVI_FreeVideo,
|
||||
AVI_IsActive,
|
||||
pfnAVI_StreamSound,
|
||||
@@ -283,40 +288,6 @@ static render_api_t gRenderAPI =
|
||||
COM_SetRandomSeed,
|
||||
};
|
||||
|
||||
static void R_FillRenderAPIFromRef( render_api_t *to, const ref_interface_t *from )
|
||||
{
|
||||
to->GetDetailScaleForTexture = from->GetDetailScaleForTexture;
|
||||
to->GetExtraParmsForTexture = from->GetExtraParmsForTexture;
|
||||
to->GetFrameTime = from->GetFrameTime;
|
||||
to->R_SetCurrentEntity = from->R_SetCurrentEntity;
|
||||
to->R_SetCurrentModel = from->R_SetCurrentModel;
|
||||
to->GL_FindTexture = from->GL_FindTexture;
|
||||
to->GL_TextureName = from->GL_TextureName;
|
||||
to->GL_TextureData = from->GL_TextureData;
|
||||
to->GL_LoadTexture = from->GL_LoadTexture;
|
||||
to->GL_CreateTexture = from->GL_CreateTexture;
|
||||
to->GL_LoadTextureArray = from->GL_LoadTextureArray;
|
||||
to->GL_CreateTextureArray = from->GL_CreateTextureArray;
|
||||
to->GL_FreeTexture = from->GL_FreeTexture;
|
||||
to->DrawSingleDecal = from->DrawSingleDecal;
|
||||
to->R_DecalSetupVerts = from->R_DecalSetupVerts;
|
||||
to->R_EntityRemoveDecals = from->R_EntityRemoveDecals;
|
||||
to->AVI_UploadRawFrame = from->AVI_UploadRawFrame;
|
||||
to->GL_Bind = from->GL_Bind;
|
||||
to->GL_SelectTexture = from->GL_SelectTexture;
|
||||
to->GL_LoadTextureMatrix = from->GL_LoadTextureMatrix;
|
||||
to->GL_TexMatrixIdentity = from->GL_TexMatrixIdentity;
|
||||
to->GL_CleanUpTextureUnits = from->GL_CleanUpTextureUnits;
|
||||
to->GL_TexGen = from->GL_TexGen;
|
||||
to->GL_TextureTarget = from->GL_TextureTarget;
|
||||
to->GL_TexCoordArrayMode = from->GL_TexCoordArrayMode;
|
||||
to->GL_UpdateTexSize = from->GL_UpdateTexSize;
|
||||
to->GL_DrawParticles = from->GL_DrawParticles;
|
||||
to->LightVec = from->LightVec;
|
||||
to->StudioGetTexture = from->StudioGetTexture;
|
||||
to->GL_GetProcAddress = from->R_GetProcAddress;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
R_InitRenderAPI
|
||||
@@ -329,8 +300,15 @@ qboolean R_InitRenderAPI( void )
|
||||
// make sure what render functions is cleared
|
||||
memset( &clgame.drawFuncs, 0, sizeof( clgame.drawFuncs ));
|
||||
|
||||
// fill missing functions from renderer
|
||||
R_FillRenderAPIFromRef( &gRenderAPI, &ref.dllFuncs );
|
||||
gRenderAPI.GetDetailScaleForTexture = ref.dllFuncs.R_GetDetailScaleForTexture;
|
||||
gRenderAPI.GL_FindTexture = ref.dllFuncs.GL_FindTexture;
|
||||
gRenderAPI.GL_TextureName = ref.dllFuncs.GL_TextureName;
|
||||
gRenderAPI.GL_TextureData = ref.dllFuncs.GL_TextureData;
|
||||
gRenderAPI.GL_LoadTexture = ref.dllFuncs.GL_LoadTexture;
|
||||
gRenderAPI.GL_FreeTexture = ref.dllFuncs.GL_FreeTexture;
|
||||
gRenderAPI.GL_Bind = ref.dllFuncs.GL_Bind;
|
||||
|
||||
ref.dllFuncs.R_FillRenderAPI( &gRenderAPI );
|
||||
|
||||
if( clgame.dllFuncs.pfnGetRenderInterface )
|
||||
{
|
||||
@@ -287,13 +287,6 @@ static entity_state_t *R_StudioGetPlayerState( int index )
|
||||
return &cl.frames[cl.parsecountmod].playerstate[index];
|
||||
}
|
||||
|
||||
static int pfnGetStudioModelInterface( int version, struct r_studio_interface_s **ppinterface, struct engine_studio_api_s *pstudio )
|
||||
{
|
||||
return clgame.dllFuncs.pfnGetStudioModelInterface ?
|
||||
clgame.dllFuncs.pfnGetStudioModelInterface( version, ppinterface, pstudio ) :
|
||||
0;
|
||||
}
|
||||
|
||||
static const bpc_desc_t *pfnImage_GetPFDesc( int idx )
|
||||
{
|
||||
return &PFDesc[idx];
|
||||
@@ -329,11 +322,6 @@ static qboolean R_Init_Video_( ref_graphic_apis_t type )
|
||||
return R_Init_Video( type );
|
||||
}
|
||||
|
||||
static mleaf_t *pfnMod_PointInLeaf( const vec3_t p, mnode_t *node )
|
||||
{
|
||||
// FIXME: get rid of this on next RefAPI update
|
||||
return Mod_PointInLeaf( p, node, cl.models[1] );
|
||||
}
|
||||
|
||||
static const ref_api_t gEngfuncs =
|
||||
{
|
||||
@@ -375,7 +363,7 @@ static const ref_api_t gEngfuncs =
|
||||
|
||||
Mod_SampleSizeForFace,
|
||||
Mod_BoxVisible,
|
||||
pfnMod_PointInLeaf,
|
||||
Mod_PointInLeaf,
|
||||
R_DrawWorldHull,
|
||||
R_DrawModelHull,
|
||||
|
||||
@@ -411,7 +399,6 @@ static const ref_api_t gEngfuncs =
|
||||
Mod_CacheCheck,
|
||||
Mod_LoadCacheFile,
|
||||
Mod_Calloc,
|
||||
pfnGetStudioModelInterface,
|
||||
|
||||
_Mem_AllocPool,
|
||||
_Mem_FreePool,
|
||||
@@ -465,6 +452,7 @@ static const ref_api_t gEngfuncs =
|
||||
&g_fsapi,
|
||||
|
||||
R_GetWindowHandle,
|
||||
R_GetSpriteFrame,
|
||||
};
|
||||
|
||||
static void R_UnloadProgs( void )
|
||||
@@ -487,28 +475,78 @@ static void R_UnloadProgs( void )
|
||||
memset( &ref.dllFuncs, 0, sizeof( ref.dllFuncs ));
|
||||
}
|
||||
|
||||
static void CL_FillTriAPIFromRef( triangleapi_t *dst, const ref_interface_t *src )
|
||||
static void CL_FillTriAPI( triangleapi_t *dst )
|
||||
{
|
||||
dst->version = TRI_API_VERSION;
|
||||
dst->Begin = src->Begin;
|
||||
dst->RenderMode = TriRenderMode;
|
||||
dst->End = src->End;
|
||||
dst->Color4f = TriColor4f;
|
||||
dst->Color4ub = TriColor4ub;
|
||||
dst->TexCoord2f = src->TexCoord2f;
|
||||
dst->Vertex3f = src->Vertex3f;
|
||||
dst->Vertex3fv = src->Vertex3fv;
|
||||
dst->Brightness = TriBrightness;
|
||||
dst->CullFace = TriCullFace;
|
||||
dst->SpriteTexture = TriSpriteTexture;
|
||||
dst->WorldToScreen = TriWorldToScreen;
|
||||
dst->Fog = src->Fog;
|
||||
dst->ScreenToWorld = src->ScreenToWorld;
|
||||
dst->GetMatrix = src->GetMatrix;
|
||||
dst->BoxInPVS = TriBoxInPVS;
|
||||
dst->LightAtPoint = TriLightAtPoint;
|
||||
dst->Color4fRendermode = TriColor4fRendermode;
|
||||
dst->FogParams = src->FogParams;
|
||||
dst->Begin = ref.dllFuncs.Begin;
|
||||
dst->End = ref.dllFuncs.End;
|
||||
dst->Vertex3f = ref.dllFuncs.Vertex3f;
|
||||
dst->Vertex3fv = ref.dllFuncs.Vertex3fv;
|
||||
|
||||
ref.dllFuncs.R_FillTriAPI( dst );
|
||||
}
|
||||
|
||||
static void R_CreateBuiltinTextures( void )
|
||||
{
|
||||
// default checkerboard
|
||||
uint data16x16[256];
|
||||
for( int y = 0; y < 16; y++ )
|
||||
{
|
||||
for( int x = 0; x < 16; x++ )
|
||||
{
|
||||
if(( y < 8 ) ^ ( x < 8 ))
|
||||
data16x16[y * 16 + x] = HostFourCC( 255, 0, 255, 255 );
|
||||
else
|
||||
data16x16[y * 16 + x] = HostFourCC( 0, 0, 0, 255 );
|
||||
}
|
||||
}
|
||||
ref.dllFuncs.GL_CreateTexture( REF_DEFAULT_TEXTURE, 16, 16, data16x16, 0 );
|
||||
|
||||
// particle texture
|
||||
uint particle[64];
|
||||
for( int y = 0; y < 8; y++ )
|
||||
{
|
||||
for( int x = 0; x < 8; x++ )
|
||||
particle[y * 8 + x] = HostFourCC( 255, 255, 255, 0 ); // fill it with invisible white
|
||||
}
|
||||
|
||||
// a1ba: moved one pixel down and to the right to make it look better with linear interpolation
|
||||
// set to 0 to make it look like in goldsrc
|
||||
const int corner = 1;
|
||||
for( int y = corner; y < 4 + corner; y++ )
|
||||
{
|
||||
for( int x = corner; x < 4 + corner; x++ )
|
||||
{
|
||||
if(( x == corner || x == 3 + corner ) && ( y == corner || y == 3 + corner ))
|
||||
continue;
|
||||
|
||||
particle[y * 8 + x] = HostFourCC( 255, 255, 255, 255 );
|
||||
}
|
||||
}
|
||||
ref.dllFuncs.GL_CreateTexture( REF_PARTICLE_TEXTURE, 8, 8, particle, TF_CLAMP|TF_HAS_ALPHA );
|
||||
|
||||
// solid colors
|
||||
uint data4x4[16];
|
||||
memset( data4x4, 0xFF, sizeof( data4x4 ));
|
||||
ref.dllFuncs.GL_CreateTexture( REF_WHITE_TEXTURE, 4, 4, data4x4, 0 );
|
||||
|
||||
for( int x = 0; x < 16; x++ )
|
||||
data4x4[x] = HostFourCC( 127, 127, 127, 255 );
|
||||
ref.dllFuncs.GL_CreateTexture( REF_GRAY_TEXTURE, 4, 4, data4x4, 0 );
|
||||
|
||||
for( int x = 0; x < 16; x++ )
|
||||
data4x4[x] = HostFourCC( 0, 0, 0, 255 );
|
||||
ref.dllFuncs.GL_CreateTexture( REF_BLACK_TEXTURE, 4, 4, data4x4, 0 );
|
||||
}
|
||||
|
||||
static qboolean R_LoadProgs( const char *name )
|
||||
@@ -554,8 +592,8 @@ static qboolean R_LoadProgs( const char *name )
|
||||
Cvar_FullSet( "host_refloaded", "1", FCVAR_READ_ONLY );
|
||||
ref.initialized = true;
|
||||
|
||||
// initialize TriAPI callbacks
|
||||
CL_FillTriAPIFromRef( &gTriApi, &ref.dllFuncs );
|
||||
R_CreateBuiltinTextures();
|
||||
CL_FillTriAPI( &gTriApi );
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -39,6 +39,10 @@ void IN_DeactivateMouse( void );
|
||||
void IN_MouseSavePos( void );
|
||||
void IN_MouseRestorePos( void );
|
||||
void IN_ToggleClientMouse( int newstate, int oldstate );
|
||||
void IN_GyroInit( void );
|
||||
void IN_GyroCheckAvailability( void );
|
||||
void IN_GyroEvent( vec3_t data );
|
||||
void IN_GyroFinalizeMove( float *fw, float *side, float *dpitch, float *dyaw );
|
||||
|
||||
uint IN_CollectInputDevices( void );
|
||||
void IN_LockInputDevices( qboolean lock );
|
||||
@@ -95,6 +99,15 @@ qboolean Touch_WantVisibleCursor( void );
|
||||
void Touch_NotifyResize( void );
|
||||
#endif
|
||||
|
||||
//
|
||||
// in_osk.c
|
||||
//
|
||||
extern convar_t osk_enable;
|
||||
void OSK_Init( void );
|
||||
qboolean OSK_KeyEvent( int key, int down );
|
||||
void OSK_EnableTextInput( qboolean enable, qboolean force );
|
||||
void OSK_Draw( void );
|
||||
|
||||
//
|
||||
// in_joy.c
|
||||
//
|
||||
|
||||
120
engine/client/input/in_gyro.c
Normal file
120
engine/client/input/in_gyro.c
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
in_gyro.c - System gyroscope input code
|
||||
Copyright (C) 2026 Xash3D FWGS contributors
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "input.h"
|
||||
#include "client.h"
|
||||
|
||||
static CVAR_DEFINE_AUTO( gyro_enable, "0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "enables aiming with built-in device gyroscope" );
|
||||
static CVAR_DEFINE_AUTO( gyro_available, "0", FCVAR_READ_ONLY, "tells whether system gyroscope hardware is available or not" );
|
||||
static CVAR_DEFINE_AUTO( gyro_pitch, "1.0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "built-in gyroscope sensitivity for looking up and down" );
|
||||
static CVAR_DEFINE_AUTO( gyro_yaw, "1.0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "built-in gyroscope sensitivity for turning left and right" );
|
||||
static CVAR_DEFINE_AUTO( gyro_roll, "0.0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "built-in gyroscope sensitivity when tilting the device sideways" );
|
||||
static CVAR_DEFINE_AUTO( gyro_pitch_deadzone, "0.5", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "built-in gyroscope pitch axis deadzone (deg/s)" );
|
||||
static CVAR_DEFINE_AUTO( gyro_yaw_deadzone, "0.5", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "built-in gyroscope yaw axis deadzone (deg/s)" );
|
||||
static CVAR_DEFINE_AUTO( gyro_roll_deadzone, "0.5", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "built-in gyroscope roll axis deadzone (deg/s)" );
|
||||
|
||||
// stores the latest instantaneous rotation rates from built-in gyroscope
|
||||
static vec3_t gyro_speed;
|
||||
|
||||
/*
|
||||
==============
|
||||
IN_GyroInit
|
||||
|
||||
==============
|
||||
*/
|
||||
void IN_GyroInit( void )
|
||||
{
|
||||
Cvar_RegisterVariable( &gyro_enable );
|
||||
Cvar_RegisterVariable( &gyro_available );
|
||||
Cvar_RegisterVariable( &gyro_pitch );
|
||||
Cvar_RegisterVariable( &gyro_yaw );
|
||||
Cvar_RegisterVariable( &gyro_roll );
|
||||
Cvar_RegisterVariable( &gyro_pitch_deadzone );
|
||||
Cvar_RegisterVariable( &gyro_yaw_deadzone );
|
||||
Cvar_RegisterVariable( &gyro_roll_deadzone );
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
IN_GyroCheckAvailability
|
||||
|
||||
One-time late check called after startup and configs
|
||||
==============
|
||||
*/
|
||||
void IN_GyroCheckAvailability( void )
|
||||
{
|
||||
#if XASH_SDL
|
||||
if( gyro_available.value )
|
||||
return;
|
||||
|
||||
if( SDLash_GyroIsAvailable() )
|
||||
{
|
||||
Cvar_FullSet( "gyro_available", "1", FCVAR_READ_ONLY );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
IN_GyroEvent
|
||||
|
||||
System gyroscope events from platform
|
||||
=============
|
||||
*/
|
||||
void IN_GyroEvent( vec3_t data )
|
||||
{
|
||||
VectorCopy( data, gyro_speed );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
IN_GyroFinalizeMove
|
||||
|
||||
Apply gyro movement to view angles
|
||||
=============
|
||||
*/
|
||||
void IN_GyroFinalizeMove( float *fw, float *side, float *dpitch, float *dyaw )
|
||||
{
|
||||
platform_orientation_t orient;
|
||||
float orient_scale = 1.0f;
|
||||
|
||||
if( !gyro_enable.value || !gyro_available.value )
|
||||
return;
|
||||
|
||||
orient = Platform_GetDisplayOrientation();
|
||||
if( orient == ORIENTATION_LANDSCAPE_FLIPPED )
|
||||
orient_scale = -1.0f;
|
||||
|
||||
// In Landscape mode axes are swapped relative to natural (Portrait) orientation
|
||||
// Y axis rotation becomes Pitch (up/down)
|
||||
// X axis rotation becomes Yaw (left/right)
|
||||
float pitch_speed = -orient_scale * gyro_speed[1] * ( 180.0f / M_PI );
|
||||
float yaw_speed = orient_scale * gyro_speed[0] * ( 180.0f / M_PI );
|
||||
float roll_speed = orient_scale * gyro_speed[2] * ( 180.0f / M_PI );
|
||||
|
||||
if( fabs( pitch_speed ) < gyro_pitch_deadzone.value )
|
||||
pitch_speed = 0.0f;
|
||||
if( fabs( yaw_speed ) < gyro_yaw_deadzone.value )
|
||||
yaw_speed = 0.0f;
|
||||
if( fabs( roll_speed ) < gyro_roll_deadzone.value )
|
||||
roll_speed = 0.0f;
|
||||
|
||||
*dpitch -= gyro_pitch.value * pitch_speed * host.realframetime;
|
||||
*dyaw += gyro_yaw.value * yaw_speed * host.realframetime;
|
||||
*dyaw += gyro_roll.value * roll_speed * host.realframetime;
|
||||
|
||||
VectorClear( gyro_speed );
|
||||
}
|
||||
@@ -68,6 +68,7 @@ static CVAR_DEFINE_AUTO( joy_gyro_roll, "0.0", FCVAR_ARCHIVE | FCVAR_FILTERABLE,
|
||||
static CVAR_DEFINE_AUTO( joy_gyro_pitch_deadzone, "0.5", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "gyroscope pitch axis deadzone (deg/s)" );
|
||||
static CVAR_DEFINE_AUTO( joy_gyro_yaw_deadzone, "0.5", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "gyroscope yaw axis deadzone (deg/s)" );
|
||||
static CVAR_DEFINE_AUTO( joy_gyro_roll_deadzone, "0.5", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "gyroscope roll axis deadzone (deg/s)" );
|
||||
static CVAR_DEFINE_AUTO( joy_gyro_enable, "1", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "enables aiming with gamepad gyroscope" );
|
||||
static CVAR_DEFINE_AUTO( joy_debug, "0", 0, "visualize gamepad axes and buttons" );
|
||||
|
||||
// stores the latest instantaneous gyroscope rotation rates (in rad/s) from platform input
|
||||
@@ -197,7 +198,7 @@ static int Joy_GetHatValueForAxis( const engineAxis_t engineAxis )
|
||||
positive = JOY_HAT_RIGHT;
|
||||
break;
|
||||
case JOY_AXIS_FWD:
|
||||
threshold = joy_side_key_threshold.value;
|
||||
threshold = joy_forward_key_threshold.value;
|
||||
negative = JOY_HAT_UP;
|
||||
positive = JOY_HAT_DOWN;
|
||||
break;
|
||||
@@ -318,7 +319,7 @@ void Joy_FinalizeMove( float *fw, float *side, float *dpitch, float *dyaw )
|
||||
const char *bind = joy_axis_binding.string;
|
||||
size_t i;
|
||||
|
||||
for( i = 0; bind[i]; i++ )
|
||||
for( i = 0; bind[i] && i < MAX_AXES; i++ )
|
||||
{
|
||||
switch( bind[i] )
|
||||
{
|
||||
@@ -340,7 +341,7 @@ void Joy_FinalizeMove( float *fw, float *side, float *dpitch, float *dyaw )
|
||||
*dpitch += joy_pitch.value * (float)joyaxis[JOY_AXIS_PITCH].val/(float)SHRT_MAX * host.realframetime;
|
||||
*dyaw -= joy_yaw.value * (float)joyaxis[JOY_AXIS_YAW ].val/(float)SHRT_MAX * host.realframetime;
|
||||
|
||||
if( joy_have_gyro.value && (int)joy_calibrated.value == JOY_CALIBRATED )
|
||||
if( joy_gyro_enable.value && joy_have_gyro.value && (int)joy_calibrated.value == JOY_CALIBRATED )
|
||||
{
|
||||
float pitch_speed = joy_gyro_speed[0] * ( 180.0f / M_PI );
|
||||
float yaw_speed = joy_gyro_speed[1] * ( 180.0f / M_PI );
|
||||
@@ -596,6 +597,7 @@ void Joy_Init( void )
|
||||
Cvar_RegisterVariable( &joy_have_gyro );
|
||||
Cvar_RegisterVariable( &joy_calibrated );
|
||||
Cvar_RegisterVariable( &joy_enable );
|
||||
Cvar_RegisterVariable( &joy_gyro_enable );
|
||||
|
||||
Cvar_RegisterVariable( &joy_gyro_pitch );
|
||||
Cvar_RegisterVariable( &joy_gyro_yaw );
|
||||
@@ -158,9 +158,6 @@ static const keyname_t keynames[] =
|
||||
{ "INTERNATIONAL9", K_INTERNATIONAL + 8, "" },
|
||||
};
|
||||
|
||||
static void OSK_EnableTextInput( qboolean enable, qboolean force );
|
||||
static qboolean OSK_KeyEvent( int key, int down );
|
||||
static CVAR_DEFINE_AUTO( osk_enable, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "enable built-in on-screen keyboard" );
|
||||
static CVAR_DEFINE_AUTO( key_rotate, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "rotate arrow keys (0-3)" );
|
||||
|
||||
/*
|
||||
@@ -200,7 +197,14 @@ static int Key_StringToKeynum( const char *str )
|
||||
|
||||
// check for hex code
|
||||
if( str[0] == '0' && str[1] == 'x' )
|
||||
return Q_atoi( str );
|
||||
{
|
||||
int key = Q_atoi( str );
|
||||
|
||||
if( key >= ARRAYSIZE( keys ))
|
||||
return -1;
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
// scan for a text match
|
||||
for( i = 0; i < ARRAYSIZE( keynames ); i++ )
|
||||
@@ -520,7 +524,7 @@ qboolean Cmd_GetKeysList( const char *s, char *completedname, int length, qboole
|
||||
const char *keyname = Key_KeynumToString( i );
|
||||
|
||||
if(( *s == '*' ) || !Q_strnicmp( keyname, s, len ))
|
||||
Q_strncpy( keys_strings[numkeys++], keyname, sizeof( keys[0] ));
|
||||
Q_strncpy( keys_strings[numkeys++], keyname, sizeof( keys_strings[0] ));
|
||||
}
|
||||
|
||||
if( !numkeys ) return false;
|
||||
@@ -579,7 +583,6 @@ void Key_Init( void )
|
||||
for( i = 0; i < ARRAYSIZE( keynames ); i++ )
|
||||
Key_SetBinding( keynames[i].keynum, keynames[i].binding );
|
||||
|
||||
Cvar_RegisterVariable( &osk_enable );
|
||||
Cvar_RegisterVariable( &key_rotate );
|
||||
|
||||
}
|
||||
@@ -985,288 +988,3 @@ int Key_ToUpper( int keynum )
|
||||
|
||||
return Q_toupper( keynum );
|
||||
}
|
||||
|
||||
/* On-screen keyboard:
|
||||
*
|
||||
* 4 lines with 13 buttons each
|
||||
* Left trigger == backspace
|
||||
* Right trigger == space
|
||||
* Any button press is button press on keyboard
|
||||
*
|
||||
* Our layout:
|
||||
* 0 1 2 3 4 5 6 7 8 9 10 11 12
|
||||
* +--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
* |` |1 |2 |3 |4 |5 |6 |7 |8 |9 |0 |- |= | 0
|
||||
* +--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
* |q |w |e |r |t |y |u |i |o |p |[ |] |\ | 1
|
||||
* +--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
* |CL|a |s |d |f |g |h |j |k |l |; |' |BS| 2
|
||||
* +--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
* |SH|z |x |c |v |b |n |m |, |. |/ |SP|EN| 3
|
||||
* +--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
*/
|
||||
|
||||
#define MAX_OSK_ROWS 13
|
||||
#define MAX_OSK_LINES 4
|
||||
|
||||
enum
|
||||
{
|
||||
OSK_DEFAULT = 0,
|
||||
OSK_UPPER, // on caps, shift
|
||||
/*
|
||||
OSK_RUSSIAN,
|
||||
OSK_RUSSIAN_UPPER,
|
||||
*/
|
||||
OSK_LAST
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
OSK_TAB = 16,
|
||||
OSK_SHIFT,
|
||||
OSK_BACKSPACE,
|
||||
OSK_ENTER,
|
||||
OSK_SPECKEY_LAST
|
||||
};
|
||||
static const char *osk_keylayout[][4] =
|
||||
{
|
||||
{
|
||||
"`1234567890-=", // 13
|
||||
"qwertyuiop[]\\", // 13
|
||||
"\x10" "asdfghjkl;'" "\x12", // 11 + caps on a left, enter on a right
|
||||
"\x11" "zxcvbnm,./ " "\x13" // 10 + esc on left + shift on a left/right
|
||||
},
|
||||
{
|
||||
"~!@#$%^&*()_+",
|
||||
"QWERTYUIOP{}|",
|
||||
"\x10" "ASDFGHJKL:\"" "\x12",
|
||||
"\x11" "ZXCVBNM<>? " "\x13"
|
||||
}
|
||||
};
|
||||
|
||||
struct osk_s
|
||||
{
|
||||
qboolean enable;
|
||||
int curlayout;
|
||||
qboolean shift;
|
||||
qboolean sending;
|
||||
struct {
|
||||
signed char x;
|
||||
signed char y;
|
||||
char val;
|
||||
} curbutton;
|
||||
} osk;
|
||||
|
||||
static qboolean OSK_KeyEvent( int key, int down )
|
||||
{
|
||||
if( !osk.enable || !osk_enable.value )
|
||||
return false;
|
||||
|
||||
if( osk.sending )
|
||||
{
|
||||
osk.sending = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if( osk.curbutton.val == 0 )
|
||||
{
|
||||
if( key == K_ENTER || key == K_A_BUTTON )
|
||||
{
|
||||
osk.curbutton.val = osk_keylayout[osk.curlayout][osk.curbutton.y][osk.curbutton.x];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
switch ( key )
|
||||
{
|
||||
case K_A_BUTTON:
|
||||
case K_ENTER:
|
||||
switch( osk.curbutton.val )
|
||||
{
|
||||
case OSK_ENTER:
|
||||
osk.sending = true;
|
||||
Key_Event( K_ENTER, down );
|
||||
//osk_enable = false; // TODO: handle multiline
|
||||
break;
|
||||
case OSK_SHIFT:
|
||||
if( !down )
|
||||
break;
|
||||
|
||||
if( osk.curlayout & 1 )
|
||||
osk.curlayout--;
|
||||
else
|
||||
osk.curlayout++;
|
||||
|
||||
osk.shift = true;
|
||||
osk.curbutton.val = osk_keylayout[osk.curlayout][osk.curbutton.y][osk.curbutton.x];
|
||||
break;
|
||||
case OSK_BACKSPACE:
|
||||
Key_Event( K_BACKSPACE, down ); break;
|
||||
case OSK_TAB:
|
||||
Key_Event( K_TAB, down ); break;
|
||||
default:
|
||||
{
|
||||
int ch;
|
||||
|
||||
if( !down )
|
||||
{
|
||||
if( osk.shift && osk.curlayout & 1 )
|
||||
osk.curlayout--;
|
||||
|
||||
osk.shift = false;
|
||||
osk.curbutton.val = osk_keylayout[osk.curlayout][osk.curbutton.y][osk.curbutton.x];
|
||||
break;
|
||||
}
|
||||
|
||||
ch = (byte)osk.curbutton.val;
|
||||
|
||||
// do not pass UTF-8 sequence into the engine, convert it here
|
||||
if( !cls.accept_utf8 )
|
||||
ch = Con_UtfProcessCharForce( ch );
|
||||
|
||||
if( !ch )
|
||||
break;
|
||||
|
||||
CL_CharEvent( ch );
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case K_UPARROW:
|
||||
if( down && --osk.curbutton.y < 0 )
|
||||
{
|
||||
osk.curbutton.y = MAX_OSK_LINES - 1;
|
||||
osk.curbutton.val = 0;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case K_DOWNARROW:
|
||||
if( down && ++osk.curbutton.y >= MAX_OSK_LINES )
|
||||
{
|
||||
osk.curbutton.y = 0;
|
||||
osk.curbutton.val = 0;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case K_LEFTARROW:
|
||||
if( down && --osk.curbutton.x < 0 )
|
||||
osk.curbutton.x = MAX_OSK_ROWS - 1;
|
||||
break;
|
||||
case K_RIGHTARROW:
|
||||
if( down && ++osk.curbutton.x >= MAX_OSK_ROWS )
|
||||
osk.curbutton.x = 0;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
osk.curbutton.val = osk_keylayout[osk.curlayout][osk.curbutton.y][osk.curbutton.x];
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
OSK_EnableTextInput
|
||||
|
||||
Enables built-in IME
|
||||
=============
|
||||
*/
|
||||
static void OSK_EnableTextInput( qboolean enable, qboolean force )
|
||||
{
|
||||
qboolean old = osk.enable;
|
||||
|
||||
osk.enable = enable;
|
||||
|
||||
if( osk.enable && (!old || force) )
|
||||
{
|
||||
osk.curlayout = 0;
|
||||
osk.curbutton.val = osk_keylayout[osk.curlayout][osk.curbutton.y][osk.curbutton.x];
|
||||
}
|
||||
}
|
||||
|
||||
#define X_START 0.1347475f
|
||||
#define Y_START 0.567f
|
||||
#define X_STEP 0.05625
|
||||
#define Y_STEP 0.0825
|
||||
|
||||
/*
|
||||
============
|
||||
Joy_DrawSymbolButton
|
||||
|
||||
Draw button with symbol on it
|
||||
============
|
||||
*/
|
||||
static void OSK_DrawSymbolButton( int symb, float x, float y, float width, float height )
|
||||
{
|
||||
cl_font_t *font = Con_GetCurFont();
|
||||
byte color[] = { 255, 255, 255, 255 };
|
||||
int x1 = x * refState.width,
|
||||
y1 = y * refState.height,
|
||||
w = width * refState.width,
|
||||
h = height * refState.height;
|
||||
|
||||
if( symb == osk.curbutton.val )
|
||||
ref.dllFuncs.FillRGBA( kRenderTransTexture, x1, y1, w, h, 255, 160, 0, 100 );
|
||||
|
||||
if( !symb || symb == ' ' || (symb >= OSK_TAB && symb < OSK_SPECKEY_LAST ) )
|
||||
return;
|
||||
|
||||
CL_DrawCharacter(
|
||||
x1 + width * 0.4 * refState.width,
|
||||
y1 + height * 0.4 * refState.height,
|
||||
symb, color, font, 0 );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
Joy_DrawSpecialButton
|
||||
|
||||
Draw special button, like shift, enter or esc
|
||||
=============
|
||||
*/
|
||||
static void OSK_DrawSpecialButton( const char *name, float x, float y, float width, float height )
|
||||
{
|
||||
byte color[] = { 0, 255, 0, 255 };
|
||||
|
||||
Con_DrawString(
|
||||
x * refState.width + width * 0.4 * refState.width,
|
||||
y * refState.height + height * 0.4 * refState.height,
|
||||
name,
|
||||
color );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
Joy_DrawOnScreenKeyboard
|
||||
|
||||
Draw on screen keyboard, if enabled
|
||||
=============
|
||||
*/
|
||||
void OSK_Draw( void )
|
||||
{
|
||||
const char **curlayout = osk_keylayout[osk.curlayout]; // shortcut :)
|
||||
float x, y;
|
||||
int i, j;
|
||||
|
||||
if( !osk.enable || !osk_enable.value || !osk.curbutton.val )
|
||||
return;
|
||||
|
||||
// draw keyboard
|
||||
ref.dllFuncs.FillRGBA( kRenderTransTexture, X_START * refState.width, Y_START * refState.height,
|
||||
X_STEP * MAX_OSK_ROWS * refState.width,
|
||||
Y_STEP * MAX_OSK_LINES * refState.height, 100, 100, 100, 100 );
|
||||
|
||||
OSK_DrawSpecialButton( "-]", X_START, Y_START + Y_STEP * 2, X_STEP, Y_STEP );
|
||||
OSK_DrawSpecialButton( "<-", X_START + X_STEP * 12, Y_START + Y_STEP * 2, X_STEP, Y_STEP );
|
||||
|
||||
OSK_DrawSpecialButton( "sh", X_START, Y_START + Y_STEP * 3, X_STEP, Y_STEP );
|
||||
OSK_DrawSpecialButton( "en", X_START + X_STEP * 12, Y_START + Y_STEP * 3, X_STEP, Y_STEP );
|
||||
|
||||
for( y = Y_START, j = 0; j < MAX_OSK_LINES; j++, y += Y_STEP )
|
||||
for( x = X_START, i = 0; i < MAX_OSK_ROWS; i++, x += X_STEP )
|
||||
OSK_DrawSymbolButton( curlayout[j][i], x, y, X_STEP, Y_STEP );
|
||||
}
|
||||
312
engine/client/input/in_osk.c
Normal file
312
engine/client/input/in_osk.c
Normal file
@@ -0,0 +1,312 @@
|
||||
/*
|
||||
in_osk.c - on-screen keyboard input
|
||||
Copyright (C) 2016-2026 Alibek Omarov
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "input.h"
|
||||
#include "client.h"
|
||||
|
||||
CVAR_DEFINE_AUTO( osk_enable, "0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "enable built-in on-screen keyboard" );
|
||||
|
||||
/* On-screen keyboard:
|
||||
*
|
||||
* 4 lines with 13 buttons each
|
||||
* Left trigger == backspace
|
||||
* Right trigger == space
|
||||
* Any button press is button press on keyboard
|
||||
*
|
||||
* Our layout:
|
||||
* 0 1 2 3 4 5 6 7 8 9 10 11 12
|
||||
* +--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
* |` |1 |2 |3 |4 |5 |6 |7 |8 |9 |0 |- |= | 0
|
||||
* +--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
* |q |w |e |r |t |y |u |i |o |p |[ |] |\ | 1
|
||||
* +--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
* |CL|a |s |d |f |g |h |j |k |l |; |' |BS| 2
|
||||
* +--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
* |SH|z |x |c |v |b |n |m |, |. |/ |SP|EN| 3
|
||||
* +--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
*/
|
||||
|
||||
#define MAX_OSK_ROWS 13
|
||||
#define MAX_OSK_LINES 4
|
||||
|
||||
enum
|
||||
{
|
||||
OSK_DEFAULT = 0,
|
||||
OSK_UPPER, // on caps, shift
|
||||
/*
|
||||
OSK_RUSSIAN,
|
||||
OSK_RUSSIAN_UPPER,
|
||||
*/
|
||||
OSK_LAST
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
OSK_TAB = 16,
|
||||
OSK_SHIFT,
|
||||
OSK_BACKSPACE,
|
||||
OSK_ENTER,
|
||||
OSK_SPECKEY_LAST
|
||||
};
|
||||
static const char *osk_keylayout[][4] =
|
||||
{
|
||||
{
|
||||
"`1234567890-=", // 13
|
||||
"qwertyuiop[]\\", // 13
|
||||
"\x10" "asdfghjkl;'" "\x12", // 11 + caps on a left, enter on a right
|
||||
"\x11" "zxcvbnm,./ " "\x13" // 10 + esc on left + shift on a left/right
|
||||
},
|
||||
{
|
||||
"~!@#$%^&*()_+",
|
||||
"QWERTYUIOP{}|",
|
||||
"\x10" "ASDFGHJKL:\"" "\x12",
|
||||
"\x11" "ZXCVBNM<>? " "\x13"
|
||||
}
|
||||
};
|
||||
|
||||
static struct osk_s
|
||||
{
|
||||
qboolean enable;
|
||||
int curlayout;
|
||||
qboolean shift;
|
||||
qboolean sending;
|
||||
struct
|
||||
{
|
||||
signed char x;
|
||||
signed char y;
|
||||
char val;
|
||||
} curbutton;
|
||||
} osk;
|
||||
|
||||
qboolean OSK_KeyEvent( int key, int down )
|
||||
{
|
||||
if( !osk.enable || !osk_enable.value )
|
||||
return false;
|
||||
|
||||
if( osk.sending )
|
||||
{
|
||||
osk.sending = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if( osk.curbutton.val == 0 )
|
||||
{
|
||||
if( key == K_ENTER || key == K_A_BUTTON )
|
||||
{
|
||||
osk.curbutton.val = osk_keylayout[osk.curlayout][osk.curbutton.y][osk.curbutton.x];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
switch( key )
|
||||
{
|
||||
case K_A_BUTTON:
|
||||
case K_ENTER:
|
||||
switch( osk.curbutton.val )
|
||||
{
|
||||
case OSK_ENTER:
|
||||
osk.sending = true;
|
||||
Key_Event( K_ENTER, down );
|
||||
// osk_enable = false; // TODO: handle multiline
|
||||
break;
|
||||
case OSK_SHIFT:
|
||||
if( !down )
|
||||
break;
|
||||
|
||||
if( osk.curlayout & 1 )
|
||||
osk.curlayout--;
|
||||
else
|
||||
osk.curlayout++;
|
||||
|
||||
osk.shift = true;
|
||||
osk.curbutton.val = osk_keylayout[osk.curlayout][osk.curbutton.y][osk.curbutton.x];
|
||||
break;
|
||||
case OSK_BACKSPACE:
|
||||
Key_Event( K_BACKSPACE, down );
|
||||
break;
|
||||
case OSK_TAB:
|
||||
Key_Event( K_TAB, down );
|
||||
break;
|
||||
default:
|
||||
{
|
||||
int ch;
|
||||
|
||||
if( !down )
|
||||
{
|
||||
if( osk.shift && osk.curlayout & 1 )
|
||||
osk.curlayout--;
|
||||
|
||||
osk.shift = false;
|
||||
osk.curbutton.val = osk_keylayout[osk.curlayout][osk.curbutton.y][osk.curbutton.x];
|
||||
break;
|
||||
}
|
||||
|
||||
ch = (byte)osk.curbutton.val;
|
||||
|
||||
// do not pass UTF-8 sequence into the engine, convert it here
|
||||
if( !cls.accept_utf8 )
|
||||
ch = Con_UtfProcessCharForce( ch );
|
||||
|
||||
if( !ch )
|
||||
break;
|
||||
|
||||
CL_CharEvent( ch );
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case K_UPARROW:
|
||||
if( down && --osk.curbutton.y < 0 )
|
||||
{
|
||||
osk.curbutton.y = MAX_OSK_LINES - 1;
|
||||
osk.curbutton.val = 0;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case K_DOWNARROW:
|
||||
if( down && ++osk.curbutton.y >= MAX_OSK_LINES )
|
||||
{
|
||||
osk.curbutton.y = 0;
|
||||
osk.curbutton.val = 0;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case K_LEFTARROW:
|
||||
if( down && --osk.curbutton.x < 0 )
|
||||
osk.curbutton.x = MAX_OSK_ROWS - 1;
|
||||
break;
|
||||
case K_RIGHTARROW:
|
||||
if( down && ++osk.curbutton.x >= MAX_OSK_ROWS )
|
||||
osk.curbutton.x = 0;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
osk.curbutton.val = osk_keylayout[osk.curlayout][osk.curbutton.y][osk.curbutton.x];
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
OSK_EnableTextInput
|
||||
|
||||
Enables built-in IME
|
||||
=============
|
||||
*/
|
||||
void OSK_EnableTextInput( qboolean enable, qboolean force )
|
||||
{
|
||||
qboolean old = osk.enable;
|
||||
|
||||
osk.enable = enable;
|
||||
|
||||
if( osk.enable && ( !old || force ))
|
||||
{
|
||||
osk.curlayout = 0;
|
||||
osk.curbutton.val = osk_keylayout[osk.curlayout][osk.curbutton.y][osk.curbutton.x];
|
||||
}
|
||||
}
|
||||
|
||||
#define X_START 0.1347475f
|
||||
#define Y_START 0.567f
|
||||
#define X_STEP 0.05625
|
||||
#define Y_STEP 0.0825
|
||||
|
||||
/*
|
||||
============
|
||||
OSK_DrawSymbolButton
|
||||
|
||||
Draw button with symbol on it
|
||||
============
|
||||
*/
|
||||
static void OSK_DrawSymbolButton( int symb, float x, float y, float width, float height )
|
||||
{
|
||||
cl_font_t *font = Con_GetCurFont();
|
||||
byte color[] = { 255, 255, 255, 255 };
|
||||
int x1 = x * refState.width,
|
||||
y1 = y * refState.height,
|
||||
w = width * refState.width,
|
||||
h = height * refState.height;
|
||||
|
||||
if( symb == osk.curbutton.val )
|
||||
ref.dllFuncs.FillRGBA( kRenderTransTexture, x1, y1, w, h, 255, 160, 0, 100 );
|
||||
|
||||
if( !symb || symb == ' ' || ( symb >= OSK_TAB && symb < OSK_SPECKEY_LAST ))
|
||||
return;
|
||||
|
||||
CL_DrawCharacter(
|
||||
x1 + width * 0.4 * refState.width,
|
||||
y1 + height * 0.4 * refState.height,
|
||||
symb, color, font, 0 );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
OSK_DrawSpecialButton
|
||||
|
||||
Draw special button, like shift, enter or esc
|
||||
=============
|
||||
*/
|
||||
static void OSK_DrawSpecialButton( const char *name, float x, float y, float width, float height )
|
||||
{
|
||||
byte color[] = { 0, 255, 0, 255 };
|
||||
|
||||
Con_DrawString(
|
||||
x * refState.width + width * 0.4 * refState.width,
|
||||
y * refState.height + height * 0.4 * refState.height,
|
||||
name,
|
||||
color );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
OSK_Draw
|
||||
|
||||
Draw on screen keyboard, if enabled
|
||||
=============
|
||||
*/
|
||||
void OSK_Draw( void )
|
||||
{
|
||||
const char **curlayout = osk_keylayout[osk.curlayout]; // shortcut :)
|
||||
float x, y;
|
||||
int i, j;
|
||||
|
||||
if( !osk.enable || !osk_enable.value || !osk.curbutton.val )
|
||||
return;
|
||||
|
||||
// draw keyboard
|
||||
ref.dllFuncs.FillRGBA( kRenderTransTexture, X_START * refState.width, Y_START * refState.height,
|
||||
X_STEP * MAX_OSK_ROWS * refState.width,
|
||||
Y_STEP * MAX_OSK_LINES * refState.height, 100, 100, 100, 100 );
|
||||
|
||||
OSK_DrawSpecialButton( "-]", X_START, Y_START + Y_STEP * 2, X_STEP, Y_STEP );
|
||||
OSK_DrawSpecialButton( "<-", X_START + X_STEP * 12, Y_START + Y_STEP * 2, X_STEP, Y_STEP );
|
||||
|
||||
OSK_DrawSpecialButton( "sh", X_START, Y_START + Y_STEP * 3, X_STEP, Y_STEP );
|
||||
OSK_DrawSpecialButton( "en", X_START + X_STEP * 12, Y_START + Y_STEP * 3, X_STEP, Y_STEP );
|
||||
|
||||
for( y = Y_START, j = 0; j < MAX_OSK_LINES; j++, y += Y_STEP )
|
||||
for( x = X_START, i = 0; i < MAX_OSK_ROWS; i++, x += X_STEP )
|
||||
OSK_DrawSymbolButton( curlayout[j][i], x, y, X_STEP, Y_STEP );
|
||||
}
|
||||
|
||||
void OSK_Init( void )
|
||||
{
|
||||
Cvar_RegisterVariable( &osk_enable );
|
||||
}
|
||||
@@ -185,10 +185,10 @@ void Touch_NotifyResize( void )
|
||||
|
||||
static inline float Touch_AspectRatio( void )
|
||||
{
|
||||
if( touch.config_aspect_ratio )
|
||||
if( touch.config_aspect_ratio >= 0.25f )
|
||||
return touch.config_aspect_ratio;
|
||||
|
||||
if( touch.actual_aspect_ratio )
|
||||
if( touch.actual_aspect_ratio >= 0.25f )
|
||||
return touch.actual_aspect_ratio;
|
||||
|
||||
if( refState.width && refState.height )
|
||||
@@ -369,7 +369,7 @@ static void Touch_ExportConfig_f( void )
|
||||
string profilebase;
|
||||
|
||||
COM_FileBase( name, profilebase, sizeof( profilebase ));
|
||||
Q_snprintf( profilename, sizeof( profilebase ), "touch_profiles/%s (copy).cfg", profilebase );
|
||||
Q_snprintf( profilename, sizeof( profilename ), "touch_profiles/%s (copy).cfg", profilebase );
|
||||
}
|
||||
else Q_strncpy( profilename, name, sizeof( profilename ));
|
||||
|
||||
@@ -588,7 +588,7 @@ static void Touch_RemoveButtonFromList( touchbuttonlist_t *list, const char *nam
|
||||
|
||||
IN_TouchEditClear();
|
||||
|
||||
while(( button = Touch_FindFirst( &touch.list_user, name, privileged )))
|
||||
while(( button = Touch_FindFirst( list, name, privileged )))
|
||||
{
|
||||
if( button->prev )
|
||||
button->prev->next = button->next;
|
||||
@@ -860,8 +860,7 @@ void Touch_AddClientButton( const char *name, const char *texture, const char *c
|
||||
if( !touch.initialized )
|
||||
return;
|
||||
|
||||
if( round )
|
||||
IN_TouchCheckCoords( &x1, &y1, &x2, &y2 );
|
||||
IN_TouchCheckCoords( &x1, &y1, &x2, &y2 );
|
||||
|
||||
if( round == round_aspect )
|
||||
y2 = y1 + ( x2 - x1 ) / (Touch_AspectRatio()) * aspect;
|
||||
@@ -1068,7 +1067,7 @@ static void Touch_InitEditor( void )
|
||||
temp = Touch_AddButton( &touch.list_edit, "close", "touch_default/edit_close", "touch_disableedit", 0, y, x, y + 0.1f, color, true );
|
||||
SetBits( temp->flags, TOUCH_FL_NOEDIT );
|
||||
|
||||
temp = Touch_AddButton( &touch.list_edit, "close", "#Close and save", "", x, y, x + 0.2f, y + 0.1f, color, true );
|
||||
temp = Touch_AddButton( &touch.list_edit, "close_label", "#Close and save", "", x, y, x + 0.2f, y + 0.1f, color, true );
|
||||
SetBits( temp->flags, TOUCH_FL_NOEDIT );
|
||||
|
||||
y += 0.2f;
|
||||
@@ -1076,7 +1075,7 @@ static void Touch_InitEditor( void )
|
||||
temp = Touch_AddButton( &touch.list_edit, "cancel", "touch_default/edit_reset", "touch_reloadconfig", 0, y, x, y + 0.1f, color, true );
|
||||
SetBits( temp->flags, TOUCH_FL_NOEDIT );
|
||||
|
||||
temp = Touch_AddButton( &touch.list_edit, "close", "#Cancel and reset", "", x, y, x + 0.2f, y + 0.1f, color, true );
|
||||
temp = Touch_AddButton( &touch.list_edit, "cancel_label", "#Cancel and reset", "", x, y, x + 0.2f, y + 0.1f, color, true );
|
||||
SetBits( temp->flags, TOUCH_FL_NOEDIT );
|
||||
|
||||
y += 0.2f;
|
||||
@@ -1256,12 +1255,21 @@ static void Touch_DrawTexture( float x1, float y1, float x2, float y2, int textu
|
||||
0, 0, 1, 1, texture );
|
||||
}
|
||||
|
||||
#define GRID_COUNT_X ((int)touch_grid_count.value )
|
||||
#define GRID_COUNT_Y (((int)touch_grid_count.value ) * Touch_AspectRatio( ))
|
||||
#define GRID_X ( 1.0f / GRID_COUNT_X )
|
||||
#define GRID_Y ( 1.0f / Touch_AspectRatio() / GRID_COUNT_X )
|
||||
#define GRID_ROUND_X( x ) ((float)round(( x ) * GRID_COUNT_X ) / GRID_COUNT_X )
|
||||
#define GRID_ROUND_Y( x ) ((float)round(( x ) * GRID_COUNT_Y ) / GRID_COUNT_Y )
|
||||
static inline int Touch_GridCountX( void )
|
||||
{
|
||||
return Q_max((int)touch_grid_count.value, 1 );
|
||||
}
|
||||
|
||||
static inline int Touch_GridCountY( void )
|
||||
{
|
||||
float grid_count_y = touch_grid_count.value * Touch_AspectRatio();
|
||||
return Q_max((int)grid_count_y, 1 );
|
||||
}
|
||||
|
||||
#define GRID_X ( 1.0f / Touch_GridCountX( ))
|
||||
#define GRID_Y ( 1.0f / Touch_GridCountY( ))
|
||||
#define GRID_ROUND_X( x ) ((float)round(( x ) * Touch_GridCountX() ) / Touch_GridCountX())
|
||||
#define GRID_ROUND_Y( x ) ((float)round(( x ) * Touch_GridCountY() ) / Touch_GridCountY())
|
||||
|
||||
static void IN_TouchCheckCoords( float *x1, float *y1, float *x2, float *y2 )
|
||||
{
|
||||
@@ -445,6 +445,10 @@ void IN_Init( void )
|
||||
{
|
||||
IN_StartupMouse( );
|
||||
|
||||
IN_GyroInit();
|
||||
|
||||
OSK_Init();
|
||||
|
||||
Joy_Init(); // common joystick support init
|
||||
|
||||
Touch_Init();
|
||||
@@ -560,6 +564,7 @@ static void IN_CollectInput( float *forward, float *side, float *pitch, float *y
|
||||
#endif
|
||||
}
|
||||
|
||||
IN_GyroFinalizeMove( forward, side, pitch, yaw );
|
||||
Joy_FinalizeMove( forward, side, pitch, yaw );
|
||||
Touch_GetMove( forward, side, pitch, yaw );
|
||||
|
||||
@@ -15,6 +15,7 @@ GNU General Public License for more details.
|
||||
|
||||
#include "common.h"
|
||||
#include "client.h"
|
||||
#include "mod_local.h"
|
||||
#include "net_encode.h"
|
||||
#include "cl_tent.h"
|
||||
#include "shake.h"
|
||||
@@ -704,13 +705,35 @@ CL_ParseResourceRequest
|
||||
|
||||
==================
|
||||
*/
|
||||
static void CL_ParseResourceRequest( sizebuf_t *msg )
|
||||
void CL_SendResourceList( const resource_t *list, int count )
|
||||
{
|
||||
byte buffer[MAX_INIT_MSG];
|
||||
int i, arg, nStartIndex;
|
||||
sizebuf_t sbuf;
|
||||
int i;
|
||||
|
||||
MSG_Init( &sbuf, "ResourceBlock", buffer, sizeof( buffer ));
|
||||
MSG_BeginClientCmd( &sbuf, clc_resourcelist );
|
||||
MSG_WriteShort( &sbuf, count );
|
||||
|
||||
for( i = 0; i < count; i++ )
|
||||
{
|
||||
MSG_WriteString( &sbuf, list[i].szFileName );
|
||||
MSG_WriteByte( &sbuf, list[i].type );
|
||||
MSG_WriteShort( &sbuf, list[i].nIndex );
|
||||
MSG_WriteLong( &sbuf, list[i].nDownloadSize );
|
||||
MSG_WriteByte( &sbuf, list[i].ucFlags );
|
||||
|
||||
if( FBitSet( list[i].ucFlags, RES_CUSTOM ))
|
||||
MSG_WriteBytes( &sbuf, list[i].rgucMD5_hash, 16 );
|
||||
}
|
||||
|
||||
Netchan_CreateFragments( &cls.netchan, &sbuf );
|
||||
Netchan_FragSend( &cls.netchan );
|
||||
}
|
||||
|
||||
static void CL_ParseResourceRequest( sizebuf_t *msg )
|
||||
{
|
||||
int arg, nStartIndex;
|
||||
|
||||
arg = MSG_ReadLong( msg );
|
||||
nStartIndex = MSG_ReadLong( msg );
|
||||
@@ -718,31 +741,10 @@ static void CL_ParseResourceRequest( sizebuf_t *msg )
|
||||
if( cl.servercount != arg )
|
||||
return;
|
||||
|
||||
if( nStartIndex < 0 && nStartIndex > cl.num_resources )
|
||||
if( nStartIndex < 0 || nStartIndex >= cl.num_resources )
|
||||
return;
|
||||
|
||||
MSG_BeginClientCmd( &sbuf, clc_resourcelist );
|
||||
MSG_WriteShort( &sbuf, cl.num_resources );
|
||||
|
||||
for( i = nStartIndex; i < cl.num_resources; i++ )
|
||||
{
|
||||
MSG_WriteString( &sbuf, cl.resourcelist[i].szFileName );
|
||||
MSG_WriteByte( &sbuf, cl.resourcelist[i].type );
|
||||
MSG_WriteShort( &sbuf, cl.resourcelist[i].nIndex );
|
||||
MSG_WriteLong( &sbuf, cl.resourcelist[i].nDownloadSize );
|
||||
MSG_WriteByte( &sbuf, cl.resourcelist[i].ucFlags );
|
||||
|
||||
if( FBitSet( cl.resourcelist[i].ucFlags, RES_CUSTOM ))
|
||||
MSG_WriteBytes( &sbuf, cl.resourcelist[i].rgucMD5_hash, 16 );
|
||||
}
|
||||
|
||||
// a1ba: useless check? MSG_BeginClientCmd and MSG_WriteShort will always
|
||||
// write to the buffer
|
||||
// if( MSG_GetNumBytesWritten( &sbuf ) > 0 )
|
||||
{
|
||||
Netchan_CreateFragments( &cls.netchan, &sbuf );
|
||||
Netchan_FragSend( &cls.netchan );
|
||||
}
|
||||
CL_SendResourceList( &cl.resourcelist[nStartIndex], cl.num_resources - nStartIndex );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1738,6 +1740,8 @@ void CL_RegisterResources( sizebuf_t *msg, connprotocol_t proto )
|
||||
// tell rendering system we have a new set of models.
|
||||
ref.dllFuncs.R_NewMap ();
|
||||
|
||||
Mod_LoadDetailTextures( cl.worldmodel );
|
||||
|
||||
// check if this map must start from dark screen
|
||||
CL_StartDark ();
|
||||
|
||||
@@ -514,17 +514,26 @@ static void CL_ParseSoundPacketGS( sizebuf_t *msg )
|
||||
static void CL_ParseSpawnStaticSound( sizebuf_t *msg )
|
||||
{
|
||||
vec3_t pos;
|
||||
int handle, entnum, pitch, flags;
|
||||
int sound, entnum, pitch, flags;
|
||||
float volume, attn;
|
||||
sound_t handle = 0;
|
||||
|
||||
MSG_ReadVec3Coord( msg, pos );
|
||||
handle = MSG_ReadShort( msg );
|
||||
sound = MSG_ReadShort( msg );
|
||||
volume = MSG_ReadByte( msg ) * ( 1.0f / 255.0f );
|
||||
attn = MSG_ReadByte( msg ) * ( 1.0f / 64.0f );
|
||||
entnum = MSG_ReadShort( msg );
|
||||
pitch = MSG_ReadByte( msg );
|
||||
flags = MSG_ReadByte( msg );
|
||||
|
||||
if( FBitSet( flags, SND_SENTENCE ))
|
||||
{
|
||||
char sentenceName[32];
|
||||
Q_snprintf( sentenceName, sizeof( sentenceName ), "!%i", sound );
|
||||
handle = S_RegisterSound( sentenceName );
|
||||
}
|
||||
else handle = cl.sound_index[sound]; // see precached sound
|
||||
|
||||
S_AmbientSound( pos, entnum, handle, volume, attn, pitch, flags );
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ qboolean Sound_LoadOggVorbis( const char *name, const byte *buffer, fs_offset_t
|
||||
SetBits( sound.flags, SOUND_RESAMPLE );
|
||||
Sound_ScanVorbisComments( &vorbisFile );
|
||||
|
||||
while(( ret = ov_read( &vorbisFile, (char *)sound.wav + written, sound.size - written, 0, sound.width, 1, §ion )) != 0 )
|
||||
while(( ret = ov_read( &vorbisFile, (char *)sound.wav + written, sound.size - written, XASH_BIG_ENDIAN, sound.width, 1, §ion )) != 0 )
|
||||
{
|
||||
if( ret < 0 )
|
||||
{
|
||||
@@ -232,7 +232,7 @@ int Stream_ReadOggVorbis( stream_t *stream, int needBytes, void *buffer )
|
||||
|
||||
if( !stream->buffsize )
|
||||
{
|
||||
stream->pos = ov_read( &ctx->vf, (char *)stream->temp, OUTBUF_SIZE, 0, stream->width, 1, §ion );
|
||||
stream->pos = ov_read( &ctx->vf, (char *)stream->temp, OUTBUF_SIZE, XASH_BIG_ENDIAN, stream->width, 1, §ion );
|
||||
if( stream->pos == 0 )
|
||||
{
|
||||
break; // end of file
|
||||
|
||||
@@ -152,6 +152,8 @@ static qboolean StreamFindNextChunk( file_t *file, const char *name, int *last_c
|
||||
if( FS_Read( file, &iff_chunk_len, sizeof( iff_chunk_len )) != sizeof( iff_chunk_len ))
|
||||
return false;
|
||||
|
||||
iff_chunk_len = LittleLong( iff_chunk_len );
|
||||
|
||||
if( iff_chunk_len < 0 )
|
||||
return false; // didn't find the chunk
|
||||
|
||||
@@ -317,6 +319,15 @@ qboolean Sound_LoadWAV( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
|
||||
memcpy( sound.wav, buffer + (iff_dataPtr - buffer), sound.size );
|
||||
|
||||
// swap 16-bit samples from little endian to native
|
||||
if( sound.width == 2 )
|
||||
{
|
||||
short *p = (short *)sound.wav;
|
||||
int count = sound.size / 2;
|
||||
for( int i = 0; i < count; i++ )
|
||||
p[i] = LittleShort( p[i] );
|
||||
}
|
||||
|
||||
// now convert 8-bit sounds to signed
|
||||
if( sound.width == 1 )
|
||||
{
|
||||
@@ -394,6 +405,7 @@ stream_t *Stream_OpenWAV( const char *filename )
|
||||
FS_Read( file, chunkName, 4 );
|
||||
|
||||
FS_Read( file, &t, sizeof( t ));
|
||||
t = LittleShort( t );
|
||||
if( t != 1 )
|
||||
{
|
||||
Con_DPrintf( S_ERROR "%s: %s not a microsoft PCM format\n", __func__, filename );
|
||||
@@ -402,14 +414,15 @@ stream_t *Stream_OpenWAV( const char *filename )
|
||||
}
|
||||
|
||||
FS_Read( file, &t, sizeof( t ));
|
||||
sound.channels = t;
|
||||
sound.channels = LittleShort( t );
|
||||
|
||||
FS_Read( file, &sound.rate, sizeof( int ));
|
||||
sound.rate = LittleLong( sound.rate );
|
||||
|
||||
FS_Seek( file, 6, SEEK_CUR );
|
||||
|
||||
FS_Read( file, &t, sizeof( t ));
|
||||
sound.width = t / 8;
|
||||
sound.width = LittleShort( t ) / 8;
|
||||
|
||||
sound.loopstart = 0;
|
||||
|
||||
@@ -423,7 +436,7 @@ stream_t *Stream_OpenWAV( const char *filename )
|
||||
}
|
||||
|
||||
FS_Read( file, &sound.samples, sizeof( int ));
|
||||
sound.samples = ( sound.samples / sound.width ) / sound.channels;
|
||||
sound.samples = ( LittleLong( sound.samples ) / sound.width ) / sound.channels;
|
||||
|
||||
// at this point we have valid stream
|
||||
stream = Mem_Calloc( host.soundpool, sizeof( stream_t ));
|
||||
@@ -458,6 +471,14 @@ int Stream_ReadWAV( stream_t *stream, int bytes, void *buffer )
|
||||
stream->pos += bytes;
|
||||
FS_Read( stream->file, buffer, bytes );
|
||||
|
||||
if( stream->width == 2 )
|
||||
{
|
||||
short *p = (short *)buffer;
|
||||
int count = bytes / 2;
|
||||
for( int i = 0; i < count; i++ )
|
||||
p[i] = LittleShort( p[i] );
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
||||
@@ -615,8 +615,11 @@ void Cmd_TokenizeString( const char *text )
|
||||
if( !*text )
|
||||
return;
|
||||
|
||||
if( cmd_argc == 1 )
|
||||
cmd_args = text;
|
||||
switch( cmd_argc )
|
||||
{
|
||||
case 0: cmd_args = ""; break;
|
||||
case 1: cmd_args = text; break;
|
||||
}
|
||||
|
||||
text = COM_ParseFileSafe( (char*)text, cmd_token, sizeof( cmd_token ), PFILE_IGNOREBRACKET, NULL, NULL );
|
||||
|
||||
|
||||
@@ -227,7 +227,7 @@ qboolean LZSS_IsCompressed( const byte *source, size_t input_len )
|
||||
|
||||
phdr = (const lzss_header_t *)source;
|
||||
|
||||
if( phdr && phdr->id == LZSS_ID )
|
||||
if( phdr && phdr->id == LittleLong( LZSS_ID ))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@@ -241,8 +241,8 @@ uint LZSS_GetActualSize( const byte *source, size_t input_len )
|
||||
|
||||
phdr = (const lzss_header_t *)source;
|
||||
|
||||
if( phdr && phdr->id == LZSS_ID )
|
||||
return phdr->size;
|
||||
if( phdr && phdr->id == LittleLong( LZSS_ID ))
|
||||
return LittleLong( phdr->size );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -296,8 +296,8 @@ static byte *LZSS_CompressNoAlloc( lzss_state_t *state, byte *pInput, int input_
|
||||
return NULL;
|
||||
|
||||
// set LZSS header
|
||||
header->id = LZSS_ID;
|
||||
header->size = input_length;
|
||||
header->id = LittleLong( LZSS_ID );
|
||||
header->size = LittleLong( input_length );
|
||||
|
||||
// create the compression work buffers, small enough (~64K) for stack
|
||||
state->hash_table = (lzss_list_t *)alloca( 256 * sizeof( lzss_list_t ));
|
||||
@@ -967,8 +967,8 @@ static void Test_LZSS( void )
|
||||
ASAN_POISON_MEMORY_REGION( poison3, sizeof( poison3 ));
|
||||
#endif
|
||||
|
||||
hdr->size = sizeof( in ) - sizeof( *hdr );
|
||||
hdr->id = LZSS_ID;
|
||||
hdr->size = LittleLong( sizeof( in ) - sizeof( *hdr ));
|
||||
hdr->id = LittleLong( LZSS_ID );
|
||||
|
||||
memset( in + sizeof( *hdr ), 0xff, sizeof( in ) - sizeof( *hdr ));
|
||||
result = LZSS_Decompress( in, out, sizeof( in ), sizeof( out ));
|
||||
@@ -978,18 +978,18 @@ static void Test_LZSS( void )
|
||||
result = LZSS_Decompress( in, out, sizeof( in ), sizeof( out ));
|
||||
TASSERT_EQi( result, 0 );
|
||||
|
||||
hdr->size = 1;
|
||||
hdr->id = LZSS_ID;
|
||||
hdr->size = LittleLong( 1 );
|
||||
hdr->id = LittleLong( LZSS_ID );
|
||||
result = LZSS_Decompress( in, out, sizeof( in ), sizeof( out ));
|
||||
TASSERT_EQi( result, 0 );
|
||||
|
||||
hdr->size = 999;
|
||||
hdr->id = LZSS_ID;
|
||||
hdr->size = LittleLong( 999 );
|
||||
hdr->id = LittleLong( LZSS_ID );
|
||||
result = LZSS_Decompress( in, out, sizeof( in ), sizeof( out ));
|
||||
TASSERT_EQi( result, 0 );
|
||||
|
||||
hdr->size = sizeof( in ) - sizeof( *hdr );
|
||||
hdr->id = 0xa1ba;
|
||||
hdr->size = LittleLong( sizeof( in ) - sizeof( *hdr ));
|
||||
hdr->id = LittleLong( 0xa1ba );
|
||||
result = LZSS_Decompress( in, out, sizeof( in ), sizeof( out ));
|
||||
TASSERT_EQi( result, 0 );
|
||||
|
||||
|
||||
@@ -1276,6 +1276,10 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
|
||||
Cbuf_ExecStuffCmds(); // execute stuffcmds (commandline)
|
||||
SCR_CheckStartupVids(); // must be last
|
||||
|
||||
#ifndef XASH_DEDICATED
|
||||
IN_GyroCheckAvailability();
|
||||
#endif
|
||||
|
||||
if( Sys_GetParmFromCmdLine( "-timedemo", demoname ))
|
||||
Cbuf_AddTextf( "timedemo %s\n", demoname );
|
||||
|
||||
|
||||
@@ -16,6 +16,24 @@ GNU General Public License for more details.
|
||||
#include "imagelib.h"
|
||||
#include "xash3d_mathlib.h"
|
||||
#include "img_bmp.h"
|
||||
#include "swaplib.h"
|
||||
|
||||
le_struct_begin( bmp_swap )
|
||||
le_struct_field( bmp_t, fileSize )
|
||||
le_struct_field( bmp_t, reserved0 )
|
||||
le_struct_field( bmp_t, bitmapDataOffset )
|
||||
le_struct_field( bmp_t, bitmapHeaderSize )
|
||||
le_struct_field( bmp_t, width )
|
||||
le_struct_field( bmp_t, height )
|
||||
le_struct_field( bmp_t, planes )
|
||||
le_struct_field( bmp_t, bitsPerPixel )
|
||||
le_struct_field( bmp_t, compression )
|
||||
le_struct_field( bmp_t, bitmapDataSize )
|
||||
le_struct_field( bmp_t, hRes )
|
||||
le_struct_field( bmp_t, vRes )
|
||||
le_struct_field( bmp_t, colors )
|
||||
le_struct_field( bmp_t, importantColors )
|
||||
le_struct_end();
|
||||
|
||||
/*
|
||||
=============
|
||||
@@ -41,6 +59,7 @@ qboolean Image_LoadBMP( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
|
||||
buf_p = (byte *)buffer;
|
||||
memcpy( &bhdr, buf_p, sizeof( bmp_t ));
|
||||
le_struct_swap( bmp_swap, &bhdr );
|
||||
buf_p += BI_FILE_HEADER_SIZE + bhdr.bitmapHeaderSize;
|
||||
|
||||
// bogus file header check
|
||||
@@ -282,7 +301,8 @@ qboolean Image_LoadBMP( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
shortPixel = *(word *)buf_p, buf_p += 2;
|
||||
shortPixel = buf_p[0] | (buf_p[1] << 8);
|
||||
buf_p += 2;
|
||||
*pixbuf++ = blue = (shortPixel & ( 31 << 10 )) >> 7;
|
||||
*pixbuf++ = green = (shortPixel & ( 31 << 5 )) >> 2;
|
||||
*pixbuf++ = red = (shortPixel & ( 31 )) << 3;
|
||||
@@ -396,7 +416,9 @@ qboolean Image_SaveBMP( const char *name, rgbdata_t *pix )
|
||||
hdr.colors = ( pixel_size == 1 ) ? 256 : 0;
|
||||
hdr.importantColors = 0;
|
||||
|
||||
le_struct_swap( bmp_swap, &hdr );
|
||||
FS_Write( pfile, &hdr, sizeof( bmp_t ));
|
||||
le_struct_swap( bmp_swap, &hdr );
|
||||
|
||||
pbBmpBits = Mem_Malloc( host.imagepool, cbBmpBits );
|
||||
|
||||
|
||||
@@ -16,6 +16,49 @@ GNU General Public License for more details.
|
||||
#include "imagelib.h"
|
||||
#include "xash3d_mathlib.h"
|
||||
#include "img_dds.h"
|
||||
#include "swaplib.h"
|
||||
|
||||
le_struct_begin( dds_pixf_swap )
|
||||
le_struct_field( dds_pixf_t, dwSize )
|
||||
le_struct_field( dds_pixf_t, dwFlags )
|
||||
le_struct_field( dds_pixf_t, dwFourCC )
|
||||
le_struct_field( dds_pixf_t, dwRGBBitCount )
|
||||
le_struct_field( dds_pixf_t, dwRBitMask )
|
||||
le_struct_field( dds_pixf_t, dwGBitMask )
|
||||
le_struct_field( dds_pixf_t, dwBBitMask )
|
||||
le_struct_field( dds_pixf_t, dwABitMask )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( dds_caps_swap )
|
||||
le_struct_field( dds_caps_t, dwCaps1 )
|
||||
le_struct_field( dds_caps_t, dwCaps2 )
|
||||
le_struct_field( dds_caps_t, dwCaps3 )
|
||||
le_struct_field( dds_caps_t, dwCaps4 )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( dds_swap )
|
||||
le_struct_field( dds_t, dwIdent )
|
||||
le_struct_field( dds_t, dwSize )
|
||||
le_struct_field( dds_t, dwFlags )
|
||||
le_struct_field( dds_t, dwHeight )
|
||||
le_struct_field( dds_t, dwWidth )
|
||||
le_struct_field( dds_t, dwLinearSize )
|
||||
le_struct_field( dds_t, dwDepth )
|
||||
le_struct_field( dds_t, dwMipMapCount )
|
||||
le_struct_field( dds_t, dwAlphaBitDepth )
|
||||
le_struct_array( dds_t, dwReserved1, 10 )
|
||||
le_struct_child( dds_t, dsPixelFormat, dds_pixf_swap )
|
||||
le_struct_child( dds_t, dsCaps, dds_caps_swap )
|
||||
le_struct_field( dds_t, dwTextureStage )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( dds_dxt10_swap )
|
||||
le_struct_field( dds_header_dxt10_t, dxgiFormat )
|
||||
le_struct_field( dds_header_dxt10_t, resourceDimension )
|
||||
le_struct_field( dds_header_dxt10_t, miscFlag )
|
||||
le_struct_field( dds_header_dxt10_t, arraySize )
|
||||
le_struct_field( dds_header_dxt10_t, miscFlags2 )
|
||||
le_struct_end();
|
||||
|
||||
static qboolean Image_CheckDXT3Alpha( dds_t *hdr, byte *fin )
|
||||
{
|
||||
@@ -295,6 +338,7 @@ qboolean Image_LoadDDS( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
return false;
|
||||
|
||||
memcpy( &header, buffer, sizeof( header ));
|
||||
le_struct_swap( dds_swap, &header );
|
||||
|
||||
if( header.dwIdent != DDSHEADER )
|
||||
return false; // it's not a dds file, just skip it
|
||||
@@ -315,6 +359,7 @@ qboolean Image_LoadDDS( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
if( header.dsPixelFormat.dwFourCC == TYPE_DX10 )
|
||||
{
|
||||
memcpy( &header2, buffer + sizeof( header ), sizeof( header2 ));
|
||||
le_struct_swap( dds_dxt10_swap, &header2 );
|
||||
headersOffset += sizeof( header2 );
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,34 @@ GNU General Public License for more details.
|
||||
#include "imagelib.h"
|
||||
#include "xash3d_mathlib.h"
|
||||
#include "img_ktx2.h"
|
||||
#include "swaplib.h"
|
||||
|
||||
le_struct_begin( ktx2_header_swap )
|
||||
le_struct_field( ktx2_header_t, vkFormat )
|
||||
le_struct_field( ktx2_header_t, typeSize )
|
||||
le_struct_field( ktx2_header_t, pixelWidth )
|
||||
le_struct_field( ktx2_header_t, pixelHeight )
|
||||
le_struct_field( ktx2_header_t, pixelDepth )
|
||||
le_struct_field( ktx2_header_t, layerCount )
|
||||
le_struct_field( ktx2_header_t, faceCount )
|
||||
le_struct_field( ktx2_header_t, levelCount )
|
||||
le_struct_field( ktx2_header_t, supercompressionScheme )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( ktx2_index_swap )
|
||||
le_struct_field( ktx2_index_t, dfdByteOffset )
|
||||
le_struct_field( ktx2_index_t, dfdByteLength )
|
||||
le_struct_field( ktx2_index_t, kvdByteOffset )
|
||||
le_struct_field( ktx2_index_t, kvdByteLength )
|
||||
le_struct_field( ktx2_index_t, sgdByteOffset )
|
||||
le_struct_field( ktx2_index_t, sgdByteLength )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( ktx2_level_swap )
|
||||
le_struct_field( ktx2_level_t, byteOffset )
|
||||
le_struct_field( ktx2_level_t, byteLength )
|
||||
le_struct_field( ktx2_level_t, uncompressedByteLength )
|
||||
le_struct_end();
|
||||
|
||||
static void Image_KTX2Format( uint32_t ktx2_format )
|
||||
{
|
||||
@@ -125,6 +153,7 @@ static qboolean Image_KTX2Parse( const ktx2_header_t *header, const byte *buffer
|
||||
}
|
||||
|
||||
memcpy( &index, buffer + KTX2_IDENTIFIER_SIZE + sizeof( ktx2_header_t ), sizeof( index ));
|
||||
le_struct_swap( ktx2_index_swap, &index );
|
||||
|
||||
for( mip = 0; mip < header->levelCount; ++mip )
|
||||
{
|
||||
@@ -134,6 +163,7 @@ static qboolean Image_KTX2Parse( const ktx2_header_t *header, const byte *buffer
|
||||
|
||||
ktx2_level_t level;
|
||||
memcpy( &level, levels_begin + mip * sizeof( level ), sizeof( level ));
|
||||
le_struct_swap( ktx2_level_swap, &level );
|
||||
|
||||
if( mip_size != level.byteLength )
|
||||
{
|
||||
@@ -159,6 +189,7 @@ static qboolean Image_KTX2Parse( const ktx2_header_t *header, const byte *buffer
|
||||
{
|
||||
ktx2_level_t level;
|
||||
memcpy( &level, levels_begin + mip * sizeof( level ), sizeof( level ));
|
||||
le_struct_swap( ktx2_level_swap, &level );
|
||||
memcpy( image.rgba + cursor, buffer + level.byteOffset, level.byteLength );
|
||||
cursor += level.byteLength;
|
||||
}
|
||||
@@ -180,6 +211,7 @@ qboolean Image_LoadKTX2( const char *name, const byte *buffer, fs_offset_t files
|
||||
}
|
||||
|
||||
memcpy( &header, buffer + KTX2_IDENTIFIER_SIZE, sizeof( header ));
|
||||
le_struct_swap( ktx2_header_swap, &header );
|
||||
|
||||
image.width = header.pixelWidth;
|
||||
image.height = header.pixelHeight;
|
||||
|
||||
@@ -16,6 +16,16 @@ GNU General Public License for more details.
|
||||
#include "imagelib.h"
|
||||
#include "xash3d_mathlib.h"
|
||||
#include "img_tga.h"
|
||||
#include "swaplib.h"
|
||||
|
||||
le_struct_begin( tga_swap )
|
||||
le_struct_field( tga_t, colormap_index )
|
||||
le_struct_field( tga_t, colormap_length )
|
||||
le_struct_field( tga_t, x_origin )
|
||||
le_struct_field( tga_t, y_origin )
|
||||
le_struct_field( tga_t, width )
|
||||
le_struct_field( tga_t, height )
|
||||
le_struct_end();
|
||||
|
||||
/*
|
||||
=============
|
||||
@@ -44,10 +54,10 @@ qboolean Image_LoadTGA( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
targa_header.colormap_index = buf_p[0] + buf_p[1] * 256; buf_p += 2;
|
||||
targa_header.colormap_length = buf_p[0] + buf_p[1] * 256; buf_p += 2;
|
||||
targa_header.colormap_size = *buf_p; buf_p += 1;
|
||||
targa_header.x_origin = *(short *)buf_p; buf_p += 2;
|
||||
targa_header.y_origin = *(short *)buf_p; buf_p += 2;
|
||||
targa_header.width = image.width = *(short *)buf_p; buf_p += 2;
|
||||
targa_header.height = image.height = *(short *)buf_p; buf_p += 2;
|
||||
targa_header.x_origin = buf_p[0] + buf_p[1] * 256; buf_p += 2;
|
||||
targa_header.y_origin = buf_p[0] + buf_p[1] * 256; buf_p += 2;
|
||||
targa_header.width = image.width = buf_p[0] + buf_p[1] * 256; buf_p += 2;
|
||||
targa_header.height = image.height = buf_p[0] + buf_p[1] * 256; buf_p += 2;
|
||||
targa_header.pixel_size = *buf_p++;
|
||||
targa_header.attributes = *buf_p++;
|
||||
if( targa_header.id_length != 0 ) buf_p += targa_header.id_length; // skip TARGA image comment
|
||||
@@ -284,6 +294,7 @@ qboolean Image_SaveTGA( const char *name, rgbdata_t *pix )
|
||||
|
||||
out = buffer;
|
||||
|
||||
le_struct_swap( tga_swap, &targa_header );
|
||||
memcpy( out, &targa_header, sizeof( tga_t ) );
|
||||
out += sizeof( tga_t );
|
||||
|
||||
|
||||
@@ -285,66 +285,34 @@ int Image_ComparePalette( const byte *pal )
|
||||
|
||||
static void Image_SetPalette( const byte *pal, uint *d_table )
|
||||
{
|
||||
byte rgba[4];
|
||||
uint uirgba; // TODO: palette looks byte-swapped on big-endian
|
||||
int i;
|
||||
|
||||
// setup palette
|
||||
switch( image.d_rendermode )
|
||||
{
|
||||
case LUMP_NORMAL:
|
||||
for( i = 0; i < 256; i++ )
|
||||
{
|
||||
memcpy( rgba, &pal[i * 3], 3 );
|
||||
rgba[3] = 0xFF;
|
||||
memcpy( &uirgba, rgba, sizeof( uirgba ));
|
||||
d_table[i] = uirgba;
|
||||
}
|
||||
for( int i = 0; i < 256; i++ )
|
||||
d_table[i] = HostFourCC( pal[i * 3 + 0], pal[i * 3 + 1], pal[i * 3 + 2], 0xFF );
|
||||
break;
|
||||
case LUMP_TEXGAMMA:
|
||||
for( i = 0; i < 256; i++ )
|
||||
for( int i = 0; i < 256; i++ )
|
||||
{
|
||||
rgba[0] = TextureToGamma( pal[i * 3 + 0] );
|
||||
rgba[1] = TextureToGamma( pal[i * 3 + 1] );
|
||||
rgba[2] = TextureToGamma( pal[i * 3 + 2] );
|
||||
rgba[3] = 0xFF;
|
||||
memcpy( &uirgba, rgba, sizeof( uirgba ));
|
||||
d_table[i] = uirgba;
|
||||
d_table[i] = HostFourCC(
|
||||
TextureToGamma( pal[i * 3 + 0] ),
|
||||
TextureToGamma( pal[i * 3 + 1] ),
|
||||
TextureToGamma( pal[i * 3 + 2] ),
|
||||
0xFF );
|
||||
}
|
||||
break;
|
||||
case LUMP_GRADIENT:
|
||||
for( i = 0; i < 256; i++ )
|
||||
{
|
||||
rgba[0] = pal[765];
|
||||
rgba[1] = pal[766];
|
||||
rgba[2] = pal[767];
|
||||
rgba[3] = i;
|
||||
memcpy( &uirgba, rgba, sizeof( uirgba ));
|
||||
d_table[i] = uirgba;
|
||||
}
|
||||
for( int i = 0; i < 256; i++ )
|
||||
d_table[i] = HostFourCC( pal[765], pal[766], pal[767], i );
|
||||
break;
|
||||
case LUMP_MASKED:
|
||||
for( i = 0; i < 255; i++ )
|
||||
{
|
||||
rgba[0] = pal[i*3+0];
|
||||
rgba[1] = pal[i*3+1];
|
||||
rgba[2] = pal[i*3+2];
|
||||
rgba[3] = 0xFF;
|
||||
memcpy( &uirgba, rgba, sizeof( uirgba ));
|
||||
d_table[i] = uirgba;
|
||||
}
|
||||
for( int i = 0; i < 255; i++ )
|
||||
d_table[i] = HostFourCC( pal[i * 3 + 0], pal[i * 3 + 1], pal[i * 3 + 2], 0xFF );
|
||||
d_table[255] = 0;
|
||||
break;
|
||||
case LUMP_EXTENDED:
|
||||
for( i = 0; i < 256; i++ )
|
||||
{
|
||||
rgba[0] = pal[i*4+0];
|
||||
rgba[1] = pal[i*4+1];
|
||||
rgba[2] = pal[i*4+2];
|
||||
rgba[3] = pal[i*4+3];
|
||||
memcpy( &uirgba, rgba, sizeof( uirgba ));
|
||||
d_table[i] = uirgba;
|
||||
}
|
||||
for( int i = 0; i < 256; i++ )
|
||||
d_table[i] = HostFourCC( pal[i * 4 + 0], pal[i * 4 + 1], pal[i * 4 + 2], pal[i * 4 + 3] );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,43 @@ GNU General Public License for more details.
|
||||
#include "studio.h"
|
||||
#include "sprite.h"
|
||||
#include "qfont.h"
|
||||
#include "swaplib.h"
|
||||
|
||||
le_struct_begin( charinfo_swap )
|
||||
le_struct_field( charinfo, startoffset )
|
||||
le_struct_field( charinfo, charwidth )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( qfont_swap )
|
||||
le_struct_field( qfont_t, width )
|
||||
le_struct_field( qfont_t, height )
|
||||
le_struct_field( qfont_t, rowcount )
|
||||
le_struct_field( qfont_t, rowheight )
|
||||
le_struct_array_child( qfont_t, fontinfo, charinfo_swap, NUM_GLYPHS )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( lmp_swap )
|
||||
le_struct_field( lmp_t, width )
|
||||
le_struct_field( lmp_t, height )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( mip_swap )
|
||||
le_struct_field( mip_t, width )
|
||||
le_struct_field( mip_t, height )
|
||||
le_struct_array( mip_t, offsets, 4 )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( dwadinfo_swap )
|
||||
le_struct_field( dwadinfo_t, ident )
|
||||
le_struct_field( dwadinfo_t, numlumps )
|
||||
le_struct_field( dwadinfo_t, infotableofs )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( dlumpinfo_swap )
|
||||
le_struct_field( dlumpinfo_t, filepos )
|
||||
le_struct_field( dlumpinfo_t, disksize )
|
||||
le_struct_field( dlumpinfo_t, size )
|
||||
le_struct_end();
|
||||
|
||||
/*
|
||||
============
|
||||
@@ -98,6 +135,7 @@ qboolean Image_LoadFNT( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
return false;
|
||||
|
||||
memcpy( &font, buffer, sizeof( font ));
|
||||
le_struct_swap( qfont_swap, &font );
|
||||
|
||||
// last sixty four bytes - what the hell ????
|
||||
size = sizeof( qfont_t ) - 4 + ( font.height * font.width * QCHAR_WIDTH ) + sizeof( short ) + 768 + 64;
|
||||
@@ -120,7 +158,8 @@ qboolean Image_LoadFNT( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
|
||||
fin = buffer + sizeof( font ) - 4;
|
||||
pal = fin + (image.width * image.height);
|
||||
numcolors = *(short *)pal, pal += sizeof( short );
|
||||
numcolors = pal[0] | (pal[1] << 8);
|
||||
pal += sizeof( short );
|
||||
|
||||
if( numcolors == 768 || numcolors == 256 )
|
||||
{
|
||||
@@ -305,6 +344,7 @@ qboolean Image_LoadLMP( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
{
|
||||
fin = (byte *)buffer;
|
||||
memcpy( &lmp, fin, sizeof( lmp ));
|
||||
le_struct_swap( lmp_swap, &lmp );
|
||||
image.width = lmp.width;
|
||||
image.height = lmp.height;
|
||||
rendermode = LUMP_NORMAL;
|
||||
@@ -337,7 +377,7 @@ qboolean Image_LoadLMP( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
}
|
||||
}
|
||||
pal = fin + pixels;
|
||||
numcolors = *(short *)pal;
|
||||
numcolors = pal[0] | (pal[1] << 8);
|
||||
if( numcolors != 256 ) pal = NULL; // corrupted lump ?
|
||||
else pal += sizeof( short );
|
||||
}
|
||||
@@ -397,6 +437,8 @@ qboolean Image_LoadMIP( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
return false;
|
||||
|
||||
memcpy( &mip, buffer, sizeof( mip ));
|
||||
if( !Image_CheckFlag( IL_HOST_ENDIAN ))
|
||||
le_struct_swap( mip_swap, &mip );
|
||||
image.width = mip.width;
|
||||
image.height = mip.height;
|
||||
|
||||
@@ -411,7 +453,7 @@ qboolean Image_LoadMIP( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
// half-life 1.0.0.1 mip version with palette
|
||||
fin = (byte *)buffer + mip.offsets[0];
|
||||
pal = (byte *)buffer + mip.offsets[0] + (((image.width * image.height) * 85)>>6);
|
||||
numcolors = *(short *)pal;
|
||||
numcolors = pal[0] | (pal[1] << 8);
|
||||
if( numcolors != 256 ) pal = NULL; // corrupted mip ?
|
||||
else pal += sizeof( short ); // skip colorsize
|
||||
|
||||
@@ -596,24 +638,23 @@ Image_LoadWAD
|
||||
*/
|
||||
qboolean Image_LoadWAD( const char *name, const byte *buffer, fs_offset_t filesize )
|
||||
{
|
||||
const dwadinfo_t *header;
|
||||
const dlumpinfo_t *lumps;
|
||||
dwadinfo_t whdr;
|
||||
const unsigned char *mipdata;
|
||||
int i, j;
|
||||
|
||||
if( !buffer || filesize < sizeof( dwadinfo_t ))
|
||||
return false;
|
||||
|
||||
header = (const dwadinfo_t *)buffer;
|
||||
if( header->numlumps <= 0 || header->infotableofs <= 0 || header->infotableofs >= (int)filesize )
|
||||
memcpy( &whdr, buffer, sizeof( whdr ));
|
||||
le_struct_swap( dwadinfo_swap, &whdr );
|
||||
if( whdr.numlumps <= 0 || whdr.infotableofs <= 0 || whdr.infotableofs >= (int)filesize )
|
||||
return false;
|
||||
|
||||
lumps = (const dlumpinfo_t *)((const unsigned char *)buffer + header->infotableofs );
|
||||
|
||||
for( i = 0; i < header->numlumps; ++i )
|
||||
for( i = 0; i < whdr.numlumps; ++i )
|
||||
{
|
||||
const unsigned char *pixels, *palette, *use_palette;
|
||||
unsigned char grad_palette[256 * 3];
|
||||
dlumpinfo_t lump;
|
||||
int mip_size;
|
||||
mip_t mip;
|
||||
uint32_t width, height, offset0;
|
||||
@@ -623,16 +664,20 @@ qboolean Image_LoadWAD( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
float t;
|
||||
byte idx;
|
||||
|
||||
if( lumps[i].type != TYP_MIPTEX && lumps[i].type != TYP_PALETTE )
|
||||
memcpy( &lump, buffer + whdr.infotableofs + i * sizeof( dlumpinfo_t ), sizeof( lump ));
|
||||
le_struct_swap( dlumpinfo_swap, &lump );
|
||||
|
||||
if( lump.type != TYP_MIPTEX && lump.type != TYP_PALETTE )
|
||||
continue;
|
||||
|
||||
// get lump data and validate
|
||||
mipdata = (const unsigned char *)buffer + lumps[i].filepos;
|
||||
mip_size = lumps[i].disksize;
|
||||
if( lumps[i].filepos < 0 || lumps[i].filepos + mip_size > (int)filesize )
|
||||
mipdata = (const unsigned char *)buffer + lump.filepos;
|
||||
mip_size = lump.disksize;
|
||||
if( lump.filepos < 0 || lump.filepos + mip_size > (int)filesize )
|
||||
continue;
|
||||
|
||||
memcpy( &mip, mipdata, sizeof( mip ));
|
||||
le_struct_swap( mip_swap, &mip );
|
||||
width = mip.width;
|
||||
height = mip.height;
|
||||
|
||||
@@ -652,7 +697,7 @@ qboolean Image_LoadWAD( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
use_palette = palette;
|
||||
|
||||
// handle gradient palette
|
||||
if( lumps[i].type == TYP_PALETTE )
|
||||
if( lump.type == TYP_PALETTE )
|
||||
{
|
||||
// gradient palette
|
||||
const unsigned char *frontColorPtr = palette + 255 * 3;
|
||||
@@ -755,12 +800,16 @@ qboolean Image_SaveWAD( const char *name, rgbdata_t *pix )
|
||||
header.ident = IDWAD3HEADER;
|
||||
header.numlumps = 1;
|
||||
|
||||
le_struct_swap( dwadinfo_swap, &header );
|
||||
FS_Write( f, &header, sizeof( header ));
|
||||
le_struct_swap( mip_swap, &miptex );
|
||||
FS_Write( f, &miptex, sizeof( mip_t ));
|
||||
le_struct_swap( mip_swap, &miptex );
|
||||
FS_Write( f, pix->buffer, m0size );
|
||||
FS_Write( f, mip1_data, m1size );
|
||||
FS_Write( f, mip2_data, m2size );
|
||||
FS_Write( f, mip3_data, m3size );
|
||||
palette_size = LittleShort( palette_size );
|
||||
FS_Write( f, &palette_size, sizeof( short ));
|
||||
|
||||
if( lump_type == TYP_PALETTE )
|
||||
@@ -793,10 +842,11 @@ qboolean Image_SaveWAD( const char *name, rgbdata_t *pix )
|
||||
lump.type = (char)lump_type;
|
||||
lump.attribs = 0;
|
||||
Q_strncpy( lump.name, "tempdecal", sizeof( lump.name ));
|
||||
le_struct_swap( dlumpinfo_swap, &lump );
|
||||
FS_Write( f, &lump, sizeof( lump ));
|
||||
|
||||
FS_Seek( f, offsetof( dwadinfo_t, infotableofs ), SEEK_SET );
|
||||
infotableofs32 = (int)infotableofs;
|
||||
infotableofs32 = LittleLong((int)infotableofs );
|
||||
FS_Write( f, &infotableofs32, sizeof( int ));
|
||||
|
||||
FS_Close( f );
|
||||
|
||||
@@ -23,6 +23,7 @@ GNU General Public License for more details.
|
||||
#include "enginefeatures.h"
|
||||
#include "client.h"
|
||||
#include "server.h" // LUMP_ error codes
|
||||
#include "swaplib.h"
|
||||
#include "ref_common.h"
|
||||
#if defined( HAVE_OPENMP )
|
||||
#include <omp.h>
|
||||
@@ -186,8 +187,162 @@ typedef struct
|
||||
const char *loadname;
|
||||
const void **dataptr;
|
||||
size_t *count;
|
||||
#if XASH_BIG_ENDIAN // do not waste memory on little endian
|
||||
const swap_struct_def_t *swap;
|
||||
size_t swaplen;
|
||||
const swap_struct_def_t *swap32;
|
||||
size_t swaplen32;
|
||||
#endif
|
||||
} mlumpinfo_t;
|
||||
|
||||
// all these macros are ugly af
|
||||
#if XASH_BIG_ENDIAN
|
||||
#define LUMP_SWAP( x ) .swap = x, .swaplen = ARRAYSIZE( x )
|
||||
#define LUMP_SWAP32( x, y ) .swap = x, .swaplen = ARRAYSIZE( x ), .swap32 = y, .swaplen32 = ARRAYSIZE( y )
|
||||
#else
|
||||
#define LUMP_SWAP( x )
|
||||
#define LUMP_SWAP32( x, y )
|
||||
#endif
|
||||
|
||||
le_struct_begin( dlump_swap )
|
||||
le_struct_field( dlump_t, fileofs )
|
||||
le_struct_field( dlump_t, filelen )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( dheader_swap )
|
||||
le_struct_field( dheader_t, version )
|
||||
le_struct_array_child( dheader_t, lumps, dlump_swap, HEADER_LUMPS )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( dextrahdr_swap )
|
||||
le_struct_field( dextrahdr_t, id )
|
||||
le_struct_field( dextrahdr_t, version )
|
||||
le_struct_array_child( dextrahdr_t, lumps, dlump_swap, EXTRA_LUMPS )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( dbspx_hdr_swap )
|
||||
le_struct_field( dbspx_hdr_t, id )
|
||||
le_struct_field( dbspx_hdr_t, numlumps )
|
||||
// flexible array member omitted
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( dbspx_lump_swap )
|
||||
le_struct_field( dbspx_lump_t, fileofs )
|
||||
le_struct_field( dbspx_lump_t, filelen )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( dplane_swap )
|
||||
le_struct_array( dplane_t, normal, 3 )
|
||||
le_struct_field( dplane_t, dist )
|
||||
le_struct_field( dplane_t, type )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( dvertex_swap )
|
||||
le_struct_array( dvertex_t, point, 3 )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( dnode_swap )
|
||||
le_struct_field( dnode_t, planenum )
|
||||
le_struct_array( dnode_t, children, 2 )
|
||||
le_struct_array( dnode_t, mins, 3 )
|
||||
le_struct_array( dnode_t, maxs, 3 )
|
||||
le_struct_field( dnode_t, firstface )
|
||||
le_struct_field( dnode_t, numfaces )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( dnode32_swap )
|
||||
le_struct_field( dnode32_t, planenum )
|
||||
le_struct_array( dnode32_t, children, 2 )
|
||||
le_struct_array( dnode32_t, mins, 3 )
|
||||
le_struct_array( dnode32_t, maxs, 3 )
|
||||
le_struct_field( dnode32_t, firstface )
|
||||
le_struct_field( dnode32_t, numfaces )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( dtexinfo_swap )
|
||||
le_struct_array( dtexinfo_t, vecs[0], 4 )
|
||||
le_struct_array( dtexinfo_t, vecs[1], 4 )
|
||||
le_struct_field( dtexinfo_t, miptex )
|
||||
le_struct_field( dtexinfo_t, flags )
|
||||
le_struct_field( dtexinfo_t, faceinfo )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( dface_swap )
|
||||
le_struct_field( dface_t, planenum )
|
||||
le_struct_field( dface_t, side )
|
||||
le_struct_field( dface_t, firstedge )
|
||||
le_struct_field( dface_t, numedges )
|
||||
le_struct_field( dface_t, texinfo )
|
||||
le_struct_field( dface_t, lightofs )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( dface32_swap )
|
||||
le_struct_field( dface32_t, planenum )
|
||||
le_struct_field( dface32_t, side )
|
||||
le_struct_field( dface32_t, firstedge )
|
||||
le_struct_field( dface32_t, numedges )
|
||||
le_struct_field( dface32_t, texinfo )
|
||||
le_struct_field( dface32_t, lightofs )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( dclipnode_swap )
|
||||
le_struct_field( dclipnode_t, planenum )
|
||||
le_struct_array( dclipnode_t, children, 2 )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( dclipnode32_swap )
|
||||
le_struct_field( dclipnode32_t, planenum )
|
||||
le_struct_array( dclipnode32_t, children, 2 )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( dleaf_swap )
|
||||
le_struct_field( dleaf_t, contents )
|
||||
le_struct_field( dleaf_t, visofs )
|
||||
le_struct_array( dleaf_t, mins, 3 )
|
||||
le_struct_array( dleaf_t, maxs, 3 )
|
||||
le_struct_field( dleaf_t, firstmarksurface )
|
||||
le_struct_field( dleaf_t, nummarksurfaces )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( dleaf32_swap )
|
||||
le_struct_field( dleaf32_t, contents )
|
||||
le_struct_field( dleaf32_t, visofs )
|
||||
le_struct_array( dleaf32_t, mins, 3 )
|
||||
le_struct_array( dleaf32_t, maxs, 3 )
|
||||
le_struct_field( dleaf32_t, firstmarksurface )
|
||||
le_struct_field( dleaf32_t, nummarksurfaces )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( dedge_swap )
|
||||
le_struct_array( dedge_t, v, 2 )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( dedge32_swap )
|
||||
le_struct_array( dedge32_t, v, 2 )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( dmodel_swap )
|
||||
le_struct_array( dmodel_t, mins, 3 )
|
||||
le_struct_array( dmodel_t, maxs, 3 )
|
||||
le_struct_array( dmodel_t, origin, 3 )
|
||||
le_struct_array( dmodel_t, headnode, MAX_MAP_HULLS )
|
||||
le_struct_field( dmodel_t, visleafs )
|
||||
le_struct_field( dmodel_t, firstface )
|
||||
le_struct_field( dmodel_t, numfaces )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( dfaceinfo_swap )
|
||||
le_struct_field( dfaceinfo_t, texture_step )
|
||||
le_struct_field( dfaceinfo_t, max_extent )
|
||||
le_struct_field( dfaceinfo_t, groupid )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( mip_swap )
|
||||
le_struct_field( mip_t, width )
|
||||
le_struct_field( mip_t, height )
|
||||
le_struct_array( mip_t, offsets, 4 )
|
||||
le_struct_end();
|
||||
|
||||
world_static_t world;
|
||||
static dbspmodel_t srcmodel;
|
||||
static loadstat_t loadstat;
|
||||
@@ -212,6 +367,7 @@ static mlumpinfo_t srclumps[HEADER_LUMPS] =
|
||||
.loadname = "planes",
|
||||
.dataptr = (const void **)&srcmodel.planes,
|
||||
.count = &srcmodel.numplanes,
|
||||
LUMP_SWAP( dplane_swap )
|
||||
},
|
||||
{
|
||||
.lumpnumber = LUMP_TEXTURES,
|
||||
@@ -229,6 +385,7 @@ static mlumpinfo_t srclumps[HEADER_LUMPS] =
|
||||
.loadname = "vertexes",
|
||||
.dataptr = (const void **)&srcmodel.vertexes,
|
||||
.count = &srcmodel.numvertexes,
|
||||
LUMP_SWAP( dvertex_swap )
|
||||
},
|
||||
{
|
||||
.lumpnumber = LUMP_VISIBILITY,
|
||||
@@ -248,6 +405,7 @@ static mlumpinfo_t srclumps[HEADER_LUMPS] =
|
||||
.flags = CHECK_OVERFLOW,
|
||||
.dataptr = (const void **)&srcmodel.nodes,
|
||||
.count = &srcmodel.numnodes,
|
||||
LUMP_SWAP32( dnode_swap, dnode32_swap )
|
||||
},
|
||||
{
|
||||
.lumpnumber = LUMP_TEXINFO,
|
||||
@@ -258,6 +416,7 @@ static mlumpinfo_t srclumps[HEADER_LUMPS] =
|
||||
.flags = CHECK_OVERFLOW,
|
||||
.dataptr = (const void **)&srcmodel.texinfo,
|
||||
.count = &srcmodel.numtexinfo,
|
||||
LUMP_SWAP( dtexinfo_swap )
|
||||
},
|
||||
{
|
||||
.lumpnumber = LUMP_FACES,
|
||||
@@ -269,6 +428,7 @@ static mlumpinfo_t srclumps[HEADER_LUMPS] =
|
||||
.flags = CHECK_OVERFLOW,
|
||||
.dataptr = (const void **)&srcmodel.surfaces,
|
||||
.count = &srcmodel.numsurfaces,
|
||||
LUMP_SWAP32( dface_swap, dface32_swap )
|
||||
},
|
||||
{
|
||||
.lumpnumber = LUMP_LIGHTING,
|
||||
@@ -290,6 +450,7 @@ static mlumpinfo_t srclumps[HEADER_LUMPS] =
|
||||
.flags = 0,
|
||||
.dataptr = (const void **)&srcmodel.clipnodes,
|
||||
.count = &srcmodel.numclipnodes,
|
||||
LUMP_SWAP32( dclipnode_swap, dclipnode32_swap )
|
||||
},
|
||||
{
|
||||
.lumpnumber = LUMP_LEAFS,
|
||||
@@ -301,6 +462,7 @@ static mlumpinfo_t srclumps[HEADER_LUMPS] =
|
||||
.flags = CHECK_OVERFLOW,
|
||||
.dataptr = (const void **)&srcmodel.leafs,
|
||||
.count = &srcmodel.numleafs,
|
||||
LUMP_SWAP32( dleaf_swap, dleaf32_swap )
|
||||
},
|
||||
{
|
||||
.lumpnumber = LUMP_MARKSURFACES,
|
||||
@@ -323,6 +485,7 @@ static mlumpinfo_t srclumps[HEADER_LUMPS] =
|
||||
.flags = 0,
|
||||
.dataptr = (const void **)&srcmodel.edges,
|
||||
.count = &srcmodel.numedges,
|
||||
LUMP_SWAP32( dedge_swap, dedge32_swap )
|
||||
},
|
||||
{
|
||||
.lumpnumber = LUMP_SURFEDGES,
|
||||
@@ -343,6 +506,7 @@ static mlumpinfo_t srclumps[HEADER_LUMPS] =
|
||||
.flags = CHECK_OVERFLOW,
|
||||
.dataptr = (const void **)&srcmodel.submodels,
|
||||
.count = &srcmodel.numsubmodels,
|
||||
LUMP_SWAP( dmodel_swap )
|
||||
},
|
||||
};
|
||||
|
||||
@@ -366,6 +530,7 @@ static const mlumpinfo_t extlumps[EXTRA_LUMPS] =
|
||||
.flags = CHECK_OVERFLOW,
|
||||
.dataptr = (const void **)&srcmodel.faceinfo,
|
||||
.count = &srcmodel.numfaceinfo,
|
||||
LUMP_SWAP( dfaceinfo_swap )
|
||||
},
|
||||
{
|
||||
.lumpnumber = LUMP_SHADOWMAP,
|
||||
@@ -758,6 +923,29 @@ static void Mod_LoadLump( const void *in, const mlumpinfo_t *info, mlumpstat_t *
|
||||
|
||||
if( info->count )
|
||||
*info->count = numelems;
|
||||
|
||||
// finally, process the data
|
||||
#if XASH_BIG_ENDIAN
|
||||
const swap_struct_def_t *swap = real_entrysize == info->entrysize32 ? info->swap32 : info->swap;
|
||||
size_t swaplen = real_entrysize == info->entrysize32 ? info->swaplen32 : info->swaplen;
|
||||
|
||||
if( info->dataptr && *info->dataptr )
|
||||
{
|
||||
byte *data = (byte *)*info->dataptr;
|
||||
|
||||
if( swap )
|
||||
{
|
||||
for( size_t j = 0; j < numelems; j++ )
|
||||
swap_struct_( swap, swaplen, data + j * real_entrysize );
|
||||
}
|
||||
// some lumps don't need a swapdef, as all needed data in the lump info
|
||||
else if( real_entrysize > 1 )
|
||||
{
|
||||
for( size_t j = 0; j < numelems; j++ )
|
||||
swap_field_( data + j * real_entrysize, real_entrysize );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2535,6 +2723,7 @@ static void Mod_InitSkyClouds( model_t *mod, const mip_t *mt, texture_t *tx, qbo
|
||||
if( custom_palette )
|
||||
size += sizeof( short ) + 768;
|
||||
|
||||
Image_SetForceFlags( IL_HOST_ENDIAN );
|
||||
r_sky = FS_LoadImage( texname, (byte *)mt, size );
|
||||
}
|
||||
else
|
||||
@@ -2717,7 +2906,7 @@ static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureInd
|
||||
const size_t size = Mod_CalculateMipTexSize( mipTex, usesCustomPalette );
|
||||
|
||||
Q_snprintf( texName, sizeof( texName ), "#%s:%s.mip", loadstat.name, mipTex->name );
|
||||
Image_SetForceFlags( texture_force_flags );
|
||||
Image_SetForceFlags( texture_force_flags | IL_HOST_ENDIAN );
|
||||
texture->gl_texturenum = ref.dllFuncs.GL_LoadTexture( texName, (byte *)mipTex, size, txFlags );
|
||||
}
|
||||
|
||||
@@ -2750,7 +2939,7 @@ static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureInd
|
||||
|
||||
Q_snprintf( texName, sizeof( texName ), "#%s:%s_luma.mip", loadstat.name, mipTex->name );
|
||||
|
||||
Image_SetForceFlags( texture_force_flags );
|
||||
Image_SetForceFlags( texture_force_flags | IL_HOST_ENDIAN );
|
||||
|
||||
if( mipTex->offsets[0] > 0 )
|
||||
{
|
||||
@@ -2975,6 +3164,24 @@ static void Mod_LoadTextures( model_t *mod, dbspmodel_t *bmod )
|
||||
|
||||
lump = bmod->textures;
|
||||
|
||||
#if XASH_BIG_ENDIAN
|
||||
if( lump )
|
||||
{
|
||||
lump->nummiptex = LittleLong( lump->nummiptex );
|
||||
|
||||
for( int i = 0; i < lump->nummiptex; i++ )
|
||||
{
|
||||
lump->dataofs[i] = LittleLong( lump->dataofs[i] );
|
||||
|
||||
if( lump->dataofs[i] >= 0 )
|
||||
{
|
||||
mip_t *mt = (mip_t *)((byte *)lump + lump->dataofs[i]);
|
||||
le_struct_swap( mip_swap, mt );
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if( bmod->texdatasize < 1 || !lump || lump->nummiptex < 1 )
|
||||
{
|
||||
// no textures
|
||||
@@ -2989,6 +3196,105 @@ static void Mod_LoadTextures( model_t *mod, dbspmodel_t *bmod )
|
||||
Mod_SequenceAllAnimatedTextures( mod );
|
||||
}
|
||||
|
||||
#if !XASH_DEDICATED
|
||||
static void Mod_ParseDetailTextures( model_t *mod )
|
||||
{
|
||||
byte *afile;
|
||||
char *pfile;
|
||||
string token, texname;
|
||||
string detail_texname;
|
||||
string detail_path;
|
||||
float xScale, yScale;
|
||||
texture_t *tex;
|
||||
int i;
|
||||
|
||||
string filepath;
|
||||
|
||||
Q_strncpy( filepath, mod->name, sizeof( filepath ));
|
||||
COM_StripExtension( filepath );
|
||||
Q_strncat( filepath, "_detail.txt", sizeof( filepath ));
|
||||
|
||||
afile = FS_LoadFile( filepath, NULL, false );
|
||||
if( !afile )
|
||||
return;
|
||||
|
||||
pfile = (char *)afile;
|
||||
|
||||
// format: 'texturename' 'detailtexture' 'xScale' 'yScale'
|
||||
while(( pfile = COM_ParseFile( pfile, token, sizeof( token ))) != NULL )
|
||||
{
|
||||
texname[0] = '\0';
|
||||
detail_texname[0] = '\0';
|
||||
|
||||
// read texname
|
||||
if( token[0] == '{' )
|
||||
{
|
||||
// NOTE: COM_ParseFile handled some symbols seperately
|
||||
// this code will be fix it
|
||||
pfile = COM_ParseFile( pfile, token, sizeof( token ));
|
||||
Q_snprintf( texname, sizeof( texname ), "{%s", token );
|
||||
}
|
||||
else
|
||||
Q_strncpy( texname, token, sizeof( texname ));
|
||||
|
||||
// read detailtexture name
|
||||
pfile = COM_ParseFile( pfile, token, sizeof( token ));
|
||||
Q_strncpy( detail_texname, token, sizeof( detail_texname ));
|
||||
|
||||
// trying the scales or '{'
|
||||
pfile = COM_ParseFile( pfile, token, sizeof( token ));
|
||||
|
||||
// read second part of detailtexture name
|
||||
if( token[0] == '{' )
|
||||
{
|
||||
Q_strncat( detail_texname, token, sizeof( detail_texname ));
|
||||
pfile = COM_ParseFile( pfile, token, sizeof( token )); // read scales
|
||||
Q_strncat( detail_texname, token, sizeof( detail_texname ));
|
||||
pfile = COM_ParseFile( pfile, token, sizeof( token )); // parse scales
|
||||
}
|
||||
|
||||
Q_snprintf( detail_path, sizeof( detail_path ), "gfx/%s", detail_texname );
|
||||
|
||||
// read scales
|
||||
xScale = Q_atof( token );
|
||||
|
||||
pfile = COM_ParseFile( pfile, token, sizeof( token ));
|
||||
yScale = Q_atof( token );
|
||||
|
||||
if( xScale <= 0.0f || yScale <= 0.0f )
|
||||
continue;
|
||||
|
||||
// search for existing texture and uploading detail texture
|
||||
for( i = 0; i < mod->numtextures; i++ )
|
||||
{
|
||||
tex = mod->textures[i];
|
||||
|
||||
if( Q_stricmp( tex->name, texname ))
|
||||
continue;
|
||||
|
||||
tex->dt_texturenum = ref.dllFuncs.GL_LoadTexture( detail_path, NULL, 0, TF_FORCE_COLOR|TF_NOFLIP_TGA );
|
||||
|
||||
if( tex->dt_texturenum )
|
||||
ref.dllFuncs.R_SetDetailScaleForTexture( tex->gl_texturenum, xScale, yScale );
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Mem_Free( afile );
|
||||
}
|
||||
|
||||
void Mod_LoadDetailTextures( model_t *mod )
|
||||
{
|
||||
convar_t *r_detailtextures = Cvar_FindVar( "r_detailtextures" );
|
||||
|
||||
if( !r_detailtextures || !r_detailtextures->value )
|
||||
return;
|
||||
|
||||
Mod_ParseDetailTextures( mod );
|
||||
}
|
||||
#endif // !XASH_DEDICATED
|
||||
|
||||
/*
|
||||
=================
|
||||
Mod_LoadTexInfo
|
||||
@@ -3746,6 +4052,103 @@ static int Mod_LumpLooksLikeEntities( const char *lump, const size_t lumplen )
|
||||
return Q_memmem( lump, lumplen, "\"classname\"", sizeof( "\"classname\"" ) - 1 ) != NULL ? 1 : 0;
|
||||
}
|
||||
|
||||
static void Mod_SwapBSPLumps( byte *mod_base, size_t bufferlen )
|
||||
{
|
||||
dheader_t *header = (dheader_t *)mod_base;
|
||||
|
||||
le_struct_swap( dheader_swap, header );
|
||||
|
||||
// BSP30ext pass
|
||||
if( header->version == HLBSP_VERSION && bufferlen > sizeof( *header ) + sizeof( dextrahdr_t ))
|
||||
{
|
||||
dextrahdr_t *ext = (dextrahdr_t *)( mod_base + sizeof( *header ));
|
||||
|
||||
if( ext->id == LittleLong( IDEXTRAHEADER ))
|
||||
le_struct_swap( dextrahdr_swap, ext );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
CRC32_MapFile
|
||||
|
||||
compute CRC for the map lump data
|
||||
=================
|
||||
*/
|
||||
qboolean CRC32_MapFile( dword *crcvalue, const char *filename, qboolean multiplayer )
|
||||
{
|
||||
byte headbuf[sizeof( dheader_t )];
|
||||
char buffer[1024];
|
||||
int i, num_bytes, lumplen;
|
||||
dheader_t *header;
|
||||
file_t *f;
|
||||
|
||||
if( !crcvalue )
|
||||
return false;
|
||||
|
||||
// always calc same checksum for singleplayer
|
||||
if( multiplayer == false )
|
||||
{
|
||||
*crcvalue = (('H'<<24)+('S'<<16)+('A'<<8)+'X');
|
||||
return true;
|
||||
}
|
||||
|
||||
f = FS_Open( filename, "rb", false );
|
||||
if( !f )
|
||||
return false;
|
||||
|
||||
num_bytes = FS_Read( f, headbuf, sizeof( headbuf ));
|
||||
|
||||
if( num_bytes != sizeof( headbuf ))
|
||||
{
|
||||
FS_Close( f );
|
||||
return false;
|
||||
}
|
||||
|
||||
header = (dheader_t *)headbuf;
|
||||
le_struct_swap( dheader_swap, header );
|
||||
|
||||
switch( header->version )
|
||||
{
|
||||
case Q1BSP_VERSION:
|
||||
case HLBSP_VERSION:
|
||||
case QBSP2_VERSION:
|
||||
break;
|
||||
default:
|
||||
FS_Close( f );
|
||||
return false;
|
||||
}
|
||||
|
||||
CRC32_Init( crcvalue );
|
||||
|
||||
for( i = LUMP_PLANES; i < HEADER_LUMPS; i++ )
|
||||
{
|
||||
lumplen = header->lumps[i].filelen;
|
||||
FS_Seek( f, header->lumps[i].fileofs, SEEK_SET );
|
||||
|
||||
while( lumplen > 0 )
|
||||
{
|
||||
if( lumplen >= sizeof( buffer ))
|
||||
num_bytes = FS_Read( f, buffer, sizeof( buffer ));
|
||||
else
|
||||
num_bytes = FS_Read( f, buffer, lumplen );
|
||||
|
||||
if( num_bytes > 0 )
|
||||
{
|
||||
lumplen -= num_bytes;
|
||||
CRC32_ProcessBuffer( crcvalue, buffer, num_bytes );
|
||||
}
|
||||
|
||||
if( FS_Eof( f ))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FS_Close( f );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Mod_FindEndOfBSPFile
|
||||
@@ -3790,20 +4193,26 @@ Mod_FindBSPX
|
||||
find BSPX header position, returns -1 on error
|
||||
=================
|
||||
*/
|
||||
static fs_offset_t Mod_FindBSPX( const byte *mod_base, size_t bufferlen )
|
||||
static fs_offset_t Mod_FindBSPX( byte *mod_base, size_t bufferlen )
|
||||
{
|
||||
fs_offset_t max_offset = Mod_FindEndOfBSPFile( mod_base, bufferlen );
|
||||
const dbspx_hdr_t *bspx_header;
|
||||
|
||||
max_offset = ALIGN( max_offset, 4 ); // force 32-bit boundary
|
||||
|
||||
if( max_offset + sizeof( dbspx_hdr_t ) > bufferlen )
|
||||
return -1;
|
||||
|
||||
bspx_header = (const dbspx_hdr_t *)( mod_base + max_offset );
|
||||
dbspx_hdr_t *bspx_header = (dbspx_hdr_t *)( mod_base + max_offset );
|
||||
|
||||
if( bspx_header->id != LittleLong( IDBSPXHEADER ))
|
||||
return -1;
|
||||
|
||||
bspx_header->id = LittleLong( bspx_header->id );
|
||||
bspx_header->numlumps = LittleLong( bspx_header->numlumps );
|
||||
|
||||
for( int i = 0; i < bspx_header->numlumps; i++ )
|
||||
le_struct_swap( dbspx_lump_swap, &bspx_header->lumps[i] );
|
||||
|
||||
Con_DPrintf( "Found valid BSPX signature at %lld\n", (long long)max_offset );
|
||||
return max_offset;
|
||||
}
|
||||
@@ -3832,6 +4241,9 @@ static qboolean Mod_LoadBmodelLumps( model_t *mod, byte *mod_base, size_t buffer
|
||||
Q_strncpy( loadstat.name, mod->name, sizeof( loadstat.name ));
|
||||
wadvalue[0] = '\0';
|
||||
|
||||
// byte-swap BSP header and lump directory from little-endian
|
||||
Mod_SwapBSPLumps( mod_base, bufferlen );
|
||||
|
||||
// restore default lump numbers
|
||||
srclumps[0].lumpnumber = LUMP_ENTITIES;
|
||||
srclumps[1].lumpnumber = LUMP_PLANES;
|
||||
@@ -4012,6 +4424,9 @@ qboolean Mod_TestBmodelLumps( file_t *f, const char *name, byte *mod_base, size_
|
||||
if( buffersize < sizeof( *header ))
|
||||
return false;
|
||||
|
||||
// byte-swap BSP header and lump directory from little-endian
|
||||
Mod_SwapBSPLumps( mod_base, buffersize );
|
||||
|
||||
// restore default lump numbers
|
||||
srclumps[0].lumpnumber = LUMP_ENTITIES;
|
||||
srclumps[1].lumpnumber = LUMP_PLANES;
|
||||
|
||||
@@ -156,6 +156,7 @@ model_t *Mod_ForName( const char *name, qboolean crash, qboolean trackCRC );
|
||||
qboolean Mod_ValidateCRC( const char *name, uint32_t crc );
|
||||
void Mod_NeedCRC( const char *name, qboolean needCRC );
|
||||
void Mod_FreeUnused( void );
|
||||
void Mod_LoadDetailTextures( model_t *mod );
|
||||
|
||||
//
|
||||
// mod_alias.c
|
||||
@@ -180,7 +181,7 @@ void Mod_PrintWorldStats_f( void );
|
||||
//
|
||||
// mod_studio.c
|
||||
//
|
||||
void Mod_LoadStudioModel( model_t *mod, const void *buffer, qboolean *loaded );
|
||||
void Mod_LoadStudioModel( model_t *mod, void *buffer, size_t buffersize, qboolean *loaded );
|
||||
void Mod_InitStudioAPI( void );
|
||||
void Mod_InitStudioHull( void );
|
||||
void Mod_ResetStudioAPI( void );
|
||||
@@ -190,13 +191,16 @@ void Mod_StudioGetAttachment( const edict_t *e, int iAttachment, float *org, flo
|
||||
void Mod_GetBonePosition( const edict_t *e, int iBone, float *org, float *ang );
|
||||
hull_t *Mod_HullForStudio( model_t *m, float frame, int seq, vec3_t ang, vec3_t org, vec3_t size, byte *pcnt, byte *pbl, int *hitboxes, edict_t *ed );
|
||||
void *R_StudioGetAnim( studiohdr_t *m_pStudioHeader, model_t *m_pSubModel, mstudioseqdesc_t *pseqdesc );
|
||||
void Mod_SwapStudioSeqGroupAnims( studiohdr_t *phdr, mstudioseqdesc_t *pseq, byte *buf );
|
||||
int Mod_HitgroupForStudioHull( int index );
|
||||
void Mod_ClearStudioCache( void );
|
||||
|
||||
//
|
||||
// mod_sprite.c
|
||||
//
|
||||
void Mod_LoadSpriteModel( model_t *mod, const void *buffer, size_t buffersize, qboolean *loaded );
|
||||
#endif
|
||||
void Mod_LoadSpriteModel( model_t *mod, void *buffer, size_t buffersize, qboolean *loaded );
|
||||
void Mod_SpriteLoadTextures( model_t *mod, const void *buffer );
|
||||
void Mod_SpriteUnloadTextures( void *data );
|
||||
|
||||
#endif
|
||||
#endif//MOD_LOCAL_H
|
||||
|
||||
@@ -17,11 +17,166 @@ GNU General Public License for more details.
|
||||
#include "common.h"
|
||||
#include "sprite.h"
|
||||
#include "studio.h"
|
||||
#if !XASH_DEDICATED
|
||||
#include "ref_common.h"
|
||||
#endif // XASH_DEDICATED
|
||||
#include "mod_local.h"
|
||||
#include "swaplib.h"
|
||||
|
||||
le_struct_begin( dsprite_q1_swap )
|
||||
le_struct_field( dsprite_q1_t, ident )
|
||||
le_struct_field( dsprite_q1_t, version )
|
||||
le_struct_field( dsprite_q1_t, type )
|
||||
le_struct_field( dsprite_q1_t, boundingradius )
|
||||
le_struct_array( dsprite_q1_t, bounds, 2 )
|
||||
le_struct_field( dsprite_q1_t, numframes )
|
||||
le_struct_field( dsprite_q1_t, beamlength )
|
||||
le_struct_field( dsprite_q1_t, synctype )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( dsprite_hl_swap )
|
||||
le_struct_field( dsprite_hl_t, ident )
|
||||
le_struct_field( dsprite_hl_t, version )
|
||||
le_struct_field( dsprite_hl_t, type )
|
||||
le_struct_field( dsprite_hl_t, texFormat )
|
||||
le_struct_field( dsprite_hl_t, boundingradius )
|
||||
le_struct_array( dsprite_hl_t, bounds, 2 )
|
||||
le_struct_field( dsprite_hl_t, numframes )
|
||||
le_struct_field( dsprite_hl_t, facetype )
|
||||
le_struct_field( dsprite_hl_t, synctype )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( dspriteframe_swap )
|
||||
le_struct_array( dspriteframe_t, origin, 2 )
|
||||
le_struct_field( dspriteframe_t, width )
|
||||
le_struct_field( dspriteframe_t, height )
|
||||
le_struct_end();
|
||||
|
||||
static byte *Mod_SwapSpriteFrame( byte *p, byte *end, int bytes )
|
||||
{
|
||||
dspriteframe_t *frame;
|
||||
|
||||
if( p + sizeof( *frame ) > end )
|
||||
return NULL;
|
||||
|
||||
frame = (dspriteframe_t *)p;
|
||||
le_struct_swap( dspriteframe_swap, frame );
|
||||
p += sizeof( *frame );
|
||||
|
||||
// skip pixel data
|
||||
if( p + frame->width * frame->height * bytes > end )
|
||||
return NULL;
|
||||
|
||||
p += frame->width * frame->height * bytes;
|
||||
return p;
|
||||
}
|
||||
|
||||
static byte *Mod_SwapSpriteGroup( byte *p, byte *end, int bytes )
|
||||
{
|
||||
dspritegroup_t *group;
|
||||
|
||||
if( p + sizeof( *group ) > end )
|
||||
return NULL;
|
||||
|
||||
group = (dspritegroup_t *)p;
|
||||
group->numframes = LittleLong( group->numframes );
|
||||
p += sizeof( *group );
|
||||
|
||||
// swap intervals
|
||||
int numframes = group->numframes;
|
||||
|
||||
if( p + numframes * sizeof( dspriteinterval_t ) > end )
|
||||
return NULL;
|
||||
|
||||
for( int i = 0; i < numframes; i++ )
|
||||
{
|
||||
dspriteinterval_t *interval = (dspriteinterval_t *)p;
|
||||
interval->interval = LittleFloat( interval->interval );
|
||||
p += sizeof( *interval );
|
||||
}
|
||||
|
||||
// swap each frame in the group
|
||||
for( int i = 0; i < numframes; i++ )
|
||||
{
|
||||
p = Mod_SwapSpriteFrame( p, end, bytes );
|
||||
if( !p )
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static qboolean Mod_SwapSprite( void *buffer, size_t buffersize, int *out_version )
|
||||
{
|
||||
byte *end = (byte *)buffer + buffersize;
|
||||
int version, numframes, bytes;
|
||||
byte *p;
|
||||
|
||||
if( buffersize < sizeof( dsprite_t ))
|
||||
return false;
|
||||
|
||||
// peek at ident + version before full swap
|
||||
version = LittleLong(((dsprite_t *)buffer)->version );
|
||||
|
||||
switch( version )
|
||||
{
|
||||
case SPRITE_VERSION_Q1:
|
||||
case SPRITE_VERSION_32:
|
||||
if( buffersize < sizeof( dsprite_q1_t ))
|
||||
return false;
|
||||
le_struct_swap( dsprite_q1_swap, buffer );
|
||||
numframes = ((dsprite_q1_t *)buffer)->numframes;
|
||||
p = (byte *)buffer + sizeof( dsprite_q1_t );
|
||||
break;
|
||||
case SPRITE_VERSION_HL:
|
||||
{
|
||||
if( buffersize < sizeof( dsprite_hl_t ))
|
||||
return false;
|
||||
le_struct_swap( dsprite_hl_swap, buffer );
|
||||
numframes = ((dsprite_hl_t *)buffer)->numframes;
|
||||
p = (byte *)buffer + sizeof( dsprite_hl_t );
|
||||
|
||||
// HL sprites have a palette count (short) + palette data
|
||||
if( p + sizeof( short ) > end )
|
||||
return false;
|
||||
|
||||
short numi = LittleShort( *(short *)p );
|
||||
*(short *)p = numi;
|
||||
p += sizeof( short ) + numi * 3;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
*out_version = version;
|
||||
bytes = ( version == SPRITE_VERSION_32 ) ? 4 : 1;
|
||||
|
||||
// swap all frames
|
||||
for( int i = 0; i < numframes && p && p < end; i++ )
|
||||
{
|
||||
dframetype_t *frametype;
|
||||
|
||||
if( p + sizeof( *frametype ) > end )
|
||||
return false;
|
||||
|
||||
frametype = (dframetype_t *)p;
|
||||
frametype->type = LittleLong( frametype->type );
|
||||
p += sizeof( *frametype );
|
||||
|
||||
switch( frametype->type )
|
||||
{
|
||||
case FRAME_SINGLE:
|
||||
p = Mod_SwapSpriteFrame( p, end, bytes );
|
||||
break;
|
||||
case FRAME_GROUP:
|
||||
case FRAME_ANGLED:
|
||||
p = Mod_SwapSpriteGroup( p, end, bytes );
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
@@ -30,46 +185,18 @@ Mod_LoadSpriteModel
|
||||
load sprite model
|
||||
====================
|
||||
*/
|
||||
void Mod_LoadSpriteModel( model_t *mod, const void *buffer, size_t buffersize, qboolean *loaded )
|
||||
void Mod_LoadSpriteModel( model_t *mod, void *buffer, size_t buffersize, qboolean *loaded )
|
||||
{
|
||||
const dsprite_t *pin = buffer;
|
||||
msprite_t *psprite;
|
||||
char poolname[MAX_VA_STRING];
|
||||
int version;
|
||||
|
||||
if( loaded )
|
||||
*loaded = false;
|
||||
|
||||
if( buffersize < sizeof( dsprite_t ))
|
||||
if( !Mod_SwapSprite( buffer, buffersize, &version ))
|
||||
{
|
||||
Con_DPrintf( S_ERROR "%s: %s have incorrect file size %zu should be greater than %zu (%s)\n", __func__, mod->name, buffersize, sizeof( dsprite_t ), "basic header" );
|
||||
return;
|
||||
}
|
||||
|
||||
if( pin->ident != IDSPRITEHEADER )
|
||||
{
|
||||
Con_DPrintf( S_ERROR "%s: %s has wrong id (0x%x should be 0x%x)\n", __func__, mod->name, pin->ident, IDSPRITEHEADER );
|
||||
return;
|
||||
}
|
||||
|
||||
switch( pin->version )
|
||||
{
|
||||
case SPRITE_VERSION_Q1:
|
||||
case SPRITE_VERSION_32:
|
||||
if( buffersize < sizeof( dsprite_q1_t ))
|
||||
{
|
||||
Con_DPrintf( S_ERROR "%s: %s have incorrect file size %zu should be greater than %zu (%s)\n", __func__, mod->name, buffersize, sizeof( dsprite_q1_t ), "q1 header" );
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case SPRITE_VERSION_HL:
|
||||
if( buffersize < sizeof( dsprite_hl_t ))
|
||||
{
|
||||
Con_DPrintf( S_ERROR "%s: %s have incorrect file size %zu should be greater than %zu (%s)\n", __func__, mod->name, buffersize, sizeof( dsprite_hl_t ), "hl header" );
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Con_DPrintf( S_ERROR "%s: %s has wrong version number (%i should be %i, %i or %i)\n", __func__, mod->name, pin->version, SPRITE_VERSION_Q1, SPRITE_VERSION_32, SPRITE_VERSION_HL );
|
||||
Con_DPrintf( S_ERROR "%s: %s is not a valid sprite\n", __func__, mod->name );
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -77,9 +204,9 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, size_t buffersize, q
|
||||
Q_snprintf( poolname, sizeof( poolname ), "^2%s^7", mod->name );
|
||||
mod->mempool = Mem_AllocPool( poolname );
|
||||
|
||||
if( pin->version == SPRITE_VERSION_Q1 || pin->version == SPRITE_VERSION_32 )
|
||||
if( version == SPRITE_VERSION_Q1 || version == SPRITE_VERSION_32 )
|
||||
{
|
||||
const dsprite_q1_t *pinq1 = buffer;
|
||||
dsprite_q1_t *pinq1 = buffer;
|
||||
size_t size;
|
||||
|
||||
if( pinq1->numframes == 0 )
|
||||
@@ -109,9 +236,9 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, size_t buffersize, q
|
||||
mod->mins[2] = -pinq1->bounds[1] * 0.5f;
|
||||
mod->maxs[2] = pinq1->bounds[1] * 0.5f;
|
||||
}
|
||||
else // if( pin->version == SPRITE_VERSION_HL )
|
||||
else // if( version == SPRITE_VERSION_HL )
|
||||
{
|
||||
const dsprite_hl_t *pinhl = buffer;
|
||||
dsprite_hl_t *pinhl = buffer;
|
||||
size_t size;
|
||||
|
||||
if( pinhl->numframes == 0 )
|
||||
@@ -147,4 +274,8 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, size_t buffersize, q
|
||||
psprite->numframes = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
#if !XASH_DEDICATED
|
||||
Mod_SpriteLoadTextures( mod, buffer );
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ GNU General Public License for more details.
|
||||
#include "r_studioint.h"
|
||||
#include "library.h"
|
||||
#include "ref_common.h"
|
||||
#include "swaplib.h"
|
||||
|
||||
typedef int (*STUDIOAPI)( int, sv_blending_interface_t**, server_studio_api_t*, float (*transform)[3][4], float (*bones)[MAXSTUDIOBONES][3][4] );
|
||||
|
||||
@@ -58,6 +59,151 @@ static int cache_current;
|
||||
static int cache_current_hull;
|
||||
static int cache_current_plane;
|
||||
|
||||
le_struct_begin( studiohdr_swap )
|
||||
le_struct_field( studiohdr_t, ident )
|
||||
le_struct_field( studiohdr_t, version )
|
||||
le_struct_field( studiohdr_t, length )
|
||||
le_struct_array( studiohdr_t, eyeposition, 3 )
|
||||
le_struct_array( studiohdr_t, min, 3 )
|
||||
le_struct_array( studiohdr_t, max, 3 )
|
||||
le_struct_array( studiohdr_t, bbmin, 3 )
|
||||
le_struct_array( studiohdr_t, bbmax, 3 )
|
||||
le_struct_field( studiohdr_t, flags )
|
||||
le_struct_field( studiohdr_t, numbones )
|
||||
le_struct_field( studiohdr_t, boneindex )
|
||||
le_struct_field( studiohdr_t, numbonecontrollers )
|
||||
le_struct_field( studiohdr_t, bonecontrollerindex )
|
||||
le_struct_field( studiohdr_t, numhitboxes )
|
||||
le_struct_field( studiohdr_t, hitboxindex )
|
||||
le_struct_field( studiohdr_t, numseq )
|
||||
le_struct_field( studiohdr_t, seqindex )
|
||||
le_struct_field( studiohdr_t, numseqgroups )
|
||||
le_struct_field( studiohdr_t, seqgroupindex )
|
||||
le_struct_field( studiohdr_t, numtextures )
|
||||
le_struct_field( studiohdr_t, textureindex )
|
||||
le_struct_field( studiohdr_t, texturedataindex )
|
||||
le_struct_field( studiohdr_t, numskinref )
|
||||
le_struct_field( studiohdr_t, numskinfamilies )
|
||||
le_struct_field( studiohdr_t, skinindex )
|
||||
le_struct_field( studiohdr_t, numbodyparts )
|
||||
le_struct_field( studiohdr_t, bodypartindex )
|
||||
le_struct_field( studiohdr_t, numattachments )
|
||||
le_struct_field( studiohdr_t, attachmentindex )
|
||||
le_struct_field( studiohdr_t, studiohdr2index )
|
||||
le_struct_field( studiohdr_t, numtransitions )
|
||||
le_struct_field( studiohdr_t, transitionindex )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( mstudiobone_swap )
|
||||
le_struct_field( mstudiobone_t, parent )
|
||||
le_struct_field( mstudiobone_t, unused )
|
||||
le_struct_array( mstudiobone_t, bonecontroller, 6 )
|
||||
le_struct_array( mstudiobone_t, value, 6 )
|
||||
le_struct_array( mstudiobone_t, scale, 6 )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( mstudiobonecontroller_swap )
|
||||
le_struct_field( mstudiobonecontroller_t, bone )
|
||||
le_struct_field( mstudiobonecontroller_t, type )
|
||||
le_struct_field( mstudiobonecontroller_t, start )
|
||||
le_struct_field( mstudiobonecontroller_t, end )
|
||||
le_struct_field( mstudiobonecontroller_t, unused )
|
||||
le_struct_field( mstudiobonecontroller_t, index )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( mstudiobbox_swap )
|
||||
le_struct_field( mstudiobbox_t, bone )
|
||||
le_struct_field( mstudiobbox_t, group )
|
||||
le_struct_array( mstudiobbox_t, bbmin, 3 )
|
||||
le_struct_array( mstudiobbox_t, bbmax, 3 )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( mstudioseqgroup_swap )
|
||||
// should we even swap seqgroup?
|
||||
le_struct_field( mstudioseqgroup_t, unused )
|
||||
le_struct_field( mstudioseqgroup_t, unused2 )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( mstudioseqdesc_swap )
|
||||
le_struct_field( mstudioseqdesc_t, fps )
|
||||
le_struct_field( mstudioseqdesc_t, flags )
|
||||
le_struct_field( mstudioseqdesc_t, activity )
|
||||
le_struct_field( mstudioseqdesc_t, actweight )
|
||||
le_struct_field( mstudioseqdesc_t, numevents )
|
||||
le_struct_field( mstudioseqdesc_t, eventindex )
|
||||
le_struct_field( mstudioseqdesc_t, numframes )
|
||||
le_struct_field( mstudioseqdesc_t, weightlistindex )
|
||||
le_struct_field( mstudioseqdesc_t, iklockindex )
|
||||
le_struct_field( mstudioseqdesc_t, motiontype )
|
||||
le_struct_field( mstudioseqdesc_t, motionbone )
|
||||
le_struct_array( mstudioseqdesc_t, linearmovement, 3 )
|
||||
le_struct_field( mstudioseqdesc_t, autolayerindex )
|
||||
le_struct_field( mstudioseqdesc_t, keyvalueindex )
|
||||
le_struct_array( mstudioseqdesc_t, bbmin, 3 )
|
||||
le_struct_array( mstudioseqdesc_t, bbmax, 3 )
|
||||
le_struct_field( mstudioseqdesc_t, numblends )
|
||||
le_struct_field( mstudioseqdesc_t, animindex )
|
||||
le_struct_array( mstudioseqdesc_t, blendtype, 2 )
|
||||
le_struct_array( mstudioseqdesc_t, blendstart, 2 )
|
||||
le_struct_array( mstudioseqdesc_t, blendend, 2 )
|
||||
le_struct_field( mstudioseqdesc_t, seqgroup )
|
||||
le_struct_field( mstudioseqdesc_t, entrynode )
|
||||
le_struct_field( mstudioseqdesc_t, exitnode )
|
||||
le_struct_field( mstudioseqdesc_t, animdescindex )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( mstudioevent_swap )
|
||||
le_struct_field( mstudioevent_t, frame )
|
||||
le_struct_field( mstudioevent_t, event )
|
||||
le_struct_field( mstudioevent_t, unused )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( mstudioattachment_swap )
|
||||
le_struct_field( mstudioattachment_t, flags )
|
||||
le_struct_field( mstudioattachment_t, bone )
|
||||
le_struct_array( mstudioattachment_t, org, 3 )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( mstudiobodyparts_swap )
|
||||
le_struct_field( mstudiobodyparts_t, nummodels )
|
||||
le_struct_field( mstudiobodyparts_t, base )
|
||||
le_struct_field( mstudiobodyparts_t, modelindex )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( mstudiotexture_swap )
|
||||
le_struct_field( mstudiotexture_t, flags )
|
||||
le_struct_field( mstudiotexture_t, width )
|
||||
le_struct_field( mstudiotexture_t, height )
|
||||
le_struct_field( mstudiotexture_t, index )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( mstudiomodel_swap )
|
||||
le_struct_field( mstudiomodel_t, unused )
|
||||
le_struct_field( mstudiomodel_t, unused2 )
|
||||
le_struct_field( mstudiomodel_t, nummesh )
|
||||
le_struct_field( mstudiomodel_t, meshindex )
|
||||
le_struct_field( mstudiomodel_t, numverts )
|
||||
le_struct_field( mstudiomodel_t, vertinfoindex )
|
||||
le_struct_field( mstudiomodel_t, vertindex )
|
||||
le_struct_field( mstudiomodel_t, numnorms )
|
||||
le_struct_field( mstudiomodel_t, norminfoindex )
|
||||
le_struct_field( mstudiomodel_t, normindex )
|
||||
le_struct_field( mstudiomodel_t, blendvertinfoindex )
|
||||
le_struct_field( mstudiomodel_t, blendnorminfoindex )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( mstudiomesh_swap )
|
||||
le_struct_field( mstudiomesh_t, numtris )
|
||||
le_struct_field( mstudiomesh_t, triindex )
|
||||
le_struct_field( mstudiomesh_t, skinref )
|
||||
le_struct_field( mstudiomesh_t, numnorms )
|
||||
le_struct_field( mstudiomesh_t, unused )
|
||||
le_struct_end();
|
||||
|
||||
le_struct_begin( mstudioanim_swap )
|
||||
le_struct_array( mstudioanim_t, offset, 6 )
|
||||
le_struct_end();
|
||||
|
||||
/*
|
||||
====================
|
||||
Mod_InitStudioHull
|
||||
@@ -404,6 +550,38 @@ static void Mod_StudioCalcRotations( int boneused[], int numbones, const byte *p
|
||||
}
|
||||
|
||||
|
||||
void Mod_SwapStudioSeqGroupAnims( studiohdr_t *phdr, mstudioseqdesc_t *pseq, byte *buf )
|
||||
{
|
||||
mstudioanim_t *panim = (mstudioanim_t *)( buf + pseq->animindex );
|
||||
int numanims = pseq->numblends * phdr->numbones;
|
||||
|
||||
for( int j = 0; j < numanims; j++, panim++ )
|
||||
{
|
||||
le_struct_swap( mstudioanim_swap, panim );
|
||||
|
||||
for( int k = 0; k < 6; k++ )
|
||||
{
|
||||
if( panim->offset[k] == 0 )
|
||||
continue;
|
||||
|
||||
mstudioanimvalue_t *panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[k] );
|
||||
|
||||
int frames = pseq->numframes;
|
||||
while( frames > 0 )
|
||||
{
|
||||
int valid = panimvalue->num.valid;
|
||||
int total = panimvalue->num.total;
|
||||
|
||||
for( int l = 1; l <= valid; l++ )
|
||||
panimvalue[l].value = LittleShort( panimvalue[l].value );
|
||||
|
||||
panimvalue += valid + 1;
|
||||
frames -= total;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
StudioGetAnim
|
||||
@@ -412,17 +590,10 @@ StudioGetAnim
|
||||
*/
|
||||
void *R_StudioGetAnim( studiohdr_t *m_pStudioHeader, model_t *m_pSubModel, mstudioseqdesc_t *pseqdesc )
|
||||
{
|
||||
mstudioseqgroup_t *pseqgroup;
|
||||
cache_user_t *paSequences;
|
||||
fs_offset_t filesize;
|
||||
byte *buf;
|
||||
|
||||
pseqgroup = (mstudioseqgroup_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqgroupindex) + pseqdesc->seqgroup;
|
||||
if( pseqdesc->seqgroup == 0 )
|
||||
return ((byte *)m_pStudioHeader + pseqdesc->animindex);
|
||||
|
||||
paSequences = (cache_user_t *)m_pSubModel->submodels;
|
||||
|
||||
cache_user_t *paSequences = (cache_user_t *)m_pSubModel->submodels;
|
||||
if( paSequences == NULL )
|
||||
{
|
||||
paSequences = (cache_user_t *)Mem_Calloc( com_studiocache, MAXSTUDIOGROUPS * sizeof( cache_user_t ));
|
||||
@@ -432,23 +603,31 @@ void *R_StudioGetAnim( studiohdr_t *m_pStudioHeader, model_t *m_pSubModel, mstud
|
||||
// check for already loaded
|
||||
if( !Mod_CacheCheck(( cache_user_t *)&( paSequences[pseqdesc->seqgroup] )))
|
||||
{
|
||||
string filepath, modelname, modelpath;
|
||||
|
||||
string modelname;
|
||||
COM_FileBase( m_pSubModel->name, modelname, sizeof( modelname ));
|
||||
|
||||
string modelpath;
|
||||
COM_ExtractFilePath( m_pSubModel->name, modelpath );
|
||||
|
||||
// NOTE: here we build real sub-animation filename because stupid user may rename model without recompile
|
||||
string filepath;
|
||||
Q_snprintf( filepath, sizeof( filepath ), "%s/%s%i%i.mdl", modelpath, modelname, pseqdesc->seqgroup / 10, pseqdesc->seqgroup % 10 );
|
||||
|
||||
buf = FS_LoadFile( filepath, &filesize, false );
|
||||
if( !buf || !filesize ) Host_Error( "%s: can't load %s\n", __func__, filepath );
|
||||
if( IDSEQGRPHEADER != *(uint *)buf ) Host_Error( "%s: %s is corrupted\n", __func__, filepath );
|
||||
fs_offset_t filesize;
|
||||
byte *buf = FS_LoadFile( filepath, &filesize, false );
|
||||
if( !buf || !filesize )
|
||||
Host_Error( "%s: can't load %s\n", __func__, filepath );
|
||||
if( LittleLong( IDSEQGRPHEADER ) != *(uint *)buf )
|
||||
Host_Error( "%s: %s is corrupted\n", __func__, filepath );
|
||||
|
||||
Con_Printf( "loading: %s\n", filepath );
|
||||
|
||||
paSequences[pseqdesc->seqgroup].data = Mem_Calloc( com_studiocache, filesize );
|
||||
memcpy( paSequences[pseqdesc->seqgroup].data, buf, filesize );
|
||||
Mem_Free( buf );
|
||||
|
||||
Mod_SwapStudioSeqGroupAnims( m_pStudioHeader, pseqdesc,
|
||||
(byte *)paSequences[pseqdesc->seqgroup].data );
|
||||
}
|
||||
|
||||
return ((byte *)paSequences[pseqdesc->seqgroup].data + pseqdesc->animindex);
|
||||
@@ -690,7 +869,6 @@ static void Mod_StudioComputeBounds( void *buffer, vec3_t mins, vec3_t maxs, qbo
|
||||
vec3_t bone_mins, bone_maxs;
|
||||
vec3_t vert_mins, vert_maxs;
|
||||
int vert_count, bone_count;
|
||||
int bodyCount = 0;
|
||||
vec3_t pos, *pverts;
|
||||
|
||||
vert_count = bone_count = 0;
|
||||
@@ -706,18 +884,16 @@ static void Mod_StudioComputeBounds( void *buffer, vec3_t mins, vec3_t maxs, qbo
|
||||
// each body part has nummodels variations so there are as many total variations as there
|
||||
// are in a matrix of each part by each other part
|
||||
for( i = 0; i < pstudiohdr->numbodyparts; i++ )
|
||||
bodyCount += pbodypart[i].nummodels;
|
||||
|
||||
// The studio models we want are vec3_t mins, vec3_t maxsight after the bodyparts (still need to
|
||||
// find a detailed breakdown of the mdl format). Move pointer there.
|
||||
m_pSubModel = (mstudiomodel_t *)(&pbodypart[pstudiohdr->numbodyparts]);
|
||||
|
||||
for( i = 0; i < bodyCount; i++ )
|
||||
{
|
||||
pverts = (vec3_t *)((byte *)pstudiohdr + m_pSubModel[i].vertindex);
|
||||
m_pSubModel = (mstudiomodel_t *)((byte *)pstudiohdr + pbodypart[i].modelindex);
|
||||
|
||||
for( j = 0; j < m_pSubModel[i].numverts; j++ )
|
||||
Mod_StudioBoundVertex( bone_mins, bone_maxs, &vert_count, pverts[j] );
|
||||
for( j = 0; j < pbodypart[i].nummodels; j++ )
|
||||
{
|
||||
pverts = (vec3_t *)((byte *)pstudiohdr + m_pSubModel[j].vertindex);
|
||||
|
||||
for( k = 0; k < m_pSubModel[j].numverts; k++ )
|
||||
Mod_StudioBoundVertex( bone_mins, bone_maxs, &vert_count, pverts[k] );
|
||||
}
|
||||
}
|
||||
|
||||
pbones = (mstudiobone_t *)((byte *)pstudiohdr + pstudiohdr->boneindex);
|
||||
@@ -820,26 +996,123 @@ static int Mod_StudioBodyVariations( model_t *mod )
|
||||
return count;
|
||||
}
|
||||
|
||||
static qboolean Mod_SwapStudioModel( const char *name, void *buffer, size_t buffersize )
|
||||
{
|
||||
studiohdr_t *phdr = buffer;
|
||||
byte *mod_base = buffer;
|
||||
|
||||
if( buffersize < sizeof( studiohdr_t ))
|
||||
return false;
|
||||
|
||||
le_struct_swap( studiohdr_swap, phdr );
|
||||
|
||||
if( phdr->ident != IDSTUDIOHEADER || phdr->version != STUDIO_VERSION )
|
||||
return false;
|
||||
|
||||
|
||||
|
||||
|
||||
#if XASH_BIG_ENDIAN
|
||||
if( phdr->studiohdr2index > 0 && phdr->studiohdr2index < phdr->length )
|
||||
{
|
||||
Con_Printf( S_ERROR "byteswapping extended studio model \"%s\" is unsupoprted\n", name );
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
for( int i = 0; i < phdr->numbones; i++ )
|
||||
le_struct_swap( mstudiobone_swap, (mstudiobone_t *)( mod_base + phdr->boneindex ) + i );
|
||||
|
||||
for( int i = 0; i < phdr->numbonecontrollers; i++ )
|
||||
le_struct_swap( mstudiobonecontroller_swap, (mstudiobonecontroller_t *)( mod_base + phdr->bonecontrollerindex ) + i );
|
||||
|
||||
for( int i = 0; i < phdr->numhitboxes; i++ )
|
||||
le_struct_swap( mstudiobbox_swap, (mstudiobbox_t *)( mod_base + phdr->hitboxindex ) + i );
|
||||
|
||||
for( int i = 0; i < phdr->numseqgroups; i++ )
|
||||
le_struct_swap( mstudioseqgroup_swap, (mstudioseqgroup_t *)( mod_base + phdr->seqgroupindex ) + i );
|
||||
|
||||
for( int i = 0; i < phdr->numattachments; i++ )
|
||||
{
|
||||
mstudioattachment_t *pattach = (mstudioattachment_t *)( mod_base + phdr->attachmentindex ) + i;
|
||||
le_struct_swap( mstudioattachment_swap, pattach );
|
||||
le_array_swap((float *)pattach->vectors, 3 * 3 );
|
||||
}
|
||||
|
||||
for( int i = 0; i < phdr->numtextures; i++ )
|
||||
le_struct_swap( mstudiotexture_swap, (mstudiotexture_t *)( mod_base + phdr->textureindex ) + i );
|
||||
|
||||
for( int i = 0; i < phdr->numbodyparts; i++ )
|
||||
le_struct_swap( mstudiobodyparts_swap, (mstudiobodyparts_t *)( mod_base + phdr->bodypartindex ) + i );
|
||||
|
||||
for( int i = 0; i < phdr->numseq; i++ )
|
||||
{
|
||||
mstudioseqdesc_t *pseq = (mstudioseqdesc_t *)( mod_base + phdr->seqindex ) + i;
|
||||
le_struct_swap( mstudioseqdesc_swap, pseq );
|
||||
|
||||
for( int j = 0; j < pseq->numevents; j++ )
|
||||
le_struct_swap( mstudioevent_swap, (mstudioevent_t *)( mod_base + pseq->eventindex ) + j );
|
||||
|
||||
if( pseq->seqgroup != 0 )
|
||||
continue;
|
||||
|
||||
Mod_SwapStudioSeqGroupAnims( phdr, pseq, mod_base );
|
||||
}
|
||||
|
||||
for( int i = 0; i < phdr->numbodyparts; i++ )
|
||||
{
|
||||
mstudiobodyparts_t *pbodypart = (mstudiobodyparts_t *)( mod_base + phdr->bodypartindex ) + i;
|
||||
|
||||
for( int j = 0; j < pbodypart->nummodels; j++ )
|
||||
{
|
||||
mstudiomodel_t *pmodel = (mstudiomodel_t *)( mod_base + pbodypart->modelindex ) + j;
|
||||
le_struct_swap( mstudiomodel_swap, pmodel );
|
||||
|
||||
le_array_swap((float *)( mod_base + pmodel->vertindex ), pmodel->numverts * 3 );
|
||||
le_array_swap((float *)( mod_base + pmodel->normindex ), pmodel->numnorms * 3 );
|
||||
|
||||
for( int k = 0; k < pmodel->nummesh; k++ )
|
||||
{
|
||||
mstudiomesh_t *pmesh = (mstudiomesh_t *)( mod_base + pmodel->meshindex ) + k;
|
||||
le_struct_swap( mstudiomesh_swap, pmesh );
|
||||
|
||||
short *ptricmds = (short *)( mod_base + pmesh->triindex );
|
||||
short n;
|
||||
while(( n = LittleShort( *ptricmds )))
|
||||
{
|
||||
*ptricmds++ = n;
|
||||
int count = abs( n ) * 4;
|
||||
for( int l = 0; l < count; l++, ptricmds++ )
|
||||
*ptricmds = LittleShort( *ptricmds );
|
||||
}
|
||||
*ptricmds = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
short *pskinref = (short *)( mod_base + phdr->skinindex );
|
||||
for( int i = 0; i < phdr->numskinfamilies * phdr->numskinref; i++ )
|
||||
pskinref[i] = LittleShort( pskinref[i] );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
R_StudioLoadHeader
|
||||
=================
|
||||
*/
|
||||
static studiohdr_t *R_StudioLoadHeader( model_t *mod, const void *buffer )
|
||||
static studiohdr_t *R_StudioLoadHeader( model_t *mod, void *buffer, size_t buffersize )
|
||||
{
|
||||
byte *pin;
|
||||
studiohdr_t *phdr;
|
||||
int i;
|
||||
studiohdr_t *phdr;
|
||||
|
||||
if( !buffer ) return NULL;
|
||||
if( !buffer )
|
||||
return NULL;
|
||||
|
||||
pin = (byte *)buffer;
|
||||
phdr = (studiohdr_t *)pin;
|
||||
i = phdr->version;
|
||||
|
||||
if( i != STUDIO_VERSION )
|
||||
if( !Mod_SwapStudioModel( mod->name, buffer, buffersize ))
|
||||
{
|
||||
Con_Printf( S_ERROR "%s has wrong version number (%i should be %i)\n", mod->name, i, STUDIO_VERSION );
|
||||
phdr = (studiohdr_t *)buffer;
|
||||
Con_Printf( S_ERROR "%s has wrong version number (%i should be %i)\n", mod->name, phdr->version, STUDIO_VERSION );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -867,7 +1140,7 @@ static studiohdr_t *Mod_MaybeTruncateStudioTextureData( model_t *mod )
|
||||
Mod_LoadStudioModel
|
||||
=================
|
||||
*/
|
||||
void Mod_LoadStudioModel( model_t *mod, const void *buffer, qboolean *loaded )
|
||||
void Mod_LoadStudioModel( model_t *mod, void *buffer, size_t buffersize, qboolean *loaded )
|
||||
{
|
||||
char poolname[MAX_VA_STRING];
|
||||
studiohdr_t *phdr;
|
||||
@@ -879,7 +1152,7 @@ void Mod_LoadStudioModel( model_t *mod, const void *buffer, qboolean *loaded )
|
||||
mod->mempool = Mem_AllocPool( poolname );
|
||||
mod->type = mod_studio;
|
||||
|
||||
phdr = R_StudioLoadHeader( mod, buffer );
|
||||
phdr = R_StudioLoadHeader( mod, buffer, buffersize );
|
||||
if( !phdr || phdr->length < sizeof( studiohdr_t )) // garbage value in length
|
||||
return; // bad model
|
||||
|
||||
@@ -888,9 +1161,10 @@ void Mod_LoadStudioModel( model_t *mod, const void *buffer, qboolean *loaded )
|
||||
{
|
||||
studiohdr_t *thdr;
|
||||
void *buffer2;
|
||||
fs_offset_t size2_len;
|
||||
|
||||
buffer2 = FS_LoadFile( Mod_StudioTexName( mod->name ), NULL, false );
|
||||
thdr = R_StudioLoadHeader( mod, buffer2 );
|
||||
buffer2 = FS_LoadFile( Mod_StudioTexName( mod->name ), &size2_len, false );
|
||||
thdr = R_StudioLoadHeader( mod, buffer2, size2_len );
|
||||
|
||||
if( thdr != NULL )
|
||||
{
|
||||
|
||||
@@ -88,6 +88,22 @@ static void Mod_Modellist_f( void )
|
||||
Con_Printf( "\n" );
|
||||
}
|
||||
|
||||
static void Mod_UnloadRenderData( model_t *mod )
|
||||
{
|
||||
#if !XASH_DEDICATED
|
||||
switch( mod->type )
|
||||
{
|
||||
case mod_sprite:
|
||||
Mod_SpriteUnloadTextures( mod->cache.data );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ref.dllFuncs.Mod_ProcessRenderData( mod, false, NULL, 0 );
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Mod_FreeUserData
|
||||
@@ -107,12 +123,10 @@ static void Mod_FreeUserData( model_t *mod )
|
||||
svgame.physFuncs.Mod_ProcessUserData( mod, false, NULL );
|
||||
}
|
||||
}
|
||||
#if !XASH_DEDICATED
|
||||
else
|
||||
{
|
||||
ref.dllFuncs.Mod_ProcessRenderData( mod, false, NULL, 0 );
|
||||
Mod_UnloadRenderData( mod );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -333,7 +347,7 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
|
||||
switch( *(uint *)buf )
|
||||
{
|
||||
case LittleLong( IDSTUDIOHEADER ):
|
||||
Mod_LoadStudioModel( mod, buf, &loaded );
|
||||
Mod_LoadStudioModel( mod, buf, length, &loaded );
|
||||
break;
|
||||
case LittleLong( IDSPRITEHEADER ):
|
||||
Mod_LoadSpriteModel( mod, buf, length, &loaded );
|
||||
@@ -594,6 +608,31 @@ void GAME_EXPORT Mod_LoadCacheFile( const char *filename, cache_user_t *cu )
|
||||
cu->data = Mem_Malloc( com_studiocache, size );
|
||||
memcpy( cu->data, buf, size );
|
||||
Mem_Free( buf );
|
||||
|
||||
// this handles when studio model renderer tries to load sequence files on it's own
|
||||
// which is what they always do in HLSDK
|
||||
#if XASH_BIG_ENDIAN
|
||||
if( size >= sizeof( int ) && LittleLong( IDSEQGRPHEADER ) == *(uint *)cu->data )
|
||||
{
|
||||
studiohdr_t *phdr = (studiohdr_t *)REF_GET_PARM( PARM_GET_STUDIO_HDR, 0 );
|
||||
if( !phdr )
|
||||
return;
|
||||
|
||||
mstudioseqdesc_t *pseq = (mstudioseqdesc_t *)((byte *)phdr + phdr->seqindex );
|
||||
|
||||
for( int i = 0; i < phdr->numseq; i++ )
|
||||
{
|
||||
if( pseq[i].seqgroup == 0 )
|
||||
continue;
|
||||
|
||||
mstudioseqgroup_t *pgrp = (mstudioseqgroup_t *)((byte *)phdr + phdr->seqgroupindex ) + pseq[i].seqgroup;
|
||||
|
||||
// assuming filename passes seqgroup's name
|
||||
if( !Q_stricmp( pgrp->name, filename ))
|
||||
Mod_SwapStudioSeqGroupAnims( phdr, &pseq[i], (byte *)cu->data );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -321,8 +321,10 @@ void MSG_WriteUBitLong( sizebuf_t *sb, uint curData, int numbits )
|
||||
}
|
||||
|
||||
iCurBitMasked = iCurBit & 31;
|
||||
((uint32_t *)sb->pData)[iDWord] &= BitWriteMasks[iCurBitMasked][nBitsLeft-1];
|
||||
((uint32_t *)sb->pData)[iDWord] |= curData << iCurBitMasked;
|
||||
uint32_t dword = LittleLong(((uint32_t *)sb->pData)[iDWord] );
|
||||
dword &= BitWriteMasks[iCurBitMasked][nBitsLeft-1];
|
||||
dword |= curData << iCurBitMasked;
|
||||
((uint32_t *)sb->pData)[iDWord] = LittleLong( dword );
|
||||
|
||||
// did it span a dword?
|
||||
nBitsWritten = 32 - iCurBitMasked;
|
||||
@@ -334,8 +336,10 @@ void MSG_WriteUBitLong( sizebuf_t *sb, uint curData, int numbits )
|
||||
curData >>= nBitsWritten;
|
||||
|
||||
iCurBitMasked = iCurBit & 31;
|
||||
((uint32_t *)sb->pData)[iDWord+1] &= BitWriteMasks[iCurBitMasked][nBitsLeft-1];
|
||||
((uint32_t *)sb->pData)[iDWord+1] |= curData << iCurBitMasked;
|
||||
uint32_t dword2 = LittleLong(((uint32_t *)sb->pData)[iDWord+1] );
|
||||
dword2 &= BitWriteMasks[iCurBitMasked][nBitsLeft-1];
|
||||
dword2 |= curData << iCurBitMasked;
|
||||
((uint32_t *)sb->pData)[iDWord+1] = LittleLong( dword2 );
|
||||
}
|
||||
sb->iCurBit += numbits;
|
||||
}
|
||||
@@ -396,7 +400,8 @@ qboolean MSG_WriteBits( sizebuf_t *sb, const void *pData, int nBits )
|
||||
// read dwords.
|
||||
while( nBitsLeft >= 32 )
|
||||
{
|
||||
MSG_WriteUBitLong( sb, *(( uint32_t *)pOut ), 32 );
|
||||
uint32_t dword = *((uint32_t *)pOut);
|
||||
MSG_WriteUBitLong( sb, LittleLong( dword ), 32 );
|
||||
|
||||
pOut += sizeof( uint32_t );
|
||||
nBitsLeft -= 32;
|
||||
@@ -519,7 +524,7 @@ void MSG_WriteDword( sizebuf_t *sb, uint val )
|
||||
|
||||
void MSG_WriteFloat( sizebuf_t *sb, float val )
|
||||
{
|
||||
MSG_WriteBits( sb, &val, sizeof( val ) << 3 );
|
||||
MSG_WriteUBitLong( sb, FloatAsUint( val ), sizeof( val ) << 3 );
|
||||
}
|
||||
|
||||
qboolean MSG_WriteBytes( sizebuf_t *sb, const void *pBuf, int nBytes )
|
||||
@@ -593,7 +598,7 @@ uint MSG_ReadUBitLong( sizebuf_t *sb, int numbits )
|
||||
|
||||
// Read the current dword.
|
||||
idword1 = sb->iCurBit >> 5;
|
||||
dword1 = ((uint *)sb->pData)[idword1];
|
||||
dword1 = LittleLong(((uint *)sb->pData)[idword1] );
|
||||
dword1 >>= ( sb->iCurBit & 31 ); // get the bits we're interested in.
|
||||
|
||||
sb->iCurBit += numbits;
|
||||
@@ -608,7 +613,7 @@ uint MSG_ReadUBitLong( sizebuf_t *sb, int numbits )
|
||||
else
|
||||
{
|
||||
int nExtraBits = sb->iCurBit & 31;
|
||||
uint dword2 = ((uint *)sb->pData)[idword1+1] & ExtraMasks[nExtraBits];
|
||||
uint dword2 = LittleLong(((uint *)sb->pData)[idword1+1] ) & ExtraMasks[nExtraBits];
|
||||
|
||||
// no need to mask since we hit the end of the dword.
|
||||
// shift the second dword's part into the high bits.
|
||||
@@ -633,7 +638,8 @@ qboolean MSG_ReadBits( sizebuf_t *sb, void *pOutData, int nBits )
|
||||
// read dwords.
|
||||
while( nBitsLeft >= 32 )
|
||||
{
|
||||
*((uint32_t *)pOut) = MSG_ReadUBitLong( sb, 32 );
|
||||
uint32_t dword = MSG_ReadUBitLong( sb, 32 );
|
||||
*((uint32_t *)pOut) = LittleLong( dword );
|
||||
pOut += sizeof( uint32_t );
|
||||
nBitsLeft -= 32;
|
||||
}
|
||||
@@ -790,11 +796,7 @@ uint MSG_ReadDword( sizebuf_t *sb )
|
||||
|
||||
float MSG_ReadFloat( sizebuf_t *sb )
|
||||
{
|
||||
float ret;
|
||||
|
||||
MSG_ReadBits( sb, &ret, sizeof( ret ) << 3 );
|
||||
|
||||
return ret;
|
||||
return UintAsFloat( MSG_ReadUBitLong( sb, sizeof( float ) << 3 ));
|
||||
}
|
||||
|
||||
qboolean MSG_ReadBytes( sizebuf_t *sb, void *pOut, int nBytes )
|
||||
|
||||
@@ -617,7 +617,10 @@ void Netchan_AddBufferToList( fragbuf_t **pplist, fragbuf_t *pbuf )
|
||||
if( id1 > id2 )
|
||||
{
|
||||
// insert here
|
||||
pbuf->next = n->next;
|
||||
// pbuf->next = n->next;
|
||||
|
||||
// a1ba: this seems to be incorrect insertion, as `n` gets removed from list and effectively leaked
|
||||
pbuf->next = n;
|
||||
pprev->next = pbuf;
|
||||
return;
|
||||
}
|
||||
@@ -1314,14 +1317,14 @@ 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( chan->use_lzss && LZSS_IsCompressed( buffer, nsize ))
|
||||
{
|
||||
byte *uncompressedBuffer;
|
||||
|
||||
uncompressedSize = LZSS_GetActualSize( buffer, nsize + 1 ) + 1;
|
||||
uncompressedSize = LZSS_GetActualSize( buffer, nsize );
|
||||
uncompressedBuffer = Mem_Calloc( net_mempool, uncompressedSize );
|
||||
|
||||
nsize = LZSS_Decompress( buffer, uncompressedBuffer, nsize + 1, uncompressedSize );
|
||||
nsize = LZSS_Decompress( buffer, uncompressedBuffer, nsize, uncompressedSize );
|
||||
Mem_Free( buffer );
|
||||
buffer = uncompressedBuffer;
|
||||
}
|
||||
|
||||
@@ -84,37 +84,37 @@ void Sound_Shutdown( void )
|
||||
|
||||
uint GAME_EXPORT Sound_GetApproxWavePlayLen( const char *filepath )
|
||||
{
|
||||
string name;
|
||||
file_t *f;
|
||||
wavehdr_t wav;
|
||||
size_t filesize;
|
||||
uint msecs;
|
||||
|
||||
string name;
|
||||
Q_strncpy( name, filepath, sizeof( name ));
|
||||
COM_FixSlashes( name );
|
||||
|
||||
f = FS_Open( name, "rb", false );
|
||||
file_t *f = FS_Open( name, "rb", false );
|
||||
if( !f )
|
||||
return 0;
|
||||
|
||||
wavehdr_t wav;
|
||||
if( FS_Read( f, &wav, sizeof( wav )) != sizeof( wav ))
|
||||
{
|
||||
FS_Close( f );
|
||||
return 0;
|
||||
}
|
||||
|
||||
filesize = FS_FileLength( f );
|
||||
filesize -= 128; // magic number from GoldSrc, seems to be header size
|
||||
// magic number from GoldSrc, seems to be header size
|
||||
size_t filesize = FS_FileLength( f ) - 128;
|
||||
|
||||
FS_Close( f );
|
||||
|
||||
// is real wav file ?
|
||||
if( wav.riff_id != RIFFHEADER || wav.wave_id != WAVEHEADER || wav.fmt_id != FORMHEADER )
|
||||
if( wav.riff_id != LittleLong( RIFFHEADER ) || wav.wave_id != LittleLong( WAVEHEADER ) || wav.fmt_id != LittleLong( FORMHEADER ))
|
||||
return 0;
|
||||
|
||||
if( wav.nAvgBytesPerSec >= 1000 )
|
||||
msecs = (uint)((float)filesize / ((float)wav.nAvgBytesPerSec / 1000.0f));
|
||||
else msecs = (uint)(((float)filesize / (float)wav.nAvgBytesPerSec) * 1000.0f);
|
||||
int avgBytes = LittleLong( wav.nAvgBytesPerSec );
|
||||
uint msecs;
|
||||
|
||||
if( avgBytes >= 1000 )
|
||||
msecs = (uint)((float)filesize / ((float)avgBytes / 1000.0f));
|
||||
else
|
||||
msecs = (uint)(((float)filesize / (float)avgBytes) * 1000.0f);
|
||||
|
||||
return msecs;
|
||||
}
|
||||
|
||||
@@ -61,6 +61,8 @@ SYSTEM LOG
|
||||
*/
|
||||
int Sys_LogFileNo( void )
|
||||
{
|
||||
if( !s_ld.logfile )
|
||||
return -1;
|
||||
return s_ld.logfileno;
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,17 @@ void Platform_MessageBox( const char *title, const char *message, qboolean paren
|
||||
void Platform_SetStatus( const char *status );
|
||||
qboolean Platform_DebuggerPresent( void );
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ORIENTATION_UNKNOWN = 0,
|
||||
ORIENTATION_LANDSCAPE,
|
||||
ORIENTATION_LANDSCAPE_FLIPPED,
|
||||
ORIENTATION_PORTRAIT,
|
||||
ORIENTATION_PORTRAIT_FLIPPED
|
||||
} platform_orientation_t;
|
||||
|
||||
platform_orientation_t Platform_GetDisplayOrientation( void );
|
||||
|
||||
// legacy iOS port functions
|
||||
#if XASH_IOS
|
||||
int IOS_GetArgs( char ***argv );
|
||||
@@ -64,6 +75,7 @@ char *Posix_Input( void );
|
||||
void SDLash_Init( void );
|
||||
void SDLash_Shutdown( void );
|
||||
void SDLash_NanoSleep( int nsec );
|
||||
qboolean SDLash_GyroIsAvailable( void );
|
||||
#endif
|
||||
|
||||
#if XASH_ANDROID
|
||||
|
||||
@@ -27,15 +27,10 @@ static qboolean enable_libbacktrace;
|
||||
|
||||
static void Sys_BacktraceError( void *data, const char *msg, int errnum )
|
||||
{
|
||||
if( errnum < 0 )
|
||||
{
|
||||
Con_Printf( S_ERROR "no symbol info, no libbacktrace\n" );
|
||||
return;
|
||||
}
|
||||
Con_Printf( S_ERROR "libbacktrace: %s (%d)\n", msg, errnum );
|
||||
|
||||
Con_Printf( S_ERROR "libbacktrace error: %s (%d)\n", msg, errnum );
|
||||
|
||||
enable_libbacktrace = false;
|
||||
if( errnum > 0 )
|
||||
enable_libbacktrace = false;
|
||||
}
|
||||
|
||||
struct print_data
|
||||
@@ -45,8 +40,16 @@ struct print_data
|
||||
int len;
|
||||
int idx;
|
||||
int logfd;
|
||||
qboolean skip_wrappers;
|
||||
};
|
||||
|
||||
static qboolean Sys_IsCrashHandlerFrame( const char *name )
|
||||
{
|
||||
if( !name )
|
||||
return false;
|
||||
return !Q_strcmp( name, "Sys_Crash" ) || !Q_strcmp( name, "Sys_CrashDetailsLibbacktrace" );
|
||||
}
|
||||
|
||||
static void Sys_AppendPrint( struct print_data *pd, const char *fmt, ... )
|
||||
{
|
||||
va_list va;
|
||||
@@ -58,13 +61,10 @@ static void Sys_AppendPrint( struct print_data *pd, const char *fmt, ... )
|
||||
|
||||
if( len > 0 )
|
||||
{
|
||||
char ch = '\n';
|
||||
|
||||
write( pd->logfd, pd->message, len );
|
||||
write( pd->logfd, &ch, 1 );
|
||||
if( pd->logfd >= 0 )
|
||||
write( pd->logfd, pd->message, len );
|
||||
|
||||
write( STDERR_FILENO, pd->message, len );
|
||||
write( STDERR_FILENO, &ch, 1 );
|
||||
|
||||
pd->message += len;
|
||||
pd->len += len;
|
||||
@@ -84,6 +84,13 @@ static void Sys_BacktracePrintSyminfo( void *data, uintptr_t pc, const char *sym
|
||||
Dl_info dlinfo = { 0 };
|
||||
const char *module_name;
|
||||
|
||||
if( pd->skip_wrappers )
|
||||
{
|
||||
if( Sys_IsCrashHandlerFrame( symname ))
|
||||
return;
|
||||
pd->skip_wrappers = false;
|
||||
}
|
||||
|
||||
if( dladdr((void *)pc, &dlinfo ))
|
||||
module_name = dlinfo.dli_fname;
|
||||
else module_name = NULL;
|
||||
@@ -110,6 +117,13 @@ static int Sys_BacktracePrintFull( void *data, uintptr_t pc, const char *filenam
|
||||
Dl_info dlinfo = { 0 };
|
||||
const char *module_name;
|
||||
|
||||
if( pd->skip_wrappers )
|
||||
{
|
||||
if( Sys_IsCrashHandlerFrame( function ))
|
||||
return 0;
|
||||
pd->skip_wrappers = false;
|
||||
}
|
||||
|
||||
if( dladdr((void *)pc, &dlinfo ))
|
||||
module_name = dlinfo.dli_fname;
|
||||
else module_name = NULL;
|
||||
@@ -136,12 +150,13 @@ int Sys_CrashDetailsLibbacktrace( int logfd, char *message, int len, size_t max_
|
||||
struct print_data pd =
|
||||
{
|
||||
.message = message + len,
|
||||
.message_size = sizeof( message ) - len,
|
||||
.message_size = max_len - len,
|
||||
.logfd = logfd,
|
||||
.len = len,
|
||||
.skip_wrappers = true,
|
||||
};
|
||||
|
||||
backtrace_full( g_bt_state, 1, Sys_BacktracePrintFull, Sys_BacktracePrintError, &pd );
|
||||
backtrace_full( g_bt_state, 0, Sys_BacktracePrintFull, Sys_BacktracePrintError, &pd );
|
||||
|
||||
return pd.len;
|
||||
}
|
||||
|
||||
@@ -15,14 +15,7 @@ GNU General Public License for more details.
|
||||
|
||||
#include "common.h"
|
||||
|
||||
// while this is mostly POSIX-compatible functions
|
||||
// the contents of ucontext_t is platform-dependent
|
||||
// before adding new OS here, check platform.h
|
||||
#define _XOPEN_SOURCE 1 // required for ucontext
|
||||
#if XASH_FREEBSD || XASH_NETBSD || XASH_OPENBSD || XASH_ANDROID || XASH_LINUX || XASH_APPLE
|
||||
#ifndef XASH_OPENBSD
|
||||
#include <ucontext.h>
|
||||
#endif
|
||||
#include <signal.h>
|
||||
#include <sys/mman.h>
|
||||
#include "library.h"
|
||||
@@ -51,7 +44,8 @@ static void Sys_Crash( int signal, siginfo_t *si, void *context )
|
||||
|
||||
// now get log fd and write trace directly to log
|
||||
logfd = Sys_LogFileNo();
|
||||
write( logfd, message, len );
|
||||
if( logfd >= 0 )
|
||||
write( logfd, message, len );
|
||||
|
||||
#if HAVE_LIBBACKTRACE
|
||||
if( have_libbacktrace && !detailed_message )
|
||||
|
||||
@@ -106,7 +106,7 @@ qboolean SNDDMA_Init( void )
|
||||
|
||||
memset( &desired, 0, sizeof( desired ) );
|
||||
desired.freq = SOUND_DMA_SPEED;
|
||||
desired.format = AUDIO_S16LSB;
|
||||
desired.format = AUDIO_S16SYS;
|
||||
desired.samples = 1024;
|
||||
desired.channels = 2;
|
||||
desired.callback = SDL_SoundCallback;
|
||||
@@ -119,7 +119,7 @@ qboolean SNDDMA_Init( void )
|
||||
return false;
|
||||
}
|
||||
|
||||
if( obtained.format != AUDIO_S16LSB )
|
||||
if( obtained.format != AUDIO_S16SYS )
|
||||
{
|
||||
Con_Printf( "SDL audio format %d unsupported.\n", obtained.format );
|
||||
goto fail;
|
||||
|
||||
@@ -368,6 +368,11 @@ static void SDLash_EventHandler( SDL_Event *event )
|
||||
#endif
|
||||
SDLash_HandleGameControllerEvent( event );
|
||||
break;
|
||||
#if SDL_VERSION_ATLEAST( 2, 0, 14 )
|
||||
case SDL_SENSORUPDATE:
|
||||
SDLash_SensorUpdate( event->sensor );
|
||||
break;
|
||||
#endif
|
||||
|
||||
case SDL_WINDOWEVENT:
|
||||
if( event->window.windowID != SDL_GetWindowID( host.hWnd ) )
|
||||
|
||||
@@ -35,5 +35,15 @@ void SDLash_FreeCursors( void );
|
||||
//
|
||||
void SDLash_HandleGameControllerEvent( SDL_Event *ev );
|
||||
|
||||
//
|
||||
// sensor_sdl2.c
|
||||
//
|
||||
void SDLash_InitSensors( void );
|
||||
void SDLash_ShutdownSensors( void );
|
||||
qboolean SDLash_GyroIsAvailable( void );
|
||||
#if SDL_VERSION_ATLEAST( 2, 0, 14 )
|
||||
void SDLash_SensorUpdate( SDL_SensorEvent sensor );
|
||||
#endif
|
||||
|
||||
#endif // XASH_SDL
|
||||
#endif // KEYWRAPPER_H
|
||||
|
||||
@@ -123,7 +123,7 @@ qboolean SNDDMA_Init( void )
|
||||
|
||||
memset( &desired, 0, sizeof( desired ) );
|
||||
desired.freq = SOUND_DMA_SPEED;
|
||||
desired.format = AUDIO_S16LSB;
|
||||
desired.format = AUDIO_S16SYS;
|
||||
desired.samples = 1024;
|
||||
desired.channels = 2;
|
||||
desired.callback = SDL_SoundCallback;
|
||||
@@ -136,7 +136,7 @@ qboolean SNDDMA_Init( void )
|
||||
return false;
|
||||
}
|
||||
|
||||
if( obtained.format != AUDIO_S16LSB )
|
||||
if( obtained.format != AUDIO_S16SYS )
|
||||
{
|
||||
Con_Printf( "SDL audio format %d unsupported.\n", obtained.format );
|
||||
goto fail;
|
||||
@@ -277,7 +277,7 @@ qboolean VoiceCapture_Init( void )
|
||||
|
||||
SDL_zero( wanted );
|
||||
wanted.freq = voice.samplerate;
|
||||
wanted.format = AUDIO_S16LSB;
|
||||
wanted.format = AUDIO_S16SYS;
|
||||
wanted.channels = VOICE_PCM_CHANNELS;
|
||||
wanted.samples = voice.frame_size;
|
||||
wanted.callback = SDL_SoundInputCallback;
|
||||
|
||||
103
engine/platform/sdl2/sensor_sdl2.c
Normal file
103
engine/platform/sdl2/sensor_sdl2.c
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
sensor_sdl2.c - SDL2 sensor handling
|
||||
Copyright (C) 2026 Xash3D FWGS contributors
|
||||
|
||||
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 <SDL.h>
|
||||
#include "common.h"
|
||||
#include "input.h"
|
||||
#include "platform_sdl2.h"
|
||||
|
||||
#if SDL_VERSION_ATLEAST( 2, 0, 14 )
|
||||
static SDL_SensorID g_system_gyro_id = -1;
|
||||
static SDL_Sensor *g_system_gyro;
|
||||
|
||||
/*
|
||||
==============
|
||||
SDLash_InitSensors
|
||||
|
||||
==============
|
||||
*/
|
||||
void SDLash_InitSensors( void )
|
||||
{
|
||||
if( SDL_InitSubSystem( SDL_INIT_SENSOR ) == 0 )
|
||||
{
|
||||
int num_sensors = SDL_NumSensors();
|
||||
|
||||
for( int i = 0; i < num_sensors; i++ )
|
||||
{
|
||||
if( SDL_SensorGetDeviceType( i ) == SDL_SENSOR_GYRO )
|
||||
{
|
||||
g_system_gyro = SDL_SensorOpen( i );
|
||||
if( g_system_gyro )
|
||||
{
|
||||
g_system_gyro_id = SDL_SensorGetInstanceID( g_system_gyro );
|
||||
Con_Printf( "SDL: Opened built-in gyroscope: %s\n", SDL_SensorGetName( g_system_gyro ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Con_Reportf( S_ERROR "Failed to init SDL Sensor subsystem: %s\n", SDL_GetError() );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
SDLash_ShutdownSensors
|
||||
|
||||
==============
|
||||
*/
|
||||
void SDLash_ShutdownSensors( void )
|
||||
{
|
||||
if( g_system_gyro )
|
||||
{
|
||||
SDL_SensorClose( g_system_gyro );
|
||||
g_system_gyro = NULL;
|
||||
g_system_gyro_id = -1;
|
||||
}
|
||||
|
||||
SDL_QuitSubSystem( SDL_INIT_SENSOR );
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
SDLash_GyroIsAvailable
|
||||
|
||||
==============
|
||||
*/
|
||||
qboolean SDLash_GyroIsAvailable( void )
|
||||
{
|
||||
return ( g_system_gyro != NULL );
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
SDLash_SensorUpdate
|
||||
|
||||
==============
|
||||
*/
|
||||
void SDLash_SensorUpdate( SDL_SensorEvent sensor )
|
||||
{
|
||||
if( sensor.which == g_system_gyro_id )
|
||||
{
|
||||
IN_GyroEvent( sensor.data );
|
||||
}
|
||||
}
|
||||
#else
|
||||
void SDLash_InitSensors( void ) { }
|
||||
void SDLash_ShutdownSensors( void ) { }
|
||||
qboolean SDLash_GyroIsAvailable( void ) { return false; }
|
||||
#endif
|
||||
@@ -146,10 +146,12 @@ void SDLash_Init( void )
|
||||
SDL_StopTextInput();
|
||||
|
||||
SDLash_InitCursors();
|
||||
SDLash_InitSensors();
|
||||
}
|
||||
|
||||
void SDLash_Shutdown( void )
|
||||
{
|
||||
SDLash_ShutdownSensors();
|
||||
SDLash_FreeCursors();
|
||||
|
||||
SDL_Quit();
|
||||
|
||||
@@ -1204,3 +1204,29 @@ void VID_Info_f( void )
|
||||
else
|
||||
Con_Printf( "Window display mode: " S_RED "fail: " S_DEFAULT "%s\n", SDL_GetError( ));
|
||||
}
|
||||
|
||||
platform_orientation_t Platform_GetDisplayOrientation( void )
|
||||
{
|
||||
if( host.hWnd )
|
||||
{
|
||||
int display_index = SDL_GetWindowDisplayIndex( host.hWnd );
|
||||
if( display_index >= 0 )
|
||||
{
|
||||
switch( SDL_GetDisplayOrientation( display_index ) )
|
||||
{
|
||||
case SDL_ORIENTATION_LANDSCAPE:
|
||||
return ORIENTATION_LANDSCAPE;
|
||||
case SDL_ORIENTATION_LANDSCAPE_FLIPPED:
|
||||
return ORIENTATION_LANDSCAPE_FLIPPED;
|
||||
case SDL_ORIENTATION_PORTRAIT:
|
||||
return ORIENTATION_PORTRAIT;
|
||||
case SDL_ORIENTATION_PORTRAIT_FLIPPED:
|
||||
return ORIENTATION_PORTRAIT_FLIPPED;
|
||||
default:
|
||||
return ORIENTATION_UNKNOWN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ORIENTATION_UNKNOWN;
|
||||
}
|
||||
|
||||
@@ -19,11 +19,11 @@ GNU General Public License for more details.
|
||||
#include <stdarg.h>
|
||||
#include "com_image.h"
|
||||
#include "vgui_api.h"
|
||||
#include "const.h"
|
||||
#include "com_model.h"
|
||||
#include "cl_entity.h"
|
||||
#include "render_api.h"
|
||||
#include "triangleapi.h"
|
||||
#include "const.h"
|
||||
#include "cl_entity.h"
|
||||
#include "com_model.h"
|
||||
#include "studio.h"
|
||||
#include "r_efx.h"
|
||||
#include "filesystem.h"
|
||||
@@ -62,7 +62,18 @@ GNU General Public License for more details.
|
||||
// 11. Added size argument to Mod_ProcessRenderData
|
||||
// 12. Added Image_CalcImageSize
|
||||
// 13. Removed ignore_flags argument from GetCvarPointer
|
||||
#define REF_API_VERSION 13
|
||||
// 14. Removed reserved functions, they are leftover from RenderAPI
|
||||
// Removed CL_AddCustomBeam, it's now handled through R_AddEntity
|
||||
// 15. Replaced CL_InitStudioAPI with R_StudioFillAPI + R_StudioSetDrawInterface
|
||||
// Engine now builds engine_studio_api_t and handles client DLL negotiation
|
||||
// Replaced R_DrawStretchRaw and AVI_UploadRawFrame with GL_UpdateTexture
|
||||
// Added GL_CreateTexture, R_GetDetailScaleForTexture, R_SetDetailScaleForTexture
|
||||
// Removed R_Flush, VGUI_UploadTextureBlock, R_BeamCull, pfnGetStudioModelInterface
|
||||
// Moved RenderAPI and TriAPI filling to renderer via R_FillRenderAPI and R_FillTriAPI
|
||||
// Moved detail textures parsing and cinematic texture management to engine
|
||||
// Moved creation of default textures to the engine
|
||||
// 16. RefGetParm return type changed from int to intptr_t.
|
||||
#define REF_API_VERSION 16
|
||||
|
||||
#define TF_SKY (TF_SKYSIDE|TF_NOMIPMAP|TF_ALLOW_NEAREST)
|
||||
#define TF_FONT (TF_NOMIPMAP|TF_CLAMP|TF_ALLOW_NEAREST)
|
||||
@@ -221,7 +232,7 @@ enum ref_defaultsprite_e
|
||||
};
|
||||
|
||||
// the order of first three is important!
|
||||
// so you can use this value in IEngineStudio.StudioIsHardware
|
||||
// so you can use this value in IEngineStudio.StudioIsHardware (but shouldn't)
|
||||
typedef enum ref_graphic_apis_e
|
||||
{
|
||||
REF_SOFTWARE, // hypothetical: just make a surface to draw on, in software
|
||||
@@ -332,6 +343,7 @@ typedef enum
|
||||
PARM_GET_LIGHTSTYLES_PTR = -20,
|
||||
PARM_GET_DLIGHTS_PTR = -21,
|
||||
PARM_GET_ELIGHTS_PTR = -22,
|
||||
PARM_GET_STUDIO_HDR = -23, // current m_pStudioHeader in renderer
|
||||
|
||||
// implemented by ref_dll
|
||||
|
||||
@@ -387,7 +399,7 @@ typedef struct ref_api_s
|
||||
// brushes
|
||||
int (*Mod_SampleSizeForFace)( const struct msurface_s *surf );
|
||||
qboolean (*Mod_BoxVisible)( const vec3_t mins, const vec3_t maxs, const byte *visbits );
|
||||
mleaf_t *(*Mod_PointInLeaf)( const vec3_t p, mnode_t *node );
|
||||
mleaf_t *(*Mod_PointInLeaf)( const vec3_t p, mnode_t *node, struct model_s *mod );
|
||||
void (*R_DrawWorldHull)( void );
|
||||
void (*R_DrawModelHull)( model_t *mod );
|
||||
|
||||
@@ -429,7 +441,6 @@ typedef struct ref_api_s
|
||||
void *(*Mod_CacheCheck)( struct cache_user_s *c );
|
||||
void (*Mod_LoadCacheFile)( const char *path, struct cache_user_s *cu );
|
||||
void *(*Mod_Calloc)( int number, size_t size );
|
||||
int (*pfnGetStudioModelInterface)( int version, struct r_studio_interface_s **ppinterface, struct engine_studio_api_s *pstudio );
|
||||
|
||||
// memory
|
||||
poolhandle_t (*_Mem_AllocPool)( const char *name, const char *filename, int fileline )
|
||||
@@ -499,6 +510,9 @@ typedef struct ref_api_s
|
||||
|
||||
// for abstracting the engine's rendering
|
||||
ref_window_type_t (*R_GetWindowHandle)( void **handle, ref_window_type_t type );
|
||||
|
||||
// sprites
|
||||
struct mspriteframe_s *(*R_GetSpriteFrame)( const struct model_s *pModel, int frame, float yaw );
|
||||
} ref_api_t;
|
||||
|
||||
struct mip_s;
|
||||
@@ -533,10 +547,7 @@ typedef struct ref_interface_s
|
||||
void (*GL_SetRenderMode)( int renderMode );
|
||||
|
||||
qboolean (*R_AddEntity)( struct cl_entity_s *clent, int type );
|
||||
void (*CL_AddCustomBeam)( cl_entity_t *pEnvBeam );
|
||||
void (*R_ProcessEntData)( qboolean allocate, cl_entity_t *entities, unsigned int max_entities );
|
||||
void (*R_Flush)( unsigned int flush_flags );
|
||||
|
||||
// debug
|
||||
void (*R_ShowTextures)( void );
|
||||
|
||||
@@ -548,7 +559,6 @@ typedef struct ref_interface_s
|
||||
|
||||
// 2D
|
||||
void (*R_Set2DMode)( qboolean enable );
|
||||
void (*R_DrawStretchRaw)( float x, float y, float w, float h, int cols, int rows, const byte *data, qboolean dirty );
|
||||
void (*R_DrawStretchPic)( float x, float y, float w, float h, float s1, float t1, float s2, float t2, int texnum );
|
||||
void (*FillRGBA)( int rendermode, float x, float y, float w, float h, byte r, byte g, byte b, byte a ); // in screen space
|
||||
int (*WorldToScreen)( const vec3_t world, vec3_t screen ); // Returns 1 if it's z clipped
|
||||
@@ -570,16 +580,14 @@ typedef struct ref_interface_s
|
||||
// studio interface
|
||||
float (*R_StudioEstimateFrame)( cl_entity_t *e, mstudioseqdesc_t *pseqdesc, double time );
|
||||
void (*R_StudioLerpMovement)( cl_entity_t *e, double time, vec3_t origin, vec3_t angles );
|
||||
void (*CL_InitStudioAPI)( void );
|
||||
qboolean (*R_StudioFillAPI)( struct engine_studio_api_s *api, struct r_studio_interface_s *pDefaultDraw );
|
||||
void (*R_StudioSetDrawInterface)( struct r_studio_interface_s *pDraw );
|
||||
|
||||
// bmodel
|
||||
void (*R_SetSkyCloudsTextures)( int solidskyTexture, int alphaskyTexture );
|
||||
void (*GL_SubdivideSurface)( model_t *mod, msurface_t *fa );
|
||||
void (*CL_RunLightStyles)( lightstyle_t *ls );
|
||||
|
||||
// sprites
|
||||
void (*R_GetSpriteParms)( int *frameWidth, int *frameHeight, int *numFrames, int currentFrame, const model_t *pSprite );
|
||||
int (*R_GetSpriteTexture)( const model_t *m_pSpriteModel, int frame );
|
||||
|
||||
// model management
|
||||
// flags ignored for everything except spritemodels
|
||||
@@ -590,55 +598,27 @@ typedef struct ref_interface_s
|
||||
void (*CL_DrawParticles)( double frametime, particle_t *particles, float partsize );
|
||||
void (*CL_DrawTracers)( double frametime, particle_t *tracers );
|
||||
void (*CL_DrawBeams)( int fTrans , BEAM *beams );
|
||||
qboolean (*R_BeamCull)( const vec3_t start, const vec3_t end, qboolean pvsOnly );
|
||||
|
||||
// Xash3D Render Interface
|
||||
// Get renderer info (doesn't changes engine state at all)
|
||||
int (*RefGetParm)( int parm, int arg ); // generic
|
||||
void (*GetDetailScaleForTexture)( int texture, float *xScale, float *yScale );
|
||||
void (*GetExtraParmsForTexture)( int texture, byte *red, byte *green, byte *blue, byte *alpha );
|
||||
float (*GetFrameTime)( void );
|
||||
intptr_t (*RefGetParm)( int parm, int arg ); // generic
|
||||
|
||||
// Set renderer info (tell engine about changes)
|
||||
void (*R_SetCurrentEntity)( struct cl_entity_s *ent ); // tell engine about both currententity and currentmodel
|
||||
void (*R_SetCurrentModel)( struct model_s *mod ); // change currentmodel but leave currententity unchanged
|
||||
// detail texture scale
|
||||
void (*R_GetDetailScaleForTexture)( int texture, float *xScale, float *yScale );
|
||||
void (*R_SetDetailScaleForTexture)( int texture, float xScale, float yScale );
|
||||
|
||||
// Texture tools
|
||||
// Texture tools (used by engine directly)
|
||||
int (*GL_CreateTexture)( const char *name, int width, int height, const void *buffer, texFlags_t flags );
|
||||
int (*GL_FindTexture)( const char *name );
|
||||
const char* (*GL_TextureName)( unsigned int texnum );
|
||||
const byte* (*GL_TextureData)( unsigned int texnum ); // may be NULL
|
||||
int (*GL_LoadTexture)( const char *name, const byte *buf, size_t size, int flags );
|
||||
int (*GL_CreateTexture)( const char *name, int width, int height, const void *buffer, texFlags_t flags );
|
||||
int (*GL_LoadTextureArray)( const char **names, int flags );
|
||||
int (*GL_CreateTextureArray)( const char *name, int width, int height, int depth, const void *buffer, texFlags_t flags );
|
||||
void (*GL_FreeTexture)( unsigned int texnum );
|
||||
void (*R_OverrideTextureSourceSize)( unsigned int texnum, unsigned int srcWidth, unsigned int srcHeight ); // used to override decal size for texture replacement
|
||||
|
||||
// Decals manipulating (draw & remove)
|
||||
void (*DrawSingleDecal)( struct decal_s *pDecal, struct msurface_s *fa );
|
||||
float *(*R_DecalSetupVerts)( struct decal_s *pDecal, struct msurface_s *surf, int texture, int *outCount );
|
||||
void (*R_EntityRemoveDecals)( struct model_s *mod ); // remove all the decals from specified entity (BSP only)
|
||||
void (*GL_UpdateTexture)( int texnum, int cols, int rows, int width, int height, const byte *buffer, pixformat_t fmt );
|
||||
|
||||
// AVI
|
||||
void (*AVI_UploadRawFrame)( int texture, int cols, int rows, int width, int height, const byte *data );
|
||||
|
||||
// glState related calls (must use this instead of normal gl-calls to prevent de-synchornize local states between engine and the client)
|
||||
// glState related calls (used by engine directly)
|
||||
void (*GL_Bind)( int tmu, unsigned int texnum );
|
||||
void (*GL_SelectTexture)( int tmu );
|
||||
void (*GL_LoadTextureMatrix)( const float *glmatrix );
|
||||
void (*GL_TexMatrixIdentity)( void );
|
||||
void (*GL_CleanUpTextureUnits)( int last ); // pass 0 for clear all the texture units
|
||||
void (*GL_TexGen)( unsigned int coord, unsigned int mode );
|
||||
void (*GL_TextureTarget)( unsigned int target ); // change texture unit mode without bind texture
|
||||
void (*GL_TexCoordArrayMode)( unsigned int texmode );
|
||||
void (*GL_UpdateTexSize)( int texnum, int width, int height, int depth ); // recalc statistics
|
||||
void (*GL_Reserved0)( void ); // for potential interface expansion without broken compatibility
|
||||
void (*GL_Reserved1)( void );
|
||||
|
||||
// Misc renderer functions
|
||||
void (*GL_DrawParticles)( const struct ref_viewpass_s *rvp, qboolean trans_pass, float frametime );
|
||||
colorVec (*LightVec)( const float *start, const float *end, float *lightspot, float *lightvec );
|
||||
struct mstudiotex_s *( *StudioGetTexture )( struct cl_entity_s *e );
|
||||
|
||||
// passed through R_RenderFrame (0 - use engine renderer, 1 - use custom client renderer)
|
||||
void (*GL_RenderFrame)( const struct ref_viewpass_s *rvp );
|
||||
@@ -652,28 +632,23 @@ typedef struct ref_interface_s
|
||||
void (*R_NewMap)( void );
|
||||
// clear the render entities before each frame
|
||||
void (*R_ClearScene)( void );
|
||||
// GL_GetProcAddress for client renderer
|
||||
void* (*R_GetProcAddress)( const char *name );
|
||||
|
||||
// TriAPI Interface
|
||||
// NOTE: implementation isn't required to be compatible
|
||||
// TriAPI Interface (functions used by engine wrappers)
|
||||
void (*TriRenderMode)( int mode );
|
||||
void (*Begin)( int primitiveCode );
|
||||
void (*End)( void );
|
||||
void (*Color4f)( float r, float g, float b, float a ); // real glColor4f
|
||||
void (*Color4ub)( unsigned char r, unsigned char g, unsigned char b, unsigned char a ); // real glColor4ub
|
||||
void (*TexCoord2f)( float u, float v );
|
||||
void (*Vertex3fv)( const float *worldPnt );
|
||||
void (*Vertex3f)( float x, float y, float z );
|
||||
void (*Fog)( float flFogColor[3], float flStart, float flEnd, int bOn ); //Works just like GL_FOG, flFogColor is r/g/b.
|
||||
void (*ScreenToWorld)( const float *screen, float *world );
|
||||
void (*GetMatrix)( const int pname, float *matrix );
|
||||
void (*FogParams)( float flDensity, int iFogSkybox );
|
||||
void (*CullFace)( TRICULLSTYLE mode );
|
||||
|
||||
// fill render_api_t and triangleapi_t with renderer-specific functions
|
||||
void (*R_FillRenderAPI)( struct render_api_s *api );
|
||||
void (*R_FillTriAPI)( struct triangleapi_s *api );
|
||||
|
||||
// vgui drawing implementation
|
||||
void (*VGUI_SetupDrawing)( qboolean rect );
|
||||
void (*VGUI_UploadTextureBlock)( int drawX, int drawY, const byte *rgba, int blockWidth, int blockHeight );
|
||||
} ref_interface_t;
|
||||
|
||||
typedef int (*REFAPI)( int version, ref_interface_t *pFunctionTable, ref_api_t* engfuncs, ref_globals_t *pGlobals );
|
||||
|
||||
@@ -252,6 +252,7 @@ typedef struct sv_client_s
|
||||
double userinfo_penalty;
|
||||
|
||||
double overflow_warn_time;
|
||||
double resourcelist_next_changetime;
|
||||
|
||||
client_frame_t *frames; // updates can be delta'd from here
|
||||
event_state_t events; // delta-updated events cycle
|
||||
@@ -419,6 +420,7 @@ extern convar_t sv_skyvec_z;
|
||||
extern convar_t sv_consistency;
|
||||
extern convar_t sv_password;
|
||||
extern convar_t sv_uploadmax;
|
||||
extern convar_t sv_upload_penalty_time;
|
||||
extern convar_t sv_trace_messages;
|
||||
extern convar_t sv_enttools_enable;
|
||||
extern convar_t sv_enttools_maxfire;
|
||||
|
||||
@@ -836,7 +836,7 @@ static void SV_TestBandWidth( netadr_t from )
|
||||
return;
|
||||
}
|
||||
|
||||
crc = svs.testpacket_crcs[ofs];
|
||||
crc = LittleLong( svs.testpacket_crcs[ofs] );
|
||||
memcpy( svs.testpacket_crcpos, &crc, sizeof( crc ));
|
||||
|
||||
// send the datagram
|
||||
@@ -2167,7 +2167,7 @@ static qboolean SV_Spawn_f( sv_client_t *cl )
|
||||
if( sv.paused )
|
||||
{
|
||||
MSG_BeginServerCmd( &sv.reliable_datagram, svc_setpause );
|
||||
MSG_WriteByte( &sv.reliable_datagram, sv.paused );
|
||||
MSG_WriteOneBit( &sv.reliable_datagram, sv.paused );
|
||||
SV_ClientPrintf( cl, "Server is paused.\n" );
|
||||
}
|
||||
return true;
|
||||
@@ -3465,6 +3465,16 @@ static void SV_ParseResourceList( sv_client_t *cl, sizebuf_t *msg )
|
||||
SV_AddToResourceList( resource, &cl->resourcesneeded );
|
||||
}
|
||||
|
||||
if( host.realtime < cl->resourcelist_next_changetime )
|
||||
{
|
||||
Con_Reportf( "%s: ignoring resource list update from %s: too soon\n", __func__, cl->name );
|
||||
SV_ClearResourceList( &cl->resourcesneeded );
|
||||
SV_ClearResourceList( &cl->resourcesonhand );
|
||||
return;
|
||||
}
|
||||
|
||||
cl->resourcelist_next_changetime = host.realtime + sv_upload_penalty_time.value;
|
||||
|
||||
totalsize = COM_SizeofResourceList( &cl->resourcesneeded, &ri );
|
||||
|
||||
if( totalsize != 0 && sv_allow_upload.value )
|
||||
|
||||
@@ -2673,7 +2673,7 @@ static void GAME_EXPORT pfnMessageEnd( void )
|
||||
return;
|
||||
}
|
||||
|
||||
realsize = svgame.msg_realsize;
|
||||
realsize = LittleShort( svgame.msg_realsize );
|
||||
memcpy( &sv.multicast.pData[svgame.msg_size_index], &realsize, sizeof( realsize ));
|
||||
}
|
||||
}
|
||||
@@ -2706,7 +2706,7 @@ static void GAME_EXPORT pfnMessageEnd( void )
|
||||
return;
|
||||
}
|
||||
|
||||
realsize = svgame.msg_realsize;
|
||||
realsize = LittleShort( svgame.msg_realsize );
|
||||
memcpy( &sv.multicast.pData[svgame.msg_size_index], &realsize, sizeof( realsize ));
|
||||
}
|
||||
else
|
||||
|
||||
@@ -833,82 +833,6 @@ static void SV_SetupClients( void )
|
||||
ClearBits( sv_maxclients.flags, FCVAR_CHANGED );
|
||||
}
|
||||
|
||||
qboolean CRC32_MapFile( dword *crcvalue, const char *filename, qboolean multiplayer )
|
||||
{
|
||||
char headbuf[1024], buffer[1024];
|
||||
int i, num_bytes, lumplen;
|
||||
int version, hdr_size;
|
||||
dheader_t *header;
|
||||
file_t *f;
|
||||
|
||||
if( !crcvalue ) return false;
|
||||
|
||||
// always calc same checksum for singleplayer
|
||||
if( multiplayer == false )
|
||||
{
|
||||
*crcvalue = (('H'<<24)+('S'<<16)+('A'<<8)+'X');
|
||||
return true;
|
||||
}
|
||||
|
||||
f = FS_Open( filename, "rb", false );
|
||||
if( !f ) return false;
|
||||
|
||||
// read version number
|
||||
FS_Read( f, &version, sizeof( int ));
|
||||
FS_Seek( f, 0, SEEK_SET );
|
||||
|
||||
hdr_size = sizeof( int ) + sizeof( dlump_t ) * HEADER_LUMPS;
|
||||
num_bytes = FS_Read( f, headbuf, hdr_size );
|
||||
|
||||
// corrupted map ?
|
||||
if( num_bytes != hdr_size )
|
||||
{
|
||||
FS_Close( f );
|
||||
return false;
|
||||
}
|
||||
|
||||
header = (dheader_t *)headbuf;
|
||||
|
||||
// invalid version ?
|
||||
switch( header->version )
|
||||
{
|
||||
case Q1BSP_VERSION:
|
||||
case HLBSP_VERSION:
|
||||
case QBSP2_VERSION:
|
||||
break;
|
||||
default:
|
||||
FS_Close( f );
|
||||
return false;
|
||||
}
|
||||
|
||||
CRC32_Init( crcvalue );
|
||||
|
||||
for( i = LUMP_PLANES; i < HEADER_LUMPS; i++ )
|
||||
{
|
||||
lumplen = header->lumps[i].filelen;
|
||||
FS_Seek( f, header->lumps[i].fileofs, SEEK_SET );
|
||||
|
||||
while( lumplen > 0 )
|
||||
{
|
||||
if( lumplen >= sizeof( buffer ))
|
||||
num_bytes = FS_Read( f, buffer, sizeof( buffer ));
|
||||
else num_bytes = FS_Read( f, buffer, lumplen );
|
||||
|
||||
if( num_bytes > 0 )
|
||||
{
|
||||
lumplen -= num_bytes;
|
||||
CRC32_ProcessBuffer( crcvalue, buffer, num_bytes );
|
||||
}
|
||||
|
||||
// file unexpected end ?
|
||||
if( FS_Eof( f )) break;
|
||||
}
|
||||
}
|
||||
|
||||
FS_Close( f );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void SV_FreeTestPacket( void )
|
||||
{
|
||||
|
||||
@@ -55,6 +55,7 @@ CVAR_DEFINE( sv_allow_upload, "sv_allowupload", "1", FCVAR_SERVER, "allow upload
|
||||
CVAR_DEFINE( sv_allow_download, "sv_allowdownload", "1", FCVAR_SERVER, "allow downloading custom resources to the client" );
|
||||
static CVAR_DEFINE_AUTO( sv_allow_dlfile, "1", 0, "compatibility cvar, does nothing" );
|
||||
CVAR_DEFINE_AUTO( sv_uploadmax, "0.5", FCVAR_SERVER, "max size to upload custom resources (500 kB as default)" );
|
||||
CVAR_DEFINE_AUTO( sv_upload_penalty_time, "60", FCVAR_ARCHIVE, "allow custom resource updates only once in this timewindow (set 0 to disable)" );
|
||||
CVAR_DEFINE_AUTO( sv_downloadurl, "", FCVAR_PROTECTED, "location from which clients can download missing files" );
|
||||
CVAR_DEFINE( sv_consistency, "mp_consistency", "1", FCVAR_SERVER, "enbale consistency check in multiplayer" );
|
||||
CVAR_DEFINE_AUTO( mp_logecho, "1", 0, "log multiplayer frags to server logfile" );
|
||||
@@ -941,6 +942,7 @@ void SV_Init( void )
|
||||
Cvar_RegisterVariable( &sv_send_logos );
|
||||
Cvar_RegisterVariable( &sv_send_resources );
|
||||
Cvar_RegisterVariable( &sv_uploadmax );
|
||||
Cvar_RegisterVariable( &sv_upload_penalty_time );
|
||||
Cvar_RegisterVariable( &sv_version );
|
||||
Cvar_RegisterVariable( &sv_instancedbaseline );
|
||||
Cvar_RegisterVariable( &sv_contact );
|
||||
|
||||
@@ -331,7 +331,7 @@ static void GAME_EXPORT pfnParticle( const float *origin, int color, float life,
|
||||
return;
|
||||
}
|
||||
|
||||
MSG_WriteByte( &sv.reliable_datagram, svc_particle );
|
||||
MSG_BeginServerCmd( &sv.reliable_datagram, svc_particle );
|
||||
MSG_WriteVec3Coord( &sv.reliable_datagram, origin );
|
||||
MSG_WriteChar( &sv.reliable_datagram, 0 ); // no x-vel
|
||||
MSG_WriteChar( &sv.reliable_datagram, 0 ); // no y-vel
|
||||
|
||||
@@ -186,7 +186,7 @@ def build(bld):
|
||||
# public includes for renderers and utils use
|
||||
bld(name = 'engine_includes', export_includes = '. common common/imagelib', use = 'filesystem_includes')
|
||||
|
||||
libs = ['engine_includes', 'public', 'werror', 'backtrace', 'library_suffix', 'build_vcs']
|
||||
libs = ['engine_includes', 'public', 'werror', 'backtrace_custom', 'library_suffix', 'build_vcs']
|
||||
includes = ['server', 'client', 'client/vgui', 'common/soundlib', 'platform']
|
||||
|
||||
# basic build: dedicated only
|
||||
|
||||
62
public/atlas.c
Normal file
62
public/atlas.c
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
atlas.c - generic 2D atlas packer (strip-based)
|
||||
Copyright (C) 1997 id Software
|
||||
Copyright (C) Xash3D and Xash3D FWGS developers
|
||||
|
||||
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 "atlas.h"
|
||||
|
||||
qboolean Atlas_AllocBlock( atlas_t *atlas, int w, int h, int *x, int *y )
|
||||
{
|
||||
int i, j;
|
||||
int best, best2;
|
||||
int size = atlas->size;
|
||||
|
||||
best = size;
|
||||
|
||||
for( i = 0; i <= size - w; )
|
||||
{
|
||||
best2 = 0;
|
||||
|
||||
for( j = 0; j < w; j++ )
|
||||
{
|
||||
if( atlas->allocated[i + j] >= best )
|
||||
break;
|
||||
if( atlas->allocated[i + j] > best2 )
|
||||
best2 = atlas->allocated[i + j];
|
||||
}
|
||||
|
||||
if( j == w )
|
||||
{
|
||||
*x = i;
|
||||
*y = best = best2;
|
||||
if( best == 0 )
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
i += j + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if( best + h > size )
|
||||
return false;
|
||||
|
||||
for( i = 0; i < w; i++ )
|
||||
atlas->allocated[*x + i] = best + h;
|
||||
|
||||
if( best + h > atlas->max_height )
|
||||
atlas->max_height = best + h;
|
||||
|
||||
return true;
|
||||
}
|
||||
41
public/atlas.h
Normal file
41
public/atlas.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
atlas.h - generic 2D atlas packer (strip-based)
|
||||
Copyright (C) 1997 id Software
|
||||
Copyright (C) Xash3D and Xash3D FWGS developers
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
#ifndef ATLAS_H
|
||||
#define ATLAS_H
|
||||
|
||||
#include <string.h>
|
||||
#include "xash3d_types.h"
|
||||
|
||||
// maximum atlas dimension
|
||||
#define ATLAS_MAX_SIZE 1024
|
||||
|
||||
typedef struct atlas_s
|
||||
{
|
||||
int allocated[ATLAS_MAX_SIZE];
|
||||
int size;
|
||||
int max_height;
|
||||
} atlas_t;
|
||||
|
||||
static inline void Atlas_Init( atlas_t *atlas, int size )
|
||||
{
|
||||
memset( atlas->allocated, 0, sizeof( atlas->allocated ));
|
||||
atlas->size = size;
|
||||
atlas->max_height = 0;
|
||||
}
|
||||
|
||||
qboolean Atlas_AllocBlock( atlas_t *atlas, int w, int h, int *x, int *y );
|
||||
|
||||
#endif // ATLAS_H
|
||||
@@ -148,19 +148,19 @@ For proxy protecting
|
||||
byte CRC32_BlockSequence( byte *base, int length, int sequence )
|
||||
{
|
||||
uint32_t CRC;
|
||||
char *ptr;
|
||||
char buffer[64];
|
||||
int off;
|
||||
uint32_t le[2];
|
||||
|
||||
if( sequence < 0 ) sequence = abs( sequence );
|
||||
ptr = (char *)crc32table + (sequence % 0x3FC);
|
||||
|
||||
if( length > 60 ) length = 60;
|
||||
memcpy( buffer, base, length );
|
||||
|
||||
buffer[length+0] = ptr[0];
|
||||
buffer[length+1] = ptr[1];
|
||||
buffer[length+2] = ptr[2];
|
||||
buffer[length+3] = ptr[3];
|
||||
off = sequence % 0x3FC;
|
||||
le[0] = LittleLong( crc32table[off / 4] );
|
||||
le[1] = LittleLong( crc32table[off / 4 + 1] );
|
||||
memcpy( buffer + length, (char *)le + ( off & 3 ), 4 );
|
||||
|
||||
length += 4;
|
||||
|
||||
@@ -173,6 +173,12 @@ byte CRC32_BlockSequence( byte *base, int length, int sequence )
|
||||
|
||||
void MD5Transform( uint buf[4], const uint in[16] );
|
||||
|
||||
static void MD5SwapBlock( uint *block, int count )
|
||||
{
|
||||
for( int i = 0; i < count; i++ )
|
||||
block[i] = LittleLong( block[i] );
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
MD5Update
|
||||
@@ -206,6 +212,7 @@ void MD5Update( MD5Context_t *ctx, const byte *buf, uint len )
|
||||
}
|
||||
|
||||
memcpy( p, buf, t );
|
||||
MD5SwapBlock( ctx->in, 16 );
|
||||
MD5Transform( ctx->buf, ctx->in );
|
||||
buf += t;
|
||||
len -= t;
|
||||
@@ -215,6 +222,7 @@ void MD5Update( MD5Context_t *ctx, const byte *buf, uint len )
|
||||
while( len >= 64 )
|
||||
{
|
||||
memcpy( ctx->in, buf, 64 );
|
||||
MD5SwapBlock( ctx->in, 16 );
|
||||
MD5Transform( ctx->buf, ctx->in );
|
||||
buf += 64;
|
||||
len -= 64;
|
||||
@@ -254,6 +262,7 @@ void MD5Final( byte digest[16], MD5Context_t *ctx )
|
||||
|
||||
// two lots of padding: pad the first block to 64 bytes
|
||||
memset( p, 0, count );
|
||||
MD5SwapBlock( ctx->in, 16 );
|
||||
MD5Transform( ctx->buf, ctx->in );
|
||||
|
||||
// now fill the next block with 56 bytes
|
||||
@@ -265,11 +274,16 @@ void MD5Final( byte digest[16], MD5Context_t *ctx )
|
||||
memset( p, 0, count - 8 );
|
||||
}
|
||||
|
||||
MD5SwapBlock( ctx->in, 14 );
|
||||
|
||||
// append length in bits and transform
|
||||
ctx->in[14] = ctx->bits[0];
|
||||
ctx->in[15] = ctx->bits[1];
|
||||
|
||||
MD5Transform( ctx->buf, ctx->in );
|
||||
|
||||
// output digest in little-endian byte order
|
||||
MD5SwapBlock( ctx->buf, 4 );
|
||||
memcpy( digest, ctx->buf, 16 );
|
||||
memset( ctx, 0, sizeof( *ctx )); // in case it's sensitive
|
||||
}
|
||||
|
||||
151
public/swaplib.h
Normal file
151
public/swaplib.h
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
swaplib.h - byte-swapping for on-disk structures
|
||||
Copyright (C) 2026 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.
|
||||
*/
|
||||
|
||||
#ifndef SWAPLIB_H
|
||||
#define SWAPLIB_H
|
||||
|
||||
#include "build.h"
|
||||
#include "xash3d_types.h"
|
||||
|
||||
typedef struct swap_struct_def_s
|
||||
{
|
||||
uint32_t offset;
|
||||
int32_t size;
|
||||
struct swap_struct_def_s *subdef;
|
||||
uint32_t count;
|
||||
uint32_t stride;
|
||||
} swap_struct_def_t;
|
||||
|
||||
static inline void swap_two_bytes_( byte *a, byte *b )
|
||||
{
|
||||
byte tmp = *a;
|
||||
*a = *b;
|
||||
*b = tmp;
|
||||
}
|
||||
|
||||
static inline void swap_field_( byte *p, int32_t size )
|
||||
{
|
||||
switch( size )
|
||||
{
|
||||
case 2:
|
||||
swap_two_bytes_( &p[0], &p[1] );
|
||||
break;
|
||||
case 4:
|
||||
swap_two_bytes_( &p[0], &p[3] );
|
||||
swap_two_bytes_( &p[1], &p[2] );
|
||||
break;
|
||||
case 8:
|
||||
swap_two_bytes_( &p[0], &p[7] );
|
||||
swap_two_bytes_( &p[1], &p[6] );
|
||||
swap_two_bytes_( &p[2], &p[5] );
|
||||
swap_two_bytes_( &p[3], &p[4] );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// this potentially breaks strict aliasing
|
||||
static inline void swap_struct_( const swap_struct_def_t *def, size_t len, byte *data )
|
||||
{
|
||||
for( size_t i = 0; i < len; i++ )
|
||||
{
|
||||
if( def[i].size < 0 ) // negative size is reserved to reference other swap defs
|
||||
{
|
||||
uint32_t count = def[i].count ? def[i].count : 1;
|
||||
for( uint32_t j = 0; j < count; j++ )
|
||||
swap_struct_( def[i].subdef, -def[i].size, &data[def[i].offset + j * def[i].stride] );
|
||||
continue;
|
||||
}
|
||||
|
||||
if( def[i].count > 0 ) // go over array of elements
|
||||
{
|
||||
for( uint32_t j = 0; j < def[i].count; j++ )
|
||||
swap_field_( &data[def[i].offset + j * def[i].stride], def[i].size );
|
||||
continue;
|
||||
}
|
||||
|
||||
// process single field
|
||||
swap_field_( &data[def[i].offset], def[i].size );
|
||||
}
|
||||
}
|
||||
|
||||
static inline void swap_array_( byte *data, int32_t elem_size, uint32_t count )
|
||||
{
|
||||
for( uint32_t i = 0; i < count; i++ )
|
||||
swap_field_( &data[i * elem_size], elem_size );
|
||||
}
|
||||
|
||||
// do not use these macros, they will swap structs unconditionally
|
||||
// you might want to use le_/be_ macros instead
|
||||
#define swap_struct( swapdef, ptr ) swap_struct_(( swapdef ), sizeof( swapdef ) / sizeof( swapdef[0] ), (byte *)( ptr ))
|
||||
#define swap_array( ptr, count ) swap_array_((byte *)( ptr ), sizeof( *( ptr )), ( count ))
|
||||
|
||||
#define swap_struct_begin( swapdef ) static swap_struct_def_t swapdef[] = {
|
||||
#define swap_struct_end() }
|
||||
|
||||
// declare a single field
|
||||
#define swap_struct_field( record, field ) { .offset = offsetof( record, field ), .size = sizeof(((record *)0)->field) },
|
||||
|
||||
// declare a struct, defined by another swap_struct
|
||||
#define swap_struct_child( record, field, child ) { .offset = offsetof( record, field ), .size = -(int32_t)(sizeof( child ) / sizeof( child[0] )), .subdef = child },
|
||||
|
||||
// declare an array of fields, doesn't work with flexible array members
|
||||
#define swap_struct_array( record, field, cnt ) { .offset = offsetof( record, field ), .size = sizeof(((record *)0)->field[0]), .count = cnt, .stride = sizeof(((record *)0)->field[0]) },
|
||||
|
||||
// combined swap_struct_child and swap_struct_array
|
||||
#define swap_struct_array_child( record, field, child, cnt ) { .offset = offsetof( record, field ), .size = -(int32_t)(sizeof( child ) / sizeof( child[0] )), .subdef = child, .count = cnt, .stride = sizeof(((record *)0)->field[0]) },
|
||||
|
||||
|
||||
// this is done in macros so we can completely avoid defining this
|
||||
// in little endian targets
|
||||
#if XASH_LITTLE_ENDIAN
|
||||
#define be_struct_begin( x ) swap_struct_begin( x )
|
||||
#define be_struct_field( x, y ) swap_struct_field( x, y )
|
||||
#define be_struct_child( x, y, z ) swap_struct_child( x, y, z )
|
||||
#define be_struct_array( x, y, z ) swap_struct_array( x, y, z )
|
||||
#define be_struct_array_child( x, y, z, w ) swap_struct_array_child( x, y, z, w )
|
||||
#define be_struct_end() swap_struct_end()
|
||||
#define be_struct_swap( x, y ) swap_struct( x, y )
|
||||
#define be_array_swap( x, y ) swap_array( x, y )
|
||||
#define le_struct_begin( x )
|
||||
#define le_struct_field( x, y )
|
||||
#define le_struct_child( x, y, z )
|
||||
#define le_struct_array( x, y, z )
|
||||
#define le_struct_array_child( x, y, z, w )
|
||||
#define le_struct_end() extern int _le_struct_end_dummy // define as extern variable, to let end() end with ;
|
||||
#define le_struct_swap( x, y ) (void)(y)
|
||||
#define le_array_swap( x, y ) (void)(x)
|
||||
#else
|
||||
#define be_struct_begin( x )
|
||||
#define be_struct_field( x, y )
|
||||
#define be_struct_child( x, y, z )
|
||||
#define be_struct_array( x, y, z )
|
||||
#define be_struct_array_child( x, y, z, w )
|
||||
#define be_struct_end() extern int _le_struct_end_dummy
|
||||
#define be_struct_swap( x, y ) (void)(y)
|
||||
#define be_array_swap( x, y ) (void)(x)
|
||||
#define le_struct_begin( x ) swap_struct_begin( x )
|
||||
#define le_struct_field( x, y ) swap_struct_field( x, y )
|
||||
#define le_struct_child( x, y, z ) swap_struct_child( x, y, z )
|
||||
#define le_struct_array( x, y, z ) swap_struct_array( x, y, z )
|
||||
#define le_struct_array_child( x, y, z, w ) swap_struct_array_child( x, y, z, w )
|
||||
#define le_struct_end() swap_struct_end()
|
||||
#define le_struct_swap( x, y ) swap_struct( x, y )
|
||||
#define le_array_swap( x, y ) swap_array( x, y )
|
||||
#endif
|
||||
|
||||
|
||||
#endif // SWAPLIB_H
|
||||
131
public/tests/test_atlas.c
Normal file
131
public/tests/test_atlas.c
Normal file
@@ -0,0 +1,131 @@
|
||||
#include "atlas.h"
|
||||
|
||||
static int Test_BasicAlloc( void )
|
||||
{
|
||||
atlas_t atlas;
|
||||
int x, y;
|
||||
|
||||
Atlas_Init( &atlas, 128 );
|
||||
|
||||
if( !Atlas_AllocBlock( &atlas, 16, 16, &x, &y ))
|
||||
return 1;
|
||||
|
||||
if( x != 0 || y != 0 )
|
||||
return 2;
|
||||
|
||||
if( atlas.max_height != 16 )
|
||||
return 3;
|
||||
|
||||
if( !Atlas_AllocBlock( &atlas, 16, 16, &x, &y ))
|
||||
return 4;
|
||||
|
||||
if( x != 16 || y != 0 )
|
||||
return 5;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Test_Full( void )
|
||||
{
|
||||
atlas_t atlas;
|
||||
int x, y;
|
||||
|
||||
Atlas_Init( &atlas, 64 );
|
||||
|
||||
if( !Atlas_AllocBlock( &atlas, 64, 64, &x, &y ))
|
||||
return 1;
|
||||
|
||||
if( Atlas_AllocBlock( &atlas, 1, 1, &x, &y ))
|
||||
return 2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Test_Packing( void )
|
||||
{
|
||||
atlas_t atlas;
|
||||
int x, y;
|
||||
|
||||
Atlas_Init( &atlas, 64 );
|
||||
|
||||
if( !Atlas_AllocBlock( &atlas, 32, 16, &x, &y ))
|
||||
return 1;
|
||||
|
||||
if( !Atlas_AllocBlock( &atlas, 32, 16, &x, &y ))
|
||||
return 2;
|
||||
|
||||
if( x != 32 || y != 0 )
|
||||
return 3;
|
||||
|
||||
if( !Atlas_AllocBlock( &atlas, 64, 16, &x, &y ))
|
||||
return 4;
|
||||
|
||||
if( y != 16 )
|
||||
return 5;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Test_Reset( void )
|
||||
{
|
||||
atlas_t atlas;
|
||||
int x, y;
|
||||
|
||||
Atlas_Init( &atlas, 64 );
|
||||
|
||||
if( !Atlas_AllocBlock( &atlas, 64, 64, &x, &y ))
|
||||
return 1;
|
||||
|
||||
Atlas_Init( &atlas, 64 );
|
||||
|
||||
if( !Atlas_AllocBlock( &atlas, 64, 64, &x, &y ))
|
||||
return 2;
|
||||
|
||||
if( x != 0 || y != 0 )
|
||||
return 3;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Test_TooLarge( void )
|
||||
{
|
||||
atlas_t atlas;
|
||||
int x, y;
|
||||
|
||||
Atlas_Init( &atlas, 64 );
|
||||
|
||||
if( Atlas_AllocBlock( &atlas, 65, 1, &x, &y ))
|
||||
return 1;
|
||||
|
||||
if( Atlas_AllocBlock( &atlas, 1, 65, &x, &y ))
|
||||
return 2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main( void )
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = Test_BasicAlloc();
|
||||
if( ret > 0 )
|
||||
return ret;
|
||||
|
||||
ret = Test_Full();
|
||||
if( ret > 0 )
|
||||
return ret + 16;
|
||||
|
||||
ret = Test_Packing();
|
||||
if( ret > 0 )
|
||||
return ret + 32;
|
||||
|
||||
ret = Test_Reset();
|
||||
if( ret > 0 )
|
||||
return ret + 48;
|
||||
|
||||
ret = Test_TooLarge();
|
||||
if( ret > 0 )
|
||||
return ret + 64;
|
||||
|
||||
return 0;
|
||||
}
|
||||
235
public/tests/test_swapstruct.c
Normal file
235
public/tests/test_swapstruct.c
Normal file
@@ -0,0 +1,235 @@
|
||||
#include <stddef.h>
|
||||
#include "swaplib.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
} inner_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t a;
|
||||
uint16_t b;
|
||||
uint32_t c;
|
||||
inner_t inner;
|
||||
} outer_t;
|
||||
|
||||
swap_struct_begin( inner_def )
|
||||
swap_struct_field( inner_t, x )
|
||||
swap_struct_field( inner_t, y )
|
||||
swap_struct_end();
|
||||
|
||||
swap_struct_begin( outer_def )
|
||||
swap_struct_field( outer_t, b )
|
||||
swap_struct_field( outer_t, c )
|
||||
swap_struct_child( outer_t, inner, inner_def )
|
||||
swap_struct_end();
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t version;
|
||||
inner_t items[4];
|
||||
} array_outer_t;
|
||||
|
||||
swap_struct_begin( array_outer_def )
|
||||
swap_struct_field( array_outer_t, version )
|
||||
swap_struct_array_child( array_outer_t, items, inner_def, 4 )
|
||||
swap_struct_end();
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t tag;
|
||||
uint32_t values[3];
|
||||
} int_array_t;
|
||||
|
||||
swap_struct_begin( int_array_def )
|
||||
swap_struct_field( int_array_t, tag )
|
||||
swap_struct_array( int_array_t, values, 3 )
|
||||
swap_struct_end();
|
||||
|
||||
static int Test_SwapField( void )
|
||||
{
|
||||
inner_t data = { .x = 0x0102, .y = 0x0304 };
|
||||
|
||||
swap_struct( inner_def, &data );
|
||||
|
||||
if( data.x != 0x0201 )
|
||||
return 1;
|
||||
|
||||
if( data.y != 0x0403 )
|
||||
return 2;
|
||||
|
||||
// swap again, should restore original
|
||||
swap_struct( inner_def, &data );
|
||||
|
||||
if( data.x != 0x0102 )
|
||||
return 3;
|
||||
|
||||
if( data.y != 0x0304 )
|
||||
return 4;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Test_SwapChild( void )
|
||||
{
|
||||
outer_t data =
|
||||
{
|
||||
.a = 0xAA,
|
||||
.b = 0x0102,
|
||||
.c = 0x01020304,
|
||||
.inner = { .x = 0x0506, .y = 0x0708 },
|
||||
};
|
||||
|
||||
swap_struct( outer_def, &data );
|
||||
|
||||
// a is uint8_t, must be untouched
|
||||
if( data.a != 0xAA )
|
||||
return 1;
|
||||
|
||||
// b must be byte-swapped
|
||||
if( data.b != 0x0201 )
|
||||
return 2;
|
||||
|
||||
// c must be byte-swapped
|
||||
if( data.c != 0x04030201 )
|
||||
return 3;
|
||||
|
||||
// child fields must be byte-swapped
|
||||
if( data.inner.x != 0x0605 )
|
||||
return 4;
|
||||
|
||||
if( data.inner.y != 0x0807 )
|
||||
return 5;
|
||||
|
||||
// swap back
|
||||
swap_struct( outer_def, &data );
|
||||
|
||||
if( data.b != 0x0102 )
|
||||
return 6;
|
||||
|
||||
if( data.c != 0x01020304 )
|
||||
return 7;
|
||||
|
||||
if( data.inner.x != 0x0506 )
|
||||
return 8;
|
||||
|
||||
if( data.inner.y != 0x0708 )
|
||||
return 9;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Test_SwapArrayChild( void )
|
||||
{
|
||||
array_outer_t data =
|
||||
{
|
||||
.version = 0x01020304,
|
||||
.items =
|
||||
{
|
||||
{ .x = 0x0102, .y = 0x0304 },
|
||||
{ .x = 0x0506, .y = 0x0708 },
|
||||
{ .x = 0x090A, .y = 0x0B0C },
|
||||
{ .x = 0x0D0E, .y = 0x0F10 },
|
||||
},
|
||||
};
|
||||
|
||||
swap_struct( array_outer_def, &data );
|
||||
|
||||
if( data.version != 0x04030201 )
|
||||
return 1;
|
||||
|
||||
if( data.items[0].x != 0x0201 || data.items[0].y != 0x0403 )
|
||||
return 2;
|
||||
|
||||
if( data.items[1].x != 0x0605 || data.items[1].y != 0x0807 )
|
||||
return 3;
|
||||
|
||||
if( data.items[2].x != 0x0A09 || data.items[2].y != 0x0C0B )
|
||||
return 4;
|
||||
|
||||
if( data.items[3].x != 0x0E0D || data.items[3].y != 0x100F )
|
||||
return 5;
|
||||
|
||||
// swap back
|
||||
swap_struct( array_outer_def, &data );
|
||||
|
||||
if( data.version != 0x01020304 )
|
||||
return 6;
|
||||
|
||||
if( data.items[0].x != 0x0102 || data.items[0].y != 0x0304 )
|
||||
return 7;
|
||||
|
||||
if( data.items[3].x != 0x0D0E || data.items[3].y != 0x0F10 )
|
||||
return 8;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Test_SwapArray( void )
|
||||
{
|
||||
int_array_t data =
|
||||
{
|
||||
.tag = 0x0102,
|
||||
.values = { 0x01020304, 0x05060708, 0x090A0B0C },
|
||||
};
|
||||
|
||||
swap_struct( int_array_def, &data );
|
||||
|
||||
if( data.tag != 0x0201 )
|
||||
return 1;
|
||||
|
||||
if( data.values[0] != 0x04030201 )
|
||||
return 2;
|
||||
|
||||
if( data.values[1] != 0x08070605 )
|
||||
return 3;
|
||||
|
||||
if( data.values[2] != 0x0C0B0A09 )
|
||||
return 4;
|
||||
|
||||
// swap back
|
||||
swap_struct( int_array_def, &data );
|
||||
|
||||
if( data.tag != 0x0102 )
|
||||
return 5;
|
||||
|
||||
if( data.values[0] != 0x01020304 )
|
||||
return 6;
|
||||
|
||||
if( data.values[1] != 0x05060708 )
|
||||
return 7;
|
||||
|
||||
if( data.values[2] != 0x090A0B0C )
|
||||
return 8;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main( void )
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = Test_SwapField();
|
||||
|
||||
if( ret > 0 )
|
||||
return ret;
|
||||
|
||||
ret = Test_SwapChild();
|
||||
|
||||
if( ret > 0 )
|
||||
return ret + 32;
|
||||
|
||||
ret = Test_SwapArrayChild();
|
||||
|
||||
if( ret > 0 )
|
||||
return ret + 64;
|
||||
|
||||
ret = Test_SwapArray();
|
||||
|
||||
if( ret > 0 )
|
||||
return ret + 96;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -157,6 +157,8 @@ def build(bld):
|
||||
'efp': 'tests/test_efp.c',
|
||||
'atoi': 'tests/test_atoi.c',
|
||||
'parsefile': 'tests/test_parsefile.c',
|
||||
'atlas': 'tests/test_atlas.c',
|
||||
'swapstruct': 'tests/test_swapstruct.c',
|
||||
}
|
||||
|
||||
for i in tests:
|
||||
|
||||
94
ref/common/ref_common.h
Normal file
94
ref/common/ref_common.h
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
ref_common.h - shared renderer code
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef REF_COMMON_H
|
||||
#define REF_COMMON_H
|
||||
|
||||
#include "xash3d_mathlib.h"
|
||||
#include "ref_api.h"
|
||||
|
||||
//
|
||||
// ref_context.c
|
||||
//
|
||||
extern ref_api_t gEngfuncs;
|
||||
extern ref_globals_t *gpGlobals;
|
||||
extern ref_client_t *gp_cl;
|
||||
extern ref_host_t *gp_host;
|
||||
extern struct movevars_s *gp_movevars;
|
||||
extern const ref_interface_t gReffuncs;
|
||||
|
||||
DECLARE_ENGINE_SHARED_CVAR_LIST()
|
||||
|
||||
#define Assert( x ) if( !( x )) gEngfuncs.Host_Error( "assert failed at %s:%i\n", __FILE__, __LINE__ )
|
||||
|
||||
#define ENGINE_GET_PARM_ (*gEngfuncs.EngineGetParm)
|
||||
#define ENGINE_GET_PARM( parm ) ENGINE_GET_PARM_( (parm), 0 )
|
||||
|
||||
extern uint16_t rtable[MOD_FRAMES][MOD_FRAMES];
|
||||
void GL_InitRandomTable( void );
|
||||
|
||||
void _Mem_Free( void *data, const char *filename, int fileline );
|
||||
void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char *filename, int fileline )
|
||||
ALLOC_CHECK( 2 ) MALLOC_LIKE( _Mem_Free, 1 ) WARN_UNUSED_RESULT;
|
||||
void *_Mem_Realloc( poolhandle_t poolptr, void *memptr, size_t size, qboolean clear, const char *filename, int fileline )
|
||||
ALLOC_CHECK( 3 ) WARN_UNUSED_RESULT;
|
||||
|
||||
#define Mem_Malloc( pool, size ) _Mem_Alloc( pool, size, false, __FILE__, __LINE__ )
|
||||
#define Mem_Calloc( pool, size ) _Mem_Alloc( pool, size, true, __FILE__, __LINE__ )
|
||||
#define Mem_Realloc( pool, ptr, size ) _Mem_Realloc( pool, ptr, size, true, __FILE__, __LINE__ )
|
||||
#define Mem_Free( mem ) _Mem_Free( mem, __FILE__, __LINE__ )
|
||||
#define Mem_AllocPool( name ) gEngfuncs._Mem_AllocPool( name, __FILE__, __LINE__ )
|
||||
#define Mem_FreePool( pool ) gEngfuncs._Mem_FreePool( pool, __FILE__, __LINE__ )
|
||||
#define Mem_EmptyPool( pool ) gEngfuncs._Mem_EmptyPool( pool, __FILE__, __LINE__ )
|
||||
|
||||
extern dlight_t *gp_dlights;
|
||||
extern int g_lightstylevalue[MAX_LIGHTSTYLES];
|
||||
extern poolhandle_t r_temppool;
|
||||
|
||||
//
|
||||
// ref_common cvars
|
||||
//
|
||||
extern convar_t r_dlight_virtual_radius;
|
||||
extern convar_t r_lighting_extended;
|
||||
|
||||
//
|
||||
// ref_math.c
|
||||
//
|
||||
void Matrix4x4_Concat( matrix4x4 out, const matrix4x4 in1, const matrix4x4 in2 );
|
||||
void Matrix4x4_ConcatTranslate( matrix4x4 out, float x, float y, float z );
|
||||
void Matrix4x4_ConcatRotate( matrix4x4 out, float angle, float x, float y, float z );
|
||||
void Matrix4x4_CreateProjection( matrix4x4 out, float xMax, float xMin, float yMax, float yMin, float zNear, float zFar );
|
||||
void Matrix4x4_CreateOrtho( matrix4x4 m, float xLeft, float xRight, float yBottom, float yTop, float zNear, float zFar );
|
||||
void Matrix4x4_CreateModelview( matrix4x4 out );
|
||||
void Matrix4x4_ToArrayFloatGL( const matrix4x4 in, float out[16] );
|
||||
|
||||
//
|
||||
// ref_light.c
|
||||
//
|
||||
void CL_RunLightStyles( lightstyle_t *ls );
|
||||
void R_PushDlightsForBmodel( model_t *model, int framecount, const matrix4x4 object_matrix );
|
||||
int R_PushDlights( model_t *model, int framecount );
|
||||
colorVec R_LightVec( const vec3_t start, const vec3_t end, vec3_t lspot, vec3_t lvec );
|
||||
colorVec R_LightPoint( const vec3_t p0 );
|
||||
void R_EntityDynamicLight( cl_entity_t *ent, alight_t *plight, qboolean draw_world, double time, vec3_t lightspot, vec3_t lightvec );
|
||||
void R_GatherPlayerLight( cl_entity_t *view );
|
||||
void R_UpdateSurfaceCachedLight( msurface_t *surf );
|
||||
|
||||
//
|
||||
// ref_image.c
|
||||
//
|
||||
byte *GL_ResampleTexture( const byte *source, int in_w, int in_h, int out_w, int out_h, qboolean isNormalMap );
|
||||
|
||||
#endif // REF_COMMON_H
|
||||
83
ref/common/ref_context.c
Normal file
83
ref/common/ref_context.c
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
ref_context.c - shared renderer context
|
||||
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 "ref_common.h"
|
||||
#include "com_strings.h"
|
||||
|
||||
DEFINE_ENGINE_SHARED_CVAR_LIST()
|
||||
|
||||
ref_api_t gEngfuncs;
|
||||
ref_globals_t *gpGlobals;
|
||||
ref_client_t *gp_cl;
|
||||
ref_host_t *gp_host;
|
||||
struct movevars_s *gp_movevars;
|
||||
uint16_t rtable[MOD_FRAMES][MOD_FRAMES];
|
||||
dlight_t *gp_dlights;
|
||||
int g_lightstylevalue[MAX_LIGHTSTYLES];
|
||||
poolhandle_t r_temppool;
|
||||
|
||||
void _Mem_Free( void *data, const char *filename, int fileline )
|
||||
{
|
||||
gEngfuncs._Mem_Free( data, filename, fileline );
|
||||
}
|
||||
|
||||
void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char *filename, int fileline )
|
||||
{
|
||||
return gEngfuncs._Mem_Alloc( poolptr, size, clear, filename, fileline );
|
||||
}
|
||||
|
||||
void *_Mem_Realloc( poolhandle_t poolptr, void *memptr, size_t size, qboolean clear, const char *filename, int fileline )
|
||||
{
|
||||
return gEngfuncs._Mem_Realloc( poolptr, memptr, size, clear, filename, fileline );
|
||||
}
|
||||
|
||||
void GL_InitRandomTable( void )
|
||||
{
|
||||
int tu, tv;
|
||||
|
||||
for( tu = 0; tu < MOD_FRAMES; tu++ )
|
||||
{
|
||||
for( tv = 0; tv < MOD_FRAMES; tv++ )
|
||||
{
|
||||
rtable[tu][tv] = gEngfuncs.COM_RandomLong( 0, 0x7FFF );
|
||||
}
|
||||
}
|
||||
|
||||
gEngfuncs.COM_SetRandomSeed( 0 );
|
||||
}
|
||||
|
||||
int EXPORT GetRefAPI( int version, ref_interface_t *funcs, ref_api_t *engfuncs, ref_globals_t *globals );
|
||||
int EXPORT GetRefAPI( int version, ref_interface_t *funcs, ref_api_t *engfuncs, ref_globals_t *globals )
|
||||
{
|
||||
if( version != REF_API_VERSION )
|
||||
return 0;
|
||||
|
||||
// fill in our callbacks
|
||||
*funcs = gReffuncs;
|
||||
gEngfuncs = *engfuncs;
|
||||
gpGlobals = globals;
|
||||
|
||||
gp_cl = (ref_client_t *)ENGINE_GET_PARM( PARM_GET_CLIENT_PTR );
|
||||
gp_host = (ref_host_t *)ENGINE_GET_PARM( PARM_GET_HOST_PTR );
|
||||
gp_movevars = (struct movevars_s *)ENGINE_GET_PARM( PARM_GET_MOVEVARS_PTR );
|
||||
gp_dlights = (dlight_t *)ENGINE_GET_PARM( PARM_GET_DLIGHTS_PTR );
|
||||
|
||||
RETRIEVE_ENGINE_SHARED_CVAR_LIST();
|
||||
|
||||
gEngfuncs.Cvar_RegisterVariable( &r_dlight_virtual_radius );
|
||||
gEngfuncs.Cvar_RegisterVariable( &r_lighting_extended );
|
||||
|
||||
return REF_API_VERSION;
|
||||
}
|
||||
108
ref/common/ref_image.c
Normal file
108
ref/common/ref_image.c
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
ref_image.c - shared image code
|
||||
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 "ref_common.h"
|
||||
#include "xash3d_mathlib.h"
|
||||
|
||||
/*
|
||||
================
|
||||
GL_ResampleTexture
|
||||
|
||||
Assume input buffer is RGBA
|
||||
=================
|
||||
*/
|
||||
byte *GL_ResampleTexture( const byte *source, int inWidth, int inHeight, int outWidth, int outHeight, qboolean isNormalMap )
|
||||
{
|
||||
uint frac, fracStep;
|
||||
uint *in = (uint *)source;
|
||||
uint p1[0x1000], p2[0x1000];
|
||||
byte *pix1, *pix2, *pix3, *pix4;
|
||||
uint *out, *inRow1, *inRow2;
|
||||
static byte *scaledImage = NULL; // pointer to a scaled image
|
||||
vec3_t normal;
|
||||
int i, x, y;
|
||||
|
||||
if( !source ) return NULL;
|
||||
|
||||
scaledImage = Mem_Realloc( r_temppool, scaledImage, outWidth * outHeight * 4 );
|
||||
fracStep = inWidth * 0x10000 / outWidth;
|
||||
out = (uint *)scaledImage;
|
||||
|
||||
frac = fracStep >> 2;
|
||||
for( i = 0; i < outWidth; i++ )
|
||||
{
|
||||
p1[i] = 4 * (frac >> 16);
|
||||
frac += fracStep;
|
||||
}
|
||||
|
||||
frac = (fracStep >> 2) * 3;
|
||||
for( i = 0; i < outWidth; i++ )
|
||||
{
|
||||
p2[i] = 4 * (frac >> 16);
|
||||
frac += fracStep;
|
||||
}
|
||||
|
||||
if( isNormalMap )
|
||||
{
|
||||
for( y = 0; y < outHeight; y++, out += outWidth )
|
||||
{
|
||||
inRow1 = in + inWidth * (int)(((float)y + 0.25f) * inHeight / outHeight);
|
||||
inRow2 = in + inWidth * (int)(((float)y + 0.75f) * inHeight / outHeight);
|
||||
|
||||
for( x = 0; x < outWidth; x++ )
|
||||
{
|
||||
pix1 = (byte *)inRow1 + p1[x];
|
||||
pix2 = (byte *)inRow1 + p2[x];
|
||||
pix3 = (byte *)inRow2 + p1[x];
|
||||
pix4 = (byte *)inRow2 + p2[x];
|
||||
|
||||
normal[0] = MAKE_SIGNED( pix1[0] ) + MAKE_SIGNED( pix2[0] ) + MAKE_SIGNED( pix3[0] ) + MAKE_SIGNED( pix4[0] );
|
||||
normal[1] = MAKE_SIGNED( pix1[1] ) + MAKE_SIGNED( pix2[1] ) + MAKE_SIGNED( pix3[1] ) + MAKE_SIGNED( pix4[1] );
|
||||
normal[2] = MAKE_SIGNED( pix1[2] ) + MAKE_SIGNED( pix2[2] ) + MAKE_SIGNED( pix3[2] ) + MAKE_SIGNED( pix4[2] );
|
||||
|
||||
if( !VectorNormalizeLength( normal ))
|
||||
VectorSet( normal, 0.5f, 0.5f, 1.0f );
|
||||
|
||||
((byte *)(out+x))[0] = 128 + (byte)(127.0f * normal[0]);
|
||||
((byte *)(out+x))[1] = 128 + (byte)(127.0f * normal[1]);
|
||||
((byte *)(out+x))[2] = 128 + (byte)(127.0f * normal[2]);
|
||||
((byte *)(out+x))[3] = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( y = 0; y < outHeight; y++, out += outWidth )
|
||||
{
|
||||
inRow1 = in + inWidth * (int)(((float)y + 0.25f) * inHeight / outHeight);
|
||||
inRow2 = in + inWidth * (int)(((float)y + 0.75f) * inHeight / outHeight);
|
||||
|
||||
for( x = 0; x < outWidth; x++ )
|
||||
{
|
||||
pix1 = (byte *)inRow1 + p1[x];
|
||||
pix2 = (byte *)inRow1 + p2[x];
|
||||
pix3 = (byte *)inRow2 + p1[x];
|
||||
pix4 = (byte *)inRow2 + p2[x];
|
||||
|
||||
((byte *)(out+x))[0] = (pix1[0] + pix2[0] + pix3[0] + pix4[0]) >> 2;
|
||||
((byte *)(out+x))[1] = (pix1[1] + pix2[1] + pix3[1] + pix4[1]) >> 2;
|
||||
((byte *)(out+x))[2] = (pix1[2] + pix2[2] + pix3[2] + pix4[2]) >> 2;
|
||||
((byte *)(out+x))[3] = (pix1[3] + pix2[3] + pix3[3] + pix4[3]) >> 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return scaledImage;
|
||||
}
|
||||
698
ref/common/ref_light.c
Normal file
698
ref/common/ref_light.c
Normal file
@@ -0,0 +1,698 @@
|
||||
/*
|
||||
ref_light.c - shared light code
|
||||
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 "ref_common.h"
|
||||
#include "xash3d_mathlib.h"
|
||||
#include "enginefeatures.h"
|
||||
#include "pm_local.h"
|
||||
|
||||
CVAR_DEFINE_AUTO( r_dlight_virtual_radius, "3", FCVAR_GLCONFIG, "increase dlight radius virtually by this amount" );
|
||||
CVAR_DEFINE_AUTO( r_lighting_extended, "1", FCVAR_GLCONFIG, "allow to get lighting from world and bmodels" );
|
||||
|
||||
/*
|
||||
==================
|
||||
CL_RunLightStyles
|
||||
|
||||
==================
|
||||
*/
|
||||
void CL_RunLightStyles( lightstyle_t *ls )
|
||||
{
|
||||
const model_t *world = gp_cl->models[1];
|
||||
int i;
|
||||
float frametime = gp_cl->time - gp_cl->oldtime;
|
||||
|
||||
if( !world )
|
||||
return;
|
||||
|
||||
if( r_fullbright->value || !world->lightdata )
|
||||
{
|
||||
for( i = 0; i < MAX_LIGHTSTYLES; i++ )
|
||||
g_lightstylevalue[i] = 256 * 256;
|
||||
return;
|
||||
}
|
||||
|
||||
// light animations
|
||||
// 'm' is normal light, 'a' is no light, 'z' is double bright
|
||||
for( i = 0; i < MAX_LIGHTSTYLES; i++ )
|
||||
{
|
||||
int k, flight, clight;
|
||||
float l, lerpfrac, backlerp;
|
||||
|
||||
if( !gp_cl->paused && frametime <= 0.1f )
|
||||
ls[i].time += frametime; // evaluate local time
|
||||
|
||||
if( !ls[i].length )
|
||||
{
|
||||
g_lightstylevalue[i] = 256;
|
||||
continue;
|
||||
}
|
||||
else if( ls[i].length == 1 )
|
||||
{
|
||||
// single length style so don't bother interpolating
|
||||
g_lightstylevalue[i] = ls[i].map[0] * 22;
|
||||
continue;
|
||||
}
|
||||
|
||||
flight = (int)Q_floor( ls[i].time * 10 );
|
||||
|
||||
if( !ls[i].interp || !cl_lightstyle_lerping->value )
|
||||
{
|
||||
g_lightstylevalue[i] = ls[i].map[flight % ls[i].length] * 22;
|
||||
continue;
|
||||
}
|
||||
|
||||
clight = (int)Q_ceil( ls[i].time * 10 );
|
||||
lerpfrac = ( ls[i].time * 10 ) - flight;
|
||||
backlerp = 1.0f - lerpfrac;
|
||||
|
||||
// interpolate animating light
|
||||
// frame just gone
|
||||
k = ls[i].map[flight % ls[i].length];
|
||||
l = (float)( k * 22.0f ) * backlerp;
|
||||
|
||||
// upcoming frame
|
||||
k = ls[i].map[clight % ls[i].length];
|
||||
l += (float)( k * 22.0f ) * lerpfrac;
|
||||
|
||||
g_lightstylevalue[i] = (int)l;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
R_MarkLights
|
||||
=============
|
||||
*/
|
||||
static void R_MarkLights( const dlight_t *light, int bit, const mnode_t *node, model_t *model, int dlightframecount )
|
||||
{
|
||||
const float virtual_radius = light->radius * Q_max( 1.0f, r_dlight_virtual_radius.value );
|
||||
const float maxdist = light->radius * light->radius;
|
||||
start:
|
||||
if( !node || node->contents < 0 )
|
||||
return;
|
||||
|
||||
float dist = PlaneDiff( light->origin, node->plane );
|
||||
|
||||
if( dist > virtual_radius )
|
||||
{
|
||||
node = node_child( node, 0, model );
|
||||
goto start;
|
||||
}
|
||||
|
||||
if( dist < -virtual_radius )
|
||||
{
|
||||
node = node_child( node, 1, model );
|
||||
goto start;
|
||||
}
|
||||
|
||||
const float dist_sq = dist * dist;
|
||||
|
||||
// mark the polygons
|
||||
int firstsurface = node_firstsurface( node, model );
|
||||
int numsurfaces = node_numsurfaces( node, model );
|
||||
|
||||
for( int i = 0; i < numsurfaces && dist_sq < maxdist; i++ )
|
||||
{
|
||||
vec3_t impact;
|
||||
float s, t, l;
|
||||
msurface_t *surf = &model->surfaces[firstsurface + i];
|
||||
const mextrasurf_t *info = surf->info;
|
||||
|
||||
if( surf->plane->type < 3 )
|
||||
{
|
||||
VectorCopy( light->origin, impact );
|
||||
impact[surf->plane->type] -= dist;
|
||||
}
|
||||
else VectorMA( light->origin, -dist, surf->plane->normal, impact );
|
||||
|
||||
// a1ba: the fix was taken from JoeQuake, which traces back to FitzQuake,
|
||||
// which attributes it to LadyHavoc (Darkplaces author)
|
||||
// clamp center of light to corner and check brightness
|
||||
l = DotProduct( impact, info->lmvecs[0] ) + info->lmvecs[0][3] - info->lightmapmins[0];
|
||||
s = l + 0.5;
|
||||
s = bound( 0, s, info->lightextents[0] );
|
||||
s = l - s;
|
||||
|
||||
l = DotProduct( impact, info->lmvecs[1] ) + info->lmvecs[1][3] - info->lightmapmins[1];
|
||||
t = l + 0.5;
|
||||
t = bound( 0, t, info->lightextents[1] );
|
||||
t = l - t;
|
||||
|
||||
if( s * s + t * t + dist_sq >= maxdist )
|
||||
continue;
|
||||
|
||||
if( surf->dlightframe != dlightframecount )
|
||||
{
|
||||
surf->dlightbits = bit;
|
||||
surf->dlightframe = dlightframecount;
|
||||
}
|
||||
else surf->dlightbits |= bit;
|
||||
}
|
||||
|
||||
R_MarkLights( light, bit, node_child( node, 0, model ), model, dlightframecount );
|
||||
node = node_child( node, 1, model );
|
||||
goto start;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
R_PushDlights
|
||||
=============
|
||||
*/
|
||||
int R_PushDlights( model_t *model, int framecount )
|
||||
{
|
||||
if( !model )
|
||||
return framecount;
|
||||
|
||||
for( int i = 0; i < MAX_DLIGHTS; i++ )
|
||||
{
|
||||
const dlight_t *l = &gp_dlights[i];
|
||||
|
||||
if( l->die < gp_cl->time || !l->radius )
|
||||
continue;
|
||||
|
||||
R_MarkLights( l, 1 << i, model->nodes, model, framecount );
|
||||
}
|
||||
|
||||
return framecount;
|
||||
}
|
||||
|
||||
void R_PushDlightsForBmodel( model_t *model, int framecount, const matrix4x4 object_matrix )
|
||||
{
|
||||
for( int i = 0; i < MAX_DLIGHTS; i++ )
|
||||
{
|
||||
dlight_t *l = &gp_dlights[i];
|
||||
|
||||
if( l->die < gp_cl->time || !l->radius )
|
||||
continue;
|
||||
|
||||
vec3_t oldorigin;
|
||||
VectorCopy( l->origin, oldorigin );
|
||||
|
||||
Matrix4x4_VectorITransform( object_matrix, oldorigin, l->origin );
|
||||
R_MarkLights( l, 1 << i, model->nodes + model->hulls[0].firstclipnode, model, framecount );
|
||||
|
||||
VectorCopy( oldorigin, l->origin );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=======================================================================
|
||||
|
||||
AMBIENT LIGHTING
|
||||
|
||||
=======================================================================
|
||||
*/
|
||||
static vec3_t g_trace_lightspot;
|
||||
static vec3_t g_trace_lightvec;
|
||||
static float g_trace_fraction;
|
||||
|
||||
/*
|
||||
=================
|
||||
R_RecursiveLightPoint
|
||||
=================
|
||||
*/
|
||||
static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f, float p2f, colorVec *cv, const vec3_t start, const vec3_t end )
|
||||
{
|
||||
start:
|
||||
// didn't hit anything
|
||||
if( !node || node->contents < 0 )
|
||||
{
|
||||
cv->r = cv->g = cv->b = cv->a = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
// calculate mid point
|
||||
float front = PlaneDiff( start, node->plane );
|
||||
float back = PlaneDiff( end, node->plane );
|
||||
|
||||
int side = front < 0;
|
||||
if(( back < 0 ) == side )
|
||||
{
|
||||
node = node_child( node, side, model );
|
||||
goto start;
|
||||
}
|
||||
|
||||
float frac = front / ( front - back );
|
||||
|
||||
vec3_t mid;
|
||||
VectorLerp( start, frac, end, mid );
|
||||
|
||||
float midf = p1f + ( p2f - p1f ) * frac;
|
||||
|
||||
// co down front side
|
||||
if( R_RecursiveLightPoint( model, node_child( node, side, model ), p1f, midf, cv, start, mid ))
|
||||
return true; // hit something
|
||||
|
||||
if(( back < 0 ) == side )
|
||||
{
|
||||
cv->r = cv->g = cv->b = cv->a = 0;
|
||||
return false; // didn't hit anything
|
||||
}
|
||||
|
||||
// check for impact on this node
|
||||
int firstsurface = node_firstsurface( node, model );
|
||||
int numsurfaces = node_numsurfaces( node, model );
|
||||
|
||||
VectorCopy( mid, g_trace_lightspot );
|
||||
|
||||
for( int i = 0; i < numsurfaces; i++ )
|
||||
{
|
||||
const msurface_t *surf = &model->surfaces[firstsurface + i];
|
||||
const mextrasurf_t *info = surf->info;
|
||||
|
||||
if( FBitSet( surf->flags, SURF_DRAWTILED ))
|
||||
continue; // no lightmaps
|
||||
|
||||
float s = DotProduct( mid, info->lmvecs[0] ) + info->lmvecs[0][3];
|
||||
float t = DotProduct( mid, info->lmvecs[1] ) + info->lmvecs[1][3];
|
||||
|
||||
if( s < info->lightmapmins[0] || t < info->lightmapmins[1] )
|
||||
continue;
|
||||
|
||||
float ds = s - info->lightmapmins[0];
|
||||
float dt = t - info->lightmapmins[1];
|
||||
|
||||
if ( ds > info->lightextents[0] || dt > info->lightextents[1] )
|
||||
continue;
|
||||
|
||||
cv->r = cv->g = cv->b = cv->a = 0;
|
||||
|
||||
if( !surf->samples )
|
||||
return true;
|
||||
|
||||
int sample_size = gEngfuncs.Mod_SampleSizeForFace( surf );
|
||||
int smax = (info->lightextents[0] / sample_size) + 1;
|
||||
int tmax = (info->lightextents[1] / sample_size) + 1;
|
||||
|
||||
ds /= sample_size;
|
||||
dt /= sample_size;
|
||||
|
||||
g_trace_fraction = midf;
|
||||
|
||||
const color24 *lm = surf->samples + Q_rint( dt ) * smax + Q_rint( ds );
|
||||
const color24 *dm = NULL;
|
||||
matrix3x4 tbn;
|
||||
|
||||
if( surf->info->deluxemap )
|
||||
{
|
||||
vec3_t faceNormal;
|
||||
|
||||
dm = surf->info->deluxemap + Q_rint( dt ) * smax + Q_rint( ds );
|
||||
|
||||
if( FBitSet( surf->flags, SURF_PLANEBACK ))
|
||||
VectorNegate( surf->plane->normal, faceNormal );
|
||||
else VectorCopy( surf->plane->normal, faceNormal );
|
||||
|
||||
// compute face TBN
|
||||
#if 1
|
||||
Vector4Set( tbn[0], surf->info->lmvecs[0][0], surf->info->lmvecs[0][1], surf->info->lmvecs[0][2], 0.0f );
|
||||
Vector4Set( tbn[1], -surf->info->lmvecs[1][0], -surf->info->lmvecs[1][1], -surf->info->lmvecs[1][2], 0.0f );
|
||||
Vector4Set( tbn[2], faceNormal[0], faceNormal[1], faceNormal[2], 0.0f );
|
||||
#else
|
||||
Vector4Set( tbn[0], surf->info->lmvecs[0][0], -surf->info->lmvecs[1][0], faceNormal[0], 0.0f );
|
||||
Vector4Set( tbn[1], surf->info->lmvecs[0][1], -surf->info->lmvecs[1][1], faceNormal[1], 0.0f );
|
||||
Vector4Set( tbn[2], surf->info->lmvecs[0][2], -surf->info->lmvecs[1][2], faceNormal[2], 0.0f );
|
||||
#endif
|
||||
VectorNormalize( tbn[0] );
|
||||
VectorNormalize( tbn[1] );
|
||||
VectorNormalize( tbn[2] );
|
||||
}
|
||||
|
||||
int size = smax * tmax;
|
||||
|
||||
for( int map = 0; map < MAXLIGHTMAPS && surf->styles[map] != 255; map++ )
|
||||
{
|
||||
uint scale = g_lightstylevalue[surf->styles[map]];
|
||||
|
||||
cv->r += lm->r * scale;
|
||||
cv->g += lm->g * scale;
|
||||
cv->b += lm->b * scale;
|
||||
|
||||
lm += size; // skip to next lightmap
|
||||
|
||||
if( dm != NULL )
|
||||
{
|
||||
vec3_t srcNormal, lightNormal;
|
||||
float f = (1.0f / 128.0f);
|
||||
|
||||
VectorSet( srcNormal, ((float)dm->r - 128.0f) * f, ((float)dm->g - 128.0f) * f, ((float)dm->b - 128.0f) * f );
|
||||
Matrix3x4_VectorIRotate( tbn, srcNormal, lightNormal ); // turn to world space
|
||||
VectorScale( lightNormal, (float)scale * -1.0f, lightNormal ); // turn direction from light
|
||||
VectorAdd( g_trace_lightvec, lightNormal, g_trace_lightvec );
|
||||
dm += size; // skip to next deluxmap
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// go down back side
|
||||
return R_RecursiveLightPoint( model, node_child( node, !side, model ), midf, p2f, cv, mid, end );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
R_LightVecInternal
|
||||
|
||||
check bspmodels to get light from
|
||||
=================
|
||||
*/
|
||||
static colorVec R_LightVecInternal( const vec3_t start, const vec3_t end, vec3_t lspot, vec3_t lvec )
|
||||
{
|
||||
if( lspot )
|
||||
VectorClear( lspot );
|
||||
|
||||
if( lvec )
|
||||
VectorClear( lvec );
|
||||
|
||||
if( !gp_cl->models[1] || !gp_cl->models[1]->lightdata )
|
||||
return (colorVec){ 255, 255, 255, 0 };
|
||||
|
||||
float last_fraction = 1.0f;
|
||||
int max_ents = r_lighting_extended.value ? MAX_PHYSENTS : 1; // get light from bmodels too
|
||||
colorVec light = { 0 };
|
||||
|
||||
// check all the bsp-models
|
||||
for( int i = 0; i < max_ents; i++ )
|
||||
{
|
||||
const physent_t *pe = gEngfuncs.EV_GetPhysent( i );
|
||||
|
||||
if( !pe )
|
||||
break;
|
||||
|
||||
if( !pe->model || pe->model->type != mod_brush )
|
||||
continue; // skip non-bsp models
|
||||
|
||||
mnode_t *pnodes = &pe->model->nodes[pe->model->hulls[0].firstclipnode];
|
||||
vec3_t offset, start_l, end_l;
|
||||
|
||||
VectorSubtract( pe->model->hulls[0].clip_mins, vec3_origin, offset );
|
||||
VectorAdd( offset, pe->origin, offset );
|
||||
VectorSubtract( start, offset, start_l );
|
||||
VectorSubtract( end, offset, end_l );
|
||||
|
||||
// rotate start and end into the models frame of reference
|
||||
if( !VectorIsNull( pe->angles ))
|
||||
{
|
||||
matrix4x4 matrix;
|
||||
Matrix4x4_CreateFromEntity( matrix, pe->angles, offset, 1.0f );
|
||||
Matrix4x4_VectorITransform( matrix, start, start_l );
|
||||
Matrix4x4_VectorITransform( matrix, end, end_l );
|
||||
}
|
||||
|
||||
VectorClear( g_trace_lightspot );
|
||||
VectorClear( g_trace_lightvec );
|
||||
g_trace_fraction = 1.0f;
|
||||
|
||||
colorVec cv;
|
||||
if( !R_RecursiveLightPoint( pe->model, pnodes, 0.0f, 1.0f, &cv, start_l, end_l ))
|
||||
continue; // didn't hit anything
|
||||
|
||||
if( g_trace_fraction < last_fraction )
|
||||
{
|
||||
if( lspot ) VectorCopy( g_trace_lightspot, lspot );
|
||||
if( lvec ) VectorNormalize2( g_trace_lightvec, lvec );
|
||||
|
||||
light.r = Q_min(( cv.r >> 8 ), 255 );
|
||||
light.g = Q_min(( cv.g >> 8 ), 255 );
|
||||
light.b = Q_min(( cv.b >> 8 ), 255 );
|
||||
last_fraction = g_trace_fraction;
|
||||
|
||||
if(( light.r + light.g + light.b ) != 0 )
|
||||
break; // we get light now
|
||||
}
|
||||
}
|
||||
|
||||
return light;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
R_LightVec
|
||||
|
||||
check bspmodels to get light from
|
||||
=================
|
||||
*/
|
||||
colorVec R_LightVec( const vec3_t start, const vec3_t end, vec3_t lspot, vec3_t lvec )
|
||||
{
|
||||
colorVec light = R_LightVecInternal( start, end, lspot, lvec );
|
||||
|
||||
if( r_lighting_extended.value && lspot != NULL && lvec != NULL )
|
||||
{
|
||||
// trying to get light from ceiling (but ignore gradient analyze)
|
||||
if(( light.r + light.g + light.b ) == 0 )
|
||||
return R_LightVecInternal( end, start, lspot, lvec );
|
||||
}
|
||||
|
||||
return light;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
R_LightPoint
|
||||
|
||||
light from floor
|
||||
=================
|
||||
*/
|
||||
colorVec R_LightPoint( const vec3_t p0 )
|
||||
{
|
||||
vec3_t p1;
|
||||
|
||||
VectorSet( p1, p0[0], p0[1], p0[2] - 2048.0f );
|
||||
|
||||
return R_LightVec( p0, p1, NULL, NULL );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
R_GatherPlayerLight
|
||||
|
||||
get light level of an entity and set it as player's light level
|
||||
=================
|
||||
*/
|
||||
void R_GatherPlayerLight( cl_entity_t *view )
|
||||
{
|
||||
colorVec c = R_LightPoint( view->origin );
|
||||
|
||||
gEngfuncs.SetLocalLightLevel(( c.r + c.g + c.b ) / 3 );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
R_EntityDynamicLight
|
||||
|
||||
===============
|
||||
*/
|
||||
void R_EntityDynamicLight( cl_entity_t *ent, alight_t *plight, qboolean draw_world, double time, vec3_t lightspot, vec3_t lightvec )
|
||||
{
|
||||
movevars_t *mv = gp_movevars;
|
||||
vec3_t lightDir, vecSrc, vecEnd;
|
||||
vec3_t origin, dist, finalLight;
|
||||
float add, radius, total;
|
||||
colorVec light;
|
||||
uint lnum;
|
||||
dlight_t *dl;
|
||||
|
||||
if( !plight || !ent )
|
||||
return;
|
||||
|
||||
if( !draw_world || r_fullbright->value || FBitSet( ent->curstate.effects, EF_FULLBRIGHT ))
|
||||
{
|
||||
plight->shadelight = 0;
|
||||
plight->ambientlight = 192;
|
||||
|
||||
VectorSet( plight->plightvec, 0.0f, 0.0f, -1.0f );
|
||||
VectorSet( plight->color, 1.0f, 1.0f, 1.0f );
|
||||
return;
|
||||
}
|
||||
|
||||
// determine plane to get lightvalues from: ceil or floor
|
||||
if( FBitSet( ent->curstate.effects, EF_INVLIGHT ))
|
||||
VectorSet( lightDir, 0.0f, 0.0f, 1.0f );
|
||||
else
|
||||
VectorSet( lightDir, 0.0f, 0.0f, -1.0f );
|
||||
|
||||
VectorCopy( ent->origin, origin );
|
||||
|
||||
VectorSet( vecSrc, origin[0], origin[1], origin[2] - lightDir[2] * 8.0f );
|
||||
light.r = light.g = light.b = light.a = 0;
|
||||
|
||||
if(( mv->skycolor[0] + mv->skycolor[1] + mv->skycolor[2] ) != 0 )
|
||||
{
|
||||
msurface_t *psurf = NULL;
|
||||
pmtrace_t trace;
|
||||
vec3_t skyvec;
|
||||
|
||||
if( FBitSet( gp_host->features, ENGINE_WRITE_LARGE_COORD ))
|
||||
VectorScale( mv->skyvec, 65536.0f, skyvec );
|
||||
else
|
||||
VectorScale( mv->skyvec, 8192.0f, skyvec );
|
||||
|
||||
VectorSubtract( origin, skyvec, vecEnd );
|
||||
|
||||
trace = gEngfuncs.CL_TraceLine( vecSrc, vecEnd, PM_WORLD_ONLY );
|
||||
if( trace.ent > 0 )
|
||||
psurf = gEngfuncs.EV_TraceSurface( trace.ent, vecSrc, vecEnd );
|
||||
else
|
||||
psurf = gEngfuncs.EV_TraceSurface( 0, vecSrc, vecEnd );
|
||||
|
||||
if(( ent->model->type == mod_studio && FBitSet( ent->model->flags, STUDIO_FORCE_SKYLIGHT ))
|
||||
|| ( psurf && FBitSet( psurf->flags, SURF_DRAWSKY )))
|
||||
{
|
||||
VectorCopy( mv->skyvec, lightDir );
|
||||
|
||||
light.r = mv->skycolor[0];
|
||||
light.g = mv->skycolor[1];
|
||||
light.b = mv->skycolor[2];
|
||||
}
|
||||
}
|
||||
|
||||
if(( light.r + light.g + light.b ) == 0 )
|
||||
{
|
||||
colorVec gcolor;
|
||||
float grad[4];
|
||||
|
||||
VectorScale( lightDir, 2048.0f, vecEnd );
|
||||
VectorAdd( vecEnd, vecSrc, vecEnd );
|
||||
|
||||
light = R_LightVec( vecSrc, vecEnd, lightspot, lightvec );
|
||||
|
||||
if( VectorIsNull( lightvec ))
|
||||
{
|
||||
vecSrc[0] -= 16.0f;
|
||||
vecSrc[1] -= 16.0f;
|
||||
vecEnd[0] -= 16.0f;
|
||||
vecEnd[1] -= 16.0f;
|
||||
|
||||
gcolor = R_LightVec( vecSrc, vecEnd, NULL, NULL );
|
||||
grad[0] = ( gcolor.r + gcolor.g + gcolor.b ) / 768.0f;
|
||||
|
||||
vecSrc[0] += 32.0f;
|
||||
vecEnd[0] += 32.0f;
|
||||
|
||||
gcolor = R_LightVec( vecSrc, vecEnd, NULL, NULL );
|
||||
grad[1] = ( gcolor.r + gcolor.g + gcolor.b ) / 768.0f;
|
||||
|
||||
vecSrc[1] += 32.0f;
|
||||
vecEnd[1] += 32.0f;
|
||||
|
||||
gcolor = R_LightVec( vecSrc, vecEnd, NULL, NULL );
|
||||
grad[2] = ( gcolor.r + gcolor.g + gcolor.b ) / 768.0f;
|
||||
|
||||
vecSrc[0] -= 32.0f;
|
||||
vecEnd[0] -= 32.0f;
|
||||
|
||||
gcolor = R_LightVec( vecSrc, vecEnd, NULL, NULL );
|
||||
grad[3] = ( gcolor.r + gcolor.g + gcolor.b ) / 768.0f;
|
||||
|
||||
lightDir[0] = grad[0] - grad[1] - grad[2] + grad[3];
|
||||
lightDir[1] = grad[1] + grad[0] - grad[2] - grad[3];
|
||||
VectorNormalize( lightDir );
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorCopy( lightvec, lightDir );
|
||||
}
|
||||
}
|
||||
|
||||
if( ent->curstate.renderfx == kRenderFxLightMultiplier && ent->curstate.iuser4 != 10 )
|
||||
{
|
||||
light.r *= ent->curstate.iuser4 / 10.0f;
|
||||
light.g *= ent->curstate.iuser4 / 10.0f;
|
||||
light.b *= ent->curstate.iuser4 / 10.0f;
|
||||
}
|
||||
|
||||
VectorSet( finalLight, light.r, light.g, light.b );
|
||||
ent->cvFloorColor = light;
|
||||
|
||||
total = Q_max( Q_max( light.r, light.g ), light.b );
|
||||
if( total == 0.0f )
|
||||
total = 1.0f;
|
||||
|
||||
// scale lightdir by light intentsity
|
||||
VectorScale( lightDir, total, lightDir );
|
||||
|
||||
for( lnum = 0; lnum < MAX_DLIGHTS; lnum++ )
|
||||
{
|
||||
dl = &gp_dlights[lnum];
|
||||
|
||||
if( dl->die < time || !r_dynamic->value )
|
||||
continue;
|
||||
|
||||
VectorSubtract( ent->origin, dl->origin, dist );
|
||||
|
||||
radius = VectorLength( dist );
|
||||
add = ( dl->radius - radius );
|
||||
|
||||
if( add > 0.0f )
|
||||
{
|
||||
total += add;
|
||||
|
||||
if( radius > 1.0f )
|
||||
VectorScale( dist, ( add / radius ), dist );
|
||||
else
|
||||
VectorScale( dist, add, dist );
|
||||
|
||||
VectorAdd( lightDir, dist, lightDir );
|
||||
|
||||
finalLight[0] += dl->color.r * ( add / 256.0f );
|
||||
finalLight[1] += dl->color.g * ( add / 256.0f );
|
||||
finalLight[2] += dl->color.b * ( add / 256.0f );
|
||||
}
|
||||
}
|
||||
|
||||
if( ent->model->type == mod_alias )
|
||||
add = 0.9f;
|
||||
else if( ent->model->type == mod_studio && FBitSet( ent->model->flags, STUDIO_AMBIENT_LIGHT ))
|
||||
add = 0.6f;
|
||||
else
|
||||
add = bound( 0.75f, v_direct->value, 1.0f );
|
||||
|
||||
VectorScale( lightDir, add, lightDir );
|
||||
|
||||
plight->shadelight = VectorLength( lightDir );
|
||||
plight->ambientlight = total - plight->shadelight;
|
||||
|
||||
total = Q_max( Q_max( finalLight[0], finalLight[1] ), finalLight[2] );
|
||||
|
||||
if( total > 0.0f )
|
||||
{
|
||||
plight->color[0] = finalLight[0] * ( 1.0f / total );
|
||||
plight->color[1] = finalLight[1] * ( 1.0f / total );
|
||||
plight->color[2] = finalLight[2] * ( 1.0f / total );
|
||||
}
|
||||
else
|
||||
VectorSet( plight->color, 1.0f, 1.0f, 1.0f );
|
||||
|
||||
if( plight->ambientlight > 128 )
|
||||
plight->ambientlight = 128;
|
||||
|
||||
if( plight->ambientlight + plight->shadelight > 255 )
|
||||
plight->shadelight = 255 - plight->ambientlight;
|
||||
|
||||
VectorNormalize2( lightDir, plight->plightvec );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
R_SetCacheState
|
||||
================
|
||||
*/
|
||||
void R_UpdateSurfaceCachedLight( msurface_t *surf )
|
||||
{
|
||||
for( int i = 0; i < MAXLIGHTMAPS && surf->styles[i] != 255; i++ )
|
||||
surf->cached_light[i] = g_lightstylevalue[surf->styles[i]];
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
gl_rmath.c - renderer mathlib
|
||||
ref_math.c - renderer mathlib
|
||||
Copyright (C) 2010 Uncle Mike
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
@@ -13,8 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "r_local.h"
|
||||
#include "xash3d_mathlib.h"
|
||||
#include "ref_common.h"
|
||||
|
||||
/*
|
||||
========================================================================
|
||||
@@ -99,7 +98,27 @@ void Matrix4x4_CreateModelview( matrix4x4 out )
|
||||
out[1][2] = 1.0f;
|
||||
}
|
||||
|
||||
void Matrix4x4_CreateTranslate( matrix4x4 out, float x, float y, float z )
|
||||
void Matrix4x4_ToArrayFloatGL( const matrix4x4 in, float out[16] )
|
||||
{
|
||||
out[ 0] = in[0][0];
|
||||
out[ 1] = in[1][0];
|
||||
out[ 2] = in[2][0];
|
||||
out[ 3] = in[3][0];
|
||||
out[ 4] = in[0][1];
|
||||
out[ 5] = in[1][1];
|
||||
out[ 6] = in[2][1];
|
||||
out[ 7] = in[3][1];
|
||||
out[ 8] = in[0][2];
|
||||
out[ 9] = in[1][2];
|
||||
out[10] = in[2][2];
|
||||
out[11] = in[3][2];
|
||||
out[12] = in[0][3];
|
||||
out[13] = in[1][3];
|
||||
out[14] = in[2][3];
|
||||
out[15] = in[3][3];
|
||||
}
|
||||
|
||||
static void Matrix4x4_CreateTranslate( matrix4x4 out, float x, float y, float z )
|
||||
{
|
||||
out[0][0] = 1.0f;
|
||||
out[0][1] = 0.0f;
|
||||
@@ -119,7 +138,7 @@ void Matrix4x4_CreateTranslate( matrix4x4 out, float x, float y, float z )
|
||||
out[3][3] = 1.0f;
|
||||
}
|
||||
|
||||
void Matrix4x4_CreateRotate( matrix4x4 out, float angle, float x, float y, float z )
|
||||
static void Matrix4x4_CreateRotate( matrix4x4 out, float angle, float x, float y, float z )
|
||||
{
|
||||
float len, c, s;
|
||||
|
||||
27
ref/common/wscript
Normal file
27
ref/common/wscript
Normal file
@@ -0,0 +1,27 @@
|
||||
#! /usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
def options(opt):
|
||||
pass
|
||||
|
||||
def configure(conf):
|
||||
pass
|
||||
|
||||
def build(bld):
|
||||
use = ['engine_includes', 'sdk_includes', 'werror']
|
||||
|
||||
# FIXME: figure out why psvita needs it and how can we avoid it
|
||||
if bld.env.DEST_OS == 'psvita':
|
||||
bld.env.CFLAGS_cstlib.remove('-fno-PIC')
|
||||
bld.env.CFLAGS += ['-fPIC']
|
||||
else:
|
||||
use += ['public']
|
||||
|
||||
bld.stlib(source = bld.path.ant_glob('*.c'),
|
||||
target = 'ref_common',
|
||||
includes = '.',
|
||||
export_includes = '.',
|
||||
defines = 'REF_DLL=1',
|
||||
use = use,
|
||||
subsystem = bld.env.MSVC_SUBSYSTEM
|
||||
)
|
||||
@@ -1681,10 +1681,12 @@ static void APIENTRY GL2_BindBufferARB( GLenum buf, GLuint obj )
|
||||
rpglBindBufferARB( buf, obj );
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void APIENTRY GL2_ActiveTextureARB( GLenum tex )
|
||||
{
|
||||
//gl2wrap_arrays.texture = GL_TEXTURE0_ARB - tex;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void APIENTRY GL2_ClientActiveTextureARB( GLenum tex )
|
||||
{
|
||||
@@ -1736,6 +1738,7 @@ static void APIENTRY GL2_ShadeModel(GLenum mode)
|
||||
{
|
||||
}
|
||||
|
||||
#if XASH_GLES
|
||||
static void APIENTRY GL2_PolygonMode(GLenum face, GLenum mode)
|
||||
{
|
||||
}
|
||||
@@ -1747,6 +1750,7 @@ static void APIENTRY GL2_PointSize(GLfloat size)
|
||||
static void APIENTRY GL2_DrawBuffer(GLenum mode)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#if XASH_EMSCRIPTEN
|
||||
static void GL2_PolygonOffset( GLfloat factor, GLfloat units )
|
||||
@@ -1783,10 +1787,12 @@ void GL2_ShimInstall( void )
|
||||
GL2_OVERRIDE_PTR( TexEnvi )
|
||||
GL2_OVERRIDE_PTR( TexEnvf )
|
||||
GL2_OVERRIDE_PTR( ClientActiveTextureARB )
|
||||
//GL2_OVERRIDE_PTR( ActiveTextureARB )
|
||||
#if 0 // FIXME: figure out why it's disabled
|
||||
GL2_OVERRIDE_PTR( ActiveTextureARB )
|
||||
#endif
|
||||
GL2_OVERRIDE_PTR( Fogi )
|
||||
GL2_OVERRIDE_PTR( ShadeModel )
|
||||
#ifdef XASH_GLES
|
||||
#if XASH_GLES
|
||||
_pglDepthRangef = gEngfuncs.GL_GetProcAddress( "glDepthRangef" );
|
||||
GL2_OVERRIDE_PTR( PolygonMode )
|
||||
GL2_OVERRIDE_PTR( PointSize )
|
||||
|
||||
@@ -559,181 +559,6 @@ void Mod_AliasUnloadTextures( void *data )
|
||||
=============================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
===============
|
||||
R_AliasDynamicLight
|
||||
|
||||
similar to R_StudioDynamicLight
|
||||
===============
|
||||
*/
|
||||
static void R_AliasDynamicLight( cl_entity_t *ent, alight_t *plight )
|
||||
{
|
||||
movevars_t *mv = tr.movevars;
|
||||
vec3_t lightDir, vecSrc, vecEnd;
|
||||
vec3_t origin, dist, finalLight;
|
||||
float add, radius, total;
|
||||
colorVec light;
|
||||
uint lnum;
|
||||
|
||||
if( !plight || !ent )
|
||||
return;
|
||||
|
||||
if( !RI.drawWorld || r_fullbright->value || FBitSet( ent->curstate.effects, EF_FULLBRIGHT ))
|
||||
{
|
||||
plight->shadelight = 0;
|
||||
plight->ambientlight = 192;
|
||||
|
||||
VectorSet( plight->plightvec, 0.0f, 0.0f, -1.0f );
|
||||
VectorSet( plight->color, 1.0f, 1.0f, 1.0f );
|
||||
return;
|
||||
}
|
||||
|
||||
// determine plane to get lightvalues from: ceil or floor
|
||||
if( FBitSet( ent->curstate.effects, EF_INVLIGHT ))
|
||||
VectorSet( lightDir, 0.0f, 0.0f, 1.0f );
|
||||
else VectorSet( lightDir, 0.0f, 0.0f, -1.0f );
|
||||
|
||||
VectorCopy( ent->origin, origin );
|
||||
|
||||
VectorSet( vecSrc, origin[0], origin[1], origin[2] - lightDir[2] * 8.0f );
|
||||
light.r = light.g = light.b = light.a = 0;
|
||||
|
||||
if(( mv->skycolor[0] + mv->skycolor[1] + mv->skycolor[2] ) != 0 )
|
||||
{
|
||||
msurface_t *psurf = NULL;
|
||||
pmtrace_t trace;
|
||||
vec3_t skyvec;
|
||||
|
||||
if( FBitSet( gp_host->features, ENGINE_WRITE_LARGE_COORD ))
|
||||
VectorScale( mv->skyvec, 65536.0f, skyvec );
|
||||
else
|
||||
VectorScale( mv->skyvec, 8192.0f, skyvec );
|
||||
|
||||
VectorSubtract( origin, skyvec, vecEnd );
|
||||
|
||||
trace = gEngfuncs.CL_TraceLine( vecSrc, vecEnd, PM_STUDIO_IGNORE );
|
||||
if( trace.ent > 0 ) psurf = gEngfuncs.EV_TraceSurface( trace.ent, vecSrc, vecEnd );
|
||||
else psurf = gEngfuncs.EV_TraceSurface( 0, vecSrc, vecEnd );
|
||||
|
||||
if( psurf && FBitSet( psurf->flags, SURF_DRAWSKY ))
|
||||
{
|
||||
VectorCopy( mv->skyvec, lightDir );
|
||||
|
||||
light.r = mv->skycolor[0];
|
||||
light.g = mv->skycolor[1];
|
||||
light.b = mv->skycolor[2];
|
||||
}
|
||||
}
|
||||
|
||||
if(( light.r + light.g + light.b ) == 0 )
|
||||
{
|
||||
colorVec gcolor;
|
||||
float grad[4];
|
||||
|
||||
VectorScale( lightDir, 2048.0f, vecEnd );
|
||||
VectorAdd( vecEnd, vecSrc, vecEnd );
|
||||
|
||||
light = R_LightVec( vecSrc, vecEnd, g_alias.lightspot, g_alias.lightvec );
|
||||
|
||||
if( VectorIsNull( g_alias.lightvec ))
|
||||
{
|
||||
vecSrc[0] -= 16.0f;
|
||||
vecSrc[1] -= 16.0f;
|
||||
vecEnd[0] -= 16.0f;
|
||||
vecEnd[1] -= 16.0f;
|
||||
|
||||
gcolor = R_LightVec( vecSrc, vecEnd, NULL, NULL );
|
||||
grad[0] = ( gcolor.r + gcolor.g + gcolor.b ) / 768.0f;
|
||||
|
||||
vecSrc[0] += 32.0f;
|
||||
vecEnd[0] += 32.0f;
|
||||
|
||||
gcolor = R_LightVec( vecSrc, vecEnd, NULL, NULL );
|
||||
grad[1] = ( gcolor.r + gcolor.g + gcolor.b ) / 768.0f;
|
||||
|
||||
vecSrc[1] += 32.0f;
|
||||
vecEnd[1] += 32.0f;
|
||||
|
||||
gcolor = R_LightVec( vecSrc, vecEnd, NULL, NULL );
|
||||
grad[2] = ( gcolor.r + gcolor.g + gcolor.b ) / 768.0f;
|
||||
|
||||
vecSrc[0] -= 32.0f;
|
||||
vecEnd[0] -= 32.0f;
|
||||
|
||||
gcolor = R_LightVec( vecSrc, vecEnd, NULL, NULL );
|
||||
grad[3] = ( gcolor.r + gcolor.g + gcolor.b ) / 768.0f;
|
||||
|
||||
lightDir[0] = grad[0] - grad[1] - grad[2] + grad[3];
|
||||
lightDir[1] = grad[1] + grad[0] - grad[2] - grad[3];
|
||||
VectorNormalize( lightDir );
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorCopy( g_alias.lightvec, lightDir );
|
||||
}
|
||||
}
|
||||
|
||||
VectorSet( finalLight, light.r, light.g, light.b );
|
||||
ent->cvFloorColor = light;
|
||||
|
||||
total = Q_max( Q_max( light.r, light.g ), light.b );
|
||||
if( total == 0.0f ) total = 1.0f;
|
||||
|
||||
// scale lightdir by light intentsity
|
||||
VectorScale( lightDir, total, lightDir );
|
||||
|
||||
for( lnum = 0; lnum < MAX_DLIGHTS; lnum++ )
|
||||
{
|
||||
const dlight_t *dl = &tr.dlights[lnum];
|
||||
|
||||
if( dl->die < g_alias.time || !r_dynamic->value )
|
||||
continue;
|
||||
|
||||
VectorSubtract( origin, dl->origin, dist );
|
||||
|
||||
radius = VectorLength( dist );
|
||||
add = dl->radius - radius;
|
||||
|
||||
if( add > 0.0f )
|
||||
{
|
||||
total += add;
|
||||
|
||||
if( radius > 1.0f )
|
||||
VectorScale( dist, ( add / radius ), dist );
|
||||
else VectorScale( dist, add, dist );
|
||||
|
||||
VectorAdd( lightDir, dist, lightDir );
|
||||
|
||||
finalLight[0] += dl->color.r * ( add / 256.0f );
|
||||
finalLight[1] += dl->color.g * ( add / 256.0f );
|
||||
finalLight[2] += dl->color.b * ( add / 256.0f );
|
||||
}
|
||||
}
|
||||
|
||||
VectorScale( lightDir, 0.9f, lightDir );
|
||||
|
||||
plight->shadelight = VectorLength( lightDir );
|
||||
plight->ambientlight = total - plight->shadelight;
|
||||
|
||||
total = Q_max( Q_max( finalLight[0], finalLight[1] ), finalLight[2] );
|
||||
|
||||
if( total > 0.0f )
|
||||
{
|
||||
plight->color[0] = finalLight[0] * ( 1.0f / total );
|
||||
plight->color[1] = finalLight[1] * ( 1.0f / total );
|
||||
plight->color[2] = finalLight[2] * ( 1.0f / total );
|
||||
}
|
||||
else VectorSet( plight->color, 1.0f, 1.0f, 1.0f );
|
||||
|
||||
if( plight->ambientlight > 128 )
|
||||
plight->ambientlight = 128;
|
||||
|
||||
if( plight->ambientlight + plight->shadelight > 255 )
|
||||
plight->shadelight = 255 - plight->ambientlight;
|
||||
|
||||
VectorNormalize2( lightDir, plight->plightvec );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
R_AliasSetupLighting
|
||||
@@ -1126,7 +951,7 @@ init current time for a given model
|
||||
*/
|
||||
static void R_AliasSetupTimings( void )
|
||||
{
|
||||
if( RI.drawWorld )
|
||||
if( FBitSet( RI.rvp.flags, RF_DRAW_WORLD ))
|
||||
{
|
||||
// synchronize with server time
|
||||
g_alias.time = gp_cl->time;
|
||||
@@ -1188,7 +1013,7 @@ void R_DrawAliasModel( cl_entity_t *e )
|
||||
// get lighting information
|
||||
//
|
||||
lighting.plightvec = dir;
|
||||
R_AliasDynamicLight( e, &lighting );
|
||||
R_EntityDynamicLight( e, &lighting, FBitSet( RI.rvp.flags, RF_DRAW_WORLD ), g_alias.time, g_alias.lightspot, g_alias.lightvec );
|
||||
|
||||
r_stats.c_alias_polys += m_pAliasHeader->numtris;
|
||||
r_stats.c_alias_models_drawn++;
|
||||
|
||||
@@ -61,7 +61,7 @@ void GL_BackendEndFrame( void )
|
||||
{
|
||||
mleaf_t *curleaf;
|
||||
|
||||
if( r_speeds->value <= 0 || !RI.drawWorld )
|
||||
if( r_speeds->value <= 0 || !FBitSet( RI.rvp.flags, RF_DRAW_WORLD ))
|
||||
return;
|
||||
|
||||
if( !RI.viewleaf )
|
||||
@@ -616,7 +616,7 @@ qboolean VID_CubemapShot( const char *base, uint size, const float *vieworg, qbo
|
||||
string basename;
|
||||
int i = 1, flags, result;
|
||||
|
||||
if( !RI.drawWorld || !WORLDMODEL )
|
||||
if( !FBitSet( RI.rvp.flags, RF_DRAW_WORLD ) || !WORLDMODEL )
|
||||
return false;
|
||||
|
||||
// make sure the specified size is valid
|
||||
@@ -633,7 +633,7 @@ qboolean VID_CubemapShot( const char *base, uint size, const float *vieworg, qbo
|
||||
r_side = Mem_Calloc( r_temppool, sizeof( rgbdata_t ));
|
||||
|
||||
// use client vieworg
|
||||
if( !vieworg ) vieworg = RI.vieworg;
|
||||
if( !vieworg ) vieworg = RI.rvp.vieworigin;
|
||||
|
||||
for( i = 0; i < 6; i++ )
|
||||
{
|
||||
|
||||
@@ -98,7 +98,7 @@ static void R_BeamComputeNormal( const vec3_t vStartPos, const vec3_t vNextPos,
|
||||
VectorSubtract( vStartPos, vNextPos, vTangentY );
|
||||
|
||||
// vDirToBeam = vector from viewer origin to beam
|
||||
VectorSubtract( vStartPos, RI.vieworg, vDirToBeam );
|
||||
VectorSubtract( vStartPos, RI.rvp.vieworigin, vDirToBeam );
|
||||
|
||||
// get a vector that is perpendicular to us and perpendicular to the beam.
|
||||
// this is used to fatten the beam.
|
||||
@@ -114,7 +114,7 @@ R_BeamCull
|
||||
Cull the beam by bbox
|
||||
==============
|
||||
*/
|
||||
qboolean R_BeamCull( const vec3_t start, const vec3_t end, qboolean pvsOnly )
|
||||
static qboolean R_BeamCull( const vec3_t start, const vec3_t end, qboolean pvsOnly )
|
||||
{
|
||||
vec3_t mins, maxs;
|
||||
int i;
|
||||
@@ -151,28 +151,6 @@ qboolean R_BeamCull( const vec3_t start, const vec3_t end, qboolean pvsOnly )
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
CL_AddCustomBeam
|
||||
|
||||
Add the beam that encoded as custom entity
|
||||
================
|
||||
*/
|
||||
void CL_AddCustomBeam( cl_entity_t *pEnvBeam )
|
||||
{
|
||||
if( tr.draw_list->num_beam_entities >= MAX_VISIBLE_PACKET )
|
||||
{
|
||||
gEngfuncs.Con_Printf( S_ERROR "Too many beams %d!\n", tr.draw_list->num_beam_entities );
|
||||
return;
|
||||
}
|
||||
|
||||
if( pEnvBeam )
|
||||
{
|
||||
tr.draw_list->beam_entities[tr.draw_list->num_beam_entities] = pEnvBeam;
|
||||
tr.draw_list->num_beam_entities++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============================================================
|
||||
@@ -1028,7 +1006,7 @@ static void R_BeamDraw( BEAM *pbeam, float frametime )
|
||||
float flDistance;
|
||||
|
||||
// fade the beam if the player's not looking at the source
|
||||
VectorSubtract( RI.vieworg, pbeam->source, localDir );
|
||||
VectorSubtract( RI.rvp.vieworigin, pbeam->source, localDir );
|
||||
flDot = DotProduct( delta, localDir );
|
||||
VectorScale( delta, flDot, vecProjection );
|
||||
VectorSubtract( localDir, vecProjection, tmp );
|
||||
|
||||
@@ -22,20 +22,7 @@ GNU General Public License for more details.
|
||||
#include "gl4es/include/gl4esinit.h"
|
||||
#endif
|
||||
|
||||
ref_api_t gEngfuncs;
|
||||
ref_globals_t *gpGlobals;
|
||||
ref_client_t *gp_cl;
|
||||
ref_host_t *gp_host;
|
||||
|
||||
void _Mem_Free( void *data, const char *filename, int fileline )
|
||||
{
|
||||
gEngfuncs._Mem_Free( data, filename, fileline );
|
||||
}
|
||||
|
||||
void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char *filename, int fileline )
|
||||
{
|
||||
return gEngfuncs._Mem_Alloc( poolptr, size, clear, filename, fileline );
|
||||
}
|
||||
|
||||
static void R_ClearScreen( void )
|
||||
{
|
||||
@@ -132,7 +119,6 @@ static void Mod_UnloadTextures( model_t *mod )
|
||||
Mod_BrushUnloadTextures( mod );
|
||||
break;
|
||||
case mod_sprite:
|
||||
Mod_SpriteUnloadTextures( mod->cache.data );
|
||||
break;
|
||||
default:
|
||||
Assert( 0 );
|
||||
@@ -159,7 +145,7 @@ static qboolean Mod_ProcessRenderData( model_t *mod, qboolean create, const byte
|
||||
loaded = true;
|
||||
break;
|
||||
case mod_sprite:
|
||||
Mod_LoadSpriteModel( mod, buf, &loaded, mod->numtexinfo );
|
||||
loaded = true;
|
||||
break;
|
||||
case mod_alias:
|
||||
Mod_LoadAliasModel( mod, buf, &loaded );
|
||||
@@ -175,7 +161,7 @@ static qboolean Mod_ProcessRenderData( model_t *mod, qboolean create, const byte
|
||||
return loaded;
|
||||
}
|
||||
|
||||
static int GL_RefGetParm( int parm, int arg )
|
||||
static intptr_t GL_RefGetParm( int parm, int arg )
|
||||
{
|
||||
gl_texture_t *glt;
|
||||
|
||||
@@ -228,7 +214,7 @@ static int GL_RefGetParm( int parm, int arg )
|
||||
return glState.activeTMU;
|
||||
case PARM_LIGHTSTYLEVALUE:
|
||||
arg = bound( 0, arg, MAX_LIGHTSTYLES - 1 );
|
||||
return tr.lightstylevalue[arg];
|
||||
return g_lightstylevalue[arg];
|
||||
case PARM_MAX_IMAGE_UNITS:
|
||||
return GL_MaxTextureUnits();
|
||||
case PARM_REBUILD_GAMMA:
|
||||
@@ -244,6 +230,8 @@ static int GL_RefGetParm( int parm, int arg )
|
||||
return gl_texture_nearest.value == 0.0f;
|
||||
|
||||
return GL_TextureFilteringEnabled( R_GetTexture( arg ));
|
||||
case PARM_GET_STUDIO_HDR:
|
||||
return (intptr_t)R_StudioGetHeader();
|
||||
default:
|
||||
return ENGINE_GET_PARM_( parm, arg );
|
||||
}
|
||||
@@ -258,6 +246,14 @@ static void R_GetDetailScaleForTexture( int texture, float *xScale, float *yScal
|
||||
if( yScale ) *yScale = glt->yscale;
|
||||
}
|
||||
|
||||
static void R_SetDetailScaleForTexture( int texture, float xScale, float yScale )
|
||||
{
|
||||
gl_texture_t *glt = R_GetTexture( texture );
|
||||
|
||||
glt->xscale = xScale;
|
||||
glt->yscale = yScale;
|
||||
}
|
||||
|
||||
static void R_GetExtraParmsForTexture( int texture, byte *red, byte *green, byte *blue, byte *density )
|
||||
{
|
||||
gl_texture_t *glt = R_GetTexture( texture );
|
||||
@@ -325,11 +321,6 @@ static void R_ProcessEntData( qboolean allocate, cl_entity_t *entities, unsigned
|
||||
gEngfuncs.drawFuncs->R_ProcessEntData( allocate );
|
||||
}
|
||||
|
||||
static void GAME_EXPORT R_Flush( unsigned int flags )
|
||||
{
|
||||
// stub
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
R_SetSkyCloudsTextures
|
||||
@@ -383,11 +374,6 @@ static qboolean R_SetDisplayTransform( ref_screen_rotation_t rotate, int offset_
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void GAME_EXPORT VGUI_UploadTextureBlock( int drawX, int drawY, const byte *rgba, int blockWidth, int blockHeight )
|
||||
{
|
||||
pglTexSubImage2D( GL_TEXTURE_2D, 0, drawX, drawY, blockWidth, blockHeight, GL_RGBA, GL_UNSIGNED_BYTE, rgba );
|
||||
}
|
||||
|
||||
static void GAME_EXPORT VGUI_SetupDrawing( qboolean rect )
|
||||
{
|
||||
pglEnable( GL_BLEND );
|
||||
@@ -427,7 +413,86 @@ static const char *R_GetConfigName( void )
|
||||
return "opengl";
|
||||
}
|
||||
|
||||
static const ref_interface_t gReffuncs =
|
||||
static void R_NewMap( void )
|
||||
{
|
||||
texture_t *tx;
|
||||
int i;
|
||||
|
||||
tr.worldmodel = gp_cl->models[1];
|
||||
|
||||
R_ClearDecals(); // clear all level decals
|
||||
|
||||
R_StudioResetPlayerModels();
|
||||
|
||||
// clear out efrags in case the level hasn't been reloaded
|
||||
for( i = 0; i < WORLDMODEL->numleafs; i++ )
|
||||
WORLDMODEL->leafs[i+1].efrags = NULL;
|
||||
|
||||
glState.isFogEnabled = false;
|
||||
tr.skytexturenum = -1;
|
||||
pglDisable( GL_FOG );
|
||||
|
||||
// clearing texture chains
|
||||
for( i = 0; i < WORLDMODEL->numtextures; i++ )
|
||||
{
|
||||
if( !WORLDMODEL->textures[i] )
|
||||
continue;
|
||||
|
||||
tx = WORLDMODEL->textures[i];
|
||||
|
||||
if( !Q_strncmp( tx->name, "sky", 3 ) && tx->width == ( tx->height * 2 ))
|
||||
tr.skytexturenum = i;
|
||||
|
||||
tx->texturechain = NULL;
|
||||
}
|
||||
|
||||
GL_BuildLightmaps ();
|
||||
|
||||
R_ClearVBO();
|
||||
if( R_HasEnabledVBO( ))
|
||||
R_GenerateVBO();
|
||||
R_ResetRipples();
|
||||
|
||||
if( gEngfuncs.drawFuncs->R_NewMap != NULL )
|
||||
gEngfuncs.drawFuncs->R_NewMap();
|
||||
}
|
||||
|
||||
static void R_FillRenderAPI( render_api_t *api )
|
||||
{
|
||||
api->GetExtraParmsForTexture = R_GetExtraParmsForTexture;
|
||||
api->GetFrameTime = R_GetFrameTime;
|
||||
api->R_SetCurrentEntity = R_SetCurrentEntity;
|
||||
api->R_SetCurrentModel = R_SetCurrentModel;
|
||||
api->GL_CreateTexture = GL_CreateTexture;
|
||||
api->GL_LoadTextureArray = GL_LoadTextureArray;
|
||||
api->GL_CreateTextureArray = GL_CreateTextureArray;
|
||||
api->DrawSingleDecal = DrawSingleDecal;
|
||||
api->R_DecalSetupVerts = R_DecalSetupVerts;
|
||||
api->R_EntityRemoveDecals = R_EntityRemoveDecals;
|
||||
api->GL_SelectTexture = GL_SelectTexture;
|
||||
api->GL_LoadTextureMatrix = GL_LoadTexMatrixExt;
|
||||
api->GL_TexMatrixIdentity = GL_LoadIdentityTexMatrix;
|
||||
api->GL_CleanUpTextureUnits = GL_CleanUpTextureUnits;
|
||||
api->GL_TexGen = GL_TexGen;
|
||||
api->GL_TextureTarget = GL_TextureTarget;
|
||||
api->GL_TexCoordArrayMode = GL_SetTexCoordArrayMode;
|
||||
api->GL_UpdateTexSize = GL_UpdateTexSize;
|
||||
api->GL_DrawParticles = CL_DrawParticlesExternal;
|
||||
api->LightVec = R_LightVec;
|
||||
api->StudioGetTexture = R_StudioGetTexture;
|
||||
api->GL_GetProcAddress = R_GetProcAddress;
|
||||
}
|
||||
|
||||
static void R_FillTriAPI( triangleapi_t *api )
|
||||
{
|
||||
api->TexCoord2f = TriTexCoord2f;
|
||||
api->Fog = TriFog;
|
||||
api->ScreenToWorld = R_ScreenToWorld;
|
||||
api->GetMatrix = TriGetMatrix;
|
||||
api->FogParams = TriFogParams;
|
||||
}
|
||||
|
||||
const ref_interface_t gReffuncs =
|
||||
{
|
||||
R_Init,
|
||||
R_Shutdown,
|
||||
@@ -452,9 +517,7 @@ static const ref_interface_t gReffuncs =
|
||||
GL_SetRenderMode,
|
||||
|
||||
R_AddEntity,
|
||||
CL_AddCustomBeam,
|
||||
R_ProcessEntData,
|
||||
R_Flush,
|
||||
|
||||
R_ShowTextures,
|
||||
|
||||
@@ -464,7 +527,6 @@ static const ref_interface_t gReffuncs =
|
||||
R_SetupSky,
|
||||
|
||||
R_Set2DMode,
|
||||
R_DrawStretchRaw,
|
||||
R_DrawStretchPic,
|
||||
CL_FillRGBA,
|
||||
R_WorldToScreen,
|
||||
@@ -481,14 +543,13 @@ static const ref_interface_t gReffuncs =
|
||||
|
||||
R_StudioEstimateFrame,
|
||||
R_StudioLerpMovement,
|
||||
CL_InitStudioAPI,
|
||||
R_StudioFillAPI,
|
||||
R_StudioSetDrawInterface,
|
||||
|
||||
R_SetSkyCloudsTextures,
|
||||
GL_SubdivideSurface,
|
||||
CL_RunLightStyles,
|
||||
|
||||
R_GetSpriteParms,
|
||||
R_GetSpriteTexture,
|
||||
|
||||
Mod_ProcessRenderData,
|
||||
Mod_StudioLoadTextures,
|
||||
@@ -496,47 +557,23 @@ static const ref_interface_t gReffuncs =
|
||||
CL_DrawParticles,
|
||||
CL_DrawTracers,
|
||||
CL_DrawBeams,
|
||||
R_BeamCull,
|
||||
|
||||
GL_RefGetParm,
|
||||
|
||||
R_GetDetailScaleForTexture,
|
||||
R_GetExtraParmsForTexture,
|
||||
R_GetFrameTime,
|
||||
|
||||
R_SetCurrentEntity,
|
||||
R_SetCurrentModel,
|
||||
R_SetDetailScaleForTexture,
|
||||
|
||||
GL_CreateTexture,
|
||||
GL_FindTexture,
|
||||
GL_TextureName,
|
||||
GL_TextureData,
|
||||
GL_LoadTexture,
|
||||
GL_CreateTexture,
|
||||
GL_LoadTextureArray,
|
||||
GL_CreateTextureArray,
|
||||
GL_FreeTexture,
|
||||
R_OverrideTextureSourceSize,
|
||||
|
||||
DrawSingleDecal,
|
||||
R_DecalSetupVerts,
|
||||
R_EntityRemoveDecals,
|
||||
|
||||
R_UploadStretchRaw,
|
||||
GL_UpdateTexture,
|
||||
|
||||
GL_Bind,
|
||||
GL_SelectTexture,
|
||||
GL_LoadTexMatrixExt,
|
||||
GL_LoadIdentityTexMatrix,
|
||||
GL_CleanUpTextureUnits,
|
||||
GL_TexGen,
|
||||
GL_TextureTarget,
|
||||
GL_SetTexCoordArrayMode,
|
||||
GL_UpdateTexSize,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
CL_DrawParticlesExternal,
|
||||
R_LightVec,
|
||||
R_StudioGetTexture,
|
||||
|
||||
R_RenderFrame,
|
||||
Mod_SetOrthoBounds,
|
||||
@@ -544,39 +581,19 @@ static const ref_interface_t gReffuncs =
|
||||
Mod_GetCurrentVis,
|
||||
R_NewMap,
|
||||
R_ClearScene,
|
||||
R_GetProcAddress,
|
||||
|
||||
TriRenderMode,
|
||||
TriBegin,
|
||||
TriEnd,
|
||||
_TriColor4f,
|
||||
_TriColor4ub,
|
||||
TriTexCoord2f,
|
||||
TriVertex3fv,
|
||||
TriVertex3f,
|
||||
TriFog,
|
||||
R_ScreenToWorld,
|
||||
TriGetMatrix,
|
||||
TriFogParams,
|
||||
TriCullFace,
|
||||
|
||||
R_FillRenderAPI,
|
||||
R_FillTriAPI,
|
||||
|
||||
VGUI_SetupDrawing,
|
||||
VGUI_UploadTextureBlock,
|
||||
};
|
||||
|
||||
int EXPORT GetRefAPI( int version, ref_interface_t *funcs, ref_api_t *engfuncs, ref_globals_t *globals );
|
||||
int EXPORT GetRefAPI( int version, ref_interface_t *funcs, ref_api_t *engfuncs, ref_globals_t *globals )
|
||||
{
|
||||
if( version != REF_API_VERSION )
|
||||
return 0;
|
||||
|
||||
// fill in our callbacks
|
||||
*funcs = gReffuncs;
|
||||
gEngfuncs = *engfuncs;
|
||||
gpGlobals = globals;
|
||||
|
||||
gp_cl = (ref_client_t *)ENGINE_GET_PARM( PARM_GET_CLIENT_PTR );
|
||||
gp_host = (ref_host_t *)ENGINE_GET_PARM( PARM_GET_HOST_PTR );
|
||||
|
||||
return REF_API_VERSION;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ qboolean R_CullModel( const cl_entity_t *e, const vec3_t absmin, const vec3_t ab
|
||||
if( ENGINE_GET_PARM( PARM_DEV_OVERVIEW ))
|
||||
return true;
|
||||
|
||||
if( RP_NORMALPASS() && !ENGINE_GET_PARM( PARM_THIRDPERSON ) && CL_IsViewEntityLocalPlayer())
|
||||
if( !FBitSet( RI.rvp.flags, RF_DRAW_CUBEMAP ) && !ENGINE_GET_PARM( PARM_THIRDPERSON ) && CL_IsViewEntityLocalPlayer())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@@ -85,7 +85,7 @@ int R_CullSurface( const msurface_t *surf, const gl_frustum_t *frustum, uint cli
|
||||
float dist;
|
||||
|
||||
// can use normal.z for world (optimisation)
|
||||
if( RI.drawOrtho )
|
||||
if( FBitSet( RI.rvp.flags, RF_DRAW_OVERVIEW ))
|
||||
{
|
||||
vec3_t orthonormal;
|
||||
|
||||
|
||||
155
ref/gl/gl_draw.c
155
ref/gl/gl_draw.c
@@ -29,34 +29,6 @@ void R_GetTextureParms( int *w, int *h, int texnum )
|
||||
if( h ) *h = glt->srcHeight;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
R_GetSpriteParms
|
||||
|
||||
same as GetImageParms but used
|
||||
for sprite models
|
||||
=============
|
||||
*/
|
||||
void R_GetSpriteParms( int *frameWidth, int *frameHeight, int *numFrames, int currentFrame, const model_t *pSprite )
|
||||
{
|
||||
mspriteframe_t *pFrame;
|
||||
|
||||
if( !pSprite || pSprite->type != mod_sprite ) return; // bad model ?
|
||||
pFrame = R_GetSpriteFrame( pSprite, currentFrame, 0.0f );
|
||||
|
||||
if( frameWidth ) *frameWidth = pFrame->width;
|
||||
if( frameHeight ) *frameHeight = pFrame->height;
|
||||
if( numFrames ) *numFrames = pSprite->numframes;
|
||||
}
|
||||
|
||||
int R_GetSpriteTexture( const model_t *m_pSpriteModel, int frame )
|
||||
{
|
||||
if( !m_pSpriteModel || m_pSpriteModel->type != mod_sprite || !m_pSpriteModel->cache.data )
|
||||
return 0;
|
||||
|
||||
return R_GetSpriteFrame( m_pSpriteModel, frame, 0.0f )->gl_texturenum;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
R_DrawStretchPic
|
||||
@@ -83,120 +55,69 @@ void R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, f
|
||||
|
||||
/*
|
||||
=============
|
||||
R_DrawStretchRaw
|
||||
GL_UpdateTexture
|
||||
=============
|
||||
*/
|
||||
void R_DrawStretchRaw( float x, float y, float w, float h, int cols, int rows, const byte *data, qboolean dirty )
|
||||
void GL_UpdateTexture( int texnum, int cols, int rows, int width, int height, const byte *buffer, pixformat_t fmt )
|
||||
{
|
||||
byte *raw = NULL;
|
||||
gl_texture_t *tex;
|
||||
GLenum gl_format;
|
||||
|
||||
switch( fmt )
|
||||
{
|
||||
case PF_RGBA_32:
|
||||
gl_format = GL_RGBA;
|
||||
break;
|
||||
case PF_BGRA_32:
|
||||
gl_format = GL_BGRA;
|
||||
break;
|
||||
case PF_RGB_24:
|
||||
gl_format = GL_RGB;
|
||||
break;
|
||||
case PF_BGR_24:
|
||||
gl_format = GL_BGR;
|
||||
break;
|
||||
case PF_LUMINANCE:
|
||||
gl_format = GL_LUMINANCE;
|
||||
break;
|
||||
default:
|
||||
gEngfuncs.Con_DPrintf( S_ERROR "%s: unsupported pixel format %i\n", __func__, fmt );
|
||||
return;
|
||||
}
|
||||
|
||||
if( !GL_Support( GL_ARB_TEXTURE_NPOT_EXT ))
|
||||
{
|
||||
int width = 1, height = 1;
|
||||
|
||||
// check the dimensions
|
||||
width = NearestPOW( cols, true );
|
||||
height = NearestPOW( rows, false );
|
||||
|
||||
if( cols != width || rows != height )
|
||||
{
|
||||
raw = GL_ResampleTexture( data, cols, rows, width, height, false );
|
||||
cols = width;
|
||||
rows = height;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
raw = (byte *)data;
|
||||
}
|
||||
|
||||
if( cols > glConfig.max_2d_texture_size )
|
||||
gEngfuncs.Host_Error( "%s: size %i exceeds hardware limits\n", __func__, cols );
|
||||
if( rows > glConfig.max_2d_texture_size )
|
||||
gEngfuncs.Host_Error( "%s: size %i exceeds hardware limits\n", __func__, rows );
|
||||
|
||||
pglDisable( GL_BLEND );
|
||||
pglDisable( GL_ALPHA_TEST );
|
||||
pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
|
||||
|
||||
tex = R_GetTexture( tr.cinTexture );
|
||||
GL_Bind( XASH_TEXTURE0, tr.cinTexture );
|
||||
|
||||
if( cols == tex->width && rows == tex->height )
|
||||
{
|
||||
if( dirty )
|
||||
{
|
||||
pglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_BGRA, GL_UNSIGNED_BYTE, raw );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tex->size = cols * rows * 4;
|
||||
tex->width = cols;
|
||||
tex->height = rows;
|
||||
if( dirty )
|
||||
{
|
||||
pglTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, cols, rows, 0, GL_BGRA, GL_UNSIGNED_BYTE, raw );
|
||||
}
|
||||
}
|
||||
|
||||
pglBegin( GL_QUADS );
|
||||
pglTexCoord2f( 0, 0 );
|
||||
pglVertex2f( x, y );
|
||||
pglTexCoord2f( 1, 0 );
|
||||
pglVertex2f( x + w, y );
|
||||
pglTexCoord2f( 1, 1 );
|
||||
pglVertex2f( x + w, y + h );
|
||||
pglTexCoord2f( 0, 1 );
|
||||
pglVertex2f( x, y + h );
|
||||
pglEnd();
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
R_UploadStretchRaw
|
||||
=============
|
||||
*/
|
||||
void R_UploadStretchRaw( int texture, int cols, int rows, int width, int height, const byte *data )
|
||||
{
|
||||
byte *raw = NULL;
|
||||
gl_texture_t *tex;
|
||||
|
||||
if( !GL_Support( GL_ARB_TEXTURE_NPOT_EXT ))
|
||||
{
|
||||
// check the dimensions
|
||||
width = NearestPOW( width, true );
|
||||
height = NearestPOW( height, false );
|
||||
}
|
||||
else
|
||||
{
|
||||
width = bound( 128, width, glConfig.max_2d_texture_size );
|
||||
height = bound( 128, height, glConfig.max_2d_texture_size );
|
||||
}
|
||||
|
||||
if( cols != width || rows != height )
|
||||
{
|
||||
raw = GL_ResampleTexture( data, cols, rows, width, height, false );
|
||||
raw = GL_ResampleTexture( buffer, cols, rows, width, height, false );
|
||||
cols = width;
|
||||
rows = height;
|
||||
}
|
||||
else
|
||||
{
|
||||
raw = (byte *)data;
|
||||
}
|
||||
raw = (byte *)buffer;
|
||||
|
||||
if( cols > glConfig.max_2d_texture_size )
|
||||
gEngfuncs.Host_Error( "%s: size %i exceeds hardware limits\n", __func__, cols );
|
||||
if( rows > glConfig.max_2d_texture_size )
|
||||
gEngfuncs.Host_Error( "%s: size %i exceeds hardware limits\n", __func__, rows );
|
||||
|
||||
tex = R_GetTexture( texture );
|
||||
GL_Bind( GL_KEEP_UNIT, texture );
|
||||
tex->width = cols;
|
||||
tex->height = rows;
|
||||
tex = R_GetTexture( texnum );
|
||||
GL_Bind( GL_KEEP_UNIT, texnum );
|
||||
|
||||
if( cols == tex->width && rows == tex->height )
|
||||
pglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, gl_format, GL_UNSIGNED_BYTE, raw );
|
||||
else
|
||||
{
|
||||
tex->width = cols;
|
||||
tex->height = rows;
|
||||
pglTexImage2D( GL_TEXTURE_2D, 0, tex->format, cols, rows, 0, gl_format, GL_UNSIGNED_BYTE, raw );
|
||||
}
|
||||
|
||||
pglTexImage2D( GL_TEXTURE_2D, 0, tex->format, cols, rows, 0, GL_BGRA, GL_UNSIGNED_BYTE, raw );
|
||||
GL_ApplyTextureParams( tex );
|
||||
}
|
||||
|
||||
|
||||
@@ -23,19 +23,6 @@ static gl_texture_t gl_textures[MAX_TEXTURES];
|
||||
static gl_texture_t* gl_texturesHashTable[TEXTURES_HASH_SIZE];
|
||||
static uint gl_numTextures;
|
||||
|
||||
static byte dottexture[8][8] =
|
||||
{
|
||||
{0,1,1,0,0,0,0,0},
|
||||
{1,1,1,1,0,0,0,0},
|
||||
{1,1,1,1,0,0,0,0},
|
||||
{0,1,1,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0},
|
||||
};
|
||||
|
||||
|
||||
#define IsLightMap( tex ) ( FBitSet(( tex )->flags, TF_ATLAS_PAGE ))
|
||||
/*
|
||||
=================
|
||||
@@ -691,97 +678,6 @@ static void GL_SetTextureFormat( gl_texture_t *tex, pixformat_t format, int chan
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
GL_ResampleTexture
|
||||
|
||||
Assume input buffer is RGBA
|
||||
=================
|
||||
*/
|
||||
byte *GL_ResampleTexture( const byte *source, int inWidth, int inHeight, int outWidth, int outHeight, qboolean isNormalMap )
|
||||
{
|
||||
uint frac, fracStep;
|
||||
uint *in = (uint *)source;
|
||||
uint p1[0x1000], p2[0x1000];
|
||||
byte *pix1, *pix2, *pix3, *pix4;
|
||||
uint *out, *inRow1, *inRow2;
|
||||
static byte *scaledImage = NULL; // pointer to a scaled image
|
||||
vec3_t normal;
|
||||
int i, x, y;
|
||||
|
||||
if( !source ) return NULL;
|
||||
|
||||
scaledImage = Mem_Realloc( r_temppool, scaledImage, outWidth * outHeight * 4 );
|
||||
fracStep = inWidth * 0x10000 / outWidth;
|
||||
out = (uint *)scaledImage;
|
||||
|
||||
frac = fracStep >> 2;
|
||||
for( i = 0; i < outWidth; i++ )
|
||||
{
|
||||
p1[i] = 4 * (frac >> 16);
|
||||
frac += fracStep;
|
||||
}
|
||||
|
||||
frac = (fracStep >> 2) * 3;
|
||||
for( i = 0; i < outWidth; i++ )
|
||||
{
|
||||
p2[i] = 4 * (frac >> 16);
|
||||
frac += fracStep;
|
||||
}
|
||||
|
||||
if( isNormalMap )
|
||||
{
|
||||
for( y = 0; y < outHeight; y++, out += outWidth )
|
||||
{
|
||||
inRow1 = in + inWidth * (int)(((float)y + 0.25f) * inHeight / outHeight);
|
||||
inRow2 = in + inWidth * (int)(((float)y + 0.75f) * inHeight / outHeight);
|
||||
|
||||
for( x = 0; x < outWidth; x++ )
|
||||
{
|
||||
pix1 = (byte *)inRow1 + p1[x];
|
||||
pix2 = (byte *)inRow1 + p2[x];
|
||||
pix3 = (byte *)inRow2 + p1[x];
|
||||
pix4 = (byte *)inRow2 + p2[x];
|
||||
|
||||
normal[0] = MAKE_SIGNED( pix1[0] ) + MAKE_SIGNED( pix2[0] ) + MAKE_SIGNED( pix3[0] ) + MAKE_SIGNED( pix4[0] );
|
||||
normal[1] = MAKE_SIGNED( pix1[1] ) + MAKE_SIGNED( pix2[1] ) + MAKE_SIGNED( pix3[1] ) + MAKE_SIGNED( pix4[1] );
|
||||
normal[2] = MAKE_SIGNED( pix1[2] ) + MAKE_SIGNED( pix2[2] ) + MAKE_SIGNED( pix3[2] ) + MAKE_SIGNED( pix4[2] );
|
||||
|
||||
if( !VectorNormalizeLength( normal ))
|
||||
VectorSet( normal, 0.5f, 0.5f, 1.0f );
|
||||
|
||||
((byte *)(out+x))[0] = 128 + (byte)(127.0f * normal[0]);
|
||||
((byte *)(out+x))[1] = 128 + (byte)(127.0f * normal[1]);
|
||||
((byte *)(out+x))[2] = 128 + (byte)(127.0f * normal[2]);
|
||||
((byte *)(out+x))[3] = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( y = 0; y < outHeight; y++, out += outWidth )
|
||||
{
|
||||
inRow1 = in + inWidth * (int)(((float)y + 0.25f) * inHeight / outHeight);
|
||||
inRow2 = in + inWidth * (int)(((float)y + 0.75f) * inHeight / outHeight);
|
||||
|
||||
for( x = 0; x < outWidth; x++ )
|
||||
{
|
||||
pix1 = (byte *)inRow1 + p1[x];
|
||||
pix2 = (byte *)inRow1 + p2[x];
|
||||
pix3 = (byte *)inRow2 + p1[x];
|
||||
pix4 = (byte *)inRow2 + p2[x];
|
||||
|
||||
((byte *)(out+x))[0] = (pix1[0] + pix2[0] + pix3[0] + pix4[0]) >> 2;
|
||||
((byte *)(out+x))[1] = (pix1[1] + pix2[1] + pix3[1] + pix4[1]) >> 2;
|
||||
((byte *)(out+x))[2] = (pix1[2] + pix2[2] + pix3[2] + pix4[2]) >> 2;
|
||||
((byte *)(out+x))[3] = (pix1[3] + pix2[3] + pix3[3] + pix4[3]) >> 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return scaledImage;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
GL_BoxFilter3x3
|
||||
@@ -1790,7 +1686,20 @@ int GL_CreateTexture( const char *name, int width, int height, const void *buffe
|
||||
r_empty.size *= 6;
|
||||
}
|
||||
|
||||
return GL_LoadTextureFromBuffer( name, &r_empty, flags, update );
|
||||
int texnum = GL_LoadTextureFromBuffer( name, &r_empty, flags, update );
|
||||
|
||||
if( !Q_strcmp( name, REF_DEFAULT_TEXTURE ))
|
||||
tr.defaultTexture = texnum;
|
||||
else if( !Q_strcmp( name, REF_PARTICLE_TEXTURE ))
|
||||
tr.particleTexture = texnum;
|
||||
else if( !Q_strcmp( name, REF_WHITE_TEXTURE ))
|
||||
tr.whiteTexture = texnum;
|
||||
else if( !Q_strcmp( name, REF_GRAY_TEXTURE ))
|
||||
tr.grayTexture = texnum;
|
||||
else if( !Q_strcmp( name, REF_BLACK_TEXTURE ))
|
||||
tr.blackTexture = texnum;
|
||||
|
||||
return texnum;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1951,35 +1860,6 @@ INTERNAL TEXTURES
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
/*
|
||||
==================
|
||||
GL_FakeImage
|
||||
==================
|
||||
*/
|
||||
static rgbdata_t *GL_FakeImage( int width, int height, int depth, int flags )
|
||||
{
|
||||
static byte data2D[1024]; // 16x16x4
|
||||
static rgbdata_t r_image;
|
||||
|
||||
// also use this for bad textures, but without alpha
|
||||
r_image.width = Q_max( 1, width );
|
||||
r_image.height = Q_max( 1, height );
|
||||
r_image.depth = Q_max( 1, depth );
|
||||
r_image.flags = flags;
|
||||
r_image.type = PF_RGBA_32;
|
||||
r_image.size = r_image.width * r_image.height * r_image.depth * 4;
|
||||
r_image.buffer = (r_image.size > sizeof( data2D )) ? NULL : data2D;
|
||||
r_image.palette = NULL;
|
||||
r_image.numMips = 1;
|
||||
r_image.encode = 0;
|
||||
|
||||
if( FBitSet( r_image.flags, IMAGE_CUBEMAP ))
|
||||
r_image.size *= 6;
|
||||
memset( data2D, 0xFF, sizeof( data2D ));
|
||||
|
||||
return &r_image;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
R_InitDlightTexture
|
||||
@@ -2003,70 +1883,6 @@ void R_InitDlightTexture( void )
|
||||
tr.dlightTexture = GL_LoadTextureFromBuffer( "*dlight", &r_image, TF_NOMIPMAP|TF_CLAMP|TF_ATLAS_PAGE, update );
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
GL_CreateInternalTextures
|
||||
==================
|
||||
*/
|
||||
static void GL_CreateInternalTextures( void )
|
||||
{
|
||||
int dx2, dy, d;
|
||||
int x, y;
|
||||
rgbdata_t *pic;
|
||||
|
||||
// emo-texture from quake1
|
||||
pic = GL_FakeImage( 16, 16, 1, IMAGE_HAS_COLOR );
|
||||
|
||||
for( y = 0; y < 16; y++ )
|
||||
{
|
||||
for( x = 0; x < 16; x++ )
|
||||
{
|
||||
if(( y < 8 ) ^ ( x < 8 ))
|
||||
((uint *)pic->buffer)[y*16+x] = 0xFFFF00FF;
|
||||
else ((uint *)pic->buffer)[y*16+x] = 0xFF000000;
|
||||
}
|
||||
}
|
||||
|
||||
tr.defaultTexture = GL_LoadTextureInternal( REF_DEFAULT_TEXTURE, pic, TF_COLORMAP );
|
||||
|
||||
// particle texture from quake1
|
||||
pic = GL_FakeImage( 8, 8, 1, IMAGE_HAS_COLOR|IMAGE_HAS_ALPHA );
|
||||
|
||||
for( x = 0; x < 8; x++ )
|
||||
{
|
||||
for( y = 0; y < 8; y++ )
|
||||
{
|
||||
if( dottexture[x][y] )
|
||||
pic->buffer[( y * 8 + x ) * 4 + 3] = 255;
|
||||
else pic->buffer[( y * 8 + x ) * 4 + 3] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
tr.particleTexture = GL_LoadTextureInternal( REF_PARTICLE_TEXTURE, pic, TF_CLAMP );
|
||||
|
||||
// white texture
|
||||
pic = GL_FakeImage( 4, 4, 1, IMAGE_HAS_COLOR );
|
||||
for( x = 0; x < 16; x++ )
|
||||
((uint *)pic->buffer)[x] = 0xFFFFFFFF;
|
||||
tr.whiteTexture = GL_LoadTextureInternal( REF_WHITE_TEXTURE, pic, TF_COLORMAP );
|
||||
|
||||
// gray texture
|
||||
pic = GL_FakeImage( 4, 4, 1, IMAGE_HAS_COLOR );
|
||||
for( x = 0; x < 16; x++ )
|
||||
((uint *)pic->buffer)[x] = 0xFF7F7F7F;
|
||||
tr.grayTexture = GL_LoadTextureInternal( REF_GRAY_TEXTURE, pic, TF_COLORMAP );
|
||||
|
||||
// black texture
|
||||
pic = GL_FakeImage( 4, 4, 1, IMAGE_HAS_COLOR );
|
||||
for( x = 0; x < 16; x++ )
|
||||
((uint *)pic->buffer)[x] = 0xFF000000;
|
||||
tr.blackTexture = GL_LoadTextureInternal( REF_BLACK_TEXTURE, pic, TF_COLORMAP );
|
||||
|
||||
// cinematic dummy
|
||||
pic = GL_FakeImage( 640, 100, 1, IMAGE_HAS_COLOR );
|
||||
tr.cinTexture = GL_LoadTextureInternal( "*cintexture", pic, TF_NOMIPMAP|TF_CLAMP );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
R_TextureList_f
|
||||
@@ -2299,7 +2115,6 @@ void R_InitImages( void )
|
||||
|
||||
// validate cvars
|
||||
R_SetTextureParameters();
|
||||
GL_CreateInternalTextures();
|
||||
|
||||
gEngfuncs.Cmd_AddCommand( "texturelist", R_TextureList_f, "display loaded textures list" );
|
||||
}
|
||||
|
||||
@@ -15,17 +15,12 @@ GNU General Public License for more details.
|
||||
|
||||
#ifndef GL_LOCAL_H
|
||||
#define GL_LOCAL_H
|
||||
#include "ref_common.h"
|
||||
#include "port.h"
|
||||
#include "xash3d_types.h"
|
||||
#include "cvardef.h"
|
||||
#include "const.h"
|
||||
#include "com_model.h"
|
||||
#include "cl_entity.h"
|
||||
#include "render_api.h"
|
||||
#include "protocol.h"
|
||||
#include "gl_frustum.h"
|
||||
#include "ref_api.h"
|
||||
#include "xash3d_mathlib.h"
|
||||
#include "ref_params.h"
|
||||
#include "enginefeatures.h"
|
||||
#include "com_strings.h"
|
||||
@@ -52,7 +47,6 @@ void VGL_ShimEndFrame( void );
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define Assert(x) if(!( x )) gEngfuncs.Host_Error( "assert failed at %s:%i\n", __FILE__, __LINE__ )
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
@@ -60,7 +54,6 @@ void VGL_ShimEndFrame( void );
|
||||
#define LM_SAMPLE_SIZE 16
|
||||
|
||||
|
||||
extern poolhandle_t r_temppool;
|
||||
|
||||
#define BLOCK_SIZE tr.block_size // lightmap blocksize
|
||||
#define BLOCK_SIZE_DEFAULT 128 // for keep backward compatibility
|
||||
@@ -77,17 +70,9 @@ extern poolhandle_t r_temppool;
|
||||
#define SHADE_LAMBERT 1.4953241
|
||||
#define DEFAULT_ALPHATEST 0.0f
|
||||
|
||||
// refparams
|
||||
#define RP_NONE 0
|
||||
#define RP_ENVVIEW BIT( 0 ) // used for cubemapshot
|
||||
#define RP_OLDVIEWLEAF BIT( 1 )
|
||||
#define RP_CLIPPLANE BIT( 2 )
|
||||
|
||||
#define RP_NONVIEWERREF (RP_ENVVIEW)
|
||||
#define R_ModelOpaque( rm ) ( rm == kRenderNormal )
|
||||
#define R_StaticEntity( ent ) ( VectorIsNull( ent->origin ) && VectorIsNull( ent->angles ))
|
||||
#define RP_LOCALCLIENT( e ) ((e) != NULL && (e)->index == ( gp_cl->playernum + 1 ) && e->player )
|
||||
#define RP_NORMALPASS() ( FBitSet( RI.params, RP_NONVIEWERREF ) == 0 )
|
||||
|
||||
#define CL_IsViewEntityLocalPlayer() ( gp_cl->viewentity == ( gp_cl->playernum + 1 ))
|
||||
|
||||
@@ -134,27 +119,16 @@ typedef struct gltexture_s
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int params; // rendering parameters
|
||||
|
||||
qboolean drawWorld; // ignore world for drawing PlayerModel
|
||||
qboolean isSkyVisible; // sky is visible
|
||||
qboolean onlyClientDraw; // disabled by client request
|
||||
qboolean drawOrtho; // draw world as orthogonal projection
|
||||
|
||||
float fov_x, fov_y; // current view fov
|
||||
ref_viewpass_t rvp;
|
||||
|
||||
cl_entity_t *currententity;
|
||||
model_t *currentmodel;
|
||||
cl_entity_t *currentbeam; // same as above but for beams
|
||||
|
||||
int viewport[4];
|
||||
gl_frustum_t frustum;
|
||||
|
||||
mleaf_t *viewleaf;
|
||||
mleaf_t *oldviewleaf;
|
||||
vec3_t pvsorigin;
|
||||
vec3_t vieworg; // locked vieworigin
|
||||
vec3_t viewangles;
|
||||
vec3_t vforward;
|
||||
vec3_t vright;
|
||||
vec3_t vup;
|
||||
@@ -213,8 +187,6 @@ typedef struct
|
||||
int lightmapTextures[MAX_LIGHTMAPS];
|
||||
int dlightTexture; // custom dlight texture
|
||||
int skyboxTextures[SKYBOX_MAX_SIDES]; // skybox sides
|
||||
int cinTexture; // cinematic texture
|
||||
|
||||
int skytexturenum; // this not a gl_texturenum!
|
||||
int skyboxbasenum; // start with 5800
|
||||
|
||||
@@ -239,7 +211,6 @@ typedef struct
|
||||
qboolean fFlipViewModel;
|
||||
|
||||
byte visbytes[(MAX_MAP_LEAFS+7)/8]; // member custom PVS
|
||||
int lightstylevalue[MAX_LIGHTSTYLES]; // value 0 - 65536
|
||||
int block_size; // lightmap blocksize
|
||||
|
||||
double frametime; // special frametime for multipass rendering (will set to 0 on a nextview)
|
||||
@@ -252,10 +223,8 @@ typedef struct
|
||||
model_t *worldmodel;
|
||||
world_static_t *world;
|
||||
cl_entity_t *entities;
|
||||
movevars_t *movevars;
|
||||
color24 *palette;
|
||||
cl_entity_t *viewent;
|
||||
dlight_t *dlights;
|
||||
dlight_t *elights;
|
||||
byte *texgammatable;
|
||||
uint *lightgammatable;
|
||||
@@ -324,7 +293,6 @@ void SCR_TimeRefresh_f( void );
|
||||
// gl_beams.c
|
||||
//
|
||||
void CL_DrawBeams( int fTrans, BEAM *active_beams );
|
||||
qboolean R_BeamCull( const vec3_t start, const vec3_t end, qboolean pvsOnly );
|
||||
|
||||
//
|
||||
// gl_cull.c
|
||||
@@ -347,7 +315,7 @@ void R_ClearDecals( void );
|
||||
// gl_draw.c
|
||||
//
|
||||
void R_Set2DMode( qboolean enable );
|
||||
void R_UploadStretchRaw( int texture, int cols, int rows, int width, int height, const byte *data );
|
||||
void GL_UpdateTexture( int texnum, int cols, int rows, int width, int height, const byte *buffer, pixformat_t fmt );
|
||||
|
||||
//
|
||||
// gl_image.c
|
||||
@@ -359,7 +327,6 @@ gl_texture_t *R_GetTexture( unsigned int texnum );
|
||||
int GL_LoadTexture( const char *name, const byte *buf, size_t size, int flags );
|
||||
int GL_LoadTextureArray( const char **names, int flags );
|
||||
int GL_LoadTextureFromBuffer( const char *name, rgbdata_t *pic, texFlags_t flags, qboolean update );
|
||||
byte *GL_ResampleTexture( const byte *source, int in_w, int in_h, int out_w, int out_h, qboolean isNormalMap );
|
||||
int GL_CreateTexture( const char *name, int width, int height, const void *buffer, texFlags_t flags );
|
||||
int GL_CreateTextureArray( const char *name, int width, int height, int depth, const void *buffer, texFlags_t flags );
|
||||
void GL_ProcessTexture( int texnum, float gamma, int topColor, int bottomColor );
|
||||
@@ -377,16 +344,6 @@ qboolean R_SearchForTextureReplacement( char *out, size_t size, const char *mode
|
||||
void R_TextureReplacementReport( const char *modelname, int gl_texturenum, const char *foundpath );
|
||||
void R_ShowTextures( void );
|
||||
|
||||
//
|
||||
// gl_rlight.c
|
||||
//
|
||||
void CL_RunLightStyles( lightstyle_t *ls );
|
||||
void R_PushDlights( void );
|
||||
void R_GetLightSpot( vec3_t lightspot );
|
||||
void R_MarkLights( const dlight_t *light, int bit, const mnode_t *node );
|
||||
colorVec R_LightVec( const vec3_t start, const vec3_t end, vec3_t lightspot, vec3_t lightvec );
|
||||
colorVec R_LightPoint( const vec3_t p0 );
|
||||
|
||||
//
|
||||
// gl_rmain.c
|
||||
//
|
||||
@@ -408,21 +365,6 @@ void R_DrawFog( void );
|
||||
int CL_FxBlend( cl_entity_t *e );
|
||||
|
||||
//
|
||||
// gl_rmath.c
|
||||
//
|
||||
void Matrix4x4_ToArrayFloatGL( const matrix4x4 in, float out[16] );
|
||||
void Matrix4x4_Concat( matrix4x4 out, const matrix4x4 in1, const matrix4x4 in2 );
|
||||
void Matrix4x4_ConcatTranslate( matrix4x4 out, float x, float y, float z );
|
||||
void Matrix4x4_ConcatRotate( matrix4x4 out, float angle, float x, float y, float z );
|
||||
void Matrix4x4_CreateProjection(matrix4x4 out, float xMax, float xMin, float yMax, float yMin, float zNear, float zFar);
|
||||
void Matrix4x4_CreateOrtho(matrix4x4 m, float xLeft, float xRight, float yBottom, float yTop, float zNear, float zFar);
|
||||
void Matrix4x4_CreateModelview( matrix4x4 out );
|
||||
|
||||
//
|
||||
// gl_rmisc.c
|
||||
//
|
||||
void R_NewMap( void );
|
||||
|
||||
//
|
||||
// gl_rsurf.c
|
||||
//
|
||||
@@ -434,7 +376,6 @@ void GL_SubdivideSurface( model_t *mod, msurface_t *fa );
|
||||
void GL_SetupFogColorForSurfaces( void );
|
||||
void R_DrawAlphaTextureChains( void );
|
||||
void GL_RebuildLightmaps( void );
|
||||
void GL_InitRandomTable( void );
|
||||
void GL_BuildLightmaps( void );
|
||||
void GL_ResetFogColor( void );
|
||||
void R_GenerateVBO( void );
|
||||
@@ -456,25 +397,23 @@ void CL_DrawTracers( double frametime, particle_t *cl_active_tracers );
|
||||
//
|
||||
// gl_sprite.c
|
||||
//
|
||||
void R_SpriteInit( void );
|
||||
void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, uint texFlags );
|
||||
mspriteframe_t *R_GetSpriteFrame( const model_t *pModel, int frame, float yaw );
|
||||
void R_DrawSpriteModel( cl_entity_t *e );
|
||||
|
||||
//
|
||||
// gl_studio.c
|
||||
//
|
||||
void R_StudioInit( void );
|
||||
studiohdr_t *R_StudioGetHeader( void );
|
||||
void R_StudioLerpMovement( cl_entity_t *e, double time, vec3_t origin, vec3_t angles );
|
||||
struct mstudiotex_s *R_StudioGetTexture( cl_entity_t *e );
|
||||
int R_GetEntityRenderMode( cl_entity_t *ent );
|
||||
void R_DrawStudioModel( cl_entity_t *e );
|
||||
player_info_t *pfnPlayerInfo( int index );
|
||||
void R_GatherPlayerLight( void );
|
||||
float R_StudioEstimateFrame( cl_entity_t *e, mstudioseqdesc_t *pseqdesc, double time );
|
||||
void R_StudioLerpMovement( cl_entity_t *e, double time, vec3_t origin, vec3_t angles );
|
||||
void R_StudioResetPlayerModels( void );
|
||||
void CL_InitStudioAPI( void );
|
||||
qboolean R_StudioFillAPI( struct engine_studio_api_s *api, struct r_studio_interface_s *pDefaultDraw );
|
||||
void R_StudioSetDrawInterface( struct r_studio_interface_s *pDraw );
|
||||
void Mod_StudioLoadTextures( model_t *mod, void *data );
|
||||
void Mod_StudioUnloadTextures( void *data );
|
||||
|
||||
@@ -517,28 +456,23 @@ void R_RenderFrame( const struct ref_viewpass_s *vp );
|
||||
void R_EndFrame( void );
|
||||
void R_ClearScene( void );
|
||||
void R_GetTextureParms( int *w, int *h, int texnum );
|
||||
void R_GetSpriteParms( int *frameWidth, int *frameHeight, int *numFrames, int curFrame, const struct model_s *pSprite );
|
||||
void R_DrawStretchRaw( float x, float y, float w, float h, int cols, int rows, const byte *data, qboolean dirty );
|
||||
void R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, int texnum );
|
||||
qboolean R_SpeedsMessage( char *out, size_t size );
|
||||
qboolean R_CullBox( const vec3_t mins, const vec3_t maxs );
|
||||
int R_WorldToScreen( const vec3_t point, vec3_t screen );
|
||||
void R_ScreenToWorld( const vec3_t screen, vec3_t point );
|
||||
qboolean R_AddEntity( struct cl_entity_s *pRefEntity, int entityType );
|
||||
void Mod_SpriteUnloadTextures( void *data );
|
||||
void Mod_UnloadAliasModel( struct model_s *mod );
|
||||
void Mod_AliasUnloadTextures( void *data );
|
||||
void GL_SetRenderMode( int mode );
|
||||
void R_RunViewmodelEvents( void );
|
||||
void R_DrawViewModel( void );
|
||||
int R_GetSpriteTexture( const struct model_s *m_pSpriteModel, int frame );
|
||||
void R_DecalShoot( int textureIndex, int entityIndex, int modelIndex, vec3_t pos, int flags, float scale );
|
||||
void R_DecalRemoveAll( int texture );
|
||||
int R_CreateDecalList( decallist_t *pList );
|
||||
void R_ClearAllDecals( void );
|
||||
byte *Mod_GetCurrentVis( void );
|
||||
void Mod_SetOrthoBounds( const float *mins, const float *maxs );
|
||||
void CL_AddCustomBeam( cl_entity_t *pEnvBeam );
|
||||
|
||||
//
|
||||
// gl_opengl.c
|
||||
@@ -698,13 +632,6 @@ extern glconfig_t glConfig;
|
||||
extern glstate_t glState;
|
||||
// move to engine
|
||||
extern glwstate_t glw_state;
|
||||
extern ref_api_t gEngfuncs;
|
||||
extern ref_globals_t *gpGlobals;
|
||||
extern ref_client_t *gp_cl;
|
||||
extern ref_host_t *gp_host;
|
||||
|
||||
#define ENGINE_GET_PARM_ (*gEngfuncs.EngineGetParm)
|
||||
#define ENGINE_GET_PARM( parm ) ENGINE_GET_PARM_( ( parm ), 0 )
|
||||
|
||||
//
|
||||
// helper funcs
|
||||
@@ -794,7 +721,6 @@ extern convar_t gl_stencilbits;
|
||||
extern convar_t gl_overbright;
|
||||
extern convar_t gl_fog;
|
||||
|
||||
extern convar_t r_lighting_extended;
|
||||
extern convar_t r_lighting_ambient;
|
||||
extern convar_t r_studio_lambert;
|
||||
extern convar_t r_detailtextures;
|
||||
@@ -814,28 +740,16 @@ extern convar_t r_ripple;
|
||||
extern convar_t r_ripple_updatetime;
|
||||
extern convar_t r_ripple_spawntime;
|
||||
extern convar_t r_large_lightmaps;
|
||||
extern convar_t r_dlight_virtual_radius;
|
||||
|
||||
//
|
||||
// engine shared convars
|
||||
//
|
||||
DECLARE_ENGINE_SHARED_CVAR_LIST()
|
||||
|
||||
//
|
||||
// engine callbacks
|
||||
//
|
||||
#include "crtlib.h"
|
||||
|
||||
void _Mem_Free( void *data, const char *filename, int fileline );
|
||||
void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char *filename, int fileline )
|
||||
ALLOC_CHECK( 2 ) MALLOC_LIKE( _Mem_Free, 1 ) WARN_UNUSED_RESULT;
|
||||
|
||||
#define Mem_Malloc( pool, size ) _Mem_Alloc( pool, size, false, __FILE__, __LINE__ )
|
||||
#define Mem_Calloc( pool, size ) _Mem_Alloc( pool, size, true, __FILE__, __LINE__ )
|
||||
#define Mem_Realloc( pool, ptr, size ) gEngfuncs._Mem_Realloc( pool, ptr, size, true, __FILE__, __LINE__ )
|
||||
#define Mem_Free( mem ) _Mem_Free( mem, __FILE__, __LINE__ )
|
||||
#define Mem_AllocPool( name ) gEngfuncs._Mem_AllocPool( name, __FILE__, __LINE__ )
|
||||
#define Mem_FreePool( pool ) gEngfuncs._Mem_FreePool( pool, __FILE__, __LINE__ )
|
||||
#define Mem_EmptyPool( pool ) gEngfuncs._Mem_EmptyPool( pool, __FILE__, __LINE__ )
|
||||
|
||||
#endif // GL_LOCAL_H
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user