Add support for HLMDL actions, and some builtins to interact with it.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@6148 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Eukara 2022-01-07 03:18:00 +00:00
parent f612b97fc9
commit 13b2a7935c
11 changed files with 174 additions and 21 deletions

View file

@ -3799,9 +3799,13 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
int numframes = 0; int numframes = 0;
float duration = 0; float duration = 0;
qboolean loop = false; qboolean loop = false;
if (!Mod_FrameInfoForNum(ent.model, mods->surfaceidx, mods->framegroup, &fname, &numframes, &duration, &loop)) int act = -1;
if (!Mod_FrameInfoForNum(ent.model, mods->surfaceidx, mods->framegroup, &fname, &numframes, &duration, &loop, &act))
fname = "Unknown Sequence"; fname = "Unknown Sequence";
Draw_FunString(0, y, va("Frame%i: %s (%i poses, %f of %f secs, %s)", mods->framegroup, fname, numframes, ent.framestate.g[FS_REG].frametime[0], duration, loop?"looped":"unlooped")); if (act != -1)
Draw_FunString(0, y, va("Frame%i[%i]: %s (%i poses, %f of %f secs, %s)", mods->framegroup, act, fname, numframes, ent.framestate.g[FS_REG].frametime[0], duration, loop?"looped":"unlooped"));
else
Draw_FunString(0, y, va("Frame%i: %s (%i poses, %f of %f secs, %s)", mods->framegroup, fname, numframes, ent.framestate.g[FS_REG].frametime[0], duration, loop?"looped":"unlooped"));
y+=8; y+=8;
} }

View file

