23 Jul 2011

This commit is contained in:
g-cont 2011-07-23 00:00:00 +04:00 committed by Alibek Omarov
parent dc5dc9f653
commit faabf8b33d
42 changed files with 989 additions and 5371 deletions

View File

@ -31,6 +31,7 @@ pm_shared\
mainui\
mainui\legacy
utils\
utils\makefont\
utils\vgui\
utils\vgui\include\
utils\vgui\lib\win32_vc6\

View File

@ -1,4 +1,4 @@
build ????
build 1613
Client: fix drawing beams for 'solid' mode
Image: fix BMP loader for 4-bit color bmp's
@ -9,6 +9,10 @@ Render: fix sprite interpolation
Render: fix angled sprites offset
Render: implement detail textures like in Steam Half-Life (thx n00b)
Client: rework env_funnel effect
Engine: get full support for input, processing and drawing russian letters
Console: add console commands 'messagemode' and 'messagemode2'
Console: fix bug with autocomplete (enable sort for found cmds)
Client: added HUD_ChatInputPosition for CS 1.6
build 1598

View File

@ -6,13 +6,13 @@
--------------------Configuration: hl - Win32 Release--------------------
</h3>
<h3>Command Lines</h3>
Creating temporary file "C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP32FA.tmp" with contents
Creating temporary file "C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP1B70.tmp" with contents
[
/nologo /G5 /MT /W3 /O2 /I "..\dlls" /I "..\engine" /I "..\common" /I "..\pm_shared" /I "..\game_shared" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "QUIVER" /D "VOXEL" /D "QUAKE2" /D "VALVE_DLL" /D "CLIENT_WEAPONS" /Fr"..\temp\dlls\!release/" /Fp"..\temp\dlls\!release/hl.pch" /YX /Fo"..\temp\dlls\!release/" /Fd"..\temp\dlls\!release/" /FD /c
"D:\Xash3D\src_main\dlls\client.cpp"
]
Creating command line "cl.exe @"C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP32FA.tmp""
Creating temporary file "C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP32FB.tmp" with contents
Creating command line "cl.exe @"C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP1B70.tmp""
Creating temporary file "C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP1B71.tmp" with contents
[
kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"..\temp\dlls\!release/hl.pdb" /debug /machine:I386 /def:".\hl.def" /out:"..\temp\dlls\!release/hl.dll" /implib:"..\temp\dlls\!release/hl.lib"
"\Xash3D\src_main\temp\dlls\!release\aflock.obj"
@ -117,13 +117,13 @@ kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32
"\Xash3D\src_main\temp\dlls\!release\xen.obj"
"\Xash3D\src_main\temp\dlls\!release\zombie.obj"
]
Creating command line "link.exe @"C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP32FB.tmp""
Creating temporary file "C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP32FC.bat" with contents
Creating command line "link.exe @"C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP1B71.tmp""
Creating temporary file "C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP1B72.bat" with contents
[
@echo off
copy \Xash3D\src_main\temp\dlls\!release\hl.dll "D:\Xash3D\valve\dlls\hl.dll"
]
Creating command line ""C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP32FC.bat""
Creating command line ""C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP1B72.bat""
Compiling...
client.cpp
Linking...

View File

