- add texture relocation to Model Import Tool

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@10210 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
nor..67 12 years ago
parent 84183ad154
commit 5e665b6804
  1. 4
      sdk/jme3-model-importer/nbproject/genfiles.properties
  2. 4
      sdk/jme3-model-importer/src/com/jme3/gde/modelimporter/Bundle.properties
  3. 187
      sdk/jme3-model-importer/src/com/jme3/gde/modelimporter/ImportModel.java
  4. 11
      sdk/jme3-model-importer/src/com/jme3/gde/modelimporter/ModelImporterVisualPanel1.java
  5. 16
      sdk/jme3-model-importer/src/com/jme3/gde/modelimporter/ModelImporterVisualPanel3.java
  6. 7
      sdk/jme3-model-importer/src/com/jme3/gde/modelimporter/ModelImporterVisualPanel4.java
  7. 85
      sdk/jme3-model-importer/src/com/jme3/gde/modelimporter/UberAssetLocator.java

@ -1,8 +1,8 @@
build.xml.data.CRC32=35b10250
build.xml.data.CRC32=ea50cec9
build.xml.script.CRC32=b6310686
build.xml.stylesheet.CRC32=a56c6a5b@2.50.1
# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
nbproject/build-impl.xml.data.CRC32=35b10250
nbproject/build-impl.xml.data.CRC32=ea50cec9
nbproject/build-impl.xml.script.CRC32=4db64ed5
nbproject/build-impl.xml.stylesheet.CRC32=238281d1@2.50.1

@ -24,7 +24,7 @@ ModelImporterVisualPanel2.jTextField1.text=/Models/MyModel
ModelImporterVisualPanel2.jCheckBox1.text=copy original model file(s) to project folder
ModelImporterVisualPanel2.jLabel1.text=Import to path:
ModelImporterVisualPanel2.jTextArea1.text=The model will be converted to j3o binary format and copied \nto the project folder including associated texture etc. files.\nThe given path will be used as the root folder for the model.\n\nIf you copy the original model files to the project folder you can re-convert the model at any time by double-clicking it.
ModelImporterVisualPanel1.jTextArea1.text=Note that the following requirements have to be met for a successful import:\n\n* The model format has to be supported\n\n* The model textures have to be in the same folder as the model or a subfolder\n\n* The textures have to be UV mapped textures\n\n* Only diffuse, normal, specular, parallax and light maps will be imported\n\n* No extended material settings will be imported\n\n* For animations be sure to have a single root bone\n\n* For more information press F1
ModelImporterVisualPanel1.jTextArea1.text=Note that the following requirements have to be met for a successful import:\n\n* The model format has to be supported\n\n* The textures have to be UV mapped textures\n\n* Only diffuse, normal, specular, parallax and light maps will be imported\n\n* No extended material settings will be imported\n\n* For animations be sure to have a single root bone\n\n* For more information press F1
ModelImporterVisualPanel2.jLabel1.text_1=Asset List
ModelImporterVisualPanel2.jLabel2.text=Assets failed to load
ModelImporterVisualPanel2.statusLabel.text=jLabel3
@ -36,5 +36,5 @@ ModelImporterVisualPanel3.statusLabel.text_missing=Model loaded, some assets cou
ModelImporterVisualPanel3.statusLabel.text_failed=Model cannot be loaded.
ModelImporterVisualPanel3.infoTextArea.text_1=Import Status Help
ModelImporterVisualPanel3.infoTextArea.text_good=Check if the model looks as expected.\nWith the buttons above you can move the camera.
ModelImporterVisualPanel3.infoTextArea.text_missing=Check if the model looks as expected, some textures fail to load, make sure they are in the same folder or a subfolder of the model. Textures that can not be found will be replaced with a red material.\nYou can also apply textures later by copying them to the project folder and applying them via a j3m material.\nWith the buttons above you can move the camera.
ModelImporterVisualPanel3.infoTextArea.text_missing=Check if the model looks as expected, some textures fail to load. Textures that can not be found will be replaced with a red material.\nYou can also apply textures later by copying them to the project folder and applying them via a j3m material.\nThe UV coords are saved in the mesh so the mapping data will still be available.\nWith the buttons above you can move the camera.
ModelImporterVisualPanel3.infoTextArea.text_failed=This file can not be loaded, it is either in an unsupported format or is incompatible.\nCheck the bottom right corner of the SDK for a little warning sign. If it is there double-click it and report the contained stack trace at jmonkeyengine.org.

