Normand Briere
2018-05-22 42107f9a01652cb2f47228d20c1148a2a22f6a63
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
/*
 * Java port of Bullet (c) 2008 Martin Dvorak <jezek2@advel.cz>
 *
 * Bullet Continuous Collision Detection and Physics Library
 * Copyright (c) 2003-2008 Erwin Coumans  http://www.bulletphysics.com/
 *
 * This software is provided 'as-is', without any express or implied warranty.
 * In no event will the authors be held liable for any damages arising from
 * the use of this software.
 * 
 * Permission is granted to anyone to use this software for any purpose, 
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 * 
 * 1. The origin of this software must not be misrepresented; you must not
 *    claim that you wrote the original software. If you use this software
 *    in a product, an acknowledgment in the product documentation would be
 *    appreciated but is not required.
 * 2. Altered source versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.
 * 3. This notice may not be removed or altered from any source distribution.
 */
 
package com.bulletphysics.collision.shapes;
 
import com.bulletphysics.collision.broadphase.BroadphaseNativeType;
import com.bulletphysics.linearmath.MatrixUtil;
import com.bulletphysics.linearmath.Transform;
import com.bulletphysics.linearmath.VectorUtil;
import com.bulletphysics.util.ObjectArrayList;
import cz.advel.stack.Stack;
import javax.vecmath.Matrix3f;
import javax.vecmath.Vector3f;
 
// JAVA NOTE: CompoundShape from 2.71
 
/**
 * CompoundShape allows to store multiple other {@link CollisionShape}s. This allows
 * for moving concave collision objects. This is more general than the {@link BvhTriangleMeshShape}.
 * 
 * @author jezek2
 */
public class CompoundShape extends CollisionShape {
 
   private final ObjectArrayList<CompoundShapeChild> children = new ObjectArrayList<CompoundShapeChild>();
   private final Vector3f localAabbMin = new Vector3f(1e30f, 1e30f, 1e30f);
   private final Vector3f localAabbMax = new Vector3f(-1e30f, -1e30f, -1e30f);
 
   private OptimizedBvh aabbTree = null;
 
   private float collisionMargin = 0f;
   protected final Vector3f localScaling = new Vector3f(1f, 1f, 1f);
 
   public void addChildShape(Transform localTransform, CollisionShape shape) {
       //m_childTransforms.push_back(localTransform);
       //m_childShapes.push_back(shape);
       CompoundShapeChild child = new CompoundShapeChild();
       child.transform.set(localTransform);
       child.childShape = shape;
       child.childShapeType = shape.getShapeType();
       child.childMargin = shape.getMargin();
 
       children.add(child);
 
       // extend the local aabbMin/aabbMax
       Vector3f _localAabbMin = Stack.alloc(Vector3f.class), _localAabbMax = Stack.alloc(Vector3f.class);
       shape.getAabb(localTransform, _localAabbMin, _localAabbMax);
 
       // JAVA NOTE: rewritten
//        for (int i=0;i<3;i++)
//        {
//            if (this.localAabbMin[i] > _localAabbMin[i])
//            {
//                this.localAabbMin[i] = _localAabbMin[i];
//            }
//            if (this.localAabbMax[i] < _localAabbMax[i])
//            {
//                this.localAabbMax[i] = _localAabbMax[i];
//            }
//        }
       VectorUtil.setMin(this.localAabbMin, _localAabbMin);
       VectorUtil.setMax(this.localAabbMax, _localAabbMax);
   }
 
   /**
    * Remove all children shapes that contain the specified shape.
    */
   public void removeChildShape(CollisionShape shape) {
       boolean done_removing;
 
       // Find the children containing the shape specified, and remove those children.
       do {
           done_removing = true;
 
           for (int i = 0; i < children.size(); i++) {
               if (children.getQuick(i).childShape == shape) {
                   children.removeQuick(i);
                   done_removing = false;  // Do another iteration pass after removing from the vector
                   break;
               }
           }
       }
       while (!done_removing);
 
       recalculateLocalAabb();
   }
   
   public int getNumChildShapes() {
       return children.size();
   }
 
