Add json-formatted framegroups files. Allow for ragdolls to be used with hlmdl. Try to be smarter/higher with gpu bone limits.
This commit is contained in:
parent
28a880c56e
commit
9bc9700506
11 changed files with 333 additions and 113 deletions
|
@ -3377,8 +3377,8 @@ typedef struct
|
|||
int boneidx;
|
||||
int bonebias; //shift the bones menu down to ensure the boneidx stays visible
|
||||
int textype;
|
||||
double framechangetime;
|
||||
double skinchangetime;
|
||||
double frametime;
|
||||
double skintime;
|
||||
|
||||
float pitch;
|
||||
float yaw;
|
||||
|
@ -3394,6 +3394,7 @@ typedef struct
|
|||
char shaderfile[MAX_QPATH];
|
||||
char *shadertext;
|
||||
|
||||
qboolean paused;
|
||||
#ifdef RAGDOLL
|
||||
lerpents_t ragent;
|
||||
world_t ragworld;
|
||||
|
@ -3523,7 +3524,7 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
|
|||
r_refdef.grect.height = vid.height;
|
||||
r_refdef.grect.x = 0;
|
||||
r_refdef.grect.y = 0;
|
||||
r_refdef.time = realtime;
|
||||
r_refdef.time = mods->skintime;
|
||||
|
||||
r_refdef.flags = RDF_NOWORLDMODEL;
|
||||
|
||||
|
@ -3620,7 +3621,7 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
|
|||
ent.shaderTime = 0;//realtime;
|
||||
ent.framestate.g[FS_REG].lerpweight[0] = 1;
|
||||
ent.framestate.g[FS_REG].frame[0] = mods->framegroup;
|
||||
ent.framestate.g[FS_REG].frametime[0] = ent.framestate.g[FS_REG].frametime[1] = realtime - mods->framechangetime;
|
||||
ent.framestate.g[FS_REG].frametime[0] = ent.framestate.g[FS_REG].frametime[1] = mods->frametime;
|
||||
ent.framestate.g[FS_REG].endbone = 0x7fffffff;
|
||||
if (*mods->skinname)
|
||||
{
|
||||
|
@ -3651,6 +3652,12 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
|
|||
#endif
|
||||
|
||||
V_ApplyRefdef();
|
||||
|
||||
if (!mods->paused)
|
||||
{
|
||||
mods->frametime += host_frametime;
|
||||
mods->skintime += host_frametime;
|
||||
}
|
||||
/*
|
||||
{
|
||||
trace_t tr;
|
||||
|
@ -3707,9 +3714,8 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
|
|||
ent.framestate.g[FS_REG].frame[0] |= 0x8000;
|
||||
if (ent.model->dollinfo && mods->ragworld.rbe)
|
||||
{
|
||||
float rate = 1.0/60;
|
||||
float rate = 1.0/60; //try a fixed tick rate...
|
||||
rag_doallanimations(&mods->ragworld);
|
||||
mods->fixedrate += host_frametime;
|
||||
if (mods->fixedrate > 1)
|
||||
mods->fixedrate = 1;
|
||||
while (mods->fixedrate >= rate)
|
||||
|
@ -3717,6 +3723,8 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
|
|||
mods->ragworld.rbe->RunFrame(&mods->ragworld, rate, 800);
|
||||
mods->fixedrate -= rate;
|
||||
}
|
||||
if (!mods->paused)
|
||||
mods->fixedrate += host_frametime;
|
||||
|
||||
rag_updatedeltaent(&mods->ragworld, &ent, &mods->ragent);
|
||||
}
|
||||
|
@ -4250,10 +4258,18 @@ static qboolean M_ModelViewerKey(struct menucustom_s *c, struct emenu_s *m, int
|
|||
case MV_NORMALS: mods->mode = MV_NONE; break;
|
||||
}
|
||||
}
|
||||
else if (key >= '1' && key <= '7')
|
||||
{
|
||||
Z_Free(mods->shadertext);
|
||||
mods->shadertext = NULL;
|
||||
mods->mode = MV_NONE + (key - '1');
|
||||
}
|
||||
else if (key == 'p')
|
||||
mods->paused = !mods->paused;
|
||||
else if (key == 'r')
|
||||
{
|
||||
mods->framechangetime = realtime;
|
||||
mods->skinchangetime = realtime;
|
||||
mods->frametime = 0;
|
||||
mods->skintime = 0;
|
||||
}
|
||||
#ifdef RAGDOLL
|
||||
else if (key == 'f')
|
||||
|
@ -4290,28 +4306,28 @@ static qboolean M_ModelViewerKey(struct menucustom_s *c, struct emenu_s *m, int
|
|||
else if (key == K_END)
|
||||
{
|
||||
mods->skingroup = max(0, mods->skingroup-1);
|
||||
mods->skinchangetime = realtime;
|
||||
mods->skintime = 0;
|
||||
Z_Free(mods->shadertext);
|
||||
mods->shadertext = NULL;
|
||||
}
|
||||
else if (key == K_HOME)
|
||||
{
|
||||
mods->skingroup += 1;
|
||||
mods->skinchangetime = realtime;
|
||||
mods->skintime = 0;
|
||||
Z_Free(mods->shadertext);
|
||||
mods->shadertext = NULL;
|
||||
}
|
||||
else if (key == K_PGDN)
|
||||
{
|
||||
mods->framegroup = max(0, mods->framegroup-1);
|
||||
mods->framechangetime = realtime;
|
||||
mods->frametime = 0;
|
||||
Z_Free(mods->shadertext);
|
||||
mods->shadertext = NULL;
|
||||
}
|
||||
else if (key == K_PGUP)
|
||||
{
|
||||
mods->framegroup += 1;
|
||||
mods->framechangetime = realtime;
|
||||
mods->frametime = 0;
|
||||
}
|
||||
else if (key == K_DEL)
|
||||
{
|
||||
|
@ -4393,8 +4409,8 @@ void M_Menu_ModelViewer_f(void)
|
|||
Q_strncpyz(mv->skinname, Cmd_Argv(2), sizeof(mv->skinname));
|
||||
Q_strncpyz(mv->animname, Cmd_Argv(3), sizeof(mv->animname));
|
||||
|
||||
mv->framechangetime = realtime;
|
||||
mv->skinchangetime = realtime;
|
||||
mv->frametime = 0;
|
||||
mv->skintime = 0;
|
||||
#ifdef RAGDOLL
|
||||
menu->menu.videoreset = M_Modelviewer_Reset;
|
||||
menu->remove = M_Modelviewer_Shutdown;
|
||||
|
|
|
@ -52,6 +52,8 @@ typedef struct doll_s
|
|||
struct doll_s *next;
|
||||
|
||||
qboolean drawn:1;
|
||||
int refanim; //-1 for skining pose. otherwise the first pose of the specified anim. probaly 0.
|
||||
float refanimtime; //usually just 0
|
||||
int numdefaultanimated;
|
||||
int numbodies;
|
||||
int numjoints;
|
||||
|
@ -349,6 +351,7 @@ static dollcreatectx_t *rag_createdoll(model_t *mod, const char *fname, int numb
|
|||
ctx->d->next = dolllist;
|
||||
ctx->d->name = strdup(fname);
|
||||
ctx->d->model = mod;
|
||||
ctx->d->refanim = -1; //skin pose.
|
||||
ctx->d->numbodies = 0;
|
||||
ctx->d->body = NULL;
|
||||
ctx->d->numjoints = 0;
|
||||
|
@ -377,6 +380,13 @@ static qboolean rag_dollline(dollcreatectx_t *ctx, int linenum)
|
|||
if (!argc)
|
||||
{
|
||||
}
|
||||
else if (argc == 2 && !stricmp(cmd, "refpose") && !strcmp(val, "skin"))
|
||||
ctx->d->refanim = -1;
|
||||
else if (argc == 3 && !stricmp(cmd, "refpose"))
|
||||
{
|
||||
ctx->d->refanim = atoi(val);
|
||||
ctx->d->refanimtime = atoi(Cmd_Argv(2));
|
||||
}
|
||||
//create a new body
|
||||
else if (argc == 3 && !stricmp(cmd, "body"))
|
||||
{
|
||||
|
@ -911,6 +921,12 @@ void skel_generateragdoll_f(void)
|
|||
if (i == 0)
|
||||
VFS_PUTS(f, "//NO FRAME INFO\n");
|
||||
|
||||
VFS_PUTS(f, "\n//reference pose that offsets are defined in terms of\n");
|
||||
if (mod->type == mod_halflife)
|
||||
VFS_PUTS(f, "refpose 0 0.0 //use first anim's first pose\n");
|
||||
else
|
||||
VFS_PUTS(f, "refpose skin\n");
|
||||
|
||||
//print background frame info.
|
||||
VFS_PUTS(f, "\n//skins are as follows:\n");
|
||||
for (i = 0; i < 32768; i++)
|
||||
|
@ -1248,11 +1264,34 @@ static qboolean rag_instanciate(skelobject_t *sko, doll_t *doll, float *emat, we
|
|||
int bone;
|
||||
rbebody_t *body1, *body2;
|
||||
rbejointinfo_t *j;
|
||||
float *absolutes;
|
||||
sko->numbodies = doll->numbodies;
|
||||
sko->body = BZ_Malloc(sizeof(*sko->body) * sko->numbodies);
|
||||
sko->doll = doll;
|
||||
doll->uses++;
|
||||
sko->numanimated = 0;
|
||||
|
||||
if (bones && doll->refanim)
|
||||
{
|
||||
framestate_t fstate = {0};
|
||||
float *relatives = alloca(sizeof(float)*12*numbones*2);
|
||||
fstate.g[FS_REG].frame[0] = doll->refanim; //which anim we're using as the reference
|
||||
fstate.g[FS_REG].frametime[0] = doll->refanimtime; //first pose of the anim
|
||||
fstate.g[FS_REG].lerpweight[0] = 1;
|
||||
fstate.g[FS_REG].endbone = numbones;
|
||||
|
||||
absolutes = relatives+numbones*12;
|
||||
numbones = Mod_GetBoneRelations(sko->model, 0, numbones, bones, &fstate, relatives);
|
||||
for (i = 0; i < numbones; i++)
|
||||
{ //compute the absolutes. not gonna make a bg3 reference here.
|
||||
if (bones[i].parent>=0)
|
||||
R_ConcatTransforms((void*)(absolutes+12*bones[i].parent), (void*)(relatives+12*i), (void*)(absolutes+12*i));
|
||||
else
|
||||
memcpy(absolutes+12*i, relatives+12*i, sizeof(float)*12);
|
||||
}
|
||||
}
|
||||
else absolutes = NULL;
|
||||
|
||||
for (i = 0; i < sko->numbodies; i++)
|
||||
{
|
||||
memset(&sko->body[i], 0, sizeof(sko->body[i]));
|
||||
|
@ -1262,7 +1301,9 @@ static qboolean rag_instanciate(skelobject_t *sko, doll_t *doll, float *emat, we
|
|||
sko->numanimated++;
|
||||
|
||||
//spawn the body in the base pose, so we can add joints etc (also ignoring the entity matrix, we'll fix all that up later).
|
||||
if (1)
|
||||
if (absolutes) //we have a reference pose
|
||||
memcpy(bodymat, absolutes+12*doll->body[i].bone, sizeof(float)*12);
|
||||
else if (1)
|
||||
Matrix3x4_Invert_Simple(bones[doll->body[i].bone].inverse, bodymat);
|
||||
else
|
||||
rag_genbodymatrix(sko, &doll->body[i], emat, bodymat);
|
||||
|
@ -1281,8 +1322,10 @@ static qboolean rag_instanciate(skelobject_t *sko, doll_t *doll, float *emat, we
|
|||
bone = j->bonepivot;
|
||||
bmat = sko->bonematrix + bone*12;
|
||||
|
||||
if (1)
|
||||
{
|
||||
if (absolutes) //we have a reference pose
|
||||
memcpy(worldmat, absolutes+12*doll->body[i].bone, sizeof(float)*12);
|
||||
else if (1)
|
||||
{ //FIXME: j->offset isn't actually used?!?
|
||||
Matrix3x4_Invert_Simple(bones[j->bonepivot].inverse, worldmat);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -1160,6 +1160,9 @@ static int Alias_FindRawSkelData(galiasinfo_t *inf, const framestate_t *fstate,
|
|||
int endbone;
|
||||
int numbonegroups=0;
|
||||
|
||||
if (lastbone > inf->numbones)
|
||||
lastbone = inf->numbones;
|
||||
|
||||
for (bonegroup = 0; bonegroup < FS_COUNT; bonegroup++)
|
||||
{
|
||||
endbone = fstate->g[bonegroup].endbone;
|
||||
|
@ -1878,7 +1881,7 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, in
|
|||
else
|
||||
{
|
||||
if (meshcache.bonecachetype != SKEL_ABSOLUTE)
|
||||
meshcache.usebonepose = Alias_GetBoneInformation(inf, &e->framestate, meshcache.bonecachetype=SKEL_ABSOLUTE, meshcache.boneposebuffer1, meshcache.boneposebuffer2, MAX_BONES, NULL);
|
||||
meshcache.usebonepose = Alias_GetBoneInformation(inf, &e->framestate, meshcache.bonecachetype=SKEL_ABSOLUTE, meshcache.boneposebuffer1, meshcache.boneposebuffer2, inf->numbones, NULL);
|
||||
#ifndef SERVERONLY
|
||||
if (inf->shares_bones != surfnum && qrenderer)
|
||||
Alias_DrawSkeletalBones(inf->ofsbones, (const float *)meshcache.usebonepose, inf->numbones, e->framestate.g[0].endbone);
|
||||
|
@ -1888,7 +1891,7 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, in
|
|||
else
|
||||
{
|
||||
if (meshcache.bonecachetype != SKEL_INVERSE_ABSOLUTE)
|
||||
meshcache.usebonepose = Alias_GetBoneInformation(inf, &e->framestate, meshcache.bonecachetype=SKEL_INVERSE_ABSOLUTE, meshcache.boneposebuffer1, meshcache.boneposebuffer2, MAX_BONES, NULL);
|
||||
meshcache.usebonepose = Alias_GetBoneInformation(inf, &e->framestate, meshcache.bonecachetype=SKEL_INVERSE_ABSOLUTE, meshcache.boneposebuffer1, meshcache.boneposebuffer2, inf->numbones, NULL);
|
||||
|
||||
//hardware bone animation
|
||||
mesh->xyz_array = inf->ofs_skel_xyz;
|
||||
|
@ -2903,11 +2906,14 @@ typedef struct
|
|||
float fps;
|
||||
qboolean loop;
|
||||
int action;
|
||||
int actionweight;
|
||||
galiasevent_t *events;
|
||||
float actionweight;
|
||||
char name[MAX_QPATH];
|
||||
} frameinfo_t;
|
||||
static frameinfo_t *ParseFrameInfo(char *modelname, int *numgroups)
|
||||
static frameinfo_t *ParseFrameInfo(model_t *mod, int *numgroups)
|
||||
{
|
||||
const char *modelname = mod->name;
|
||||
|
||||
int count = 0;
|
||||
int maxcount = 0;
|
||||
char *line, *eol;
|
||||
|
@ -2917,11 +2923,84 @@ static frameinfo_t *ParseFrameInfo(char *modelname, int *numgroups)
|
|||
char tok[MAX_FRAMEINFO_POSES * 4];
|
||||
size_t fsize;
|
||||
com_tokentype_t ttype;
|
||||
json_t *rootjson;
|
||||
Q_snprintfz(fname, sizeof(fname), "%s.framegroups", modelname);
|
||||
line = file = FS_LoadMallocFile(fname, &fsize);
|
||||
if (!file)
|
||||
return NULL;
|
||||
while(line && *line)
|
||||
|
||||
rootjson = JSON_Parse(file); //must be a fully valid json file, so any space-separated tokens from the dp format will return NULL here just fine.
|
||||
if (rootjson)
|
||||
{
|
||||
json_t *framegroups = JSON_FindChild(rootjson, "framegroups");
|
||||
maxcount = JSON_GetCount(framegroups);
|
||||
frames = realloc(frames, sizeof(*frames)*maxcount);
|
||||
for(count = 0; count < maxcount; count++)
|
||||
{
|
||||
galiasevent_t *ev, **link;
|
||||
char eventdata[65536];
|
||||
unsigned int posecount;
|
||||
json_t *arr, *c;
|
||||
json_t *in = JSON_GetIndexed(framegroups, count);
|
||||
if (!in)
|
||||
break; //erk? shouldn't really happen. not an issue though.
|
||||
|
||||
frames[count].firstpose = JSON_GetInteger(in, "firstpose", 0);
|
||||
frames[count].posecount = JSON_GetInteger(in, "numposes", 1);
|
||||
frames[count].posesarray = false;
|
||||
arr = JSON_FindChild(in, "poses");
|
||||
if (arr)
|
||||
{ //override with explicit poses, if specified.
|
||||
for (posecount = 0; posecount < countof(frames[count].poses); posecount++)
|
||||
{
|
||||
c = JSON_GetIndexed(arr, posecount);
|
||||
if (!c) //ran out of elements...
|
||||
break;
|
||||
frames[count].poses[posecount] = JSON_GetUInteger(c, NULL, 0);
|
||||
}
|
||||
if (posecount>0)
|
||||
{
|
||||
frames[count].posecount = posecount;
|
||||
frames[count].posesarray = true;
|
||||
}
|
||||
}
|
||||
|
||||
frames[count].fps = JSON_GetFloat(in, "fps", 20);
|
||||
if (frames[count].fps <= 0)
|
||||
frames[count].fps = 10;
|
||||
frames[count].loop = JSON_GetUInteger(in, "loop", false);
|
||||
|
||||
Q_snprintfz(frames[count].name,sizeof(frames[count].name), "%s[%d]", fname, count);
|
||||
JSON_GetString(in, "name", frames[count].name, sizeof(frames[count].name), NULL);
|
||||
|
||||
frames[count].action = JSON_GetInteger(in, "action", -1);
|
||||
frames[count].actionweight = JSON_GetFloat(in, "actionweight", 0);
|
||||
frames[count].events = NULL;
|
||||
|
||||
arr = JSON_FindChild(in, "events");
|
||||
for (posecount = 0; (c=JSON_GetIndexed(arr, posecount))!=NULL; posecount++)
|
||||
{
|
||||
*eventdata = 0;
|
||||
JSON_GetString(c, "value", eventdata,sizeof(eventdata), NULL);
|
||||
ev = ZG_Malloc(&mod->memgroup, sizeof(*ev) + strlen(eventdata)+1);
|
||||
ev->code = JSON_GetInteger(c, "code", 0);
|
||||
ev->timestamp = JSON_GetFloat(c, "timestamp", JSON_GetFloat(c, "pose", 0)/frames[count].fps);
|
||||
ev->data = strcpy((char*)(ev+1), eventdata);
|
||||
|
||||
link = &frames[count].events;
|
||||
while (*link && (*link)->timestamp <= ev->timestamp)
|
||||
link = &(*link)->next;
|
||||
ev->next = *link;
|
||||
*link = ev;
|
||||
}
|
||||
}
|
||||
|
||||
mod->flags = JSON_GetUInteger(rootjson, "modelflags", mod->flags);
|
||||
|
||||
|
||||
JSON_Destroy(rootjson);
|
||||
}
|
||||
else while(line && *line)
|
||||
{
|
||||
unsigned int posecount = 0;
|
||||
|
||||
|
@ -2961,6 +3040,7 @@ static frameinfo_t *ParseFrameInfo(char *modelname, int *numgroups)
|
|||
else
|
||||
frames[count].loop = !!atoi(tok);
|
||||
|
||||
frames[count].events = NULL;
|
||||
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.
|
||||
|
@ -2990,6 +3070,11 @@ static frameinfo_t *ParseFrameInfo(char *modelname, int *numgroups)
|
|||
BZ_Free(file);
|
||||
|
||||
*numgroups = count;
|
||||
if (!count)
|
||||
{
|
||||
free(frames);
|
||||
frames = NULL;
|
||||
}
|
||||
return frames;
|
||||
}
|
||||
|
||||
|
@ -3985,10 +4070,10 @@ static void *Q1MDL_LoadSkins_GL (galiasinfo_t *galias, dmdl_t *pq1inmodel, model
|
|||
#endif
|
||||
|
||||
static void Mesh_HandleFramegroupsFile(model_t *mod, galiasinfo_t *galias)
|
||||
{
|
||||
{ //use ONLY with vertex models.
|
||||
unsigned int numanims, a, p, g, oldnumanims = galias->numanimations, targpose;
|
||||
galiasanimation_t *o, *oldanims = galias->ofsanimations, *frame;
|
||||
frameinfo_t *framegroups = ParseFrameInfo(mod->name, &numanims);
|
||||
frameinfo_t *framegroups = ParseFrameInfo(mod, &numanims);
|
||||
if (framegroups)
|
||||
{
|
||||
galias->ofsanimations = o = ZG_Malloc(&mod->memgroup, sizeof(*galias->ofsanimations) * numanims);
|
||||
|
@ -4014,8 +4099,9 @@ static void Mesh_HandleFramegroupsFile(model_t *mod, galiasinfo_t *galias)
|
|||
o->numposes = p;
|
||||
o->rate = framegroups[a].fps;
|
||||
o->loop = framegroups[a].loop;
|
||||
o->action = -1;
|
||||
o->actionweight = 0;
|
||||
o->events = framegroups[a].events;
|
||||
o->action = framegroups[a].action;
|
||||
o->actionweight = framegroups[a].actionweight;
|
||||
Q_strncpyz(o->name, framegroups[a].name, sizeof(o->name));
|
||||
}
|
||||
galias->numanimations = numanims;
|
||||
|
@ -5128,25 +5214,23 @@ int Mod_GetBoneRelations(model_t *model, int firstbone, int lastbone, const gali
|
|||
galiasbone_t *Mod_GetBoneInfo(model_t *model, int *numbones)
|
||||
{
|
||||
#ifdef SKELETALMODELS
|
||||
galiasbone_t *bone;
|
||||
galiasinfo_t *inf;
|
||||
|
||||
|
||||
if (!model || model->type != mod_alias)
|
||||
if (model && model->type == mod_alias)
|
||||
{
|
||||
*numbones = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inf = Mod_Extradata(model);
|
||||
|
||||
bone = inf->ofsbones;
|
||||
galiasinfo_t *inf = Mod_Extradata(model);
|
||||
*numbones = inf->numbones;
|
||||
return bone;
|
||||
#else
|
||||
return inf->ofsbones;
|
||||
}
|
||||
#endif
|
||||
#ifdef HALFLIFEMODELS
|
||||
if (model && model->type == mod_halflife)
|
||||
{
|
||||
hlmodel_t *hlmod = Mod_Extradata(model);
|
||||
*numbones = hlmod->header->numbones;
|
||||
return hlmod->compatbones;
|
||||
}
|
||||
#endif
|
||||
*numbones = 0;
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
int Mod_GetBoneParent(model_t *model, int bonenum)
|
||||
|
@ -6014,7 +6098,7 @@ static galiasinfo_t *Mod_LoadQ3ModelLod(model_t *mod, int *surfcount, void *buff
|
|||
externalskins = Mod_CountSkinFiles(mod);
|
||||
#endif
|
||||
|
||||
framegroups = ParseFrameInfo(mod->name, &numgroups);
|
||||
framegroups = ParseFrameInfo(mod, &numgroups);
|
||||
|
||||
ClearBounds(min, max);
|
||||
|
||||
|
@ -6087,46 +6171,6 @@ static galiasinfo_t *Mod_LoadQ3ModelLod(model_t *mod, int *surfcount, void *buff
|
|||
tvector = (vec3_t*)(svector + numverts*numposes);
|
||||
#endif
|
||||
|
||||
if (framegroups)
|
||||
{ //group the poses into animations.
|
||||
for (i = 0; i < numgroups; i++)
|
||||
{
|
||||
int first = framegroups[i].firstpose, count = framegroups[i].posecount;
|
||||
if (first >= numposes) //bound the numbers.
|
||||
first = numposes-1;
|
||||
if (first < 0)
|
||||
first = 0;
|
||||
if (count > numposes-first)
|
||||
count = numposes-first;
|
||||
if (count < 0)
|
||||
count = 0;
|
||||
Q_snprintfz(group->name, sizeof(group->name), "%s", framegroups[i].name);
|
||||
group->numposes = count;
|
||||
group->rate = framegroups[i].fps;
|
||||
group->poseofs = pose + first;
|
||||
group->loop = framegroups[i].loop;
|
||||
group->events = NULL;
|
||||
group->action = -1;
|
||||
group->actionweight = 0;
|
||||
group++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ //raw poses, no animations.
|
||||
for (i = 0; i < numgroups; i++)
|
||||
{
|
||||
Q_snprintfz(group->name, sizeof(group->name), "frame%i", i);
|
||||
group->numposes = 1;
|
||||
group->rate = 1;
|
||||
group->poseofs = pose + i;
|
||||
group->loop = false;
|
||||
group->events = NULL;
|
||||
group->action = -1;
|
||||
group->actionweight = 0;
|
||||
group++;
|
||||
}
|
||||
}
|
||||
|
||||
//load in that per-pose data
|
||||
invert = (md3XyzNormal_t *)((qbyte*)surf + LittleLong(surf->ofsXyzNormals));
|
||||
for (i = 0; i < numposes; i++)
|
||||
|
@ -6172,6 +6216,64 @@ static galiasinfo_t *Mod_LoadQ3ModelLod(model_t *mod, int *surfcount, void *buff
|
|||
#endif
|
||||
pose++;
|
||||
}
|
||||
pose -= numposes;
|
||||
|
||||
if (framegroups)
|
||||
{ //group the poses into animations.
|
||||
for (i = 0; i < numgroups; i++)
|
||||
{
|
||||
Q_snprintfz(group->name, sizeof(group->name), "%s", framegroups[i].name);
|
||||
|
||||
if (framegroups[i].posesarray)
|
||||
{
|
||||
unsigned int p, targpose;
|
||||
group->poseofs = ZG_Malloc(&mod->memgroup, sizeof(*group->poseofs) * framegroups[i].posecount);
|
||||
group->numposes = 0;
|
||||
for (p = 0; p < framegroups[i].posecount; p++)
|
||||
{
|
||||
targpose = framegroups[i].poses[p];
|
||||
if (targpose < numposes)
|
||||
group->poseofs[group->numposes++] = pose[targpose];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int first = framegroups[i].firstpose, count = framegroups[i].posecount;
|
||||
if (first >= numposes) //bound the numbers.
|
||||
first = numposes-1;
|
||||
if (first < 0)
|
||||
first = 0;
|
||||
if (count > numposes-first)
|
||||
count = numposes-first;
|
||||
if (count < 0)
|
||||
count = 0;
|
||||
group->poseofs = pose + first;
|
||||
group->numposes = count;
|
||||
}
|
||||
|
||||
group->rate = framegroups[i].fps;
|
||||
group->loop = framegroups[i].loop;
|
||||
group->events = framegroups[i].events;
|
||||
group->action = framegroups[i].action;
|
||||
group->actionweight = framegroups[i].actionweight;
|
||||
group++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ //raw poses, no animations.
|
||||
for (i = 0; i < numgroups; i++)
|
||||
{
|
||||
Q_snprintfz(group->name, sizeof(group->name), "frame%i", i);
|
||||
group->numposes = 1;
|
||||
group->rate = 1;
|
||||
group->poseofs = pose + i;
|
||||
group->loop = false;
|
||||
group->events = NULL;
|
||||
group->action = -1;
|
||||
group->actionweight = 0;
|
||||
group++;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SERVERONLY
|
||||
if (externalskins<LittleLong(surf->numShaders))
|
||||
|
@ -7160,7 +7262,7 @@ static qboolean QDECL Mod_LoadPSKModel(model_t *mod, void *buffer, size_t fsize)
|
|||
if (animinfo && animkeys)
|
||||
{
|
||||
int numgroups = 0;
|
||||
frameinfo_t *frameinfo = ParseFrameInfo(mod->name, &numgroups);
|
||||
frameinfo_t *frameinfo = ParseFrameInfo(mod, &numgroups);
|
||||
if (numgroups)
|
||||
{
|
||||
/*externally supplied listing of frames. ignore all framegroups in the model and use only the pose info*/
|
||||
|
@ -7169,6 +7271,8 @@ static qboolean QDECL Mod_LoadPSKModel(model_t *mod, void *buffer, size_t fsize)
|
|||
for (j = 0; j < numgroups; j++)
|
||||
{
|
||||
/*bound check*/
|
||||
if (frameinfo[j].posesarray)
|
||||
Con_Printf(CON_WARNING"Mod_LoadPSKModel(%s): framegroup[%i] poses array not suppported\n", mod->name, j);
|
||||
if (frameinfo[j].firstpose+frameinfo[j].posecount > num_animkeys)
|
||||
frameinfo[j].posecount = num_animkeys - frameinfo[j].firstpose;
|
||||
if (frameinfo[j].firstpose >= num_animkeys)
|
||||
|
@ -7186,8 +7290,9 @@ static qboolean QDECL Mod_LoadPSKModel(model_t *mod, void *buffer, size_t fsize)
|
|||
group[j].loop = frameinfo[j].loop;
|
||||
group[j].rate = frameinfo[j].fps;
|
||||
group[j].skeltype = SKEL_RELATIVE;
|
||||
group[j].action = -1;
|
||||
group[j].actionweight = 0;
|
||||
group[j].events = frameinfo[j].events;
|
||||
group[j].action = frameinfo[j].action;
|
||||
group[j].actionweight = frameinfo[j].actionweight;
|
||||
}
|
||||
num_animinfo = numgroups;
|
||||
}
|
||||
|
@ -7537,7 +7642,7 @@ static qboolean QDECL Mod_LoadDarkPlacesModel(model_t *mod, void *buffer, size_t
|
|||
//throw away the flags.
|
||||
}
|
||||
|
||||
framegroups = ParseFrameInfo(mod->name, &numgroups);
|
||||
framegroups = ParseFrameInfo(mod, &numgroups);
|
||||
if (!framegroups)
|
||||
{ //use the dpm's poses directly.
|
||||
numgroups = header->num_frames;
|
||||
|
@ -7596,14 +7701,16 @@ static qboolean QDECL Mod_LoadDarkPlacesModel(model_t *mod, void *buffer, size_t
|
|||
numposes = 0;
|
||||
if (firstpose + numposes > header->num_frames)
|
||||
numposes = header->num_frames - firstpose;
|
||||
if (framegroups[i].posesarray)
|
||||
Con_Printf(CON_WARNING"Mod_LoadDarkPlacesModel(%s): No support for explicit pose lists\n", mod->name);
|
||||
outgroups[i].skeltype = SKEL_RELATIVE;
|
||||
outgroups[i].boneofs = outposedata + firstpose*header->num_bones*12;
|
||||
outgroups[i].numposes = numposes;
|
||||
outgroups[i].loop = framegroups[i].loop;
|
||||
outgroups[i].rate = framegroups[i].fps;
|
||||
outgroups[i].events = NULL;
|
||||
outgroups[i].action = -1;
|
||||
outgroups[i].actionweight = 0;
|
||||
outgroups[i].events = framegroups[i].events;
|
||||
outgroups[i].action = framegroups[i].action;
|
||||
outgroups[i].actionweight = framegroups[i].actionweight;
|
||||
Q_strncpyz(outgroups[i].name, framegroups[i].name, sizeof(outgroups[i].name));
|
||||
}
|
||||
}
|
||||
|
@ -8406,7 +8513,7 @@ static galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, siz
|
|||
numgroups = 0;
|
||||
framegroups = NULL;
|
||||
if (!numgroups)
|
||||
framegroups = ParseFrameInfo(mod->name, &numgroups);
|
||||
framegroups = ParseFrameInfo(mod, &numgroups);
|
||||
if (!numgroups && h->num_anims)
|
||||
{
|
||||
/*use the model's framegroups*/
|
||||
|
@ -8421,6 +8528,7 @@ static galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, siz
|
|||
framegroups[i].posecount = LittleLong(anim[i].num_frames);
|
||||
framegroups[i].fps = LittleFloat(anim[i].framerate);
|
||||
framegroups[i].loop = !!(LittleLong(anim[i].flags) & IQM_LOOP);
|
||||
framegroups[i].events = NULL;
|
||||
framegroups[i].action = -1;
|
||||
framegroups[i].actionweight = 0;
|
||||
Q_strncpyz(framegroups[i].name, Mod_IQMString(&strings, anim[i].name), sizeof(fgroup[i].name));
|
||||
|
@ -8437,6 +8545,7 @@ static galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, siz
|
|||
framegroups->posecount = 1;
|
||||
framegroups->fps = 10;
|
||||
framegroups->loop = 1;
|
||||
framegroups->events = NULL;
|
||||
framegroups->action = -1;
|
||||
framegroups->actionweight = 0;
|
||||
strcpy(framegroups->name, "base");
|
||||
|
@ -8606,6 +8715,8 @@ static galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, siz
|
|||
//now generate the animations.
|
||||
for (i = 0; i < numgroups; i++)
|
||||
{
|
||||
if (framegroups[i].posesarray)
|
||||
Con_Printf(CON_WARNING"Mod_ParseIQMMeshModel(%s): framegroup[%i] poses array not suppported\n", mod->name, i);
|
||||
if (framegroups[i].firstpose + framegroups[i].posecount > h->num_frames)
|
||||
framegroups[i].posecount = h->num_frames - framegroups[i].firstpose;
|
||||
if (framegroups[i].firstpose >= h->num_frames)
|
||||
|
@ -8629,6 +8740,7 @@ static galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, siz
|
|||
if (fgroup[i].rate <= 0)
|
||||
fgroup[i].rate = 10;
|
||||
|
||||
fgroup[i].events = framegroups[i].events;
|
||||
fgroup[i].action = framegroups[i].action;
|
||||
fgroup[i].actionweight = framegroups[i].actionweight;
|
||||
}
|
||||
|
|
|
@ -371,6 +371,31 @@ qboolean QDECL Mod_LoadHLModel (model_t *mod, void *buffer, size_t fsize)
|
|||
model->bonectls = bonectls;
|
||||
|
||||
#ifndef SERVERONLY
|
||||
model->compatbones = ZG_Malloc(&mod->memgroup, header->numbones * sizeof(*model->compatbones));
|
||||
for (i = 0; i < header->numbones; i++)
|
||||
{
|
||||
float matrix[12];
|
||||
Q_strncpyz(model->compatbones[i].name, model->bones[i].name, sizeof(model->bones[i].name));
|
||||
model->compatbones[i].parent = model->bones[i].parent;
|
||||
model->compatbones[i].ref.org[0] = model->bones[i].value[0];
|
||||
model->compatbones[i].ref.org[1] = model->bones[i].value[1];
|
||||
model->compatbones[i].ref.org[2] = model->bones[i].value[2];
|
||||
QuaternionGLAngle(model->bones[i].value+3, model->compatbones[i].ref.quat);
|
||||
model->compatbones[i].ref.scale[0] = 1.0f;
|
||||
model->compatbones[i].ref.scale[1] = 1.0f;
|
||||
model->compatbones[i].ref.scale[2] = 1.0f;
|
||||
|
||||
//compute rel matrix
|
||||
GenMatrixPosQuat4Scale(model->compatbones[i].ref.org, model->compatbones[i].ref.quat, model->compatbones[i].ref.scale, matrix);
|
||||
//compute abs matrix.
|
||||
if(model->bones[i].parent>=0)
|
||||
R_ConcatTransforms((void*)transform_matrix[model->bones[i].parent], (void*)matrix, transform_matrix[i]);
|
||||
else
|
||||
memcpy(transform_matrix[i], matrix, 12 * sizeof(float));
|
||||
//keep the ragdoll code happy with its insistance on using inverses.
|
||||
Matrix3x4_Invert_Simple((const float*)transform_matrix[i], model->compatbones[i].inverse);
|
||||
}
|
||||
|
||||
tex = (hlmdl_tex_t *) ((qbyte *) texheader + texheader->textures);
|
||||
|
||||
shaders = ZG_Malloc(&mod->memgroup, texheader->numtextures*sizeof(shader_t));
|
||||
|
@ -1192,7 +1217,7 @@ static int HLMDL_GetBoneData_Internal(hlmodel_t *model, int firstbone, int lastb
|
|||
lastbone = model->header->numbones;
|
||||
if (cbone >= lastbone)
|
||||
continue;
|
||||
HL_SetupBones(model, fstate->g[bgroup].frame[0], cbone, lastbone, fstate->g[bgroup].subblendfrac, fstate->g[bgroup].subblend2frac, fstate->g[bgroup].frametime[0], result); /* Setup the bones */
|
||||
HL_SetupBones(model, fstate->g[bgroup].frame[0] & ~0x8000, cbone, lastbone, fstate->g[bgroup].subblendfrac, fstate->g[bgroup].subblend2frac, fstate->g[bgroup].frametime[0], result); /* Setup the bones */
|
||||
cbone = lastbone;
|
||||
}
|
||||
return cbone;
|
||||
|
|
|
@ -1031,9 +1031,10 @@ void Mod_ModelLoaded(void *ctx, void *data, size_t a, size_t b)
|
|||
{
|
||||
if (qrenderer != QR_NONE)
|
||||
Mod_LoadAliasShaders(mod);
|
||||
|
||||
}
|
||||
|
||||
#ifdef RAGDOLL
|
||||
if (mod->type == mod_alias || mod->type == mod_halflife)
|
||||
{
|
||||
int numbones = Mod_GetNumBones(mod, false);
|
||||
if (numbones)
|
||||
|
@ -1051,7 +1052,7 @@ void Mod_ModelLoaded(void *ctx, void *data, size_t a, size_t b)
|
|||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
switch(verbose)
|
||||
|
|
|
@ -4349,6 +4349,8 @@ qboolean Shader_Init (void)
|
|||
#ifdef FTE_TARGET_WEB
|
||||
sh_config.max_gpu_bones = 0; //webgl tends to crap out if this is too high, so 32 is a good enough value to play safe. some browsers have really shitty uniform performance too, so lets just default to pure-cpu transforms. in javascript. yes, its that bad.
|
||||
#else
|
||||
//some of our APIs will set their own guesses from queries. don't stomp on that.
|
||||
if (!sh_config.max_gpu_bones)
|
||||
sh_config.max_gpu_bones = 64; //ATI drivers bug out and start to crash if you put this at 128.
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -1541,7 +1541,7 @@ static const char *glsl_hdrs[] =
|
|||
"float e_time;"
|
||||
"};\n"
|
||||
"#ifdef SKELETAL\n"
|
||||
"layout(std140) unform u_bones\n"
|
||||
"layout(std140) uniform u_bones\n"
|
||||
"{\n"
|
||||
"#ifdef PACKEDBONES\n"
|
||||
"vec4 m_bones_packed[3*MAX_GPU_BONES];\n"
|
||||
|
@ -1648,7 +1648,7 @@ static const char *glsl_hdrs[] =
|
|||
"wmat[2] += m_bones_packed[2+3*int(v_bone.y)] * v_weight.y;"
|
||||
"wmat[2] += m_bones_packed[2+3*int(v_bone.z)] * v_weight.z;"
|
||||
"wmat[2] += m_bones_packed[2+3*int(v_bone.w)] * v_weight.w;"
|
||||
"wmat[3] = vec4(0.0,0.0,0.0,1.0);\n"
|
||||
"wmat[3] = vec4(0.0,0.0,0.0,1.0);"
|
||||
"return m_modelviewprojection * (vec4(v_position.xyz, 1.0) * wmat);"
|
||||
"}\n"
|
||||
"vec4 skeletaltransform_nst(out vec3 n, out vec3 t, out vec3 b)"
|
||||
|
@ -3664,6 +3664,21 @@ qboolean GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name))
|
|||
sh_config.progs_supported = gl_config.arb_shader_objects;
|
||||
sh_config.progs_required = gl_config_nofixedfunc;
|
||||
|
||||
if (gl_config.glversion >= 4.1)
|
||||
{
|
||||
GLint maxuniformvecs = 256; //minimum value... or 128 on webgl1(grr)
|
||||
if (gl_config.glversion >= 4.1)
|
||||
qglGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &maxuniformvecs);
|
||||
else if (gl_config.glversion >= 2.0)
|
||||
{
|
||||
qglGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &maxuniformvecs); //at least 1024, supposedly.
|
||||
maxuniformvecs /= 4;
|
||||
}
|
||||
|
||||
sh_config.max_gpu_bones = (maxuniformvecs-64)/3; //we don't know how many we're actually going to use for any specific bit of glsl, so make a generous guess and throw in a bit more for drivers that lie. we need 3 per bone matrix.
|
||||
sh_config.max_gpu_bones = bound(0, sh_config.max_gpu_bones, MAX_BONES); //o.O
|
||||
}
|
||||
|
||||
if (sh_config.progs_supported)
|
||||
{
|
||||
sh_config.pDeleteProg = GLSlang_DeleteProg;
|
||||
|
|
|
@ -582,7 +582,7 @@ static qboolean EGLHeadless_Init (rendererstate_t *info, unsigned char *palette)
|
|||
|
||||
if (GL_Init(info, &EGL_Proc))
|
||||
return true;
|
||||
Con_Printf(CON_ERROR "Unable to initialise opengl-on-wayland.\n");
|
||||
Con_Printf(CON_ERROR "Unable to initialise egl_headless.\n");
|
||||
return false;
|
||||
}
|
||||
static void EGLHeadless_DeInit(void)
|
||||
|
|
|
@ -349,9 +349,12 @@ typedef void (APIENTRY * PFNGLACTIVESTENCILFACEEXTPROC) (GLenum face);
|
|||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef GL_VERSION_4_1
|
||||
#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB
|
||||
#endif
|
||||
#ifndef GL_VERSION_2_0
|
||||
#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef GL_ARB_vertex_program
|
||||
|
|
|
@ -298,6 +298,7 @@ typedef struct //this is stored as the cache. an hlmodel_t is generated when dra
|
|||
|
||||
hlmdl_header_t *header;
|
||||
hlmdl_bone_t *bones;
|
||||
struct galiasbone_s *compatbones;
|
||||
hlmdl_bonecontroller_t *bonectls;
|
||||
hlmdl_sequencefile_t *animcache[MAX_ANIM_GROUPS];
|
||||
zonegroup_t *memgroup;
|
||||
|
|
|
@ -2898,6 +2898,8 @@ static float *QDECL GLTF_AnimateBones(const galiasinfo_t *surf, const galiasanim
|
|||
int j = 0, l;
|
||||
const struct galiasanimation_gltf_s *a = anim->boneofs;
|
||||
|
||||
numbones = min(numbones, surf->numbones); //if you're asking for more bones, then expect bugs.
|
||||
|
||||
if (anim->loop && time >= a->duration)
|
||||
time = time - a->duration*floor(time/a->duration);
|
||||
|
||||
|
|
Loading…
Reference in a new issue