├── .gitattributes ├── .gitignore ├── .travis.yml ├── HEADER.txt ├── LICENSE.txt ├── README.md ├── build.gradle ├── bump.sh ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── pom.xml └── src ├── main └── java │ └── com │ └── flowpowered │ └── react │ ├── ReactDefaults.java │ ├── Utilities.java │ ├── body │ ├── Body.java │ ├── CollisionBody.java │ └── RigidBody.java │ ├── collision │ ├── BroadPhasePair.java │ ├── CollisionDetection.java │ ├── RayCaster.java │ ├── broadphase │ │ ├── BroadPhaseAlgorithm.java │ │ ├── NoBroadPhaseAlgorithm.java │ │ ├── PairManager.java │ │ └── SweepAndPruneAlgorithm.java │ ├── linkedphase │ │ └── LinkedPhase.java │ ├── narrowphase │ │ ├── EPA │ │ │ ├── EPAAlgorithm.java │ │ │ ├── EdgeEPA.java │ │ │ ├── TriangleEPA.java │ │ │ └── TrianglesStore.java │ │ ├── GJK │ │ │ ├── GJKAlgorithm.java │ │ │ └── Simplex.java │ │ ├── NarrowPhaseAlgorithm.java │ │ └── SphereVsSphereAlgorithm.java │ └── shape │ │ ├── AABB.java │ │ ├── BoxShape.java │ │ ├── CapsuleShape.java │ │ ├── CollisionShape.java │ │ ├── ConeShape.java │ │ ├── ConvexMeshShape.java │ │ ├── CylinderShape.java │ │ └── SphereShape.java │ ├── constraint │ ├── BallAndSocketJoint.java │ ├── ConstraintSolver.java │ ├── ContactPoint.java │ ├── FixedJoint.java │ ├── HingeJoint.java │ ├── Joint.java │ └── SliderJoint.java │ ├── engine │ ├── CollisionWorld.java │ ├── ContactManifold.java │ ├── ContactSolver.java │ ├── DynamicsWorld.java │ ├── EventListener.java │ ├── Impulse.java │ ├── Island.java │ ├── Material.java │ ├── OverlappingPair.java │ ├── Timer.java │ └── linked │ │ ├── LinkedDynamicsWorld.java │ │ └── LinkedWorldInfo.java │ └── math │ ├── Mathematics.java │ ├── Matrix2x2.java │ ├── Matrix3x3.java │ ├── Matrix4x4.java │ ├── Quaternion.java │ ├── Transform.java │ ├── Vector2.java │ ├── Vector3.java │ └── Vector4.java └── test └── java └── com └── flowpowered └── react ├── Dummies.java ├── DynamicsWorldTest.java ├── GJKAndEPAAlgorithmTest.java ├── PairManagerTest.java ├── SphereVsSphereAlgorithmTest.java └── SweepAndPruneAlgorithmTest.java /.gitattributes: -------------------------------------------------------------------------------- 1 | # Normalize as LF in the repository, OS native locally 2 | * text=auto 3 | *.java text 4 | 5 | # Binary files that should not be modified 6 | *.dat binary 7 | *.db binary 8 | *.gif binary 9 | *.icns binary 10 | *.ico binary 11 | *.jks binary 12 | *.jpg binary 13 | *.key binary 14 | *.png binary 15 | *.ttf binary 16 | *.wav binary 17 | JavaApplicationStub binary 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build # 2 | ######### 3 | MANIFEST.MF 4 | dependency-reduced-pom.xml 5 | 6 | # Compiled # 7 | ############ 8 | bin 9 | build 10 | dist 11 | lib 12 | out 13 | run 14 | target 15 | *.com 16 | *.class 17 | *.dll 18 | *.exe 19 | *.o 20 | *.so 21 | 22 | # Databases # 23 | ############# 24 | *.db 25 | *.sql 26 | *.sqlite 27 | 28 | # Packages # 29 | ############ 30 | *.7z 31 | *.dmg 32 | *.ear 33 | *.gz 34 | *.iso 35 | *.jar 36 | !/gradle/wrapper/gradle-wrapper.jar 37 | *.rar 38 | *.tar 39 | *.war 40 | *.zip 41 | 42 | # Repository # 43 | ############## 44 | .git 45 | 46 | # Logging # 47 | ########### 48 | /logs 49 | *.log 50 | 51 | # Misc # 52 | ######## 53 | *.bak 54 | *.tmp 55 | 56 | # System # 57 | ########## 58 | .DS_Store 59 | ehthumbs.db 60 | Thumbs.db 61 | 62 | # Project # 63 | ########### 64 | .buildpath 65 | .classpath 66 | .cproject 67 | .externalToolBuilders 68 | .gradle 69 | .idea 70 | .project 71 | .settings 72 | nbproject 73 | atlassian-ide-plugin.xml 74 | build.xml 75 | nb-configuration.xml 76 | *.iml 77 | *.ipr 78 | *.iws 79 | *.launch 80 | *.pydevproject 81 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Use new Travis-CI infrastructure 2 | sudo: false 3 | 4 | # Source language and JDK version to use 5 | language: java 6 | jdk: oraclejdk8 7 | 8 | # Use cached Maven dependencies 9 | cache: 10 | directories: 11 | - $HOME/.m2 12 | 13 | # Pre-install Maven dependencies 14 | install: mvn dependency:go-offline 15 | 16 | # Compile and test source 17 | script: mvn clean -DbuildNumber=$TRAVIS_BUILD_NUMBER -DciSystem=travis -Dcommit=${TRAVIS_COMMIT:0:7} 18 | 19 | # Fetch resources, run deployment goal/task, and generate Javadocs and reports 20 | after_success: 21 | # Get files for use with build, namely the custom Maven settings.xml and scripts 22 | - "git clone https://github.com/flow/travis-ci-resources.git $HOME/build/flow/travis" 23 | # DEVELOP: Check if commit is not a pull request, if repo is official, if branch is not master; then deploy artifacts 24 | - "[[ $TRAVIS_PULL_REQUEST == false ]] && [[ $TRAVIS_REPO_SLUG == flow/react ]] && [[ $TRAVIS_BRANCH == develop ]] && mvn javadoc:jar source:jar deploy --settings $HOME/build/flow/travis/settings.xml" 25 | # RELEASE: Check if commit is not a pull request, if repo is official, if branch is master; then run deployment script 26 | - "[[ $TRAVIS_PULL_REQUEST == false ]] && [[ $TRAVIS_REPO_SLUG == flow/react ]] && [[ $TRAVIS_BRANCH == master ]] && $HOME/build/flow/travis/deploy.sh && $HOME/build/flow/travis/gh-pages.sh" 27 | # Generate Javadocs and report for Coveralls.io 28 | - "mvn javadoc:javadoc cobertura:cobertura coveralls:report -DserviceJobId=$TRAVIS_JOB_ID" 29 | 30 | # RELEASE: Deploy JARs to GitHub Releases 31 | 32 | deploy: 33 | provider: releases 34 | api-key: $GITHUB_TOKEN 35 | file_glob: true 36 | file: target/react-*.jar 37 | skip_cleanup: true 38 | on: 39 | branch: master 40 | 41 | # Notification services 42 | notifications: 43 | # Disable build status email notifications, until the issue with forks is fixed 44 | email: false 45 | webhooks: 46 | # Send build information and status to Notifico 47 | - http://n.tkte.ch/h/2706/sBWzX8LRWtZPWo2EmAlFQzAM 48 | 49 | # Environmental system variables 50 | env: 51 | global: 52 | # Make the log output cleaner 53 | - TERM=dumb 54 | # Super secure, encrypted variables! Ssssh! 55 | - secure: "f9ktzIdIVbDJ6Ufp994qV3S05p/0o8MWu0VXFjy+zZDeAXJ8kpKspyDCRZc3rEXNknt4JZjbe/0azv0u/lzkc5Vkvj57ShaWrihh0owMAaU7kg+ot4hFrhPXXBIosOhU/2vx253WqMoFO8mPtQ/zet/DnY7IyCEp3ZnAF4Emc44=" 56 | - secure: "FUdwmQB3Xammty3HuixmHU6CeCrmkapcfSOAT4nI4ASmAyRnhmSgxYnQjM/5lCkltqQWOEnrDQezaPBWTq/y69vMOu6Wjp7kANV/GXFItRTHvTn53ty0lAf+tpaLAgaqY7h1qHb++RuTJ8TFbgab+4YFIfonO823bCYx1+AIKiA=" 57 | - secure: "R+cvcpDT+zRcevpz1hKW3vZVLCFzDgJyy6HzyzN7a0TdgxQeWZFnBil9okak6HqVOraUQ4ct4tO7Qd9WWzq0kz5zQNttcuez6e69HApjquEvhnnfVa8QcIMrKDQ6mE3UztuIfQ95ytmvoNPbGsFyw9fpVNrLGcn8k09DtBlQPw0=" 58 | - secure: "VN8Ou5EZjUz6RF2Ac/CEYH/hR3P4xbOSNgnAGL++Zb8CHUAY7CMuhd3rAqC1F1SETvw/r2oJRc7eSDUzAlnvZKRgCUHoHDtkPCJazM5VxmNylBPMAMHD13zSKnRbIgRTJI4cpfzYYw1bznBYkbIEIfihTTfijEOoHWrxZncirEg=" 59 | -------------------------------------------------------------------------------- /HEADER.txt: -------------------------------------------------------------------------------- 1 | This file is part of ${project}, licensed under the MIT License (MIT). 2 | 3 | Copyright (c) ${year} ${name} <${url}/> 4 | Original ReactPhysics3D C++ library by Daniel Chappuis 5 | ${project} is re-licensed with permission from ReactPhysics3D author. 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | THE SOFTWARE. -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React [![License](http://img.shields.io/badge/license-MIT-lightgrey.svg?style=flat)][License] [![Flattr this](http://img.shields.io/badge/flattr-donate-lightgrey.svg?style=flat)][Donate] [![Build Status](http://img.shields.io/travis/flow/react/develop.svg?style=flat)](https://travis-ci.org/flow/react) [![Coverage Status](http://img.shields.io/coveralls/flow/react/develop.svg?style=flat)](https://coveralls.io/r/flow/react) 2 | 3 | Real-time 3D physics library for Java, based on the [ReactPhysics3D](https://code.google.com/p/reactphysics3d/) C++ library by [Daniel Chappuis](http://www.danielchappuis.ch/). 4 | 5 | ## Features 6 | * Rigid body dynamics 7 | * Discrete collision detection 8 | * Collision shapes (Sphere, Box, Cone, Cylinder, Capsule, Convex Mesh) 9 | * Broadphase collision detection (Sweep and Prune using AABB) 10 | * Narrowphase collision detection (GJK/EPA) 11 | * Collision response and friction (Sequential Impulses solver) 12 | * Joints (Ball-and-socket, Hinge, Slider, Fixed) 13 | * Sleeping technique for inactive bodies 14 | * Multi-platform (Windows, Linux, Mac OS X) 15 | * Unit tests and Javadocs 16 | 17 | ## Getting Started 18 | * [Examples and code snippets](https://github.com/flow/examples/tree/master/react) 19 | * [Official documentation](#documentation) 20 | * [IRC support chat](http://kiwiirc.com/client/irc.esper.net/flow) 21 | * [Issues tracker](https://github.com/flow/react/issues) 22 | 23 | ## Source Code 24 | The latest and greatest source can be found here on [GitHub](https://github.com/flow/react). If you are using Git, use this command to clone the project: 25 | 26 | git clone git://github.com/flow/react.git 27 | 28 | Or download the latest [development archive](https://github.com/flow/react/archive/develop.zip) or the latest [stable archive](https://github.com/flow/react/archive/master.zip). 29 | 30 | ## Test Dependencies 31 | The following dependencies are only needed if you compiling the tests included with this project. Gotta test 'em all! 32 | * [junit:junit](https://oss.sonatype.org/#nexus-search;gav~junit~junit~~~) 33 | 34 | ## Building from Source 35 | This project can be built with the _latest_ [Java Development Kit](http://oracle.com/technetwork/java/javase/downloads) and [Maven](https://maven.apache.org/) or [Gradle](https://www.gradle.org/). Maven and Gradle are used to simplify dependency management, but using either of them is optional. 36 | 37 | For Maven, the command `mvn clean package` will build the project and will put the compiled JAR in `target`, and `mvn clean install` will copy it to your local Maven repository. 38 | 39 | For Gradle, the command `gradlew` will build the project and will put the compiled JAR in `~/build/distributions`, and `gradlew install` will copy it to your local Maven repository. 40 | 41 | ## Contributing 42 | Are you a talented programmer looking to contribute some code? We'd love the help! 43 | 44 | * Open a pull request with your changes, following our [guidelines and coding standards](CONTRIBUTING.md). 45 | * Please follow the above guidelines for your pull request(s) accepted. 46 | * For help setting up the project, keep reading! 47 | 48 | Love the project? Feel free to [donate] to help continue development! Flow projects are open-source and powered by community members, like yourself. Without you, we wouldn't be here today! 49 | 50 | Don't forget to watch and star our repo to keep up-to-date with the latest Flow development! 51 | 52 | ## Usage 53 | If you're using [Maven](https://maven.apache.org/download.html) to manage project dependencies, simply include the following in your `pom.xml` file: 54 | 55 | 56 | com.flowpowered 57 | react 58 | 1.0.1-SNAPSHOT 59 | 60 | 61 | If you're using [Gradle](https://www.gradle.org/) to manage project dependencies, simply include the following in your `build.gradle` file: 62 | 63 | repositories { 64 | mavenCentral() 65 | } 66 | dependencies { 67 | compile 'com.flowpowered:react:1.0.1-SNAPSHOT' 68 | } 69 | 70 | If you plan on using snapshots and do not already have the snapshot repo in your repository list, you will need to add this as well: 71 | 72 | https://oss.sonatype.org/content/groups/public/ 73 | 74 | If you'd prefer to manually import the latest .jar file, you can get it [here](https://github.com/flow/react/releases). 75 | 76 | ## Documentation 77 | Want to get friendly with the project and put it to good use? Check out the latest [Javadocs](https://flowpowered.com/react). 78 | 79 | To generate Javadocs with Maven, use the `mvn javadoc:javadoc` command. To view the Javadocs simply go to `target/site/apidocs/` and open `index.html` in a web browser. 80 | 81 | To generate Javadocs with Gradle, use the `gradlew javadoc` command. To view the Javadocs simply go to `build/docs/javadoc/` and open `index.html` in a web browser. 82 | 83 | ## Version Control 84 | We've adopted the [git flow branching model](http://nvie.com/posts/a-successful-git-branching-model/) in our projects. The creators of git flow released a [short intro video](http://vimeo.com/16018419) to explain the model. 85 | 86 | The `master` branch is production-ready and contains the latest tagged releases. Before a release is made, it is stagged in `release/x` branches before being pushed and tagged in the `master` branch. Small patches from `hotfix/x` branches are also pushed to `master`, and will always have a release version. The `develop` branch is pre-production, and is where we push `feature/x` branches for testing. 87 | 88 | ## Legal Stuff 89 | React is licensed under the [MIT License][License]. Basically, you can do whatever you want as long as you include the original copyright. Please see the `LICENSE.txt` file for details. 90 | 91 | ## Credits 92 | * Daniel Chappuis and contributors of the original [ReactPhysics3d](https://code.google.com/p/reactphysics3d/) C++ library. 93 | * [Spout](https://spout.org/) and contributors - *where we all began, and for much of the re-licensed code.* 94 | * All the people behind [Java](http://www.oracle.com/technetwork/java/index.html), [Maven](https://maven.apache.org/), and [Gradle](https://www.gradle.org/). 95 | 96 | [Donate]: https://flattr.com/submit/auto?user_id=spout&url=https://github.com/flow/react&title=React&language=Java&tags=github&category=software 97 | [License]: https://tldrlegal.com/l/mit 98 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Default tasks 2 | defaultTasks 'clean', 'licenseFormat', 'build', 'install' 3 | 4 | // Apply plugins 5 | apply plugin: 'java' 6 | apply plugin: 'cobertura' // Coveralls dependency 7 | apply plugin: 'com.github.kt3k.coveralls' 8 | apply plugin: 'license' 9 | apply plugin: 'maven' 10 | apply plugin: 'signing' 11 | 12 | // Project information 13 | ext.projectName = 'React' 14 | group = 'com.flowpowered' 15 | archivesBaseName = 'react' 16 | version = '1.0.1-SNAPSHOT' 17 | ext.packaging = 'jar' 18 | ext.inceptionYear = '2013' 19 | ext.url = 'https://flowpowered.com/react' 20 | ext.description = 'Real-time 3D physics library for Java, based on the ReactPhysics3D library.' 21 | 22 | // Organization information 23 | ext.organization = 'Flow Powered' 24 | ext.organizationUrl = 'https://flowpowered.com' 25 | 26 | // Build properties 27 | ext.buildNumber = project.hasProperty('buildNumber') ? buildNumber : '0' 28 | ext.ciSystem = project.hasProperty('ciSystem') ? ciSystem : 'unknown' 29 | ext.commit = project.hasProperty('commit') ? commit : 'unknown' 30 | 31 | // Build plugin repositories and dependencies 32 | buildscript { 33 | repositories { 34 | mavenLocal() 35 | mavenCentral() 36 | maven { 37 | name = 'sonatype-nexus' 38 | url = 'https://oss.sonatype.org/content/groups/public/' 39 | } 40 | } 41 | dependencies { 42 | classpath 'net.saliman:gradle-cobertura-plugin:2.2.8' // Coveralls dependency 43 | classpath 'nl.javadude.gradle.plugins:license-gradle-plugin:0.10.0' 44 | classpath 'org.kt3k.gradle.plugin:coveralls-gradle-plugin:2.4.0' 45 | } 46 | } 47 | 48 | // Project repositories 49 | repositories { 50 | mavenLocal() 51 | mavenCentral() 52 | maven { 53 | name = 'sonatype-nexus' 54 | url = 'https://oss.sonatype.org/content/groups/public/' 55 | } 56 | } 57 | 58 | // Project dependencies 59 | dependencies { 60 | compile 'net.sf.trove4j:trove4j:3.0.3' 61 | testCompile 'junit:junit:4.12' 62 | } 63 | 64 | // Filter, process, and include resources 65 | processResources { 66 | // Include in final JAR 67 | from(rootProject.rootDir) { 68 | include 'LICENSE.txt' 69 | } 70 | } 71 | 72 | // License header formatting 73 | license { 74 | ext.project = projectName 75 | ext.year = inceptionYear 76 | ext.name = organization 77 | ext.url = organizationUrl 78 | header rootProject.file('HEADER.txt') 79 | ignoreFailures true 80 | strictCheck true 81 | useDefaultMappings false 82 | mapping { java = 'SLASHSTAR_STYLE' } 83 | } 84 | 85 | // Source compiler configuration 86 | configure([compileJava, compileTestJava]) { 87 | sourceCompatibility = '1.7' 88 | targetCompatibility = '1.7' 89 | options.encoding = 'UTF-8' 90 | options.compilerArgs << '-Xlint:all' 91 | options.compilerArgs << '-Xlint:-path' 92 | options.deprecation = true 93 | } 94 | 95 | // JAR manifest configuration 96 | jar.manifest.mainAttributes( 97 | 'Built-By': System.properties['user.name'], 98 | 'Created-By': System.properties['java.vm.version'] + ' (' + System.properties['java.vm.vendor'] + ')', 99 | 'Specification-Title': projectName, 100 | 'Specification-Version': version + '+' + ciSystem + '-b' + buildNumber + '.git-' + commit, 101 | 'Specification-Vendor': organization + ' - ' + organizationUrl) 102 | 103 | // Javadoc doclint configuration 104 | if (JavaVersion.current().isJava8Compatible()) { 105 | allprojects { 106 | tasks.withType(Javadoc) { 107 | options.addStringOption('Xdoclint:none', '-quiet') 108 | } 109 | } 110 | } 111 | 112 | // Coveralls report configuration 113 | cobertura.coverageFormats = ['html', 'xml'] // Coveralls requires xml format 114 | 115 | // Artifact deployment 116 | uploadArchives { 117 | repositories.mavenDeployer { 118 | // Javadoc JAR generation 119 | task javadocJar(type: Jar, dependsOn: javadoc) { 120 | classifier = 'javadoc' 121 | from 'build/docs/javadoc' 122 | } 123 | 124 | // Source JAR generation 125 | task sourcesJar(type: Jar) { 126 | classifier = 'sources' 127 | from sourceSets.main.java.srcDirs 128 | } 129 | 130 | // Set all artifacts 131 | artifacts { 132 | archives jar, javadocJar, sourcesJar 133 | } 134 | 135 | // Tasks and variables based on if release or snapshot 136 | if (version.endsWith('-SNAPSHOT')) { 137 | // Set variable to snapshots repository URL 138 | ext.sonatypeUrl = 'https://oss.sonatype.org/content/repositories/snapshots/' 139 | } else { 140 | // Set variable to releases repository URL 141 | ext.sonatypeUrl = 'https://oss.sonatype.org/service/local/staging/deploy/maven2/' 142 | 143 | // Artifact signing 144 | signing { 145 | // Sign JAR artifacts 146 | sign configurations.archives 147 | 148 | // Sign Maven POM 149 | beforeDeployment { 150 | org.gradle.api.artifacts.maven.MavenDeployment deployment -> signing.signPom(deployment) 151 | } 152 | } 153 | } 154 | 155 | // Set login credentials for repository 156 | repository(url: sonatypeUrl) { 157 | authentication(userName: System.getenv("sonatypeUsername"), password: System.getenv("sonatypePassword")) 158 | } 159 | 160 | // Maven POM generation 161 | pom.project { 162 | name projectName 163 | artifactId archivesBaseName 164 | packaging packaging 165 | inceptionYear inceptionYear 166 | url url 167 | description project.ext.description 168 | 169 | scm { 170 | connection 'scm:git:git://github.com/flow/react.git' 171 | developerConnection 'scm:git:ssh://git@github.com:flow/react.git' 172 | url 'https://github.com/flow/react' 173 | } 174 | 175 | licenses { 176 | license { 177 | name 'MIT License' 178 | url 'https://tldrlegal.com/l/mit' 179 | distribution 'repo' 180 | } 181 | } 182 | 183 | organization { 184 | name organization 185 | url organizationUrl 186 | } 187 | 188 | developers { 189 | developer { 190 | id 'DDoS' 191 | name 'Aleksi Sapon' 192 | email 'qctechs@gmail.com' 193 | } 194 | developer { 195 | id 'kitskub' 196 | name 'Jack Huey' 197 | email 'kitskub@gmail.com' 198 | } 199 | developer { 200 | id 'Wolf480pl' 201 | name 'Wolf480pl' 202 | email 'wolf480@interia.pl' 203 | } 204 | developer { 205 | id 'lukespragg' 206 | name 'Luke Spragg' 207 | email 'the@wulf.im' 208 | } 209 | } 210 | } 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /bump.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function die_with() { echo "$*" >&2; exit 1; } 4 | 5 | echo "Getting current version from pom.xml" 6 | CURRENT_VERSION="`sed -n 's|.*\(.*\).*|\1|p' pom.xml | awk '{ print $1; exit }'`" 7 | echo "Current version from pom.xml: $CURRENT_VERSION" 8 | 9 | read -p "New version: " NEW_VERSION || die_with "Prompt for new version failed" 10 | 11 | if ! echo $NEW_VERSION | grep -i -- '-SNAPSHOT' >/dev/null; then echo "WARNING: changing to a release version!"; fi 12 | 13 | if [ -f pom.xml ]; then 14 | echo "Updating the project version in pom.xml to $NEW_VERSION" 15 | awk "/${CURRENT_VERSION//./\\.}/{ if (DONE != 1) {gsub(/${CURRENT_VERSION//./\\.}/, \"$NEW_VERSION\"); DONE=1; }} {print;}" < pom.xml > pom.xml.1 && mv -f pom.xml.1 pom.xml || die_with "Failed to update pom.xml!" 16 | fi 17 | 18 | if [ -f build.gradle ]; then 19 | echo "Updating the project version in build.gradle to $NEW_VERSION" 20 | awk "/${CURRENT_VERSION//./\\.}/{ if (DONE != 1) {gsub(/${CURRENT_VERSION//./\\.}/, \"$NEW_VERSION\"); DONE=1; }} {print;}" < build.gradle > build.gradle.1 && mv -f build.gradle.1 build.gradle || die_with "Failed to update build.gradle!" 21 | fi 22 | 23 | if [ -f README.md ]; then 24 | echo "Updating the project version in README.md to $NEW_VERSION" 25 | awk "/${CURRENT_VERSION//./\\.}/{ if (DONE != 1) {gsub(/${CURRENT_VERSION//./\\.}/, \"$NEW_VERSION\"); }} {print;}" < README.md > README.md.1 && mv -f README.md.1 README.md || die_with "Failed to update README.md!" 26 | fi 27 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flowpowered/react/e8f7ee5ec666d2d1783c8a16b9cbd49bc11f037c/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=http\://services.gradle.org/distributions/gradle-2.6-all.zip 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 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 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /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 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 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 Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /src/main/java/com/flowpowered/react/ReactDefaults.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react; 27 | 28 | /** 29 | * Physics engine constants 30 | */ 31 | public class ReactDefaults { 32 | /** 33 | * The machine epsilon. Default: 1.1920929E-7 34 | */ 35 | public static final float MACHINE_EPSILON = 1.1920929E-7f; 36 | /** 37 | * 2 * Pi constant. 38 | */ 39 | public static final float PI_TIMES_2 = 6.28318530f; 40 | /** 41 | * Default internal constant timestep in seconds. Default: 1/60s 42 | */ 43 | public static final float DEFAULT_TIMESTEP = 1f / 60; 44 | /** 45 | * Default restitution coefficient for a rigid body. Default: 0.5 46 | */ 47 | public static final float DEFAULT_RESTITUTION_COEFFICIENT = 0.5f; 48 | /** 49 | * Default friction coefficient for a rigid body. Default: 0.3 50 | */ 51 | public static final float DEFAULT_FRICTION_COEFFICIENT = 0.3f; 52 | /** 53 | * Default bounciness factor for a rigid body. Default: 0.5 54 | */ 55 | public static final float DEFAULT_BOUNCINESS = 0.5f; 56 | /** 57 | * True if the sleeping technique is enabled. Default: true 58 | */ 59 | public static final boolean SLEEPING_ENABLED = true; 60 | /** 61 | * Object margin for collision detection in meters (for the GJK-EPA Algorithm). Default: 0.04 62 | */ 63 | public static final float OBJECT_MARGIN = 0.04f; 64 | /** 65 | * Distance threshold for two contact points for a valid persistent contact. Default: 0.02 66 | */ 67 | public static final float PERSISTENT_CONTACT_DIST_THRESHOLD = 0.02f; 68 | /** 69 | * Velocity threshold for contact velocity restitution. Default: 1 70 | */ 71 | public static final float RESTITUTION_VELOCITY_THRESHOLD = 1; 72 | /** 73 | * Number of iterations when solving the velocity constraints of the Sequential Impulse technique. Default: 10 74 | */ 75 | public static final int DEFAULT_VELOCITY_SOLVER_NB_ITERATIONS = 10; 76 | /** 77 | * Number of iterations when solving the position constraints of the Sequential Impulse technique. Default: 5 78 | */ 79 | public static final int DEFAULT_POSITION_SOLVER_NB_ITERATIONS = 5; 80 | /** 81 | * Time (in seconds) that a body must stay still to be considered sleeping. Default: 1 82 | */ 83 | public static final float DEFAULT_TIME_BEFORE_SLEEP = 1.0f; 84 | /** 85 | * A body with a linear velocity smaller than the sleep linear velocity (in m/s) might enter sleeping mode. Default: 0.02 86 | */ 87 | public static final float DEFAULT_SLEEP_LINEAR_VELOCITY = 0.02f; 88 | /** 89 | * A body with angular velocity smaller than the sleep angular velocity (in rad/s) might enter sleeping mode. Default: 3pi/180 90 | */ 91 | public static final float DEFAULT_SLEEP_ANGULAR_VELOCITY = (float) (3 * (Math.PI / 180)); 92 | /** 93 | * The linked phase AABB scaling factor. Default: 2 94 | */ 95 | public static final float LINKED_PHASE_AABB_SCALING = 2; 96 | 97 | /** 98 | * Position correction technique used in the constraint solver (for joints). Default: NON_LINEAR_GAUSS_SEIDEL 99 | *

