mirror of
https://github.com/Shpoike/Quakespasm.git
synced 2025-02-02 22:11:22 +00:00
Fix QSS's iqm woes.
This commit is contained in:
parent
5cbb199b5c
commit
dd6368c41c
5 changed files with 204 additions and 42 deletions
161
Quake/gl_mesh.c
161
Quake/gl_mesh.c
|
@ -849,14 +849,36 @@ struct iqmvertexarray
|
|||
{
|
||||
float bbmin[3], bbmax[3];
|
||||
float xyradius, radius;
|
||||
};
|
||||
};*/
|
||||
|
||||
struct iqmextension
|
||||
{
|
||||
unsigned int name;
|
||||
unsigned int num_data, ofs_data;
|
||||
unsigned int ofs_extensions; // pointer to next extension
|
||||
};*/
|
||||
};
|
||||
|
||||
//skin lump is made of 3 parts
|
||||
struct iqmext_fte_skin
|
||||
{
|
||||
unsigned int numskinframes;
|
||||
unsigned int nummeshskins;
|
||||
//unsigned int numskins[nummeshes];
|
||||
//iqmext_fte_skin_skinframe[numskinframes];
|
||||
//iqmext_fte_skin_meshskin mesh0[numskins[0]];
|
||||
//iqmext_fte_skin_meshskin mesh1[numskins[1]]; etc
|
||||
};
|
||||
struct iqmext_fte_skin_skinframe
|
||||
{ //as many as needed
|
||||
unsigned int material_idx;
|
||||
unsigned int shadertext_idx;
|
||||
};
|
||||
struct iqmext_fte_skin_meshskin
|
||||
{
|
||||
unsigned int firstframe; //index into skinframes
|
||||
unsigned int countframes; //skinframes
|
||||
float interval;
|
||||
};
|
||||
|
||||
//IQM Implementation: Copyright 2019 spike, licensed like the rest of quakespasm.
|
||||
static void IQM_LoadVertexes_Float(float *o, size_t c, size_t numverts, const byte *buffer, const struct iqmvertexarray *va)
|
||||
|
@ -1021,6 +1043,102 @@ static void Matrix3x4_Invert_Simple (const float *in1, float *out)
|
|||
out[11] = -(in1[3] * out[8] + in1[7] * out[9] + in1[11] * out[10]);
|
||||
}
|
||||
|
||||
|
||||
static const void *IQM_FindExtension(const char *buffer, size_t buffersize, const char *extname, int index, size_t *extsize)
|
||||
{
|
||||
const struct iqmheader *h = (const struct iqmheader *)buffer;
|
||||
const char *strings = buffer + h->ofs_text;
|
||||
const struct iqmextension *ext;
|
||||
int i;
|
||||
for (i = 0, ext = (const struct iqmextension*)(buffer + h->ofs_extensions); i < h->num_extensions; i++, ext = (const struct iqmextension*)(buffer + ext->ofs_extensions))
|
||||
{
|
||||
if ((const char*)ext > buffer+buffersize || ext->name > h->num_text || ext->ofs_data+ext->num_data>buffersize)
|
||||
break;
|
||||
if (!q_strcasecmp(strings + ext->name, extname) && index-->=0)
|
||||
{
|
||||
*extsize = ext->num_data;
|
||||
return buffer + ext->ofs_data;
|
||||
}
|
||||
}
|
||||
*extsize = 0;
|
||||
return NULL;
|
||||
}
|
||||
static void Mod_LoadIQMSkin (qmodel_t *mod, const struct iqmheader *pinheader, aliashdr_t *osurf, unsigned int meshidx, unsigned int nummeshes, const char *fallback)
|
||||
{
|
||||
unsigned int j, k;
|
||||
size_t extsize;
|
||||
const struct iqmext_fte_skin *iqmext = IQM_FindExtension((const char *)pinheader, pinheader->filesize, "FTE_SKINS", 0, &extsize);
|
||||
if (iqmext)
|
||||
{
|
||||
const struct iqmext_fte_skin_skinframe *skinframe = (const struct iqmext_fte_skin_skinframe*)((const unsigned int*)(iqmext+1) + nummeshes), *sf;
|
||||
const struct iqmext_fte_skin_meshskin *skin = (const struct iqmext_fte_skin_meshskin*)(skinframe+iqmext->numskinframes);
|
||||
osurf->numskins = ((const unsigned int*)(iqmext+1))[meshidx];
|
||||
|
||||
for (j = 0; j < meshidx; j++)
|
||||
skin += ((const unsigned int*)(iqmext+1))[j];
|
||||
for (j = 0; j < osurf->numskins && j < MAX_SKINS; j++, skin++)
|
||||
{
|
||||
if (!skin->countframes)
|
||||
break; //doesn't make sense.
|
||||
if (skin->firstframe+skin->countframes>iqmext->numskinframes)
|
||||
break; //some kind of error
|
||||
sf = skinframe+skin->firstframe;
|
||||
for (k = 0; k < skin->countframes && k < 4; k++, sf++)
|
||||
{
|
||||
const char *texturename = (const char *)pinheader + pinheader->ofs_text + sf->material_idx;
|
||||
char hackytexturename[MAX_QPATH];
|
||||
COM_StripExtension(texturename, hackytexturename, sizeof(hackytexturename));
|
||||
osurf->gltextures[j][k] = TexMgr_LoadImage(mod, texturename, osurf->skinwidth, osurf->skinheight, SRC_EXTERNAL, NULL, hackytexturename, 0, TEXPREF_PAD|TEXPREF_ALPHA|TEXPREF_NOBRIGHT|TEXPREF_MIPMAP);
|
||||
osurf->fbtextures[j][k] = NULL;//TexMgr_LoadImage(mod, fullbrightname, osurf->skinwidth, osurf->skinheight, SRC_EXTERNAL, NULL, fullbrightname, 0, TEXPREF_PAD|TEXPREF_ALPHA|TEXPREF_FULLBRIGHT|TEXPREF_MIPMAP);
|
||||
}
|
||||
for (; k < 4; k++)
|
||||
{
|
||||
osurf->gltextures[j][k] = osurf->gltextures[j][k%skin->countframes];
|
||||
osurf->fbtextures[j][k] = osurf->fbtextures[j][k%skin->countframes];
|
||||
}
|
||||
}
|
||||
osurf->numskins = j;
|
||||
}
|
||||
else
|
||||
{
|
||||
osurf->numskins = 1;
|
||||
for (j = 0; j < 1; j++)
|
||||
{
|
||||
char texturename[MAX_QPATH];
|
||||
char fullbrightname[MAX_QPATH];
|
||||
char *ext;
|
||||
//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
|
||||
if (strchr(fallback, '/') || strchr(fallback, '\\'))
|
||||
{ //so if there's a path then we want to use that.
|
||||
q_strlcpy(texturename, fallback, sizeof(texturename));
|
||||
}
|
||||
else
|
||||
{ //and if there's no path then we want to prefix it with our own.
|
||||
q_strlcpy(texturename, mod->name, sizeof(texturename));
|
||||
*(char*)COM_SkipPath(texturename) = 0;
|
||||
//and concat the specified name
|
||||
q_strlcat(texturename, fallback, sizeof(texturename));
|
||||
}
|
||||
//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);
|
||||
if (*ext)
|
||||
*--ext = 0;
|
||||
//luma has an extra postfix.
|
||||
q_snprintf(fullbrightname, sizeof(fullbrightname), "%s_luma", texturename);
|
||||
osurf->gltextures[j][0] = TexMgr_LoadImage(mod, texturename, osurf->skinwidth, osurf->skinheight, SRC_EXTERNAL, NULL, texturename, 0, TEXPREF_PAD|TEXPREF_ALPHA|TEXPREF_NOBRIGHT|TEXPREF_MIPMAP);
|
||||
osurf->fbtextures[j][0] = NULL;//TexMgr_LoadImage(mod, fullbrightname, osurf->skinwidth, osurf->skinheight, SRC_EXTERNAL, NULL, fullbrightname, 0, TEXPREF_PAD|TEXPREF_ALPHA|TEXPREF_FULLBRIGHT|TEXPREF_MIPMAP);
|
||||
osurf->gltextures[j][3] = osurf->gltextures[j][2] = osurf->gltextures[j][1] = osurf->gltextures[j][0];
|
||||
osurf->fbtextures[j][3] = osurf->fbtextures[j][2] = osurf->fbtextures[j][1] = osurf->fbtextures[j][0];
|
||||
}
|
||||
}
|
||||
if (osurf->numskins)
|
||||
{
|
||||
osurf->skinwidth = osurf->gltextures[0][0]->source_width;
|
||||
osurf->skinheight = osurf->gltextures[0][0]->source_height;
|
||||
}
|
||||
}
|
||||
|
||||
void Mod_LoadIQMModel (qmodel_t *mod, const void *buffer)
|
||||
{
|
||||
const struct iqmheader *pinheader;
|
||||
|
@ -1238,44 +1356,7 @@ void Mod_LoadIQMModel (qmodel_t *mod, const void *buffer)
|
|||
|
||||
//load the textures
|
||||
if (!isDedicated)
|
||||
{
|
||||
const char *pinshader = pintext + LittleLong(pinsurface->material);
|
||||
osurf->numskins = 1;
|
||||
for (j = 0; j < 1; j++, pinshader++)
|
||||
{
|
||||
char texturename[MAX_QPATH];
|
||||
char fullbrightname[MAX_QPATH];
|
||||
char *ext;
|
||||
//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
|
||||
if (strchr(pinshader, '/') || strchr(pinshader, '\\'))
|
||||
{ //so if there's a path then we want to use that.
|
||||
q_strlcpy(texturename, pinshader, sizeof(texturename));
|
||||
}
|
||||
else
|
||||
{ //and if there's no path then we want to prefix it with our own.
|
||||
q_strlcpy(texturename, mod->name, sizeof(texturename));
|
||||
*(char*)COM_SkipPath(texturename) = 0;
|
||||
//and concat the specified name
|
||||
q_strlcat(texturename, pinshader, sizeof(texturename));
|
||||
}
|
||||
//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);
|
||||
if (*ext)
|
||||
*--ext = 0;
|
||||
//luma has an extra postfix.
|
||||
q_snprintf(fullbrightname, sizeof(fullbrightname), "%s_luma", texturename);
|
||||
osurf->gltextures[j][0] = TexMgr_LoadImage(mod, texturename, osurf->skinwidth, osurf->skinheight, SRC_EXTERNAL, NULL, texturename, 0, TEXPREF_PAD|TEXPREF_ALPHA|TEXPREF_NOBRIGHT|TEXPREF_MIPMAP);
|
||||
osurf->fbtextures[j][0] = NULL;//TexMgr_LoadImage(mod, fullbrightname, osurf->skinwidth, osurf->skinheight, SRC_EXTERNAL, NULL, fullbrightname, 0, TEXPREF_PAD|TEXPREF_ALPHA|TEXPREF_FULLBRIGHT|TEXPREF_MIPMAP);
|
||||
osurf->gltextures[j][3] = osurf->gltextures[j][2] = osurf->gltextures[j][1] = osurf->gltextures[j][0];
|
||||
osurf->fbtextures[j][3] = osurf->fbtextures[j][2] = osurf->fbtextures[j][1] = osurf->fbtextures[j][0];
|
||||
}
|
||||
if (osurf->numskins)
|
||||
{
|
||||
osurf->skinwidth = osurf->gltextures[0][0]->source_width;
|
||||
osurf->skinheight = osurf->gltextures[0][0]->source_height;
|
||||
}
|
||||
}
|
||||
Mod_LoadIQMSkin (mod, pinheader, osurf, surf, pinheader->num_meshes, pintext + LittleLong(pinsurface->material));
|
||||
}
|
||||
GLMesh_LoadVertexBuffer (mod, outhdr);
|
||||
|
||||
|
|
|
@ -339,7 +339,23 @@ qmodel_t *Mod_LoadModel (qmodel_t *mod, qboolean crash)
|
|||
if (*mod->name == '*')
|
||||
buf = NULL;
|
||||
else
|
||||
buf = COM_LoadStackFile (mod->name, stackbuf, sizeof(stackbuf), & mod->path_id);
|
||||
{
|
||||
const char *exts = gl_load24bit.value?"iqm":"";
|
||||
char *e;
|
||||
char newname[MAX_QPATH];
|
||||
buf = NULL;
|
||||
q_strlcpy(newname, mod->name, sizeof(newname));
|
||||
e = (char*)COM_FileGetExtension(newname);
|
||||
if (*e) while ((exts = COM_Parse(exts)))
|
||||
{
|
||||
q_strlcpy(e, com_token, sizeof(newname)-(e-newname));
|
||||
buf = COM_LoadStackFile (newname, stackbuf, sizeof(stackbuf), & mod->path_id);
|
||||
if (buf)
|
||||
break;
|
||||
}
|
||||
if (!buf)
|
||||
buf = COM_LoadStackFile (mod->name, stackbuf, sizeof(stackbuf), & mod->path_id);
|
||||
}
|
||||
if (!buf)
|
||||
{
|
||||
if (crash)
|
||||
|
|
|
@ -520,13 +520,19 @@ byte *Image_LoadImage (const char *name, int *width, int *height, enum srcformat
|
|||
char *prefixes[3] = {"", "textures/", "textures/"};
|
||||
int i;
|
||||
|
||||
const char *origname = name;
|
||||
|
||||
*malloced = false;
|
||||
*fmt = SRC_RGBA;
|
||||
|
||||
for (i = 0; i < sizeof(prefixes)/sizeof(prefixes[0]); i++)
|
||||
{
|
||||
if (i == 2) //last resort...
|
||||
{
|
||||
name = COM_SkipPath(name);
|
||||
if (origname == name)
|
||||
continue; //no point trying.
|
||||
}
|
||||
|
||||
q_snprintf (loadfilename, sizeof(loadfilename), "%s%s.dds", prefixes[i], name);
|
||||
COM_FOpenFile (loadfilename, &f, NULL);
|
||||
|
@ -559,6 +565,12 @@ byte *Image_LoadImage (const char *name, int *width, int *height, enum srcformat
|
|||
return Image_LoadPCX (f, width, height);
|
||||
}
|
||||
|
||||
name = origname;
|
||||
q_snprintf (loadfilename, sizeof(loadfilename), "%s%s.lmp", "", name);
|
||||
COM_FOpenFile (loadfilename, &f, NULL);
|
||||
if (f)
|
||||
return Image_LoadLMP (f, width, height);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -983,6 +995,58 @@ byte *Image_LoadPCX (FILE *f, int *width, int *height)
|
|||
return data;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
//
|
||||
// QPIC (aka '.lmp')
|
||||
//
|
||||
//==============================================================================
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int width, height;
|
||||
} lmpheader_t;
|
||||
|
||||
/*
|
||||
============
|
||||
Image_LoadLMP
|
||||
============
|
||||
*/
|
||||
byte *Image_LoadLMP (FILE *f, int *width, int *height)
|
||||
{
|
||||
lmpheader_t qpic;
|
||||
size_t pix;
|
||||
void *data;
|
||||
byte *src;
|
||||
unsigned int *dest;
|
||||
|
||||
fread(&qpic, sizeof(qpic), 1, f);
|
||||
qpic.width = LittleLong (qpic.width);
|
||||
qpic.height = LittleLong (qpic.height);
|
||||
|
||||
pix = qpic.width*qpic.height;
|
||||
|
||||
if (com_filesize != 8+pix)
|
||||
{
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data = (byte *) Hunk_Alloc(pix*4); //+1 to allow reading padding byte on last line
|
||||
dest = data;
|
||||
src = (byte *)data + pix*(4-1);
|
||||
|
||||
fread(src, 1, pix, f);
|
||||
|
||||
while(pix --> 0)
|
||||
*dest++ = d_8to24table[*src++];
|
||||
|
||||
fclose(f);
|
||||
|
||||
*width = qpic.width;
|
||||
*height = qpic.height;
|
||||
return data;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
//
|
||||
// STB_IMAGE_WRITE
|
||||
|
|
|
@ -28,6 +28,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
//be sure to free the hunk after using these loading functions
|
||||
byte *Image_LoadTGA (FILE *f, int *width, int *height);
|
||||
byte *Image_LoadPCX (FILE *f, int *width, int *height);
|
||||
byte *Image_LoadLMP (FILE *f, int *width, int *height);
|
||||
enum srcformat;
|
||||
byte *Image_LoadImage (const char *name, int *width, int *height, enum srcformat *fmt, qboolean *malloced);
|
||||
|
||||
|
|
|
@ -223,7 +223,7 @@ void GLAlias_CreateShaders (void)
|
|||
" wmat[2] += BoneTable[2+3*int(BoneIndex.w)] * BoneWeight.w;"
|
||||
" wmat[3] = vec4(0.0,0.0,0.0,1.0);\n"
|
||||
" vec4 lerpedVert = (vec4(Pose1Vert.xyz, 1.0) * wmat);\n"
|
||||
" float dot1 = r_avertexnormal_dot((vec4(Pose1Vert.xyz, 0.0) * wmat).xyz);\n"
|
||||
" float dot1 = r_avertexnormal_dot(normalize((vec4(Pose1Normal.xyz, 0.0) * wmat).xyz));\n"
|
||||
"#else\n"
|
||||
" vec4 lerpedVert = mix(vec4(Pose1Vert.xyz, 1.0), vec4(Pose2Vert.xyz, 1.0), Blend);\n"
|
||||
" float dot1 = mix(r_avertexnormal_dot(Pose1Normal), r_avertexnormal_dot(Pose2Normal), Blend);\n"
|
||||
|
|
Loading…
Reference in a new issue