   public CollisionShape getChildShape(int index) {
       return children.getQuick(index).childShape;
   }
 
   public Transform getChildTransform(int index, Transform out) {
       out.set(children.getQuick(index).transform);
       return out;
   }
 
   public ObjectArrayList<CompoundShapeChild> getChildList() {
       return children;
   }
 
   /**
    * getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version.
    */
   @Override
   public void getAabb(Transform trans, Vector3f aabbMin, Vector3f aabbMax) {
       Vector3f localHalfExtents = Stack.alloc(Vector3f.class);
       localHalfExtents.sub(localAabbMax, localAabbMin);
       localHalfExtents.scale(0.5f);
       localHalfExtents.x += getMargin();
       localHalfExtents.y += getMargin();
       localHalfExtents.z += getMargin();
 
       Vector3f localCenter = Stack.alloc(Vector3f.class);
       localCenter.add(localAabbMax, localAabbMin);
       localCenter.scale(0.5f);
 
       Matrix3f abs_b = (Matrix3f) Stack.alloc(trans.basis);
       MatrixUtil.absolute(abs_b);
 
       Vector3f center = (Vector3f) Stack.alloc(localCenter);
       trans.transform(center);
 
       Vector3f tmp = Stack.alloc(Vector3f.class);
 
       Vector3f extent = Stack.alloc(Vector3f.class);
       abs_b.getRow(0, tmp);
       extent.x = tmp.dot(localHalfExtents);
       abs_b.getRow(1, tmp);
       extent.y = tmp.dot(localHalfExtents);
       abs_b.getRow(2, tmp);
       extent.z = tmp.dot(localHalfExtents);
 
       aabbMin.sub(center, extent);
       aabbMax.add(center, extent);
   }
 
   /**
    * Re-calculate the local Aabb. Is called at the end of removeChildShapes.
    * Use this yourself if you modify the children or their transforms.
    */
   public void recalculateLocalAabb() {
       // Recalculate the local aabb
       // Brute force, it iterates over all the shapes left.
       localAabbMin.set(1e30f, 1e30f, 1e30f);
       localAabbMax.set(-1e30f, -1e30f, -1e30f);
 
       Vector3f tmpLocalAabbMin = Stack.alloc(Vector3f.class);
       Vector3f tmpLocalAabbMax = Stack.alloc(Vector3f.class);
 
       // extend the local aabbMin/aabbMax
       for (int j = 0; j < children.size(); j++) {
           children.getQuick(j).childShape.getAabb(children.getQuick(j).transform, tmpLocalAabbMin, tmpLocalAabbMax);
           
           for (int i = 0; i < 3; i++) {
               if (VectorUtil.getCoord(localAabbMin, i) > VectorUtil.getCoord(tmpLocalAabbMin, i)) {
                   VectorUtil.setCoord(localAabbMin, i, VectorUtil.getCoord(tmpLocalAabbMin, i));
               }
               if (VectorUtil.getCoord(localAabbMax, i) < VectorUtil.getCoord(tmpLocalAabbMax, i)) {
                   VectorUtil.setCoord(localAabbMax, i, VectorUtil.getCoord(tmpLocalAabbMax, i));
               }
           }
       }
   }
   
   @Override
   public void setLocalScaling(Vector3f scaling) {
       localScaling.set(scaling);
   }
 
   @Override
   public Vector3f getLocalScaling(Vector3f out) {
       out.set(localScaling);
       return out;
   }
 
   @Override
   public void calculateLocalInertia(float mass, Vector3f inertia) {
       // approximation: take the inertia from the aabb for now
       Transform ident = Stack.alloc(Transform.class);
       ident.setIdentity();
       Vector3f aabbMin = Stack.alloc(Vector3f.class), aabbMax = Stack.alloc(Vector3f.class);
       getAabb(ident, aabbMin, aabbMax);
 
       Vector3f halfExtents = Stack.alloc(Vector3f.class);
       halfExtents.sub(aabbMax, aabbMin);
       halfExtents.scale(0.5f);
 
       float lx = 2f * halfExtents.x;
       float ly = 2f * halfExtents.y;
       float lz = 2f * halfExtents.z;
 
       inertia.x = (mass / 12f) * (ly * ly + lz * lz);
       inertia.y = (mass / 12f) * (lx * lx + lz * lz);
       inertia.z = (mass / 12f) * (lx * lx + ly * ly);
   }
   
