diff --git a/examples/SamplesApp/core/src/main/java/jolt/example/samples/app/GameScreen.java b/examples/SamplesApp/core/src/main/java/jolt/example/samples/app/GameScreen.java index 53f6fc0..99895db 100644 --- a/examples/SamplesApp/core/src/main/java/jolt/example/samples/app/GameScreen.java +++ b/examples/SamplesApp/core/src/main/java/jolt/example/samples/app/GameScreen.java @@ -1,170 +1,23 @@ package jolt.example.samples.app; import com.badlogic.gdx.ScreenAdapter; -import com.badlogic.gdx.math.MathUtils; -import com.badlogic.gdx.utils.ScreenUtils; -import jolt.JoltInterface; -import jolt.JoltSettings; -import jolt.MeshShapeSettings; -import jolt.PhysicsMaterialList; -import jolt.RVec3; -import jolt.ShapeResult; -import jolt.TriangleList; -import jolt.jolt.geometry.Triangle; -import jolt.jolt.math.Quat; -import jolt.jolt.physics.PhysicsSystem; -import jolt.jolt.physics.body.Body; -import jolt.jolt.physics.body.BodyCreationSettings; -import jolt.jolt.physics.body.BodyInterface; -import jolt.jolt.physics.collision.ObjectLayerPairFilterTable; -import jolt.jolt.physics.collision.broadphase.BroadPhaseLayer; -import jolt.jolt.physics.collision.broadphase.BroadPhaseLayerInterfaceTable; -import jolt.jolt.physics.collision.broadphase.ObjectVsBroadPhaseLayerFilterTable; -import static jolt.EMotionType.EMotionType_Static; -import static jolt.jolt.physics.EActivation.EActivation_Activate; +import jolt.example.samples.app.tests.BoxShapeTest; public class GameScreen extends ScreenAdapter { - // Object layers - static int LAYER_NON_MOVING = 0; - static int LAYER_MOVING = 1; - static int NUM_OBJECT_LAYERS = 2; + private SamplesApp samplesApp; - private JoltInterface jolt; - private PhysicsSystem physicsSystem; - private BodyInterface bodyInterface; @Override public void show() { - JoltSettings settings = new JoltSettings(); - setupCollisionFiltering(settings); - jolt = new JoltInterface(settings); -// settings.dispose(); - - physicsSystem = jolt.GetPhysicsSystem(); - bodyInterface = physicsSystem.GetBodyInterface(); - - createMeshFloor(30, 1, 4, 0, 5, 0); + samplesApp = new SamplesApp(); + samplesApp.setup(); + samplesApp.startTest(BoxShapeTest.class); } @Override public void render(float delta) { - ScreenUtils.clear(1, 1, 1, 1, true); - // Don't go below 30 Hz to prevent spiral of death - float deltaTime = (float)Math.min(delta, 1.0 / 30.0); - - updatePhysics(deltaTime); - } - - private void setupCollisionFiltering(JoltSettings settings) { - // Layer that objects can be in, determines which other objects it can collide with - // Typically you at least want to have 1 layer for moving bodies and 1 layer for static bodies, but you can have more - // layers if you want. E.g. you could have a layer for high detail collision (which is not used by the physics simulation - // but only if you do collision testing). - - ObjectLayerPairFilterTable objectFilter = new ObjectLayerPairFilterTable(NUM_OBJECT_LAYERS); - objectFilter.EnableCollision(LAYER_NON_MOVING, LAYER_MOVING); - objectFilter.EnableCollision(LAYER_MOVING, LAYER_MOVING); - - // Each broadphase layer results in a separate bounding volume tree in the broad phase. You at least want to have - // a layer for non-moving and moving objects to avoid having to update a tree full of static objects every frame. - // You can have a 1-on-1 mapping between object layers and broadphase layers (like in this case) but if you have - // many object layers you'll be creating many broad phase trees, which is not efficient. - - BroadPhaseLayer BP_LAYER_NON_MOVING = new BroadPhaseLayer((short)0); - BroadPhaseLayer BP_LAYER_MOVING = new BroadPhaseLayer((short)1); - int NUM_BROAD_PHASE_LAYERS = 2; - BroadPhaseLayerInterfaceTable bpInterface = new BroadPhaseLayerInterfaceTable(NUM_OBJECT_LAYERS, NUM_BROAD_PHASE_LAYERS); - bpInterface.MapObjectToBroadPhaseLayer(LAYER_NON_MOVING, BP_LAYER_NON_MOVING); - bpInterface.MapObjectToBroadPhaseLayer(LAYER_MOVING, BP_LAYER_MOVING); - - settings.set_mObjectLayerPairFilter(objectFilter); - settings.set_mBroadPhaseLayerInterface(bpInterface); - ObjectVsBroadPhaseLayerFilterTable broadPhaseLayerFilter = new ObjectVsBroadPhaseLayerFilterTable(settings.get_mBroadPhaseLayerInterface(), NUM_BROAD_PHASE_LAYERS, settings.get_mObjectLayerPairFilter(), NUM_OBJECT_LAYERS); - settings.set_mObjectVsBroadPhaseLayerFilter(broadPhaseLayerFilter); + samplesApp.update(delta); } - - private void updatePhysics(float deltaTime) { - // When running below 55 Hz, do 2 steps instead of 1 - var numSteps = deltaTime > 1.0 / 55.0 ? 2 : 1; - jolt.Step(deltaTime, numSteps); - } - - private float height(float x, float y) { - return MathUtils.sin(x / 2) * MathUtils.cos(y / 3); - } - - private void createMeshFloor(int n, int cellSize, int maxHeight, float posX, float posY, float posZ) { - // Create regular grid of triangles - - TriangleList triangles = new TriangleList(); - triangles.resize(n * n * 2); - for (int x = 0; x < n; ++x) - for (int z = 0; z < n; ++z) { - float center = n * cellSize / 2.0f; - - float x1 = cellSize * x - center; - float z1 = cellSize * z - center; - float x2 = x1 + cellSize; - float z2 = z1 + cellSize; - - { - Triangle t = triangles.at((x * n + z) * 2); - var v1 = t.get_mV(0); - v1.set_x(x1); - v1.set_y(height(x, z)); - v1.set_z(z1); - var v2 = t.get_mV(1); - v2.set_x(x1); - v2.set_y(height(x, z + 1)); - v2.set_z(z2); - var v3 = t.get_mV(2); - v3.set_x(x2); - v3.set_y(height(x + 1, z + 1)); - v3.set_z(z2); - } - - { - var t = triangles.at((x * n + z) * 2 + 1); - var v1 = t.get_mV(0); - v1.set_x(x1); - v1.set_y(height(x, z)); - v1.set_z(z1); - var v2 = t.get_mV(1); - v2.set_x(x2); - v2.set_y(height(x + 1, z + 1)); - v2.set_z(z2); - var v3 = t.get_mV(2); - v3.set_x(x2); - v3.set_y(height(x + 1, z)); - v3.set_z(z1); - } - } - var materials = new PhysicsMaterialList(); - ShapeResult shapeResult = new MeshShapeSettings(triangles, materials).Create(); - triangles.dispose(); - materials.dispose(); - boolean hasError = shapeResult.HasError(); - boolean isValid = shapeResult.IsValid(); - System.out.println("ShapeResult hasError: " + hasError); - System.out.println("ShapeResult isValid: " + isValid); -// IDLString idlString = shapeResult.GetError(); -// long cPointer = idlString.getCPointer(); -// String data = idlString.data(); -// System.out.println("ShapeResult GetError: " + data); - var shape = shapeResult.Get(); - // Create body - var creationSettings = new BodyCreationSettings(shape, new RVec3(posX, posY, posZ), new Quat(0, 0, 0, 1), EMotionType_Static, LAYER_NON_MOVING); - var body = bodyInterface.CreateBody(creationSettings); - creationSettings.dispose(); - addToScene(body, 0xc7c7c7); - } - - void addToScene(Body body, int color) { - bodyInterface.AddBody(body.GetID(), EActivation_Activate); - -// addToThreeScene(body, color); - } - } \ No newline at end of file diff --git a/examples/SamplesApp/core/src/main/java/jolt/example/samples/app/SamplesApp.java b/examples/SamplesApp/core/src/main/java/jolt/example/samples/app/SamplesApp.java index 56fe8a5..8a85bff 100644 --- a/examples/SamplesApp/core/src/main/java/jolt/example/samples/app/SamplesApp.java +++ b/examples/SamplesApp/core/src/main/java/jolt/example/samples/app/SamplesApp.java @@ -1,9 +1,28 @@ package jolt.example.samples.app; +import jolt.example.samples.app.tests.BoxShapeTest; + public class SamplesApp { - public void startTest(Class testClass) { + Test test; + + public void setup() { + + } + + public void update(float delta) { + if(test != null) { + test.update(delta); + } + } + public void startTest(Class testClass) { + if(test != null) { + test.dispose(); + test = null; + } + test = new BoxShapeTest(); + test.setup(); } public void nextTest() { diff --git a/examples/SamplesApp/core/src/main/java/jolt/example/samples/app/Test.java b/examples/SamplesApp/core/src/main/java/jolt/example/samples/app/Test.java index 894544b..d1161bc 100644 --- a/examples/SamplesApp/core/src/main/java/jolt/example/samples/app/Test.java +++ b/examples/SamplesApp/core/src/main/java/jolt/example/samples/app/Test.java @@ -1,15 +1,199 @@ package jolt.example.samples.app; +import com.badlogic.gdx.math.MathUtils; +import com.badlogic.gdx.utils.ScreenUtils; import jolt.DebugRendererEm; +import jolt.EMotionType; +import jolt.JoltInterface; +import jolt.JoltSettings; +import jolt.MeshShapeSettings; +import jolt.PhysicsMaterialList; +import jolt.RVec3; +import jolt.ShapeResult; +import jolt.TriangleList; import jolt.jolt.core.TempAllocator; +import jolt.jolt.geometry.Triangle; +import jolt.jolt.math.Quat; +import jolt.jolt.math.Vec3; import jolt.jolt.physics.PhysicsSystem; +import jolt.jolt.physics.body.Body; +import jolt.jolt.physics.body.BodyCreationSettings; import jolt.jolt.physics.body.BodyInterface; +import jolt.jolt.physics.collision.ObjectLayerPairFilterTable; +import jolt.jolt.physics.collision.broadphase.BroadPhaseLayer; +import jolt.jolt.physics.collision.broadphase.BroadPhaseLayerInterfaceTable; +import jolt.jolt.physics.collision.broadphase.ObjectVsBroadPhaseLayerFilterTable; +import jolt.jolt.physics.collision.shape.BoxShape; +import static jolt.EMotionType.EMotionType_Static; +import static jolt.jolt.physics.EActivation.EActivation_Activate; +import static jolt.jolt.physics.EActivation.EActivation_DontActivate; public abstract class Test { - PhysicsSystem mPhysicsSystem = null; - BodyInterface mBodyInterface = null; - DebugRendererEm mDebugRenderer = null; - TempAllocator mTempAllocator = null; + // Object layers + protected static int LAYER_NON_MOVING = 0; + protected static int LAYER_MOVING = 1; + protected static int NUM_OBJECT_LAYERS = 2; -} + protected JoltInterface jolt; + protected PhysicsSystem physicsSystem = null; + protected BodyInterface bodyInterface = null; + protected DebugRendererEm debugRenderer = null; + protected TempAllocator tempAllocator = null; + + public void setup() { + JoltSettings settings = new JoltSettings(); + setupCollisionFiltering(settings); + jolt = new JoltInterface(settings); + settings.dispose(); + physicsSystem = jolt.GetPhysicsSystem(); + bodyInterface = physicsSystem.GetBodyInterface(); + +// createMeshFloor(30, 1, 4, 0, 5, 0); + } + + public void dispose() { + + } + + public void update(float delta) { + ScreenUtils.clear(1, 1, 1, 1, true); + // Don't go below 30 Hz to prevent spiral of death + float deltaTime = (float)Math.min(delta, 1.0 / 30.0); + + updatePhysics(deltaTime); + } + + protected void initialize() {} + + protected float getWorldScale() { return 1.0f; } + + protected Body createFloor() { + return createFloor(200f); + } + + protected Body createFloor(float inSize) { + float scale = getWorldScale(); + Vec3 inHalfExtent = new Vec3(scale * (0.5f * inSize), scale * 1.0f, scale * (0.5f * inSize)); + RVec3 inPosition = new RVec3(0.0f, scale * -1.0f, 0.0f); + Quat inRotation = Quat.sIdentity(); + BoxShape bodyShape = new BoxShape(inHalfExtent, 0.0f); + BodyCreationSettings bodySettings = new BodyCreationSettings(bodyShape, inPosition, inRotation, EMotionType_Static, LAYER_NON_MOVING); + Body body = bodyInterface.CreateBody(bodySettings); + bodyInterface.AddBody(body.GetID(), EActivation_DontActivate); + inHalfExtent.dispose(); + inPosition.dispose(); + return body; + } + + private void updatePhysics(float deltaTime) { + // When running below 55 Hz, do 2 steps instead of 1 + var numSteps = deltaTime > 1.0 / 55.0 ? 2 : 1; + jolt.Step(deltaTime, numSteps); + } + + private void setupCollisionFiltering(JoltSettings settings) { + // Layer that objects can be in, determines which other objects it can collide with + // Typically you at least want to have 1 layer for moving bodies and 1 layer for static bodies, but you can have more + // layers if you want. E.g. you could have a layer for high detail collision (which is not used by the physics simulation + // but only if you do collision testing). + + ObjectLayerPairFilterTable objectFilter = new ObjectLayerPairFilterTable(NUM_OBJECT_LAYERS); + objectFilter.EnableCollision(LAYER_NON_MOVING, LAYER_MOVING); + objectFilter.EnableCollision(LAYER_MOVING, LAYER_MOVING); + + // Each broadphase layer results in a separate bounding volume tree in the broad phase. You at least want to have + // a layer for non-moving and moving objects to avoid having to update a tree full of static objects every frame. + // You can have a 1-on-1 mapping between object layers and broadphase layers (like in this case) but if you have + // many object layers you'll be creating many broad phase trees, which is not efficient. + + BroadPhaseLayer BP_LAYER_NON_MOVING = new BroadPhaseLayer((short)0); + BroadPhaseLayer BP_LAYER_MOVING = new BroadPhaseLayer((short)1); + int NUM_BROAD_PHASE_LAYERS = 2; + BroadPhaseLayerInterfaceTable bpInterface = new BroadPhaseLayerInterfaceTable(NUM_OBJECT_LAYERS, NUM_BROAD_PHASE_LAYERS); + bpInterface.MapObjectToBroadPhaseLayer(LAYER_NON_MOVING, BP_LAYER_NON_MOVING); + bpInterface.MapObjectToBroadPhaseLayer(LAYER_MOVING, BP_LAYER_MOVING); + + settings.set_mObjectLayerPairFilter(objectFilter); + settings.set_mBroadPhaseLayerInterface(bpInterface); + ObjectVsBroadPhaseLayerFilterTable broadPhaseLayerFilter = new ObjectVsBroadPhaseLayerFilterTable(settings.get_mBroadPhaseLayerInterface(), NUM_BROAD_PHASE_LAYERS, settings.get_mObjectLayerPairFilter(), NUM_OBJECT_LAYERS); + settings.set_mObjectVsBroadPhaseLayerFilter(broadPhaseLayerFilter); + } + + private float height(float x, float y) { + return MathUtils.sin(x / 2) * MathUtils.cos(y / 3); + } + + private void createMeshFloor(int n, int cellSize, int maxHeight, float posX, float posY, float posZ) { + // Create regular grid of triangles + + TriangleList triangles = new TriangleList(); + triangles.resize(n * n * 2); + for (int x = 0; x < n; ++x) + for (int z = 0; z < n; ++z) { + float center = n * cellSize / 2.0f; + + float x1 = cellSize * x - center; + float z1 = cellSize * z - center; + float x2 = x1 + cellSize; + float z2 = z1 + cellSize; + + { + Triangle t = triangles.at((x * n + z) * 2); + var v1 = t.get_mV(0); + v1.set_x(x1); + v1.set_y(height(x, z)); + v1.set_z(z1); + var v2 = t.get_mV(1); + v2.set_x(x1); + v2.set_y(height(x, z + 1)); + v2.set_z(z2); + var v3 = t.get_mV(2); + v3.set_x(x2); + v3.set_y(height(x + 1, z + 1)); + v3.set_z(z2); + } + + { + var t = triangles.at((x * n + z) * 2 + 1); + var v1 = t.get_mV(0); + v1.set_x(x1); + v1.set_y(height(x, z)); + v1.set_z(z1); + var v2 = t.get_mV(1); + v2.set_x(x2); + v2.set_y(height(x + 1, z + 1)); + v2.set_z(z2); + var v3 = t.get_mV(2); + v3.set_x(x2); + v3.set_y(height(x + 1, z)); + v3.set_z(z1); + } + } + var materials = new PhysicsMaterialList(); + ShapeResult shapeResult = new MeshShapeSettings(triangles, materials).Create(); + triangles.dispose(); + materials.dispose(); + boolean hasError = shapeResult.HasError(); + boolean isValid = shapeResult.IsValid(); + System.out.println("ShapeResult hasError: " + hasError); + System.out.println("ShapeResult isValid: " + isValid); +// IDLString idlString = shapeResult.GetError(); +// long cPointer = idlString.getCPointer(); +// String data = idlString.data(); +// System.out.println("ShapeResult GetError: " + data); + var shape = shapeResult.Get(); + // Create body + var creationSettings = new BodyCreationSettings(shape, new RVec3(posX, posY, posZ), new Quat(0, 0, 0, 1), EMotionType_Static, LAYER_NON_MOVING); + var body = bodyInterface.CreateBody(creationSettings); + creationSettings.dispose(); + addToScene(body, 0xc7c7c7); + } + + void addToScene(Body body, int color) { + bodyInterface.AddBody(body.GetID(), EActivation_Activate); + +// addToThreeScene(body, color); + } + +} \ No newline at end of file diff --git a/examples/SamplesApp/core/src/main/java/jolt/example/samples/app/tests/BoxShapeTest.java b/examples/SamplesApp/core/src/main/java/jolt/example/samples/app/tests/BoxShapeTest.java new file mode 100644 index 0000000..e81b93d --- /dev/null +++ b/examples/SamplesApp/core/src/main/java/jolt/example/samples/app/tests/BoxShapeTest.java @@ -0,0 +1,49 @@ +package jolt.example.samples.app.tests; + +import com.badlogic.gdx.math.Vector3; +import jolt.RVec3; +import jolt.example.samples.app.Test; +import jolt.jolt.math.Quat; +import jolt.jolt.math.Vec3; +import jolt.jolt.physics.body.Body; +import jolt.jolt.physics.body.BodyCreationSettings; +import jolt.jolt.physics.collision.shape.BoxShape; +import static jolt.EMotionType.EMotionType_Dynamic; +import static jolt.jolt.physics.EActivation.EActivation_Activate; + +public class BoxShapeTest extends Test { + + static float JPH_PI = 3.14159265358979323846f; + + @Override + protected void initialize() { + // Floor + createFloor(); + + Body body1 = createBody(new Vector3(20, 1, 1), new Vector3(0, 10, 0), Quat.sIdentity()); + bodyInterface.AddBody(body1.GetID(), EActivation_Activate); + + Body body2 = createBody(new Vector3(2, 3, 4), new Vector3(0, 10, 10), Quat.sRotation(Vec3.sAxisZ(), 0.25f * JPH_PI)); + bodyInterface.AddBody(body2.GetID(), EActivation_Activate); + + Quat quatX3 = Quat.sRotation(Vec3.sAxisX(), 0.25f * JPH_PI); + Quat quatZ3 = Quat.sRotation(Vec3.sAxisZ(), 0.25f * JPH_PI); + quatX3.SetX(quatX3.GetX() * quatZ3.GetX()); + quatX3.SetY(quatX3.GetY() * quatZ3.GetY()); + quatX3.SetZ(quatX3.GetZ() * quatZ3.GetZ()); + Body body3 = createBody(new Vector3(0.5f, 0.75f, 1.0f), new Vector3(0, 10, 20), quatX3); + bodyInterface.AddBody(body3.GetID(), EActivation_Activate); + } + + private Body createBody(Vector3 inHalfExtent, Vector3 inPosition, Quat inRotation) { + float scale = getWorldScale(); + Vec3 inHalfExtentJolt = new Vec3(inHalfExtent.x, inHalfExtent.y, inHalfExtent.z); + RVec3 inPositionJolt = new RVec3(inPosition.x, inPosition.y, inPosition.z); + BoxShape bodyShape = new BoxShape(inHalfExtentJolt); + BodyCreationSettings bodySettings = new BodyCreationSettings(bodyShape, inPositionJolt, inRotation, EMotionType_Dynamic, LAYER_MOVING); + Body body = bodyInterface.CreateBody(bodySettings); + inHalfExtentJolt.dispose(); + inPositionJolt.dispose(); + return body; + } +} \ No newline at end of file