672 lines
18 KiB
C
672 lines
18 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"
|
||
|
#include "pr_common.h"
|
||
|
|
||
|
#define MAX_SKEL_OBJECTS 1024
|
||
|
|
||
|
/*this is the description of the ragdoll, it is how the doll flops around*/
|
||
|
typedef struct doll_s
|
||
|
{
|
||
|
char *name;
|
||
|
struct doll_s *next;
|
||
|
|
||
|
int numbodies;
|
||
|
struct
|
||
|
{
|
||
|
int joint;
|
||
|
char *name;
|
||
|
} body[32];
|
||
|
// struct
|
||
|
// {
|
||
|
|
||
|
// };
|
||
|
} 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;
|
||
|
|
||
|
/*this is the skeletal object*/
|
||
|
typedef struct {
|
||
|
int inuse;
|
||
|
|
||
|
model_t *model;
|
||
|
enum
|
||
|
{
|
||
|
SKOT_HBLEND,
|
||
|
SKOT_ABLEND,
|
||
|
SKOT_ARAG
|
||
|
} type;
|
||
|
|
||
|
unsigned int numbones;
|
||
|
float *bonematrix;
|
||
|
/*
|
||
|
unsigned int numbodies;
|
||
|
body_t *body;
|
||
|
doll_t *doll;
|
||
|
*/
|
||
|
} skelobject_t;
|
||
|
|
||
|
static doll_t *dolllist;
|
||
|
static skelobject_t skelobjects[MAX_SKEL_OBJECTS];
|
||
|
static int numskelobjectsused;
|
||
|
|
||
|
static qboolean pendingkill; /*states that there is a skel waiting to be killed*/
|
||
|
#if 0
|
||
|
doll_t *rag_loaddoll(char *fname)
|
||
|
{
|
||
|
doll_t *d;
|
||
|
void *fptr = NULL;
|
||
|
int fsize;
|
||
|
|
||
|
for (d = dolllist; d; d = d->next)
|
||
|
{
|
||
|
if (!strcmp(d->name, fname))
|
||
|
return d;
|
||
|
}
|
||
|
|
||
|
fsize = FS_LoadFile(fname, &fptr);
|
||
|
if (!fptr)
|
||
|
return NULL;
|
||
|
FS_FreeFile(fptr);
|
||
|
}
|
||
|
|
||
|
void skel_integrate(progfuncs_t *prinst, skelobject_t *sko, float ft)
|
||
|
{
|
||
|
unsigned int p;
|
||
|
trace_t t;
|
||
|
vec3_t npos, opos;
|
||
|
world_t *w = prinst->parms->user;
|
||
|
body_t *b;
|
||
|
float gravity = 800;
|
||
|
|
||
|
for (p = 0, b = sko->body; p < sko->numbodies; p++, b++)
|
||
|
{
|
||
|
/*handle gravity*/
|
||
|
b->vel[2] = b->vel[2] - gravity * ft / 2;
|
||
|
|
||
|
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] + b->vel[0]*ft;
|
||
|
npos[1] = opos[1] + b->vel[1]*ft;
|
||
|
npos[2] = opos[2] + b->vel[2]*ft;
|
||
|
t = World_Move(w, opos, vec3_origin, vec3_origin, npos, MOVE_NOMONSTERS, w->edicts);
|
||
|
sko->bonematrix[b->jointo + 3 ] = t.endpos[0];
|
||
|
sko->bonematrix[b->jointo + 7 ] = t.endpos[1];
|
||
|
sko->bonematrix[b->jointo + 11] = t.endpos[2];
|
||
|
|
||
|
/*handle gravity again to compensate for framerate*/
|
||
|
b->vel[2] = b->vel[2] - gravity * ft / 2;
|
||
|
}
|
||
|
|
||
|
/*draw points*/
|
||
|
for (p = 0, b = sko->body; p < sko->numbodies; p++, b++)
|
||
|
{
|
||
|
opos[0] = sko->bonematrix[b->jointo + 3 ];
|
||
|
opos[1] = sko->bonematrix[b->jointo + 7 ];
|
||
|
opos[2] = sko->bonematrix[b->jointo + 11];
|
||
|
P_RunParticleEffectTypeString(opos, b->vel, 1, "ragdolltest");
|
||
|
}
|
||
|
}
|
||
|
#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);
|
||
|
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->bonecount = sko->numbones;
|
||
|
out->bonestate = sko->bonematrix;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//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;
|
||
|
char *afname;
|
||
|
|
||
|
midx = G_FLOAT(OFS_PARM0);
|
||
|
|
||
|
if (*prinst->callargc > 1)
|
||
|
afname = PR_GetStringOfs(prinst, OFS_PARM1);
|
||
|
else
|
||
|
afname = "";
|
||
|
|
||
|
//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
|
||
|
|
||
|
type = SKOT_HBLEND;
|
||
|
numbones = Mod_GetNumBones(model, type != SKOT_HBLEND);
|
||
|
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 = 1?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);
|
||
|
}
|
||
|
|
||
|
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_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;
|
||
|
}
|
||
|
|
||
|
//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_HBLEND)
|
||
|
{
|
||
|
//FIXME
|
||
|
bonematident_toqcvectors(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_HBLEND)
|
||
|
{
|
||
|
//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(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(skelobj->bonematrix+12*boneidx, 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;
|
||
|
//testme
|
||
|
while(startbone < endbone && startbone < skelobj->numbones)
|
||
|
{
|
||
|
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));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//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 (skelobjsrc->type != skelobjdst->type)
|
||
|
return;
|
||
|
|
||
|
if (startbone == -1)
|
||
|
startbone = 0;
|
||
|
//testme
|
||
|
while(startbone < endbone && startbone < skelobjdst->numbones && startbone < skelobjsrc->numbones)
|
||
|
{
|
||
|
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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//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.
|
||
|
pendingkill = true;
|
||
|
}
|
||
|
}
|