
com.almasb.fxgl.physics.box2d.collision.broadphase.DefaultBroadPhaseBuffer Maven / Gradle / Ivy
/*
* FXGL - JavaFX Game Library. The MIT License (MIT).
* Copyright (c) AlmasB ([email protected]).
* See LICENSE for details.
*/
package com.almasb.fxgl.physics.box2d.collision.broadphase;
import com.almasb.fxgl.core.math.Vec2;
import com.almasb.fxgl.physics.box2d.callbacks.PairCallback;
import com.almasb.fxgl.physics.box2d.callbacks.TreeCallback;
import com.almasb.fxgl.physics.box2d.callbacks.TreeRayCastCallback;
import com.almasb.fxgl.physics.box2d.collision.AABB;
import com.almasb.fxgl.physics.box2d.collision.RayCastInput;
import java.util.Arrays;
/**
* 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.
*
* @author Daniel Murphy
*/
public final class DefaultBroadPhaseBuffer implements TreeCallback, BroadPhase {
private final BroadPhaseStrategy tree;
private int moveCapacity = 16;
private int[] moveBuffer = new int[moveCapacity];
private int moveCount = 0;
private int pairCapacity = 16;
private Pair[] pairBuffer = new Pair[pairCapacity];
private int pairCount = 0;
private int m_queryProxyId = NULL_PROXY;
public DefaultBroadPhaseBuffer(BroadPhaseStrategy strategy) {
for (int i = 0; i < pairCapacity; i++) {
pairBuffer[i] = new Pair();
}
tree = strategy;
}
@Override
public int createProxy(AABB aabb, Object userData) {
int proxyId = tree.createProxy(aabb, userData);
bufferMove(proxyId);
return proxyId;
}
@Override
public void destroyProxy(int proxyId) {
unbufferMove(proxyId);
tree.destroyProxy(proxyId);
}
@Override
public void moveProxy(int proxyId, AABB aabb, Vec2 displacement) {
boolean buffer = tree.moveProxy(proxyId, aabb, displacement);
if (buffer) {
bufferMove(proxyId);
}
}
@Override
public void touchProxy(int proxyId) {
bufferMove(proxyId);
}
@Override
public Object getUserData(int proxyId) {
return tree.getUserData(proxyId);
}
@Override
public boolean testOverlap(int proxyIdA, int proxyIdB) {
AABB a = tree.getFatAABB(proxyIdA);
AABB b = tree.getFatAABB(proxyIdB);
return AABB.testOverlap(a, b);
}
@Override
public void updatePairs(PairCallback callback) {
// Reset pair buffer
pairCount = 0;
// Perform tree queries for all moving proxies.
for (int i = 0; i < moveCount; ++i) {
m_queryProxyId = moveBuffer[i];
if (m_queryProxyId == NULL_PROXY) {
continue;
}
// We have to query the tree with the fat AABB so that
// we don't fail to create a pair that may touch later.
final AABB fatAABB = tree.getFatAABB(m_queryProxyId);
// Query tree, create pairs and add them pair buffer.
tree.query(this, fatAABB);
}
// Reset move buffer
moveCount = 0;
// Sort the pair buffer to expose duplicates.
Arrays.sort(pairBuffer, 0, pairCount);
// Send the pairs back to the client.
int i = 0;
while (i < pairCount) {
Pair primaryPair = pairBuffer[i];
Object userDataA = tree.getUserData(primaryPair.proxyIdA);
Object userDataB = tree.getUserData(primaryPair.proxyIdB);
callback.addPair(userDataA, userDataB);
++i;
// Skip any duplicate pairs.
while (i < pairCount) {
Pair pair = pairBuffer[i];
if (pair.proxyIdA != primaryPair.proxyIdA || pair.proxyIdB != primaryPair.proxyIdB) {
break;
}
++i;
}
}
}
@Override
public void query(TreeCallback callback, AABB aabb) {
tree.query(callback, aabb);
}
@Override
public void raycast(TreeRayCastCallback callback, RayCastInput input) {
tree.raycast(callback, input);
}
private void bufferMove(int proxyId) {
if (moveCount == moveCapacity) {
int[] old = moveBuffer;
moveCapacity *= 2;
moveBuffer = new int[moveCapacity];
System.arraycopy(old, 0, moveBuffer, 0, old.length);
}
moveBuffer[moveCount] = proxyId;
++moveCount;
}
private void unbufferMove(int proxyId) {
for (int i = 0; i < moveCount; i++) {
if (moveBuffer[i] == proxyId) {
moveBuffer[i] = NULL_PROXY;
}
}
}
/**
* This is called from DynamicTree::query when we are gathering pairs.
*/
@Override
public boolean treeCallback(int proxyId) {
// A proxy cannot form a pair with itself.
if (proxyId == m_queryProxyId) {
return true;
}
// Grow the pair buffer as needed.
if (pairCount == pairCapacity) {
Pair[] oldBuffer = pairBuffer;
pairCapacity *= 2;
pairBuffer = new Pair[pairCapacity];
System.arraycopy(oldBuffer, 0, pairBuffer, 0, oldBuffer.length);
for (int i = oldBuffer.length; i < pairCapacity; i++) {
pairBuffer[i] = new Pair();
}
}
if (proxyId < m_queryProxyId) {
pairBuffer[pairCount].proxyIdA = proxyId;
pairBuffer[pairCount].proxyIdB = m_queryProxyId;
} else {
pairBuffer[pairCount].proxyIdA = m_queryProxyId;
pairBuffer[pairCount].proxyIdB = proxyId;
}
++pairCount;
return true;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy