mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-23 04:11:53 +00:00
de29dce680
fix attempt to fix npfte issues. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@3938 fc73d0e0-1445-4013-8a0c-d673dee63da5
1061 lines
29 KiB
C
1061 lines
29 KiB
C
/*
|
|
Copyright (C) 2011 Id Software, Inc.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
/*
|
|
this file deals with qc builtins to apply custom skeletal blending (skeletal objects extension), as well as the logic required to perform realtime ragdoll, if I ever implement that.
|
|
*/
|
|
|
|
#include "quakedef.h"
|
|
|
|
#if defined(CSQC_DAT) || !defined(CLIENTONLY)
|
|
#define RAGDOLL
|
|
|
|
#include "pr_common.h"
|
|
#include "com_mesh.h"
|
|
|
|
#define MAX_SKEL_OBJECTS 1024
|
|
|
|
#ifdef RAGDOLL
|
|
/*this is the description of the ragdoll, it is how the doll flops around*/
|
|
typedef struct doll_s
|
|
{
|
|
char *name;
|
|
model_t *model;
|
|
struct doll_s *next;
|
|
|
|
int numbodies;
|
|
int numjoints;
|
|
struct
|
|
{
|
|
int bone;
|
|
char *name;
|
|
} body[32];
|
|
struct
|
|
{
|
|
int type;
|
|
int body[2];
|
|
} joint[32];
|
|
} doll_t;
|
|
|
|
enum
|
|
{
|
|
BF_ACTIVE, /*used to avoid traces if doll is stationary*/
|
|
BF_INSOLID
|
|
};
|
|
typedef struct
|
|
{
|
|
int jointo; /*multiple of 12*/
|
|
int flags;
|
|
vec3_t vel;
|
|
} body_t;
|
|
#endif
|
|
|
|
/*this is the skeletal object*/
|
|
typedef struct skelobject_s
|
|
{
|
|
int inuse;
|
|
|
|
model_t *model;
|
|
world_t *world; /*be it ssqc or csqc*/
|
|
enum
|
|
{
|
|
SKOT_RELATIVE,
|
|
SKOT_ABSOLUTE
|
|
} type;
|
|
|
|
unsigned int numbones;
|
|
float *bonematrix;
|
|
|
|
#ifdef RAGDOLL
|
|
struct skelobject_s *animsource;
|
|
unsigned int numbodies;
|
|
body_t *body;
|
|
doll_t *doll;
|
|
#endif
|
|
} skelobject_t;
|
|
|
|
static doll_t *dolllist;
|
|
static skelobject_t skelobjects[MAX_SKEL_OBJECTS];
|
|
static int numskelobjectsused;
|
|
|
|
static void bonemat_fromidentity(float *out)
|
|
{
|
|
out[0] = 1;
|
|
out[1] = 0;
|
|
out[2] = 0;
|
|
out[3] = 0;
|
|
|
|
out[4] = 0;
|
|
out[5] = 1;
|
|
out[6] = 0;
|
|
out[7] = 0;
|
|
|
|
out[8] = 0;
|
|
out[9] = 0;
|
|
out[10] = 1;
|
|
out[11] = 0;
|
|
}
|
|
static void bonemat_fromqcvectors(float *out, const float vx[3], const float vy[3], const float vz[3], const float t[3])
|
|
{
|
|
out[0] = vx[0];
|
|
out[1] = -vy[0];
|
|
out[2] = vz[0];
|
|
out[3] = t[0];
|
|
out[4] = vx[1];
|
|
out[5] = -vy[1];
|
|
out[6] = vz[1];
|
|
out[7] = t[1];
|
|
out[8] = vx[2];
|
|
out[9] = -vy[2];
|
|
out[10] = vz[2];
|
|
out[11] = t[2];
|
|
}
|
|
static void bonemat_fromentity(world_t *w, wedict_t *ed, float *trans)
|
|
{
|
|
vec3_t d[3], a;
|
|
model_t *mod;
|
|
mod = w->Get_CModel(w, ed->v->modelindex);
|
|
if (!mod || mod->type == mod_alias)
|
|
a[0] = -ed->v->angles[0];
|
|
else
|
|
a[0] = ed->v->angles[0];
|
|
a[1] = ed->v->angles[1];
|
|
a[2] = ed->v->angles[2];
|
|
AngleVectors(a, d[0], d[1], d[2]);
|
|
bonemat_fromqcvectors(trans, d[0], d[1], d[2], ed->v->origin);
|
|
}
|
|
static void bonemat_toqcvectors(const float *in, float vx[3], float vy[3], float vz[3], float t[3])
|
|
{
|
|
vx[0] = in[0];
|
|
vx[1] = in[4];
|
|
vx[2] = in[8];
|
|
vy[0] = -in[1];
|
|
vy[1] = -in[5];
|
|
vy[2] = -in[9];
|
|
vz[0] = in[2];
|
|
vz[1] = in[6];
|
|
vz[2] = in[10];
|
|
t [0] = in[3];
|
|
t [1] = in[7];
|
|
t [2] = in[11];
|
|
}
|
|
|
|
static void bonematident_toqcvectors(float vx[3], float vy[3], float vz[3], float t[3])
|
|
{
|
|
vx[0] = 1;
|
|
vx[1] = 0;
|
|
vx[2] = 0;
|
|
vy[0] = -0;
|
|
vy[1] = -1;
|
|
vy[2] = -0;
|
|
vz[0] = 0;
|
|
vz[1] = 0;
|
|
vz[2] = 1;
|
|
t [0] = 0;
|
|
t [1] = 0;
|
|
t [2] = 0;
|
|
}
|
|
|
|
|
|
static qboolean pendingkill; /*states that there is a skel waiting to be killed*/
|
|
#ifdef RAGDOLL
|
|
doll_t *rag_loaddoll(model_t *mod, char *fname)
|
|
{
|
|
doll_t *d;
|
|
void *fptr = NULL;
|
|
char *file;
|
|
int fsize;
|
|
int i, j;
|
|
|
|
for (d = dolllist; d; d = d->next)
|
|
{
|
|
if (d->model == mod)
|
|
if (!strcmp(d->name, fname))
|
|
return d;
|
|
}
|
|
|
|
fsize = FS_LoadFile(fname, &fptr);
|
|
if (!fptr)
|
|
return NULL;
|
|
d = malloc(sizeof(*d));
|
|
d->next = dolllist;
|
|
dolllist = d;
|
|
d->name = strdup(fname);
|
|
d->model = mod;
|
|
d->numbodies = 0;
|
|
d->numjoints = 0;
|
|
file = fptr;
|
|
while(file)
|
|
{
|
|
file = COM_Parse(file);
|
|
if (!strcmp(com_token, "body"))
|
|
{
|
|
file = COM_Parse(file);
|
|
d->body[d->numbodies].name = strdup(com_token);
|
|
file = COM_Parse(file);
|
|
d->body[d->numbodies].bone = Mod_TagNumForName(d->model, com_token);
|
|
d->numbodies++;
|
|
}
|
|
else if (!strcmp(com_token, "joint"))
|
|
{
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
file = COM_Parse(file);
|
|
d->joint[d->numjoints].body[i] = 0;
|
|
for (j = 0; j < d->numbodies; j++)
|
|
{
|
|
if (!strcmp(d->body[j].name, com_token))
|
|
{
|
|
d->joint[d->numjoints].body[i] = j;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
d->numjoints++;
|
|
}
|
|
}
|
|
FS_FreeFile(fptr);
|
|
return d;
|
|
}
|
|
|
|
void skel_integrate(progfuncs_t *prinst, skelobject_t *sko, skelobject_t *skelobjsrc, float ft, float mmat[12])
|
|
{
|
|
trace_t t;
|
|
vec3_t npos, opos, wnpos, wopos;
|
|
vec3_t move;
|
|
float wantmat[12];
|
|
world_t *w = prinst->parms->user;
|
|
body_t *b;
|
|
float gravity = 800;
|
|
int bone, bno;
|
|
int boffs;
|
|
galiasbone_t *boneinfo = Mod_GetBoneInfo(sko->model);
|
|
if (!boneinfo)
|
|
return;
|
|
|
|
for (bone = 0, bno = 0, b = sko->body; bone < sko->numbones; bone++)
|
|
{
|
|
boffs = bone*12;
|
|
/*if this bone is positioned using a physical body...*/
|
|
if (bno < sko->numbodies && b->jointo == boffs)
|
|
{
|
|
if (skelobjsrc)
|
|
{
|
|
/*attempt to move to target*/
|
|
if (boneinfo[bone].parent >= 0)
|
|
{
|
|
Matrix3x4_Multiply(skelobjsrc->bonematrix+boffs, sko->bonematrix+12*boneinfo[bone].parent, wantmat);
|
|
}
|
|
else
|
|
{
|
|
Vector4Copy(skelobjsrc->bonematrix+boffs+0, wantmat+0);
|
|
Vector4Copy(skelobjsrc->bonematrix+boffs+4, wantmat+4);
|
|
Vector4Copy(skelobjsrc->bonematrix+boffs+8, wantmat+8);
|
|
}
|
|
b->vel[0] = (wantmat[3 ] - sko->bonematrix[b->jointo + 3 ])/ft;
|
|
b->vel[1] = (wantmat[7 ] - sko->bonematrix[b->jointo + 7 ])/ft;
|
|
b->vel[2] = (wantmat[11] - sko->bonematrix[b->jointo + 11])/ft;
|
|
}
|
|
else
|
|
{
|
|
/*handle gravity*/
|
|
b->vel[2] = b->vel[2] - gravity * ft / 2;
|
|
}
|
|
|
|
VectorScale(b->vel, ft, move);
|
|
|
|
opos[0] = sko->bonematrix[b->jointo + 3 ];
|
|
opos[1] = sko->bonematrix[b->jointo + 7 ];
|
|
opos[2] = sko->bonematrix[b->jointo + 11];
|
|
npos[0] = opos[0] + move[0];
|
|
npos[1] = opos[1] + move[1];
|
|
npos[2] = opos[2] + move[2];
|
|
|
|
Matrix3x4_RM_Transform3(mmat, opos, wopos);
|
|
Matrix3x4_RM_Transform3(mmat, npos, wnpos);
|
|
|
|
t = World_Move(w, wopos, vec3_origin, vec3_origin, wnpos, MOVE_NOMONSTERS, w->edicts);
|
|
if (t.startsolid)
|
|
t.fraction = 1;
|
|
else if (t.fraction < 1)
|
|
{
|
|
/*clip the velocity*/
|
|
float backoff = -DotProduct (b->vel, t.plane.normal) * 1.9; /*teehee, bouncy corpses*/
|
|
VectorMA(b->vel, backoff, t.plane.normal, b->vel);
|
|
}
|
|
if (skelobjsrc)
|
|
{
|
|
VectorCopy(wantmat+0, sko->bonematrix+b->jointo+0);
|
|
VectorCopy(wantmat+4, sko->bonematrix+b->jointo+4);
|
|
VectorCopy(wantmat+8, sko->bonematrix+b->jointo+8);
|
|
}
|
|
|
|
sko->bonematrix[b->jointo + 3 ] += move[0] * t.fraction;
|
|
sko->bonematrix[b->jointo + 7 ] += move[1] * t.fraction;
|
|
sko->bonematrix[b->jointo + 11] += move[2] * t.fraction;
|
|
|
|
if (!skelobjsrc)
|
|
b->vel[2] = b->vel[2] - gravity * ft / 2;
|
|
|
|
b++;
|
|
bno++;
|
|
}
|
|
else if (skelobjsrc)
|
|
{
|
|
/*directly copy animation skeleton*/
|
|
if (boneinfo[bone].parent >= 0)
|
|
{
|
|
Matrix3x4_Multiply(skelobjsrc->bonematrix+boffs, sko->bonematrix+12*boneinfo[bone].parent, sko->bonematrix+boffs);
|
|
}
|
|
else
|
|
{
|
|
Vector4Copy(skelobjsrc->bonematrix+boffs+0, sko->bonematrix+boffs+0);
|
|
Vector4Copy(skelobjsrc->bonematrix+boffs+4, sko->bonematrix+boffs+4);
|
|
Vector4Copy(skelobjsrc->bonematrix+boffs+8, sko->bonematrix+boffs+8);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*retain the old relation*/
|
|
/*FIXME*/
|
|
}
|
|
}
|
|
|
|
/*debugging*/
|
|
#if 0
|
|
/*draw points*/
|
|
for (bone = 0; p < sko->numbones; bone++)
|
|
{
|
|
opos[0] = sko->bonematrix[bone*12 + 3 ];
|
|
opos[1] = sko->bonematrix[bone*12 + 7 ];
|
|
opos[2] = sko->bonematrix[bone*12 + 11];
|
|
Matrix3x4_RM_Transform3(mmat, opos, wopos);
|
|
P_RunParticleEffectTypeString(wopos, vec3_origin, 1, "ragdolltest");
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
/*destroys all skeletons*/
|
|
void skel_reset(progfuncs_t *prinst)
|
|
{
|
|
while (numskelobjectsused > 0)
|
|
{
|
|
numskelobjectsused--;
|
|
skelobjects[numskelobjectsused].numbones = 0;
|
|
skelobjects[numskelobjectsused].inuse = false;
|
|
}
|
|
}
|
|
|
|
/*deletes any skeletons marked for deletion*/
|
|
void skel_dodelete(progfuncs_t *prinst)
|
|
{
|
|
int skelidx;
|
|
if (!pendingkill)
|
|
return;
|
|
|
|
pendingkill = false;
|
|
for (skelidx = 0; skelidx < numskelobjectsused; skelidx++)
|
|
{
|
|
if (skelobjects[skelidx].inuse == 2)
|
|
skelobjects[skelidx].inuse = 0;
|
|
}
|
|
|
|
while (numskelobjectsused && !skelobjects[numskelobjectsused-1].inuse)
|
|
numskelobjectsused--;
|
|
}
|
|
|
|
skelobject_t *skel_get(progfuncs_t *prinst, int skelidx, int bonecount)
|
|
{
|
|
if (skelidx == 0)
|
|
{
|
|
//allocation
|
|
if (!bonecount)
|
|
return NULL;
|
|
|
|
for (skelidx = 0; skelidx < numskelobjectsused; skelidx++)
|
|
{
|
|
if (!skelobjects[skelidx].inuse && skelobjects[skelidx].numbones == bonecount)
|
|
return &skelobjects[skelidx];
|
|
}
|
|
|
|
for (skelidx = 0; skelidx <= numskelobjectsused; skelidx++)
|
|
{
|
|
if (!skelobjects[skelidx].inuse && !skelobjects[skelidx].numbones)
|
|
{
|
|
skelobjects[skelidx].numbones = bonecount;
|
|
/*so bone matrix list can be mmapped some day*/
|
|
skelobjects[skelidx].bonematrix = (float*)PR_AddString(prinst, "", sizeof(float)*12*bonecount);
|
|
skelobjects[skelidx].world = prinst->parms->user;
|
|
if (skelidx <= numskelobjectsused)
|
|
{
|
|
numskelobjectsused = skelidx + 1;
|
|
skelobjects[skelidx].model = NULL;
|
|
skelobjects[skelidx].inuse = 1;
|
|
}
|
|
return &skelobjects[skelidx];
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
skelidx--;
|
|
if ((unsigned int)skelidx >= numskelobjectsused)
|
|
return NULL;
|
|
if (skelobjects[skelidx].inuse != 1)
|
|
return NULL;
|
|
if (bonecount && skelobjects[skelidx].numbones != bonecount)
|
|
return NULL;
|
|
return &skelobjects[skelidx];
|
|
}
|
|
}
|
|
|
|
void skel_lookup(progfuncs_t *prinst, int skelidx, framestate_t *out)
|
|
{
|
|
skelobject_t *sko = skel_get(prinst, skelidx, 0);
|
|
if (sko && sko->inuse)
|
|
{
|
|
out->boneabs = sko->type;
|
|
out->bonecount = sko->numbones;
|
|
out->bonestate = sko->bonematrix;
|
|
}
|
|
}
|
|
|
|
void QCBUILTIN PF_skel_mmap(progfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
int skelidx = G_FLOAT(OFS_PARM0);
|
|
skelobject_t *sko = skel_get(prinst, skelidx, 0);
|
|
if (!sko || sko->world != prinst->parms->user)
|
|
G_INT(OFS_RETURN) = 0;
|
|
else
|
|
G_INT(OFS_RETURN) = PR_SetString(prinst, (void*)sko->bonematrix);
|
|
}
|
|
|
|
void QCBUILTIN PF_skel_ragedit(progfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
#ifdef RAGDOLL
|
|
int skelidx = G_FLOAT(OFS_PARM0);
|
|
char *skelname = PR_GetStringOfs(prinst, OFS_PARM1);
|
|
int parentskel = G_FLOAT(OFS_PARM2);
|
|
float *entorg = G_VECTOR(OFS_PARM3);
|
|
float *forward = G_VECTOR(OFS_PARM4);
|
|
float *right = G_VECTOR(OFS_PARM5);
|
|
float *up = G_VECTOR(OFS_PARM6);
|
|
skelobject_t *sko, *psko;
|
|
doll_t *doll;
|
|
int i;
|
|
float emat[12];
|
|
|
|
bonemat_fromqcvectors(emat, forward, right, up, entorg);
|
|
|
|
G_FLOAT(OFS_RETURN) = 0;
|
|
|
|
sko = skel_get(prinst, skelidx, 0);
|
|
if (!sko)
|
|
return;
|
|
|
|
if (*skelname)
|
|
{
|
|
doll = rag_loaddoll(sko->model, skelname);
|
|
if (!doll)
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
/*no doll name makes it revert to a normal skeleton*/
|
|
sko->doll = NULL;
|
|
G_FLOAT(OFS_RETURN) = 1;
|
|
return;
|
|
}
|
|
|
|
if (sko->doll != doll)
|
|
{
|
|
sko->doll = doll;
|
|
free(sko->body);
|
|
sko->numbodies = doll->numbodies;
|
|
sko->body = malloc(sko->numbodies * sizeof(*sko->body));
|
|
memset(sko->body, 0, sko->numbodies * sizeof(*sko->body));
|
|
for (i = 0; i < sko->numbodies; i++)
|
|
sko->body[i].jointo = doll->body[i].bone * 12;
|
|
}
|
|
|
|
psko = skel_get(prinst, parentskel, 0);
|
|
skel_integrate(prinst, sko, psko, host_frametime, emat);
|
|
|
|
G_FLOAT(OFS_RETURN) = 1;
|
|
#endif
|
|
}
|
|
|
|
//float(float modelindex) skel_create (FTE_CSQC_SKELETONOBJECTS)
|
|
void QCBUILTIN PF_skel_create (progfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
world_t *w = prinst->parms->user;
|
|
|
|
int numbones;
|
|
skelobject_t *skelobj;
|
|
model_t *model;
|
|
int midx;
|
|
int type;
|
|
|
|
midx = G_FLOAT(OFS_PARM0);
|
|
type = (*prinst->callargc > 1)?G_FLOAT(OFS_PARM1):SKOT_RELATIVE;
|
|
|
|
//default to failure
|
|
G_FLOAT(OFS_RETURN) = 0;
|
|
|
|
model = w->Get_CModel(w, midx);
|
|
if (!model)
|
|
return; //no model set, can't get a skeleton
|
|
|
|
numbones = Mod_GetNumBones(model, type != SKOT_RELATIVE);
|
|
if (!numbones)
|
|
{
|
|
// isabs = true;
|
|
// numbones = Mod_GetNumBones(model, isabs);
|
|
// if (!numbones)
|
|
return; //this isn't a skeletal model.
|
|
}
|
|
|
|
skelobj = skel_get(prinst, 0, numbones);
|
|
if (!skelobj)
|
|
return; //couldn't get one, ran out of memory or something?
|
|
|
|
skelobj->model = model;
|
|
skelobj->type = type;
|
|
|
|
G_FLOAT(OFS_RETURN) = (skelobj - skelobjects) + 1;
|
|
}
|
|
|
|
//float(float skel, entity ent, float modelindex, float retainfrac, float firstbone, float lastbone) skel_build (FTE_CSQC_SKELETONOBJECTS)
|
|
void QCBUILTIN PF_skel_build(progfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
world_t *w = prinst->parms->user;
|
|
int skelidx = G_FLOAT(OFS_PARM0);
|
|
wedict_t *ent = (wedict_t*)G_EDICT(prinst, OFS_PARM1);
|
|
int midx = G_FLOAT(OFS_PARM2);
|
|
float retainfrac = G_FLOAT(OFS_PARM3);
|
|
int firstbone = G_FLOAT(OFS_PARM4)-1;
|
|
int lastbone = G_FLOAT(OFS_PARM5)-1;
|
|
float addition = (*prinst->callargc>6)?G_FLOAT(OFS_PARM6):1-retainfrac;
|
|
|
|
int i, j;
|
|
int numbones;
|
|
framestate_t fstate;
|
|
skelobject_t *skelobj;
|
|
model_t *model;
|
|
|
|
//default to failure
|
|
G_FLOAT(OFS_RETURN) = 0;
|
|
|
|
model = w->Get_CModel(w, midx);
|
|
if (!model)
|
|
return; //invalid model, can't get a skeleton
|
|
|
|
w->Get_FrameState(w, ent, &fstate);
|
|
|
|
//heh... don't copy.
|
|
fstate.bonecount = 0;
|
|
fstate.bonestate = NULL;
|
|
|
|
numbones = Mod_GetNumBones(model, false);
|
|
if (!numbones)
|
|
{
|
|
return; //this isn't a skeletal model.
|
|
}
|
|
|
|
skelobj = skel_get(prinst, skelidx, 0);
|
|
if (!skelobj)
|
|
return; //couldn't get one, ran out of memory or something?
|
|
|
|
if (lastbone < 0)
|
|
lastbone = numbones;
|
|
if (lastbone > numbones)
|
|
lastbone = numbones;
|
|
if (firstbone < 0)
|
|
firstbone = 0;
|
|
|
|
if (retainfrac == 0)
|
|
{
|
|
/*replace everything*/
|
|
if (addition == 1)
|
|
Mod_GetBoneRelations(model, firstbone, lastbone, &fstate, skelobj->bonematrix);
|
|
else
|
|
{
|
|
//scale new
|
|
float relationsbuf[MAX_BONES*12];
|
|
Mod_GetBoneRelations(model, firstbone, lastbone, &fstate, relationsbuf);
|
|
for (i = firstbone; i < lastbone; i++)
|
|
{
|
|
for (j = 0; j < 12; j++)
|
|
skelobj->bonematrix[i*12+j] = addition*relationsbuf[i*12+j];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (retainfrac != 1)
|
|
{
|
|
//rescale the existing bones
|
|
for (i = firstbone; i < lastbone; i++)
|
|
{
|
|
for (j = 0; j < 12; j++)
|
|
skelobj->bonematrix[i*12+j] *= retainfrac;
|
|
}
|
|
}
|
|
if (addition == 1)
|
|
{
|
|
//just add
|
|
float relationsbuf[MAX_BONES*12];
|
|
Mod_GetBoneRelations(model, firstbone, lastbone, &fstate, relationsbuf);
|
|
for (i = firstbone; i < lastbone; i++)
|
|
{
|
|
for (j = 0; j < 12; j++)
|
|
skelobj->bonematrix[i*12+j] += relationsbuf[i*12+j];
|
|
}
|
|
}
|
|
else if (addition)
|
|
{
|
|
//add+scale
|
|
float relationsbuf[MAX_BONES*12];
|
|
Mod_GetBoneRelations(model, firstbone, lastbone, &fstate, relationsbuf);
|
|
for (i = firstbone; i < lastbone; i++)
|
|
{
|
|
for (j = 0; j < 12; j++)
|
|
skelobj->bonematrix[i*12+j] += addition*relationsbuf[i*12+j];
|
|
}
|
|
}
|
|
}
|
|
|
|
G_FLOAT(OFS_RETURN) = (skelobj - skelobjects) + 1;
|
|
}
|
|
|
|
//float(float skel) skel_get_numbones (FTE_CSQC_SKELETONOBJECTS)
|
|
void QCBUILTIN PF_skel_get_numbones (progfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
int skelidx = G_FLOAT(OFS_PARM0);
|
|
skelobject_t *skelobj;
|
|
|
|
skelobj = skel_get(prinst, skelidx, 0);
|
|
|
|
if (!skelobj)
|
|
G_FLOAT(OFS_RETURN) = 0;
|
|
else
|
|
G_FLOAT(OFS_RETURN) = skelobj->numbones;
|
|
}
|
|
|
|
//string(float skel, float bonenum) skel_get_bonename (FTE_CSQC_SKELETONOBJECTS) (returns tempstring)
|
|
void QCBUILTIN PF_skel_get_bonename (progfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
int skelidx = G_FLOAT(OFS_PARM0);
|
|
int boneidx = G_FLOAT(OFS_PARM1);
|
|
skelobject_t *skelobj;
|
|
|
|
skelobj = skel_get(prinst, skelidx, 0);
|
|
|
|
if (!skelobj)
|
|
G_INT(OFS_RETURN) = 0;
|
|
else
|
|
{
|
|
RETURN_TSTRING(Mod_GetBoneName(skelobj->model, boneidx));
|
|
}
|
|
}
|
|
|
|
//float(float skel, float bonenum) skel_get_boneparent (FTE_CSQC_SKELETONOBJECTS)
|
|
void QCBUILTIN PF_skel_get_boneparent (progfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
int skelidx = G_FLOAT(OFS_PARM0);
|
|
int boneidx = G_FLOAT(OFS_PARM1);
|
|
skelobject_t *skelobj;
|
|
|
|
skelobj = skel_get(prinst, skelidx, 0);
|
|
|
|
if (!skelobj)
|
|
G_FLOAT(OFS_RETURN) = 0;
|
|
else
|
|
G_FLOAT(OFS_RETURN) = Mod_GetBoneParent(skelobj->model, boneidx);
|
|
}
|
|
|
|
//float(float skel, string tagname) skel_find_bone (FTE_CSQC_SKELETONOBJECTS)
|
|
void QCBUILTIN PF_skel_find_bone (progfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
int skelidx = G_FLOAT(OFS_PARM0);
|
|
char *bname = PR_GetStringOfs(prinst, OFS_PARM1);
|
|
skelobject_t *skelobj;
|
|
|
|
skelobj = skel_get(prinst, skelidx, 0);
|
|
if (!skelobj)
|
|
G_FLOAT(OFS_RETURN) = 0;
|
|
else
|
|
G_FLOAT(OFS_RETURN) = Mod_TagNumForName(skelobj->model, bname);
|
|
}
|
|
|
|
//vector(float skel, float bonenum) skel_get_bonerel (FTE_CSQC_SKELETONOBJECTS) (sets v_forward etc)
|
|
void QCBUILTIN PF_skel_get_bonerel (progfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
world_t *w = prinst->parms->user;
|
|
int skelidx = G_FLOAT(OFS_PARM0);
|
|
int boneidx = G_FLOAT(OFS_PARM1)-1;
|
|
skelobject_t *skelobj = skel_get(prinst, skelidx, 0);
|
|
if (!skelobj || (unsigned int)boneidx >= skelobj->numbones)
|
|
bonematident_toqcvectors(w->g.v_forward, w->g.v_right, w->g.v_up, G_VECTOR(OFS_RETURN));
|
|
else if (skelobj->type!=SKOT_RELATIVE)
|
|
{
|
|
float tmp[12];
|
|
float invparent[12];
|
|
int parent;
|
|
/*invert the parent, multiply that against the child, we now know the transform required to go from parent to child. woo.*/
|
|
parent = Mod_GetBoneParent(skelobj->model, boneidx+1)-1;
|
|
Matrix3x4_Invert(skelobj->bonematrix+12*parent, invparent);
|
|
Matrix3x4_Multiply(invparent, skelobj->bonematrix+12*boneidx, tmp);
|
|
bonemat_toqcvectors(tmp, w->g.v_forward, w->g.v_right, w->g.v_up, G_VECTOR(OFS_RETURN));
|
|
}
|
|
else
|
|
bonemat_toqcvectors(skelobj->bonematrix+12*boneidx, w->g.v_forward, w->g.v_right, w->g.v_up, G_VECTOR(OFS_RETURN));
|
|
}
|
|
|
|
//vector(float skel, float bonenum) skel_get_boneabs (FTE_CSQC_SKELETONOBJECTS) (sets v_forward etc)
|
|
void QCBUILTIN PF_skel_get_boneabs (progfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
world_t *w = prinst->parms->user;
|
|
int skelidx = G_FLOAT(OFS_PARM0);
|
|
int boneidx = G_FLOAT(OFS_PARM1)-1;
|
|
float workingm[12], tempmatrix[3][4];
|
|
int i;
|
|
skelobject_t *skelobj = skel_get(prinst, skelidx, 0);
|
|
|
|
if (!skelobj || (unsigned int)boneidx >= skelobj->numbones)
|
|
bonematident_toqcvectors(w->g.v_forward, w->g.v_right, w->g.v_up, G_VECTOR(OFS_RETURN));
|
|
else if (skelobj->type != SKOT_RELATIVE)
|
|
{
|
|
//can just copy it out
|
|
bonemat_toqcvectors(skelobj->bonematrix + boneidx*12, w->g.v_forward, w->g.v_right, w->g.v_up, G_VECTOR(OFS_RETURN));
|
|
}
|
|
else
|
|
{
|
|
//we need to work out the abs position
|
|
|
|
//testme
|
|
|
|
//set up an identity matrix
|
|
for (i = 0;i < 12;i++)
|
|
workingm[i] = 0;
|
|
workingm[0] = 1;
|
|
workingm[5] = 1;
|
|
workingm[10] = 1;
|
|
|
|
while(boneidx >= 0)
|
|
{
|
|
//copy out the previous working matrix, so we don't stomp on it
|
|
memcpy(tempmatrix, workingm, sizeof(tempmatrix));
|
|
R_ConcatTransforms((void*)(skelobj->bonematrix + boneidx*12), (void*)tempmatrix, (void*)workingm);
|
|
|
|
boneidx = Mod_GetBoneParent(skelobj->model, boneidx+1)-1;
|
|
}
|
|
bonemat_toqcvectors(workingm, w->g.v_forward, w->g.v_right, w->g.v_up, G_VECTOR(OFS_RETURN));
|
|
}
|
|
}
|
|
|
|
//void(entity ent, float bonenum, vector org, optional fwd, right, up) skel_set_bone_world (FTE_CSQC_SKELETONOBJECTS2) (reads v_forward etc)
|
|
void QCBUILTIN PF_skel_set_bone_world (progfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
world_t *w = prinst->parms->user;
|
|
wedict_t *ent = G_WEDICT(prinst, OFS_PARM0);
|
|
unsigned int boneidx = G_FLOAT(OFS_PARM1)-1;
|
|
float *matrix[3];
|
|
skelobject_t *skelobj;
|
|
float *bone;
|
|
float childworld[12], parentinv[12];
|
|
|
|
/*sort out the parameters*/
|
|
if (*prinst->callargc == 4)
|
|
{
|
|
vec3_t d[3], a;
|
|
a[0] = G_VECTOR(OFS_PARM3)[0] * -1; /*mod_alias bug*/
|
|
a[1] = G_VECTOR(OFS_PARM3)[1];
|
|
a[2] = G_VECTOR(OFS_PARM3)[2];
|
|
AngleVectors(a, d[0], d[1], d[2]);
|
|
bonemat_fromqcvectors(childworld, d[0], d[1], d[2], G_VECTOR(OFS_PARM2));
|
|
}
|
|
else
|
|
{
|
|
if (*prinst->callargc > 5)
|
|
{
|
|
matrix[0] = G_VECTOR(OFS_PARM3);
|
|
matrix[1] = G_VECTOR(OFS_PARM4);
|
|
matrix[2] = G_VECTOR(OFS_PARM5);
|
|
}
|
|
else
|
|
{
|
|
matrix[0] = w->g.v_forward;
|
|
matrix[1] = w->g.v_right;
|
|
matrix[2] = w->g.v_up;
|
|
}
|
|
bonemat_fromqcvectors(childworld, matrix[0], matrix[1], matrix[2], G_VECTOR(OFS_PARM2));
|
|
}
|
|
|
|
/*make sure the skeletal object is correct*/
|
|
skelobj = skel_get(prinst, ent->xv->skeletonindex, 0);
|
|
if (!skelobj || boneidx >= skelobj->numbones)
|
|
return;
|
|
|
|
/*get the inverse of the parent matrix*/
|
|
{
|
|
float parentabs[12];
|
|
float parentw[12];
|
|
float parentent[12];
|
|
framestate_t fstate;
|
|
w->Get_FrameState(w, ent, &fstate);
|
|
if (skelobj->type == SKOT_ABSOLUTE || !Mod_GetTag(skelobj->model, Mod_GetBoneParent(skelobj->model, boneidx+1), &fstate, parentabs))
|
|
{
|
|
bonemat_fromentity(w, ent, parentw);
|
|
}
|
|
else
|
|
{
|
|
bonemat_fromentity(w, ent, parentent);
|
|
Matrix3x4_Multiply(parentabs, parentent, parentw);
|
|
}
|
|
Matrix3x4_Invert(parentw, parentinv);
|
|
}
|
|
|
|
/*calc the result*/
|
|
bone = skelobj->bonematrix+12*boneidx;
|
|
Matrix3x4_Multiply(childworld, parentinv, bone);
|
|
}
|
|
|
|
//void(float skel, float bonenum, vector org) skel_set_bone (FTE_CSQC_SKELETONOBJECTS) (reads v_forward etc)
|
|
void QCBUILTIN PF_skel_set_bone (progfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
world_t *w = prinst->parms->user;
|
|
int skelidx = G_FLOAT(OFS_PARM0);
|
|
unsigned int boneidx = G_FLOAT(OFS_PARM1)-1;
|
|
float *matrix[3];
|
|
skelobject_t *skelobj;
|
|
float *bone;
|
|
|
|
if (*prinst->callargc > 5)
|
|
{
|
|
matrix[0] = G_VECTOR(OFS_PARM3);
|
|
matrix[1] = G_VECTOR(OFS_PARM4);
|
|
matrix[2] = G_VECTOR(OFS_PARM5);
|
|
}
|
|
else
|
|
{
|
|
matrix[0] = w->g.v_forward;
|
|
matrix[1] = w->g.v_right;
|
|
matrix[2] = w->g.v_up;
|
|
}
|
|
|
|
skelobj = skel_get(prinst, skelidx, 0);
|
|
if (!skelobj || boneidx >= skelobj->numbones)
|
|
return;
|
|
|
|
bone = skelobj->bonematrix+12*boneidx;
|
|
bonemat_fromqcvectors(bone, matrix[0], matrix[1], matrix[2], G_VECTOR(OFS_PARM2));
|
|
}
|
|
|
|
//void(float skel, float bonenum, vector org [, vector fwd, vector right, vector up]) skel_mul_bone (FTE_CSQC_SKELETONOBJECTS) (reads v_forward etc)
|
|
void QCBUILTIN PF_skel_mul_bone (progfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
world_t *w = prinst->parms->user;
|
|
int skelidx = G_FLOAT(OFS_PARM0);
|
|
int boneidx = G_FLOAT(OFS_PARM1)-1;
|
|
float temp[3][4];
|
|
float mult[3][4];
|
|
skelobject_t *skelobj;
|
|
if (*prinst->callargc > 5)
|
|
bonemat_fromqcvectors((float*)mult, G_VECTOR(OFS_PARM3), G_VECTOR(OFS_PARM4), G_VECTOR(OFS_PARM5), G_VECTOR(OFS_PARM2));
|
|
else
|
|
bonemat_fromqcvectors((float*)mult, w->g.v_forward, w->g.v_right, w->g.v_up, G_VECTOR(OFS_PARM2));
|
|
|
|
skelobj = skel_get(prinst, skelidx, 0);
|
|
if (!skelobj || boneidx >= skelobj->numbones)
|
|
return;
|
|
//testme
|
|
Vector4Copy(skelobj->bonematrix+12*boneidx+0, temp[0]);
|
|
Vector4Copy(skelobj->bonematrix+12*boneidx+4, temp[1]);
|
|
Vector4Copy(skelobj->bonematrix+12*boneidx+8, temp[2]);
|
|
R_ConcatTransforms(mult, temp, (float(*)[4])(skelobj->bonematrix+12*boneidx));
|
|
}
|
|
|
|
//void(float skel, float startbone, float endbone, vector org) skel_mul_bone (FTE_CSQC_SKELETONOBJECTS) (reads v_forward etc)
|
|
void QCBUILTIN PF_skel_mul_bones (progfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
world_t *w = prinst->parms->user;
|
|
int skelidx = G_FLOAT(OFS_PARM0);
|
|
unsigned int startbone = G_FLOAT(OFS_PARM1)-1;
|
|
unsigned int endbone = G_FLOAT(OFS_PARM2)-1;
|
|
float temp[3][4];
|
|
float mult[3][4];
|
|
skelobject_t *skelobj;
|
|
if (*prinst->callargc > 6)
|
|
bonemat_fromqcvectors((float*)mult, G_VECTOR(OFS_PARM4), G_VECTOR(OFS_PARM5), G_VECTOR(OFS_PARM6), G_VECTOR(OFS_PARM3));
|
|
else
|
|
bonemat_fromqcvectors((float*)mult, w->g.v_forward, w->g.v_right, w->g.v_up, G_VECTOR(OFS_PARM3));
|
|
|
|
skelobj = skel_get(prinst, skelidx, 0);
|
|
if (!skelobj)
|
|
return;
|
|
|
|
if (startbone == -1)
|
|
startbone = 0;
|
|
if (endbone == -1)
|
|
endbone = skelobj->numbones;
|
|
else if (endbone > skelobj->numbones)
|
|
endbone = skelobj->numbones;
|
|
|
|
while(startbone < endbone)
|
|
{
|
|
Vector4Copy(skelobj->bonematrix+12*startbone+0, temp[0]);
|
|
Vector4Copy(skelobj->bonematrix+12*startbone+4, temp[1]);
|
|
Vector4Copy(skelobj->bonematrix+12*startbone+8, temp[2]);
|
|
R_ConcatTransforms(mult, temp, (float(*)[4])(skelobj->bonematrix+12*startbone));
|
|
|
|
startbone++;
|
|
}
|
|
}
|
|
|
|
//void(float skeldst, float skelsrc, float startbone, float entbone) skel_copybones (FTE_CSQC_SKELETONOBJECTS)
|
|
void QCBUILTIN PF_skel_copybones (progfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
int skeldst = G_FLOAT(OFS_PARM0);
|
|
int skelsrc = G_FLOAT(OFS_PARM1);
|
|
int startbone = G_FLOAT(OFS_PARM2)-1;
|
|
int endbone = G_FLOAT(OFS_PARM3)-1;
|
|
|
|
skelobject_t *skelobjdst;
|
|
skelobject_t *skelobjsrc;
|
|
|
|
skelobjdst = skel_get(prinst, skeldst, 0);
|
|
skelobjsrc = skel_get(prinst, skelsrc, 0);
|
|
if (!skelobjdst || !skelobjsrc)
|
|
return;
|
|
if (startbone == -1)
|
|
startbone = 0;
|
|
if (endbone == -1)
|
|
endbone = skelobjdst->numbones;
|
|
if (endbone > skelobjdst->numbones)
|
|
endbone = skelobjdst->numbones;
|
|
if (endbone > skelobjsrc->numbones)
|
|
endbone = skelobjsrc->numbones;
|
|
|
|
if (skelobjsrc->type == skelobjdst->type)
|
|
{
|
|
while(startbone < endbone)
|
|
{
|
|
Vector4Copy(skelobjsrc->bonematrix+12*startbone+0, skelobjdst->bonematrix+12*startbone+0);
|
|
Vector4Copy(skelobjsrc->bonematrix+12*startbone+4, skelobjdst->bonematrix+12*startbone+4);
|
|
Vector4Copy(skelobjsrc->bonematrix+12*startbone+8, skelobjdst->bonematrix+12*startbone+8);
|
|
|
|
startbone++;
|
|
}
|
|
}
|
|
else if (skelobjsrc->type == SKOT_RELATIVE && skelobjdst->type == SKOT_ABSOLUTE)
|
|
{
|
|
/*copy from relative to absolute*/
|
|
|
|
galiasbone_t *boneinfo = Mod_GetBoneInfo(skelobjsrc->model);
|
|
if (!boneinfo)
|
|
return;
|
|
while(startbone < endbone)
|
|
{
|
|
if (boneinfo[startbone].parent >= 0)
|
|
{
|
|
Matrix3x4_Multiply(skelobjsrc->bonematrix+12*startbone, skelobjdst->bonematrix+12*boneinfo[startbone].parent, skelobjdst->bonematrix+12*startbone);
|
|
}
|
|
else
|
|
{
|
|
Vector4Copy(skelobjsrc->bonematrix+12*startbone+0, skelobjdst->bonematrix+12*startbone+0);
|
|
Vector4Copy(skelobjsrc->bonematrix+12*startbone+4, skelobjdst->bonematrix+12*startbone+4);
|
|
Vector4Copy(skelobjsrc->bonematrix+12*startbone+8, skelobjdst->bonematrix+12*startbone+8);
|
|
}
|
|
|
|
startbone++;
|
|
}
|
|
}
|
|
}
|
|
|
|
//void(float skel) skel_delete (FTE_CSQC_SKELETONOBJECTS)
|
|
void QCBUILTIN PF_skel_delete (progfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
int skelidx = G_FLOAT(OFS_PARM0);
|
|
skelobject_t *skelobj;
|
|
|
|
skelobj = skel_get(prinst, skelidx, 0);
|
|
if (skelobj)
|
|
{
|
|
skelobj->inuse = 2; //2 means don't reuse yet.
|
|
skelobj->model = NULL;
|
|
pendingkill = true;
|
|
}
|
|
}
|
|
|
|
//vector(entity ent, float tag) gettaginfo (DP_MD3_TAGSINFO)
|
|
void QCBUILTIN PF_gettaginfo (progfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
world_t *w = prinst->parms->user;
|
|
wedict_t *ent = G_WEDICT(prinst, OFS_PARM0);
|
|
int tagnum = G_FLOAT(OFS_PARM1);
|
|
|
|
int modelindex = ent->v->modelindex;
|
|
|
|
model_t *mod = w->Get_CModel(w, modelindex);
|
|
|
|
float transent[12];
|
|
float transforms[12];
|
|
float result[12];
|
|
|
|
framestate_t fstate;
|
|
|
|
w->Get_FrameState(w, ent, &fstate);
|
|
|
|
if (!Mod_GetTag(mod, tagnum, &fstate, transforms))
|
|
{
|
|
bonemat_fromidentity(transforms);
|
|
}
|
|
|
|
if (ent->xv->tag_entity)
|
|
{
|
|
#ifdef warningmsg
|
|
#pragma warningmsg("PF_gettaginfo: This function doesn't honour attachments")
|
|
#endif
|
|
Con_Printf("bug: PF_gettaginfo doesn't support attachments\n");
|
|
}
|
|
|
|
bonemat_fromentity(w, ent, transent);
|
|
R_ConcatTransforms((void*)transent, (void*)transforms, (void*)result);
|
|
|
|
bonemat_toqcvectors(result, w->g.v_forward, w->g.v_right, w->g.v_up, G_VECTOR(OFS_RETURN));
|
|
}
|
|
|
|
//vector(entity ent, string tagname) gettagindex (DP_MD3_TAGSINFO)
|
|
void QCBUILTIN PF_gettagindex (progfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
world_t *w = prinst->parms->user;
|
|
wedict_t *ent = G_WEDICT(prinst, OFS_PARM0);
|
|
char *tagname = PR_GetStringOfs(prinst, OFS_PARM1);
|
|
model_t *mod = *tagname?w->Get_CModel(w, ent->v->modelindex):NULL;
|
|
if (mod)
|
|
G_FLOAT(OFS_RETURN) = Mod_TagNumForName(mod, tagname);
|
|
else
|
|
G_FLOAT(OFS_RETURN) = 0;
|
|
}
|
|
#endif
|
|
|