23 Jul 2011
This commit is contained in:
parent
dc5dc9f653
commit
faabf8b33d
|
@ -31,6 +31,7 @@ pm_shared\
|
|||
mainui\
|
||||
mainui\legacy
|
||||
utils\
|
||||
utils\makefont\
|
||||
utils\vgui\
|
||||
utils\vgui\include\
|
||||
utils\vgui\lib\win32_vc6\
|
|
@ -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
|
||||
|
||||
|
|
12
dlls/hl.plg
12
dlls/hl.plg
|
@ -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...
|
||||
|
|
|
@ -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 ))
|
||||
|
|
|
@ -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" );
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
//
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 ))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -48,6 +48,6 @@ int Q_buildnum( void )
|
|||
|
||||
return b;
|
||||
#else
|
||||
return 1540;
|
||||
return 1613;
|
||||
#endif
|
||||
}
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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] );
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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" );
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
@ -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 );
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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" );
|
||||
|
|
|
@ -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.
2811
mainui/images.h
2811
mainui/images.h
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||
|
|
|
@ -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] )
|
||||
|
|
|
@ -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\*.*
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
makefont.exe -font "Arial" fonts.wad
|
||||
pause
|
Binary file not shown.
|
@ -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\
|
Reference in New Issue