fix many, many bugs in the alias skin loading, transforming and rendering

code. This fixes blather's `melted models' (sw), the nq alt player model
skins (gl), the arbitrary limits on skins and skin groups in gl, and the
incorrect timing of group skins (animated) in gl.
This commit is contained in:
Bill Currie 2001-11-21 08:14:05 +00:00
parent 3e34fc83e4
commit 7d14013041
6 changed files with 146 additions and 110 deletions

View file

@ -290,6 +290,8 @@ typedef struct
{
aliasskintype_t type;
int skin;
int texnum;
int fb_texnum;
} maliasskindesc_t;
typedef struct
@ -336,9 +338,6 @@ typedef struct {
unsigned short crc;
int gl_texturenum[MAX_SKINS][4];
int gl_fb_texturenum[MAX_SKINS][4];
int texels[MAX_SKINS]; // only for player skins
maliasframedesc_t frames[1];
} aliashdr_t;

View file

@ -136,43 +136,47 @@ Mod_FloodFillSkin (byte * skin, int skinwidth, int skinheight)
}
void *
Mod_LoadSkin (byte * skin, int skinsize, int snum, int gnum, qboolean group)
Mod_LoadSkin (byte * skin, int skinsize, int snum, int gnum, qboolean group,
maliasskindesc_t *skindesc)
{
char name[32];
int fbtexnum = 0;
int fb_texnum = 0;
int texnum = 0;
byte *pskin;
Mod_FloodFillSkin (skin, pheader->mdl.skinwidth, pheader->mdl.skinheight);
pskin = Hunk_AllocName (skinsize, loadname);
skindesc->skin = (byte *) pskin - (byte *) pheader;
memcpy (pskin, skin, skinsize);
Mod_FloodFillSkin (pskin, pheader->mdl.skinwidth, pheader->mdl.skinheight);
// save 8 bit texels for the player model to remap
if (!strcmp (loadmodel->name, "progs/player.mdl")) {
byte *texels;
if (strequal (loadmodel->name, "progs/player.mdl")) {
if (skinsize > sizeof (player_8bit_texels))
Sys_Error ("Player skin too large");
texels = Hunk_AllocName (skinsize, loadname);
pheader->texels[snum] = texels - (byte *) pheader;
memcpy (texels, skin, skinsize);
memcpy (player_8bit_texels, skin, skinsize);
memcpy (player_8bit_texels, pskin, skinsize);
}
if (group) {
snprintf (name, sizeof (name), "fb_%s_%i_%i", loadmodel->name, snum,
gnum);
} else {
snprintf (name, sizeof (name), "fb_%s_%i", loadmodel->name, snum);
}
if (!loadmodel->fullbright)
fbtexnum = Mod_Fullbright (skin + 1, pheader->mdl.skinwidth,
pheader->mdl.skinheight, name);
if ((loadmodel->hasfullbrights = (fbtexnum))) {
pheader->gl_fb_texturenum[snum][gnum] = fbtexnum;
if (!loadmodel->fullbright) {
if (group) {
snprintf (name, sizeof (name), "fb_%s_%i_%i", loadmodel->name,
snum, gnum);
} else {
snprintf (name, sizeof (name), "fb_%s_%i", loadmodel->name, snum);
}
fb_texnum = Mod_Fullbright (pskin, pheader->mdl.skinwidth,
pheader->mdl.skinheight, name);
}
if (group) {
snprintf (name, sizeof (name), "%s_%i_%i", loadmodel->name, snum, gnum);
} else {
snprintf (name, sizeof (name), "%s_%i", loadmodel->name, snum);
}
pheader->gl_texturenum[snum][gnum] =
GL_LoadTexture (name, pheader->mdl.skinwidth,
pheader->mdl.skinheight, skin, true, false, 1);
texnum = GL_LoadTexture (name, pheader->mdl.skinwidth,
pheader->mdl.skinheight, pskin, true, false, 1);
skindesc->texnum = texnum;
skindesc->fb_texnum = fb_texnum;
loadmodel->hasfullbrights = fb_texnum;
// alpha param was true for non group skins
return skin + skinsize;
}
@ -180,48 +184,63 @@ Mod_LoadSkin (byte * skin, int skinsize, int snum, int gnum, qboolean group)
void *
Mod_LoadAllSkins (int numskins, daliasskintype_t *pskintype, int *pskinindex)
{
int i, j, k;
int snum, gnum, t;
int skinsize;
byte *skin;
daliasskingroup_t *pinskingroup;
int groupskins;
daliasskingroup_t *pinskingroup;
daliasskininterval_t *pinskinintervals;
maliasskindesc_t *pskindesc;
maliasskingroup_t *paliasskingroup;
float *poutskinintervals;
if (numskins < 1 || numskins > MAX_SKINS)
Sys_Error ("Mod_LoadAliasModel: Invalid # of skins: %d\n", numskins);
skinsize = pheader->mdl.skinwidth * pheader->mdl.skinheight;
pskindesc = Hunk_AllocName (numskins * sizeof (maliasskindesc_t),
loadname);
for (i = 0; i < numskins; i++) {
*pskinindex = (byte *) pskindesc - (byte *) pheader;
for (snum = 0; snum < numskins; snum++) {
pskindesc[snum].type = pskintype->type;
if (pskintype->type == ALIAS_SKIN_SINGLE) {
skin = (byte *) (pskintype + 1);
skin = Mod_LoadSkin (skin, skinsize, i, 0, false);
for (j = 1; j < 4; j++) {
pheader->gl_texturenum[i][j] = pheader->gl_texturenum[i][j - 1];
pheader->gl_fb_texturenum[i][j] =
pheader->gl_fb_texturenum[i][j - 1];
}
skin = Mod_LoadSkin (skin, skinsize, snum, 0, false,
&pskindesc[snum]);
} else {
// animating skin group. yuck.
// Sys_Printf("Animating Skin Group, if you get this message
// please notify warp@debian.org\n");
pskintype++;
pinskingroup = (daliasskingroup_t *) pskintype;
groupskins = LittleLong (pinskingroup->numskins);
pinskinintervals = (daliasskininterval_t *) (pinskingroup + 1);
pskintype = (void *) (pinskinintervals + groupskins);
t = field_offset (maliasskingroup_t, skindescs[groupskins]);
paliasskingroup = Hunk_AllocName (t, loadname);
paliasskingroup->numskins = groupskins;
pskindesc[snum].skin = (byte *) paliasskingroup - (byte *) pheader;
pinskinintervals = (daliasskininterval_t *) (pinskingroup + 1);
poutskinintervals = Hunk_AllocName (groupskins * sizeof (float),
loadname);
paliasskingroup->intervals =
(byte *) poutskinintervals - (byte *) pheader;
for (gnum = 0; gnum < groupskins; gnum++) {
*poutskinintervals = LittleFloat (pinskinintervals->interval);
if (*poutskinintervals <= 0)
Sys_Error ("Mod_LoadAliasSkinGroup: interval<=0");
poutskinintervals++;
pinskinintervals++;
}
pskintype = (void *) pinskinintervals;
skin = (byte *) pskintype;
for (j = 0; j < groupskins; j++) {
skin = Mod_LoadSkin (skin, skinsize, i, j & 3, true);
}
k = j;
for ( /* */ ; j < 4; j++) {
pheader->gl_texturenum[i][j] = pheader->gl_texturenum[i][j - k];
pheader->gl_fb_texturenum[i][j] =
pheader->gl_fb_texturenum[i][j - k];
for (gnum = 0; gnum < groupskins; gnum++) {
paliasskingroup->skindescs[gnum].type = ALIAS_SKIN_SINGLE;
skin = Mod_LoadSkin (skin, skinsize, snum, gnum, true,
&paliasskingroup->skindescs[gnum]);
}
}
pskintype = (daliasskintype_t *) skin;

View file

@ -44,6 +44,7 @@ static const char rcsid[] =
#include "QF/qendian.h"
#include "QF/sys.h"
#include "compat.h"
#include "d_iface.h"
@ -58,34 +59,16 @@ static const char rcsid[] =
void *
Mod_LoadSkin (byte * skin, int skinsize, int *pskinindex, int snum, int gnum)
Mod_LoadSkin (byte * skin, int skinsize, maliasskindesc_t *skindesc)
{
byte *pskin;
// unsigned short *pusskin;
// int i;
// LordHavoc: model rendering expects skin in 8bit always
pskin = Hunk_AllocName (skinsize, loadname);
memcpy (pskin, skin, skinsize);
/*
pskin = Hunk_AllocName (skinsize * r_pixbytes, loadname);
skindesc->skin = (byte *) pskin - (byte *) pheader;
memcpy (pskin, skin, skinsize);
switch (r_pixbytes) {
case 1:
memcpy (pskin, skin, skinsize);
break;
case 2:
pusskin = (unsigned short *) skin;
for (i = 0; i < skinsize; i++)
pusskin[i] = d_8to16table[skin[i]];
break;
default:
Sys_Error ("Mod_LoadAliasSkin: driver set invalid r_pixbytes: "
"%d\n", r_pixbytes);
break;
}
*/
*pskinindex = (byte *) pskin - (byte *) pheader;
return skin + skinsize;
}
@ -109,28 +92,27 @@ Mod_LoadAllSkins (int numskins, daliasskintype_t *pskintype, int *pskinindex)
pskindesc = Hunk_AllocName (numskins * sizeof (maliasskindesc_t),
loadname);
pheader->skindesc = (byte *) pskindesc - (byte *) pheader;
*pskinindex = (byte *) pskindesc - (byte *) pheader;
for (snum = 0; snum < numskins; snum++) {
pskindesc[snum].type = pskintype->type;
if (pskintype->type == ALIAS_SKIN_SINGLE) {
skin = (byte *) (pskintype + 1);
skin =
Mod_LoadSkin (skin, skinsize, &pskindesc[snum].skin, snum, 0);
skin = Mod_LoadSkin (skin, skinsize, &pskindesc[snum]);
} else {
pskintype++;
pinskingroup = (daliasskingroup_t *) pskintype;
groupskins = LittleLong (pinskingroup->numskins);
t = (int) &((maliasskingroup_t *) 0)->skindescs[groupskins];
t = field_offset (maliasskingroup_t, skindescs[groupskins]);
paliasskingroup = Hunk_AllocName (t, loadname);
paliasskingroup->numskins = groupskins;
*pskinindex = (byte *) paliasskingroup - (byte *) pheader;
pskindesc[snum].skin = (byte *) paliasskingroup - (byte *) pheader;
pinskinintervals = (daliasskininterval_t *) (pinskingroup + 1);
poutskinintervals =
Hunk_AllocName (groupskins * sizeof (float), loadname);
poutskinintervals = Hunk_AllocName (groupskins * sizeof (float),
loadname);
paliasskingroup->intervals =
(byte *) poutskinintervals - (byte *) pheader;
for (gnum = 0; gnum < groupskins; gnum++) {
@ -146,10 +128,9 @@ Mod_LoadAllSkins (int numskins, daliasskintype_t *pskintype, int *pskinindex)
skin = (byte *) pskintype;
for (gnum = 0; gnum < groupskins; gnum++) {
skin =
Mod_LoadSkin (skin, skinsize,
&paliasskingroup->skindescs[snum].skin, snum,
gnum);
paliasskingroup->skindescs[gnum].type = ALIAS_SKIN_SINGLE;
skin = Mod_LoadSkin (skin, skinsize,
&paliasskingroup->skindescs[gnum]);
}
}
pskintype = (daliasskintype_t *) skin;

View file

@ -60,14 +60,14 @@ static const char rcsid[] =
void *
Mod_LoadSkin (byte * skin, int skinsize, int *pskinindex, int snum, int gnum)
Mod_LoadSkin (byte * skin, int skinsize, maliasskindesc_t *skindesc)
{
byte *pskin;
unsigned short *pusskin;
int i;
pskin = Hunk_AllocName (skinsize * r_pixbytes, loadname);
*pskinindex = (byte *) pskin - (byte *) pheader;
skindesc->skin = (byte *) pskin - (byte *) pheader;
switch (r_pixbytes) {
case 1:
@ -106,13 +106,13 @@ Mod_LoadAllSkins (int numskins, daliasskintype_t *pskintype, int *pskinindex)
pskindesc = Hunk_AllocName (numskins * sizeof (maliasskindesc_t),
loadname);
pheader->skindesc = (byte *) pskindesc - (byte *) pheader;
*pskinindex = (byte *) pskindesc - (byte *) pheader;
for (snum = 0; snum < numskins; snum++) {
pskindesc[snum].type = pskintype->type;
if (pskintype->type == ALIAS_SKIN_SINGLE) {
skin = (byte *) (pskintype + 1);
skin =
Mod_LoadSkin (skin, skinsize, &pskindesc[snum].skin, snum, 0);
skin = Mod_LoadSkin (skin, skinsize, &pskindesc[snum]);
} else {
pskintype++;
pinskingroup = (daliasskingroup_t *) pskintype;
@ -122,7 +122,7 @@ Mod_LoadAllSkins (int numskins, daliasskintype_t *pskintype, int *pskinindex)
paliasskingroup = Hunk_AllocName (t, loadname);
paliasskingroup->numskins = groupskins;
*pskinindex = (byte *) paliasskingroup - (byte *) pheader;
pskindesc[snum].skin = (byte *) paliasskingroup - (byte *) pheader;
pinskinintervals = (daliasskininterval_t *) (pinskingroup + 1);
poutskinintervals = Hunk_AllocName (groupskins * sizeof (float),
@ -142,10 +142,9 @@ Mod_LoadAllSkins (int numskins, daliasskintype_t *pskintype, int *pskinindex)
skin = (byte *) pskintype;
for (gnum = 0; gnum < groupskins; gnum++) {
skin =
Mod_LoadSkin (skin, skinsize,
&paliasskingroup->skindescs[snum].skin, snum,
gnum);
paliasskingroup->skindescs[gnum].type = ALIAS_SKIN_SINGLE;
skin = Mod_LoadSkin (skin, skinsize,
&paliasskingroup->skindescs[gnum]);
}
}
pskintype = (daliasskintype_t *) skin;

View file

@ -379,11 +379,52 @@ GL_GetAliasFrameVerts (int frame, aliashdr_t *paliashdr, entity_t *e)
return vo;
}
maliasskindesc_t *
R_AliasGetSkindesc (int skinnum, aliashdr_t *ahdr)
{
maliasskindesc_t *pskindesc;
maliasskingroup_t *paliasskingroup;
if ((skinnum >= ahdr->mdl.numskins) || (skinnum < 0)) {
Con_DPrintf ("R_AliasSetupSkin: no such skin # %d\n", skinnum);
skinnum = 0;
}
pskindesc = ((maliasskindesc_t *)
((byte *) ahdr + ahdr->skindesc)) + skinnum;
if (pskindesc->type == ALIAS_SKIN_GROUP) {
float fullskininterval;
int i;
float skintargettime, skintime;
float *pskinintervals;
paliasskingroup = (maliasskingroup_t *) ((byte *) ahdr +
pskindesc->skin);
pskinintervals = (float *)
((byte *) ahdr + paliasskingroup->intervals);
numskins = paliasskingroup->numskins;
fullskininterval = pskinintervals[numskins - 1];
skintime = r_realtime + currententity->syncbase;
skintargettime = skintime -
((int) (skintime / fullskininterval)) * fullskininterval;
for (i = 0; i < (numskins - 1); i++) {
if (pskinintervals[i] > skintargettime)
break;
}
pskindesc = &paliasskingroup->skindescs[i];
}
return pskindesc;
}
void
R_DrawAliasModel (entity_t *e, qboolean cull)
{
float add, an;
int anim, lnum, skinnum, texture;
int lnum, texture;
int fb_texture = 0;
aliashdr_t *paliashdr;
model_t *clmodel;
@ -461,18 +502,6 @@ R_DrawAliasModel (entity_t *e, qboolean cull)
qfglScalef (paliashdr->mdl.scale[0], paliashdr->mdl.scale[1],
paliashdr->mdl.scale[2]);
anim = (int) (r_realtime * 10) & 3;
skinnum = e->skinnum;
if ((skinnum >= paliashdr->mdl.numskins) || (skinnum < 0)) {
Con_DPrintf ("R_AliasSetupSkin: no such skin # %d\n", skinnum);
skinnum = 0;
}
texture = paliashdr->gl_texturenum[skinnum][anim];
if (gl_fb_models->int_val && !clmodel->fullbright)
fb_texture = paliashdr->gl_fb_texturenum[skinnum][anim];
// we can't dynamically colormap textures, so they are cached
// seperately for the players. Heads are just uncolored.
if (e->skin && !gl_nocolors->int_val) {
@ -482,6 +511,13 @@ R_DrawAliasModel (entity_t *e, qboolean cull)
if (gl_fb_models->int_val) {
fb_texture = skin->fb_texture;
}
} else {
maliasskindesc_t *skindesc;
skindesc = R_AliasGetSkindesc (e->skinnum, paliashdr);
texture = skindesc->texnum;
if (gl_fb_models->int_val && !clmodel->fullbright)
fb_texture = skindesc->fb_texnum;
}
qfglBindTexture (GL_TEXTURE_2D, texture);

View file

@ -198,6 +198,7 @@ Skin_Do_Translation_Model (model_t *model, int skinnum, int slot, skin_t *skin)
int inwidth, inheight;
int texnum = skin->texture;
aliashdr_t *paliashdr;
maliasskindesc_t *pskindesc;
if (!model) // player doesn't have a model yet
return;
@ -209,11 +210,12 @@ Skin_Do_Translation_Model (model_t *model, int skinnum, int slot, skin_t *skin)
|| skinnum >= paliashdr->mdl.numskins) {
Con_Printf ("(%d): Invalid player skin #%d\n", slot,
skinnum);
original = (byte *) paliashdr + paliashdr->texels[0];
} else {
original =
(byte *) paliashdr + paliashdr->texels[skinnum];
skinnum = 0;
}
pskindesc = ((maliasskindesc_t *)
((byte *) paliashdr + paliashdr->skindesc)) + skinnum;
//FIXME: broken for skin groups
original = (byte *) paliashdr + pskindesc->skin;
inwidth = paliashdr->mdl.skinwidth;
inheight = paliashdr->mdl.skinheight;