• 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.physics.bullet;
18 
19 import java.util.Arrays;
20 
21 import com.badlogic.gdx.graphics.g3d.model.MeshPart;
22 import com.badlogic.gdx.graphics.g3d.model.Node;
23 import com.badlogic.gdx.math.Matrix4;
24 import com.badlogic.gdx.physics.bullet.collision.btBvhTriangleMeshShape;
25 import com.badlogic.gdx.physics.bullet.collision.btCollisionShape;
26 import com.badlogic.gdx.physics.bullet.collision.btCompoundShape;
27 import com.badlogic.gdx.physics.bullet.linearmath.LinearMath;
28 import com.badlogic.gdx.physics.bullet.linearmath.LinearMathConstants;
29 import com.badlogic.gdx.utils.Array;
30 import com.badlogic.gdx.utils.GdxRuntimeException;
31 import com.badlogic.gdx.utils.Pool;
32 import com.badlogic.gdx.utils.SharedLibraryLoader;
33 
34 public class Bullet {
35 	/** The version of the Bullet library used by this wrapper. */
36 	public final static int VERSION = LinearMathConstants.BT_BULLET_VERSION;
37 
38 	protected static boolean useRefCounting = false;
39 	protected static boolean enableLogging = true;
40 
41 	/** Loads the native Bullet native library and initializes the gdx-bullet extension. Must be called before any of the bullet
42 	 * classes/methods can be used. */
init()43 	public static void init () {
44 		init(false);
45 	}
46 
47 	/** Loads the native Bullet native library and initializes the gdx-bullet extension. Must be called before any of the bullet
48 	 * classes/methods can be used.
49 	 * @param useRefCounting Whether to use reference counting, causing object to be destroyed when no longer referenced. You must
50 	 *           use {@link BulletBase#obtain()} and {@link BulletBase#release()} when using reference counting. */
init(boolean useRefCounting)51 	public static void init (boolean useRefCounting) {
52 		init(useRefCounting, true);
53 	}
54 
55 	/** Loads the native Bullet native library and initializes the gdx-bullet extension. Must be called before any of the bullet
56 	 * classes/methods can be used.
57 	 * @param useRefCounting Whether to use reference counting, causing object to be destroyed when no longer referenced. You must
58 	 *           use {@link BulletBase#obtain()} and {@link BulletBase#release()} when using reference counting.
59 	 * @param logging Whether to log an error on potential errors in the application. */
init(boolean useRefCounting, boolean logging)60 	public static void init (boolean useRefCounting, boolean logging) {
61 		Bullet.useRefCounting = useRefCounting;
62 		Bullet.enableLogging = logging;
63 		new SharedLibraryLoader().load("gdx-bullet");
64 		final int version = LinearMath.btGetVersion();
65 		if (version != VERSION)
66 			throw new GdxRuntimeException("Bullet binaries version (" + version + ") does not match source version (" + VERSION
67 				+ ")");
68 	}
69 
70 	protected static class ShapePart {
71 		public Array<MeshPart> parts = new Array<MeshPart>();
72 		public Matrix4 transform = new Matrix4();
73 	}
74 
75 	private final static Pool<ShapePart> shapePartPool = new Pool<ShapePart>() {
76 		@Override
77 		protected ShapePart newObject () {
78 			return new ShapePart();
79 		}
80 	};
81 	private final static Array<ShapePart> shapePartArray = new Array<ShapePart>();
82 
83 	private final static Matrix4 idt = new Matrix4();
84 	private final static Matrix4 tmpM = new Matrix4();
85 
getShapeParts(final Node node, final boolean applyTransform, final Array<ShapePart> out, final int offset, final Pool<ShapePart> pool)86 	public static void getShapeParts (final Node node, final boolean applyTransform, final Array<ShapePart> out, final int offset,
87 		final Pool<ShapePart> pool) {
88 		final Matrix4 transform = applyTransform ? node.localTransform : idt;
89 		if (node.parts.size > 0) {
90 			ShapePart part = null;
91 			for (int i = offset, n = out.size; i < n; i++) {
92 				final ShapePart p = out.get(i);
93 				if (Arrays.equals(p.transform.val, transform.val)) {
94 					part = p;
95 					break;
96 				}
97 			}
98 			if (part == null) {
99 				part = pool.obtain();
100 				part.parts.clear();
101 				part.transform.set(transform);
102 				out.add(part);
103 			}
104 			for (int i = 0, n = node.parts.size; i < n; i++)
105 				part.parts.add(node.parts.get(i).meshPart);
106 		}
107 		if (node.hasChildren()) {
108 			final boolean transformed = applyTransform && !Arrays.equals(transform.val, idt.val);
109 			final int o = transformed ? out.size : offset;
110 			getShapeParts(node.getChildren(), out, o, pool);
111 			if (transformed) {
112 				for (int i = o, n = out.size; i < n; i++) {
113 					final ShapePart part = out.get(i);
114 					tmpM.set(part.transform);
115 					part.transform.set(transform).mul(tmpM);
116 				}
117 			}
118 		}
119 	}
120 
getShapeParts(final Iterable<T> nodes, final Array<ShapePart> out, final int offset, final Pool<ShapePart> pool)121 	public static <T extends Node> void getShapeParts (final Iterable<T> nodes, final Array<ShapePart> out, final int offset,
122 		final Pool<ShapePart> pool) {
123 		for (T node : nodes)
124 			getShapeParts(node, true, out, offset, pool);
125 	}
126 
obtainStaticNodeShape(final Node node, final boolean applyTransform)127 	public static btCollisionShape obtainStaticNodeShape (final Node node, final boolean applyTransform) {
128 		getShapeParts(node, applyTransform, shapePartArray, 0, shapePartPool);
129 		btCollisionShape result = obtainStaticShape(shapePartArray);
130 		shapePartPool.freeAll(shapePartArray);
131 		shapePartArray.clear();
132 		return result;
133 	}
134 
135 	/** Obtain a {@link btCollisionShape} based on the specified nodes, which can be used for a static body but not for a dynamic
136 	 * body. Depending on the specified nodes the result will be either a {@link btBvhTriangleMeshShape} or a
137 	 * {@link btCompoundShape} of multiple btBvhTriangleMeshShape's. Where possible, the same btBvhTriangleMeshShape will be reused
138 	 * if multiple nodes use the same (mesh) part. The node transformation (translation and rotation) will be included, but scaling
139 	 * will be ignored.
140 	 * @param nodes The nodes for which to obtain a node, typically this would be: `model.nodes`.
141 	 * @return The obtained shape, if you're using reference counting then you can release the shape when no longer needed. */
obtainStaticNodeShape(final Array<Node> nodes)142 	public static btCollisionShape obtainStaticNodeShape (final Array<Node> nodes) {
143 		getShapeParts(nodes, shapePartArray, 0, shapePartPool);
144 		btCollisionShape result = obtainStaticShape(shapePartArray);
145 		shapePartPool.freeAll(shapePartArray);
146 		shapePartArray.clear();
147 		return result;
148 	}
149 
obtainStaticShape(final Array<ShapePart> parts)150 	public static btCollisionShape obtainStaticShape (final Array<ShapePart> parts) {
151 		if (parts.size == 0) return null;
152 		if (parts.size == 1 && Arrays.equals(parts.get(0).transform.val, idt.val))
153 			return btBvhTriangleMeshShape.obtain(parts.get(0).parts);
154 		btCompoundShape result = new btCompoundShape();
155 		result.obtain();
156 		for (int i = 0, n = parts.size; i < n; i++) {
157 			final btBvhTriangleMeshShape shape = btBvhTriangleMeshShape.obtain(parts.get(i).parts);
158 			result.addChildShape(parts.get(i).transform, shape);
159 			shape.release();
160 		}
161 		return result;
162 	}
163 }
164