2004-08-23 00:15:46 +00:00
|
|
|
/*
|
|
|
|
Copyright (C) 1996-1997 Id Software, Inc.
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License
|
|
|
|
as published by the Free Software Foundation; either version 2
|
|
|
|
of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "quakedef.h"
|
2009-11-04 21:16:50 +00:00
|
|
|
#include "glquake.h"
|
2004-08-23 00:15:46 +00:00
|
|
|
|
2009-04-06 00:34:32 +00:00
|
|
|
cvar_t baseskin = SCVAR("baseskin", "");
|
2006-02-11 02:09:43 +00:00
|
|
|
cvar_t noskins = SCVAR("noskins", "0");
|
2004-08-23 00:15:46 +00:00
|
|
|
|
2004-12-29 03:24:21 +00:00
|
|
|
extern cvar_t cl_teamskin;
|
|
|
|
extern cvar_t cl_enemyskin;
|
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
extern cvar_t r_fb_models;
|
|
|
|
|
|
|
|
char allskins[128];
|
|
|
|
#define MAX_CACHED_SKINS 128
|
|
|
|
skin_t skins[MAX_CACHED_SKINS];
|
|
|
|
int numskins;
|
|
|
|
|
2004-12-29 03:24:21 +00:00
|
|
|
//returns the name
|
|
|
|
char *Skin_FindName (player_info_t *sc)
|
|
|
|
{
|
|
|
|
int tracknum;
|
|
|
|
char *s;
|
|
|
|
static char name[MAX_OSPATH];
|
|
|
|
|
|
|
|
char *skinforcing_team;
|
|
|
|
|
|
|
|
if (allskins[0])
|
|
|
|
{
|
|
|
|
Q_strncpyz(name, allskins, sizeof(name));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
s = Info_ValueForKey(sc->userinfo, "skin");
|
|
|
|
if (s && s[0])
|
|
|
|
Q_strncpyz(name, s, sizeof(name));
|
|
|
|
else
|
|
|
|
Q_strncpyz(name, baseskin.string, sizeof(name));
|
|
|
|
}
|
|
|
|
|
2007-11-03 15:09:12 +00:00
|
|
|
if (cl.spectator && (tracknum = Cam_TrackNum(0)) != -1)
|
2004-12-29 03:24:21 +00:00
|
|
|
skinforcing_team = cl.players[tracknum].team;
|
|
|
|
else if (cl.spectator)
|
|
|
|
skinforcing_team = "spec";
|
|
|
|
else
|
|
|
|
skinforcing_team = cl.players[cl.playernum[0]].team;
|
|
|
|
|
|
|
|
//Don't force skins in splitscreen (it's probable that the new skin would be wrong).
|
|
|
|
//Don't force skins in TF (where skins are forced on a class basis by the mod).
|
|
|
|
//Don't force skins on servers that have it disabled.
|
|
|
|
if (cl.splitclients<2 && !cl.teamfortress && !(cl.fpd & FPD_NO_FORCE_SKIN))
|
|
|
|
{
|
|
|
|
char *skinname = NULL;
|
2005-01-05 08:00:20 +00:00
|
|
|
// player_state_t *state;
|
2004-12-29 03:24:21 +00:00
|
|
|
qboolean teammate;
|
|
|
|
|
|
|
|
teammate = (cl.teamplay && !strcmp(sc->team, skinforcing_team)) ? true : false;
|
|
|
|
/*
|
|
|
|
if (!cl.validsequence)
|
|
|
|
goto nopowerups;
|
|
|
|
|
|
|
|
state = cl.frames[cl.parsecount & UPDATE_MASK].playerstate + (sc - cl.players);
|
|
|
|
|
|
|
|
if (state->messagenum != cl.parsecount)
|
|
|
|
goto nopowerups;
|
|
|
|
|
|
|
|
if ((state->effects & (EF_BLUE | EF_RED)) == (EF_BLUE | EF_RED))
|
|
|
|
skinname = teammate ? cl_teambothskin.string : cl_enemybothskin.string;
|
|
|
|
else if (state->effects & EF_BLUE)
|
|
|
|
skinname = teammate ? cl_teamquadskin.string : cl_enemyquadskin.string;
|
|
|
|
else if (state->effects & EF_RED)
|
|
|
|
skinname = teammate ? cl_teampentskin.string : cl_enemypentskin.string;
|
|
|
|
|
|
|
|
nopowerups:
|
|
|
|
*/
|
|
|
|
if (!skinname || !skinname[0])
|
|
|
|
skinname = teammate ? cl_teamskin.string : cl_enemyskin.string;
|
2008-06-05 07:45:34 +00:00
|
|
|
|
|
|
|
//per-player skin forcing
|
|
|
|
if (teammate && sc->colourised && *sc->colourised->skin)
|
|
|
|
skinname = sc->colourised->skin;
|
|
|
|
|
2004-12-29 03:24:21 +00:00
|
|
|
if (skinname[0] && !strchr(skinname, '/')) // a '/' in a skin name is deemed as a model name, so we ignore it.
|
|
|
|
Q_strncpyz(name, skinname, sizeof(name));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strstr(name, "..") || *name == '.')
|
|
|
|
Q_strncpyz(name, baseskin.string, sizeof(name));
|
|
|
|
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
/*
|
|
|
|
================
|
|
|
|
Skin_Find
|
|
|
|
|
|
|
|
Determines the best skin for the given scoreboard
|
|
|
|
slot, and sets scoreboard->skin
|
|
|
|
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
void Skin_Find (player_info_t *sc)
|
|
|
|
{
|
|
|
|
skin_t *skin;
|
|
|
|
int i;
|
2004-11-27 08:16:25 +00:00
|
|
|
char name[128], *s, *mn;
|
|
|
|
model_t *model;
|
|
|
|
|
|
|
|
mn = Info_ValueForKey (sc->userinfo, "model");
|
2004-12-09 23:36:54 +00:00
|
|
|
while((s = strchr(mn, '/')))
|
2004-11-27 08:16:25 +00:00
|
|
|
*mn = '\0';
|
2004-08-23 00:15:46 +00:00
|
|
|
|
|
|
|
if (allskins[0])
|
2004-11-27 08:16:25 +00:00
|
|
|
s = allskins;
|
2004-08-23 00:15:46 +00:00
|
|
|
else
|
|
|
|
s = Info_ValueForKey (sc->userinfo, "skin");
|
2004-11-27 08:16:25 +00:00
|
|
|
|
|
|
|
if (strstr (mn, "..") || *mn == '.')
|
2004-12-22 18:58:54 +00:00
|
|
|
mn = "";
|
2004-11-27 08:16:25 +00:00
|
|
|
|
2004-12-22 18:58:54 +00:00
|
|
|
if (!*s)
|
|
|
|
s = baseskin.string;
|
|
|
|
if (!*s)
|
|
|
|
s = "default";
|
|
|
|
|
|
|
|
if (*mn)
|
|
|
|
{
|
|
|
|
mn = va("%s/%s", mn, s);
|
2006-03-11 03:12:10 +00:00
|
|
|
COM_StripExtension (mn, name, sizeof(name));
|
2004-12-22 18:58:54 +00:00
|
|
|
}
|
|
|
|
else
|
2006-03-11 03:12:10 +00:00
|
|
|
{
|
|
|
|
s = Skin_FindName(sc);
|
|
|
|
COM_StripExtension (s, name, sizeof(name));
|
|
|
|
}
|
2004-11-27 08:16:25 +00:00
|
|
|
|
|
|
|
s = strchr(name, '/');
|
|
|
|
if (s)
|
|
|
|
{
|
|
|
|
*s = '\0';
|
2005-04-16 16:21:27 +00:00
|
|
|
#ifdef Q2CLIENT
|
2005-05-26 12:55:34 +00:00
|
|
|
if (cls.protocol == CP_QUAKE2)
|
2013-03-12 23:13:39 +00:00
|
|
|
model = Mod_ForName(va("players/%s/tris.md2", name), false);
|
2005-03-20 02:57:11 +00:00
|
|
|
else
|
2005-04-16 16:21:27 +00:00
|
|
|
#endif
|
2008-11-09 22:29:28 +00:00
|
|
|
model = NULL;//Mod_ForName(va("models/players/%s.mdl", name), false);
|
|
|
|
if (model && model->type == mod_dummy)
|
2004-11-27 08:16:25 +00:00
|
|
|
model = NULL;
|
|
|
|
*s = '/';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
model = NULL;
|
2004-08-23 00:15:46 +00:00
|
|
|
|
2004-11-27 08:16:25 +00:00
|
|
|
sc->model = model;
|
2004-08-23 00:15:46 +00:00
|
|
|
|
|
|
|
for (i=0 ; i<numskins ; i++)
|
|
|
|
{
|
|
|
|
if (!strcmp (name, skins[i].name))
|
|
|
|
{
|
|
|
|
sc->skin = &skins[i];
|
2006-02-22 23:43:59 +00:00
|
|
|
if (cls.protocol == CP_QUAKE2)
|
|
|
|
Skin_Cache32 (sc->skin);
|
|
|
|
else
|
|
|
|
Skin_Cache8 (sc->skin);
|
2004-08-23 00:15:46 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (numskins == MAX_CACHED_SKINS)
|
|
|
|
{ // ran out of spots, so flush everything
|
|
|
|
Skin_Skins_f ();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
skin = &skins[numskins];
|
|
|
|
sc->skin = skin;
|
|
|
|
numskins++;
|
|
|
|
|
|
|
|
memset (skin, 0, sizeof(*skin));
|
|
|
|
Q_strncpyz(skin->name, name, sizeof(skin->name));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
==========
|
|
|
|
Skin_Cache
|
|
|
|
|
|
|
|
Returns a pointer to the skin bitmap, or NULL to use the default
|
|
|
|
==========
|
|
|
|
*/
|
|
|
|
qbyte *Skin_Cache8 (skin_t *skin)
|
|
|
|
{
|
|
|
|
char name[1024];
|
|
|
|
qbyte *raw;
|
|
|
|
qbyte *out, *pix;
|
|
|
|
pcx_t *pcx;
|
2008-01-16 03:19:14 +00:00
|
|
|
int x, y, srcw, srch;
|
2004-08-23 00:15:46 +00:00
|
|
|
int dataByte;
|
|
|
|
int runLength;
|
|
|
|
int fbremap[256];
|
2013-03-12 22:56:10 +00:00
|
|
|
char *skinpath;
|
2004-08-23 00:15:46 +00:00
|
|
|
|
|
|
|
if (noskins.value==1) // JACK: So NOSKINS > 1 will show skins, but
|
|
|
|
return NULL; // not download new ones.
|
|
|
|
|
|
|
|
if (skin->failedload)
|
|
|
|
return NULL;
|
|
|
|
|
2013-03-12 22:56:10 +00:00
|
|
|
TEXASSIGN(skin->textures.base, r_nulltex);
|
|
|
|
TEXASSIGN(skin->textures.loweroverlay, r_nulltex);
|
|
|
|
TEXASSIGN(skin->textures.upperoverlay, r_nulltex);
|
2009-07-17 22:28:16 +00:00
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
out = Cache_Check (&skin->cache);
|
|
|
|
if (out)
|
|
|
|
return out;
|
|
|
|
|
2005-12-02 02:38:10 +00:00
|
|
|
// TODO: we build a fullbright remap.. can we get rid of this?
|
2009-07-16 22:06:59 +00:00
|
|
|
for (x = 0; x < vid.fullbright; x++)
|
|
|
|
fbremap[x] = x + (256-vid.fullbright); //fullbrights don't exist, so don't loose palette info.
|
2004-08-23 00:15:46 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// load the pic from disk
|
|
|
|
//
|
2005-01-05 08:00:20 +00:00
|
|
|
if (strchr(skin->name, ' ')) //see if it's actually three colours
|
|
|
|
{
|
|
|
|
qbyte bv;
|
|
|
|
int col[3];
|
|
|
|
char *s;
|
|
|
|
|
|
|
|
s = COM_Parse(skin->name);
|
|
|
|
col[0] = atof(com_token);
|
|
|
|
s = COM_Parse(s);
|
|
|
|
col[1] = atof(com_token);
|
|
|
|
s = COM_Parse(s);
|
|
|
|
col[2] = atof(com_token);
|
|
|
|
|
2007-09-22 19:28:27 +00:00
|
|
|
bv = GetPaletteIndex(col[0], col[1], col[2]);
|
2005-01-05 08:00:20 +00:00
|
|
|
|
|
|
|
skin->width = 320;
|
|
|
|
skin->height = 200;
|
|
|
|
|
|
|
|
out = Cache_Alloc (&skin->cache, 320*200, skin->name);
|
|
|
|
|
|
|
|
memset (out, bv, 320*200);
|
|
|
|
|
|
|
|
skin->failedload = false;
|
|
|
|
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2005-04-16 16:21:27 +00:00
|
|
|
#ifdef Q2CLIENT
|
2005-05-26 12:55:34 +00:00
|
|
|
if (cls.protocol == CP_QUAKE2)
|
2013-03-12 22:56:10 +00:00
|
|
|
skinpath = "players";
|
2005-03-20 02:57:11 +00:00
|
|
|
else
|
2005-04-16 16:21:27 +00:00
|
|
|
#endif
|
2013-03-12 22:56:10 +00:00
|
|
|
skinpath = "skins";
|
|
|
|
|
|
|
|
//favour 24bit+recoloured skins if gl_load24bit is enabled.
|
|
|
|
Q_snprintfz (name, sizeof(name), "%s_shirt", skin->name);
|
|
|
|
TEXASSIGN(skin->textures.upperoverlay, R_LoadReplacementTexture(name, skinpath, 0));
|
|
|
|
Q_snprintfz (name, sizeof(name), "%s_pants", skin->name);
|
|
|
|
TEXASSIGN(skin->textures.loweroverlay, R_LoadReplacementTexture(name, skinpath, 0));
|
|
|
|
if (TEXVALID(skin->textures.upperoverlay) || TEXVALID(skin->textures.loweroverlay))
|
|
|
|
{
|
|
|
|
TEXASSIGN(skin->textures.base, R_LoadReplacementTexture(skin->name, skinpath, IF_NOALPHA));
|
|
|
|
if (TEXVALID(skin->textures.base))
|
|
|
|
{
|
|
|
|
Q_snprintfz (name, sizeof(name), "%s_luma", skin->name);
|
|
|
|
TEXASSIGN(skin->textures.fullbright, R_LoadReplacementTexture(skin->name, skinpath, IF_NOALPHA));
|
|
|
|
Q_snprintfz (name, sizeof(name), "%s_gloss", skin->name);
|
|
|
|
TEXASSIGN(skin->textures.specular, R_LoadReplacementTexture(skin->name, skinpath, 0));
|
|
|
|
skin->failedload = true;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Q_snprintfz (name, sizeof(name), "%s/%s.pcx", skinpath, skin->name);
|
2004-08-23 00:15:46 +00:00
|
|
|
raw = COM_LoadTempFile (name);
|
|
|
|
if (!raw)
|
|
|
|
{
|
2013-03-12 22:56:10 +00:00
|
|
|
//use 24bit skins even if gl_load24bit is failed
|
2009-03-03 01:52:30 +00:00
|
|
|
if (strcmp(skin->name, baseskin.string))
|
|
|
|
{
|
2013-03-12 22:58:34 +00:00
|
|
|
// if (!gl_load24bit.value)
|
2009-07-17 22:28:16 +00:00
|
|
|
{
|
2013-03-12 22:56:10 +00:00
|
|
|
TEXASSIGN(skin->textures.base, R_LoadHiResTexture(skin->name, skinpath, IF_NOALPHA));
|
|
|
|
if (TEXVALID(skin->textures.base))
|
|
|
|
{
|
|
|
|
Q_snprintfz (name, sizeof(name), "%s_shirt", skin->name);
|
|
|
|
TEXASSIGN(skin->textures.upperoverlay, R_LoadHiResTexture(name, skinpath, 0));
|
|
|
|
Q_snprintfz (name, sizeof(name), "%s_pants", skin->name);
|
|
|
|
TEXASSIGN(skin->textures.loweroverlay, R_LoadHiResTexture(name, skinpath, 0));
|
2012-09-30 05:52:03 +00:00
|
|
|
|
2013-03-12 22:56:10 +00:00
|
|
|
Q_snprintfz (name, sizeof(name), "%s_luma", skin->name);
|
|
|
|
TEXASSIGN(skin->textures.fullbright, R_LoadHiResTexture(skin->name, skinpath, IF_NOALPHA));
|
|
|
|
Q_snprintfz (name, sizeof(name), "%s_gloss", skin->name);
|
|
|
|
TEXASSIGN(skin->textures.specular, R_LoadHiResTexture(skin->name, skinpath, 0));
|
|
|
|
|
|
|
|
skin->failedload = true;
|
|
|
|
return NULL;
|
|
|
|
}
|
2009-07-17 22:28:16 +00:00
|
|
|
}
|
2012-09-30 05:52:03 +00:00
|
|
|
|
2009-03-03 01:52:30 +00:00
|
|
|
//if its not already the base skin, try the base (and warn if anything not base couldn't load).
|
|
|
|
Con_Printf ("Couldn't load skin %s\n", name);
|
2011-07-22 15:11:35 +00:00
|
|
|
Q_snprintfz (name, sizeof(name), "skins/%s.pcx", baseskin.string);
|
2009-03-03 01:52:30 +00:00
|
|
|
raw = COM_LoadTempFile (name);
|
|
|
|
}
|
2004-08-23 00:15:46 +00:00
|
|
|
if (!raw)
|
|
|
|
{
|
|
|
|
skin->failedload = true;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// parse the PCX file
|
|
|
|
//
|
|
|
|
pcx = (pcx_t *)raw;
|
|
|
|
raw = (qbyte *)(pcx+1);
|
|
|
|
|
2008-01-16 03:19:14 +00:00
|
|
|
//check format (sizes are checked later)
|
2004-08-23 00:15:46 +00:00
|
|
|
if (pcx->manufacturer != 0x0a
|
|
|
|
|| pcx->version != 5
|
|
|
|
|| pcx->encoding != 1
|
2008-01-16 03:19:14 +00:00
|
|
|
|| pcx->bits_per_pixel != 8)
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
|
|
|
skin->failedload = true;
|
2008-01-16 03:19:14 +00:00
|
|
|
Con_Printf ("Bad skin %s (unsupported format)\n", name);
|
2004-08-23 00:15:46 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2005-04-19 21:09:29 +00:00
|
|
|
|
|
|
|
pcx->xmax = (unsigned short)LittleShort(pcx->xmax);
|
|
|
|
pcx->ymax = (unsigned short)LittleShort(pcx->ymax);
|
2008-01-16 03:19:14 +00:00
|
|
|
pcx->xmin = (unsigned short)LittleShort(pcx->xmin);
|
|
|
|
pcx->ymin = (unsigned short)LittleShort(pcx->ymin);
|
2005-04-19 21:09:29 +00:00
|
|
|
|
2008-01-16 03:19:14 +00:00
|
|
|
srcw = pcx->xmax-pcx->xmin+1;
|
|
|
|
srch = pcx->ymax-pcx->ymin+1;
|
|
|
|
|
|
|
|
if (srcw < 1 || srch < 1 || srcw > 320 || srch > 200)
|
2005-03-20 02:57:11 +00:00
|
|
|
{
|
2008-01-16 03:19:14 +00:00
|
|
|
skin->failedload = true;
|
|
|
|
Con_Printf ("Bad skin %s (unsupported size)\n", name);
|
|
|
|
return NULL;
|
|
|
|
}
|
2009-07-16 22:06:59 +00:00
|
|
|
skin->width = srcw;
|
|
|
|
skin->height = srch;
|
2008-01-16 03:19:14 +00:00
|
|
|
|
2005-03-20 02:57:11 +00:00
|
|
|
out = Cache_Alloc (&skin->cache, skin->width*skin->height, skin->name);
|
2004-08-23 00:15:46 +00:00
|
|
|
if (!out)
|
|
|
|
Sys_Error ("Skin_Cache: couldn't allocate");
|
|
|
|
|
|
|
|
pix = out;
|
2008-01-16 03:19:14 +00:00
|
|
|
// memset (out, 0, skin->width*skin->height);
|
2004-08-23 00:15:46 +00:00
|
|
|
|
2008-01-16 03:19:14 +00:00
|
|
|
dataByte = 0; //typically black (this is in case a 0*0 file is loaded... which won't happen anyway)
|
|
|
|
for (y=0 ; y < srch ; y++, pix += skin->width)
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
2008-01-16 03:19:14 +00:00
|
|
|
for (x=0 ; x < srcw ; )
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
|
|
|
if (raw - (qbyte*)pcx > com_filesize)
|
|
|
|
{
|
|
|
|
Cache_Free (&skin->cache);
|
|
|
|
skin->failedload = true;
|
|
|
|
Con_Printf ("Skin %s was malformed. You should delete it.\n", name);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
dataByte = *raw++;
|
|
|
|
|
|
|
|
if((dataByte & 0xC0) == 0xC0)
|
|
|
|
{
|
|
|
|
runLength = dataByte & 0x3F;
|
|
|
|
if (raw - (qbyte*)pcx > com_filesize)
|
|
|
|
{
|
|
|
|
Cache_Free (&skin->cache);
|
|
|
|
skin->failedload = true;
|
|
|
|
Con_Printf ("Skin %s was malformed. You should delete it.\n", name);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
dataByte = *raw++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
runLength = 1;
|
|
|
|
|
|
|
|
// skin sanity check
|
|
|
|
if (runLength + x > pcx->xmax + 2) {
|
|
|
|
Cache_Free (&skin->cache);
|
|
|
|
skin->failedload = true;
|
|
|
|
Con_Printf ("Skin %s was malformed. You should delete it.\n", name);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dataByte >= 256-vid.fullbright) //kill the fb componant
|
2009-11-04 21:16:50 +00:00
|
|
|
if (!r_fb_models.ival)
|
2004-08-23 00:15:46 +00:00
|
|
|
dataByte = fbremap[dataByte + vid.fullbright-256];
|
|
|
|
|
|
|
|
while(runLength-- > 0)
|
|
|
|
pix[x++] = dataByte;
|
|
|
|
}
|
|
|
|
|
2008-01-16 03:19:14 +00:00
|
|
|
//pad the end of the scan line with the trailing pixel
|
|
|
|
for ( ; x < skin->width ; )
|
|
|
|
pix[x++] = dataByte;
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
2008-01-16 03:19:14 +00:00
|
|
|
//pad the bottom of the skin with that final pixel
|
|
|
|
for ( ; y < skin->height; y++, pix += skin->width)
|
|
|
|
for (x = 0; x < skin->width; )
|
|
|
|
pix[x++] = dataByte;
|
2004-08-23 00:15:46 +00:00
|
|
|
|
|
|
|
if ( raw - (qbyte *)pcx > com_filesize)
|
|
|
|
{
|
|
|
|
Cache_Free (&skin->cache);
|
|
|
|
skin->failedload = true;
|
|
|
|
Con_Printf ("Skin %s was malformed. You should delete it.\n", name);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
skin->failedload = false;
|
|
|
|
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
qbyte *Skin_Cache32 (skin_t *skin)
|
|
|
|
{
|
|
|
|
char name[1024];
|
|
|
|
qbyte *raw;
|
|
|
|
qbyte *out, *pix;
|
2006-02-22 23:43:59 +00:00
|
|
|
char *path;
|
2012-02-12 05:18:31 +00:00
|
|
|
qboolean hasalpha;
|
2004-08-23 00:15:46 +00:00
|
|
|
|
|
|
|
if (noskins.value==1) // JACK: So NOSKINS > 1 will show skins, but
|
|
|
|
return NULL; // not download new ones.
|
|
|
|
|
|
|
|
if (skin->failedload)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
out = Cache_Check (&skin->cache);
|
|
|
|
if (out)
|
|
|
|
return out;
|
|
|
|
|
2006-02-22 23:43:59 +00:00
|
|
|
if (cls.protocol == CP_QUAKE2)
|
|
|
|
path = "players/";
|
|
|
|
else
|
|
|
|
path = "skins/";
|
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
//
|
|
|
|
// load the pic from disk
|
|
|
|
//
|
2011-07-22 15:11:35 +00:00
|
|
|
Q_snprintfz (name, sizeof(name), "%s%s.tga", path, skin->name);
|
2004-08-23 00:15:46 +00:00
|
|
|
raw = COM_LoadTempFile (name);
|
|
|
|
if (raw)
|
|
|
|
{
|
2012-02-12 05:18:31 +00:00
|
|
|
pix = ReadTargaFile(raw, com_filesize, &skin->width, &skin->height, &hasalpha, false);
|
2004-08-23 00:15:46 +00:00
|
|
|
if (pix)
|
|
|
|
{
|
|
|
|
out = Cache_Alloc(&skin->cache, skin->width*skin->height*4, name);
|
|
|
|
memcpy(out, pix, skin->width*skin->height*4);
|
2006-04-09 02:02:44 +00:00
|
|
|
BZ_Free(pix);
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
}
|
2011-07-22 15:11:35 +00:00
|
|
|
Q_snprintfz (name, sizeof(name), "%s%s.pcx", path, skin->name);
|
2006-04-09 02:02:44 +00:00
|
|
|
raw = COM_LoadTempFile (name);
|
|
|
|
if (raw)
|
|
|
|
{
|
|
|
|
pix = ReadPCXFile(raw, com_filesize, &skin->width, &skin->height);
|
|
|
|
if (pix)
|
|
|
|
{
|
|
|
|
out = Cache_Alloc(&skin->cache, skin->width*skin->height*4, name);
|
|
|
|
memcpy(out, pix, skin->width*skin->height*4);
|
2004-08-23 00:15:46 +00:00
|
|
|
BZ_Free(pix);
|
2006-02-22 23:43:59 +00:00
|
|
|
return out;
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef AVAIL_PNGLIB
|
2011-07-22 15:11:35 +00:00
|
|
|
Q_snprintfz (name, sizeof(name), "%s%s.png", path, skin->name);
|
2004-08-23 00:15:46 +00:00
|
|
|
raw = COM_LoadTempFile (name);
|
|
|
|
if (raw)
|
|
|
|
{
|
2006-02-27 00:42:25 +00:00
|
|
|
pix = ReadPNGFile(raw, com_filesize, &skin->width, &skin->height, name);
|
2004-08-23 00:15:46 +00:00
|
|
|
if (pix)
|
|
|
|
{
|
|
|
|
out = Cache_Alloc(&skin->cache, skin->width*skin->height*4, name);
|
|
|
|
memcpy(out, pix, skin->width*skin->height*4);
|
|
|
|
BZ_Free(pix);
|
2006-02-22 23:43:59 +00:00
|
|
|
return out;
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef AVAIL_JPEGLIB
|
2011-07-22 15:11:35 +00:00
|
|
|
Q_snprintfz (name, sizeof(name), "%s%s.jpeg", path, skin->name);
|
2004-08-23 00:15:46 +00:00
|
|
|
raw = COM_LoadTempFile (name);
|
|
|
|
if (raw)
|
|
|
|
{
|
|
|
|
pix = ReadJPEGFile(raw, com_filesize, &skin->width, &skin->height);
|
|
|
|
if (pix)
|
|
|
|
{
|
|
|
|
out = Cache_Alloc(&skin->cache, skin->width*skin->height*4, name);
|
|
|
|
memcpy(out, pix, skin->width*skin->height*4);
|
|
|
|
BZ_Free(pix);
|
2006-02-22 23:43:59 +00:00
|
|
|
return out;
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
}
|
2011-07-22 15:11:35 +00:00
|
|
|
Q_snprintfz (name, sizeof(name), "%s%s.jpg", path, skin->name); //jpegs are gready with 2 extensions...
|
2004-08-23 00:15:46 +00:00
|
|
|
raw = COM_LoadTempFile (name);
|
|
|
|
if (raw)
|
|
|
|
{
|
|
|
|
pix = ReadJPEGFile(raw, com_filesize, &skin->width, &skin->height);
|
|
|
|
if (pix)
|
|
|
|
{
|
|
|
|
out = Cache_Alloc(&skin->cache, skin->width*skin->height*4, name);
|
|
|
|
memcpy(out, pix, skin->width*skin->height*4);
|
|
|
|
BZ_Free(pix);
|
2006-02-22 23:43:59 +00:00
|
|
|
return out;
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
skin->failedload = true;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
Skin_NextDownload
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
void Skin_NextDownload (void)
|
|
|
|
{
|
|
|
|
player_info_t *sc;
|
|
|
|
int i;
|
|
|
|
|
2009-03-03 01:52:30 +00:00
|
|
|
//Con_Printf ("Checking skins...\n");
|
2004-08-23 00:15:46 +00:00
|
|
|
|
2006-01-04 00:44:34 +00:00
|
|
|
for (i = 0; i != MAX_CLIENTS; i++)
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
2006-01-04 00:44:34 +00:00
|
|
|
sc = &cl.players[i];
|
2004-08-23 00:15:46 +00:00
|
|
|
if (!sc->name[0])
|
|
|
|
continue;
|
|
|
|
Skin_Find (sc);
|
2009-11-04 21:16:50 +00:00
|
|
|
if (noskins.ival)
|
2004-08-23 00:15:46 +00:00
|
|
|
continue;
|
2005-01-05 08:00:20 +00:00
|
|
|
|
|
|
|
if (strchr(sc->skin->name, ' ')) //skip over skins using a space
|
|
|
|
continue;
|
|
|
|
|
2009-04-06 00:34:32 +00:00
|
|
|
if (!*sc->skin->name)
|
|
|
|
continue;
|
|
|
|
|
2010-11-10 03:32:47 +00:00
|
|
|
if (cls.protocol == CP_QUAKE2)
|
|
|
|
{
|
|
|
|
int j;
|
|
|
|
char *slash;
|
|
|
|
slash = strchr(sc->skin->name, '/');
|
|
|
|
if (slash)
|
|
|
|
{
|
|
|
|
*slash = 0;
|
|
|
|
CL_CheckOrEnqueDownloadFile(va("players/%s/tris.md2", sc->skin->name), NULL, 0);
|
|
|
|
for (j = 0; j < MAX_MODELS; j++)
|
|
|
|
{
|
|
|
|
if (cl.model_name[j][0] == '#')
|
|
|
|
CL_CheckOrEnqueDownloadFile(va("players/%s/%s", sc->skin->name, cl.model_name[j]+1), NULL, 0);
|
|
|
|
}
|
|
|
|
for (j = 0; j < MAX_SOUNDS; j++)
|
|
|
|
{
|
|
|
|
if (cl.sound_name[j][0] == '*')
|
|
|
|
CL_CheckOrEnqueDownloadFile(va("players/%s/%s", sc->skin->name, cl.sound_name[j]+1), NULL, 0);
|
|
|
|
}
|
|
|
|
*slash = '/';
|
|
|
|
CL_CheckOrEnqueDownloadFile(va("players/%s.pcx", sc->skin->name), NULL, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
CL_CheckOrEnqueDownloadFile(va("skins/%s.pcx", sc->skin->name), NULL, 0);
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// now load them in for real
|
|
|
|
for (i=0 ; i<MAX_CLIENTS ; i++)
|
|
|
|
{
|
|
|
|
sc = &cl.players[i];
|
|
|
|
if (!sc->name[0])
|
|
|
|
continue;
|
2006-02-22 23:43:59 +00:00
|
|
|
if (cls.protocol == CP_QUAKE2)
|
|
|
|
Skin_Cache32(sc->skin);
|
|
|
|
else
|
|
|
|
Skin_Cache8 (sc->skin);
|
2009-11-04 21:16:50 +00:00
|
|
|
#ifdef GLQUAKE
|
2004-08-23 00:15:46 +00:00
|
|
|
sc->skin = NULL;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-01-23 17:49:42 +00:00
|
|
|
//called from a few places when some skin cheat is applied.
|
|
|
|
//flushes all player skins.
|
|
|
|
void Skin_FlushPlayers(void)
|
|
|
|
{ //wipe the skin info
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < MAX_CLIENTS; i++)
|
|
|
|
cl.players[i].skin = NULL;
|
2009-04-01 22:03:56 +00:00
|
|
|
|
|
|
|
for (i = 0; i < MAX_CLIENTS; i++)
|
|
|
|
CL_NewTranslation(i);
|
2005-01-23 17:49:42 +00:00
|
|
|
}
|
2004-08-23 00:15:46 +00:00
|
|
|
|
2013-03-12 22:53:23 +00:00
|
|
|
void Skin_FlushAll(void)
|
|
|
|
{ //wipe the skin info
|
|
|
|
int i;
|
|
|
|
for (i=0 ; i<numskins ; i++)
|
|
|
|
{
|
|
|
|
if (skins[i].cache.data)
|
|
|
|
Cache_Free (&skins[i].cache);
|
|
|
|
}
|
|
|
|
numskins = 0;
|
|
|
|
|
|
|
|
Skin_FlushPlayers();
|
|
|
|
}
|
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
/*
|
|
|
|
==========
|
|
|
|
Skin_Skins_f
|
|
|
|
|
|
|
|
Refind all skins, downloading if needed.
|
|
|
|
==========
|
|
|
|
*/
|
|
|
|
void Skin_Skins_f (void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2004-12-22 18:58:54 +00:00
|
|
|
if (cls.state == ca_disconnected)
|
|
|
|
{
|
|
|
|
Con_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-03-12 22:56:10 +00:00
|
|
|
GL_GAliasFlushSkinCache();
|
2004-08-23 00:15:46 +00:00
|
|
|
for (i=0 ; i<numskins ; i++)
|
|
|
|
{
|
|
|
|
if (skins[i].cache.data)
|
|
|
|
Cache_Free (&skins[i].cache);
|
|
|
|
}
|
|
|
|
numskins = 0;
|
|
|
|
|
|
|
|
Skin_NextDownload ();
|
|
|
|
|
2006-01-04 00:44:34 +00:00
|
|
|
|
Fixes, workarounds, and breakages. Hexen2 should work much better (-hexen2 says no mission pack, -portals says h2mp). Started working on splitting bigcoords per client, far too much work still to go on that. Removed gl_ztrick entirely. Enabled csprogs download by default. Added client support for fitzquake's 666 protocol, needs testing, some cleanup for dp protocols too, no server support, couldn't selectively enable it anyway. Now attempting to cache shadow meshes for explosions and stuff. Played with lightmaps a little, should potentially run a little faster on certain (intel?) cards. Tweeked npfte a little to try to avoid deadlocks and crashes. Fixed sky worldspawn parsing. Added h2mp's model format. Fixed baseline issue in q2 client, made servers generate q2 baselines. MOVETYPE_PUSH will not rotate extra if rotation is forced. Made status command show allowed client types. Changed lighting on weapons - should now be shaded.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/branches/wip@3572 fc73d0e0-1445-4013-8a0c-d673dee63da5
2010-08-11 03:36:31 +00:00
|
|
|
// if (Cmd_FromServer())
|
|
|
|
{
|
|
|
|
SCR_SetLoadingStage(LS_NONE);
|
2009-04-06 00:34:32 +00:00
|
|
|
|
Fixes, workarounds, and breakages. Hexen2 should work much better (-hexen2 says no mission pack, -portals says h2mp). Started working on splitting bigcoords per client, far too much work still to go on that. Removed gl_ztrick entirely. Enabled csprogs download by default. Added client support for fitzquake's 666 protocol, needs testing, some cleanup for dp protocols too, no server support, couldn't selectively enable it anyway. Now attempting to cache shadow meshes for explosions and stuff. Played with lightmaps a little, should potentially run a little faster on certain (intel?) cards. Tweeked npfte a little to try to avoid deadlocks and crashes. Fixed sky worldspawn parsing. Added h2mp's model format. Fixed baseline issue in q2 client, made servers generate q2 baselines. MOVETYPE_PUSH will not rotate extra if rotation is forced. Made status command show allowed client types. Changed lighting on weapons - should now be shaded.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/branches/wip@3572 fc73d0e0-1445-4013-8a0c-d673dee63da5
2010-08-11 03:36:31 +00:00
|
|
|
CL_SendClientCommand(true, "begin %i", cl.servercount);
|
|
|
|
Cache_Report (); // print remaining memory
|
|
|
|
}
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
==========
|
|
|
|
Skin_AllSkins_f
|
|
|
|
|
|
|
|
Sets all skins to one specific one
|
|
|
|
==========
|
|
|
|
*/
|
|
|
|
void Skin_AllSkins_f (void)
|
|
|
|
{
|
|
|
|
strcpy (allskins, Cmd_Argv(1));
|
|
|
|
Skin_Skins_f ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Skin_FlushSkin(char *name)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
char sname[16]="";
|
|
|
|
if (strncmp(name, "skins/", 6))
|
|
|
|
return;
|
|
|
|
Q_strncpyz(sname, (name + 6), strlen(name+6)-3);
|
|
|
|
for (i=0 ; i<numskins ; i++)
|
|
|
|
{
|
|
|
|
if (!strcmp(skins[i].name, sname))
|
|
|
|
skins[i].failedload = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-05-25 22:23:43 +00:00
|
|
|
|