From 03d96bff729198228d2030ce3e819893e12ba8ec Mon Sep 17 00:00:00 2001 From: Spoike Date: Mon, 19 Dec 2016 13:31:05 +0000 Subject: [PATCH] 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 --- engine/Makefile | 2 +- engine/client/cl_main.c | 4 + engine/client/m_options.c | 193 +++++++++++++++-- engine/client/r_d3.c | 2 +- engine/client/r_part.c | 2 +- engine/client/render.h | 4 + engine/client/view.c | 4 + engine/common/bothdefs.h | 1 - engine/common/com_mesh.c | 295 +++++++++++++++----------- engine/common/gl_q2bsp.c | 18 +- engine/common/mathlib.c | 67 ++++-- engine/common/mathlib.h | 2 + engine/common/q1bsp.c | 4 +- engine/common/world.h | 2 +- engine/dotnet2005/ftequake.vcproj | 1 - engine/gl/gl_heightmap.c | 14 +- engine/gl/gl_hlmdl.c | 334 +++++++++++++++++++++++++++--- engine/gl/gl_model.h | 8 +- engine/gl/gl_rmain.c | 69 ++++-- engine/gl/model_hl.h | 35 +++- engine/gl/shader.h | 7 + engine/qclib/qcd_main.c | 2 +- engine/server/pr_cmds.c | 6 + engine/server/world.c | 19 +- engine/web/ftejslib.h | 3 + engine/web/ftejslib.js | 94 ++++++++- plugins/avplug/avencode.c | 36 ++-- 27 files changed, 961 insertions(+), 267 deletions(-) diff --git a/engine/Makefile b/engine/Makefile index 89fea4683..03b72d2a9 100644 --- a/engine/Makefile +++ b/engine/Makefile @@ -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 \ diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 60f020561..51dd90dcd 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -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(); { diff --git a/engine/client/m_options.c b/engine/client/m_options.c index c283a1aa5..7758016f4 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -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) diff --git a/engine/client/r_d3.c b/engine/client/r_d3.c index 1e1d1e4d2..85775a5dc 100644 --- a/engine/client/r_d3.c +++ b/engine/client/r_d3.c @@ -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; diff --git a/engine/client/r_part.c b/engine/client/r_part.c index 35890de46..ed115444b 100644 --- a/engine/client/r_part.c +++ b/engine/client/r_part.c @@ -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); diff --git a/engine/client/render.h b/engine/client/render.h index dcda32866..a9d9f5a70 100644 --- a/engine/client/render.h +++ b/engine/client/render.h @@ -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 diff --git a/engine/client/view.c b/engine/client/view.c index 0e0809fe5..fc1ca0d78 100644 --- a/engine/client/view.c +++ b/engine/client/view.c @@ -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; diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index f507bb47d..8cb541033 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -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 diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c index 98c58c4d4..6aaf94997 100644 --- a/engine/common/com_mesh.c +++ b/engine/common/com_mesh.c @@ -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) diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index c2969b3e1..be0f31d08 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -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; } diff --git a/engine/common/mathlib.c b/engine/common/mathlib.c index 16aeeaeb0..e2428abe5 100644 --- a/engine/common/mathlib.c +++ b/engine/common/mathlib.c @@ -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) diff --git a/engine/common/mathlib.h b/engine/common/mathlib.h index 91af269db..acecd9432 100644 --- a/engine/common/mathlib.h +++ b/engine/common/mathlib.h @@ -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); diff --git a/engine/common/q1bsp.c b/engine/common/q1bsp.c index 42ec9e5b4..e8c07eef9 100644 --- a/engine/common/q1bsp.c +++ b/engine/common/q1bsp.c @@ -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; } diff --git a/engine/common/world.h b/engine/common/world.h index f68086c09..463cbe792 100644 --- a/engine/common/world.h +++ b/engine/common/world.h @@ -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: diff --git a/engine/dotnet2005/ftequake.vcproj b/engine/dotnet2005/ftequake.vcproj index 5b9a0bb61..b171902fd 100644 --- a/engine/dotnet2005/ftequake.vcproj +++ b/engine/dotnet2005/ftequake.vcproj @@ -25246,7 +25246,6 @@ 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"); diff --git a/engine/gl/gl_hlmdl.c b/engine/gl/gl_hlmdl.c index 2b927c8c9..1423bf74c 100644 --- a/engine/gl/gl_hlmdl.c +++ b/engine/gl/gl_hlmdl.c @@ -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 diff --git a/engine/gl/gl_model.h b/engine/gl/gl_model.h index 88986285a..fbcc2af4d 100644 --- a/engine/gl/gl_model.h +++ b/engine/gl/gl_model.h @@ -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); diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index 4e5d777c7..eedea479b 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -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) diff --git a/engine/gl/model_hl.h b/engine/gl/model_hl.h index 04025624a..146a9891e 100644 --- a/engine/gl/model_hl.h +++ b/engine/gl/model_hl.h @@ -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 diff --git a/engine/gl/shader.h b/engine/gl/shader.h index 81bc69554..8b99e70a7 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -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 diff --git a/engine/qclib/qcd_main.c b/engine/qclib/qcd_main.c index 4319504c6..56e626592 100644 --- a/engine/qclib/qcd_main.c +++ b/engine/qclib/qcd_main.c @@ -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 diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index efb402958..b579fb40c 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -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) diff --git a/engine/server/world.c b/engine/server/world.c index 39f852e9d..60fb160c9 100644 --- a/engine/server/world.c +++ b/engine/server/world.c @@ -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); } } diff --git a/engine/web/ftejslib.h b/engine/web/ftejslib.h index 9f08245a8..f8143e176 100644 --- a/engine/web/ftejslib.h +++ b/engine/web/ftejslib.h @@ -54,3 +54,6 @@ int emscriptenfte_setupcanvas( int (*ShouldSwitchToFullscreen)(void) ); +int emscriptenfte_getvrframedata(void); +int emscriptenfte_getvreyedata(int eye, float *projectionmatrix, float *viewmatrix); + diff --git a/engine/web/ftejslib.js b/engine/web/ftejslib.js index 16ce85da1..b1bede061 100644 --- a/engine/web/ftejslib.js +++ b/engine/web/ftejslib.js @@ -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); }; diff --git a/plugins/avplug/avencode.c b/plugins/avplug/avencode.c index 85e58918b..4cd7098fc 100644 --- a/plugins/avplug/avencode.c +++ b/plugins/avplug/avencode.c @@ -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");