   @Override
   public BroadphaseNativeType getShapeType() {
       return BroadphaseNativeType.COMPOUND_SHAPE_PROXYTYPE;
   }
 
   @Override
   public void setMargin(float margin) {
       collisionMargin = margin;
   }
 
   @Override
   public float getMargin() {
       return collisionMargin;
   }
 
   @Override
   public String getName() {
       return "Compound";
   }
 
   // this is optional, but should make collision queries faster, by culling non-overlapping nodes
   // void    createAabbTreeFromChildren();
   
   public OptimizedBvh getAabbTree() {
       return aabbTree;
   }
 
   /**
    * Computes the exact moment of inertia and the transform from the coordinate
    * system defined by the principal axes of the moment of inertia and the center
    * of mass to the current coordinate system. "masses" points to an array
    * of masses of the children. The resulting transform "principal" has to be
    * applied inversely to all children transforms in order for the local coordinate
    * system of the compound shape to be centered at the center of mass and to coincide
    * with the principal axes. This also necessitates a correction of the world transform
    * of the collision object by the principal transform.
    */
   public void calculatePrincipalAxisTransform(float[] masses, Transform principal, Vector3f inertia) {
       int n = children.size();
 
       float totalMass = 0;
       Vector3f center = Stack.alloc(Vector3f.class);
       center.set(0, 0, 0);
       for (int k = 0; k < n; k++) {
           center.scaleAdd(masses[k], children.getQuick(k).transform.origin, center);
           totalMass += masses[k];
       }
       center.scale(1f / totalMass);
       principal.origin.set(center);
 
       Matrix3f tensor = Stack.alloc(Matrix3f.class);
       tensor.setZero();
 
       for (int k = 0; k < n; k++) {
           Vector3f i = Stack.alloc(Vector3f.class);
           children.getQuick(k).childShape.calculateLocalInertia(masses[k], i);
 
           Transform t = children.getQuick(k).transform;
           Vector3f o = Stack.alloc(Vector3f.class);
           o.sub(t.origin, center);
 
           // compute inertia tensor in coordinate system of compound shape
           Matrix3f j = Stack.alloc(Matrix3f.class);
           j.transpose(t.basis);
 
           j.m00 *= i.x;
           j.m01 *= i.x;
           j.m02 *= i.x;
           j.m10 *= i.y;
           j.m11 *= i.y;
           j.m12 *= i.y;
           j.m20 *= i.z;
           j.m21 *= i.z;
           j.m22 *= i.z;
 
           j.mul(t.basis, j);
 
           // add inertia tensor
           tensor.add(j);
 
           // compute inertia tensor of pointmass at o
           float o2 = o.lengthSquared();
           j.setRow(0, o2, 0, 0);
           j.setRow(1, 0, o2, 0);
           j.setRow(2, 0, 0, o2);
           j.m00 += o.x * -o.x;
           j.m01 += o.y * -o.x;
           j.m02 += o.z * -o.x;
           j.m10 += o.x * -o.y;
           j.m11 += o.y * -o.y;
           j.m12 += o.z * -o.y;
           j.m20 += o.x * -o.z;
           j.m21 += o.y * -o.z;
           j.m22 += o.z * -o.z;
 
           // add inertia tensor of pointmass
           tensor.m00 += masses[k] * j.m00;
           tensor.m01 += masses[k] * j.m01;
           tensor.m02 += masses[k] * j.m02;
           tensor.m10 += masses[k] * j.m10;
           tensor.m11 += masses[k] * j.m11;
           tensor.m12 += masses[k] * j.m12;
           tensor.m20 += masses[k] * j.m20;
           tensor.m21 += masses[k] * j.m21;
           tensor.m22 += masses[k] * j.m22;
       }
 
       MatrixUtil.diagonalize(tensor, principal.basis, 0.00001f, 20);
 
       inertia.set(tensor.m00, tensor.m11, tensor.m22);
   }
 
}