@ -7054,8 +7054,9 @@ static struct {
// {"skel_postmul_bones", PF_skel_postmul_bones, 0},//void(float skel, float startbone, float endbone, vector org) skel_mul_bone = #273; // (FTE_CSQC_SKELETONOBJECTS) (reads v_forward etc) // {"skel_postmul_bones", PF_skel_postmul_bones, 0},//void(float skel, float startbone, float endbone, vector org) skel_mul_bone = #273; // (FTE_CSQC_SKELETONOBJECTS) (reads v_forward etc)
{"skel_copybones", PF_skel_copybones, 274},//void(float skeldst, float skelsrc, float startbone, float entbone) skel_copybones = #274; // (FTE_CSQC_SKELETONOBJECTS) {"skel_copybones", PF_skel_copybones, 274},//void(float skeldst, float skelsrc, float startbone, float entbone) skel_copybones = #274; // (FTE_CSQC_SKELETONOBJECTS)
{"skel_delete", PF_skel_delete, 275},//void(float skel) skel_delete = #275; // (FTE_CSQC_SKELETONOBJECTS) {"skel_delete", PF_skel_delete, 275},//void(float skel) skel_delete = #275; // (FTE_CSQC_SKELETONOBJECTS)
{"frameforname", PF_frameforname, 276},//void(float modidx, string framename) frameforname = #276 (FTE_CSQC_SKELETONOBJECTS) {"frameforname", PF_frameforname, 276},//float(float modidx, string framename) frameforname = #276 (FTE_CSQC_SKELETONOBJECTS)
{"frameduration", PF_frameduration, 277},//void(float modidx, float framenum) frameduration = #277 (FTE_CSQC_SKELETONOBJECTS) {"frameduration", PF_frameduration, 277},//float(float modidx, float framenum) frameduration = #277 (FTE_CSQC_SKELETONOBJECTS)
{"frameforaction", PF_frameforaction, 0},//float(float modidx, string actionid) frameforaction = #0
{"processmodelevents", PF_processmodelevents, 0}, {"processmodelevents", PF_processmodelevents, 0},
{"getnextmodelevent", PF_getnextmodelevent, 0}, {"getnextmodelevent", PF_getnextmodelevent, 0},
{"getmodeleventidx", PF_getmodeleventidx, 0}, {"getmodeleventidx", PF_getmodeleventidx, 0},

View file

@ -903,7 +903,8 @@ void skel_generateragdoll_f(void)
int numframes; int numframes;
float duration; float duration;
qboolean loop; qboolean loop;
if (!Mod_FrameInfoForNum(mod, 0, i, &fname, &numframes, &duration, &loop)) int act;
if (!Mod_FrameInfoForNum(mod, 0, i, &fname, &numframes, &duration, &loop, &act))
break; break;
VFS_PUTS(f, va("//%i %s (%i frames) (%f secs)%s", i, fname, numframes, duration, loop?" (loop)":"")); VFS_PUTS(f, va("//%i %s (%i frames) (%f secs)%s", i, fname, numframes, duration, loop?" (loop)":""));
} }
@ -2669,7 +2670,7 @@ void QCBUILTIN PF_gettagindex (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
void QCBUILTIN PF_frametoname (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_frametoname (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
world_t *w = prinst->parms->user; world_t *w = prinst->parms->user;
unsigned int modelindex = G_FLOAT(OFS_PARM0); int modelindex = G_FLOAT(OFS_PARM0);
unsigned int skinnum = G_FLOAT(OFS_PARM1); unsigned int skinnum = G_FLOAT(OFS_PARM1);
int surfaceidx = 0; int surfaceidx = 0;
model_t *mod = w->Get_CModel(w, modelindex); model_t *mod = w->Get_CModel(w, modelindex);
@ -2684,7 +2685,7 @@ void QCBUILTIN PF_frametoname (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
void QCBUILTIN PF_frameforname (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_frameforname (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
world_t *w = prinst->parms->user; world_t *w = prinst->parms->user;
unsigned int modelindex = G_FLOAT(OFS_PARM0); int modelindex = G_FLOAT(OFS_PARM0);
int surfaceidx = 0; int surfaceidx = 0;
const char *str = PF_VarString(prinst, 1, pr_globals); const char *str = PF_VarString(prinst, 1, pr_globals);
model_t *mod = w->Get_CModel(w, modelindex); model_t *mod = w->Get_CModel(w, modelindex);
@ -2694,10 +2695,23 @@ void QCBUILTIN PF_frameforname (pubprogfuncs_t *prinst, struct globalvars_s *pr_
else else
G_FLOAT(OFS_RETURN) = -1; G_FLOAT(OFS_RETURN) = -1;
} }
void QCBUILTIN PF_frameforaction (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
world_t *w = prinst->parms->user;
int modelindex = G_FLOAT(OFS_PARM0);
int surfaceidx = 0;
int actionid = G_INT(OFS_PARM1);
model_t *mod = w->Get_CModel(w, modelindex);
if (mod)
G_FLOAT(OFS_RETURN) = Mod_FrameNumForAction(mod, surfaceidx, actionid);
else
G_FLOAT(OFS_RETURN) = -1;
}
void QCBUILTIN PF_frameduration (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_frameduration (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
world_t *w = prinst->parms->user; world_t *w = prinst->parms->user;
unsigned int modelindex = G_FLOAT(OFS_PARM0); int modelindex = G_FLOAT(OFS_PARM0);
unsigned int framenum = G_FLOAT(OFS_PARM1); unsigned int framenum = G_FLOAT(OFS_PARM1);
int surfaceidx = 0; int surfaceidx = 0;
model_t *mod = w->Get_CModel(w, modelindex); model_t *mod = w->Get_CModel(w, modelindex);
@ -2723,7 +2737,7 @@ void QCBUILTIN PF_modelframecount (pubprogfuncs_t *prinst, struct globalvars_s *
void QCBUILTIN PF_processmodelevents (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_processmodelevents (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
world_t *w = prinst->parms->user; world_t *w = prinst->parms->user;
unsigned int modelindex = G_FLOAT(OFS_PARM0); int modelindex = G_FLOAT(OFS_PARM0);
unsigned int frame = G_FLOAT(OFS_PARM1); unsigned int frame = G_FLOAT(OFS_PARM1);
float basetime = G_FLOAT(OFS_PARM2); float basetime = G_FLOAT(OFS_PARM2);
float targettime = G_FLOAT(OFS_PARM3); float targettime = G_FLOAT(OFS_PARM3);
@ -2786,8 +2800,9 @@ void QCBUILTIN PF_processmodelevents (pubprogfuncs_t *prinst, struct globalvars_
char *data; char *data;
float loopduration; float loopduration;
qboolean looping; qboolean looping;
int act;
if (Mod_FrameInfoForNum(mod, 0, frame, &data, &code, &loopduration, &looping)) if (Mod_FrameInfoForNum(mod, 0, frame, &data, &code, &loopduration, &looping, &act))
{ {
if (looping && loopduration) if (looping && loopduration)
starttime = loopduration*(unsigned int)(basetime/loopduration); starttime = loopduration*(unsigned int)(basetime/loopduration);
@ -2891,8 +2906,9 @@ void QCBUILTIN PF_getnextmodelevent (pubprogfuncs_t *prinst, struct globalvars_s
char *data; char *data;
float loopduration; float loopduration;
qboolean looping; qboolean looping;
int act;
if (!Mod_FrameInfoForNum(mod, 0, frame, &data, &code, &loopduration, &looping)) if (!Mod_FrameInfoForNum(mod, 0, frame, &data, &code, &loopduration, &looping, &act))
return; //invalid frame return; //invalid frame
if (looping && loopduration) if (looping && loopduration)

View file

@ -555,6 +555,7 @@ void Mod_Shutdown (qboolean final);
int Mod_TagNumForName(struct model_s *model, const char *name); int Mod_TagNumForName(struct model_s *model, const char *name);
int Mod_SkinNumForName(struct model_s *model, int surfaceidx, const char *name); int Mod_SkinNumForName(struct model_s *model, int surfaceidx, const char *name);
int Mod_FrameNumForName(struct model_s *model, int surfaceidx, const char *name); int Mod_FrameNumForName(struct model_s *model, int surfaceidx, const char *name);
int Mod_FrameNumForAction(struct model_s *model, int surfaceidx, int actionid);
float Mod_GetFrameDuration(struct model_s *model, int surfaceidx, int frameno); float Mod_GetFrameDuration(struct model_s *model, int surfaceidx, int frameno);
void Mod_ResortShaders(void); void Mod_ResortShaders(void);

View file

@ -2883,6 +2883,8 @@ typedef struct
unsigned int posecount; unsigned int posecount;
float fps; float fps;
qboolean loop; qboolean loop;
int action;
int actionweight;
char name[MAX_QPATH]; char name[MAX_QPATH];
} frameinfo_t; } frameinfo_t;
static frameinfo_t *ParseFrameInfo(char *modelname, int *numgroups) static frameinfo_t *ParseFrameInfo(char *modelname, int *numgroups)
@ -2923,11 +2925,25 @@ static frameinfo_t *ParseFrameInfo(char *modelname, int *numgroups)
frames[count].loop = true; frames[count].loop = true;
else else
frames[count].loop = !!atoi(tok); frames[count].loop = !!atoi(tok);
frames[count].action = -1;
frames[count].actionweight = 0;
Q_snprintfz(frames[count].name, sizeof(frames[count].name), "groupified_%d_anim", count); //to match DP. frameforname cares.
line = COM_ParseType(line, tok, sizeof(tok), &ttype); line = COM_ParseType(line, tok, sizeof(tok), &ttype);
if (ttype != TTP_EOF) if (ttype != TTP_EOF)
{
Q_strncpyz(frames[count].name, tok, sizeof(frames[count].name)); Q_strncpyz(frames[count].name, tok, sizeof(frames[count].name));
else line = COM_ParseType(line, tok, sizeof(tok), &ttype);
Q_snprintfz(frames[count].name, sizeof(frames[count].name), "groupified_%d_anim", count); //to match DP. frameforname cares. }
if (ttype != TTP_EOF)
{
frames[count].action = atoi(tok);
line = COM_ParseType(line, tok, sizeof(tok), &ttype);
}
if (ttype != TTP_EOF)
frames[count].actionweight = atoi(tok);
if (frames[count].posecount>0 && frames[count].fps) if (frames[count].posecount>0 && frames[count].fps)
count++; count++;
@ -3509,6 +3525,8 @@ static void *Q1MDL_LoadFrameGroup (galiasinfo_t *galias, dmdl_t *pq1inmodel, mod
for (i = 0; i < pq1inmodel->numframes; i++) for (i = 0; i < pq1inmodel->numframes; i++)
{ {
frame->action = -1;
frame->actionweight = 0;
switch(LittleLong(pframetype->type)) switch(LittleLong(pframetype->type))
{ {
case ALIAS_SINGLE: case ALIAS_SINGLE:
@ -3979,6 +3997,8 @@ static void Mesh_HandleFramegroupsFile(model_t *mod, galiasinfo_t *galias)
o->numposes = p; o->numposes = p;
o->rate = framegroups[a].fps; o->rate = framegroups[a].fps;
o->loop = framegroups[a].loop; o->loop = framegroups[a].loop;
o->action = -1;
o->actionweight = 0;
Q_strncpyz(o->name, framegroups[a].name, sizeof(o->name)); Q_strncpyz(o->name, framegroups[a].name, sizeof(o->name));
} }
galias->numanimations = numanims; galias->numanimations = numanims;
@ -4981,6 +5001,8 @@ static qboolean QDECL Mod_LoadKingpinModel (model_t *mod, void *buffer, size_t f
{ {
poutframe->poseofs = pose; poutframe->poseofs = pose;
poutframe->numposes = 1; poutframe->numposes = 1;
poutframe->action = -1;
poutframe->actionweight = 0;
galias->numanimations++; galias->numanimations++;
#ifndef SERVERONLY #ifndef SERVERONLY
@ -5490,6 +5512,47 @@ int Mod_FrameNumForName(model_t *model, int surfaceidx, const char *name)
return -1; return -1;
} }
int Mod_FrameNumForAction(model_t *model, int surfaceidx, int actionid)
{
galiasanimation_t *group;
galiasinfo_t *inf;
int i;
float weight;
if (!model)
return -1;
#ifdef HALFLIFEMODELS
if (model->type == mod_halflife)
return HLMDL_FrameForAction(model, actionid);
#endif
if (model->type != mod_alias)
return -1;
inf = Mod_Extradata(model);
while(surfaceidx-->0 && inf)
inf = inf->nextsurf;
if (inf)
{
for (i = 0, weight = 0, group = inf->ofsanimations; i < inf->numanimations; i++, group++)
{
if (group->action == actionid)
weight += group->actionweight;
}
weight *= frandom();
for (i = 0, group = inf->ofsanimations; i < inf->numanimations; i++, group++)
{
if (group->action == actionid)
{
if (weight <= group->actionweight)
return i;
weight -= group->actionweight;
}
}
}
return -1;
}
qboolean Mod_GetModelEvent(model_t *model, int animation, int eventidx, float *timestamp, int *eventcode, char **eventdata) qboolean Mod_GetModelEvent(model_t *model, int animation, int eventidx, float *timestamp, int *eventcode, char **eventdata)
{ {
@ -5586,7 +5649,7 @@ const char *Mod_FrameNameForNum(model_t *model, int surfaceidx, int num)
return NULL; return NULL;
} }
qboolean Mod_FrameInfoForNum(model_t *model, int surfaceidx, int num, char **name, int *numframes, float *duration, qboolean *loop) qboolean Mod_FrameInfoForNum(model_t *model, int surfaceidx, int num, char **name, int *numframes, float *duration, qboolean *loop, int *act)
{ {
galiasanimation_t *group; galiasanimation_t *group;
galiasinfo_t *inf; galiasinfo_t *inf;
@ -5615,11 +5678,12 @@ qboolean Mod_FrameInfoForNum(model_t *model, int surfaceidx, int num, char **nam
*numframes = group[num].numposes; *numframes = group[num].numposes;
*loop = group[num].loop; *loop = group[num].loop;
*duration = group->numposes/group->rate; *duration = group->numposes/group->rate;
*act = group[num].action;
return true; return true;
} }
#ifdef HALFLIFEMODELS #ifdef HALFLIFEMODELS
if (model->type == mod_halflife) if (model->type == mod_halflife)
return HLMDL_FrameInfoForNum(model, surfaceidx, num, name, numframes, duration, loop); return HLMDL_FrameInfoForNum(model, surfaceidx, num, name, numframes, duration, loop, act);
#endif #endif
return false; return false;
} }
@ -5766,7 +5830,8 @@ float Mod_GetFrameDuration(model_t *model, int surfaceidx, int frameno)
float duration; float duration;
char *name; char *name;
qboolean loop; qboolean loop;
HLMDL_FrameInfoForNum(model, surfaceidx, frameno, &name, &unused, &duration, &loop); int act;
HLMDL_FrameInfoForNum(model, surfaceidx, frameno, &name, &unused, &duration, &loop, &act);
return duration; return duration;
} }
#endif #endif
@ -6020,6 +6085,8 @@ static galiasinfo_t *Mod_LoadQ3ModelLod(model_t *mod, int *surfcount, void *buff
group->poseofs = pose + first; group->poseofs = pose + first;
group->loop = framegroups[i].loop; group->loop = framegroups[i].loop;
group->events = NULL; group->events = NULL;
group->action = -1;
group->actionweight = 0;
group++; group++;
} }
} }
@ -6033,6 +6100,8 @@ static galiasinfo_t *Mod_LoadQ3ModelLod(model_t *mod, int *surfcount, void *buff
group->poseofs = pose + i; group->poseofs = pose + i;
group->loop = false; group->loop = false;
group->events = NULL; group->events = NULL;
group->action = -1;
group->actionweight = 0;
group++; group++;
} }
} }
@ -6523,6 +6592,8 @@ static qboolean QDECL Mod_LoadZymoticModel(model_t *mod, void *buffer, size_t fs
grp->loop = !(BigLong(inscene->flags) & ZYMSCENEFLAG_NOLOOP); grp->loop = !(BigLong(inscene->flags) & ZYMSCENEFLAG_NOLOOP);
grp->numposes = BigLong(inscene->length); grp->numposes = BigLong(inscene->length);
grp->boneofs = matrix + BigLong(inscene->start)*12*root->numbones; grp->boneofs = matrix + BigLong(inscene->start)*12*root->numbones;
grp->action = -1;
grp->actionweight = 0;
} }
if (inscene != (zymscene_t*)((char*)header + header->lump_scenes.start+header->lump_scenes.length)) if (inscene != (zymscene_t*)((char*)header + header->lump_scenes.start+header->lump_scenes.length))
@ -7083,6 +7154,8 @@ static qboolean QDECL Mod_LoadPSKModel(model_t *mod, void *buffer, size_t fsize)
group[j].loop = frameinfo[j].loop; group[j].loop = frameinfo[j].loop;
group[j].rate = frameinfo[j].fps; group[j].rate = frameinfo[j].fps;
group[j].skeltype = SKEL_RELATIVE; group[j].skeltype = SKEL_RELATIVE;
group[j].action = -1;
group[j].actionweight = 0;
} }
num_animinfo = numgroups; num_animinfo = numgroups;
} }
@ -7107,6 +7180,8 @@ static qboolean QDECL Mod_LoadPSKModel(model_t *mod, void *buffer, size_t fsize)
group[iframe].loop = true; group[iframe].loop = true;
group[iframe].rate = animinfo[j].fps; group[iframe].rate = animinfo[j].fps;
group[iframe].skeltype = SKEL_RELATIVE; group[iframe].skeltype = SKEL_RELATIVE;
group[iframe].action = -1;
group[iframe].actionweight = 0;
iframe++; iframe++;
} }
} }
@ -7126,6 +7201,8 @@ static qboolean QDECL Mod_LoadPSKModel(model_t *mod, void *buffer, size_t fsize)
group[i].loop = true; group[i].loop = true;
group[i].rate = animinfo[i].fps; group[i].rate = animinfo[i].fps;
group[i].skeltype = SKEL_RELATIVE; group[i].skeltype = SKEL_RELATIVE;
group[i].action = -1;
group[i].actionweight = 0;
} }
} }
for (j = 0; j < num_animkeys; j += num_boneinfo) for (j = 0; j < num_animkeys; j += num_boneinfo)
@ -7153,6 +7230,8 @@ static qboolean QDECL Mod_LoadPSKModel(model_t *mod, void *buffer, size_t fsize)
group->loop = true; group->loop = true;
group->rate = 10; group->rate = 10;
group->skeltype = SKEL_ABSOLUTE; group->skeltype = SKEL_ABSOLUTE;
group->action = -1;
group->actionweight = 0;
} }
@ -7451,6 +7530,8 @@ static qboolean QDECL Mod_LoadDarkPlacesModel(model_t *mod, void *buffer, size_t
outgroups[i].numposes = 1; outgroups[i].numposes = 1;
outgroups[i].skeltype = SKEL_RELATIVE; outgroups[i].skeltype = SKEL_RELATIVE;
outgroups[i].boneofs = outposedata; outgroups[i].boneofs = outposedata;
outgroups[i].action = -1;
outgroups[i].actionweight = 0;
inposedata = (float*)((char*)buffer + inframes[i].ofs_bonepositions); inposedata = (float*)((char*)buffer + inframes[i].ofs_bonepositions);
for (j = 0; j < header->num_bones*12; j++) for (j = 0; j < header->num_bones*12; j++)
@ -7488,6 +7569,8 @@ static qboolean QDECL Mod_LoadDarkPlacesModel(model_t *mod, void *buffer, size_t
outgroups[i].loop = framegroups[i].loop; outgroups[i].loop = framegroups[i].loop;
outgroups[i].rate = framegroups[i].fps; outgroups[i].rate = framegroups[i].fps;
outgroups[i].events = NULL; outgroups[i].events = NULL;
outgroups[i].action = -1;
outgroups[i].actionweight = 0;
Q_strncpyz(outgroups[i].name, framegroups[i].name, sizeof(outgroups[i].name)); Q_strncpyz(outgroups[i].name, framegroups[i].name, sizeof(outgroups[i].name));
} }
} }
@ -8290,6 +8373,8 @@ static galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, siz
framegroups[i].posecount = LittleLong(anim[i].num_frames); framegroups[i].posecount = LittleLong(anim[i].num_frames);
framegroups[i].fps = LittleFloat(anim[i].framerate); framegroups[i].fps = LittleFloat(anim[i].framerate);
framegroups[i].loop = !!(LittleLong(anim[i].flags) & IQM_LOOP); framegroups[i].loop = !!(LittleLong(anim[i].flags) & IQM_LOOP);
framegroups[i].action = -1;
framegroups[i].actionweight = 0;
Q_strncpyz(framegroups[i].name, strings+anim[i].name, sizeof(fgroup[i].name)); Q_strncpyz(framegroups[i].name, strings+anim[i].name, sizeof(fgroup[i].name));
} }
} }
@ -8303,6 +8388,8 @@ static galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, siz
framegroups->posecount = 1; framegroups->posecount = 1;
framegroups->fps = 10; framegroups->fps = 10;
framegroups->loop = 1; framegroups->loop = 1;
framegroups->action = -1;
framegroups->actionweight = 0;
strcpy(framegroups->name, "base"); strcpy(framegroups->name, "base");
} }
@ -8473,6 +8560,9 @@ static galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, siz
if (fgroup[i].rate <= 0) if (fgroup[i].rate <= 0)
fgroup[i].rate = 10; fgroup[i].rate = 10;
fgroup[i].action = framegroups[i].action;
fgroup[i].actionweight = framegroups[i].actionweight;
} }
free(framegroups); free(framegroups);

