• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*******************************************************************************
2  * Copyright 2011 See AUTHORS file.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  ******************************************************************************/
16 
17 package com.badlogic.gdx.tests.bullet;
18 
19 import com.badlogic.gdx.Gdx;
20 import com.badlogic.gdx.graphics.Color;
21 import com.badlogic.gdx.graphics.PerspectiveCamera;
22 import com.badlogic.gdx.graphics.g3d.Model;
23 import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
24 import com.badlogic.gdx.math.Vector3;
25 import com.badlogic.gdx.physics.bullet.collision.*;
26 
27 /** Based on FrustumCullingTest by Xoppa.
28  *
29  * @author jsjolund */
30 public class PairCacheTest extends BaseBulletTest {
31 
32 	final static float BOX_X_MIN = -25;
33 	final static float BOX_Y_MIN = -25;
34 	final static float BOX_Z_MIN = -25;
35 
36 	final static float BOX_X_MAX = 25;
37 	final static float BOX_Y_MAX = 25;
38 	final static float BOX_Z_MAX = 25;
39 
40 	final static float SPEED_X = 360f / 7f;
41 	final static float SPEED_Y = 360f / 19f;
42 	final static float SPEED_Z = 360f / 13f;
43 
44 	final static int BOXCOUNT = 100;
45 
46 	private boolean useFrustumCam = false;
47 
48 	private btPairCachingGhostObject ghostObject;
49 	private BulletEntity ghostEntity;
50 	private btPersistentManifoldArray manifoldArray;
51 
52 	private float angleX, angleY, angleZ;
53 
54 	private ShapeRenderer shapeRenderer;
55 
56 	private PerspectiveCamera frustumCam;
57 	private PerspectiveCamera overviewCam;
58 
59 	@Override
create()60 	public void create () {
61 		super.create();
62 
63 		instructions = "Tap to toggle view\nLong press to toggle debug mode\nSwipe for next test\nCtrl+drag to rotate\nScroll to zoom";
64 
65 		world.addConstructor("collisionBox", new BulletConstructor(world.getConstructor("box").model));
66 
67 		// Create the entities
68 		final float dX = BOX_X_MAX - BOX_X_MIN;
69 		final float dY = BOX_Y_MAX - BOX_Y_MIN;
70 		final float dZ = BOX_Z_MAX - BOX_Z_MIN;
71 		for (int i = 0; i < BOXCOUNT; i++)
72 			world.add("collisionBox", BOX_X_MIN + dX * (float)Math.random(), BOX_Y_MIN + dY * (float)Math.random(),
73 					BOX_Z_MIN + dZ * (float)Math.random()).setColor(0.25f + 0.5f * (float)Math.random(),
74 					0.25f + 0.5f * (float)Math.random(), 0.25f + 0.5f * (float)Math.random(), 1f);
75 
76 		manifoldArray = new btPersistentManifoldArray();
77 		disposables.add(manifoldArray);
78 
79 		overviewCam = camera;
80 		overviewCam.position.set(BOX_X_MAX, BOX_Y_MAX, BOX_Z_MAX);
81 		overviewCam.lookAt(Vector3.Zero);
82 		overviewCam.far = 150f;
83 		overviewCam.update();
84 
85 		frustumCam = new PerspectiveCamera(camera.fieldOfView, camera.viewportWidth, camera.viewportHeight);
86 		frustumCam.far = Vector3.len(BOX_X_MAX, BOX_Y_MAX, BOX_Z_MAX);
87 		frustumCam.update();
88 
89 		final Model ghostModel = FrustumCullingTest.createFrustumModel(frustumCam.frustum.planePoints);
90 		disposables.add(ghostModel);
91 
92 		// The ghost object does not need to be shaped as a camera frustum, it can have any collision shape.
93 		ghostObject = FrustumCullingTest.createFrustumObject(frustumCam.frustum.planePoints);
94 		disposables.add(ghostObject);
95 
96 		world.add(ghostEntity = new BulletEntity(ghostModel, ghostObject, 0, 0, 0));
97 		disposables.add(ghostEntity);
98 
99 		shapeRenderer = new ShapeRenderer();
100 		disposables.add(shapeRenderer);
101 
102 	}
103 
104 	@Override
createWorld()105 	public BulletWorld createWorld () {
106 		// No need to use dynamics for this test
107 		btDbvtBroadphase broadphase = new btDbvtBroadphase();
108 		btDefaultCollisionConfiguration collisionConfig = new btDefaultCollisionConfiguration();
109 		btCollisionDispatcher dispatcher = new btCollisionDispatcher(collisionConfig);
110 		btCollisionWorld collisionWorld = new btCollisionWorld(dispatcher, broadphase, collisionConfig);
111 		return new BulletWorld(collisionConfig, dispatcher, broadphase, null, collisionWorld);
112 	}
113 
114 	@Override
render()115 	public void render () {
116 		final float dt = Gdx.graphics.getDeltaTime();
117 		ghostEntity.transform.idt();
118 		ghostEntity.transform.rotate(Vector3.X, angleX = (angleX + dt * SPEED_X) % 360);
119 		ghostEntity.transform.rotate(Vector3.Y, angleY = (angleY + dt * SPEED_Y) % 360);
120 		ghostEntity.transform.rotate(Vector3.Z, angleZ = (angleZ + dt * SPEED_Z) % 360);
121 
122 		// Transform the ghost object
123 		ghostEntity.body.setWorldTransform(ghostEntity.transform);
124 
125 		// Transform the frustum cam
126 		frustumCam.direction.set(0, 0, -1);
127 		frustumCam.up.set(0, 1, 0);
128 		frustumCam.position.set(0, 0, 0);
129 		frustumCam.rotate(ghostEntity.transform);
130 		frustumCam.update();
131 
132 		super.render();
133 
134 		// Find all overlapping pairs which contain the ghost object and draw lines between the collision points.
135 		shapeRenderer.setProjectionMatrix(camera.combined);
136 		shapeRenderer.begin(ShapeRenderer.ShapeType.Line);
137 		shapeRenderer.setColor(Color.WHITE);
138 
139 		btBroadphasePairArray arr = world.broadphase.getOverlappingPairCache().getOverlappingPairArray();
140 		int numPairs = arr.size();
141 		for (int i = 0; i < numPairs; ++i) {
142 			manifoldArray.clear();
143 
144 			btBroadphasePair pair = arr.at(i);
145 			btBroadphaseProxy proxy0 = btBroadphaseProxy.obtain(pair.getPProxy0().getCPointer(), false);
146 			btBroadphaseProxy proxy1 = btBroadphaseProxy.obtain(pair.getPProxy1().getCPointer(), false);
147 
148 			btBroadphasePair collisionPair = world.collisionWorld.getPairCache().findPair(proxy0, proxy1);
149 
150 			if (collisionPair == null) continue;
151 
152 			btCollisionAlgorithm algorithm = collisionPair.getAlgorithm();
153 			if (algorithm != null) algorithm.getAllContactManifolds(manifoldArray);
154 
155 			for (int j = 0; j < manifoldArray.size(); j++) {
156 				btPersistentManifold manifold = manifoldArray.at(j);
157 
158 				boolean isFirstBody = manifold.getBody0() == ghostObject;
159 				int otherObjectIndex = isFirstBody ? manifold.getBody1().getUserValue() : manifold.getBody0().getUserValue();
160 				Color otherObjectColor = world.entities.get(otherObjectIndex).getColor();
161 
162 				for (int p = 0; p < manifold.getNumContacts(); ++p) {
163 					btManifoldPoint pt = manifold.getContactPoint(p);
164 
165 					if (pt.getDistance() < 0.f) {
166 						if (isFirstBody) {
167 							pt.getPositionWorldOnA(tmpV2);
168 							pt.getPositionWorldOnB(tmpV1);
169 						} else {
170 							pt.getPositionWorldOnA(tmpV1);
171 							pt.getPositionWorldOnB(tmpV2);
172 						}
173 						shapeRenderer.line(tmpV1.x, tmpV1.y, tmpV1.z, tmpV2.x, tmpV2.y, tmpV2.z, otherObjectColor, Color.WHITE);
174 					}
175 				}
176 			}
177 			btBroadphaseProxy.free(proxy0);
178 			btBroadphaseProxy.free(proxy1);
179 		}
180 		shapeRenderer.end();
181 	}
182 
183 	@Override
tap(float x, float y, int count, int button)184 	public boolean tap (float x, float y, int count, int button) {
185 		useFrustumCam = !useFrustumCam;
186 		if (useFrustumCam)
187 			camera = frustumCam;
188 		else
189 			camera = overviewCam;
190 		return true;
191 	}
192 
193 	@Override
update()194 	public void update () {
195 		super.update();
196 		// Not using dynamics, so update the collision world manually
197 		world.collisionWorld.performDiscreteCollisionDetection();
198 	}
199 }
200