UNPKG

the-world-engine

Version:

three.js based, unity like game engine for browser

524 lines (492 loc) 15.4 kB
import { b2_maxFloat, b2_epsilon, b2_epsilon_sq, b2_maxManifoldPoints, b2MakeArray, b2MakeNumberArray } from "../common/b2_settings.js"; import { b2Abs, b2Min, b2Max, b2Vec2, b2Rot, b2Transform } from "../common/b2_math.js"; import { b2Distance, b2DistanceInput, b2DistanceOutput, b2SimplexCache } from "./b2_distance.js"; export var b2ContactFeatureType; (function(t) { t[t["e_vertex"] = 0] = "e_vertex"; t[t["e_face"] = 1] = "e_face"; })(b2ContactFeatureType || (b2ContactFeatureType = {})); export class b2ContactFeature { constructor() { this._key = 0; this._key_invalid = false; this._indexA = 0; this._indexB = 0; this._typeA = 0; this._typeB = 0; } get key() { if (this._key_invalid) { this._key_invalid = false; this._key = this._indexA | this._indexB << 8 | this._typeA << 16 | this._typeB << 24; } return this._key; } set key(t) { this._key = t; this._key_invalid = false; this._indexA = this._key & 255; this._indexB = this._key >> 8 & 255; this._typeA = this._key >> 16 & 255; this._typeB = this._key >> 24 & 255; } get indexA() { return this._indexA; } set indexA(t) { this._indexA = t; this._key_invalid = true; } get indexB() { return this._indexB; } set indexB(t) { this._indexB = t; this._key_invalid = true; } get typeA() { return this._typeA; } set typeA(t) { this._typeA = t; this._key_invalid = true; } get typeB() { return this._typeB; } set typeB(t) { this._typeB = t; this._key_invalid = true; } } export class b2ContactID { constructor() { this.cf = new b2ContactFeature; } Copy(t) { this.key = t.key; return this; } Clone() { return (new b2ContactID).Copy(this); } get key() { return this.cf.key; } set key(t) { this.cf.key = t; } } export class b2ManifoldPoint { constructor() { this.localPoint = new b2Vec2; this.normalImpulse = 0; this.tangentImpulse = 0; this.id = new b2ContactID; } static MakeArray(t) { return b2MakeArray(t, (t => new b2ManifoldPoint)); } Reset() { this.localPoint.SetZero(); this.normalImpulse = 0; this.tangentImpulse = 0; this.id.key = 0; } Copy(t) { this.localPoint.Copy(t.localPoint); this.normalImpulse = t.normalImpulse; this.tangentImpulse = t.tangentImpulse; this.id.Copy(t.id); return this; } } export var b2ManifoldType; (function(t) { t[t["e_unknown"] = -1] = "e_unknown"; t[t["e_circles"] = 0] = "e_circles"; t[t["e_faceA"] = 1] = "e_faceA"; t[t["e_faceB"] = 2] = "e_faceB"; })(b2ManifoldType || (b2ManifoldType = {})); export class b2Manifold { constructor() { this.points = b2ManifoldPoint.MakeArray(b2_maxManifoldPoints); this.localNormal = new b2Vec2; this.localPoint = new b2Vec2; this.type = b2ManifoldType.e_unknown; this.pointCount = 0; } Reset() { for (let t = 0; t < b2_maxManifoldPoints; ++t) { this.points[t].Reset(); } this.localNormal.SetZero(); this.localPoint.SetZero(); this.type = b2ManifoldType.e_unknown; this.pointCount = 0; } Copy(t) { this.pointCount = t.pointCount; for (let e = 0; e < b2_maxManifoldPoints; ++e) { this.points[e].Copy(t.points[e]); } this.localNormal.Copy(t.localNormal); this.localPoint.Copy(t.localPoint); this.type = t.type; return this; } Clone() { return (new b2Manifold).Copy(this); } } export class b2WorldManifold { constructor() { this.normal = new b2Vec2; this.points = b2Vec2.MakeArray(b2_maxManifoldPoints); this.separations = b2MakeNumberArray(b2_maxManifoldPoints); } Initialize(t, e, s, i, n) { if (t.pointCount === 0) { return; } switch (t.type) { case b2ManifoldType.e_circles: { this.normal.Set(1, 0); const r = b2Transform.MulXV(e, t.localPoint, b2WorldManifold.Initialize_s_pointA); const o = b2Transform.MulXV(i, t.points[0].localPoint, b2WorldManifold.Initialize_s_pointB); if (b2Vec2.DistanceSquaredVV(r, o) > b2_epsilon_sq) { b2Vec2.SubVV(o, r, this.normal).SelfNormalize(); } const a = b2Vec2.AddVMulSV(r, s, this.normal, b2WorldManifold.Initialize_s_cA); const b = b2Vec2.SubVMulSV(o, n, this.normal, b2WorldManifold.Initialize_s_cB); b2Vec2.MidVV(a, b, this.points[0]); this.separations[0] = b2Vec2.DotVV(b2Vec2.SubVV(b, a, b2Vec2.s_t0), this.normal); break; } case b2ManifoldType.e_faceA: { b2Rot.MulRV(e.q, t.localNormal, this.normal); const r = b2Transform.MulXV(e, t.localPoint, b2WorldManifold.Initialize_s_planePoint); for (let e = 0; e < t.pointCount; ++e) { const o = b2Transform.MulXV(i, t.points[e].localPoint, b2WorldManifold.Initialize_s_clipPoint); const a = s - b2Vec2.DotVV(b2Vec2.SubVV(o, r, b2Vec2.s_t0), this.normal); const b = b2Vec2.AddVMulSV(o, a, this.normal, b2WorldManifold.Initialize_s_cA); const h = b2Vec2.SubVMulSV(o, n, this.normal, b2WorldManifold.Initialize_s_cB); b2Vec2.MidVV(b, h, this.points[e]); this.separations[e] = b2Vec2.DotVV(b2Vec2.SubVV(h, b, b2Vec2.s_t0), this.normal); } break; } case b2ManifoldType.e_faceB: { b2Rot.MulRV(i.q, t.localNormal, this.normal); const r = b2Transform.MulXV(i, t.localPoint, b2WorldManifold.Initialize_s_planePoint); for (let i = 0; i < t.pointCount; ++i) { const o = b2Transform.MulXV(e, t.points[i].localPoint, b2WorldManifold.Initialize_s_clipPoint); const a = n - b2Vec2.DotVV(b2Vec2.SubVV(o, r, b2Vec2.s_t0), this.normal); const b = b2Vec2.AddVMulSV(o, a, this.normal, b2WorldManifold.Initialize_s_cB); const h = b2Vec2.SubVMulSV(o, s, this.normal, b2WorldManifold.Initialize_s_cA); b2Vec2.MidVV(h, b, this.points[i]); this.separations[i] = b2Vec2.DotVV(b2Vec2.SubVV(h, b, b2Vec2.s_t0), this.normal); } this.normal.SelfNeg(); break; } } } } b2WorldManifold.Initialize_s_pointA = new b2Vec2; b2WorldManifold.Initialize_s_pointB = new b2Vec2; b2WorldManifold.Initialize_s_cA = new b2Vec2; b2WorldManifold.Initialize_s_cB = new b2Vec2; b2WorldManifold.Initialize_s_planePoint = new b2Vec2; b2WorldManifold.Initialize_s_clipPoint = new b2Vec2; export var b2PointState; (function(t) { t[t["b2_nullState"] = 0] = "b2_nullState"; t[t["b2_addState"] = 1] = "b2_addState"; t[t["b2_persistState"] = 2] = "b2_persistState"; t[t["b2_removeState"] = 3] = "b2_removeState"; })(b2PointState || (b2PointState = {})); export function b2GetPointStates(t, e, s, i) { let n; for (n = 0; n < s.pointCount; ++n) { const e = s.points[n].id; const r = e.key; t[n] = b2PointState.b2_removeState; for (let e = 0, s = i.pointCount; e < s; ++e) { if (i.points[e].id.key === r) { t[n] = b2PointState.b2_persistState; break; } } } for (;n < b2_maxManifoldPoints; ++n) { t[n] = b2PointState.b2_nullState; } for (n = 0; n < i.pointCount; ++n) { const t = i.points[n].id; const r = t.key; e[n] = b2PointState.b2_addState; for (let t = 0, i = s.pointCount; t < i; ++t) { if (s.points[t].id.key === r) { e[n] = b2PointState.b2_persistState; break; } } } for (;n < b2_maxManifoldPoints; ++n) { e[n] = b2PointState.b2_nullState; } } export class b2ClipVertex { constructor() { this.v = new b2Vec2; this.id = new b2ContactID; } static MakeArray(t) { return b2MakeArray(t, (t => new b2ClipVertex)); } Copy(t) { this.v.Copy(t.v); this.id.Copy(t.id); return this; } } export class b2RayCastInput { constructor() { this.p1 = new b2Vec2; this.p2 = new b2Vec2; this.maxFraction = 1; } Copy(t) { this.p1.Copy(t.p1); this.p2.Copy(t.p2); this.maxFraction = t.maxFraction; return this; } } export class b2RayCastOutput { constructor() { this.normal = new b2Vec2; this.fraction = 0; } Copy(t) { this.normal.Copy(t.normal); this.fraction = t.fraction; return this; } } export class b2AABB { constructor() { this.lowerBound = new b2Vec2; this.upperBound = new b2Vec2; this.m_cache_center = new b2Vec2; this.m_cache_extent = new b2Vec2; } Copy(t) { this.lowerBound.Copy(t.lowerBound); this.upperBound.Copy(t.upperBound); return this; } IsValid() { if (!this.lowerBound.IsValid()) { return false; } if (!this.upperBound.IsValid()) { return false; } if (this.upperBound.x < this.lowerBound.x) { return false; } if (this.upperBound.y < this.lowerBound.y) { return false; } return true; } GetCenter() { return b2Vec2.MidVV(this.lowerBound, this.upperBound, this.m_cache_center); } GetExtents() { return b2Vec2.ExtVV(this.lowerBound, this.upperBound, this.m_cache_extent); } GetPerimeter() { const t = this.upperBound.x - this.lowerBound.x; const e = this.upperBound.y - this.lowerBound.y; return 2 * (t + e); } Combine1(t) { this.lowerBound.x = b2Min(this.lowerBound.x, t.lowerBound.x); this.lowerBound.y = b2Min(this.lowerBound.y, t.lowerBound.y); this.upperBound.x = b2Max(this.upperBound.x, t.upperBound.x); this.upperBound.y = b2Max(this.upperBound.y, t.upperBound.y); return this; } Combine2(t, e) { this.lowerBound.x = b2Min(t.lowerBound.x, e.lowerBound.x); this.lowerBound.y = b2Min(t.lowerBound.y, e.lowerBound.y); this.upperBound.x = b2Max(t.upperBound.x, e.upperBound.x); this.upperBound.y = b2Max(t.upperBound.y, e.upperBound.y); return this; } static Combine(t, e, s) { s.Combine2(t, e); return s; } Contains(t) { let e = true; e = e && this.lowerBound.x <= t.lowerBound.x; e = e && this.lowerBound.y <= t.lowerBound.y; e = e && t.upperBound.x <= this.upperBound.x; e = e && t.upperBound.y <= this.upperBound.y; return e; } RayCast(t, e) { let s = -b2_maxFloat; let i = b2_maxFloat; const n = e.p1.x; const r = e.p1.y; const o = e.p2.x - e.p1.x; const a = e.p2.y - e.p1.y; const b = b2Abs(o); const h = b2Abs(a); const c = t.normal; if (b < b2_epsilon) { if (n < this.lowerBound.x || this.upperBound.x < n) { return false; } } else { const t = 1 / o; let e = (this.lowerBound.x - n) * t; let r = (this.upperBound.x - n) * t; let a = -1; if (e > r) { const t = e; e = r; r = t; a = 1; } if (e > s) { c.x = a; c.y = 0; s = e; } i = b2Min(i, r); if (s > i) { return false; } } if (h < b2_epsilon) { if (r < this.lowerBound.y || this.upperBound.y < r) { return false; } } else { const t = 1 / a; let e = (this.lowerBound.y - r) * t; let n = (this.upperBound.y - r) * t; let o = -1; if (e > n) { const t = e; e = n; n = t; o = 1; } if (e > s) { c.x = 0; c.y = o; s = e; } i = b2Min(i, n); if (s > i) { return false; } } if (s < 0 || e.maxFraction < s) { return false; } t.fraction = s; return true; } TestContain(t) { if (t.x < this.lowerBound.x || this.upperBound.x < t.x) { return false; } if (t.y < this.lowerBound.y || this.upperBound.y < t.y) { return false; } return true; } TestOverlap(t) { if (this.upperBound.x < t.lowerBound.x) { return false; } if (this.upperBound.y < t.lowerBound.y) { return false; } if (t.upperBound.x < this.lowerBound.x) { return false; } if (t.upperBound.y < this.lowerBound.y) { return false; } return true; } } export function b2TestOverlapAABB(t, e) { if (t.upperBound.x < e.lowerBound.x) { return false; } if (t.upperBound.y < e.lowerBound.y) { return false; } if (e.upperBound.x < t.lowerBound.x) { return false; } if (e.upperBound.y < t.lowerBound.y) { return false; } return true; } export function b2ClipSegmentToLine(t, e, s, i, n) { let r = 0; const o = e[0]; const a = e[1]; const b = b2Vec2.DotVV(s, o.v) - i; const h = b2Vec2.DotVV(s, a.v) - i; if (b <= 0) { t[r++].Copy(o); } if (h <= 0) { t[r++].Copy(a); } if (b * h < 0) { const e = b / (b - h); const s = t[r].v; s.x = o.v.x + e * (a.v.x - o.v.x); s.y = o.v.y + e * (a.v.y - o.v.y); const i = t[r].id; i.cf.indexA = n; i.cf.indexB = o.id.cf.indexB; i.cf.typeA = b2ContactFeatureType.e_vertex; i.cf.typeB = b2ContactFeatureType.e_face; ++r; } return r; } const b2TestOverlapShape_s_input = new b2DistanceInput; const b2TestOverlapShape_s_simplexCache = new b2SimplexCache; const b2TestOverlapShape_s_output = new b2DistanceOutput; export function b2TestOverlapShape(t, e, s, i, n, r) { const o = b2TestOverlapShape_s_input.Reset(); o.proxyA.SetShape(t, e); o.proxyB.SetShape(s, i); o.transformA.Copy(n); o.transformB.Copy(r); o.useRadii = true; const a = b2TestOverlapShape_s_simplexCache.Reset(); a.count = 0; const b = b2TestOverlapShape_s_output.Reset(); b2Distance(b, a, o); return b.distance < 10 * b2_epsilon; }