1
0
Fork 0
forked from fte/fteqw

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:
Shpoike 2024-11-07 20:01:50 +00:00
parent 28a880c56e
commit 9bc9700506
11 changed files with 333 additions and 113 deletions

View file

@ -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;

View file

@ -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,7 +921,13 @@ void skel_generateragdoll_f(void)
if (i == 0)
VFS_PUTS(f, "//NO FRAME INFO\n");
//print background frame info.
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

View file

@ -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;
galiasinfo_t *inf = Mod_Extradata(model);
*numbones = inf->numbones;
return inf->ofsbones;
}
inf = Mod_Extradata(model);
bone = inf->ofsbones;
*numbones = inf->numbones;
return bone;
#else
#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;
}

View file

@ -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;

View file

@ -1031,27 +1031,28 @@ 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)
{
int numbones = Mod_GetNumBones(mod, false);
if (numbones)
size_t filesize;
char *buf;
char dollname[MAX_QPATH];
Q_snprintfz(dollname, sizeof(dollname), "%s.doll", mod->name);
buf = FS_LoadMallocFile(dollname, &filesize);
if (buf)
{
size_t filesize;
char *buf;
char dollname[MAX_QPATH];
Q_snprintfz(dollname, sizeof(dollname), "%s.doll", mod->name);
buf = FS_LoadMallocFile(dollname, &filesize);
if (buf)
{
mod->dollinfo = rag_createdollfromstring(mod, dollname, numbones, buf);
BZ_Free(buf);
}
mod->dollinfo = rag_createdollfromstring(mod, dollname, numbones, buf);
BZ_Free(buf);
}
}
#endif
}
#endif
#endif
switch(verbose)

View file

@ -4349,7 +4349,9 @@ 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
sh_config.max_gpu_bones = 64; //ATI drivers bug out and start to crash if you put this at 128.
//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
}
else

View file

@ -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;

View file

@ -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)

View file

@ -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

View file

@ -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;

View file

@ -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);