SDK
- Clean up AssetDataObject / SpatialAssetDataObject / AssetData, add javadoc - Add AssetDataPropertyChangeListener interface and functionality - Improve storage of ORIGINAL_XXX data - Add SpatialUtil git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@10303 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
This commit is contained in:
parent
9a9e9a8d5a
commit
940e5315cf
@ -32,13 +32,16 @@
|
||||
package com.jme3.gde.core.assets;
|
||||
|
||||
import com.jme3.asset.AssetKey;
|
||||
import com.jme3.export.Savable;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.logging.Level;
|
||||
@ -62,6 +65,7 @@ import org.openide.util.Mutex.Action;
|
||||
public class AssetData {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(AssetData.class.getName());
|
||||
private final List<AssetDataPropertyChangeListener> listeners = new ArrayList<AssetDataPropertyChangeListener>();
|
||||
private final Mutex propsMutex = new Mutex();
|
||||
private final Properties props = new Properties();
|
||||
private AssetDataObject file;
|
||||
@ -81,14 +85,28 @@ public class AssetData {
|
||||
this.extension = extension;
|
||||
}
|
||||
|
||||
public void setExtension(String extension) {
|
||||
this.extension = extension;
|
||||
}
|
||||
/**
|
||||
* Sets the extension of the assetData properties file, normally not
|
||||
* necessary to use this, it will be .[originalsuffix]data, for example
|
||||
* .j3odata.
|
||||
*
|
||||
* @param extension
|
||||
*/
|
||||
// public void setExtension(String extension) {
|
||||
// this.extension = extension;
|
||||
// }
|
||||
|
||||
public AssetKey<?> getAssetKey() {
|
||||
return file.getAssetKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the supplied keys data to the assets assetKey so it will be
|
||||
* loaded with these settings next time loadAsset is actually loading the
|
||||
* asset from the ProjectAssetManager.
|
||||
*
|
||||
* @param key
|
||||
*/
|
||||
public void setAssetKey(AssetKey key) {
|
||||
file.setAssetKeyData(key);
|
||||
}
|
||||
@ -101,10 +119,23 @@ public class AssetData {
|
||||
file.setSaveCookie(cookie);
|
||||
}
|
||||
|
||||
public Object loadAsset() {
|
||||
/**
|
||||
* Loads the asset from the DataObject via the ProjectAssetManager in the
|
||||
* lookup. Returns the currently loaded asset when it has been loaded
|
||||
* already, close the asset using closeAsset().
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Savable loadAsset() {
|
||||
return file.loadAsset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves this asset, when a saveExtension is set, saves it as a brother file
|
||||
* with that extension.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public void saveAsset() throws IOException {
|
||||
file.saveAsset();
|
||||
}
|
||||
@ -152,6 +183,7 @@ public class AssetData {
|
||||
}
|
||||
});
|
||||
writeProperties();
|
||||
notifyListeners(key, ret, value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -233,4 +265,25 @@ public class AssetData {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void notifyListeners(String property, String before, String after) {
|
||||
synchronized (listeners) {
|
||||
for (Iterator<AssetDataPropertyChangeListener> it = listeners.iterator(); it.hasNext();) {
|
||||
AssetDataPropertyChangeListener assetDataPropertyChangeListener = it.next();
|
||||
assetDataPropertyChangeListener.assetDataPropertyChanged(property, before, after);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addPropertyChangeListener(AssetDataPropertyChangeListener listener) {
|
||||
synchronized (listeners) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public void removePropertyChangeListener(AssetDataPropertyChangeListener listener) {
|
||||
synchronized (listeners) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,13 +33,16 @@ package com.jme3.gde.core.assets;
|
||||
|
||||
import com.jme3.asset.AssetEventListener;
|
||||
import com.jme3.asset.AssetKey;
|
||||
import com.jme3.asset.BlenderKey;
|
||||
import com.jme3.export.Savable;
|
||||
import com.jme3.export.binary.BinaryExporter;
|
||||
import com.jme3.gde.core.scene.ApplicationLogHandler.LogLevel;
|
||||
import com.jme3.gde.core.scene.SceneApplication;
|
||||
import com.jme3.scene.Spatial;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
@ -75,8 +78,15 @@ import org.openide.util.lookup.ProxyLookup;
|
||||
public class AssetDataObject extends MultiDataObject {
|
||||
|
||||
protected static final Logger logger = Logger.getLogger(AssetDataObject.class.getName());
|
||||
protected final Lookup lookup;
|
||||
protected final InstanceContent lookupContents = new InstanceContent();
|
||||
protected final AbstractLookup contentLookup;
|
||||
protected final Lookup lookup;
|
||||
protected final AssetData assetData;
|
||||
protected final ProjectAssetManager assetManager;
|
||||
protected final AssetListListener listListener;
|
||||
protected final List<FileObject> assetList = new LinkedList<FileObject>();
|
||||
protected final List<AssetKey> assetKeyList = new LinkedList<AssetKey>();
|
||||
protected final List<AssetKey> failedList = new LinkedList<AssetKey>();
|
||||
protected SaveCookie saveCookie = new SaveCookie() {
|
||||
public void save() throws IOException {
|
||||
//TODO: On OpenGL thread? -- safest way.. with get()?
|
||||
@ -92,23 +102,20 @@ public class AssetDataObject extends MultiDataObject {
|
||||
protected AssetKey assetKey;
|
||||
protected Savable savable;
|
||||
protected String saveExtension;
|
||||
protected AbstractLookup contentLookup;
|
||||
protected AssetListListener listListener;
|
||||
protected List<FileObject> assetList = new LinkedList<FileObject>();
|
||||
protected List<AssetKey> assetKeyList = new LinkedList<AssetKey>();
|
||||
protected List<AssetKey> failedList = new LinkedList<AssetKey>();
|
||||
|
||||
public AssetDataObject(FileObject pf, MultiFileLoader loader) throws DataObjectExistsException, IOException {
|
||||
super(pf, loader);
|
||||
contentLookup = new AbstractLookup(getLookupContents());
|
||||
lookupContents.add(new AssetData(this));
|
||||
contentLookup = new AbstractLookup(lookupContents);
|
||||
assetData = new AssetData(this);
|
||||
lookupContents.add(assetData);
|
||||
lookup = new ProxyLookup(getCookieSet().getLookup(), contentLookup);
|
||||
listListener = new AssetListListener(this, assetList, assetKeyList, failedList);
|
||||
assetManager = findAssetManager();
|
||||
//assign savecookie (same as method)
|
||||
setSaveCookie(saveCookie);
|
||||
findAssetManager();
|
||||
}
|
||||
|
||||
protected void findAssetManager() {
|
||||
private ProjectAssetManager findAssetManager() {
|
||||
FileObject file = getPrimaryFile();
|
||||
ProjectManager pm = ProjectManager.getDefault();
|
||||
while (file != null) {
|
||||
@ -119,7 +126,7 @@ public class AssetDataObject extends MultiDataObject {
|
||||
ProjectAssetManager mgr = project.getLookup().lookup(ProjectAssetManager.class);
|
||||
if (mgr != null) {
|
||||
getLookupContents().add(mgr);
|
||||
return;
|
||||
return mgr;
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
@ -128,7 +135,7 @@ public class AssetDataObject extends MultiDataObject {
|
||||
}
|
||||
file = file.getParent();
|
||||
}
|
||||
// getLookupContents().add(new ProjectAssetManager(file.getParent()));
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -163,9 +170,16 @@ public class AssetDataObject extends MultiDataObject {
|
||||
setModified(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the asset from the DataObject via the ProjectAssetManager in the
|
||||
* lookup. Returns the currently loaded asset when it has been loaded
|
||||
* already, close the asset using closeAsset().
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public synchronized Savable loadAsset() {
|
||||
if (isModified() && savable != null) {
|
||||
return savable;
|
||||
if (savable != null) {
|
||||
return (Spatial) savable;
|
||||
}
|
||||
ProjectAssetManager mgr = getLookup().lookup(ProjectAssetManager.class);
|
||||
if (mgr == null) {
|
||||
@ -190,6 +204,12 @@ public class AssetDataObject extends MultiDataObject {
|
||||
return savable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves this asset, when a saveExtension is set, saves it as a brother file
|
||||
* with that extension.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public synchronized void saveAsset() throws IOException {
|
||||
if (savable == null) {
|
||||
logger.log(Level.WARNING, "Trying to write asset failed, asset data null!\nImport failed?");
|
||||
@ -222,14 +242,47 @@ public class AssetDataObject extends MultiDataObject {
|
||||
}
|
||||
}
|
||||
progressHandle.finish();
|
||||
logger.log(LogLevel.USERINFO, "File {0} saved successfully", getPrimaryFile().getNameExt());
|
||||
setModified(false);
|
||||
logger.log(LogLevel.USERINFO, "File {0} saved successfully", getPrimaryFile().getNameExt());
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this asset so that loadAsset will cause it to be loaded
|
||||
*/
|
||||
public synchronized void closeAsset() {
|
||||
ProjectAssetManager mgr = getLookup().lookup(ProjectAssetManager.class);
|
||||
if (mgr != null) {
|
||||
logger.log(Level.INFO, "Closing asset {0}, deleting from cache.", getName());
|
||||
mgr.deleteFromCache(getAssetKey());
|
||||
//delete referenced assets too
|
||||
for (Iterator<AssetKey> it = assetKeyList.iterator(); it.hasNext();) {
|
||||
AssetKey assetKey1 = it.next();
|
||||
mgr.deleteFromCache(assetKey1);
|
||||
}
|
||||
} else {
|
||||
logger.log(Level.WARNING, "Closing asset {0} with no ProjectAssetManager assigned..?", getName());
|
||||
}
|
||||
savable = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the AssetKey of this asset type. When extending AssetDataObject
|
||||
* or a subtype the class should override this so the key type and
|
||||
* properties can be recognized properly:
|
||||
* <pre>
|
||||
* public synchronized MyKeyType getAssetKey() {
|
||||
* //return key if already set
|
||||
* if(super.getAssetKey() instanceof MyKeyType){
|
||||
* return (MyKeyType)assetKey;
|
||||
* }
|
||||
* //set own key type and return
|
||||
* assetKey = new MyKeyType(super.getAssetKey().getName());
|
||||
* return (MyKeyType)assetKey;
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public synchronized AssetKey<?> getAssetKey() {
|
||||
if (assetKey == null) {
|
||||
ProjectAssetManager mgr = getLookup().lookup(ProjectAssetManager.class);
|
||||
@ -242,6 +295,13 @@ public class AssetDataObject extends MultiDataObject {
|
||||
return assetKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the supplied keys data to the assets assetKey so it will be
|
||||
* loaded with these settings next time loadAsset is actually loading the
|
||||
* asset from the ProjectAssetManager.
|
||||
*
|
||||
* @param key
|
||||
*/
|
||||
public synchronized void setAssetKeyData(AssetKey key) {
|
||||
try {
|
||||
BeanUtils.copyProperties(getAssetKey(), key);
|
||||
@ -287,9 +347,9 @@ public class AssetDataObject extends MultiDataObject {
|
||||
if (pm == null || loadingThread != Thread.currentThread()) {
|
||||
return;
|
||||
}
|
||||
FileObject obj = pm.getAssetFileObject(ak);
|
||||
if (obj != null && !assetList.contains(obj)) {
|
||||
assetList.add(obj);
|
||||
FileObject fObj = pm.getAssetFileObject(ak);
|
||||
if (fObj != null && !assetList.contains(fObj)) {
|
||||
assetList.add(fObj);
|
||||
assetKeyList.add(ak);
|
||||
}
|
||||
}
|
||||
@ -299,9 +359,9 @@ public class AssetDataObject extends MultiDataObject {
|
||||
if (pm == null || loadingThread != Thread.currentThread()) {
|
||||
return;
|
||||
}
|
||||
FileObject obj = pm.getAssetFileObject(ak1);
|
||||
if (obj != null && assetList.contains(obj)) {
|
||||
assetList.remove(obj);
|
||||
FileObject fObj = pm.getAssetFileObject(ak1);
|
||||
if (fObj != null && assetList.contains(fObj)) {
|
||||
assetList.remove(fObj);
|
||||
assetKeyList.remove(ak1);
|
||||
}
|
||||
if (!failedList.contains(ak1)) {
|
||||
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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
|
||||
* 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 com.jme3.gde.core.assets;
|
||||
|
||||
/**
|
||||
* Allows listening for property changes in AssetData objects. The call is not
|
||||
* necessarily coming from the main AWT thread but from the import thread.
|
||||
*
|
||||
* @author normenhansen
|
||||
*/
|
||||
public interface AssetDataPropertyChangeListener {
|
||||
|
||||
public void assetDataPropertyChanged(String property, String before, String after);
|
||||
}
|
@ -33,11 +33,9 @@ package com.jme3.gde.core.assets;
|
||||
|
||||
import com.jme3.asset.AssetKey;
|
||||
import com.jme3.asset.ModelKey;
|
||||
import com.jme3.scene.Geometry;
|
||||
import com.jme3.scene.SceneGraphVisitorAdapter;
|
||||
import com.jme3.gde.core.util.SpatialUtil;
|
||||
import com.jme3.scene.Spatial;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.openide.DialogDisplayer;
|
||||
@ -81,7 +79,7 @@ public class SpatialAssetDataObject extends AssetDataObject {
|
||||
|
||||
@Override
|
||||
public synchronized Spatial loadAsset() {
|
||||
if (isModified() && savable != null) {
|
||||
if (savable != null) {
|
||||
return (Spatial) savable;
|
||||
}
|
||||
ProjectAssetManager mgr = getLookup().lookup(ProjectAssetManager.class);
|
||||
@ -98,7 +96,7 @@ public class SpatialAssetDataObject extends AssetDataObject {
|
||||
listListener.stop();
|
||||
savable = spatial;
|
||||
if (!(this instanceof BinaryModelDataObject)) {
|
||||
storeOriginalPathUserData();
|
||||
SpatialUtil.storeOriginalPathUserData(spatial);
|
||||
}
|
||||
lock.releaseLock();
|
||||
return spatial;
|
||||
@ -135,56 +133,15 @@ public class SpatialAssetDataObject extends AssetDataObject {
|
||||
AssetData properties = targetModel.getLookup().lookup(AssetData.class);
|
||||
if (properties != null) {
|
||||
if (properties.getProperty("ORIGINAL_PATH") == null) {
|
||||
properties.setProperty("ORIGINAL_PATH", mgr.getRelativeAssetPath(outFile.getPath()));
|
||||
String path = mgr.getRelativeAssetPath(getPrimaryFile().getPath());
|
||||
properties.setProperty("ORIGINAL_PATH", path);
|
||||
logger.log(Level.INFO, "Set original path for {0} to {1}", new Object[]{getName(), path});
|
||||
}
|
||||
} else {
|
||||
logger.log(Level.WARNING, "New object {0} has no AssetData?", getName());
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Exceptions.printStackTrace(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores ORIGINAL_NAME and ORIGINAL_PATH UserData to all Geometry in
|
||||
* loaded spatial
|
||||
*/
|
||||
protected void storeOriginalPathUserData() {
|
||||
final ArrayList<String> geomMap = new ArrayList<String>();
|
||||
Spatial spat = (Spatial) savable;
|
||||
if (spat != null) {
|
||||
spat.depthFirstTraversal(new SceneGraphVisitorAdapter() {
|
||||
@Override
|
||||
public void visit(Geometry geom) {
|
||||
StringBuilder geometryIdentifier = new StringBuilder();
|
||||
Spatial curSpat = geom;
|
||||
String geomName = curSpat.getName();
|
||||
if (geomName == null) {
|
||||
logger.log(Level.WARNING, "Null geometry name!");
|
||||
geomName = "null";
|
||||
}
|
||||
geom.setUserData("ORIGINAL_NAME", geomName);
|
||||
logger.log(Level.FINE, "Set ORIGINAL_NAME for {0}", geomName);
|
||||
while (curSpat != null) {
|
||||
String name = curSpat.getName();
|
||||
if (name == null) {
|
||||
logger.log(Level.WARNING, "Null spatial name!");
|
||||
name = "null";
|
||||
}
|
||||
geometryIdentifier.insert(0, name);
|
||||
geometryIdentifier.insert(0, '/');
|
||||
curSpat = curSpat.getParent();
|
||||
}
|
||||
String id = geometryIdentifier.toString();
|
||||
if (geomMap.contains(id)) {
|
||||
logger.log(Level.WARNING, "Cannot create unique name for Geometry {0}: {1}", new Object[]{geom, id});
|
||||
}
|
||||
geomMap.add(id);
|
||||
geom.setUserData("ORIGINAL_PATH", id);
|
||||
logger.log(Level.FINE, "Set ORIGINAL_PATH for {0}", id);
|
||||
super.visit(geom);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
logger.log(Level.SEVERE, "No geometry available when trying to scan initial geometry configuration");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
216
sdk/jme3-core/src/com/jme3/gde/core/util/SpatialUtil.java
Normal file
216
sdk/jme3-core/src/com/jme3/gde/core/util/SpatialUtil.java
Normal file
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* 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
|
||||
* 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 com.jme3.gde.core.util;
|
||||
|
||||
import com.jme3.gde.core.scene.ApplicationLogHandler.LogLevel;
|
||||
import com.jme3.scene.Geometry;
|
||||
import com.jme3.scene.SceneGraphVisitor;
|
||||
import com.jme3.scene.SceneGraphVisitorAdapter;
|
||||
import com.jme3.scene.Spatial;
|
||||
import java.util.ArrayList;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Various utilities, mostly for operating on Spatials recursively.
|
||||
*
|
||||
* @author normenhansen
|
||||
*/
|
||||
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";
|
||||
|
||||
/**
|
||||
* Gets a "pathname" for the given Spatial, combines the Spatials and
|
||||
* parents names to make a long name. This "path" is stored in geometry
|
||||
* after the first import for example.
|
||||
*
|
||||
* @param spat
|
||||
* @return
|
||||
*/
|
||||
public static String getSpatialPath(Spatial spat) {
|
||||
StringBuilder geometryIdentifier = new StringBuilder();
|
||||
while (spat != null) {
|
||||
String name = spat.getName();
|
||||
if (name == null) {
|
||||
logger.log(Level.WARNING, "Null spatial name!");
|
||||
name = "null";
|
||||
}
|
||||
geometryIdentifier.insert(0, name);
|
||||
geometryIdentifier.insert(0, '/');
|
||||
spat = spat.getParent();
|
||||
}
|
||||
String id = geometryIdentifier.toString();
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores ORIGINAL_NAME and ORIGINAL_PATH UserData to all Geometry in loaded
|
||||
* spatial
|
||||
*
|
||||
* @param spat
|
||||
*/
|
||||
public static void storeOriginalPathUserData(Spatial spat) {
|
||||
//TODO: only stores for geometry atm
|
||||
final ArrayList<String> geomMap = new ArrayList<String>();
|
||||
if (spat != null) {
|
||||
spat.depthFirstTraversal(new SceneGraphVisitorAdapter() {
|
||||
@Override
|
||||
public void visit(Geometry geom) {
|
||||
Spatial curSpat = geom;
|
||||
String geomName = curSpat.getName();
|
||||
if (geomName == null) {
|
||||
logger.log(Level.WARNING, "Null geometry name!");
|
||||
geomName = "null";
|
||||
}
|
||||
geom.setUserData("ORIGINAL_NAME", 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 Geometry {0}: {1}", new Object[]{geom, id});
|
||||
}
|
||||
geomMap.add(id);
|
||||
geom.setUserData("ORIGINAL_PATH", id);
|
||||
logger.log(Level.FINE, "Set ORIGINAL_PATH for {0}", id);
|
||||
super.visit(geom);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
logger.log(Level.SEVERE, "No geometry available when trying to scan initial geometry configuration");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.INFO, "Trying to find tagged spatial with null name spatial for {0}.", root);
|
||||
}
|
||||
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() {
|
||||
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.equals(root.getName()) && getSpatialPath(root).equals(path)) {
|
||||
return root;
|
||||
}
|
||||
final SpatialHolder holder = new SpatialHolder();
|
||||
root.depthFirstTraversal(new SceneGraphVisitor() {
|
||||
public void visit(Spatial spatial) {
|
||||
if (name.equals(spatial.getName()) && getSpatialPath(spatial).equals(path)) {
|
||||
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;
|
||||
}
|
||||
|
||||
public static void updateOriginalMeshData(final Spatial root, final Spatial original) {
|
||||
original.depthFirstTraversal(new SceneGraphVisitorAdapter() {
|
||||
@Override
|
||||
public void visit(Geometry geom) {
|
||||
//will always return same class type, so casting is safe
|
||||
Geometry spat = (Geometry) findTaggedSpatial(root, geom);
|
||||
if (spat != null) {
|
||||
spat.setMesh(geom.getMesh().deepClone());
|
||||
logger.log(LogLevel.USERINFO, "Updated mesh for geometry {0}", geom.getName());
|
||||
} else {
|
||||
// addNewOriginal()
|
||||
}
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
private void addNewOriginalGeometry(final Spatial root, final Geometry original) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
public void clearRemovedOriginals(final Spatial root, final Spatial original) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
private static class SpatialHolder {
|
||||
|
||||
Spatial spatial;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user