PSK (with implicit PSA) support.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/branches/wip@3606 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
dfd02ad9e3
commit
c1bf210da1
6 changed files with 804 additions and 99 deletions
|
@ -220,24 +220,21 @@ qboolean Media_FakeTrack(int i, qboolean loop)
|
||||||
{
|
{
|
||||||
char trackname[512];
|
char trackname[512];
|
||||||
|
|
||||||
if (i > 999 || i < 0)
|
if (i > 0 && i <= 999)
|
||||||
{
|
{
|
||||||
fakecdactive = false;
|
sprintf(trackname, "sound/cdtracks/track%03i.ogg", i);
|
||||||
return;
|
if (COM_FCheckExists(trackname))
|
||||||
}
|
{
|
||||||
|
Media_Clear();
|
||||||
|
strcpy(currenttrack.filename, trackname+6);
|
||||||
|
|
||||||
sprintf(trackname, "sound/cdtracks/track%03i.ogg", i);
|
fakecdactive = true;
|
||||||
if (COM_FCheckExists(trackname))
|
media_playing = true;
|
||||||
{
|
return true;
|
||||||
Media_Clear();
|
}
|
||||||
strcpy(currenttrack.filename, trackname+6);
|
|
||||||
|
|
||||||
fakecdactive = true;
|
|
||||||
media_playing = true;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
fakecdactive = false;
|
fakecdactive = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -134,13 +134,17 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
#define SIDEVIEWS 4 //enable secondary/reverse views.
|
#define SIDEVIEWS 4 //enable secondary/reverse views.
|
||||||
|
|
||||||
#define SP2MODELS //quake2 sprite models
|
#define SP2MODELS //quake2 sprite models
|
||||||
#define MD2MODELS //quake2 alias models
|
#define MD2MODELS //quake2 alias models
|
||||||
#define MD3MODELS //quake3 alias models
|
#define MD3MODELS //quake3 alias models
|
||||||
#define MD5MODELS //doom3 models
|
#define MD5MODELS //doom3 models
|
||||||
#define ZYMOTICMODELS //zymotic skeletal models.
|
#define ZYMOTICMODELS //zymotic skeletal models.
|
||||||
#define HUFFNETWORK //huffman network compression
|
#define DPMMODELS //darkplaces model format (which I've never seen anyone use)
|
||||||
|
#define PSKMODELS //PSK model format (ActorX stuff from UT, though not the format the game itself uses)
|
||||||
#define HALFLIFEMODELS //halflife model support (experimental)
|
#define HALFLIFEMODELS //halflife model support (experimental)
|
||||||
|
|
||||||
|
#define HUFFNETWORK //huffman network compression
|
||||||
//#define DOOMWADS //doom wad/sprite support
|
//#define DOOMWADS //doom wad/sprite support
|
||||||
//#define MAP_DOOM //doom map support
|
//#define MAP_DOOM //doom map support
|
||||||
//#define MAP_PROC //doom3/quake4 map support
|
//#define MAP_PROC //doom3/quake4 map support
|
||||||
|
|
|
@ -211,6 +211,98 @@ void Mod_NormaliseTextureVectors(vec3_t *n, vec3_t *s, vec3_t *t, int v)
|
||||||
|
|
||||||
#ifdef SKELETALMODELS
|
#ifdef SKELETALMODELS
|
||||||
|
|
||||||
|
static void GenMatrix(float x, float y, float z, float qx, float qy, float qz, float result[12])
|
||||||
|
{
|
||||||
|
float qw;
|
||||||
|
{ //figure out qw
|
||||||
|
float term = 1 - (qx*qx) - (qy*qy) - (qz*qz);
|
||||||
|
if (term < 0)
|
||||||
|
qw = 0;
|
||||||
|
else
|
||||||
|
qw = - (float) sqrt(term);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ //generate the matrix
|
||||||
|
/*
|
||||||
|
float xx = qx * qx;
|
||||||
|
float xy = qx * qy;
|
||||||
|
float xz = qx * qz;
|
||||||
|
float xw = qx * qw;
|
||||||
|
float yy = qy * qy;
|
||||||
|
float yz = qy * qz;
|
||||||
|
float yw = qy * qw;
|
||||||
|
float zz = qz * qz;
|
||||||
|
float zw = qz * qw;
|
||||||
|
result[0*4+0] = 1 - 2 * ( yy + zz );
|
||||||
|
result[0*4+1] = 2 * ( xy - zw );
|
||||||
|
result[0*4+2] = 2 * ( xz + yw );
|
||||||
|
result[0*4+3] = x;
|
||||||
|
result[1*4+0] = 2 * ( xy + zw );
|
||||||
|
result[1*4+1] = 1 - 2 * ( xx + zz );
|
||||||
|
result[1*4+2] = 2 * ( yz - xw );
|
||||||
|
result[1*4+3] = y;
|
||||||
|
result[2*4+0] = 2 * ( xz - yw );
|
||||||
|
result[2*4+1] = 2 * ( yz + xw );
|
||||||
|
result[2*4+2] = 1 - 2 * ( xx + yy );
|
||||||
|
result[2*4+3] = z;
|
||||||
|
*/
|
||||||
|
|
||||||
|
float xx, xy, xz, xw, yy, yz, yw, zz, zw;
|
||||||
|
float x2, y2, z2;
|
||||||
|
x2 = qx + qx;
|
||||||
|
y2 = qy + qy;
|
||||||
|
z2 = qz + qz;
|
||||||
|
|
||||||
|
xx = qx * x2; xy = qx * y2; xz = qx * z2;
|
||||||
|
yy = qy * y2; yz = qy * z2; zz = qz * z2;
|
||||||
|
xw = qw * x2; yw = qw * y2; zw = qw * z2;
|
||||||
|
|
||||||
|
result[0*4+0] = 1.0f - (yy + zz);
|
||||||
|
result[1*4+0] = xy + zw;
|
||||||
|
result[2*4+0] = xz - yw;
|
||||||
|
|
||||||
|
result[0*4+1] = xy - zw;
|
||||||
|
result[1*4+1] = 1.0f - (xx + zz);
|
||||||
|
result[2*4+1] = yz + xw;
|
||||||
|
|
||||||
|
result[0*4+2] = xz + yw;
|
||||||
|
result[1*4+2] = yz - xw;
|
||||||
|
result[2*4+2] = 1.0f - (xx + yy);
|
||||||
|
|
||||||
|
result[0*4+3] = x;
|
||||||
|
result[1*4+3] = y;
|
||||||
|
result[2*4+3] = z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PSKGenMatrix(float x, float y, float z, float qx, float qy, float qz, float qw, float result[12])
|
||||||
|
{
|
||||||
|
float xx, xy, xz, xw, yy, yz, yw, zz, zw;
|
||||||
|
float x2, y2, z2;
|
||||||
|
x2 = qx + qx;
|
||||||
|
y2 = qy + qy;
|
||||||
|
z2 = qz + qz;
|
||||||
|
|
||||||
|
xx = qx * x2; xy = qx * y2; xz = qx * z2;
|
||||||
|
yy = qy * y2; yz = qy * z2; zz = qz * z2;
|
||||||
|
xw = qw * x2; yw = qw * y2; zw = qw * z2;
|
||||||
|
|
||||||
|
result[0*4+0] = 1.0f - (yy + zz);
|
||||||
|
result[1*4+0] = xy + zw;
|
||||||
|
result[2*4+0] = xz - yw;
|
||||||
|
|
||||||
|
result[0*4+1] = xy - zw;
|
||||||
|
result[1*4+1] = 1.0f - (xx + zz);
|
||||||
|
result[2*4+1] = yz + xw;
|
||||||
|
|
||||||
|
result[0*4+2] = xz + yw;
|
||||||
|
result[1*4+2] = yz - xw;
|
||||||
|
result[2*4+2] = 1.0f - (xx + yy);
|
||||||
|
|
||||||
|
result[0*4+3] = x;
|
||||||
|
result[1*4+3] = y;
|
||||||
|
result[2*4+3] = z;
|
||||||
|
}
|
||||||
|
|
||||||
void Alias_TransformVerticies(float *bonepose, galisskeletaltransforms_t *weights, int numweights, vecV_t *xyzout, vec3_t *normout)
|
void Alias_TransformVerticies(float *bonepose, galisskeletaltransforms_t *weights, int numweights, vecV_t *xyzout, vec3_t *normout)
|
||||||
{
|
{
|
||||||
|
@ -254,7 +346,7 @@ void Alias_TransformVerticies(float *bonepose, galisskeletaltransforms_t *weight
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Alias_CalculateSkeletalNormals(galiasinfo_t *model)
|
static float Alias_CalculateSkeletalNormals(galiasinfo_t *model)
|
||||||
{
|
{
|
||||||
#ifndef SERVERONLY
|
#ifndef SERVERONLY
|
||||||
//servers don't need normals. except maybe for tracing... but hey. The normal is calculated on a per-triangle basis.
|
//servers don't need normals. except maybe for tracing... but hey. The normal is calculated on a per-triangle basis.
|
||||||
|
@ -275,6 +367,9 @@ static void Alias_CalculateSkeletalNormals(galiasinfo_t *model)
|
||||||
index_t *idx;
|
index_t *idx;
|
||||||
float *bonepose = NULL;
|
float *bonepose = NULL;
|
||||||
float angle;
|
float angle;
|
||||||
|
float maxvdist = 0, d, maxbdist = 0;
|
||||||
|
float absmatrix[MAX_BONES*12];
|
||||||
|
float bonedist[MAX_BONES];
|
||||||
|
|
||||||
while (model)
|
while (model)
|
||||||
{
|
{
|
||||||
|
@ -296,16 +391,64 @@ static void Alias_CalculateSkeletalNormals(galiasinfo_t *model)
|
||||||
if (!model->sharesbones || !bonepose)
|
if (!model->sharesbones || !bonepose)
|
||||||
{
|
{
|
||||||
galiasgroup_t *g;
|
galiasgroup_t *g;
|
||||||
if (!model->groups)
|
galiasbone_t *bones = (galiasbone_t *)((char*)model + model->ofsbones);
|
||||||
return;
|
if (model->baseframeofs)
|
||||||
g = (galiasgroup_t*)((char*)model+model->groupofs);
|
bonepose = (float*)((char*)model + model->baseframeofs);
|
||||||
if (g->numposes < 1)
|
else
|
||||||
return;
|
{
|
||||||
bonepose = (float*)((char*)g+g->poseofs);
|
if (!model->groups)
|
||||||
|
return 0;
|
||||||
|
g = (galiasgroup_t*)((char*)model+model->groupofs);
|
||||||
|
if (g->numposes < 1)
|
||||||
|
return 0;
|
||||||
|
bonepose = (float*)((char*)g+g->poseofs);
|
||||||
|
if (g->isheirachical)
|
||||||
|
{
|
||||||
|
/*needs to be an absolute skeleton*/
|
||||||
|
for (i = 0; i < model->numbones; i++)
|
||||||
|
{
|
||||||
|
if (bones[i].parent >= 0)
|
||||||
|
R_ConcatTransforms((void*)(absmatrix + bones[i].parent*12), (void*)(bonepose+i*12), (void*)(absmatrix+i*12));
|
||||||
|
else
|
||||||
|
for (j = 0;j < 12;j++) //parentless
|
||||||
|
absmatrix[i*12+j] = (bonepose)[i*12+j];
|
||||||
|
}
|
||||||
|
bonepose = absmatrix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*calculate the bone sizes (assuming the bones are strung up and hanging or such)*/
|
||||||
|
for (i = 0; i < model->numbones; i++)
|
||||||
|
{
|
||||||
|
vec3_t d;
|
||||||
|
float *b;
|
||||||
|
b = bonepose + i*12;
|
||||||
|
d[0] = b[3];
|
||||||
|
d[1] = b[7];
|
||||||
|
d[2] = b[11];
|
||||||
|
if (bones[i].parent >= 0)
|
||||||
|
{
|
||||||
|
b = bonepose + bones[i].parent*12;
|
||||||
|
d[0] -= b[3];
|
||||||
|
d[1] -= b[7];
|
||||||
|
d[2] -= b[11];
|
||||||
|
}
|
||||||
|
bonedist[i] = Length(d);
|
||||||
|
if (bones[i].parent >= 0)
|
||||||
|
bonedist[i] += bonedist[bones[i].parent];
|
||||||
|
if (maxbdist < bonedist[i])
|
||||||
|
maxbdist = bonedist[i];
|
||||||
|
}
|
||||||
for (i = 0; i < numbones; i++)
|
for (i = 0; i < numbones; i++)
|
||||||
Matrix3x4_InvertTo3x3(bonepose+i*12, inversepose+i*9);
|
Matrix3x4_InvertTo3x3(bonepose+i*12, inversepose+i*9);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < numweights; i++)
|
||||||
|
{
|
||||||
|
d = Length(v[i].org);
|
||||||
|
if (maxvdist < d)
|
||||||
|
maxvdist = d;
|
||||||
|
}
|
||||||
|
|
||||||
//build the actual base pose positions
|
//build the actual base pose positions
|
||||||
Alias_TransformVerticies(bonepose, v, numweights, xyz, NULL);
|
Alias_TransformVerticies(bonepose, v, numweights, xyz, NULL);
|
||||||
|
|
||||||
|
@ -389,6 +532,8 @@ static void Alias_CalculateSkeletalNormals(galiasinfo_t *model)
|
||||||
model = next;
|
model = next;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
return maxvdist+maxbdist;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int Alias_BuildLerps(float plerp[4], float *pose[4], int numbones, galiasgroup_t *g1, galiasgroup_t *g2, float lerpfrac, float fg1time, float fg2time)
|
static int Alias_BuildLerps(float plerp[4], float *pose[4], int numbones, galiasgroup_t *g1, galiasgroup_t *g2, float lerpfrac, float fg1time, float fg2time)
|
||||||
|
@ -397,6 +542,8 @@ static int Alias_BuildLerps(float plerp[4], float *pose[4], int numbones, galias
|
||||||
int frame2;
|
int frame2;
|
||||||
float mlerp; //minor lerp, poses within a group.
|
float mlerp; //minor lerp, poses within a group.
|
||||||
int l = 0;
|
int l = 0;
|
||||||
|
if (g1 == g2)
|
||||||
|
lerpfrac = 0;
|
||||||
if (fg1time < 0)
|
if (fg1time < 0)
|
||||||
fg1time = 0;
|
fg1time = 0;
|
||||||
mlerp = (fg1time)*g1->rate;
|
mlerp = (fg1time)*g1->rate;
|
||||||
|
@ -413,7 +560,8 @@ static int Alias_BuildLerps(float plerp[4], float *pose[4], int numbones, galias
|
||||||
frame1=(frame1>g1->numposes-1)?g1->numposes-1:frame1;
|
frame1=(frame1>g1->numposes-1)?g1->numposes-1:frame1;
|
||||||
frame2=(frame2>g1->numposes-1)?g1->numposes-1:frame2;
|
frame2=(frame2>g1->numposes-1)?g1->numposes-1:frame2;
|
||||||
}
|
}
|
||||||
|
if (frame1 == frame2)
|
||||||
|
mlerp = 0;
|
||||||
plerp[l] = (1-mlerp)*(1-lerpfrac);
|
plerp[l] = (1-mlerp)*(1-lerpfrac);
|
||||||
if (plerp[l]>0)
|
if (plerp[l]>0)
|
||||||
pose[l++] = (float *)((char *)g1 + g1->poseofs + sizeof(float)*numbones*12*frame1);
|
pose[l++] = (float *)((char *)g1 + g1->poseofs + sizeof(float)*numbones*12*frame1);
|
||||||
|
@ -439,7 +587,8 @@ static int Alias_BuildLerps(float plerp[4], float *pose[4], int numbones, galias
|
||||||
frame1=(frame1>g2->numposes-1)?g2->numposes-1:frame1;
|
frame1=(frame1>g2->numposes-1)?g2->numposes-1:frame1;
|
||||||
frame2=(frame2>g2->numposes-1)?g2->numposes-1:frame2;
|
frame2=(frame2>g2->numposes-1)?g2->numposes-1:frame2;
|
||||||
}
|
}
|
||||||
|
if (frame1 == frame2)
|
||||||
|
mlerp = 0;
|
||||||
plerp[l] = (1-mlerp)*(lerpfrac);
|
plerp[l] = (1-mlerp)*(lerpfrac);
|
||||||
if (plerp[l]>0)
|
if (plerp[l]>0)
|
||||||
pose[l++] = (float *)((char *)g2 + g2->poseofs + sizeof(float)*numbones*12*frame1);
|
pose[l++] = (float *)((char *)g2 + g2->poseofs + sizeof(float)*numbones*12*frame1);
|
||||||
|
@ -567,7 +716,7 @@ int Alias_GetBoneRelations(galiasinfo_t *inf, framestate_t *fstate, float *resul
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//_may_ into bonepose, return value is the real result
|
//_may_ write into bonepose, return value is the real result
|
||||||
float *Alias_GetBonePositions(galiasinfo_t *inf, framestate_t *fstate, float *buffer, int buffersize)
|
float *Alias_GetBonePositions(galiasinfo_t *inf, framestate_t *fstate, float *buffer, int buffersize)
|
||||||
{
|
{
|
||||||
#ifdef SKELETALMODELS
|
#ifdef SKELETALMODELS
|
||||||
|
@ -920,6 +1069,8 @@ static void Alias_BuildSkeletalMesh(mesh_t *mesh, float *bonepose, galisskeletal
|
||||||
#ifdef GLQUAKE
|
#ifdef GLQUAKE
|
||||||
static void Alias_GLDrawSkeletalBones(galiasbone_t *bones, float *bonepose, int bonecount)
|
static void Alias_GLDrawSkeletalBones(galiasbone_t *bones, float *bonepose, int bonecount)
|
||||||
{
|
{
|
||||||
|
PPL_RevertToKnownState();
|
||||||
|
BE_SelectEntity(currententity);
|
||||||
qglColor3f(1, 0, 0);
|
qglColor3f(1, 0, 0);
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -1060,8 +1211,8 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, galiasinfo_t *inf,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef GLQUAKE
|
#ifdef GLQUAKE
|
||||||
if (!mesh->numindexes && qrenderer == QR_OPENGL)
|
if (!inf->numtransforms && qrenderer == QR_OPENGL)
|
||||||
Alias_GLDrawSkeletalBones((galiasbone_t*)((char*)inf + inf->ofsbones), (float *)bonepose, inf->numbones);
|
Alias_GLDrawSkeletalBones((galiasbone_t*)((char*)inf + inf->ofsbones), (float *)usebonepose, inf->numbones);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (mesh->colors4f_array)
|
if (mesh->colors4f_array)
|
||||||
|
@ -3992,10 +4143,614 @@ qboolean Mod_LoadZymoticModel(model_t *mod, void *buffer)
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
#endif //ZYMOTICMODELS
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////
|
||||||
|
//psk
|
||||||
|
#ifdef PSKMODELS
|
||||||
|
/*Typedefs copied from DarkPlaces*/
|
||||||
|
|
||||||
|
typedef struct pskchunk_s
|
||||||
|
{
|
||||||
|
// id is one of the following:
|
||||||
|
// .psk:
|
||||||
|
// ACTRHEAD (recordsize = 0, numrecords = 0)
|
||||||
|
// PNTS0000 (recordsize = 12, pskpnts_t)
|
||||||
|
// VTXW0000 (recordsize = 16, pskvtxw_t)
|
||||||
|
// FACE0000 (recordsize = 12, pskface_t)
|
||||||
|
// MATT0000 (recordsize = 88, pskmatt_t)
|
||||||
|
// REFSKELT (recordsize = 120, pskboneinfo_t)
|
||||||
|
// RAWWEIGHTS (recordsize = 12, pskrawweights_t)
|
||||||
|
// .psa:
|
||||||
|
// ANIMHEAD (recordsize = 0, numrecords = 0)
|
||||||
|
// BONENAMES (recordsize = 120, pskboneinfo_t)
|
||||||
|
// ANIMINFO (recordsize = 168, pskaniminfo_t)
|
||||||
|
// ANIMKEYS (recordsize = 32, pskanimkeys_t)
|
||||||
|
char id[20];
|
||||||
|
// in .psk always 0x1e83b9
|
||||||
|
// in .psa always 0x2e
|
||||||
|
int version;
|
||||||
|
int recordsize;
|
||||||
|
int numrecords;
|
||||||
|
} pskchunk_t;
|
||||||
|
|
||||||
|
typedef struct pskpnts_s
|
||||||
|
{
|
||||||
|
float origin[3];
|
||||||
|
} pskpnts_t;
|
||||||
|
|
||||||
|
typedef struct pskvtxw_s
|
||||||
|
{
|
||||||
|
unsigned short pntsindex; // index into PNTS0000 chunk
|
||||||
|
unsigned char unknown1[2]; // seems to be garbage
|
||||||
|
float texcoord[2];
|
||||||
|
unsigned char mattindex; // index into MATT0000 chunk
|
||||||
|
unsigned char unknown2; // always 0?
|
||||||
|
unsigned char unknown3[2]; // seems to be garbage
|
||||||
|
} pskvtxw_t;
|
||||||
|
|
||||||
|
typedef struct pskface_s
|
||||||
|
{
|
||||||
|
unsigned short vtxwindex[3]; // triangle
|
||||||
|
unsigned char mattindex; // index into MATT0000 chunk
|
||||||
|
unsigned char unknown; // seems to be garbage
|
||||||
|
unsigned int group; // faces seem to be grouped, possibly for smoothing?
|
||||||
|
} pskface_t;
|
||||||
|
|
||||||
|
typedef struct pskmatt_s
|
||||||
|
{
|
||||||
|
char name[64];
|
||||||
|
int unknown[6]; // observed 0 0 0 0 5 0
|
||||||
|
} pskmatt_t;
|
||||||
|
|
||||||
|
typedef struct pskpose_s
|
||||||
|
{
|
||||||
|
float quat[4];
|
||||||
|
float origin[3];
|
||||||
|
float unknown; // probably a float, always seems to be 0
|
||||||
|
float size[3];
|
||||||
|
} pskpose_t;
|
||||||
|
|
||||||
|
typedef struct pskboneinfo_s
|
||||||
|
{
|
||||||
|
char name[64];
|
||||||
|
int unknown1;
|
||||||
|
int numchildren;
|
||||||
|
int parent; // root bones have 0 here
|
||||||
|
pskpose_t basepose;
|
||||||
|
} pskboneinfo_t;
|
||||||
|
|
||||||
|
typedef struct pskrawweights_s
|
||||||
|
{
|
||||||
|
float weight;
|
||||||
|
int pntsindex;
|
||||||
|
int boneindex;
|
||||||
|
} pskrawweights_t;
|
||||||
|
|
||||||
|
typedef struct pskaniminfo_s
|
||||||
|
{
|
||||||
|
char name[64];
|
||||||
|
char group[64];
|
||||||
|
int numbones;
|
||||||
|
int unknown1;
|
||||||
|
int unknown2;
|
||||||
|
int unknown3;
|
||||||
|
float unknown4;
|
||||||
|
float playtime; // not really needed
|
||||||
|
float fps; // frames per second
|
||||||
|
int unknown5;
|
||||||
|
int firstframe;
|
||||||
|
int numframes;
|
||||||
|
// firstanimkeys = (firstframe + frameindex) * numbones
|
||||||
|
} pskaniminfo_t;
|
||||||
|
|
||||||
|
typedef struct pskanimkeys_s
|
||||||
|
{
|
||||||
|
float origin[3];
|
||||||
|
float quat[4];
|
||||||
|
float frametime;
|
||||||
|
} pskanimkeys_t;
|
||||||
|
|
||||||
|
|
||||||
|
qboolean Mod_LoadPSKModel(model_t *mod, void *buffer)
|
||||||
|
{
|
||||||
|
pskchunk_t *chunk;
|
||||||
|
unsigned int pos = 0;
|
||||||
|
unsigned int i, j;
|
||||||
|
qboolean fail = false;
|
||||||
|
char basename[MAX_QPATH];
|
||||||
|
|
||||||
|
float *stcoord;
|
||||||
|
galiasinfo_t *gmdl;
|
||||||
|
galiasskin_t *skin;
|
||||||
|
texnums_t *gtexnums;
|
||||||
|
galisskeletaltransforms_t *trans;
|
||||||
|
galiasbone_t *bones;
|
||||||
|
galiasgroup_t *group;
|
||||||
|
float *animmatrix, *basematrix, *basematrix_inverse;
|
||||||
|
unsigned int num_trans;
|
||||||
|
index_t *indexes;
|
||||||
|
float vrad;
|
||||||
|
|
||||||
|
pskpnts_t *pnts = NULL;
|
||||||
|
pskvtxw_t *vtxw = NULL;
|
||||||
|
pskface_t *face = NULL;
|
||||||
|
pskmatt_t *matt = NULL;
|
||||||
|
pskboneinfo_t *boneinfo = NULL;
|
||||||
|
pskrawweights_t *rawweights = NULL;
|
||||||
|
unsigned int num_pnts, num_vtxw=0, num_face=0, num_matt = 0, num_boneinfo=0, num_rawweights=0;
|
||||||
|
|
||||||
|
pskaniminfo_t *animinfo = NULL;
|
||||||
|
pskanimkeys_t *animkeys = NULL;
|
||||||
|
unsigned int num_animinfo=0, num_animkeys=0;
|
||||||
|
|
||||||
|
int hunkstart, hunkend, hunktotal;
|
||||||
|
extern cvar_t temp1;
|
||||||
|
|
||||||
|
/*load the psk*/
|
||||||
|
while (pos < com_filesize && !fail)
|
||||||
|
{
|
||||||
|
chunk = (pskchunk_t*)((char*)buffer + pos);
|
||||||
|
chunk->version = LittleLong(chunk->version);
|
||||||
|
chunk->recordsize = LittleLong(chunk->recordsize);
|
||||||
|
chunk->numrecords = LittleLong(chunk->numrecords);
|
||||||
|
|
||||||
|
pos += sizeof(*chunk);
|
||||||
|
|
||||||
|
if (!strcmp("ACTRHEAD", chunk->id) && chunk->recordsize == 0 && chunk->numrecords == 0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else if (!strcmp("PNTS0000", chunk->id) && chunk->recordsize == sizeof(pskpnts_t))
|
||||||
|
{
|
||||||
|
num_pnts = chunk->numrecords;
|
||||||
|
pnts = (pskpnts_t*)((char*)buffer + pos);
|
||||||
|
pos += chunk->recordsize * chunk->numrecords;
|
||||||
|
|
||||||
|
for (i = 0; i < num_pnts; i++)
|
||||||
|
{
|
||||||
|
pnts[i].origin[0] = LittleFloat(pnts[i].origin[0]);
|
||||||
|
pnts[i].origin[1] = LittleFloat(pnts[i].origin[1]);
|
||||||
|
pnts[i].origin[2] = LittleFloat(pnts[i].origin[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!strcmp("VTXW0000", chunk->id) && chunk->recordsize == sizeof(pskvtxw_t))
|
||||||
|
{
|
||||||
|
num_vtxw = chunk->numrecords;
|
||||||
|
vtxw = (pskvtxw_t*)((char*)buffer + pos);
|
||||||
|
pos += chunk->recordsize * chunk->numrecords;
|
||||||
|
|
||||||
|
for (i = 0; i < num_vtxw; i++)
|
||||||
|
{
|
||||||
|
vtxw[i].pntsindex = LittleShort(vtxw[i].pntsindex);
|
||||||
|
vtxw[i].texcoord[0] = LittleFloat(vtxw[i].texcoord[0]);
|
||||||
|
vtxw[i].texcoord[1] = LittleFloat(vtxw[i].texcoord[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!strcmp("FACE0000", chunk->id) && chunk->recordsize == sizeof(pskface_t))
|
||||||
|
{
|
||||||
|
num_face = chunk->numrecords;
|
||||||
|
face = (pskface_t*)((char*)buffer + pos);
|
||||||
|
pos += chunk->recordsize * chunk->numrecords;
|
||||||
|
|
||||||
|
for (i = 0; i < num_face; i++)
|
||||||
|
{
|
||||||
|
face[i].vtxwindex[0] = LittleShort(face[i].vtxwindex[0]);
|
||||||
|
face[i].vtxwindex[1] = LittleShort(face[i].vtxwindex[1]);
|
||||||
|
face[i].vtxwindex[2] = LittleShort(face[i].vtxwindex[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!strcmp("MATT0000", chunk->id) && chunk->recordsize == sizeof(pskmatt_t))
|
||||||
|
{
|
||||||
|
num_matt = chunk->numrecords;
|
||||||
|
matt = (pskmatt_t*)((char*)buffer + pos);
|
||||||
|
pos += chunk->recordsize * chunk->numrecords;
|
||||||
|
}
|
||||||
|
else if (!strcmp("REFSKELT", chunk->id) && chunk->recordsize == sizeof(pskboneinfo_t))
|
||||||
|
{
|
||||||
|
num_boneinfo = chunk->numrecords;
|
||||||
|
boneinfo = (pskboneinfo_t*)((char*)buffer + pos);
|
||||||
|
pos += chunk->recordsize * chunk->numrecords;
|
||||||
|
|
||||||
|
for (i = 0; i < num_boneinfo; i++)
|
||||||
|
{
|
||||||
|
boneinfo[i].parent = LittleLong(boneinfo[i].parent);
|
||||||
|
boneinfo[i].basepose.origin[0] = LittleFloat(boneinfo[i].basepose.origin[0]);
|
||||||
|
boneinfo[i].basepose.origin[1] = LittleFloat(boneinfo[i].basepose.origin[1]);
|
||||||
|
boneinfo[i].basepose.origin[2] = LittleFloat(boneinfo[i].basepose.origin[2]);
|
||||||
|
boneinfo[i].basepose.quat[0] = LittleFloat(boneinfo[i].basepose.quat[0]);
|
||||||
|
boneinfo[i].basepose.quat[1] = LittleFloat(boneinfo[i].basepose.quat[1]);
|
||||||
|
boneinfo[i].basepose.quat[2] = LittleFloat(boneinfo[i].basepose.quat[2]);
|
||||||
|
boneinfo[i].basepose.quat[3] = LittleFloat(boneinfo[i].basepose.quat[3]);
|
||||||
|
boneinfo[i].basepose.size[0] = LittleFloat(boneinfo[i].basepose.size[0]);
|
||||||
|
boneinfo[i].basepose.size[1] = LittleFloat(boneinfo[i].basepose.size[1]);
|
||||||
|
boneinfo[i].basepose.size[2] = LittleFloat(boneinfo[i].basepose.size[2]);
|
||||||
|
|
||||||
|
/*not sure if this is needed, but mimic DP*/
|
||||||
|
if (i)
|
||||||
|
{
|
||||||
|
boneinfo[i].basepose.quat[0] *= -1;
|
||||||
|
boneinfo[i].basepose.quat[2] *= -1;
|
||||||
|
}
|
||||||
|
boneinfo[i].basepose.quat[1] *= -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!strcmp("RAWWEIGHTS", chunk->id) && chunk->recordsize == sizeof(pskrawweights_t))
|
||||||
|
{
|
||||||
|
num_rawweights = chunk->numrecords;
|
||||||
|
rawweights = (pskrawweights_t*)((char*)buffer + pos);
|
||||||
|
pos += chunk->recordsize * chunk->numrecords;
|
||||||
|
|
||||||
|
for (i = 0; i < num_rawweights; i++)
|
||||||
|
{
|
||||||
|
rawweights[i].boneindex = LittleLong(rawweights[i].boneindex);
|
||||||
|
rawweights[i].pntsindex = LittleLong(rawweights[i].pntsindex);
|
||||||
|
rawweights[i].weight = LittleFloat(rawweights[i].weight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Con_Printf(CON_ERROR "%s has unsupported chunk %s of %i size with version %i.\n", mod->name, chunk->id, chunk->recordsize, chunk->version);
|
||||||
|
fail = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!num_matt)
|
||||||
|
fail = true;
|
||||||
|
|
||||||
|
if (!pnts || !vtxw || !face || !matt || !boneinfo || !rawweights)
|
||||||
|
fail = true;
|
||||||
|
|
||||||
|
/*attempt to load a psa file. don't die if we can't find one*/
|
||||||
|
COM_StripExtension(mod->name, basename, sizeof(basename));
|
||||||
|
buffer = COM_LoadTempFile2(va("%s.psa", basename));
|
||||||
|
if (buffer)
|
||||||
|
{
|
||||||
|
pos = 0;
|
||||||
|
while (pos < com_filesize && !fail)
|
||||||
|
{
|
||||||
|
chunk = (pskchunk_t*)((char*)buffer + pos);
|
||||||
|
chunk->version = LittleLong(chunk->version);
|
||||||
|
chunk->recordsize = LittleLong(chunk->recordsize);
|
||||||
|
chunk->numrecords = LittleLong(chunk->numrecords);
|
||||||
|
|
||||||
|
pos += sizeof(*chunk);
|
||||||
|
|
||||||
|
if (!strcmp("ANIMHEAD", chunk->id) && chunk->recordsize == 0 && chunk->numrecords == 0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else if (!strcmp("BONENAMES", chunk->id) && chunk->recordsize == sizeof(pskboneinfo_t))
|
||||||
|
{
|
||||||
|
/*parsed purely to ensure that the bones match the main model*/
|
||||||
|
pskboneinfo_t *animbones = (pskboneinfo_t*)((char*)buffer + pos);
|
||||||
|
pos += chunk->recordsize * chunk->numrecords;
|
||||||
|
if (num_boneinfo != chunk->numrecords)
|
||||||
|
{
|
||||||
|
fail = true;
|
||||||
|
Con_Printf("PSK/PSA bone counts do not match\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (i = 0; i < num_boneinfo; i++)
|
||||||
|
{
|
||||||
|
animbones[i].parent = LittleLong(animbones[i].parent);
|
||||||
|
|
||||||
|
if (strcmp(boneinfo[i].name, animbones[i].name))
|
||||||
|
{
|
||||||
|
fail = true;
|
||||||
|
Con_Printf("PSK/PSA bone names do not match\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (boneinfo[i].parent != animbones[i].parent)
|
||||||
|
{
|
||||||
|
fail = true;
|
||||||
|
Con_Printf("PSK/PSA bone parents do not match\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!strcmp("ANIMINFO", chunk->id) && chunk->recordsize == sizeof(pskaniminfo_t))
|
||||||
|
{
|
||||||
|
num_animinfo = chunk->numrecords;
|
||||||
|
animinfo = (pskaniminfo_t*)((char*)buffer + pos);
|
||||||
|
pos += chunk->recordsize * chunk->numrecords;
|
||||||
|
|
||||||
|
for (i = 0; i < num_animinfo; i++)
|
||||||
|
{
|
||||||
|
animinfo[i].firstframe = LittleLong(animinfo[i].firstframe);
|
||||||
|
animinfo[i].numframes = LittleLong(animinfo[i].numframes);
|
||||||
|
animinfo[i].numbones = LittleLong(animinfo[i].numbones);
|
||||||
|
animinfo[i].fps = LittleFloat(animinfo[i].fps);
|
||||||
|
animinfo[i].playtime = LittleFloat(animinfo[i].playtime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!strcmp("ANIMKEYS", chunk->id) && chunk->recordsize == sizeof(pskanimkeys_t))
|
||||||
|
{
|
||||||
|
num_animkeys = chunk->numrecords;
|
||||||
|
animkeys = (pskanimkeys_t*)((char*)buffer + pos);
|
||||||
|
pos += chunk->recordsize * chunk->numrecords;
|
||||||
|
|
||||||
|
for (i = 0; i < num_animkeys; i++)
|
||||||
|
{
|
||||||
|
animkeys[i].origin[0] = LittleFloat(animkeys[i].origin[0]);
|
||||||
|
animkeys[i].origin[1] = LittleFloat(animkeys[i].origin[1]);
|
||||||
|
animkeys[i].origin[2] = LittleFloat(animkeys[i].origin[2]);
|
||||||
|
animkeys[i].quat[0] = LittleFloat(animkeys[i].quat[0]);
|
||||||
|
animkeys[i].quat[1] = LittleFloat(animkeys[i].quat[1]);
|
||||||
|
animkeys[i].quat[2] = LittleFloat(animkeys[i].quat[2]);
|
||||||
|
animkeys[i].quat[3] = LittleFloat(animkeys[i].quat[3]);
|
||||||
|
|
||||||
|
/*not sure if this is needed, but mimic DP*/
|
||||||
|
if (i%num_boneinfo)
|
||||||
|
{
|
||||||
|
animkeys[i].quat[0] *= -1;
|
||||||
|
animkeys[i].quat[2] *= -1;
|
||||||
|
}
|
||||||
|
animkeys[i].quat[1] *= -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!strcmp("SCALEKEYS", chunk->id) && chunk->recordsize == 16)
|
||||||
|
{
|
||||||
|
pos += chunk->recordsize * chunk->numrecords;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Con_Printf(CON_ERROR "%s has unsupported chunk %s of %i size with version %i.\n", va("%s.psa", basename), chunk->id, chunk->recordsize, chunk->version);
|
||||||
|
fail = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fail)
|
||||||
|
{
|
||||||
|
animinfo = NULL;
|
||||||
|
num_animinfo = 0;
|
||||||
|
animkeys = NULL;
|
||||||
|
num_animkeys = 0;
|
||||||
|
fail = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fail)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
hunkstart = Hunk_LowMark ();
|
||||||
|
|
||||||
|
gmdl = Hunk_Alloc(sizeof(*gmdl)*num_matt);
|
||||||
|
|
||||||
|
/*bones!*/
|
||||||
|
bones = Hunk_Alloc(sizeof(galiasbone_t) * num_boneinfo);
|
||||||
|
for (i = 0; i < num_boneinfo; i++)
|
||||||
|
{
|
||||||
|
Q_strncpyz(bones[i].name, boneinfo[i].name, sizeof(bones[i].name));
|
||||||
|
bones[i].parent = boneinfo[i].parent;
|
||||||
|
if (i == 0 && bones[i].parent == 0)
|
||||||
|
bones[i].parent = -1;
|
||||||
|
else if (bones[i].parent >= i || bones[i].parent < -1)
|
||||||
|
{
|
||||||
|
Con_Printf("Invalid bones\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
basematrix = Hunk_Alloc(num_boneinfo*sizeof(float)*12);
|
||||||
|
for (i = 0; i < num_boneinfo; i++)
|
||||||
|
{
|
||||||
|
float tmp[12];
|
||||||
|
PSKGenMatrix(
|
||||||
|
boneinfo[i].basepose.origin[0], boneinfo[i].basepose.origin[1], boneinfo[i].basepose.origin[2],
|
||||||
|
boneinfo[i].basepose.quat[0], boneinfo[i].basepose.quat[1], boneinfo[i].basepose.quat[2], boneinfo[i].basepose.quat[3],
|
||||||
|
tmp);
|
||||||
|
if (bones[i].parent < 0)
|
||||||
|
memcpy(basematrix + i*12, tmp, sizeof(float)*12);
|
||||||
|
else
|
||||||
|
R_ConcatTransforms((void*)(basematrix + bones[i].parent*12), (void*)tmp, (void*)(basematrix+i*12));
|
||||||
|
}
|
||||||
|
|
||||||
|
basematrix_inverse = Hunk_TempAllocMore(num_boneinfo*sizeof(float)*16);
|
||||||
|
for (i = 0; i < num_boneinfo; i++)
|
||||||
|
{
|
||||||
|
Matrix4Q_Invert_Simple(basematrix+i*12, basematrix_inverse+i*16);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*expand the translations*/
|
||||||
|
num_trans = 0;
|
||||||
|
for (i = 0; i < num_vtxw; i++)
|
||||||
|
{
|
||||||
|
for (j = 0; j < num_rawweights; j++)
|
||||||
|
{
|
||||||
|
if (rawweights[j].pntsindex == vtxw[i].pntsindex)
|
||||||
|
{
|
||||||
|
num_trans++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trans = Hunk_Alloc(sizeof(*trans)*num_trans);
|
||||||
|
num_trans = 0;
|
||||||
|
for (i = 0; i < num_vtxw; i++)
|
||||||
|
{
|
||||||
|
// first_trans = num_trans;
|
||||||
|
for (j = 0; j < num_rawweights; j++)
|
||||||
|
{
|
||||||
|
if (rawweights[j].pntsindex == vtxw[i].pntsindex)
|
||||||
|
{
|
||||||
|
vec3_t tmp;
|
||||||
|
trans[num_trans].vertexindex = i;
|
||||||
|
trans[num_trans].boneindex = rawweights[j].boneindex;
|
||||||
|
VectorTransform(pnts[rawweights[j].pntsindex].origin, (void*)(basematrix_inverse + rawweights[j].boneindex*16), tmp);
|
||||||
|
VectorScale(tmp, rawweights[j].weight, trans[num_trans].org);
|
||||||
|
trans[num_trans].org[3] = rawweights[j].weight;
|
||||||
|
num_trans++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// for (j = 0; j < num_trans-first_trans; j++)
|
||||||
|
// {
|
||||||
|
// VectorScale(pnts[rawweights[j].pntsindex].origin, rawweights[j].weight, trans[num_trans].org);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
/*st coords, all share the same list*/
|
||||||
|
stcoord = Hunk_Alloc(sizeof(vec2_t)*num_vtxw);
|
||||||
|
for (i = 0; i < num_vtxw; i++)
|
||||||
|
{
|
||||||
|
stcoord[i*2+0] = vtxw[i].texcoord[0];
|
||||||
|
stcoord[i*2+1] = vtxw[i].texcoord[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*allocate faces in a single block, as we at least know an upper bound*/
|
||||||
|
indexes = Hunk_Alloc(sizeof(index_t)*num_face*3);
|
||||||
|
|
||||||
|
if (animinfo && animkeys)
|
||||||
|
{
|
||||||
|
if (1/*dpcompat_psa_ungroup.ival*/)
|
||||||
|
{
|
||||||
|
/*unpack each frame of each animation to be a separate framegroup*/
|
||||||
|
unsigned int iframe; /*individual frame count*/
|
||||||
|
iframe = 0;
|
||||||
|
for (i = 0; i < num_animinfo; i++)
|
||||||
|
iframe += animinfo[i].numframes;
|
||||||
|
group = Hunk_Alloc(sizeof(galiasgroup_t)*iframe + num_animkeys*sizeof(float)*12);
|
||||||
|
animmatrix = (float*)(group+iframe);
|
||||||
|
iframe = 0;
|
||||||
|
for (j = 0; j < num_animinfo; j++)
|
||||||
|
{
|
||||||
|
for (i = 0; i < animinfo[j].numframes; i++)
|
||||||
|
{
|
||||||
|
group[iframe].poseofs = ((char*)animmatrix - (char*)&group[iframe]) + sizeof(float)*12*num_boneinfo*(animinfo[j].firstframe+i);
|
||||||
|
group[iframe].numposes = 1;
|
||||||
|
snprintf(group[iframe].name, sizeof(group[iframe].name), "%s_%i", animinfo[j].name, i);
|
||||||
|
group[iframe].loop = true;
|
||||||
|
group[iframe].rate = animinfo[j].fps;
|
||||||
|
group[iframe].isheirachical = true;
|
||||||
|
iframe++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
num_animinfo = iframe;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*keep each framegroup as a group*/
|
||||||
|
group = Hunk_Alloc(sizeof(galiasgroup_t)*num_animinfo + num_animkeys*sizeof(float)*12);
|
||||||
|
animmatrix = (float*)(group+num_animinfo);
|
||||||
|
for (i = 0; i < num_animinfo; i++)
|
||||||
|
{
|
||||||
|
group[i].poseofs = (char*)animmatrix - (char*)&group[i] + sizeof(float)*12*num_boneinfo*animinfo[i].firstframe;
|
||||||
|
group[i].numposes = animinfo[i].numframes;
|
||||||
|
Q_strncpyz(group[i].name, animinfo[i].name, sizeof(group[i].name));
|
||||||
|
group[i].loop = true;
|
||||||
|
group[i].rate = animinfo[i].fps;
|
||||||
|
group[i].isheirachical = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i = 0; i < num_animkeys; i++)
|
||||||
|
{
|
||||||
|
PSKGenMatrix(
|
||||||
|
animkeys[i].origin[0], animkeys[i].origin[1], animkeys[i].origin[2],
|
||||||
|
animkeys[i].quat[0], animkeys[i].quat[1], animkeys[i].quat[2], animkeys[i].quat[3],
|
||||||
|
animmatrix + i*12);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
num_animinfo = 1;
|
||||||
|
/*build a base pose*/
|
||||||
|
group = Hunk_Alloc(sizeof(galiasgroup_t) + num_boneinfo*sizeof(float)*12);
|
||||||
|
animmatrix = basematrix;
|
||||||
|
group->poseofs = (char*)animmatrix - (char*)group;
|
||||||
|
group->numposes = 1;
|
||||||
|
strcpy(group->name, "base");
|
||||||
|
group->loop = true;
|
||||||
|
group->rate = 10;
|
||||||
|
group->isheirachical = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < num_matt; i++)
|
||||||
|
{
|
||||||
|
skin = Hunk_Alloc(sizeof(galiasskin_t) + sizeof(texnums_t));
|
||||||
|
gtexnums = (texnums_t*)(skin+1);
|
||||||
|
skin->ofstexnums = sizeof(*skin);
|
||||||
|
skin->texnums = 1;
|
||||||
|
skin->skinspeed = 10;
|
||||||
|
Q_strncpyz(skin->name, matt[i].name, sizeof(skin->name));
|
||||||
|
gtexnums->shader = R_RegisterSkin(matt[i].name);
|
||||||
|
R_BuildDefaultTexnums(gtexnums, gtexnums->shader);
|
||||||
|
|
||||||
|
gmdl[i].groupofs = (char*)group - (char*)&gmdl[i];
|
||||||
|
gmdl[i].groups = num_animinfo;
|
||||||
|
gmdl[i].baseframeofs = (char*)basematrix - (char*)&gmdl[i];
|
||||||
|
|
||||||
|
gmdl[i].ofsskins = (char*)skin - (char*)&gmdl[i];
|
||||||
|
gmdl[i].numskins = 1;
|
||||||
|
|
||||||
|
gmdl[i].numindexes = 0;
|
||||||
|
for (j = 0; j < num_face; j++)
|
||||||
|
{
|
||||||
|
if (face[j].mattindex == i)
|
||||||
|
{
|
||||||
|
indexes[gmdl[i].numindexes+0] = face[j].vtxwindex[0];
|
||||||
|
indexes[gmdl[i].numindexes+1] = face[j].vtxwindex[1];
|
||||||
|
indexes[gmdl[i].numindexes+2] = face[j].vtxwindex[2];
|
||||||
|
gmdl[i].numindexes += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gmdl[i].ofs_indexes = (char*)indexes - (char*)&gmdl[i];
|
||||||
|
indexes += gmdl[i].numindexes;
|
||||||
|
|
||||||
|
gmdl[i].ofs_st_array = (char*)stcoord - (char*)&gmdl[i];
|
||||||
|
gmdl[i].numverts = num_vtxw;
|
||||||
|
|
||||||
|
gmdl[i].ofsbones = (char*)bones - (char*)&gmdl[i];
|
||||||
|
gmdl[i].numbones = num_boneinfo;
|
||||||
|
|
||||||
|
gmdl[i].ofstransforms = (char*)trans - (char*)&gmdl[i];
|
||||||
|
gmdl[i].numtransforms = num_trans;
|
||||||
|
|
||||||
|
gmdl[i].sharesverts = i!=0;
|
||||||
|
gmdl[i].sharesbones = i!=0;
|
||||||
|
gmdl[i].nextsurf = (i != num_matt-1)?sizeof(*gmdl):0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fail)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
vrad = Alias_CalculateSkeletalNormals(gmdl);
|
||||||
|
|
||||||
|
mod->mins[0] = mod->mins[1] = mod->mins[2] = -vrad;
|
||||||
|
mod->maxs[0] = mod->maxs[1] = mod->maxs[2] = vrad;
|
||||||
|
mod->radius = vrad;
|
||||||
|
//
|
||||||
|
// move the complete, relocatable alias model to the cache
|
||||||
|
//
|
||||||
|
hunkend = Hunk_LowMark ();
|
||||||
|
|
||||||
|
mod->flags = Mod_ReadFlagsFromMD1(mod->name, 0); //file replacement - inherit flags from any defunc mdl files.
|
||||||
|
|
||||||
|
Mod_ClampModelSize(mod);
|
||||||
|
|
||||||
|
Hunk_Alloc(0);
|
||||||
|
hunktotal = hunkend - hunkstart;
|
||||||
|
|
||||||
|
Cache_Alloc (&mod->cache, hunktotal, loadname);
|
||||||
|
mod->type = mod_alias;
|
||||||
|
if (!mod->cache.data)
|
||||||
|
{
|
||||||
|
Hunk_FreeToLowMark (hunkstart);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memcpy (mod->cache.data, gmdl, hunktotal);
|
||||||
|
|
||||||
|
Hunk_FreeToLowMark (hunkstart);
|
||||||
|
|
||||||
|
|
||||||
|
mod->funcs.Trace = Mod_Trace;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -4003,7 +4758,7 @@ qboolean Mod_LoadZymoticModel(model_t *mod, void *buffer)
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////
|
||||||
//dpm
|
//dpm
|
||||||
|
#ifdef DPMMODELS
|
||||||
|
|
||||||
// header for the entire file
|
// header for the entire file
|
||||||
typedef struct dpmheader_s
|
typedef struct dpmheader_s
|
||||||
|
@ -4351,16 +5106,11 @@ qboolean Mod_LoadDarkPlacesModel(model_t *mod, void *buffer)
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
#endif //DPMMODELS
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif //ZYMOTICMODELS
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef INTERQUAKEMODELS
|
#ifdef INTERQUAKEMODELS
|
||||||
#define IQM_MAGIC "INTERQUAKEMODEL"
|
#define IQM_MAGIC "INTERQUAKEMODEL"
|
||||||
#define IQM_VERSION 1
|
#define IQM_VERSION 1
|
||||||
|
@ -4617,70 +5367,6 @@ qboolean Mod_LoadInterQuakeModel(model_t *mod, void *buffer)
|
||||||
|
|
||||||
#ifdef MD5MODELS
|
#ifdef MD5MODELS
|
||||||
|
|
||||||
static void GenMatrix(float x, float y, float z, float qx, float qy, float qz, float result[12])
|
|
||||||
{
|
|
||||||
float qw;
|
|
||||||
{ //figure out qw
|
|
||||||
float term = 1 - (qx*qx) - (qy*qy) - (qz*qz);
|
|
||||||
if (term < 0)
|
|
||||||
qw = 0;
|
|
||||||
else
|
|
||||||
qw = - (float) sqrt(term);
|
|
||||||
}
|
|
||||||
|
|
||||||
{ //generate the matrix
|
|
||||||
/*
|
|
||||||
float xx = qx * qx;
|
|
||||||
float xy = qx * qy;
|
|
||||||
float xz = qx * qz;
|
|
||||||
float xw = qx * qw;
|
|
||||||
float yy = qy * qy;
|
|
||||||
float yz = qy * qz;
|
|
||||||
float yw = qy * qw;
|
|
||||||
float zz = qz * qz;
|
|
||||||
float zw = qz * qw;
|
|
||||||
result[0*4+0] = 1 - 2 * ( yy + zz );
|
|
||||||
result[0*4+1] = 2 * ( xy - zw );
|
|
||||||
result[0*4+2] = 2 * ( xz + yw );
|
|
||||||
result[0*4+3] = x;
|
|
||||||
result[1*4+0] = 2 * ( xy + zw );
|
|
||||||
result[1*4+1] = 1 - 2 * ( xx + zz );
|
|
||||||
result[1*4+2] = 2 * ( yz - xw );
|
|
||||||
result[1*4+3] = y;
|
|
||||||
result[2*4+0] = 2 * ( xz - yw );
|
|
||||||
result[2*4+1] = 2 * ( yz + xw );
|
|
||||||
result[2*4+2] = 1 - 2 * ( xx + yy );
|
|
||||||
result[2*4+3] = z;
|
|
||||||
*/
|
|
||||||
|
|
||||||
float xx, xy, xz, xw, yy, yz, yw, zz, zw;
|
|
||||||
float x2, y2, z2;
|
|
||||||
x2 = qx + qx;
|
|
||||||
y2 = qy + qy;
|
|
||||||
z2 = qz + qz;
|
|
||||||
|
|
||||||
xx = qx * x2; xy = qx * y2; xz = qx * z2;
|
|
||||||
yy = qy * y2; yz = qy * z2; zz = qz * z2;
|
|
||||||
xw = qw * x2; yw = qw * y2; zw = qw * z2;
|
|
||||||
|
|
||||||
result[0*4+0] = 1.0f - (yy + zz);
|
|
||||||
result[1*4+0] = xy + zw;
|
|
||||||
result[2*4+0] = xz - yw;
|
|
||||||
|
|
||||||
result[0*4+1] = xy - zw;
|
|
||||||
result[1*4+1] = 1.0f - (xx + zz);
|
|
||||||
result[2*4+1] = yz + xw;
|
|
||||||
|
|
||||||
result[0*4+2] = xz + yw;
|
|
||||||
result[1*4+2] = yz - xw;
|
|
||||||
result[2*4+2] = 1.0f - (xx + yy);
|
|
||||||
|
|
||||||
result[0*4+3] = x;
|
|
||||||
result[1*4+3] = y;
|
|
||||||
result[2*4+3] = z;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
qboolean Mod_ParseMD5Anim(char *buffer, galiasinfo_t *prototype, void**poseofs, galiasgroup_t *gat)
|
qboolean Mod_ParseMD5Anim(char *buffer, galiasinfo_t *prototype, void**poseofs, galiasgroup_t *gat)
|
||||||
{
|
{
|
||||||
#define MD5ERROR0PARAM(x) { Con_Printf(CON_ERROR x "\n"); return false; }
|
#define MD5ERROR0PARAM(x) { Con_Printf(CON_ERROR x "\n"); return false; }
|
||||||
|
@ -5063,6 +5749,7 @@ galiasinfo_t *Mod_ParseMD5MeshModel(char *buffer)
|
||||||
inf->numbones = numjoints;
|
inf->numbones = numjoints;
|
||||||
inf->groups = 1;
|
inf->groups = 1;
|
||||||
inf->groupofs = (char*)pose - (char*)inf;
|
inf->groupofs = (char*)pose - (char*)inf;
|
||||||
|
inf->baseframeofs = inf->groupofs + pose->poseofs;
|
||||||
|
|
||||||
#ifndef SERVERONLY
|
#ifndef SERVERONLY
|
||||||
skin = Hunk_Alloc(sizeof(*skin));
|
skin = Hunk_Alloc(sizeof(*skin));
|
||||||
|
|
|
@ -34,6 +34,7 @@ typedef struct {
|
||||||
|
|
||||||
int groups;
|
int groups;
|
||||||
int groupofs;
|
int groupofs;
|
||||||
|
int baseframeofs; /*non-heirachical*/
|
||||||
|
|
||||||
int nextsurf;
|
int nextsurf;
|
||||||
|
|
||||||
|
@ -136,8 +137,13 @@ qboolean Mod_LoadQ1Model (model_t *mod, void *buffer);
|
||||||
#endif
|
#endif
|
||||||
#ifdef ZYMOTICMODELS
|
#ifdef ZYMOTICMODELS
|
||||||
qboolean Mod_LoadZymoticModel(model_t *mod, void *buffer);
|
qboolean Mod_LoadZymoticModel(model_t *mod, void *buffer);
|
||||||
|
#endif
|
||||||
|
#ifdef DPMMODELS
|
||||||
qboolean Mod_LoadDarkPlacesModel(model_t *mod, void *buffer);
|
qboolean Mod_LoadDarkPlacesModel(model_t *mod, void *buffer);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef PSKMODELS
|
||||||
|
qboolean Mod_LoadPSKModel(model_t *mod, void *buffer);
|
||||||
|
#endif
|
||||||
#ifdef MD5MODELS
|
#ifdef MD5MODELS
|
||||||
qboolean Mod_LoadMD5MeshModel(model_t *mod, void *buffer);
|
qboolean Mod_LoadMD5MeshModel(model_t *mod, void *buffer);
|
||||||
qboolean Mod_LoadCompositeAnim(model_t *mod, void *buffer);
|
qboolean Mod_LoadCompositeAnim(model_t *mod, void *buffer);
|
||||||
|
|
|
@ -971,6 +971,8 @@ void R_GAlias_GenerateBatches(entity_t *e, batch_t **batches)
|
||||||
for(surfnum=0; inf; ((inf->nextsurf)?(inf = (galiasinfo_t*)((char *)inf + inf->nextsurf)):(inf=NULL)), surfnum++)
|
for(surfnum=0; inf; ((inf->nextsurf)?(inf = (galiasinfo_t*)((char *)inf + inf->nextsurf)):(inf=NULL)), surfnum++)
|
||||||
{
|
{
|
||||||
skin = GL_ChooseSkin(inf, clmodel->name, surfnum, e);
|
skin = GL_ChooseSkin(inf, clmodel->name, surfnum, e);
|
||||||
|
if (!skin)
|
||||||
|
continue;
|
||||||
shader = e->forcedshader?e->forcedshader:skin->shader;
|
shader = e->forcedshader?e->forcedshader:skin->shader;
|
||||||
if (shader)
|
if (shader)
|
||||||
{
|
{
|
||||||
|
|
|
@ -607,12 +607,21 @@ model_t *RMod_LoadModel (model_t *mod, qboolean crash)
|
||||||
if (!Mod_LoadZymoticModel(mod, buf))
|
if (!Mod_LoadZymoticModel(mod, buf))
|
||||||
continue;
|
continue;
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef DPMMODELS
|
||||||
case (('K'<<24)+('R'<<16)+('A'<<8)+'D'):
|
case (('K'<<24)+('R'<<16)+('A'<<8)+'D'):
|
||||||
if (!Mod_LoadDarkPlacesModel(mod, buf))
|
if (!Mod_LoadDarkPlacesModel(mod, buf))
|
||||||
continue;
|
continue;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef PSKMODELS
|
||||||
|
case ('A'<<0)+('C'<<8)+('T'<<16)+('R'<<24):
|
||||||
|
if (!Mod_LoadPSKModel (mod, buf))
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
//Binary Sprites
|
//Binary Sprites
|
||||||
#ifdef SP2MODELS
|
#ifdef SP2MODELS
|
||||||
|
|
Loading…
Reference in a new issue