Merge branch 'master' of https://github.com/jMonkeyEngine/jmonkeyengine into GL4ShaderSupport

Conflicts:
	jme3-core/src/main/resources/com/jme3/asset/Desktop.cfg
experimental
michael 10 years ago
commit 5b58bda23f
  1. 111
      jme3-android/src/main/java/com/jme3/asset/AndroidAssetManager.java
  2. 1
      jme3-android/src/main/java/com/jme3/asset/AndroidImageInfo.java
  3. 49
      jme3-android/src/main/java/com/jme3/system/android/JmeAndroidSystem.java
  4. 1
      jme3-android/src/main/java/com/jme3/texture/plugins/AndroidBufferImageLoader.java
  5. 1
      jme3-android/src/main/java/com/jme3/texture/plugins/AndroidImageLoader.java
  6. 8
      jme3-android/src/main/resources/com/jme3/asset/Android.cfg
  7. 8
      jme3-core/src/main/java/com/jme3/animation/AnimControl.java
  8. 20
      jme3-core/src/main/java/com/jme3/app/Application.java
  9. 135
      jme3-core/src/main/java/com/jme3/asset/AssetConfig.java
  10. 160
      jme3-core/src/main/java/com/jme3/asset/AssetManager.java
  11. 185
      jme3-core/src/main/java/com/jme3/asset/DesktopAssetManager.java
  12. 6
      jme3-core/src/main/java/com/jme3/asset/ImplHandler.java
  13. 31
      jme3-core/src/main/java/com/jme3/asset/StreamAssetInfo.java
  14. 5
      jme3-core/src/main/java/com/jme3/asset/cache/WeakRefAssetCache.java
  15. 2
      jme3-core/src/main/java/com/jme3/asset/cache/WeakRefCloneAssetCache.java
  16. 30
      jme3-core/src/main/java/com/jme3/asset/cache/package.html
  17. 10
      jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
  18. 10
      jme3-core/src/main/java/com/jme3/system/JmeSystem.java
  19. 22
      jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java
  20. 5
      jme3-core/src/main/resources/com/jme3/asset/Desktop.cfg
  21. 26
      jme3-core/src/main/resources/com/jme3/asset/General.cfg
  22. 10
      jme3-core/src/plugins/java/com/jme3/asset/plugins/ClasspathLocator.java
  23. 1
      jme3-core/src/plugins/java/com/jme3/asset/plugins/FileLocator.java
  24. 17
      jme3-core/src/plugins/java/com/jme3/asset/plugins/HttpZipLocator.java
  25. 4
      jme3-core/src/plugins/java/com/jme3/asset/plugins/UrlLocator.java
  26. 8
      jme3-core/src/plugins/java/com/jme3/asset/plugins/ZipLocator.java
  27. 80
      jme3-core/src/tools/java/jme3tools/converters/FolderConverter.java
  28. 351
      jme3-core/src/tools/java/jme3tools/converters/model/FloatToFixed.java
  29. 15
      jme3-desktop/src/main/java/com/jme3/system/JmeDesktopSystem.java
  30. 4
      jme3-ios/src/main/java/com/jme3/asset/IOS.cfg
  31. 109
      jme3-ios/src/main/java/com/jme3/system/ios/IosAssetManager.java
  32. 22
      jme3-ios/src/main/java/com/jme3/system/ios/JmeIosSystem.java
  33. 224
      jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/file/FBXDump.java
  34. 11
      jme3-plugins/src/xml/java/com/jme3/export/xml/XMLImporter.java

@ -1,111 +0,0 @@
/*
* Copyright (c) 2009-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.asset;
import com.jme3.asset.plugins.AndroidLocator;
import com.jme3.asset.plugins.ClasspathLocator;
import com.jme3.audio.plugins.AndroidAudioLoader;
import com.jme3.audio.plugins.NativeVorbisLoader;
import com.jme3.audio.plugins.WAVLoader;
import com.jme3.system.AppSettings;
import com.jme3.system.android.JmeAndroidSystem;
import com.jme3.texture.plugins.AndroidBufferImageLoader;
import com.jme3.texture.plugins.AndroidNativeImageLoader;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* <code>AndroidAssetManager</code> is an implementation of DesktopAssetManager for Android
*
* @author larynx
*/
public class AndroidAssetManager extends DesktopAssetManager {
private static final Logger logger = Logger.getLogger(AndroidAssetManager.class.getName());
private void registerLoaderSafe(String loaderClass, String ... extensions) {
try {
Class<? extends AssetLoader> loader = (Class<? extends AssetLoader>) Class.forName(loaderClass);
registerLoader(loader, extensions);
} catch (Exception e){
logger.log(Level.WARNING, "Failed to load AssetLoader", e);
}
}
/**
* AndroidAssetManager constructor
* If URL == null then a default list of locators and loaders for android is set
* @param configFile
*/
public AndroidAssetManager(URL configFile) {
System.setProperty("org.xml.sax.driver", "org.xmlpull.v1.sax2.Driver");
// Set Default Android config
registerLocator("", AndroidLocator.class);
registerLocator("", ClasspathLocator.class);
registerLoader(AndroidNativeImageLoader.class, "jpg", "jpeg", "bmp", "gif", "png");
if (JmeAndroidSystem.getAudioRendererType().equals(AppSettings.ANDROID_MEDIAPLAYER)) {
registerLoader(AndroidAudioLoader.class, "ogg", "mp3", "wav");
} else if (JmeAndroidSystem.getAudioRendererType().equals(AppSettings.ANDROID_OPENAL_SOFT)) {
registerLoader(WAVLoader.class, "wav");
registerLoader(NativeVorbisLoader.class, "ogg");
} else {
throw new IllegalStateException("No Audio Renderer Type defined!");
}
registerLoader(com.jme3.material.plugins.J3MLoader.class, "j3m");
registerLoader(com.jme3.material.plugins.J3MLoader.class, "j3md");
registerLoader(com.jme3.material.plugins.ShaderNodeDefinitionLoader.class, "j3sn");
registerLoader(com.jme3.shader.plugins.GLSLLoader.class, "vert", "frag", "glsl", "glsllib");
registerLoader(com.jme3.export.binary.BinaryImporter.class, "j3o");
registerLoader(com.jme3.font.plugins.BitmapFontLoader.class, "fnt");
// Less common loaders (especially on Android)
registerLoaderSafe("com.jme3.texture.plugins.DDSLoader", "dds");
registerLoaderSafe("com.jme3.texture.plugins.PFMLoader", "pfm");
registerLoaderSafe("com.jme3.texture.plugins.HDRLoader", "hdr");
registerLoaderSafe("com.jme3.texture.plugins.TGALoader", "tga");
registerLoaderSafe("com.jme3.scene.plugins.OBJLoader", "obj");
registerLoaderSafe("com.jme3.scene.plugins.MTLLoader", "mtl");
registerLoaderSafe("com.jme3.scene.plugins.ogre.MeshLoader", "mesh.xml");
registerLoaderSafe("com.jme3.scene.plugins.ogre.SkeletonLoader", "skeleton.xml");
registerLoaderSafe("com.jme3.scene.plugins.ogre.MaterialLoader", "material");
registerLoaderSafe("com.jme3.scene.plugins.ogre.SceneLoader", "scene");
logger.fine("AndroidAssetManager created.");
}
}

