Fix md3 skins not loading properly (since colormap change). Throw in support for eg foo.md3_0.skin files too, so armour model replacements can be handled properly.

This commit is contained in:
Shpoike 2023-07-10 03:06:15 +01:00
parent 09b9a76bb4
commit cf2a1421bd
2 changed files with 90 additions and 21 deletions

View file

@ -461,6 +461,7 @@ void GLMesh_DeleteVertexBuffers (void)
//from gl_model.c //from gl_model.c
extern char loadname[]; // for hunk tags extern char loadname[]; // for hunk tags
extern char diskname[]; // for skin files/etc.
void Mod_CalcAliasBounds (aliashdr_t *a); void Mod_CalcAliasBounds (aliashdr_t *a);
@ -538,7 +539,44 @@ typedef struct {
int shaderIndex; int shaderIndex;
} md3Shader_t; } md3Shader_t;
qboolean Mod_GetShaderNameForSurface(const char *skinfile, const char *surfacename, char *texturename, size_t texturenamesize)
{
const char *linestart = skinfile;
//lots of `surfacename,shadername` pair lines.
while (*skinfile)
{
if (*skinfile == ',')
{
while (*linestart == ' ' || *linestart == '\t')
linestart++;
if (skinfile - linestart == strlen(surfacename))
if (!strncmp(linestart, surfacename, skinfile-linestart))
{ //okay, this is the one we're after.
skinfile++;
while(*skinfile == ' ' || *skinfile == '\t')
skinfile++;
linestart = skinfile;
while (*skinfile && *skinfile != '\n')
skinfile++;
while (skinfile > linestart && (skinfile[-1] == '\r' || skinfile[-1] == ' ' || skinfile[-1] == '\t'))
skinfile--;
if (skinfile-linestart >= texturenamesize)
return false; //too long.
memcpy(texturename, linestart, skinfile-linestart);
texturename[skinfile-linestart] = 0;
return true;
}
//walk to the end of the line.
while (*skinfile && *skinfile != '\n')
skinfile++;
}
else if (*skinfile++ == '\n')
linestart = skinfile;
}
return false;
}
void Mod_LoadMD3Model (qmodel_t *mod, void *buffer) void Mod_LoadMD3Model (qmodel_t *mod, void *buffer)
{ {
@ -559,6 +597,9 @@ void Mod_LoadMD3Model (qmodel_t *mod, void *buffer)
int numframes; int numframes;
aliashdr_t *outhdr; aliashdr_t *outhdr;
char *skinfile[countof(outhdr->textures)];
unsigned int numskinfiles;
start = Hunk_LowMark (); start = Hunk_LowMark ();
pinheader = (md3Header_t *)buffer; pinheader = (md3Header_t *)buffer;
@ -566,16 +607,16 @@ void Mod_LoadMD3Model (qmodel_t *mod, void *buffer)
ival = LittleLong (pinheader->version); ival = LittleLong (pinheader->version);
if (ival != MD3_VERSION) if (ival != MD3_VERSION)
Sys_Error ("%s has wrong version number (%i should be %i)", Sys_Error ("%s has wrong version number (%i should be %i)",
mod->name, ival, MD3_VERSION); diskname, ival, MD3_VERSION);
numsurfs = LittleLong (pinheader->numSurfaces); numsurfs = LittleLong (pinheader->numSurfaces);
numframes = LittleLong(pinheader->numFrames); numframes = LittleLong(pinheader->numFrames);
if (numframes > MAXALIASFRAMES) if (numframes > MAXALIASFRAMES)
Sys_Error ("%s has too many frames (%i vs %i)", Sys_Error ("%s has too many frames (%i vs %i)",
mod->name, numframes, MAXALIASFRAMES); diskname, numframes, MAXALIASFRAMES);
if (!numsurfs) if (!numsurfs)
Sys_Error ("%s has nosurfaces", mod->name); Sys_Error ("%s has nosurfaces", diskname);
pinframes = (md3Frame_t*)((byte*)buffer + LittleLong(pinheader->ofsFrames)); pinframes = (md3Frame_t*)((byte*)buffer + LittleLong(pinheader->ofsFrames));
// //
@ -585,13 +626,20 @@ void Mod_LoadMD3Model (qmodel_t *mod, void *buffer)
size = sizeof(aliashdr_t) + (numframes-1) * sizeof (outhdr->frames[0]); size = sizeof(aliashdr_t) + (numframes-1) * sizeof (outhdr->frames[0]);
outhdr = (aliashdr_t *) Hunk_AllocName (size * numsurfs, loadname); outhdr = (aliashdr_t *) Hunk_AllocName (size * numsurfs, loadname);
for (numskinfiles = 0; numskinfiles < countof(skinfile); numskinfiles++)
{ //q3 doesn't really support multiple skins any other way. plus this lets us fix up some texture paths...
skinfile[numskinfiles] = COM_LoadMallocFile(va("%s_%i.skin", diskname, numskinfiles), NULL);
if (!skinfile[numskinfiles])
break;
}
for (surf = 0, pinsurface = (md3Surface_t*)((byte*)buffer + LittleLong(pinheader->ofsSurfaces)); surf < numsurfs; surf++, pinsurface = (md3Surface_t*)((byte*)pinsurface + LittleLong(pinsurface->ofsEnd))) for (surf = 0, pinsurface = (md3Surface_t*)((byte*)buffer + LittleLong(pinheader->ofsSurfaces)); surf < numsurfs; surf++, pinsurface = (md3Surface_t*)((byte*)pinsurface + LittleLong(pinsurface->ofsEnd)))
{ {
aliashdr_t *osurf = (aliashdr_t*)((byte*)outhdr + size*surf); aliashdr_t *osurf = (aliashdr_t*)((byte*)outhdr + size*surf);
if (LittleLong(pinsurface->ident) != (('I'<<0)|('D'<<8)|('P'<<16)|('3'<<24))) if (LittleLong(pinsurface->ident) != (('I'<<0)|('D'<<8)|('P'<<16)|('3'<<24)))
Sys_Error ("%s corrupt surface ident", mod->name); Sys_Error ("%s corrupt surface ident", diskname);
if (LittleLong(pinsurface->numFrames) != numframes) if (LittleLong(pinsurface->numFrames) != numframes)
Sys_Error ("%s mismatched framecounts", mod->name); Sys_Error ("%s mismatched framecounts", diskname);
if (surf+1 < numsurfs) if (surf+1 < numsurfs)
osurf->nextsurface = size; osurf->nextsurface = size;
@ -647,8 +695,12 @@ void Mod_LoadMD3Model (qmodel_t *mod, void *buffer)
//load the textures //load the textures
if (!isDedicated) if (!isDedicated)
{ {
int numshaders = pinsurface->numShaders;
pinshader = (md3Shader_t*)((byte*)pinsurface + LittleLong(pinsurface->ofsShaders)); pinshader = (md3Shader_t*)((byte*)pinsurface + LittleLong(pinsurface->ofsShaders));
osurf->numskins = LittleLong(pinsurface->numShaders); if (numskinfiles)
osurf->numskins = numskinfiles;
else
osurf->numskins = q_max(1, q_min(countof(osurf->textures), numshaders));
for (j = 0; j < osurf->numskins; j++, pinshader++) for (j = 0; j < osurf->numskins; j++, pinshader++)
{ {
char texturename[MAX_QPATH]; char texturename[MAX_QPATH];
@ -656,6 +708,15 @@ void Mod_LoadMD3Model (qmodel_t *mod, void *buffer)
char uppername[MAX_QPATH]; char uppername[MAX_QPATH];
char lowername[MAX_QPATH]; char lowername[MAX_QPATH];
char *ext; char *ext;
if (j >= numshaders)
{ //invalid skin index for the model... not a major issue I guess
q_strlcpy(texturename, diskname, sizeof(texturename));
*(char*)COM_SkipPath(texturename) = 0;
//and concat the specified name
q_strlcat(texturename, pinsurface->name, sizeof(texturename));
}
else
{
//texture names in md3s are kinda fucked. they could be just names relative to the mdl, or full paths, or just simple shader names. //texture names in md3s are kinda fucked. they could be just names relative to the mdl, or full paths, or just simple shader names.
//our texture manager is too lame to scan all 1000 possibilities //our texture manager is too lame to scan all 1000 possibilities
if (strchr(pinshader->name, '/') || strchr(pinshader->name, '\\')) if (strchr(pinshader->name, '/') || strchr(pinshader->name, '\\'))
@ -664,23 +725,26 @@ void Mod_LoadMD3Model (qmodel_t *mod, void *buffer)
} }
else else
{ //and if there's no path then we want to prefix it with our own. { //and if there's no path then we want to prefix it with our own.
q_strlcpy(texturename, mod->name, sizeof(texturename)); q_strlcpy(texturename, diskname, sizeof(texturename));
*(char*)COM_SkipPath(texturename) = 0; *(char*)COM_SkipPath(texturename) = 0;
//and concat the specified name //and concat the specified name
q_strlcat(texturename, pinshader->name, sizeof(texturename)); q_strlcat(texturename, pinshader->name, sizeof(texturename));
} }
}
if (j < numskinfiles)
Mod_GetShaderNameForSurface(skinfile[j], pinsurface->name, texturename, sizeof(texturename)); //swap it out for the skinned texture..
//and make sure there's no extensions. these get ignored in q3, which is kinda annoying, but this is an md3 and standards are standards (and it makes luma easier). //and make sure there's no extensions. these get ignored in q3, which is kinda annoying, but this is an md3 and standards are standards (and it makes luma easier).
ext = (char*)COM_FileGetExtension(texturename); ext = (char*)COM_FileGetExtension(texturename);
if (*ext) if (*ext)
*--ext = 0; *--ext = 0;
//luma has an extra postfix. //luma has an extra postfix.
q_snprintf(uppername, sizeof(fullbrightname), "%s_shirt", texturename); q_snprintf(uppername, sizeof(uppername), "%s_shirt", texturename);
q_snprintf(lowername, sizeof(fullbrightname), "%s_pants", texturename); q_snprintf(lowername, sizeof(lowername), "%s_pants", texturename);
q_snprintf(fullbrightname, sizeof(fullbrightname), "%s_luma", texturename); q_snprintf(fullbrightname, sizeof(fullbrightname), "%s_luma", texturename);
osurf->textures[j][0].base = TexMgr_LoadImage(mod, texturename, osurf->skinwidth, osurf->skinheight, SRC_EXTERNAL, NULL, texturename, 0, TEXPREF_PAD|TEXPREF_ALPHA|TEXPREF_NOBRIGHT|TEXPREF_MIPMAP); osurf->textures[j][0].base = TexMgr_LoadImage(mod, texturename, osurf->skinwidth, osurf->skinheight, SRC_EXTERNAL, NULL, texturename, 0, TEXPREF_PAD|TEXPREF_ALPHA|TEXPREF_NOBRIGHT|TEXPREF_MIPMAP);
osurf->textures[j][0].lower = TexMgr_LoadImage(mod, lowername, osurf->skinwidth, osurf->skinheight, SRC_EXTERNAL, NULL, lowername, 0, TEXPREF_PAD|TEXPREF_ALPHA|TEXPREF_NOBRIGHT|TEXPREF_MIPMAP); osurf->textures[j][0].lower = TexMgr_LoadImage(mod, lowername, osurf->skinwidth, osurf->skinheight, SRC_EXTERNAL, NULL, lowername, 0, TEXPREF_ALLOWMISSING|TEXPREF_PAD|TEXPREF_MIPMAP);
osurf->textures[j][0].upper = TexMgr_LoadImage(mod, uppername, osurf->skinwidth, osurf->skinheight, SRC_EXTERNAL, NULL, uppername, 0, TEXPREF_PAD|TEXPREF_ALPHA|TEXPREF_NOBRIGHT|TEXPREF_MIPMAP); osurf->textures[j][0].upper = TexMgr_LoadImage(mod, uppername, osurf->skinwidth, osurf->skinheight, SRC_EXTERNAL, NULL, uppername, 0, TEXPREF_ALLOWMISSING|TEXPREF_PAD|TEXPREF_MIPMAP);
osurf->textures[j][0].luma = TexMgr_LoadImage(mod, fullbrightname, osurf->skinwidth, osurf->skinheight, SRC_EXTERNAL, NULL, fullbrightname, 0, TEXPREF_PAD|TEXPREF_ALPHA|TEXPREF_FULLBRIGHT|TEXPREF_MIPMAP); osurf->textures[j][0].luma = TexMgr_LoadImage(mod, fullbrightname, osurf->skinwidth, osurf->skinheight, SRC_EXTERNAL, NULL, fullbrightname, 0, TEXPREF_ALLOWMISSING|TEXPREF_PAD|TEXPREF_ALPHA|TEXPREF_FULLBRIGHT|TEXPREF_MIPMAP);
osurf->textures[j][3] = osurf->textures[j][2] = osurf->textures[j][1] = osurf->textures[j][0]; osurf->textures[j][3] = osurf->textures[j][2] = osurf->textures[j][1] = osurf->textures[j][0];
} }
if (osurf->numskins) if (osurf->numskins)

View file

@ -28,6 +28,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
qmodel_t *loadmodel; qmodel_t *loadmodel;
char loadname[32]; // for hunk tags char loadname[32]; // for hunk tags
char diskname[MAX_QPATH]; // for loading related name-based files.
static void Mod_LoadSpriteModel (qmodel_t *mod, void *buffer); static void Mod_LoadSpriteModel (qmodel_t *mod, void *buffer);
static void Mod_LoadBrushModel (qmodel_t *mod, void *buffer); static void Mod_LoadBrushModel (qmodel_t *mod, void *buffer);
@ -381,12 +382,16 @@ static qmodel_t *Mod_LoadModel (qmodel_t *mod, qboolean crash)
Con_DPrintf("Ignoring %s from lower priority path\n", newname); Con_DPrintf("Ignoring %s from lower priority path\n", newname);
continue; continue;
} }
memcpy(diskname, newname, sizeof(newname));
break; break;
} }
} }
if (!buf) if (!buf)
{
memcpy(diskname, mod->name, sizeof(mod->name));
buf = COM_LoadStackFile (mod->name, stackbuf, sizeof(stackbuf), & mod->path_id); buf = COM_LoadStackFile (mod->name, stackbuf, sizeof(stackbuf), & mod->path_id);
} }
}
if (!buf) if (!buf)
{ {
if (crash) if (crash)