fix the iqm loader to be more versatile, so we now support more exotic forms of iqm.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4918 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2015-06-26 12:15:56 +00:00
parent f35aa1d123
commit f7b61a1dd8

View file

@ -6166,6 +6166,214 @@ galisskeletaltransforms_t *IQM_ImportTransforms(int *resultcount, int inverts, f
}
*/
static qboolean IQM_ImportArray4B(qbyte *base, struct iqmvertexarray *src, byte_vec4_t *out, size_t count, unsigned int maxval)
{
size_t i;
unsigned int j;
unsigned int sz = LittleLong(src->size);
unsigned int fmt = LittleLong(src->format);
unsigned int offset = LittleLong(src->offset);
qboolean invalid = false;
maxval = min(256,maxval);
if (!offset)
{
sz = 0;
fmt = IQM_UBYTE;
}
switch(fmt)
{
default:
sz = 0;
invalid = true;
break;
case IQM_BYTE: //FIXME: should be signed, but this makes no sense for our uses
case IQM_UBYTE:
{
qbyte *in = (qbyte*)(base+offset);
/*if (sz == 4)
memcpy(out, in, count * sizeof(*out)); //the fast path.
else*/ for (i = 0; i < count; i++)
{
for (j = 0; j < 4 && j < sz; j++)
{
if (in[i*sz+j] >= maxval)
{
out[i][j] = 0;
invalid = true;
}
else
out[i][j] = in[i*sz+j];
}
}
}
break;
case IQM_SHORT://FIXME: should be signed, but this makes no sense for our uses
case IQM_USHORT:
{
unsigned short *in = (unsigned short*)(base+offset);
for (i = 0; i < count; i++)
{
for (j = 0; j < 4 && j < sz; j++)
{
if (in[i*sz+j] >= maxval)
{
out[i][j] = 0;
invalid = true;
}
else
out[i][j] = in[i*sz+j];
}
}
}
break;
case IQM_INT://FIXME: should be signed, but this makes no sense for our uses
case IQM_UINT:
{
unsigned int *in = (unsigned int*)(base+offset);
for (i = 0; i < count; i++)
{
for (j = 0; j < 4 && j < sz; j++)
{
if (in[i*sz+j] >= maxval)
{
out[i][j] = 0;
invalid = true;
}
else
out[i][j] = in[i*sz+j];
}
}
}
break;
//float types don't really make sense
}
//if there were not enough elements, pad it.
if (sz < 4)
{
for (i = 0; i < count; i++)
{
for (j = sz; j < 4; j++)
out[i][j] = 0;
}
}
return !invalid;
}
static void IQM_ImportArrayF(qbyte *base, struct iqmvertexarray *src, float *out, size_t e, size_t count, float *def)
{
size_t i;
unsigned int j;
unsigned int sz = LittleLong(src->size);
unsigned int fmt = LittleLong(src->format);
unsigned int offset = LittleLong(src->offset);
if (!offset)
{
sz = 0;
fmt = IQM_FLOAT;
}
switch(fmt)
{
default:
sz = 0;
break;
case IQM_BYTE: //FIXME: should be signed
{
char *in = (qbyte*)(base+offset);
for (i = 0; i < count; i++)
{
for (j = 0; j < e && j < sz; j++)
out[i*e+j] = in[i*sz+j] * (1.0/127);
}
}
break;
case IQM_UBYTE:
{
qbyte *in = (qbyte*)(base+offset);
for (i = 0; i < count; i++)
{
for (j = 0; j < e && j < sz; j++)
out[i*e+j] = in[i*sz+j] * (1.0/255);
}
}
break;
case IQM_SHORT:
{
short *in = (short*)(base+offset);
for (i = 0; i < count; i++)
{
for (j = 0; j < e && j < sz; j++)
out[i*e+j] = in[i*sz+j] * (1.0/32767);
}
}
break;
case IQM_USHORT:
{
unsigned short *in = (unsigned short*)(base+offset);
for (i = 0; i < count; i++)
{
for (j = 0; j < e && j < sz; j++)
out[i*e+j] = in[i*sz+j] * (1.0/65535);
}
}
break;
case IQM_INT://FIXME: should be signed
case IQM_UINT:
{
unsigned int *in = (unsigned int*)(base+offset);
for (i = 0; i < count; i++)
{
for (j = 0; j < e && j < sz; j++)
out[i*e+j] = in[i*sz+j];
}
}
break;
/*case IQM_HALF:
{
__fp16 *in = (qbyte*)(base+offset);
for (i = 0; i < count; i++)
{
for (j = 0; j < e && j < sz; j++)
out[i*e+j] = in[i*sz+j];
}
}
break;*/
case IQM_FLOAT:
{
float *in = (float*)(base+offset);
if (e == sz)
memcpy(out, in, e * sizeof(float) * count);
else for (i = 0; i < count; i++)
{
for (j = 0; j < e && j < sz; j++)
out[i*e+j] = in[i*sz+j];
}
}
break;
case IQM_DOUBLE:
{
double *in = (double*)(base+offset);
for (i = 0; i < count; i++)
{
for (j = 0; j < e && j < sz; j++)
out[i*e+j] = in[i*sz+j];
}
}
break;
}
//if there were not enough elements, pad it.
if (sz < e)
{
for (i = 0; i < count; i++)
{
for (j = sz; j < e; j++)
out[i*e+j] = def[j];
}
}
}
galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, char *buffer, size_t fsize)
{
struct iqmheader *h = (struct iqmheader *)buffer;
@ -6177,10 +6385,13 @@ galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, char *buffer, size_t fsize)
char *strings;
float *vpos = NULL, *vtcoord = NULL, *vnorm = NULL, *vtang = NULL, *vrgbaf = NULL;
unsigned char *vbone = NULL, *vweight = NULL, *vrgbaub = NULL;
float *vtang = NULL;
struct iqmvertexarray vpos = {0}, vnorm = {0}, vtcoord = {0}, vbone = {0}, vweight = {0}, vrgba = {0};
unsigned int type, fmt, size, offset;
unsigned short *framedata;
vec4_t defaultcolour = {1,1,1,1};
vec4_t defaultweight = {0,0,0,0};
vec4_t defaultvert = {0,0,0,1};
int memsize;
qbyte *obase=NULL;
@ -6230,24 +6441,22 @@ galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, char *buffer, size_t fsize)
fmt = LittleLong(varray[i].format);
size = LittleLong(varray[i].size);
offset = LittleLong(varray[i].offset);
if (type == IQM_POSITION && fmt == IQM_FLOAT && size == 3)
vpos = (float*)(buffer + offset);
else if (type == IQM_TEXCOORD && fmt == IQM_FLOAT && size == 2)
vtcoord = (float*)(buffer + offset);
else if (type == IQM_NORMAL && fmt == IQM_FLOAT && size == 3)
vnorm = (float*)(buffer + offset);
else if (type == IQM_TANGENT && fmt == IQM_FLOAT && size == 4) /*yup, 4*/
if (type == IQM_POSITION)
vpos = varray[i];
else if (type == IQM_TEXCOORD)
vtcoord = varray[i];
else if (type == IQM_NORMAL)
vnorm = varray[i];
else if (type == IQM_TANGENT && fmt == IQM_FLOAT && size == 4) /*yup, 4, extra is side, for the bitangent*/
vtang = (float*)(buffer + offset);
else if (type == IQM_BLENDINDEXES && fmt == IQM_UBYTE && size == 4)
vbone = (unsigned char *)(buffer + offset);
else if (type == IQM_BLENDWEIGHTS && fmt == IQM_UBYTE && size == 4)
vweight = (unsigned char *)(buffer + offset);
else if (type == IQM_COLOR && fmt == IQM_UBYTE && size == 4)
vrgbaub = (qbyte *)(buffer + offset);
else if (type == IQM_COLOR && fmt == IQM_FLOAT && size == 4)
vrgbaf = (float *)(buffer + offset);
else if (type == IQM_BLENDINDEXES)
vbone = varray[i];
else if (type == IQM_BLENDWEIGHTS)
vweight = varray[i];
else if (type == IQM_COLOR)
vrgba = varray[i];
else
Con_Printf("Unrecognised iqm info\n");
Con_Printf("Unrecognised iqm info (type=%i, fmt=%i, size=%i)\n", type, fmt, size);
}
if (!h->num_meshes)
@ -6260,12 +6469,12 @@ galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, char *buffer, size_t fsize)
//we also require texcoords because we can.
//we don't require normals
//we don't require weights, but such models won't animate.
if (h->num_vertexes > 0 && (!vpos || !vtcoord))
if (h->num_vertexes > 0 && (!vpos.offset || !vtcoord.offset))
{
Con_Printf("%s is missing vertex array data\n", mod->name);
return NULL;
}
noweights = !vbone || !vweight;
noweights = !vbone.offset || !vweight.offset;
if (noweights)
{
if (h->num_frames || h->num_anims || h->num_joints)
@ -6348,11 +6557,11 @@ galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, char *buffer, size_t fsize)
oweight = NULL;
}
#ifndef SERVERONLY
if (vtcoord)
if (vtcoord.offset)
dalloc(otcoords, h->num_vertexes);
else
otcoords = NULL;
if (vrgbaf || vrgbaub)
if (vrgba.offset)
dalloc(orgbaf, h->num_vertexes);
else
orgbaf = NULL;
@ -6545,45 +6754,30 @@ galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, char *buffer, size_t fsize)
gai[i].shares_verts = i;
gai[i].numverts = LittleLong(mesh[i].num_vertexes);
gai[i].ofs_skel_xyz = (opos+offset);
gai[i].ofs_skel_norm = vnorm?(onorm1+offset):NULL;
gai[i].ofs_skel_svect = (vnorm&&vtang)?(onorm2+offset):NULL;
gai[i].ofs_skel_tvect = (vnorm&&vtang)?(onorm3+offset):NULL;
gai[i].ofs_skel_norm = (onorm1+offset);
gai[i].ofs_skel_svect = (onorm2+offset);
gai[i].ofs_skel_tvect = (onorm3+offset);
gai[i].ofs_skel_idx = oindex?(oindex+offset):NULL;
gai[i].ofs_skel_weight = oweight?(oweight+offset):NULL;
}
if (!noweights)
{
for (i = 0; i < h->num_vertexes; i++)
{
Vector4Copy(vbone+i*4, oindex[i]);
Vector4Scale(vweight+i*4, 1/255.0, oweight[i]);
//FIXME: should we be normalising?
if (!oweight[i][0] && !oweight[i][1] && !oweight[i][2] && !oweight[i][3])
oweight[i][0] = 1;
}
if (!IQM_ImportArray4B(buffer, &vbone, oindex, h->num_vertexes, h->num_joints))
Con_Printf(CON_WARNING "Invalid bone indexes detected inside %s\n", mod->name);
IQM_ImportArrayF(buffer, &vweight, (float*)oweight, 4, h->num_vertexes, defaultweight);
}
if (otcoords)
memcpy(otcoords, vtcoord, h->num_vertexes*sizeof(*otcoords));
IQM_ImportArrayF(buffer, &vtcoord, (float*)otcoords, 2, h->num_vertexes, defaultweight);
if (orgbaf)
{
if (vrgbaf)
memcpy(orgbaf, vrgbaf, h->num_vertexes*sizeof(*orgbaf));
else
IQM_ImportArrayF(buffer, &vrgba, (float*)orgbaf, 4, h->num_vertexes, defaultcolour);
IQM_ImportArrayF(buffer, &vnorm, (float*)onorm1, 3, h->num_vertexes, defaultcolour);
IQM_ImportArrayF(buffer, &vpos, (float*)opos, sizeof(opos[0])/sizeof(float), h->num_vertexes, defaultvert);
if (vnorm.offset && vtang)
{
for (i = 0; i < h->num_vertexes; i++)
Vector4Scale(vrgbaub+i*4, 1/255.0f, orgbaf[i]);
}
}
for (i = 0; i < h->num_vertexes; i++)
{
VectorCopy(vpos+i*3, opos[i]);
if (vnorm)
{
VectorCopy(vnorm+i*3, onorm1[i]);
}
if (vnorm && vtang)
{
VectorCopy(vtang+i*4, onorm2[i]);
if(LittleFloat(vtang[i*4 + 3]) < 0)
@ -6592,6 +6786,18 @@ galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, char *buffer, size_t fsize)
CrossProduct(onorm1[i], onorm2[i], onorm3[i]);
}
}
else if (h->num_vertexes)
{ //make something up
for (i = 0; i < h->num_meshes; i++)
{
Mod_AccumulateTextureVectors(gai[i].ofs_skel_xyz, gai[i].ofs_st_array, gai[i].ofs_skel_norm, gai[i].ofs_skel_svect, gai[i].ofs_skel_tvect, gai[i].ofs_indexes, gai[i].numindexes);
}
for (i = 0; i < h->num_meshes; i++)
{
Mod_NormaliseTextureVectors(gai[i].ofs_skel_norm, gai[i].ofs_skel_svect, gai[i].ofs_skel_tvect, gai[i].numverts);
}
}
return gai;
}