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