/// <summary> /// SV_HullPointContents /// </summary> static int HullPointContents(hull_t hull, int num, ref Vector3 p) { while (num >= 0) { if (num < hull.firstclipnode || num > hull.lastclipnode) { Sys.Error("SV_HullPointContents: bad node number"); } short[] node_children = hull.clipnodes[num].children; mplane_t plane = hull.planes[hull.clipnodes[num].planenum]; float d; if (plane.type < 3) { d = Mathlib.Comp(ref p, plane.type) - plane.dist; } else { d = Vector3.Dot(plane.normal, p) - plane.dist; } if (d < 0) { num = node_children[1]; } else { num = node_children[0]; } } return(num); }
/// <summary> /// SV_ClipMoveToEntity /// Handles selection or creation of a clipping hull, and offseting (and /// eventually rotation) of the end points /// </summary> static trace_t ClipMoveToEntity(edict_t ent, ref Vector3 start, ref Vector3 mins, ref Vector3 maxs, ref Vector3 end) { trace_t trace = new trace_t(); // fill in a default trace trace.fraction = 1; trace.allsolid = true; trace.endpos = end; // get the clipping hull Vector3 offset; hull_t hull = HullForEntity(ent, ref mins, ref maxs, out offset); Vector3 start_l = start - offset; Vector3 end_l = end - offset; // trace a line through the apropriate clipping hull RecursiveHullCheck(hull, hull.firstclipnode, 0, 1, ref start_l, ref end_l, trace); // fix trace up by the offset if (trace.fraction != 1) { trace.endpos += offset; } // did we clip the move? if (trace.fraction < 1 || trace.startsolid) { trace.ent = ent; } return(trace); }
public void CopyFrom(hull_t src) { this.clipnodes = src.clipnodes; this.planes = src.planes; this.firstclipnode = src.firstclipnode; this.lastclipnode = src.lastclipnode; this.clip_mins = src.clip_mins; this.clip_maxs = src.clip_maxs; }
/// <summary> /// SV_HullForEntity /// Returns a hull that can be used for testing or clipping an object of mins/maxs size. /// Offset is filled in to contain the adjustment that must be added to the /// testing object's origin to get a point to use with the returned hull. /// </summary> static hull_t HullForEntity(edict_t ent, ref Vector3 mins, ref Vector3 maxs, out Vector3 offset) { hull_t hull = null; // decide which clipping hull to use, based on the size if (ent.v.solid == Solids.SOLID_BSP) { // explicit hulls in the BSP model if (ent.v.movetype != Movetypes.MOVETYPE_PUSH) { Sys.Error("SOLID_BSP without MOVETYPE_PUSH"); } model_t model = sv.models[(int)ent.v.modelindex]; if (model == null || model.type != modtype_t.mod_brush) { Sys.Error("MOVETYPE_PUSH with a non bsp model"); } Vector3 size = maxs - mins; if (size.X < 3) { hull = model.hulls[0]; } else if (size.X <= 32) { hull = model.hulls[1]; } else { hull = model.hulls[2]; } // calculate an offset value to center the origin offset = hull.clip_mins - mins; offset += Common.ToVector(ref ent.v.origin); } else { // create a temp hull from bounding box sizes Vector3 hullmins = Common.ToVector(ref ent.v.mins) - maxs; Vector3 hullmaxs = Common.ToVector(ref ent.v.maxs) - mins; hull = HullForBox(ref hullmins, ref hullmaxs); offset = Common.ToVector(ref ent.v.origin); } return(hull); }
/// <summary> /// SV_RecursiveHullCheck /// </summary> public static bool RecursiveHullCheck(hull_t hull, int num, float p1f, float p2f, ref Vector3 p1, ref Vector3 p2, trace_t trace) { // check for empty if (num < 0) { if (num != Contents.CONTENTS_SOLID) { trace.allsolid = false; if (num == Contents.CONTENTS_EMPTY) { trace.inopen = true; } else { trace.inwater = true; } } else { trace.startsolid = true; } return(true); // empty } if (num < hull.firstclipnode || num > hull.lastclipnode) { Sys.Error("SV_RecursiveHullCheck: bad node number"); } // // find the point distances // short[] node_children = hull.clipnodes[num].children; mplane_t plane = hull.planes[hull.clipnodes[num].planenum]; float t1, t2; if (plane.type < 3) { t1 = Mathlib.Comp(ref p1, plane.type) - plane.dist; t2 = Mathlib.Comp(ref p2, plane.type) - plane.dist; } else { t1 = Vector3.Dot(plane.normal, p1) - plane.dist; t2 = Vector3.Dot(plane.normal, p2) - plane.dist; } if (t1 >= 0 && t2 >= 0) { return(RecursiveHullCheck(hull, node_children[0], p1f, p2f, ref p1, ref p2, trace)); } if (t1 < 0 && t2 < 0) { return(RecursiveHullCheck(hull, node_children[1], p1f, p2f, ref p1, ref p2, trace)); } // put the crosspoint DIST_EPSILON pixels on the near side float frac; if (t1 < 0) { frac = (t1 + DIST_EPSILON) / (t1 - t2); } else { frac = (t1 - DIST_EPSILON) / (t1 - t2); } if (frac < 0) { frac = 0; } if (frac > 1) { frac = 1; } float midf = p1f + (p2f - p1f) * frac; Vector3 mid = p1 + (p2 - p1) * frac; int side = (t1 < 0) ? 1 : 0; // move up to the node if (!RecursiveHullCheck(hull, node_children[side], p1f, midf, ref p1, ref mid, trace)) { return(false); } if (HullPointContents(hull, node_children[side ^ 1], ref mid) != Contents.CONTENTS_SOLID) { // go past the node return(RecursiveHullCheck(hull, node_children[side ^ 1], midf, p2f, ref mid, ref p2, trace)); } if (trace.allsolid) { return(false); // never got out of the solid area } //================== // the other side of the node is solid, this is the impact point //================== if (side == 0) { trace.plane.normal = plane.normal; trace.plane.dist = plane.dist; } else { trace.plane.normal = -plane.normal; trace.plane.dist = -plane.dist; } while (HullPointContents(hull, hull.firstclipnode, ref mid) == Contents.CONTENTS_SOLID) { // shouldn't really happen, but does occasionally frac -= 0.1f; if (frac < 0) { trace.fraction = midf; trace.endpos = mid; Con.DPrint("backup past 0\n"); return(false); } midf = p1f + (p2f - p1f) * frac; mid = p1 + (p2 - p1) * frac; } trace.fraction = midf; trace.endpos = mid; return(false); }