|
@@ -1,22 +1,22 @@
|
|
|
/*
|
|
|
* Copyright (c) 2003-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
|
|
@@ -31,14 +31,10 @@
|
|
|
*/
|
|
|
package com.jme3.gde.core.util;
|
|
|
|
|
|
-import com.jme3.animation.AnimControl;
|
|
|
-import com.jme3.animation.SkeletonControl;
|
|
|
-import com.jme3.gde.core.scene.ApplicationLogHandler.LogLevel;
|
|
|
-import com.jme3.scene.Geometry;
|
|
|
-import com.jme3.scene.Node;
|
|
|
+import com.jme3.anim.AnimComposer;
|
|
|
import com.jme3.scene.SceneGraphVisitor;
|
|
|
-import com.jme3.scene.SceneGraphVisitorAdapter;
|
|
|
import com.jme3.scene.Spatial;
|
|
|
+
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.concurrent.atomic.AtomicBoolean;
|
|
|
import java.util.logging.Level;
|
|
@@ -54,10 +50,9 @@ import java.util.logging.Logger;
|
|
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
|
|
public class SpatialUtil {
|
|
|
|
|
|
- private static final Logger logger = Logger.getLogger(SpatialUtil.class.getName());
|
|
|
- //TODO: use these variables
|
|
|
- public static final String ORIGINAL_NAME = "ORIGINAL_NAME";
|
|
|
- public static final String ORIGINAL_PATH = "ORIGINAL_PATH";
|
|
|
+ private static final Logger logger =
|
|
|
+ Logger.getLogger(SpatialUtil.class.getName());
|
|
|
+
|
|
|
|
|
|
/**
|
|
|
* Gets a "pathname" for the given Spatial, combines the Spatials and
|
|
@@ -103,10 +98,12 @@ public class SpatialUtil {
|
|
|
geomName = "null";
|
|
|
}
|
|
|
geom.setUserData("ORIGINAL_NAME", geomName);
|
|
|
- logger.log(Level.FINE, "Set ORIGINAL_NAME for {0}", geomName);
|
|
|
+ logger.log(Level.FINE, "Set ORIGINAL_NAME for {0}",
|
|
|
+ geomName);
|
|
|
String id = SpatialUtil.getSpatialPath(curSpat);
|
|
|
if (geomMap.contains(id)) {
|
|
|
- logger.log(Level.WARNING, "Cannot create unique name for Spatial {0}: {1}", new Object[]{geom, id});
|
|
|
+ logger.log(Level.WARNING, "Cannot create unique name " +
|
|
|
+ "for Spatial {0}: {1}", new Object[]{geom, id});
|
|
|
}
|
|
|
geomMap.add(id);
|
|
|
geom.setUserData("ORIGINAL_PATH", id);
|
|
@@ -114,231 +111,13 @@ public class SpatialUtil {
|
|
|
}
|
|
|
});
|
|
|
} else {
|
|
|
- logger.log(Level.SEVERE, "No Spatial available when trying to add Spatial paths.");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Finds a previously marked spatial in the supplied root Spatial, creates
|
|
|
- * the name and path to be looked for from the given needle Spatial.
|
|
|
- *
|
|
|
- * @param root
|
|
|
- * @param needle
|
|
|
- * @return
|
|
|
- */
|
|
|
- public static Spatial findTaggedSpatial(final Spatial root, final Spatial needle) {
|
|
|
- if (needle == null) {
|
|
|
- logger.log(Level.WARNING, "Trying to find null needle for {0}", root);
|
|
|
- return null;
|
|
|
- }
|
|
|
- final String name = needle.getName();
|
|
|
- final String path = getSpatialPath(needle);
|
|
|
- if (name == null || path == null) {
|
|
|
- logger.log(Level.WARNING, "Trying to find tagged Spatial with null name spatial for {0}.", root);
|
|
|
- return null;
|
|
|
- }
|
|
|
- final Class clazz = needle.getClass();
|
|
|
- String rootName = root.getUserData("ORIGINAL_NAME");
|
|
|
- String rootPath = root.getUserData("ORIGINAL_PATH");
|
|
|
- if (name.equals(rootName) && path.equals(rootPath)) {
|
|
|
- return root;
|
|
|
- }
|
|
|
- final SpatialHolder holder = new SpatialHolder();
|
|
|
- root.depthFirstTraversal(new SceneGraphVisitor() {
|
|
|
- @Override
|
|
|
- public void visit(Spatial spatial) {
|
|
|
- String spName = spatial.getUserData("ORIGINAL_NAME");
|
|
|
- String spPath = spatial.getUserData("ORIGINAL_PATH");
|
|
|
- if (name.equals(spName) && path.equals(spPath) && clazz.isInstance(spatial)) {
|
|
|
- if (holder.spatial == null) {
|
|
|
- holder.spatial = spatial;
|
|
|
- } else {
|
|
|
- logger.log(Level.WARNING, "Found Spatial {0} twice in {1}", new Object[]{path, root});
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
- return holder.spatial;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Finds a spatial in the given Spatial tree with the specified name and
|
|
|
- * path, the path and name are constructed from the given (sub-)spatial(s)
|
|
|
- * and is not read from the UserData of the objects. This is mainly used to
|
|
|
- * check if the original spatial still exists in the original file.
|
|
|
- *
|
|
|
- * @param root
|
|
|
- * @param name
|
|
|
- * @param path
|
|
|
- */
|
|
|
- public static Spatial findSpatial(final Spatial root, final String name, final String path) {
|
|
|
- if (name == null || path == null) {
|
|
|
- logger.log(Level.WARNING, "Trying to find Spatial with null name spatial for {0}.", root);
|
|
|
- return null;
|
|
|
- }
|
|
|
- if (name.equals(root.getName()) && path.equals(getSpatialPath(root))) {
|
|
|
- return root;
|
|
|
- }
|
|
|
- final SpatialHolder holder = new SpatialHolder();
|
|
|
- root.depthFirstTraversal(new SceneGraphVisitor() {
|
|
|
- @Override
|
|
|
- public void visit(Spatial spatial) {
|
|
|
- if (name.equals(spatial.getName()) && path.equals(getSpatialPath(spatial))) {
|
|
|
- if (holder.spatial == null) {
|
|
|
- holder.spatial = spatial;
|
|
|
- } else {
|
|
|
- logger.log(Level.WARNING, "Found Spatial {0} twice in {1}", new Object[]{path, root});
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
- return holder.spatial;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Updates the mesh data of existing objects from an original file, adds new
|
|
|
- * nonexisting geometry objects to the root, including their parents if they
|
|
|
- * don't exist.
|
|
|
- *
|
|
|
- * @param root
|
|
|
- * @param original
|
|
|
- */
|
|
|
- public static void updateMeshDataFromOriginal(final Spatial root, final Spatial original) {
|
|
|
- //loop through original to also find new geometry
|
|
|
- original.depthFirstTraversal(new SceneGraphVisitorAdapter() {
|
|
|
- @Override
|
|
|
- public void visit(Geometry geom) {
|
|
|
- //will always return same class type as 2nd param, so casting is safe
|
|
|
- Geometry spat = (Geometry) findTaggedSpatial(root, geom);
|
|
|
- if (spat != null) {
|
|
|
- spat.setMesh(geom.getMesh());
|
|
|
- logger.log(LogLevel.USERINFO, "Updated mesh for Geometry {0}", geom.getName());
|
|
|
- } else {
|
|
|
- addLeafWithNonExistingParents(root, geom);
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- public static void updateMaterialDataFromOriginal(final Spatial root, final Spatial original) {
|
|
|
- //loop through original to also find new geometry
|
|
|
- original.depthFirstTraversal(new SceneGraphVisitorAdapter() {
|
|
|
- @Override
|
|
|
- public void visit(Geometry geom) {
|
|
|
- //will always return same class type as 2nd param, so casting is safe
|
|
|
- Geometry spat = (Geometry) findTaggedSpatial(root, geom);
|
|
|
- if (spat != null && spat.getMaterial() != null && geom.getMaterial() != null) {
|
|
|
- spat.setMaterial(geom.getMaterial());
|
|
|
- logger.log(LogLevel.USERINFO, "Updated material for Geometry {0}", geom.getName());
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Adds a leaf to a spatial, including all nonexisting parents.
|
|
|
- *
|
|
|
- * @param root
|
|
|
- * @param original
|
|
|
- */
|
|
|
- private static void addLeafWithNonExistingParents(Spatial root, Spatial leaf) {
|
|
|
- if (!(root instanceof Node)) {
|
|
|
- logger.log(Level.WARNING, "Cannot add new Leaf {0} to {1}, is not a Node!", new Object[]{leaf.getName(), root.getName()});
|
|
|
- return;
|
|
|
+ logger.log(Level.SEVERE, "No Spatial available when trying to add" +
|
|
|
+ " Spatial paths.");
|
|
|
}
|
|
|
- for (Spatial s = leaf; s.getParent() != null; s = s.getParent()) {
|
|
|
- Spatial parent = s.getParent();
|
|
|
- Spatial other = findTaggedSpatial(root, parent);
|
|
|
- if (other == null) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (other instanceof Node) {
|
|
|
- logger.log(Level.INFO, "Attaching {0} to {1} in root {2} to add leaf {3}", new Object[]{s, other, root, leaf});
|
|
|
- //set original path data to leaf and new parents
|
|
|
- for (Spatial spt = leaf; spt != parent; spt = spt.getParent()) {
|
|
|
- if(spt == null){
|
|
|
- return; // this is to avoid a crash when changing names of meshes externally
|
|
|
- }
|
|
|
- spt.setUserData(ORIGINAL_NAME, spt.getName());
|
|
|
- spt.setUserData(ORIGINAL_PATH, getSpatialPath(spt));
|
|
|
- spt = spt.getParent();
|
|
|
- }
|
|
|
- //attach to new node in own root
|
|
|
- Node otherNode = (Node) other;
|
|
|
- otherNode.attachChild(s);
|
|
|
- logger.log(LogLevel.USERINFO, "Attached Node {0} with leaf {0}", new Object[]{other.getName(), leaf.getName()});
|
|
|
- return;
|
|
|
- } else {
|
|
|
- logger.log(Level.WARNING, "Cannot attach leaf {0} to found spatial {1} in root {2}, not a node.", new Object[]{leaf, other, root});
|
|
|
- }
|
|
|
- }
|
|
|
- logger.log(Level.WARNING, "Could not attach new Leaf {0}, no root node found.", leaf.getName());
|
|
|
- }
|
|
|
-
|
|
|
- public static void updateAnimControlDataFromOriginal(final Spatial root, final Spatial original) {
|
|
|
- //loop through original to also find new AnimControls, we expect all nodes etc. to exist
|
|
|
- //TODO: can (blender) AnimControls end up in other nodes that are not a parent of the geometry they modify?
|
|
|
- removeAnimData(root);
|
|
|
- original.depthFirstTraversal(new SceneGraphVisitor() {
|
|
|
- @Override
|
|
|
- public void visit(Spatial spat) {
|
|
|
- AnimControl animControl = spat.getControl(AnimControl.class);
|
|
|
- if (animControl != null) {
|
|
|
- Spatial mySpatial = findTaggedSpatial(root, spat);
|
|
|
- if (mySpatial != null) {
|
|
|
- //TODO: move attachments: have to scan through all nodes and find the ones
|
|
|
- //where UserData "AttachedBone" == Bone and move it to new Bone
|
|
|
- AnimControl myAnimControl = mySpatial.getControl(AnimControl.class);
|
|
|
- SkeletonControl mySkeletonControl = spat.getControl(SkeletonControl.class);
|
|
|
- if (mySkeletonControl != null) {
|
|
|
- mySpatial.removeControl(mySkeletonControl);
|
|
|
- }
|
|
|
- if (myAnimControl != null) {
|
|
|
- mySpatial.removeControl(myAnimControl);
|
|
|
- }
|
|
|
- AnimControl newControl = (AnimControl) animControl.cloneForSpatial(mySpatial);
|
|
|
- if (mySpatial.getControl(SkeletonControl.class) == null) {
|
|
|
- logger.log(Level.INFO, "Adding control for {0}", mySpatial.getName());
|
|
|
- mySpatial.addControl(newControl);
|
|
|
- } else {
|
|
|
- logger.log(Level.INFO, "Control for {0} was added automatically", mySpatial.getName());
|
|
|
- }
|
|
|
- if (mySpatial.getControl(SkeletonControl.class) == null) {
|
|
|
- if (animControl.getSkeleton() == null) {
|
|
|
- logger.log(Level.INFO, "Could not add a SkeletonControl for {0}, because animControl.getSkeleton() return null. Broken file? Gltf?", mySpatial.getName());
|
|
|
- } else {
|
|
|
- mySpatial.addControl(new SkeletonControl(animControl.getSkeleton()));
|
|
|
- }
|
|
|
- } else {
|
|
|
- logger.log(Level.INFO, "SkeletonControl for {0} was added by AnimControl already", mySpatial.getName());
|
|
|
- }
|
|
|
- logger.log(LogLevel.USERINFO, "Updated animation for {0}", mySpatial.getName());
|
|
|
- } else {
|
|
|
- logger.log(Level.WARNING, "Could not find sibling for {0} in root {1} when trying to apply AnimControl data", new Object[]{spat, root});
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
- //TODO: remove old AnimControls?
|
|
|
}
|
|
|
|
|
|
- public static void removeAnimData(Spatial root) {
|
|
|
- root.depthFirstTraversal(new SceneGraphVisitor() {
|
|
|
- @Override
|
|
|
- public void visit(Spatial spat) {
|
|
|
- AnimControl animControl = spat.getControl(AnimControl.class);
|
|
|
- if (animControl != null) {
|
|
|
- spat.removeControl(animControl);
|
|
|
- SkeletonControl skeletonControl = spat.getControl(SkeletonControl.class);
|
|
|
- if (skeletonControl != null) {
|
|
|
- spat.removeControl(skeletonControl);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- public static void clearRemovedOriginals(final Spatial root, final Spatial original) {
|
|
|
+ public static void clearRemovedOriginals(final Spatial root,
|
|
|
+ final Spatial original) {
|
|
|
//TODO: Clear old stuff at all?
|
|
|
return;
|
|
|
}
|
|
@@ -352,7 +131,7 @@ public class SpatialUtil {
|
|
|
final AtomicBoolean animFound = new AtomicBoolean(false);
|
|
|
root.depthFirstTraversal(new SceneGraphVisitor() {
|
|
|
public void visit(Spatial spatial) {
|
|
|
- if (spatial.getControl(AnimControl.class) != null) {
|
|
|
+ if (spatial.getControl(AnimComposer.class) != null) {
|
|
|
animFound.set(true);
|
|
|
}
|
|
|
}
|
|
@@ -360,8 +139,4 @@ public class SpatialUtil {
|
|
|
return animFound.get();
|
|
|
}
|
|
|
|
|
|
- private static class SpatialHolder {
|
|
|
-
|
|
|
- Spatial spatial;
|
|
|
- }
|
|
|
}
|