100 | * BAUMGARTE: Faster but can be inaccurate in some situations. 101 | *

102 | * NON_LINEAR_GAUSS_SEIDEL: Slower but more precise. This is the option used by default. 103 | */ 104 | public static enum JointsPositionCorrectionTechnique { 105 | /** 106 | * Faster but can be inaccurate in some situations. 107 | */ 108 | BAUMGARTE_JOINTS, 109 | /** 110 | * Slower but more precise. This is the option used by default. 111 | */ 112 | NON_LINEAR_GAUSS_SEIDEL 113 | } 114 | 115 | /** 116 | * Position correction technique used in the contact solver (for contacts). Default: SPLIT_IMPULSES 117 | *

118 | * BAUMGARTE: Faster but can be inaccurate and can lead to unexpected bounciness in some situations (due to error correction factor being added to the bodies momentum). 119 | *

120 | * SPLIT_IMPULSES: A bit slower but the error correction factor is not added to the bodies momentum. This is the option used by default. 121 | */ 122 | public static enum ContactsPositionCorrectionTechnique { 123 | /** 124 | * Faster but can be inaccurate and can lead to unexpected bounciness in some situations (due to error correction factor being added to the bodies momentum). 125 | */ 126 | BAUMGARTE_CONTACTS, 127 | /** 128 | * A bit slower but the error correction factor is not added to the bodies momentum. This is the option used by default. 129 | */ 130 | SPLIT_IMPULSES 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/main/java/com/flowpowered/react/Utilities.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react; 27 | 28 | /** 29 | * This class contains static utilities. It was added for the port to implement some C++ code in Java. 30 | */ 31 | public class Utilities { 32 | /** 33 | * Returns the index of an object in an array, or -1 if it can't be found. 34 | * 35 | * @param array The array to search 36 | * @param object The object to look for 37 | * @return The index, or -1 if the object wasn't found 38 | */ 39 | public static int indexOf(Object[] array, Object object) { 40 | for (int i = 0; i < array.length; i++) { 41 | if (object.equals(array[i])) { 42 | return i; 43 | } 44 | } 45 | return -1; 46 | } 47 | 48 | /** 49 | * Represents a pair of 32 bit integers. 50 | */ 51 | public static class IntPair { 52 | private int first; 53 | private int second; 54 | 55 | /** 56 | * Constructs a new int pair with both integers being 0. 57 | */ 58 | public IntPair() { 59 | this(0, 0); 60 | } 61 | 62 | /** 63 | * Constructs a new int pair with the desired value for each member. 64 | * 65 | * @param first The value of the first member 66 | * @param second The value of the second member 67 | */ 68 | public IntPair(int first, int second) { 69 | this.first = first; 70 | this.second = second; 71 | } 72 | 73 | /** 74 | * Gets the value of the first member. 75 | * 76 | * @return The first member's value 77 | */ 78 | public int getFirst() { 79 | return first; 80 | } 81 | 82 | /** 83 | * Sets the first member's value. 84 | * 85 | * @param first The value for the first member 86 | */ 87 | public void setFirst(int first) { 88 | this.first = first; 89 | } 90 | 91 | /** 92 | * Gets the value of the second member. 93 | * 94 | * @return The second member's value 95 | */ 96 | public int getSecond() { 97 | return second; 98 | } 99 | 100 | /** 101 | * Sets the second member's value. 102 | * 103 | * @param second The value for the second member 104 | */ 105 | public void setSecond(int second) { 106 | this.second = second; 107 | } 108 | 109 | /** 110 | * Swaps both members. First becomes second, second becomes first. 111 | */ 112 | public void swap() { 113 | final int temp = first; 114 | first = second; 115 | second = temp; 116 | } 117 | 118 | @Override 119 | public boolean equals(Object o) { 120 | if (this == o) { 121 | return true; 122 | } 123 | if (!(o instanceof IntPair)) { 124 | return false; 125 | } 126 | final IntPair intPair = (IntPair) o; 127 | if (first != intPair.getFirst()) { 128 | return false; 129 | } 130 | if (second != intPair.getSecond()) { 131 | return false; 132 | } 133 | return true; 134 | } 135 | 136 | @Override 137 | public int hashCode() { 138 | int result = first; 139 | result = 31 * result + second; 140 | return result; 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/main/java/com/flowpowered/react/body/Body.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react.body; 27 | 28 | /** 29 | * This is the base class for a body in the physics engine. 30 | */ 31 | public class Body { 32 | protected final int mID; 33 | protected boolean mIsAlreadyInIsland; 34 | protected boolean mIsAllowedToSleep; 35 | protected boolean mIsActive; 36 | protected boolean mIsSleeping; 37 | protected float mSleepTime; 38 | 39 | /** 40 | * Construct a new body from its ID. 41 | * 42 | * @param id The body's ID 43 | */ 44 | public Body(int id) { 45 | mID = id; 46 | mIsAlreadyInIsland = false; 47 | mIsAllowedToSleep = true; 48 | mIsActive = true; 49 | mIsSleeping = false; 50 | mSleepTime = 0; 51 | } 52 | 53 | /** 54 | * Gets the body's unique ID. 55 | * 56 | * @return The body's ID 57 | */ 58 | public int getID() { 59 | return mID; 60 | } 61 | 62 | /** 63 | * Returns true if the body has already been added in an island (for the sleeping technique). 64 | * 65 | * @return Whether or not the body is already in an island 66 | */ 67 | public boolean isAlreadyInIsland() { 68 | return mIsAlreadyInIsland; 69 | } 70 | 71 | /** 72 | * Sets the value of to know if the body has already been added into an island. 73 | * 74 | * @param isAlreadyInIsland Whether or not the body is in an island 75 | */ 76 | public void setIsAlreadyInIsland(boolean isAlreadyInIsland) { 77 | mIsAlreadyInIsland = isAlreadyInIsland; 78 | } 79 | 80 | /** 81 | * Returns whether or not the body is allowed to sleep. 82 | * 83 | * @return Whether or not the body can sleep 84 | */ 85 | public boolean isAllowedToSleep() { 86 | return mIsAllowedToSleep; 87 | } 88 | 89 | /** 90 | * Set whether or not the body is allowed to go to sleep. 91 | * 92 | * @param isAllowedToSleep Whether or not the body should be able to sleep 93 | */ 94 | public void setIsAllowedToSleep(boolean isAllowedToSleep) { 95 | mIsAllowedToSleep = isAllowedToSleep; 96 | if (!mIsAllowedToSleep) { 97 | setIsSleeping(false); 98 | } 99 | } 100 | 101 | /** 102 | * Returns true if the body is active, false if not. 103 | * 104 | * @return Whether or not the body is active 105 | */ 106 | public boolean isActive() { 107 | return mIsActive; 108 | } 109 | 110 | /** 111 | * Sets the activity for this body. True for active, false for inactive. 112 | * 113 | * @param mIsActive True if this body is active, false if not 114 | */ 115 | public void setActive(boolean mIsActive) { 116 | this.mIsActive = mIsActive; 117 | } 118 | 119 | /** 120 | * Returns whether or not the body is sleeping. 121 | * 122 | * @return Whether or not the body is sleeping 123 | */ 124 | public boolean isSleeping() { 125 | return mIsSleeping; 126 | } 127 | 128 | /** 129 | * Set the variable to know whether or not the body is sleeping. 130 | * 131 | * @param isSleeping Whether or not the body is sleeping 132 | */ 133 | public void setIsSleeping(boolean isSleeping) { 134 | if (isSleeping) { 135 | mSleepTime = 0; 136 | } else { 137 | if (mIsSleeping) { 138 | mSleepTime = 0; 139 | } 140 | } 141 | mIsSleeping = isSleeping; 142 | } 143 | 144 | /** 145 | * Returns the sleep time. 146 | * 147 | * @return The sleep time 148 | */ 149 | public float getSleepTime() { 150 | return mSleepTime; 151 | } 152 | 153 | /** 154 | * Sets the sleep time. 155 | * 156 | * @param sleepTime The sleep time 157 | */ 158 | public void setSleepTime(float sleepTime) { 159 | mSleepTime = sleepTime; 160 | } 161 | 162 | /** 163 | * Returns true this body's ID is smaller than the other body's ID, false if not. 164 | * 165 | * @param other The body to compare with 166 | * @return True if this body is smaller, false if not 167 | */ 168 | public boolean isSmallerThan(Body other) { 169 | return mID < other.getID(); 170 | } 171 | 172 | /** 173 | * Returns true this body's ID is greater than the other body's ID, false if not. 174 | * 175 | * @param other The body to compare with 176 | * @return True if this body is greater, false if not 177 | */ 178 | public boolean isGreaterThan(Body other) { 179 | return mID > other.getID(); 180 | } 181 | 182 | /** 183 | * Returns true this body's ID is equal than the other body's ID, false if not. 184 | * 185 | * @param other The body to compare with 186 | * @return True if this body is equal, false if not 187 | */ 188 | public boolean isEqualTo(Body other) { 189 | return mID == other.getID(); 190 | } 191 | 192 | /** 193 | * Returns true this body's ID is not equal than the other body's ID, false if not. 194 | * 195 | * @param other The body to compare with 196 | * @return True if this body is not equal, false if not 197 | */ 198 | public boolean isNotEqualTo(Body other) { 199 | return mID != other.getID(); 200 | } 201 | 202 | @Override 203 | public boolean equals(Object o) { 204 | if (this == o) { 205 | return true; 206 | } 207 | if (!(o instanceof Body)) { 208 | return false; 209 | } 210 | final Body body = (Body) o; 211 | return mID == body.mID; 212 | } 213 | 214 | @Override 215 | public int hashCode() { 216 | return mID; 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /src/main/java/com/flowpowered/react/body/CollisionBody.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react.body; 27 | 28 | import com.flowpowered.react.collision.shape.AABB; 29 | import com.flowpowered.react.collision.shape.CollisionShape; 30 | import com.flowpowered.react.engine.ContactManifold.ContactManifoldListElement; 31 | import com.flowpowered.react.math.Transform; 32 | 33 | /** 34 | * Represents a body that is able to collide with others bodies. This class inherits from the Body class. 35 | */ 36 | public class CollisionBody extends Body { 37 | protected CollisionShape mCollisionShape; 38 | protected final Transform mTransform; 39 | protected final Transform mOldTransform; 40 | protected float mInterpolationFactor; 41 | protected boolean mIsMotionEnabled; 42 | protected boolean mIsCollisionEnabled; 43 | protected final AABB mAabb = new AABB(); 44 | protected boolean mHasMoved; 45 | protected ContactManifoldListElement mContactManifoldsList; 46 | 47 | /** 48 | * Constructs a new collision body from its transform, collision shape, and ID. 49 | * 50 | * @param transform The transform 51 | * @param collisionShape The collision shape 52 | * @param id The ID 53 | */ 54 | public CollisionBody(Transform transform, CollisionShape collisionShape, int id) { 55 | super(id); 56 | if (collisionShape == null) { 57 | throw new IllegalArgumentException("collisionShape cannot be null"); 58 | } 59 | mCollisionShape = collisionShape; 60 | mTransform = transform; 61 | mHasMoved = false; 62 | mIsMotionEnabled = true; 63 | mIsCollisionEnabled = true; 64 | mInterpolationFactor = 0; 65 | mOldTransform = transform; 66 | mCollisionShape.updateAABB(mAabb, transform); 67 | mContactManifoldsList = null; 68 | } 69 | 70 | /** 71 | * Returns true if the body has moved during the last frame, false if not. 72 | * 73 | * @return Whether or not the body has moved in the last frame 74 | */ 75 | public boolean getHasMoved() { 76 | return mHasMoved; 77 | } 78 | 79 | /** 80 | * Set the hasMoved variable (true if the body has moved during the last frame). 81 | * 82 | * @param mHasMoved Whether or not the body has moved in the last frame 83 | */ 84 | public void setHasMoved(boolean mHasMoved) { 85 | this.mHasMoved = mHasMoved; 86 | } 87 | 88 | /** 89 | * Gets the collision shape. 90 | * 91 | * @return The collision shape 92 | */ 93 | public CollisionShape getCollisionShape() { 94 | return mCollisionShape; 95 | } 96 | 97 | /** 98 | * Sets the collision shape 99 | * 100 | * @param mCollisionShape The collision shape to set 101 | */ 102 | public void setCollisionShape(CollisionShape mCollisionShape) { 103 | this.mCollisionShape = mCollisionShape; 104 | } 105 | 106 | /** 107 | * Returns an interpolated body from the old to the current transform, based on this body's interpolation factor. 108 | * 109 | * @return A transform interpolated from the old to the current transform based on the interpolation factor 110 | */ 111 | public Transform getInterpolatedTransform() { 112 | return Transform.interpolateTransforms(mOldTransform, mTransform, mInterpolationFactor); 113 | } 114 | 115 | /** 116 | * Sets the interpolation factor for the transforms of this body. 117 | * 118 | * @param factor The interpolation factor 119 | */ 120 | public void setInterpolationFactor(float factor) { 121 | mInterpolationFactor = factor; 122 | } 123 | 124 | /** 125 | * Gets this body's current position and orientation as a transform. 126 | * 127 | * @return The body's transform 128 | */ 129 | public Transform getTransform() { 130 | return mTransform; 131 | } 132 | 133 | /** 134 | * Sets this body's current position and orientation as a transform. 135 | * 136 | * @param transform The transform to set for this body 137 | */ 138 | public void setTransform(Transform transform) { 139 | if (!mTransform.equals(transform)) { 140 | mHasMoved = true; 141 | } 142 | mTransform.set(transform); 143 | } 144 | 145 | /** 146 | * Gets this body's axis-aligned bounding box (AABB). 147 | * 148 | * @return The body's AABB 149 | */ 150 | public AABB getAABB() { 151 | return mAabb; 152 | } 153 | 154 | /** 155 | * Returns true if the body can move, false if not. 156 | * 157 | * @return Whether or not the body can move 158 | */ 159 | public boolean isMotionEnabled() { 160 | return mIsMotionEnabled; 161 | } 162 | 163 | /** 164 | * Sets whether or not this body can move. True to allow movement, false to disallow. 165 | * 166 | * @param isMotionEnabled True if the body should move, false if not 167 | */ 168 | public void enableMotion(boolean isMotionEnabled) { 169 | mIsMotionEnabled = isMotionEnabled; 170 | } 171 | 172 | /** 173 | * Return true if the body can collide with others bodies. 174 | * 175 | * @return Whether or not this body can collide with others 176 | */ 177 | public boolean isCollisionEnabled() { 178 | return mIsCollisionEnabled; 179 | } 180 | 181 | /** 182 | * Sets whether or not this body can collide. True to allow collisions, false to disallow. 183 | * 184 | * @param isCollisionEnabled True if the body should collide, false if not 185 | */ 186 | public void enableCollision(boolean isCollisionEnabled) { 187 | mIsCollisionEnabled = isCollisionEnabled; 188 | } 189 | 190 | /** 191 | * Update the old transform with the current one. This is used to compute the interpolated position and orientation of the body. 192 | */ 193 | public void updateOldTransform() { 194 | mOldTransform.set(mTransform); 195 | } 196 | 197 | /** 198 | * Update the rigid body in order to reflect a change in the body state. 199 | */ 200 | public void updateAABB() { 201 | if (mHasMoved) { 202 | mCollisionShape.updateAABB(mAabb, mTransform); 203 | } 204 | } 205 | 206 | /** 207 | * Returns the first element of the linked list of contact manifolds involving this body. 208 | * 209 | * @return The first element of the list 210 | */ 211 | public ContactManifoldListElement getContactManifoldsLists() { 212 | return mContactManifoldsList; 213 | } 214 | 215 | /** 216 | * Sets the first element in the contact element list, discarding the entire list. 217 | * 218 | * @param contactManifoldsList The first element in the list 219 | */ 220 | public void setContactManifoldsList(ContactManifoldListElement contactManifoldsList) { 221 | mContactManifoldsList = contactManifoldsList; 222 | } 223 | 224 | /** 225 | * Resets the contact manifold lists. 226 | */ 227 | public void resetContactManifoldsList() { 228 | mContactManifoldsList = null; 229 | } 230 | } 231 | -------------------------------------------------------------------------------- /src/main/java/com/flowpowered/react/collision/BroadPhasePair.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react.collision; 27 | 28 | import com.flowpowered.react.Utilities.IntPair; 29 | import com.flowpowered.react.body.CollisionBody; 30 | import com.flowpowered.react.math.Vector3; 31 | 32 | /** 33 | * Represents a pair of bodies during the broad-phase collision detection. 34 | */ 35 | public class BroadPhasePair { 36 | private CollisionBody body1; 37 | private CollisionBody body2; 38 | private final Vector3 previousSeparatingAxis = new Vector3(1, 1, 1); 39 | 40 | /** 41 | * Constructs a new broad phase pair from the first and the second body. 42 | * 43 | * @param body1 The first body 44 | * @param body2 The second body 45 | */ 46 | public BroadPhasePair(CollisionBody body1, CollisionBody body2) { 47 | this.body1 = body1; 48 | this.body2 = body2; 49 | } 50 | 51 | /** 52 | * Gets the pair of bodies indexes (IDs) as a pair of integers. 53 | * 54 | * @return The pair of body indexes (IDs) 55 | */ 56 | public IntPair getBodiesIndexPair() { 57 | return computeBodiesIndexPair(body1, body2); 58 | } 59 | 60 | /** 61 | * Gets the previous separating axis. 62 | * 63 | * @return The previous separating axis 64 | */ 65 | public Vector3 getPreviousSeparatingAxis() { 66 | return previousSeparatingAxis; 67 | } 68 | 69 | /** 70 | * Sets the previous separating axis. 71 | * 72 | * @param previousSeparatingAxis The axis to set 73 | */ 74 | public void setPreviousSeparatingAxis(Vector3 previousSeparatingAxis) { 75 | this.previousSeparatingAxis.set(previousSeparatingAxis); 76 | } 77 | 78 | /** 79 | * Gets the first body of the pair. 80 | * 81 | * @return The first body 82 | */ 83 | public CollisionBody getFirstBody() { 84 | return body1; 85 | } 86 | 87 | /** 88 | * Sets the first body of the pair. 89 | * 90 | * @param body1 The first body 91 | */ 92 | public void setFirstBody(CollisionBody body1) { 93 | this.body1 = body1; 94 | } 95 | 96 | /** 97 | * Gets the second body of the pair. 98 | * 99 | * @return The second body 100 | */ 101 | public CollisionBody getSecondBody() { 102 | return body2; 103 | } 104 | 105 | /** 106 | * Sets the second body of the pair. 107 | * 108 | * @param body2 The second body 109 | */ 110 | public void setSecondBody(CollisionBody body2) { 111 | this.body2 = body2; 112 | } 113 | 114 | /** 115 | * Returns true this broad phase pair is smaller than the other broad phase pair, false if not. 116 | * 117 | * @param broadPhasePair2 The broad phase pair to compare with 118 | * @return True if this broad phase pair is smaller, false if not 119 | */ 120 | public boolean isSmallerThan(BroadPhasePair broadPhasePair2) { 121 | return body1.isSmallerThan(broadPhasePair2.body1) || (body2.isSmallerThan(broadPhasePair2.body2)); 122 | } 123 | 124 | /** 125 | * Returns true this broad phase pair is greater than the other broad phase pair, false if not. 126 | * 127 | * @param broadPhasePair2 The broad phase pair to compare with 128 | * @return True if this broad phase pair is greater, false if not 129 | */ 130 | public boolean isGreaterThan(BroadPhasePair broadPhasePair2) { 131 | return body1.isGreaterThan(broadPhasePair2.body1) || (body2.isGreaterThan(broadPhasePair2.body2)); 132 | } 133 | 134 | /** 135 | * Returns true this broad phase pair is equal than the other broad phase pair, false if not. 136 | * 137 | * @param broadPhasePair2 The broad phase pair to compare with 138 | * @return True if this broad phase pair equal, false if not 139 | */ 140 | public boolean isEqualTo(BroadPhasePair broadPhasePair2) { 141 | return body1.isEqualTo(broadPhasePair2.body1) && body2.isEqualTo(broadPhasePair2.body2); 142 | } 143 | 144 | /** 145 | * Returns true this broad phase pair is not equal than the other broad phase pair, false if not. 146 | * 147 | * @param broadPhasePair2 The broad phase pair to compare with 148 | * @return True if this broad phase pair is not equal, false if not 149 | */ 150 | public boolean isNotEqualTo(BroadPhasePair broadPhasePair2) { 151 | return body1.isNotEqualTo(broadPhasePair2.body1) || body2.isNotEqualTo(broadPhasePair2.body2); 152 | } 153 | 154 | /** 155 | * Converts the pair of bodies to a pair of indexes (IDs) as a pair of integers. 156 | * 157 | * @param body1 The first body 158 | * @param body2 The second body 159 | * @return The pair of body indexes (IDs) 160 | */ 161 | public static IntPair computeBodiesIndexPair(CollisionBody body1, CollisionBody body2) { 162 | final IntPair indexPair = body1.getID() < body2.getID() ? 163 | new IntPair(body1.getID(), body2.getID()) : 164 | new IntPair(body2.getID(), body1.getID()); 165 | if (indexPair.getFirst() == indexPair.getSecond()) { 166 | throw new IllegalStateException("First int of the pair cannot be equal to the second int of the pair"); 167 | } 168 | return indexPair; 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /src/main/java/com/flowpowered/react/collision/broadphase/BroadPhaseAlgorithm.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react.collision.broadphase; 27 | 28 | import com.flowpowered.react.body.CollisionBody; 29 | import com.flowpowered.react.collision.CollisionDetection; 30 | import com.flowpowered.react.collision.broadphase.PairManager.BodyPair; 31 | import com.flowpowered.react.collision.shape.AABB; 32 | 33 | /** 34 | * This class is an abstract class that represents an algorithm used to perform the broad-phase of a collision detection. The goal of the broad-phase algorithm is to compute the pair of bodies that 35 | * can collide. It's important to understand that the broad-phase doesn't only compute body pairs that can collide, but could those that don't collide but are very close. The goal of the broad-phase 36 | * is to remove pairs of body that cannot collide in order to reduce the quantity of bodies to be tested in the narrow-phase. 37 | */ 38 | public abstract class BroadPhaseAlgorithm { 39 | protected final PairManager mPairManager; 40 | protected final CollisionDetection mCollisionDetection; 41 | 42 | /** 43 | * Constructs a new broad-phase algorithm from the collision detection it's associated to. 44 | * 45 | * @param collisionDetection The collision detection 46 | */ 47 | protected BroadPhaseAlgorithm(CollisionDetection collisionDetection) { 48 | mPairManager = new PairManager(collisionDetection); 49 | mCollisionDetection = collisionDetection; 50 | } 51 | 52 | /** 53 | * Notify the broad-phase about the addition of an object from the world. 54 | * 55 | * @param body The body that was added 56 | * @param aabb The body's AABB 57 | */ 58 | public abstract void addObject(CollisionBody body, AABB aabb); 59 | 60 | /** 61 | * Notify the broad-phase about the removal of an object from the world. 62 | * 63 | * @param body The body that was removed 64 | */ 65 | public abstract void removeObject(CollisionBody body); 66 | 67 | /** 68 | * Notify the broad-phase that the AABB of an object has changed. 69 | * 70 | * @param body The body who had his AABB change 71 | * @param aabb The body's new AABB 72 | */ 73 | public abstract void updateObject(CollisionBody body, AABB aabb); 74 | 75 | /** 76 | * Returns the array of overlapping pairs managed by the pair manager, for iteration purposes. Note that the array returned contains trailing null elements. 77 | * 78 | * @return The array of overlapping pairs 79 | */ 80 | public BodyPair[] getOverlappingPairs() { 81 | return mPairManager.getOverlappingPairs(); 82 | } 83 | 84 | /** 85 | * Return the last overlapping pair (used to iterate over the overlapping pairs) or returns null if there are no overlapping pairs. Note that the array returned by {@link #getOverlappingPairs()} 86 | * contains trailing null elements. 87 | * 88 | * @return The last overlapping pair 89 | */ 90 | public BodyPair getLastOverlappingPair() { 91 | return mPairManager.getLastOverlappingPair(); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/com/flowpowered/react/collision/broadphase/NoBroadPhaseAlgorithm.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react.collision.broadphase; 27 | 28 | import java.util.HashSet; 29 | import java.util.Set; 30 | 31 | import com.flowpowered.react.body.CollisionBody; 32 | import com.flowpowered.react.collision.CollisionDetection; 33 | import com.flowpowered.react.collision.shape.AABB; 34 | 35 | /** 36 | * This class implements a broad-phase algorithm that does nothing. It should be use if we don't want to perform a broad-phase for the collision detection. 37 | */ 38 | public class NoBroadPhaseAlgorithm extends BroadPhaseAlgorithm { 39 | private final Set mBodies = new HashSet<>(); 40 | 41 | /** 42 | * Constructs a new no broad-phase algorithm from the collision detection it's associated to. 43 | * 44 | * @param collisionDetection The collision detection 45 | */ 46 | public NoBroadPhaseAlgorithm(CollisionDetection collisionDetection) { 47 | super(collisionDetection); 48 | } 49 | 50 | @Override 51 | public void addObject(CollisionBody body, AABB aabb) { 52 | for (CollisionBody collisionBody : mBodies) { 53 | if (body.isMotionEnabled() || collisionBody.isMotionEnabled()) { 54 | mPairManager.addPair(collisionBody, body); 55 | } 56 | } 57 | mBodies.add(body); 58 | } 59 | 60 | @Override 61 | public void removeObject(CollisionBody body) { 62 | for (CollisionBody collisionBody : mBodies) { 63 | if (collisionBody.getID() != body.getID()) { 64 | mPairManager.removePair(collisionBody.getID(), body.getID()); 65 | } 66 | } 67 | mBodies.remove(body); 68 | } 69 | 70 | @Override 71 | public void updateObject(CollisionBody body, AABB aabb) { 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/com/flowpowered/react/collision/linkedphase/LinkedPhase.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react.collision.linkedphase; 27 | 28 | import java.util.HashSet; 29 | import java.util.Set; 30 | 31 | import com.flowpowered.react.ReactDefaults; 32 | import com.flowpowered.react.body.RigidBody; 33 | import com.flowpowered.react.collision.shape.AABB; 34 | import com.flowpowered.react.engine.linked.LinkedDynamicsWorld; 35 | import com.flowpowered.react.math.Vector3; 36 | 37 | /** 38 | * A phase of the physics tick where bodies are added via the {@link com.flowpowered.react.engine.linked.LinkedDynamicsWorld}'s {@link com.flowpowered.react.engine.linked.LinkedWorldInfo}. 39 | */ 40 | public class LinkedPhase { 41 | private final LinkedDynamicsWorld linkedWorld; 42 | 43 | /** 44 | * Constructs a new linked phase from the linked dynamics world. 45 | * 46 | * @param linkedWorld The linked dynamics world this phase is associate to 47 | */ 48 | public LinkedPhase(LinkedDynamicsWorld linkedWorld) { 49 | this.linkedWorld = linkedWorld; 50 | } 51 | 52 | /** 53 | * Sweeps for {@link RigidBody}s around the body provided.

The algorithm will ask for all bodies within the bounds of the bodies' AABB scaled by a {@link 54 | * ReactDefaults#LINKED_PHASE_AABB_SCALING}.

55 | * 56 | * @param body The mobile body to scan around 57 | * @return A set of all bodies in range 58 | */ 59 | public Set getBodiesInRange(RigidBody body) { 60 | final AABB aabb = body.getAABB(); 61 | // To object coords 62 | final Vector3 max = Vector3.subtract(aabb.getMax(), aabb.getCenter()); 63 | final Vector3 min = Vector3.subtract(aabb.getMin(), aabb.getCenter()); 64 | // Scale the coords 65 | max.multiply(ReactDefaults.LINKED_PHASE_AABB_SCALING); 66 | min.multiply(ReactDefaults.LINKED_PHASE_AABB_SCALING); 67 | // Back to world coords 68 | max.add(aabb.getCenter()); 69 | min.add(aabb.getCenter()); 70 | final int startX = (int) Math.floor(min.getX()); 71 | final int startY = (int) Math.floor(min.getY()); 72 | final int startZ = (int) Math.floor(min.getZ()); 73 | final int endX = (int) Math.ceil(max.getX()); 74 | final int endY = (int) Math.ceil(max.getY()); 75 | final int endZ = (int) Math.ceil(max.getZ()); 76 | final Set foundBodies = new HashSet<>(); 77 | for (int xx = startX; xx <= endX; xx++) { 78 | for (int yy = startY; yy <= endY; yy++) { 79 | for (int zz = startZ; zz <= endZ; zz++) { 80 | final RigidBody immobile = linkedWorld.getLinkedInfo().getBody(xx, yy, zz); 81 | if (immobile == null) { 82 | continue; 83 | } 84 | foundBodies.add(immobile); 85 | } 86 | } 87 | } 88 | return foundBodies; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/com/flowpowered/react/collision/narrowphase/EPA/EdgeEPA.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react.collision.narrowphase.EPA; 27 | 28 | import com.flowpowered.react.math.Vector3; 29 | 30 | /** 31 | * Represents an edge for the current polytope in the EPA algorithm. 32 | */ 33 | public class EdgeEPA { 34 | private TriangleEPA mOwnerTriangle; 35 | private int mIndex; 36 | 37 | /** 38 | * Default constructor. The owner triangle is null and the index is zero. 39 | */ 40 | public EdgeEPA() { 41 | this(null, 0); 42 | } 43 | 44 | /** 45 | * Construct a new edge for the EPA from its owner triangle and index. 46 | * 47 | * @param ownerTriangle The owner triangle 48 | * @param index The index 49 | */ 50 | public EdgeEPA(TriangleEPA ownerTriangle, int index) { 51 | if (index < 0 || index >= 3) { 52 | throw new IllegalArgumentException("index must be greater or equal to zero and smaller than three"); 53 | } 54 | mOwnerTriangle = ownerTriangle; 55 | mIndex = index; 56 | } 57 | 58 | /** 59 | * Copy constructor. 60 | * 61 | * @param edge The edge to copy 62 | */ 63 | public EdgeEPA(EdgeEPA edge) { 64 | mOwnerTriangle = edge.mOwnerTriangle; 65 | mIndex = edge.mIndex; 66 | } 67 | 68 | /** 69 | * Gets the owner triangle. 70 | * 71 | * @return The owner triangle 72 | */ 73 | public TriangleEPA getOwnerTriangle() { 74 | return mOwnerTriangle; 75 | } 76 | 77 | /** 78 | * Gets the edge index. 79 | * 80 | * @return The edge index 81 | */ 82 | public int getIndex() { 83 | return mIndex; 84 | } 85 | 86 | /** 87 | * Sets the values of this edge to the ones of the provided edge. 88 | * 89 | * @param edge The edge to copy the values from 90 | */ 91 | public void set(EdgeEPA edge) { 92 | mOwnerTriangle = edge.mOwnerTriangle; 93 | mIndex = edge.mIndex; 94 | } 95 | 96 | /** 97 | * Gets the index of the source vertex for the edge (vertex starting the edge). 98 | * 99 | * @return The index of the source vertex 100 | */ 101 | public int getSourceVertexIndex() { 102 | return mOwnerTriangle.get(mIndex); 103 | } 104 | 105 | /** 106 | * Gets the index of the target vertex for the edge (vertex ending the edge). 107 | * 108 | * @return The index of the target vertex 109 | */ 110 | public int getTargetVertexIndex() { 111 | return mOwnerTriangle.get(indexOfNextCounterClockwiseEdge(mIndex)); 112 | } 113 | 114 | /** 115 | * Executes the recursive silhouette algorithm from this edge. 116 | * 117 | * @param vertices The vertices 118 | * @param indexNewVertex The index of the new vertex 119 | * @param triangleStore The triangle store 120 | * @return True if the owner triangle was obsolete or if a new triangle edge was half liked with this one 121 | */ 122 | public boolean computeSilhouette(Vector3[] vertices, int indexNewVertex, TrianglesStore triangleStore) { 123 | if (!mOwnerTriangle.isObsolete()) { 124 | if (!mOwnerTriangle.isVisibleFromVertex(vertices, indexNewVertex)) { 125 | TriangleEPA triangle = triangleStore.newTriangle( 126 | vertices, 127 | indexNewVertex, 128 | getTargetVertexIndex(), 129 | getSourceVertexIndex()); 130 | if (triangle != null) { 131 | TriangleEPA.halfLink(new EdgeEPA(triangle, 1), this); 132 | return true; 133 | } 134 | return false; 135 | } else { 136 | mOwnerTriangle.setObsolete(true); 137 | int backup = triangleStore.getNbTriangles(); 138 | if (!mOwnerTriangle.getAdjacentEdge(indexOfNextCounterClockwiseEdge(this.mIndex)) 139 | .computeSilhouette(vertices, indexNewVertex, triangleStore)) { 140 | mOwnerTriangle.setObsolete(false); 141 | TriangleEPA triangle = triangleStore.newTriangle( 142 | vertices, 143 | indexNewVertex, 144 | getTargetVertexIndex(), 145 | getSourceVertexIndex()); 146 | if (triangle != null) { 147 | TriangleEPA.halfLink(new EdgeEPA(triangle, 1), this); 148 | return true; 149 | } 150 | return false; 151 | } else if (!mOwnerTriangle.getAdjacentEdge(indexOfPreviousCounterClockwiseEdge(this.mIndex)) 152 | .computeSilhouette(vertices, indexNewVertex, triangleStore)) { 153 | mOwnerTriangle.setObsolete(false); 154 | triangleStore.setNbTriangles(backup); 155 | TriangleEPA triangle = triangleStore.newTriangle( 156 | vertices, 157 | indexNewVertex, 158 | getTargetVertexIndex(), 159 | getSourceVertexIndex()); 160 | if (triangle != null) { 161 | TriangleEPA.halfLink(new EdgeEPA(triangle, 1), this); 162 | return true; 163 | } 164 | return false; 165 | } 166 | } 167 | } 168 | return true; 169 | } 170 | 171 | // Returns the index of the next counter-clockwise edge of the owner triangle. 172 | private static int indexOfNextCounterClockwiseEdge(int i) { 173 | return (i + 1) % 3; 174 | } 175 | 176 | // Returns the index of the previous counter-clockwise edge of the owner triangle. 177 | private static int indexOfPreviousCounterClockwiseEdge(int i) { 178 | return (i + 2) % 3; 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /src/main/java/com/flowpowered/react/collision/narrowphase/EPA/TrianglesStore.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react.collision.narrowphase.EPA; 27 | 28 | import com.flowpowered.react.math.Vector3; 29 | 30 | /** 31 | * This class stores several triangles for the polytope in the EPA algorithm. The max number of triangles is {@link #MAX_TRIANGLES}. 32 | */ 33 | public class TrianglesStore { 34 | public static final int MAX_TRIANGLES = 200; 35 | private final TriangleEPA[] mTriangles = new TriangleEPA[MAX_TRIANGLES]; 36 | private int mNbTriangles = 0; 37 | 38 | /** 39 | * Clears all the triangles in the storage. 40 | */ 41 | public void clear() { 42 | mNbTriangles = 0; 43 | } 44 | 45 | /** 46 | * Gets the number of triangles in the store. 47 | * 48 | * @return The number of triangles 49 | */ 50 | public int getNbTriangles() { 51 | return mNbTriangles; 52 | } 53 | 54 | /** 55 | * Sets the number of triangles back to the specified number. This number should be smaller than the current number. 56 | * 57 | * @param backup The new number of triangles. 58 | */ 59 | public void setNbTriangles(int backup) { 60 | mNbTriangles = backup; 61 | } 62 | 63 | /** 64 | * Gets the last triangle in the store. This will fail if there's no triangles in the store. 65 | * 66 | * @return The last triangle if the store 67 | * @throws IllegalStateException If there's no triangles in the store. 68 | */ 69 | public TriangleEPA last() { 70 | if (mNbTriangles <= 0) { 71 | throw new IllegalStateException("nbTriangles must be greater than zero"); 72 | } 73 | return mTriangles[mNbTriangles - 1]; 74 | } 75 | 76 | /** 77 | * Creates and returns a new triangle, keeping it in the store. If the store is full or the triangle is invalid, this will return null. 78 | * 79 | * @param vertices The vertices of this triangle (three) 80 | * @param v0 The index of the first vertex 81 | * @param v1 The index of the second vertex 82 | * @param v2 The index of the third vertex 83 | * @return The new triangle or null if the creation failed or the store is full 84 | */ 85 | public TriangleEPA newTriangle(Vector3[] vertices, int v0, int v1, int v2) { 86 | TriangleEPA newTriangle = null; 87 | if (mNbTriangles != MAX_TRIANGLES) { 88 | newTriangle = new TriangleEPA(v0, v1, v2); 89 | mTriangles[mNbTriangles++] = newTriangle; 90 | if (!newTriangle.computeClosestPoint(vertices)) { 91 | mNbTriangles--; 92 | newTriangle = null; 93 | mTriangles[mNbTriangles] = null; 94 | } 95 | } 96 | return newTriangle; 97 | } 98 | 99 | /** 100 | * Gets the triangle at the desired index in the store. This index should be smaller than {@link #MAX_TRIANGLES}. 101 | * 102 | * @param index The index 103 | * @return The triangle, or null if there's not triangle at the index 104 | */ 105 | public TriangleEPA get(int index) { 106 | return mTriangles[index]; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/main/java/com/flowpowered/react/collision/narrowphase/NarrowPhaseAlgorithm.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react.collision.narrowphase; 27 | 28 | import com.flowpowered.react.collision.BroadPhasePair; 29 | import com.flowpowered.react.collision.shape.CollisionShape; 30 | import com.flowpowered.react.constraint.ContactPoint.ContactPointInfo; 31 | import com.flowpowered.react.math.Transform; 32 | 33 | /** 34 | * This class is an abstract class that represents an algorithm used to perform the narrow-phase of a collision detection. The goal of the narrow phase algorithm is to compute contact information of a 35 | * collision between two bodies. 36 | */ 37 | public abstract class NarrowPhaseAlgorithm { 38 | protected BroadPhasePair mCurrentOverlappingPair = null; 39 | 40 | /** 41 | * Sets the current overlapping pair. 42 | * 43 | * @param overlappingPair The overlapping pair 44 | */ 45 | public void setCurrentOverlappingPair(BroadPhasePair overlappingPair) { 46 | mCurrentOverlappingPair = overlappingPair; 47 | } 48 | 49 | /** 50 | * Returns true and computes the contact info if the two bounding volume collide. If they do not, this method returns false and the contact info will remain unchanged. The new contact info is 51 | * stored in the {@code ContactInfo} parameter. 52 | * 53 | * @param collisionShape1 The first collisionShape of the collision 54 | * @param transform1 The first shape's transform 55 | * @param collisionShape2 The second collisionShape of the collision 56 | * @param transform2 The second shape's transform 57 | * @param contactInfo Where to store the contact info of this collision 58 | * @return True if the volumes collided, false if not 59 | */ 60 | public abstract boolean testCollision( 61 | CollisionShape collisionShape1, Transform transform1, 62 | CollisionShape collisionShape2, Transform transform2, 63 | ContactPointInfo contactInfo); 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/flowpowered/react/collision/narrowphase/SphereVsSphereAlgorithm.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react.collision.narrowphase; 27 | 28 | import com.flowpowered.react.collision.shape.CollisionShape; 29 | import com.flowpowered.react.collision.shape.SphereShape; 30 | import com.flowpowered.react.constraint.ContactPoint.ContactPointInfo; 31 | import com.flowpowered.react.math.Transform; 32 | import com.flowpowered.react.math.Vector3; 33 | 34 | /** 35 | * This class is used to compute the narrow-phase collision detection between two sphere shaped collision volumes. 36 | */ 37 | public class SphereVsSphereAlgorithm extends NarrowPhaseAlgorithm { 38 | @Override 39 | public boolean testCollision(CollisionShape collisionShape1, Transform transform1, 40 | CollisionShape collisionShape2, Transform transform2, 41 | ContactPointInfo contactInfo) { 42 | final SphereShape sphereShape1 = (SphereShape) collisionShape1; 43 | final SphereShape sphereShape2 = (SphereShape) collisionShape2; 44 | final Vector3 vectorBetweenCenters = Vector3.subtract(transform2.getPosition(), transform1.getPosition()); 45 | final float squaredDistanceBetweenCenters = vectorBetweenCenters.lengthSquare(); 46 | final float sumRadius = sphereShape1.getRadius() + sphereShape2.getRadius(); 47 | if (squaredDistanceBetweenCenters <= sumRadius * sumRadius) { 48 | final Vector3 centerSphere2InBody1LocalSpace = Transform.multiply(transform1.getInverse(), transform2.getPosition()); 49 | final Vector3 centerSphere1InBody2LocalSpace = Transform.multiply(transform2.getInverse(), transform1.getPosition()); 50 | final Vector3 intersectionOnBody1 = Vector3.multiply(sphereShape1.getRadius(), centerSphere2InBody1LocalSpace.getUnit()); 51 | final Vector3 intersectionOnBody2 = Vector3.multiply(sphereShape2.getRadius(), centerSphere1InBody2LocalSpace.getUnit()); 52 | final float penetrationDepth = sumRadius - (float) Math.sqrt(squaredDistanceBetweenCenters); 53 | contactInfo.set(vectorBetweenCenters.getUnit(), penetrationDepth, intersectionOnBody1, intersectionOnBody2); 54 | return true; 55 | } 56 | return false; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/flowpowered/react/collision/shape/AABB.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react.collision.shape; 27 | 28 | import com.flowpowered.react.math.Vector3; 29 | 30 | /** 31 | * Represents a bounding volume of type "Axis Aligned Bounding Box". It's a box where all the edges are always aligned with the world coordinate system. The AABB is defined by the minimum and maximum 32 | * world coordinates of the three axis. 33 | */ 34 | public class AABB { 35 | private final Vector3 mMinCoordinates = new Vector3(); 36 | private final Vector3 mMaxCoordinates = new Vector3(); 37 | 38 | /** 39 | * Default constructor. Min and max are the both zero vector3s. 40 | */ 41 | public AABB() { 42 | } 43 | 44 | /** 45 | * Constructs a new AABB with the specified min and max vector3s. 46 | * 47 | * @param minCoordinates The minimum vector3 48 | * @param maxCoordinates The maximum vector3 49 | */ 50 | public AABB(Vector3 minCoordinates, Vector3 maxCoordinates) { 51 | mMinCoordinates.set(minCoordinates); 52 | mMaxCoordinates.set(maxCoordinates); 53 | } 54 | 55 | /** 56 | * Gets the center of this AABB as a new vector3. 57 | * 58 | * @return The center vector3 59 | */ 60 | public Vector3 getCenter() { 61 | return Vector3.multiply(Vector3.add(mMinCoordinates, mMaxCoordinates), 0.5f); 62 | } 63 | 64 | /** 65 | * Gets the minimum vector3 of this AABB. 66 | * 67 | * @return The minimum vector3 68 | */ 69 | public Vector3 getMin() { 70 | return mMinCoordinates; 71 | } 72 | 73 | /** 74 | * Gets the maximum vector3 of this AABB. 75 | * 76 | * @return The maximum vector3 77 | */ 78 | public Vector3 getMax() { 79 | return mMaxCoordinates; 80 | } 81 | 82 | /** 83 | * Sets the minimum vector3 of this AABB to the desired minimum. 84 | * 85 | * @param min the minimum vector3 to set 86 | */ 87 | public void setMin(Vector3 min) { 88 | mMinCoordinates.set(min); 89 | } 90 | 91 | /** 92 | * Sets the maximum vector3 of this AABB to the desired maximum. 93 | * 94 | * @param max the maximum vector3 to set 95 | */ 96 | public void setMax(Vector3 max) { 97 | mMaxCoordinates.set(max); 98 | } 99 | 100 | /** 101 | * Test whether or not two AABBs are colliding. Returns true if they are colliding, false if not. 102 | * 103 | * @param aabb The AABB to test for collision 104 | * @return True if the AABBs are colliding, false if not 105 | */ 106 | public boolean testCollision(AABB aabb) { 107 | if (mMaxCoordinates.getX() < aabb.getMin().getX() 108 | || aabb.getMax().getX() < mMinCoordinates.getX()) { 109 | return false; 110 | } 111 | if (mMaxCoordinates.getY() < aabb.getMin().getY() 112 | || aabb.getMax().getY() < mMinCoordinates.getY()) { 113 | return false; 114 | } 115 | if (mMaxCoordinates.getZ() < aabb.getMin().getZ() 116 | || aabb.getMax().getZ() < mMinCoordinates.getZ()) { 117 | return false; 118 | } 119 | return true; 120 | } 121 | 122 | @Override 123 | public String toString() { 124 | return "AABB{min= " + mMinCoordinates + ", max= " + mMaxCoordinates + "}"; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/main/java/com/flowpowered/react/collision/shape/BoxShape.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react.collision.shape; 27 | 28 | import com.flowpowered.react.ReactDefaults; 29 | import com.flowpowered.react.math.Matrix3x3; 30 | import com.flowpowered.react.math.Vector3; 31 | 32 | /** 33 | * Represents a 3D box shape. Those axis are unit length. The three extents are half-lengths of the box along the three x, y, z local axes. The "transform" of the corresponding rigid body will give an 34 | * orientation and a position to the box. This collision shape uses an extra margin distance around it for collision detection purpose. The default margin is 4cm (if your units are meters, which is 35 | * recommended). In case, you want to simulate small objects (smaller than the margin distance), you might want to reduce the margin by specifying your own margin distance using the "margin" parameter 36 | * in the constructor of the box shape. Otherwise, it is recommended to use the default margin distance by not using the "margin" parameter in the constructor. 37 | */ 38 | public class BoxShape extends CollisionShape { 39 | private final Vector3 mExtent = new Vector3(); 40 | 41 | /** 42 | * Constructs a box shape from the components of its extents which is half the vector between the two opposing corners that are the furthest away. 43 | * 44 | * @param x The x extent 45 | * @param y The y extent 46 | * @param z The z extent 47 | */ 48 | public BoxShape(float x, float y, float z) { 49 | this(new Vector3(x, y, z), ReactDefaults.OBJECT_MARGIN); 50 | } 51 | 52 | /** 53 | * Constructs a box shape from its extents which is half the vector between the two opposing corners that are the furthest away. 54 | * 55 | * @param extent The extent vector 56 | */ 57 | public BoxShape(Vector3 extent) { 58 | this(extent, ReactDefaults.OBJECT_MARGIN); 59 | } 60 | 61 | /** 62 | * Constructs a box shape from its extents which is half the vector between the two opposing corners that are the furthest away and the AABB margin. 63 | * 64 | * @param extent The extent vector 65 | * @param margin The margin 66 | */ 67 | public BoxShape(Vector3 extent, float margin) { 68 | super(CollisionShapeType.BOX, margin); 69 | mExtent.set(Vector3.subtract(extent, new Vector3(margin, margin, margin))); 70 | if (extent.getX() <= 0 || extent.getX() <= margin) { 71 | throw new IllegalArgumentException("Extent x coordinate must be greater than 0 and the margin"); 72 | } 73 | if (extent.getY() <= 0 || extent.getY() <= margin) { 74 | throw new IllegalArgumentException("Extent y coordinate must be greater than 0 and the margin"); 75 | } 76 | if (extent.getZ() <= 0 || extent.getZ() <= margin) { 77 | throw new IllegalArgumentException("Extent z coordinate must be greater than 0 and the margin"); 78 | } 79 | if (margin <= 0) { 80 | throw new IllegalArgumentException("Margin must be greater than 0"); 81 | } 82 | } 83 | 84 | /** 85 | * Copy constructor. 86 | * 87 | * @param shape The shape to copy 88 | */ 89 | public BoxShape(BoxShape shape) { 90 | super(shape); 91 | mExtent.set(shape.mExtent); 92 | } 93 | 94 | /** 95 | * Gets the extent vector, which is half the vector between the two opposing corners that are the furthest away. 96 | * 97 | * @return The extents vector 98 | */ 99 | public Vector3 getExtent() { 100 | return Vector3.add(mExtent, new Vector3(mMargin, mMargin, mMargin)); 101 | } 102 | 103 | @Override 104 | public Vector3 getLocalSupportPointWithMargin(Vector3 direction) { 105 | if (mMargin < 0) { 106 | throw new IllegalStateException("margin must be greater than zero"); 107 | } 108 | return new Vector3( 109 | direction.getX() < 0 ? -mExtent.getX() - mMargin : mExtent.getX() + mMargin, 110 | direction.getY() < 0 ? -mExtent.getY() - mMargin : mExtent.getY() + mMargin, 111 | direction.getZ() < 0 ? -mExtent.getZ() - mMargin : mExtent.getZ() + mMargin); 112 | } 113 | 114 | @Override 115 | public Vector3 getLocalSupportPointWithoutMargin(Vector3 direction) { 116 | return new Vector3( 117 | direction.getX() < 0 ? -mExtent.getX() : mExtent.getX(), 118 | direction.getY() < 0 ? -mExtent.getY() : mExtent.getY(), 119 | direction.getZ() < 0 ? -mExtent.getZ() : mExtent.getZ()); 120 | } 121 | 122 | @Override 123 | public void getLocalBounds(Vector3 min, Vector3 max) { 124 | max.set(Vector3.add(mExtent, new Vector3(mMargin, mMargin, mMargin))); 125 | min.set(Vector3.negate(max)); 126 | } 127 | 128 | @Override 129 | public void computeLocalInertiaTensor(Matrix3x3 tensor, float mass) { 130 | final float factor = (1f / 3) * mass; 131 | Vector3 realExtent = Vector3.add(mExtent, new Vector3(mMargin, mMargin, mMargin)); 132 | final float xSquare = realExtent.getX() * realExtent.getX(); 133 | final float ySquare = realExtent.getY() * realExtent.getY(); 134 | final float zSquare = realExtent.getZ() * realExtent.getZ(); 135 | tensor.setAllValues( 136 | factor * (ySquare + zSquare), 0, 0, 137 | 0, factor * (xSquare + zSquare), 0, 138 | 0, 0, factor * (xSquare + ySquare)); 139 | } 140 | 141 | @Override 142 | public BoxShape clone() { 143 | return new BoxShape(this); 144 | } 145 | 146 | @Override 147 | public boolean isEqualTo(CollisionShape otherCollisionShape) { 148 | final BoxShape otherShape = (BoxShape) otherCollisionShape; 149 | return mExtent.equals(otherShape.mExtent); 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/main/java/com/flowpowered/react/collision/shape/CapsuleShape.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react.collision.shape; 27 | 28 | import com.flowpowered.react.ReactDefaults; 29 | import com.flowpowered.react.math.Matrix3x3; 30 | import com.flowpowered.react.math.Vector3; 31 | 32 | /** 33 | * Represents a capsule collision shape that is defined around the Y axis. A capsule shape can be seen as the convex hull of two spheres. The capsule shape is defined by its radius (radius of the two 34 | * spheres of the capsule) and its height (distance between the centers of the two spheres). This collision shape does not have an explicit object margin distance. The margin is implicitly the radius 35 | * and height of the shape. Therefore, there is no need to specify an object margin for a capsule shape. 36 | */ 37 | public class CapsuleShape extends CollisionShape { 38 | private final float mRadius; 39 | private final float mHalfHeight; 40 | 41 | /** 42 | * Constructs a new capsule shape from its radius and height. 43 | * 44 | * @param radius The radius 45 | * @param height The height 46 | */ 47 | public CapsuleShape(float radius, float height) { 48 | super(CollisionShapeType.CAPSULE, radius); 49 | mRadius = radius; 50 | mHalfHeight = height * 0.5f; 51 | if (radius <= 0) { 52 | throw new IllegalArgumentException("Radius must be greater than zero"); 53 | } 54 | if (height <= 0) { 55 | throw new IllegalArgumentException("Height must be greater than zero"); 56 | } 57 | } 58 | 59 | /** 60 | * Copy constructor. 61 | * 62 | * @param shape The shape to copy 63 | */ 64 | public CapsuleShape(CapsuleShape shape) { 65 | super(shape); 66 | mRadius = shape.mRadius; 67 | mHalfHeight = shape.mHalfHeight; 68 | } 69 | 70 | /** 71 | * Returns the radius of the spherical ends of the capsule. 72 | * 73 | * @return The radius of the capsule 74 | */ 75 | public float getRadius() { 76 | return mRadius; 77 | } 78 | 79 | /** 80 | * Returns the distance between the middle of the two hemispheres. 81 | * 82 | * @return The height of the capsule 83 | */ 84 | public float getHeight() { 85 | return mHalfHeight + mHalfHeight; 86 | } 87 | 88 | @Override 89 | public Vector3 getLocalSupportPointWithMargin(Vector3 direction) { 90 | if (direction.lengthSquare() >= ReactDefaults.MACHINE_EPSILON * ReactDefaults.MACHINE_EPSILON) { 91 | final Vector3 unitDirection = direction.getUnit(); 92 | final Vector3 centerTopSphere = new Vector3(0, mHalfHeight, 0); 93 | final Vector3 topSpherePoint = Vector3.add(centerTopSphere, Vector3.multiply(unitDirection, mRadius)); 94 | final float dotProductTop = topSpherePoint.dot(direction); 95 | final Vector3 centerBottomSphere = new Vector3(0, -mHalfHeight, 0); 96 | final Vector3 bottomSpherePoint = Vector3.add(centerBottomSphere, Vector3.multiply(unitDirection, mRadius)); 97 | final float dotProductBottom = bottomSpherePoint.dot(direction); 98 | if (dotProductTop > dotProductBottom) { 99 | return topSpherePoint; 100 | } else { 101 | return bottomSpherePoint; 102 | } 103 | } 104 | return new Vector3(0, mRadius, 0); 105 | } 106 | 107 | @Override 108 | public Vector3 getLocalSupportPointWithoutMargin(Vector3 direction) { 109 | if (direction.getY() > 0) { 110 | return new Vector3(0, mHalfHeight, 0); 111 | } else { 112 | return new Vector3(0, -mHalfHeight, 0); 113 | } 114 | } 115 | 116 | @Override 117 | public void getLocalBounds(Vector3 min, Vector3 max) { 118 | max.setX(mRadius); 119 | max.setY(mHalfHeight + mRadius); 120 | max.setZ(mRadius); 121 | min.setX(-mRadius); 122 | min.setY(-max.getY()); 123 | min.setZ(min.getX()); 124 | } 125 | 126 | @Override 127 | public void computeLocalInertiaTensor(Matrix3x3 tensor, float mass) { 128 | final float height = mHalfHeight + mHalfHeight; 129 | final float radiusSquare = mRadius * mRadius; 130 | final float heightSquare = height * height; 131 | final float radiusSquareDouble = radiusSquare + radiusSquare; 132 | final float factor1 = 2 * mRadius / (4 * mRadius + 3 * height); 133 | final float factor2 = 3 * height / (4 * mRadius + 3 * height); 134 | final float sum1 = 0.4f * radiusSquareDouble; 135 | final float sum2 = 0.75f * height * mRadius + 0.5f * heightSquare; 136 | final float sum3 = 0.25f * radiusSquare + 1f / 12 * heightSquare; 137 | final float IxxAndzz = factor1 * mass * (sum1 + sum2) + factor2 * mass * sum3; 138 | final float Iyy = factor1 * mass * sum1 + factor2 * mass * 0.25f * radiusSquareDouble; 139 | tensor.setAllValues( 140 | IxxAndzz, 0, 0, 141 | 0, Iyy, 0, 142 | 0, 0, IxxAndzz); 143 | } 144 | 145 | @Override 146 | public CollisionShape clone() { 147 | return new CapsuleShape(this); 148 | } 149 | 150 | @Override 151 | public boolean isEqualTo(CollisionShape otherCollisionShape) { 152 | final CapsuleShape otherShape = (CapsuleShape) otherCollisionShape; 153 | return mRadius == otherShape.mRadius && mHalfHeight == otherShape.mHalfHeight; 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /src/main/java/com/flowpowered/react/collision/shape/CollisionShape.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react.collision.shape; 27 | 28 | import com.flowpowered.react.math.Matrix3x3; 29 | import com.flowpowered.react.math.Transform; 30 | import com.flowpowered.react.math.Vector3; 31 | 32 | /** 33 | * Represents the collision shape associated with a body that is used during the narrow-phase collision detection. 34 | */ 35 | public abstract class CollisionShape { 36 | protected final CollisionShapeType mType; 37 | private int mNbSimilarCreatedShapes; 38 | protected final float mMargin; 39 | 40 | /** 41 | * Constructs a new collision shape from its type. 42 | * 43 | * @param type The type of the collision shape 44 | */ 45 | protected CollisionShape(CollisionShapeType type, float margin) { 46 | mType = type; 47 | mNbSimilarCreatedShapes = 0; 48 | mMargin = margin; 49 | } 50 | 51 | /** 52 | * Copy constructor. 53 | * 54 | * @param shape The shape to copy 55 | */ 56 | protected CollisionShape(CollisionShape shape) { 57 | mType = shape.mType; 58 | mNbSimilarCreatedShapes = shape.mNbSimilarCreatedShapes; 59 | mMargin = shape.mMargin; 60 | } 61 | 62 | /** 63 | * Gets the type of collision shape associated to this shape. 64 | * 65 | * @return The collision shape type 66 | */ 67 | public CollisionShapeType getType() { 68 | return mType; 69 | } 70 | 71 | /** 72 | * Gets the margin distance around the shape. 73 | * 74 | * @return The margin for the shape 75 | */ 76 | public float getMargin() { 77 | return mMargin; 78 | } 79 | 80 | /** 81 | * Gets a local support point in a given direction with the object margin. 82 | * 83 | * @param direction The desired direction 84 | * @return The local support point as a vector3 85 | */ 86 | public abstract Vector3 getLocalSupportPointWithMargin(Vector3 direction); 87 | 88 | /** 89 | * Gets a local support point in a given direction without the object margin. 90 | * 91 | * @param direction The desired direction 92 | * @return The local support point as a vector3 93 | */ 94 | public abstract Vector3 getLocalSupportPointWithoutMargin(Vector3 direction); 95 | 96 | /** 97 | * Gets the local extents in x,y and z direction. 98 | * 99 | * @param min Where to store the minimum point of the bounds 100 | * @param max Where to store the maximum point of the bounds 101 | */ 102 | public abstract void getLocalBounds(Vector3 min, Vector3 max); 103 | 104 | /** 105 | * Computes the local inertia tensor of the collision shape for the mass. Stores the results in the passed matrix3x3. 106 | * 107 | * @param tensor The matrix3x3 in which the tensor should be stored 108 | * @param mass The mass of the shape 109 | */ 110 | public abstract void computeLocalInertiaTensor(Matrix3x3 tensor, float mass); 111 | 112 | /** 113 | * Allocates and returns a copy of the object. 114 | * 115 | * @return A copy of the objects 116 | */ 117 | @Override 118 | public abstract CollisionShape clone(); 119 | 120 | /** 121 | * Tests equality between two collision shapes of the same type (same derived classes). 122 | * 123 | * @param otherCollisionShape The shape to test for equality 124 | */ 125 | public abstract boolean isEqualTo(CollisionShape otherCollisionShape); 126 | 127 | /** 128 | * Update the AABB of a body using its collision shape. 129 | * 130 | * @param aabb The AABB to update 131 | * @param transform The AABB's transform 132 | */ 133 | public void updateAABB(AABB aabb, Transform transform) { 134 | final Vector3 minBounds = new Vector3(); 135 | final Vector3 maxBounds = new Vector3(); 136 | getLocalBounds(minBounds, maxBounds); 137 | final Matrix3x3 worldAxis = transform.getOrientation().getMatrix().getAbsoluteMatrix(); 138 | final Vector3 worldMinBounds = new Vector3( 139 | worldAxis.getColumn(0).dot(minBounds), 140 | worldAxis.getColumn(1).dot(minBounds), 141 | worldAxis.getColumn(2).dot(minBounds)); 142 | final Vector3 worldMaxBounds = new Vector3( 143 | worldAxis.getColumn(0).dot(maxBounds), 144 | worldAxis.getColumn(1).dot(maxBounds), 145 | worldAxis.getColumn(2).dot(maxBounds)); 146 | final Vector3 minCoordinates = Vector3.add(transform.getPosition(), worldMinBounds); 147 | final Vector3 maxCoordinates = Vector3.add(transform.getPosition(), worldMaxBounds); 148 | aabb.setMin(minCoordinates); 149 | aabb.setMax(maxCoordinates); 150 | } 151 | 152 | /** 153 | * Returns the number of similar created shapes. 154 | * 155 | * @return The number of similar created shapes 156 | */ 157 | public int getNbSimilarCreatedShapes() { 158 | return mNbSimilarCreatedShapes; 159 | } 160 | 161 | /** 162 | * Increments the number of similar allocated collision shapes. 163 | */ 164 | public void incrementNbSimilarCreatedShapes() { 165 | mNbSimilarCreatedShapes++; 166 | } 167 | 168 | /** 169 | * Decrements the number of similar allocated collision shapes. 170 | */ 171 | public void decrementNbSimilarCreatedShapes() { 172 | mNbSimilarCreatedShapes--; 173 | } 174 | 175 | @Override 176 | public boolean equals(Object o) { 177 | if (this == o) { 178 | return true; 179 | } 180 | if (!(o instanceof CollisionShape)) { 181 | return false; 182 | } 183 | final CollisionShape that = (CollisionShape) o; 184 | return mMargin == that.mMargin && mType == that.mType && that.isEqualTo(this); 185 | } 186 | 187 | @Override 188 | protected void finalize() throws Throwable { 189 | try { 190 | if (mNbSimilarCreatedShapes != 0) { 191 | // Thrown exceptions are ignored, so we need to print instead 192 | System.err.println("The number of similar created shapes should be 0, is " + mNbSimilarCreatedShapes + " instead"); 193 | } 194 | } finally { 195 | super.finalize(); 196 | } 197 | } 198 | 199 | /** 200 | * An enumeration of the possible collision shape (box, sphere, cone and cylinder). 201 | */ 202 | public static enum CollisionShapeType { 203 | BOX, 204 | SPHERE, 205 | CONE, 206 | CYLINDER, 207 | CAPSULE, 208 | CONVEX_MESH 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /src/main/java/com/flowpowered/react/collision/shape/ConeShape.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react.collision.shape; 27 | 28 | import com.flowpowered.react.ReactDefaults; 29 | import com.flowpowered.react.math.Matrix3x3; 30 | import com.flowpowered.react.math.Vector3; 31 | 32 | /** 33 | * Represents a cone collision shape centered at the origin and aligned with the Y axis. The cone is defined by its height and by the radius of its base. The center of the cone is at the half of the 34 | * height. The "transform" of the corresponding rigid body gives an orientation and a position to the cone. This collision shape uses an extra margin distance around it for collision detection 35 | * purpose. The default margin is 4cm (if your units are meters, which is recommended). In case, you want to simulate small objects (smaller than the margin distance), you might want to reduce the 36 | * margin by specifying your own margin distance using the "margin" parameter in the constructor of the cone shape. Otherwise, it is recommended to use the default margin distance by not using the 37 | * "margin" parameter in the constructor. 38 | */ 39 | public class ConeShape extends CollisionShape { 40 | private final float mRadius; 41 | private final float mHalfHeight; 42 | private final float mSinTheta; 43 | 44 | /** 45 | * Constructs a new cone shape from the radius of the base and the height. 46 | * 47 | * @param radius The radius of the base 48 | * @param height The height 49 | */ 50 | public ConeShape(float radius, float height) { 51 | this(radius, height, ReactDefaults.OBJECT_MARGIN); 52 | } 53 | 54 | /** 55 | * Constructs a new cone shape from the radius of the base and the height and the AABB margin. 56 | * 57 | * @param radius The radius of the base 58 | * @param height The height 59 | * @param margin The margin 60 | */ 61 | public ConeShape(float radius, float height, float margin) { 62 | super(CollisionShapeType.CONE, margin); 63 | mRadius = radius; 64 | mHalfHeight = height * 0.5f; 65 | if (mRadius <= 0) { 66 | throw new IllegalArgumentException("Radius must be greater than zero"); 67 | } 68 | if (mHalfHeight <= 0) { 69 | throw new IllegalArgumentException("Height must be greater than zero"); 70 | } 71 | if (margin <= 0) { 72 | throw new IllegalArgumentException("Margin must be greater than 0"); 73 | } 74 | mSinTheta = mRadius / (float) Math.sqrt(mRadius * mRadius + height * height); 75 | } 76 | 77 | /** 78 | * Copy constructor. 79 | * 80 | * @param shape The shape to copy 81 | */ 82 | public ConeShape(ConeShape shape) { 83 | super(shape); 84 | mRadius = shape.mRadius; 85 | mHalfHeight = shape.mHalfHeight; 86 | mSinTheta = shape.mSinTheta; 87 | } 88 | 89 | /** 90 | * Gets the radius of the base. 91 | * 92 | * @return The radius 93 | */ 94 | public float getRadius() { 95 | return mRadius; 96 | } 97 | 98 | /** 99 | * Gets the height of the cone. 100 | * 101 | * @return The height 102 | */ 103 | public float getHeight() { 104 | return mHalfHeight + mHalfHeight; 105 | } 106 | 107 | @Override 108 | public Vector3 getLocalSupportPointWithMargin(Vector3 direction) { 109 | final Vector3 supportPoint = getLocalSupportPointWithoutMargin(direction); 110 | final Vector3 unitVec; 111 | if (direction.lengthSquare() > ReactDefaults.MACHINE_EPSILON * ReactDefaults.MACHINE_EPSILON) { 112 | unitVec = direction.getUnit(); 113 | } else { 114 | unitVec = new Vector3(0, -1, 0); 115 | } 116 | supportPoint.add(Vector3.multiply(unitVec, mMargin)); 117 | return supportPoint; 118 | } 119 | 120 | @Override 121 | public Vector3 getLocalSupportPointWithoutMargin(Vector3 direction) { 122 | final Vector3 v = direction; 123 | final float sinThetaTimesLengthV = mSinTheta * v.length(); 124 | final Vector3 supportPoint; 125 | if (v.getY() > sinThetaTimesLengthV) { 126 | supportPoint = new Vector3(0, mHalfHeight, 0); 127 | } else { 128 | final float projectedLength = (float) Math.sqrt(v.getX() * v.getX() + v.getZ() * v.getZ()); 129 | if (projectedLength > ReactDefaults.MACHINE_EPSILON) { 130 | final float d = mRadius / projectedLength; 131 | supportPoint = new Vector3(v.getX() * d, -mHalfHeight, v.getZ() * d); 132 | } else { 133 | supportPoint = new Vector3(0, -mHalfHeight, 0); 134 | } 135 | } 136 | return supportPoint; 137 | } 138 | 139 | @Override 140 | public void getLocalBounds(Vector3 min, Vector3 max) { 141 | max.setX(mRadius + mMargin); 142 | max.setY(mHalfHeight + mMargin); 143 | max.setZ(max.getX()); 144 | min.setX(-max.getX()); 145 | min.setY(-max.getY()); 146 | min.setZ(min.getX()); 147 | } 148 | 149 | @Override 150 | public void computeLocalInertiaTensor(Matrix3x3 tensor, float mass) { 151 | final float rSquare = mRadius * mRadius; 152 | final float diagXZ = 0.15f * mass * (rSquare + mHalfHeight); 153 | tensor.setAllValues( 154 | diagXZ, 0, 0, 155 | 0, 0.3f * mass * rSquare, 0, 156 | 0, 0, diagXZ); 157 | } 158 | 159 | @Override 160 | public ConeShape clone() { 161 | return new ConeShape(this); 162 | } 163 | 164 | @Override 165 | public boolean isEqualTo(CollisionShape otherCollisionShape) { 166 | final ConeShape otherShape = (ConeShape) otherCollisionShape; 167 | return mRadius == otherShape.mRadius && mHalfHeight == otherShape.mHalfHeight; 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /src/main/java/com/flowpowered/react/collision/shape/CylinderShape.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react.collision.shape; 27 | 28 | import com.flowpowered.react.ReactDefaults; 29 | import com.flowpowered.react.math.Matrix3x3; 30 | import com.flowpowered.react.math.Vector3; 31 | 32 | /** 33 | * Represents a cylinder collision shape around the Y axis and centered at the origin. The cylinder is defined by its height and the radius of its base. The "transform" of the corresponding rigid body 34 | * gives an orientation and a position to the cylinder. This collision shape uses an extra margin distance around it for collision detection purpose. The default margin is 4cm (if your units are 35 | * meters, which is recommended). In case, you want to simulate small objects (smaller than the margin distance), you might want to reduce the margin by specifying your own margin distance using the 36 | * "margin" parameter in the constructor of the cylinder shape. Otherwise, it is recommended to use the default margin distance by not using the "margin" parameter in the constructor. 37 | */ 38 | public class CylinderShape extends CollisionShape { 39 | private final float mRadius; 40 | private final float mHalfHeight; 41 | 42 | /** 43 | * Constructs a new cylinder from the radius of the base and the height. 44 | * 45 | * @param radius The radius of the base 46 | * @param height The height 47 | */ 48 | public CylinderShape(float radius, float height) { 49 | this(radius, height, ReactDefaults.OBJECT_MARGIN); 50 | } 51 | 52 | /** 53 | * Constructs a new cylinder from the radius of the base and the height and the AABB margin. 54 | * 55 | * @param radius The radius of the base 56 | * @param height The height 57 | * @param margin The margin 58 | */ 59 | public CylinderShape(float radius, float height, float margin) { 60 | super(CollisionShapeType.CYLINDER, margin); 61 | mRadius = radius; 62 | mHalfHeight = height / 2; 63 | if (mRadius <= 0) { 64 | throw new IllegalArgumentException("Radius must be greater than zero"); 65 | } 66 | if (height <= 0) { 67 | throw new IllegalArgumentException("Height must be greater than zero"); 68 | } 69 | if (margin <= 0) { 70 | throw new IllegalArgumentException("Margin must be greater than 0"); 71 | } 72 | } 73 | 74 | /** 75 | * Copy constructor. 76 | * 77 | * @param shape The shape to copy 78 | */ 79 | public CylinderShape(CylinderShape shape) { 80 | super(shape); 81 | mRadius = shape.mRadius; 82 | mHalfHeight = shape.mHalfHeight; 83 | } 84 | 85 | /** 86 | * Gets the radius of the base. 87 | * 88 | * @return The radius 89 | */ 90 | public float getRadius() { 91 | return mRadius; 92 | } 93 | 94 | /** 95 | * Gets the height of the cylinder. 96 | * 97 | * @return The height 98 | */ 99 | public float getHeight() { 100 | return mHalfHeight + mHalfHeight; 101 | } 102 | 103 | @Override 104 | public Vector3 getLocalSupportPointWithMargin(Vector3 direction) { 105 | final Vector3 supportPoint = getLocalSupportPointWithoutMargin(direction); 106 | final Vector3 unitVec; 107 | if (direction.lengthSquare() > ReactDefaults.MACHINE_EPSILON * ReactDefaults.MACHINE_EPSILON) { 108 | unitVec = direction.getUnit(); 109 | } else { 110 | unitVec = new Vector3(0, 1, 0); 111 | } 112 | supportPoint.add(Vector3.multiply(unitVec, mMargin)); 113 | return supportPoint; 114 | } 115 | 116 | @Override 117 | public Vector3 getLocalSupportPointWithoutMargin(Vector3 direction) { 118 | final Vector3 supportPoint = new Vector3(0, 0, 0); 119 | final float uDotv = direction.getY(); 120 | final Vector3 w = new Vector3(direction.getX(), 0, direction.getZ()); 121 | final float lengthW = (float) Math.sqrt(direction.getX() * direction.getX() + direction.getZ() * direction.getZ()); 122 | if (lengthW > ReactDefaults.MACHINE_EPSILON) { 123 | if (uDotv < 0.0) { 124 | supportPoint.setY(-mHalfHeight); 125 | } else { 126 | supportPoint.setY(mHalfHeight); 127 | } 128 | supportPoint.add(Vector3.multiply(mRadius / lengthW, w)); 129 | } else { 130 | if (uDotv < 0.0) { 131 | supportPoint.setY(-mHalfHeight); 132 | } else { 133 | supportPoint.setY(mHalfHeight); 134 | } 135 | } 136 | return supportPoint; 137 | } 138 | 139 | @Override 140 | public void getLocalBounds(Vector3 min, Vector3 max) { 141 | max.setX(mRadius + mMargin); 142 | max.setY(mHalfHeight + mMargin); 143 | max.setZ(max.getX()); 144 | min.setX(-max.getX()); 145 | min.setY(-max.getY()); 146 | min.setZ(min.getX()); 147 | } 148 | 149 | @Override 150 | public void computeLocalInertiaTensor(Matrix3x3 tensor, float mass) { 151 | final float height = 2 * mHalfHeight; 152 | final float diag = (1f / 12) * mass * (3 * mRadius * mRadius + height * height); 153 | tensor.setAllValues( 154 | diag, 0, 0, 155 | 0, 0.5f * mass * mRadius * mRadius, 0, 156 | 0, 0, diag); 157 | } 158 | 159 | @Override 160 | public CylinderShape clone() { 161 | return new CylinderShape(this); 162 | } 163 | 164 | @Override 165 | public boolean isEqualTo(CollisionShape otherCollisionShape) { 166 | final CylinderShape otherShape = (CylinderShape) otherCollisionShape; 167 | return mRadius == otherShape.mRadius && mHalfHeight == otherShape.mHalfHeight; 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /src/main/java/com/flowpowered/react/collision/shape/SphereShape.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react.collision.shape; 27 | 28 | import com.flowpowered.react.ReactDefaults; 29 | import com.flowpowered.react.math.Matrix3x3; 30 | import com.flowpowered.react.math.Transform; 31 | import com.flowpowered.react.math.Vector3; 32 | 33 | /** 34 | * Represents a sphere collision shape that is centered at the origin and defined by its radius. This collision shape does not have an explicit object margin distance. The margin is implicitly the 35 | * radius of the sphere. Therefore, there is no need to specify an object margin for a sphere shape. 36 | */ 37 | public class SphereShape extends CollisionShape { 38 | private final float mRadius; 39 | 40 | /** 41 | * Constructs a new sphere from the radius. 42 | * 43 | * @param radius The radius 44 | */ 45 | public SphereShape(float radius) { 46 | super(CollisionShapeType.SPHERE, radius); 47 | mRadius = radius; 48 | if (radius <= 0) { 49 | throw new IllegalArgumentException("Radius must be greater than zero"); 50 | } 51 | } 52 | 53 | /** 54 | * Copy constructor. 55 | * 56 | * @param shape The shape to copy 57 | */ 58 | public SphereShape(SphereShape shape) { 59 | super(shape); 60 | mRadius = shape.mRadius; 61 | } 62 | 63 | /** 64 | * Gets the radius. 65 | * 66 | * @return The radius 67 | */ 68 | public float getRadius() { 69 | return mRadius; 70 | } 71 | 72 | @Override 73 | public Vector3 getLocalSupportPointWithMargin(Vector3 direction) { 74 | if (direction.lengthSquare() >= ReactDefaults.MACHINE_EPSILON * ReactDefaults.MACHINE_EPSILON) { 75 | return Vector3.multiply(mMargin, direction.getUnit()); 76 | } 77 | return new Vector3(0, mMargin, 0); 78 | } 79 | 80 | @Override 81 | public Vector3 getLocalSupportPointWithoutMargin(Vector3 direction) { 82 | return new Vector3(0, 0, 0); 83 | } 84 | 85 | @Override 86 | public void getLocalBounds(Vector3 min, Vector3 max) { 87 | max.setX(mRadius); 88 | max.setY(mRadius); 89 | max.setZ(mRadius); 90 | min.setX(-mRadius); 91 | min.setY(min.getX()); 92 | min.setZ(min.getX()); 93 | } 94 | 95 | @Override 96 | public void computeLocalInertiaTensor(Matrix3x3 tensor, float mass) { 97 | final float diag = 0.4f * mass * mRadius * mRadius; 98 | tensor.setAllValues( 99 | diag, 0, 0, 100 | 0, diag, 0, 101 | 0, 0, diag); 102 | } 103 | 104 | @Override 105 | public void updateAABB(AABB aabb, Transform transform) { 106 | final Vector3 extents = new Vector3(mRadius, mRadius, mRadius); 107 | aabb.setMin(Vector3.subtract(transform.getPosition(), extents)); 108 | aabb.setMax(Vector3.add(transform.getPosition(), extents)); 109 | } 110 | 111 | @Override 112 | public SphereShape clone() { 113 | return new SphereShape(this); 114 | } 115 | 116 | @Override 117 | public boolean isEqualTo(CollisionShape otherCollisionShape) { 118 | final SphereShape otherShape = (SphereShape) otherCollisionShape; 119 | return mRadius == otherShape.mRadius; 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/main/java/com/flowpowered/react/engine/CollisionWorld.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react.engine; 27 | 28 | import java.util.ArrayList; 29 | import java.util.HashMap; 30 | import java.util.HashSet; 31 | import java.util.List; 32 | import java.util.Map; 33 | import java.util.Set; 34 | 35 | import gnu.trove.stack.TIntStack; 36 | import gnu.trove.stack.array.TIntArrayStack; 37 | 38 | import com.flowpowered.react.Utilities.IntPair; 39 | import com.flowpowered.react.body.CollisionBody; 40 | import com.flowpowered.react.collision.BroadPhasePair; 41 | import com.flowpowered.react.collision.CollisionDetection; 42 | import com.flowpowered.react.collision.RayCaster; 43 | import com.flowpowered.react.collision.RayCaster.IntersectedBody; 44 | import com.flowpowered.react.collision.shape.CollisionShape; 45 | import com.flowpowered.react.constraint.ContactPoint.ContactPointInfo; 46 | import com.flowpowered.react.math.Vector3; 47 | 48 | /** 49 | * Represents a world where it is possible to move bodies by hand and to test collisions between them. In this kind of world the body movement is not computed using the laws of physics. 50 | */ 51 | public abstract class CollisionWorld { 52 | protected final CollisionDetection mCollisionDetection; 53 | protected final Set mBodies = new HashSet<>(); 54 | protected final List mCollisionShapes = new ArrayList<>(); 55 | protected final Map mOverlappingPairs = new HashMap<>(); 56 | protected int mCurrentBodyID = 0; 57 | protected final TIntStack mFreeBodiesIDs = new TIntArrayStack(); 58 | 59 | /** 60 | * Constructs a new empty collision world. 61 | */ 62 | protected CollisionWorld() { 63 | mCollisionDetection = new CollisionDetection(this); 64 | } 65 | 66 | /** 67 | * Notifies the world about a new broad-phase overlapping pair. 68 | * 69 | * @param addedPair The pair that was added 70 | */ 71 | public abstract void notifyAddedOverlappingPair(BroadPhasePair addedPair); 72 | 73 | /** 74 | * Notifies the world about a removed broad-phase overlapping pair. 75 | * 76 | * @param removedPair The pair that was removed 77 | */ 78 | public abstract void notifyRemovedOverlappingPair(BroadPhasePair removedPair); 79 | 80 | /** 81 | * Notifies the world about a new narrow-phase contact. 82 | * 83 | * @param pair The pair of bodies in contact 84 | * @param contactInfo The information for the contact 85 | */ 86 | public abstract void notifyNewContact(BroadPhasePair pair, ContactPointInfo contactInfo); 87 | 88 | /** 89 | * Updates the overlapping pair. 90 | * 91 | * @param pair The pair to update 92 | */ 93 | public abstract void updateOverlappingPair(BroadPhasePair pair); 94 | 95 | /** 96 | * Gets the set of the bodies of the physics world. 97 | * 98 | * @return The {@link java.util.Set} of {@link com.flowpowered.react.body.CollisionBody} 99 | */ 100 | public Set getBodies() { 101 | return mBodies; 102 | } 103 | 104 | /** 105 | * Finds the closest of the bodies in the world intersecting with the ray to the ray start. The ray is defined by a starting point and a direction. This method returns an {@link IntersectedBody} 106 | * object containing the body and the intersection point. 107 | * 108 | * @param rayStart The ray starting point 109 | * @param rayDir The ray direction 110 | * @return The closest body to the ray start and its intersection point 111 | */ 112 | public IntersectedBody findClosestIntersectingBody(Vector3 rayStart, Vector3 rayDir) { 113 | return RayCaster.findClosestIntersectingBody(rayStart, rayDir, mBodies); 114 | } 115 | 116 | /** 117 | * Finds the furthest of the bodies in the world intersecting with the ray from the ray start. The ray is defined by a starting point and a direction. This method returns an {@link 118 | * IntersectedBody} object containing the body and the intersection point. 119 | * 120 | * @param rayStart The ray starting point 121 | * @param rayDir The ray direction 122 | * @return The furthest body from the ray start and its intersection point 123 | */ 124 | public IntersectedBody findFurthestIntersectingBody(Vector3 rayStart, Vector3 rayDir) { 125 | return RayCaster.findFurthestIntersectingBody(rayStart, rayDir, mBodies); 126 | } 127 | 128 | /** 129 | * Finds all of the bodies in the world intersecting with the ray. The ray is defined by a starting point and a direction. The bodies are returned mapped with the closest intersection point. 130 | * 131 | * @param rayStart The ray starting point 132 | * @param rayDir The ray direction 133 | * @return All of the intersection bodies, in no particular order, mapped to the distance vector 134 | */ 135 | public Map findIntersectingBodies(Vector3 rayStart, Vector3 rayDir) { 136 | return RayCaster.findIntersectingBodies(rayStart, rayDir, mBodies); 137 | } 138 | 139 | /** 140 | * Returns the next available body ID for this world. 141 | * 142 | * @return The next available id 143 | * @throws IllegalStateException If the id for the body is greater than Integer.MAX_VALUE 144 | */ 145 | public int getNextFreeID() { 146 | final int bodyID; 147 | if (mFreeBodiesIDs.size() != 0) { 148 | bodyID = mFreeBodiesIDs.pop(); 149 | } else { 150 | bodyID = mCurrentBodyID; 151 | mCurrentBodyID++; 152 | } 153 | if (bodyID >= Integer.MAX_VALUE) { 154 | throw new IllegalStateException("body id cannot be larger or equal to the largest integer"); 155 | } 156 | return bodyID; 157 | } 158 | 159 | /** 160 | * Creates a new collision shape. First, this methods checks that the new collision shape does not exist yet in the world. If it already exists, we do not allocate memory for a new one but instead 161 | * we reuse the existing one. The goal is to only allocate memory for a single collision shape if this one is used for several bodies in the world. 162 | * 163 | * @param collisionShape The collision shape to create 164 | * @return The desired collision shape 165 | */ 166 | protected CollisionShape createCollisionShape(CollisionShape collisionShape) { 167 | for (CollisionShape shape : mCollisionShapes) { 168 | if (collisionShape.equals(shape)) { 169 | shape.incrementNbSimilarCreatedShapes(); 170 | return shape; 171 | } 172 | } 173 | final CollisionShape newCollisionShape = collisionShape.clone(); 174 | mCollisionShapes.add(newCollisionShape); 175 | newCollisionShape.incrementNbSimilarCreatedShapes(); 176 | return newCollisionShape; 177 | } 178 | 179 | /** 180 | * Removes a collision shape. First, we check if another body is still using the same collision shape. If so, we keep the allocated collision shape. If it is not the case, we can deallocate the 181 | * memory associated with the collision shape. 182 | * 183 | * @param collisionShape The collision shape to remove 184 | */ 185 | protected void removeCollisionShape(CollisionShape collisionShape) { 186 | if (collisionShape.getNbSimilarCreatedShapes() == 0) { 187 | throw new IllegalStateException("Expected at least one similar collision shape remaining"); 188 | } 189 | collisionShape.decrementNbSimilarCreatedShapes(); 190 | if (collisionShape.getNbSimilarCreatedShapes() == 0) { 191 | mCollisionShapes.remove(collisionShape); 192 | } 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /src/main/java/com/flowpowered/react/engine/EventListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react.engine; 27 | 28 | import com.flowpowered.react.constraint.ContactPoint.ContactPointInfo; 29 | 30 | /** 31 | * This class can be used to receive event callbacks from the physics engine. In order to receive callbacks, you need to create a new class that inherits from this one and you must override the 32 | * methods you need. Then, you need to register your new event listener class to the physics world using the {@link DynamicsWorld#setEventListener(EventListener)} method. 33 | */ 34 | public interface EventListener { 35 | /** 36 | * Called when a new contact point is found between two bodies that were separated before. 37 | * 38 | * @param contactInfo The info for the contact 39 | */ 40 | void beginContact(ContactPointInfo contactInfo); 41 | 42 | /** 43 | * Called when a new contact point is found between two bodies. 44 | * 45 | * @param contactInfo The info for the contact 46 | */ 47 | void newContact(ContactPointInfo contactInfo); 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/flowpowered/react/engine/Impulse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react.engine; 27 | 28 | import com.flowpowered.react.math.Vector3; 29 | 30 | /** 31 | * Represents an impulse that we can apply to bodies in the contact or constraint solver. 32 | */ 33 | public class Impulse { 34 | private final Vector3 linearImpulseBody1; 35 | private final Vector3 linearImpulseBody2; 36 | private final Vector3 angularImpulseBody1; 37 | private final Vector3 angularImpulseBody2; 38 | 39 | /** 40 | * Constructs a new impulse from the linear and angular impulses on both bodies. 41 | * 42 | * @param linearImpulseBody1 The linear impulse on the first body 43 | * @param angularImpulseBody1 The linear impulse on the second body 44 | * @param linearImpulseBody2 The angular impulse on the first body 45 | * @param angularImpulseBody2 The angular impulse on the second body 46 | */ 47 | public Impulse(Vector3 linearImpulseBody1, Vector3 angularImpulseBody1, Vector3 linearImpulseBody2, Vector3 angularImpulseBody2) { 48 | this.linearImpulseBody1 = linearImpulseBody1; 49 | this.angularImpulseBody1 = angularImpulseBody1; 50 | this.linearImpulseBody2 = linearImpulseBody2; 51 | this.angularImpulseBody2 = angularImpulseBody2; 52 | } 53 | 54 | /** 55 | * Returns the linear impulse on the first body. 56 | * 57 | * @return The linear impulse 58 | */ 59 | public Vector3 getLinearImpulseFirstBody() { 60 | return linearImpulseBody1; 61 | } 62 | 63 | /** 64 | * Returns the linear impulse on the second body. 65 | * 66 | * @return The linear impulse 67 | */ 68 | public Vector3 getLinearImpulseSecondBody() { 69 | return linearImpulseBody2; 70 | } 71 | 72 | /** 73 | * Returns the angular impulse on the first body. 74 | * 75 | * @return The angular impulse 76 | */ 77 | public Vector3 getAngularImpulseFirstBody() { 78 | return angularImpulseBody1; 79 | } 80 | 81 | /** 82 | * Returns the angular impulse on the second body. 83 | * 84 | * @return The angular impulse 85 | */ 86 | public Vector3 getAngularImpulseSecondBody() { 87 | return angularImpulseBody2; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/com/flowpowered/react/engine/Island.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react.engine; 27 | 28 | import com.flowpowered.react.body.RigidBody; 29 | import com.flowpowered.react.constraint.Joint; 30 | 31 | /** 32 | * An island represent an isolated group of awake bodies that are connected with each other by some constraints (contacts or joints). 33 | */ 34 | public class Island { 35 | private RigidBody[] mBodies; 36 | private ContactManifold[] mContactManifolds; 37 | private Joint[] mJoints; 38 | private int mNbBodies; 39 | private int mNbContactManifolds; 40 | private int mNbJoints; 41 | 42 | /** 43 | * Constructs a new island from the maximum number of bodies, the maximum number of contact manifolds and the maximum number of joints. 44 | * 45 | * @param nbMaxBodies The maximum number of bodies 46 | * @param nbMaxContactManifolds The maximum number of contact manifolds 47 | * @param nbMaxJoints The maximum number of joints 48 | */ 49 | public Island(int nbMaxBodies, int nbMaxContactManifolds, int nbMaxJoints) { 50 | mNbBodies = 0; 51 | mNbContactManifolds = 0; 52 | mNbJoints = 0; 53 | mBodies = new RigidBody[nbMaxBodies]; 54 | mContactManifolds = new ContactManifold[nbMaxContactManifolds]; 55 | mJoints = new Joint[nbMaxJoints]; 56 | } 57 | 58 | /** 59 | * Adds a body into the island 60 | * 61 | * @param body The body 62 | */ 63 | public void addBody(RigidBody body) { 64 | if (body.isSleeping()) { 65 | throw new IllegalArgumentException("Body to add is sleeping"); 66 | } 67 | mBodies[mNbBodies] = body; 68 | mNbBodies++; 69 | } 70 | 71 | /** 72 | * Adds a contact manifold into the island 73 | * 74 | * @param contactManifold The contact manifold 75 | */ 76 | public void addContactManifold(ContactManifold contactManifold) { 77 | mContactManifolds[mNbContactManifolds] = contactManifold; 78 | mNbContactManifolds++; 79 | } 80 | 81 | /** 82 | * Adds a joint into the island. 83 | * 84 | * @param joint The joint 85 | */ 86 | public void addJoint(Joint joint) { 87 | mJoints[mNbJoints] = joint; 88 | mNbJoints++; 89 | } 90 | 91 | /** 92 | * Returns the number of bodies in the island. 93 | * 94 | * @return The number of bodies 95 | */ 96 | public int getNbBodies() { 97 | return mNbBodies; 98 | } 99 | 100 | /** 101 | * Returns the number of contact manifolds in the island. 102 | * 103 | * @return The number of contact manifolds 104 | */ 105 | public int getNbContactManifolds() { 106 | return mNbContactManifolds; 107 | } 108 | 109 | /** 110 | * Returns the number of joints in the island. 111 | * 112 | * @return The number of joints 113 | */ 114 | public int getNbJoints() { 115 | return mNbJoints; 116 | } 117 | 118 | /** 119 | * Returns the array of bodies. 120 | * 121 | * @return The array of bodies 122 | */ 123 | public RigidBody[] getBodies() { 124 | return mBodies; 125 | } 126 | 127 | /** 128 | * Returns the array of contact manifolds. 129 | * 130 | * @return The array of contact manifold 131 | */ 132 | public ContactManifold[] getContactManifolds() { 133 | return mContactManifolds; 134 | } 135 | 136 | /** 137 | * Returns the array of joints. 138 | * 139 | * @return The array of joints 140 | */ 141 | public Joint[] getJoints() { 142 | return mJoints; 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/main/java/com/flowpowered/react/engine/Material.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react.engine; 27 | 28 | import com.flowpowered.react.ReactDefaults; 29 | 30 | /** 31 | * Represents a material for a rigid body. The material has the restitution and friction coefficients. Altering these constants for a material will alter the constants for all bodies. 32 | */ 33 | public class Material { 34 | private float mFrictionCoefficient; 35 | private float mBounciness; 36 | 37 | /** 38 | * Constructs a new rigid body material using {@link ReactDefaults#DEFAULT_BOUNCINESS} as the default bounciness and {@link ReactDefaults#DEFAULT_FRICTION_COEFFICIENT} as the default friction 39 | * coefficient. 40 | */ 41 | public Material() { 42 | mBounciness = ReactDefaults.DEFAULT_BOUNCINESS; 43 | mFrictionCoefficient = ReactDefaults.DEFAULT_FRICTION_COEFFICIENT; 44 | } 45 | 46 | /** 47 | * Copy constructor. 48 | * 49 | * @param material The material to copy 50 | */ 51 | public Material(Material material) { 52 | mBounciness = material.mBounciness; 53 | mFrictionCoefficient = material.mFrictionCoefficient; 54 | } 55 | 56 | /** 57 | * Constructs a new rigid body material from the provided bounciness and friction coefficient. 58 | * 59 | * @param bounciness The bounciness 60 | * @param frictionCoefficient The friction coefficient 61 | */ 62 | public Material(float bounciness, float frictionCoefficient) { 63 | mBounciness = bounciness; 64 | mFrictionCoefficient = frictionCoefficient; 65 | } 66 | 67 | /** 68 | * Gets the bounciness. 69 | * 70 | * @return The bounciness 71 | */ 72 | public float getBounciness() { 73 | return mBounciness; 74 | } 75 | 76 | /** 77 | * Sets the bounciness. The bounciness should be a value between 0 and 1. The value 1 is used for a very bouncy body and zero is used for a body that is not bouncy at all. 78 | * 79 | * @param bounciness The bounciness 80 | */ 81 | public void setBounciness(float bounciness) { 82 | if (bounciness < 0 || bounciness > 1) { 83 | throw new IllegalArgumentException("Bounciness must be between 0 and 1 inclusively"); 84 | } 85 | mBounciness = bounciness; 86 | } 87 | 88 | /** 89 | * Gets the friction coefficient. 90 | * 91 | * @return The friction 92 | */ 93 | public float getFrictionCoefficient() { 94 | return mFrictionCoefficient; 95 | } 96 | 97 | /** 98 | * Sets the friction coefficient. The friction coefficient has to be a positive value. The value zero is used for no friction at all. 99 | * 100 | * @param frictionCoefficient The coefficient to set 101 | */ 102 | public void setFrictionCoefficient(float frictionCoefficient) { 103 | if (frictionCoefficient < 0) { 104 | throw new IllegalArgumentException("Friction coefficient must be greater or equal to 0"); 105 | } 106 | mFrictionCoefficient = frictionCoefficient; 107 | } 108 | 109 | /** 110 | * Sets the material to be same as the provided one. 111 | * 112 | * @param material The material to assign 113 | */ 114 | public void set(Material material) { 115 | mBounciness = material.mBounciness; 116 | mFrictionCoefficient = material.mFrictionCoefficient; 117 | } 118 | 119 | /** 120 | * Returns a new unmodifiable rigid body material. Unmodifiable means that the {@link #setBounciness(float)} (float)} and {@link #setFrictionCoefficient(float)} (float)} methods will throw an 121 | * {@link UnsupportedOperationException}. This is does not use a wrapper class, and the original material is not linked to the one returned. That is, changes to the original material are not 122 | * reflected by the returned material. 123 | * 124 | * @param material The material to make an unmodifiable copy of 125 | * @return A new unmodifiable rigid body material. 126 | */ 127 | public static Material asUnmodifiableMaterial(Material material) { 128 | return new UnmodifiableMaterial(material); 129 | } 130 | 131 | private static class UnmodifiableMaterial extends Material { 132 | private UnmodifiableMaterial(Material material) { 133 | super(material); 134 | } 135 | 136 | @Override 137 | public void setBounciness(float bounciness) { 138 | throw new UnsupportedOperationException("You cannot alter this material"); 139 | } 140 | 141 | @Override 142 | public void setFrictionCoefficient(float frictionCoefficient) { 143 | throw new UnsupportedOperationException("You cannot alter this material"); 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/main/java/com/flowpowered/react/engine/OverlappingPair.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react.engine; 27 | 28 | import com.flowpowered.react.body.CollisionBody; 29 | import com.flowpowered.react.constraint.ContactPoint; 30 | import com.flowpowered.react.math.Vector3; 31 | 32 | /** 33 | * Represents a pair of two bodies that are overlapping during the broad-phase collision detection. It is created when the two bodies start to overlap and is destroyed when they do not overlap 34 | * anymore. This class contains a contact manifold that stores all the contact points between the two bodies. 35 | */ 36 | public class OverlappingPair { 37 | private final CollisionBody mBody1; 38 | private final CollisionBody mBody2; 39 | private final ContactManifold mContactManifold; 40 | private final Vector3 mCachedSeparatingAxis; 41 | 42 | /** 43 | * Constructs a new overlapping pair from the first and second body. 44 | * 45 | * @param body1 The first body 46 | * @param body2 The second body 47 | */ 48 | public OverlappingPair(CollisionBody body1, CollisionBody body2) { 49 | mBody1 = body1; 50 | mBody2 = body2; 51 | mContactManifold = new ContactManifold(body1, body2); 52 | mCachedSeparatingAxis = new Vector3(1, 1, 1); 53 | } 54 | 55 | /** 56 | * Gets the first body. 57 | * 58 | * @return The first body 59 | */ 60 | public CollisionBody getFirstBody() { 61 | return mBody1; 62 | } 63 | 64 | /** 65 | * Gets the second body. 66 | * 67 | * @return The second body 68 | */ 69 | public CollisionBody getSecondBody() { 70 | return mBody2; 71 | } 72 | 73 | /** 74 | * Adds a contact point to the contact manifold. 75 | * 76 | * @param contact The contact point to add 77 | */ 78 | public void addContact(ContactPoint contact) { 79 | mContactManifold.addContactPoint(contact); 80 | } 81 | 82 | /** 83 | * Updates the contact manifold. 84 | */ 85 | public void update() { 86 | mContactManifold.update(mBody1.getTransform(), mBody2.getTransform()); 87 | } 88 | 89 | /** 90 | * Gets the cached separating axis. 91 | * 92 | * @return The cached separating axis 93 | */ 94 | public Vector3 getCachedSeparatingAxis() { 95 | return mCachedSeparatingAxis; 96 | } 97 | 98 | /** 99 | * Sets the cached separating axis. 100 | * 101 | * @param axis The separating axis to set 102 | */ 103 | public void setCachedSeparatingAxis(Vector3 axis) { 104 | mCachedSeparatingAxis.set(axis); 105 | } 106 | 107 | /** 108 | * Gets the number of contact points in the contact manifold. 109 | * 110 | * @return The number of contact points 111 | */ 112 | public int getNbContactPoints() { 113 | return mContactManifold.getNbContactPoints(); 114 | } 115 | 116 | /** 117 | * Gets the contact manifold. 118 | * 119 | * @return The contact manifold 120 | */ 121 | public ContactManifold getContactManifold() { 122 | return mContactManifold; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/main/java/com/flowpowered/react/engine/Timer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react.engine; 27 | 28 | /** 29 | * This class takes care of the time in the physics engine. It uses {@link System#nanoTime()} to get the current time. 30 | */ 31 | public class Timer { 32 | private double mTimeStep; 33 | private double mLastUpdateTime; 34 | private double mDeltaTime; 35 | private double mAccumulator; 36 | private boolean mIsRunning = false; 37 | 38 | /** 39 | * Constructs a new timer from the time step. 40 | * 41 | * @param timeStep The time step 42 | */ 43 | public Timer(double timeStep) { 44 | if (timeStep <= 0) { 45 | throw new IllegalArgumentException("time step cannot be smaller or equal to zero"); 46 | } 47 | mTimeStep = timeStep; 48 | } 49 | 50 | /** 51 | * Gets the time step of the physics engine. 52 | * 53 | * @return The time step 54 | */ 55 | public double getTimeStep() { 56 | return mTimeStep; 57 | } 58 | 59 | /** 60 | * Sets the time step of the physics engine. 61 | * 62 | * @param timeStep The time step to set 63 | */ 64 | public void setTimeStep(double timeStep) { 65 | if (timeStep <= 0) { 66 | throw new IllegalArgumentException("time step must be greater than zero"); 67 | } 68 | mTimeStep = timeStep; 69 | } 70 | 71 | /** 72 | * Gets the current time. 73 | * 74 | * @return The current time 75 | */ 76 | public double getPhysicsTime() { 77 | return mLastUpdateTime; 78 | } 79 | 80 | /** 81 | * Returns true if the timer is running, false if not. 82 | * 83 | * @return Whether or not the timer is running 84 | */ 85 | public boolean isRunning() { 86 | return mIsRunning; 87 | } 88 | 89 | /** 90 | * Start the timer. 91 | */ 92 | public void start() { 93 | if (!mIsRunning) { 94 | mLastUpdateTime = getCurrentSystemTime(); 95 | mAccumulator = 0; 96 | mIsRunning = true; 97 | } 98 | } 99 | 100 | /** 101 | * Stop the timer. 102 | */ 103 | public void stop() { 104 | mIsRunning = false; 105 | } 106 | 107 | /** 108 | * Returns true if it's possible to take a new step, false if not. 109 | * 110 | * @return Whether or not a new step is possible 111 | */ 112 | public boolean isPossibleToTakeStep() { 113 | return mAccumulator >= mTimeStep; 114 | } 115 | 116 | /** 117 | * Takes a new step: updates the timer by adding the timeStep value to the current time. 118 | */ 119 | public void nextStep() { 120 | if (!mIsRunning) { 121 | throw new IllegalStateException("Timer is not running"); 122 | } 123 | mAccumulator -= mTimeStep; 124 | } 125 | 126 | /** 127 | * Compute the interpolation factor for the time step. 128 | * 129 | * @return The interpolation factor 130 | */ 131 | public float computeInterpolationFactor() { 132 | return (float) (mAccumulator / mTimeStep); 133 | } 134 | 135 | /** 136 | * Compute the time since the last update call and add it to the accumulator. 137 | */ 138 | public void update() { 139 | final double currentTime = getCurrentSystemTime(); 140 | mDeltaTime = currentTime - mLastUpdateTime; 141 | mLastUpdateTime = currentTime; 142 | mAccumulator += mDeltaTime; 143 | } 144 | 145 | private static double getCurrentSystemTime() { 146 | return System.nanoTime() / 1e9d; 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /src/main/java/com/flowpowered/react/engine/linked/LinkedDynamicsWorld.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react.engine.linked; 27 | 28 | import java.util.Collection; 29 | import java.util.HashSet; 30 | import java.util.Set; 31 | 32 | import com.flowpowered.react.body.RigidBody; 33 | import com.flowpowered.react.engine.DynamicsWorld; 34 | import com.flowpowered.react.math.Vector3; 35 | 36 | /** 37 | * Represents a dynamics world linked to another world. Information is shared between them through an instance of {@link LinkedWorldInfo}. 38 | */ 39 | public class LinkedDynamicsWorld extends DynamicsWorld { 40 | private final LinkedWorldInfo info; 41 | private final Set linkedBodies = new HashSet<>(); 42 | 43 | /** 44 | * Constructs a new linked dynamics world from the gravity, the time step and the linked world information. 45 | * 46 | * @param gravity The gravity 47 | * @param timeStep The simulation time step 48 | * @param info The linked world information 49 | */ 50 | public LinkedDynamicsWorld(Vector3 gravity, float timeStep, LinkedWorldInfo info) { 51 | super(gravity, timeStep); 52 | this.info = info; 53 | } 54 | 55 | /** 56 | * Constructs a new linked dynamics world from the gravity, the default time step and the linked world information. 57 | * 58 | * @param gravity The gravity 59 | * @param info The linked world information 60 | */ 61 | public LinkedDynamicsWorld(Vector3 gravity, LinkedWorldInfo info) { 62 | super(gravity); 63 | this.info = info; 64 | } 65 | 66 | @Override 67 | public void tick() { 68 | super.tick(); 69 | clearLinkedBodies(); 70 | } 71 | 72 | /** 73 | * Returns the {@link com.flowpowered.react.engine.linked.LinkedWorldInfo} of this world. 74 | * 75 | * @return The linked info 76 | */ 77 | public LinkedWorldInfo getLinkedInfo() { 78 | return info; 79 | } 80 | 81 | /** 82 | * Adds {@link RigidBody}s to this world. These will be cleared at the end of the physics tick. 83 | * 84 | * @param bodies The bodies to add 85 | */ 86 | public void addLinkedBodies(Collection bodies) { 87 | linkedBodies.addAll(bodies); 88 | for (RigidBody body : bodies) { 89 | addRigidBodyIgnoreTick(body); 90 | } 91 | } 92 | 93 | // Clears all bodies tracked in the world. 94 | private void clearLinkedBodies() { 95 | for (RigidBody linkedBody : linkedBodies) { 96 | // We're in a safe part of the tick so we can clear them immediately 97 | destroyRigidBodyImmediately(linkedBody); 98 | } 99 | linkedBodies.clear(); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/com/flowpowered/react/engine/linked/LinkedWorldInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react.engine.linked; 27 | 28 | import com.flowpowered.react.body.RigidBody; 29 | 30 | /** 31 | * A simple class made for implementations with dynamic world planes (ex. Voxel generation) where no assumptions can be made about the world.

It is left up to the implementation of this class to 32 | * provide the body to be used at the x, y, z provided. 33 | */ 34 | public interface LinkedWorldInfo { 35 | /** 36 | * Fetches the {@link RigidBody} at the x, y, z in world space.

Implementations of this method are expected to generate a body based on data stored for the 3D coordinate in world 37 | * space.

38 | * 39 | * @param x The x coordinate in world space 40 | * @param y The y coordinate in world space 41 | * @param z The z coordinate in world space 42 | * @return The constructed body 43 | */ 44 | public RigidBody getBody(int x, int y, int z); 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/flowpowered/react/math/Mathematics.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react.math; 27 | 28 | import com.flowpowered.react.ReactDefaults; 29 | 30 | /** 31 | * Various mathematical functions. 32 | */ 33 | public class Mathematics { 34 | /** 35 | * Returns true if the values a and b are approximately equal, using {@link ReactDefaults#MACHINE_EPSILON} as the acceptable error. Returns false if the values are not approximately equal. 36 | * 37 | * @param a The first value 38 | * @param b The second value 39 | * @return Whether or not the values are approximately equal 40 | */ 41 | public static boolean approxEquals(float a, float b) { 42 | return approxEquals(a, b, ReactDefaults.MACHINE_EPSILON); 43 | } 44 | 45 | /** 46 | * Returns true if the values a and b are approximately equal, using the provided acceptable error. Returns false if the values are not approximately equal. 47 | * 48 | * @param a The first value 49 | * @param b The second value 50 | * @param epsilon The acceptable error 51 | * @return Whether or not the values are approximately equal 52 | */ 53 | public static boolean approxEquals(float a, float b, float epsilon) { 54 | float difference = a - b; 55 | return difference < epsilon && difference > -epsilon; 56 | } 57 | 58 | /** 59 | * Returns the result of the "value" clamped by two others values "lowerLimit" and "upperLimit". 60 | * 61 | * @param value The value to clamp 62 | * @param lowerLimit The lower limit 63 | * @param upperLimit The upper limit 64 | * @return The clamped value 65 | */ 66 | public static float clamp(float value, float lowerLimit, float upperLimit) { 67 | if (lowerLimit > upperLimit) { 68 | throw new IllegalArgumentException("Lower limit must be smaller or equal to the upper limit"); 69 | } 70 | return Math.min(Math.max(value, lowerLimit), upperLimit); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/com/flowpowered/react/math/Transform.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react.math; 27 | 28 | /** 29 | * Represents a position and an orientation in 3D. It can also be seen as representing a translation and a rotation. 30 | */ 31 | public class Transform { 32 | private final Vector3 mPosition = new Vector3(); 33 | private final Quaternion mOrientation = new Quaternion(); 34 | 35 | /** 36 | * Default constructor. Position will be the zero vector and the rotation, quaternion identity. 37 | */ 38 | public Transform() { 39 | this(new Vector3(0, 0, 0), Quaternion.identity()); 40 | } 41 | 42 | /** 43 | * Constructs a new transform from the position as a vector3 and the orientation as a 3x3 matrix. 44 | * 45 | * @param position The position 46 | * @param orientation The orientation 47 | */ 48 | public Transform(Vector3 position, Matrix3x3 orientation) { 49 | this(position, new Quaternion(orientation)); 50 | } 51 | 52 | /** 53 | * Constructs a new transform from the position as a vector3 and the orientation as a quaternion. 54 | * 55 | * @param position The position 56 | * @param orientation The orientation 57 | */ 58 | public Transform(Vector3 position, Quaternion orientation) { 59 | this.mPosition.set(position); 60 | this.mOrientation.set(orientation); 61 | } 62 | 63 | /** 64 | * Copy constructor. 65 | * 66 | * @param transform The transform to copy 67 | */ 68 | public Transform(Transform transform) { 69 | this(transform.getPosition(), transform.getOrientation()); 70 | } 71 | 72 | /** 73 | * Gets the position component of this transform as a vector3. 74 | * 75 | * @return The position 76 | */ 77 | public Vector3 getPosition() { 78 | return mPosition; 79 | } 80 | 81 | /** 82 | * Gets the orientation component of this transform as a quaternion. 83 | * 84 | * @return The orientation 85 | */ 86 | public Quaternion getOrientation() { 87 | return mOrientation; 88 | } 89 | 90 | /** 91 | * Sets the position component of this transform to the desired vector3. 92 | * 93 | * @param position The position to set 94 | */ 95 | public void setPosition(Vector3 position) { 96 | mPosition.set(position); 97 | } 98 | 99 | /** 100 | * Sets the orientation component of this transform to the desired quaternion. 101 | * 102 | * @param orientation The position to set 103 | */ 104 | public void setOrientation(Quaternion orientation) { 105 | mOrientation.set(orientation); 106 | } 107 | 108 | /** 109 | * Sets the position and orientation of this transform to those of the provided transform. 110 | * 111 | * @param transform The transform to copy the position and orientation from 112 | */ 113 | public Transform set(Transform transform) { 114 | mPosition.set(transform.getPosition()); 115 | mOrientation.set(transform.getOrientation()); 116 | return this; 117 | } 118 | 119 | /** 120 | * Sets this transform to identity. The vector is set to the zero vector, and the quaternion, to the identity quaternion. 121 | */ 122 | public void setToIdentity() { 123 | mPosition.set(new Vector3(0, 0, 0)); 124 | mOrientation.set(Quaternion.identity()); 125 | } 126 | 127 | /** 128 | * Inverses the rotation and position of this transform and returns it as a new one. 129 | * 130 | * @return The transform which is the inverse of this one 131 | */ 132 | public Transform getInverse() { 133 | final Quaternion invQuaternion = mOrientation.getInverse(); 134 | final Matrix3x3 invMatrix = invQuaternion.getMatrix(); 135 | return new Transform(Matrix3x3.multiply(invMatrix, Vector3.negate(mPosition)), invQuaternion); 136 | } 137 | 138 | @Override 139 | public int hashCode() { 140 | int hash = 3; 141 | hash = 11 * hash + mPosition.hashCode(); 142 | hash = 11 * hash + mOrientation.hashCode(); 143 | return hash; 144 | } 145 | 146 | @Override 147 | public boolean equals(Object obj) { 148 | if (!(obj instanceof Transform)) { 149 | return false; 150 | } 151 | final Transform other = (Transform) obj; 152 | if (mPosition != other.mPosition && !mPosition.equals(other.mPosition)) { 153 | return false; 154 | } 155 | if (mOrientation != other.mOrientation && !mOrientation.equals(other.mOrientation)) { 156 | return false; 157 | } 158 | return true; 159 | } 160 | 161 | @Override 162 | public String toString() { 163 | return "Transform{position= " + mPosition + ", orientation= " + mOrientation + "}"; 164 | } 165 | 166 | /** 167 | * Returns a new identity transform. That is, a transform with the position as the zero vector and the orientation as the identity quaternion. 168 | * 169 | * @return A new identity transform 170 | */ 171 | public static Transform identity() { 172 | return new Transform(new Vector3(0, 0, 0), Quaternion.identity()); 173 | } 174 | 175 | /** 176 | * Multiplies the transform by a vector3 and returns the result as a new vector3. 177 | * 178 | * @param transform The transform 179 | * @param vector The vector 180 | * @return The result of the multiplication of the transform by a vector3 as a new vector3 181 | */ 182 | public static Vector3 multiply(Transform transform, Vector3 vector) { 183 | return Vector3.add(Matrix3x3.multiply(transform.getOrientation().getMatrix(), vector), transform.getPosition()); 184 | } 185 | 186 | /** 187 | * Multiplies the first transform by the second one and returns the result as a new transform. 188 | * 189 | * @param transform1 The first transform 190 | * @param transform2 The second transform 191 | * @return The result of the multiplication of the two transforms as a new transform 192 | */ 193 | public static Transform multiply(Transform transform1, Transform transform2) { 194 | return new Transform( 195 | Vector3.add(transform1.getPosition(), Matrix3x3.multiply(transform1.getOrientation().getMatrix(), transform2.getPosition())), 196 | Quaternion.multiply(transform1.getOrientation(), transform2.getOrientation())); 197 | } 198 | 199 | /** 200 | * Interpolates a transform between two other. 201 | * 202 | * @param transform1 The first transform 203 | * @param transform2 The second transform 204 | * @param percent The percent for the interpolation, between 0 and 1 inclusively 205 | * @return The interpolated transform 206 | */ 207 | public static Transform interpolateTransforms(Transform transform1, Transform transform2, float percent) { 208 | final Vector3 interPosition = Vector3.add( 209 | Vector3.multiply(transform1.getPosition(), (1 - percent)), 210 | Vector3.multiply(transform2.getPosition(), percent)); 211 | final Quaternion interOrientation = Quaternion.slerp(transform1.getOrientation(), transform2.getOrientation(), percent); 212 | return new Transform(interPosition, interOrientation); 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /src/test/java/com/flowpowered/react/Dummies.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react; 27 | 28 | import java.util.Random; 29 | 30 | import com.flowpowered.react.body.CollisionBody; 31 | import com.flowpowered.react.body.RigidBody; 32 | import com.flowpowered.react.collision.BroadPhasePair; 33 | import com.flowpowered.react.collision.CollisionDetection; 34 | import com.flowpowered.react.collision.shape.AABB; 35 | import com.flowpowered.react.collision.shape.BoxShape; 36 | import com.flowpowered.react.collision.shape.CapsuleShape; 37 | import com.flowpowered.react.collision.shape.CollisionShape; 38 | import com.flowpowered.react.collision.shape.ConeShape; 39 | import com.flowpowered.react.collision.shape.ConvexMeshShape; 40 | import com.flowpowered.react.collision.shape.CylinderShape; 41 | import com.flowpowered.react.collision.shape.SphereShape; 42 | import com.flowpowered.react.constraint.ContactPoint.ContactPointInfo; 43 | import com.flowpowered.react.engine.CollisionWorld; 44 | import com.flowpowered.react.math.Matrix3x3; 45 | import com.flowpowered.react.math.Quaternion; 46 | import com.flowpowered.react.math.Transform; 47 | import com.flowpowered.react.math.Vector3; 48 | 49 | /** 50 | * Provides fake implementations and objects for tests. 51 | */ 52 | public class Dummies { 53 | private static final Random RANDOM = new Random(); 54 | /* 55 | 2------4 56 | / | / | 57 | 6------7 | 58 | | 0--|---1 59 | | / | / 60 | 3------5 61 | */ 62 | private static final float[] CUBE_MESH_VERTICES = { 63 | -1, -1, -1, 64 | 1, -1, -1, 65 | -1, 1, -1, 66 | -1, -1, 1, 67 | 1, 1, -1, 68 | 1, -1, 1, 69 | -1, 1, 1, 70 | 1, 1, 1 71 | }; 72 | private static final int NB_CUBE_MESH_VERTICES = CUBE_MESH_VERTICES.length / 3; 73 | private static final int CUBE_MESH_VERTEX_STRIDE = 3 * 4; 74 | private static final int[][] CUBE_MESH_EDGES = { 75 | {0, 1}, {0, 2}, {0, 3}, 76 | {1, 4}, {1, 5}, 77 | {2, 4}, {2, 6}, 78 | {3, 5}, {3, 6}, 79 | {7, 4}, {7, 5}, {7, 6} 80 | }; 81 | 82 | public static Vector3 newPosition() { 83 | return new Vector3(RANDOM.nextInt(21) - 10, RANDOM.nextInt(21) - 10, RANDOM.nextInt(21) - 10); 84 | } 85 | 86 | public static Quaternion newOrientation() { 87 | final float phi = RANDOM.nextFloat() * 2 * (float) Math.PI; 88 | final float theta = RANDOM.nextFloat() * 2 * (float) Math.PI; 89 | final float x = (float) Math.sin(theta) * (float) Math.cos(phi); 90 | final float y = (float) Math.sin(theta) * (float) Math.sin(phi); 91 | final float z = (float) Math.cos(theta); 92 | final float halfAngle = (float) Math.toRadians(RANDOM.nextFloat() * 2 * Math.PI) / 2; 93 | final float q = (float) Math.sin(halfAngle); 94 | return new Quaternion(x * q, y * q, z * q, (float) Math.cos(halfAngle)); 95 | } 96 | 97 | public static Transform newTransform() { 98 | return new Transform(newPosition(), newOrientation()); 99 | } 100 | 101 | public static CollisionBody newCollisionBody(int id) { 102 | return new RigidBody(Transform.identity(), 0, Matrix3x3.identity(), new BoxShape(new Vector3(1, 1, 1)), id); 103 | } 104 | 105 | public static AABB newAABB() { 106 | final Vector3 min = newPosition(); 107 | return new AABB(min, Vector3.add(min, new Vector3(RANDOM.nextInt(5) + 4, RANDOM.nextInt(5) + 4, RANDOM.nextInt(5) + 4))); 108 | } 109 | 110 | public static AABB newIntersectingAABB(AABB with) { 111 | final Vector3 wMin = with.getMin(); 112 | final Vector3 wSize = Vector3.subtract(with.getMax(), wMin); 113 | final int iSizeX = RANDOM.nextInt((int) wSize.getX() + 1); 114 | final int iSizeY = RANDOM.nextInt((int) wSize.getY() + 1); 115 | final int iSizeZ = RANDOM.nextInt((int) wSize.getZ() + 1); 116 | final int eSizeX = RANDOM.nextInt(5) + 4; 117 | final int eSizeY = RANDOM.nextInt(5) + 4; 118 | final int eSizeZ = RANDOM.nextInt(5) + 4; 119 | final Vector3 min = Vector3.subtract(wMin, new Vector3(eSizeX, eSizeY, eSizeZ)); 120 | final Vector3 max = Vector3.add(wMin, new Vector3(iSizeX, iSizeY, iSizeZ)); 121 | return new AABB(min, max); 122 | } 123 | 124 | public static BoxShape newBoxShape() { 125 | return new BoxShape(new Vector3(RANDOM.nextInt(5) + 4, RANDOM.nextInt(5) + 4, RANDOM.nextInt(5) + 4)); 126 | } 127 | 128 | public static ConeShape newConeShape() { 129 | return new ConeShape(RANDOM.nextInt(5) + 4, RANDOM.nextInt(5) + 4); 130 | } 131 | 132 | public static CylinderShape newCylinderShape() { 133 | return new CylinderShape(RANDOM.nextInt(5) + 4, RANDOM.nextInt(5) + 4); 134 | } 135 | 136 | public static SphereShape newSphereShape() { 137 | return new SphereShape(RANDOM.nextInt(5) + 4); 138 | } 139 | 140 | public static CapsuleShape newCapsuleShape() { 141 | return new CapsuleShape(RANDOM.nextInt(5) + 4, RANDOM.nextInt(5) + 4); 142 | } 143 | 144 | public static ConvexMeshShape newConvexMeshShape() { 145 | final ConvexMeshShape shape = new ConvexMeshShape(CUBE_MESH_VERTICES, NB_CUBE_MESH_VERTICES, CUBE_MESH_VERTEX_STRIDE); 146 | for (int[] edge : CUBE_MESH_EDGES) { 147 | shape.addEdge(edge[0], edge[1]); 148 | } 149 | shape.setIsEdgesInformationUsed(true); 150 | return shape; 151 | } 152 | 153 | public static CollisionShape newCollisionShape() { 154 | switch (RANDOM.nextInt(6)) { 155 | case 0: 156 | return newBoxShape(); 157 | case 1: 158 | return newConeShape(); 159 | case 2: 160 | return newCylinderShape(); 161 | case 3: 162 | return newSphereShape(); 163 | case 4: 164 | return newCapsuleShape(); 165 | case 5: 166 | return newConvexMeshShape(); 167 | default: 168 | throw new IllegalStateException("random int larger than shape types count"); 169 | } 170 | } 171 | 172 | public static CollisionWorld newCollisionWorld() { 173 | return new DummyCollisionWorld(); 174 | } 175 | 176 | public static CollisionDetection newCollisionDetection() { 177 | return new CollisionDetection(newCollisionWorld()); 178 | } 179 | 180 | private static class DummyCollisionWorld extends CollisionWorld { 181 | private DummyCollisionWorld() { 182 | } 183 | 184 | @Override 185 | public void notifyAddedOverlappingPair(BroadPhasePair addedPair) { 186 | } 187 | 188 | @Override 189 | public void notifyRemovedOverlappingPair(BroadPhasePair removedPair) { 190 | } 191 | 192 | @Override 193 | public void notifyNewContact(BroadPhasePair pair, ContactPointInfo contactInfo) { 194 | } 195 | 196 | @Override 197 | public void updateOverlappingPair(BroadPhasePair pair) { 198 | } 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /src/test/java/com/flowpowered/react/DynamicsWorldTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react; 27 | 28 | import org.junit.Assert; 29 | import org.junit.Test; 30 | 31 | import com.flowpowered.react.body.RigidBody; 32 | import com.flowpowered.react.collision.shape.BoxShape; 33 | import com.flowpowered.react.constraint.ContactPoint.ContactPointInfo; 34 | import com.flowpowered.react.engine.DynamicsWorld; 35 | import com.flowpowered.react.engine.EventListener; 36 | import com.flowpowered.react.math.Matrix3x3; 37 | import com.flowpowered.react.math.Quaternion; 38 | import com.flowpowered.react.math.Transform; 39 | import com.flowpowered.react.math.Vector3; 40 | 41 | public class DynamicsWorldTest { 42 | private static final float RUN_TIME = 2; 43 | private int beginContactCount = 0; 44 | private int newContactCount = 0; 45 | 46 | @Test 47 | public void test() throws InterruptedException { 48 | final float timeStep = ReactDefaults.DEFAULT_TIMESTEP; 49 | final DynamicsWorld world = new DynamicsWorld(new Vector3(0, -9.81f, 0), timeStep); 50 | world.setEventListener(new TestListener()); 51 | world.start(); 52 | Thread.sleep(200); 53 | // We want to do one update with no bodies 54 | world.update(); 55 | world.stop(); 56 | final BoxShape floorShape = new BoxShape(new Vector3(10, 0.5f, 10)); 57 | final Transform floorTransform = new Transform(new Vector3(0, 0, 0), Quaternion.identity()); 58 | final Matrix3x3 floorInertia = new Matrix3x3(); 59 | final float floorMass = 100; 60 | floorShape.computeLocalInertiaTensor(floorInertia, floorMass); 61 | final RigidBody floor = world.createRigidBody(floorTransform, floorMass, floorInertia, floorShape); 62 | floor.enableMotion(false); 63 | final BoxShape boxShape = new BoxShape(new Vector3(1, 1, 1)); 64 | final Transform boxTransform = new Transform(new Vector3(0, 5, 0), Quaternion.identity()); 65 | final Matrix3x3 boxInertia = new Matrix3x3(); 66 | final float boxMass = 5; 67 | boxShape.computeLocalInertiaTensor(boxInertia, boxMass); 68 | final RigidBody box = world.createRigidBody(boxTransform, boxMass, boxInertia, boxShape); 69 | final int stepCount = Math.round((1 / timeStep) * RUN_TIME); 70 | final int sleepTime = Math.round(timeStep * 1000); 71 | world.start(); 72 | for (int i = 0; i < stepCount; i++) { 73 | final long start = System.nanoTime(); 74 | world.update(); 75 | final long delta = Math.round((System.nanoTime() - start) / 1000000d); 76 | Thread.sleep(Math.max(sleepTime - delta, 0)); 77 | } 78 | world.destroyRigidBody(floor); 79 | world.destroyRigidBody(box); 80 | world.stop(); 81 | Assert.assertTrue("There was no contact in the simulation", beginContactCount > 0); 82 | Assert.assertTrue("There were more contacts begun than new contacts", newContactCount > beginContactCount); 83 | } 84 | 85 | private class TestListener implements EventListener { 86 | @Override 87 | public void beginContact(ContactPointInfo contactInfo) { 88 | beginContactCount++; 89 | } 90 | 91 | @Override 92 | public void newContact(ContactPointInfo contactInfo) { 93 | newContactCount++; 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/test/java/com/flowpowered/react/PairManagerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react; 27 | 28 | import org.junit.Assert; 29 | import org.junit.Test; 30 | 31 | import com.flowpowered.react.collision.broadphase.PairManager; 32 | import com.flowpowered.react.collision.broadphase.PairManager.BodyPair; 33 | 34 | public class PairManagerTest { 35 | @Test 36 | public void test() { 37 | final PairManager manager = new PairManager(Dummies.newCollisionDetection()); 38 | Assert.assertEquals(manager.getNbOverlappingPairs(), 0); 39 | for (int i = 0; i < 20; i += 2) { 40 | final BodyPair pair = manager.addPair(Dummies.newCollisionBody(i), Dummies.newCollisionBody(i + 1)); 41 | Assert.assertNotNull(pair); 42 | Assert.assertEquals(pair.getFirstBody().getID(), i); 43 | Assert.assertEquals(pair.getSecondBody().getID(), i + 1); 44 | } 45 | Assert.assertEquals(manager.getNbOverlappingPairs(), 10); 46 | for (int i = 0; i < 20; i += 2) { 47 | final BodyPair pair = manager.findPair(i, i + 1); 48 | Assert.assertNotNull(pair); 49 | Assert.assertEquals(pair.getFirstBody().getID(), i); 50 | Assert.assertEquals(pair.getSecondBody().getID(), i + 1); 51 | } 52 | Assert.assertEquals(manager.getNbOverlappingPairs(), 10); 53 | for (int i = 0; i < 20; i += 2) { 54 | Assert.assertTrue(manager.removePair(i, i + 1)); 55 | } 56 | Assert.assertEquals(manager.getNbOverlappingPairs(), 0); 57 | } 58 | } -------------------------------------------------------------------------------- /src/test/java/com/flowpowered/react/SphereVsSphereAlgorithmTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react; 27 | 28 | import java.util.Random; 29 | 30 | import org.junit.Assert; 31 | import org.junit.Test; 32 | 33 | import com.flowpowered.react.collision.narrowphase.SphereVsSphereAlgorithm; 34 | import com.flowpowered.react.collision.shape.SphereShape; 35 | import com.flowpowered.react.constraint.ContactPoint.ContactPointInfo; 36 | import com.flowpowered.react.math.Transform; 37 | import com.flowpowered.react.math.Vector3; 38 | 39 | public class SphereVsSphereAlgorithmTest { 40 | private static final Random RANDOM = new Random(); 41 | 42 | @Test 43 | public void test() { 44 | final SphereVsSphereAlgorithm sphereVsSphere = new SphereVsSphereAlgorithm(); 45 | for (int i = 0; i < 100; i++) { 46 | final SphereShape s1 = Dummies.newSphereShape(); 47 | final Transform t1 = Dummies.newTransform(); 48 | final SphereShape s2 = Dummies.newSphereShape(); 49 | final Transform t2 = Dummies.newTransform(); 50 | if (i < 50) { 51 | nonCollideSpheres(s1, t1, s2, t2); 52 | Assert.assertFalse(sphereVsSphere.testCollision(s1, t1, s2, t2, new ContactPointInfo())); 53 | } else { 54 | collideSpheres(s1, t1, s2, t2); 55 | Assert.assertTrue(sphereVsSphere.testCollision(s1, t1, s2, t2, new ContactPointInfo())); 56 | } 57 | } 58 | } 59 | 60 | private static void collideSpheres(SphereShape s1, Transform t1, SphereShape s2, Transform t2) { 61 | final Vector3 pos1 = t1.getPosition(); 62 | final float rad1 = s1.getRadius(); 63 | final float phi1 = RANDOM.nextFloat() * 2 * (float) Math.PI; 64 | final float theta1 = RANDOM.nextFloat() * 2 * (float) Math.PI; 65 | final float r1 = RANDOM.nextFloat() * rad1; 66 | final Vector3 in = new Vector3( 67 | r1 * (float) Math.sin(theta1) * (float) Math.cos(phi1), 68 | r1 * (float) Math.sin(theta1) * (float) Math.sin(phi1), 69 | r1 * (float) Math.cos(theta1)) 70 | .add(pos1); 71 | final float phi2 = RANDOM.nextFloat() * 2 * (float) Math.PI; 72 | final float theta2 = RANDOM.nextFloat() * 2 * (float) Math.PI; 73 | final float r2 = s2.getRadius(); 74 | final Vector3 pos2 = new Vector3( 75 | r2 * (float) Math.sin(theta2) * (float) Math.cos(phi2), 76 | r2 * (float) Math.sin(theta2) * (float) Math.sin(phi2), 77 | r2 * (float) Math.cos(theta2)) 78 | .add(in); 79 | t2.setPosition(pos2); 80 | } 81 | 82 | private static void nonCollideSpheres(SphereShape s1, Transform t1, SphereShape s2, Transform t2) { 83 | final Vector3 pos1 = t1.getPosition(); 84 | final float rad1 = s1.getRadius(); 85 | final float rad2 = s2.getRadius(); 86 | final float phi = RANDOM.nextFloat() * 2 * (float) Math.PI; 87 | final float theta = RANDOM.nextFloat() * 2 * (float) Math.PI; 88 | final float r = rad1 + rad2 + RANDOM.nextInt(5) + 0.01f; 89 | final Vector3 pos2 = new Vector3( 90 | r * (float) Math.sin(theta) * (float) Math.cos(phi), 91 | r * (float) Math.sin(theta) * (float) Math.sin(phi), 92 | r * (float) Math.cos(theta)) 93 | .add(pos1); 94 | t2.setPosition(pos2); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/test/java/com/flowpowered/react/SweepAndPruneAlgorithmTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of React, licensed under the MIT License (MIT). 3 | * 4 | * Copyright (c) 2013 Flow Powered 5 | * Original ReactPhysics3D C++ library by Daniel Chappuis 6 | * React is re-licensed with permission from ReactPhysics3D author. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.flowpowered.react; 27 | 28 | import java.util.HashSet; 29 | import java.util.Set; 30 | 31 | import org.junit.Assert; 32 | import org.junit.Test; 33 | 34 | import com.flowpowered.react.body.CollisionBody; 35 | import com.flowpowered.react.collision.broadphase.SweepAndPruneAlgorithm; 36 | import com.flowpowered.react.collision.shape.AABB; 37 | 38 | public class SweepAndPruneAlgorithmTest { 39 | private static final int BODY_COUNT = 100; 40 | private int ID = 0; 41 | 42 | @Test 43 | public void test() { 44 | final SweepAndPruneAlgorithm sweepAndPrune = new SweepAndPruneAlgorithm(Dummies.newCollisionDetection()); 45 | final Set bodies = new HashSet<>(); 46 | for (int repeat = 0; repeat < 2; repeat++) { 47 | for (int i = 0; i < BODY_COUNT / 10; i++) { 48 | final CollisionBody body = Dummies.newCollisionBody(ID++); 49 | bodies.add(body); 50 | sweepAndPrune.addObject(body, Dummies.newAABB()); 51 | } 52 | Assert.assertEquals(BODY_COUNT / 10, sweepAndPrune.getNbObjects()); 53 | Assert.assertTrue(countNotNull(sweepAndPrune.getOverlappingPairs()) >= 0); 54 | for (int i = 0; i < BODY_COUNT / 2; i++) { 55 | final AABB aabb = Dummies.newAABB(); 56 | final CollisionBody body0 = Dummies.newCollisionBody(ID++); 57 | bodies.add(body0); 58 | sweepAndPrune.addObject(body0, aabb); 59 | final CollisionBody body1 = Dummies.newCollisionBody(ID++); 60 | bodies.add(body1); 61 | sweepAndPrune.addObject(body1, Dummies.newIntersectingAABB(aabb)); 62 | } 63 | Assert.assertEquals(BODY_COUNT + BODY_COUNT / 10, sweepAndPrune.getNbObjects()); 64 | Assert.assertTrue(countNotNull(sweepAndPrune.getOverlappingPairs()) >= BODY_COUNT / 2); 65 | for (CollisionBody body : bodies) { 66 | sweepAndPrune.removeObject(body); 67 | } 68 | Assert.assertEquals(0, sweepAndPrune.getNbObjects()); 69 | bodies.clear(); 70 | ID = 0; 71 | } 72 | } 73 | 74 | private static int countNotNull(Object[] array) { 75 | if (array == null) { 76 | return 0; 77 | } 78 | int count = 0; 79 | for (Object object : array) { 80 | if (object != null) { 81 | count++; 82 | } 83 | } 84 | return count; 85 | } 86 | } 87 | --------------------------------------------------------------------------------