UNPKG

the-world-engine

Version:

three.js based, unity like game engine for browser

382 lines (341 loc) 13 kB
import { b2_linearSlop, b2_maxPolygonVertices } from "../common/b2_settings.js"; import { b2Abs, b2Max, b2Vec2, b2Rot, b2Transform, b2Sweep } from "../common/b2_math.js"; import { b2Timer } from "../common/b2_timer.js"; import { b2Distance, b2DistanceInput, b2DistanceOutput, b2DistanceProxy, b2SimplexCache } from "./b2_distance.js"; export let b2_toiTime = 0; export let b2_toiMaxTime = 0; export let b2_toiCalls = 0; export let b2_toiIters = 0; export let b2_toiMaxIters = 0; export let b2_toiRootIters = 0; export let b2_toiMaxRootIters = 0; export function b2_toi_reset() { b2_toiTime = 0; b2_toiMaxTime = 0; b2_toiCalls = 0; b2_toiIters = 0; b2_toiMaxIters = 0; b2_toiRootIters = 0; b2_toiMaxRootIters = 0; } const b2TimeOfImpact_s_xfA = new b2Transform; const b2TimeOfImpact_s_xfB = new b2Transform; const b2TimeOfImpact_s_pointA = new b2Vec2; const b2TimeOfImpact_s_pointB = new b2Vec2; const b2TimeOfImpact_s_normal = new b2Vec2; const b2TimeOfImpact_s_axisA = new b2Vec2; const b2TimeOfImpact_s_axisB = new b2Vec2; export class b2TOIInput { constructor() { this.proxyA = new b2DistanceProxy; this.proxyB = new b2DistanceProxy; this.sweepA = new b2Sweep; this.sweepB = new b2Sweep; this.tMax = 0; } } export var b2TOIOutputState; (function(t) { t[t["e_unknown"] = 0] = "e_unknown"; t[t["e_failed"] = 1] = "e_failed"; t[t["e_overlapped"] = 2] = "e_overlapped"; t[t["e_touching"] = 3] = "e_touching"; t[t["e_separated"] = 4] = "e_separated"; })(b2TOIOutputState || (b2TOIOutputState = {})); export class b2TOIOutput { constructor() { this.state = b2TOIOutputState.e_unknown; this.t = 0; } } export var b2SeparationFunctionType; (function(t) { t[t["e_unknown"] = -1] = "e_unknown"; t[t["e_points"] = 0] = "e_points"; t[t["e_faceA"] = 1] = "e_faceA"; t[t["e_faceB"] = 2] = "e_faceB"; })(b2SeparationFunctionType || (b2SeparationFunctionType = {})); export class b2SeparationFunction { constructor() { this.m_sweepA = new b2Sweep; this.m_sweepB = new b2Sweep; this.m_type = b2SeparationFunctionType.e_unknown; this.m_localPoint = new b2Vec2; this.m_axis = new b2Vec2; } Initialize(t, e, s, i, o, n) { this.m_proxyA = e; this.m_proxyB = i; const c = t.count; this.m_sweepA.Copy(s); this.m_sweepB.Copy(o); const b = b2TimeOfImpact_s_xfA; const a = b2TimeOfImpact_s_xfB; this.m_sweepA.GetTransform(b, n); this.m_sweepB.GetTransform(a, n); if (c === 1) { this.m_type = b2SeparationFunctionType.e_points; const e = this.m_proxyA.GetVertex(t.indexA[0]); const s = this.m_proxyB.GetVertex(t.indexB[0]); const i = b2Transform.MulXV(b, e, b2TimeOfImpact_s_pointA); const o = b2Transform.MulXV(a, s, b2TimeOfImpact_s_pointB); b2Vec2.SubVV(o, i, this.m_axis); const n = this.m_axis.Normalize(); this.m_localPoint.SetZero(); return n; } else if (t.indexA[0] === t.indexA[1]) { this.m_type = b2SeparationFunctionType.e_faceB; const e = this.m_proxyB.GetVertex(t.indexB[0]); const s = this.m_proxyB.GetVertex(t.indexB[1]); b2Vec2.CrossVOne(b2Vec2.SubVV(s, e, b2Vec2.s_t0), this.m_axis).SelfNormalize(); const i = b2Rot.MulRV(a.q, this.m_axis, b2TimeOfImpact_s_normal); b2Vec2.MidVV(e, s, this.m_localPoint); const o = b2Transform.MulXV(a, this.m_localPoint, b2TimeOfImpact_s_pointB); const n = this.m_proxyA.GetVertex(t.indexA[0]); const c = b2Transform.MulXV(b, n, b2TimeOfImpact_s_pointA); let m = b2Vec2.DotVV(b2Vec2.SubVV(c, o, b2Vec2.s_t0), i); if (m < 0) { this.m_axis.SelfNeg(); m = -m; } return m; } else { this.m_type = b2SeparationFunctionType.e_faceA; const e = this.m_proxyA.GetVertex(t.indexA[0]); const s = this.m_proxyA.GetVertex(t.indexA[1]); b2Vec2.CrossVOne(b2Vec2.SubVV(s, e, b2Vec2.s_t0), this.m_axis).SelfNormalize(); const i = b2Rot.MulRV(b.q, this.m_axis, b2TimeOfImpact_s_normal); b2Vec2.MidVV(e, s, this.m_localPoint); const o = b2Transform.MulXV(b, this.m_localPoint, b2TimeOfImpact_s_pointA); const n = this.m_proxyB.GetVertex(t.indexB[0]); const c = b2Transform.MulXV(a, n, b2TimeOfImpact_s_pointB); let m = b2Vec2.DotVV(b2Vec2.SubVV(c, o, b2Vec2.s_t0), i); if (m < 0) { this.m_axis.SelfNeg(); m = -m; } return m; } } FindMinSeparation(t, e, s) { const i = b2TimeOfImpact_s_xfA; const o = b2TimeOfImpact_s_xfB; this.m_sweepA.GetTransform(i, s); this.m_sweepB.GetTransform(o, s); switch (this.m_type) { case b2SeparationFunctionType.e_points: { const s = b2Rot.MulTRV(i.q, this.m_axis, b2TimeOfImpact_s_axisA); const n = b2Rot.MulTRV(o.q, b2Vec2.NegV(this.m_axis, b2Vec2.s_t0), b2TimeOfImpact_s_axisB); t[0] = this.m_proxyA.GetSupport(s); e[0] = this.m_proxyB.GetSupport(n); const c = this.m_proxyA.GetVertex(t[0]); const b = this.m_proxyB.GetVertex(e[0]); const a = b2Transform.MulXV(i, c, b2TimeOfImpact_s_pointA); const m = b2Transform.MulXV(o, b, b2TimeOfImpact_s_pointB); const p = b2Vec2.DotVV(b2Vec2.SubVV(m, a, b2Vec2.s_t0), this.m_axis); return p; } case b2SeparationFunctionType.e_faceA: { const s = b2Rot.MulRV(i.q, this.m_axis, b2TimeOfImpact_s_normal); const n = b2Transform.MulXV(i, this.m_localPoint, b2TimeOfImpact_s_pointA); const c = b2Rot.MulTRV(o.q, b2Vec2.NegV(s, b2Vec2.s_t0), b2TimeOfImpact_s_axisB); t[0] = -1; e[0] = this.m_proxyB.GetSupport(c); const b = this.m_proxyB.GetVertex(e[0]); const a = b2Transform.MulXV(o, b, b2TimeOfImpact_s_pointB); const m = b2Vec2.DotVV(b2Vec2.SubVV(a, n, b2Vec2.s_t0), s); return m; } case b2SeparationFunctionType.e_faceB: { const s = b2Rot.MulRV(o.q, this.m_axis, b2TimeOfImpact_s_normal); const n = b2Transform.MulXV(o, this.m_localPoint, b2TimeOfImpact_s_pointB); const c = b2Rot.MulTRV(i.q, b2Vec2.NegV(s, b2Vec2.s_t0), b2TimeOfImpact_s_axisA); e[0] = -1; t[0] = this.m_proxyA.GetSupport(c); const b = this.m_proxyA.GetVertex(t[0]); const a = b2Transform.MulXV(i, b, b2TimeOfImpact_s_pointA); const m = b2Vec2.DotVV(b2Vec2.SubVV(a, n, b2Vec2.s_t0), s); return m; } default: t[0] = -1; e[0] = -1; return 0; } } Evaluate(t, e, s) { const i = b2TimeOfImpact_s_xfA; const o = b2TimeOfImpact_s_xfB; this.m_sweepA.GetTransform(i, s); this.m_sweepB.GetTransform(o, s); switch (this.m_type) { case b2SeparationFunctionType.e_points: { const s = this.m_proxyA.GetVertex(t); const n = this.m_proxyB.GetVertex(e); const c = b2Transform.MulXV(i, s, b2TimeOfImpact_s_pointA); const b = b2Transform.MulXV(o, n, b2TimeOfImpact_s_pointB); const a = b2Vec2.DotVV(b2Vec2.SubVV(b, c, b2Vec2.s_t0), this.m_axis); return a; } case b2SeparationFunctionType.e_faceA: { const t = b2Rot.MulRV(i.q, this.m_axis, b2TimeOfImpact_s_normal); const s = b2Transform.MulXV(i, this.m_localPoint, b2TimeOfImpact_s_pointA); const n = this.m_proxyB.GetVertex(e); const c = b2Transform.MulXV(o, n, b2TimeOfImpact_s_pointB); const b = b2Vec2.DotVV(b2Vec2.SubVV(c, s, b2Vec2.s_t0), t); return b; } case b2SeparationFunctionType.e_faceB: { const e = b2Rot.MulRV(o.q, this.m_axis, b2TimeOfImpact_s_normal); const s = b2Transform.MulXV(o, this.m_localPoint, b2TimeOfImpact_s_pointB); const n = this.m_proxyA.GetVertex(t); const c = b2Transform.MulXV(i, n, b2TimeOfImpact_s_pointA); const b = b2Vec2.DotVV(b2Vec2.SubVV(c, s, b2Vec2.s_t0), e); return b; } default: return 0; } } } const b2TimeOfImpact_s_timer = new b2Timer; const b2TimeOfImpact_s_cache = new b2SimplexCache; const b2TimeOfImpact_s_distanceInput = new b2DistanceInput; const b2TimeOfImpact_s_distanceOutput = new b2DistanceOutput; const b2TimeOfImpact_s_fcn = new b2SeparationFunction; const b2TimeOfImpact_s_indexA = [ 0 ]; const b2TimeOfImpact_s_indexB = [ 0 ]; const b2TimeOfImpact_s_sweepA = new b2Sweep; const b2TimeOfImpact_s_sweepB = new b2Sweep; export function b2TimeOfImpact(t, e) { const s = b2TimeOfImpact_s_timer.Reset(); ++b2_toiCalls; t.state = b2TOIOutputState.e_unknown; t.t = e.tMax; const i = e.proxyA; const o = e.proxyB; const n = b2Max(b2_maxPolygonVertices, b2Max(i.m_count, o.m_count)); const c = b2TimeOfImpact_s_sweepA.Copy(e.sweepA); const b = b2TimeOfImpact_s_sweepB.Copy(e.sweepB); c.Normalize(); b.Normalize(); const a = e.tMax; const m = i.m_radius + o.m_radius; const p = b2Max(b2_linearSlop, m - 3 * b2_linearSlop); const _ = .25 * b2_linearSlop; let r = 0; const f = 20; let T = 0; const I = b2TimeOfImpact_s_cache; I.count = 0; const O = b2TimeOfImpact_s_distanceInput; O.proxyA.Copy(e.proxyA); O.proxyB.Copy(e.proxyB); O.useRadii = false; for (;;) { const e = b2TimeOfImpact_s_xfA; const s = b2TimeOfImpact_s_xfB; c.GetTransform(e, r); b.GetTransform(s, r); O.transformA.Copy(e); O.transformB.Copy(s); const m = b2TimeOfImpact_s_distanceOutput; b2Distance(m, I, O); if (m.distance <= 0) { t.state = b2TOIOutputState.e_overlapped; t.t = 0; break; } if (m.distance < p + _) { t.state = b2TOIOutputState.e_touching; t.t = r; break; } const h = b2TimeOfImpact_s_fcn; h.Initialize(I, i, c, o, b, r); let u = false; let l = a; let x = 0; for (;;) { const e = b2TimeOfImpact_s_indexA; const s = b2TimeOfImpact_s_indexB; let i = h.FindMinSeparation(e, s, l); if (i > p + _) { t.state = b2TOIOutputState.e_separated; t.t = a; u = true; break; } if (i > p - _) { r = l; break; } let o = h.Evaluate(e[0], s[0], r); if (o < p - _) { t.state = b2TOIOutputState.e_failed; t.t = r; u = true; break; } if (o <= p + _) { t.state = b2TOIOutputState.e_touching; t.t = r; u = true; break; } let c = 0; let b = r; let m = l; for (;;) { let t = 0; if (c & 1) { t = b + (p - o) * (m - b) / (i - o); } else { t = .5 * (b + m); } ++c; ++b2_toiRootIters; const n = h.Evaluate(e[0], s[0], t); if (b2Abs(n - p) < _) { l = t; break; } if (n > p) { b = t; o = n; } else { m = t; i = n; } if (c === 50) { break; } } b2_toiMaxRootIters = b2Max(b2_toiMaxRootIters, c); ++x; if (x === n) { break; } } ++T; ++b2_toiIters; if (u) { break; } if (T === f) { t.state = b2TOIOutputState.e_failed; t.t = r; break; } } b2_toiMaxIters = b2Max(b2_toiMaxIters, T); const h = s.GetMilliseconds(); b2_toiMaxTime = b2Max(b2_toiMaxTime, h); b2_toiTime += h; }