@ -20,6 +20,7 @@ import java.util.logging.Logger;
*
* @author Kirill Vainer
*/
@Deprecated
public class AndroidImageInfo extends ImageRaster {
private static final Logger logger = Logger.getLogger(AndroidImageInfo.class.getName());

@ -6,9 +6,6 @@ import android.graphics.Bitmap;
import android.os.Environment;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import com.jme3.asset.AndroidAssetManager;
import com.jme3.asset.AndroidImageInfo;
import com.jme3.asset.AssetManager;
import com.jme3.audio.AudioRenderer;
import com.jme3.audio.android.AndroidAL;
import com.jme3.audio.android.AndroidALC;
@ -19,14 +16,10 @@ import com.jme3.audio.openal.ALC;
import com.jme3.audio.openal.EFX;
import com.jme3.system.*;
import com.jme3.system.JmeContext.Type;
import com.jme3.texture.Image;
import com.jme3.texture.image.DefaultImageRaster;
import com.jme3.texture.image.ImageRaster;
import com.jme3.util.AndroidScreenshots;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
import java.nio.ByteBuffer;
import java.util.logging.Level;
@ -42,6 +35,11 @@ public class JmeAndroidSystem extends JmeSystemDelegate {
}
}
@Override
public String getPlatformAssetConfigPath() {
return "com/jme3/asset/Android.cfg";
}
@Override
public void writeImageFile(OutputStream outStream, String format, ByteBuffer imageData, int width, int height) throws IOException {
Bitmap bitmapImage = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
@ -58,27 +56,6 @@ public class JmeAndroidSystem extends JmeSystemDelegate {
bitmapImage.recycle();
}
@Override
public ImageRaster createImageRaster(Image image, int slice) {
if (image.getEfficentData() != null) {
return (AndroidImageInfo) image.getEfficentData();
} else {
return new DefaultImageRaster(image, slice);
}
}
@Override
public AssetManager newAssetManager(URL configFile) {
logger.log(Level.FINE, "Creating asset manager with config {0}", configFile);
return new AndroidAssetManager(configFile);
}
@Override
public AssetManager newAssetManager() {
logger.log(Level.FINE, "Creating asset manager with default config");
return new AndroidAssetManager(null);
}
@Override
public void showErrorDialog(String message) {
final String finalMsg = message;
@ -122,21 +99,6 @@ public class JmeAndroidSystem extends JmeSystemDelegate {
AL al = new AndroidAL();
EFX efx = new AndroidEFX();
return new ALAudioRenderer(al, alc, efx);
/*
if (settings.getAudioRenderer().equals(AppSettings.ANDROID_MEDIAPLAYER)) {
logger.log(Level.INFO, "newAudioRenderer settings set to Android MediaPlayer / SoundPool");
audioRendererType = AppSettings.ANDROID_MEDIAPLAYER;
return new AndroidMediaPlayerAudioRenderer(activity);
} else if (settings.getAudioRenderer().equals(AppSettings.ANDROID_OPENAL_SOFT)) {
logger.log(Level.INFO, "newAudioRenderer settings set to Android OpenAL Soft");
audioRendererType = AppSettings.ANDROID_OPENAL_SOFT;
return new AndroidMediaPlayerAudioRenderer(activity);
} else {
logger.log(Level.INFO, "AudioRenderer not set. Defaulting to Android MediaPlayer / SoundPool");
audioRendererType = AppSettings.ANDROID_MEDIAPLAYER;
return new AndroidMediaPlayerAudioRenderer(activity);
}
*/
}
@Override
@ -145,6 +107,7 @@ public class JmeAndroidSystem extends JmeSystemDelegate {
return;
}
initialized = true;
System.setProperty("org.xml.sax.driver", "org.xmlpull.v1.sax2.Driver");
logger.log(Level.INFO, getBuildInfo());
}

@ -50,6 +50,7 @@ import java.nio.ByteBuffer;
*
* @author Kirill Vainer
*/
@Deprecated
public class AndroidBufferImageLoader implements AssetLoader {
private final byte[] tempData = new byte[16 * 1024];

@ -8,6 +8,7 @@ import com.jme3.texture.Image;
import com.jme3.texture.image.ColorSpace;
import java.io.IOException;
@Deprecated
public class AndroidImageLoader implements AssetLoader {
public Object load(AssetInfo info) throws IOException {

@ -0,0 +1,8 @@
INCLUDE com/jme3/asset/General.cfg
# Android specific locators
LOCATOR / com.jme3.asset.plugins.AndroidLocator
# Android specific loaders
LOADER com.jme3.texture.plugins.AndroidNativeImageLoader : jpg, bmp, gif, png, jpeg
LOADER com.jme3.audio.plugins.NativeVorbisLoader : ogg

@ -56,12 +56,12 @@ import java.util.Map.Entry;
* 4) Animation event listeners
* 5) Animated model cloning
* 6) Animated model binary import/export
* 7) Hardware skinning
* 8) Attachments
* 9) Add/remove skins
*
* Planned:
* 1) Hardware skinning
* 2) Morph/Pose animation
* 3) Attachments
* 4) Add/remove skins
* 1) Morph/Pose animation
*
* @author Kirill Vainer
*/

