Home | History | Annotate | Download | only in bullet
      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. */
     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. */
     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. */
     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 
     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 
    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 
    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. */
    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 
    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