@awayfl/awayfl-player
Version:
Flash Player emulator for executing SWF files (published for FP versions 6 and up) in javascript
177 lines (152 loc) • 5.23 kB
text/typescript
import { IBroadPhase } from './IBroadPhase';
import { b2AABB } from './b2AABB';
import { b2Vec2 } from '../Common/Math';
import { b2DynamicTreeNode } from './b2DynamicTreeNode';
import { b2DynamicTreePair } from './b2DynamicTreePair';
import { b2DynamicTree } from './b2DynamicTree';
import { b2RayCastInput } from './b2RayCastInput';
/**
* The broad-phase is used for computing pairs and performing volume queries and ray casts.
* This broad-phase does not persist pairs. Instead, this reports potentially new pairs.
* It is up to the client to consume the new pairs and to track subsequent overlap.
*/
export class b2DynamicTreeBroadPhase implements IBroadPhase {
/**
* Create a proxy with an initial AABB. Pairs are not reported until
* UpdatePairs is called.
*/
public CreateProxy(aabb: b2AABB, userData: any): any {
const proxy: b2DynamicTreeNode = this.m_tree.CreateProxy(aabb, userData);
++this.m_proxyCount;
this.BufferMove(proxy);
return proxy;
}
/**
* Destroy a proxy. It is up to the client to remove any pairs.
*/
public DestroyProxy(proxy: any): void {
this.UnBufferMove(proxy);
--this.m_proxyCount;
this.m_tree.DestroyProxy(proxy);
}
/**
* Call MoveProxy as many times as you like, then when you are done
* call UpdatePairs to finalized the proxy pairs (for your time step).
*/
public MoveProxy(proxy: any, aabb: b2AABB, displacement: b2Vec2): void {
const buffer: boolean = this.m_tree.MoveProxy(proxy, aabb, displacement);
if (buffer) {
this.BufferMove(proxy);
}
}
public TestOverlap(proxyA: any, proxyB: any): boolean {
const aabbA: b2AABB = this.m_tree.GetFatAABB(proxyA);
const aabbB: b2AABB = this.m_tree.GetFatAABB(proxyB);
return aabbA.TestOverlap(aabbB);
}
/**
* Get user data from a proxy. Returns null if the proxy is invalid.
*/
public GetUserData(proxy: any): any {
return this.m_tree.GetUserData(proxy);
}
/**
* Get the AABB for a proxy.
*/
public GetFatAABB(proxy: any): b2AABB {
return this.m_tree.GetFatAABB(proxy);
}
/**
* Get the number of proxies.
*/
public GetProxyCount(): number /**int */
{
return this.m_proxyCount;
}
/**
* Update the pairs. This results in pair callbacks. This can only add pairs.
*/
public UpdatePairs(callback: Function): void {
this.m_pairCount = 0;
// Perform tree queries for all moving queries
for (var queryProxy of this.m_moveBuffer) {
const QueryCallback: Function = (proxy: b2DynamicTreeNode) => {
// A proxy cannot form a pair with itself.
if (proxy == queryProxy)
return true;
// Grow the pair buffer as needed
if (this.m_pairCount == this.m_pairBuffer.length) {
this.m_pairBuffer[this.m_pairCount] = new b2DynamicTreePair();
}
const pair: b2DynamicTreePair = this.m_pairBuffer[this.m_pairCount];
pair.proxyA = proxy < queryProxy ? proxy : queryProxy;
pair.proxyB = proxy >= queryProxy ? proxy : queryProxy;
++this.m_pairCount;
return true;
};
// We have to query the tree with the fat AABB so that
// we don't fail to create a pair that may touch later.
const fatAABB: b2AABB = this.m_tree.GetFatAABB(queryProxy);
this.m_tree.Query(QueryCallback, fatAABB);
}
// Reset move buffer
this.m_moveBuffer.length = 0;
// Sort the pair buffer to expose duplicates.
// TODO: Something more sensible
//m_pairBuffer.sort(ComparePairs);
// Send the pair buffer
for (let i: number /**int */ = 0; i < this.m_pairCount;) {
const primaryPair: b2DynamicTreePair = this.m_pairBuffer[i];
const userDataA: any = this.m_tree.GetUserData(primaryPair.proxyA);
const userDataB: any = this.m_tree.GetUserData(primaryPair.proxyB);
callback(userDataA, userDataB);
++i;
// Skip any duplicate pairs
while (i < this.m_pairCount) {
const pair: b2DynamicTreePair = this.m_pairBuffer[i];
if (pair.proxyA != primaryPair.proxyA || pair.proxyB != primaryPair.proxyB) {
break;
}
++i;
}
}
}
/**
* @inheritDoc
*/
public Query(callback: Function, aabb: b2AABB): void {
this.m_tree.Query(callback, aabb);
}
/**
* @inheritDoc
*/
public RayCast(callback: Function, input: b2RayCastInput): void {
this.m_tree.RayCast(callback, input);
}
public Validate(): void {
//TODO_BORIS
}
public Rebalance(iterations: number /**int */): void {
this.m_tree.Rebalance(iterations);
}
// Private ///////////////
private BufferMove(proxy: b2DynamicTreeNode): void {
this.m_moveBuffer[this.m_moveBuffer.length] = proxy;
}
private UnBufferMove(proxy: b2DynamicTreeNode): void {
const i: number /**int */ = this.m_moveBuffer.indexOf(proxy);
this.m_moveBuffer.splice(i, 1);
}
private ComparePairs(pair1: b2DynamicTreePair, pair2: b2DynamicTreePair): number /**int */
{
//TODO_BORIS:
// We cannot consistently sort objects easily in AS3
// The caller of this needs replacing with a different method.
return 0;
}
private m_tree: b2DynamicTree = new b2DynamicTree();
private m_proxyCount: number /**int */;
private m_moveBuffer: Array<b2DynamicTreeNode> = new Array<b2DynamicTreeNode>();
private m_pairBuffer: Array<b2DynamicTreePair> = new Array<b2DynamicTreePair>();
private m_pairCount: number /**int */ = 0;
}