@ -174,28 +174,30 @@ public class Application implements SystemListener {
}
private void initAssetManager(){
URL assetCfgUrl = null;
if (settings != null){
String assetCfg = settings.getString("AssetConfigURL");
if (assetCfg != null){
URL url = null;
try {
url = new URL(assetCfg);
assetCfgUrl = new URL(assetCfg);
} catch (MalformedURLException ex) {
}
if (url == null) {
url = Application.class.getClassLoader().getResource(assetCfg);
if (url == null) {
if (assetCfgUrl == null) {
assetCfgUrl = Application.class.getClassLoader().getResource(assetCfg);
if (assetCfgUrl == null) {
logger.log(Level.SEVERE, "Unable to access AssetConfigURL in asset config:{0}", assetCfg);
return;
}
}
assetManager = JmeSystem.newAssetManager(url);
}
}
if (assetCfgUrl == null) {
String assetCfg = JmeSystem.getPlatformAssetConfigPath();
assetCfgUrl = Thread.currentThread().getContextClassLoader().getResource(assetCfg);
}
if (assetManager == null){
assetManager = JmeSystem.newAssetManager(
Thread.currentThread().getContextClassLoader()
.getResource("com/jme3/asset/Desktop.cfg"));
assetManager = JmeSystem.newAssetManager(assetCfgUrl);
}
}

@ -33,6 +33,9 @@ package com.jme3.asset;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Locale;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -42,97 +45,77 @@ import java.util.logging.Logger;
* <br/><br/>
* The config file is specified with the following format:
* <code>
* "INCLUDE" <path>
* "LOADER" <class> : (<extension> ",")* <extension>
* "LOCATOR" <path> <class> : (<extension> ",")* <extension>
* "LOCATOR" <path> <class>
* </code>
*
* @author Kirill Vainer
*/
public class AssetConfig {
public final class AssetConfig {
private AssetManager manager;
private static final Logger logger = Logger.getLogger(AssetConfig.class.getName());
public AssetConfig(AssetManager manager){
this.manager = manager;
}
public void loadText(InputStream in) throws IOException{
Scanner scan = new Scanner(in);
while (scan.hasNext()){
String cmd = scan.next();
if (cmd.equals("LOADER")){
String loaderClass = scan.next();
String colon = scan.next();
if (!colon.equals(":")){
throw new IOException("Expected ':', got '"+colon+"'");
}
String extensionsList = scan.nextLine();
String[] extensions = extensionsList.split(",");
for (int i = 0; i < extensions.length; i++){
extensions[i] = extensions[i].trim();
}
Class clazz = acquireClass(loaderClass);
if (clazz != null) {
manager.registerLoader(clazz, extensions);
} else {
Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Cannot find loader {0}", loaderClass);
}
} else if (cmd.equals("LOCATOR")) {
String rootPath = scan.next();
String locatorClass = scan.nextLine().trim();
Class clazz = acquireClass(locatorClass);
if (clazz != null) {
manager.registerLocator(rootPath, clazz);
} else {
Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Cannot find locator {0}", locatorClass);
}
} else {
throw new IOException("Expected command, got '" + cmd + "'");
}
}
}
private AssetConfig() { }
private Class acquireClass(String name) {
private static Class acquireClass(String name) {
try {
Class clazz = Class.forName(name);
return clazz;
return Class.forName(name);
} catch (ClassNotFoundException ex) {
return null;
}
}
/*
private static String readString(DataInput dataIn) throws IOException{
int length = dataIn.readUnsignedShort();
char[] chrs = new char[length];
for (int i = 0; i < length; i++){
chrs[i] = (char) dataIn.readUnsignedByte();
}
return String.valueOf(chrs);
}
public void loadBinary(DataInput dataIn) throws IOException{
// read signature and version
// how many locator entries?
int locatorEntries = dataIn.readUnsignedShort();
for (int i = 0; i < locatorEntries; i++){
String locatorClazz = readString(dataIn);
String rootPath = readString(dataIn);
manager.registerLocator(rootPath, locatorClazz);
}
int loaderEntries = dataIn.readUnsignedShort();
for (int i = 0; i < loaderEntries; i++){
String loaderClazz = readString(dataIn);
int numExtensions = dataIn.readUnsignedByte();
String[] extensions = new String[numExtensions];
for (int j = 0; j < numExtensions; j++){
extensions[j] = readString(dataIn);
public static void loadText(AssetManager assetManager, URL configUrl) throws IOException{
InputStream in = configUrl.openStream();
try {
Scanner scan = new Scanner(in);
scan.useLocale(Locale.US); // Fix commas / periods ??
while (scan.hasNext()){
String cmd = scan.next();
if (cmd.equals("LOADER")){
String loaderClass = scan.next();
String colon = scan.next();
if (!colon.equals(":")){
throw new IOException("Expected ':', got '"+colon+"'");
}
String extensionsList = scan.nextLine();
String[] extensions = extensionsList.split(",");
for (int i = 0; i < extensions.length; i++){
extensions[i] = extensions[i].trim();
}
Class clazz = acquireClass(loaderClass);
if (clazz != null) {
assetManager.registerLoader(clazz, extensions);
} else {
logger.log(Level.WARNING, "Cannot find loader {0}", loaderClass);
}
} else if (cmd.equals("LOCATOR")) {
String rootPath = scan.next();
String locatorClass = scan.nextLine().trim();
Class clazz = acquireClass(locatorClass);
if (clazz != null) {
assetManager.registerLocator(rootPath, clazz);
} else {
logger.log(Level.WARNING, "Cannot find locator {0}", locatorClass);
}
} else if (cmd.equals("INCLUDE")) {
String includedCfg = scan.nextLine().trim();
URL includedCfgUrl = Thread.currentThread().getContextClassLoader().getResource(includedCfg);
if (includedCfgUrl != null) {
loadText(assetManager, includedCfgUrl);
} else {
logger.log(Level.WARNING, "Cannot find config include {0}", includedCfg);
}
} else if (cmd.trim().startsWith("#")) {
scan.nextLine();
continue;
} else {
throw new IOException("Expected command, got '" + cmd + "'");
}
}
manager.registerLoader(loaderClazz, extensions);
} finally {
if (in != null) in.close();
}
}
*/
}

@ -46,6 +46,8 @@ import com.jme3.shader.ShaderGenerator;
import com.jme3.shader.ShaderKey;
import com.jme3.texture.Texture;
import com.jme3.texture.plugins.TGALoader;
import java.io.IOException;
import java.io.InputStream;
import java.util.EnumSet;
import java.util.List;
@ -75,7 +77,15 @@ import java.util.List;
* <li>{@link TGALoader} - Used to load Targa image files</li>
* </ul>
* <p>
* Once the asset has been loaded,
* Once the asset has been loaded, it will be
* {@link AssetProcessor#postProcess(com.jme3.asset.AssetKey, java.lang.Object)
* post-processed} by the {@link AssetKey#getProcessorType() key's processor}.
* If the key specifies a {@link AssetKey#getCacheType() cache type}, the asset
* will be cached in the specified cache. Next, the {@link AssetProcessor}
* will be requested to {@link AssetProcessor#createClone(java.lang.Object) }
* generate a clone for the asset. Some assets do not require cloning,
* such as immutable or shared assets. Others, like models, must be cloned
* so that modifications to one instance do not leak onto others.
*/
public interface AssetManager {
@ -100,46 +110,13 @@ public interface AssetManager {
*/
public List<ClassLoader> getClassLoaders();
/**
* Registers a loader for the given extensions.
*
* @param loaderClassName
* @param extensions
*
* @deprecated Please use {@link #registerLoader(java.lang.Class, java.lang.String[]) }
* together with {@link Class#forName(java.lang.String) } to find a class
* and then register it.
*
* @deprecated Please use {@link #registerLoader(java.lang.Class, java.lang.String[]) }
* with {@link Class#forName(java.lang.String) } instead.
*/
@Deprecated
public void registerLoader(String loaderClassName, String ... extensions);
/**
* Registers an {@link AssetLocator} by using a class name.
* See the {@link AssetManager#registerLocator(java.lang.String, java.lang.Class) }
* method for more information.
*
* @param rootPath The root path from which to locate assets, this
* depends on the implementation of the asset locator.
* A URL based locator will expect a url folder such as "http://www.example.com/"
* while a File based locator will expect a file path (OS dependent).
* @param locatorClassName The full class name of the {@link AssetLocator}
* implementation.
*
* @deprecated Please use {@link #registerLocator(java.lang.String, java.lang.Class) }
* together with {@link Class#forName(java.lang.String) } to find a class
* and then register it.
*/
@Deprecated
public void registerLocator(String rootPath, String locatorClassName);
/**
* Register an {@link AssetLoader} by using a class object.
*
* @param loaderClass
* @param extensions
* @param loaderClass The loader class to register.
* @param extensions Which extensions this loader is responsible for loading,
* if there are already other loaders registered for that extension, they
* will be overridden - there should only be one loader for each extension.
*/
public void registerLoader(Class<? extends AssetLoader> loaderClass, String ... extensions);
@ -206,18 +183,6 @@ public interface AssetManager {
*/
public void clearAssetEventListeners();
/**
* Set an {@link AssetEventListener} to receive events from this
* <code>AssetManager</code>. Any currently added listeners are
* cleared and then the given listener is added.
*
* @param listener The listener to set
* @deprecated Please use {@link #addAssetEventListener(com.jme3.asset.AssetEventListener) }
* to listen for asset events.
*/
@Deprecated
public void setAssetEventListener(AssetEventListener listener);
/**
* Manually locates an asset with the given {@link AssetKey}.
* This method should be used for debugging or internal uses.
@ -233,6 +198,23 @@ public interface AssetManager {
*/
public AssetInfo locateAsset(AssetKey<?> key);
/**
* Load an asset from an {@link InputStream}.
* In some cases it may be required to load an asset from memory
* or arbitrary streams so that registering a custom locator and key
* type is not necessary.
*
* @param <T> The object type that will be loaded from the AssetKey instance.
* @param key The AssetKey. Note that the asset will not be cached -
* following the same behavior as if {@link AssetKey#getCacheType()} returned null.
* @param inputStream The input stream from which the asset shall be loaded.
* @return The loaded asset.
*
* @throws AssetLoadException If the {@link AssetLoader} has failed
* to load the asset due to an {@link IOException} or another error.
*/
public <T> T loadAssetFromStream(AssetKey<T> key, InputStream inputStream);
/**
* Load an asset from a key, the asset will be located
* by one of the {@link AssetLocator} implementations provided in the
@ -244,17 +226,18 @@ public interface AssetManager {
*
* @param <T> The object type that will be loaded from the AssetKey instance.
* @param key The AssetKey
* @return The loaded asset, or null if it was failed to be located
* or loaded.
* @return The loaded asset.
*
* @throws AssetNotFoundException If all registered locators have failed
* to locate the asset.
* @throws AssetLoadException If the {@link AssetLoader} has failed
* to load the asset due to an {@link IOException} or another error.
*/
public <T> T loadAsset(AssetKey<T> key);
/**
* Load an asset by name, calling this method
* is the same as calling
* <code>
* loadAsset(new AssetKey(name)).
* </code>
* Load an asset by name, calling this method is the same as calling
* <code>loadAsset(new AssetKey(name))</code>.
*
* @param name The name of the asset to load.
* @return The loaded asset, or null if failed to be loaded.
@ -265,7 +248,7 @@ public interface AssetManager {
/**
* Loads texture file, supported types are BMP, JPG, PNG, GIF,
* TGA and DDS.
* TGA, DDS, PFM, and HDR.
*
* @param key The {@link TextureKey} to use for loading.
* @return The loaded texture, or null if failed to be loaded.
@ -276,7 +259,9 @@ public interface AssetManager {
/**
* Loads texture file, supported types are BMP, JPG, PNG, GIF,
* TGA and DDS.
* TGA, DDS, PFM, and HDR.
*
* The texture will be loaded with mip-mapping enabled.
*
* @param name The name of the texture to load.
* @return The texture that was loaded
@ -306,7 +291,8 @@ public interface AssetManager {
/**
* Loads a 3D model with a ModelKey.
* Models can be jME3 object files (J3O) or OgreXML/OBJ files.
* Models can be jME3 object files (J3O), OgreXML (mesh.xml), BLEND, FBX
* and OBJ files.
* @param key Asset key of the model to load
* @return The model that was loaded
*
@ -315,8 +301,9 @@ public interface AssetManager {
public Spatial loadModel(ModelKey key);
/**
* Loads a 3D model. Models can be jME3 object files (J3O) or
* OgreXML/OBJ files.
* Loads a 3D model. Models can be jME3 object files (J3O),
* OgreXML (mesh.xml), BLEND, FBX and OBJ files.
*
* @param name Asset name of the model to load
* @return The model that was loaded
*
@ -381,4 +368,53 @@ public interface AssetManager {
*/
public ShaderGenerator getShaderGenerator(EnumSet<Caps> caps);
/**
* Retrieve an asset from the asset cache.
*
* <b>NOTE:</b> Do <em>not</em> modify the returned asset!
* It is the same reference as what is stored in the cache, therefore any
* modifications to it will leak onto assets loaded from the same key in the future.
*
* @param <T> The object type that will be retrieved from the AssetKey instance.
* @param key The AssetKey to get from the cache.
* @return The cached asset, if found. Otherwise, <code>null</code>.
*
* @throws IllegalArgumentException If {@link AssetKey#getCacheType() caching}
* is disabled for the key.
*/
public <T> T getFromCache(AssetKey<T> key);
/**
* Inject an asset into the asset cache.
*
* <b>NOTE:</b> Do <em>not</em> modify the cached asset after storing!
* It is the same reference as what is stored in the cache, therefore any
* modifications to it will leak onto assets loaded from the same key in the future.
*
* @param <T> The object type of the asset.
* @param key The key where the asset shall be stored.
* @param asset The asset to inject into the cache.
*
* @throws IllegalArgumentException If {@link AssetKey#getCacheType() caching}
* is disabled for the key.
*/
public <T> void addToCache(AssetKey<T> key, T asset);
/**
* Delete an asset from the asset cache.
*
* @param <T> The object type of the AssetKey instance.
* @param key The asset key to remove from the cache.
* @return True if the asset key was found in the cache and was removed
* successfully. False if the asset key was not present in the cache.
*
* @throws IllegalArgumentException If {@link AssetKey#getCacheType() caching}
* is disabled for the key.
*/
public <T> boolean deleteFromCache(AssetKey<T> key);
/**
* Clears the asset cache.
*/
public void clearCache();
}

@ -81,11 +81,6 @@ public class DesktopAssetManager implements AssetManager {
this(null);
}
@Deprecated
public DesktopAssetManager(boolean loadDefaults){
this(Thread.currentThread().getContextClassLoader().getResource("com/jme3/asset/Desktop.cfg"));
}
public DesktopAssetManager(URL configFile){
if (configFile != null){
loadConfigFile(configFile);
@ -93,20 +88,11 @@ public class DesktopAssetManager implements AssetManager {
logger.fine("DesktopAssetManager created.");
}
private void loadConfigFile(URL configFile){
InputStream stream = null;
try{
AssetConfig cfg = new AssetConfig(this);
stream = configFile.openStream();
cfg.loadText(stream);
}catch (IOException ex){
private void loadConfigFile(URL configFile) {
try {
AssetConfig.loadText(this, configFile);
} catch (IOException ex) {
logger.log(Level.SEVERE, "Failed to load asset config", ex);
}finally{
if (stream != null)
try{
stream.close();
}catch (IOException ex){
}
}
}
@ -207,6 +193,7 @@ public class DesktopAssetManager implements AssetManager {
return info;
}
@Override
public <T> T getFromCache(AssetKey<T> key) {
AssetCache cache = handler.getCache(key.getCacheType());
if (cache != null) {
@ -221,6 +208,7 @@ public class DesktopAssetManager implements AssetManager {
}
}
@Override
public <T> void addToCache(AssetKey<T> key, T asset) {
AssetCache cache = handler.getCache(key.getCacheType());
if (cache != null) {
@ -231,6 +219,7 @@ public class DesktopAssetManager implements AssetManager {
}
}
@Override
public <T> boolean deleteFromCache(AssetKey<T> key) {
AssetCache cache = handler.getCache(key.getCacheType());
if (cache != null) {
@ -240,6 +229,7 @@ public class DesktopAssetManager implements AssetManager {
}
}
@Override
public void clearCache(){
handler.clearCache();
if (logger.isLoggable(Level.FINER)){
@ -248,13 +238,110 @@ public class DesktopAssetManager implements AssetManager {
}
/**
* <font color="red">Thread-safe.</font>
* Loads an asset that has already been located.
* @param <T> The asset type
* @param key The asset key
* @param info The AssetInfo from the locator
* @param proc AssetProcessor to use, or null to disable processing
* @param cache The cache to store the asset in, or null to disable caching
* @return The loaded asset
*
* @param <T>
* @param key
* @return the loaded asset
* @throws AssetLoadException If failed to load asset due to exception or
* other error.
*/
public <T> T loadAsset(AssetKey<T> key){
protected <T> T loadLocatedAsset(AssetKey<T> key, AssetInfo info, AssetProcessor proc, AssetCache cache) {
AssetLoader loader = handler.aquireLoader(key);
Object obj;
try {
handler.establishParentKey(key);
obj = loader.load(info);
} catch (IOException ex) {
throw new AssetLoadException("An exception has occured while loading asset: " + key, ex);
} finally {
handler.releaseParentKey(key);
}
if (obj == null) {
throw new AssetLoadException("Error occured while loading asset \""
+ key + "\" using " + loader.getClass().getSimpleName());
} else {
if (logger.isLoggable(Level.FINER)) {
logger.log(Level.FINER, "Loaded {0} with {1}",
new Object[]{key, loader.getClass().getSimpleName()});
}
if (proc != null) {
// do processing on asset before caching
obj = proc.postProcess(key, obj);
}
if (cache != null) {
// At this point, obj should be of type T
cache.addToCache(key, (T) obj);
}
for (AssetEventListener listener : eventListeners) {
listener.assetLoaded(key);
}
return (T) obj;
}
}
/**
* Clones the asset using the given processor and registers the clone
* with the cache.
*
* @param <T> The asset type
* @param key The asset key
* @param obj The asset to clone / register, must implement
* {@link CloneableSmartAsset}.
* @param proc The processor which will generate the clone, cannot be null
* @param cache The cache to register the clone with, cannot be null.
* @return The cloned asset, cannot be the same as the given asset since
* it is a clone.
*
* @throws IllegalStateException If asset does not implement
* {@link CloneableSmartAsset}, if the cache is null, or if the
* processor did not clone the asset.
*/
protected <T> T registerAndCloneSmartAsset(AssetKey<T> key, T obj, AssetProcessor proc, AssetCache cache) {
// object obj is the original asset
// create an instance for user
T clone = (T) obj;
if (proc == null) {
throw new IllegalStateException("Asset implements "
+ "CloneableSmartAsset but doesn't "
+ "have processor to handle cloning");
} else {
clone = (T) proc.createClone(obj);
if (cache != null && clone != obj) {
cache.registerAssetClone(key, clone);
} else {
throw new IllegalStateException("Asset implements "
+ "CloneableSmartAsset but doesn't have cache or "
+ "was not cloned");
}
}
return clone;
}
@Override
public <T> T loadAssetFromStream(AssetKey<T> key, InputStream inputStream) {
if (key == null) {
throw new IllegalArgumentException("key cannot be null");
}
for (AssetEventListener listener : eventListeners){
listener.assetRequested(key);
}
AssetProcessor proc = handler.getProcessor(key.getProcessorType());
StreamAssetInfo info = new StreamAssetInfo(this, key, inputStream);
return loadLocatedAsset(key, info, proc, null);
}
@Override
public <T> T loadAsset(AssetKey<T> key){
if (key == null)
throw new IllegalArgumentException("key cannot be null");
@ -268,7 +355,6 @@ public class DesktopAssetManager implements AssetManager {
Object obj = cache != null ? cache.getFromCache(key) : null;
if (obj == null){
// Asset not in cache, load it from file system.
AssetLoader loader = handler.aquireLoader(key);
AssetInfo info = handler.tryLocate(key);
if (info == null){
if (handler.getParentKey() != null){
@ -283,56 +369,13 @@ public class DesktopAssetManager implements AssetManager {
throw new AssetNotFoundException(key.toString());
}
try {
handler.establishParentKey(key);
obj = loader.load(info);
} catch (IOException ex) {
throw new AssetLoadException("An exception has occured while loading asset: " + key, ex);
} finally {
handler.releaseParentKey(key);
}
if (obj == null){
throw new AssetLoadException("Error occured while loading asset \"" + key + "\" using " + loader.getClass().getSimpleName());
}else{
if (logger.isLoggable(Level.FINER)){
logger.log(Level.FINER, "Loaded {0} with {1}",
new Object[]{key, loader.getClass().getSimpleName()});
}
if (proc != null){
// do processing on asset before caching
obj = proc.postProcess(key, obj);
}
if (cache != null){
// At this point, obj should be of type T
cache.addToCache(key, (T) obj);
}
for (AssetEventListener listener : eventListeners){
listener.assetLoaded(key);
}
}
obj = loadLocatedAsset(key, info, proc, cache);
}
// object obj is the original asset
// create an instance for user
T clone = (T) obj;
if (clone instanceof CloneableSmartAsset){
if (proc == null){
throw new IllegalStateException("Asset implements "
+ "CloneableSmartAsset but doesn't "
+ "have processor to handle cloning");
}else{
clone = (T) proc.createClone(obj);
if (cache != null && clone != obj){
cache.registerAssetClone(key, clone);
} else{
throw new IllegalStateException("Asset implements "
+ "CloneableSmartAsset but doesn't have cache or "
+ "was not cloned");
}
}
if (obj instanceof CloneableSmartAsset) {
clone = registerAndCloneSmartAsset(key, clone, proc, cache);
}
return clone;

@ -204,8 +204,10 @@ public class ImplHandler {
public void clearCache(){
// The iterator of the values collection is thread safe
for (AssetCache cache : classToCacheMap.values()){
cache.clearCache();
synchronized (classToCacheMap) {
for (AssetCache cache : classToCacheMap.values()){
cache.clearCache();
}
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2015 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -29,11 +29,32 @@
* 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.asset;
package jme3tools.converters;
import java.io.InputStream;
import java.util.Map;
/**
* An {@link AssetInfo} wrapper for {@link InputStream InputStreams}.
*
* @author Kirill Vainer
*/
public class StreamAssetInfo extends AssetInfo {
private boolean alreadyOpened;
private final InputStream inputStream;
public StreamAssetInfo(AssetManager assetManager, AssetKey<?> assetKey, InputStream inputStream) {
super(assetManager, assetKey);
this.inputStream = inputStream;
}
@Override
public InputStream openStream() {
if (alreadyOpened) {
throw new IllegalStateException("Stream already opened");
}
alreadyOpened = true;
return inputStream;
}
public interface Converter<T> {
public T convert(T input, Map<String, String> params);
}

@ -77,7 +77,6 @@ public class WeakRefAssetCache implements AssetCache {
// might not even have this asset anymore, it is OK.
if (assetCache.remove(ref.assetKey) != null){
removedAssets ++;
//System.out.println("WeakRefAssetCache: The asset " + ref.assetKey + " was purged from the cache");
}
}
if (removedAssets >= 1) {
@ -92,10 +91,6 @@ public class WeakRefAssetCache implements AssetCache {
// thread is loading an asset with the same key ..
AssetRef ref = new AssetRef(key, obj, refQueue);
assetCache.put(key, ref);
// Texture t = (Texture) obj;
// Image i = t.getImage();
// System.out.println("add to cache " + System.identityHashCode(i));
}
public <T> T getFromCache(AssetKey<T> key) {

@ -42,7 +42,7 @@ import java.util.logging.Level;
import java.util.logging.Logger;
/**
* <codeWeakRefCloneAssetCache</code> caches cloneable assets in a weak-key
* <code>WeakRefCloneAssetCache</code> caches cloneable assets in a weak-key
* cache, allowing them to be collected when memory is low.
* The cache stores weak references to the asset keys, so that
* when all clones of the original asset are collected, will cause the

@ -0,0 +1,30 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<code>com.jme3.asset.cache</code> contains the {@link com.jme3.asset.cache.AssetCache}
interface as well as its implementations.<br>
<p>
<h3>AssetCaches</h3>
The asset cache implementations are used by {@link com.jme3.asset.AssetManager}
to cache loaded assets for faster access if they are requested again.
<p>
Assets in jME3 are cached in such a way that if there are no instances of
that asset anymore in memory, then jME3 is likely to reclaim them.
Some asset types must be cloned prior to being used, for example, 3D models
cannot be stored in the cache as-is, because the user is likely to modify them
after loading them. To handle this, a copy of the asset is stored in the
cache instead. The asset cache that implements these rules is the
{@link com.jme3.asset.cache.WeakRefCloneAssetCache} and it is used
for caching most asset types.
</body>
</html>

@ -863,10 +863,12 @@ public class RenderManager {
private void setViewPort(Camera cam) {
// this will make sure to update viewport only if needed
if (cam != prevCam || cam.isViewportChanged()) {
viewX = (int) (cam.getViewPortLeft() * cam.getWidth());
viewY = (int) (cam.getViewPortBottom() * cam.getHeight());
viewWidth = ((int)(cam.getViewPortRight() * cam.getWidth())) - ((int)(cam.getViewPortLeft() * cam.getWidth()));
viewHeight = ((int)(cam.getViewPortTop() * cam.getHeight())) - ((int)(cam.getViewPortBottom() * cam.getHeight()));
viewX = (int) (cam.getViewPortLeft() * cam.getWidth());
viewY = (int) (cam.getViewPortBottom() * cam.getHeight());
int viewX2 = (int) (cam.getViewPortRight() * cam.getWidth());
int viewY2 = (int) (cam.getViewPortTop() * cam.getHeight());
viewWidth = viewX2 - viewX;
viewHeight = viewY2 - viewY;
uniformBindingManager.setViewPort(viewX, viewY, viewWidth, viewHeight);
renderer.setViewPort(viewX, viewY, viewWidth, viewHeight);
renderer.setClipRect(viewX, viewY, viewWidth, viewHeight);

@ -35,6 +35,7 @@ import com.jme3.asset.AssetManager;
import com.jme3.audio.AudioRenderer;
import com.jme3.input.SoftTextDialogInput;
import com.jme3.texture.Image;
import com.jme3.texture.image.DefaultImageRaster;
import com.jme3.texture.image.ImageRaster;
import java.io.File;
import java.io.IOException;
@ -166,6 +167,15 @@ public class JmeSystem {
return systemDelegate.newAudioRenderer(settings);
}
public static String getPlatformAssetConfigPath() {
checkDelegate();
return systemDelegate.getPlatformAssetConfigPath();
}
/**
* @deprecated Directly create an image raster via {@link DefaultImageRaster}.
*/
@Deprecated
public static ImageRaster createImageRaster(Image image, int slice) {
checkDelegate();
return systemDelegate.createImageRaster(image, slice);

@ -32,9 +32,11 @@
package com.jme3.system;
import com.jme3.asset.AssetManager;
import com.jme3.asset.DesktopAssetManager;
import com.jme3.audio.AudioRenderer;
import com.jme3.input.SoftTextDialogInput;
import com.jme3.texture.Image;
import com.jme3.texture.image.DefaultImageRaster;
import com.jme3.texture.image.ImageRaster;
import java.io.File;
import java.io.IOException;
@ -117,15 +119,25 @@ public abstract class JmeSystemDelegate {
public void setSoftTextDialogInput(SoftTextDialogInput input) {
softTextDialogInput = input;
}
public SoftTextDialogInput getSoftTextDialogInput() {
return softTextDialogInput;
}
public abstract void writeImageFile(OutputStream outStream, String format, ByteBuffer imageData, int width, int height) throws IOException;
public final AssetManager newAssetManager(URL configFile) {
return new DesktopAssetManager(configFile);
}
public abstract AssetManager newAssetManager(URL configFile);
public final AssetManager newAssetManager() {
return new DesktopAssetManager(null);
}
public abstract AssetManager newAssetManager();
@Deprecated
public final ImageRaster createImageRaster(Image image, int slice) {
return new DefaultImageRaster(image, slice);
}
public abstract void writeImageFile(OutputStream outStream, String format, ByteBuffer imageData, int width, int height) throws IOException;
public abstract void showErrorDialog(String message);
@ -181,13 +193,13 @@ public abstract class JmeSystemDelegate {
return sb.toString();
}
public abstract String getPlatformAssetConfigPath();
public abstract JmeContext newContext(AppSettings settings, JmeContext.Type contextType);
public abstract AudioRenderer newAudioRenderer(AppSettings settings);
public abstract void initialize(AppSettings settings);
public abstract ImageRaster createImageRaster(Image image, int slice);
public abstract void showSoftKeyboard(boolean show);
}

@ -1,7 +1,8 @@
LOCATOR / com.jme3.asset.plugins.ClasspathLocator
INCLUDE com/jme3/asset/General.cfg
# Desktop-specific loaders
LOADER com.jme3.texture.plugins.AWTLoader : jpg, bmp, gif, png, jpeg
LOADER com.jme3.audio.plugins.WAVLoader : wav
LOADER com.jme3.audio.plugins.OGGLoader : oggLOADER com.jme3.audio.plugins.WAVLoader : wav
LOADER com.jme3.audio.plugins.OGGLoader : ogg
LOADER com.jme3.cursors.plugins.CursorLoader : ani, cur, ico
LOADER com.jme3.material.plugins.J3MLoader : j3m

@ -0,0 +1,26 @@
# Generic locators that should be supported on all platforms.
LOCATOR / com.jme3.asset.plugins.ClasspathLocator
# Generic loaders that should be supported on all platforms.
LOADER com.jme3.audio.plugins.WAVLoader : wav
LOADER com.jme3.cursors.plugins.CursorLoader : ani, cur, ico
LOADER com.jme3.material.plugins.J3MLoader : j3m
LOADER com.jme3.material.plugins.J3MLoader : j3md
LOADER com.jme3.material.plugins.ShaderNodeDefinitionLoader : j3sn
LOADER com.jme3.font.plugins.BitmapFontLoader : fnt
LOADER com.jme3.texture.plugins.DDSLoader : dds
LOADER com.jme3.texture.plugins.PFMLoader : pfm
LOADER com.jme3.texture.plugins.HDRLoader : hdr
LOADER com.jme3.texture.plugins.TGALoader : tga
LOADER com.jme3.export.binary.BinaryImporter : j3o
LOADER com.jme3.export.binary.BinaryImporter : j3f
LOADER com.jme3.scene.plugins.OBJLoader : obj
LOADER com.jme3.scene.plugins.MTLLoader : mtl
LOADER com.jme3.scene.plugins.ogre.MeshLoader : meshxml, mesh.xml
LOADER com.jme3.scene.plugins.ogre.SkeletonLoader : skeletonxml, skeleton.xml
LOADER com.jme3.scene.plugins.ogre.MaterialLoader : material
LOADER com.jme3.scene.plugins.ogre.SceneLoader : scene
LOADER com.jme3.scene.plugins.blender.BlenderModelLoader : blend
LOADER com.jme3.shader.plugins.GLSLLoader : vert, frag, glsl, glsllib
LOADER com.jme3.scene.plugins.fbx.SceneLoader : fbx
LOADER com.jme3.scene.plugins.fbx.SceneWithAnimationLoader : fba

@ -41,6 +41,16 @@ import java.util.logging.Logger;
/**
* The <code>ClasspathLocator</code> looks up an asset in the classpath.
*
* This locator is used by default in all jME3 projects (unless
* {@link AssetManager#unregisterLocator(java.lang.String, java.lang.Class) unregistered}
* ).
* Unlike Java's default resource loading mechanism, the <code>ClasspathLocator</code>
* enforces case-sensitivity on platforms which do not have it such as Windows.
* Therefore, it is critical to provide a path matching the case of the file on
* the filesystem. This also ensures that the file can be loaded if it was
* later included in a <code>.JAR</code> file instead of a folder.
*
* @author Kirill Vainer
*/
public class ClasspathLocator implements AssetLocator {

@ -37,6 +37,7 @@ import java.io.*;
/**
* <code>FileLocator</code> allows you to specify a folder where to
* look for assets.
*
* @author Kirill Vainer
*/
public class FileLocator implements AssetLocator {

@ -52,6 +52,23 @@ import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;
import java.util.zip.ZipEntry;
/**
* <code>HttpZipLocator</code> is similar to {@link ZipLocator}, except
* it allows loading assets from a <code>.ZIP</code> file on the web instead of
* on the local filesystem.
* <p>
* The root path must be a valid HTTP(S) {@link URL} pointing to ZIP or
* ZIP-like file (such as a JAR). For example,<br>
* <code>https://www.example.com/my/sub/path/assets.zip</code>.
* <p>
* The locator is designed in such a way that it does not require downloading
* the entire <code>.ZIP</code> file from the web in order to load
* assets from it. Instead, the ZIP header is extracted first, and then
* is used to lookup assets from within the ZIP file and download them
* as requested by the user.
*
* @author Kirill Vainer
*/
public class HttpZipLocator implements AssetLocator {
private static final Logger logger = Logger.getLogger(HttpZipLocator.class.getName());

@ -46,6 +46,10 @@ import java.util.logging.Logger;
* <code>UrlLocator</code> is a locator that combines a root URL
* and the given path in the AssetKey to construct a new URL
* that allows locating the asset.
* <p>
* The root path must be a valid {@link URL}, for example, <br>
* <code>https://www.example.com/assets/</code>
*
* @author Kirill Vainer
*/
public class UrlLocator implements AssetLocator {

@ -40,7 +40,13 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
/**
* <code>ZipLocator</code> is a locator that looks up resources in a .ZIP file.
* <code>ZipLocator</code> is a locator that looks up resources in a
* <code>.ZIP</code> file.
*
* The root path must be a valid ZIP or ZIP-like {@link File file},
* for example, <br>
* <code>C:\My App\data.zip</code>
*
* @author Kirill Vainer
*/
public class ZipLocator implements AssetLocator {

@ -1,80 +0,0 @@
/*
* Copyright (c) 2009-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 jme3tools.converters;
import com.jme3.asset.AssetManager;
import com.jme3.system.JmeSystem;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
public class FolderConverter {
private static AssetManager assetManager;
private static File sourceRoot;
private static JarOutputStream jarOut;
private static long time;
private static void process(File file) throws IOException{
String name = file.getName().replaceAll("[\\/\\.]", "_");
JarEntry entry = new JarEntry(name);
entry.setTime(time);
jarOut.putNextEntry(entry);
}
public static void main(String[] args) throws IOException{
if (args.length == 0){
System.out.println("Usage: java -jar FolderConverter <input folder>");
System.out.println();
System.out.println(" Converts files from input to output");
System.exit(1);
}
sourceRoot = new File(args[0]);
File jarFile = new File(sourceRoot.getParent(), sourceRoot.getName()+".jar");
FileOutputStream out = new FileOutputStream(jarFile);
jarOut = new JarOutputStream(out);
assetManager = JmeSystem.newAssetManager();
assetManager.registerLocator(sourceRoot.toString(),
"com.jme3.asset.plugins.FileSystemLocator");
for (File f : sourceRoot.listFiles()){
process(f);
}
}
}

@ -1,351 +0,0 @@
/*
* Copyright (c) 2009-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 jme3tools.converters.model;
import com.jme3.bounding.BoundingBox;
import com.jme3.math.Transform;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.VertexBuffer;
import com.jme3.scene.VertexBuffer.Format;
import com.jme3.scene.VertexBuffer.Type;
import com.jme3.scene.VertexBuffer.Usage;
import com.jme3.scene.mesh.IndexBuffer;
import com.jme3.util.BufferUtils;
import java.nio.*;
@Deprecated
public class FloatToFixed {
private static final float shortSize = Short.MAX_VALUE - Short.MIN_VALUE;
private static final float shortOff = (Short.MAX_VALUE + Short.MIN_VALUE) * 0.5f;
private static final float byteSize = Byte.MAX_VALUE - Byte.MIN_VALUE;
private static final float byteOff = (Byte.MAX_VALUE + Byte.MIN_VALUE) * 0.5f;
@Deprecated
public static void convertToFixed(Geometry geom, Format posFmt, Format nmFmt, Format tcFmt){
geom.updateModelBound();
BoundingBox bbox = (BoundingBox) geom.getModelBound();
Mesh mesh = geom.getMesh();
VertexBuffer positions = mesh.getBuffer(Type.Position);
VertexBuffer normals = mesh.getBuffer(Type.Normal);
VertexBuffer texcoords = mesh.getBuffer(Type.TexCoord);
VertexBuffer indices = mesh.getBuffer(Type.Index);
// positions
FloatBuffer fb = (FloatBuffer) positions.getData();
if (posFmt != Format.Float){
Buffer newBuf = VertexBuffer.createBuffer(posFmt, positions.getNumComponents(),
mesh.getVertexCount());
Transform t = convertPositions(fb, bbox, newBuf);
t.combineWithParent(geom.getLocalTransform());
geom.setLocalTransform(t);
VertexBuffer newPosVb = new VertexBuffer(Type.Position);
newPosVb.setupData(positions.getUsage(),
positions.getNumComponents(),
posFmt,
newBuf);
mesh.clearBuffer(Type.Position);
mesh.setBuffer(newPosVb);
}
// normals, automatically convert to signed byte
fb = (FloatBuffer) normals.getData();
ByteBuffer bb = BufferUtils.createByteBuffer(fb.capacity());
convertNormals(fb, bb);
normals = new VertexBuffer(Type.Normal);
normals.setupData(Usage.Static, 3, Format.Byte, bb);
normals.setNormalized(true);
mesh.clearBuffer(Type.Normal);
mesh.setBuffer(normals);
// texcoords
fb = (FloatBuffer) texcoords.getData();
if (tcFmt != Format.Float){
Buffer newBuf = VertexBuffer.createBuffer(tcFmt,
texcoords.getNumComponents(),
mesh.getVertexCount());
convertTexCoords2D(fb, newBuf);
VertexBuffer newTcVb = new VertexBuffer(Type.TexCoord);
newTcVb.setupData(texcoords.getUsage(),
texcoords.getNumComponents(),
tcFmt,
newBuf);
mesh.clearBuffer(Type.TexCoord);
mesh.setBuffer(newTcVb);
}
}
public static void compressIndexBuffer(Mesh mesh){
int vertCount = mesh.getVertexCount();
VertexBuffer vb = mesh.getBuffer(Type.Index);
Format targetFmt;
if (vb.getFormat() == Format.UnsignedInt && vertCount <= 0xffff){
if (vertCount <= 256)
targetFmt = Format.UnsignedByte;
else
targetFmt = Format.UnsignedShort;
}else if (vb.getFormat() == Format.UnsignedShort && vertCount <= 0xff){
targetFmt = Format.UnsignedByte;
}else{
return;
}
IndexBuffer src = mesh.getIndexBuffer();
Buffer newBuf = VertexBuffer.createBuffer(targetFmt, vb.getNumComponents(), src.size());
VertexBuffer newVb = new VertexBuffer(Type.Index);
newVb.setupData(vb.getUsage(), vb.getNumComponents(), targetFmt, newBuf);
mesh.clearBuffer(Type.Index);
mesh.setBuffer(newVb);
IndexBuffer dst = mesh.getIndexBuffer();
for (int i = 0; i < src.size(); i++){
dst.put(i, src.get(i));
}
}
private static void convertToFixed(FloatBuffer input, IntBuffer output){
if (output.capacity() < input.capacity())
throw new RuntimeException("Output must be at least as large as input!");
input.clear();
output.clear();
for (int i = 0; i < input.capacity(); i++){
output.put( (int) (input.get() * (float)(1<<16)) );
}
output.flip();
}
private static void convertToFloat(IntBuffer input, FloatBuffer output){
if (output.capacity() < input.capacity())
throw new RuntimeException("Output must be at least as large as input!");
input.clear();
output.clear();
for (int i = 0; i < input.capacity(); i++){
output.put( ((float)input.get() / (float)(1<<16)) );
}
output.flip();
}
private static void convertToUByte(FloatBuffer input, ByteBuffer output){
if (output.capacity() < input.capacity())
throw new RuntimeException("Output must be at least as large as input!");
input.clear();
output.clear();
for (int i = 0; i < input.capacity(); i++){
output.put( (byte) (input.get() * 255f) );
}
output.flip();
}
public static VertexBuffer convertToUByte(VertexBuffer vb){
FloatBuffer fb = (FloatBuffer) vb.getData();
ByteBuffer bb = BufferUtils.createByteBuffer(fb.capacity());
convertToUByte(fb, bb);
VertexBuffer newVb = new VertexBuffer(vb.getBufferType());
newVb.setupData(vb.getUsage(),
vb.getNumComponents(),
Format.UnsignedByte,
bb);
newVb.setNormalized(true);
return newVb;
}
public static VertexBuffer convertToFixed(VertexBuffer vb){
if (vb.getFormat() == Format.Int)
return vb;
FloatBuffer fb = (FloatBuffer) vb.getData();
IntBuffer ib = BufferUtils.createIntBuffer(fb.capacity());
convertToFixed(fb, ib);
VertexBuffer newVb = new VertexBuffer(vb.getBufferType());
newVb.setupData(vb.getUsage(),
vb.getNumComponents(),
Format.Int,
ib);
return newVb;
}
public static VertexBuffer convertToFloat(VertexBuffer vb){
if (vb.getFormat() == Format.Float)
return vb;
IntBuffer ib = (IntBuffer) vb.getData();
FloatBuffer fb = BufferUtils.createFloatBuffer(ib.capacity());
convertToFloat(ib, fb);
VertexBuffer newVb = new VertexBuffer(vb.getBufferType());
newVb.setupData(vb.getUsage(),
vb.getNumComponents(),
Format.Float,
fb);
return newVb;
}
private static void convertNormals(FloatBuffer input, ByteBuffer output){
if (output.capacity() < input.capacity())
throw new RuntimeException("Output must be at least as large as input!");
input.clear();
output.clear();
Vector3f temp = new Vector3f();
int vertexCount = input.capacity() / 3;
for (int i = 0; i < vertexCount; i++){
BufferUtils.populateFromBuffer(temp, input, i);
// offset and scale vector into -128 ... 127
temp.multLocal(127).addLocal(0.5f, 0.5f, 0.5f);
// quantize
byte v1 = (byte) temp.getX();
byte v2 = (byte) temp.getY();
byte v3 = (byte) temp.getZ();
// store
output.put(v1).put(v2).put(v3);
}
}
private static void convertTexCoords2D(FloatBuffer input, Buffer output){
if (output.capacity() < input.capacity())
throw new RuntimeException("Output must be at least as large as input!");
input.clear();
output.clear();
Vector2f temp = new Vector2f();
int vertexCount = input.capacity() / 2;
ShortBuffer sb = null;
IntBuffer ib = null;
if (output instanceof ShortBuffer)
sb = (ShortBuffer) output;
else if (output instanceof IntBuffer)
ib = (IntBuffer) output;
else
throw new UnsupportedOperationException();
for (int i = 0; i < vertexCount; i++){
BufferUtils.populateFromBuffer(temp, input, i);
if (sb != null){
sb.put( (short) (temp.getX()*Short.MAX_VALUE) );
sb.put( (short) (temp.getY()*Short.MAX_VALUE) );
}else{
int v1 = (int) (temp.getX() * ((float)(1 << 16)));
int v2 = (int) (temp.getY() * ((float)(1 << 16)));
ib.put(v1).put(v2);
}
}
}
private static Transform convertPositions(FloatBuffer input, BoundingBox bbox, Buffer output){
if (output.capacity() < input.capacity())
throw new RuntimeException("Output must be at least as large as input!");
Vector3f offset = bbox.getCenter().negate();
Vector3f size = new Vector3f(bbox.getXExtent(), bbox.getYExtent(), bbox.getZExtent());
size.multLocal(2);
ShortBuffer sb = null;
ByteBuffer bb = null;
float dataTypeSize;
float dataTypeOffset;
if (output instanceof ShortBuffer){
sb = (ShortBuffer) output;
dataTypeOffset = shortOff;
dataTypeSize = shortSize;
}else{
bb = (ByteBuffer) output;
dataTypeOffset = byteOff;
dataTypeSize = byteSize;
}
Vector3f scale = new Vector3f();
scale.set(dataTypeSize, dataTypeSize, dataTypeSize).divideLocal(size);
Vector3f invScale = new Vector3f();
invScale.set(size).divideLocal(dataTypeSize);
offset.multLocal(scale);
offset.addLocal(dataTypeOffset, dataTypeOffset, dataTypeOffset);
// offset = (-modelOffset * shortSize)/modelSize + shortOff
// scale = shortSize / modelSize
input.clear();
output.clear();
Vector3f temp = new Vector3f();
int vertexCount = input.capacity() / 3;
for (int i = 0; i < vertexCount; i++){
BufferUtils.populateFromBuffer(temp, input, i);
// offset and scale vector into -32768 ... 32767
// or into -128 ... 127 if using bytes
temp.multLocal(scale);
temp.addLocal(offset);
// quantize and store
if (sb != null){
short v1 = (short) temp.getX();
short v2 = (short) temp.getY();
short v3 = (short) temp.getZ();
sb.put(v1).put(v2).put(v3);
}else{
byte v1 = (byte) temp.getX();
byte v2 = (byte) temp.getY();
byte v3 = (byte) temp.getZ();
bb.put(v1).put(v2).put(v3);
}
}
Transform transform = new Transform();
transform.setTranslation(offset.negate().multLocal(invScale));
transform.setScale(invScale);
return transform;
}
}

@ -75,8 +75,8 @@ import javax.swing.SwingUtilities;
public class JmeDesktopSystem extends JmeSystemDelegate {
@Override
public AssetManager newAssetManager(URL configFile) {
return new DesktopAssetManager(configFile);
public String getPlatformAssetConfigPath() {
return "com/jme3/asset/Desktop.cfg";
}
private static BufferedImage verticalFlip(BufferedImage original) {
@ -119,17 +119,6 @@ public class JmeDesktopSystem extends JmeSystemDelegate {
}
}
@Override
public ImageRaster createImageRaster(Image image, int slice) {
assert image.getEfficentData() == null;
return new DefaultImageRaster(image, slice);
}
@Override
public AssetManager newAssetManager() {
return new DesktopAssetManager(null);
}
@Override
public void showErrorDialog(String message) {
final String msg = message;

@ -0,0 +1,4 @@
INCLUDE com/jme3/asset/General.cfg
# IOS specific loaders
LOADER com.jme3.system.ios.IosImageLoader : jpg, bmp, gif, png, jpeg

@ -1,109 +0,0 @@
/*
* Copyright (c) 2009-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.system.ios;
import com.jme3.asset.AssetLoader;
import com.jme3.asset.DesktopAssetManager;
import com.jme3.asset.TextureKey;
import com.jme3.asset.plugins.ClasspathLocator;
import com.jme3.audio.plugins.WAVLoader;
import com.jme3.texture.Texture;
import java.io.InputStream;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author normenhansen
*/
public class IosAssetManager extends DesktopAssetManager {
private static final Logger logger = Logger.getLogger(IosAssetManager.class.getName());
public IosAssetManager() {
this(null);
}
@Deprecated
public IosAssetManager(boolean loadDefaults) {
//this(Thread.currentThread().getContextClassLoader().getResource("com/jme3/asset/Android.cfg"));
this(null);
}
private void registerLoaderSafe(String loaderClass, String ... extensions) {
try {
Class<? extends AssetLoader> loader = (Class<? extends AssetLoader>) Class.forName(loaderClass);
registerLoader(loader, extensions);
} catch (Exception e){
logger.log(Level.WARNING, "Failed to load AssetLoader", e);
}
}
/**
* AndroidAssetManager constructor
* If URL == null then a default list of locators and loaders for android is set
* @param configFile
*/
public IosAssetManager(URL configFile) {
System.setProperty("org.xml.sax.driver", "org.xmlpull.v1.sax2.Driver");
// Set Default iOS config
registerLocator("", ClasspathLocator.class);
registerLoader(IosImageLoader.class, "jpg", "bmp", "gif", "png", "jpeg");
//registerLoader(AndroidImageLoader.class, "jpg", "bmp", "gif", "png", "jpeg");
//registerLoader(AndroidAudioLoader.class, "ogg", "mp3", "wav");
registerLoader(com.jme3.material.plugins.J3MLoader.class, "j3m");
registerLoader(com.jme3.material.plugins.J3MLoader.class, "j3md");
registerLoader(com.jme3.shader.plugins.GLSLLoader.class, "vert", "frag", "glsl", "glsllib");
registerLoader(com.jme3.export.binary.BinaryImporter.class, "j3o");
registerLoader(com.jme3.font.plugins.BitmapFontLoader.class, "fnt");
registerLoader(WAVLoader.class, "wav");
// Less common loaders (especially on iOS)
registerLoaderSafe("com.jme3.audio.plugins.OGGLoader", "ogg");
registerLoaderSafe("com.jme3.texture.plugins.DDSLoader", "dds");
registerLoaderSafe("com.jme3.texture.plugins.PFMLoader", "pfm");
registerLoaderSafe("com.jme3.texture.plugins.HDRLoader", "hdr");
registerLoaderSafe("com.jme3.texture.plugins.TGALoader", "tga");
registerLoaderSafe("com.jme3.scene.plugins.OBJLoader", "obj");
registerLoaderSafe("com.jme3.scene.plugins.MTLLoader", "mtl");
registerLoaderSafe("com.jme3.scene.plugins.ogre.MeshLoader", "mesh.xml");
registerLoaderSafe("com.jme3.scene.plugins.ogre.SkeletonLoader", "skeleton.xml");
registerLoaderSafe("com.jme3.scene.plugins.ogre.MaterialLoader", "material");
registerLoaderSafe("com.jme3.scene.plugins.ogre.SceneLoader", "scene");
logger.fine("IosAssetManager created.");
}
}

@ -31,17 +31,13 @@
*/
package com.jme3.system.ios;
import com.jme3.asset.AssetManager;
import com.jme3.audio.AudioRenderer;
import com.jme3.system.AppSettings;
import com.jme3.system.JmeContext;
import com.jme3.system.JmeSystemDelegate;
import com.jme3.system.NullContext;
import com.jme3.texture.Image;
import com.jme3.texture.image.ImageRaster;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
import java.nio.ByteBuffer;
import java.util.logging.Logger;
@ -52,18 +48,13 @@ import java.util.logging.Logger;
public class JmeIosSystem extends JmeSystemDelegate {
@Override
public void writeImageFile(OutputStream outStream, String format, ByteBuffer imageData, int width, int height) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public AssetManager newAssetManager(URL configFile) {
return new IosAssetManager(configFile);
public String getPlatformAssetConfigPath() {
return "com/jme3/asset/IOS.cfg";
}
@Override
public AssetManager newAssetManager() {
return new IosAssetManager();
public void writeImageFile(OutputStream outStream, String format, ByteBuffer imageData, int width, int height) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
@ -106,11 +97,6 @@ public class JmeIosSystem extends JmeSystemDelegate {
// throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public ImageRaster createImageRaster(Image image, int slice) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void showSoftKeyboard(boolean show) {
throw new UnsupportedOperationException("Not supported yet.");

@ -0,0 +1,224 @@
/*
* Copyright (c) 2009-2015 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.scene.plugins.fbx.file;
import java.io.OutputStream;
import java.io.PrintStream;
import java.lang.reflect.Array;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;
import static org.omg.IOP.IORHelper.id;
/**
* Quick n' dirty dumper of FBX binary files.
*
* Outputs a format similar to an ASCII FBX file.
*
* @author Kirill Vainer
*/
public final class FBXDump {
private static final DecimalFormat DECIMAL_FORMAT
= new DecimalFormat("0.0000000000");
private FBXDump() { }
/**
* Creates a map between object UIDs and the objects themselves.
*
* @param file The file to create the mappings for.
* @return The UID to object map.
*/
private static Map<Long, FBXElement> createUidToObjectMap(FBXFile file) {
Map<Long, FBXElement> uidToObjectMap = new HashMap<Long, FBXElement>();
for (FBXElement rootElement : file.rootElements) {
if (rootElement.id.equals("Objects")) {
for (FBXElement fbxObj : rootElement.children) {
if (fbxObj.propertiesTypes[0] != 'L') {
continue; // error
}
Long uid = (Long) fbxObj.properties.get(0);
uidToObjectMap.put(uid, fbxObj);
}
}
}
return uidToObjectMap;
}
/**
* Dump FBX to standard output.
*
* @param file the file to dump.
*/
public static void dumpFBX(FBXFile file) {
dumpFBX(file, System.out);
}
/**
* Dump FBX to the given output stream.
*
* @param file the file to dump.
* @param out the output stream where to output.
*/
public static void dumpFBX(FBXFile file, OutputStream out) {
Map<Long, FBXElement> uidToObjectMap = createUidToObjectMap(file);
PrintStream ps = new PrintStream(out);
for (FBXElement rootElement : file.rootElements) {
dumpFBXElement(rootElement, ps, 0, uidToObjectMap);
}
}
private static String indent(int amount) {
return " ".substring(0, amount);
}
/**
* Convert FBX string - this replaces all instances of
* <code>\x00\x01</code> to "::".
*
* @param string The string to convert
* @return
*/
private static String convertFBXString(String string) {
return string.replaceAll("\u0000\u0001", "::");
}
protected static void dumpFBXProperty(String id, char propertyType,
Object property, PrintStream ps,
Map<Long, FBXElement> uidToObjectMap) {
switch (propertyType) {
case 'S':
// String
String str = (String) property;
ps.print("\"" + convertFBXString(str) + "\"");
break;
case 'R':
// RAW data.
byte[] bytes = (byte[]) property;
ps.print("[");
for (int j = 0; j < bytes.length; j++) {
ps.print(String.format("%02X", bytes[j] & 0xff));
if (j != bytes.length - 1) {
ps.print(" ");
}
}
ps.print("]");
break;
case 'D':
case 'F':
// Double, Float.
if (property instanceof Double) {
ps.print(DECIMAL_FORMAT.format((Double)property));
} else if (property instanceof Float) {
ps.print(DECIMAL_FORMAT.format((Float)property));
} else {
ps.print(property);
}
break;
case 'I':
case 'Y':
// Integer, Signed Short.
ps.print(property);
break;
case 'C':
// Boolean
ps.print((Boolean)property ? "1" : "0");
break;
case 'L':
// Long
// If this is a connection, decode UID into object name.
if (id.equals("C")) {
Long uid = (Long) property;
FBXElement element = uidToObjectMap.get(uid);
if (element != null) {
String name = (String) element.properties.get(1);
ps.print("\"" + convertFBXString(name) + "\"");
} else {
ps.print(property);
}
} else {
ps.print(property);
}
break;
case 'd':
case 'i':
case 'l':
case 'f':
// Arrays of things..
int length = Array.getLength(property);
for (int j = 0; j < length; j++) {
Object arrayEntry = Array.get(property, j);
dumpFBXProperty(id, Character.toUpperCase(propertyType), arrayEntry, ps, uidToObjectMap);
if (j != length - 1) {
ps.print(",");
}
}
break;
default:
throw new UnsupportedOperationException("" + propertyType);
}
}
protected static void dumpFBXElement(FBXElement el, PrintStream ps,
int indent, Map<Long, FBXElement> uidToObjectMap) {
// 4 spaces per tab should be OK.
String indentStr = indent(indent * 4);
String textId = el.id;
// Properties are called 'P' and connections are called 'C'.
if (el.id.equals("P")) {
textId = "Property";
} else if (el.id.equals("C")) {
textId = "Connect";
}
ps.print(indentStr + textId + ": ");
for (int i = 0; i < el.properties.size(); i++) {
Object property = el.properties.get(i);
char propertyType = el.propertiesTypes[i];
dumpFBXProperty(el.id, propertyType, property, ps, uidToObjectMap);
if (i != el.properties.size() - 1) {
ps.print(", ");
}
}
if (el.children.isEmpty()) {
ps.println();
} else {
ps.println(" {");
for (FBXElement childElement : el.children) {
dumpFBXElement(childElement, ps, indent + 1, uidToObjectMap);
}
ps.println(indentStr + "}");
}
}
}

@ -71,12 +71,15 @@ public class XMLImporter implements JmeImporter {
this.assetManager = assetManager;
}
public Object load(AssetInfo info) throws IOException{
public Object load(AssetInfo info) throws IOException {
assetManager = info.getManager();
InputStream in = info.openStream();
Savable obj = load(in);
in.close();
return obj;
try {
return load(in);
} finally {
if (in != null)
in.close();
}
}
public Savable load(File f) throws IOException {

Loading…
Cancel
Save