();
+ cameras.add(getCamera());
+ TerrainLodControl control = new TerrainLodControl(terrain, cameras);
+ terrain.addControl(control);
+ terrain.setMaterial(matRock);
+ terrain.setLocalScale(new Vector3f(2, 2, 2));
+ terrain.setLocked(false); // unlock it so we can edit the height
+
+ terrain.setShadowMode(ShadowMode.CastAndReceive);
+ terrain.addControl(new RigidBodyControl(0));
+ rootNode.attachChild(terrain);
+ getPhysicsSpace().addAll(terrain);
+
+ }
+}
diff --git a/JmeTests/src/jme3test/bullet/TestIK.java b/JmeTests/src/jme3test/bullet/TestIK.java
new file mode 100644
index 0000000..43313e7
--- /dev/null
+++ b/JmeTests/src/jme3test/bullet/TestIK.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.bullet;
+
+import com.jme3.animation.AnimEventListener;
+import com.jme3.animation.Bone;
+import com.jme3.bullet.collision.RagdollCollisionListener;
+import com.jme3.bullet.control.KinematicRagdollControl;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Node;
+
+/**
+ * @author reden
+ */
+public class TestIK extends TestBoneRagdoll implements RagdollCollisionListener, AnimEventListener {
+
+ Node targetNode = new Node("");
+ Vector3f targetPoint;
+ Bone mouseBone;
+ Vector3f oldMousePos;
+
+ public static void main(String[] args) {
+ TestIK app = new TestIK();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ super.simpleInitApp();
+ final KinematicRagdollControl ikControl = model.getControl(KinematicRagdollControl.class);
+ inputManager.addListener(new ActionListener() {
+
+ public void onAction(String name, boolean isPressed, float tpf) {
+
+ if (name.equals("stop") && isPressed) {
+ ikControl.setEnabled(!ikControl.isEnabled());
+ ikControl.setIKMode();
+ }
+
+ if (name.equals("one") && isPressed) {
+ //ragdoll.setKinematicMode();
+ targetPoint = model.getWorldTranslation().add(new Vector3f(0,2,4));
+ targetNode.setLocalTranslation(targetPoint);
+ ikControl.setIKTarget(ikControl.getBone("Hand.L"), targetPoint, 2);
+ ikControl.setIKMode();
+ }
+ if (name.equals("two") && isPressed) {
+ //ragdoll.setKinematicMode();
+ targetPoint = model.getWorldTranslation().add(new Vector3f(-3,3,0));
+ targetNode.setLocalTranslation(targetPoint);
+ ikControl.setIKTarget(ikControl.getBone("Hand.R"), targetPoint, 3);
+ ikControl.setIKMode();
+ }
+ }
+ }, "one", "two");
+ inputManager.addMapping("one", new KeyTrigger(KeyInput.KEY_1));
+ inputManager.addMapping("two", new KeyTrigger(KeyInput.KEY_2));
+ inputManager.addMapping("stop", new KeyTrigger(KeyInput.KEY_H));
+ }
+
+}
diff --git a/JmeTests/src/jme3test/bullet/TestIssue877.java b/JmeTests/src/jme3test/bullet/TestIssue877.java
new file mode 100644
index 0000000..d17d340
--- /dev/null
+++ b/JmeTests/src/jme3test/bullet/TestIssue877.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2018 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.bullet;
+
+/**
+ * Test case for JME issue #877: multiple hinges. Based on code submitted by
+ * Daniel Martensson.
+ *
+ * If successful, all pendulums will swing at the same frequency, and all the
+ * free-falling objects will fall straight down.
+ */
+import com.jme3.app.SimpleApplication;
+import com.jme3.bullet.BulletAppState;
+import com.jme3.bullet.collision.shapes.BoxCollisionShape;
+import com.jme3.bullet.collision.shapes.CollisionShape;
+import com.jme3.bullet.control.RigidBodyControl;
+import com.jme3.bullet.joints.HingeJoint;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Node;
+
+public class TestIssue877 extends SimpleApplication {
+
+ BulletAppState bulletAppState = new BulletAppState();
+ int numPendulums = 6;
+ int numFalling = 6;
+ Node pivots[] = new Node[numPendulums];
+ Node bobs[] = new Node[numPendulums];
+ Node falling[] = new Node[numFalling];
+ float timeToNextPrint = 1f; // in seconds
+
+ public static void main(String[] args) {
+ TestIssue877 app = new TestIssue877();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ flyCam.setEnabled(false);
+ cam.setLocation(new Vector3f(-4.77f, -7.55f, 16.52f));
+ cam.setRotation(new Quaternion(-0.103433f, 0.889420f, 0.368792f, 0.249449f));
+
+ stateManager.attach(bulletAppState);
+ bulletAppState.setDebugEnabled(true);
+
+ float pivotY = 14.6214f;
+ float bobStartY = 3f;
+ float length = pivotY - bobStartY;
+ for (int i = 0; i < numPendulums; i++) {
+ float x = 6f - 2.5f * i;
+ Vector3f pivotLocation = new Vector3f(x, pivotY, 0f);
+ pivots[i] = createTestNode(0f, pivotLocation);
+
+ Vector3f bobLocation = new Vector3f(x, bobStartY, 0f);
+ bobs[i] = createTestNode(1f, bobLocation);
+ }
+
+ for (int i = 0; i < numFalling; i++) {
+ float x = -6f - 2.5f * (i + numPendulums);
+ Vector3f createLocation = new Vector3f(x, bobStartY, 0f);
+ falling[i] = createTestNode(1f, createLocation);
+ }
+
+ for (int i = 0; i < numPendulums; i++) {
+ HingeJoint joint = new HingeJoint(
+ pivots[i].getControl(RigidBodyControl.class),
+ bobs[i].getControl(RigidBodyControl.class),
+ new Vector3f(0f, 0f, 0f),
+ new Vector3f(length, 0f, 0f),
+ Vector3f.UNIT_Z.clone(),
+ Vector3f.UNIT_Z.clone());
+ bulletAppState.getPhysicsSpace().add(joint);
+ }
+ }
+
+ Node createTestNode(float mass, Vector3f location) {
+ float size = 0.1f;
+ Vector3f halfExtents = new Vector3f(size, size, size);
+ CollisionShape shape = new BoxCollisionShape(halfExtents);
+ RigidBodyControl control = new RigidBodyControl(shape, mass);
+ Node node = new Node();
+ node.addControl(control);
+ rootNode.attachChild(node);
+ bulletAppState.getPhysicsSpace().add(node);
+ control.setPhysicsLocation(location);
+
+ return node;
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ if (timeToNextPrint > 0f) {
+ timeToNextPrint -= tpf;
+ return;
+ }
+
+ if (numFalling > 0) {
+ Vector3f fallingLocation = falling[0].getWorldTranslation();
+ System.out.printf(" falling[0] location(x=%f, z=%f)",
+ fallingLocation.x, fallingLocation.z);
+ /*
+ * If an object is falling vertically, its X- and Z-coordinates
+ * should not change.
+ */
+ }
+ if (numPendulums > 0) {
+ Vector3f bobLocation = bobs[0].getWorldTranslation();
+ Vector3f pivotLocation = pivots[0].getWorldTranslation();
+ float distance = bobLocation.distance(pivotLocation);
+ System.out.printf(" bob[0] distance=%f", distance);
+ /*
+ * If the hinge is working properly, the distance from the
+ * pivot to the bob should remain roughly constant.
+ */
+ }
+ System.out.println();
+ timeToNextPrint = 1f;
+ }
+}
diff --git a/JmeTests/src/jme3test/bullet/TestIssue883.java b/JmeTests/src/jme3test/bullet/TestIssue883.java
new file mode 100644
index 0000000..f4e794f
--- /dev/null
+++ b/JmeTests/src/jme3test/bullet/TestIssue883.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2018 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.bullet;
+
+/**
+ * Test case for JME issue #883: extra physicsTicks in ThreadingType.PARALLEL.
+ *
+ * If successful, physics time and frame time will advance at the same rate.
+ */
+import com.jme3.app.SimpleApplication;
+import com.jme3.bullet.BulletAppState;
+import com.jme3.bullet.PhysicsSpace;
+
+public class TestIssue883 extends SimpleApplication {
+
+ boolean firstPrint = true;
+ float timeToNextPrint = 1f; // in seconds
+ double frameTime; // in seconds
+ double physicsTime; // in seconds
+
+ public static void main(String[] args) {
+ TestIssue883 app = new TestIssue883();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+
+ BulletAppState bulletAppState = new BulletAppState() {
+ @Override
+ public void physicsTick(PhysicsSpace space, float timeStep) {
+ physicsTime += timeStep;
+ }
+ };
+ bulletAppState.setThreadingType(BulletAppState.ThreadingType.PARALLEL);
+ stateManager.attach(bulletAppState);
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ frameTime += tpf;
+
+ if (timeToNextPrint > 0f) {
+ timeToNextPrint -= tpf;
+ return;
+ }
+
+ if (firstPrint) { // synchronize
+ frameTime = 0.;
+ physicsTime = 0.;
+ firstPrint = false;
+ }
+
+ System.out.printf(" frameTime= %s physicsTime= %s%n",
+ frameTime, physicsTime);
+ timeToNextPrint = 1f;
+ }
+}
diff --git a/JmeTests/src/jme3test/bullet/TestIssue889.java b/JmeTests/src/jme3test/bullet/TestIssue889.java
new file mode 100644
index 0000000..0704233
--- /dev/null
+++ b/JmeTests/src/jme3test/bullet/TestIssue889.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2018 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.bullet;
+
+/**
+ * Test case for JME issue #889: disabled physics control gets added to a
+ * physics space.
+ *
+ * If successful, no debug meshes will be visible.
+ */
+import com.jme3.app.SimpleApplication;
+import com.jme3.bullet.BulletAppState;
+import com.jme3.bullet.PhysicsSpace;
+import com.jme3.bullet.collision.shapes.BoxCollisionShape;
+import com.jme3.bullet.collision.shapes.CollisionShape;
+import com.jme3.bullet.collision.shapes.SphereCollisionShape;
+import com.jme3.bullet.control.BetterCharacterControl;
+import com.jme3.bullet.control.GhostControl;
+import com.jme3.bullet.control.RigidBodyControl;
+import com.jme3.math.Vector3f;
+
+public class TestIssue889 extends SimpleApplication {
+
+ public static void main(String[] args) {
+ TestIssue889 app = new TestIssue889();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ flyCam.setEnabled(false);
+
+ BulletAppState bulletAppState = new BulletAppState();
+ bulletAppState.setDebugEnabled(true);
+ bulletAppState.setSpeed(0f);
+ stateManager.attach(bulletAppState);
+ PhysicsSpace space = bulletAppState.getPhysicsSpace();
+
+ float radius = 1f;
+ CollisionShape sphere = new SphereCollisionShape(radius);
+ CollisionShape box = new BoxCollisionShape(Vector3f.UNIT_XYZ);
+
+ RigidBodyControl rbc = new RigidBodyControl(box);
+ rbc.setEnabled(false);
+ rbc.setPhysicsSpace(space);
+ rootNode.addControl(rbc);
+
+ BetterCharacterControl bcc = new BetterCharacterControl(radius, 4f, 1f);
+ bcc.setEnabled(false);
+ bcc.setPhysicsSpace(space);
+ rootNode.addControl(bcc);
+
+ GhostControl gc = new GhostControl(sphere);
+ gc.setEnabled(false);
+ gc.setPhysicsSpace(space);
+ rootNode.addControl(gc);
+ }
+}
diff --git a/JmeTests/src/jme3test/bullet/TestIssue918.java b/JmeTests/src/jme3test/bullet/TestIssue918.java
new file mode 100644
index 0000000..ed5a726
--- /dev/null
+++ b/JmeTests/src/jme3test/bullet/TestIssue918.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2018 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.bullet;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.bullet.collision.shapes.CollisionShape;
+import com.jme3.bullet.collision.shapes.SphereCollisionShape;
+import com.jme3.bullet.joints.Point2PointJoint;
+import com.jme3.bullet.objects.PhysicsRigidBody;
+import com.jme3.math.Vector3f;
+
+/**
+ * Test case for JME issue #918: Point2PointJoint.getImpulseClamp() and
+ * .getTau() return the damping value instead. The bug existed in Native Bullet
+ * only.
+ *
+ * If successful, no UnsatisfiedLinkError exception will be thrown.
+ */
+public class TestIssue918 extends SimpleApplication {
+ // *************************************************************************
+ // new methods exposed
+
+ public static void main(String[] args) {
+ TestIssue918 app = new TestIssue918();
+ app.start();
+ }
+ // *************************************************************************
+ // SimpleApplication methods
+
+ @Override
+ public void simpleInitApp() {
+ CollisionShape capsule = new SphereCollisionShape(1f);
+ PhysicsRigidBody body1 = new PhysicsRigidBody(capsule, 1f);
+ PhysicsRigidBody body2 = new PhysicsRigidBody(capsule, 1f);
+ Vector3f pivot1 = new Vector3f();
+ Vector3f pivot2 = new Vector3f();
+ Point2PointJoint joint
+ = new Point2PointJoint(body1, body2, pivot1, pivot2);
+
+ joint.setImpulseClamp(42f);
+ joint.setTau(99f);
+
+ if (joint.getImpulseClamp() != 42f) {
+ throw new RuntimeException();
+ }
+ if (joint.getTau() != 99f) {
+ throw new RuntimeException();
+ }
+
+ stop();
+ }
+}
diff --git a/JmeTests/src/jme3test/bullet/TestIssue919.java b/JmeTests/src/jme3test/bullet/TestIssue919.java
new file mode 100644
index 0000000..3fb6578
--- /dev/null
+++ b/JmeTests/src/jme3test/bullet/TestIssue919.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2018 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.bullet;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.bullet.collision.shapes.CollisionShape;
+import com.jme3.bullet.collision.shapes.SphereCollisionShape;
+import com.jme3.bullet.joints.SixDofJoint;
+import com.jme3.bullet.objects.PhysicsRigidBody;
+import com.jme3.math.Vector3f;
+
+/**
+ * Test case for JME issue #919: native implementation of
+ * TranslationalLimitMotor.getLimitSoftness() has wrong name. The bug existed in
+ * Native Bullet only.
+ *
+ * If successful, no UnsatisfiedLinkError exception will be thrown.
+ */
+public class TestIssue919 extends SimpleApplication {
+ // *************************************************************************
+ // new methods exposed
+
+ public static void main(String[] args) {
+ TestIssue919 app = new TestIssue919();
+ app.start();
+ }
+ // *************************************************************************
+ // SimpleApplication methods
+
+ @Override
+ public void simpleInitApp() {
+ CollisionShape capsule = new SphereCollisionShape(1f);
+ PhysicsRigidBody body1 = new PhysicsRigidBody(capsule, 1f);
+ PhysicsRigidBody body2 = new PhysicsRigidBody(capsule, 1f);
+ Vector3f pivot1 = new Vector3f();
+ Vector3f pivot2 = new Vector3f();
+ SixDofJoint joint = new SixDofJoint(body1, body2, pivot1, pivot2, true);
+
+ joint.getTranslationalLimitMotor().getLimitSoftness();
+
+ stop();
+ }
+}
diff --git a/JmeTests/src/jme3test/bullet/TestIssue928.java b/JmeTests/src/jme3test/bullet/TestIssue928.java
new file mode 100644
index 0000000..886fb82
--- /dev/null
+++ b/JmeTests/src/jme3test/bullet/TestIssue928.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2018 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.bullet;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.bullet.BulletAppState;
+import com.jme3.bullet.BulletAppState.ThreadingType;
+
+/**
+ * Test case for JME issue #928: crash after 64 attached and detached
+ * BulletAppStates with parallel threading. The bug existed in Native Bullet
+ * only.
+ *
+ * If successful, no crash will occur.
+ */
+public class TestIssue928 extends SimpleApplication {
+ // *************************************************************************
+ // new methods exposed
+
+ public static void main(String[] args) {
+ TestIssue928 app = new TestIssue928();
+ app.start();
+ }
+
+ int count = 0;
+ int frame = 0;
+ BulletAppState bulletAppState;
+ // *************************************************************************
+ // SimpleApplication methods
+
+ @Override
+ public void simpleInitApp() {
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ if (frame % 4 == 0) {
+ System.out.println(++count);
+ bulletAppState = new BulletAppState();
+ bulletAppState.setThreadingType(ThreadingType.PARALLEL);
+ stateManager.attach(bulletAppState);
+ } else if (frame % 4 == 2) {
+ stateManager.detach(bulletAppState);
+ }
+
+ frame++;
+ if (count == 70) {
+ System.exit(0);
+ }
+ }
+}
diff --git a/JmeTests/src/jme3test/bullet/TestKinematicAddToPhysicsSpaceIssue.java b/JmeTests/src/jme3test/bullet/TestKinematicAddToPhysicsSpaceIssue.java
new file mode 100644
index 0000000..84bf607
--- /dev/null
+++ b/JmeTests/src/jme3test/bullet/TestKinematicAddToPhysicsSpaceIssue.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2009-2018 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.bullet;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.bullet.BulletAppState;
+import com.jme3.bullet.PhysicsSpace;
+import com.jme3.bullet.collision.shapes.MeshCollisionShape;
+import com.jme3.bullet.collision.shapes.PlaneCollisionShape;
+import com.jme3.bullet.collision.shapes.SphereCollisionShape;
+import com.jme3.bullet.control.RigidBodyControl;
+import com.jme3.math.Plane;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Node;
+import com.jme3.scene.shape.Sphere;
+
+/**
+ *
+ * @author Nehon
+ */
+public class TestKinematicAddToPhysicsSpaceIssue extends SimpleApplication {
+
+ public static void main(String[] args) {
+ TestKinematicAddToPhysicsSpaceIssue app = new TestKinematicAddToPhysicsSpaceIssue();
+ app.start();
+ }
+ BulletAppState bulletAppState;
+
+ @Override
+ public void simpleInitApp() {
+
+ bulletAppState = new BulletAppState();
+ stateManager.attach(bulletAppState);
+ bulletAppState.setDebugEnabled(true);
+ // Add a physics sphere to the world
+ Node physicsSphere = PhysicsTestHelper.createPhysicsTestNode(assetManager, new SphereCollisionShape(1), 1);
+ physicsSphere.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(3, 6, 0));
+ rootNode.attachChild(physicsSphere);
+
+ //Setting the rigidBody to kinematic before adding it to the physics space
+ physicsSphere.getControl(RigidBodyControl.class).setKinematic(true);
+ //adding it to the physics space
+ getPhysicsSpace().add(physicsSphere);
+ //Making it not kinematic again, it should fall under gravity, it doesn't
+ physicsSphere.getControl(RigidBodyControl.class).setKinematic(false);
+
+ // Add a physics sphere to the world using the collision shape from sphere one
+ Node physicsSphere2 = PhysicsTestHelper.createPhysicsTestNode(assetManager, new SphereCollisionShape(1), 1);
+ physicsSphere2.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(5, 6, 0));
+ rootNode.attachChild(physicsSphere2);
+
+ //Adding the rigid body to physics space
+ getPhysicsSpace().add(physicsSphere2);
+ //making it kinematic
+ physicsSphere2.getControl(RigidBodyControl.class).setKinematic(false);
+ //Making it not kinematic again, it works properly, the rigidbody is affected by grvity.
+ physicsSphere2.getControl(RigidBodyControl.class).setKinematic(false);
+
+
+
+ // an obstacle mesh, does not move (mass=0)
+ Node node2 = PhysicsTestHelper.createPhysicsTestNode(assetManager, new MeshCollisionShape(new Sphere(16, 16, 1.2f)), 0);
+ node2.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(2.5f, -4, 0f));
+ rootNode.attachChild(node2);
+ getPhysicsSpace().add(node2);
+
+ // the floor mesh, does not move (mass=0)
+ Node node3 = PhysicsTestHelper.createPhysicsTestNode(assetManager, new PlaneCollisionShape(new Plane(new Vector3f(0, 1, 0), 0)), 0);
+ node3.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(0f, -6, 0f));
+ rootNode.attachChild(node3);
+ getPhysicsSpace().add(node3);
+
+ }
+
+ private PhysicsSpace getPhysicsSpace() {
+ return bulletAppState.getPhysicsSpace();
+ }
+}
diff --git a/JmeTests/src/jme3test/bullet/TestLocalPhysics.java b/JmeTests/src/jme3test/bullet/TestLocalPhysics.java
new file mode 100644
index 0000000..3835b1c
--- /dev/null
+++ b/JmeTests/src/jme3test/bullet/TestLocalPhysics.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.bullet;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.bullet.BulletAppState;
+import com.jme3.bullet.PhysicsSpace;
+import com.jme3.bullet.collision.shapes.*;
+import com.jme3.bullet.control.RigidBodyControl;
+import com.jme3.math.Plane;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Node;
+import com.jme3.scene.shape.Sphere;
+
+/**
+ * This is a basic Test of jbullet-jme functions
+ *
+ * @author normenhansen
+ */
+public class TestLocalPhysics extends SimpleApplication {
+
+ private BulletAppState bulletAppState;
+
+ public static void main(String[] args) {
+ TestLocalPhysics app = new TestLocalPhysics();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ bulletAppState = new BulletAppState();
+ stateManager.attach(bulletAppState);
+ bulletAppState.setDebugEnabled(true);
+
+ // Add a physics sphere to the world
+ Node physicsSphere = PhysicsTestHelper.createPhysicsTestNode(assetManager, new SphereCollisionShape(1), 1);
+ physicsSphere.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(3, 6, 0));
+ physicsSphere.getControl(RigidBodyControl.class).setApplyPhysicsLocal(true);
+ rootNode.attachChild(physicsSphere);
+ getPhysicsSpace().add(physicsSphere);
+
+ // Add a physics sphere to the world using the collision shape from sphere one
+ Node physicsSphere2 = PhysicsTestHelper.createPhysicsTestNode(assetManager, physicsSphere.getControl(RigidBodyControl.class).getCollisionShape(), 1);
+ physicsSphere2.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(4, 8, 0));
+ physicsSphere2.getControl(RigidBodyControl.class).setApplyPhysicsLocal(true);
+ rootNode.attachChild(physicsSphere2);
+ getPhysicsSpace().add(physicsSphere2);
+
+ // Add a physics box to the world
+ Node physicsBox = PhysicsTestHelper.createPhysicsTestNode(assetManager, new BoxCollisionShape(new Vector3f(1, 1, 1)), 1);
+ physicsBox.getControl(RigidBodyControl.class).setFriction(0.1f);
+ physicsBox.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(.6f, 4, .5f));
+ physicsBox.getControl(RigidBodyControl.class).setApplyPhysicsLocal(true);
+ rootNode.attachChild(physicsBox);
+ getPhysicsSpace().add(physicsBox);
+
+ // Add a physics cylinder to the world
+ Node physicsCylinder = PhysicsTestHelper.createPhysicsTestNode(assetManager, new CylinderCollisionShape(new Vector3f(1f, 1f, 1.5f)), 1);
+ physicsCylinder.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(2, 2, 0));
+ physicsCylinder.getControl(RigidBodyControl.class).setApplyPhysicsLocal(true);
+ rootNode.attachChild(physicsCylinder);
+ getPhysicsSpace().add(physicsCylinder);
+
+ // an obstacle mesh, does not move (mass=0)
+ Node node2 = PhysicsTestHelper.createPhysicsTestNode(assetManager, new MeshCollisionShape(new Sphere(16, 16, 1.2f)), 0);
+ node2.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(2.5f, -4, 0f));
+ node2.getControl(RigidBodyControl.class).setApplyPhysicsLocal(true);
+ rootNode.attachChild(node2);
+ getPhysicsSpace().add(node2);
+
+ // the floor mesh, does not move (mass=0)
+ Node node3 = PhysicsTestHelper.createPhysicsTestNode(assetManager, new PlaneCollisionShape(new Plane(new Vector3f(0, 1, 0), 0)), 0);
+ node3.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(0f, -6, 0f));
+ node3.getControl(RigidBodyControl.class).setApplyPhysicsLocal(true);
+ rootNode.attachChild(node3);
+ getPhysicsSpace().add(node3);
+
+ // Join the physics objects with a Point2Point joint
+// PhysicsPoint2PointJoint joint=new PhysicsPoint2PointJoint(physicsSphere, physicsBox, new Vector3f(-2,0,0), new Vector3f(2,0,0));
+// PhysicsHingeJoint joint=new PhysicsHingeJoint(physicsSphere, physicsBox, new Vector3f(-2,0,0), new Vector3f(2,0,0), Vector3f.UNIT_Z,Vector3f.UNIT_Z);
+// getPhysicsSpace().add(joint);
+
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ rootNode.rotate(tpf, 0, 0);
+ }
+
+ private PhysicsSpace getPhysicsSpace() {
+ return bulletAppState.getPhysicsSpace();
+ }
+}
diff --git a/JmeTests/src/jme3test/bullet/TestPhysicsCar.java b/JmeTests/src/jme3test/bullet/TestPhysicsCar.java
new file mode 100644
index 0000000..4ba4e06
--- /dev/null
+++ b/JmeTests/src/jme3test/bullet/TestPhysicsCar.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.bullet;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.bullet.BulletAppState;
+import com.jme3.bullet.PhysicsSpace;
+import com.jme3.bullet.collision.shapes.BoxCollisionShape;
+import com.jme3.bullet.collision.shapes.CompoundCollisionShape;
+import com.jme3.bullet.control.VehicleControl;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Matrix3f;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.shape.Cylinder;
+
+public class TestPhysicsCar extends SimpleApplication implements ActionListener {
+
+ private BulletAppState bulletAppState;
+ private VehicleControl vehicle;
+ private final float accelerationForce = 1000.0f;
+ private final float brakeForce = 100.0f;
+ private float steeringValue = 0;
+ private float accelerationValue = 0;
+ private Vector3f jumpForce = new Vector3f(0, 3000, 0);
+
+ public static void main(String[] args) {
+ TestPhysicsCar app = new TestPhysicsCar();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ bulletAppState = new BulletAppState();
+ stateManager.attach(bulletAppState);
+ bulletAppState.setDebugEnabled(true);
+ PhysicsTestHelper.createPhysicsTestWorld(rootNode, assetManager, bulletAppState.getPhysicsSpace());
+ setupKeys();
+ buildPlayer();
+ }
+
+ private PhysicsSpace getPhysicsSpace(){
+ return bulletAppState.getPhysicsSpace();
+ }
+
+ private void setupKeys() {
+ inputManager.addMapping("Lefts", new KeyTrigger(KeyInput.KEY_H));
+ inputManager.addMapping("Rights", new KeyTrigger(KeyInput.KEY_K));
+ inputManager.addMapping("Ups", new KeyTrigger(KeyInput.KEY_U));
+ inputManager.addMapping("Downs", new KeyTrigger(KeyInput.KEY_J));
+ inputManager.addMapping("Space", new KeyTrigger(KeyInput.KEY_SPACE));
+ inputManager.addMapping("Reset", new KeyTrigger(KeyInput.KEY_RETURN));
+ inputManager.addListener(this, "Lefts");
+ inputManager.addListener(this, "Rights");
+ inputManager.addListener(this, "Ups");
+ inputManager.addListener(this, "Downs");
+ inputManager.addListener(this, "Space");
+ inputManager.addListener(this, "Reset");
+ }
+
+ private void buildPlayer() {
+ Material mat = new Material(getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
+ mat.getAdditionalRenderState().setWireframe(true);
+ mat.setColor("Color", ColorRGBA.Red);
+
+ //create a compound shape and attach the BoxCollisionShape for the car body at 0,1,0
+ //this shifts the effective center of mass of the BoxCollisionShape to 0,-1,0
+ CompoundCollisionShape compoundShape = new CompoundCollisionShape();
+ BoxCollisionShape box = new BoxCollisionShape(new Vector3f(1.2f, 0.5f, 2.4f));
+ compoundShape.addChildShape(box, new Vector3f(0, 1, 0));
+
+ //create vehicle node
+ Node vehicleNode=new Node("vehicleNode");
+ vehicle = new VehicleControl(compoundShape, 400);
+ vehicleNode.addControl(vehicle);
+
+ //setting suspension values for wheels, this can be a bit tricky
+ //see also https://docs.google.com/Doc?docid=0AXVUZ5xw6XpKZGNuZG56a3FfMzU0Z2NyZnF4Zmo&hl=en
+ float stiffness = 60.0f;//200=f1 car
+ float compValue = .3f; //(should be lower than damp)
+ float dampValue = .4f;
+ vehicle.setSuspensionCompression(compValue * 2.0f * FastMath.sqrt(stiffness));
+ vehicle.setSuspensionDamping(dampValue * 2.0f * FastMath.sqrt(stiffness));
+ vehicle.setSuspensionStiffness(stiffness);
+ vehicle.setMaxSuspensionForce(10000.0f);
+
+ //Create four wheels and add them at their locations
+ Vector3f wheelDirection = new Vector3f(0, -1, 0); // was 0, -1, 0
+ Vector3f wheelAxle = new Vector3f(-1, 0, 0); // was -1, 0, 0
+ float radius = 0.5f;
+ float restLength = 0.3f;
+ float yOff = 0.5f;
+ float xOff = 1f;
+ float zOff = 2f;
+
+ Cylinder wheelMesh = new Cylinder(16, 16, radius, radius * 0.6f, true);
+
+ Node node1 = new Node("wheel 1 node");
+ Geometry wheels1 = new Geometry("wheel 1", wheelMesh);
+ node1.attachChild(wheels1);
+ wheels1.rotate(0, FastMath.HALF_PI, 0);
+ wheels1.setMaterial(mat);
+ vehicle.addWheel(node1, new Vector3f(-xOff, yOff, zOff),
+ wheelDirection, wheelAxle, restLength, radius, true);
+
+ Node node2 = new Node("wheel 2 node");
+ Geometry wheels2 = new Geometry("wheel 2", wheelMesh);
+ node2.attachChild(wheels2);
+ wheels2.rotate(0, FastMath.HALF_PI, 0);
+ wheels2.setMaterial(mat);
+ vehicle.addWheel(node2, new Vector3f(xOff, yOff, zOff),
+ wheelDirection, wheelAxle, restLength, radius, true);
+
+ Node node3 = new Node("wheel 3 node");
+ Geometry wheels3 = new Geometry("wheel 3", wheelMesh);
+ node3.attachChild(wheels3);
+ wheels3.rotate(0, FastMath.HALF_PI, 0);
+ wheels3.setMaterial(mat);
+ vehicle.addWheel(node3, new Vector3f(-xOff, yOff, -zOff),
+ wheelDirection, wheelAxle, restLength, radius, false);
+
+ Node node4 = new Node("wheel 4 node");
+ Geometry wheels4 = new Geometry("wheel 4", wheelMesh);
+ node4.attachChild(wheels4);
+ wheels4.rotate(0, FastMath.HALF_PI, 0);
+ wheels4.setMaterial(mat);
+ vehicle.addWheel(node4, new Vector3f(xOff, yOff, -zOff),
+ wheelDirection, wheelAxle, restLength, radius, false);
+
+ vehicleNode.attachChild(node1);
+ vehicleNode.attachChild(node2);
+ vehicleNode.attachChild(node3);
+ vehicleNode.attachChild(node4);
+ rootNode.attachChild(vehicleNode);
+
+ getPhysicsSpace().add(vehicle);
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ cam.lookAt(vehicle.getPhysicsLocation(), Vector3f.UNIT_Y);
+ }
+
+ public void onAction(String binding, boolean value, float tpf) {
+ if (binding.equals("Lefts")) {
+ if (value) {
+ steeringValue += .5f;
+ } else {
+ steeringValue += -.5f;
+ }
+ vehicle.steer(steeringValue);
+ } else if (binding.equals("Rights")) {
+ if (value) {
+ steeringValue += -.5f;
+ } else {
+ steeringValue += .5f;
+ }
+ vehicle.steer(steeringValue);
+ } else if (binding.equals("Ups")) {
+ if (value) {
+ accelerationValue += accelerationForce;
+ } else {
+ accelerationValue -= accelerationForce;
+ }
+ vehicle.accelerate(accelerationValue);
+ } else if (binding.equals("Downs")) {
+ if (value) {
+ vehicle.brake(brakeForce);
+ } else {
+ vehicle.brake(0f);
+ }
+ } else if (binding.equals("Space")) {
+ if (value) {
+ vehicle.applyImpulse(jumpForce, Vector3f.ZERO);
+ }
+ } else if (binding.equals("Reset")) {
+ if (value) {
+ System.out.println("Reset");
+ vehicle.setPhysicsLocation(Vector3f.ZERO);
+ vehicle.setPhysicsRotation(new Matrix3f());
+ vehicle.setLinearVelocity(Vector3f.ZERO);
+ vehicle.setAngularVelocity(Vector3f.ZERO);
+ vehicle.resetSuspension();
+ } else {
+ }
+ }
+ }
+}
diff --git a/JmeTests/src/jme3test/bullet/TestPhysicsCharacter.java b/JmeTests/src/jme3test/bullet/TestPhysicsCharacter.java
new file mode 100644
index 0000000..420a5a4
--- /dev/null
+++ b/JmeTests/src/jme3test/bullet/TestPhysicsCharacter.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer. * Redistributions
+ * in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution. * Neither the name of
+ * 'jMonkeyEngine' nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior written
+ * permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
+ * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.bullet;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.bullet.BulletAppState;
+import com.jme3.bullet.PhysicsSpace;
+import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
+import com.jme3.bullet.control.CharacterControl;
+import com.jme3.input.KeyInput;
+import com.jme3.input.MouseInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.input.controls.MouseButtonTrigger;
+import com.jme3.math.Vector3f;
+import com.jme3.renderer.RenderManager;
+import com.jme3.scene.CameraNode;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.control.CameraControl.ControlDirection;
+
+/**
+ * A walking physical character followed by a 3rd person camera. (No animation.)
+ * @author normenhansen, zathras
+ */
+public class TestPhysicsCharacter extends SimpleApplication implements ActionListener {
+
+ private BulletAppState bulletAppState;
+ private CharacterControl physicsCharacter;
+ private Node characterNode;
+ private CameraNode camNode;
+ boolean rotate = false;
+ private Vector3f walkDirection = new Vector3f(0,0,0);
+ private Vector3f viewDirection = new Vector3f(0,0,0);
+ boolean leftStrafe = false, rightStrafe = false, forward = false, backward = false,
+ leftRotate = false, rightRotate = false;
+
+ public static void main(String[] args) {
+ TestPhysicsCharacter app = new TestPhysicsCharacter();
+ app.start();
+ }
+
+ private void setupKeys() {
+ inputManager.addMapping("Strafe Left",
+ new KeyTrigger(KeyInput.KEY_Q),
+ new KeyTrigger(KeyInput.KEY_Z));
+ inputManager.addMapping("Strafe Right",
+ new KeyTrigger(KeyInput.KEY_E),
+ new KeyTrigger(KeyInput.KEY_X));
+ inputManager.addMapping("Rotate Left",
+ new KeyTrigger(KeyInput.KEY_A),
+ new KeyTrigger(KeyInput.KEY_LEFT));
+ inputManager.addMapping("Rotate Right",
+ new KeyTrigger(KeyInput.KEY_D),
+ new KeyTrigger(KeyInput.KEY_RIGHT));
+ inputManager.addMapping("Walk Forward",
+ new KeyTrigger(KeyInput.KEY_W),
+ new KeyTrigger(KeyInput.KEY_UP));
+ inputManager.addMapping("Walk Backward",
+ new KeyTrigger(KeyInput.KEY_S),
+ new KeyTrigger(KeyInput.KEY_DOWN));
+ inputManager.addMapping("Jump",
+ new KeyTrigger(KeyInput.KEY_SPACE),
+ new KeyTrigger(KeyInput.KEY_RETURN));
+ inputManager.addMapping("Shoot",
+ new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
+ inputManager.addListener(this, "Strafe Left", "Strafe Right");
+ inputManager.addListener(this, "Rotate Left", "Rotate Right");
+ inputManager.addListener(this, "Walk Forward", "Walk Backward");
+ inputManager.addListener(this, "Jump", "Shoot");
+ }
+ @Override
+ public void simpleInitApp() {
+ // activate physics
+ bulletAppState = new BulletAppState();
+ stateManager.attach(bulletAppState);
+
+ // init a physical test scene
+ PhysicsTestHelper.createPhysicsTestWorldSoccer(rootNode, assetManager, bulletAppState.getPhysicsSpace());
+ setupKeys();
+
+ // Add a physics character to the world
+ physicsCharacter = new CharacterControl(new CapsuleCollisionShape(0.5f, 1.8f), .1f);
+ physicsCharacter.setPhysicsLocation(new Vector3f(0, 1, 0));
+ characterNode = new Node("character node");
+ Spatial model = assetManager.loadModel("Models/Sinbad/Sinbad.mesh.xml");
+ model.scale(0.25f);
+ characterNode.addControl(physicsCharacter);
+ getPhysicsSpace().add(physicsCharacter);
+ rootNode.attachChild(characterNode);
+ characterNode.attachChild(model);
+
+ // set forward camera node that follows the character
+ camNode = new CameraNode("CamNode", cam);
+ camNode.setControlDir(ControlDirection.SpatialToCamera);
+ camNode.setLocalTranslation(new Vector3f(0, 1, -5));
+ camNode.lookAt(model.getLocalTranslation(), Vector3f.UNIT_Y);
+ characterNode.attachChild(camNode);
+
+ //disable the default 1st-person flyCam (don't forget this!!)
+ flyCam.setEnabled(false);
+
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ Vector3f camDir = cam.getDirection().mult(0.2f);
+ Vector3f camLeft = cam.getLeft().mult(0.2f);
+ camDir.y = 0;
+ camLeft.y = 0;
+ viewDirection.set(camDir);
+ walkDirection.set(0, 0, 0);
+ if (leftStrafe) {
+ walkDirection.addLocal(camLeft);
+ } else
+ if (rightStrafe) {
+ walkDirection.addLocal(camLeft.negate());
+ }
+ if (leftRotate) {
+ viewDirection.addLocal(camLeft.mult(0.02f));
+ } else
+ if (rightRotate) {
+ viewDirection.addLocal(camLeft.mult(0.02f).negate());
+ }
+ if (forward) {
+ walkDirection.addLocal(camDir);
+ } else
+ if (backward) {
+ walkDirection.addLocal(camDir.negate());
+ }
+ physicsCharacter.setWalkDirection(walkDirection);
+ physicsCharacter.setViewDirection(viewDirection);
+ }
+
+ public void onAction(String binding, boolean value, float tpf) {
+ if (binding.equals("Strafe Left")) {
+ if (value) {
+ leftStrafe = true;
+ } else {
+ leftStrafe = false;
+ }
+ } else if (binding.equals("Strafe Right")) {
+ if (value) {
+ rightStrafe = true;
+ } else {
+ rightStrafe = false;
+ }
+ } else if (binding.equals("Rotate Left")) {
+ if (value) {
+ leftRotate = true;
+ } else {
+ leftRotate = false;
+ }
+ } else if (binding.equals("Rotate Right")) {
+ if (value) {
+ rightRotate = true;
+ } else {
+ rightRotate = false;
+ }
+ } else if (binding.equals("Walk Forward")) {
+ if (value) {
+ forward = true;
+ } else {
+ forward = false;
+ }
+ } else if (binding.equals("Walk Backward")) {
+ if (value) {
+ backward = true;
+ } else {
+ backward = false;
+ }
+ } else if (binding.equals("Jump")) {
+ physicsCharacter.jump();
+ }
+ }
+
+ private PhysicsSpace getPhysicsSpace() {
+ return bulletAppState.getPhysicsSpace();
+ }
+
+ @Override
+ public void simpleRender(RenderManager rm) {
+ //TODO: add render code
+ }
+}
diff --git a/JmeTests/src/jme3test/bullet/TestPhysicsHingeJoint.java b/JmeTests/src/jme3test/bullet/TestPhysicsHingeJoint.java
new file mode 100644
index 0000000..029892a
--- /dev/null
+++ b/JmeTests/src/jme3test/bullet/TestPhysicsHingeJoint.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.bullet;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.bullet.BulletAppState;
+import com.jme3.bullet.PhysicsSpace;
+import com.jme3.bullet.collision.shapes.BoxCollisionShape;
+import com.jme3.bullet.control.RigidBodyControl;
+import com.jme3.bullet.joints.HingeJoint;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.AnalogListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Node;
+
+public class TestPhysicsHingeJoint extends SimpleApplication implements AnalogListener {
+ private BulletAppState bulletAppState;
+ private HingeJoint joint;
+
+ public static void main(String[] args) {
+ TestPhysicsHingeJoint app = new TestPhysicsHingeJoint();
+ app.start();
+ }
+
+ private void setupKeys() {
+ inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_H));
+ inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_K));
+ inputManager.addMapping("Swing", new KeyTrigger(KeyInput.KEY_SPACE));
+ inputManager.addListener(this, "Left", "Right", "Swing");
+ }
+
+ public void onAnalog(String binding, float value, float tpf) {
+ if(binding.equals("Left")){
+ joint.enableMotor(true, 1, .1f);
+ }
+ else if(binding.equals("Right")){
+ joint.enableMotor(true, -1, .1f);
+ }
+ else if(binding.equals("Swing")){
+ joint.enableMotor(false, 0, 0);
+ }
+ }
+
+ @Override
+ public void simpleInitApp() {
+ bulletAppState = new BulletAppState();
+ stateManager.attach(bulletAppState);
+ bulletAppState.setDebugEnabled(true);
+ setupKeys();
+ setupJoint();
+ }
+
+ private PhysicsSpace getPhysicsSpace(){
+ return bulletAppState.getPhysicsSpace();
+ }
+
+ public void setupJoint() {
+ Node holderNode=PhysicsTestHelper.createPhysicsTestNode(assetManager, new BoxCollisionShape(new Vector3f( .1f, .1f, .1f)),0);
+ holderNode.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(0f,0,0f));
+ rootNode.attachChild(holderNode);
+ getPhysicsSpace().add(holderNode);
+
+ Node hammerNode=PhysicsTestHelper.createPhysicsTestNode(assetManager, new BoxCollisionShape(new Vector3f( .3f, .3f, .3f)),1);
+ hammerNode.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(0f,-1,0f));
+ rootNode.attachChild(hammerNode);
+ getPhysicsSpace().add(hammerNode);
+
+ joint=new HingeJoint(holderNode.getControl(RigidBodyControl.class), hammerNode.getControl(RigidBodyControl.class), Vector3f.ZERO, new Vector3f(0f,-1,0f), Vector3f.UNIT_Z, Vector3f.UNIT_Z);
+ getPhysicsSpace().add(joint);
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/JmeTests/src/jme3test/bullet/TestPhysicsRayCast.java b/JmeTests/src/jme3test/bullet/TestPhysicsRayCast.java
new file mode 100644
index 0000000..24665b4
--- /dev/null
+++ b/JmeTests/src/jme3test/bullet/TestPhysicsRayCast.java
@@ -0,0 +1,69 @@
+package jme3test.bullet;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.bullet.BulletAppState;
+import com.jme3.bullet.collision.PhysicsCollisionObject;
+import com.jme3.bullet.collision.PhysicsRayTestResult;
+import com.jme3.bullet.collision.shapes.CollisionShape;
+import com.jme3.bullet.control.RigidBodyControl;
+import com.jme3.bullet.util.CollisionShapeFactory;
+import com.jme3.font.BitmapText;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import java.util.List;
+
+/**
+ *
+ * @author @wezrule
+ */
+public class TestPhysicsRayCast extends SimpleApplication {
+
+ private BulletAppState bulletAppState = new BulletAppState();
+
+ public static void main(String[] args) {
+ new TestPhysicsRayCast().start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ stateManager.attach(bulletAppState);
+ initCrossHair();
+
+ Spatial s = assetManager.loadModel("Models/Elephant/Elephant.mesh.xml");
+ s.setLocalScale(0.1f);
+
+ CollisionShape collisionShape = CollisionShapeFactory.createMeshShape(s);
+ Node n = new Node("elephant");
+ n.addControl(new RigidBodyControl(collisionShape, 1));
+ n.getControl(RigidBodyControl.class).setKinematic(true);
+ bulletAppState.getPhysicsSpace().add(n);
+ rootNode.attachChild(n);
+ bulletAppState.setDebugEnabled(true);
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ float rayLength = 50f;
+ Vector3f start = cam.getLocation();
+ Vector3f end = cam.getDirection().scaleAdd(rayLength, start);
+ List rayTest
+ = bulletAppState.getPhysicsSpace().rayTest(start, end);
+ if (rayTest.size() > 0) {
+ PhysicsRayTestResult get = rayTest.get(0);
+ PhysicsCollisionObject collisionObject = get.getCollisionObject();
+ // Display the name of the 1st object in place of FPS.
+ fpsText.setText(collisionObject.getUserObject().toString());
+ } else {
+ // Provide prompt feedback that no collision object was hit.
+ fpsText.setText("MISSING");
+ }
+ }
+
+ private void initCrossHair() {
+ BitmapText bitmapText = new BitmapText(guiFont);
+ bitmapText.setText("+");
+ bitmapText.setLocalTranslation((settings.getWidth() - bitmapText.getLineWidth())*0.5f, (settings.getHeight() + bitmapText.getLineHeight())*0.5f, 0);
+ guiNode.attachChild(bitmapText);
+ }
+}
diff --git a/JmeTests/src/jme3test/bullet/TestPhysicsReadWrite.java b/JmeTests/src/jme3test/bullet/TestPhysicsReadWrite.java
new file mode 100644
index 0000000..7d94e05
--- /dev/null
+++ b/JmeTests/src/jme3test/bullet/TestPhysicsReadWrite.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.bullet;
+
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.bullet.BulletAppState;
+import com.jme3.bullet.PhysicsSpace;
+import com.jme3.bullet.collision.shapes.*;
+import com.jme3.bullet.control.RigidBodyControl;
+import com.jme3.bullet.joints.HingeJoint;
+import com.jme3.export.binary.BinaryExporter;
+import com.jme3.export.binary.BinaryImporter;
+import com.jme3.math.Plane;
+import com.jme3.math.Vector3f;
+import com.jme3.renderer.RenderManager;
+import com.jme3.scene.Node;
+import com.jme3.scene.shape.Sphere;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * This is a basic Test of jbullet-jme functions
+ *
+ * @author normenhansen
+ */
+public class TestPhysicsReadWrite extends SimpleApplication{
+ private BulletAppState bulletAppState;
+ private Node physicsRootNode;
+ public static void main(String[] args){
+ TestPhysicsReadWrite app = new TestPhysicsReadWrite();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ bulletAppState = new BulletAppState();
+ stateManager.attach(bulletAppState);
+ bulletAppState.setDebugEnabled(true);
+ physicsRootNode=new Node("PhysicsRootNode");
+ rootNode.attachChild(physicsRootNode);
+
+ // Add a physics sphere to the world
+ Node physicsSphere = PhysicsTestHelper.createPhysicsTestNode(assetManager, new SphereCollisionShape(1), 1);
+ physicsSphere.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(3, 6, 0));
+ rootNode.attachChild(physicsSphere);
+ getPhysicsSpace().add(physicsSphere);
+
+ // Add a physics sphere to the world using the collision shape from sphere one
+ Node physicsSphere2 = PhysicsTestHelper.createPhysicsTestNode(assetManager, physicsSphere.getControl(RigidBodyControl.class).getCollisionShape(), 1);
+ physicsSphere2.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(4, 8, 0));
+ rootNode.attachChild(physicsSphere2);
+ getPhysicsSpace().add(physicsSphere2);
+
+ // Add a physics box to the world
+ Node physicsBox = PhysicsTestHelper.createPhysicsTestNode(assetManager, new BoxCollisionShape(new Vector3f(1, 1, 1)), 1);
+ physicsBox.getControl(RigidBodyControl.class).setFriction(0.1f);
+ physicsBox.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(.6f, 4, .5f));
+ rootNode.attachChild(physicsBox);
+ getPhysicsSpace().add(physicsBox);
+
+ // Add a physics cylinder to the world
+ Node physicsCylinder = PhysicsTestHelper.createPhysicsTestNode(assetManager, new CylinderCollisionShape(new Vector3f(1f, 1f, 1.5f)), 1);
+ physicsCylinder.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(2, 2, 0));
+ rootNode.attachChild(physicsCylinder);
+ getPhysicsSpace().add(physicsCylinder);
+
+ // an obstacle mesh, does not move (mass=0)
+ Node node2 = PhysicsTestHelper.createPhysicsTestNode(assetManager, new MeshCollisionShape(new Sphere(16, 16, 1.2f)), 0);
+ node2.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(2.5f, -4, 0f));
+ rootNode.attachChild(node2);
+ getPhysicsSpace().add(node2);
+
+ // the floor mesh, does not move (mass=0)
+ Node node3 = PhysicsTestHelper.createPhysicsTestNode(assetManager, new PlaneCollisionShape(new Plane(new Vector3f(0, 1, 0), 0)), 0);
+ node3.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(0f, -6, 0f));
+ rootNode.attachChild(node3);
+ getPhysicsSpace().add(node3);
+
+ // Join the physics objects with a Point2Point joint
+ HingeJoint joint=new HingeJoint(physicsSphere.getControl(RigidBodyControl.class), physicsBox.getControl(RigidBodyControl.class), new Vector3f(-2,0,0), new Vector3f(2,0,0), Vector3f.UNIT_Z,Vector3f.UNIT_Z);
+ getPhysicsSpace().add(joint);
+
+ //save and load the physicsRootNode
+ try {
+ //remove all physics objects from physics space
+ getPhysicsSpace().removeAll(physicsRootNode);
+ physicsRootNode.removeFromParent();
+ //export to byte array
+ ByteArrayOutputStream bout=new ByteArrayOutputStream();
+ BinaryExporter.getInstance().save(physicsRootNode, bout);
+ //import from byte array
+ ByteArrayInputStream bin=new ByteArrayInputStream(bout.toByteArray());
+ BinaryImporter imp=BinaryImporter.getInstance();
+ imp.setAssetManager(assetManager);
+ Node newPhysicsRootNode=(Node)imp.load(bin);
+ //add all physics objects to physics space
+ getPhysicsSpace().addAll(newPhysicsRootNode);
+ rootNode.attachChild(newPhysicsRootNode);
+ } catch (IOException ex) {
+ Logger.getLogger(TestPhysicsReadWrite.class.getName()).log(Level.SEVERE, null, ex);
+ }
+
+ }
+
+ private PhysicsSpace getPhysicsSpace(){
+ return bulletAppState.getPhysicsSpace();
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ //TODO: add update code
+ }
+
+ @Override
+ public void simpleRender(RenderManager rm) {
+ //TODO: add render code
+ }
+
+}
diff --git a/JmeTests/src/jme3test/bullet/TestQ3.java b/JmeTests/src/jme3test/bullet/TestQ3.java
new file mode 100644
index 0000000..01d0c9a
--- /dev/null
+++ b/JmeTests/src/jme3test/bullet/TestQ3.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2009-2018 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.bullet;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.asset.plugins.HttpZipLocator;
+import com.jme3.asset.plugins.ZipLocator;
+import com.jme3.bullet.BulletAppState;
+import com.jme3.bullet.PhysicsSpace;
+import com.jme3.bullet.collision.shapes.SphereCollisionShape;
+import com.jme3.bullet.control.RigidBodyControl;
+import com.jme3.bullet.objects.PhysicsCharacter;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.light.AmbientLight;
+import com.jme3.light.DirectionalLight;
+import com.jme3.material.MaterialList;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Node;
+import com.jme3.scene.plugins.ogre.OgreMeshKey;
+import java.io.File;
+
+public class TestQ3 extends SimpleApplication implements ActionListener {
+
+ private BulletAppState bulletAppState;
+ private Node gameLevel;
+ private PhysicsCharacter player;
+ private Vector3f walkDirection = new Vector3f();
+ private static boolean useHttp = false;
+ private boolean left=false,right=false,up=false,down=false;
+
+ public static void main(String[] args) {
+ File file = new File("quake3level.zip");
+ if (!file.exists()) {
+ useHttp = true;
+ }
+ TestQ3 app = new TestQ3();
+ app.start();
+ }
+
+ public void simpleInitApp() {
+ bulletAppState = new BulletAppState();
+ stateManager.attach(bulletAppState);
+ flyCam.setMoveSpeed(100);
+ setupKeys();
+
+ this.cam.setFrustumFar(2000);
+
+ DirectionalLight dl = new DirectionalLight();
+ dl.setColor(ColorRGBA.White.clone().multLocal(2));
+ dl.setDirection(new Vector3f(-1, -1, -1).normalize());
+ rootNode.addLight(dl);
+
+ AmbientLight am = new AmbientLight();
+ am.setColor(ColorRGBA.White.mult(2));
+ rootNode.addLight(am);
+
+ // load the level from zip or http zip
+ if (useHttp) {
+ assetManager.registerLocator(
+ "https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/jmonkeyengine/quake3level.zip",
+ HttpZipLocator.class);
+ } else {
+ assetManager.registerLocator("quake3level.zip", ZipLocator.class);
+ }
+
+ // create the geometry and attach it
+ MaterialList matList = (MaterialList) assetManager.loadAsset("Scene.material");
+ OgreMeshKey key = new OgreMeshKey("main.meshxml", matList);
+ gameLevel = (Node) assetManager.loadAsset(key);
+ gameLevel.setLocalScale(0.1f);
+
+ // add a physics control, it will generate a MeshCollisionShape based on the gameLevel
+ gameLevel.addControl(new RigidBodyControl(0));
+
+ player = new PhysicsCharacter(new SphereCollisionShape(5), .01f);
+ player.setJumpSpeed(20);
+ player.setFallSpeed(30);
+ player.setGravity(30);
+
+ player.setPhysicsLocation(new Vector3f(60, 10, -60));
+
+ rootNode.attachChild(gameLevel);
+
+ getPhysicsSpace().addAll(gameLevel);
+ getPhysicsSpace().add(player);
+ }
+
+ private PhysicsSpace getPhysicsSpace(){
+ return bulletAppState.getPhysicsSpace();
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ Vector3f camDir = cam.getDirection().clone().multLocal(0.6f);
+ Vector3f camLeft = cam.getLeft().clone().multLocal(0.4f);
+ walkDirection.set(0,0,0);
+ if(left)
+ walkDirection.addLocal(camLeft);
+ if(right)
+ walkDirection.addLocal(camLeft.negate());
+ if(up)
+ walkDirection.addLocal(camDir);
+ if(down)
+ walkDirection.addLocal(camDir.negate());
+ player.setWalkDirection(walkDirection);
+ cam.setLocation(player.getPhysicsLocation());
+ }
+
+ private void setupKeys() {
+ inputManager.addMapping("Lefts", new KeyTrigger(KeyInput.KEY_A));
+ inputManager.addMapping("Rights", new KeyTrigger(KeyInput.KEY_D));
+ inputManager.addMapping("Ups", new KeyTrigger(KeyInput.KEY_W));
+ inputManager.addMapping("Downs", new KeyTrigger(KeyInput.KEY_S));
+ inputManager.addMapping("Space", new KeyTrigger(KeyInput.KEY_SPACE));
+ inputManager.addListener(this,"Lefts");
+ inputManager.addListener(this,"Rights");
+ inputManager.addListener(this,"Ups");
+ inputManager.addListener(this,"Downs");
+ inputManager.addListener(this,"Space");
+ }
+
+ public void onAction(String binding, boolean value, float tpf) {
+
+ if (binding.equals("Lefts")) {
+ if(value)
+ left=true;
+ else
+ left=false;
+ } else if (binding.equals("Rights")) {
+ if(value)
+ right=true;
+ else
+ right=false;
+ } else if (binding.equals("Ups")) {
+ if(value)
+ up=true;
+ else
+ up=false;
+ } else if (binding.equals("Downs")) {
+ if(value)
+ down=true;
+ else
+ down=false;
+ } else if (binding.equals("Space")) {
+ player.jump();
+ }
+ }
+}
diff --git a/JmeTests/src/jme3test/bullet/TestRagDoll.java b/JmeTests/src/jme3test/bullet/TestRagDoll.java
new file mode 100644
index 0000000..2752ce5
--- /dev/null
+++ b/JmeTests/src/jme3test/bullet/TestRagDoll.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.bullet;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.bullet.BulletAppState;
+import com.jme3.bullet.PhysicsSpace;
+import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
+import com.jme3.bullet.control.RigidBodyControl;
+import com.jme3.bullet.joints.ConeJoint;
+import com.jme3.bullet.joints.PhysicsJoint;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.MouseButtonTrigger;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Node;
+
+/**
+ *
+ * @author normenhansen
+ */
+public class TestRagDoll extends SimpleApplication implements ActionListener {
+
+ private BulletAppState bulletAppState = new BulletAppState();
+ private Node ragDoll = new Node();
+ private Node shoulders;
+ private Vector3f upforce = new Vector3f(0, 200, 0);
+ private boolean applyForce = false;
+
+ public static void main(String[] args) {
+ TestRagDoll app = new TestRagDoll();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ bulletAppState = new BulletAppState();
+ stateManager.attach(bulletAppState);
+ bulletAppState.setDebugEnabled(true);
+ inputManager.addMapping("Pull ragdoll up", new MouseButtonTrigger(0));
+ inputManager.addListener(this, "Pull ragdoll up");
+ PhysicsTestHelper.createPhysicsTestWorld(rootNode, assetManager, bulletAppState.getPhysicsSpace());
+ createRagDoll();
+ }
+
+ private void createRagDoll() {
+ shoulders = createLimb(0.2f, 1.0f, new Vector3f(0.00f, 1.5f, 0), true);
+ Node uArmL = createLimb(0.2f, 0.5f, new Vector3f(-0.75f, 0.8f, 0), false);
+ Node uArmR = createLimb(0.2f, 0.5f, new Vector3f(0.75f, 0.8f, 0), false);
+ Node lArmL = createLimb(0.2f, 0.5f, new Vector3f(-0.75f, -0.2f, 0), false);
+ Node lArmR = createLimb(0.2f, 0.5f, new Vector3f(0.75f, -0.2f, 0), false);
+ Node body = createLimb(0.2f, 1.0f, new Vector3f(0.00f, 0.5f, 0), false);
+ Node hips = createLimb(0.2f, 0.5f, new Vector3f(0.00f, -0.5f, 0), true);
+ Node uLegL = createLimb(0.2f, 0.5f, new Vector3f(-0.25f, -1.2f, 0), false);
+ Node uLegR = createLimb(0.2f, 0.5f, new Vector3f(0.25f, -1.2f, 0), false);
+ Node lLegL = createLimb(0.2f, 0.5f, new Vector3f(-0.25f, -2.2f, 0), false);
+ Node lLegR = createLimb(0.2f, 0.5f, new Vector3f(0.25f, -2.2f, 0), false);
+
+ join(body, shoulders, new Vector3f(0f, 1.4f, 0));
+ join(body, hips, new Vector3f(0f, -0.5f, 0));
+
+ join(uArmL, shoulders, new Vector3f(-0.75f, 1.4f, 0));
+ join(uArmR, shoulders, new Vector3f(0.75f, 1.4f, 0));
+ join(uArmL, lArmL, new Vector3f(-0.75f, .4f, 0));
+ join(uArmR, lArmR, new Vector3f(0.75f, .4f, 0));
+
+ join(uLegL, hips, new Vector3f(-.25f, -0.5f, 0));
+ join(uLegR, hips, new Vector3f(.25f, -0.5f, 0));
+ join(uLegL, lLegL, new Vector3f(-.25f, -1.7f, 0));
+ join(uLegR, lLegR, new Vector3f(.25f, -1.7f, 0));
+
+ ragDoll.attachChild(shoulders);
+ ragDoll.attachChild(body);
+ ragDoll.attachChild(hips);
+ ragDoll.attachChild(uArmL);
+ ragDoll.attachChild(uArmR);
+ ragDoll.attachChild(lArmL);
+ ragDoll.attachChild(lArmR);
+ ragDoll.attachChild(uLegL);
+ ragDoll.attachChild(uLegR);
+ ragDoll.attachChild(lLegL);
+ ragDoll.attachChild(lLegR);
+
+ rootNode.attachChild(ragDoll);
+ bulletAppState.getPhysicsSpace().addAll(ragDoll);
+ }
+
+ private Node createLimb(float width, float height, Vector3f location, boolean rotate) {
+ int axis = rotate ? PhysicsSpace.AXIS_X : PhysicsSpace.AXIS_Y;
+ CapsuleCollisionShape shape = new CapsuleCollisionShape(width, height, axis);
+ Node node = new Node("Limb");
+ RigidBodyControl rigidBodyControl = new RigidBodyControl(shape, 1);
+ node.setLocalTranslation(location);
+ node.addControl(rigidBodyControl);
+ return node;
+ }
+
+ private PhysicsJoint join(Node A, Node B, Vector3f connectionPoint) {
+ Vector3f pivotA = A.worldToLocal(connectionPoint, new Vector3f());
+ Vector3f pivotB = B.worldToLocal(connectionPoint, new Vector3f());
+ ConeJoint joint = new ConeJoint(A.getControl(RigidBodyControl.class), B.getControl(RigidBodyControl.class), pivotA, pivotB);
+ joint.setLimit(1f, 1f, 0);
+ return joint;
+ }
+
+ public void onAction(String string, boolean bln, float tpf) {
+ if ("Pull ragdoll up".equals(string)) {
+ if (bln) {
+ shoulders.getControl(RigidBodyControl.class).activate();
+ applyForce = true;
+ } else {
+ applyForce = false;
+ }
+ }
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ if (applyForce) {
+ shoulders.getControl(RigidBodyControl.class).applyForce(upforce, Vector3f.ZERO);
+ }
+ }
+}
diff --git a/JmeTests/src/jme3test/bullet/TestRagdollCharacter.java b/JmeTests/src/jme3test/bullet/TestRagdollCharacter.java
new file mode 100644
index 0000000..5b9e948
--- /dev/null
+++ b/JmeTests/src/jme3test/bullet/TestRagdollCharacter.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.bullet;
+
+import com.jme3.animation.AnimChannel;
+import com.jme3.animation.AnimControl;
+import com.jme3.animation.AnimEventListener;
+import com.jme3.animation.LoopMode;
+import com.jme3.app.SimpleApplication;
+import com.jme3.asset.TextureKey;
+import com.jme3.bullet.BulletAppState;
+import com.jme3.bullet.PhysicsSpace;
+import com.jme3.bullet.control.KinematicRagdollControl;
+import com.jme3.bullet.control.RigidBodyControl;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.light.DirectionalLight;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Vector2f;
+import com.jme3.math.Vector3f;
+import com.jme3.renderer.queue.RenderQueue.ShadowMode;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.shape.Box;
+import com.jme3.texture.Texture;
+
+/**
+ * @author normenhansen
+ */
+public class TestRagdollCharacter extends SimpleApplication implements AnimEventListener, ActionListener {
+
+ BulletAppState bulletAppState;
+ Node model;
+ KinematicRagdollControl ragdoll;
+ boolean leftStrafe = false, rightStrafe = false, forward = false, backward = false,
+ leftRotate = false, rightRotate = false;
+ AnimControl animControl;
+ AnimChannel animChannel;
+
+ public static void main(String[] args) {
+ TestRagdollCharacter app = new TestRagdollCharacter();
+ app.start();
+ }
+
+ public void simpleInitApp() {
+ setupKeys();
+
+ bulletAppState = new BulletAppState();
+ bulletAppState.setEnabled(true);
+ stateManager.attach(bulletAppState);
+
+
+// bulletAppState.getPhysicsSpace().enableDebug(assetManager);
+ PhysicsTestHelper.createPhysicsTestWorld(rootNode, assetManager, bulletAppState.getPhysicsSpace());
+ initWall(2,1,1);
+ setupLight();
+
+ cam.setLocation(new Vector3f(-8,0,-4));
+ cam.lookAt(new Vector3f(4,0,-7), Vector3f.UNIT_Y);
+
+ model = (Node) assetManager.loadModel("Models/Sinbad/Sinbad.mesh.xml");
+ model.lookAt(new Vector3f(0,0,-1), Vector3f.UNIT_Y);
+ model.setLocalTranslation(4, 0, -7f);
+
+ ragdoll = new KinematicRagdollControl(0.5f);
+ model.addControl(ragdoll);
+
+ getPhysicsSpace().add(ragdoll);
+ speed = 1.3f;
+
+ rootNode.attachChild(model);
+
+
+ AnimControl control = model.getControl(AnimControl.class);
+ animChannel = control.createChannel();
+ animChannel.setAnim("IdleTop");
+ control.addListener(this);
+
+ }
+
+ private void setupLight() {
+ DirectionalLight dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(-0.1f, -0.7f, -1).normalizeLocal());
+ dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f));
+ rootNode.addLight(dl);
+ }
+
+ private PhysicsSpace getPhysicsSpace() {
+ return bulletAppState.getPhysicsSpace();
+ }
+
+ private void setupKeys() {
+ inputManager.addMapping("Rotate Left",
+ new KeyTrigger(KeyInput.KEY_H));
+ inputManager.addMapping("Rotate Right",
+ new KeyTrigger(KeyInput.KEY_K));
+ inputManager.addMapping("Walk Forward",
+ new KeyTrigger(KeyInput.KEY_U));
+ inputManager.addMapping("Walk Backward",
+ new KeyTrigger(KeyInput.KEY_J));
+ inputManager.addMapping("Slice",
+ new KeyTrigger(KeyInput.KEY_SPACE),
+ new KeyTrigger(KeyInput.KEY_RETURN));
+ inputManager.addListener(this, "Strafe Left", "Strafe Right");
+ inputManager.addListener(this, "Rotate Left", "Rotate Right");
+ inputManager.addListener(this, "Walk Forward", "Walk Backward");
+ inputManager.addListener(this, "Slice");
+ }
+
+ public void initWall(float bLength, float bWidth, float bHeight) {
+ Box brick = new Box(bLength, bHeight, bWidth);
+ brick.scaleTextureCoordinates(new Vector2f(1f, .5f));
+ Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ TextureKey key = new TextureKey("Textures/Terrain/BrickWall/BrickWall.jpg");
+ key.setGenerateMips(true);
+ Texture tex = assetManager.loadTexture(key);
+ mat2.setTexture("ColorMap", tex);
+
+ float startpt = bLength / 4;
+ float height = -5;
+ for (int j = 0; j < 15; j++) {
+ for (int i = 0; i < 4; i++) {
+ Vector3f ori = new Vector3f(i * bLength * 2 + startpt, bHeight + height, -10);
+ Geometry reBoxg = new Geometry("brick", brick);
+ reBoxg.setMaterial(mat2);
+ reBoxg.setLocalTranslation(ori);
+ //for geometry with sphere mesh the physics system automatically uses a sphere collision shape
+ reBoxg.addControl(new RigidBodyControl(1.5f));
+ reBoxg.setShadowMode(ShadowMode.CastAndReceive);
+ reBoxg.getControl(RigidBodyControl.class).setFriction(0.6f);
+ this.rootNode.attachChild(reBoxg);
+ this.getPhysicsSpace().add(reBoxg);
+ }
+ startpt = -startpt;
+ height += 2 * bHeight;
+ }
+ }
+
+ public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) {
+
+ if (channel.getAnimationName().equals("SliceHorizontal")) {
+ channel.setLoopMode(LoopMode.DontLoop);
+ channel.setAnim("IdleTop", 5);
+ channel.setLoopMode(LoopMode.Loop);
+ }
+
+ }
+
+ public void onAnimChange(AnimControl control, AnimChannel channel, String animName) {
+ }
+
+ public void onAction(String binding, boolean value, float tpf) {
+ if (binding.equals("Rotate Left")) {
+ if (value) {
+ leftRotate = true;
+ } else {
+ leftRotate = false;
+ }
+ } else if (binding.equals("Rotate Right")) {
+ if (value) {
+ rightRotate = true;
+ } else {
+ rightRotate = false;
+ }
+ } else if (binding.equals("Walk Forward")) {
+ if (value) {
+ forward = true;
+ } else {
+ forward = false;
+ }
+ } else if (binding.equals("Walk Backward")) {
+ if (value) {
+ backward = true;
+ } else {
+ backward = false;
+ }
+ } else if (binding.equals("Slice")) {
+ if (value) {
+ animChannel.setAnim("SliceHorizontal");
+ animChannel.setSpeed(0.3f);
+ }
+ }
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ if(forward){
+ model.move(model.getLocalRotation().multLocal(new Vector3f(0,0,1)).multLocal(tpf));
+ }else if(backward){
+ model.move(model.getLocalRotation().multLocal(new Vector3f(0,0,1)).multLocal(-tpf));
+ }else if(leftRotate){
+ model.rotate(0, tpf, 0);
+ }else if(rightRotate){
+ model.rotate(0, -tpf, 0);
+ }
+ fpsText.setText(cam.getLocation() + "/" + cam.getRotation());
+ }
+
+}
diff --git a/JmeTests/src/jme3test/bullet/TestSimplePhysics.java b/JmeTests/src/jme3test/bullet/TestSimplePhysics.java
new file mode 100644
index 0000000..9cf2808
--- /dev/null
+++ b/JmeTests/src/jme3test/bullet/TestSimplePhysics.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.bullet;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.bullet.BulletAppState;
+import com.jme3.bullet.PhysicsSpace;
+import com.jme3.bullet.collision.shapes.*;
+import com.jme3.bullet.control.RigidBodyControl;
+import com.jme3.math.Plane;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Node;
+import com.jme3.scene.shape.Sphere;
+
+/**
+ * This is a basic Test of jbullet-jme functions
+ *
+ * @author normenhansen
+ */
+public class TestSimplePhysics extends SimpleApplication {
+
+ private BulletAppState bulletAppState;
+
+ public static void main(String[] args) {
+ TestSimplePhysics app = new TestSimplePhysics();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ bulletAppState = new BulletAppState();
+ stateManager.attach(bulletAppState);
+ bulletAppState.setDebugEnabled(true);
+
+ // Add a physics sphere to the world
+ Node physicsSphere = PhysicsTestHelper.createPhysicsTestNode(assetManager, new SphereCollisionShape(1), 1);
+ physicsSphere.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(3, 6, 0));
+ rootNode.attachChild(physicsSphere);
+ getPhysicsSpace().add(physicsSphere);
+
+ // Add a physics sphere to the world using the collision shape from sphere one
+ Node physicsSphere2 = PhysicsTestHelper.createPhysicsTestNode(assetManager, physicsSphere.getControl(RigidBodyControl.class).getCollisionShape(), 1);
+ physicsSphere2.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(4, 8, 0));
+ rootNode.attachChild(physicsSphere2);
+ getPhysicsSpace().add(physicsSphere2);
+
+ // Add a physics box to the world
+ Node physicsBox = PhysicsTestHelper.createPhysicsTestNode(assetManager, new BoxCollisionShape(new Vector3f(1, 1, 1)), 1);
+ physicsBox.getControl(RigidBodyControl.class).setFriction(0.1f);
+ physicsBox.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(.6f, 4, .5f));
+ rootNode.attachChild(physicsBox);
+ getPhysicsSpace().add(physicsBox);
+
+ // Add a physics cylinder to the world
+ Node physicsCylinder = PhysicsTestHelper.createPhysicsTestNode(assetManager, new CylinderCollisionShape(new Vector3f(1f, 1f, 1.5f)), 1);
+ physicsCylinder.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(2, 2, 0));
+ rootNode.attachChild(physicsCylinder);
+ getPhysicsSpace().add(physicsCylinder);
+
+ // an obstacle mesh, does not move (mass=0)
+ Node node2 = PhysicsTestHelper.createPhysicsTestNode(assetManager, new MeshCollisionShape(new Sphere(16, 16, 1.2f)), 0);
+ node2.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(2.5f, -4, 0f));
+ rootNode.attachChild(node2);
+ getPhysicsSpace().add(node2);
+
+ // the floor mesh, does not move (mass=0)
+ Node node3 = PhysicsTestHelper.createPhysicsTestNode(assetManager, new PlaneCollisionShape(new Plane(new Vector3f(0, 1, 0), 0)), 0);
+ node3.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(0f, -6, 0f));
+ rootNode.attachChild(node3);
+ getPhysicsSpace().add(node3);
+
+ // Join the physics objects with a Point2Point joint
+// PhysicsPoint2PointJoint joint=new PhysicsPoint2PointJoint(physicsSphere, physicsBox, new Vector3f(-2,0,0), new Vector3f(2,0,0));
+// PhysicsHingeJoint joint=new PhysicsHingeJoint(physicsSphere, physicsBox, new Vector3f(-2,0,0), new Vector3f(2,0,0), Vector3f.UNIT_Z,Vector3f.UNIT_Z);
+// getPhysicsSpace().add(joint);
+
+ }
+
+ private PhysicsSpace getPhysicsSpace() {
+ return bulletAppState.getPhysicsSpace();
+ }
+}
diff --git a/JmeTests/src/jme3test/bullet/TestSweepTest.java b/JmeTests/src/jme3test/bullet/TestSweepTest.java
new file mode 100644
index 0000000..da9089c
--- /dev/null
+++ b/JmeTests/src/jme3test/bullet/TestSweepTest.java
@@ -0,0 +1,79 @@
+package jme3test.bullet;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.bullet.BulletAppState;
+import com.jme3.bullet.collision.PhysicsCollisionObject;
+import com.jme3.bullet.collision.PhysicsSweepTestResult;
+import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
+import com.jme3.bullet.control.RigidBodyControl;
+import com.jme3.math.Transform;
+import com.jme3.scene.Node;
+import java.util.List;
+
+/**
+ *
+ * A spatial moves and sweeps its next movement for obstacles before moving
+ * there Run this example with Vsync enabled
+ *
+ * @author
+ * @wezrule
+ */
+public class TestSweepTest extends SimpleApplication {
+
+ private BulletAppState bulletAppState = new BulletAppState();
+ private CapsuleCollisionShape obstacleCollisionShape;
+ private CapsuleCollisionShape capsuleCollisionShape;
+ private Node capsule;
+ private Node obstacle;
+ private float dist = .5f;
+
+ public static void main(String[] args) {
+ new TestSweepTest().start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ obstacleCollisionShape = new CapsuleCollisionShape(0.3f, 0.5f);
+ capsuleCollisionShape = new CapsuleCollisionShape(1f, 1f);
+
+ stateManager.attach(bulletAppState);
+
+ capsule = new Node("capsule");
+ capsule.move(-2, 0, 0);
+ capsule.addControl(new RigidBodyControl(capsuleCollisionShape, 1));
+ capsule.getControl(RigidBodyControl.class).setKinematic(true);
+ bulletAppState.getPhysicsSpace().add(capsule);
+ rootNode.attachChild(capsule);
+
+ obstacle = new Node("obstacle");
+ obstacle.move(2, 0, 0);
+ RigidBodyControl bodyControl = new RigidBodyControl(obstacleCollisionShape, 0);
+ obstacle.addControl(bodyControl);
+ bulletAppState.getPhysicsSpace().add(obstacle);
+ rootNode.attachChild(obstacle);
+
+ bulletAppState.setDebugEnabled(true);
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+
+ float move = tpf * 1;
+ boolean colliding = false;
+
+ List sweepTest = bulletAppState.getPhysicsSpace().sweepTest(capsuleCollisionShape, new Transform(capsule.getWorldTranslation()), new Transform(capsule.getWorldTranslation().add(dist, 0, 0)));
+
+ for (PhysicsSweepTestResult result : sweepTest) {
+ if (result.getCollisionObject().getCollisionShape() != capsuleCollisionShape) {
+ PhysicsCollisionObject collisionObject = result.getCollisionObject();
+ fpsText.setText("Almost colliding with " + collisionObject.getUserObject().toString());
+ colliding = true;
+ }
+ }
+
+ if (!colliding) {
+ // if the sweep is clear then move the spatial
+ capsule.move(move, 0, 0);
+ }
+ }
+}
diff --git a/JmeTests/src/jme3test/bullet/TestWalkingChar.java b/JmeTests/src/jme3test/bullet/TestWalkingChar.java
new file mode 100644
index 0000000..c2c4866
--- /dev/null
+++ b/JmeTests/src/jme3test/bullet/TestWalkingChar.java
@@ -0,0 +1,433 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.bullet;
+
+import com.jme3.animation.AnimChannel;
+import com.jme3.animation.AnimControl;
+import com.jme3.animation.AnimEventListener;
+import com.jme3.animation.LoopMode;
+import com.jme3.app.SimpleApplication;
+import com.jme3.bullet.BulletAppState;
+import com.jme3.bullet.PhysicsSpace;
+import com.jme3.bullet.collision.PhysicsCollisionEvent;
+import com.jme3.bullet.collision.PhysicsCollisionListener;
+import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
+import com.jme3.bullet.collision.shapes.SphereCollisionShape;
+import com.jme3.bullet.control.CharacterControl;
+import com.jme3.bullet.control.RigidBodyControl;
+import com.jme3.bullet.util.CollisionShapeFactory;
+import com.jme3.effect.ParticleEmitter;
+import com.jme3.effect.ParticleMesh.Type;
+import com.jme3.effect.shapes.EmitterSphereShape;
+import com.jme3.input.ChaseCamera;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.light.DirectionalLight;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Vector2f;
+import com.jme3.math.Vector3f;
+import com.jme3.post.FilterPostProcessor;
+import com.jme3.post.filters.BloomFilter;
+import com.jme3.renderer.Camera;
+import com.jme3.renderer.queue.RenderQueue.ShadowMode;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.shape.Box;
+import com.jme3.scene.shape.Sphere;
+import com.jme3.scene.shape.Sphere.TextureMode;
+import com.jme3.terrain.geomipmap.TerrainLodControl;
+import com.jme3.terrain.geomipmap.TerrainQuad;
+import com.jme3.terrain.heightmap.AbstractHeightMap;
+import com.jme3.terrain.heightmap.ImageBasedHeightMap;
+import com.jme3.texture.Texture;
+import com.jme3.texture.Texture.WrapMode;
+import com.jme3.util.SkyFactory;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A walking animated character followed by a 3rd person camera on a terrain with LOD.
+ * @author normenhansen
+ */
+public class TestWalkingChar extends SimpleApplication implements ActionListener, PhysicsCollisionListener, AnimEventListener {
+
+ private BulletAppState bulletAppState;
+ //character
+ CharacterControl character;
+ Node model;
+ //temp vectors
+ Vector3f walkDirection = new Vector3f();
+ //terrain
+ TerrainQuad terrain;
+ RigidBodyControl terrainPhysicsNode;
+ //Materials
+ Material matRock;
+ Material matBullet;
+ //animation
+ AnimChannel animationChannel;
+ AnimChannel shootingChannel;
+ AnimControl animationControl;
+ float airTime = 0;
+ //camera
+ boolean left = false, right = false, up = false, down = false;
+ ChaseCamera chaseCam;
+ //bullet
+ Sphere bullet;
+ SphereCollisionShape bulletCollisionShape;
+ //explosion
+ ParticleEmitter effect;
+ //brick wall
+ Box brick;
+ float bLength = 0.8f;
+ float bWidth = 0.4f;
+ float bHeight = 0.4f;
+ FilterPostProcessor fpp;
+
+ public static void main(String[] args) {
+ TestWalkingChar app = new TestWalkingChar();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ bulletAppState = new BulletAppState();
+ bulletAppState.setThreadingType(BulletAppState.ThreadingType.PARALLEL);
+ stateManager.attach(bulletAppState);
+ setupKeys();
+ prepareBullet();
+ prepareEffect();
+ createLight();
+ createSky();
+ createTerrain();
+ createWall();
+ createCharacter();
+ setupChaseCamera();
+ setupAnimationController();
+ setupFilter();
+ }
+
+ private void setupFilter() {
+ FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
+ BloomFilter bloom = new BloomFilter(BloomFilter.GlowMode.Objects);
+ fpp.addFilter(bloom);
+ viewPort.addProcessor(fpp);
+ }
+
+ private PhysicsSpace getPhysicsSpace() {
+ return bulletAppState.getPhysicsSpace();
+ }
+
+ private void setupKeys() {
+ inputManager.addMapping("wireframe", new KeyTrigger(KeyInput.KEY_T));
+ inputManager.addListener(this, "wireframe");
+ inputManager.addMapping("CharLeft", new KeyTrigger(KeyInput.KEY_A));
+ inputManager.addMapping("CharRight", new KeyTrigger(KeyInput.KEY_D));
+ inputManager.addMapping("CharUp", new KeyTrigger(KeyInput.KEY_W));
+ inputManager.addMapping("CharDown", new KeyTrigger(KeyInput.KEY_S));
+ inputManager.addMapping("CharSpace", new KeyTrigger(KeyInput.KEY_RETURN));
+ inputManager.addMapping("CharShoot", new KeyTrigger(KeyInput.KEY_SPACE));
+ inputManager.addListener(this, "CharLeft");
+ inputManager.addListener(this, "CharRight");
+ inputManager.addListener(this, "CharUp");
+ inputManager.addListener(this, "CharDown");
+ inputManager.addListener(this, "CharSpace");
+ inputManager.addListener(this, "CharShoot");
+ }
+
+ private void createWall() {
+ float xOff = -144;
+ float zOff = -40;
+ float startpt = bLength / 4 - xOff;
+ float height = 6.1f;
+ brick = new Box(bLength, bHeight, bWidth);
+ brick.scaleTextureCoordinates(new Vector2f(1f, .5f));
+ for (int j = 0; j < 15; j++) {
+ for (int i = 0; i < 4; i++) {
+ Vector3f vt = new Vector3f(i * bLength * 2 + startpt, bHeight + height, zOff);
+ addBrick(vt);
+ }
+ startpt = -startpt;
+ height += 1.01f * bHeight;
+ }
+ }
+
+ private void addBrick(Vector3f ori) {
+ Geometry reBoxg = new Geometry("brick", brick);
+ reBoxg.setMaterial(matBullet);
+ reBoxg.setLocalTranslation(ori);
+ reBoxg.addControl(new RigidBodyControl(1.5f));
+ reBoxg.setShadowMode(ShadowMode.CastAndReceive);
+ this.rootNode.attachChild(reBoxg);
+ this.getPhysicsSpace().add(reBoxg);
+ }
+
+ private void prepareBullet() {
+ bullet = new Sphere(32, 32, 0.4f, true, false);
+ bullet.setTextureMode(TextureMode.Projected);
+ bulletCollisionShape = new SphereCollisionShape(0.4f);
+ matBullet = new Material(getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
+ matBullet.setColor("Color", ColorRGBA.Green);
+ matBullet.setColor("GlowColor", ColorRGBA.Green);
+ getPhysicsSpace().addCollisionListener(this);
+ }
+
+ private void prepareEffect() {
+ int COUNT_FACTOR = 1;
+ float COUNT_FACTOR_F = 1f;
+ effect = new ParticleEmitter("Flame", Type.Triangle, 32 * COUNT_FACTOR);
+ effect.setSelectRandomImage(true);
+ effect.setStartColor(new ColorRGBA(1f, 0.4f, 0.05f, (float) (1f / COUNT_FACTOR_F)));
+ effect.setEndColor(new ColorRGBA(.4f, .22f, .12f, 0f));
+ effect.setStartSize(1.3f);
+ effect.setEndSize(2f);
+ effect.setShape(new EmitterSphereShape(Vector3f.ZERO, 1f));
+ effect.setParticlesPerSec(0);
+ effect.setGravity(0, -5, 0);
+ effect.setLowLife(.4f);
+ effect.setHighLife(.5f);
+ effect.getParticleInfluencer()
+ .setInitialVelocity(new Vector3f(0, 7, 0));
+ effect.getParticleInfluencer().setVelocityVariation(1f);
+ effect.setImagesX(2);
+ effect.setImagesY(2);
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
+ mat.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/flame.png"));
+ effect.setMaterial(mat);
+// effect.setLocalScale(100);
+ rootNode.attachChild(effect);
+ }
+
+ private void createLight() {
+ Vector3f direction = new Vector3f(-0.1f, -0.7f, -1).normalizeLocal();
+ DirectionalLight dl = new DirectionalLight();
+ dl.setDirection(direction);
+ dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f));
+ rootNode.addLight(dl);
+ }
+
+ private void createSky() {
+ rootNode.attachChild(SkyFactory.createSky(assetManager,
+ "Textures/Sky/Bright/BrightSky.dds",
+ SkyFactory.EnvMapType.CubeMap));
+ }
+
+ private void createTerrain() {
+ matRock = new Material(assetManager, "Common/MatDefs/Terrain/TerrainLighting.j3md");
+ matRock.setBoolean("useTriPlanarMapping", false);
+ matRock.setBoolean("WardIso", true);
+ matRock.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png"));
+ Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png");
+ Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg");
+ grass.setWrap(WrapMode.Repeat);
+ matRock.setTexture("DiffuseMap", grass);
+ matRock.setFloat("DiffuseMap_0_scale", 64);
+ Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg");
+ dirt.setWrap(WrapMode.Repeat);
+ matRock.setTexture("DiffuseMap_1", dirt);
+ matRock.setFloat("DiffuseMap_1_scale", 16);
+ Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg");
+ rock.setWrap(WrapMode.Repeat);
+ matRock.setTexture("DiffuseMap_2", rock);
+ matRock.setFloat("DiffuseMap_2_scale", 128);
+ Texture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg");
+ normalMap0.setWrap(WrapMode.Repeat);
+ Texture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png");
+ normalMap1.setWrap(WrapMode.Repeat);
+ Texture normalMap2 = assetManager.loadTexture("Textures/Terrain/splat/road_normal.png");
+ normalMap2.setWrap(WrapMode.Repeat);
+ matRock.setTexture("NormalMap", normalMap0);
+ matRock.setTexture("NormalMap_1", normalMap2);
+ matRock.setTexture("NormalMap_2", normalMap2);
+
+ AbstractHeightMap heightmap = null;
+ try {
+ heightmap = new ImageBasedHeightMap(heightMapImage.getImage(), 0.25f);
+ heightmap.load();
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ terrain = new TerrainQuad("terrain", 65, 513, heightmap.getHeightMap());
+ List cameras = new ArrayList();
+ cameras.add(getCamera());
+ TerrainLodControl control = new TerrainLodControl(terrain, cameras);
+ terrain.addControl(control);
+ terrain.setMaterial(matRock);
+ terrain.setLocalScale(new Vector3f(2, 2, 2));
+
+ terrainPhysicsNode = new RigidBodyControl(CollisionShapeFactory.createMeshShape(terrain), 0);
+ terrain.addControl(terrainPhysicsNode);
+ rootNode.attachChild(terrain);
+ getPhysicsSpace().add(terrainPhysicsNode);
+ }
+
+ private void createCharacter() {
+ CapsuleCollisionShape capsule = new CapsuleCollisionShape(3f, 4f);
+ character = new CharacterControl(capsule, 0.01f);
+ model = (Node) assetManager.loadModel("Models/Oto/Oto.mesh.xml");
+ //model.setLocalScale(0.5f);
+ model.addControl(character);
+ character.setPhysicsLocation(new Vector3f(-140, 40, -10));
+ rootNode.attachChild(model);
+ getPhysicsSpace().add(character);
+ }
+
+ private void setupChaseCamera() {
+ flyCam.setEnabled(false);
+ chaseCam = new ChaseCamera(cam, model, inputManager);
+ }
+
+ private void setupAnimationController() {
+ animationControl = model.getControl(AnimControl.class);
+ animationControl.addListener(this);
+ animationChannel = animationControl.createChannel();
+ shootingChannel = animationControl.createChannel();
+ shootingChannel.addBone(animationControl.getSkeleton().getBone("uparm.right"));
+ shootingChannel.addBone(animationControl.getSkeleton().getBone("arm.right"));
+ shootingChannel.addBone(animationControl.getSkeleton().getBone("hand.right"));
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ Vector3f camDir = cam.getDirection().clone().multLocal(0.1f);
+ Vector3f camLeft = cam.getLeft().clone().multLocal(0.1f);
+ camDir.y = 0;
+ camLeft.y = 0;
+ walkDirection.set(0, 0, 0);
+ if (left) {
+ walkDirection.addLocal(camLeft);
+ }
+ if (right) {
+ walkDirection.addLocal(camLeft.negate());
+ }
+ if (up) {
+ walkDirection.addLocal(camDir);
+ }
+ if (down) {
+ walkDirection.addLocal(camDir.negate());
+ }
+ if (!character.onGround()) {
+ airTime = airTime + tpf;
+ } else {
+ airTime = 0;
+ }
+ if (walkDirection.length() == 0) {
+ if (!"stand".equals(animationChannel.getAnimationName())) {
+ animationChannel.setAnim("stand", 1f);
+ }
+ } else {
+ character.setViewDirection(walkDirection);
+ if (airTime > .3f) {
+ if (!"stand".equals(animationChannel.getAnimationName())) {
+ animationChannel.setAnim("stand");
+ }
+ } else if (!"Walk".equals(animationChannel.getAnimationName())) {
+ animationChannel.setAnim("Walk", 0.7f);
+ }
+ }
+ character.setWalkDirection(walkDirection);
+ }
+
+ public void onAction(String binding, boolean value, float tpf) {
+ if (binding.equals("CharLeft")) {
+ if (value) {
+ left = true;
+ } else {
+ left = false;
+ }
+ } else if (binding.equals("CharRight")) {
+ if (value) {
+ right = true;
+ } else {
+ right = false;
+ }
+ } else if (binding.equals("CharUp")) {
+ if (value) {
+ up = true;
+ } else {
+ up = false;
+ }
+ } else if (binding.equals("CharDown")) {
+ if (value) {
+ down = true;
+ } else {
+ down = false;
+ }
+ } else if (binding.equals("CharSpace")) {
+ character.jump();
+ } else if (binding.equals("CharShoot") && !value) {
+ bulletControl();
+ }
+ }
+
+ private void bulletControl() {
+ shootingChannel.setAnim("Dodge", 0.1f);
+ shootingChannel.setLoopMode(LoopMode.DontLoop);
+ Geometry bulletg = new Geometry("bullet", bullet);
+ bulletg.setMaterial(matBullet);
+ bulletg.setShadowMode(ShadowMode.CastAndReceive);
+ bulletg.setLocalTranslation(character.getPhysicsLocation().add(cam.getDirection().mult(5)));
+ RigidBodyControl bulletControl = new BombControl(bulletCollisionShape, 1);
+ bulletControl.setCcdMotionThreshold(0.1f);
+ bulletControl.setLinearVelocity(cam.getDirection().mult(80));
+ bulletg.addControl(bulletControl);
+ rootNode.attachChild(bulletg);
+ getPhysicsSpace().add(bulletControl);
+ }
+
+ public void collision(PhysicsCollisionEvent event) {
+ if (event.getObjectA() instanceof BombControl) {
+ final Spatial node = event.getNodeA();
+ effect.killAllParticles();
+ effect.setLocalTranslation(node.getLocalTranslation());
+ effect.emitAllParticles();
+ } else if (event.getObjectB() instanceof BombControl) {
+ final Spatial node = event.getNodeB();
+ effect.killAllParticles();
+ effect.setLocalTranslation(node.getLocalTranslation());
+ effect.emitAllParticles();
+ }
+ }
+
+ public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) {
+ if (channel == shootingChannel) {
+ channel.setAnim("stand");
+ }
+ }
+
+ public void onAnimChange(AnimControl control, AnimChannel channel, String animName) {
+ }
+}
diff --git a/JmeTests/src/jme3test/collision/RayTrace.java b/JmeTests/src/jme3test/collision/RayTrace.java
new file mode 100644
index 0000000..d7cc5a2
--- /dev/null
+++ b/JmeTests/src/jme3test/collision/RayTrace.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.collision;
+
+import com.jme3.collision.CollisionResults;
+import com.jme3.math.Ray;
+import com.jme3.math.Vector2f;
+import com.jme3.math.Vector3f;
+import com.jme3.renderer.Camera;
+import com.jme3.scene.Spatial;
+import java.awt.FlowLayout;
+import java.awt.image.BufferedImage;
+import javax.swing.ImageIcon;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+
+public class RayTrace {
+
+ private BufferedImage image;
+ private Camera cam;
+ private Spatial scene;
+ private CollisionResults results = new CollisionResults();
+ private JFrame frame;
+ private JLabel label;
+
+ public RayTrace(Spatial scene, Camera cam, int width, int height){
+ image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+ this.scene = scene;
+ this.cam = cam;
+ }
+
+ public void show(){
+ frame = new JFrame("HDR View");
+ label = new JLabel(new ImageIcon(image));
+ frame.getContentPane().add(label);
+ frame.setLayout(new FlowLayout());
+ frame.pack();
+ frame.setVisible(true);
+ }
+
+ public void update(){
+ int w = image.getWidth();
+ int h = image.getHeight();
+
+ float wr = (float) cam.getWidth() / image.getWidth();
+ float hr = (float) cam.getHeight() / image.getHeight();
+
+ scene.updateGeometricState();
+
+ for (int y = 0; y < h; y++){
+ for (int x = 0; x < w; x++){
+ Vector2f v = new Vector2f(x * wr,y * hr);
+ Vector3f pos = cam.getWorldCoordinates(v, 0.0f);
+ Vector3f dir = cam.getWorldCoordinates(v, 0.3f);
+ dir.subtractLocal(pos).normalizeLocal();
+
+ Ray r = new Ray(pos, dir);
+
+ results.clear();
+ scene.collideWith(r, results);
+ if (results.size() > 0){
+ image.setRGB(x, h - y - 1, 0xFFFFFFFF);
+ }else{
+ image.setRGB(x, h - y - 1, 0xFF000000);
+ }
+ }
+ }
+
+ label.repaint();
+ }
+
+}
diff --git a/JmeTests/src/jme3test/collision/TestMousePick.java b/JmeTests/src/jme3test/collision/TestMousePick.java
new file mode 100644
index 0000000..9f58b7f
--- /dev/null
+++ b/JmeTests/src/jme3test/collision/TestMousePick.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.collision;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.collision.CollisionResult;
+import com.jme3.collision.CollisionResults;
+import com.jme3.light.DirectionalLight;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Ray;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.debug.Arrow;
+import com.jme3.scene.shape.Box;
+
+public class TestMousePick extends SimpleApplication {
+
+ public static void main(String[] args) {
+ TestMousePick app = new TestMousePick();
+ app.start();
+ }
+
+ Node shootables;
+ Geometry mark;
+
+ @Override
+ public void simpleInitApp() {
+ flyCam.setEnabled(false);
+ initMark(); // a red sphere to mark the hit
+
+ /** create four colored boxes and a floor to shoot at: */
+ shootables = new Node("Shootables");
+ rootNode.attachChild(shootables);
+ shootables.attachChild(makeCube("a Dragon", -2f, 0f, 1f));
+ shootables.attachChild(makeCube("a tin can", 1f, -2f, 0f));
+ shootables.attachChild(makeCube("the Sheriff", 0f, 1f, -2f));
+ shootables.attachChild(makeCube("the Deputy", 1f, 0f, -4f));
+ shootables.attachChild(makeFloor());
+ shootables.attachChild(makeCharacter());
+ }
+
+ @Override
+ public void simpleUpdate(float tpf){
+ Vector3f origin = cam.getWorldCoordinates(inputManager.getCursorPosition(), 0.0f);
+ Vector3f direction = cam.getWorldCoordinates(inputManager.getCursorPosition(), 0.3f);
+ direction.subtractLocal(origin).normalizeLocal();
+
+ Ray ray = new Ray(origin, direction);
+ CollisionResults results = new CollisionResults();
+ shootables.collideWith(ray, results);
+// System.out.println("----- Collisions? " + results.size() + "-----");
+// for (int i = 0; i < results.size(); i++) {
+// // For each hit, we know distance, impact point, name of geometry.
+// float dist = results.getCollision(i).getDistance();
+// Vector3f pt = results.getCollision(i).getWorldContactPoint();
+// String hit = results.getCollision(i).getGeometry().getName();
+// System.out.println("* Collision #" + i);
+// System.out.println(" You shot " + hit + " at " + pt + ", " + dist + " wu away.");
+// }
+ if (results.size() > 0) {
+ CollisionResult closest = results.getClosestCollision();
+ mark.setLocalTranslation(closest.getContactPoint());
+
+ Quaternion q = new Quaternion();
+ q.lookAt(closest.getContactNormal(), Vector3f.UNIT_Y);
+ mark.setLocalRotation(q);
+
+ rootNode.attachChild(mark);
+ } else {
+ rootNode.detachChild(mark);
+ }
+ }
+
+ /** A cube object for target practice */
+ protected Geometry makeCube(String name, float x, float y, float z) {
+ Box box = new Box(1, 1, 1);
+ Geometry cube = new Geometry(name, box);
+ cube.setLocalTranslation(x, y, z);
+ Material mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat1.setColor("Color", ColorRGBA.randomColor());
+ cube.setMaterial(mat1);
+ return cube;
+ }
+
+ /** A floor to show that the "shot" can go through several objects. */
+ protected Geometry makeFloor() {
+ Box box = new Box(15, .2f, 15);
+ Geometry floor = new Geometry("the Floor", box);
+ floor.setLocalTranslation(0, -4, -5);
+ Material mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat1.setColor("Color", ColorRGBA.Gray);
+ floor.setMaterial(mat1);
+ return floor;
+ }
+
+ /** A red ball that marks the last spot that was "hit" by the "shot". */
+ protected void initMark() {
+ Arrow arrow = new Arrow(Vector3f.UNIT_Z.mult(2f));
+
+ //Sphere sphere = new Sphere(30, 30, 0.2f);
+ mark = new Geometry("BOOM!", arrow);
+ //mark = new Geometry("BOOM!", sphere);
+ Material mark_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mark_mat.getAdditionalRenderState().setLineWidth(3);
+ mark_mat.setColor("Color", ColorRGBA.Red);
+ mark.setMaterial(mark_mat);
+ }
+
+ protected Spatial makeCharacter() {
+ // load a character from jme3test-test-data
+ Spatial golem = assetManager.loadModel("Models/Oto/Oto.mesh.xml");
+ golem.scale(0.5f);
+ golem.setLocalTranslation(-1.0f, -1.5f, -0.6f);
+
+ // We must add a light to make the model visible
+ DirectionalLight sun = new DirectionalLight();
+ sun.setDirection(new Vector3f(-0.1f, -0.7f, -1.0f).normalizeLocal());
+ golem.addLight(sun);
+ return golem;
+ }
+}
diff --git a/JmeTests/src/jme3test/collision/TestRayCasting.java b/JmeTests/src/jme3test/collision/TestRayCasting.java
new file mode 100644
index 0000000..06b07e8
--- /dev/null
+++ b/JmeTests/src/jme3test/collision/TestRayCasting.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.collision;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.bounding.BoundingSphere;
+import com.jme3.material.Material;
+import com.jme3.math.FastMath;
+import com.jme3.scene.Mesh;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.VertexBuffer.Type;
+
+public class TestRayCasting extends SimpleApplication {
+
+ private RayTrace tracer;
+ private Spatial teapot;
+
+ public static void main(String[] args){
+ TestRayCasting app = new TestRayCasting();
+ app.setPauseOnLostFocus(false);
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+// flyCam.setEnabled(false);
+
+ // load material
+ Material mat = (Material) assetManager.loadMaterial("Interface/Logo/Logo.j3m");
+
+ Mesh q = new Mesh();
+ q.setBuffer(Type.Position, 3, new float[]
+ {
+ 1, 0, 0,
+ 0, 1.5f, 0,
+ -1, 0, 0
+ }
+ );
+ q.setBuffer(Type.Index, 3, new int[]{ 0, 1, 2 });
+ q.setBound(new BoundingSphere());
+ q.updateBound();
+// Geometry teapot = new Geometry("MyGeom", q);
+
+ teapot = assetManager.loadModel("Models/Teapot/Teapot.mesh.xml");
+// teapot.scale(2f, 2f, 2f);
+// teapot.move(2f, 2f, -.5f);
+ teapot.rotate(FastMath.HALF_PI, FastMath.HALF_PI, FastMath.HALF_PI);
+ teapot.setMaterial(mat);
+ rootNode.attachChild(teapot);
+
+// cam.setLocation(cam.getLocation().add(0,1,0));
+// cam.lookAt(teapot.getWorldBound().getCenter(), Vector3f.UNIT_Y);
+
+ tracer = new RayTrace(rootNode, cam, 160, 128);
+ tracer.show();
+ tracer.update();
+ }
+
+ @Override
+ public void simpleUpdate(float tpf){
+ teapot.rotate(0,tpf,0);
+ tracer.update();
+ }
+
+}
\ No newline at end of file
diff --git a/JmeTests/src/jme3test/collision/TestTriangleCollision.java b/JmeTests/src/jme3test/collision/TestTriangleCollision.java
new file mode 100644
index 0000000..e28d7c7
--- /dev/null
+++ b/JmeTests/src/jme3test/collision/TestTriangleCollision.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.collision;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.bounding.BoundingVolume;
+import com.jme3.collision.CollisionResults;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.AnalogListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.light.DirectionalLight;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Mesh;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.shape.Box;
+
+public class TestTriangleCollision extends SimpleApplication {
+
+ Geometry geom1;
+
+ Spatial golem;
+
+ public static void main(String[] args) {
+ TestTriangleCollision app = new TestTriangleCollision();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ // Create two boxes
+ Mesh mesh1 = new Box(0.5f, 0.5f, 0.5f);
+ geom1 = new Geometry("Box", mesh1);
+ geom1.move(2, 2, -.5f);
+ Material m1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ m1.setColor("Color", ColorRGBA.Blue);
+ geom1.setMaterial(m1);
+ rootNode.attachChild(geom1);
+
+ // load a character from jme3test-test-data
+ golem = assetManager.loadModel("Models/Oto/Oto.mesh.xml");
+ golem.scale(0.5f);
+ golem.setLocalTranslation(-1.0f, -1.5f, -0.6f);
+
+ // We must add a light to make the model visible
+ DirectionalLight sun = new DirectionalLight();
+ sun.setDirection(new Vector3f(-0.1f, -0.7f, -1.0f).normalizeLocal());
+ golem.addLight(sun);
+ rootNode.attachChild(golem);
+
+ // Create input
+ inputManager.addMapping("MoveRight", new KeyTrigger(KeyInput.KEY_L));
+ inputManager.addMapping("MoveLeft", new KeyTrigger(KeyInput.KEY_J));
+ inputManager.addMapping("MoveUp", new KeyTrigger(KeyInput.KEY_I));
+ inputManager.addMapping("MoveDown", new KeyTrigger(KeyInput.KEY_K));
+
+ inputManager.addListener(analogListener, new String[]{
+ "MoveRight", "MoveLeft", "MoveUp", "MoveDown"
+ });
+ }
+ private AnalogListener analogListener = new AnalogListener() {
+
+ public void onAnalog(String name, float value, float tpf) {
+ if (name.equals("MoveRight")) {
+ geom1.move(2 * tpf, 0, 0);
+ }
+
+ if (name.equals("MoveLeft")) {
+ geom1.move(-2 * tpf, 0, 0);
+ }
+
+ if (name.equals("MoveUp")) {
+ geom1.move(0, 2 * tpf, 0);
+ }
+
+ if (name.equals("MoveDown")) {
+ geom1.move(0, -2 * tpf, 0);
+ }
+ }
+ };
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ CollisionResults results = new CollisionResults();
+ BoundingVolume bv = geom1.getWorldBound();
+ golem.collideWith(bv, results);
+
+ if (results.size() > 0) {
+ geom1.getMaterial().setColor("Color", ColorRGBA.Red);
+ }else{
+ geom1.getMaterial().setColor("Color", ColorRGBA.Blue);
+ }
+ }
+}
diff --git a/JmeTests/src/jme3test/conversion/TestMipMapGen.java b/JmeTests/src/jme3test/conversion/TestMipMapGen.java
new file mode 100644
index 0000000..6110469
--- /dev/null
+++ b/JmeTests/src/jme3test/conversion/TestMipMapGen.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2009-2018 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.conversion;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.font.BitmapText;
+import com.jme3.material.Material;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Quad;
+import com.jme3.texture.Image;
+import com.jme3.texture.Texture;
+import com.jme3.util.MipMapGenerator;
+
+public class TestMipMapGen extends SimpleApplication {
+
+ public static void main(String[] args){
+ TestMipMapGen app = new TestMipMapGen();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ BitmapText txt = guiFont.createLabel("Left: HW Mips");
+ txt.setLocalTranslation(0, settings.getHeight() - txt.getLineHeight() * 4, 0);
+ guiNode.attachChild(txt);
+
+ txt = guiFont.createLabel("Right: AWT Mips");
+ txt.setLocalTranslation(0, settings.getHeight() - txt.getLineHeight() * 3, 0);
+ guiNode.attachChild(txt);
+
+ // create a simple plane/quad
+ Quad quadMesh = new Quad(1, 1);
+ quadMesh.updateGeometry(1, 1, false);
+ quadMesh.updateBound();
+
+ Geometry quad1 = new Geometry("Textured Quad", quadMesh);
+ Geometry quad2 = new Geometry("Textured Quad 2", quadMesh);
+
+ Texture tex = assetManager.loadTexture("Interface/Logo/Monkey.png");
+ tex.setMinFilter(Texture.MinFilter.Trilinear);
+
+ Texture texCustomMip = tex.clone();
+ Image imageCustomMip = texCustomMip.getImage().clone();
+ MipMapGenerator.generateMipMaps(imageCustomMip);
+ texCustomMip.setImage(imageCustomMip);
+
+ Material mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat1.setTexture("ColorMap", tex);
+
+ Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat2.setTexture("ColorMap", texCustomMip);
+
+ quad1.setMaterial(mat1);
+// quad1.setLocalTranslation(1, 0, 0);
+
+ quad2.setMaterial(mat2);
+ quad2.setLocalTranslation(1, 0, 0);
+
+ rootNode.attachChild(quad1);
+ rootNode.attachChild(quad2);
+ }
+
+}
diff --git a/JmeTests/src/jme3test/effect/TestEverything.java b/JmeTests/src/jme3test/effect/TestEverything.java
new file mode 100644
index 0000000..62f06a4
--- /dev/null
+++ b/JmeTests/src/jme3test/effect/TestEverything.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.effect;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.light.DirectionalLight;
+import com.jme3.material.Material;
+import com.jme3.math.*;
+import com.jme3.post.FilterPostProcessor;
+import com.jme3.post.filters.ToneMapFilter;
+import com.jme3.renderer.Caps;
+import com.jme3.renderer.queue.RenderQueue.ShadowMode;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.Spatial.CullHint;
+import com.jme3.scene.shape.Box;
+import com.jme3.shadow.DirectionalLightShadowRenderer;
+import com.jme3.texture.Texture;
+import com.jme3.texture.Texture.WrapMode;
+import com.jme3.util.SkyFactory;
+import com.jme3.util.TangentBinormalGenerator;
+
+public class TestEverything extends SimpleApplication {
+
+ private DirectionalLightShadowRenderer dlsr;
+ private ToneMapFilter toneMapFilter;
+ private Vector3f lightDir = new Vector3f(-1, -1, .5f).normalizeLocal();
+
+ public static void main(String[] args){
+ TestEverything app = new TestEverything();
+ app.start();
+ }
+
+ public void setupHdr(){
+ if (renderer.getCaps().contains(Caps.GLSL100)){
+ toneMapFilter = new ToneMapFilter();
+ toneMapFilter.setWhitePoint(new Vector3f(3f, 3f, 3f));
+ FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
+ fpp.addFilter(toneMapFilter);
+ viewPort.addProcessor(fpp);
+
+ // setPauseOnLostFocus(false);
+ }
+ }
+
+ public void setupBasicShadow(){
+ if (renderer.getCaps().contains(Caps.GLSL100)){
+ dlsr = new DirectionalLightShadowRenderer(assetManager, 1024, 1);
+ viewPort.addProcessor(dlsr);
+ }
+ }
+
+ public void setupSkyBox(){
+ Texture envMap;
+ if (renderer.getCaps().contains(Caps.FloatTexture)){
+ envMap = assetManager.loadTexture("Textures/Sky/St Peters/StPeters.hdr");
+ }else{
+ envMap = assetManager.loadTexture("Textures/Sky/St Peters/StPeters.jpg");
+ }
+ rootNode.attachChild(SkyFactory.createSky(assetManager, envMap,
+ new Vector3f(-1,-1,-1), SkyFactory.EnvMapType.SphereMap));
+ }
+
+ public void setupLighting(){
+ boolean hdr = false;
+ if (toneMapFilter != null){
+ hdr = toneMapFilter.isEnabled();
+ }
+
+ DirectionalLight dl = new DirectionalLight();
+ if (dlsr != null) {
+ dlsr.setLight(dl);
+ }
+ dl.setDirection(lightDir);
+ if (hdr){
+ dl.setColor(new ColorRGBA(3, 3, 3, 1));
+ }else{
+ dl.setColor(new ColorRGBA(.9f, .9f, .9f, 1));
+ }
+ rootNode.addLight(dl);
+
+ dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(1, 0, -1).normalizeLocal());
+ if (hdr){
+ dl.setColor(new ColorRGBA(1, 1, 1, 1));
+ }else{
+ dl.setColor(new ColorRGBA(.4f, .4f, .4f, 1));
+ }
+ rootNode.addLight(dl);
+ }
+
+ public void setupFloor(){
+ Material mat = assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall.j3m");
+ Box floor = new Box(50, 1f, 50);
+ TangentBinormalGenerator.generate(floor);
+ floor.scaleTextureCoordinates(new Vector2f(5, 5));
+ Geometry floorGeom = new Geometry("Floor", floor);
+ floorGeom.setMaterial(mat);
+ floorGeom.setShadowMode(ShadowMode.Receive);
+ rootNode.attachChild(floorGeom);
+ }
+
+// public void setupTerrain(){
+// Material mat = manager.loadMaterial("Textures/Terrain/Rock/Rock.j3m");
+// mat.getTextureParam("DiffuseMap").getValue().setWrap(WrapMode.Repeat);
+// mat.getTextureParam("NormalMap").getValue().setWrap(WrapMode.Repeat);
+// try{
+// Geomap map = GeomapLoader.fromImage(TestEverything.class.getResource("/textures/heightmap.png"));
+// Mesh m = map.createMesh(new Vector3f(0.35f, 0.0005f, 0.35f), new Vector2f(10, 10), true);
+// Logger.getLogger(TangentBinormalGenerator.class.getName()).setLevel(Level.SEVERE);
+// TangentBinormalGenerator.generate(m);
+// Geometry t = new Geometry("Terrain", m);
+// t.setLocalTranslation(85, -15, 0);
+// t.setMaterial(mat);
+// t.updateModelBound();
+// t.setShadowMode(ShadowMode.Receive);
+// rootNode.attachChild(t);
+// }catch (IOException ex){
+// ex.printStackTrace();
+// }
+//
+// }
+
+ public void setupRobotGuy(){
+ Node model = (Node) assetManager.loadModel("Models/Oto/Oto.mesh.xml");
+ Material mat = assetManager.loadMaterial("Models/Oto/Oto.j3m");
+ model.getChild(0).setMaterial(mat);
+// model.setAnimation("Walk");
+ model.setLocalTranslation(30, 10.5f, 30);
+ model.setLocalScale(2);
+ model.setShadowMode(ShadowMode.CastAndReceive);
+ rootNode.attachChild(model);
+ }
+
+ public void setupSignpost(){
+ Spatial signpost = assetManager.loadModel("Models/Sign Post/Sign Post.mesh.xml");
+ Material mat = assetManager.loadMaterial("Models/Sign Post/Sign Post.j3m");
+ signpost.setMaterial(mat);
+ signpost.rotate(0, FastMath.HALF_PI, 0);
+ signpost.setLocalTranslation(12, 3.5f, 30);
+ signpost.setLocalScale(4);
+ signpost.setShadowMode(ShadowMode.CastAndReceive);
+ rootNode.attachChild(signpost);
+ }
+
+ @Override
+ public void simpleInitApp() {
+ cam.setLocation(new Vector3f(-32.295086f, 54.80136f, 79.59805f));
+ cam.setRotation(new Quaternion(0.074364014f, 0.92519957f, -0.24794696f, 0.27748522f));
+ cam.update();
+
+ cam.setFrustumFar(300);
+ flyCam.setMoveSpeed(30);
+
+ rootNode.setCullHint(CullHint.Never);
+
+ setupBasicShadow();
+ setupHdr();
+
+ setupLighting();
+ setupSkyBox();
+
+// setupTerrain();
+ setupFloor();
+// setupRobotGuy();
+ setupSignpost();
+
+
+ }
+
+}
diff --git a/JmeTests/src/jme3test/effect/TestExplosionEffect.java b/JmeTests/src/jme3test/effect/TestExplosionEffect.java
new file mode 100644
index 0000000..ff5100f
--- /dev/null
+++ b/JmeTests/src/jme3test/effect/TestExplosionEffect.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.effect;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.effect.ParticleEmitter;
+import com.jme3.effect.ParticleMesh.Type;
+import com.jme3.effect.shapes.EmitterSphereShape;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Node;
+
+public class TestExplosionEffect extends SimpleApplication {
+
+ private float time = 0;
+ private int state = 0;
+ private Node explosionEffect = new Node("explosionFX");
+ private ParticleEmitter flame, flash, spark, roundspark, smoketrail, debris,
+ shockwave;
+
+
+ private static final int COUNT_FACTOR = 1;
+ private static final float COUNT_FACTOR_F = 1f;
+
+ private static final boolean POINT_SPRITE = true;
+ private static final Type EMITTER_TYPE = POINT_SPRITE ? Type.Point : Type.Triangle;
+
+ public static void main(String[] args){
+ TestExplosionEffect app = new TestExplosionEffect();
+ app.start();
+ }
+
+ private void createFlame(){
+ flame = new ParticleEmitter("Flame", EMITTER_TYPE, 32 * COUNT_FACTOR);
+ flame.setSelectRandomImage(true);
+ flame.setStartColor(new ColorRGBA(1f, 0.4f, 0.05f, (float) (1f / COUNT_FACTOR_F)));
+ flame.setEndColor(new ColorRGBA(.4f, .22f, .12f, 0f));
+ flame.setStartSize(1.3f);
+ flame.setEndSize(2f);
+ flame.setShape(new EmitterSphereShape(Vector3f.ZERO, 1f));
+ flame.setParticlesPerSec(0);
+ flame.setGravity(0, -5, 0);
+ flame.setLowLife(.4f);
+ flame.setHighLife(.5f);
+ flame.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 7, 0));
+ flame.getParticleInfluencer().setVelocityVariation(1f);
+ flame.setImagesX(2);
+ flame.setImagesY(2);
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
+ mat.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/flame.png"));
+ mat.setBoolean("PointSprite", POINT_SPRITE);
+ flame.setMaterial(mat);
+ explosionEffect.attachChild(flame);
+ }
+
+ private void createFlash(){
+ flash = new ParticleEmitter("Flash", EMITTER_TYPE, 24 * COUNT_FACTOR);
+ flash.setSelectRandomImage(true);
+ flash.setStartColor(new ColorRGBA(1f, 0.8f, 0.36f, (float) (1f / COUNT_FACTOR_F)));
+ flash.setEndColor(new ColorRGBA(1f, 0.8f, 0.36f, 0f));
+ flash.setStartSize(.1f);
+ flash.setEndSize(3.0f);
+ flash.setShape(new EmitterSphereShape(Vector3f.ZERO, .05f));
+ flash.setParticlesPerSec(0);
+ flash.setGravity(0, 0, 0);
+ flash.setLowLife(.2f);
+ flash.setHighLife(.2f);
+ flash.getParticleInfluencer()
+ .setInitialVelocity(new Vector3f(0, 5f, 0));
+ flash.getParticleInfluencer().setVelocityVariation(1);
+ flash.setImagesX(2);
+ flash.setImagesY(2);
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
+ mat.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/flash.png"));
+ mat.setBoolean("PointSprite", POINT_SPRITE);
+ flash.setMaterial(mat);
+ explosionEffect.attachChild(flash);
+ }
+
+ private void createRoundSpark(){
+ roundspark = new ParticleEmitter("RoundSpark", EMITTER_TYPE, 20 * COUNT_FACTOR);
+ roundspark.setStartColor(new ColorRGBA(1f, 0.29f, 0.34f, (float) (1.0 / COUNT_FACTOR_F)));
+ roundspark.setEndColor(new ColorRGBA(0, 0, 0, (float) (0.5f / COUNT_FACTOR_F)));
+ roundspark.setStartSize(1.2f);
+ roundspark.setEndSize(1.8f);
+ roundspark.setShape(new EmitterSphereShape(Vector3f.ZERO, 2f));
+ roundspark.setParticlesPerSec(0);
+ roundspark.setGravity(0, -.5f, 0);
+ roundspark.setLowLife(1.8f);
+ roundspark.setHighLife(2f);
+ roundspark.getParticleInfluencer()
+ .setInitialVelocity(new Vector3f(0, 3, 0));
+ roundspark.getParticleInfluencer().setVelocityVariation(.5f);
+ roundspark.setImagesX(1);
+ roundspark.setImagesY(1);
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
+ mat.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/roundspark.png"));
+ mat.setBoolean("PointSprite", POINT_SPRITE);
+ roundspark.setMaterial(mat);
+ explosionEffect.attachChild(roundspark);
+ }
+
+ private void createSpark(){
+ spark = new ParticleEmitter("Spark", Type.Triangle, 30 * COUNT_FACTOR);
+ spark.setStartColor(new ColorRGBA(1f, 0.8f, 0.36f, (float) (1.0f / COUNT_FACTOR_F)));
+ spark.setEndColor(new ColorRGBA(1f, 0.8f, 0.36f, 0f));
+ spark.setStartSize(.5f);
+ spark.setEndSize(.5f);
+ spark.setFacingVelocity(true);
+ spark.setParticlesPerSec(0);
+ spark.setGravity(0, 5, 0);
+ spark.setLowLife(1.1f);
+ spark.setHighLife(1.5f);
+ spark.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 20, 0));
+ spark.getParticleInfluencer().setVelocityVariation(1);
+ spark.setImagesX(1);
+ spark.setImagesY(1);
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
+ mat.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/spark.png"));
+ spark.setMaterial(mat);
+ explosionEffect.attachChild(spark);
+ }
+
+ private void createSmokeTrail(){
+ smoketrail = new ParticleEmitter("SmokeTrail", Type.Triangle, 22 * COUNT_FACTOR);
+ smoketrail.setStartColor(new ColorRGBA(1f, 0.8f, 0.36f, (float) (1.0f / COUNT_FACTOR_F)));
+ smoketrail.setEndColor(new ColorRGBA(1f, 0.8f, 0.36f, 0f));
+ smoketrail.setStartSize(.2f);
+ smoketrail.setEndSize(1f);
+
+// smoketrail.setShape(new EmitterSphereShape(Vector3f.ZERO, 1f));
+ smoketrail.setFacingVelocity(true);
+ smoketrail.setParticlesPerSec(0);
+ smoketrail.setGravity(0, 1, 0);
+ smoketrail.setLowLife(.4f);
+ smoketrail.setHighLife(.5f);
+ smoketrail.getParticleInfluencer()
+ .setInitialVelocity(new Vector3f(0, 12, 0));
+ smoketrail.getParticleInfluencer().setVelocityVariation(1);
+ smoketrail.setImagesX(1);
+ smoketrail.setImagesY(3);
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
+ mat.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/smoketrail.png"));
+ smoketrail.setMaterial(mat);
+ explosionEffect.attachChild(smoketrail);
+ }
+
+ private void createDebris(){
+ debris = new ParticleEmitter("Debris", Type.Triangle, 15 * COUNT_FACTOR);
+ debris.setSelectRandomImage(true);
+ debris.setRandomAngle(true);
+ debris.setRotateSpeed(FastMath.TWO_PI * 4);
+ debris.setStartColor(new ColorRGBA(1f, 0.59f, 0.28f, (float) (1.0f / COUNT_FACTOR_F)));
+ debris.setEndColor(new ColorRGBA(.5f, 0.5f, 0.5f, 0f));
+ debris.setStartSize(.2f);
+ debris.setEndSize(.2f);
+
+// debris.setShape(new EmitterSphereShape(Vector3f.ZERO, .05f));
+ debris.setParticlesPerSec(0);
+ debris.setGravity(0, 12f, 0);
+ debris.setLowLife(1.4f);
+ debris.setHighLife(1.5f);
+ debris.getParticleInfluencer()
+ .setInitialVelocity(new Vector3f(0, 15, 0));
+ debris.getParticleInfluencer().setVelocityVariation(.60f);
+ debris.setImagesX(3);
+ debris.setImagesY(3);
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
+ mat.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/Debris.png"));
+ debris.setMaterial(mat);
+ explosionEffect.attachChild(debris);
+ }
+
+ private void createShockwave(){
+ shockwave = new ParticleEmitter("Shockwave", Type.Triangle, 1 * COUNT_FACTOR);
+// shockwave.setRandomAngle(true);
+ shockwave.setFaceNormal(Vector3f.UNIT_Y);
+ shockwave.setStartColor(new ColorRGBA(.48f, 0.17f, 0.01f, (float) (.8f / COUNT_FACTOR_F)));
+ shockwave.setEndColor(new ColorRGBA(.48f, 0.17f, 0.01f, 0f));
+
+ shockwave.setStartSize(0f);
+ shockwave.setEndSize(7f);
+
+ shockwave.setParticlesPerSec(0);
+ shockwave.setGravity(0, 0, 0);
+ shockwave.setLowLife(0.5f);
+ shockwave.setHighLife(0.5f);
+ shockwave.getParticleInfluencer()
+ .setInitialVelocity(new Vector3f(0, 0, 0));
+ shockwave.getParticleInfluencer().setVelocityVariation(0f);
+ shockwave.setImagesX(1);
+ shockwave.setImagesY(1);
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
+ mat.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/shockwave.png"));
+ shockwave.setMaterial(mat);
+ explosionEffect.attachChild(shockwave);
+ }
+
+ @Override
+ public void simpleInitApp() {
+ createFlame();
+ createFlash();
+ createSpark();
+ createRoundSpark();
+ createSmokeTrail();
+ createDebris();
+ createShockwave();
+ explosionEffect.setLocalScale(0.5f);
+ renderManager.preloadScene(explosionEffect);
+
+ cam.setLocation(new Vector3f(0, 3.5135868f, 10));
+ cam.setRotation(new Quaternion(1.5714673E-4f, 0.98696727f, -0.16091813f, 9.6381607E-4f));
+
+ rootNode.attachChild(explosionEffect);
+ }
+
+ @Override
+ public void simpleUpdate(float tpf){
+ time += tpf / speed;
+ if (time > 1f && state == 0){
+ flash.emitAllParticles();
+ spark.emitAllParticles();
+ smoketrail.emitAllParticles();
+ debris.emitAllParticles();
+ shockwave.emitAllParticles();
+ state++;
+ }
+ if (time > 1f + .05f / speed && state == 1){
+ flame.emitAllParticles();
+ roundspark.emitAllParticles();
+ state++;
+ }
+
+ // rewind the effect
+ if (time > 5 / speed && state == 2){
+ state = 0;
+ time = 0;
+
+ flash.killAllParticles();
+ spark.killAllParticles();
+ smoketrail.killAllParticles();
+ debris.killAllParticles();
+ flame.killAllParticles();
+ roundspark.killAllParticles();
+ shockwave.killAllParticles();
+ }
+ }
+
+}
diff --git a/JmeTests/src/jme3test/effect/TestMovingParticle.java b/JmeTests/src/jme3test/effect/TestMovingParticle.java
new file mode 100644
index 0000000..b38eed9
--- /dev/null
+++ b/JmeTests/src/jme3test/effect/TestMovingParticle.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.effect;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.effect.ParticleEmitter;
+import com.jme3.effect.ParticleMesh.Type;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.material.Material;
+import com.jme3.math.FastMath;
+import com.jme3.math.Vector3f;
+
+/**
+ * Particle that moves in a circle.
+ *
+ * @author Kirill Vainer
+ */
+public class TestMovingParticle extends SimpleApplication {
+
+ private ParticleEmitter emit;
+ private float angle = 0;
+
+ public static void main(String[] args) {
+ TestMovingParticle app = new TestMovingParticle();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ emit = new ParticleEmitter("Emitter", Type.Triangle, 300);
+ emit.setGravity(0, 0, 0);
+ emit.getParticleInfluencer().setVelocityVariation(1);
+ emit.setLowLife(1);
+ emit.setHighLife(1);
+ emit.getParticleInfluencer()
+ .setInitialVelocity(new Vector3f(0, .5f, 0));
+ emit.setImagesX(15);
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
+ mat.setTexture("Texture", assetManager.loadTexture("Effects/Smoke/Smoke.png"));
+ emit.setMaterial(mat);
+
+ rootNode.attachChild(emit);
+
+ inputManager.addListener(new ActionListener() {
+
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if ("setNum".equals(name) && isPressed) {
+ emit.setNumParticles(1000);
+ }
+ }
+ }, "setNum");
+
+ inputManager.addMapping("setNum", new KeyTrigger(KeyInput.KEY_SPACE));
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ angle += tpf;
+ angle %= FastMath.TWO_PI;
+ float x = FastMath.cos(angle) * 2;
+ float y = FastMath.sin(angle) * 2;
+ emit.setLocalTranslation(x, 0, y);
+ }
+}
diff --git a/JmeTests/src/jme3test/effect/TestParticleExportingCloning.java b/JmeTests/src/jme3test/effect/TestParticleExportingCloning.java
new file mode 100644
index 0000000..d38fdbd
--- /dev/null
+++ b/JmeTests/src/jme3test/effect/TestParticleExportingCloning.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.effect;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.effect.ParticleEmitter;
+import com.jme3.effect.ParticleMesh.Type;
+import com.jme3.effect.shapes.EmitterSphereShape;
+import com.jme3.export.binary.BinaryExporter;
+import com.jme3.export.binary.BinaryImporter;
+import com.jme3.material.Material;
+import com.jme3.math.Vector3f;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+public class TestParticleExportingCloning extends SimpleApplication {
+
+ public static void main(String[] args){
+ TestParticleExportingCloning app = new TestParticleExportingCloning();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ ParticleEmitter emit = new ParticleEmitter("Emitter", Type.Triangle, 200);
+ emit.setShape(new EmitterSphereShape(Vector3f.ZERO, 1f));
+ emit.setGravity(0, 0, 0);
+ emit.setLowLife(5);
+ emit.setHighLife(10);
+ emit.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 0, 0));
+ emit.setImagesX(15);
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
+ mat.setTexture("Texture", assetManager.loadTexture("Effects/Smoke/Smoke.png"));
+ emit.setMaterial(mat);
+
+ ParticleEmitter emit2 = emit.clone();
+ emit2.move(3, 0, 0);
+
+ rootNode.attachChild(emit);
+ rootNode.attachChild(emit2);
+
+ ParticleEmitter emit3 = BinaryExporter.saveAndLoad(assetManager, emit);
+ emit3.move(-3, 0, 0);
+ rootNode.attachChild(emit3);
+ }
+
+}
diff --git a/JmeTests/src/jme3test/effect/TestPointSprite.java b/JmeTests/src/jme3test/effect/TestPointSprite.java
new file mode 100644
index 0000000..1a3e890
--- /dev/null
+++ b/JmeTests/src/jme3test/effect/TestPointSprite.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.effect;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.effect.ParticleEmitter;
+import com.jme3.effect.ParticleMesh.Type;
+import com.jme3.effect.shapes.EmitterBoxShape;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Vector3f;
+
+public class TestPointSprite extends SimpleApplication {
+
+ public static void main(String[] args){
+ TestPointSprite app = new TestPointSprite();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ final ParticleEmitter emit = new ParticleEmitter("Emitter", Type.Point, 10000);
+ emit.setShape(new EmitterBoxShape(new Vector3f(-1.8f, -1.8f, -1.8f),
+ new Vector3f(1.8f, 1.8f, 1.8f)));
+ emit.setGravity(0, 0, 0);
+ emit.setLowLife(60);
+ emit.setHighLife(60);
+ emit.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 0, 0));
+ emit.setImagesX(15);
+ emit.setStartSize(0.05f);
+ emit.setEndSize(0.05f);
+ emit.setStartColor(ColorRGBA.White);
+ emit.setEndColor(ColorRGBA.White);
+ emit.setSelectRandomImage(true);
+ emit.emitAllParticles();
+
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
+ mat.setBoolean("PointSprite", true);
+ mat.setTexture("Texture", assetManager.loadTexture("Effects/Smoke/Smoke.png"));
+ emit.setMaterial(mat);
+
+ rootNode.attachChild(emit);
+ inputManager.addListener(new ActionListener() {
+
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if ("setNum".equals(name) && isPressed) {
+ emit.setNumParticles(5000);
+ emit.emitAllParticles();
+ }
+ }
+ }, "setNum");
+
+ inputManager.addMapping("setNum", new KeyTrigger(KeyInput.KEY_SPACE));
+
+ }
+
+}
diff --git a/JmeTests/src/jme3test/effect/TestSoftParticles.java b/JmeTests/src/jme3test/effect/TestSoftParticles.java
new file mode 100644
index 0000000..84189e1
--- /dev/null
+++ b/JmeTests/src/jme3test/effect/TestSoftParticles.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.effect;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.effect.ParticleEmitter;
+import com.jme3.effect.ParticleMesh;
+import com.jme3.effect.shapes.EmitterSphereShape;
+import com.jme3.input.KeyInput;
+import com.jme3.input.MouseInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.input.controls.MouseButtonTrigger;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.post.FilterPostProcessor;
+import com.jme3.post.filters.TranslucentBucketFilter;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.shape.Box;
+
+/**
+ *
+ * @author Nehon
+ */
+public class TestSoftParticles extends SimpleApplication {
+
+ private boolean softParticles = true;
+ private FilterPostProcessor fpp;
+ private TranslucentBucketFilter tbf;
+ private Node particleNode;
+
+ public static void main(String[] args) {
+ TestSoftParticles app = new TestSoftParticles();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+
+ cam.setLocation(new Vector3f(-7.2221026f, 4.1183004f, 7.759811f));
+ cam.setRotation(new Quaternion(0.06152846f, 0.91236454f, -0.1492115f, 0.37621948f));
+
+ flyCam.setMoveSpeed(10);
+
+
+ // -------- floor
+ Box b = new Box(10, 0.1f, 10);
+ Geometry geom = new Geometry("Box", b);
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat.setColor("Color", ColorRGBA.Gray);
+ mat.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg"));
+ geom.setMaterial(mat);
+ rootNode.attachChild(geom);
+
+ Box b2 = new Box(1, 1, 1);
+ Geometry geom2 = new Geometry("Box", b2);
+ Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat2.setColor("Color", ColorRGBA.DarkGray);
+ geom2.setMaterial(mat2);
+ rootNode.attachChild(geom2);
+ geom2.setLocalScale(0.1f, 0.2f, 1);
+
+ fpp = new FilterPostProcessor(assetManager);
+ tbf = new TranslucentBucketFilter(true);
+ fpp.addFilter(tbf);
+ int samples = context.getSettings().getSamples();
+ if (samples > 0) {
+ fpp.setNumSamples(samples);
+ }
+ viewPort.addProcessor(fpp);
+
+ particleNode = new Node("particleNode");
+ rootNode.attachChild(particleNode);
+
+ createParticles();
+
+
+ inputManager.addListener(new ActionListener() {
+
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if(isPressed && name.equals("toggle")){
+ // tbf.setEnabled(!tbf.isEnabled());
+ softParticles = !softParticles;
+ if(softParticles){
+ viewPort.addProcessor(fpp);
+ }else{
+ viewPort.removeProcessor(fpp);
+ }
+ }
+ }
+ }, "toggle");
+ inputManager.addMapping("toggle", new KeyTrigger(KeyInput.KEY_SPACE));
+
+ // emit again
+ inputManager.addListener(new ActionListener() {
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if(isPressed && name.equals("refire")) {
+ //fpp.removeFilter(tbf); // <-- add back in to fix
+ particleNode.detachAllChildren();
+ createParticles();
+ //fpp.addFilter(tbf);
+ }
+ }
+ }, "refire");
+ inputManager.addMapping("refire", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
+ }
+
+ private void createParticles() {
+
+ Material material = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
+ material.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/flame.png"));
+ material.setFloat("Softness", 3f); //
+
+ //Fire
+ ParticleEmitter fire = new ParticleEmitter("Fire", ParticleMesh.Type.Triangle, 30);
+ fire.setMaterial(material);
+ fire.setShape(new EmitterSphereShape(Vector3f.ZERO, 0.1f));
+ fire.setImagesX(2);
+ fire.setImagesY(2); // 2x2 texture animation
+ fire.setEndColor(new ColorRGBA(1f, 0f, 0f, 1f)); // red
+ fire.setStartColor(new ColorRGBA(1f, 1f, 0f, 0.5f)); // yellow
+ fire.setStartSize(0.6f);
+ fire.setEndSize(0.01f);
+ fire.setGravity(0, -0.3f, 0);
+ fire.setLowLife(0.5f);
+ fire.setHighLife(3f);
+ fire.setLocalTranslation(0, 0.2f, 0);
+
+ particleNode.attachChild(fire);
+
+
+ ParticleEmitter smoke = new ParticleEmitter("Smoke", ParticleMesh.Type.Triangle, 30);
+ smoke.setMaterial(material);
+ smoke.setShape(new EmitterSphereShape(Vector3f.ZERO, 5));
+ smoke.setImagesX(1);
+ smoke.setImagesY(1); // 2x2 texture animation
+ smoke.setStartColor(new ColorRGBA(0.1f, 0.1f, 0.1f,1f)); // dark gray
+ smoke.setEndColor(new ColorRGBA(0.5f, 0.5f, 0.5f, 0.3f)); // gray
+ smoke.setStartSize(3f);
+ smoke.setEndSize(5f);
+ smoke.setGravity(0, -0.001f, 0);
+ smoke.setLowLife(100f);
+ smoke.setHighLife(100f);
+ smoke.setLocalTranslation(0, 0.1f, 0);
+ smoke.emitAllParticles();
+
+ particleNode.attachChild(smoke);
+ }
+
+
+}
diff --git a/JmeTests/src/jme3test/export/TestAssetLinkNode.java b/JmeTests/src/jme3test/export/TestAssetLinkNode.java
new file mode 100644
index 0000000..d2c7213
--- /dev/null
+++ b/JmeTests/src/jme3test/export/TestAssetLinkNode.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.export;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.asset.AssetKey;
+import com.jme3.asset.ModelKey;
+import com.jme3.export.binary.BinaryExporter;
+import com.jme3.export.binary.BinaryImporter;
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.PointLight;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.AssetLinkNode;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.shape.Sphere;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class TestAssetLinkNode extends SimpleApplication {
+
+ float angle;
+ PointLight pl;
+ Spatial lightMdl;
+
+ public static void main(String[] args){
+ TestAssetLinkNode app = new TestAssetLinkNode();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ AssetLinkNode loaderNode=new AssetLinkNode();
+ loaderNode.addLinkedChild(new ModelKey("Models/MonkeyHead/MonkeyHead.mesh.xml"));
+ //load/attach the children (happens automatically on load)
+// loaderNode.attachLinkedChildren(assetManager);
+// rootNode.attachChild(loaderNode);
+
+ //save and load the loaderNode
+ try {
+ //export to byte array
+ ByteArrayOutputStream bout=new ByteArrayOutputStream();
+ BinaryExporter.getInstance().save(loaderNode, bout);
+ //import from byte array, automatically loads the monkeyhead from file
+ ByteArrayInputStream bin=new ByteArrayInputStream(bout.toByteArray());
+ BinaryImporter imp=BinaryImporter.getInstance();
+ imp.setAssetManager(assetManager);
+ Node newLoaderNode=(Node)imp.load(bin);
+ //attach to rootNode
+ rootNode.attachChild(newLoaderNode);
+ } catch (IOException ex) {
+ Logger.getLogger(TestAssetLinkNode.class.getName()).log(Level.SEVERE, null, ex);
+ }
+
+
+ rootNode.attachChild(loaderNode);
+
+ lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f));
+ lightMdl.setMaterial( (Material) assetManager.loadAsset(new AssetKey("Common/Materials/RedColor.j3m")));
+ rootNode.attachChild(lightMdl);
+
+ // flourescent main light
+ pl = new PointLight();
+ pl.setColor(new ColorRGBA(0.88f, 0.92f, 0.95f, 1.0f));
+ rootNode.addLight(pl);
+
+ // sunset light
+ DirectionalLight dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(-0.1f,-0.7f,1).normalizeLocal());
+ dl.setColor(new ColorRGBA(0.44f, 0.30f, 0.20f, 1.0f));
+ rootNode.addLight(dl);
+
+ // skylight
+ dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(-0.6f,-1,-0.6f).normalizeLocal());
+ dl.setColor(new ColorRGBA(0.10f, 0.22f, 0.44f, 1.0f));
+ rootNode.addLight(dl);
+
+ // white ambient light
+ dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(1, -0.5f,-0.1f).normalizeLocal());
+ dl.setColor(new ColorRGBA(0.50f, 0.40f, 0.50f, 1.0f));
+ rootNode.addLight(dl);
+ }
+
+ @Override
+ public void simpleUpdate(float tpf){
+ angle += tpf * 0.25f;
+ angle %= FastMath.TWO_PI;
+
+ pl.setPosition(new Vector3f(FastMath.cos(angle) * 6f, 3f, FastMath.sin(angle) * 6f));
+ lightMdl.setLocalTranslation(pl.getPosition());
+ }
+
+}
diff --git a/JmeTests/src/jme3test/export/TestOgreConvert.java b/JmeTests/src/jme3test/export/TestOgreConvert.java
new file mode 100644
index 0000000..bfc03c0
--- /dev/null
+++ b/JmeTests/src/jme3test/export/TestOgreConvert.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.export;
+
+import com.jme3.animation.AnimChannel;
+import com.jme3.animation.AnimControl;
+import com.jme3.app.SimpleApplication;
+import com.jme3.export.binary.BinaryExporter;
+import com.jme3.export.binary.BinaryImporter;
+import com.jme3.light.DirectionalLight;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+public class TestOgreConvert extends SimpleApplication {
+
+ public static void main(String[] args){
+ TestOgreConvert app = new TestOgreConvert();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ Spatial ogreModel = assetManager.loadModel("Models/Oto/Oto.mesh.xml");
+
+ DirectionalLight dl = new DirectionalLight();
+ dl.setColor(ColorRGBA.White);
+ dl.setDirection(new Vector3f(0,-1,-1).normalizeLocal());
+ rootNode.addLight(dl);
+
+ try {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ BinaryExporter exp = new BinaryExporter();
+ exp.save(ogreModel, baos);
+
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ BinaryImporter imp = new BinaryImporter();
+ imp.setAssetManager(assetManager);
+ Node ogreModelReloaded = (Node) imp.load(bais, null, null);
+
+ AnimControl control = ogreModelReloaded.getControl(AnimControl.class);
+ AnimChannel chan = control.createChannel();
+ chan.setAnim("Walk");
+
+ rootNode.attachChild(ogreModelReloaded);
+ } catch (IOException ex){
+ ex.printStackTrace();
+ }
+ }
+}
diff --git a/JmeTests/src/jme3test/games/CubeField.java b/JmeTests/src/jme3test/games/CubeField.java
new file mode 100644
index 0000000..c166b58
--- /dev/null
+++ b/JmeTests/src/jme3test/games/CubeField.java
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.games;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.bounding.BoundingVolume;
+import com.jme3.font.BitmapFont;
+import com.jme3.font.BitmapText;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.AnalogListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.shape.Box;
+import com.jme3.scene.shape.Dome;
+import java.util.ArrayList;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * @author Kyle "bonechilla" Williams
+ */
+public class CubeField extends SimpleApplication implements AnalogListener {
+
+ public static void main(String[] args) {
+ CubeField app = new CubeField();
+ app.start();
+ }
+
+ private BitmapFont defaultFont;
+
+ private boolean START;
+ private int difficulty, Score, colorInt, highCap, lowCap,diffHelp;
+ private Node player;
+ private Geometry fcube;
+ private ArrayList cubeField;
+ private ArrayList obstacleColors;
+ private float speed, coreTime,coreTime2;
+ private float camAngle = 0;
+ private BitmapText fpsScoreText, pressStart;
+
+ private boolean solidBox = true;
+ private Material playerMaterial;
+ private Material floorMaterial;
+
+ private float fpsRate = 1000f / 1f;
+
+ /**
+ * Initializes game
+ */
+ @Override
+ public void simpleInitApp() {
+ Logger.getLogger("com.jme3").setLevel(Level.WARNING);
+
+ flyCam.setEnabled(false);
+ setDisplayStatView(false);
+
+ Keys();
+
+ defaultFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
+ pressStart = new BitmapText(defaultFont, false);
+ fpsScoreText = new BitmapText(defaultFont, false);
+
+ loadText(fpsScoreText, "Current Score: 0", defaultFont, 0, 2, 0);
+ loadText(pressStart, "PRESS ENTER", defaultFont, 0, 5, 0);
+
+ player = createPlayer();
+ rootNode.attachChild(player);
+ cubeField = new ArrayList();
+ obstacleColors = new ArrayList();
+
+ gameReset();
+ }
+ /**
+ * Used to reset cubeField
+ */
+ private void gameReset(){
+ Score = 0;
+ lowCap = 10;
+ colorInt = 0;
+ highCap = 40;
+ difficulty = highCap;
+
+ for (Geometry cube : cubeField){
+ cube.removeFromParent();
+ }
+ cubeField.clear();
+
+ if (fcube != null){
+ fcube.removeFromParent();
+ }
+ fcube = createFirstCube();
+
+ obstacleColors.clear();
+ obstacleColors.add(ColorRGBA.Orange);
+ obstacleColors.add(ColorRGBA.Red);
+ obstacleColors.add(ColorRGBA.Yellow);
+ renderer.setBackgroundColor(ColorRGBA.White);
+ speed = lowCap / 400f;
+ coreTime = 20.0f;
+ coreTime2 = 10.0f;
+ diffHelp=lowCap;
+ player.setLocalTranslation(0,0,0);
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ camTakeOver(tpf);
+ if (START){
+ gameLogic(tpf);
+ }
+ colorLogic();
+ }
+ /**
+ * Forcefully takes over Camera adding functionality and placing it behind the character
+ * @param tpf Tickes Per Frame
+ */
+ private void camTakeOver(float tpf) {
+ cam.setLocation(player.getLocalTranslation().add(-8, 2, 0));
+ cam.lookAt(player.getLocalTranslation(), Vector3f.UNIT_Y);
+
+ Quaternion rot = new Quaternion();
+ rot.fromAngleNormalAxis(camAngle, Vector3f.UNIT_Z);
+ cam.setRotation(cam.getRotation().mult(rot));
+ camAngle *= FastMath.pow(.99f, fpsRate * tpf);
+ }
+
+ @Override
+ public void requestClose(boolean esc) {
+ if (!esc){
+ System.out.println("The game was quit.");
+ }else{
+ System.out.println("Player has Collided. Final Score is " + Score);
+ }
+ context.destroy(false);
+ }
+ /**
+ * Randomly Places a cube on the map between 30 and 90 paces away from player
+ */
+ private void randomizeCube() {
+ Geometry cube = fcube.clone();
+ int playerX = (int) player.getLocalTranslation().getX();
+ int playerZ = (int) player.getLocalTranslation().getZ();
+// float x = FastMath.nextRandomInt(playerX + difficulty + 10, playerX + difficulty + 150);
+ float x = FastMath.nextRandomInt(playerX + difficulty + 30, playerX + difficulty + 90);
+ float z = FastMath.nextRandomInt(playerZ - difficulty - 50, playerZ + difficulty + 50);
+ cube.getLocalTranslation().set(x, 0, z);
+
+// playerX+difficulty+30,playerX+difficulty+90
+
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ if (!solidBox){
+ mat.getAdditionalRenderState().setWireframe(true);
+ }
+ mat.setColor("Color", obstacleColors.get(FastMath.nextRandomInt(0, obstacleColors.size() - 1)));
+ cube.setMaterial(mat);
+
+ rootNode.attachChild(cube);
+ cubeField.add(cube);
+ }
+
+ private Geometry createFirstCube() {
+ Vector3f loc = player.getLocalTranslation();
+ loc.addLocal(4, 0, 0);
+ Box b = new Box(1, 1, 1);
+ Geometry geom = new Geometry("Box", b);
+ geom.setLocalTranslation(loc);
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat.setColor("Color", ColorRGBA.Blue);
+ geom.setMaterial(mat);
+
+ return geom;
+ }
+
+ private Node createPlayer() {
+ Dome b = new Dome(Vector3f.ZERO, 10, 100, 1);
+ Geometry playerMesh = new Geometry("Box", b);
+
+ playerMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ playerMaterial.setColor("Color", ColorRGBA.Red);
+ playerMesh.setMaterial(playerMaterial);
+ playerMesh.setName("player");
+
+ Box floor = new Box(100, 0, 100);
+
+ Geometry floorMesh = new Geometry("Box", floor);
+
+ Vector3f translation = Vector3f.ZERO.add(playerMesh.getLocalTranslation().getX(),
+ playerMesh.getLocalTranslation().getY() - 1, 0);
+
+ floorMesh.setLocalTranslation(translation);
+
+ floorMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ floorMaterial.setColor("Color", ColorRGBA.LightGray);
+ floorMesh.setMaterial(floorMaterial);
+ floorMesh.setName("floor");
+
+ Node playerNode = new Node();
+ playerNode.attachChild(playerMesh);
+ playerNode.attachChild(floorMesh);
+
+ return playerNode;
+ }
+
+ /**
+ * If Game is Lost display Score and Reset the Game
+ */
+ private void gameLost(){
+ START = false;
+ loadText(pressStart, "You lost! Press enter to try again.", defaultFont, 0, 5, 0);
+ gameReset();
+ }
+
+ /**
+ * Core Game Logic
+ */
+ private void gameLogic(float tpf){
+ //Subtract difficulty level in accordance to speed every 10 seconds
+ if(timer.getTimeInSeconds()>=coreTime2){
+ coreTime2=timer.getTimeInSeconds()+10;
+ if(difficulty<=lowCap){
+ difficulty=lowCap;
+ }
+ else if(difficulty>lowCap){
+ difficulty-=5;
+ diffHelp+=1;
+ }
+ }
+
+ if(speed<.1f){
+ speed+=.000001f*tpf*fpsRate;
+ }
+
+ player.move(speed * tpf * fpsRate, 0, 0);
+ if (cubeField.size() > difficulty){
+ cubeField.remove(0);
+ }else if (cubeField.size() != difficulty){
+ randomizeCube();
+ }
+
+ if (cubeField.isEmpty()){
+ requestClose(false);
+ }else{
+ for (int i = 0; i < cubeField.size(); i++){
+
+ //better way to check collision
+ Geometry playerModel = (Geometry) player.getChild(0);
+ Geometry cubeModel = cubeField.get(i);
+ cubeModel.updateGeometricState();
+
+ BoundingVolume pVol = playerModel.getWorldBound();
+ BoundingVolume vVol = cubeModel.getWorldBound();
+
+ if (pVol.intersects(vVol)){
+ gameLost();
+ return;
+ }
+ //Remove cube if 10 world units behind player
+ if (cubeField.get(i).getLocalTranslation().getX() + 10 < player.getLocalTranslation().getX()){
+ cubeField.get(i).removeFromParent();
+ cubeField.remove(cubeField.get(i));
+ }
+
+ }
+ }
+
+ Score += fpsRate * tpf;
+ fpsScoreText.setText("Current Score: "+Score);
+ }
+ /**
+ * Sets up the keyboard bindings
+ */
+ private void Keys() {
+ inputManager.addMapping("START", new KeyTrigger(KeyInput.KEY_RETURN));
+ inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_LEFT));
+ inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_RIGHT));
+ inputManager.addListener(this, "START", "Left", "Right");
+ }
+
+ public void onAnalog(String binding, float value, float tpf) {
+ if (binding.equals("START") && !START){
+ START = true;
+ guiNode.detachChild(pressStart);
+ System.out.println("START");
+ }else if (START == true && binding.equals("Left")){
+ player.move(0, 0, -(speed / 2f) * value * fpsRate);
+ camAngle -= value*tpf;
+ }else if (START == true && binding.equals("Right")){
+ player.move(0, 0, (speed / 2f) * value * fpsRate);
+ camAngle += value*tpf;
+ }
+ }
+
+ /**
+ * Determines the colors of the player, floor, obstacle and background
+ */
+ private void colorLogic() {
+ if (timer.getTimeInSeconds() >= coreTime){
+
+ colorInt++;
+ coreTime = timer.getTimeInSeconds() + 20;
+
+
+ switch (colorInt){
+ case 1:
+ obstacleColors.clear();
+ solidBox = false;
+ obstacleColors.add(ColorRGBA.Green);
+ renderer.setBackgroundColor(ColorRGBA.Black);
+ playerMaterial.setColor("Color", ColorRGBA.White);
+ floorMaterial.setColor("Color", ColorRGBA.Black);
+ break;
+ case 2:
+ obstacleColors.set(0, ColorRGBA.Black);
+ solidBox = true;
+ renderer.setBackgroundColor(ColorRGBA.White);
+ playerMaterial.setColor("Color", ColorRGBA.Gray);
+ floorMaterial.setColor("Color", ColorRGBA.LightGray);
+ break;
+ case 3:
+ obstacleColors.set(0, ColorRGBA.Pink);
+ break;
+ case 4:
+ obstacleColors.set(0, ColorRGBA.Cyan);
+ obstacleColors.add(ColorRGBA.Magenta);
+ renderer.setBackgroundColor(ColorRGBA.Gray);
+ floorMaterial.setColor("Color", ColorRGBA.Gray);
+ playerMaterial.setColor("Color", ColorRGBA.White);
+ break;
+ case 5:
+ obstacleColors.remove(0);
+ renderer.setBackgroundColor(ColorRGBA.Pink);
+ solidBox = false;
+ playerMaterial.setColor("Color", ColorRGBA.White);
+ break;
+ case 6:
+ obstacleColors.set(0, ColorRGBA.White);
+ solidBox = true;
+ renderer.setBackgroundColor(ColorRGBA.Black);
+ playerMaterial.setColor("Color", ColorRGBA.Gray);
+ floorMaterial.setColor("Color", ColorRGBA.LightGray);
+ break;
+ case 7:
+ obstacleColors.set(0, ColorRGBA.Green);
+ renderer.setBackgroundColor(ColorRGBA.Gray);
+ playerMaterial.setColor("Color", ColorRGBA.Black);
+ floorMaterial.setColor("Color", ColorRGBA.Orange);
+ break;
+ case 8:
+ obstacleColors.set(0, ColorRGBA.Red);
+ floorMaterial.setColor("Color", ColorRGBA.Pink);
+ break;
+ case 9:
+ obstacleColors.set(0, ColorRGBA.Orange);
+ obstacleColors.add(ColorRGBA.Red);
+ obstacleColors.add(ColorRGBA.Yellow);
+ renderer.setBackgroundColor(ColorRGBA.White);
+ playerMaterial.setColor("Color", ColorRGBA.Red);
+ floorMaterial.setColor("Color", ColorRGBA.Gray);
+ colorInt=0;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ /**
+ * Sets up a BitmapText to be displayed
+ * @param txt the Bitmap Text
+ * @param text the
+ * @param font the font of the text
+ * @param x
+ * @param y
+ * @param z
+ */
+ private void loadText(BitmapText txt, String text, BitmapFont font, float x, float y, float z) {
+ txt.setSize(font.getCharSet().getRenderedSize());
+ txt.setLocalTranslation(txt.getLineWidth() * x, txt.getLineHeight() * y, z);
+ txt.setText(text);
+ guiNode.attachChild(txt);
+ }
+}
\ No newline at end of file
diff --git a/JmeTests/src/jme3test/games/RollingTheMonkey.java b/JmeTests/src/jme3test/games/RollingTheMonkey.java
new file mode 100644
index 0000000..b349be3
--- /dev/null
+++ b/JmeTests/src/jme3test/games/RollingTheMonkey.java
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) 2009-2017 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.games;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.bullet.BulletAppState;
+import com.jme3.bullet.PhysicsSpace;
+import com.jme3.bullet.collision.PhysicsCollisionEvent;
+import com.jme3.bullet.collision.PhysicsCollisionListener;
+import com.jme3.bullet.collision.shapes.BoxCollisionShape;
+import com.jme3.bullet.collision.shapes.CompoundCollisionShape;
+import com.jme3.bullet.collision.shapes.SphereCollisionShape;
+import com.jme3.bullet.control.GhostControl;
+import com.jme3.bullet.control.RigidBodyControl;
+import com.jme3.font.BitmapText;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.light.DirectionalLight;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.post.FilterPostProcessor;
+import com.jme3.renderer.queue.RenderQueue.ShadowMode;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.shape.Box;
+import com.jme3.scene.shape.Sphere;
+import com.jme3.shadow.DirectionalLightShadowFilter;
+import java.util.concurrent.Callable;
+
+/**
+ * Physics based marble game.
+ *
+ * @author SkidRunner (Mark E. Picknell)
+ */
+public class RollingTheMonkey extends SimpleApplication implements ActionListener, PhysicsCollisionListener {
+
+ private static final String TITLE = "Rolling The Monkey";
+ private static final String MESSAGE = "Thanks for Playing!";
+ private static final String INFO_MESSAGE = "Collect all the spinning cubes!\nPress the 'R' key any time to reset!";
+
+ private static final float PLAYER_DENSITY = 1200; // OLK(Java LOL) = 1200, STEEL = 8000, RUBBER = 1000
+ private static final float PLAYER_REST = 0.1f; // OLK = 0.1f, STEEL = 0.0f, RUBBER = 1.0f I made these up.
+
+ private static final float PLAYER_RADIUS = 2.0f;
+ private static final float PLAYER_ACCEL = 1.0f;
+
+ private static final float PICKUP_SIZE = 0.5f;
+ private static final float PICKUP_RADIUS = 15.0f;
+ private static final int PICKUP_COUNT = 16;
+ private static final float PICKUP_SPEED = 5.0f;
+
+ private static final float PLAYER_VOLUME = (FastMath.pow(PLAYER_RADIUS, 3) * FastMath.PI) / 3; // V = 4/3 * PI * R pow 3
+ private static final float PLAYER_MASS = PLAYER_DENSITY * PLAYER_VOLUME;
+ private static final float PLAYER_FORCE = 80000 * PLAYER_ACCEL; // F = M(4m diameter steel ball) * A
+ private static final Vector3f PLAYER_START = new Vector3f(0.0f, PLAYER_RADIUS * 2, 0.0f);
+
+ private static final String INPUT_MAPPING_FORWARD = "INPUT_MAPPING_FORWARD";
+ private static final String INPUT_MAPPING_BACKWARD = "INPUT_MAPPING_BACKWARD";
+ private static final String INPUT_MAPPING_LEFT = "INPUT_MAPPING_LEFT";
+ private static final String INPUT_MAPPING_RIGHT = "INPUT_MAPPING_RIGHT";
+ private static final String INPUT_MAPPING_RESET = "INPUT_MAPPING_RESET";
+
+ public static void main(String[] args) {
+ RollingTheMonkey app = new RollingTheMonkey();
+ app.start();
+ }
+
+ private boolean keyForward;
+ private boolean keyBackward;
+ private boolean keyLeft;
+ private boolean keyRight;
+
+ private PhysicsSpace space;
+
+ private RigidBodyControl player;
+ private int score;
+
+ private Node pickUps;
+
+ BitmapText infoText;
+ BitmapText scoreText;
+ BitmapText messageText;
+
+ @Override
+ public void simpleInitApp() {
+ flyCam.setEnabled(false);
+ cam.setLocation(new Vector3f(0.0f, 12.0f, 21.0f));
+ viewPort.setBackgroundColor(new ColorRGBA(0.2118f, 0.0824f, 0.6549f, 1.0f));
+
+ // init physics
+ BulletAppState bulletState = new BulletAppState();
+ stateManager.attach(bulletState);
+ space = bulletState.getPhysicsSpace();
+ space.addCollisionListener(this);
+
+ // create light
+ DirectionalLight sun = new DirectionalLight();
+ sun.setDirection((new Vector3f(-0.7f, -0.3f, -0.5f)).normalizeLocal());
+ System.out.println("Here We Go: " + sun.getDirection());
+ sun.setColor(ColorRGBA.White);
+ rootNode.addLight(sun);
+
+ // create materials
+ Material materialRed = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+ materialRed.setBoolean("UseMaterialColors",true);
+ materialRed.setBoolean("HardwareShadows", true);
+ materialRed.setColor("Diffuse", new ColorRGBA(0.9451f, 0.0078f, 0.0314f, 1.0f));
+ materialRed.setColor("Specular", ColorRGBA.White);
+ materialRed.setFloat("Shininess", 64.0f);
+
+ Material materialGreen = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+ materialGreen.setBoolean("UseMaterialColors",true);
+ materialGreen.setBoolean("HardwareShadows", true);
+ materialGreen.setColor("Diffuse", new ColorRGBA(0.0431f, 0.7725f, 0.0078f, 1.0f));
+ materialGreen.setColor("Specular", ColorRGBA.White);
+ materialGreen.setFloat("Shininess", 64.0f);
+
+ Material logoMaterial = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+ logoMaterial.setBoolean("UseMaterialColors",true);
+ logoMaterial.setBoolean("HardwareShadows", true);
+ logoMaterial.setTexture("DiffuseMap", assetManager.loadTexture("com/jme3/app/Monkey.png"));
+ logoMaterial.setColor("Diffuse", ColorRGBA.White);
+ logoMaterial.setColor("Specular", ColorRGBA.White);
+ logoMaterial.setFloat("Shininess", 32.0f);
+
+ Material materialYellow = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+ materialYellow.setBoolean("UseMaterialColors",true);
+ materialYellow.setBoolean("HardwareShadows", true);
+ materialYellow.setColor("Diffuse", new ColorRGBA(0.9529f, 0.7843f, 0.0078f, 1.0f));
+ materialYellow.setColor("Specular", ColorRGBA.White);
+ materialYellow.setFloat("Shininess", 64.0f);
+
+ // create level spatial
+ // TODO: create your own level mesh
+ Node level = new Node("level");
+ level.setShadowMode(ShadowMode.CastAndReceive);
+
+ Geometry floor = new Geometry("floor", new Box(22.0f, 0.5f, 22.0f));
+ floor.setShadowMode(ShadowMode.Receive);
+ floor.setLocalTranslation(0.0f, -0.5f, 0.0f);
+ floor.setMaterial(materialGreen);
+
+ Geometry wallNorth = new Geometry("wallNorth", new Box(22.0f, 2.0f, 0.5f));
+ wallNorth.setLocalTranslation(0.0f, 2.0f, 21.5f);
+ wallNorth.setMaterial(materialRed);
+
+ Geometry wallSouth = new Geometry("wallSouth", new Box(22.0f, 2.0f, 0.5f));
+ wallSouth.setLocalTranslation(0.0f, 2.0f, -21.5f);
+ wallSouth.setMaterial(materialRed);
+
+ Geometry wallEast = new Geometry("wallEast", new Box(0.5f, 2.0f, 21.0f));
+ wallEast.setLocalTranslation(-21.5f, 2.0f, 0.0f);
+ wallEast.setMaterial(materialRed);
+
+ Geometry wallWest = new Geometry("wallWest", new Box(0.5f, 2.0f, 21.0f));
+ wallWest.setLocalTranslation(21.5f, 2.0f, 0.0f);
+ wallWest.setMaterial(materialRed);
+
+ level.attachChild(floor);
+ level.attachChild(wallNorth);
+ level.attachChild(wallSouth);
+ level.attachChild(wallEast);
+ level.attachChild(wallWest);
+
+ // The easy way: level.addControl(new RigidBodyControl(0));
+
+ // create level Shape
+ CompoundCollisionShape levelShape = new CompoundCollisionShape();
+ BoxCollisionShape floorShape = new BoxCollisionShape(new Vector3f(22.0f, 0.5f, 22.0f));
+ BoxCollisionShape wallNorthShape = new BoxCollisionShape(new Vector3f(22.0f, 2.0f, 0.5f));
+ BoxCollisionShape wallSouthShape = new BoxCollisionShape(new Vector3f(22.0f, 2.0f, 0.5f));
+ BoxCollisionShape wallEastShape = new BoxCollisionShape(new Vector3f(0.5f, 2.0f, 21.0f));
+ BoxCollisionShape wallWestShape = new BoxCollisionShape(new Vector3f(0.5f, 2.0f, 21.0f));
+
+ levelShape.addChildShape(floorShape, new Vector3f(0.0f, -0.5f, 0.0f));
+ levelShape.addChildShape(wallNorthShape, new Vector3f(0.0f, 2.0f, -21.5f));
+ levelShape.addChildShape(wallSouthShape, new Vector3f(0.0f, 2.0f, 21.5f));
+ levelShape.addChildShape(wallEastShape, new Vector3f(-21.5f, 2.0f, 0.0f));
+ levelShape.addChildShape(wallEastShape, new Vector3f(21.5f, 2.0f, 0.0f));
+
+ level.addControl(new RigidBodyControl(levelShape, 0));
+
+ rootNode.attachChild(level);
+ space.addAll(level);
+
+ // create Pickups
+ // TODO: create your own pickUp mesh
+ // create single mesh for all pickups
+ // HINT: think particles.
+ pickUps = new Node("pickups");
+
+ Quaternion rotation = new Quaternion();
+ Vector3f translation = new Vector3f(0.0f, PICKUP_SIZE * 1.5f, -PICKUP_RADIUS);
+ int index = 0;
+ float ammount = FastMath.TWO_PI / PICKUP_COUNT;
+ for(float angle = 0; angle < FastMath.TWO_PI; angle += ammount) {
+ Geometry pickUp = new Geometry("pickUp" + (index++), new Box(PICKUP_SIZE,PICKUP_SIZE, PICKUP_SIZE));
+ pickUp.setShadowMode(ShadowMode.CastAndReceive);
+ pickUp.setMaterial(materialYellow);
+ pickUp.setLocalRotation(rotation.fromAngles(
+ FastMath.rand.nextFloat() * FastMath.TWO_PI,
+ FastMath.rand.nextFloat() * FastMath.TWO_PI,
+ FastMath.rand.nextFloat() * FastMath.TWO_PI));
+
+ rotation.fromAngles(0.0f, angle, 0.0f);
+ rotation.mult(translation, pickUp.getLocalTranslation());
+ pickUps.attachChild(pickUp);
+
+ pickUp.addControl(new GhostControl(new SphereCollisionShape(PICKUP_SIZE)));
+
+
+ space.addAll(pickUp);
+ //space.addCollisionListener(pickUpControl);
+ }
+ rootNode.attachChild(pickUps);
+
+ // Create player
+ // TODO: create your own player mesh
+ Geometry playerGeometry = new Geometry("player", new Sphere(16, 32, PLAYER_RADIUS));
+ playerGeometry.setShadowMode(ShadowMode.CastAndReceive);
+ playerGeometry.setLocalTranslation(PLAYER_START.clone());
+ playerGeometry.setMaterial(logoMaterial);
+
+ // Store control for applying forces
+ // TODO: create your own player control
+ player = new RigidBodyControl(new SphereCollisionShape(PLAYER_RADIUS), PLAYER_MASS);
+ player.setRestitution(PLAYER_REST);
+
+ playerGeometry.addControl(player);
+
+ rootNode.attachChild(playerGeometry);
+ space.addAll(playerGeometry);
+
+ inputManager.addMapping(INPUT_MAPPING_FORWARD, new KeyTrigger(KeyInput.KEY_UP)
+ , new KeyTrigger(KeyInput.KEY_W));
+ inputManager.addMapping(INPUT_MAPPING_BACKWARD, new KeyTrigger(KeyInput.KEY_DOWN)
+ , new KeyTrigger(KeyInput.KEY_S));
+ inputManager.addMapping(INPUT_MAPPING_LEFT, new KeyTrigger(KeyInput.KEY_LEFT)
+ , new KeyTrigger(KeyInput.KEY_A));
+ inputManager.addMapping(INPUT_MAPPING_RIGHT, new KeyTrigger(KeyInput.KEY_RIGHT)
+ , new KeyTrigger(KeyInput.KEY_D));
+ inputManager.addMapping(INPUT_MAPPING_RESET, new KeyTrigger(KeyInput.KEY_R));
+ inputManager.addListener(this, INPUT_MAPPING_FORWARD, INPUT_MAPPING_BACKWARD
+ , INPUT_MAPPING_LEFT, INPUT_MAPPING_RIGHT, INPUT_MAPPING_RESET);
+
+ // init UI
+ infoText = new BitmapText(guiFont, false);
+ infoText.setText(INFO_MESSAGE);
+ guiNode.attachChild(infoText);
+
+ scoreText = new BitmapText(guiFont, false);
+ scoreText.setText("Score: 0");
+ guiNode.attachChild(scoreText);
+
+ messageText = new BitmapText(guiFont, false);
+ messageText.setText(MESSAGE);
+ messageText.setLocalScale(0.0f);
+ guiNode.attachChild(messageText);
+
+ infoText.setLocalTranslation(0.0f, cam.getHeight(), 0.0f);
+ scoreText.setLocalTranslation((cam.getWidth() - scoreText.getLineWidth()) / 2.0f,
+ scoreText.getLineHeight(), 0.0f);
+ messageText.setLocalTranslation((cam.getWidth() - messageText.getLineWidth()) / 2.0f,
+ (cam.getHeight() - messageText.getLineHeight()) / 2, 0.0f);
+
+ // init shadows
+ FilterPostProcessor processor = new FilterPostProcessor(assetManager);
+ DirectionalLightShadowFilter filter = new DirectionalLightShadowFilter(assetManager, 2048, 1);
+ filter.setLight(sun);
+ processor.addFilter(filter);
+ viewPort.addProcessor(processor);
+
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ // Update and position the score
+ scoreText.setText("Score: " + score);
+ scoreText.setLocalTranslation((cam.getWidth() - scoreText.getLineWidth()) / 2.0f,
+ scoreText.getLineHeight(), 0.0f);
+
+ // Rotate all the pickups
+ float pickUpSpeed = PICKUP_SPEED * tpf;
+ for(Spatial pickUp : pickUps.getChildren()) {
+ pickUp.rotate(pickUpSpeed, pickUpSpeed, pickUpSpeed);
+ }
+
+ Vector3f centralForce = new Vector3f();
+
+ if(keyForward) centralForce.addLocal(cam.getDirection());
+ if(keyBackward) centralForce.addLocal(cam.getDirection().negate());
+ if(keyLeft) centralForce.addLocal(cam.getLeft());
+ if(keyRight) centralForce.addLocal(cam.getLeft().negate());
+
+ if(!Vector3f.ZERO.equals(centralForce)) {
+ centralForce.setY(0); // stop ball from pusing down or flying up
+ centralForce.normalizeLocal(); // normalize force
+ centralForce.multLocal(PLAYER_FORCE); // scale vector to force
+
+ player.applyCentralForce(centralForce); // apply force to player
+ }
+
+ cam.lookAt(player.getPhysicsLocation(), Vector3f.UNIT_Y);
+ }
+
+ @Override
+ public void onAction(String name, boolean isPressed, float tpf) {
+ switch(name) {
+ case INPUT_MAPPING_FORWARD:
+ keyForward = isPressed;
+ break;
+ case INPUT_MAPPING_BACKWARD:
+ keyBackward = isPressed;
+ break;
+ case INPUT_MAPPING_LEFT:
+ keyLeft = isPressed;
+ break;
+ case INPUT_MAPPING_RIGHT:
+ keyRight = isPressed;
+ break;
+ case INPUT_MAPPING_RESET:
+ enqueue(new Callable() {
+ @Override
+ public Void call() {
+ reset();
+ return null;
+ }
+ });
+ break;
+ }
+ }
+ @Override
+ public void collision(PhysicsCollisionEvent event) {
+ Spatial nodeA = event.getNodeA();
+ Spatial nodeB = event.getNodeB();
+
+ String nameA = nodeA == null ? "" : nodeA.getName();
+ String nameB = nodeB == null ? "" : nodeB.getName();
+
+ if(nameA.equals("player") && nameB.startsWith("pickUp")) {
+ GhostControl pickUpControl = nodeB.getControl(GhostControl.class);
+ if(pickUpControl != null && pickUpControl.isEnabled()) {
+ pickUpControl.setEnabled(false);
+ nodeB.removeFromParent();
+ nodeB.setLocalScale(0.0f);
+ score += 1;
+ if(score >= PICKUP_COUNT) {
+ messageText.setLocalScale(1.0f);
+ }
+ }
+ } else if(nameA.startsWith("pickUp") && nameB.equals("player")) {
+ GhostControl pickUpControl = nodeA.getControl(GhostControl.class);
+ if(pickUpControl != null && pickUpControl.isEnabled()) {
+ pickUpControl.setEnabled(false);
+ nodeA.setLocalScale(0.0f);
+ score += 1;
+ if(score >= PICKUP_COUNT) {
+ messageText.setLocalScale(1.0f);
+ }
+ }
+ }
+ }
+
+ private void reset() {
+ // Reset the pickups
+ for(Spatial pickUp : pickUps.getChildren()) {
+ GhostControl pickUpControl = pickUp.getControl(GhostControl.class);
+ if(pickUpControl != null) {
+ pickUpControl.setEnabled(true);
+ }
+ pickUp.setLocalScale(1.0f);
+ }
+ // Reset the player
+ player.setPhysicsLocation(PLAYER_START.clone());
+ player.setAngularVelocity(Vector3f.ZERO.clone());
+ player.setLinearVelocity(Vector3f.ZERO.clone());
+ // Reset the score
+ score = 0;
+ // Reset the message
+ messageText.setLocalScale(0.0f);
+ }
+
+}
diff --git a/JmeTests/src/jme3test/games/WorldOfInception.java b/JmeTests/src/jme3test/games/WorldOfInception.java
new file mode 100644
index 0000000..6e15926
--- /dev/null
+++ b/JmeTests/src/jme3test/games/WorldOfInception.java
@@ -0,0 +1,534 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.games;
+
+import com.jme3.app.Application;
+import com.jme3.app.SimpleApplication;
+import com.jme3.app.state.AbstractAppState;
+import com.jme3.app.state.AppStateManager;
+import com.jme3.bullet.BulletAppState;
+import com.jme3.bullet.collision.shapes.CollisionShape;
+import com.jme3.bullet.collision.shapes.MeshCollisionShape;
+import com.jme3.bullet.collision.shapes.SphereCollisionShape;
+import com.jme3.bullet.control.RigidBodyControl;
+import com.jme3.bullet.debug.DebugTools;
+import com.jme3.font.BitmapText;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.AnalogListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Ray;
+import com.jme3.math.Vector3f;
+import com.jme3.post.FilterPostProcessor;
+import com.jme3.post.filters.FogFilter;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Mesh;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.shape.Sphere;
+import java.util.Random;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * WorldOfInception - Find the galaxy center ;)
+ *
+ * @author normenhansen
+ */
+public class WorldOfInception extends SimpleApplication implements AnalogListener {
+
+ //Assumptions: POI radius in world == 1, only one player, vector3f hash describes enough worlds
+ private static final Logger logger = Logger.getLogger(WorldOfInception.class.getName());
+ private static final Random random = new Random(System.currentTimeMillis());
+ private static final float scaleDist = 10;
+ private static final float poiRadius = 100;
+ private static final int poiCount = 30;
+ private static Material poiMaterial;
+ private static Mesh poiMesh;
+ private static Material ballMaterial;
+ private static Mesh ballMesh;
+ private static CollisionShape poiHorizonCollisionShape;
+ private static CollisionShape poiCollisionShape;
+ private static CollisionShape ballCollisionShape;
+ private InceptionLevel currentLevel;
+ private final Vector3f walkDirection = new Vector3f();
+ private static DebugTools debugTools;
+
+ public WorldOfInception() {
+ //base level vector position hash == seed
+ super(new InceptionLevel(null, Vector3f.ZERO));
+ currentLevel = super.getStateManager().getState(InceptionLevel.class);
+ currentLevel.takeOverParent();
+ currentLevel.getRootNode().setLocalScale(Vector3f.UNIT_XYZ);
+ currentLevel.getRootNode().setLocalTranslation(Vector3f.ZERO);
+ }
+
+ public static void main(String[] args) {
+ WorldOfInception app = new WorldOfInception();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ //set far frustum only so we see the outer world longer
+ cam.setFrustumFar(10000);
+ cam.setLocation(Vector3f.ZERO);
+ debugTools = new DebugTools(assetManager);
+ rootNode.attachChild(debugTools.debugNode);
+ poiMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ poiMaterial.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg"));
+ poiMesh = new Sphere(16, 16, 1f);
+
+ ballMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ ballMaterial.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg"));
+ ballMaterial.setColor("Color", ColorRGBA.Red);
+ ballMesh = new Sphere(16, 16, 1.0f);
+
+ poiHorizonCollisionShape = new MeshCollisionShape(new Sphere(128, 128, poiRadius));
+ poiCollisionShape = new SphereCollisionShape(1f);
+ ballCollisionShape = new SphereCollisionShape(1f);
+ setupKeys();
+ setupDisplay();
+ setupFog();
+ }
+
+ private void setupKeys() {
+ inputManager.addMapping("StrafeLeft", new KeyTrigger(KeyInput.KEY_A));
+ inputManager.addMapping("StrafeRight", new KeyTrigger(KeyInput.KEY_D));
+ inputManager.addMapping("Forward", new KeyTrigger(KeyInput.KEY_W));
+ inputManager.addMapping("Back", new KeyTrigger(KeyInput.KEY_S));
+ inputManager.addMapping("StrafeUp", new KeyTrigger(KeyInput.KEY_Q));
+ inputManager.addMapping("StrafeDown", new KeyTrigger(KeyInput.KEY_Z), new KeyTrigger(KeyInput.KEY_Y));
+ inputManager.addMapping("Space", new KeyTrigger(KeyInput.KEY_SPACE));
+ inputManager.addMapping("Return", new KeyTrigger(KeyInput.KEY_RETURN));
+ inputManager.addMapping("Esc", new KeyTrigger(KeyInput.KEY_ESCAPE));
+ inputManager.addMapping("Up", new KeyTrigger(KeyInput.KEY_UP));
+ inputManager.addMapping("Down", new KeyTrigger(KeyInput.KEY_DOWN));
+ inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_LEFT));
+ inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_RIGHT));
+ inputManager.addListener(this, "StrafeLeft", "StrafeRight", "Forward", "Back", "StrafeUp", "StrafeDown", "Space", "Reset", "Esc", "Up", "Down", "Left", "Right");
+ }
+
+ private void setupDisplay() {
+ if (fpsText == null) {
+ fpsText = new BitmapText(guiFont, false);
+ }
+ fpsText.setLocalScale(0.7f, 0.7f, 0.7f);
+ fpsText.setLocalTranslation(0, fpsText.getLineHeight(), 0);
+ fpsText.setText("");
+ fpsText.setCullHint(Spatial.CullHint.Never);
+ guiNode.attachChild(fpsText);
+ }
+
+ private void setupFog() {
+ // use fog to give more sense of depth
+ FilterPostProcessor fpp;
+ FogFilter fog;
+ fpp=new FilterPostProcessor(assetManager);
+ fog=new FogFilter();
+ fog.setFogColor(new ColorRGBA(0.0f, 0.0f, 0.0f, 1.0f));
+ fog.setFogDistance(poiRadius);
+ fog.setFogDensity(2.0f);
+ fpp.addFilter(fog);
+ viewPort.addProcessor(fpp);
+ }
+
+ public void onAnalog(String name, float value, float tpf) {
+ Vector3f left = rootNode.getLocalRotation().mult(Vector3f.UNIT_X.negate());
+ Vector3f forward = rootNode.getLocalRotation().mult(Vector3f.UNIT_Z.negate());
+ Vector3f up = rootNode.getLocalRotation().mult(Vector3f.UNIT_Y);
+ //TODO: properly scale input based on current scaling level
+ tpf = tpf * (10 - (9.0f * currentLevel.getCurrentScaleAmount()));
+ if (name.equals("StrafeLeft") && value > 0) {
+ walkDirection.addLocal(left.mult(tpf));
+ } else if (name.equals("StrafeRight") && value > 0) {
+ walkDirection.addLocal(left.negate().multLocal(tpf));
+ } else if (name.equals("Forward") && value > 0) {
+ walkDirection.addLocal(forward.mult(tpf));
+ } else if (name.equals("Back") && value > 0) {
+ walkDirection.addLocal(forward.negate().multLocal(tpf));
+ } else if (name.equals("StrafeUp") && value > 0) {
+ walkDirection.addLocal(up.mult(tpf));
+ } else if (name.equals("StrafeDown") && value > 0) {
+ walkDirection.addLocal(up.negate().multLocal(tpf));
+ } else if (name.equals("Up") && value > 0) {
+ //TODO: rotate rootNode, needs to be global
+ } else if (name.equals("Down") && value > 0) {
+ } else if (name.equals("Left") && value > 0) {
+ } else if (name.equals("Right") && value > 0) {
+ } else if (name.equals("Esc")) {
+ stop();
+ }
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ currentLevel = currentLevel.getCurrentLevel();
+ currentLevel.move(walkDirection);
+ fpsText.setText("Location: " + currentLevel.getCoordinates());
+ walkDirection.set(Vector3f.ZERO);
+ }
+
+ public static class InceptionLevel extends AbstractAppState {
+
+ private final InceptionLevel parent;
+ private final Vector3f inParentPosition;
+ private SimpleApplication application;
+ private BulletAppState physicsState;
+ private Node rootNode;
+ private Vector3f playerPos;
+ private InceptionLevel currentActiveChild;
+ private InceptionLevel currentReturnLevel;
+ private float curScaleAmount = 0;
+
+ public InceptionLevel(InceptionLevel parent, Vector3f inParentPosition) {
+ this.parent = parent;
+ this.inParentPosition = inParentPosition;
+ }
+
+ @Override
+ public void update(float tpf) {
+ super.update(tpf);
+ if (currentReturnLevel != this) {
+ return;
+ }
+ debugTools.setYellowArrow(new Vector3f(0, 0, -2), playerPos.divide(poiRadius));
+ float curLocalDist = getPlayerPosition().length();
+ // If we are outside the range of one point of interest, move out to
+ // the next upper level
+ if (curLocalDist > poiRadius + FastMath.ZERO_TOLERANCE) { //DAFUQ normalize?
+ if (parent == null) {
+ //TODO: could add new nodes coming in instead for literally endless space
+ logger.log(Level.INFO, "Hit event horizon");
+ currentReturnLevel = this;
+ return;
+ }
+ //give to parent
+ logger.log(Level.INFO, "give to parent");;
+ parent.takeOverChild(inParentPosition.add(playerPos.normalize()));
+ application.getStateManager().attach(parent);
+ currentReturnLevel = parent;
+ return;
+ }
+
+ AppStateManager stateManager = application.getStateManager();
+ // We create child positions based on the parent position hash so we
+ // should in practice get the same galaxy w/o too many doubles
+ // with each run with the same root vector.
+ Vector3f[] vectors = getPositions(poiCount, inParentPosition.hashCode());
+ for (int i = 0; i < vectors.length; i++) {
+ Vector3f vector3f = vectors[i];
+ //negative rootNode location is our actual player position
+ Vector3f distVect = vector3f.subtract(playerPos);
+ float distance = distVect.length();
+ if (distance <= 1) {
+ checkActiveChild(vector3f);
+ float percent = 0;
+ curScaleAmount = 0;
+ this.scaleAsParent(percent, playerPos, distVect);
+ currentActiveChild.scaleAsChild(percent, distVect);
+ logger.log(Level.INFO, "Give over to child {0}", currentActiveChild);
+ currentActiveChild.takeOverParent();
+ stateManager.detach(this);
+ currentReturnLevel = currentActiveChild;
+ return;
+ } else if (distance <= 1 + scaleDist) {
+ debugTools.setRedArrow(Vector3f.ZERO, distVect);
+ checkActiveChild(vector3f);
+ //TODO: scale percent nicer for less of an "explosion" effect
+ float percent = 1 - mapValue(distance - 1, 0, scaleDist, 0, 1);
+ curScaleAmount = percent;
+ rootNode.getChild(i).setCullHint(Spatial.CullHint.Always);
+ this.scaleAsParent(percent, playerPos, distVect);
+ currentActiveChild.scaleAsChild(percent, distVect);
+ currentReturnLevel = this;
+ return;
+ } else if (currentActiveChild != null && currentActiveChild.getPositionInParent().equals(vector3f)) {
+ //TODO: doing this here causes problems when close to multiple pois
+ rootNode.getChild(i).setCullHint(Spatial.CullHint.Inherit);
+ }
+ }
+ checkActiveChild(null);
+ curScaleAmount = 0;
+ rootNode.setLocalScale(1);
+ rootNode.setLocalTranslation(playerPos.negate());
+ debugTools.setRedArrow(Vector3f.ZERO, Vector3f.ZERO);
+ debugTools.setBlueArrow(Vector3f.ZERO, Vector3f.ZERO);
+ debugTools.setGreenArrow(Vector3f.ZERO, Vector3f.ZERO);
+ }
+
+ private void checkActiveChild(Vector3f vector3f) {
+ AppStateManager stateManager = application.getStateManager();
+ if(vector3f == null){
+ if(currentActiveChild != null){
+ logger.log(Level.INFO, "Detach child {0}", currentActiveChild);
+ stateManager.detach(currentActiveChild);
+ currentActiveChild = null;
+ }
+ return;
+ }
+ if (currentActiveChild == null) {
+ currentActiveChild = new InceptionLevel(this, vector3f);
+ stateManager.attach(currentActiveChild);
+ logger.log(Level.INFO, "Attach child {0}", currentActiveChild);
+ } else if (!currentActiveChild.getPositionInParent().equals(vector3f)) {
+ logger.log(Level.INFO, "Switching from child {0}", currentActiveChild);
+ stateManager.detach(currentActiveChild);
+ currentActiveChild = new InceptionLevel(this, vector3f);
+ stateManager.attach(currentActiveChild);
+ logger.log(Level.INFO, "Attach child {0}", currentActiveChild);
+ }
+ }
+
+ private void scaleAsChild(float percent, Vector3f dist) {
+ float childScale = mapValue(percent, 1.0f / poiRadius, 1);
+ Vector3f distToHorizon = dist.normalize();
+ Vector3f scaledDistToHorizon = distToHorizon.mult(childScale * poiRadius);
+ Vector3f rootOff = dist.add(scaledDistToHorizon);
+ debugTools.setBlueArrow(Vector3f.ZERO, rootOff);
+ getRootNode().setLocalScale(childScale);
+ getRootNode().setLocalTranslation(rootOff);
+ //prepare player position already
+ Vector3f playerPosition = dist.normalize().mult(-poiRadius);
+ setPlayerPosition(playerPosition);
+ }
+
+ private void scaleAsParent(float percent, Vector3f playerPos, Vector3f dist) {
+ float scale = mapValue(percent, 1.0f, poiRadius);
+ Vector3f distToHorizon = dist.subtract(dist.normalize());
+ Vector3f offLocation = playerPos.add(distToHorizon);
+ Vector3f rootOff = offLocation.mult(scale).negate();
+ rootOff.addLocal(dist);
+ debugTools.setGreenArrow(Vector3f.ZERO, offLocation);
+ getRootNode().setLocalScale(scale);
+ getRootNode().setLocalTranslation(rootOff);
+ }
+
+ public void takeOverParent() {
+ //got playerPos from scaleAsChild before
+ getPlayerPosition().normalizeLocal().multLocal(poiRadius);
+ currentReturnLevel = this;
+ }
+
+ public void takeOverChild(Vector3f playerPos) {
+ this.playerPos.set(playerPos);
+ currentReturnLevel = this;
+ }
+
+ public InceptionLevel getLastLevel(Ray pickRay) {
+ // TODO: get a level based on positions getting ever more accurate,
+ // from any given position
+ return null;
+ }
+
+ public InceptionLevel getLevel(Vector3f... location) {
+ // TODO: get a level based on positions getting ever more accurate,
+ // from any given position
+ return null;
+ }
+
+ private void initData() {
+ getRootNode();
+ physicsState = new BulletAppState();
+ physicsState.startPhysics();
+ physicsState.getPhysicsSpace().setGravity(Vector3f.ZERO);
+ //horizon
+ physicsState.getPhysicsSpace().add(new RigidBodyControl(poiHorizonCollisionShape, 0));
+ int hashCode = inParentPosition.hashCode();
+ Vector3f[] positions = getPositions(poiCount, hashCode);
+ for (int i = 0; i < positions.length; i++) {
+ Vector3f vector3f = positions[i];
+ Geometry poiGeom = new Geometry("poi", poiMesh);
+ poiGeom.setLocalTranslation(vector3f);
+ poiGeom.setMaterial(poiMaterial);
+ RigidBodyControl control = new RigidBodyControl(poiCollisionShape, 0);
+ //!!! Important
+ control.setApplyPhysicsLocal(true);
+ poiGeom.addControl(control);
+ physicsState.getPhysicsSpace().add(poiGeom);
+ rootNode.attachChild(poiGeom);
+
+ }
+ //add balls after so first 10 geoms == locations
+ for (int i = 0; i < positions.length; i++) {
+ Vector3f vector3f = positions[i];
+ Geometry ball = getRandomBall(vector3f);
+ physicsState.getPhysicsSpace().add(ball);
+ rootNode.attachChild(ball);
+ }
+
+ }
+
+ private Geometry getRandomBall(Vector3f location) {
+ Vector3f localLocation = new Vector3f();
+ localLocation.set(location);
+ localLocation.addLocal(new Vector3f(random.nextFloat() - 0.5f, random.nextFloat() - 0.5f, random.nextFloat() - 0.5f).normalize().mult(3));
+ Geometry poiGeom = new Geometry("ball", ballMesh);
+ poiGeom.setLocalTranslation(localLocation);
+ poiGeom.setMaterial(ballMaterial);
+ RigidBodyControl control = new RigidBodyControl(ballCollisionShape, 1);
+ //!!! Important
+ control.setApplyPhysicsLocal(true);
+ poiGeom.addControl(control);
+ float x = (random.nextFloat() - 0.5f) * 100;
+ float y = (random.nextFloat() - 0.5f) * 100;
+ float z = (random.nextFloat() - 0.5f) * 100;
+ control.setLinearVelocity(new Vector3f(x, y, z));
+ return poiGeom;
+ }
+
+ private void cleanupData() {
+ physicsState.stopPhysics();
+ //TODO: remove all objects?
+ physicsState = null;
+ rootNode = null;
+ }
+
+ @Override
+ public void initialize(AppStateManager stateManager, Application app) {
+ super.initialize(stateManager, app);
+ //only generate data and attach node when we are actually attached (or picking)
+ initData();
+ application = (SimpleApplication) app;
+ application.getRootNode().attachChild(getRootNode());
+ application.getStateManager().attach(physicsState);
+ }
+
+ @Override
+ public void cleanup() {
+ super.cleanup();
+ //detach everything when we are detached
+ application.getRootNode().detachChild(rootNode);
+ application.getStateManager().detach(physicsState);
+ cleanupData();
+ }
+
+ public Node getRootNode() {
+ if (rootNode == null) {
+ rootNode = new Node("ZoomLevel");
+ if (parent != null) {
+ rootNode.setLocalScale(1.0f / poiRadius);
+ }
+ }
+ return rootNode;
+ }
+
+ public Vector3f getPositionInParent() {
+ return inParentPosition;
+ }
+
+ public Vector3f getPlayerPosition() {
+ if (playerPos == null) {
+ playerPos = new Vector3f();
+ }
+ return playerPos;
+ }
+
+ public void setPlayerPosition(Vector3f vec) {
+ if (playerPos == null) {
+ playerPos = new Vector3f();
+ }
+ playerPos.set(vec);
+ }
+
+ public void move(Vector3f dir) {
+ if (playerPos == null) {
+ playerPos = new Vector3f();
+ }
+ playerPos.addLocal(dir);
+ }
+
+ public float getCurrentScaleAmount() {
+ return curScaleAmount;
+ }
+
+ public InceptionLevel getParent() {
+ return parent;
+ }
+
+ public InceptionLevel getCurrentLevel() {
+ return currentReturnLevel;
+ }
+
+ public String getCoordinates() {
+ InceptionLevel cur = this;
+ StringBuilder strb = new StringBuilder();
+ strb.insert(0, this.getPlayerPosition());
+ strb.insert(0, this.getPositionInParent() + " / ");
+ cur = cur.getParent();
+ while (cur != null) {
+ strb.insert(0, cur.getPositionInParent() + " / ");
+ cur = cur.getParent();
+ }
+ return strb.toString();
+ }
+ }
+
+ public static Vector3f[] getPositions(int count, long seed) {
+ Random rnd = new Random(seed);
+ Vector3f[] vectors = new Vector3f[count];
+ for (int i = 0; i < count; i++) {
+ vectors[i] = new Vector3f((rnd.nextFloat() - 0.5f) * poiRadius,
+ (rnd.nextFloat() - 0.5f) * poiRadius,
+ (rnd.nextFloat() - 0.5f) * poiRadius);
+ }
+ return vectors;
+ }
+
+ /**
+ * Maps a value from 0-1 to a range from min to max.
+ *
+ * @param x
+ * @param min
+ * @param max
+ * @return
+ */
+ public static float mapValue(float x, float min, float max) {
+ return mapValue(x, 0, 1, min, max);
+ }
+
+ /**
+ * Maps a value from inputMin to inputMax to a range from min to max.
+ *
+ * @param x
+ * @param inputMin
+ * @param inputMax
+ * @param min
+ * @param max
+ * @return
+ */
+ public static float mapValue(float x, float inputMin, float inputMax, float min, float max) {
+ return (x - inputMin) * (max - min) / (inputMax - inputMin) + min;
+ }
+}
diff --git a/JmeTests/src/jme3test/gui/TestBitmapFont.java b/JmeTests/src/jme3test/gui/TestBitmapFont.java
new file mode 100644
index 0000000..11fc69a
--- /dev/null
+++ b/JmeTests/src/jme3test/gui/TestBitmapFont.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.gui;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.font.BitmapFont;
+import com.jme3.font.BitmapText;
+import com.jme3.font.LineWrapMode;
+import com.jme3.font.Rectangle;
+import com.jme3.input.KeyInput;
+import com.jme3.input.RawInputListener;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.input.event.*;
+
+public class TestBitmapFont extends SimpleApplication {
+
+ private String txtB =
+ "ABCDEFGHIKLMNOPQRSTUVWXYZ1234567 890`~!@#$%^&*()-=_+[]\\;',./{}|:<>?";
+
+ private BitmapText txt;
+ private BitmapText txt2;
+ private BitmapText txt3;
+
+ public static void main(String[] args){
+ TestBitmapFont app = new TestBitmapFont();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ inputManager.addMapping("WordWrap", new KeyTrigger(KeyInput.KEY_TAB));
+ inputManager.addListener(keyListener, "WordWrap");
+ inputManager.addRawInputListener(textListener);
+
+ BitmapFont fnt = assetManager.loadFont("Interface/Fonts/Default.fnt");
+ txt = new BitmapText(fnt, false);
+ txt.setBox(new Rectangle(0, 0, settings.getWidth(), settings.getHeight()));
+ txt.setSize(fnt.getPreferredSize() * 2f);
+ txt.setText(txtB);
+ txt.setLocalTranslation(0, txt.getHeight(), 0);
+ guiNode.attachChild(txt);
+
+ txt2 = new BitmapText(fnt, false);
+ txt2.setSize(fnt.getPreferredSize() * 1.2f);
+ txt2.setText("Text without restriction. \nText without restriction. Text without restriction. Text without restriction");
+ txt2.setLocalTranslation(0, txt2.getHeight(), 0);
+ guiNode.attachChild(txt2);
+
+ txt3 = new BitmapText(fnt, false);
+ txt3.setBox(new Rectangle(0, 0, settings.getWidth(), 0));
+ txt3.setText("Press Tab to toggle word-wrap. type text and enter to input text");
+ txt3.setLocalTranslation(0, settings.getHeight()/2, 0);
+ guiNode.attachChild(txt3);
+ }
+
+ private ActionListener keyListener = new ActionListener() {
+ @Override
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if (name.equals("WordWrap") && !isPressed) {
+ txt.setLineWrapMode( txt.getLineWrapMode() == LineWrapMode.Word ?
+ LineWrapMode.NoWrap : LineWrapMode.Word );
+ }
+ }
+ };
+
+ private RawInputListener textListener = new RawInputListener() {
+ private StringBuilder str = new StringBuilder();
+
+ @Override
+ public void onMouseMotionEvent(MouseMotionEvent evt) { }
+
+ @Override
+ public void onMouseButtonEvent(MouseButtonEvent evt) { }
+
+ @Override
+ public void onKeyEvent(KeyInputEvent evt) {
+ if (evt.isReleased())
+ return;
+ if (evt.getKeyChar() == '\n' || evt.getKeyChar() == '\r') {
+ txt3.setText(str.toString());
+ str.setLength(0);
+ } else {
+ str.append(evt.getKeyChar());
+ }
+ }
+
+ @Override
+ public void onJoyButtonEvent(JoyButtonEvent evt) { }
+
+ @Override
+ public void onJoyAxisEvent(JoyAxisEvent evt) { }
+
+ @Override
+ public void endInput() { }
+
+ @Override
+ public void beginInput() { }
+
+ @Override
+ public void onTouchEvent(TouchEvent evt) { }
+
+ };
+
+}
diff --git a/JmeTests/src/jme3test/gui/TestBitmapText3D.java b/JmeTests/src/jme3test/gui/TestBitmapText3D.java
new file mode 100644
index 0000000..ce32e7a
--- /dev/null
+++ b/JmeTests/src/jme3test/gui/TestBitmapText3D.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.gui;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.font.BitmapFont;
+import com.jme3.font.BitmapText;
+import com.jme3.font.Rectangle;
+import com.jme3.renderer.queue.RenderQueue.Bucket;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Quad;
+
+public class TestBitmapText3D extends SimpleApplication {
+
+ private String txtB =
+ "ABCDEFGHIKLMNOPQRSTUVWXYZ1234567890`~!@#$%^&*()-=_+[]\\;',./{}|:<>?";
+
+ public static void main(String[] args){
+ TestBitmapText3D app = new TestBitmapText3D();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ Quad q = new Quad(6, 3);
+ Geometry g = new Geometry("quad", q);
+ g.setLocalTranslation(0, -3, -0.0001f);
+ g.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m"));
+ rootNode.attachChild(g);
+
+ BitmapFont fnt = assetManager.loadFont("Interface/Fonts/Default.fnt");
+ BitmapText txt = new BitmapText(fnt, false);
+ txt.setBox(new Rectangle(0, 0, 6, 3));
+ txt.setQueueBucket(Bucket.Transparent);
+ txt.setSize( 0.5f );
+ txt.setText(txtB);
+ rootNode.attachChild(txt);
+ }
+
+}
diff --git a/JmeTests/src/jme3test/gui/TestCursor.java b/JmeTests/src/jme3test/gui/TestCursor.java
new file mode 100644
index 0000000..d2b10fc
--- /dev/null
+++ b/JmeTests/src/jme3test/gui/TestCursor.java
@@ -0,0 +1,77 @@
+package jme3test.gui;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.cursors.plugins.JmeCursor;
+import java.util.ArrayList;
+
+/**
+ * This test class demonstrate how to change cursor in jME3.
+ *
+ * NOTE: This will not work on Android as it does not support cursors.
+ *
+ * Cursor test
+ * @author MadJack
+ */
+public class TestCursor extends SimpleApplication {
+
+ private ArrayList cursors = new ArrayList();
+ private long sysTime;
+ private int count = 0;
+
+ public static void main(String[] args){
+ TestCursor app = new TestCursor();
+
+ app.setShowSettings(false);
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ flyCam.setEnabled(false);
+ // We need the cursor to be visible. If it is not visible the cursor
+ // will still be "used" and loaded, you just won't see it on the screen.
+ inputManager.setCursorVisible(true);
+
+ /*
+ * To make jME3 use a custom cursor it is as simple as putting the
+ * .cur/.ico/.ani file in an asset directory. Here we use
+ * "Textures/GUI/Cursors".
+ *
+ * For the purpose of this demonstration we load 3 different cursors and add them
+ * into an array list and switch cursor every 8 seconds.
+ *
+ * The first ico has been made by Sirea and the set can be found here:
+ * http://www.rw-designer.com/icon-set/nyan-cat
+ *
+ * The second cursor has been made by Virum64 and is Public Domain.
+ * http://www.rw-designer.com/cursor-set/memes-faces-v64
+ *
+ * The animated cursor has been made by Pointer Adic and can be found here:
+ * http://www.rw-designer.com/cursor-set/monkey
+ */
+ cursors.add((JmeCursor) assetManager.loadAsset("Textures/Cursors/meme.cur"));
+ cursors.add((JmeCursor) assetManager.loadAsset("Textures/Cursors/nyancat.ico"));
+ cursors.add((JmeCursor) assetManager.loadAsset("Textures/Cursors/monkey.ani"));
+
+ sysTime = System.currentTimeMillis();
+ inputManager.setMouseCursor(cursors.get(count));
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ long currentTime = System.currentTimeMillis();
+
+ if (currentTime - sysTime > 8000) {
+ count++;
+ if (count >= cursors.size()) {
+ count = 0;
+ }
+ sysTime = currentTime;
+ // 8 seconds have passed,
+ // tell jME3 to swith to a different cursor.
+ inputManager.setMouseCursor(cursors.get(count));
+ }
+
+ }
+}
+
diff --git a/JmeTests/src/jme3test/gui/TestOrtho.java b/JmeTests/src/jme3test/gui/TestOrtho.java
new file mode 100644
index 0000000..2e252aa
--- /dev/null
+++ b/JmeTests/src/jme3test/gui/TestOrtho.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.gui;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.ui.Picture;
+
+public class TestOrtho extends SimpleApplication {
+
+ public static void main(String[] args){
+ TestOrtho app = new TestOrtho();
+ app.start();
+ }
+
+ public void simpleInitApp() {
+ Picture p = new Picture("Picture");
+ p.move(0, 0, -1); // make it appear behind stats view
+ p.setPosition(0, 0);
+ p.setWidth(settings.getWidth());
+ p.setHeight(settings.getHeight());
+ p.setImage(assetManager, "Interface/Logo/Monkey.png", false);
+
+ // attach geometry to orthoNode
+ guiNode.attachChild(p);
+ }
+
+}
diff --git a/JmeTests/src/jme3test/gui/TestSoftwareMouse.java b/JmeTests/src/jme3test/gui/TestSoftwareMouse.java
new file mode 100644
index 0000000..44bee28
--- /dev/null
+++ b/JmeTests/src/jme3test/gui/TestSoftwareMouse.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.gui;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.input.RawInputListener;
+import com.jme3.input.event.*;
+import com.jme3.math.FastMath;
+import com.jme3.system.AppSettings;
+import com.jme3.texture.Texture;
+import com.jme3.texture.Texture2D;
+import com.jme3.ui.Picture;
+
+public class TestSoftwareMouse extends SimpleApplication {
+
+ private Picture cursor;
+
+ private RawInputListener inputListener = new RawInputListener() {
+
+ private float x = 0, y = 0;
+
+ public void beginInput() {
+ }
+ public void endInput() {
+ }
+ public void onJoyAxisEvent(JoyAxisEvent evt) {
+ }
+ public void onJoyButtonEvent(JoyButtonEvent evt) {
+ }
+ public void onMouseMotionEvent(MouseMotionEvent evt) {
+ x += evt.getDX();
+ y += evt.getDY();
+
+ // Prevent mouse from leaving screen
+ AppSettings settings = TestSoftwareMouse.this.settings;
+ x = FastMath.clamp(x, 0, settings.getWidth());
+ y = FastMath.clamp(y, 0, settings.getHeight());
+
+ // adjust for hotspot
+ cursor.setPosition(x, y - 64);
+ }
+ public void onMouseButtonEvent(MouseButtonEvent evt) {
+ }
+ public void onKeyEvent(KeyInputEvent evt) {
+ }
+ public void onTouchEvent(TouchEvent evt) {
+ }
+ };
+
+ public static void main(String[] args){
+ TestSoftwareMouse app = new TestSoftwareMouse();
+
+// AppSettings settings = new AppSettings(true);
+// settings.setFrameRate(60);
+// app.setSettings(settings);
+
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ flyCam.setEnabled(false);
+// inputManager.setCursorVisible(false);
+
+ Texture tex = assetManager.loadTexture("Interface/Logo/Cursor.png");
+
+ cursor = new Picture("cursor");
+ cursor.setTexture(assetManager, (Texture2D) tex, true);
+ cursor.setWidth(64);
+ cursor.setHeight(64);
+ guiNode.attachChild(cursor);
+
+ inputManager.addRawInputListener(inputListener);
+
+// Image img = tex.getImage();
+// ByteBuffer data = img.getData(0);
+// IntBuffer image = BufferUtils.createIntBuffer(64 * 64);
+// for (int y = 0; y < 64; y++){
+// for (int x = 0; x < 64; x++){
+// int rgba = data.getInt();
+// image.put(rgba);
+// }
+// }
+// image.clear();
+//
+// try {
+// Cursor cur = new Cursor(64, 64, 2, 62, 1, image, null);
+// Mouse.setNativeCursor(cur);
+// } catch (LWJGLException ex) {
+// Logger.getLogger(TestSoftwareMouse.class.getName()).log(Level.SEVERE, null, ex);
+// }
+ }
+}
diff --git a/JmeTests/src/jme3test/gui/TestZOrder.java b/JmeTests/src/jme3test/gui/TestZOrder.java
new file mode 100644
index 0000000..5a5683f
--- /dev/null
+++ b/JmeTests/src/jme3test/gui/TestZOrder.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.gui;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.ui.Picture;
+
+public class TestZOrder extends SimpleApplication {
+
+ public static void main(String[] args){
+ TestZOrder app = new TestZOrder();
+ app.start();
+ }
+
+ public void simpleInitApp() {
+ Picture p = new Picture("Picture1");
+ p.move(0,0,-1);
+ p.setPosition(100, 100);
+ p.setWidth(100);
+ p.setHeight(100);
+ p.setImage(assetManager, "Interface/Logo/Monkey.png", false);
+ guiNode.attachChild(p);
+
+ Picture p2 = new Picture("Picture2");
+ p2.move(0,0,1.001f);
+ p2.setPosition(150, 150);
+ p2.setWidth(100);
+ p2.setHeight(100);
+ p2.setImage(assetManager, "Interface/Logo/Monkey.png", false);
+ guiNode.attachChild(p2);
+ }
+
+}
diff --git a/JmeTests/src/jme3test/helloworld/HelloAnimation.java b/JmeTests/src/jme3test/helloworld/HelloAnimation.java
new file mode 100644
index 0000000..bb1587b
--- /dev/null
+++ b/JmeTests/src/jme3test/helloworld/HelloAnimation.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.helloworld;
+
+import com.jme3.animation.AnimChannel;
+import com.jme3.animation.AnimControl;
+import com.jme3.animation.AnimEventListener;
+import com.jme3.animation.LoopMode;
+import com.jme3.app.SimpleApplication;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.light.DirectionalLight;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Node;
+
+/** Sample 7 - how to load an OgreXML model and play an animation,
+ * using channels, a controller, and an AnimEventListener. */
+public class HelloAnimation extends SimpleApplication
+ implements AnimEventListener {
+
+ Node player;
+ private AnimChannel channel;
+ private AnimControl control;
+
+ public static void main(String[] args) {
+ HelloAnimation app = new HelloAnimation();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ viewPort.setBackgroundColor(ColorRGBA.LightGray);
+ initKeys();
+
+ /** Add a light source so we can see the model */
+ DirectionalLight dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(-0.1f, -1f, -1).normalizeLocal());
+ rootNode.addLight(dl);
+
+ /** Load a model that contains animation */
+ player = (Node) assetManager.loadModel("Models/Oto/Oto.mesh.xml");
+ player.setLocalScale(0.5f);
+ rootNode.attachChild(player);
+
+ /** Create a controller and channels. */
+ control = player.getControl(AnimControl.class);
+ control.addListener(this);
+ channel = control.createChannel();
+ channel.setAnim("stand");
+ }
+
+ /** Use this listener to trigger something after an animation is done. */
+ public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) {
+ if (animName.equals("Walk")) {
+ /** After "walk", reset to "stand". */
+ channel.setAnim("stand", 0.50f);
+ channel.setLoopMode(LoopMode.DontLoop);
+ channel.setSpeed(1f);
+ }
+ }
+
+ /** Use this listener to trigger something between two animations. */
+ public void onAnimChange(AnimControl control, AnimChannel channel, String animName) {
+ // unused
+ }
+
+ /** Custom Keybindings: Mapping a named action to a key input. */
+ private void initKeys() {
+ inputManager.addMapping("Walk", new KeyTrigger(KeyInput.KEY_SPACE));
+ inputManager.addListener(actionListener, "Walk");
+ }
+
+ /** Definining the named action that can be triggered by key inputs. */
+ private ActionListener actionListener = new ActionListener() {
+ public void onAction(String name, boolean keyPressed, float tpf) {
+ if (name.equals("Walk") && !keyPressed) {
+ if (!channel.getAnimationName().equals("Walk")) {
+ /** Play the "walk" animation! */
+ channel.setAnim("Walk", 0.50f);
+ channel.setLoopMode(LoopMode.Loop);
+ }
+ }
+ }
+ };
+
+}
diff --git a/JmeTests/src/jme3test/helloworld/HelloAssets.java b/JmeTests/src/jme3test/helloworld/HelloAssets.java
new file mode 100644
index 0000000..4fb4738
--- /dev/null
+++ b/JmeTests/src/jme3test/helloworld/HelloAssets.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.helloworld;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.font.BitmapText;
+import com.jme3.light.DirectionalLight;
+import com.jme3.material.Material;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.shape.Box;
+
+/** Sample 3 - how to load an OBJ model, and OgreXML model,
+ * a material/texture, or text. */
+public class HelloAssets extends SimpleApplication {
+
+ public static void main(String[] args) {
+ HelloAssets app = new HelloAssets();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+
+ /** Load a teapot model (OBJ file from test-data) */
+ Spatial teapot = assetManager.loadModel("Models/Teapot/Teapot.obj");
+ Material mat_default = new Material( assetManager, "Common/MatDefs/Misc/ShowNormals.j3md");
+ teapot.setMaterial(mat_default);
+ rootNode.attachChild(teapot);
+
+ /** Create a wall (Box with material and texture from test-data) */
+ Box box = new Box(2.5f, 2.5f, 1.0f);
+ Spatial wall = new Geometry("Box", box );
+ Material mat_brick = new Material( assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat_brick.setTexture("ColorMap", assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg"));
+ wall.setMaterial(mat_brick);
+ wall.setLocalTranslation(2.0f,-2.5f,0.0f);
+ rootNode.attachChild(wall);
+
+ /** Display a line of text (default font from test-data) */
+ setDisplayStatView(false);
+ guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
+ BitmapText helloText = new BitmapText(guiFont, false);
+ helloText.setSize(guiFont.getCharSet().getRenderedSize());
+ helloText.setText("Hello World");
+ helloText.setLocalTranslation(300, helloText.getLineHeight(), 0);
+ guiNode.attachChild(helloText);
+
+ /** Load a Ninja model (OgreXML + material + texture from test_data) */
+ Spatial ninja = assetManager.loadModel("Models/Ninja/Ninja.mesh.xml");
+ ninja.scale(0.05f, 0.05f, 0.05f);
+ ninja.rotate(0.0f, -3.0f, 0.0f);
+ ninja.setLocalTranslation(0.0f, -5.0f, -2.0f);
+ rootNode.attachChild(ninja);
+ /** You must add a light to make the model visible */
+ DirectionalLight sun = new DirectionalLight();
+ sun.setDirection(new Vector3f(-0.1f, -0.7f, -1.0f).normalizeLocal());
+ rootNode.addLight(sun);
+ }
+}
diff --git a/JmeTests/src/jme3test/helloworld/HelloAudio.java b/JmeTests/src/jme3test/helloworld/HelloAudio.java
new file mode 100644
index 0000000..bc13e01
--- /dev/null
+++ b/JmeTests/src/jme3test/helloworld/HelloAudio.java
@@ -0,0 +1,86 @@
+package jme3test.helloworld;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.audio.AudioData.DataType;
+import com.jme3.audio.AudioNode;
+import com.jme3.input.MouseInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.MouseButtonTrigger;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Box;
+
+/** Sample 11 - playing 3D audio. */
+public class HelloAudio extends SimpleApplication {
+
+ private AudioNode audio_gun;
+ private AudioNode audio_nature;
+ private Geometry player;
+
+ public static void main(String[] args) {
+ HelloAudio app = new HelloAudio();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ flyCam.setMoveSpeed(40);
+
+ /** just a blue box floating in space */
+ Box box1 = new Box(1, 1, 1);
+ player = new Geometry("Player", box1);
+ Material mat1 = new Material(assetManager,"Common/MatDefs/Misc/Unshaded.j3md");
+ mat1.setColor("Color", ColorRGBA.Blue);
+ player.setMaterial(mat1);
+ rootNode.attachChild(player);
+
+ /** custom init methods, see below */
+ initKeys();
+ initAudio();
+ }
+
+ /** We create two audio nodes. */
+ private void initAudio() {
+ /* gun shot sound is to be triggered by a mouse click. */
+ audio_gun = new AudioNode(assetManager,
+ "Sound/Effects/Gun.wav", DataType.Buffer);
+ audio_gun.setPositional(false);
+ audio_gun.setLooping(false);
+ audio_gun.setVolume(2);
+ rootNode.attachChild(audio_gun);
+
+ /* nature sound - keeps playing in a loop. */
+ audio_nature = new AudioNode(assetManager,
+ "Sound/Environment/Ocean Waves.ogg", DataType.Stream);
+ audio_nature.setLooping(true); // activate continuous playing
+ audio_nature.setPositional(true);
+ audio_nature.setVolume(3);
+ rootNode.attachChild(audio_nature);
+ audio_nature.play(); // play continuously!
+ }
+
+ /** Declaring "Shoot" action, mapping it to a trigger (mouse left click). */
+ private void initKeys() {
+ inputManager.addMapping("Shoot", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
+ inputManager.addListener(actionListener, "Shoot");
+ }
+
+ /** Defining the "Shoot" action: Play a gun sound. */
+ private ActionListener actionListener = new ActionListener() {
+ @Override
+ public void onAction(String name, boolean keyPressed, float tpf) {
+ if (name.equals("Shoot") && !keyPressed) {
+ audio_gun.playInstance(); // play each instance once!
+ }
+ }
+ };
+
+ /** Move the listener with the a camera - for 3D audio. */
+ @Override
+ public void simpleUpdate(float tpf) {
+ listener.setLocation(cam.getLocation());
+ listener.setRotation(cam.getRotation());
+ }
+
+}
diff --git a/JmeTests/src/jme3test/helloworld/HelloCollision.java b/JmeTests/src/jme3test/helloworld/HelloCollision.java
new file mode 100644
index 0000000..60db3b0
--- /dev/null
+++ b/JmeTests/src/jme3test/helloworld/HelloCollision.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.helloworld;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.asset.plugins.ZipLocator;
+import com.jme3.bullet.BulletAppState;
+import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
+import com.jme3.bullet.collision.shapes.CollisionShape;
+import com.jme3.bullet.control.CharacterControl;
+import com.jme3.bullet.control.RigidBodyControl;
+import com.jme3.bullet.util.CollisionShapeFactory;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.light.AmbientLight;
+import com.jme3.light.DirectionalLight;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+
+/**
+ * Example 9 - How to make walls and floors solid.
+ * This collision code uses Physics and a custom Action Listener.
+ * @author normen, with edits by Zathras
+ */
+public class HelloCollision extends SimpleApplication
+ implements ActionListener {
+
+ private Spatial sceneModel;
+ private BulletAppState bulletAppState;
+ private RigidBodyControl landscape;
+ private CharacterControl player;
+ private Vector3f walkDirection = new Vector3f();
+ private boolean left = false, right = false, up = false, down = false;
+
+ //Temporary vectors used on each frame.
+ //They here to avoid instanciating new vectors on each frame
+ private Vector3f camDir = new Vector3f();
+ private Vector3f camLeft = new Vector3f();
+
+ public static void main(String[] args) {
+ HelloCollision app = new HelloCollision();
+ app.start();
+ }
+
+ public void simpleInitApp() {
+ /** Set up Physics */
+ bulletAppState = new BulletAppState();
+ stateManager.attach(bulletAppState);
+ //bulletAppState.getPhysicsSpace().enableDebug(assetManager);
+
+ // We re-use the flyby camera for rotation, while positioning is handled by physics
+ viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f));
+ flyCam.setMoveSpeed(100);
+ setUpKeys();
+ setUpLight();
+
+ // We load the scene from the zip file and adjust its size.
+ assetManager.registerLocator("town.zip", ZipLocator.class);
+ sceneModel = assetManager.loadModel("main.scene");
+ sceneModel.setLocalScale(2f);
+
+ // We set up collision detection for the scene by creating a
+ // compound collision shape and a static RigidBodyControl with mass zero.
+ CollisionShape sceneShape =
+ CollisionShapeFactory.createMeshShape((Node) sceneModel);
+ landscape = new RigidBodyControl(sceneShape, 0);
+ sceneModel.addControl(landscape);
+
+ // We set up collision detection for the player by creating
+ // a capsule collision shape and a CharacterControl.
+ // The CharacterControl offers extra settings for
+ // size, stepheight, jumping, falling, and gravity.
+ // We also put the player in its starting position.
+ CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(1.5f, 6f, 1);
+ player = new CharacterControl(capsuleShape, 0.05f);
+ player.setJumpSpeed(20);
+ player.setFallSpeed(30);
+ player.setGravity(30);
+ player.setPhysicsLocation(new Vector3f(0, 10, 0));
+
+ // We attach the scene and the player to the rootnode and the physics space,
+ // to make them appear in the game world.
+ rootNode.attachChild(sceneModel);
+ bulletAppState.getPhysicsSpace().add(landscape);
+ bulletAppState.getPhysicsSpace().add(player);
+ }
+
+ private void setUpLight() {
+ // We add light so we see the scene
+ AmbientLight al = new AmbientLight();
+ al.setColor(ColorRGBA.White.mult(1.3f));
+ rootNode.addLight(al);
+
+ DirectionalLight dl = new DirectionalLight();
+ dl.setColor(ColorRGBA.White);
+ dl.setDirection(new Vector3f(2.8f, -2.8f, -2.8f).normalizeLocal());
+ rootNode.addLight(dl);
+ }
+
+ /** We over-write some navigational key mappings here, so we can
+ * add physics-controlled walking and jumping: */
+ private void setUpKeys() {
+ inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_A));
+ inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_D));
+ inputManager.addMapping("Up", new KeyTrigger(KeyInput.KEY_W));
+ inputManager.addMapping("Down", new KeyTrigger(KeyInput.KEY_S));
+ inputManager.addMapping("Jump", new KeyTrigger(KeyInput.KEY_SPACE));
+ inputManager.addListener(this, "Left");
+ inputManager.addListener(this, "Right");
+ inputManager.addListener(this, "Up");
+ inputManager.addListener(this, "Down");
+ inputManager.addListener(this, "Jump");
+ }
+
+ /** These are our custom actions triggered by key presses.
+ * We do not walk yet, we just keep track of the direction the user pressed. */
+ public void onAction(String binding, boolean value, float tpf) {
+ if (binding.equals("Left")) {
+ if (value) { left = true; } else { left = false; }
+ } else if (binding.equals("Right")) {
+ if (value) { right = true; } else { right = false; }
+ } else if (binding.equals("Up")) {
+ if (value) { up = true; } else { up = false; }
+ } else if (binding.equals("Down")) {
+ if (value) { down = true; } else { down = false; }
+ } else if (binding.equals("Jump")) {
+ player.jump();
+ }
+ }
+
+ /**
+ * This is the main event loop--walking happens here.
+ * We check in which direction the player is walking by interpreting
+ * the camera direction forward (camDir) and to the side (camLeft).
+ * The setWalkDirection() command is what lets a physics-controlled player walk.
+ * We also make sure here that the camera moves with player.
+ */
+ @Override
+ public void simpleUpdate(float tpf) {
+ camDir.set(cam.getDirection()).multLocal(0.6f);
+ camLeft.set(cam.getLeft()).multLocal(0.4f);
+ walkDirection.set(0, 0, 0);
+ if (left) {
+ walkDirection.addLocal(camLeft);
+ }
+ if (right) {
+ walkDirection.addLocal(camLeft.negate());
+ }
+ if (up) {
+ walkDirection.addLocal(camDir);
+ }
+ if (down) {
+ walkDirection.addLocal(camDir.negate());
+ }
+ player.setWalkDirection(walkDirection);
+ cam.setLocation(player.getPhysicsLocation());
+ }
+}
diff --git a/JmeTests/src/jme3test/helloworld/HelloEffects.java b/JmeTests/src/jme3test/helloworld/HelloEffects.java
new file mode 100644
index 0000000..1210c70
--- /dev/null
+++ b/JmeTests/src/jme3test/helloworld/HelloEffects.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.helloworld;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.effect.ParticleEmitter;
+import com.jme3.effect.ParticleMesh;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Vector3f;
+
+/** Sample 11 - how to create fire, water, and explosion effects. */
+public class HelloEffects extends SimpleApplication {
+
+ public static void main(String[] args) {
+ HelloEffects app = new HelloEffects();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ ParticleEmitter fire =
+ new ParticleEmitter("Emitter", ParticleMesh.Type.Triangle, 30);
+ Material mat_red = new Material(assetManager,
+ "Common/MatDefs/Misc/Particle.j3md");
+ mat_red.setTexture("Texture", assetManager.loadTexture(
+ "Effects/Explosion/flame.png"));
+ fire.setMaterial(mat_red);
+ fire.setImagesX(2);
+ fire.setImagesY(2); // 2x2 texture animation
+ fire.setEndColor( new ColorRGBA(1f, 0f, 0f, 1f)); // red
+ fire.setStartColor(new ColorRGBA(1f, 1f, 0f, 0.5f)); // yellow
+ fire.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 2, 0));
+ fire.setStartSize(1.5f);
+ fire.setEndSize(0.1f);
+ fire.setGravity(0, 0, 0);
+ fire.setLowLife(1f);
+ fire.setHighLife(3f);
+ fire.getParticleInfluencer().setVelocityVariation(0.3f);
+ rootNode.attachChild(fire);
+
+ ParticleEmitter debris =
+ new ParticleEmitter("Debris", ParticleMesh.Type.Triangle, 10);
+ Material debris_mat = new Material(assetManager,
+ "Common/MatDefs/Misc/Particle.j3md");
+ debris_mat.setTexture("Texture", assetManager.loadTexture(
+ "Effects/Explosion/Debris.png"));
+ debris.setMaterial(debris_mat);
+ debris.setImagesX(3);
+ debris.setImagesY(3); // 3x3 texture animation
+ debris.setSelectRandomImage(true);
+ debris.setRotateSpeed(4);
+ debris.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 4, 0));
+ debris.setStartColor(ColorRGBA.White);
+ debris.setGravity(0, 6, 0);
+ debris.getParticleInfluencer().setVelocityVariation(.60f);
+ rootNode.attachChild(debris);
+ debris.emitAllParticles();
+
+// ParticleEmitter water =
+// new ParticleEmitter("Emitter", ParticleMesh.Type.Triangle, 20);
+// Material mat_blue = new Material(assetManager,
+// "Common/MatDefs/Misc/Particle.j3md");
+// mat_blue.setTexture("Texture", assetManager.loadTexture(
+// "Effects/Explosion/flame.png"));
+// water.setMaterial(mat_blue);
+// water.setImagesX(2);
+// water.setImagesY(2); // 2x2 texture animation
+// water.setStartColor( ColorRGBA.Blue);
+// water.setEndColor( ColorRGBA.Cyan);
+// water.getParticleInfluencer().setInitialVelocity(new Vector3f(0, -4, 0));
+// water.setStartSize(1f);
+// water.setEndSize(1.5f);
+// water.setGravity(0,1,0);
+// water.setLowLife(1f);
+// water.setHighLife(1f);
+// water.getParticleInfluencer().setVelocityVariation(0.1f);
+// water.setLocalTranslation(0, 6, 0);
+// rootNode.attachChild(water);
+
+ }
+}
diff --git a/JmeTests/src/jme3test/helloworld/HelloInput.java b/JmeTests/src/jme3test/helloworld/HelloInput.java
new file mode 100644
index 0000000..8bfebc4
--- /dev/null
+++ b/JmeTests/src/jme3test/helloworld/HelloInput.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.helloworld;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.input.KeyInput;
+import com.jme3.input.MouseInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.AnalogListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.input.controls.MouseButtonTrigger;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Box;
+
+/** Sample 5 - how to map keys and mousebuttons to actions */
+public class HelloInput extends SimpleApplication {
+
+ public static void main(String[] args) {
+ HelloInput app = new HelloInput();
+ app.start();
+ }
+ protected Geometry player;
+ Boolean isRunning=true;
+
+ @Override
+ public void simpleInitApp() {
+ Box b = new Box(1, 1, 1);
+ player = new Geometry("Player", b);
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat.setColor("Color", ColorRGBA.Blue);
+ player.setMaterial(mat);
+ rootNode.attachChild(player);
+ initKeys(); // load my custom keybinding
+ }
+
+ /** Custom Keybinding: Map named actions to inputs. */
+ private void initKeys() {
+ /** You can map one or several inputs to one named mapping. */
+ inputManager.addMapping("Pause", new KeyTrigger(keyInput.KEY_P));
+ inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_J));
+ inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_K));
+ inputManager.addMapping("Rotate", new KeyTrigger(KeyInput.KEY_SPACE), // spacebar!
+ new MouseButtonTrigger(MouseInput.BUTTON_LEFT) ); // left click!
+ /** Add the named mappings to the action listeners. */
+ inputManager.addListener(actionListener,"Pause");
+ inputManager.addListener(analogListener,"Left", "Right", "Rotate");
+ }
+
+ /** Use this listener for KeyDown/KeyUp events */
+ private ActionListener actionListener = new ActionListener() {
+ public void onAction(String name, boolean keyPressed, float tpf) {
+ if (name.equals("Pause") && !keyPressed) {
+ isRunning = !isRunning;
+ }
+ }
+ };
+
+ /** Use this listener for continuous events */
+ private AnalogListener analogListener = new AnalogListener() {
+ public void onAnalog(String name, float value, float tpf) {
+ if (isRunning) {
+ if (name.equals("Rotate")) {
+ player.rotate(0, value, 0);
+ }
+ if (name.equals("Right")) {
+ player.move((new Vector3f(value, 0,0)) );
+ }
+ if (name.equals("Left")) {
+ player.move(new Vector3f(-value, 0,0));
+ }
+ } else {
+ System.out.println("Press P to unpause.");
+ }
+ }
+ };
+
+}
diff --git a/JmeTests/src/jme3test/helloworld/HelloJME3.java b/JmeTests/src/jme3test/helloworld/HelloJME3.java
new file mode 100644
index 0000000..9ffc193
--- /dev/null
+++ b/JmeTests/src/jme3test/helloworld/HelloJME3.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.helloworld;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Box;
+
+/** Sample 1 - how to get started with the most simple JME 3 application.
+ * Display a blue 3D cube and view from all sides by
+ * moving the mouse and pressing the WASD keys. */
+public class HelloJME3 extends SimpleApplication {
+
+ public static void main(String[] args){
+ HelloJME3 app = new HelloJME3();
+ app.start(); // start the game
+ }
+
+ @Override
+ public void simpleInitApp() {
+ Box b = new Box(1, 1, 1); // create cube shape
+ Geometry geom = new Geometry("Box", b); // create cube geometry from the shape
+ Material mat = new Material(assetManager,
+ "Common/MatDefs/Misc/Unshaded.j3md"); // create a simple material
+ mat.setColor("Color", ColorRGBA.Blue); // set color of material to blue
+ geom.setMaterial(mat); // set the cube's material
+ rootNode.attachChild(geom); // make the cube appear in the scene
+ }
+}
\ No newline at end of file
diff --git a/JmeTests/src/jme3test/helloworld/HelloLoop.java b/JmeTests/src/jme3test/helloworld/HelloLoop.java
new file mode 100644
index 0000000..f154a05
--- /dev/null
+++ b/JmeTests/src/jme3test/helloworld/HelloLoop.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.helloworld;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Box;
+
+/** Sample 4 - how to trigger repeating actions from the main event loop.
+ * In this example, you use the loop to make the player character
+ * rotate continuously. */
+public class HelloLoop extends SimpleApplication {
+
+ public static void main(String[] args){
+ HelloLoop app = new HelloLoop();
+ app.start();
+ }
+
+ protected Geometry player;
+
+ @Override
+ public void simpleInitApp() {
+ /** this blue box is our player character */
+ Box b = new Box(1, 1, 1);
+ player = new Geometry("blue cube", b);
+ Material mat = new Material(assetManager,
+ "Common/MatDefs/Misc/Unshaded.j3md");
+ mat.setColor("Color", ColorRGBA.Blue);
+ player.setMaterial(mat);
+ rootNode.attachChild(player);
+ }
+
+ /* Use the main event loop to trigger repeating actions. */
+ @Override
+ public void simpleUpdate(float tpf) {
+ // make the player rotate:
+ player.rotate(0, 2*tpf, 0);
+ }
+}
\ No newline at end of file
diff --git a/JmeTests/src/jme3test/helloworld/HelloMaterial.java b/JmeTests/src/jme3test/helloworld/HelloMaterial.java
new file mode 100644
index 0000000..9d93492
--- /dev/null
+++ b/JmeTests/src/jme3test/helloworld/HelloMaterial.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.helloworld;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.light.DirectionalLight;
+import com.jme3.material.Material;
+import com.jme3.material.RenderState.BlendMode;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Vector3f;
+import com.jme3.renderer.queue.RenderQueue.Bucket;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Box;
+import com.jme3.scene.shape.Sphere;
+import com.jme3.texture.Texture;
+import com.jme3.util.TangentBinormalGenerator;
+
+/** Sample 6 - how to give an object's surface a material and texture.
+ * How to make objects transparent. How to make bumpy and shiny surfaces. */
+public class HelloMaterial extends SimpleApplication {
+
+ public static void main(String[] args) {
+ HelloMaterial app = new HelloMaterial();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+
+ /** A simple textured cube -- in good MIP map quality. */
+ Box cube1Mesh = new Box( 1f,1f,1f);
+ Geometry cube1Geo = new Geometry("My Textured Box", cube1Mesh);
+ cube1Geo.setLocalTranslation(new Vector3f(-3f,1.1f,0f));
+ Material cube1Mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ Texture cube1Tex = assetManager.loadTexture("Interface/Logo/Monkey.jpg");
+ cube1Mat.setTexture("ColorMap", cube1Tex);
+ cube1Geo.setMaterial(cube1Mat);
+ rootNode.attachChild(cube1Geo);
+
+ /** A translucent/transparent texture, similar to a window frame. */
+ Box cube2Mesh = new Box( 1f,1f,0.01f);
+ Geometry cube2Geo = new Geometry("window frame", cube2Mesh);
+ Material cube2Mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ cube2Mat.setTexture("ColorMap", assetManager.loadTexture("Textures/ColoredTex/Monkey.png"));
+ cube2Mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha); // activate transparency
+ cube2Geo.setQueueBucket(Bucket.Transparent);
+ cube2Geo.setMaterial(cube2Mat);
+ rootNode.attachChild(cube2Geo);
+
+ /** A bumpy rock with a shiny light effect. To make bumpy objects you must create a NormalMap. */
+ Sphere sphereMesh = new Sphere(32,32, 2f);
+ Geometry sphereGeo = new Geometry("Shiny rock", sphereMesh);
+ sphereMesh.setTextureMode(Sphere.TextureMode.Projected); // better quality on spheres
+ TangentBinormalGenerator.generate(sphereMesh); // for lighting effect
+ Material sphereMat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+ sphereMat.setTexture("DiffuseMap", assetManager.loadTexture("Textures/Terrain/Pond/Pond.jpg"));
+ sphereMat.setTexture("NormalMap", assetManager.loadTexture("Textures/Terrain/Pond/Pond_normal.png"));
+ sphereMat.setBoolean("UseMaterialColors",true);
+ sphereMat.setColor("Diffuse",ColorRGBA.White);
+ sphereMat.setColor("Specular",ColorRGBA.White);
+ sphereMat.setFloat("Shininess", 64f); // [0,128]
+ sphereGeo.setMaterial(sphereMat);
+ //sphereGeo.setMaterial((Material) assetManager.loadMaterial("Materials/MyCustomMaterial.j3m"));
+ sphereGeo.setLocalTranslation(0,2,-2); // Move it a bit
+ sphereGeo.rotate(1.6f, 0, 0); // Rotate it a bit
+ rootNode.attachChild(sphereGeo);
+
+ /** Must add a light to make the lit object visible! */
+ DirectionalLight sun = new DirectionalLight();
+ sun.setDirection(new Vector3f(1,0,-2).normalizeLocal());
+ sun.setColor(ColorRGBA.White);
+ rootNode.addLight(sun);
+ }
+}
diff --git a/JmeTests/src/jme3test/helloworld/HelloNode.java b/JmeTests/src/jme3test/helloworld/HelloNode.java
new file mode 100644
index 0000000..d70632f
--- /dev/null
+++ b/JmeTests/src/jme3test/helloworld/HelloNode.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.helloworld;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.shape.Box;
+
+/** Sample 2 - How to use nodes as handles to manipulate objects in the scene.
+ * You can rotate, translate, and scale objects by manipulating their parent nodes.
+ * The Root Node is special: Only what is attached to the Root Node appears in the scene. */
+public class HelloNode extends SimpleApplication {
+
+ public static void main(String[] args){
+ HelloNode app = new HelloNode();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+
+ /** create a blue box at coordinates (1,-1,1) */
+ Box box1 = new Box(1,1,1);
+ Geometry blue = new Geometry("Box", box1);
+ blue.setLocalTranslation(new Vector3f(1,-1,1));
+ Material mat1 = new Material(assetManager,
+ "Common/MatDefs/Misc/Unshaded.j3md");
+ mat1.setColor("Color", ColorRGBA.Blue);
+ blue.setMaterial(mat1);
+
+ /** create a red box straight above the blue one at (1,3,1) */
+ Box box2 = new Box(1,1,1);
+ Geometry red = new Geometry("Box", box2);
+ red.setLocalTranslation(new Vector3f(1,3,1));
+ Material mat2 = new Material(assetManager,
+ "Common/MatDefs/Misc/Unshaded.j3md");
+ mat2.setColor("Color", ColorRGBA.Red);
+ red.setMaterial(mat2);
+
+ /** Create a pivot node at (0,0,0) and attach it to the root node */
+ Node pivot = new Node("pivot");
+ rootNode.attachChild(pivot); // put this node in the scene
+
+ /** Attach the two boxes to the *pivot* node. (And transitively to the root node.) */
+ pivot.attachChild(blue);
+ pivot.attachChild(red);
+ /** Rotate the pivot node: Note that both boxes have rotated! */
+ pivot.rotate(.4f,.4f,0f);
+ }
+}
+
diff --git a/JmeTests/src/jme3test/helloworld/HelloPhysics.java b/JmeTests/src/jme3test/helloworld/HelloPhysics.java
new file mode 100644
index 0000000..75777e5
--- /dev/null
+++ b/JmeTests/src/jme3test/helloworld/HelloPhysics.java
@@ -0,0 +1,228 @@
+/**
+ * Copyright (c) 2009-2018 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.helloworld;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.asset.TextureKey;
+import com.jme3.bullet.BulletAppState;
+import com.jme3.bullet.control.RigidBodyControl;
+import com.jme3.font.BitmapText;
+import com.jme3.input.MouseInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.MouseButtonTrigger;
+import com.jme3.material.Material;
+import com.jme3.math.Vector2f;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Box;
+import com.jme3.scene.shape.Sphere;
+import com.jme3.scene.shape.Sphere.TextureMode;
+import com.jme3.texture.Texture;
+import com.jme3.texture.Texture.WrapMode;
+
+/**
+ * Example 12 - how to give objects physical properties so they bounce and fall.
+ * @author base code by double1984, updated by zathras
+ */
+public class HelloPhysics extends SimpleApplication {
+
+ public static void main(String args[]) {
+ HelloPhysics app = new HelloPhysics();
+ app.start();
+ }
+
+ /** Prepare the Physics Application State (jBullet) */
+ private BulletAppState bulletAppState;
+
+ /** Prepare Materials */
+ Material wall_mat;
+ Material stone_mat;
+ Material floor_mat;
+
+ /** Prepare geometries and physical nodes for bricks and cannon balls. */
+ private RigidBodyControl brick_phy;
+ private static final Box box;
+ private RigidBodyControl ball_phy;
+ private static final Sphere sphere;
+ private RigidBodyControl floor_phy;
+ private static final Box floor;
+
+ /** dimensions used for bricks and wall */
+ private static final float brickLength = 0.48f;
+ private static final float brickWidth = 0.24f;
+ private static final float brickHeight = 0.12f;
+
+ static {
+ /** Initialize the cannon ball geometry */
+ sphere = new Sphere(32, 32, 0.4f, true, false);
+ sphere.setTextureMode(TextureMode.Projected);
+ /** Initialize the brick geometry */
+ box = new Box(brickLength, brickHeight, brickWidth);
+ box.scaleTextureCoordinates(new Vector2f(1f, .5f));
+ /** Initialize the floor geometry */
+ floor = new Box(10f, 0.1f, 5f);
+ floor.scaleTextureCoordinates(new Vector2f(3, 6));
+ }
+
+ @Override
+ public void simpleInitApp() {
+ /** Set up Physics Game */
+ bulletAppState = new BulletAppState();
+ stateManager.attach(bulletAppState);
+ //bulletAppState.getPhysicsSpace().enableDebug(assetManager);
+ /** Configure cam to look at scene */
+ cam.setLocation(new Vector3f(0, 4f, 6f));
+ cam.lookAt(new Vector3f(2, 2, 0), Vector3f.UNIT_Y);
+ /** Initialize the scene, materials, inputs, and physics space */
+ initInputs();
+ initMaterials();
+ initWall();
+ initFloor();
+ initCrossHairs();
+ }
+
+ /** Add InputManager action: Left click triggers shooting. */
+ private void initInputs() {
+ inputManager.addMapping("shoot",
+ new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
+ inputManager.addListener(actionListener, "shoot");
+ }
+
+ /**
+ * Every time the shoot action is triggered, a new cannon ball is produced.
+ * The ball is set up to fly from the camera position in the camera direction.
+ */
+ private ActionListener actionListener = new ActionListener() {
+ public void onAction(String name, boolean keyPressed, float tpf) {
+ if (name.equals("shoot") && !keyPressed) {
+ makeCannonBall();
+ }
+ }
+ };
+
+ /** Initialize the materials used in this scene. */
+ public void initMaterials() {
+ wall_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ TextureKey key = new TextureKey("Textures/Terrain/BrickWall/BrickWall.jpg");
+ key.setGenerateMips(true);
+ Texture tex = assetManager.loadTexture(key);
+ wall_mat.setTexture("ColorMap", tex);
+
+ stone_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ TextureKey key2 = new TextureKey("Textures/Terrain/Rock/Rock.PNG");
+ key2.setGenerateMips(true);
+ Texture tex2 = assetManager.loadTexture(key2);
+ stone_mat.setTexture("ColorMap", tex2);
+
+ floor_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ TextureKey key3 = new TextureKey("Textures/Terrain/Pond/Pond.jpg");
+ key3.setGenerateMips(true);
+ Texture tex3 = assetManager.loadTexture(key3);
+ tex3.setWrap(WrapMode.Repeat);
+ floor_mat.setTexture("ColorMap", tex3);
+ }
+
+ /** Make a solid floor and add it to the scene. */
+ public void initFloor() {
+ Geometry floor_geo = new Geometry("Floor", floor);
+ floor_geo.setMaterial(floor_mat);
+ floor_geo.setLocalTranslation(0, -0.1f, 0);
+ this.rootNode.attachChild(floor_geo);
+ /* Make the floor physical with mass 0.0f! */
+ floor_phy = new RigidBodyControl(0.0f);
+ floor_geo.addControl(floor_phy);
+ bulletAppState.getPhysicsSpace().add(floor_phy);
+ }
+
+ /** This loop builds a wall out of individual bricks. */
+ public void initWall() {
+ float startpt = brickLength / 4;
+ float height = 0;
+ for (int j = 0; j < 15; j++) {
+ for (int i = 0; i < 6; i++) {
+ Vector3f vt =
+ new Vector3f(i * brickLength * 2 + startpt, brickHeight + height, 0);
+ makeBrick(vt);
+ }
+ startpt = -startpt;
+ height += 2 * brickHeight;
+ }
+ }
+
+ /** This method creates one individual physical brick. */
+ public void makeBrick(Vector3f loc) {
+ /** Create a brick geometry and attach to scene graph. */
+ Geometry brick_geo = new Geometry("brick", box);
+ brick_geo.setMaterial(wall_mat);
+ rootNode.attachChild(brick_geo);
+ /** Position the brick geometry */
+ brick_geo.setLocalTranslation(loc);
+ /** Make brick physical with a mass > 0.0f. */
+ brick_phy = new RigidBodyControl(2f);
+ /** Add physical brick to physics space. */
+ brick_geo.addControl(brick_phy);
+ bulletAppState.getPhysicsSpace().add(brick_phy);
+ }
+
+ /** This method creates one individual physical cannon ball.
+ * By defaul, the ball is accelerated and flies
+ * from the camera position in the camera direction.*/
+ public void makeCannonBall() {
+ /** Create a cannon ball geometry and attach to scene graph. */
+ Geometry ball_geo = new Geometry("cannon ball", sphere);
+ ball_geo.setMaterial(stone_mat);
+ rootNode.attachChild(ball_geo);
+ /** Position the cannon ball */
+ ball_geo.setLocalTranslation(cam.getLocation());
+ /** Make the ball physical with a mass > 0.0f */
+ ball_phy = new RigidBodyControl(1f);
+ /** Add physical ball to physics space. */
+ ball_geo.addControl(ball_phy);
+ bulletAppState.getPhysicsSpace().add(ball_phy);
+ /** Accelerate the physical ball to shoot it. */
+ ball_phy.setLinearVelocity(cam.getDirection().mult(25));
+ }
+
+ /** A plus sign used as crosshairs to help the player with aiming.*/
+ protected void initCrossHairs() {
+ setDisplayStatView(false);
+ //guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
+ BitmapText ch = new BitmapText(guiFont, false);
+ ch.setSize(guiFont.getCharSet().getRenderedSize() * 2);
+ ch.setText("+"); // fake crosshairs :)
+ ch.setLocalTranslation( // center
+ settings.getWidth() / 2,
+ settings.getHeight() / 2, 0);
+ guiNode.attachChild(ch);
+ }
+}
diff --git a/JmeTests/src/jme3test/helloworld/HelloPicking.java b/JmeTests/src/jme3test/helloworld/HelloPicking.java
new file mode 100644
index 0000000..caee4f9
--- /dev/null
+++ b/JmeTests/src/jme3test/helloworld/HelloPicking.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.helloworld;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.collision.CollisionResult;
+import com.jme3.collision.CollisionResults;
+import com.jme3.font.BitmapText;
+import com.jme3.input.KeyInput;
+import com.jme3.input.MouseInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.input.controls.MouseButtonTrigger;
+import com.jme3.light.DirectionalLight;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Ray;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.shape.Box;
+import com.jme3.scene.shape.Sphere;
+
+/** Sample 8 - how to let the user pick (select) objects in the scene
+ * using the mouse or key presses. Can be used for shooting, opening doors, etc. */
+public class HelloPicking extends SimpleApplication {
+
+ public static void main(String[] args) {
+ HelloPicking app = new HelloPicking();
+ app.start();
+ }
+ private Node shootables;
+ private Geometry mark;
+
+ @Override
+ public void simpleInitApp() {
+ initCrossHairs(); // a "+" in the middle of the screen to help aiming
+ initKeys(); // load custom key mappings
+ initMark(); // a red sphere to mark the hit
+
+ /** create four colored boxes and a floor to shoot at: */
+ shootables = new Node("Shootables");
+ rootNode.attachChild(shootables);
+ shootables.attachChild(makeCube("a Dragon", -2f, 0f, 1f));
+ shootables.attachChild(makeCube("a tin can", 1f, -2f, 0f));
+ shootables.attachChild(makeCube("the Sheriff", 0f, 1f, -2f));
+ shootables.attachChild(makeCube("the Deputy", 1f, 0f, -4f));
+ shootables.attachChild(makeFloor());
+ shootables.attachChild(makeCharacter());
+ }
+
+ /** Declaring the "Shoot" action and mapping to its triggers. */
+ private void initKeys() {
+ inputManager.addMapping("Shoot",
+ new KeyTrigger(KeyInput.KEY_SPACE), // trigger 1: spacebar
+ new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); // trigger 2: left-button click
+ inputManager.addListener(actionListener, "Shoot");
+ }
+ /** Defining the "Shoot" action: Determine what was hit and how to respond. */
+ private ActionListener actionListener = new ActionListener() {
+
+ public void onAction(String name, boolean keyPressed, float tpf) {
+ if (name.equals("Shoot") && !keyPressed) {
+ // 1. Reset results list.
+ CollisionResults results = new CollisionResults();
+ // 2. Aim the ray from cam loc to cam direction.
+ Ray ray = new Ray(cam.getLocation(), cam.getDirection());
+ // 3. Collect intersections between Ray and Shootables in results list.
+ shootables.collideWith(ray, results);
+ // 4. Print the results
+ System.out.println("----- Collisions? " + results.size() + "-----");
+ for (int i = 0; i < results.size(); i++) {
+ // For each hit, we know distance, impact point, name of geometry.
+ float dist = results.getCollision(i).getDistance();
+ Vector3f pt = results.getCollision(i).getContactPoint();
+ String hit = results.getCollision(i).getGeometry().getName();
+ System.out.println("* Collision #" + i);
+ System.out.println(" You shot " + hit + " at " + pt + ", " + dist + " wu away.");
+ }
+ // 5. Use the results (we mark the hit object)
+ if (results.size() > 0) {
+ // The closest collision point is what was truly hit:
+ CollisionResult closest = results.getClosestCollision();
+ // Let's interact - we mark the hit with a red dot.
+ mark.setLocalTranslation(closest.getContactPoint());
+ rootNode.attachChild(mark);
+ } else {
+ // No hits? Then remove the red mark.
+ rootNode.detachChild(mark);
+ }
+ }
+ }
+ };
+
+ /** A cube object for target practice */
+ protected Geometry makeCube(String name, float x, float y, float z) {
+ Box box = new Box(1, 1, 1);
+ Geometry cube = new Geometry(name, box);
+ cube.setLocalTranslation(x, y, z);
+ Material mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat1.setColor("Color", ColorRGBA.randomColor());
+ cube.setMaterial(mat1);
+ return cube;
+ }
+
+ /** A floor to show that the "shot" can go through several objects. */
+ protected Geometry makeFloor() {
+ Box box = new Box(15, .2f, 15);
+ Geometry floor = new Geometry("the Floor", box);
+ floor.setLocalTranslation(0, -4, -5);
+ Material mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat1.setColor("Color", ColorRGBA.Gray);
+ floor.setMaterial(mat1);
+ return floor;
+ }
+
+ /** A red ball that marks the last spot that was "hit" by the "shot". */
+ protected void initMark() {
+ Sphere sphere = new Sphere(30, 30, 0.2f);
+ mark = new Geometry("BOOM!", sphere);
+ Material mark_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mark_mat.setColor("Color", ColorRGBA.Red);
+ mark.setMaterial(mark_mat);
+ }
+
+ /** A centred plus sign to help the player aim. */
+ protected void initCrossHairs() {
+ setDisplayStatView(false);
+ guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
+ BitmapText ch = new BitmapText(guiFont, false);
+ ch.setSize(guiFont.getCharSet().getRenderedSize() * 2);
+ ch.setText("+"); // crosshairs
+ ch.setLocalTranslation( // center
+ settings.getWidth() / 2 - ch.getLineWidth()/2, settings.getHeight() / 2 + ch.getLineHeight()/2, 0);
+ guiNode.attachChild(ch);
+ }
+
+ protected Spatial makeCharacter() {
+ // load a character from jme3test-test-data
+ Spatial golem = assetManager.loadModel("Models/Oto/Oto.mesh.xml");
+ golem.scale(0.5f);
+ golem.setLocalTranslation(-1.0f, -1.5f, -0.6f);
+
+ // We must add a light to make the model visible
+ DirectionalLight sun = new DirectionalLight();
+ sun.setDirection(new Vector3f(-0.1f, -0.7f, -1.0f));
+ golem.addLight(sun);
+ return golem;
+ }
+}
diff --git a/JmeTests/src/jme3test/helloworld/HelloTerrain.java b/JmeTests/src/jme3test/helloworld/HelloTerrain.java
new file mode 100644
index 0000000..69b8caf
--- /dev/null
+++ b/JmeTests/src/jme3test/helloworld/HelloTerrain.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.helloworld;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.material.Material;
+import com.jme3.terrain.geomipmap.TerrainLodControl;
+import com.jme3.terrain.geomipmap.TerrainQuad;
+import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator;
+import com.jme3.terrain.heightmap.AbstractHeightMap;
+import com.jme3.terrain.heightmap.ImageBasedHeightMap;
+import com.jme3.texture.Texture;
+import com.jme3.texture.Texture.WrapMode;
+
+public class HelloTerrain extends SimpleApplication {
+
+ private TerrainQuad terrain;
+ Material mat_terrain;
+
+ public static void main(String[] args) {
+ HelloTerrain app = new HelloTerrain();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ flyCam.setMoveSpeed(50);
+
+ /** 1. Create terrain material and load four textures into it. */
+ mat_terrain = new Material(assetManager,
+ "Common/MatDefs/Terrain/Terrain.j3md");
+
+ /** 1.1) Add ALPHA map (for red-blue-green coded splat textures) */
+ mat_terrain.setTexture("Alpha", assetManager.loadTexture(
+ "Textures/Terrain/splat/alphamap.png"));
+
+ /** 1.2) Add GRASS texture into the red layer (Tex1). */
+ Texture grass = assetManager.loadTexture(
+ "Textures/Terrain/splat/grass.jpg");
+ grass.setWrap(WrapMode.Repeat);
+ mat_terrain.setTexture("Tex1", grass);
+ mat_terrain.setFloat("Tex1Scale", 64f);
+
+ /** 1.3) Add DIRT texture into the green layer (Tex2) */
+ Texture dirt = assetManager.loadTexture(
+ "Textures/Terrain/splat/dirt.jpg");
+ dirt.setWrap(WrapMode.Repeat);
+ mat_terrain.setTexture("Tex2", dirt);
+ mat_terrain.setFloat("Tex2Scale", 32f);
+
+ /** 1.4) Add ROAD texture into the blue layer (Tex3) */
+ Texture rock = assetManager.loadTexture(
+ "Textures/Terrain/splat/road.jpg");
+ rock.setWrap(WrapMode.Repeat);
+ mat_terrain.setTexture("Tex3", rock);
+ mat_terrain.setFloat("Tex3Scale", 128f);
+
+ /** 2.a Create a custom height map from an image */
+ AbstractHeightMap heightmap = null;
+ Texture heightMapImage = assetManager.loadTexture(
+ "Textures/Terrain/splat/mountains512.png");
+ heightmap = new ImageBasedHeightMap(heightMapImage.getImage());
+
+/** 2.b Create a random height map */
+// HillHeightMap heightmap = null;
+// HillHeightMap.NORMALIZE_RANGE = 100;
+// try {
+// heightmap = new HillHeightMap(513, 1000, 50, 100, (byte) 3);
+// } catch (Exception ex) {
+// ex.printStackTrace();
+// }
+
+ heightmap.load();
+
+ /** 3. We have prepared material and heightmap.
+ * Now we create the actual terrain:
+ * 3.1) Create a TerrainQuad and name it "my terrain".
+ * 3.2) A good value for terrain tiles is 64x64 -- so we supply 64+1=65.
+ * 3.3) We prepared a heightmap of size 512x512 -- so we supply 512+1=513.
+ * 3.4) As LOD step scale we supply Vector3f(1,1,1).
+ * 3.5) We supply the prepared heightmap itself.
+ */
+ int patchSize = 65;
+ terrain = new TerrainQuad("my terrain", patchSize, 513, heightmap.getHeightMap());
+
+ /** 4. We give the terrain its material, position & scale it, and attach it. */
+ terrain.setMaterial(mat_terrain);
+ terrain.setLocalTranslation(0, -100, 0);
+ terrain.setLocalScale(2f, 1f, 2f);
+ rootNode.attachChild(terrain);
+
+ /** 5. The LOD (level of detail) depends on were the camera is: */
+ TerrainLodControl control = new TerrainLodControl(terrain, getCamera());
+ control.setLodCalculator( new DistanceLodCalculator(patchSize, 2.7f) ); // patch size, and a multiplier
+ terrain.addControl(control);
+ }
+}
diff --git a/JmeTests/src/jme3test/helloworld/HelloTerrainCollision.java b/JmeTests/src/jme3test/helloworld/HelloTerrainCollision.java
new file mode 100644
index 0000000..d7ea68f
--- /dev/null
+++ b/JmeTests/src/jme3test/helloworld/HelloTerrainCollision.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.helloworld;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.bullet.BulletAppState;
+import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
+import com.jme3.bullet.control.CharacterControl;
+import com.jme3.bullet.control.RigidBodyControl;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.material.Material;
+import com.jme3.math.Vector3f;
+import com.jme3.renderer.Camera;
+import com.jme3.terrain.geomipmap.TerrainLodControl;
+import com.jme3.terrain.geomipmap.TerrainQuad;
+import com.jme3.terrain.heightmap.AbstractHeightMap;
+import com.jme3.terrain.heightmap.ImageBasedHeightMap;
+import com.jme3.texture.Texture;
+import com.jme3.texture.Texture.WrapMode;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This demo shows a terrain with collision detection,
+ * that you can walk around in with a first-person perspective.
+ * This code combines HelloCollision and HelloTerrain.
+ */
+public class HelloTerrainCollision extends SimpleApplication
+ implements ActionListener {
+
+ private BulletAppState bulletAppState;
+ private RigidBodyControl landscape;
+ private CharacterControl player;
+ private Vector3f walkDirection = new Vector3f();
+ private boolean left = false, right = false, up = false, down = false;
+ private TerrainQuad terrain;
+ private Material mat_terrain;
+ //Temporary vectors used on each frame.
+ //They here to avoid instanciating new vectors on each frame
+ private Vector3f camDir = new Vector3f();
+ private Vector3f camLeft = new Vector3f();
+
+ public static void main(String[] args) {
+ HelloTerrainCollision app = new HelloTerrainCollision();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ /** Set up Physics */
+ bulletAppState = new BulletAppState();
+ stateManager.attach(bulletAppState);
+ //bulletAppState.getPhysicsSpace().enableDebug(assetManager);
+
+ flyCam.setMoveSpeed(100);
+ setUpKeys();
+
+ /** 1. Create terrain material and load four textures into it. */
+ mat_terrain = new Material(assetManager,
+ "Common/MatDefs/Terrain/Terrain.j3md");
+
+ /** 1.1) Add ALPHA map (for red-blue-green coded splat textures) */
+ mat_terrain.setTexture("Alpha", assetManager.loadTexture(
+ "Textures/Terrain/splat/alphamap.png"));
+
+ /** 1.2) Add GRASS texture into the red layer (Tex1). */
+ Texture grass = assetManager.loadTexture(
+ "Textures/Terrain/splat/grass.jpg");
+ grass.setWrap(WrapMode.Repeat);
+ mat_terrain.setTexture("Tex1", grass);
+ mat_terrain.setFloat("Tex1Scale", 64f);
+
+ /** 1.3) Add DIRT texture into the green layer (Tex2) */
+ Texture dirt = assetManager.loadTexture(
+ "Textures/Terrain/splat/dirt.jpg");
+ dirt.setWrap(WrapMode.Repeat);
+ mat_terrain.setTexture("Tex2", dirt);
+ mat_terrain.setFloat("Tex2Scale", 32f);
+
+ /** 1.4) Add ROAD texture into the blue layer (Tex3) */
+ Texture rock = assetManager.loadTexture(
+ "Textures/Terrain/splat/road.jpg");
+ rock.setWrap(WrapMode.Repeat);
+ mat_terrain.setTexture("Tex3", rock);
+ mat_terrain.setFloat("Tex3Scale", 128f);
+
+ /** 2. Create the height map */
+ AbstractHeightMap heightmap = null;
+ Texture heightMapImage = assetManager.loadTexture(
+ "Textures/Terrain/splat/mountains512.png");
+ heightmap = new ImageBasedHeightMap(heightMapImage.getImage());
+ heightmap.load();
+
+ /** 3. We have prepared material and heightmap.
+ * Now we create the actual terrain:
+ * 3.1) Create a TerrainQuad and name it "my terrain".
+ * 3.2) A good value for terrain tiles is 64x64 -- so we supply 64+1=65.
+ * 3.3) We prepared a heightmap of size 512x512 -- so we supply 512+1=513.
+ * 3.4) As LOD step scale we supply Vector3f(1,1,1).
+ * 3.5) We supply the prepared heightmap itself.
+ */
+ terrain = new TerrainQuad("my terrain", 65, 513, heightmap.getHeightMap());
+
+ /** 4. We give the terrain its material, position & scale it, and attach it. */
+ terrain.setMaterial(mat_terrain);
+ terrain.setLocalTranslation(0, -100, 0);
+ terrain.setLocalScale(2f, 1f, 2f);
+ rootNode.attachChild(terrain);
+
+ /** 5. The LOD (level of detail) depends on were the camera is: */
+ List cameras = new ArrayList();
+ cameras.add(getCamera());
+ TerrainLodControl control = new TerrainLodControl(terrain, cameras);
+ terrain.addControl(control);
+
+ /** 6. Add physics: */
+ /* We set up collision detection for the scene by creating a static
+ * RigidBodyControl with mass zero.*/
+ terrain.addControl(new RigidBodyControl(0));
+
+ // We set up collision detection for the player by creating
+ // a capsule collision shape and a CharacterControl.
+ // The CharacterControl offers extra settings for
+ // size, stepheight, jumping, falling, and gravity.
+ // We also put the player in its starting position.
+ CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(1.5f, 6f, 1);
+ player = new CharacterControl(capsuleShape, 0.05f);
+ player.setJumpSpeed(20);
+ player.setFallSpeed(30);
+ player.setGravity(30);
+ player.setPhysicsLocation(new Vector3f(-10, 10, 10));
+
+ // We attach the scene and the player to the rootnode and the physics space,
+ // to make them appear in the game world.
+ bulletAppState.getPhysicsSpace().add(terrain);
+ bulletAppState.getPhysicsSpace().add(player);
+
+ }
+ /** We over-write some navigational key mappings here, so we can
+ * add physics-controlled walking and jumping: */
+ private void setUpKeys() {
+ inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_A));
+ inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_D));
+ inputManager.addMapping("Up", new KeyTrigger(KeyInput.KEY_W));
+ inputManager.addMapping("Down", new KeyTrigger(KeyInput.KEY_S));
+ inputManager.addMapping("Jump", new KeyTrigger(KeyInput.KEY_SPACE));
+ inputManager.addListener(this, "Left");
+ inputManager.addListener(this, "Right");
+ inputManager.addListener(this, "Up");
+ inputManager.addListener(this, "Down");
+ inputManager.addListener(this, "Jump");
+ }
+
+ /** These are our custom actions triggered by key presses.
+ * We do not walk yet, we just keep track of the direction the user pressed. */
+ public void onAction(String binding, boolean value, float tpf) {
+ if (binding.equals("Left")) {
+ if (value) { left = true; } else { left = false; }
+ } else if (binding.equals("Right")) {
+ if (value) { right = true; } else { right = false; }
+ } else if (binding.equals("Up")) {
+ if (value) { up = true; } else { up = false; }
+ } else if (binding.equals("Down")) {
+ if (value) { down = true; } else { down = false; }
+ } else if (binding.equals("Jump")) {
+ player.jump();
+ }
+ }
+
+ /**
+ * This is the main event loop--walking happens here.
+ * We check in which direction the player is walking by interpreting
+ * the camera direction forward (camDir) and to the side (camLeft).
+ * The setWalkDirection() command is what lets a physics-controlled player walk.
+ * We also make sure here that the camera moves with player.
+ */
+ @Override
+ public void simpleUpdate(float tpf) {
+ camDir.set(cam.getDirection()).multLocal(0.6f);
+ camLeft.set(cam.getLeft()).multLocal(0.4f);
+ walkDirection.set(0, 0, 0);
+ if (left) {
+ walkDirection.addLocal(camLeft);
+ }
+ if (right) {
+ walkDirection.addLocal(camLeft.negate());
+ }
+ if (up) {
+ walkDirection.addLocal(camDir);
+ }
+ if (down) {
+ walkDirection.addLocal(camDir.negate());
+ }
+ player.setWalkDirection(walkDirection);
+ cam.setLocation(player.getPhysicsLocation());
+ }
+}
+
diff --git a/JmeTests/src/jme3test/input/TestCameraNode.java b/JmeTests/src/jme3test/input/TestCameraNode.java
new file mode 100644
index 0000000..c1ebfeb
--- /dev/null
+++ b/JmeTests/src/jme3test/input/TestCameraNode.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.input;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.input.MouseInput;
+import com.jme3.input.controls.*;
+import com.jme3.material.Material;
+import com.jme3.math.FastMath;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.CameraNode;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.control.CameraControl.ControlDirection;
+import com.jme3.scene.shape.Quad;
+import com.jme3.system.AppSettings;
+
+/**
+ * A 3rd-person camera node follows a target (teapot). Follow the teapot with
+ * WASD keys, rotate by dragging the mouse.
+ */
+public class TestCameraNode extends SimpleApplication implements AnalogListener, ActionListener {
+
+ private Geometry teaGeom;
+ private Node teaNode;
+ CameraNode camNode;
+ boolean rotate = false;
+ Vector3f direction = new Vector3f();
+
+ public static void main(String[] args) {
+ TestCameraNode app = new TestCameraNode();
+ AppSettings s = new AppSettings(true);
+ s.setFrameRate(100);
+ app.setSettings(s);
+ app.start();
+ }
+
+ public void simpleInitApp() {
+ // load a teapot model
+ teaGeom = (Geometry) assetManager.loadModel("Models/Teapot/Teapot.obj");
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/ShowNormals.j3md");
+ teaGeom.setMaterial(mat);
+ //create a node to attach the geometry and the camera node
+ teaNode = new Node("teaNode");
+ teaNode.attachChild(teaGeom);
+ rootNode.attachChild(teaNode);
+ // create a floor
+ mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg"));
+ Geometry ground = new Geometry("ground", new Quad(50, 50));
+ ground.setLocalRotation(new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X));
+ ground.setLocalTranslation(-25, -1, 25);
+ ground.setMaterial(mat);
+ rootNode.attachChild(ground);
+
+ //creating the camera Node
+ camNode = new CameraNode("CamNode", cam);
+ //Setting the direction to Spatial to camera, this means the camera will copy the movements of the Node
+ camNode.setControlDir(ControlDirection.SpatialToCamera);
+ //attaching the camNode to the teaNode
+ teaNode.attachChild(camNode);
+ //setting the local translation of the cam node to move it away from the teanNode a bit
+ camNode.setLocalTranslation(new Vector3f(-10, 0, 0));
+ //setting the camNode to look at the teaNode
+ camNode.lookAt(teaNode.getLocalTranslation(), Vector3f.UNIT_Y);
+
+ //disable the default 1st-person flyCam (don't forget this!!)
+ flyCam.setEnabled(false);
+
+ registerInput();
+ }
+
+ public void registerInput() {
+ inputManager.addMapping("moveForward", new KeyTrigger(keyInput.KEY_UP), new KeyTrigger(keyInput.KEY_W));
+ inputManager.addMapping("moveBackward", new KeyTrigger(keyInput.KEY_DOWN), new KeyTrigger(keyInput.KEY_S));
+ inputManager.addMapping("moveRight", new KeyTrigger(keyInput.KEY_RIGHT), new KeyTrigger(keyInput.KEY_D));
+ inputManager.addMapping("moveLeft", new KeyTrigger(keyInput.KEY_LEFT), new KeyTrigger(keyInput.KEY_A));
+ inputManager.addMapping("toggleRotate", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
+ inputManager.addMapping("rotateRight", new MouseAxisTrigger(MouseInput.AXIS_X, true));
+ inputManager.addMapping("rotateLeft", new MouseAxisTrigger(MouseInput.AXIS_X, false));
+ inputManager.addListener(this, "moveForward", "moveBackward", "moveRight", "moveLeft");
+ inputManager.addListener(this, "rotateRight", "rotateLeft", "toggleRotate");
+ }
+
+ public void onAnalog(String name, float value, float tpf) {
+ //computing the normalized direction of the cam to move the teaNode
+ direction.set(cam.getDirection()).normalizeLocal();
+ if (name.equals("moveForward")) {
+ direction.multLocal(5 * tpf);
+ teaNode.move(direction);
+ }
+ if (name.equals("moveBackward")) {
+ direction.multLocal(-5 * tpf);
+ teaNode.move(direction);
+ }
+ if (name.equals("moveRight")) {
+ direction.crossLocal(Vector3f.UNIT_Y).multLocal(5 * tpf);
+ teaNode.move(direction);
+ }
+ if (name.equals("moveLeft")) {
+ direction.crossLocal(Vector3f.UNIT_Y).multLocal(-5 * tpf);
+ teaNode.move(direction);
+ }
+ if (name.equals("rotateRight") && rotate) {
+ teaNode.rotate(0, 5 * tpf, 0);
+ }
+ if (name.equals("rotateLeft") && rotate) {
+ teaNode.rotate(0, -5 * tpf, 0);
+ }
+
+ }
+
+ public void onAction(String name, boolean keyPressed, float tpf) {
+ //toggling rotation on or off
+ if (name.equals("toggleRotate") && keyPressed) {
+ rotate = true;
+ inputManager.setCursorVisible(false);
+ }
+ if (name.equals("toggleRotate") && !keyPressed) {
+ rotate = false;
+ inputManager.setCursorVisible(true);
+ }
+
+ }
+}
diff --git a/JmeTests/src/jme3test/input/TestChaseCamera.java b/JmeTests/src/jme3test/input/TestChaseCamera.java
new file mode 100644
index 0000000..d933f96
--- /dev/null
+++ b/JmeTests/src/jme3test/input/TestChaseCamera.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2009-2018 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.input;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.input.ChaseCamera;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.AnalogListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.material.Material;
+import com.jme3.math.FastMath;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Quad;
+
+/** A 3rd-person chase camera orbits a target (teapot).
+ * Follow the teapot with WASD keys, rotate by dragging the mouse. */
+public class TestChaseCamera extends SimpleApplication implements AnalogListener, ActionListener {
+
+ private Geometry teaGeom;
+ private ChaseCamera chaseCam;
+
+ public static void main(String[] args) {
+ TestChaseCamera app = new TestChaseCamera();
+ app.start();
+ }
+
+ public void simpleInitApp() {
+ // Load a teapot model
+ teaGeom = (Geometry) assetManager.loadModel("Models/Teapot/Teapot.obj");
+ Material mat_tea = new Material(assetManager, "Common/MatDefs/Misc/ShowNormals.j3md");
+ teaGeom.setMaterial(mat_tea);
+ rootNode.attachChild(teaGeom);
+
+ // Load a floor model
+ Material mat_ground = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat_ground.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg"));
+ Geometry ground = new Geometry("ground", new Quad(50, 50));
+ ground.setLocalRotation(new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X));
+ ground.setLocalTranslation(-25, -1, 25);
+ ground.setMaterial(mat_ground);
+ rootNode.attachChild(ground);
+
+ // Disable the default first-person cam!
+ flyCam.setEnabled(false);
+
+ // Enable a chase cam
+ chaseCam = new ChaseCamera(cam, teaGeom, inputManager);
+
+ //Uncomment this to invert the camera's vertical rotation Axis
+ //chaseCam.setInvertVerticalAxis(true);
+
+ //Uncomment this to invert the camera's horizontal rotation Axis
+ //chaseCam.setInvertHorizontalAxis(true);
+
+ //Comment this to disable smooth camera motion
+ chaseCam.setSmoothMotion(true);
+
+ //Uncomment this to disable trailing of the camera
+ //WARNING, trailing only works with smooth motion enabled. It is true by default.
+ //chaseCam.setTrailingEnabled(false);
+
+ //Uncomment this to look 3 world units above the target
+ //chaseCam.setLookAtOffset(Vector3f.UNIT_Y.mult(3));
+
+ //Uncomment this to enable rotation when the middle mouse button is pressed (like Blender)
+ //WARNING : setting this trigger disable the rotation on right and left mouse button click
+ //chaseCam.setToggleRotationTrigger(new MouseButtonTrigger(MouseInput.BUTTON_MIDDLE));
+
+ //Uncomment this to set multiple triggers to enable rotation of the cam
+ //Here spade bar and middle mouse button
+ //chaseCam.setToggleRotationTrigger(new MouseButtonTrigger(MouseInput.BUTTON_MIDDLE),new KeyTrigger(KeyInput.KEY_SPACE));
+
+ //registering inputs for target's movement
+ registerInput();
+
+ }
+
+ public void registerInput() {
+ inputManager.addMapping("moveForward", new KeyTrigger(keyInput.KEY_UP), new KeyTrigger(keyInput.KEY_W));
+ inputManager.addMapping("moveBackward", new KeyTrigger(keyInput.KEY_DOWN), new KeyTrigger(keyInput.KEY_S));
+ inputManager.addMapping("moveRight", new KeyTrigger(keyInput.KEY_RIGHT), new KeyTrigger(keyInput.KEY_D));
+ inputManager.addMapping("moveLeft", new KeyTrigger(keyInput.KEY_LEFT), new KeyTrigger(keyInput.KEY_A));
+ inputManager.addMapping("displayPosition", new KeyTrigger(keyInput.KEY_P));
+ inputManager.addListener(this, "moveForward", "moveBackward", "moveRight", "moveLeft");
+ inputManager.addListener(this, "displayPosition");
+ }
+
+ public void onAnalog(String name, float value, float tpf) {
+ if (name.equals("moveForward")) {
+ teaGeom.move(0, 0, -5 * tpf);
+ }
+ if (name.equals("moveBackward")) {
+ teaGeom.move(0, 0, 5 * tpf);
+ }
+ if (name.equals("moveRight")) {
+ teaGeom.move(5 * tpf, 0, 0);
+ }
+ if (name.equals("moveLeft")) {
+ teaGeom.move(-5 * tpf, 0, 0);
+
+ }
+
+ }
+
+ public void onAction(String name, boolean keyPressed, float tpf) {
+ if (name.equals("displayPosition") && keyPressed) {
+ teaGeom.move(10, 10, 10);
+
+ }
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ super.simpleUpdate(tpf);
+
+ // teaGeom.move(new Vector3f(0.001f, 0, 0));
+ // pivot.rotate(0, 0.00001f, 0);
+ // rootNode.updateGeometricState();
+ }
+// public void update() {
+// super.update();
+//// render the viewports
+// float tpf = timer.getTimePerFrame();
+// state.getRootNode().rotate(0, 0.000001f, 0);
+// stateManager.update(tpf);
+// stateManager.render(renderManager);
+// renderManager.render(tpf);
+// }
+}
diff --git a/JmeTests/src/jme3test/input/TestChaseCameraAppState.java b/JmeTests/src/jme3test/input/TestChaseCameraAppState.java
new file mode 100644
index 0000000..00d6dd8
--- /dev/null
+++ b/JmeTests/src/jme3test/input/TestChaseCameraAppState.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2009-2018 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.input;
+
+import com.jme3.app.ChaseCameraAppState;
+import com.jme3.app.FlyCamAppState;
+import com.jme3.app.SimpleApplication;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.AnalogListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.material.Material;
+import com.jme3.math.FastMath;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Quad;
+
+/** A 3rd-person chase camera orbits a target (teapot).
+ * Follow the teapot with WASD keys, rotate by dragging the mouse. */
+public class TestChaseCameraAppState extends SimpleApplication implements AnalogListener, ActionListener {
+
+ private Geometry teaGeom;
+
+ public static void main(String[] args) {
+ TestChaseCameraAppState app = new TestChaseCameraAppState();
+ app.start();
+ }
+
+ public void simpleInitApp() {
+ // Load a teapot model
+ teaGeom = (Geometry) assetManager.loadModel("Models/Teapot/Teapot.obj");
+ Material mat_tea = new Material(assetManager, "Common/MatDefs/Misc/ShowNormals.j3md");
+ teaGeom.setMaterial(mat_tea);
+ rootNode.attachChild(teaGeom);
+
+ // Load a floor model
+ Material mat_ground = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat_ground.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg"));
+ Geometry ground = new Geometry("ground", new Quad(50, 50));
+ ground.setLocalRotation(new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X));
+ ground.setLocalTranslation(-25, -1, 25);
+ ground.setMaterial(mat_ground);
+ rootNode.attachChild(ground);
+
+ //disable the flyCam
+ stateManager.detach(stateManager.getState(FlyCamAppState.class));
+
+ // Enable a chase cam
+ ChaseCameraAppState chaseCamAS = new ChaseCameraAppState();
+ chaseCamAS.setTarget(teaGeom);
+ stateManager.attach(chaseCamAS);
+
+ //Uncomment this to invert the camera's vertical rotation Axis
+ //chaseCamAS.setInvertVerticalAxis(true);
+
+ //Uncomment this to invert the camera's horizontal rotation Axis
+ //chaseCamAS.setInvertHorizontalAxis(true);
+
+ //Uncomment this to enable rotation when the middle mouse button is pressed (like Blender)
+ //WARNING : setting this trigger disable the rotation on right and left mouse button click
+ //chaseCamAS.setToggleRotationTrigger(new MouseButtonTrigger(MouseInput.BUTTON_MIDDLE));
+
+ //Uncomment this to set multiple triggers to enable rotation of the cam
+ //Here space bar and middle mouse button
+ //chaseCamAS.setToggleRotationTrigger(new MouseButtonTrigger(MouseInput.BUTTON_MIDDLE),new KeyTrigger(KeyInput.KEY_SPACE));
+
+ //registering inputs for target's movement
+ registerInput();
+
+ }
+
+ public void registerInput() {
+ inputManager.addMapping("moveForward", new KeyTrigger(KeyInput.KEY_UP), new KeyTrigger(KeyInput.KEY_W));
+ inputManager.addMapping("moveBackward", new KeyTrigger(KeyInput.KEY_DOWN), new KeyTrigger(KeyInput.KEY_S));
+ inputManager.addMapping("moveRight", new KeyTrigger(KeyInput.KEY_RIGHT), new KeyTrigger(KeyInput.KEY_D));
+ inputManager.addMapping("moveLeft", new KeyTrigger(KeyInput.KEY_LEFT), new KeyTrigger(KeyInput.KEY_A));
+ inputManager.addMapping("displayPosition", new KeyTrigger(KeyInput.KEY_P));
+ inputManager.addListener(this, "moveForward", "moveBackward", "moveRight", "moveLeft");
+ inputManager.addListener(this, "displayPosition");
+ }
+
+ public void onAnalog(String name, float value, float tpf) {
+ if (name.equals("moveForward")) {
+ teaGeom.move(0, 0, -5 * tpf);
+ }
+ if (name.equals("moveBackward")) {
+ teaGeom.move(0, 0, 5 * tpf);
+ }
+ if (name.equals("moveRight")) {
+ teaGeom.move(5 * tpf, 0, 0);
+ }
+ if (name.equals("moveLeft")) {
+ teaGeom.move(-5 * tpf, 0, 0);
+
+ }
+
+ }
+
+ public void onAction(String name, boolean keyPressed, float tpf) {
+ if (name.equals("displayPosition") && keyPressed) {
+ teaGeom.move(10, 10, 10);
+
+ }
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ super.simpleUpdate(tpf);
+
+ // teaGeom.move(new Vector3f(0.001f, 0, 0));
+ // pivot.rotate(0, 0.00001f, 0);
+ // rootNode.updateGeometricState();
+ }
+// public void update() {
+// super.update();
+//// render the viewports
+// float tpf = timer.getTimePerFrame();
+// state.getRootNode().rotate(0, 0.000001f, 0);
+// stateManager.update(tpf);
+// stateManager.render(renderManager);
+// renderManager.render(tpf);
+// }
+}
diff --git a/JmeTests/src/jme3test/input/TestControls.java b/JmeTests/src/jme3test/input/TestControls.java
new file mode 100644
index 0000000..07568b2
--- /dev/null
+++ b/JmeTests/src/jme3test/input/TestControls.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.input;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.input.KeyInput;
+import com.jme3.input.MouseInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.AnalogListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.input.controls.MouseAxisTrigger;
+
+public class TestControls extends SimpleApplication {
+
+ private ActionListener actionListener = new ActionListener(){
+ public void onAction(String name, boolean pressed, float tpf){
+ System.out.println(name + " = " + pressed);
+ }
+ };
+ public AnalogListener analogListener = new AnalogListener() {
+ public void onAnalog(String name, float value, float tpf) {
+ System.out.println(name + " = " + value);
+ }
+ };
+
+ public static void main(String[] args){
+ TestControls app = new TestControls();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ // Test multiple inputs per mapping
+ inputManager.addMapping("My Action",
+ new KeyTrigger(KeyInput.KEY_SPACE),
+ new MouseAxisTrigger(MouseInput.AXIS_WHEEL, false));
+
+ // Test multiple listeners per mapping
+ inputManager.addListener(actionListener, "My Action");
+ inputManager.addListener(analogListener, "My Action");
+ }
+
+}
diff --git a/JmeTests/src/jme3test/input/TestJoystick.java b/JmeTests/src/jme3test/input/TestJoystick.java
new file mode 100644
index 0000000..29a9166
--- /dev/null
+++ b/JmeTests/src/jme3test/input/TestJoystick.java
@@ -0,0 +1,443 @@
+package jme3test.input;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.collision.CollisionResult;
+import com.jme3.collision.CollisionResults;
+import com.jme3.font.BitmapText;
+import com.jme3.input.Joystick;
+import com.jme3.input.JoystickAxis;
+import com.jme3.input.JoystickButton;
+import com.jme3.input.RawInputListener;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.MouseButtonTrigger;
+import com.jme3.input.event.JoyAxisEvent;
+import com.jme3.input.event.JoyButtonEvent;
+import com.jme3.input.event.KeyInputEvent;
+import com.jme3.input.event.MouseButtonEvent;
+import com.jme3.input.event.MouseMotionEvent;
+import com.jme3.input.event.TouchEvent;
+import com.jme3.material.Material;
+import com.jme3.material.RenderState.BlendMode;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Ray;
+import com.jme3.math.Vector2f;
+import com.jme3.math.Vector3f;
+import com.jme3.renderer.Camera;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.shape.Quad;
+import com.jme3.system.AppSettings;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.Map;
+
+public class TestJoystick extends SimpleApplication {
+
+ private Joystick viewedJoystick;
+ private GamepadView gamepad;
+ private Node joystickInfo;
+ private float yInfo = 0;
+ private JoystickButton lastButton;
+
+ public static void main(String[] args){
+ TestJoystick app = new TestJoystick();
+ AppSettings settings = new AppSettings(true);
+ settings.setUseJoysticks(true);
+ app.setSettings(settings);
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ getFlyByCamera().setEnabled(false);
+
+ Joystick[] joysticks = inputManager.getJoysticks();
+ if (joysticks == null)
+ throw new IllegalStateException("Cannot find any joysticks!");
+
+ try {
+ PrintWriter out = new PrintWriter( new FileWriter( "joysticks-" + System.currentTimeMillis() + ".txt" ) );
+ dumpJoysticks( joysticks, out );
+ out.close();
+ } catch( IOException e ) {
+ throw new RuntimeException( "Error writing joystick dump", e );
+ }
+
+
+ int gamepadSize = cam.getHeight() / 2;
+ float scale = gamepadSize / 512.0f;
+ gamepad = new GamepadView();
+ gamepad.setLocalTranslation( cam.getWidth() - gamepadSize - (scale * 20), 0, 0 );
+ gamepad.setLocalScale( scale, scale, scale );
+ guiNode.attachChild(gamepad);
+
+ joystickInfo = new Node( "joystickInfo" );
+ joystickInfo.setLocalTranslation( 0, cam.getHeight(), 0 );
+ guiNode.attachChild( joystickInfo );
+
+ // Add a raw listener because it's eisier to get all joystick events
+ // this way.
+ inputManager.addRawInputListener( new JoystickEventListener() );
+
+ // add action listener for mouse click
+ // to all easier custom mapping
+ inputManager.addMapping("mouseClick", new MouseButtonTrigger(mouseInput.BUTTON_LEFT));
+ inputManager.addListener(new ActionListener() {
+ @Override
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if(isPressed){
+ pickGamePad(getInputManager().getCursorPosition());
+ }
+ }
+ }, "mouseClick");
+ }
+
+ protected void dumpJoysticks( Joystick[] joysticks, PrintWriter out ) {
+ for( Joystick j : joysticks ) {
+ out.println( "Joystick[" + j.getJoyId() + "]:" + j.getName() );
+ out.println( " buttons:" + j.getButtonCount() );
+ for( JoystickButton b : j.getButtons() ) {
+ out.println( " " + b );
+ }
+
+ out.println( " axes:" + j.getAxisCount() );
+ for( JoystickAxis axis : j.getAxes() ) {
+ out.println( " " + axis );
+ }
+ }
+ }
+
+ protected void addInfo( String info, int column ) {
+
+ BitmapText t = new BitmapText(guiFont);
+ t.setText( info );
+ t.setLocalTranslation( column * 200, yInfo, 0 );
+ joystickInfo.attachChild(t);
+ yInfo -= t.getHeight();
+ }
+
+ protected void setViewedJoystick( Joystick stick ) {
+ if( this.viewedJoystick == stick )
+ return;
+
+ if( this.viewedJoystick != null ) {
+ joystickInfo.detachAllChildren();
+ }
+
+ this.viewedJoystick = stick;
+
+ if( this.viewedJoystick != null ) {
+ // Draw the hud
+ yInfo = 0;
+
+ addInfo( "Joystick:\"" + stick.getName() + "\" id:" + stick.getJoyId(), 0 );
+
+ yInfo -= 5;
+
+ float ySave = yInfo;
+
+ // Column one for the buttons
+ addInfo( "Buttons:", 0 );
+ for( JoystickButton b : stick.getButtons() ) {
+ addInfo( " '" + b.getName() + "' id:'" + b.getLogicalId() + "'", 0 );
+ }
+ yInfo = ySave;
+
+ // Column two for the axes
+ addInfo( "Axes:", 1 );
+ for( JoystickAxis a : stick.getAxes() ) {
+ addInfo( " '" + a.getName() + "' id:'" + a.getLogicalId() + "' analog:" + a.isAnalog(), 1 );
+ }
+
+ }
+ }
+
+ /**
+ * Easier to watch for all button and axis events with a raw input listener.
+ */
+ protected class JoystickEventListener implements RawInputListener {
+
+ public void onJoyAxisEvent(JoyAxisEvent evt) {
+ setViewedJoystick( evt.getAxis().getJoystick() );
+ gamepad.setAxisValue( evt.getAxis(), evt.getValue() );
+ }
+
+ public void onJoyButtonEvent(JoyButtonEvent evt) {
+ setViewedJoystick( evt.getButton().getJoystick() );
+ gamepad.setButtonValue( evt.getButton(), evt.isPressed() );
+ }
+
+ public void beginInput() {}
+ public void endInput() {}
+ public void onMouseMotionEvent(MouseMotionEvent evt) {}
+ public void onMouseButtonEvent(MouseButtonEvent evt) {}
+ public void onKeyEvent(KeyInputEvent evt) {}
+ public void onTouchEvent(TouchEvent evt) {}
+ }
+
+ protected class GamepadView extends Node {
+
+ float xAxis = 0;
+ float yAxis = 0;
+ float zAxis = 0;
+ float zRotation = 0;
+
+ float lastPovX = 0;
+ float lastPovY = 0;
+
+ Geometry leftStick;
+ Geometry rightStick;
+
+ Map buttons = new HashMap();
+
+ public GamepadView() {
+ super( "gamepad" );
+
+ // Sizes naturally for the texture size. All positions will
+ // be in that space because it's easier.
+ int size = 512;
+
+ Material m = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ m.setTexture( "ColorMap", assetManager.loadTexture( "Interface/Joystick/gamepad-buttons.png" ) );
+ m.getAdditionalRenderState().setBlendMode( BlendMode.Alpha );
+ Geometry buttonPanel = new Geometry( "buttons", new Quad(size, size) );
+ buttonPanel.setLocalTranslation( 0, 0, -1 );
+ buttonPanel.setMaterial(m);
+ attachChild(buttonPanel);
+
+ m = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ m.setTexture( "ColorMap", assetManager.loadTexture( "Interface/Joystick/gamepad-frame.png" ) );
+ m.getAdditionalRenderState().setBlendMode( BlendMode.Alpha );
+ Geometry frame = new Geometry( "frame", new Quad(size, size) );
+ frame.setMaterial(m);
+ attachChild(frame);
+
+ m = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ m.setTexture( "ColorMap", assetManager.loadTexture( "Interface/Joystick/gamepad-stick.png" ) );
+ m.getAdditionalRenderState().setBlendMode( BlendMode.Alpha );
+ leftStick = new Geometry( "leftStick", new Quad(64, 64) );
+ leftStick.setMaterial(m);
+ attachChild(leftStick);
+ rightStick = new Geometry( "rightStick", new Quad(64, 64) );
+ rightStick.setMaterial(m);
+ attachChild(rightStick);
+
+ // A "standard" mapping... fits a majority of my game pads
+ addButton( JoystickButton.BUTTON_0, 371, 512 - 176, 42, 42 );
+ addButton( JoystickButton.BUTTON_1, 407, 512 - 212, 42, 42 );
+ addButton( JoystickButton.BUTTON_2, 371, 512 - 248, 42, 42 );
+ addButton( JoystickButton.BUTTON_3, 334, 512 - 212, 42, 42 );
+
+ // Front buttons Some of these have the top ones and the bottoms ones flipped.
+ addButton( JoystickButton.BUTTON_4, 67, 512 - 111, 95, 21 );
+ addButton( JoystickButton.BUTTON_5, 348, 512 - 111, 95, 21 );
+ addButton( JoystickButton.BUTTON_6, 67, 512 - 89, 95, 21 );
+ addButton( JoystickButton.BUTTON_7, 348, 512 - 89, 95, 21 );
+
+ // Select and start buttons
+ addButton( JoystickButton.BUTTON_8, 206, 512 - 198, 48, 30 );
+ addButton( JoystickButton.BUTTON_9, 262, 512 - 198, 48, 30 );
+
+ // Joystick push buttons
+ addButton( JoystickButton.BUTTON_10, 147, 512 - 300, 75, 70 );
+ addButton( JoystickButton.BUTTON_11, 285, 512 - 300, 75, 70 );
+
+ // Fake button highlights for the POV axes
+ //
+ // +Y
+ // -X +X
+ // -Y
+ //
+ addButton( "POV +Y", 96, 512 - 174, 40, 38 );
+ addButton( "POV +X", 128, 512 - 208, 40, 38 );
+ addButton( "POV -Y", 96, 512 - 239, 40, 38 );
+ addButton( "POV -X", 65, 512 - 208, 40, 38 );
+
+ resetPositions();
+ }
+
+ private void addButton( String name, float x, float y, float width, float height ) {
+ ButtonView b = new ButtonView(name, x, y, width, height);
+ attachChild(b);
+ buttons.put(name, b);
+ }
+
+ public void setAxisValue( JoystickAxis axis, float value ) {
+ System.out.println( "Axis:" + axis.getName() + "=" + value );
+ if( axis == axis.getJoystick().getXAxis() ) {
+ setXAxis(value);
+ } else if( axis == axis.getJoystick().getYAxis() ) {
+ setYAxis(-value);
+ } else if( axis == axis.getJoystick().getAxis(JoystickAxis.Z_AXIS) ) {
+ // Note: in the above condition, we could check the axis name but
+ // I have at least one joystick that reports 2 "Z Axis" axes.
+ // In this particular case, the first one is the right one so
+ // a name based lookup will find the proper one. It's a problem
+ // because the erroneous axis sends a constant stream of values.
+ setZAxis(value);
+ } else if( axis == axis.getJoystick().getAxis(JoystickAxis.Z_ROTATION) ) {
+ setZRotation(-value);
+ } else if( axis == axis.getJoystick().getPovXAxis() ) {
+ if( lastPovX < 0 ) {
+ setButtonValue( "POV -X", false );
+ } else if( lastPovX > 0 ) {
+ setButtonValue( "POV +X", false );
+ }
+ if( value < 0 ) {
+ setButtonValue( "POV -X", true );
+ } else if( value > 0 ) {
+ setButtonValue( "POV +X", true );
+ }
+ lastPovX = value;
+ } else if( axis == axis.getJoystick().getPovYAxis() ) {
+ if( lastPovY < 0 ) {
+ setButtonValue( "POV -Y", false );
+ } else if( lastPovY > 0 ) {
+ setButtonValue( "POV +Y", false );
+ }
+ if( value < 0 ) {
+ setButtonValue( "POV -Y", true );
+ } else if( value > 0 ) {
+ setButtonValue( "POV +Y", true );
+ }
+ lastPovY = value;
+ }
+ }
+
+ public void setButtonValue( JoystickButton button, boolean isPressed ) {
+ System.out.println( "Button:" + button.getName() + "=" + (isPressed ? "Down" : "Up") );
+ setButtonValue( button.getLogicalId(), isPressed );
+ lastButton = button;
+ }
+
+ protected void setButtonValue( String name, boolean isPressed ) {
+ ButtonView view = buttons.get(name);
+ if( view != null ) {
+ if( isPressed ) {
+ view.down();
+ } else {
+ view.up();
+ }
+ }
+ }
+
+ public void setXAxis( float f ) {
+ xAxis = f;
+ resetPositions();
+ }
+
+ public void setYAxis( float f ) {
+ yAxis = f;
+ resetPositions();
+ }
+
+ public void setZAxis( float f ) {
+ zAxis = f;
+ resetPositions();
+ }
+
+ public void setZRotation( float f ) {
+ zRotation = f;
+ resetPositions();
+ }
+
+ private void resetPositions() {
+
+ float xBase = 155;
+ float yBase = 212;
+
+ Vector2f dir = new Vector2f(xAxis, yAxis);
+ float length = Math.min(1, dir.length());
+ dir.normalizeLocal();
+
+ float angle = dir.getAngle();
+ float x = FastMath.cos(angle) * length * 10;
+ float y = FastMath.sin(angle) * length * 10;
+ leftStick.setLocalTranslation( xBase + x, yBase + y, 0 );
+
+
+ xBase = 291;
+ dir = new Vector2f(zAxis, zRotation);
+ length = Math.min(1, dir.length());
+ dir.normalizeLocal();
+
+ angle = dir.getAngle();
+ x = FastMath.cos(angle) * length * 10;
+ y = FastMath.sin(angle) * length * 10;
+ rightStick.setLocalTranslation( xBase + x, yBase + y, 0 );
+ }
+ }
+
+ protected class ButtonView extends Node {
+
+ private int state = 0;
+ private Material material;
+ private ColorRGBA hilite = new ColorRGBA( 0.0f, 0.75f, 0.75f, 0.5f );
+
+ public ButtonView( String name, float x, float y, float width, float height ) {
+ super( "Button:" + name );
+ setLocalTranslation( x, y, -0.5f );
+
+ material = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ material.setColor( "Color", hilite );
+ material.getAdditionalRenderState().setBlendMode( BlendMode.Alpha );
+
+ Geometry g = new Geometry( "highlight", new Quad(width, height) );
+ g.setMaterial(material);
+ attachChild(g);
+
+ resetState();
+ }
+
+ private void resetState() {
+ if( state <= 0 ) {
+ setCullHint( CullHint.Always );
+ } else {
+ setCullHint( CullHint.Dynamic );
+ }
+
+ System.out.println( getName() + " state:" + state );
+ }
+
+ public void down() {
+ state++;
+ resetState();
+ }
+
+ public void up() {
+ state--;
+ resetState();
+ }
+ }
+
+ private void pickGamePad(Vector2f mouseLoc){
+ if (lastButton != null) {
+ CollisionResults cresults = pick(cam, mouseLoc, gamepad);
+ for (CollisionResult cr : cresults) {
+ Node n = cr.getGeometry().getParent();
+ if (n != null && (n instanceof ButtonView)) {
+ String b = ((ButtonView) n).getName().substring("Button:".length());
+ String name = lastButton.getJoystick().getName().replaceAll(" ", "\\\\ ");
+ String id = lastButton.getLogicalId().replaceAll(" ", "\\\\ ");
+ System.out.println(name + "." + id + "=" + b);
+ return;
+ }
+ }
+ }
+ }
+
+ private static CollisionResults pick(Camera cam, Vector2f mouseLoc, Node node) {
+ CollisionResults results = new CollisionResults();
+ Ray ray = new Ray();
+ Vector3f pos = new Vector3f(mouseLoc.x, mouseLoc.y, -1);
+ Vector3f dir = new Vector3f(mouseLoc.x, mouseLoc.y, 1);
+ dir.subtractLocal(pos).normalizeLocal();
+ ray.setOrigin(pos);
+ ray.setDirection(dir);
+ node.collideWith(ray, results);
+ return results;
+ }
+}
diff --git a/JmeTests/src/jme3test/input/combomoves/ComboMove.java b/JmeTests/src/jme3test/input/combomoves/ComboMove.java
new file mode 100644
index 0000000..ee1a3c3
--- /dev/null
+++ b/JmeTests/src/jme3test/input/combomoves/ComboMove.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.input.combomoves;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ComboMove {
+
+ public static class ComboMoveState {
+
+ private String[] pressedMappings;
+ private String[] unpressedMappings;
+ private float timeElapsed;
+
+ public ComboMoveState(String[] pressedMappings, String[] unpressedMappings, float timeElapsed) {
+ this.pressedMappings = pressedMappings;
+ this.unpressedMappings = unpressedMappings;
+ this.timeElapsed = timeElapsed;
+ }
+
+ public String[] getUnpressedMappings() {
+ return unpressedMappings;
+ }
+
+ public String[] getPressedMappings() {
+ return pressedMappings;
+ }
+
+ public float getTimeElapsed() {
+ return timeElapsed;
+ }
+
+ }
+
+ private String moveName;
+ private List states = new ArrayList();
+ private boolean useFinalState = true;
+ private float priority = 1;
+ private float castTime = 0.8f;
+
+ private transient String[] pressed, unpressed;
+ private transient float timeElapsed;
+
+ public ComboMove(String moveName){
+ this.moveName = moveName;
+ }
+
+ public float getPriority() {
+ return priority;
+ }
+
+ public void setPriority(float priority) {
+ this.priority = priority;
+ }
+
+ public float getCastTime() {
+ return castTime;
+ }
+
+ public void setCastTime(float castTime) {
+ this.castTime = castTime;
+ }
+
+ public boolean useFinalState() {
+ return useFinalState;
+ }
+
+ public void setUseFinalState(boolean useFinalState) {
+ this.useFinalState = useFinalState;
+ }
+
+ public ComboMove press(String ... pressedMappings){
+ this.pressed = pressedMappings;
+ return this;
+ }
+
+ public ComboMove notPress(String ... unpressedMappings){
+ this.unpressed = unpressedMappings;
+ return this;
+ }
+
+ public ComboMove timeElapsed(float time){
+ this.timeElapsed = time;
+ return this;
+ }
+
+ public void done(){
+ if (pressed == null)
+ pressed = new String[0];
+
+ if (unpressed == null)
+ unpressed = new String[0];
+
+ states.add(new ComboMoveState(pressed, unpressed, timeElapsed));
+ pressed = null;
+ unpressed = null;
+ timeElapsed = -1;
+ }
+
+ public ComboMoveState getState(int num){
+ return states.get(num);
+ }
+
+ public int getNumStates(){
+ return states.size();
+ }
+
+ public String getMoveName() {
+ return moveName;
+ }
+
+}
diff --git a/JmeTests/src/jme3test/input/combomoves/ComboMoveExecution.java b/JmeTests/src/jme3test/input/combomoves/ComboMoveExecution.java
new file mode 100644
index 0000000..9b8e266
--- /dev/null
+++ b/JmeTests/src/jme3test/input/combomoves/ComboMoveExecution.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.input.combomoves;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import jme3test.input.combomoves.ComboMove.ComboMoveState;
+
+public class ComboMoveExecution {
+
+ private static final float TIME_LIMIT = 0.3f;
+
+ private ComboMove moveDef;
+ private int state;
+ private float moveTime;
+ private boolean finalState = false;
+
+ private String debugString = ""; // for debug only
+
+ public ComboMoveExecution(ComboMove move){
+ moveDef = move;
+ }
+
+ private boolean isStateSatisfied(HashSet pressedMappings, float time,
+ ComboMoveState state){
+
+ if (state.getTimeElapsed() != -1f){
+ // check if an appropriate amount of time has passed
+ // if the state requires it
+ if (moveTime + state.getTimeElapsed() >= time){
+ return false;
+ }
+ }
+ for (String mapping : state.getPressedMappings()){
+ if (!pressedMappings.contains(mapping))
+ return false;
+ }
+ for (String mapping : state.getUnpressedMappings()){
+ if (pressedMappings.contains(mapping))
+ return false;
+ }
+ return true;
+ }
+
+ public String getDebugString(){
+ return debugString;
+ }
+
+ public void updateExpiration(float time){
+ if (!finalState && moveTime > 0 && moveTime + TIME_LIMIT < time){
+ state = 0;
+ moveTime = 0;
+ finalState = false;
+
+ // reset debug string.
+ debugString = "";
+ }
+ }
+
+ /**
+ * Check if move needs to be executed.
+ * @param pressedMappings Which mappings are currently pressed
+ * @param time Current time since start of app
+ * @return True if move needs to be executed.
+ */
+ public boolean updateState(HashSet pressedMappings, float time){
+ ComboMoveState currentState = moveDef.getState(state);
+ if (isStateSatisfied(pressedMappings, time, currentState)){
+ state ++;
+ moveTime = time;
+
+ if (state >= moveDef.getNumStates()){
+ finalState = false;
+ state = 0;
+
+ moveTime = time+0.5f; // this is for the reset of the debug string only.
+ debugString += ", -CASTING " + moveDef.getMoveName().toUpperCase() + "-";
+ return true;
+ }
+
+ // the following for debug only.
+ if (currentState.getPressedMappings().length > 0){
+ if (!debugString.equals(""))
+ debugString += ", ";
+
+ debugString += Arrays.toString(currentState.getPressedMappings()).replace(", ", "+");
+ }
+
+ if (moveDef.useFinalState() && state == moveDef.getNumStates() - 1){
+ finalState = true;
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/JmeTests/src/jme3test/input/combomoves/TestComboMoves.java b/JmeTests/src/jme3test/input/combomoves/TestComboMoves.java
new file mode 100644
index 0000000..3ca46db
--- /dev/null
+++ b/JmeTests/src/jme3test/input/combomoves/TestComboMoves.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.input.combomoves;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.font.BitmapText;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.math.ColorRGBA;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+
+public class TestComboMoves extends SimpleApplication implements ActionListener {
+
+ private HashSet pressedMappings = new HashSet();
+
+ private ComboMove fireball;
+ private ComboMoveExecution fireballExec;
+ private BitmapText fireballText;
+
+ private ComboMove shuriken;
+ private ComboMoveExecution shurikenExec;
+ private BitmapText shurikenText;
+
+ private ComboMove jab;
+ private ComboMoveExecution jabExec;
+ private BitmapText jabText;
+
+ private ComboMove punch;
+ private ComboMoveExecution punchExec;
+ private BitmapText punchText;
+
+ private ComboMove currentMove = null;
+ private float currentMoveCastTime = 0;
+ private float time = 0;
+
+ public static void main(String[] args){
+ TestComboMoves app = new TestComboMoves();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ setDisplayFps(false);
+ setDisplayStatView(false);
+
+ // Create debug text
+ BitmapText helpText = new BitmapText(guiFont);
+ helpText.setLocalTranslation(0, settings.getHeight(), 0);
+ helpText.setText("Moves:\n" +
+ "Fireball: Down, Down+Right, Right\n"+
+ "Shuriken: Left, Down, Attack1(Z)\n"+
+ "Jab: Attack1(Z)\n"+
+ "Punch: Attack1(Z), Attack1(Z)\n");
+ guiNode.attachChild(helpText);
+
+ fireballText = new BitmapText(guiFont);
+ fireballText.setColor(ColorRGBA.Orange);
+ fireballText.setLocalTranslation(0, fireballText.getLineHeight(), 0);
+ guiNode.attachChild(fireballText);
+
+ shurikenText = new BitmapText(guiFont);
+ shurikenText.setColor(ColorRGBA.Cyan);
+ shurikenText.setLocalTranslation(0, shurikenText.getLineHeight()*2f, 0);
+ guiNode.attachChild(shurikenText);
+
+ jabText = new BitmapText(guiFont);
+ jabText.setColor(ColorRGBA.Red);
+ jabText.setLocalTranslation(0, jabText.getLineHeight()*3f, 0);
+ guiNode.attachChild(jabText);
+
+ punchText = new BitmapText(guiFont);
+ punchText.setColor(ColorRGBA.Green);
+ punchText.setLocalTranslation(0, punchText.getLineHeight()*4f, 0);
+ guiNode.attachChild(punchText);
+
+ inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_LEFT));
+ inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_RIGHT));
+ inputManager.addMapping("Up", new KeyTrigger(KeyInput.KEY_UP));
+ inputManager.addMapping("Down", new KeyTrigger(KeyInput.KEY_DOWN));
+ inputManager.addMapping("Attack1", new KeyTrigger(KeyInput.KEY_Z));
+ inputManager.addListener(this, "Left", "Right", "Up", "Down", "Attack1");
+
+ fireball = new ComboMove("Fireball");
+ fireball.press("Down").notPress("Right").done();
+ fireball.press("Right", "Down").done();
+ fireball.press("Right").notPress("Down").done();
+ fireball.notPress("Right", "Down").done();
+ fireball.setUseFinalState(false); // no waiting on final state
+
+ shuriken = new ComboMove("Shuriken");
+ shuriken.press("Left").notPress("Down", "Attack1").done();
+ shuriken.press("Down").notPress("Attack1").timeElapsed(0.11f).done();
+ shuriken.press("Attack1").notPress("Left").timeElapsed(0.11f).done();
+ shuriken.notPress("Left", "Down", "Attack1").done();
+
+ jab = new ComboMove("Jab");
+ jab.setPriority(0.5f); // make jab less important than other moves
+ jab.press("Attack1").done();
+
+ punch = new ComboMove("Punch");
+ punch.press("Attack1").done();
+ punch.notPress("Attack1").done();
+ punch.press("Attack1").done();
+
+ fireballExec = new ComboMoveExecution(fireball);
+ shurikenExec = new ComboMoveExecution(shuriken);
+ jabExec = new ComboMoveExecution(jab);
+ punchExec = new ComboMoveExecution(punch);
+ }
+
+ @Override
+ public void simpleUpdate(float tpf){
+ time += tpf;
+
+ // check every frame if any executions are expired
+ shurikenExec.updateExpiration(time);
+ shurikenText.setText("Shuriken Exec: " + shurikenExec.getDebugString());
+
+ fireballExec.updateExpiration(time);
+ fireballText.setText("Fireball Exec: " + fireballExec.getDebugString());
+
+ jabExec.updateExpiration(time);
+ jabText.setText("Jab Exec: " + jabExec.getDebugString());
+
+ punchExec.updateExpiration(time);
+ punchText.setText("Punch Exec: " + punchExec.getDebugString());
+
+ if (currentMove != null){
+ currentMoveCastTime -= tpf;
+ if (currentMoveCastTime <= 0){
+ System.out.println("DONE CASTING " + currentMove.getMoveName());
+ currentMoveCastTime = 0;
+ currentMove = null;
+ }
+ }
+ }
+
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if (isPressed){
+ pressedMappings.add(name);
+ }else{
+ pressedMappings.remove(name);
+ }
+
+ // the pressed mappings was changed. update combo executions
+ List invokedMoves = new ArrayList();
+ if (shurikenExec.updateState(pressedMappings, time)){
+ invokedMoves.add(shuriken);
+ }
+
+ if (fireballExec.updateState(pressedMappings, time)){
+ invokedMoves.add(fireball);
+ }
+
+ if (jabExec.updateState(pressedMappings, time)){
+ invokedMoves.add(jab);
+ }
+
+ if (punchExec.updateState(pressedMappings, time)){
+ invokedMoves.add(punch);
+ }
+
+ if (invokedMoves.size() > 0){
+ // choose move with highest priority
+ float priority = 0;
+ ComboMove toExec = null;
+ for (ComboMove move : invokedMoves){
+ if (move.getPriority() > priority){
+ priority = move.getPriority();
+ toExec = move;
+ }
+ }
+ if (currentMove != null && currentMove.getPriority() > toExec.getPriority()){
+ return;
+ }
+
+ currentMove = toExec;
+ currentMoveCastTime = currentMove.getCastTime();
+ //System.out.println("CASTING " + currentMove.getMoveName());
+ }
+ }
+
+}
diff --git a/JmeTests/src/jme3test/light/ShadowTestUIManager.java b/JmeTests/src/jme3test/light/ShadowTestUIManager.java
new file mode 100644
index 0000000..38d0548
--- /dev/null
+++ b/JmeTests/src/jme3test/light/ShadowTestUIManager.java
@@ -0,0 +1,154 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package jme3test.light;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.font.BitmapFont;
+import com.jme3.font.BitmapText;
+import com.jme3.input.InputManager;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.renderer.Camera;
+import com.jme3.renderer.ViewPort;
+import com.jme3.scene.Node;
+import com.jme3.shadow.AbstractShadowFilter;
+import com.jme3.shadow.AbstractShadowRenderer;
+import com.jme3.shadow.CompareMode;
+import com.jme3.shadow.EdgeFilteringMode;
+
+/**
+ *
+ * @author Nehon
+ */
+public class ShadowTestUIManager implements ActionListener {
+
+ private BitmapText shadowTypeText;
+ private BitmapText shadowCompareText;
+ private BitmapText shadowFilterText;
+ private BitmapText shadowIntensityText;
+ private final static String TYPE_TEXT = "(Space) Shadow type : ";
+ private final static String COMPARE_TEXT = "(enter) Shadow compare ";
+ private final static String FILTERING_TEXT = "(f) Edge filtering : ";
+ private final static String INTENSITY_TEXT = "(t:up, g:down) Shadow intensity : ";
+ private boolean hardwareShadows = true;
+ private AbstractShadowRenderer plsr;
+ private AbstractShadowFilter plsf;
+ private ViewPort viewPort;
+ private int filteringIndex = 0;
+ private int renderModeIndex = 0;
+
+
+ public ShadowTestUIManager(AssetManager assetManager,AbstractShadowRenderer plsr, AbstractShadowFilter plsf,
+ Node guiNode, InputManager inputManager, ViewPort viewPort) {
+ this.plsr = plsr;
+ this.plsf = plsf;
+ this.viewPort = viewPort;
+ BitmapFont guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
+ shadowTypeText = createText(guiFont);
+ shadowCompareText = createText(guiFont);
+ shadowFilterText = createText(guiFont);
+ shadowIntensityText = createText(guiFont);
+
+ shadowTypeText.setText(TYPE_TEXT + "Processor");
+ shadowCompareText.setText(COMPARE_TEXT + (hardwareShadows ? "Hardware" : "Software"));
+ shadowFilterText.setText(FILTERING_TEXT + plsr.getEdgeFilteringMode().toString());
+ shadowIntensityText.setText(INTENSITY_TEXT + plsr.getShadowIntensity());
+
+ shadowTypeText.setLocalTranslation(10, viewPort.getCamera().getHeight() - 20, 0);
+ shadowCompareText.setLocalTranslation(10, viewPort.getCamera().getHeight() - 40, 0);
+ shadowFilterText.setLocalTranslation(10, viewPort.getCamera().getHeight() - 60, 0);
+ shadowIntensityText.setLocalTranslation(10, viewPort.getCamera().getHeight() - 80, 0);
+
+ guiNode.attachChild(shadowTypeText);
+ guiNode.attachChild(shadowCompareText);
+ guiNode.attachChild(shadowFilterText);
+ guiNode.attachChild(shadowIntensityText);
+
+ inputManager.addMapping("toggle", new KeyTrigger(KeyInput.KEY_SPACE));
+ inputManager.addMapping("changeFiltering", new KeyTrigger(KeyInput.KEY_F));
+ inputManager.addMapping("ShadowUp", new KeyTrigger(KeyInput.KEY_T));
+ inputManager.addMapping("ShadowDown", new KeyTrigger(KeyInput.KEY_G));
+ inputManager.addMapping("ThicknessUp", new KeyTrigger(KeyInput.KEY_Y));
+ inputManager.addMapping("ThicknessDown", new KeyTrigger(KeyInput.KEY_H));
+ inputManager.addMapping("toggleHW", new KeyTrigger(KeyInput.KEY_RETURN));
+
+
+ inputManager.addListener(this, "toggleHW", "toggle", "ShadowUp", "ShadowDown", "ThicknessUp", "ThicknessDown", "changeFiltering");
+
+ }
+
+
+ public void onAction(String name, boolean keyPressed, float tpf) {
+ if (name.equals("toggle") && keyPressed) {
+ renderModeIndex += 1;
+ renderModeIndex %= 3;
+
+ switch (renderModeIndex) {
+ case 0:
+ viewPort.addProcessor(plsr);
+ shadowTypeText.setText(TYPE_TEXT + "Processor");
+ break;
+ case 1:
+ viewPort.removeProcessor(plsr);
+ plsf.setEnabled(true);
+ shadowTypeText.setText(TYPE_TEXT + "Filter");
+ break;
+ case 2:
+ plsf.setEnabled(false);
+ shadowTypeText.setText(TYPE_TEXT + "None");
+ break;
+ }
+
+
+
+ } else if (name.equals("toggleHW") && keyPressed) {
+ hardwareShadows = !hardwareShadows;
+ plsr.setShadowCompareMode(hardwareShadows ? CompareMode.Hardware : CompareMode.Software);
+ plsf.setShadowCompareMode(hardwareShadows ? CompareMode.Hardware : CompareMode.Software);
+
+ shadowCompareText.setText(COMPARE_TEXT + (hardwareShadows ? "Hardware" : "Software"));
+ }
+
+
+ if (name.equals("changeFiltering") && keyPressed) {
+ filteringIndex = plsr.getEdgeFilteringMode().ordinal();
+ filteringIndex = (filteringIndex + 1) % EdgeFilteringMode.values().length;
+ EdgeFilteringMode m = EdgeFilteringMode.values()[filteringIndex];
+ plsr.setEdgeFilteringMode(m);
+ plsf.setEdgeFilteringMode(m);
+ shadowFilterText.setText(FILTERING_TEXT + m.toString());
+ }
+
+ if (name.equals("ShadowUp") && keyPressed) {
+ plsr.setShadowIntensity(plsr.getShadowIntensity() + 0.1f);
+ plsf.setShadowIntensity(plsf.getShadowIntensity() + 0.1f);
+
+ shadowIntensityText.setText(INTENSITY_TEXT + plsr.getShadowIntensity());
+ }
+ if (name.equals("ShadowDown") && keyPressed) {
+ plsr.setShadowIntensity(plsr.getShadowIntensity() - 0.1f);
+ plsf.setShadowIntensity(plsf.getShadowIntensity() - 0.1f);
+ shadowIntensityText.setText(INTENSITY_TEXT + plsr.getShadowIntensity());
+ }
+ if (name.equals("ThicknessUp") && keyPressed) {
+ plsr.setEdgesThickness(plsr.getEdgesThickness() + 1);
+ plsf.setEdgesThickness(plsf.getEdgesThickness() + 1);
+ System.out.println("Shadow thickness : " + plsr.getEdgesThickness());
+ }
+ if (name.equals("ThicknessDown") && keyPressed) {
+ plsr.setEdgesThickness(plsr.getEdgesThickness() - 1);
+ plsf.setEdgesThickness(plsf.getEdgesThickness() - 1);
+ System.out.println("Shadow thickness : " + plsr.getEdgesThickness());
+ }
+
+ }
+
+ private BitmapText createText(BitmapFont guiFont) {
+ BitmapText t = new BitmapText(guiFont, false);
+ t.setSize(guiFont.getCharSet().getRenderedSize() * 0.75f);
+ return t;
+ }
+}
diff --git a/JmeTests/src/jme3test/light/TestColorApp.java b/JmeTests/src/jme3test/light/TestColorApp.java
new file mode 100644
index 0000000..03bef02
--- /dev/null
+++ b/JmeTests/src/jme3test/light/TestColorApp.java
@@ -0,0 +1,90 @@
+package jme3test.light;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.input.ChaseCamera;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.AnalogListener;
+import com.jme3.light.DirectionalLight;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.post.FilterPostProcessor;
+import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Box;
+import com.jme3.shadow.DirectionalLightShadowFilter;
+import com.jme3.shadow.DirectionalLightShadowRenderer;
+
+public class TestColorApp extends SimpleApplication {
+ public static void main(String[] args) {
+ TestColorApp app = new TestColorApp();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ // Lights
+ DirectionalLight sun = new DirectionalLight();
+ Vector3f sunPosition = new Vector3f(1, -1, 1);
+ sun.setDirection(sunPosition);
+ sun.setColor(new ColorRGBA(1f,1f,1f,1f));
+ rootNode.addLight(sun);
+
+ //DirectionalLightShadowFilter sun_renderer = new DirectionalLightShadowFilter(assetManager, 2048, 4);
+ DirectionalLightShadowRenderer sun_renderer = new DirectionalLightShadowRenderer(assetManager, 2048, 1);
+ sun_renderer.setLight(sun);
+ viewPort.addProcessor(sun_renderer);
+
+// FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
+// fpp.addFilter(sun_renderer);
+// viewPort.addProcessor(fpp);
+
+ rootNode.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
+
+ // Camera
+ viewPort.setBackgroundColor(new ColorRGBA(.6f, .6f, .6f, 1f));
+ ChaseCamera chaseCam = new ChaseCamera(cam, inputManager);
+
+
+ // Objects
+ // Ground Object
+ final Geometry groundBoxWhite = new Geometry("Box", new Box(7.5f, 7.5f, .25f));
+ float[] f = {-FastMath.PI / 2, 3 * FastMath.PI / 2, 0f};
+ groundBoxWhite.setLocalRotation(new Quaternion(f));
+ groundBoxWhite.move(7.5f, -.75f, 7.5f);
+ final Material groundMaterial = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+ groundMaterial.setColor("Diffuse", new ColorRGBA(.9f, .9f, .9f, .9f));
+ groundBoxWhite.setMaterial(groundMaterial);
+ groundBoxWhite.addControl(chaseCam);
+ rootNode.attachChild(groundBoxWhite);
+
+ // Planter
+ Geometry planterBox = new Geometry("Box", new Box(.5f, .5f, .5f));
+ final Material planterMaterial = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+ planterMaterial.setTexture("DiffuseMap", assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg"));
+ planterBox.setMaterial(groundMaterial);
+ planterBox.setLocalTranslation(10, 0, 9);
+ rootNode.attachChild(planterBox);
+
+ // Action!
+ inputManager.addMapping("on", new KeyTrigger(KeyInput.KEY_Z));
+ inputManager.addMapping("off", new KeyTrigger(KeyInput.KEY_X));
+
+ inputManager.addListener(new AnalogListener() {
+ @Override
+ public void onAnalog(String s, float v, float v1) {
+ if (s.equals("on")) {
+ groundBoxWhite.setMaterial(planterMaterial);
+ }
+ if (s.equals("off")) {
+ groundBoxWhite.setMaterial(groundMaterial);
+ }
+ }
+ }, "on", "off");
+
+ inputEnabled = true;
+ }
+}
\ No newline at end of file
diff --git a/JmeTests/src/jme3test/light/TestConeVSFrustum.java b/JmeTests/src/jme3test/light/TestConeVSFrustum.java
new file mode 100644
index 0000000..d96edf7
--- /dev/null
+++ b/JmeTests/src/jme3test/light/TestConeVSFrustum.java
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.light;
+
+import com.jme3.app.ChaseCameraAppState;
+import com.jme3.app.SimpleApplication;
+import com.jme3.input.KeyInput;
+import com.jme3.input.MouseInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.AnalogListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.input.controls.MouseAxisTrigger;
+import com.jme3.input.controls.MouseButtonTrigger;
+import com.jme3.light.AmbientLight;
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.SpotLight;
+import com.jme3.material.Material;
+import com.jme3.math.*;
+import com.jme3.renderer.Camera;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.LightNode;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.debug.Grid;
+import com.jme3.scene.debug.WireFrustum;
+import com.jme3.scene.shape.Box;
+import com.jme3.scene.shape.Cylinder;
+import com.jme3.shadow.ShadowUtil;
+import com.jme3.texture.Texture;
+import com.jme3.util.TempVars;
+
+public class TestConeVSFrustum extends SimpleApplication {
+
+ public static void main(String[] args) {
+ TestConeVSFrustum app = new TestConeVSFrustum();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ viewPort.setBackgroundColor(ColorRGBA.DarkGray);
+ frustumCam = cam.clone();
+ frustumCam.setFrustumFar(25);
+ Vector3f[] points = new Vector3f[8];
+ for (int i = 0; i < 8; i++) {
+ points[i] = new Vector3f();
+ }
+ ShadowUtil.updateFrustumPoints2(frustumCam, points);
+ WireFrustum frustumShape = new WireFrustum(points);
+ Geometry frustum = new Geometry("frustum", frustumShape);
+ frustum.setMaterial(new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"));
+ rootNode.attachChild(frustum);
+
+ rootNode.addLight(new DirectionalLight());
+ AmbientLight al = new AmbientLight();
+ al.setColor(ColorRGBA.White.mult(0.2f));
+ rootNode.addLight(al);
+
+ Grid grid = new Grid(50, 50, 5);
+ Geometry gridGeom = new Geometry("grid", grid);
+ gridGeom.setMaterial(new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"));
+ gridGeom.getMaterial().setColor("Color", ColorRGBA.Gray);
+ rootNode.attachChild(gridGeom);
+ gridGeom.setLocalTranslation(-125, -25, -125);
+
+// flyCam.setMoveSpeed(30);
+// flyCam.setDragToRotate(true);
+// cam.setLocation(new Vector3f(56.182674f, 19.037334f, 7.093905f));
+// cam.setRotation(new Quaternion(0.0816657f, -0.82228005f, 0.12213967f, 0.5497892f));
+ spotLight = new SpotLight();
+ spotLight.setSpotRange(25);
+ spotLight.setSpotOuterAngle(10 * FastMath.DEG_TO_RAD);
+
+ float radius = FastMath.tan(spotLight.getSpotOuterAngle()) * spotLight.getSpotRange();
+
+ Cylinder cylinder = new Cylinder(5, 16, 0.01f, radius, spotLight.getSpotRange(), true, false);
+ geom = new Geometry("light", cylinder);
+ geom.setMaterial(new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"));
+ geom.getMaterial().setColor("Diffuse", ColorRGBA.White);
+ geom.getMaterial().setColor("Ambient", ColorRGBA.DarkGray);
+ geom.getMaterial().setBoolean("UseMaterialColors", true);
+ final LightNode ln = new LightNode("lb", spotLight);
+ ln.attachChild(geom);
+ geom.setLocalTranslation(0, -spotLight.getSpotRange() / 2f, 0);
+ geom.rotate(-FastMath.HALF_PI, 0, 0);
+ rootNode.attachChild(ln);
+// ln.rotate(FastMath.QUARTER_PI, 0, 0);
+ // ln.setLocalTranslation(0, 0, -16);
+
+ inputManager.addMapping("click", new MouseButtonTrigger(MouseInput.BUTTON_RIGHT));
+ inputManager.addMapping("shift", new KeyTrigger(KeyInput.KEY_LSHIFT), new KeyTrigger(KeyInput.KEY_RSHIFT));
+ inputManager.addMapping("middleClick", new MouseButtonTrigger(MouseInput.BUTTON_MIDDLE));
+ inputManager.addMapping("up", new MouseAxisTrigger(MouseInput.AXIS_Y, false));
+ inputManager.addMapping("down", new MouseAxisTrigger(MouseInput.AXIS_Y, true));
+ inputManager.addMapping("left", new MouseAxisTrigger(MouseInput.AXIS_X, true));
+ inputManager.addMapping("right", new MouseAxisTrigger(MouseInput.AXIS_X, false));
+
+
+ final Node camTarget = new Node("CamTarget");
+ rootNode.attachChild(camTarget);
+
+ ChaseCameraAppState chaser = new ChaseCameraAppState();
+ chaser.setTarget(camTarget);
+ chaser.setMaxDistance(150);
+ chaser.setDefaultDistance(70);
+ chaser.setDefaultHorizontalRotation(FastMath.HALF_PI);
+ chaser.setMinVerticalRotation(-FastMath.PI);
+ chaser.setMaxVerticalRotation(FastMath.PI * 2);
+ chaser.setToggleRotationTrigger(new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
+ stateManager.attach(chaser);
+ flyCam.setEnabled(false);
+
+ inputManager.addListener(new AnalogListener() {
+ public void onAnalog(String name, float value, float tpf) {
+ Spatial s = null;
+ float mult = 1;
+ if (moving) {
+ s = ln;
+ }
+ if (panning) {
+ s = camTarget;
+ mult = -1;
+ }
+ if ((moving || panning) && s!=null) {
+ if (shift) {
+ if (name.equals("left")) {
+ tmp.set(cam.getDirection());
+ s.rotate(tmpQuat.fromAngleAxis(value, tmp));
+ }
+ if (name.equals("right")) {
+ tmp.set(cam.getDirection());
+ s.rotate(tmpQuat.fromAngleAxis(-value, tmp));
+ }
+ } else {
+ value *= MOVE_SPEED * mult;
+ if (name.equals("up")) {
+ tmp.set(cam.getUp()).multLocal(value);
+ s.move(tmp);
+ }
+ if (name.equals("down")) {
+ tmp.set(cam.getUp()).multLocal(-value);
+ s.move(tmp);
+ }
+ if (name.equals("left")) {
+ tmp.set(cam.getLeft()).multLocal(value);
+ s.move(tmp);
+ }
+ if (name.equals("right")) {
+ tmp.set(cam.getLeft()).multLocal(-value);
+ s.move(tmp);
+ }
+ }
+ }
+ }
+ }, "up", "down", "left", "right");
+
+ inputManager.addListener(new ActionListener() {
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if (name.equals("click")) {
+ if (isPressed) {
+ moving = true;
+ } else {
+ moving = false;
+ }
+ }
+ if (name.equals("middleClick")) {
+ if (isPressed) {
+ panning = true;
+ } else {
+ panning = false;
+ }
+ }
+ if (name.equals("shift")) {
+ if (isPressed) {
+ shift = true;
+ } else {
+ shift = false;
+ }
+ }
+ }
+ }, "click", "middleClick", "shift");
+ /**
+ * An unshaded textured cube. // * Uses texture from jme3-test-data
+ * library!
+ */
+ Box boxMesh = new Box(1f, 1f, 1f);
+ boxGeo = new Geometry("A Textured Box", boxMesh);
+ Material boxMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ Texture monkeyTex = assetManager.loadTexture("Interface/Logo/Monkey.jpg");
+ boxMat.setTexture("ColorMap", monkeyTex);
+ boxGeo.setMaterial(boxMat);
+// rootNode.attachChild(boxGeo);
+//
+//boxGeo2 = boxGeo.clone();
+//rootNode.attachChild(boxGeo2);
+ System.err.println("light " + spotLight.getPosition());
+
+ }
+ Geometry boxGeo, boxGeo2;
+ private final static float MOVE_SPEED = 60;
+ Vector3f tmp = new Vector3f();
+ Quaternion tmpQuat = new Quaternion();
+ boolean moving, shift;
+ boolean panning;
+ Geometry geom;
+ SpotLight spotLight;
+ Camera frustumCam;
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ TempVars vars = TempVars.get();
+ boolean intersect = spotLight.intersectsFrustum(frustumCam, vars);
+
+
+ if (intersect) {
+ geom.getMaterial().setColor("Diffuse", ColorRGBA.Green);
+ } else {
+ geom.getMaterial().setColor("Diffuse", ColorRGBA.White);
+ }
+ Vector3f farPoint = vars.vect1.set(spotLight.getPosition()).addLocal(vars.vect2.set(spotLight.getDirection()).multLocal(spotLight.getSpotRange()));
+
+ //computing the radius of the base disc
+ float farRadius = (spotLight.getSpotRange() / FastMath.cos(spotLight.getSpotOuterAngle())) * FastMath.sin(spotLight.getSpotOuterAngle());
+ //computing the projection direction : perpendicular to the light direction and coplanar with the direction vector and the normal vector
+ Vector3f perpDirection = vars.vect2.set(spotLight.getDirection()).crossLocal(frustumCam.getWorldPlane(3).getNormal()).normalizeLocal().crossLocal(spotLight.getDirection());
+ //projecting the far point on the base disc perimeter
+ Vector3f projectedPoint = vars.vect3.set(farPoint).addLocal(perpDirection.multLocal(farRadius));
+
+
+ vars.release();
+// boxGeo.setLocalTranslation(spotLight.getPosition());
+ // boxGeo.setLocalTranslation(projectedPoint);
+ }
+}
diff --git a/JmeTests/src/jme3test/light/TestDirectionalLightShadow.java b/JmeTests/src/jme3test/light/TestDirectionalLightShadow.java
new file mode 100644
index 0000000..79aacc6
--- /dev/null
+++ b/JmeTests/src/jme3test/light/TestDirectionalLightShadow.java
@@ -0,0 +1,383 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.light;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.font.BitmapText;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.AnalogListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.light.AmbientLight;
+import com.jme3.light.DirectionalLight;
+import com.jme3.material.Material;
+import com.jme3.material.RenderState;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector2f;
+import com.jme3.math.Vector3f;
+import com.jme3.post.FilterPostProcessor;
+import com.jme3.post.ssao.SSAOFilter;
+import com.jme3.renderer.queue.RenderQueue.ShadowMode;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.shape.Box;
+import com.jme3.scene.shape.Sphere;
+import com.jme3.shadow.DirectionalLightShadowFilter;
+import com.jme3.shadow.DirectionalLightShadowRenderer;
+import com.jme3.shadow.EdgeFilteringMode;
+import com.jme3.texture.Texture;
+import com.jme3.texture.Texture.WrapMode;
+import com.jme3.util.SkyFactory;
+import com.jme3.util.SkyFactory.EnvMapType;
+import com.jme3.util.TangentBinormalGenerator;
+
+public class TestDirectionalLightShadow extends SimpleApplication implements ActionListener, AnalogListener {
+
+ public static final int SHADOWMAP_SIZE = 1024;
+ private Spatial[] obj;
+ private Material[] mat;
+ private DirectionalLightShadowRenderer dlsr;
+ private DirectionalLightShadowFilter dlsf;
+ private Geometry ground;
+ private Material matGroundU;
+ private Material matGroundL;
+ private AmbientLight al;
+
+ public static void main(String[] args) {
+ TestDirectionalLightShadow app = new TestDirectionalLightShadow();
+ app.start();
+ }
+ private float frustumSize = 100;
+
+ public void onAnalog(String name, float value, float tpf) {
+ if (cam.isParallelProjection()) {
+ // Instead of moving closer/farther to object, we zoom in/out.
+ if (name.equals("Size-")) {
+ frustumSize += 5f * tpf;
+ } else {
+ frustumSize -= 5f * tpf;
+ }
+
+ float aspect = (float) cam.getWidth() / cam.getHeight();
+ cam.setFrustum(-1000, 1000, -aspect * frustumSize, aspect * frustumSize, frustumSize, -frustumSize);
+ }
+ }
+
+ public void loadScene() {
+ obj = new Spatial[2];
+ // Setup first view
+
+
+ mat = new Material[2];
+ mat[0] = assetManager.loadMaterial("Common/Materials/RedColor.j3m");
+ mat[1] = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m");
+ mat[1].setBoolean("UseMaterialColors", true);
+ mat[1].setColor("Ambient", ColorRGBA.White);
+ mat[1].setColor("Diffuse", ColorRGBA.White.clone());
+
+
+ obj[0] = new Geometry("sphere", new Sphere(30, 30, 2));
+ obj[0].setShadowMode(ShadowMode.CastAndReceive);
+ obj[1] = new Geometry("cube", new Box(1.0f, 1.0f, 1.0f));
+ obj[1].setShadowMode(ShadowMode.CastAndReceive);
+ TangentBinormalGenerator.generate(obj[1]);
+ TangentBinormalGenerator.generate(obj[0]);
+
+ Spatial t = obj[0].clone(false);
+ t.setLocalScale(10f);
+ t.setMaterial(mat[1]);
+ rootNode.attachChild(t);
+ t.setLocalTranslation(0, 25, 0);
+
+ for (int i = 0; i < 60; i++) {
+ t = obj[FastMath.nextRandomInt(0, obj.length - 1)].clone(false);
+ t.setLocalScale(FastMath.nextRandomFloat() * 10f);
+ t.setMaterial(mat[FastMath.nextRandomInt(0, mat.length - 1)]);
+ rootNode.attachChild(t);
+ t.setLocalTranslation(FastMath.nextRandomFloat() * 200f, FastMath.nextRandomFloat() * 30f + 20, 30f * (i + 2f));
+ }
+
+ Box b = new Box(1000, 2, 1000);
+ b.scaleTextureCoordinates(new Vector2f(10, 10));
+ ground = new Geometry("soil", b);
+ ground.setLocalTranslation(0, 10, 550);
+ matGroundU = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ matGroundU.setColor("Color", ColorRGBA.Green);
+
+
+ matGroundL = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+ Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg");
+ grass.setWrap(WrapMode.Repeat);
+ matGroundL.setTexture("DiffuseMap", grass);
+
+ ground.setMaterial(matGroundL);
+
+ ground.setShadowMode(ShadowMode.CastAndReceive);
+ rootNode.attachChild(ground);
+
+ l = new DirectionalLight();
+ //l.setDirection(new Vector3f(0.5973172f, -0.16583486f, 0.7846725f).normalizeLocal());
+ l.setDirection(new Vector3f(-1, -1, -1));
+ rootNode.addLight(l);
+
+
+ al = new AmbientLight();
+ al.setColor(ColorRGBA.White.mult(0.02f));
+ rootNode.addLight(al);
+
+ Spatial sky = SkyFactory.createSky(assetManager,
+ "Scenes/Beach/FullskiesSunset0068.dds", EnvMapType.CubeMap);
+ sky.setLocalScale(350);
+
+ rootNode.attachChild(sky);
+ }
+ DirectionalLight l;
+
+ @Override
+ public void simpleInitApp() {
+ // put the camera in a bad position
+// cam.setLocation(new Vector3f(65.25412f, 44.38738f, 9.087874f));
+// cam.setRotation(new Quaternion(0.078139365f, 0.050241485f, -0.003942559f, 0.9956679f));
+
+ cam.setLocation(new Vector3f(3.3720117f, 42.838284f, -83.43792f));
+ cam.setRotation(new Quaternion(0.13833192f, -0.08969371f, 0.012581267f, 0.9862358f));
+
+ flyCam.setMoveSpeed(100);
+
+ loadScene();
+
+ dlsr = new DirectionalLightShadowRenderer(assetManager, SHADOWMAP_SIZE, 3);
+ dlsr.setLight(l);
+ dlsr.setLambda(0.55f);
+ dlsr.setShadowIntensity(0.8f);
+ dlsr.setEdgeFilteringMode(EdgeFilteringMode.Nearest);
+ dlsr.displayDebug();
+ viewPort.addProcessor(dlsr);
+
+ dlsf = new DirectionalLightShadowFilter(assetManager, SHADOWMAP_SIZE, 3);
+ dlsf.setLight(l);
+ dlsf.setLambda(0.55f);
+ dlsf.setShadowIntensity(0.8f);
+ dlsf.setEdgeFilteringMode(EdgeFilteringMode.Nearest);
+ dlsf.setEnabled(false);
+
+ FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
+ fpp.addFilter(dlsf);
+
+ viewPort.addProcessor(fpp);
+
+ initInputs();
+ }
+
+ private void initInputs() {
+
+ inputManager.addMapping("ThicknessUp", new KeyTrigger(KeyInput.KEY_Y));
+ inputManager.addMapping("ThicknessDown", new KeyTrigger(KeyInput.KEY_H));
+ inputManager.addMapping("lambdaUp", new KeyTrigger(KeyInput.KEY_U));
+ inputManager.addMapping("lambdaDown", new KeyTrigger(KeyInput.KEY_J));
+ inputManager.addMapping("switchGroundMat", new KeyTrigger(KeyInput.KEY_M));
+ inputManager.addMapping("debug", new KeyTrigger(KeyInput.KEY_X));
+ inputManager.addMapping("stabilize", new KeyTrigger(KeyInput.KEY_B));
+ inputManager.addMapping("distance", new KeyTrigger(KeyInput.KEY_N));
+
+
+ inputManager.addMapping("up", new KeyTrigger(KeyInput.KEY_NUMPAD8));
+ inputManager.addMapping("down", new KeyTrigger(KeyInput.KEY_NUMPAD2));
+ inputManager.addMapping("right", new KeyTrigger(KeyInput.KEY_NUMPAD6));
+ inputManager.addMapping("left", new KeyTrigger(KeyInput.KEY_NUMPAD4));
+ inputManager.addMapping("fwd", new KeyTrigger(KeyInput.KEY_PGUP));
+ inputManager.addMapping("back", new KeyTrigger(KeyInput.KEY_PGDN));
+ inputManager.addMapping("pp", new KeyTrigger(KeyInput.KEY_P));
+ inputManager.addMapping("backShadows", new KeyTrigger(KeyInput.KEY_K));
+
+
+ inputManager.addListener(this, "lambdaUp", "lambdaDown", "ThicknessUp", "ThicknessDown",
+ "switchGroundMat", "debug", "up", "down", "right", "left", "fwd", "back", "pp", "stabilize", "distance", "ShadowUp", "ShadowDown", "backShadows");
+
+ ShadowTestUIManager uiMan = new ShadowTestUIManager(assetManager, dlsr, dlsf, guiNode, inputManager, viewPort);
+
+ inputManager.addListener(this, "Size+", "Size-");
+ inputManager.addMapping("Size+", new KeyTrigger(KeyInput.KEY_W));
+ inputManager.addMapping("Size-", new KeyTrigger(KeyInput.KEY_S));
+
+ shadowStabilizationText = new BitmapText(guiFont, false);
+ shadowStabilizationText.setSize(guiFont.getCharSet().getRenderedSize() * 0.75f);
+ shadowStabilizationText.setText("(b:on/off) Shadow stabilization : " + dlsr.isEnabledStabilization());
+ shadowStabilizationText.setLocalTranslation(10, viewPort.getCamera().getHeight() - 100, 0);
+ guiNode.attachChild(shadowStabilizationText);
+
+
+ shadowZfarText = new BitmapText(guiFont, false);
+ shadowZfarText.setSize(guiFont.getCharSet().getRenderedSize() * 0.75f);
+ shadowZfarText.setText("(n:on/off) Shadow extend to 500 and fade to 50 : " + (dlsr.getShadowZExtend() > 0));
+ shadowZfarText.setLocalTranslation(10, viewPort.getCamera().getHeight() - 120, 0);
+ guiNode.attachChild(shadowZfarText);
+ }
+ private BitmapText shadowStabilizationText;
+ private BitmapText shadowZfarText;
+
+ public void onAction(String name, boolean keyPressed, float tpf) {
+
+
+ if (name.equals("pp") && keyPressed) {
+ if (cam.isParallelProjection()) {
+ cam.setFrustumPerspective(45, (float) cam.getWidth() / cam.getHeight(), 1, 1000);
+ } else {
+ cam.setParallelProjection(true);
+ float aspect = (float) cam.getWidth() / cam.getHeight();
+ cam.setFrustum(-1000, 1000, -aspect * frustumSize, aspect * frustumSize, frustumSize, -frustumSize);
+
+ }
+ }
+
+ if (name.equals("lambdaUp") && keyPressed) {
+ dlsr.setLambda(dlsr.getLambda() + 0.01f);
+ dlsf.setLambda(dlsr.getLambda() + 0.01f);
+ System.out.println("Lambda : " + dlsr.getLambda());
+ } else if (name.equals("lambdaDown") && keyPressed) {
+ dlsr.setLambda(dlsr.getLambda() - 0.01f);
+ dlsf.setLambda(dlsr.getLambda() - 0.01f);
+ System.out.println("Lambda : " + dlsr.getLambda());
+ }
+ if ((name.equals("ShadowUp") || name.equals("ShadowDown")) && keyPressed) {
+ al.setColor(ColorRGBA.White.mult((1 - dlsr.getShadowIntensity()) * 0.2f));
+ }
+
+ if (name.equals("debug") && keyPressed) {
+ dlsr.displayFrustum();
+ }
+
+ if (name.equals("backShadows") && keyPressed) {
+ dlsr.setRenderBackFacesShadows(!dlsr.isRenderBackFacesShadows());
+ dlsf.setRenderBackFacesShadows(!dlsf.isRenderBackFacesShadows());
+ }
+
+ if (name.equals("stabilize") && keyPressed) {
+ dlsr.setEnabledStabilization(!dlsr.isEnabledStabilization());
+ dlsf.setEnabledStabilization(!dlsf.isEnabledStabilization());
+ shadowStabilizationText.setText("(b:on/off) Shadow stabilization : " + dlsr.isEnabledStabilization());
+ }
+ if (name.equals("distance") && keyPressed) {
+ if (dlsr.getShadowZExtend() > 0) {
+ dlsr.setShadowZExtend(0);
+ dlsr.setShadowZFadeLength(0);
+ dlsf.setShadowZExtend(0);
+ dlsf.setShadowZFadeLength(0);
+
+ } else {
+ dlsr.setShadowZExtend(500);
+ dlsr.setShadowZFadeLength(50);
+ dlsf.setShadowZExtend(500);
+ dlsf.setShadowZFadeLength(50);
+ }
+ shadowZfarText.setText("(n:on/off) Shadow extend to 500 and fade to 50 : " + (dlsr.getShadowZExtend() > 0));
+
+ }
+
+ if (name.equals("switchGroundMat") && keyPressed) {
+ if (ground.getMaterial() == matGroundL) {
+ ground.setMaterial(matGroundU);
+ } else {
+ ground.setMaterial(matGroundL);
+ }
+ }
+
+ if (name.equals("up")) {
+ up = keyPressed;
+ }
+ if (name.equals("down")) {
+ down = keyPressed;
+ }
+ if (name.equals("right")) {
+ right = keyPressed;
+ }
+ if (name.equals("left")) {
+ left = keyPressed;
+ }
+ if (name.equals("fwd")) {
+ fwd = keyPressed;
+ }
+ if (name.equals("back")) {
+ back = keyPressed;
+ }
+
+ }
+ boolean up = false;
+ boolean down = false;
+ boolean left = false;
+ boolean right = false;
+ boolean fwd = false;
+ boolean back = false;
+ float time = 0;
+ float s = 1f;
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ if (up) {
+ Vector3f v = l.getDirection();
+ v.y += tpf / s;
+ setDir(v);
+ }
+ if (down) {
+ Vector3f v = l.getDirection();
+ v.y -= tpf / s;
+ setDir(v);
+ }
+ if (right) {
+ Vector3f v = l.getDirection();
+ v.x += tpf / s;
+ setDir(v);
+ }
+ if (left) {
+ Vector3f v = l.getDirection();
+ v.x -= tpf / s;
+ setDir(v);
+ }
+ if (fwd) {
+ Vector3f v = l.getDirection();
+ v.z += tpf / s;
+ setDir(v);
+ }
+ if (back) {
+ Vector3f v = l.getDirection();
+ v.z -= tpf / s;
+ setDir(v);
+ }
+
+ }
+
+ private void setDir(Vector3f v) {
+ l.setDirection(v);
+ }
+}
diff --git a/JmeTests/src/jme3test/light/TestEnvironmentMapping.java b/JmeTests/src/jme3test/light/TestEnvironmentMapping.java
new file mode 100644
index 0000000..4785b33
--- /dev/null
+++ b/JmeTests/src/jme3test/light/TestEnvironmentMapping.java
@@ -0,0 +1,67 @@
+package jme3test.light;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.asset.TextureKey;
+import com.jme3.input.ChaseCamera;
+import com.jme3.light.DirectionalLight;
+import com.jme3.material.Material;
+import com.jme3.math.Vector3f;
+import com.jme3.post.FilterPostProcessor;
+import com.jme3.post.filters.BloomFilter;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import com.jme3.texture.Texture;
+import com.jme3.util.SkyFactory;
+
+/**
+ * test
+ * @author nehon
+ */
+public class TestEnvironmentMapping extends SimpleApplication {
+
+ public static void main(String[] args) {
+ TestEnvironmentMapping app = new TestEnvironmentMapping();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ final Node buggy = (Node) assetManager.loadModel("Models/Buggy/Buggy.j3o");
+
+ TextureKey key = new TextureKey("Textures/Sky/Bright/BrightSky.dds", true);
+ key.setGenerateMips(true);
+ key.setTextureTypeHint(Texture.Type.CubeMap);
+ final Texture tex = assetManager.loadTexture(key);
+
+ for (Spatial geom : buggy.getChildren()) {
+ if (geom instanceof Geometry) {
+ Material m = ((Geometry) geom).getMaterial();
+ m.setTexture("EnvMap", tex);
+ m.setVector3("FresnelParams", new Vector3f(0.05f, 0.18f, 0.11f));
+ }
+ }
+
+ flyCam.setEnabled(false);
+
+ ChaseCamera chaseCam = new ChaseCamera(cam, inputManager);
+ chaseCam.setLookAtOffset(new Vector3f(0,0.5f,-1.0f));
+ buggy.addControl(chaseCam);
+ rootNode.attachChild(buggy);
+ rootNode.attachChild(SkyFactory.createSky(assetManager, tex,
+ SkyFactory.EnvMapType.CubeMap));
+
+ FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
+ BloomFilter bf = new BloomFilter(BloomFilter.GlowMode.Objects);
+ bf.setBloomIntensity(2.3f);
+ bf.setExposurePower(0.6f);
+
+ fpp.addFilter(bf);
+
+ DirectionalLight l = new DirectionalLight();
+ l.setDirection(new Vector3f(0, -1, -1));
+ rootNode.addLight(l);
+
+ viewPort.addProcessor(fpp);
+ }
+}
diff --git a/JmeTests/src/jme3test/light/TestLightNode.java b/JmeTests/src/jme3test/light/TestLightNode.java
new file mode 100644
index 0000000..e2d337b
--- /dev/null
+++ b/JmeTests/src/jme3test/light/TestLightNode.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.light;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.PointLight;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.LightNode;
+import com.jme3.scene.Node;
+import com.jme3.scene.shape.Sphere;
+import com.jme3.scene.shape.Torus;
+
+public class TestLightNode extends SimpleApplication {
+
+ float angle;
+ Node movingNode;
+
+ public static void main(String[] args){
+ TestLightNode app = new TestLightNode();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ Torus torus = new Torus(10, 6, 1, 3);
+// Torus torus = new Torus(50, 30, 1, 3);
+ Geometry g = new Geometry("Torus Geom", torus);
+ g.rotate(-FastMath.HALF_PI, 0, 0);
+ g.center();
+// g.move(0, 1, 0);
+
+ Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+ mat.setFloat("Shininess", 32f);
+ mat.setBoolean("UseMaterialColors", true);
+ mat.setColor("Ambient", ColorRGBA.Black);
+ mat.setColor("Diffuse", ColorRGBA.White);
+ mat.setColor("Specular", ColorRGBA.White);
+// mat.setBoolean("VertexLighting", true);
+// mat.setBoolean("LowQuality", true);
+ g.setMaterial(mat);
+
+ rootNode.attachChild(g);
+
+ Geometry lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f));
+ lightMdl.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m"));
+
+ movingNode=new Node("lightParentNode");
+ movingNode.attachChild(lightMdl);
+ rootNode.attachChild(movingNode);
+
+ PointLight pl = new PointLight();
+ pl.setColor(ColorRGBA.Green);
+ pl.setRadius(4f);
+ rootNode.addLight(pl);
+
+ LightNode lightNode=new LightNode("pointLight", pl);
+ movingNode.attachChild(lightNode);
+
+ DirectionalLight dl = new DirectionalLight();
+ dl.setColor(ColorRGBA.Red);
+ dl.setDirection(new Vector3f(0, 1, 0));
+ rootNode.addLight(dl);
+ }
+
+ @Override
+ public void simpleUpdate(float tpf){
+// cam.setLocation(new Vector3f(5.0347548f, 6.6481347f, 3.74853f));
+// cam.setRotation(new Quaternion(-0.19183293f, 0.80776674f, -0.37974006f, -0.40805697f));
+
+ angle += tpf;
+ angle %= FastMath.TWO_PI;
+
+ movingNode.setLocalTranslation(new Vector3f(FastMath.cos(angle) * 3f, 2, FastMath.sin(angle) * 3f));
+ }
+
+}
diff --git a/JmeTests/src/jme3test/light/TestLightRadius.java b/JmeTests/src/jme3test/light/TestLightRadius.java
new file mode 100644
index 0000000..f313309
--- /dev/null
+++ b/JmeTests/src/jme3test/light/TestLightRadius.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.light;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.PointLight;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Sphere;
+import com.jme3.scene.shape.Torus;
+
+public class TestLightRadius extends SimpleApplication {
+
+ float pos, vel=1;
+ PointLight pl;
+ Geometry lightMdl;
+
+ public static void main(String[] args){
+ TestLightRadius app = new TestLightRadius();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ Torus torus = new Torus(10, 6, 1, 3);
+// Torus torus = new Torus(50, 30, 1, 3);
+ Geometry g = new Geometry("Torus Geom", torus);
+ g.rotate(-FastMath.HALF_PI, 0, 0);
+ g.center();
+// g.move(0, 1, 0);
+
+ Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+ mat.setFloat("Shininess", 32f);
+ mat.setBoolean("UseMaterialColors", true);
+ mat.setColor("Ambient", ColorRGBA.Black);
+ mat.setColor("Diffuse", ColorRGBA.White);
+ mat.setColor("Specular", ColorRGBA.White);
+// mat.setBoolean("VertexLighting", true);
+// mat.setBoolean("LowQuality", true);
+ g.setMaterial(mat);
+
+ rootNode.attachChild(g);
+
+ lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f));
+ lightMdl.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m"));
+ rootNode.attachChild(lightMdl);
+
+ pl = new PointLight();
+ pl.setColor(ColorRGBA.Green);
+ pl.setRadius(4f);
+ rootNode.addLight(pl);
+
+ DirectionalLight dl = new DirectionalLight();
+ dl.setColor(ColorRGBA.Red);
+ dl.setDirection(new Vector3f(0, 1, 0));
+ rootNode.addLight(dl);
+ }
+
+ @Override
+ public void simpleUpdate(float tpf){
+// cam.setLocation(new Vector3f(5.0347548f, 6.6481347f, 3.74853f));
+// cam.setRotation(new Quaternion(-0.19183293f, 0.80776674f, -0.37974006f, -0.40805697f));
+
+ pos += tpf * vel * 5f;
+ if (pos > 15){
+ vel *= -1;
+ }else if (pos < -15){
+ vel *= -1;
+ }
+
+ pl.setPosition(new Vector3f(pos, 2, 0));
+ lightMdl.setLocalTranslation(pl.getPosition());
+ }
+
+}
diff --git a/JmeTests/src/jme3test/light/TestManyLights.java b/JmeTests/src/jme3test/light/TestManyLights.java
new file mode 100644
index 0000000..644344b
--- /dev/null
+++ b/JmeTests/src/jme3test/light/TestManyLights.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.light;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.scene.Node;
+
+public class TestManyLights extends SimpleApplication {
+
+ public static void main(String[] args){
+ TestManyLights app = new TestManyLights();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ flyCam.setMoveSpeed(10);
+
+ Node scene = (Node) assetManager.loadModel("Scenes/ManyLights/Main.scene");
+ rootNode.attachChild(scene);
+// guiNode.setCullHint(CullHint.Always);
+ }
+
+}
\ No newline at end of file
diff --git a/JmeTests/src/jme3test/light/TestManyLightsSingle.java b/JmeTests/src/jme3test/light/TestManyLightsSingle.java
new file mode 100644
index 0000000..005634b
--- /dev/null
+++ b/JmeTests/src/jme3test/light/TestManyLightsSingle.java
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.light;
+
+import com.jme3.app.BasicProfilerState;
+import com.jme3.app.SimpleApplication;
+import com.jme3.font.BitmapText;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.light.AmbientLight;
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.Light;
+import com.jme3.light.LightList;
+import com.jme3.light.PointLight;
+import com.jme3.light.SpotLight;
+import com.jme3.material.Material;
+import com.jme3.material.TechniqueDef;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.LightNode;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.control.AbstractControl;
+import com.jme3.scene.shape.Box;
+import com.jme3.util.MaterialDebugAppState;
+
+public class TestManyLightsSingle extends SimpleApplication {
+
+ public static void main(String[] args) {
+ TestManyLightsSingle app = new TestManyLightsSingle();
+ app.start();
+ }
+
+ /**
+ * Switch mode with space bar at run time
+ */
+ TechniqueDef.LightMode lm = TechniqueDef.LightMode.SinglePass;
+
+ @Override
+ public void simpleInitApp() {
+ renderManager.setPreferredLightMode(lm);
+ renderManager.setSinglePassLightBatchSize(6);
+
+ flyCam.setMoveSpeed(10);
+
+ Node scene = (Node) assetManager.loadModel("Scenes/ManyLights/Main.scene");
+ rootNode.attachChild(scene);
+ Node n = (Node) rootNode.getChild(0);
+ final LightList lightList = n.getWorldLightList();
+ final Geometry g = (Geometry) n.getChild("Grid-geom-1");
+
+ g.getMaterial().setColor("Ambient", new ColorRGBA(0.2f, 0.2f, 0.2f, 1f));
+
+ /* A colored lit cube. Needs light source! */
+ Box boxMesh = new Box(1f, 1f, 1f);
+ final Geometry boxGeo = new Geometry("Colored Box", boxMesh);
+ Material boxMat = g.getMaterial().clone();
+ boxMat.clearParam("DiffuseMap");
+ boxMat.setBoolean("UseMaterialColors", true);
+ boxMat.setColor("Ambient", new ColorRGBA(0.2f, 0.2f, 0.2f, 1f));
+ boxMat.setColor("Diffuse", ColorRGBA.Blue);
+ boxGeo.setMaterial(boxMat);
+
+ final Node cubeNodes = new Node();
+ n.attachChild(cubeNodes);
+ int nb = 0;
+ for (Light light : lightList) {
+ nb++;
+ PointLight p = (PointLight) light;
+ if (nb > 60) {
+ n.removeLight(light);
+ } else {
+
+ LightNode ln = new LightNode("l", light);
+ n.attachChild(ln);
+ ln.setLocalTranslation(p.getPosition());
+ int rand = FastMath.nextRandomInt(0, 3);
+ switch (rand) {
+ case 0:
+ light.setColor(ColorRGBA.Red);
+ // ln.addControl(new MoveControl(5f));
+ break;
+ case 1:
+ light.setColor(ColorRGBA.Yellow);
+ // ln.addControl(new MoveControl(5f));
+ break;
+ case 2:
+ light.setColor(ColorRGBA.Green);
+ //ln.addControl(new MoveControl(-5f));
+ break;
+ case 3:
+ light.setColor(ColorRGBA.Orange);
+ //ln.addControl(new MoveControl(-5f));
+ break;
+ }
+ }
+ Geometry b = boxGeo.clone(false);
+ cubeNodes.attachChild(b);
+ b.setLocalTranslation(p.getPosition().x, 2, p.getPosition().z);
+
+ }
+
+
+// cam.setLocation(new Vector3f(3.1893547f, 17.977385f, 30.8378f));
+// cam.setRotation(new Quaternion(0.14317635f, 0.82302624f, -0.23777823f, 0.49557027f));
+
+ cam.setLocation(new Vector3f(-1.8901939f, 29.34097f, 73.07533f));
+ cam.setRotation(new Quaternion(0.0021000702f, 0.971012f, -0.23886925f, 0.008527749f));
+
+
+ BasicProfilerState profiler = new BasicProfilerState(true);
+ profiler.setGraphScale(1000f);
+
+ // getStateManager().attach(profiler);
+// guiNode.setCullHint(CullHint.Always);
+
+
+ flyCam.setDragToRotate(true);
+ flyCam.setMoveSpeed(50);
+
+ final MaterialDebugAppState debug = new MaterialDebugAppState();
+ stateManager.attach(debug);
+
+ inputManager.addListener(new ActionListener() {
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if (name.equals("toggle") && isPressed) {
+ if (lm == TechniqueDef.LightMode.SinglePass) {
+ lm = TechniqueDef.LightMode.MultiPass;
+ helloText.setText("(Multi pass)");
+ } else {
+ lm = TechniqueDef.LightMode.SinglePass;
+ helloText.setText("(Single pass) nb lights per batch : " + renderManager.getSinglePassLightBatchSize());
+ }
+ renderManager.setPreferredLightMode(lm);
+ reloadScene(g, boxGeo, cubeNodes);
+ }
+ if (name.equals("lightsUp") && isPressed) {
+ renderManager.setSinglePassLightBatchSize(renderManager.getSinglePassLightBatchSize() + 1);
+ helloText.setText("(Single pass) nb lights per batch : " + renderManager.getSinglePassLightBatchSize());
+ }
+ if (name.equals("lightsDown") && isPressed) {
+ renderManager.setSinglePassLightBatchSize(renderManager.getSinglePassLightBatchSize() - 1);
+ helloText.setText("(Single pass) nb lights per batch : " + renderManager.getSinglePassLightBatchSize());
+ }
+ if (name.equals("toggleOnOff") && isPressed) {
+ for (final Light light : lightList) {
+ if (light instanceof AmbientLight) {
+ continue;
+ }
+
+ light.setEnabled(!light.isEnabled());
+ }
+ }
+ }
+ }, "toggle", "lightsUp", "lightsDown", "toggleOnOff");
+
+ inputManager.addMapping("toggle", new KeyTrigger(KeyInput.KEY_SPACE));
+ inputManager.addMapping("lightsUp", new KeyTrigger(KeyInput.KEY_UP));
+ inputManager.addMapping("lightsDown", new KeyTrigger(KeyInput.KEY_DOWN));
+ inputManager.addMapping("toggleOnOff", new KeyTrigger(KeyInput.KEY_L));
+
+
+ SpotLight spot = new SpotLight();
+ spot.setDirection(new Vector3f(-1f, -1f, -1f).normalizeLocal());
+ spot.setColor(ColorRGBA.Blue.mult(5));
+ spot.setSpotOuterAngle(FastMath.DEG_TO_RAD * 20);
+ spot.setSpotInnerAngle(FastMath.DEG_TO_RAD * 5);
+ spot.setPosition(new Vector3f(10, 10, 20));
+ rootNode.addLight(spot);
+
+ DirectionalLight dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(-1, -1, 1));
+ rootNode.addLight(dl);
+
+ AmbientLight al = new AmbientLight();
+ al.setColor(new ColorRGBA(0.2f, 0.2f, 0.2f, 1f));
+ rootNode.addLight(al);
+
+
+ /**
+ * Write text on the screen (HUD)
+ */
+ guiNode.detachAllChildren();
+ guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
+ helloText = new BitmapText(guiFont, false);
+ helloText.setSize(guiFont.getCharSet().getRenderedSize());
+ helloText.setText("(Single pass) nb lights per batch : " + renderManager.getSinglePassLightBatchSize());
+ helloText.setLocalTranslation(300, helloText.getLineHeight(), 0);
+ guiNode.attachChild(helloText);
+ }
+
+ protected void reloadScene(Geometry g, Geometry boxGeo, Node cubeNodes) {
+ MaterialDebugAppState debug = stateManager.getState(MaterialDebugAppState.class);
+ Material m = debug.reloadMaterial(g.getMaterial());
+ if (m != null) {
+ g.setMaterial(m);
+ }
+ m = debug.reloadMaterial(boxGeo.getMaterial());
+ if (m != null) {
+ cubeNodes.setMaterial(m);
+ }
+ }
+
+ BitmapText helloText;
+ long time;
+ long nbFrames;
+ long startTime = 0;
+
+ @Override
+ public void simpleUpdate(float tpf) {
+// if (nbFrames == 4000) {
+// startTime = System.nanoTime();
+// }
+// if (nbFrames > 4000) {
+// time = System.nanoTime();
+// float average = ((float) time - (float) startTime) / ((float) nbFrames - 4000f);
+// helloText.setText("Average = " + average);
+// }
+// nbFrames++;
+ }
+
+ class MoveControl extends AbstractControl {
+
+ float direction;
+ Vector3f origPos = new Vector3f();
+
+ public MoveControl(float direction) {
+ this.direction = direction;
+ }
+
+ @Override
+ public void setSpatial(Spatial spatial) {
+ super.setSpatial(spatial); //To change body of generated methods, choose Tools | Templates.
+ origPos.set(spatial.getLocalTranslation());
+ }
+ float time = 0;
+
+ @Override
+ protected void controlUpdate(float tpf) {
+ time += tpf;
+ spatial.setLocalTranslation(origPos.x + FastMath.cos(time) * direction, origPos.y, origPos.z + FastMath.sin(time) * direction);
+ }
+
+ @Override
+ protected void controlRender(RenderManager rm, ViewPort vp) {
+ }
+ }
+}
\ No newline at end of file
diff --git a/JmeTests/src/jme3test/light/TestPointDirectionalAndSpotLightShadows.java b/JmeTests/src/jme3test/light/TestPointDirectionalAndSpotLightShadows.java
new file mode 100644
index 0000000..473ba8d
--- /dev/null
+++ b/JmeTests/src/jme3test/light/TestPointDirectionalAndSpotLightShadows.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.light;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.PointLight;
+import com.jme3.light.SpotLight;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.post.FilterPostProcessor;
+import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.shape.Box;
+import com.jme3.scene.shape.Sphere;
+import com.jme3.shadow.DirectionalLightShadowFilter;
+import com.jme3.shadow.DirectionalLightShadowRenderer;
+import com.jme3.shadow.EdgeFilteringMode;
+import com.jme3.shadow.PointLightShadowFilter;
+import com.jme3.shadow.PointLightShadowRenderer;
+import com.jme3.shadow.SpotLightShadowFilter;
+import com.jme3.shadow.SpotLightShadowRenderer;
+
+public class TestPointDirectionalAndSpotLightShadows extends SimpleApplication {
+ public static final int SHADOWMAP_SIZE = 512;
+
+ public static void main(String[] args) {
+ TestPointDirectionalAndSpotLightShadows app = new TestPointDirectionalAndSpotLightShadows();
+ app.start();
+ }
+ Node lightNode;
+ PointLightShadowRenderer plsr;
+ PointLightShadowFilter plsf;
+ DirectionalLightShadowRenderer dlsr;
+ DirectionalLightShadowFilter dlsf;
+ SpotLightShadowRenderer slsr;
+ SpotLightShadowFilter slsf;
+ SpotLight spotLight;
+
+ boolean useFilter = false;
+
+ @Override
+ public void simpleInitApp() {
+ flyCam.setMoveSpeed(10);
+ cam.setLocation(new Vector3f(0.040581334f, 1.7745866f, 6.155161f));
+ cam.setRotation(new Quaternion(4.3868728E-5f, 0.9999293f, -0.011230096f, 0.0039059948f));
+
+
+ Node scene = (Node) assetManager.loadModel("Models/Test/CornellBox.j3o");
+ scene.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
+ rootNode.attachChild(scene);
+ rootNode.getChild("Cube").setShadowMode(RenderQueue.ShadowMode.Receive);
+ lightNode = (Node) rootNode.getChild("Lamp");
+ Geometry lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f));
+ //Geometry lightMdl = new Geometry("Light", new Box(.1f,.1f,.1f));
+ lightMdl.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m"));
+ lightMdl.setShadowMode(RenderQueue.ShadowMode.Off);
+ lightNode.attachChild(lightMdl);
+ //lightMdl.setLocalTranslation(lightNode.getLocalTranslation());
+
+
+ Geometry box = new Geometry("box", new Box(0.2f, 0.2f, 0.2f));
+ //Geometry lightMdl = new Geometry("Light", new Box(.1f,.1f,.1f));
+ box.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m"));
+ box.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
+ rootNode.attachChild(box);
+ box.setLocalTranslation(-1f, 0.5f, -2);
+
+ ((PointLight) scene.getLocalLightList().get(0)).setColor(ColorRGBA.Red);
+
+ plsr = new PointLightShadowRenderer(assetManager, SHADOWMAP_SIZE);
+ plsr.setLight((PointLight) scene.getLocalLightList().get(0));
+ plsr.setEdgeFilteringMode(EdgeFilteringMode.PCF4);
+
+
+
+ plsf = new PointLightShadowFilter(assetManager, SHADOWMAP_SIZE);
+ plsf.setLight((PointLight) scene.getLocalLightList().get(0));
+ plsf.setEdgeFilteringMode(EdgeFilteringMode.PCF4);
+ plsf.setEnabled(useFilter);
+
+ //DIRECTIONAL LIGHT
+ DirectionalLight directionalLight = new DirectionalLight();
+ rootNode.addLight(directionalLight);
+ directionalLight.setColor(ColorRGBA.Blue);
+ directionalLight.setDirection(new Vector3f(-1f, -.2f, 0f));
+ dlsr = new DirectionalLightShadowRenderer(assetManager, SHADOWMAP_SIZE*2, 4);
+ dlsr.setLight(directionalLight);
+ dlsr.setEdgeFilteringMode(EdgeFilteringMode.PCF4);
+
+ dlsf = new DirectionalLightShadowFilter(assetManager, SHADOWMAP_SIZE*2, 4);
+ dlsf.setEdgeFilteringMode(EdgeFilteringMode.PCF4);
+ dlsf.setLight(directionalLight);
+ dlsf.setEnabled(useFilter);
+
+ //SPOT LIGHT
+ spotLight = new SpotLight();
+ spotLight.setDirection(new Vector3f(1f,-1f,0f));
+ spotLight.setPosition(new Vector3f(-1f,3f,0f));
+ spotLight.setSpotOuterAngle(0.5f);
+ spotLight.setColor(ColorRGBA.Green);
+ Sphere sphere = new Sphere(8, 8, .1f);
+ Geometry sphereGeometry = new Geometry("Sphere", sphere);
+ sphereGeometry.setLocalTranslation(-1f, 3f, 0f);
+ sphereGeometry.setMaterial(assetManager.loadMaterial("Common/Materials/WhiteColor.j3m"));
+ rootNode.attachChild(sphereGeometry);
+ rootNode.addLight(spotLight);
+
+ slsr = new SpotLightShadowRenderer(assetManager, SHADOWMAP_SIZE);
+ slsr.setLight(spotLight);
+ slsr.setEdgeFilteringMode(EdgeFilteringMode.PCF4);
+
+ slsf = new SpotLightShadowFilter(assetManager, SHADOWMAP_SIZE);
+ slsf.setLight(spotLight);
+ slsf.setEdgeFilteringMode(EdgeFilteringMode.PCF4);
+ slsf.setEnabled(useFilter);
+
+
+
+ if (!useFilter)viewPort.addProcessor(slsr);
+ if (!useFilter)viewPort.addProcessor(plsr);
+ if (!useFilter)viewPort.addProcessor(dlsr);
+
+ FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
+ fpp.addFilter(plsf);
+ fpp.addFilter(dlsf);
+ fpp.addFilter(slsf);
+ viewPort.addProcessor(fpp);
+
+ ShadowTestUIManager uiMan = new ShadowTestUIManager(assetManager, plsr, plsf, guiNode, inputManager, viewPort);
+ ShadowTestUIManager uiManPls = new ShadowTestUIManager(assetManager, plsr, plsf, guiNode, inputManager, viewPort);
+ ShadowTestUIManager uiManDls = new ShadowTestUIManager(assetManager, dlsr, dlsf, guiNode, inputManager, viewPort);
+ ShadowTestUIManager uiManSls = new ShadowTestUIManager(assetManager, slsr, slsf, guiNode, inputManager, viewPort);
+
+ }
+
+ float timeElapsed = 0.0f;
+ @Override
+ public void simpleUpdate(float tpf) {
+ timeElapsed += tpf;
+ lightNode.setLocalTranslation(FastMath.cos(timeElapsed), lightNode.getLocalTranslation().y, FastMath.sin(timeElapsed));
+ spotLight.setDirection(new Vector3f(FastMath.cos(-timeElapsed*.7f), -1.0f, FastMath.sin(-timeElapsed*.7f)));
+ }
+}
\ No newline at end of file
diff --git a/JmeTests/src/jme3test/light/TestPointLightShadows.java b/JmeTests/src/jme3test/light/TestPointLightShadows.java
new file mode 100644
index 0000000..8007971
--- /dev/null
+++ b/JmeTests/src/jme3test/light/TestPointLightShadows.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.light;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.light.AmbientLight;
+import com.jme3.light.PointLight;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.post.FilterPostProcessor;
+import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.shape.Box;
+import com.jme3.scene.shape.Sphere;
+import com.jme3.shadow.EdgeFilteringMode;
+import com.jme3.shadow.PointLightShadowFilter;
+import com.jme3.shadow.PointLightShadowRenderer;
+
+public class TestPointLightShadows extends SimpleApplication implements ActionListener{
+ public static final int SHADOWMAP_SIZE = 512;
+
+ public static void main(String[] args) {
+ TestPointLightShadows app = new TestPointLightShadows();
+ app.start();
+ }
+ Node lightNode;
+ PointLightShadowRenderer plsr;
+ PointLightShadowFilter plsf;
+ AmbientLight al;
+
+ @Override
+ public void simpleInitApp () {
+ flyCam.setMoveSpeed(10);
+ cam.setLocation(new Vector3f(0.040581334f, 1.7745866f, 6.155161f));
+ cam.setRotation(new Quaternion(4.3868728E-5f, 0.9999293f, -0.011230096f, 0.0039059948f));
+
+ al = new AmbientLight(ColorRGBA.White.mult(0.02f));
+ rootNode.addLight(al);
+
+
+
+
+ Node scene = (Node) assetManager.loadModel("Models/Test/CornellBox.j3o");
+ scene.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
+ rootNode.attachChild(scene);
+ rootNode.getChild("Cube").setShadowMode(RenderQueue.ShadowMode.Receive);
+ lightNode = (Node) rootNode.getChild("Lamp");
+ Geometry lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f));
+ //Geometry lightMdl = new Geometry("Light", new Box(.1f,.1f,.1f));
+ lightMdl.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m"));
+ lightMdl.setShadowMode(RenderQueue.ShadowMode.Off);
+ lightNode.attachChild(lightMdl);
+ //lightMdl.setLocalTranslation(lightNode.getLocalTranslation());
+
+
+ Geometry box = new Geometry("box", new Box(0.2f, 0.2f, 0.2f));
+ //Geometry lightMdl = new Geometry("Light", new Box(.1f,.1f,.1f));
+ box.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m"));
+ box.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
+ rootNode.attachChild(box);
+ box.setLocalTranslation(-1f, 0.5f, -2);
+
+
+ plsr = new PointLightShadowRenderer(assetManager, SHADOWMAP_SIZE);
+ plsr.setLight((PointLight) scene.getLocalLightList().get(0));
+ plsr.setEdgeFilteringMode(EdgeFilteringMode.PCF4);
+ plsr.setShadowZExtend(15);
+ plsr.setShadowZFadeLength(5);
+ plsr.setShadowIntensity(0.9f);
+ // plsr.setFlushQueues(false);
+ //plsr.displayFrustum();
+ plsr.displayDebug();
+ viewPort.addProcessor(plsr);
+
+
+ plsf = new PointLightShadowFilter(assetManager, SHADOWMAP_SIZE);
+ plsf.setLight((PointLight) scene.getLocalLightList().get(0));
+ plsf.setShadowZExtend(15);
+ plsf.setShadowZFadeLength(5);
+ plsf.setShadowIntensity(0.8f);
+ plsf.setEdgeFilteringMode(EdgeFilteringMode.PCF4);
+ plsf.setEnabled(false);
+
+ FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
+ fpp.addFilter(plsf);
+ viewPort.addProcessor(fpp);
+ inputManager.addListener(this,"ShadowUp","ShadowDown");
+ ShadowTestUIManager uiMan = new ShadowTestUIManager(assetManager, plsr, plsf, guiNode, inputManager, viewPort);
+
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ // lightNode.move(FastMath.cos(tpf) * 0.4f, 0, FastMath.sin(tpf) * 0.4f);
+ }
+
+ @Override
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if ((name.equals("ShadowUp") || name.equals("ShadowDown")) && isPressed) {
+ al.setColor(ColorRGBA.White.mult((1 - plsr.getShadowIntensity()) * 0.2f));
+ }
+ }
+}
\ No newline at end of file
diff --git a/JmeTests/src/jme3test/light/TestShadowBug.java b/JmeTests/src/jme3test/light/TestShadowBug.java
new file mode 100644
index 0000000..acf2d6d
--- /dev/null
+++ b/JmeTests/src/jme3test/light/TestShadowBug.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2009-2015 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.light;
+
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.PointLight;
+import com.jme3.light.SpotLight;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector2f;
+import com.jme3.math.Vector3f;
+import com.jme3.renderer.queue.RenderQueue.ShadowMode;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.shape.Box;
+import com.jme3.shadow.EdgeFilteringMode;
+import com.jme3.shadow.PointLightShadowRenderer;
+import com.jme3.shadow.SpotLightShadowRenderer;
+import com.jme3.texture.Texture;
+import com.jme3.texture.Texture.WrapMode;
+
+
+public class TestShadowBug extends SimpleApplication {
+ public static void main(String[] args) {
+ TestShadowBug app = new TestShadowBug();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ flyCam.setMoveSpeed(100f);
+ rootNode.attachChild(makeFloor());
+
+ Node characters = new Node("Characters");
+ characters.setShadowMode(ShadowMode.Cast);
+ rootNode.attachChild(characters);
+
+ Spatial golem = assetManager.loadModel("Models/Oto/Oto.mesh.xml");
+ golem.scale(0.5f);
+ golem.setLocalTranslation(200.0f, -6f, 200f);
+ golem.setShadowMode(ShadowMode.CastAndReceive);
+ characters.attachChild(golem);
+
+ DirectionalLight sun = new DirectionalLight();
+ sun.setDirection(new Vector3f(-1f, -1f, 1f));
+ sun.setColor(ColorRGBA.White.mult(1.3f));
+ rootNode.addLight(sun);
+ characters.addLight(sun);
+
+ SpotLight spot = new SpotLight();
+ spot.setSpotRange(13f); // distance
+ spot.setSpotInnerAngle(15f * FastMath.DEG_TO_RAD); // inner light cone (central beam)
+ spot.setSpotOuterAngle(20f * FastMath.DEG_TO_RAD); // outer light cone (edge of the light)
+ spot.setColor(ColorRGBA.White.mult(1.3f)); // light color
+ spot.setPosition(new Vector3f(192.0f, -1f, 192f));
+ spot.setDirection(new Vector3f(1, -0.5f, 1));
+ rootNode.addLight(spot);
+
+ PointLight lamp_light = new PointLight();
+ lamp_light.setColor(ColorRGBA.Yellow);
+ lamp_light.setRadius(20f);
+ lamp_light.setPosition(new Vector3f(210.0f, 0f, 210f));
+ rootNode.addLight(lamp_light);
+
+ SpotLightShadowRenderer slsr = new SpotLightShadowRenderer(assetManager, 512);
+ slsr.setLight(spot);
+ slsr.setEdgeFilteringMode(EdgeFilteringMode.Nearest);
+ slsr.setShadowIntensity(0.6f);
+ viewPort.addProcessor(slsr);
+
+ PointLightShadowRenderer plsr = new PointLightShadowRenderer(assetManager, 512);
+ plsr.setLight(lamp_light);
+ plsr.setShadowIntensity(0.6f);
+ plsr.setEdgeFilteringMode(EdgeFilteringMode.Nearest);
+ viewPort.addProcessor(plsr);
+
+ viewPort.getCamera().setLocation(new Vector3f(192.0f, 10f, 192f));
+ float[] angles = new float[]{3.14f/2, 3.14f/2, 0};
+ viewPort.getCamera().setRotation(new Quaternion(angles));
+ }
+
+ protected Geometry makeFloor() {
+ Box box = new Box(220, .2f, 220);
+ box.scaleTextureCoordinates(new Vector2f(10, 10));
+ Geometry floor = new Geometry("the Floor", box);
+ floor.setLocalTranslation(200, -9, 200);
+ Material matGroundL = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+ Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg");
+ grass.setWrap(WrapMode.Repeat);
+ matGroundL.setTexture("DiffuseMap", grass);
+ floor.setMaterial(matGroundL);
+ floor.setShadowMode(ShadowMode.CastAndReceive);
+ return floor;
+ }
+}
\ No newline at end of file
diff --git a/JmeTests/src/jme3test/light/TestShadowsPerf.java b/JmeTests/src/jme3test/light/TestShadowsPerf.java
new file mode 100644
index 0000000..f267b1d
--- /dev/null
+++ b/JmeTests/src/jme3test/light/TestShadowsPerf.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.light;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.light.AmbientLight;
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.PointLight;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector2f;
+import com.jme3.math.Vector3f;
+import com.jme3.renderer.queue.RenderQueue.ShadowMode;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.shape.Box;
+import com.jme3.scene.shape.Sphere;
+import com.jme3.shadow.DirectionalLightShadowRenderer;
+import com.jme3.shadow.EdgeFilteringMode;
+import com.jme3.util.TangentBinormalGenerator;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class TestShadowsPerf extends SimpleApplication {
+
+ float angle;
+ PointLight pl;
+ Spatial lightMdl;
+
+ public static void main(String[] args) {
+ TestShadowsPerf app = new TestShadowsPerf();
+ app.start();
+ }
+ Geometry sphere;
+ Material mat;
+
+ @Override
+ public void simpleInitApp() {
+ Logger.getLogger("com.jme3").setLevel(Level.SEVERE);
+ flyCam.setMoveSpeed(50);
+ flyCam.setEnabled(false);
+ viewPort.setBackgroundColor(ColorRGBA.DarkGray);
+ cam.setLocation(new Vector3f(-53.952988f, 27.15874f, -32.875023f));
+ cam.setRotation(new Quaternion(0.1564309f, 0.6910534f, -0.15713608f, 0.6879555f));
+
+// cam.setLocation(new Vector3f(53.64627f, 130.56f, -11.247704f));
+// cam.setRotation(new Quaternion(-6.5737107E-4f, 0.76819664f, -0.64021313f, -7.886125E-4f));
+////
+ cam.setFrustumFar(500);
+
+ mat = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m");
+
+ Box b = new Box(800, 1, 700);
+ b.scaleTextureCoordinates(new Vector2f(50, 50));
+ Geometry ground = new Geometry("ground", b);
+ ground.setMaterial(mat);
+ rootNode.attachChild(ground);
+ ground.setShadowMode(ShadowMode.Receive);
+
+ Sphere sphMesh = new Sphere(32, 32, 1);
+ sphMesh.setTextureMode(Sphere.TextureMode.Projected);
+ sphMesh.updateGeometry(32, 32, 1, false, false);
+ TangentBinormalGenerator.generate(sphMesh);
+
+ sphere = new Geometry("Rock Ball", sphMesh);
+ sphere.setLocalTranslation(0, 5, 0);
+ sphere.setMaterial(mat);
+ sphere.setShadowMode(ShadowMode.CastAndReceive);
+ rootNode.attachChild(sphere);
+
+
+
+
+ DirectionalLight dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(0, -1, 0).normalizeLocal());
+ dl.setColor(ColorRGBA.White);
+ rootNode.addLight(dl);
+
+ AmbientLight al = new AmbientLight();
+ al.setColor(ColorRGBA.White.mult(0.7f));
+ rootNode.addLight(al);
+ //rootNode.setShadowMode(ShadowMode.CastAndReceive);
+
+ createballs();
+
+ final DirectionalLightShadowRenderer pssmRenderer = new DirectionalLightShadowRenderer(assetManager, 1024, 4);
+ viewPort.addProcessor(pssmRenderer);
+//
+// final PssmShadowFilter pssmRenderer = new PssmShadowFilter(assetManager, 1024, 4);
+// FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
+// fpp.addFilter(pssmRenderer);
+// viewPort.addProcessor(fpp);
+
+ pssmRenderer.setLight(dl);
+ pssmRenderer.setLambda(0.55f);
+ pssmRenderer.setShadowIntensity(0.55f);
+ pssmRenderer.setShadowCompareMode(com.jme3.shadow.CompareMode.Software);
+ pssmRenderer.setEdgeFilteringMode(EdgeFilteringMode.PCF4);
+ //pssmRenderer.displayDebug();
+
+ inputManager.addListener(new ActionListener() {
+
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if (name.equals("display") && isPressed) {
+ //pssmRenderer.debugFrustrums();
+ System.out.println("tetetetet");
+ }
+ if (name.equals("add") && isPressed) {
+ createballs();
+ }
+ }
+ }, "display", "add");
+ inputManager.addMapping("display", new KeyTrigger(KeyInput.KEY_SPACE));
+ inputManager.addMapping("add", new KeyTrigger(KeyInput.KEY_RETURN));
+ }
+ int val = 0;
+
+ private void createballs() {
+ System.out.println((frames / time) + ";" + val);
+
+
+ for (int i = val; i < val+1 ; i++) {
+
+ Geometry s = sphere.clone().clone(false);
+ s.setMaterial(mat);
+ s.setLocalTranslation(i - 30, 5, (((i) * 2) % 40) - 50);
+ s.setShadowMode(ShadowMode.CastAndReceive);
+ rootNode.attachChild(s);
+ }
+ if (val == 300) {
+ stop();
+ }
+ val += 1;
+ time = 0;
+ frames = 0;
+ }
+ float time;
+ float frames = 0;
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ time += tpf;
+ frames++;
+ if (time > 1) {
+ createballs();
+ }
+ }
+}
diff --git a/JmeTests/src/jme3test/light/TestSimpleLighting.java b/JmeTests/src/jme3test/light/TestSimpleLighting.java
new file mode 100644
index 0000000..840aa2f
--- /dev/null
+++ b/JmeTests/src/jme3test/light/TestSimpleLighting.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.light;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.PointLight;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Sphere;
+import com.jme3.util.MaterialDebugAppState;
+import com.jme3.util.TangentBinormalGenerator;
+
+public class TestSimpleLighting extends SimpleApplication {
+
+ float angle;
+ PointLight pl;
+ Geometry lightMdl;
+
+ public static void main(String[] args){
+ TestSimpleLighting app = new TestSimpleLighting();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ Geometry teapot = (Geometry) assetManager.loadModel("Models/Teapot/Teapot.obj");
+ TangentBinormalGenerator.generate(teapot.getMesh(), true);
+
+ teapot.setLocalScale(2f);
+ Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+// mat.selectTechnique("GBuf");
+ mat.setFloat("Shininess", 25);
+ mat.setBoolean("UseMaterialColors", true);
+ cam.setLocation(new Vector3f(0.015041917f, 0.4572918f, 5.2874837f));
+ cam.setRotation(new Quaternion(-1.8875003E-4f, 0.99882424f, 0.04832061f, 0.0039016632f));
+
+// mat.setTexture("ColorRamp", assetManager.loadTexture("Textures/ColorRamp/cloudy.png"));
+//
+// mat.setBoolean("VTangent", true);
+// mat.setBoolean("Minnaert", true);
+// mat.setBoolean("WardIso", true);
+// mat.setBoolean("VertexLighting", true);
+// mat.setBoolean("LowQuality", true);
+// mat.setBoolean("HighQuality", true);
+
+ mat.setColor("Ambient", ColorRGBA.Black);
+ mat.setColor("Diffuse", ColorRGBA.Gray);
+ mat.setColor("Specular", ColorRGBA.Gray);
+
+ teapot.setMaterial(mat);
+ rootNode.attachChild(teapot);
+
+ lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f));
+ lightMdl.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m"));
+ lightMdl.getMesh().setStatic();
+ rootNode.attachChild(lightMdl);
+
+ pl = new PointLight();
+ pl.setColor(ColorRGBA.White);
+ pl.setRadius(4f);
+ rootNode.addLight(pl);
+
+ DirectionalLight dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(-1, -1, -1).normalizeLocal());
+ dl.setColor(ColorRGBA.Green);
+ rootNode.addLight(dl);
+
+
+ MaterialDebugAppState debug = new MaterialDebugAppState();
+ debug.registerBinding("Common/ShaderLib/BlinnPhongLighting.glsllib", teapot);
+ stateManager.attach(debug);
+ setPauseOnLostFocus(false);
+ flyCam.setDragToRotate(true);
+
+ }
+
+ @Override
+ public void simpleUpdate(float tpf){
+// cam.setLocation(new Vector3f(2.0632997f, 1.9493936f, 2.6885238f));
+// cam.setRotation(new Quaternion(-0.053555284f, 0.9407851f, -0.17754152f, -0.28378546f));
+
+ angle += tpf;
+ angle %= FastMath.TWO_PI;
+
+ pl.setPosition(new Vector3f(FastMath.cos(angle) * 2f, 0.5f, FastMath.sin(angle) * 2f));
+ lightMdl.setLocalTranslation(pl.getPosition());
+ }
+
+}
diff --git a/JmeTests/src/jme3test/light/TestSpotLight.java b/JmeTests/src/jme3test/light/TestSpotLight.java
new file mode 100644
index 0000000..0cd4512
--- /dev/null
+++ b/JmeTests/src/jme3test/light/TestSpotLight.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.light;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.light.AmbientLight;
+import com.jme3.light.SpotLight;
+import com.jme3.material.Material;
+import com.jme3.math.*;
+import com.jme3.renderer.queue.RenderQueue.ShadowMode;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.shape.Box;
+import com.jme3.scene.shape.Sphere;
+import com.jme3.texture.Texture.WrapMode;
+import com.jme3.util.TangentBinormalGenerator;
+
+public class TestSpotLight extends SimpleApplication {
+
+ private Vector3f lightTarget = new Vector3f(12, 3.5f, 30);
+
+ public static void main(String[] args){
+ TestSpotLight app = new TestSpotLight();
+ app.start();
+ }
+
+ SpotLight spot;
+ Geometry lightMdl;
+ public void setupLighting(){
+ AmbientLight al=new AmbientLight();
+ al.setColor(ColorRGBA.White.mult(0.02f));
+ rootNode.addLight(al);
+
+ spot=new SpotLight();
+
+ spot.setSpotRange(1000);
+ spot.setSpotInnerAngle(5*FastMath.DEG_TO_RAD);
+ spot.setSpotOuterAngle(10*FastMath.DEG_TO_RAD);
+ spot.setPosition(new Vector3f(77.70334f, 34.013165f, 27.1017f));
+ spot.setDirection(lightTarget.subtract(spot.getPosition()));
+ spot.setColor(ColorRGBA.White.mult(2));
+ rootNode.addLight(spot);
+
+
+// PointLight pl=new PointLight();
+// pl.setPosition(new Vector3f(77.70334f, 34.013165f, 27.1017f));
+// pl.setRadius(1000);
+// pl.setColor(ColorRGBA.White.mult(2));
+// rootNode.addLight(pl);
+ lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f));
+ lightMdl.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m"));
+ lightMdl.setLocalTranslation(new Vector3f(77.70334f, 34.013165f, 27.1017f));
+ lightMdl.setLocalScale(5);
+ rootNode.attachChild(lightMdl);
+
+// DirectionalLight dl = new DirectionalLight();
+// dl.setDirection(lightTarget.subtract(new Vector3f(77.70334f, 34.013165f, 27.1017f)));
+// dl.setColor(ColorRGBA.White.mult(2));
+// rootNode.addLight(dl);
+
+
+ }
+
+ public void setupFloor(){
+ Material mat = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m");
+ mat.getTextureParam("DiffuseMap").getTextureValue().setWrap(WrapMode.Repeat);
+ mat.getTextureParam("NormalMap").getTextureValue().setWrap(WrapMode.Repeat);
+ // mat.getTextureParam("ParallaxMap").getTextureValue().setWrap(WrapMode.Repeat);
+ mat.setFloat("Shininess",3);
+ // mat.setBoolean("VertexLighting", true);
+
+
+ Box floor = new Box(50, 1f, 50);
+ TangentBinormalGenerator.generate(floor);
+ floor.scaleTextureCoordinates(new Vector2f(5, 5));
+ Geometry floorGeom = new Geometry("Floor", floor);
+ floorGeom.setMaterial(mat);
+ floorGeom.setShadowMode(ShadowMode.Receive);
+ rootNode.attachChild(floorGeom);
+ }
+
+
+
+ public void setupSignpost(){
+ Spatial signpost = assetManager.loadModel("Models/Sign Post/Sign Post.mesh.xml");
+ Material mat = assetManager.loadMaterial("Models/Sign Post/Sign Post.j3m");
+ // mat.setBoolean("VertexLighting", true);
+ signpost.setMaterial(mat);
+ signpost.rotate(0, FastMath.HALF_PI, 0);
+ signpost.setLocalTranslation(12, 3.5f, 30);
+ signpost.setLocalScale(4);
+ signpost.setShadowMode(ShadowMode.CastAndReceive);
+ TangentBinormalGenerator.generate(signpost);
+ rootNode.attachChild(signpost);
+ }
+
+ @Override
+ public void simpleInitApp() {
+ cam.setLocation(new Vector3f(27.492603f, 29.138166f, -13.232513f));
+ cam.setRotation(new Quaternion(0.25168246f, -0.10547892f, 0.02760565f, 0.96164864f));
+ flyCam.setMoveSpeed(30);
+
+ setupLighting();
+ setupFloor();
+ setupSignpost();
+
+
+ }
+
+ float angle;
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ super.simpleUpdate(tpf);
+ angle += tpf;
+ angle %= FastMath.TWO_PI;
+
+ spot.setPosition(new Vector3f(FastMath.cos(angle) * 30f, 34.013165f, FastMath.sin(angle) * 30f));
+ lightMdl.setLocalTranslation(spot.getPosition());
+ spot.setDirection(lightTarget.subtract(spot.getPosition()));
+ }
+
+
+
+}
diff --git a/JmeTests/src/jme3test/light/TestSpotLightShadows.java b/JmeTests/src/jme3test/light/TestSpotLightShadows.java
new file mode 100644
index 0000000..52a5dc8
--- /dev/null
+++ b/JmeTests/src/jme3test/light/TestSpotLightShadows.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.light;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.light.AmbientLight;
+import com.jme3.light.SpotLight;
+import com.jme3.material.Material;
+import com.jme3.math.*;
+import com.jme3.post.FilterPostProcessor;
+import com.jme3.renderer.queue.RenderQueue.ShadowMode;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.shape.Box;
+import com.jme3.scene.shape.Sphere;
+import com.jme3.shadow.EdgeFilteringMode;
+import com.jme3.shadow.SpotLightShadowFilter;
+import com.jme3.shadow.SpotLightShadowRenderer;
+import com.jme3.texture.Texture.WrapMode;
+import com.jme3.util.MaterialDebugAppState;
+import com.jme3.util.TangentBinormalGenerator;
+
+public class TestSpotLightShadows extends SimpleApplication {
+
+ private Vector3f lightTarget = new Vector3f(12, 3.5f, 30);
+
+ public static void main(String[] args) {
+ TestSpotLightShadows app = new TestSpotLightShadows();
+ app.start();
+ }
+ SpotLight spot;
+ Geometry lightMdl;
+
+ public void setupLighting() {
+ AmbientLight al = new AmbientLight();
+ al.setColor(ColorRGBA.White.mult(0.02f));
+ rootNode.addLight(al);
+
+ rootNode.setShadowMode(ShadowMode.CastAndReceive);
+
+ spot = new SpotLight();
+
+ spot.setSpotRange(1000);
+ spot.setSpotInnerAngle(5f * FastMath.DEG_TO_RAD);
+ spot.setSpotOuterAngle(10 * FastMath.DEG_TO_RAD);
+ spot.setPosition(new Vector3f(70.70334f, 34.013165f, 27.1017f));
+ spot.setDirection(lightTarget.subtract(spot.getPosition()).normalizeLocal());
+ spot.setColor(ColorRGBA.White.mult(2));
+ rootNode.addLight(spot);
+
+
+// PointLight pl=new PointLight();
+// pl.setPosition(new Vector3f(77.70334f, 34.013165f, 27.1017f));
+// pl.setRadius(1000);
+// pl.setColor(ColorRGBA.White.mult(2));
+// rootNode.addLight(pl);
+ lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f));
+ lightMdl.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m"));
+ lightMdl.setLocalTranslation(new Vector3f(77.70334f, 34.013165f, 27.1017f));
+ lightMdl.setLocalScale(5);
+ rootNode.attachChild(lightMdl);
+
+// DirectionalLight dl = new DirectionalLight();
+// dl.setDirection(lightTarget.subtract(new Vector3f(77.70334f, 34.013165f, 27.1017f)));
+// dl.setColor(ColorRGBA.White.mult(0.7f));
+// rootNode.addLight(dl);
+
+
+ final SpotLightShadowRenderer slsr = new SpotLightShadowRenderer(assetManager, 512);
+ slsr.setLight(spot);
+ slsr.setShadowIntensity(0.5f);
+ slsr.setShadowZExtend(100);
+ slsr.setShadowZFadeLength(5);
+ slsr.setEdgeFilteringMode(EdgeFilteringMode.PCFPOISSON);
+ viewPort.addProcessor(slsr);
+
+ SpotLightShadowFilter slsf = new SpotLightShadowFilter(assetManager, 512);
+ slsf.setLight(spot);
+ slsf.setShadowIntensity(0.5f);
+ slsf.setShadowZExtend(100);
+ slsf.setShadowZFadeLength(5);
+ slsf.setEdgeFilteringMode(EdgeFilteringMode.PCFPOISSON);
+ slsf.setEnabled(false);
+
+ FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
+ fpp.addFilter(slsf);
+ viewPort.addProcessor(fpp);
+
+ ShadowTestUIManager uiMan = new ShadowTestUIManager(assetManager, slsr, slsf, guiNode, inputManager, viewPort);
+
+ inputManager.addListener(new ActionListener() {
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if (name.equals("stop") && isPressed) {
+ stop = !stop;
+ // slsr.displayFrustum();
+ System.out.println("pos : " + spot.getPosition());
+ System.out.println("dir : " + spot.getDirection());
+ }
+ }
+ }, "stop");
+
+ inputManager.addMapping("stop", new KeyTrigger(KeyInput.KEY_1));
+ flyCam.setDragToRotate(true);
+ }
+
+ public void setupFloor() {
+ Material mat = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m");
+ mat.getTextureParam("DiffuseMap").getTextureValue().setWrap(WrapMode.Repeat);
+ mat.getTextureParam("NormalMap").getTextureValue().setWrap(WrapMode.Repeat);
+ mat.setBoolean("UseMaterialColors", true);
+ mat.setColor("Diffuse", ColorRGBA.White.clone());
+ mat.setColor("Ambient", ColorRGBA.White.clone());
+ // mat.setColor("Specular", ColorRGBA.White.clone());
+ // mat.getTextureParam("ParallaxMap").getTextureValue().setWrap(WrapMode.Repeat);
+ mat.setFloat("Shininess", 0);
+ // mat.setBoolean("VertexLighting", true);
+
+
+ Box floor = new Box(50, 1f, 50);
+ TangentBinormalGenerator.generate(floor);
+ floor.scaleTextureCoordinates(new Vector2f(5, 5));
+ Geometry floorGeom = new Geometry("Floor", floor);
+ floorGeom.setMaterial(mat);
+ floorGeom.setShadowMode(ShadowMode.Receive);
+ rootNode.attachChild(floorGeom);
+ }
+
+ public void setupSignpost() {
+ Spatial signpost = assetManager.loadModel("Models/Sign Post/Sign Post.mesh.xml");
+ Material mat = assetManager.loadMaterial("Models/Sign Post/Sign Post.j3m");
+ // mat.setBoolean("VertexLighting", true);
+ signpost.setMaterial(mat);
+ signpost.rotate(0, FastMath.HALF_PI, 0);
+ signpost.setLocalTranslation(12, 3.5f, 30);
+ signpost.setLocalScale(4);
+ signpost.setShadowMode(ShadowMode.CastAndReceive);
+ TangentBinormalGenerator.generate(signpost);
+ rootNode.attachChild(signpost);
+ }
+
+ @Override
+ public void simpleInitApp() {
+ cam.setLocation(new Vector3f(27.492603f, 29.138166f, -13.232513f));
+ cam.setRotation(new Quaternion(0.25168246f, -0.10547892f, 0.02760565f, 0.96164864f));
+ flyCam.setMoveSpeed(30);
+
+ setupLighting();
+ setupFloor();
+ setupSignpost();
+
+
+ }
+ float angle;
+ boolean stop = true;
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ if (!stop) {
+ super.simpleUpdate(tpf);
+ angle += tpf;
+ angle %= FastMath.TWO_PI;
+
+ spot.setPosition(new Vector3f(FastMath.cos(angle) * 30f, 34.013165f, FastMath.sin(angle) * 30f));
+ lightMdl.setLocalTranslation(spot.getPosition());
+ spot.setDirection(lightTarget.subtract(spot.getPosition()));
+ }
+ }
+}
diff --git a/JmeTests/src/jme3test/light/TestSpotLightTerrain.java b/JmeTests/src/jme3test/light/TestSpotLightTerrain.java
new file mode 100644
index 0000000..02bd48a
--- /dev/null
+++ b/JmeTests/src/jme3test/light/TestSpotLightTerrain.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.light;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.bounding.BoundingBox;
+import com.jme3.font.BitmapText;
+import com.jme3.light.AmbientLight;
+import com.jme3.light.PointLight;
+import com.jme3.light.SpotLight;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Spatial;
+import com.jme3.terrain.geomipmap.TerrainLodControl;
+import com.jme3.terrain.geomipmap.TerrainQuad;
+import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator;
+import com.jme3.terrain.heightmap.AbstractHeightMap;
+import com.jme3.terrain.heightmap.ImageBasedHeightMap;
+import com.jme3.texture.Texture;
+import com.jme3.texture.Texture.WrapMode;
+import com.jme3.util.SkyFactory;
+
+/**
+ * Uses the terrain's lighting texture with normal maps and lights.
+ *
+ * @author bowens
+ */
+public class TestSpotLightTerrain extends SimpleApplication {
+
+ private TerrainQuad terrain;
+ Material matTerrain;
+ Material matWire;
+ boolean wireframe = false;
+ boolean triPlanar = false;
+ boolean wardiso = false;
+ boolean minnaert = false;
+ protected BitmapText hintText;
+ PointLight pl;
+ Geometry lightMdl;
+ private float grassScale = 64;
+ private float dirtScale = 16;
+ private float rockScale = 128;
+ SpotLight sl;
+
+ public static void main(String[] args) {
+ TestSpotLightTerrain app = new TestSpotLightTerrain();
+ app.start();
+ }
+
+
+ @Override
+ public void simpleInitApp() {
+ makeTerrain();
+ flyCam.setMoveSpeed(50);
+
+ sl = new SpotLight();
+ sl.setSpotRange(100);
+ sl.setSpotOuterAngle(20 * FastMath.DEG_TO_RAD);
+ sl.setSpotInnerAngle(15 * FastMath.DEG_TO_RAD);
+ sl.setDirection(new Vector3f(-0.39820394f, -0.73094344f, 0.55421597f));
+ sl.setPosition(new Vector3f(-64.61567f, -87.615425f, -202.41328f));
+ rootNode.addLight(sl);
+
+ AmbientLight ambLight = new AmbientLight();
+ ambLight.setColor(ColorRGBA.Black);
+ rootNode.addLight(ambLight);
+
+ cam.setLocation(new Vector3f(-41.219646f, 0.8363f, -171.67267f));
+ cam.setRotation(new Quaternion(-0.04562731f, 0.89917684f, -0.09668826f, -0.4243236f));
+ sl.setDirection(cam.getDirection());
+ sl.setPosition(cam.getLocation());
+
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ super.simpleUpdate(tpf);
+ sl.setDirection(cam.getDirection());
+ sl.setPosition(cam.getLocation());
+
+ }
+
+ private void makeTerrain() {
+ // TERRAIN TEXTURE material
+ matTerrain = new Material(assetManager, "Common/MatDefs/Terrain/TerrainLighting.j3md");
+ matTerrain.setBoolean("useTriPlanarMapping", false);
+ matTerrain.setBoolean("WardIso", true);
+
+ // ALPHA map (for splat textures)
+ matTerrain.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alpha1.png"));
+ matTerrain.setTexture("AlphaMap_1", assetManager.loadTexture("Textures/Terrain/splat/alpha2.png"));
+
+ // HEIGHTMAP image (for the terrain heightmap)
+ Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png");
+
+
+ // GRASS texture
+ Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg");
+ grass.setWrap(WrapMode.Repeat);
+ matTerrain.setTexture("DiffuseMap", grass);
+ matTerrain.setFloat("DiffuseMap_0_scale", grassScale);
+
+ // DIRT texture
+ Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg");
+ dirt.setWrap(WrapMode.Repeat);
+ matTerrain.setTexture("DiffuseMap_1", dirt);
+ matTerrain.setFloat("DiffuseMap_1_scale", dirtScale);
+
+ // ROCK texture
+ Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg");
+ rock.setWrap(WrapMode.Repeat);
+ matTerrain.setTexture("DiffuseMap_2", rock);
+ matTerrain.setFloat("DiffuseMap_2_scale", rockScale);
+
+ // BRICK texture
+ Texture brick = assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg");
+ brick.setWrap(WrapMode.Repeat);
+ matTerrain.setTexture("DiffuseMap_3", brick);
+ matTerrain.setFloat("DiffuseMap_3_scale", rockScale);
+
+ // RIVER ROCK texture
+ Texture riverRock = assetManager.loadTexture("Textures/Terrain/Pond/Pond.jpg");
+ riverRock.setWrap(WrapMode.Repeat);
+ matTerrain.setTexture("DiffuseMap_4", riverRock);
+ matTerrain.setFloat("DiffuseMap_4_scale", rockScale);
+
+
+ Texture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg");
+ normalMap0.setWrap(WrapMode.Repeat);
+ Texture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png");
+ normalMap1.setWrap(WrapMode.Repeat);
+ Texture normalMap2 = assetManager.loadTexture("Textures/Terrain/splat/road_normal.png");
+ normalMap2.setWrap(WrapMode.Repeat);
+ matTerrain.setTexture("NormalMap", normalMap0);
+ matTerrain.setTexture("NormalMap_1", normalMap2);
+ matTerrain.setTexture("NormalMap_2", normalMap2);
+ matTerrain.setTexture("NormalMap_4", normalMap2);
+
+ // WIREFRAME material
+ matWire = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ matWire.getAdditionalRenderState().setWireframe(true);
+ matWire.setColor("Color", ColorRGBA.Green);
+
+ createSky();
+
+ // CREATE HEIGHTMAP
+ AbstractHeightMap heightmap = null;
+ try {
+ //heightmap = new HillHeightMap(1025, 1000, 50, 100, (byte) 3);
+
+ heightmap = new ImageBasedHeightMap(heightMapImage.getImage(), 1f);
+ heightmap.load();
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ terrain = new TerrainQuad("terrain", 65, 513, heightmap.getHeightMap());//, new LodPerspectiveCalculatorFactory(getCamera(), 4)); // add this in to see it use entropy for LOD calculations
+ TerrainLodControl control = new TerrainLodControl(terrain, getCamera());
+ control.setLodCalculator( new DistanceLodCalculator(65, 2.7f) );
+ terrain.addControl(control);
+ terrain.setMaterial(matTerrain);
+ terrain.setModelBound(new BoundingBox());
+ terrain.updateModelBound();
+ terrain.setLocalTranslation(0, -100, 0);
+ terrain.setLocalScale(1f, 1f, 1f);
+ rootNode.attachChild(terrain);
+ }
+
+ private void createSky() {
+ Texture west = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_west.jpg");
+ Texture east = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_east.jpg");
+ Texture north = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_north.jpg");
+ Texture south = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_south.jpg");
+ Texture up = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_up.jpg");
+ Texture down = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_down.jpg");
+
+ Spatial sky = SkyFactory.createSky(assetManager, west, east, north, south, up, down);
+ rootNode.attachChild(sky);
+ }
+
+
+}
diff --git a/JmeTests/src/jme3test/light/TestTangentCube.java b/JmeTests/src/jme3test/light/TestTangentCube.java
new file mode 100644
index 0000000..c7c3b67
--- /dev/null
+++ b/JmeTests/src/jme3test/light/TestTangentCube.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2009-2015 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.light;
+
+import com.jme3.app.ChaseCameraAppState;
+import com.jme3.app.SimpleApplication;
+import com.jme3.light.AmbientLight;
+import com.jme3.light.PointLight;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Box;
+import com.jme3.util.TangentBinormalGenerator;
+
+/**
+ *
+ * @author Nehon
+ */
+public class TestTangentCube extends SimpleApplication {
+
+ public static void main(String... args) {
+ TestTangentCube app = new TestTangentCube();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ Box aBox = new Box(1, 1, 1);
+ Geometry aGeometry = new Geometry("Box", aBox);
+ TangentBinormalGenerator.generate(aBox);
+
+ Material aMaterial = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+ aMaterial.setTexture("DiffuseMap",
+ assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg"));
+ aMaterial.setTexture("NormalMap",
+ assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall_normal.jpg"));
+ aMaterial.setBoolean("UseMaterialColors", false);
+ aMaterial.setColor("Diffuse", ColorRGBA.White);
+ aMaterial.setColor("Specular", ColorRGBA.White);
+ aMaterial.setFloat("Shininess", 64f);
+ aGeometry.setMaterial(aMaterial);
+
+ // Rotate 45 degrees to see multiple faces
+ aGeometry.rotate(FastMath.QUARTER_PI, FastMath.QUARTER_PI, 0.0f);
+ rootNode.attachChild(aGeometry);
+
+ /**
+ * Must add a light to make the lit object visible!
+ */
+ PointLight aLight = new PointLight();
+ aLight.setPosition(new Vector3f(0, 3, 3));
+ aLight.setColor(ColorRGBA.Red);
+ rootNode.addLight(aLight);
+//
+// AmbientLight bLight = new AmbientLight();
+// bLight.setColor(ColorRGBA.Gray);
+// rootNode.addLight(bLight);
+
+
+ ChaseCameraAppState chaser = new ChaseCameraAppState();
+ chaser.setTarget(aGeometry);
+ getStateManager().attach(chaser);
+ }
+
+}
diff --git a/JmeTests/src/jme3test/light/TestTangentGen.java b/JmeTests/src/jme3test/light/TestTangentGen.java
new file mode 100644
index 0000000..042a857
--- /dev/null
+++ b/JmeTests/src/jme3test/light/TestTangentGen.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.light;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.PointLight;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Mesh;
+import com.jme3.scene.Mesh.Mode;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.VertexBuffer.Type;
+import com.jme3.scene.shape.Quad;
+import com.jme3.scene.shape.Sphere;
+import com.jme3.util.BufferUtils;
+import com.jme3.util.TangentBinormalGenerator;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+
+
+public class TestTangentGen extends SimpleApplication {
+
+ float angle;
+ PointLight pl;
+ Geometry lightMdl;
+
+ public static void main(String[] args){
+ TestTangentGen app = new TestTangentGen();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ flyCam.setMoveSpeed(20);
+ Sphere sphereMesh = new Sphere(32, 32, 1);
+ sphereMesh.setTextureMode(Sphere.TextureMode.Projected);
+ sphereMesh.updateGeometry(32, 32, 1, false, false);
+ addMesh("Sphere", sphereMesh, new Vector3f(-1, 0, 0));
+
+ Quad quadMesh = new Quad(1, 1);
+ quadMesh.updateGeometry(1, 1);
+ addMesh("Quad", quadMesh, new Vector3f(1, 0, 0));
+
+ Mesh strip = createTriangleStripMesh();
+ addMesh("strip", strip, new Vector3f(0, -3, 0));
+
+ DirectionalLight dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(1, -1, -1).normalizeLocal());
+ dl.setColor(ColorRGBA.White);
+ rootNode.addLight(dl);
+ }
+
+ private void addMesh(String name, Mesh mesh, Vector3f translation) {
+ TangentBinormalGenerator.generate(mesh);
+
+ Geometry testGeom = new Geometry(name, mesh);
+ Material mat = assetManager.loadMaterial("Textures/BumpMapTest/Tangent.j3m");
+ testGeom.setMaterial(mat);
+ testGeom.getLocalTranslation().set(translation);
+ rootNode.attachChild(testGeom);
+
+ Geometry debug = new Geometry(
+ "Debug " + name,
+ TangentBinormalGenerator.genTbnLines(mesh, 0.08f)
+ );
+ Material debugMat = assetManager.loadMaterial("Common/Materials/VertexColor.j3m");
+ debug.setMaterial(debugMat);
+ debug.setCullHint(Spatial.CullHint.Never);
+ debug.getLocalTranslation().set(translation);
+ rootNode.attachChild(debug);
+ }
+
+ @Override
+ public void simpleUpdate(float tpf){
+ }
+
+ private Mesh createTriangleStripMesh() {
+ Mesh strip = new Mesh();
+ strip.setMode(Mode.TriangleStrip);
+ FloatBuffer vb = BufferUtils.createFloatBuffer(3*3*3); // 3 rows * 3 columns * 3 floats
+ vb.rewind();
+ vb.put(new float[]{0,2,0}); vb.put(new float[]{1,2,0}); vb.put(new float[]{2,2,0});
+ vb.put(new float[]{0,1,0}); vb.put(new float[]{1,1,0}); vb.put(new float[]{2,1,0});
+ vb.put(new float[]{0,0,0}); vb.put(new float[]{1,0,0}); vb.put(new float[]{2,0,0});
+ FloatBuffer nb = BufferUtils.createFloatBuffer(3*3*3);
+ nb.rewind();
+ nb.put(new float[]{0,0,1}); nb.put(new float[]{0,0,1}); nb.put(new float[]{0,0,1});
+ nb.put(new float[]{0,0,1}); nb.put(new float[]{0,0,1}); nb.put(new float[]{0,0,1});
+ nb.put(new float[]{0,0,1}); nb.put(new float[]{0,0,1}); nb.put(new float[]{0,0,1});
+ FloatBuffer tb = BufferUtils.createFloatBuffer(3*3*2);
+ tb.rewind();
+ tb.put(new float[]{0,0}); tb.put(new float[]{0.5f,0}); tb.put(new float[]{1,0});
+ tb.put(new float[]{0,0.5f}); tb.put(new float[]{0.5f,0.5f}); tb.put(new float[]{1,0.5f});
+ tb.put(new float[]{0,1}); tb.put(new float[]{0.5f,1}); tb.put(new float[]{1,1});
+ int[] indexes = new int[]{0,3,1,4,2,5, 5,3, 3,6,4,7,5,8};
+ IntBuffer ib = BufferUtils.createIntBuffer(indexes.length);
+ ib.put(indexes);
+ strip.setBuffer(Type.Position, 3, vb);
+ strip.setBuffer(Type.Normal, 3, nb);
+ strip.setBuffer(Type.TexCoord, 2, tb);
+ strip.setBuffer(Type.Index, 3, ib);
+ strip.updateBound();
+ return strip;
+ }
+
+}
diff --git a/JmeTests/src/jme3test/light/TestTangentGenBadModels.java b/JmeTests/src/jme3test/light/TestTangentGenBadModels.java
new file mode 100644
index 0000000..21817e7
--- /dev/null
+++ b/JmeTests/src/jme3test/light/TestTangentGenBadModels.java
@@ -0,0 +1,135 @@
+package jme3test.light;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.font.BitmapText;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.PointLight;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Vector3f;
+import com.jme3.renderer.queue.RenderQueue.Bucket;
+import com.jme3.scene.*;
+import com.jme3.scene.Spatial.CullHint;
+import com.jme3.scene.shape.Sphere;
+import com.jme3.util.TangentBinormalGenerator;
+
+/**
+ *
+ * @author Kirusha
+ */
+public class TestTangentGenBadModels extends SimpleApplication {
+
+ float angle;
+ PointLight pl;
+ Geometry lightMdl;
+
+ public static void main(String[] args){
+ TestTangentGenBadModels app = new TestTangentGenBadModels();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+// assetManager.registerLocator("http://jme-glsl-shaders.googlecode.com/hg/assets/Models/LightBlow/", UrlLocator.class);
+// assetManager.registerLocator("http://jmonkeyengine.googlecode.com/files/", UrlLocator.class);
+
+ final Spatial badModel = assetManager.loadModel("Models/TangentBugs/test.blend");
+// badModel.setLocalScale(1f);
+
+ Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+ mat.setTexture("NormalMap", assetManager.loadTexture("Models/TangentBugs/test_normal.png"));
+// Material mat = assetManager.loadMaterial("Textures/BumpMapTest/Tangent.j3m");
+ badModel.setMaterial(mat);
+ rootNode.attachChild(badModel);
+
+ // TODO: For some reason blender loader fails to load this.
+ // need to check it
+// Spatial model = assetManager.loadModel("test.blend");
+// rootNode.attachChild(model);
+
+ final Node debugTangents = new Node("debug tangents");
+ debugTangents.setCullHint(CullHint.Always);
+ rootNode.attachChild(debugTangents);
+
+ final Material debugMat = assetManager.loadMaterial("Common/Materials/VertexColor.j3m");
+
+ badModel.depthFirstTraversal(new SceneGraphVisitorAdapter(){
+ @Override
+ public void visit(Geometry g){
+ Mesh m = g.getMesh();
+ Material mat = g.getMaterial();
+
+// if (mat.getParam("DiffuseMap") != null){
+// mat.setTexture("DiffuseMap", null);
+// }
+ TangentBinormalGenerator.generate(m);
+
+ Geometry debug = new Geometry(
+ "debug tangents geom",
+ TangentBinormalGenerator.genTbnLines(g.getMesh(), 0.2f)
+ );
+ debug.setMaterial(debugMat);
+ debug.setCullHint(Spatial.CullHint.Never);
+ debug.setLocalTransform(g.getWorldTransform());
+ debugTangents.attachChild(debug);
+ }
+ });
+
+ DirectionalLight dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(-0.8f, -0.6f, -0.08f).normalizeLocal());
+ dl.setColor(new ColorRGBA(1,1,1,1));
+ rootNode.addLight(dl);
+
+ lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f));
+ lightMdl.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m"));
+ lightMdl.getMesh().setStatic();
+ rootNode.attachChild(lightMdl);
+
+ pl = new PointLight();
+ pl.setColor(ColorRGBA.White);
+// rootNode.addLight(pl);
+
+
+ BitmapText info = new BitmapText(guiFont);
+ info.setText("Press SPACE to switch between lighting and tangent display");
+ info.setQueueBucket(Bucket.Gui);
+ info.move(0, settings.getHeight() - info.getLineHeight(), 0);
+ rootNode.attachChild(info);
+
+ inputManager.addMapping("space", new KeyTrigger(KeyInput.KEY_SPACE));
+ inputManager.addListener(new ActionListener() {
+
+ private boolean isLit = true;
+
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if (isPressed) return;
+ Material mat;
+ if (isLit){
+ mat = assetManager.loadMaterial("Textures/BumpMapTest/Tangent.j3m");
+ debugTangents.setCullHint(CullHint.Inherit);
+ }else{
+ mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+ mat.setTexture("NormalMap", assetManager.loadTexture("Models/TangentBugs/test_normal.png"));
+ debugTangents.setCullHint(CullHint.Always);
+ }
+ isLit = !isLit;
+ badModel.setMaterial(mat);
+ }
+ }, "space");
+ }
+
+ @Override
+ public void simpleUpdate(float tpf){
+ angle += tpf;
+ angle %= FastMath.TWO_PI;
+
+ pl.setPosition(new Vector3f(FastMath.cos(angle) * 2f, 2f, FastMath.sin(angle) * 2f));
+ lightMdl.setLocalTranslation(pl.getPosition());
+ }
+
+
+}
diff --git a/JmeTests/src/jme3test/light/TestTangentGenBadUV.java b/JmeTests/src/jme3test/light/TestTangentGenBadUV.java
new file mode 100644
index 0000000..6b7a630
--- /dev/null
+++ b/JmeTests/src/jme3test/light/TestTangentGenBadUV.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.light;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.PointLight;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.shape.Sphere;
+import com.jme3.util.TangentBinormalGenerator;
+
+public class TestTangentGenBadUV extends SimpleApplication {
+
+ float angle;
+ PointLight pl;
+ Geometry lightMdl;
+
+ public static void main(String[] args){
+ TestTangentGenBadUV app = new TestTangentGenBadUV();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ Spatial teapot = assetManager.loadModel("Models/Teapot/Teapot.obj");
+ if (teapot instanceof Geometry){
+ Geometry g = (Geometry) teapot;
+ TangentBinormalGenerator.generate(g.getMesh());
+ }else{
+ throw new RuntimeException();
+ }
+ teapot.setLocalScale(2f);
+ Material mat = assetManager.loadMaterial("Textures/BumpMapTest/Tangent.j3m");
+ teapot.setMaterial(mat);
+ rootNode.attachChild(teapot);
+
+ Geometry debug = new Geometry(
+ "Debug Teapot",
+ TangentBinormalGenerator.genTbnLines(((Geometry) teapot).getMesh(), 0.03f)
+ );
+ Material debugMat = assetManager.loadMaterial("Common/Materials/VertexColor.j3m");
+ debug.setMaterial(debugMat);
+ debug.setCullHint(Spatial.CullHint.Never);
+ debug.getLocalTranslation().set(teapot.getLocalTranslation());
+ debug.getLocalScale().set(teapot.getLocalScale());
+ rootNode.attachChild(debug);
+
+
+ DirectionalLight dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(1,-1,-1).normalizeLocal());
+ dl.setColor(ColorRGBA.White);
+ rootNode.addLight(dl);
+
+ lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f));
+ lightMdl.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m"));
+ lightMdl.getMesh().setStatic();
+ rootNode.attachChild(lightMdl);
+
+ pl = new PointLight();
+ pl.setColor(ColorRGBA.White);
+ //pl.setRadius(3f);
+ rootNode.addLight(pl);
+ }
+
+ @Override
+ public void simpleUpdate(float tpf){
+ angle += tpf;
+ angle %= FastMath.TWO_PI;
+
+ pl.setPosition(new Vector3f(FastMath.cos(angle) * 2f, 0.5f, FastMath.sin(angle) * 2f));
+ lightMdl.setLocalTranslation(pl.getPosition());
+ }
+
+}
diff --git a/JmeTests/src/jme3test/light/TestTangentSpace.java b/JmeTests/src/jme3test/light/TestTangentSpace.java
new file mode 100644
index 0000000..9f8daf8
--- /dev/null
+++ b/JmeTests/src/jme3test/light/TestTangentSpace.java
@@ -0,0 +1,100 @@
+package jme3test.light;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.light.DirectionalLight;
+import com.jme3.material.*;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import com.jme3.util.TangentBinormalGenerator;
+import com.jme3.util.mikktspace.MikktspaceTangentGenerator;
+
+/**
+ * test
+ *
+ * @author normenhansen
+ */
+public class TestTangentSpace extends SimpleApplication {
+
+ public static void main(String[] args) {
+ TestTangentSpace app = new TestTangentSpace();
+ app.start();
+ }
+
+ private Node debugNode = new Node("debug");
+
+ @Override
+ public void simpleInitApp() {
+ renderManager.setSinglePassLightBatchSize(2);
+ renderManager.setPreferredLightMode(TechniqueDef.LightMode.SinglePass);
+ initView();
+
+ Spatial s = assetManager.loadModel("Models/Test/BasicCubeLow.obj");
+ rootNode.attachChild(s);
+
+ Material m = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+ m.setTexture("NormalMap", assetManager.loadTexture("Models/Test/Normal_pixel.png"));
+
+ Geometry g = (Geometry)s;
+ Geometry g2 = (Geometry) g.deepClone();
+ g2.move(5, 0, 0);
+ g.getParent().attachChild(g2);
+
+ g.setMaterial(m);
+ g2.setMaterial(m);
+
+ //Regular tangent generation (left geom)
+ TangentBinormalGenerator.generate(g2.getMesh(), true);
+
+ //MikkTSPace Tangent generation (right geom)
+
+ MikktspaceTangentGenerator.generate(g);
+
+ createDebugTangents(g2);
+ createDebugTangents(g);
+
+ inputManager.addListener(new ActionListener() {
+ @Override
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if (name.equals("toggleDebug") && isPressed) {
+ if (debugNode.getParent() == null) {
+ rootNode.attachChild(debugNode);
+ } else {
+ debugNode.removeFromParent();
+ }
+ }
+ }
+ }, "toggleDebug");
+
+ inputManager.addMapping("toggleDebug", new KeyTrigger(KeyInput.KEY_SPACE));
+
+
+ DirectionalLight dl = new DirectionalLight(new Vector3f(-1, -1, -1).normalizeLocal());
+ rootNode.addLight(dl);
+ }
+
+ private void initView() {
+ viewPort.setBackgroundColor(ColorRGBA.DarkGray);
+ cam.setLocation(new Vector3f(8.569681f, 3.335546f, 5.4372444f));
+ cam.setRotation(new Quaternion(-0.07608022f, 0.9086564f, -0.18992864f, -0.3639813f));
+ flyCam.setMoveSpeed(10);
+ }
+
+ private void createDebugTangents(Geometry geom) {
+ Geometry debug = new Geometry(
+ "Debug " + geom.getName(),
+ TangentBinormalGenerator.genTbnLines(geom.getMesh(), 0.8f)
+ );
+ Material debugMat = assetManager.loadMaterial("Common/Materials/VertexColor.j3m");
+ debug.setMaterial(debugMat);
+ debug.setCullHint(Spatial.CullHint.Never);
+ debug.getLocalTranslation().set(geom.getWorldTranslation());
+ debugNode.attachChild(debug);
+ }
+}
diff --git a/JmeTests/src/jme3test/light/TestTransparentShadow.java b/JmeTests/src/jme3test/light/TestTransparentShadow.java
new file mode 100644
index 0000000..23fe73c
--- /dev/null
+++ b/JmeTests/src/jme3test/light/TestTransparentShadow.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.light;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.effect.ParticleEmitter;
+import com.jme3.effect.ParticleMesh;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.light.AmbientLight;
+import com.jme3.light.DirectionalLight;
+import com.jme3.material.Material;
+import com.jme3.math.*;
+import com.jme3.renderer.queue.RenderQueue.Bucket;
+import com.jme3.renderer.queue.RenderQueue.ShadowMode;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.shape.Quad;
+import com.jme3.scene.shape.Sphere;
+import com.jme3.shadow.CompareMode;
+import com.jme3.shadow.DirectionalLightShadowRenderer;
+import com.jme3.shadow.EdgeFilteringMode;
+import com.jme3.util.TangentBinormalGenerator;
+
+public class TestTransparentShadow extends SimpleApplication {
+
+ public static void main(String[] args){
+ TestTransparentShadow app = new TestTransparentShadow();
+ app.start();
+ }
+
+ public void simpleInitApp() {
+ cam.setLocation(new Vector3f(5.700248f, 6.161693f, 5.1404157f));
+ cam.setRotation(new Quaternion(-0.09441641f, 0.8993388f, -0.24089815f, -0.35248178f));
+
+ viewPort.setBackgroundColor(ColorRGBA.DarkGray);
+
+ Quad q = new Quad(20, 20);
+ q.scaleTextureCoordinates(Vector2f.UNIT_XY.mult(10));
+ TangentBinormalGenerator.generate(q);
+ Geometry geom = new Geometry("floor", q);
+ Material mat = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m");
+ geom.setMaterial(mat);
+
+ geom.rotate(-FastMath.HALF_PI, 0, 0);
+ geom.center();
+ geom.setShadowMode(ShadowMode.CastAndReceive);
+ rootNode.attachChild(geom);
+
+ AmbientLight al = new AmbientLight();
+ al.setColor(ColorRGBA.White.mult(0.7f));
+ rootNode.addLight(al);
+
+ DirectionalLight dl1 = new DirectionalLight();
+ dl1.setDirection(new Vector3f(0, -1, 0.5f).normalizeLocal());
+ dl1.setColor(ColorRGBA.White.mult(1.5f));
+ rootNode.addLight(dl1);
+
+ // create the geometry and attach it
+ Spatial tree = assetManager.loadModel("Models/Tree/Tree.mesh.j3o");
+ tree.setQueueBucket(Bucket.Transparent);
+ tree.setShadowMode(ShadowMode.CastAndReceive);
+
+ rootNode.attachChild(tree);
+
+ // Uses Texture from jme3-test-data library!
+ ParticleEmitter fire = new ParticleEmitter("Emitter", ParticleMesh.Type.Triangle, 30);
+ Material mat_red = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
+ mat_red.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/flame.png"));
+ fire.setShadowMode(ShadowMode.Cast);
+ fire.setMaterial(mat_red);
+ fire.setImagesX(2);
+ fire.setImagesY(2); // 2x2 texture animation
+ fire.setEndColor(new ColorRGBA(1f, 0f, 0f, 1f)); // red
+ fire.setStartColor(new ColorRGBA(1f, 1f, 0f, 0.5f)); // yellow
+ fire.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 2, 0));
+ fire.setStartSize(0.6f);
+ fire.setEndSize(0.1f);
+ fire.setGravity(0, 0, 0);
+ fire.setLowLife(0.5f);
+ fire.setHighLife(1.5f);
+ fire.getParticleInfluencer().setVelocityVariation(0.3f);
+ fire.setLocalTranslation(5.0f, 0, 1.0f);
+ fire.setLocalScale(0.3f);
+ fire.setQueueBucket(Bucket.Translucent);
+ rootNode.attachChild(fire);
+
+ Material mat2 = assetManager.loadMaterial("Common/Materials/RedColor.j3m");
+
+ Geometry ball = new Geometry("sphere", new Sphere(16, 16, 0.5f));
+ ball.setMaterial(mat2);
+ ball.setShadowMode(ShadowMode.CastAndReceive);
+ rootNode.attachChild(ball);
+ ball.setLocalTranslation(-1.0f, 1.5f, 1.0f);
+
+ final DirectionalLightShadowRenderer dlsRenderer = new DirectionalLightShadowRenderer(assetManager, 1024, 1);
+ dlsRenderer.setLight(dl1);
+ dlsRenderer.setLambda(0.55f);
+ dlsRenderer.setShadowIntensity(0.8f);
+ dlsRenderer.setShadowCompareMode(CompareMode.Software);
+ dlsRenderer.setEdgeFilteringMode(EdgeFilteringMode.Nearest);
+ dlsRenderer.displayDebug();
+ viewPort.addProcessor(dlsRenderer);
+ inputManager.addMapping("stabilize", new KeyTrigger(KeyInput.KEY_B));
+
+ inputManager.addListener(new ActionListener() {
+ @Override
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if (name.equals("stabilize") && isPressed) {
+ dlsRenderer.setEnabledStabilization(!dlsRenderer.isEnabledStabilization()) ;
+ }
+ }
+ }, "stabilize");
+ }
+}
diff --git a/JmeTests/src/jme3test/light/TestTwoSideLighting.java b/JmeTests/src/jme3test/light/TestTwoSideLighting.java
new file mode 100644
index 0000000..03fe89e
--- /dev/null
+++ b/JmeTests/src/jme3test/light/TestTwoSideLighting.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2009-2015 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.light;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.PointLight;
+import com.jme3.material.Material;
+import com.jme3.material.RenderState;
+import com.jme3.material.TechniqueDef;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Quad;
+import com.jme3.scene.shape.Sphere;
+import com.jme3.util.MaterialDebugAppState;
+import com.jme3.util.TangentBinormalGenerator;
+
+/**
+ * Checks two sided lighting capability.
+ *
+ * @author Kirill Vainer
+ */
+public class TestTwoSideLighting extends SimpleApplication {
+
+ float angle;
+ PointLight pl;
+ Geometry lightMdl;
+
+ public static void main(String[] args){
+ TestTwoSideLighting app = new TestTwoSideLighting();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ // Two-sided lighting requires single pass.
+ renderManager.setPreferredLightMode(TechniqueDef.LightMode.SinglePass);
+ renderManager.setSinglePassLightBatchSize(4);
+
+ cam.setLocation(new Vector3f(5.936224f, 3.3759952f, -3.3202777f));
+ cam.setRotation(new Quaternion(0.16265652f, -0.4811838f, 0.09137692f, 0.8565368f));
+
+ Geometry quadGeom = new Geometry("quad", new Quad(1, 1));
+ quadGeom.move(1, 0, 0);
+ Material mat1 = assetManager.loadMaterial("Textures/BumpMapTest/SimpleBump.j3m");
+
+ // Display both front and back faces.
+ mat1.getAdditionalRenderState().setFaceCullMode(RenderState.FaceCullMode.Off);
+
+ quadGeom.setMaterial(mat1);
+ // SimpleBump material requires tangents.
+ TangentBinormalGenerator.generate(quadGeom);
+ rootNode.attachChild(quadGeom);
+
+ Geometry teapot = (Geometry) assetManager.loadModel("Models/Teapot/Teapot.obj");
+ teapot.move(-1, 0, 0);
+ teapot.setLocalScale(2f);
+ Material mat2 = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+ mat2.setFloat("Shininess", 25);
+ mat2.setBoolean("UseMaterialColors", true);
+ mat2.setColor("Ambient", ColorRGBA.Black);
+ mat2.setColor("Diffuse", ColorRGBA.Gray);
+ mat2.setColor("Specular", ColorRGBA.Gray);
+
+ // Only display backfaces.
+ mat2.getAdditionalRenderState().setFaceCullMode(RenderState.FaceCullMode.Front);
+
+ teapot.setMaterial(mat2);
+ rootNode.attachChild(teapot);
+
+ lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f));
+ lightMdl.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m"));
+ lightMdl.getMesh().setStatic();
+ rootNode.attachChild(lightMdl);
+
+ pl = new PointLight();
+ pl.setColor(ColorRGBA.White);
+ pl.setRadius(4f);
+ rootNode.addLight(pl);
+ }
+
+ @Override
+ public void simpleUpdate(float tpf){
+ angle += tpf;
+ angle %= FastMath.TWO_PI;
+
+ pl.setPosition(new Vector3f(FastMath.cos(angle) * 3f, 0.5f, FastMath.sin(angle) * 3f));
+ lightMdl.setLocalTranslation(pl.getPosition());
+ }
+
+}
diff --git a/JmeTests/src/jme3test/light/pbr/ConsoleProgressReporter.java b/JmeTests/src/jme3test/light/pbr/ConsoleProgressReporter.java
new file mode 100644
index 0000000..f0d100e
--- /dev/null
+++ b/JmeTests/src/jme3test/light/pbr/ConsoleProgressReporter.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2009-2015 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.light.pbr;
+
+import com.jme3.environment.generation.JobProgressAdapter;
+import com.jme3.light.LightProbe;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * A basic logger for environment map rendering progress.
+ * @author nehon
+ */
+public class ConsoleProgressReporter extends JobProgressAdapter{
+
+ private static final Logger logger = Logger.getLogger(ConsoleProgressReporter.class.getName());
+
+ long time;
+
+ @Override
+ public void start() {
+ time = System.currentTimeMillis();
+ logger.log(Level.INFO,"Starting generation");
+ }
+
+ @Override
+ public void progress(double value) {
+ logger.log(Level.INFO, "Progress : {0}%", (value * 100));
+ }
+
+ @Override
+ public void step(String message) {
+ logger.info(message);
+ }
+
+ @Override
+ public void done(LightProbe result) {
+ long end = System.currentTimeMillis();
+ logger.log(Level.INFO, "Generation done in {0}", ((float)(end - time) / 1000f));
+ }
+
+}
diff --git a/JmeTests/src/jme3test/light/pbr/RefEnv.java b/JmeTests/src/jme3test/light/pbr/RefEnv.java
new file mode 100644
index 0000000..a88e12b
--- /dev/null
+++ b/JmeTests/src/jme3test/light/pbr/RefEnv.java
@@ -0,0 +1,135 @@
+package jme3test.light.pbr;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.bounding.BoundingSphere;
+import com.jme3.environment.EnvironmentCamera;
+import com.jme3.environment.LightProbeFactory;
+import com.jme3.environment.generation.JobProgressAdapter;
+import com.jme3.environment.util.EnvMapUtils;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.light.LightProbe;
+import com.jme3.material.Material;
+import com.jme3.math.*;
+import com.jme3.scene.*;
+import com.jme3.ui.Picture;
+import com.jme3.util.SkyFactory;
+
+/**
+ * test
+ *
+ * @author nehon
+ */
+public class RefEnv extends SimpleApplication {
+
+ private Node tex;
+ private Node ref;
+ private Picture refImg;
+
+ public static void main(String[] args) {
+ RefEnv app = new RefEnv();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+
+ cam.setLocation(new Vector3f(-17.95047f, 4.917353f, -17.970531f));
+ cam.setRotation(new Quaternion(0.11724457f, 0.29356146f, -0.03630452f, 0.94802815f));
+// cam.setLocation(new Vector3f(14.790441f, 7.164179f, 19.720007f));
+// cam.setRotation(new Quaternion(-0.038261678f, 0.9578362f, -0.15233073f, -0.24058504f));
+ flyCam.setDragToRotate(true);
+ flyCam.setMoveSpeed(5);
+ Spatial sc = assetManager.loadModel("Scenes/PBR/ref/scene.gltf");
+ rootNode.attachChild(sc);
+ Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/Path.hdr", SkyFactory.EnvMapType.EquirectMap);
+ rootNode.attachChild(sky);
+ rootNode.getChild(0).setCullHint(Spatial.CullHint.Always);
+
+ ref = new Node("reference pictures");
+ refImg = new Picture("refImg");
+ refImg.setHeight(cam.getHeight());
+ refImg.setWidth(cam.getWidth());
+ refImg.setImage(assetManager, "jme3test/light/pbr/ref.png", false);
+
+ ref.attachChild(refImg);
+
+ stateManager.attach(new EnvironmentCamera(256, Vector3f.ZERO));
+
+ inputManager.addMapping("tex", new KeyTrigger(KeyInput.KEY_SPACE));
+ inputManager.addMapping("switch", new KeyTrigger(KeyInput.KEY_RETURN));
+ inputManager.addMapping("ref", new KeyTrigger(KeyInput.KEY_R));
+ inputManager.addListener(new ActionListener() {
+
+ @Override
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if (name.equals("tex") && isPressed) {
+ if (tex == null) {
+ tex = EnvMapUtils.getCubeMapCrossDebugViewWithMipMaps(stateManager.getState(EnvironmentCamera.class).debugEnv, assetManager);
+ }
+ if (tex.getParent() == null) {
+ guiNode.attachChild(tex);
+ } else {
+ tex.removeFromParent();
+ }
+ }
+
+ if (name.equals("switch") && isPressed) {
+ switchMat(rootNode.getChild("Scene"));
+ }
+ if (name.equals("ref") && isPressed) {
+ if (ref.getParent() == null) {
+ guiNode.attachChild(ref);
+ } else {
+ ref.removeFromParent();
+ }
+ }
+ }
+ }, "tex", "switch", "ref");
+
+ }
+
+ private void switchMat(Spatial s) {
+ if (s instanceof Node) {
+ Node n = (Node) s;
+ for (Spatial children : n.getChildren()) {
+ switchMat(children);
+ }
+ } else if (s instanceof Geometry) {
+ Geometry g = (Geometry) s;
+ Material mat = g.getMaterial();
+ if (((Float) mat.getParam("Metallic").getValue()) == 1f) {
+ mat.setFloat("Metallic", 0);
+ mat.setColor("BaseColor", ColorRGBA.Black);
+ ref.attachChild(refImg);
+ } else {
+ mat.setFloat("Metallic", 1);
+ mat.setColor("BaseColor", ColorRGBA.White);
+ refImg.removeFromParent();
+ }
+ }
+ }
+
+ private int frame = 0;
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ frame++;
+
+ if (frame == 2) {
+ final LightProbe probe = LightProbeFactory.makeProbe(stateManager.getState(EnvironmentCamera.class), rootNode, EnvMapUtils.GenerationType.Fast, new JobProgressAdapter() {
+
+ @Override
+ public void done(LightProbe result) {
+ System.err.println("Done rendering env maps");
+ tex = EnvMapUtils.getCubeMapCrossDebugViewWithMipMaps(result.getPrefilteredEnvMap(), assetManager);
+ rootNode.getChild(0).setCullHint(Spatial.CullHint.Dynamic);
+ }
+ });
+ ((BoundingSphere) probe.getBounds()).setRadius(100);
+ rootNode.addLight(probe);
+
+ }
+ }
+}
diff --git a/JmeTests/src/jme3test/light/pbr/TestPBRDirectLighting.java b/JmeTests/src/jme3test/light/pbr/TestPBRDirectLighting.java
new file mode 100644
index 0000000..26cae09
--- /dev/null
+++ b/JmeTests/src/jme3test/light/pbr/TestPBRDirectLighting.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2009-2015 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.light.pbr;
+
+import com.jme3.app.ChaseCameraAppState;
+import com.jme3.app.SimpleApplication;
+import com.jme3.bounding.BoundingSphere;
+import com.jme3.environment.EnvironmentCamera;
+import com.jme3.environment.LightProbeFactory;
+import com.jme3.environment.generation.JobProgressAdapter;
+import com.jme3.environment.util.EnvMapUtils;
+import com.jme3.environment.util.LightsDebugState;
+import com.jme3.input.ChaseCamera;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.LightProbe;
+import com.jme3.material.Material;
+import com.jme3.math.*;
+import com.jme3.post.FilterPostProcessor;
+import com.jme3.post.filters.ToneMapFilter;
+import com.jme3.scene.*;
+import com.jme3.scene.shape.Sphere;
+import com.jme3.texture.plugins.ktx.KTXLoader;
+import com.jme3.util.MaterialDebugAppState;
+import com.jme3.util.SkyFactory;
+import com.jme3.util.mikktspace.MikktspaceTangentGenerator;
+
+/**
+ * A test case for PBR lighting.
+ * Still experimental.
+ *
+ * @author nehon
+ */
+public class TestPBRDirectLighting extends SimpleApplication {
+
+ public static void main(String[] args) {
+ TestPBRDirectLighting app = new TestPBRDirectLighting();
+ app.start();
+ }
+
+ private DirectionalLight dl;
+
+ private float roughness = 0.0f;
+
+ @Override
+ public void simpleInitApp() {
+
+
+ viewPort.setBackgroundColor(ColorRGBA.DarkGray);
+
+ dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(-1, -1, -1).normalizeLocal());
+ rootNode.addLight(dl);
+ dl.setColor(ColorRGBA.White);
+
+ ChaseCameraAppState chaser = new ChaseCameraAppState();
+ chaser.setDragToRotate(true);
+ chaser.setMinVerticalRotation(-FastMath.HALF_PI);
+ chaser.setMaxDistance(1000);
+ chaser.setInvertVerticalAxis(true);
+ getStateManager().attach(chaser);
+ chaser.setTarget(rootNode);
+ flyCam.setEnabled(false);
+
+ Geometry sphere = new Geometry("sphere", new Sphere(32, 32, 1));
+ final Material m = new Material(assetManager, "Common/MatDefs/Light/PBRLighting.j3md");
+ m.setColor("BaseColor", ColorRGBA.Black);
+ m.setFloat("Metallic", 0f);
+ m.setFloat("Roughness", roughness);
+ sphere.setMaterial(m);
+ rootNode.attachChild(sphere);
+
+ inputManager.addListener(new ActionListener() {
+ @Override
+ public void onAction(String name, boolean isPressed, float tpf) {
+
+ if (name.equals("rup") && isPressed) {
+ roughness = FastMath.clamp(roughness + 0.1f, 0.0f, 1.0f);
+ m.setFloat("Roughness", roughness);
+ }
+ if (name.equals("rdown") && isPressed) {
+ roughness = FastMath.clamp(roughness - 0.1f, 0.0f, 1.0f);
+ m.setFloat("Roughness", roughness);
+ }
+
+ if (name.equals("light") && isPressed) {
+ dl.setDirection(cam.getDirection().normalize());
+ }
+ }
+ }, "light", "rup", "rdown");
+
+
+ inputManager.addMapping("light", new KeyTrigger(KeyInput.KEY_F));
+ inputManager.addMapping("rup", new KeyTrigger(KeyInput.KEY_UP));
+ inputManager.addMapping("rdown", new KeyTrigger(KeyInput.KEY_DOWN));
+
+
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ }
+
+}
+
diff --git a/JmeTests/src/jme3test/light/pbr/TestPBRLighting.java b/JmeTests/src/jme3test/light/pbr/TestPBRLighting.java
new file mode 100644
index 0000000..5cb276a
--- /dev/null
+++ b/JmeTests/src/jme3test/light/pbr/TestPBRLighting.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2009-2015 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.light.pbr;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.bounding.BoundingSphere;
+import com.jme3.environment.EnvironmentCamera;
+import com.jme3.environment.LightProbeFactory;
+import com.jme3.environment.generation.JobProgressAdapter;
+import com.jme3.environment.util.EnvMapUtils;
+import com.jme3.environment.util.LightsDebugState;
+import com.jme3.input.ChaseCamera;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.LightProbe;
+import com.jme3.material.Material;
+import com.jme3.math.*;
+import com.jme3.post.FilterPostProcessor;
+import com.jme3.post.filters.ToneMapFilter;
+import com.jme3.scene.*;
+import com.jme3.texture.plugins.ktx.KTXLoader;
+import com.jme3.util.MaterialDebugAppState;
+import com.jme3.util.SkyFactory;
+import com.jme3.util.mikktspace.MikktspaceTangentGenerator;
+
+/**
+ * A test case for PBR lighting.
+ * Still experimental.
+ *
+ * @author nehon
+ */
+public class TestPBRLighting extends SimpleApplication {
+
+ public static void main(String[] args) {
+ TestPBRLighting app = new TestPBRLighting();
+ app.start();
+ }
+
+ private Node tex;
+
+ private Geometry model;
+ private DirectionalLight dl;
+ private Node modelNode;
+ private int frame = 0;
+ private Material pbrMat;
+ private float roughness = 1.0f;
+
+ @Override
+ public void simpleInitApp() {
+ assetManager.registerLoader(KTXLoader.class, "ktx");
+
+ viewPort.setBackgroundColor(ColorRGBA.White);
+ modelNode = (Node) new Node("modelNode");
+ model = (Geometry) assetManager.loadModel("Models/Tank/tank.j3o");
+ MikktspaceTangentGenerator.generate(model);
+ modelNode.attachChild(model);
+
+ dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(-1, -1, -1).normalizeLocal());
+ rootNode.addLight(dl);
+ dl.setColor(ColorRGBA.White);
+ rootNode.attachChild(modelNode);
+
+
+ FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
+// fpp.addFilter(new FXAAFilter());
+ fpp.addFilter(new ToneMapFilter(Vector3f.UNIT_XYZ.mult(4.0f)));
+// fpp.addFilter(new SSAOFilter(0.5f, 3, 0.2f, 0.2f));
+ viewPort.addProcessor(fpp);
+
+ //Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/Sky_Cloudy.hdr", SkyFactory.EnvMapType.EquirectMap);
+ Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/Path.hdr", SkyFactory.EnvMapType.EquirectMap);
+ //Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/Bright/BrightSky.dds", SkyFactory.EnvMapType.CubeMap);
+ //Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/road.hdr", SkyFactory.EnvMapType.EquirectMap);
+ rootNode.attachChild(sky);
+
+ pbrMat = assetManager.loadMaterial("Models/Tank/tank.j3m");
+ model.setMaterial(pbrMat);
+
+
+ final EnvironmentCamera envCam = new EnvironmentCamera(256, new Vector3f(0, 3f, 0));
+ stateManager.attach(envCam);
+
+// EnvironmentManager envManager = new EnvironmentManager();
+// stateManager.attach(envManager);
+
+ // envManager.setScene(rootNode);
+
+ LightsDebugState debugState = new LightsDebugState();
+ stateManager.attach(debugState);
+
+ ChaseCamera chaser = new ChaseCamera(cam, modelNode, inputManager);
+ chaser.setDragToRotate(true);
+ chaser.setMinVerticalRotation(-FastMath.HALF_PI);
+ chaser.setMaxDistance(1000);
+ chaser.setSmoothMotion(true);
+ chaser.setRotationSensitivity(10);
+ chaser.setZoomSensitivity(5);
+ flyCam.setEnabled(false);
+ //flyCam.setMoveSpeed(100);
+
+ inputManager.addListener(new ActionListener() {
+ @Override
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if (name.equals("debug") && isPressed) {
+ if (tex == null) {
+ return;
+ }
+ if (tex.getParent() == null) {
+ guiNode.attachChild(tex);
+ } else {
+ tex.removeFromParent();
+ }
+ }
+
+ if (name.equals("rup") && isPressed) {
+ roughness = FastMath.clamp(roughness + 0.1f, 0.0f, 1.0f);
+ pbrMat.setFloat("Roughness", roughness);
+ }
+ if (name.equals("rdown") && isPressed) {
+ roughness = FastMath.clamp(roughness - 0.1f, 0.0f, 1.0f);
+ pbrMat.setFloat("Roughness", roughness);
+ }
+
+
+ if (name.equals("up") && isPressed) {
+ model.move(0, tpf * 100f, 0);
+ }
+
+ if (name.equals("down") && isPressed) {
+ model.move(0, -tpf * 100f, 0);
+ }
+ if (name.equals("left") && isPressed) {
+ model.move(0, 0, tpf * 100f);
+ }
+ if (name.equals("right") && isPressed) {
+ model.move(0, 0, -tpf * 100f);
+ }
+ if (name.equals("light") && isPressed) {
+ dl.setDirection(cam.getDirection().normalize());
+ }
+ }
+ }, "toggle", "light", "up", "down", "left", "right", "debug", "rup", "rdown");
+
+ inputManager.addMapping("toggle", new KeyTrigger(KeyInput.KEY_RETURN));
+ inputManager.addMapping("light", new KeyTrigger(KeyInput.KEY_F));
+ inputManager.addMapping("up", new KeyTrigger(KeyInput.KEY_UP));
+ inputManager.addMapping("down", new KeyTrigger(KeyInput.KEY_DOWN));
+ inputManager.addMapping("left", new KeyTrigger(KeyInput.KEY_LEFT));
+ inputManager.addMapping("right", new KeyTrigger(KeyInput.KEY_RIGHT));
+ inputManager.addMapping("debug", new KeyTrigger(KeyInput.KEY_D));
+ inputManager.addMapping("rup", new KeyTrigger(KeyInput.KEY_T));
+ inputManager.addMapping("rdown", new KeyTrigger(KeyInput.KEY_G));
+
+
+ MaterialDebugAppState debug = new MaterialDebugAppState();
+ debug.registerBinding("Common/MatDefs/Light/PBRLighting.frag", rootNode);
+ debug.registerBinding("Common/ShaderLib/PBR.glsllib", rootNode);
+ getStateManager().attach(debug);
+
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ frame++;
+
+ if (frame == 2) {
+ modelNode.removeFromParent();
+ final LightProbe probe = LightProbeFactory.makeProbe(stateManager.getState(EnvironmentCamera.class), rootNode, new JobProgressAdapter() {
+
+ @Override
+ public void done(LightProbe result) {
+ System.err.println("Done rendering env maps");
+ tex = EnvMapUtils.getCubeMapCrossDebugViewWithMipMaps(result.getPrefilteredEnvMap(), assetManager);
+ }
+ });
+ ((BoundingSphere) probe.getBounds()).setRadius(100);
+ rootNode.addLight(probe);
+ //getStateManager().getState(EnvironmentManager.class).addEnvProbe(probe);
+
+ }
+ if (frame > 10 && modelNode.getParent() == null) {
+ rootNode.attachChild(modelNode);
+ }
+ }
+
+}
+
diff --git a/JmeTests/src/jme3test/light/pbr/TestPbrEnv.java b/JmeTests/src/jme3test/light/pbr/TestPbrEnv.java
new file mode 100644
index 0000000..eb30e2d
--- /dev/null
+++ b/JmeTests/src/jme3test/light/pbr/TestPbrEnv.java
@@ -0,0 +1,378 @@
+/*
+ * Copyright (c) 2009-2015 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.light.pbr;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.bounding.BoundingSphere;
+import com.jme3.input.CameraInput;
+import com.jme3.input.KeyInput;
+import com.jme3.input.MouseInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.input.controls.MouseAxisTrigger;
+import com.jme3.light.AmbientLight;
+import com.jme3.light.DirectionalLight;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector2f;
+import com.jme3.math.Vector3f;
+import com.jme3.renderer.queue.RenderQueue.ShadowMode;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.shape.Box;
+import com.jme3.scene.shape.Sphere;
+import com.jme3.shadow.DirectionalLightShadowRenderer;
+import com.jme3.shadow.EdgeFilteringMode;
+
+import com.jme3.environment.LightProbeFactory;
+import com.jme3.environment.EnvironmentCamera;
+import com.jme3.environment.util.LightsDebugState;
+import com.jme3.light.LightProbe;
+import com.jme3.material.TechniqueDef;
+import com.jme3.post.FilterPostProcessor;
+import com.jme3.post.filters.BloomFilter;
+import com.jme3.post.filters.FXAAFilter;
+import com.jme3.post.filters.ToneMapFilter;
+import com.jme3.post.ssao.SSAOFilter;
+import com.jme3.scene.Node;
+import com.jme3.texture.plugins.ktx.KTXLoader;
+import com.jme3.util.SkyFactory;
+import com.jme3.util.TangentBinormalGenerator;
+
+public class TestPbrEnv extends SimpleApplication implements ActionListener {
+
+ public static final int SHADOWMAP_SIZE = 1024;
+ private Spatial[] obj;
+ private Material[] mat;
+ private DirectionalLightShadowRenderer dlsr;
+ private LightsDebugState debugState;
+
+ private EnvironmentCamera envCam;
+
+ private Geometry ground;
+ private Material matGroundU;
+ private Material matGroundL;
+
+ private Geometry camGeom;
+
+ public static void main(String[] args) {
+ TestPbrEnv app = new TestPbrEnv();
+ app.start();
+ }
+
+
+ public void loadScene() {
+
+ renderManager.setPreferredLightMode(TechniqueDef.LightMode.SinglePass);
+ renderManager.setSinglePassLightBatchSize(3);
+ obj = new Spatial[2];
+ // Setup first view
+
+ mat = new Material[2];
+ mat[0] = assetManager.loadMaterial("jme3test/light/pbr/pbrMat.j3m");
+ //mat[1] = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m");
+ mat[1] = assetManager.loadMaterial("jme3test/light/pbr/pbrMat2.j3m");
+// mat[1].setBoolean("UseMaterialColors", true);
+// mat[1].setColor("Ambient", ColorRGBA.White.mult(0.5f));
+// mat[1].setColor("Diffuse", ColorRGBA.White.clone());
+
+ obj[0] = new Geometry("sphere", new Sphere(30, 30, 2));
+ obj[0].setShadowMode(ShadowMode.CastAndReceive);
+ obj[1] = new Geometry("cube", new Box(1.0f, 1.0f, 1.0f));
+ obj[1].setShadowMode(ShadowMode.CastAndReceive);
+ TangentBinormalGenerator.generate(obj[1]);
+ TangentBinormalGenerator.generate(obj[0]);
+
+// for (int i = 0; i < 60; i++) {
+// Spatial t = obj[FastMath.nextRandomInt(0, obj.length - 1)].clone(false);
+// t.setName("Cube" + i);
+// t.setLocalScale(FastMath.nextRandomFloat() * 10f);
+// t.setMaterial(mat[FastMath.nextRandomInt(0, mat.length - 1)]);
+// rootNode.attachChild(t);
+// t.setLocalTranslation(FastMath.nextRandomFloat() * 200f, FastMath.nextRandomFloat() * 30f + 20, 30f * (i + 2f));
+// }
+
+ for (int i = 0; i < 2; i++) {
+ Spatial t = obj[0].clone(false);
+ t.setName("Cube" + i);
+ t.setLocalScale( 10f);
+ t.setMaterial(mat[1].clone());
+ rootNode.attachChild(t);
+ t.setLocalTranslation(i * 200f+ 100f, 50, 800f * (i));
+ }
+
+ Box b = new Box(1000, 2, 1000);
+ b.scaleTextureCoordinates(new Vector2f(20, 20));
+ ground = new Geometry("soil", b);
+ TangentBinormalGenerator.generate(ground);
+ ground.setLocalTranslation(0, 10, 550);
+ matGroundU = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ matGroundU.setColor("Color", ColorRGBA.Green);
+
+// matGroundL = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+// Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg");
+// grass.setWrap(WrapMode.Repeat);
+// matGroundL.setTexture("DiffuseMap", grass);
+
+ matGroundL = assetManager.loadMaterial("jme3test/light/pbr/pbrMat4.j3m");
+
+ ground.setMaterial(matGroundL);
+
+ //ground.setShadowMode(ShadowMode.CastAndReceive);
+ rootNode.attachChild(ground);
+
+ l = new DirectionalLight();
+ l.setColor(ColorRGBA.White);
+ //l.setDirection(new Vector3f(0.5973172f, -0.16583486f, 0.7846725f).normalizeLocal());
+ l.setDirection(new Vector3f(-0.2823181f, -0.41889593f, 0.863031f).normalizeLocal());
+
+ rootNode.addLight(l);
+
+ AmbientLight al = new AmbientLight();
+ al.setColor(ColorRGBA.White.mult(0.5f));
+ // rootNode.addLight(al);
+
+ //Spatial sky = SkyFactory.createSky(assetManager, "Scenes/Beach/FullskiesSunset0068.dds", SkyFactory.EnvMapType.CubeMap);
+ Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/Path.hdr", SkyFactory.EnvMapType.EquirectMap);
+ sky.setLocalScale(350);
+
+ rootNode.attachChild(sky);
+ }
+ DirectionalLight l;
+
+ @Override
+ public void simpleInitApp() {
+ assetManager.registerLoader(KTXLoader.class, "ktx");
+
+
+ // put the camera in a bad position
+ cam.setLocation(new Vector3f(-52.433647f, 68.69636f, -118.60924f));
+ cam.setRotation(new Quaternion(0.10294232f, 0.25269797f, -0.027049713f, 0.96167296f));
+
+ flyCam.setMoveSpeed(100);
+
+ loadScene();
+
+ dlsr = new DirectionalLightShadowRenderer(assetManager, SHADOWMAP_SIZE, 4);
+ dlsr.setLight(l);
+ //dlsr.setLambda(0.55f);
+ dlsr.setShadowIntensity(0.5f);
+ dlsr.setEdgeFilteringMode(EdgeFilteringMode.PCFPOISSON);
+ //dlsr.displayDebug();
+ // viewPort.addProcessor(dlsr);
+
+ FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
+
+ fpp.addFilter(new ToneMapFilter(Vector3f.UNIT_XYZ.mult(6.0f)));
+ SSAOFilter ssao = new SSAOFilter();
+ ssao.setIntensity(5);
+
+ fpp.addFilter(ssao);
+
+ BloomFilter bloomFilter = new BloomFilter();
+ fpp.addFilter(bloomFilter);
+ fpp.addFilter(new FXAAFilter());
+ //viewPort.addProcessor(fpp);
+
+ initInputs();
+
+// envManager = new EnvironmentManager();
+// getStateManager().attach(envManager);
+//
+ envCam = new EnvironmentCamera();
+ getStateManager().attach(envCam);
+
+ debugState = new LightsDebugState();
+ debugState.setProbeScale(5);
+ getStateManager().attach(debugState);
+
+ camGeom = new Geometry("camGeom", new Sphere(16, 16, 2));
+// Material m = new Material(assetManager, "Common/MatDefs/Misc/UnshadedNodes.j3md");
+// m.setColor("Color", ColorRGBA.Green);
+ Material m = assetManager.loadMaterial("jme3test/light/pbr/pbrMat3.j3m");
+ camGeom.setMaterial(m);
+ camGeom.setLocalTranslation(0, 20, 0);
+ camGeom.setLocalScale(5);
+ rootNode.attachChild(camGeom);
+
+ // envManager.setScene(rootNode);
+
+// MaterialDebugAppState debug = new MaterialDebugAppState();
+// debug.registerBinding("MatDefs/PBRLighting.frag", rootNode);
+// getStateManager().attach(debug);
+
+ flyCam.setDragToRotate(true);
+ setPauseOnLostFocus(false);
+
+ // cam.lookAt(camGeom.getWorldTranslation(), Vector3f.UNIT_Y);
+
+ }
+
+ private void fixFLyCamInputs() {
+ inputManager.deleteMapping(CameraInput.FLYCAM_LEFT);
+ inputManager.deleteMapping(CameraInput.FLYCAM_RIGHT);
+ inputManager.deleteMapping(CameraInput.FLYCAM_UP);
+ inputManager.deleteMapping(CameraInput.FLYCAM_DOWN);
+
+ inputManager.addMapping(CameraInput.FLYCAM_LEFT, new MouseAxisTrigger(MouseInput.AXIS_X, true));
+
+ inputManager.addMapping(CameraInput.FLYCAM_RIGHT, new MouseAxisTrigger(MouseInput.AXIS_X, false));
+
+ inputManager.addMapping(CameraInput.FLYCAM_UP, new MouseAxisTrigger(MouseInput.AXIS_Y, false));
+
+ inputManager.addMapping(CameraInput.FLYCAM_DOWN, new MouseAxisTrigger(MouseInput.AXIS_Y, true));
+
+ inputManager.addListener(flyCam, CameraInput.FLYCAM_LEFT, CameraInput.FLYCAM_RIGHT, CameraInput.FLYCAM_UP, CameraInput.FLYCAM_DOWN);
+ }
+
+ private void initInputs() {
+ inputManager.addMapping("switchGroundMat", new KeyTrigger(KeyInput.KEY_M));
+ inputManager.addMapping("snapshot", new KeyTrigger(KeyInput.KEY_SPACE));
+ inputManager.addMapping("fc", new KeyTrigger(KeyInput.KEY_F));
+ inputManager.addMapping("debugProbe", new KeyTrigger(KeyInput.KEY_RETURN));
+ inputManager.addMapping("debugTex", new KeyTrigger(KeyInput.KEY_T));
+ inputManager.addMapping("up", new KeyTrigger(KeyInput.KEY_UP));
+ inputManager.addMapping("down", new KeyTrigger(KeyInput.KEY_DOWN));
+ inputManager.addMapping("right", new KeyTrigger(KeyInput.KEY_RIGHT));
+ inputManager.addMapping("left", new KeyTrigger(KeyInput.KEY_LEFT));
+ inputManager.addMapping("delete", new KeyTrigger(KeyInput.KEY_DELETE));
+
+ inputManager.addListener(this, "delete","switchGroundMat", "snapshot", "debugTex", "debugProbe", "fc", "up", "down", "left", "right");
+ }
+
+ private LightProbe lastProbe;
+ private Node debugGui ;
+
+ @Override
+ public void onAction(String name, boolean keyPressed, float tpf) {
+
+ if (name.equals("switchGroundMat") && keyPressed) {
+ if (ground.getMaterial() == matGroundL) {
+ ground.setMaterial(matGroundU);
+ } else {
+
+ ground.setMaterial(matGroundL);
+ }
+ }
+
+ if (name.equals("snapshot") && keyPressed) {
+ envCam.setPosition(camGeom.getWorldTranslation());
+ lastProbe = LightProbeFactory.makeProbe(envCam, rootNode, new ConsoleProgressReporter());
+ ((BoundingSphere)lastProbe.getBounds()).setRadius(200);
+ rootNode.addLight(lastProbe);
+
+ }
+
+ if (name.equals("delete") && keyPressed) {
+ System.err.println(rootNode.getWorldLightList().size());
+ rootNode.removeLight(lastProbe);
+ System.err.println("deleted");
+ System.err.println(rootNode.getWorldLightList().size());
+ }
+
+ if (name.equals("fc") && keyPressed) {
+
+ flyCam.setEnabled(true);
+ }
+
+ if (name.equals("debugProbe") && keyPressed) {
+ debugState.setEnabled(!debugState.isEnabled());
+ }
+
+ if (name.equals("debugTex") && keyPressed) {
+ if(debugGui == null || debugGui.getParent() == null){
+ debugGui = lastProbe.getDebugGui(assetManager);
+ debugGui.setLocalTranslation(10, 200, 0);
+ guiNode.attachChild(debugGui);
+ } else if(debugGui != null){
+ debugGui.removeFromParent();
+ }
+ }
+
+ if (name.equals("up")) {
+ up = keyPressed;
+ }
+ if (name.equals("down")) {
+ down = keyPressed;
+ }
+ if (name.equals("right")) {
+ right = keyPressed;
+ }
+ if (name.equals("left")) {
+ left = keyPressed;
+ }
+ if (name.equals("fwd")) {
+ fwd = keyPressed;
+ }
+ if (name.equals("back")) {
+ back = keyPressed;
+ }
+
+ }
+ boolean up = false;
+ boolean down = false;
+ boolean left = false;
+ boolean right = false;
+ boolean fwd = false;
+ boolean back = false;
+ float time = 0;
+ float s = 50f;
+ boolean initialized = false;
+
+ @Override
+ public void simpleUpdate(float tpf) {
+
+ if (!initialized) {
+ fixFLyCamInputs();
+ initialized = true;
+ }
+ float val = tpf * s;
+ if (up) {
+ camGeom.move(0, 0, val);
+ }
+ if (down) {
+ camGeom.move(0, 0, -val);
+
+ }
+ if (right) {
+ camGeom.move(-val, 0, 0);
+
+ }
+ if (left) {
+ camGeom.move(val, 0, 0);
+
+ }
+
+ }
+
+}
diff --git a/JmeTests/src/jme3test/light/pbr/pbrMat.j3m b/JmeTests/src/jme3test/light/pbr/pbrMat.j3m
new file mode 100644
index 0000000..22e50b6
--- /dev/null
+++ b/JmeTests/src/jme3test/light/pbr/pbrMat.j3m
@@ -0,0 +1,13 @@
+Material My Material : Common/MatDefs/Light/PBRLighting.j3md {
+ MaterialParameters {
+ Roughness : 0.1
+ BaseColor : 1.0 0.2 0.2 1.0
+ Metallic : 0.0
+ EmissivePower : 0.0
+ EmissiveIntensity : 0.0
+ Emissive : 1.0 0.8 0.8 1.0
+ ParallaxHeight : 0.0
+ }
+ AdditionalRenderState {
+ }
+}
diff --git a/JmeTests/src/jme3test/light/pbr/pbrMat2.j3m b/JmeTests/src/jme3test/light/pbr/pbrMat2.j3m
new file mode 100644
index 0000000..2414bf3
--- /dev/null
+++ b/JmeTests/src/jme3test/light/pbr/pbrMat2.j3m
@@ -0,0 +1,12 @@
+Material My Material : Common/MatDefs/Light/PBRLighting.j3md {
+ MaterialParameters {
+ Metallic : 0.0
+ Roughness : 0.0
+ BaseColor : 0.8 0.81960785 0.39607844 1.0
+ EmissiveIntensity : 5.0
+ EmissivePower : 2.0
+ Emissive : 1.0 0.0 0.0 1.0
+ }
+ AdditionalRenderState {
+ }
+}
diff --git a/JmeTests/src/jme3test/light/pbr/pbrMat3.j3m b/JmeTests/src/jme3test/light/pbr/pbrMat3.j3m
new file mode 100644
index 0000000..bdf52aa
--- /dev/null
+++ b/JmeTests/src/jme3test/light/pbr/pbrMat3.j3m
@@ -0,0 +1,9 @@
+Material My Material : Common/MatDefs/Light/PBRLighting.j3md {
+ MaterialParameters {
+ BaseColor : 0.6 0.6 0.6 1.0
+ Metallic : 1.0
+ Roughness : 0.05
+ }
+ AdditionalRenderState {
+ }
+}
diff --git a/JmeTests/src/jme3test/light/pbr/pbrMat4.j3m b/JmeTests/src/jme3test/light/pbr/pbrMat4.j3m
new file mode 100644
index 0000000..892c9f8
--- /dev/null
+++ b/JmeTests/src/jme3test/light/pbr/pbrMat4.j3m
@@ -0,0 +1,11 @@
+Material My Material : Common/MatDefs/Light/PBRLighting.j3md {
+ MaterialParameters {
+ BaseColorMap : Repeat Textures/Terrain/BrickWall/BrickWall.jpg
+ Roughness : 0.01
+ NormalMap : Repeat Textures/Terrain/BrickWall/BrickWall_normal.jpg
+ Metallic : 1.0
+ BaseColor : 1.0 1.0 1.0 1.0
+ }
+ AdditionalRenderState {
+ }
+}
diff --git a/JmeTests/src/jme3test/light/pbr/ref.png b/JmeTests/src/jme3test/light/pbr/ref.png
new file mode 100644
index 0000000..23ac5e8
Binary files /dev/null and b/JmeTests/src/jme3test/light/pbr/ref.png differ
diff --git a/JmeTests/src/jme3test/material/TestBumpModel.java b/JmeTests/src/jme3test/material/TestBumpModel.java
new file mode 100644
index 0000000..49028ba
--- /dev/null
+++ b/JmeTests/src/jme3test/material/TestBumpModel.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.material;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.PointLight;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.plugins.ogre.OgreMeshKey;
+import com.jme3.scene.shape.Sphere;
+import com.jme3.util.TangentBinormalGenerator;
+
+public class TestBumpModel extends SimpleApplication {
+
+ float angle;
+ PointLight pl;
+ Spatial lightMdl;
+
+ public static void main(String[] args){
+ TestBumpModel app = new TestBumpModel();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ Spatial signpost = (Spatial) assetManager.loadAsset(new OgreMeshKey("Models/Sign Post/Sign Post.mesh.xml"));
+ signpost.setMaterial( (Material) assetManager.loadMaterial("Models/Sign Post/Sign Post.j3m"));
+ TangentBinormalGenerator.generate(signpost);
+ rootNode.attachChild(signpost);
+
+ lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f));
+ lightMdl.setMaterial( (Material) assetManager.loadMaterial("Common/Materials/RedColor.j3m"));
+ rootNode.attachChild(lightMdl);
+
+ // flourescent main light
+ pl = new PointLight();
+ pl.setColor(new ColorRGBA(0.88f, 0.92f, 0.95f, 1.0f));
+ rootNode.addLight(pl);
+
+ // sunset light
+ DirectionalLight dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(-0.1f,-0.7f,1).normalizeLocal());
+ dl.setColor(new ColorRGBA(0.44f, 0.30f, 0.20f, 1.0f));
+ rootNode.addLight(dl);
+
+ // skylight
+ dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(-0.6f,-1,-0.6f).normalizeLocal());
+ dl.setColor(new ColorRGBA(0.10f, 0.22f, 0.44f, 1.0f));
+ rootNode.addLight(dl);
+
+ // white ambient light
+ dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(1, -0.5f,-0.1f).normalizeLocal());
+ dl.setColor(new ColorRGBA(0.50f, 0.40f, 0.50f, 1.0f));
+ rootNode.addLight(dl);
+ }
+
+ @Override
+ public void simpleUpdate(float tpf){
+ angle += tpf * 0.25f;
+ angle %= FastMath.TWO_PI;
+
+ pl.setPosition(new Vector3f(FastMath.cos(angle) * 6f, 3f, FastMath.sin(angle) * 6f));
+ lightMdl.setLocalTranslation(pl.getPosition());
+ }
+
+}
diff --git a/JmeTests/src/jme3test/material/TestColoredTexture.java b/JmeTests/src/jme3test/material/TestColoredTexture.java
new file mode 100644
index 0000000..7f7c50f
--- /dev/null
+++ b/JmeTests/src/jme3test/material/TestColoredTexture.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.material;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.renderer.queue.RenderQueue.Bucket;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Quad;
+
+public class TestColoredTexture extends SimpleApplication {
+
+ private float time = 0;
+ private ColorRGBA nextColor;
+ private ColorRGBA prevColor;
+ private Material mat;
+
+ public static void main(String[] args){
+ TestColoredTexture app = new TestColoredTexture();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ Quad quadMesh = new Quad(512,512);
+ Geometry quad = new Geometry("Quad", quadMesh);
+ quad.setQueueBucket(Bucket.Gui);
+
+ mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat.setTexture("ColorMap", assetManager.loadTexture("Textures/ColoredTex/Monkey.png"));
+ quad.setMaterial(mat);
+ guiNode.attachChildAt(quad, 0);
+
+ nextColor = ColorRGBA.randomColor();
+ prevColor = ColorRGBA.Black;
+ }
+
+ @Override
+ public void simpleUpdate(float tpf){
+ time += tpf;
+ if (time > 1f){
+ time -= 1f;
+ prevColor = nextColor;
+ nextColor = ColorRGBA.randomColor();
+ }
+ ColorRGBA currentColor = new ColorRGBA();
+ currentColor.interpolateLocal(prevColor, nextColor, time);
+
+ mat.setColor("Color", currentColor);
+ }
+
+}
diff --git a/JmeTests/src/jme3test/material/TestGeometryShader.java b/JmeTests/src/jme3test/material/TestGeometryShader.java
new file mode 100644
index 0000000..04c8223
--- /dev/null
+++ b/JmeTests/src/jme3test/material/TestGeometryShader.java
@@ -0,0 +1,42 @@
+package jme3test.material;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.bounding.BoundingBox;
+import com.jme3.material.Material;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Mesh;
+import com.jme3.scene.VertexBuffer;
+import com.jme3.scene.shape.Sphere;
+import com.jme3.util.BufferUtils;
+
+/**
+ * Created by michael on 23.02.15.
+ */
+public class TestGeometryShader extends SimpleApplication {
+ @Override
+ public void simpleInitApp() {
+ Mesh mesh = new Mesh();
+ mesh.setBuffer(VertexBuffer.Type.Index, 1, BufferUtils.createIntBuffer(new int[]{1}));
+ mesh.setBuffer(VertexBuffer.Type.Position, 3, BufferUtils.createFloatBuffer(new float[]{0, 0, 0}));
+ mesh.setMode(Mesh.Mode.Points);
+ mesh.setBound(new BoundingBox(new Vector3f(0, 0, 0), 10, 10, 10));
+ mesh.updateCounts();
+ Geometry geometry = new Geometry("Test", mesh);
+ geometry.updateGeometricState();
+ geometry.setMaterial(new Material(assetManager, "Materials/Geom/SimpleGeom.j3md"));
+ //geometry.getMaterial().getAdditionalRenderState().setFaceCullMode(RenderState.FaceCullMode.Off);
+ //geometry.setMaterial(assetManager.loadMaterial("Materials/Geom/SimpleTess.j3md"));
+ rootNode.attachChild(geometry);
+
+ Geometry geometry1 = new Geometry("T1", new Sphere(10, 10, 1));
+ geometry1.setMaterial(new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"));
+ rootNode.attachChild(geometry1);
+
+ }
+
+ public static void main(String[] args) {
+ TestGeometryShader app = new TestGeometryShader();
+ app.start();
+ }
+}
diff --git a/JmeTests/src/jme3test/material/TestMatParamOverride.java b/JmeTests/src/jme3test/material/TestMatParamOverride.java
new file mode 100644
index 0000000..6124d9e
--- /dev/null
+++ b/JmeTests/src/jme3test/material/TestMatParamOverride.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2009-2017 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.material;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.material.MatParamOverride;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector4f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Box;
+import com.jme3.shader.VarType;
+
+/**
+ * Test if {@link MatParamOverride}s are working correctly.
+ *
+ * @author Kirill Vainer
+ */
+public class TestMatParamOverride extends SimpleApplication {
+
+ private Box box = new Box(1, 1, 1);
+ final MatParamOverride overrideYellow
+ = new MatParamOverride(VarType.Vector4, "Color",
+ ColorRGBA.Yellow);
+ final MatParamOverride overrideWhite
+ = new MatParamOverride(VarType.Vector4, "Color",
+ Vector4f.UNIT_XYZW);
+ final MatParamOverride overrideGray
+ = new MatParamOverride(VarType.Vector4, "Color",
+ new Quaternion(0.5f, 0.5f, 0.5f, 1f));
+
+ public static void main(String[] args) {
+ TestMatParamOverride app = new TestMatParamOverride();
+ app.start();
+ }
+
+ private void createBox(float location, ColorRGBA color) {
+ Geometry geom = new Geometry("Box", box);
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat.setColor("Color", color);
+ geom.setMaterial(mat);
+ geom.move(location, 0, 0);
+ rootNode.attachChild(geom);
+ }
+
+ @Override
+ public void simpleInitApp() {
+ inputManager.setCursorVisible(true);
+
+ createBox(-3, ColorRGBA.Red);
+ createBox(0, ColorRGBA.Green);
+ createBox(3, ColorRGBA.Blue);
+
+ System.out.println("Press G, W, Y, or space bar ...");
+ inputManager.addMapping("overrideClear", new KeyTrigger(KeyInput.KEY_SPACE));
+ inputManager.addMapping("overrideGray", new KeyTrigger(KeyInput.KEY_G));
+ inputManager.addMapping("overrideWhite", new KeyTrigger(KeyInput.KEY_W));
+ inputManager.addMapping("overrideYellow", new KeyTrigger(KeyInput.KEY_Y));
+ inputManager.addListener(new ActionListener() {
+ @Override
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if (isPressed) {
+ if (name.equals("overrideClear")) {
+ rootNode.clearMatParamOverrides();
+ } else if (name.equals("overrideGray")) {
+ rootNode.clearMatParamOverrides();
+ rootNode.addMatParamOverride(overrideGray);
+ } else if (name.equals("overrideWhite")) {
+ rootNode.clearMatParamOverrides();
+ rootNode.addMatParamOverride(overrideWhite);
+ } else if (name.equals("overrideYellow")) {
+ rootNode.clearMatParamOverrides();
+ rootNode.addMatParamOverride(overrideYellow);
+ }
+ System.out.println(rootNode.getLocalMatParamOverrides());
+ }
+ }
+ }, "overrideClear", "overrideGray", "overrideWhite", "overrideYellow");
+ }
+}
diff --git a/JmeTests/src/jme3test/material/TestMaterialCompare.java b/JmeTests/src/jme3test/material/TestMaterialCompare.java
new file mode 100644
index 0000000..a378551
--- /dev/null
+++ b/JmeTests/src/jme3test/material/TestMaterialCompare.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.material;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.asset.TextureKey;
+import com.jme3.material.Material;
+import com.jme3.material.RenderState.BlendMode;
+import com.jme3.math.ColorRGBA;
+import com.jme3.system.JmeSystem;
+import com.jme3.texture.Texture;
+
+public class TestMaterialCompare {
+
+ public static void main(String[] args) {
+ AssetManager assetManager = JmeSystem.newAssetManager(
+ TestMaterialCompare.class.getResource("/com/jme3/asset/Desktop.cfg"));
+
+ // Cloned materials
+ Material mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat1.setName("mat1");
+ mat1.setColor("Color", ColorRGBA.Blue);
+
+ Material mat2 = mat1.clone();
+ mat2.setName("mat2");
+ testEquality(mat1, mat2, true);
+
+ // Cloned material with different render states
+ Material mat3 = mat1.clone();
+ mat3.setName("mat3");
+ mat3.getAdditionalRenderState().setBlendMode(BlendMode.ModulateX2);
+ testEquality(mat1, mat3, false);
+
+ // Two separately loaded materials
+ Material mat4 = assetManager.loadMaterial("Models/Sign Post/Sign Post.j3m");
+ mat4.setName("mat4");
+ Material mat5 = assetManager.loadMaterial("Models/Sign Post/Sign Post.j3m");
+ mat5.setName("mat5");
+ testEquality(mat4, mat5, true);
+
+ // Comparing same textures
+ TextureKey originalKey = (TextureKey) mat4.getTextureParam("DiffuseMap").getTextureValue().getKey();
+ TextureKey tex1key = new TextureKey("Models/Sign Post/Sign Post.jpg", false);
+ tex1key.setGenerateMips(true);
+
+ // Texture keys from the original and the loaded texture
+ // must be identical, otherwise the resultant textures not identical
+ // and thus materials are not identical!
+ if (!originalKey.equals(tex1key)){
+ System.out.println("TEXTURE KEYS ARE NOT EQUAL");
+ }
+
+ Texture tex1 = assetManager.loadTexture(tex1key);
+ mat4.setTexture("DiffuseMap", tex1);
+ testEquality(mat4, mat5, true);
+
+ // Change some stuff on the texture and compare, materials no longer equal
+ tex1.setWrap(Texture.WrapMode.MirroredRepeat);
+ testEquality(mat4, mat5, false);
+
+ // Comparing different textures
+ Texture tex2 = assetManager.loadTexture("Interface/Logo/Monkey.jpg");
+ mat4.setTexture("DiffuseMap", tex2);
+ testEquality(mat4, mat5, false);
+
+ // Two materials created the same way
+ Material mat6 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat6.setName("mat6");
+ mat6.setColor("Color", ColorRGBA.Blue);
+ testEquality(mat1, mat6, true);
+
+ // Changing a material param
+ mat6.setColor("Color", ColorRGBA.Green);
+ testEquality(mat1, mat6, false);
+ }
+
+ private static void testEquality(Material mat1, Material mat2, boolean expected) {
+ if (mat2.contentEquals(mat1)) {
+ System.out.print(mat1.getName() + " == " + mat2.getName());
+ if (expected) {
+ System.out.println(" EQUAL OK");
+ } else {
+ System.out.println(" EQUAL FAIL!");
+ }
+ } else {
+ System.out.print(mat1.getName() + " != " + mat2.getName());
+ if (!expected) {
+ System.out.println(" EQUAL OK");
+ } else {
+ System.out.println(" EQUAL FAIL!");
+ }
+ }
+ if (mat2.hashCode() == mat1.hashCode()){
+ System.out.print(mat1.getName() + " == " + mat2.getName());
+ if (expected) {
+ System.out.println(" HASH OK");
+ } else {
+ System.out.println(" HASH FAIL!");
+ }
+ } else {
+ System.out.print(mat1.getName() + " != " + mat2.getName());
+ if (!expected) {
+ System.out.println(" HASH OK");
+ } else {
+ System.out.println(" HASH FAIL!");
+ }
+ }
+ }
+}
diff --git a/JmeTests/src/jme3test/material/TestNormalMapping.java b/JmeTests/src/jme3test/material/TestNormalMapping.java
new file mode 100644
index 0000000..c955b34
--- /dev/null
+++ b/JmeTests/src/jme3test/material/TestNormalMapping.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.material;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.light.PointLight;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.shape.Sphere;
+import com.jme3.util.TangentBinormalGenerator;
+
+public class TestNormalMapping extends SimpleApplication {
+
+ float angle;
+ PointLight pl;
+ Spatial lightMdl;
+
+ public static void main(String[] args){
+ TestNormalMapping app = new TestNormalMapping();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ Sphere sphMesh = new Sphere(32, 32, 1);
+ sphMesh.setTextureMode(Sphere.TextureMode.Projected);
+ sphMesh.updateGeometry(32, 32, 1, false, false);
+ TangentBinormalGenerator.generate(sphMesh);
+
+ Geometry sphere = new Geometry("Rock Ball", sphMesh);
+ Material mat = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m");
+ sphere.setMaterial(mat);
+ rootNode.attachChild(sphere);
+
+ lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f));
+ lightMdl.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m"));
+ rootNode.attachChild(lightMdl);
+
+ pl = new PointLight();
+ pl.setColor(ColorRGBA.White);
+ pl.setPosition(new Vector3f(0f, 0f, 4f));
+ rootNode.addLight(pl);
+
+// DirectionalLight dl = new DirectionalLight();
+// dl.setDirection(new Vector3f(1,-1,1).normalizeLocal());
+// dl.setColor(new ColorRGBA(0.22f, 0.15f, 0.1f, 1.0f));
+// rootNode.addLight(dl);
+ }
+
+ @Override
+ public void simpleUpdate(float tpf){
+ angle += tpf * 0.25f;
+ angle %= FastMath.TWO_PI;
+
+ pl.setPosition(new Vector3f(FastMath.cos(angle) * 4f, 0.5f, FastMath.sin(angle) * 4f));
+ lightMdl.setLocalTranslation(pl.getPosition());
+ }
+
+}
diff --git a/JmeTests/src/jme3test/material/TestParallax.java b/JmeTests/src/jme3test/material/TestParallax.java
new file mode 100644
index 0000000..cf5263e
--- /dev/null
+++ b/JmeTests/src/jme3test/material/TestParallax.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2009-2015 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.material;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.AnalogListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.light.DirectionalLight;
+import com.jme3.material.Material;
+import com.jme3.math.*;
+import com.jme3.renderer.queue.RenderQueue.ShadowMode;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.shape.Quad;
+import com.jme3.util.SkyFactory;
+import com.jme3.util.TangentBinormalGenerator;
+
+public class TestParallax extends SimpleApplication {
+
+ private final Vector3f lightDir = new Vector3f(-1, -1, .5f).normalizeLocal();
+
+ public static void main(String[] args) {
+ TestParallax app = new TestParallax();
+ app.start();
+ }
+
+ public void setupSkyBox() {
+ rootNode.attachChild(SkyFactory.createSky(assetManager, "Scenes/Beach/FullskiesSunset0068.dds", SkyFactory.EnvMapType.CubeMap));
+ }
+ DirectionalLight dl;
+
+ public void setupLighting() {
+
+ dl = new DirectionalLight();
+ dl.setDirection(lightDir);
+ dl.setColor(new ColorRGBA(.9f, .9f, .9f, 1));
+ rootNode.addLight(dl);
+ }
+ Material mat;
+
+ public void setupFloor() {
+ mat = assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall.j3m");
+
+ Node floorGeom = new Node("floorGeom");
+ Quad q = new Quad(100, 100);
+ q.scaleTextureCoordinates(new Vector2f(10, 10));
+ Geometry g = new Geometry("geom", q);
+ g.setLocalRotation(new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X));
+ floorGeom.attachChild(g);
+
+
+ TangentBinormalGenerator.generate(floorGeom);
+ floorGeom.setLocalTranslation(-50, 22, 60);
+ //floorGeom.setLocalScale(100);
+
+ floorGeom.setMaterial(mat);
+ rootNode.attachChild(floorGeom);
+ }
+
+ public void setupSignpost() {
+ Spatial signpost = assetManager.loadModel("Models/Sign Post/Sign Post.mesh.xml");
+ Material matSp = assetManager.loadMaterial("Models/Sign Post/Sign Post.j3m");
+ TangentBinormalGenerator.generate(signpost);
+ signpost.setMaterial(matSp);
+ signpost.rotate(0, FastMath.HALF_PI, 0);
+ signpost.setLocalTranslation(12, 23.5f, 30);
+ signpost.setLocalScale(4);
+ signpost.setShadowMode(ShadowMode.CastAndReceive);
+ rootNode.attachChild(signpost);
+ }
+
+ @Override
+ public void simpleInitApp() {
+ cam.setLocation(new Vector3f(-15.445636f, 30.162927f, 60.252777f));
+ cam.setRotation(new Quaternion(0.05173137f, 0.92363626f, -0.13454558f, 0.35513034f));
+ flyCam.setMoveSpeed(30);
+
+ setupLighting();
+ setupSkyBox();
+ setupFloor();
+ setupSignpost();
+
+ inputManager.addListener(new AnalogListener() {
+
+ @Override
+ public void onAnalog(String name, float value, float tpf) {
+ if ("heightUP".equals(name)) {
+ parallaxHeigh += 0.01;
+ mat.setFloat("ParallaxHeight", parallaxHeigh);
+ }
+ if ("heightDown".equals(name)) {
+ parallaxHeigh -= 0.01;
+ parallaxHeigh = Math.max(parallaxHeigh, 0);
+ mat.setFloat("ParallaxHeight", parallaxHeigh);
+ }
+
+ }
+ }, "heightUP", "heightDown");
+ inputManager.addMapping("heightUP", new KeyTrigger(KeyInput.KEY_I));
+ inputManager.addMapping("heightDown", new KeyTrigger(KeyInput.KEY_K));
+
+ inputManager.addListener(new ActionListener() {
+
+ @Override
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if (isPressed && "toggleSteep".equals(name)) {
+ steep = !steep;
+ mat.setBoolean("SteepParallax", steep);
+ }
+ }
+ }, "toggleSteep");
+ inputManager.addMapping("toggleSteep", new KeyTrigger(KeyInput.KEY_SPACE));
+ }
+ float parallaxHeigh = 0.05f;
+ float time = 0;
+ boolean steep = false;
+
+ @Override
+ public void simpleUpdate(float tpf) {
+// time+=tpf;
+// lightDir.set(FastMath.sin(time), -1, FastMath.cos(time));
+// bsr.setDirection(lightDir);
+// dl.setDirection(lightDir);
+ }
+}
diff --git a/JmeTests/src/jme3test/material/TestParallaxPBR.java b/JmeTests/src/jme3test/material/TestParallaxPBR.java
new file mode 100644
index 0000000..2a97a70
--- /dev/null
+++ b/JmeTests/src/jme3test/material/TestParallaxPBR.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.material;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.AnalogListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.light.DirectionalLight;
+import com.jme3.material.Material;
+import com.jme3.math.*;
+import com.jme3.renderer.queue.RenderQueue.ShadowMode;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.shape.Quad;
+import com.jme3.util.SkyFactory;
+import com.jme3.util.TangentBinormalGenerator;
+
+public class TestParallaxPBR extends SimpleApplication {
+
+ private Vector3f lightDir = new Vector3f(-1, -1, .5f).normalizeLocal();
+
+ public static void main(String[] args) {
+ TestParallaxPBR app = new TestParallaxPBR();
+ app.start();
+ }
+
+ public void setupSkyBox() {
+ rootNode.attachChild(SkyFactory.createSky(assetManager, "Scenes/Beach/FullskiesSunset0068.dds", SkyFactory.EnvMapType.CubeMap));
+ }
+ DirectionalLight dl;
+
+ public void setupLighting() {
+
+ dl = new DirectionalLight();
+ dl.setDirection(lightDir);
+ dl.setColor(new ColorRGBA(.9f, .9f, .9f, 1));
+ rootNode.addLight(dl);
+ }
+ Material mat;
+
+ public void setupFloor() {
+ mat = assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWallPBR.j3m");
+ //mat = assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWallPBR2.j3m");
+
+ Node floorGeom = new Node("floorGeom");
+ Quad q = new Quad(100, 100);
+ q.scaleTextureCoordinates(new Vector2f(10, 10));
+ Geometry g = new Geometry("geom", q);
+ g.setLocalRotation(new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X));
+ floorGeom.attachChild(g);
+
+
+ TangentBinormalGenerator.generate(floorGeom);
+ floorGeom.setLocalTranslation(-50, 22, 60);
+ //floorGeom.setLocalScale(100);
+
+ floorGeom.setMaterial(mat);
+ rootNode.attachChild(floorGeom);
+ }
+
+ public void setupSignpost() {
+ Spatial signpost = assetManager.loadModel("Models/Sign Post/Sign Post.mesh.xml");
+ Material mat = assetManager.loadMaterial("Models/Sign Post/Sign Post.j3m");
+ TangentBinormalGenerator.generate(signpost);
+ signpost.setMaterial(mat);
+ signpost.rotate(0, FastMath.HALF_PI, 0);
+ signpost.setLocalTranslation(12, 23.5f, 30);
+ signpost.setLocalScale(4);
+ signpost.setShadowMode(ShadowMode.CastAndReceive);
+ rootNode.attachChild(signpost);
+ }
+
+ @Override
+ public void simpleInitApp() {
+ cam.setLocation(new Vector3f(-15.445636f, 30.162927f, 60.252777f));
+ cam.setRotation(new Quaternion(0.05173137f, 0.92363626f, -0.13454558f, 0.35513034f));
+ flyCam.setMoveSpeed(30);
+
+
+ setupLighting();
+ setupSkyBox();
+ setupFloor();
+ setupSignpost();
+
+ inputManager.addListener(new AnalogListener() {
+
+ public void onAnalog(String name, float value, float tpf) {
+ if ("heightUP".equals(name)) {
+ parallaxHeigh += 0.01;
+ mat.setFloat("ParallaxHeight", parallaxHeigh);
+ }
+ if ("heightDown".equals(name)) {
+ parallaxHeigh -= 0.01;
+ parallaxHeigh = Math.max(parallaxHeigh, 0);
+ mat.setFloat("ParallaxHeight", parallaxHeigh);
+ }
+
+ }
+ }, "heightUP", "heightDown");
+ inputManager.addMapping("heightUP", new KeyTrigger(KeyInput.KEY_I));
+ inputManager.addMapping("heightDown", new KeyTrigger(KeyInput.KEY_K));
+
+ inputManager.addListener(new ActionListener() {
+
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if (isPressed && "toggleSteep".equals(name)) {
+ steep = !steep;
+ mat.setBoolean("SteepParallax", steep);
+ }
+ }
+ }, "toggleSteep");
+ inputManager.addMapping("toggleSteep", new KeyTrigger(KeyInput.KEY_SPACE));
+ }
+ float parallaxHeigh = 0.05f;
+ float time = 0;
+ boolean steep = false;
+
+ @Override
+ public void simpleUpdate(float tpf) {
+// time+=tpf;
+// lightDir.set(FastMath.sin(time), -1, FastMath.cos(time));
+// bsr.setDirection(lightDir);
+// dl.setDirection(lightDir);
+ }
+}
diff --git a/JmeTests/src/jme3test/material/TestShaderNodes.java b/JmeTests/src/jme3test/material/TestShaderNodes.java
new file mode 100644
index 0000000..b1683fc
--- /dev/null
+++ b/JmeTests/src/jme3test/material/TestShaderNodes.java
@@ -0,0 +1,43 @@
+package jme3test.material;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.material.Material;
+import com.jme3.material.Technique;
+import com.jme3.material.TechniqueDef;
+import com.jme3.math.ColorRGBA;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Box;
+import com.jme3.shader.Shader;
+import com.jme3.texture.Texture;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class TestShaderNodes extends SimpleApplication {
+
+ public static void main(String[] args) {
+ TestShaderNodes app = new TestShaderNodes();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ flyCam.setMoveSpeed(20);
+ Logger.getLogger("com.jme3").setLevel(Level.WARNING);
+ Box boxshape1 = new Box(1f, 1f, 1f);
+ Geometry cube_tex = new Geometry("A Textured Box", boxshape1);
+ Texture tex = assetManager.loadTexture("Interface/Logo/Monkey.jpg");
+
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/UnshadedNodes.j3md");
+ mat.selectTechnique(TechniqueDef.DEFAULT_TECHNIQUE_NAME, renderManager);
+ Technique t = mat.getActiveTechnique();
+
+ for (Shader.ShaderSource shaderSource : t.getDef().getShader(assetManager, renderer.getCaps(), t.getDynamicDefines()).getSources()) {
+ System.out.println(shaderSource.getSource());
+ }
+
+ mat.setColor("Color", ColorRGBA.Yellow);
+ mat.setTexture("ColorMap", tex);
+ cube_tex.setMaterial(mat);
+ rootNode.attachChild(cube_tex);
+ }
+}
diff --git a/JmeTests/src/jme3test/material/TestSimpleBumps.java b/JmeTests/src/jme3test/material/TestSimpleBumps.java
new file mode 100644
index 0000000..5be1adf
--- /dev/null
+++ b/JmeTests/src/jme3test/material/TestSimpleBumps.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.material;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.light.PointLight;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.shape.Quad;
+import com.jme3.scene.shape.Sphere;
+import com.jme3.util.TangentBinormalGenerator;
+
+// phong cutoff for light to normal angle > 90?
+public class TestSimpleBumps extends SimpleApplication {
+
+ float angle;
+ PointLight pl;
+ Spatial lightMdl;
+
+ public static void main(String[] args){
+ TestSimpleBumps app = new TestSimpleBumps();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ Quad quadMesh = new Quad(1, 1);
+
+ Geometry sphere = new Geometry("Rock Ball", quadMesh);
+ Material mat = assetManager.loadMaterial("Textures/BumpMapTest/SimpleBump.j3m");
+ sphere.setMaterial(mat);
+ TangentBinormalGenerator.generate(sphere);
+ rootNode.attachChild(sphere);
+
+ lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f));
+ lightMdl.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m"));
+ rootNode.attachChild(lightMdl);
+
+ pl = new PointLight();
+ pl.setColor(ColorRGBA.White);
+ pl.setPosition(new Vector3f(0f, 0f, 4f));
+ rootNode.addLight(pl);
+
+// DirectionalLight dl = new DirectionalLight();
+// dl.setDirection(new Vector3f(1, -1, -1).normalizeLocal());
+// dl.setColor(new ColorRGBA(0.22f, 0.15f, 0.1f, 1.0f));
+// rootNode.addLight(dl);
+ }
+
+ @Override
+ public void simpleUpdate(float tpf){
+ angle += tpf * 0.25f;
+ angle %= FastMath.TWO_PI;
+
+ pl.setPosition(new Vector3f(FastMath.cos(angle) * 4f, 0.5f, FastMath.sin(angle) * 4f));
+ lightMdl.setLocalTranslation(pl.getPosition());
+ }
+
+}
diff --git a/JmeTests/src/jme3test/material/TestTessellationShader.java b/JmeTests/src/jme3test/material/TestTessellationShader.java
new file mode 100644
index 0000000..dbf9381
--- /dev/null
+++ b/JmeTests/src/jme3test/material/TestTessellationShader.java
@@ -0,0 +1,68 @@
+package jme3test.material;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.AnalogListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.material.Material;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Mesh;
+import com.jme3.scene.VertexBuffer;
+import com.jme3.scene.shape.Quad;
+import com.jme3.util.BufferUtils;
+
+import java.util.concurrent.Callable;
+
+/**
+ * Created by michael on 28.02.15.
+ */
+public class TestTessellationShader extends SimpleApplication {
+ Material tessellationMaterial;
+ int tessFactor=5;
+ @Override
+ public void simpleInitApp() {
+ tessellationMaterial = new Material(getAssetManager(), "Materials/Tess/SimpleTess.j3md");
+ tessellationMaterial.setInt("TessellationFactor", tessFactor);
+ tessellationMaterial.getAdditionalRenderState().setWireframe(true);
+ Quad quad = new Quad(10, 10);
+ quad.clearBuffer(VertexBuffer.Type.Index);
+ quad.setBuffer(VertexBuffer.Type.Index, 4, BufferUtils.createIntBuffer(0, 1, 2, 3));
+ quad.setMode(Mesh.Mode.Patch);
+ quad.setPatchVertexCount(4);
+ Geometry geometry = new Geometry("tessTest", quad);
+ geometry.setMaterial(tessellationMaterial);
+ rootNode.attachChild(geometry);
+
+ getInputManager().addMapping("TessUp", new KeyTrigger(KeyInput.KEY_O));
+ getInputManager().addMapping("TessDo", new KeyTrigger(KeyInput.KEY_L));
+ getInputManager().addListener(new AnalogListener() {
+ @Override
+ public void onAnalog(String name, float value, float tpf) {
+ if(name.equals("TessUp")){
+ tessFactor++;
+ enqueue(new Callable() {
+ @Override
+ public Boolean call() throws Exception {
+ tessellationMaterial.setInt("TessellationFactor",tessFactor);
+ return true;
+ }
+ });
+ }
+ if(name.equals("TessDo")){
+ tessFactor--;
+ enqueue(new Callable() {
+ @Override
+ public Boolean call() throws Exception {
+ tessellationMaterial.setInt("TessellationFactor",tessFactor);
+ return true;
+ }
+ });
+ }
+ }
+ },"TessUp","TessDo");
+ }
+
+ public static void main(String[] args) {
+ new TestTessellationShader().start();
+ }
+}
diff --git a/JmeTests/src/jme3test/material/TestUnshadedModel.java b/JmeTests/src/jme3test/material/TestUnshadedModel.java
new file mode 100644
index 0000000..826ef44
--- /dev/null
+++ b/JmeTests/src/jme3test/material/TestUnshadedModel.java
@@ -0,0 +1,44 @@
+package jme3test.material;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.light.AmbientLight;
+import com.jme3.light.PointLight;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Sphere;
+import com.jme3.util.TangentBinormalGenerator;
+
+public class TestUnshadedModel extends SimpleApplication {
+
+ public static void main(String[] args){
+ TestUnshadedModel app = new TestUnshadedModel();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ Sphere sphMesh = new Sphere(32, 32, 1);
+ sphMesh.setTextureMode(Sphere.TextureMode.Projected);
+ sphMesh.updateGeometry(32, 32, 1, false, false);
+ TangentBinormalGenerator.generate(sphMesh);
+
+ Geometry sphere = new Geometry("Rock Ball", sphMesh);
+ Material mat = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m");
+ mat.setColor("Ambient", ColorRGBA.DarkGray);
+ mat.setColor("Diffuse", ColorRGBA.White);
+ mat.setBoolean("UseMaterialColors", true);
+ sphere.setMaterial(mat);
+ rootNode.attachChild(sphere);
+
+ PointLight pl = new PointLight();
+ pl.setColor(ColorRGBA.White);
+ pl.setPosition(new Vector3f(4f, 0f, 0f));
+ rootNode.addLight(pl);
+
+ AmbientLight al = new AmbientLight();
+ al.setColor(ColorRGBA.White);
+ rootNode.addLight(al);
+ }
+}
diff --git a/JmeTests/src/jme3test/math/TestHalfFloat.java b/JmeTests/src/jme3test/math/TestHalfFloat.java
new file mode 100644
index 0000000..1bd9361
--- /dev/null
+++ b/JmeTests/src/jme3test/math/TestHalfFloat.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.math;
+
+import com.jme3.math.FastMath;
+import java.util.Scanner;
+
+public class TestHalfFloat {
+ public static void main(String[] args){
+ Scanner scan = new Scanner(System.in);
+ while (true){
+ System.out.println("Enter float to convert or 'x' to exit: ");
+ String s = scan.nextLine();
+ if (s.equals("x"))
+ break;
+
+ float flt = Float.valueOf(s);
+ short half = FastMath.convertFloatToHalf(flt);
+ float flt2 = FastMath.convertHalfToFloat(half);
+
+ System.out.println("Input float: "+flt);
+ System.out.println("Result float: "+flt2);
+ }
+ }
+}
diff --git a/JmeTests/src/jme3test/model/TestGltfLoading.java b/JmeTests/src/jme3test/model/TestGltfLoading.java
new file mode 100644
index 0000000..3373638
--- /dev/null
+++ b/JmeTests/src/jme3test/model/TestGltfLoading.java
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.model;
+
+import com.jme3.animation.*;
+import com.jme3.app.ChaseCameraAppState;
+import com.jme3.app.SimpleApplication;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.math.*;
+import com.jme3.renderer.Limits;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.control.Control;
+import com.jme3.scene.debug.custom.SkeletonDebugAppState;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class TestGltfLoading extends SimpleApplication {
+
+ Node autoRotate = new Node("autoRotate");
+ List assets = new ArrayList<>();
+ Node probeNode;
+ float time = 0;
+ int assetIndex = 0;
+ boolean useAutoRotate = false;
+ private final static String indentString = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
+ int duration = 2;
+ boolean playAnim = true;
+
+ public static void main(String[] args) {
+ TestGltfLoading app = new TestGltfLoading();
+ app.start();
+ }
+
+ /*
+ WARNING this test case can't wok without the assets, and considering their size, they are not pushed into the repo
+ you can find them here :
+ https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0
+ https://sketchfab.com/features/gltf
+ You have to copy them in Model/gltf folder in the test-data project.
+ */
+ public void simpleInitApp() {
+
+ SkeletonDebugAppState skeletonDebugAppState = new SkeletonDebugAppState();
+ getStateManager().attach(skeletonDebugAppState);
+
+ // cam.setLocation(new Vector3f(4.0339394f, 2.645184f, 6.4627485f));
+ // cam.setRotation(new Quaternion(-0.013950467f, 0.98604023f, -0.119502485f, -0.11510504f));
+ cam.setFrustumPerspective(45f, (float) cam.getWidth() / cam.getHeight(), 0.1f, 100f);
+ renderer.setDefaultAnisotropicFilter(Math.min(renderer.getLimits().get(Limits.TextureAnisotropy), 8));
+ setPauseOnLostFocus(false);
+
+ flyCam.setMoveSpeed(5);
+ flyCam.setDragToRotate(true);
+ flyCam.setEnabled(false);
+ viewPort.setBackgroundColor(new ColorRGBA().setAsSrgb(0.2f, 0.2f, 0.2f, 1.0f));
+ rootNode.attachChild(autoRotate);
+ probeNode = (Node) assetManager.loadModel("Scenes/defaultProbe.j3o");
+ autoRotate.attachChild(probeNode);
+
+// DirectionalLight dl = new DirectionalLight();
+// dl.setDirection(new Vector3f(-1f, -1.0f, -1f).normalizeLocal());
+// dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f));
+// rootNode.addLight(dl);
+
+// DirectionalLight dl2 = new DirectionalLight();
+// dl2.setDirection(new Vector3f(1f, 1.0f, 1f).normalizeLocal());
+// dl2.setColor(new ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f));
+// rootNode.addLight(dl2);
+
+// PointLight pl = new PointLight(new Vector3f(5.0f, 5.0f, 5.0f), ColorRGBA.White, 30);
+// rootNode.addLight(pl);
+// PointLight pl1 = new PointLight(new Vector3f(-5.0f, -5.0f, -5.0f), ColorRGBA.White.mult(0.5f), 50);
+// rootNode.addLight(pl1);
+
+// loadModel("Models/gltf/box/box.gltf", Vector3f.ZERO, 1);
+// loadModel("Models/gltf/duck/Duck.gltf", new Vector3f(0, -1, 0), 1);
+// loadModel("Models/gltf/damagedHelmet/damagedHelmet.gltf", Vector3f.ZERO, 1);
+// loadModel("Models/gltf/hornet/scene.gltf", new Vector3f(0, -0.5f, 0), 0.4f);
+//// loadModel("Models/gltf/adamHead/adamHead.gltf", Vector3f.ZERO, 0.6f);
+ // loadModel("Models/gltf/busterDrone/busterDrone.gltf", new Vector3f(0, 0f, 0), 0.8f);
+// loadModel("Models/gltf/animatedCube/AnimatedCube.gltf", Vector3f.ZERO, 0.5f);
+//
+// //loadModel("Models/gltf/BoxAnimated/BoxAnimated.gltf", new Vector3f(0, 0f, 0), 0.8f);
+//
+// loadModel("Models/gltf/RiggedFigure/RiggedSimple.gltf", new Vector3f(0, -0.3f, 0), 0.2f);
+ //loadModel("Models/gltf/RiggedFigure/RiggedFigure.gltf", new Vector3f(0, -1f, 0), 1f);
+ //loadModel("Models/gltf/CesiumMan/CesiumMan.gltf", new Vector3f(0, -1, 0), 1f);
+ //loadModel("Models/gltf/BrainStem/BrainStem.gltf", new Vector3f(0, -1, 0), 1f);
+ //loadModel("Models/gltf/Jaime/Jaime.gltf", new Vector3f(0, -1, 0), 1f);
+// loadModel("Models/gltf/GiantWorm/GiantWorm.gltf", new Vector3f(0, -1, 0), 1f);
+// //loadModel("Models/gltf/RiggedFigure/WalkingLady.gltf", new Vector3f(0, -0.f, 0), 1f);
+// loadModel("Models/gltf/Monster/Monster.gltf", Vector3f.ZERO, 0.03f);
+
+// loadModel("Models/gltf/corset/Corset.gltf", new Vector3f(0, -1, 0), 20f);
+ loadModel("Models/gltf/boxInter/BoxInterleaved.gltf", new Vector3f(0, 0, 0), 1f);
+
+
+ probeNode.attachChild(assets.get(0));
+
+ ChaseCameraAppState chaseCam = new ChaseCameraAppState();
+ chaseCam.setTarget(probeNode);
+ getStateManager().attach(chaseCam);
+ chaseCam.setInvertHorizontalAxis(true);
+ chaseCam.setInvertVerticalAxis(true);
+ chaseCam.setZoomSpeed(0.5f);
+ chaseCam.setMinVerticalRotation(-FastMath.HALF_PI);
+ chaseCam.setRotationSpeed(3);
+ chaseCam.setDefaultDistance(3);
+ chaseCam.setDefaultVerticalRotation(0.3f);
+
+ inputManager.addMapping("autorotate", new KeyTrigger(KeyInput.KEY_SPACE));
+ inputManager.addListener(new ActionListener() {
+ @Override
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if (isPressed) {
+ useAutoRotate = !useAutoRotate;
+ }
+ }
+ }, "autorotate");
+
+ inputManager.addMapping("toggleAnim", new KeyTrigger(KeyInput.KEY_RETURN));
+ inputManager.addListener(new ActionListener() {
+ @Override
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if (isPressed) {
+ playAnim = !playAnim;
+ if (playAnim) {
+ playFirstAnim(rootNode);
+ } else {
+ stopAnim(rootNode);
+ }
+ }
+ }
+ }, "toggleAnim");
+
+ dumpScene(rootNode, 0);
+ }
+
+ private T findControl(Spatial s, Class controlClass) {
+ T ctrl = s.getControl(controlClass);
+ if (ctrl != null) {
+ return ctrl;
+ }
+ if (s instanceof Node) {
+ Node n = (Node) s;
+ for (Spatial spatial : n.getChildren()) {
+ ctrl = findControl(spatial, controlClass);
+ if (ctrl != null) {
+ return ctrl;
+ }
+ }
+ }
+ return null;
+ }
+
+ private void loadModel(String path, Vector3f offset, float scale) {
+ Spatial s = assetManager.loadModel(path);
+ s.scale(scale);
+ s.move(offset);
+ assets.add(s);
+ if (playAnim) {
+ playFirstAnim(s);
+ }
+
+ SkeletonControl ctrl = findControl(s, SkeletonControl.class);
+
+// //ctrl.getSpatial().removeControl(ctrl);
+ if (ctrl == null) {
+ return;
+ }
+ ctrl.setHardwareSkinningPreferred(false);
+ getStateManager().getState(SkeletonDebugAppState.class).addSkeleton(ctrl, true);
+// AnimControl aCtrl = findControl(s, AnimControl.class);
+// //ctrl.getSpatial().removeControl(ctrl);
+// if (aCtrl == null) {
+// return;
+// }
+// if (aCtrl.getSkeleton() != null) {
+// getStateManager().getState(SkeletonDebugAppState.class).addSkeleton(aCtrl.getSkeleton(), aCtrl.getSpatial(), true);
+// }
+
+ }
+
+ private void playFirstAnim(Spatial s) {
+
+ AnimControl control = s.getControl(AnimControl.class);
+ if (control != null) {
+// if (control.getAnimationNames().size() > 0) {
+// control.createChannel().setAnim(control.getAnimationNames().iterator().next());
+// }
+ for (String name : control.getAnimationNames()) {
+ control.createChannel().setAnim(name);
+ }
+
+ }
+ if (s instanceof Node) {
+ Node n = (Node) s;
+ for (Spatial spatial : n.getChildren()) {
+ playFirstAnim(spatial);
+ }
+ }
+ }
+
+ private void stopAnim(Spatial s) {
+
+ AnimControl control = s.getControl(AnimControl.class);
+ if (control != null) {
+ for (int i = 0; i < control.getNumChannels(); i++) {
+ AnimChannel ch = control.getChannel(i);
+ ch.reset(true);
+ }
+ control.clearChannels();
+ if (control.getSkeleton() != null) {
+ control.getSkeleton().reset();
+ }
+
+ }
+ if (s instanceof Node) {
+ Node n = (Node) s;
+ for (Spatial spatial : n.getChildren()) {
+ stopAnim(spatial);
+ }
+ }
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+
+ if (!useAutoRotate) {
+ return;
+ }
+ time += tpf;
+ autoRotate.rotate(0, tpf * 0.5f, 0);
+ if (time > duration) {
+ assets.get(assetIndex).removeFromParent();
+ assetIndex = (assetIndex + 1) % assets.size();
+ if (assetIndex == 0) {
+ duration = 10;
+ }
+ probeNode.attachChild(assets.get(assetIndex));
+ time = 0;
+ }
+ }
+
+ private void dumpScene(Spatial s, int indent) {
+ System.err.println(indentString.substring(0, indent) + s.getName() + " (" + s.getClass().getSimpleName() + ") / " +
+ s.getLocalTransform().getTranslation().toString() + ", " +
+ s.getLocalTransform().getRotation().toString() + ", " +
+ s.getLocalTransform().getScale().toString());
+ if (s instanceof Node) {
+ Node n = (Node) s;
+ for (Spatial spatial : n.getChildren()) {
+ dumpScene(spatial, indent + 1);
+ }
+ }
+ }
+}
diff --git a/JmeTests/src/jme3test/model/TestGltfLoading2.java b/JmeTests/src/jme3test/model/TestGltfLoading2.java
new file mode 100644
index 0000000..7988da4
--- /dev/null
+++ b/JmeTests/src/jme3test/model/TestGltfLoading2.java
@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.model;
+
+import com.jme3.animation.*;
+import com.jme3.app.ChaseCameraAppState;
+import com.jme3.app.SimpleApplication;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.math.*;
+import com.jme3.renderer.Limits;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.control.Control;
+import com.jme3.scene.debug.custom.SkeletonDebugAppState;
+import com.jme3.scene.plugins.gltf.GltfModelKey;
+
+import java.util.*;
+
+public class TestGltfLoading2 extends SimpleApplication {
+
+ Node autoRotate = new Node("autoRotate");
+ List assets = new ArrayList<>();
+ Node probeNode;
+ float time = 0;
+ int assetIndex = 0;
+ boolean useAutoRotate = false;
+ private final static String indentString = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
+ int duration = 2;
+ boolean playAnim = true;
+
+ public static void main(String[] args) {
+ TestGltfLoading2 app = new TestGltfLoading2();
+ app.start();
+ }
+
+ /*
+ WARNING this test case can't wok without the assets, and considering their size, they are not pushed into the repo
+ you can find them here :
+ https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0
+ https://sketchfab.com/features/gltf
+ You have to copy them in Model/gltf folder in the test-data project.
+ */
+ public void simpleInitApp() {
+
+ SkeletonDebugAppState skeletonDebugAppState = new SkeletonDebugAppState();
+ getStateManager().attach(skeletonDebugAppState);
+
+ // cam.setLocation(new Vector3f(4.0339394f, 2.645184f, 6.4627485f));
+ // cam.setRotation(new Quaternion(-0.013950467f, 0.98604023f, -0.119502485f, -0.11510504f));
+ cam.setFrustumPerspective(45f, (float) cam.getWidth() / cam.getHeight(), 0.1f, 100f);
+ renderer.setDefaultAnisotropicFilter(Math.min(renderer.getLimits().get(Limits.TextureAnisotropy), 8));
+ setPauseOnLostFocus(false);
+
+ flyCam.setMoveSpeed(5);
+ flyCam.setDragToRotate(true);
+ flyCam.setEnabled(false);
+ viewPort.setBackgroundColor(new ColorRGBA().setAsSrgb(0.2f, 0.2f, 0.2f, 1.0f));
+ rootNode.attachChild(autoRotate);
+ probeNode = (Node) assetManager.loadModel("Scenes/defaultProbe.j3o");
+ autoRotate.attachChild(probeNode);
+
+// DirectionalLight dl = new DirectionalLight();
+// dl.setDirection(new Vector3f(-1f, -1.0f, -1f).normalizeLocal());
+// dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f));
+// rootNode.addLight(dl);
+
+// DirectionalLight dl2 = new DirectionalLight();
+// dl2.setDirection(new Vector3f(1f, 1.0f, 1f).normalizeLocal());
+// dl2.setColor(new ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f));
+// rootNode.addLight(dl2);
+
+// PointLight pl = new PointLight(new Vector3f(5.0f, 5.0f, 5.0f), ColorRGBA.White, 30);
+// rootNode.addLight(pl);
+// PointLight pl1 = new PointLight(new Vector3f(-5.0f, -5.0f, -5.0f), ColorRGBA.White.mult(0.5f), 50);
+// rootNode.addLight(pl1);
+ //loadModel("Models/gltf/buffalo/scene.gltf", new Vector3f(0, -1, 0), 0.1f);
+ //loadModel("Models/gltf/war/scene.gltf", new Vector3f(0, -1, 0), 0.1f);
+ loadModel("Models/gltf/ganjaarl/scene.gltf", new Vector3f(0, -1, 0), 0.01f);
+ //loadModel("Models/gltf/hero/scene.gltf", new Vector3f(0, -1, 0), 0.1f);
+ //loadModel("Models/gltf/mercy/scene.gltf", new Vector3f(0, -1, 0), 0.01f);
+ //loadModel("Models/gltf/crab/scene.gltf", Vector3f.ZERO, 1);
+ //loadModel("Models/gltf/manta/scene.gltf", Vector3f.ZERO, 0.2f);
+// loadModel("Models/gltf/bone/scene.gltf", Vector3f.ZERO, 0.1f);
+// loadModel("Models/gltf/box/box.gltf", Vector3f.ZERO, 1);
+// loadModel("Models/gltf/duck/Duck.gltf", new Vector3f(0, -1, 0), 1);
+// loadModel("Models/gltf/damagedHelmet/damagedHelmet.gltf", Vector3f.ZERO, 1);
+// loadModel("Models/gltf/hornet/scene.gltf", new Vector3f(0, -0.5f, 0), 0.4f);
+//// loadModel("Models/gltf/adamHead/adamHead.gltf", Vector3f.ZERO, 0.6f);
+ //loadModel("Models/gltf/busterDrone/busterDrone.gltf", new Vector3f(0, 0f, 0), 0.8f);
+// loadModel("Models/gltf/animatedCube/AnimatedCube.gltf", Vector3f.ZERO, 0.5f);
+//
+// //loadModel("Models/gltf/BoxAnimated/BoxAnimated.gltf", new Vector3f(0, 0f, 0), 0.8f);
+//
+ //loadModel("Models/gltf/RiggedFigure/RiggedSimple.gltf", new Vector3f(0, -0.3f, 0), 0.2f);
+ //loadModel("Models/gltf/RiggedFigure/RiggedFigure.gltf", new Vector3f(0, -1f, 0), 1f);
+ //loadModel("Models/gltf/CesiumMan/CesiumMan.gltf", new Vector3f(0, -1, 0), 1f);
+ //loadModel("Models/gltf/BrainStem/BrainStem.gltf", new Vector3f(0, -1, 0), 1f);
+ //loadModel("Models/gltf/Jaime/Jaime.gltf", new Vector3f(0, -1, 0), 1f);
+ //loadModel("Models/gltf/GiantWorm/GiantWorm.gltf", new Vector3f(0, -1, 0), 1f);
+ //loadModel("Models/gltf/RiggedFigure/WalkingLady.gltf", new Vector3f(0, -0.f, 0), 1f);
+ //loadModel("Models/gltf/Monster/Monster.gltf", Vector3f.ZERO, 0.03f);
+
+// loadModel("Models/gltf/corset/Corset.gltf", new Vector3f(0, -1, 0), 20f);
+ // loadModel("Models/gltf/boxInter/BoxInterleaved.gltf", new Vector3f(0, 0, 0), 1f);
+
+
+ probeNode.attachChild(assets.get(0));
+
+ ChaseCameraAppState chaseCam = new ChaseCameraAppState();
+ chaseCam.setTarget(probeNode);
+ getStateManager().attach(chaseCam);
+ chaseCam.setInvertHorizontalAxis(true);
+ chaseCam.setInvertVerticalAxis(true);
+ chaseCam.setZoomSpeed(0.5f);
+ chaseCam.setMinVerticalRotation(-FastMath.HALF_PI);
+ chaseCam.setRotationSpeed(3);
+ chaseCam.setDefaultDistance(3);
+ chaseCam.setDefaultVerticalRotation(0.3f);
+
+ inputManager.addMapping("autorotate", new KeyTrigger(KeyInput.KEY_SPACE));
+ inputManager.addListener(new ActionListener() {
+ @Override
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if (isPressed) {
+ useAutoRotate = !useAutoRotate;
+ }
+ }
+ }, "autorotate");
+
+ inputManager.addMapping("toggleAnim", new KeyTrigger(KeyInput.KEY_RETURN));
+
+ inputManager.addListener(new ActionListener() {
+ @Override
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if (isPressed) {
+ playAnim = !playAnim;
+ if (playAnim) {
+ playFirstAnim(rootNode);
+ } else {
+ stopAnim(rootNode);
+ }
+ }
+ }
+ }, "toggleAnim");
+ inputManager.addMapping("nextAnim", new KeyTrigger(KeyInput.KEY_RIGHT));
+ inputManager.addListener(new ActionListener() {
+ @Override
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if (isPressed && animControl != null) {
+ AnimChannel c = animControl.getChannel(0);
+ if (c == null) {
+ c = animControl.createChannel();
+ }
+ String anim = anims.poll();
+ anims.add(anim);
+ c.setAnim(anim);
+ }
+ }
+ }, "nextAnim");
+
+ dumpScene(rootNode, 0);
+ }
+
+ private T findControl(Spatial s, Class controlClass) {
+ T ctrl = s.getControl(controlClass);
+ if (ctrl != null) {
+ return ctrl;
+ }
+ if (s instanceof Node) {
+ Node n = (Node) s;
+ for (Spatial spatial : n.getChildren()) {
+ ctrl = findControl(spatial, controlClass);
+ if (ctrl != null) {
+ return ctrl;
+ }
+ }
+ }
+ return null;
+ }
+
+ private void loadModel(String path, Vector3f offset, float scale) {
+ GltfModelKey k = new GltfModelKey(path);
+ //k.setKeepSkeletonPose(true);
+ Spatial s = assetManager.loadModel(k);
+ s.scale(scale);
+ s.move(offset);
+ assets.add(s);
+ if (playAnim) {
+ playFirstAnim(s);
+ }
+
+ SkeletonControl ctrl = findControl(s, SkeletonControl.class);
+
+ // ctrl.getSpatial().removeControl(ctrl);
+ if (ctrl == null) {
+ return;
+ }
+ //System.err.println(ctrl.getSkeleton().toString());
+ //ctrl.setHardwareSkinningPreferred(false);
+ // getStateManager().getState(SkeletonDebugAppState.class).addSkeleton(ctrl, true);
+// AnimControl aCtrl = findControl(s, AnimControl.class);
+// //ctrl.getSpatial().removeControl(ctrl);
+// if (aCtrl == null) {
+// return;
+// }
+// if (aCtrl.getSkeleton() != null) {
+// getStateManager().getState(SkeletonDebugAppState.class).addSkeleton(aCtrl.getSkeleton(), aCtrl.getSpatial(), true);
+// }
+
+ }
+
+ Queue anims = new LinkedList<>();
+ AnimControl animControl;
+
+ private void playFirstAnim(Spatial s) {
+
+ AnimControl control = s.getControl(AnimControl.class);
+ if (control != null) {
+ anims.clear();
+ for (String name : control.getAnimationNames()) {
+ anims.add(name);
+ }
+ if (anims.isEmpty()) {
+ return;
+ }
+ String anim = anims.poll();
+ anims.add(anim);
+ control.createChannel().setAnim(anim);
+ animControl = control;
+ }
+ if (s instanceof Node) {
+ Node n = (Node) s;
+ for (Spatial spatial : n.getChildren()) {
+ playFirstAnim(spatial);
+ }
+ }
+ }
+
+ private void stopAnim(Spatial s) {
+
+ AnimControl control = s.getControl(AnimControl.class);
+ if (control != null) {
+ for (int i = 0; i < control.getNumChannels(); i++) {
+ AnimChannel ch = control.getChannel(i);
+ ch.reset(true);
+ }
+ control.clearChannels();
+ }
+ if (s instanceof Node) {
+ Node n = (Node) s;
+ for (Spatial spatial : n.getChildren()) {
+ stopAnim(spatial);
+ }
+ }
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+
+ if (!useAutoRotate) {
+ return;
+ }
+ time += tpf;
+ autoRotate.rotate(0, tpf * 0.5f, 0);
+ if (time > duration) {
+ assets.get(assetIndex).removeFromParent();
+ assetIndex = (assetIndex + 1) % assets.size();
+ if (assetIndex == 0) {
+ duration = 10;
+ }
+ probeNode.attachChild(assets.get(assetIndex));
+ time = 0;
+ }
+ }
+
+ private void dumpScene(Spatial s, int indent) {
+ System.err.println(indentString.substring(0, indent) + s.getName() + " (" + s.getClass().getSimpleName() + ") / " +
+ s.getLocalTransform().getTranslation().toString() + ", " +
+ s.getLocalTransform().getRotation().toString() + ", " +
+ s.getLocalTransform().getScale().toString());
+ if (s instanceof Node) {
+ Node n = (Node) s;
+ for (Spatial spatial : n.getChildren()) {
+ dumpScene(spatial, indent + 1);
+ }
+ }
+ }
+}
diff --git a/JmeTests/src/jme3test/model/TestHoverTank.java b/JmeTests/src/jme3test/model/TestHoverTank.java
new file mode 100644
index 0000000..648f739
--- /dev/null
+++ b/JmeTests/src/jme3test/model/TestHoverTank.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.model;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.input.ChaseCamera;
+import com.jme3.light.DirectionalLight;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Vector3f;
+import com.jme3.post.FilterPostProcessor;
+import com.jme3.post.filters.BloomFilter;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.control.LodControl;
+import jme3test.post.BloomUI;
+
+/**
+ *
+ * @author Nehon
+ */
+public class TestHoverTank extends SimpleApplication {
+
+ public static void main(String[] args) {
+ TestHoverTank app = new TestHoverTank();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ Node tank = (Node) assetManager.loadModel("Models/HoverTank/Tank2.mesh.xml");
+
+ flyCam.setEnabled(false);
+ ChaseCamera chaseCam = new ChaseCamera(cam, tank, inputManager);
+ chaseCam.setSmoothMotion(true);
+ chaseCam.setMaxDistance(100000);
+ chaseCam.setMinVerticalRotation(-FastMath.PI / 2);
+ viewPort.setBackgroundColor(ColorRGBA.DarkGray);
+
+ Geometry tankGeom = (Geometry) tank.getChild(0);
+ LodControl control = new LodControl();
+ tankGeom.addControl(control);
+ rootNode.attachChild(tank);
+
+ Vector3f lightDir = new Vector3f(-0.8719428f, -0.46824604f, 0.14304268f);
+ DirectionalLight dl = new DirectionalLight();
+ dl.setColor(new ColorRGBA(1.0f, 0.92f, 0.75f, 1f));
+ dl.setDirection(lightDir);
+
+ Vector3f lightDir2 = new Vector3f(0.70518064f, 0.5902297f, -0.39287305f);
+ DirectionalLight dl2 = new DirectionalLight();
+ dl2.setColor(new ColorRGBA(0.7f, 0.85f, 1.0f, 1f));
+ dl2.setDirection(lightDir2);
+
+ rootNode.addLight(dl);
+ rootNode.addLight(dl2);
+ rootNode.attachChild(tank);
+
+ FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
+ BloomFilter bf = new BloomFilter(BloomFilter.GlowMode.Objects);
+ bf.setBloomIntensity(2.0f);
+ bf.setExposurePower(1.3f);
+ fpp.addFilter(bf);
+ BloomUI bui = new BloomUI(inputManager, bf);
+ viewPort.addProcessor(fpp);
+ }
+}
diff --git a/JmeTests/src/jme3test/model/TestMonkeyHead.java b/JmeTests/src/jme3test/model/TestMonkeyHead.java
new file mode 100644
index 0000000..c75e221
--- /dev/null
+++ b/JmeTests/src/jme3test/model/TestMonkeyHead.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.model;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.PointLight;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.shape.Sphere;
+
+public class TestMonkeyHead extends SimpleApplication {
+
+ float angle;
+ PointLight pl;
+ Spatial lightMdl;
+
+ public static void main(String[] args){
+ TestMonkeyHead app = new TestMonkeyHead();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ viewPort.setBackgroundColor(ColorRGBA.DarkGray);
+
+ Spatial bumpy = (Spatial) assetManager.loadModel("Models/MonkeyHead/MonkeyHead.mesh.xml");
+ rootNode.attachChild(bumpy);
+
+ lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f));
+ lightMdl.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m"));
+ rootNode.attachChild(lightMdl);
+
+ // flourescent main light
+ pl = new PointLight();
+ pl.setColor(new ColorRGBA(0.88f, 0.92f, 0.95f, 1.0f));
+ rootNode.addLight(pl);
+
+ // sunset light
+ DirectionalLight dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(-0.1f,-0.7f,1).normalizeLocal());
+ dl.setColor(new ColorRGBA(0.44f, 0.30f, 0.20f, 1.0f));
+ rootNode.addLight(dl);
+
+ // skylight
+ dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(-0.6f,-1,-0.6f).normalizeLocal());
+ dl.setColor(new ColorRGBA(0.10f, 0.22f, 0.44f, 1.0f));
+ rootNode.addLight(dl);
+
+ // white ambient light
+ dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(1, -0.5f,-0.1f).normalizeLocal());
+ dl.setColor(new ColorRGBA(0.50f, 0.40f, 0.50f, 1.0f));
+ rootNode.addLight(dl);
+ }
+
+ @Override
+ public void simpleUpdate(float tpf){
+ angle += tpf * 0.25f;
+ angle %= FastMath.TWO_PI;
+
+ pl.setPosition(new Vector3f(FastMath.cos(angle) * 6f, 3f, FastMath.sin(angle) * 6f));
+ lightMdl.setLocalTranslation(pl.getPosition());
+ }
+
+}
diff --git a/JmeTests/src/jme3test/model/TestObjLoading.java b/JmeTests/src/jme3test/model/TestObjLoading.java
new file mode 100644
index 0000000..2546fdd
--- /dev/null
+++ b/JmeTests/src/jme3test/model/TestObjLoading.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.model;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.material.Material;
+import com.jme3.scene.Geometry;
+
+/**
+ * Tests OBJ format loading
+ */
+public class TestObjLoading extends SimpleApplication {
+
+ public static void main(String[] args){
+ TestObjLoading app = new TestObjLoading();
+ app.start();
+ }
+
+ public void simpleInitApp() {
+ // create the geometry and attach it
+ Geometry teaGeom = (Geometry) assetManager.loadModel("Models/Teapot/Teapot.obj");
+
+ // show normals as material
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/ShowNormals.j3md");
+ teaGeom.setMaterial(mat);
+
+ rootNode.attachChild(teaGeom);
+ }
+}
diff --git a/JmeTests/src/jme3test/model/TestOgreLoading.java b/JmeTests/src/jme3test/model/TestOgreLoading.java
new file mode 100644
index 0000000..47001ea
--- /dev/null
+++ b/JmeTests/src/jme3test/model/TestOgreLoading.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.model;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.PointLight;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.shape.Sphere;
+
+public class TestOgreLoading extends SimpleApplication {
+
+ float angle1;
+ float angle2;
+ PointLight pl;
+ PointLight p2;
+ Spatial lightMdl;
+ Spatial lightMd2;
+
+ public static void main(String[] args) {
+ TestOgreLoading app = new TestOgreLoading();
+ app.start();
+ }
+
+ public void simpleInitApp() {
+// PointLight pl = new PointLight();
+// pl.setPosition(new Vector3f(10, 10, -10));
+// rootNode.addLight(pl);
+ flyCam.setMoveSpeed(10f);
+
+ // sunset light
+ DirectionalLight dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(-0.1f, -0.7f, 1).normalizeLocal());
+ dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f));
+ rootNode.addLight(dl);
+
+
+ lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f));
+ lightMdl.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m"));
+ rootNode.attachChild(lightMdl);
+
+ lightMd2 = new Geometry("Light", new Sphere(10, 10, 0.1f));
+ lightMd2.setMaterial(assetManager.loadMaterial("Common/Materials/WhiteColor.j3m"));
+ rootNode.attachChild(lightMd2);
+
+
+ pl = new PointLight();
+ pl.setColor(new ColorRGBA(1, 0.9f, 0.9f, 0));
+ pl.setPosition(new Vector3f(0f, 0f, 4f));
+ rootNode.addLight(pl);
+
+ p2 = new PointLight();
+ p2.setColor(new ColorRGBA(0.9f, 1, 0.9f, 0));
+ p2.setPosition(new Vector3f(0f, 0f, 3f));
+ rootNode.addLight(p2);
+
+
+ // create the geometry and attach it
+ Spatial elephant = (Spatial) assetManager.loadModel("Models/Elephant/Elephant.mesh.xml");
+ float scale = 0.05f;
+ elephant.scale(scale, scale, scale);
+ rootNode.attachChild(elephant);
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ angle1 += tpf * 0.25f;
+ angle1 %= FastMath.TWO_PI;
+
+ angle2 += tpf * 0.50f;
+ angle2 %= FastMath.TWO_PI;
+
+ pl.setPosition(new Vector3f(FastMath.cos(angle1) * 4f, 0.5f, FastMath.sin(angle1) * 4f));
+ p2.setPosition(new Vector3f(FastMath.cos(angle2) * 4f, 0.5f, FastMath.sin(angle2) * 4f));
+ lightMdl.setLocalTranslation(pl.getPosition());
+ lightMd2.setLocalTranslation(p2.getPosition());
+ }
+}
diff --git a/JmeTests/src/jme3test/model/anim/TestAnimBlendBug.java b/JmeTests/src/jme3test/model/anim/TestAnimBlendBug.java
new file mode 100644
index 0000000..b57fc83
--- /dev/null
+++ b/JmeTests/src/jme3test/model/anim/TestAnimBlendBug.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.model.anim;
+
+import com.jme3.animation.AnimChannel;
+import com.jme3.animation.AnimControl;
+import com.jme3.app.SimpleApplication;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.light.DirectionalLight;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Node;
+import com.jme3.scene.debug.SkeletonDebugger;
+
+public class TestAnimBlendBug extends SimpleApplication implements ActionListener {
+
+// private AnimControl control;
+ private AnimChannel channel1, channel2;
+ private String[] animNames;
+
+ private float blendTime = 0.5f;
+ private float lockAfterBlending = blendTime + 0.25f;
+ private float blendingAnimationLock;
+
+ public static void main(String[] args) {
+ TestAnimBlendBug app = new TestAnimBlendBug();
+ app.start();
+ }
+
+ public void onAction(String name, boolean value, float tpf) {
+ if (name.equals("One") && value){
+ channel1.setAnim(animNames[4], blendTime);
+ channel2.setAnim(animNames[4], 0);
+ channel1.setSpeed(0.25f);
+ channel2.setSpeed(0.25f);
+ blendingAnimationLock = lockAfterBlending;
+ }
+ }
+
+ public void onPreUpdate(float tpf) {
+ }
+
+ public void onPostUpdate(float tpf) {
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ // Is there currently a blending underway?
+ if (blendingAnimationLock > 0f) {
+ blendingAnimationLock -= tpf;
+ }
+ }
+
+ @Override
+ public void simpleInitApp() {
+ inputManager.addMapping("One", new KeyTrigger(KeyInput.KEY_1));
+ inputManager.addListener(this, "One");
+
+ flyCam.setMoveSpeed(100f);
+ cam.setLocation( new Vector3f( 0f, 150f, -325f ) );
+ cam.lookAt( new Vector3f( 0f, 100f, 0f ), Vector3f.UNIT_Y );
+
+ DirectionalLight dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(-0.1f, -0.7f, 1).normalizeLocal());
+ dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f));
+ rootNode.addLight(dl);
+
+ Node model1 = (Node) assetManager.loadModel("Models/Ninja/Ninja.mesh.xml");
+ Node model2 = (Node) assetManager.loadModel("Models/Ninja/Ninja.mesh.xml");
+// Node model2 = model1.clone();
+
+ model1.setLocalTranslation(-60, 0, 0);
+ model2.setLocalTranslation(60, 0, 0);
+
+ AnimControl control1 = model1.getControl(AnimControl.class);
+ animNames = control1.getAnimationNames().toArray(new String[0]);
+ channel1 = control1.createChannel();
+
+ AnimControl control2 = model2.getControl(AnimControl.class);
+ channel2 = control2.createChannel();
+
+ SkeletonDebugger skeletonDebug = new SkeletonDebugger("skeleton1", control1.getSkeleton());
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat.getAdditionalRenderState().setWireframe(true);
+ mat.setColor("Color", ColorRGBA.Red);
+ mat.setFloat("PointSize", 7f);
+ mat.getAdditionalRenderState().setDepthTest(false);
+ skeletonDebug.setMaterial(mat);
+ model1.attachChild(skeletonDebug);
+
+ skeletonDebug = new SkeletonDebugger("skeleton2", control2.getSkeleton());
+ skeletonDebug.setMaterial(mat);
+ model2.attachChild(skeletonDebug);
+
+ rootNode.attachChild(model1);
+ rootNode.attachChild(model2);
+ }
+
+}
diff --git a/JmeTests/src/jme3test/model/anim/TestAnimationFactory.java b/JmeTests/src/jme3test/model/anim/TestAnimationFactory.java
new file mode 100644
index 0000000..49c8878
--- /dev/null
+++ b/JmeTests/src/jme3test/model/anim/TestAnimationFactory.java
@@ -0,0 +1,85 @@
+package jme3test.model.anim;
+
+import com.jme3.animation.AnimControl;
+import com.jme3.animation.AnimationFactory;
+import com.jme3.app.SimpleApplication;
+import com.jme3.light.AmbientLight;
+import com.jme3.light.DirectionalLight;
+import com.jme3.math.FastMath;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.shape.Box;
+import com.jme3.util.TangentBinormalGenerator;
+
+public class TestAnimationFactory extends SimpleApplication {
+
+ public static void main(String[] args) {
+ TestSpatialAnim app = new TestSpatialAnim();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+
+ AmbientLight al = new AmbientLight();
+ rootNode.addLight(al);
+
+ DirectionalLight dl = new DirectionalLight();
+ dl.setDirection(Vector3f.UNIT_XYZ.negate());
+ rootNode.addLight(dl);
+
+ // Create model
+ Box box = new Box(1, 1, 1);
+ Geometry geom = new Geometry("box", box);
+ geom.setMaterial(assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall.j3m"));
+ Node model = new Node("model");
+ model.attachChild(geom);
+
+ Box child = new Box(0.5f, 0.5f, 0.5f);
+ Geometry childGeom = new Geometry("box", child);
+ childGeom.setMaterial(assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall.j3m"));
+ Node childModel = new Node("childmodel");
+ childModel.setLocalTranslation(2, 2, 2);
+ childModel.attachChild(childGeom);
+ model.attachChild(childModel);
+ TangentBinormalGenerator.generate(model);
+
+ //creating quite complex animation witht the AnimationHelper
+ // animation of 6 seconds named "anim" and with 25 frames per second
+ AnimationFactory animationFactory = new AnimationFactory(6, "anim", 25);
+
+ //creating a translation keyFrame at time = 3 with a translation on the x axis of 5 WU
+ animationFactory.addTimeTranslation(3, new Vector3f(5, 0, 0));
+ //resetting the translation to the start position at time = 6
+ animationFactory.addTimeTranslation(6, new Vector3f(0, 0, 0));
+
+ //Creating a scale keyFrame at time = 2 with the unit scale.
+ animationFactory.addTimeScale(2, new Vector3f(1, 1, 1));
+ //Creating a scale keyFrame at time = 4 scaling to 1.5
+ animationFactory.addTimeScale(4, new Vector3f(1.5f, 1.5f, 1.5f));
+ //resetting the scale to the start value at time = 5
+ animationFactory.addTimeScale(5, new Vector3f(1, 1, 1));
+
+
+ //Creating a rotation keyFrame at time = 0.5 of quarter PI around the Z axis
+ animationFactory.addTimeRotation(0.5f,new Quaternion().fromAngleAxis(FastMath.QUARTER_PI, Vector3f.UNIT_Z));
+ //rotating back to initial rotation value at time = 1
+ animationFactory.addTimeRotation(1,Quaternion.IDENTITY);
+ //Creating a rotation keyFrame at time = 2. Note that i used the Euler angle version because the angle is higher than PI
+ //this should result in a complete revolution of the spatial around the x axis in 1 second (from 1 to 2)
+ animationFactory.addTimeRotationAngles(2, FastMath.TWO_PI,0, 0);
+
+
+ AnimControl control = new AnimControl();
+ control.addAnim(animationFactory.buildAnimation());
+
+ model.addControl(control);
+
+ rootNode.attachChild(model);
+
+ //run animation
+ control.createChannel().setAnim("anim");
+ }
+}
diff --git a/JmeTests/src/jme3test/model/anim/TestAttachmentsNode.java b/JmeTests/src/jme3test/model/anim/TestAttachmentsNode.java
new file mode 100644
index 0000000..89e6055
--- /dev/null
+++ b/JmeTests/src/jme3test/model/anim/TestAttachmentsNode.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2009-2018 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.model.anim;
+
+import com.jme3.animation.AnimChannel;
+import com.jme3.animation.AnimControl;
+import com.jme3.animation.AnimEventListener;
+import com.jme3.animation.LoopMode;
+import com.jme3.animation.SkeletonControl;
+import com.jme3.app.SimpleApplication;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.light.DirectionalLight;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.shape.Box;
+
+/**
+ * Simple application to test an attachments node on the Jaime model.
+ *
+ * Derived from {@link jme3test.model.anim.TestOgreAnim}.
+ */
+public class TestAttachmentsNode extends SimpleApplication
+ implements AnimEventListener, ActionListener {
+
+ public static void main(String[] args) {
+ TestAttachmentsNode app = new TestAttachmentsNode();
+ app.start();
+ }
+
+ private AnimChannel channel;
+ private AnimControl control;
+
+ @Override
+ public void simpleInitApp() {
+ flyCam.setMoveSpeed(10f);
+ cam.setLocation(new Vector3f(6.4f, 7.5f, 12.8f));
+ cam.setRotation(new Quaternion(-0.060740203f, 0.93925786f, -0.2398315f, -0.2378785f));
+
+ DirectionalLight dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(-0.1f, -0.7f, -1).normalizeLocal());
+ dl.setColor(ColorRGBA.White);
+ rootNode.addLight(dl);
+
+ Spatial model = assetManager.loadModel("Models/Jaime/Jaime.j3o");
+ control = model.getControl(AnimControl.class);
+ SkeletonControl skeletonControl = model.getControl(SkeletonControl.class);
+
+ model.center();
+ model.setLocalScale(5f);
+
+ control.addListener(this);
+ channel = control.createChannel();
+ channel.setAnim("Idle");
+
+ Box box = new Box(0.3f, 0.02f, 0.02f);
+ Geometry saber = new Geometry("saber", box);
+ saber.move(0.4f, 0.05f, 0.01f);
+ Material red = assetManager.loadMaterial("Common/Materials/RedColor.j3m");
+ saber.setMaterial(red);
+ Node n = skeletonControl.getAttachmentsNode("hand.R");
+ n.attachChild(saber);
+ rootNode.attachChild(model);
+
+ inputManager.addListener(this, "Attack");
+ inputManager.addMapping("Attack", new KeyTrigger(KeyInput.KEY_SPACE));
+ }
+
+ @Override
+ public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) {
+ if (animName.equals("Punches")) {
+ channel.setAnim("Idle", 0.5f);
+ channel.setLoopMode(LoopMode.DontLoop);
+ channel.setSpeed(1f);
+ }
+ }
+
+ @Override
+ public void onAnimChange(AnimControl control, AnimChannel channel, String animName) {
+ }
+
+ @Override
+ public void onAction(String binding, boolean value, float tpf) {
+ if (binding.equals("Attack") && value) {
+ if (!channel.getAnimationName().equals("Punches")) {
+ channel.setAnim("Punches", 0.5f);
+ channel.setLoopMode(LoopMode.Cycle);
+ channel.setSpeed(0.5f);
+ }
+ }
+ }
+}
diff --git a/JmeTests/src/jme3test/model/anim/TestBlenderAnim.java b/JmeTests/src/jme3test/model/anim/TestBlenderAnim.java
new file mode 100644
index 0000000..ca636c0
--- /dev/null
+++ b/JmeTests/src/jme3test/model/anim/TestBlenderAnim.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.model.anim;
+
+import com.jme3.animation.AnimChannel;
+import com.jme3.animation.AnimControl;
+import com.jme3.app.SimpleApplication;
+import com.jme3.asset.BlenderKey;
+import com.jme3.light.DirectionalLight;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+
+public class TestBlenderAnim extends SimpleApplication {
+
+ private AnimChannel channel;
+ private AnimControl control;
+
+ public static void main(String[] args) {
+ TestBlenderAnim app = new TestBlenderAnim();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ flyCam.setMoveSpeed(10f);
+ cam.setLocation(new Vector3f(6.4013605f, 7.488437f, 12.843031f));
+ cam.setRotation(new Quaternion(-0.060740203f, 0.93925786f, -0.2398315f, -0.2378785f));
+
+ DirectionalLight dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(-0.1f, -0.7f, -1).normalizeLocal());
+ dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f));
+ rootNode.addLight(dl);
+
+ BlenderKey blenderKey = new BlenderKey("Blender/2.4x/BaseMesh_249.blend");
+
+ Spatial scene = (Spatial) assetManager.loadModel(blenderKey);
+ rootNode.attachChild(scene);
+
+ Spatial model = this.findNode(rootNode, "BaseMesh_01");
+ model.center();
+
+ control = model.getControl(AnimControl.class);
+ channel = control.createChannel();
+
+ channel.setAnim("run_01");
+ }
+
+ /**
+ * This method finds a node of a given name.
+ * @param rootNode the root node to search
+ * @param name the name of the searched node
+ * @return the found node or null
+ */
+ private Spatial findNode(Node rootNode, String name) {
+ if (name.equals(rootNode.getName())) {
+ return rootNode;
+ }
+ return rootNode.getChild(name);
+ }
+}
diff --git a/JmeTests/src/jme3test/model/anim/TestBlenderObjectAnim.java b/JmeTests/src/jme3test/model/anim/TestBlenderObjectAnim.java
new file mode 100644
index 0000000..b352ec2
--- /dev/null
+++ b/JmeTests/src/jme3test/model/anim/TestBlenderObjectAnim.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.model.anim;
+
+import com.jme3.animation.AnimChannel;
+import com.jme3.animation.AnimControl;
+import com.jme3.app.SimpleApplication;
+import com.jme3.asset.BlenderKey;
+import com.jme3.light.DirectionalLight;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+
+public class TestBlenderObjectAnim extends SimpleApplication {
+
+ private AnimChannel channel;
+ private AnimControl control;
+
+ public static void main(String[] args) {
+ TestBlenderObjectAnim app = new TestBlenderObjectAnim();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ flyCam.setMoveSpeed(10f);
+ cam.setLocation(new Vector3f(6.4013605f, 7.488437f, 12.843031f));
+ cam.setRotation(new Quaternion(-0.060740203f, 0.93925786f, -0.2398315f, -0.2378785f));
+
+ DirectionalLight dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(-0.1f, -0.7f, -1).normalizeLocal());
+ dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f));
+ rootNode.addLight(dl);
+
+ BlenderKey blenderKey = new BlenderKey("Blender/2.4x/animtest.blend");
+
+ Spatial scene = (Spatial) assetManager.loadModel(blenderKey);
+ rootNode.attachChild(scene);
+
+ Spatial model = this.findNode(rootNode, "Cube");
+ model.center();
+
+ control = model.getControl(AnimControl.class);
+ channel = control.createChannel();
+
+ channel.setAnim("Action");
+ }
+
+ /**
+ * This method finds a node of a given name.
+ * @param rootNode the root node to search
+ * @param name the name of the searched node
+ * @return the found node or null
+ */
+ private Spatial findNode(Node rootNode, String name) {
+ if (name.equals(rootNode.getName())) {
+ return rootNode;
+ }
+ return rootNode.getChild(name);
+ }
+}
diff --git a/JmeTests/src/jme3test/model/anim/TestCustomAnim.java b/JmeTests/src/jme3test/model/anim/TestCustomAnim.java
new file mode 100644
index 0000000..9340358
--- /dev/null
+++ b/JmeTests/src/jme3test/model/anim/TestCustomAnim.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.model.anim;
+
+import com.jme3.animation.Bone;
+import com.jme3.animation.Skeleton;
+import com.jme3.animation.SkeletonControl;
+import com.jme3.app.SimpleApplication;
+import com.jme3.light.AmbientLight;
+import com.jme3.light.DirectionalLight;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.VertexBuffer;
+import com.jme3.scene.VertexBuffer.Format;
+import com.jme3.scene.VertexBuffer.Type;
+import com.jme3.scene.VertexBuffer.Usage;
+import com.jme3.scene.shape.Box;
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+
+public class TestCustomAnim extends SimpleApplication {
+
+ private Bone bone;
+ private Skeleton skeleton;
+ private Quaternion rotation = new Quaternion();
+
+ public static void main(String[] args) {
+ TestCustomAnim app = new TestCustomAnim();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+
+ AmbientLight al = new AmbientLight();
+ rootNode.addLight(al);
+
+ DirectionalLight dl = new DirectionalLight();
+ dl.setDirection(Vector3f.UNIT_XYZ.negate());
+ rootNode.addLight(dl);
+
+ Box box = new Box(1, 1, 1);
+
+ VertexBuffer weightsHW = new VertexBuffer(Type.HWBoneWeight);
+ VertexBuffer indicesHW = new VertexBuffer(Type.HWBoneIndex);
+ indicesHW.setUsage(Usage.CpuOnly);
+ weightsHW.setUsage(Usage.CpuOnly);
+ box.setBuffer(weightsHW);
+ box.setBuffer(indicesHW);
+
+ // Setup bone weight buffer
+ FloatBuffer weights = FloatBuffer.allocate( box.getVertexCount() * 4 );
+ VertexBuffer weightsBuf = new VertexBuffer(Type.BoneWeight);
+ weightsBuf.setupData(Usage.CpuOnly, 4, Format.Float, weights);
+ box.setBuffer(weightsBuf);
+
+ // Setup bone index buffer
+ ByteBuffer indices = ByteBuffer.allocate( box.getVertexCount() * 4 );
+ VertexBuffer indicesBuf = new VertexBuffer(Type.BoneIndex);
+ indicesBuf.setupData(Usage.CpuOnly, 4, Format.UnsignedByte, indices);
+ box.setBuffer(indicesBuf);
+
+ // Create bind pose buffers
+ box.generateBindPose();
+
+ // Create skeleton
+ bone = new Bone("root");
+ bone.setBindTransforms(Vector3f.ZERO, Quaternion.IDENTITY, Vector3f.UNIT_XYZ);
+ bone.setUserControl(true);
+ skeleton = new Skeleton(new Bone[]{ bone });
+
+ // Assign all verticies to bone 0 with weight 1
+ for (int i = 0; i < box.getVertexCount() * 4; i += 4){
+ // assign vertex to bone index 0
+ indices.array()[i+0] = 0;
+ indices.array()[i+1] = 0;
+ indices.array()[i+2] = 0;
+ indices.array()[i+3] = 0;
+
+ // set weight to 1 only for first entry
+ weights.array()[i+0] = 1;
+ weights.array()[i+1] = 0;
+ weights.array()[i+2] = 0;
+ weights.array()[i+3] = 0;
+ }
+
+ // Maximum number of weights per bone is 1
+ box.setMaxNumWeights(1);
+
+ // Create model
+ Geometry geom = new Geometry("box", box);
+ geom.setMaterial(assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall.j3m"));
+ Node model = new Node("model");
+ model.attachChild(geom);
+
+ // Create skeleton control
+ SkeletonControl skeletonControl = new SkeletonControl(skeleton);
+ model.addControl(skeletonControl);
+
+ rootNode.attachChild(model);
+ }
+
+ @Override
+ public void simpleUpdate(float tpf){
+ // Rotate around X axis
+ Quaternion rotate = new Quaternion();
+ rotate.fromAngleAxis(tpf, Vector3f.UNIT_X);
+
+ // Combine rotation with previous
+ rotation.multLocal(rotate);
+
+ // Set new rotation into bone
+ bone.setUserTransforms(Vector3f.ZERO, rotation, Vector3f.UNIT_XYZ);
+
+ // After changing skeleton transforms, must update world data
+ skeleton.updateWorldVectors();
+ }
+
+}
diff --git a/JmeTests/src/jme3test/model/anim/TestHWSkinning.java b/JmeTests/src/jme3test/model/anim/TestHWSkinning.java
new file mode 100644
index 0000000..9a2e788
--- /dev/null
+++ b/JmeTests/src/jme3test/model/anim/TestHWSkinning.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.model.anim;
+
+import com.jme3.animation.*;
+import com.jme3.app.SimpleApplication;
+import com.jme3.font.BitmapText;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.light.DirectionalLight;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Spatial;
+import java.util.ArrayList;
+import java.util.List;
+
+public class TestHWSkinning extends SimpleApplication implements ActionListener{
+
+ private AnimChannel channel;
+ private AnimControl control;
+ private String[] animNames = {"Dodge", "Walk", "pull", "push"};
+ private final static int SIZE = 10;
+ private boolean hwSkinningEnable = true;
+ private List skControls = new ArrayList();
+ private BitmapText hwsText;
+
+ public static void main(String[] args) {
+ TestHWSkinning app = new TestHWSkinning();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ flyCam.setMoveSpeed(10f);
+ cam.setLocation(new Vector3f(3.8664846f, 6.2704787f, 9.664585f));
+ cam.setRotation(new Quaternion(-0.054774776f, 0.94064945f, -0.27974048f, -0.18418397f));
+ makeHudText();
+
+ DirectionalLight dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(-0.1f, -0.7f, -1).normalizeLocal());
+ dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f));
+ rootNode.addLight(dl);
+
+ for (int i = 0; i < SIZE; i++) {
+ for (int j = 0; j < SIZE; j++) {
+ Spatial model = (Spatial) assetManager.loadModel("Models/Oto/Oto.mesh.xml");
+ model.setLocalScale(0.1f);
+ model.setLocalTranslation(i - SIZE / 2, 0, j - SIZE / 2);
+ control = model.getControl(AnimControl.class);
+
+ channel = control.createChannel();
+ channel.setAnim(animNames[(i + j) % 4]);
+ SkeletonControl skeletonControl = model.getControl(SkeletonControl.class);
+ skeletonControl.setHardwareSkinningPreferred(hwSkinningEnable);
+ skControls.add(skeletonControl);
+ rootNode.attachChild(model);
+ }
+ }
+
+ inputManager.addListener(this, "toggleHWS");
+ inputManager.addMapping("toggleHWS", new KeyTrigger(KeyInput.KEY_SPACE));
+ }
+
+ @Override
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if(isPressed && name.equals("toggleHWS")){
+ hwSkinningEnable = !hwSkinningEnable;
+ for (SkeletonControl control : skControls) {
+ control.setHardwareSkinningPreferred(hwSkinningEnable);
+ hwsText.setText("HWS : "+ hwSkinningEnable);
+ }
+ }
+ }
+
+ private void makeHudText() {
+ guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
+ hwsText = new BitmapText(guiFont, false);
+ hwsText.setSize(guiFont.getCharSet().getRenderedSize());
+ hwsText.setText("HWS : "+ hwSkinningEnable);
+ hwsText.setLocalTranslation(0, cam.getHeight(), 0);
+ guiNode.attachChild(hwsText);
+ }
+}
diff --git a/JmeTests/src/jme3test/model/anim/TestModelExportingCloning.java b/JmeTests/src/jme3test/model/anim/TestModelExportingCloning.java
new file mode 100644
index 0000000..7552583
--- /dev/null
+++ b/JmeTests/src/jme3test/model/anim/TestModelExportingCloning.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2009-2015 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.model.anim;
+
+import com.jme3.animation.AnimChannel;
+import com.jme3.animation.AnimControl;
+import com.jme3.app.SimpleApplication;
+import com.jme3.export.binary.BinaryExporter;
+import com.jme3.light.DirectionalLight;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Spatial;
+
+public class TestModelExportingCloning extends SimpleApplication {
+
+ public static void main(String[] args) {
+ TestModelExportingCloning app = new TestModelExportingCloning();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ Spatial s = assetManager.loadModel("Models/gltf/human/human.j3o");
+ rootNode.attachChild(s);
+
+ rootNode.addLight(new DirectionalLight(new Vector3f(-1,-1,-1)));
+ }
+}
diff --git a/JmeTests/src/jme3test/model/anim/TestOgreAnim.java b/JmeTests/src/jme3test/model/anim/TestOgreAnim.java
new file mode 100644
index 0000000..b6bd4cd
--- /dev/null
+++ b/JmeTests/src/jme3test/model/anim/TestOgreAnim.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.model.anim;
+
+import com.jme3.animation.*;
+import com.jme3.app.SimpleApplication;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.light.DirectionalLight;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.shape.Box;
+
+public class TestOgreAnim extends SimpleApplication
+ implements AnimEventListener, ActionListener {
+
+ private AnimChannel channel;
+ private AnimControl control;
+ private Geometry geom;
+
+ public static void main(String[] args) {
+ TestOgreAnim app = new TestOgreAnim();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ flyCam.setMoveSpeed(10f);
+ cam.setLocation(new Vector3f(6.4013605f, 7.488437f, 12.843031f));
+ cam.setRotation(new Quaternion(-0.060740203f, 0.93925786f, -0.2398315f, -0.2378785f));
+
+ DirectionalLight dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(-0.1f, -0.7f, -1).normalizeLocal());
+ dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f));
+ rootNode.addLight(dl);
+
+ Spatial model = (Spatial) assetManager.loadModel("Models/Oto/Oto.mesh.xml");
+ model.center();
+
+ control = model.getControl(AnimControl.class);
+ control.addListener(this);
+ channel = control.createChannel();
+
+ for (String anim : control.getAnimationNames())
+ System.out.println(anim);
+
+ channel.setAnim("stand");
+ geom = (Geometry)((Node)model).getChild(0);
+ SkeletonControl skeletonControl = model.getControl(SkeletonControl.class);
+
+ Box b = new Box(.25f,3f,.25f);
+ Geometry item = new Geometry("Item", b);
+ item.move(0, 1.5f, 0);
+ item.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m"));
+ Node n = skeletonControl.getAttachmentsNode("hand.right");
+ n.attachChild(item);
+
+ rootNode.attachChild(model);
+
+ inputManager.addListener(this, "Attack");
+ inputManager.addMapping("Attack", new KeyTrigger(KeyInput.KEY_SPACE));
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ super.simpleUpdate(tpf);
+// geom.getMesh().createCollisionData();
+
+ }
+
+
+ public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) {
+ if (animName.equals("Dodge")){
+ channel.setAnim("stand", 0.50f);
+ channel.setLoopMode(LoopMode.DontLoop);
+ channel.setSpeed(1f);
+ }
+ }
+
+ public void onAnimChange(AnimControl control, AnimChannel channel, String animName) {
+ }
+
+ public void onAction(String binding, boolean value, float tpf) {
+ if (binding.equals("Attack") && value){
+ if (!channel.getAnimationName().equals("Dodge")){
+ channel.setAnim("Dodge", 0.50f);
+ channel.setLoopMode(LoopMode.Cycle);
+ channel.setSpeed(0.10f);
+ }
+ }
+ }
+
+}
diff --git a/JmeTests/src/jme3test/model/anim/TestOgreComplexAnim.java b/JmeTests/src/jme3test/model/anim/TestOgreComplexAnim.java
new file mode 100644
index 0000000..fa12835
--- /dev/null
+++ b/JmeTests/src/jme3test/model/anim/TestOgreComplexAnim.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.model.anim;
+
+import com.jme3.animation.AnimChannel;
+import com.jme3.animation.AnimControl;
+import com.jme3.animation.Bone;
+import com.jme3.animation.LoopMode;
+import com.jme3.app.SimpleApplication;
+import com.jme3.light.DirectionalLight;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Node;
+import com.jme3.scene.debug.SkeletonDebugger;
+
+public class TestOgreComplexAnim extends SimpleApplication {
+
+ private AnimControl control;
+ private float angle = 0;
+ private float scale = 1;
+ private float rate = 1;
+
+ public static void main(String[] args) {
+ TestOgreComplexAnim app = new TestOgreComplexAnim();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ flyCam.setMoveSpeed(10f);
+ cam.setLocation(new Vector3f(6.4013605f, 7.488437f, 12.843031f));
+ cam.setRotation(new Quaternion(-0.060740203f, 0.93925786f, -0.2398315f, -0.2378785f));
+
+ DirectionalLight dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(-0.1f, -0.7f, -1).normalizeLocal());
+ dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f));
+ rootNode.addLight(dl);
+
+ Node model = (Node) assetManager.loadModel("Models/Oto/Oto.mesh.xml");
+
+ control = model.getControl(AnimControl.class);
+
+ AnimChannel feet = control.createChannel();
+ AnimChannel leftHand = control.createChannel();
+ AnimChannel rightHand = control.createChannel();
+
+ // feet will dodge
+ feet.addFromRootBone("hip.right");
+ feet.addFromRootBone("hip.left");
+ feet.setAnim("Dodge");
+ feet.setSpeed(2);
+ feet.setLoopMode(LoopMode.Cycle);
+
+ // will blend over 15 seconds to stand
+ feet.setAnim("Walk", 15);
+ feet.setSpeed(0.25f);
+ feet.setLoopMode(LoopMode.Cycle);
+
+ // left hand will pull
+ leftHand.addFromRootBone("uparm.right");
+ leftHand.setAnim("pull");
+ leftHand.setSpeed(.5f);
+
+ // will blend over 15 seconds to stand
+ leftHand.setAnim("stand", 15);
+
+ // right hand will push
+ rightHand.addBone("spinehigh");
+ rightHand.addFromRootBone("uparm.left");
+ rightHand.setAnim("push");
+
+ SkeletonDebugger skeletonDebug = new SkeletonDebugger("skeleton", control.getSkeleton());
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat.getAdditionalRenderState().setWireframe(true);
+ mat.setColor("Color", ColorRGBA.Green);
+ mat.setFloat("PointSize", 7f);
+ mat.getAdditionalRenderState().setDepthTest(false);
+ skeletonDebug.setMaterial(mat);
+
+ model.attachChild(skeletonDebug);
+ rootNode.attachChild(model);
+ }
+
+ @Override
+ public void simpleUpdate(float tpf){
+ Bone b = control.getSkeleton().getBone("spinehigh");
+ Bone b2 = control.getSkeleton().getBone("uparm.left");
+
+ angle += tpf * rate;
+ if (angle > FastMath.HALF_PI / 2f){
+ angle = FastMath.HALF_PI / 2f;
+ rate = -1;
+ }else if (angle < -FastMath.HALF_PI / 2f){
+ angle = -FastMath.HALF_PI / 2f;
+ rate = 1;
+ }
+
+ Quaternion q = new Quaternion();
+ q.fromAngles(0, angle, 0);
+
+ b.setUserControl(true);
+ b.setUserTransforms(Vector3f.ZERO, q, Vector3f.UNIT_XYZ);
+
+ b2.setUserControl(true);
+ b2.setUserTransforms(Vector3f.ZERO, Quaternion.IDENTITY, new Vector3f(1+angle,1+ angle, 1+angle));
+
+
+ }
+
+}
diff --git a/JmeTests/src/jme3test/model/anim/TestSkeletonControlRefresh.java b/JmeTests/src/jme3test/model/anim/TestSkeletonControlRefresh.java
new file mode 100644
index 0000000..6356d2a
--- /dev/null
+++ b/JmeTests/src/jme3test/model/anim/TestSkeletonControlRefresh.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.model.anim;
+
+/**
+ *
+ * @author Nehon
+ */
+
+
+
+import com.jme3.animation.*;
+import com.jme3.app.SimpleApplication;
+import com.jme3.asset.TextureKey;
+import com.jme3.font.BitmapText;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.light.DirectionalLight;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector2f;
+import com.jme3.math.Vector3f;
+import com.jme3.post.FilterPostProcessor;
+import com.jme3.post.ssao.SSAOFilter;
+import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.shape.Quad;
+import com.jme3.shadow.DirectionalLightShadowFilter;
+import com.jme3.shadow.DirectionalLightShadowRenderer;
+import java.util.ArrayList;
+import java.util.List;
+import jme3test.post.SSAOUI;
+
+public class TestSkeletonControlRefresh extends SimpleApplication implements ActionListener{
+
+ private AnimChannel channel;
+ private AnimControl control;
+ private String[] animNames = {"Dodge", "Walk", "pull", "push"};
+ private final static int SIZE = 10;
+ private boolean hwSkinningEnable = true;
+ private List skControls = new ArrayList();
+ private BitmapText hwsText;
+
+ public static void main(String[] args) {
+ TestSkeletonControlRefresh app = new TestSkeletonControlRefresh();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ viewPort.setBackgroundColor(ColorRGBA.White);
+ flyCam.setMoveSpeed(10f);
+ cam.setLocation(new Vector3f(3.8664846f, 6.2704787f, 9.664585f));
+ cam.setRotation(new Quaternion(-0.054774776f, 0.94064945f, -0.27974048f, -0.18418397f));
+ makeHudText();
+
+ DirectionalLight dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(-0.1f, -0.7f, -1).normalizeLocal());
+ dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f));
+ rootNode.addLight(dl);
+ Material m = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ TextureKey k = new TextureKey("Models/Oto/Oto.jpg", false);
+ m.setTexture("ColorMap", assetManager.loadTexture(k));
+
+ for (int i = 0; i < SIZE; i++) {
+ for (int j = 0; j < SIZE; j++) {
+ Spatial model = (Spatial) assetManager.loadModel("Models/Oto/Oto.mesh.xml");
+ //setting a different material
+ model.setMaterial(m.clone());
+ model.setLocalScale(0.1f);
+ model.setLocalTranslation(i - SIZE / 2, 0, j - SIZE / 2);
+ control = model.getControl(AnimControl.class);
+
+ channel = control.createChannel();
+ channel.setAnim(animNames[(i + j) % 4]);
+ channel.setLoopMode(LoopMode.DontLoop);
+ SkeletonControl skeletonControl = model.getControl(SkeletonControl.class);
+
+ //This is a workaround the issue. this call will make the SkeletonControl gather the targets again.
+ //skeletonControl.setSpatial(model);
+ skeletonControl.setHardwareSkinningPreferred(hwSkinningEnable);
+ skControls.add(skeletonControl);
+ rootNode.attachChild(model);
+ }
+ }
+
+ rootNode.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
+ setupFloor();
+
+ inputManager.addListener(this, "toggleHWS");
+ inputManager.addMapping("toggleHWS", new KeyTrigger(KeyInput.KEY_SPACE));
+
+// DirectionalLightShadowRenderer pssm = new DirectionalLightShadowRenderer(assetManager, 1024, 2);
+// pssm.setLight(dl);
+// viewPort.addProcessor(pssm);
+
+ FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
+
+ DirectionalLightShadowFilter sf = new DirectionalLightShadowFilter(assetManager, 1024, 2);
+ sf.setLight(dl);
+ fpp.addFilter(sf);
+ fpp.addFilter(new SSAOFilter());
+ viewPort.addProcessor(fpp);
+
+
+ }
+
+ public void setupFloor() {
+ Quad q = new Quad(20, 20);
+ q.scaleTextureCoordinates(Vector2f.UNIT_XY.mult(10));
+ Geometry geom = new Geometry("floor", q);
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat.setColor("Color", ColorRGBA.White);
+ geom.setMaterial(mat);
+
+ geom.rotate(-FastMath.HALF_PI, 0, 0);
+ geom.center();
+ geom.move(0, -0.3f, 0);
+ geom.setShadowMode(RenderQueue.ShadowMode.Receive);
+ rootNode.attachChild(geom);
+ }
+
+
+ @Override
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if(isPressed && name.equals("toggleHWS")){
+ hwSkinningEnable = !hwSkinningEnable;
+ for (SkeletonControl skControl : skControls) {
+ skControl.setHardwareSkinningPreferred(hwSkinningEnable);
+ hwsText.setText("HWS : "+ hwSkinningEnable);
+ }
+ }
+ }
+
+ private void makeHudText() {
+ guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
+ hwsText = new BitmapText(guiFont, false);
+ hwsText.setSize(guiFont.getCharSet().getRenderedSize());
+ hwsText.setText("HWS : "+ hwSkinningEnable);
+ hwsText.setLocalTranslation(0, cam.getHeight(), 0);
+ guiNode.attachChild(hwsText);
+ }
+}
\ No newline at end of file
diff --git a/JmeTests/src/jme3test/model/anim/TestSpatialAnim.java b/JmeTests/src/jme3test/model/anim/TestSpatialAnim.java
new file mode 100644
index 0000000..6813803
--- /dev/null
+++ b/JmeTests/src/jme3test/model/anim/TestSpatialAnim.java
@@ -0,0 +1,87 @@
+package jme3test.model.anim;
+
+import com.jme3.animation.AnimControl;
+import com.jme3.animation.Animation;
+import com.jme3.animation.SpatialTrack;
+import com.jme3.app.SimpleApplication;
+import com.jme3.light.AmbientLight;
+import com.jme3.light.DirectionalLight;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.shape.Box;
+import java.util.HashMap;
+
+public class TestSpatialAnim extends SimpleApplication {
+
+ public static void main(String[] args) {
+ TestSpatialAnim app = new TestSpatialAnim();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+
+ AmbientLight al = new AmbientLight();
+ rootNode.addLight(al);
+
+ DirectionalLight dl = new DirectionalLight();
+ dl.setDirection(Vector3f.UNIT_XYZ.negate());
+ rootNode.addLight(dl);
+
+ // Create model
+ Box box = new Box(1, 1, 1);
+ Geometry geom = new Geometry("box", box);
+ geom.setMaterial(assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall.j3m"));
+ Node model = new Node("model");
+ model.attachChild(geom);
+
+ Box child = new Box(0.5f, 0.5f, 0.5f);
+ Geometry childGeom = new Geometry("box", child);
+ childGeom.setMaterial(assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall.j3m"));
+ Node childModel = new Node("childmodel");
+ childModel.setLocalTranslation(2, 2, 2);
+ childModel.attachChild(childGeom);
+ model.attachChild(childModel);
+
+ //animation parameters
+ float animTime = 5;
+ int fps = 25;
+ float totalXLength = 10;
+
+ //calculating frames
+ int totalFrames = (int) (fps * animTime);
+ float dT = animTime / totalFrames, t = 0;
+ float dX = totalXLength / totalFrames, x = 0;
+ float[] times = new float[totalFrames];
+ Vector3f[] translations = new Vector3f[totalFrames];
+ Quaternion[] rotations = new Quaternion[totalFrames];
+ Vector3f[] scales = new Vector3f[totalFrames];
+ for (int i = 0; i < totalFrames; ++i) {
+ times[i] = t;
+ t += dT;
+ translations[i] = new Vector3f(x, 0, 0);
+ x += dX;
+ rotations[i] = Quaternion.IDENTITY;
+ scales[i] = Vector3f.UNIT_XYZ;
+ }
+ SpatialTrack spatialTrack = new SpatialTrack(times, translations, rotations, scales);
+
+ //creating the animation
+ Animation spatialAnimation = new Animation("anim", animTime);
+ spatialAnimation.setTracks(new SpatialTrack[] { spatialTrack });
+
+ //create spatial animation control
+ AnimControl control = new AnimControl();
+ HashMap animations = new HashMap();
+ animations.put("anim", spatialAnimation);
+ control.setAnimations(animations);
+ model.addControl(control);
+
+ rootNode.attachChild(model);
+
+ //run animation
+ control.createChannel().setAnim("anim");
+ }
+}
diff --git a/JmeTests/src/jme3test/model/shape/TestBillboard.java b/JmeTests/src/jme3test/model/shape/TestBillboard.java
new file mode 100644
index 0000000..8fa8a66
--- /dev/null
+++ b/JmeTests/src/jme3test/model/shape/TestBillboard.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.model.shape;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.control.BillboardControl;
+import com.jme3.scene.shape.Box;
+import com.jme3.scene.shape.Quad;
+
+/**
+ *
+ * @author Kirill Vainer
+ */
+public class TestBillboard extends SimpleApplication {
+
+ public void simpleInitApp() {
+ flyCam.setMoveSpeed(10);
+
+ Quad q = new Quad(2, 2);
+ Geometry g = new Geometry("Quad", q);
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat.setColor("Color", ColorRGBA.Blue);
+ g.setMaterial(mat);
+
+ Quad q2 = new Quad(1, 1);
+ Geometry g3 = new Geometry("Quad2", q2);
+ Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat2.setColor("Color", ColorRGBA.Yellow);
+ g3.setMaterial(mat2);
+ g3.setLocalTranslation(.5f, .5f, .01f);
+
+ Box b = new Box(.25f, .5f, .25f);
+ Geometry g2 = new Geometry("Box", b);
+ g2.setLocalTranslation(0, 0, 3);
+ g2.setMaterial(mat);
+
+ Node bb = new Node("billboard");
+
+ BillboardControl control=new BillboardControl();
+
+ bb.addControl(control);
+ bb.attachChild(g);
+ bb.attachChild(g3);
+
+
+ n=new Node("parent");
+ n.attachChild(g2);
+ n.attachChild(bb);
+ rootNode.attachChild(n);
+
+ n2=new Node("parentParent");
+ n2.setLocalTranslation(Vector3f.UNIT_X.mult(5));
+ n2.attachChild(n);
+
+ rootNode.attachChild(n2);
+
+
+// rootNode.attachChild(bb);
+// rootNode.attachChild(g2);
+ }
+ Node n;
+ Node n2;
+ @Override
+ public void simpleUpdate(float tpf) {
+ super.simpleUpdate(tpf);
+ n.rotate(0, tpf, 0);
+ n.move(0.1f*tpf, 0, 0);
+ n2.rotate(0, 0, -tpf);
+ }
+
+
+
+ public static void main(String[] args) {
+ TestBillboard app = new TestBillboard();
+ app.start();
+ }
+}
\ No newline at end of file
diff --git a/JmeTests/src/jme3test/model/shape/TestBox.java b/JmeTests/src/jme3test/model/shape/TestBox.java
new file mode 100644
index 0000000..0e5e86a
--- /dev/null
+++ b/JmeTests/src/jme3test/model/shape/TestBox.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.model.shape;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.material.Material;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Box;
+
+public class TestBox extends SimpleApplication {
+
+ public static void main(String[] args){
+ TestBox app = new TestBox();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ Box b = new Box(1, 1, 1);
+ Geometry geom = new Geometry("Box", b);
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg"));
+ geom.setMaterial(mat);
+ rootNode.attachChild(geom);
+ }
+
+}
diff --git a/JmeTests/src/jme3test/model/shape/TestCustomMesh.java b/JmeTests/src/jme3test/model/shape/TestCustomMesh.java
new file mode 100644
index 0000000..e11b526
--- /dev/null
+++ b/JmeTests/src/jme3test/model/shape/TestCustomMesh.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.model.shape;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Vector2f;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Mesh;
+import com.jme3.scene.VertexBuffer.Type;
+import com.jme3.util.BufferUtils;
+
+/**
+ * How to create custom meshes by specifying vertices
+ * We render the mesh in three different ways, once with a solid blue color,
+ * once with vertex colors, and once with a wireframe material.
+ * @author KayTrance
+ */
+public class TestCustomMesh extends SimpleApplication {
+
+ public static void main(String[] args){
+ TestCustomMesh app = new TestCustomMesh();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+
+ Mesh m = new Mesh();
+
+ // Vertex positions in space
+ Vector3f [] vertices = new Vector3f[4];
+ vertices[0] = new Vector3f(0,0,0);
+ vertices[1] = new Vector3f(3,0,0);
+ vertices[2] = new Vector3f(0,3,0);
+ vertices[3] = new Vector3f(3,3,0);
+
+ // Texture coordinates
+ Vector2f [] texCoord = new Vector2f[4];
+ texCoord[0] = new Vector2f(0,0);
+ texCoord[1] = new Vector2f(1,0);
+ texCoord[2] = new Vector2f(0,1);
+ texCoord[3] = new Vector2f(1,1);
+
+ // Indexes. We define the order in which mesh should be constructed
+ short[] indexes = {2, 0, 1, 1, 3, 2};
+
+ // Setting buffers
+ m.setBuffer(Type.Position, 3, BufferUtils.createFloatBuffer(vertices));
+ m.setBuffer(Type.TexCoord, 2, BufferUtils.createFloatBuffer(texCoord));
+ m.setBuffer(Type.Index, 1, BufferUtils.createShortBuffer(indexes));
+ m.updateBound();
+
+ // *************************************************************************
+ // First mesh uses one solid color
+ // *************************************************************************
+
+ // Creating a geometry, and apply a single color material to it
+ Geometry geom = new Geometry("OurMesh", m);
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat.setColor("Color", ColorRGBA.Blue);
+ geom.setMaterial(mat);
+
+ // Attaching our geometry to the root node.
+ rootNode.attachChild(geom);
+
+ // *************************************************************************
+ // Second mesh uses vertex colors to color each vertex
+ // *************************************************************************
+ Mesh cMesh = m.clone();
+ Geometry coloredMesh = new Geometry ("ColoredMesh", cMesh);
+ Material matVC = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ matVC.setBoolean("VertexColor", true);
+
+ //We have 4 vertices and 4 color values for each of them.
+ //If you have more vertices, you need 'new float[yourVertexCount * 4]' here!
+ float[] colorArray = new float[4*4];
+ int colorIndex = 0;
+
+ //Set custom RGBA value for each Vertex. Values range from 0.0f to 1.0f
+ for(int i = 0; i < 4; i++){
+ // Red value (is increased by .2 on each next vertex here)
+ colorArray[colorIndex++]= 0.1f+(.2f*i);
+ // Green value (is reduced by .2 on each next vertex)
+ colorArray[colorIndex++]= 0.9f-(0.2f*i);
+ // Blue value (remains the same in our case)
+ colorArray[colorIndex++]= 0.5f;
+ // Alpha value (no transparency set here)
+ colorArray[colorIndex++]= 1.0f;
+ }
+ // Set the color buffer
+ cMesh.setBuffer(Type.Color, 4, colorArray);
+ coloredMesh.setMaterial(matVC);
+ // move mesh a bit so that it doesn't intersect with the first one
+ coloredMesh.setLocalTranslation(4, 0, 0);
+ rootNode.attachChild(coloredMesh);
+
+// /** Alternatively, you can show the mesh vertixes as points
+// * instead of coloring the faces. */
+// cMesh.setMode(Mesh.Mode.Points);
+// cMesh.setPointSize(10f);
+// cMesh.updateBound();
+// cMesh.setStatic();
+// Geometry points = new Geometry("Points", m);
+// points.setMaterial(mat);
+// rootNode.attachChild(points);
+
+ // *************************************************************************
+ // Third mesh will use a wireframe shader to show wireframe
+ // *************************************************************************
+ Mesh wfMesh = m.clone();
+ Geometry wfGeom = new Geometry("wireframeGeometry", wfMesh);
+ Material matWireframe = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ matWireframe.setColor("Color", ColorRGBA.Green);
+ matWireframe.getAdditionalRenderState().setWireframe(true);
+ wfGeom.setMaterial(matWireframe);
+ wfGeom.setLocalTranslation(4, 4, 0);
+ rootNode.attachChild(wfGeom);
+
+ }
+}
diff --git a/JmeTests/src/jme3test/model/shape/TestCylinder.java b/JmeTests/src/jme3test/model/shape/TestCylinder.java
new file mode 100644
index 0000000..bec3847
--- /dev/null
+++ b/JmeTests/src/jme3test/model/shape/TestCylinder.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.model.shape;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.asset.TextureKey;
+import com.jme3.material.Material;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Cylinder;
+import com.jme3.texture.Texture;
+
+public class TestCylinder extends SimpleApplication {
+
+ public static void main(String[] args){
+ TestCylinder app = new TestCylinder();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ Cylinder t = new Cylinder(20, 50, 1, 2, true);
+ Geometry geom = new Geometry("Cylinder", t);
+
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ TextureKey key = new TextureKey("Interface/Logo/Monkey.jpg", true);
+ key.setGenerateMips(true);
+ Texture tex = assetManager.loadTexture(key);
+ tex.setMinFilter(Texture.MinFilter.Trilinear);
+ mat.setTexture("ColorMap", tex);
+
+ geom.setMaterial(mat);
+
+ rootNode.attachChild(geom);
+ }
+
+}
diff --git a/JmeTests/src/jme3test/model/shape/TestDebugShapes.java b/JmeTests/src/jme3test/model/shape/TestDebugShapes.java
new file mode 100644
index 0000000..fc47316
--- /dev/null
+++ b/JmeTests/src/jme3test/model/shape/TestDebugShapes.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.model.shape;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Mesh;
+import com.jme3.scene.debug.Arrow;
+import com.jme3.scene.debug.Grid;
+import com.jme3.scene.debug.WireBox;
+import com.jme3.scene.debug.WireSphere;
+
+public class TestDebugShapes extends SimpleApplication {
+
+ public static void main(String[] args){
+ TestDebugShapes app = new TestDebugShapes();
+ app.start();
+ }
+
+ public Geometry putShape(Mesh shape, ColorRGBA color, float lineWidth){
+ Geometry g = new Geometry("shape", shape);
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat.getAdditionalRenderState().setWireframe(true);
+ mat.getAdditionalRenderState().setLineWidth(lineWidth);
+ mat.setColor("Color", color);
+ g.setMaterial(mat);
+ rootNode.attachChild(g);
+ return g;
+ }
+
+ public void putArrow(Vector3f pos, Vector3f dir, ColorRGBA color){
+ Arrow arrow = new Arrow(dir);
+ putShape(arrow, color, 4).setLocalTranslation(pos);
+ }
+
+ public void putBox(Vector3f pos, float size, ColorRGBA color){
+ putShape(new WireBox(size, size, size), color, 1).setLocalTranslation(pos);
+ }
+
+ public void putGrid(Vector3f pos, ColorRGBA color){
+ putShape(new Grid(6, 6, 0.2f), color, 1).center().move(pos);
+ }
+
+ public void putSphere(Vector3f pos, ColorRGBA color){
+ putShape(new WireSphere(1), color, 1).setLocalTranslation(pos);
+ }
+
+ @Override
+ public void simpleInitApp() {
+ cam.setLocation(new Vector3f(2,1.5f,2));
+ cam.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y);
+
+ putArrow(Vector3f.ZERO, Vector3f.UNIT_X, ColorRGBA.Red);
+ putArrow(Vector3f.ZERO, Vector3f.UNIT_Y, ColorRGBA.Green);
+ putArrow(Vector3f.ZERO, Vector3f.UNIT_Z, ColorRGBA.Blue);
+
+ putBox(new Vector3f(2, 0, 0), 0.5f, ColorRGBA.Yellow);
+ putGrid(new Vector3f(3.5f, 0, 0), ColorRGBA.White);
+ putSphere(new Vector3f(4.5f, 0, 0), ColorRGBA.Magenta);
+ }
+
+}
diff --git a/JmeTests/src/jme3test/model/shape/TestExpandingTorus.java b/JmeTests/src/jme3test/model/shape/TestExpandingTorus.java
new file mode 100644
index 0000000..cdab039
--- /dev/null
+++ b/JmeTests/src/jme3test/model/shape/TestExpandingTorus.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.model.shape;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.material.Material;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Torus;
+
+public class TestExpandingTorus extends SimpleApplication {
+
+ private float outerRadius = 1.5f;
+ private float rate = 1;
+ private Torus torus;
+ private Geometry geom;
+
+ public static void main(String[] args) {
+ TestExpandingTorus app = new TestExpandingTorus();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ torus = new Torus(30, 10, .5f, 1f);
+ geom = new Geometry("Torus", torus);
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ geom.setMaterial(mat);
+ rootNode.attachChild(geom);
+ }
+
+ @Override
+ public void simpleUpdate(float tpf){
+ if (outerRadius > 2.5f){
+ outerRadius = 2.5f;
+ rate = -rate;
+ }else if (outerRadius < 1f){
+ outerRadius = 1f;
+ rate = -rate;
+ }
+ outerRadius += rate * tpf;
+ torus.updateGeometry(30, 10, .5f, outerRadius);
+ }
+}
\ No newline at end of file
diff --git a/JmeTests/src/jme3test/model/shape/TestSphere.java b/JmeTests/src/jme3test/model/shape/TestSphere.java
new file mode 100644
index 0000000..0bdf0e7
--- /dev/null
+++ b/JmeTests/src/jme3test/model/shape/TestSphere.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.model.shape;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.material.Material;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Sphere;
+
+public class TestSphere extends SimpleApplication {
+
+ public static void main(String[] args){
+ TestSphere app = new TestSphere();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ Sphere sphMesh = new Sphere(14, 14, 1);
+ Material solidColor = assetManager.loadMaterial("Common/Materials/RedColor.j3m");
+
+ for (int y = -5; y < 5; y++){
+ for (int x = -5; x < 5; x++){
+ Geometry sphere = new Geometry("sphere", sphMesh);
+ sphere.setMaterial(solidColor);
+ sphere.setLocalTranslation(x * 2, 0, y * 2);
+ rootNode.attachChild(sphere);
+ }
+ }
+ cam.setLocation(new Vector3f(0, 5, 0));
+ cam.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y);
+ }
+
+}
diff --git a/JmeTests/src/jme3test/network/MovingAverage.java b/JmeTests/src/jme3test/network/MovingAverage.java
new file mode 100644
index 0000000..991b5e5
--- /dev/null
+++ b/JmeTests/src/jme3test/network/MovingAverage.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.network;
+
+class MovingAverage {
+
+ private long[] samples;
+ private long sum;
+ private int count, index;
+
+ public MovingAverage(int numSamples){
+ samples = new long[numSamples];
+ }
+
+ public void add(long sample){
+ sum = sum - samples[index] + sample;
+ samples[index++] = sample;
+ if (index > count){
+ count = index;
+ }
+ if (index >= samples.length){
+ index = 0;
+ }
+ }
+
+ public long getAverage(){
+ if (count == 0)
+ return 0;
+ else
+ return (long) ((float) sum / (float) count);
+ }
+
+}
\ No newline at end of file
diff --git a/JmeTests/src/jme3test/network/TestChatClient.java b/JmeTests/src/jme3test/network/TestChatClient.java
new file mode 100644
index 0000000..2e8ecbf
--- /dev/null
+++ b/JmeTests/src/jme3test/network/TestChatClient.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2011 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.network;
+
+import com.jme3.network.Client;
+import com.jme3.network.ClientStateListener;
+import com.jme3.network.ErrorListener;
+import com.jme3.network.Message;
+import com.jme3.network.MessageListener;
+import com.jme3.network.Network;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.event.ActionEvent;
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.swing.*;
+import jme3test.network.TestChatServer.ChatMessage;
+
+/**
+ * A simple test chat server. When SM implements a set
+ * of standard chat classes this can become a lot simpler.
+ *
+ * @version $Revision$
+ * @author Paul Speed
+ */
+public class TestChatClient extends JFrame {
+
+ private final Client client;
+ private final JEditorPane chatLog;
+ private final StringBuilder chatMessages = new StringBuilder();
+ private final JTextField nameField;
+ private final JTextField messageField;
+
+ public TestChatClient(String host) throws IOException {
+ super("jME3 Test Chat Client - to:" + host);
+
+ // Build out the UI
+ setDefaultCloseOperation(DISPOSE_ON_CLOSE);
+ setSize(800, 600);
+
+ chatLog = new JEditorPane();
+ chatLog.setEditable(false);
+ chatLog.setContentType("text/html");
+ chatLog.setText("");
+
+ getContentPane().add(new JScrollPane(chatLog), "Center");
+
+ // A crude form
+ JPanel p = new JPanel();
+ p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
+ p.add(new JLabel("Name:"));
+ nameField = new JTextField(System.getProperty("user.name", "yourname"));
+ Dimension d = nameField.getPreferredSize();
+ nameField.setMaximumSize(new Dimension(120, d.height + 6));
+ p.add(nameField);
+ p.add(new JLabel(" Message:"));
+ messageField = new JTextField();
+ p.add(messageField);
+ p.add(new JButton(new SendAction(true)));
+ p.add(new JButton(new SendAction(false)));
+
+ getContentPane().add(p, "South");
+
+ client = Network.connectToServer(TestChatServer.NAME, TestChatServer.VERSION,
+ host, TestChatServer.PORT, TestChatServer.UDP_PORT);
+ client.addMessageListener(new ChatHandler(), ChatMessage.class);
+ client.addClientStateListener(new ChatClientStateListener());
+ client.addErrorListener(new ChatErrorListener());
+ client.start();
+
+ System.out.println("Started client:" + client);
+ }
+
+ @Override
+ public void dispose() {
+ System.out.println("Chat window closing.");
+ super.dispose();
+ if( client.isConnected() ) {
+ client.close();
+ }
+ }
+
+ public static String getString(Component owner, String title, String message, String initialValue) {
+ return (String) JOptionPane.showInputDialog(owner, message, title, JOptionPane.PLAIN_MESSAGE,
+ null, null, initialValue);
+ }
+
+ public static void main(String... args) throws Exception {
+
+ // Increate the logging level for networking...
+ System.out.println("Setting logging to max");
+ Logger networkLog = Logger.getLogger("com.jme3.network");
+ networkLog.setLevel(Level.FINEST);
+
+ // And we have to tell JUL's handler also
+ // turn up logging in a very convoluted way
+ Logger rootLog = Logger.getLogger("");
+ if( rootLog.getHandlers().length > 0 ) {
+ rootLog.getHandlers()[0].setLevel(Level.FINEST);
+ }
+
+ // Note: in JME 3.1 this is generally unnecessary as the server will
+ // send a message with all server-registered classes.
+ // TestChatServer.initializeClasses();
+ // Leaving the call commented out to be illustrative regarding the
+ // common old pattern.
+
+ // Grab a host string from the user
+ String s = getString(null, "Host Info", "Enter chat host:", "localhost");
+ if (s == null) {
+ System.out.println("User cancelled.");
+ return;
+ }
+
+ // Register a shutdown hook to get a message on the console when the
+ // app actually finishes
+ Runtime.getRuntime().addShutdownHook(new Thread() {
+ @Override
+ public void run() {
+ System.out.println("Chat client is terminating.");
+ }
+ });
+
+
+ TestChatClient test = new TestChatClient(s);
+ test.setVisible(true);
+ }
+
+ private class ChatHandler implements MessageListener {
+
+ @Override
+ public void messageReceived(Client source, Message m) {
+ ChatMessage chat = (ChatMessage) m;
+
+ System.out.println("Received:" + chat);
+
+ // One of the least efficient ways to add text to a
+ // JEditorPane
+ chatMessages.append("" + (m.isReliable() ? "TCP" : "UDP") + "");
+ chatMessages.append(" -- " + chat.getName() + " : ");
+ chatMessages.append(chat.getMessage());
+ chatMessages.append("
");
+ String s = "" + chatMessages + "";
+ chatLog.setText(s);
+
+ // Set selection to the end so that the scroll panel will scroll
+ // down.
+ chatLog.select(s.length(), s.length());
+ }
+ }
+
+ private class ChatClientStateListener implements ClientStateListener {
+
+ @Override
+ public void clientConnected(Client c) {
+ System.out.println("clientConnected(" + c + ")");
+ }
+
+ @Override
+ public void clientDisconnected(Client c, DisconnectInfo info) {
+ System.out.println("clientDisconnected(" + c + "):" + info);
+ if( info != null ) {
+ // The connection was closed by the server
+ JOptionPane.showMessageDialog(rootPane,
+ info.reason,
+ "Connection Closed",
+ JOptionPane.INFORMATION_MESSAGE);
+ dispose();
+ }
+ }
+ }
+
+ private class ChatErrorListener implements ErrorListener {
+
+ @Override
+ public void handleError( Client source, Throwable t ) {
+ System.out.println("handleError(" + source + ", " + t + ")");
+ JOptionPane.showMessageDialog(rootPane,
+ String.valueOf(t),
+ "Connection Error",
+ JOptionPane.ERROR_MESSAGE);
+ }
+
+ }
+
+ private class SendAction extends AbstractAction {
+
+ private final boolean reliable;
+
+ public SendAction(boolean reliable) {
+ super(reliable ? "TCP" : "UDP");
+ this.reliable = reliable;
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent evt) {
+ String name = nameField.getText();
+ String message = messageField.getText();
+
+ ChatMessage chat = new ChatMessage(name, message);
+ chat.setReliable(reliable);
+ System.out.println("Sending:" + chat);
+ client.send(chat);
+ }
+ }
+}
diff --git a/JmeTests/src/jme3test/network/TestChatClientAndServer.java b/JmeTests/src/jme3test/network/TestChatClientAndServer.java
new file mode 100644
index 0000000..0069446
--- /dev/null
+++ b/JmeTests/src/jme3test/network/TestChatClientAndServer.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2015 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.network;
+
+
+/**
+ * Combines the server instance and a client instance into the
+ * same JVM to show an example of, and to test, a pattern like
+ * self-hosted multiplayer games.
+ *
+ * @author Paul Speed
+ */
+public class TestChatClientAndServer {
+
+ public static void main( String... args ) throws Exception {
+
+ System.out.println("Starting chat server...");
+ TestChatServer chatServer = new TestChatServer();
+ chatServer.start();
+
+ System.out.println("Waiting for connections on port:" + TestChatServer.PORT);
+
+ // Now launch a client
+
+ TestChatClient test = new TestChatClient("localhost");
+ test.setVisible(true);
+
+ // Register a shutdown hook to get a message on the console when the
+ // app actually finishes
+ Runtime.getRuntime().addShutdownHook(new Thread() {
+ @Override
+ public void run() {
+ System.out.println("Client and server test is terminating.");
+ }
+ });
+
+ // Keep running basically forever or until the server
+ // shuts down
+ while( chatServer.isRunning() ) {
+ synchronized (chatServer) {
+ chatServer.wait();
+ }
+ }
+ }
+}
diff --git a/JmeTests/src/jme3test/network/TestChatServer.java b/JmeTests/src/jme3test/network/TestChatServer.java
new file mode 100644
index 0000000..8bdb740
--- /dev/null
+++ b/JmeTests/src/jme3test/network/TestChatServer.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2011 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.network;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.jme3.network.*;
+import com.jme3.network.serializing.Serializable;
+import com.jme3.network.serializing.Serializer;
+import java.io.IOException;
+
+/**
+ * A simple test chat server. When SM implements a set
+ * of standard chat classes this can become a lot simpler.
+ *
+ * @version $Revision$
+ * @author Paul Speed
+ */
+public class TestChatServer {
+ // Normally these and the initialized method would
+ // be in shared constants or something.
+
+ public static final String NAME = "Test Chat Server";
+ public static final int VERSION = 1;
+ public static final int PORT = 5110;
+ public static final int UDP_PORT = 5110;
+
+ private Server server;
+ private boolean isRunning;
+
+ public TestChatServer() throws IOException {
+
+ // Use this to test the client/server name version check
+ this.server = Network.createServer(NAME, VERSION, PORT, UDP_PORT);
+
+ // Initialize our own messages only after the server has been created.
+ // It registers some additional messages with the serializer by default
+ // that need to go before custom messages.
+ initializeClasses();
+
+ ChatHandler handler = new ChatHandler();
+ server.addMessageListener(handler, ChatMessage.class);
+
+ server.addConnectionListener(new ChatConnectionListener());
+ }
+
+ public boolean isRunning() {
+ return isRunning;
+ }
+
+ public synchronized void start() {
+ if( isRunning ) {
+ return;
+ }
+ server.start();
+ isRunning = true;
+ }
+
+ public synchronized void close() {
+ if( !isRunning ) {
+ return;
+ }
+
+ // Gracefully let any connections know that the server is
+ // going down. Without this, their connections will simply
+ // error out.
+ for( HostedConnection conn : server.getConnections() ) {
+ conn.close("Server is shutting down.");
+ }
+ try {
+ Thread.sleep(1000); // wait a couple beats to let the messages go out
+ } catch( InterruptedException e ) {
+ e.printStackTrace();
+ }
+
+ server.close();
+ isRunning = false;
+ notifyAll();
+ }
+
+ protected void runCommand( HostedConnection conn, String user, String command ) {
+ if( "/shutdown".equals(command) ) {
+ server.broadcast(new ChatMessage("server", "Server is shutting down."));
+ close();
+ } else if( "/help".equals(command) ) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Chat commands:\n");
+ sb.append("/help - prints this message.\n");
+ sb.append("/shutdown - shuts down the server.");
+ server.broadcast(new ChatMessage("server", sb.toString()));
+ }
+ }
+
+ public static void initializeClasses() {
+ // Doing it here means that the client code only needs to
+ // call our initialize.
+ Serializer.registerClass(ChatMessage.class);
+ }
+
+ public static void main(String... args) throws Exception {
+
+ // Increate the logging level for networking...
+ System.out.println("Setting logging to max");
+ Logger networkLog = Logger.getLogger("com.jme3.network");
+ networkLog.setLevel(Level.FINEST);
+
+ // And we have to tell JUL's handler also
+ // turn up logging in a very convoluted way
+ Logger rootLog = Logger.getLogger("");
+ if( rootLog.getHandlers().length > 0 ) {
+ rootLog.getHandlers()[0].setLevel(Level.FINEST);
+ }
+
+ TestChatServer chatServer = new TestChatServer();
+ chatServer.start();
+
+ System.out.println("Waiting for connections on port:" + PORT);
+
+ // Keep running basically forever
+ while( chatServer.isRunning ) {
+ synchronized (chatServer) {
+ chatServer.wait();
+ }
+ }
+ }
+
+ private class ChatHandler implements MessageListener {
+
+ public ChatHandler() {
+ }
+
+ @Override
+ public void messageReceived(HostedConnection source, Message m) {
+ if (m instanceof ChatMessage) {
+ // Keep track of the name just in case we
+ // want to know it for some other reason later and it's
+ // a good example of session data
+ ChatMessage cm = (ChatMessage)m;
+ source.setAttribute("name", cm.getName());
+
+ // Check for a / command
+ if( cm.message.startsWith("/") ) {
+ runCommand(source, cm.name, cm.message);
+ return;
+ }
+
+ System.out.println("Broadcasting:" + m + " reliable:" + m.isReliable());
+
+ // Just rebroadcast... the reliable flag will stay the
+ // same so if it came in on UDP it will go out on that too
+ source.getServer().broadcast(cm);
+ } else {
+ System.err.println("Received odd message:" + m);
+ }
+ }
+ }
+
+ private class ChatConnectionListener implements ConnectionListener {
+
+ @Override
+ public void connectionAdded( Server server, HostedConnection conn ) {
+ System.out.println("connectionAdded(" + conn + ")");
+ }
+
+ @Override
+ public void connectionRemoved(Server server, HostedConnection conn) {
+ System.out.println("connectionRemoved(" + conn + ")");
+ }
+
+ }
+
+ @Serializable
+ public static class ChatMessage extends AbstractMessage {
+
+ private String name;
+ private String message;
+
+ public ChatMessage() {
+ }
+
+ public ChatMessage(String name, String message) {
+ setName(name);
+ setMessage(message);
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setMessage(String s) {
+ this.message = s;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ @Override
+ public String toString() {
+ return name + ":" + message;
+ }
+ }
+}
diff --git a/JmeTests/src/jme3test/network/TestLatency.java b/JmeTests/src/jme3test/network/TestLatency.java
new file mode 100644
index 0000000..c47ae05
--- /dev/null
+++ b/JmeTests/src/jme3test/network/TestLatency.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2009-2018 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.network;
+
+import com.jme3.network.*;
+import com.jme3.network.serializing.Serializable;
+import com.jme3.network.serializing.Serializer;
+import java.io.IOException;
+
+public class TestLatency {
+
+ private static long startTime;
+ private static Client client;
+ private static MovingAverage average = new MovingAverage(100);
+
+ static {
+ startTime = System.currentTimeMillis();
+ }
+
+ private static long getTime(){
+ return System.currentTimeMillis() - startTime;
+ }
+
+ @Serializable
+ public static class TimestampMessage extends AbstractMessage {
+
+ long timeSent = 0;
+ long timeReceived = 0;
+
+ public TimestampMessage(){
+ setReliable(false);
+ }
+
+ public TimestampMessage(long timeSent, long timeReceived){
+ setReliable(false);
+ this.timeSent = timeSent;
+ this.timeReceived = timeReceived;
+ }
+
+ }
+
+ public static void main(String[] args) throws IOException, InterruptedException{
+ Serializer.registerClass(TimestampMessage.class);
+
+ Server server = Network.createServer(5110);
+ server.start();
+
+ client = Network.connectToServer("localhost", 5110);
+ client.start();
+
+ client.addMessageListener(new MessageListener(){
+ public void messageReceived(Client source, Message m) {
+ TimestampMessage timeMsg = (TimestampMessage) m;
+
+ long curTime = getTime();
+ //System.out.println("Time sent: " + timeMsg.timeSent);
+ //System.out.println("Time received by server: " + timeMsg.timeReceived);
+ //System.out.println("Time received by client: " + curTime);
+
+ long latency = (curTime - timeMsg.timeSent);
+ System.out.println("Latency: " + (latency) + " ms");
+ //long timeOffset = ((timeMsg.timeSent + curTime) / 2) - timeMsg.timeReceived;
+ //System.out.println("Approximate timeoffset: "+ (timeOffset) + " ms");
+
+ average.add(latency);
+ System.out.println("Average latency: " + average.getAverage());
+
+ long latencyOffset = latency - average.getAverage();
+ System.out.println("Latency offset: " + latencyOffset);
+
+ client.send(new TimestampMessage(getTime(), 0));
+ }
+ }, TimestampMessage.class);
+
+ server.addMessageListener(new MessageListener(){
+ public void messageReceived(HostedConnection source, Message m) {
+ TimestampMessage timeMsg = (TimestampMessage) m;
+ TimestampMessage outMsg = new TimestampMessage(timeMsg.timeSent, getTime());
+ source.send(outMsg);
+ }
+ }, TimestampMessage.class);
+
+ Thread.sleep(1);
+
+ client.send(new TimestampMessage(getTime(), 0));
+
+ Object obj = new Object();
+ synchronized(obj){
+ obj.wait();
+ }
+ }
+
+}
diff --git a/JmeTests/src/jme3test/network/TestMessages.java b/JmeTests/src/jme3test/network/TestMessages.java
new file mode 100644
index 0000000..361f097
--- /dev/null
+++ b/JmeTests/src/jme3test/network/TestMessages.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.network;
+
+import com.jme3.network.*;
+import com.jme3.network.serializing.Serializable;
+import com.jme3.network.serializing.Serializer;
+import java.io.IOException;
+
+public class TestMessages {
+
+ @Serializable
+ public static class PingMessage extends AbstractMessage {
+ }
+
+ @Serializable
+ public static class PongMessage extends AbstractMessage {
+ }
+
+ private static class ServerPingResponder implements MessageListener {
+ public void messageReceived(HostedConnection source, com.jme3.network.Message message) {
+ if (message instanceof PingMessage){
+ System.out.println("Server: Received ping message!");
+ source.send(new PongMessage());
+ }
+ }
+ }
+
+ private static class ClientPingResponder implements MessageListener {
+ public void messageReceived(Client source, com.jme3.network.Message message) {
+ if (message instanceof PongMessage){
+ System.out.println("Client: Received pong message!");
+ }
+ }
+ }
+
+ public static void main(String[] args) throws IOException, InterruptedException{
+ Serializer.registerClass(PingMessage.class);
+ Serializer.registerClass(PongMessage.class);
+
+ Server server = Network.createServer(5110);
+ server.start();
+
+ Client client = Network.connectToServer("localhost", 5110);
+ client.start();
+
+ server.addMessageListener(new ServerPingResponder(), PingMessage.class);
+ client.addMessageListener(new ClientPingResponder(), PongMessage.class);
+
+ System.out.println("Client: Sending ping message..");
+ client.send(new PingMessage());
+
+ Object obj = new Object();
+ synchronized (obj){
+ obj.wait();
+ }
+ }
+}
diff --git a/JmeTests/src/jme3test/network/TestNetworkStress.java b/JmeTests/src/jme3test/network/TestNetworkStress.java
new file mode 100644
index 0000000..dab33c5
--- /dev/null
+++ b/JmeTests/src/jme3test/network/TestNetworkStress.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.network;
+
+import com.jme3.network.*;
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class TestNetworkStress implements ConnectionListener {
+
+ public void connectionAdded(Server server, HostedConnection conn) {
+ System.out.println("Client Connected: "+conn.getId());
+ //conn.close("goodbye");
+ }
+
+ public void connectionRemoved(Server server, HostedConnection conn) {
+ }
+
+ public static void main(String[] args) throws IOException, InterruptedException{
+ Logger.getLogger("").getHandlers()[0].setLevel(Level.OFF);
+
+ Server server = Network.createServer(5110);
+ server.start();
+ server.addConnectionListener(new TestNetworkStress());
+
+ for (int i = 0; i < 1000; i++){
+ Client client = Network.connectToServer("localhost", 5110);
+ client.start();
+
+ Thread.sleep(10);
+
+ client.close();
+ }
+ }
+}
diff --git a/JmeTests/src/jme3test/network/TestRemoteCall.java b/JmeTests/src/jme3test/network/TestRemoteCall.java
new file mode 100644
index 0000000..4335bb3
--- /dev/null
+++ b/JmeTests/src/jme3test/network/TestRemoteCall.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.network;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.export.Savable;
+import com.jme3.network.Client;
+import com.jme3.network.Network;
+import com.jme3.network.Server;
+import com.jme3.network.rmi.ObjectStore;
+import com.jme3.network.serializing.Serializer;
+import com.jme3.network.serializing.serializers.SavableSerializer;
+import com.jme3.scene.Spatial;
+import java.io.IOException;
+import java.util.concurrent.Callable;
+
+public class TestRemoteCall {
+
+ private static SimpleApplication serverApp;
+
+ /**
+ * Interface implemented by the server, exposing
+ * RMI calls that clients can use.
+ */
+ public static interface ServerAccess {
+ /**
+ * Attaches the model with the given name to the server's scene.
+ *
+ * @param model The model name
+ *
+ * @return True if the model was attached.
+ *
+ * @throws RuntimeException If some error occurs.
+ */
+ public boolean attachChild(String model);
+ }
+
+ public static class ServerAccessImpl implements ServerAccess {
+ public boolean attachChild(String model) {
+ if (model == null)
+ throw new RuntimeException("Cannot be null. .. etc");
+
+ final String finalModel = model;
+ serverApp.enqueue(new Callable() {
+ public Void call() throws Exception {
+ Spatial spatial = serverApp.getAssetManager().loadModel(finalModel);
+ serverApp.getRootNode().attachChild(spatial);
+ return null;
+ }
+ });
+ return true;
+ }
+ }
+
+ public static void createServer(){
+ serverApp = new SimpleApplication() {
+ @Override
+ public void simpleInitApp() {
+ }
+ };
+ serverApp.start();
+
+ try {
+ Server server = Network.createServer(5110);
+ server.start();
+
+ ObjectStore store = new ObjectStore(server);
+ store.exposeObject("access", new ServerAccessImpl());
+ } catch (IOException ex) {
+ ex.printStackTrace();
+ }
+ }
+
+ public static void main(String[] args) throws IOException, InterruptedException{
+ Serializer.registerClass(Savable.class, new SavableSerializer());
+
+ createServer();
+
+ Client client = Network.connectToServer("localhost", 5110);
+ client.start();
+
+ ObjectStore store = new ObjectStore(client);
+ ServerAccess access = store.getExposedObject("access", ServerAccess.class, true);
+ boolean result = access.attachChild("Models/Oto/Oto.mesh.xml");
+ System.out.println(result);
+ }
+}
diff --git a/JmeTests/src/jme3test/network/TestSerialization.java b/JmeTests/src/jme3test/network/TestSerialization.java
new file mode 100644
index 0000000..cbdeb66
--- /dev/null
+++ b/JmeTests/src/jme3test/network/TestSerialization.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package jme3test.network;
+
+import com.jme3.network.*;
+import com.jme3.network.serializing.Serializable;
+import com.jme3.network.serializing.Serializer;
+import java.io.IOException;
+import java.util.*;
+
+public class TestSerialization implements MessageListener {
+
+ @Serializable
+ public static class SomeObject {
+
+ private int val;
+
+ public SomeObject(){
+ }
+
+ public SomeObject(int val){
+ this.val = val;
+ }
+
+ public int getVal(){
+ return val;
+ }
+
+ @Override
+ public String toString(){
+ return "SomeObject[val="+val+"]";
+ }
+ }
+
+ public enum Status {
+ High,
+ Middle,
+ Low;
+ }
+
+ @Serializable
+ public static class TestSerializationMessage extends AbstractMessage {
+
+ boolean z;
+ byte b;
+ char c;
+ short s;
+ int i;
+ float f;
+ long l;
+ double d;
+
+ int[] ia;
+ List