diff --git a/sdk/jme3-core/src/com/jme3/gde/core/assets/AssetDataObject.java b/sdk/jme3-core/src/com/jme3/gde/core/assets/AssetDataObject.java index e4cb80942..293721102 100644 --- a/sdk/jme3-core/src/com/jme3/gde/core/assets/AssetDataObject.java +++ b/sdk/jme3-core/src/com/jme3/gde/core/assets/AssetDataObject.java @@ -286,7 +286,7 @@ public class AssetDataObject extends MultiDataObject { if (pm == null || loadingThread != Thread.currentThread()) { return; } - FileObject obj = pm.getAssetFolder().getFileObject(ak.getName()); + FileObject obj = pm.getAssetFileObject(ak); if (obj != null && !assetList.contains(obj)) { assetList.add(obj); assetKeyList.add(ak); @@ -298,7 +298,7 @@ public class AssetDataObject extends MultiDataObject { if (pm == null || loadingThread != Thread.currentThread()) { return; } - FileObject obj = pm.getAssetFolder().getFileObject(ak1.getName()); + FileObject obj = pm.getAssetFileObject(ak1); if (obj != null && assetList.contains(obj)) { assetList.remove(obj); assetKeyList.remove(ak1); diff --git a/sdk/jme3-core/src/com/jme3/gde/core/assets/ProjectAssetManager.java b/sdk/jme3-core/src/com/jme3/gde/core/assets/ProjectAssetManager.java index 279362554..ad3d68014 100644 --- a/sdk/jme3-core/src/com/jme3/gde/core/assets/ProjectAssetManager.java +++ b/sdk/jme3-core/src/com/jme3/gde/core/assets/ProjectAssetManager.java @@ -84,7 +84,8 @@ public class ProjectAssetManager extends DesktopAssetManager { private final List folderNames = new LinkedList(); private final List jarItems = new LinkedList(); private URLClassLoader loader; - + private boolean disableAbsolutePaths; + public ProjectAssetManager(Project prj, String folderName) { super(true); this.project = prj; @@ -96,16 +97,28 @@ public class ProjectAssetManager extends DesktopAssetManager { prepAssetEventListeners(); } - public ProjectAssetManager(FileObject path) { + /** + * Creates ProjectAssetManager for dummy projects. + * + * @param path Path on disk to find assets from + * @param disableAbsolutePaths If true, absolute asset paths won't + * be used and the filename is loaded from the path argument directly. + */ + public ProjectAssetManager(FileObject path, boolean disableAbsolutePaths) { super(true); if (path == null) { this.project = new DummyProject(this); } else { this.project = new DummyProject(this, path); } - String string = project.getProjectDirectory().getPath(); - logger.log(Level.INFO, "Add locator: {0}", string); - registerLocator(string, "com.jme3.asset.plugins.FileLocator"); + String projectRootPath = project.getProjectDirectory().getPath(); + logger.log(Level.INFO, "Add locator: {0}", projectRootPath); + this.disableAbsolutePaths = disableAbsolutePaths; + if (disableAbsolutePaths) { + registerLocator(projectRootPath, RelativeOnlyFileLocator.class); + } else { + registerLocator(projectRootPath, "com.jme3.asset.plugins.FileLocator"); + } for (AssetManagerConfigurator di : Lookup.getDefault().lookupAll(AssetManagerConfigurator.class)) { di.prepareManager(this); } @@ -113,7 +126,33 @@ public class ProjectAssetManager extends DesktopAssetManager { } public ProjectAssetManager() { - this(null); + this(null, false); + } + + /** + * If true, then this ProjectAssetManager ignores + * absolute asset paths. + * The assumption that asset paths are present physically under the assets + * folder root does not hold true in this case. + */ + public boolean isAbsolutePathsDisabled() { + return disableAbsolutePaths; + } + + /** + * Returns the FileObject for a given asset key, or null + * if no such asset exists. + * + * @param assetKey The asset key to get the file object for + * @return Either a FileObject for the asset or null if not found. + */ + public FileObject getAssetFileObject(AssetKey assetKey) { + if (isAbsolutePathsDisabled()) { + String fileName = assetKey.getName().substring(assetKey.getFolder().length()); + return getAssetFolder().getFileObject(fileName); + } else { + return getAssetFolder().getFileObject(assetKey.getName()); + } } private void clearClassLoader() { diff --git a/sdk/jme3-core/src/com/jme3/gde/core/assets/RelativeOnlyFileLocator.java b/sdk/jme3-core/src/com/jme3/gde/core/assets/RelativeOnlyFileLocator.java new file mode 100644 index 000000000..28590f140 --- /dev/null +++ b/sdk/jme3-core/src/com/jme3/gde/core/assets/RelativeOnlyFileLocator.java @@ -0,0 +1,122 @@ +/* + * 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 com.jme3.gde.core.assets; + +import com.jme3.asset.AssetInfo; +import com.jme3.asset.AssetKey; +import com.jme3.asset.AssetLoadException; +import com.jme3.asset.AssetLocator; +import com.jme3.asset.AssetManager; +import com.jme3.asset.AssetNotFoundException; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; + +/** + * Special version of FileLocator that cuts off the folder part + * of the path prior to loading it from the folder. + *
+ * E.g. using root = C:\Blah\ and then loading a model that uses + * some texture like Textures/Something/Tex.png + * will actually attempt to load it from + * C:\Blah\Tex.png but the texture will still + * appear to have been loaded from Textures/Something/Tex.png. + * + * @author Kirill Vainer + */ +public class RelativeOnlyFileLocator implements AssetLocator { + + private File root; + + public void setRootPath(String rootPath) { + if (rootPath == null) + throw new NullPointerException(); + + try { + root = new File(rootPath).getCanonicalFile(); + if (!root.isDirectory()){ + throw new IllegalArgumentException("Given root path \"" + root + "\" is not a directory"); + } + } catch (IOException ex) { + throw new AssetLoadException("Root path is invalid", ex); + } + } + + private static class AssetInfoFile extends AssetInfo { + + private File file; + + public AssetInfoFile(AssetManager manager, AssetKey key, File file){ + super(manager, key); + this.file = file; + } + + @Override + public InputStream openStream() { + try{ + return new FileInputStream(file); + }catch (FileNotFoundException ex){ + // NOTE: Can still happen even if file.exists() is true, e.g. + // permissions issue and similar + throw new AssetLoadException("Failed to open file: " + file, ex); + } + } + } + + public AssetInfo locate(AssetManager assetManager, AssetKey assetKey) { + // Load the asset from root, based on the name of the file in the key + // (THIS IS THE ONLY PART THAT DIFFERS FROM FILELOCATOR) + String fileName = assetKey.getName().substring(assetKey.getFolder().length()); + + // This is copied verbatim from FileLocator in the engine. + File file = new File(root, fileName); + if (file.exists() && file.isFile()) { + try { + // Now, check asset name requirements + String canonical = file.getCanonicalPath(); + String absolute = file.getAbsolutePath(); + if (!canonical.endsWith(absolute)) { + throw new AssetNotFoundException("Asset name doesn't match requirements.\n" + + "\"" + canonical + "\" doesn't match \"" + absolute + "\""); + } + } catch (IOException ex) { + throw new AssetLoadException("Failed to get file canonical path " + file, ex); + } + + return new AssetInfoFile(assetManager, assetKey, file); + } else { + return null; + } + } +} diff --git a/sdk/jme3-model-importer/src/com/jme3/gde/modelimporter/ImportModel.java b/sdk/jme3-model-importer/src/com/jme3/gde/modelimporter/ImportModel.java index 91101e284..a5b8638d0 100644 --- a/sdk/jme3-model-importer/src/com/jme3/gde/modelimporter/ImportModel.java +++ b/sdk/jme3-model-importer/src/com/jme3/gde/modelimporter/ImportModel.java @@ -5,8 +5,10 @@ package com.jme3.gde.modelimporter; import com.jme3.asset.AssetKey; +import com.jme3.asset.MaterialKey; import com.jme3.asset.TextureKey; 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.scene.Spatial; @@ -99,12 +101,24 @@ public final class ImportModel implements ActionListener { } } + private String correctImportPathLetterCase(String importPath, List assetKeys) { + for (AssetKey key : assetKeys) { + if (importPath.equalsIgnoreCase(key.getFolder())) { + // Recommend using the folder letter case from asset key. + return key.getFolder(); + } + } + // No assets or none match the path. Use original. + return importPath; + } + private void copyModel(WizardDescriptor wiz) { -// List keyList = (List) wiz.getProperty("assetlist"); // String path = (String) wiz.getProperty("path"); - AssetKey key = (AssetKey) wiz.getProperty("mainkey"); + AssetKey modelKey = (AssetKey) wiz.getProperty("mainkey"); boolean keepFiles = (Boolean) wiz.getProperty("keepfiles"); + List assetList = (List) wiz.getProperty("assetfiles"); + List assetKeys = (List) wiz.getProperty("assetlist"); String importPath = (String) wiz.getProperty("destpath"); Project context = (Project) wiz.getProperty("project"); ProjectAssetManager importManager = (ProjectAssetManager) wiz.getProperty("manager"); @@ -112,11 +126,27 @@ public final class ImportModel implements ActionListener { if (manager == null) { throw new IllegalStateException("Cannot find project AssetManager!"); } + + // Try to correct letter case in import path (this fixes case mismatch issues in Windows) + importPath = correctImportPathLetterCase(importPath, assetKeys); + List deleteList = new LinkedList(); - for (Iterator it = assetList.iterator(); it.hasNext();) { - FileObject source = it.next(); + int i = 0; + for (FileObject source : assetList) { + AssetKey assetKey = assetKeys.get(i++); try { - String folderName = importPath + "/" + importManager.getRelativeAssetPath(source.getParent().getPath()); + String folderName; + // Put it in the user's import path if we use relative paths + // (asset keys have folders) + // or loading the model portion of the asset. + // If we are loading dependent assets of J3O or J3M (absolute paths), + // put them in the expected absolute paths. + if (assetKey.equals(modelKey) || assetKey.getFolder().equals("")) { + folderName = importPath + "/" + importManager.getRelativeAssetPath(source.getParent().getPath()); + } else { + folderName = assetKey.getFolder(); + } + FileObject dest = manager.getAssetFolder().getFileObject(folderName); if (dest == null) { dest = FileUtil.createFolder(manager.getAssetFolder(), folderName); @@ -141,8 +171,14 @@ public final class ImportModel implements ActionListener { DataObject obj = DataObject.find(fileObj); AssetData data = obj.getLookup().lookup(AssetData.class); if (data != null) { - AssetKey assetKey = data.getAssetKey(); - if (!(assetKey instanceof TextureKey)) { + if (obj instanceof SpatialAssetDataObject) { + // Delete models that are not J3O. + if (!(obj instanceof BinaryModelDataObject)) { + deleteList.add(fileObj); + } + } else if (!(assetKey instanceof TextureKey) + && !(assetKey instanceof MaterialKey)) { + // Also delete anything thats not an image or J3M file. deleteList.add(fileObj); } } @@ -152,7 +188,7 @@ public final class ImportModel implements ActionListener { } } - FileObject file = manager.getAssetFolder().getFileObject(importPath + "/" + key.getName()); + FileObject file = manager.getAssetFolder().getFileObject(importPath + "/" + modelKey.getName()); DataObject targetModel; try { targetModel = DataObject.find(file); @@ -160,7 +196,7 @@ public final class ImportModel implements ActionListener { //TODO: wtf? why do i have to add the assetmanager? ((SpatialAssetDataObject) targetModel).getLookupContents().add(manager); AssetData data = targetModel.getLookup().lookup(AssetData.class); - data.setAssetKey(key); + data.setAssetKey(modelKey); Spatial spat = (Spatial) data.loadAsset(); if (spat == null) { throw new IllegalStateException("Cannot load model after copying!"); diff --git a/sdk/jme3-model-importer/src/com/jme3/gde/modelimporter/ModelImporterVisualPanel1.java b/sdk/jme3-model-importer/src/com/jme3/gde/modelimporter/ModelImporterVisualPanel1.java index d2a2a7c22..3fdc4a8dc 100644 --- a/sdk/jme3-model-importer/src/com/jme3/gde/modelimporter/ModelImporterVisualPanel1.java +++ b/sdk/jme3-model-importer/src/com/jme3/gde/modelimporter/ModelImporterVisualPanel1.java @@ -80,7 +80,7 @@ public final class ModelImporterVisualPanel1 extends JPanel { manager = null; dataObject = null; data = null; - manager = new ProjectAssetManager(FileUtil.toFileObject(path).getParent()); + manager = new ProjectAssetManager(FileUtil.toFileObject(path).getParent(), true); try { dataObject = DataObject.find(FileUtil.toFileObject(path)); data = dataObject != null ? dataObject.getLookup().lookup(AssetData.class) : null;