the-world-engine
Version:
three.js based, unity like game engine for browser
1,359 lines (1,329 loc) • 130 kB
JavaScript
import { b2_linearSlop, b2_maxFloat, b2_invalidParticleIndex, b2_minParticleSystemBufferCapacity, b2_maxTriadDistanceSquared, b2_barrierCollisionTime, b2MakeArray, b2Maybe } from "../common/b2_settings.js";
import { b2_maxParticlePressure, b2_minParticleWeight, b2_maxParticleForce, b2_particleStride } from "../common/b2_settings.js";
import { b2Min, b2Max, b2Abs, b2Clamp, b2Sqrt, b2InvSqrt, b2Vec2, b2TypedVec2, b2Rot, b2Transform } from "../common/b2_math.js";
import { b2Color, b2TypedColor } from "../common/b2_draw.js";
import { b2AABB, b2RayCastInput, b2RayCastOutput } from "../collision/b2_collision.js";
import { b2ShapeType, b2Shape } from "../collision/b2_shape.js";
import { b2EdgeShape } from "../collision/b2_edge_shape.js";
import { b2TimeStep } from "../dynamics/b2_time_step.js";
import { b2QueryCallback } from "../dynamics/b2_world_callbacks.js";
import { b2ParticleFlag, b2ParticleDef, b2ParticleHandle } from "./b2_particle.js";
import { b2ParticleGroupFlag, b2ParticleGroupDef, b2ParticleGroup } from "./b2_particle_group.js";
import { b2VoronoiDiagram } from "./b2_voronoi_diagram.js";
function std_iter_swap(t, s, i) {
const e = t[s];
t[s] = t[i];
t[i] = e;
}
function default_compare(t, s) {
return t < s;
}
function std_sort(t, s = 0, i = t.length - s, e = default_compare) {
let c = s;
const r = [];
let n = 0;
for (;;) {
for (;c + 1 < i; i++) {
const s = t[c + Math.floor(Math.random() * (i - c))];
r[n++] = i;
for (let r = c - 1; ;) {
while (e(t[++r], s)) {}
while (e(s, t[--i])) {}
if (r >= i) {
break;
}
std_iter_swap(t, r, i);
}
}
if (n === 0) {
break;
}
c = i;
i = r[--n];
}
return t;
}
function std_stable_sort(t, s = 0, i = t.length - s, e = default_compare) {
return std_sort(t, s, i, e);
}
function std_remove_if(t, s, i = t.length) {
let e = 0;
for (let c = 0; c < i; ++c) {
if (s(t[c])) {
continue;
}
if (c === e) {
++e;
continue;
}
std_iter_swap(t, e++, c);
}
return e;
}
function std_lower_bound(t, s, i, e, c) {
let r = i - s;
while (r > 0) {
const i = Math.floor(r / 2);
let n = s + i;
if (c(t[n], e)) {
s = ++n;
r -= i + 1;
} else {
r = i;
}
}
return s;
}
function std_upper_bound(t, s, i, e, c) {
let r = i - s;
while (r > 0) {
const i = Math.floor(r / 2);
let n = s + i;
if (!c(e, t[n])) {
s = ++n;
r -= i + 1;
} else {
r = i;
}
}
return s;
}
function std_rotate(t, s, i, e) {
let c = i;
while (s !== c) {
std_iter_swap(t, s++, c++);
if (c === e) {
c = i;
} else if (s === i) {
i = c;
}
}
}
function std_unique(t, s, i, e) {
if (s === i) {
return i;
}
let c = s;
while (++s !== i) {
if (!e(t[c], t[s])) {
std_iter_swap(t, ++c, s);
}
}
return ++c;
}
export class b2GrowableBuffer {
constructor(t) {
this.data = [];
this.count = 0;
this.capacity = 0;
this.allocator = t;
}
Append() {
if (this.count >= this.capacity) {
this.Grow();
}
return this.count++;
}
Reserve(t) {
if (this.capacity >= t) {
return;
}
for (let s = this.capacity; s < t; ++s) {
this.data[s] = this.allocator();
}
this.capacity = t;
}
Grow() {
const t = this.capacity ? 2 * this.capacity : b2_minParticleSystemBufferCapacity;
this.Reserve(t);
}
Free() {
if (this.data.length === 0) {
return;
}
this.data = [];
this.capacity = 0;
this.count = 0;
}
Shorten(t) {}
Data() {
return this.data;
}
GetCount() {
return this.count;
}
SetCount(t) {
this.count = t;
}
GetCapacity() {
return this.capacity;
}
RemoveIf(t) {
this.count = std_remove_if(this.data, t, this.count);
}
Unique(t) {
this.count = std_unique(this.data, 0, this.count, t);
}
}
export class b2FixtureParticleQueryCallback extends b2QueryCallback {
constructor(t) {
super();
this.m_system = t;
}
ShouldQueryParticleSystem(t) {
return false;
}
ReportFixture(t) {
if (t.IsSensor()) {
return true;
}
const s = t.GetShape();
const i = s.GetChildCount();
for (let s = 0; s < i; s++) {
const i = t.GetAABB(s);
const e = this.m_system.GetInsideBoundsEnumerator(i);
let c;
while ((c = e.GetNext()) >= 0) {
this.ReportFixtureAndParticle(t, s, c);
}
}
return true;
}
ReportParticle(t, s) {
return false;
}
ReportFixtureAndParticle(t, s, i) {}
}
export class b2ParticleContact {
constructor() {
this.indexA = 0;
this.indexB = 0;
this.weight = 0;
this.normal = new b2Vec2;
this.flags = 0;
}
SetIndices(t, s) {
this.indexA = t;
this.indexB = s;
}
SetWeight(t) {
this.weight = t;
}
SetNormal(t) {
this.normal.Copy(t);
}
SetFlags(t) {
this.flags = t;
}
GetIndexA() {
return this.indexA;
}
GetIndexB() {
return this.indexB;
}
GetWeight() {
return this.weight;
}
GetNormal() {
return this.normal;
}
GetFlags() {
return this.flags;
}
IsEqual(t) {
return this.indexA === t.indexA && this.indexB === t.indexB && this.flags === t.flags && this.weight === t.weight && this.normal.x === t.normal.x && this.normal.y === t.normal.y;
}
IsNotEqual(t) {
return !this.IsEqual(t);
}
ApproximatelyEqual(t) {
const s = .01;
const i = .01 * .01;
return this.indexA === t.indexA && this.indexB === t.indexB && this.flags === t.flags && b2Abs(this.weight - t.weight) < s && b2Vec2.DistanceSquaredVV(this.normal, t.normal) < i;
}
}
export class b2ParticleBodyContact {
constructor() {
this.index = 0;
this.weight = 0;
this.normal = new b2Vec2;
this.mass = 0;
}
}
export class b2ParticlePair {
constructor() {
this.indexA = 0;
this.indexB = 0;
this.flags = 0;
this.strength = 0;
this.distance = 0;
}
}
export class b2ParticleTriad {
constructor() {
this.indexA = 0;
this.indexB = 0;
this.indexC = 0;
this.flags = 0;
this.strength = 0;
this.pa = new b2Vec2(0, 0);
this.pb = new b2Vec2(0, 0);
this.pc = new b2Vec2(0, 0);
this.ka = 0;
this.kb = 0;
this.kc = 0;
this.s = 0;
}
}
export class b2ParticleSystemDef {
constructor() {
this.strictContactCheck = false;
this.density = 1;
this.gravityScale = 1;
this.radius = 1;
this.maxCount = 0;
this.pressureStrength = .005;
this.dampingStrength = 1;
this.elasticStrength = .25;
this.springStrength = .25;
this.viscousStrength = .25;
this.surfaceTensionPressureStrength = .2;
this.surfaceTensionNormalStrength = .2;
this.repulsiveStrength = 1;
this.powderStrength = .5;
this.ejectionStrength = .5;
this.staticPressureStrength = .2;
this.staticPressureRelaxation = .2;
this.staticPressureIterations = 8;
this.colorMixingStrength = .5;
this.destroyByAge = true;
this.lifetimeGranularity = 1 / 60;
}
Copy(t) {
this.strictContactCheck = t.strictContactCheck;
this.density = t.density;
this.gravityScale = t.gravityScale;
this.radius = t.radius;
this.maxCount = t.maxCount;
this.pressureStrength = t.pressureStrength;
this.dampingStrength = t.dampingStrength;
this.elasticStrength = t.elasticStrength;
this.springStrength = t.springStrength;
this.viscousStrength = t.viscousStrength;
this.surfaceTensionPressureStrength = t.surfaceTensionPressureStrength;
this.surfaceTensionNormalStrength = t.surfaceTensionNormalStrength;
this.repulsiveStrength = t.repulsiveStrength;
this.powderStrength = t.powderStrength;
this.ejectionStrength = t.ejectionStrength;
this.staticPressureStrength = t.staticPressureStrength;
this.staticPressureRelaxation = t.staticPressureRelaxation;
this.staticPressureIterations = t.staticPressureIterations;
this.colorMixingStrength = t.colorMixingStrength;
this.destroyByAge = t.destroyByAge;
this.lifetimeGranularity = t.lifetimeGranularity;
return this;
}
Clone() {
return (new b2ParticleSystemDef).Copy(this);
}
}
export class b2ParticleSystem {
constructor(t, s) {
this.m_paused = false;
this.m_timestamp = 0;
this.m_allParticleFlags = 0;
this.m_needsUpdateAllParticleFlags = false;
this.m_allGroupFlags = 0;
this.m_needsUpdateAllGroupFlags = false;
this.m_hasForce = false;
this.m_iterationIndex = 0;
this.m_inverseDensity = 0;
this.m_particleDiameter = 0;
this.m_inverseDiameter = 0;
this.m_squaredDiameter = 0;
this.m_count = 0;
this.m_internalAllocatedCapacity = 0;
this.m_handleIndexBuffer = new b2ParticleSystem_UserOverridableBuffer;
this.m_flagsBuffer = new b2ParticleSystem_UserOverridableBuffer;
this.m_positionBuffer = new b2ParticleSystem_UserOverridableBuffer;
this.m_velocityBuffer = new b2ParticleSystem_UserOverridableBuffer;
this.m_forceBuffer = [];
this.m_weightBuffer = [];
this.m_staticPressureBuffer = [];
this.m_accumulationBuffer = [];
this.m_accumulation2Buffer = [];
this.m_depthBuffer = [];
this.m_colorBuffer = new b2ParticleSystem_UserOverridableBuffer;
this.m_groupBuffer = [];
this.m_userDataBuffer = new b2ParticleSystem_UserOverridableBuffer;
this.m_stuckThreshold = 0;
this.m_lastBodyContactStepBuffer = new b2ParticleSystem_UserOverridableBuffer;
this.m_bodyContactCountBuffer = new b2ParticleSystem_UserOverridableBuffer;
this.m_consecutiveContactStepsBuffer = new b2ParticleSystem_UserOverridableBuffer;
this.m_stuckParticleBuffer = new b2GrowableBuffer((() => 0));
this.m_proxyBuffer = new b2GrowableBuffer((() => new b2ParticleSystem_Proxy));
this.m_contactBuffer = new b2GrowableBuffer((() => new b2ParticleContact));
this.m_bodyContactBuffer = new b2GrowableBuffer((() => new b2ParticleBodyContact));
this.m_pairBuffer = new b2GrowableBuffer((() => new b2ParticlePair));
this.m_triadBuffer = new b2GrowableBuffer((() => new b2ParticleTriad));
this.m_expirationTimeBuffer = new b2ParticleSystem_UserOverridableBuffer;
this.m_indexByExpirationTimeBuffer = new b2ParticleSystem_UserOverridableBuffer;
this.m_timeElapsed = 0;
this.m_expirationTimeBufferRequiresSorting = false;
this.m_groupCount = 0;
this.m_groupList = null;
this.m_def = new b2ParticleSystemDef;
this.m_prev = null;
this.m_next = null;
this.UpdateBodyContacts_callback = null;
this.SolveCollision_callback = null;
this.SetStrictContactCheck(t.strictContactCheck);
this.SetDensity(t.density);
this.SetGravityScale(t.gravityScale);
this.SetRadius(t.radius);
this.SetMaxParticleCount(t.maxCount);
this.m_def = t.Clone();
this.m_world = s;
this.SetDestructionByAge(this.m_def.destroyByAge);
}
static computeTag(t, s) {
return (s + b2ParticleSystem.yOffset >>> 0 << b2ParticleSystem.yShift) + (b2ParticleSystem.xScale * t + b2ParticleSystem.xOffset >>> 0) >>> 0;
}
static computeRelativeTag(t, s, i) {
return t + (i << b2ParticleSystem.yShift) + (s << b2ParticleSystem.xShift) >>> 0;
}
Drop() {
while (this.m_groupList) {
this.DestroyParticleGroup(this.m_groupList);
}
this.FreeUserOverridableBuffer(this.m_handleIndexBuffer);
this.FreeUserOverridableBuffer(this.m_flagsBuffer);
this.FreeUserOverridableBuffer(this.m_lastBodyContactStepBuffer);
this.FreeUserOverridableBuffer(this.m_bodyContactCountBuffer);
this.FreeUserOverridableBuffer(this.m_consecutiveContactStepsBuffer);
this.FreeUserOverridableBuffer(this.m_positionBuffer);
this.FreeUserOverridableBuffer(this.m_velocityBuffer);
this.FreeUserOverridableBuffer(this.m_colorBuffer);
this.FreeUserOverridableBuffer(this.m_userDataBuffer);
this.FreeUserOverridableBuffer(this.m_expirationTimeBuffer);
this.FreeUserOverridableBuffer(this.m_indexByExpirationTimeBuffer);
this.FreeBuffer(this.m_forceBuffer, this.m_internalAllocatedCapacity);
this.FreeBuffer(this.m_weightBuffer, this.m_internalAllocatedCapacity);
this.FreeBuffer(this.m_staticPressureBuffer, this.m_internalAllocatedCapacity);
this.FreeBuffer(this.m_accumulationBuffer, this.m_internalAllocatedCapacity);
this.FreeBuffer(this.m_accumulation2Buffer, this.m_internalAllocatedCapacity);
this.FreeBuffer(this.m_depthBuffer, this.m_internalAllocatedCapacity);
this.FreeBuffer(this.m_groupBuffer, this.m_internalAllocatedCapacity);
}
CreateParticle(t) {
if (this.m_world.IsLocked()) {
throw new Error;
}
if (this.m_count >= this.m_internalAllocatedCapacity) {
const t = this.m_count ? 2 * this.m_count : b2_minParticleSystemBufferCapacity;
this.ReallocateInternalAllocatedBuffers(t);
}
if (this.m_count >= this.m_internalAllocatedCapacity) {
if (this.m_def.destroyByAge) {
this.DestroyOldestParticle(0, false);
this.SolveZombie();
} else {
return b2_invalidParticleIndex;
}
}
const s = this.m_count++;
this.m_flagsBuffer.data[s] = 0;
if (this.m_lastBodyContactStepBuffer.data) {
this.m_lastBodyContactStepBuffer.data[s] = 0;
}
if (this.m_bodyContactCountBuffer.data) {
this.m_bodyContactCountBuffer.data[s] = 0;
}
if (this.m_consecutiveContactStepsBuffer.data) {
this.m_consecutiveContactStepsBuffer.data[s] = 0;
}
this.m_positionBuffer.data[s] = (this.m_positionBuffer.data[s] || new b2Vec2).Copy(b2Maybe(t.position, b2Vec2.ZERO));
this.m_velocityBuffer.data[s] = (this.m_velocityBuffer.data[s] || new b2Vec2).Copy(b2Maybe(t.velocity, b2Vec2.ZERO));
this.m_weightBuffer[s] = 0;
this.m_forceBuffer[s] = (this.m_forceBuffer[s] || new b2Vec2).SetZero();
if (this.m_staticPressureBuffer) {
this.m_staticPressureBuffer[s] = 0;
}
if (this.m_depthBuffer) {
this.m_depthBuffer[s] = 0;
}
const i = (new b2Color).Copy(b2Maybe(t.color, b2Color.ZERO));
if (this.m_colorBuffer.data || !i.IsZero()) {
this.m_colorBuffer.data = this.RequestBuffer(this.m_colorBuffer.data);
this.m_colorBuffer.data[s] = (this.m_colorBuffer.data[s] || new b2Color).Copy(i);
}
if (this.m_userDataBuffer.data || t.userData) {
this.m_userDataBuffer.data = this.RequestBuffer(this.m_userDataBuffer.data);
this.m_userDataBuffer.data[s] = t.userData;
}
if (this.m_handleIndexBuffer.data) {
this.m_handleIndexBuffer.data[s] = null;
}
const e = this.m_proxyBuffer.data[this.m_proxyBuffer.Append()];
const c = b2Maybe(t.lifetime, 0);
const r = c > 0;
if (this.m_expirationTimeBuffer.data || r) {
this.SetParticleLifetime(s, r ? c : this.ExpirationTimeToLifetime(-this.GetQuantizedTimeElapsed()));
this.m_indexByExpirationTimeBuffer.data[s] = s;
}
e.index = s;
const n = b2Maybe(t.group, null);
this.m_groupBuffer[s] = n;
if (n) {
if (n.m_firstIndex < n.m_lastIndex) {
this.RotateBuffer(n.m_firstIndex, n.m_lastIndex, s);
n.m_lastIndex = s + 1;
} else {
n.m_firstIndex = s;
n.m_lastIndex = s + 1;
}
}
this.SetParticleFlags(s, b2Maybe(t.flags, 0));
return s;
}
GetParticleHandleFromIndex(t) {
this.m_handleIndexBuffer.data = this.RequestBuffer(this.m_handleIndexBuffer.data);
let s = this.m_handleIndexBuffer.data[t];
if (s) {
return s;
}
s = new b2ParticleHandle;
s.SetIndex(t);
this.m_handleIndexBuffer.data[t] = s;
return s;
}
DestroyParticle(t, s = false) {
let i = b2ParticleFlag.b2_zombieParticle;
if (s) {
i |= b2ParticleFlag.b2_destructionListenerParticle;
}
this.SetParticleFlags(t, this.m_flagsBuffer.data[t] | i);
}
DestroyOldestParticle(t, s = false) {
const i = this.GetParticleCount();
const e = this.m_indexByExpirationTimeBuffer.data[i - (t + 1)];
const c = this.m_indexByExpirationTimeBuffer.data[t];
this.DestroyParticle(this.m_expirationTimeBuffer.data[e] > 0 ? e : c, s);
}
DestroyParticlesInShape(t, s, i = false) {
const e = b2ParticleSystem.DestroyParticlesInShape_s_aabb;
if (this.m_world.IsLocked()) {
throw new Error;
}
const c = new b2ParticleSystem_DestroyParticlesInShapeCallback(this, t, s, i);
const r = e;
t.ComputeAABB(r, s, 0);
this.m_world.QueryAABB(c, r);
return c.Destroyed();
}
CreateParticleGroup(t) {
const s = b2ParticleSystem.CreateParticleGroup_s_transform;
if (this.m_world.IsLocked()) {
throw new Error;
}
const i = s;
i.SetPositionAngle(b2Maybe(t.position, b2Vec2.ZERO), b2Maybe(t.angle, 0));
const e = this.m_count;
if (t.shape) {
this.CreateParticlesWithShapeForGroup(t.shape, t, i);
}
if (t.shapes) {
this.CreateParticlesWithShapesForGroup(t.shapes, b2Maybe(t.shapeCount, t.shapes.length), t, i);
}
if (t.positionData) {
const s = b2Maybe(t.particleCount, t.positionData.length);
for (let e = 0; e < s; e++) {
const s = t.positionData[e];
this.CreateParticleForGroup(t, i, s);
}
}
const c = this.m_count;
let r = new b2ParticleGroup(this);
r.m_firstIndex = e;
r.m_lastIndex = c;
r.m_strength = b2Maybe(t.strength, 1);
r.m_userData = t.userData;
r.m_transform.Copy(i);
r.m_prev = null;
r.m_next = this.m_groupList;
if (this.m_groupList) {
this.m_groupList.m_prev = r;
}
this.m_groupList = r;
++this.m_groupCount;
for (let t = e; t < c; t++) {
this.m_groupBuffer[t] = r;
}
this.SetGroupFlags(r, b2Maybe(t.groupFlags, 0));
const n = new b2ParticleSystem_ConnectionFilter;
this.UpdateContacts(true);
this.UpdatePairsAndTriads(e, c, n);
if (t.group) {
this.JoinParticleGroups(t.group, r);
r = t.group;
}
return r;
}
JoinParticleGroups(t, s) {
if (this.m_world.IsLocked()) {
throw new Error;
}
this.RotateBuffer(s.m_firstIndex, s.m_lastIndex, this.m_count);
this.RotateBuffer(t.m_firstIndex, t.m_lastIndex, s.m_firstIndex);
const i = new b2ParticleSystem_JoinParticleGroupsFilter(s.m_firstIndex);
this.UpdateContacts(true);
this.UpdatePairsAndTriads(t.m_firstIndex, s.m_lastIndex, i);
for (let i = s.m_firstIndex; i < s.m_lastIndex; i++) {
this.m_groupBuffer[i] = t;
}
const e = t.m_groupFlags | s.m_groupFlags;
this.SetGroupFlags(t, e);
t.m_lastIndex = s.m_lastIndex;
s.m_firstIndex = s.m_lastIndex;
this.DestroyParticleGroup(s);
}
SplitParticleGroup(t) {
this.UpdateContacts(true);
const s = t.GetParticleCount();
const i = b2MakeArray(s, (t => new b2ParticleSystem_ParticleListNode));
b2ParticleSystem.InitializeParticleLists(t, i);
this.MergeParticleListsInContact(t, i);
const e = b2ParticleSystem.FindLongestParticleList(t, i);
this.MergeZombieParticleListNodes(t, i, e);
this.CreateParticleGroupsFromParticleList(t, i, e);
this.UpdatePairsAndTriadsWithParticleList(t, i);
}
GetParticleGroupList() {
return this.m_groupList;
}
GetParticleGroupCount() {
return this.m_groupCount;
}
GetParticleCount() {
return this.m_count;
}
GetMaxParticleCount() {
return this.m_def.maxCount;
}
SetMaxParticleCount(t) {
this.m_def.maxCount = t;
}
GetAllParticleFlags() {
return this.m_allParticleFlags;
}
GetAllGroupFlags() {
return this.m_allGroupFlags;
}
SetPaused(t) {
this.m_paused = t;
}
GetPaused() {
return this.m_paused;
}
SetDensity(t) {
this.m_def.density = t;
this.m_inverseDensity = 1 / this.m_def.density;
}
GetDensity() {
return this.m_def.density;
}
SetGravityScale(t) {
this.m_def.gravityScale = t;
}
GetGravityScale() {
return this.m_def.gravityScale;
}
SetDamping(t) {
this.m_def.dampingStrength = t;
}
GetDamping() {
return this.m_def.dampingStrength;
}
SetStaticPressureIterations(t) {
this.m_def.staticPressureIterations = t;
}
GetStaticPressureIterations() {
return this.m_def.staticPressureIterations;
}
SetRadius(t) {
this.m_particleDiameter = 2 * t;
this.m_squaredDiameter = this.m_particleDiameter * this.m_particleDiameter;
this.m_inverseDiameter = 1 / this.m_particleDiameter;
}
GetRadius() {
return this.m_particleDiameter / 2;
}
GetPositionBuffer() {
return this.m_positionBuffer.data;
}
GetVelocityBuffer() {
return this.m_velocityBuffer.data;
}
GetColorBuffer() {
this.m_colorBuffer.data = this.RequestBuffer(this.m_colorBuffer.data);
return this.m_colorBuffer.data;
}
GetGroupBuffer() {
return this.m_groupBuffer;
}
GetWeightBuffer() {
return this.m_weightBuffer;
}
GetUserDataBuffer() {
this.m_userDataBuffer.data = this.RequestBuffer(this.m_userDataBuffer.data);
return this.m_userDataBuffer.data;
}
GetFlagsBuffer() {
return this.m_flagsBuffer.data;
}
SetParticleFlags(t, s) {
const i = this.m_flagsBuffer.data[t];
if (i & ~s) {
this.m_needsUpdateAllParticleFlags = true;
}
if (~this.m_allParticleFlags & s) {
if (s & b2ParticleFlag.b2_tensileParticle) {
this.m_accumulation2Buffer = this.RequestBuffer(this.m_accumulation2Buffer);
}
if (s & b2ParticleFlag.b2_colorMixingParticle) {
this.m_colorBuffer.data = this.RequestBuffer(this.m_colorBuffer.data);
}
this.m_allParticleFlags |= s;
}
this.m_flagsBuffer.data[t] = s;
}
GetParticleFlags(t) {
return this.m_flagsBuffer.data[t];
}
SetFlagsBuffer(t) {
this.SetUserOverridableBuffer(this.m_flagsBuffer, t);
}
SetPositionBuffer(t) {
if (t instanceof Float32Array) {
if (t.length % 2 !== 0) {
throw new Error;
}
const s = t.length / 2;
const i = new Array(s);
for (let e = 0; e < s; ++e) {
i[e] = new b2TypedVec2(t.subarray(e * 2, e * 2 + 2));
}
t = i;
}
this.SetUserOverridableBuffer(this.m_positionBuffer, t);
}
SetVelocityBuffer(t) {
if (t instanceof Float32Array) {
if (t.length % 2 !== 0) {
throw new Error;
}
const s = t.length / 2;
const i = new Array(s);
for (let e = 0; e < s; ++e) {
i[e] = new b2TypedVec2(t.subarray(e * 2, e * 2 + 2));
}
t = i;
}
this.SetUserOverridableBuffer(this.m_velocityBuffer, t);
}
SetColorBuffer(t) {
if (t instanceof Float32Array) {
if (t.length % 4 !== 0) {
throw new Error;
}
const s = t.length / 4;
const i = new Array(s);
for (let e = 0; e < s; ++e) {
i[e] = new b2TypedColor(t.subarray(e * 4, e * 4 + 4));
}
t = i;
}
this.SetUserOverridableBuffer(this.m_colorBuffer, t);
}
SetUserDataBuffer(t) {
this.SetUserOverridableBuffer(this.m_userDataBuffer, t);
}
GetContacts() {
return this.m_contactBuffer.data;
}
GetContactCount() {
return this.m_contactBuffer.count;
}
GetBodyContacts() {
return this.m_bodyContactBuffer.data;
}
GetBodyContactCount() {
return this.m_bodyContactBuffer.count;
}
GetPairs() {
return this.m_pairBuffer.data;
}
GetPairCount() {
return this.m_pairBuffer.count;
}
GetTriads() {
return this.m_triadBuffer.data;
}
GetTriadCount() {
return this.m_triadBuffer.count;
}
SetStuckThreshold(t) {
this.m_stuckThreshold = t;
if (t > 0) {
this.m_lastBodyContactStepBuffer.data = this.RequestBuffer(this.m_lastBodyContactStepBuffer.data);
this.m_bodyContactCountBuffer.data = this.RequestBuffer(this.m_bodyContactCountBuffer.data);
this.m_consecutiveContactStepsBuffer.data = this.RequestBuffer(this.m_consecutiveContactStepsBuffer.data);
}
}
GetStuckCandidates() {
return this.m_stuckParticleBuffer.Data();
}
GetStuckCandidateCount() {
return this.m_stuckParticleBuffer.GetCount();
}
ComputeCollisionEnergy() {
const t = b2ParticleSystem.ComputeCollisionEnergy_s_v;
const s = this.m_velocityBuffer.data;
let i = 0;
for (let e = 0; e < this.m_contactBuffer.count; e++) {
const c = this.m_contactBuffer.data[e];
const r = c.indexA;
const n = c.indexB;
const o = c.normal;
const h = b2Vec2.SubVV(s[n], s[r], t);
const l = b2Vec2.DotVV(h, o);
if (l < 0) {
i += l * l;
}
}
return .5 * this.GetParticleMass() * i;
}
SetStrictContactCheck(t) {
this.m_def.strictContactCheck = t;
}
GetStrictContactCheck() {
return this.m_def.strictContactCheck;
}
SetParticleLifetime(t, s) {
const i = this.m_indexByExpirationTimeBuffer.data === null;
this.m_expirationTimeBuffer.data = this.RequestBuffer(this.m_expirationTimeBuffer.data);
this.m_indexByExpirationTimeBuffer.data = this.RequestBuffer(this.m_indexByExpirationTimeBuffer.data);
if (i) {
const t = this.GetParticleCount();
for (let s = 0; s < t; ++s) {
this.m_indexByExpirationTimeBuffer.data[s] = s;
}
}
const e = s / this.m_def.lifetimeGranularity;
const c = e > 0 ? this.GetQuantizedTimeElapsed() + e : e;
if (c !== this.m_expirationTimeBuffer.data[t]) {
this.m_expirationTimeBuffer.data[t] = c;
this.m_expirationTimeBufferRequiresSorting = true;
}
}
GetParticleLifetime(t) {
return this.ExpirationTimeToLifetime(this.GetExpirationTimeBuffer()[t]);
}
SetDestructionByAge(t) {
if (t) {
this.GetExpirationTimeBuffer();
}
this.m_def.destroyByAge = t;
}
GetDestructionByAge() {
return this.m_def.destroyByAge;
}
GetExpirationTimeBuffer() {
this.m_expirationTimeBuffer.data = this.RequestBuffer(this.m_expirationTimeBuffer.data);
return this.m_expirationTimeBuffer.data;
}
ExpirationTimeToLifetime(t) {
return (t > 0 ? t - this.GetQuantizedTimeElapsed() : t) * this.m_def.lifetimeGranularity;
}
GetIndexByExpirationTimeBuffer() {
if (this.GetParticleCount()) {
this.SetParticleLifetime(0, this.GetParticleLifetime(0));
} else {
this.m_indexByExpirationTimeBuffer.data = this.RequestBuffer(this.m_indexByExpirationTimeBuffer.data);
}
return this.m_indexByExpirationTimeBuffer.data;
}
ParticleApplyLinearImpulse(t, s) {
this.ApplyLinearImpulse(t, t + 1, s);
}
ApplyLinearImpulse(t, s, i) {
const e = this.m_velocityBuffer.data;
const c = s - t;
const r = c * this.GetParticleMass();
const n = (new b2Vec2).Copy(i).SelfMul(1 / r);
for (let i = t; i < s; i++) {
e[i].SelfAdd(n);
}
}
static IsSignificantForce(t) {
return t.x !== 0 || t.y !== 0;
}
ParticleApplyForce(t, s) {
if (b2ParticleSystem.IsSignificantForce(s) && this.ForceCanBeApplied(this.m_flagsBuffer.data[t])) {
this.PrepareForceBuffer();
this.m_forceBuffer[t].SelfAdd(s);
}
}
ApplyForce(t, s, i) {
const e = (new b2Vec2).Copy(i).SelfMul(1 / (s - t));
if (b2ParticleSystem.IsSignificantForce(e)) {
this.PrepareForceBuffer();
for (let i = t; i < s; i++) {
this.m_forceBuffer[i].SelfAdd(e);
}
}
}
GetNext() {
return this.m_next;
}
QueryAABB(t, s) {
if (this.m_proxyBuffer.count === 0) {
return;
}
const i = 0;
const e = this.m_proxyBuffer.count;
const c = std_lower_bound(this.m_proxyBuffer.data, i, e, b2ParticleSystem.computeTag(this.m_inverseDiameter * s.lowerBound.x, this.m_inverseDiameter * s.lowerBound.y), b2ParticleSystem_Proxy.CompareProxyTag);
const r = std_upper_bound(this.m_proxyBuffer.data, c, e, b2ParticleSystem.computeTag(this.m_inverseDiameter * s.upperBound.x, this.m_inverseDiameter * s.upperBound.y), b2ParticleSystem_Proxy.CompareTagProxy);
const n = this.m_positionBuffer.data;
for (let i = c; i < r; ++i) {
const e = this.m_proxyBuffer.data[i];
const c = e.index;
const r = n[c];
if (s.lowerBound.x < r.x && r.x < s.upperBound.x && s.lowerBound.y < r.y && r.y < s.upperBound.y) {
if (!t.ReportParticle(this, c)) {
break;
}
}
}
}
QueryShapeAABB(t, s, i, e = 0) {
const c = b2ParticleSystem.QueryShapeAABB_s_aabb;
const r = c;
s.ComputeAABB(r, i, e);
this.QueryAABB(t, r);
}
QueryPointAABB(t, s, i = b2_linearSlop) {
const e = b2ParticleSystem.QueryPointAABB_s_aabb;
const c = e;
c.lowerBound.Set(s.x - i, s.y - i);
c.upperBound.Set(s.x + i, s.y + i);
this.QueryAABB(t, c);
}
RayCast(t, s, i) {
const e = b2ParticleSystem.RayCast_s_aabb;
const c = b2ParticleSystem.RayCast_s_p;
const r = b2ParticleSystem.RayCast_s_v;
const n = b2ParticleSystem.RayCast_s_n;
const o = b2ParticleSystem.RayCast_s_point;
if (this.m_proxyBuffer.count === 0) {
return;
}
const h = this.m_positionBuffer.data;
const l = e;
b2Vec2.MinV(s, i, l.lowerBound);
b2Vec2.MaxV(s, i, l.upperBound);
let a = 1;
const b = b2Vec2.SubVV(i, s, r);
const f = b2Vec2.DotVV(b, b);
const P = this.GetInsideBoundsEnumerator(l);
let u;
while ((u = P.GetNext()) >= 0) {
const i = b2Vec2.SubVV(s, h[u], c);
const e = b2Vec2.DotVV(i, b);
const r = b2Vec2.DotVV(i, i);
const l = e * e - f * (r - this.m_squaredDiameter);
if (l >= 0) {
const c = b2Sqrt(l);
let r = (-e - c) / f;
if (r > a) {
continue;
}
if (r < 0) {
r = (-e + c) / f;
if (r < 0 || r > a) {
continue;
}
}
const h = b2Vec2.AddVMulSV(i, r, b, n);
h.Normalize();
const P = t.ReportParticle(this, u, b2Vec2.AddVMulSV(s, r, b, o), h, r);
a = b2Min(a, P);
if (a <= 0) {
break;
}
}
}
}
ComputeAABB(t) {
const s = this.GetParticleCount();
t.lowerBound.x = +b2_maxFloat;
t.lowerBound.y = +b2_maxFloat;
t.upperBound.x = -b2_maxFloat;
t.upperBound.y = -b2_maxFloat;
const i = this.m_positionBuffer.data;
for (let e = 0; e < s; e++) {
const s = i[e];
b2Vec2.MinV(t.lowerBound, s, t.lowerBound);
b2Vec2.MaxV(t.upperBound, s, t.upperBound);
}
t.lowerBound.x -= this.m_particleDiameter;
t.lowerBound.y -= this.m_particleDiameter;
t.upperBound.x += this.m_particleDiameter;
t.upperBound.y += this.m_particleDiameter;
}
FreeBuffer(t, s) {
if (t === null) {
return;
}
t.length = 0;
}
FreeUserOverridableBuffer(t) {
if (t.userSuppliedCapacity === 0) {
this.FreeBuffer(t.data, this.m_internalAllocatedCapacity);
}
}
ReallocateBuffer3(t, s, i) {
if (i <= s) {
throw new Error;
}
const e = t ? t.slice() : [];
e.length = i;
return e;
}
ReallocateBuffer5(t, s, i, e, c) {
if (e <= i) {
throw new Error;
}
if (!(!s || e <= s)) {
throw new Error;
}
if ((!c || t) && !s) {
t = this.ReallocateBuffer3(t, i, e);
}
return t;
}
ReallocateBuffer4(t, s, i, e) {
return this.ReallocateBuffer5(t.data, t.userSuppliedCapacity, s, i, e);
}
RequestBuffer(t) {
if (!t) {
if (this.m_internalAllocatedCapacity === 0) {
this.ReallocateInternalAllocatedBuffers(b2_minParticleSystemBufferCapacity);
}
t = [];
t.length = this.m_internalAllocatedCapacity;
}
return t;
}
ReallocateHandleBuffers(t) {
this.m_handleIndexBuffer.data = this.ReallocateBuffer4(this.m_handleIndexBuffer, this.m_internalAllocatedCapacity, t, true);
}
ReallocateInternalAllocatedBuffers(t) {
function LimitCapacity(t, s) {
return s && t > s ? s : t;
}
t = LimitCapacity(t, this.m_def.maxCount);
t = LimitCapacity(t, this.m_flagsBuffer.userSuppliedCapacity);
t = LimitCapacity(t, this.m_positionBuffer.userSuppliedCapacity);
t = LimitCapacity(t, this.m_velocityBuffer.userSuppliedCapacity);
t = LimitCapacity(t, this.m_colorBuffer.userSuppliedCapacity);
t = LimitCapacity(t, this.m_userDataBuffer.userSuppliedCapacity);
if (this.m_internalAllocatedCapacity < t) {
this.ReallocateHandleBuffers(t);
this.m_flagsBuffer.data = this.ReallocateBuffer4(this.m_flagsBuffer, this.m_internalAllocatedCapacity, t, false);
const s = this.m_stuckThreshold > 0;
this.m_lastBodyContactStepBuffer.data = this.ReallocateBuffer4(this.m_lastBodyContactStepBuffer, this.m_internalAllocatedCapacity, t, s);
this.m_bodyContactCountBuffer.data = this.ReallocateBuffer4(this.m_bodyContactCountBuffer, this.m_internalAllocatedCapacity, t, s);
this.m_consecutiveContactStepsBuffer.data = this.ReallocateBuffer4(this.m_consecutiveContactStepsBuffer, this.m_internalAllocatedCapacity, t, s);
this.m_positionBuffer.data = this.ReallocateBuffer4(this.m_positionBuffer, this.m_internalAllocatedCapacity, t, false);
this.m_velocityBuffer.data = this.ReallocateBuffer4(this.m_velocityBuffer, this.m_internalAllocatedCapacity, t, false);
this.m_forceBuffer = this.ReallocateBuffer5(this.m_forceBuffer, 0, this.m_internalAllocatedCapacity, t, false);
this.m_weightBuffer = this.ReallocateBuffer5(this.m_weightBuffer, 0, this.m_internalAllocatedCapacity, t, false);
this.m_staticPressureBuffer = this.ReallocateBuffer5(this.m_staticPressureBuffer, 0, this.m_internalAllocatedCapacity, t, true);
this.m_accumulationBuffer = this.ReallocateBuffer5(this.m_accumulationBuffer, 0, this.m_internalAllocatedCapacity, t, false);
this.m_accumulation2Buffer = this.ReallocateBuffer5(this.m_accumulation2Buffer, 0, this.m_internalAllocatedCapacity, t, true);
this.m_depthBuffer = this.ReallocateBuffer5(this.m_depthBuffer, 0, this.m_internalAllocatedCapacity, t, true);
this.m_colorBuffer.data = this.ReallocateBuffer4(this.m_colorBuffer, this.m_internalAllocatedCapacity, t, true);
this.m_groupBuffer = this.ReallocateBuffer5(this.m_groupBuffer, 0, this.m_internalAllocatedCapacity, t, false);
this.m_userDataBuffer.data = this.ReallocateBuffer4(this.m_userDataBuffer, this.m_internalAllocatedCapacity, t, true);
this.m_expirationTimeBuffer.data = this.ReallocateBuffer4(this.m_expirationTimeBuffer, this.m_internalAllocatedCapacity, t, true);
this.m_indexByExpirationTimeBuffer.data = this.ReallocateBuffer4(this.m_indexByExpirationTimeBuffer, this.m_internalAllocatedCapacity, t, false);
this.m_internalAllocatedCapacity = t;
}
}
CreateParticleForGroup(t, s, i) {
const e = new b2ParticleDef;
e.flags = b2Maybe(t.flags, 0);
b2Transform.MulXV(s, i, e.position);
b2Vec2.AddVV(b2Maybe(t.linearVelocity, b2Vec2.ZERO), b2Vec2.CrossSV(b2Maybe(t.angularVelocity, 0), b2Vec2.SubVV(e.position, b2Maybe(t.position, b2Vec2.ZERO), b2Vec2.s_t0), b2Vec2.s_t0), e.velocity);
e.color.Copy(b2Maybe(t.color, b2Color.ZERO));
e.lifetime = b2Maybe(t.lifetime, 0);
e.userData = t.userData;
this.CreateParticle(e);
}
CreateParticlesStrokeShapeForGroup(t, s, i) {
const e = b2ParticleSystem.CreateParticlesStrokeShapeForGroup_s_edge;
const c = b2ParticleSystem.CreateParticlesStrokeShapeForGroup_s_d;
const r = b2ParticleSystem.CreateParticlesStrokeShapeForGroup_s_p;
let n = b2Maybe(s.stride, 0);
if (n === 0) {
n = this.GetParticleStride();
}
let o = 0;
const h = t.GetChildCount();
for (let l = 0; l < h; l++) {
let h = null;
if (t.GetType() === b2ShapeType.e_edgeShape) {
h = t;
} else {
h = e;
t.GetChildEdge(h, l);
}
const a = b2Vec2.SubVV(h.m_vertex2, h.m_vertex1, c);
const b = a.Length();
while (o < b) {
const t = b2Vec2.AddVMulSV(h.m_vertex1, o / b, a, r);
this.CreateParticleForGroup(s, i, t);
o += n;
}
o -= b;
}
}
CreateParticlesFillShapeForGroup(t, s, i) {
const e = b2ParticleSystem.CreateParticlesFillShapeForGroup_s_aabb;
const c = b2ParticleSystem.CreateParticlesFillShapeForGroup_s_p;
let r = b2Maybe(s.stride, 0);
if (r === 0) {
r = this.GetParticleStride();
}
const n = b2Transform.IDENTITY;
const o = e;
t.ComputeAABB(o, n, 0);
for (let e = Math.floor(o.lowerBound.y / r) * r; e < o.upperBound.y; e += r) {
for (let h = Math.floor(o.lowerBound.x / r) * r; h < o.upperBound.x; h += r) {
const r = c.Set(h, e);
if (t.TestPoint(n, r)) {
this.CreateParticleForGroup(s, i, r);
}
}
}
}
CreateParticlesWithShapeForGroup(t, s, i) {
switch (t.GetType()) {
case b2ShapeType.e_edgeShape:
case b2ShapeType.e_chainShape:
this.CreateParticlesStrokeShapeForGroup(t, s, i);
break;
case b2ShapeType.e_polygonShape:
case b2ShapeType.e_circleShape:
this.CreateParticlesFillShapeForGroup(t, s, i);
break;
default:
break;
}
}
CreateParticlesWithShapesForGroup(t, s, i, e) {
const c = new b2ParticleSystem_CompositeShape(t, s);
this.CreateParticlesFillShapeForGroup(c, i, e);
}
CloneParticle(t, s) {
const i = new b2ParticleDef;
i.flags = this.m_flagsBuffer.data[t];
i.position.Copy(this.m_positionBuffer.data[t]);
i.velocity.Copy(this.m_velocityBuffer.data[t]);
if (this.m_colorBuffer.data) {
i.color.Copy(this.m_colorBuffer.data[t]);
}
if (this.m_userDataBuffer.data) {
i.userData = this.m_userDataBuffer.data[t];
}
i.group = s;
const e = this.CreateParticle(i);
if (this.m_handleIndexBuffer.data) {
const s = this.m_handleIndexBuffer.data[t];
if (s) {
s.SetIndex(e);
}
this.m_handleIndexBuffer.data[e] = s;
this.m_handleIndexBuffer.data[t] = null;
}
if (this.m_lastBodyContactStepBuffer.data) {
this.m_lastBodyContactStepBuffer.data[e] = this.m_lastBodyContactStepBuffer.data[t];
}
if (this.m_bodyContactCountBuffer.data) {
this.m_bodyContactCountBuffer.data[e] = this.m_bodyContactCountBuffer.data[t];
}
if (this.m_consecutiveContactStepsBuffer.data) {
this.m_consecutiveContactStepsBuffer.data[e] = this.m_consecutiveContactStepsBuffer.data[t];
}
if (this.m_hasForce) {
this.m_forceBuffer[e].Copy(this.m_forceBuffer[t]);
}
if (this.m_staticPressureBuffer) {
this.m_staticPressureBuffer[e] = this.m_staticPressureBuffer[t];
}
if (this.m_depthBuffer) {
this.m_depthBuffer[e] = this.m_depthBuffer[t];
}
if (this.m_expirationTimeBuffer.data) {
this.m_expirationTimeBuffer.data[e] = this.m_expirationTimeBuffer.data[t];
}
return e;
}
DestroyParticlesInGroup(t, s = false) {
for (let i = t.m_firstIndex; i < t.m_lastIndex; i++) {
this.DestroyParticle(i, s);
}
}
DestroyParticleGroup(t) {
if (this.m_world.m_destructionListener) {
this.m_world.m_destructionListener.SayGoodbyeParticleGroup(t);
}
this.SetGroupFlags(t, 0);
for (let s = t.m_firstIndex; s < t.m_lastIndex; s++) {
this.m_groupBuffer[s] = null;
}
if (t.m_prev) {
t.m_prev.m_next = t.m_next;
}
if (t.m_next) {
t.m_next.m_prev = t.m_prev;
}
if (t === this.m_groupList) {
this.m_groupList = t.m_next;
}
--this.m_groupCount;
}
static ParticleCanBeConnected(t, s) {
return (t & (b2ParticleFlag.b2_wallParticle | b2ParticleFlag.b2_springParticle | b2ParticleFlag.b2_elasticParticle)) !== 0 || s !== null && (s.GetGroupFlags() & b2ParticleGroupFlag.b2_rigidParticleGroup) !== 0;
}
UpdatePairsAndTriads(t, s, i) {
const e = b2ParticleSystem.UpdatePairsAndTriads_s_dab;
const c = b2ParticleSystem.UpdatePairsAndTriads_s_dbc;
const r = b2ParticleSystem.UpdatePairsAndTriads_s_dca;
const n = this.m_positionBuffer.data;
let o = 0;
for (let i = t; i < s; i++) {
o |= this.m_flagsBuffer.data[i];
}
if (o & b2ParticleSystem.k_pairFlags) {
for (let e = 0; e < this.m_contactBuffer.count; e++) {
const c = this.m_contactBuffer.data[e];
const r = c.indexA;
const o = c.indexB;
const h = this.m_flagsBuffer.data[r];
const l = this.m_flagsBuffer.data[o];
const a = this.m_groupBuffer[r];
const b = this.m_groupBuffer[o];
if (r >= t && r < s && o >= t && o < s && !((h | l) & b2ParticleFlag.b2_zombieParticle) && (h | l) & b2ParticleSystem.k_pairFlags && (i.IsNecessary(r) || i.IsNecessary(o)) && b2ParticleSystem.ParticleCanBeConnected(h, a) && b2ParticleSystem.ParticleCanBeConnected(l, b) && i.ShouldCreatePair(r, o)) {
const t = this.m_pairBuffer.data[this.m_pairBuffer.Append()];
t.indexA = r;
t.indexB = o;
t.flags = c.flags;
t.strength = b2Min(a ? a.m_strength : 1, b ? b.m_strength : 1);
t.distance = b2Vec2.DistanceVV(n[r], n[o]);
}
std_stable_sort(this.m_pairBuffer.data, 0, this.m_pairBuffer.count, b2ParticleSystem.ComparePairIndices);
this.m_pairBuffer.Unique(b2ParticleSystem.MatchPairIndices);
}
}
if (o & b2ParticleSystem.k_triadFlags) {
const o = new b2VoronoiDiagram(s - t);
for (let e = t; e < s; e++) {
const t = this.m_flagsBuffer.data[e];
const s = this.m_groupBuffer[e];
if (!(t & b2ParticleFlag.b2_zombieParticle) && b2ParticleSystem.ParticleCanBeConnected(t, s)) {
o.AddGenerator(n[e], e, i.IsNecessary(e));
}
}
const h = this.GetParticleStride();
o.Generate(h / 2, h * 2);
const l = this;
const callback = (t, s, o) => {
const h = l.m_flagsBuffer.data[t];
const a = l.m_flagsBuffer.data[s];
const b = l.m_flagsBuffer.data[o];
if ((h | a | b) & b2ParticleSystem.k_triadFlags && i.ShouldCreateTriad(t, s, o)) {
const i = n[t];
const f = n[s];
const P = n[o];
const u = b2Vec2.SubVV(i, f, e);
const m = b2Vec2.SubVV(f, P, c);
const S = b2Vec2.SubVV(P, i, r);
const y = b2_maxTriadDistanceSquared * l.m_squaredDiameter;
if (b2Vec2.DotVV(u, u) > y || b2Vec2.DotVV(m, m) > y || b2Vec2.DotVV(S, S) > y) {
return;
}
const d = l.m_groupBuffer[t];
const p = l.m_groupBuffer[s];
const V = l.m_groupBuffer[o];
const w = l.m_triadBuffer.data[l.m_triadBuffer.Append()];
w.indexA = t;
w.indexB = s;
w.indexC = o;
w.flags = h | a | b;
w.strength = b2Min(b2Min(d ? d.m_strength : 1, p ? p.m_strength : 1), V ? V.m_strength : 1);
const _ = (i.x + f.x + P.x) / 3;
const C = (i.y + f.y + P.y) / 3;
w.pa.x = i.x - _;
w.pa.y = i.y - C;
w.pb.x = f.x - _;
w.pb.y = f.y - C;
w.pc.x = P.x - _;
w.pc.y = P.y - C;
w.ka = -b2Vec2.DotVV(S, u);
w.kb = -b2Vec2.DotVV(u, m);
w.kc = -b2Vec2.DotVV(m, S);
w.s = b2Vec2.CrossVV(i, f) + b2Vec2.CrossVV(f, P) + b2Vec2.CrossVV(P, i);
}
};
o.GetNodes(callback);
std_stable_sort(this.m_triadBuffer.data, 0, this.m_triadBuffer.count, b2ParticleSystem.CompareTriadIndices);
this.m_triadBuffer.Unique(b2ParticleSystem.MatchTriadIndices);
}
}
UpdatePairsAndTriadsWithReactiveParticles() {
const t = new b2ParticleSystem_ReactiveFilter(this.m_flagsBuffer);
this.UpdatePairsAndTriads(0, this.m_count, t);
for (let t = 0; t < this.m_count; t++) {
this.m_flagsBuffer.data[t] &= ~b2ParticleFlag.b2_reactiveParticle;
}
this.m_allParticleFlags &= ~b2ParticleFlag.b2_reactiveParticle;
}
static ComparePairIndices(t, s) {
const i = t.indexA - s.indexA;
if (i !== 0) {
return i < 0;
}
return t.indexB < s.indexB;
}
static MatchPairIndices(t, s) {
return t.indexA === s.indexA && t.indexB === s.indexB;
}
static CompareTriadIndices(t, s) {
const i = t.indexA - s.indexA;
if (i !== 0) {
return i < 0;
}
const e = t.indexB - s.indexB;
if (e !== 0) {
return e < 0;
}
return t.indexC < s.indexC;
}
static MatchTriadIndices(t, s) {
return t.indexA === s.indexA && t.indexB === s.indexB && t.indexC === s.indexC;
}
static InitializeParticleLists(t, s) {
const i = t.GetBufferIndex();
const e = t.GetP