first attempt at webvr support. probably totally crap.

fix hitmodel with skeletal models(can also now support lerps, skeletal objects, etc).
more hlmdl fixes for eukara, including hitboxes.
modelviewer can now display bones.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5033 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2016-12-19 13:31:05 +00:00
parent ebd1f75634
commit 03d96bff72
27 changed files with 961 additions and 267 deletions

View File

@ -565,7 +565,6 @@ D3DGL_OBJS = \
gl_shader.o \
gl_shadow.o \
gl_rlight.o \
gl_hlmdl.o \
gl_warp.o \
ltface.o \
r_surf.o \
@ -655,6 +654,7 @@ WINDOWS_OBJS = \
COMMON_OBJS = \
gl_alias.o \
gl_hlmdl.o \
gl_heightmap.o \
gl_model.o \
com_mesh.o \

View File

@ -5257,6 +5257,10 @@ double Host_Frame (double time)
scr_chatmode = 0;
r_refdef.stereomethod = r_stereo_method.ival;
#ifdef FTE_TARGET_WEB
if (emscriptenfte_getvrframedata())
r_refdef.stereomethod = STEREO_WEBVR;
#endif
CL_UpdateHeadAngles();
{

View File

@ -2759,11 +2759,13 @@ typedef struct
MV_NONE,
MV_BONES,
MV_SHADER,
MV_TEXTURE
MV_TEXTURE,
MV_COLLISION
} mode;
int surfaceidx;
int skingroup;
int framegroup;
int boneidx;
double framechangetime;
double skinchangetime;
float pitch;
@ -2805,7 +2807,7 @@ static unsigned int genhsv(float h_, float s, float v)
#include "com_mesh.h"
#ifdef SKELETALMODELS
static void M_BoneDisplayLame(entity_t *e, int *y, int depth, int parent, int first, int last)
static void M_BoneDisplayLame(entity_t *e, int *y, int depth, int parent, int first, int last, int sel)
{
int i;
for (i = first; i < last; i++)
@ -2819,11 +2821,17 @@ static void M_BoneDisplayLame(entity_t *e, int *y, int depth, int parent, int fi
bname = "NULL";
memset(result, 0, sizeof(result));
if (Mod_GetTag(e->model, i+1, &e->framestate, result))
Draw_FunString(depth*16, *y, va("%i: %s (%g %g %g)", i, bname, result[3], result[7], result[11]));
{
#if 0//def _DEBUG
Draw_FunString(depth*16, *y, va("%s%i: %s (%g %g %g)", (i==sel)?"^1":"", i, bname, result[3], result[7], result[11]));
#else
Draw_FunString(depth*16, *y, va("%s%i: %s", (i==sel)?"^1":"", i, bname));
#endif
}
else
Draw_FunString(depth*16, *y, va("%i: %s", i, bname));
Draw_FunString(depth*16, *y, va("%s%i: %s (err)", (i==sel)?"^1":"", i, bname));
*y += 8;
M_BoneDisplayLame(e, y, depth+1, i+1, i+1, last);
M_BoneDisplayLame(e, y, depth+1, i+1, i+1, last, sel);
}
}
}
@ -2893,33 +2901,166 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_
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].endbone = 0x7fffffff;
ent.customskin = Mod_RegisterSkinFile(va("%s_0.skin", mods->modelname));
// ent.framestate.bonecount = Mod_GetNumBones(ent.model, false);
// ent.framestate.bonestate = bones;
// ent.framestate.bonecount = Mod_GetBoneRelations(ent.model, 0, MAX_BONES, &ent.framestate, ent.framestate.bonestate);
// ent.framestate.skeltype = SKEL_RELATIVE;
ent.light_avg[0] = ent.light_avg[1] = ent.light_avg[2] = 0.66;
ent.light_range[0] = ent.light_range[1] = ent.light_range[2] = 0.33;
ent.light_dir[0] = 0; ent.light_dir[1] = 1; ent.light_dir[2] = 0;
ent.light_known = 2;
// ent.angles[0]*=-1;
AngleVectors(ent.angles, ent.axis[0], ent.axis[1], ent.axis[2]);
VectorInverse(ent.axis[1]);
// ent.angles[0]*=-1;
if (ent.model->type == mod_dummy)
{
Draw_FunString(0, 0, va("model \"%s\" not loaded", ent.model->name));
return;
}
switch(ent.model->loadstate)
{
case MLS_LOADED:
break;
case MLS_NOTLOADED:
Draw_FunString(0, 0, va("%s not loaded", ent.model->name));
Draw_FunString(0, 0, va("\"%s\" not loaded", ent.model->name));
return;
case MLS_LOADING:
Draw_FunString(0, 0, va("%s still loading", ent.model->name));
Draw_FunString(0, 0, va("\"%s\" still loading", ent.model->name));
return;
case MLS_FAILED:
Draw_FunString(0, 0, va("Unable to load %s", ent.model->name));
Draw_FunString(0, 0, va("Unable to load \"%s\"", ent.model->name));
return;
}
#if 0
ent.framestate.bonestate = bones;
ent.framestate.bonecount = Mod_GetBoneRelations(ent.model, 0, MAX_BONES, &ent.framestate, ent.framestate.bonestate);
ent.framestate.skeltype = SKEL_RELATIVE;
#endif
if (mods->mode == MV_COLLISION)
{
shader_t *s = R_RegisterShader("bboxshader_nodepth", SUF_NONE,
"{\n"
"polygonoffset\n"
"{\n"
"map $whiteimage\n"
"blendfunc gl_src_alpha gl_one\n"
"rgbgen vertex\n"
"alphagen vertex\n"
"nodepthtest\n"
"}\n"
"}\n");
#ifdef HALFLIFEMODELS
if (ent.model->type == mod_halflife)
HLMDL_DrawHitBoxes(&ent);
else
#endif
{
vec3_t mins, maxs;
VectorAdd(ent.model->mins, ent.origin, mins);
VectorAdd(ent.model->maxs, ent.origin, maxs);
CLQ1_AddOrientedCube(s, mins, maxs, NULL, 1, 1, 1, 0.2);
}
#ifdef _DEBUG
{
trace_t tr;
vec3_t v1, v2;
VectorSet(v1, 1000*sin(realtime*2*M_PI/180), 1000*cos(realtime*2*M_PI/180), -ent.origin[2]);
VectorScale(v1, -1, v2);
v2[2] = v1[2];
s = R_RegisterShader("bboxshader", SUF_NONE,
"{\n"
"polygonoffset\n"
"{\n"
"map $whiteimage\n"
"blendfunc gl_src_alpha gl_one\n"
"rgbgen vertex\n"
"alphagen vertex\n"
"}\n"
"}\n");
if (ent.model->funcs.NativeTrace(ent.model, 0, &ent.framestate, NULL, v1, v2, vec3_origin, vec3_origin, false, ~0, &tr))
{
vec3_t dir;
float f;
VectorAdd(v1, ent.origin, v1);
VectorAdd(v2, ent.origin, v2);
VectorAdd(tr.endpos, ent.origin, tr.endpos);
VectorSubtract(tr.endpos, v1, dir);
f = DotProduct(dir, tr.plane.normal) * -2;
VectorMA(dir, f, tr.plane.normal, v2);
VectorAdd(v2, tr.endpos, v2);
CLQ1_DrawLine(s, v1, tr.endpos, 0, 1, 0, 1);
CLQ1_DrawLine(s, tr.endpos, v2, 1, 0, 0, 1);
}
else
{
VectorAdd(v1, ent.origin, v1);
VectorAdd(v2, ent.origin, v2);
CLQ1_DrawLine(s, v1, v2, 0, 1, 0, 1);
}
}
#endif
}
if (mods->mode == MV_BONES)
{
shader_t *lineshader;
int tags = Mod_GetNumBones(ent.model, true);
int b;
//if (ragdoll)
// ent->frame[] |= 0x8000;
//rag_updatedeltaent(&ent, le);
lineshader = R_RegisterShader("lineshader_nodepth", SUF_NONE,
"{\n"
"polygonoffset\n"
"{\n"
"map $whiteimage\n"
"blendfunc add\n"
"rgbgen vertex\n"
"alphagen vertex\n"
"nodepthtest\n"
"}\n"
"}\n");
for (b = 1; b <= tags; b++)
{
int p = Mod_GetBoneParent(ent.model, b);
vec3_t start, end;
float boneinfo[12];
Mod_GetTag(ent.model, b, &ent.framestate, boneinfo);
VectorSet(start, boneinfo[3], boneinfo[7], boneinfo[11]);
VectorAdd(start, ent.origin, start);
if (p)
{
Mod_GetTag(ent.model, p, &ent.framestate, boneinfo);
VectorSet(end, boneinfo[3], boneinfo[7], boneinfo[11]);
VectorAdd(end, ent.origin, end);
CLQ1_DrawLine(lineshader, start, end, 1, (b-1 == mods->boneidx)?0:1, 1, 1);
}
if (b-1 == mods->boneidx)
{
VectorSet(end, start[0]+1, start[1], start[2]);
CLQ1_DrawLine(lineshader, start, end, 1, 0, 0, 1);
VectorSet(end, start[0], start[1]+1, start[2]);
CLQ1_DrawLine(lineshader, start, end, 0, 1, 0, 1);
VectorSet(end, start[0], start[1], start[2]+1);
CLQ1_DrawLine(lineshader, start, end, 0, 0, 1, 1);
}
}
}
V_AddEntity(&ent);
V_ApplyRefdef();
@ -2966,15 +3107,24 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_
"mins: %g %g %g, maxs: %g %g %g\n", ent.model->mins[0], ent.model->mins[1], ent.model->mins[2], ent.model->maxs[0], ent.model->maxs[1], ent.model->maxs[2])
, CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN, font_default, fs);
break;
case MV_COLLISION:
if (ent.model->type != mod_halflife)
{
R_DrawTextField(r_refdef.grect.x, r_refdef.grect.y+y, r_refdef.grect.width, r_refdef.grect.height-y,
va("mins: %g %g %g, maxs: %g %g %g\n", ent.model->mins[0], ent.model->mins[1], ent.model->mins[2], ent.model->maxs[0], ent.model->maxs[1], ent.model->maxs[2])
, CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN, font_default, fs);
break;
}
//fallthrough
case MV_BONES:
#ifdef SKELETALMODELS
{
int bonecount = Mod_GetNumBones(ent.model, false);
int bonecount = Mod_GetNumBones(ent.model, true);
if (bonecount)
{
Draw_FunString(0, y, va("Bones: "));
y+=8;
M_BoneDisplayLame(&ent, &y, 0, 0, 0, bonecount);
M_BoneDisplayLame(&ent, &y, 0, 0, 0, bonecount, mods->boneidx);
}
else
R_DrawTextField(r_refdef.grect.x, r_refdef.grect.y+y, r_refdef.grect.width, r_refdef.grect.height-y, "No bones in model", CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN, font_default, fs);
@ -3030,10 +3180,11 @@ static qboolean M_ModelViewerKey(struct menucustom_s *c, struct menu_s *m, int k
mods->shadertext = NULL;
switch (mods->mode)
{
case MV_NONE: mods->mode = MV_BONES; break;
case MV_BONES: mods->mode = MV_SHADER; break;
case MV_SHADER: mods->mode = MV_TEXTURE;break;
case MV_TEXTURE: mods->mode = MV_NONE; break;
case MV_NONE: mods->mode = MV_BONES; break;
case MV_BONES: mods->mode = MV_SHADER; break;
case MV_SHADER: mods->mode = MV_TEXTURE; break;
case MV_TEXTURE: mods->mode = MV_COLLISION; break;
case MV_COLLISION: mods->mode = MV_NONE; break;
}
}
else if (key == 'r')
@ -3041,6 +3192,10 @@ static qboolean M_ModelViewerKey(struct menucustom_s *c, struct menu_s *m, int k
mods->framechangetime = realtime;
mods->skinchangetime = realtime;
}
else if (key == '[')
mods->boneidx--;
else if (key == ']')
mods->boneidx++;
else if (key == K_UPARROW)
mods->pitch += 5;
else if (key == K_DOWNARROW)

View File

@ -973,7 +973,7 @@ return;
D3_RecursiveSurfCheck (node->child[side^1], midf, p2f, mid, p2);
}
static qboolean D3_Trace (struct model_s *model, int hulloverride, int frame, vec3_t axis[3], vec3_t p1, vec3_t p2, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int hitcontentsmask, struct trace_s *trace)
static qboolean D3_Trace (struct model_s *model, int hulloverride, framestate_t *framestate, vec3_t axis[3], vec3_t p1, vec3_t p2, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int hitcontentsmask, struct trace_s *trace)
{
int i;
float e1,e2;

View File

@ -845,7 +845,7 @@ entity_t *TraceLineR (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal)
VectorSubtract(start, pe->origin, ts);
VectorSubtract(end, pe->origin, te);
pe->model->funcs.NativeTrace(pe->model, 0, pe->framestate.g[FS_REG].frame[pe->framestate.g[FS_REG].lerpweight[1] > pe->framestate.g[FS_REG].lerpweight[0]], pe->axis, ts, te, vec3_origin, vec3_origin, false, MASK_WORLDSOLID, &trace);
pe->model->funcs.NativeTrace(pe->model, 0, &pe->framestate, pe->axis, ts, te, vec3_origin, vec3_origin, false, MASK_WORLDSOLID, &trace);
if (trace.fraction<1)
{
VectorSubtract(trace.endpos, ts, delta);

View File

@ -215,6 +215,10 @@ typedef enum {
STEREO_RED_GREEN,
STEREO_CROSSEYED,
#ifdef FTE_TARGET_WEB
STEREO_WEBVR,
#endif
//these are internal methods and do not form part of any public API
STEREO_LEFTONLY,
STEREO_RIGHTONLY

View File

@ -1178,6 +1178,10 @@ void V_ApplyAFov(playerview_t *pv)
afov = bound(0.001, afov, 170);
ws = 1;
#ifdef FTE_TARGET_WEB
if (r_refdef.stereomethod == STEREO_WEBVR)
ws = 0.5;
#endif
if (r_refdef.stereomethod == STEREO_CROSSEYED && r_stereo_separation.value)
ws = 0.5;

View File

@ -460,7 +460,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#undef Q2CLIENT
#undef Q3CLIENT
#undef HLCLIENT
#undef HALFLIFEMODELS
#undef VM_UI
#undef VM_CG
#undef TEXTEDITOR

View File

@ -335,39 +335,76 @@ static void PSKGenMatrix(float x, float y, float z, float qx, float qy, float qz
/*transforms some skeletal vecV_t values*/
static void Alias_TransformVerticies_V(const float *bonepose, int vertcount, qbyte *bidx, float *weights, float *xyzin, float *fte_restrict xyzout)
{
int i;
const float *matrix;
for (i = 0; i < vertcount; i++, xyzout+=sizeof(vecV_t)/sizeof(vec_t), xyzin+=sizeof(vecV_t)/sizeof(vec_t), bidx+=4, weights+=4)
#if 1
int i, j;
const float *matrix, *matrix1;
float mat[12];
for (i = 0; i < vertcount; i++, bidx+=4, weights+=4)
{
matrix = &bonepose[12*bidx[0]];
xyzout[0] = weights[0] * (xyzin[0] * matrix[0] + xyzin[1] * matrix[1] + xyzin[2] * matrix[ 2] + xyzin[3] * matrix[ 3]);
xyzout[1] = weights[0] * (xyzin[0] * matrix[4] + xyzin[1] * matrix[5] + xyzin[2] * matrix[ 6] + xyzin[3] * matrix[ 7]);
xyzout[2] = weights[0] * (xyzin[0] * matrix[8] + xyzin[1] * matrix[9] + xyzin[2] * matrix[10] + xyzin[3] * matrix[11]);
if (weights[1])
{
matrix1 = &bonepose[12*bidx[1]];
for (j = 0; j < 12; j++)
mat[j] = (weights[0] * matrix[j]) + (weights[1] * matrix1[j]);
if (weights[2])
{
matrix = &bonepose[12*bidx[2]];
for (j = 0; j < 12; j++)
mat[j] += weights[2] * matrix[j];
if (weights[3])
{
matrix = &bonepose[12*bidx[3]];
for (j = 0; j < 12; j++)
mat[j] += weights[3] * matrix[j];
}
}
matrix = mat;
}
xyzout[0] = (xyzin[0] * matrix[0] + xyzin[1] * matrix[1] + xyzin[2] * matrix[ 2] + matrix[ 3]);
xyzout[1] = (xyzin[0] * matrix[4] + xyzin[1] * matrix[5] + xyzin[2] * matrix[ 6] + matrix[ 7]);
xyzout[2] = (xyzin[0] * matrix[8] + xyzin[1] * matrix[9] + xyzin[2] * matrix[10] + matrix[11]);
xyzout+=sizeof(vecV_t)/sizeof(vec_t);
xyzin+=sizeof(vecV_t)/sizeof(vec_t);
}
#else
int i;
const float *matrix;
for (i = 0; i < vertcount; i++, bidx+=4, weights+=4)
{
matrix = &bonepose[12*bidx[0]];
xyzout[0] = weights[0] * (xyzin[0] * matrix[0] + xyzin[1] * matrix[1] + xyzin[2] * matrix[ 2] + matrix[ 3]);
xyzout[1] = weights[0] * (xyzin[0] * matrix[4] + xyzin[1] * matrix[5] + xyzin[2] * matrix[ 6] + matrix[ 7]);
xyzout[2] = weights[0] * (xyzin[0] * matrix[8] + xyzin[1] * matrix[9] + xyzin[2] * matrix[10] + matrix[11]);
if (weights[1])
{
matrix = &bonepose[12*bidx[1]];
xyzout[0] += weights[1] * (xyzin[0] * matrix[0] + xyzin[1] * matrix[1] + xyzin[2] * matrix[ 2] + xyzin[3] * matrix[ 3]);
xyzout[1] += weights[1] * (xyzin[0] * matrix[4] + xyzin[1] * matrix[5] + xyzin[2] * matrix[ 6] + xyzin[3] * matrix[ 7]);
xyzout[2] += weights[1] * (xyzin[0] * matrix[8] + xyzin[1] * matrix[9] + xyzin[2] * matrix[10] + xyzin[3] * matrix[11]);
xyzout[0] += weights[1] * (xyzin[0] * matrix[0] + xyzin[1] * matrix[1] + xyzin[2] * matrix[ 2] + matrix[ 3]);
xyzout[1] += weights[1] * (xyzin[0] * matrix[4] + xyzin[1] * matrix[5] + xyzin[2] * matrix[ 6] + matrix[ 7]);
xyzout[2] += weights[1] * (xyzin[0] * matrix[8] + xyzin[1] * matrix[9] + xyzin[2] * matrix[10] + matrix[11]);
if (weights[2])
{
matrix = &bonepose[12*bidx[2]];
xyzout[0] += weights[2] * (xyzin[0] * matrix[0] + xyzin[1] * matrix[1] + xyzin[2] * matrix[ 2] + xyzin[3] * matrix[ 3]);
xyzout[1] += weights[2] * (xyzin[0] * matrix[4] + xyzin[1] * matrix[5] + xyzin[2] * matrix[ 6] + xyzin[3] * matrix[ 7]);
xyzout[2] += weights[2] * (xyzin[0] * matrix[8] + xyzin[1] * matrix[9] + xyzin[2] * matrix[10] + xyzin[3] * matrix[11]);
xyzout[0] += weights[2] * (xyzin[0] * matrix[0] + xyzin[1] * matrix[1] + xyzin[2] * matrix[ 2] + matrix[ 3]);
xyzout[1] += weights[2] * (xyzin[0] * matrix[4] + xyzin[1] * matrix[5] + xyzin[2] * matrix[ 6] + matrix[ 7]);
xyzout[2] += weights[2] * (xyzin[0] * matrix[8] + xyzin[1] * matrix[9] + xyzin[2] * matrix[10] + matrix[11]);
if (weights[3])
{
matrix = &bonepose[12*bidx[3]];
xyzout[0] += weights[3] * (xyzin[0] * matrix[0] + xyzin[1] * matrix[1] + xyzin[2] * matrix[ 2] + xyzin[3] * matrix[ 3]);
xyzout[1] += weights[3] * (xyzin[0] * matrix[4] + xyzin[1] * matrix[5] + xyzin[2] * matrix[ 6] + xyzin[3] * matrix[ 7]);
xyzout[2] += weights[3] * (xyzin[0] * matrix[8] + xyzin[1] * matrix[9] + xyzin[2] * matrix[10] + xyzin[3] * matrix[11]);
xyzout[0] += weights[3] * (xyzin[0] * matrix[0] + xyzin[1] * matrix[1] + xyzin[2] * matrix[ 2] + matrix[ 3]);
xyzout[1] += weights[3] * (xyzin[0] * matrix[4] + xyzin[1] * matrix[5] + xyzin[2] * matrix[ 6] + matrix[ 7]);
xyzout[2] += weights[3] * (xyzin[0] * matrix[8] + xyzin[1] * matrix[9] + xyzin[2] * matrix[10] + matrix[11]);
}
}
}
xyzout+=sizeof(vecV_t)/sizeof(vec_t);
xyzin+=sizeof(vecV_t)/sizeof(vec_t);
}
#endif
}
/*transforms some skeletal vecV_t values*/
@ -1214,16 +1251,15 @@ static void Alias_BuildSkeletalMesh(mesh_t *mesh, framestate_t *framestate, gali
);
}
static void Alias_BuildSkeletalVPositionsPose(float *xyzout, skeltype_t bonetype, const float *bonepose, galiasinfo_t *inf)
static void Alias_BuildSkeletalVerts(float *xyzout, framestate_t *framestate, galiasinfo_t *inf)
{
float buffer[MAX_BONES*12];
float bufferalt[MAX_BONES*12];
qbyte *fte_restrict bidx = inf->ofs_skel_idx[0];
float *fte_restrict xyzin = inf->ofs_skel_xyz[0];
float *fte_restrict weight = inf->ofs_skel_weight[0];
bonepose = Alias_ConvertBoneData(bonetype, bonepose, inf->numbones, inf->ofsbones, SKEL_INVERSE_ABSOLUTE, buffer, bufferalt, MAX_BONES);
const float *bonepose = Alias_GetBoneInformation(inf, framestate, SKEL_INVERSE_ABSOLUTE, buffer, bufferalt, MAX_BONES);
Alias_TransformVerticies_V(bonepose, inf->numverts, bidx, weight, xyzin, xyzout);
Alias_TransformVerticies_V(bonepose, inf->numverts, bidx, weight, inf->ofs_skel_xyz[0], xyzout);
}
#if defined(MD5MODELS) || defined(ZYMOTICMODELS) || defined(DPMMODELS)
@ -1908,21 +1944,34 @@ qboolean Mod_Trace_Trisoup(vecV_t *posedata, index_t *indexes, int numindexes, v
float frac;
vec3_t impactpoint;
// shader_t *lineshader = NULL;
for (i = 0; i < numindexes; i+=3)
{
p1 = posedata[indexes[i+0]];
p2 = posedata[indexes[i+1]];
p3 = posedata[indexes[i+2]];
/*
VectorAdd(p1, r_refdef.pvsorigin, edge1);
VectorAdd(p2, r_refdef.pvsorigin, edge2);
VectorAdd(p3, r_refdef.pvsorigin, edge3);
CLQ1_DrawLine(lineshader, edge1, edge2, 0, 0, 1, 1);
CLQ1_DrawLine(lineshader, edge2, edge3, 0, 0, 1, 1);
CLQ1_DrawLine(lineshader, edge3, edge1, 0, 0, 1, 1);
*/
#if 0
{
shader_t *lineshader = R_RegisterShader("lineshader", SUF_NONE,
"{\n"
"polygonoffset\n"
"{\n"
"map $whiteimage\n"
"blendfunc add\n"
"rgbgen vertex\n"
"alphagen vertex\n"
"}\n"
"}\n");
VectorAdd(p1, r_refdef.pvsorigin, edge1);
VectorAdd(p2, r_refdef.pvsorigin, edge2);
VectorAdd(p3, r_refdef.pvsorigin, edge3);
CLQ1_DrawLine(lineshader, edge1, edge2, 0, 1, 0, 1);
CLQ1_DrawLine(lineshader, edge2, edge3, 0, 1, 0, 1);
CLQ1_DrawLine(lineshader, edge3, edge1, 0, 1, 0, 1);
}
#endif
VectorSubtract(p1, p2, edge1);
VectorSubtract(p3, p2, edge2);
CrossProduct(edge1, edge2, normal);
@ -2029,30 +2078,32 @@ qboolean Mod_Trace_Trisoup(vecV_t *posedata, index_t *indexes, int numindexes, v
// if (fabs(normal[0]) != 1 && fabs(normal[1]) != 1 && fabs(normal[2]) != 1)
// Con_Printf("Non-axial impact\n");
/* if (!lineshader)
lineshader = R_RegisterShader("lineshader", SUF_NONE,
"{\n"
"polygonoffset\n"
"{\n"
"map $whiteimage\n"
"blendfunc add\n"
"rgbgen vertex\n"
"alphagen vertex\n"
"}\n"
"}\n");
VectorAdd(p1, r_refdef.pvsorigin, edge1);
VectorAdd(p2, r_refdef.pvsorigin, edge2);
VectorAdd(p3, r_refdef.pvsorigin, edge3);
CLQ1_DrawLine(lineshader, edge1, edge2, 0, 1, 0, 1);
CLQ1_DrawLine(lineshader, edge2, edge3, 0, 1, 0, 1);
CLQ1_DrawLine(lineshader, edge3, edge1, 0, 1, 0, 1);
*/
#if 0
{
shader_t *lineshader = R_RegisterShader("lineshader", SUF_NONE,
"{\n"
"polygonoffset\n"
"{\n"
"map $whiteimage\n"
"blendfunc add\n"
"rgbgen vertex\n"
"alphagen vertex\n"
"}\n"
"}\n");
VectorAdd(p1, r_refdef.pvsorigin, edge1);
VectorAdd(p2, r_refdef.pvsorigin, edge2);
VectorAdd(p3, r_refdef.pvsorigin, edge3);
CLQ1_DrawLine(lineshader, edge1, edge2, 0, 1, 0, 1);
CLQ1_DrawLine(lineshader, edge2, edge3, 0, 1, 0, 1);
CLQ1_DrawLine(lineshader, edge3, edge1, 0, 1, 0, 1);
}
#endif
}
return impacted;
}
//The whole reason why model loading is supported in the server.
qboolean Mod_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int contentsmask, trace_t *trace)
qboolean Mod_Trace(model_t *model, int forcehullnum, framestate_t *framestate, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int contentsmask, trace_t *trace)
{
galiasinfo_t *mod = Mod_Extradata(model);
galiasanimation_t *group;
@ -2089,36 +2140,33 @@ qboolean Mod_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3],
for(; mod; mod = mod->nextsurf, surfnum++)
{
indexes = mod->ofs_indexes;
if (!mod->numanimations)
{
#ifdef SKELETALMODELS
//certain models have no possibility of animation.
//fixme: skeletal objects...
if (mod->ofs_skel_xyz)
posedata = mod->ofs_skel_xyz;
else
#endif
continue;
if (mod->numbones)
{
if (!mod->ofs_skel_idx)
posedata = mod->ofs_skel_xyz; //if there's no weights, don't try animating anything.
else if (mod->shares_verts != cursurfnum)
{
cursurfnum = mod->shares_verts;
posedata = alloca(mod->numverts*sizeof(vecV_t));
Alias_BuildSkeletalVerts((float*)posedata, framestate, mod);
}
}
else
#endif
if (!mod->numanimations)
continue;
else
{
group = mod->ofsanimations;
group += frame % mod->numanimations;
group += framestate->g[FS_REG].frame[0] % mod->numanimations;
//FIXME: no support for frame blending.
if (!group->numposes)
continue;
pose = group->poseofs;
pose += 0%group->numposes; //FIXME: no framegroup support
pose += (int)(framestate->g[FS_REG].frametime[0] * group->rate)%group->numposes;
posedata = pose->ofsverts;
#ifdef SKELETALMODELS
if (mod->numbones && mod->shares_verts != cursurfnum)
{
posedata = alloca(mod->numverts*sizeof(vecV_t));
Alias_BuildSkeletalVPositionsPose((float*)posedata, group->skeltype, group->boneofs, mod);
cursurfnum = mod->shares_verts;
}
#endif
}
trace->truefraction = 1;
@ -3878,7 +3926,7 @@ int Mod_GetNumBones(model_t *model, qboolean allowtags)
}
#ifdef HALFLIFEMODELS
if (model && model->type == mod_halflife)
return HLMDL_GetNumBones(model);
return HLMDL_GetNumBones(model, allowtags);
#endif
return 0;
}
@ -3970,13 +4018,14 @@ qboolean Mod_GetTag(model_t *model, int tagnum, framestate_t *fstate, float *res
#ifdef HALFLIFEMODELS
if (model && model->type == mod_halflife)
{
int numbones = Mod_GetNumBones(model, false);
int numbones = Mod_GetNumBones(model, true);
if (tagnum > 0 && tagnum <= numbones)
{
float relatives[MAX_BONES*12];
float tempmatrix[12]; //flipped between this and bonematrix
float *matrix; //the matrix for a single bone in a single pose.
float *lerps = relatives;
int k;
if (tagnum <= 0 || tagnum > numbones)
return false;
@ -3985,7 +4034,10 @@ qboolean Mod_GetTag(model_t *model, int tagnum, framestate_t *fstate, float *res
//data comes from skeletal object, if possible
if (fstate->bonestate)
{
if (tagnum >= fstate->bonecount)
numbones = fstate->bonecount;
lerps = fstate->bonestate;
if (tagnum >= numbones)
return false;
if (fstate->skeltype == SKEL_ABSOLUTE)
@ -3993,19 +4045,21 @@ qboolean Mod_GetTag(model_t *model, int tagnum, framestate_t *fstate, float *res
memcpy(result, fstate->bonestate + 12 * tagnum, 12*sizeof(*result));
return true;
}
lerps = fstate->bonestate;
}
else //try getting the data from the frame state
{
numbones = Mod_GetBoneRelations(model, 0, tagnum+1, fstate, relatives);
lerps = relatives;
//make sure it was all okay.
if (tagnum >= numbones)
return false;
}
//set up the identity matrix
for (k = 0;k < 12;k++)
result[k] = 0;
result[0] = 1;
result[5] = 1;
result[10] = 1;
if (tagnum >= numbones)
tagnum = HLMDL_GetAttachment(model, tagnum-numbones, result);
while(tagnum >= 0)
{
//set up the per-bone transform matrix
@ -6952,7 +7006,7 @@ qboolean Mod_ParseMD5Anim(model_t *mod, char *buffer, galiasinfo_t *prototype, v
{
#define MD5ERROR0PARAM(x) { Con_Printf(CON_ERROR x "\n"); return false; }
#define MD5ERROR1PARAM(x, y) { Con_Printf(CON_ERROR x "\n", y); return false; }
#define EXPECT(x) buffer = COM_Parse(buffer); if (strcmp(com_token, x)) MD5ERROR1PARAM("MD5ANIM: expected %s", x);
#define EXPECT(x) buffer = COM_ParseOut(buffer, token, sizeof(token)); if (strcmp(token, x)) MD5ERROR1PARAM("MD5ANIM: expected %s", x);
unsigned int i, j;
galiasanimation_t grp;
@ -6973,29 +7027,29 @@ qboolean Mod_ParseMD5Anim(model_t *mod, char *buffer, galiasinfo_t *prototype, v
float tx, ty, tz, qx, qy, qz;
int fac, flags;
float f;
char com_token[8192];
char token[8192];
EXPECT("MD5Version");
EXPECT("10");
EXPECT("commandline");
buffer = COM_Parse(buffer);
buffer = COM_ParseOut(buffer, token, sizeof(token));
EXPECT("numFrames");
buffer = COM_Parse(buffer);
numframes = atoi(com_token);
buffer = COM_ParseOut(buffer, token, sizeof(token));
numframes = atoi(token);
EXPECT("numJoints");
buffer = COM_Parse(buffer);
numjoints = atoi(com_token);
buffer = COM_ParseOut(buffer, token, sizeof(token));
numjoints = atoi(token);
EXPECT("frameRate");
buffer = COM_Parse(buffer);
framespersecond = atof(com_token);
buffer = COM_ParseOut(buffer, token, sizeof(token));
framespersecond = atof(token);
EXPECT("numAnimatedComponents");
buffer = COM_Parse(buffer);
numanimatedparts = atoi(com_token);
buffer = COM_ParseOut(buffer, token, sizeof(token));
numanimatedparts = atoi(token);
firstanimatedcomponents = BZ_Malloc(sizeof(int)*numjoints);
animatedcomponents = BZ_Malloc(sizeof(float)*numanimatedparts);
@ -7020,28 +7074,28 @@ qboolean Mod_ParseMD5Anim(model_t *mod, char *buffer, galiasinfo_t *prototype, v
EXPECT("{");
for (i = 0; i < numjoints; i++, bonelist++)
{
buffer = COM_Parse(buffer);
buffer = COM_ParseOut(buffer, token, sizeof(token));
if (prototype->numbones)
{
if (strcmp(bonelist->name, com_token))
MD5ERROR1PARAM("MD5ANIM: bone name doesn't match (%s)", com_token);
if (strcmp(bonelist->name, token))
MD5ERROR1PARAM("MD5ANIM: bone name doesn't match (%s)", token);
}
else
Q_strncpyz(bonelist->name, com_token, sizeof(bonelist->name));
buffer = COM_Parse(buffer);
parent = atoi(com_token);
Q_strncpyz(bonelist->name, token, sizeof(bonelist->name));
buffer = COM_ParseOut(buffer, token, sizeof(token));
parent = atoi(token);
if (prototype->numbones)
{
if (bonelist->parent != parent)
MD5ERROR1PARAM("MD5ANIM: bone name doesn't match (%s)", com_token);
MD5ERROR1PARAM("MD5ANIM: bone name doesn't match (%s)", token);
}
else
bonelist->parent = parent;
buffer = COM_Parse(buffer);
boneflags[i] = atoi(com_token);
buffer = COM_Parse(buffer);
firstanimatedcomponents[i] = atoi(com_token);
buffer = COM_ParseOut(buffer, token, sizeof(token));
boneflags[i] = atoi(token);
buffer = COM_ParseOut(buffer, token, sizeof(token));
firstanimatedcomponents[i] = atoi(token);
}
EXPECT("}");
@ -7053,19 +7107,19 @@ qboolean Mod_ParseMD5Anim(model_t *mod, char *buffer, galiasinfo_t *prototype, v
for (i = 0; i < numframes; i++)
{
EXPECT("(");
buffer = COM_Parse(buffer);f=atoi(com_token);
buffer = COM_ParseOut(buffer, token, sizeof(token));f=atoi(token);
if (f < mod->mins[0]) mod->mins[0] = f;
buffer = COM_Parse(buffer);f=atoi(com_token);
buffer = COM_ParseOut(buffer, token, sizeof(token));f=atoi(token);
if (f < mod->mins[1]) mod->mins[1] = f;
buffer = COM_Parse(buffer);f=atoi(com_token);
buffer = COM_ParseOut(buffer, token, sizeof(token));f=atoi(token);
if (f < mod->mins[2]) mod->mins[2] = f;
EXPECT(")");
EXPECT("(");
buffer = COM_Parse(buffer);f=atoi(com_token);
buffer = COM_ParseOut(buffer, token, sizeof(token));f=atoi(token);
if (f > mod->maxs[0]) mod->maxs[0] = f;
buffer = COM_Parse(buffer);f=atoi(com_token);
buffer = COM_ParseOut(buffer, token, sizeof(token));f=atoi(token);
if (f > mod->maxs[1]) mod->maxs[1] = f;
buffer = COM_Parse(buffer);f=atoi(com_token);
buffer = COM_ParseOut(buffer, token, sizeof(token));f=atoi(token);
if (f > mod->maxs[2]) mod->maxs[2] = f;
EXPECT(")");
}
@ -7076,20 +7130,20 @@ qboolean Mod_ParseMD5Anim(model_t *mod, char *buffer, galiasinfo_t *prototype, v
for (i = 0; i < numjoints; i++)
{
EXPECT("(");
buffer = COM_Parse(buffer);
baseframe[i*6+0] = atof(com_token);
buffer = COM_Parse(buffer);
baseframe[i*6+1] = atof(com_token);
buffer = COM_Parse(buffer);
baseframe[i*6+2] = atof(com_token);
buffer = COM_ParseOut(buffer, token, sizeof(token));
baseframe[i*6+0] = atof(token);
buffer = COM_ParseOut(buffer, token, sizeof(token));
baseframe[i*6+1] = atof(token);
buffer = COM_ParseOut(buffer, token, sizeof(token));
baseframe[i*6+2] = atof(token);
EXPECT(")");
EXPECT("(");
buffer = COM_Parse(buffer);
baseframe[i*6+3] = atof(com_token);
buffer = COM_Parse(buffer);
baseframe[i*6+4] = atof(com_token);
buffer = COM_Parse(buffer);
baseframe[i*6+5] = atof(com_token);
buffer = COM_ParseOut(buffer, token, sizeof(token));
baseframe[i*6+3] = atof(token);
buffer = COM_ParseOut(buffer, token, sizeof(token));
baseframe[i*6+4] = atof(token);
buffer = COM_ParseOut(buffer, token, sizeof(token));
baseframe[i*6+5] = atof(token);
EXPECT(")");
}
EXPECT("}");
@ -7101,8 +7155,8 @@ qboolean Mod_ParseMD5Anim(model_t *mod, char *buffer, galiasinfo_t *prototype, v
EXPECT("{");
for (j = 0; j < numanimatedparts; j++)
{
buffer = COM_Parse(buffer);
animatedcomponents[j] = atof(com_token);
buffer = COM_ParseOut(buffer, token, sizeof(token));
animatedcomponents[j] = atof(token);
}
EXPECT("}");
@ -7177,7 +7231,6 @@ galiasinfo_t *Mod_ParseMD5MeshModel(model_t *mod, char *buffer, char *modname)
skinframe_t *frames;
#endif
char *filestart = buffer;
const int com_token = 4;
char token[1024];
float x, y, z, qx, qy, qz;
@ -7468,7 +7521,7 @@ galiasinfo_t *Mod_ParseMD5MeshModel(model_t *mod, char *buffer, char *modname)
else if (!strcmp(token, "}"))
break;
else
MD5ERROR1PARAM("MD5MESH: Unrecognised token inside mesh (%s)", com_token);
MD5ERROR1PARAM("MD5MESH: Unrecognised token inside mesh (%s)", token);
}
@ -7505,7 +7558,7 @@ galiasinfo_t *Mod_ParseMD5MeshModel(model_t *mod, char *buffer, char *modname)
Z_Free(rawweightbone);
}
else
MD5ERROR1PARAM("Unrecognised token in MD5 model (%s)", com_token);
MD5ERROR1PARAM("Unrecognised token in MD5 model (%s)", token);
}
if (!lastsurf)

View File

@ -61,8 +61,8 @@ void Mod_LoadEntities (model_t *loadmodel, qbyte *mod_base, lump_t *l);
extern void BuildLightMapGammaTable (float g, float c);
#ifdef Q2BSPS
static qboolean CM_NativeTrace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int contents, trace_t *trace);
static unsigned int CM_NativeContents(struct model_s *model, int hulloverride, int frame, vec3_t axis[3], vec3_t p, vec3_t mins, vec3_t maxs);
static qboolean CM_NativeTrace(model_t *model, int forcehullnum, framestate_t *framestate, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int contents, trace_t *trace);
static unsigned int CM_NativeContents(struct model_s *model, int hulloverride, framestate_t *framestate, vec3_t axis[3], vec3_t p, vec3_t mins, vec3_t maxs);
static unsigned int Q2BSP_PointContents(model_t *mod, vec3_t axis[3], vec3_t p);
static int CM_PointCluster (model_t *mod, vec3_t p);
#endif
@ -4423,8 +4423,8 @@ mplane_t box_planes[6];
model_t box_model;
q2cbrush_t box_brush;
q2cbrushside_t box_sides[6];
static qboolean BM_NativeTrace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int contents, trace_t *trace);
static unsigned int BM_NativeContents(struct model_s *model, int hulloverride, int frame, vec3_t axis[3], vec3_t p, vec3_t mins, vec3_t maxs)
static qboolean BM_NativeTrace(model_t *model, int forcehullnum, framestate_t *framestate, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int contents, trace_t *trace);
static unsigned int BM_NativeContents(struct model_s *model, int hulloverride, framestate_t *framestate, vec3_t axis[3], vec3_t p, vec3_t mins, vec3_t maxs)
{
unsigned int j;
q2cbrushside_t *brushside = box_sides;
@ -4694,7 +4694,7 @@ int CM_PointContents (model_t *mod, vec3_t p)
return contents;
}
unsigned int CM_NativeContents(struct model_s *model, int hulloverride, int frame, vec3_t axis[3], vec3_t p, vec3_t mins, vec3_t maxs)
unsigned int CM_NativeContents(struct model_s *model, int hulloverride, framestate_t *framestate, vec3_t axis[3], vec3_t p, vec3_t mins, vec3_t maxs)
{
cminfo_t *prv = (cminfo_t*)model->meshinfo;
int contents;
@ -5861,7 +5861,7 @@ static trace_t CM_BoxTrace (model_t *mod, vec3_t start, vec3_t end,
return trace_trace;
}
static qboolean BM_NativeTrace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int contents, trace_t *trace)
static qboolean BM_NativeTrace(model_t *model, int forcehullnum, framestate_t *framestate, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int contents, trace_t *trace)
{
int i;
memset (trace, 0, sizeof(*trace));
@ -5905,7 +5905,7 @@ static qboolean BM_NativeTrace(model_t *model, int forcehullnum, int frame, vec3
}
return trace->fraction != 1;
}
static qboolean CM_NativeTrace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int contents, trace_t *trace)
static qboolean CM_NativeTrace(model_t *model, int forcehullnum, framestate_t *framestate, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int contents, trace_t *trace)
{
if (axis)
{
@ -5923,7 +5923,7 @@ static qboolean CM_NativeTrace(model_t *model, int forcehullnum, int frame, vec3
if (model->terrain)
{
trace_t hmt;
Heightmap_Trace(model, forcehullnum, frame, NULL, start, end, mins, maxs, capsule, contents, &hmt);
Heightmap_Trace(model, forcehullnum, framestate, NULL, start, end, mins, maxs, capsule, contents, &hmt);
if (hmt.fraction < trace->fraction)
*trace = hmt;
}
@ -5955,7 +5955,7 @@ static qboolean CM_NativeTrace(model_t *model, int forcehullnum, int frame, vec3
if (model->terrain)
{
trace_t hmt;
Heightmap_Trace(model, forcehullnum, frame, NULL, start, end, mins, maxs, capsule, contents, &hmt);
Heightmap_Trace(model, forcehullnum, framestate, NULL, start, end, mins, maxs, capsule, contents, &hmt);
if (hmt.fraction < trace->fraction)
*trace = hmt;
}

View File

@ -552,7 +552,6 @@ void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3])
in1[2][2] * in2[2][2];
}
/*
================
R_ConcatTransforms
@ -586,24 +585,36 @@ void QDECL R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]
in1[2][2] * in2[2][3] + in1[2][3];
}
void Matrix3x4_Multiply(const float *a, const float *b, float *out)
//R_ConcatTransforms where there's no offset values
void R_ConcatTransformsAxis (float in1[3][3], float in2[3][4], float out[3][4])
{
out[0] = a[0] * b[0] + a[4] * b[1] + a[8] * b[2];
out[1] = a[1] * b[0] + a[5] * b[1] + a[9] * b[2];
out[2] = a[2] * b[0] + a[6] * b[1] + a[10] * b[2];
out[3] = a[3] * b[0] + a[7] * b[1] + a[11] * b[2] + b[3];
out[4] = a[0] * b[4] + a[4] * b[5] + a[8] * b[6];
out[5] = a[1] * b[4] + a[5] * b[5] + a[9] * b[6];
out[6] = a[2] * b[4] + a[6] * b[5] + a[10] * b[6];
out[7] = a[3] * b[4] + a[7] * b[5] + a[11] * b[6] + b[7];
out[8] = a[0] * b[8] + a[4] * b[9] + a[8] * b[10];
out[9] = a[1] * b[8] + a[5] * b[9] + a[9] * b[10];
out[10] = a[2] * b[8] + a[6] * b[9] + a[10] * b[10];
out[11] = a[3] * b[8] + a[7] * b[9] + a[11] * b[10] + b[11];
out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] +
in1[0][2] * in2[2][0];
out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] +
in1[0][2] * in2[2][1];
out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] +
in1[0][2] * in2[2][2];
out[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] +
in1[0][2] * in2[2][3];
out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] +
in1[1][2] * in2[2][0];
out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] +
in1[1][2] * in2[2][1];
out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] +
in1[1][2] * in2[2][2];
out[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] +
in1[1][2] * in2[2][3];
out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] +
in1[2][2] * in2[2][0];
out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] +
in1[2][2] * in2[2][1];
out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] +
in1[2][2] * in2[2][2];
out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] +
in1[2][2] * in2[2][3];
}
//R_ConcatTransforms where we don't care about the resulting offsets.
void R_ConcatRotationsPad (float in1[3][4], float in2[3][4], float out[3][4])
{
out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] +
@ -628,6 +639,24 @@ void R_ConcatRotationsPad (float in1[3][4], float in2[3][4], float out[3][4])
in1[2][2] * in2[2][2];
}
void Matrix3x4_Multiply(const float *a, const float *b, float *out)
{
out[0] = a[0] * b[0] + a[4] * b[1] + a[8] * b[2];
out[1] = a[1] * b[0] + a[5] * b[1] + a[9] * b[2];
out[2] = a[2] * b[0] + a[6] * b[1] + a[10] * b[2];
out[3] = a[3] * b[0] + a[7] * b[1] + a[11] * b[2] + b[3];
out[4] = a[0] * b[4] + a[4] * b[5] + a[8] * b[6];
out[5] = a[1] * b[4] + a[5] * b[5] + a[9] * b[6];
out[6] = a[2] * b[4] + a[6] * b[5] + a[10] * b[6];
out[7] = a[3] * b[4] + a[7] * b[5] + a[11] * b[6] + b[7];
out[8] = a[0] * b[8] + a[4] * b[9] + a[8] * b[10];
out[9] = a[1] * b[8] + a[5] * b[9] + a[9] * b[10];
out[10] = a[2] * b[8] + a[6] * b[9] + a[10] * b[10];
out[11] = a[3] * b[8] + a[7] * b[9] + a[11] * b[10] + b[11];
}
/*
===================
FloorDivMod
@ -1005,6 +1034,12 @@ void Matrix3x4_RM_Transform3(const float *matrix, const float *vector, float *pr
product[1] = matrix[4]*vector[0] + matrix[5]*vector[1] + matrix[6]*vector[2] + matrix[7];
product[2] = matrix[8]*vector[0] + matrix[9]*vector[1] + matrix[10]*vector[2] + matrix[11];
}
void Matrix3x4_RM_Transform3x3(const float *matrix, const float *vector, float *product)
{
product[0] = matrix[0]*vector[0] + matrix[1]*vector[1] + matrix[2]*vector[2];
product[1] = matrix[4]*vector[0] + matrix[5]*vector[1] + matrix[6]*vector[2];
product[2] = matrix[8]*vector[0] + matrix[9]*vector[1] + matrix[10]*vector[2];
}
//transform 4d vector by a 4d matrix.
void Matrix4x4_CM_Transform4(const float *matrix, const float *vector, float *product)

View File

@ -171,6 +171,7 @@ void Matrix3x4_RM_FromVectors(float *out, const float vx[3], const float vy[3],
void Matrix4x4_RM_FromVectors(float *out, const float vx[3], const float vy[3], const float vz[3], const float t[3]);
void Matrix3x4_RM_ToVectors(const float *in, float vx[3], float vy[3], float vz[3], float t[3]);
void Matrix3x4_RM_Transform3(const float *matrix, const float *vector, float *product);
void Matrix3x4_RM_Transform3x3(const float *matrix, const float *vector, float *product);
float *Matrix4x4_CM_NewRotation(float a, float x, float y, float z);
float *Matrix4x4_CM_NewTranslation(float x, float y, float z);
@ -198,6 +199,7 @@ int Q_log2 (int val);
void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]);
void R_ConcatRotationsPad (float in1[3][4], float in2[3][4], float out[3][4]);
void QDECL R_ConcatTransforms (matrix3x4 in1, matrix3x4 in2, matrix3x4 out);
void R_ConcatTransformsAxis (float in1[3][3], float in2[3][4], float out[3][4]);
void RotatePointAroundVector (vec3_t dst, const vec3_t dir, const vec3_t point, float degrees);
void RotateLightVector(const vec3_t *axis, const vec3_t origin, const vec3_t lightpoint, vec3_t result);
int VectorCompare (const vec3_t v1, const vec3_t v2);

View File

@ -885,7 +885,7 @@ hull_t *Q1BSP_ChooseHull(model_t *model, int forcehullnum, vec3_t mins, vec3_t m
VectorSubtract (hull->clip_mins, mins, offset);
return hull;
}
qboolean Q1BSP_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int hitcontentsmask, trace_t *trace)
qboolean Q1BSP_Trace(model_t *model, int forcehullnum, framestate_t *framestate, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int hitcontentsmask, trace_t *trace)
{
hull_t *hull;
vec3_t start_l, end_l;
@ -1007,7 +1007,7 @@ qboolean Q1BSP_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3]
if (model->terrain && trace->fraction)
{
trace_t hmt;
Heightmap_Trace(model, forcehullnum, frame, axis, start, end, mins, maxs, capsule, hitcontentsmask, &hmt);
Heightmap_Trace(model, forcehullnum, framestate, axis, start, end, mins, maxs, capsule, hitcontentsmask, &hmt);
if (hmt.fraction < trace->fraction)
*trace = hmt;
}

View File

@ -283,7 +283,7 @@ int World_PointContents (world_t *w, vec3_t p);
wedict_t *World_TestEntityPosition (world_t *w, wedict_t *ent);
qboolean World_TransformedTrace (struct model_s *model, int hulloverride, int frame, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, struct trace_s *trace, vec3_t origin, vec3_t angles, unsigned int hitcontentsmask);
qboolean World_TransformedTrace (struct model_s *model, int hulloverride, framestate_t *framestate, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, struct trace_s *trace, vec3_t origin, vec3_t angles, unsigned int hitcontentsmask);
/*
World_Move:

View File

@ -25246,7 +25246,6 @@
</FileConfiguration>
<FileConfiguration
Name="Debug Dedicated Server|Win32"
ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"

View File

@ -3269,7 +3269,7 @@ unsigned int Heightmap_PointContents(model_t *model, vec3_t axis[3], vec3_t org)
return cont;
}
unsigned int Heightmap_NativeBoxContents(model_t *model, int hulloverride, int frame, vec3_t axis[3], vec3_t org, vec3_t mins, vec3_t maxs)
unsigned int Heightmap_NativeBoxContents(model_t *model, int hulloverride, framestate_t *framestate, vec3_t axis[3], vec3_t org, vec3_t mins, vec3_t maxs)
{
heightmap_t *hm = model->terrain;
return Heightmap_PointContentsHM(hm, mins[2], org);
@ -3706,12 +3706,10 @@ static void Heightmap_Trace_Square(hmtrace_t *tr, int tx, int ty)
vec3_t start_l, end_l;
trace_t etr;
model_t *model;
int frame;
if (s->ents[i]->traceseq == tr->hm->traceseq)
continue;
s->ents[i]->traceseq = tr->hm->traceseq;
model = s->ents[i]->ent.model;
frame = s->ents[i]->ent.framestate.g[FS_REG].frame[0];
//FIXME: IGNORE the entity if it isn't loaded yet? surely that's bad?
if (!model || model->loadstate != MLS_LOADED || !model->funcs.NativeTrace)
continue;
@ -3735,7 +3733,7 @@ static void Heightmap_Trace_Square(hmtrace_t *tr, int tx, int ty)
//do the trace
memset(&etr, 0, sizeof(etr));
etr.fraction = 1;
model->funcs.NativeTrace (model, 0, frame, s->ents[i]->ent.axis, start_l, end_l, tr->mins, tr->maxs, tr->shape == iscapsule, tr->hitcontentsmask, &etr);
model->funcs.NativeTrace (model, 0, &s->ents[i]->ent.framestate, s->ents[i]->ent.axis, start_l, end_l, tr->mins, tr->maxs, tr->shape == iscapsule, tr->hitcontentsmask, &etr);
if (etr.startsolid)
{ //many many bsp objects are not enclosed 'properly' (qbsp strips any surfaces outside the world).
@ -3935,7 +3933,7 @@ Why is recursion good?
Obviously, we don't care all that much about 1
*/
qboolean Heightmap_Trace(struct model_s *model, int hulloverride, int frame, vec3_t mataxis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int against, struct trace_s *trace)
qboolean Heightmap_Trace(struct model_s *model, int hulloverride, framestate_t *framestate, vec3_t mataxis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int against, struct trace_s *trace)
{
vec2_t pos;
vec2_t frac;
@ -4201,14 +4199,14 @@ qboolean Heightmap_Trace(struct model_s *model, int hulloverride, int frame, vec
return trace->fraction < 1;
}
qboolean Heightmap_Trace_Test(struct model_s *model, int hulloverride, int frame, vec3_t mataxis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int against, struct trace_s *trace)
qboolean Heightmap_Trace_Test(struct model_s *model, int hulloverride, framestate_t *framestate, vec3_t mataxis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int against, struct trace_s *trace)
{
qboolean ret = Heightmap_Trace(model, hulloverride, frame, mataxis, start, end, mins, maxs, capsule, against, trace);
qboolean ret = Heightmap_Trace(model, hulloverride, framestate, mataxis, start, end, mins, maxs, capsule, against, trace);
if (!trace->startsolid)
{
trace_t testtrace;
Heightmap_Trace(model, hulloverride, frame, mataxis, trace->endpos, trace->endpos, mins, maxs, capsule, against, &testtrace);
Heightmap_Trace(model, hulloverride, framestate, mataxis, trace->endpos, trace->endpos, mins, maxs, capsule, against, &testtrace);
if (testtrace.startsolid)
{
Con_DPrintf("Trace became solid\n");

View File

@ -6,17 +6,18 @@
#include "com_mesh.h"
/*
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Half-Life Model Renderer (Experimental) Copyright (C) 2001 James 'Ender' Brown [ender@quakesrc.org] This program is
free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details. You should have received a copy of the GNU General Public License along with this program; if not, write
to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. fromquake.h -
Half-Life Model Renderer (Experimental) Copyright (C) 2001 James 'Ender' Brown [ender@quakesrc.org] This program is
free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details. You should have received a copy of the GNU General Public License along with this program; if not, write
to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. fromquake.h -
render.c - apart from calculations (mostly range checking or value conversion code is a mix of standard Quake 1
meshing, and vertex deforms. The rendering loop uses standard Quake 1 drawing, after SetupBones deforms the vertex.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Note: this code has since been greatly modified to fix skin, submodels, hitboxes, attachments, etc.
@ -24,6 +25,9 @@
Nor will it work 100%
*/
qboolean HLMDL_Trace (struct model_s *model, int hulloverride, framestate_t *framestate, vec3_t axis[3], vec3_t p1, vec3_t p2, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int against, struct trace_s *trace);
unsigned int HLMDL_Contents (struct model_s *model, int hulloverride, framestate_t *framestate, vec3_t axis[3], vec3_t p, vec3_t mins, vec3_t maxs);
void QuaternionGLMatrix(float x, float y, float z, float w, vec4_t *GLM)
{
GLM[0][0] = 1 - 2 * y * y - 2 * z * z;
@ -64,6 +68,7 @@ void QuaternionGLAngle(const vec3_t angles, vec4_t quaternion)
matrix3x4 transform_matrix[MAX_BONES]; /* Vertex transformation matrix */
#ifndef SERVERONLY
void GL_Draw_HL_AliasFrame(short *order, vec3_t *transformed, float tex_w, float tex_h);
struct hlvremaps
@ -218,6 +223,7 @@ static void HLMDL_PrepareVerticies (hlmodel_t *model, hlmdl_submodel_t *amodel,
//treat this as the base pose, and calculate the sdir+tdir for bumpmaps.
R_Generate_Mesh_ST_Vectors(mesh);
}
#endif
/*
=======================================================================================================================
@ -226,7 +232,11 @@ static void HLMDL_PrepareVerticies (hlmodel_t *model, hlmdl_submodel_t *amodel,
*/
qboolean QDECL Mod_LoadHLModel (model_t *mod, void *buffer, size_t fsize)
{
#ifndef SERVERONLY
int i;
int body;
struct hlmodelshaders_s *shaders;
#endif
hlmodel_t *model;
hlmdl_header_t *header;
@ -234,9 +244,7 @@ qboolean QDECL Mod_LoadHLModel (model_t *mod, void *buffer, size_t fsize)
hlmdl_tex_t *tex;
hlmdl_bone_t *bones;
hlmdl_bonecontroller_t *bonectls;
struct hlmodelshaders_s *shaders;
void *texmem = NULL;
int body;
//load the model into hunk
@ -247,7 +255,7 @@ qboolean QDECL Mod_LoadHLModel (model_t *mod, void *buffer, size_t fsize)
memcpy(header, buffer, fsize);
#if defined(HLSERVER) && (defined(__powerpc__) || defined(__ppc__))
//this is to let bigfoot know when he comes to port it all... And I'm lazy.
//this is to let anyone who tries porting it know that there is a serious issue. And I'm lazy.
#ifdef warningmsg
#pragma warningmsg("-----------------------------------------")
#pragma warningmsg("FIXME: No byteswapping on halflife models") //hah, yeah, good luck with that, you'll need it.
@ -301,6 +309,7 @@ qboolean QDECL Mod_LoadHLModel (model_t *mod, void *buffer, size_t fsize)
model->bones = bones;
model->bonectls = bonectls;
#ifndef SERVERONLY
shaders = ZG_Malloc(&mod->memgroup, texheader->numtextures*sizeof(shader_t));
model->shaders = shaders;
for(i = 0; i < texheader->numtextures; i++)
@ -316,18 +325,21 @@ qboolean QDECL Mod_LoadHLModel (model_t *mod, void *buffer, size_t fsize)
model->numskingroups = texheader->skingroups;
model->skinref = ZG_Malloc(&mod->memgroup, model->numskinrefs*model->numskingroups*sizeof(*model->skinref));
memcpy(model->skinref, (short *) ((qbyte *) texheader + texheader->skins), model->numskinrefs*model->numskingroups*sizeof(*model->skinref));
#endif
if (texmem)
Z_Free(texmem);
mod->funcs.NativeContents = HLMDL_Contents;
mod->funcs.NativeTrace = HLMDL_Trace;
mod->type = mod_halflife;
mod->numframes = model->header->numseq;
mod->meshinfo = model;
#ifndef SERVERONLY
model->numgeomsets = model->header->numbodyparts;
model->geomset = ZG_Malloc(&mod->memgroup, sizeof(*model->geomset) * model->numgeomsets);
for (body = 0; body < model->header->numbodyparts; body++)
for (body = 0; body < model->numgeomsets; body++)
{
hlmdl_bodypart_t *bodypart = (hlmdl_bodypart_t *) ((qbyte *) model->header + model->header->bodypartindex) + body;
int bodyindex;
@ -341,6 +353,8 @@ qboolean QDECL Mod_LoadHLModel (model_t *mod, void *buffer, size_t fsize)
HLMDL_PrepareVerticies(model, amodel, &model->geomset[body].alternatives[bodyindex]);
}
}
//FIXME: No VBOs used.
#endif
return true;
}
@ -557,17 +571,18 @@ void HL_SetupBones(hlmodel_t *model, int seqnum, int firstbone, int lastbone, fl
if (!sequence->numframes)
return;
//halflife seems to dupe the last frame in looping animations, so don't use it.
if(frame1 >= sequence->numframes)
{
if (sequence->loop)
frame1 %= sequence->numframes;
frame1 %= sequence->numframes-1;
else
frame1 = sequence->numframes-1;
}
if(frame2 >= sequence->numframes)
{
if (sequence->loop)
frame2 %= sequence->numframes;
frame2 %= sequence->numframes-1;
else
frame2 = sequence->numframes-1;
}
@ -691,13 +706,15 @@ void HL_SetupBones(hlmodel_t *model, int seqnum, int firstbone, int lastbone, fl
}
}
int HLMDL_GetNumBones(model_t *mod)
int HLMDL_GetNumBones(model_t *mod, qboolean tags)
{
hlmodel_t *mc;
if (!mod || mod->type != mod_halflife)
return -1; //halflife models only, please
mc = Mod_Extradata(mod);
if (tags)
return mc->header->numbones + mc->header->num_attachments;
return mc->header->numbones;
}
@ -707,6 +724,12 @@ int HLMDL_GetBoneParent(model_t *mod, int bonenum)
if (bonenum >= 0 && bonenum < model->header->numbones)
return model->bones[bonenum].parent;
bonenum -= model->header->numbones;
if (bonenum >= 0 && bonenum < model->header->num_attachments)
{
hlmdl_attachment_t *attachments = bonenum+(hlmdl_attachment_t*)((char*)model->header + model->header->ofs_attachments);
return attachments->bone;
}
return -1;
}
@ -716,13 +739,34 @@ const char *HLMDL_GetBoneName(model_t *mod, int bonenum)
if (bonenum >= 0 && bonenum < model->header->numbones)
return model->bones[bonenum].name;
bonenum -= model->header->numbones;
if (bonenum >= 0 && bonenum < model->header->num_attachments)
{
hlmdl_attachment_t *attachments = bonenum+(hlmdl_attachment_t*)((char*)model->header + model->header->ofs_attachments);
if (*attachments->name)
return attachments->name;
return "Unnamed Attachment";
}
return NULL;
}
int HLMDL_GetBoneData(model_t *mod, int firstbone, int lastbone, framestate_t *fstate, float *result)
int HLMDL_GetAttachment(model_t *mod, int tagnum, float *resultmatrix)
{
hlmodel_t *model = Mod_Extradata(mod);
if (tagnum >= 0 && tagnum < model->header->num_attachments)
{
hlmdl_attachment_t *attachments = tagnum+(hlmdl_attachment_t*)((char*)model->header + model->header->ofs_attachments);
resultmatrix[3] = attachments->org[0];
resultmatrix[7] = attachments->org[1];
resultmatrix[11] = attachments->org[2];
return attachments->bone;
}
return -1;
}
static int HLMDL_GetBoneData_Internal(hlmodel_t *model, int firstbone, int lastbone, framestate_t *fstate, float *result)
{
int b, cbone, bgroup;
hlmodel_t *model = Mod_Extradata(mod);
for (b = 0; b < MAX_BONE_CONTROLLERS; b++)
model->controller[b] = fstate->bonecontrols[b];
@ -738,6 +782,10 @@ int HLMDL_GetBoneData(model_t *mod, int firstbone, int lastbone, framestate_t *f
}
return cbone;
}
int HLMDL_GetBoneData(model_t *mod, int firstbone, int lastbone, framestate_t *fstate, float *result)
{
return HLMDL_GetBoneData_Internal(Mod_Extradata(mod), firstbone, lastbone, fstate, result);
}
const char *HLMDL_FrameNameForNum(model_t *mod, int surfaceidx, int seqnum)
{
@ -754,17 +802,205 @@ qboolean HLMDL_FrameInfoForNum(model_t *mod, int surfaceidx, int seqnum, char **
*name = sequence->name;
*numframes = sequence->numframes;
*duration = sequence->numframes/sequence->timing;
*duration = (sequence->numframes-1)/sequence->timing;
*loop = sequence->loop;
return true;
}
qboolean HLMDL_Trace (model_t *model, int hulloverride, framestate_t *framestate, vec3_t axis[3], vec3_t p1, vec3_t p2, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int against, struct trace_s *trace)
{
hlmodel_t *hm = Mod_Extradata(model);
float *relbones;
float calcrelbones[MAX_BONES*12];
int bonecount;
int b, i;
vec3_t norm, p1l, p2l;
float inverse[12];
hlmdl_hitbox_t *hitbox = (hlmdl_hitbox_t*)((char*)hm->header+hm->header->ofs_hitboxes);
float dist, d1, d2, f, enterfrac, enterdist, exitfrac;
qboolean startout, endout;
int enterplane;
extern cvar_t temp1;
p1[2] += temp1.value;
p2[2] += temp1.value;
memset (trace, 0, sizeof(trace_t));
trace->fraction = trace->truefraction = 1;
if (!(against & FTECONTENTS_BODY))
return false;
if (framestate->bonestate && framestate->skeltype == SKEL_ABSOLUTE)
{
relbones = framestate->bonestate;
bonecount = framestate->bonecount;
if (axis)
{
for (b = 0; b < bonecount; b++)
R_ConcatTransformsAxis(axis, (void*)(relbones+b*12), transform_matrix[b]);
}
else
memcpy(transform_matrix, relbones, bonecount * 12 * sizeof(float));
}
else
{
//get relative bones from th emodel.
if (framestate->bonestate)
{
relbones = framestate->bonestate;
bonecount = framestate->bonecount;
}
else
{
relbones = calcrelbones;
bonecount = HLMDL_GetBoneData(model, 0, MAX_BONES, framestate, calcrelbones);
}
//convert relative to absolutes
for (b = 0; b < bonecount; b++)
{
/* If we have a parent, take the addition. Otherwise just copy the values */
if(hm->bones[b].parent>=0)
R_ConcatTransforms(transform_matrix[hm->bones[b].parent], (void*)(relbones+b*12), transform_matrix[b]);
else if (axis)
R_ConcatTransformsAxis(axis, (void*)(relbones+b*12), transform_matrix[b]);
else
memcpy(transform_matrix[b], relbones+b*12, 12 * sizeof(float));
}
}
for (b = 0; b < hm->header->num_hitboxes; b++, hitbox++)
{
startout = false;
endout = false;
enterplane= 0;
enterfrac = -1;
exitfrac = 10;
//fixme: would be nice to check if there's a possible collision a bit faster, without needing to do lots of excess maths.
//transform start+end into the bbox, so everything is axial and simple.
Matrix3x4_Invert_Simple((void*)transform_matrix[hitbox->bone], inverse);
Matrix3x4_RM_Transform3(inverse, p1, p1l);
Matrix3x4_RM_Transform3(inverse, p2, p2l);
//fixme: would it be faster to just generate the plane and transform that, colliding non-axially? would probably be better for sized impactors.
//clip against the 6 axial faces
for (i = 0; i < 6; i++)
{
if (i < 3)
{ //normal>0
dist = hitbox->maxs[i] - mins[i];
d1 = p1l[i] - dist;
d2 = p2l[i] - dist;
}
else
{//normal<0
dist = maxs[i-3] - hitbox->mins[i-3];
d1 = -p1l[i-3] - dist;
d2 = -p2l[i-3] - dist;
}
//FIXME: if the trace has size, we should insert 6 extra planes for the shape of the impactor
//FIXME: capsules
if (d1 >= 0)
startout = true;
if (d2 > 0)
endout = true;
//if we're fully outside any plane, then we cannot possibly enter the brush, skip to the next one
if (d1 > 0 && d2 >= 0)
goto nextbrush;
//if we're fully inside the plane, then whatever is happening is not relevent for this plane
if (d1 < 0 && d2 <= 0)
continue;
f = d1 / (d1-d2);
if (d1 > d2)
{
//entered the brush. favour the furthest fraction to avoid extended edges (yay for convex shapes)
if (enterfrac < f)
{
enterfrac = f;
enterplane = i;
enterdist = dist;
}
}
else
{
//left the brush, favour the nearest plane (smallest frac)
if (exitfrac > f)
{
exitfrac = f;
}
}
}
if (!startout)
{
trace->startsolid = true;
if (!endout)
trace->allsolid = true;
trace->contents = FTECONTENTS_BODY;
trace->brush_face = 0;
trace->bone_id = hitbox->bone+1;
trace->brush_id = b+1;
trace->surface_id = hitbox->body;
break;
}
if (enterfrac != -1 && enterfrac < exitfrac)
{
//impact!
if (enterfrac < trace->fraction)
{
trace->fraction = trace->truefraction = enterfrac;
trace->plane.dist = enterdist;
trace->contents = FTECONTENTS_BODY;
trace->brush_face = enterplane+1;
trace->bone_id = hitbox->bone+1;
trace->brush_id = b+1;
trace->surface_id = hitbox->body;
}
}
nextbrush:
;
}
if (trace->brush_face)
{
VectorClear(norm);
if (trace->brush_face < 4)
norm[trace->brush_face-1] = 1;
else
norm[trace->brush_face-4] = -1;
Matrix3x4_RM_Transform3x3((void*)transform_matrix[trace->bone_id-1], norm, trace->plane.normal);
}
else
VectorClear(trace->plane.normal);
VectorInterpolate(p1, trace->fraction, p2, trace->endpos);
return trace->truefraction != 1;
}
unsigned int HLMDL_Contents (model_t *model, int hulloverride, framestate_t *framestate, vec3_t axis[3], vec3_t p, vec3_t mins, vec3_t maxs)
{
trace_t tr;
HLMDL_Trace(model, hulloverride, framestate, axis, p, p, mins, maxs, false, ~0, &tr);
return tr.contents;
}
#ifndef SERVERONLY
void R_HL_BuildFrame(hlmodel_t *model, hlmdl_submodel_t *amodel, entity_t *curent, int bodypart, int bodyidx, int meshidx, float tex_s, float tex_t, mesh_t *mesh, qboolean gpubones)
{
int b;
int cbone;
int bgroup;
int lastbone;
// int bgroup;
// int lastbone;
int v;
*mesh = model->geomset[bodypart].alternatives[bodyidx].mesh;
@ -801,7 +1037,7 @@ void R_HL_BuildFrame(hlmodel_t *model, hlmdl_submodel_t *amodel, entity_t *curen
mesh->bones = transform_matrix[0][0];
mesh->numbones = model->header->numbones;
//FIXME: needs caching.
/* //FIXME: needs caching.
for (b = 0; b < MAX_BONE_CONTROLLERS; b++)
model->controller[b] = curent->framestate.bonecontrols[b];
for (cbone = 0, bgroup = 0; bgroup < FS_COUNT; bgroup++)
@ -811,9 +1047,11 @@ void R_HL_BuildFrame(hlmodel_t *model, hlmdl_submodel_t *amodel, entity_t *curen
lastbone = model->header->numbones;
if (cbone >= lastbone)
continue;
HL_SetupBones(model, curent->framestate.g[bgroup].frame[0], cbone, lastbone, (curent->framestate.g[bgroup].subblendfrac+1)*0.5, curent->framestate.g[bgroup].frametime[0], relatives); /* Setup the bones */
HL_SetupBones(model, curent->framestate.g[bgroup].frame[0], cbone, lastbone, (curent->framestate.g[bgroup].subblendfrac+1)*0.5, curent->framestate.g[bgroup].frametime[0], relatives); // Setup the bones
cbone = lastbone;
}
*/
cbone = HLMDL_GetBoneData_Internal(model, 0, model->header->numbones, &curent->framestate, relatives);
//convert relative to absolutes
for (b = 0; b < cbone; b++)
@ -867,13 +1105,13 @@ void R_HL_BuildFrame(hlmodel_t *model, hlmdl_submodel_t *amodel, entity_t *curen
}
}
void R_HalfLife_WalkMeshes(entity_t *rent, batch_t *b, batch_t **batches);
void R_HL_BuildMesh(struct batch_s *b)
static void R_HalfLife_WalkMeshes(entity_t *rent, batch_t *b, batch_t **batches);
static void R_HL_BuildMesh(struct batch_s *b)
{
R_HalfLife_WalkMeshes(b->ent, b, NULL);
}
void R_HalfLife_WalkMeshes(entity_t *rent, batch_t *b, batch_t **batches)
static void R_HalfLife_WalkMeshes(entity_t *rent, batch_t *b, batch_t **batches)
{
hlmodel_t *model = Mod_Extradata(rent->model);
int body, m;
@ -887,7 +1125,7 @@ void R_HalfLife_WalkMeshes(entity_t *rent, batch_t *b, batch_t **batches)
sk = Mod_LookupSkin(rent->customskin);
//entity_body = rent->body; //hey, if its there, lets use it.
for (body = 0; body < model->header->numbodyparts; body++)
for (body = 0; body < model->numgeomsets; body++)
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
hlmdl_bodypart_t *bodypart = (hlmdl_bodypart_t *) ((qbyte *) model->header + model->header->bodypartindex) + body;
@ -1007,4 +1245,48 @@ void R_HalfLife_GenerateBatches(entity_t *e, batch_t **batches)
R_HalfLife_WalkMeshes(e, NULL, batches);
}
void HLMDL_DrawHitBoxes(entity_t *rent)
{
hlmodel_t *model = Mod_Extradata(rent->model);
hlmdl_hitbox_t *hitbox = (hlmdl_hitbox_t*)((char*)model->header+model->header->ofs_hitboxes);
matrix3x4 entitymatrix;
shader_t *shader = R_RegisterShader("hitbox_nodepth", SUF_NONE,
"{\n"
"polygonoffset\n"
"{\n"
"map $whiteimage\n"
"blendfunc gl_src_alpha gl_one\n"
"rgbgen vertex\n"
"alphagen vertex\n"
"nodepthtest\n"
"}\n"
"}\n");
float relbones[MAX_BONES*12];
int bonecount = HLMDL_GetBoneData(rent->model, 0, MAX_BONES, &rent->framestate, relbones);
int b;
VectorCopy(rent->axis[0], entitymatrix[0]);
VectorCopy(rent->axis[1], entitymatrix[1]);
VectorCopy(rent->axis[2], entitymatrix[2]);
entitymatrix[0][3] = rent->origin[0];
entitymatrix[1][3] = rent->origin[1];
entitymatrix[2][3] = rent->origin[2];
//convert relative to absolutes
for (b = 0; b < bonecount; b++)
{
//If we have a parent, take the addition. Otherwise just copy the values
if(model->bones[b].parent>=0)
R_ConcatTransforms(transform_matrix[model->bones[b].parent], (void*)(relbones+b*12), transform_matrix[b]);
else
R_ConcatTransforms(entitymatrix, (void*)(relbones+b*12), transform_matrix[b]);
}
for (b = 0; b < model->header->num_hitboxes; b++, hitbox++)
CLQ1_AddOrientedCube(shader, hitbox->mins, hitbox->maxs, transform_matrix[hitbox->bone][0], 1, 1, 1, 0.2);
}
#endif
#endif

View File

@ -216,11 +216,11 @@ typedef struct {
void (*PurgeModel) (struct model_s *mod);
unsigned int (*PointContents) (struct model_s *model, vec3_t axis[3], vec3_t p);
unsigned int (*BoxContents) (struct model_s *model, int hulloverride, int frame, vec3_t axis[3], vec3_t p, vec3_t mins, vec3_t maxs);
unsigned int (*BoxContents) (struct model_s *model, int hulloverride, framestate_t *framestate, vec3_t axis[3], vec3_t p, vec3_t mins, vec3_t maxs);
//deals with whatever is native for the bsp (gamecode is expected to distinguish this).
qboolean (*NativeTrace) (struct model_s *model, int hulloverride, int frame, vec3_t axis[3], vec3_t p1, vec3_t p2, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int against, struct trace_s *trace);
unsigned int (*NativeContents)(struct model_s *model, int hulloverride, int frame, vec3_t axis[3], vec3_t p, vec3_t mins, vec3_t maxs);
qboolean (*NativeTrace) (struct model_s *model, int hulloverride, framestate_t *framestate, vec3_t axis[3], vec3_t p1, vec3_t p2, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int against, struct trace_s *trace);
unsigned int (*NativeContents)(struct model_s *model, int hulloverride, framestate_t *framestate, vec3_t axis[3], vec3_t p, vec3_t mins, vec3_t maxs);
unsigned int (*FatPVS) (struct model_s *model, vec3_t org, qbyte *pvsbuffer, unsigned int buffersize, qboolean merge);
qboolean (*EdictInFatPVS) (struct model_s *model, struct pvscache_s *edict, qbyte *pvsbuffer);
@ -1030,7 +1030,7 @@ void Terr_FinishTerrain(model_t *model);
void Terr_PurgeTerrainModel(model_t *hm, qboolean lightmapsonly, qboolean lightmapreusable);
void *Mod_LoadTerrainInfo(model_t *mod, char *loadname, qboolean force); //call this after loading a bsp
qboolean Terrain_LocateSection(char *name, flocation_t *loc); //used on servers to generate sections for download.
qboolean Heightmap_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int contentmask, struct trace_s *trace);
qboolean Heightmap_Trace(model_t *model, int forcehullnum, framestate_t *framestate, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int contentmask, struct trace_s *trace);
unsigned int Heightmap_PointContents(model_t *model, vec3_t axis[3], vec3_t org);
struct fragmentdecal_s;
void Terrain_ClipDecal(struct fragmentdecal_s *dec, float *center, float radius, model_t *model);

View File

@ -418,7 +418,7 @@ qboolean R_GameRectIsFullscreen(void);
R_SetupGL
=============
*/
void R_SetupGL (float stereooffset)
void R_SetupGL (float stereooffset, int i)
{
int x, x2, y2, y, w, h;
vec3_t newa;
@ -430,8 +430,8 @@ void R_SetupGL (float stereooffset)
newa[0] = r_refdef.viewangles[0];
newa[1] = r_refdef.viewangles[1];
newa[2] = r_refdef.viewangles[2] + gl_screenangle.value;
if (stereooffset)
newa[1] += r_stereo_convergence.value * ((stereooffset>0)?-0.5:0.5); //can we get away with this cheapness? rip 6dof
if (r_refdef.stereomethod)
newa[1] += r_stereo_convergence.value * (i?0.5:-0.5); //can we get away with this cheapness? rip 6dof
if (0)
{
vec3_t paxis[3];
@ -507,10 +507,14 @@ void R_SetupGL (float stereooffset)
w = x2 - x;
h = y2 - y;
if (stereooffset && r_refdef.stereomethod == STEREO_CROSSEYED)
if (r_refdef.stereomethod == STEREO_CROSSEYED
#ifdef FTE_TARGET_WEB
|| r_refdef.stereomethod == STEREO_WEBVR
#endif
)
{
w /= 2;
if (stereooffset < 0)
if (i)
x += vid.fbpwidth/2;
}
@ -537,31 +541,47 @@ void R_SetupGL (float stereooffset)
GL_ViewportUpdate();
if (r_refdef.useperspective)
#ifdef FTE_TARGET_WEB
if (r_refdef.stereomethod == STEREO_WEBVR)
{
int stencilshadows = Sh_StencilShadowsActive();
float vm[16], em[16];
emscriptenfte_getvreyedata(i, r_refdef.m_projection, em);
Matrix4x4_Identity(em);
if ((!stencilshadows || !gl_stencilbits) && r_refdef.maxdist)//gl_nv_range_clamp)
Matrix4x4_CM_ModelViewMatrixFromAxis(vm, vpn, vright, vup, r_origin);
Matrix4_Multiply(vm, em, r_refdef.m_view);
//fixme: read the axis+org back out...
// Matrix4x4_CM_ModelViewMatrixFromAxis(r_refdef.m_view, vpn, vright, vup, r_origin);
}
else
#endif
{
if (r_refdef.useperspective)
{
// yfov = 2*atan((float)r_refdef.vrect.height/r_refdef.vrect.width)*180/M_PI;
// yfov = (2.0 * tan (scr_fov.value/360*M_PI)) / screenaspect;
// yfov = 2*atan((float)r_refdef.vrect.height/r_refdef.vrect.width)*(scr_fov.value*2)/M_PI;
// MYgluPerspective (yfov, screenaspect, 4, 4096);
int stencilshadows = Sh_StencilShadowsActive();
Matrix4x4_CM_Projection_Far(r_refdef.m_projection, fov_x, fov_y, r_refdef.mindist, r_refdef.maxdist);
if ((!stencilshadows || !gl_stencilbits) && r_refdef.maxdist)//gl_nv_range_clamp)
{
// yfov = 2*atan((float)r_refdef.vrect.height/r_refdef.vrect.width)*180/M_PI;
// yfov = (2.0 * tan (scr_fov.value/360*M_PI)) / screenaspect;
// yfov = 2*atan((float)r_refdef.vrect.height/r_refdef.vrect.width)*(scr_fov.value*2)/M_PI;
// MYgluPerspective (yfov, screenaspect, 4, 4096);
Matrix4x4_CM_Projection_Far(r_refdef.m_projection, fov_x, fov_y, r_refdef.mindist, r_refdef.maxdist);
}
else
{
Matrix4x4_CM_Projection_Inf(r_refdef.m_projection, fov_x, fov_y, r_refdef.mindist);
}
}
else
{
Matrix4x4_CM_Projection_Inf(r_refdef.m_projection, fov_x, fov_y, r_refdef.mindist);
Matrix4x4_CM_Orthographic(r_refdef.m_projection, -fov_x/2, fov_x/2, -fov_y/2, fov_y/2, r_refdef.mindist, r_refdef.maxdist?r_refdef.maxdist:9999);
}
}
else
{
Matrix4x4_CM_Orthographic(r_refdef.m_projection, -fov_x/2, fov_x/2, -fov_y/2, fov_y/2, r_refdef.mindist, r_refdef.maxdist?r_refdef.maxdist:9999);
}
Matrix4x4_CM_ModelViewMatrixFromAxis(r_refdef.m_view, vpn, vright, vup, r_origin);
Matrix4x4_CM_ModelViewMatrixFromAxis(r_refdef.m_view, vpn, vright, vup, r_origin);
}
}
if (qglLoadMatrixf)
@ -691,6 +711,11 @@ void R_RenderScene (void)
else
qglColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_TRUE);
break;
#ifdef FTE_TARGET_WEB
case STEREO_WEBVR:
stereooffset[i] = 0; //webgl overrides our separation.
break;
#endif
case STEREO_CROSSEYED: //eyestrain
break;
case STEREO_LEFTONLY:
@ -710,7 +735,7 @@ void R_RenderScene (void)
}
TRACE(("dbg: calling R_SetupGL\n"));
R_SetupGL (stereooffset[i]);
R_SetupGL (stereooffset[i], i);
TRACE(("dbg: calling R_SetFrustrum\n"));
if (!r_refdef.recurse)

View File

@ -31,7 +31,8 @@ typedef struct
int boneindex;
int numcontrollers;
int controllerindex;
int unknown5[2]; //hitboxes
int num_hitboxes;
int ofs_hitboxes;
int numseq;
int seqindex;
int unknown6; //external sequences
@ -44,7 +45,9 @@ typedef struct
int skins;
int numbodyparts;
int bodypartindex;
int unknown9[8]; //attachments, sounds, transitions
int num_attachments;
int ofs_attachments;
int unknown9[6]; //sounds, transitions
} hlmdl_header_t;
/*
@ -103,6 +106,23 @@ typedef struct
float scale[6];
} hlmdl_bone_t;
typedef struct
{
char name[32]; //I assume
int unk;
int bone;
vec3_t org;
vec3_t unk2[3];
} hlmdl_attachment_t;
typedef struct
{
int bone;
int body; //value reported to gamecode on impact
vec3_t mins;
vec3_t maxs;
} hlmdl_hitbox_t;
/*
-----------------------------------------------------------------------------------------------------------------------
bone controllers
@ -259,9 +279,7 @@ void QuaternionGLAngle(const vec3_t angles, vec4_t quaternion);
void QuaternionGLMatrix(float x, float y, float z, float w, vec4_t *GLM);
//void UploadTexture(hlmdl_tex_t *ptexture, qbyte *data, qbyte *pal);
/* HL drawing */
qboolean QDECL Mod_LoadHLModel (model_t *mod, void *buffer, size_t fsize);
void R_DrawHLModel(entity_t *curent);
/* physics stuff */
void *Mod_GetHalfLifeModelData(model_t *mod);
@ -271,7 +289,14 @@ int HLMDL_BoneForName(model_t *mod, const char *name);
int HLMDL_FrameForName(model_t *mod, const char *name);
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);
int HLMDL_GetNumBones(model_t *mod);
int HLMDL_GetNumBones(model_t *mod, qboolean tagstoo);
int HLMDL_GetBoneParent(model_t *mod, int bonenum);
const char *HLMDL_GetBoneName(model_t *mod, int bonenum);
int HLMDL_GetBoneData(model_t *model, int firstbone, int lastbone, framestate_t *fstate, float *result);
int HLMDL_GetAttachment(model_t *model, int tagnum, float *resultmatrix);
#ifndef SERVERONLY
//stuff only useful for clients that need to draw stuff
void R_DrawHLModel(entity_t *curent);
void HLMDL_DrawHitBoxes(entity_t *ent);
#endif

View File

@ -861,4 +861,11 @@ struct shader_field_names_s
extern struct shader_field_names_s shader_field_names[];
extern struct shader_field_names_s shader_unif_names[];
extern struct shader_field_names_s shader_attr_names[];
void CLQ1_DrawLine(shader_t *shader, vec3_t v1, vec3_t v2, float r, float g, float b, float a);
void CLQ1_AddOrientedCube(shader_t *shader, vec3_t mins, vec3_t maxs, float *matrix, float r, float g, float b, float a);
void CL_DrawDebugPlane(float *normal, float dist, float r, float g, float b, qboolean enqueue);
void CLQ1_AddOrientedCylinder(shader_t *shader, float radius, float height, qboolean capsule, float *matrix, float r, float g, float b, float a);
void CLQ1_AddOrientedHalfSphere(shader_t *shader, float radius, float gap, float *matrix, float r, float g, float b, float a);
#endif

View File

@ -1,7 +1,7 @@
#include "progsint.h"
#include "qcc.h"
#ifndef NO_ZLIB
#if !defined(NO_ZLIB) && !defined(FTE_TARGET_WEB)
#define AVAIL_ZLIB
#endif

View File

@ -519,6 +519,12 @@ static void QDECL SVPR_Get_FrameState(world_t *w, wedict_t *ent, framestate_t *f
fstate->g[FS_REG].frame[0] = ent->v->frame;
fstate->g[FS_REG].frametime[0] = ent->xv->frame1time;
fstate->g[FS_REG].lerpweight[0] = 1;
fstate->g[FS_REG].endbone = 0x7fffffff;
fstate->g[FST_BASE].frame[0] = ent->xv->baseframe;
fstate->g[FST_BASE].frametime[0] = ent->xv->/*base*/frame1time;
fstate->g[FST_BASE].lerpweight[0] = 1;
fstate->g[FST_BASE].endbone = ent->xv->basebone;
#if defined(SKELETALOBJECTS) || defined(RAGDOLL)
if (ent->xv->skeletonindex)

View File

@ -135,7 +135,7 @@ qboolean World_BoxTrace(struct model_s *model, int hulloverride, int frame, vec3
VectorCopy (p2, trace->endpos);
return Q1BSP_RecursiveHullCheck (hull, hull->firstclipnode, 0, 1, p1, p2, trace);
}
qboolean World_CapsuleTrace(struct model_s *model, int hulloverride, int frame, vec3_t axis[3], vec3_t p1, vec3_t p2, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int against, struct trace_s *trace)
qboolean World_CapsuleTrace(struct model_s *model, int hulloverride, framestate_t *framestate, vec3_t axis[3], vec3_t p1, vec3_t p2, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int against, struct trace_s *trace)
{
//bbox vs capsule (NYI)
//capsule vs capsule (NYI)
@ -1016,7 +1016,7 @@ qboolean Q1BSP_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f,
//wrapper function. Rotates the start and end positions around the angles if needed.
//qboolean TransformedHullCheck (hull_t *hull, vec3_t start, vec3_t end, trace_t *trace, vec3_t angles)
qboolean World_TransformedTrace (struct model_s *model, int hulloverride, int frame, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, struct trace_s *trace, vec3_t origin, vec3_t angles, unsigned int hitcontentsmask)
qboolean World_TransformedTrace (struct model_s *model, int hulloverride, framestate_t *framestate, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, struct trace_s *trace, vec3_t origin, vec3_t angles, unsigned int hitcontentsmask)
{
vec3_t start_l, end_l;
vec3_t axis[3];
@ -1045,11 +1045,11 @@ qboolean World_TransformedTrace (struct model_s *model, int hulloverride, int fr
{
AngleVectors (angles, axis[0], axis[1], axis[2]);
VectorNegate(axis[1], axis[1]);
result = model->funcs.NativeTrace (model, hulloverride, frame, axis, start_l, end_l, mins, maxs, capsule, hitcontentsmask, trace);
result = model->funcs.NativeTrace (model, hulloverride, framestate, axis, start_l, end_l, mins, maxs, capsule, hitcontentsmask, trace);
}
else
{
result = model->funcs.NativeTrace (model, hulloverride, frame, NULL, start_l, end_l, mins, maxs, capsule, hitcontentsmask, trace);
result = model->funcs.NativeTrace (model, hulloverride, framestate, NULL, start_l, end_l, mins, maxs, capsule, hitcontentsmask, trace);
}
VectorAdd (trace->endpos, origin, trace->endpos);
@ -1083,6 +1083,7 @@ static trace_t World_ClipMoveToEntity (world_t *w, wedict_t *ent, vec3_t eorg, v
trace_t trace;
model_t *model;
int mdlidx = ent->v->modelindex;
framestate_t framestate;
// get the clipping hull
if ((ent->v->solid == SOLID_BSP || ent->v->solid == SOLID_PORTAL) && mdlidx)
@ -1109,11 +1110,13 @@ static trace_t World_ClipMoveToEntity (world_t *w, wedict_t *ent, vec3_t eorg, v
World_HullForBox(boxmins, boxmaxs);
}
w->Get_FrameState(w, ent, &framestate);
// trace a line through the apropriate clipping hull
if (ent->v->solid == SOLID_PORTAL)
{
//solid_portal cares only about origins and as such has no mins/max
World_TransformedTrace(model, 0, ent->v->frame, start, end, vec3_origin, vec3_origin, capsule, &trace, eorg, ent->v->angles, hitcontentsmask);
World_TransformedTrace(model, 0, &framestate, start, end, vec3_origin, vec3_origin, capsule, &trace, eorg, ent->v->angles, hitcontentsmask);
if (trace.startsolid) //portals should not block traces. this prevents infinite looping
trace.startsolid = false;
hitmodel = false;
@ -1121,12 +1124,12 @@ static trace_t World_ClipMoveToEntity (world_t *w, wedict_t *ent, vec3_t eorg, v
else if (ent->v->solid != SOLID_BSP)
{
ent->v->angles[0]*=-1; //carmack made bsp models rotate wrongly.
World_TransformedTrace(model, hullnum, ent->v->frame, start, end, mins, maxs, capsule, &trace, eorg, ent->v->angles, hitcontentsmask);
World_TransformedTrace(model, hullnum, &framestate, start, end, mins, maxs, capsule, &trace, eorg, ent->v->angles, hitcontentsmask);
ent->v->angles[0]*=-1;
}
else
{
World_TransformedTrace(model, hullnum, ent->v->frame, start, end, mins, maxs, capsule, &trace, eorg, ent->v->angles, hitcontentsmask);
World_TransformedTrace(model, hullnum, &framestate, start, end, mins, maxs, capsule, &trace, eorg, ent->v->angles, hitcontentsmask);
}
// if using hitmodel, we know it hit the bounding box, so try a proper trace now.
@ -1138,7 +1141,7 @@ static trace_t World_ClipMoveToEntity (world_t *w, wedict_t *ent, vec3_t eorg, v
if (model && model->funcs.NativeTrace && model->loadstate == MLS_LOADED)
{
//do the second trace, using the actual mesh.
World_TransformedTrace(model, hullnum, ent->v->frame, start, end, mins, maxs, capsule, &trace, eorg, ent->v->angles, hitcontentsmask);
World_TransformedTrace(model, hullnum, &framestate, start, end, mins, maxs, capsule, &trace, eorg, ent->v->angles, hitcontentsmask);
}
}

View File

@ -54,3 +54,6 @@ int emscriptenfte_setupcanvas(
int (*ShouldSwitchToFullscreen)(void)
);
int emscriptenfte_getvrframedata(void);
int emscriptenfte_getvreyedata(int eye, float *projectionmatrix, float *viewmatrix);

View File

@ -151,6 +151,12 @@ mergeInto(LibraryManager.library,
FTEC.pointerislocked = -1; //don't repeat the request on every click. firefox has a fit at that, so require the mouse to leave the element or something before we retry.
Module['canvas'].requestPointerLock();
}
if (FTEC.usevr)
if (FTEC.vrDisplay)
if (!FTEC.vrDisplay.isPresenting)
FTEC.vrDisplay.requestPresent([{ source: Module['canvas'] }]).then(function (){console.log("zomg, presenting!");}, function (err){FTEC.usevr = false;console.log("cannot vrdisplay!");});
//fallthrough
case 'mouseup':
if (FTEC.evcb.button != 0)
@ -272,12 +278,65 @@ mergeInto(LibraryManager.library,
document.webkitPointerLockElement === Module['canvas'];
console.log("Pointer lock now " + FTEC.pointerislocked);
break;
case 'vrdisplaypresentchange':
console.log("vr present changed");
console.log(event);
break;
case 'vrdisplayactivate':
console.log("vr display active");
if (event.display == FTEC.vrDisplay)
{
FTEC.usevr = true;
if (!FTEC.vrDisplay.isPresenting)
FTEC.vrDisplay.requestPresent([{ source: Module['canvas'] }]).then(function (){console.log("zomg, presenting!");}, function (err){FTEC.usevr = false;console.log("cannot vrdisplay!");});
}
break;
case 'vrdisplaydeactivate':
console.log("vr display inactive");
if (event.display == FTEC.vrDisplay)
{
FTEC.vrDisplay.exitPresent()
FTEC.usevr = false;
}
break;
default:
console.log(event);
break;
}
}
},
emscriptenfte_getvrframedata : function()
{
if (!FTEC.vrDisplay)
return 0;
return FTEC.vrDisplay.isPresenting;
// FTEC.vrframeData
},
emscriptenfte_getvreyedata : function (eye, ptr_proj, ptr_view)
{
var pm;
var vm;
if (eye)
{
pm = FTEC.vrframeData.leftProjectionMatrix;
vm = FTEC.vrframeData.leftViewMatrix;
}
else
{
pm = FTEC.vrframeData.rightProjectionMatrix;
vm = FTEC.vrframeData.rightViewMatrix;
}
var i;
ptr_proj /= 4;
ptr_view /= 4;
for (i = 0; i < 16; i++)
{
HEAPF32[ptr_proj + i] = pm[i];
HEAPF32[ptr_view + i] = vm[i];
}
},
emscriptenfte_updatepointerlock : function(wantlock, softcursor)
{
FTEC.pointerwantlock = wantlock;
@ -312,6 +371,8 @@ mergeInto(LibraryManager.library,
var gp = gamepads[i];
if (gp === undefined)
continue;
if (gp == null)
continue;
for (var j = 0; j < gp.buttons.length; j+=1)
{
var b = gp.buttons[j];
@ -348,6 +409,20 @@ mergeInto(LibraryManager.library,
FTEC.evcb.jaxis = evjaxis;
FTEC.evcb.wantfullscreen = evwantfullscreen;
if (navigator.getVRDisplays)
{
FTEC.vrframeData = new VRFrameData();
navigator.getVRDisplays().then(function (displays)
{
if (displays.length > 0)
{
FTEC.vrDisplay = displays[0];
// if (vrDisplay.capabilities.canPresent)
}
})
}
if ('GamepadEvent' in window)
FTEH.gamepads = []; //don't bother ever trying to poll if we can use gamepad events. this will hopefully avoid weirdness.
@ -374,7 +449,7 @@ mergeInto(LibraryManager.library,
document.addEventListener(event, FTEC.handleevent, true);
});
var windowevents = ['message'];
var windowevents = ['message','vrdisplaypresentchange','vrdisplayactivate','vrdisplaydeactivate'];
windowevents.forEach(function(event)
{
window.addEventListener(event, FTEC.handleevent, true);
@ -446,8 +521,16 @@ mergeInto(LibraryManager.library,
Module["sched"] = function()
{
var dovsync = false;
var vr = false;
if (ABORT)
return;
if (FTEC.vrDisplay)
{
vr = FTEC.vrDisplay.isPresenting;
FTEC.vrDisplay.getFrameData(FTEC.vrframeData);
}
try
{
dovsync = Runtime.dynCall('i', fnc, []);
@ -456,8 +539,15 @@ mergeInto(LibraryManager.library,
{
console.log(err);
}
if (vr)
FTEC.vrDisplay.submitFrame();
if (dovsync)
Browser.requestAnimationFrame(Module["sched"]);
{
if (FTEC.vrDisplay)
FTEC.vrDisplay.requestAnimationFrame(Module["sched"]);
else
Browser.requestAnimationFrame(Module["sched"]);
}
else
setTimeout(Module["sched"], 0);
};

View File

@ -40,24 +40,24 @@ static void AVEnc_End (void *ctx);
static AVFrame *alloc_frame(enum AVPixelFormat pix_fmt, int width, int height)
{
AVFrame *picture;
uint8_t *picture_buf;
int size;
AVFrame *picture;
uint8_t *picture_buf;
int size;
picture = av_frame_alloc();
if(!picture)
return NULL;
size = av_image_get_buffer_size(pix_fmt, width, height, 1);
picture_buf = (uint8_t*)(av_malloc(size));
if (!picture_buf)
{
av_free(picture);
return NULL;
}
av_image_fill_arrays(picture->data, picture->linesize, picture_buf, pix_fmt, width, height, 1/*fixme: align*/);
picture->width = width;
picture->height = height;
return picture;
picture = av_frame_alloc();
if(!picture)
return NULL;
size = av_image_get_buffer_size(pix_fmt, width, height, 1);
picture_buf = (uint8_t*)(av_malloc(size));
if (!picture_buf)
{
av_free(picture);
return NULL;
}
av_image_fill_arrays(picture->data, picture->linesize, picture_buf, pix_fmt, width, height, 1/*fixme: align*/);
picture->width = width;
picture->height = height;
return picture;
}
AVStream *add_video_stream(struct encctx *ctx, AVCodec *codec, int fps, int width, int height)
{
@ -502,7 +502,7 @@ static void *AVEnc_Begin (char *streamname, int videorate, int width, int height
Con_DPrintf("avplug: Using Audio Codec \"%s\"\n", audiocodec->name);
else
Con_DPrintf("avplug: Not encoding audio\n");
if (!videocodec && !audiocodec)
{
Con_DPrintf("avplug: Nothing to encode!\n");