the-world-engine
Version:
three.js based, unity like game engine for browser
524 lines (492 loc) • 15.4 kB
JavaScript
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;
}