├── .gitignore ├── .idea ├── bullet.iml ├── gradle.xml ├── libraries │ ├── Gradle__com_google_guava_guava_20_0.xml │ ├── Gradle__io_kotlintest_kotlintest_2_0_7.xml │ ├── Gradle__junit_junit_4_12.xml │ ├── Gradle__net_bytebuddy_byte_buddy_1_6_5.xml │ ├── Gradle__net_bytebuddy_byte_buddy_agent_1_6_5.xml │ ├── Gradle__org_hamcrest_hamcrest_core_1_3.xml │ ├── Gradle__org_javassist_javassist_3_21_0_GA.xml │ ├── Gradle__org_jetbrains_annotations_13_0.xml │ ├── Gradle__org_jetbrains_kotlin_kotlin_reflect_1_1_51.xml │ ├── Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_2_30_eap_47.xml │ ├── Gradle__org_mockito_mockito_core_2_7_11.xml │ ├── Gradle__org_objenesis_objenesis_2_5.xml │ └── Gradle__org_reflections_reflections_0_9_11.xml ├── misc.xml ├── modules.xml ├── uiDesigner.xml └── vcs.xml ├── .travis.yml ├── LICENSE ├── README.md ├── build.gradle ├── bullet.iml ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src ├── main └── kotlin │ └── bullet │ ├── Template.kt │ ├── bullet.kt │ ├── collision │ ├── broadphaseCollision │ │ ├── BroadphaseInterface.kt │ │ ├── BroadphaseProxy.kt │ │ ├── CollistionAlgorithm.kt │ │ ├── DbvBroadphase.kt │ │ ├── Dbvt.kt │ │ ├── Dispatcher.kt │ │ ├── OverlappingPairCache.kt │ │ ├── OverlappingPairCallback.kt │ │ └── QuantizedBvh.kt │ ├── collisionDispatch │ │ ├── ActivatingCollisionAlgorithm.kt │ │ ├── BoxBoxCollisionAlgorithm.kt │ │ ├── BoxBoxDetector.kt │ │ ├── CollisionConfiguration.kt │ │ ├── CollisionCreateFunc.kt │ │ ├── CollisionDispatcher.kt │ │ ├── CollisionObject.kt │ │ ├── CollisionObjectWrapper.kt │ │ ├── CollisionWorld.kt │ │ ├── CompoundCollisionAlgorithm.kt │ │ ├── CompoundCompoundCollisionAlgorithm.kt │ │ ├── CompoundShape.kt │ │ ├── ConvexConcaveCollisionAlgorithm.kt │ │ ├── ConvexConvexAlgorithm.kt │ │ ├── ConvexPlaneCollisionAlgorithm.kt │ │ ├── DefaultCollisionConfiguration.kt │ │ ├── EmptyAlgorithm.kt │ │ ├── HashedSimplePairCache.kt │ │ ├── ManifoldResult.kt │ │ ├── SimulationIslandManager.kt │ │ ├── SphereSphereCollisionAlgorithm.kt │ │ ├── SphereTriangleCollisionAlgorithm.kt │ │ ├── SphereTriangleDetector.kt │ │ └── UnionFind.kt │ ├── collisionShapes │ │ ├── BoxShape.kt │ │ ├── BvhTriangleMeshShape.kt │ │ ├── CapsuleShape.kt │ │ ├── CollisionMargin.kt │ │ ├── CollisionShape.kt │ │ ├── CompoundShape.kt │ │ ├── ConcaveShape.kt │ │ ├── ConvexHullShape.kt │ │ ├── ConvexInternalAabbCachingShape.kt │ │ ├── ConvexInternalShape.kt │ │ ├── ConvexPointCloudShape.kt │ │ ├── ConvexPolyhedron.kt │ │ ├── ConvexShape.kt │ │ ├── CylinderShape.kt │ │ ├── MultiSphereShape.kt │ │ ├── OptimizedBvh.kt │ │ ├── PolyhedralConvexShape.kt │ │ ├── ScaledBvhTriangleMeshShape.kt │ │ ├── SphereShape.kt │ │ ├── StaticPlaneShape.kt │ │ ├── StridingMeshInterface.kt │ │ ├── TriangleCallback.kt │ │ ├── TriangleIndexVertexArray.kt │ │ ├── TriangleInfoMap.kt │ │ ├── TriangleMeshShape.kt │ │ └── TriangleShape.kt │ └── narrowPhaseCollision │ │ ├── ContinuousConvexCollision.kt │ │ ├── ConvexCast.kt │ │ ├── ConvexPenetrationDepthSolver.kt │ │ ├── DiscreteCollisionDetectorInterface.kt │ │ ├── GjkCollisionDescription.kt │ │ ├── GjkConvexCast.kt │ │ ├── GjkEpa2.kt │ │ ├── GjkEpa3.kt │ │ ├── GjkEpaPenetrationDepthSolver.kt │ │ ├── GjkPairDetector.kt │ │ ├── ManifoldPoint.kt │ │ ├── MinkowskiPenetrationDepthSolver.kt │ │ ├── MprPenetration.kt │ │ ├── PersistentManifold.kt │ │ ├── PointCollector.kt │ │ ├── PolyhedralContractClipping.kt │ │ ├── RaycastCallback.kt │ │ ├── SimplexSolverInterface.kt │ │ ├── SubSimplexConvexCast.kt │ │ ├── VoronoiSimplexSolver.kt │ │ └── computeGjkEpaPenetration.kt │ ├── dynamics │ ├── constraintSolver │ │ ├── ConstraintSolver.kt │ │ ├── ContactSolverInfo.kt │ │ ├── SequentialImpulseConstraintSolver.kt │ │ ├── SolverBody.kt │ │ ├── SolverConstraint.kt │ │ └── TypedConstraint.kt │ └── dynamics │ │ ├── ActionInterface.kt │ │ ├── DiscreteDynamicsWorld.kt │ │ ├── DynamicsWorld.kt │ │ └── RigidBody.kt │ └── linearMath │ ├── AabbUtil2.kt │ ├── AlignedObjectArray.kt │ ├── ConvexHullComputer.kt │ ├── ConvexHullInternal.kt │ ├── DebugDraw.kt │ ├── DefaultMotionState.kt │ ├── HashMap.kt │ ├── Mat3.kt │ ├── MinMax.kt │ ├── MotionState.kt │ ├── Quat.kt │ ├── Scalar.kt │ ├── Transform.kt │ ├── TransformUtil.kt │ ├── Vec3.kt │ ├── Vec4.kt │ └── threads.kt └── test └── kotlin └── bullet ├── HelloWord.kt └── collision ├── Collision.kt └── helper.kt /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Kotlin template 3 | # Compiled class file 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | #*.jar 15 | *.war 16 | *.ear 17 | *.zip 18 | *.tar.gz 19 | *.rar 20 | 21 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 22 | hs_err_pid* 23 | 24 | .gradle/ 25 | .idea/inspectionProfiles/ 26 | .idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_2_0_rc_39.xml 27 | .idea/workspace.xml 28 | build/ 29 | out/ 30 | -------------------------------------------------------------------------------- /.idea/bullet.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 19 | 22 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/libraries/Gradle__com_google_guava_guava_20_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/libraries/Gradle__io_kotlintest_kotlintest_2_0_7.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/libraries/Gradle__junit_junit_4_12.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/libraries/Gradle__net_bytebuddy_byte_buddy_1_6_5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/libraries/Gradle__net_bytebuddy_byte_buddy_agent_1_6_5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/libraries/Gradle__org_hamcrest_hamcrest_core_1_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/libraries/Gradle__org_javassist_javassist_3_21_0_GA.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/libraries/Gradle__org_jetbrains_annotations_13_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_reflect_1_1_51.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_2_30_eap_47.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/libraries/Gradle__org_mockito_mockito_core_2_7_11.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/libraries/Gradle__org_objenesis_objenesis_2_5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/libraries/Gradle__org_reflections_reflections_0_9_11.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The files in this repository are licensed under the zlib license, except for the files under 'Extras' and examples/ThirdPartyLibs. 2 | 3 | Bullet Continuous Collision Detection and Physics Library 4 | http://bulletphysics.org 5 | 6 | This software is provided 'as-is', without any express or implied warranty. 7 | In no event will the authors be held liable for any damages arising from the use of this software. 8 | Permission is granted to anyone to use this software for any purpose, 9 | including commercial applications, and to alter it and redistribute it freely, 10 | subject to the following restrictions: 11 | 12 | 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. 13 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 14 | 3. This notice may not be removed or altered from any source distribution. 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bullet 2 | 3 | [![Build Status](https://travis-ci.org/kotlin-graphics/bullet.svg?branch=master)](https://travis-ci.org/kotlin-graphics/bullet) 4 | [![license](https://img.shields.io/badge/License-MIT-orange.svg)](https://github.com/kotlin-graphics/bullet/blob/master/LICENSE) 5 | [![Release](https://jitpack.io/v/kotlin-graphics/bullet.svg)](https://jitpack.io/#kotlin-graphics/bullet) 6 | ![](https://reposs.herokuapp.com/?path=kotlin-graphics/bullet&color=yellow) 7 | [![Slack Status](http://slack.kotlinlang.org/badge.svg)](http://slack.kotlinlang.org/) 8 | 9 | Jvm port of [Bullet](https://github.com/bulletphysics/bullet3), by [Erwin Coumans](https://github.com/erwincoumans) 10 | 11 | Take a look at the [tests](https://github.com/kotlin-graphics/bullet/tree/master/src/test/kotlin/bullet/collision) to see what has been ported and tested to be working. 12 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'maven' 2 | apply plugin: 'kotlin' 3 | 4 | apply plugin: 'com.github.johnrengelman.shadow' 5 | 6 | buildscript { 7 | 8 | ext.kotlinVersion = '1.2.30-eap-47' 9 | 10 | repositories { 11 | jcenter() // shadow 12 | mavenCentral() 13 | maven { setUrl("https://dl.bintray.com/kotlin/kotlin-dev") } 14 | } 15 | dependencies { 16 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" 17 | classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.2' 18 | } 19 | } 20 | 21 | dependencies { 22 | compile "org.jetbrains.kotlin:kotlin-stdlib" 23 | testCompile 'io.kotlintest:kotlintest:2.0.7' 24 | } 25 | 26 | repositories { 27 | mavenCentral() 28 | jcenter() 29 | maven { setUrl("https://dl.bintray.com/kotlin/kotlin-dev") } 30 | maven { setUrl("https://jitpack.io") } 31 | } 32 | 33 | 34 | task sourcesJar(type: Jar, dependsOn: classes) { 35 | classifier = 'sources' 36 | from sourceSets.main.allSource 37 | } 38 | 39 | task javadocJar(type: Jar, dependsOn: javadoc) { 40 | classifier = 'javadoc' 41 | from javadoc.destinationDir 42 | } 43 | 44 | artifacts { 45 | archives sourcesJar 46 | archives javadocJar 47 | } -------------------------------------------------------------------------------- /bullet.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 19 | 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 | } --------------------------------------------------------------------------------