From 06f8a00549b56a357f55e2291ba3b123e8dc53a1 Mon Sep 17 00:00:00 2001
From: Stephen Gold <sgold@sonic.net>
Date: Fri, 23 Mar 2018 01:42:08 -0700
Subject: [PATCH] fix JME issue #742 (attachment nodes for ignoreTransform
 geometries)

---
 .../main/java/com/jme3/animation/Bone.java    | 10 +++-
 .../src/main/java/com/jme3/scene/Spatial.java | 47 +++++++++++++++++++
 2 files changed, 56 insertions(+), 1 deletion(-)

diff --git a/jme3-core/src/main/java/com/jme3/animation/Bone.java b/jme3-core/src/main/java/com/jme3/animation/Bone.java
index 6cd751e3c..b60273ecc 100644
--- a/jme3-core/src/main/java/com/jme3/animation/Bone.java
+++ b/jme3-core/src/main/java/com/jme3/animation/Bone.java
@@ -535,11 +535,19 @@ public final class Bone implements Savable, JmeCloneable {
             attachNode.setLocalRotation(modelRot);
             attachNode.setLocalScale(modelScale);
 
+        } else if (targetGeometry.isIgnoreTransform()) {
+            /*
+             * The animated meshes ignore transforms: match the world transform
+             * of the attachments node to the bone's transform.
+             */
+            Transform combined = new Transform(modelPos, modelRot, modelScale);
+            attachNode.setWorldTransform(combined);
+
         } else {
             Spatial loopSpatial = targetGeometry;
             Transform combined = new Transform(modelPos, modelRot, modelScale);
             /*
-             * Climb the scene graph applying local transforms until the 
+             * Climb the scene graph applying local transforms until the
              * attachments node's parent is reached.
              */
             while (loopSpatial != attachParent && loopSpatial != null) {
diff --git a/jme3-core/src/main/java/com/jme3/scene/Spatial.java b/jme3-core/src/main/java/com/jme3/scene/Spatial.java
index c44db734b..ec2d992f7 100644
--- a/jme3-core/src/main/java/com/jme3/scene/Spatial.java
+++ b/jme3-core/src/main/java/com/jme3/scene/Spatial.java
@@ -495,6 +495,53 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
         return worldTransform;
     }
 
+    /**
+     * Alter the local transform so that the world transform approximates the
+     * specified value.
+     *
+     * @param world desired world transform (not null, unaffected)
+     * @throws IllegalArgumentException if the spatial ignores transform OR the
+     * parent's world transform isn't invertible
+     */
+    public void setWorldTransform(Transform world) {
+        if (this instanceof Geometry && ((Geometry) this).ignoreTransform) {
+            throw new RuntimeException("spatial ignores transforms");
+        }
+
+        if (parent == null) {
+            /*
+             * special case: for a root spatial, the world transform is
+             * precisely the local transform
+             */
+            setLocalTransform(world);
+            return;
+        }
+
+        Transform parentTransform = parent.getWorldTransform();
+        Vector3f parentScale = parentTransform.getScale();
+        if (parentScale.x == 0f || parentScale.y == 0f || parentScale.z == 0f) {
+            throw new RuntimeException("parent scale isn't invertible");
+        }
+        Quaternion parentInvRotation = parentTransform.getRotation().inverse();
+        if (parentInvRotation == null) {
+            throw new RuntimeException("parent rotation isn't invertible");
+        }
+        /*
+         * Undo the operations of Transform.combineWithParent()
+         */
+        Transform tmpLocal = world.clone();
+        Vector3f translation = tmpLocal.getTranslation();
+        Quaternion rotation = tmpLocal.getRotation();
+        tmpLocal.getScale().divideLocal(parentScale);
+        parentInvRotation.mult(rotation, rotation);
+        Vector3f parentTranslation = parentTransform.getTranslation();
+        translation.subtractLocal(parentTranslation);
+        parentInvRotation.multLocal(translation);
+        translation.divideLocal(parentScale);
+
+        setLocalTransform(tmpLocal);
+    }
+
     /**
      * <code>rotateUpTo</code> is a utility function that alters the
      * local rotation to point the Y axis in the direction given by newUp.