@ -11,16 +11,27 @@ import com.jme3.gde.core.assets.AssetData;
import com.jme3.gde.core.assets.BinaryModelDataObject;
import com.jme3.gde.core.assets.ProjectAssetManager;
import com.jme3.gde.core.assets.SpatialAssetDataObject;
import com.jme3.gde.core.util.Beans;
import com.jme3.gde.modelimporter.UberAssetLocator.UberAssetInfo;
import com.jme3.material.MatParam;
import com.jme3.material.Material;
import com.jme3.scene.Geometry;
import com.jme3.scene.SceneGraphVisitorAdapter;
import com.jme3.scene.Spatial;
import com.jme3.shader.VarType;
import com.jme3.texture.Texture;
import java.awt.Component;
import java.awt.Dialog;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Logger;
import java.util.logging.Level;
import javax.swing.JComponent;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory;
@ -28,14 +39,12 @@ import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectInformation;
import org.netbeans.api.project.ui.OpenProjects;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.WizardDescriptor;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.awt.ActionReferences;
import org.openide.awt.ActionRegistration;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.loaders.DataObject;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
@ -54,6 +63,7 @@ displayName = "#CTL_ImportModel")
@SuppressWarnings("unchecked")
public final class ImportModel implements ActionListener {
private static final Logger logger = Logger.getLogger(ImportModel.class.getName());
private Project context;
private WizardDescriptor.Panel[] panels;
@ -115,71 +125,108 @@ public final class ImportModel implements ActionListener {
}
List<FileObject> deleteList = new LinkedList<FileObject>();
int idx = 0;
//go through list and copy assets to project
for (Iterator<FileObject> it = assetList.iterator(); it.hasNext();) {
FileObject source = it.next();
String folderName = importPath + "/" + importManager.getRelativeAssetPath(source.getParent().getPath());
try {
FileObject dest = manager.getAssetFolder().getFileObject(folderName);
if (dest == null) {
dest = FileUtil.createFolder(manager.getAssetFolder(), folderName);
AssetKey key = assetKeys.get(idx);
UberAssetInfo info = UberAssetLocator.getInfo(key);
if (info != null) {
logger.log(Level.INFO, "Found relocation info for {0}", key.getName());
//save texture in Textures folder
int i = 0;
String newTexturePath = importPath + key.getName().replace(key.getFolder(), "");
while (manager.getAssetFolder().getFileObject(newTexturePath) != null) {
i++;
newTexturePath = importPath + i + key.getName().replace(key.getFolder(), "");
}
FileObject fileObj = dest.getFileObject(source.getName(), source.getExt());
if (fileObj != null) {
NotifyDescriptor.Confirmation msg = new NotifyDescriptor.Confirmation(
"File " + source.getNameExt() + " exists, overwrite?",
NotifyDescriptor.YES_NO_OPTION,
NotifyDescriptor.WARNING_MESSAGE);
Object result = DialogDisplayer.getDefault().notify(msg);
if (NotifyDescriptor.YES_OPTION.equals(result)) {
fileObj.delete();
fileObj = source.copy(dest, source.getName(), source.getExt());
} else {
fileObj = null;
}
newTexturePath = new AssetKey(newTexturePath).getName();
FileObject newFile = manager.createAsset(newTexturePath, info.getFileObject());
if (newFile == null) {
logger.log(Level.SEVERE, "Could not create new file {0}", newTexturePath);
} else {
fileObj = source.copy(dest, source.getName(), source.getExt());
info.setNewAssetName(newTexturePath);
logger.log(Level.INFO, "Created relocated texture file {0}", newTexturePath);
}
if (fileObj != null) {
DataObject obj = DataObject.find(fileObj);
AssetData data = obj.getLookup().lookup(AssetData.class);
if (obj instanceof SpatialAssetDataObject) {
// Delete models that are not J3O.
if (!(obj instanceof BinaryModelDataObject)) {
deleteList.add(fileObj);
}
} else if (data != null) {
AssetKey assetKey = data.getAssetKey();
if (!(assetKey instanceof TextureKey)
&& !(assetKey instanceof MaterialKey)) {
// Also delete anything thats not an image or J3M file.
deleteList.add(fileObj);
} else {
try {
String path = importPath + importManager.getRelativeAssetPath(source.getPath());
FileObject fileObj = manager.createAsset(path, source);
//add to delete list if not texture or j3o model
if (fileObj != null) {
logger.log(Level.INFO, "Copied file {0} to {1}", new Object[]{source.getPath(), path});
DataObject obj = DataObject.find(fileObj);
AssetData data = obj.getLookup().lookup(AssetData.class);
if (obj instanceof SpatialAssetDataObject) {
// Delete models that are not J3O.
if (!(obj instanceof BinaryModelDataObject)) {
deleteList.add(fileObj);
logger.log(Level.INFO, "Add file {0} to delete list", path);
}
} else if (data != null) {
AssetKey assetKey = data.getAssetKey();
if (!(assetKey instanceof TextureKey)
&& !(assetKey instanceof MaterialKey)) {
// Also delete anything thats not an image or J3M file.
deleteList.add(fileObj);
logger.log(Level.INFO, "Add file {0} to delete list", path);
}
}
} else {
logger.log(Level.SEVERE, "Error copying file {0} to {1}", new Object[]{source.getPath(), path});
}
} catch (Exception ex) {
Exceptions.printStackTrace(ex);
}
} catch (Exception ex) {
Exceptions.printStackTrace(ex);
}
idx++;
}
//Find original model file
FileObject newFile = manager.getAssetFolder().getFileObject(importPath + modelKey.getName());
if (newFile == null) {
logger.log(Level.SEVERE, "Could not find file {0} after copying to project folder!", importPath + modelKey.getName());
return;
}
FileObject file = manager.getAssetFolder().getFileObject(importPath + "/" + modelKey.getName());
DataObject targetModel;
ProjectAssetManager tempProjectManager = null;
try {
targetModel = DataObject.find(file);
targetModel = DataObject.find(newFile);
if (targetModel instanceof SpatialAssetDataObject) {
//TODO: wtf? why do i have to add the assetmanager?
((SpatialAssetDataObject) targetModel).getLookupContents().add(manager);
AssetData data = targetModel.getLookup().lookup(AssetData.class);
data.setAssetKey(modelKey);
Spatial spat = (Spatial) data.loadAsset();
//Load model
tempProjectManager = targetModel.getLookup().lookup(ProjectAssetManager.class);
if (tempProjectManager != null) {
logger.log(Level.INFO, "Using real ProjectAssetManager for import instatiation.");
} else {
logger.log(Level.WARNING, "Using dummy ProjectAssetManager for import instantiation.");
tempProjectManager = new ProjectAssetManager(manager.getAssetFolder());
((SpatialAssetDataObject) targetModel).getLookupContents().add(tempProjectManager);
}
UberAssetLocator.setAssetBaseFolder(importPath);
//register locator with cached located assets so they can be replaced later
tempProjectManager.registerLocator(importManager.getAssetFolderName(), UberAssetLocator.class);
AssetData targetData = targetModel.getLookup().lookup(AssetData.class);
targetData.setAssetKey(modelKey);
Spatial spat = (Spatial) targetData.loadAsset();
if (spat == null) {
throw new IllegalStateException("Cannot load model after copying!");
}
data.saveAsset();
replaceLocatedTextures(spat, manager);
targetData.saveAsset();
((SpatialAssetDataObject) targetModel).getLookupContents().remove(tempProjectManager);
}
} catch (Exception ex) {
Exceptions.printStackTrace(ex);
} finally {
if (tempProjectManager != null) {
try {
tempProjectManager.unregisterLocator(importManager.getAssetFolderName(), UberAssetLocator.class);
} catch (Exception e) {
Exceptions.printStackTrace(e);
}
}
UberAssetLocator.setAssetBaseFolder(null);
}
//delete files if not keeping original
if (!keepFiles) {
for (Iterator<FileObject> it = deleteList.iterator(); it.hasNext();) {
FileObject fileObject = it.next();
@ -196,6 +243,52 @@ public final class ImportModel implements ActionListener {
importFolder.refresh();
}
private void replaceLocatedTextures(Spatial spat, final ProjectAssetManager mgr) {
spat.depthFirstTraversal(new SceneGraphVisitorAdapter() {
@Override
public void visit(Geometry geom) {
Material mat = geom.getMaterial();
if (mat != null) {
Collection<MatParam> params = mat.getParams();
for (Iterator<MatParam> it = params.iterator(); it.hasNext();) {
MatParam matParam = it.next();
VarType paramType = matParam.getVarType();
String paramName = matParam.getName();
switch (paramType) {
case Texture2D:
case Texture3D:
case TextureArray:
case TextureBuffer:
case TextureCubeMap:
try {
Texture tex = mat.getTextureParam(paramName).getTextureValue();
AssetKey curKey = tex.getKey();
UberAssetInfo newInfo = UberAssetLocator.getInfo(curKey);
if (newInfo != null) {
TextureKey newKey = new TextureKey(newInfo.getNewAssetName());
Beans.copyProperties(curKey, newKey);
Texture texture = mgr.loadTexture(newKey);
if (texture != null) {
mat.setTextureParam(paramName, paramType, texture);
geom.setMaterial(mat);
logger.log(Level.INFO, "Apply relocated texture {0} for {1}", new Object[]{geom, newKey.getName()});
} else {
logger.log(Level.WARNING, "Could not find relocated texture!");
}
}
} catch (Exception ex) {
Exceptions.printStackTrace(ex);
}
break;
default:
}
}
}
super.visit(geom);
}
});
}
/**
* Initialize panels representing individual wizard's steps and sets various
* properties for them influencing wizard appearance.

@ -48,6 +48,10 @@ public final class ModelImporterVisualPanel1 extends JPanel {
}
public void loadSettings(WizardDescriptor wiz) {
}
public void applySettings(WizardDescriptor wiz) {
//reset
wiz.putProperty("path", null);
wiz.putProperty("manager", null);
wiz.putProperty("dataobject", null);
@ -58,9 +62,10 @@ public final class ModelImporterVisualPanel1 extends JPanel {
wiz.putProperty("assetlist", null);
wiz.putProperty("failedlist", null);
wiz.putProperty("model", null);
}
public void applySettings(WizardDescriptor wiz) {
UberAssetLocator.resetLocatedList();
UberAssetLocator.setFindMode(true);
manager.clearCache();
wiz.putProperty("path", currentPath);
wiz.putProperty("manager", manager);
wiz.putProperty("dataobject", dataObject);

@ -50,16 +50,14 @@ public final class ModelImporterVisualPanel3 extends JPanel {
}
public void loadSettings(WizardDescriptor wiz) {
logger.log(Level.INFO, "Start offview panel");
offPanel.startPreview();
jList1.setListData(new Object[0]);
jList2.setListData(new Object[0]);
manager = (ProjectAssetManager) wiz.getProperty("manager");
mainKey = (AssetKey) wiz.getProperty("mainkey");
data = (AssetData) wiz.getProperty("assetdata");
assets = null;
assetKeys = null;
failedKeys = null;
loadModel(mainKey);
loadModel();
if (currentModel != null) {
logger.log(Level.INFO, "Attaching model {0}", currentModel);
offPanel.attach(currentModel);
@ -69,6 +67,7 @@ public final class ModelImporterVisualPanel3 extends JPanel {
}
public void applySettings(WizardDescriptor wiz) {
UberAssetLocator.setFindMode(false);
wiz.putProperty("assetfiles", assets);
wiz.putProperty("assetlist", assetKeys);
wiz.putProperty("failedlist", failedKeys);
@ -77,6 +76,7 @@ public final class ModelImporterVisualPanel3 extends JPanel {
logger.log(Level.INFO, "Detaching model {0}", currentModel);
offPanel.detach(currentModel);
}
logger.log(Level.INFO, "Stop offview panel");
offPanel.stopPreview();
}
@ -84,7 +84,11 @@ public final class ModelImporterVisualPanel3 extends JPanel {
return currentModel != null;
}
public synchronized void loadModel(AssetKey modelKey) {
private void loadModel() {
assets = null;
assetKeys = null;
failedKeys = null;
manager.registerLocator(manager.getAssetFolderName(), UberAssetLocator.class);
try {
currentModel = (Spatial) data.loadAsset();
if (currentModel != null) {
@ -113,7 +117,7 @@ public final class ModelImporterVisualPanel3 extends JPanel {
DialogDisplayer.getDefault().notifyLater(msg);
Exceptions.printStackTrace(e);
}
manager.clearCache();
manager.unregisterLocator(manager.getAssetFolderName(), UberAssetLocator.class);
panel.fireChangeEvent();
}

@ -24,7 +24,12 @@ public final class ModelImporterVisualPanel4 extends JPanel {
}
public void applySettings(WizardDescriptor wiz) {
wiz.putProperty("destpath", jTextField1.getText());
//TODO real check for path!
String path = jTextField1.getText().trim();
if (path != null && !path.endsWith("/")) {
path = path + "/";
}
wiz.putProperty("destpath", path);
wiz.putProperty("keepfiles", jCheckBox1.isSelected());
}

@ -35,12 +35,17 @@ import com.jme3.asset.AssetInfo;
import com.jme3.asset.AssetKey;
import com.jme3.asset.AssetLocator;
import com.jme3.asset.AssetManager;
import com.jme3.asset.TextureKey;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.filechooser.FileFilter;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.filesystems.FileChooserBuilder;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
@ -55,10 +60,30 @@ import org.openide.util.Exceptions;
public class UberAssetLocator implements AssetLocator {
//ugly static due to Locator instantiation
private static final Logger logger = Logger.getLogger(UberAssetLocator.class.getName());
private static final List<UberAssetInfo> locatedAssets = new ArrayList<UberAssetInfo>();
private static boolean findMode = true;
private static String assetBaseFolder;
public static boolean isFindMode() {
return findMode;
}
public static void setFindMode(boolean aFindMode) {
findMode = aFindMode;
}
public static String getAssetBaseFolder() {
return assetBaseFolder;
}
public static void setAssetBaseFolder(String aAssetBaseFolder) {
assetBaseFolder = aAssetBaseFolder;
}
private String rootPath;
public static void resetLocatedList() {
logger.log(Level.INFO, "Clearing asset List");
locatedAssets.clear();
}
@ -66,9 +91,24 @@ public class UberAssetLocator implements AssetLocator {
return new ArrayList<UberAssetInfo>(locatedAssets);
}
private static UberAssetInfo getInfo(AssetKey key) {
public static UberAssetInfo getInfo(AssetKey key) {
if (locatedAssets.isEmpty()) {
logger.log(Level.INFO, "Looking in empty list for {0}", key.getName());
}
for (UberAssetInfo uberAssetInfo : locatedAssets) {
if (uberAssetInfo.getKey().getName().equals(key.getName())) {
String normalName = uberAssetInfo.getKey().getName();
if (assetBaseFolder != null) {
//sanitize filename by creating new asset key
String extendedName = new AssetKey(assetBaseFolder + "/" + normalName).getName();
logger.log(Level.INFO, "Looking for extended name {0}", extendedName);
if (extendedName.equals(key.getName())) {
logger.log(Level.INFO, "Found extended name {0}", extendedName);
return uberAssetInfo;
}
}
logger.log(Level.INFO, "Looking for normal name {0}", normalName);
if (normalName.equals(key.getName())) {
logger.log(Level.INFO, "Found normal name {0}", normalName);
return uberAssetInfo;
}
}
@ -83,17 +123,25 @@ public class UberAssetLocator implements AssetLocator {
}
public AssetInfo locate(AssetManager manager, AssetKey key) {
//we only locate texture keys atm
if (!(key instanceof TextureKey)) {
return null;
}
AssetInfo existing = getInfo(key);
if (existing != null) {
return existing;
}
FileObject file = findFile(key);
if (file == null) {
return null;
if (findMode) {
FileObject file = findFile(key);
if (file == null) {
return null;
}
logger.log(Level.INFO, "Storing location for {0}", key.getName());
UberAssetInfo info = new UberAssetInfo(file, manager, key);
locatedAssets.add(info);
return info;
}
UberAssetInfo info = new UberAssetInfo(file, manager, key);
locatedAssets.add(info);
return info;
return null;
}
private FileObject findFile(AssetKey key) {
@ -101,20 +149,32 @@ public class UberAssetLocator implements AssetLocator {
String rootPath = this.rootPath != null ? this.rootPath.replace("\\", "/") : null;
if (rootPath != null) {
File file = new File(rootPath + "/" + key.getName());
file = FileUtil.normalizeFile(file);
FileObject fileObject = FileUtil.toFileObject(file);
if (fileObject != null) {
logger.log(Level.INFO, "Found file {0}" + fileObject);
return fileObject;
}
}
File file = new File(key.getName());
file = FileUtil.normalizeFile(file);
FileObject fileObject = FileUtil.toFileObject(file);
if (fileObject != null) {
logger.log(Level.INFO, "Found file {0}" + fileObject);
return fileObject;
}
return getUserPath(key);
}
private FileObject getUserPath(AssetKey key) {
NotifyDescriptor.Confirmation msg = new NotifyDescriptor.Confirmation(
"Referenced file " + key.getName() + " cannot be found!\nDo you want to look for it?",
NotifyDescriptor.YES_NO_OPTION,
NotifyDescriptor.WARNING_MESSAGE);
Object result = DialogDisplayer.getDefault().notify(msg);
if (!NotifyDescriptor.YES_OPTION.equals(result)) {
return null;
}
final String ext = key.getExtension();
FileChooserBuilder fcb = new FileChooserBuilder(this.getClass());
fcb.setTitle("Locate " + key.getName());
@ -144,6 +204,7 @@ public class UberAssetLocator implements AssetLocator {
public static class UberAssetInfo extends AssetInfo {
final FileObject file;
String newAssetName;
public UberAssetInfo(FileObject file, AssetManager manager, AssetKey key) {
super(manager, key);
@ -154,6 +215,14 @@ public class UberAssetLocator implements AssetLocator {
return file;
}
public String getNewAssetName() {
return newAssetName;
}
public void setNewAssetName(String newAssetName) {
this.newAssetName = newAssetName;
}
@Override
public InputStream openStream() {
try {

Loading…
Cancel
Save