View file

@ -62,6 +62,8 @@ typedef struct galiasanimation_s
int numposes; int numposes;
//float *poseendtime; //first starts at 0, anim duration is poseendtime[numposes-1] //float *poseendtime; //first starts at 0, anim duration is poseendtime[numposes-1]
float rate; //average framerate of animation. float rate; //average framerate of animation.
int action;
float actionweight;
#ifdef NONSKELETALMODELS #ifdef NONSKELETALMODELS
galiaspose_t *poseofs; galiaspose_t *poseofs;
#endif #endif
@ -270,7 +272,7 @@ typedef struct modplugfuncs_s
#define plugmodfuncs_name "Models_IDX" STRINGIFY(sizeof_index_t) #define plugmodfuncs_name "Models_IDX" STRINGIFY(sizeof_index_t)
#endif #endif
} plugmodfuncs_t; } plugmodfuncs_t;
#define MODPLUGFUNCS_VERSION 2 #define MODPLUGFUNCS_VERSION 3
#ifdef SKELETALMODELS #ifdef SKELETALMODELS
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);
@ -286,7 +288,7 @@ const char *Mod_SkinNameForNum(model_t *model, int surfaceidx, int num);
const char *Mod_SurfaceNameForNum(model_t *model, int num); const char *Mod_SurfaceNameForNum(model_t *model, int num);
const char *Mod_FrameNameForNum(model_t *model, int surfaceidx, int num); const char *Mod_FrameNameForNum(model_t *model, int surfaceidx, int num);
const char *Mod_SkinNameForNum(model_t *model, int surfaceidx, int num); const char *Mod_SkinNameForNum(model_t *model, int surfaceidx, int num);
qboolean Mod_FrameInfoForNum(model_t *model, int surfaceidx, int num, char **name, int *numframes, float *duration, qboolean *loop); qboolean Mod_FrameInfoForNum(model_t *model, int surfaceidx, int num, char **name, int *numframes, float *duration, qboolean *loop, int *act);
qboolean Mod_DoCRC(model_t *mod, char *buffer, int buffersize); qboolean Mod_DoCRC(model_t *mod, char *buffer, int buffersize);

