From a37f38a412bfe4472a9d295069fae863d34afd9f Mon Sep 17 00:00:00 2001 From: shadowislord Date: Fri, 20 Mar 2015 23:51:15 -0400 Subject: [PATCH 01/47] Build: fix build failure if not building from git repo --- jme3-core/build.gradle | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/jme3-core/build.gradle b/jme3-core/build.gradle index 78bc24dd1..bd699f52a 100644 --- a/jme3-core/build.gradle +++ b/jme3-core/build.gradle @@ -26,14 +26,29 @@ import org.ajoberstar.grgit.* task updateVersion << { - def grgit = Grgit.open(project.file('.').parent) + def verfile = file('src/main/java/com/jme3/system/JmeVersion.java') + def jmeGitHash + def jmeShortGitHash + def jmeBuildDate + def jmeBranchName - def jmeGitHash = grgit.head().id - def jmeShortGitHash = grgit.head().abbreviatedId - def jmeBuildDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date()) - def jmeBranchName = grgit.branch.current.name + try { + def grgit = Grgit.open(project.file('.').parent) + jmeGitHash = grgit.head().id + jmeShortGitHash = grgit.head().abbreviatedId + jmeBuildDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date()) + jmeBranchName = grgit.branch.current.name + } catch (ex) { + // Failed to get repo info + logger.warn("Failed to get repository info: " + ex.message + ". " + \ + "Only partial build info will be generated.") + + jmeGitHash = "" + jmeShortGitHash = "" + jmeBuildDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date()) + jmeBranchName = "unknown" + } - def verfile = file('src/main/java/com/jme3/system/JmeVersion.java') verfile.text = "\npackage com.jme3.system;\n\n" + "/**\n * THIS IS AN AUTO-GENERATED FILE..\n * DO NOT MODIFY!\n */\n" + "public class JmeVersion {\n" + From eb767e75802cab5ae20597fee7fb6fa40ac55d45 Mon Sep 17 00:00:00 2001 From: jmekaelthas Date: Mon, 23 Mar 2015 20:09:45 +0100 Subject: [PATCH 02/47] Feature: added support for loading assets linked from external blender files. --- .../main/java/com/jme3/asset/BlenderKey.java | 312 +----------------- .../blender/AbstractBlenderHelper.java | 138 +++++++- .../scene/plugins/blender/BlenderContext.java | 91 +++-- .../scene/plugins/blender/BlenderLoader.java | 263 +++++++++------ .../plugins/blender/BlenderModelLoader.java | 71 +--- .../blender/animations/AnimationHelper.java | 3 +- .../plugins/blender/cameras/CameraHelper.java | 15 +- .../plugins/blender/file/FileBlockHeader.java | 87 ++--- .../scene/plugins/blender/file/Structure.java | 3 +- .../plugins/blender/lights/LightHelper.java | 8 +- .../blender/materials/MaterialContext.java | 25 +- .../blender/materials/MaterialHelper.java | 7 +- .../plugins/blender/meshes/MeshHelper.java | 13 +- .../plugins/blender/objects/ObjectHelper.java | 70 ++-- .../blender/textures/TextureHelper.java | 90 +++-- .../blending/AbstractTextureBlender.java | 18 +- .../blending/TextureBlenderFactory.java | 7 +- .../main/java/com/jme3/scene/UserData.java | 221 +++++++++++-- 18 files changed, 780 insertions(+), 662 deletions(-) diff --git a/jme3-blender/src/main/java/com/jme3/asset/BlenderKey.java b/jme3-blender/src/main/java/com/jme3/asset/BlenderKey.java index c215d0677..c412c07b3 100644 --- a/jme3-blender/src/main/java/com/jme3/asset/BlenderKey.java +++ b/jme3-blender/src/main/java/com/jme3/asset/BlenderKey.java @@ -32,36 +32,19 @@ package com.jme3.asset; import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Queue; -import com.jme3.animation.Animation; -import com.jme3.bounding.BoundingVolume; -import com.jme3.collision.Collidable; -import com.jme3.collision.CollisionResults; -import com.jme3.collision.UnsupportedCollisionException; import com.jme3.export.InputCapsule; import com.jme3.export.JmeExporter; import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; import com.jme3.material.Material; import com.jme3.material.RenderState.FaceCullMode; -import com.jme3.math.ColorRGBA; -import com.jme3.post.Filter; -import com.jme3.scene.CameraNode; -import com.jme3.scene.LightNode; -import com.jme3.scene.Node; -import com.jme3.scene.SceneGraphVisitor; -import com.jme3.scene.Spatial; -import com.jme3.texture.Texture; /** * Blender key. Contains path of the blender file and its loading properties. * @author Marcin Roguski (Kaelthas) */ public class BlenderKey extends ModelKey { - protected static final int DEFAULT_FPS = 25; /** * FramesPerSecond parameter describe how many frames there are in each second. It allows to calculate the time @@ -72,7 +55,7 @@ public class BlenderKey extends ModelKey { * This variable is a bitwise flag of FeatureToLoad interface values; By default everything is being loaded. */ protected int featuresToLoad = FeaturesToLoad.ALL; - /** This variable determines if assets that are not linked to the objects should be loaded. */ + /** The variable that tells if content of the file (along with data unlinked to any feature on the scene) should be stored as 'user data' in the result spatial. */ protected boolean loadUnlinkedAssets; /** The root path for all the assets. */ protected String assetRootPath; @@ -268,6 +251,7 @@ public class BlenderKey extends ModelKey { * @param featuresToLoad * bitwise flag of FeaturesToLoad interface values */ + @Deprecated public void includeInLoading(int featuresToLoad) { this.featuresToLoad |= featuresToLoad; } @@ -277,10 +261,12 @@ public class BlenderKey extends ModelKey { * @param featuresNotToLoad * bitwise flag of FeaturesToLoad interface values */ + @Deprecated public void excludeFromLoading(int featuresNotToLoad) { featuresToLoad &= ~featuresNotToLoad; } + @Deprecated public boolean shouldLoad(int featureToLoad) { return (featuresToLoad & featureToLoad) != 0; } @@ -290,6 +276,7 @@ public class BlenderKey extends ModelKey { * the blender file loader. * @return features that will be loaded by the blender file loader */ + @Deprecated public int getFeaturesToLoad() { return featuresToLoad; } @@ -317,15 +304,6 @@ public class BlenderKey extends ModelKey { this.loadUnlinkedAssets = loadUnlinkedAssets; } - /** - * This method creates an object where loading results will be stores. Only those features will be allowed to store - * that were specified by features-to-load flag. - * @return an object to store loading results - */ - public LoadingResults prepareLoadingResults() { - return new LoadingResults(featuresToLoad); - } - /** * This method sets the fix up axis state. If set to true then Y is up axis. Otherwise the up i Z axis. By default Y * is up axis. @@ -699,8 +677,11 @@ public class BlenderKey extends ModelKey { /** * This interface describes the features of the scene that are to be loaded. + * @deprecated this interface is deprecated and is not used anymore; to ensure the loading models consistency + * everything must be loaded because in blender one feature might depend on another * @author Marcin Roguski (Kaelthas) */ + @Deprecated public static interface FeaturesToLoad { int SCENES = 0x0000FFFF; @@ -745,281 +726,4 @@ public class BlenderKey extends ModelKey { */ ALL_NAMES_MATCH; } - - /** - * This class holds the loading results according to the given loading flag. - * @author Marcin Roguski (Kaelthas) - */ - public static class LoadingResults extends Spatial { - - /** Bitwise mask of features that are to be loaded. */ - private final int featuresToLoad; - /** The scenes from the file. */ - private List scenes; - /** Objects from all scenes. */ - private List objects; - /** Materials from all objects. */ - private List materials; - /** Textures from all objects. */ - private List textures; - /** Animations of all objects. */ - private List animations; - /** All cameras from the file. */ - private List cameras; - /** All lights from the file. */ - private List lights; - /** Loaded sky. */ - private Spatial sky; - /** Scene filters (ie. FOG). */ - private List filters; - /** - * The background color of the render loaded from the horizon color of the world. If no world is used than the gray color - * is set to default (as in blender editor. - */ - private ColorRGBA backgroundColor = ColorRGBA.Gray; - - /** - * Private constructor prevents users to create an instance of this class from outside the - * @param featuresToLoad - * bitwise mask of features that are to be loaded - * @see FeaturesToLoad FeaturesToLoad - */ - private LoadingResults(int featuresToLoad) { - this.featuresToLoad = featuresToLoad; - if ((featuresToLoad & FeaturesToLoad.SCENES) != 0) { - scenes = new ArrayList(); - } - if ((featuresToLoad & FeaturesToLoad.OBJECTS) != 0) { - objects = new ArrayList(); - if ((featuresToLoad & FeaturesToLoad.MATERIALS) != 0) { - materials = new ArrayList(); - if ((featuresToLoad & FeaturesToLoad.TEXTURES) != 0) { - textures = new ArrayList(); - } - } - if ((featuresToLoad & FeaturesToLoad.ANIMATIONS) != 0) { - animations = new ArrayList(); - } - } - if ((featuresToLoad & FeaturesToLoad.CAMERAS) != 0) { - cameras = new ArrayList(); - } - if ((featuresToLoad & FeaturesToLoad.LIGHTS) != 0) { - lights = new ArrayList(); - } - } - - /** - * This method returns a bitwise flag describing what features of the blend file will be included in the result. - * @return bitwise mask of features that are to be loaded - * @see FeaturesToLoad FeaturesToLoad - */ - public int getLoadedFeatures() { - return featuresToLoad; - } - - /** - * This method adds a scene to the result set. - * @param scene - * scene to be added to the result set - */ - public void addScene(Node scene) { - if (scenes != null) { - scenes.add(scene); - } - } - - /** - * This method adds an object to the result set. - * @param object - * object to be added to the result set - */ - public void addObject(Node object) { - if (objects != null) { - objects.add(object); - } - } - - /** - * This method adds a material to the result set. - * @param material - * material to be added to the result set - */ - public void addMaterial(Material material) { - if (materials != null) { - materials.add(material); - } - } - - /** - * This method adds a texture to the result set. - * @param texture - * texture to be added to the result set - */ - public void addTexture(Texture texture) { - if (textures != null) { - textures.add(texture); - } - } - - /** - * This method adds a camera to the result set. - * @param camera - * camera to be added to the result set - */ - public void addCamera(CameraNode camera) { - if (cameras != null) { - cameras.add(camera); - } - } - - /** - * This method adds a light to the result set. - * @param light - * light to be added to the result set - */ - public void addLight(LightNode light) { - if (lights != null) { - lights.add(light); - } - } - - /** - * This method sets the sky of the scene. Only one sky can be set. - * @param sky - * the sky to be set - */ - public void setSky(Spatial sky) { - this.sky = sky; - } - - /** - * This method adds a scene filter. Filters are used to load FOG or other - * scene effects that blender can define. - * @param filter - * the filter to be added - */ - public void addFilter(Filter filter) { - if (filter != null) { - if (filters == null) { - filters = new ArrayList(5); - } - filters.add(filter); - } - } - - /** - * @param backgroundColor - * the background color - */ - public void setBackgroundColor(ColorRGBA backgroundColor) { - this.backgroundColor = backgroundColor; - } - - /** - * @return all loaded scenes - */ - public List getScenes() { - return scenes; - } - - /** - * @return all loaded objects - */ - public List getObjects() { - return objects; - } - - /** - * @return all loaded materials - */ - public List getMaterials() { - return materials; - } - - /** - * @return all loaded textures - */ - public List getTextures() { - return textures; - } - - /** - * @return all loaded animations - */ - public List getAnimations() { - return animations; - } - - /** - * @return all loaded cameras - */ - public List getCameras() { - return cameras; - } - - /** - * @return all loaded lights - */ - public List getLights() { - return lights; - } - - /** - * @return the scene's sky - */ - public Spatial getSky() { - return sky; - } - - /** - * @return scene filters - */ - public List getFilters() { - return filters; - } - - /** - * @return the background color - */ - public ColorRGBA getBackgroundColor() { - return backgroundColor; - } - - @Override - public int collideWith(Collidable other, CollisionResults results) throws UnsupportedCollisionException { - return 0; - } - - @Override - public void updateModelBound() { - } - - @Override - public void setModelBound(BoundingVolume modelBound) { - } - - @Override - public int getVertexCount() { - return 0; - } - - @Override - public int getTriangleCount() { - return 0; - } - - @Override - public Spatial deepClone() { - return null; - } - - @Override - public void depthFirstTraversal(SceneGraphVisitor visitor) { - } - - @Override - protected void breadthFirstTraversal(SceneGraphVisitor visitor, Queue queue) { - } - } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/AbstractBlenderHelper.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/AbstractBlenderHelper.java index eff993f76..e11101c14 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/AbstractBlenderHelper.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/AbstractBlenderHelper.java @@ -31,17 +31,34 @@ */ package com.jme3.scene.plugins.blender; +import java.io.File; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.logging.Level; +import java.util.logging.Logger; +import com.jme3.animation.Animation; +import com.jme3.asset.AssetNotFoundException; +import com.jme3.asset.BlenderKey; import com.jme3.export.Savable; +import com.jme3.light.Light; import com.jme3.math.FastMath; import com.jme3.math.Quaternion; +import com.jme3.post.Filter; +import com.jme3.renderer.Camera; +import com.jme3.scene.Node; import com.jme3.scene.Spatial; +import com.jme3.scene.plugins.blender.BlenderContext.LoadedDataType; import com.jme3.scene.plugins.blender.file.BlenderFileException; import com.jme3.scene.plugins.blender.file.Pointer; import com.jme3.scene.plugins.blender.file.Structure; +import com.jme3.scene.plugins.blender.materials.MaterialContext; +import com.jme3.scene.plugins.blender.meshes.TemporalMesh; import com.jme3.scene.plugins.blender.objects.Properties; +import com.jme3.texture.Texture; /** * A purpose of the helper class is to split calculation code into several classes. Each helper after use should be cleared because it can @@ -49,14 +66,16 @@ import com.jme3.scene.plugins.blender.objects.Properties; * @author Marcin Roguski */ public abstract class AbstractBlenderHelper { + private static final Logger LOGGER = Logger.getLogger(AbstractBlenderHelper.class.getName()); + /** The blender context. */ - protected BlenderContext blenderContext; + protected BlenderContext blenderContext; /** The version of the blend file. */ - protected final int blenderVersion; + protected final int blenderVersion; /** This variable indicates if the Y asxis is the UP axis or not. */ - protected boolean fixUpAxis; + protected boolean fixUpAxis; /** Quaternion used to rotate data when Y is up axis. */ - protected Quaternion upAxisRotationQuaternion; + protected Quaternion upAxisRotationQuaternion; /** * This constructor parses the given blender version and stores the result. Some functionalities may differ in different blender @@ -129,4 +148,115 @@ public abstract class AbstractBlenderHelper { } } } + + /** + * The method loads library of a given ID from linked blender file. + * @param id + * the ID of the linked feature (it contains its name and blender path) + * @return loaded feature or null if none was found + * @throws BlenderFileException + * and exception is throw when problems with reading a blend file occur + */ + @SuppressWarnings("unchecked") + protected Object loadLibrary(Structure id) throws BlenderFileException { + Pointer pLib = (Pointer) id.getFieldValue("lib"); + if (pLib.isNotNull()) { + String fullName = id.getFieldValue("name").toString();// we need full name with the prefix + String nameOfFeatureToLoad = id.getName(); + Structure library = pLib.fetchData().get(0); + String path = library.getFieldValue("filepath").toString(); + + if (!blenderContext.getLinkedFeatures().keySet().contains(path)) { + File file = new File(path); + List pathsToCheck = new ArrayList(); + String currentPath = file.getName(); + do { + pathsToCheck.add(currentPath); + file = file.getParentFile(); + if (file != null) { + currentPath = file.getName() + '/' + currentPath; + } + } while (file != null); + + Spatial loadedAsset = null; + BlenderKey blenderKey = null; + for (String p : pathsToCheck) { + blenderKey = new BlenderKey(p); + blenderKey.setLoadUnlinkedAssets(true); + try { + loadedAsset = blenderContext.getAssetManager().loadAsset(blenderKey); + break;// break if no exception was thrown + } catch (AssetNotFoundException e) { + LOGGER.log(Level.FINEST, "Cannot locate linked resource at path: {0}.", p); + } + } + + if (loadedAsset != null) { + Map> linkedData = loadedAsset.getUserData("linkedData"); + for (Entry> entry : linkedData.entrySet()) { + String linkedDataFilePath = "this".equals(entry.getKey()) ? path : entry.getKey(); + + List scenes = (List) entry.getValue().get("scenes"); + for (Node scene : scenes) { + blenderContext.addLinkedFeature(linkedDataFilePath, "SC" + scene.getName(), scene); + } + List objects = (List) entry.getValue().get("objects"); + for (Node object : objects) { + blenderContext.addLinkedFeature(linkedDataFilePath, "OB" + object.getName(), object); + } + List meshes = (List) entry.getValue().get("meshes"); + for (TemporalMesh mesh : meshes) { + blenderContext.addLinkedFeature(linkedDataFilePath, "ME" + mesh.getName(), mesh); + } + List materials = (List) entry.getValue().get("materials"); + for (MaterialContext materialContext : materials) { + blenderContext.addLinkedFeature(linkedDataFilePath, "MA" + materialContext.getName(), materialContext); + } + List textures = (List) entry.getValue().get("textures"); + for (Texture texture : textures) { + blenderContext.addLinkedFeature(linkedDataFilePath, "TE" + texture.getName(), texture); + } + List images = (List) entry.getValue().get("images"); + for (Texture image : images) { + blenderContext.addLinkedFeature(linkedDataFilePath, "IM" + image.getName(), image); + } + List animations = (List) entry.getValue().get("animations"); + for (Animation animation : animations) { + blenderContext.addLinkedFeature(linkedDataFilePath, "AC" + animation.getName(), animation); + } + List cameras = (List) entry.getValue().get("cameras"); + for (Camera camera : cameras) { + blenderContext.addLinkedFeature(linkedDataFilePath, "CA" + camera.getName(), camera); + } + List lights = (List) entry.getValue().get("lights"); + for (Light light : lights) { + blenderContext.addLinkedFeature(linkedDataFilePath, "LA" + light.getName(), light); + } + Spatial sky = (Spatial) entry.getValue().get("sky"); + if (sky != null) { + blenderContext.addLinkedFeature(linkedDataFilePath, sky.getName(), sky); + } + List filters = (List) entry.getValue().get("filters"); + for (Filter filter : filters) { + blenderContext.addLinkedFeature(linkedDataFilePath, filter.getName(), filter); + } + } + } else { + LOGGER.log(Level.WARNING, "No features loaded from path: {0}.", path); + } + } + + Object result = blenderContext.getLinkedFeature(path, fullName); + if (result == null) { + LOGGER.log(Level.WARNING, "Could NOT find asset named {0} in the library of path: {1}.", new Object[] { nameOfFeatureToLoad, path }); + } else { + blenderContext.addLoadedFeatures(id.getOldMemoryAddress(), LoadedDataType.STRUCTURE, id); + blenderContext.addLoadedFeatures(id.getOldMemoryAddress(), LoadedDataType.FEATURE, result); + } + return result; + } else { + LOGGER.warning("Library link points to nothing!"); + } + return null; + } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/BlenderContext.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/BlenderContext.java index cde38e327..6e8042b09 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/BlenderContext.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/BlenderContext.java @@ -53,6 +53,7 @@ import com.jme3.scene.plugins.blender.constraints.Constraint; import com.jme3.scene.plugins.blender.file.BlenderInputStream; import com.jme3.scene.plugins.blender.file.DnaBlockData; import com.jme3.scene.plugins.blender.file.FileBlockHeader; +import com.jme3.scene.plugins.blender.file.FileBlockHeader.BlockCode; import com.jme3.scene.plugins.blender.file.Structure; /** @@ -64,49 +65,51 @@ import com.jme3.scene.plugins.blender.file.Structure; */ public class BlenderContext { /** The blender file version. */ - private int blenderVersion; + private int blenderVersion; /** The blender key. */ - private BlenderKey blenderKey; + private BlenderKey blenderKey; /** The header of the file block. */ - private DnaBlockData dnaBlockData; + private DnaBlockData dnaBlockData; /** The scene structure. */ - private Structure sceneStructure; + private Structure sceneStructure; /** The input stream of the blend file. */ - private BlenderInputStream inputStream; + private BlenderInputStream inputStream; /** The asset manager. */ - private AssetManager assetManager; + private AssetManager assetManager; /** The blocks read from the file. */ - protected List blocks; + protected List blocks; /** * A map containing the file block headers. The key is the old memory address. */ - private Map fileBlockHeadersByOma = new HashMap(); + private Map fileBlockHeadersByOma = new HashMap(); /** A map containing the file block headers. The key is the block code. */ - private Map> fileBlockHeadersByCode = new HashMap>(); + private Map> fileBlockHeadersByCode = new HashMap>(); /** * This map stores the loaded features by their old memory address. The * first object in the value table is the loaded structure and the second - * the structure already converted into proper data. */ - private Map> loadedFeatures = new HashMap>(); + private Map> loadedFeatures = new HashMap>(); + /** Features loaded from external blender files. The key is the file path and the value is a map between feature name and loaded feature. */ + private Map> linkedFeatures = new HashMap>(); /** A stack that hold the parent structure of currently loaded feature. */ - private Stack parentStack = new Stack(); + private Stack parentStack = new Stack(); /** A list of constraints for the specified object. */ - protected Map> constraints = new HashMap>(); + protected Map> constraints = new HashMap>(); /** Animations loaded for features. */ - private Map> animations = new HashMap>(); + private Map> animations = new HashMap>(); /** Loaded skeletons. */ - private Map skeletons = new HashMap(); + private Map skeletons = new HashMap(); /** A map between skeleton and node it modifies. */ - private Map nodesWithSkeletons = new HashMap(); + private Map nodesWithSkeletons = new HashMap(); /** A map of bone contexts. */ - protected Map boneContexts = new HashMap(); + protected Map boneContexts = new HashMap(); /** A map og helpers that perform loading. */ - private Map helpers = new HashMap(); + private Map helpers = new HashMap(); /** Markers used by loading classes to store some custom data. This is made to avoid putting this data into user properties. */ - private Map> markers = new HashMap>(); + private Map> markers = new HashMap>(); /** A map of blender actions. The key is the action name and the value is the action itself. */ - private Map actions = new HashMap(); + private Map actions = new HashMap(); /** * This method sets the blender file version. @@ -231,10 +234,10 @@ public class BlenderContext { */ public void addFileBlockHeader(Long oldMemoryAddress, FileBlockHeader fileBlockHeader) { fileBlockHeadersByOma.put(oldMemoryAddress, fileBlockHeader); - List headers = fileBlockHeadersByCode.get(Integer.valueOf(fileBlockHeader.getCode())); + List headers = fileBlockHeadersByCode.get(fileBlockHeader.getCode()); if (headers == null) { headers = new ArrayList(); - fileBlockHeadersByCode.put(Integer.valueOf(fileBlockHeader.getCode()), headers); + fileBlockHeadersByCode.put(fileBlockHeader.getCode(), headers); } headers.add(fileBlockHeader); } @@ -258,7 +261,7 @@ public class BlenderContext { * the code of file blocks * @return a list of file blocks' headers of a specified code */ - public List getFileBlocks(Integer code) { + public List getFileBlocks(BlockCode code) { return fileBlockHeadersByCode.get(code); } @@ -299,7 +302,7 @@ public class BlenderContext { throw new IllegalArgumentException("One of the given arguments is null!"); } Map map = loadedFeatures.get(oldMemoryAddress); - if(map == null) { + if (map == null) { map = new HashMap(); loadedFeatures.put(oldMemoryAddress, map); } @@ -325,6 +328,48 @@ public class BlenderContext { return null; } + /** + * The method adds linked content to the blender context. + * @param blenderFilePath + * the path of linked blender file + * @param featureName + * the linked feature name + * @param feature + * the linked feature + */ + public void addLinkedFeature(String blenderFilePath, String featureName, Object feature) { + if (feature != null) { + Map linkedFeatures = this.linkedFeatures.get(blenderFilePath); + if (linkedFeatures == null) { + linkedFeatures = new HashMap(); + this.linkedFeatures.put(blenderFilePath, linkedFeatures); + } + if (!linkedFeatures.containsKey(featureName)) { + linkedFeatures.put(featureName, feature); + } + } + } + + /** + * The method returns linked feature of a given name from the specified blender path. + * @param blenderFilePath + * the blender file path + * @param featureName + * the feature name we want to get + * @return linked feature or null if none was found + */ + public Object getLinkedFeature(String blenderFilePath, String featureName) { + Map linkedFeatures = this.linkedFeatures.get(blenderFilePath); + return linkedFeatures != null ? linkedFeatures.get(featureName) : null; + } + + /** + * @return all linked features for the current blend file + */ + public Map> getLinkedFeatures() { + return linkedFeatures; + } + /** * This method adds the structure to the parent stack. * diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/BlenderLoader.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/BlenderLoader.java index 200f83b39..dd0160063 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/BlenderLoader.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/BlenderLoader.java @@ -33,17 +33,21 @@ package com.jme3.scene.plugins.blender; import java.io.IOException; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; +import com.jme3.animation.Animation; import com.jme3.asset.AssetInfo; import com.jme3.asset.AssetLoader; import com.jme3.asset.BlenderKey; -import com.jme3.asset.BlenderKey.FeaturesToLoad; -import com.jme3.asset.BlenderKey.LoadingResults; import com.jme3.asset.ModelKey; import com.jme3.light.Light; +import com.jme3.math.ColorRGBA; +import com.jme3.post.Filter; +import com.jme3.renderer.Camera; import com.jme3.scene.CameraNode; import com.jme3.scene.LightNode; import com.jme3.scene.Node; @@ -55,16 +59,20 @@ import com.jme3.scene.plugins.blender.curves.CurvesHelper; import com.jme3.scene.plugins.blender.file.BlenderFileException; import com.jme3.scene.plugins.blender.file.BlenderInputStream; import com.jme3.scene.plugins.blender.file.FileBlockHeader; +import com.jme3.scene.plugins.blender.file.FileBlockHeader.BlockCode; import com.jme3.scene.plugins.blender.file.Pointer; import com.jme3.scene.plugins.blender.file.Structure; import com.jme3.scene.plugins.blender.landscape.LandscapeHelper; import com.jme3.scene.plugins.blender.lights.LightHelper; +import com.jme3.scene.plugins.blender.materials.MaterialContext; import com.jme3.scene.plugins.blender.materials.MaterialHelper; import com.jme3.scene.plugins.blender.meshes.MeshHelper; +import com.jme3.scene.plugins.blender.meshes.TemporalMesh; import com.jme3.scene.plugins.blender.modifiers.ModifierHelper; import com.jme3.scene.plugins.blender.objects.ObjectHelper; import com.jme3.scene.plugins.blender.particles.ParticlesHelper; import com.jme3.scene.plugins.blender.textures.TextureHelper; +import com.jme3.texture.Texture; /** * This is the main loading class. Have in notice that asset manager needs to have loaders for resources like textures. @@ -83,72 +91,130 @@ public class BlenderLoader implements AssetLoader { try { this.setup(assetInfo); - List sceneBlocks = new ArrayList(); - BlenderKey blenderKey = blenderContext.getBlenderKey(); - LoadingResults loadingResults = blenderKey.prepareLoadingResults(); - AnimationHelper animationHelper = blenderContext.getHelper(AnimationHelper.class); animationHelper.loadAnimations(); - + + BlenderKey blenderKey = blenderContext.getBlenderKey(); + LoadedFeatures loadedFeatures = new LoadedFeatures(); for (FileBlockHeader block : blocks) { switch (block.getCode()) { - case FileBlockHeader.BLOCK_OB00:// Object + case BLOCK_OB00: ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class); - Object object = objectHelper.toObject(block.getStructure(blenderContext), blenderContext); - if (object instanceof LightNode) { - loadingResults.addLight((LightNode) object); - } else if (object instanceof CameraNode) { - loadingResults.addCamera((CameraNode) object); - } else if (object instanceof Node) { - if (LOGGER.isLoggable(Level.FINE)) { - LOGGER.log(Level.FINE, "{0}: {1}--> {2}", new Object[] { ((Node) object).getName(), ((Node) object).getLocalTranslation().toString(), ((Node) object).getParent() == null ? "null" : ((Node) object).getParent().getName() }); - } - if (this.isRootObject(loadingResults, (Node) object)) { - loadingResults.addObject((Node) object); - } + Node object = (Node) objectHelper.toObject(block.getStructure(blenderContext), blenderContext); + if (LOGGER.isLoggable(Level.FINE)) { + LOGGER.log(Level.FINE, "{0}: {1}--> {2}", new Object[] { object.getName(), object.getLocalTranslation().toString(), object.getParent() == null ? "null" : object.getParent().getName() }); } + if (object.getParent() == null) { + loadedFeatures.objects.add(object); + } + if (object instanceof LightNode && ((LightNode) object).getLight() != null) { + loadedFeatures.lights.add(((LightNode) object).getLight()); + } else if (object instanceof CameraNode && ((CameraNode) object).getCamera() != null) { + loadedFeatures.cameras.add(((CameraNode) object).getCamera()); + } + break; + case BLOCK_SC00:// Scene + loadedFeatures.sceneBlocks.add(block); break; -// case FileBlockHeader.BLOCK_MA00:// Material -// MaterialHelper materialHelper = blenderContext.getHelper(MaterialHelper.class); -// MaterialContext materialContext = materialHelper.toMaterialContext(block.getStructure(blenderContext), blenderContext); -// if (blenderKey.isLoadUnlinkedAssets() && blenderKey.shouldLoad(FeaturesToLoad.MATERIALS)) { -// loadingResults.addMaterial(this.toMaterial(block.getStructure(blenderContext))); -// } -// break; - case FileBlockHeader.BLOCK_SC00:// Scene - if (blenderKey.shouldLoad(FeaturesToLoad.SCENES)) { - sceneBlocks.add(block); + case BLOCK_MA00:// Material + MaterialHelper materialHelper = blenderContext.getHelper(MaterialHelper.class); + MaterialContext materialContext = materialHelper.toMaterialContext(block.getStructure(blenderContext), blenderContext); + loadedFeatures.materials.add(materialContext); + break; + case BLOCK_ME00:// Mesh + MeshHelper meshHelper = blenderContext.getHelper(MeshHelper.class); + TemporalMesh temporalMesh = meshHelper.toTemporalMesh(block.getStructure(blenderContext), blenderContext); + loadedFeatures.meshes.add(temporalMesh); + break; + case BLOCK_IM00:// Image + TextureHelper textureHelper = blenderContext.getHelper(TextureHelper.class); + Texture image = textureHelper.loadImageAsTexture(block.getStructure(blenderContext), 0, blenderContext); + if (image != null && image.getImage() != null) {// render results are stored as images but are not being loaded + loadedFeatures.images.add(image); } break; - case FileBlockHeader.BLOCK_WO00:// World - if (blenderKey.shouldLoad(FeaturesToLoad.WORLD)) { - Structure worldStructure = block.getStructure(blenderContext); - String worldName = worldStructure.getName(); - if (blenderKey.getUsedWorld() == null || blenderKey.getUsedWorld().equals(worldName)) { - LandscapeHelper landscapeHelper = blenderContext.getHelper(LandscapeHelper.class); - Light ambientLight = landscapeHelper.toAmbientLight(worldStructure); - if(ambientLight != null) { - loadingResults.addLight(new LightNode(null, ambientLight)); - } - loadingResults.setSky(landscapeHelper.toSky(worldStructure)); - loadingResults.addFilter(landscapeHelper.toFog(worldStructure)); - loadingResults.setBackgroundColor(landscapeHelper.toBackgroundColor(worldStructure)); + case BLOCK_TE00: + Structure textureStructure = block.getStructure(blenderContext); + int type = ((Number) textureStructure.getFieldValue("type")).intValue(); + if (type == TextureHelper.TEX_IMAGE) { + TextureHelper texHelper = blenderContext.getHelper(TextureHelper.class); + Texture texture = texHelper.getTexture(textureStructure, null, blenderContext); + if (texture != null) {// null is returned when texture has no image + loadedFeatures.textures.add(texture); } + } else { + LOGGER.fine("Only image textures can be loaded as unlinked assets. Generated textures will be applied to an existing object."); } break; + case BLOCK_WO00:// World + LandscapeHelper landscapeHelper = blenderContext.getHelper(LandscapeHelper.class); + Structure worldStructure = block.getStructure(blenderContext); + + String worldName = worldStructure.getName(); + if (blenderKey.getUsedWorld() == null || blenderKey.getUsedWorld().equals(worldName)) { + + Light ambientLight = landscapeHelper.toAmbientLight(worldStructure); + if (ambientLight != null) { + loadedFeatures.objects.add(new LightNode(null, ambientLight)); + loadedFeatures.lights.add(ambientLight); + } + loadedFeatures.sky = landscapeHelper.toSky(worldStructure); + loadedFeatures.backgroundColor = landscapeHelper.toBackgroundColor(worldStructure); + + Filter fogFilter = landscapeHelper.toFog(worldStructure); + if (fogFilter != null) { + loadedFeatures.filters.add(landscapeHelper.toFog(worldStructure)); + } + } + break; + case BLOCK_AC00: + LOGGER.fine("Loading unlinked animations is not yet supported!"); + break; + default: + LOGGER.log(Level.FINEST, "Ommiting the block: {0}.", block.getCode()); } } - // bake constraints after everything is loaded + LOGGER.fine("Baking constraints after every feature is loaded."); ConstraintHelper constraintHelper = blenderContext.getHelper(ConstraintHelper.class); constraintHelper.bakeConstraints(blenderContext); - // load the scene at the very end so that the root nodes have no parent during loading or constraints applying - for (FileBlockHeader sceneBlock : sceneBlocks) { - loadingResults.addScene(this.toScene(sceneBlock.getStructure(blenderContext))); + LOGGER.fine("Loading scenes and attaching them to the root object."); + for (FileBlockHeader sceneBlock : loadedFeatures.sceneBlocks) { + loadedFeatures.scenes.add(this.toScene(sceneBlock.getStructure(blenderContext))); + } + + LOGGER.fine("Creating the root node of the model and applying loaded nodes of the scene and loaded features to it."); + Node modelRoot = new Node(blenderKey.getName()); + for (Node scene : loadedFeatures.scenes) { + modelRoot.attachChild(scene); } - return loadingResults; + if (blenderKey.isLoadUnlinkedAssets()) { + LOGGER.fine("Setting loaded content as user data in resulting sptaial."); + Map> linkedData = new HashMap>(); + + Map thisFileData = new HashMap(); + thisFileData.put("scenes", loadedFeatures.scenes == null ? new ArrayList() : loadedFeatures.scenes); + thisFileData.put("objects", loadedFeatures.objects == null ? new ArrayList() : loadedFeatures.objects); + thisFileData.put("meshes", loadedFeatures.meshes == null ? new ArrayList() : loadedFeatures.meshes); + thisFileData.put("materials", loadedFeatures.materials == null ? new ArrayList() : loadedFeatures.materials); + thisFileData.put("textures", loadedFeatures.textures == null ? new ArrayList() : loadedFeatures.textures); + thisFileData.put("images", loadedFeatures.images == null ? new ArrayList() : loadedFeatures.images); + thisFileData.put("animations", loadedFeatures.animations == null ? new ArrayList() : loadedFeatures.animations); + thisFileData.put("cameras", loadedFeatures.cameras == null ? new ArrayList() : loadedFeatures.cameras); + thisFileData.put("lights", loadedFeatures.lights == null ? new ArrayList() : loadedFeatures.lights); + thisFileData.put("filters", loadedFeatures.filters == null ? new ArrayList() : loadedFeatures.filters); + thisFileData.put("backgroundColor", loadedFeatures.backgroundColor); + thisFileData.put("sky", loadedFeatures.sky); + + linkedData.put("this", thisFileData); + linkedData.putAll(blenderContext.getLinkedFeatures()); + + modelRoot.setUserData("linkedData", linkedData); + } + + return modelRoot; } catch (BlenderFileException e) { throw new IOException(e.getLocalizedMessage(), e); } catch (Exception e) { @@ -158,62 +224,36 @@ public class BlenderLoader implements AssetLoader { } } - /** - * This method indicates if the given spatial is a root object. It means it - * has no parent or is directly attached to one of the already loaded scene - * nodes. - * - * @param loadingResults - * loading results containing the scene nodes - * @param spatial - * spatial object - * @return true if the given spatial is a root object and - * false otherwise - */ - protected boolean isRootObject(LoadingResults loadingResults, Spatial spatial) { - if (spatial.getParent() == null) { - return true; - } - for (Node scene : loadingResults.getScenes()) { - if (spatial.getParent().equals(scene)) { - return true; - } - } - return false; - } - /** * This method converts the given structure to a scene node. * @param structure * structure of a scene * @return scene's node + * @throws BlenderFileException + * an exception throw when problems with blender file occur */ - private Node toScene(Structure structure) { + private Node toScene(Structure structure) throws BlenderFileException { ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class); Node result = new Node(structure.getName()); - try { - List base = ((Structure) structure.getFieldValue("base")).evaluateListBase(); - for (Structure b : base) { - Pointer pObject = (Pointer) b.getFieldValue("object"); - if (pObject.isNotNull()) { - Structure objectStructure = pObject.fetchData().get(0); + List base = ((Structure) structure.getFieldValue("base")).evaluateListBase(); + for (Structure b : base) { + Pointer pObject = (Pointer) b.getFieldValue("object"); + if (pObject.isNotNull()) { + Structure objectStructure = pObject.fetchData().get(0); - Object object = objectHelper.toObject(objectStructure, blenderContext); - if (object instanceof LightNode) { - result.addLight(((LightNode) object).getLight()); - result.attachChild((LightNode) object); - } else if (object instanceof Node) { - if (LOGGER.isLoggable(Level.FINE)) { - LOGGER.log(Level.FINE, "{0}: {1}--> {2}", new Object[] { ((Node) object).getName(), ((Node) object).getLocalTranslation().toString(), ((Node) object).getParent() == null ? "null" : ((Node) object).getParent().getName() }); - } - if (((Node) object).getParent() == null) { - result.attachChild((Spatial) object); - } + Object object = objectHelper.toObject(objectStructure, blenderContext); + if (object instanceof LightNode) { + result.addLight(((LightNode) object).getLight());// FIXME: check if this is needed !!! + result.attachChild((LightNode) object); + } else if (object instanceof Node) { + if (LOGGER.isLoggable(Level.FINE)) { + LOGGER.log(Level.FINE, "{0}: {1}--> {2}", new Object[] { ((Node) object).getName(), ((Node) object).getLocalTranslation().toString(), ((Node) object).getParent() == null ? "null" : ((Node) object).getParent().getName() }); + } + if (((Node) object).getParent() == null) { + result.attachChild((Spatial) object); } } } - } catch (BlenderFileException e) { - LOGGER.log(Level.SEVERE, e.getLocalizedMessage(), e); } return result; } @@ -261,7 +301,7 @@ public class BlenderLoader implements AssetLoader { blenderContext.putHelper(ConstraintHelper.class, new ConstraintHelper(inputStream.getVersionNumber(), blenderContext)); blenderContext.putHelper(ParticlesHelper.class, new ParticlesHelper(inputStream.getVersionNumber(), blenderContext)); blenderContext.putHelper(LandscapeHelper.class, new LandscapeHelper(inputStream.getVersionNumber(), blenderContext)); - + // reading the blocks (dna block is automatically saved in the blender context when found) FileBlockHeader sceneFileBlock = null; do { @@ -269,7 +309,7 @@ public class BlenderLoader implements AssetLoader { if (!fileBlock.isDnaBlock()) { blocks.add(fileBlock); // save the scene's file block - if (fileBlock.getCode() == FileBlockHeader.BLOCK_SC00) { + if (fileBlock.getCode() == BlockCode.BLOCK_SC00) { sceneFileBlock = fileBlock; } } @@ -287,4 +327,39 @@ public class BlenderLoader implements AssetLoader { blenderContext = null; blocks = null; } + + /** + * This class holds the loading results according to the given loading flag. + * @author Marcin Roguski (Kaelthas) + */ + private static class LoadedFeatures { + private List sceneBlocks = new ArrayList(); + /** The scenes from the file. */ + private List scenes = new ArrayList(); + /** Objects from all scenes. */ + private List objects = new ArrayList(); + /** All meshes. */ + private List meshes = new ArrayList(); + /** Materials from all objects. */ + private List materials = new ArrayList(); + /** Textures from all objects. */ + private List textures = new ArrayList(); + /** The images stored in the blender file. */ + private List images = new ArrayList(); + /** Animations of all objects. */ + private List animations = new ArrayList(); + /** All cameras from the file. */ + private List cameras = new ArrayList(); + /** All lights from the file. */ + private List lights = new ArrayList(); + /** Loaded sky. */ + private Spatial sky; + /** Scene filters (ie. FOG). */ + private List filters = new ArrayList(); + /** + * The background color of the render loaded from the horizon color of the world. If no world is used than the gray color + * is set to default (as in blender editor. + */ + private ColorRGBA backgroundColor = ColorRGBA.Gray; + } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/BlenderModelLoader.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/BlenderModelLoader.java index 021a6082f..eae047421 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/BlenderModelLoader.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/BlenderModelLoader.java @@ -31,79 +31,10 @@ */ package com.jme3.scene.plugins.blender; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.jme3.asset.AssetInfo; -import com.jme3.asset.BlenderKey; -import com.jme3.asset.BlenderKey.FeaturesToLoad; -import com.jme3.scene.LightNode; -import com.jme3.scene.Node; -import com.jme3.scene.Spatial; -import com.jme3.scene.plugins.blender.animations.AnimationHelper; -import com.jme3.scene.plugins.blender.constraints.ConstraintHelper; -import com.jme3.scene.plugins.blender.file.BlenderFileException; -import com.jme3.scene.plugins.blender.file.FileBlockHeader; -import com.jme3.scene.plugins.blender.objects.ObjectHelper; - /** * This is the main loading class. Have in notice that asset manager needs to have loaders for resources like textures. - * + * @deprecated this class is deprecated; use BlenderLoader instead * @author Marcin Roguski (Kaelthas) */ public class BlenderModelLoader extends BlenderLoader { - - private static final Logger LOGGER = Logger.getLogger(BlenderModelLoader.class.getName()); - - @Override - public Spatial load(AssetInfo assetInfo) throws IOException { - try { - this.setup(assetInfo); - - AnimationHelper animationHelper = blenderContext.getHelper(AnimationHelper.class); - animationHelper.loadAnimations(); - - BlenderKey blenderKey = blenderContext.getBlenderKey(); - List rootObjects = new ArrayList(); - for (FileBlockHeader block : blocks) { - if (block.getCode() == FileBlockHeader.BLOCK_OB00) { - ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class); - Object object = objectHelper.toObject(block.getStructure(blenderContext), blenderContext); - if (object instanceof LightNode && (blenderKey.getFeaturesToLoad() & FeaturesToLoad.LIGHTS) != 0) { - rootObjects.add((LightNode) object); - } else if (object instanceof Node && (blenderKey.getFeaturesToLoad() & FeaturesToLoad.OBJECTS) != 0) { - LOGGER.log(Level.FINE, "{0}: {1}--> {2}", new Object[] { ((Node) object).getName(), ((Node) object).getLocalTranslation().toString(), ((Node) object).getParent() == null ? "null" : ((Node) object).getParent().getName() }); - if (((Node) object).getParent() == null) { - rootObjects.add((Node) object); - } - } - } - } - - // bake constraints after everything is loaded - ConstraintHelper constraintHelper = blenderContext.getHelper(ConstraintHelper.class); - constraintHelper.bakeConstraints(blenderContext); - - // attach the nodes to the root node at the very end so that the root objects have no parents during constraint applying - LOGGER.fine("Creating the root node of the model and applying loaded nodes of the scene to it."); - Node modelRoot = new Node(blenderKey.getName()); - for (Node node : rootObjects) { - if (node instanceof LightNode) { - modelRoot.addLight(((LightNode) node).getLight()); - } - modelRoot.attachChild(node); - } - - return modelRoot; - } catch (BlenderFileException e) { - throw new IOException(e.getLocalizedMessage(), e); - } catch (Exception e) { - throw new IOException("Unexpected importer exception occured: " + e.getLocalizedMessage(), e); - } finally { - this.clear(); - } - } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/animations/AnimationHelper.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/animations/AnimationHelper.java index 1b5a40e79..f8c1cdad3 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/animations/AnimationHelper.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/animations/AnimationHelper.java @@ -25,6 +25,7 @@ import com.jme3.scene.plugins.blender.curves.BezierCurve; import com.jme3.scene.plugins.blender.file.BlenderFileException; import com.jme3.scene.plugins.blender.file.BlenderInputStream; import com.jme3.scene.plugins.blender.file.FileBlockHeader; +import com.jme3.scene.plugins.blender.file.FileBlockHeader.BlockCode; import com.jme3.scene.plugins.blender.file.Pointer; import com.jme3.scene.plugins.blender.file.Structure; import com.jme3.scene.plugins.blender.objects.ObjectHelper; @@ -48,7 +49,7 @@ public class AnimationHelper extends AbstractBlenderHelper { */ public void loadAnimations() throws BlenderFileException { LOGGER.info("Loading animations that will be later applied to scene features."); - List actionHeaders = blenderContext.getFileBlocks(Integer.valueOf(FileBlockHeader.BLOCK_AC00)); + List actionHeaders = blenderContext.getFileBlocks(BlockCode.BLOCK_AC00); if (actionHeaders != null) { for (FileBlockHeader header : actionHeaders) { Structure actionStructure = header.getStructure(blenderContext); diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/cameras/CameraHelper.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/cameras/CameraHelper.java index c5e1f0192..70cb09b1f 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/cameras/CameraHelper.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/cameras/CameraHelper.java @@ -5,7 +5,6 @@ import java.util.logging.Logger; import com.jme3.math.FastMath; import com.jme3.renderer.Camera; -import com.jme3.scene.CameraNode; import com.jme3.scene.plugins.blender.AbstractBlenderHelper; import com.jme3.scene.plugins.blender.BlenderContext; import com.jme3.scene.plugins.blender.file.BlenderFileException; @@ -43,7 +42,7 @@ public class CameraHelper extends AbstractBlenderHelper { * an exception is thrown when there are problems with the * blender file */ - public CameraNode toCamera(Structure structure, BlenderContext blenderContext) throws BlenderFileException { + public Camera toCamera(Structure structure, BlenderContext blenderContext) throws BlenderFileException { if (blenderVersion >= 250) { return this.toCamera250(structure, blenderContext.getSceneStructure()); } else { @@ -63,7 +62,7 @@ public class CameraHelper extends AbstractBlenderHelper { * an exception is thrown when there are problems with the * blender file */ - private CameraNode toCamera250(Structure structure, Structure sceneStructure) throws BlenderFileException { + private Camera toCamera250(Structure structure, Structure sceneStructure) throws BlenderFileException { int width = DEFAULT_CAM_WIDTH; int height = DEFAULT_CAM_HEIGHT; if (sceneStructure != null) { @@ -99,7 +98,7 @@ public class CameraHelper extends AbstractBlenderHelper { sensor = ((Number) structure.getFieldValue(sensorName)).floatValue(); } float focalLength = ((Number) structure.getFieldValue("lens")).floatValue(); - float fov = 2.0f * FastMath.atan((sensor / 2.0f) / focalLength); + float fov = 2.0f * FastMath.atan(sensor / 2.0f / focalLength); if (sensorVertical) { fovY = fov * FastMath.RAD_TO_DEG; } else { @@ -111,7 +110,8 @@ public class CameraHelper extends AbstractBlenderHelper { fovY = ((Number) structure.getFieldValue("ortho_scale")).floatValue(); } camera.setFrustumPerspective(fovY, aspect, clipsta, clipend); - return new CameraNode(null, camera); + camera.setName(structure.getName()); + return camera; } /** @@ -124,7 +124,7 @@ public class CameraHelper extends AbstractBlenderHelper { * an exception is thrown when there are problems with the * blender file */ - private CameraNode toCamera249(Structure structure) throws BlenderFileException { + private Camera toCamera249(Structure structure) throws BlenderFileException { Camera camera = new Camera(DEFAULT_CAM_WIDTH, DEFAULT_CAM_HEIGHT); int type = ((Number) structure.getFieldValue("type")).intValue(); if (type != 0 && type != 1) { @@ -142,6 +142,7 @@ public class CameraHelper extends AbstractBlenderHelper { aspect = ((Number) structure.getFieldValue("ortho_scale")).floatValue(); } camera.setFrustumPerspective(aspect, camera.getWidth() / camera.getHeight(), clipsta, clipend); - return new CameraNode(null, camera); + camera.setName(structure.getName()); + return camera; } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/file/FileBlockHeader.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/file/FileBlockHeader.java index 7bd634254..666da7896 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/file/FileBlockHeader.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/file/FileBlockHeader.java @@ -31,6 +31,8 @@ */ package com.jme3.scene.plugins.blender.file; +import java.util.logging.Logger; + import com.jme3.scene.plugins.blender.BlenderContext; /** @@ -39,39 +41,23 @@ import com.jme3.scene.plugins.blender.BlenderContext; * @author Marcin Roguski */ public class FileBlockHeader { + private static final Logger LOGGER = Logger.getLogger(FileBlockHeader.class.getName()); - public static final int BLOCK_TE00 = 'T' << 24 | 'E' << 16; // TE00 - public static final int BLOCK_ME00 = 'M' << 24 | 'E' << 16; // ME00 - public static final int BLOCK_SR00 = 'S' << 24 | 'R' << 16; // SR00 - public static final int BLOCK_CA00 = 'C' << 24 | 'A' << 16; // CA00 - public static final int BLOCK_LA00 = 'L' << 24 | 'A' << 16; // LA00 - public static final int BLOCK_OB00 = 'O' << 24 | 'B' << 16; // OB00 - public static final int BLOCK_MA00 = 'M' << 24 | 'A' << 16; // MA00 - public static final int BLOCK_SC00 = 'S' << 24 | 'C' << 16; // SC00 - public static final int BLOCK_WO00 = 'W' << 24 | 'O' << 16; // WO00 - public static final int BLOCK_TX00 = 'T' << 24 | 'X' << 16; // TX00 - public static final int BLOCK_IP00 = 'I' << 24 | 'P' << 16; // IP00 - public static final int BLOCK_AC00 = 'A' << 24 | 'C' << 16; // AC00 - public static final int BLOCK_GLOB = 'G' << 24 | 'L' << 16 | 'O' << 8 | 'B'; // GLOB - public static final int BLOCK_REND = 'R' << 24 | 'E' << 16 | 'N' << 8 | 'D'; // REND - public static final int BLOCK_DATA = 'D' << 24 | 'A' << 16 | 'T' << 8 | 'A'; // DATA - public static final int BLOCK_DNA1 = 'D' << 24 | 'N' << 16 | 'A' << 8 | '1'; // DNA1 - public static final int BLOCK_ENDB = 'E' << 24 | 'N' << 16 | 'D' << 8 | 'B'; // ENDB /** Identifier of the file-block [4 bytes]. */ - private int code; + private BlockCode code; /** Total length of the data after the file-block-header [4 bytes]. */ - private int size; + private int size; /** * Memory address the structure was located when written to disk [4 or 8 bytes (defined in file header as a pointer * size)]. */ - private long oldMemoryAddress; + private long oldMemoryAddress; /** Index of the SDNA structure [4 bytes]. */ - private int sdnaIndex; + private int sdnaIndex; /** Number of structure located in this file-block [4 bytes]. */ - private int count; + private int count; /** Start position of the block's data in the stream. */ - private int blockPosition; + private int blockPosition; /** * Constructor. Loads the block header from the given stream during instance creation. @@ -84,13 +70,13 @@ public class FileBlockHeader { */ public FileBlockHeader(BlenderInputStream inputStream, BlenderContext blenderContext) throws BlenderFileException { inputStream.alignPosition(4); - code = inputStream.readByte() << 24 | inputStream.readByte() << 16 | inputStream.readByte() << 8 | inputStream.readByte(); + code = BlockCode.valueOf(inputStream.readByte() << 24 | inputStream.readByte() << 16 | inputStream.readByte() << 8 | inputStream.readByte()); size = inputStream.readInt(); oldMemoryAddress = inputStream.readPointer(); sdnaIndex = inputStream.readInt(); count = inputStream.readInt(); blockPosition = inputStream.getPosition(); - if (FileBlockHeader.BLOCK_DNA1 == code) { + if (BlockCode.BLOCK_DNA1 == code) { blenderContext.setBlockData(new DnaBlockData(inputStream, blenderContext)); } else { inputStream.setPosition(blockPosition + size); @@ -116,7 +102,7 @@ public class FileBlockHeader { * This method returns the code of this data block. * @return the code of this data block */ - public int getCode() { + public BlockCode getCode() { return code; } @@ -157,7 +143,7 @@ public class FileBlockHeader { * @return true if this block is the last one in the file nad false otherwise */ public boolean isLastBlock() { - return FileBlockHeader.BLOCK_ENDB == code; + return BlockCode.BLOCK_ENDB == code; } /** @@ -165,25 +151,44 @@ public class FileBlockHeader { * @return true if this block is the SDNA block and false otherwise */ public boolean isDnaBlock() { - return FileBlockHeader.BLOCK_DNA1 == code; + return BlockCode.BLOCK_DNA1 == code; } @Override public String toString() { - return "FILE BLOCK HEADER [" + this.codeToString(code) + " : " + size + " : " + oldMemoryAddress + " : " + sdnaIndex + " : " + count + "]"; + return "FILE BLOCK HEADER [" + code.toString() + " : " + size + " : " + oldMemoryAddress + " : " + sdnaIndex + " : " + count + "]"; } - /** - * This method transforms the coded bloch id into a string value. - * @param code - * the id of the block - * @return the string value of the block id - */ - protected String codeToString(int code) { - char c1 = (char) ((code & 0xFF000000) >> 24); - char c2 = (char) ((code & 0xFF0000) >> 16); - char c3 = (char) ((code & 0xFF00) >> 8); - char c4 = (char) (code & 0xFF); - return String.valueOf(c1) + c2 + c3 + c4; + public static enum BlockCode { + BLOCK_ME00('M' << 24 | 'E' << 16), // mesh + BLOCK_CA00('C' << 24 | 'A' << 16), // camera + BLOCK_LA00('L' << 24 | 'A' << 16), // lamp + BLOCK_OB00('O' << 24 | 'B' << 16), // object + BLOCK_MA00('M' << 24 | 'A' << 16), // material + BLOCK_SC00('S' << 24 | 'C' << 16), // scene + BLOCK_WO00('W' << 24 | 'O' << 16), // world + BLOCK_TX00('T' << 24 | 'X' << 16), // texture + BLOCK_IP00('I' << 24 | 'P' << 16), // ipo + BLOCK_AC00('A' << 24 | 'C' << 16), // action + BLOCK_IM00('I' << 24 | 'M' << 16), // image + BLOCK_TE00('T' << 24 | 'E' << 16), BLOCK_WM00('W' << 24 | 'M' << 16), BLOCK_SR00('S' << 24 | 'R' << 16), BLOCK_SN00('S' << 24 | 'N' << 16), BLOCK_BR00('B' << 24 | 'R' << 16), BLOCK_LS00('L' << 24 | 'S' << 16), BLOCK_GLOB('G' << 24 | 'L' << 16 | 'O' << 8 | 'B'), BLOCK_REND('R' << 24 | 'E' << 16 | 'N' << 8 | 'D'), BLOCK_DATA('D' << 24 | 'A' << 16 | 'T' << 8 | 'A'), BLOCK_DNA1('D' << 24 | 'N' << 16 | 'A' << 8 | '1'), BLOCK_ENDB('E' << 24 | 'N' << 16 | 'D' << 8 | 'B'), BLOCK_TEST('T' << 24 | 'E' << 16 + | 'S' << 8 | 'T'), BLOCK_UNKN(0); + + private int code; + + private BlockCode(int code) { + this.code = code; + } + + public static BlockCode valueOf(int code) { + for (BlockCode blockCode : BlockCode.values()) { + if (blockCode.code == code) { + return blockCode; + } + } + byte[] codeBytes = new byte[] { (byte) (code >> 24 & 0xFF), (byte) (code >> 16 & 0xFF), (byte) (code >> 8 & 0xFF), (byte) (code & 0xFF) }; + LOGGER.warning("Unknown block header: " + new String(codeBytes)); + return BLOCK_UNKN; + } } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/file/Structure.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/file/Structure.java index 4f0de7e04..941c7a8fc 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/file/Structure.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/file/Structure.java @@ -254,7 +254,8 @@ public class Structure implements Cloneable { Structure id = (Structure) fieldValue; return id == null ? null : id.getFieldValue("name").toString().substring(2);// blender adds 2-charactes as a name prefix } - return null; + Object name = this.getFieldValue("name", null); + return name == null ? null : name.toString().substring(2); } @Override diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/lights/LightHelper.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/lights/LightHelper.java index 17e38c92b..3ae866b7c 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/lights/LightHelper.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/lights/LightHelper.java @@ -40,7 +40,6 @@ import com.jme3.light.PointLight; import com.jme3.light.SpotLight; import com.jme3.math.ColorRGBA; import com.jme3.math.FastMath; -import com.jme3.scene.LightNode; import com.jme3.scene.plugins.blender.AbstractBlenderHelper; import com.jme3.scene.plugins.blender.BlenderContext; import com.jme3.scene.plugins.blender.BlenderContext.LoadedDataType; @@ -67,8 +66,8 @@ public class LightHelper extends AbstractBlenderHelper { super(blenderVersion, blenderContext); } - public LightNode toLight(Structure structure, BlenderContext blenderContext) throws BlenderFileException { - LightNode result = (LightNode) blenderContext.getLoadedFeature(structure.getOldMemoryAddress(), LoadedDataType.FEATURE); + public Light toLight(Structure structure, BlenderContext blenderContext) throws BlenderFileException { + Light result = (Light) blenderContext.getLoadedFeature(structure.getOldMemoryAddress(), LoadedDataType.FEATURE); if (result != null) { return result; } @@ -111,6 +110,7 @@ public class LightHelper extends AbstractBlenderHelper { float g = ((Number) structure.getFieldValue("g")).floatValue(); float b = ((Number) structure.getFieldValue("b")).floatValue(); light.setColor(new ColorRGBA(r, g, b, 1.0f)); - return new LightNode(structure.getName(), light); + light.setName(structure.getName()); + return light; } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/materials/MaterialContext.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/materials/MaterialContext.java index 6e67da967..51c7072b1 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/materials/MaterialContext.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/materials/MaterialContext.java @@ -1,11 +1,15 @@ package com.jme3.scene.plugins.blender.materials; +import java.io.IOException; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.logging.Level; import java.util.logging.Logger; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.Savable; import com.jme3.material.Material; import com.jme3.material.RenderState.BlendMode; import com.jme3.material.RenderState.FaceCullMode; @@ -30,7 +34,7 @@ import com.jme3.util.BufferUtils; * This class holds the data about the material. * @author Marcin Roguski (Kaelthas) */ -public final class MaterialContext { +public final class MaterialContext implements Savable { private static final Logger LOGGER = Logger.getLogger(MaterialContext.class.getName()); // texture mapping types @@ -67,7 +71,7 @@ public final class MaterialContext { int diff_shader = ((Number) structure.getFieldValue("diff_shader")).intValue(); diffuseShader = DiffuseShader.values()[diff_shader]; ambientFactor = ((Number) structure.getFieldValue("amb")).floatValue(); - + if (shadeless) { float r = ((Number) structure.getFieldValue("r")).floatValue(); float g = ((Number) structure.getFieldValue("g")).floatValue(); @@ -107,6 +111,13 @@ public final class MaterialContext { this.transparent = transparent; } + /** + * @return the name of the material + */ + public String getName() { + return name; + } + /** * Applies material to a given geometry. * @@ -314,4 +325,14 @@ public final class MaterialContext { float alpha = ((Number) materialStructure.getFieldValue("alpha")).floatValue(); return new ColorRGBA(r, g, b, alpha); } + + @Override + public void write(JmeExporter e) throws IOException { + throw new IOException("Material context is not for saving! It implements savable only to be passed to another blend file as a Savable in user data!"); + } + + @Override + public void read(JmeImporter e) throws IOException { + throw new IOException("Material context is not for loading! It implements savable only to be passed to another blend file as a Savable in user data!"); + } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/materials/MaterialHelper.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/materials/MaterialHelper.java index 5fcccc389..0809cec9a 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/materials/MaterialHelper.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/materials/MaterialHelper.java @@ -161,12 +161,17 @@ public class MaterialHelper extends AbstractBlenderHelper { * an exception is throw when problems with blend file occur */ public MaterialContext toMaterialContext(Structure structure, BlenderContext blenderContext) throws BlenderFileException { - LOGGER.log(Level.FINE, "Loading material."); MaterialContext result = (MaterialContext) blenderContext.getLoadedFeature(structure.getOldMemoryAddress(), LoadedDataType.FEATURE); if (result != null) { return result; } + if ("ID".equals(structure.getType())) { + LOGGER.fine("Loading material from external blend file."); + return (MaterialContext) this.loadLibrary(structure); + } + + LOGGER.fine("Loading material."); result = new MaterialContext(structure, blenderContext); LOGGER.log(Level.FINE, "Material''s name: {0}", result.name); Long oma = structure.getOldMemoryAddress(); diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/meshes/MeshHelper.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/meshes/MeshHelper.java index 92b236f4c..5284b964a 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/meshes/MeshHelper.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/meshes/MeshHelper.java @@ -40,7 +40,6 @@ import java.util.Map.Entry; import java.util.logging.Level; import java.util.logging.Logger; -import com.jme3.asset.BlenderKey.FeaturesToLoad; import com.jme3.material.Material; import com.jme3.math.ColorRGBA; import com.jme3.math.Vector2f; @@ -52,7 +51,6 @@ import com.jme3.scene.plugins.blender.file.BlenderFileException; import com.jme3.scene.plugins.blender.file.DynamicArray; import com.jme3.scene.plugins.blender.file.Pointer; import com.jme3.scene.plugins.blender.file.Structure; -import com.jme3.scene.plugins.blender.materials.MaterialContext; import com.jme3.scene.plugins.blender.materials.MaterialHelper; import com.jme3.scene.plugins.blender.objects.Properties; @@ -106,17 +104,18 @@ public class MeshHelper extends AbstractBlenderHelper { return temporalMesh.clone(); } + if ("ID".equals(meshStructure.getType())) { + LOGGER.fine("Loading mesh from external blend file."); + return (TemporalMesh) this.loadLibrary(meshStructure); + } + String name = meshStructure.getName(); LOGGER.log(Level.FINE, "Reading mesh: {0}.", name); temporalMesh = new TemporalMesh(meshStructure, blenderContext); LOGGER.fine("Loading materials."); MaterialHelper materialHelper = blenderContext.getHelper(MaterialHelper.class); - MaterialContext[] materials = null; - if ((blenderContext.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.MATERIALS) != 0) { - materials = materialHelper.getMaterials(meshStructure, blenderContext); - } - temporalMesh.setMaterials(materials); + temporalMesh.setMaterials(materialHelper.getMaterials(meshStructure, blenderContext)); LOGGER.fine("Reading custom properties."); Properties properties = this.loadProperties(meshStructure, blenderContext); diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/objects/ObjectHelper.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/objects/ObjectHelper.java index 8e2dc2652..17c0d421e 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/objects/ObjectHelper.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/objects/ObjectHelper.java @@ -40,12 +40,15 @@ import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; -import com.jme3.asset.BlenderKey.FeaturesToLoad; +import com.jme3.light.Light; import com.jme3.math.FastMath; import com.jme3.math.Matrix4f; import com.jme3.math.Transform; import com.jme3.math.Vector3f; +import com.jme3.renderer.Camera; +import com.jme3.scene.CameraNode; import com.jme3.scene.Geometry; +import com.jme3.scene.LightNode; import com.jme3.scene.Mesh.Mode; import com.jme3.scene.Node; import com.jme3.scene.Spatial; @@ -106,39 +109,34 @@ public class ObjectHelper extends AbstractBlenderHelper { * an exception is thrown when the given data is inapropriate */ public Object toObject(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException { - LOGGER.fine("Loading blender object."); + Object loadedResult = blenderContext.getLoadedFeature(objectStructure.getOldMemoryAddress(), LoadedDataType.FEATURE); + if (loadedResult != null) { + return loadedResult; + } + LOGGER.fine("Loading blender object."); + if ("ID".equals(objectStructure.getType())) { + Node object = (Node) this.loadLibrary(objectStructure); + if (object.getParent() != null) { + LOGGER.log(Level.FINEST, "Detaching object {0}, loaded from external file, from its parent.", object); + object.getParent().detachChild(object); + } + return object; + } int type = ((Number) objectStructure.getFieldValue("type")).intValue(); ObjectType objectType = ObjectType.valueOf(type); LOGGER.log(Level.FINE, "Type of the object: {0}.", objectType); - if (objectType == ObjectType.LAMP && !blenderContext.getBlenderKey().shouldLoad(FeaturesToLoad.LIGHTS)) { - LOGGER.fine("Lamps are not included in loading."); - return null; - } - if (objectType == ObjectType.CAMERA && !blenderContext.getBlenderKey().shouldLoad(FeaturesToLoad.CAMERAS)) { - LOGGER.fine("Cameras are not included in loading."); - return null; - } - if (!blenderContext.getBlenderKey().shouldLoad(FeaturesToLoad.OBJECTS)) { - LOGGER.fine("Objects are not included in loading."); - return null; - } + int lay = ((Number) objectStructure.getFieldValue("lay")).intValue(); if ((lay & blenderContext.getBlenderKey().getLayersToLoad()) == 0) { LOGGER.fine("The layer this object is located in is not included in loading."); return null; } - LOGGER.fine("Checking if the object has not been already loaded."); - Object loadedResult = blenderContext.getLoadedFeature(objectStructure.getOldMemoryAddress(), LoadedDataType.FEATURE); - if (loadedResult != null) { - return loadedResult; - } - blenderContext.pushParent(objectStructure); String name = objectStructure.getName(); LOGGER.log(Level.FINE, "Loading obejct: {0}", name); - + int restrictflag = ((Number) objectStructure.getFieldValue("restrictflag")).intValue(); boolean visible = (restrictflag & 0x01) != 0; @@ -171,7 +169,7 @@ public class ObjectHelper extends AbstractBlenderHelper { Pointer pMesh = (Pointer) objectStructure.getFieldValue("data"); List meshesArray = pMesh.fetchData(); TemporalMesh temporalMesh = meshHelper.toTemporalMesh(meshesArray.get(0), blenderContext); - if(temporalMesh != null) { + if (temporalMesh != null) { result.attachChild(temporalMesh); } break; @@ -183,7 +181,7 @@ public class ObjectHelper extends AbstractBlenderHelper { CurvesHelper curvesHelper = blenderContext.getHelper(CurvesHelper.class); Structure curveData = pCurve.fetchData().get(0); TemporalMesh curvesTemporalMesh = curvesHelper.toCurve(curveData, blenderContext); - if(curvesTemporalMesh != null) { + if (curvesTemporalMesh != null) { result.attachChild(curvesTemporalMesh); } } @@ -193,10 +191,12 @@ public class ObjectHelper extends AbstractBlenderHelper { if (pLamp.isNotNull()) { LightHelper lightHelper = blenderContext.getHelper(LightHelper.class); List lampsArray = pLamp.fetchData(); - result = lightHelper.toLight(lampsArray.get(0), blenderContext); - if (result == null) { + Light light = lightHelper.toLight(lampsArray.get(0), blenderContext); + if (light == null) { // probably some light type is not supported, just create a node so that we can maintain child-parent relationship for nodes result = new Node(name); + } else { + result = new LightNode(name, light); } } break; @@ -205,19 +205,25 @@ public class ObjectHelper extends AbstractBlenderHelper { if (pCamera.isNotNull()) { CameraHelper cameraHelper = blenderContext.getHelper(CameraHelper.class); List camerasArray = pCamera.fetchData(); - result = cameraHelper.toCamera(camerasArray.get(0), blenderContext); + Camera camera = cameraHelper.toCamera(camerasArray.get(0), blenderContext); + if (camera == null) { + // just create a node so that we can maintain child-parent relationship for nodes + result = new Node(name); + } else { + result = new CameraNode(name, camera); + } } break; default: LOGGER.log(Level.WARNING, "Unsupported object type: {0}", type); } - + if (result != null) { LOGGER.fine("Storing loaded feature in blender context and applying markers (those will be removed before the final result is released)."); Long oma = objectStructure.getOldMemoryAddress(); blenderContext.addLoadedFeatures(oma, LoadedDataType.STRUCTURE, objectStructure); blenderContext.addLoadedFeatures(oma, LoadedDataType.FEATURE, result); - + blenderContext.addMarker(OMA_MARKER, result, objectStructure.getOldMemoryAddress()); if (objectType == ObjectType.ARMATURE) { blenderContext.addMarker(ARMATURE_NODE_MARKER, result, Boolean.TRUE); @@ -235,13 +241,13 @@ public class ObjectHelper extends AbstractBlenderHelper { for (Modifier modifier : modifiers) { modifier.apply(result, blenderContext); } - + if (result.getChildren() != null && result.getChildren().size() > 0) { - if(result.getChildren().size() == 1 && result.getChild(0) instanceof TemporalMesh) { + if (result.getChildren().size() == 1 && result.getChild(0) instanceof TemporalMesh) { LOGGER.fine("Converting temporal mesh into jme geometries."); - ((TemporalMesh)result.getChild(0)).toGeometries(); + ((TemporalMesh) result.getChild(0)).toGeometries(); } - + LOGGER.fine("Applying proper scale to the geometries."); for (Spatial child : result.getChildren()) { if (child instanceof Geometry) { diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/TextureHelper.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/TextureHelper.java index ad35a2ebc..f6ed89ce7 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/TextureHelper.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/TextureHelper.java @@ -121,7 +121,7 @@ public class TextureHelper extends AbstractBlenderHelper { * data. The returned texture has the name set to the value of its blender * type. * - * @param tex + * @param textureStructure * texture structure filled with data * @param blenderContext * the blender context @@ -130,23 +130,29 @@ public class TextureHelper extends AbstractBlenderHelper { * this exception is thrown when the blend file structure is * somehow invalid or corrupted */ - public Texture getTexture(Structure tex, Structure mTex, BlenderContext blenderContext) throws BlenderFileException { - Texture result = (Texture) blenderContext.getLoadedFeature(tex.getOldMemoryAddress(), LoadedDataType.FEATURE); + public Texture getTexture(Structure textureStructure, Structure mTex, BlenderContext blenderContext) throws BlenderFileException { + Texture result = (Texture) blenderContext.getLoadedFeature(textureStructure.getOldMemoryAddress(), LoadedDataType.FEATURE); if (result != null) { return result; } - int type = ((Number) tex.getFieldValue("type")).intValue(); - int imaflag = ((Number) tex.getFieldValue("imaflag")).intValue(); + + if ("ID".equals(textureStructure.getType())) { + LOGGER.fine("Loading texture from external blend file."); + return (Texture) this.loadLibrary(textureStructure); + } + + int type = ((Number) textureStructure.getFieldValue("type")).intValue(); + int imaflag = ((Number) textureStructure.getFieldValue("imaflag")).intValue(); switch (type) { case TEX_IMAGE:// (it is first because probably this will be most commonly used) - Pointer pImage = (Pointer) tex.getFieldValue("ima"); + Pointer pImage = (Pointer) textureStructure.getFieldValue("ima"); if (pImage.isNotNull()) { Structure image = pImage.fetchData().get(0); - Texture loadedTexture = this.loadTexture(image, imaflag, blenderContext); + Texture loadedTexture = this.loadImageAsTexture(image, imaflag, blenderContext); if (loadedTexture != null) { result = loadedTexture; - this.applyColorbandAndColorFactors(tex, result.getImage(), blenderContext); + this.applyColorbandAndColorFactors(textureStructure, result.getImage(), blenderContext); } } break; @@ -160,7 +166,7 @@ public class TextureHelper extends AbstractBlenderHelper { case TEX_MUSGRAVE: case TEX_VORONOI: case TEX_DISTNOISE: - result = new GeneratedTexture(tex, mTex, textureGeneratorFactory.createTextureGenerator(type), blenderContext); + result = new GeneratedTexture(textureStructure, mTex, textureGeneratorFactory.createTextureGenerator(type), blenderContext); break; case TEX_NONE:// No texture, do nothing break; @@ -169,13 +175,13 @@ public class TextureHelper extends AbstractBlenderHelper { case TEX_PLUGIN: case TEX_ENVMAP: case TEX_OCEAN: - LOGGER.log(Level.WARNING, "Unsupported texture type: {0} for texture: {1}", new Object[] { type, tex.getName() }); + LOGGER.log(Level.WARNING, "Unsupported texture type: {0} for texture: {1}", new Object[] { type, textureStructure.getName() }); break; default: - throw new BlenderFileException("Unknown texture type: " + type + " for texture: " + tex.getName()); + throw new BlenderFileException("Unknown texture type: " + type + " for texture: " + textureStructure.getName()); } if (result != null) { - result.setName(tex.getName()); + result.setName(textureStructure.getName()); result.setWrap(WrapMode.Repeat); // decide if the mipmaps will be generated @@ -195,14 +201,14 @@ public class TextureHelper extends AbstractBlenderHelper { } if (type != TEX_IMAGE) {// only generated textures should have this key - result.setKey(new GeneratedTextureKey(tex.getName())); + result.setKey(new GeneratedTextureKey(textureStructure.getName())); } if (LOGGER.isLoggable(Level.FINE)) { - LOGGER.log(Level.FINE, "Adding texture {0} to the loaded features with OMA = {1}", new Object[] { result.getName(), tex.getOldMemoryAddress() }); + LOGGER.log(Level.FINE, "Adding texture {0} to the loaded features with OMA = {1}", new Object[] { result.getName(), textureStructure.getOldMemoryAddress() }); } - blenderContext.addLoadedFeatures(tex.getOldMemoryAddress(), LoadedDataType.STRUCTURE, tex); - blenderContext.addLoadedFeatures(tex.getOldMemoryAddress(), LoadedDataType.FEATURE, result); + blenderContext.addLoadedFeatures(textureStructure.getOldMemoryAddress(), LoadedDataType.STRUCTURE, textureStructure); + blenderContext.addLoadedFeatures(textureStructure.getOldMemoryAddress(), LoadedDataType.FEATURE, result); } return result; } @@ -222,30 +228,40 @@ public class TextureHelper extends AbstractBlenderHelper { * this exception is thrown when the blend file structure is * somehow invalid or corrupted */ - protected Texture loadTexture(Structure imageStructure, int imaflag, BlenderContext blenderContext) throws BlenderFileException { + public Texture loadImageAsTexture(Structure imageStructure, int imaflag, BlenderContext blenderContext) throws BlenderFileException { LOGGER.log(Level.FINE, "Fetching texture with OMA = {0}", imageStructure.getOldMemoryAddress()); Texture result = null; Image im = (Image) blenderContext.getLoadedFeature(imageStructure.getOldMemoryAddress(), LoadedDataType.FEATURE); if (im == null) { - String texturePath = imageStructure.getFieldValue("name").toString(); - Pointer pPackedFile = (Pointer) imageStructure.getFieldValue("packedfile"); - if (pPackedFile.isNull()) { - LOGGER.log(Level.FINE, "Reading texture from file: {0}", texturePath); - result = this.loadImageFromFile(texturePath, imaflag, blenderContext); + if ("ID".equals(imageStructure.getType())) { + LOGGER.fine("Loading texture from external blend file."); + result = (Texture) this.loadLibrary(imageStructure); } else { - LOGGER.fine("Packed texture. Reading directly from the blend file!"); - Structure packedFile = pPackedFile.fetchData().get(0); - Pointer pData = (Pointer) packedFile.getFieldValue("data"); - FileBlockHeader dataFileBlock = blenderContext.getFileBlock(pData.getOldMemoryAddress()); - blenderContext.getInputStream().setPosition(dataFileBlock.getBlockPosition()); - ImageLoader imageLoader = new ImageLoader(); - - // Should the texture be flipped? It works for sinbad .. - result = new Texture2D(imageLoader.loadImage(blenderContext.getInputStream(), dataFileBlock.getBlockPosition(), true)); + String texturePath = imageStructure.getFieldValue("name").toString(); + Pointer pPackedFile = (Pointer) imageStructure.getFieldValue("packedfile"); + if (pPackedFile.isNull()) { + LOGGER.log(Level.FINE, "Reading texture from file: {0}", texturePath); + result = this.loadImageFromFile(texturePath, imaflag, blenderContext); + } else { + LOGGER.fine("Packed texture. Reading directly from the blend file!"); + Structure packedFile = pPackedFile.fetchData().get(0); + Pointer pData = (Pointer) packedFile.getFieldValue("data"); + FileBlockHeader dataFileBlock = blenderContext.getFileBlock(pData.getOldMemoryAddress()); + blenderContext.getInputStream().setPosition(dataFileBlock.getBlockPosition()); + + // Should the texture be flipped? It works for sinbad .. + result = new Texture2D(new ImageLoader().loadImage(blenderContext.getInputStream(), dataFileBlock.getBlockPosition(), true)); + } } } else { result = new Texture2D(im); } + + if (result != null) {// render result is not being loaded + blenderContext.addLoadedFeatures(imageStructure.getOldMemoryAddress(), LoadedDataType.STRUCTURE, imageStructure); + blenderContext.addLoadedFeatures(imageStructure.getOldMemoryAddress(), LoadedDataType.FEATURE, result.getImage()); + result.setName(imageStructure.getName()); + } return result; } @@ -524,6 +540,18 @@ public class TextureHelper extends AbstractBlenderHelper { return result; } + /** + * Reads the texture data from the given material or sky structure. + * @param structure + * the structure of material or sky + * @param diffuseColorArray + * array of diffuse colors + * @param skyTexture + * indicates it we're going to read sky texture or not + * @return a list of combined textures + * @throws BlenderFileException + * an exception is thrown when problems with reading the blend file occur + */ @SuppressWarnings("unchecked") public List readTextureData(Structure structure, float[] diffuseColorArray, boolean skyTexture) throws BlenderFileException { DynamicArray mtexsArray = (DynamicArray) structure.getFieldValue("mtex"); diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/blending/AbstractTextureBlender.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/blending/AbstractTextureBlender.java index 5c3504771..8ff55baac 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/blending/AbstractTextureBlender.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/blending/AbstractTextureBlender.java @@ -1,10 +1,12 @@ package com.jme3.scene.plugins.blender.textures.blending; +import java.util.logging.Logger; + +import jme3tools.converters.MipMapGenerator; + import com.jme3.scene.plugins.blender.BlenderContext; import com.jme3.scene.plugins.blender.materials.MaterialHelper; import com.jme3.texture.Image; -import java.util.logging.Logger; -import jme3tools.converters.MipMapGenerator; /** * An abstract class that contains the basic methods used by the classes that @@ -103,12 +105,12 @@ import jme3tools.converters.MipMapGenerator; public void copyBlendingData(TextureBlender textureBlender) { if (textureBlender instanceof AbstractTextureBlender) { - this.flag = ((AbstractTextureBlender) textureBlender).flag; - this.negateTexture = ((AbstractTextureBlender) textureBlender).negateTexture; - this.blendType = ((AbstractTextureBlender) textureBlender).blendType; - this.materialColor = ((AbstractTextureBlender) textureBlender).materialColor.clone(); - this.color = ((AbstractTextureBlender) textureBlender).color.clone(); - this.blendFactor = ((AbstractTextureBlender) textureBlender).blendFactor; + flag = ((AbstractTextureBlender) textureBlender).flag; + negateTexture = ((AbstractTextureBlender) textureBlender).negateTexture; + blendType = ((AbstractTextureBlender) textureBlender).blendType; + materialColor = ((AbstractTextureBlender) textureBlender).materialColor.clone(); + color = ((AbstractTextureBlender) textureBlender).color.clone(); + blendFactor = ((AbstractTextureBlender) textureBlender).blendFactor; } else { LOGGER.warning("Cannot copy blending data from other types than " + this.getClass()); } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderFactory.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderFactory.java index c682ed1e5..f487e240d 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderFactory.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderFactory.java @@ -31,13 +31,13 @@ */ package com.jme3.scene.plugins.blender.textures.blending; +import java.util.logging.Level; +import java.util.logging.Logger; + import com.jme3.scene.plugins.blender.BlenderContext; import com.jme3.texture.Image; import com.jme3.texture.Image.Format; -import java.util.logging.Level; -import java.util.logging.Logger; - /** * This class creates the texture blending class depending on the texture type. * @@ -66,7 +66,6 @@ public class TextureBlenderFactory { * the texture format * @return texture blending class */ - @SuppressWarnings("deprecation") public static TextureBlender createTextureBlender(Format format, int flag, boolean negate, int blendType, float[] materialColor, float[] color, float colfac) { switch (format) { case Luminance8: diff --git a/jme3-core/src/main/java/com/jme3/scene/UserData.java b/jme3-core/src/main/java/com/jme3/scene/UserData.java index 4b5d70404..3047618fc 100644 --- a/jme3-core/src/main/java/com/jme3/scene/UserData.java +++ b/jme3-core/src/main/java/com/jme3/scene/UserData.java @@ -33,6 +33,12 @@ package com.jme3.scene; import com.jme3.export.*; import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** * UserData is used to contain user data objects @@ -48,28 +54,40 @@ public final class UserData implements Savable { * shape generation should ignore them. */ public static final String JME_PHYSICSIGNORE = "JmePhysicsIgnore"; - + /** * For geometries using shared mesh, this will specify the shared * mesh reference. */ - public static final String JME_SHAREDMESH = "JmeSharedMesh"; - - protected byte type; - protected Object value; + public static final String JME_SHAREDMESH = "JmeSharedMesh"; + + private static final int TYPE_INTEGER = 0; + private static final int TYPE_FLOAT = 1; + private static final int TYPE_BOOLEAN = 2; + private static final int TYPE_STRING = 3; + private static final int TYPE_LONG = 4; + private static final int TYPE_SAVABLE = 5; + private static final int TYPE_LIST = 6; + private static final int TYPE_MAP = 7; + private static final int TYPE_ARRAY = 8; + + protected byte type; + protected Object value; public UserData() { } /** - * Creates a new UserData with the given + * Creates a new UserData with the given * type and value. * - * @param type Type of data, should be between 0 and 4. - * @param value Value of the data + * @param type + * Type of data, should be between 0 and 8. + * @param value + * Value of the data */ public UserData(byte type, Object value) { - assert type >= 0 && type <= 4; + assert type >= 0 && type <= 8; this.type = type; this.value = value; } @@ -85,15 +103,23 @@ public final class UserData implements Savable { public static byte getObjectType(Object type) { if (type instanceof Integer) { - return 0; + return TYPE_INTEGER; } else if (type instanceof Float) { - return 1; + return TYPE_FLOAT; } else if (type instanceof Boolean) { - return 2; + return TYPE_BOOLEAN; } else if (type instanceof String) { - return 3; + return TYPE_STRING; } else if (type instanceof Long) { - return 4; + return TYPE_LONG; + } else if (type instanceof Savable) { + return TYPE_SAVABLE; + } else if (type instanceof List) { + return TYPE_LIST; + } else if (type instanceof Map) { + return TYPE_MAP; + } else if (type instanceof Object[]) { + return TYPE_ARRAY; } else { throw new IllegalArgumentException("Unsupported type: " + type.getClass().getName()); } @@ -101,56 +127,195 @@ public final class UserData implements Savable { public void write(JmeExporter ex) throws IOException { OutputCapsule oc = ex.getCapsule(this); - oc.write(type, "type", (byte)0); + oc.write(type, "type", (byte) 0); switch (type) { - case 0: + case TYPE_INTEGER: int i = (Integer) value; oc.write(i, "intVal", 0); break; - case 1: + case TYPE_FLOAT: float f = (Float) value; oc.write(f, "floatVal", 0f); break; - case 2: + case TYPE_BOOLEAN: boolean b = (Boolean) value; oc.write(b, "boolVal", false); break; - case 3: + case TYPE_STRING: String s = (String) value; oc.write(s, "strVal", null); break; - case 4: + case TYPE_LONG: Long l = (Long) value; oc.write(l, "longVal", 0l); break; + case TYPE_SAVABLE: + Savable sav = (Savable) value; + oc.write(sav, "savableVal", null); + break; + case TYPE_LIST: + this.writeList(oc, (List) value, "0"); + break; + case TYPE_MAP: + Map map = (Map) value; + this.writeList(oc, map.keySet(), "0"); + this.writeList(oc, map.values(), "1"); + break; + case TYPE_ARRAY: + this.writeList(oc, Arrays.asList((Object[]) value), "0"); + break; default: - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Unsupported value type: " + value.getClass()); } } public void read(JmeImporter im) throws IOException { InputCapsule ic = im.getCapsule(this); type = ic.readByte("type", (byte) 0); - switch (type) { - case 0: + case TYPE_INTEGER: value = ic.readInt("intVal", 0); break; - case 1: + case TYPE_FLOAT: value = ic.readFloat("floatVal", 0f); break; - case 2: + case TYPE_BOOLEAN: value = ic.readBoolean("boolVal", false); break; - case 3: + case TYPE_STRING: value = ic.readString("strVal", null); break; - case 4: + case TYPE_LONG: value = ic.readLong("longVal", 0l); break; + case TYPE_SAVABLE: + value = ic.readSavable("savableVal", null); + break; + case TYPE_LIST: + value = this.readList(ic, "0"); + break; + case TYPE_MAP: + Map map = new HashMap(); + List keys = this.readList(ic, "0"); + List values = this.readList(ic, "1"); + for (int i = 0; i < keys.size(); ++i) { + map.put(keys.get(i), values.get(i)); + } + value = map; + break; + case TYPE_ARRAY: + value = this.readList(ic, "0").toArray(); + break; default: - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Unknown type of stored data: " + type); + } + } + + /** + * The method stores a list in the capsule. + * @param oc + * output capsule + * @param list + * the list to be stored + * @throws IOException + */ + private void writeList(OutputCapsule oc, Collection list, String listName) throws IOException { + if (list != null) { + oc.write(list.size(), listName + "size", 0); + int counter = 0; + for (Object o : list) { + // t is for 'type'; v is for 'value' + if (o instanceof Integer) { + oc.write(TYPE_INTEGER, listName + "t" + counter, 0); + oc.write((Integer) o, listName + "v" + counter, 0); + } else if (o instanceof Float) { + oc.write(TYPE_FLOAT, listName + "t" + counter, 0); + oc.write((Float) o, listName + "v" + counter, 0f); + } else if (o instanceof Boolean) { + oc.write(TYPE_BOOLEAN, listName + "t" + counter, 0); + oc.write((Boolean) o, listName + "v" + counter, false); + } else if (o instanceof String || o == null) {// treat null's like Strings just to store them and keep the List like the user intended + oc.write(TYPE_STRING, listName + "t" + counter, 0); + oc.write((String) o, listName + "v" + counter, null); + } else if (o instanceof Long) { + oc.write(TYPE_LONG, listName + "t" + counter, 0); + oc.write((Long) o, listName + "v" + counter, 0L); + } else if (o instanceof Savable) { + oc.write(TYPE_SAVABLE, listName + "t" + counter, 0); + oc.write((Savable) o, listName + "v" + counter, null); + } else if(o instanceof Object[]) { + oc.write(TYPE_ARRAY, listName + "t" + counter, 0); + this.writeList(oc, Arrays.asList((Object[]) o), listName + "v" + counter); + } else if(o instanceof List) { + oc.write(TYPE_LIST, listName + "t" + counter, 0); + this.writeList(oc, (List) o, listName + "v" + counter); + } else if(o instanceof Map) { + oc.write(TYPE_MAP, listName + "t" + counter, 0); + Map map = (Map) o; + this.writeList(oc, map.keySet(), listName + "v(keys)" + counter); + this.writeList(oc, map.values(), listName + "v(vals)" + counter); + } else { + throw new UnsupportedOperationException("Unsupported type stored in the list: " + o.getClass()); + } + + ++counter; + } + } else { + oc.write(0, "size", 0); + } + } + + /** + * The method loads a list from the given input capsule. + * @param ic + * the input capsule + * @return loaded list (an empty list in case its size is 0) + * @throws IOException + */ + private List readList(InputCapsule ic, String listName) throws IOException { + int size = ic.readInt(listName + "size", 0); + List list = new ArrayList(size); + for (int i = 0; i < size; ++i) { + int type = ic.readInt(listName + "t" + i, 0); + switch (type) { + case TYPE_INTEGER: + list.add(ic.readInt(listName + "v" + i, 0)); + break; + case TYPE_FLOAT: + list.add(ic.readFloat(listName + "v" + i, 0)); + break; + case TYPE_BOOLEAN: + list.add(ic.readBoolean(listName + "v" + i, false)); + break; + case TYPE_STRING: + list.add(ic.readString(listName + "v" + i, null)); + break; + case TYPE_LONG: + list.add(ic.readLong(listName + "v" + i, 0L)); + break; + case TYPE_SAVABLE: + list.add(ic.readSavable(listName + "v" + i, null)); + break; + case TYPE_ARRAY: + list.add(this.readList(ic, listName + "v" + i).toArray()); + break; + case TYPE_LIST: + list.add(this.readList(ic, listName + "v" + i)); + break; + case TYPE_MAP: + Map map = new HashMap(); + List keys = this.readList(ic, listName + "v(keys)" + i); + List values = this.readList(ic, listName + "v(vals)" + i); + for (int j = 0; j < keys.size(); ++j) { + map.put(keys.get(j), values.get(j)); + } + list.add(map); + break; + default: + throw new UnsupportedOperationException("Unknown type of stored data in a list: " + type); + } } + return list; } } From a5c98a59be27285100cb41c0bca705753329c06a Mon Sep 17 00:00:00 2001 From: jmekaelthas Date: Mon, 23 Mar 2015 21:01:21 +0100 Subject: [PATCH 03/47] Refactoring: catching up wth latest jme3 core changes. --- .../blender/landscape/LandscapeHelper.java | 2 +- .../blender/materials/MaterialHelper.java | 3 ++- .../blender/textures/CombinedTexture.java | 8 +++++- .../plugins/blender/textures/ImageUtils.java | 11 ++++---- .../blender/textures/TriangulatedTexture.java | 27 ++++++++++--------- .../textures/blending/TextureBlenderAWT.java | 4 ++- .../textures/blending/TextureBlenderDDS.java | 5 +++- .../blending/TextureBlenderLuminance.java | 4 ++- .../textures/io/AWTPixelInputOutput.java | 18 +++++++++++++ .../blender/textures/io/PixelIOFactory.java | 2 ++ 10 files changed, 60 insertions(+), 24 deletions(-) diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/landscape/LandscapeHelper.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/landscape/LandscapeHelper.java index c05eed775..8466d5cce 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/landscape/LandscapeHelper.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/landscape/LandscapeHelper.java @@ -208,6 +208,6 @@ public class LandscapeHelper extends AbstractBlenderHelper { } LOGGER.fine("Sky texture created. Creating sky."); - return SkyFactory.createSky(blenderContext.getAssetManager(), texture, false); + return SkyFactory.createSky(blenderContext.getAssetManager(), texture, SkyFactory.EnvMapType.CubeMap); } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/materials/MaterialHelper.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/materials/MaterialHelper.java index 0809cec9a..885c5850e 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/materials/MaterialHelper.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/materials/MaterialHelper.java @@ -51,6 +51,7 @@ import com.jme3.scene.plugins.blender.file.Structure; import com.jme3.shader.VarType; import com.jme3.texture.Image; import com.jme3.texture.Image.Format; +import com.jme3.texture.image.ColorSpace; import com.jme3.texture.Texture; import com.jme3.util.BufferUtils; @@ -217,7 +218,7 @@ public class MaterialHelper extends AbstractBlenderHelper { } } - image = new Image(Format.RGBA8, w, h, bb); + image = new Image(Format.RGBA8, w, h, bb, ColorSpace.Linear); texture.setImage(image); result.setTextureParam("Texture", VarType.Texture2D, texture); diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/CombinedTexture.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/CombinedTexture.java index 5bfc9eb78..b7d6958ca 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/CombinedTexture.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/CombinedTexture.java @@ -444,13 +444,17 @@ public class CombinedTexture { case RGB8: return true;// these types have no alpha by definition case ABGR8: + case DXT1A: case DXT3: case DXT5: case Luminance16FAlpha16F: case Luminance8Alpha8: case RGBA16F: case RGBA32F: - case RGBA8:// with these types it is better to make sure if the texture is or is not transparent + case RGBA8: + case ARGB8: + case BGRA8: + case RGB5A1:// with these types it is better to make sure if the texture is or is not transparent PixelInputOutput pixelInputOutput = PixelIOFactory.getPixelIO(image.getFormat()); TexturePixel pixel = new TexturePixel(); int depth = image.getDepth() == 0 ? 1 : image.getDepth(); @@ -465,6 +469,8 @@ public class CombinedTexture { } } return true; + default: + throw new IllegalStateException("Unknown image format: " + image.getFormat()); } } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/ImageUtils.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/ImageUtils.java index 66740769d..99ea9b5d2 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/ImageUtils.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/ImageUtils.java @@ -41,13 +41,13 @@ public final class ImageUtils { public static Image createEmptyImage(Format format, int width, int height, int depth) { int bufferSize = width * height * (format.getBitsPerPixel() >> 3); if (depth < 2) { - return new Image(format, width, height, BufferUtils.createByteBuffer(bufferSize)); + return new Image(format, width, height, BufferUtils.createByteBuffer(bufferSize), com.jme3.texture.image.ColorSpace.Linear); } ArrayList data = new ArrayList(depth); for (int i = 0; i < depth; ++i) { data.add(BufferUtils.createByteBuffer(bufferSize)); } - return new Image(Format.RGB8, width, height, depth, data); + return new Image(Format.RGB8, width, height, depth, data, com.jme3.texture.image.ColorSpace.Linear); } /** @@ -337,7 +337,7 @@ public final class ImageUtils { alphas[0] = data.get() * 255.0f; alphas[1] = data.get() * 255.0f; //the casts to long must be done here because otherwise 32-bit integers would be shifetd by 32 and 40 bits which would result in improper values - long alphaIndices = (long)data.get() | (long)data.get() << 8 | (long)data.get() << 16 | (long)data.get() << 24 | (long)data.get() << 32 | (long)data.get() << 40; + long alphaIndices = data.get() | (long)data.get() << 8 | (long)data.get() << 16 | (long)data.get() << 24 | (long)data.get() << 32 | (long)data.get() << 40; if (alphas[0] > alphas[1]) {// 6 interpolated alpha values. alphas[2] = (6 * alphas[0] + alphas[1]) / 7; alphas[3] = (5 * alphas[0] + 2 * alphas[1]) / 7; @@ -404,7 +404,8 @@ public final class ImageUtils { dataArray.add(BufferUtils.createByteBuffer(bytes)); } - Image result = depth > 1 ? new Image(Format.RGBA8, image.getWidth(), image.getHeight(), depth, dataArray) : new Image(Format.RGBA8, image.getWidth(), image.getHeight(), dataArray.get(0)); + Image result = depth > 1 ? new Image(Format.RGBA8, image.getWidth(), image.getHeight(), depth, dataArray, com.jme3.texture.image.ColorSpace.Linear) : + new Image(Format.RGBA8, image.getWidth(), image.getHeight(), dataArray.get(0), com.jme3.texture.image.ColorSpace.Linear); if (newMipmapSizes != null) { result.setMipMapSizes(newMipmapSizes); } @@ -467,6 +468,6 @@ public final class ImageUtils { private static Image toJmeImage(BufferedImage bufferedImage, Format format) { ByteBuffer byteBuffer = BufferUtils.createByteBuffer(bufferedImage.getWidth() * bufferedImage.getHeight() * 3); ImageToAwt.convert(bufferedImage, format, byteBuffer); - return new Image(format, bufferedImage.getWidth(), bufferedImage.getHeight(), byteBuffer); + return new Image(format, bufferedImage.getWidth(), bufferedImage.getHeight(), byteBuffer, com.jme3.texture.image.ColorSpace.Linear); } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/TriangulatedTexture.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/TriangulatedTexture.java index fd4044244..9a4889109 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/TriangulatedTexture.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/TriangulatedTexture.java @@ -31,6 +31,7 @@ import com.jme3.texture.Image; import com.jme3.texture.Image.Format; import com.jme3.texture.Texture; import com.jme3.texture.Texture2D; +import com.jme3.texture.image.ColorSpace; import com.jme3.util.BufferUtils; /** @@ -77,7 +78,7 @@ import com.jme3.util.BufferUtils; for (int i = 0; i < facesCount; ++i) { faceTextures.add(new TriangleTextureElement(i, texture2d.getImage(), uvs, true, blenderContext)); } - this.format = texture2d.getImage().getFormat(); + format = texture2d.getImage().getFormat(); } /** @@ -113,7 +114,7 @@ import com.jme3.util.BufferUtils; */ public void blend(TextureBlender textureBlender, TriangulatedTexture baseTexture, BlenderContext blenderContext) { Format newFormat = null; - for (TriangleTextureElement triangleTextureElement : this.faceTextures) { + for (TriangleTextureElement triangleTextureElement : faceTextures) { Image baseImage = baseTexture == null ? null : baseTexture.getFaceTextureElement(triangleTextureElement.faceIndex).image; triangleTextureElement.image = textureBlender.blend(triangleTextureElement.image, baseImage, blenderContext); if (newFormat == null) { @@ -122,7 +123,7 @@ import com.jme3.util.BufferUtils; throw new IllegalArgumentException("Face texture element images MUST have the same image format!"); } } - this.format = newFormat; + format = newFormat; } /** @@ -242,7 +243,7 @@ import com.jme3.util.BufferUtils; resultUVS.set(entry.getKey().faceIndex * 3 + 2, uvs[2]); } - Image resultImage = new Image(format, resultImageWidth, resultImageHeight, BufferUtils.createByteBuffer(resultImageWidth * resultImageHeight * (format.getBitsPerPixel() >> 3))); + Image resultImage = new Image(format, resultImageWidth, resultImageHeight, BufferUtils.createByteBuffer(resultImageWidth * resultImageHeight * (format.getBitsPerPixel() >> 3)), ColorSpace.Linear); resultTexture = new Texture2D(resultImage); for (Entry entry : imageLayoutData.entrySet()) { if (!duplicatedFaceIndexes.contains(entry.getKey().faceIndex)) { @@ -420,7 +421,7 @@ import com.jme3.util.BufferUtils; data.put(pixel.getA8()); } } - image = new Image(Format.RGBA8, width, height, data); + image = new Image(Format.RGBA8, width, height, data, ColorSpace.Linear); // modify the UV values so that they fit the new image float heightUV = maxUVY - minUVY; @@ -481,7 +482,7 @@ import com.jme3.util.BufferUtils; imageHeight = 1; } ByteBuffer data = BufferUtils.createByteBuffer(imageWidth * imageHeight * (imageFormat.getBitsPerPixel() >> 3)); - image = new Image(texture.getImage().getFormat(), imageWidth, imageHeight, data); + image = new Image(texture.getImage().getFormat(), imageWidth, imageHeight, data, ColorSpace.Linear); // computing the pixels PixelInputOutput pixelWriter = PixelIOFactory.getPixelIO(imageFormat); @@ -529,8 +530,8 @@ import com.jme3.util.BufferUtils; public void computeFinalUVCoordinates(int totalImageWidth, int totalImageHeight, int xPos, int yPos, Vector2f[] result) { for (int i = 0; i < 3; ++i) { result[i] = new Vector2f(); - result[i].x = xPos / (float) totalImageWidth + this.uv[i].x * (this.image.getWidth() / (float) totalImageWidth); - result[i].y = yPos / (float) totalImageHeight + this.uv[i].y * (this.image.getHeight() / (float) totalImageHeight); + result[i].x = xPos / (float) totalImageWidth + uv[i].x * (image.getWidth() / (float) totalImageWidth); + result[i].y = yPos / (float) totalImageHeight + uv[i].y * (image.getHeight() / (float) totalImageHeight); } } @@ -623,9 +624,9 @@ import com.jme3.util.BufferUtils; * a position in 3D space */ public RectangleEnvelope(Vector3f pointPosition) { - this.min = pointPosition; - this.h = this.w = Vector3f.ZERO; - this.width = this.height = 1; + min = pointPosition; + h = w = Vector3f.ZERO; + width = height = 1; } /** @@ -642,8 +643,8 @@ import com.jme3.util.BufferUtils; this.min = min; this.h = h; this.w = w; - this.width = w.length(); - this.height = h.length(); + width = w.length(); + height = h.length(); } @Override diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderAWT.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderAWT.java index d7f26b1be..1d7bf2146 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderAWT.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderAWT.java @@ -38,7 +38,9 @@ import com.jme3.scene.plugins.blender.textures.io.PixelIOFactory; import com.jme3.scene.plugins.blender.textures.io.PixelInputOutput; import com.jme3.texture.Image; import com.jme3.texture.Image.Format; +import com.jme3.texture.image.ColorSpace; import com.jme3.util.BufferUtils; + import java.nio.ByteBuffer; import java.util.ArrayList; @@ -141,7 +143,7 @@ public class TextureBlenderAWT extends AbstractTextureBlender { dataArray.add(newData); } - Image result = depth > 1 ? new Image(Format.RGBA8, width, height, depth, dataArray) : new Image(Format.RGBA8, width, height, dataArray.get(0)); + Image result = depth > 1 ? new Image(Format.RGBA8, width, height, depth, dataArray, ColorSpace.Linear) : new Image(Format.RGBA8, width, height, dataArray.get(0), ColorSpace.Linear); if (image.getMipMapSizes() != null) { result.setMipMapSizes(image.getMipMapSizes().clone()); } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderDDS.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderDDS.java index 264ebc1da..b40e2cc8f 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderDDS.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderDDS.java @@ -6,9 +6,12 @@ import com.jme3.scene.plugins.blender.textures.io.PixelIOFactory; import com.jme3.scene.plugins.blender.textures.io.PixelInputOutput; import com.jme3.texture.Image; import com.jme3.texture.Image.Format; +import com.jme3.texture.image.ColorSpace; import com.jme3.util.BufferUtils; + import java.nio.ByteBuffer; import java.util.ArrayList; + import jme3tools.converters.RGB565; /** @@ -119,7 +122,7 @@ public class TextureBlenderDDS extends TextureBlenderAWT { dataArray.add(newData); } - Image result = dataArray.size() > 1 ? new Image(format, width, height, depth, dataArray) : new Image(format, width, height, dataArray.get(0)); + Image result = dataArray.size() > 1 ? new Image(format, width, height, depth, dataArray, ColorSpace.Linear) : new Image(format, width, height, dataArray.get(0), ColorSpace.Linear); if (image.getMipMapSizes() != null) { result.setMipMapSizes(image.getMipMapSizes().clone()); } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderLuminance.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderLuminance.java index cbfc28631..1f2ae01e1 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderLuminance.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderLuminance.java @@ -7,7 +7,9 @@ import com.jme3.scene.plugins.blender.textures.io.PixelIOFactory; import com.jme3.scene.plugins.blender.textures.io.PixelInputOutput; import com.jme3.texture.Image; import com.jme3.texture.Image.Format; +import com.jme3.texture.image.ColorSpace; import com.jme3.util.BufferUtils; + import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.logging.Level; @@ -93,7 +95,7 @@ public class TextureBlenderLuminance extends AbstractTextureBlender { dataArray.add(newData); } - Image result = depth > 1 ? new Image(Format.RGBA8, width, height, depth, dataArray) : new Image(Format.RGBA8, width, height, dataArray.get(0)); + Image result = depth > 1 ? new Image(Format.RGBA8, width, height, depth, dataArray, ColorSpace.Linear) : new Image(Format.RGBA8, width, height, dataArray.get(0), ColorSpace.Linear); if (image.getMipMapSizes() != null) { result.setMipMapSizes(image.getMipMapSizes().clone()); } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/io/AWTPixelInputOutput.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/io/AWTPixelInputOutput.java index efacee639..569c328be 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/io/AWTPixelInputOutput.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/io/AWTPixelInputOutput.java @@ -17,12 +17,18 @@ import jme3tools.converters.RGB565; case RGBA8: pixel.fromARGB8(data.get(index + 3), data.get(index), data.get(index + 1), data.get(index + 2)); break; + case ARGB8: + pixel.fromARGB8(data.get(index), data.get(index + 1), data.get(index + 2), data.get(index + 3)); + break; case ABGR8: pixel.fromARGB8(data.get(index), data.get(index + 3), data.get(index + 2), data.get(index + 1)); break; case BGR8: pixel.fromARGB8((byte) 0xFF, data.get(index + 2), data.get(index + 1), data.get(index)); break; + case BGRA8: + pixel.fromARGB8(data.get(index + 3), data.get(index + 2), data.get(index + 1), data.get(index)); + break; case RGB8: pixel.fromARGB8((byte) 0xFF, data.get(index), data.get(index + 1), data.get(index + 2)); break; @@ -72,6 +78,12 @@ import jme3tools.converters.RGB565; data.put(index + 2, pixel.getB8()); data.put(index + 3, pixel.getA8()); break; + case ARGB8: + data.put(index, pixel.getA8()); + data.put(index + 1, pixel.getR8()); + data.put(index + 2, pixel.getG8()); + data.put(index + 3, pixel.getB8()); + break; case ABGR8: data.put(index, pixel.getA8()); data.put(index + 1, pixel.getB8()); @@ -83,6 +95,12 @@ import jme3tools.converters.RGB565; data.put(index + 1, pixel.getG8()); data.put(index + 2, pixel.getR8()); break; + case BGRA8: + data.put(index, pixel.getB8()); + data.put(index + 1, pixel.getG8()); + data.put(index + 2, pixel.getR8()); + data.put(index + 3, pixel.getA8()); + break; case RGB8: data.put(index, pixel.getR8()); data.put(index + 1, pixel.getG8()); diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/io/PixelIOFactory.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/io/PixelIOFactory.java index 916090228..47cf7090b 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/io/PixelIOFactory.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/io/PixelIOFactory.java @@ -26,7 +26,9 @@ public class PixelIOFactory { case ABGR8: case RGBA8: case BGR8: + case BGRA8: case RGB8: + case ARGB8: case RGB111110F: case RGB16F: case RGB16F_to_RGB111110F: From 15ec285b1a8db3bcf9e37e081add056983760432 Mon Sep 17 00:00:00 2001 From: jmekaelthas Date: Wed, 25 Mar 2015 21:59:48 +0100 Subject: [PATCH 04/47] Feature: added support for linear and constant interpolation types for ipo curves. --- .../plugins/blender/curves/BezierCurve.java | 45 +++++++++++++------ 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/curves/BezierCurve.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/curves/BezierCurve.java index 9876702c8..96a91335d 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/curves/BezierCurve.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/curves/BezierCurve.java @@ -1,10 +1,11 @@ package com.jme3.scene.plugins.blender.curves; +import java.util.ArrayList; +import java.util.List; + import com.jme3.math.Vector3f; import com.jme3.scene.plugins.blender.file.DynamicArray; import com.jme3.scene.plugins.blender.file.Structure; -import java.util.ArrayList; -import java.util.List; /** * A class that helps to calculate the bezier curves calues. It uses doubles for performing calculations to minimize @@ -12,21 +13,26 @@ import java.util.List; * @author Marcin Roguski (Kaelthas) */ public class BezierCurve { + private static final int IPO_CONSTANT = 0; + private static final int IPO_LINEAR = 1; + private static final int IPO_BEZIER = 2; - public static final int X_VALUE = 0; - public static final int Y_VALUE = 1; - public static final int Z_VALUE = 2; + public static final int X_VALUE = 0; + public static final int Y_VALUE = 1; + public static final int Z_VALUE = 2; /** * The type of the curve. Describes the data it modifies. * Used in ipos calculations. */ - private int type; + private int type; /** The dimension of the curve. */ - private int dimension; + private int dimension; /** A table of the bezier points. */ - private double[][][] bezierPoints; + private double[][][] bezierPoints; /** Array that stores a radius for each bezier triple. */ - private double[] radiuses; + private double[] radiuses; + /** Interpolation types of the bezier triples. */ + private int[] interpolations; public BezierCurve(final int type, final List bezTriples, final int dimension) { this(type, bezTriples, dimension, false); @@ -44,6 +50,7 @@ public class BezierCurve { // the third index specifies the coordinates of the specific point in a bezier triple bezierPoints = new double[bezTriples.size()][3][dimension]; radiuses = new double[bezTriples.size()]; + interpolations = new int[bezTriples.size()]; int i = 0, j, k; for (Structure bezTriple : bezTriples) { DynamicArray vec = (DynamicArray) bezTriple.getFieldValue("vec"); @@ -57,7 +64,8 @@ public class BezierCurve { bezierPoints[i][j][1] = temp; } } - radiuses[i++] = ((Number) bezTriple.getFieldValue("radius")).floatValue(); + radiuses[i] = ((Number) bezTriple.getFieldValue("radius")).floatValue(); + interpolations[i++] = ((Number) bezTriple.getFieldValue("ipo", IPO_BEZIER)).intValue(); } } @@ -75,10 +83,19 @@ public class BezierCurve { for (int i = 0; i < bezierPoints.length - 1; ++i) { if (frame >= bezierPoints[i][1][0] && frame <= bezierPoints[i + 1][1][0]) { double t = (frame - bezierPoints[i][1][0]) / (bezierPoints[i + 1][1][0] - bezierPoints[i][1][0]); - double oneMinusT = 1.0f - t; - double oneMinusT2 = oneMinusT * oneMinusT; - double t2 = t * t; - return bezierPoints[i][1][valuePart] * oneMinusT2 * oneMinusT + 3.0f * bezierPoints[i][2][valuePart] * t * oneMinusT2 + 3.0f * bezierPoints[i + 1][0][valuePart] * t2 * oneMinusT + bezierPoints[i + 1][1][valuePart] * t2 * t; + switch (interpolations[i]) { + case IPO_BEZIER: + double oneMinusT = 1.0f - t; + double oneMinusT2 = oneMinusT * oneMinusT; + double t2 = t * t; + return bezierPoints[i][1][valuePart] * oneMinusT2 * oneMinusT + 3.0f * bezierPoints[i][2][valuePart] * t * oneMinusT2 + 3.0f * bezierPoints[i + 1][0][valuePart] * t2 * oneMinusT + bezierPoints[i + 1][1][valuePart] * t2 * t; + case IPO_LINEAR: + return (1f - t) * bezierPoints[i][1][valuePart] + t * bezierPoints[i + 1][1][valuePart]; + case IPO_CONSTANT: + return bezierPoints[i][1][valuePart]; + default: + throw new IllegalStateException("Unknown interpolation type for curve: " + interpolations[i]); + } } } if (frame < bezierPoints[0][1][0]) { From 25da36e5907b79f2b538d86cdaa56e8aa90e4834 Mon Sep 17 00:00:00 2001 From: Kirill Vainer Date: Thu, 26 Mar 2015 17:02:01 -0400 Subject: [PATCH 05/47] jme3-bullet-native: copyBinaryToLibs to depend on building native lib --- jme3-bullet-native/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jme3-bullet-native/build.gradle b/jme3-bullet-native/build.gradle index 163485f0e..dbb74981a 100644 --- a/jme3-bullet-native/build.gradle +++ b/jme3-bullet-native/build.gradle @@ -175,7 +175,7 @@ binaries.withType(SharedLibraryBinary) { binary -> // Add depend on build jar.dependsOn builderTask // Add output to libs folder - task "copyBinaryToLibs${targetPlatform}"(type: Copy) { + task "copyBinaryToLibs${targetPlatform}"(type: Copy, dependsOn: builderTask) { from builderTask.outputFile into "libs/native/${targetPlatform.operatingSystem.name}/${targetPlatform.architecture.name}" } From 1076b489abbe3ecb5b3db97fd4783d7e78e18358 Mon Sep 17 00:00:00 2001 From: Kirill Vainer Date: Thu, 26 Mar 2015 17:03:04 -0400 Subject: [PATCH 06/47] GLRenderer: remove check FB error calls as it causes GPU stall --- .../com/jme3/renderer/opengl/GLRenderer.java | 77 +++++-------------- 1 file changed, 21 insertions(+), 56 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java index 9d080384a..9ae1c8cc7 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java @@ -1321,13 +1321,6 @@ public class GLRenderer implements Renderer { glfbo.glBindFramebufferEXT(GLExt.GL_FRAMEBUFFER_EXT, prevFBO); - try { - checkFrameBufferError(); - } catch (IllegalStateException ex) { - logger.log(Level.SEVERE, "Source FBO:\n{0}", src); - logger.log(Level.SEVERE, "Dest FBO:\n{0}", dst); - throw ex; - } } else { throw new RendererException("Framebuffer blitting not supported by the video hardware"); } @@ -1488,6 +1481,8 @@ public class GLRenderer implements Renderer { updateFrameBufferAttachment(fb, colorBuf); } + checkFrameBufferError(); + fb.clearUpdateNeeded(); } @@ -1645,8 +1640,6 @@ public class GLRenderer implements Renderer { assert context.boundFBO == fb.getId(); context.boundFB = fb; - - checkFrameBufferError(); } } @@ -2221,53 +2214,25 @@ public class GLRenderer implements Renderer { int usage = convertUsage(vb.getUsage()); vb.getData().rewind(); -// if (created || vb.hasDataSizeChanged()) { - // upload data based on format - switch (vb.getFormat()) { - case Byte: - case UnsignedByte: - gl.glBufferData(target, (ByteBuffer) vb.getData(), usage); - break; - // case Half: - case Short: - case UnsignedShort: - gl.glBufferData(target, (ShortBuffer) vb.getData(), usage); - break; - case Int: - case UnsignedInt: - glext.glBufferData(target, (IntBuffer) vb.getData(), usage); - break; - case Float: - gl.glBufferData(target, (FloatBuffer) vb.getData(), usage); - break; - default: - throw new UnsupportedOperationException("Unknown buffer format."); - } -// } else { -// // Invalidate buffer data (orphan) before uploading new data. -// switch (vb.getFormat()) { -// case Byte: -// case UnsignedByte: -// gl.glBufferSubData(target, 0, (ByteBuffer) vb.getData()); -// break; -// case Short: -// case UnsignedShort: -// gl.glBufferSubData(target, 0, (ShortBuffer) vb.getData()); -// break; -// case Int: -// case UnsignedInt: -// gl.glBufferSubData(target, 0, (IntBuffer) vb.getData()); -// break; -// case Float: -// gl.glBufferSubData(target, 0, (FloatBuffer) vb.getData()); -// break; -// case Double: -// gl.glBufferSubData(target, 0, (DoubleBuffer) vb.getData()); -// break; -// default: -// throw new UnsupportedOperationException("Unknown buffer format."); -// } -// } + switch (vb.getFormat()) { + case Byte: + case UnsignedByte: + gl.glBufferData(target, (ByteBuffer) vb.getData(), usage); + break; + case Short: + case UnsignedShort: + gl.glBufferData(target, (ShortBuffer) vb.getData(), usage); + break; + case Int: + case UnsignedInt: + glext.glBufferData(target, (IntBuffer) vb.getData(), usage); + break; + case Float: + gl.glBufferData(target, (FloatBuffer) vb.getData(), usage); + break; + default: + throw new UnsupportedOperationException("Unknown buffer format."); + } vb.clearUpdateNeeded(); } From 31835366b2f3e833f34f701f00c780571ded78bf Mon Sep 17 00:00:00 2001 From: rainmantsr Date: Fri, 27 Mar 2015 20:37:23 +0100 Subject: [PATCH 07/47] Add: sweepTest to jme3-bullet-native --- .../cpp/com_jme3_bullet_PhysicsSpace.cpp | 62 +++++++++++++ .../native/cpp/com_jme3_bullet_PhysicsSpace.h | 9 ++ .../src/native/cpp/jmeBulletUtil.cpp | 90 +++++++++++++++++++ .../src/native/cpp/jmeBulletUtil.h | 3 + .../src/native/cpp/jmeClasses.cpp | 79 ++++++++++++++++ .../src/native/cpp/jmeClasses.h | 12 +++ .../java/com/jme3/bullet/PhysicsSpace.java | 59 ++++++------ 7 files changed, 286 insertions(+), 28 deletions(-) diff --git a/jme3-bullet-native/src/native/cpp/com_jme3_bullet_PhysicsSpace.cpp b/jme3-bullet-native/src/native/cpp/com_jme3_bullet_PhysicsSpace.cpp index b51630c55..32bc249dd 100644 --- a/jme3-bullet-native/src/native/cpp/com_jme3_bullet_PhysicsSpace.cpp +++ b/jme3-bullet-native/src/native/cpp/com_jme3_bullet_PhysicsSpace.cpp @@ -468,6 +468,68 @@ extern "C" { return; } + + + JNIEXPORT void JNICALL Java_com_jme3_bullet_PhysicsSpace_sweepTest_1native + (JNIEnv * env, jobject object, jlong shapeId, jobject from, jobject to, jlong spaceId, jobject resultlist, jfloat allowedCcdPenetration) { + + jmePhysicsSpace* space = reinterpret_cast (spaceId); + if (space == NULL) { + jclass newExc = env->FindClass("java/lang/NullPointerException"); + env->ThrowNew(newExc, "The physics space does not exist."); + return; + } + + btCollisionShape* shape = reinterpret_cast (shapeId); + if (shape == NULL) { + jclass newExc = env->FindClass("java/lang/NullPointerException"); + env->ThrowNew(newExc, "The shape does not exist."); + return; + } + + struct AllConvexResultCallback : public btCollisionWorld::ConvexResultCallback { + + AllConvexResultCallback(const btTransform& convexFromWorld, const btTransform & convexToWorld) : m_convexFromWorld(convexFromWorld), m_convexToWorld(convexToWorld) { + } + jobject resultlist; + JNIEnv* env; + btTransform m_convexFromWorld; //used to calculate hitPointWorld from hitFraction + btTransform m_convexToWorld; + + btVector3 m_hitNormalWorld; + btVector3 m_hitPointWorld; + + virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult, bool normalInWorldSpace) { + if (normalInWorldSpace) { + m_hitNormalWorld = convexResult.m_hitNormalLocal; + } + else { + m_hitNormalWorld = convexResult.m_hitCollisionObject->getWorldTransform().getBasis() * convexResult.m_hitNormalLocal; + } + m_hitPointWorld.setInterpolate3(m_convexFromWorld.getBasis() * m_convexFromWorld.getOrigin(), m_convexToWorld.getBasis() * m_convexToWorld.getOrigin(), convexResult.m_hitFraction); + + jmeBulletUtil::addSweepResult(env, resultlist, &m_hitNormalWorld, &m_hitPointWorld, convexResult.m_hitFraction, convexResult.m_hitCollisionObject); + + return 1.f; + } + }; + + btTransform native_to = btTransform(); + jmeBulletUtil::convert(env, to, &native_to); + + btTransform native_from = btTransform(); + jmeBulletUtil::convert(env, from, &native_from); + + btScalar native_allowed_ccd_penetration = btScalar(allowedCcdPenetration); + + + AllConvexResultCallback resultCallback(native_from, native_to); + resultCallback.env = env; + resultCallback.resultlist = resultlist; + space->getDynamicsWorld()->convexSweepTest((btConvexShape *) shape, native_from, native_to, resultCallback, native_allowed_ccd_penetration); + return; + } + #ifdef __cplusplus } #endif diff --git a/jme3-bullet-native/src/native/cpp/com_jme3_bullet_PhysicsSpace.h b/jme3-bullet-native/src/native/cpp/com_jme3_bullet_PhysicsSpace.h index e040f8da8..b499ff04c 100644 --- a/jme3-bullet-native/src/native/cpp/com_jme3_bullet_PhysicsSpace.h +++ b/jme3-bullet-native/src/native/cpp/com_jme3_bullet_PhysicsSpace.h @@ -165,6 +165,15 @@ JNIEXPORT void JNICALL Java_com_jme3_bullet_PhysicsSpace_initNativePhysics JNIEXPORT void JNICALL Java_com_jme3_bullet_PhysicsSpace_finalizeNative (JNIEnv *, jobject, jlong); + +/* +* Class: com_jme3_bullet_PhysicsSpace +* Method : sweepTest_native +* Signature: (J;L;Lcom/jme3/math/Transform;Lcom/jme3/math/Transform;L;JLjava/util/List;F)V +*/ +JNIEXPORT void JNICALL Java_com_jme3_bullet_PhysicsSpace_sweepTest_1native +(JNIEnv *, jobject, jlong, jobject, jobject, jlong, jobject, jfloat); + #ifdef __cplusplus } #endif diff --git a/jme3-bullet-native/src/native/cpp/jmeBulletUtil.cpp b/jme3-bullet-native/src/native/cpp/jmeBulletUtil.cpp index fa88ad473..04b56a545 100644 --- a/jme3-bullet-native/src/native/cpp/jmeBulletUtil.cpp +++ b/jme3-bullet-native/src/native/cpp/jmeBulletUtil.cpp @@ -59,6 +59,38 @@ void jmeBulletUtil::convert(JNIEnv* env, jobject in, btVector3* out) { out->setZ(z); } +void jmeBulletUtil::convert(JNIEnv* env, jobject in, btQuaternion* out) { + if (in == NULL || out == NULL) { + jmeClasses::throwNPE(env); + } + float x = env->GetFloatField(in, jmeClasses::Quaternion_x); + if (env->ExceptionCheck()) { + env->Throw(env->ExceptionOccurred()); + return; + } + float y = env->GetFloatField(in, jmeClasses::Quaternion_y); //env->CallFloatMethod(in, jmeClasses::Vector3f_getY); + if (env->ExceptionCheck()) { + env->Throw(env->ExceptionOccurred()); + return; + } + float z = env->GetFloatField(in, jmeClasses::Quaternion_z); //env->CallFloatMethod(in, jmeClasses::Vector3f_getZ); + if (env->ExceptionCheck()) { + env->Throw(env->ExceptionOccurred()); + return; + } + + float w = env->GetFloatField(in, jmeClasses::Quaternion_w); //env->CallFloatMethod(in, jmeClasses::Vector3f_getZ); + if (env->ExceptionCheck()) { + env->Throw(env->ExceptionOccurred()); + return; + } + out->setX(x); + out->setY(y); + out->setZ(z); + out->setW(w); +} + + void jmeBulletUtil::convert(JNIEnv* env, const btVector3* in, jobject out) { if (in == NULL || out == NULL) { jmeClasses::throwNPE(env); @@ -325,3 +357,61 @@ void jmeBulletUtil::addResult(JNIEnv* env, jobject resultlist, btVector3* hitnor return; } } + + +void jmeBulletUtil::addSweepResult(JNIEnv* env, jobject resultlist, btVector3* hitnormal, btVector3* m_hitPointWorld, btScalar m_hitFraction, const btCollisionObject* hitobject) { + + jobject singleresult = env->AllocObject(jmeClasses::PhysicsSweep_Class); + jobject hitnormalvec = env->AllocObject(jmeClasses::Vector3f); + + convert(env, hitnormal, hitnormalvec); + jmeUserPointer *up1 = (jmeUserPointer*)hitobject->getUserPointer(); + + env->SetObjectField(singleresult, jmeClasses::PhysicsSweep_normalInWorldSpace, hitnormalvec); + env->SetFloatField(singleresult, jmeClasses::PhysicsSweep_hitfraction, m_hitFraction); + + env->SetObjectField(singleresult, jmeClasses::PhysicsSweep_collisionObject, up1->javaCollisionObject); + env->CallVoidMethod(resultlist, jmeClasses::PhysicsSweep_addmethod, singleresult); + if (env->ExceptionCheck()) { + env->Throw(env->ExceptionOccurred()); + return; + } +} + +void jmeBulletUtil::convert(JNIEnv* env, jobject in, btTransform* out) { + if (in == NULL || out == NULL) { + jmeClasses::throwNPE(env); + } + + jobject translation_vec = env->CallObjectMethod(in, jmeClasses::Transform_translation); + if (env->ExceptionCheck()) { + env->Throw(env->ExceptionOccurred()); + return; + } + + jobject rot_quat = env->CallObjectMethod(in, jmeClasses::Transform_rotation); + if (env->ExceptionCheck()) { + env->Throw(env->ExceptionOccurred()); + return; + } + + /* + //Scale currently not supported by bullet + //@TBD: Create an assertion somewhere to avoid scale values + jobject scale_vec = env->GetObjectField(in, jmeClasses::Transform_scale); + if (env->ExceptionCheck()) { + env->Throw(env->ExceptionOccurred()); + return; + } + */ + btVector3 native_translation_vec = btVector3(); + //btVector3 native_scale_vec = btVector3(); + btQuaternion native_rot_quat = btQuaternion(); + + convert(env, translation_vec, &native_translation_vec); + //convert(env, scale_vec, native_scale_vec); + convert(env, rot_quat, &native_rot_quat); + + out->setRotation(native_rot_quat); + out->setOrigin(native_translation_vec); +} diff --git a/jme3-bullet-native/src/native/cpp/jmeBulletUtil.h b/jme3-bullet-native/src/native/cpp/jmeBulletUtil.h index 96509ab9e..fa09d09cc 100644 --- a/jme3-bullet-native/src/native/cpp/jmeBulletUtil.h +++ b/jme3-bullet-native/src/native/cpp/jmeBulletUtil.h @@ -42,10 +42,13 @@ public: static void convert(JNIEnv* env, jobject in, btVector3* out); static void convert(JNIEnv* env, const btVector3* in, jobject out); static void convert(JNIEnv* env, jobject in, btMatrix3x3* out); + static void convert(JNIEnv* env, jobject in, btQuaternion* out); static void convert(JNIEnv* env, const btMatrix3x3* in, jobject out); static void convertQuat(JNIEnv* env, jobject in, btMatrix3x3* out); static void convertQuat(JNIEnv* env, const btMatrix3x3* in, jobject out); + static void convert(JNIEnv* env, jobject in, btTransform* out); static void addResult(JNIEnv* env, jobject resultlist, btVector3* hitnormal, btVector3* m_hitPointWorld,const btScalar m_hitFraction,const btCollisionObject* hitobject); + static void addSweepResult(JNIEnv* env, jobject resultlist, btVector3* hitnormal, btVector3* m_hitPointWorld, const btScalar m_hitFraction, const btCollisionObject* hitobject); private: jmeBulletUtil(){}; ~jmeBulletUtil(){}; diff --git a/jme3-bullet-native/src/native/cpp/jmeClasses.cpp b/jme3-bullet-native/src/native/cpp/jmeClasses.cpp index e0b5515b4..6b7caa0e9 100644 --- a/jme3-bullet-native/src/native/cpp/jmeClasses.cpp +++ b/jme3-bullet-native/src/native/cpp/jmeClasses.cpp @@ -91,6 +91,21 @@ jfieldID jmeClasses::PhysicsRay_collisionObject; jclass jmeClasses::PhysicsRay_listresult; jmethodID jmeClasses::PhysicsRay_addmethod; +jclass jmeClasses::PhysicsSweep_Class; +jmethodID jmeClasses::PhysicsSweep_newSingleResult; + +jfieldID jmeClasses::PhysicsSweep_normalInWorldSpace; +jfieldID jmeClasses::PhysicsSweep_hitfraction; +jfieldID jmeClasses::PhysicsSweep_collisionObject; + +jclass jmeClasses::PhysicsSweep_listresult; +jmethodID jmeClasses::PhysicsSweep_addmethod; + + +jclass jmeClasses::Transform; +jmethodID jmeClasses::Transform_rotation; +jmethodID jmeClasses::Transform_translation; + //private fields //JNIEnv* jmeClasses::env; JavaVM* jmeClasses::vm; @@ -240,6 +255,70 @@ void jmeClasses::initJavaClasses(JNIEnv* env) { env->Throw(env->ExceptionOccurred()); return; } + + PhysicsSweep_Class = (jclass)env->NewGlobalRef(env->FindClass("com/jme3/bullet/collision/PhysicsSweepTestResult")); + if (env->ExceptionCheck()) { + env->Throw(env->ExceptionOccurred()); + return; +} + + PhysicsSweep_newSingleResult = env->GetMethodID(PhysicsSweep_Class, "", "()V"); + if (env->ExceptionCheck()) { + env->Throw(env->ExceptionOccurred()); + return; + } + + PhysicsSweep_normalInWorldSpace = env->GetFieldID(PhysicsSweep_Class, "hitNormalLocal", "Lcom/jme3/math/Vector3f;"); + if (env->ExceptionCheck()) { + env->Throw(env->ExceptionOccurred()); + return; + } + + + PhysicsSweep_hitfraction = env->GetFieldID(PhysicsSweep_Class, "hitFraction", "F"); + if (env->ExceptionCheck()) { + env->Throw(env->ExceptionOccurred()); + return; + } + + + PhysicsSweep_collisionObject = env->GetFieldID(PhysicsSweep_Class, "collisionObject", "Lcom/jme3/bullet/collision/PhysicsCollisionObject;"); + if (env->ExceptionCheck()) { + env->Throw(env->ExceptionOccurred()); + return; + } + + PhysicsSweep_listresult = env->FindClass("java/util/List"); + PhysicsSweep_listresult = (jclass)env->NewGlobalRef(PhysicsSweep_listresult); + if (env->ExceptionCheck()) { + env->Throw(env->ExceptionOccurred()); + return; + } + + PhysicsSweep_addmethod = env->GetMethodID(PhysicsSweep_listresult, "add", "(Ljava/lang/Object;)Z"); + if (env->ExceptionCheck()) { + env->Throw(env->ExceptionOccurred()); + return; + } + + Transform = (jclass)env->NewGlobalRef(env->FindClass("com/jme3/math/Transform")); + if (env->ExceptionCheck()) { + env->Throw(env->ExceptionOccurred()); + return; + } + + Transform_rotation = env->GetMethodID(Transform, "getRotation", "()Lcom/jme3/math/Quaternion;"); + if (env->ExceptionCheck()) { + env->Throw(env->ExceptionOccurred()); + return; + } + + Transform_translation = env->GetMethodID(Transform, "getTranslation", "()Lcom/jme3/math/Vector3f;"); + if (env->ExceptionCheck()) { + env->Throw(env->ExceptionOccurred()); + return; + } + } void jmeClasses::throwNPE(JNIEnv* env) { diff --git a/jme3-bullet-native/src/native/cpp/jmeClasses.h b/jme3-bullet-native/src/native/cpp/jmeClasses.h index 24684dae9..bb1b0e99a 100644 --- a/jme3-bullet-native/src/native/cpp/jmeClasses.h +++ b/jme3-bullet-native/src/native/cpp/jmeClasses.h @@ -89,6 +89,18 @@ public: static jclass PhysicsRay_listresult; static jmethodID PhysicsRay_addmethod; + static jclass PhysicsSweep_Class; + static jmethodID PhysicsSweep_newSingleResult; + static jfieldID PhysicsSweep_normalInWorldSpace; + static jfieldID PhysicsSweep_hitfraction; + static jfieldID PhysicsSweep_collisionObject; + static jclass PhysicsSweep_listresult; + static jmethodID PhysicsSweep_addmethod; + + static jclass Transform; + static jmethodID Transform_rotation; + static jmethodID Transform_translation; + static jclass DebugMeshCallback; static jmethodID DebugMeshCallback_addVector; diff --git a/jme3-bullet/src/main/java/com/jme3/bullet/PhysicsSpace.java b/jme3-bullet/src/main/java/com/jme3/bullet/PhysicsSpace.java index 0f011f8d7..5aa4f6abf 100644 --- a/jme3-bullet/src/main/java/com/jme3/bullet/PhysicsSpace.java +++ b/jme3-bullet/src/main/java/com/jme3/bullet/PhysicsSpace.java @@ -820,6 +820,10 @@ public class PhysicsSpace { // return lrr.hitFraction; // } // } +// +// + + /** * Performs a sweep collision test and returns the results as a list of * PhysicsSweepTestResults
You have to use different Transforms for @@ -828,16 +832,16 @@ public class PhysicsSpace { * center. */ public List sweepTest(CollisionShape shape, Transform start, Transform end) { - List results = new LinkedList(); -// if (!(shape.getCShape() instanceof ConvexShape)) { -// logger.log(Level.WARNING, "Trying to sweep test with incompatible mesh shape!"); -// return results; -// } -// dynamicsWorld.convexSweepTest((ConvexShape) shape.getCShape(), Converter.convert(start, sweepTrans1), Converter.convert(end, sweepTrans2), new InternalSweepListener(results)); - return results; + List results = new LinkedList(); + sweepTest(shape, start, end , results); + return (List) results; + } + public List sweepTest(CollisionShape shape, Transform start, Transform end, List results) { + return sweepTest(shape, start, end, results, 0.0f); } + public native void sweepTest_native(long shape, Transform from, Transform to, long physicsSpaceId, List results, float allowedCcdPenetration); /** * Performs a sweep collision test and returns the results as a list of * PhysicsSweepTestResults
You have to use different Transforms for @@ -845,31 +849,30 @@ public class PhysicsSpace { * collision if it starts INSIDE an object and is moving AWAY from its * center. */ - public List sweepTest(CollisionShape shape, Transform start, Transform end, List results) { + public List sweepTest(CollisionShape shape, Transform start, Transform end, List results, float allowedCcdPenetration ) { results.clear(); -// if (!(shape.getCShape() instanceof ConvexShape)) { -// logger.log(Level.WARNING, "Trying to sweep test with incompatible mesh shape!"); -// return results; -// } -// dynamicsWorld.convexSweepTest((ConvexShape) shape.getCShape(), Converter.convert(start, sweepTrans1), Converter.convert(end, sweepTrans2), new InternalSweepListener(results)); + sweepTest_native(shape.getObjectId(), start, end, physicsSpaceId, results, allowedCcdPenetration); return results; } -// private class InternalSweepListener extends CollisionWorld.ConvexResultCallback { -// -// private List results; -// -// public InternalSweepListener(List results) { -// this.results = results; -// } -// -// @Override -// public float addSingleResult(LocalConvexResult lcr, boolean bln) { -// PhysicsCollisionObject obj = (PhysicsCollisionObject) lcr.hitCollisionObject.getUserPointer(); -// results.add(new PhysicsSweepTestResult(obj, Converter.convert(lcr.hitNormalLocal), lcr.hitFraction, bln)); -// return lcr.hitFraction; -// } -// } +/* private class InternalSweepListener extends CollisionWorld.ConvexResultCallback { + + private List results; + + public InternalSweepListener(List results) { + this.results = results; + } + + @Override + public float addSingleResult(LocalConvexResult lcr, boolean bln) { + PhysicsCollisionObject obj = (PhysicsCollisionObject) lcr.hitCollisionObject.getUserPointer(); + results.add(new PhysicsSweepTestResult(obj, Converter.convert(lcr.hitNormalLocal), lcr.hitFraction, bln)); + return lcr.hitFraction; + } + } + + */ + /** * destroys the current PhysicsSpace so that a new one can be created */ From 400c09a6331dff96076690fe3767e331ed702f73 Mon Sep 17 00:00:00 2001 From: shadowislord Date: Fri, 27 Mar 2015 21:32:52 -0400 Subject: [PATCH 08/47] jme3-core: fix minor issues pointed in static analysis --- .../main/java/com/jme3/asset/AssetConfig.java | 2 +- .../com/jme3/asset/DesktopAssetManager.java | 5 ++--- .../main/java/com/jme3/asset/ImplHandler.java | 6 +++--- .../main/java/com/jme3/light/SpotLight.java | 2 +- .../main/java/com/jme3/scene/BatchNode.java | 2 +- .../src/main/java/com/jme3/scene/Node.java | 2 +- .../jme3/scene/instancing/InstancedNode.java | 2 +- .../main/java/com/jme3/shader/DefineList.java | 2 +- .../java/com/jme3/texture/FrameBuffer.java | 7 ++++--- .../src/main/java/com/jme3/util/IntMap.java | 3 ++- .../jme3/util/TangentBinormalGenerator.java | 18 +++++++----------- .../util/blockparser/BlockLanguageParser.java | 2 +- .../java/com/jme3/audio/plugins/WAVLoader.java | 2 +- .../com/jme3/export/binary/BinaryImporter.java | 4 +--- 14 files changed, 27 insertions(+), 32 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/asset/AssetConfig.java b/jme3-core/src/main/java/com/jme3/asset/AssetConfig.java index 50b6e38af..71c4d8bb1 100644 --- a/jme3-core/src/main/java/com/jme3/asset/AssetConfig.java +++ b/jme3-core/src/main/java/com/jme3/asset/AssetConfig.java @@ -69,7 +69,7 @@ public final class AssetConfig { public static void loadText(AssetManager assetManager, URL configUrl) throws IOException{ InputStream in = configUrl.openStream(); try { - Scanner scan = new Scanner(in); + Scanner scan = new Scanner(in, "UTF-8"); scan.useLocale(Locale.US); // Fix commas / periods ?? while (scan.hasNext()){ String cmd = scan.next(); diff --git a/jme3-core/src/main/java/com/jme3/asset/DesktopAssetManager.java b/jme3-core/src/main/java/com/jme3/asset/DesktopAssetManager.java index 4364f3b60..66a6fbbdf 100644 --- a/jme3-core/src/main/java/com/jme3/asset/DesktopAssetManager.java +++ b/jme3-core/src/main/java/com/jme3/asset/DesktopAssetManager.java @@ -312,13 +312,12 @@ public class DesktopAssetManager implements AssetManager { protected T registerAndCloneSmartAsset(AssetKey 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); + T clone = (T) proc.createClone(obj); if (cache != null && clone != obj) { cache.registerAssetClone(key, clone); } else { @@ -326,8 +325,8 @@ public class DesktopAssetManager implements AssetManager { + "CloneableSmartAsset but doesn't have cache or " + "was not cloned"); } + return clone; } - return clone; } @Override diff --git a/jme3-core/src/main/java/com/jme3/asset/ImplHandler.java b/jme3-core/src/main/java/com/jme3/asset/ImplHandler.java index 3601bc463..73e6d8df3 100644 --- a/jme3-core/src/main/java/com/jme3/asset/ImplHandler.java +++ b/jme3-core/src/main/java/com/jme3/asset/ImplHandler.java @@ -47,7 +47,7 @@ import java.util.logging.Logger; * This is done by keeping an instance of each asset loader and asset * locator object in a thread local. */ -public class ImplHandler { +final class ImplHandler { private static final Logger logger = Logger.getLogger(ImplHandler.class.getName()); @@ -75,7 +75,7 @@ public class ImplHandler { this.assetManager = assetManager; } - protected class ImplThreadLocal extends ThreadLocal { + protected static class ImplThreadLocal extends ThreadLocal { private final Class type; private final String path; @@ -83,7 +83,7 @@ public class ImplHandler { public ImplThreadLocal(Class type, String[] extensions){ this.type = type; - this.extensions = extensions; + this.extensions = extensions.clone(); this.path = null; } diff --git a/jme3-core/src/main/java/com/jme3/light/SpotLight.java b/jme3-core/src/main/java/com/jme3/light/SpotLight.java index 0499ce254..f02f76fa4 100644 --- a/jme3-core/src/main/java/com/jme3/light/SpotLight.java +++ b/jme3-core/src/main/java/com/jme3/light/SpotLight.java @@ -56,7 +56,7 @@ import java.io.IOException; * the light intensity slowly decrease between the inner cone and the outer cone. * @author Nehon */ -public class SpotLight extends Light implements Savable { +public class SpotLight extends Light { protected Vector3f position = new Vector3f(); protected Vector3f direction = new Vector3f(0,-1,0); diff --git a/jme3-core/src/main/java/com/jme3/scene/BatchNode.java b/jme3-core/src/main/java/com/jme3/scene/BatchNode.java index 8cfed4244..475cfdf71 100644 --- a/jme3-core/src/main/java/com/jme3/scene/BatchNode.java +++ b/jme3-core/src/main/java/com/jme3/scene/BatchNode.java @@ -64,7 +64,7 @@ import java.util.logging.Logger; * TODO more automagic (batch when needed in the updateLogicalState) * @author Nehon */ -public class BatchNode extends GeometryGroupNode implements Savable { +public class BatchNode extends GeometryGroupNode { private static final Logger logger = Logger.getLogger(BatchNode.class.getName()); /** diff --git a/jme3-core/src/main/java/com/jme3/scene/Node.java b/jme3-core/src/main/java/com/jme3/scene/Node.java index 816140e21..5edfa021b 100644 --- a/jme3-core/src/main/java/com/jme3/scene/Node.java +++ b/jme3-core/src/main/java/com/jme3/scene/Node.java @@ -58,7 +58,7 @@ import java.util.logging.Logger; * @author Gregg Patton * @author Joshua Slack */ -public class Node extends Spatial implements Savable { +public class Node extends Spatial { private static final Logger logger = Logger.getLogger(Node.class.getName()); diff --git a/jme3-core/src/main/java/com/jme3/scene/instancing/InstancedNode.java b/jme3-core/src/main/java/com/jme3/scene/instancing/InstancedNode.java index b3cb26da0..554b8606a 100644 --- a/jme3-core/src/main/java/com/jme3/scene/instancing/InstancedNode.java +++ b/jme3-core/src/main/java/com/jme3/scene/instancing/InstancedNode.java @@ -57,7 +57,7 @@ public class InstancedNode extends GeometryGroupNode { setGeometryStartIndex(geom, startIndex); } - private static class InstanceTypeKey implements Cloneable { + private static final class InstanceTypeKey implements Cloneable { Mesh mesh; Material material; diff --git a/jme3-core/src/main/java/com/jme3/shader/DefineList.java b/jme3-core/src/main/java/com/jme3/shader/DefineList.java index 93d4cbeaf..dd605fc7e 100644 --- a/jme3-core/src/main/java/com/jme3/shader/DefineList.java +++ b/jme3-core/src/main/java/com/jme3/shader/DefineList.java @@ -40,7 +40,7 @@ import java.io.IOException; import java.util.Map; import java.util.TreeMap; -public class DefineList implements Savable, Cloneable { +public final class DefineList implements Savable, Cloneable { private static final String ONE = "1"; diff --git a/jme3-core/src/main/java/com/jme3/texture/FrameBuffer.java b/jme3-core/src/main/java/com/jme3/texture/FrameBuffer.java index ed053339c..bc21fd82b 100644 --- a/jme3-core/src/main/java/com/jme3/texture/FrameBuffer.java +++ b/jme3-core/src/main/java/com/jme3/texture/FrameBuffer.java @@ -72,9 +72,10 @@ import java.util.ArrayList; * @author Kirill Vainer */ public class FrameBuffer extends NativeObject { - public static int SLOT_UNDEF = -1; - public static int SLOT_DEPTH = -100; - public static int SLOT_DEPTH_STENCIL = -101; + + public static final int SLOT_UNDEF = -1; + public static final int SLOT_DEPTH = -100; + public static final int SLOT_DEPTH_STENCIL = -101; private int width = 0; private int height = 0; diff --git a/jme3-core/src/main/java/com/jme3/util/IntMap.java b/jme3-core/src/main/java/com/jme3/util/IntMap.java index fed91be06..38ffb2431 100644 --- a/jme3-core/src/main/java/com/jme3/util/IntMap.java +++ b/jme3-core/src/main/java/com/jme3/util/IntMap.java @@ -34,6 +34,7 @@ package com.jme3.util; import com.jme3.util.IntMap.Entry; import java.util.Iterator; import java.util.Map; +import java.util.NoSuchElementException; /** * Similar to a {@link Map} except that ints are used as keys. @@ -234,7 +235,7 @@ public final class IntMap implements Iterable>, Cloneable { public Entry next() { if (el >= size) - throw new IllegalStateException("No more elements!"); + throw new NoSuchElementException("No more elements!"); if (cur != null){ Entry e = cur; diff --git a/jme3-core/src/main/java/com/jme3/util/TangentBinormalGenerator.java b/jme3-core/src/main/java/com/jme3/util/TangentBinormalGenerator.java index ae82b3422..0f9aac1fc 100644 --- a/jme3-core/src/main/java/com/jme3/util/TangentBinormalGenerator.java +++ b/jme3-core/src/main/java/com/jme3/util/TangentBinormalGenerator.java @@ -274,11 +274,9 @@ public class TangentBinormalGenerator { triData.setIndex(index); triData.triangleOffset = i * 3 ; } - if (triData != null) { - vertices.get(index[0]).triangles.add(triData); - vertices.get(index[1]).triangles.add(triData); - vertices.get(index[2]).triangles.add(triData); - } + vertices.get(index[0]).triangles.add(triData); + vertices.get(index[1]).triangles.add(triData); + vertices.get(index[2]).triangles.add(triData); } return vertices; @@ -483,7 +481,7 @@ public class TangentBinormalGenerator { boolean isDegenerate = isDegenerateTriangle(v[0], v[1], v[2]); TriangleData triData = processTriangle(index, v, t); - if (triData != null && !isDegenerate) { + if (!isDegenerate) { vertices.get(index[0]).triangles.add(triData); vertices.get(index[1]).triangles.add(triData); vertices.get(index[2]).triangles.add(triData); @@ -529,11 +527,9 @@ public class TangentBinormalGenerator { populateFromBuffer(t[2], textureBuffer, index[2]); TriangleData triData = processTriangle(index, v, t); - if (triData != null) { - vertices.get(index[0]).triangles.add(triData); - vertices.get(index[1]).triangles.add(triData); - vertices.get(index[2]).triangles.add(triData); - } + vertices.get(index[0]).triangles.add(triData); + vertices.get(index[1]).triangles.add(triData); + vertices.get(index[2]).triangles.add(triData); Vector3f vTemp = v[1]; v[1] = v[2]; diff --git a/jme3-core/src/main/java/com/jme3/util/blockparser/BlockLanguageParser.java b/jme3-core/src/main/java/com/jme3/util/blockparser/BlockLanguageParser.java index 16968aad2..7718a0f4b 100644 --- a/jme3-core/src/main/java/com/jme3/util/blockparser/BlockLanguageParser.java +++ b/jme3-core/src/main/java/com/jme3/util/blockparser/BlockLanguageParser.java @@ -71,7 +71,7 @@ public class BlockLanguageParser { private void load(InputStream in) throws IOException{ reset(); - reader = new InputStreamReader(in); + reader = new InputStreamReader(in, "UTF-8"); StringBuilder buffer = new StringBuilder(); boolean insideComment = false; diff --git a/jme3-core/src/plugins/java/com/jme3/audio/plugins/WAVLoader.java b/jme3-core/src/plugins/java/com/jme3/audio/plugins/WAVLoader.java index 098de7a15..997a8f4fb 100644 --- a/jme3-core/src/plugins/java/com/jme3/audio/plugins/WAVLoader.java +++ b/jme3-core/src/plugins/java/com/jme3/audio/plugins/WAVLoader.java @@ -196,7 +196,7 @@ public class WAVLoader implements AssetLoader { break; case i_data: // Compute duration based on data chunk size - duration = len / bytesPerSec; + duration = (float)(len / bytesPerSec); if (readStream) { readDataChunkForStream(inOffset, len); diff --git a/jme3-core/src/plugins/java/com/jme3/export/binary/BinaryImporter.java b/jme3-core/src/plugins/java/com/jme3/export/binary/BinaryImporter.java index 933bee721..b34adbca6 100644 --- a/jme3-core/src/plugins/java/com/jme3/export/binary/BinaryImporter.java +++ b/jme3-core/src/plugins/java/com/jme3/export/binary/BinaryImporter.java @@ -270,9 +270,7 @@ public final class BinaryImporter implements JmeImporter { try { return load(fis, listener); } finally { - if (fis != null) { - fis.close(); - } + fis.close(); } } From 2bc55451713875a9dfcfae044016c752fc7f2e1b Mon Sep 17 00:00:00 2001 From: shadowislord Date: Fri, 27 Mar 2015 21:36:43 -0400 Subject: [PATCH 09/47] OGLESShaderRenderer: remove clearTextureUnits since it doesnt do anything --- .../renderer/android/OGLESShaderRenderer.java | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/jme3-android/src/main/java/com/jme3/renderer/android/OGLESShaderRenderer.java b/jme3-android/src/main/java/com/jme3/renderer/android/OGLESShaderRenderer.java index cef3e9f66..462715f37 100644 --- a/jme3-android/src/main/java/com/jme3/renderer/android/OGLESShaderRenderer.java +++ b/jme3-android/src/main/java/com/jme3/renderer/android/OGLESShaderRenderer.java @@ -1850,21 +1850,6 @@ public class OGLESShaderRenderer implements Renderer { TextureUtil.uploadSubTexture(pixels, convertTextureType(tex.getType()), 0, x, y); } - public void clearTextureUnits() { - IDList textureList = context.textureIndexList; - Image[] textures = context.boundTextures; - for (int i = 0; i < textureList.oldLen; i++) { - int idx = textureList.oldList[i]; -// if (context.boundTextureUnit != idx){ -// glActiveTexture(GL_TEXTURE0 + idx); -// context.boundTextureUnit = idx; -// } -// glDisable(convertTextureType(textures[idx].getType())); - textures[idx] = null; - } - context.textureIndexList.copyNewToOld(); - } - public void deleteImage(Image image) { int texId = image.getId(); if (texId != -1) { @@ -2339,7 +2324,6 @@ public class OGLESShaderRenderer implements Renderer { RendererUtil.checkGLError(); } clearVertexAttribs(); - clearTextureUnits(); } private void renderMeshDefault(Mesh mesh, int lod, int count) { @@ -2378,7 +2362,6 @@ public class OGLESShaderRenderer implements Renderer { RendererUtil.checkGLError(); } clearVertexAttribs(); - clearTextureUnits(); } public void renderMesh(Mesh mesh, int lod, int count, VertexBuffer[] instanceData) { From 4f15fa314765ac312c4b719f0a29061f118cfeb0 Mon Sep 17 00:00:00 2001 From: shadowislord Date: Fri, 27 Mar 2015 21:37:50 -0400 Subject: [PATCH 10/47] AnimChannel: remove useless println --- jme3-core/src/main/java/com/jme3/animation/AnimChannel.java | 1 - 1 file changed, 1 deletion(-) diff --git a/jme3-core/src/main/java/com/jme3/animation/AnimChannel.java b/jme3-core/src/main/java/com/jme3/animation/AnimChannel.java index 4c362ff00..44b836115 100644 --- a/jme3-core/src/main/java/com/jme3/animation/AnimChannel.java +++ b/jme3-core/src/main/java/com/jme3/animation/AnimChannel.java @@ -312,7 +312,6 @@ public final class AnimChannel { } } animation = null; - // System.out.println("Setting notified false"); notified = false; } From f0fbdffb85f520fb3af8d99c08356d8b0a3162c0 Mon Sep 17 00:00:00 2001 From: shadowislord Date: Fri, 27 Mar 2015 21:38:14 -0400 Subject: [PATCH 11/47] BoundingSphere: remove useless null check --- jme3-core/src/main/java/com/jme3/bounding/BoundingSphere.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/bounding/BoundingSphere.java b/jme3-core/src/main/java/com/jme3/bounding/BoundingSphere.java index 30751e078..d5dd56203 100644 --- a/jme3-core/src/main/java/com/jme3/bounding/BoundingSphere.java +++ b/jme3-core/src/main/java/com/jme3/bounding/BoundingSphere.java @@ -640,8 +640,7 @@ public class BoundingSphere extends BoundingVolume { return rVal; } - return new BoundingSphere(radius, - (center != null ? (Vector3f) center.clone() : null)); + return new BoundingSphere(radius, center.clone()); } /** From fdf050c13d52a3d8b639388c26c68c99fc8e4cdc Mon Sep 17 00:00:00 2001 From: shadowislord Date: Fri, 27 Mar 2015 21:38:56 -0400 Subject: [PATCH 12/47] J3MLoader: set texture name in addition to key when loading it --- .../src/plugins/java/com/jme3/material/plugins/J3MLoader.java | 1 + 1 file changed, 1 insertion(+) diff --git a/jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java b/jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java index 449802161..5d7f5ca8c 100644 --- a/jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java +++ b/jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java @@ -175,6 +175,7 @@ public class J3MLoader implements AssetLoader { tex.setWrap(WrapMode.Repeat); } tex.setKey(texKey); + tex.setName(texKey.getName()); } return tex; }else{ From a683fbb16c8cc43e115d8b9d24439c16eee30a97 Mon Sep 17 00:00:00 2001 From: shadowislord Date: Fri, 27 Mar 2015 21:39:27 -0400 Subject: [PATCH 13/47] Texture: allow setting aniso = 0, since that's the default anyway --- jme3-core/src/main/java/com/jme3/texture/Texture.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/texture/Texture.java b/jme3-core/src/main/java/com/jme3/texture/Texture.java index b41d2ac10..582d06565 100644 --- a/jme3-core/src/main/java/com/jme3/texture/Texture.java +++ b/jme3-core/src/main/java/com/jme3/texture/Texture.java @@ -488,7 +488,8 @@ public abstract class Texture implements CloneableSmartAsset, Savable, Cloneable /** * @return the anisotropic filtering level for this texture. Default value - * is 1 (no anisotrophy), 2 means x2, 4 is x4, etc. + * is 0 (use value from config), + * 1 means 1x (no anisotrophy), 2 means x2, 4 is x4, etc. */ public int getAnisotropicFilter() { return anisotropicFilter; @@ -499,11 +500,7 @@ public abstract class Texture implements CloneableSmartAsset, Savable, Cloneable * the anisotropic filtering level for this texture. */ public void setAnisotropicFilter(int level) { - if (level < 1) { - anisotropicFilter = 1; - } else { - anisotropicFilter = level; - } + anisotropicFilter = Math.max(0, level); } @Override From 068047200e22ff391567e655010c19474ace057b Mon Sep 17 00:00:00 2001 From: shadowislord Date: Fri, 27 Mar 2015 21:43:32 -0400 Subject: [PATCH 14/47] Threads: standardize names. Make sure they all start with "jME3". --- .../main/java/com/jme3/app/state/VideoRecorderAppState.java | 2 +- .../src/main/java/com/jme3/audio/openal/ALAudioRenderer.java | 5 ++++- jme3-core/src/main/java/com/jme3/system/NullContext.java | 4 +++- .../main/java/com/jme3/app/state/VideoRecorderAppState.java | 2 +- .../src/main/java/com/jme3/system/jogl/JoglContext.java | 2 ++ .../main/java/com/jme3/system/jogl/JoglOffscreenBuffer.java | 2 +- .../src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java | 4 ++-- .../src/main/java/com/jme3/system/lwjgl/LwjglContext.java | 2 ++ .../src/main/java/com/jme3/system/lwjgl/LwjglDisplay.java | 2 +- .../java/com/jme3/system/lwjgl/LwjglOffscreenBuffer.java | 2 +- .../java/com/jme3/terrain/geomipmap/TerrainLodControl.java | 2 +- 11 files changed, 19 insertions(+), 10 deletions(-) diff --git a/jme3-android/src/main/java/com/jme3/app/state/VideoRecorderAppState.java b/jme3-android/src/main/java/com/jme3/app/state/VideoRecorderAppState.java index c915164b3..a388ad612 100644 --- a/jme3-android/src/main/java/com/jme3/app/state/VideoRecorderAppState.java +++ b/jme3-android/src/main/java/com/jme3/app/state/VideoRecorderAppState.java @@ -74,7 +74,7 @@ public class VideoRecorderAppState extends AbstractAppState { public Thread newThread(Runnable r) { Thread th = new Thread(r); - th.setName("jME Video Processing Thread"); + th.setName("jME3 Video Processor"); th.setDaemon(true); return th; } diff --git a/jme3-core/src/main/java/com/jme3/audio/openal/ALAudioRenderer.java b/jme3-core/src/main/java/com/jme3/audio/openal/ALAudioRenderer.java index 346998e2e..c3ccea741 100644 --- a/jme3-core/src/main/java/com/jme3/audio/openal/ALAudioRenderer.java +++ b/jme3-core/src/main/java/com/jme3/audio/openal/ALAudioRenderer.java @@ -51,6 +51,9 @@ import static com.jme3.audio.openal.EFX.*; public class ALAudioRenderer implements AudioRenderer, Runnable { private static final Logger logger = Logger.getLogger(ALAudioRenderer.class.getName()); + + private static final String THREAD_NAME = "jME3 Audio Decoder"; + private final NativeObjectManager objManager = new NativeObjectManager(); // When multiplied by STREAMING_BUFFER_COUNT, will equal 44100 * 2 * 2 // which is exactly 1 second of audio. @@ -75,7 +78,7 @@ public class ALAudioRenderer implements AudioRenderer, Runnable { // Fill streaming sources every 50 ms private static final float UPDATE_RATE = 0.05f; - private final Thread decoderThread = new Thread(this, "jME3 Audio Decoding Thread"); + private final Thread decoderThread = new Thread(this, THREAD_NAME); private final Object threadLock = new Object(); private final AL al; diff --git a/jme3-core/src/main/java/com/jme3/system/NullContext.java b/jme3-core/src/main/java/com/jme3/system/NullContext.java index f7d4b3d5a..41204e6c9 100644 --- a/jme3-core/src/main/java/com/jme3/system/NullContext.java +++ b/jme3-core/src/main/java/com/jme3/system/NullContext.java @@ -46,6 +46,8 @@ public class NullContext implements JmeContext, Runnable { protected static final Logger logger = Logger.getLogger(NullContext.class.getName()); + protected static final String THREAD_NAME = "jME3 Headless Main"; + protected AtomicBoolean created = new AtomicBoolean(false); protected AtomicBoolean needClose = new AtomicBoolean(false); protected final Object createdLock = new Object(); @@ -150,7 +152,7 @@ public class NullContext implements JmeContext, Runnable { return; } - new Thread(this, "Headless Application Thread").start(); + new Thread(this, THREAD_NAME).start(); if (waitFor) waitFor(true); } diff --git a/jme3-desktop/src/main/java/com/jme3/app/state/VideoRecorderAppState.java b/jme3-desktop/src/main/java/com/jme3/app/state/VideoRecorderAppState.java index 9466b4a50..ccaecc580 100644 --- a/jme3-desktop/src/main/java/com/jme3/app/state/VideoRecorderAppState.java +++ b/jme3-desktop/src/main/java/com/jme3/app/state/VideoRecorderAppState.java @@ -71,7 +71,7 @@ public class VideoRecorderAppState extends AbstractAppState { public Thread newThread(Runnable r) { Thread th = new Thread(r); - th.setName("jME Video Processing Thread"); + th.setName("jME3 Video Processor"); th.setDaemon(true); return th; } diff --git a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglContext.java b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglContext.java index eca36d84b..8861904b8 100644 --- a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglContext.java +++ b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglContext.java @@ -55,6 +55,8 @@ public abstract class JoglContext implements JmeContext { private static final Logger logger = Logger.getLogger(JoglContext.class.getName()); + protected static final String THREAD_NAME = "jME3 Main"; + protected AtomicBoolean created = new AtomicBoolean(false); protected AtomicBoolean renderable = new AtomicBoolean(false); protected final Object createdLock = new Object(); diff --git a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglOffscreenBuffer.java b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglOffscreenBuffer.java index 505808878..e2ad1f79a 100644 --- a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglOffscreenBuffer.java +++ b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglOffscreenBuffer.java @@ -146,7 +146,7 @@ public class JoglOffscreenBuffer extends JoglContext implements Runnable { return; } - new Thread(this, "JOGL Renderer Thread").start(); + new Thread(this, THREAD_NAME).start(); if (waitFor) { waitFor(true); } diff --git a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java index f1fcc34a2..2452e470b 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java +++ b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java @@ -96,7 +96,7 @@ public class LwjglCanvas extends LwjglAbstractDisplay implements JmeCanvasContex canvas.setFocusable(true); canvas.setIgnoreRepaint(true); - renderThread = new Thread(LwjglCanvas.this, "LWJGL Renderer Thread"); + renderThread = new Thread(LwjglCanvas.this, THREAD_NAME); renderThread.start(); }else if (needClose.get()){ return; @@ -162,7 +162,7 @@ public class LwjglCanvas extends LwjglAbstractDisplay implements JmeCanvasContex if (renderThread == null){ logger.log(Level.FINE, "MAIN: Creating OGL thread."); - renderThread = new Thread(LwjglCanvas.this, "LWJGL Renderer Thread"); + renderThread = new Thread(LwjglCanvas.this, THREAD_NAME); renderThread.start(); } // do not do anything. diff --git a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java index e318d24a2..1286323ef 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java +++ b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java @@ -67,6 +67,8 @@ public abstract class LwjglContext implements JmeContext { private static final Logger logger = Logger.getLogger(LwjglContext.class.getName()); + protected static final String THREAD_NAME = "jME3 Main"; + protected AtomicBoolean created = new AtomicBoolean(false); protected AtomicBoolean renderable = new AtomicBoolean(false); protected final Object createdLock = new Object(); diff --git a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglDisplay.java b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglDisplay.java index 4ecfc9a49..853e02933 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglDisplay.java +++ b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglDisplay.java @@ -166,7 +166,7 @@ public class LwjglDisplay extends LwjglAbstractDisplay { return; } - new Thread(this, "LWJGL Renderer Thread").start(); + new Thread(this, THREAD_NAME).start(); if (waitFor) waitFor(true); } diff --git a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglOffscreenBuffer.java b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglOffscreenBuffer.java index efdb5dfdf..b06db1b29 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglOffscreenBuffer.java +++ b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglOffscreenBuffer.java @@ -170,7 +170,7 @@ public class LwjglOffscreenBuffer extends LwjglContext implements Runnable { return; } - new Thread(this, "LWJGL Renderer Thread").start(); + new Thread(this, THREAD_NAME).start(); if (waitFor) waitFor(true); } diff --git a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/TerrainLodControl.java b/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/TerrainLodControl.java index f52eaee01..8ad2425ad 100644 --- a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/TerrainLodControl.java +++ b/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/TerrainLodControl.java @@ -137,7 +137,7 @@ public class TerrainLodControl extends AbstractControl { return Executors.newSingleThreadExecutor(new ThreadFactory() { public Thread newThread(Runnable r) { Thread th = new Thread(r); - th.setName("jME Terrain Thread"); + th.setName("jME3 Terrain Thread"); th.setDaemon(true); return th; } From 305e56a921925974e460332e257433278a813a93 Mon Sep 17 00:00:00 2001 From: shadowislord Date: Fri, 27 Mar 2015 21:47:21 -0400 Subject: [PATCH 15/47] ShaderNode: remove incorrect attribution --- .../src/main/java/com/jme3/asset/ShaderNodeDefinitionKey.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/asset/ShaderNodeDefinitionKey.java b/jme3-core/src/main/java/com/jme3/asset/ShaderNodeDefinitionKey.java index db25a1217..9713d6ab8 100644 --- a/jme3-core/src/main/java/com/jme3/asset/ShaderNodeDefinitionKey.java +++ b/jme3-core/src/main/java/com/jme3/asset/ShaderNodeDefinitionKey.java @@ -39,8 +39,6 @@ import java.util.List; * Used for loading {@link ShaderNodeDefinition shader nodes definition} * * Tells if the defintion has to be loaded with or without its documentation - * - * @author Kirill Vainer */ public class ShaderNodeDefinitionKey extends AssetKey> { From 06408410cf70c242501d77d2ce7bc21cb788391d Mon Sep 17 00:00:00 2001 From: shadowislord Date: Fri, 27 Mar 2015 21:47:54 -0400 Subject: [PATCH 16/47] CollisionResult: add hashCode() - required if we have equals() --- .../src/main/java/com/jme3/collision/CollisionResult.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/jme3-core/src/main/java/com/jme3/collision/CollisionResult.java b/jme3-core/src/main/java/com/jme3/collision/CollisionResult.java index a777bc9b6..ae271c880 100644 --- a/jme3-core/src/main/java/com/jme3/collision/CollisionResult.java +++ b/jme3-core/src/main/java/com/jme3/collision/CollisionResult.java @@ -109,6 +109,11 @@ public class CollisionResult implements Comparable { return super.equals(obj); } + @Override + public int hashCode() { + return Float.floatToIntBits(distance); + } + public Vector3f getContactPoint() { return contactPoint; } From a3467def1eaf14292c0ff7d49648c1386335ec22 Mon Sep 17 00:00:00 2001 From: shadowislord Date: Fri, 27 Mar 2015 21:48:24 -0400 Subject: [PATCH 17/47] WeakRefCloneAssetCache: remove useless "synchronized" (the map is already thread-safe) --- .../java/com/jme3/asset/cache/WeakRefCloneAssetCache.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/asset/cache/WeakRefCloneAssetCache.java b/jme3-core/src/main/java/com/jme3/asset/cache/WeakRefCloneAssetCache.java index e3566d22c..ab3581013 100644 --- a/jme3-core/src/main/java/com/jme3/asset/cache/WeakRefCloneAssetCache.java +++ b/jme3-core/src/main/java/com/jme3/asset/cache/WeakRefCloneAssetCache.java @@ -155,11 +155,7 @@ public class WeakRefCloneAssetCache implements AssetCache { } public T getFromCache(AssetKey key) { - AssetRef smartInfo; - synchronized (smartCache){ - smartInfo = smartCache.get(key); - } - + AssetRef smartInfo = smartCache.get(key); if (smartInfo == null) { return null; } else { From 26f702cc91ae0aa40be46b537f49931d661fa3f7 Mon Sep 17 00:00:00 2001 From: shadowislord Date: Fri, 27 Mar 2015 21:49:33 -0400 Subject: [PATCH 18/47] GLTracer: add more no-enum methods --- .../src/main/java/com/jme3/renderer/opengl/GLTracer.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLTracer.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLTracer.java index 459e2d3a3..b69d524b4 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLTracer.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLTracer.java @@ -70,6 +70,7 @@ public final class GLTracer implements InvocationHandler { // noEnumArgs("glTexParameteri", 2); noEnumArgs("glTexImage2D", 1, 3, 4, 5); noEnumArgs("glTexImage3D", 1, 3, 4, 5, 6); + noEnumArgs("glTexSubImage2D", 1, 2, 3, 4, 5); noEnumArgs("glTexSubImage3D", 1, 2, 3, 4, 5, 6, 7); noEnumArgs("glCompressedTexImage2D", 1, 3, 4, 5); noEnumArgs("glCompressedTexSubImage3D", 1, 2, 3, 4, 5, 6, 7); @@ -83,6 +84,8 @@ public final class GLTracer implements InvocationHandler { noEnumArgs("glDrawRangeElements", 1, 2, 3, 5); noEnumArgs("glDrawArrays", 1, 2); noEnumArgs("glDeleteBuffers", 0); + noEnumArgs("glBindVertexArray", 0); + noEnumArgs("glGenVertexArrays", 0); noEnumArgs("glBindFramebufferEXT", 1); noEnumArgs("glBindRenderbufferEXT", 1); @@ -110,6 +113,7 @@ public final class GLTracer implements InvocationHandler { noEnumArgs("glUniform1f", 0); noEnumArgs("glUniform2f", 0); noEnumArgs("glUniform3f", 0); + noEnumArgs("glUniform4", 0); noEnumArgs("glUniform4f", 0); noEnumArgs("glGetAttribLocation", 0, -1); noEnumArgs("glDetachShader", 0, 1); From fa324cad8ff71a2d77ec25b55dbe44b7f5faf6d1 Mon Sep 17 00:00:00 2001 From: shadowislord Date: Fri, 27 Mar 2015 21:49:59 -0400 Subject: [PATCH 19/47] Dome: fix crash when center = null --- jme3-core/src/main/java/com/jme3/scene/shape/Dome.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jme3-core/src/main/java/com/jme3/scene/shape/Dome.java b/jme3-core/src/main/java/com/jme3/scene/shape/Dome.java index 3e2cfb031..8060498f9 100644 --- a/jme3-core/src/main/java/com/jme3/scene/shape/Dome.java +++ b/jme3-core/src/main/java/com/jme3/scene/shape/Dome.java @@ -266,7 +266,7 @@ public class Dome extends Mesh { vars.release(); // pole - vb.put(center.x).put(center.y + radius).put(center.z); + vb.put(this.center.x).put(this.center.y + radius).put(this.center.z); nb.put(0).put(insideView ? -1 : 1).put(0); tb.put(0.5f).put(1.0f); From 6252258c987dbd1afd9bcf6cf53fdb41dd2bfb7b Mon Sep 17 00:00:00 2001 From: shadowislord Date: Fri, 27 Mar 2015 21:55:32 -0400 Subject: [PATCH 20/47] TechniqueDef: remove useless usesShaders variable --- .../src/main/java/com/jme3/material/TechniqueDef.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java b/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java index e618a046c..665742db3 100644 --- a/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java +++ b/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java @@ -98,7 +98,6 @@ public class TechniqueDef implements Savable { private EnumMap shaderName; private DefineList presetDefines; - private boolean usesShaders; private boolean usesNodes = false; private List shaderNodes; private ShaderGenerationInfo shaderGenerationInfo; @@ -207,7 +206,7 @@ public class TechniqueDef implements Savable { */ @Deprecated public boolean isUsingShaders(){ - return usesShaders; + return true; } /** @@ -248,7 +247,6 @@ public class TechniqueDef implements Savable { Caps fragCap = Caps.valueOf(fragLanguage); requiredCaps.add(fragCap); - usesShaders = true; } @@ -268,7 +266,6 @@ public class TechniqueDef implements Savable { requiredCaps.add(Caps.TesselationShader); } } - usesShaders=true; } /** @@ -449,7 +446,6 @@ public class TechniqueDef implements Savable { oc.write(lightMode, "lightMode", LightMode.Disable); oc.write(shadowMode, "shadowMode", ShadowMode.Disable); oc.write(renderState, "renderState", null); - oc.write(usesShaders, "usesShaders", false); oc.write(usesNodes, "usesNodes", false); oc.writeSavableArrayList((ArrayList)shaderNodes,"shaderNodes", null); oc.write(shaderGenerationInfo, "shaderGenerationInfo", null); @@ -472,7 +468,6 @@ public class TechniqueDef implements Savable { lightMode = ic.readEnum("lightMode", LightMode.class, LightMode.Disable); shadowMode = ic.readEnum("shadowMode", ShadowMode.class, ShadowMode.Disable); renderState = (RenderState) ic.readSavable("renderState", null); - usesShaders = ic.readBoolean("usesShaders", false); if (ic.getSavableVersion(TechniqueDef.class) == 0) { // Old version @@ -499,7 +494,6 @@ public class TechniqueDef implements Savable { public void setShaderNodes(List shaderNodes) { this.shaderNodes = shaderNodes; usesNodes = true; - usesShaders = true; } /** @@ -529,6 +523,6 @@ public class TechniqueDef implements Savable { //todo: make toString return something usefull @Override public String toString() { - return "TechniqueDef{" + "requiredCaps=" + requiredCaps + ", name=" + name /*+ ", vertName=" + vertName + ", fragName=" + fragName + ", vertLanguage=" + vertLanguage + ", fragLanguage=" + fragLanguage */+ ", presetDefines=" + presetDefines + ", usesShaders=" + usesShaders + ", usesNodes=" + usesNodes + ", shaderNodes=" + shaderNodes + ", shaderGenerationInfo=" + shaderGenerationInfo + ", renderState=" + renderState + ", forcedRenderState=" + forcedRenderState + ", lightMode=" + lightMode + ", shadowMode=" + shadowMode + ", defineParams=" + defineParams + ", worldBinds=" + worldBinds + '}'; + return "TechniqueDef{" + "requiredCaps=" + requiredCaps + ", name=" + name /*+ ", vertName=" + vertName + ", fragName=" + fragName + ", vertLanguage=" + vertLanguage + ", fragLanguage=" + fragLanguage */+ ", presetDefines=" + presetDefines + ", usesNodes=" + usesNodes + ", shaderNodes=" + shaderNodes + ", shaderGenerationInfo=" + shaderGenerationInfo + ", renderState=" + renderState + ", forcedRenderState=" + forcedRenderState + ", lightMode=" + lightMode + ", shadowMode=" + shadowMode + ", defineParams=" + defineParams + ", worldBinds=" + worldBinds + '}'; } } From 26109fcbacfaa976cd131d0499553ee390da3552 Mon Sep 17 00:00:00 2001 From: shadowislord Date: Fri, 27 Mar 2015 22:19:02 -0400 Subject: [PATCH 21/47] (SP)Lighting.vert: clarify comment regarding material colors --- .../src/main/resources/Common/MatDefs/Light/Lighting.vert | 3 ++- .../src/main/resources/Common/MatDefs/Light/SPLighting.vert | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.vert b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.vert index 3ee6f38c6..f92b91fff 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.vert +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.vert @@ -126,7 +126,8 @@ void main(){ DiffuseSum = m_Diffuse * vec4(lightColor.rgb, 1.0); SpecularSum = (m_Specular * lightColor).rgb; #else - AmbientSum = g_AmbientLightColor.rgb; // Default: ambient color is dark gray + // Defaults: Ambient and diffuse are white, specular is black. + AmbientSum = g_AmbientLightColor.rgb; DiffuseSum = vec4(lightColor.rgb, 1.0); SpecularSum = vec3(0.0); #endif diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.vert b/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.vert index b0d8828a5..62b206b7e 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.vert +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.vert @@ -117,6 +117,7 @@ void main(){ SpecularSum = m_Specular.rgb; DiffuseSum = m_Diffuse; #else + // Defaults: Ambient and diffuse are white, specular is black. AmbientSum = g_AmbientLightColor.rgb; SpecularSum = vec3(0.0); DiffuseSum = vec4(1.0); From 22957c3d28a00a20533f1b45d271b4229f6f52cb Mon Sep 17 00:00:00 2001 From: shadowislord Date: Fri, 27 Mar 2015 22:20:38 -0400 Subject: [PATCH 22/47] IOS Renderer: remove clear texture units (does nothing anyway) --- .../renderer/ios/IGLESShaderRenderer.java | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/jme3-ios/src/main/java/com/jme3/renderer/ios/IGLESShaderRenderer.java b/jme3-ios/src/main/java/com/jme3/renderer/ios/IGLESShaderRenderer.java index d6b7010f4..8a59d0be8 100644 --- a/jme3-ios/src/main/java/com/jme3/renderer/ios/IGLESShaderRenderer.java +++ b/jme3-ios/src/main/java/com/jme3/renderer/ios/IGLESShaderRenderer.java @@ -759,14 +759,6 @@ public class IGLESShaderRenderer implements Renderer { Image[] textures = context.boundTextures; int type = convertTextureType(tex.getType()); - if (!context.textureIndexList.moveToNew(unit)) { -// if (context.boundTextureUnit != unit){ -// glActiveTexture(GL_TEXTURE0 + unit); -// context.boundTextureUnit = unit; -// } -// glEnable(type); - } - if (textures[unit] != image) { if (context.boundTextureUnit != unit) { JmeIosGLES.glActiveTexture(JmeIosGLES.GL_TEXTURE0 + unit); @@ -1768,7 +1760,6 @@ public class IGLESShaderRenderer implements Renderer { JmeIosGLES.checkGLError(); } clearVertexAttribs(); - clearTextureUnits(); } private void renderMeshDefault(Mesh mesh, int lod, int count) { @@ -1807,7 +1798,6 @@ public class IGLESShaderRenderer implements Renderer { JmeIosGLES.checkGLError(); } clearVertexAttribs(); - clearTextureUnits(); } @@ -2085,23 +2075,6 @@ public class IGLESShaderRenderer implements Renderer { context.attribIndexList.copyNewToOld(); } - - public void clearTextureUnits() { - IDList textureList = context.textureIndexList; - Image[] textures = context.boundTextures; - for (int i = 0; i < textureList.oldLen; i++) { - int idx = textureList.oldList[i]; -// if (context.boundTextureUnit != idx){ -// glActiveTexture(GL_TEXTURE0 + idx); -// context.boundTextureUnit = idx; -// } -// glDisable(convertTextureType(textures[idx].getType())); - textures[idx] = null; - } - context.textureIndexList.copyNewToOld(); - } - - public void updateFrameBuffer(FrameBuffer fb) { int id = fb.getId(); if (id == -1) { From 51952de16aec3afb4a3df793e469991142de05c1 Mon Sep 17 00:00:00 2001 From: shadowislord Date: Fri, 27 Mar 2015 22:21:14 -0400 Subject: [PATCH 23/47] jme3-testdata: fix issue #241 --- jme3-testdata/build.gradle | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/jme3-testdata/build.gradle b/jme3-testdata/build.gradle index 1df94c4d2..aad9f2ae9 100644 --- a/jme3-testdata/build.gradle +++ b/jme3-testdata/build.gradle @@ -2,5 +2,12 @@ if (!hasProperty('mainClass')) { ext.mainClass = '' } +repositories { + maven { + url 'http://nifty-gui.sourceforge.net/nifty-maven-repo' + } +} + dependencies { + compile 'lessvoid:nifty-examples:1.4.1' } From d2af0017b227f2f2087a71f2e4fa85a74866b950 Mon Sep 17 00:00:00 2001 From: shadowislord Date: Fri, 27 Mar 2015 22:40:18 -0400 Subject: [PATCH 24/47] Nifty BatchRenderBackend: set colorspace property on images --- .../main/java/com/jme3/niftygui/JmeBatchRenderBackend.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/jme3-niftygui/src/main/java/com/jme3/niftygui/JmeBatchRenderBackend.java b/jme3-niftygui/src/main/java/com/jme3/niftygui/JmeBatchRenderBackend.java index 97f46120a..9dd831020 100644 --- a/jme3-niftygui/src/main/java/com/jme3/niftygui/JmeBatchRenderBackend.java +++ b/jme3-niftygui/src/main/java/com/jme3/niftygui/JmeBatchRenderBackend.java @@ -55,6 +55,7 @@ import com.jme3.texture.Image.Format; import com.jme3.texture.Texture.MagFilter; import com.jme3.texture.Texture.MinFilter; import com.jme3.texture.Texture2D; +import com.jme3.texture.image.ColorSpace; import com.jme3.util.BufferUtils; import de.lessvoid.nifty.render.batch.spi.BatchRenderBackend; @@ -302,7 +303,7 @@ public class JmeBatchRenderBackend implements BatchRenderBackend { initialData.rewind(); modifyTexture( getTextureAtlas(atlasTextureId), - new com.jme3.texture.Image(Format.RGBA8, image.getWidth(), image.getHeight(), initialData), + new com.jme3.texture.Image(Format.RGBA8, image.getWidth(), image.getHeight(), initialData, ColorSpace.sRGB), x, y); } @@ -338,7 +339,7 @@ public class JmeBatchRenderBackend implements BatchRenderBackend { } initialData.rewind(); - Texture2D texture = new Texture2D(new com.jme3.texture.Image(Format.RGBA8, width, height, initialData)); + Texture2D texture = new Texture2D(new com.jme3.texture.Image(Format.RGBA8, width, height, initialData, ColorSpace.sRGB)); texture.setMinFilter(MinFilter.NearestNoMipMaps); texture.setMagFilter(MagFilter.Nearest); return texture; From 19338deaf88ae1683df2b83fefff77f1d30500ca Mon Sep 17 00:00:00 2001 From: shadowislord Date: Fri, 27 Mar 2015 22:42:34 -0400 Subject: [PATCH 25/47] LWJGL Backend: fix issue #232 --- .../main/java/com/jme3/system/lwjgl/LwjglAbstractDisplay.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglAbstractDisplay.java b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglAbstractDisplay.java index ee6a81c53..7cdca0a57 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglAbstractDisplay.java +++ b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglAbstractDisplay.java @@ -181,7 +181,9 @@ public abstract class LwjglAbstractDisplay extends LwjglContext implements Runna // check input after we synchronize with framerate. // this reduces input lag. - Display.processMessages(); + if (renderable.get()){ + Display.processMessages(); + } // Subclasses just call GLObjectManager clean up objects here // it is safe .. for now. From 414e1b3fffcb770d894564cfc523899c4d6548cc Mon Sep 17 00:00:00 2001 From: shadowislord Date: Fri, 27 Mar 2015 23:34:53 -0400 Subject: [PATCH 26/47] Lighting.glsllib: Use quadratic spotlight falloff in SRGB mode --- .../main/resources/Common/ShaderLib/Lighting.glsllib | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/jme3-core/src/main/resources/Common/ShaderLib/Lighting.glsllib b/jme3-core/src/main/resources/Common/ShaderLib/Lighting.glsllib index 6ac1fce5c..fb8f40524 100644 --- a/jme3-core/src/main/resources/Common/ShaderLib/Lighting.glsllib +++ b/jme3-core/src/main/resources/Common/ShaderLib/Lighting.glsllib @@ -30,6 +30,14 @@ float computeSpotFalloff(in vec4 lightDirection, in vec3 lightVector){ float innerAngleCos = floor(lightDirection.w) * 0.001; float outerAngleCos = fract(lightDirection.w); float innerMinusOuter = innerAngleCos - outerAngleCos; - return clamp((curAngleCos - outerAngleCos) / innerMinusOuter, step(lightDirection.w, 0.001), 1.0); + float falloff = clamp((curAngleCos - outerAngleCos) / innerMinusOuter, step(lightDirection.w, 0.001), 1.0); + +#ifdef SRGB + // Use quadratic falloff (notice the ^4) + return pow(clamp((curAngleCos - outerAngleCos) / innerMinusOuter, 0.0, 1.0), 4.0); +#else + // Use linear falloff + return falloff; +#endif } From 38e4580857e032137741278563645cbf14ff6903 Mon Sep 17 00:00:00 2001 From: shadowislord Date: Fri, 27 Mar 2015 23:37:13 -0400 Subject: [PATCH 27/47] TestSweepTest: fix crash on native bullet (natives not loaded when shapes are created) --- .../src/main/java/jme3test/bullet/TestSweepTest.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/jme3-examples/src/main/java/jme3test/bullet/TestSweepTest.java b/jme3-examples/src/main/java/jme3test/bullet/TestSweepTest.java index 6f9e3fdd6..c8bd631d9 100644 --- a/jme3-examples/src/main/java/jme3test/bullet/TestSweepTest.java +++ b/jme3-examples/src/main/java/jme3test/bullet/TestSweepTest.java @@ -21,8 +21,8 @@ import java.util.List; public class TestSweepTest extends SimpleApplication { private BulletAppState bulletAppState = new BulletAppState(); - private CapsuleCollisionShape obstacleCollisionShape = new CapsuleCollisionShape(0.3f, 0.5f); - private CapsuleCollisionShape capsuleCollisionShape = new CapsuleCollisionShape(1f, 1f); + private CapsuleCollisionShape obstacleCollisionShape; + private CapsuleCollisionShape capsuleCollisionShape; private Node capsule; private Node obstacle; private float dist = .5f; @@ -33,6 +33,9 @@ public class TestSweepTest extends SimpleApplication { @Override public void simpleInitApp() { + obstacleCollisionShape = new CapsuleCollisionShape(0.3f, 0.5f); + capsuleCollisionShape = new CapsuleCollisionShape(1f, 1f); + stateManager.attach(bulletAppState); capsule = new Node("capsule"); From 5c8b1fe585282034966b1e31920c58e251ddfdf3 Mon Sep 17 00:00:00 2001 From: rainmantsr Date: Sat, 28 Mar 2015 13:30:53 +0100 Subject: [PATCH 28/47] Corrected JavaDoc comment --- jme3-bullet/src/main/java/com/jme3/bullet/PhysicsSpace.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jme3-bullet/src/main/java/com/jme3/bullet/PhysicsSpace.java b/jme3-bullet/src/main/java/com/jme3/bullet/PhysicsSpace.java index 5aa4f6abf..380dc3e16 100644 --- a/jme3-bullet/src/main/java/com/jme3/bullet/PhysicsSpace.java +++ b/jme3-bullet/src/main/java/com/jme3/bullet/PhysicsSpace.java @@ -845,7 +845,7 @@ public class PhysicsSpace { /** * Performs a sweep collision test and returns the results as a list of * PhysicsSweepTestResults
You have to use different Transforms for - * start and end (at least distance > 0.4f). SweepTest will not see a + * start and end (at least distance > allowedCcdPenetration). SweepTest will not see a * collision if it starts INSIDE an object and is moving AWAY from its * center. */ From fe7f30d5ec0628f8ab62a343a97007239c2a4243 Mon Sep 17 00:00:00 2001 From: shadowislord Date: Sat, 28 Mar 2015 13:17:16 -0400 Subject: [PATCH 29/47] Native SweepTest: fix formatting --- .../cpp/com_jme3_bullet_PhysicsSpace.cpp | 117 +++++++++--------- .../src/native/cpp/jmeBulletUtil.h | 6 +- 2 files changed, 61 insertions(+), 62 deletions(-) diff --git a/jme3-bullet-native/src/native/cpp/com_jme3_bullet_PhysicsSpace.cpp b/jme3-bullet-native/src/native/cpp/com_jme3_bullet_PhysicsSpace.cpp index 32bc249dd..f9be6a6ad 100644 --- a/jme3-bullet-native/src/native/cpp/com_jme3_bullet_PhysicsSpace.cpp +++ b/jme3-bullet-native/src/native/cpp/com_jme3_bullet_PhysicsSpace.cpp @@ -470,65 +470,64 @@ extern "C" { - JNIEXPORT void JNICALL Java_com_jme3_bullet_PhysicsSpace_sweepTest_1native - (JNIEnv * env, jobject object, jlong shapeId, jobject from, jobject to, jlong spaceId, jobject resultlist, jfloat allowedCcdPenetration) { - - jmePhysicsSpace* space = reinterpret_cast (spaceId); - if (space == NULL) { - jclass newExc = env->FindClass("java/lang/NullPointerException"); - env->ThrowNew(newExc, "The physics space does not exist."); - return; - } - - btCollisionShape* shape = reinterpret_cast (shapeId); - if (shape == NULL) { - jclass newExc = env->FindClass("java/lang/NullPointerException"); - env->ThrowNew(newExc, "The shape does not exist."); - return; - } - - struct AllConvexResultCallback : public btCollisionWorld::ConvexResultCallback { - - AllConvexResultCallback(const btTransform& convexFromWorld, const btTransform & convexToWorld) : m_convexFromWorld(convexFromWorld), m_convexToWorld(convexToWorld) { - } - jobject resultlist; - JNIEnv* env; - btTransform m_convexFromWorld; //used to calculate hitPointWorld from hitFraction - btTransform m_convexToWorld; - - btVector3 m_hitNormalWorld; - btVector3 m_hitPointWorld; - - virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult, bool normalInWorldSpace) { - if (normalInWorldSpace) { - m_hitNormalWorld = convexResult.m_hitNormalLocal; - } - else { - m_hitNormalWorld = convexResult.m_hitCollisionObject->getWorldTransform().getBasis() * convexResult.m_hitNormalLocal; - } - m_hitPointWorld.setInterpolate3(m_convexFromWorld.getBasis() * m_convexFromWorld.getOrigin(), m_convexToWorld.getBasis() * m_convexToWorld.getOrigin(), convexResult.m_hitFraction); - - jmeBulletUtil::addSweepResult(env, resultlist, &m_hitNormalWorld, &m_hitPointWorld, convexResult.m_hitFraction, convexResult.m_hitCollisionObject); - - return 1.f; - } - }; - - btTransform native_to = btTransform(); - jmeBulletUtil::convert(env, to, &native_to); - - btTransform native_from = btTransform(); - jmeBulletUtil::convert(env, from, &native_from); - - btScalar native_allowed_ccd_penetration = btScalar(allowedCcdPenetration); - - - AllConvexResultCallback resultCallback(native_from, native_to); - resultCallback.env = env; - resultCallback.resultlist = resultlist; - space->getDynamicsWorld()->convexSweepTest((btConvexShape *) shape, native_from, native_to, resultCallback, native_allowed_ccd_penetration); - return; - } + JNIEXPORT void JNICALL Java_com_jme3_bullet_PhysicsSpace_sweepTest_1native + (JNIEnv * env, jobject object, jlong shapeId, jobject from, jobject to, jlong spaceId, jobject resultlist, jfloat allowedCcdPenetration) { + + jmePhysicsSpace* space = reinterpret_cast (spaceId); + if (space == NULL) { + jclass newExc = env->FindClass("java/lang/NullPointerException"); + env->ThrowNew(newExc, "The physics space does not exist."); + return; + } + + btCollisionShape* shape = reinterpret_cast (shapeId); + if (shape == NULL) { + jclass newExc = env->FindClass("java/lang/NullPointerException"); + env->ThrowNew(newExc, "The shape does not exist."); + return; + } + + struct AllConvexResultCallback : public btCollisionWorld::ConvexResultCallback { + + AllConvexResultCallback(const btTransform& convexFromWorld, const btTransform & convexToWorld) : m_convexFromWorld(convexFromWorld), m_convexToWorld(convexToWorld) { + } + jobject resultlist; + JNIEnv* env; + btTransform m_convexFromWorld; //used to calculate hitPointWorld from hitFraction + btTransform m_convexToWorld; + + btVector3 m_hitNormalWorld; + btVector3 m_hitPointWorld; + + virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult, bool normalInWorldSpace) { + if (normalInWorldSpace) { + m_hitNormalWorld = convexResult.m_hitNormalLocal; + } + else { + m_hitNormalWorld = convexResult.m_hitCollisionObject->getWorldTransform().getBasis() * convexResult.m_hitNormalLocal; + } + m_hitPointWorld.setInterpolate3(m_convexFromWorld.getBasis() * m_convexFromWorld.getOrigin(), m_convexToWorld.getBasis() * m_convexToWorld.getOrigin(), convexResult.m_hitFraction); + + jmeBulletUtil::addSweepResult(env, resultlist, &m_hitNormalWorld, &m_hitPointWorld, convexResult.m_hitFraction, convexResult.m_hitCollisionObject); + + return 1.f; + } + }; + + btTransform native_to = btTransform(); + jmeBulletUtil::convert(env, to, &native_to); + + btTransform native_from = btTransform(); + jmeBulletUtil::convert(env, from, &native_from); + + btScalar native_allowed_ccd_penetration = btScalar(allowedCcdPenetration); + + AllConvexResultCallback resultCallback(native_from, native_to); + resultCallback.env = env; + resultCallback.resultlist = resultlist; + space->getDynamicsWorld()->convexSweepTest((btConvexShape *) shape, native_from, native_to, resultCallback, native_allowed_ccd_penetration); + return; + } #ifdef __cplusplus } diff --git a/jme3-bullet-native/src/native/cpp/jmeBulletUtil.h b/jme3-bullet-native/src/native/cpp/jmeBulletUtil.h index fa09d09cc..7d982c80e 100644 --- a/jme3-bullet-native/src/native/cpp/jmeBulletUtil.h +++ b/jme3-bullet-native/src/native/cpp/jmeBulletUtil.h @@ -42,13 +42,13 @@ public: static void convert(JNIEnv* env, jobject in, btVector3* out); static void convert(JNIEnv* env, const btVector3* in, jobject out); static void convert(JNIEnv* env, jobject in, btMatrix3x3* out); - static void convert(JNIEnv* env, jobject in, btQuaternion* out); + static void convert(JNIEnv* env, jobject in, btQuaternion* out); static void convert(JNIEnv* env, const btMatrix3x3* in, jobject out); static void convertQuat(JNIEnv* env, jobject in, btMatrix3x3* out); static void convertQuat(JNIEnv* env, const btMatrix3x3* in, jobject out); - static void convert(JNIEnv* env, jobject in, btTransform* out); + static void convert(JNIEnv* env, jobject in, btTransform* out); static void addResult(JNIEnv* env, jobject resultlist, btVector3* hitnormal, btVector3* m_hitPointWorld,const btScalar m_hitFraction,const btCollisionObject* hitobject); - static void addSweepResult(JNIEnv* env, jobject resultlist, btVector3* hitnormal, btVector3* m_hitPointWorld, const btScalar m_hitFraction, const btCollisionObject* hitobject); + static void addSweepResult(JNIEnv* env, jobject resultlist, btVector3* hitnormal, btVector3* m_hitPointWorld, const btScalar m_hitFraction, const btCollisionObject* hitobject); private: jmeBulletUtil(){}; ~jmeBulletUtil(){}; From 87b6c117f25a53a4d072faac0beb6cf32d5e529a Mon Sep 17 00:00:00 2001 From: shadowislord Date: Sat, 28 Mar 2015 13:23:00 -0400 Subject: [PATCH 30/47] TestSweepTest: ignore collisions against ourselves (needed for native bullet) --- .../main/java/jme3test/bullet/TestSweepTest.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/jme3-examples/src/main/java/jme3test/bullet/TestSweepTest.java b/jme3-examples/src/main/java/jme3test/bullet/TestSweepTest.java index c8bd631d9..0613e5d22 100644 --- a/jme3-examples/src/main/java/jme3test/bullet/TestSweepTest.java +++ b/jme3-examples/src/main/java/jme3test/bullet/TestSweepTest.java @@ -59,14 +59,19 @@ public class TestSweepTest extends SimpleApplication { public void simpleUpdate(float tpf) { float move = tpf * 1; + boolean colliding = false; List sweepTest = bulletAppState.getPhysicsSpace().sweepTest(capsuleCollisionShape, new Transform(capsule.getWorldTranslation()), new Transform(capsule.getWorldTranslation().add(dist, 0, 0))); - if (sweepTest.size() > 0) { - PhysicsSweepTestResult get = sweepTest.get(0); - PhysicsCollisionObject collisionObject = get.getCollisionObject(); - fpsText.setText("Almost colliding with " + collisionObject.getUserObject().toString()); - } else { + for (PhysicsSweepTestResult result : sweepTest) { + if (result.getCollisionObject().getCollisionShape() != capsuleCollisionShape) { + PhysicsCollisionObject collisionObject = result.getCollisionObject(); + fpsText.setText("Almost colliding with " + collisionObject.getUserObject().toString()); + colliding = true; + } + } + + if (!colliding) { // if the sweep is clear then move the spatial capsule.move(move, 0, 0); } From 36493353c9f1fef5559174bf20f5ddc9ebc62613 Mon Sep 17 00:00:00 2001 From: shadowislord Date: Sun, 29 Mar 2015 11:47:58 -0400 Subject: [PATCH 31/47] TechniqueDef: fix caps loading for shader language versions --- .../java/com/jme3/material/TechniqueDef.java | 112 +++++++++--------- 1 file changed, 57 insertions(+), 55 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java b/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java index 665742db3..f8152e563 100644 --- a/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java +++ b/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java @@ -94,8 +94,8 @@ public class TechniqueDef implements Savable { private EnumSet requiredCaps = EnumSet.noneOf(Caps.class); private String name; - private EnumMap shaderLanguage; - private EnumMap shaderName; + private EnumMap shaderLanguages; + private EnumMap shaderNames; private DefineList presetDefines; private boolean usesNodes = false; @@ -128,8 +128,8 @@ public class TechniqueDef implements Savable { * Serialization only. Do not use. */ public TechniqueDef(){ - shaderLanguage=new EnumMap(Shader.ShaderType.class); - shaderName=new EnumMap(Shader.ShaderType.class); + shaderLanguages=new EnumMap(Shader.ShaderType.class); + shaderNames=new EnumMap(Shader.ShaderType.class); } /** @@ -238,31 +238,41 @@ public class TechniqueDef implements Savable { * @param fragLanguage The fragment shader language */ public void setShaderFile(String vertexShader, String fragmentShader, String vertLanguage, String fragLanguage) { - this.shaderLanguage.put(Shader.ShaderType.Vertex, vertLanguage); - this.shaderName.put(Shader.ShaderType.Vertex, vertexShader); - this.shaderLanguage.put(Shader.ShaderType.Fragment, fragLanguage); - this.shaderName.put(Shader.ShaderType.Fragment, fragmentShader); + this.shaderLanguages.put(Shader.ShaderType.Vertex, vertLanguage); + this.shaderNames.put(Shader.ShaderType.Vertex, vertexShader); + this.shaderLanguages.put(Shader.ShaderType.Fragment, fragLanguage); + this.shaderNames.put(Shader.ShaderType.Fragment, fragmentShader); + + requiredCaps.clear(); Caps vertCap = Caps.valueOf(vertLanguage); requiredCaps.add(vertCap); Caps fragCap = Caps.valueOf(fragLanguage); requiredCaps.add(fragCap); - } /** * Sets the shaders that this technique definition will use. * - * @param shaderName EnumMap containing all shader names for this stage - * @param shaderLanguage EnumMap containing all shader languages for this stage + * @param shaderNames EnumMap containing all shader names for this stage + * @param shaderLanguages EnumMap containing all shader languages for this stage */ - public void setShaderFile(EnumMap shaderName, EnumMap shaderLanguage) { - for (Shader.ShaderType shaderType : shaderName.keySet()) { - this.shaderLanguage.put(shaderType,shaderLanguage.get(shaderType)); - this.shaderName.put(shaderType,shaderName.get(shaderType)); - if(shaderType.equals(Shader.ShaderType.Geometry)){ + public void setShaderFile(EnumMap shaderNames, EnumMap shaderLanguages) { + requiredCaps.clear(); + + for (Shader.ShaderType shaderType : shaderNames.keySet()) { + String language = shaderLanguages.get(shaderType); + String shaderFile = shaderNames.get(shaderType); + + this.shaderLanguages.put(shaderType, language); + this.shaderNames.put(shaderType, shaderFile); + + Caps vertCap = Caps.valueOf(language); + requiredCaps.add(vertCap); + + if (shaderType.equals(Shader.ShaderType.Geometry)) { requiredCaps.add(Caps.GeometryShader); - }else if(shaderType.equals(Shader.ShaderType.TessellationControl)){ + } else if (shaderType.equals(Shader.ShaderType.TessellationControl)) { requiredCaps.add(Caps.TesselationShader); } } @@ -340,7 +350,7 @@ public class TechniqueDef implements Savable { * @return the name of the fragment shader to be used. */ public String getFragmentShaderName() { - return shaderName.get(Shader.ShaderType.Fragment); + return shaderNames.get(Shader.ShaderType.Fragment); } @@ -351,42 +361,34 @@ public class TechniqueDef implements Savable { * @return the name of the vertex shader to be used. */ public String getVertexShaderName() { - return shaderName.get(Shader.ShaderType.Vertex); - } - - /** - * @deprecated Use {@link #getVertexShaderLanguage() } instead. - */ - @Deprecated - public String getShaderLanguage() { - return shaderLanguage.get(Shader.ShaderType.Vertex); + return shaderNames.get(Shader.ShaderType.Vertex); } /** * Returns the language of the fragment shader used in this technique. */ public String getFragmentShaderLanguage() { - return shaderLanguage.get(Shader.ShaderType.Fragment); + return shaderLanguages.get(Shader.ShaderType.Fragment); } /** * Returns the language of the vertex shader used in this technique. */ public String getVertexShaderLanguage() { - return shaderLanguage.get(Shader.ShaderType.Vertex); + return shaderLanguages.get(Shader.ShaderType.Vertex); } /**Returns the language for each shader program * @param shaderType */ public String getShaderProgramLanguage(Shader.ShaderType shaderType){ - return shaderLanguage.get(shaderType); + return shaderLanguages.get(shaderType); } /**Returns the name for each shader program * @param shaderType */ public String getShaderProgramName(Shader.ShaderType shaderType){ - return shaderName.get(shaderType); + return shaderNames.get(shaderType); } /** @@ -431,16 +433,16 @@ public class TechniqueDef implements Savable { OutputCapsule oc = ex.getCapsule(this); oc.write(name, "name", null); - oc.write(shaderName.get(Shader.ShaderType.Vertex), "vertName", null); - oc.write(shaderName.get(Shader.ShaderType.Fragment), "fragName", null); - oc.write(shaderName.get(Shader.ShaderType.Geometry), "geomName", null); - oc.write(shaderName.get(Shader.ShaderType.TessellationControl), "tsctrlName", null); - oc.write(shaderName.get(Shader.ShaderType.TessellationEvaluation), "tsevalName", null); - oc.write(shaderLanguage.get(Shader.ShaderType.Vertex), "vertLanguage", null); - oc.write(shaderLanguage.get(Shader.ShaderType.Fragment), "fragLanguage", null); - oc.write(shaderLanguage.get(Shader.ShaderType.Geometry), "geomLanguage", null); - oc.write(shaderLanguage.get(Shader.ShaderType.TessellationControl), "tsctrlLanguage", null); - oc.write(shaderLanguage.get(Shader.ShaderType.TessellationEvaluation), "tsevalLanguage", null); + oc.write(shaderNames.get(Shader.ShaderType.Vertex), "vertName", null); + oc.write(shaderNames.get(Shader.ShaderType.Fragment), "fragName", null); + oc.write(shaderNames.get(Shader.ShaderType.Geometry), "geomName", null); + oc.write(shaderNames.get(Shader.ShaderType.TessellationControl), "tsctrlName", null); + oc.write(shaderNames.get(Shader.ShaderType.TessellationEvaluation), "tsevalName", null); + oc.write(shaderLanguages.get(Shader.ShaderType.Vertex), "vertLanguage", null); + oc.write(shaderLanguages.get(Shader.ShaderType.Fragment), "fragLanguage", null); + oc.write(shaderLanguages.get(Shader.ShaderType.Geometry), "geomLanguage", null); + oc.write(shaderLanguages.get(Shader.ShaderType.TessellationControl), "tsctrlLanguage", null); + oc.write(shaderLanguages.get(Shader.ShaderType.TessellationEvaluation), "tsevalLanguage", null); oc.write(presetDefines, "presetDefines", null); oc.write(lightMode, "lightMode", LightMode.Disable); @@ -459,11 +461,11 @@ public class TechniqueDef implements Savable { public void read(JmeImporter im) throws IOException{ InputCapsule ic = im.getCapsule(this); name = ic.readString("name", null); - shaderName.put(Shader.ShaderType.Vertex,ic.readString("vertName", null)); - shaderName.put(Shader.ShaderType.Fragment,ic.readString("fragName", null)); - shaderName.put(Shader.ShaderType.Geometry,ic.readString("geomName", null)); - shaderName.put(Shader.ShaderType.TessellationControl,ic.readString("tsctrlName", null)); - shaderName.put(Shader.ShaderType.TessellationEvaluation,ic.readString("tsevalName", null)); + shaderNames.put(Shader.ShaderType.Vertex,ic.readString("vertName", null)); + shaderNames.put(Shader.ShaderType.Fragment,ic.readString("fragName", null)); + shaderNames.put(Shader.ShaderType.Geometry,ic.readString("geomName", null)); + shaderNames.put(Shader.ShaderType.TessellationControl,ic.readString("tsctrlName", null)); + shaderNames.put(Shader.ShaderType.TessellationEvaluation,ic.readString("tsevalName", null)); presetDefines = (DefineList) ic.readSavable("presetDefines", null); lightMode = ic.readEnum("lightMode", LightMode.class, LightMode.Disable); shadowMode = ic.readEnum("shadowMode", ShadowMode.class, ShadowMode.Disable); @@ -471,15 +473,15 @@ public class TechniqueDef implements Savable { if (ic.getSavableVersion(TechniqueDef.class) == 0) { // Old version - shaderLanguage.put(Shader.ShaderType.Vertex,ic.readString("shaderLang", null)); - shaderLanguage.put(Shader.ShaderType.Fragment,shaderLanguage.get(Shader.ShaderType.Vertex)); + shaderLanguages.put(Shader.ShaderType.Vertex,ic.readString("shaderLang", null)); + shaderLanguages.put(Shader.ShaderType.Fragment,shaderLanguages.get(Shader.ShaderType.Vertex)); } else { // New version - shaderLanguage.put(Shader.ShaderType.Vertex,ic.readString("vertLanguage", null)); - shaderLanguage.put(Shader.ShaderType.Fragment,ic.readString("fragLanguage", null)); - shaderLanguage.put(Shader.ShaderType.Geometry,ic.readString("geomLanguage", null)); - shaderLanguage.put(Shader.ShaderType.TessellationControl,ic.readString("tsctrlLanguage", null)); - shaderLanguage.put(Shader.ShaderType.TessellationEvaluation,ic.readString("tsevalLanguage", null)); + shaderLanguages.put(Shader.ShaderType.Vertex,ic.readString("vertLanguage", null)); + shaderLanguages.put(Shader.ShaderType.Fragment,ic.readString("fragLanguage", null)); + shaderLanguages.put(Shader.ShaderType.Geometry,ic.readString("geomLanguage", null)); + shaderLanguages.put(Shader.ShaderType.TessellationControl,ic.readString("tsctrlLanguage", null)); + shaderLanguages.put(Shader.ShaderType.TessellationEvaluation,ic.readString("tsevalLanguage", null)); } usesNodes = ic.readBoolean("usesNodes", false); @@ -501,7 +503,7 @@ public class TechniqueDef implements Savable { * @return */ public EnumMap getShaderProgramNames() { - return shaderName; + return shaderNames; } /** @@ -509,7 +511,7 @@ public class TechniqueDef implements Savable { * @return */ public EnumMap getShaderProgramLanguages() { - return shaderLanguage; + return shaderLanguages; } public ShaderGenerationInfo getShaderGenerationInfo() { From ca76754889244eed407860b9cc7c953822b22004 Mon Sep 17 00:00:00 2001 From: iwgeric Date: Sun, 29 Mar 2015 23:02:05 -0400 Subject: [PATCH 32/47] SDK: Add missing global library for android native bullet --- sdk/build.gradle | 31 ++++++++++--------- .../baselibs/jme3-bullet-native-android.xml | 19 ++++++++++++ .../com/jme3/gde/project/baselibs/layer.xml | 1 + 3 files changed, 36 insertions(+), 15 deletions(-) create mode 100644 sdk/jme3-project-baselibs/src/com/jme3/gde/project/baselibs/jme3-bullet-native-android.xml diff --git a/sdk/build.gradle b/sdk/build.gradle index 55722cbfb..745b878c6 100644 --- a/sdk/build.gradle +++ b/sdk/build.gradle @@ -25,17 +25,18 @@ dependencies { corelibs project(':jme3-niftygui') corelibs project(':jme3-plugins') corelibs project(':jme3-terrain') - + optlibs project(':jme3-bullet') optlibs project(':jme3-jogl') optlibs project(':jme3-android') optlibs project(':jme3-ios') optlibs project(':jme3-android-native') optlibs project(':jme3-bullet-native') + optlibs project(':jme3-bullet-native-android') testdatalibs project(':jme3-testdata') examplelibs project(':jme3-examples') - + } artifacts { @@ -97,7 +98,7 @@ task createBaseXml(dependsOn: configurations.corelibs) <<{ "jme3-core-baselibs and jme3-core-libraries" def jmeJarFiles = [] // jme3 jar files def externalJarFiles = [] // external jar files - + // collect jar files project.configurations.corelibs.dependencies.each {dep -> // collect external jar files @@ -120,7 +121,7 @@ task createBaseXml(dependsOn: configurations.corelibs) <<{ def packages = [] jmeJarFiles.each{jarFile -> ZipFile file = new ZipFile(jarFile) - file.entries().each { entry -> + file.entries().each { entry -> if(entry.name.endsWith('.class')){ // TODO: "/" works on windows? def pathPart = entry.name.substring(0,entry.name.lastIndexOf('/')) @@ -129,14 +130,14 @@ task createBaseXml(dependsOn: configurations.corelibs) <<{ packages.add(classPath) } } - } + } } - + // collect library packages def extPackages = [] externalJarFiles.each{jarFile -> ZipFile file = new ZipFile(jarFile) - file.entries().each { entry -> + file.entries().each { entry -> if(entry.name.endsWith('.class')){ // TODO: "/" works on windows? def pathPart = entry.name.substring(0,entry.name.lastIndexOf('/')) @@ -145,9 +146,9 @@ task createBaseXml(dependsOn: configurations.corelibs) <<{ extPackages.add(classPath) } } - } + } } - + def writer = new StringWriter() def xml = new MarkupBuilder(writer) xml.mkp.xmlDeclaration(version:'1.0') @@ -252,7 +253,7 @@ task copyProjectLibs(dependsOn: [configurations.corelibs, configurations.testdat into "jme3-project-libraries/release/libs/" } } - + project.configurations.testdatalibs.dependencies.each {dep -> // copy jme3 test data to jme3-project-testdata dep.dependencyProject.configurations.archives.allArtifacts.each{ artifact-> @@ -281,10 +282,10 @@ def makeFile(builder, nameR) { builder.file(name:nameR, url:nameR) } task createProjectXml(dependsOn: configurations.corelibs) <<{ description "Creates needed J2SE library and layer XML files in jme3-project-baselibs" - - def eol = System.properties.'line.separator' + + def eol = System.properties.'line.separator' def j2seLibraries = [] // created J2SE library descriptors - + // for each dependency in corelibs.. def deps = [] deps.addAll(project.configurations.corelibs.dependencies) @@ -315,7 +316,7 @@ task createProjectXml(dependsOn: configurations.corelibs) <<{ def libraryWriter = new StringWriter() def libraryXml = new MarkupBuilder(libraryWriter) // xml.mkp.xmlDeclaration(version:'1.0') - libraryWriter << '' << eol + libraryWriter << '' << eol libraryWriter << '' << eol libraryXml.library(version:"1.0", encoding: "UTF-8"){ makeName(libraryXml, "${dep.dependencyProject.name}") @@ -352,7 +353,7 @@ task createProjectXml(dependsOn: configurations.corelibs) <<{ def layerWriter = new StringWriter() def layerXml = new MarkupBuilder(layerWriter) // layerXml.mkp.xmlDeclaration(version:'1.0') - layerWriter << '' << eol + layerWriter << '' << eol layerWriter << '' << eol layerXml.filesystem{ folder(name:"org-netbeans-api-project-libraries"){ diff --git a/sdk/jme3-project-baselibs/src/com/jme3/gde/project/baselibs/jme3-bullet-native-android.xml b/sdk/jme3-project-baselibs/src/com/jme3/gde/project/baselibs/jme3-bullet-native-android.xml new file mode 100644 index 000000000..083970e02 --- /dev/null +++ b/sdk/jme3-project-baselibs/src/com/jme3/gde/project/baselibs/jme3-bullet-native-android.xml @@ -0,0 +1,19 @@ + + + + jme3-bullet-native-android + j2se + com.jme3.gde.project.baselibs.Bundle + + classpath + jar:nbinst://com.jme3.gde.project.baselibs/libs/jme3-bullet-native-android-3.1.0-snapshot-github.jar!/ + + + src + jar:nbinst://com.jme3.gde.project.baselibs/libs/jme3-bullet-native-android-3.1.0-snapshot-github-sources.jar!/ + + + javadoc + jar:nbinst://com.jme3.gde.project.baselibs/libs/jme3-bullet-native-android-3.1.0-snapshot-github-javadoc.jar!/ + + \ No newline at end of file diff --git a/sdk/jme3-project-baselibs/src/com/jme3/gde/project/baselibs/layer.xml b/sdk/jme3-project-baselibs/src/com/jme3/gde/project/baselibs/layer.xml index 1a7e7bf0e..837ff7e16 100644 --- a/sdk/jme3-project-baselibs/src/com/jme3/gde/project/baselibs/layer.xml +++ b/sdk/jme3-project-baselibs/src/com/jme3/gde/project/baselibs/layer.xml @@ -20,6 +20,7 @@ + \ No newline at end of file From 1fa4eb441d392640e0f672c5d17435002fa83744 Mon Sep 17 00:00:00 2001 From: iwgeric Date: Tue, 31 Mar 2015 13:12:15 -0400 Subject: [PATCH 33/47] SDK: Remove android.jar from jme3-android global library --- .../src/com/jme3/gde/project/baselibs/jme3-android.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/sdk/jme3-project-baselibs/src/com/jme3/gde/project/baselibs/jme3-android.xml b/sdk/jme3-project-baselibs/src/com/jme3/gde/project/baselibs/jme3-android.xml index 801e5bb3b..d937b98a9 100644 --- a/sdk/jme3-project-baselibs/src/com/jme3/gde/project/baselibs/jme3-android.xml +++ b/sdk/jme3-project-baselibs/src/com/jme3/gde/project/baselibs/jme3-android.xml @@ -7,7 +7,6 @@ classpath jar:nbinst://com.jme3.gde.project.baselibs/libs/jme3-android-3.1.0-snapshot-github.jar!/ - jar:nbinst://com.jme3.gde.project.libraries/libs/android.jar!/ src From 32275596bf279c06333bfe9deda9e1779d598d87 Mon Sep 17 00:00:00 2001 From: iwgeric Date: Tue, 31 Mar 2015 13:29:25 -0400 Subject: [PATCH 34/47] SDK: Update mobile-impl.xml in user projects for jME 3.1 libraries --- .../com/jme3/gde/android/mobile-targets.xml | 78 +++++++------------ 1 file changed, 30 insertions(+), 48 deletions(-) diff --git a/sdk/jme3-android/src/com/jme3/gde/android/mobile-targets.xml b/sdk/jme3-android/src/com/jme3/gde/android/mobile-targets.xml index 437500ba6..cadd23107 100644 --- a/sdk/jme3-android/src/com/jme3/gde/android/mobile-targets.xml +++ b/sdk/jme3-android/src/com/jme3/gde/android/mobile-targets.xml @@ -29,58 +29,56 @@ - + - - + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + Adding libraries for android. - + + - - Replacing bullet library with android native version. - - - - - + + Replacing android native bullet library. + + + + + - - - - - - - @@ -91,25 +89,9 @@ - - Adding OpenAL Soft - - - - - - - - - - - - - - - + From 00a2a844470c51d829b0c87fb838a4c61917133e Mon Sep 17 00:00:00 2001 From: iwgeric Date: Tue, 31 Mar 2015 13:32:26 -0400 Subject: [PATCH 35/47] SDK: fix message during android build --- sdk/jme3-android/src/com/jme3/gde/android/mobile-targets.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/jme3-android/src/com/jme3/gde/android/mobile-targets.xml b/sdk/jme3-android/src/com/jme3/gde/android/mobile-targets.xml index cadd23107..d57833296 100644 --- a/sdk/jme3-android/src/com/jme3/gde/android/mobile-targets.xml +++ b/sdk/jme3-android/src/com/jme3/gde/android/mobile-targets.xml @@ -71,7 +71,7 @@ - Replacing android native bullet library. + Replacing bullet library with android native bullet version. From 1569e9583a9a5c0c0ec317df8ac44424445f88a4 Mon Sep 17 00:00:00 2001 From: iwgeric Date: Thu, 2 Apr 2015 13:08:53 -0400 Subject: [PATCH 36/47] Android: remove deprecated screenOrientation from AndroidHarness. Screen orientation is set in manifest instead of in MainActivity. --- .../java/com/jme3/app/AndroidHarness.java | 1166 ++++++++--------- 1 file changed, 580 insertions(+), 586 deletions(-) diff --git a/jme3-android/src/main/java/com/jme3/app/AndroidHarness.java b/jme3-android/src/main/java/com/jme3/app/AndroidHarness.java index 1d2835bc3..b103e92df 100644 --- a/jme3-android/src/main/java/com/jme3/app/AndroidHarness.java +++ b/jme3-android/src/main/java/com/jme3/app/AndroidHarness.java @@ -1,586 +1,580 @@ -package com.jme3.app; - -import android.app.Activity; -import android.app.AlertDialog; -import android.content.DialogInterface; -import android.content.pm.ActivityInfo; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.NinePatchDrawable; -import android.opengl.GLSurfaceView; -import android.os.Bundle; -import android.util.Log; -import android.view.*; -import android.view.ViewGroup.LayoutParams; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.TextView; -import com.jme3.audio.AudioRenderer; -import com.jme3.input.JoyInput; -import com.jme3.input.TouchInput; -import com.jme3.input.android.AndroidSensorJoyInput; -import com.jme3.input.controls.TouchListener; -import com.jme3.input.controls.TouchTrigger; -import com.jme3.input.event.TouchEvent; -import com.jme3.system.AppSettings; -import com.jme3.system.SystemListener; -import com.jme3.system.android.JmeAndroidSystem; -import com.jme3.system.android.OGLESContext; -import com.jme3.util.AndroidLogHandler; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.logging.Handler; -import java.util.logging.Level; -import java.util.logging.LogManager; -import java.util.logging.Logger; - -/** - * AndroidHarness wraps a jme application object and runs it on - * Android - * - * @author Kirill - * @author larynx - */ -public class AndroidHarness extends Activity implements TouchListener, DialogInterface.OnClickListener, SystemListener { - - protected final static Logger logger = Logger.getLogger(AndroidHarness.class.getName()); - /** - * The application class to start - */ - protected String appClass = "jme3test.android.Test"; - /** - * The jme3 application object - */ - protected Application app = null; - - /** - * Sets the desired RGB size for the surfaceview. 16 = RGB565, 24 = RGB888. - * (default = 24) - */ - protected int eglBitsPerPixel = 24; - - /** - * Sets the desired number of Alpha bits for the surfaceview. This affects - * how the surfaceview is able to display Android views that are located - * under the surfaceview jME uses to render the scenegraph. - * 0 = Opaque surfaceview background (fastest) - * 1->7 = Transparent surfaceview background - * 8 or higher = Translucent surfaceview background - * (default = 0) - */ - protected int eglAlphaBits = 0; - - /** - * The number of depth bits specifies the precision of the depth buffer. - * (default = 16) - */ - protected int eglDepthBits = 16; - - /** - * Sets the number of samples to use for multisampling.
- * Leave 0 (default) to disable multisampling.
- * Set to 2 or 4 to enable multisampling. - */ - protected int eglSamples = 0; - - /** - * Set the number of stencil bits. - * (default = 0) - */ - protected int eglStencilBits = 0; - - /** - * Set the desired frame rate. If frameRate > 0, the application - * will be capped at the desired frame rate. - * (default = -1, no frame rate cap) - */ - protected int frameRate = -1; - - /** - * Sets the type of Audio Renderer to be used. - *

- * Android MediaPlayer / SoundPool can be used on all - * supported Android platform versions (2.2+)
- * OpenAL Soft uses an OpenSL backend and is only supported on Android - * versions 2.3+. - *

- * Only use ANDROID_ static strings found in AppSettings - * - */ - protected String audioRendererType = AppSettings.ANDROID_OPENAL_SOFT; - - /** - * If true Android Sensors are used as simulated Joysticks. Users can use the - * Android sensor feedback through the RawInputListener or by registering - * JoyAxisTriggers. - */ - protected boolean joystickEventsEnabled = false; - /** - * If true KeyEvents are generated from TouchEvents - */ - protected boolean keyEventsEnabled = true; - /** - * If true MouseEvents are generated from TouchEvents - */ - protected boolean mouseEventsEnabled = true; - /** - * Flip X axis - */ - protected boolean mouseEventsInvertX = false; - /** - * Flip Y axis - */ - protected boolean mouseEventsInvertY = false; - /** - * if true finish this activity when the jme app is stopped - */ - protected boolean finishOnAppStop = true; - /** - * set to false if you don't want the harness to handle the exit hook - */ - protected boolean handleExitHook = true; - /** - * Title of the exit dialog, default is "Do you want to exit?" - */ - protected String exitDialogTitle = "Do you want to exit?"; - /** - * Message of the exit dialog, default is "Use your home key to bring this - * app into the background or exit to terminate it." - */ - protected String exitDialogMessage = "Use your home key to bring this app into the background or exit to terminate it."; - /** - * Set the screen window mode. If screenFullSize is true, then the - * notification bar and title bar are removed and the screen covers the - * entire display. If screenFullSize is false, then the notification bar - * remains visible if screenShowTitle is true while screenFullScreen is - * false, then the title bar is also displayed under the notification bar. - */ - protected boolean screenFullScreen = true; - /** - * if screenShowTitle is true while screenFullScreen is false, then the - * title bar is also displayed under the notification bar - */ - protected boolean screenShowTitle = true; - /** - * Splash Screen picture Resource ID. If a Splash Screen is desired, set - * splashPicID to the value of the Resource ID (i.e. R.drawable.picname). If - * splashPicID = 0, then no splash screen will be displayed. - */ - protected int splashPicID = 0; - - /** - * No longer used - Use the android:screenOrientation declaration in - * the AndroidManifest.xml file. - */ - @Deprecated - protected int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR; - - protected OGLESContext ctx; - protected GLSurfaceView view = null; - protected boolean isGLThreadPaused = true; - protected ImageView splashImageView = null; - protected FrameLayout frameLayout = null; - final private String ESCAPE_EVENT = "TouchEscape"; - private boolean firstDrawFrame = true; - private boolean inConfigChange = false; - - private class DataObject { - protected Application app = null; - } - - @Override - public Object onRetainNonConfigurationInstance() { - logger.log(Level.FINE, "onRetainNonConfigurationInstance"); - final DataObject data = new DataObject(); - data.app = this.app; - inConfigChange = true; - return data; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - initializeLogHandler(); - - logger.fine("onCreate"); - super.onCreate(savedInstanceState); - - if (screenFullScreen) { - requestWindowFeature(Window.FEATURE_NO_TITLE); - getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, - WindowManager.LayoutParams.FLAG_FULLSCREEN); - } else { - if (!screenShowTitle) { - requestWindowFeature(Window.FEATURE_NO_TITLE); - } - } - - final DataObject data = (DataObject) getLastNonConfigurationInstance(); - if (data != null) { - logger.log(Level.FINE, "Using Retained App"); - this.app = data.app; - } else { - // Discover the screen reolution - //TODO try to find a better way to get a hand on the resolution - WindowManager wind = this.getWindowManager(); - Display disp = wind.getDefaultDisplay(); - Log.d("AndroidHarness", "Resolution from Window, width:" + disp.getWidth() + ", height: " + disp.getHeight()); - - // Create Settings - logger.log(Level.FINE, "Creating settings"); - AppSettings settings = new AppSettings(true); - settings.setEmulateMouse(mouseEventsEnabled); - settings.setEmulateMouseFlipAxis(mouseEventsInvertX, mouseEventsInvertY); - settings.setUseJoysticks(joystickEventsEnabled); - settings.setEmulateKeyboard(keyEventsEnabled); - - settings.setBitsPerPixel(eglBitsPerPixel); - settings.setAlphaBits(eglAlphaBits); - settings.setDepthBits(eglDepthBits); - settings.setSamples(eglSamples); - settings.setStencilBits(eglStencilBits); - - settings.setResolution(disp.getWidth(), disp.getHeight()); - settings.setAudioRenderer(audioRendererType); - - settings.setFrameRate(frameRate); - - // Create application instance - try { - if (app == null) { - @SuppressWarnings("unchecked") - Class clazz = (Class) Class.forName(appClass); - app = clazz.newInstance(); - } - - app.setSettings(settings); - app.start(); - } catch (Exception ex) { - handleError("Class " + appClass + " init failed", ex); - setContentView(new TextView(this)); - } - } - - ctx = (OGLESContext) app.getContext(); - view = ctx.createView(this); - // store the glSurfaceView in JmeAndroidSystem for future use - JmeAndroidSystem.setView(view); - // AndroidHarness wraps the app as a SystemListener. - ctx.setSystemListener(this); - layoutDisplay(); - } - - @Override - protected void onRestart() { - logger.fine("onRestart"); - super.onRestart(); - if (app != null) { - app.restart(); - } - } - - @Override - protected void onStart() { - logger.fine("onStart"); - super.onStart(); - } - - @Override - protected void onResume() { - logger.fine("onResume"); - super.onResume(); - - gainFocus(); - } - - @Override - protected void onPause() { - logger.fine("onPause"); - loseFocus(); - - super.onPause(); - } - - @Override - protected void onStop() { - logger.fine("onStop"); - super.onStop(); - } - - @Override - protected void onDestroy() { - logger.fine("onDestroy"); - final DataObject data = (DataObject) getLastNonConfigurationInstance(); - if (data != null || inConfigChange) { - logger.fine("In Config Change, not stopping app."); - } else { - if (app != null) { - app.stop(!isGLThreadPaused); - } - } - setContentView(new TextView(this)); - ctx = null; - app = null; - view = null; - JmeAndroidSystem.setView(null); - - super.onDestroy(); - } - - public Application getJmeApplication() { - return app; - } - - /** - * Called when an error has occurred. By default, will show an error message - * to the user and print the exception/error to the log. - */ - @Override - public void handleError(final String errorMsg, final Throwable t) { - String stackTrace = ""; - String title = "Error"; - - if (t != null) { - // Convert exception to string - StringWriter sw = new StringWriter(100); - t.printStackTrace(new PrintWriter(sw)); - stackTrace = sw.toString(); - title = t.toString(); - } - - final String finalTitle = title; - final String finalMsg = (errorMsg != null ? errorMsg : "Uncaught Exception") - + "\n" + stackTrace; - - logger.log(Level.SEVERE, finalMsg); - - runOnUiThread(new Runnable() { - @Override - public void run() { - AlertDialog dialog = new AlertDialog.Builder(AndroidHarness.this) // .setIcon(R.drawable.alert_dialog_icon) - .setTitle(finalTitle).setPositiveButton("Kill", AndroidHarness.this).setMessage(finalMsg).create(); - dialog.show(); - } - }); - } - - /** - * Called by the android alert dialog, terminate the activity and OpenGL - * rendering - * - * @param dialog - * @param whichButton - */ - public void onClick(DialogInterface dialog, int whichButton) { - if (whichButton != -2) { - if (app != null) { - app.stop(true); - } - app = null; - this.finish(); - } - } - - /** - * Gets called by the InputManager on all touch/drag/scale events - */ - @Override - public void onTouch(String name, TouchEvent evt, float tpf) { - if (name.equals(ESCAPE_EVENT)) { - switch (evt.getType()) { - case KEY_UP: - runOnUiThread(new Runnable() { - @Override - public void run() { - AlertDialog dialog = new AlertDialog.Builder(AndroidHarness.this) // .setIcon(R.drawable.alert_dialog_icon) - .setTitle(exitDialogTitle).setPositiveButton("Yes", AndroidHarness.this).setNegativeButton("No", AndroidHarness.this).setMessage(exitDialogMessage).create(); - dialog.show(); - } - }); - break; - default: - break; - } - } - } - - public void layoutDisplay() { - logger.log(Level.FINE, "Splash Screen Picture Resource ID: {0}", splashPicID); - if (view == null) { - logger.log(Level.FINE, "view is null!"); - } - if (splashPicID != 0) { - FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams( - LayoutParams.MATCH_PARENT, - LayoutParams.MATCH_PARENT, - Gravity.CENTER); - - frameLayout = new FrameLayout(this); - splashImageView = new ImageView(this); - - Drawable drawable = this.getResources().getDrawable(splashPicID); - if (drawable instanceof NinePatchDrawable) { - splashImageView.setBackgroundDrawable(drawable); - } else { - splashImageView.setImageResource(splashPicID); - } - - if (view.getParent() != null) { - ((ViewGroup) view.getParent()).removeView(view); - } - frameLayout.addView(view); - - if (splashImageView.getParent() != null) { - ((ViewGroup) splashImageView.getParent()).removeView(splashImageView); - } - frameLayout.addView(splashImageView, lp); - - setContentView(frameLayout); - logger.log(Level.FINE, "Splash Screen Created"); - } else { - logger.log(Level.FINE, "Splash Screen Skipped."); - setContentView(view); - } - } - - public void removeSplashScreen() { - logger.log(Level.FINE, "Splash Screen Picture Resource ID: {0}", splashPicID); - if (splashPicID != 0) { - if (frameLayout != null) { - if (splashImageView != null) { - this.runOnUiThread(new Runnable() { - @Override - public void run() { - splashImageView.setVisibility(View.INVISIBLE); - frameLayout.removeView(splashImageView); - } - }); - } else { - logger.log(Level.FINE, "splashImageView is null"); - } - } else { - logger.log(Level.FINE, "frameLayout is null"); - } - } - } - - /** - * Removes the standard Android log handler due to an issue with not logging - * entries lower than INFO level and adds a handler that produces - * JME formatted log messages. - */ - protected void initializeLogHandler() { - Logger log = LogManager.getLogManager().getLogger(""); - for (Handler handler : log.getHandlers()) { - if (log.getLevel() != null && log.getLevel().intValue() <= Level.FINE.intValue()) { - Log.v("AndroidHarness", "Removing Handler class: " + handler.getClass().getName()); - } - log.removeHandler(handler); - } - Handler handler = new AndroidLogHandler(); - log.addHandler(handler); - handler.setLevel(Level.ALL); - } - - public void initialize() { - app.initialize(); - if (handleExitHook) { - // remove existing mapping from SimpleApplication that stops the app - // when the esc key is pressed (esc key = android back key) so that - // AndroidHarness can produce the exit app dialog box. - if (app.getInputManager().hasMapping(SimpleApplication.INPUT_MAPPING_EXIT)) { - app.getInputManager().deleteMapping(SimpleApplication.INPUT_MAPPING_EXIT); - } - - app.getInputManager().addMapping(ESCAPE_EVENT, new TouchTrigger(TouchInput.KEYCODE_BACK)); - app.getInputManager().addListener(this, new String[]{ESCAPE_EVENT}); - } - } - - public void reshape(int width, int height) { - app.reshape(width, height); - } - - public void update() { - app.update(); - // call to remove the splash screen, if present. - // call after app.update() to make sure no gap between - // splash screen going away and app display being shown. - if (firstDrawFrame) { - removeSplashScreen(); - firstDrawFrame = false; - } - } - - public void requestClose(boolean esc) { - app.requestClose(esc); - } - - public void destroy() { - if (app != null) { - app.destroy(); - } - if (finishOnAppStop) { - finish(); - } - } - - public void gainFocus() { - logger.fine("gainFocus"); - if (view != null) { - view.onResume(); - } - - if (app != null) { - //resume the audio - AudioRenderer audioRenderer = app.getAudioRenderer(); - if (audioRenderer != null) { - audioRenderer.resumeAll(); - } - //resume the sensors (aka joysticks) - if (app.getContext() != null) { - JoyInput joyInput = app.getContext().getJoyInput(); - if (joyInput != null) { - if (joyInput instanceof AndroidSensorJoyInput) { - AndroidSensorJoyInput androidJoyInput = (AndroidSensorJoyInput) joyInput; - androidJoyInput.resumeSensors(); - } - } - } - } - - isGLThreadPaused = false; - - if (app != null) { - app.gainFocus(); - } - } - - public void loseFocus() { - logger.fine("loseFocus"); - if (app != null) { - app.loseFocus(); - } - - if (view != null) { - view.onPause(); - } - - if (app != null) { - //pause the audio - AudioRenderer audioRenderer = app.getAudioRenderer(); - if (audioRenderer != null) { - audioRenderer.pauseAll(); - } - //pause the sensors (aka joysticks) - if (app.getContext() != null) { - JoyInput joyInput = app.getContext().getJoyInput(); - if (joyInput != null) { - if (joyInput instanceof AndroidSensorJoyInput) { - AndroidSensorJoyInput androidJoyInput = (AndroidSensorJoyInput) joyInput; - androidJoyInput.pauseSensors(); - } - } - } - } - isGLThreadPaused = true; - } -} +package com.jme3.app; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.pm.ActivityInfo; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.NinePatchDrawable; +import android.opengl.GLSurfaceView; +import android.os.Bundle; +import android.util.Log; +import android.view.*; +import android.view.ViewGroup.LayoutParams; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; +import com.jme3.audio.AudioRenderer; +import com.jme3.input.JoyInput; +import com.jme3.input.TouchInput; +import com.jme3.input.android.AndroidSensorJoyInput; +import com.jme3.input.controls.TouchListener; +import com.jme3.input.controls.TouchTrigger; +import com.jme3.input.event.TouchEvent; +import com.jme3.system.AppSettings; +import com.jme3.system.SystemListener; +import com.jme3.system.android.JmeAndroidSystem; +import com.jme3.system.android.OGLESContext; +import com.jme3.util.AndroidLogHandler; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.LogManager; +import java.util.logging.Logger; + +/** + * AndroidHarness wraps a jme application object and runs it on + * Android + * + * @author Kirill + * @author larynx + */ +public class AndroidHarness extends Activity implements TouchListener, DialogInterface.OnClickListener, SystemListener { + + protected final static Logger logger = Logger.getLogger(AndroidHarness.class.getName()); + /** + * The application class to start + */ + protected String appClass = "jme3test.android.Test"; + /** + * The jme3 application object + */ + protected Application app = null; + + /** + * Sets the desired RGB size for the surfaceview. 16 = RGB565, 24 = RGB888. + * (default = 24) + */ + protected int eglBitsPerPixel = 24; + + /** + * Sets the desired number of Alpha bits for the surfaceview. This affects + * how the surfaceview is able to display Android views that are located + * under the surfaceview jME uses to render the scenegraph. + * 0 = Opaque surfaceview background (fastest) + * 1->7 = Transparent surfaceview background + * 8 or higher = Translucent surfaceview background + * (default = 0) + */ + protected int eglAlphaBits = 0; + + /** + * The number of depth bits specifies the precision of the depth buffer. + * (default = 16) + */ + protected int eglDepthBits = 16; + + /** + * Sets the number of samples to use for multisampling.
+ * Leave 0 (default) to disable multisampling.
+ * Set to 2 or 4 to enable multisampling. + */ + protected int eglSamples = 0; + + /** + * Set the number of stencil bits. + * (default = 0) + */ + protected int eglStencilBits = 0; + + /** + * Set the desired frame rate. If frameRate > 0, the application + * will be capped at the desired frame rate. + * (default = -1, no frame rate cap) + */ + protected int frameRate = -1; + + /** + * Sets the type of Audio Renderer to be used. + *

+ * Android MediaPlayer / SoundPool can be used on all + * supported Android platform versions (2.2+)
+ * OpenAL Soft uses an OpenSL backend and is only supported on Android + * versions 2.3+. + *

+ * Only use ANDROID_ static strings found in AppSettings + * + */ + protected String audioRendererType = AppSettings.ANDROID_OPENAL_SOFT; + + /** + * If true Android Sensors are used as simulated Joysticks. Users can use the + * Android sensor feedback through the RawInputListener or by registering + * JoyAxisTriggers. + */ + protected boolean joystickEventsEnabled = false; + /** + * If true KeyEvents are generated from TouchEvents + */ + protected boolean keyEventsEnabled = true; + /** + * If true MouseEvents are generated from TouchEvents + */ + protected boolean mouseEventsEnabled = true; + /** + * Flip X axis + */ + protected boolean mouseEventsInvertX = false; + /** + * Flip Y axis + */ + protected boolean mouseEventsInvertY = false; + /** + * if true finish this activity when the jme app is stopped + */ + protected boolean finishOnAppStop = true; + /** + * set to false if you don't want the harness to handle the exit hook + */ + protected boolean handleExitHook = true; + /** + * Title of the exit dialog, default is "Do you want to exit?" + */ + protected String exitDialogTitle = "Do you want to exit?"; + /** + * Message of the exit dialog, default is "Use your home key to bring this + * app into the background or exit to terminate it." + */ + protected String exitDialogMessage = "Use your home key to bring this app into the background or exit to terminate it."; + /** + * Set the screen window mode. If screenFullSize is true, then the + * notification bar and title bar are removed and the screen covers the + * entire display. If screenFullSize is false, then the notification bar + * remains visible if screenShowTitle is true while screenFullScreen is + * false, then the title bar is also displayed under the notification bar. + */ + protected boolean screenFullScreen = true; + /** + * if screenShowTitle is true while screenFullScreen is false, then the + * title bar is also displayed under the notification bar + */ + protected boolean screenShowTitle = true; + /** + * Splash Screen picture Resource ID. If a Splash Screen is desired, set + * splashPicID to the value of the Resource ID (i.e. R.drawable.picname). If + * splashPicID = 0, then no splash screen will be displayed. + */ + protected int splashPicID = 0; + + + protected OGLESContext ctx; + protected GLSurfaceView view = null; + protected boolean isGLThreadPaused = true; + protected ImageView splashImageView = null; + protected FrameLayout frameLayout = null; + final private String ESCAPE_EVENT = "TouchEscape"; + private boolean firstDrawFrame = true; + private boolean inConfigChange = false; + + private class DataObject { + protected Application app = null; + } + + @Override + public Object onRetainNonConfigurationInstance() { + logger.log(Level.FINE, "onRetainNonConfigurationInstance"); + final DataObject data = new DataObject(); + data.app = this.app; + inConfigChange = true; + return data; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + initializeLogHandler(); + + logger.fine("onCreate"); + super.onCreate(savedInstanceState); + + if (screenFullScreen) { + requestWindowFeature(Window.FEATURE_NO_TITLE); + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + } else { + if (!screenShowTitle) { + requestWindowFeature(Window.FEATURE_NO_TITLE); + } + } + + final DataObject data = (DataObject) getLastNonConfigurationInstance(); + if (data != null) { + logger.log(Level.FINE, "Using Retained App"); + this.app = data.app; + } else { + // Discover the screen reolution + //TODO try to find a better way to get a hand on the resolution + WindowManager wind = this.getWindowManager(); + Display disp = wind.getDefaultDisplay(); + Log.d("AndroidHarness", "Resolution from Window, width:" + disp.getWidth() + ", height: " + disp.getHeight()); + + // Create Settings + logger.log(Level.FINE, "Creating settings"); + AppSettings settings = new AppSettings(true); + settings.setEmulateMouse(mouseEventsEnabled); + settings.setEmulateMouseFlipAxis(mouseEventsInvertX, mouseEventsInvertY); + settings.setUseJoysticks(joystickEventsEnabled); + settings.setEmulateKeyboard(keyEventsEnabled); + + settings.setBitsPerPixel(eglBitsPerPixel); + settings.setAlphaBits(eglAlphaBits); + settings.setDepthBits(eglDepthBits); + settings.setSamples(eglSamples); + settings.setStencilBits(eglStencilBits); + + settings.setResolution(disp.getWidth(), disp.getHeight()); + settings.setAudioRenderer(audioRendererType); + + settings.setFrameRate(frameRate); + + // Create application instance + try { + if (app == null) { + @SuppressWarnings("unchecked") + Class clazz = (Class) Class.forName(appClass); + app = clazz.newInstance(); + } + + app.setSettings(settings); + app.start(); + } catch (Exception ex) { + handleError("Class " + appClass + " init failed", ex); + setContentView(new TextView(this)); + } + } + + ctx = (OGLESContext) app.getContext(); + view = ctx.createView(this); + // store the glSurfaceView in JmeAndroidSystem for future use + JmeAndroidSystem.setView(view); + // AndroidHarness wraps the app as a SystemListener. + ctx.setSystemListener(this); + layoutDisplay(); + } + + @Override + protected void onRestart() { + logger.fine("onRestart"); + super.onRestart(); + if (app != null) { + app.restart(); + } + } + + @Override + protected void onStart() { + logger.fine("onStart"); + super.onStart(); + } + + @Override + protected void onResume() { + logger.fine("onResume"); + super.onResume(); + + gainFocus(); + } + + @Override + protected void onPause() { + logger.fine("onPause"); + loseFocus(); + + super.onPause(); + } + + @Override + protected void onStop() { + logger.fine("onStop"); + super.onStop(); + } + + @Override + protected void onDestroy() { + logger.fine("onDestroy"); + final DataObject data = (DataObject) getLastNonConfigurationInstance(); + if (data != null || inConfigChange) { + logger.fine("In Config Change, not stopping app."); + } else { + if (app != null) { + app.stop(!isGLThreadPaused); + } + } + setContentView(new TextView(this)); + ctx = null; + app = null; + view = null; + JmeAndroidSystem.setView(null); + + super.onDestroy(); + } + + public Application getJmeApplication() { + return app; + } + + /** + * Called when an error has occurred. By default, will show an error message + * to the user and print the exception/error to the log. + */ + @Override + public void handleError(final String errorMsg, final Throwable t) { + String stackTrace = ""; + String title = "Error"; + + if (t != null) { + // Convert exception to string + StringWriter sw = new StringWriter(100); + t.printStackTrace(new PrintWriter(sw)); + stackTrace = sw.toString(); + title = t.toString(); + } + + final String finalTitle = title; + final String finalMsg = (errorMsg != null ? errorMsg : "Uncaught Exception") + + "\n" + stackTrace; + + logger.log(Level.SEVERE, finalMsg); + + runOnUiThread(new Runnable() { + @Override + public void run() { + AlertDialog dialog = new AlertDialog.Builder(AndroidHarness.this) // .setIcon(R.drawable.alert_dialog_icon) + .setTitle(finalTitle).setPositiveButton("Kill", AndroidHarness.this).setMessage(finalMsg).create(); + dialog.show(); + } + }); + } + + /** + * Called by the android alert dialog, terminate the activity and OpenGL + * rendering + * + * @param dialog + * @param whichButton + */ + public void onClick(DialogInterface dialog, int whichButton) { + if (whichButton != -2) { + if (app != null) { + app.stop(true); + } + app = null; + this.finish(); + } + } + + /** + * Gets called by the InputManager on all touch/drag/scale events + */ + @Override + public void onTouch(String name, TouchEvent evt, float tpf) { + if (name.equals(ESCAPE_EVENT)) { + switch (evt.getType()) { + case KEY_UP: + runOnUiThread(new Runnable() { + @Override + public void run() { + AlertDialog dialog = new AlertDialog.Builder(AndroidHarness.this) // .setIcon(R.drawable.alert_dialog_icon) + .setTitle(exitDialogTitle).setPositiveButton("Yes", AndroidHarness.this).setNegativeButton("No", AndroidHarness.this).setMessage(exitDialogMessage).create(); + dialog.show(); + } + }); + break; + default: + break; + } + } + } + + public void layoutDisplay() { + logger.log(Level.FINE, "Splash Screen Picture Resource ID: {0}", splashPicID); + if (view == null) { + logger.log(Level.FINE, "view is null!"); + } + if (splashPicID != 0) { + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams( + LayoutParams.MATCH_PARENT, + LayoutParams.MATCH_PARENT, + Gravity.CENTER); + + frameLayout = new FrameLayout(this); + splashImageView = new ImageView(this); + + Drawable drawable = this.getResources().getDrawable(splashPicID); + if (drawable instanceof NinePatchDrawable) { + splashImageView.setBackgroundDrawable(drawable); + } else { + splashImageView.setImageResource(splashPicID); + } + + if (view.getParent() != null) { + ((ViewGroup) view.getParent()).removeView(view); + } + frameLayout.addView(view); + + if (splashImageView.getParent() != null) { + ((ViewGroup) splashImageView.getParent()).removeView(splashImageView); + } + frameLayout.addView(splashImageView, lp); + + setContentView(frameLayout); + logger.log(Level.FINE, "Splash Screen Created"); + } else { + logger.log(Level.FINE, "Splash Screen Skipped."); + setContentView(view); + } + } + + public void removeSplashScreen() { + logger.log(Level.FINE, "Splash Screen Picture Resource ID: {0}", splashPicID); + if (splashPicID != 0) { + if (frameLayout != null) { + if (splashImageView != null) { + this.runOnUiThread(new Runnable() { + @Override + public void run() { + splashImageView.setVisibility(View.INVISIBLE); + frameLayout.removeView(splashImageView); + } + }); + } else { + logger.log(Level.FINE, "splashImageView is null"); + } + } else { + logger.log(Level.FINE, "frameLayout is null"); + } + } + } + + /** + * Removes the standard Android log handler due to an issue with not logging + * entries lower than INFO level and adds a handler that produces + * JME formatted log messages. + */ + protected void initializeLogHandler() { + Logger log = LogManager.getLogManager().getLogger(""); + for (Handler handler : log.getHandlers()) { + if (log.getLevel() != null && log.getLevel().intValue() <= Level.FINE.intValue()) { + Log.v("AndroidHarness", "Removing Handler class: " + handler.getClass().getName()); + } + log.removeHandler(handler); + } + Handler handler = new AndroidLogHandler(); + log.addHandler(handler); + handler.setLevel(Level.ALL); + } + + public void initialize() { + app.initialize(); + if (handleExitHook) { + // remove existing mapping from SimpleApplication that stops the app + // when the esc key is pressed (esc key = android back key) so that + // AndroidHarness can produce the exit app dialog box. + if (app.getInputManager().hasMapping(SimpleApplication.INPUT_MAPPING_EXIT)) { + app.getInputManager().deleteMapping(SimpleApplication.INPUT_MAPPING_EXIT); + } + + app.getInputManager().addMapping(ESCAPE_EVENT, new TouchTrigger(TouchInput.KEYCODE_BACK)); + app.getInputManager().addListener(this, new String[]{ESCAPE_EVENT}); + } + } + + public void reshape(int width, int height) { + app.reshape(width, height); + } + + public void update() { + app.update(); + // call to remove the splash screen, if present. + // call after app.update() to make sure no gap between + // splash screen going away and app display being shown. + if (firstDrawFrame) { + removeSplashScreen(); + firstDrawFrame = false; + } + } + + public void requestClose(boolean esc) { + app.requestClose(esc); + } + + public void destroy() { + if (app != null) { + app.destroy(); + } + if (finishOnAppStop) { + finish(); + } + } + + public void gainFocus() { + logger.fine("gainFocus"); + if (view != null) { + view.onResume(); + } + + if (app != null) { + //resume the audio + AudioRenderer audioRenderer = app.getAudioRenderer(); + if (audioRenderer != null) { + audioRenderer.resumeAll(); + } + //resume the sensors (aka joysticks) + if (app.getContext() != null) { + JoyInput joyInput = app.getContext().getJoyInput(); + if (joyInput != null) { + if (joyInput instanceof AndroidSensorJoyInput) { + AndroidSensorJoyInput androidJoyInput = (AndroidSensorJoyInput) joyInput; + androidJoyInput.resumeSensors(); + } + } + } + } + + isGLThreadPaused = false; + + if (app != null) { + app.gainFocus(); + } + } + + public void loseFocus() { + logger.fine("loseFocus"); + if (app != null) { + app.loseFocus(); + } + + if (view != null) { + view.onPause(); + } + + if (app != null) { + //pause the audio + AudioRenderer audioRenderer = app.getAudioRenderer(); + if (audioRenderer != null) { + audioRenderer.pauseAll(); + } + //pause the sensors (aka joysticks) + if (app.getContext() != null) { + JoyInput joyInput = app.getContext().getJoyInput(); + if (joyInput != null) { + if (joyInput instanceof AndroidSensorJoyInput) { + AndroidSensorJoyInput androidJoyInput = (AndroidSensorJoyInput) joyInput; + androidJoyInput.pauseSensors(); + } + } + } + } + isGLThreadPaused = true; + } +} From 5ab8fb8f6a8fafd8a27d3509928ceb427e2f24c3 Mon Sep 17 00:00:00 2001 From: iwgeric Date: Thu, 2 Apr 2015 13:09:49 -0400 Subject: [PATCH 37/47] Android: remove reference to screenOrientation from unused test project --- .../java/jme3test/android/DemoAndroidHarness.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/jme3-android/src/main/java/jme3test/android/DemoAndroidHarness.java b/jme3-android/src/main/java/jme3test/android/DemoAndroidHarness.java index 42c621a4f..61d0d6868 100644 --- a/jme3-android/src/main/java/jme3test/android/DemoAndroidHarness.java +++ b/jme3-android/src/main/java/jme3test/android/DemoAndroidHarness.java @@ -7,21 +7,19 @@ import com.jme3.app.AndroidHarness; public class DemoAndroidHarness extends AndroidHarness { @Override - public void onCreate(Bundle savedInstanceState) - { + public void onCreate(Bundle savedInstanceState) + { // Set the application class to run // First Extract the bundle from intent Bundle bundle = getIntent().getExtras(); //Next extract the values using the key as - appClass = bundle.getString("APPCLASSNAME"); - + appClass = bundle.getString("APPCLASSNAME"); + exitDialogTitle = "Close Demo?"; exitDialogMessage = "Press Yes"; - screenOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; - - super.onCreate(savedInstanceState); + super.onCreate(savedInstanceState); } } From be6416b736326b1c3d6f77b8dd7d6141cf4364d9 Mon Sep 17 00:00:00 2001 From: iwgeric Date: Thu, 2 Apr 2015 13:12:08 -0400 Subject: [PATCH 38/47] SDK: Add layout.xml and strings.xml to Important Files node in Android projects. Useful to quickly modify the layout for the upcoming switch to Android Fragments. --- .../com/jme3/gde/android/AndroidImportantFiles.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sdk/jme3-android/src/com/jme3/gde/android/AndroidImportantFiles.java b/sdk/jme3-android/src/com/jme3/gde/android/AndroidImportantFiles.java index cbfb487cc..b96bb769c 100644 --- a/sdk/jme3-android/src/com/jme3/gde/android/AndroidImportantFiles.java +++ b/sdk/jme3-android/src/com/jme3/gde/android/AndroidImportantFiles.java @@ -67,6 +67,18 @@ public class AndroidImportantFiles implements ImportantFiles { node.setDisplayName("Android Properties"); list.add(node); } + FileObject layout = project.getProjectDirectory().getFileObject("mobile/res/layout/main.xml"); + if (layout != null) { + Node node = DataObject.find(layout).getNodeDelegate(); + node.setDisplayName("Android Layout"); + list.add(node); + } + FileObject strings = project.getProjectDirectory().getFileObject("mobile/res/values/strings.xml"); + if (strings != null) { + Node node = DataObject.find(strings).getNodeDelegate(); + node.setDisplayName("Android Strings"); + list.add(node); + } } catch (DataObjectNotFoundException ex) { Exceptions.printStackTrace(ex); } From 664dfc037cd84594f1e3506044af2d000fad69e6 Mon Sep 17 00:00:00 2001 From: iwgeric Date: Thu, 2 Apr 2015 13:14:16 -0400 Subject: [PATCH 39/47] SDK: Update creation of MainActivity and AndroidManifest to support jME 3.1 Add screen orientation to manifest and update the min version to 9. Update MainActivity creation to remove references to properties removed from AndroidHarness. --- .../com/jme3/gde/android/AndroidSdkTool.java | 29 +++++++------------ 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/sdk/jme3-android/src/com/jme3/gde/android/AndroidSdkTool.java b/sdk/jme3-android/src/com/jme3/gde/android/AndroidSdkTool.java index b93b089cc..066265e74 100644 --- a/sdk/jme3-android/src/com/jme3/gde/android/AndroidSdkTool.java +++ b/sdk/jme3-android/src/com/jme3/gde/android/AndroidSdkTool.java @@ -299,17 +299,15 @@ public class AndroidSdkTool { changed = true; } } - // add the following after AndroidHarness.screenOrientation is depreciated - // for jME 3.1 -// if (sdkActivity != null) { -// if (sdkActivity.hasAttribute("android:screenOrientation")) { -// String attrScreenOrientation = sdkActivity.getAttribute("android:screenOrientation"); -// } else { -// Logger.getLogger(AndroidSdkTool.class.getName()).log(Level.INFO, "creating attrScreenOrientation"); -// sdkActivity.setAttribute("android:screenOrientation", "landscape"); -// changed = true; -// } -// } + if (sdkActivity != null) { + if (sdkActivity.hasAttribute("android:screenOrientation")) { + String attrScreenOrientation = sdkActivity.getAttribute("android:screenOrientation"); + } else { + Logger.getLogger(AndroidSdkTool.class.getName()).log(Level.INFO, "creating attrScreenOrientation"); + sdkActivity.setAttribute("android:screenOrientation", "landscape"); + changed = true; + } + } } Element sdkElement = XmlHelper.findChildElement(configuration.getDocumentElement(), "uses-sdk"); @@ -319,7 +317,7 @@ public class AndroidSdkTool { changed = true; } if (!"8".equals(sdkElement.getAttribute("android:minSdkVersion"))) { - sdkElement.setAttribute("android:minSdkVersion", "8"); + sdkElement.setAttribute("android:minSdkVersion", "9"); changed = true; } Element screensElement = XmlHelper.findChildElement(configuration.getDocumentElement(), "supports-screens"); @@ -419,7 +417,6 @@ public class AndroidSdkTool { + " \n" + "import android.content.pm.ActivityInfo;\n" + "import com.jme3.app.AndroidHarness;\n" - + "import com.jme3.system.android.AndroidConfigChooser.ConfigType;\n" + "import java.util.logging.Level;\n" + "import java.util.logging.LogManager;\n" + " \n" @@ -435,15 +432,9 @@ public class AndroidSdkTool { + " public MainActivity(){\n" + " // Set the application class to run\n" + " appClass = \"" + mainClass + "\";\n" - + " // Try ConfigType.FASTEST; or ConfigType.LEGACY if you have problems\n" - + " eglConfigType = ConfigType.BEST;\n" + " // Exit Dialog title & message\n" + " exitDialogTitle = \"Exit?\";\n" + " exitDialogMessage = \"Press Yes\";\n" - + " // Enable verbose logging\n" - + " eglConfigVerboseLogging = false;\n" - + " // Choose screen orientation\n" - + " screenOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;\n" + " // Enable MouseEvents being generated from TouchEvents (default = true)\n" + " mouseEventsEnabled = true;\n" + " // Set the default logging level (default=Level.INFO, Level.ALL=All Debug Info)\n" From b095158bc0d29d4de539c1624e4c380d55b7da77 Mon Sep 17 00:00:00 2001 From: iwgeric Date: Thu, 2 Apr 2015 13:16:03 -0400 Subject: [PATCH 40/47] SDK: Add temporary fix to remove android.jar from mobile/libs folder during build. android.jar is being added to jme3-android.jar during the build. Build script of jme3-android project needs to be updated to not add android.jar to begin with. --- sdk/jme3-android/src/com/jme3/gde/android/mobile-targets.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sdk/jme3-android/src/com/jme3/gde/android/mobile-targets.xml b/sdk/jme3-android/src/com/jme3/gde/android/mobile-targets.xml index d57833296..2a302ee57 100644 --- a/sdk/jme3-android/src/com/jme3/gde/android/mobile-targets.xml +++ b/sdk/jme3-android/src/com/jme3/gde/android/mobile-targets.xml @@ -68,6 +68,8 @@ + + From d00c8a109f125892bfbaae6aa1d3f172051907d4 Mon Sep 17 00:00:00 2001 From: iwgeric Date: Thu, 2 Apr 2015 23:50:37 -0400 Subject: [PATCH 41/47] SDK: Switch android projects to use an Android Fragment --- .../com/jme3/gde/android/AndroidSdkTool.java | 139 ++++++++++++++++-- 1 file changed, 128 insertions(+), 11 deletions(-) diff --git a/sdk/jme3-android/src/com/jme3/gde/android/AndroidSdkTool.java b/sdk/jme3-android/src/com/jme3/gde/android/AndroidSdkTool.java index 066265e74..21340ab6e 100644 --- a/sdk/jme3-android/src/com/jme3/gde/android/AndroidSdkTool.java +++ b/sdk/jme3-android/src/com/jme3/gde/android/AndroidSdkTool.java @@ -243,6 +243,7 @@ public class AndroidSdkTool { } updateAndroidManifest(project); updateAndroidApplicationName(project, name); + updateAndroidLayout(project, packag); } public static void updateProject(Project project, String target, String name) { @@ -411,17 +412,79 @@ public class AndroidSdkTool { } } + private static void updateAndroidLayout(Project project, String packag) { + FileObject layout = project.getProjectDirectory().getFileObject("mobile/res/layout/main.xml"); + if (layout == null) { + Logger.getLogger(AndroidSdkTool.class.getName()).log(Level.WARNING, "Cannot find layout"); + return; + } + InputStream in = null; + FileLock lock = null; + OutputStream out = null; + try { + in = layout.getInputStream(); + Document configuration = XMLUtil.parse(new InputSource(in), false, false, null, null); + in.close(); + in = null; + + Element textViewElement = XmlHelper.findChildElement(configuration.getDocumentElement(), "TextView"); + + Element fragmentElement = configuration.createElement("fragment"); + fragmentElement.setAttribute("android:name", packag+".MainActivity$JmeFragment"); + fragmentElement.setAttribute("android:id", "@+id/jmeFragment"); + fragmentElement.setAttribute("android:layout_width", "match_parent"); + fragmentElement.setAttribute("android:layout_height", "match_parent"); + + if (textViewElement == null) { + configuration.getDocumentElement().appendChild(fragmentElement); + } else { + configuration.getDocumentElement().replaceChild(fragmentElement, textViewElement); + } + + lock = layout.lock(); + out = layout.getOutputStream(lock); + XMLUtil.write(configuration, out, "UTF-8"); + out.close(); + out = null; + lock.releaseLock(); + lock = null; + + } catch (SAXException ex) { + Exceptions.printStackTrace(ex); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } finally { + if (lock != null) { + lock.releaseLock(); + } + try { + if (in != null) { + in.close(); + } + if (out != null) { + out.close(); + } + } catch (IOException ex1) { + Exceptions.printStackTrace(ex1); + } + } + } + private static String mainActivityString(String mainClass, String packag) { String str = "package " + packag + ";\n" + " \n" - + "import android.content.pm.ActivityInfo;\n" - + "import com.jme3.app.AndroidHarness;\n" + + "import com.jme3.app.DefaultAndroidProfiler;\n" + + "import android.app.Activity;\n" + + "import android.app.FragmentManager;\n" + + "import android.os.Bundle;\n" + + "import android.view.Window;\n" + + "import android.view.WindowManager;\n" + + "import com.jme3.app.AndroidHarnessFragment;\n" + "import java.util.logging.Level;\n" + "import java.util.logging.LogManager;\n" + " \n" - + "public class MainActivity extends AndroidHarness{\n" - + " \n" + + "public class MainActivity extends Activity {\n" + " /*\n" + " * Note that you can ignore the errors displayed in this file,\n" + " * the android project will build regardless.\n" @@ -430,18 +493,72 @@ public class AndroidSdkTool { + " */\n" + " \n" + " public MainActivity(){\n" - + " // Set the application class to run\n" - + " appClass = \"" + mainClass + "\";\n" - + " // Exit Dialog title & message\n" - + " exitDialogTitle = \"Exit?\";\n" - + " exitDialogMessage = \"Press Yes\";\n" - + " // Enable MouseEvents being generated from TouchEvents (default = true)\n" - + " mouseEventsEnabled = true;\n" + " // Set the default logging level (default=Level.INFO, Level.ALL=All Debug Info)\n" + " LogManager.getLogManager().getLogger(\"\").setLevel(Level.INFO);\n" + " }\n" + " \n" + + " @Override\n" + + " protected void onCreate(Bundle savedInstanceState) {\n" + + " super.onCreate(savedInstanceState);\n" + + " // Set window fullscreen and remove title bar\n" + + " requestWindowFeature(Window.FEATURE_NO_TITLE);\n" + + " getWindow().setFlags(\n" + + " WindowManager.LayoutParams.FLAG_FULLSCREEN,\n" + + " WindowManager.LayoutParams.FLAG_FULLSCREEN);\n" + + " setContentView(R.layout.main);\n" + + " \n" + + " // find the fragment\n" + + " FragmentManager fm = getFragmentManager();\n" + + " AndroidHarnessFragment jmeFragment =\n" + + " (AndroidHarnessFragment) fm.findFragmentById(R.id.jmeFragment);\n" + + " \n" + + " // uncomment the next line to add the default android profiler to the project\n" + + " //jmeFragment.getJmeApplication().setAppProfiler(new DefaultAndroidProfiler());\n" + + " }\n" + + " \n" + + " \n" + + " public static class JmeFragment extends AndroidHarnessFragment {\n" + + " public JmeFragment() {\n" + + " // Set main project class (fully qualified path)\n" + + " appClass = \"" + mainClass + "\";\n" + + " \n" + + " // Set the desired EGL configuration\n" + + " eglBitsPerPixel = 24;\n" + + " eglAlphaBits = 0;\n" + + " eglDepthBits = 16;\n" + + " eglSamples = 0;\n" + + " eglStencilBits = 0;\n" + + " \n" + + " // Set the maximum framerate\n" + + " // (default = -1 for unlimited)\n" + + " frameRate = -1;\n" + + " \n" + + " // Set the maximum resolution dimension\n" + + " // (the smaller side, height or width, is set automatically\n" + + " // to maintain the original device screen aspect ratio)\n" + + " // (default = -1 to match device screen resolution)\n" + + " maxResolutionDimension = -1;\n" + + " \n" + + " // Set input configuration settings\n" + + " joystickEventsEnabled = false;\n" + + " keyEventsEnabled = true;\n" + + " mouseEventsEnabled = true;\n" + + " \n" + + " // Set application exit settings\n" + + " finishOnAppStop = true;\n" + + " handleExitHook = true;\n" + + " exitDialogTitle = \"Do you want to exit?\";\n" + + " exitDialogMessage = \"Use your home key to bring this app into the background or exit to terminate it.\";\n" + + " \n" + + " // Set splash screen resource id, if used\n" + + " // (default = 0, no splash screen)\n" + + " // For example, if the image file name is \"splash\"...\n" + + " // splashPicID = R.drawable.splash;\n" + + " splashPicID = 0;\n" + + " }\n" + + " }\n" + "}\n"; + return str; } From 4102e91456df871530613e647474155fc9a5ea2c Mon Sep 17 00:00:00 2001 From: iwgeric Date: Thu, 2 Apr 2015 23:51:26 -0400 Subject: [PATCH 42/47] Android: remove unused properties in AndroidHarnessFragment --- .../java/com/jme3/app/AndroidHarnessFragment.java | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/jme3-android/src/main/java/com/jme3/app/AndroidHarnessFragment.java b/jme3-android/src/main/java/com/jme3/app/AndroidHarnessFragment.java index 1b205d6dd..5673c8609 100644 --- a/jme3-android/src/main/java/com/jme3/app/AndroidHarnessFragment.java +++ b/jme3-android/src/main/java/com/jme3/app/AndroidHarnessFragment.java @@ -195,19 +195,6 @@ public class AndroidHarnessFragment extends Fragment implements */ protected String exitDialogMessage = "Use your home key to bring this app into the background or exit to terminate it."; - /** - * Set the screen window mode. If screenFullSize is true, then the - * notification bar and title bar are removed and the screen covers the - * entire display. If screenFullSize is false, then the notification bar - * remains visible if screenShowTitle is true while screenFullScreen is - * false, then the title bar is also displayed under the notification bar. - */ - protected boolean screenFullScreen = true; - /** - * if screenShowTitle is true while screenFullScreen is false, then the - * title bar is also displayed under the notification bar - */ - protected boolean screenShowTitle = true; /** * Splash Screen picture Resource ID. If a Splash Screen is desired, set * splashPicID to the value of the Resource ID (i.e. R.drawable.picname). If From 5b56f1e513a9de16cf14e2f5b446c903588b028f Mon Sep 17 00:00:00 2001 From: Julien Gouesse Date: Sat, 4 Apr 2015 16:37:36 +0200 Subject: [PATCH 43/47] Updates the JogAmp backend, uses JOGL 2.3.1 --- jme3-jogl/build.gradle | 6 ++-- .../com/jme3/input/jogl/NewtMouseInput.java | 10 +++---- .../com/jme3/renderer/jogl/JoglRenderer.java | 22 +++++++-------- .../com/jme3/renderer/jogl/TextureUtil.java | 19 +++++++------ .../jme3/system/jogl/JoglAbstractDisplay.java | 28 +++++++++---------- .../java/com/jme3/system/jogl/JoglCanvas.java | 2 +- .../com/jme3/system/jogl/JoglContext.java | 6 ++-- .../com/jme3/system/jogl/JoglDisplay.java | 2 +- .../system/jogl/JoglNewtAbstractDisplay.java | 26 ++++++++--------- .../com/jme3/system/jogl/JoglNewtCanvas.java | 2 +- .../com/jme3/system/jogl/JoglNewtDisplay.java | 4 +-- .../jme3/system/jogl/JoglOffscreenBuffer.java | 12 ++++---- 12 files changed, 71 insertions(+), 68 deletions(-) diff --git a/jme3-jogl/build.gradle b/jme3-jogl/build.gradle index 135656ee6..e82139729 100644 --- a/jme3-jogl/build.gradle +++ b/jme3-jogl/build.gradle @@ -5,7 +5,7 @@ if (!hasProperty('mainClass')) { dependencies { compile project(':jme3-core') compile project(':jme3-desktop') - compile 'org.jogamp.gluegen:gluegen-rt-main:2.2.0' - compile 'org.jogamp.jogl:jogl-all-main:2.2.0' - compile 'org.jogamp.joal:joal-main:2.2.0' + compile 'org.jogamp.gluegen:gluegen-rt-main:2.3.1' + compile 'org.jogamp.jogl:jogl-all-main:2.3.1' + compile 'org.jogamp.joal:joal-main:2.3.1' } diff --git a/jme3-jogl/src/main/java/com/jme3/input/jogl/NewtMouseInput.java b/jme3-jogl/src/main/java/com/jme3/input/jogl/NewtMouseInput.java index d50017ccc..773f62b8a 100644 --- a/jme3-jogl/src/main/java/com/jme3/input/jogl/NewtMouseInput.java +++ b/jme3-jogl/src/main/java/com/jme3/input/jogl/NewtMouseInput.java @@ -45,11 +45,11 @@ import com.jogamp.newt.opengl.GLWindow; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.logging.Logger; -import javax.media.nativewindow.util.Dimension; -import javax.media.nativewindow.util.DimensionImmutable; -import javax.media.nativewindow.util.PixelFormat; -import javax.media.nativewindow.util.PixelRectangle; -import javax.media.nativewindow.util.Point; +import com.jogamp.nativewindow.util.Dimension; +import com.jogamp.nativewindow.util.DimensionImmutable; +import com.jogamp.nativewindow.util.PixelFormat; +import com.jogamp.nativewindow.util.PixelRectangle; +import com.jogamp.nativewindow.util.Point; public class NewtMouseInput implements MouseInput, MouseListener { diff --git a/jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglRenderer.java b/jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglRenderer.java index 85e5c7102..111719265 100644 --- a/jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglRenderer.java +++ b/jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglRenderer.java @@ -70,15 +70,15 @@ import java.util.EnumSet; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; -import javax.media.nativewindow.NativeWindowFactory; -import javax.media.opengl.GL; -import javax.media.opengl.GL2; -import javax.media.opengl.GL2ES1; -import javax.media.opengl.GL2ES2; -import javax.media.opengl.GL2ES3; -import javax.media.opengl.GL2GL3; -import javax.media.opengl.GL3; -import javax.media.opengl.GLContext; +import com.jogamp.nativewindow.NativeWindowFactory; +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GL2; +import com.jogamp.opengl.GL2ES1; +import com.jogamp.opengl.GL2ES2; +import com.jogamp.opengl.GL2ES3; +import com.jogamp.opengl.GL2GL3; +import com.jogamp.opengl.GL3; +import com.jogamp.opengl.GLContext; import jme3tools.converters.MipMapGenerator; import jme3tools.shader.ShaderDebug; @@ -1800,7 +1800,7 @@ public class JoglRenderer implements Renderer { if (samples > 1) { return GL3.GL_TEXTURE_2D_MULTISAMPLE_ARRAY; } else { - return GL.GL_TEXTURE_2D_ARRAY; + return GL2ES3.GL_TEXTURE_2D_ARRAY; } case ThreeDimensional: return GL2ES2.GL_TEXTURE_3D; @@ -2014,7 +2014,7 @@ public class JoglRenderer implements Renderer { for (int i = 0; i < 6; i++) { TextureUtil.uploadTexture(img, GL.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, i, 0, linearizeSrgbImages); } - } else if (target == GL.GL_TEXTURE_2D_ARRAY) { + } else if (target == GL2ES3.GL_TEXTURE_2D_ARRAY) { if (!caps.contains(Caps.TextureArray)) { throw new RendererException("Texture arrays not supported by graphics hardware"); } diff --git a/jme3-jogl/src/main/java/com/jme3/renderer/jogl/TextureUtil.java b/jme3-jogl/src/main/java/com/jme3/renderer/jogl/TextureUtil.java index 9bdc0ca2d..8f3c5b156 100644 --- a/jme3-jogl/src/main/java/com/jme3/renderer/jogl/TextureUtil.java +++ b/jme3-jogl/src/main/java/com/jme3/renderer/jogl/TextureUtil.java @@ -36,14 +36,17 @@ import com.jme3.renderer.RendererException; import com.jme3.texture.Image; import com.jme3.texture.Image.Format; import com.jme3.texture.image.ColorSpace; + import java.nio.ByteBuffer; import java.util.logging.Level; import java.util.logging.Logger; -import javax.media.opengl.GL; -import javax.media.opengl.GL2; -import javax.media.opengl.GL2ES2; -import javax.media.opengl.GL2GL3; -import javax.media.opengl.GLContext; + +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GL2; +import com.jogamp.opengl.GL2ES2; +import com.jogamp.opengl.GL2ES3; +import com.jogamp.opengl.GL2GL3; +import com.jogamp.opengl.GLContext; public class TextureUtil { @@ -124,9 +127,9 @@ public class TextureUtil { setFormat(Format.RGB32F, GL.GL_RGB32F, GL.GL_RGB, GL.GL_FLOAT, false); // Special RGB formats - setFormat(Format.RGB111110F, GL.GL_R11F_G11F_B10F, GL.GL_RGB, GL.GL_UNSIGNED_INT_10F_11F_11F_REV, false); + setFormat(Format.RGB111110F, GL2ES3.GL_R11F_G11F_B10F, GL.GL_RGB, GL.GL_UNSIGNED_INT_10F_11F_11F_REV, false); setFormat(Format.RGB9E5, GL2GL3.GL_RGB9_E5, GL.GL_RGB, GL2GL3.GL_UNSIGNED_INT_5_9_9_9_REV, false); - setFormat(Format.RGB16F_to_RGB111110F, GL.GL_R11F_G11F_B10F, GL.GL_RGB, GL.GL_HALF_FLOAT, false); + setFormat(Format.RGB16F_to_RGB111110F, GL2ES3.GL_R11F_G11F_B10F, GL.GL_RGB, GL.GL_HALF_FLOAT, false); setFormat(Format.RGB16F_to_RGB9E5, GL2.GL_RGB9_E5, GL.GL_RGB, GL.GL_HALF_FLOAT, false); // RGBA formats @@ -346,7 +349,7 @@ public class TextureUtil { glFmt.format, glFmt.dataType, data); - }else if (target == GL.GL_TEXTURE_2D_ARRAY){ + }else if (target == GL2ES3.GL_TEXTURE_2D_ARRAY){ // prepare data for 2D array // or upload slice if (index == -1){ diff --git a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglAbstractDisplay.java b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglAbstractDisplay.java index 8c6ec6e55..a7f7fbfd7 100644 --- a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglAbstractDisplay.java +++ b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglAbstractDisplay.java @@ -45,20 +45,20 @@ import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Logger; -import javax.media.opengl.DebugGL2; -import javax.media.opengl.DebugGL3; -import javax.media.opengl.DebugGL3bc; -import javax.media.opengl.DebugGL4; -import javax.media.opengl.DebugGL4bc; -import javax.media.opengl.DebugGLES1; -import javax.media.opengl.DebugGLES2; -import javax.media.opengl.GL; -import javax.media.opengl.GLAutoDrawable; -import javax.media.opengl.GLCapabilities; -import javax.media.opengl.GLEventListener; -import javax.media.opengl.GLProfile; -import javax.media.opengl.GLRunnable; -import javax.media.opengl.awt.GLCanvas; +import com.jogamp.opengl.DebugGL2; +import com.jogamp.opengl.DebugGL3; +import com.jogamp.opengl.DebugGL3bc; +import com.jogamp.opengl.DebugGL4; +import com.jogamp.opengl.DebugGL4bc; +import com.jogamp.opengl.DebugGLES1; +import com.jogamp.opengl.DebugGLES2; +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLCapabilities; +import com.jogamp.opengl.GLEventListener; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.GLRunnable; +import com.jogamp.opengl.awt.GLCanvas; public abstract class JoglAbstractDisplay extends JoglContext implements GLEventListener { diff --git a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglCanvas.java b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglCanvas.java index c4e97570e..9a409b85e 100644 --- a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglCanvas.java +++ b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglCanvas.java @@ -35,7 +35,7 @@ package com.jme3.system.jogl; import com.jme3.system.JmeCanvasContext; import java.awt.Canvas; import java.util.logging.Logger; -import javax.media.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLAutoDrawable; public class JoglCanvas extends JoglAbstractDisplay implements JmeCanvasContext { diff --git a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglContext.java b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglContext.java index 8861904b8..5d687af8d 100644 --- a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglContext.java +++ b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglContext.java @@ -47,9 +47,9 @@ import java.nio.IntBuffer; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.logging.Logger; -import javax.media.opengl.GL; -import javax.media.opengl.GL2GL3; -import javax.media.opengl.GLContext; +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GL2GL3; +import com.jogamp.opengl.GLContext; public abstract class JoglContext implements JmeContext { diff --git a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglDisplay.java b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglDisplay.java index 363ccd096..3bac0ab53 100644 --- a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglDisplay.java +++ b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglDisplay.java @@ -45,7 +45,7 @@ import java.lang.reflect.InvocationTargetException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.logging.Logger; -import javax.media.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLAutoDrawable; import javax.swing.JFrame; import javax.swing.SwingUtilities; diff --git a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglNewtAbstractDisplay.java b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglNewtAbstractDisplay.java index 4899c9c39..cb75d5d37 100644 --- a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglNewtAbstractDisplay.java +++ b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglNewtAbstractDisplay.java @@ -44,19 +44,19 @@ import com.jogamp.opengl.util.AnimatorBase; import com.jogamp.opengl.util.FPSAnimator; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Logger; -import javax.media.opengl.DebugGL2; -import javax.media.opengl.DebugGL3; -import javax.media.opengl.DebugGL3bc; -import javax.media.opengl.DebugGL4; -import javax.media.opengl.DebugGL4bc; -import javax.media.opengl.DebugGLES1; -import javax.media.opengl.DebugGLES2; -import javax.media.opengl.GL; -import javax.media.opengl.GLAutoDrawable; -import javax.media.opengl.GLCapabilities; -import javax.media.opengl.GLEventListener; -import javax.media.opengl.GLProfile; -import javax.media.opengl.GLRunnable; +import com.jogamp.opengl.DebugGL2; +import com.jogamp.opengl.DebugGL3; +import com.jogamp.opengl.DebugGL3bc; +import com.jogamp.opengl.DebugGL4; +import com.jogamp.opengl.DebugGL4bc; +import com.jogamp.opengl.DebugGLES1; +import com.jogamp.opengl.DebugGLES2; +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLCapabilities; +import com.jogamp.opengl.GLEventListener; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.GLRunnable; public abstract class JoglNewtAbstractDisplay extends JoglContext implements GLEventListener { diff --git a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglNewtCanvas.java b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglNewtCanvas.java index e4f46d8fb..3ed501580 100644 --- a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglNewtCanvas.java +++ b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglNewtCanvas.java @@ -35,7 +35,7 @@ package com.jme3.system.jogl; import com.jme3.system.JmeCanvasContext; import com.jogamp.newt.awt.NewtCanvasAWT; import java.util.logging.Logger; -import javax.media.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLAutoDrawable; public class JoglNewtCanvas extends JoglNewtAbstractDisplay implements JmeCanvasContext { diff --git a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglNewtDisplay.java b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglNewtDisplay.java index 011002aff..84a99e8d2 100644 --- a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglNewtDisplay.java +++ b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglNewtDisplay.java @@ -42,8 +42,8 @@ import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.logging.Logger; -import javax.media.nativewindow.util.Dimension; -import javax.media.opengl.GLAutoDrawable; +import com.jogamp.nativewindow.util.Dimension; +import com.jogamp.opengl.GLAutoDrawable; public class JoglNewtDisplay extends JoglNewtAbstractDisplay { diff --git a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglOffscreenBuffer.java b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglOffscreenBuffer.java index e2ad1f79a..cd2b84f73 100644 --- a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglOffscreenBuffer.java +++ b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglOffscreenBuffer.java @@ -41,12 +41,12 @@ import com.jogamp.newt.NewtVersion; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.logging.Logger; -import javax.media.opengl.GL; -import javax.media.opengl.GLCapabilities; -import javax.media.opengl.GLContext; -import javax.media.opengl.GLDrawableFactory; -import javax.media.opengl.GLOffscreenAutoDrawable; -import javax.media.opengl.GLProfile; +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GLCapabilities; +import com.jogamp.opengl.GLContext; +import com.jogamp.opengl.GLDrawableFactory; +import com.jogamp.opengl.GLOffscreenAutoDrawable; +import com.jogamp.opengl.GLProfile; public class JoglOffscreenBuffer extends JoglContext implements Runnable { From 9f32bcf7bb116afcfcc8bcacd3bdfbdc18fb2bf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20B=C3=B6rnert?= Date: Tue, 7 Apr 2015 01:26:13 +0200 Subject: [PATCH 44/47] Hack fix for blenderloader. The optimisation disabled would result in null TextureKeys. -> This would then result in textures being embedded into the j3o file, seriously bloating the assets. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kai Börnert --- .../scene/plugins/blender/textures/TextureHelper.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/TextureHelper.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/TextureHelper.java index f6ed89ce7..f1c1c64fc 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/TextureHelper.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/TextureHelper.java @@ -232,7 +232,7 @@ public class TextureHelper extends AbstractBlenderHelper { LOGGER.log(Level.FINE, "Fetching texture with OMA = {0}", imageStructure.getOldMemoryAddress()); Texture result = null; Image im = (Image) blenderContext.getLoadedFeature(imageStructure.getOldMemoryAddress(), LoadedDataType.FEATURE); - if (im == null) { + // if (im == null) { HACK force reaload always, as constructor in else case is destroying the TextureKeys! if ("ID".equals(imageStructure.getType())) { LOGGER.fine("Loading texture from external blend file."); result = (Texture) this.loadLibrary(imageStructure); @@ -253,9 +253,9 @@ public class TextureHelper extends AbstractBlenderHelper { result = new Texture2D(new ImageLoader().loadImage(blenderContext.getInputStream(), dataFileBlock.getBlockPosition(), true)); } } - } else { - result = new Texture2D(im); - } + //} else { + // result = new Texture2D(im); + // } if (result != null) {// render result is not being loaded blenderContext.addLoadedFeatures(imageStructure.getOldMemoryAddress(), LoadedDataType.STRUCTURE, imageStructure); From 47e9b9ba16adc7d0cebf1f453936f9ae704c13cf Mon Sep 17 00:00:00 2001 From: iwgeric Date: Tue, 7 Apr 2015 17:53:54 -0400 Subject: [PATCH 45/47] Android: Remove unused property to track if joysticks are enabled. --- .../input/android/AndroidInputHandler.java | 528 +++++++++--------- 1 file changed, 263 insertions(+), 265 deletions(-) diff --git a/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler.java b/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler.java index 592baecaf..202907316 100644 --- a/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler.java +++ b/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler.java @@ -1,265 +1,263 @@ -/* - * 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.input.android; - -import android.opengl.GLSurfaceView; -import android.os.Build; -import android.view.View; -import com.jme3.input.RawInputListener; -import com.jme3.input.TouchInput; -import com.jme3.input.event.InputEvent; -import com.jme3.input.event.KeyInputEvent; -import com.jme3.input.event.MouseButtonEvent; -import com.jme3.input.event.MouseMotionEvent; -import com.jme3.input.event.TouchEvent; -import com.jme3.system.AppSettings; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * AndroidInput is the main class that connects the Android system - * inputs to jME. It serves as the manager that gathers inputs from the various - * Android input methods and provides them to jME's InputManager. - * - * @author iwgeric - */ -public class AndroidInputHandler implements TouchInput { - private static final Logger logger = Logger.getLogger(AndroidInputHandler.class.getName()); - - // Custom settings - private boolean mouseEventsEnabled = true; - private boolean mouseEventsInvertX = false; - private boolean mouseEventsInvertY = false; - private boolean keyboardEventsEnabled = false; - private boolean joystickEventsEnabled = false; - private boolean dontSendHistory = false; - - - // Internal - private GLSurfaceView view; - private AndroidTouchHandler touchHandler; - private AndroidKeyHandler keyHandler; - private AndroidGestureHandler gestureHandler; - private boolean initialized = false; - private RawInputListener listener = null; - private ConcurrentLinkedQueue inputEventQueue = new ConcurrentLinkedQueue(); - private final static int MAX_TOUCH_EVENTS = 1024; - private final TouchEventPool touchEventPool = new TouchEventPool(MAX_TOUCH_EVENTS); - private float scaleX = 1f; - private float scaleY = 1f; - - - public AndroidInputHandler() { - int buildVersion = Build.VERSION.SDK_INT; - logger.log(Level.INFO, "Android Build Version: {0}", buildVersion); - if (buildVersion >= 14) { - // add support for onHover and GenericMotionEvent (ie. gamepads) - gestureHandler = new AndroidGestureHandler(this); - touchHandler = new AndroidTouchHandler14(this, gestureHandler); - keyHandler = new AndroidKeyHandler(this); - } else if (buildVersion >= 8){ - gestureHandler = new AndroidGestureHandler(this); - touchHandler = new AndroidTouchHandler(this, gestureHandler); - keyHandler = new AndroidKeyHandler(this); - } - } - - public AndroidInputHandler(AndroidTouchHandler touchInput, - AndroidKeyHandler keyInput, AndroidGestureHandler gestureHandler) { - this.touchHandler = touchInput; - this.keyHandler = keyInput; - this.gestureHandler = gestureHandler; - } - - public void setView(View view) { - if (touchHandler != null) { - touchHandler.setView(view); - } - if (keyHandler != null) { - keyHandler.setView(view); - } - if (gestureHandler != null) { - gestureHandler.setView(view); - } - this.view = (GLSurfaceView)view; - } - - public View getView() { - return view; - } - - public float invertX(float origX) { - return getJmeX(view.getWidth()) - origX; - } - - public float invertY(float origY) { - return getJmeY(view.getHeight()) - origY; - } - - public float getJmeX(float origX) { - return origX * scaleX; - } - - public float getJmeY(float origY) { - return origY * scaleY; - } - - public void loadSettings(AppSettings settings) { - keyboardEventsEnabled = settings.isEmulateKeyboard(); - mouseEventsEnabled = settings.isEmulateMouse(); - mouseEventsInvertX = settings.isEmulateMouseFlipX(); - mouseEventsInvertY = settings.isEmulateMouseFlipY(); - joystickEventsEnabled = settings.useJoysticks(); - - // view width and height are 0 until the view is displayed on the screen - if (view.getWidth() != 0 && view.getHeight() != 0) { - scaleX = (float)settings.getWidth() / (float)view.getWidth(); - scaleY = (float)settings.getHeight() / (float)view.getHeight(); - } - logger.log(Level.FINE, "Setting input scaling, scaleX: {0}, scaleY: {1}", - new Object[]{scaleX, scaleY}); - - } - - // ----------------------------------------- - // JME3 Input interface - @Override - public void initialize() { - touchEventPool.initialize(); - if (touchHandler != null) { - touchHandler.initialize(); - } - if (keyHandler != null) { - keyHandler.initialize(); - } - if (gestureHandler != null) { - gestureHandler.initialize(); - } - - initialized = true; - } - - @Override - public void destroy() { - initialized = false; - - touchEventPool.destroy(); - if (touchHandler != null) { - touchHandler.destroy(); - } - if (keyHandler != null) { - keyHandler.destroy(); - } - if (gestureHandler != null) { - gestureHandler.destroy(); - } - - setView(null); - } - - @Override - public boolean isInitialized() { - return initialized; - } - - @Override - public void setInputListener(RawInputListener listener) { - this.listener = listener; - } - - @Override - public long getInputTimeNanos() { - return System.nanoTime(); - } - - public void update() { - if (listener != null) { - InputEvent inputEvent; - - while ((inputEvent = inputEventQueue.poll()) != null) { - if (inputEvent instanceof TouchEvent) { - listener.onTouchEvent((TouchEvent)inputEvent); - } else if (inputEvent instanceof MouseButtonEvent) { - listener.onMouseButtonEvent((MouseButtonEvent)inputEvent); - } else if (inputEvent instanceof MouseMotionEvent) { - listener.onMouseMotionEvent((MouseMotionEvent)inputEvent); - } else if (inputEvent instanceof KeyInputEvent) { - listener.onKeyEvent((KeyInputEvent)inputEvent); - } - } - } - } - - // ----------------------------------------- - - public TouchEvent getFreeTouchEvent() { - return touchEventPool.getNextFreeEvent(); - } - - public void addEvent(InputEvent event) { - inputEventQueue.add(event); - if (event instanceof TouchEvent) { - touchEventPool.storeEvent((TouchEvent)event); - } - } - - public void setSimulateMouse(boolean simulate) { - this.mouseEventsEnabled = simulate; - } - - public boolean isSimulateMouse() { - return mouseEventsEnabled; - } - - public boolean isMouseEventsInvertX() { - return mouseEventsInvertX; - } - - public boolean isMouseEventsInvertY() { - return mouseEventsInvertY; - } - - public void setSimulateKeyboard(boolean simulate) { - this.keyboardEventsEnabled = simulate; - } - - public boolean isSimulateKeyboard() { - return keyboardEventsEnabled; - } - - public void setOmitHistoricEvents(boolean dontSendHistory) { - this.dontSendHistory = dontSendHistory; - } - -} +/* + * 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.input.android; + +import android.opengl.GLSurfaceView; +import android.os.Build; +import android.view.View; +import com.jme3.input.RawInputListener; +import com.jme3.input.TouchInput; +import com.jme3.input.event.InputEvent; +import com.jme3.input.event.KeyInputEvent; +import com.jme3.input.event.MouseButtonEvent; +import com.jme3.input.event.MouseMotionEvent; +import com.jme3.input.event.TouchEvent; +import com.jme3.system.AppSettings; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * AndroidInput is the main class that connects the Android system + * inputs to jME. It serves as the manager that gathers inputs from the various + * Android input methods and provides them to jME's InputManager. + * + * @author iwgeric + */ +public class AndroidInputHandler implements TouchInput { + private static final Logger logger = Logger.getLogger(AndroidInputHandler.class.getName()); + + // Custom settings + private boolean mouseEventsEnabled = true; + private boolean mouseEventsInvertX = false; + private boolean mouseEventsInvertY = false; + private boolean keyboardEventsEnabled = false; + private boolean dontSendHistory = false; + + + // Internal + private GLSurfaceView view; + private AndroidTouchHandler touchHandler; + private AndroidKeyHandler keyHandler; + private AndroidGestureHandler gestureHandler; + private boolean initialized = false; + private RawInputListener listener = null; + private ConcurrentLinkedQueue inputEventQueue = new ConcurrentLinkedQueue(); + private final static int MAX_TOUCH_EVENTS = 1024; + private final TouchEventPool touchEventPool = new TouchEventPool(MAX_TOUCH_EVENTS); + private float scaleX = 1f; + private float scaleY = 1f; + + + public AndroidInputHandler() { + int buildVersion = Build.VERSION.SDK_INT; + logger.log(Level.INFO, "Android Build Version: {0}", buildVersion); + if (buildVersion >= 14) { + // add support for onHover and GenericMotionEvent (ie. gamepads) + gestureHandler = new AndroidGestureHandler(this); + touchHandler = new AndroidTouchHandler14(this, gestureHandler); + keyHandler = new AndroidKeyHandler(this); + } else if (buildVersion >= 8){ + gestureHandler = new AndroidGestureHandler(this); + touchHandler = new AndroidTouchHandler(this, gestureHandler); + keyHandler = new AndroidKeyHandler(this); + } + } + + public AndroidInputHandler(AndroidTouchHandler touchInput, + AndroidKeyHandler keyInput, AndroidGestureHandler gestureHandler) { + this.touchHandler = touchInput; + this.keyHandler = keyInput; + this.gestureHandler = gestureHandler; + } + + public void setView(View view) { + if (touchHandler != null) { + touchHandler.setView(view); + } + if (keyHandler != null) { + keyHandler.setView(view); + } + if (gestureHandler != null) { + gestureHandler.setView(view); + } + this.view = (GLSurfaceView)view; + } + + public View getView() { + return view; + } + + public float invertX(float origX) { + return getJmeX(view.getWidth()) - origX; + } + + public float invertY(float origY) { + return getJmeY(view.getHeight()) - origY; + } + + public float getJmeX(float origX) { + return origX * scaleX; + } + + public float getJmeY(float origY) { + return origY * scaleY; + } + + public void loadSettings(AppSettings settings) { + keyboardEventsEnabled = settings.isEmulateKeyboard(); + mouseEventsEnabled = settings.isEmulateMouse(); + mouseEventsInvertX = settings.isEmulateMouseFlipX(); + mouseEventsInvertY = settings.isEmulateMouseFlipY(); + + // view width and height are 0 until the view is displayed on the screen + if (view.getWidth() != 0 && view.getHeight() != 0) { + scaleX = (float)settings.getWidth() / (float)view.getWidth(); + scaleY = (float)settings.getHeight() / (float)view.getHeight(); + } + logger.log(Level.FINE, "Setting input scaling, scaleX: {0}, scaleY: {1}", + new Object[]{scaleX, scaleY}); + + } + + // ----------------------------------------- + // JME3 Input interface + @Override + public void initialize() { + touchEventPool.initialize(); + if (touchHandler != null) { + touchHandler.initialize(); + } + if (keyHandler != null) { + keyHandler.initialize(); + } + if (gestureHandler != null) { + gestureHandler.initialize(); + } + + initialized = true; + } + + @Override + public void destroy() { + initialized = false; + + touchEventPool.destroy(); + if (touchHandler != null) { + touchHandler.destroy(); + } + if (keyHandler != null) { + keyHandler.destroy(); + } + if (gestureHandler != null) { + gestureHandler.destroy(); + } + + setView(null); + } + + @Override + public boolean isInitialized() { + return initialized; + } + + @Override + public void setInputListener(RawInputListener listener) { + this.listener = listener; + } + + @Override + public long getInputTimeNanos() { + return System.nanoTime(); + } + + public void update() { + if (listener != null) { + InputEvent inputEvent; + + while ((inputEvent = inputEventQueue.poll()) != null) { + if (inputEvent instanceof TouchEvent) { + listener.onTouchEvent((TouchEvent)inputEvent); + } else if (inputEvent instanceof MouseButtonEvent) { + listener.onMouseButtonEvent((MouseButtonEvent)inputEvent); + } else if (inputEvent instanceof MouseMotionEvent) { + listener.onMouseMotionEvent((MouseMotionEvent)inputEvent); + } else if (inputEvent instanceof KeyInputEvent) { + listener.onKeyEvent((KeyInputEvent)inputEvent); + } + } + } + } + + // ----------------------------------------- + + public TouchEvent getFreeTouchEvent() { + return touchEventPool.getNextFreeEvent(); + } + + public void addEvent(InputEvent event) { + inputEventQueue.add(event); + if (event instanceof TouchEvent) { + touchEventPool.storeEvent((TouchEvent)event); + } + } + + public void setSimulateMouse(boolean simulate) { + this.mouseEventsEnabled = simulate; + } + + public boolean isSimulateMouse() { + return mouseEventsEnabled; + } + + public boolean isMouseEventsInvertX() { + return mouseEventsInvertX; + } + + public boolean isMouseEventsInvertY() { + return mouseEventsInvertY; + } + + public void setSimulateKeyboard(boolean simulate) { + this.keyboardEventsEnabled = simulate; + } + + public boolean isSimulateKeyboard() { + return keyboardEventsEnabled; + } + + public void setOmitHistoricEvents(boolean dontSendHistory) { + this.dontSendHistory = dontSendHistory; + } + +} From 22d3f7f9f462c539ea03559962be8b12425bf84e Mon Sep 17 00:00:00 2001 From: iwgeric Date: Tue, 7 Apr 2015 18:35:48 -0400 Subject: [PATCH 46/47] Android: Refactor joystick support to prepare for upcoming gamepad support. --- .../input/android/AndroidJoyInputHandler.java | 257 ++++++++++++++++++ .../input/android/AndroidSensorJoyInput.java | 176 ++++-------- .../com/jme3/system/android/OGLESContext.java | 20 +- 3 files changed, 315 insertions(+), 138 deletions(-) create mode 100644 jme3-android/src/main/java/com/jme3/input/android/AndroidJoyInputHandler.java diff --git a/jme3-android/src/main/java/com/jme3/input/android/AndroidJoyInputHandler.java b/jme3-android/src/main/java/com/jme3/input/android/AndroidJoyInputHandler.java new file mode 100644 index 000000000..2c3a1d74e --- /dev/null +++ b/jme3-android/src/main/java/com/jme3/input/android/AndroidJoyInputHandler.java @@ -0,0 +1,257 @@ +/* + * 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.input.android; + +import android.content.Context; +import android.opengl.GLSurfaceView; +import android.os.Build; +import android.os.Vibrator; +import android.view.View; +import com.jme3.input.InputManager; +import com.jme3.input.JoyInput; +import com.jme3.input.Joystick; +import com.jme3.input.RawInputListener; +import com.jme3.input.event.InputEvent; +import com.jme3.input.event.JoyAxisEvent; +import com.jme3.input.event.JoyButtonEvent; +import com.jme3.system.AppSettings; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Main class that manages various joystick devices. Joysticks can be many forms + * including a simulated joystick to communicate the device orientation as well + * as physical gamepads.
+ * This class manages all the joysticks and feeds the inputs from each back + * to jME's InputManager. + * + * This handler also supports the joystick.rumble(rumbleAmount) method. In this + * case, when joystick.rumble(rumbleAmount) is called, the Android device will vibrate + * if the device has a built in vibrate motor. + * + * Because Andorid does not allow for the user to define the intensity of the + * vibration, the rumble amount (ie strength) is converted into vibration pulses + * The stronger the strength amount, the shorter the delay between pulses. If + * amount is 1, then the vibration stays on the whole time. If amount is 0.5, + * the vibration will a pulse of equal parts vibration and delay. + * To turn off vibration, set rumble amount to 0. + * + * MainActivity needs the following line to enable Joysticks on Android platforms + * joystickEventsEnabled = true; + * This is done to allow for battery conservation when sensor data or gamepads + * are not required by the application. + * + * To use the joystick rumble feature, the following line needs to be + * added to the Android Manifest File + * + * + * @author iwgeric + */ +public class AndroidJoyInputHandler implements JoyInput { + private static final Logger logger = Logger.getLogger(AndroidJoyInputHandler.class.getName()); + + private List joystickList = new ArrayList(); +// private boolean dontSendHistory = false; + + + // Internal + private GLSurfaceView view; + private boolean initialized = false; + private RawInputListener listener = null; + private ConcurrentLinkedQueue eventQueue = new ConcurrentLinkedQueue(); + private AndroidSensorJoyInput sensorJoyInput; + private Vibrator vibrator = null; + private boolean vibratorActive = false; + private long maxRumbleTime = 250; // 250ms + + public AndroidJoyInputHandler() { + int buildVersion = Build.VERSION.SDK_INT; + logger.log(Level.INFO, "Android Build Version: {0}", buildVersion); +// if (buildVersion >= 14) { +// touchHandler = new AndroidTouchHandler14(this); +// } else if (buildVersion >= 8){ +// touchHandler = new AndroidTouchHandler(this); +// } + sensorJoyInput = new AndroidSensorJoyInput(this); + } + + public void setView(GLSurfaceView view) { +// if (touchHandler != null) { +// touchHandler.setView(view); +// } + if (sensorJoyInput != null) { + sensorJoyInput.setView(view); + } + this.view = (GLSurfaceView)view; + + } + + public View getView() { + return view; + } + + public void loadSettings(AppSettings settings) { +// sensorEventsEnabled = settings.useSensors(); + } + + public void addEvent(InputEvent event) { + eventQueue.add(event); + } + + /** + * Pauses the joystick device listeners to save battery life if they are not needed. + * Used to pause when the activity pauses + */ + public void pauseJoysticks() { + if (sensorJoyInput != null) { + sensorJoyInput.pauseSensors(); + } + if (vibrator != null && vibratorActive) { + vibrator.cancel(); + } + + } + + /** + * Resumes the joystick device listeners. + * Used to resume when the activity comes to the top of the stack + */ + public void resumeJoysticks() { + if (sensorJoyInput != null) { + sensorJoyInput.resumeSensors(); + } + + } + + + + + + @Override + public void initialize() { +// if (sensorJoyInput != null) { +// sensorJoyInput.initialize(); +// } + // Get instance of Vibrator from current Context + vibrator = (Vibrator) view.getContext().getSystemService(Context.VIBRATOR_SERVICE); + if (vibrator == null) { + logger.log(Level.FINE, "Vibrator Service not found."); + } + initialized = true; + } + + @Override + public boolean isInitialized() { + return initialized; + } + + @Override + public void destroy() { + initialized = false; + + if (sensorJoyInput != null) { + sensorJoyInput.destroy(); + } + + setView(null); + } + + @Override + public void setInputListener(RawInputListener listener) { + this.listener = listener; + } + + @Override + public long getInputTimeNanos() { + return System.nanoTime(); + } + + @Override + public void setJoyRumble(int joyId, float amount) { + // convert amount to pulses since Android doesn't allow intensity + if (vibrator != null) { + final long rumbleOnDur = (long)(amount * maxRumbleTime); // ms to pulse vibration on + final long rumbleOffDur = maxRumbleTime - rumbleOnDur; // ms to delay between pulses + final long[] rumblePattern = { + 0, // start immediately + rumbleOnDur, // time to leave vibration on + rumbleOffDur // time to delay between vibrations + }; + final int rumbleRepeatFrom = 0; // index into rumble pattern to repeat from + + logger.log(Level.FINE, "Rumble amount: {0}, rumbleOnDur: {1}, rumbleOffDur: {2}", + new Object[]{amount, rumbleOnDur, rumbleOffDur}); + + if (rumbleOnDur > 0) { + vibrator.vibrate(rumblePattern, rumbleRepeatFrom); + vibratorActive = true; + } else { + vibrator.cancel(); + vibratorActive = false; + } + } + } + + @Override + public Joystick[] loadJoysticks(InputManager inputManager) { + joystickList.add(sensorJoyInput.loadJoystick(joystickList.size(), inputManager)); + + + return joystickList.toArray( new Joystick[joystickList.size()] ); + } + + @Override + public void update() { + if (sensorJoyInput != null) { + sensorJoyInput.update(); + } + + if (listener != null) { + InputEvent inputEvent; + + while ((inputEvent = eventQueue.poll()) != null) { + if (inputEvent instanceof JoyAxisEvent) { + listener.onJoyAxisEvent((JoyAxisEvent)inputEvent); + } else if (inputEvent instanceof JoyButtonEvent) { + listener.onJoyButtonEvent((JoyButtonEvent)inputEvent); + } + } + } + + } + + + +} diff --git a/jme3-android/src/main/java/com/jme3/input/android/AndroidSensorJoyInput.java b/jme3-android/src/main/java/com/jme3/input/android/AndroidSensorJoyInput.java index 034b068d8..823aa3d9d 100644 --- a/jme3-android/src/main/java/com/jme3/input/android/AndroidSensorJoyInput.java +++ b/jme3-android/src/main/java/com/jme3/input/android/AndroidSensorJoyInput.java @@ -37,7 +37,7 @@ import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; -import android.os.Vibrator; +import android.opengl.GLSurfaceView; import android.view.Surface; import android.view.WindowManager; import com.jme3.input.AbstractJoystick; @@ -47,10 +47,8 @@ import com.jme3.input.JoyInput; import com.jme3.input.Joystick; import com.jme3.input.JoystickAxis; import com.jme3.input.SensorJoystickAxis; -import com.jme3.input.RawInputListener; import com.jme3.input.event.JoyAxisEvent; import com.jme3.math.FastMath; -import com.jme3.system.android.JmeAndroidSystem; import com.jme3.util.IntMap; import com.jme3.util.IntMap.Entry; import java.util.ArrayList; @@ -63,7 +61,7 @@ import java.util.logging.Logger; * A single joystick is configured and includes data for all configured sensors * as seperate axes of the joystick. * - * Each axis is named accounting to the static strings in SensorJoystickAxis. + * Each axis is named according to the static strings in SensorJoystickAxis. * Refer to the strings defined in SensorJoystickAxis for a list of supported * sensors and their axis data. Each sensor type defined in SensorJoystickAxis * will be attempted to be configured. If the device does not support a particular @@ -72,46 +70,21 @@ import java.util.logging.Logger; * The joystick.getXAxis and getYAxis methods of the joystick are configured to * return the device orientation values in the device's X and Y directions. * - * This joystick also supports the joystick.rumble(rumbleAmount) method. In this - * case, when joystick.rumble(rumbleAmount) is called, the Android device will vibrate - * if the device has a built in vibrate motor. - * - * Because Andorid does not allow for the user to define the intensity of the - * vibration, the rumble amount (ie strength) is converted into vibration pulses - * The stronger the strength amount, the shorter the delay between pulses. If - * amount is 1, then the vibration stays on the whole time. If amount is 0.5, - * the vibration will a pulse of equal parts vibration and delay. - * To turn off vibration, set rumble amount to 0. - * - * MainActivity needs the following line to enable Joysticks on Android platforms - * joystickEventsEnabled = true; - * This is done to allow for battery conservation when sensor data is not required - * by the application. - * - * To use the joystick rumble feature, the following line needs to be - * added to the Android Manifest File - * - * * @author iwgeric */ -public class AndroidSensorJoyInput implements JoyInput, SensorEventListener { +public class AndroidSensorJoyInput implements SensorEventListener { private final static Logger logger = Logger.getLogger(AndroidSensorJoyInput.class.getName()); - private Context context = null; - private InputManager inputManager = null; + private AndroidJoyInputHandler joyHandler; private SensorManager sensorManager = null; private WindowManager windowManager = null; - private Vibrator vibrator = null; - private boolean vibratorActive = false; - private long maxRumbleTime = 250; // 250ms - private RawInputListener listener = null; private IntMap sensors = new IntMap(); - private AndroidJoystick[] joysticks; private int lastRotation = 0; - private boolean initialized = false; private boolean loaded = false; - private final ArrayList eventQueue = new ArrayList(); + public AndroidSensorJoyInput(AndroidJoyInputHandler joyHandler) { + this.joyHandler = joyHandler; + } /** * Internal class to enclose data for each sensor. @@ -120,7 +93,7 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener { int androidSensorType = -1; int androidSensorSpeed = SensorManager.SENSOR_DELAY_GAME; Sensor sensor = null; - int sensorAccuracy = 0; + int sensorAccuracy = -1; float[] lastValues; final Object valuesLock = new Object(); ArrayList axes = new ArrayList(); @@ -134,16 +107,19 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener { } - private void initSensorManager() { - this.context = JmeAndroidSystem.getView().getContext(); - // Get instance of the WindowManager from the current Context - windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); - // Get instance of the SensorManager from the current Context - sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); - // Get instance of Vibrator from current Context - vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); - if (vibrator == null) { - logger.log(Level.FINE, "Vibrator Service not found."); + public void setView(GLSurfaceView view) { + pauseSensors(); + if (sensorManager != null) { + sensorManager.unregisterListener(this); + } + if (view == null) { + windowManager = null; + sensorManager = null; + } else { + // Get instance of the WindowManager from the current Context + windowManager = (WindowManager) view.getContext().getSystemService(Context.WINDOW_SERVICE); + // Get instance of the SensorManager from the current Context + sensorManager = (SensorManager) view.getContext().getSystemService(Context.SENSOR_SERVICE); } } @@ -222,9 +198,6 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener { unRegisterListener(entry.getKey()); } } - if (vibrator != null && vibratorActive) { - vibrator.cancel(); - } } /** @@ -400,10 +373,8 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener { if (!sensorData.haveData) { sensorData.haveData = true; } else { - synchronized (eventQueue){ - if (axis.isChanged()) { - eventQueue.add(new JoyAxisEvent(axis, axis.getJoystickAxisValue())); - } + if (axis.isChanged()) { + joyHandler.addEvent(new JoyAxisEvent(axis, axis.getJoystickAxisValue())); } } } @@ -428,47 +399,14 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener { // Start of JoyInput methods - public void setJoyRumble(int joyId, float amount) { - // convert amount to pulses since Android doesn't allow intensity - if (vibrator != null) { - final long rumbleOnDur = (long)(amount * maxRumbleTime); // ms to pulse vibration on - final long rumbleOffDur = maxRumbleTime - rumbleOnDur; // ms to delay between pulses - final long[] rumblePattern = { - 0, // start immediately - rumbleOnDur, // time to leave vibration on - rumbleOffDur // time to delay between vibrations - }; - final int rumbleRepeatFrom = 0; // index into rumble pattern to repeat from - - logger.log(Level.FINE, "Rumble amount: {0}, rumbleOnDur: {1}, rumbleOffDur: {2}", - new Object[]{amount, rumbleOnDur, rumbleOffDur}); - - if (rumbleOnDur > 0) { - vibrator.vibrate(rumblePattern, rumbleRepeatFrom); - vibratorActive = true; - } else { - vibrator.cancel(); - vibratorActive = false; - } - } - - } - - public Joystick[] loadJoysticks(InputManager inputManager) { - this.inputManager = inputManager; - - initSensorManager(); - + public Joystick loadJoystick(int joyId, InputManager inputManager) { SensorData sensorData; - List list = new ArrayList(); - AndroidJoystick joystick; AndroidJoystickAxis axis; - joystick = new AndroidJoystick(inputManager, - this, - list.size(), + AndroidJoystick joystick = new AndroidJoystick(inputManager, + joyHandler, + joyId, "AndroidSensorsJoystick"); - list.add(joystick); List availSensors = sensorManager.getSensorList(Sensor.TYPE_ALL); for (Sensor sensor: availSensors) { @@ -555,14 +493,8 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener { // } - joysticks = list.toArray( new AndroidJoystick[list.size()] ); loaded = true; - return joysticks; - } - - public void initialize() { - initialized = true; - loaded = false; + return joystick; } public void update() { @@ -570,15 +502,6 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener { return; } updateOrientation(); - synchronized (eventQueue){ - // flush events to listener - if (listener != null && eventQueue.size() > 0) { - for (int i = 0; i < eventQueue.size(); i++){ - listener.onJoyAxisEvent(eventQueue.get(i)); - } - eventQueue.clear(); - } - } } public void destroy() { @@ -588,39 +511,27 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener { sensorManager.unregisterListener(this); } sensors.clear(); - eventQueue.clear(); - initialized = false; loaded = false; - joysticks = null; sensorManager = null; - vibrator = null; - context = null; - } - - public boolean isInitialized() { - return initialized; - } - - public void setInputListener(RawInputListener listener) { - this.listener = listener; - } - - public long getInputTimeNanos() { - return System.nanoTime(); } - // End of JoyInput methods - // Start of Android SensorEventListener methods + @Override public void onSensorChanged(SensorEvent se) { - if (!initialized || !loaded) { + if (!loaded) { return; } + logger.log(Level.FINE, "onSensorChanged for {0}: accuracy: {1}, values: {2}", + new Object[]{se.sensor.getName(), se.accuracy, se.values}); int sensorType = se.sensor.getType(); SensorData sensorData = sensors.get(sensorType); + if (sensorData != null) { + logger.log(Level.FINE, "sensorData name: {0}, enabled: {1}, unreliable: {2}", + new Object[]{sensorData.sensor.getName(), sensorData.enabled, sensorData.sensorAccuracy == SensorManager.SENSOR_STATUS_UNRELIABLE}); + } if (sensorData != null && sensorData.sensor.equals(se.sensor) && sensorData.enabled) { if (sensorData.sensorAccuracy == SensorManager.SENSOR_STATUS_UNRELIABLE) { @@ -641,10 +552,11 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener { if (!sensorData.haveData) { sensorData.haveData = true; } else { - synchronized (eventQueue){ - if (axis.isChanged()) { - eventQueue.add(new JoyAxisEvent(axis, axis.getJoystickAxisValue())); - } + if (axis.isChanged()) { + JoyAxisEvent event = new JoyAxisEvent(axis, axis.getJoystickAxisValue()); + logger.log(Level.INFO, "adding JoyAxisEvent: {0}", event); + joyHandler.addEvent(event); +// joyHandler.addEvent(new JoyAxisEvent(axis, axis.getJoystickAxisValue())); } } } @@ -658,6 +570,7 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener { } } + @Override public void onAccuracyChanged(Sensor sensor, int i) { int sensorType = sensor.getType(); SensorData sensorData = sensors.get(sensorType); @@ -697,7 +610,7 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener { AndroidJoystickAxis axis; axis = new AndroidJoystickAxis( - inputManager, // InputManager (InputManager) + getInputManager(), // InputManager (InputManager) this, // parent Joystick (Joystick) axisNum, // Axis Index (int) axisName, // Axis Name (String) @@ -758,10 +671,12 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener { this.maxRawValue = maxRawValue; } + @Override public float getMaxRawValue() { return maxRawValue; } + @Override public void setMaxRawValue(float maxRawValue) { this.maxRawValue = maxRawValue; } @@ -787,6 +702,7 @@ public class AndroidSensorJoyInput implements JoyInput, SensorEventListener { return hasChanged; } + @Override public void calibrateCenter() { zeroRawValue = lastRawValue; logger.log(Level.FINE, "Calibrating axis {0} to {1}", diff --git a/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java b/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java index cd849b1dd..5ef866188 100644 --- a/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java +++ b/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java @@ -46,17 +46,15 @@ import android.view.ViewGroup.LayoutParams; import android.widget.EditText; import android.widget.FrameLayout; import com.jme3.input.*; -import com.jme3.input.android.AndroidSensorJoyInput; import com.jme3.input.android.AndroidInputHandler; +import com.jme3.input.android.AndroidJoyInputHandler; import com.jme3.input.controls.SoftTextDialogInputListener; import com.jme3.input.dummy.DummyKeyInput; import com.jme3.input.dummy.DummyMouseInput; import com.jme3.renderer.android.AndroidGL; import com.jme3.renderer.opengl.GL; -import com.jme3.renderer.opengl.GLDebugES; import com.jme3.renderer.opengl.GLExt; import com.jme3.renderer.opengl.GLRenderer; -import com.jme3.renderer.opengl.GLTracer; import com.jme3.system.*; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; @@ -77,9 +75,9 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex protected SystemListener listener; protected boolean autoFlush = true; protected AndroidInputHandler androidInput; + protected AndroidJoyInputHandler androidJoyInput = null; protected long minFrameDuration = 0; // No FPS cap protected long lastUpdateTime = 0; - protected JoyInput androidSensorJoyInput = null; public OGLESContext() { } @@ -119,6 +117,12 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex androidInput.setView(view); androidInput.loadSettings(settings); + if (androidJoyInput == null) { + androidJoyInput = new AndroidJoyInputHandler(); + } + androidJoyInput.setView(view); + androidJoyInput.loadSettings(settings); + // setEGLContextClientVersion must be set before calling setRenderer // this means it cannot be set in AndroidConfigChooser (too late) view.setEGLContextClientVersion(2); @@ -231,6 +235,9 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex if (androidInput != null) { androidInput.loadSettings(settings); } + if (androidJoyInput != null) { + androidJoyInput.loadSettings(settings); + } if (settings.getFrameRate() > 0) { minFrameDuration = (long)(1000d / (double)settings.getFrameRate()); // ms @@ -267,10 +274,7 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex @Override public JoyInput getJoyInput() { - if (androidSensorJoyInput == null) { - androidSensorJoyInput = new AndroidSensorJoyInput(); - } - return androidSensorJoyInput; + return androidJoyInput; } @Override From f9be42ee62f7dcdbaa9928458deeb27571101e39 Mon Sep 17 00:00:00 2001 From: jmekaelthas Date: Wed, 8 Apr 2015 20:02:33 +0200 Subject: [PATCH 47/47] Bugfix: fixed problem with ipo curves computin during animations import. --- .../plugins/blender/animations/AnimationHelper.java | 4 ++-- .../plugins/blender/animations/BlenderAction.java | 12 ++++++------ .../plugins/blender/animations/BoneContext.java | 11 +++++++---- .../jme3/scene/plugins/blender/animations/Ipo.java | 13 +++++++++++-- 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/animations/AnimationHelper.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/animations/AnimationHelper.java index f8c1cdad3..1d889f992 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/animations/AnimationHelper.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/animations/AnimationHelper.java @@ -71,7 +71,7 @@ public class AnimationHelper extends AbstractBlenderHelper { if (actions.size() > 0) { List animations = new ArrayList(); for (BlenderAction action : actions) { - SpatialTrack[] tracks = action.toTracks(node); + SpatialTrack[] tracks = action.toTracks(node, blenderContext); if (tracks != null && tracks.length > 0) { Animation spatialAnimation = new Animation(action.getName(), action.getAnimationTime()); spatialAnimation.setTracks(tracks); @@ -110,7 +110,7 @@ public class AnimationHelper extends AbstractBlenderHelper { if (actions.size() > 0) { List animations = new ArrayList(); for (BlenderAction action : actions) { - BoneTrack[] tracks = action.toTracks(skeleton); + BoneTrack[] tracks = action.toTracks(skeleton, blenderContext); if (tracks != null && tracks.length > 0) { Animation boneAnimation = new Animation(action.getName(), action.getAnimationTime()); boneAnimation.setTracks(tracks); diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/animations/BlenderAction.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/animations/BlenderAction.java index aa36c918e..38a437ba0 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/animations/BlenderAction.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/animations/BlenderAction.java @@ -10,9 +10,8 @@ import java.util.Map.Entry; import com.jme3.animation.BoneTrack; import com.jme3.animation.Skeleton; import com.jme3.animation.SpatialTrack; -import com.jme3.math.Quaternion; -import com.jme3.math.Vector3f; import com.jme3.scene.Node; +import com.jme3.scene.plugins.blender.BlenderContext; /** * An abstract representation of animation. The data stored here is mainly a @@ -69,10 +68,10 @@ public class BlenderAction implements Cloneable { * the node that will be animated * @return the spatial tracks for the node */ - public SpatialTrack[] toTracks(Node node) { + public SpatialTrack[] toTracks(Node node, BlenderContext blenderContext) { List tracks = new ArrayList(featuresTracks.size()); for (Entry entry : featuresTracks.entrySet()) { - tracks.add((SpatialTrack) entry.getValue().calculateTrack(0, node.getLocalTranslation(), node.getLocalRotation(), node.getLocalScale(), 1, stopFrame, fps, true)); + tracks.add((SpatialTrack) entry.getValue().calculateTrack(0, null, node.getLocalTranslation(), node.getLocalRotation(), node.getLocalScale(), 1, stopFrame, fps, true)); } return tracks.toArray(new SpatialTrack[tracks.size()]); } @@ -84,11 +83,12 @@ public class BlenderAction implements Cloneable { * the skeleton that will be animated * @return the bone tracks for the node */ - public BoneTrack[] toTracks(Skeleton skeleton) { + public BoneTrack[] toTracks(Skeleton skeleton, BlenderContext blenderContext) { List tracks = new ArrayList(featuresTracks.size()); for (Entry entry : featuresTracks.entrySet()) { int boneIndex = skeleton.getBoneIndex(entry.getKey()); - tracks.add((BoneTrack) entry.getValue().calculateTrack(boneIndex, Vector3f.ZERO, Quaternion.IDENTITY, Vector3f.UNIT_XYZ, 1, stopFrame, fps, false)); + BoneContext boneContext = blenderContext.getBoneContext(skeleton.getBone(boneIndex)); + tracks.add((BoneTrack) entry.getValue().calculateTrack(boneIndex, boneContext, boneContext.getBone().getBindPosition(), boneContext.getBone().getBindRotation(), boneContext.getBone().getBindScale(), 1, stopFrame, fps, false)); } return tracks.toArray(new BoneTrack[tracks.size()]); } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/animations/BoneContext.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/animations/BoneContext.java index 0eb50fb65..adc0a5c4c 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/animations/BoneContext.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/animations/BoneContext.java @@ -25,10 +25,13 @@ import com.jme3.scene.plugins.blender.objects.ObjectHelper; */ public class BoneContext { // the flags of the bone - public static final int SELECTED = 0x0001; - public static final int CONNECTED_TO_PARENT = 0x0010; - public static final int DEFORM = 0x1000; - + public static final int SELECTED = 0x000001; + public static final int CONNECTED_TO_PARENT = 0x000010; + public static final int DEFORM = 0x001000; + public static final int NO_LOCAL_LOCATION = 0x400000; + public static final int NO_INHERIT_SCALE = 0x008000; + public static final int NO_INHERIT_ROTATION = 0x000200; + /** * The bones' matrices have, unlike objects', the coordinate system identical to JME's (Y axis is UP, X to the right and Z toward us). * So in order to have them loaded properly we need to transform their armature matrix (which blender sees as rotated) to make sure we get identical results. diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/animations/Ipo.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/animations/Ipo.java index f388b703f..f5113129f 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/animations/Ipo.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/animations/Ipo.java @@ -137,7 +137,7 @@ public class Ipo { * as jme while other features have different one (Z is UP) * @return bone track for the specified bone */ - public Track calculateTrack(int targetIndex, Vector3f localTranslation, Quaternion localRotation, Vector3f localScale, int startFrame, int stopFrame, int fps, boolean spatialTrack) { + public Track calculateTrack(int targetIndex, BoneContext boneContext, Vector3f localTranslation, Quaternion localRotation, Vector3f localScale, int startFrame, int stopFrame, int fps, boolean spatialTrack) { if (calculatedTrack == null) { // preparing data for track int framesAmount = stopFrame - startFrame; @@ -236,6 +236,15 @@ public class Ipo { } } translations[index] = localRotation.multLocal(new Vector3f(translation[0], translation[1], translation[2])); + + if(boneContext != null) { + if(boneContext.getBone().getParent() == null && boneContext.is(BoneContext.NO_LOCAL_LOCATION)) { + float temp = translations[index].z; + translations[index].z = -translations[index].y; + translations[index].y = temp; + } + } + if (queternionRotationUsed) { rotations[index] = new Quaternion(quaternionRotation[0], quaternionRotation[1], quaternionRotation[2], quaternionRotation[3]); } else { @@ -292,7 +301,7 @@ public class Ipo { } @Override - public BoneTrack calculateTrack(int boneIndex, Vector3f localTranslation, Quaternion localRotation, Vector3f localScale, int startFrame, int stopFrame, int fps, boolean boneTrack) { + public BoneTrack calculateTrack(int boneIndex, BoneContext boneContext, Vector3f localTranslation, Quaternion localRotation, Vector3f localScale, int startFrame, int stopFrame, int fps, boolean boneTrack) { throw new IllegalStateException("Constatnt ipo object cannot be used for calculating bone tracks!"); } }