@ -146,10 +146,7 @@ void CL_UpdateEntityFields( cl_entity_t *ent )
qboolean CL_AddVisibleEntity( cl_entity_t *ent, int entityType )
{
model_t *mod;
mod = Mod_Handle( ent->curstate.modelindex );
if( !mod ) return false;
if( !ent->model ) return false;
// if entity is beam add it here
// because render doesn't know how to draw beams
@ -179,7 +176,7 @@ qboolean CL_AddVisibleEntity( cl_entity_t *ent, int entityType )
else
{
// check for adding this entity
if( !clgame.dllFuncs.pfnAddEntity( entityType, ent, mod->name ))
if( !clgame.dllFuncs.pfnAddEntity( entityType, ent, ent->model->name ))
return false;
if( !R_AddEntity( ent, entityType ))

View File

@ -78,11 +78,12 @@ static dllfunc_t cdll_exports[] =
{ NULL, NULL }
};
static dllfunc_t cdll_new_exports[] = // allowed only in SDK 2.3
static dllfunc_t cdll_new_exports[] = // allowed only in SDK 2.3 and higher
{
{ "HUD_GetStudioModelInterface", (void **)&clgame.dllFuncs.pfnGetStudioModelInterface },
{ "HUD_DirectorMessage", (void **)&clgame.dllFuncs.pfnDirectorMessage },
{ "HUD_VoiceStatus", (void **)&clgame.dllFuncs.pfnVoiceStatus },
{ "HUD_ChatInputPosition", (void **)&clgame.dllFuncs.pfnChatInputPosition },
{ NULL, NULL }
};
@ -1348,6 +1349,13 @@ void CL_InitEdicts( void )
cls.num_client_entities = CL_UPDATE_BACKUP * 64;
cls.packet_entities = Z_Realloc( cls.packet_entities, sizeof( entity_state_t ) * cls.num_client_entities );
clgame.entities = Mem_Alloc( clgame.mempool, sizeof( cl_entity_t ) * clgame.maxEntities );
if(( clgame.maxRemapInfos - 1 ) != clgame.maxEntities )
{
CL_ClearAllRemaps (); // purge old remap info
clgame.maxRemapInfos = clgame.maxEntities + 1;
clgame.remap_info = (remap_info_t **)Mem_Alloc( clgame.mempool, sizeof( remap_info_t* ) * clgame.maxRemapInfos );
}
}
void CL_FreeEdicts( void )
@ -1373,6 +1381,7 @@ static qboolean CL_LoadHudSprite( const char *szSpriteName, model_t *m_pSprite,
{
byte *buf;
size_t size;
qboolean loaded;
ASSERT( m_pSprite != NULL );
@ -1382,14 +1391,14 @@ static qboolean CL_LoadHudSprite( const char *szSpriteName, model_t *m_pSprite,
Q_strncpy( m_pSprite->name, szSpriteName, sizeof( m_pSprite->name ));
m_pSprite->flags = 256; // it's hud sprite, make difference names to prevent free shared textures
if( mapSprite ) Mod_LoadMapSprite( m_pSprite, buf, size );
else Mod_LoadSpriteModel( m_pSprite, buf );
if( mapSprite ) Mod_LoadMapSprite( m_pSprite, buf, size, &loaded );
else Mod_LoadSpriteModel( m_pSprite, buf, &loaded );
Mem_Free( buf );
if( m_pSprite->type != mod_sprite )
if( !loaded )
{
Q_memset( m_pSprite, 0, sizeof( *m_pSprite ));
Mod_UnloadSpriteModel( m_pSprite );
return false;
}
return true;
@ -3673,12 +3682,14 @@ void CL_UnloadProgs( void )
CL_FreeTempEnts();
CL_FreeViewBeams();
CL_FreeParticles();
CL_ClearAllRemaps();
VGui_Shutdown();
// NOTE: HLFX 0.5 has strange bug: hanging on exit if no map was loaded
if( !( !Q_stricmp( GI->gamedir, "hlfx" ) && GI->version == 0.5f ))
clgame.dllFuncs.pfnShutdown();
Cvar_FullSet( "host_clientloaded", "0", CVAR_INIT );
Com_FreeLibrary( clgame.hInstance );
Mem_FreePool( &cls.mempool );
Mem_FreePool( &clgame.mempool );
@ -3752,7 +3763,9 @@ qboolean CL_LoadProgs( const char *name )
Cvar_Get( "cl_nopred", "1", CVAR_ARCHIVE|CVAR_USERINFO, "disable client movement predicting" );
Cvar_Get( "cl_lw", "0", CVAR_ARCHIVE|CVAR_USERINFO, "enable client weapon predicting" );
Cvar_Get( "cl_lc", "0", CVAR_ARCHIVE|CVAR_USERINFO, "enable lag compensation" );
Cvar_FullSet( "host_clientloaded", "1", CVAR_INIT );
clgame.maxRemapInfos = 0; // will be alloc on first call CL_InitEdicts();
clgame.maxEntities = 2; // world + localclient (have valid entities not in game)
CL_InitCDAudio( "media/cdaudio.txt" );
CL_InitTitles( "titles.txt" );

View File

@ -472,9 +472,6 @@ void CL_WritePacket( void )
// update download/upload slider.
Netchan_UpdateProgress( &cls.netchan );
// make sure what menu and CL_WritePacket catch changes
userinfo->modified = false;
}
/*
@ -492,6 +489,9 @@ void CL_SendCmd( void )
// clc_move, userinfo etc
CL_WritePacket();
// make sure what menu and CL_WritePacket catch changes
userinfo->modified = false;
}
/*

View File

@ -216,6 +216,8 @@ static void UI_UpdateUserinfo( void )
Q_strncpy( player->userinfo, Cvar_Userinfo(), sizeof( player->userinfo ));
Q_strncpy( player->name, Info_ValueForKey( player->userinfo, "name" ), sizeof( player->name ));
Q_strncpy( player->model, Info_ValueForKey( player->userinfo, "model" ), sizeof( player->model ));
player->topcolor = Q_atoi( Info_ValueForKey( player->userinfo, "topcolor" ));
player->bottomcolor = Q_atoi( Info_ValueForKey( player->userinfo, "bottomcolor" ));
}
void Host_Credits( void )

View File

@ -478,7 +478,7 @@ void CL_ParseServerData( sizebuf_t *msg )
clgame.load_sequence++; // now all hud sprites are invalid
// wipe the client_t struct
CL_ClearState();
if( !cls.changelevel ) CL_ClearState();
cls.state = ca_connected;
// parse protocol version number
@ -522,7 +522,7 @@ void CL_ParseServerData( sizebuf_t *msg )
menu.globals->maxClients = cl.maxclients;
Q_strncpy( menu.globals->maptitle, clgame.maptitle, sizeof( menu.globals->maptitle ));
CL_InitEdicts (); // re-arrange edicts
if( !cls.changelevel ) CL_InitEdicts (); // re-arrange edicts
// get splash name
Cvar_Set( "cl_levelshot_name", va( "levelshots/%s", clgame.mapname ));
@ -782,6 +782,9 @@ void CL_UpdateUserinfo( sizebuf_t *msg )
Q_strncpy( player->userinfo, BF_ReadString( msg ), sizeof( player->userinfo ));
Q_strncpy( player->name, Info_ValueForKey( player->userinfo, "name" ), sizeof( player->name ));
Q_strncpy( player->model, Info_ValueForKey( player->userinfo, "model" ), sizeof( player->model ));
player->topcolor = Q_atoi( Info_ValueForKey( player->userinfo, "topcolor" ));
player->bottomcolor = Q_atoi( Info_ValueForKey( player->userinfo, "bottomcolor" ));
if( slot == cl.playernum ) Q_memcpy( &menu.playerinfo, player, sizeof( player_info_t ));
}
else Q_memset( player, 0, sizeof( *player ));
@ -1242,6 +1245,7 @@ void CL_ParseServerMessage( sizebuf_t *msg )
else MsgDev( D_INFO, "Server disconnected, reconnecting\n" );
CL_ClearState ();
CL_InitEdicts (); // re-arrange edicts
cls.state = ca_connecting;
cls.connect_time = MAX_HEARTBEAT; // CL_CheckForResend() will fire immediately

387
engine/client/cl_remap.c Normal file
View File

@ -0,0 +1,387 @@
/*
gl_remap.c - remap model textures
Copyright (C) 2011 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "common.h"
#include "client.h"
#include "gl_local.h"
#include "studio.h"
static void CL_PaletteHueReplace( byte *palSrc, int newHue, int start, int end )
{
float r, g, b;
float maxcol, mincol;
float hue, val, sat;
int i;
hue = (float)(newHue * ( 360.0f / 255 ));
for( i = start; i <= end; i++ )
{
r = palSrc[i*3+0];
g = palSrc[i*3+1];
b = palSrc[i*3+2];
maxcol = max( max( r, g ), b ) / 255.0f;
mincol = min( min( r, g ), b ) / 255.0f;
val = maxcol;
sat = (maxcol - mincol) / maxcol;
mincol = val * (1.0f - sat);
if( hue <= 120.0f )
{
b = mincol;
if( hue < 60 )
{
r = val;
g = mincol + hue * (val - mincol) / (120.0f - hue);
}
else
{
g = val;
r = mincol + (120.0f - hue) * (val - mincol) / hue;
}
}
else if( hue <= 240.0f )
{
r = mincol;
if( hue < 180.0f )
{
g = val;
b = mincol + (hue - 120.0f) * (val - mincol) / (240.0f - hue);
}
else
{
b = val;
g = mincol + (240.0f - hue) * (val - mincol) / (hue - 120.0f);
}
}
else
{
g = mincol;
if( hue < 300.0f )
{
b = val;
r = mincol + (hue - 240.0f) * (val - mincol) / (360.0f - hue);
}
else
{
r = val;
b = mincol + (360.0f - hue) * (val - mincol) / (hue - 240.0f);
}
}
palSrc[i*3+0] = (byte)(r * 255);
palSrc[i*3+1] = (byte)(g * 255);
palSrc[i*3+2] = (byte)(b * 255);
}
}
/*
====================
CL_GetRemapInfoForEntity
Returns remapinfo slot for specified entity
====================
*/
remap_info_t *CL_GetRemapInfoForEntity( cl_entity_t *e )
{
if( !e ) return NULL;
if( e == &clgame.viewent )
return clgame.remap_info[clgame.maxEntities];
return clgame.remap_info[e->curstate.number];
}
/*
====================
CL_CreateRawTextureFromPixels
Convert texture_t struct into mstudiotexture_t prototype
====================
*/
byte *CL_CreateRawTextureFromPixels( texture_t *tx, size_t *size, int topcolor, int bottomcolor )
{
static mstudiotexture_t pin;
byte *pal;
ASSERT( size != NULL );
*size = sizeof( pin ) + (tx->width * tx->height) + 768;
// fill header
if( !pin.name[0] ) Q_strncpy( pin.name, "#raw_remap_image.mdl", sizeof( pin.name ));
pin.flags = STUDIO_NF_COLORMAP; // just in case :-)
pin.index = (int)(tx + 1); // pointer to pixels
pin.width = tx->width;
pin.height = tx->height;
// update palette
pal = (byte *)(tx + 1) + (tx->width * tx->height);
CL_PaletteHueReplace( pal, topcolor, tx->anim_min, tx->anim_max );
CL_PaletteHueReplace( pal, bottomcolor, tx->anim_max + 1, tx->anim_total );
return (byte *)&pin;
}
/*
====================
CL_DuplicateTexture
Dupliacte texture with remap pixels
====================
*/
void CL_DuplicateTexture( mstudiotexture_t *ptexture, int topcolor, int bottomcolor )
{
gltexture_t *glt;
texture_t *tx = NULL;
char texname[128];
int i, size, index;
byte *raw;
// save of the real texture index
index = ptexture->index;
glt = R_GetTexture( index );
Q_snprintf( texname, sizeof( texname ), "#%i_%s", RI.currententity->curstate.number, glt->name + 1 );
// search for pixels
for( i = 0; i < RI.currentmodel->numtextures; i++ )
{
tx = RI.currentmodel->textures[i];
if( tx->gl_texturenum == index )
break; // found
}
ASSERT( tx != NULL );
raw = CL_CreateRawTextureFromPixels( tx, &size, topcolor, bottomcolor );
ptexture->index = GL_LoadTexture( texname, raw, size, TF_FORCE_COLOR ); // do copy
GL_SetTextureType( ptexture->index, TEX_REMAP );
}
/*
====================
CL_UpdateTexture
Update texture top and bottom colors
====================
*/
void CL_UpdateTexture( mstudiotexture_t *ptexture, int topcolor, int bottomcolor )
{
gltexture_t *glt;
rgbdata_t *pic;
texture_t *tx = NULL;
char texname[128], name[128];
int i, size, index;
byte paletteBackup[768];
byte *raw, *pal;
// save of the real texture index
glt = R_GetTexture( ptexture->index );
// build name of original texture
FS_FileBase( ptexture->name, name );
Q_snprintf( texname, sizeof( texname ), "#%s/%s.mdl", RI.currentmodel->name, name );
index = GL_FindTexture( texname );
if( !index ) return; // couldn't find texture
// search for pixels
for( i = 0; i < RI.currentmodel->numtextures; i++ )
{
tx = RI.currentmodel->textures[i];
if( tx->gl_texturenum == index )
break; // found
}
ASSERT( tx != NULL );
// backup original palette
pal = (byte *)(tx + 1) + (tx->width * tx->height);
Q_memcpy( paletteBackup, pal, 768 );
raw = CL_CreateRawTextureFromPixels( tx, &size, topcolor, bottomcolor );
pic = FS_LoadImage( glt->name, raw, size );
if( !pic )
{
MsgDev( D_ERROR, "Couldn't update texture %s\n", glt->name );
return;
}
index = GL_LoadTextureInternal( glt->name, pic, 0, true );
FS_FreeImage( pic );
// restore original palette
Q_memcpy( pal, paletteBackup, 768 );
ASSERT( index == ptexture->index );
}
/*
====================
CL_AllocRemapInfo
Allocate new remap info per entity
and make copy of remap textures
====================
*/
void CL_AllocRemapInfo( int topcolor, int bottomcolor )
{
remap_info_t *info;
studiohdr_t *phdr;
mstudiotexture_t *src, *dst;
int i, size;
i = ( RI.currententity == &clgame.viewent ) ? clgame.maxEntities : RI.currententity->curstate.number;
if( !RI.currentmodel || RI.currentmodel->type != mod_studio )
{
// entity has changed model by another type, release remap info
if( clgame.remap_info[i] )
{
CL_FreeRemapInfo( clgame.remap_info[i] );
clgame.remap_info[i] = NULL;
}
return; // missed or hided model, ignore it
}
// model doesn't contains remap textures
if( RI.currentmodel->numtextures <= 0 )
{
// entity has changed model with no remap textures
if( clgame.remap_info[i] )
{
CL_FreeRemapInfo( clgame.remap_info[i] );
clgame.remap_info[i] = NULL;
}
return;
}
phdr = (studiohdr_t *)Mod_Extradata( RI.currentmodel );
if( !phdr ) return; // missed header ???
// NOTE: we must copy all the structures 'mstudiotexture_t' for easy acces when model is rendering
if( !clgame.remap_info[i] || clgame.remap_info[i]->model != RI.currentmodel )
{
// this code catches studiomodel change with another studiomodel with remap textures
// e.g. playermodel 'barney' with playermodel 'gordon'
if( clgame.remap_info[i] ) CL_FreeRemapInfo( clgame.remap_info[i] ); // free old info
size = sizeof( remap_info_t ) + ( sizeof( mstudiotexture_t ) * phdr->numtextures );
info = clgame.remap_info[i] = Mem_Alloc( clgame.mempool, size );
info->ptexture = (mstudiotexture_t *)(info + 1); // textures are immediately comes after remap_info
}
else
{
// studiomodel is valid, nothing to change
return;
}
info->numtextures = phdr->numtextures;
info->model = RI.currentmodel;
info->topcolor = topcolor;
info->bottomcolor = bottomcolor;
src = (mstudiotexture_t *)(((byte *)phdr) + phdr->textureindex);
dst = info->ptexture;
// copy unchanged first
Q_memcpy( dst, src, sizeof( mstudiotexture_t ) * phdr->numtextures );
// make local copies for remap textures
for( i = 0; i < info->numtextures; i++ )
{
if( dst[i].flags & STUDIO_NF_COLORMAP )
CL_DuplicateTexture( &dst[i], topcolor, bottomcolor );
}
}
/*
====================
CL_UpdateRemapInfo
Update all remaps per entity
====================
*/
void CL_UpdateRemapInfo( int topcolor, int bottomcolor )
{
remap_info_t *info;
mstudiotexture_t *dst;
int i;
i = ( RI.currententity == &clgame.viewent ) ? clgame.maxEntities : RI.currententity->curstate.number;
info = clgame.remap_info[i];
if( !info ) return; // no remap info
if( info->topcolor == topcolor && info->bottomcolor == bottomcolor )
return; // values is valid
dst = info->ptexture;
for( i = 0; i < info->numtextures; i++ )
{
if( dst[i].flags & STUDIO_NF_COLORMAP )
CL_UpdateTexture( &dst[i], topcolor, bottomcolor );
}
info->topcolor = topcolor;
info->bottomcolor = bottomcolor;
}
/*
====================
CL_FreeRemapInfo
Release remap info per entity
====================
*/
void CL_FreeRemapInfo( remap_info_t *info )
{
int i;
ASSERT( info != NULL );
// release all colormap texture copies
for( i = 0; i < info->numtextures; i++ )
{
if( info->ptexture[i].flags & STUDIO_NF_COLORMAP )
GL_FreeTexture( info->ptexture[i].index );
}
Mem_Free( info ); // release struct
}
/*
====================
CL_ClearAllRemaps
Release all remap infos
====================
*/
void CL_ClearAllRemaps( void )
{
int i;
if( clgame.remap_info )
{
for( i = 0; i < clgame.maxRemapInfos; i++ )
{
if( clgame.remap_info[i] )
CL_FreeRemapInfo( clgame.remap_info[i] );
}
Mem_Free( clgame.remap_info );
}
clgame.remap_info = NULL;
}

View File

@ -37,6 +37,7 @@ void V_SetupRefDef( void )
VectorCopy( cl.frame.local.client.punchangle, cl.refdef.punchangle );
clgame.viewent.curstate.modelindex = cl.frame.local.client.viewmodel;
clgame.viewent.model = Mod_Handle( clgame.viewent.curstate.modelindex );
clgame.viewent.curstate.number = cl.playernum + 1;
clgame.viewent.curstate.entityType = ET_NORMAL;
clgame.viewent.index = cl.playernum + 1;

View File

@ -274,6 +274,15 @@ typedef struct
float applied_angle;
} screen_shake_t;
typedef struct
{
struct mstudiotex_s *ptexture; // array of textures with local copy of remapped textures
short numtextures; // textures count
short topcolor; // cached value
short bottomcolor; // cached value
model_t *model; // for catch model changes
} remap_info_t;
typedef struct
{
int (*pfnInitialize)( cl_enginefunc_t *pEnginefuncs, int iVersion );
@ -302,6 +311,7 @@ typedef struct
void (*pfnTxferPredictionData)( entity_state_t *ps, const entity_state_t *pps, clientdata_t *pcd, const clientdata_t *ppcd, weapon_data_t *wd, const weapon_data_t *pwd );
void (*pfnTempEntUpdate)( double frametime, double client_time, double cl_gravity, struct tempent_s **ppTempEntFree, struct tempent_s **ppTempEntActive, int ( *Callback_AddVisibleEntity )( cl_entity_t *pEntity ), void ( *Callback_TempEntPlaySound )( struct tempent_s *pTemp, float damp ));
int (*pfnGetStudioModelInterface)( int version, struct r_studio_interface_s **ppinterface, struct engine_studio_api_s *pstudio );
void (*pfnChatInputPosition)( int *x, int *y );
void (*pfnDrawNormalTriangles)( void );
void (*pfnDrawTransparentTriangles)( void );
cl_entity_t *(*pfnGetUserEntity)( int index );
@ -327,8 +337,10 @@ typedef struct
string itemspath; // path to items description for auto-complete func
cl_entity_t *entities; // dynamically allocated entity array
remap_info_t **remap_info; // store local copy of all remap textures for each entity
int maxEntities;
int maxRemapInfos; // maxEntities + cl.viewEnt; also used for catch entcount
// movement values from server
movevars_t movevars;
@ -647,6 +659,16 @@ qboolean CL_AddVisibleEntity( cl_entity_t *ent, int entityType );
qboolean CL_GetEntitySpatialization( int ent, vec3_t origin, vec3_t velocity );
qboolean CL_IsPlayerIndex( int idx );
//
// cl_remap.c
//
remap_info_t *CL_GetRemapInfoForEntity( cl_entity_t *e );
void CL_AllocRemapInfo( int topcolor, int bottomcolor );
void CL_FreeRemapInfo( remap_info_t *info );
void R_StudioSetRemapColors( int top, int bottom );
void CL_UpdateRemapInfo( int topcolor, int bottomcolor );
void CL_ClearAllRemaps( void );
//
// cl_tent.c
//

View File

@ -898,8 +898,7 @@ static void GL_UploadTexture( rgbdata_t *pic, gltexture_t *tex, qboolean subImag
}
}
// critical stuff!!!
GL_MBind( tex - r_textures );
pglBindTexture( tex->target, tex->texnum );
buf = pic->buffer;
bufend = pic->buffer + pic->size;
@ -960,7 +959,7 @@ int GL_LoadTexture( const char *name, const byte *buf, size_t size, int flags )
if( Q_strlen( name ) >= sizeof( r_textures->name ))
{
MsgDev( D_ERROR, "GL_LoadTexture: too long name %s\n", name, sizeof( r_textures->name ));
MsgDev( D_ERROR, "GL_LoadTexture: too long name %s\n", name );
return 0;
}
@ -1039,7 +1038,7 @@ int GL_LoadTextureInternal( const char *name, rgbdata_t *pic, texFlags_t flags,
if( Q_strlen( name ) >= sizeof( r_textures->name ))
{
MsgDev( D_ERROR, "GL_LoadTexture: too long name %s\n", name, sizeof( r_textures->name ));
MsgDev( D_ERROR, "GL_LoadTexture: too long name %s\n", name );
return 0;
}
@ -1051,8 +1050,11 @@ int GL_LoadTextureInternal( const char *name, rgbdata_t *pic, texFlags_t flags,
if( tex->flags & TF_CUBEMAP )
continue;
if( !Q_stricmp( tex->name, name ) && !update )
return tex->texnum;
if( !Q_stricmp( tex->name, name ))
{
if( update ) break;
return tex->texnum;
}
}
if( !pic ) return 0; // couldn't loading image
@ -1106,6 +1108,40 @@ int GL_LoadTextureInternal( const char *name, rgbdata_t *pic, texFlags_t flags,
return tex->texnum;
}
/*
================
GL_LoadTexture
================
*/
int GL_FindTexture( const char *name )
{
gltexture_t *tex;
uint hash;
if( !name || !name[0] || !glw_state.initialized )
return 0;
if( Q_strlen( name ) >= sizeof( r_textures->name ))
{
MsgDev( D_ERROR, "GL_FindTexture: too long name %s\n", name );
return 0;
}
// see if already loaded
hash = Com_HashKey( name, TEXTURES_HASH_SIZE );
for( tex = r_texturesHashTable[hash]; tex != NULL; tex = tex->nextHash )
{
if( tex->flags & TF_CUBEMAP )
continue;
if( !Q_stricmp( tex->name, name ))
return tex->texnum;
}
return 0;
}
/*
================
GL_FreeImage

View File

@ -64,12 +64,13 @@ typedef enum
TEX_DECAL, // decals
TEX_VGUI, // vgui fonts or images
TEX_CUBEMAP, // cubemap textures (sky)
TEX_DETAIL // detail textures
TEX_DETAIL, // detail textures
TEX_REMAP // local copy of remap texture
} texType_t;
typedef enum
{
TF_STATIC = BIT(0), // don't free until Shader_FreeUnused()
TF_STATIC = BIT(0), // don't free until Image_FreeUnused()
TF_NOPICMIP = BIT(1), // ignore r_picmip resample rules
TF_UNCOMPRESSED = BIT(2), // don't compress texture in video memory
TF_CUBEMAP = BIT(3), // it's cubemap texture
@ -206,10 +207,12 @@ typedef struct
gl_entity_t mirror_entities[MAX_VISIBLE_PACKET]; // an entities that has mirror
cl_entity_t *solid_entities[MAX_VISIBLE_PACKET]; // opaque moving or alpha brushes
cl_entity_t *trans_entities[MAX_VISIBLE_PACKET]; // translucent brushes
cl_entity_t *child_entities[MAX_VISIBLE_PACKET]; // entities with MOVETYPE_FOLLOW
uint num_static_entities;
uint num_mirror_entities;
uint num_solid_entities;
uint num_trans_entities;
uint num_child_entities;
// OpenGL matrix states
qboolean modelviewIdentity;
@ -244,7 +247,7 @@ extern mleaf_t *r_viewleaf, *r_oldviewleaf;
extern mleaf_t *r_viewleaf2, *r_oldviewleaf2;
extern dlight_t cl_dlights[MAX_DLIGHTS];
extern dlight_t cl_elights[MAX_ELIGHTS];
#define r_numEntities (tr.num_solid_entities + tr.num_trans_entities)
#define r_numEntities (tr.num_solid_entities + tr.num_trans_entities + tr.num_child_entities)
#define r_numStatics (tr.num_static_entities)
//
@ -297,6 +300,7 @@ void GL_SetTextureType( GLenum texnum, GLenum type );
int GL_LoadTexture( const char *name, const byte *buf, size_t size, int flags );
int GL_LoadTextureInternal( 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_FindTexture( const char *name );
void GL_FreeTexture( GLenum texnum );
void GL_FreeImage( const char *name );
void R_TextureList_f( void );
@ -362,7 +366,7 @@ void GL_BuildLightmaps( void );
// gl_sprite.c
//
void R_SpriteInit( void );
void Mod_LoadSpriteModel( model_t *mod, const void *buffer );
void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded );
mspriteframe_t *R_GetSpriteFrame( const model_t *pModel, int frame, float yaw );
void R_DrawSpriteModel( cl_entity_t *e );
@ -370,7 +374,7 @@ void R_DrawSpriteModel( cl_entity_t *e );
// gl_studio.c
//
void R_StudioInit( void );
void Mod_LoadStudioModel( model_t *mod, const void *buffer );
void Mod_LoadStudioModel( model_t *mod, const void *buffer, qboolean *loaded );
void R_DrawStudioModel( cl_entity_t *e );
//
@ -423,8 +427,7 @@ qboolean R_CullBox( const vec3_t mins, const vec3_t maxs, uint clipflags );
qboolean 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_LoadSpriteModel( struct model_s *mod, const void *buffer );
void Mod_LoadMapSprite( struct model_s *mod, const void *buffer, size_t size );
void Mod_LoadMapSprite( struct model_s *mod, const void *buffer, size_t size, qboolean *loaded );
void Mod_UnloadSpriteModel( struct model_s *mod );
void Mod_UnloadStudioModel( struct model_s *mod );
void Mod_UnloadBrushModel( struct model_s *mod );

View File

@ -72,6 +72,28 @@ static qboolean R_StaticEntity( cl_entity_t *ent )
return true;
}
/*
===============
R_FollowEntity
Follow entity is attached to another studiomodel and used last cached bones
from parent
===============
*/
static qboolean R_FollowEntity( cl_entity_t *ent )
{
if( ent->model->type != mod_studio )
return false;
if( ent->curstate.movetype != MOVETYPE_FOLLOW )
return false;
if( ent->curstate.aiment <= 0 )
return false;
return true;
}
/*
===============
R_OpaqueEntity
@ -315,6 +337,7 @@ void R_ClearScene( void )
{
tr.num_solid_entities = tr.num_trans_entities = 0;
tr.num_static_entities = tr.num_mirror_entities = 0;
tr.num_child_entities = 0;
}
/*
@ -338,6 +361,18 @@ qboolean R_AddEntity( struct cl_entity_s *clent, int entityType )
clent->curstate.entityType = entityType;
if( R_FollowEntity( clent ))
{
// follow entity
if( tr.num_child_entities >= MAX_VISIBLE_PACKET )
return false;
tr.child_entities[tr.num_child_entities] = clent;
tr.num_child_entities++;
return true;
}
if( R_OpaqueEntity( clent ))
{
if( R_StaticEntity( clent ))

View File

@ -170,7 +170,7 @@ void R_CreateDetailTexturesList( const char *filename )
// detailtexture detected
if( detail_name )
{
if( !detail_txt ) detail_txt = FS_Open( filename, "wb", false );
if( !detail_txt ) detail_txt = FS_Open( filename, "w", false );
if( !detail_txt )
{
MsgDev( D_ERROR, "Can't write %s\n", filename );
@ -272,7 +272,13 @@ void R_NewMap( void )
// clear out efrags in case the level hasn't been reloaded
for( i = 0; i < cl.worldmodel->numleafs; i++ )
{
cl.worldmodel->leafs[i].efrags = NULL;
cl.worldmodel->leafs[i].visframe = 0;
}
for( i = 0; i < cl.worldmodel->numnodes; i++ )
cl.worldmodel->nodes[i].visframe = 0;
tr.skytexturenum = -1;
r_viewleaf = r_oldviewleaf = NULL;

View File

@ -1915,7 +1915,7 @@ void GL_BuildLightmaps( void )
skychain = NULL;
tr.framecount = 1; // no dlight cache
tr.framecount = tr.visframecount = 1; // no dlight cache
gl_lms.current_lightmap_texture = 0;
// setup all the lightstyles
@ -1937,6 +1937,7 @@ void GL_BuildLightmaps( void )
{
// clearing all decal chains
m->surfaces[j].pdecals = NULL;
m->surfaces[j].visframe = 0;
GL_CreateSurfaceLightmap( m->surfaces + j );

File diff suppressed because it is too large Load Diff

View File

@ -132,7 +132,7 @@ Mod_LoadSpriteModel
load sprite model
====================
*/
void Mod_LoadSpriteModel( model_t *mod, const void *buffer )
void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded )
{
dsprite_t *pin;
short *numi;
@ -140,7 +140,9 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer )
dframetype_t *pframetype;
int i, size;
if( loaded ) *loaded = false;
pin = (dsprite_t *)buffer;
mod->type = mod_sprite;
i = pin->version;
if( pin->ident != IDSPRITEHEADER )
@ -176,7 +178,7 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer )
if( host.type == HOST_DEDICATED )
{
// skip frames loading
mod->type = mod_sprite;
if( loaded ) *loaded = true; // done
psprite->numframes = 0;
return;
}
@ -210,14 +212,12 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer )
else
{
MsgDev( D_ERROR, "%s has wrong number of palette colors %i (should be 256)\n", mod->name, numi );
Mem_FreePool( &mod->mempool );
return;
}
if( pin->numframes < 1 )
{
MsgDev( D_ERROR, "%s has invalid # of frames: %d\n", mod->name, pin->numframes );
Mem_FreePool( &mod->mempool );
return;
}
@ -244,7 +244,7 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer )
if( pframetype == NULL ) break; // technically an error
}
mod->type = mod_sprite; // done
if( loaded ) *loaded = true; // done
}
/*
@ -255,7 +255,7 @@ Loading a bitmap image as sprite with multiple frames
as pieces of input image
====================
*/
void Mod_LoadMapSprite( model_t *mod, const void *buffer, size_t size )
void Mod_LoadMapSprite( model_t *mod, const void *buffer, size_t size, qboolean *loaded )
{
byte *src, *dst;
rgbdata_t *pix, temp;
@ -266,10 +266,13 @@ void Mod_LoadMapSprite( model_t *mod, const void *buffer, size_t size )
mspriteframe_t *pspriteframe;
msprite_t *psprite;
if( loaded ) *loaded = false;
Q_snprintf( texname, sizeof( texname ), "#%s", mod->name );
pix = FS_LoadImage( texname, buffer, size );
if( !pix ) return; // bad image or something else
mod->type = mod_sprite;
if( pix->width % MAPSPRITE_SIZE )
w = pix->width - ( pix->width % MAPSPRITE_SIZE );
else w = pix->width;
@ -358,7 +361,8 @@ void Mod_LoadMapSprite( model_t *mod, const void *buffer, size_t size )
FS_FreeImage( pix );
Mem_Free( temp.buffer );
mod->type = mod_sprite; // done
if( loaded ) *loaded = true;
}
/*

View File

@ -61,7 +61,7 @@ convar_t *r_studio_lighting;
convar_t *r_drawviewmodel;
convar_t *r_customdraw_playermodel;
convar_t *cl_himodels;
cvar_t r_shadows = { "r_shadows", "0", 0, 0 }; // dead cvar. especially disabled
cvar_t r_shadows = { "r_shadows", "0", 0, 1 }; // dead cvar. especially disabled
cvar_t r_shadowalpha = { "r_shadowalpha", "0.5", 0, 0 };
static r_studio_interface_t *pStudioDraw;
static float aliasXscale, aliasYscale; // software renderer scale
@ -77,6 +77,11 @@ static vec3_t g_chromeup[MAXSTUDIOBONES]; // chrome vector "up" in bone referen
static int g_chromeage[MAXSTUDIOBONES]; // last time chrome vectors were updated
static vec3_t g_xformverts[MAXSTUDIOVERTS];
static vec3_t g_xformnorms[MAXSTUDIOVERTS];
static vec3_t g_xarrayverts[MAXSTUDIOVERTS];
static vec3_t g_xarraynorms[MAXSTUDIOVERTS];
static uint g_xarrayelems[MAXSTUDIOVERTS*6];
static uint g_nNumArrayVerts;
static uint g_nNumArrayElems;
static vec3_t g_lightvalues[MAXSTUDIOVERTS];
static studiolight_t g_studiolight;
char g_nCachedBoneNames[MAXSTUDIOBONES][32];
@ -88,6 +93,7 @@ float studio_radius;
// global variables
qboolean m_fDoInterp;
qboolean m_fDoRemap;
mstudiomodel_t *m_pSubModel;
mstudiobodyparts_t *m_pBodyPart;
player_info_t *m_pPlayerInfo;
@ -129,6 +135,7 @@ void R_StudioInit( void )
Matrix3x4_LoadIdentity( g_rotationmatrix );
g_nStudioCount = 0;
m_fDoRemap = false;
}
/*
@ -272,6 +279,9 @@ pfnPlayerInfo
*/
static player_info_t *pfnPlayerInfo( int index )
{
if( cls.key_dest == key_menu && !index )
return &menu.playerinfo;
if( index < 0 || index > cl.maxclients )
return NULL;
return &cl.players[index];
@ -1230,7 +1240,7 @@ void R_StudioSetupChrome( float *pchrome, int bone, vec3_t normal )
// calculate vectors from the viewer to the bone. This roughly adjusts for position
vec3_t chromeupvec; // g_chrome t vector in world reference frame
vec3_t chromerightvec; // g_chrome s vector in world reference frame
vec3_t tmp; // vector pointing at bone in world reference frame
vec3_t tmp, v_left; // vector pointing at bone in world reference frame
VectorScale( cl.refdef.vieworg, -1.0f, tmp );
tmp[0] += g_bonestransform[bone][0][3];
@ -1238,16 +1248,17 @@ void R_StudioSetupChrome( float *pchrome, int bone, vec3_t normal )
tmp[2] += g_bonestransform[bone][2][3];
VectorNormalize( tmp );
VectorNegate( RI.vright, v_left );
if( g_nFaceFlags & STUDIO_NF_CHROME )
{
float angle = anglemod( RI.refdef.time * 40 );
RotatePointAroundVector( chromeupvec, tmp, RI.vright, angle - 180 );
RotatePointAroundVector( chromerightvec, chromeupvec, RI.vright, 180 + angle );
RotatePointAroundVector( chromeupvec, tmp, v_left, angle - 180 );
RotatePointAroundVector( chromerightvec, chromeupvec, v_left, 180 + angle );
}
else
{
CrossProduct( tmp, RI.vright, chromeupvec );
CrossProduct( tmp, v_left, chromeupvec );
VectorNormalize( chromeupvec );
CrossProduct( tmp, chromeupvec, chromerightvec );
VectorNormalize( chromerightvec );
@ -1636,6 +1647,9 @@ static void R_StudioSetupSkin( mstudiotexture_t *ptexture, int index )
if( !m_pTextureHeader ) return;
// NOTE: user can comment call StudioRemapColors and remap_info will be unavailable
if( m_fDoRemap ) ptexture = CL_GetRemapInfoForEntity( RI.currententity )->ptexture;
m_skinnum = RI.currententity->curstate.skin;
pskinref = (short *)((byte *)m_pTextureHeader + m_pTextureHeader->skinindex);
if( m_skinnum != 0 && m_skinnum < m_pTextureHeader->numskinfamilies )
@ -1664,6 +1678,8 @@ static void R_StudioDrawPoints( void )
R_StudioSetupTextureHeader ();
g_nNumArrayVerts = g_nNumArrayElems = 0;
if( !m_pTextureHeader ) return;
if( RI.currententity->curstate.renderfx == kRenderFxGlowShell )
g_nStudioCount++;
@ -1671,7 +1687,12 @@ static void R_StudioDrawPoints( void )
m_skinnum = RI.currententity->curstate.skin;
pvertbone = ((byte *)m_pStudioHeader + m_pSubModel->vertinfoindex);
pnormbone = ((byte *)m_pStudioHeader + m_pSubModel->norminfoindex);
ptexture = (mstudiotexture_t *)((byte *)m_pTextureHeader + m_pTextureHeader->textureindex);
// NOTE: user can comment call StudioRemapColors and remap_info will be unavailable
if( m_fDoRemap ) ptexture = CL_GetRemapInfoForEntity( RI.currententity )->ptexture;
else ptexture = (mstudiotexture_t *)((byte *)m_pTextureHeader + m_pTextureHeader->textureindex);
ASSERT( ptexture != NULL );
pmesh = (mstudiomesh_t *)((byte *)m_pStudioHeader + m_pSubModel->meshindex);
pstudioverts = (vec3_t *)((byte *)m_pStudioHeader + m_pSubModel->vertindex);
@ -1757,20 +1778,56 @@ static void R_StudioDrawPoints( void )
while( i = *( ptricmds++ ))
{
int vertexState = 0;
qboolean tri_strip;
if( i < 0 )
{
pglBegin( GL_TRIANGLE_FAN );
tri_strip = false;
i = -i;
}
else
{
pglBegin( GL_TRIANGLE_STRIP );
tri_strip = true;
}
r_stats.c_studio_polys++;
for( ; i > 0; i--, ptricmds += 4 )
{
// build in indices
if( vertexState++ < 3 )
{
g_xarrayelems[g_nNumArrayElems++] = g_nNumArrayVerts;
}
else if( tri_strip )
{
// flip triangles between clockwise and counter clockwise
if( vertexState & 1 )
{
// draw triangle [n-2 n-1 n]
g_xarrayelems[g_nNumArrayElems++] = g_nNumArrayVerts - 2;
g_xarrayelems[g_nNumArrayElems++] = g_nNumArrayVerts - 1;
g_xarrayelems[g_nNumArrayElems++] = g_nNumArrayVerts;
}
else
{
// draw triangle [n-1 n-2 n]
g_xarrayelems[g_nNumArrayElems++] = g_nNumArrayVerts - 1;
g_xarrayelems[g_nNumArrayElems++] = g_nNumArrayVerts - 2;
g_xarrayelems[g_nNumArrayElems++] = g_nNumArrayVerts;
}
}
else
{
// draw triangle fan [0 n-1 n]
g_xarrayelems[g_nNumArrayElems++] = g_nNumArrayVerts - ( vertexState - 1 );
g_xarrayelems[g_nNumArrayElems++] = g_nNumArrayVerts - 1;
g_xarrayelems[g_nNumArrayElems++] = g_nNumArrayVerts;
}
if( flags & STUDIO_NF_CHROME || ( g_nFaceFlags & STUDIO_NF_CHROME ))
pglTexCoord2f( g_chrome[ptricmds[1]][0] * s, g_chrome[ptricmds[1]][1] * t );
else pglTexCoord2f( ptricmds[2] * s, ptricmds[3] * t );
@ -1796,6 +1853,8 @@ static void R_StudioDrawPoints( void )
av = g_xformverts[ptricmds[0]];
pglVertex3f( av[0], av[1], av[2] );
VectorCopy( av, g_xarrayverts[g_nNumArrayVerts] ); // store off vertex
g_nNumArrayVerts++;
}
pglEnd();
}
@ -2053,9 +2112,28 @@ R_StudioSetRemapColors
===============
*/
void R_StudioSetRemapColors( int top, int bottom )
void R_StudioSetRemapColors( int newTop, int newBottom )
{
// TODO: implement
// update colors for viewentity
if( RI.currententity == &clgame.viewent )
{
player_info_t *pLocalPlayer;
// copy top and bottom colors for viewmodel
if(( pLocalPlayer = pfnPlayerInfo( clgame.viewent.curstate.number - 1 )) != NULL )
{
newTop = bound( 0, pLocalPlayer->topcolor, 360 );
newBottom = bound( 0, pLocalPlayer->bottomcolor, 360 );
}
}
CL_AllocRemapInfo( newTop, newBottom );
if( CL_GetRemapInfoForEntity( RI.currententity ))
{
CL_UpdateRemapInfo( newTop, newBottom );
m_fDoRemap = true;
}
}
/*
@ -2192,6 +2270,7 @@ pfnStudioSetHeader
void R_StudioSetHeader( studiohdr_t *pheader )
{
m_pStudioHeader = pheader;
m_fDoRemap = false;
}
/*
@ -2234,6 +2313,8 @@ static void R_StudioRestoreRenderer( void )
// restore depthmask state for sprites etc
if( glState.drawTrans ) pglDepthMask( GL_FALSE );
m_fDoRemap = false;
}
/*
@ -2256,15 +2337,85 @@ Xash3D is always works in hadrware mode
*/
static int pfnIsHardware( void )
{
return true;
return 1; // 0 is Software, 1 is OpenGL, 2 is Direct3D
}
static void StudioDrawShadow( void )
/*
===============
R_StudioGetShadowImpactAndDir
===============
*/
void R_StudioGetShadowImpactAndDir( pmtrace_t *ptr, vec3_t lightdir )
{
// in GoldSrc shadow call is dsiabled with 'return' at start of the function
// some mods used a hack with calling DrawShadow ahead of 'return'
// this code is for HL compatibility.
// MsgDev( D_INFO, "GL_StudioDrawShadow()\n" ); // just a debug
vec3_t start, end;
studiolight_t *plight;
plight = &g_studiolight;
VectorSet( lightdir, -0.5, -0.2, -1.0f );
VectorNormalizeFast( lightdir );
VectorCopy( RI.currententity->origin, start );
start[2] += 78;
VectorMA( start, 1024.0f, lightdir, end );
*ptr = PM_PlayerTrace( clgame.pmove, start, end, PM_STUDIO_IGNORE, 2, -1, NULL );
}
/*
===============
R_StudioDeformShadow
Deform vertices by specified lightdir
===============
*/
void R_StudioDeformShadow( void )
{
float *verts, planedist, dist;
vec3_t planenormal, lightdir, lightdir2, point;
int numVerts;
pmtrace_t tr;
R_StudioGetShadowImpactAndDir( &tr, lightdir );
Matrix3x4_VectorIRotate( g_rotationmatrix, lightdir, lightdir2 );
Matrix3x4_VectorIRotate( g_rotationmatrix, tr.plane.normal, planenormal );
// VectorScale( planenormal, RI.currententity->curstate.scale, planenormal );
VectorSubtract( tr.endpos, RI.currententity->origin, point );
planedist = DotProduct( point, tr.plane.normal ) + 1;
dist = -1.0f / DotProduct( lightdir2, planenormal );
VectorScale( lightdir2, dist, lightdir2 );
verts = g_xarrayverts[0];
numVerts = g_nNumArrayVerts;
for( ; numVerts > 0; numVerts--, verts += 3 )
{
dist = DotProduct( verts, tr.plane.normal ) - planedist;
if( dist > 0 ) VectorMA( verts, dist, lightdir, verts );
}
}
static void R_StudioDrawPlanarShadow( void )
{
R_StudioDeformShadow ();
// if( glState.stencilEnabled )
// pglEnable( GL_STENCIL_TEST );
pglEnableClientState( GL_VERTEX_ARRAY );
pglVertexPointer( 3, GL_FLOAT, 12, g_xarrayverts );
Msg( "DrawShadow( %i %i )\n", g_nNumArrayVerts, g_nNumArrayElems );
if( GL_Support( GL_DRAW_RANGEELEMENTS_EXT ))
pglDrawRangeElementsEXT( GL_TRIANGLES, 0, g_nNumArrayVerts, g_nNumArrayElems, GL_UNSIGNED_INT, g_xarrayelems );
else pglDrawElements( GL_TRIANGLES, g_nNumArrayElems, GL_UNSIGNED_INT, g_xarrayelems );
// if( glState.stencilEnabled )
// pglDisable( GL_STENCIL_TEST );
pglDisableClientState( GL_VERTEX_ARRAY );
}
/*
@ -2293,7 +2444,7 @@ void _cdecl GL_StudioDrawShadow( void )
{
shadow_alpha = 1.0 - r_shadowalpha.value * 0.5f;
pglDisable( GL_TEXTURE_2D );
pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
// pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
pglEnable( GL_BLEND );
shadow_alpha2 = 1.0 - shadow_alpha;
@ -2303,16 +2454,16 @@ void _cdecl GL_StudioDrawShadow( void )
// depthmode = GL_LESS;
// else
depthmode = GL_GREATER;
pglDepthFunc( depthmode );
// pglDepthFunc( depthmode );
StudioDrawShadow();
R_StudioDrawPlanarShadow();
// if( flt_100DB994 == 0.0 || flt_107BA8A8 < 0.5 )
depthmode2 = GL_LEQUAL;
// else
// depthmode2 = GL_GEQUAL;
pglDepthFunc( depthmode2 );
// pglDepthFunc( depthmode2 );
pglEnable( GL_TEXTURE_2D );
pglDisable( GL_BLEND );
@ -2792,9 +2943,9 @@ static int R_StudioDrawModel( int flags )
R_DrawStudioModel
=================
*/
void R_DrawStudioModel( cl_entity_t *e )
void R_DrawStudioModelInternal( cl_entity_t *e, qboolean follow_entity )
{
int flags, result;
int i, flags, result;
if( RI.params & RP_ENVVIEW )
return;
@ -2825,6 +2976,34 @@ void R_DrawStudioModel( cl_entity_t *e )
result = pStudioDraw->StudioDrawPlayer( flags, &e->curstate );
else result = pStudioDraw->StudioDrawModel( flags );
}
if( !result || follow_entity ) return;
// NOTE: we must draw all followed entities
// immediately after drawing parent when cached bones is valid
for( i = 0; i < tr.num_child_entities; i++ )
{
if( CL_GetEntityByIndex( tr.child_entities[i]->curstate.aiment ) == e )
{
// copy the parent origin for right frustum culling
// FIXME: we really need to cull follow entities?
VectorCopy( e->origin, tr.child_entities[i]->origin );
RI.currententity = tr.child_entities[i];
RI.currentmodel = RI.currententity->model;
R_DrawStudioModelInternal( RI.currententity, true );
}
}
}
/*
=================
R_DrawStudioModel
=================
*/
void R_DrawStudioModel( cl_entity_t *e )
{
R_DrawStudioModelInternal( e, false );
}
/*
@ -2900,13 +3079,62 @@ static void R_StudioLoadTexture( model_t *mod, studiohdr_t *phdr, mstudiotexture
size_t size;
int flags = 0;
char texname[128], name[128];
texture_t *tx = NULL;
if( ptexture->flags & STUDIO_NF_TRANSPARENT )
flags |= (TF_CLAMP|TF_NOMIPMAP);
if( ptexture->flags & ( STUDIO_NF_NORMALMAP|STUDIO_NF_HEIGHTMAP ))
flags |= TF_NORMALMAP;
// store some textures for remapping
if( !Q_strnicmp( ptexture->name, "DM_Base", 7 ) || !Q_strnicmp( ptexture->name, "remap", 5 ))
{
int i, size;
char val[6];
byte *pixels;
i = mod->numtextures;
mod->textures = (texture_t **)Mem_Realloc( mod->mempool, mod->textures, ( i + 1 ) * sizeof( texture_t* ));
size = ptexture->width * ptexture->height + 768;
tx = Mem_Alloc( mod->mempool, sizeof( *tx ) + size );
mod->textures[i] = tx;
// parse ranges and store it
// HACKHACK: store ranges into anim_min, anim_max etc
if( !Q_strnicmp( ptexture->name, "DM_Base", 7 ))
{
Q_strncpy( tx->name, "DM_Base", sizeof( tx->name ));
tx->anim_min = PLATE_HUE_START; // topcolor start
tx->anim_max = PLATE_HUE_END; // topcolor end
// bottomcolor start always equal is (topcolor end + 1)
tx->anim_total = SUIT_HUE_END;// bottomcolor end
}
else
{
Q_strncpy( tx->name, "DM_User", sizeof( tx->name )); // custom remapped
Q_strncpy( val, ptexture->name + 7, 4 );
tx->anim_min = bound( 0, Q_atoi( val ), 255 ); // topcolor start
Q_strncpy( val, ptexture->name + 11, 4 );
tx->anim_max = bound( 0, Q_atoi( val ), 255 ); // topcolor end
// bottomcolor start always equal is (topcolor end + 1)
Q_strncpy( val, ptexture->name + 15, 4 );
tx->anim_total = bound( 0, Q_atoi( val ), 255 ); // bottomcolor end
}
tx->width = ptexture->width;
tx->height = ptexture->height;
// the pixels immediately follow the structures
pixels = (byte *)phdr + ptexture->index;
Q_memcpy( tx+1, pixels, size );
ptexture->flags |= STUDIO_NF_COLORMAP; // yes, this is colormap image
flags |= TF_FORCE_COLOR;
mod->numtextures++; // done
}
// NOTE: replace index with pointer to start of imagebuffer, ImageLib expected it
ptexture->index = (int)((byte *)phdr) + ptexture->index;
size = sizeof( mstudiotexture_t ) + ptexture->width * ptexture->height + 768;
@ -2923,6 +3151,8 @@ static void R_StudioLoadTexture( model_t *mod, studiohdr_t *phdr, mstudiotexture
}
else
{
// duplicate texnum for easy acess
if( tx ) tx->gl_texturenum = ptexture->index;
GL_SetTextureType( ptexture->index, TEX_STUDIO );
}
}
@ -2968,14 +3198,17 @@ studiohdr_t *R_StudioLoadHeader( model_t *mod, const void *buffer )
Mod_LoadStudioModel
=================
*/
void Mod_LoadStudioModel( model_t *mod, const void *buffer )
void Mod_LoadStudioModel( model_t *mod, const void *buffer, qboolean *loaded )
{
studiohdr_t *phdr;
if( loaded ) *loaded = false;
loadmodel->mempool = Mem_AllocPool( va( "^2%s^7", loadmodel->name ));
loadmodel->type = mod_studio;
phdr = R_StudioLoadHeader( mod, buffer );
if( !phdr ) return; // bad model
loadmodel->mempool = Mem_AllocPool( va("^2%s^7", loadmodel->name ));
#ifdef STUDIO_MERGE_TEXTURES
if( phdr->numtextures == 0 )
{
@ -3027,11 +3260,12 @@ void Mod_LoadStudioModel( model_t *mod, const void *buffer )
// setup bounding box
VectorCopy( phdr->bbmin, loadmodel->mins );
VectorCopy( phdr->bbmax, loadmodel->maxs );
loadmodel->type = mod_studio; // all done
loadmodel->numframes = R_StudioBodyVariations( loadmodel );
loadmodel->radius = RadiusFromBounds( loadmodel->mins, loadmodel->maxs );
loadmodel->flags = phdr->flags; // copy header flags
if( loaded ) *loaded = true;
}
/*

View File

@ -48,6 +48,6 @@ int Q_buildnum( void )
return b;
#else
return 1540;
return 1613;
#endif
}

View File

@ -609,6 +609,7 @@ Cmd_LookupCmds
void Cmd_LookupCmds( char *buffer, void *ptr, setpair_t callback )
{
cmd_function_t *cmd;
cmdalias_t *alias;
// nothing to process ?
if( !callback ) return;
@ -618,6 +619,10 @@ void Cmd_LookupCmds( char *buffer, void *ptr, setpair_t callback )
if( !buffer ) callback( cmd->name, (char *)cmd->function, cmd->desc, ptr );
else callback( cmd->name, (char *)cmd->function, buffer, ptr );
}
// lookup an aliases too
for( alias = cmd_alias; alias; alias = alias->next )
callback( alias->name, alias->value, buffer, ptr );
}
/*
@ -777,12 +782,18 @@ void Cmd_Unlink( int group )
cmd_function_t **prev;
int count = 0;
if( Cvar_VariableInteger( "host_gameloaded" ))
if( Cvar_VariableInteger( "host_gameloaded" ) && ( group & CMD_EXTDLL ))
{
Msg( "can't unlink cvars while game is loaded\n" );
return;
}
if( Cvar_VariableInteger( "host_clientloaded" ) && ( group & CMD_CLIENTDLL ))
{
Msg( "can't unlink cvars while client is loaded\n" );
return;
}
prev = &cmd_functions;
while( 1 )
{

View File

@ -76,7 +76,7 @@ typedef enum
#include "com_model.h"
#include "crtlib.h"
#define XASH_VERSION 0.85f // engine current version
#define XASH_VERSION 0.89f // engine current version
// PERFORMANCE INFO
#define MIN_FPS 15.0 // host minimum fps value for maxfps.

View File

@ -29,6 +29,7 @@ convar_t *con_fontsize;
#define COLOR_DEFAULT '7'
#define CON_HISTORY 64
#define MAX_DBG_NOTIFY 128
#define CON_MAXCMDS 4096 // auto-complete intermediate list
#define CON_TEXTSIZE 131072 // 128 kb buffer
@ -93,6 +94,7 @@ typedef struct
// chatfiled
field_t chat;
string chat_cmd; // can be overrieded by user
// console history
field_t historyLines[CON_HISTORY];
@ -103,14 +105,14 @@ typedef struct
qboolean draw_notify; // true if we have NXPrint message
// console auto-complete
field_t *completionField;
char *completionString;
string shortestMatch;
field_t *completionField; // con.input or dedicated server fake field-line
char *completionString;
char *cmds[CON_MAXCMDS];
int matchCount;
} console_t;
static console_t con;
static qboolean chat_team; // say_team is active
void Field_CharEvent( field_t *edit, int ch );
@ -185,8 +187,22 @@ Con_ClearTyping
*/
void Con_ClearTyping( void )
{
int i;
Con_ClearField( &con.input );
con.input.widthInChars = con.linewidth;
// free the old autocomplete list
for( i = 0; i < con.matchCount; i++ )
{
if( con.cmds[i] != NULL )
{
Mem_Free( con.cmds[i] );
con.cmds[i] = NULL;
}
}
con.matchCount = 0;
}
/*
@ -225,7 +241,10 @@ Con_MessageMode_f
*/
void Con_MessageMode_f( void )
{
chat_team = false;
if( Cmd_Argc() == 2 )
Q_strncpy( con.chat_cmd, Cmd_Argv( 1 ), sizeof( con.chat_cmd ));
else Q_strncpy( con.chat_cmd, "say", sizeof( con.chat_cmd ));
Key_SetKeyDest( key_message );
}
@ -236,34 +255,10 @@ Con_MessageMode2_f
*/
void Con_MessageMode2_f( void )
{
chat_team = true;
Q_strncpy( con.chat_cmd, "say_team", sizeof( con.chat_cmd ));
Key_SetKeyDest( key_message );
}
/*
================
Con_ToggleChat_f
================
*/
void Con_ToggleChat_f( void )
{
Con_ClearTyping ();
if( cls.key_dest == key_console )
{
if( Cvar_VariableInteger( "sv_background" ))
UI_SetActiveMenu( true );
else UI_SetActiveMenu( false );
}
else
{
UI_SetActiveMenu( false );
Key_SetKeyDest( key_console );
}
Con_ClearNotify();
}
/*
================
Con_ToggleConsole_f
@ -654,7 +649,6 @@ void Con_Init( void )
Cmd_AddCommand( "toggleconsole", Con_ToggleConsole_f, "opens or closes the console" );
Cmd_AddCommand( "con_color", Con_SetColor_f, "set a custom console color" );
Cmd_AddCommand( "clear", Con_Clear_f, "clear console history" );
Cmd_AddCommand( "togglechat", Con_ToggleChat_f, "toggle console chat" );
Cmd_AddCommand( "messagemode", Con_MessageMode_f, "enable message mode \"say\"" );
Cmd_AddCommand( "messagemode2", Con_MessageMode2_f, "enable message mode \"say_team\"" );
@ -885,32 +879,29 @@ static qboolean Cmd_CheckName( const char *name )
/*
===============
pfnFindMatches
Con_AddCommandToList
===============
*/
static void pfnFindMatches( const char *s, const char *unused1, const char *unused2, void *unused3 )
static void Con_AddCommandToList( const char *s, const char *unused1, const char *unused2, void *unused3 )
{
int i;
if( *s == '@' ) return; // never show system cvars or cmds
if( con.matchCount >= CON_MAXCMDS ) return; // list is full
if( Q_strnicmp( s, con.completionString, Q_strlen( con.completionString )))
return;
return; // no match
con.matchCount++;
con.cmds[con.matchCount++] = copystring( s );
}
if( con.matchCount == 1 )
{
Q_strncpy( con.shortestMatch, s, sizeof( con.shortestMatch ));
return;
}
// cut shortestMatch to the amount common with s
for( i = 0; s[i]; i++ )
{
if( Q_tolower( con.shortestMatch[i] ) != Q_tolower( s[i] ))
con.shortestMatch[i] = 0;
}
/*
=================
Con_SortCmds
=================
*/
static int Con_SortCmds( const char **arg1, const char **arg2 )
{
return Q_stricmp( *arg1, *arg2 );
}
/*
@ -918,7 +909,7 @@ static void pfnFindMatches( const char *s, const char *unused1, const char *unus
pfnPrintMatches
===============
*/
static void pfnPrintMatches( const char *s, const char *unused1, const char *m, void *unused2 )
static void Con_PrintMatches( const char *s, const char *unused1, const char *m, void *unused2 )
{
if( !Q_strnicmp( s, con.shortestMatch, Q_strlen( con.shortestMatch )))
{
@ -972,38 +963,54 @@ void Con_CompleteCommand( field_t *field )
field_t temp;
string filename;
autocomplete_list_t *list;
int i;
// setup the completion field
con.completionField = field;
// only look at the first token for completion purposes
Cmd_TokenizeString( con.completionField->buffer );
con.completionString = Cmd_Argv( 0 );
if( con.completionString[0] == '\\' || con.completionString[0] == '/' )
// skip backslash
while( *con.completionString && ( *con.completionString == '\\' || *con.completionString == '/' ))
con.completionString++;
con.matchCount = 0;
con.shortestMatch[0] = 0;
if( !Q_strlen( con.completionString ))
return;
Cmd_LookupCmds( NULL, NULL, pfnFindMatches );
Cvar_LookupVars( 0, NULL, NULL, pfnFindMatches );
// free the old autocomplete list
for( i = 0; i < con.matchCount; i++ )
{
if( con.cmds[i] != NULL )
{
Mem_Free( con.cmds[i] );
con.cmds[i] = NULL;
}
}
con.matchCount = 0;
con.shortestMatch[0] = 0;
// find matching commands and variables
Cmd_LookupCmds( NULL, NULL, Con_AddCommandToList );
Cvar_LookupVars( 0, NULL, NULL, Con_AddCommandToList );
if( !con.matchCount ) return; // no matches
if( con.matchCount == 0 ) return; // no matches
Q_memcpy( &temp, con.completionField, sizeof( field_t ));
if( Cmd_Argc() == 2 )
{
qboolean result = false;
qboolean result = false;
// autocomplete second arg
for( list = cmd_list; list->name; list++ )
{
if( Cmd_CheckName( list->name ))
{
result = list->func( Cmd_Argv(1), filename, MAX_STRING );
result = list->func( Cmd_Argv( 1 ), filename, MAX_STRING );
break;
}
}
@ -1018,24 +1025,44 @@ void Con_CompleteCommand( field_t *field )
if( con.matchCount == 1 )
{
Q_sprintf( con.completionField->buffer, "\\%s", con.shortestMatch );
if( Cmd_Argc() == 1 )
Q_strncat( con.completionField->buffer, " ", sizeof( con.completionField->buffer ));
Q_sprintf( con.completionField->buffer, "\\%s", con.cmds[0] );
if( Cmd_Argc() == 1 ) Q_strncat( con.completionField->buffer, " ", sizeof( con.completionField->buffer ));
else ConcatRemaining( temp.buffer, con.completionString );
con.completionField->cursor = Q_strlen( con.completionField->buffer );
return;
}
else
{
char *first, *last;
int len = 0;
// multiple matches, complete to shortest
Q_sprintf( con.completionField->buffer, "\\%s", con.shortestMatch );
con.completionField->cursor = Q_strlen( con.completionField->buffer );
ConcatRemaining( temp.buffer, con.completionString );
qsort( con.cmds, con.matchCount, sizeof( char* ), Con_SortCmds );
Msg( "]%s\n", con.completionField->buffer );
// find the number of matching characters between the first and
// the last element in the list and copy it
first = con.cmds[0];
last = con.cmds[con.matchCount-1];
// run through again, printing matches
Cmd_LookupCmds( NULL, NULL, pfnPrintMatches );
Cvar_LookupVars( 0, NULL, NULL, pfnPrintMatches );
while( *first && *last && Q_tolower( *first ) == Q_tolower( *last ))
{
first++;
last++;
con.shortestMatch[len] = con.cmds[0][len];
len++;
}
con.shortestMatch[len] = 0;
// multiple matches, complete to shortest
Q_sprintf( con.completionField->buffer, "\\%s", con.shortestMatch );
con.completionField->cursor = Q_strlen( con.completionField->buffer );
ConcatRemaining( temp.buffer, con.completionString );
Msg( "]%s\n", con.completionField->buffer );
// run through again, printing matches
Cmd_LookupCmds( NULL, NULL, Con_PrintMatches );
Cvar_LookupVars( 0, NULL, NULL, Con_PrintMatches );
}
}
/*
@ -1429,9 +1456,7 @@ void Key_Message( int key )
{
if( con.chat.buffer[0] && cls.state == ca_active )
{
if( chat_team ) Q_snprintf( buffer, sizeof( buffer ), "say_team \"%s\"\n", con.chat.buffer );
else Q_snprintf( buffer, sizeof( buffer ), "say \"%s\"\n", con.chat.buffer );
Q_snprintf( buffer, sizeof( buffer ), "%s \"%s\"\n", con.chat_cmd, con.chat.buffer );
Cbuf_AddText( buffer );
}
@ -1570,7 +1595,7 @@ void Con_DrawNotify( void )
if( cls.key_dest == key_message )
{
char buf[16];
string buf;
int len;
currentColor = 7;
@ -1578,8 +1603,11 @@ void Con_DrawNotify( void )
start = con.charWidths[' ']; // offset one space at left screen side
if( chat_team ) Q_strncpy( buf, "say_team: ", sizeof( buf ));
else Q_strncpy( buf, "say: ", sizeof( buf ));
// update chatline position from client.dll
if( clgame.dllFuncs.pfnChatInputPosition )
clgame.dllFuncs.pfnChatInputPosition( &start, &v );
Q_snprintf( buf, sizeof( buf ), "%s: ", con.chat_cmd );
Con_DrawStringLen( buf, &len, NULL );
Con_DrawString( start, v, buf, g_color_table[7] );

View File

@ -1191,6 +1191,12 @@ void Cvar_Unlink( void )
convar_t **prev;
int count = 0;
if( Cvar_VariableInteger( "host_clientloaded" ))
{
MsgDev( D_NOTE, "can't unlink cvars while client is loaded\n" );
return;
}
prev = &cvar_vars;
while( 1 )

View File

@ -32,6 +32,7 @@ sysinfo_t SI;
convar_t *host_serverstate;
convar_t *host_gameloaded;
convar_t *host_clientloaded;
convar_t *host_limitlocal;
convar_t *host_cheats;
convar_t *host_maxfps;
@ -688,6 +689,7 @@ int EXPORT Host_Main( const char *progname, int bChangeGame, pfnChangeGame func
host_framerate = Cvar_Get( "host_framerate", "0", 0, "locks frame timing to this value in seconds" );
host_serverstate = Cvar_Get( "host_serverstate", "0", CVAR_INIT, "displays current server state" );
host_gameloaded = Cvar_Get( "host_gameloaded", "0", CVAR_INIT, "inidcates a loaded game.dll" );
host_clientloaded = Cvar_Get( "host_clientloaded", "0", CVAR_INIT, "inidcates a loaded client.dll" );
host_limitlocal = Cvar_Get( "host_limitlocal", "0", 0, "apply cl_cmdrate and rate to loopback connection" );
con_gamemaps = Cvar_Get( "con_gamemaps", "1", CVAR_ARCHIVE, "when true show only maps in game folder" );

View File

@ -31,6 +31,12 @@ GNU General Public License for more details.
#define DVIS_PHS 1
#define ANIM_CYCLE 2
// remapping info
#define SUIT_HUE_START 192
#define SUIT_HUE_END 223
#define PLATE_HUE_START 160
#define PLATE_HUE_END 191
#define SURF_INFO( surf, mod ) ((mextrasurf_t *)mod->cache.data + (surf - mod->surfaces))
// model flags (stored in model_t->flags)

View File

@ -934,7 +934,7 @@ static void Mod_LoadSurfaces( const dlump_t *l )
if( !Q_strncmp( tex->name, "sky", 3 ))
out->flags |= (SURF_DRAWTILED|SURF_DRAWSKY);
if( tex->name[0] == '*' || tex->name[0] == '!' )
if(( tex->name[0] == '*' && Q_stricmp( tex->name, "*default" )) || tex->name[0] == '!' )
out->flags |= (SURF_DRAWTURB|SURF_DRAWTILED);
if( !Q_strnicmp( tex->name, "water", 5 ) || !Q_strnicmp( tex->name, "laser", 5 ))
@ -1521,13 +1521,15 @@ void Mod_UnloadBrushModel( model_t *mod )
Mod_LoadBrushModel
=================
*/
static void Mod_LoadBrushModel( model_t *mod, const void *buffer )
static void Mod_LoadBrushModel( model_t *mod, const void *buffer, qboolean *loaded )
{
int i, j;
dheader_t *header;
dmodel_t *bm;
if( loaded ) *loaded = false;
header = (dheader_t *)buffer;
loadmodel->type = mod_brush;
i = header->version;
switch( i )
@ -1544,7 +1546,6 @@ static void Mod_LoadBrushModel( model_t *mod, const void *buffer )
}
// will be merged later
loadmodel->type = mod_brush;
if( world.loading ) world.version = i;
bmodel_version = i; // share it
@ -1651,6 +1652,8 @@ static void Mod_LoadBrushModel( model_t *mod, const void *buffer )
mod = loadmodel;
}
}
if( loaded ) *loaded = true; // all done
}
/*
@ -1714,6 +1717,7 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
{
byte *buf;
char tempname[64];
qboolean loaded;
if( !mod )
{
@ -1749,20 +1753,20 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
switch( *(uint *)buf )
{
case IDSTUDIOHEADER:
Mod_LoadStudioModel( mod, buf );
Mod_LoadStudioModel( mod, buf, &loaded );
break;
case IDSPRITEHEADER:
Mod_LoadSpriteModel( mod, buf );
Mod_LoadSpriteModel( mod, buf, &loaded );
break;
case Q1BSP_VERSION:
case HLBSP_VERSION:
Mod_LoadBrushModel( mod, buf );
Mod_LoadBrushModel( mod, buf, &loaded );
break;
}
Mem_Free( buf );
if( mod->type == mod_bad )
if( !loaded )
{
Mod_FreeModel( mod );

Binary file not shown.

View File

@ -1,480 +0,0 @@
/*
snd_mp3.c - mp3 format loading and streaming
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 "soundlib.h"
/*
=======================================================================
LIBMAD DEFINITION
=======================================================================
*/
#define BUFFER_GUARD 8
#define BUFFER_MDLEN (511 + 2048 + BUFFER_GUARD)
#define BUFFER_SIZE 4096 // must be large than BUFFER_MDLEN
#define MPEG_F_FRACBITS 28
#define MPEG_F( x ) ((int)( x##L ))
#define MPEG_F_ONE MPEG_F( 0x10000000 )
enum
{
MP3_ERROR_NONE = 0x0000, // no error
MP3_ERROR_BUFLEN = 0x0001, // input buffer too small (or EOF)
MP3_ERROR_BUFPTR = 0x0002, // invalid (null) buffer pointer
MP3_ERROR_NOMEM = 0x0031, // not enough memory
MP3_ERROR_LOSTSYNC = 0x0101, // lost synchronization
MP3_ERROR_BADLAYER = 0x0102, // reserved header layer value
MP3_ERROR_BADBITRATE = 0x0103, // forbidden bitrate value
MP3_ERROR_BADSAMPLERATE = 0x0104, // reserved sample frequency value
MP3_ERROR_BADEMPHASIS = 0x0105, // reserved emphasis value
MP3_ERROR_BADCRC = 0x0201, // CRC check failed
MP3_ERROR_BADBITALLOC = 0x0211, // forbidden bit allocation value
MP3_ERROR_BADSCALEFACTOR = 0x0221, // bad scalefactor index
MP3_ERROR_BADMODE = 0x0222, // bad bitrate/mode combination
MP3_ERROR_BADFRAMELEN = 0x0231, // bad frame length
MP3_ERROR_BADBIGVALUES = 0x0232, // bad big_values count
MP3_ERROR_BADBLOCKTYPE = 0x0233, // reserved block_type
MP3_ERROR_BADSCFSI = 0x0234, // bad scalefactor selection info
MP3_ERROR_BADDATAPTR = 0x0235, // bad main_data_begin pointer
MP3_ERROR_BADPART3LEN = 0x0236, // bad audio data length
MP3_ERROR_BADHUFFTABLE = 0x0237, // bad Huffman table select
MP3_ERROR_BADHUFFDATA = 0x0238, // Huffman data overrun
MP3_ERROR_BADSTEREO = 0x0239 // incompatible block_type for JS
};
enum
{
MODE_SINGLE_CHANNEL = 0, // single channel
MODE_DUAL_CHANNEL, // dual channel
MODE_JOINT_STEREO, // joint (MS/intensity) stereo
MODE_STEREO // normal LR stereo
};
typedef struct
{
uint samplerate; // sampling frequency (Hz)
word channels; // number of channels
word length; // number of samples per channel
int samples[2][1152]; // PCM output samples [ch][sample]
} pcm_t;
typedef struct
{
int filter[2][2][2][16][8]; // polyphase filterbank outputs
uint phase; // current processing phase
pcm_t pcm; // PCM output
} synth_t;
typedef struct
{
const byte *byte;
word cache;
word left;
} bitptr_t;
typedef struct
{
long seconds; // whole seconds
dword fraction; // 1 / TIMER_RESOLUTION seconds
} mp3_timer_t;
typedef struct
{
int layer; // audio layer (1, 2, or 3)
int mode; // channel mode (see above)
int mode_extension; // additional mode info
int emphasis; // de-emphasis to use (see above)
dword bitrate; // stream bitrate (bps)
uint samplerate; // sampling frequency (Hz)
word crc_check; // frame CRC accumulator
word crc_target; // final target CRC checksum
int flags; // flags (see below)
int private_bits; // private bits (see below)
mp3_timer_t duration; // audio playing time of frame
} mp3_header_t;
typedef struct
{
mp3_header_t header; // MPEG audio header
int options; // decoding options (from stream)
int sbsample[2][36][32]; // synthesis subband filter samples
int (*overlap)[2][32][18]; // Layer III block overlap data
} mp3_frame_t;
typedef struct
{
const byte *buffer; // input bitstream buffer
const byte *bufend; // end of buffer
dword skiplen; // bytes to skip before next frame
int sync; // stream sync found
dword freerate; // free bitrate (fixed)
const byte *this_frame; // start of current frame
const byte *next_frame; // start of next frame
bitptr_t ptr; // current processing bit pointer
bitptr_t anc_ptr; // ancillary bits pointer
uint anc_bitlen; // number of ancillary bits
byte (*data)[BUFFER_MDLEN];
// Layer III data()
uint md_len; // bytes in data
int options; // decoding options
int error; // error code
} mp3_stream_t;
typedef struct
{
synth_t synth;
mp3_stream_t stream;
mp3_frame_t frame;
int buffer_length; // for reading
byte buffer[BUFFER_SIZE];// frame buffer
} mpegfile_t;
// libmad exports
extern void mad_synth_init( synth_t* );
extern void mad_synth_frame( synth_t*, const mp3_frame_t* );
extern void mad_stream_init( mp3_stream_t* );
extern void mad_stream_buffer( mp3_stream_t*, const byte*, dword );
extern void mad_stream_finish( mp3_stream_t* );
extern void mad_frame_init( mp3_frame_t* );
extern int mad_frame_decode( mp3_frame_t*, mp3_stream_t* );
extern void mad_frame_finish( mp3_frame_t* );
/*
=================================================================
MPEG decompression
=================================================================
*/
static int mpeg_read( file_t *file, mpegfile_t *mpeg )
{
int ret;
while( 1 )
{
ret = FS_Read( file, &mpeg->buffer[mpeg->buffer_length], BUFFER_SIZE - mpeg->buffer_length );
// no more bytes are left
if( ret <= 0 ) break;
mpeg->buffer_length += ret;
while( 1 )
{
mad_stream_buffer( &mpeg->stream, mpeg->buffer, mpeg->buffer_length );
ret = mad_frame_decode( &mpeg->frame, &mpeg->stream );
if( mpeg->stream.next_frame )
{
int length;
length = mpeg->buffer + mpeg->buffer_length - mpeg->stream.next_frame;
memmove( mpeg->buffer, mpeg->stream.next_frame, length );
mpeg->buffer_length = length;
}
if( !ret ) return 1;
if( mpeg->stream.error == MP3_ERROR_BUFLEN )
break;
}
}
return 0;
}
static int mpeg_read_mem( const byte *buffer, int *pos, size_t filesize, mpegfile_t *mpeg )
{
int ret, readSize;
while( 1 )
{
readSize = ( BUFFER_SIZE - mpeg->buffer_length );
if(( *pos + readSize ) > filesize )
readSize = ( filesize - *pos );
Q_memcpy( &mpeg->buffer[mpeg->buffer_length], buffer + *pos, readSize );
// no more bytes are left
if( readSize <= 0 ) break;
*pos += readSize;
mpeg->buffer_length += readSize;
while( 1 )
{
mad_stream_buffer( &mpeg->stream, mpeg->buffer, mpeg->buffer_length );
ret = mad_frame_decode( &mpeg->frame, &mpeg->stream );
if( mpeg->stream.next_frame )
{
int length;
length = mpeg->buffer + mpeg->buffer_length - mpeg->stream.next_frame;
memmove( mpeg->buffer, mpeg->stream.next_frame, length );
mpeg->buffer_length = length;
}
if( !ret ) return 1;
if( mpeg->stream.error == MP3_ERROR_BUFLEN )
break;
}
}
return 0;
}
static int mpeg_scale( int sample )
{
sample += (1 << ( MPEG_F_FRACBITS - 16 ));
if( sample >= MPEG_F_ONE ) sample = MPEG_F_ONE - 1;
else if( sample < -MPEG_F_ONE ) sample = -MPEG_F_ONE;
return sample >> ( MPEG_F_FRACBITS + 1 - 16 );
}
static int mpeg_size( mp3_frame_t *frame, long bytes )
{
return bytes * 8 / frame->header.bitrate * sound.channels * sound.rate * sound.width;
}
/*
=================================================================
MPEG decompression
=================================================================
*/
qboolean Sound_LoadMPG( const char *name, const byte *buffer, size_t filesize )
{
mpegfile_t mpeg;
size_t pos = 0;
size_t bytesWrite = 0;
// load the file
if( !buffer || filesize <= 0 )
return false;
Q_memset( &mpeg, 0, sizeof( mpeg ));
mad_synth_init( &mpeg.synth );
mad_stream_init( &mpeg.stream );
mad_frame_init( &mpeg.frame );
if( mpeg_read_mem( buffer, &pos, filesize, &mpeg ) == 0 )
{
MsgDev( D_ERROR, "Sound_LoadMPG: (%s) is probably corrupted\n", name );
mad_stream_finish( &mpeg.stream );
mad_frame_finish( &mpeg.frame );
return false;
}
sound.channels = ( mpeg.frame.header.mode == MODE_SINGLE_CHANNEL ) ? 1 : 2;
sound.rate = mpeg.frame.header.samplerate;
sound.width = 2; // always 16-bit PCM
sound.loopstart = -1;
sound.size = mpeg_size( &mpeg.frame, filesize );
if( !sound.size )
{
// bad ogg file
MsgDev( D_ERROR, "Sound_LoadMPG: (%s) is probably corrupted\n", name );
mad_stream_finish( &mpeg.stream );
mad_frame_finish( &mpeg.frame );
return false;
}
sound.type = WF_PCMDATA;
sound.wav = (byte *)Mem_Alloc( host.soundpool, sound.size );
// decompress mpg into pcm wav format
while( bytesWrite < sound.size )
{
word *data;
int i;
mad_synth_frame( &mpeg.synth, &mpeg.frame );
data = (short *)(sound.wav + bytesWrite);
for( i = 0; i < mpeg.synth.pcm.length; i++ )
{
if( sound.channels == 2 )
{
*data++ = mpeg_scale( mpeg.synth.pcm.samples[0][i] );
*data++ = mpeg_scale( mpeg.synth.pcm.samples[1][i] );
}
else
{
*data++ = mpeg_scale( mpeg.synth.pcm.samples[0][i] );
}
bytesWrite += ( sound.width * sound.channels );
if( bytesWrite >= sound.size ) break;
}
if( !mpeg_read_mem( buffer, &pos, filesize, &mpeg ))
break;
}
sound.samples = bytesWrite / ( sound.width * sound.channels );
mad_stream_finish( &mpeg.stream );
mad_frame_finish( &mpeg.frame );
return true;
}
/*
=================
Stream_OpenMPG
=================
*/
stream_t *Stream_OpenMPG( const char *filename )
{
mpegfile_t *mpegFile;
stream_t *stream;
file_t *file;
file = FS_Open( filename, "rb", false );
if( !file ) return NULL;
// at this point we have valid stream
stream = Mem_Alloc( host.soundpool, sizeof( stream_t ));
stream->file = file;
mpegFile = Mem_Alloc( host.soundpool, sizeof( mpegfile_t ));
mad_synth_init( &mpegFile->synth );
mad_stream_init( &mpegFile->stream );
mad_frame_init( &mpegFile->frame );
if( mpeg_read( file, mpegFile ) == 0 )
{
MsgDev( D_ERROR, "Stream_OpenMPG: couldn't open %s\n", filename );
mad_stream_finish( &mpegFile->stream );
mad_frame_finish( &mpegFile->frame );
Mem_Free( mpegFile );
Mem_Free( stream );
FS_Close( file );
return NULL;
}
stream->pos = 0; // how many samples left from previous frame
stream->channels = ( mpegFile->frame.header.mode == MODE_SINGLE_CHANNEL ) ? 1 : 2;
stream->rate = mpegFile->frame.header.samplerate;
stream->width = 2; // always 16 bit
stream->ptr = mpegFile;
stream->type = WF_MPGDATA;
// g-cont: there is a stupid way...
if( stream->rate > 44100 )
{
mpegFile->stream.options = 0x0002;
stream->rate /= 2;
}
return stream;
}
/*
=================
Stream_ReadMPG
assume stream is valid
=================
*/
long Stream_ReadMPG( stream_t *stream, long bytes, void *buffer )
{
// buffer handling
int bytesRead = 0;
mpegfile_t *mpg;
mpg = (mpegfile_t *)stream->ptr;
ASSERT( mpg != NULL );
while( 1 )
{
pcm_t *wav;
word *data;
int i;
if( !stream->pos )
{
// if there are no bytes remainig so we can synth new frame
mad_synth_frame( &mpg->synth, &mpg->frame );
}
wav = &mpg->synth.pcm;
data = (word *)((byte *)buffer + bytesRead);
for( i = stream->pos; i < wav->length; i++ )
{
if( stream->channels == 2 )
{
*data++ = mpeg_scale( wav->samples[0][i] );
*data++ = mpeg_scale( wav->samples[1][i] );
}
else
{
*data++ = mpeg_scale( wav->samples[0][i] );
}
bytesRead += ( stream->width * stream->channels );
if( bytesRead >= bytes )
{
// continue from this sample on a next call
stream->pos = i;
return bytesRead;
}
}
stream->pos = 0; // no bytes remainig
if( !mpeg_read( stream->file, mpg )) break;
}
return 0;
}
/*
=================
Stream_FreeMPG
assume stream is valid
=================
*/
void Stream_FreeMPG( stream_t *stream )
{
if( stream->ptr )
{
mpegfile_t *mpg;
mpg = (mpegfile_t *)stream->ptr;
mad_stream_finish( &mpg->stream );
mad_frame_finish( &mpg->frame );
Mem_Free( stream->ptr );
}
if( stream->file )
{
FS_Close( stream->file );
}
Mem_Free( stream );
}

View File

@ -43,7 +43,7 @@ RSC=rc.exe
# PROP Ignore_Export_Lib 1
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
# ADD CPP /nologo /MD /W3 /GX /O2 /Oy /I "./" /I "common" /I "common/imagelib" /I "common/soundlib" /I "server" /I "client" /I "client/vgui" /I "../common" /I "../game_shared" /I "../pm_shared" /I "../utils/vgui/include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
# ADD CPP /nologo /MD /W3 /GX /O2 /I "./" /I "common" /I "common/imagelib" /I "common/soundlib" /I "server" /I "client" /I "client/vgui" /I "../common" /I "../game_shared" /I "../pm_shared" /I "../utils/vgui/include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
# SUBTRACT CPP /Fr /YX
# ADD BASE MTL /nologo /D "NDEBUG" /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
@ -154,6 +154,10 @@ SOURCE=.\client\cl_pmove.c
# End Source File
# Begin Source File
SOURCE=.\client\cl_remap.c
# End Source File
# Begin Source File
SOURCE=.\client\cl_scrn.c
# End Source File
# Begin Source File

View File

@ -773,9 +773,9 @@ Writes all update values to a bitbuf
*/
void SV_FullClientUpdate( sv_client_t *cl, sizebuf_t *msg )
{
int i;
char info[MAX_INFO_STRING];
int i;
i = cl - svs.clients;
BF_WriteByte( msg, svc_updateuserinfo );
@ -1635,6 +1635,7 @@ void SV_UserinfoChanged( sv_client_t *cl, const char *userinfo )
{
if( current == cl || current->state != cs_spawned )
continue;
if( !Q_stricmp( current->name, val ))
break;
}

View File

@ -775,7 +775,7 @@ void SV_InitOperatorCommands( void )
Cmd_AddCommand( "map", SV_Map_f, "start new level" );
Cmd_AddCommand( "newgame", SV_Newgame_f, "begin new game" );
Cmd_AddCommand( "endgame", SV_Endgame_f, "end current game" );
Cmd_AddCommand( "killgame", SV_Endgame_f, "end current game" );
Cmd_AddCommand( "hazardcourse", SV_HazardCourse_f, "starting a Hazard Course" );
Cmd_AddCommand( "changelevel", SV_ChangeLevel_f, "changing level" );
Cmd_AddCommand( "restart", SV_Restart_f, "restarting current level" );

View File

@ -307,7 +307,7 @@ typedef struct
} mstudiobodyparts_t;
// skin info
typedef struct
typedef struct mstudiotex_s
{
char name[64];
int flags;

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -167,8 +167,8 @@ static void UI_PlayerSetup_SetConfig( void )
{
CVAR_SET_STRING( "name", uiPlayerSetup.name.buffer );
CVAR_SET_STRING( "model", uiPlayerSetup.currentModel );
CVAR_SET_FLOAT( "topcolor", uiPlayerSetup.topColor.curValue * 255 );
CVAR_SET_FLOAT( "bottomcolor", uiPlayerSetup.bottomColor.curValue * 255 );
CVAR_SET_FLOAT( "topcolor", (int)(uiPlayerSetup.topColor.curValue * 255 ));
CVAR_SET_FLOAT( "bottomcolor", (int)(uiPlayerSetup.bottomColor.curValue * 255 ));
CVAR_SET_FLOAT( "cl_himodels", uiPlayerSetup.hiModels.enabled );
CVAR_SET_FLOAT( "spectator", uiPlayerSetup.spectator.enabled );
}
@ -198,6 +198,8 @@ static void UI_PlayerSetup_UpdateConfig( void )
CVAR_SET_STRING( "model", uiPlayerSetup.currentModel );
CVAR_SET_FLOAT( "cl_himodels", uiPlayerSetup.hiModels.enabled );
CVAR_SET_FLOAT( "spectator", uiPlayerSetup.spectator.enabled );
CVAR_SET_FLOAT( "topcolor", (int)(uiPlayerSetup.topColor.curValue * 255 ));
CVAR_SET_FLOAT( "bottomcolor", (int)(uiPlayerSetup.bottomColor.curValue * 255 ));
// IMPORTANT: always set default model becuase we need to have something valid here
// if you wish draw your playermodel as normal studiomodel please change "models/player.mdl" to path
@ -367,8 +369,9 @@ static void UI_PlayerSetup_Init( void )
uiPlayerSetup.topColor.generic.type = QMTYPE_SLIDER;
uiPlayerSetup.topColor.generic.flags = QMF_PULSEIFFOCUS|QMF_DROPSHADOW;
uiPlayerSetup.topColor.generic.name = "Top color";
uiPlayerSetup.topColor.generic.x = 350;
uiPlayerSetup.topColor.generic.x = 250;
uiPlayerSetup.topColor.generic.y = 550;
uiPlayerSetup.topColor.generic.width = 300;
uiPlayerSetup.topColor.generic.callback = UI_PlayerSetup_Callback;
uiPlayerSetup.topColor.generic.statusText = "Set a player model top color";
uiPlayerSetup.topColor.minValue = 0.0;
@ -379,8 +382,9 @@ static void UI_PlayerSetup_Init( void )
uiPlayerSetup.bottomColor.generic.type = QMTYPE_SLIDER;
uiPlayerSetup.bottomColor.generic.flags = QMF_PULSEIFFOCUS|QMF_DROPSHADOW;
uiPlayerSetup.bottomColor.generic.name = "Bottom color";
uiPlayerSetup.bottomColor.generic.x = 350;
uiPlayerSetup.bottomColor.generic.x = 250;
uiPlayerSetup.bottomColor.generic.y = 620;
uiPlayerSetup.bottomColor.generic.width = 300;
uiPlayerSetup.bottomColor.generic.callback = UI_PlayerSetup_Callback;
uiPlayerSetup.bottomColor.generic.statusText = "Set a player model bottom color";
uiPlayerSetup.bottomColor.minValue = 0.0;

View File

@ -611,13 +611,13 @@ void UI_ScrollList_Draw( menuScrollList_s *sl )
if(((downY - upY - arrowHeight) - (((sl->numItems-1)*sl->generic.charHeight)/2)) < 2)
{
sl->scrollBarHeight = (downY - upY - arrowHeight) - (step*(sl->numItems-1));
sl->scrollBarHeight = (downY - upY - arrowHeight) - (step * (sl->numItems-1));
sl->scrollBarY = upY + arrowHeight + (step*sl->curItem);
}
else
{
sl->scrollBarHeight = downY - upY - arrowHeight - (((sl->numItems-1)*sl->generic.charHeight)/2);
sl->scrollBarY = upY + arrowHeight + (((sl->curItem)*sl->generic.charHeight)/2);
sl->scrollBarHeight = downY - upY - arrowHeight - (((sl->numItems-1) * sl->generic.charHeight) / 2);
sl->scrollBarY = upY + arrowHeight + (((sl->curItem) * sl->generic.charHeight)/2);
}
if( sl->scrollBarSliding )
@ -714,6 +714,7 @@ void UI_ScrollList_Draw( menuScrollList_s *sl )
w = sl->generic.width2;
h = sl->generic.charHeight;
y = sl->generic.y2 + sl->generic.charHeight;
for( i = sl->topItem; i < sl->topItem + sl->numRows; i++, y += sl->generic.charHeight )
{
if( !sl->itemNames[i] )

View File

@ -10,6 +10,7 @@ if not exist D:\Xash3D\src_main\xash_sdk\common/ mkdir D:\Xash3D\src_main\xash_s
if not exist D:\Xash3D\src_main\xash_sdk\mainui/ mkdir D:\Xash3D\src_main\xash_sdk\mainui\
if not exist D:\Xash3D\src_main\xash_sdk\mainui\legacy/ mkdir D:\Xash3D\src_main\xash_sdk\mainui\legacy
if not exist D:\Xash3D\src_main\xash_sdk\utils/ mkdir D:\Xash3D\src_main\xash_sdk\utils\
if not exist D:\Xash3D\src_main\xash_sdk\utils\makefont/ mkdir D:\Xash3D\src_main\xash_sdk\utils\makefont
if not exist D:\Xash3D\src_main\xash_sdk\utils\vgui/ mkdir D:\Xash3D\src_main\xash_sdk\utils\vgui
if not exist D:\Xash3D\src_main\xash_sdk\utils\vgui\include/ mkdir D:\Xash3D\src_main\xash_sdk\utils\vgui\include
if not exist D:\Xash3D\src_main\xash_sdk\utils\vgui\lib/ mkdir D:\Xash3D\src_main\xash_sdk\utils\vgui\lib
@ -30,6 +31,7 @@ if not exist D:\Xash3D\src_main\xash_sdk\pm_shared/ mkdir D:\Xash3D\src_main\xas
@copy /Y cl_dll\hl\*.* xash_sdk\cl_dll\hl\*.*
@copy /Y dlls\*.* xash_sdk\dlls\*.*
@copy /Y dlls\wpn_shared\*.* xash_sdk\dlls\wpn_shared\*.*
@copy /Y utils\makefont\*.* xash_sdk\utils\makefont\*.*
@copy /Y utils\vgui\include\*.* xash_sdk\utils\vgui\include\*.*
@copy /Y utils\vgui\lib\win32_vc6\*.* xash_sdk\utils\vgui\lib\win32_vc6\*.*
@copy /Y game_shared\*.* xash_sdk\game_shared\*.*

View File

@ -0,0 +1,2 @@
makefont.exe -font "Arial" fonts.wad
pause

BIN
utils/makefont/makefont.exe Normal file

Binary file not shown.

View File

@ -17,6 +17,7 @@ xash_sdk\pm_shared\
xash_sdk\mainui\
xash_dsk\mainui\legacy
xash_sdk\utils\
xash_sdk\makefont\
xash_sdk\utils\vgui\
xash_sdk\utils\vgui\include\
xash_sdk\utils\vgui\lib\win32_vc6\