View file

@ -315,6 +315,7 @@ void QCBUILTIN PF_setattachment(pubprogfuncs_t *prinst, struct globalvars_s *pr_
void QCBUILTIN PF_frametoname (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_frametoname (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_skintoname (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_skintoname (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_frameforname (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_frameforname (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_frameforaction (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_frameduration (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_frameduration (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_modelframecount (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_modelframecount (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_skinforname (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_skinforname (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);

View file

@ -612,6 +612,38 @@ int HLMDL_FrameForName(model_t *mod, const char *name)
return -1; return -1;
} }
int HLMDL_FrameForAction(model_t *mod, int actionid)
{
int i;
hlmdl_header_t *h;
hlmdl_sequencelist_t *seqs;
hlmodel_t *mc;
int weight = 0;
if (!mod || mod->type != mod_halflife)
return -1; //halflife models only, please
mc = Mod_Extradata(mod);
h = mc->header;
seqs = (hlmdl_sequencelist_t*)((char*)h+h->seqindex);
//figure out the total weight.
for (i = 0; i < h->numseq; i++)
if (seqs[i].action == actionid)
weight += seqs[i].actionweight;
//pick a random number between 0 and the total weight...
weight *= frandom();
//now figure out which sequence that gives us.
for (i = 0; i < h->numseq; i++)
if (seqs[i].action == actionid)
{
if (weight <= seqs[i].actionweight)
return i;
weight -= seqs[i].actionweight;
}
return -1; //failed...
}
qboolean HLMDL_GetModelEvent(model_t *model, int animation, int eventidx, float *timestamp, int *eventcode, char **eventdata) qboolean HLMDL_GetModelEvent(model_t *model, int animation, int eventidx, float *timestamp, int *eventcode, char **eventdata)
{ {
hlmodel_t *mc = Mod_Extradata(model); hlmodel_t *mc = Mod_Extradata(model);
@ -1146,7 +1178,7 @@ const char *HLMDL_FrameNameForNum(model_t *mod, int surfaceidx, int seqnum)
((unsigned int)seqnum>=model->header->numseq?0:seqnum); ((unsigned int)seqnum>=model->header->numseq?0:seqnum);
return sequence->name; return sequence->name;
} }
qboolean HLMDL_FrameInfoForNum(model_t *mod, int surfaceidx, int seqnum, char **name, int *numframes, float *duration, qboolean *loop) qboolean HLMDL_FrameInfoForNum(model_t *mod, int surfaceidx, int seqnum, char **name, int *numframes, float *duration, qboolean *loop, int *act)
{ {
hlmodel_t *model = Mod_Extradata(mod); hlmodel_t *model = Mod_Extradata(mod);
hlmdl_sequencelist_t *sequence = (hlmdl_sequencelist_t *) ((qbyte *) model->header + model->header->seqindex) + hlmdl_sequencelist_t *sequence = (hlmdl_sequencelist_t *) ((qbyte *) model->header + model->header->seqindex) +
@ -1156,6 +1188,7 @@ qboolean HLMDL_FrameInfoForNum(model_t *mod, int surfaceidx, int seqnum, char **
*numframes = sequence->numframes; *numframes = sequence->numframes;
*duration = (sequence->numframes-1)/sequence->timing; *duration = (sequence->numframes-1)/sequence->timing;
*loop = sequence->loop; *loop = sequence->loop;
*act = sequence->action;
return true; return true;
} }

View file

@ -224,7 +224,8 @@ typedef struct
char name[32]; char name[32];
float timing; float timing;
int loop; int loop;
int unknown1[2]; int action;
int actionweight;
int num_events; int num_events;
int ofs_events; int ofs_events;
int numframes; int numframes;
@ -330,8 +331,9 @@ void *Mod_GetHalfLifeModelData(model_t *mod);
//reflectioney things, including bone data //reflectioney things, including bone data
int HLMDL_BoneForName(model_t *mod, const char *name); int HLMDL_BoneForName(model_t *mod, const char *name);
int HLMDL_FrameForName(model_t *mod, const char *name); int HLMDL_FrameForName(model_t *mod, const char *name);
int HLMDL_FrameForAction(model_t *mod, int actionid);
const char *HLMDL_FrameNameForNum(model_t *model, int surfaceidx, int num); const char *HLMDL_FrameNameForNum(model_t *model, int surfaceidx, int num);
qboolean HLMDL_FrameInfoForNum(model_t *model, int surfaceidx, int num, char **name, int *numframes, float *duration, qboolean *loop); qboolean HLMDL_FrameInfoForNum(model_t *model, int surfaceidx, int num, char **name, int *numframes, float *duration, qboolean *loop, int *act);
qboolean HLMDL_GetModelEvent(model_t *model, int animation, int eventidx, float *timestamp, int *eventcode, char **eventdata); qboolean HLMDL_GetModelEvent(model_t *model, int animation, int eventidx, float *timestamp, int *eventcode, char **eventdata);
int HLMDL_GetNumBones(model_t *mod, qboolean tagstoo); int HLMDL_GetNumBones(model_t *mod, qboolean tagstoo);
int HLMDL_GetBoneParent(model_t *mod, int bonenum); int HLMDL_GetBoneParent(model_t *mod, int bonenum);

View file

@ -11407,6 +11407,7 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"skel_delete", PF_skel_delete, 0, 0, 0, 275, D("void(float skel)", "Deletes a skeletal object. The actual delete is delayed, allowing the skeletal object to be deleted in an entity's predraw function yet still be valid by the time the addentity+renderscene builtins need it. Also uninstanciates any ragdoll currently in effect on the skeletal object.")}, // (FTE_CSQC_SKELETONOBJECTS) {"skel_delete", PF_skel_delete, 0, 0, 0, 275, D("void(float skel)", "Deletes a skeletal object. The actual delete is delayed, allowing the skeletal object to be deleted in an entity's predraw function yet still be valid by the time the addentity+renderscene builtins need it. Also uninstanciates any ragdoll currently in effect on the skeletal object.")}, // (FTE_CSQC_SKELETONOBJECTS)
{"frameforname", PF_frameforname, 0, 0, 0, 276, D("float(float modidx, string framename)", "Looks up a framegroup from a model by name, avoiding the need for hardcoding. Returns -1 on error.")},// (FTE_CSQC_SKELETONOBJECTS) {"frameforname", PF_frameforname, 0, 0, 0, 276, D("float(float modidx, string framename)", "Looks up a framegroup from a model by name, avoiding the need for hardcoding. Returns -1 on error.")},// (FTE_CSQC_SKELETONOBJECTS)
{"frameduration", PF_frameduration, 0, 0, 0, 277, D("float(float modidx, float framenum)", "Retrieves the duration (in seconds) of the specified framegroup.")},// (FTE_CSQC_SKELETONOBJECTS) {"frameduration", PF_frameduration, 0, 0, 0, 277, D("float(float modidx, float framenum)", "Retrieves the duration (in seconds) of the specified framegroup.")},// (FTE_CSQC_SKELETONOBJECTS)
{"frameforaction", PF_frameforaction, 0, 0, 0, 0, D("float(float modidx, int actionid)", "Returns a random frame/animation for the specified mod-defined action, or -1 if no animations have the specified action.")},
{"processmodelevents",PF_processmodelevents,0, 0, 0, 0, D("void(float modidx, float framenum, __inout float basetime, float targettime, void(float timestamp, int code, string data) callback)", "Calls a callback for each event that has been reached. Basetime is set to targettime.")}, {"processmodelevents",PF_processmodelevents,0, 0, 0, 0, D("void(float modidx, float framenum, __inout float basetime, float targettime, void(float timestamp, int code, string data) callback)", "Calls a callback for each event that has been reached. Basetime is set to targettime.")},
{"getnextmodelevent",PF_getnextmodelevent,0, 0, 0, 0, D("float(float modidx, float framenum, __inout float basetime, float targettime, __out int code, __out string data)", "Reports the next event within a model's animation. Returns a boolean if an event was found between basetime and targettime. Writes to basetime,code,data arguments (if an event was found, basetime is set to the event's time, otherwise to targettime).\nWARNING: this builtin cannot deal with multiple events with the same timestamp (only the first will be reported).")}, {"getnextmodelevent",PF_getnextmodelevent,0, 0, 0, 0, D("float(float modidx, float framenum, __inout float basetime, float targettime, __out int code, __out string data)", "Reports the next event within a model's animation. Returns a boolean if an event was found between basetime and targettime. Writes to basetime,code,data arguments (if an event was found, basetime is set to the event's time, otherwise to targettime).\nWARNING: this builtin cannot deal with multiple events with the same timestamp (only the first will be reported).")},
{"getmodeleventidx",PF_getmodeleventidx,0, 0, 0, 0, D("float(float modidx, float framenum, int eventidx, __out float timestamp, __out int code, __out string data)", "Reports an indexed event within a model's animation. Writes to timestamp,code,data arguments on success. Returns false if the animation/event/model was out of range/invalid. Does not consider looping animations (retry from index 0 if it fails and you know that its a looping animation). This builtin is more annoying to use than getnextmodelevent, but can be made to deal with multiple events with the exact same timestamp.")}, {"getmodeleventidx",PF_getmodeleventidx,0, 0, 0, 0, D("float(float modidx, float framenum, int eventidx, __out float timestamp, __out int code, __out string data)", "Reports an indexed event within a model's animation. Writes to timestamp,code,data arguments on success. Returns false if the animation/event/model was out of range/invalid. Does not consider looping animations (retry from index 0 if it fails and you know that its a looping animation). This builtin is more annoying to use than getnextmodelevent, but can be made to deal with multiple events with the exact same timestamp.")},

View file

@ -3428,6 +3428,8 @@ static qboolean GLTF_LoadModel(struct model_s *mod, char *json, size_t jsonsize,
} }
fg->loop = !!mod_gltf_loop->ival; fg->loop = !!mod_gltf_loop->ival;
fg->skeltype = SKEL_RELATIVE; fg->skeltype = SKEL_RELATIVE;
fg->action = -1;
fg->actionweight = 0;
for(chan = JSON_FindIndexedChild(anim, "channels", 0); chan; chan = chan->sibling) for(chan = JSON_FindIndexedChild(anim, "channels", 0); chan; chan = chan->sibling)
{ {
struct gltf_animsampler s; struct gltf_animsampler s;