babylon-box3d 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -3
- package/dist/loadBox3D.d.ts +7 -0
- package/dist/loadBox3D.d.ts.map +1 -1
- package/dist/loadBox3D.js +5 -4
- package/dist/loadBox3D.js.map +1 -1
- package/lib/esm/box3d.d.ts +46 -1
- package/lib/esm/box3d.js +2 -2
- package/lib/esm/box3d.wasm +0 -0
- package/lib/esm-f64/box3d.d.ts +312 -0
- package/lib/esm-f64/box3d.js +2 -0
- package/lib/esm-f64/box3d.wasm +0 -0
- package/lib/esm-f64-threads/box3d.d.ts +312 -0
- package/lib/esm-f64-threads/box3d.js +2 -0
- package/lib/esm-f64-threads/box3d.wasm +0 -0
- package/lib/esm-threads/box3d.d.ts +46 -1
- package/lib/esm-threads/box3d.js +2 -2
- package/lib/esm-threads/box3d.wasm +0 -0
- package/lib/node/box3d.d.ts +46 -1
- package/lib/node/box3d.mjs +2 -2
- package/lib/node/box3d.wasm +0 -0
- package/lib/node-f64/box3d.d.ts +312 -0
- package/lib/node-f64/box3d.mjs +2 -0
- package/lib/node-f64/box3d.wasm +0 -0
- package/lib/node-f64-threads/box3d.d.ts +312 -0
- package/lib/node-f64-threads/box3d.mjs +2 -0
- package/lib/node-f64-threads/box3d.wasm +0 -0
- package/lib/node-threads/box3d.d.ts +46 -1
- package/lib/node-threads/box3d.mjs +2 -2
- package/lib/node-threads/box3d.wasm +0 -0
- package/lib/umd/box3d.umd.js +2 -2
- package/lib/umd/box3d.umd.wasm +0 -0
- package/package.json +17 -1
- package/umd/babylon.box3d.js +30 -4
- package/umd/babylon.box3d.js.map +3 -3
- package/umd/babylon.box3d.min.js +2 -2
- package/umd/babylon.box3d.min.js.map +4 -4
- package/wasm/box3d_shim.c +390 -35
package/wasm/box3d_shim.c
CHANGED
|
@@ -50,6 +50,54 @@ BX_EXPORT int bx_GetVersion( void )
|
|
|
50
50
|
return v.major * 10000 + v.minor * 100 + v.revision;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
// World positions cross the boundary in doubles. Entry points take them as doubles, and those that give one back
|
|
54
|
+
// write it to s_scratchF64 (or a double buffer beside their float records) as well as to the float scratch. A build with
|
|
55
|
+
// BOX3D_DOUBLE_PRECISION keeps them exact far from the origin; the default build holds floats, so there the doubles
|
|
56
|
+
// are its floats widened, and the floats are what they always were.
|
|
57
|
+
#define BX_SCRATCH_F64_SIZE 16
|
|
58
|
+
static double s_scratchF64[BX_SCRATCH_F64_SIZE];
|
|
59
|
+
|
|
60
|
+
BX_EXPORT double* bx_ScratchF64( void )
|
|
61
|
+
{
|
|
62
|
+
return s_scratchF64;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/// 1 when this module was built with BOX3D_DOUBLE_PRECISION, so world positions are held in doubles.
|
|
66
|
+
BX_EXPORT int bx_IsDoublePrecision( void )
|
|
67
|
+
{
|
|
68
|
+
return b3IsDoublePrecision() ? 1 : 0;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
typedef struct bxDoubleBuffer
|
|
72
|
+
{
|
|
73
|
+
double* data;
|
|
74
|
+
int count;
|
|
75
|
+
int capacity;
|
|
76
|
+
} bxDoubleBuffer;
|
|
77
|
+
|
|
78
|
+
static void bxDoubleBuffer_Reserve( bxDoubleBuffer* buf, int count )
|
|
79
|
+
{
|
|
80
|
+
if ( count <= buf->capacity )
|
|
81
|
+
{
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
int capacity = buf->capacity == 0 ? 256 : buf->capacity;
|
|
85
|
+
while ( capacity < count )
|
|
86
|
+
{
|
|
87
|
+
capacity *= 2;
|
|
88
|
+
}
|
|
89
|
+
buf->data = (double*)realloc( buf->data, (size_t)capacity * sizeof( double ) );
|
|
90
|
+
buf->capacity = capacity;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/// A world position from three doubles: exact in a double precision build, rounded to float in the default one, as a
|
|
94
|
+
/// float argument always was.
|
|
95
|
+
static b3Pos bxPos( double x, double y, double z )
|
|
96
|
+
{
|
|
97
|
+
b3Pos p = { x, y, z };
|
|
98
|
+
return p;
|
|
99
|
+
}
|
|
100
|
+
|
|
53
101
|
typedef struct bxFloatBuffer
|
|
54
102
|
{
|
|
55
103
|
float* data;
|
|
@@ -106,8 +154,13 @@ typedef struct bxBody
|
|
|
106
154
|
bxHelper* helpers;
|
|
107
155
|
int helperCount;
|
|
108
156
|
int helperCapacity;
|
|
157
|
+
// The body's feature key: each of its shapes gets (featureKey << BX_FEATURE_INDEX_BITS) | its index in the body as
|
|
158
|
+
// Box3D's b3ShapeDef::featureKey, which orders new contacts, continuous collision and cast ties. 0 until it is set.
|
|
159
|
+
uint64_t featureKey;
|
|
109
160
|
} bxBody;
|
|
110
161
|
|
|
162
|
+
#define BX_FEATURE_INDEX_BITS 20
|
|
163
|
+
|
|
111
164
|
static void bxReleaseBodyShapes( bxBody* body, int destroyShapes );
|
|
112
165
|
|
|
113
166
|
static bxBody* s_bodies;
|
|
@@ -154,6 +207,10 @@ typedef struct bxShapeDesc
|
|
|
154
207
|
int groupIndex;
|
|
155
208
|
float rollingResistance;
|
|
156
209
|
int isSensor;
|
|
210
|
+
// Box3D's b3ShapeDef::invokeContactCreation, on by default: a static shape made with it starts in the broad phase's
|
|
211
|
+
// move buffer and looks for its own pairs on the next step. Off, it waits to be found by a moving shape. A container
|
|
212
|
+
// that has it off turns it off for every shape made from its children.
|
|
213
|
+
int invokeContactCreation;
|
|
157
214
|
bxChild* children;
|
|
158
215
|
int childCount;
|
|
159
216
|
int childCapacity;
|
|
@@ -685,7 +742,7 @@ BX_EXPORT void bx_World_SetContactTuning( int w, float hertz, float dampingRatio
|
|
|
685
742
|
}
|
|
686
743
|
}
|
|
687
744
|
|
|
688
|
-
BX_EXPORT void bx_World_Explode( int w,
|
|
745
|
+
BX_EXPORT void bx_World_Explode( int w, double px, double py, double pz, float radius, float falloff, float impulsePerArea )
|
|
689
746
|
{
|
|
690
747
|
b3WorldId worldId = bxGetWorld( w );
|
|
691
748
|
if ( B3_IS_NULL( worldId ) )
|
|
@@ -693,7 +750,7 @@ BX_EXPORT void bx_World_Explode( int w, float px, float py, float pz, float radi
|
|
|
693
750
|
return;
|
|
694
751
|
}
|
|
695
752
|
b3ExplosionDef def = b3DefaultExplosionDef();
|
|
696
|
-
def.position =
|
|
753
|
+
def.position = bxPos( px, py, pz );
|
|
697
754
|
def.radius = radius;
|
|
698
755
|
def.falloff = falloff;
|
|
699
756
|
def.impulsePerArea = impulsePerArea;
|
|
@@ -714,6 +771,13 @@ BX_EXPORT int bx_World_GetJointEventCount( int w )
|
|
|
714
771
|
return B3_IS_NON_NULL( worldId ) ? b3World_GetJointEvents( worldId ).count : 0;
|
|
715
772
|
}
|
|
716
773
|
|
|
774
|
+
/// The most the world's step stack has held at once, in bytes. Box3D grows the stack to 1.5 times this and keeps it.
|
|
775
|
+
BX_EXPORT int bx_World_GetStackUsed( int w )
|
|
776
|
+
{
|
|
777
|
+
b3WorldId worldId = bxGetWorld( w );
|
|
778
|
+
return B3_IS_NON_NULL( worldId ) ? b3World_GetCounters( worldId ).stackUsed : 0;
|
|
779
|
+
}
|
|
780
|
+
|
|
717
781
|
/// scratch: [bodyCount, shapeCount, contactCount, jointCount, islandCount, stepMs, collideMs, solveMs]
|
|
718
782
|
BX_EXPORT void bx_World_GetStats( int w )
|
|
719
783
|
{
|
|
@@ -985,7 +1049,7 @@ BX_EXPORT int bx_World_GetSensorEvents( int w )
|
|
|
985
1049
|
// ---------------------------------------------------------------------------------------------
|
|
986
1050
|
|
|
987
1051
|
/// type: 0 static, 1 kinematic, 2 dynamic
|
|
988
|
-
BX_EXPORT int bx_CreateBody( int w, int type,
|
|
1052
|
+
BX_EXPORT int bx_CreateBody( int w, int type, double px, double py, double pz, float qx, float qy, float qz, float qw, int isAwake )
|
|
989
1053
|
{
|
|
990
1054
|
b3WorldId worldId = bxGetWorld( w );
|
|
991
1055
|
if ( B3_IS_NULL( worldId ) )
|
|
@@ -996,7 +1060,7 @@ BX_EXPORT int bx_CreateBody( int w, int type, float px, float py, float pz, floa
|
|
|
996
1060
|
bxBody* body = s_bodies + slot;
|
|
997
1061
|
b3BodyDef def = b3DefaultBodyDef();
|
|
998
1062
|
def.type = (b3BodyType)type;
|
|
999
|
-
def.position =
|
|
1063
|
+
def.position = bxPos( px, py, pz );
|
|
1000
1064
|
def.rotation = bxQuat( qx, qy, qz, qw );
|
|
1001
1065
|
def.isAwake = isAwake != 0;
|
|
1002
1066
|
def.userData = (void*)(intptr_t)slot;
|
|
@@ -1092,37 +1156,47 @@ BX_EXPORT int bx_Body_GetType( int slot )
|
|
|
1092
1156
|
return (int)b3Body_GetType( body->id );
|
|
1093
1157
|
}
|
|
1094
1158
|
|
|
1095
|
-
BX_EXPORT void bx_Body_SetTransform( int slot,
|
|
1159
|
+
BX_EXPORT void bx_Body_SetTransform( int slot, double px, double py, double pz, float qx, float qy, float qz, float qw )
|
|
1096
1160
|
{
|
|
1097
1161
|
BX_BODY( slot );
|
|
1098
|
-
b3Body_SetTransform( body->id,
|
|
1162
|
+
b3Body_SetTransform( body->id, bxPos( px, py, pz ), bxQuat( qx, qy, qz, qw ) );
|
|
1099
1163
|
if ( body->helperCount > 0 )
|
|
1100
1164
|
{
|
|
1101
|
-
|
|
1165
|
+
b3WorldTransform xf;
|
|
1166
|
+
xf.p = bxPos( px, py, pz );
|
|
1167
|
+
xf.q = bxTransform( 0.0f, 0.0f, 0.0f, qx, qy, qz, qw ).q;
|
|
1102
1168
|
for ( int i = 0; i < body->helperCount; ++i )
|
|
1103
1169
|
{
|
|
1104
1170
|
if ( b3Body_IsValid( body->helpers[i].id ) )
|
|
1105
1171
|
{
|
|
1106
|
-
|
|
1172
|
+
b3WorldTransform h = b3MulWorldTransforms( xf, body->helpers[i].local );
|
|
1107
1173
|
b3Body_SetTransform( body->helpers[i].id, h.p, h.q );
|
|
1108
1174
|
}
|
|
1109
1175
|
}
|
|
1110
1176
|
}
|
|
1111
1177
|
}
|
|
1112
1178
|
|
|
1113
|
-
/// scratch: [px, py, pz, qx, qy, qz, qw]
|
|
1179
|
+
/// scratch: [px, py, pz, qx, qy, qz, qw]; scratchF64: [px, py, pz], the position as the build holds it
|
|
1114
1180
|
BX_EXPORT void bx_Body_GetTransform( int slot )
|
|
1115
1181
|
{
|
|
1116
1182
|
BX_BODY( slot );
|
|
1117
1183
|
b3WorldTransform xf = b3Body_GetTransform( body->id );
|
|
1118
|
-
|
|
1184
|
+
s_scratch[0] = (float)xf.p.x;
|
|
1185
|
+
s_scratch[1] = (float)xf.p.y;
|
|
1186
|
+
s_scratch[2] = (float)xf.p.z;
|
|
1119
1187
|
bxWriteQuat( 3, xf.q );
|
|
1188
|
+
s_scratchF64[0] = xf.p.x;
|
|
1189
|
+
s_scratchF64[1] = xf.p.y;
|
|
1190
|
+
s_scratchF64[2] = xf.p.z;
|
|
1120
1191
|
}
|
|
1121
1192
|
|
|
1122
|
-
BX_EXPORT void bx_Body_SetTargetTransform( int slot,
|
|
1193
|
+
BX_EXPORT void bx_Body_SetTargetTransform( int slot, double px, double py, double pz, float qx, float qy, float qz, float qw,
|
|
1194
|
+
float dt )
|
|
1123
1195
|
{
|
|
1124
1196
|
BX_BODY( slot );
|
|
1125
|
-
b3WorldTransform xf
|
|
1197
|
+
b3WorldTransform xf;
|
|
1198
|
+
xf.p = bxPos( px, py, pz );
|
|
1199
|
+
xf.q = bxTransform( 0.0f, 0.0f, 0.0f, qx, qy, qz, qw ).q;
|
|
1126
1200
|
b3Body_SetTargetTransform( body->id, xf, dt, true );
|
|
1127
1201
|
}
|
|
1128
1202
|
|
|
@@ -1186,10 +1260,10 @@ BX_EXPORT float bx_Body_GetGravityScale( int slot )
|
|
|
1186
1260
|
return b3Body_GetGravityScale( body->id );
|
|
1187
1261
|
}
|
|
1188
1262
|
|
|
1189
|
-
BX_EXPORT void bx_Body_ApplyForce( int slot, float fx, float fy, float fz,
|
|
1263
|
+
BX_EXPORT void bx_Body_ApplyForce( int slot, float fx, float fy, float fz, double px, double py, double pz )
|
|
1190
1264
|
{
|
|
1191
1265
|
BX_BODY( slot );
|
|
1192
|
-
b3Body_ApplyForce( body->id, bxVec3( fx, fy, fz ),
|
|
1266
|
+
b3Body_ApplyForce( body->id, bxVec3( fx, fy, fz ), bxPos( px, py, pz ), true );
|
|
1193
1267
|
}
|
|
1194
1268
|
|
|
1195
1269
|
BX_EXPORT void bx_Body_ApplyForceToCenter( int slot, float fx, float fy, float fz )
|
|
@@ -1204,10 +1278,10 @@ BX_EXPORT void bx_Body_ApplyTorque( int slot, float x, float y, float z )
|
|
|
1204
1278
|
b3Body_ApplyTorque( body->id, bxVec3( x, y, z ), true );
|
|
1205
1279
|
}
|
|
1206
1280
|
|
|
1207
|
-
BX_EXPORT void bx_Body_ApplyLinearImpulse( int slot, float ix, float iy, float iz,
|
|
1281
|
+
BX_EXPORT void bx_Body_ApplyLinearImpulse( int slot, float ix, float iy, float iz, double px, double py, double pz )
|
|
1208
1282
|
{
|
|
1209
1283
|
BX_BODY( slot );
|
|
1210
|
-
b3Body_ApplyLinearImpulse( body->id, bxVec3( ix, iy, iz ),
|
|
1284
|
+
b3Body_ApplyLinearImpulse( body->id, bxVec3( ix, iy, iz ), bxPos( px, py, pz ), true );
|
|
1211
1285
|
}
|
|
1212
1286
|
|
|
1213
1287
|
BX_EXPORT void bx_Body_ApplyLinearImpulseToCenter( int slot, float ix, float iy, float iz )
|
|
@@ -1301,6 +1375,15 @@ BX_EXPORT float* bx_BodyContactsPtr( void )
|
|
|
1301
1375
|
return s_bodyContacts.data;
|
|
1302
1376
|
}
|
|
1303
1377
|
|
|
1378
|
+
// Each record's points as [x, y, z] doubles, room for four to a record, beside the float records
|
|
1379
|
+
#define BX_BODY_CONTACT_POINTS_STRIDE ( 3 * B3_MAX_MANIFOLD_POINTS )
|
|
1380
|
+
static bxDoubleBuffer s_bodyContactPoints;
|
|
1381
|
+
|
|
1382
|
+
BX_EXPORT double* bx_BodyContactPointsF64Ptr( void )
|
|
1383
|
+
{
|
|
1384
|
+
return s_bodyContactPoints.data;
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1304
1387
|
/// The index of shapeId among the body's shapes, or -1.
|
|
1305
1388
|
static int bxShapeIndex( const bxBody* body, b3ShapeId shapeId )
|
|
1306
1389
|
{
|
|
@@ -1373,8 +1456,10 @@ BX_EXPORT int bx_Body_GetContacts( int slot )
|
|
|
1373
1456
|
}
|
|
1374
1457
|
bxFloatBuffer_Reserve( &s_bodyContacts, manifoldTotal * BX_BODY_CONTACT_STRIDE );
|
|
1375
1458
|
|
|
1459
|
+
bxDoubleBuffer_Reserve( &s_bodyContactPoints, manifoldTotal * BX_BODY_CONTACT_POINTS_STRIDE );
|
|
1376
1460
|
b3Pos center = b3Body_GetWorldCenter( body->id );
|
|
1377
1461
|
float* out = s_bodyContacts.data;
|
|
1462
|
+
double* outPoints = s_bodyContactPoints.data;
|
|
1378
1463
|
int count = 0;
|
|
1379
1464
|
for ( int i = 0; i < contactCount; ++i )
|
|
1380
1465
|
{
|
|
@@ -1394,6 +1479,7 @@ BX_EXPORT int bx_Body_GetContacts( int slot )
|
|
|
1394
1479
|
{
|
|
1395
1480
|
const b3Manifold* manifold = data->manifolds + m;
|
|
1396
1481
|
memset( out, 0, BX_BODY_CONTACT_STRIDE * sizeof( float ) );
|
|
1482
|
+
memset( outPoints, 0, BX_BODY_CONTACT_POINTS_STRIDE * sizeof( double ) );
|
|
1397
1483
|
out[0] = (float)selfIndex;
|
|
1398
1484
|
out[1] = (float)( other != NULL ? otherSlot : 0 );
|
|
1399
1485
|
out[2] = (float)otherIndex;
|
|
@@ -1414,6 +1500,9 @@ BX_EXPORT int bx_Body_GetContacts( int slot )
|
|
|
1414
1500
|
po[0] = (float)point.x;
|
|
1415
1501
|
po[1] = (float)point.y;
|
|
1416
1502
|
po[2] = (float)point.z;
|
|
1503
|
+
outPoints[3 * p + 0] = point.x;
|
|
1504
|
+
outPoints[3 * p + 1] = point.y;
|
|
1505
|
+
outPoints[3 * p + 2] = point.z;
|
|
1417
1506
|
po[3] = mp->separation;
|
|
1418
1507
|
po[4] = mp->normalImpulse;
|
|
1419
1508
|
po[5] = mp->totalNormalImpulse;
|
|
@@ -1422,6 +1511,7 @@ BX_EXPORT int bx_Body_GetContacts( int slot )
|
|
|
1422
1511
|
po[8] = (float)bxContactMaterial( other, otherIndex, mp->triangleIndex );
|
|
1423
1512
|
}
|
|
1424
1513
|
out += BX_BODY_CONTACT_STRIDE;
|
|
1514
|
+
outPoints += BX_BODY_CONTACT_POINTS_STRIDE;
|
|
1425
1515
|
count += 1;
|
|
1426
1516
|
}
|
|
1427
1517
|
}
|
|
@@ -1570,6 +1660,40 @@ BX_EXPORT int bx_Body_GetShapeCount( int slot )
|
|
|
1570
1660
|
return body->shapeCount;
|
|
1571
1661
|
}
|
|
1572
1662
|
|
|
1663
|
+
/// Gives the body a feature key, an integer from 1 to 2^44 - 1 passed as a double, and each of its shapes, now and when
|
|
1664
|
+
/// it is next shaped, the key (key << 20) | its index in the body. A moving shape's new contacts are made in the order
|
|
1665
|
+
/// of these keys, continuous collision sweeps in that order and a closest cast's tie goes to the lower key, so statics
|
|
1666
|
+
/// keyed by what they are (a cell, a piece) give the same contacts in the same order however and whenever they were
|
|
1667
|
+
/// made. Keys must differ between bodies a moving shape can reach. 0 takes the key off.
|
|
1668
|
+
BX_EXPORT void bx_Body_SetFeatureKey( int slot, double key )
|
|
1669
|
+
{
|
|
1670
|
+
BX_BODY( slot );
|
|
1671
|
+
uint64_t bodyKey = key >= 1.0 && key < 17592186044416.0 ? (uint64_t)key : 0;
|
|
1672
|
+
body->featureKey = bodyKey;
|
|
1673
|
+
for ( int i = 0; i < body->shapeCount; ++i )
|
|
1674
|
+
{
|
|
1675
|
+
if ( b3Shape_IsValid( body->shapes[i] ) )
|
|
1676
|
+
{
|
|
1677
|
+
b3Shape_SetFeatureKey( body->shapes[i], bodyKey == 0 ? 0 : ( bodyKey << BX_FEATURE_INDEX_BITS ) | (uint64_t)i );
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
|
|
1682
|
+
BX_EXPORT double bx_Body_GetFeatureKey( int slot )
|
|
1683
|
+
{
|
|
1684
|
+
BX_BODY_RET( slot, 0.0 );
|
|
1685
|
+
return (double)body->featureKey;
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1688
|
+
static b3ShapeId bxBodyShape( int slot, int index );
|
|
1689
|
+
|
|
1690
|
+
/// Shape `index`'s own feature key, as Box3D orders by it, passed as a double: exact up to 2^53.
|
|
1691
|
+
BX_EXPORT double bx_Body_GetShapeFeatureKey( int slot, int index )
|
|
1692
|
+
{
|
|
1693
|
+
b3ShapeId shapeId = bxBodyShape( slot, index );
|
|
1694
|
+
return B3_IS_NULL( shapeId ) ? 0.0 : (double)b3Shape_GetFeatureKey( shapeId );
|
|
1695
|
+
}
|
|
1696
|
+
|
|
1573
1697
|
/// Begin/end touch events and hit events are enabled separately so a body only pays for the events it asked for.
|
|
1574
1698
|
BX_EXPORT void bx_Body_SetEventFlags( int slot, int contactEvents, int hitEvents )
|
|
1575
1699
|
{
|
|
@@ -1614,6 +1738,7 @@ static int bxNewDesc( int kind )
|
|
|
1614
1738
|
desc->categoryBits = B3_DEFAULT_CATEGORY_BITS;
|
|
1615
1739
|
desc->maskBits = B3_DEFAULT_MASK_BITS;
|
|
1616
1740
|
desc->meshScale = b3Vec3_one;
|
|
1741
|
+
desc->invokeContactCreation = 1;
|
|
1617
1742
|
return slot;
|
|
1618
1743
|
}
|
|
1619
1744
|
|
|
@@ -1762,6 +1887,146 @@ BX_EXPORT int bx_ShapeDesc_CreateHeightField( const float* heights, const unsign
|
|
|
1762
1887
|
return slot;
|
|
1763
1888
|
}
|
|
1764
1889
|
|
|
1890
|
+
// Box3D's own allocator (core.c), which b3DestroyMesh and b3DestroyHeightField free with: an imported block must come
|
|
1891
|
+
// from it, with its alignment and its byte count.
|
|
1892
|
+
extern void* b3Alloc( size_t size );
|
|
1893
|
+
|
|
1894
|
+
/// Where a mesh or height field description's data starts in this instance's memory, or 0 for any other description.
|
|
1895
|
+
/// Box3D keeps either as one block addressed by offsets from its start, with no pointer in it, so the block's bytes
|
|
1896
|
+
/// (bx_ShapeDesc_GetGeometryByteCount of them) can be copied out and made into a shape in another instance of the same
|
|
1897
|
+
/// build: a worker's instance with no world builds the geometry, and the simulation's instance only copies it in.
|
|
1898
|
+
BX_EXPORT const void* bx_ShapeDesc_GetGeometryBytes( int slot )
|
|
1899
|
+
{
|
|
1900
|
+
bxShapeDesc* desc = bxGetDesc( slot );
|
|
1901
|
+
if ( desc == NULL )
|
|
1902
|
+
{
|
|
1903
|
+
return NULL;
|
|
1904
|
+
}
|
|
1905
|
+
if ( desc->kind == bx_meshDesc )
|
|
1906
|
+
{
|
|
1907
|
+
return desc->mesh;
|
|
1908
|
+
}
|
|
1909
|
+
if ( desc->kind == bx_heightFieldDesc )
|
|
1910
|
+
{
|
|
1911
|
+
return desc->heightField;
|
|
1912
|
+
}
|
|
1913
|
+
return NULL;
|
|
1914
|
+
}
|
|
1915
|
+
|
|
1916
|
+
/// The byte count of the block bx_ShapeDesc_GetGeometryBytes points at, or 0.
|
|
1917
|
+
BX_EXPORT int bx_ShapeDesc_GetGeometryByteCount( int slot )
|
|
1918
|
+
{
|
|
1919
|
+
bxShapeDesc* desc = bxGetDesc( slot );
|
|
1920
|
+
if ( desc == NULL )
|
|
1921
|
+
{
|
|
1922
|
+
return 0;
|
|
1923
|
+
}
|
|
1924
|
+
if ( desc->kind == bx_meshDesc && desc->mesh != NULL )
|
|
1925
|
+
{
|
|
1926
|
+
return desc->mesh->byteCount;
|
|
1927
|
+
}
|
|
1928
|
+
if ( desc->kind == bx_heightFieldDesc && desc->heightField != NULL )
|
|
1929
|
+
{
|
|
1930
|
+
return desc->heightField->byteCount;
|
|
1931
|
+
}
|
|
1932
|
+
return 0;
|
|
1933
|
+
}
|
|
1934
|
+
|
|
1935
|
+
// Whether an array of count elements of size bytes at offset lies inside a block of byteCount bytes. An offset of 0
|
|
1936
|
+
// means the array is absent.
|
|
1937
|
+
static int bxInBlock( int32_t offset, int32_t count, int size, int byteCount )
|
|
1938
|
+
{
|
|
1939
|
+
if ( offset == 0 )
|
|
1940
|
+
{
|
|
1941
|
+
return 1;
|
|
1942
|
+
}
|
|
1943
|
+
return offset > 0 && count >= 0 && (int64_t)offset + (int64_t)count * size <= byteCount;
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1946
|
+
/// A copy of bytes the caller has put in this instance's memory, in a block from Box3D's allocator, if they are a mesh
|
|
1947
|
+
/// (kind 3) or height field (kind 4) block of this build, whole and with every array inside it. NULL otherwise.
|
|
1948
|
+
static void* bxImportGeometry( const void* bytes, int byteCount, int kind )
|
|
1949
|
+
{
|
|
1950
|
+
if ( bytes == NULL || byteCount < 16 )
|
|
1951
|
+
{
|
|
1952
|
+
return NULL;
|
|
1953
|
+
}
|
|
1954
|
+
if ( kind == bx_meshDesc )
|
|
1955
|
+
{
|
|
1956
|
+
if ( byteCount < (int)sizeof( b3MeshData ) )
|
|
1957
|
+
{
|
|
1958
|
+
return NULL;
|
|
1959
|
+
}
|
|
1960
|
+
b3MeshData header;
|
|
1961
|
+
memcpy( &header, bytes, sizeof( header ) );
|
|
1962
|
+
if ( header.version != B3_MESH_VERSION || header.byteCount != byteCount ||
|
|
1963
|
+
bxInBlock( header.nodeOffset, header.nodeCount, (int)sizeof( b3MeshNode ), byteCount ) == 0 ||
|
|
1964
|
+
bxInBlock( header.vertexOffset, header.vertexCount, (int)sizeof( b3Vec3 ), byteCount ) == 0 ||
|
|
1965
|
+
bxInBlock( header.triangleOffset, header.triangleCount, (int)sizeof( b3MeshTriangle ), byteCount ) == 0 ||
|
|
1966
|
+
bxInBlock( header.materialOffset, header.triangleCount, 1, byteCount ) == 0 ||
|
|
1967
|
+
bxInBlock( header.flagsOffset, header.triangleCount, 1, byteCount ) == 0 )
|
|
1968
|
+
{
|
|
1969
|
+
return NULL;
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
else
|
|
1973
|
+
{
|
|
1974
|
+
if ( byteCount < (int)sizeof( b3HeightFieldData ) )
|
|
1975
|
+
{
|
|
1976
|
+
return NULL;
|
|
1977
|
+
}
|
|
1978
|
+
b3HeightFieldData header;
|
|
1979
|
+
memcpy( &header, bytes, sizeof( header ) );
|
|
1980
|
+
int points = header.columnCount * header.rowCount;
|
|
1981
|
+
int cells = ( header.columnCount - 1 ) * ( header.rowCount - 1 );
|
|
1982
|
+
if ( header.version != B3_HEIGHT_FIELD_VERSION || header.byteCount != byteCount || header.columnCount < 2 ||
|
|
1983
|
+
header.rowCount < 2 || bxInBlock( header.heightsOffset, points, 2, byteCount ) == 0 ||
|
|
1984
|
+
bxInBlock( header.materialOffset, cells, 1, byteCount ) == 0 ||
|
|
1985
|
+
bxInBlock( header.flagsOffset, 2 * cells, 1, byteCount ) == 0 )
|
|
1986
|
+
{
|
|
1987
|
+
return NULL;
|
|
1988
|
+
}
|
|
1989
|
+
}
|
|
1990
|
+
void* block = b3Alloc( (size_t)byteCount );
|
|
1991
|
+
if ( block != NULL )
|
|
1992
|
+
{
|
|
1993
|
+
memcpy( block, bytes, (size_t)byteCount );
|
|
1994
|
+
}
|
|
1995
|
+
return block;
|
|
1996
|
+
}
|
|
1997
|
+
|
|
1998
|
+
/// A mesh description from the bytes of a mesh block (bx_ShapeDesc_GetGeometryBytes, from this instance or another of
|
|
1999
|
+
/// the same build) that the caller has put at `bytes`: the block is copied as it is, and nothing in it needs fixing up.
|
|
2000
|
+
/// The scale is the description's, as bx_ShapeDesc_CreateMesh takes it. Returns 0 if the bytes are not such a block.
|
|
2001
|
+
BX_EXPORT int bx_ShapeDesc_CreateMeshFromBytes( const void* bytes, int byteCount, float sx, float sy, float sz )
|
|
2002
|
+
{
|
|
2003
|
+
b3MeshData* mesh = (b3MeshData*)bxImportGeometry( bytes, byteCount, bx_meshDesc );
|
|
2004
|
+
if ( mesh == NULL )
|
|
2005
|
+
{
|
|
2006
|
+
return 0;
|
|
2007
|
+
}
|
|
2008
|
+
int slot = bxNewDesc( bx_meshDesc );
|
|
2009
|
+
s_descs[slot].mesh = mesh;
|
|
2010
|
+
s_descs[slot].meshScale = bxVec3( sx, sy, sz );
|
|
2011
|
+
return slot;
|
|
2012
|
+
}
|
|
2013
|
+
|
|
2014
|
+
/// A height field description from the bytes of a height field block, as bx_ShapeDesc_CreateMeshFromBytes makes a mesh.
|
|
2015
|
+
/// The block carries its scale, quantization and winding; (ox, oy, oz) is the description's local offset, as
|
|
2016
|
+
/// bx_ShapeDesc_CreateHeightField takes it.
|
|
2017
|
+
BX_EXPORT int bx_ShapeDesc_CreateHeightFieldFromBytes( const void* bytes, int byteCount, float ox, float oy, float oz )
|
|
2018
|
+
{
|
|
2019
|
+
b3HeightFieldData* hf = (b3HeightFieldData*)bxImportGeometry( bytes, byteCount, bx_heightFieldDesc );
|
|
2020
|
+
if ( hf == NULL )
|
|
2021
|
+
{
|
|
2022
|
+
return 0;
|
|
2023
|
+
}
|
|
2024
|
+
int slot = bxNewDesc( bx_heightFieldDesc );
|
|
2025
|
+
s_descs[slot].heightField = hf;
|
|
2026
|
+
s_descs[slot].offset = bxVec3( ox, oy, oz );
|
|
2027
|
+
return slot;
|
|
2028
|
+
}
|
|
2029
|
+
|
|
1765
2030
|
BX_EXPORT int bx_ShapeDesc_CreateContainer( void )
|
|
1766
2031
|
{
|
|
1767
2032
|
return bxNewDesc( bx_containerDesc );
|
|
@@ -1905,6 +2170,27 @@ BX_EXPORT int bx_ShapeDesc_IsSensor( int slot )
|
|
|
1905
2170
|
return desc == NULL ? 0 : desc->isSensor;
|
|
1906
2171
|
}
|
|
1907
2172
|
|
|
2173
|
+
/// Whether a static shape made from this description looks for its own pairs on the next step (1, Box3D's default), or
|
|
2174
|
+
/// waits until a moving shape finds it (0). With 0 a static never enters the broad phase's move buffer, which saves the
|
|
2175
|
+
/// step the pair slots it would reserve for it (Box3D keeps its step stack at 1.5 times the largest it has needed), and
|
|
2176
|
+
/// a static made where a moving shape's fat bounds already reach it is paired only once that shape moves again, so a
|
|
2177
|
+
/// static made late pairs on the same step as one made at the start. Off on a container, it is off for every shape made
|
|
2178
|
+
/// from its children. Dynamic and kinematic shapes always look for pairs.
|
|
2179
|
+
BX_EXPORT void bx_ShapeDesc_SetInvokeContactCreation( int slot, int flag )
|
|
2180
|
+
{
|
|
2181
|
+
bxShapeDesc* desc = bxGetDesc( slot );
|
|
2182
|
+
if ( desc != NULL )
|
|
2183
|
+
{
|
|
2184
|
+
desc->invokeContactCreation = flag != 0;
|
|
2185
|
+
}
|
|
2186
|
+
}
|
|
2187
|
+
|
|
2188
|
+
BX_EXPORT int bx_ShapeDesc_GetInvokeContactCreation( int slot )
|
|
2189
|
+
{
|
|
2190
|
+
bxShapeDesc* desc = bxGetDesc( slot );
|
|
2191
|
+
return desc == NULL ? 0 : desc->invokeContactCreation;
|
|
2192
|
+
}
|
|
2193
|
+
|
|
1908
2194
|
static b3AABB bxDescAABB( bxShapeDesc* desc, b3Transform xf, b3Vec3 scale, int depth )
|
|
1909
2195
|
{
|
|
1910
2196
|
b3AABB aabb = { b3Vec3_zero, b3Vec3_zero };
|
|
@@ -2165,13 +2451,15 @@ static int bxBakeTransformedMesh( const bxShapeDesc* source, b3Transform xf, b3V
|
|
|
2165
2451
|
return slot;
|
|
2166
2452
|
}
|
|
2167
2453
|
|
|
2168
|
-
|
|
2454
|
+
/// invoke is 0 when a container above this description has contact creation off.
|
|
2455
|
+
static void bxInstantiate( bxBody* body, int descSlot, b3Transform xf, b3Vec3 scale, int depth, int invoke )
|
|
2169
2456
|
{
|
|
2170
2457
|
bxShapeDesc* desc = bxGetDesc( descSlot );
|
|
2171
2458
|
if ( desc == NULL || depth > 8 )
|
|
2172
2459
|
{
|
|
2173
2460
|
return;
|
|
2174
2461
|
}
|
|
2462
|
+
invoke = invoke != 0 && desc->invokeContactCreation != 0;
|
|
2175
2463
|
|
|
2176
2464
|
b3ShapeDef def = b3DefaultShapeDef();
|
|
2177
2465
|
def.density = desc->density;
|
|
@@ -2188,6 +2476,10 @@ static void bxInstantiate( bxBody* body, int descSlot, b3Transform xf, b3Vec3 sc
|
|
|
2188
2476
|
def.enableHitEvents = body->hitEvents != 0;
|
|
2189
2477
|
// the caller applies the mass once after instantiating every shape of the description
|
|
2190
2478
|
def.updateBodyMass = false;
|
|
2479
|
+
def.invokeContactCreation = invoke != 0;
|
|
2480
|
+
// the shape takes the next index on the body, whichever Box3D body it is made on; a body without a key leaves its
|
|
2481
|
+
// shapes at zero, so they fall back to their ids as unkeyed shapes do
|
|
2482
|
+
def.featureKey = body->featureKey == 0 ? 0 : ( body->featureKey << BX_FEATURE_INDEX_BITS ) | (uint64_t)body->shapeCount;
|
|
2191
2483
|
|
|
2192
2484
|
switch ( desc->kind )
|
|
2193
2485
|
{
|
|
@@ -2265,7 +2557,7 @@ static void bxInstantiate( bxBody* body, int descSlot, b3Transform xf, b3Vec3 sc
|
|
|
2265
2557
|
body->helperCapacity = capacity;
|
|
2266
2558
|
}
|
|
2267
2559
|
b3WorldTransform bodyXf = b3Body_GetTransform( body->id );
|
|
2268
|
-
|
|
2560
|
+
b3WorldTransform world = b3MulWorldTransforms( bodyXf, local );
|
|
2269
2561
|
b3BodyDef helperDef = b3DefaultBodyDef();
|
|
2270
2562
|
helperDef.type = b3_staticBody;
|
|
2271
2563
|
helperDef.position = world.p;
|
|
@@ -2291,7 +2583,8 @@ static void bxInstantiate( bxBody* body, int descSlot, b3Transform xf, b3Vec3 sc
|
|
|
2291
2583
|
break;
|
|
2292
2584
|
}
|
|
2293
2585
|
bxChild child = container->children[i];
|
|
2294
|
-
bxInstantiate( body, child.desc, b3MulTransforms( xf, child.transform ), bxMulScale( scale, child.scale ), depth + 1
|
|
2586
|
+
bxInstantiate( body, child.desc, b3MulTransforms( xf, child.transform ), bxMulScale( scale, child.scale ), depth + 1,
|
|
2587
|
+
invoke );
|
|
2295
2588
|
}
|
|
2296
2589
|
break;
|
|
2297
2590
|
}
|
|
@@ -2308,7 +2601,7 @@ BX_EXPORT void bx_Body_SetShape( int slot, int descSlot )
|
|
|
2308
2601
|
body->shapeDesc = descSlot;
|
|
2309
2602
|
if ( descSlot != 0 )
|
|
2310
2603
|
{
|
|
2311
|
-
bxInstantiate( body, descSlot, b3Transform_identity, b3Vec3_one, 0 );
|
|
2604
|
+
bxInstantiate( body, descSlot, b3Transform_identity, b3Vec3_one, 0, 1 );
|
|
2312
2605
|
}
|
|
2313
2606
|
b3Body_ApplyMassFromShapes( body->id );
|
|
2314
2607
|
}
|
|
@@ -3234,8 +3527,27 @@ typedef struct bxRayContext
|
|
|
3234
3527
|
int hitSensors;
|
|
3235
3528
|
int closestOnly;
|
|
3236
3529
|
int count;
|
|
3530
|
+
// the closest hit so far, for ties
|
|
3531
|
+
uint64_t bestKey;
|
|
3532
|
+
int bestBody;
|
|
3533
|
+
int bestIndex;
|
|
3237
3534
|
} bxRayContext;
|
|
3238
3535
|
|
|
3536
|
+
/// Whether a hit on (key, body, index) wins a tie against the closest so far: the lower feature key, then the lower body
|
|
3537
|
+
/// slot and shape index, so a tie does not go to whichever shape the broad phase's tree happened to give first.
|
|
3538
|
+
static int bxHitPrecedes( uint64_t key, int body, int index, uint64_t bestKey, int bestBody, int bestIndex )
|
|
3539
|
+
{
|
|
3540
|
+
if ( key != bestKey )
|
|
3541
|
+
{
|
|
3542
|
+
return key < bestKey;
|
|
3543
|
+
}
|
|
3544
|
+
if ( body != bestBody )
|
|
3545
|
+
{
|
|
3546
|
+
return body < bestBody;
|
|
3547
|
+
}
|
|
3548
|
+
return index < bestIndex;
|
|
3549
|
+
}
|
|
3550
|
+
|
|
3239
3551
|
static bxFloatBuffer s_rayHits;
|
|
3240
3552
|
#define BX_RAY_HIT_STRIDE 11
|
|
3241
3553
|
|
|
@@ -3244,6 +3556,22 @@ BX_EXPORT float* bx_RayHitsPtr( void )
|
|
|
3244
3556
|
return s_rayHits.data;
|
|
3245
3557
|
}
|
|
3246
3558
|
|
|
3559
|
+
// Each hit's point as [x, y, z] doubles, beside its float record
|
|
3560
|
+
static bxDoubleBuffer s_rayHitPoints;
|
|
3561
|
+
|
|
3562
|
+
BX_EXPORT double* bx_RayHitPointsF64Ptr( void )
|
|
3563
|
+
{
|
|
3564
|
+
return s_rayHitPoints.data;
|
|
3565
|
+
}
|
|
3566
|
+
|
|
3567
|
+
static void bxWriteHitPoint( int index, b3Pos point )
|
|
3568
|
+
{
|
|
3569
|
+
bxDoubleBuffer_Reserve( &s_rayHitPoints, ( index + 1 ) * 3 );
|
|
3570
|
+
s_rayHitPoints.data[3 * index + 0] = point.x;
|
|
3571
|
+
s_rayHitPoints.data[3 * index + 1] = point.y;
|
|
3572
|
+
s_rayHitPoints.data[3 * index + 2] = point.z;
|
|
3573
|
+
}
|
|
3574
|
+
|
|
3247
3575
|
static float bxRayCallback( b3ShapeId shapeId, b3Pos point, b3Vec3 normal, float fraction, uint64_t userMaterialId, int triangleIndex,
|
|
3248
3576
|
int childIndex, void* context )
|
|
3249
3577
|
{
|
|
@@ -3259,6 +3587,26 @@ static float bxRayCallback( b3ShapeId shapeId, b3Pos point, b3Vec3 normal, float
|
|
|
3259
3587
|
{
|
|
3260
3588
|
return -1.0f;
|
|
3261
3589
|
}
|
|
3590
|
+
int shapeIndex = bxShapeIndex( s_bodies + bodySlot, shapeId );
|
|
3591
|
+
// The ray is clipped just past the closest hit, not at it, so a shape that ties with it is still reported, and the
|
|
3592
|
+
// tie goes by feature key.
|
|
3593
|
+
float clip = b3MinFloat( nextafterf( fraction, 2.0f ), 1.0f );
|
|
3594
|
+
if ( ctx->closestOnly )
|
|
3595
|
+
{
|
|
3596
|
+
uint64_t key = b3Shape_GetFeatureKey( shapeId );
|
|
3597
|
+
if ( ctx->count > 0 )
|
|
3598
|
+
{
|
|
3599
|
+
float best = s_rayHits.data[6];
|
|
3600
|
+
if ( fraction > best ||
|
|
3601
|
+
( fraction == best && bxHitPrecedes( key, bodySlot, shapeIndex, ctx->bestKey, ctx->bestBody, ctx->bestIndex ) == 0 ) )
|
|
3602
|
+
{
|
|
3603
|
+
return b3MinFloat( nextafterf( best, 2.0f ), 1.0f );
|
|
3604
|
+
}
|
|
3605
|
+
}
|
|
3606
|
+
ctx->bestKey = key;
|
|
3607
|
+
ctx->bestBody = bodySlot;
|
|
3608
|
+
ctx->bestIndex = shapeIndex;
|
|
3609
|
+
}
|
|
3262
3610
|
int index = ctx->closestOnly ? 0 : ctx->count;
|
|
3263
3611
|
bxFloatBuffer_Reserve( &s_rayHits, ( index + 1 ) * BX_RAY_HIT_STRIDE );
|
|
3264
3612
|
float* out = s_rayHits.data + index * BX_RAY_HIT_STRIDE;
|
|
@@ -3272,14 +3620,15 @@ static float bxRayCallback( b3ShapeId shapeId, b3Pos point, b3Vec3 normal, float
|
|
|
3272
3620
|
out[7] = (float)bodySlot;
|
|
3273
3621
|
out[8] = (float)bxDescSlotFromShape( shapeId );
|
|
3274
3622
|
out[9] = (float)triangleIndex;
|
|
3275
|
-
out[10] = (float)
|
|
3623
|
+
out[10] = (float)shapeIndex;
|
|
3624
|
+
bxWriteHitPoint( index, point );
|
|
3276
3625
|
ctx->count = ctx->closestOnly ? 1 : ctx->count + 1;
|
|
3277
|
-
return ctx->closestOnly ?
|
|
3626
|
+
return ctx->closestOnly ? clip : 1.0f;
|
|
3278
3627
|
}
|
|
3279
3628
|
|
|
3280
3629
|
/// Casts a ray from origin along translation. Returns the number of hits written to bx_RayHitsPtr().
|
|
3281
3630
|
/// Each hit: [px, py, pz, nx, ny, nz, fraction, bodySlot, shapeDesc, triangleIndex, shapeIndex]
|
|
3282
|
-
BX_EXPORT int bx_World_CastRay( int w,
|
|
3631
|
+
BX_EXPORT int bx_World_CastRay( int w, double ox, double oy, double oz, float dx, float dy, float dz, unsigned int categoryBits,
|
|
3283
3632
|
unsigned int maskBits, int ignoreBody, int hitSensors, int closestOnly )
|
|
3284
3633
|
{
|
|
3285
3634
|
b3WorldId worldId = bxGetWorld( w );
|
|
@@ -3287,21 +3636,14 @@ BX_EXPORT int bx_World_CastRay( int w, float ox, float oy, float oz, float dx, f
|
|
|
3287
3636
|
{
|
|
3288
3637
|
return 0;
|
|
3289
3638
|
}
|
|
3290
|
-
bxRayContext ctx = { ignoreBody, hitSensors, closestOnly, 0 };
|
|
3639
|
+
bxRayContext ctx = { ignoreBody, hitSensors, closestOnly, 0, 0, 0, 0 };
|
|
3291
3640
|
b3QueryFilter filter = b3DefaultQueryFilter();
|
|
3292
3641
|
filter.categoryBits = (uint64_t)categoryBits;
|
|
3293
3642
|
filter.maskBits = (uint64_t)maskBits;
|
|
3294
|
-
b3World_CastRay( worldId,
|
|
3643
|
+
b3World_CastRay( worldId, bxPos( ox, oy, oz ), bxVec3( dx, dy, dz ), filter, bxRayCallback, &ctx );
|
|
3295
3644
|
return ctx.count;
|
|
3296
3645
|
}
|
|
3297
3646
|
|
|
3298
|
-
/// A world position from three doubles: exact in a double precision build, rounded to float in the default one.
|
|
3299
|
-
static b3Pos bxPos( double x, double y, double z )
|
|
3300
|
-
{
|
|
3301
|
-
b3Pos p = { x, y, z };
|
|
3302
|
-
return p;
|
|
3303
|
-
}
|
|
3304
|
-
|
|
3305
3647
|
typedef struct bxShapeCastContext
|
|
3306
3648
|
{
|
|
3307
3649
|
int ignoreBody;
|
|
@@ -3309,6 +3651,10 @@ typedef struct bxShapeCastContext
|
|
|
3309
3651
|
int count;
|
|
3310
3652
|
float radius;
|
|
3311
3653
|
b3Vec3 translation;
|
|
3654
|
+
// the closest hit so far, for ties
|
|
3655
|
+
uint64_t bestKey;
|
|
3656
|
+
int bestBody;
|
|
3657
|
+
int bestIndex;
|
|
3312
3658
|
} bxShapeCastContext;
|
|
3313
3659
|
|
|
3314
3660
|
// Box3D's shape cast stops where the two cores are max(slop, radii - slop) apart, so that a body moved to the hit is
|
|
@@ -3354,12 +3700,20 @@ static float bxShapeCastCallback( b3ShapeId shapeId, b3Pos point, b3Vec3 normal,
|
|
|
3354
3700
|
touch = b3MaxFloat( touch, 0.0f );
|
|
3355
3701
|
|
|
3356
3702
|
int index = ctx->count;
|
|
3703
|
+
int shapeIndex = bxShapeIndex( s_bodies + bodySlot, shapeId );
|
|
3357
3704
|
if ( ctx->closestOnly )
|
|
3358
3705
|
{
|
|
3359
|
-
|
|
3706
|
+
// a tie goes by feature key, not to whichever shape the tree gave first
|
|
3707
|
+
uint64_t key = b3Shape_GetFeatureKey( shapeId );
|
|
3708
|
+
if ( ctx->count > 0 &&
|
|
3709
|
+
( s_rayHits.data[6] < touch ||
|
|
3710
|
+
( s_rayHits.data[6] == touch && bxHitPrecedes( key, bodySlot, shapeIndex, ctx->bestKey, ctx->bestBody, ctx->bestIndex ) == 0 ) ) )
|
|
3360
3711
|
{
|
|
3361
3712
|
return 1.0f;
|
|
3362
3713
|
}
|
|
3714
|
+
ctx->bestKey = key;
|
|
3715
|
+
ctx->bestBody = bodySlot;
|
|
3716
|
+
ctx->bestIndex = shapeIndex;
|
|
3363
3717
|
index = 0;
|
|
3364
3718
|
}
|
|
3365
3719
|
bxFloatBuffer_Reserve( &s_rayHits, ( index + 1 ) * BX_RAY_HIT_STRIDE );
|
|
@@ -3374,7 +3728,8 @@ static float bxShapeCastCallback( b3ShapeId shapeId, b3Pos point, b3Vec3 normal,
|
|
|
3374
3728
|
out[7] = (float)bodySlot;
|
|
3375
3729
|
out[8] = (float)bxDescSlotFromShape( shapeId );
|
|
3376
3730
|
out[9] = (float)triangleIndex;
|
|
3377
|
-
out[10] = (float)
|
|
3731
|
+
out[10] = (float)shapeIndex;
|
|
3732
|
+
bxWriteHitPoint( index, point );
|
|
3378
3733
|
ctx->count = ctx->closestOnly ? 1 : ctx->count + 1;
|
|
3379
3734
|
return 1.0f;
|
|
3380
3735
|
}
|
|
@@ -3391,7 +3746,7 @@ BX_EXPORT int bx_World_CastShape( int w, double ox, double oy, double oz, const
|
|
|
3391
3746
|
{
|
|
3392
3747
|
return 0;
|
|
3393
3748
|
}
|
|
3394
|
-
bxShapeCastContext ctx = { ignoreBody, closestOnly, 0, radius, bxVec3( dx, dy, dz ) };
|
|
3749
|
+
bxShapeCastContext ctx = { ignoreBody, closestOnly, 0, radius, bxVec3( dx, dy, dz ), 0, 0, 0 };
|
|
3395
3750
|
b3QueryFilter filter = b3DefaultQueryFilter();
|
|
3396
3751
|
filter.categoryBits = (uint64_t)categoryBits;
|
|
3397
3752
|
filter.maskBits = (uint64_t)maskBits;
|