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 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kotlin-graphics/bullet/73b7d39778c05936af120ac95ab88c249c71c508/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Oct 07 11:32:36 CEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.5.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.buildFileName = 'build.gradle'
2 |
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/Template.kt:
--------------------------------------------------------------------------------
1 | package bullet
2 |
3 | import bullet.linearMath.Transform
4 | import bullet.linearMath.Vec3
5 |
6 | interface ConvexTemplate {
7 |
8 | var worldTrans: Transform
9 |
10 | var margin: Float
11 |
12 | fun getLocalSupportWithMargin(dir: Vec3): Vec3
13 | fun getLocalSupportWithoutMargin(dir: Vec3): Vec3
14 |
15 | val objectCenterInWorld: Vec3
16 | }
17 |
18 | abstract class DistanceTemplate {
19 |
20 | var pointOnA = Vec3()
21 | var pointOnB = Vec3()
22 | var normalBtoA = Vec3()
23 | var distance = 0f
24 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/bullet.kt:
--------------------------------------------------------------------------------
1 | package bullet
2 |
3 | import bullet.collision.broadphaseCollision.*
4 | import bullet.dynamics.constraintSolver.SolverConstraint
5 | import bullet.dynamics.constraintSolver.TypedConstraint
6 | import bullet.linearMath.Vec3
7 |
8 |
9 | //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
10 | //
11 | // Constants
12 | //
13 | //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
14 | //#define DBL_DECIMAL_DIG 17 // # of decimal digits of rounding precision
15 | //#define DBL_DIG 15 // # of decimal digits of precision
16 | //#define DBL_EPSILON 2.2204460492503131e-016 // smallest such that 1.0+DBL_EPSILON != 1.0
17 | //#define DBL_HAS_SUBNORM 1 // type does support subnormal numbers
18 | //#define DBL_MANT_DIG 53 // # of bits in mantissa
19 | //#define DBL_MAX 1.7976931348623158e+308 // max value
20 | //#define DBL_MAX_10_EXP 308 // max decimal exponent
21 | //#define DBL_MAX_EXP 1024 // max binary exponent
22 | //#define DBL_MIN 2.2250738585072014e-308 // min positive value
23 | //#define DBL_MIN_10_EXP (-307) // min decimal exponent
24 | //#define DBL_MIN_EXP (-1021) // min binary exponent
25 | //#define _DBL_RADIX 2 // exponent radix
26 | //#define DBL_TRUE_MIN 4.9406564584124654e-324 // min positive value
27 | //
28 | //#define FLT_DECIMAL_DIG 9 // # of decimal digits of rounding precision
29 | //#define FLT_DIG 6 // # of decimal digits of precision
30 | /** smallest such that 1.0+FLT_EPSILON != 1.0 */
31 | val Float.Companion.EPSILON get() = 1.192092896e-07F
32 | //#define FLT_HAS_SUBNORM 1 // type does support subnormal numbers
33 | //#define FLT_GUARD 0
34 | //#define FLT_MANT_DIG 24 // # of bits in mantissa
35 | //#define FLT_MAX 3.402823466e+38F // max value
36 | //#define FLT_MAX_10_EXP 38 // max decimal exponent
37 | //#define FLT_MAX_EXP 128 // max binary exponent
38 | //#define FLT_MIN 1.175494351e-38F // min normalized positive value
39 | //#define FLT_MIN_10_EXP (-37) // min decimal exponent
40 | //#define FLT_MIN_EXP (-125) // min binary exponent
41 | //#define FLT_NORMALIZE 0
42 | //#define FLT_RADIX 2 // exponent radix
43 | //#define FLT_TRUE_MIN 1.401298464e-45F // min positive value
44 | //
45 | //#define LDBL_DIG DBL_DIG // # of decimal digits of precision
46 | //#define LDBL_EPSILON DBL_EPSILON // smallest such that 1.0+LDBL_EPSILON != 1.0
47 | //#define LDBL_HAS_SUBNORM DBL_HAS_SUBNORM // type does support subnormal numbers
48 | //#define LDBL_MANT_DIG DBL_MANT_DIG // # of bits in mantissa
49 | //#define LDBL_MAX DBL_MAX // max value
50 | //#define LDBL_MAX_10_EXP DBL_MAX_10_EXP // max decimal exponent
51 | //#define LDBL_MAX_EXP DBL_MAX_EXP // max binary exponent
52 | //#define LDBL_MIN DBL_MIN // min normalized positive value
53 | //#define LDBL_MIN_10_EXP DBL_MIN_10_EXP // min decimal exponent
54 | //#define LDBL_MIN_EXP DBL_MIN_EXP // min binary exponent
55 | //#define _LDBL_RADIX _DBL_RADIX // exponent radix
56 | //#define LDBL_TRUE_MIN DBL_TRUE_MIN // min positive value
57 | //
58 | //#define DECIMAL_DIG DBL_DECIMAL_DIG
59 |
60 | val Boolean.i get() = if (this) 1 else 0
61 | val Byte.i get() = toInt()
62 | val Int.f get() = toFloat()
63 | val Int.L get() = toLong()
64 | val Int.bool get() = this != 0
65 | val Int.s get() = toShort()
66 | val Short.i get() = toInt()
67 | val Number.f get() = toFloat()
68 | val Long.i get() = toInt()
69 | val Float.s get() = toShort()
70 | val Float.i get() = toInt()
71 | val Char.i get() = toInt()
72 |
73 | infix fun Int.has(b: Int) = (this and b) != 0
74 | infix fun Int.hasnt(b: Int) = (this and b) == 0
75 | infix fun Int.wo(b: Int) = this and b.inv()
76 |
77 | val Int.Companion.BYTES get() = 4
78 | val Float.Companion.BYTES get() = 4
79 |
80 | val DEBUG = true
81 | val DEBUG_DRAW = false
82 |
83 |
84 | infix fun ArrayList.push(element: T) = add(element)
85 | fun ArrayList.pop(): T {
86 | val last = last()
87 | remove(last)
88 | return last
89 | }
90 |
91 | fun ArrayList.swapLastAt(index: Int) = swap(index, lastIndex)
92 |
93 | fun ArrayList.swap(index0: Int, index1: Int) {
94 | val e = get(index0)
95 | set(index0, get(index1))
96 | set(index1, e)
97 | }
98 |
99 | infix fun ArrayList.resize(newSize: Int) {
100 | if (newSize == 0) clear()
101 | else when {
102 | size > newSize -> for (i in newSize until size) pop()
103 | newSize > size -> when (get(0)) {
104 | // is Dbvt.StkNN? -> for (i in size until newSize) add(null as T)
105 | is Dbvt.StkNN -> for (i in size until newSize) add(Dbvt.StkNN() as T)
106 | is DbvtNode -> for (i in size until newSize) add(DbvtNode() as T)
107 | is BroadphasePair -> for (i in size until newSize) add(BroadphasePair() as T)
108 | is TypedConstraint.ConstraintInfo1 -> for (i in size until newSize) add(TypedConstraint.ConstraintInfo1() as T)
109 | is SolverConstraint -> for (i in size until newSize) add(SolverConstraint() as T)
110 | is Int -> for (i in size until newSize) add(0 as T)
111 | is Vec3 -> for (i in size until newSize) add(Vec3() as T)
112 | is QuantizedBvhNode -> for (i in size until newSize) add(QuantizedBvhNode() as T)
113 | is CollisionAlgorithm -> for (i in size until newSize) add(null as T)
114 | }
115 | }
116 | }
117 |
118 |
119 | var DISABLE_DBVT_COMPOUNDSHAPE_RAYCAST_ACCELERATION = false
120 | var COMPARE_BTRAY_AABB2 = false
121 | var USE_PATH_COMPRESSION = true
122 | var USE_STATIC_ONLY = false
123 | var BT_NO_PROFILE = true
124 | var USE_SEPDISTANCE_UTIL2 = false
125 | var DISABLE_CAPSULE_CAPSULE_COLLIDER = false
126 | var TEST_INTERNAL_OBJECTS = true
127 | var ONLY_REPORT_DEEPEST_POINT = false
128 | var ZERO_MARGIN = false
129 | var DEBUG_CONTACTS = false
130 | var CLEAR_MANIFOLD = true
131 | var USE_PERSISTENT_CONTACTS = true
132 | var USE_CENTER_POINT = false
133 |
134 |
135 | /** internal debugging variable. this value shouldn't be too high */
136 | var gNumClampedCcdMotions = 0
137 |
138 |
139 | fun BT_PROFILE(text: String) {
140 | if (DEBUG) println(text)
141 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/broadphaseCollision/BroadphaseInterface.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.collision.broadphaseCollision
17 |
18 | import bullet.collision.collisionDispatch.CollisionObject
19 | import bullet.linearMath.Vec3
20 |
21 | interface BroadphaseAabbCallback {
22 | infix fun process(proxy: BroadphaseProxy) = false
23 | }
24 |
25 |
26 | open class BroadphaseRayCallback : BroadphaseAabbCallback {
27 | /** added some cached data to accelerate ray-AABB tests */
28 | val rayDirectionInverse = Vec3()
29 | val signs = IntArray(3)
30 | var lambdaMax = 0f
31 | }
32 |
33 | /** The BroadphaseInterface class provides an interface to detect aabb-overlapping object pairs.
34 | * Some implementations for this broadphase interface include AxisSweep3, _32BitAxisSweep3 and DbvtBroadphase.
35 | * The actual overlapping pair management, storage, adding and removing of pairs is dealt by the OverlappingPairCache
36 | * class. */
37 | interface BroadphaseInterface {
38 |
39 | fun createProxy(aabbMin: Vec3, aabbMax: Vec3, shapeType: Int, userPtr: CollisionObject, collisionFilterGroup: Int,
40 | collisionFilterMask: Int, dispatcher: Dispatcher): BroadphaseProxy
41 |
42 | fun destroyProxy(proxy: BroadphaseProxy, dispatcher: Dispatcher)
43 | fun setAabb(proxy: BroadphaseProxy, aabbMin: Vec3, aabbMax: Vec3, dispatcher: Dispatcher)
44 | fun getAabb(proxy: BroadphaseProxy, aabbMin: Vec3, aabbMax: Vec3)
45 |
46 | fun rayTest(rayFrom: Vec3, rayTo: Vec3, rayCallback: BroadphaseRayCallback, aabbMin: Vec3 = Vec3(), aabbMax: Vec3 = Vec3())
47 |
48 | fun aabbTest(aabbMin: Vec3, aabbMax: Vec3, callback: BroadphaseAabbCallback)
49 |
50 | /** calculateOverlappingPairs is optional: incremental algorithms (sweep and prune) might do it during the set aabb */
51 | fun calculateOverlappingPairs(dispatcher: Dispatcher)
52 |
53 | val overlappingPairCache: OverlappingPairCache
54 |
55 | /** getAabb returns the axis aligned bounding box in the 'global' coordinate frame will add some transform later */
56 | fun getBroadphaseAabb(aabbMin: Vec3, aabbMax: Vec3)
57 |
58 | /** reset broadphase internal structures, to ensure determinism/reproducability */
59 | fun resetPool(dispatcher: Dispatcher)
60 |
61 | fun printStats()
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/broadphaseCollision/CollistionAlgorithm.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.collision.broadphaseCollision
17 |
18 | import bullet.collision.collisionDispatch.CollisionObject
19 | import bullet.collision.collisionDispatch.CollisionObjectWrapper
20 | import bullet.collision.collisionDispatch.ManifoldResult
21 | import bullet.collision.narrowPhaseCollision.PersistentManifold
22 |
23 | class CollisionAlgorithmConstructionInfo(var dispatcher: Dispatcher? = null, var manifold: PersistentManifold? = null)
24 |
25 | /** CollisionAlgorithm is an collision interface that is compatible with the Broadphase and Dispatcher.
26 | * It is persistent over frames */
27 | abstract class CollisionAlgorithm {
28 |
29 | var dispatcher: Dispatcher? = null
30 |
31 | constructor()
32 | constructor(ci: CollisionAlgorithmConstructionInfo) {
33 | dispatcher = ci.dispatcher
34 | }
35 |
36 | open fun processCollision(body0Wrap: CollisionObjectWrapper, body1Wrap: CollisionObjectWrapper, dispatchInfo: DispatcherInfo,
37 | resultOut: ManifoldResult) = Unit
38 |
39 | open fun calculateTimeOfImpact(body0: CollisionObject, body1: CollisionObject, dispatchInfo: DispatcherInfo,
40 | resultOut: ManifoldResult) = 0f
41 |
42 | open fun getAllContactManifolds(manifoldArray: ArrayList) = Unit
43 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/broadphaseCollision/Dispatcher.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.collision.broadphaseCollision
17 |
18 | import bullet.collision.collisionDispatch.CollisionObject
19 | import bullet.collision.collisionDispatch.CollisionObjectWrapper
20 | import bullet.collision.narrowPhaseCollision.PersistentManifold
21 | import bullet.linearMath.DebugDraw
22 |
23 | class DispatcherInfo {
24 |
25 | enum class DispatchFunc { Invalid, DISCRETE, CONTINUOUS }
26 |
27 | var timeStep = 0f
28 | var stepCount = 0
29 | var dispatchFunc = DispatchFunc.DISCRETE
30 | var timeOfImpact = 1f
31 | var useContinuous = true
32 | var debugDraw: DebugDraw? = null
33 | var enableSatConvex = false
34 | var enableSPU = true
35 | var useEpa = true
36 | var allowedCcdPenetration = 0.04f
37 | var useConvexConservativeDistanceUtil = false
38 | var convexConservativeDistanceThreshold = 0f
39 | var deterministicOverlappingPairs = true
40 | }
41 |
42 | enum class DispatcherQueryType { Invalid, CONTACT_POINT_ALGORITHMS, CLOSEST_POINT_ALGORITHMS }
43 |
44 | /** The btDispatcher interface class can be used in combination with broadphase to dispatch calculations for
45 | * overlapping pairs.
46 | * For example for pairwise collision detection, calculating contact points stored in btPersistentManifold or user
47 | * callbacks (game logic). */
48 | interface Dispatcher {
49 |
50 | fun findAlgorithm(body0Wrap: CollisionObjectWrapper, body1Wrap: CollisionObjectWrapper, sharedManifold: PersistentManifold?,
51 | queryType: DispatcherQueryType): CollisionAlgorithm?
52 |
53 | fun getNewManifold(body0: CollisionObject, body1: CollisionObject): PersistentManifold
54 |
55 | fun releaseManifold(manifold: PersistentManifold)
56 |
57 | fun clearManifold(manifold: PersistentManifold)
58 |
59 | fun needsCollision(body0: CollisionObject?, body1: CollisionObject?): Boolean
60 |
61 | fun needsResponse(body0: CollisionObject, body1: CollisionObject): Boolean
62 |
63 | fun dispatchAllCollisionPairs(pairCache: OverlappingPairCache, dispatchInfo: DispatcherInfo, dispatcher: Dispatcher)
64 |
65 | val numManifolds: Int
66 |
67 | fun getManifoldByIndexInternal(index: Int): PersistentManifold
68 |
69 | val internalManifoldPointer: ArrayList? // TODO virtual btPersistentManifold** getInternalManifoldPointer() = 0;
70 |
71 | // virtual btPoolAllocator* getInternalManifoldPool() = 0;
72 |
73 | // virtual const btPoolAllocator* getInternalManifoldPool() const = 0;
74 |
75 | fun allocateCollisionAlgorithm(size: Int): Any?
76 |
77 | fun freeCollisionAlgorithm(ptr: Any?) // TODO useless, remove
78 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/broadphaseCollision/OverlappingPairCallback.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.collision.broadphaseCollision
17 |
18 | /** The OverlappingPairCallback interface is an additional optional broadphase user callback for adding/removing
19 | * overlapping pairs, similar interface to OverlappingPairCache. */
20 | interface OverlappingPairCallback{
21 |
22 | fun addOverlappingPair(proxy0: BroadphaseProxy, proxy1:BroadphaseProxy): BroadphasePair?
23 |
24 | fun removeOverlappingPair(proxy0:BroadphaseProxy,proxy1:BroadphaseProxy,dispatcher:Dispatcher): Any?
25 |
26 | fun removeOverlappingPairsContainingProxy(proxy0:BroadphaseProxy,dispatcher:Dispatcher)
27 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/collisionDispatch/ActivatingCollisionAlgorithm.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2008 Erwin Coumans http://bulletphysics.com
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.collision.collisionDispatch
17 |
18 | import bullet.collision.broadphaseCollision.CollisionAlgorithm
19 | import bullet.collision.broadphaseCollision.CollisionAlgorithmConstructionInfo
20 |
21 | /** This class is not enabled yet (work-in-progress) to more aggressively activate objects. */
22 | open class ActivatingCollisionAlgorithm : CollisionAlgorithm {
23 | // btCollisionObject* m_colObj0;
24 | // btCollisionObject* m_colObj1;
25 |
26 | constructor(ci: CollisionAlgorithmConstructionInfo) : super()
27 |
28 | constructor(ci: CollisionAlgorithmConstructionInfo,
29 | body0Wrap: CollisionObjectWrapper, body1Wrap: CollisionObjectWrapper) : super(ci)
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/collisionDispatch/BoxBoxCollisionAlgorithm.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.collision.collisionDispatch
17 |
18 | import bullet.USE_PERSISTENT_CONTACTS
19 | import bullet.collision.broadphaseCollision.CollisionAlgorithmConstructionInfo
20 | import bullet.collision.broadphaseCollision.DispatcherInfo
21 | import bullet.collision.collisionShapes.BoxShape
22 | import bullet.collision.narrowPhaseCollision.DiscreteCollisionDetectorInterface
23 | import bullet.collision.narrowPhaseCollision.PersistentManifold
24 | import bullet.linearMath.LARGE_FLOAT
25 |
26 | /** box-box collision detection */
27 | class BoxBoxCollisionAlgorithm : ActivatingCollisionAlgorithm {
28 |
29 | var ownManifold = false
30 | var manifold: PersistentManifold? = null
31 |
32 | constructor(ci: CollisionAlgorithmConstructionInfo) : super(ci)
33 | constructor(mf: PersistentManifold?, ci: CollisionAlgorithmConstructionInfo, body0Wrap: CollisionObjectWrapper,
34 | body1Wrap: CollisionObjectWrapper) : super(ci, body0Wrap, body1Wrap) {
35 | manifold = mf
36 | if (manifold == null && dispatcher!!.needsCollision(body0Wrap.collisionObject, body1Wrap.collisionObject)) {
37 | manifold = dispatcher!!.getNewManifold(body0Wrap.collisionObject!!, body1Wrap.collisionObject!!)
38 | ownManifold = true
39 | }
40 | }
41 |
42 | override fun processCollision(body0Wrap: CollisionObjectWrapper, body1Wrap: CollisionObjectWrapper, dispatchInfo: DispatcherInfo, resultOut: ManifoldResult) {
43 |
44 | if (manifold == null) return
45 |
46 | val box0 = body0Wrap.collisionShape as BoxShape
47 | val box1 = body1Wrap.collisionShape as BoxShape
48 |
49 | // report a contact. internally this will be kept persistent, and contact reduction is done
50 | resultOut.manifold = manifold
51 | if (!USE_PERSISTENT_CONTACTS) manifold!!.clearManifold()
52 |
53 | val input = DiscreteCollisionDetectorInterface.ClosestPointInput().apply {
54 | maximumDistanceSquared = LARGE_FLOAT
55 | transformA put body0Wrap.worldTransform
56 | transformB put body1Wrap.worldTransform
57 | }
58 |
59 | val detector = BoxBoxDetector(box0, box1)
60 | detector.getClosestPoints(input, resultOut, dispatchInfo.debugDraw)
61 |
62 | // refreshContactPoints is only necessary when using persistent contact points. otherwise all points are newly added
63 | if (USE_PERSISTENT_CONTACTS) if (ownManifold) resultOut.refreshContactPoints()
64 | }
65 |
66 | override fun calculateTimeOfImpact(body0: CollisionObject, body1: CollisionObject, dispatchInfo: DispatcherInfo,
67 | resultOut: ManifoldResult) = 1f //not yet
68 |
69 | override fun getAllContactManifolds(manifoldArray: ArrayList) {
70 | manifold?.let { if (ownManifold) manifoldArray.add(it) }
71 | }
72 |
73 | class CreateFunc : CollisionAlgorithmCreateFunc() {
74 | override fun createCollisionAlgorithm(info: CollisionAlgorithmConstructionInfo, body0Wrap: CollisionObjectWrapper,
75 | body1Wrap: CollisionObjectWrapper) =
76 | BoxBoxCollisionAlgorithm(null, info, body0Wrap, body1Wrap)
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/collisionDispatch/CollisionConfiguration.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.collision.collisionDispatch
17 |
18 | import bullet.collision.broadphaseCollision.BroadphaseNativeTypes
19 |
20 | /** CollisionConfiguration allows to configure Bullet collision detection
21 | * stack allocator size, default collision algorithms and persistent manifold pool size
22 | * todo: describe the meaning */
23 | abstract class CollisionConfiguration {
24 |
25 | ///memory pools TODO
26 | // virtual btPoolAllocator* getPersistentManifoldPool() = 0;
27 | //
28 | // virtual btPoolAllocator* getCollisionAlgorithmPool() = 0;
29 |
30 | abstract fun getCollisionAlgorithmCreateFunc(proxyType0: BroadphaseNativeTypes, proxyType1: BroadphaseNativeTypes): CollisionAlgorithmCreateFunc
31 | fun getCollisionAlgorithmCreateFunc(proxyType0: Int, proxyType1: Int) =
32 | getCollisionAlgorithmCreateFunc(BroadphaseNativeTypes.of(proxyType0), BroadphaseNativeTypes.of(proxyType1))
33 |
34 | abstract fun getClosestPointsAlgorithmCreateFunc(proxyType0: BroadphaseNativeTypes, proxyType1: BroadphaseNativeTypes): CollisionAlgorithmCreateFunc
35 | fun getClosestPointsAlgorithmCreateFunc(proxyType0: Int, proxyType1: Int) =
36 | getClosestPointsAlgorithmCreateFunc(BroadphaseNativeTypes.of(proxyType0), BroadphaseNativeTypes.of(proxyType1))
37 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/collisionDispatch/CollisionCreateFunc.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.collision.collisionDispatch
17 |
18 | import bullet.collision.broadphaseCollision.CollisionAlgorithm
19 | import bullet.collision.broadphaseCollision.CollisionAlgorithmConstructionInfo
20 |
21 | /** Used by the CollisionDispatcher to register and create instances for btCollisionAlgorithm */
22 | abstract class CollisionAlgorithmCreateFunc {
23 |
24 | var swapped = false
25 |
26 | abstract fun createCollisionAlgorithm(info: CollisionAlgorithmConstructionInfo, body0Wrap: CollisionObjectWrapper,
27 | body1Wrap: CollisionObjectWrapper) : CollisionAlgorithm
28 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/collisionDispatch/CollisionObjectWrapper.kt:
--------------------------------------------------------------------------------
1 | package bullet.collision.collisionDispatch
2 |
3 | import bullet.collision.collisionShapes.CollisionShape
4 | import bullet.linearMath.Transform
5 |
6 | class CollisionObjectWrapper {
7 |
8 | /** not implemented. Not allowed. */
9 | private constructor(collisionObjectWrapper: CollisionObjectWrapper?)
10 |
11 | // open infix fun put(collisionObjectWrapper: CollisionObjectWrapper) = CollisionObjectWrapper(null) TODO
12 |
13 | var parent: CollisionObjectWrapper? = null
14 | var shape: CollisionShape? = null
15 | var collisionObject: CollisionObject? = null
16 | var worldTransform = Transform()
17 | var partId = 0
18 | var index = 0
19 |
20 | // TODO check constructors
21 | constructor(parent: CollisionObjectWrapper?, shape: CollisionShape?, collisionObject: CollisionObject, worldTransform: Transform,
22 | partId: Int, index: Int) {
23 | this.parent = parent
24 | this.shape = shape
25 | this.collisionObject = collisionObject
26 | this.worldTransform = worldTransform
27 | this.partId = partId
28 | this.index = index
29 | }
30 |
31 | val collisionShape get() = shape!!
32 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/collisionDispatch/CompoundShape.kt:
--------------------------------------------------------------------------------
1 | package bullet.collision.collisionDispatch
2 |
3 |
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/collisionDispatch/EmptyAlgorithm.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.collision.collisionDispatch
17 |
18 | import bullet.collision.broadphaseCollision.CollisionAlgorithm
19 | import bullet.collision.broadphaseCollision.CollisionAlgorithmConstructionInfo
20 | import bullet.collision.broadphaseCollision.DispatcherInfo
21 |
22 | /** EmptyAlgorithm is a stub for unsupported collision pairs.
23 | * The dispatcher can dispatch a persistent EmptyAlgorithm to avoid a search every frame. */
24 | class EmptyAlgorithm(ci: CollisionAlgorithmConstructionInfo) : CollisionAlgorithm(ci) {
25 |
26 | override fun calculateTimeOfImpact(body0: CollisionObject, body1: CollisionObject, dispatchInfo: DispatcherInfo,
27 | resultOut: ManifoldResult) = 0f
28 |
29 | class CreateFunc : CollisionAlgorithmCreateFunc() {
30 | override fun createCollisionAlgorithm(info: CollisionAlgorithmConstructionInfo, body0Wrap: CollisionObjectWrapper,
31 | body1Wrap: CollisionObjectWrapper) = EmptyAlgorithm(info)
32 | }
33 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/collisionDispatch/SphereSphereCollisionAlgorithm.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.collision.collisionDispatch
17 |
18 | import bullet.CLEAR_MANIFOLD
19 | import bullet.EPSILON
20 | import bullet.collision.broadphaseCollision.CollisionAlgorithmConstructionInfo
21 | import bullet.collision.broadphaseCollision.DispatcherInfo
22 | import bullet.collision.collisionShapes.SphereShape
23 | import bullet.collision.narrowPhaseCollision.PersistentManifold
24 | import bullet.linearMath.Vec3
25 | import bullet.linearMath.times
26 |
27 | /** SphereSphereCollisionAlgorithm provides sphere-sphere collision detection.
28 | * Other features are frame-coherency (persistent data) and collision response.
29 | * Also provides the most basic sample for custom/user CollisionAlgorithm */
30 | class SphereSphereCollisionAlgorithm : ActivatingCollisionAlgorithm {
31 |
32 | var ownManifold = false
33 | var manifold: PersistentManifold? = null
34 |
35 | constructor(mf: PersistentManifold?, ci: CollisionAlgorithmConstructionInfo, col0Wrap: CollisionObjectWrapper,
36 | col1Wrap: CollisionObjectWrapper) : super(ci, col0Wrap, col1Wrap) {
37 | manifold = mf ?: dispatcher!!.getNewManifold(col0Wrap.collisionObject!!, col1Wrap.collisionObject!!).also { ownManifold = true }
38 | }
39 |
40 | constructor(ci: CollisionAlgorithmConstructionInfo) : super(ci)
41 |
42 | override fun processCollision(body0Wrap: CollisionObjectWrapper, body1Wrap: CollisionObjectWrapper, dispatchInfo: DispatcherInfo, resultOut: ManifoldResult) {
43 |
44 | if (manifold == null) return
45 |
46 | resultOut.manifold = manifold
47 |
48 | val sphere0 = body0Wrap.collisionShape as SphereShape
49 | val sphere1 = body1Wrap.collisionShape as SphereShape
50 |
51 | val diff = body0Wrap.worldTransform.origin - body1Wrap.worldTransform.origin
52 | val len = diff.length()
53 | val radius0 = sphere0.radius
54 | val radius1 = sphere1.radius
55 |
56 | if (CLEAR_MANIFOLD) manifold!!.clearManifold() //don't do this, it disables warmstarting
57 |
58 | // iff distance positive, don't generate a new contact
59 | if (len > (radius0 + radius1 + resultOut.closestPointDistanceThreshold)) {
60 | if (!CLEAR_MANIFOLD) resultOut.refreshContactPoints()
61 | return
62 | }
63 | // distance (negative means penetration)
64 | val dist = len - (radius0 + radius1)
65 |
66 | val normalOnSurfaceB = if (len > Float.EPSILON) diff / len else Vec3 (1, 0, 0)
67 |
68 | // point on A (worldspace)
69 | // btVector3 pos0 = col0->getWorldTransform().getOrigin() - radius0 * normalOnSurfaceB;
70 | // point on B (worldspace)
71 | val pos1 = body1Wrap.worldTransform.origin+radius1* normalOnSurfaceB
72 |
73 | // report a contact. internally this will be kept persistent, and contact reduction is done
74 |
75 | resultOut.addContactPoint(normalOnSurfaceB, pos1, dist)
76 |
77 | if(!CLEAR_MANIFOLD) resultOut.refreshContactPoints()
78 | }
79 |
80 | override fun calculateTimeOfImpact(body0: CollisionObject, body1: CollisionObject, dispatchInfo: DispatcherInfo,
81 | resultOut: ManifoldResult) = 1f //not yet
82 |
83 | override fun getAllContactManifolds(manifoldArray: ArrayList) {
84 | manifold?.let { if (ownManifold) manifoldArray.add(manifold!!) }
85 | }
86 |
87 | class CreateFunc : CollisionAlgorithmCreateFunc() {
88 | override fun createCollisionAlgorithm(info: CollisionAlgorithmConstructionInfo, body0Wrap: CollisionObjectWrapper,
89 | body1Wrap: CollisionObjectWrapper) =
90 | SphereSphereCollisionAlgorithm (null, info, body0Wrap, body1Wrap)
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/collisionDispatch/SphereTriangleCollisionAlgorithm.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.collision.collisionDispatch
17 |
18 | import bullet.collision.broadphaseCollision.CollisionAlgorithmConstructionInfo
19 | import bullet.collision.broadphaseCollision.DispatcherInfo
20 | import bullet.collision.collisionShapes.SphereShape
21 | import bullet.collision.collisionShapes.TriangleShape
22 | import bullet.collision.narrowPhaseCollision.DiscreteCollisionDetectorInterface
23 | import bullet.collision.narrowPhaseCollision.PersistentManifold
24 | import bullet.linearMath.LARGE_FLOAT
25 |
26 | /** SphereSphereCollisionAlgorithm provides sphere-sphere collision detection.
27 | * Other features are frame-coherency (persistent data) and collision response.
28 | * Also provides the most basic sample for custom/user CollisionAlgorithm */
29 | class SphereTriangleCollisionAlgorithm : ActivatingCollisionAlgorithm {
30 |
31 | var ownManifold = false
32 | var manifold: PersistentManifold? = null
33 | var swapped = false
34 |
35 | constructor(mf: PersistentManifold?, ci: CollisionAlgorithmConstructionInfo, body0Wrap: CollisionObjectWrapper,
36 | body1Wrap: CollisionObjectWrapper, swapped: Boolean) : super(ci, body0Wrap, body1Wrap) {
37 | manifold = mf ?: dispatcher!!.getNewManifold(body0Wrap.collisionObject!!, body1Wrap.collisionObject!!).also { ownManifold = true }
38 | this.swapped = swapped
39 | }
40 |
41 | constructor(ci: CollisionAlgorithmConstructionInfo) : super(ci)
42 |
43 | override fun processCollision(body0Wrap: CollisionObjectWrapper, body1Wrap: CollisionObjectWrapper, dispatchInfo: DispatcherInfo, resultOut: ManifoldResult) {
44 |
45 | if (manifold == null) return
46 |
47 | val sphereObjWrap = if (swapped) body1Wrap else body0Wrap
48 | val triObjWrap = if (swapped) body0Wrap else body1Wrap
49 |
50 | val sphere = sphereObjWrap.collisionShape as SphereShape
51 | val triangle = triObjWrap.collisionShape as TriangleShape
52 |
53 | /// report a contact. internally this will be kept persistent, and contact reduction is done
54 | resultOut.manifold = manifold
55 | val detector = SphereTriangleDetector(sphere, triangle, manifold!!.contactBreakingThreshold +
56 | resultOut.closestPointDistanceThreshold)
57 |
58 | val input = DiscreteCollisionDetectorInterface.ClosestPointInput().apply {
59 | maximumDistanceSquared = LARGE_FLOAT ///@todo: tighter bounds
60 | transformA put sphereObjWrap.worldTransform
61 | transformB put triObjWrap.worldTransform
62 | }
63 |
64 | detector.getClosestPoints(input, resultOut, dispatchInfo.debugDraw, swapResults = swapped)
65 | if (ownManifold) resultOut.refreshContactPoints()
66 | }
67 |
68 | override fun calculateTimeOfImpact(body0: CollisionObject, body1: CollisionObject, dispatchInfo: DispatcherInfo,
69 | resultOut: ManifoldResult) = 1f //not yet
70 |
71 | override fun getAllContactManifolds(manifoldArray: ArrayList) {
72 | manifold?.let { if (ownManifold) manifoldArray.add(it) }
73 | }
74 |
75 | class CreateFunc : CollisionAlgorithmCreateFunc() {
76 |
77 | override fun createCollisionAlgorithm(info: CollisionAlgorithmConstructionInfo, body0Wrap: CollisionObjectWrapper,
78 | body1Wrap: CollisionObjectWrapper) =
79 | SphereTriangleCollisionAlgorithm(info.manifold, info, body0Wrap, body1Wrap, swapped)
80 | }
81 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/collisionDispatch/UnionFind.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.collision.collisionDispatch
17 |
18 | import bullet.USE_PATH_COMPRESSION
19 | import bullet.pop
20 |
21 | /** see for discussion of static island optimizations by Vroonsh here: http://code.google.com/p/bullet/issues/detail?id=406 */
22 | val STATIC_SIMULATION_ISLAND_OPTIMIZATION = true
23 |
24 | class Element {
25 | var id = 0
26 | var sz = 0
27 | }
28 |
29 | /** UnionFind calculates connected subsets
30 | * Implements weighted Quick Union with path compression
31 | * optimization: could use short ints instead of ints (halving memory, would limit the number of rigid bodies to 64k,
32 | * sounds reasonable) */
33 | class UnionFind {
34 |
35 | val elements = ArrayList()
36 |
37 | /** this is a special operation, destroying the content of UnionFind.
38 | * it sorts the elements, based on island id, in order to make it easy to iterate over islands */
39 | fun sortIslands() = elements.sortBy { it.id }
40 |
41 | fun reset(n: Int) {
42 | allocate(n)
43 | for (i in 0 until n) {
44 | elements[i].id = i
45 | elements[i].sz = 1
46 | }
47 | }
48 |
49 | val numElements get() = elements.size
50 | fun isRoot(x: Int) = x == elements[x].id
51 |
52 | operator fun get(index: Int) = elements[index]
53 |
54 | fun allocate(n: Int) {
55 | if (elements.size < n)
56 | for (i in elements.size until n)
57 | elements.add(Element())
58 | else if (elements.size > n)
59 | for (i in n until elements.size)
60 | elements.pop()
61 | }
62 |
63 | fun free() = elements.clear()
64 |
65 | fun find(p: Int, q: Int) = find(p) == find(q)
66 |
67 | fun unite(p: Int, q: Int) {
68 | val i = find(p)
69 | val j = find(q)
70 | if (i == j) return
71 |
72 | if (!USE_PATH_COMPRESSION)
73 | // weighted quick union, this keeps the 'trees' balanced, and keeps performance of unite O( log(n) )
74 | if (elements[i].sz < elements[j].sz) {
75 | elements[i].id = j
76 | elements[j].sz += elements[i].sz
77 | } else {
78 | elements[j].id = i
79 | elements[i].sz += elements[j].sz
80 | }
81 | else {
82 | elements[i].id = j
83 | elements[j].sz += elements[i].sz
84 | }
85 | }
86 |
87 | fun find(x: Int): Int {
88 | //btAssert(x < m_N);
89 | //btAssert(x >= 0);
90 | var x = x
91 | while (x != elements[x].id) {
92 | //not really a reason not to use path compression, and it flattens the trees/improves find performance dramatically
93 | if (USE_PATH_COMPRESSION) {
94 | val elementPtr = elements[elements[x].id]
95 | elements[x].id = elementPtr.id
96 | x = elementPtr.id
97 | } else
98 | x = elements[x].id
99 | //btAssert(x < m_N);
100 | //btAssert(x >= 0);
101 | }
102 | return x
103 | }
104 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/collisionShapes/CollisionMargin.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.collision.collisionShapes
17 |
18 | /** The CONVEX_DISTANCE_MARGIN is a default collision margin for convex collision shapes derived from ConvexInternalShape.
19 | * This collision margin is used by Gjk and some other algorithms
20 | * Note that when creating small objects, you need to make sure to set a smaller collision margin, using the 'setMargin' API */
21 | val CONVEX_DISTANCE_MARGIN = 0.04f
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/collisionShapes/CollisionShape.kt:
--------------------------------------------------------------------------------
1 | package bullet.collision.collisionShapes
2 |
3 | import bullet.collision.broadphaseCollision.BroadphaseNativeTypes
4 | import bullet.collision.broadphaseCollision.BroadphaseProxy
5 | import bullet.linearMath.Transform
6 | import bullet.linearMath.Vec3
7 |
8 | /** The CollisionShape class provides an interface for collision shapes that can be shared among CollisionObjects. */
9 | abstract class CollisionShape {
10 |
11 | var shapeType = BroadphaseNativeTypes.INVALID_SHAPE_PROXYTYPE
12 | // void* m_userPointer = null;
13 | var userIndex = -1
14 |
15 | /** getAabb returns the axis aligned bounding box in the coordinate frame of the given transform trans. */
16 | abstract fun getAabb(trans: Transform, aabbMin: Vec3, aabbMax: Vec3)
17 |
18 | /** JVM specific, radius in returns */
19 | open fun getBoundingSphere(center: Vec3): Float {
20 | val tr = Transform()
21 | tr.setIdentity()
22 | val aabbMin = Vec3()
23 | val aabbMax = Vec3()
24 |
25 | getAabb(tr, aabbMin, aabbMax)
26 |
27 | val radius = (aabbMax - aabbMin).length() * 0.5f
28 | center put ((aabbMin + aabbMax) * 0.5f)
29 | return radius
30 | }
31 |
32 | /** getAngularMotionDisc returns the maximum radius needed for Conservative Advancement to handle time-of-impact
33 | * with rotations. */
34 | val angularMotionDisc
35 | get(): Float {
36 | ///@todo cache this value, to improve performance
37 | val center = Vec3()
38 | val disc = getBoundingSphere(center)
39 | return disc + center.length()
40 | }
41 |
42 | open fun getContactBreakingThreshold(defaultContactThresholdFactor: Float) = angularMotionDisc * defaultContactThresholdFactor
43 |
44 | /** calculateTemporalAabb calculates the enclosing aabb for the moving object over interval [0..timeStep)
45 | * result is conservative */
46 | fun calculateTemporalAabb(curTrans: Transform, linvel: Vec3, angvel: Vec3, timeStep: Float, temporalAabbMin: Vec3,
47 | temporalAabbMax: Vec3) {
48 | //start with static aabb
49 | getAabb(curTrans, temporalAabbMin, temporalAabbMax)
50 |
51 | var temporalAabbMaxx = temporalAabbMax.x
52 | var temporalAabbMaxy = temporalAabbMax.y
53 | var temporalAabbMaxz = temporalAabbMax.z
54 | var temporalAabbMinx = temporalAabbMin.x
55 | var temporalAabbMiny = temporalAabbMin.y
56 | var temporalAabbMinz = temporalAabbMin.z
57 |
58 | // add linear motion
59 | val linMotion = linvel * timeStep
60 | ///@todo: simd would have a vector max/min operation, instead of per-element access
61 | if (linMotion.x > 0f)
62 | temporalAabbMaxx += linMotion.x
63 | else
64 | temporalAabbMinx += linMotion.x
65 | if (linMotion.y > 0f)
66 | temporalAabbMaxy += linMotion.y
67 | else
68 | temporalAabbMiny += linMotion.y
69 | if (linMotion.z > 0f)
70 | temporalAabbMaxz += linMotion.z
71 | else
72 | temporalAabbMinz += linMotion.z
73 |
74 | //add conservative angular motion
75 | val angularMotion = angvel.length() * angularMotionDisc * timeStep
76 | val angularMotion3d = Vec3(angularMotion)
77 | temporalAabbMin.put(temporalAabbMinx, temporalAabbMiny, temporalAabbMinz)
78 | temporalAabbMax.put(temporalAabbMaxx, temporalAabbMaxy, temporalAabbMaxz)
79 |
80 | temporalAabbMin -= angularMotion3d
81 | temporalAabbMax += angularMotion3d
82 | }
83 |
84 | val isPolyhedral get() = BroadphaseProxy.isPolyhedral(shapeType.i) // TODO check if leave enum or int
85 | val isConvex2d get() = BroadphaseProxy.isConvex2d(shapeType.i)
86 | val isConvex get() = BroadphaseProxy.isConvex(shapeType.i)
87 | val isNonMoving get() = BroadphaseProxy.isNonMoving(shapeType.i)
88 | val isConcave get() = BroadphaseProxy.isConcave(shapeType.i)
89 | val isCompound get() = BroadphaseProxy.isCompound(shapeType.i)
90 | val isSoftBody get() = BroadphaseProxy.isSoftBody(shapeType.i)
91 |
92 | open var localScaling = Vec3()
93 | open fun calculateLocalInertia(mass: Float, inertia: Vec3) {}
94 |
95 | /** debugging support */
96 | open val name get() = ""
97 |
98 | /** the getAnisotropicRollingFrictionDirection can be used in combination with setAnisotropicFriction
99 | * See Bullet/Demos/RollingFrictionDemo for an example */
100 | open val anisotropicRollingFrictionDirection get() = Vec3(1f)
101 |
102 | open var margin = 0f
103 |
104 | open fun calculateSerializeBufferSize() = 0
105 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/collisionShapes/ConcaveShape.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.collision.collisionShapes
17 |
18 | import bullet.linearMath.Vec3
19 |
20 | /** PHY_ScalarType enumerates possible scalar types.
21 | * See the StridingMeshInterface or btHeightfieldTerrainShape for its use */
22 | enum class PHY_ScalarType { NULL, FLOAT, DOUBLE, INTEGER, SHORT, FIXEDPOINT88, UCHAR;
23 |
24 | val i = ordinal - 1
25 | }
26 |
27 | /** The ConcaveShape class provides an interface for non-moving (static) concave shapes.
28 | * It has been implemented by the StaticPlaneShape, BvhTriangleMeshShape and HeightfieldTerrainShape. */
29 | abstract class ConcaveShape : CollisionShape() {
30 |
31 | var collisionMargin = 0f
32 |
33 | abstract fun processAllTriangles(callback: TriangleCallback, aabbMin: Vec3, aabbMax: Vec3): Unit
34 |
35 | override var margin
36 | set(value) {
37 | collisionMargin = value
38 | }
39 | get() = collisionMargin
40 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/collisionShapes/ConvexInternalAabbCachingShape.kt:
--------------------------------------------------------------------------------
1 | package bullet.collision.collisionShapes
2 |
3 | import bullet.linearMath.Transform
4 | import bullet.linearMath.Vec3
5 | import bullet.linearMath.transformAabb
6 |
7 | /** ConvexInternalAabbCachingShape adds local aabb caching for convex shapes, to avoid expensive bounding box calculations */
8 | abstract class ConvexInternalAabbCachingShape : ConvexInternalShape() {
9 |
10 | var localAabbMin = Vec3(1)
11 | var localAabbMax = Vec3(-1)
12 | var isLocalAabbValid = false
13 |
14 | fun setCachedLocalAabb(aabbMin: Vec3, aabbMax: Vec3) {
15 | isLocalAabbValid = true
16 | localAabbMin put aabbMin
17 | localAabbMax put aabbMax
18 | }
19 |
20 | fun getCachedLocalAabb(aabbMin: Vec3, aabbMax: Vec3) {
21 | assert(isLocalAabbValid)
22 | aabbMin put localAabbMin
23 | aabbMax put localAabbMax
24 | }
25 |
26 | fun getNonvirtualAabb(trans: Transform, aabbMin: Vec3, aabbMax: Vec3, margin: Float) {
27 |
28 | //lazy evaluation of local aabb
29 | assert(isLocalAabbValid)
30 | transformAabb(localAabbMin, localAabbMax, margin, trans, aabbMin, aabbMax)
31 | }
32 |
33 | override var localScaling
34 | get() = super.localScaling
35 | set(value) {
36 | super.localScaling = value
37 | recalcLocalAabb()
38 | }
39 |
40 | override fun getAabb(trans: Transform, aabbMin: Vec3, aabbMax: Vec3) = getNonvirtualAabb(trans, aabbMin, aabbMax, margin)
41 |
42 | fun recalcLocalAabb() {
43 |
44 | isLocalAabbValid = true
45 |
46 | val _supporting = arrayOf(Vec3(), Vec3(), Vec3(), Vec3(), Vec3(), Vec3())
47 |
48 | batchedUnitVectorGetSupportingVertexWithoutMargin(_directions, _supporting, 6)
49 |
50 | for (i in 0 .. 2) {
51 | localAabbMax[i] = _supporting[i][i] + collisionMargin
52 | localAabbMin[i] = _supporting[i + 3][i] - collisionMargin
53 | }
54 | }
55 |
56 | companion object {
57 |
58 | private val _directions = arrayOf(
59 | Vec3(1f, 0f, 0f),
60 | Vec3(0f, 1f, 0f),
61 | Vec3(0f, 0f, 1f),
62 | Vec3(-1f, 0f, 0f),
63 | Vec3(0f, -1f, 0f),
64 | Vec3(0f, 0f, -1f))
65 | }
66 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/collisionShapes/ConvexInternalShape.kt:
--------------------------------------------------------------------------------
1 | package bullet.collision.collisionShapes
2 |
3 | import bullet.EPSILON
4 | import bullet.linearMath.Transform
5 | import bullet.linearMath.Vec3
6 | import bullet.linearMath.times
7 |
8 | abstract class ConvexInternalShape : ConvexShape() {
9 |
10 | /** local scaling. collisionMargin is not scaled ! */
11 | override var localScaling = Vec3(1)
12 | set(value) {
13 | localScaling put value.absolute()
14 | }
15 |
16 | /** Warning: use setImplicitShapeDimensions with care
17 | * changing a collision shape while the body is in the world is not recommended, it is best to remove the body
18 | * from the world, then make the change, and re-add it
19 | * alternatively flush the contact points, see documentation for 'cleanProxyFromPairs' */
20 | val implicitShapeDimensions = Vec3()
21 |
22 | var collisionMargin = CONVEX_DISTANCE_MARGIN
23 |
24 | var padding = 0f
25 |
26 | override fun localGetSupportingVertex(vec: Vec3): Vec3 {
27 |
28 | val supVertex = localGetSupportingVertexWithoutMargin(vec)
29 |
30 | if (margin != 0f) {
31 | val vecnorm = Vec3(vec)
32 | if (vecnorm.length2() < Float.EPSILON * Float.EPSILON)
33 | vecnorm put -1f
34 | vecnorm.normalize()
35 | supVertex += margin * vecnorm
36 | }
37 | return supVertex
38 | }
39 |
40 | fun setSafeMargin(minDimension: Float, defaultMarginMultiplier: Float = 0.1f) {
41 | val safeMargin = defaultMarginMultiplier * minDimension
42 | if (safeMargin < margin) margin = safeMargin
43 | }
44 |
45 | fun setSafeMargin(halfExtents: Vec3, defaultMarginMultiplier: Float = 0.1f) {
46 | /* see http://code.google.com/p/bullet/issues/detail?id=349
47 | this margin check could could be added to other collision shapes too, or add some assert/warning somewhere */
48 | val minDimension = halfExtents[halfExtents.minAxis()]
49 | setSafeMargin(minDimension, defaultMarginMultiplier)
50 | }
51 |
52 | /** getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version */
53 | override fun getAabb(trans: Transform, aabbMin: Vec3, aabbMax: Vec3) = getAabbSlow(trans, aabbMin, aabbMax)
54 |
55 | override fun getAabbSlow(trans: Transform, aabbMin: Vec3, aabbMax: Vec3) {
56 | //use localGetSupportingVertexWithoutMargin?
57 | for (i in 0..2) {
58 | val vec = Vec3()
59 | vec[i] = 1f
60 |
61 | val sv = localGetSupportingVertex(vec * trans.basis)
62 |
63 | var tmp = trans * sv
64 | aabbMax[i] = tmp[i] + margin
65 | vec[i] = -1f
66 | tmp = trans * localGetSupportingVertex(vec * trans.basis)
67 | aabbMin[i] = tmp[i] - margin
68 | }
69 | }
70 |
71 | val localScalingNV get() = localScaling
72 |
73 | override var margin
74 | get() = collisionMargin
75 | set(value) {
76 | collisionMargin = value
77 | }
78 |
79 | val marginNV get() = collisionMargin
80 |
81 | override val numPreferredPenetrationDirections = 0
82 |
83 | override fun getPreferredPenetrationDirection(index: Int, penetrationVector: Vec3) {
84 | throw Error()
85 | }
86 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/collisionShapes/ConvexPointCloudShape.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.collision.collisionShapes
17 |
18 | import bullet.EPSILON
19 | import bullet.linearMath.LARGE_FLOAT
20 | import bullet.linearMath.Vec3
21 | import bullet.linearMath.times
22 | import kotlin.math.sqrt
23 | import bullet.collision.broadphaseCollision.BroadphaseNativeTypes as BNT
24 |
25 | /** The ConvexPointCloudShape implements an implicit convex hull of an array of vertices. */
26 | class ConvexPointCloudShape : PolyhedralConvexAabbCachingShape {
27 |
28 | var unscaledPoints = arrayOf()
29 | var numPoints = 0
30 |
31 | constructor() {
32 | localScaling put 1f
33 | shapeType = BNT.CONVEX_POINT_CLOUD_SHAPE_PROXYTYPE
34 | }
35 |
36 | constructor(points: Array, numPoints: Int, localScaling: Vec3, computeAabb: Boolean = true) {
37 | this.localScaling put localScaling
38 | shapeType = BNT.CONVEX_POINT_CLOUD_SHAPE_PROXYTYPE
39 | unscaledPoints = points
40 | this.numPoints = numPoints
41 |
42 | if (computeAabb) recalcLocalAabb()
43 | }
44 |
45 | fun setPoints(points: Array, numPoints: Int, computeAabb: Boolean = true, localScaling: Vec3 = Vec3(1f)) {
46 | unscaledPoints = points
47 | this.numPoints = numPoints
48 | this.localScaling = localScaling
49 |
50 | if (computeAabb) recalcLocalAabb()
51 | }
52 |
53 | fun getScaledPoint(index: Int) = unscaledPoints[index] * localScaling
54 |
55 | override fun localGetSupportingVertex(vec: Vec3): Vec3 {
56 | val supVertex = localGetSupportingVertexWithoutMargin(vec)
57 |
58 | if (margin != 0f) {
59 | val vecNorm = Vec3(vec)
60 | if (vecNorm.length2() < Float.EPSILON * Float.EPSILON)
61 | vecNorm put -1f
62 | vecNorm.normalize()
63 | supVertex += margin * vecNorm
64 | }
65 | return supVertex
66 | }
67 |
68 | override fun localGetSupportingVertexWithoutMargin(vec: Vec3): Vec3 {
69 | val supVec = Vec3()
70 | var maxDot = -LARGE_FLOAT
71 |
72 | val vec = Vec3(vec)
73 | val lenSqr = vec.length2()
74 | if (lenSqr < 0.0001f)
75 | vec.put(1f, 0f, 0f)
76 | else
77 | vec *= 1f / sqrt(lenSqr) // rlen
78 |
79 | if (numPoints > 0) {
80 | /* Here we take advantage of dot(a*b, c) = dot( a, b*c) to do less work. Note this transformation is true
81 | mathematically, not numerically. */
82 | // btVector3 scaled = vec * m_localScaling;
83 | val p = FloatArray(1)
84 | val index = vec.maxDot(unscaledPoints, numPoints, p) //FIXME: may violate encapsulation of m_unscaledPoints
85 | maxDot = p[0]
86 | return getScaledPoint(index)
87 | }
88 | return supVec
89 | }
90 |
91 | override fun batchedUnitVectorGetSupportingVertexWithoutMargin(vectors: Array, supportVerticesOut: Array, numVectors: Int) {
92 | for (j in 0 until numVectors) {
93 | val vec = vectors[j] * localScaling // dot( a*c, b) = dot(a, b*c)
94 | val p = FloatArray(1)
95 | val index = vec.maxDot(unscaledPoints, numPoints, p)
96 | val maxDot = p[0]
97 | supportVerticesOut[j][3] = -LARGE_FLOAT
98 | if (0 <= index) {
99 | // WARNING: don't swap next lines, the w component would get overwritten!
100 | supportVerticesOut[j] = getScaledPoint(index)
101 | supportVerticesOut[j][3] = maxDot
102 | }
103 | }
104 | }
105 |
106 | /** debugging */
107 | override val name get() = "ConvexPointCloud"
108 |
109 | /** currently just for debugging (drawing), perhaps future support for algebraic continuous collision detection
110 | * Please note that you can debug-draw btConvexHullShape with the Raytracer Demo */
111 | override val numVertices get() = numPoints
112 |
113 | override val numEdges get() = 0
114 | override fun getEdge(i: Int, pa: Vec3, pb: Vec3) = throw Error()
115 | override fun getVertex(i: Int, vtx: Vec3) = vtx.put(unscaledPoints[i] * localScaling)
116 | override val numPlanes get() = 0
117 | override fun getPlane(planeNormal: Vec3, planeSupport: Vec3, i: Int) = throw Error()
118 | override fun isInside(pt:Vec3,tolerance:Float) = throw Error()
119 |
120 | override var localScaling
121 | get() = super.localScaling
122 | set(value) {
123 | localScaling put value
124 | recalcLocalAabb()
125 | }
126 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/collisionShapes/MultiSphereShape.kt:
--------------------------------------------------------------------------------
1 | package bullet.collision.collisionShapes
2 |
3 | import bullet.EPSILON
4 | import bullet.linearMath.LARGE_FLOAT
5 | import bullet.linearMath.Vec3
6 | import kotlin.math.min
7 | import kotlin.math.sqrt
8 | import bullet.collision.broadphaseCollision.BroadphaseNativeTypes as BNT
9 |
10 | /** The btMultiSphereShape represents the convex hull of a collection of spheres. You can create special capsules or
11 | * other smooth volumes.
12 | * It is possible to animate the spheres for deformation, but call 'recalcLocalAabb' after changing
13 | * any sphere position/radius */
14 | class MultiSphereShape : ConvexInternalAabbCachingShape {
15 |
16 | var localPositionArray: Array
17 | var radiArray: FloatArray
18 |
19 | constructor(positions: Array, radi: FloatArray, numSpheres: Int) {
20 | localPositionArray = positions
21 | radiArray = radi
22 | shapeType = BNT.MULTI_SPHERE_SHAPE_PROXYTYPE
23 | //btScalar startMargin = btScalar(BT_LARGE_FLOAT);
24 | recalcLocalAabb()
25 | }
26 |
27 | constructor(position: Vec3, radi: Float, numSpheres: Int) : this(arrayOf(position), floatArrayOf(radi), numSpheres)
28 |
29 | /** CollisionShape Interface */
30 | override fun calculateLocalInertia(mass: Float, inertia: Vec3) {
31 | //as an approximation, take the inertia of the box that bounds the spheres
32 | val localAabbMin = Vec3()
33 | val localAabbMax = Vec3()
34 | getCachedLocalAabb(localAabbMin, localAabbMax)
35 | val halfExtents = (localAabbMax - localAabbMin) * 0.5f
36 |
37 | val lx = 2f * halfExtents.x
38 | val ly = 2f * halfExtents.y
39 | val lz = 2f * halfExtents.z
40 |
41 | inertia.put(mass / 12f * (ly * ly + lz * lz),
42 | mass / 12f * (lx * lx + lz * lz),
43 | mass / 12f * (lx * lx + ly * ly))
44 | }
45 |
46 | /** btConvexShape Interface */
47 | override fun localGetSupportingVertexWithoutMargin(vec: Vec3): Vec3 {
48 |
49 | val supVec = Vec3()
50 |
51 | var maxDot = -LARGE_FLOAT
52 |
53 | val vec = Vec3(vec)
54 | val lenSqr = vec.length2()
55 | if (lenSqr < Float.EPSILON * Float.EPSILON)
56 | vec.put(1f, 0f, 0f)
57 | else
58 | vec *= 1f / sqrt(lenSqr) // rlen
59 |
60 | var newDot: Float
61 |
62 | var pos = 0
63 | var rad = 0
64 | val numSpheres = localPositionArray.size
65 | val p = FloatArray(1)
66 |
67 | for (k in 0 until numSpheres step 128) {
68 | val temp = Array(128, { Vec3() })
69 | val innerCount = min(numSpheres - k, 128)
70 | for (i in 0 until innerCount) {
71 | temp[i] = localPositionArray[pos] * localScaling + vec * localScaling * radiArray[rad] - vec * margin
72 | pos++
73 | rad++
74 | }
75 | val i = vec.maxDot(temp, innerCount, p)
76 | newDot = p[0]
77 | if (newDot > maxDot) {
78 | maxDot = newDot
79 | supVec put temp[i]
80 | }
81 | }
82 | return supVec
83 | }
84 |
85 | override fun batchedUnitVectorGetSupportingVertexWithoutMargin(vectors: Array,
86 | supportVerticesOut: Array, numVectors: Int) {
87 | for (j in 0 until numVectors) {
88 |
89 | var maxDot = -LARGE_FLOAT
90 |
91 | val vec = vectors[j]
92 |
93 | var newDot: Float
94 |
95 | var pos = 0
96 | var rad = 0
97 | val numSpheres = localPositionArray.size
98 | val p = FloatArray(1)
99 |
100 | for (k in 0 until numSpheres step 128) {
101 | val temp = Array(128, { Vec3() })
102 | val innerCount = min(numSpheres - k, 128)
103 | for (i in 0 until innerCount) {
104 | temp[i] = localPositionArray[pos] * localScaling + vec * localScaling * radiArray[rad] - vec * margin
105 | pos++
106 | rad++
107 | }
108 | val i = vec.maxDot(temp, innerCount, p)
109 | newDot = p[0]
110 | if (newDot > maxDot) {
111 | maxDot = newDot
112 | supportVerticesOut[j] = temp[i]
113 | }
114 | }
115 | }
116 | }
117 |
118 | val sphereCount get() = localPositionArray.size
119 |
120 | fun getSpherePosition(index: Int) = localPositionArray[index]
121 |
122 | fun getSphereRadius(index: Int) = radiArray[index]
123 |
124 | override val name get() = "MultiSphere"
125 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/collisionShapes/ScaledBvhTriangleMeshShape.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org
4 | This software is provided 'as-is', without any express or implied warranty.
5 | In no event will the authors be held liable for any damages arising from the use of this software.
6 | Permission is granted to anyone to use this software for any purpose,
7 | including commercial applications, and to alter it and redistribute it freely,
8 | subject to the following restrictions:
9 | 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.
10 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
11 | 3. This notice may not be removed or altered from any source distribution.
12 | */
13 |
14 | package bullet.collision.collisionShapes
15 |
16 | import bullet.collision.broadphaseCollision.BroadphaseNativeTypes
17 | import bullet.linearMath.Transform
18 | import bullet.linearMath.Vec3
19 | import bullet.linearMath.div
20 | import bullet.linearMath.times
21 |
22 |
23 | /** The ScaledBvhTriangleMeshShape allows to instance a scaled version of an existing BvhTriangleMeshShape.
24 | * Note that each BvhTriangleMeshShape still can have its own local scaling, independent from this
25 | * ScaledBvhTriangleMeshShape 'localScaling' */
26 | class ScaledBvhTriangleMeshShape(val bvhTriMeshShape: BvhTriangleMeshShape, val localScaling_: Vec3) : ConcaveShape() {
27 |
28 | init {
29 | shapeType = BroadphaseNativeTypes.SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE
30 | }
31 |
32 | val childShape get() = bvhTriMeshShape
33 |
34 | override fun getAabb(trans: Transform, aabbMin: Vec3, aabbMax: Vec3) {
35 |
36 | val localAabbMin = Vec3(bvhTriMeshShape.localAabbMin)
37 | val localAabbMax = Vec3(bvhTriMeshShape.localAabbMax)
38 |
39 | val tmpLocalAabbMin = localAabbMin * localScaling
40 | val tmpLocalAabbMax = localAabbMax * localScaling
41 |
42 | for (i in 0..2) {
43 | localAabbMin[i] = if (localScaling[i] >= 0) tmpLocalAabbMin[i] else tmpLocalAabbMax[i]
44 | localAabbMax[i] = if (localScaling[i] <= 0) tmpLocalAabbMin[i] else tmpLocalAabbMax[i]
45 | }
46 |
47 | val localHalfExtents = 0.5f * (localAabbMax - localAabbMin)
48 | val margin = bvhTriMeshShape.margin
49 | localHalfExtents += margin
50 | val localCenter = 0.5f * (localAabbMax + localAabbMin)
51 |
52 | val absB = trans.basis.absolute()
53 |
54 | val center = trans(localCenter)
55 |
56 | val extent = localHalfExtents dot3 absB
57 | aabbMin put center - extent
58 | aabbMax put center + extent
59 | }
60 |
61 | override fun calculateLocalInertia(mass: Float, inertia: Vec3) {
62 | // don't make this a movable object!
63 | // assert(false)
64 | }
65 |
66 | class ScaledTriangleCallback(val originalCallback: TriangleCallback, val localScaling: Vec3) : TriangleCallback {
67 | override fun processTriangle(triangle: Array, partId: Int, triangleIndex: Int) {
68 | val newTriangle = Array(3) { triangle[it] * localScaling }
69 | originalCallback.processTriangle(newTriangle, partId, triangleIndex)
70 | }
71 | }
72 |
73 | override fun processAllTriangles(callback: TriangleCallback, aabbMin: Vec3, aabbMax: Vec3) {
74 |
75 | val scaledCallback = ScaledTriangleCallback(callback, localScaling)
76 |
77 | val invLocalScaling = 1f / localScaling
78 | val scaledAabbMin = Vec3()
79 | val scaledAabbMax = Vec3()
80 |
81 | // support negative scaling
82 | for (i in 0..2) {
83 | scaledAabbMin[i] = invLocalScaling[i] * if (localScaling[i] >= 0) aabbMin[i] else aabbMax[i]
84 | scaledAabbMax[i] = invLocalScaling[i] * if (localScaling[i] <= 0) aabbMin[i] else aabbMax[i]
85 | }
86 |
87 | bvhTriMeshShape.processAllTriangles(scaledCallback, scaledAabbMin, scaledAabbMax)
88 | }
89 |
90 | override val name get() = "SCALEDBVHTRIANGLEMESH"
91 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/collisionShapes/SphereShape.kt:
--------------------------------------------------------------------------------
1 | package bullet.collision.collisionShapes
2 |
3 | import bullet.EPSILON
4 | import bullet.linearMath.Transform
5 | import bullet.linearMath.Vec3
6 | import bullet.linearMath.times
7 | import bullet.collision.broadphaseCollision.BroadphaseNativeTypes as BNT
8 |
9 | class SphereShape(radius: Float) : ConvexInternalShape() {
10 |
11 | init {
12 | shapeType = BNT.SPHERE_SHAPE_PROXYTYPE
13 | localScaling put 1f
14 | implicitShapeDimensions.put(0f)
15 | implicitShapeDimensions.x = radius
16 | collisionMargin = radius
17 | padding = 0f
18 | }
19 |
20 | override fun localGetSupportingVertex(vec: Vec3): Vec3 {
21 | val supVertex = localGetSupportingVertexWithoutMargin(vec)
22 |
23 | val vecnorm = Vec3(vec)
24 | if (vecnorm.length2() < Float.EPSILON * Float.EPSILON)
25 | vecnorm put -1f
26 | vecnorm.normalize()
27 | supVertex += margin * vecnorm
28 | return supVertex
29 | }
30 |
31 | override fun localGetSupportingVertexWithoutMargin(vec: Vec3) = Vec3()
32 | /** notice that the vectors should be unit length */
33 | override fun batchedUnitVectorGetSupportingVertexWithoutMargin(vectors: Array, supportVerticesOut: Array, numVectors: Int) {
34 | for (i in 0 until numVectors) supportVerticesOut[i] put 0f
35 | }
36 |
37 |
38 | override fun calculateLocalInertia(mass: Float, inertia: Vec3) {
39 | inertia.put(0.4f * mass * margin * margin)
40 | }
41 |
42 | /** broken due to scaling */
43 | override fun getAabb(trans: Transform, aabbMin: Vec3, aabbMax: Vec3) {
44 | val center = trans.origin
45 | val extent = Vec3(margin)
46 | aabbMin put (center - extent)
47 | aabbMax put (center + extent)
48 | }
49 |
50 | var radius
51 | get() = implicitShapeDimensions.x * localScaling.x
52 | set(value) {
53 | implicitShapeDimensions.x = value
54 | super.margin = value
55 | }
56 |
57 | /** debugging */
58 | override val name get() = "SPHERE"
59 |
60 | override var margin
61 | set(value) {
62 | super.margin = margin
63 | }
64 | /* to improve gjk behaviour, use radius + margin as the full margin, so never get into the penetration case
65 | this means, non-uniform scaling is not supported anymore */
66 | get() = radius
67 |
68 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/collisionShapes/StaticPlaneShape.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.collision.collisionShapes
17 |
18 | import bullet.linearMath.LARGE_FLOAT
19 | import bullet.linearMath.Transform
20 | import bullet.linearMath.Vec3
21 | import bullet.linearMath.times
22 | import bullet.linearMath.planeSpace1
23 |
24 | /** The StaticPlaneShape simulates an infinite non-moving (static) collision plane. */
25 | class StaticPlaneShape(planeNormal: Vec3, val planeConstant: Float) : ConcaveShape() {
26 |
27 | val localAabbMin = Vec3()
28 | val localAabbMax = Vec3()
29 |
30 | val planeNormal = planeNormal.normalized()
31 | override var localScaling = Vec3(1f)
32 |
33 | override fun getAabb(trans: Transform, aabbMin: Vec3, aabbMax: Vec3) {
34 | aabbMin put -LARGE_FLOAT
35 | aabbMax put LARGE_FLOAT
36 | }
37 |
38 | override fun processAllTriangles(callback: TriangleCallback, aabbMin: Vec3, aabbMax: Vec3) {
39 | val halfExtents = (aabbMax - aabbMin) * 0.5f
40 | val radius = halfExtents.length()
41 | val center = (aabbMax + aabbMin) * 0.5f
42 |
43 | //this is where the triangles are generated, given AABB and plane equation (normal/constant)
44 | val tangentDir0 = Vec3()
45 | val tangentDir1 = Vec3()
46 |
47 | //tangentDir0/tangentDir1 can be precalculated
48 | planeSpace1(planeNormal, tangentDir0, tangentDir1)
49 |
50 | val projectedCenter = center - (planeNormal.dot(center) - planeConstant) * planeNormal
51 |
52 | val triangle = arrayOf(
53 | projectedCenter + tangentDir0 * radius + tangentDir1 * radius,
54 | projectedCenter + tangentDir0 * radius - tangentDir1 * radius,
55 | projectedCenter - tangentDir0 * radius - tangentDir1 * radius)
56 |
57 | callback.processTriangle(triangle, 0, 0)
58 |
59 | triangle[0] = projectedCenter - tangentDir0 * radius - tangentDir1 * radius
60 | triangle[1] = projectedCenter - tangentDir0 * radius + tangentDir1 * radius
61 | triangle[2] = projectedCenter + tangentDir0 * radius + tangentDir1 * radius
62 |
63 | callback.processTriangle(triangle, 0, 1)
64 | }
65 |
66 | override fun calculateLocalInertia(mass: Float, inertia: Vec3) {
67 | //moving concave objects not supported
68 | inertia put 0f
69 | }
70 |
71 | /** debugging */
72 | override val name get()= "STATICPLANE"
73 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/collisionShapes/TriangleCallback.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.collision.collisionShapes
17 |
18 | import bullet.linearMath.Vec3
19 |
20 | /** The TriangleCallback provides a callback for each overlapping triangle when calling processAllTriangles.
21 | * This callback is called by processAllTriangles for all btConcaveShape derived class, such as BvhTriangleMeshShape,
22 | * StaticPlaneShape and HeightfieldTerrainShape. */
23 | interface TriangleCallback {
24 | fun processTriangle(triangle: Array, partId: Int, triangleIndex: Int)
25 | }
26 |
27 | interface InternalTriangleIndexCallback {
28 | fun internalProcessTriangleIndex(triangle:Array, partId: Int, triangleIndex: Int)
29 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/collisionShapes/TriangleIndexVertexArray.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.collision.collisionShapes
17 |
18 | import bullet.linearMath.Vec3
19 |
20 | /** The IndexedMesh indexes a single vertex and index array. Multiple IndexedMesh objects can be passed into a
21 | * TriangleIndexVertexArray using addIndexedMesh.
22 | * Instead of the number of indices, we pass the number of triangles. */
23 | class IndexedMesh {
24 | var numTriangles = 0
25 | var indices: Any? = null // TODO not nullable?
26 | var triangleIndexBase = 0
27 | /** Size in byte of the indices for one triangle (3 * indexType.size if the indices are tightly packed) */
28 | var triangleIndexStride = 0
29 | var numVertices = 0
30 | var vertices: Any? = null // TODO not nullable?
31 | var vertexBase = 0
32 | /** Size of a vertex, in bytes */
33 | var vertexStride = 0
34 | /** The index type is set when adding an indexed mesh to the TriangleIndexVertexArray, do not set it manually */
35 | var indexType = PHY_ScalarType.INTEGER
36 | /** The vertex type has a default type similar to Bullet's precision mode (float or double) but can be set manually
37 | * if you for example run Bullet with double precision but have mesh data in single precision.. */
38 | var vertexType = PHY_ScalarType.FLOAT
39 |
40 | operator fun component1() = vertices!!
41 | operator fun component2() = vertexBase
42 | operator fun component3() = numVertices
43 | operator fun component4() = vertexType
44 | operator fun component5() = vertexStride
45 | operator fun component6() = indices!!
46 | operator fun component7() = triangleIndexBase
47 | operator fun component8() = triangleIndexStride
48 | operator fun component9() = numTriangles
49 | operator fun component10() = indexType
50 | }
51 |
52 | /** The TriangleIndexVertexArray allows to access multiple triangle meshes, by indexing into existing triangle/index arrays.
53 | * Additional meshes can be added using addIndexedMesh
54 | * No duplicate is made of the vertex/index data, it only indexes into external vertex/index arrays.
55 | * So keep those arrays around during the lifetime of this TriangleIndexVertexArray. */
56 | class TriangleIndexVertexArray : StridingMeshInterface() {
57 |
58 | var indexedMeshes = ArrayList()
59 | var hasAabb = false
60 | val aabbMin = Vec3()
61 | val aabbMax = Vec3()
62 |
63 | // just to be backwards compatible
64 | // btTriangleIndexVertexArray(int numTriangles, int * triangleIndexBase, int triangleIndexStride, int numVertices, btScalar * vertexBase, int vertexStride);
65 |
66 | fun addIndexedMesh(mesh: IndexedMesh, indexType: PHY_ScalarType = PHY_ScalarType.INTEGER) {
67 | indexedMeshes.add(mesh)
68 | indexedMeshes.last().indexType = indexType
69 | }
70 |
71 | /** JVM specific, returns the mesh with filled data */
72 | override fun getLockedVertexIndexBase(subPart: Int): IndexedMesh {
73 | assert(subPart < numSubParts)
74 | return indexedMeshes[subPart]
75 | }
76 |
77 | /** JVM specific, returns the mesh with filled data */
78 | override fun getLockedReadOnlyVertexIndexBase(subPart: Int) = indexedMeshes[subPart]
79 |
80 | /** unLockVertexBase finishes the access to a subpart of the triangle mesh
81 | * make a call to unLockVertexBase when the read and write access (using getLockedVertexIndexBase) is finished */
82 | override fun unLockVertexBase(subPart: Int) = Unit
83 |
84 | override fun unLockReadOnlyVertexBase(subPart: Int) = Unit
85 |
86 | /** numSubParts returns the number of seperate subparts, each subpart has a continuous array of vertices and indices */
87 | override val numSubParts get() = indexedMeshes.size
88 |
89 | override fun preallocateVertices(numVerts: Int) = Unit
90 | override fun preallocateIndices(numIndices: Int) = Unit
91 |
92 | //virtual bool hasPremadeAabb() const;
93 | override fun setPremadeAabb(aabbMin: Vec3, aabbMax: Vec3) {
94 | this.aabbMin put aabbMin // TODO check if copy reference or not
95 | this.aabbMax put aabbMax
96 | hasAabb = true
97 | }
98 | override fun getPremadeAabb(aabbMin: Vec3, aabbMax: Vec3) {
99 | this.aabbMin put aabbMin
100 | this.aabbMax put aabbMax
101 | }
102 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/collisionShapes/TriangleInfoMap.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2010 Erwin Coumans http://bulletphysics.org
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.collision.collisionShapes
17 |
18 | import bullet.linearMath.PI2
19 |
20 | // for btTriangleInfo m_flags
21 | val TRI_INFO_V0V1_CONVEX = 1
22 | val TRI_INFO_V1V2_CONVEX = 2
23 | val TRI_INFO_V2V0_CONVEX = 4
24 |
25 | val TRI_INFO_V0V1_SWAP_NORMALB = 8
26 | val TRI_INFO_V1V2_SWAP_NORMALB = 16
27 | val TRI_INFO_V2V0_SWAP_NORMALB = 32
28 |
29 |
30 | /** The TriangleInfo structure stores information to adjust collision normals to avoid collisions against internal edges
31 | * it can be generated using */
32 | class TriangleInfo {
33 | var flags = 0
34 | var edgeV0V1Angle = PI2
35 | var edgeV1V2Angle = PI2
36 | var edgeV2V0Angle = PI2
37 | }
38 |
39 | /** The TriangleInfoMap stores edge angle information for some triangles. You can compute this information yourself or
40 | * using GenerateInternalEdgeInfo. */
41 | class TriangleInfoMap : HashMap() {
42 | /** used to determine if an edge or contact normal is convex, using the dot product */
43 | var convexEpsilon = 0f
44 | /** used to determine if a triangle edge is planar with zero angle */
45 | var planarEpsilon = 0.0001f
46 | /** used to compute connectivity: if the distance between two vertices is smaller than m_equalVertexThreshold,
47 | * they are considered to be 'shared' */
48 | var equalVertexThreshold = 0.0001f * 0.0001f
49 | /** used to determine edge contacts: if the closest distance between a contact point and an edge is smaller than
50 | * this distance threshold it is considered to "hit the edge" */
51 | var edgeDistanceThreshold = 0.1f
52 | /** ignore edges that connect triangles at an angle larger than this maxEdgeAngleThreshold */
53 | var maxEdgeAngleThreshold = 0.0001f * 0.0001f
54 | /** used to determine if a triangle is degenerate (length squared of cross product of 2 triangle edges < threshold) */
55 | var zeroAreaThreshold = PI2
56 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/collisionShapes/TriangleMeshShape.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.collision.collisionShapes
17 |
18 | import bullet.collision.broadphaseCollision.BroadphaseNativeTypes
19 | import bullet.linearMath.*
20 |
21 | /** The TriangleMeshShape is an internal concave triangle mesh interface. Don't use this class directly, use
22 | * BvhTriangleMeshShape instead. */
23 | abstract class TriangleMeshShape
24 | /** TriangleMeshShape constructor has been disabled/protected, so that users will not mistakenly use this class.
25 | * Don't use TriangleMeshShape but use BvhTriangleMeshShape instead! */
26 | protected constructor(val meshInterface: StridingMeshInterface) : ConcaveShape() {
27 |
28 | val localAabbMin = Vec3()
29 | val localAabbMax = Vec3()
30 |
31 | init {
32 | shapeType = BroadphaseNativeTypes.TRIANGLE_MESH_SHAPE_PROXYTYPE
33 | if (meshInterface.hasPremadeAabb()) meshInterface.getPremadeAabb(localAabbMin, localAabbMax)
34 | else recalcLocalAabb()
35 | }
36 |
37 | fun localGetSupportingVertex(vec: Vec3): Vec3 {
38 | val ident = Transform().apply { setIdentity() }
39 | val supportCallback = SupportVertexCallback(vec, ident)
40 | val aabbMax = Vec3(LARGE_FLOAT)
41 | processAllTriangles(supportCallback, -aabbMax, aabbMax)
42 | return supportCallback.supportVertexLocal // supportVertex, TODO check if copy needed
43 | }
44 |
45 | fun localGetSupportingVertexWithoutMargin(vec: Vec3): Vec3 {
46 | assert(false)
47 | return localGetSupportingVertex(vec)
48 | }
49 |
50 | fun recalcLocalAabb() {
51 | for (i in 0..2) {
52 | val vec = Vec3().apply { set(i, 1f) }
53 | val tmp = localGetSupportingVertex(vec)
54 | localAabbMax[i] = tmp[i] + collisionMargin
55 | vec[i] = -1f
56 | tmp put localGetSupportingVertex(vec)
57 | localAabbMin[i] = tmp[i] - collisionMargin
58 | }
59 | }
60 |
61 | override fun getAabb(trans: Transform, aabbMin: Vec3, aabbMax: Vec3) {
62 | val localHalfExtents = 0.5f * (localAabbMax - localAabbMin)
63 | localHalfExtents += margin
64 | val localCenter = 0.5f * (localAabbMax + localAabbMin)
65 |
66 | val absB = trans.basis.absolute()
67 |
68 | val center = trans(localCenter)
69 |
70 | val extent = localHalfExtents dot3 absB
71 | aabbMin put center - extent // TODO order
72 | aabbMax put center + extent
73 | }
74 |
75 | override fun processAllTriangles(callback: TriangleCallback, aabbMin: Vec3, aabbMax: Vec3) {
76 |
77 | class FilteredCallback(val callback: TriangleCallback, val aabbMin: Vec3, val aabbMax: Vec3) : InternalTriangleIndexCallback {
78 |
79 | override fun internalProcessTriangleIndex(triangle: Array, partId: Int, triangleIndex: Int) {
80 | if (testTriangleAgainstAabb2(triangle, aabbMin, aabbMax))
81 | callback.processTriangle(triangle, partId, triangleIndex) //check aabb in triangle-space, before doing this
82 | }
83 | }
84 |
85 | val filterCallback = FilteredCallback(callback, aabbMin, aabbMax)
86 | meshInterface.internalProcessAllTriangles(filterCallback, aabbMin, aabbMax)
87 | }
88 |
89 | override fun calculateLocalInertia(mass: Float, inertia: Vec3) {
90 | assert(false, { "moving concave objects not supported" })
91 | inertia put 0f
92 | }
93 |
94 | override var localScaling // TODO search for potential bug
95 | get() = meshInterface.scaling
96 | set(value) {
97 | meshInterface.scaling put value
98 | recalcLocalAabb()
99 | }
100 |
101 | /** debugging */
102 | override val name get() = "TRIANGLEMESH"
103 | }
104 |
105 | class SupportVertexCallback(supportVecWorld: Vec3, val worldTrans: Transform) : TriangleCallback {
106 |
107 | val supportVertexLocal = Vec3()
108 | var maxDot = -LARGE_FLOAT
109 | val supportVecLocal = supportVecWorld * worldTrans.basis
110 |
111 | override fun processTriangle(triangle: Array, partId: Int, triangleIndex: Int) {
112 | for (t in triangle) {
113 | val dot = supportVecLocal dot t
114 | if (dot > maxDot) {
115 | maxDot = dot
116 | supportVertexLocal put t
117 | }
118 | }
119 | }
120 |
121 | val supportVertexWorldSpace get() = worldTrans(supportVertexLocal)
122 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/collisionShapes/TriangleShape.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.collision.collisionShapes
17 |
18 | import bullet.linearMath.Transform
19 | import bullet.linearMath.Vec3
20 | import bullet.collision.broadphaseCollision.BroadphaseNativeTypes as BNT
21 |
22 | class TriangleShape : PolyhedralConvexShape {
23 |
24 | val vertices = Array(3, { Vec3() })
25 |
26 | override val numVertices get() = 3
27 |
28 | fun getVertexPtr(index: Int) = vertices[index]
29 |
30 | override fun getVertex(i: Int, vtx: Vec3) = vtx put vertices[i]
31 |
32 | override val numEdges get() = 3
33 |
34 | override fun getEdge(i: Int, pa: Vec3, pb: Vec3) {
35 | getVertex(i, pa)
36 | getVertex((i + 1) % 3, pb)
37 | }
38 |
39 | override fun getAabb(trans: Transform, aabbMin: Vec3, aabbMax: Vec3) = getAabbSlow(trans, aabbMin, aabbMax)
40 |
41 | override fun localGetSupportingVertexWithoutMargin(vec: Vec3) = vertices[(vec dot3 vertices).maxAxis()]
42 |
43 | override fun batchedUnitVectorGetSupportingVertexWithoutMargin(vectors: Array, supportVerticesOut: Array, numVectors: Int) {
44 | for (i in 0 until numVectors) {
45 | val dir = vectors[i]
46 | val dots = dir dot3 vertices
47 | supportVerticesOut[i] = vertices[dots.maxAxis()]
48 | }
49 | }
50 |
51 | constructor() : super() {
52 | shapeType = BNT.TRIANGLE_SHAPE_PROXYTYPE
53 | }
54 |
55 | constructor(ps: Array) : this(ps[0], ps[1], ps[2])
56 | constructor(p0: Vec3, p1: Vec3, p2: Vec3) : super() {
57 | shapeType = BNT.TRIANGLE_SHAPE_PROXYTYPE
58 | vertices[0] put p0
59 | vertices[1] put p1
60 | vertices[2] put p2
61 | }
62 |
63 | override fun getPlane(planeNormal: Vec3, planeSupport: Vec3, i: Int) = getPlaneEquation(i, planeNormal, planeSupport)
64 |
65 | override val numPlanes get() = 1
66 |
67 | fun calcNormal(normal: Vec3 = Vec3()): Vec3 {
68 | normal put ((vertices[1] - vertices[0]) cross (vertices[2] - vertices[0]))
69 | return normal.normalize()
70 | }
71 |
72 | fun getPlaneEquation(i: Int, planeNormal: Vec3, planeSupport: Vec3) {
73 | calcNormal(planeNormal)
74 | planeSupport put vertices[0]
75 | }
76 |
77 | override fun calculateLocalInertia(mass: Float, inertia: Vec3) {
78 | TODO()
79 | // btAssert(0)
80 | // inertia.setValue(btScalar(0.), btScalar(0.), btScalar(0.))
81 | }
82 |
83 | override fun isInside(pt: Vec3, tolerance: Float): Boolean {
84 | val normal = calcNormal()
85 | //distance to plane
86 | var dist = pt dot normal
87 | val planeConst = vertices[0] dot normal
88 | dist -= planeConst
89 | if (dist in -tolerance..tolerance) {
90 | //inside check on edge-planes
91 | for (i in 0..2) {
92 | val pa = Vec3()
93 | val pb = Vec3()
94 | getEdge(i, pa, pb)
95 | val edge = pb - pa
96 | val edgeNormal = edge cross normal
97 | edgeNormal.normalize()
98 | var dist = pt dot edgeNormal
99 | val edgeConst = pa dot edgeNormal
100 | dist -= edgeConst
101 | if (dist < -tolerance) return false
102 | }
103 | return true
104 | }
105 | return false
106 | }
107 |
108 | override val name get() = "Triangle"
109 |
110 | override val numPreferredPenetrationDirections get() = 2
111 |
112 | override fun getPreferredPenetrationDirection(index: Int, penetrationVector: Vec3) {
113 | calcNormal(penetrationVector)
114 | if (index != 0) penetrationVector *= -1f
115 | }
116 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/narrowPhaseCollision/ConvexCast.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.collision.narrowPhaseCollision
17 |
18 | import bullet.linearMath.DebugDraw
19 | import bullet.linearMath.LARGE_FLOAT
20 | import bullet.linearMath.Transform
21 | import bullet.linearMath.Vec3
22 |
23 |
24 | /** ConvexCast is an interface for Casting */
25 | abstract class ConvexCast {
26 |
27 | /** RayResult stores the closest result
28 | * alternatively, add a callback method to decide about closest/all results */
29 | class CastResult {
30 | infix fun debugDraw(fraction: Float) = Unit
31 | infix fun drawCoordSystem(trans: Transform) = Unit
32 | fun reportFailure(errNo: Int, numIterations: Int) = Unit
33 |
34 | val hitTransformA = Transform()
35 | val hitTransformB = Transform()
36 | val normal = Vec3()
37 | val hitPoint = Vec3()
38 | /** input and output */
39 | var fraction = LARGE_FLOAT
40 | var debugDrawer: DebugDraw? = null
41 | var allowedPenetration = 0f
42 | }
43 |
44 | /** cast a convex against another convex object */
45 | abstract fun calcTimeOfImpact(fromA: Transform, toA: Transform, fromB: Transform, toB: Transform, result: CastResult): Boolean
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/narrowPhaseCollision/ConvexPenetrationDepthSolver.kt:
--------------------------------------------------------------------------------
1 | package bullet.collision.narrowPhaseCollision
2 |
3 | import bullet.collision.collisionShapes.ConvexShape
4 | import bullet.linearMath.DebugDraw
5 | import bullet.linearMath.Transform
6 | import bullet.linearMath.Vec3
7 |
8 | /** ConvexPenetrationDepthSolver provides an interface for penetration depth calculation. */
9 | interface ConvexPenetrationDepthSolver {
10 |
11 | fun calcPenDepth(simplexSolver: SimplexSolverInterface,
12 | convexA: ConvexShape, convexB: ConvexShape,
13 | transA: Transform, transB: Transform,
14 | v: Vec3, pa: Vec3, pb: Vec3,
15 | debugDraw: DebugDraw?): Boolean
16 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/narrowPhaseCollision/DiscreteCollisionDetectorInterface.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.collision.narrowPhaseCollision
17 |
18 | import bullet.linearMath.DebugDraw
19 | import bullet.linearMath.LARGE_FLOAT
20 | import bullet.linearMath.Transform
21 | import bullet.linearMath.Vec3
22 |
23 | /** This interface is made to be used by an iterative approach to do TimeOfImpact calculations
24 | * This interface allows to query for closest points and penetration depth between two (convex) objects
25 | * The closest point is on the second object (B), and the normal points from the surface on B towards A.
26 | * Distance is between closest points on B and closest point on A. So you can calculate closest point on A by taking
27 | * closestPointInA = closestPointInB + distance * normalOnSurfaceB */
28 | interface DiscreteCollisionDetectorInterface {
29 |
30 | interface Result {
31 |
32 | /** provides experimental support for per-triangle material / custom material combiner */
33 | fun setShapeIdentifiersA(partId0: Int, index0: Int)
34 |
35 | /** provides experimental support for per-triangle material / custom material combiner */
36 | fun setShapeIdentifiersB(partId1: Int, index1: Int)
37 |
38 | fun addContactPoint(normalOnBInWorld: Vec3, pointInWorld: Vec3, depth: Float)
39 | }
40 |
41 | class ClosestPointInput {
42 | val transformA = Transform()
43 | val transformB = Transform()
44 | var maximumDistanceSquared = LARGE_FLOAT
45 | }
46 |
47 | /** give either closest points (distance > 0) or penetration (distance)
48 | * the normal always points from B towards A */
49 | fun getClosestPoints(input: ClosestPointInput, output: Result, debugDraw: DebugDraw?, swapResults: Boolean = false)
50 | }
51 |
52 | abstract class StorageResult : DiscreteCollisionDetectorInterface.Result {
53 |
54 | val normalOnSurfaceB = Vec3()
55 | val closestPointInB = Vec3()
56 | /** negative means penetration ! */
57 | var distance = LARGE_FLOAT
58 |
59 | override fun addContactPoint(normalOnBInWorld: Vec3, pointInWorld: Vec3, depth: Float) {
60 | if (depth < distance) {
61 | normalOnSurfaceB put normalOnBInWorld
62 | closestPointInB put pointInWorld
63 | distance = depth
64 | }
65 | }
66 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/narrowPhaseCollision/GjkCollisionDescription.kt:
--------------------------------------------------------------------------------
1 | package bullet.collision.narrowPhaseCollision
2 |
3 | import bullet.linearMath.Vec3
4 |
5 | class GjkCollisionDescription {
6 |
7 | var firstDir = Vec3(0f, 1f, 0f)
8 | var maxGjkIterations = 1000
9 | var maximumDistanceSquared = 1e30f
10 | var gjkRelError2 = 1e-6f
11 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/narrowPhaseCollision/GjkConvexCast.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.collision.narrowPhaseCollision
17 |
18 | import bullet.collision.collisionShapes.ConvexShape
19 | import bullet.linearMath.Transform
20 | import bullet.linearMath.Vec3
21 |
22 | private val MAX_ITERATIONS = 32
23 |
24 | /** GjkConvexCast performs a raycast on a convex object using support mapping. */
25 | class GjkConvexCast(val convexA: ConvexShape, val convexB: ConvexShape, val simplexSolver: SimplexSolverInterface) : ConvexCast() {
26 |
27 | override fun calcTimeOfImpact(fromA: Transform, toA: Transform, fromB: Transform, toB: Transform, result: CastResult): Boolean {
28 |
29 | simplexSolver.reset()
30 |
31 | /* Compute linear velocity for this interval, to interpolate
32 | assume no rotation/angular velocity, assert here? */
33 | val linVelA = toA.origin - fromA.origin
34 | val linVelB = toB.origin - fromB.origin
35 |
36 | val radius = 0.001f
37 | var lambda = 0f
38 | val v = Vec3(1f, 0f, 0f)
39 |
40 | var maxIter = MAX_ITERATIONS
41 |
42 | val n = Vec3()
43 | var hasResult = false
44 | val r = linVelA - linVelB
45 |
46 | var lastLambda = lambda
47 | //btScalar epsilon = btScalar(0.001);
48 |
49 | var numIter = 0
50 | //first solution, using GJK
51 |
52 | val identityTrans = Transform().apply { setIdentity() }
53 |
54 | // result.drawCoordSystem(sphereTr);
55 |
56 | val pointCollector = PointCollector()
57 |
58 | val gjk = GjkPairDetector(convexA, convexB, simplexSolver, null)//m_penetrationDepthSolver);
59 | val input = DiscreteCollisionDetectorInterface.ClosestPointInput()
60 |
61 | //we don't use margins during CCD
62 | // gjk.setIgnoreMargin(true);
63 |
64 | input.transformA put fromA
65 | input.transformB put fromB
66 | gjk.getClosestPoints(input, pointCollector, null)
67 |
68 | hasResult = pointCollector.hasResult
69 | val c = Vec3(pointCollector.pointInWorld)
70 |
71 | if (hasResult) {
72 | var dist = pointCollector.distance
73 | n put pointCollector.normalOnBInWorld
74 |
75 | //not close enough
76 | while (dist > radius) {
77 | numIter++
78 | if (numIter > maxIter) return false //todo: report a failure
79 | var dLambda = 0f
80 |
81 | val projectedLinearVelocity = r dot n
82 |
83 | dLambda = dist / (projectedLinearVelocity)
84 |
85 | lambda -= dLambda
86 |
87 | if (lambda > 1f) return false
88 |
89 | if (lambda < 0f) return false
90 |
91 | //todo: next check with relative epsilon
92 | if (lambda <= lastLambda) {
93 | return false
94 | //n.setValue(0,0,0);
95 | break
96 | }
97 | lastLambda = lambda
98 |
99 | //interpolate to next lambda
100 | result debugDraw lambda
101 | input.transformA.origin.setInterpolate3(fromA.origin, toA.origin, lambda)
102 | input.transformB.origin.setInterpolate3(fromB.origin, toB.origin, lambda)
103 |
104 | gjk.getClosestPoints(input, pointCollector, null)
105 | if (pointCollector.hasResult) {
106 | if (pointCollector.distance < 0f) {
107 | result.fraction = lastLambda
108 | n put pointCollector.normalOnBInWorld
109 | result.normal put n
110 | result.hitPoint put pointCollector.pointInWorld
111 | return true
112 | }
113 | c put pointCollector.pointInWorld
114 | n put pointCollector.normalOnBInWorld
115 | dist = pointCollector.distance
116 | } else return false //??
117 | }
118 |
119 | // is n normalized?
120 | // don't report time of impact for motion away from the contact normal (or causes minor penetration)
121 | if (n.dot(r) >= -result.allowedPenetration) return false
122 |
123 | result.fraction = lambda
124 | result.normal put n
125 | result.hitPoint put c
126 | return true
127 | }
128 | return false
129 | }
130 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/narrowPhaseCollision/GjkEpaPenetrationDepthSolver.kt:
--------------------------------------------------------------------------------
1 | package bullet.collision.narrowPhaseCollision
2 |
3 | import bullet.collision.collisionShapes.ConvexShape
4 | import bullet.linearMath.DebugDraw
5 | import bullet.linearMath.Transform
6 | import bullet.linearMath.Vec3
7 |
8 | class GjkEpaPenetrationDepthSolver : ConvexPenetrationDepthSolver {
9 |
10 | override fun calcPenDepth(simplexSolver: SimplexSolverInterface,
11 | convexA: ConvexShape, convexB: ConvexShape,
12 | transA: Transform, transB: Transform,
13 | v: Vec3, pa: Vec3, pb: Vec3,
14 | debugDraw: DebugDraw?): Boolean {
15 |
16 |
17 | // const btScalar radialmargin(btScalar(0.));
18 |
19 | val guessVector = Vec3(transB.origin - transA.origin)
20 | val results = GjkEpaSolver2.Results()
21 |
22 | return when {
23 | GjkEpaSolver2.penetration(convexA, transA,
24 | convexB, transB,
25 | guessVector, results) -> {
26 | // debugDraw->drawLine(results.witnesses[1],results.witnesses[1]+results.normal,btVector3(255,0,0));
27 | //resultOut->addContactPoint(results.normal,results.witnesses[1],-results.depth);
28 | pa put results.witnesses[0]
29 | pb put results.witnesses[1]
30 | v put results.normal
31 | true
32 | }
33 | GjkEpaSolver2.distance(convexA, transA, convexB, transB, guessVector, results) -> {
34 | pa put results.witnesses[0]
35 | pb put results.witnesses[1]
36 | v put results.normal
37 | false
38 | }
39 | else -> false
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/narrowPhaseCollision/ManifoldPoint.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.collision.narrowPhaseCollision
17 |
18 | import bullet.linearMath.Vec3
19 |
20 | // Don't change following order of parameters
21 | class ConstraintRow {
22 | val normal = FloatArray(3)
23 | var rhs = 0f
24 | var jacDiagInv = 0f
25 | var lowerLimit = 0f
26 | var upperLimit = 0f
27 | var accumImpulse = 0f
28 | }
29 |
30 | enum class ContactPointFlags { LATERAL_FRICTION_INITIALIZED, HAS_CONTACT_CFM, HAS_CONTACT_ERP, CONTACT_STIFFNESS_DAMPING, FRICTION_ANCHOR;
31 |
32 | val i = 1 shl ordinal
33 | }
34 |
35 | infix fun Int.or(b: ContactPointFlags) = or(b.i)
36 | infix fun Int.has(b: ContactPointFlags) = (this and b.i) != 0
37 | infix fun Int.hasnt(b: ContactPointFlags) = (this and b.i) == 0
38 |
39 | /** ManifoldContactPoint collects and maintains persistent contactpoints.
40 | * used to improve stability and performance of rigidbody dynamics response. */
41 | class ManifoldPoint {
42 |
43 |
44 | val localPointA = Vec3()
45 | val localPointB = Vec3()
46 | val positionWorldOnB = Vec3()
47 | /** m_positionWorldOnA is redundant information, see getPositionWorldOnA(), but for clarity */
48 | val positionWorldOnA = Vec3()
49 | val normalWorldOnB = Vec3()
50 |
51 | var distance = 0f
52 | var combinedFriction = 0f
53 | /** torsional friction orthogonal to contact normal, useful to make spheres stop rolling forever */
54 | var combinedRollingFriction = 0f
55 | /** torsional friction around contact normal, useful for grasping objects */
56 | var combinedSpinningFriction = 0f
57 | var combinedRestitution = 0f
58 |
59 | //BP mod, store contact triangles.
60 | var partId0 = 0
61 | var partId1 = 0
62 | var index0 = 0
63 | var index1 = 0
64 |
65 | var userPersistentData: Any? = null
66 | var contactPointFlags = 0
67 |
68 | var appliedImpulse = 0f
69 |
70 | var appliedImpulseLateral1 = 0f
71 | var appliedImpulseLateral2 = 0f
72 | var contactMotion1 = 0f
73 | var contactMotion2 = 0f
74 |
75 | private var union0 = 0f
76 |
77 | var contactCFM
78 | get() = union0
79 | set(value) {
80 | union0 = value
81 | }
82 | var combinedContactStiffness1
83 | get() = union0
84 | set(value) {
85 | union0 = value
86 | }
87 |
88 | private var union1 = 0f
89 | var contactERP
90 | get() = union1
91 | set(value) {
92 | union1 = value
93 | }
94 | var combinedContactDamping1
95 | get() = union1
96 | set(value) {
97 | union1 = value
98 | }
99 |
100 | var frictionCFM = 0f
101 | /** lifetime of the contactpoint in frames */
102 | var lifeTime = 0f
103 |
104 | val lateralFrictionDir1 = Vec3()
105 | val lateralFrictionDir2 = Vec3()
106 |
107 |
108 | constructor()
109 | constructor(pointA: Vec3, pointB: Vec3, normal: Vec3, distance: Float) {
110 | localPointA put pointA
111 | localPointB put pointB
112 | normalWorldOnB put normal
113 | this.distance = distance
114 | }
115 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/narrowPhaseCollision/PointCollector.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.collision.narrowPhaseCollision
17 |
18 | import bullet.linearMath.LARGE_FLOAT
19 | import bullet.linearMath.Vec3
20 |
21 | class PointCollector : DiscreteCollisionDetectorInterface.Result{
22 |
23 | val normalOnBInWorld = Vec3()
24 | val pointInWorld = Vec3()
25 | /** negative means penetration */
26 | var distance = LARGE_FLOAT
27 |
28 | var hasResult = false
29 |
30 | override fun setShapeIdentifiersA(partId0: Int, index0: Int) = Unit
31 | override fun setShapeIdentifiersB(partId1: Int, index1: Int) = Unit
32 |
33 | override fun addContactPoint(normalOnBInWorld: Vec3, pointInWorld: Vec3, depth: Float) {
34 | if (depth< distance) {
35 | hasResult = true
36 | this.normalOnBInWorld put normalOnBInWorld
37 | this.pointInWorld put pointInWorld
38 | //negative means penetration
39 | distance = depth
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/narrowPhaseCollision/RaycastCallback.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.collision.narrowPhaseCollision
17 |
18 | import bullet.collision.collisionShapes.ConvexShape
19 | import bullet.collision.collisionShapes.TriangleCallback
20 | import bullet.collision.collisionShapes.TriangleShape
21 | import bullet.has
22 | import bullet.hasnt
23 | import bullet.linearMath.Transform
24 | import bullet.linearMath.Vec3
25 |
26 | open class TriangleRaycastCallback(val from: Vec3, val to: Vec3, flags: Int = 0) : TriangleCallback {
27 |
28 | //@BP Mod - allow backface filtering and unflipped normals
29 | enum class Flags(val i: Int) {
30 | None(0),
31 | FilterBackfaces(1 shl 0),
32 | /** Prevents returned face normal getting flipped when a ray hits a back-facing triangle */
33 | KeepUnflippedNormal(1 shl 1),
34 | /** SubSimplexConvexCastRaytest is the default, even if kF_None is set. */
35 | /** Uses an approximate but faster ray versus convex intersection algorithm */
36 | UseSubSimplexConvexCastRaytest(1 shl 2),
37 | UseGjkConvexCastRaytest(1 shl 3),
38 | Terminator(0.inv())
39 | }
40 |
41 | var flags = 0
42 |
43 | var hitFraction = 1f
44 |
45 | override fun processTriangle(triangle: Array, partId: Int, triangleIndex: Int) {
46 |
47 | val (vert0, vert1, vert2) = triangle
48 |
49 | val v10 = vert1 - vert0
50 | val v20 = vert2 - vert0
51 |
52 | val triangleNormal = v10 cross v20
53 |
54 | val dist = vert0 dot triangleNormal
55 | val distA = (triangleNormal dot from) - dist
56 | val distB = (triangleNormal dot to) - dist
57 |
58 | if (distA * distB >= 0f) return // same sign
59 |
60 | if (flags has Flags.FilterBackfaces.i && distA <= 0f) return // Backface, skip check
61 |
62 | val projLength = distA - distB
63 | val distance = distA / projLength
64 | /* Now we have the intersection point on the plane, we'll see if it's inside the triangle
65 | Add an epsilon as a tolerance for the raycast,
66 | In case the ray hits exacly on the edge of the triangle.
67 | It must be scaled for the triangle size. */
68 | if (distance < hitFraction) {
69 | val edgeTolerance = triangleNormal.length2() * -0.0001f
70 | val point = Vec3().apply { setInterpolate3(from, to, distance) }
71 | val v0p = vert0 - point
72 | val v1p = vert1 - point
73 | val cp0 = v0p cross v1p
74 | if (cp0 dot triangleNormal >= edgeTolerance) {
75 | val v2p = vert2 - point
76 | val cp1 = v1p cross v2p
77 | if (cp1 dot triangleNormal >= edgeTolerance) {
78 | val cp2 = v2p cross v0p
79 | if (cp2 dot triangleNormal >= edgeTolerance) {
80 | //@BP Mod
81 | // Triangle normal isn't normalized
82 | triangleNormal.normalize()
83 | //@BP Mod - Allow for unflipped normal when raycasting against backfaces
84 | hitFraction = reportHit(
85 | if (flags hasnt Flags.KeepUnflippedNormal.i && distA <= 0f) -triangleNormal else triangleNormal,
86 | distance, partId, triangleIndex)
87 | }
88 | }
89 | }
90 | }
91 | }
92 |
93 | open fun reportHit(hitNormalLocal: Vec3, hitFraction: Float, partId: Int, triangleIndex: Int) = 0f
94 | }
95 |
96 | open class TriangleConvexcastCallback(val convexShape: ConvexShape, val convexShapeFrom: Transform, val convexShapeTo: Transform,
97 | val triangleToWorld: Transform, var triangleCollisionMargin: Float) : TriangleCallback {
98 | var hitFraction = 1f
99 | var allowedPenetration = 0f
100 |
101 | override fun processTriangle(triangle: Array, partId: Int, triangleIndex: Int) {
102 |
103 | val triangleShape = TriangleShape(triangle)
104 | triangleShape.margin = triangleCollisionMargin
105 |
106 | val simplexSolver = VoronoiSimplexSolver()
107 | val gjkEpaPenetrationSolver = GjkEpaPenetrationDepthSolver()
108 |
109 | val convexCaster = ContinuousConvexCollision(convexShape, triangleShape, simplexSolver, gjkEpaPenetrationSolver)
110 |
111 | val castResult = ConvexCast.CastResult().apply {
112 | fraction = 1f
113 | this.allowedPenetration = allowedPenetration
114 | }
115 | if (convexCaster.calcTimeOfImpact(convexShapeFrom, convexShapeTo, triangleToWorld, triangleToWorld, castResult))
116 | //add hit
117 | if (castResult.normal.length2() > 0.0001f)
118 | if (castResult.fraction < hitFraction) {
119 | castResult.normal.normalize()
120 | reportHit(castResult.normal, castResult.hitPoint, castResult.fraction, partId, triangleIndex)
121 | }
122 | }
123 |
124 | open fun reportHit(hitNormalLocal: Vec3, hitPointLocal: Vec3, hitFraction: Float, partId: Int, triangleIndex: Int) = 0f
125 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/narrowPhaseCollision/SimplexSolverInterface.kt:
--------------------------------------------------------------------------------
1 | package bullet.collision.narrowPhaseCollision
2 |
3 | typealias SimplexSolverInterface = VoronoiSimplexSolver
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/collision/narrowPhaseCollision/SubSimplexConvexCast.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.collision.narrowPhaseCollision
17 |
18 | import bullet.EPSILON
19 | import bullet.collision.collisionShapes.ConvexShape
20 | import bullet.linearMath.Transform
21 | import bullet.linearMath.Vec3
22 | import bullet.linearMath.times
23 |
24 | private val MAX_ITERATIONS = 32
25 |
26 | /** SubsimplexConvexCast implements Gino van den Bergens' paper
27 | * "Ray Casting against bteral Convex Objects with Application to Continuous Collision Detection"
28 | * GJK based Ray Cast, optimized version
29 | * Objects should not start in overlap, otherwise results are not defined. */
30 | class SubsimplexConvexCast(val convexA: ConvexShape, val convexB: ConvexShape, val simplexSolver: SimplexSolverInterface)
31 | : ConvexCast() {
32 |
33 | /** SimsimplexConvexCast calculateTimeOfImpact calculates the time of impact+normal for the linear cast (sweep) between two moving objects.
34 | * Precondition is that objects should not penetration/overlap at the start from the interval. Overlap can be tested using GjkPairDetector. */
35 | override fun calcTimeOfImpact(fromA: Transform, toA: Transform, fromB: Transform, toB: Transform, result: CastResult): Boolean {
36 |
37 | simplexSolver.reset()
38 |
39 | val linVelA = toA.origin - fromA.origin
40 | val linVelB = toB.origin - fromB.origin
41 |
42 | var lambda = 0f
43 |
44 | val interpolatedTransA = Transform(fromA)
45 | val interpolatedTransB = Transform(fromB)
46 |
47 | // take relative motion
48 | val r = linVelA - linVelB
49 |
50 | val supVertexA = fromA(convexA.localGetSupportingVertex(-r * fromA.basis))
51 | val supVertexB = fromB(convexB.localGetSupportingVertex(r * fromB.basis))
52 | val v = supVertexA - supVertexB
53 | var maxIter = MAX_ITERATIONS
54 |
55 | val n = Vec3()
56 |
57 | var dist2 = v.length2()
58 | val epsilon = 0.0001f
59 | val w = Vec3()
60 | val p = Vec3()
61 | var vDotR = 0f
62 |
63 | while (dist2 > epsilon && maxIter != 0) {
64 | maxIter--
65 | supVertexA put interpolatedTransA(convexA.localGetSupportingVertex(-v * interpolatedTransA.basis))
66 | supVertexB put interpolatedTransB(convexB.localGetSupportingVertex(v * interpolatedTransB.basis))
67 | w put supVertexA - supVertexB
68 |
69 | val vDotW = v dot w
70 |
71 | if (lambda > 1f) return false
72 |
73 | if (vDotW > 0f) {
74 | vDotR = v dot r
75 | if (vDotR >= -Float.EPSILON * Float.EPSILON) return false
76 | else {
77 | lambda -= vDotW / vDotR
78 | //interpolate to next lambda
79 | // x = s + lambda * r;
80 | interpolatedTransA.origin.setInterpolate3(fromA.origin, toA.origin, lambda)
81 | interpolatedTransB.origin.setInterpolate3(fromB.origin, toB.origin, lambda)
82 | //m_simplexSolver->reset();
83 | //check next line
84 | w put supVertexA - supVertexB
85 | n put v
86 | }
87 | }
88 | // Just like regular GJK only add the vertex if it isn't already (close) to current vertex, it would lead to divisions by zero and NaN etc.
89 | if (!simplexSolver.inSimplex(w))
90 | simplexSolver.addVertex(w, supVertexA, supVertexB)
91 |
92 | dist2 = if (simplexSolver.closest(v)) v.length2()
93 | //todo: check this normal for validity
94 | //n=v;
95 | //printf("V=%f , %f, %f\n",v[0],v[1],v[2]);
96 | //printf("DIST2=%f\n",dist2);
97 | //printf("numverts = %i\n",m_simplexSolver->numVertices());
98 | else 0f
99 | }
100 | //int numiter = MAX_ITERATIONS - maxIter;
101 | // printf("number of iterations: %d", numiter);
102 | // don't report a time of impact when moving 'away' from the hitnormal
103 | result.fraction = lambda
104 | if (n.length2() >= Float.EPSILON * Float.EPSILON)
105 | result.normal put n.normalized()
106 | else result.normal put 0f
107 | // don't report time of impact for motion away from the contact normal (or causes minor penetration)
108 | if (result.normal dot r >= -result.allowedPenetration) return false
109 | val hitA = Vec3()
110 | val hitB = Vec3()
111 | simplexSolver.computePoints(hitA, hitB)
112 | result.hitPoint put hitB
113 | return true
114 | }
115 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/dynamics/constraintSolver/ConstraintSolver.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.dynamics.constraintSolver
17 |
18 | import bullet.collision.broadphaseCollision.Dispatcher
19 | import bullet.collision.collisionDispatch.CollisionObject
20 | import bullet.collision.narrowPhaseCollision.PersistentManifold
21 | import bullet.linearMath.DebugDraw
22 |
23 | enum class ConstraintSolverType { SEQUENTIAL_IMPULSE_SOLVER, MLCP_SOLVER, NNCG_SOLVER;
24 |
25 | val i = 1 shl ordinal
26 | }
27 |
28 | abstract class ConstraintSolver {
29 |
30 | fun prepareSolve(numBodies: Int, numManifolds: Int) = Unit
31 |
32 | /** solve a group of constraints */
33 | abstract fun solveGroup(bodies: ArrayList, numBodies: Int,
34 | manifolds: ArrayList, manifoldsPtr: Int, numManifolds: Int,
35 | constraints: ArrayList, constraintsPtr: Int, numConstraints: Int,
36 | infoGlobal: ContactSolverInfo, debugDrawer: DebugDraw?, dispatcher: Dispatcher): Float
37 |
38 | fun allSolved(info: ContactSolverInfo, debugDrawer: DebugDraw?) = Unit
39 |
40 | /** clear internal cached data and reset random seed */
41 | abstract fun reset()
42 |
43 | val solverType = ConstraintSolverType.SEQUENTIAL_IMPULSE_SOLVER
44 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/dynamics/constraintSolver/ContactSolverInfo.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.dynamics.constraintSolver
17 |
18 | enum class SolverMode {
19 | RANDOMIZE_ORDER,
20 | FRICTION_SEPARATE,
21 | USE_WARMSTARTING,
22 | USE_2_FRICTION_DIRECTIONS,
23 | ENABLE_FRICTION_DIRECTION_CACHING,
24 | DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION,
25 | CACHE_FRIENDLY,
26 | SIMD,
27 | INTERLEAVE_CONTACT_AND_FRICTION_CONSTRAINTS,
28 | ALLOW_ZERO_LENGTH_FRICTION_DIRECTIONS,
29 | DISABLE_IMPLICIT_CONE_FRICTION;
30 |
31 | val i = 1 shl ordinal
32 | }
33 |
34 | infix fun SolverMode.or(b: SolverMode) = i or b.i
35 | infix fun Int.has(b: SolverMode) = (this and b.i) != 0
36 | infix fun Int.hasnt(b: SolverMode) = (this and b.i) == 0
37 |
38 | open class ContactSolverInfoData {
39 |
40 | var tau = 0f
41 | /** global non-contact constraint damping, can be locally overridden by constraints during 'getInfo2'. */
42 | var damping = 0f
43 | var friction = 0f
44 | var timeStep = 0f
45 | var restitution = 0f
46 | var numIterations = 0
47 | var maxErrorReduction = 0f
48 | /** successive over-relaxation term */
49 | var sor = 0f
50 | /** error reduction for non-contact constraints */
51 | var erp = 0f
52 | /** error reduction for contact constraints */
53 | var erp2 = 0f
54 | /** constraint force mixing for contacts and non-contacts */
55 | var globalCfm = 0f
56 | /** error reduction for friction constraints */
57 | var frictionERP = 0f
58 | /** constraint force mixing for friction constraints */
59 | var frictionCFM = 0f
60 |
61 | var splitImpulse = false
62 | var splitImpulsePenetrationThreshold = 0f
63 | var splitImpulseTurnErp = 0f
64 | var linearSlop = 0f
65 | var warmstartingFactor = 0f
66 |
67 | var solverMode = 0
68 | var restingContactRestitutionThreshold = 0
69 | var minimumSolverBatchSize = 0
70 | var maxGyroscopicForce = 0f
71 | var singleAxisRollingFrictionThreshold = 0f
72 | var leastSquaresResidualThreshold = 0f
73 | var restitutionVelocityThreshold = 0f
74 | }
75 |
76 | class ContactSolverInfo : ContactSolverInfoData() {
77 | init {
78 | tau = 0.6f
79 | damping = 1f
80 | friction = 0.3f
81 | timeStep = 1f / 60f
82 | restitution = 0f
83 | maxErrorReduction = 20f
84 | numIterations = 10
85 | erp = 0.2f
86 | erp2 = 0.2f
87 | globalCfm = 0f
88 | frictionERP = 0.2f // positional friction 'anchors' are disabled by default
89 | frictionCFM = 0f
90 | sor = 1f
91 | splitImpulse = true
92 | splitImpulsePenetrationThreshold = -.04f
93 | splitImpulseTurnErp = 0.1f
94 | linearSlop = 0f
95 | warmstartingFactor = 0.85f
96 | //m_solverMode = SOLVER_USE_WARMSTARTING | SOLVER_SIMD | SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION|SOLVER_USE_2_FRICTION_DIRECTIONS|SOLVER_ENABLE_FRICTION_DIRECTION_CACHING;// | SOLVER_RANDMIZE_ORDER;
97 | solverMode = SolverMode.USE_WARMSTARTING or SolverMode.SIMD// | SOLVER_RANDMIZE_ORDER;
98 | restingContactRestitutionThreshold = 2//unused as of 2.81
99 | minimumSolverBatchSize = 128 //try to combine islands until the amount of constraints reaches this limit
100 | maxGyroscopicForce = 100f ///it is only used for 'explicit' version of gyroscopic force
101 | singleAxisRollingFrictionThreshold = 1e30f///if the velocity is above this threshold, it will use a single constraint row (axis), otherwise 3 rows.
102 | leastSquaresResidualThreshold = 0f
103 | restitutionVelocityThreshold = 0.2f//if the relative velocity is below this threshold, there is zero restitution
104 | }
105 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/dynamics/constraintSolver/SolverBody.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.dynamics.constraintSolver
17 |
18 | import bullet.dynamics.dynamics.RigidBody
19 | import bullet.linearMath.Transform
20 | import bullet.linearMath.TransformUtil
21 | import bullet.linearMath.Vec3
22 | import bullet.linearMath.times
23 |
24 | /** The SolverBody is an internal datastructure for the constraint solver. Only necessary data is packed to increase
25 | * cache coherence/performance. */
26 | class SolverBody {
27 |
28 | var worldTransform = Transform()
29 | val deltaLinearVelocity = Vec3()
30 | val deltaAngularVelocity = Vec3()
31 | val angularFactor = Vec3()
32 | val linearFactor = Vec3()
33 | val invMass = Vec3()
34 | val pushVelocity = Vec3()
35 | val turnVelocity = Vec3()
36 | val linearVelocity = Vec3()
37 | val angularVelocity = Vec3()
38 | val externalForceImpulse = Vec3()
39 | val externalTorqueImpulse = Vec3()
40 |
41 | var originalBody: RigidBody? = null
42 |
43 | fun getVelocityInLocalPointNoDelta(relPos: Vec3, velocity: Vec3) {
44 | if (originalBody != null)
45 | velocity put (linearVelocity + externalForceImpulse + (angularVelocity + externalTorqueImpulse).cross(relPos))
46 | else
47 | velocity put 0f
48 | }
49 |
50 | fun getVelocityInLocalPointObsolete(relPos: Vec3, velocity: Vec3) {
51 | if (originalBody != null)
52 | velocity put (linearVelocity + deltaLinearVelocity + (angularVelocity + deltaAngularVelocity).cross(relPos))
53 | else
54 | velocity put 0f
55 | }
56 |
57 | fun getAngularVelocity(angVel: Vec3) {
58 | if (originalBody != null)
59 | angVel put angularVelocity + deltaAngularVelocity // TODO check order
60 | else
61 | angVel put 0f
62 | }
63 |
64 | /** Optimization for the iterative solver: avoid calculating constant terms involving inertia, normal, relative position */
65 | fun applyImpulse(linearComponent: Vec3, angularComponent: Vec3, impulseMagnitude: Float) {
66 | originalBody?.let {
67 | deltaLinearVelocity += linearComponent * impulseMagnitude * linearFactor
68 | deltaAngularVelocity += angularComponent * (impulseMagnitude * angularFactor)
69 | }
70 | }
71 |
72 | fun internalApplyPushImpulse(linearComponent: Vec3, angularComponent: Vec3, impulseMagnitude: Float) {
73 | originalBody?.let {
74 | pushVelocity += linearComponent * impulseMagnitude * linearFactor
75 | turnVelocity += angularComponent * (impulseMagnitude * angularFactor)
76 | }
77 | }
78 |
79 | ////////////////////////////////////////////////
80 | ///some internal methods, don't use them
81 |
82 | fun internalGetVelocityInLocalPointObsolete(relPos: Vec3, velocity: Vec3) {
83 | velocity put (linearVelocity + deltaLinearVelocity + (angularVelocity + deltaAngularVelocity).cross(relPos))
84 | }
85 |
86 | fun internalGetAngularVelocity(angVel: Vec3) = angVel.put(angularVelocity + deltaAngularVelocity)
87 |
88 | /** Optimization for the iterative solver: avoid calculating constant terms involving inertia, normal, relative position */
89 | fun internalApplyImpulse(linearComponent: Vec3, angularComponent: Vec3, impulseMagnitude: Float) {
90 | originalBody?.let {
91 | deltaLinearVelocity += linearComponent * impulseMagnitude * linearFactor
92 | deltaAngularVelocity += angularComponent * (impulseMagnitude * angularFactor)
93 | }
94 | }
95 |
96 | fun writebackVelocity() {
97 | originalBody?.let {
98 | linearVelocity += deltaLinearVelocity
99 | angularVelocity += deltaAngularVelocity
100 | //m_originalBody->setCompanionId(-1);
101 | }
102 | }
103 |
104 |
105 | fun writebackVelocityAndTransform(timeStep: Float, splitImpulseTurnErp: Float) {
106 | originalBody?.let {
107 | linearVelocity += deltaLinearVelocity
108 | angularVelocity += deltaAngularVelocity
109 | //correct the position/orientation based on push/turn recovery
110 | val newTransform = Transform()
111 | if (pushVelocity[0] != 0f || pushVelocity[1] != 0f || pushVelocity[2] != 0f || turnVelocity[0] != 0f || turnVelocity[1] != 0f || turnVelocity[2] != 0f) {
112 | // btQuaternion orn = m_worldTransform.getRotation();
113 | TransformUtil.integrateTransform(worldTransform, pushVelocity, turnVelocity * splitImpulseTurnErp, timeStep, newTransform)
114 | worldTransform put newTransform
115 | }
116 | //m_worldTransform.setRotation(orn);
117 | //m_originalBody->setCompanionId(-1);
118 | }
119 | }
120 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/dynamics/constraintSolver/SolverConstraint.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.dynamics.constraintSolver
17 |
18 | import bullet.BYTES
19 | import bullet.collision.narrowPhaseCollision.ManifoldPoint
20 | import bullet.linearMath.Vec3
21 |
22 | /** 1D constraint along a normal axis between bodyA and bodyB. It can be combined to solve contact and friction constraints. */
23 | class SolverConstraint {
24 |
25 | val relpos1CrossNormal = Vec3()
26 | val contactNormal1 = Vec3()
27 |
28 | val relpos2CrossNormal = Vec3()
29 | /** usually m_contactNormal2 == -m_contactNormal1, but not always */
30 | val contactNormal2 = Vec3()
31 |
32 | val angularComponentA = Vec3()
33 | val angularComponentB = Vec3()
34 |
35 | var appliedPushImpulse = 0f
36 | var appliedImpulse = 0f
37 |
38 | var friction = 0f
39 | var jacDiagABInv = 0f
40 | var rhs = 0f
41 | var cfm = 0f
42 |
43 | var lowerLimit = 0f
44 | var upperLimit = 0f
45 | var rhsPenetration = 0f
46 |
47 | private var union: Any? = null
48 | var originalContactPoint
49 | get() = union
50 | set(value) {
51 | union = value
52 | }
53 | var unusedPadding4
54 | get() = union as? Float
55 | set(value) {
56 | union = value
57 | }
58 | var numRowsForNonContactConstraint
59 | get() = union as? Int
60 | set(value) {
61 | union = value
62 | }
63 |
64 | var overrideNumSolverIterations = 0
65 | var frictionIndex = 0
66 | var solverBodyIdA = 0
67 | var solverBodyIdB = 0
68 |
69 |
70 | enum class SolverConstraintType { CONTACT_1D, FRICTION_1D;
71 |
72 | val i = ordinal
73 | }
74 |
75 | companion object {
76 | val size = 6 * Vec3.size + 14 * Float.BYTES
77 | }
78 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/dynamics/dynamics/ActionInterface.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.dynamics.dynamics
17 |
18 | import bullet.collision.collisionDispatch.CollisionWorld
19 | import bullet.linearMath.DebugDraw
20 |
21 | /** Basic interface to allow actions such as vehicles and characters to be updated inside a DynamicsWorld */
22 | interface ActionInterface {
23 |
24 | fun updateAction( collisionWorld: CollisionWorld, deltaTimeStep: Float)
25 | fun debugDraw(debugDrawer: DebugDraw)
26 | // static btRigidBody& getFixedBody()
27 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/dynamics/dynamics/DynamicsWorld.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.dynamics.dynamics
17 |
18 | import bullet.collision.broadphaseCollision.BroadphaseInterface
19 | import bullet.collision.broadphaseCollision.Dispatcher
20 | import bullet.collision.collisionDispatch.CollisionConfiguration
21 | import bullet.collision.collisionDispatch.CollisionWorld
22 | import bullet.dynamics.constraintSolver.ConstraintSolver
23 | import bullet.dynamics.constraintSolver.ContactSolverInfo
24 | import bullet.dynamics.constraintSolver.TypedConstraint
25 | import bullet.linearMath.Vec3
26 |
27 | /** Type for the callback for each tick */
28 | typealias InternalTickCallback = (DynamicsWorld, Float) -> Unit
29 |
30 | enum class DynamicsWorldType { SIMPLE_DYNAMICS_WORLD, DISCRETE_DYNAMICS_WORLD, CONTINUOUS_DYNAMICS_WORLD,
31 | SOFT_RIGID_DYNAMICS_WORLD, GPU_DYNAMICS_WORLD, SOFT_MULTIBODY_DYNAMICS_WORLD;
32 |
33 | val i = ordinal + 1
34 | }
35 |
36 | /** The DynamicsWorld is the interface class for several dynamics implementation, basic, discrete, parallel, and
37 | * continuous etc. */
38 | abstract class DynamicsWorld(dispatcher: Dispatcher?, broadphase: BroadphaseInterface, collisionConfiguration: CollisionConfiguration)
39 | : CollisionWorld(dispatcher, broadphase, collisionConfiguration) {
40 |
41 | var internalTickCallback: InternalTickCallback? = null
42 | var internalPreTickCallback: InternalTickCallback? = null
43 | var worldUserInfo: Any? = null
44 |
45 | var solverInfo = ContactSolverInfo()
46 |
47 | /** stepSimulation proceeds the simulation over 'timeStep', units in preferably in seconds.
48 | * By default, Bullet will subdivide the timestep in constant substeps of each 'fixedTimeStep'.
49 | * in order to keep the simulation real-time, the maximum number of substeps can be clamped to 'maxSubSteps'.
50 | * You can disable subdividing the timestep/substepping by passing maxSubSteps = 0 as second argument to stepSimulation,
51 | * but in that case you have to keep the timeStep constant. */
52 | abstract fun stepSimulation(timeStep: Float, maxSubSteps: Int = 1, fixedTimeStep: Float = 1f / 60f): Int
53 |
54 | abstract override fun debugDrawWorld()
55 |
56 | abstract fun addConstraint(constraint: TypedConstraint, disableCollisionsBetweenLinkedBodies: Boolean = false)
57 |
58 | abstract fun removeConstraint(constraint: TypedConstraint)
59 |
60 | abstract fun addAction(action: ActionInterface)
61 |
62 | abstract fun removeAction(action: ActionInterface)
63 |
64 | /** once a rigidbody is added to the dynamics world, it will get this gravity assigned existing rigidbodies in the
65 | * world get gravity assigned too, during this method */
66 | abstract var gravity: Vec3
67 |
68 | abstract fun synchronizeMotionStates()
69 |
70 | abstract fun addRigidBody(body: RigidBody)
71 |
72 | abstract fun addRigidBody(body: RigidBody, group: Int, mask: Int)
73 |
74 | abstract fun removeRigidBody(body: RigidBody)
75 |
76 | abstract var constraintSolver: ConstraintSolver
77 |
78 | open val numConstraints get() = 0
79 |
80 | open fun getConstraint(index: Int): TypedConstraint? = null
81 |
82 | abstract val worldType: DynamicsWorldType
83 |
84 | abstract fun clearForces()
85 |
86 | /** Set the callback for when an internal tick (simulation substep) happens, optional user info */
87 | fun setInternalTickCallback(cb: InternalTickCallback, worldUserInfo: Any? = null, isPreTick: Boolean = false) {
88 | if (isPreTick)
89 | internalPreTickCallback = cb
90 | else
91 | internalTickCallback = cb
92 | this.worldUserInfo = worldUserInfo
93 | }
94 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/linearMath/ConvexHullComputer.kt:
--------------------------------------------------------------------------------
1 | package bullet.linearMath
2 |
3 | class ConvexHullComputer {
4 |
5 | class Edge {
6 |
7 | private var next = 0
8 | private var reverse = 0
9 | private var targetVertex = 0
10 |
11 | val sourceVertex: Nothing get() = TODO()//(this + reverse)->targetVertex
12 |
13 | // val targetVertex() const
14 | // {
15 | // return targetVertex;
16 | // }
17 | //
18 | // const Edge* getNextEdgeOfVertex() const // clockwise list of all edges of a vertex
19 | // {
20 | // return this + next;
21 | // }
22 | //
23 | // const Edge* getNextEdgeOfFace() const // counter-clockwise list of all edges of a face
24 | // {
25 | // return (this + reverse)->getNextEdgeOfVertex();
26 | // }
27 | //
28 | // const Edge* getReverseEdge() const
29 | // {
30 | // return this + reverse;
31 | // }
32 | }
33 |
34 | /** Vertices of the output hull */
35 | val vertices = ArrayList()
36 |
37 | /** Edges of the output hull */
38 | val edges = ArrayList()
39 |
40 | /** Faces of the convex hull. Each entry is an index into the "edges" array pointing to an edge of the face.
41 | * Faces are planar n-gons */
42 | val faces = ArrayList()
43 |
44 | /* Compute convex hull of "count" vertices stored in "coords". "stride" is the difference in bytes between the
45 | addresses of consecutive vertices. If "shrink" is positive, the convex hull is shrunken by that amount
46 | (each face is moved by "shrink" length units towards the center along its normal).
47 | If "shrinkClamp" is positive, "shrink" is clamped to not exceed "shrinkClamp * innerRadius", where "innerRadius"
48 | is the minimum distance of a face to the center of the convex hull.
49 |
50 | The returned value is the amount by which the hull has been shrunken. If it is negative, the amount was so large
51 | that the resulting convex hull is empty.
52 |
53 | The output convex hull can be found in the member variables "vertices", "edges", "faces". */
54 | fun compute(coords: FloatArray, stride: Int, count: Int, shrink: Float, shrinkClamp: Float): Float {
55 |
56 | if (count <= 0) {
57 | vertices.clear()
58 | edges.clear()
59 | faces.clear()
60 | return 0f
61 | }
62 | TODO()
63 | // val hull = ConvexHullInternal()
64 | // hull.compute(coords, doubleCoords, stride, count)
65 | //
66 | // btScalar shift = 0
67 | // if ((shrink > 0) && ((shift = hull.shrink(shrink, shrinkClamp)) < 0)) {
68 | // vertices.clear()
69 | // edges.clear()
70 | // faces.clear()
71 | // return shift
72 | // }
73 | //
74 | // vertices.resize(0)
75 | // edges.resize(0)
76 | // faces.resize(0)
77 | //
78 | // btAlignedObjectArray < btConvexHullInternal::Vertex * > oldVertices
79 | // getVertexCopy(hull.vertexList, oldVertices)
80 | // int copied = 0
81 | // while (copied < oldVertices.size()) {
82 | // btConvexHullInternal::Vertex * v = oldVertices[copied]
83 | // vertices.push_back(hull.getCoordinates(v))
84 | // btConvexHullInternal::Edge * firstEdge = v->edges
85 | // if (firstEdge) {
86 | // int firstCopy = - 1
87 | // int prevCopy = - 1
88 | // btConvexHullInternal::Edge * e = firstEdge
89 | // do {
90 | // if (e->copy < 0)
91 | // {
92 | // int s = edges . size ()
93 | // edges.push_back(Edge())
94 | // edges.push_back(Edge())
95 | // Edge * c = & edges [s]
96 | // Edge * r = & edges [s + 1]
97 | // e->copy = s
98 | // e->reverse->copy = s+1
99 | // c->reverse = 1
100 | // r->reverse = -1
101 | // c->targetVertex = getVertexCopy(e->target, oldVertices)
102 | // r->targetVertex = copied
103 | // #ifdef DEBUG_CONVEX_HULL
104 | // printf(" CREATE: Vertex *%d has edge to *%d\n", copied, c->getTargetVertex())
105 | // #endif
106 | // }
107 | // if (prevCopy >= 0) {
108 | // edges[e->copy].next = prevCopy-e->copy
109 | // } else {
110 | // firstCopy = e->copy
111 | // }
112 | // prevCopy = e->copy
113 | // e = e->next
114 | // } while (e != firstEdge)
115 | // edges[firstCopy].next = prevCopy - firstCopy
116 | // }
117 | // copied++
118 | // }
119 | //
120 | // for (int i = 0; i < copied; i++)
121 | // {
122 | // btConvexHullInternal::Vertex * v = oldVertices[i]
123 | // btConvexHullInternal::Edge * firstEdge = v->edges
124 | // if (firstEdge) {
125 | // btConvexHullInternal::Edge * e = firstEdge
126 | // do {
127 | // if (e->copy >= 0)
128 | // {
129 | // #ifdef DEBUG_CONVEX_HULL
130 | // printf("Vertex *%d has edge to *%d\n", i, edges[e->copy].getTargetVertex())
131 | // #endif
132 | // faces.push_back(e->copy)
133 | // btConvexHullInternal::Edge * f = e
134 | // do {
135 | // #ifdef DEBUG_CONVEX_HULL
136 | // printf(" Face *%d\n", edges[f->copy].getTargetVertex())
137 | // #endif
138 | // f->copy = -1
139 | // f = f->reverse->prev
140 | // } while (f != e)
141 | // }
142 | // e = e->next
143 | // } while (e != firstEdge)
144 | // }
145 | // }
146 | //
147 | // return shift
148 | }
149 |
150 | // / same as above, but double precision
151 | // btScalar compute(const double* coords, int stride, int count, btScalar shrink, btScalar shrinkClamp)
152 | // {
153 | // return compute(coords, true, stride, count, shrink, shrinkClamp);
154 | // }
155 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/linearMath/ConvexHullInternal.kt:
--------------------------------------------------------------------------------
1 | package bullet.linearMath
2 |
3 | class ConvexHullInternal {
4 |
5 | // btVector3 scaling;
6 | // btVector3 center;
7 | // Pool vertexPool;
8 | // Pool edgePool;
9 | // Pool facePool;
10 | // btAlignedObjectArray originalVertices;
11 | // int mergeStamp;
12 | // int minAxis;
13 | // int medAxis;
14 | // int maxAxis;
15 | // int usedEdgePairs;
16 | // int maxUsedEdgePairs;
17 | //
18 | // static Orientation getOrientation(const Edge* prev, const Edge* next, const Point32& s, const Point32& t);
19 | // Edge* findMaxAngle(bool ccw, const Vertex* start, const Point32& s, const Point64& rxs, const Point64& sxrxs, Rational64& minCot);
20 | // void findEdgeForCoplanarFaces(Vertex* c0, Vertex* c1, Edge*& e0, Edge*& e1, Vertex* stop0, Vertex* stop1);
21 | //
22 | // Edge* newEdgePair(Vertex* from, Vertex* to);
23 | //
24 | // void removeEdgePair(Edge* edge)
25 | // {
26 | // Edge* n = edge->next;
27 | // Edge* r = edge->reverse;
28 | //
29 | // btAssert(edge->target && r->target);
30 | //
31 | // if (n != edge)
32 | // {
33 | // n->prev = edge->prev;
34 | // edge->prev->next = n;
35 | // r->target->edges = n;
36 | // }
37 | // else
38 | // {
39 | // r->target->edges = NULL;
40 | // }
41 | //
42 | // n = r->next;
43 | //
44 | // if (n != r)
45 | // {
46 | // n->prev = r->prev;
47 | // r->prev->next = n;
48 | // edge->target->edges = n;
49 | // }
50 | // else
51 | // {
52 | // edge->target->edges = NULL;
53 | // }
54 | //
55 | // edgePool.freeObject(edge);
56 | // edgePool.freeObject(r);
57 | // usedEdgePairs--;
58 | // }
59 | //
60 | // void computeInternal(int start, int end, IntermediateHull& result);
61 | //
62 | // bool mergeProjection(IntermediateHull& h0, IntermediateHull& h1, Vertex*& c0, Vertex*& c1);
63 | //
64 | // void merge(IntermediateHull& h0, IntermediateHull& h1);
65 | //
66 | // btVector3 toBtVector(const Point32& v);
67 | //
68 | // btVector3 getBtNormal(Face* face);
69 | //
70 | // bool shiftFace(Face* face, btScalar amount, btAlignedObjectArray stack);
71 | //
72 | // public:
73 | // Vertex* vertexList;
74 |
75 | fun compute(coords: List, stride: String, count: Int) {
76 |
77 | val min = Vec3(1e30f)
78 | val max = Vec3(-1e30f)
79 | // const char * ptr =(const char *) coords;
80 | TODO()
81 | // for (i in 0 until count) {
82 | // val p = Vec3 (v[0], v[1], v[2]);
83 | // ptr += stride;
84 | // min.setMin(p);
85 | // max.setMax(p);
86 | // }
87 | //
88 | // btVector3 s = max -min;
89 | // maxAxis = s.maxAxis();
90 | // minAxis = s.minAxis();
91 | // if (minAxis == maxAxis) {
92 | // minAxis = (maxAxis + 1) % 3;
93 | // }
94 | // medAxis = 3 - maxAxis - minAxis;
95 | //
96 | // s /= btScalar(10216);
97 | // if (((medAxis + 1) % 3) != maxAxis) {
98 | // s *= -1;
99 | // }
100 | // scaling = s;
101 | //
102 | // if (s[0] != 0) {
103 | // s[0] = btScalar(1) / s[0];
104 | // }
105 | // if (s[1] != 0) {
106 | // s[1] = btScalar(1) / s[1];
107 | // }
108 | // if (s[2] != 0) {
109 | // s[2] = btScalar(1) / s[2];
110 | // }
111 | //
112 | // center = (min + max) * btScalar(0.5);
113 | //
114 | // btAlignedObjectArray points;
115 | // points.resize(count);
116 | // ptr = (const char *) coords;
117 | // if (doubleCoords) {
118 | // for (int i = 0; i < count; i++)
119 | // {
120 | // const double * v =(const double *) ptr;
121 | // btVector3 p ((btScalar) v [0], (btScalar) v[1], (btScalar) v[2]);
122 | // ptr += stride;
123 | // p = (p - center) * s;
124 | // points[i].x = (int32_t) p [medAxis];
125 | // points[i].y = (int32_t) p [maxAxis];
126 | // points[i].z = (int32_t) p [minAxis];
127 | // points[i].index = i;
128 | // }
129 | // } else {
130 | // for (int i = 0; i < count; i++)
131 | // {
132 | // const float * v =(const float *) ptr;
133 | // btVector3 p (v[0], v[1], v[2]);
134 | // ptr += stride;
135 | // p = (p - center) * s;
136 | // points[i].x = (int32_t) p [medAxis];
137 | // points[i].y = (int32_t) p [maxAxis];
138 | // points[i].z = (int32_t) p [minAxis];
139 | // points[i].index = i;
140 | // }
141 | // }
142 | // points.quickSort(pointCmp());
143 | //
144 | // vertexPool.reset();
145 | // vertexPool.setArraySize(count);
146 | // originalVertices.resize(count);
147 | // for (int i = 0; i < count; i++)
148 | // {
149 | // Vertex * v = vertexPool.newObject();
150 | // v->edges = NULL;
151 | // v->point = points[i];
152 | // v->copy = -1;
153 | // originalVertices[i] = v;
154 | // }
155 | //
156 | // points.clear();
157 | //
158 | // edgePool.reset();
159 | // edgePool.setArraySize(6 * count);
160 | //
161 | // usedEdgePairs = 0;
162 | // maxUsedEdgePairs = 0;
163 | //
164 | // mergeStamp = -3;
165 | //
166 | // IntermediateHull hull;
167 | // computeInternal(0, count, hull);
168 | // vertexList = hull.minXy;
169 | }
170 |
171 | // btVector3 getCoordinates(const Vertex* v);
172 | //
173 | // btScalar shrink(btScalar amount, btScalar clampAmount);
174 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/linearMath/DebugDraw.kt:
--------------------------------------------------------------------------------
1 | package bullet.linearMath
2 |
3 | class DebugDraw {
4 |
5 | var activeObject = Vec3(1f, 1f, 1f)
6 | var deactivatedObject = Vec3(0f, 1f, 0f)
7 | var wantsDeactivationObject = Vec3(0f, 1f, 1f)
8 | var disabledDeactivationObject = Vec3(1f, 0f, 0f)
9 | var disabledSimulationObject = Vec3(1f, 1f, 0f)
10 | var aabb = Vec3(1f, 0f, 0f)
11 | var contactPoint = Vec3(1f, 1f, 0f)
12 |
13 | enum class Modes(val i: Int) {
14 | NoDebug(0),
15 | DrawWireframe(1),
16 | DrawAabb(2),
17 | DrawFeaturesText(4),
18 | DrawContactPoints(8),
19 | NoDeactivation(16),
20 | NoHelpText(32),
21 | DrawText(64),
22 | ProfileTimings(128),
23 | EnableSatComparison(256),
24 | DisableBulletLCP(512),
25 | EnableCCD(1024),
26 | DrawConstraints(1 shl 11),
27 | DrawConstraintLimits(1 shl 12),
28 | FastWireframe(1 shl 13),
29 | DrawNormals(1 shl 14),
30 | DrawFrames(1 shl 15),
31 | MAX_DEBUG_DRAW_MODE(DrawFrames.i + 1)
32 | }
33 |
34 | fun drawSphere(c: Vec3, fl: Float, btVector3: Any) {}
35 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/linearMath/DefaultMotionState.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.linearMath
17 |
18 | /** The DefaultMotionState provides a common implementation to synchronize world transforms with offsets. */
19 | class DefaultMotionState(val startWorldTrans: Transform = Transform.identity,
20 | val centerOfMassOffset: Transform = Transform.identity) : MotionState {
21 |
22 | val graphicsWorldTrans = Transform(startWorldTrans)
23 | var userPointer: Any? = null
24 |
25 | /** synchronizes world transform from user to physics */
26 | override fun getWorldTransform(worldTransform: Transform ) = worldTransform put graphicsWorldTrans * centerOfMassOffset.inverse()
27 |
28 | /** synchronizes world transform from physics to user
29 | * Bullet only calls the update of worldtransform for active objects */
30 | override fun setWorldTransform(worldTransform: Transform) = graphicsWorldTrans put worldTransform * centerOfMassOffset // TODO check
31 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/linearMath/HashMap.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.linearMath
17 |
18 | import bullet.i
19 |
20 | /** very basic hashable string implementation, compatible with HashMap */
21 | class HashString(val string: String) {
22 |
23 | val hash = run {
24 | /* Fowler / Noll / Vo (FNV) Hash */
25 | var hash = initialFNV
26 | for (i in 0 until string.length) {
27 | hash = hash xor (string[i].i and 0xff) /* xor the low 8 bits */
28 | hash *= fnvMultiple /* multiply by the magic number */
29 | }
30 | hash
31 | }
32 |
33 | override fun equals(other: Any?) = other is HashString && string == other.string
34 | override fun hashCode() = 31 * string.hashCode() + hash
35 |
36 | companion object {
37 | /* magic numbers from http://www.isthe.com/chongo/tech/comp/fnv/ */
38 | val initialFNV = 2166136261.i
39 | val fnvMultiple = 16777619
40 | }
41 | }
42 |
43 | val HASH_NULL = 0xffffffff.i
44 |
45 | data class HashInt(var uid: Int = 0) {
46 | //to our success
47 | val hash: Int
48 | get() {
49 | var key = uid
50 | // Thomas Wang's hash
51 | key += (key shl 15).inv()
52 | key = key xor (key ushr 10)
53 | key += key shl 3
54 | key = key xor (key ushr 6)
55 | key += (key shl 11).inv()
56 | return key xor (key ushr 16)
57 | }
58 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/linearMath/MinMax.kt:
--------------------------------------------------------------------------------
1 | package bullet.linearMath
2 |
3 | infix fun Float.min(b: Float) = if (this < b) this else b
4 | infix fun Float.max(b: Float) = if (this > b) this else b
5 |
6 | fun clamped(a: Float, lb: Float, ub: Float) = if (a < lb) lb else if (ub < a) ub else a
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/linearMath/MotionState.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Bullet Continuous Collision Detection and Physics Library
3 | Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
4 |
5 | This software is provided 'as-is', without any express or implied warranty.
6 | In no event will the authors be held liable for any damages arising from the use of this software.
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it freely,
9 | subject to the following restrictions:
10 |
11 | 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.
12 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 | 3. This notice may not be removed or altered from any source distribution.
14 | */
15 |
16 | package bullet.linearMath
17 |
18 | /** The MotionState interface class allows the dynamics world to synchronize and interpolate
19 | * the updated world transforms with graphics
20 | * For optimizations, potentially only moving objects get synchronized (using setWorldPosition/setWorldOrientation) */
21 | interface MotionState {
22 | /** Bullet only calls the update of worldtransform for active objects */
23 | fun setWorldTransform(worldTransform: Transform)
24 | fun getWorldTransform(worldTransform: Transform)
25 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/linearMath/Scalar.kt:
--------------------------------------------------------------------------------
1 | package bullet.linearMath
2 |
3 | import bullet.EPSILON
4 | import kotlin.math.abs
5 | import kotlin.math.sqrt
6 |
7 | /* SVN $Revision$ on $Date$ from http://bullet.googlecode.com*/
8 | val BULLET_VERSION = 287
9 |
10 |
11 | val LARGE_FLOAT = 1e18f
12 |
13 |
14 | val PI = kotlin.math.PI.toFloat()
15 | val PI2 = PI * 2
16 | val HALF_PI = PI * 0.5f
17 | val SIMDSQRT12 = 0.7071067811865475244008443621048490f
18 | /* reciprocal square root */
19 | fun recipSqrt(x: Float) = 1f / sqrt(x)
20 |
21 | fun recip(x: Float) = 1f / x
22 |
23 | fun fsels(a: Float, b: Float, c: Float) = if (a >= 0) b else c
24 |
25 |
26 | /** @returns normalized value in range [-SIMD_PI, SIMD_PI] */
27 | fun normalizeAngle(angleInRadians: Float): Float {
28 | val angleInRadians = angleInRadians % PI2
29 | return when {
30 | angleInRadians < -PI -> angleInRadians + PI2
31 | angleInRadians > PI -> angleInRadians - PI2
32 | else -> angleInRadians
33 | }
34 | }
35 |
36 | /** rudimentary class to provide type info */
37 | open class TypedObject(val objectType: Int)
38 |
39 | val Float.fuzzyZero get() = abs(this) < Float.EPSILON
40 |
41 | fun equal(a: Float, eps: Float) = a <= eps && !(a < -eps)
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/linearMath/Transform.kt:
--------------------------------------------------------------------------------
1 | package bullet.linearMath
2 |
3 | /** The Transform class supports rigid transforms with only translation and rotation and no scaling/shear.
4 | * It can be used in combination with btVector3, btQuaternion and btMatrix3x3 linear algebra classes */
5 | class Transform {
6 |
7 | /** Storage for the rotation */
8 | var basis = Mat3()
9 | /** Storage for the translation */
10 | var origin = Vec3()
11 |
12 | constructor()
13 |
14 | /** @constructor from btQuaternion (optional btVector3 )
15 | * @param q Rotation from quaternion
16 | * @param c Translation from Vector (default 0,0,0) */
17 | constructor(q: Quat, c: Vec3 = Vec3()) {
18 | basis = Mat3(q)
19 | origin put c
20 | }
21 |
22 | /** @constructor from btMatrix3x3 (optional btVector3)
23 | * @param b Rotation from Matrix
24 | * @param c Translation from Vector default (0,0,0)*/
25 | constructor(b: Mat3, c: Vec3 = Vec3()) {
26 | basis put b
27 | origin put c
28 | }
29 |
30 | /** @constructor Copy constructor */
31 | constructor(other: Transform) {
32 | basis put other.basis
33 | origin put other.origin
34 | }
35 |
36 | /** Set the current transform as the value of the product of two transforms
37 | * @param t1 Transform 1
38 | * @param t2 Transform 2
39 | * This = Transform1 * Transform2 */
40 | fun mult(t1: Transform, t2: Transform) {
41 | basis = t1.basis * t2.basis
42 | origin = t1 * t2.origin
43 | }
44 |
45 | /* void multInverseLeft(const btTransform& t1, const btTransform& t2) {
46 | btVector3 v = t2.m_origin - t1.m_origin;
47 | m_basis = btMultTransposeLeft(t1.m_basis, t2.m_basis);
48 | m_origin = v * t1.m_basis;
49 | }
50 | */
51 |
52 | /** @return the transform of the vector */
53 | operator fun times(x: Vec3) = x.dot3(basis[0], basis[1], basis[2]) + origin
54 |
55 | operator fun invoke(x: Vec3) = x.dot3(basis[0], basis[1], basis[2]) + origin
56 |
57 | /** @return the transform of the btQuaternion */
58 | operator fun times(q: Quat) = getRotation() * q
59 |
60 | /** @return a quaternion representing the rotation */
61 | fun getRotation(): Quat {
62 | val q = Quat()
63 | basis.getRotation(q)
64 | return q
65 | }
66 |
67 | /** Set from an array
68 | * @param m A pointer to a 16 element array (12 rotation(row major padded on the right by 1), and 3 translation */
69 | fun setFromOpenGLMatrix(m: FloatArray) {
70 | basis.setFromOpenGLSubMatrix(m)
71 | origin.put(m[12], m[13], m[14])
72 | }
73 |
74 | /** Fill an array representation
75 | * @param m A pointer to a 16 element array (12 rotation(row major padded on the right by 1), and 3 translation */
76 | fun getOpenGLMatrix(m: FloatArray) {
77 | basis.getOpenGLSubMatrix(m)
78 | m[12] = origin.x
79 | m[13] = origin.y
80 | m[14] = origin.z
81 | m[15] = 1f
82 | }
83 |
84 | infix fun invXform(inVec: Vec3) = basis.transpose() * (inVec - origin)
85 |
86 | /** Set the rotational element by Quat */
87 | infix fun setRotation(q: Quat) = basis.setRotation(q)
88 |
89 | /** Set this transformation to the identity */
90 | fun setIdentity() {
91 | basis.setIdentity()
92 | origin put 0f
93 | }
94 |
95 | /** Multiply this Transform by another(this = this * another)
96 | * @param t The other transform */
97 | operator fun times(t: Transform) = Transform(basis * t.basis, this(t.origin))
98 |
99 | /** Return the inverse of this transform */
100 | fun inverse() = basis.transpose().let { Transform(it, it * -origin) }
101 |
102 | /** Return the inverse of this transform times the other transform
103 | * @param t The other transform
104 | * return this.inverse() * the other */
105 | infix fun inverseTimes(t: Transform): Transform {
106 | val v = t.origin - origin
107 | return Transform(basis transposeTimes t.basis, v * basis)
108 | }
109 |
110 | infix fun put(other: Transform) {
111 | basis put other.basis
112 | origin put other.origin
113 | }
114 |
115 | override fun equals(other: Any?) = other is Transform && basis == other.basis && origin == other.origin
116 | override fun hashCode() = 31 * basis.hashCode() + origin.hashCode()
117 |
118 | companion object {
119 | /**@brief Return an identity transform */
120 | val identity get() = Transform(Mat3.identity)
121 | }
122 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/linearMath/Vec4.kt:
--------------------------------------------------------------------------------
1 | package bullet.linearMath
2 |
3 | import kotlin.math.abs
4 |
5 | // TODO move same place an Bullet
6 | class Vec4 : Vec3 {
7 |
8 | constructor() : super()
9 |
10 | constructor(x: Float, y: Float, z: Float, w: Float) : super(x, y, z) {
11 | this.w = w
12 | }
13 |
14 | fun absolute4() = Vec4(abs(x), abs(y), abs(z), abs(w))
15 |
16 | fun maxAxis4(): Int {
17 | var maxIndex = -1
18 | var maxVal = -LARGE_FLOAT
19 | if (x > maxVal) {
20 | maxIndex = 0
21 | maxVal = x
22 | }
23 | if (y > maxVal) {
24 | maxIndex = 1
25 | maxVal = y
26 | }
27 | if (z > maxVal) {
28 | maxIndex = 2
29 | maxVal = z
30 | }
31 | if (w > maxVal) maxIndex = 3
32 | return maxIndex
33 | }
34 |
35 | fun minAxis4(): Int {
36 | var minIndex = -1
37 | var minVal = LARGE_FLOAT
38 | if (x < minVal) {
39 | minIndex = 0
40 | minVal = x
41 | }
42 | if (y < minVal) {
43 | minIndex = 1
44 | minVal = y
45 | }
46 | if (z < minVal) {
47 | minIndex = 2
48 | minVal = z
49 | }
50 | if (w < minVal) minIndex = 3
51 | return minIndex
52 | }
53 |
54 | fun closestAxis4() = absolute4().maxAxis4()
55 |
56 | fun put(x: Float, y: Float, z: Float, w: Float) {
57 | this.x = x
58 | this.y = y
59 | this.z = z
60 | this.w = w
61 | }
62 | }
--------------------------------------------------------------------------------
/src/main/kotlin/bullet/linearMath/threads.kt:
--------------------------------------------------------------------------------
1 | package bullet.linearMath
2 |
3 | /** SpinMutex -- lightweight spin-mutex implemented with atomic ops, never puts a thread to sleep because it is designed
4 | * to be used with a task scheduler which has one thread per core and the threads don't sleep until they run out of
5 | * tasks. Not good for general purpose use. */
6 | class SpinMutex{
7 | var lock = 0
8 |
9 | // void lock();
10 | // void unlock();
11 | // bool tryLock();
12 | }
--------------------------------------------------------------------------------
/src/test/kotlin/bullet/collision/Collision.kt:
--------------------------------------------------------------------------------
1 | package bullet.collision
2 |
3 | import bullet.f
4 | import bullet.linearMath.Vec3
5 | import bullet.linearMath.times
6 | import io.kotlintest.matchers.shouldBe
7 | import io.kotlintest.specs.StringSpec
8 | import kotlin.math.abs
9 | import bullet.collision.Collision.SphereSphereTestMethod as SSTM
10 |
11 | class Collision : StringSpec() {
12 |
13 | enum class SphereSphereTestMethod { ANALYTIC, GJKEPA, GJKEPA_RADIUS_NOT_FULL_MARGIN, GJKMPR }
14 |
15 | init {
16 |
17 | "GjkMPR sphere sphere distance" {
18 | testSphereSphereDistance(SSTM.GJKMPR, 0.0001f)
19 | }
20 | "GjkEpa sphere sphere distance" {
21 | testSphereSphereDistance(SSTM.GJKEPA, 0.00001f)
22 | }
23 | "GjkEpa sphere sphere radius not full margin distance)" {
24 | testSphereSphereDistance(SSTM.GJKEPA_RADIUS_NOT_FULL_MARGIN, 0.1f)
25 | }
26 | "Analytic sphere sphere distance" {
27 | testSphereSphereDistance(SSTM.ANALYTIC, 0.00001f)
28 | }
29 | }
30 |
31 | fun testSphereSphereDistance(method: SSTM, absError: Float) {
32 |
33 | run {
34 | val ssd = SphereSphereCollisionDescription()
35 | ssd.sphereTransformA.setIdentity()
36 | ssd.sphereTransformB.setIdentity()
37 | val distInfo = DistanceInfo()
38 | val result = computeSphereSphereCollision(ssd, distInfo)
39 | result shouldBe 0
40 | distInfo.distance shouldBe 0f
41 | }
42 |
43 | for (rb in 1..4)
44 | for (z in -5..4)
45 | for (j in 1..4)
46 | for (i in -5..4)
47 | if (i != z) { //skip co-centric spheres for now (todo(erwincoumans) fix this)
48 | val ssd = SphereSphereCollisionDescription().apply {
49 | sphereTransformA.setIdentity()
50 | sphereTransformA.origin = Vec3(0f, i.f, 0f)
51 | sphereTransformB.setIdentity()
52 | sphereTransformB.origin = Vec3(0f, z.f, 0f)
53 | radiusA = j.f
54 | radiusB = rb.f * 0.1f
55 | }
56 | val distInfo = DistanceInfo()
57 | val result = when (method) {
58 | SSTM.ANALYTIC -> computeSphereSphereCollision(ssd, distInfo)
59 | else -> computeGjkEpaSphereSphereCollision(ssd, distInfo, method)
60 | }
61 | // int result = btComputeSphereSphereCollision(ssd,&distInfo);
62 | result shouldBe 0
63 | val distance = abs((i - z).f) - j.f - ssd.radiusB
64 | assert(distInfo.distance in distance - absError..distance + absError) // TODO plusOrMinus kotlinTest
65 | val computedA = distInfo.pointOnB + distInfo.distance * distInfo.normalBtoA
66 | val p = distInfo.pointOnA
67 | assert(computedA.x in p.x - absError..p.x + absError)
68 | assert(computedA.y in p.y - absError..p.y + absError)
69 | assert(computedA.z in p.z - absError..p.z + absError)
70 | }
71 | }
72 | }
--------------------------------------------------------------------------------
/src/test/kotlin/bullet/collision/helper.kt:
--------------------------------------------------------------------------------
1 | package bullet.collision
2 |
3 | import bullet.ConvexTemplate
4 | import bullet.DistanceTemplate
5 | import bullet.EPSILON
6 | import bullet.collision.collisionShapes.ConvexShape
7 | import bullet.collision.collisionShapes.MultiSphereShape
8 | import bullet.collision.collisionShapes.SphereShape
9 | import bullet.collision.narrowPhaseCollision.*
10 | import bullet.linearMath.Transform
11 | import bullet.linearMath.Vec3
12 | import bullet.linearMath.times
13 | import bullet.collision.Collision.SphereSphereTestMethod as SSTM
14 |
15 | class SphereSphereCollisionDescription {
16 |
17 | val sphereTransformA = Transform()
18 | val sphereTransformB = Transform()
19 | var radiusA = 0f
20 | var radiusB = 0f
21 | }
22 |
23 | class DistanceInfo : DistanceTemplate()
24 |
25 | /** compute the distance between two spheres, where the distance is zero when the spheres are touching
26 | * positive distance means the spheres are separate and negative distance means penetration
27 | * point A and pointB are witness points, and normalOnB points from sphere B to sphere A */
28 | fun computeSphereSphereCollision(input: SphereSphereCollisionDescription, distInfo: DistanceInfo): Int {
29 |
30 | val diff = input.sphereTransformA.origin - input.sphereTransformB.origin
31 | val len = diff.length()
32 | val radiusA = input.radiusA
33 | val radiusB = input.radiusB
34 |
35 | ///distance (negative means penetration)
36 | val dist = len - (radiusA + radiusB)
37 | var normalOnSurfaceB = Vec3(1f, 0f, 0f)
38 | if (len > Float.EPSILON)
39 | normalOnSurfaceB = diff / len
40 | with(distInfo) {
41 | distance = dist
42 | normalBtoA = normalOnSurfaceB
43 | pointOnA = input.sphereTransformA.origin - input.radiusA * normalOnSurfaceB
44 | pointOnB = input.sphereTransformB.origin + input.radiusB * normalOnSurfaceB
45 | }
46 | return 0//sphere-sphere cannot fail
47 | }
48 |
49 | fun computeGjkEpaSphereSphereCollision(input: SphereSphereCollisionDescription, distInfo: DistanceInfo,
50 | method: Collision.SphereSphereTestMethod): Int {
51 | // for spheres it is best to use a 'point' and set the margin to the radius (which is what btSphereShape does)
52 | val singleSphereA = SphereShape(input.radiusA)
53 | val singleSphereB = SphereShape(input.radiusB)
54 | val org = Vec3()
55 | val radA = input.radiusA
56 | val radB = input.radiusB
57 |
58 | val a = ConvexWrap()
59 | val b = ConvexWrap()
60 | a.worldTrans = input.sphereTransformA
61 | b.worldTrans = input.sphereTransformB
62 |
63 | val multiSphereA = MultiSphereShape(org, radA, 1)
64 | val multiSphereB = MultiSphereShape(org, radB, 1)
65 |
66 | val colDesc = GjkCollisionDescription()
67 | when (method) {
68 | SSTM.GJKEPA_RADIUS_NOT_FULL_MARGIN -> {
69 | a.convex = multiSphereA
70 | b.convex = multiSphereB
71 | }
72 | else -> {
73 | a.convex = singleSphereA
74 | b.convex = singleSphereB
75 | }
76 | }
77 |
78 | val simplexSolver = VoronoiSimplexSolver()
79 | simplexSolver.reset()
80 |
81 | ///todo(erwincoumans): improve convex-convex quality and performance
82 | ///also compare with https://code.google.com/p/bullet/source/browse/branches/PhysicsEffects/src/base_level/collision/pfx_gjk_solver.cpp
83 | return when (method) {
84 | SSTM.GJKEPA_RADIUS_NOT_FULL_MARGIN, SSTM.GJKEPA -> computeGjkEpaPenetration(a, b, colDesc, simplexSolver, distInfo)
85 | SSTM.GJKMPR -> {
86 | val res = computeGjkDistance(a, b, colDesc, distInfo)
87 | if (res == 0)
88 | // printf("use GJK results in distance %f\n",distInfo->m_distance);
89 | res
90 | else
91 | Mpr.computeMprPenetration(a, b, Mpr.CollisionDescription(), distInfo)
92 | }
93 | else -> throw Error()
94 | }
95 | }
96 |
97 | class ConvexWrap : ConvexTemplate {
98 |
99 | lateinit var convex: ConvexShape
100 | override lateinit var worldTrans: Transform
101 |
102 | override var margin = 0f
103 | get() = convex.margin
104 | override val objectCenterInWorld get() = worldTrans.origin
105 | override fun getLocalSupportWithMargin(dir: Vec3) = convex.localGetSupportingVertex(dir)
106 | override fun getLocalSupportWithoutMargin(dir: Vec3) = convex.localGetSupportingVertexWithoutMargin(dir)
107 | }
--------------------------------------------------------------------------------