├── .github
└── workflows
│ └── push.yml
├── .gitignore
├── LICENSE
├── README.md
├── apps
├── build.gradle.kts
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── github
│ │ └── stephengold
│ │ ├── lbjexamples
│ │ ├── AppChooser.java
│ │ ├── apps
│ │ │ ├── HelloCcd.java
│ │ │ ├── HelloCharacter.java
│ │ │ ├── HelloCloth.java
│ │ │ ├── HelloClothRigid.java
│ │ │ ├── HelloContactResponse.java
│ │ │ ├── HelloCustomShape.java
│ │ │ ├── HelloDamping.java
│ │ │ ├── HelloDeactivation.java
│ │ │ ├── HelloDoor.java
│ │ │ ├── HelloDoubleEnded.java
│ │ │ ├── HelloGhost.java
│ │ │ ├── HelloJoint.java
│ │ │ ├── HelloKinematics.java
│ │ │ ├── HelloLimit.java
│ │ │ ├── HelloMadMallet.java
│ │ │ ├── HelloMassDistribution.java
│ │ │ ├── HelloMinkowski.java
│ │ │ ├── HelloMotor.java
│ │ │ ├── HelloNewHinge.java
│ │ │ ├── HelloNonUniformGravity.java
│ │ │ ├── HelloPin.java
│ │ │ ├── HelloRigidBody.java
│ │ │ ├── HelloServo.java
│ │ │ ├── HelloSoftBody.java
│ │ │ ├── HelloSoftRope.java
│ │ │ ├── HelloSoftSoft.java
│ │ │ ├── HelloSport.java
│ │ │ ├── HelloSpring.java
│ │ │ ├── HelloStaticBody.java
│ │ │ ├── HelloVehicle.java
│ │ │ ├── HelloWalk.java
│ │ │ ├── HelloWind.java
│ │ │ ├── console
│ │ │ │ ├── HelloLibbulletjme.java
│ │ │ │ ├── HelloVehicle0.java
│ │ │ │ ├── SpeedTest.java
│ │ │ │ └── package-info.java
│ │ │ └── package-info.java
│ │ └── package-info.java
│ │ └── shapes
│ │ └── custom
│ │ ├── CustomBox.java
│ │ ├── CustomCone.java
│ │ ├── CustomCylinder.java
│ │ ├── CustomEllipsoid.java
│ │ ├── CustomFrustum.java
│ │ ├── CustomHalfCylinder.java
│ │ ├── CustomHemisphere.java
│ │ ├── CustomLemon.java
│ │ ├── CustomParaboloid.java
│ │ ├── CustomSegment.java
│ │ └── package-info.java
│ └── resources
│ └── Textures
│ ├── Terrain
│ └── splat
│ │ └── mountains512.png
│ ├── TextureTest.png
│ └── greenTile.png
├── bash
└── meld.sh
├── build.gradle.kts
├── config
└── checkstyle
│ ├── checkstyle.xml
│ └── java-header
├── docs
├── build.gradle.kts
├── en
│ ├── antora.yml
│ └── modules
│ │ └── ROOT
│ │ ├── images
│ │ ├── CustomConvex.png
│ │ ├── box.png
│ │ ├── box2d.png
│ │ ├── capsule.png
│ │ ├── compound.png
│ │ ├── cone.png
│ │ ├── convex2d.png
│ │ ├── conveyorDemo.png
│ │ ├── cylinder.png
│ │ ├── frustum.png
│ │ ├── gimpact.png
│ │ ├── heightfield.png
│ │ ├── hull.png
│ │ ├── margin1.png
│ │ ├── margin4.png
│ │ ├── margin5.png
│ │ ├── margin6.png
│ │ ├── mesh.png
│ │ ├── minkowski.png
│ │ ├── multiSphere.png
│ │ ├── newtonsCradle.png
│ │ ├── pachinko.png
│ │ ├── plane.png
│ │ ├── segment.png
│ │ ├── simplex.png
│ │ ├── sphere.png
│ │ ├── splitDemo.png
│ │ ├── testGearJoint.png
│ │ ├── thousandCubes.png
│ │ └── windlass.png
│ │ ├── nav.adoc
│ │ └── pages
│ │ ├── add.adoc
│ │ ├── build.adoc
│ │ ├── character.adoc
│ │ ├── collision.adoc
│ │ ├── debug.adoc
│ │ ├── demos.adoc
│ │ ├── implementation.adoc
│ │ ├── lexicon.adoc
│ │ ├── misc.adoc
│ │ ├── new6dof.adoc
│ │ ├── overview.adoc
│ │ ├── rigidbody.adoc
│ │ ├── shape.adoc
│ │ ├── softbody.adoc
│ │ ├── sport.adoc
│ │ └── vehicle.adoc
└── playbook.yml
├── gradle.properties
├── gradle
├── libs.versions.toml
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── kotlin-apps
├── build.gradle.kts
└── src
│ └── main
│ ├── kotlin
│ └── com
│ │ └── github
│ │ └── stephengold
│ │ └── lbjexamples
│ │ └── ktapps
│ │ ├── HelloCcd.kt
│ │ ├── HelloCharacter.kt
│ │ ├── HelloCloth.kt
│ │ ├── HelloClothRigid.kt
│ │ ├── HelloContactResponse.kt
│ │ ├── HelloDamping.kt
│ │ ├── HelloDeactivation.kt
│ │ ├── HelloDoubleEnded.kt
│ │ ├── HelloGhost.kt
│ │ ├── HelloJoint.kt
│ │ ├── HelloKinematics.kt
│ │ ├── HelloLimit.kt
│ │ ├── HelloMadMallet.kt
│ │ ├── HelloMassDistribution.kt
│ │ ├── HelloMotor.kt
│ │ ├── HelloNonUniformGravity.kt
│ │ ├── HelloPin.kt
│ │ ├── HelloRigidBody.kt
│ │ ├── HelloServo.kt
│ │ ├── HelloSoftBody.kt
│ │ ├── HelloSoftRope.kt
│ │ ├── HelloSoftSoft.kt
│ │ ├── HelloSport.kt
│ │ ├── HelloSpring.kt
│ │ ├── HelloStaticBody.kt
│ │ ├── HelloVehicle.kt
│ │ ├── HelloWalk.kt
│ │ └── console
│ │ ├── HelloLibbulletjme.kt
│ │ └── HelloVehicle0.kt
│ └── resources
│ └── Textures
│ ├── Terrain
│ └── splat
│ │ └── mountains512.png
│ └── greenTile.png
├── package-lock.json
├── package.json
└── settings.gradle.kts
/.github/workflows/push.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # GitHub Actions workflow for commits pushed to the LbjExamples repo - all branches
3 |
4 | name: CI at GitHub
5 | on: [push]
6 |
7 | jobs:
8 | Java8-Linux:
9 | if: contains(toJson(github.event.commits), '[ci skip] ') == false
10 | runs-on: ubuntu-22.04
11 | steps:
12 | - uses: actions/setup-java@v4
13 | with:
14 | distribution: 'zulu'
15 | java-version: 8
16 | - uses: actions/checkout@v4
17 | - run: ./gradlew javadoc --console=plain --stacktrace
18 | - run: ./gradlew :apps:HelloLibbulletjme --console=plain --stacktrace
19 | - run: ./gradlew :apps:HelloVehicle0 --console=plain --stacktrace
20 |
21 | Java11-Linux:
22 | if: contains(toJson(github.event.commits), '[ci skip] ') == false
23 | runs-on: ubuntu-24.04
24 | steps:
25 | - uses: actions/setup-java@v4
26 | with:
27 | distribution: 'zulu'
28 | java-version: 11
29 | - uses: actions/checkout@v4
30 | - uses: gradle/actions/wrapper-validation@v4
31 | - run: ./gradlew javadoc --console=plain --stacktrace
32 | - run: ./gradlew :apps:HelloLibbulletjme --console=plain --stacktrace
33 | - run: ./gradlew :apps:HelloVehicle0 --console=plain --stacktrace
34 |
35 | Java17-MacOS:
36 | if: contains(toJson(github.event.commits), '[ci skip] ') == false
37 | runs-on: macOS-13
38 | steps:
39 | - uses: actions/setup-java@v4
40 | with:
41 | distribution: 'zulu'
42 | java-version: 17
43 | - uses: actions/checkout@v4
44 | - run: ./gradlew javadoc --console=plain --stacktrace
45 | - run: ./gradlew :apps:HelloLibbulletjme --console=plain --stacktrace
46 | - run: ./gradlew :apps:HelloVehicle0 --console=plain --stacktrace
47 |
48 | Java21-MacOS:
49 | if: contains(toJson(github.event.commits), '[ci skip] ') == false
50 | runs-on: macOS-15
51 | steps:
52 | - uses: actions/setup-java@v4
53 | with:
54 | distribution: 'zulu'
55 | java-version: 21
56 | - uses: actions/checkout@v4
57 | - run: ./gradlew javadoc --console=plain --stacktrace
58 | - run: ./gradlew :apps:HelloLibbulletjme --console=plain --stacktrace
59 | - run: ./gradlew :apps:HelloVehicle0 --console=plain --stacktrace
60 |
61 | Java23-Windows:
62 | if: contains(toJson(github.event.commits), '[ci skip] ') == false
63 | runs-on: windows-2025
64 | steps:
65 | - uses: actions/setup-java@v4
66 | with:
67 | distribution: 'zulu'
68 | java-version: 23
69 | - uses: actions/checkout@v4
70 | - run: ./gradlew javadoc --console=plain --stacktrace
71 | shell: bash
72 | - run: ./gradlew :apps:HelloLibbulletjme --console=plain --stacktrace
73 | shell: bash
74 | - run: ./gradlew :apps:HelloVehicle0 --console=plain --stacktrace
75 | shell: bash
76 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Ignore Gradle's project-specific cache directory:
2 | /.gradle/
3 |
4 | # Ignore Gradle's build output directories:
5 | /apps/build/
6 | /build/
7 | /docs/build/
8 | /kotlin-apps/build/
9 |
10 | /.kotlin/
11 | /node_modules/
12 |
13 | # JVM crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
14 | hs_err_pid*
15 |
16 | # Ignore IDE-specific directories:
17 | /.idea/
18 | /.nb-gradle/
19 |
20 | # Ignore extracted native libraries:
21 | *.dll
22 | *.dylib
23 | *.so
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Software packages Copyright (c) 2017-2024 Stephen Gold and Yanis Boudiaf
4 | mountains512.png Copyright (c) 2009-2022 jMonkeyEngine
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | 1. Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | 3. Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | [The LbjExamples Project][project] provides
4 | documentation and example applications
5 | for [the Libbulletjme 3-D physics library][libbulletjme].
6 |
7 | It contains 3 subprojects:
8 |
9 | 1. docs: [Antora] documentation for Libbulletjme, including the tutorial
10 | 2. apps: [Java] applications referenced in the tutorial
11 | 3. kotlin-apps: [Kotlin] translations of certain apps
12 |
13 | The applications make use of [the SPORT graphics engine][sport],
14 | which was formerly a subproject and
15 | is now a separate project at [GitHub].
16 |
17 | Complete source code is provided under
18 | [a 3-clause BSD license][license].
19 |
20 |
21 | ## How to build and run LbjExamples from source
22 |
23 | ### Initial build
24 |
25 | 1. Install a [Java Development Kit (JDK)][adoptium],
26 | if you don't already have one.
27 | 2. Point the `JAVA_HOME` environment variable to your JDK installation:
28 | (In other words, set it to the path of a directory/folder
29 | containing a "bin" that contains a Java executable.
30 | That path might look something like
31 | "C:\Program Files\Eclipse Adoptium\jdk-17.0.3.7-hotspot"
32 | or "/usr/lib/jvm/java-17-openjdk-amd64/" or
33 | "/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home" .)
34 | + using Bash or Zsh: `export JAVA_HOME="` *path to installation* `"`
35 | + using [Fish]: `set -g JAVA_HOME "` *path to installation* `"`
36 | + using Windows Command Prompt: `set JAVA_HOME="` *path to installation* `"`
37 | + using PowerShell: `$env:JAVA_HOME = '` *path to installation* `'`
38 | 3. Download and extract the LbjExamples source code from GitHub:
39 | + using [Git]:
40 | + `git clone https://github.com/stephengold/LbjExamples.git`
41 | + `cd LbjExamples`
42 | 4. Run the [Gradle] wrapper:
43 | + using Bash or Fish or PowerShell or Zsh: `./gradlew build`
44 | + using Windows Command Prompt: `.\gradlew build`
45 |
46 | ### Tutorials
47 |
48 | The tutorial apps all have names starting with "Hello".
49 | For instance, the first tutorial app is named "HelloLibbulletjme".
50 |
51 | To execute "HelloLibbulletjme":
52 | + using Bash or Fish or PowerShell or Zsh: `./gradlew :apps:HelloLibbulletjme`
53 | + using Windows Command Prompt: `.\gradlew :apps:HelloLibbulletjme`
54 |
55 | ### Chooser
56 |
57 | A [Swing]-based chooser application is provided.
58 | However, it includes only the graphical apps and doesn't work on macOS yet.
59 |
60 | To run the chooser:
61 | + using Bash or Fish or PowerShell or Zsh: `./gradlew AppChooser`
62 | + using Windows Command Prompt: `.\gradlew AppChooser`
63 |
64 | ### Cleanup
65 |
66 | You can restore the project to a pristine state:
67 | + using Bash or Fish or PowerShell or Zsh: `./gradlew clean`
68 | + using Windows Command Prompt: `.\gradlew clean`
69 |
70 |
71 | [adoptium]: https://adoptium.net/releases.html "Adoptium"
72 | [antora]: https://antora.org/ "Antora site generator"
73 | [fish]: https://fishshell.com/ "Fish command-line shell"
74 | [git]: https://git-scm.com "Git version-control system"
75 | [github]: https://en.wikipedia.org/wiki/GitHub "GitHub"
76 | [gradle]: https://gradle.org "Gradle build tool"
77 | [java]: https://en.wikipedia.org/wiki/Java_(programming_language) "Java programming language"
78 | [kotlin]: https://en.wikipedia.org/wiki/Kotlin_(programming_language) "Kotlin programming language"
79 | [libbulletjme]: https://stephengold.github.io/Libbulletjme/lbj-en/English/overview.html "Libbulletjme Project"
80 | [license]: https://github.com/stephengold/LbjExamples/blob/master/LICENSE "LbjExamples license"
81 | [project]: https://github.com/stephengold/LbjExamples "LbjExamples Project"
82 | [sport]: https://github.com/stephengold/sport "SPORT Project"
83 | [swing]: https://en.wikipedia.org/wiki/Swing_(Java) "Swing toolkit"
84 |
--------------------------------------------------------------------------------
/apps/src/main/java/com/github/stephengold/lbjexamples/apps/HelloCcd.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2020-2025 Stephen Gold and Yanis Boudiaf
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package com.github.stephengold.lbjexamples.apps;
30 |
31 | import com.github.stephengold.sport.physics.BasePhysicsApp;
32 | import com.jme3.bullet.PhysicsSpace;
33 | import com.jme3.bullet.collision.shapes.CollisionShape;
34 | import com.jme3.bullet.collision.shapes.CylinderCollisionShape;
35 | import com.jme3.bullet.collision.shapes.SphereCollisionShape;
36 | import com.jme3.bullet.objects.PhysicsBody;
37 | import com.jme3.bullet.objects.PhysicsRigidBody;
38 | import com.jme3.math.Vector3f;
39 |
40 | /**
41 | * A simple example of continuous collision detection (CCD).
42 | *
43 | * Builds upon HelloStaticBody.
44 | *
45 | * @author Stephen Gold sgold@sonic.net
46 | */
47 | public class HelloCcd extends BasePhysicsApp {
48 | // *************************************************************************
49 | // constructors
50 |
51 | /**
52 | * Instantiate the HelloCcd application.
53 | *
54 | * This no-arg constructor was made explicit to avoid javadoc warnings from
55 | * JDK 18+.
56 | */
57 | public HelloCcd() {
58 | // do nothing
59 | }
60 | // *************************************************************************
61 | // new methods exposed
62 |
63 | /**
64 | * Main entry point for the HelloCcd application.
65 | *
66 | * @param arguments array of command-line arguments (not null)
67 | */
68 | public static void main(String[] arguments) {
69 | HelloCcd application = new HelloCcd();
70 | application.start();
71 | }
72 | // *************************************************************************
73 | // BasePhysicsApp methods
74 |
75 | /**
76 | * Create the PhysicsSpace. Invoked once during initialization.
77 | *
78 | * @return a new object
79 | */
80 | @Override
81 | public PhysicsSpace createSpace() {
82 | PhysicsSpace result
83 | = new PhysicsSpace(PhysicsSpace.BroadphaseType.DBVT);
84 |
85 | // Increase gravity to make the balls fall faster.
86 | result.setGravity(new Vector3f(0f, -100f, 0f));
87 |
88 | return result;
89 | }
90 |
91 | /**
92 | * Initialize the application. Invoked once.
93 | */
94 | @Override
95 | public void initialize() {
96 | super.initialize();
97 | setVsync(true);
98 | }
99 |
100 | /**
101 | * Populate the PhysicsSpace. Invoked once during initialization.
102 | */
103 | @Override
104 | public void populateSpace() {
105 | // Create a CollisionShape for balls.
106 | float ballRadius = 0.1f;
107 | CollisionShape ballShape = new SphereCollisionShape(ballRadius);
108 |
109 | // Create 2 dynamic balls, one with CCD and one without,
110 | // and add them to the space.
111 | float mass = 1f;
112 | PhysicsRigidBody ccdBall = new PhysicsRigidBody(ballShape, mass);
113 | physicsSpace.addCollisionObject(ccdBall);
114 | ccdBall.setCcdMotionThreshold(ballRadius);
115 | ccdBall.setCcdSweptSphereRadius(ballRadius);
116 | ccdBall.setPhysicsLocation(new Vector3f(-1f, 4f, 0f));
117 |
118 | PhysicsRigidBody controlBall = new PhysicsRigidBody(ballShape, mass);
119 | physicsSpace.addCollisionObject(controlBall);
120 | controlBall.setPhysicsLocation(new Vector3f(1f, 4f, 0f));
121 |
122 | // Create a thin, static disc and add it to the space.
123 | float discRadius = 2f;
124 | float discThickness = 0.05f;
125 | CollisionShape discShape = new CylinderCollisionShape(
126 | discRadius, discThickness, PhysicsSpace.AXIS_Y);
127 | PhysicsRigidBody disc
128 | = new PhysicsRigidBody(discShape, PhysicsBody.massForStatic);
129 | physicsSpace.addCollisionObject(disc);
130 |
131 | // Visualize the shapes of all 3 rigid bodies:
132 | visualizeShape(ccdBall);
133 | visualizeShape(controlBall);
134 | visualizeShape(disc).setProgram("Unshaded/Monochrome");
135 | }
136 |
137 | /**
138 | * Advance the physics simulation by the specified amount. Invoked during
139 | * each update.
140 | *
141 | * @param wallClockSeconds the elapsed wall-clock time since the previous
142 | * invocation of {@code updatePhysics} (in seconds, ≥0)
143 | */
144 | @Override
145 | public void updatePhysics(float wallClockSeconds) {
146 | // For clarity, simulate at 1/10th normal speed.
147 | float simulateSeconds = 0.1f * wallClockSeconds;
148 | physicsSpace.update(simulateSeconds);
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/apps/src/main/java/com/github/stephengold/lbjexamples/apps/HelloCloth.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2019-2025 Stephen Gold and Yanis Boudiaf
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package com.github.stephengold.lbjexamples.apps;
30 |
31 | import com.github.stephengold.sport.Mesh;
32 | import com.github.stephengold.sport.mesh.ClothGrid;
33 | import com.github.stephengold.sport.physics.BasePhysicsApp;
34 | import com.github.stephengold.sport.physics.LinksGeometry;
35 | import com.jme3.bullet.PhysicsSoftSpace;
36 | import com.jme3.bullet.PhysicsSpace;
37 | import com.jme3.bullet.collision.shapes.SphereCollisionShape;
38 | import com.jme3.bullet.objects.PhysicsBody;
39 | import com.jme3.bullet.objects.PhysicsRigidBody;
40 | import com.jme3.bullet.objects.PhysicsSoftBody;
41 | import com.jme3.bullet.objects.infos.SoftBodyConfig;
42 | import com.jme3.bullet.objects.infos.SoftBodyMaterial;
43 | import com.jme3.bullet.util.NativeSoftBodyUtil;
44 | import com.jme3.math.Vector3f;
45 |
46 | /**
47 | * A simple cloth simulation using a soft body.
48 | *
49 | * Builds upon HelloSoftBody.
50 | *
51 | * @author Stephen Gold sgold@sonic.net
52 | */
53 | public class HelloCloth extends BasePhysicsApp {
54 | // *************************************************************************
55 | // constructors
56 |
57 | /**
58 | * Instantiate the HelloCloth application.
59 | *
60 | * This no-arg constructor was made explicit to avoid javadoc warnings from
61 | * JDK 18+.
62 | */
63 | public HelloCloth() {
64 | // do nothing
65 | }
66 | // *************************************************************************
67 | // new methods exposed
68 |
69 | /**
70 | * Main entry point for the HelloCloth application.
71 | *
72 | * @param arguments array of command-line arguments (not null)
73 | */
74 | public static void main(String[] arguments) {
75 | HelloCloth application = new HelloCloth();
76 | application.start();
77 | }
78 | // *************************************************************************
79 | // BasePhysicsApp methods
80 |
81 | /**
82 | * Create the PhysicsSpace. Invoked once during initialization.
83 | *
84 | * @return a new object
85 | */
86 | @Override
87 | public PhysicsSoftSpace createSpace() {
88 | Vector3f worldMin = new Vector3f(-999f, -999f, -999f);
89 | Vector3f worldMax = new Vector3f(+999f, +999f, +999f);
90 | PhysicsSoftSpace result = new PhysicsSoftSpace(
91 | worldMin, worldMax, PhysicsSpace.BroadphaseType.DBVT);
92 |
93 | return result;
94 | }
95 |
96 | /**
97 | * Initialize the application. Invoked once.
98 | */
99 | @Override
100 | public void initialize() {
101 | super.initialize();
102 | setVsync(true);
103 |
104 | // Relocate the camera.
105 | cam.setLocation(new Vector3f(0f, 1f, 8f));
106 | }
107 |
108 | /**
109 | * Populate the PhysicsSpace. Invoked once during initialization.
110 | */
111 | @Override
112 | public void populateSpace() {
113 | // Create a static, rigid sphere and add it to the physics space.
114 | float radius = 1f;
115 | SphereCollisionShape shape = new SphereCollisionShape(radius);
116 | PhysicsRigidBody sphere
117 | = new PhysicsRigidBody(shape, PhysicsBody.massForStatic);
118 | physicsSpace.addCollisionObject(sphere);
119 | visualizeShape(sphere);
120 |
121 | // Generate a subdivided square mesh with alternating diagonals.
122 | int numLines = 41;
123 | float lineSpacing = 0.1f; // mesh units
124 | Mesh squareGrid = new ClothGrid(numLines, numLines, lineSpacing);
125 |
126 | // Create a soft square and add it to the physics space.
127 | PhysicsSoftBody cloth = new PhysicsSoftBody();
128 | NativeSoftBodyUtil.appendFromTriMesh(squareGrid, cloth);
129 | physicsSpace.addCollisionObject(cloth);
130 | /*
131 | * Make the cloth flexible by reducing the angular stiffness
132 | * of its material.
133 | */
134 | SoftBodyMaterial mat = cloth.getSoftMaterial();
135 | mat.setAngularStiffness(0f); // default=1
136 | /*
137 | * Improve simulation accuracy by increasing
138 | * the number of position-solver iterations for the cloth.
139 | */
140 | SoftBodyConfig config = cloth.getSoftConfig();
141 | config.setPositionIterations(9); // default=1
142 |
143 | // Translate the cloth upward to its starting location.
144 | cloth.applyTranslation(new Vector3f(0f, 2f, 0f));
145 |
146 | // Visualize the soft-body links:
147 | new LinksGeometry(cloth);
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/apps/src/main/java/com/github/stephengold/lbjexamples/apps/HelloDamping.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2020-2025 Stephen Gold and Yanis Boudiaf
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package com.github.stephengold.lbjexamples.apps;
30 |
31 | import com.github.stephengold.sport.physics.BasePhysicsApp;
32 | import com.jme3.bullet.PhysicsSpace;
33 | import com.jme3.bullet.collision.shapes.BoxCollisionShape;
34 | import com.jme3.bullet.collision.shapes.CollisionShape;
35 | import com.jme3.bullet.objects.PhysicsRigidBody;
36 | import com.jme3.math.Vector3f;
37 |
38 | /**
39 | * A simple example illustrating the effect of damping on dynamic rigid bodies.
40 | *
41 | * Builds upon HelloRigidBody.
42 | *
43 | * @author Stephen Gold sgold@sonic.net
44 | */
45 | public class HelloDamping extends BasePhysicsApp {
46 | // *************************************************************************
47 | // constructors
48 |
49 | /**
50 | * Instantiate the HelloDamping application.
51 | *
52 | * This no-arg constructor was made explicit to avoid javadoc warnings from
53 | * JDK 18+.
54 | */
55 | public HelloDamping() {
56 | // do nothing
57 | }
58 | // *************************************************************************
59 | // new methods exposed
60 |
61 | /**
62 | * Main entry point for the HelloDamping application.
63 | *
64 | * @param arguments array of command-line arguments (not null)
65 | */
66 | public static void main(String[] arguments) {
67 | HelloDamping application = new HelloDamping();
68 | application.start();
69 | }
70 | // *************************************************************************
71 | // BasePhysicsApp methods
72 |
73 | /**
74 | * Create the PhysicsSpace. Invoked once during initialization.
75 | *
76 | * @return a new object
77 | */
78 | @Override
79 | public PhysicsSpace createSpace() {
80 | PhysicsSpace result
81 | = new PhysicsSpace(PhysicsSpace.BroadphaseType.DBVT);
82 |
83 | // For clarity, disable gravity.
84 | result.setGravity(Vector3f.ZERO);
85 |
86 | return result;
87 | }
88 |
89 | /**
90 | * Populate the PhysicsSpace. Invoked once during initialization.
91 | */
92 | @Override
93 | public void populateSpace() {
94 | // Create a CollisionShape for unit cubes.
95 | float cubeHalfExtent = 0.5f;
96 | CollisionShape cubeShape = new BoxCollisionShape(cubeHalfExtent);
97 |
98 | // Create 4 cubes (dynamic rigid bodies) and add them to the space.
99 | int numCubes = 4;
100 | float cubeMass = 2f;
101 | PhysicsRigidBody[] cube = new PhysicsRigidBody[numCubes];
102 | for (int cubeIndex = 0; cubeIndex < numCubes; ++cubeIndex) {
103 | cube[cubeIndex] = new PhysicsRigidBody(cubeShape, cubeMass);
104 | physicsSpace.addCollisionObject(cube[cubeIndex]);
105 |
106 | // Disable sleep (deactivation) for clarity.
107 | cube[cubeIndex].setEnableSleep(false);
108 | }
109 |
110 | // Locate the cubes 4 psu apart, center to center.
111 | cube[0].setPhysicsLocation(new Vector3f(0f, +2f, 0f));
112 | cube[1].setPhysicsLocation(new Vector3f(4f, +2f, 0f));
113 | cube[2].setPhysicsLocation(new Vector3f(0f, -2f, 0f));
114 | cube[3].setPhysicsLocation(new Vector3f(4f, -2f, 0f));
115 |
116 | // Give each cube its own set of damping parameters (linear, angular).
117 | cube[0].setDamping(0f, 0f);
118 | cube[1].setDamping(0f, 0.9f);
119 | cube[2].setDamping(0.9f, 0f);
120 | cube[3].setDamping(0.9f, 0.9f);
121 | /*
122 | * Apply an off-center impulse to each cube,
123 | * causing it to drift and spin.
124 | */
125 | Vector3f impulse = new Vector3f(-1f, 0f, 0f);
126 | Vector3f offset = new Vector3f(0f, 1f, 1f);
127 | for (int cubeIndex = 0; cubeIndex < numCubes; ++cubeIndex) {
128 | cube[cubeIndex].applyImpulse(impulse, offset);
129 | }
130 |
131 | // Visualize the shapes of all 4 cubes:
132 | for (int cubeIndex = 0; cubeIndex < numCubes; ++cubeIndex) {
133 | visualizeShape(cube[cubeIndex]);
134 | }
135 | }
136 |
137 | /**
138 | * Advance the physics simulation by the specified amount. Invoked during
139 | * each update.
140 | *
141 | * @param wallClockSeconds the elapsed wall-clock time since the previous
142 | * invocation of {@code updatePhysics} (in seconds, ≥0)
143 | */
144 | @Override
145 | public void updatePhysics(float wallClockSeconds) {
146 | physicsSpace.update(wallClockSeconds);
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/apps/src/main/java/com/github/stephengold/lbjexamples/apps/HelloMadMallet.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2020-2025 Stephen Gold and Yanis Boudiaf
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package com.github.stephengold.lbjexamples.apps;
30 |
31 | import com.github.stephengold.sport.input.RotateMode;
32 | import com.github.stephengold.sport.physics.BasePhysicsApp;
33 | import com.jme3.bullet.PhysicsSpace;
34 | import com.jme3.bullet.collision.shapes.CollisionShape;
35 | import com.jme3.bullet.collision.shapes.CompoundCollisionShape;
36 | import com.jme3.bullet.collision.shapes.CylinderCollisionShape;
37 | import com.jme3.bullet.objects.PhysicsBody;
38 | import com.jme3.bullet.objects.PhysicsRigidBody;
39 | import com.jme3.math.Vector3f;
40 |
41 | /**
42 | * A simple example of a dynamic rigid body with an implausible center.
43 | *
44 | * Builds upon HelloStaticBody.
45 | *
46 | * @author Stephen Gold sgold@sonic.net
47 | */
48 | public class HelloMadMallet extends BasePhysicsApp {
49 | // *************************************************************************
50 | // constructors
51 |
52 | /**
53 | * Instantiate the HelloMadMallet application.
54 | *
55 | * This no-arg constructor was made explicit to avoid javadoc warnings from
56 | * JDK 18+.
57 | */
58 | public HelloMadMallet() {
59 | // do nothing
60 | }
61 | // *************************************************************************
62 | // new methods exposed
63 |
64 | /**
65 | * Main entry point for the HelloMadMallet application.
66 | *
67 | * @param arguments array of command-line arguments (not null)
68 | */
69 | public static void main(String[] arguments) {
70 | HelloMadMallet application = new HelloMadMallet();
71 | application.start();
72 | }
73 | // *************************************************************************
74 | // BasePhysicsApp methods
75 |
76 | /**
77 | * Create the PhysicsSpace. Invoked once during initialization.
78 | *
79 | * @return a new object
80 | */
81 | @Override
82 | public PhysicsSpace createSpace() {
83 | PhysicsSpace result
84 | = new PhysicsSpace(PhysicsSpace.BroadphaseType.DBVT);
85 | result.setGravity(new Vector3f(0f, -50f, 0f));
86 |
87 | return result;
88 | }
89 |
90 | /**
91 | * Initialize the application. Invoked once.
92 | */
93 | @Override
94 | public void initialize() {
95 | super.initialize();
96 | setVsync(true);
97 | getCameraInputProcessor().setRotationMode(RotateMode.DragLMB);
98 |
99 | // Position the camera for a good view.
100 | cam.setLocation(new Vector3f(10f, -2.75f, 0f));
101 | cam.setUpAngle(0.05f);
102 | cam.setAzimuth(-3.05f);
103 | }
104 |
105 | /**
106 | * Populate the PhysicsSpace. Invoked once during initialization.
107 | */
108 | @Override
109 | public void populateSpace() {
110 | // Construct a compound shape for the mallet.
111 | float headLength = 1f;
112 | float headRadius = 0.5f;
113 | Vector3f hes = new Vector3f(headLength / 2f, headRadius, headRadius);
114 | CollisionShape headShape
115 | = new CylinderCollisionShape(hes, PhysicsSpace.AXIS_X);
116 |
117 | float handleLength = 3f;
118 | float handleRadius = 0.3f;
119 | hes.set(handleRadius, handleRadius, handleLength / 2f);
120 | CollisionShape handleShape
121 | = new CylinderCollisionShape(hes, PhysicsSpace.AXIS_Z);
122 |
123 | CompoundCollisionShape malletShape = new CompoundCollisionShape();
124 | malletShape.addChildShape(handleShape, 0f, 0f, handleLength / 2f);
125 | malletShape.addChildShape(headShape, 0f, 0f, handleLength);
126 |
127 | // Create a dynamic body for the mallet.
128 | float mass = 2f;
129 | PhysicsRigidBody mallet = new PhysicsRigidBody(malletShape, mass);
130 | mallet.setPhysicsLocation(new Vector3f(0f, 4f, 0f));
131 |
132 | // Increase the mallet's angular damping to stabilize it.
133 | mallet.setAngularDamping(0.9f);
134 |
135 | physicsSpace.addCollisionObject(mallet);
136 |
137 | // Create a static disc and add it to the space.
138 | float discRadius = 5f;
139 | float discThickness = 0.5f;
140 | CollisionShape discShape = new CylinderCollisionShape(
141 | discRadius, discThickness, PhysicsSpace.AXIS_Y);
142 | PhysicsRigidBody disc
143 | = new PhysicsRigidBody(discShape, PhysicsBody.massForStatic);
144 | physicsSpace.addCollisionObject(disc);
145 | disc.setPhysicsLocation(new Vector3f(0f, -3f, 0f));
146 |
147 | // Visualize the mallet, including its local axes.
148 | visualizeShape(mallet);
149 | float debugAxisLength = 1f;
150 | visualizeAxes(mallet, debugAxisLength);
151 |
152 | // Visualize the shape of the disc:
153 | visualizeShape(disc);
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/apps/src/main/java/com/github/stephengold/lbjexamples/apps/HelloMinkowski.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2020-2025 Stephen Gold and Yanis Boudiaf
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package com.github.stephengold.lbjexamples.apps;
30 |
31 | import com.github.stephengold.sport.input.RotateMode;
32 | import com.github.stephengold.sport.physics.BasePhysicsApp;
33 | import com.jme3.bullet.PhysicsSpace;
34 | import com.jme3.bullet.collision.shapes.ConeCollisionShape;
35 | import com.jme3.bullet.collision.shapes.MinkowskiSum;
36 | import com.jme3.bullet.objects.PhysicsBody;
37 | import com.jme3.bullet.objects.PhysicsRigidBody;
38 | import com.jme3.math.Vector3f;
39 |
40 | /**
41 | * A simple example of a MinkowskiSum collision shape.
42 | *
43 | * Builds upon HelloStaticBody.
44 | *
45 | * @author Stephen Gold sgold@sonic.net
46 | */
47 | public class HelloMinkowski extends BasePhysicsApp {
48 | // *************************************************************************
49 | // constructors
50 |
51 | /**
52 | * Instantiate the HelloMinkowski application.
53 | *
54 | * This no-arg constructor was made explicit to avoid javadoc warnings from
55 | * JDK 18+.
56 | */
57 | public HelloMinkowski() {
58 | // do nothing
59 | }
60 | // *************************************************************************
61 | // new methods exposed
62 |
63 | /**
64 | * Main entry point for the HelloMinkowski application.
65 | *
66 | * @param arguments array of command-line arguments (not null)
67 | */
68 | public static void main(String[] arguments) {
69 | HelloMinkowski application = new HelloMinkowski();
70 | application.start();
71 | }
72 | // *************************************************************************
73 | // BasePhysicsApp methods
74 |
75 | /**
76 | * Create the PhysicsSpace. Invoked once during initialization.
77 | *
78 | * @return a new object
79 | */
80 | @Override
81 | public PhysicsSpace createSpace() {
82 | PhysicsSpace result
83 | = new PhysicsSpace(PhysicsSpace.BroadphaseType.DBVT);
84 | return result;
85 | }
86 |
87 | /**
88 | * Initialize the application. Invoked once.
89 | */
90 | @Override
91 | public void initialize() {
92 | super.initialize();
93 |
94 | setVsync(true);
95 | getCameraInputProcessor().setRotationMode(RotateMode.DragLMB);
96 | }
97 |
98 | /**
99 | * Populate the PhysicsSpace. Invoked once during initialization.
100 | */
101 | @Override
102 | public void populateSpace() {
103 | // Add a static rigid body with a cone shape.
104 | float radius = 1f;
105 | float height = 1f;
106 | ConeCollisionShape coneShape = new ConeCollisionShape(radius, height);
107 | PhysicsRigidBody cone
108 | = new PhysicsRigidBody(coneShape, PhysicsBody.massForStatic);
109 | cone.setPhysicsLocation(new Vector3f(3f, 0f, 0f));
110 | physicsSpace.addCollisionObject(cone);
111 | visualizeShape(cone);
112 |
113 | // Add a static rigid body with a Minkowski-sum shape.
114 | MinkowskiSum sumShape = new MinkowskiSum(coneShape, coneShape);
115 | PhysicsRigidBody sum
116 | = new PhysicsRigidBody(sumShape, PhysicsBody.massForStatic);
117 | physicsSpace.addCollisionObject(sum);
118 | visualizeShape(sum);
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/apps/src/main/java/com/github/stephengold/lbjexamples/apps/HelloRigidBody.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2020-2025 Stephen Gold and Yanis Boudiaf
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package com.github.stephengold.lbjexamples.apps;
30 |
31 | import com.github.stephengold.sport.physics.BasePhysicsApp;
32 | import com.jme3.bullet.PhysicsSpace;
33 | import com.jme3.bullet.collision.shapes.CollisionShape;
34 | import com.jme3.bullet.collision.shapes.SphereCollisionShape;
35 | import com.jme3.bullet.objects.PhysicsRigidBody;
36 | import com.jme3.math.Vector3f;
37 |
38 | /**
39 | * A simple example of 2 colliding balls, illustrating the 5 basic features of
40 | * responsive, dynamic, rigid bodies:
41 | * - rigidity (fixed shape),
42 | * - inertia (resistance to changes of motion),
43 | * - dynamics (motion determined by forces, torques, and impulses),
44 | * - gravity (continual downward force), and
45 | * - contact response (avoid intersecting with other bodies).
46 | *
47 | *
48 | * Builds upon HelloSport.
49 | *
50 | * @author Stephen Gold sgold@sonic.net
51 | */
52 | public class HelloRigidBody extends BasePhysicsApp {
53 | // *************************************************************************
54 | // constructors
55 |
56 | /**
57 | * Instantiate the HelloRigidBody application.
58 | *
59 | * This no-arg constructor was made explicit to avoid javadoc warnings from
60 | * JDK 18+.
61 | */
62 | public HelloRigidBody() {
63 | // do nothing
64 | }
65 | // *************************************************************************
66 | // new methods exposed
67 |
68 | /**
69 | * Main entry point for the HelloRigidBody application.
70 | *
71 | * @param arguments array of command-line arguments (not null)
72 | */
73 | public static void main(String[] arguments) {
74 | HelloRigidBody application = new HelloRigidBody();
75 | application.start();
76 | }
77 | // *************************************************************************
78 | // BasePhysicsApp methods
79 |
80 | /**
81 | * Create the PhysicsSpace. Invoked once during initialization.
82 | *
83 | * @return a new object
84 | */
85 | @Override
86 | public PhysicsSpace createSpace() {
87 | PhysicsSpace result
88 | = new PhysicsSpace(PhysicsSpace.BroadphaseType.DBVT);
89 | return result;
90 | }
91 |
92 | /**
93 | * Populate the PhysicsSpace. Invoked once during initialization.
94 | */
95 | @Override
96 | public void populateSpace() {
97 | // Create a collision shape for balls.
98 | float ballRadius = 1f;
99 | CollisionShape ballShape = new SphereCollisionShape(ballRadius);
100 |
101 | // Create 2 balls (dynamic rigid bodies) and add them to the space.
102 | float ballMass = 2f;
103 | PhysicsRigidBody ball1 = new PhysicsRigidBody(ballShape, ballMass);
104 | physicsSpace.addCollisionObject(ball1);
105 | PhysicsRigidBody ball2 = new PhysicsRigidBody(ballShape, ballMass);
106 | physicsSpace.addCollisionObject(ball2);
107 |
108 | // Locate the balls initially 2 PSU (physics-space units) apart.
109 | // In other words, 4 PSU from center to center.
110 | ball1.setPhysicsLocation(new Vector3f(1f, 1f, 0f));
111 | ball2.setPhysicsLocation(new Vector3f(5f, 1f, 0f));
112 |
113 | // Set ball #2 on a collision course with ball #1.
114 | ball2.applyCentralImpulse(new Vector3f(-25f, 0f, 0f));
115 |
116 | // Visualize the shapes of both rigid bodies:
117 | visualizeShape(ball1);
118 | visualizeShape(ball2);
119 | }
120 |
121 | /**
122 | * Advance the physics simulation by the specified amount. Invoked during
123 | * each update.
124 | *
125 | * @param wallClockSeconds the elapsed wall-clock time since the previous
126 | * invocation of {@code updatePhysics} (in seconds, ≥0)
127 | */
128 | @Override
129 | public void updatePhysics(float wallClockSeconds) {
130 | // For clarity, simulate at 1/10th normal speed.
131 | float simulateSeconds = 0.1f * wallClockSeconds;
132 | physicsSpace.update(simulateSeconds);
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/apps/src/main/java/com/github/stephengold/lbjexamples/apps/HelloSoftBody.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2020-2025 Stephen Gold and Yanis Boudiaf
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package com.github.stephengold.lbjexamples.apps;
30 |
31 | import com.github.stephengold.sport.Mesh;
32 | import com.github.stephengold.sport.mesh.IcosphereMesh;
33 | import com.github.stephengold.sport.physics.BasePhysicsApp;
34 | import com.github.stephengold.sport.physics.FacesGeometry;
35 | import com.jme3.bullet.PhysicsSoftSpace;
36 | import com.jme3.bullet.PhysicsSpace;
37 | import com.jme3.bullet.collision.shapes.BoxCollisionShape;
38 | import com.jme3.bullet.objects.PhysicsBody;
39 | import com.jme3.bullet.objects.PhysicsRigidBody;
40 | import com.jme3.bullet.objects.PhysicsSoftBody;
41 | import com.jme3.bullet.objects.infos.Sbcp;
42 | import com.jme3.bullet.objects.infos.SoftBodyConfig;
43 | import com.jme3.bullet.util.NativeSoftBodyUtil;
44 | import com.jme3.math.Vector3f;
45 |
46 | /**
47 | * A simple example of a soft body colliding with a static rigid body.
48 | *
49 | * Builds upon HelloStaticBody.
50 | *
51 | * @author Stephen Gold sgold@sonic.net
52 | */
53 | public class HelloSoftBody extends BasePhysicsApp {
54 | // *************************************************************************
55 | // constructors
56 |
57 | /**
58 | * Instantiate the HelloSoftBody application.
59 | *
60 | * This no-arg constructor was made explicit to avoid javadoc warnings from
61 | * JDK 18+.
62 | */
63 | public HelloSoftBody() {
64 | // do nothing
65 | }
66 | // *************************************************************************
67 | // new methods exposed
68 |
69 | /**
70 | * Main entry point for the HelloSoftBody application.
71 | *
72 | * @param arguments array of command-line arguments (not null)
73 | */
74 | public static void main(String[] arguments) {
75 | HelloSoftBody application = new HelloSoftBody();
76 | application.start();
77 | }
78 | // *************************************************************************
79 | // BasePhysicsApp methods
80 |
81 | /**
82 | * Create the PhysicsSpace. Invoked once during initialization.
83 | *
84 | * @return a new object
85 | */
86 | @Override
87 | public PhysicsSoftSpace createSpace() {
88 | Vector3f worldMin = new Vector3f(-999f, -999f, -999f);
89 | Vector3f worldMax = new Vector3f(+999f, +999f, +999f);
90 | PhysicsSoftSpace result = new PhysicsSoftSpace(
91 | worldMin, worldMax, PhysicsSpace.BroadphaseType.DBVT);
92 |
93 | return result;
94 | }
95 |
96 | /**
97 | * Initialize the application. Invoked once.
98 | */
99 | @Override
100 | public void initialize() {
101 | super.initialize();
102 | setVsync(true);
103 |
104 | // Relocate the camera.
105 | cam.setLocation(new Vector3f(0f, 1f, 8f));
106 | }
107 |
108 | /**
109 | * Populate the PhysicsSpace. Invoked once during initialization.
110 | */
111 | @Override
112 | public void populateSpace() {
113 | addBox();
114 |
115 | // A mesh is used to generate the shape and topology of the soft body.
116 | int numRefinementIterations = 3;
117 | boolean indexed = true;
118 | Mesh mesh = new IcosphereMesh(numRefinementIterations, indexed);
119 |
120 | // Create a soft ball and add it to the physics space.
121 | PhysicsSoftBody body = new PhysicsSoftBody();
122 | NativeSoftBodyUtil.appendFromTriMesh(mesh, body);
123 | physicsSpace.addCollisionObject(body);
124 | /*
125 | * Set the ball's default frame pose: if deformed,
126 | * it will tend to return to its current shape.
127 | */
128 | boolean setVolumePose = false;
129 | boolean setFramePose = true;
130 | body.setPose(setVolumePose, setFramePose);
131 |
132 | // Enable pose matching to make the body bouncy.
133 | SoftBodyConfig config = body.getSoftConfig();
134 | config.set(Sbcp.PoseMatching, 0.05f);
135 |
136 | // Translate the body to its start location.
137 | body.applyTranslation(new Vector3f(0f, 3f, 0f));
138 |
139 | // Visualize the soft-body faces:
140 | new FacesGeometry(body);
141 | }
142 | // *************************************************************************
143 | // private methods
144 |
145 | /**
146 | * Add a large static cube to serve as a platform.
147 | */
148 | private void addBox() {
149 | float halfExtent = 3f; // mesh units
150 | BoxCollisionShape shape = new BoxCollisionShape(halfExtent);
151 |
152 | PhysicsRigidBody body
153 | = new PhysicsRigidBody(shape, PhysicsBody.massForStatic);
154 | body.setPhysicsLocation(new Vector3f(0f, -halfExtent, 0f));
155 | physicsSpace.addCollisionObject(body);
156 |
157 | visualizeShape(body);
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/apps/src/main/java/com/github/stephengold/lbjexamples/apps/HelloSoftRope.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2019-2025 Stephen Gold and Yanis Boudiaf
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package com.github.stephengold.lbjexamples.apps;
30 |
31 | import com.github.stephengold.sport.Mesh;
32 | import com.github.stephengold.sport.mesh.DividedLine;
33 | import com.github.stephengold.sport.physics.BasePhysicsApp;
34 | import com.github.stephengold.sport.physics.LinksGeometry;
35 | import com.github.stephengold.sport.physics.PinsGeometry;
36 | import com.jme3.bullet.PhysicsSoftSpace;
37 | import com.jme3.bullet.PhysicsSpace;
38 | import com.jme3.bullet.objects.PhysicsBody;
39 | import com.jme3.bullet.objects.PhysicsSoftBody;
40 | import com.jme3.bullet.util.NativeSoftBodyUtil;
41 | import com.jme3.math.Vector3f;
42 |
43 | /**
44 | * A simple rope simulation using a soft body.
45 | *
46 | * Builds upon HelloPin.
47 | *
48 | * @author Stephen Gold sgold@sonic.net
49 | */
50 | public class HelloSoftRope extends BasePhysicsApp {
51 | // *************************************************************************
52 | // constructors
53 |
54 | /**
55 | * Instantiate the HelloSoftRope application.
56 | *
57 | * This no-arg constructor was made explicit to avoid javadoc warnings from
58 | * JDK 18+.
59 | */
60 | public HelloSoftRope() {
61 | // do nothing
62 | }
63 | // *************************************************************************
64 | // new methods exposed
65 |
66 | /**
67 | * Main entry point for the HelloSoftRope application.
68 | *
69 | * @param arguments array of command-line arguments (not null)
70 | */
71 | public static void main(String[] arguments) {
72 | HelloSoftRope application = new HelloSoftRope();
73 | application.start();
74 | }
75 | // *************************************************************************
76 | // BasePhysicsApp methods
77 |
78 | /**
79 | * Create the PhysicsSpace. Invoked once during initialization.
80 | *
81 | * @return a new object
82 | */
83 | @Override
84 | public PhysicsSoftSpace createSpace() {
85 | Vector3f worldMin = new Vector3f(-999f, -999f, -999f);
86 | Vector3f worldMax = new Vector3f(+999f, +999f, +999f);
87 | PhysicsSoftSpace result = new PhysicsSoftSpace(
88 | worldMin, worldMax, PhysicsSpace.BroadphaseType.DBVT);
89 |
90 | return result;
91 | }
92 |
93 | /**
94 | * Initialize the application. Invoked once.
95 | */
96 | @Override
97 | public void initialize() {
98 | super.initialize();
99 | setVsync(true);
100 |
101 | // Relocate the camera:
102 | cam.setLocation(new Vector3f(0f, 1f, 8f));
103 | }
104 |
105 | /**
106 | * Populate the PhysicsSpace with bodies. Invoked once during
107 | * initialization.
108 | */
109 | @Override
110 | public void populateSpace() {
111 | // Generate a subdivided line segment:
112 | int numSegments = 40;
113 | Vector3f endPoint1 = new Vector3f(0f, 4f, 0f);
114 | Vector3f endPoint2 = new Vector3f(2f, 4f, 2f);
115 | Mesh lineMesh = new DividedLine(endPoint1, endPoint2, numSegments);
116 |
117 | // Create a soft body and add it to the physics space:
118 | PhysicsSoftBody rope = new PhysicsSoftBody();
119 | NativeSoftBodyUtil.appendFromLineMesh(lineMesh, rope);
120 | physicsSpace.addCollisionObject(rope);
121 |
122 | // Pin one of the end nodes by zeroing its mass:
123 | int nodeIndex = 0;
124 | rope.setNodeMass(nodeIndex, PhysicsBody.massForStatic);
125 |
126 | // Visualize the soft-body links and the pin:
127 | new LinksGeometry(rope);
128 | new PinsGeometry(rope);
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/apps/src/main/java/com/github/stephengold/lbjexamples/apps/HelloSport.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2020-2025 Stephen Gold and Yanis Boudiaf
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package com.github.stephengold.lbjexamples.apps;
30 |
31 | import com.github.stephengold.sport.physics.BasePhysicsApp;
32 | import com.jme3.bullet.PhysicsSpace;
33 | import com.jme3.bullet.collision.shapes.CollisionShape;
34 | import com.jme3.bullet.collision.shapes.PlaneCollisionShape;
35 | import com.jme3.bullet.collision.shapes.SphereCollisionShape;
36 | import com.jme3.bullet.objects.PhysicsBody;
37 | import com.jme3.bullet.objects.PhysicsRigidBody;
38 | import com.jme3.math.Plane;
39 | import com.jme3.math.Vector3f;
40 |
41 | /**
42 | * Drop a dynamic sphere onto a horizontal surface and visualize them both using
43 | * SPORT graphics.
44 | *
45 | * Builds upon HelloLibbulletjme.
46 | *
47 | * @author Stephen Gold sgold@sonic.net
48 | */
49 | public class HelloSport extends BasePhysicsApp {
50 | // *************************************************************************
51 | // constructors
52 |
53 | /**
54 | * Instantiate the HelloSport application.
55 | *
56 | * This no-arg constructor was made explicit to avoid javadoc warnings from
57 | * JDK 18+.
58 | */
59 | public HelloSport() {
60 | // do nothing
61 | }
62 | // *************************************************************************
63 | // new methods exposed
64 |
65 | /**
66 | * Main entry point for the HelloSport application.
67 | *
68 | * @param arguments array of command-line arguments (not null)
69 | */
70 | public static void main(String[] arguments) {
71 | HelloSport application = new HelloSport();
72 | application.start();
73 | /*
74 | * During initialization, BasePhysicsApp loads the native library
75 | * and invokes createSpace() and populateSpace().
76 | */
77 | }
78 | // *************************************************************************
79 | // BasePhysicsApp methods
80 |
81 | /**
82 | * Create the PhysicsSpace. Invoked once during initialization.
83 | *
84 | * @return a new object
85 | */
86 | @Override
87 | public PhysicsSpace createSpace() {
88 | PhysicsSpace.BroadphaseType bPhase = PhysicsSpace.BroadphaseType.DBVT;
89 | return new PhysicsSpace(bPhase);
90 | }
91 |
92 | /**
93 | * Populate the PhysicsSpace. Invoked once during initialization.
94 | */
95 | @Override
96 | public void populateSpace() {
97 | // Add a static horizontal plane at y=-1:
98 | float groundY = -1f;
99 | Plane plane = new Plane(Vector3f.UNIT_Y, groundY);
100 | CollisionShape planeShape = new PlaneCollisionShape(plane);
101 | float mass = PhysicsBody.massForStatic;
102 | PhysicsRigidBody floor = new PhysicsRigidBody(planeShape, mass);
103 | physicsSpace.addCollisionObject(floor);
104 |
105 | // Add a sphere-shaped, dynamic, rigid body at the origin:
106 | float ballRadius = 0.3f;
107 | CollisionShape ballShape = new SphereCollisionShape(ballRadius);
108 | mass = 1f;
109 | PhysicsRigidBody ball = new PhysicsRigidBody(ballShape, mass);
110 | physicsSpace.addCollisionObject(ball);
111 |
112 | // Visualize the shapes of both rigid bodies:
113 | visualizeShape(floor);
114 | visualizeShape(ball);
115 | }
116 |
117 | /**
118 | * Advance the physics simulation by the specified amount. Invoked during
119 | * each update.
120 | *
121 | * @param wallClockSeconds the elapsed wall-clock time since the previous
122 | * invocation of {@code updatePhysics} (in seconds, ≥0)
123 | */
124 | @Override
125 | public void updatePhysics(float wallClockSeconds) {
126 | physicsSpace.update(wallClockSeconds);
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/apps/src/main/java/com/github/stephengold/lbjexamples/apps/HelloStaticBody.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2020-2025 Stephen Gold and Yanis Boudiaf
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package com.github.stephengold.lbjexamples.apps;
30 |
31 | import com.github.stephengold.sport.physics.BasePhysicsApp;
32 | import com.jme3.bullet.PhysicsSpace;
33 | import com.jme3.bullet.collision.shapes.CollisionShape;
34 | import com.jme3.bullet.collision.shapes.SphereCollisionShape;
35 | import com.jme3.bullet.objects.PhysicsBody;
36 | import com.jme3.bullet.objects.PhysicsRigidBody;
37 | import com.jme3.math.Vector3f;
38 |
39 | /**
40 | * A simple example combining static and dynamic rigid bodies.
41 | *
42 | * Builds upon HelloRigidBody.
43 | *
44 | * @author Stephen Gold sgold@sonic.net
45 | */
46 | public class HelloStaticBody extends BasePhysicsApp {
47 | // *************************************************************************
48 | // constructors
49 |
50 | /**
51 | * Instantiate the HelloStaticBody application.
52 | *
53 | * This no-arg constructor was made explicit to avoid javadoc warnings from
54 | * JDK 18+.
55 | */
56 | public HelloStaticBody() {
57 | // do nothing
58 | }
59 | // *************************************************************************
60 | // new methods exposed
61 |
62 | /**
63 | * Main entry point for the HelloStaticBody application.
64 | *
65 | * @param arguments array of command-line arguments (not null)
66 | */
67 | public static void main(String[] arguments) {
68 | HelloStaticBody application = new HelloStaticBody();
69 | application.start();
70 | }
71 | // *************************************************************************
72 | // BasePhysicsApp methods
73 |
74 | /**
75 | * Create the PhysicsSpace. Invoked once during initialization.
76 | *
77 | * @return a new object
78 | */
79 | @Override
80 | public PhysicsSpace createSpace() {
81 | PhysicsSpace result
82 | = new PhysicsSpace(PhysicsSpace.BroadphaseType.DBVT);
83 | return result;
84 | }
85 |
86 | /**
87 | * Populate the PhysicsSpace. Invoked once during initialization.
88 | */
89 | @Override
90 | public void populateSpace() {
91 | // Create a CollisionShape for balls.
92 | float ballRadius = 1f;
93 | CollisionShape ballShape = new SphereCollisionShape(ballRadius);
94 |
95 | // Create a dynamic body and add it to the space.
96 | float mass = 2f;
97 | PhysicsRigidBody dynaBall = new PhysicsRigidBody(ballShape, mass);
98 | physicsSpace.addCollisionObject(dynaBall);
99 |
100 | // Create a static body and add it to the space.
101 | PhysicsRigidBody statBall
102 | = new PhysicsRigidBody(ballShape, PhysicsBody.massForStatic);
103 | physicsSpace.addCollisionObject(statBall);
104 |
105 | // Position the balls in physics space.
106 | dynaBall.setPhysicsLocation(new Vector3f(0f, 4f, 0f));
107 | statBall.setPhysicsLocation(new Vector3f(0.1f, 0f, 0f));
108 |
109 | // Visualize the shapes of both rigid bodies:
110 | visualizeShape(dynaBall);
111 | visualizeShape(statBall);
112 | }
113 |
114 | /**
115 | * Advance the physics simulation by the specified amount. Invoked during
116 | * each update.
117 | *
118 | * @param wallClockSeconds the elapsed wall-clock time since the previous
119 | * invocation of {@code updatePhysics} (in seconds, ≥0)
120 | */
121 | @Override
122 | public void updatePhysics(float wallClockSeconds) {
123 | physicsSpace.update(wallClockSeconds);
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/apps/src/main/java/com/github/stephengold/lbjexamples/apps/console/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2022, Stephen Gold and Yanis Boudiaf
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | /**
30 | * Examples of console applications using Libbulletjme. No graphics!
31 | */
32 | package com.github.stephengold.lbjexamples.apps.console;
33 |
--------------------------------------------------------------------------------
/apps/src/main/java/com/github/stephengold/lbjexamples/apps/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2022, Stephen Gold and Yanis Boudiaf
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | /**
30 | * Graphical example applications from the Libbulletjme tutorials.
31 | */
32 | package com.github.stephengold.lbjexamples.apps;
33 |
--------------------------------------------------------------------------------
/apps/src/main/java/com/github/stephengold/lbjexamples/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2022-2024 Stephen Gold and Yanis Boudiaf
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | /**
30 | * LbjExamples test chooser.
31 | */
32 | package com.github.stephengold.lbjexamples;
33 |
--------------------------------------------------------------------------------
/apps/src/main/java/com/github/stephengold/shapes/custom/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2024 Stephen Gold and Yanis Boudiaf
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | /**
30 | * Classes that generate custom collision shapes for testing.
31 | */
32 | package com.github.stephengold.shapes.custom;
33 |
--------------------------------------------------------------------------------
/apps/src/main/resources/Textures/Terrain/splat/mountains512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/apps/src/main/resources/Textures/Terrain/splat/mountains512.png
--------------------------------------------------------------------------------
/apps/src/main/resources/Textures/TextureTest.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/apps/src/main/resources/Textures/TextureTest.png
--------------------------------------------------------------------------------
/apps/src/main/resources/Textures/greenTile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/apps/src/main/resources/Textures/greenTile.png
--------------------------------------------------------------------------------
/bash/meld.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | GitDir=~/NetBeansProjects
6 | #GitDir="/c/Users/sgold/My Documents/NetBeansProjects"
7 |
8 | S1="$GitDir/LbjExamples/apps/src/main/java/com/github/stephengold/lbjexamples/apps"
9 | D1="$GitDir/Minie/TutorialApps/src/main/java/jme3utilities/tutorial"
10 |
11 | S2="$GitDir/LbjExamples/apps/src/main/java/com/github/stephengold/lbjexamples"
12 | D2="$GitDir/sport/apps/src/main/java/com/github/stephengold/sport/demo"
13 |
14 | S3="$GitDir/LbjExamples/docs/en/modules/ROOT"
15 | D3="$GitDir/Minie/MinieLibrary/src/site/antora/tutorials/modules/minie-library-tutorials"
16 |
17 | S4="$GitDir/LbjExamples/docs/en/modules/ROOT"
18 | D4="$GitDir/Minie/src/site/antora/minie-project/modules/ROOT"
19 |
20 | S5="$GitDir/LbjExamples/apps/src/main/java/com/github/stephengold/lbjexamples"
21 | D5="$GitDir/V-Sport/apps/src/main/java/com/github/stephengold/vsport/demo"
22 |
23 | S6="$GitDir/LbjExamples/apps/src/main/java/com/github/stephengold/lbjexamples/apps"
24 | D6="$GitDir/V-Sport/apps/src/main/java/com/github/stephengold/vsport/tutorial"
25 |
26 | S7="$GitDir/LbjExamples/apps/src/main/java"
27 | D7="$GitDir/Minie/MinieExamples/src/main/java"
28 |
29 | Meld="/usr/bin/meld"
30 | #Meld="/c/Program Files/Meld/meld"
31 |
32 | "$Meld" --diff "$S1" "$D1" --diff "$S2" "$D2" --diff "$S3" "$D3" --diff "$S4" "$D4" \
33 | --diff "$S5" "$D5" --diff "$S6" "$D6" --diff "$S7" "$D7"
34 |
--------------------------------------------------------------------------------
/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Gradle script to build the LbjExamples project
2 |
3 | plugins {
4 | base // to add a "clean" task to the root project
5 | }
6 |
7 | configurations.all {
8 | resolutionStrategy.cacheChangingModulesFor(0, "seconds") // to disable caching of snapshots
9 | }
10 |
11 | tasks.register("checkstyle") {
12 | dependsOn(":apps:checkstyleMain")
13 | description = "Checks the style of all Java sourcecode."
14 | }
15 |
16 | // Register cleanup tasks:
17 |
18 | tasks.named("clean") {
19 | dependsOn("cleanDocsBuild", "cleanNodeModules")
20 | }
21 | tasks.register("cleanDocsBuild") {
22 | delete("docs/build")
23 | }
24 | tasks.register("cleanNodeModules") {
25 | delete("node_modules")
26 | }
27 |
--------------------------------------------------------------------------------
/config/checkstyle/java-header:
--------------------------------------------------------------------------------
1 | /*
2 | [Copyright information goes here.]
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 |
--------------------------------------------------------------------------------
/docs/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Gradle script to build the "docs" subproject of LbjExamples
2 |
3 | plugins {
4 | java
5 | }
6 |
7 | sourceSets.main {
8 | java {
9 | srcDir("en") // for IDE access (no Java there)
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/docs/en/antora.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # descriptor of the "lbj-en" Antora component
3 |
4 | name: lbj-en
5 | title: The Libbulletjme project
6 | version: English
7 | start_page: ROOT:overview.adoc
8 | nav:
9 | - modules/ROOT/nav.adoc
10 |
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/images/CustomConvex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/docs/en/modules/ROOT/images/CustomConvex.png
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/images/box.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/docs/en/modules/ROOT/images/box.png
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/images/box2d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/docs/en/modules/ROOT/images/box2d.png
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/images/capsule.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/docs/en/modules/ROOT/images/capsule.png
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/images/compound.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/docs/en/modules/ROOT/images/compound.png
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/images/cone.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/docs/en/modules/ROOT/images/cone.png
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/images/convex2d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/docs/en/modules/ROOT/images/convex2d.png
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/images/conveyorDemo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/docs/en/modules/ROOT/images/conveyorDemo.png
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/images/cylinder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/docs/en/modules/ROOT/images/cylinder.png
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/images/frustum.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/docs/en/modules/ROOT/images/frustum.png
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/images/gimpact.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/docs/en/modules/ROOT/images/gimpact.png
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/images/heightfield.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/docs/en/modules/ROOT/images/heightfield.png
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/images/hull.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/docs/en/modules/ROOT/images/hull.png
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/images/margin1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/docs/en/modules/ROOT/images/margin1.png
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/images/margin4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/docs/en/modules/ROOT/images/margin4.png
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/images/margin5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/docs/en/modules/ROOT/images/margin5.png
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/images/margin6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/docs/en/modules/ROOT/images/margin6.png
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/images/mesh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/docs/en/modules/ROOT/images/mesh.png
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/images/minkowski.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/docs/en/modules/ROOT/images/minkowski.png
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/images/multiSphere.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/docs/en/modules/ROOT/images/multiSphere.png
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/images/newtonsCradle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/docs/en/modules/ROOT/images/newtonsCradle.png
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/images/pachinko.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/docs/en/modules/ROOT/images/pachinko.png
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/images/plane.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/docs/en/modules/ROOT/images/plane.png
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/images/segment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/docs/en/modules/ROOT/images/segment.png
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/images/simplex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/docs/en/modules/ROOT/images/simplex.png
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/images/sphere.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/docs/en/modules/ROOT/images/sphere.png
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/images/splitDemo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/docs/en/modules/ROOT/images/splitDemo.png
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/images/testGearJoint.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/docs/en/modules/ROOT/images/testGearJoint.png
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/images/thousandCubes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/docs/en/modules/ROOT/images/thousandCubes.png
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/images/windlass.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/docs/en/modules/ROOT/images/windlass.png
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/nav.adoc:
--------------------------------------------------------------------------------
1 | * xref:implementation.adoc[Implementation]
2 | * Library tutorials
3 | ** xref:add.adoc[Add to existing project]
4 | ** xref:sport.adoc[SPORT visualization]
5 | ** xref:rigidbody.adoc[Rigid bodies]
6 | ** xref:shape.adoc[Collision shapes]
7 | ** xref:character.adoc[Characters]
8 | ** xref:vehicle.adoc[Vehicles]
9 | ** xref:new6dof.adoc[New6Dof constraints]
10 | ** xref:collision.adoc[Managing collisions]
11 | ** xref:softbody.adoc[Soft bodies]
12 | ** xref:debug.adoc[Troubleshooting]
13 | ** xref:misc.adoc[Miscellany]
14 | * xref:build.adoc[Build procedures]
15 | * xref:demos.adoc[Demo apps]
16 | * xref:lexicon.adoc[Type lexicon]
17 | * https://github.com/stephengold/Libbulletjme[GitHub repository]
18 | ** https://github.com/stephengold/Libbulletjme/releases/latest[Latest release]
19 | ** https://github.com/stephengold/Libbulletjme/releases[Recent releases]
20 | ** https://github.com/stephengold/Libbulletjme/blob/master/README.md[ReadMe file]
21 | ** https://raw.githubusercontent.com/stephengold/Libbulletjme/master/LICENSE[License]
22 | ** https://github.com/stephengold/Libbulletjme/blob/master/release-notes.md[Release log]
23 | ** https://github.com/stephengold/Libbulletjme/commits/master[Recent commits]
24 | ** https://github.com/stephengold/Libbulletjme/issues[Issue tracker]
25 | ** https://github.com/stephengold/Libbulletjme/issues/new[Report an issue]
26 | * Library APIs (javadoc)
27 | ** https://stephengold.github.io/Libbulletjme/javadoc/master["master" branch]
28 | * Libbulletjme at other sites
29 | ** https://repo1.maven.org/maven2/com/github/stephengold/Libbulletjme[Maven Central download]
30 | ** https://central.sonatype.com/search?q=Libbulletjme&namespace=com.github.stephengold[Maven Central search]
31 | ** https://jitpack.io/#stephengold/Libbulletjme[JitPack (unofficial)]
32 | * Projects using Libbulletjme
33 | ** https://stephengold.github.io/Minie[Minie]
34 | ** https://dynamx.fr/[DynamX]
35 | ** https://github.com/stephengold/LbjExamples[LbjExamples]
36 | ** https://github.com/stephengold/macana[Macana]
37 | ** https://github.com/stephengold/sport[SPORT]
38 | ** https://github.com/stephengold/V-Sport[V-Sport]
39 | * Other related projects
40 | ** https://pybullet.org/wordpress[Bullet]
41 | ** https://jmonkeyengine.org[JMonkeyEngine]
42 | ** https://github.com/Simsilica/SimMath[SimMath]
43 | ** https://github.com/kmammou/v-hacd[V-HACD]
44 | ** https://github.com/stephengold/antora-ui-bundle[Website UI bundle]
45 | * People
46 | ** https://stephengold.github.io[Stephen Gold]
47 | ** Yanis Boudiaf
48 |
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/pages/build.adoc:
--------------------------------------------------------------------------------
1 | = How to build Libbulletjme from source
2 | :Project: Libbulletjme
3 |
4 | {Project} is free, open-source software.
5 |
6 | While pre-built library artifacts (including AARs and JARs)
7 | can be downloaded from the Maven Central Repository,
8 | some people prefer to build them from source.
9 |
10 | You can also build a local copy of the documentation website (including HTML).
11 | This is useful if you are editing the documentation,
12 | or if your Internet access is limited or unreliable.
13 |
14 | == Libraries
15 |
16 | Here's the recommended procedure:
17 |
18 | . Install build software:
19 | .. a https://adoptium.net/releases.html[Java Development Kit (JDK)],
20 | version 8 or higher, and
21 | .. one of the supported C++ compilers:
22 | ... for Linux: https://gcc.gnu.org/[the GNU Compiler Collection] or https://www.llvm.org[Clang]
23 | ... for macOS: https://developer.apple.com/xcode[Xcode]
24 | ... for Windows: https://visualstudio.microsoft.com[Microsoft Visual Studio]
25 | .. If you use GCC, you might also need to install the "g++-multilib" package:
26 | ... `sudo apt install g++-multilib`
27 | . Point the `JAVA_HOME` environment variable to your JDK installation:
28 | (The path might look something like "C:\Program Files\Java\jre1.8.0_301"
29 | or "/usr/lib/jvm/java-8-openjdk-amd64/" or
30 | "/Library/Java/JavaVirtualMachines/liberica-jdk-17-full.jdk/Contents/Home" .)
31 | .. using Bash or Zsh: `export JAVA_HOME="` *path to installation* `"`
32 | .. using https://fishshell.com/[Fish]: `set -g JAVA_HOME "` *path to installation* `"`
33 | .. using Windows Command Prompt: `set JAVA_HOME="` *path to installation* `"`
34 | .. using PowerShell: `$env:JAVA_HOME = '` *path to installation* `'`
35 | . Download and extract the {Project} source code from GitHub:
36 | .. using https://git-scm.com[Git]:
37 | ... `git clone https://github.com/stephengold/Libbulletjme.git`
38 | ... `cd Libbulletjme`
39 | ... `git checkout -b latest 22.0.1`
40 | .. using a web browser:
41 | ... browse to https://github.com/stephengold/Libbulletjme/releases/latest
42 | ... follow the "Source code (zip)" link
43 | ... save the ZIP file
44 | ... extract the contents of the saved ZIP file
45 | ... `cd` to the extracted directory
46 | . Cross-compilation using GCC requires the g++-multilib package:
47 | .. `sudo apt-get install g++-multilib`
48 | . (optional) Edit the "gradle.properties" file to configure the build.
49 | . Run the https://gradle.org[Gradle] wrapper on the desktop build script:
50 | .. using Bash or Fish or PowerShell or Zsh: `./gradlew build`
51 | .. using Windows Command Prompt: `.\gradlew build`
52 | . To build Android artifacts, you'll need to
53 | install https://developer.android.com/studio[Android Studio]
54 | and point the `ANDROID_HOME` environment variable to that installation.
55 | . Run the Gradle wrapper on the Android build script:
56 | .. using Bash or Fish or PowerShell or Zsh: `./gradlew -b android.gradle build`
57 | .. using Windows Command Prompt: `.\gradlew -b android.gradle build`
58 |
59 | After a successful build,
60 | artifacts will be found in "build/libs" (desktop) and "build/outputs/aar" (Android).
61 |
62 | === Install artifacts
63 |
64 | You can install the built artifacts to your local Maven repository:
65 |
66 | * using Bash or Fish or PowerShell or Zsh: `./gradlew install;./gradlew -b android.gradle install`
67 | * using Windows Command Prompt:
68 | ** `.\gradlew install`
69 | ** `.\gradlew -b android.gradle install`
70 |
71 | === Cleanup
72 |
73 | After a build, you can restore the project to a pristine state:
74 |
75 | * using Bash or Fish or PowerShell or Zsh: `./gradlew clean;./gradlew -b android.gradle clean`
76 | * using Windows Command Prompt:
77 | ** `.\gradlew clean`
78 | ** `.\gradlew -b android.gradle clean`
79 |
80 | == Website content
81 |
82 | . Download and extract the source code from GitHub:
83 | .. `git clone https://github.com/stephengold/LbjExamples.git`
84 | .. `cd LbjExamples`
85 | . Edit "docs/playbook.yml" and replace "/home/sgold/NetBeansProjects/LbjExamples"
86 | with an absolute path to your checkout directory (2 places).
87 | . https://docs.antora.org/antora/latest/install-and-run-quickstart/#install-nodejs[Install Node.js]
88 | . Run Antora:
89 | .. `npx antora docs/playbook.yml`
90 |
91 | After a successful build,
92 | the local copy of the site will be found in the "docs/build/site" directory.
93 |
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/pages/character.adoc:
--------------------------------------------------------------------------------
1 | = An introduction to character physics
2 | :experimental:
3 | :page-pagination:
4 | :pi: π
5 | :Sport: SPORT
6 | :url-api: https://stephengold.github.io/Libbulletjme/javadoc/master/com/jme3/bullet
7 | :url-kt: https://github.com/stephengold/LbjExamples/blob/master/kotlin-apps/src/main/kotlin/com/github/stephengold/lbjexamples/ktapps
8 | :url-tutorial: https://github.com/stephengold/LbjExamples/blob/master/apps/src/main/java/com/github/stephengold/lbjexamples/apps
9 |
10 | A _physics character_ is a collision object
11 | used to simulate game characters (people) walking, jumping, and falling.
12 |
13 | The standard physics character makes some simplifying assumptions:
14 |
15 | * The character's shape must be convex.
16 | * The character remains upright even when jumping or falling:
17 | no sitting, squatting, ducking, or lying down.
18 | * Limits are placed on:
19 | ** how steep a slope the character can climb,
20 | ** how high a step the character can climb, and
21 | ** how fast the character can fall.
22 |
23 | Like a dynamic rigid body,
24 | a physics character has a collision shape, a location, and
25 | a gravity vector, along with velocities and damping parameters.
26 | It also has an option for contact response, which is enabled by default.
27 |
28 | However, a physics character has no concept of mass,
29 | and its motion is controlled very differently from a dynamic body.
30 | Instead of applying forces or directly updating the character's velocities,
31 | the app should specify when and how the character should walk and jump.
32 |
33 | == Creation
34 |
35 | You can create a character by invoking the
36 | {url-api}/objects/PhysicsCharacter.html[`PhysicsCharacter`] constructor.
37 | This allows you to specify its collision shape and step height.
38 |
39 | {url-tutorial}/HelloCharacter.java[HelloCharacter] (also {url-kt}/HelloCharacter.kt[in Kotlin]) is a SPORT app
40 | that demonstrates the creation of a character,
41 | followed by automated jumps.
42 | Things to notice about the app:
43 |
44 | . The constructor requires a convex shape.
45 | In this app, a capsule is used.
46 | . The `onGround()` method tests whether the character is supported
47 | by a solid surface (as opposed to jumping or falling).
48 | . In {Sport}, characters that are jumping or falling are shown in pink,
49 | while characters that are on ground are shown in brown.
50 |
51 | == Walking
52 |
53 | A character's walking motion is controlled by its _walk direction_ vector.
54 | During each simulation step, the horizontal component of the walk direction
55 | gets added to the character's location.
56 | To stop the character from walking, invoke `setWalkDirection(Vector3f.ZERO)`.
57 |
58 | NOTE: Despite its name, the walk direction need not be a unit vector.
59 |
60 | {url-tutorial}/HelloWalk.java[HelloWalk] (also {url-kt}/HelloWalk.kt[in Kotlin]) demonstrates
61 | keyboard-controlled motion of a physics character.
62 | Things to notice while running the app:
63 |
64 | . Drag with the left mouse button to rotate the camera.
65 | . Press kbd:[Space bar] to jump.
66 | . Press kbd:[W] to walk in the camera's forward direction.
67 | . Some of the mountains have slopes too steep for the character to climb.
68 |
69 |
70 | == Configuration
71 |
72 | === Gravity and up direction
73 |
74 | The _up direction_ of a physics character is a unit vector
75 | that points in the direction opposite its gravity vector.
76 | By default, the up direction is (0,1,0) and
77 | the gravity vector is (0,-29.4,0).
78 |
79 | NOTE: A character's default gravity is 3x stronger
80 | than the default gravity of a {url-api}/PhysicsSpace.html[`PhysicsSpace`].
81 |
82 | NOTE: Unlike the gravity of a rigid body, a character's gravity is never
83 | overridden by any physics space.
84 |
85 | To alter a character's gravity vector,
86 | use `character.setGravity(Vector3f)`.
87 |
88 | Altering the gravity vector automatically updates the character's up direction.
89 | To alter the *magnitude* of a character's gravity
90 | (without changing its direction) use `character.setGravity(float)`.
91 |
92 | To alter a character's up direction, use `character.setUp(Vector3f)`.
93 | Altering the up direction automatically updates the gravity vector.
94 |
95 | === Jump speed
96 |
97 | If a character jumps in its up direction,
98 | its predicted rise time and jump height
99 | are determined by its gravity and jump speed.
100 | Roughly speaking:
101 |
102 | [source,java]
103 | ----
104 | float g = character.getGravity(null).length();
105 | float v0 = character.getJumpSpeed();
106 | float riseSeconds = v0 / g;
107 | float jumpHeight = v0 * v0 / (2f * g);
108 | ----
109 |
110 | The default jump speed is 10 psu per second.
111 | To alter a character's jump speed, use `character.setJumpSpeed(float)`.
112 |
113 | === Fall speed
114 |
115 | _Fall speed_ limits the speed of a falling character.
116 | To be realistic, it should be larger than the character's jump speed.
117 |
118 | The default fall speed is 55 psu per second.
119 | To alter a character's fall speed, use `character.setFallSpeed(float)`.
120 |
121 | === Step height
122 |
123 | _Step height_ limits how high a step the character can climb.
124 | To be realistic, it should be less than the character's height.
125 |
126 | A character's initial step height is set by the constructor.
127 | To alter it, use `character.setStepHeight(float)`.
128 |
129 | === Maximum slope
130 |
131 | _Maximum slope_ limits how steep a slope the character can climb.
132 | It is expressed as an angle in radians relative to the horizontal plane.
133 |
134 | The default maximum slope is {pi}/4, indicating a 45-degree angle.
135 | To alter it, use `character.setMaxSlope(float)`.
136 |
137 | === Contact response
138 |
139 | As with a rigid body, you can disable the contact response of a character using
140 | `character.setContactResponse(false)`.
141 |
142 | Disabling a character's contact response
143 | will compel it to fall, at least until contact response is re-enabled.
144 |
145 | == Summary
146 |
147 | * A physics character simulates a game character walking, jumping, and falling.
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/pages/debug.adoc:
--------------------------------------------------------------------------------
1 | = Troubleshooting physics issues
2 | :Project: Libbulletjme
3 | :page-pagination:
4 |
5 | {Project} uses `assert` statements to verify assumptions made while coding.
6 | During development, Java assertions should be enabled using:
7 |
8 | * the "-ea" JVM argument or
9 | * the `enableAssertions` setting of Gradle `JavaExec` tasks.
10 |
11 | Similarly, native-code assertions should be enabled during development,
12 | by loading a native library of the "debug" type,
13 | such as "com.github.stephengold:Libbulletjme-Linux64:22.0.1:SpDebug".
14 |
15 | == Visualization
16 |
17 | Many physics issues can be diagnosed visually.
18 | For instance, if you neglect to add a collision object to the physics space,
19 | SPORT will automatically omit it from the visualization.
20 |
21 | SPORT can be used to visualize:
22 |
23 | * collision shapes,
24 | * vehicle wheels,
25 | * physics joints,
26 | * soft bodies,
27 | * the centers and local axes of collision objects, and
28 | * the axis-aligned bounding boxes of collision objects.
29 |
30 | === Color conventions
31 |
32 | When visualizing a collision shape,
33 | SPORT uses colors to distinguish different types of collision objects:
34 |
35 | * yellow for an object without contact response,
36 | including any ghost object,
37 | * magenta for a rigid body (or collider) that's dynamic, responsive, and active,
38 | * gray for a rigid body or collider
39 | (with contact response) that's static, kinematic, or inactive,
40 | * brown for a character that's grounded, and
41 | * pink for a character (with contact response) that isn't grounded.
42 |
43 | When visualizing a physics joint, SPORT uses:
44 |
45 | * green for a "A" end and
46 | * red for a "B" end.
47 |
48 | When visualizing a soft body, SPORT uses:
49 |
50 | * red for the faces and
51 | * orange for the links.
52 |
53 | When visualizing coordinate axes, SPORT uses:
54 |
55 | * red for the +X axis,
56 | * green for the +Y axis, and
57 | * blue for the +Z axis.
58 |
59 | When visualizing bounding boxes, SPORT uses:
60 |
61 | * red for a ghost object whose overlapping count has increased,
62 | * green for a ghost whose count has decreased,
63 | * yellow for a ghost whose count is unchanged, and
64 | * white for a non-ghost collision object.
65 |
66 | == An introduction to `PhysicsDumper`
67 |
68 | The following temporary statements could be used to dump
69 | (to `System.out`) all collision objects in a physics space:
70 |
71 | [source,java]
72 | ----
73 | PhysicsDumper dumper = new PhysicsDumper();
74 | dumper.dump(physicsSpace);
75 | ----
76 |
77 | Here is sample output for a space containing 2 rigid bodies and nothing else:
78 |
79 | ....
80 | PhysicsSpace with 0 chars, 0 ghosts, 0 joints, 2 rigids, 0 vehicles
81 | bphase=DBVT grav[y=-9.81] timeStep[0.0166667 maxSS=4] listeners[c=0 t=1]
82 | solver[SI iters=10 cfm=0 batch=128 splitImp[th=global erp=0.1] mode=WarmStart,VelocityDependent,SIMD,Cone]
83 | rayTest=SubSimplex,HeightfieldAccel
84 | Rigid Kin msLoc[x=-0.243501 y=-0.317344]
85 | contact[fric=0.5 rest=0 damp=0.1 pth=1e+18 stiff=1e+18]
86 | Sphere r=1 marg=0
87 | with 0 ignores and 0 joints
88 | Rigid Dyn(mass=2) msLoc[x=3.39744 y=-4.02647] loc[x=3.42799 y=-4.13896] orient[x=0 y=0 z=-0.24 w=0.971]
89 | contact[fric=0.5 rest=0 damp=0.1 pth=1e+18 stiff=1e+18]
90 | grav[y=-9.81] NOTprotected ccd[mth=0] damp[l=0 a=0] sleep[lth=0.8 ath=1 time=0]
91 | v[x=2.96385 y=-10.9131] force[xyz=0] lFact[xyz=1]
92 | inert[xyz=0.8] w[z=-0.714854] torq[xyz=0] aFact[xyz=1]
93 | Sphere r=1 marg=0
94 | with 0 ignores and 0 joints
95 | ....
96 |
97 | 2-space indentation indicates the hierarchy of spaces/objects/joints.
98 | Single-space indentation indicates additional description
99 | of the foregoing object.
100 | Related values are enclosed in square brackets.
101 |
102 | To dump a physics space to a text file:
103 |
104 | [source,java]
105 | ----
106 | PrintStream dumpStream = new PrintStream("dump.txt");
107 | PhysicsDumper dumper = new PhysicsDumper(dumpStream);
108 | dumper.dump(physicsSpace);
109 | ----
110 |
111 | === What is dumped
112 |
113 | You can dump specific collision objects:
114 |
115 | [source,java]
116 | ----
117 | dumper.dump(character);
118 | dumper.dump(multiBodyCollider);
119 | dumper.dump(ghostObject);
120 | dumper.dump(rigidBody);
121 | dumper.dump(softBody);
122 | ----
123 |
124 | You can dump specific collision shapes:
125 |
126 | [source,java]
127 | ----
128 | dumper.dump(collisionShape, "");
129 | ----
130 |
131 | When dumping a space,
132 | the default is to describe every collision object;
133 | physics joints are counted but not described in detail.
134 | To describe the joints in each body, configure the dumper like so:
135 |
136 | [source,java]
137 | ----
138 | dumper.setEnabled(DumpFlags.JointsInBodies, true); // default=false
139 | ----
140 |
141 | To describe the motors in each joint, configure the dumper like so:
142 |
143 | [source,java]
144 | ----
145 | dumper.setEnabled(DumpFlags.Motors, true); // default=false
146 | ----
147 |
148 | To dump just the physics joints (no collision objects):
149 |
150 | [source,java]
151 | ----
152 | dumper.setEnabled(DumpFlags.Pcos, false); // default=true
153 | dumper.setEnabled(DumpFlags.JointsInSpaces, true); // default=false
154 | ----
155 |
156 | Other dump flags can be set to describe the nodes or clusters in each soft body
157 | or the child shapes in each compound collision shape.
158 |
159 | == Summary
160 |
161 | * During development, enable Java assertions and use debug-enabled libraries.
162 | * SPORT visualization can be used to diagnose issues.
163 | * To obtain detailed information about scenes and physics, use a dumper.
164 |
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/pages/demos.adoc:
--------------------------------------------------------------------------------
1 | = An overview of the demo applications
2 | :Project: Libbulletjme
3 | :experimental:
4 | :url-examples: https://github.com/stephengold/sport/tree/master/apps/src/main/java/com/github/stephengold/sport/demo
5 |
6 | _Demo applications_ are provided to showcase certain features of {Project}.
7 | The following demos are found in
8 | {url-examples}[the com.github.stephengold.sport.demo package of the SPORT "apps" sub-project]:
9 |
10 | * {url-examples}/ConveyorDemo.java[`ConveyorDemo`]
11 | demonstrates contact-point modifications +
12 | image:conveyorDemo.png[height=80]
13 | * {url-examples}/NewtonsCradle.java[`NewtonsCradle`]
14 | demonstrates dynamic restitution and point-to-point joints +
15 | image:newtonsCradle.png[height=50]
16 | * {url-examples}/Pachinko.java[`Pachinko`]
17 | demonstrates compound collision shapes and 2-D physics +
18 | image:pachinko.png[height=100]
19 | * {url-examples}/SplitDemo.java[`SplitDemo`]
20 | demonstrates dynamic splitting of rigid bodies +
21 | image:splitDemo.png[height=80]
22 | * {url-examples}/TestGearJoint.java[`TestGearJoint`]
23 | demonstrates a gear joint +
24 | image:testGearJoint.png[height=80]
25 | * {url-examples}/ThousandCubes.java[`ThousandCubes`]
26 | demonstrates stacking cubes and launching projectiles +
27 | image:thousandCubes.png[height=100]
28 | * {url-examples}/Windlass.java[`Windlass`]
29 | demonstrates rope simulation using rigid bodies +
30 | image:windlass.png[height=100]
31 |
32 | == User interface
33 |
34 | The demos are controlled primarily by keyboard input.
35 |
36 | NOTE: The descriptions below assume a keyboard with the "US" (QWERTY) layout.
37 | On keyboards with other layouts, the keys may be labeled differently.
38 |
39 | For convenience, the mapping of keys to actions is partly standardized.
40 | In most demos:
41 |
42 | * kbd:[.] and kbd:[Pause] toggle the simulation between running and paused,
43 | * kbd:[C] dumps the camera's position to the console, and
44 | * kbd:[Esc] ends the application.
45 |
46 | For camera control,
47 | all demos except `ThousandCubes` use `DragLMB` rotation mode.
48 | This means you can rotate the camera
49 | by dragging the mouse with the left button depressed.
50 | Furthermore:
51 |
52 | * kbd:[W] and kbd:[S] dolly the camera forward and back, respectively,
53 | * kbd:[A] and kbd:[D] dolly the camera left and right, respectively,
54 | * kbd:[Q] raises the camera, and
55 | * kbd:[Z] lowers the camera.
56 |
57 | Additional mappings are specific to each application:
58 |
59 | * In `ConveyorDemo`:
60 |
61 | ** kbd:[Enter], kbd:[I], kbd:[Ins], kbd:[Numpad0], and kbd:[Spacebar]
62 | drop a box onto the conveyor belt
63 |
64 | * In `NewtonsCradle`:
65 |
66 | ** kbd:[F1], kbd:[1], and kbd:[Numpad1] restart with a single ball
67 | ** kbd:[F2], kbd:[2], and kbd:[Numpad2] restart with 2 balls
68 | ** kbd:[F3], kbd:[3], and kbd:[Numpad3] restart with 3 balls
69 | ** kbd:[F4], kbd:[4], and kbd:[Numpad4] restart with 4 balls
70 | ** kbd:[F5], kbd:[5], and kbd:[Numpad5] restart with 5 balls
71 |
72 | * In `Pachinko`:
73 |
74 | ** kbd:[F4], kbd:[4], and kbd:[Numpad4] restart with 4 rows of pins
75 | ** kbd:[F5], kbd:[5], and kbd:[Numpad5] restart with 5 rows of pins
76 | ** kbd:[F6], kbd:[6], and kbd:[Numpad6] restart with 6 rows of pins
77 | ** kbd:[F7], kbd:[7], and kbd:[Numpad7] restart with 7 rows of pins
78 | ** kbd:[F8], kbd:[8], and kbd:[Numpad8] restart with 8 rows of pins
79 | ** kbd:[F9], kbd:[9], and kbd:[Numpad9] restart with 9 rows of pins
80 |
81 | * In `SplitDemo`:
82 |
83 | ** kbd:[Tab] convert all bodies to splittable shapes
84 | ** kbd:[Home] and kbd:[Numpad5] restart with a random shape
85 | ** kbd:[Enter], kbd:[Numpad0], and kbd:[Spacebar] split all shapes
86 | ** kbd:[L bracket] and kbd:[R bracket] rotate the splitting plane
87 |
88 | * In `TestGearJoint`:
89 |
90 | ** kbd:[R] and kbd:[Down arrow] apply +Y torque to the drive shaft
91 | ** kbd:[F] and kbd:[Up arrow] apply -Y torque to the drive shaft
92 |
93 | * In `ThousandCubes`:
94 |
95 | ** kbd:[E] launch a red ball
96 |
97 | * In `Windlass`:
98 |
99 | ** kbd:[Down arrow] turn the barrel counter-clockwise
100 | ** kbd:[Up arrow] turn the barrel clockwise
101 |
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/pages/misc.adoc:
--------------------------------------------------------------------------------
1 | = Miscellaneous tutorial material
2 | :page-pagination:
3 | :url-api: https://stephengold.github.io/Libbulletjme/javadoc/master/com/jme3/bullet
4 | :url-examples: https://github.com/stephengold/sport/blob/master/apps/src/main/java/com/github/stephengold/sport/demo
5 |
6 | This page acts as a holding area for tutorial material that's waiting
7 | to be organized.
8 |
9 | == Startup message
10 |
11 | By default, the native library prints a startup message to `System.out`.
12 | Once the library is loaded (but not started) you can disable this message:
13 |
14 | [source,java]
15 | ----
16 | NativeLibrary.setStartupMessageEnabled(false);
17 | ----
18 |
19 | == Library versions and properties
20 |
21 | Once the native library is loaded,
22 | you can test whether it uses double-precision arithmetic:
23 |
24 | [source,java]
25 | ----
26 | boolean doublePrecision = NativeLibrary.isDoublePrecision();
27 | ----
28 |
29 | You can also test whether it was built for debugging
30 | (with assertions enabled, symbols not stripped,
31 | and debug information generated):
32 |
33 | [source,java]
34 | ----
35 | boolean debug = NativeLibrary.isDebug();
36 | ----
37 |
38 | You can also read the native library's version string,
39 | which consists of 3 unsigned decimal numbers separated by dots:
40 |
41 | [source,java]
42 | ----
43 | String nativeVersion = NativeLibrary.versionNumber();
44 | ----
45 |
46 |
47 | == Default collision margin
48 |
49 | The default collision margin for new shapes is 0.04 physics-space units.
50 | To configure a default margin of 0.1 psu:
51 |
52 | [source,java]
53 | ----
54 | CollisionShape.setDefaultMargin(0.1f);
55 | ----
56 |
57 | NOTE: The Bullet Manual advises against changing the default margin.
58 |
59 | == Broadphase types
60 |
61 | By default, a Dynamic Bounding-Volume Tree (DBVT) is used for broadphase
62 | collision detection.
63 | To specify a different data structure, specify the corresponding enum value
64 | in the `PhysicsSpace` constructor:
65 |
66 | [source,java]
67 | ----
68 | PhysicsSoftSpace physicsSpace = new PhysicsSoftSpace(worldMin, worldMax,
69 | PhysicsSpace.BroadphaseType.AXIS_SWEEP_3);
70 | ----
71 |
72 | NOTE: The world max/min bounds are used
73 | only by the `AXIS_SWEEP_3` and `AXIS_SWEEP_3_32` broadphase algorithms.
74 | The `SIMPLE` and `DBVT` algorithms ignore those parameters.
75 |
76 |
77 | == Contact-and-constraint solver
78 |
79 | === Algorithms
80 |
81 | By default, a
82 | http://allenchou.net/2013/12/game-physics-constraints-sequential-impulse[Sequential Impulse (SI) solver]
83 | is used to resolve contacts and constraints.
84 | To specify a different type of solver, specify the corresponding enum value
85 | in the `PhysicsSpace` constructor:
86 |
87 | [source,java]
88 | ----
89 | PhysicsSoftSpace physicsSpace = new PhysicsSpace(worldMin, worldMax,
90 | broadphaseType, SolverType.Dantzig);
91 | ----
92 |
93 | NOTE: For soft-body simulations, SI is the only supported solver type.
94 |
95 | NOTE: The NNCG solver doesn't support multibodies.
96 |
97 | === Tuning parameters
98 |
99 | The contact-and-constraint solver
100 | performs a limited number of iterations per simulation step,
101 | by default, 10.
102 | For higher-quality (but slower) simulation, increase this number.
103 | For instance, to use 20 iterations:
104 |
105 | [source,java]
106 | ----
107 | space.getSolverInfo().setNumIterations(20);
108 | ----
109 |
110 | Other solver parameters can be tuned, including:
111 |
112 | * the global error reduction parameter (ERP) for physics joints,
113 | described on xref:new6dof.adoc#_caveats[the New6Dof page]
114 | * the contact ERP
115 | * the constraint-force mixing parameter (CFM)
116 | * the batch size
117 | * the mode flags,
118 | which enable warm start, constraint ordering, and other features
119 | * the flag to enable the split-impulse feature
120 |
121 |
122 | == Advanced rigid-body friction
123 |
124 | In addition to the basic friction parameter (which affects sliding friction)
125 | each rigid body has 2 additional friction parameters:
126 | one for rolling friction and one for spinning friction.
127 | Both parameters default to zero.
128 |
129 | _Rolling friction_ generates torque orthogonal to the contact normal,
130 | which tends to slow down a rolling body.
131 | _Spinning friction_ generates torque parallel to the contact normal,
132 | which tends to prevent a body from spinning when grasped.
133 |
134 | To simulate objects with grooved surfaces, it's also possible to configure
135 | a rigid body for _anisotropic friction_:
136 | friction that depends on the direction of relative motion.
137 |
138 |
139 | == Gear joint
140 |
141 | {url-api}/joints/GearJoint.html[`GearJoint`] implements
142 | a special type of constraint used to simulate rotating shafts
143 | linked by belts, cables, chains, or gears.
144 | Unlike other constraints, it has no pivot points, only axes.
145 | It's a double-ended constraint
146 | with a single rotational degree-of-freedom.
147 | The rotational rate of the A body around its axis
148 | is matched to that of the B body around its axis, or made proportional.
149 |
150 | To see a gear joint in action, run
151 | {url-examples}/TestGearJoint.java[the TestGearJoint application].
152 |
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/pages/overview.adoc:
--------------------------------------------------------------------------------
1 | = Libbulletjme project overview
2 | :Cplusplus: C++
3 | :Project: Libbulletjme
4 | :url-enwiki: https://en.wikipedia.org/wiki
5 |
6 | _{Project}_ is a {url-enwiki}/Physics_engine[physics-simulation] library
7 | for {url-enwiki}/Java_virtual_machine[Java].
8 |
9 | Use it to:
10 |
11 | * add solidity to walls, characters, projectiles, landscapes, and vehicles,
12 | * detect collisions between complex shapes,
13 | * perform contact, ray, and sweep tests,
14 | * simulate characters and buildings collapsing in real time, and
15 | * simulate cloth, rope, and deformable volumes,
16 | including their interactions with rigid bodies and each other.
17 |
18 | Tutorials and example apps are provided to help you get started.
19 |
20 | All software in the {Project} project is free and open-source,
21 | including the JVM library, the native libraries, the demo and tutorial apps,
22 | and the software used to build, test, and run them.
23 |
24 | The underlying simulation software comes from
25 | https://pybullet.org/wordpress[_Bullet_], a mature real-time physics simulator.
26 | But although Bullet is written in {url-enwiki}/C%2B%2B[C++],
27 | you won't need any knowledge of {Cplusplus} to use {Project}.
28 |
29 | {Project} also incorporates source code from
30 | https://github.com/kmammou/v-hacd[the V-HACD project] and
31 | https://github.com/Simsilica/SimMath[the SimMath library].
32 |
33 |
34 | == Caveats
35 |
36 | {Project}'s focus is on simulating
37 | {url-enwiki}/Classical_mechanics[classical mechanics]
38 | in just enough detail to add verisimilitude to 3-D games.
39 | It's not intended for 2-D {url-enwiki}/Platform_game[platformers],
40 | nor for scientific research.
41 | For 2-D physics, consider using http://www.dyn4j.org/[dyn4j] instead.
42 |
43 | {Project} and its documentation
44 | assume a certain level of proficiency with
45 | {url-enwiki}/Java_(programming_language)[the Java programming language].
46 | The project isn't aimed at non-programmers,
47 | nor developers without prior Java experience.
48 | Similarly, it assumes familiarity with vector math and 3-D computer graphics.
49 |
50 | While an understanding of classical mechanics is assumed,
51 | many of its technical terms are linked (at first use)
52 | to the relevant article in the English Wikipedia.
53 |
54 | https://raw.githubusercontent.com/stephengold/Libbulletjme/master/LICENSE[The project's mixed open-source license]
55 | disclaims liability for defects.
56 | Please don't use this software in safety-critical applications.
57 |
58 | Starting with version 16.1.0,
59 | {Project} is no longer compatible with old versions of the "libc" library
60 | found on systems such as CentOS 7 and Ubuntu 16.04 (Xenial).
61 |
62 |
63 | == What's missing
64 |
65 | Bullet is a large project, and
66 | Libbulletjme doesn't yet provide access to all its features.
67 | In particular:
68 |
69 | * `btRigidBodyConstructionInfo`
70 | * "additional damping" for rigid bodies
71 | * Bullet's debug drawer (but see the https://github.com/stephengold/sport[SPORT]
72 | and https://github.com/stephengold/V-Sport[V-Sport] graphics engines)
73 | * serialization (file loader) for classes other than `btOptimizedBvh`
74 | * certain constraints:
75 | ** `btFixedConstraint`
76 | ** `btUniversalConstraint`
77 | * certain collision shapes:
78 | ** `btCompoundFromGimpactShape`
79 | ** `btConvexPointCloudShape`
80 | ** `btConvexTriangleMeshShape`
81 | ** `btGImpactCompoundShape`
82 | ** `btMultimaterialTriangleMeshShape`
83 | ** `btScaledBvhTriangleMeshShape`
84 | ** `btSdfCollisionShape`
85 | ** `btTriangleShape`
86 | ** `btUniformScalingShape`
87 | * certain world types:
88 | ** `btSimpleDynamicsWorld`
89 | ** `btSoftMultiBodyDynamicsWorld`
90 | * inverse dynamics
91 | * Bullet v3
92 | * Bullet extras, examples, and tests (but see the Java examples in LbjExamples)
93 |
94 | Furthermore, Libbulletjme hasn't yet been ported to the following platforms:
95 |
96 | * the FreeBSD and iOS operating systems
97 | * Windows-on-ARM
98 | * MIPS, POWER, RISC-V, and System Z architectures
99 |
100 | We welcome suggestions concerning the future development of {Project}.
101 |
102 |
103 | == Getting help
104 |
105 | For self-help, utilize
106 | xref:add.adoc[the tutorials],
107 | https://stephengold.github.io/Libbulletjme/javadoc/master[the javadoc], and
108 | https://github.com/stephengold/Libbulletjme[the source code].
109 |
110 | For issues that are best handled privately, contact Stephen by e-mail.
111 | His personal e-mail address appears
112 | on https://stephengold.github.io/[his homepage] and in the source code.
113 |
114 |
115 | == The name
116 |
117 | The project's (somewhat awkward) name
118 | reflects that fact that it was originally created
119 | for the JMonkeyEngine (JME) game engine.
120 |
121 | Despite its history, Libbulletjme is self-contained;
122 | it doesn't depend on JME.
123 | If you're seeking a physics engine that's integrated with JME,
124 | please consider https://stephengold.github.io/Minie[Minie].
125 |
126 |
127 | == Next steps
128 |
129 | If you're curious how {Project} works,
130 | proceed to xref:implementation.adoc[the Implementation page].
131 |
132 | To gain hands-on experience,
133 | proceed to xref:add.adoc[the first tutorial page].
134 |
--------------------------------------------------------------------------------
/docs/en/modules/ROOT/pages/sport.adoc:
--------------------------------------------------------------------------------
1 | = Visualization using the SPORT graphics engine
2 | :experimental:
3 | :page-pagination:
4 | :url-kt: https://github.com/stephengold/LbjExamples/blob/master/kotlin-apps/src/main/kotlin/com/github/stephengold/lbjexamples/ktapps
5 | :url-tutorial: https://github.com/stephengold/LbjExamples/blob/master/apps/src/main/java/com/github/stephengold/lbjexamples/apps
6 |
7 | The `HelloLibbulletjme` app
8 | (introduced on xref:add.adoc[the previous page])
9 | is simple, readable and complete.
10 | However, as a console app, its output is limited to text.
11 |
12 | Text provides scant insight into what the physics simulation is doing.
13 | For most people, pictures are much easier to understand.
14 |
15 | For the purpose of this tutorial series,
16 | we've created a graphics engine named SPORT
17 | (the Simple Physics-ORienTed engine).
18 | SPORT enables us to visualize physics objects
19 | without adding much code to the tutorial apps.
20 | It is open-source, written in Java, and available from
21 | https://github.com/stephengold/sport[GitHub] and
22 | https://central.sonatype.com/artifact/com.github.stephengold/sport[Maven Central].
23 |
24 | == HelloSport
25 |
26 | {url-tutorial}/HelloSport.java[HelloSport] (also {url-kt}/HelloSport.kt[in Kotlin])
27 | is a direct conversion of `HelloLibbulletjme` into a SPORT app.
28 |
29 | Details to note:
30 |
31 | . The app is declared as a subclass of `BasePhysicsApp`,
32 | indicating that it will simulate a plain `PhysicsSpace`.
33 | . The app implements the 3 abstract methods of `BasePhysicsApp`
34 | (`createSpace`, `populateSpace`, and `updateSpace`),
35 | which are all invoked automatically.
36 | . `BasePhysicsApp` automatically loads the Libbulletjme native library.
37 | . `BasePhysicsApp` provides:
38 | .. the `physicsSpace` field to access the space and
39 | .. the `visualizeShape()` method to visualize the shape of a collision object.
40 | . Whereas `HelloLibbulletjme` used `update(intervalSeconds, 0)`
41 | to simulate one step at a time,
42 | `HelloSport` attempts real-time simulation using `update(intervalSeconds)`.
43 |
44 | Running `HelloSport` should open a window on your computer's desktop
45 | and play a brief animation of a sphere falling onto a horizontal surface.
46 |
47 | Pressing kbd:[Esc] should close the window and terminate the app.
48 |
49 | Hereafter, all our tutorial apps will use SPORT.
50 | Additional features of SPORT will be introduced as needed.
51 |
52 | == Summary
53 |
54 | * SPORT is a graphics engine, created specifically for Libbulletjme tutorials.
55 | * SPORT provides a simple toolkit for visualizing 3-D physics.
--------------------------------------------------------------------------------
/docs/playbook.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # configure Antora for a local test using the published UI bundle
3 |
4 | site:
5 | title: The Libbulletjme project (local test using the published bundle)
6 | start_page: lbj-en:ROOT:overview.adoc
7 | url: /home/sgold/NetBeansProjects/LbjExamples/docs/build/site
8 | content:
9 | sources:
10 | - url: /home/sgold/NetBeansProjects/LbjExamples
11 | branches: master
12 | start_path: docs/en
13 | ui:
14 | bundle:
15 | url: https://github.com/stephengold/antora-ui-bundle/releases/download/v-sgold250101a/ui-bundle.zip
16 | snapshot: true
17 | output:
18 | clean: true
19 | dir: docs/build/site
20 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | ## configure Gradle properties for building the LbjExamples project
2 |
3 | #bft = SpDebug
4 | bft = SpRelease
5 |
--------------------------------------------------------------------------------
/gradle/libs.versions.toml:
--------------------------------------------------------------------------------
1 | ## catalog of libraries and plugins used to build the LbjExamples project
2 |
3 | [versions]
4 |
5 | checkstyle = "9.3"
6 | libbulletjme = "22.0.1"
7 | lwjgl = "3.3.6"
8 |
9 | [libraries]
10 |
11 | jsnaploader = "io.github.electrostat-lab:snaploader:1.1.1-stable"
12 |
13 | libbulletjme-linux64 = { module = "com.github.stephengold:Libbulletjme-Linux64", version.ref = "libbulletjme" }
14 | libbulletjme-linuxarm32hf = { module = "com.github.stephengold:Libbulletjme-Linux_ARM32hf", version.ref = "libbulletjme" }
15 | libbulletjme-linuxarm64 = { module = "com.github.stephengold:Libbulletjme-Linux_ARM64", version.ref = "libbulletjme" }
16 | libbulletjme-macosx64 = { module = "com.github.stephengold:Libbulletjme-MacOSX64", version.ref = "libbulletjme" }
17 | libbulletjme-macosxarm64 = { module = "com.github.stephengold:Libbulletjme-MacOSX_ARM64", version.ref = "libbulletjme" }
18 | libbulletjme-windows64 = { module = "com.github.stephengold:Libbulletjme-Windows64", version.ref = "libbulletjme" }
19 |
20 | lwjgl = { module = "org.lwjgl:lwjgl", version.ref = "lwjgl" }
21 | lwjgl-assimp = { module = "org.lwjgl:lwjgl-assimp", version.ref = "lwjgl" }
22 | lwjgl-glfw = { module = "org.lwjgl:lwjgl-glfw", version.ref = "lwjgl" }
23 | lwjgl-opengl = { module = "org.lwjgl:lwjgl-opengl", version.ref = "lwjgl" }
24 |
25 | sport = "com.github.stephengold:sport:0.9.6"
26 |
27 | [bundles]
28 |
29 | [plugins]
30 |
31 | kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version = "2.2.0" }
32 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 | @rem SPDX-License-Identifier: Apache-2.0
17 | @rem
18 |
19 | @if "%DEBUG%"=="" @echo off
20 | @rem ##########################################################################
21 | @rem
22 | @rem Gradle startup script for Windows
23 | @rem
24 | @rem ##########################################################################
25 |
26 | @rem Set local scope for the variables with windows NT shell
27 | if "%OS%"=="Windows_NT" setlocal
28 |
29 | set DIRNAME=%~dp0
30 | if "%DIRNAME%"=="" set DIRNAME=.
31 | @rem This is normally unused
32 | set APP_BASE_NAME=%~n0
33 | set APP_HOME=%DIRNAME%
34 |
35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
37 |
38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
40 |
41 | @rem Find java.exe
42 | if defined JAVA_HOME goto findJavaFromJavaHome
43 |
44 | set JAVA_EXE=java.exe
45 | %JAVA_EXE% -version >NUL 2>&1
46 | if %ERRORLEVEL% equ 0 goto execute
47 |
48 | echo. 1>&2
49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
50 | echo. 1>&2
51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
52 | echo location of your Java installation. 1>&2
53 |
54 | goto fail
55 |
56 | :findJavaFromJavaHome
57 | set JAVA_HOME=%JAVA_HOME:"=%
58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
59 |
60 | if exist "%JAVA_EXE%" goto execute
61 |
62 | echo. 1>&2
63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
64 | echo. 1>&2
65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
66 | echo location of your Java installation. 1>&2
67 |
68 | goto fail
69 |
70 | :execute
71 | @rem Setup the command line
72 |
73 | set CLASSPATH=
74 |
75 |
76 | @rem Execute Gradle
77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
78 |
79 | :end
80 | @rem End local scope for the variables with windows NT shell
81 | if %ERRORLEVEL% equ 0 goto mainEnd
82 |
83 | :fail
84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
85 | rem the _cmd.exe /c_ return code!
86 | set EXIT_CODE=%ERRORLEVEL%
87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
89 | exit /b %EXIT_CODE%
90 |
91 | :mainEnd
92 | if "%OS%"=="Windows_NT" endlocal
93 |
94 | :omega
95 |
--------------------------------------------------------------------------------
/kotlin-apps/src/main/kotlin/com/github/stephengold/lbjexamples/ktapps/HelloCcd.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2024-2025 Stephen Gold and Yanis Boudiaf
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package com.github.stephengold.lbjexamples.ktapps
30 |
31 | import com.github.stephengold.sport.physics.BasePhysicsApp
32 | import com.jme3.bullet.PhysicsSpace
33 | import com.jme3.bullet.collision.shapes.CylinderCollisionShape
34 | import com.jme3.bullet.collision.shapes.SphereCollisionShape
35 | import com.jme3.bullet.objects.PhysicsBody
36 | import com.jme3.bullet.objects.PhysicsRigidBody
37 | import com.jme3.math.Vector3f
38 |
39 | /*
40 | * A simple example of continuous collision detection (CCD).
41 | *
42 | * Builds upon HelloStaticBody.
43 | *
44 | * author: Stephen Gold sgold@sonic.net
45 | */
46 |
47 | /*
48 | * Main entry point for the HelloCcd application.
49 | */
50 | fun main() {
51 | val application = HelloCcd()
52 | application.start()
53 | }
54 |
55 | class HelloCcd : BasePhysicsApp() {
56 | /*
57 | * Create the PhysicsSpace. Invoked once during initialization.
58 | */
59 | override fun createSpace(): PhysicsSpace {
60 | val result = PhysicsSpace(PhysicsSpace.BroadphaseType.DBVT)
61 |
62 | // Increase gravity to make the balls fall faster.
63 | result.setGravity(Vector3f(0f, -100f, 0f))
64 |
65 | return result
66 | }
67 |
68 | /*
69 | * Populate the PhysicsSpace. Invoked once during initialization.
70 | */
71 | override fun populateSpace() {
72 | // Create a CollisionShape for balls.
73 | val ballRadius = 0.1f
74 | val ballShape = SphereCollisionShape(ballRadius)
75 |
76 | // Create 2 dynamic balls, one with CCD and one without,
77 | // and add them to the space.
78 | val mass = 1f
79 | val ccdBall = PhysicsRigidBody(ballShape, mass)
80 | physicsSpace.addCollisionObject(ccdBall)
81 | ccdBall.setCcdMotionThreshold(ballRadius)
82 | ccdBall.setCcdSweptSphereRadius(ballRadius)
83 | ccdBall.setPhysicsLocation(Vector3f(-1f, 4f, 0f))
84 |
85 | val controlBall = PhysicsRigidBody(ballShape, mass)
86 | physicsSpace.addCollisionObject(controlBall)
87 | controlBall.setPhysicsLocation(Vector3f(1f, 4f, 0f))
88 |
89 | // Create a thin, static disc and add it to the space.
90 | val discRadius = 2f
91 | val discThickness = 0.05f
92 | val discShape = CylinderCollisionShape(
93 | discRadius, discThickness, PhysicsSpace.AXIS_Y)
94 | val disc = PhysicsRigidBody(discShape, PhysicsBody.massForStatic)
95 | physicsSpace.addCollisionObject(disc)
96 |
97 | // Visualize the shapes of all 3 rigid bodies:
98 | visualizeShape(ccdBall)
99 | visualizeShape(controlBall)
100 | visualizeShape(disc).setProgram("Unshaded/Monochrome")
101 | }
102 |
103 | /*
104 | * Advance the physics simulation by the specified amount. Invoked during
105 | * each update.
106 | *
107 | * wallClockSeconds: the elapsed wall-clock time since the previous
108 | * invocation of updatePhysics() (in seconds, >=0)
109 | */
110 | override fun updatePhysics(wallClockSeconds: Float) {
111 | // For clarity, simulate at 1/10th normal speed.
112 | val simulateSeconds = 0.1f * wallClockSeconds
113 | physicsSpace.update(simulateSeconds)
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/kotlin-apps/src/main/kotlin/com/github/stephengold/lbjexamples/ktapps/HelloCloth.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2024 Stephen Gold and Yanis Boudiaf
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package com.github.stephengold.lbjexamples.ktapps
30 |
31 | import com.github.stephengold.sport.Mesh
32 | import com.github.stephengold.sport.mesh.ClothGrid
33 | import com.github.stephengold.sport.physics.BasePhysicsApp
34 | import com.github.stephengold.sport.physics.LinksGeometry
35 | import com.jme3.bullet.PhysicsSoftSpace
36 | import com.jme3.bullet.PhysicsSpace
37 | import com.jme3.bullet.collision.shapes.SphereCollisionShape
38 | import com.jme3.bullet.objects.PhysicsBody
39 | import com.jme3.bullet.objects.PhysicsRigidBody
40 | import com.jme3.bullet.objects.PhysicsSoftBody
41 | import com.jme3.bullet.objects.infos.SoftBodyConfig
42 | import com.jme3.bullet.objects.infos.SoftBodyMaterial
43 | import com.jme3.bullet.util.NativeSoftBodyUtil
44 | import com.jme3.math.Vector3f
45 |
46 | /*
47 | * A simple cloth simulation using a soft body.
48 | *
49 | * Builds upon HelloSoftBody.
50 | *
51 | * author: Stephen Gold sgold@sonic.net
52 | */
53 |
54 | /*
55 | * Main entry point for the HelloCloth application.
56 | */
57 | fun main() {
58 | val application = HelloCloth()
59 | application.start()
60 | }
61 |
62 | class HelloCloth : BasePhysicsApp() {
63 | /*
64 | * Create the PhysicsSpace. Invoked once during initialization.
65 | */
66 | override fun createSpace(): PhysicsSoftSpace {
67 | val worldMin = Vector3f(-999f, -999f, -999f)
68 | val worldMax = Vector3f(+999f, +999f, +999f)
69 | val result = PhysicsSoftSpace(
70 | worldMin, worldMax, PhysicsSpace.BroadphaseType.DBVT)
71 |
72 | return result
73 | }
74 |
75 | /*
76 | * Initialize the application. Invoked once.
77 | */
78 | override fun initialize() {
79 | super.initialize()
80 |
81 | // Relocate the camera.
82 | cam.setLocation(Vector3f(0f, 1f, 8f))
83 | }
84 |
85 | /*
86 | * Populate the PhysicsSpace. Invoked once during initialization.
87 | */
88 | override fun populateSpace() {
89 | // Create a static, rigid sphere and add it to the physics space.
90 | val radius = 1f
91 | val shape = SphereCollisionShape(radius)
92 | val sphere = PhysicsRigidBody(shape, PhysicsBody.massForStatic)
93 | physicsSpace.addCollisionObject(sphere)
94 | visualizeShape(sphere)
95 |
96 | // Generate a subdivided square mesh with alternating diagonals.
97 | val numLines = 41
98 | val lineSpacing = 0.1f // mesh units
99 | val squareGrid = ClothGrid(numLines, numLines, lineSpacing)
100 |
101 | // Create a soft square and add it to the physics space.
102 | val cloth = PhysicsSoftBody()
103 | NativeSoftBodyUtil.appendFromTriMesh(squareGrid, cloth)
104 | physicsSpace.addCollisionObject(cloth)
105 | /*
106 | * Make the cloth flexible by reducing the angular stiffness
107 | * of its material.
108 | */
109 | val mat = cloth.getSoftMaterial()
110 | mat.setAngularStiffness(0f) // default=1
111 | /*
112 | * Improve simulation accuracy by increasing
113 | * the number of position-solver iterations for the cloth.
114 | */
115 | val config = cloth.getSoftConfig()
116 | config.setPositionIterations(9) // default=1
117 |
118 | // Translate the cloth upward to its starting location.
119 | cloth.applyTranslation(Vector3f(0f, 2f, 0f))
120 |
121 | // Visualize the soft-body links:
122 | LinksGeometry(cloth)
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/kotlin-apps/src/main/kotlin/com/github/stephengold/lbjexamples/ktapps/HelloContactResponse.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2024-2025 Stephen Gold and Yanis Boudiaf
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package com.github.stephengold.lbjexamples.ktapps
30 |
31 | import com.github.stephengold.sport.input.InputProcessor
32 | import com.github.stephengold.sport.physics.BasePhysicsApp
33 | import com.jme3.bullet.PhysicsSpace
34 | import com.jme3.bullet.collision.shapes.BoxCollisionShape
35 | import com.jme3.bullet.collision.shapes.SphereCollisionShape
36 | import com.jme3.bullet.objects.PhysicsBody
37 | import com.jme3.bullet.objects.PhysicsRigidBody
38 | import com.jme3.math.Vector3f
39 | import org.lwjgl.glfw.GLFW
40 |
41 | /*
42 | * A simple demonstration of contact response.
43 | *
44 | * Press the E key to disable the ball's contact response. Once this happens,
45 | * the gray (static) box no longer exerts any contact force on the ball. Gravity
46 | * takes over, and the ball falls through.
47 | *
48 | * Builds upon HelloStaticBody.
49 | *
50 | * author: Stephen Gold sgold@sonic.net
51 | */
52 |
53 | /*
54 | * Main entry point for the HelloContactResponse application.
55 | */
56 | fun main() {
57 | val application = HelloContactResponse()
58 | application.start()
59 | }
60 |
61 | /*
62 | * collision object for the dynamic ball
63 | */
64 | private var ball : PhysicsRigidBody? = null
65 |
66 | class HelloContactResponse : BasePhysicsApp() {
67 | // *************************************************************************
68 | // BasePhysicsApp override functions
69 |
70 | /*
71 | * Create the PhysicsSpace. Invoked once during initialization.
72 | */
73 | override fun createSpace(): PhysicsSpace {
74 | val result = PhysicsSpace(PhysicsSpace.BroadphaseType.DBVT)
75 | return result
76 | }
77 |
78 | /*
79 | * Initialize the application. Invoked once.
80 | */
81 | override fun initialize() {
82 | super.initialize()
83 | configureInput()
84 | }
85 |
86 | /*
87 | * Populate the PhysicsSpace. Invoked once during initialization.
88 | */
89 | override fun populateSpace() {
90 | // Add a static box to the space, to serve as a horizontal platform.
91 | val boxHalfExtent = 3f
92 | val boxShape = BoxCollisionShape(boxHalfExtent)
93 | val box = PhysicsRigidBody(boxShape, PhysicsBody.massForStatic)
94 | physicsSpace.addCollisionObject(box)
95 | box.setPhysicsLocation(Vector3f(0f, -4f, 0f))
96 |
97 | // Add a dynamic ball to the space.
98 | val ballRadius = 1f
99 | val ballShape = SphereCollisionShape(ballRadius)
100 | val ballMass = 2f
101 | ball = PhysicsRigidBody(ballShape, ballMass)
102 | physicsSpace.addCollisionObject(ball)
103 | assert(ball!!.isContactResponse())
104 |
105 | // Position the ball directly above the box.
106 | ball!!.setPhysicsLocation(Vector3f(0f, 4f, 0f))
107 |
108 | // Visualize the shapes of both rigid bodies:
109 | visualizeShape(ball)
110 | visualizeShape(box)
111 | }
112 |
113 | /*
114 | * Advance the physics simulation by the specified amount. Invoked during
115 | * each update.
116 | *
117 | * wallClockSeconds: the elapsed wall-clock time since the previous
118 | * invocation of updatePhysics() (in seconds, >=0)
119 | */
120 | override fun updatePhysics(wallClockSeconds: Float) {
121 | physicsSpace.update(wallClockSeconds)
122 | }
123 | // *************************************************************************
124 | // private functions
125 |
126 | /*
127 | * Configure keyboard input during startup.
128 | */
129 | private fun configureInput() {
130 | getInputManager().add(object : InputProcessor() {
131 | override fun onKeyboard(glfwKeyId: Int, isPressed: Boolean) {
132 | if (glfwKeyId == GLFW.GLFW_KEY_E) {
133 | if (isPressed) {
134 | // Disable the ball's contact response.
135 | ball!!.setContactResponse(false)
136 |
137 | // Activate the ball in case it got deactivated.
138 | ball!!.activate()
139 | }
140 | return
141 | }
142 | super.onKeyboard(glfwKeyId, isPressed)
143 | }
144 | })
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/kotlin-apps/src/main/kotlin/com/github/stephengold/lbjexamples/ktapps/HelloDamping.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2024-2025 Stephen Gold and Yanis Boudiaf
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package com.github.stephengold.lbjexamples.ktapps
30 |
31 | import com.github.stephengold.sport.physics.BasePhysicsApp
32 | import com.jme3.bullet.PhysicsSpace
33 | import com.jme3.bullet.collision.shapes.BoxCollisionShape
34 | import com.jme3.bullet.objects.PhysicsRigidBody
35 | import com.jme3.math.Vector3f
36 |
37 | /*
38 | * A simple example illustrating the effect of damping on dynamic rigid bodies.
39 | *
40 | * Builds upon HelloRigidBody.
41 | *
42 | * author: Stephen Gold sgold@sonic.net
43 | */
44 |
45 | /*
46 | * Main entry point for the HelloDamping application.
47 | */
48 | fun main() {
49 | val application = HelloDamping()
50 | application.start()
51 | }
52 |
53 | class HelloDamping : BasePhysicsApp() {
54 | /*
55 | * Create the PhysicsSpace. Invoked once during initialization.
56 | */
57 | override fun createSpace(): PhysicsSpace {
58 | val result = PhysicsSpace(PhysicsSpace.BroadphaseType.DBVT)
59 |
60 | // For clarity, disable gravity.
61 | result.setGravity(Vector3f.ZERO)
62 |
63 | return result
64 | }
65 |
66 | /*
67 | * Populate the PhysicsSpace. Invoked once during initialization.
68 | */
69 | override fun populateSpace() {
70 | // Create a CollisionShape for unit cubes.
71 | val cubeHalfExtent = 0.5f
72 | val cubeShape = BoxCollisionShape(cubeHalfExtent)
73 |
74 | // Create 4 cubes (dynamic rigid bodies) and add them to the space.
75 | val numCubes = 4
76 | val cubeMass = 2f
77 | val cube = mutableListOf()
78 | for (cubeIndex in 0 ..< numCubes) {
79 | val c = PhysicsRigidBody(cubeShape, cubeMass)
80 | cube.add(c)
81 | physicsSpace.addCollisionObject(c)
82 |
83 | // Disable sleep (deactivation) for clarity.
84 | c.setEnableSleep(false)
85 | }
86 |
87 | // Locate the cubes 4 psu apart, center to center.
88 | cube[0].setPhysicsLocation(Vector3f(0f, +2f, 0f))
89 | cube[1].setPhysicsLocation(Vector3f(4f, +2f, 0f))
90 | cube[2].setPhysicsLocation(Vector3f(0f, -2f, 0f))
91 | cube[3].setPhysicsLocation(Vector3f(4f, -2f, 0f))
92 |
93 | // Give each cube its own set of damping parameters (linear, angular).
94 | cube[0].setDamping(0f, 0f)
95 | cube[1].setDamping(0f, 0.9f)
96 | cube[2].setDamping(0.9f, 0f)
97 | cube[3].setDamping(0.9f, 0.9f)
98 | /*
99 | * Apply an off-center impulse to each cube,
100 | * causing it to drift and spin.
101 | */
102 | val impulse = Vector3f(-1f, 0f, 0f)
103 | val offset = Vector3f(0f, 1f, 1f)
104 | for (c in cube) {
105 | c.applyImpulse(impulse, offset)
106 | }
107 |
108 | // Visualize the shapes of all 4 rigid bodies.
109 | for (c in cube) {
110 | visualizeShape(c)
111 | }
112 | }
113 |
114 | /*
115 | * Advance the physics simulation by the specified amount. Invoked during
116 | * each update.
117 | *
118 | * wallClockSeconds: the elapsed wall-clock time since the previous
119 | * invocation of updatePhysics() (in seconds, >=0)
120 | */
121 | override fun updatePhysics(wallClockSeconds: Float) {
122 | physicsSpace.update(wallClockSeconds)
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/kotlin-apps/src/main/kotlin/com/github/stephengold/lbjexamples/ktapps/HelloDeactivation.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2024-2025 Stephen Gold and Yanis Boudiaf
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package com.github.stephengold.lbjexamples.ktapps
30 |
31 | import com.github.stephengold.sport.physics.BasePhysicsApp
32 | import com.jme3.bullet.PhysicsSpace
33 | import com.jme3.bullet.PhysicsTickListener
34 | import com.jme3.bullet.collision.shapes.BoxCollisionShape
35 | import com.jme3.bullet.collision.shapes.SphereCollisionShape
36 | import com.jme3.bullet.objects.PhysicsBody
37 | import com.jme3.bullet.objects.PhysicsRigidBody
38 | import com.jme3.math.Vector3f
39 |
40 | /*
41 | * A simple example of rigid-body deactivation.
42 | *
43 | * Builds upon HelloStaticBody.
44 | *
45 | * author: Stephen Gold sgold@sonic.net
46 | */
47 |
48 | private var dynamicCube: PhysicsRigidBody? = null
49 | private var supportCube: PhysicsRigidBody? = null
50 |
51 | /*
52 | * Main entry point for the HelloDeactivation application.
53 | */
54 | fun main() {
55 | val application = HelloDeactivation()
56 | application.start()
57 | }
58 |
59 | class HelloDeactivation : BasePhysicsApp(), PhysicsTickListener {
60 | // *************************************************************************
61 | // BasePhysicsApp override functions
62 |
63 | /*
64 | * Create the PhysicsSpace. Invoked once during initialization.
65 | */
66 | override fun createSpace(): PhysicsSpace {
67 | val result = PhysicsSpace(PhysicsSpace.BroadphaseType.DBVT)
68 |
69 | // To enable the callbacks, register the application as a tick listener.
70 | result.addTickListener(this)
71 |
72 | return result
73 | }
74 |
75 | /*
76 | * Populate the PhysicsSpace. Invoked once during initialization.
77 | */
78 | override fun populateSpace() {
79 | // Create a dynamic cube and add it to the space.
80 | val boxHalfExtent = 0.5f
81 | val smallCubeShape = BoxCollisionShape(boxHalfExtent)
82 | val boxMass = 1f
83 | dynamicCube = PhysicsRigidBody(smallCubeShape, boxMass)
84 | physicsSpace.addCollisionObject(dynamicCube)
85 | dynamicCube!!.setPhysicsLocation(Vector3f(0f, 4f, 0f))
86 |
87 | // Create 2 static bodies and add them to the space...
88 | // The top body serves as a temporary support.
89 | val cubeHalfExtent = 1f
90 | val largeCubeShape = BoxCollisionShape(cubeHalfExtent)
91 | supportCube = PhysicsRigidBody(
92 | largeCubeShape, PhysicsBody.massForStatic)
93 | physicsSpace.addCollisionObject(supportCube)
94 |
95 | // The bottom body serves as a visual reference point.
96 | val ballRadius = 0.5f
97 | val ballShape = SphereCollisionShape(ballRadius)
98 | val bottomBody = PhysicsRigidBody(ballShape, PhysicsBody.massForStatic)
99 | bottomBody.setPhysicsLocation(Vector3f(0f, -2f, 0f))
100 | physicsSpace.addCollisionObject(bottomBody)
101 |
102 | // Visualize the shapes of all 3 rigid bodies:
103 | visualizeShape(dynamicCube)
104 | visualizeShape(supportCube)
105 | visualizeShape(bottomBody)
106 | }
107 |
108 | /*
109 | * Advance the physics simulation by the specified amount. Invoked during
110 | * each update.
111 | *
112 | * wallClockSeconds: the elapsed wall-clock time since the previous
113 | * invocation of updatePhysics() (in seconds, >=0)
114 | */
115 | override fun updatePhysics(wallClockSeconds: Float) {
116 | physicsSpace.update(wallClockSeconds)
117 | }
118 | // *************************************************************************
119 | // PhysicsTickListener override functions
120 |
121 | /*
122 | * Callback from Bullet, invoked just before each simulation step.
123 | *
124 | * space: the space that's about to be stepped (not null)
125 | * timeStep: the duration of the simulation step (in seconds, >=0)
126 | */
127 | override fun prePhysicsTick(space: PhysicsSpace, timeStep: Float) {
128 | // do nothing
129 | }
130 |
131 | /*
132 | * Callback from Bullet, invoked just after each simulation step.
133 | *
134 | * space: the space that was just stepped (not null)
135 | * timeStep: the duration of the simulation step (in seconds, >=0)
136 | */
137 | override fun physicsTick(space: PhysicsSpace, timeStep: Float) {
138 | /*
139 | * Once the dynamic cube gets deactivated,
140 | * remove the support cube from the PhysicsSpace.
141 | */
142 | if (!dynamicCube!!.isActive() && space.contains(supportCube)) {
143 | space.removeCollisionObject(supportCube)
144 | }
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/kotlin-apps/src/main/kotlin/com/github/stephengold/lbjexamples/ktapps/HelloKinematics.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2024-2025 Stephen Gold and Yanis Boudiaf
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package com.github.stephengold.lbjexamples.ktapps
30 |
31 | import com.github.stephengold.sport.physics.BasePhysicsApp
32 | import com.jme3.bullet.PhysicsSpace
33 | import com.jme3.bullet.PhysicsTickListener
34 | import com.jme3.bullet.collision.shapes.SphereCollisionShape
35 | import com.jme3.bullet.objects.PhysicsRigidBody
36 | import com.jme3.math.FastMath
37 | import com.jme3.math.Vector3f
38 |
39 | /*
40 | * A simple example combining kinematic and dynamic rigid bodies.
41 | *
42 | * Builds upon HelloStaticBody.
43 | *
44 | * author: Stephen Gold sgold@sonic.net
45 | */
46 |
47 | /*
48 | * Main entry point for the HelloKinematics application.
49 | */
50 | fun main() {
51 | val application = HelloKinematics()
52 | application.start()
53 | }
54 |
55 | /*
56 | * physics-simulation time (in seconds, >=0)
57 | */
58 | private var elapsedTime = 0f
59 | /*
60 | * kinematic ball, orbiting the origin
61 | */
62 | private var kineBall: PhysicsRigidBody? = null
63 |
64 | class HelloKinematics : BasePhysicsApp(), PhysicsTickListener {
65 | // *************************************************************************
66 | // BasePhysicsApp override functions
67 |
68 | /*
69 | * Create the PhysicsSpace. Invoked once during initialization.
70 | */
71 | override fun createSpace(): PhysicsSpace {
72 | val result = PhysicsSpace(PhysicsSpace.BroadphaseType.DBVT)
73 |
74 | // To enable the callbacks, register the application as a tick listener.
75 | result.addTickListener(this)
76 |
77 | return result
78 | }
79 |
80 | /*
81 | * Populate the PhysicsSpace. Invoked once during initialization.
82 | */
83 | override fun populateSpace() {
84 | // Create a CollisionShape for balls.
85 | val ballRadius = 1f
86 | val ballShape = SphereCollisionShape(ballRadius)
87 |
88 | // Create a dynamic body and add it to the space.
89 | val mass = 2f
90 | val dynaBall = PhysicsRigidBody(ballShape, mass)
91 | physicsSpace.addCollisionObject(dynaBall)
92 | dynaBall.setPhysicsLocation(Vector3f(0f, 4f, 0f))
93 |
94 | // Create a kinematic body and add it to the space.
95 | kineBall = PhysicsRigidBody(ballShape)
96 | physicsSpace.addCollisionObject(kineBall)
97 | kineBall!!.setKinematic(true)
98 |
99 | // Visualize the shapes of both rigid bodies:
100 | visualizeShape(dynaBall)
101 | visualizeShape(kineBall)
102 | }
103 |
104 | /*
105 | * Advance the physics simulation by the specified amount. Invoked during
106 | * each update.
107 | *
108 | * wallClockSeconds: the elapsed wall-clock time since the previous
109 | * invocation of updatePhysics() (in seconds, >=0)
110 | */
111 | override fun updatePhysics(wallClockSeconds: Float) {
112 | physicsSpace.update(wallClockSeconds)
113 | }
114 | // *************************************************************************
115 | // PhysicsTickListener override functions
116 |
117 | /*
118 | * Callback from Bullet, invoked just before each simulation step.
119 | *
120 | * space: the space that's about to be stepped (not null)
121 | * timeStep: the duration of the simulation step (in seconds, >=0)
122 | */
123 | override fun prePhysicsTick(space: PhysicsSpace, timeStep: Float) {
124 | // Make the kinematic ball orbit the origin.
125 | val orbitalPeriod = 0.8f // seconds
126 | val phaseAngle = elapsedTime * FastMath.TWO_PI / orbitalPeriod
127 |
128 | val orbitRadius = 0.4f // physics-space units
129 | val x = orbitRadius * FastMath.sin(phaseAngle)
130 | val y = orbitRadius * FastMath.cos(phaseAngle)
131 | val location = Vector3f(x, y, 0f)
132 | kineBall!!.setPhysicsLocation(location)
133 |
134 | elapsedTime += timeStep
135 | }
136 |
137 | /*
138 | * Callback from Bullet, invoked just after each simulation step.
139 | *
140 | * space: the space that was just stepped (not null)
141 | * timeStep: the duration of the simulation step (in seconds, >=0)
142 | */
143 | override fun physicsTick(space: PhysicsSpace, timeStep: Float) {
144 | // do nothing
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/kotlin-apps/src/main/kotlin/com/github/stephengold/lbjexamples/ktapps/HelloMadMallet.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2024-2025 Stephen Gold and Yanis Boudiaf
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package com.github.stephengold.lbjexamples.ktapps
30 |
31 | import com.github.stephengold.sport.input.RotateMode
32 | import com.github.stephengold.sport.physics.BasePhysicsApp
33 | import com.jme3.bullet.PhysicsSpace
34 | import com.jme3.bullet.collision.shapes.CompoundCollisionShape
35 | import com.jme3.bullet.collision.shapes.CylinderCollisionShape
36 | import com.jme3.bullet.objects.PhysicsBody
37 | import com.jme3.bullet.objects.PhysicsRigidBody
38 | import com.jme3.math.Vector3f
39 |
40 | /*
41 | * A simple example of a dynamic rigid body with an implausible center.
42 | *
43 | * Builds upon HelloStaticBody.
44 | *
45 | * author: Stephen Gold sgold@sonic.net
46 | */
47 |
48 | /*
49 | * Main entry point for the HelloMadMallet application.
50 | */
51 | fun main() {
52 | val application = HelloMadMallet()
53 | application.start()
54 | }
55 |
56 | class HelloMadMallet : BasePhysicsApp() {
57 | /*
58 | * Create the PhysicsSpace. Invoked once during initialization.
59 | */
60 | override fun createSpace(): PhysicsSpace {
61 | val result = PhysicsSpace(PhysicsSpace.BroadphaseType.DBVT)
62 | result.setGravity(Vector3f(0f, -50f, 0f))
63 |
64 | return result
65 | }
66 |
67 | /*
68 | * Initialize the application. Invoked once.
69 | */
70 | override fun initialize() {
71 | super.initialize()
72 | getCameraInputProcessor().setRotationMode(RotateMode.DragLMB)
73 |
74 | // Position the camera for a good view.
75 | cam.setLocation(Vector3f(10f, -2.75f, 0f))
76 | cam.setUpAngle(0.05f)
77 | cam.setAzimuth(-3.05f)
78 | }
79 |
80 | /*
81 | * Populate the PhysicsSpace. Invoked once during initialization.
82 | */
83 | override fun populateSpace() {
84 | // Construct a compound shape for the mallet.
85 | val headLength = 1f
86 | val headRadius = 0.5f
87 | val hes = Vector3f(headLength / 2f, headRadius, headRadius)
88 | val headShape = CylinderCollisionShape(hes, PhysicsSpace.AXIS_X)
89 |
90 | val handleLength = 3f
91 | val handleRadius = 0.3f
92 | hes.set(handleRadius, handleRadius, handleLength / 2f)
93 | val handleShape = CylinderCollisionShape(hes, PhysicsSpace.AXIS_Z)
94 |
95 | val malletShape = CompoundCollisionShape()
96 | malletShape.addChildShape(handleShape, 0f, 0f, handleLength / 2f)
97 | malletShape.addChildShape(headShape, 0f, 0f, handleLength)
98 |
99 | // Create a dynamic body for the mallet.
100 | val mass = 2f
101 | val mallet = PhysicsRigidBody(malletShape, mass)
102 | mallet.setPhysicsLocation(Vector3f(0f, 4f, 0f))
103 |
104 | // Increase the mallet's angular damping to stabilize it.
105 | mallet.setAngularDamping(0.9f)
106 |
107 | physicsSpace.addCollisionObject(mallet)
108 |
109 | // Create a static disc and add it to the space.
110 | val discRadius = 5f
111 | val discThickness = 0.5f
112 | val discShape = CylinderCollisionShape(
113 | discRadius, discThickness, PhysicsSpace.AXIS_Y)
114 | val disc = PhysicsRigidBody(discShape, PhysicsBody.massForStatic)
115 | physicsSpace.addCollisionObject(disc)
116 | disc.setPhysicsLocation(Vector3f(0f, -3f, 0f))
117 |
118 | // Visualize the mallet, including its local axes:
119 | visualizeShape(mallet)
120 | val debugAxisLength = 1f
121 | visualizeAxes(mallet, debugAxisLength)
122 |
123 | // Visualize the shape of the disc:
124 | visualizeShape(disc)
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/kotlin-apps/src/main/kotlin/com/github/stephengold/lbjexamples/ktapps/HelloMassDistribution.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2024-2025 Stephen Gold and Yanis Boudiaf
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package com.github.stephengold.lbjexamples.ktapps
30 |
31 | import com.github.stephengold.sport.input.RotateMode
32 | import com.github.stephengold.sport.physics.BasePhysicsApp
33 | import com.jme3.bullet.PhysicsSpace
34 | import com.jme3.bullet.collision.shapes.CompoundCollisionShape
35 | import com.jme3.bullet.collision.shapes.CylinderCollisionShape
36 | import com.jme3.bullet.objects.PhysicsBody
37 | import com.jme3.bullet.objects.PhysicsRigidBody
38 | import com.jme3.math.Transform
39 | import com.jme3.math.Vector3f
40 | import com.jme3.util.BufferUtils
41 | import java.nio.FloatBuffer
42 |
43 | /*
44 | * A simple example to demonstrate the use of principalAxes() and correctAxes()
45 | * to improve the plausibility of a compound shape.
46 | *
47 | * Builds upon HelloMadMallet.
48 | *
49 | * author: Stephen Gold sgold@sonic.net
50 | */
51 |
52 | /*
53 | * Main entry point for the HelloMassDistribution application.
54 | */
55 | fun main() {
56 | val application = HelloMassDistribution()
57 | application.start()
58 | }
59 |
60 | class HelloMassDistribution : BasePhysicsApp() {
61 | /*
62 | * Create the PhysicsSpace. Invoked once during initialization.
63 | */
64 | override fun createSpace(): PhysicsSpace {
65 | val result = PhysicsSpace(PhysicsSpace.BroadphaseType.DBVT)
66 | result.setGravity(Vector3f(0f, -50f, 0f))
67 |
68 | return result
69 | }
70 |
71 | /*
72 | * Initialize the application. Invoked once.
73 | */
74 | override fun initialize() {
75 | super.initialize()
76 | getCameraInputProcessor().setRotationMode(RotateMode.DragLMB)
77 |
78 | // Position the camera for a good view.
79 | cam.setLocation(Vector3f(10f, -2.75f, 0f))
80 | cam.setUpAngle(0.05f)
81 | cam.setAzimuth(-3.05f)
82 | }
83 |
84 | /*
85 | * Populate the PhysicsSpace. Invoked once during initialization.
86 | */
87 | override fun populateSpace() {
88 | // Construct a compound shape for the mallet.
89 | val headLength = 1f
90 | val headRadius = 0.5f
91 | val hes = Vector3f(headLength / 2f, headRadius, headRadius)
92 | val headShape = CylinderCollisionShape(hes, PhysicsSpace.AXIS_X)
93 |
94 | val handleLength = 3f
95 | val handleRadius = 0.3f
96 | hes.set(handleRadius, handleRadius, handleLength / 2f)
97 | val handleShape = CylinderCollisionShape(hes, PhysicsSpace.AXIS_Z)
98 |
99 | val malletShape = CompoundCollisionShape()
100 | malletShape.addChildShape(handleShape, 0f, 0f, handleLength / 2f)
101 | malletShape.addChildShape(headShape, 0f, 0f, handleLength)
102 |
103 | // Calculate a correction to put 75% of the mass in the head.
104 | val handleMass = 0.5f
105 | val headMass = 1.5f
106 | val massDistribution = BufferUtils.createFloatBuffer(
107 | handleMass, headMass)
108 | val inertiaVector = Vector3f()
109 | val correction = malletShape.principalAxes(
110 | massDistribution, null, inertiaVector)
111 |
112 | // Correct the shape.
113 | malletShape.correctAxes(correction)
114 |
115 | // Create a dynamic body for the mallet.
116 | val mass = handleMass + headMass
117 | val mallet = PhysicsRigidBody(malletShape, mass)
118 | mallet.setPhysicsLocation(Vector3f(0f, 4f, 0f))
119 |
120 | // Increase the mallet's angular damping to stabilize it.
121 | mallet.setAngularDamping(0.9f)
122 |
123 | // The mallet's center has changed, so adjust its moment of inertia.
124 | val inverseInertia = Vector3f(1f, 1f, 1f).divideLocal(inertiaVector)
125 | mallet.setInverseInertiaLocal(inverseInertia)
126 |
127 | physicsSpace.addCollisionObject(mallet)
128 |
129 | // Create a static disc and add it to the space.
130 | val discRadius = 5f
131 | val discThickness = 0.5f
132 | val discShape = CylinderCollisionShape(
133 | discRadius, discThickness, PhysicsSpace.AXIS_Y)
134 | val disc = PhysicsRigidBody(discShape, PhysicsBody.massForStatic)
135 | physicsSpace.addCollisionObject(disc)
136 | disc.setPhysicsLocation(Vector3f(0f, -3f, 0f))
137 |
138 | // Visualize the mallet, including its local axes:
139 | visualizeShape(mallet)
140 | val debugAxisLength = 1f
141 | visualizeAxes(mallet, debugAxisLength)
142 |
143 | // Visualize the shape of the disc:
144 | visualizeShape(disc)
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/kotlin-apps/src/main/kotlin/com/github/stephengold/lbjexamples/ktapps/HelloNonUniformGravity.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2024-2025 Stephen Gold and Yanis Boudiaf
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package com.github.stephengold.lbjexamples.ktapps
30 |
31 | import com.github.stephengold.sport.physics.BasePhysicsApp
32 | import com.github.stephengold.sport.physics.LocalAxisGeometry
33 | import com.jme3.bullet.PhysicsSpace
34 | import com.jme3.bullet.PhysicsTickListener
35 | import com.jme3.bullet.collision.shapes.SphereCollisionShape
36 | import com.jme3.bullet.objects.PhysicsRigidBody
37 | import com.jme3.math.Vector3f
38 | import jme3utilities.math.MyVector3f
39 |
40 | /*
41 | * A simple example of non-uniform gravity.
42 | *
43 | * Builds upon HelloRigidBody.
44 | *
45 | * author: Stephen Gold sgold@sonic.net
46 | */
47 |
48 | /*
49 | * Main entry point for the HelloNonUniformGravity application.
50 | */
51 | fun main() {
52 | val application = HelloNonUniformGravity()
53 | application.start()
54 | }
55 |
56 | /*
57 | * dynamic body subjected to non-uniform gravity
58 | */
59 | private var planet: PhysicsRigidBody? = null
60 | /*
61 | * temporary storage for vectors
62 | */
63 | private val tmpVector = Vector3f()
64 |
65 | class HelloNonUniformGravity :
66 | BasePhysicsApp(), PhysicsTickListener {
67 | // *************************************************************************
68 | // BasePhysicsApp override functions
69 |
70 | /*
71 | * Create the PhysicsSpace. Invoked once during initialization.
72 | */
73 | override fun createSpace(): PhysicsSpace {
74 | val result = PhysicsSpace(PhysicsSpace.BroadphaseType.DBVT)
75 |
76 | // To enable the callbacks, register the application as a tick listener.
77 | result.addTickListener(this)
78 |
79 | // Reduce the time step for better accuracy.
80 | result.setAccuracy(0.005f)
81 |
82 | return result
83 | }
84 |
85 | /*
86 | * Populate the PhysicsSpace. Invoked once during initialization.
87 | */
88 | override fun populateSpace() {
89 | // Create a CollisionShape for the planet.
90 | val planetRadius = 0.1f
91 | val planetShape = SphereCollisionShape(planetRadius)
92 |
93 | // Create a planet (dynamic rigid body) and add it to the space.
94 | val planetMass = 1f // physics mass unit = 10^25 kg
95 | planet = PhysicsRigidBody(planetShape, planetMass)
96 | physicsSpace.addCollisionObject(planet)
97 |
98 | // Prevent deactivation of the planet.
99 | planet!!.setEnableSleep(false)
100 |
101 | // Kick the planet into orbit around the central black hole.
102 | planet!!.setPhysicsLocation(Vector3f(2f, 0f, 0f))
103 | planet!!.applyCentralImpulse(Vector3f(0f, -1f, 0f))
104 |
105 | // Visualize the shape of the planet:
106 | visualizeShape(planet)
107 |
108 | // Visualize axes to indicate the black hole's location:
109 | LocalAxisGeometry(null, MyVector3f.xAxis, 1f)
110 | LocalAxisGeometry(null, MyVector3f.yAxis, 1f)
111 | }
112 |
113 | /*
114 | * Advance the physics simulation by the specified amount. Invoked during
115 | * each update.
116 | *
117 | * wallClockSeconds: the elapsed wall-clock time since the previous
118 | * invocation of updatePhysics() (in seconds, >=0)
119 | */
120 | override fun updatePhysics(wallClockSeconds: Float) {
121 | physicsSpace.update(wallClockSeconds)
122 | }
123 | // *************************************************************************
124 | // PhysicsTickListener override functions
125 |
126 | /*
127 | * Callback from Bullet, invoked just before each simulation step.
128 | *
129 | * space: the space that's about to be stepped (not null)
130 | * timeStep: the duration of the simulation step (in seconds, >=0)
131 | */
132 | override fun prePhysicsTick(space: PhysicsSpace, timeStep: Float) {
133 | // Calculate the gravitational acceleration GM/r^2.
134 | planet!!.getPhysicsLocation(tmpVector)
135 | val r2 = tmpVector.lengthSquared() //squared distance from black hole
136 | MyVector3f.normalizeLocal(tmpVector)
137 | tmpVector.multLocal(-3f / r2)
138 | planet!!.setGravity(tmpVector)
139 | }
140 |
141 | /*
142 | * Callback from Bullet, invoked just after each simulation step.
143 | *
144 | * space: the space that was just stepped (not null)
145 | * timeStep: the duration of the simulation step (in seconds, >=0)
146 | */
147 | override fun physicsTick(space: PhysicsSpace, timeStep: Float) {
148 | // do nothing
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/kotlin-apps/src/main/kotlin/com/github/stephengold/lbjexamples/ktapps/HelloPin.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2024 Stephen Gold and Yanis Boudiaf
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package com.github.stephengold.lbjexamples.ktapps
30 |
31 | import com.github.stephengold.sport.Mesh
32 | import com.github.stephengold.sport.mesh.ClothGrid
33 | import com.github.stephengold.sport.physics.BasePhysicsApp
34 | import com.github.stephengold.sport.physics.LinksGeometry
35 | import com.github.stephengold.sport.physics.PinsGeometry
36 | import com.jme3.bullet.PhysicsSoftSpace
37 | import com.jme3.bullet.PhysicsSpace
38 | import com.jme3.bullet.collision.shapes.SphereCollisionShape
39 | import com.jme3.bullet.objects.PhysicsBody
40 | import com.jme3.bullet.objects.PhysicsRigidBody
41 | import com.jme3.bullet.objects.PhysicsSoftBody
42 | import com.jme3.bullet.objects.infos.SoftBodyConfig
43 | import com.jme3.bullet.objects.infos.SoftBodyMaterial
44 | import com.jme3.bullet.util.NativeSoftBodyUtil
45 | import com.jme3.math.Vector3f
46 |
47 | /*
48 | * A simple cloth simulation with a pinned node.
49 | *
50 | * Builds upon HelloCloth.
51 | *
52 | * author: Stephen Gold sgold@sonic.net
53 | */
54 |
55 | /*
56 | * Main entry point for the HelloPin application.
57 | */
58 | fun main() {
59 | val application = HelloPin()
60 | application.start()
61 | }
62 |
63 | class HelloPin : BasePhysicsApp() {
64 | /*
65 | * Create the PhysicsSpace. Invoked once during initialization.
66 | */
67 | override fun createSpace(): PhysicsSoftSpace {
68 | val worldMin = Vector3f(-999f, -999f, -999f)
69 | val worldMax = Vector3f(+999f, +999f, +999f)
70 | val result = PhysicsSoftSpace(
71 | worldMin, worldMax, PhysicsSpace.BroadphaseType.DBVT)
72 |
73 | return result
74 | }
75 |
76 | /*
77 | * Initialize the application. Invoked once.
78 | */
79 | override fun initialize() {
80 | super.initialize()
81 |
82 | // Relocate the camera.
83 | cam.setLocation(Vector3f(0f, 1f, 8f))
84 | }
85 |
86 | /*
87 | * Populate the PhysicsSpace. Invoked once during initialization.
88 | */
89 | override fun populateSpace() {
90 | // Create a static, rigid sphere and add it to the physics space.
91 | val radius = 1f
92 | val shape = SphereCollisionShape(radius)
93 | val sphere = PhysicsRigidBody(shape, PhysicsBody.massForStatic)
94 | physicsSpace.addCollisionObject(sphere)
95 | visualizeShape(sphere)
96 |
97 | // Generate a subdivided square mesh with alternating diagonals.
98 | val numLines = 41
99 | val lineSpacing = 0.1f // mesh units
100 | val squareGrid = ClothGrid(numLines, numLines, lineSpacing)
101 |
102 | // Create a soft square and add it to the physics space.
103 | val cloth = PhysicsSoftBody()
104 | NativeSoftBodyUtil.appendFromTriMesh(squareGrid, cloth)
105 | physicsSpace.addCollisionObject(cloth)
106 |
107 | // Pin one of the corner nodes by setting its mass to zero.
108 | val nodeIndex = 0 // upper left corner
109 | cloth.setNodeMass(nodeIndex, PhysicsBody.massForStatic)
110 | /*
111 | * Make the cloth flexible by reducing the angular stiffness
112 | * of its material.
113 | */
114 | val mat = cloth.getSoftMaterial()
115 | mat.setAngularStiffness(0f) // default=1
116 | /*
117 | * Improve simulation accuracy by increasing
118 | * the number of position-solver iterations for the cloth.
119 | */
120 | val config = cloth.getSoftConfig()
121 | config.setPositionIterations(9) // default=1
122 |
123 | // Translate the cloth upward to its starting location.
124 | cloth.applyTranslation(Vector3f(0f, 2f, 0f))
125 |
126 | // Visualize the soft-body links and pin:
127 | LinksGeometry(cloth)
128 | PinsGeometry(cloth)
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/kotlin-apps/src/main/kotlin/com/github/stephengold/lbjexamples/ktapps/HelloRigidBody.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2024-2025 Stephen Gold and Yanis Boudiaf
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package com.github.stephengold.lbjexamples.ktapps
30 |
31 | import com.github.stephengold.sport.physics.BasePhysicsApp
32 | import com.jme3.bullet.PhysicsSpace
33 | import com.jme3.bullet.collision.shapes.SphereCollisionShape
34 | import com.jme3.bullet.objects.PhysicsRigidBody
35 | import com.jme3.math.Vector3f
36 |
37 | /*
38 | * A simple example of 2 colliding balls, illustrating the 5 basic features of
39 | * responsive, dynamic, rigid bodies:
40 | * 1. rigidity (fixed shape),
41 | * 2. inertia (resistance to changes of motion),
42 | * 3. dynamics (motion determined by forces, torques, and impulses),
43 | * 4. gravity (continual downward force), and
44 | * 5. contact response (avoid intersecting with other bodies).
45 | *
46 | * Builds upon HelloSport.
47 | *
48 | * author: Stephen Gold sgold@sonic.net
49 | */
50 |
51 | /*
52 | * Main entry point for the HelloRigidBody application.
53 | */
54 | fun main() {
55 | val application = HelloRigidBody()
56 | application.start()
57 | }
58 |
59 | class HelloRigidBody : BasePhysicsApp() {
60 | /*
61 | * Create the PhysicsSpace. Invoked once during initialization.
62 | */
63 | override fun createSpace(): PhysicsSpace {
64 | val result = PhysicsSpace(PhysicsSpace.BroadphaseType.DBVT)
65 | return result
66 | }
67 |
68 | /*
69 | * Populate the PhysicsSpace. Invoked once during initialization.
70 | */
71 | override fun populateSpace() {
72 | // Create a CollisionShape for balls.
73 | val ballRadius = 1f
74 | val ballShape = SphereCollisionShape(ballRadius)
75 |
76 | // Create 2 balls (dynamic rigid bodies) and add them to the space.
77 | val ballMass = 2f
78 | val ball1 = PhysicsRigidBody(ballShape, ballMass)
79 | physicsSpace.addCollisionObject(ball1)
80 | val ball2 = PhysicsRigidBody(ballShape, ballMass)
81 | physicsSpace.addCollisionObject(ball2)
82 |
83 | // Locate the balls initially 2 PSU (physics-space units) apart.
84 | // In other words, 4 PSU from center to center.
85 | ball1.setPhysicsLocation(Vector3f(1f, 1f, 0f))
86 | ball2.setPhysicsLocation(Vector3f(5f, 1f, 0f))
87 |
88 | // Set ball #2 on a collision course with ball #1.
89 | ball2.applyCentralImpulse(Vector3f(-25f, 0f, 0f))
90 |
91 | // Visualize the shapes of both rigid bodies:
92 | visualizeShape(ball1)
93 | visualizeShape(ball2)
94 | }
95 |
96 | /*
97 | * Advance the physics simulation by the specified amount. Invoked during
98 | * each update.
99 | *
100 | * wallClockSeconds: the elapsed wall-clock time since the previous
101 | * invocation of updatePhysics() (in seconds, >=0)
102 | */
103 | override fun updatePhysics(wallClockSeconds: Float) {
104 | // For clarity, simulate at 1/10th normal speed.
105 | val simulateSeconds = 0.1f * wallClockSeconds
106 | physicsSpace.update(simulateSeconds)
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/kotlin-apps/src/main/kotlin/com/github/stephengold/lbjexamples/ktapps/HelloSoftBody.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2024-2025 Stephen Gold and Yanis Boudiaf
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package com.github.stephengold.lbjexamples.ktapps
30 |
31 | import com.github.stephengold.sport.Mesh
32 | import com.github.stephengold.sport.mesh.IcosphereMesh
33 | import com.github.stephengold.sport.physics.BasePhysicsApp
34 | import com.github.stephengold.sport.physics.FacesGeometry
35 | import com.jme3.bullet.PhysicsSoftSpace
36 | import com.jme3.bullet.PhysicsSpace
37 | import com.jme3.bullet.collision.shapes.BoxCollisionShape
38 | import com.jme3.bullet.objects.PhysicsBody
39 | import com.jme3.bullet.objects.PhysicsRigidBody
40 | import com.jme3.bullet.objects.PhysicsSoftBody
41 | import com.jme3.bullet.objects.infos.Sbcp
42 | import com.jme3.bullet.objects.infos.SoftBodyConfig
43 | import com.jme3.bullet.util.NativeSoftBodyUtil
44 | import com.jme3.math.Vector3f
45 |
46 | /*
47 | * A simple example of a soft body colliding with a static rigid body.
48 | *
49 | * Builds upon HelloStaticBody.
50 | *
51 | * author: Stephen Gold sgold@sonic.net
52 | */
53 |
54 | /*
55 | * Main entry point for the HelloSoftBody application.
56 | */
57 | fun main() {
58 | val application = HelloSoftBody()
59 | application.start()
60 | }
61 |
62 | class HelloSoftBody : BasePhysicsApp() {
63 | // *************************************************************************
64 | // BasePhysicsApp override functions
65 |
66 | /*
67 | * Create the PhysicsSpace. Invoked once during initialization.
68 | */
69 | override fun createSpace(): PhysicsSoftSpace {
70 | val worldMin = Vector3f(-999f, -999f, -999f)
71 | val worldMax = Vector3f(+999f, +999f, +999f)
72 | val result = PhysicsSoftSpace(
73 | worldMin, worldMax, PhysicsSpace.BroadphaseType.DBVT)
74 |
75 | return result
76 | }
77 |
78 | /*
79 | * Initialize the application. Invoked once.
80 | */
81 | override fun initialize() {
82 | super.initialize()
83 |
84 | // Relocate the camera.
85 | cam.setLocation(Vector3f(0f, 1f, 8f))
86 | }
87 |
88 | /*
89 | * Populate the PhysicsSpace. Invoked once during initialization.
90 | */
91 | override fun populateSpace() {
92 | addBox()
93 |
94 | // A mesh is used to generate the shape and topology of the soft body.
95 | val numRefinementIterations = 3
96 | val sphere = IcosphereMesh(numRefinementIterations, true)
97 |
98 | // Create a soft ball and add it to the physics space.
99 | val body = PhysicsSoftBody()
100 | NativeSoftBodyUtil.appendFromTriMesh(sphere, body)
101 | physicsSpace.addCollisionObject(body)
102 | /*
103 | * Set the ball's default frame pose: if deformed,
104 | * it will tend to return to its current shape.
105 | */
106 | val setVolumePose = false
107 | val setFramePose = true
108 | body.setPose(setVolumePose, setFramePose)
109 |
110 | // Enable pose matching to make the body bouncy.
111 | val config = body.getSoftConfig()
112 | config.set(Sbcp.PoseMatching, 0.05f)
113 |
114 | // Translate the body to its start location.
115 | body.applyTranslation(Vector3f(0f, 3f, 0f))
116 |
117 | // Visualize the soft-body faces:
118 | FacesGeometry(body)
119 | }
120 | // *************************************************************************
121 | // private methods
122 |
123 | /*
124 | * Add a large static cube to serve as a platform.
125 | */
126 | private fun addBox() {
127 | val halfExtent = 3f // mesh units
128 | val shape = BoxCollisionShape(halfExtent)
129 |
130 | val body = PhysicsRigidBody(shape, PhysicsBody.massForStatic)
131 | body.setPhysicsLocation(Vector3f(0f, -halfExtent, 0f))
132 | physicsSpace.addCollisionObject(body)
133 |
134 | visualizeShape(body)
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/kotlin-apps/src/main/kotlin/com/github/stephengold/lbjexamples/ktapps/HelloSoftRope.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2024 Stephen Gold and Yanis Boudiaf
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package com.github.stephengold.lbjexamples.ktapps
30 |
31 | import com.github.stephengold.sport.Mesh
32 | import com.github.stephengold.sport.mesh.DividedLine
33 | import com.github.stephengold.sport.physics.BasePhysicsApp
34 | import com.github.stephengold.sport.physics.LinksGeometry
35 | import com.github.stephengold.sport.physics.PinsGeometry
36 | import com.jme3.bullet.PhysicsSoftSpace
37 | import com.jme3.bullet.PhysicsSpace
38 | import com.jme3.bullet.objects.PhysicsBody
39 | import com.jme3.bullet.objects.PhysicsSoftBody
40 | import com.jme3.bullet.util.NativeSoftBodyUtil
41 | import com.jme3.math.Vector3f
42 |
43 | /*
44 | * A simple rope simulation using a soft body.
45 | *
46 | * Builds upon HelloPin.
47 | *
48 | * author: Stephen Gold sgold@sonic.net
49 | */
50 |
51 | /*
52 | * Main entry point for the HelloSoftRope application.
53 | */
54 | fun main() {
55 | val application = HelloSoftRope()
56 | application.start()
57 | }
58 |
59 | class HelloSoftRope : BasePhysicsApp() {
60 | /*
61 | * Create the PhysicsSpace. Invoked once during initialization.
62 | */
63 | override fun createSpace(): PhysicsSoftSpace {
64 | val worldMin = Vector3f(-999f, -999f, -999f)
65 | val worldMax = Vector3f(+999f, +999f, +999f)
66 | val result = PhysicsSoftSpace(
67 | worldMin, worldMax, PhysicsSpace.BroadphaseType.DBVT)
68 |
69 | return result
70 | }
71 |
72 | /*
73 | * Initialize the application. Invoked once.
74 | */
75 | override fun initialize() {
76 | super.initialize()
77 |
78 | // Relocate the camera.
79 | cam.setLocation(Vector3f(0f, 1f, 8f))
80 | }
81 |
82 | /**
83 | * Populate the PhysicsSpace. Invoked once during initialization.
84 | */
85 | override fun populateSpace() {
86 | // Generate a subdivided line segment.
87 | val numSegments = 40
88 | val endPoint1 = Vector3f(0f, 4f, 0f)
89 | val endPoint2 = Vector3f(2f, 4f, 2f)
90 | val lineMesh = DividedLine(endPoint1, endPoint2, numSegments)
91 |
92 | // Create a soft body and add it to the physics space.
93 | val rope = PhysicsSoftBody()
94 | NativeSoftBodyUtil.appendFromLineMesh(lineMesh, rope)
95 | physicsSpace.addCollisionObject(rope)
96 |
97 | // Pin one of the end nodes by setting its mass to zero.
98 | val nodeIndex = 0
99 | rope.setNodeMass(nodeIndex, PhysicsBody.massForStatic)
100 |
101 | // Visualize the soft-body links and pin:
102 | LinksGeometry(rope)
103 | PinsGeometry(rope)
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/kotlin-apps/src/main/kotlin/com/github/stephengold/lbjexamples/ktapps/HelloSoftSoft.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2024 Stephen Gold and Yanis Boudiaf
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package com.github.stephengold.lbjexamples.ktapps
30 |
31 | import com.github.stephengold.sport.Mesh
32 | import com.github.stephengold.sport.mesh.IcosphereMesh
33 | import com.github.stephengold.sport.physics.BasePhysicsApp
34 | import com.github.stephengold.sport.physics.FacesGeometry
35 | import com.jme3.bullet.PhysicsSoftSpace
36 | import com.jme3.bullet.PhysicsSpace
37 | import com.jme3.bullet.objects.PhysicsSoftBody
38 | import com.jme3.bullet.objects.infos.ConfigFlag
39 | import com.jme3.bullet.objects.infos.Sbcp
40 | import com.jme3.bullet.objects.infos.SoftBodyConfig
41 | import com.jme3.bullet.util.NativeSoftBodyUtil
42 | import com.jme3.math.Vector3f
43 |
44 | /*
45 | * A simple example of a soft-soft collision.
46 | *
47 | * Builds upon HelloSoftBody.
48 | *
49 | * author: Stephen Gold sgold@sonic.net
50 | */
51 |
52 | /*
53 | * Main entry point for the HelloSoftSoft application.
54 | */
55 | fun main() {
56 | val application = HelloSoftSoft()
57 | application.start()
58 | }
59 |
60 | class HelloSoftSoft : BasePhysicsApp() {
61 | /*
62 | * Create the PhysicsSpace. Invoked once during initialization.
63 | */
64 | override fun createSpace(): PhysicsSoftSpace {
65 | val worldMin = Vector3f(-999f, -999f, -999f)
66 | val worldMax = Vector3f(+999f, +999f, +999f)
67 | val result = PhysicsSoftSpace(
68 | worldMin, worldMax, PhysicsSpace.BroadphaseType.DBVT)
69 |
70 | // Set gravity to zero.
71 | result.setGravity(Vector3f.ZERO) // default = (0,-9.81,0)
72 |
73 | return result
74 | }
75 |
76 | /*
77 | * Initialize the application. Invoked once.
78 | */
79 | override fun initialize() {
80 | super.initialize()
81 |
82 | // Relocate the camera.
83 | cam.setLocation(Vector3f(0f, 1f, 8f))
84 | }
85 |
86 | /*
87 | * Populate the PhysicsSpace. Invoked once during initialization.
88 | */
89 | override fun populateSpace() {
90 | /*
91 | * A mesh is used to generate the shape and topology
92 | * of each soft body.
93 | */
94 | val numRefinementIterations = 3
95 | val sphere = IcosphereMesh(numRefinementIterations, true)
96 |
97 | // Create 2 squishy balls and add them to the physics space.
98 | val ball1 = PhysicsSoftBody()
99 | NativeSoftBodyUtil.appendFromTriMesh(sphere, ball1)
100 | physicsSpace.addCollisionObject(ball1)
101 |
102 | val ball2 = PhysicsSoftBody()
103 | NativeSoftBodyUtil.appendFromTriMesh(sphere, ball2)
104 | physicsSpace.addCollisionObject(ball2)
105 | /*
106 | * Set each ball's default frame pose: if deformed,
107 | * it will tend to return to its current shape.
108 | */
109 | val setVolumePose = false
110 | val setFramePose = true
111 | ball1.setPose(setVolumePose, setFramePose)
112 | ball2.setPose(setVolumePose, setFramePose)
113 |
114 | // Enable pose matching to make the balls bouncy.
115 | val config1 = ball1.getSoftConfig()
116 | config1.set(Sbcp.PoseMatching, 0.01f) // default = 0
117 | val config2 = ball2.getSoftConfig()
118 | config2.set(Sbcp.PoseMatching, 0.01f)
119 | /*
120 | * Enable soft-soft collisions for each ball.
121 | * Clearing all other collision flags disables soft-rigid collisions.
122 | */
123 | config1.setCollisionFlags(ConfigFlag.VF_SS) // default = SDF_RS
124 | config2.setCollisionFlags(ConfigFlag.VF_SS)
125 |
126 | // Translate ball2 upward and put it on a collision course with ball1.
127 | ball2.applyTranslation(Vector3f(0f, 3f, 0f))
128 | ball2.setVelocity(Vector3f(0f, -1f, 0f))
129 |
130 | // Visualize the soft-body faces:
131 | FacesGeometry(ball1)
132 | FacesGeometry(ball2)
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/kotlin-apps/src/main/kotlin/com/github/stephengold/lbjexamples/ktapps/HelloSport.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2024-2025 Stephen Gold and Yanis Boudiaf
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package com.github.stephengold.lbjexamples.ktapps
30 |
31 | import com.github.stephengold.sport.physics.BasePhysicsApp
32 | import com.jme3.bullet.PhysicsSpace
33 | import com.jme3.bullet.collision.shapes.PlaneCollisionShape
34 | import com.jme3.bullet.collision.shapes.SphereCollisionShape
35 | import com.jme3.bullet.objects.PhysicsBody
36 | import com.jme3.bullet.objects.PhysicsRigidBody
37 | import com.jme3.math.Plane
38 | import com.jme3.math.Vector3f
39 |
40 | /*
41 | * Drop a dynamic sphere onto a horizontal surface and visualize them both using
42 | * SPORT graphics.
43 | *
44 | * Builds upon HelloLibbulletjme.
45 | *
46 | * author: Stephen Gold sgold@sonic.net
47 | */
48 |
49 | /*
50 | * Main entry point for the HelloSport application.
51 | */
52 | fun main() {
53 | val application = HelloSport()
54 | application.start()
55 | /*
56 | * During initialization, BasePhysicsApp loads the native library
57 | * and invokes createSpace() and populateSpace().
58 | */
59 | }
60 |
61 | class HelloSport : BasePhysicsApp() {
62 | /*
63 | * Create the PhysicsSpace. Invoked once during initialization.
64 | */
65 | override fun createSpace(): PhysicsSpace {
66 | val result = PhysicsSpace(PhysicsSpace.BroadphaseType.DBVT)
67 | return result
68 | }
69 |
70 | /*
71 | * Populate the PhysicsSpace. Invoked once during initialization.
72 | */
73 | override fun populateSpace() {
74 | // Add a static horizontal plane at y=-1:
75 | val groundY = -1f
76 | val plane = Plane(Vector3f.UNIT_Y, groundY)
77 | val planeShape = PlaneCollisionShape(plane)
78 | val floor = PhysicsRigidBody(planeShape, PhysicsBody.massForStatic)
79 | physicsSpace!!.addCollisionObject(floor)
80 |
81 | // Add a sphere-shaped, dynamic, rigid body at the origin:
82 | val radius = 0.3f
83 | val ballShape = SphereCollisionShape(radius)
84 | val mass = 1f
85 | val ball = PhysicsRigidBody(ballShape, mass)
86 | physicsSpace!!.addCollisionObject(ball)
87 |
88 | // Visualize the shapes of both rigid bodies:
89 | visualizeShape(floor)
90 | visualizeShape(ball)
91 | }
92 |
93 | /*
94 | * Advance the physics simulation by the specified amount. Invoked during
95 | * each update.
96 | *
97 | * wallClockSeconds: the elapsed wall-clock time since the previous
98 | * invocation of updatePhysics() (in seconds, >=0)
99 | */
100 | override fun updatePhysics(wallClockSeconds: Float) {
101 | physicsSpace.update(wallClockSeconds)
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/kotlin-apps/src/main/kotlin/com/github/stephengold/lbjexamples/ktapps/HelloStaticBody.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2024-2025 Stephen Gold and Yanis Boudiaf
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package com.github.stephengold.lbjexamples.ktapps
30 |
31 | import com.github.stephengold.sport.physics.BasePhysicsApp
32 | import com.jme3.bullet.PhysicsSpace
33 | import com.jme3.bullet.collision.shapes.SphereCollisionShape
34 | import com.jme3.bullet.objects.PhysicsBody
35 | import com.jme3.bullet.objects.PhysicsRigidBody
36 | import com.jme3.math.Vector3f
37 |
38 | /*
39 | * A simple example combining static and dynamic rigid bodies.
40 | *
41 | * Builds upon HelloRigidBody.
42 | *
43 | * author: Stephen Gold sgold@sonic.net
44 | */
45 |
46 | /*
47 | * Main entry point for the HelloStaticBody application.
48 | */
49 | fun main() {
50 | val application = HelloStaticBody()
51 | application.start()
52 | }
53 |
54 | class HelloStaticBody : BasePhysicsApp() {
55 | /*
56 | * Create the PhysicsSpace. Invoked once during initialization.
57 | */
58 | override fun createSpace(): PhysicsSpace {
59 | val result = PhysicsSpace(PhysicsSpace.BroadphaseType.DBVT)
60 | return result
61 | }
62 |
63 | /*
64 | * Populate the PhysicsSpace. Invoked once during initialization.
65 | */
66 | override fun populateSpace() {
67 | // Create a CollisionShape for balls.
68 | val ballRadius = 1f
69 | val ballShape = SphereCollisionShape(ballRadius)
70 |
71 | // Create a dynamic body and add it to the space.
72 | val mass = 2f
73 | val dynaBall = PhysicsRigidBody(ballShape, mass)
74 | physicsSpace.addCollisionObject(dynaBall)
75 |
76 | // Create a static body and add it to the space.
77 | val statBall = PhysicsRigidBody(ballShape, PhysicsBody.massForStatic)
78 | physicsSpace.addCollisionObject(statBall)
79 |
80 | // Position the balls in physics space.
81 | dynaBall.setPhysicsLocation(Vector3f(0f, 4f, 0f))
82 | statBall.setPhysicsLocation(Vector3f(0.1f, 0f, 0f))
83 |
84 | // Visualize the shapes of both rigid bodies:
85 | visualizeShape(dynaBall)
86 | visualizeShape(statBall)
87 | }
88 |
89 | /*
90 | * Advance the physics simulation by the specified amount. Invoked during
91 | * each update.
92 | *
93 | * wallClockSeconds: the elapsed wall-clock time since the previous
94 | * invocation of updatePhysics() (in seconds, >=0)
95 | */
96 | override fun updatePhysics(wallClockSeconds: Float) {
97 | physicsSpace.update(wallClockSeconds)
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/kotlin-apps/src/main/kotlin/com/github/stephengold/lbjexamples/ktapps/console/HelloLibbulletjme.kt:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2024-2025 Stephen Gold and Yanis Boudiaf
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package com.github.stephengold.lbjexamples.ktapps.console
30 |
31 | import com.jme3.bullet.PhysicsSpace
32 | import com.jme3.bullet.collision.shapes.PlaneCollisionShape
33 | import com.jme3.bullet.collision.shapes.SphereCollisionShape
34 | import com.jme3.bullet.objects.PhysicsBody
35 | import com.jme3.bullet.objects.PhysicsRigidBody
36 | import com.jme3.math.Plane
37 | import com.jme3.math.Vector3f
38 | import electrostatic4j.snaploader.LibraryInfo;
39 | import electrostatic4j.snaploader.LoadingCriterion;
40 | import electrostatic4j.snaploader.NativeBinaryLoader;
41 | import electrostatic4j.snaploader.filesystem.DirectoryPath;
42 | import electrostatic4j.snaploader.platform.NativeDynamicLibrary;
43 | import electrostatic4j.snaploader.platform.util.PlatformPredicate;
44 |
45 | /*
46 | * Drop a dynamic sphere onto a horizontal surface (non-graphical illustrative
47 | * example).
48 | *
49 | * author: Stephen Gold sgold@sonic.net
50 | */
51 |
52 | private var ball: PhysicsRigidBody? = null
53 | private var physicsSpace: PhysicsSpace? = null
54 |
55 | /*
56 | * Main entry point for the HelloLibbulletjme application.
57 | */
58 | fun main() {
59 | val info = LibraryInfo(null, "bulletjme", DirectoryPath.USER_DIR)
60 | val loader = NativeBinaryLoader(info)
61 |
62 | val libraries = arrayOf(
63 | NativeDynamicLibrary("native/linux/arm64", PlatformPredicate.LINUX_ARM_64),
64 | NativeDynamicLibrary("native/linux/arm32", PlatformPredicate.LINUX_ARM_32),
65 | NativeDynamicLibrary("native/linux/x86_64", PlatformPredicate.LINUX_X86_64),
66 | NativeDynamicLibrary("native/osx/arm64", PlatformPredicate.MACOS_ARM_64),
67 | NativeDynamicLibrary("native/osx/x86_64", PlatformPredicate.MACOS_X86_64),
68 | NativeDynamicLibrary("native/windows/x86_64", PlatformPredicate.WIN_X86_64)
69 | )
70 | loader.registerNativeLibraries(libraries)
71 | .initPlatformLibrary()
72 | .setLoggingEnabled(true)
73 | loader.setRetryWithCleanExtraction(true)
74 |
75 | // Load the Libbulletjme native library for this platform.
76 | try {
77 | loader.loadLibrary(LoadingCriterion.CLEAN_EXTRACTION)
78 | } catch (exception: Exception) {
79 | throw IllegalStateException("Failed to load the Libbulletjme library!")
80 | }
81 |
82 | physicsSpace = createSpace()
83 | populateSpace()
84 |
85 | val location = Vector3f()
86 | for (iteration in 0 ..< 50) {
87 | updatePhysics(intervalSeconds = 0.02f)
88 |
89 | ball!!.getPhysicsLocation(location)
90 | println(location)
91 | }
92 | }
93 |
94 | /*
95 | * Create the PhysicsSpace. Invoked once during initialization.
96 | */
97 | private fun createSpace(): PhysicsSpace {
98 | val result = PhysicsSpace(PhysicsSpace.BroadphaseType.DBVT)
99 | return result
100 | }
101 |
102 | /*
103 | * Populate the PhysicsSpace. Invoked once during initialization.
104 | */
105 | private fun populateSpace() {
106 | // Add a static horizontal plane at y=-1:
107 | val groundY = -1f
108 | val plane = Plane(Vector3f.UNIT_Y, groundY)
109 | val planeShape = PlaneCollisionShape(plane)
110 | val floor = PhysicsRigidBody(planeShape, PhysicsBody.massForStatic)
111 | physicsSpace!!.addCollisionObject(floor)
112 |
113 | // Add a sphere-shaped, dynamic, rigid body at the origin:
114 | val radius = 0.3f
115 | val ballShape = SphereCollisionShape(radius)
116 | val mass = 1f
117 | ball = PhysicsRigidBody(ballShape, mass)
118 | physicsSpace!!.addCollisionObject(ball)
119 | }
120 |
121 | /*
122 | * Advance the physics simulation by the specified amount.
123 | *
124 | * intervalSeconds: the amount of time to simulate (in seconds, >=0)
125 | */
126 | private fun updatePhysics(intervalSeconds: Float) {
127 | val maxSteps = 0 // for a single step of the specified duration
128 | physicsSpace!!.update(intervalSeconds, maxSteps)
129 | }
--------------------------------------------------------------------------------
/kotlin-apps/src/main/resources/Textures/Terrain/splat/mountains512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/kotlin-apps/src/main/resources/Textures/Terrain/splat/mountains512.png
--------------------------------------------------------------------------------
/kotlin-apps/src/main/resources/Textures/greenTile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephengold/LbjExamples/5d761d3708d4bdd7a07f7d89f9cc345b1edd174b/kotlin-apps/src/main/resources/Textures/greenTile.png
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "devDependencies": {
3 | "@antora/cli": "3.1.10",
4 | "@antora/site-generator": "3.1.10"
5 | },
6 | "overrides": {
7 | "asciidoctor-opal-runtime": {
8 | "glob": "~10.4"
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | // global build settings shared by all LbjExamples subprojects
2 |
3 | rootProject.name = "LbjExamples"
4 |
5 | dependencyResolutionManagement {
6 | repositories {
7 | //mavenLocal() // to find libraries installed locally
8 | mavenCentral() // to find libraries released to the Maven Central repository
9 | //maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots") } // to find public snapshots of LWJGL
10 | //maven { url = uri("https://s01.oss.sonatype.org/content/groups/staging") } // to find libraries staged but not yet released
11 | //maven { url = uri("https://s01.oss.sonatype.org/content/repositories/snapshots") } // to find public snapshots of libraries
12 | }
13 | }
14 |
15 | // subprojects:
16 | include("apps")
17 | include("docs")
18 | include("kotlin-apps")
19 |
--------------------------------------------------------------------------------