mirror of
https://github.com/Shpoike/Quakespasm.git
synced 2025-03-10 20:11:42 +00:00
Hacked in support for IQMs.
This commit is contained in:
parent
34414e41e1
commit
e38664c222
7 changed files with 965 additions and 80 deletions
629
Quake/gl_mesh.c
629
Quake/gl_mesh.c
|
@ -110,9 +110,9 @@ void GL_MakeAliasModelDisplayLists (qmodel_t *m, aliashdr_t *paliashdr)
|
|||
switch(paliashdr->poseverttype)
|
||||
{
|
||||
case PV_QUAKEFORGE:
|
||||
verts = (trivertx_t *) Hunk_Alloc (paliashdr->numposes * paliashdr->numverts_vbo*2 * sizeof(*verts));
|
||||
verts = (trivertx_t *) Hunk_Alloc (paliashdr->nummorphposes * paliashdr->numverts_vbo*2 * sizeof(*verts));
|
||||
paliashdr->vertexes = (byte *)verts - (byte *)paliashdr;
|
||||
for (i=0 ; i<paliashdr->numposes ; i++)
|
||||
for (i=0 ; i<paliashdr->nummorphposes ; i++)
|
||||
for (j=0 ; j<paliashdr->numverts_vbo ; j++)
|
||||
{
|
||||
verts[i*paliashdr->numverts_vbo*2 + j] = poseverts_mdl[i][desc[j].vertindex];
|
||||
|
@ -120,12 +120,13 @@ void GL_MakeAliasModelDisplayLists (qmodel_t *m, aliashdr_t *paliashdr)
|
|||
}
|
||||
break;
|
||||
case PV_QUAKE1:
|
||||
verts = (trivertx_t *) Hunk_Alloc (paliashdr->numposes * paliashdr->numverts_vbo * sizeof(*verts));
|
||||
verts = (trivertx_t *) Hunk_Alloc (paliashdr->nummorphposes * paliashdr->numverts_vbo * sizeof(*verts));
|
||||
paliashdr->vertexes = (byte *)verts - (byte *)paliashdr;
|
||||
for (i=0 ; i<paliashdr->numposes ; i++)
|
||||
for (i=0 ; i<paliashdr->nummorphposes ; i++)
|
||||
for (j=0 ; j<paliashdr->numverts_vbo ; j++)
|
||||
verts[i*paliashdr->numverts_vbo + j] = poseverts_mdl[i][desc[j].vertindex];
|
||||
break;
|
||||
case PV_IQM:
|
||||
case PV_QUAKE3:
|
||||
break; //invalid here.
|
||||
}
|
||||
|
@ -167,13 +168,16 @@ void GLMesh_LoadVertexBuffer (qmodel_t *m, aliashdr_t *mainhdr)
|
|||
switch(hdr->poseverttype)
|
||||
{
|
||||
case PV_QUAKE1:
|
||||
totalvbosize += (hdr->numposes * hdr->numverts_vbo * sizeof (meshxyz_mdl_t)); // ericw -- what RMQEngine called nummeshframes is called numposes in QuakeSpasm
|
||||
totalvbosize += (hdr->nummorphposes * hdr->numverts_vbo * sizeof (meshxyz_mdl_t)); // ericw -- what RMQEngine called nummeshframes is called numposes in QuakeSpasm
|
||||
break;
|
||||
case PV_QUAKEFORGE:
|
||||
totalvbosize += (hdr->numposes * hdr->numverts_vbo * sizeof (meshxyz_mdl16_t));
|
||||
totalvbosize += (hdr->nummorphposes * hdr->numverts_vbo * sizeof (meshxyz_mdl16_t));
|
||||
break;
|
||||
case PV_QUAKE3:
|
||||
totalvbosize += (hdr->numposes * hdr->numverts_vbo * sizeof (meshxyz_md3_t));
|
||||
totalvbosize += (hdr->nummorphposes * hdr->numverts_vbo * sizeof (meshxyz_md3_t));
|
||||
break;
|
||||
case PV_IQM:
|
||||
totalvbosize += (hdr->nummorphposes * hdr->numverts_vbo * sizeof (iqmvert_t));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -228,11 +232,11 @@ void GLMesh_LoadVertexBuffer (qmodel_t *m, aliashdr_t *mainhdr)
|
|||
switch(hdr->poseverttype)
|
||||
{
|
||||
case PV_QUAKE1:
|
||||
for (f = 0; f < hdr->numposes; f++) // ericw -- what RMQEngine called nummeshframes is called numposes in QuakeSpasm
|
||||
for (f = 0; f < hdr->nummorphposes; f++) // ericw -- what RMQEngine called nummeshframes is called numposes in QuakeSpasm
|
||||
{
|
||||
int v;
|
||||
meshxyz_mdl_t *xyz = (meshxyz_mdl_t *) (vbodata + vertofs);
|
||||
const trivertx_t *tv = (trivertx_t*)trivertexes + (hdr->numverts_vbo * f);
|
||||
const trivertx_t *tv = (const trivertx_t*)trivertexes + (hdr->numverts_vbo * f);
|
||||
vertofs += hdr->numverts_vbo * sizeof (*xyz);
|
||||
|
||||
for (v = 0; v < hdr->numverts_vbo; v++, tv++)
|
||||
|
@ -253,11 +257,11 @@ void GLMesh_LoadVertexBuffer (qmodel_t *m, aliashdr_t *mainhdr)
|
|||
}
|
||||
break;
|
||||
case PV_QUAKEFORGE:
|
||||
for (f = 0; f < hdr->numposes; f++) // ericw -- what RMQEngine called nummeshframes is called numposes in QuakeSpasm
|
||||
for (f = 0; f < hdr->nummorphposes; f++) // ericw -- what RMQEngine called nummeshframes is called numposes in QuakeSpasm
|
||||
{
|
||||
int v;
|
||||
meshxyz_mdl16_t *xyz = (meshxyz_mdl16_t *) (vbodata + vertofs);
|
||||
const trivertx_t *tv = (trivertx_t*)trivertexes + (hdr->numverts_vbo*2 * f);
|
||||
const trivertx_t *tv = (const trivertx_t*)trivertexes + (hdr->numverts_vbo*2 * f);
|
||||
vertofs += hdr->numverts_vbo * sizeof (*xyz);
|
||||
|
||||
for (v = 0; v < hdr->numverts_vbo; v++, tv++)
|
||||
|
@ -278,11 +282,11 @@ void GLMesh_LoadVertexBuffer (qmodel_t *m, aliashdr_t *mainhdr)
|
|||
}
|
||||
break;
|
||||
case PV_QUAKE3:
|
||||
for (f = 0; f < hdr->numposes; f++) // ericw -- what RMQEngine called nummeshframes is called numposes in QuakeSpasm
|
||||
for (f = 0; f < hdr->nummorphposes; f++) // ericw -- what RMQEngine called nummeshframes is called numposes in QuakeSpasm
|
||||
{
|
||||
int v;
|
||||
meshxyz_md3_t *xyz = (meshxyz_md3_t *) (vbodata + vertofs);
|
||||
const md3XyzNormal_t *tv = (md3XyzNormal_t*)trivertexes + (hdr->numverts_vbo * f);
|
||||
const md3XyzNormal_t *tv = (const md3XyzNormal_t*)trivertexes + (hdr->numverts_vbo * f);
|
||||
float lat,lng;
|
||||
vertofs += hdr->numverts_vbo * sizeof (*xyz);
|
||||
|
||||
|
@ -305,6 +309,18 @@ void GLMesh_LoadVertexBuffer (qmodel_t *m, aliashdr_t *mainhdr)
|
|||
}
|
||||
}
|
||||
break;
|
||||
case PV_IQM:
|
||||
for (f = 0; f < hdr->nummorphposes; f++) // ericw -- what RMQEngine called nummeshframes is called numposes in QuakeSpasm
|
||||
{
|
||||
int v;
|
||||
iqmvert_t *xyz = (iqmvert_t *) (vbodata + vertofs);
|
||||
const iqmvert_t *tv = (const iqmvert_t*)trivertexes + (hdr->numverts_vbo * f);
|
||||
vertofs += hdr->numverts_vbo * sizeof (*xyz);
|
||||
|
||||
for (v = 0; v < hdr->numverts_vbo; v++, tv++)
|
||||
xyz[v] = *tv;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// fill in the ST coords at the end of the buffer
|
||||
|
@ -337,6 +353,9 @@ void GLMesh_LoadVertexBuffer (qmodel_t *m, aliashdr_t *mainhdr)
|
|||
st[f].st[1] = vscale * ((float) desc[f].st[1] + 0.5f) / (float) hdr->skinheight;
|
||||
}
|
||||
break;
|
||||
case PV_IQM:
|
||||
//st coords are interleaved.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -591,7 +610,6 @@ void Mod_LoadMD3Model (qmodel_t *mod, void *buffer)
|
|||
osurf->frames[ival].firstpose = ival;
|
||||
osurf->frames[ival].numposes = 1;
|
||||
osurf->frames[ival].interval = 0.1;
|
||||
osurf->frames[ival].frame = ival;
|
||||
|
||||
q_strlcpy(osurf->frames[ival].name, pinframes->name, sizeof(osurf->frames[ival].name));
|
||||
for (j = 0; j < 3; j++)
|
||||
|
@ -605,7 +623,7 @@ void Mod_LoadMD3Model (qmodel_t *mod, void *buffer)
|
|||
poutvert += osurf->numverts;
|
||||
pinvert += osurf->numverts;
|
||||
}
|
||||
osurf->numposes = osurf->numframes = numframes;
|
||||
osurf->nummorphposes = osurf->numframes = numframes;
|
||||
|
||||
osurf->numtris = LittleLong(pinsurface->numTriangles);
|
||||
osurf->numindexes = osurf->numtris*3;
|
||||
|
@ -686,6 +704,587 @@ void Mod_LoadMD3Model (qmodel_t *mod, void *buffer)
|
|||
mod->flags = LittleLong (pinheader->flags);
|
||||
|
||||
|
||||
mod->type = mod_alias;
|
||||
|
||||
Mod_CalcAliasBounds (outhdr); //johnfitz
|
||||
|
||||
//
|
||||
// move the complete, relocatable alias model to the cache
|
||||
//
|
||||
end = Hunk_LowMark ();
|
||||
total = end - start;
|
||||
|
||||
Cache_Alloc (&mod->cache, total, loadname);
|
||||
if (!mod->cache.data)
|
||||
return;
|
||||
memcpy (mod->cache.data, outhdr, total);
|
||||
|
||||
Hunk_FreeToLowMark (start);
|
||||
}
|
||||
|
||||
/*
|
||||
=================================================================
|
||||
InterQuake Models.
|
||||
=================================================================
|
||||
|
||||
Header:
|
||||
*/
|
||||
//Copyright (c) 2010-2019 Lee Salzman
|
||||
//MIT License etc at: https://github.com/lsalzman/iqm
|
||||
#define IQM_MAGIC "INTERQUAKEMODEL"
|
||||
#define IQM_VERSION 2
|
||||
|
||||
struct iqmheader
|
||||
{
|
||||
char magic[16];
|
||||
unsigned int version;
|
||||
unsigned int filesize;
|
||||
unsigned int flags;
|
||||
unsigned int num_text, ofs_text; //text strings
|
||||
unsigned int num_meshes, ofs_meshes; //surface info
|
||||
unsigned int num_vertexarrays, num_vertexes, ofs_vertexarrays; //for loading vertex data
|
||||
unsigned int num_triangles, ofs_triangles, ofs_adjacency; //the index data+neighbours(which we ignore)
|
||||
unsigned int num_joints, ofs_joints; //mesh joints (base pose info)
|
||||
unsigned int num_poses, ofs_poses; //animated joints (num_poses should match num_joints)
|
||||
unsigned int num_anims, ofs_anims; //animations info
|
||||
unsigned int num_frames, num_framechannels, ofs_frames, ofs_bounds; //the actual per-pose(aka:single-frame) data
|
||||
unsigned int num_comment, ofs_comment; //extra stuff
|
||||
unsigned int num_extensions, ofs_extensions;//extra stuff
|
||||
};
|
||||
|
||||
struct iqmmesh
|
||||
{
|
||||
unsigned int name;
|
||||
unsigned int material;
|
||||
unsigned int first_vertex, num_vertexes;
|
||||
unsigned int first_triangle, num_triangles;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
IQM_POSITION = 0,
|
||||
IQM_TEXCOORD = 1,
|
||||
IQM_NORMAL = 2,
|
||||
IQM_TANGENT = 3,
|
||||
IQM_BLENDINDEXES = 4,
|
||||
IQM_BLENDWEIGHTS = 5,
|
||||
IQM_COLOR = 6,
|
||||
IQM_CUSTOM = 0x10
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
IQM_BYTE = 0,
|
||||
IQM_UBYTE = 1,
|
||||
IQM_SHORT = 2,
|
||||
IQM_USHORT = 3,
|
||||
IQM_INT = 4,
|
||||
IQM_UINT = 5,
|
||||
IQM_HALF = 6,
|
||||
IQM_FLOAT = 7,
|
||||
IQM_DOUBLE = 8
|
||||
};
|
||||
|
||||
/*struct iqmtriangle
|
||||
{
|
||||
unsigned int vertex[3];
|
||||
};
|
||||
|
||||
struct iqmadjacency
|
||||
{
|
||||
unsigned int triangle[3];
|
||||
};
|
||||
|
||||
struct iqmjointv1
|
||||
{
|
||||
unsigned int name;
|
||||
int parent;
|
||||
float translate[3], rotate[3], scale[3];
|
||||
};*/
|
||||
|
||||
struct iqmjoint
|
||||
{
|
||||
unsigned int name;
|
||||
int parent;
|
||||
float translate[3], rotate[4], scale[3];
|
||||
};
|
||||
|
||||
/*struct iqmposev1
|
||||
{
|
||||
int parent;
|
||||
unsigned int mask;
|
||||
float channeloffset[9];
|
||||
float channelscale[9];
|
||||
};*/
|
||||
|
||||
struct iqmpose
|
||||
{
|
||||
int parent;
|
||||
unsigned int mask;
|
||||
float channeloffset[10];
|
||||
float channelscale[10];
|
||||
};
|
||||
|
||||
struct iqmanim
|
||||
{
|
||||
unsigned int name;
|
||||
unsigned int first_frame, num_frames;
|
||||
float framerate;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
IQM_LOOP = 1<<0
|
||||
};
|
||||
|
||||
struct iqmvertexarray
|
||||
{
|
||||
unsigned int type;
|
||||
unsigned int flags;
|
||||
unsigned int format;
|
||||
unsigned int size;
|
||||
unsigned int offset;
|
||||
};
|
||||
|
||||
/*struct iqmbounds
|
||||
{
|
||||
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
|
||||
};*/
|
||||
|
||||
//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)
|
||||
{
|
||||
size_t j, k;
|
||||
if (c != va->size)
|
||||
return; //erk, too lazy to handle weirdness.
|
||||
switch(va->format)
|
||||
{
|
||||
// case IQM_BYTE:
|
||||
case IQM_UBYTE:
|
||||
{ //weights+colours are often normalised bytes.
|
||||
const byte *in = (const byte*)(buffer+va->offset);
|
||||
for (j = 0; j < numverts; j++, in+=va->size, o+=sizeof(iqmvert_t)/sizeof(*o))
|
||||
{
|
||||
for (k = 0; k < c; k++)
|
||||
o[k] = in[k]/255.0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
// case IQM_SHORT:
|
||||
// case IQM_USHORT:
|
||||
// case IQM_INT:
|
||||
// case IQM_UINT:
|
||||
// case IQM_HALF:
|
||||
case IQM_FLOAT:
|
||||
{
|
||||
const float *in = (const float*)(buffer+va->offset);
|
||||
for (j = 0; j < numverts; j++, in+=va->size, o+=sizeof(iqmvert_t)/sizeof(*o))
|
||||
{
|
||||
for (k = 0; k < c; k++)
|
||||
o[k] = in[k];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IQM_DOUBLE:
|
||||
{ //truncate, sorry...
|
||||
const double *in = (const double*)(buffer+va->offset);
|
||||
for (j = 0; j < numverts; j++, in+=va->size, o+=sizeof(iqmvert_t)/sizeof(*o))
|
||||
{
|
||||
for (k = 0; k < c; k++)
|
||||
o[k] = in[k];
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return; //oh bum. my laziness strikes again.
|
||||
}
|
||||
}
|
||||
|
||||
static void IQM_LoadVertexes_Index(byte *o, size_t c, size_t numverts, const byte *buffer, const struct iqmvertexarray *va)
|
||||
{
|
||||
size_t j, k;
|
||||
if (c != va->size)
|
||||
return; //erk, too lazy to handle weirdness.
|
||||
switch(va->format)
|
||||
{
|
||||
// case IQM_BYTE:
|
||||
case IQM_UBYTE:
|
||||
{
|
||||
const byte *in = (const byte*)(buffer+va->offset);
|
||||
for (j = 0; j < numverts; j++, in+=va->size, o+=sizeof(iqmvert_t)/sizeof(*o))
|
||||
{
|
||||
for (k = 0; k < c; k++)
|
||||
o[k] = in[k];
|
||||
}
|
||||
}
|
||||
break;
|
||||
// case IQM_SHORT:
|
||||
case IQM_USHORT:
|
||||
{ //truncate...
|
||||
const unsigned short *in = (const unsigned short*)(buffer+va->offset);
|
||||
for (j = 0; j < numverts; j++, in+=va->size, o+=sizeof(iqmvert_t)/sizeof(*o))
|
||||
{
|
||||
for (k = 0; k < c; k++)
|
||||
o[k] = in[k];
|
||||
}
|
||||
}
|
||||
break;
|
||||
// case IQM_INT:
|
||||
case IQM_UINT:
|
||||
{ //truncate... noesis likes writing these.
|
||||
const unsigned int *in = (const unsigned int*)(buffer+va->offset);
|
||||
for (j = 0; j < numverts; j++, in+=va->size, o+=sizeof(iqmvert_t)/sizeof(*o))
|
||||
{
|
||||
for (k = 0; k < c; k++)
|
||||
o[k] = in[k];
|
||||
}
|
||||
}
|
||||
break;
|
||||
// case IQM_HALF:
|
||||
// case IQM_FLOAT:
|
||||
// case IQM_DOUBLE:
|
||||
default:
|
||||
return; //oh bum. my laziness strikes again.
|
||||
}
|
||||
}
|
||||
|
||||
static void GenMatrixPosQuat4Scale(const vec3_t pos, const vec4_t quat, const vec3_t scale, float result[12])
|
||||
{
|
||||
float xx, xy, xz, xw, yy, yz, yw, zz, zw;
|
||||
float x2, y2, z2;
|
||||
float s;
|
||||
x2 = quat[0] + quat[0];
|
||||
y2 = quat[1] + quat[1];
|
||||
z2 = quat[2] + quat[2];
|
||||
|
||||
xx = quat[0] * x2; xy = quat[0] * y2; xz = quat[0] * z2;
|
||||
yy = quat[1] * y2; yz = quat[1] * z2; zz = quat[2] * z2;
|
||||
xw = quat[3] * x2; yw = quat[3] * y2; zw = quat[3] * z2;
|
||||
|
||||
s = scale[0];
|
||||
result[0*4+0] = s*(1.0f - (yy + zz));
|
||||
result[1*4+0] = s*(xy + zw);
|
||||
result[2*4+0] = s*(xz - yw);
|
||||
|
||||
s = scale[1];
|
||||
result[0*4+1] = s*(xy - zw);
|
||||
result[1*4+1] = s*(1.0f - (xx + zz));
|
||||
result[2*4+1] = s*(yz + xw);
|
||||
|
||||
s = scale[2];
|
||||
result[0*4+2] = s*(xz + yw);
|
||||
result[1*4+2] = s*(yz - xw);
|
||||
result[2*4+2] = s*(1.0f - (xx + yy));
|
||||
|
||||
result[0*4+3] = pos[0];
|
||||
result[1*4+3] = pos[1];
|
||||
result[2*4+3] = pos[2];
|
||||
}
|
||||
static void Matrix3x4_Invert_Simple (const float *in1, float *out)
|
||||
{
|
||||
// we only support uniform scaling, so assume the first row is enough
|
||||
// (note the lack of sqrt here, because we're trying to undo the scaling,
|
||||
// this means multiplying by the inverse scale twice - squaring it, which
|
||||
// makes the sqrt a waste of time)
|
||||
#if 1
|
||||
double scale = 1.0 / (in1[0] * in1[0] + in1[1] * in1[1] + in1[2] * in1[2]);
|
||||
#else
|
||||
double scale = 3.0 / sqrt
|
||||
(in1->m[0][0] * in1->m[0][0] + in1->m[0][1] * in1->m[0][1] + in1->m[0][2] * in1->m[0][2]
|
||||
+ in1->m[1][0] * in1->m[1][0] + in1->m[1][1] * in1->m[1][1] + in1->m[1][2] * in1->m[1][2]
|
||||
+ in1->m[2][0] * in1->m[2][0] + in1->m[2][1] * in1->m[2][1] + in1->m[2][2] * in1->m[2][2]);
|
||||
scale *= scale;
|
||||
#endif
|
||||
|
||||
// invert the rotation by transposing and multiplying by the squared
|
||||
// recipricol of the input matrix scale as described above
|
||||
out[0] = in1[0] * scale;
|
||||
out[1] = in1[4] * scale;
|
||||
out[2] = in1[8] * scale;
|
||||
out[4] = in1[1] * scale;
|
||||
out[5] = in1[5] * scale;
|
||||
out[6] = in1[9] * scale;
|
||||
out[8] = in1[2] * scale;
|
||||
out[9] = in1[6] * scale;
|
||||
out[10] = in1[10] * scale;
|
||||
|
||||
// invert the translate
|
||||
out[3] = -(in1[3] * out[0] + in1[7] * out[1] + in1[11] * out[2]);
|
||||
out[7] = -(in1[3] * out[4] + in1[7] * out[5] + in1[11] * out[6]);
|
||||
out[11] = -(in1[3] * out[8] + in1[7] * out[9] + in1[11] * out[10]);
|
||||
}
|
||||
|
||||
void Mod_LoadIQMModel (qmodel_t *mod, const void *buffer)
|
||||
{
|
||||
const struct iqmheader *pinheader;
|
||||
const char *pintext;
|
||||
const struct iqmmesh *pinsurface;
|
||||
const struct iqmanim *pinframes;
|
||||
const unsigned int *pintriangle;
|
||||
unsigned short *poutindexes;
|
||||
iqmvert_t *poutvert;
|
||||
int size;
|
||||
int start, end, total;
|
||||
int ival, j, a;
|
||||
int numsurfs, surf;
|
||||
aliashdr_t *outhdr;
|
||||
int numverts, firstidx, firstvert;
|
||||
int numanims;
|
||||
|
||||
bonepose_t *outposes;
|
||||
boneinfo_t *outbones;
|
||||
int numposes, numjoints;
|
||||
|
||||
start = Hunk_LowMark ();
|
||||
|
||||
pinheader = (const struct iqmheader *)buffer;
|
||||
|
||||
|
||||
if (strcmp(pinheader->magic, IQM_MAGIC))
|
||||
Sys_Error ("%s has invalid magic for iqm file", mod->name);
|
||||
if (LittleLong(pinheader->version) != IQM_VERSION) //v1 is outdated.
|
||||
Sys_Error ("%s is an unsupported version, %i must be %i", mod->name, LittleLong(pinheader->version), IQM_VERSION);
|
||||
|
||||
pintext = buffer + LittleLong(pinheader->ofs_text);
|
||||
|
||||
numsurfs = LittleLong (pinheader->num_meshes);
|
||||
if (!numsurfs)
|
||||
Sys_Error ("%s has no surfaces (animation-only iqms are not supported)", mod->name);
|
||||
if (pinheader->num_vertexes > 0xffff) //indexes is an unsigned short.
|
||||
Sys_Error ("%s has too many verts (%u>%u)", mod->name, pinheader->num_vertexes, 0xffffu);
|
||||
|
||||
numanims = LittleLong (pinheader->num_anims);
|
||||
size = sizeof(aliashdr_t) + q_max(1,numanims-1) * sizeof (outhdr->frames[0]);
|
||||
outhdr = (aliashdr_t *) Hunk_AllocName (size * numsurfs, loadname);
|
||||
|
||||
numverts = LittleLong(pinheader->num_vertexes);
|
||||
poutvert = (iqmvert_t *) Hunk_Alloc (sizeof (*poutvert) * numverts);
|
||||
for (j = 0; j < numverts; j++) //initialise verts, just in case.
|
||||
poutvert[j].rgba[0] = poutvert[j].rgba[1] = poutvert[j].rgba[2] = poutvert[j].rgba[3] = poutvert[j].weight[0] = 1;
|
||||
for (a = 0; a < LittleLong(pinheader->num_vertexarrays); a++)
|
||||
{
|
||||
const struct iqmvertexarray *va = (const struct iqmvertexarray*)(buffer+LittleLong(pinheader->ofs_vertexarrays)) + a;
|
||||
switch(va->type)
|
||||
{
|
||||
case IQM_POSITION: IQM_LoadVertexes_Float(poutvert->xyz, 3, numverts, buffer, va); break;
|
||||
case IQM_TEXCOORD: IQM_LoadVertexes_Float(poutvert->st, 2, numverts, buffer, va); break;
|
||||
case IQM_NORMAL: IQM_LoadVertexes_Float(poutvert->norm, 3, numverts, buffer, va); break;
|
||||
//case IQM_TANGENT: IQM_LoadVertexes_Float(poutvert->tang, 4, numverts, buffer, va); break; //bitangent must be calced using a crossproduct and the fourth component (for direction). we don't need this (unless you want rtlights or bumpmaps)
|
||||
case IQM_COLOR: IQM_LoadVertexes_Float(poutvert->rgba, 4, numverts, buffer, va); break;
|
||||
case IQM_BLENDINDEXES: IQM_LoadVertexes_Index(poutvert->idx, 4, numverts, buffer, va); break;
|
||||
case IQM_BLENDWEIGHTS: IQM_LoadVertexes_Float(poutvert->weight,4, numverts, buffer, va); break;
|
||||
default:
|
||||
continue; //no idea what it is. probably custom
|
||||
}
|
||||
}
|
||||
|
||||
numposes = LittleLong (pinheader->num_frames);
|
||||
numjoints = LittleLong(pinheader->num_poses);
|
||||
if (pinheader->num_poses == pinheader->num_joints)
|
||||
{
|
||||
const unsigned short *pinframedata = (const unsigned short*)(buffer + pinheader->ofs_frames);
|
||||
const struct iqmpose *pinajoint = (const struct iqmpose*)(buffer + pinheader->ofs_poses), *p;
|
||||
vec3_t pos, scale;
|
||||
vec4_t quat;
|
||||
outposes = Hunk_Alloc(sizeof(*outposes)*numposes*numjoints);
|
||||
for (a = 0; a < numposes; a++)
|
||||
{
|
||||
for (j = 0, p = pinajoint; j < numjoints; j++, p++)
|
||||
{
|
||||
unsigned int mask = LittleLong(p->mask);
|
||||
pos[0] = LittleFloat(p->channeloffset[0]); if (mask & 1) pos[0] += (unsigned short)LittleShort(*pinframedata++) * LittleFloat(p->channelscale[0]);
|
||||
pos[1] = LittleFloat(p->channeloffset[1]); if (mask & 2) pos[1] += (unsigned short)LittleShort(*pinframedata++) * LittleFloat(p->channelscale[1]);
|
||||
pos[2] = LittleFloat(p->channeloffset[2]); if (mask & 4) pos[2] += (unsigned short)LittleShort(*pinframedata++) * LittleFloat(p->channelscale[2]);
|
||||
quat[0] = LittleFloat(p->channeloffset[3]); if (mask & 8) quat[0] += (unsigned short)LittleShort(*pinframedata++) * LittleFloat(p->channelscale[3]);
|
||||
quat[1] = LittleFloat(p->channeloffset[4]); if (mask & 16) quat[1] += (unsigned short)LittleShort(*pinframedata++) * LittleFloat(p->channelscale[4]);
|
||||
quat[2] = LittleFloat(p->channeloffset[5]); if (mask & 32) quat[2] += (unsigned short)LittleShort(*pinframedata++) * LittleFloat(p->channelscale[5]);
|
||||
quat[3] = LittleFloat(p->channeloffset[6]); if (mask & 64) quat[3] += (unsigned short)LittleShort(*pinframedata++) * LittleFloat(p->channelscale[6]);
|
||||
scale[0] = LittleFloat(p->channeloffset[7]); if (mask & 128) scale[0] += (unsigned short)LittleShort(*pinframedata++) * LittleFloat(p->channelscale[7]);
|
||||
scale[1] = LittleFloat(p->channeloffset[8]); if (mask & 256) scale[1] += (unsigned short)LittleShort(*pinframedata++) * LittleFloat(p->channelscale[8]);
|
||||
scale[2] = LittleFloat(p->channeloffset[9]); if (mask & 512) scale[2] += (unsigned short)LittleShort(*pinframedata++) * LittleFloat(p->channelscale[9]);
|
||||
|
||||
//fixme: should probably save the 10 values above and slerp, but its simpler to just save+lerp a matrix (although this does result in denormalisation when interpolating).
|
||||
GenMatrixPosQuat4Scale(pos, quat, scale, outposes[(a*numjoints+j)].mat);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{ //panic! panic! something weird is going on!
|
||||
numposes = 0;
|
||||
numjoints = 0;
|
||||
outposes = NULL;
|
||||
}
|
||||
|
||||
{
|
||||
const struct iqmjoint *pinbjoint = (const struct iqmjoint*)(buffer + pinheader->ofs_joints);
|
||||
bonepose_t basepose[256], rel;
|
||||
vec3_t pos, scale;
|
||||
vec4_t quat;
|
||||
outbones = Hunk_Alloc(sizeof(*outbones)*numjoints);
|
||||
for (j = 0; j < numjoints; j++)
|
||||
{
|
||||
outbones[j].parent = LittleLong(pinbjoint[j].parent);
|
||||
q_strlcpy(outbones[j].name, pintext+LittleLong(pinbjoint[j].name), sizeof(outbones[j].name));
|
||||
|
||||
pos[0] = LittleFloat(pinbjoint[j].translate[0]);
|
||||
pos[1] = LittleFloat(pinbjoint[j].translate[1]);
|
||||
pos[2] = LittleFloat(pinbjoint[j].translate[2]);
|
||||
quat[0] = LittleFloat(pinbjoint[j].rotate[0]);
|
||||
quat[1] = LittleFloat(pinbjoint[j].rotate[1]);
|
||||
quat[2] = LittleFloat(pinbjoint[j].rotate[2]);
|
||||
quat[3] = LittleFloat(pinbjoint[j].rotate[3]);
|
||||
scale[0] = LittleFloat(pinbjoint[j].scale[0]);
|
||||
scale[1] = LittleFloat(pinbjoint[j].scale[1]);
|
||||
scale[2] = LittleFloat(pinbjoint[j].scale[2]);
|
||||
GenMatrixPosQuat4Scale(pos, quat, scale, rel.mat);
|
||||
//urgh, these are relative.
|
||||
if (outbones[j].parent < 0)
|
||||
memcpy(basepose[j].mat, rel.mat, sizeof(rel.mat));
|
||||
else
|
||||
R_ConcatTransforms((void*)basepose[outbones[j].parent].mat, (void*)rel.mat, (void*)basepose[j].mat);
|
||||
|
||||
Matrix3x4_Invert_Simple(basepose[j].mat, outbones[j].inverse.mat);
|
||||
//and now we have the inversion matrix to use to undo the bone positions baked into the vertex data.
|
||||
}
|
||||
}
|
||||
|
||||
mod->numframes = q_max(1,numanims);
|
||||
|
||||
for (surf = 0, pinsurface = (const struct iqmmesh*)(buffer + LittleLong(pinheader->ofs_meshes)); surf < numsurfs; surf++, pinsurface++)
|
||||
{
|
||||
aliashdr_t *osurf = (aliashdr_t*)((byte*)outhdr + size*surf);
|
||||
|
||||
if (surf+1 < numsurfs)
|
||||
osurf->nextsurface = size;
|
||||
else
|
||||
osurf->nextsurface = 0;
|
||||
|
||||
osurf->poseverttype = PV_IQM;
|
||||
osurf->numverts_vbo = osurf->numverts = LittleLong(pinsurface->num_vertexes);
|
||||
|
||||
firstvert = LittleLong(pinsurface->first_vertex);
|
||||
osurf->vertexes = (intptr_t)(poutvert + firstvert) - (intptr_t)osurf;
|
||||
osurf->numverts = LittleLong(pinsurface->num_vertexes);
|
||||
osurf->nummorphposes = 1; //as a skeletal model, we do all our animations via bones rather than vertex morphs.
|
||||
|
||||
osurf->numtris = LittleLong(pinsurface->num_triangles);
|
||||
osurf->numindexes = osurf->numtris*3;
|
||||
poutindexes = (unsigned short *) Hunk_Alloc (sizeof (*poutindexes) * osurf->numindexes);
|
||||
osurf->indexes = (intptr_t)poutindexes - (intptr_t)osurf;
|
||||
pintriangle = (const unsigned int*)(buffer + LittleLong(pinheader->ofs_triangles));
|
||||
firstidx = LittleLong(pinsurface->first_triangle)*3;
|
||||
pintriangle += firstidx;
|
||||
for (j = 0; j < osurf->numindexes; j++)
|
||||
poutindexes[j] = pintriangle[j] - firstvert;
|
||||
|
||||
pinframes = (const struct iqmanim*)(buffer + pinheader->ofs_anims);
|
||||
for (a = 0; a < numanims; a++, pinframes++)
|
||||
{
|
||||
osurf->frames[a].firstpose = LittleLong(pinframes->first_frame);
|
||||
osurf->frames[a].numposes = LittleLong(pinframes->num_frames);
|
||||
osurf->frames[a].interval = LittleFloat(pinframes->framerate);
|
||||
if (!osurf->frames[a].interval)
|
||||
osurf->frames[a].interval = 20;
|
||||
osurf->frames[a].interval = 1.0/osurf->frames[a].interval;
|
||||
if (LittleLong(pinframes->flags) & IQM_LOOP)
|
||||
/*FIXME*/;
|
||||
|
||||
q_strlcpy(osurf->frames[a].name, pintext+LittleLong(pinframes->name), sizeof(osurf->frames[ival].name));
|
||||
for (j = 0; j < 3; j++)
|
||||
{ //fixme...
|
||||
osurf->frames[a].bboxmin.v[j] = 0;
|
||||
osurf->frames[a].bboxmax.v[j] = 255;
|
||||
}
|
||||
}
|
||||
for (; a < 1; a++, pinframes++)
|
||||
{ //unanimated models need to pick their morphpose without warnings.
|
||||
osurf->frames[a].firstpose = 0;
|
||||
osurf->frames[a].numposes = 1;
|
||||
osurf->frames[a].interval = 0.1;
|
||||
|
||||
q_strlcpy(osurf->frames[a].name, "", sizeof(osurf->frames[ival].name));
|
||||
for (j = 0; j < 3; j++)
|
||||
{ //fixme...
|
||||
osurf->frames[a].bboxmin.v[j] = 0;
|
||||
osurf->frames[a].bboxmax.v[j] = 255;
|
||||
}
|
||||
}
|
||||
osurf->numframes = a;
|
||||
if (numposes)
|
||||
{
|
||||
osurf->numboneposes = numposes;
|
||||
osurf->boneposedata = (intptr_t)outposes - (intptr_t)osurf;
|
||||
}
|
||||
osurf->numbones = numjoints;
|
||||
osurf->boneinfo = (intptr_t)outbones - (intptr_t)osurf;
|
||||
|
||||
for (j = 0; j < 3; j++)
|
||||
{
|
||||
osurf->scale_origin[j] = 0;
|
||||
osurf->scale[j] = 1.0;
|
||||
}
|
||||
|
||||
//skin size is irrelevant
|
||||
osurf->skinwidth = 1;
|
||||
osurf->skinheight = 1;
|
||||
|
||||
//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;
|
||||
}
|
||||
}
|
||||
}
|
||||
GLMesh_LoadVertexBuffer (mod, outhdr);
|
||||
|
||||
//small violation of the spec, but it seems like noone else uses it.
|
||||
mod->flags = LittleLong (pinheader->flags);
|
||||
|
||||
|
||||
mod->type = mod_alias;
|
||||
|
||||
Mod_CalcAliasBounds (outhdr); //johnfitz
|
||||
|
|
|
@ -33,6 +33,7 @@ void Mod_LoadSpriteModel (qmodel_t *mod, void *buffer);
|
|||
void Mod_LoadBrushModel (qmodel_t *mod, void *buffer);
|
||||
void Mod_LoadAliasModel (qmodel_t *mod, void *buffer, int pvtype);
|
||||
void Mod_LoadMD3Model (qmodel_t *mod, void *buffer);
|
||||
void Mod_LoadIQMModel (qmodel_t *mod, const void *buffer);
|
||||
qmodel_t *Mod_LoadModel (qmodel_t *mod, qboolean crash);
|
||||
|
||||
cvar_t external_ents = {"external_ents", "1", CVAR_ARCHIVE};
|
||||
|
@ -388,6 +389,11 @@ qmodel_t *Mod_LoadModel (qmodel_t *mod, qboolean crash)
|
|||
Mod_LoadMD3Model(mod, buf);
|
||||
break;
|
||||
|
||||
//Spike -- iqm support
|
||||
case (('I'<<0)+('N'<<8)+('T'<<16)+('E'<<24)): //iqm
|
||||
Mod_LoadIQMModel(mod, buf);
|
||||
break;
|
||||
|
||||
//Spike -- added checks for a few other model types.
|
||||
//this is useful because of the number of models with renamed extensions.
|
||||
//that and its hard to test the extension stuff when this was crashing.
|
||||
|
@ -399,10 +405,6 @@ qmodel_t *Mod_LoadModel (qmodel_t *mod, qboolean crash)
|
|||
Con_Warning("%s is an md2 (unsupported)\n", mod->name);
|
||||
mod->type = mod_ext_invalid;
|
||||
break;
|
||||
case (('I'<<0)+('N'<<8)+('T'<<16)+('E'<<24)): //iqm
|
||||
Con_Warning("%s is an iqm (unsupported)\n", mod->name);
|
||||
mod->type = mod_ext_invalid;
|
||||
break;
|
||||
case (('D'<<0)+('A'<<8)+('R'<<16)+('K'<<24)): //dpm
|
||||
Con_Warning("%s is an dpm (unsupported)\n", mod->name);
|
||||
mod->type = mod_ext_invalid;
|
||||
|
@ -2938,13 +2940,13 @@ void Mod_CalcAliasBounds (aliashdr_t *a)
|
|||
|
||||
for (;;)
|
||||
{
|
||||
if (a->numposes && a->numverts)
|
||||
if (a->nummorphposes && a->numverts)
|
||||
{
|
||||
switch(a->poseverttype)
|
||||
{
|
||||
case PV_QUAKE1:
|
||||
//process verts
|
||||
for (i=0 ; i<a->numposes; i++)
|
||||
for (i=0 ; i<a->nummorphposes; i++)
|
||||
for (j=0; j<a->numverts; j++)
|
||||
{
|
||||
for (k=0; k<3;k++)
|
||||
|
@ -2965,7 +2967,7 @@ void Mod_CalcAliasBounds (aliashdr_t *a)
|
|||
break;
|
||||
case PV_QUAKEFORGE:
|
||||
//process verts
|
||||
for (i=0 ; i<a->numposes; i++)
|
||||
for (i=0 ; i<a->nummorphposes; i++)
|
||||
for (j=0; j<a->numverts; j++)
|
||||
{
|
||||
for (k=0; k<3;k++)
|
||||
|
@ -2986,7 +2988,7 @@ void Mod_CalcAliasBounds (aliashdr_t *a)
|
|||
break;
|
||||
case PV_QUAKE3:
|
||||
//process verts
|
||||
for (i=0 ; i<a->numposes; i++)
|
||||
for (i=0 ; i<a->nummorphposes; i++)
|
||||
{
|
||||
md3XyzNormal_t *pv = (md3XyzNormal_t *)((byte*)a+a->vertexes) + i*a->numverts;
|
||||
for (j=0; j<a->numverts; j++)
|
||||
|
@ -3008,6 +3010,30 @@ void Mod_CalcAliasBounds (aliashdr_t *a)
|
|||
}
|
||||
}
|
||||
break;
|
||||
case PV_IQM:
|
||||
//process verts
|
||||
for (i=0 ; i<a->nummorphposes; i++)
|
||||
{
|
||||
const iqmvert_t *pv = (const iqmvert_t *)((byte*)a+a->vertexes) + i*a->numverts;
|
||||
for (j=0; j<a->numverts; j++)
|
||||
{
|
||||
for (k=0; k<3;k++)
|
||||
v[k] = pv[j].xyz[k];
|
||||
|
||||
for (k=0; k<3;k++)
|
||||
{
|
||||
loadmodel->mins[k] = q_min(loadmodel->mins[k], v[k]);
|
||||
loadmodel->maxs[k] = q_max(loadmodel->maxs[k], v[k]);
|
||||
}
|
||||
dist = v[0] * v[0] + v[1] * v[1];
|
||||
if (yawradius < dist)
|
||||
yawradius = dist;
|
||||
dist += v[2] * v[2];
|
||||
if (radius < dist)
|
||||
radius = dist;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3264,7 +3290,7 @@ void Mod_LoadAliasModel (qmodel_t *mod, void *buffer, int pvtype)
|
|||
pframetype = (daliasframetype_t *) Mod_LoadAliasGroup (pframetype + 1, &pheader->frames[i], pvtype);
|
||||
}
|
||||
|
||||
pheader->numposes = posenum;
|
||||
pheader->nummorphposes = posenum;
|
||||
pheader->poseverttype = pvtype; //it would be safe to always store PV_QUAKE1 here if you wanted to drop the low-order data.
|
||||
|
||||
mod->type = mod_alias;
|
||||
|
|
|
@ -318,7 +318,7 @@ typedef struct
|
|||
float interval;
|
||||
trivertx_t bboxmin;
|
||||
trivertx_t bboxmax;
|
||||
int frame;
|
||||
// int frame; //spike - this was redundant.
|
||||
char name[16];
|
||||
} maliasframedesc_t;
|
||||
|
||||
|
@ -374,12 +374,17 @@ typedef struct {
|
|||
//ericw --
|
||||
|
||||
intptr_t nextsurface; //spike
|
||||
int numposes;
|
||||
int nummorphposes; //spike -- renamed from numposes
|
||||
int numboneposes; //spike -- for iqm
|
||||
int numbones; //spike -- for iqm
|
||||
intptr_t boneinfo; //spike -- for iqm, boneinfo_t[numbones]
|
||||
intptr_t boneposedata; //spike -- for iqm, bonepose_t[numboneposes*numbones]
|
||||
enum
|
||||
{
|
||||
PV_QUAKE1 = 1, //trivertx_t
|
||||
PV_QUAKE3 = 2, //md3XyzNormal_t
|
||||
PV_QUAKEFORGE, //trivertx16_t
|
||||
PV_IQM, //iqmvert_t
|
||||
} poseverttype; //spike
|
||||
struct gltexture_s *gltextures[MAX_SKINS][4]; //johnfitz
|
||||
struct gltexture_s *fbtextures[MAX_SKINS][4]; //johnfitz
|
||||
|
@ -392,13 +397,32 @@ typedef struct {
|
|||
byte latlong[2];
|
||||
} md3XyzNormal_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float xyz[3];
|
||||
float norm[3];
|
||||
float st[2]; //these are separate for consistency
|
||||
float rgba[4]; //because we can.
|
||||
float weight[4];
|
||||
byte idx[4];
|
||||
} iqmvert_t;
|
||||
typedef struct
|
||||
{
|
||||
float mat[12];
|
||||
} bonepose_t; //pose data for a single bone.
|
||||
typedef struct
|
||||
{
|
||||
int parent; //-1 for a root bone
|
||||
char name[32];
|
||||
bonepose_t inverse;
|
||||
} boneinfo_t;
|
||||
|
||||
#define VANILLA_MAXALIASVERTS 1024
|
||||
#define MAXALIASVERTS 65536 // spike -- was 2000 //johnfitz -- was 1024
|
||||
#define MAXALIASFRAMES 1024 //spike -- was 256
|
||||
extern stvert_t stverts[MAXALIASVERTS];
|
||||
extern mtriangle_t *triangles;
|
||||
extern trivertx_t *poseverts_mdl[MAXALIASFRAMES];
|
||||
extern md3XyzNormal_t *poseverts_md3[MAXALIASFRAMES];
|
||||
|
||||
//===================================================================
|
||||
|
||||
|
|
|
@ -142,6 +142,7 @@ QS_PFNGLUNIFORM1IPROC GL_Uniform1iFunc = NULL; //ericw
|
|||
QS_PFNGLUNIFORM1FPROC GL_Uniform1fFunc = NULL; //ericw
|
||||
QS_PFNGLUNIFORM3FPROC GL_Uniform3fFunc = NULL; //ericw
|
||||
QS_PFNGLUNIFORM4FPROC GL_Uniform4fFunc = NULL; //ericw
|
||||
QS_PFNGLUNIFORM4FVPROC GL_Uniform4fvFunc = NULL; //spike (for iqms)
|
||||
|
||||
//====================================
|
||||
|
||||
|
@ -1201,6 +1202,7 @@ static void GL_CheckExtensions (void)
|
|||
GL_Uniform1fFunc = (QS_PFNGLUNIFORM1FPROC) SDL_GL_GetProcAddress("glUniform1f");
|
||||
GL_Uniform3fFunc = (QS_PFNGLUNIFORM3FPROC) SDL_GL_GetProcAddress("glUniform3f");
|
||||
GL_Uniform4fFunc = (QS_PFNGLUNIFORM4FPROC) SDL_GL_GetProcAddress("glUniform4f");
|
||||
GL_Uniform4fvFunc = (QS_PFNGLUNIFORM4FVPROC) SDL_GL_GetProcAddress("glUniform4fv");
|
||||
|
||||
if (GL_CreateShaderFunc &&
|
||||
GL_DeleteShaderFunc &&
|
||||
|
@ -1224,7 +1226,8 @@ static void GL_CheckExtensions (void)
|
|||
GL_Uniform1iFunc &&
|
||||
GL_Uniform1fFunc &&
|
||||
GL_Uniform3fFunc &&
|
||||
GL_Uniform4fFunc)
|
||||
GL_Uniform4fFunc &&
|
||||
GL_Uniform4fvFunc)
|
||||
{
|
||||
Con_Printf("FOUND: GLSL\n");
|
||||
gl_glsl_able = true;
|
||||
|
|
|
@ -235,6 +235,7 @@ typedef void (APIENTRYP QS_PFNGLUNIFORM1IPROC) (GLint location, GLint v0);
|
|||
typedef void (APIENTRYP QS_PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0);
|
||||
typedef void (APIENTRYP QS_PFNGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
|
||||
typedef void (APIENTRYP QS_PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
|
||||
typedef void (APIENTRYP QS_PFNGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value);
|
||||
|
||||
extern QS_PFNGLCREATESHADERPROC GL_CreateShaderFunc;
|
||||
extern QS_PFNGLDELETESHADERPROC GL_DeleteShaderFunc;
|
||||
|
@ -259,6 +260,7 @@ extern QS_PFNGLUNIFORM1IPROC GL_Uniform1iFunc;
|
|||
extern QS_PFNGLUNIFORM1FPROC GL_Uniform1fFunc;
|
||||
extern QS_PFNGLUNIFORM3FPROC GL_Uniform3fFunc;
|
||||
extern QS_PFNGLUNIFORM4FPROC GL_Uniform4fFunc;
|
||||
extern QS_PFNGLUNIFORM4FVPROC GL_Uniform4fvFunc;
|
||||
extern qboolean gl_glsl_able;
|
||||
extern qboolean gl_glsl_gamma_able;
|
||||
extern qboolean gl_glsl_alias_able;
|
||||
|
|
|
@ -2278,16 +2278,39 @@ void Host_Give_f (void)
|
|||
edict_t *FindViewthing (void)
|
||||
{
|
||||
int i;
|
||||
edict_t *e;
|
||||
edict_t *e = NULL;
|
||||
|
||||
PR_SwitchQCVM(&sv.qcvm);
|
||||
i = qcvm->num_edicts;
|
||||
|
||||
if (i == qcvm->num_edicts)
|
||||
{
|
||||
for (i=0 ; i<qcvm->num_edicts ; i++)
|
||||
{
|
||||
e = EDICT_NUM(i);
|
||||
if ( !strcmp (PR_GetString(e->v.classname), "viewthing") )
|
||||
return e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == qcvm->num_edicts)
|
||||
{
|
||||
for (i=0 ; i<qcvm->num_edicts ; i++)
|
||||
{
|
||||
e = EDICT_NUM(i);
|
||||
if ( !strcmp (PR_GetString(e->v.classname), "info_player_start") )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == qcvm->num_edicts)
|
||||
{
|
||||
e = NULL;
|
||||
Con_Printf ("No viewthing on map\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PR_SwitchQCVM(NULL);
|
||||
return e;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2311,8 +2334,11 @@ void Host_Viewmodel_f (void)
|
|||
return;
|
||||
}
|
||||
|
||||
PR_SwitchQCVM(&sv.qcvm);
|
||||
e->v.modelindex = SV_Precache_Model(m->name);
|
||||
e->v.model = PR_SetEngineString(sv.model_precache[(int)e->v.modelindex]);
|
||||
e->v.frame = 0;
|
||||
cl.model_precache[(int)e->v.modelindex] = m;
|
||||
PR_SwitchQCVM(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
285
Quake/r_alias.c
285
Quake/r_alias.c
|
@ -63,28 +63,46 @@ typedef struct {
|
|||
float blend;
|
||||
vec3_t origin;
|
||||
vec3_t angles;
|
||||
bonepose_t *bonestate;
|
||||
} lerpdata_t;
|
||||
//johnfitz
|
||||
|
||||
static GLuint r_alias_program;
|
||||
enum
|
||||
{
|
||||
ALIAS_GLSL_BASIC,
|
||||
ALIAS_GLSL_SKELETAL,
|
||||
ALIAS_GLSL_MODES
|
||||
};
|
||||
typedef struct
|
||||
{
|
||||
int maxbones;
|
||||
|
||||
GLuint program;
|
||||
|
||||
// uniforms used in vert shader
|
||||
static GLuint blendLoc;
|
||||
static GLuint shadevectorLoc;
|
||||
static GLuint lightColorLoc;
|
||||
GLuint bonesLoc;
|
||||
GLuint blendLoc;
|
||||
GLuint shadevectorLoc;
|
||||
GLuint lightColorLoc;
|
||||
|
||||
// uniforms used in frag shader
|
||||
static GLuint texLoc;
|
||||
static GLuint fullbrightTexLoc;
|
||||
static GLuint useFullbrightTexLoc;
|
||||
static GLuint useOverbrightLoc;
|
||||
static GLuint useAlphaTestLoc;
|
||||
GLuint texLoc;
|
||||
GLuint fullbrightTexLoc;
|
||||
GLuint useFullbrightTexLoc;
|
||||
GLuint useOverbrightLoc;
|
||||
GLuint useAlphaTestLoc;
|
||||
} aliasglsl_t;
|
||||
static aliasglsl_t r_alias_glsl[ALIAS_GLSL_MODES];
|
||||
|
||||
#define pose1VertexAttrIndex 0
|
||||
#define pose1NormalAttrIndex 1
|
||||
#define pose2VertexAttrIndex 2
|
||||
#define pose2NormalAttrIndex 3
|
||||
#define texCoordsAttrIndex 4
|
||||
#define vertColoursAttrIndex 5
|
||||
|
||||
#define boneWeightAttrIndex pose2VertexAttrIndex
|
||||
#define boneIndexAttrIndex pose2NormalAttrIndex
|
||||
|
||||
/*
|
||||
=============
|
||||
|
@ -141,25 +159,39 @@ GLAlias_CreateShaders
|
|||
*/
|
||||
void GLAlias_CreateShaders (void)
|
||||
{
|
||||
int i;
|
||||
aliasglsl_t *glsl;
|
||||
char processedVertSource[8192], *defines;
|
||||
const glsl_attrib_binding_t bindings[] = {
|
||||
{ "TexCoords", texCoordsAttrIndex },
|
||||
{ "Pose1Vert", pose1VertexAttrIndex },
|
||||
{ "Pose1Normal", pose1NormalAttrIndex },
|
||||
{ "Pose2Vert", pose2VertexAttrIndex },
|
||||
{ "Pose2Normal", pose2NormalAttrIndex }
|
||||
{ "Pose2Normal", pose2NormalAttrIndex },
|
||||
{ "VertColours", vertColoursAttrIndex }
|
||||
};
|
||||
|
||||
const GLchar *vertSource = \
|
||||
"#version 110\n"
|
||||
"%s"
|
||||
"\n"
|
||||
"uniform float Blend;\n"
|
||||
"uniform vec3 ShadeVector;\n"
|
||||
"uniform vec4 LightColor;\n"
|
||||
"attribute vec4 TexCoords; // only xy are used \n"
|
||||
"attribute vec4 Pose1Vert;\n"
|
||||
"attribute vec3 Pose1Normal;\n"
|
||||
"#ifdef SKELETAL\n"
|
||||
"#define BoneWeight Pose2Vert\n"
|
||||
"#define BoneIndex Pose2Normal\n"
|
||||
"attribute vec4 BoneWeight;\n"
|
||||
"attribute vec4 BoneIndex;\n"
|
||||
"attribute vec4 VertColours;\n"
|
||||
"uniform vec4 BoneTable[MAXBONES*3];\n" //fixme: should probably try to use a UBO or SSBO.
|
||||
"#else\n"
|
||||
"uniform float Blend;\n"
|
||||
"attribute vec4 Pose2Vert;\n"
|
||||
"attribute vec3 Pose2Normal;\n"
|
||||
"#endif\n"
|
||||
"\n"
|
||||
"varying float FogFragCoord;\n"
|
||||
"\n"
|
||||
|
@ -175,12 +207,33 @@ void GLAlias_CreateShaders (void)
|
|||
"void main()\n"
|
||||
"{\n"
|
||||
" gl_TexCoord[0] = TexCoords;\n"
|
||||
"#ifdef SKELETAL\n"
|
||||
" mat4 wmat;"
|
||||
" wmat[0] = BoneTable[0+3*int(BoneIndex.x)] * BoneWeight.x;"
|
||||
" wmat[0] += BoneTable[0+3*int(BoneIndex.y)] * BoneWeight.y;"
|
||||
" wmat[0] += BoneTable[0+3*int(BoneIndex.z)] * BoneWeight.z;"
|
||||
" wmat[0] += BoneTable[0+3*int(BoneIndex.w)] * BoneWeight.w;"
|
||||
" wmat[1] = BoneTable[1+3*int(BoneIndex.x)] * BoneWeight.x;"
|
||||
" wmat[1] += BoneTable[1+3*int(BoneIndex.y)] * BoneWeight.y;"
|
||||
" wmat[1] += BoneTable[1+3*int(BoneIndex.z)] * BoneWeight.z;"
|
||||
" wmat[1] += BoneTable[1+3*int(BoneIndex.w)] * BoneWeight.w;"
|
||||
" wmat[2] = BoneTable[2+3*int(BoneIndex.x)] * BoneWeight.x;"
|
||||
" wmat[2] += BoneTable[2+3*int(BoneIndex.y)] * BoneWeight.y;"
|
||||
" wmat[2] += BoneTable[2+3*int(BoneIndex.z)] * BoneWeight.z;"
|
||||
" 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"
|
||||
"#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"
|
||||
"#endif\n"
|
||||
" gl_Position = gl_ModelViewProjectionMatrix * lerpedVert;\n"
|
||||
" FogFragCoord = gl_Position.w;\n"
|
||||
" float dot1 = r_avertexnormal_dot(Pose1Normal);\n"
|
||||
" float dot2 = r_avertexnormal_dot(Pose2Normal);\n"
|
||||
" gl_FrontColor = LightColor * vec4(vec3(mix(dot1, dot2, Blend)), 1.0);\n"
|
||||
" gl_FrontColor = LightColor * vec4(vec3(dot1), 1.0);\n"
|
||||
"#ifdef SKELETAL\n"
|
||||
" gl_FrontColor *= VertColours;\n" //this is basically only useful for vertex alphas.
|
||||
"#endif\n"
|
||||
"}\n";
|
||||
|
||||
const GLchar *fragSource = \
|
||||
|
@ -215,19 +268,45 @@ void GLAlias_CreateShaders (void)
|
|||
if (!gl_glsl_alias_able)
|
||||
return;
|
||||
|
||||
r_alias_program = GL_CreateProgram (vertSource, fragSource, sizeof(bindings)/sizeof(bindings[0]), bindings);
|
||||
for (i = 0; i < ALIAS_GLSL_MODES; i++)
|
||||
{
|
||||
glsl = &r_alias_glsl[i];
|
||||
|
||||
if (r_alias_program != 0)
|
||||
if (i == ALIAS_GLSL_SKELETAL)
|
||||
{
|
||||
defines = "#define SKELETAL\n#define MAXBONES 64\n";
|
||||
glsl->maxbones = 64;
|
||||
}
|
||||
else
|
||||
{
|
||||
defines = "";
|
||||
glsl->maxbones = 0;
|
||||
}
|
||||
q_snprintf(processedVertSource, sizeof(processedVertSource), vertSource, defines);
|
||||
|
||||
glsl->program = GL_CreateProgram (processedVertSource, fragSource, sizeof(bindings)/sizeof(bindings[0]), bindings);
|
||||
|
||||
if (glsl->program != 0)
|
||||
{
|
||||
// get uniform locations
|
||||
blendLoc = GL_GetUniformLocation (&r_alias_program, "Blend");
|
||||
shadevectorLoc = GL_GetUniformLocation (&r_alias_program, "ShadeVector");
|
||||
lightColorLoc = GL_GetUniformLocation (&r_alias_program, "LightColor");
|
||||
texLoc = GL_GetUniformLocation (&r_alias_program, "Tex");
|
||||
fullbrightTexLoc = GL_GetUniformLocation (&r_alias_program, "FullbrightTex");
|
||||
useFullbrightTexLoc = GL_GetUniformLocation (&r_alias_program, "UseFullbrightTex");
|
||||
useOverbrightLoc = GL_GetUniformLocation (&r_alias_program, "UseOverbright");
|
||||
useAlphaTestLoc = GL_GetUniformLocation (&r_alias_program, "UseAlphaTest");
|
||||
if (i == ALIAS_GLSL_SKELETAL)
|
||||
{
|
||||
glsl->bonesLoc = GL_GetUniformLocation (&glsl->program, "BoneTable");
|
||||
glsl->blendLoc = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
glsl->bonesLoc = -1;
|
||||
glsl->blendLoc = GL_GetUniformLocation (&glsl->program, "Blend");
|
||||
}
|
||||
glsl->shadevectorLoc = GL_GetUniformLocation (&glsl->program, "ShadeVector");
|
||||
glsl->lightColorLoc = GL_GetUniformLocation (&glsl->program, "LightColor");
|
||||
glsl->texLoc = GL_GetUniformLocation (&glsl->program, "Tex");
|
||||
glsl->fullbrightTexLoc = GL_GetUniformLocation (&glsl->program, "FullbrightTex");
|
||||
glsl->useFullbrightTexLoc = GL_GetUniformLocation (&glsl->program, "UseFullbrightTex");
|
||||
glsl->useOverbrightLoc = GL_GetUniformLocation (&glsl->program, "UseOverbright");
|
||||
glsl->useAlphaTestLoc = GL_GetUniformLocation (&glsl->program, "UseAlphaTest");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -245,7 +324,7 @@ Supports optional overbright, optional fullbright pixels.
|
|||
Based on code by MH from RMQEngine
|
||||
=============
|
||||
*/
|
||||
void GL_DrawAliasFrame_GLSL (aliashdr_t *paliashdr, lerpdata_t lerpdata, gltexture_t *tx, gltexture_t *fb)
|
||||
void GL_DrawAliasFrame_GLSL (aliasglsl_t *glsl, aliashdr_t *paliashdr, lerpdata_t lerpdata, gltexture_t *tx, gltexture_t *fb)
|
||||
{
|
||||
float blend;
|
||||
|
||||
|
@ -258,7 +337,7 @@ void GL_DrawAliasFrame_GLSL (aliashdr_t *paliashdr, lerpdata_t lerpdata, gltextu
|
|||
blend = 0;
|
||||
}
|
||||
|
||||
GL_UseProgramFunc (r_alias_program);
|
||||
GL_UseProgramFunc (glsl->program);
|
||||
|
||||
GL_BindBuffer (GL_ARRAY_BUFFER, currententity->model->meshvbo);
|
||||
GL_BindBuffer (GL_ELEMENT_ARRAY_BUFFER, currententity->model->meshindexesvbo);
|
||||
|
@ -269,10 +348,11 @@ void GL_DrawAliasFrame_GLSL (aliashdr_t *paliashdr, lerpdata_t lerpdata, gltextu
|
|||
GL_EnableVertexAttribArrayFunc (pose1NormalAttrIndex);
|
||||
GL_EnableVertexAttribArrayFunc (pose2NormalAttrIndex);
|
||||
|
||||
GL_VertexAttribPointerFunc (texCoordsAttrIndex, 2, GL_FLOAT, GL_FALSE, 0, currententity->model->meshvboptr+paliashdr->vbostofs);
|
||||
switch(paliashdr->poseverttype)
|
||||
{
|
||||
case PV_QUAKE1:
|
||||
GL_VertexAttribPointerFunc (texCoordsAttrIndex, 2, GL_FLOAT, GL_FALSE, 0, currententity->model->meshvboptr+paliashdr->vbostofs);
|
||||
|
||||
GL_VertexAttribPointerFunc (pose1VertexAttrIndex, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof (meshxyz_mdl_t), GLARB_GetXYZOffset_MDL (paliashdr, lerpdata.pose1));
|
||||
GL_VertexAttribPointerFunc (pose2VertexAttrIndex, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof (meshxyz_mdl_t), GLARB_GetXYZOffset_MDL (paliashdr, lerpdata.pose2));
|
||||
// GL_TRUE to normalize the signed bytes to [-1 .. 1]
|
||||
|
@ -280,6 +360,8 @@ void GL_DrawAliasFrame_GLSL (aliashdr_t *paliashdr, lerpdata_t lerpdata, gltextu
|
|||
GL_VertexAttribPointerFunc (pose2NormalAttrIndex, 4, GL_BYTE, GL_TRUE, sizeof (meshxyz_mdl_t), GLARB_GetNormalOffset_MDL (paliashdr, lerpdata.pose2));
|
||||
break;
|
||||
case PV_QUAKEFORGE:
|
||||
GL_VertexAttribPointerFunc (texCoordsAttrIndex, 2, GL_FLOAT, GL_FALSE, 0, currententity->model->meshvboptr+paliashdr->vbostofs);
|
||||
|
||||
GL_VertexAttribPointerFunc (pose1VertexAttrIndex, 4, GL_UNSIGNED_SHORT, GL_FALSE, sizeof (meshxyz_mdl16_t), GLARB_GetXYZOffset_MDLQF (paliashdr, lerpdata.pose1));
|
||||
GL_VertexAttribPointerFunc (pose2VertexAttrIndex, 4, GL_UNSIGNED_SHORT, GL_FALSE, sizeof (meshxyz_mdl16_t), GLARB_GetXYZOffset_MDLQF (paliashdr, lerpdata.pose2));
|
||||
// GL_TRUE to normalize the signed bytes to [-1 .. 1]
|
||||
|
@ -287,23 +369,42 @@ void GL_DrawAliasFrame_GLSL (aliashdr_t *paliashdr, lerpdata_t lerpdata, gltextu
|
|||
GL_VertexAttribPointerFunc (pose2NormalAttrIndex, 4, GL_BYTE, GL_TRUE, sizeof (meshxyz_mdl16_t), GLARB_GetNormalOffset_MDLQF (paliashdr, lerpdata.pose2));
|
||||
break;
|
||||
case PV_QUAKE3:
|
||||
GL_VertexAttribPointerFunc (texCoordsAttrIndex, 2, GL_FLOAT, GL_FALSE, 0, currententity->model->meshvboptr+paliashdr->vbostofs);
|
||||
|
||||
GL_VertexAttribPointerFunc (pose1VertexAttrIndex, 4, GL_SHORT, GL_FALSE, sizeof (meshxyz_md3_t), GLARB_GetXYZOffset_MD3 (paliashdr, lerpdata.pose1));
|
||||
GL_VertexAttribPointerFunc (pose2VertexAttrIndex, 4, GL_SHORT, GL_FALSE, sizeof (meshxyz_md3_t), GLARB_GetXYZOffset_MD3 (paliashdr, lerpdata.pose2));
|
||||
// GL_TRUE to normalize the signed bytes to [-1 .. 1]
|
||||
GL_VertexAttribPointerFunc (pose1NormalAttrIndex, 4, GL_BYTE, GL_TRUE, sizeof (meshxyz_md3_t), GLARB_GetNormalOffset_MD3 (paliashdr, lerpdata.pose1));
|
||||
GL_VertexAttribPointerFunc (pose2NormalAttrIndex, 4, GL_BYTE, GL_TRUE, sizeof (meshxyz_md3_t), GLARB_GetNormalOffset_MD3 (paliashdr, lerpdata.pose2));
|
||||
break;
|
||||
case PV_IQM:
|
||||
{
|
||||
const iqmvert_t *pose = (const iqmvert_t*)(currententity->model->meshvboptr+paliashdr->vbovertofs + (paliashdr->numverts_vbo * 0 * sizeof (iqmvert_t)));
|
||||
|
||||
GL_VertexAttribPointerFunc (pose1VertexAttrIndex, 3, GL_FLOAT, GL_FALSE, sizeof (iqmvert_t), pose->xyz);
|
||||
GL_VertexAttribPointerFunc (pose1NormalAttrIndex, 3, GL_FLOAT, GL_FALSE, sizeof (iqmvert_t), pose->norm);
|
||||
GL_VertexAttribPointerFunc (boneWeightAttrIndex, 4, GL_FLOAT, GL_FALSE, sizeof (iqmvert_t), pose->weight);
|
||||
GL_VertexAttribPointerFunc (boneIndexAttrIndex, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof (iqmvert_t), pose->idx);
|
||||
GL_VertexAttribPointerFunc (texCoordsAttrIndex, 2, GL_FLOAT, GL_FALSE, sizeof (iqmvert_t), pose->st);
|
||||
|
||||
GL_EnableVertexAttribArrayFunc (vertColoursAttrIndex);
|
||||
GL_VertexAttribPointerFunc (vertColoursAttrIndex, 4, GL_FLOAT, GL_FALSE, sizeof (iqmvert_t), pose->rgba);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// set uniforms
|
||||
GL_Uniform1fFunc (blendLoc, blend);
|
||||
GL_Uniform3fFunc (shadevectorLoc, shadevector[0], shadevector[1], shadevector[2]);
|
||||
GL_Uniform4fFunc (lightColorLoc, lightcolor[0], lightcolor[1], lightcolor[2], entalpha);
|
||||
GL_Uniform1iFunc (texLoc, 0);
|
||||
GL_Uniform1iFunc (fullbrightTexLoc, 1);
|
||||
GL_Uniform1iFunc (useFullbrightTexLoc, (fb != NULL) ? 1 : 0);
|
||||
GL_Uniform1fFunc (useOverbrightLoc, overbright ? 1 : 0);
|
||||
GL_Uniform1iFunc (useAlphaTestLoc, (currententity->model->flags & MF_HOLEY) ? 1 : 0);
|
||||
if (glsl->blendLoc != -1)
|
||||
GL_Uniform1fFunc (glsl->blendLoc, blend);
|
||||
if (glsl->bonesLoc != -1)
|
||||
GL_Uniform4fvFunc (glsl->bonesLoc, paliashdr->numbones*3, lerpdata.bonestate->mat);
|
||||
GL_Uniform3fFunc (glsl->shadevectorLoc, shadevector[0], shadevector[1], shadevector[2]);
|
||||
GL_Uniform4fFunc (glsl->lightColorLoc, lightcolor[0], lightcolor[1], lightcolor[2], entalpha);
|
||||
GL_Uniform1iFunc (glsl->texLoc, 0);
|
||||
GL_Uniform1iFunc (glsl->fullbrightTexLoc, 1);
|
||||
GL_Uniform1iFunc (glsl->useFullbrightTexLoc, (fb != NULL) ? 1 : 0);
|
||||
GL_Uniform1fFunc (glsl->useOverbrightLoc, overbright ? 1 : 0);
|
||||
GL_Uniform1iFunc (glsl->useAlphaTestLoc, (currententity->model->flags & MF_HOLEY) ? 1 : 0);
|
||||
|
||||
// set textures
|
||||
GL_SelectTexture (GL_TEXTURE0);
|
||||
|
@ -324,6 +425,7 @@ void GL_DrawAliasFrame_GLSL (aliashdr_t *paliashdr, lerpdata_t lerpdata, gltextu
|
|||
GL_DisableVertexAttribArrayFunc (pose2VertexAttrIndex);
|
||||
GL_DisableVertexAttribArrayFunc (pose1NormalAttrIndex);
|
||||
GL_DisableVertexAttribArrayFunc (pose2NormalAttrIndex);
|
||||
GL_DisableVertexAttribArrayFunc (vertColoursAttrIndex);
|
||||
|
||||
GL_UseProgramFunc (0);
|
||||
GL_SelectTexture (GL_TEXTURE0);
|
||||
|
@ -344,6 +446,8 @@ void GL_DrawAliasFrame (aliashdr_t *paliashdr, lerpdata_t lerpdata)
|
|||
static vec4_t vc[65536];
|
||||
int i;
|
||||
float blend, iblend;
|
||||
const float *texcoords = (const float *)(currententity->model->meshvboptr+paliashdr->vbostofs);
|
||||
int texcoordstride = 0;
|
||||
|
||||
if (lerpdata.pose1 != lerpdata.pose2)
|
||||
{
|
||||
|
@ -511,6 +615,75 @@ void GL_DrawAliasFrame (aliashdr_t *paliashdr, lerpdata_t lerpdata)
|
|||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PV_IQM:
|
||||
{ //iqm does its blending using bones instead of verts, so we only have to care about one pose here
|
||||
int morphpose = 0;
|
||||
const iqmvert_t *verts2 = (const iqmvert_t*)((byte *)paliashdr + paliashdr->vertexes) + morphpose * paliashdr->numverts_vbo;
|
||||
const iqmvert_t *vboverts2 = (const iqmvert_t*)(currententity->model->meshvboptr+paliashdr->vbovertofs) + (paliashdr->numverts_vbo * morphpose);
|
||||
|
||||
if (shading)
|
||||
{
|
||||
for (i = 0; i < paliashdr->numverts_vbo; i++)
|
||||
{
|
||||
float dot;
|
||||
dot = DotProduct(verts2[i].norm, shadevector); //NOTE: ignores animated normals
|
||||
if (dot < 0.0) //bizzare maths guessed by mh
|
||||
dot = 1.0 + dot * (13.0 / 44.0);
|
||||
else
|
||||
dot = 1.0 + dot;
|
||||
vc[i][0] = dot * lightcolor[0] * verts2[i].rgba[0];
|
||||
vc[i][1] = dot * lightcolor[1] * verts2[i].rgba[1];
|
||||
vc[i][2] = dot * lightcolor[2] * verts2[i].rgba[2];
|
||||
vc[i][3] = entalpha * verts2[i].rgba[3];
|
||||
}
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
GL_BindBuffer (GL_ARRAY_BUFFER, 0);
|
||||
glColorPointer(4, GL_FLOAT, 0, vc);
|
||||
}
|
||||
|
||||
if (lerpdata.bonestate)
|
||||
{ //oh dear. its animated. and we don't have any glsl to animate it for us.
|
||||
bonepose_t pose;
|
||||
const bonepose_t *in;
|
||||
const float *xyz;
|
||||
float w;
|
||||
int j, k;
|
||||
for (i = 0; i < paliashdr->numverts_vbo; i++)
|
||||
{
|
||||
//lerp the matrix... this is less of a nightmare in glsl...
|
||||
in = lerpdata.bonestate + verts2[i].idx[0];
|
||||
w = verts2[i].weight[0];
|
||||
for (j = 0; j < 12; j++)
|
||||
pose.mat[j] = in->mat[j] * w;
|
||||
for (k = 1; k < 3; k++)
|
||||
{
|
||||
w = verts2[i].weight[k];
|
||||
if (!w)
|
||||
continue;
|
||||
in = lerpdata.bonestate + verts2[i].idx[k];
|
||||
for (j = 0; j < 12; j++)
|
||||
pose.mat[j] += in->mat[j] * w;
|
||||
}
|
||||
|
||||
xyz = verts2[i].xyz;
|
||||
vpos[i][0] = xyz[0]*pose.mat[0] + xyz[1]*pose.mat[1] + xyz[2]*pose.mat[2] + pose.mat[3];
|
||||
vpos[i][1] = xyz[0]*pose.mat[4] + xyz[1]*pose.mat[5] + xyz[2]*pose.mat[6] + pose.mat[7];
|
||||
vpos[i][2] = xyz[0]*pose.mat[8] + xyz[1]*pose.mat[9] + xyz[2]*pose.mat[10] + pose.mat[11];
|
||||
}
|
||||
|
||||
GL_BindBuffer (GL_ARRAY_BUFFER, 0);
|
||||
glVertexPointer(3, GL_FLOAT, 0, vpos);
|
||||
}
|
||||
else
|
||||
{
|
||||
GL_BindBuffer (GL_ARRAY_BUFFER, currententity->model->meshvbo);
|
||||
glVertexPointer(3, GL_FLOAT, sizeof (iqmvert_t), vboverts2->xyz);
|
||||
}
|
||||
texcoordstride = sizeof(iqmvert_t);
|
||||
texcoords = vboverts2->st;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// set textures
|
||||
|
@ -519,16 +692,16 @@ void GL_DrawAliasFrame (aliashdr_t *paliashdr, lerpdata_t lerpdata)
|
|||
{
|
||||
GL_ClientActiveTextureFunc (GL_TEXTURE0);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glTexCoordPointer(2, GL_FLOAT, 0, currententity->model->meshvboptr+paliashdr->vbostofs);
|
||||
glTexCoordPointer(2, GL_FLOAT, texcoordstride, texcoords);
|
||||
|
||||
GL_ClientActiveTextureFunc (GL_TEXTURE1);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glTexCoordPointer(2, GL_FLOAT, 0, currententity->model->meshvboptr+paliashdr->vbostofs);
|
||||
glTexCoordPointer(2, GL_FLOAT, texcoordstride, texcoords);
|
||||
}
|
||||
else
|
||||
{
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glTexCoordPointer(2, GL_FLOAT, 0, currententity->model->meshvboptr+paliashdr->vbostofs);
|
||||
glTexCoordPointer(2, GL_FLOAT, texcoordstride, texcoords);
|
||||
}
|
||||
|
||||
// draw
|
||||
|
@ -619,6 +792,35 @@ void R_SetupAliasFrame (aliashdr_t *paliashdr, int frame, lerpdata_t *lerpdata)
|
|||
lerpdata->pose1 = posenum;
|
||||
lerpdata->pose2 = posenum;
|
||||
}
|
||||
|
||||
|
||||
if (paliashdr->numboneposes)
|
||||
{
|
||||
static bonepose_t inverted[256];
|
||||
bonepose_t lerpbones[256], l;
|
||||
int b, j;
|
||||
const boneinfo_t *bi = (const boneinfo_t *)((byte*)paliashdr + paliashdr->boneinfo);
|
||||
const bonepose_t *p1 = (const bonepose_t *)((byte*)paliashdr + paliashdr->boneposedata) + lerpdata->pose1*paliashdr->numbones;
|
||||
const bonepose_t *p2 = (const bonepose_t *)((byte*)paliashdr + paliashdr->boneposedata) + lerpdata->pose2*paliashdr->numbones;
|
||||
float w2 = lerpdata->blend;
|
||||
float w1 = 1-w2;
|
||||
for (b = 0; b < paliashdr->numbones; b++, p1++, p2++)
|
||||
{
|
||||
//interpolate it
|
||||
for (j = 0; j < 12; j++)
|
||||
l.mat[j] = p1->mat[j]*w1 + p2->mat[j]*w2;
|
||||
//concat it onto the parent (relative->abs)
|
||||
if (bi[b].parent < 0)
|
||||
memcpy(lerpbones[b].mat, l.mat, sizeof(l.mat));
|
||||
else
|
||||
R_ConcatTransforms((void*)lerpbones[bi[b].parent].mat, (void*)l.mat, (void*)lerpbones[b].mat);
|
||||
//and finally invert it
|
||||
R_ConcatTransforms((void*)lerpbones[b].mat, (void*)bi[b].inverse.mat, (void*)inverted[b].mat);
|
||||
}
|
||||
lerpdata->bonestate = inverted; //and now we can use it.
|
||||
}
|
||||
else
|
||||
lerpdata->bonestate = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -780,6 +982,7 @@ R_DrawAliasModel -- johnfitz -- almost completely rewritten
|
|||
*/
|
||||
void R_DrawAliasModel (entity_t *e)
|
||||
{
|
||||
aliasglsl_t *glsl;
|
||||
aliashdr_t *paliashdr;
|
||||
int i, anim, skinnum;
|
||||
gltexture_t *tx, *fb;
|
||||
|
@ -794,6 +997,8 @@ void R_DrawAliasModel (entity_t *e)
|
|||
R_SetupAliasFrame (paliashdr, e->frame, &lerpdata);
|
||||
R_SetupEntityTransform (e, &lerpdata);
|
||||
|
||||
glsl = &r_alias_glsl[(paliashdr->poseverttype==PV_IQM)?ALIAS_GLSL_SKELETAL:ALIAS_GLSL_BASIC];
|
||||
|
||||
if (e->eflags & EFLAGS_VIEWMODEL)
|
||||
{
|
||||
//transform it relative to the view, by rebuilding the modelview matrix without the view position.
|
||||
|
@ -931,9 +1136,9 @@ void R_DrawAliasModel (entity_t *e)
|
|||
}
|
||||
// call fast path if possible. if the shader compliation failed for some reason,
|
||||
// r_alias_program will be 0.
|
||||
else if (r_alias_program != 0)
|
||||
else if (glsl->program != 0 && paliashdr->numbones <= glsl->maxbones)
|
||||
{
|
||||
GL_DrawAliasFrame_GLSL (paliashdr, lerpdata, tx, fb);
|
||||
GL_DrawAliasFrame_GLSL (glsl, paliashdr, lerpdata, tx, fb);
|
||||
}
|
||||
else if (overbright)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue