OSDN Git Service

* Javadocs for com.jme3.material
authorshadowislord <shadowislord@75d07b2b-3a1a-0410-a2c5-0572b91ccdca>
Sun, 12 Jun 2011 04:19:16 +0000 (04:19 +0000)
committershadowislord <shadowislord@75d07b2b-3a1a-0410-a2c5-0572b91ccdca>
Sun, 12 Jun 2011 04:19:16 +0000 (04:19 +0000)
 * Formatted the blender loader files according to NetBeans
 * Removed any "I" prefixes on interfaces
 * Small javadoc fixes

git-svn-id: http://jmonkeyengine.googlecode.com/svn/trunk@7592 75d07b2b-3a1a-0410-a2c5-0572b91ccdca

80 files changed:
engine/src/blender/com/jme3/asset/BlenderKey.java
engine/src/blender/com/jme3/scene/plugins/blender/BlenderLoader.java
engine/src/blender/com/jme3/scene/plugins/blender/BlenderModelLoader.java
engine/src/blender/com/jme3/scene/plugins/blender/data/DnaBlockData.java
engine/src/blender/com/jme3/scene/plugins/blender/data/Field.java
engine/src/blender/com/jme3/scene/plugins/blender/data/FileBlockHeader.java
engine/src/blender/com/jme3/scene/plugins/blender/data/Structure.java
engine/src/blender/com/jme3/scene/plugins/blender/exception/BlenderFileException.java
engine/src/blender/com/jme3/scene/plugins/blender/helpers/ArmatureHelper.java
engine/src/blender/com/jme3/scene/plugins/blender/helpers/CameraHelper.java
engine/src/blender/com/jme3/scene/plugins/blender/helpers/ConstraintHelper.java
engine/src/blender/com/jme3/scene/plugins/blender/helpers/CurvesHelper.java
engine/src/blender/com/jme3/scene/plugins/blender/helpers/IpoHelper.java
engine/src/blender/com/jme3/scene/plugins/blender/helpers/LightHelper.java
engine/src/blender/com/jme3/scene/plugins/blender/helpers/MaterialHelper.java
engine/src/blender/com/jme3/scene/plugins/blender/helpers/MeshHelper.java
engine/src/blender/com/jme3/scene/plugins/blender/helpers/ModifierHelper.java
engine/src/blender/com/jme3/scene/plugins/blender/helpers/NoiseHelper.java
engine/src/blender/com/jme3/scene/plugins/blender/helpers/ObjectHelper.java
engine/src/blender/com/jme3/scene/plugins/blender/helpers/ParticlesHelper.java
engine/src/blender/com/jme3/scene/plugins/blender/helpers/TextureHelper.java
engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/ArmatureHelper.java
engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/CameraHelper.java
engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/ConstraintHelper.java
engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/CurvesHelper.java
engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/IpoHelper.java
engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/LightHelper.java
engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/MaterialHelper.java
engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/MeshHelper.java
engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/ModifierHelper.java
engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/NoiseHelper.java
engine/src/blender/com/jme3/scene/plugins/blender/structures/AbstractInfluenceFunction.java
engine/src/blender/com/jme3/scene/plugins/blender/structures/BezierCurve.java
engine/src/blender/com/jme3/scene/plugins/blender/structures/Constraint.java
engine/src/blender/com/jme3/scene/plugins/blender/structures/ConstraintType.java
engine/src/blender/com/jme3/scene/plugins/blender/structures/Ipo.java
engine/src/blender/com/jme3/scene/plugins/blender/structures/Modifier.java
engine/src/blender/com/jme3/scene/plugins/blender/utils/AbstractBlenderHelper.java
engine/src/blender/com/jme3/scene/plugins/blender/utils/BlenderConverter.java [moved from engine/src/blender/com/jme3/scene/plugins/blender/utils/IBlenderConverter.java with 53% similarity]
engine/src/blender/com/jme3/scene/plugins/blender/utils/BlenderInputStream.java
engine/src/blender/com/jme3/scene/plugins/blender/utils/DataRepository.java
engine/src/blender/com/jme3/scene/plugins/blender/utils/DynamicArray.java
engine/src/blender/com/jme3/scene/plugins/blender/utils/JmeConverter.java
engine/src/blender/com/jme3/scene/plugins/blender/utils/Pointer.java
engine/src/core/com/jme3/animation/Bone.java
engine/src/core/com/jme3/animation/CompactArray.java
engine/src/core/com/jme3/app/package.html
engine/src/core/com/jme3/app/state/AppStateManager.java
engine/src/core/com/jme3/asset/AssetLocator.java
engine/src/core/com/jme3/asset/AssetManager.java
engine/src/core/com/jme3/asset/TextureKey.java
engine/src/core/com/jme3/audio/AudioRenderer.java
engine/src/core/com/jme3/bounding/BoundingBox.java
engine/src/core/com/jme3/bounding/BoundingSphere.java
engine/src/core/com/jme3/input/controls/MouseButtonTrigger.java
engine/src/core/com/jme3/light/Light.java
engine/src/core/com/jme3/material/Material.java
engine/src/core/com/jme3/material/Technique.java
engine/src/core/com/jme3/material/TechniqueDef.java
engine/src/core/com/jme3/material/package.html
engine/src/core/com/jme3/math/Matrix4f.java
engine/src/core/com/jme3/math/Ray.java
engine/src/core/com/jme3/math/Spline.java
engine/src/core/com/jme3/math/Triangle.java
engine/src/core/com/jme3/math/Vector2f.java
engine/src/core/com/jme3/math/Vector4f.java
engine/src/core/com/jme3/post/Filter.java
engine/src/core/com/jme3/renderer/Camera.java
engine/src/core/com/jme3/renderer/GLObject.java
engine/src/core/com/jme3/renderer/RenderManager.java
engine/src/core/com/jme3/renderer/Renderer.java
engine/src/core/com/jme3/renderer/queue/GeometryList.java
engine/src/core/com/jme3/scene/Geometry.java
engine/src/core/com/jme3/scene/Node.java
engine/src/core/com/jme3/scene/Spatial.java
engine/src/core/com/jme3/scene/VertexBuffer.java
engine/src/core/com/jme3/scene/control/Control.java
engine/src/core/com/jme3/scene/control/LightControl.java
engine/src/core/com/jme3/shader/Shader.java
engine/src/core/com/jme3/system/JmeContext.java

index 7eddfd1..1af3124 100644 (file)
@@ -64,728 +64,736 @@ import com.jme3.texture.Texture;
  * @author Marcin Roguski (Kaelthas)\r
  */\r
 public class BlenderKey extends ModelKey {\r
-       protected static final int                                      DEFAULT_FPS                             = 25;\r
-\r
-       /**\r
-        * Animation definitions. The key is the object name that owns the animation. The value is a map between animation\r
-        * name and its start and stop frames. Blender stores a pointer for animation within object. Therefore one object\r
-        * can only have one animation at the time. We want to be able to switch between animations for one object so we\r
-        * need to map the object name to animation names the object will use.\r
-        */\r
-       protected Map<String, Map<String, int[]>>       animations;\r
-       /**\r
-        * FramesPerSecond parameter describe how many frames there are in each second. It allows to calculate the time\r
-        * between the frames.\r
-        */\r
-       protected int                                                           fps                                             = DEFAULT_FPS;\r
-       /** Width of generated textures (in pixels). Blender uses 140x140 by default. */\r
-       protected int                                                           generatedTextureWidth   = 140;\r
-       /** Height of generated textures (in pixels). Blender uses 140x140 by default. */\r
-       protected int                                                           generatedTextureHeight  = 140;\r
-       /**\r
-        * This variable is a bitwise flag of FeatureToLoad interface values; By default everything is being loaded.\r
-        */\r
-       protected int                                                           featuresToLoad                  = FeaturesToLoad.ALL;\r
-       /** The root path for all the assets. */\r
-       protected String                                                        assetRootPath;\r
-       /** This variable indicate if Y axis is UP axis. If not then Z is up. By default set to true. */\r
-       protected boolean                                                       fixUpAxis                               = true;\r
-       /**\r
-        * The name of world settings that the importer will use. If not set or specified name does not occur in the file\r
-        * then the first world settings in the file will be used.\r
-        */\r
-       protected String                                                        usedWorld;\r
-       /**\r
-        * User's default material that is set fo objects that have no material definition in blender. The default value is\r
-        * null. If the value is null the importer will use its own default material (gray color - like in blender).\r
-        */\r
-       protected Material                                                      defaultMaterial;\r
-       /** Face cull mode. By default it is disabled. */\r
-       protected FaceCullMode                                          faceCullMode                    = FaceCullMode.Off;\r
-       /** \r
-        * Variable describes which layers will be loaded. N-th bit set means N-th layer will be loaded.\r
-        * If set to -1 then the current layer will be loaded.\r
-        */\r
-       protected int                                                           layersToLoad                    = -1;\r
-       \r
-       /**\r
-        * Constructor used by serialization mechanisms.\r
-        */\r
-       public BlenderKey() {}\r
-\r
-       /**\r
-        * Constructor. Creates a key for the given file name.\r
-        * @param name\r
-        *        the name (path) of a file\r
-        */\r
-       public BlenderKey(String name) {\r
-               super(name);\r
-       }\r
-\r
-       /**\r
-        * This method adds an animation definition. If a definition already eixists in the key then it is replaced.\r
-        * @param objectName\r
-        *        the name of animation's owner\r
-        * @param name\r
-        *        the name of the animation\r
-        * @param start\r
-        *        the start frame of the animation\r
-        * @param stop\r
-        *        the stop frame of the animation\r
-        */\r
-       public synchronized void addAnimation(String objectName, String name, int start, int stop) {\r
-               if(objectName == null) {\r
-                       throw new IllegalArgumentException("Object name cannot be null!");\r
-               }\r
-               if(name == null) {\r
-                       throw new IllegalArgumentException("Animation name cannot be null!");\r
-               }\r
-               if(start > stop) {\r
-                       throw new IllegalArgumentException("Start frame cannot be greater than stop frame!");\r
-               }\r
-               if(animations == null) {\r
-                       animations = new HashMap<String, Map<String, int[]>>();\r
-                       animations.put(objectName, new HashMap<String, int[]>());\r
-               }\r
-               Map<String, int[]> objectAnimations = animations.get(objectName);\r
-               if(objectAnimations == null) {\r
-                       objectAnimations = new HashMap<String, int[]>();\r
-                       animations.put(objectName, objectAnimations);\r
-               }\r
-               objectAnimations.put(name, new int[] {start, stop});\r
-       }\r
-\r
-       /**\r
-        * This method returns the animation frames boundaries.\r
-        * @param objectName\r
-        *        the name of animation's owner\r
-        * @param name\r
-        *        animation name\r
-        * @return animation frame boundaries in a table [start, stop] or null if animation of the given name does not\r
-        *         exists\r
-        */\r
-       public int[] getAnimationFrames(String objectName, String name) {\r
-               Map<String, int[]> objectAnimations = animations == null ? null : animations.get(objectName);\r
-               int[] frames = objectAnimations == null ? null : objectAnimations.get(name);\r
-               return frames == null ? null : frames.clone();\r
-       }\r
-\r
-       /**\r
-        * This method returns the animation names for the given object name.\r
-        * @param objectName\r
-        *        the name of the object\r
-        * @return an array of animations for this object\r
-        */\r
-       public Set<String> getAnimationNames(String objectName) {\r
-               Map<String, int[]> objectAnimations = animations == null ? null : animations.get(objectName);\r
-               return objectAnimations == null ? null : objectAnimations.keySet();\r
-       }\r
-\r
-       /**\r
-        * This method returns the animations map.\r
-        * @return the animations map\r
-        */\r
-       public Map<String, Map<String, int[]>> getAnimations() {\r
-               return animations;\r
-       }\r
-\r
-       /**\r
-        * This method returns frames per second amount. The default value is BlenderKey.DEFAULT_FPS = 25.\r
-        * @return the frames per second amount\r
-        */\r
-       public int getFps() {\r
-               return fps;\r
-       }\r
-\r
-       /**\r
-        * This method sets frames per second amount.\r
-        * @param fps\r
-        *        the frames per second amount\r
-        */\r
-       public void setFps(int fps) {\r
-               this.fps = fps;\r
-       }\r
-\r
-       /**\r
-        * This method sets the width of generated texture (in pixels). By default the value is 140 px.\r
-        * @param generatedTextureWidth\r
-        *        the width of generated texture\r
-        */\r
-       public void setGeneratedTextureWidth(int generatedTextureWidth) {\r
-               this.generatedTextureWidth = generatedTextureWidth;\r
-       }\r
-\r
-       /**\r
-        * This method returns the width of generated texture (in pixels). By default the value is 140 px.\r
-        * @return the width of generated texture\r
-        */\r
-       public int getGeneratedTextureWidth() {\r
-               return generatedTextureWidth;\r
-       }\r
-\r
-       /**\r
-        * This method sets the height of generated texture (in pixels). By default the value is 140 px.\r
-        * @param generatedTextureHeight\r
-        *        the height of generated texture\r
-        */\r
-       public void setGeneratedTextureHeight(int generatedTextureHeight) {\r
-               this.generatedTextureHeight = generatedTextureHeight;\r
-       }\r
-\r
-       /**\r
-        * This method returns the height of generated texture (in pixels). By default the value is 140 px.\r
-        * @return the height of generated texture\r
-        */\r
-       public int getGeneratedTextureHeight() {\r
-               return generatedTextureHeight;\r
-       }\r
-\r
-       /**\r
-        * This method returns the face cull mode.\r
-        * @return the face cull mode\r
-        */\r
-       public FaceCullMode getFaceCullMode() {\r
-               return faceCullMode;\r
-       }\r
-\r
-       /**\r
-        * This method sets the face cull mode.\r
-        * @param faceCullMode\r
-        *        the face cull mode\r
-        */\r
-       public void setFaceCullMode(FaceCullMode faceCullMode) {\r
-               this.faceCullMode = faceCullMode;\r
-       }\r
-\r
-       /**\r
-        * This method sets layers to be loaded.\r
-        * @param layersToLoad layers to be loaded\r
-        */\r
-       public void setLayersToLoad(int layersToLoad) {\r
-               this.layersToLoad = layersToLoad;\r
-       }\r
-       \r
-       /**\r
-        * This method returns layers to be loaded.\r
-        * @return layers to be loaded\r
-        */\r
-       public int getLayersToLoad() {\r
-               return layersToLoad;\r
-       }\r
-       \r
-       /**\r
-        * This method sets the asset root path.\r
-        * @param assetRootPath\r
-        *        the assets root path\r
-        */\r
-       public void setAssetRootPath(String assetRootPath) {\r
-               this.assetRootPath = assetRootPath;\r
-       }\r
-\r
-       /**\r
-        * This method returns the asset root path.\r
-        * @return the asset root path\r
-        */\r
-       public String getAssetRootPath() {\r
-               return assetRootPath;\r
-       }\r
-\r
-       /**\r
-        * This method adds features to be loaded.\r
-        * @param featuresToLoad\r
-        *        bitwise flag of FeaturesToLoad interface values\r
-        */\r
-       public void includeInLoading(int featuresToLoad) {\r
-               this.featuresToLoad |= featuresToLoad;\r
-       }\r
-\r
-       /**\r
-        * This method removes features from being loaded.\r
-        * @param featuresToLoad\r
-        *        bitwise flag of FeaturesToLoad interface values\r
-        */\r
-       public void excludeFromLoading(int featuresNotToLoad) {\r
-               this.featuresToLoad &= ~featuresNotToLoad;\r
-       }\r
-\r
-       /**\r
-        * This method returns bitwise value of FeaturesToLoad interface value. It describes features that will be loaded by\r
-        * the blender file loader.\r
-        * @return features that will be loaded by the blender file loader\r
-        */\r
-       public int getFeaturesToLoad() {\r
-               return featuresToLoad;\r
-       }\r
-\r
-       /**\r
-        * This method creates an object where loading results will be stores. Only those features will be allowed to store\r
-        * that were specified by features-to-load flag.\r
-        * @return an object to store loading results\r
-        */\r
-       public LoadingResults prepareLoadingResults() {\r
-               return new LoadingResults(featuresToLoad);\r
-       }\r
-\r
-       /**\r
-        * 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\r
-        * is up axis.\r
-        * @param fixUpAxis\r
-        *        the up axis state variable\r
-        */\r
-       public void setFixUpAxis(boolean fixUpAxis) {\r
-               this.fixUpAxis = fixUpAxis;\r
-       }\r
-\r
-       /**\r
-        * This method returns the fix up axis state. If set to true then Y is up axis. Otherwise the up i Z axis. By\r
-        * default Y is up axis.\r
-        * @return the up axis state variable\r
-        */\r
-       public boolean isFixUpAxis() {\r
-               return fixUpAxis;\r
-       }\r
-\r
-       /**\r
-        * This mehtod sets the name of the WORLD data block taht should be used during file loading. By default the name is\r
-        * not set. If no name is set or the given name does not occur in the file - the first WORLD data block will be used\r
-        * during loading (assumin any exists in the file).\r
-        * @param usedWorld\r
-        *        the name of the WORLD block used during loading\r
-        */\r
-       public void setUsedWorld(String usedWorld) {\r
-               this.usedWorld = usedWorld;\r
-       }\r
-\r
-       /**\r
-        * This mehtod returns the name of the WORLD data block taht should be used during file loading.\r
-        * @return the name of the WORLD block used during loading\r
-        */\r
-       public String getUsedWorld() {\r
-               return usedWorld;\r
-       }\r
-\r
-       /**\r
-        * This method sets the default material for objects.\r
-        * @param defaultMaterial\r
-        *        the default material\r
-        */\r
-       public void setDefaultMaterial(Material defaultMaterial) {\r
-               this.defaultMaterial = defaultMaterial;\r
-       }\r
-\r
-       /**\r
-        * This method returns the default material.\r
-        * @return the default material\r
-        */\r
-       public Material getDefaultMaterial() {\r
-               return defaultMaterial;\r
-       }\r
-\r
-       @Override\r
-       public void write(JmeExporter e) throws IOException {\r
-               super.write(e);\r
-               OutputCapsule oc = e.getCapsule(this);\r
-               //saving animations\r
-               oc.write(animations == null ? 0 : animations.size(), "anim-size", 0);\r
-               if(animations != null) {\r
-                       int objectCounter = 0;\r
-                       for(Entry<String, Map<String, int[]>> animEntry : animations.entrySet()) {\r
-                               oc.write(animEntry.getKey(), "animated-object-" + objectCounter, null);\r
-                               int animsAmount = animEntry.getValue().size();\r
-                               oc.write(animsAmount, "anims-amount-" + objectCounter, 0);\r
-                               for(Entry<String, int[]> animsEntry : animEntry.getValue().entrySet()) {\r
-                                       oc.write(animsEntry.getKey(), "anim-name-" + objectCounter, null);\r
-                                       oc.write(animsEntry.getValue(), "anim-frames-" + objectCounter, null);\r
-                               }\r
-                               ++objectCounter;\r
-                       }\r
-               }\r
-               //saving the rest of the data\r
-               oc.write(fps, "fps", DEFAULT_FPS);\r
-               oc.write(featuresToLoad, "features-to-load", FeaturesToLoad.ALL);\r
-               oc.write(assetRootPath, "asset-root-path", null);\r
-               oc.write(fixUpAxis, "fix-up-axis", true);\r
-               oc.write(usedWorld, "used-world", null);\r
-               oc.write(defaultMaterial, "default-material", null);\r
-               oc.write(faceCullMode, "face-cull-mode", FaceCullMode.Off);\r
-               oc.write(layersToLoad, "layers-to-load", -1);\r
-       }\r
-\r
-       @Override\r
-       public void read(JmeImporter e) throws IOException {\r
-               super.read(e);\r
-               InputCapsule ic = e.getCapsule(this);\r
-               //reading animations\r
-               int animSize = ic.readInt("anim-size", 0);\r
-               if(animSize > 0) {\r
-                       if(animations == null) {\r
-                               animations = new HashMap<String, Map<String, int[]>>(animSize);\r
-                       } else {\r
-                               animations.clear();\r
-                       }\r
-                       for(int i = 0; i < animSize; ++i) {\r
-                               String objectName = ic.readString("animated-object-" + i, null);\r
-                               int animationsAmount = ic.readInt("anims-amount-" + i, 0);\r
-                               Map<String, int[]> objectAnimations = new HashMap<String, int[]>(animationsAmount);\r
-                               for(int j = 0; j < animationsAmount; ++j) {\r
-                                       String animName = ic.readString("anim-name-" + i, null);\r
-                                       int[] animFrames = ic.readIntArray("anim-frames-" + i, null);\r
-                                       objectAnimations.put(animName, animFrames);\r
-                               }\r
-                               animations.put(objectName, objectAnimations);\r
-                       }\r
-               }\r
-\r
-               //reading the rest of the data\r
-               fps = ic.readInt("fps", DEFAULT_FPS);\r
-               featuresToLoad = ic.readInt("features-to-load", FeaturesToLoad.ALL);\r
-               assetRootPath = ic.readString("asset-root-path", null);\r
-               fixUpAxis = ic.readBoolean("fix-up-axis", true);\r
-               usedWorld = ic.readString("used-world", null);\r
-               defaultMaterial = (Material)ic.readSavable("default-material", null);\r
-               faceCullMode = ic.readEnum("face-cull-mode", FaceCullMode.class, FaceCullMode.Off);\r
-               layersToLoad = ic.readInt("layers-to=load", -1);\r
-       }\r
-\r
-       @Override\r
-       public int hashCode() {\r
-               final int prime = 31;\r
-               int result = super.hashCode();\r
-               result = prime * result + (animations == null ? 0 : animations.hashCode());\r
-               result = prime * result + (assetRootPath == null ? 0 : assetRootPath.hashCode());\r
-               result = prime * result + (defaultMaterial == null ? 0 : defaultMaterial.hashCode());\r
-               result = prime * result + (faceCullMode == null ? 0 : faceCullMode.hashCode());\r
-               result = prime * result + featuresToLoad;\r
-               result = prime * result + (fixUpAxis ? 1231 : 1237);\r
-               result = prime * result + fps;\r
-               result = prime * result + generatedTextureHeight;\r
-               result = prime * result + generatedTextureWidth;\r
-               result = prime * result + layersToLoad;\r
-               result = prime * result + (usedWorld == null ? 0 : usedWorld.hashCode());\r
-               return result;\r
-       }\r
-\r
-       @Override\r
-       public boolean equals(Object obj) {\r
-               if (this == obj) {\r
-                       return true;\r
-               }\r
-               if (!super.equals(obj)) {\r
-                       return false;\r
-               }\r
-               if (this.getClass() != obj.getClass()) {\r
-                       return false;\r
-               }\r
-               BlenderKey other = (BlenderKey) obj;\r
-               if (animations == null) {\r
-                       if (other.animations != null) {\r
-                               return false;\r
-                       }\r
-               } else if (!animations.equals(other.animations)) {\r
-                       return false;\r
-               }\r
-               if (assetRootPath == null) {\r
-                       if (other.assetRootPath != null) {\r
-                               return false;\r
-                       }\r
-               } else if (!assetRootPath.equals(other.assetRootPath)) {\r
-                       return false;\r
-               }\r
-               if (defaultMaterial == null) {\r
-                       if (other.defaultMaterial != null) {\r
-                               return false;\r
-                       }\r
-               } else if (!defaultMaterial.equals(other.defaultMaterial)) {\r
-                       return false;\r
-               }\r
-               if (faceCullMode != other.faceCullMode) {\r
-                       return false;\r
-               }\r
-               if (featuresToLoad != other.featuresToLoad) {\r
-                       return false;\r
-               }\r
-               if (fixUpAxis != other.fixUpAxis) {\r
-                       return false;\r
-               }\r
-               if (fps != other.fps) {\r
-                       return false;\r
-               }\r
-               if (generatedTextureHeight != other.generatedTextureHeight) {\r
-                       return false;\r
-               }\r
-               if (generatedTextureWidth != other.generatedTextureWidth) {\r
-                       return false;\r
-               }\r
-               if (layersToLoad != other.layersToLoad) {\r
-                       return false;\r
-               }\r
-               if (usedWorld == null) {\r
-                       if (other.usedWorld != null) {\r
-                               return false;\r
-                       }\r
-               } else if (!usedWorld.equals(other.usedWorld)) {\r
-                       return false;\r
-               }\r
-               return true;\r
-       }\r
-\r
-       /**\r
-        * This interface describes the features of the scene that are to be loaded.\r
-        * @author Marcin Roguski (Kaelthas)\r
-        */\r
-       public static interface FeaturesToLoad {\r
-               int     SCENES          = 0x0000FFFF;\r
-               int     OBJECTS         = 0x0000000B;\r
-               int     ANIMATIONS      = 0x00000004;\r
-               int     MATERIALS       = 0x00000003;\r
-               int     TEXTURES        = 0x00000001;\r
-               int     CAMERAS         = 0x00000020;\r
-               int     LIGHTS          = 0x00000010;\r
-               int     ALL                     = 0xFFFFFFFF;\r
-       }\r
-\r
-       /**\r
-        * This class holds the loading results according to the given loading flag.\r
-        * @author Marcin Roguski (Kaelthas)\r
-        */\r
-       public static class LoadingResults extends Spatial {\r
-               /** Bitwise mask of features that are to be loaded. */\r
-               private final int               featuresToLoad;\r
-               /** The scenes from the file. */\r
-               private List<Node>              scenes;\r
-               /** Objects from all scenes. */\r
-               private List<Node>              objects;\r
-               /** Materials from all objects. */\r
-               private List<Material>  materials;\r
-               /** Textures from all objects. */\r
-               private List<Texture>   textures;\r
-               /** Animations of all objects. */\r
-               private List<AnimData>  animations;\r
-               /** All cameras from the file. */\r
-               private List<Camera>    cameras;\r
-               /** All lights from the file. */\r
-               private List<Light>             lights;\r
-\r
-               /**\r
-                * Private constructor prevents users to create an instance of this class from outside the\r
-                * @param featuresToLoad\r
-                *        bitwise mask of features that are to be loaded\r
-                * @see FeaturesToLoad FeaturesToLoad\r
-                */\r
-               private LoadingResults(int featuresToLoad) {\r
-                       this.featuresToLoad = featuresToLoad;\r
-                       if((featuresToLoad & FeaturesToLoad.SCENES) != 0) {\r
-                               scenes = new ArrayList<Node>();\r
-                       }\r
-                       if((featuresToLoad & FeaturesToLoad.OBJECTS) != 0) {\r
-                               objects = new ArrayList<Node>();\r
-                               if((featuresToLoad & FeaturesToLoad.MATERIALS) != 0) {\r
-                                       materials = new ArrayList<Material>();\r
-                                       if((featuresToLoad & FeaturesToLoad.TEXTURES) != 0) {\r
-                                               textures = new ArrayList<Texture>();\r
-                                       }\r
-                               }\r
-                               if((featuresToLoad & FeaturesToLoad.ANIMATIONS) != 0) {\r
-                                       animations = new ArrayList<AnimData>();\r
-                               }\r
-                       }\r
-                       if((featuresToLoad & FeaturesToLoad.CAMERAS) != 0) {\r
-                               cameras = new ArrayList<Camera>();\r
-                       }\r
-                       if((featuresToLoad & FeaturesToLoad.LIGHTS) != 0) {\r
-                               lights = new ArrayList<Light>();\r
-                       }\r
-               }\r
-\r
-               /**\r
-                * This method returns a bitwise flag describing what features of the blend file will be included in the result.\r
-                * @return bitwise mask of features that are to be loaded\r
-                * @see FeaturesToLoad FeaturesToLoad\r
-                */\r
-               public int getLoadedFeatures() {\r
-                       return featuresToLoad;\r
-               }\r
-\r
-               /**\r
-                * This method adds a scene to the result set.\r
-                * @param scene\r
-                *        scene to be added to the result set\r
-                */\r
-               public void addScene(Node scene) {\r
-                       if(scenes != null) {\r
-                               scenes.add(scene);\r
-                       }\r
-               }\r
-\r
-               /**\r
-                * This method adds an object to the result set.\r
-                * @param object\r
-                *        object to be added to the result set\r
-                */\r
-               public void addObject(Node object) {\r
-                       if(objects != null) {\r
-                               objects.add(object);\r
-                       }\r
-               }\r
-\r
-               /**\r
-                * This method adds a material to the result set.\r
-                * @param material\r
-                *        material to be added to the result set\r
-                */\r
-               public void addMaterial(Material material) {\r
-                       if(materials != null) {\r
-                               materials.add(material);\r
-                       }\r
-               }\r
-\r
-               /**\r
-                * This method adds a texture to the result set.\r
-                * @param texture\r
-                *        texture to be added to the result set\r
-                */\r
-               public void addTexture(Texture texture) {\r
-                       if(textures != null) {\r
-                               textures.add(texture);\r
-                       }\r
-               }\r
-\r
-               /**\r
-                * This method adds a camera to the result set.\r
-                * @param camera\r
-                *        camera to be added to the result set\r
-                */\r
-               public void addCamera(Camera camera) {\r
-                       if(cameras != null) {\r
-                               cameras.add(camera);\r
-                       }\r
-               }\r
-\r
-               /**\r
-                * This method adds a light to the result set.\r
-                * @param light\r
-                *        light to be added to the result set\r
-                */\r
-               @Override\r
-               public void addLight(Light light) {\r
-                       if(lights != null) {\r
-                               lights.add(light);\r
-                       }\r
-               }\r
-\r
-               /**\r
-                * This method returns all loaded scenes.\r
-                * @return all loaded scenes\r
-                */\r
-               public List<Node> getScenes() {\r
-                       return scenes;\r
-               }\r
-\r
-               /**\r
-                * This method returns all loaded objects.\r
-                * @return all loaded objects\r
-                */\r
-               public List<Node> getObjects() {\r
-                       return objects;\r
-               }\r
-\r
-               /**\r
-                * This method returns all loaded materials.\r
-                * @return all loaded materials\r
-                */\r
-               public List<Material> getMaterials() {\r
-                       return materials;\r
-               }\r
-\r
-               /**\r
-                * This method returns all loaded textures.\r
-                * @return all loaded textures\r
-                */\r
-               public List<Texture> getTextures() {\r
-                       return textures;\r
-               }\r
-\r
-               /**\r
-                * This method returns all loaded animations.\r
-                * @return all loaded animations\r
-                */\r
-               public List<AnimData> getAnimations() {\r
-                       return animations;\r
-               }\r
-\r
-               /**\r
-                * This method returns all loaded cameras.\r
-                * @return all loaded cameras\r
-                */\r
-               public List<Camera> getCameras() {\r
-                       return cameras;\r
-               }\r
-\r
-               /**\r
-                * This method returns all loaded lights.\r
-                * @return all loaded lights\r
-                */\r
-               public List<Light> getLights() {\r
-                       return lights;\r
-               }\r
-\r
-               @Override\r
-               public int collideWith(Collidable other, CollisionResults results) throws UnsupportedCollisionException {\r
-                       return 0;\r
-               }\r
-\r
-               @Override\r
-               public void updateModelBound() {}\r
-\r
-               @Override\r
-               public void setModelBound(BoundingVolume modelBound) {}\r
-\r
-               @Override\r
-               public int getVertexCount() {\r
-                       return 0;\r
-               }\r
-\r
-               @Override\r
-               public int getTriangleCount() {\r
-                       return 0;\r
-               }\r
-\r
-               @Override\r
-               public Spatial deepClone() {\r
-                       return null;\r
-               }\r
-\r
-               @Override\r
-               public void depthFirstTraversal(SceneGraphVisitor visitor) {}\r
-\r
-               @Override\r
-               protected void breadthFirstTraversal(SceneGraphVisitor visitor, Queue<Spatial> queue) {}\r
-       }\r
-\r
-       /**\r
-        * The WORLD file block contains various data that could be added to the scene. The contained data includes: ambient\r
-        * light.\r
-        * @author Marcin Roguski (Kaelthas)\r
-        */\r
-       public static class WorldData {\r
-               /** The ambient light. */\r
-               private AmbientLight    ambientLight;\r
-\r
-               /**\r
-                * This method returns the world's ambient light.\r
-                * @return the world's ambient light\r
-                */\r
-               public AmbientLight getAmbientLight() {\r
-                       return ambientLight;\r
-               }\r
-\r
-               /**\r
-                * This method sets the world's ambient light.\r
-                * @param ambientLight\r
-                *        the world's ambient light\r
-                */\r
-               public void setAmbientLight(AmbientLight ambientLight) {\r
-                       this.ambientLight = ambientLight;\r
-               }\r
-       }\r
+\r
+    protected static final int DEFAULT_FPS = 25;\r
+    /**\r
+     * Animation definitions. The key is the object name that owns the animation. The value is a map between animation\r
+     * name and its start and stop frames. Blender stores a pointer for animation within object. Therefore one object\r
+     * can only have one animation at the time. We want to be able to switch between animations for one object so we\r
+     * need to map the object name to animation names the object will use.\r
+     */\r
+    protected Map<String, Map<String, int[]>> animations;\r
+    /**\r
+     * FramesPerSecond parameter describe how many frames there are in each second. It allows to calculate the time\r
+     * between the frames.\r
+     */\r
+    protected int fps = DEFAULT_FPS;\r
+    /** Width of generated textures (in pixels). Blender uses 140x140 by default. */\r
+    protected int generatedTextureWidth = 140;\r
+    /** Height of generated textures (in pixels). Blender uses 140x140 by default. */\r
+    protected int generatedTextureHeight = 140;\r
+    /**\r
+     * This variable is a bitwise flag of FeatureToLoad interface values; By default everything is being loaded.\r
+     */\r
+    protected int featuresToLoad = FeaturesToLoad.ALL;\r
+    /** The root path for all the assets. */\r
+    protected String assetRootPath;\r
+    /** This variable indicate if Y axis is UP axis. If not then Z is up. By default set to true. */\r
+    protected boolean fixUpAxis = true;\r
+    /**\r
+     * The name of world settings that the importer will use. If not set or specified name does not occur in the file\r
+     * then the first world settings in the file will be used.\r
+     */\r
+    protected String usedWorld;\r
+    /**\r
+     * User's default material that is set fo objects that have no material definition in blender. The default value is\r
+     * null. If the value is null the importer will use its own default material (gray color - like in blender).\r
+     */\r
+    protected Material defaultMaterial;\r
+    /** Face cull mode. By default it is disabled. */\r
+    protected FaceCullMode faceCullMode = FaceCullMode.Off;\r
+    /** \r
+     * Variable describes which layers will be loaded. N-th bit set means N-th layer will be loaded.\r
+     * If set to -1 then the current layer will be loaded.\r
+     */\r
+    protected int layersToLoad = -1;\r
+\r
+    /**\r
+     * Constructor used by serialization mechanisms.\r
+     */\r
+    public BlenderKey() {\r
+    }\r
+\r
+    /**\r
+     * Constructor. Creates a key for the given file name.\r
+     * @param name\r
+     *        the name (path) of a file\r
+     */\r
+    public BlenderKey(String name) {\r
+        super(name);\r
+    }\r
+\r
+    /**\r
+     * This method adds an animation definition. If a definition already eixists in the key then it is replaced.\r
+     * @param objectName\r
+     *        the name of animation's owner\r
+     * @param name\r
+     *        the name of the animation\r
+     * @param start\r
+     *        the start frame of the animation\r
+     * @param stop\r
+     *        the stop frame of the animation\r
+     */\r
+    public synchronized void addAnimation(String objectName, String name, int start, int stop) {\r
+        if (objectName == null) {\r
+            throw new IllegalArgumentException("Object name cannot be null!");\r
+        }\r
+        if (name == null) {\r
+            throw new IllegalArgumentException("Animation name cannot be null!");\r
+        }\r
+        if (start > stop) {\r
+            throw new IllegalArgumentException("Start frame cannot be greater than stop frame!");\r
+        }\r
+        if (animations == null) {\r
+            animations = new HashMap<String, Map<String, int[]>>();\r
+            animations.put(objectName, new HashMap<String, int[]>());\r
+        }\r
+        Map<String, int[]> objectAnimations = animations.get(objectName);\r
+        if (objectAnimations == null) {\r
+            objectAnimations = new HashMap<String, int[]>();\r
+            animations.put(objectName, objectAnimations);\r
+        }\r
+        objectAnimations.put(name, new int[]{start, stop});\r
+    }\r
+\r
+    /**\r
+     * This method returns the animation frames boundaries.\r
+     * @param objectName\r
+     *        the name of animation's owner\r
+     * @param name\r
+     *        animation name\r
+     * @return animation frame boundaries in a table [start, stop] or null if animation of the given name does not\r
+     *         exists\r
+     */\r
+    public int[] getAnimationFrames(String objectName, String name) {\r
+        Map<String, int[]> objectAnimations = animations == null ? null : animations.get(objectName);\r
+        int[] frames = objectAnimations == null ? null : objectAnimations.get(name);\r
+        return frames == null ? null : frames.clone();\r
+    }\r
+\r
+    /**\r
+     * This method returns the animation names for the given object name.\r
+     * @param objectName\r
+     *        the name of the object\r
+     * @return an array of animations for this object\r
+     */\r
+    public Set<String> getAnimationNames(String objectName) {\r
+        Map<String, int[]> objectAnimations = animations == null ? null : animations.get(objectName);\r
+        return objectAnimations == null ? null : objectAnimations.keySet();\r
+    }\r
+\r
+    /**\r
+     * This method returns the animations map.\r
+     * @return the animations map\r
+     */\r
+    public Map<String, Map<String, int[]>> getAnimations() {\r
+        return animations;\r
+    }\r
+\r
+    /**\r
+     * This method returns frames per second amount. The default value is BlenderKey.DEFAULT_FPS = 25.\r
+     * @return the frames per second amount\r
+     */\r
+    public int getFps() {\r
+        return fps;\r
+    }\r
+\r
+    /**\r
+     * This method sets frames per second amount.\r
+     * @param fps\r
+     *        the frames per second amount\r
+     */\r
+    public void setFps(int fps) {\r
+        this.fps = fps;\r
+    }\r
+\r
+    /**\r
+     * This method sets the width of generated texture (in pixels). By default the value is 140 px.\r
+     * @param generatedTextureWidth\r
+     *        the width of generated texture\r
+     */\r
+    public void setGeneratedTextureWidth(int generatedTextureWidth) {\r
+        this.generatedTextureWidth = generatedTextureWidth;\r
+    }\r
+\r
+    /**\r
+     * This method returns the width of generated texture (in pixels). By default the value is 140 px.\r
+     * @return the width of generated texture\r
+     */\r
+    public int getGeneratedTextureWidth() {\r
+        return generatedTextureWidth;\r
+    }\r
+\r
+    /**\r
+     * This method sets the height of generated texture (in pixels). By default the value is 140 px.\r
+     * @param generatedTextureHeight\r
+     *        the height of generated texture\r
+     */\r
+    public void setGeneratedTextureHeight(int generatedTextureHeight) {\r
+        this.generatedTextureHeight = generatedTextureHeight;\r
+    }\r
+\r
+    /**\r
+     * This method returns the height of generated texture (in pixels). By default the value is 140 px.\r
+     * @return the height of generated texture\r
+     */\r
+    public int getGeneratedTextureHeight() {\r
+        return generatedTextureHeight;\r
+    }\r
+\r
+    /**\r
+     * This method returns the face cull mode.\r
+     * @return the face cull mode\r
+     */\r
+    public FaceCullMode getFaceCullMode() {\r
+        return faceCullMode;\r
+    }\r
+\r
+    /**\r
+     * This method sets the face cull mode.\r
+     * @param faceCullMode\r
+     *        the face cull mode\r
+     */\r
+    public void setFaceCullMode(FaceCullMode faceCullMode) {\r
+        this.faceCullMode = faceCullMode;\r
+    }\r
+\r
+    /**\r
+     * This method sets layers to be loaded.\r
+     * @param layersToLoad layers to be loaded\r
+     */\r
+    public void setLayersToLoad(int layersToLoad) {\r
+        this.layersToLoad = layersToLoad;\r
+    }\r
+\r
+    /**\r
+     * This method returns layers to be loaded.\r
+     * @return layers to be loaded\r
+     */\r
+    public int getLayersToLoad() {\r
+        return layersToLoad;\r
+    }\r
+\r
+    /**\r
+     * This method sets the asset root path.\r
+     * @param assetRootPath\r
+     *        the assets root path\r
+     */\r
+    public void setAssetRootPath(String assetRootPath) {\r
+        this.assetRootPath = assetRootPath;\r
+    }\r
+\r
+    /**\r
+     * This method returns the asset root path.\r
+     * @return the asset root path\r
+     */\r
+    public String getAssetRootPath() {\r
+        return assetRootPath;\r
+    }\r
+\r
+    /**\r
+     * This method adds features to be loaded.\r
+     * @param featuresToLoad\r
+     *        bitwise flag of FeaturesToLoad interface values\r
+     */\r
+    public void includeInLoading(int featuresToLoad) {\r
+        this.featuresToLoad |= featuresToLoad;\r
+    }\r
+\r
+    /**\r
+     * This method removes features from being loaded.\r
+     * @param featuresToLoad\r
+     *        bitwise flag of FeaturesToLoad interface values\r
+     */\r
+    public void excludeFromLoading(int featuresNotToLoad) {\r
+        this.featuresToLoad &= ~featuresNotToLoad;\r
+    }\r
+\r
+    /**\r
+     * This method returns bitwise value of FeaturesToLoad interface value. It describes features that will be loaded by\r
+     * the blender file loader.\r
+     * @return features that will be loaded by the blender file loader\r
+     */\r
+    public int getFeaturesToLoad() {\r
+        return featuresToLoad;\r
+    }\r
+\r
+    /**\r
+     * This method creates an object where loading results will be stores. Only those features will be allowed to store\r
+     * that were specified by features-to-load flag.\r
+     * @return an object to store loading results\r
+     */\r
+    public LoadingResults prepareLoadingResults() {\r
+        return new LoadingResults(featuresToLoad);\r
+    }\r
+\r
+    /**\r
+     * 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\r
+     * is up axis.\r
+     * @param fixUpAxis\r
+     *        the up axis state variable\r
+     */\r
+    public void setFixUpAxis(boolean fixUpAxis) {\r
+        this.fixUpAxis = fixUpAxis;\r
+    }\r
+\r
+    /**\r
+     * This method returns the fix up axis state. If set to true then Y is up axis. Otherwise the up i Z axis. By\r
+     * default Y is up axis.\r
+     * @return the up axis state variable\r
+     */\r
+    public boolean isFixUpAxis() {\r
+        return fixUpAxis;\r
+    }\r
+\r
+    /**\r
+     * This mehtod sets the name of the WORLD data block taht should be used during file loading. By default the name is\r
+     * not set. If no name is set or the given name does not occur in the file - the first WORLD data block will be used\r
+     * during loading (assumin any exists in the file).\r
+     * @param usedWorld\r
+     *        the name of the WORLD block used during loading\r
+     */\r
+    public void setUsedWorld(String usedWorld) {\r
+        this.usedWorld = usedWorld;\r
+    }\r
+\r
+    /**\r
+     * This mehtod returns the name of the WORLD data block taht should be used during file loading.\r
+     * @return the name of the WORLD block used during loading\r
+     */\r
+    public String getUsedWorld() {\r
+        return usedWorld;\r
+    }\r
+\r
+    /**\r
+     * This method sets the default material for objects.\r
+     * @param defaultMaterial\r
+     *        the default material\r
+     */\r
+    public void setDefaultMaterial(Material defaultMaterial) {\r
+        this.defaultMaterial = defaultMaterial;\r
+    }\r
+\r
+    /**\r
+     * This method returns the default material.\r
+     * @return the default material\r
+     */\r
+    public Material getDefaultMaterial() {\r
+        return defaultMaterial;\r
+    }\r
+\r
+    @Override\r
+    public void write(JmeExporter e) throws IOException {\r
+        super.write(e);\r
+        OutputCapsule oc = e.getCapsule(this);\r
+        //saving animations\r
+        oc.write(animations == null ? 0 : animations.size(), "anim-size", 0);\r
+        if (animations != null) {\r
+            int objectCounter = 0;\r
+            for (Entry<String, Map<String, int[]>> animEntry : animations.entrySet()) {\r
+                oc.write(animEntry.getKey(), "animated-object-" + objectCounter, null);\r
+                int animsAmount = animEntry.getValue().size();\r
+                oc.write(animsAmount, "anims-amount-" + objectCounter, 0);\r
+                for (Entry<String, int[]> animsEntry : animEntry.getValue().entrySet()) {\r
+                    oc.write(animsEntry.getKey(), "anim-name-" + objectCounter, null);\r
+                    oc.write(animsEntry.getValue(), "anim-frames-" + objectCounter, null);\r
+                }\r
+                ++objectCounter;\r
+            }\r
+        }\r
+        //saving the rest of the data\r
+        oc.write(fps, "fps", DEFAULT_FPS);\r
+        oc.write(featuresToLoad, "features-to-load", FeaturesToLoad.ALL);\r
+        oc.write(assetRootPath, "asset-root-path", null);\r
+        oc.write(fixUpAxis, "fix-up-axis", true);\r
+        oc.write(usedWorld, "used-world", null);\r
+        oc.write(defaultMaterial, "default-material", null);\r
+        oc.write(faceCullMode, "face-cull-mode", FaceCullMode.Off);\r
+        oc.write(layersToLoad, "layers-to-load", -1);\r
+    }\r
+\r
+    @Override\r
+    public void read(JmeImporter e) throws IOException {\r
+        super.read(e);\r
+        InputCapsule ic = e.getCapsule(this);\r
+        //reading animations\r
+        int animSize = ic.readInt("anim-size", 0);\r
+        if (animSize > 0) {\r
+            if (animations == null) {\r
+                animations = new HashMap<String, Map<String, int[]>>(animSize);\r
+            } else {\r
+                animations.clear();\r
+            }\r
+            for (int i = 0; i < animSize; ++i) {\r
+                String objectName = ic.readString("animated-object-" + i, null);\r
+                int animationsAmount = ic.readInt("anims-amount-" + i, 0);\r
+                Map<String, int[]> objectAnimations = new HashMap<String, int[]>(animationsAmount);\r
+                for (int j = 0; j < animationsAmount; ++j) {\r
+                    String animName = ic.readString("anim-name-" + i, null);\r
+                    int[] animFrames = ic.readIntArray("anim-frames-" + i, null);\r
+                    objectAnimations.put(animName, animFrames);\r
+                }\r
+                animations.put(objectName, objectAnimations);\r
+            }\r
+        }\r
+\r
+        //reading the rest of the data\r
+        fps = ic.readInt("fps", DEFAULT_FPS);\r
+        featuresToLoad = ic.readInt("features-to-load", FeaturesToLoad.ALL);\r
+        assetRootPath = ic.readString("asset-root-path", null);\r
+        fixUpAxis = ic.readBoolean("fix-up-axis", true);\r
+        usedWorld = ic.readString("used-world", null);\r
+        defaultMaterial = (Material) ic.readSavable("default-material", null);\r
+        faceCullMode = ic.readEnum("face-cull-mode", FaceCullMode.class, FaceCullMode.Off);\r
+        layersToLoad = ic.readInt("layers-to=load", -1);\r
+    }\r
+\r
+    @Override\r
+    public int hashCode() {\r
+        final int prime = 31;\r
+        int result = super.hashCode();\r
+        result = prime * result + (animations == null ? 0 : animations.hashCode());\r
+        result = prime * result + (assetRootPath == null ? 0 : assetRootPath.hashCode());\r
+        result = prime * result + (defaultMaterial == null ? 0 : defaultMaterial.hashCode());\r
+        result = prime * result + (faceCullMode == null ? 0 : faceCullMode.hashCode());\r
+        result = prime * result + featuresToLoad;\r
+        result = prime * result + (fixUpAxis ? 1231 : 1237);\r
+        result = prime * result + fps;\r
+        result = prime * result + generatedTextureHeight;\r
+        result = prime * result + generatedTextureWidth;\r
+        result = prime * result + layersToLoad;\r
+        result = prime * result + (usedWorld == null ? 0 : usedWorld.hashCode());\r
+        return result;\r
+    }\r
+\r
+    @Override\r
+    public boolean equals(Object obj) {\r
+        if (this == obj) {\r
+            return true;\r
+        }\r
+        if (!super.equals(obj)) {\r
+            return false;\r
+        }\r
+        if (this.getClass() != obj.getClass()) {\r
+            return false;\r
+        }\r
+        BlenderKey other = (BlenderKey) obj;\r
+        if (animations == null) {\r
+            if (other.animations != null) {\r
+                return false;\r
+            }\r
+        } else if (!animations.equals(other.animations)) {\r
+            return false;\r
+        }\r
+        if (assetRootPath == null) {\r
+            if (other.assetRootPath != null) {\r
+                return false;\r
+            }\r
+        } else if (!assetRootPath.equals(other.assetRootPath)) {\r
+            return false;\r
+        }\r
+        if (defaultMaterial == null) {\r
+            if (other.defaultMaterial != null) {\r
+                return false;\r
+            }\r
+        } else if (!defaultMaterial.equals(other.defaultMaterial)) {\r
+            return false;\r
+        }\r
+        if (faceCullMode != other.faceCullMode) {\r
+            return false;\r
+        }\r
+        if (featuresToLoad != other.featuresToLoad) {\r
+            return false;\r
+        }\r
+        if (fixUpAxis != other.fixUpAxis) {\r
+            return false;\r
+        }\r
+        if (fps != other.fps) {\r
+            return false;\r
+        }\r
+        if (generatedTextureHeight != other.generatedTextureHeight) {\r
+            return false;\r
+        }\r
+        if (generatedTextureWidth != other.generatedTextureWidth) {\r
+            return false;\r
+        }\r
+        if (layersToLoad != other.layersToLoad) {\r
+            return false;\r
+        }\r
+        if (usedWorld == null) {\r
+            if (other.usedWorld != null) {\r
+                return false;\r
+            }\r
+        } else if (!usedWorld.equals(other.usedWorld)) {\r
+            return false;\r
+        }\r
+        return true;\r
+    }\r
+\r
+    /**\r
+     * This interface describes the features of the scene that are to be loaded.\r
+     * @author Marcin Roguski (Kaelthas)\r
+     */\r
+    public static interface FeaturesToLoad {\r
+\r
+        int SCENES = 0x0000FFFF;\r
+        int OBJECTS = 0x0000000B;\r
+        int ANIMATIONS = 0x00000004;\r
+        int MATERIALS = 0x00000003;\r
+        int TEXTURES = 0x00000001;\r
+        int CAMERAS = 0x00000020;\r
+        int LIGHTS = 0x00000010;\r
+        int ALL = 0xFFFFFFFF;\r
+    }\r
+\r
+    /**\r
+     * This class holds the loading results according to the given loading flag.\r
+     * @author Marcin Roguski (Kaelthas)\r
+     */\r
+    public static class LoadingResults extends Spatial {\r
+\r
+        /** Bitwise mask of features that are to be loaded. */\r
+        private final int featuresToLoad;\r
+        /** The scenes from the file. */\r
+        private List<Node> scenes;\r
+        /** Objects from all scenes. */\r
+        private List<Node> objects;\r
+        /** Materials from all objects. */\r
+        private List<Material> materials;\r
+        /** Textures from all objects. */\r
+        private List<Texture> textures;\r
+        /** Animations of all objects. */\r
+        private List<AnimData> animations;\r
+        /** All cameras from the file. */\r
+        private List<Camera> cameras;\r
+        /** All lights from the file. */\r
+        private List<Light> lights;\r
+\r
+        /**\r
+         * Private constructor prevents users to create an instance of this class from outside the\r
+         * @param featuresToLoad\r
+         *        bitwise mask of features that are to be loaded\r
+         * @see FeaturesToLoad FeaturesToLoad\r
+         */\r
+        private LoadingResults(int featuresToLoad) {\r
+            this.featuresToLoad = featuresToLoad;\r
+            if ((featuresToLoad & FeaturesToLoad.SCENES) != 0) {\r
+                scenes = new ArrayList<Node>();\r
+            }\r
+            if ((featuresToLoad & FeaturesToLoad.OBJECTS) != 0) {\r
+                objects = new ArrayList<Node>();\r
+                if ((featuresToLoad & FeaturesToLoad.MATERIALS) != 0) {\r
+                    materials = new ArrayList<Material>();\r
+                    if ((featuresToLoad & FeaturesToLoad.TEXTURES) != 0) {\r
+                        textures = new ArrayList<Texture>();\r
+                    }\r
+                }\r
+                if ((featuresToLoad & FeaturesToLoad.ANIMATIONS) != 0) {\r
+                    animations = new ArrayList<AnimData>();\r
+                }\r
+            }\r
+            if ((featuresToLoad & FeaturesToLoad.CAMERAS) != 0) {\r
+                cameras = new ArrayList<Camera>();\r
+            }\r
+            if ((featuresToLoad & FeaturesToLoad.LIGHTS) != 0) {\r
+                lights = new ArrayList<Light>();\r
+            }\r
+        }\r
+\r
+        /**\r
+         * This method returns a bitwise flag describing what features of the blend file will be included in the result.\r
+         * @return bitwise mask of features that are to be loaded\r
+         * @see FeaturesToLoad FeaturesToLoad\r
+         */\r
+        public int getLoadedFeatures() {\r
+            return featuresToLoad;\r
+        }\r
+\r
+        /**\r
+         * This method adds a scene to the result set.\r
+         * @param scene\r
+         *        scene to be added to the result set\r
+         */\r
+        public void addScene(Node scene) {\r
+            if (scenes != null) {\r
+                scenes.add(scene);\r
+            }\r
+        }\r
+\r
+        /**\r
+         * This method adds an object to the result set.\r
+         * @param object\r
+         *        object to be added to the result set\r
+         */\r
+        public void addObject(Node object) {\r
+            if (objects != null) {\r
+                objects.add(object);\r
+            }\r
+        }\r
+\r
+        /**\r
+         * This method adds a material to the result set.\r
+         * @param material\r
+         *        material to be added to the result set\r
+         */\r
+        public void addMaterial(Material material) {\r
+            if (materials != null) {\r
+                materials.add(material);\r
+            }\r
+        }\r
+\r
+        /**\r
+         * This method adds a texture to the result set.\r
+         * @param texture\r
+         *        texture to be added to the result set\r
+         */\r
+        public void addTexture(Texture texture) {\r
+            if (textures != null) {\r
+                textures.add(texture);\r
+            }\r
+        }\r
+\r
+        /**\r
+         * This method adds a camera to the result set.\r
+         * @param camera\r
+         *        camera to be added to the result set\r
+         */\r
+        public void addCamera(Camera camera) {\r
+            if (cameras != null) {\r
+                cameras.add(camera);\r
+            }\r
+        }\r
+\r
+        /**\r
+         * This method adds a light to the result set.\r
+         * @param light\r
+         *        light to be added to the result set\r
+         */\r
+        @Override\r
+        public void addLight(Light light) {\r
+            if (lights != null) {\r
+                lights.add(light);\r
+            }\r
+        }\r
+\r
+        /**\r
+         * This method returns all loaded scenes.\r
+         * @return all loaded scenes\r
+         */\r
+        public List<Node> getScenes() {\r
+            return scenes;\r
+        }\r
+\r
+        /**\r
+         * This method returns all loaded objects.\r
+         * @return all loaded objects\r
+         */\r
+        public List<Node> getObjects() {\r
+            return objects;\r
+        }\r
+\r
+        /**\r
+         * This method returns all loaded materials.\r
+         * @return all loaded materials\r
+         */\r
+        public List<Material> getMaterials() {\r
+            return materials;\r
+        }\r
+\r
+        /**\r
+         * This method returns all loaded textures.\r
+         * @return all loaded textures\r
+         */\r
+        public List<Texture> getTextures() {\r
+            return textures;\r
+        }\r
+\r
+        /**\r
+         * This method returns all loaded animations.\r
+         * @return all loaded animations\r
+         */\r
+        public List<AnimData> getAnimations() {\r
+            return animations;\r
+        }\r
+\r
+        /**\r
+         * This method returns all loaded cameras.\r
+         * @return all loaded cameras\r
+         */\r
+        public List<Camera> getCameras() {\r
+            return cameras;\r
+        }\r
+\r
+        /**\r
+         * This method returns all loaded lights.\r
+         * @return all loaded lights\r
+         */\r
+        public List<Light> getLights() {\r
+            return lights;\r
+        }\r
+\r
+        @Override\r
+        public int collideWith(Collidable other, CollisionResults results) throws UnsupportedCollisionException {\r
+            return 0;\r
+        }\r
+\r
+        @Override\r
+        public void updateModelBound() {\r
+        }\r
+\r
+        @Override\r
+        public void setModelBound(BoundingVolume modelBound) {\r
+        }\r
+\r
+        @Override\r
+        public int getVertexCount() {\r
+            return 0;\r
+        }\r
+\r
+        @Override\r
+        public int getTriangleCount() {\r
+            return 0;\r
+        }\r
+\r
+        @Override\r
+        public Spatial deepClone() {\r
+            return null;\r
+        }\r
+\r
+        @Override\r
+        public void depthFirstTraversal(SceneGraphVisitor visitor) {\r
+        }\r
+\r
+        @Override\r
+        protected void breadthFirstTraversal(SceneGraphVisitor visitor, Queue<Spatial> queue) {\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The WORLD file block contains various data that could be added to the scene. The contained data includes: ambient\r
+     * light.\r
+     * @author Marcin Roguski (Kaelthas)\r
+     */\r
+    public static class WorldData {\r
+\r
+        /** The ambient light. */\r
+        private AmbientLight ambientLight;\r
+\r
+        /**\r
+         * This method returns the world's ambient light.\r
+         * @return the world's ambient light\r
+         */\r
+        public AmbientLight getAmbientLight() {\r
+            return ambientLight;\r
+        }\r
+\r
+        /**\r
+         * This method sets the world's ambient light.\r
+         * @param ambientLight\r
+         *        the world's ambient light\r
+         */\r
+        public void setAmbientLight(AmbientLight ambientLight) {\r
+            this.ambientLight = ambientLight;\r
+        }\r
+    }\r
 }\r
index bc8a51b..e8dee73 100644 (file)
@@ -72,122 +72,123 @@ import com.jme3.scene.plugins.blender.utils.JmeConverter;
  * @author Marcin Roguski\r
  */\r
 public class BlenderLoader implements AssetLoader {\r
-       private static final Logger     LOGGER  = Logger.getLogger(BlenderLoader.class.getName());\r
 \r
-       @Override\r
-       public LoadingResults load(AssetInfo assetInfo) throws IOException {\r
-               try {\r
-                       //registering loaders\r
-                       ModelKey modelKey = (ModelKey)assetInfo.getKey();\r
-                       BlenderKey blenderKey;\r
-                       if(modelKey instanceof BlenderKey) {\r
-                               blenderKey = (BlenderKey)modelKey;\r
-                       } else {\r
-                               blenderKey = new BlenderKey(modelKey.getName());\r
-                               blenderKey.setAssetRootPath(modelKey.getFolder());\r
-                       }\r
+    private static final Logger LOGGER = Logger.getLogger(BlenderLoader.class.getName());\r
 \r
-                       //opening stream\r
-                       BlenderInputStream inputStream = new BlenderInputStream(assetInfo.openStream(), assetInfo.getManager());\r
+    @Override\r
+    public LoadingResults load(AssetInfo assetInfo) throws IOException {\r
+        try {\r
+            //registering loaders\r
+            ModelKey modelKey = (ModelKey) assetInfo.getKey();\r
+            BlenderKey blenderKey;\r
+            if (modelKey instanceof BlenderKey) {\r
+                blenderKey = (BlenderKey) modelKey;\r
+            } else {\r
+                blenderKey = new BlenderKey(modelKey.getName());\r
+                blenderKey.setAssetRootPath(modelKey.getFolder());\r
+            }\r
 \r
-                       //reading blocks\r
-                       List<FileBlockHeader> blocks = new ArrayList<FileBlockHeader>();\r
-                       FileBlockHeader fileBlock;\r
-                       DataRepository dataRepository = new DataRepository();\r
-                       dataRepository.setAssetManager(assetInfo.getManager());\r
-                       dataRepository.setInputStream(inputStream);\r
-                       dataRepository.setBlenderKey(blenderKey);\r
-                       \r
-                       //creating helpers\r
-                       dataRepository.putHelper(ArmatureHelper.class, new ArmatureHelper(inputStream.getVersionNumber()));\r
-                       dataRepository.putHelper(TextureHelper.class, new TextureHelper(inputStream.getVersionNumber()));\r
-                       dataRepository.putHelper(MeshHelper.class, new MeshHelper(inputStream.getVersionNumber()));\r
-                       dataRepository.putHelper(ObjectHelper.class, new ObjectHelper(inputStream.getVersionNumber()));\r
-                       dataRepository.putHelper(CurvesHelper.class, new CurvesHelper(inputStream.getVersionNumber()));\r
-                       dataRepository.putHelper(LightHelper.class, new LightHelper(inputStream.getVersionNumber()));\r
-                       dataRepository.putHelper(CameraHelper.class, new CameraHelper(inputStream.getVersionNumber()));\r
-                       dataRepository.putHelper(ModifierHelper.class, new ModifierHelper(inputStream.getVersionNumber()));\r
-                       dataRepository.putHelper(MaterialHelper.class, new MaterialHelper(inputStream.getVersionNumber()));\r
-                       dataRepository.putHelper(ConstraintHelper.class, new ConstraintHelper(inputStream.getVersionNumber(), dataRepository));\r
-                       dataRepository.putHelper(IpoHelper.class, new IpoHelper(inputStream.getVersionNumber()));\r
-                       dataRepository.putHelper(NoiseHelper.class, new NoiseHelper(inputStream.getVersionNumber()));\r
-                       dataRepository.putHelper(ParticlesHelper.class, new ParticlesHelper(inputStream.getVersionNumber()));\r
-                       \r
-                       //setting additional data to helpers\r
-                       if(blenderKey.isFixUpAxis()) {\r
-                               ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);\r
-                               objectHelper.setyIsUpAxis(true);\r
-                               CurvesHelper curvesHelper = dataRepository.getHelper(CurvesHelper.class);\r
-                               curvesHelper.setyIsUpAxis(true);\r
-                       }\r
-                       MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);\r
-                       materialHelper.setFaceCullMode(blenderKey.getFaceCullMode());\r
+            //opening stream\r
+            BlenderInputStream inputStream = new BlenderInputStream(assetInfo.openStream(), assetInfo.getManager());\r
 \r
-                       //reading the blocks (dna block is automatically saved in the data repository when found)//TODO: zmienić to\r
-                       do {\r
-                               fileBlock = new FileBlockHeader(inputStream, dataRepository);\r
-                               if(!fileBlock.isDnaBlock()) {\r
-                                       blocks.add(fileBlock);\r
-                               }\r
-                       } while(!fileBlock.isLastBlock());\r
+            //reading blocks\r
+            List<FileBlockHeader> blocks = new ArrayList<FileBlockHeader>();\r
+            FileBlockHeader fileBlock;\r
+            DataRepository dataRepository = new DataRepository();\r
+            dataRepository.setAssetManager(assetInfo.getManager());\r
+            dataRepository.setInputStream(inputStream);\r
+            dataRepository.setBlenderKey(blenderKey);\r
 \r
-                       JmeConverter converter = new JmeConverter(dataRepository);\r
-                       LoadingResults loadingResults = blenderKey.prepareLoadingResults();\r
-                       WorldData worldData = null;//a set of data used in different scene aspects\r
-                       for(FileBlockHeader block : blocks) {\r
-                               switch(block.getCode()) {\r
-                                       case FileBlockHeader.BLOCK_OB00://Object\r
-                                               Object object = converter.toObject(block.getStructure(dataRepository));\r
-                                               if(object instanceof Node) {\r
-                                                       if((blenderKey.getFeaturesToLoad() & FeaturesToLoad.OBJECTS) != 0) {\r
-                                                               LOGGER.log(Level.INFO, ((Node)object).getName() + ": " + ((Node)object).getLocalTranslation().toString() + "--> " + (((Node)object).getParent() == null ? "null" : ((Node)object).getParent().getName()));\r
-                                                               if(((Node)object).getParent() == null) {\r
-                                                                       loadingResults.addObject((Node)object);\r
-                                                               }\r
-                                                       }\r
-                                               } else if(object instanceof Camera) {\r
-                                                       if((blenderKey.getFeaturesToLoad() & FeaturesToLoad.CAMERAS) != 0) {\r
-                                                               loadingResults.addCamera((Camera)object);\r
-                                                       }\r
-                                               } else if(object instanceof Light) {\r
-                                                       if((blenderKey.getFeaturesToLoad() & FeaturesToLoad.LIGHTS) != 0) {\r
-                                                               loadingResults.addLight((Light)object);\r
-                                                       }\r
-                                               }\r
-                                               break;\r
-                                       case FileBlockHeader.BLOCK_MA00://Material\r
-                                               if((blenderKey.getFeaturesToLoad() & FeaturesToLoad.MATERIALS) != 0) {\r
-                                                       loadingResults.addMaterial(converter.toMaterial(block.getStructure(dataRepository)));\r
-                                               }\r
-                                               break;\r
-                                       case FileBlockHeader.BLOCK_SC00://Scene\r
-                                               if((blenderKey.getFeaturesToLoad() & FeaturesToLoad.SCENES) != 0) {\r
-                                                       loadingResults.addScene(converter.toScene(block.getStructure(dataRepository)));\r
-                                               }\r
-                                               break;\r
-                                       case FileBlockHeader.BLOCK_WO00://World\r
-                                               if(worldData == null) {//onlu one world data is used\r
-                                                       Structure worldStructure = block.getStructure(dataRepository);\r
-                                                       String worldName = worldStructure.getName();\r
-                                                       if(blenderKey.getUsedWorld() == null || blenderKey.getUsedWorld().equals(worldName)) {\r
-                                                               worldData = converter.toWorldData(worldStructure);\r
-                                                               if((blenderKey.getFeaturesToLoad() & FeaturesToLoad.LIGHTS) != 0) {\r
-                                                                       loadingResults.addLight(worldData.getAmbientLight());\r
-                                                               }\r
-                                                       }\r
-                                               }\r
-                                               break;\r
-                               }\r
-                       }\r
-                       try {\r
-                               inputStream.close();\r
-                       } catch(IOException e) {\r
-                               LOGGER.log(Level.SEVERE, e.getMessage(), e);\r
-                       }\r
-                       return loadingResults;\r
-               } catch(BlenderFileException e) {\r
-                       LOGGER.log(Level.SEVERE, e.getMessage(), e);\r
-               }\r
-               return null;\r
-       }\r
+            //creating helpers\r
+            dataRepository.putHelper(ArmatureHelper.class, new ArmatureHelper(inputStream.getVersionNumber()));\r
+            dataRepository.putHelper(TextureHelper.class, new TextureHelper(inputStream.getVersionNumber()));\r
+            dataRepository.putHelper(MeshHelper.class, new MeshHelper(inputStream.getVersionNumber()));\r
+            dataRepository.putHelper(ObjectHelper.class, new ObjectHelper(inputStream.getVersionNumber()));\r
+            dataRepository.putHelper(CurvesHelper.class, new CurvesHelper(inputStream.getVersionNumber()));\r
+            dataRepository.putHelper(LightHelper.class, new LightHelper(inputStream.getVersionNumber()));\r
+            dataRepository.putHelper(CameraHelper.class, new CameraHelper(inputStream.getVersionNumber()));\r
+            dataRepository.putHelper(ModifierHelper.class, new ModifierHelper(inputStream.getVersionNumber()));\r
+            dataRepository.putHelper(MaterialHelper.class, new MaterialHelper(inputStream.getVersionNumber()));\r
+            dataRepository.putHelper(ConstraintHelper.class, new ConstraintHelper(inputStream.getVersionNumber(), dataRepository));\r
+            dataRepository.putHelper(IpoHelper.class, new IpoHelper(inputStream.getVersionNumber()));\r
+            dataRepository.putHelper(NoiseHelper.class, new NoiseHelper(inputStream.getVersionNumber()));\r
+            dataRepository.putHelper(ParticlesHelper.class, new ParticlesHelper(inputStream.getVersionNumber()));\r
+\r
+            //setting additional data to helpers\r
+            if (blenderKey.isFixUpAxis()) {\r
+                ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);\r
+                objectHelper.setyIsUpAxis(true);\r
+                CurvesHelper curvesHelper = dataRepository.getHelper(CurvesHelper.class);\r
+                curvesHelper.setyIsUpAxis(true);\r
+            }\r
+            MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);\r
+            materialHelper.setFaceCullMode(blenderKey.getFaceCullMode());\r
+\r
+            //reading the blocks (dna block is automatically saved in the data repository when found)//TODO: zmienić to\r
+            do {\r
+                fileBlock = new FileBlockHeader(inputStream, dataRepository);\r
+                if (!fileBlock.isDnaBlock()) {\r
+                    blocks.add(fileBlock);\r
+                }\r
+            } while (!fileBlock.isLastBlock());\r
+\r
+            JmeConverter converter = new JmeConverter(dataRepository);\r
+            LoadingResults loadingResults = blenderKey.prepareLoadingResults();\r
+            WorldData worldData = null;//a set of data used in different scene aspects\r
+            for (FileBlockHeader block : blocks) {\r
+                switch (block.getCode()) {\r
+                    case FileBlockHeader.BLOCK_OB00://Object\r
+                        Object object = converter.toObject(block.getStructure(dataRepository));\r
+                        if (object instanceof Node) {\r
+                            if ((blenderKey.getFeaturesToLoad() & FeaturesToLoad.OBJECTS) != 0) {\r
+                                LOGGER.log(Level.INFO, "{0}: {1}--> {2}", new Object[]{((Node) object).getName(), ((Node) object).getLocalTranslation().toString(), ((Node) object).getParent() == null ? "null" : ((Node) object).getParent().getName()});\r
+                                if (((Node) object).getParent() == null) {\r
+                                    loadingResults.addObject((Node) object);\r
+                                }\r
+                            }\r
+                        } else if (object instanceof Camera) {\r
+                            if ((blenderKey.getFeaturesToLoad() & FeaturesToLoad.CAMERAS) != 0) {\r
+                                loadingResults.addCamera((Camera) object);\r
+                            }\r
+                        } else if (object instanceof Light) {\r
+                            if ((blenderKey.getFeaturesToLoad() & FeaturesToLoad.LIGHTS) != 0) {\r
+                                loadingResults.addLight((Light) object);\r
+                            }\r
+                        }\r
+                        break;\r
+                    case FileBlockHeader.BLOCK_MA00://Material\r
+                        if ((blenderKey.getFeaturesToLoad() & FeaturesToLoad.MATERIALS) != 0) {\r
+                            loadingResults.addMaterial(converter.toMaterial(block.getStructure(dataRepository)));\r
+                        }\r
+                        break;\r
+                    case FileBlockHeader.BLOCK_SC00://Scene\r
+                        if ((blenderKey.getFeaturesToLoad() & FeaturesToLoad.SCENES) != 0) {\r
+                            loadingResults.addScene(converter.toScene(block.getStructure(dataRepository)));\r
+                        }\r
+                        break;\r
+                    case FileBlockHeader.BLOCK_WO00://World\r
+                        if (worldData == null) {//onlu one world data is used\r
+                            Structure worldStructure = block.getStructure(dataRepository);\r
+                            String worldName = worldStructure.getName();\r
+                            if (blenderKey.getUsedWorld() == null || blenderKey.getUsedWorld().equals(worldName)) {\r
+                                worldData = converter.toWorldData(worldStructure);\r
+                                if ((blenderKey.getFeaturesToLoad() & FeaturesToLoad.LIGHTS) != 0) {\r
+                                    loadingResults.addLight(worldData.getAmbientLight());\r
+                                }\r
+                            }\r
+                        }\r
+                        break;\r
+                }\r
+            }\r
+            try {\r
+                inputStream.close();\r
+            } catch (IOException e) {\r
+                LOGGER.log(Level.SEVERE, e.getMessage(), e);\r
+            }\r
+            return loadingResults;\r
+        } catch (BlenderFileException e) {\r
+            LOGGER.log(Level.SEVERE, e.getMessage(), e);\r
+        }\r
+        return null;\r
+    }\r
 }\r
index 096ec23..a6e0a03 100644 (file)
@@ -69,89 +69,90 @@ import com.jme3.scene.plugins.blender.utils.JmeConverter;
  * @author Marcin Roguski
  */
 public class BlenderModelLoader implements AssetLoader {
-       private static final Logger     LOGGER  = Logger.getLogger(BlenderModelLoader.class.getName());
 
-       @Override
-       public Spatial load(AssetInfo assetInfo) throws IOException {
-               try {
-                       //registering loaders
-                       ModelKey modelKey = (ModelKey)assetInfo.getKey();
-                       BlenderKey blenderKey;
-                       if(modelKey instanceof BlenderKey) {
-                               blenderKey = (BlenderKey)modelKey;
-                       } else {
-                               blenderKey = new BlenderKey(modelKey.getName());
-                               blenderKey.setAssetRootPath(modelKey.getFolder());
-                       }
+    private static final Logger LOGGER = Logger.getLogger(BlenderModelLoader.class.getName());
 
-                       //opening stream
-                       BlenderInputStream inputStream = new BlenderInputStream(assetInfo.openStream(), assetInfo.getManager());
-                       List<FileBlockHeader> blocks = new ArrayList<FileBlockHeader>();
-                       FileBlockHeader fileBlock;
-                       DataRepository dataRepository = new DataRepository();
-                       dataRepository.setAssetManager(assetInfo.getManager());
-                       dataRepository.setInputStream(inputStream);
-                       dataRepository.setBlenderKey(blenderKey);
-                       dataRepository.putHelper(ArmatureHelper.class, new ArmatureHelper(inputStream.getVersionNumber()));
-                       dataRepository.putHelper(TextureHelper.class, new TextureHelper(inputStream.getVersionNumber()));
-                       dataRepository.putHelper(MeshHelper.class, new MeshHelper(inputStream.getVersionNumber()));
-                       dataRepository.putHelper(ObjectHelper.class, new ObjectHelper(inputStream.getVersionNumber()));
-                       dataRepository.putHelper(CurvesHelper.class, new CurvesHelper(inputStream.getVersionNumber()));
-                       dataRepository.putHelper(LightHelper.class, new LightHelper(inputStream.getVersionNumber()));
-                       dataRepository.putHelper(CameraHelper.class, new CameraHelper(inputStream.getVersionNumber()));
-                       dataRepository.putHelper(ModifierHelper.class, new ModifierHelper(inputStream.getVersionNumber()));
-                       dataRepository.putHelper(MaterialHelper.class, new MaterialHelper(inputStream.getVersionNumber()));
-                       dataRepository.putHelper(ConstraintHelper.class, new ConstraintHelper(inputStream.getVersionNumber(), dataRepository));
-                       dataRepository.putHelper(IpoHelper.class, new IpoHelper(inputStream.getVersionNumber()));
-                       dataRepository.putHelper(NoiseHelper.class, new NoiseHelper(inputStream.getVersionNumber()));
-                       dataRepository.putHelper(ParticlesHelper.class, new ParticlesHelper(inputStream.getVersionNumber()));
-                       
-                       //setting additional data to helpers
-                       if(blenderKey.isFixUpAxis()) {
-                               ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);
-                               objectHelper.setyIsUpAxis(true);
-                               CurvesHelper curvesHelper = dataRepository.getHelper(CurvesHelper.class);
-                               curvesHelper.setyIsUpAxis(true);
-                       }
-                       MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);
-                       materialHelper.setFaceCullMode(blenderKey.getFaceCullMode());
+    @Override
+    public Spatial load(AssetInfo assetInfo) throws IOException {
+        try {
+            //registering loaders
+            ModelKey modelKey = (ModelKey) assetInfo.getKey();
+            BlenderKey blenderKey;
+            if (modelKey instanceof BlenderKey) {
+                blenderKey = (BlenderKey) modelKey;
+            } else {
+                blenderKey = new BlenderKey(modelKey.getName());
+                blenderKey.setAssetRootPath(modelKey.getFolder());
+            }
 
-                       //reading the blocks (dna block is automatically saved in the data repository when found)//TODO: zmienić to
-                       do {
-                               fileBlock = new FileBlockHeader(inputStream, dataRepository);
-                               if(!fileBlock.isDnaBlock()) {
-                                       blocks.add(fileBlock);
-                               }
-                       } while(!fileBlock.isLastBlock());
+            //opening stream
+            BlenderInputStream inputStream = new BlenderInputStream(assetInfo.openStream(), assetInfo.getManager());
+            List<FileBlockHeader> blocks = new ArrayList<FileBlockHeader>();
+            FileBlockHeader fileBlock;
+            DataRepository dataRepository = new DataRepository();
+            dataRepository.setAssetManager(assetInfo.getManager());
+            dataRepository.setInputStream(inputStream);
+            dataRepository.setBlenderKey(blenderKey);
+            dataRepository.putHelper(ArmatureHelper.class, new ArmatureHelper(inputStream.getVersionNumber()));
+            dataRepository.putHelper(TextureHelper.class, new TextureHelper(inputStream.getVersionNumber()));
+            dataRepository.putHelper(MeshHelper.class, new MeshHelper(inputStream.getVersionNumber()));
+            dataRepository.putHelper(ObjectHelper.class, new ObjectHelper(inputStream.getVersionNumber()));
+            dataRepository.putHelper(CurvesHelper.class, new CurvesHelper(inputStream.getVersionNumber()));
+            dataRepository.putHelper(LightHelper.class, new LightHelper(inputStream.getVersionNumber()));
+            dataRepository.putHelper(CameraHelper.class, new CameraHelper(inputStream.getVersionNumber()));
+            dataRepository.putHelper(ModifierHelper.class, new ModifierHelper(inputStream.getVersionNumber()));
+            dataRepository.putHelper(MaterialHelper.class, new MaterialHelper(inputStream.getVersionNumber()));
+            dataRepository.putHelper(ConstraintHelper.class, new ConstraintHelper(inputStream.getVersionNumber(), dataRepository));
+            dataRepository.putHelper(IpoHelper.class, new IpoHelper(inputStream.getVersionNumber()));
+            dataRepository.putHelper(NoiseHelper.class, new NoiseHelper(inputStream.getVersionNumber()));
+            dataRepository.putHelper(ParticlesHelper.class, new ParticlesHelper(inputStream.getVersionNumber()));
 
-                       JmeConverter converter = new JmeConverter(dataRepository);
-                       LoadingResults loadingResults = blenderKey.prepareLoadingResults();
-                       for(FileBlockHeader block : blocks) {
-                               if(block.getCode() == FileBlockHeader.BLOCK_OB00) {
-                                       Object object = converter.toObject(block.getStructure(dataRepository));
-                                       if(object instanceof Node) {
-                                               LOGGER.log(Level.INFO, ((Node)object).getName() + ": " + ((Node)object).getLocalTranslation().toString() + "--> " + (((Node)object).getParent() == null ? "null" : ((Node)object).getParent().getName()));
-                                               if(((Node)object).getParent() == null) {
-                                                       loadingResults.addObject((Node)object);
-                                               }
-                                       }
-                               }
-                       }
-                       inputStream.close();
-                       List<Node> objects = loadingResults.getObjects();
-                       if(objects.size() > 0) {
-                               Node modelNode = new Node(blenderKey.getName());
-                               for(Iterator<Node> it = objects.iterator(); it.hasNext();) {
-                                       Node node = it.next();
-                                       modelNode.attachChild(node);
-                               }
-                               return modelNode;
-                       } else if(objects.size() == 1) {
-                               return objects.get(0);
-                       }
-               } catch(BlenderFileException e) {
-                       LOGGER.log(Level.SEVERE, e.getMessage(), e);
-               }
-               return null;
-       }
+            //setting additional data to helpers
+            if (blenderKey.isFixUpAxis()) {
+                ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);
+                objectHelper.setyIsUpAxis(true);
+                CurvesHelper curvesHelper = dataRepository.getHelper(CurvesHelper.class);
+                curvesHelper.setyIsUpAxis(true);
+            }
+            MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);
+            materialHelper.setFaceCullMode(blenderKey.getFaceCullMode());
+
+            //reading the blocks (dna block is automatically saved in the data repository when found)//TODO: zmienić to
+            do {
+                fileBlock = new FileBlockHeader(inputStream, dataRepository);
+                if (!fileBlock.isDnaBlock()) {
+                    blocks.add(fileBlock);
+                }
+            } while (!fileBlock.isLastBlock());
+
+            JmeConverter converter = new JmeConverter(dataRepository);
+            LoadingResults loadingResults = blenderKey.prepareLoadingResults();
+            for (FileBlockHeader block : blocks) {
+                if (block.getCode() == FileBlockHeader.BLOCK_OB00) {
+                    Object object = converter.toObject(block.getStructure(dataRepository));
+                    if (object instanceof Node) {
+                        LOGGER.log(Level.INFO, "{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) {
+                            loadingResults.addObject((Node) object);
+                        }
+                    }
+                }
+            }
+            inputStream.close();
+            List<Node> objects = loadingResults.getObjects();
+            if (objects.size() > 0) {
+                Node modelNode = new Node(blenderKey.getName());
+                for (Iterator<Node> it = objects.iterator(); it.hasNext();) {
+                    Node node = it.next();
+                    modelNode.attachChild(node);
+                }
+                return modelNode;
+            } else if (objects.size() == 1) {
+                return objects.get(0);
+            }
+        } catch (BlenderFileException e) {
+            LOGGER.log(Level.SEVERE, e.getMessage(), e);
+        }
+        return null;
+    }
 }
index 5872039..8f72f6d 100644 (file)
@@ -43,168 +43,168 @@ import com.jme3.scene.plugins.blender.utils.DataRepository;
  * @author Marcin Roguski\r
  */\r
 public class DnaBlockData {\r
-       private static final int                                SDNA_ID = 'S' << 24 | 'D' << 16 | 'N' << 8 | 'A';       //SDNA\r
-       private static final int                                NAME_ID = 'N' << 24 | 'A' << 16 | 'M' << 8 | 'E';       //NAME\r
-       private static final int                                TYPE_ID = 'T' << 24 | 'Y' << 16 | 'P' << 8 | 'E';       //TYPE\r
-       private static final int                                TLEN_ID = 'T' << 24 | 'L' << 16 | 'E' << 8 | 'N';       //TLEN\r
-       private static final int                                STRC_ID = 'S' << 24 | 'T' << 16 | 'R' << 8 | 'C';       //STRC\r
-\r
-       /** Structures available inside the file. */\r
-       private final Structure[]                               structures;\r
-       /** A map that helps finding a structure by type. */\r
-       private final Map<String, Structure>    structuresMap;\r
-\r
-       /**\r
-        * Constructor. Loads the block from the given stream during instance creation.\r
-        * @param inputStream\r
-        *        the stream we read the block from\r
-        * @param dataRepository\r
-        *        the data repository\r
-        * @throws BlenderFileException\r
-        *         this exception is throw if the blend file is invalid or somehow corrupted\r
-        */\r
-       public DnaBlockData(BlenderInputStream inputStream, DataRepository dataRepository) throws BlenderFileException {\r
-               int identifier;\r
-\r
-               //reading 'SDNA' identifier\r
-               identifier = inputStream.readByte() << 24 | inputStream.readByte() << 16 |\r
-                                        inputStream.readByte() << 8 | inputStream.readByte();\r
-\r
-               if(identifier != SDNA_ID) {\r
-                       throw new BlenderFileException("Invalid identifier! '" + this.toString(SDNA_ID) + "' expected and found: " + this.toString(identifier));\r
-               }\r
-\r
-               //reading names\r
-               identifier = inputStream.readByte() << 24 | inputStream.readByte() << 16 |\r
-                                        inputStream.readByte() << 8 | inputStream.readByte();\r
-               if(identifier != NAME_ID) {\r
-                       throw new BlenderFileException("Invalid identifier! '" + this.toString(NAME_ID) + "' expected and found: " + this.toString(identifier));\r
-               }\r
-               int amount = inputStream.readInt();\r
-               if(amount <= 0) {\r
-                       throw new BlenderFileException("The names amount number should be positive!");\r
-               }\r
-               String[] names = new String[amount];\r
-               for(int i = 0; i < amount; ++i) {\r
-                       names[i] = inputStream.readString();\r
-               }\r
-\r
-               //reding types\r
-               inputStream.alignPosition(4);\r
-               identifier = inputStream.readByte() << 24 | inputStream.readByte() << 16 |\r
-                                        inputStream.readByte() << 8 | inputStream.readByte();\r
-               if(identifier != TYPE_ID) {\r
-                       throw new BlenderFileException("Invalid identifier! '" + this.toString(TYPE_ID) + "' expected and found: " + this.toString(identifier));\r
-               }\r
-               amount = inputStream.readInt();\r
-               if(amount <= 0) {\r
-                       throw new BlenderFileException("The types amount number should be positive!");\r
-               }\r
-               String[] types = new String[amount];\r
-               for(int i = 0; i < amount; ++i) {\r
-                       types[i] = inputStream.readString();\r
-               }\r
-\r
-               //reading lengths\r
-               inputStream.alignPosition(4);\r
-               identifier = inputStream.readByte() << 24 | inputStream.readByte() << 16 |\r
-                                        inputStream.readByte() << 8 | inputStream.readByte();\r
-               if(identifier != TLEN_ID) {\r
-                       throw new BlenderFileException("Invalid identifier! '" + this.toString(TLEN_ID) + "' expected and found: " + this.toString(identifier));\r
-               }\r
-               int[] lengths = new int[amount];//theamount is the same as int types\r
-               for(int i = 0; i < amount; ++i) {\r
-                       lengths[i] = inputStream.readShort();\r
-               }\r
-\r
-               //reading structures\r
-               inputStream.alignPosition(4);\r
-               identifier = inputStream.readByte() << 24 | inputStream.readByte() << 16 |\r
-                                        inputStream.readByte() << 8 | inputStream.readByte();\r
-               if(identifier != STRC_ID) {\r
-                       throw new BlenderFileException("Invalid identifier! '" + this.toString(STRC_ID) + "' expected and found: " + this.toString(identifier));\r
-               }\r
-               amount = inputStream.readInt();\r
-               if(amount <= 0) {\r
-                       throw new BlenderFileException("The structures amount number should be positive!");\r
-               }\r
-               structures = new Structure[amount];\r
-               structuresMap = new HashMap<String, Structure>(amount);\r
-               for(int i = 0; i < amount; ++i) {\r
-                       structures[i] = new Structure(inputStream, names, types, dataRepository);\r
-                       if(structuresMap.containsKey(structures[i].getType())) {\r
-                               throw new BlenderFileException("Blend file seems to be corrupted! The type " + structures[i].getType() + " is defined twice!");\r
-                       }\r
-                       structuresMap.put(structures[i].getType(), structures[i]);\r
-               }\r
-       }\r
-\r
-       /**\r
-        * This method returns the amount of the structures.\r
-        * @return the amount of the structures\r
-        */\r
-       public int getStructuresCount() {\r
-               return structures.length;\r
-       }\r
-\r
-       /**\r
-        * This method returns the structure of the given index.\r
-        * @param index\r
-        *        the index of the structure\r
-        * @return the structure of the given index\r
-        */\r
-       public Structure getStructure(int index) {\r
-               try {\r
-                       return (Structure)structures[index].clone();\r
-               } catch(CloneNotSupportedException e) {\r
-                       throw new IllegalStateException("Structure should be clonable!!!", e);\r
-               }\r
-       }\r
-\r
-       /**\r
-        * This method returns a structure of the given name. If the name does not exists then null is returned.\r
-        * @param name\r
-        *        the name of the structure\r
-        * @return the required structure or null if the given name is inapropriate\r
-        */\r
-       public Structure getStructure(String name) {\r
-               try {\r
-                       return (Structure)structuresMap.get(name).clone();\r
-               } catch(CloneNotSupportedException e) {\r
-                       throw new IllegalStateException(e.getMessage(), e);\r
-               }\r
-       }\r
-\r
-       /**\r
-        * This method indicates if the structure of the given name exists.\r
-        * @param name\r
-        *        the name of the structure\r
-        * @return true if the structure exists and false otherwise\r
-        */\r
-       public boolean hasStructure(String name) {\r
-               return structuresMap.containsKey(name);\r
-       }\r
-\r
-       /**\r
-        * This method converts the given identifier code to string.\r
-        * @param code\r
-        *        the code taht is to be converted\r
-        * @return the string value of the identifier\r
-        */\r
-       private String toString(int code) {\r
-               char c1 = (char)((code & 0xFF000000) >> 24);\r
-               char c2 = (char)((code & 0xFF0000) >> 16);\r
-               char c3 = (char)((code & 0xFF00) >> 8);\r
-               char c4 = (char)(code & 0xFF);\r
-               return String.valueOf(c1) + c2 + c3 + c4;\r
-       }\r
-\r
-       @Override\r
-       public String toString() {\r
-               StringBuilder stringBuilder = new StringBuilder("=============== ").append(SDNA_ID).append('\n');\r
-               for(Structure structure : structures) {\r
-                       stringBuilder.append(structure.toString()).append('\n');\r
-               }\r
-               return stringBuilder.append("===============").toString();\r
-       }\r
+\r
+    private static final int SDNA_ID = 'S' << 24 | 'D' << 16 | 'N' << 8 | 'A'; //SDNA\r
+    private static final int NAME_ID = 'N' << 24 | 'A' << 16 | 'M' << 8 | 'E'; //NAME\r
+    private static final int TYPE_ID = 'T' << 24 | 'Y' << 16 | 'P' << 8 | 'E'; //TYPE\r
+    private static final int TLEN_ID = 'T' << 24 | 'L' << 16 | 'E' << 8 | 'N'; //TLEN\r
+    private static final int STRC_ID = 'S' << 24 | 'T' << 16 | 'R' << 8 | 'C'; //STRC\r
+    /** Structures available inside the file. */\r
+    private final Structure[] structures;\r
+    /** A map that helps finding a structure by type. */\r
+    private final Map<String, Structure> structuresMap;\r
+\r
+    /**\r
+     * Constructor. Loads the block from the given stream during instance creation.\r
+     * @param inputStream\r
+     *        the stream we read the block from\r
+     * @param dataRepository\r
+     *        the data repository\r
+     * @throws BlenderFileException\r
+     *         this exception is throw if the blend file is invalid or somehow corrupted\r
+     */\r
+    public DnaBlockData(BlenderInputStream inputStream, DataRepository dataRepository) throws BlenderFileException {\r
+        int identifier;\r
+\r
+        //reading 'SDNA' identifier\r
+        identifier = inputStream.readByte() << 24 | inputStream.readByte() << 16\r
+                | inputStream.readByte() << 8 | inputStream.readByte();\r
+\r
+        if (identifier != SDNA_ID) {\r
+            throw new BlenderFileException("Invalid identifier! '" + this.toString(SDNA_ID) + "' expected and found: " + this.toString(identifier));\r
+        }\r
+\r
+        //reading names\r
+        identifier = inputStream.readByte() << 24 | inputStream.readByte() << 16\r
+                | inputStream.readByte() << 8 | inputStream.readByte();\r
+        if (identifier != NAME_ID) {\r
+            throw new BlenderFileException("Invalid identifier! '" + this.toString(NAME_ID) + "' expected and found: " + this.toString(identifier));\r
+        }\r
+        int amount = inputStream.readInt();\r
+        if (amount <= 0) {\r
+            throw new BlenderFileException("The names amount number should be positive!");\r
+        }\r
+        String[] names = new String[amount];\r
+        for (int i = 0; i < amount; ++i) {\r
+            names[i] = inputStream.readString();\r
+        }\r
+\r
+        //reding types\r
+        inputStream.alignPosition(4);\r
+        identifier = inputStream.readByte() << 24 | inputStream.readByte() << 16\r
+                | inputStream.readByte() << 8 | inputStream.readByte();\r
+        if (identifier != TYPE_ID) {\r
+            throw new BlenderFileException("Invalid identifier! '" + this.toString(TYPE_ID) + "' expected and found: " + this.toString(identifier));\r
+        }\r
+        amount = inputStream.readInt();\r
+        if (amount <= 0) {\r
+            throw new BlenderFileException("The types amount number should be positive!");\r
+        }\r
+        String[] types = new String[amount];\r
+        for (int i = 0; i < amount; ++i) {\r
+            types[i] = inputStream.readString();\r
+        }\r
+\r
+        //reading lengths\r
+        inputStream.alignPosition(4);\r
+        identifier = inputStream.readByte() << 24 | inputStream.readByte() << 16\r
+                | inputStream.readByte() << 8 | inputStream.readByte();\r
+        if (identifier != TLEN_ID) {\r
+            throw new BlenderFileException("Invalid identifier! '" + this.toString(TLEN_ID) + "' expected and found: " + this.toString(identifier));\r
+        }\r
+        int[] lengths = new int[amount];//theamount is the same as int types\r
+        for (int i = 0; i < amount; ++i) {\r
+            lengths[i] = inputStream.readShort();\r
+        }\r
+\r
+        //reading structures\r
+        inputStream.alignPosition(4);\r
+        identifier = inputStream.readByte() << 24 | inputStream.readByte() << 16\r
+                | inputStream.readByte() << 8 | inputStream.readByte();\r
+        if (identifier != STRC_ID) {\r
+            throw new BlenderFileException("Invalid identifier! '" + this.toString(STRC_ID) + "' expected and found: " + this.toString(identifier));\r
+        }\r
+        amount = inputStream.readInt();\r
+        if (amount <= 0) {\r
+            throw new BlenderFileException("The structures amount number should be positive!");\r
+        }\r
+        structures = new Structure[amount];\r
+        structuresMap = new HashMap<String, Structure>(amount);\r
+        for (int i = 0; i < amount; ++i) {\r
+            structures[i] = new Structure(inputStream, names, types, dataRepository);\r
+            if (structuresMap.containsKey(structures[i].getType())) {\r
+                throw new BlenderFileException("Blend file seems to be corrupted! The type " + structures[i].getType() + " is defined twice!");\r
+            }\r
+            structuresMap.put(structures[i].getType(), structures[i]);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * This method returns the amount of the structures.\r
+     * @return the amount of the structures\r
+     */\r
+    public int getStructuresCount() {\r
+        return structures.length;\r
+    }\r
+\r
+    /**\r
+     * This method returns the structure of the given index.\r
+     * @param index\r
+     *        the index of the structure\r
+     * @return the structure of the given index\r
+     */\r
+    public Structure getStructure(int index) {\r
+        try {\r
+            return (Structure) structures[index].clone();\r
+        } catch (CloneNotSupportedException e) {\r
+            throw new IllegalStateException("Structure should be clonable!!!", e);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * This method returns a structure of the given name. If the name does not exists then null is returned.\r
+     * @param name\r
+     *        the name of the structure\r
+     * @return the required structure or null if the given name is inapropriate\r
+     */\r
+    public Structure getStructure(String name) {\r
+        try {\r
+            return (Structure) structuresMap.get(name).clone();\r
+        } catch (CloneNotSupportedException e) {\r
+            throw new IllegalStateException(e.getMessage(), e);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * This method indicates if the structure of the given name exists.\r
+     * @param name\r
+     *        the name of the structure\r
+     * @return true if the structure exists and false otherwise\r
+     */\r
+    public boolean hasStructure(String name) {\r
+        return structuresMap.containsKey(name);\r
+    }\r
+\r
+    /**\r
+     * This method converts the given identifier code to string.\r
+     * @param code\r
+     *        the code taht is to be converted\r
+     * @return the string value of the identifier\r
+     */\r
+    private String toString(int code) {\r
+        char c1 = (char) ((code & 0xFF000000) >> 24);\r
+        char c2 = (char) ((code & 0xFF0000) >> 16);\r
+        char c3 = (char) ((code & 0xFF00) >> 8);\r
+        char c4 = (char) (code & 0xFF);\r
+        return String.valueOf(c1) + c2 + c3 + c4;\r
+    }\r
+\r
+    @Override\r
+    public String toString() {\r
+        StringBuilder stringBuilder = new StringBuilder("=============== ").append(SDNA_ID).append('\n');\r
+        for (Structure structure : structures) {\r
+            stringBuilder.append(structure.toString()).append('\n');\r
+        }\r
+        return stringBuilder.append("===============").toString();\r
+    }\r
 }\r
index e57862e..4823af7 100644 (file)
@@ -15,305 +15,306 @@ import com.jme3.scene.plugins.blender.utils.Pointer;
  * another structure.\r
  * @author Marcin Roguski\r
  */\r
-/*package*/class Field implements Cloneable {\r
-       private static final int        NAME_LENGTH     = 24;\r
-       private static final int        TYPE_LENGTH     = 16;\r
+/*package*/\r
+class Field implements Cloneable {\r
 \r
-       /** The data repository. */\r
-       public DataRepository           dataRepository;\r
-       /** The type of the field. */\r
-       public String                           type;\r
-       /** The name of the field. */\r
-       public String                           name;\r
-       /** The value of the field. Filled during data reading. */\r
-       public Object                           value;\r
-       /** This variable indicates the level of the pointer. */\r
-       public int                                      pointerLevel;\r
-       /**\r
-        * This variable determines the sizes of the array. If the value is null the n the field is not an array.\r
-        */\r
-       public int[]                            tableSizes;\r
-       /** This variable indicates if the field is a function pointer. */\r
-       public boolean                          function;\r
+    private static final int NAME_LENGTH = 24;\r
+    private static final int TYPE_LENGTH = 16;\r
+    /** The data repository. */\r
+    public DataRepository dataRepository;\r
+    /** The type of the field. */\r
+    public String type;\r
+    /** The name of the field. */\r
+    public String name;\r
+    /** The value of the field. Filled during data reading. */\r
+    public Object value;\r
+    /** This variable indicates the level of the pointer. */\r
+    public int pointerLevel;\r
+    /**\r
+     * This variable determines the sizes of the array. If the value is null the n the field is not an array.\r
+     */\r
+    public int[] tableSizes;\r
+    /** This variable indicates if the field is a function pointer. */\r
+    public boolean function;\r
 \r
-       /**\r
-        * Constructor. Saves the field data and parses its name.\r
-        * @param name\r
-        *        the name of the field\r
-        * @param type\r
-        *        the type of the field\r
-        * @param dataRepository\r
-        *        the data repository\r
-        * @throws BlenderFileException\r
-        *         this exception is thrown if the names contain errors\r
-        */\r
-       public Field(String name, String type, DataRepository dataRepository) throws BlenderFileException {\r
-               this.type = type;\r
-               this.dataRepository = dataRepository;\r
-               this.parseField(new StringBuilder(name));\r
-       }\r
+    /**\r
+     * Constructor. Saves the field data and parses its name.\r
+     * @param name\r
+     *        the name of the field\r
+     * @param type\r
+     *        the type of the field\r
+     * @param dataRepository\r
+     *        the data repository\r
+     * @throws BlenderFileException\r
+     *         this exception is thrown if the names contain errors\r
+     */\r
+    public Field(String name, String type, DataRepository dataRepository) throws BlenderFileException {\r
+        this.type = type;\r
+        this.dataRepository = dataRepository;\r
+        this.parseField(new StringBuilder(name));\r
+    }\r
 \r
-       /**\r
-        * Copy constructor. Used in clone method. Copying is not full. The value in the new object is not set so that we\r
-        * have a clead empty copy of the filed to fill with data.\r
-        * @param field\r
-        *        the object that we copy\r
-        */\r
-       private Field(Field field) {\r
-               type = field.type;\r
-               name = field.name;\r
-               dataRepository = field.dataRepository;\r
-               pointerLevel = field.pointerLevel;\r
-               if(field.tableSizes != null) {\r
-                       tableSizes = field.tableSizes.clone();\r
-               }\r
-               function = field.function;\r
-       }\r
+    /**\r
+     * Copy constructor. Used in clone method. Copying is not full. The value in the new object is not set so that we\r
+     * have a clead empty copy of the filed to fill with data.\r
+     * @param field\r
+     *        the object that we copy\r
+     */\r
+    private Field(Field field) {\r
+        type = field.type;\r
+        name = field.name;\r
+        dataRepository = field.dataRepository;\r
+        pointerLevel = field.pointerLevel;\r
+        if (field.tableSizes != null) {\r
+            tableSizes = field.tableSizes.clone();\r
+        }\r
+        function = field.function;\r
+    }\r
 \r
-       @Override\r
-       public Object clone() throws CloneNotSupportedException {\r
-               return new Field(this);\r
-       }\r
+    @Override\r
+    public Object clone() throws CloneNotSupportedException {\r
+        return new Field(this);\r
+    }\r
 \r
-       /**\r
-        * This method fills the field wth data read from the input stream.\r
-        * @param blenderInputStream\r
-        *        the stream we read data from\r
-        * @throws BlenderFileException\r
-        *         an exception is thrown when the blend file is somehow invalid or corrupted\r
-        */\r
-       public void fill(BlenderInputStream blenderInputStream) throws BlenderFileException {\r
-               int dataToRead = 1;\r
-               if(tableSizes != null && tableSizes.length > 0) {\r
-                       for(int size : tableSizes) {\r
-                               if(size <= 0) {\r
-                                       throw new BlenderFileException("The field " + name + " has invalid table size: " + size);\r
-                               }\r
-                               dataToRead *= size;\r
-                       }\r
-               }\r
-               DataType dataType = pointerLevel == 0 ? DataType.getDataType(type, dataRepository) : DataType.POINTER;\r
-               switch(dataType) {\r
-                       case POINTER:\r
-                               if(dataToRead == 1) {\r
-                                       Pointer pointer = new Pointer(pointerLevel, function, dataRepository);\r
-                                       pointer.fill(blenderInputStream);\r
-                                       value = pointer;\r
-                               } else {\r
-                                       Pointer[] data = new Pointer[dataToRead];\r
-                                       for(int i = 0; i < dataToRead; ++i) {\r
-                                               Pointer pointer = new Pointer(pointerLevel, function, dataRepository);\r
-                                               pointer.fill(blenderInputStream);\r
-                                               data[i] = pointer;\r
-                                       }\r
-                                       value = new DynamicArray<Pointer>(tableSizes, data);\r
-                               }\r
-                               break;\r
-                       case CHARACTER:\r
-                               //character is also stored as a number, because sometimes the new blender version uses\r
-                               //other number type instead of character as a field type\r
-                               //and characters are very often used as byte number stores instead of real chars\r
-                               if(dataToRead == 1) {\r
-                                       value = Byte.valueOf((byte)blenderInputStream.readByte());\r
-                               } else {\r
-                                       Character[] data = new Character[dataToRead];\r
-                                       for(int i = 0; i < dataToRead; ++i) {\r
-                                               data[i] = Character.valueOf((char)blenderInputStream.readByte());\r
-                                       }\r
-                                       value = new DynamicArray<Character>(tableSizes, data);\r
-                               }\r
-                               break;\r
-                       case SHORT:\r
-                               if(dataToRead == 1) {\r
-                                       value = Integer.valueOf(blenderInputStream.readShort());\r
-                               } else {\r
-                                       Number[] data = new Number[dataToRead];\r
-                                       for(int i = 0; i < dataToRead; ++i) {\r
-                                               data[i] = Integer.valueOf(blenderInputStream.readShort());\r
-                                       }\r
-                                       value = new DynamicArray<Number>(tableSizes, data);\r
-                               }\r
-                               break;\r
-                       case INTEGER:\r
-                               if(dataToRead == 1) {\r
-                                       value = Integer.valueOf(blenderInputStream.readInt());\r
-                               } else {\r
-                                       Number[] data = new Number[dataToRead];\r
-                                       for(int i = 0; i < dataToRead; ++i) {\r
-                                               data[i] = Integer.valueOf(blenderInputStream.readInt());\r
-                                       }\r
-                                       value = new DynamicArray<Number>(tableSizes, data);\r
-                               }\r
-                               break;\r
-                       case LONG:\r
-                               if(dataToRead == 1) {\r
-                                       value = Long.valueOf(blenderInputStream.readLong());\r
-                               } else {\r
-                                       Number[] data = new Number[dataToRead];\r
-                                       for(int i = 0; i < dataToRead; ++i) {\r
-                                               data[i] = Long.valueOf(blenderInputStream.readLong());\r
-                                       }\r
-                                       value = new DynamicArray<Number>(tableSizes, data);\r
-                               }\r
-                               break;\r
-                       case FLOAT:\r
-                               if(dataToRead == 1) {\r
-                                       value = Float.valueOf(blenderInputStream.readFloat());\r
-                               } else {\r
-                                       Number[] data = new Number[dataToRead];\r
-                                       for(int i = 0; i < dataToRead; ++i) {\r
-                                               data[i] = Float.valueOf(blenderInputStream.readFloat());\r
-                                       }\r
-                                       value = new DynamicArray<Number>(tableSizes, data);\r
-                               }\r
-                               break;\r
-                       case DOUBLE:\r
-                               if(dataToRead == 1) {\r
-                                       value = Double.valueOf(blenderInputStream.readDouble());\r
-                               } else {\r
-                                       Number[] data = new Number[dataToRead];\r
-                                       for(int i = 0; i < dataToRead; ++i) {\r
-                                               data[i] = Double.valueOf(blenderInputStream.readDouble());\r
-                                       }\r
-                                       value = new DynamicArray<Number>(tableSizes, data);\r
-                               }\r
-                               break;\r
-                       case VOID:\r
-                               break;\r
-                       case STRUCTURE:\r
-                               if(dataToRead == 1) {\r
-                                       Structure structure = dataRepository.getDnaBlockData().getStructure(type);\r
-                                       structure.fill(blenderInputStream);\r
-                                       value = structure;\r
-                               } else {\r
-                                       Structure[] data = new Structure[dataToRead];\r
-                                       for(int i = 0; i < dataToRead; ++i) {\r
-                                               Structure structure = dataRepository.getDnaBlockData().getStructure(type);\r
-                                               structure.fill(blenderInputStream);\r
-                                               data[i] = structure;\r
-                                       }\r
-                                       value = new DynamicArray<Structure>(tableSizes, data);\r
-                               }\r
-                               break;\r
-                       default:\r
-                               throw new IllegalStateException("Unimplemented filling of type: " + type);\r
-               }\r
-       }\r
+    /**\r
+     * This method fills the field wth data read from the input stream.\r
+     * @param blenderInputStream\r
+     *        the stream we read data from\r
+     * @throws BlenderFileException\r
+     *         an exception is thrown when the blend file is somehow invalid or corrupted\r
+     */\r
+    public void fill(BlenderInputStream blenderInputStream) throws BlenderFileException {\r
+        int dataToRead = 1;\r
+        if (tableSizes != null && tableSizes.length > 0) {\r
+            for (int size : tableSizes) {\r
+                if (size <= 0) {\r
+                    throw new BlenderFileException("The field " + name + " has invalid table size: " + size);\r
+                }\r
+                dataToRead *= size;\r
+            }\r
+        }\r
+        DataType dataType = pointerLevel == 0 ? DataType.getDataType(type, dataRepository) : DataType.POINTER;\r
+        switch (dataType) {\r
+            case POINTER:\r
+                if (dataToRead == 1) {\r
+                    Pointer pointer = new Pointer(pointerLevel, function, dataRepository);\r
+                    pointer.fill(blenderInputStream);\r
+                    value = pointer;\r
+                } else {\r
+                    Pointer[] data = new Pointer[dataToRead];\r
+                    for (int i = 0; i < dataToRead; ++i) {\r
+                        Pointer pointer = new Pointer(pointerLevel, function, dataRepository);\r
+                        pointer.fill(blenderInputStream);\r
+                        data[i] = pointer;\r
+                    }\r
+                    value = new DynamicArray<Pointer>(tableSizes, data);\r
+                }\r
+                break;\r
+            case CHARACTER:\r
+                //character is also stored as a number, because sometimes the new blender version uses\r
+                //other number type instead of character as a field type\r
+                //and characters are very often used as byte number stores instead of real chars\r
+                if (dataToRead == 1) {\r
+                    value = Byte.valueOf((byte) blenderInputStream.readByte());\r
+                } else {\r
+                    Character[] data = new Character[dataToRead];\r
+                    for (int i = 0; i < dataToRead; ++i) {\r
+                        data[i] = Character.valueOf((char) blenderInputStream.readByte());\r
+                    }\r
+                    value = new DynamicArray<Character>(tableSizes, data);\r
+                }\r
+                break;\r
+            case SHORT:\r
+                if (dataToRead == 1) {\r
+                    value = Integer.valueOf(blenderInputStream.readShort());\r
+                } else {\r
+                    Number[] data = new Number[dataToRead];\r
+                    for (int i = 0; i < dataToRead; ++i) {\r
+                        data[i] = Integer.valueOf(blenderInputStream.readShort());\r
+                    }\r
+                    value = new DynamicArray<Number>(tableSizes, data);\r
+                }\r
+                break;\r
+            case INTEGER:\r
+                if (dataToRead == 1) {\r
+                    value = Integer.valueOf(blenderInputStream.readInt());\r
+                } else {\r
+                    Number[] data = new Number[dataToRead];\r
+                    for (int i = 0; i < dataToRead; ++i) {\r
+                        data[i] = Integer.valueOf(blenderInputStream.readInt());\r
+                    }\r
+                    value = new DynamicArray<Number>(tableSizes, data);\r
+                }\r
+                break;\r
+            case LONG:\r
+                if (dataToRead == 1) {\r
+                    value = Long.valueOf(blenderInputStream.readLong());\r
+                } else {\r
+                    Number[] data = new Number[dataToRead];\r
+                    for (int i = 0; i < dataToRead; ++i) {\r
+                        data[i] = Long.valueOf(blenderInputStream.readLong());\r
+                    }\r
+                    value = new DynamicArray<Number>(tableSizes, data);\r
+                }\r
+                break;\r
+            case FLOAT:\r
+                if (dataToRead == 1) {\r
+                    value = Float.valueOf(blenderInputStream.readFloat());\r
+                } else {\r
+                    Number[] data = new Number[dataToRead];\r
+                    for (int i = 0; i < dataToRead; ++i) {\r
+                        data[i] = Float.valueOf(blenderInputStream.readFloat());\r
+                    }\r
+                    value = new DynamicArray<Number>(tableSizes, data);\r
+                }\r
+                break;\r
+            case DOUBLE:\r
+                if (dataToRead == 1) {\r
+                    value = Double.valueOf(blenderInputStream.readDouble());\r
+                } else {\r
+                    Number[] data = new Number[dataToRead];\r
+                    for (int i = 0; i < dataToRead; ++i) {\r
+                        data[i] = Double.valueOf(blenderInputStream.readDouble());\r
+                    }\r
+                    value = new DynamicArray<Number>(tableSizes, data);\r
+                }\r
+                break;\r
+            case VOID:\r
+                break;\r
+            case STRUCTURE:\r
+                if (dataToRead == 1) {\r
+                    Structure structure = dataRepository.getDnaBlockData().getStructure(type);\r
+                    structure.fill(blenderInputStream);\r
+                    value = structure;\r
+                } else {\r
+                    Structure[] data = new Structure[dataToRead];\r
+                    for (int i = 0; i < dataToRead; ++i) {\r
+                        Structure structure = dataRepository.getDnaBlockData().getStructure(type);\r
+                        structure.fill(blenderInputStream);\r
+                        data[i] = structure;\r
+                    }\r
+                    value = new DynamicArray<Structure>(tableSizes, data);\r
+                }\r
+                break;\r
+            default:\r
+                throw new IllegalStateException("Unimplemented filling of type: " + type);\r
+        }\r
+    }\r
 \r
-       /**\r
-        * This method parses the field name to determine how the field should be used.\r
-        * @param nameBuilder\r
-        *        the name of the field (given as StringBuilder)\r
-        * @throws BlenderFileException\r
-        *         this exception is thrown if the names contain errors\r
-        */\r
-       private void parseField(StringBuilder nameBuilder) throws BlenderFileException {\r
-               this.removeWhitespaces(nameBuilder);\r
-               //veryfying if the name is a pointer\r
-               int pointerIndex = nameBuilder.indexOf("*");\r
-               while(pointerIndex >= 0) {\r
-                       ++pointerLevel;\r
-                       nameBuilder.deleteCharAt(pointerIndex);\r
-                       pointerIndex = nameBuilder.indexOf("*");\r
-               }\r
-               //veryfying if the name is a function pointer\r
-               if(nameBuilder.indexOf("(") >= 0) {\r
-                       function = true;\r
-                       this.removeCharacter(nameBuilder, '(');\r
-                       this.removeCharacter(nameBuilder, ')');\r
-               } else {\r
-                       //veryfying if the name is a table\r
-                       int tableStartIndex = 0;\r
-                       List<Integer> lengths = new ArrayList<Integer>(3);//3 dimensions will be enough in most cases\r
-                       do {\r
-                               tableStartIndex = nameBuilder.indexOf("[");\r
-                               if(tableStartIndex > 0) {\r
-                                       int tableStopIndex = nameBuilder.indexOf("]");\r
-                                       if(tableStopIndex < 0) {\r
-                                               throw new BlenderFileException("Invalid structure name: " + name);\r
-                                       }\r
-                                       try {\r
-                                               lengths.add(Integer.valueOf(nameBuilder.substring(tableStartIndex + 1, tableStopIndex)));\r
-                                       } catch(NumberFormatException e) {\r
-                                               throw new BlenderFileException("Invalid structure name caused by invalid table length: " + name, e);\r
-                                       }\r
-                                       nameBuilder.delete(tableStartIndex, tableStopIndex + 1);\r
-                               }\r
-                       } while(tableStartIndex > 0);\r
-                       if(!lengths.isEmpty()) {\r
-                               tableSizes = new int[lengths.size()];\r
-                               for(int i = 0; i < tableSizes.length; ++i) {\r
-                                       tableSizes[i] = lengths.get(i).intValue();\r
-                               }\r
-                       }\r
-               }\r
-               name = nameBuilder.toString();\r
-       }\r
+    /**\r
+     * This method parses the field name to determine how the field should be used.\r
+     * @param nameBuilder\r
+     *        the name of the field (given as StringBuilder)\r
+     * @throws BlenderFileException\r
+     *         this exception is thrown if the names contain errors\r
+     */\r
+    private void parseField(StringBuilder nameBuilder) throws BlenderFileException {\r
+        this.removeWhitespaces(nameBuilder);\r
+        //veryfying if the name is a pointer\r
+        int pointerIndex = nameBuilder.indexOf("*");\r
+        while (pointerIndex >= 0) {\r
+            ++pointerLevel;\r
+            nameBuilder.deleteCharAt(pointerIndex);\r
+            pointerIndex = nameBuilder.indexOf("*");\r
+        }\r
+        //veryfying if the name is a function pointer\r
+        if (nameBuilder.indexOf("(") >= 0) {\r
+            function = true;\r
+            this.removeCharacter(nameBuilder, '(');\r
+            this.removeCharacter(nameBuilder, ')');\r
+        } else {\r
+            //veryfying if the name is a table\r
+            int tableStartIndex = 0;\r
+            List<Integer> lengths = new ArrayList<Integer>(3);//3 dimensions will be enough in most cases\r
+            do {\r
+                tableStartIndex = nameBuilder.indexOf("[");\r
+                if (tableStartIndex > 0) {\r
+                    int tableStopIndex = nameBuilder.indexOf("]");\r
+                    if (tableStopIndex < 0) {\r
+                        throw new BlenderFileException("Invalid structure name: " + name);\r
+                    }\r
+                    try {\r
+                        lengths.add(Integer.valueOf(nameBuilder.substring(tableStartIndex + 1, tableStopIndex)));\r
+                    } catch (NumberFormatException e) {\r
+                        throw new BlenderFileException("Invalid structure name caused by invalid table length: " + name, e);\r
+                    }\r
+                    nameBuilder.delete(tableStartIndex, tableStopIndex + 1);\r
+                }\r
+            } while (tableStartIndex > 0);\r
+            if (!lengths.isEmpty()) {\r
+                tableSizes = new int[lengths.size()];\r
+                for (int i = 0; i < tableSizes.length; ++i) {\r
+                    tableSizes[i] = lengths.get(i).intValue();\r
+                }\r
+            }\r
+        }\r
+        name = nameBuilder.toString();\r
+    }\r
 \r
-       /**\r
-        * This method removes the required character from the text.\r
-        * @param text\r
-        *        the text we remove characters from\r
-        * @param toRemove\r
-        *        the character to be removed\r
-        */\r
-       private void removeCharacter(StringBuilder text, char toRemove) {\r
-               for(int i = 0; i < text.length(); ++i) {\r
-                       if(text.charAt(i) == toRemove) {\r
-                               text.deleteCharAt(i);\r
-                               --i;\r
-                       }\r
-               }\r
-       }\r
+    /**\r
+     * This method removes the required character from the text.\r
+     * @param text\r
+     *        the text we remove characters from\r
+     * @param toRemove\r
+     *        the character to be removed\r
+     */\r
+    private void removeCharacter(StringBuilder text, char toRemove) {\r
+        for (int i = 0; i < text.length(); ++i) {\r
+            if (text.charAt(i) == toRemove) {\r
+                text.deleteCharAt(i);\r
+                --i;\r
+            }\r
+        }\r
+    }\r
 \r
-       /**\r
-        * This method removes all whitespaces from the text.\r
-        * @param text\r
-        *        the text we remove whitespaces from\r
-        */\r
-       private void removeWhitespaces(StringBuilder text) {\r
-               for(int i = 0; i < text.length(); ++i) {\r
-                       if(Character.isWhitespace(text.charAt(i))) {\r
-                               text.deleteCharAt(i);\r
-                               --i;\r
-                       }\r
-               }\r
-       }\r
+    /**\r
+     * This method removes all whitespaces from the text.\r
+     * @param text\r
+     *        the text we remove whitespaces from\r
+     */\r
+    private void removeWhitespaces(StringBuilder text) {\r
+        for (int i = 0; i < text.length(); ++i) {\r
+            if (Character.isWhitespace(text.charAt(i))) {\r
+                text.deleteCharAt(i);\r
+                --i;\r
+            }\r
+        }\r
+    }\r
 \r
-       @Override\r
-       public String toString() {\r
-               StringBuilder result = new StringBuilder();\r
-               if(function) {\r
-                       result.append('(');\r
-               }\r
-               for(int i = 0; i < pointerLevel; ++i) {\r
-                       result.append('*');\r
-               }\r
-               result.append(name);\r
-               if(tableSizes != null) {\r
-                       for(int i = 0; i < tableSizes.length; ++i) {\r
-                               result.append('[').append(tableSizes[i]).append(']');\r
-                       }\r
-               }\r
-               if(function) {\r
-                       result.append(")()");\r
-               }\r
-               //insert appropriate amount of spaces to format the output corrently\r
-               int nameLength = result.length();\r
-               result.append(' ');//at least one space is a must\r
-               for(int i = 1; i < NAME_LENGTH - nameLength; ++i) {//we start from i=1 because one space is already added\r
-                       result.append(' ');\r
-               }\r
-               result.append(type);\r
-               nameLength = result.length();\r
-               for(int i = 0; i < NAME_LENGTH + TYPE_LENGTH - nameLength; ++i) {\r
-                       result.append(' ');\r
-               }\r
-               if(value instanceof Character) {\r
-                       result.append(" = ").append((int)((Character)value).charValue());\r
-               } else {\r
-                       result.append(" = ").append(value != null ? value.toString() : "null");\r
-               }\r
-               return result.toString();\r
-       }\r
+    @Override\r
+    public String toString() {\r
+        StringBuilder result = new StringBuilder();\r
+        if (function) {\r
+            result.append('(');\r
+        }\r
+        for (int i = 0; i < pointerLevel; ++i) {\r
+            result.append('*');\r
+        }\r
+        result.append(name);\r
+        if (tableSizes != null) {\r
+            for (int i = 0; i < tableSizes.length; ++i) {\r
+                result.append('[').append(tableSizes[i]).append(']');\r
+            }\r
+        }\r
+        if (function) {\r
+            result.append(")()");\r
+        }\r
+        //insert appropriate amount of spaces to format the output corrently\r
+        int nameLength = result.length();\r
+        result.append(' ');//at least one space is a must\r
+        for (int i = 1; i < NAME_LENGTH - nameLength; ++i) {//we start from i=1 because one space is already added\r
+            result.append(' ');\r
+        }\r
+        result.append(type);\r
+        nameLength = result.length();\r
+        for (int i = 0; i < NAME_LENGTH + TYPE_LENGTH - nameLength; ++i) {\r
+            result.append(' ');\r
+        }\r
+        if (value instanceof Character) {\r
+            result.append(" = ").append((int) ((Character) value).charValue());\r
+        } else {\r
+            result.append(" = ").append(value != null ? value.toString() : "null");\r
+        }\r
+        return result.toString();\r
+    }\r
 }
\ No newline at end of file
index b69f926..cf6e567 100644 (file)
@@ -41,161 +41,160 @@ import com.jme3.scene.plugins.blender.utils.DataRepository;
  * @author Marcin Roguski\r
  */\r
 public class FileBlockHeader {\r
-       public static final int BLOCK_TE00      = 'T' << 24 | 'E' << 16;                                        //TE00\r
-       public static final int BLOCK_ME00      = 'M' << 24 | 'E' << 16;                                        //ME00\r
-       public static final int BLOCK_SR00      = 'S' << 24 | 'R' << 16;                                        //SR00\r
-       public static final int BLOCK_CA00      = 'C' << 24 | 'A' << 16;                                        //CA00\r
-       public static final int BLOCK_LA00      = 'L' << 24 | 'A' << 16;                                        //LA00\r
-       public static final int BLOCK_OB00      = 'O' << 24 | 'B' << 16;                                        //OB00\r
-       public static final int BLOCK_MA00      = 'M' << 24 | 'A' << 16;                                        //MA00\r
-       public static final int BLOCK_SC00      = 'S' << 24 | 'C' << 16;                                        //SC00\r
-       public static final int BLOCK_WO00      = 'W' << 24 | 'O' << 16;                                        //WO00\r
-       public static final int BLOCK_TX00      = 'T' << 24 | 'X' << 16;                                        //TX00\r
-       public static final int BLOCK_IP00      = 'I' << 24 | 'P' << 16;                                        //IP00\r
-       public static final int BLOCK_AC00      = 'A' << 24 | 'C' << 16;                                        //AC00\r
 \r
-       public static final int BLOCK_GLOB      = 'G' << 24 | 'L' << 16 | 'O' << 8 | 'B';       //GLOB\r
-       public static final int BLOCK_REND      = 'R' << 24 | 'E' << 16 | 'N' << 8 | 'D';       //REND\r
-       public static final int BLOCK_DATA      = 'D' << 24 | 'A' << 16 | 'T' << 8 | 'A';       //DATA\r
-       public static final int BLOCK_DNA1      = 'D' << 24 | 'N' << 16 | 'A' << 8 | '1';       //DNA1\r
-       public static final int BLOCK_ENDB      = 'E' << 24 | 'N' << 16 | 'D' << 8 | 'B';       //ENDB\r
-\r
-       /** Identifier of the file-block [4 bytes]. */\r
-       private int                             code;\r
-       /** Total length of the data after the file-block-header [4 bytes]. */\r
-       private int                             size;\r
-       /**\r
-        * Memory address the structure was located when written to disk [4 or 8 bytes (defined in file header as a pointer\r
-        * size)].\r
-        */\r
-       private long                    oldMemoryAddress;\r
-       /** Index of the SDNA structure [4 bytes]. */\r
-       private int                             sdnaIndex;\r
-       /** Number of structure located in this file-block [4 bytes]. */\r
-       private int                             count;\r
-       /** Start position of the block's data in the stream. */\r
-       private int                             blockPosition;\r
-\r
-       /**\r
-        * Constructor. Loads the block header from the given stream during instance creation.\r
-        * @param inputStream\r
-        *        the stream we read the block header from\r
-        * @param dataRepository\r
-        *        the data repository\r
-        * @throws BlenderFileException\r
-        *         this exception is thrown when the pointer size is neither 4 nor 8\r
-        */\r
-       public FileBlockHeader(BlenderInputStream inputStream, DataRepository dataRepository) throws BlenderFileException {\r
-               inputStream.alignPosition(4);\r
-               code = inputStream.readByte() << 24 | inputStream.readByte() << 16 |\r
-                          inputStream.readByte() << 8 | inputStream.readByte();\r
-               size = inputStream.readInt();\r
-               oldMemoryAddress = inputStream.readPointer();\r
-               sdnaIndex = inputStream.readInt();\r
-               count = inputStream.readInt();\r
-               blockPosition = inputStream.getPosition();\r
-               if(FileBlockHeader.BLOCK_DNA1 == code) {\r
-                       dataRepository.setBlockData(new DnaBlockData(inputStream, dataRepository));\r
-               } else {\r
-                       inputStream.setPosition(blockPosition + size);\r
-                       dataRepository.addFileBlockHeader(Long.valueOf(oldMemoryAddress), this);\r
-               }\r
-       }\r
-\r
-       /**\r
-        * This method returns the structure described by the header filled with appropriate data.\r
-        * @param dataRepository\r
-        *        the data repository\r
-        * @return structure filled with data\r
-        * @throws BlenderFileException\r
-        */\r
-       public Structure getStructure(DataRepository dataRepository) throws BlenderFileException {\r
-               dataRepository.getInputStream().setPosition(blockPosition);\r
-               Structure structure = dataRepository.getDnaBlockData().getStructure(sdnaIndex);\r
-               structure.fill(dataRepository.getInputStream());\r
-               return structure;\r
-       }\r
-\r
-       /**\r
-        * This method returns the code of this data block.\r
-        * @return the code of this data block\r
-        */\r
-       public int getCode() {\r
-               return code;\r
-       }\r
-\r
-       /**\r
-        * This method returns the size of the data stored in this block.\r
-        * @return the size of the data stored in this block\r
-        */\r
-       public int getSize() {\r
-               return size;\r
-       }\r
-\r
-       /**\r
-        * This method returns the memory address.\r
-        * @return the memory address\r
-        */\r
-       public long getOldMemoryAddress() {\r
-               return oldMemoryAddress;\r
-       }\r
-\r
-       /**\r
-        * This method returns the sdna index.\r
-        * @return the sdna index\r
-        */\r
-       public int getSdnaIndex() {\r
-               return sdnaIndex;\r
-       }\r
-\r
-       /**\r
-        * This data returns the number of structure stored in the data block after this header.\r
-        * @return the number of structure stored in the data block after this header\r
-        */\r
-       public int getCount() {\r
-               return count;\r
-       }\r
-\r
-       /**\r
-        * This method returns the start position of the data block in the blend file stream.\r
-        * @return the start position of the data block\r
-        */\r
-       public int getBlockPosition() {\r
-               return blockPosition;\r
-       }\r
-\r
-       /**\r
-        * This method indicates if the block is the last block in the file.\r
-        * @return true if this block is the last one in the file nad false otherwise\r
-        */\r
-       public boolean isLastBlock() {\r
-               return FileBlockHeader.BLOCK_ENDB == code;\r
-       }\r
-\r
-       /**\r
-        * This method indicates if the block is the SDNA block.\r
-        * @return true if this block is the SDNA block and false otherwise\r
-        */\r
-       public boolean isDnaBlock() {\r
-               return FileBlockHeader.BLOCK_DNA1 == code;\r
-       }\r
-\r
-       @Override\r
-       public String toString() {\r
-               return "FILE BLOCK HEADER [" + this.codeToString(code) + " : " + size + " : " + oldMemoryAddress + " : " + sdnaIndex + " : " + count + "]";\r
-       }\r
-\r
-       /**\r
-        * This method transforms the coded bloch id into a string value.\r
-        * @param code\r
-        *        the id of the block\r
-        * @return the string value of the block id\r
-        */\r
-       protected String codeToString(int code) {\r
-               char c1 = (char)((code & 0xFF000000) >> 24);\r
-               char c2 = (char)((code & 0xFF0000) >> 16);\r
-               char c3 = (char)((code & 0xFF00) >> 8);\r
-               char c4 = (char)(code & 0xFF);\r
-               return String.valueOf(c1) + c2 + c3 + c4;\r
-       }\r
+    public static final int BLOCK_TE00 = 'T' << 24 | 'E' << 16;                                        //TE00\r
+    public static final int BLOCK_ME00 = 'M' << 24 | 'E' << 16;                                        //ME00\r
+    public static final int BLOCK_SR00 = 'S' << 24 | 'R' << 16;                                        //SR00\r
+    public static final int BLOCK_CA00 = 'C' << 24 | 'A' << 16;                                        //CA00\r
+    public static final int BLOCK_LA00 = 'L' << 24 | 'A' << 16;                                        //LA00\r
+    public static final int BLOCK_OB00 = 'O' << 24 | 'B' << 16;                                        //OB00\r
+    public static final int BLOCK_MA00 = 'M' << 24 | 'A' << 16;                                        //MA00\r
+    public static final int BLOCK_SC00 = 'S' << 24 | 'C' << 16;                                        //SC00\r
+    public static final int BLOCK_WO00 = 'W' << 24 | 'O' << 16;                                        //WO00\r
+    public static final int BLOCK_TX00 = 'T' << 24 | 'X' << 16;                                        //TX00\r
+    public static final int BLOCK_IP00 = 'I' << 24 | 'P' << 16;                                        //IP00\r
+    public static final int BLOCK_AC00 = 'A' << 24 | 'C' << 16;                                        //AC00\r
+    public static final int BLOCK_GLOB = 'G' << 24 | 'L' << 16 | 'O' << 8 | 'B';       //GLOB\r
+    public static final int BLOCK_REND = 'R' << 24 | 'E' << 16 | 'N' << 8 | 'D';       //REND\r
+    public static final int BLOCK_DATA = 'D' << 24 | 'A' << 16 | 'T' << 8 | 'A';       //DATA\r
+    public static final int BLOCK_DNA1 = 'D' << 24 | 'N' << 16 | 'A' << 8 | '1';       //DNA1\r
+    public static final int BLOCK_ENDB = 'E' << 24 | 'N' << 16 | 'D' << 8 | 'B';       //ENDB\r
+    /** Identifier of the file-block [4 bytes]. */\r
+    private int code;\r
+    /** Total length of the data after the file-block-header [4 bytes]. */\r
+    private int size;\r
+    /**\r
+     * Memory address the structure was located when written to disk [4 or 8 bytes (defined in file header as a pointer\r
+     * size)].\r
+     */\r
+    private long oldMemoryAddress;\r
+    /** Index of the SDNA structure [4 bytes]. */\r
+    private int sdnaIndex;\r
+    /** Number of structure located in this file-block [4 bytes]. */\r
+    private int count;\r
+    /** Start position of the block's data in the stream. */\r
+    private int blockPosition;\r
+\r
+    /**\r
+     * Constructor. Loads the block header from the given stream during instance creation.\r
+     * @param inputStream\r
+     *        the stream we read the block header from\r
+     * @param dataRepository\r
+     *        the data repository\r
+     * @throws BlenderFileException\r
+     *         this exception is thrown when the pointer size is neither 4 nor 8\r
+     */\r
+    public FileBlockHeader(BlenderInputStream inputStream, DataRepository dataRepository) throws BlenderFileException {\r
+        inputStream.alignPosition(4);\r
+        code = inputStream.readByte() << 24 | inputStream.readByte() << 16\r
+                | inputStream.readByte() << 8 | inputStream.readByte();\r
+        size = inputStream.readInt();\r
+        oldMemoryAddress = inputStream.readPointer();\r
+        sdnaIndex = inputStream.readInt();\r
+        count = inputStream.readInt();\r
+        blockPosition = inputStream.getPosition();\r
+        if (FileBlockHeader.BLOCK_DNA1 == code) {\r
+            dataRepository.setBlockData(new DnaBlockData(inputStream, dataRepository));\r
+        } else {\r
+            inputStream.setPosition(blockPosition + size);\r
+            dataRepository.addFileBlockHeader(Long.valueOf(oldMemoryAddress), this);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * This method returns the structure described by the header filled with appropriate data.\r
+     * @param dataRepository\r
+     *        the data repository\r
+     * @return structure filled with data\r
+     * @throws BlenderFileException\r
+     */\r
+    public Structure getStructure(DataRepository dataRepository) throws BlenderFileException {\r
+        dataRepository.getInputStream().setPosition(blockPosition);\r
+        Structure structure = dataRepository.getDnaBlockData().getStructure(sdnaIndex);\r
+        structure.fill(dataRepository.getInputStream());\r
+        return structure;\r
+    }\r
+\r
+    /**\r
+     * This method returns the code of this data block.\r
+     * @return the code of this data block\r
+     */\r
+    public int getCode() {\r
+        return code;\r
+    }\r
+\r
+    /**\r
+     * This method returns the size of the data stored in this block.\r
+     * @return the size of the data stored in this block\r
+     */\r
+    public int getSize() {\r
+        return size;\r
+    }\r
+\r
+    /**\r
+     * This method returns the memory address.\r
+     * @return the memory address\r
+     */\r
+    public long getOldMemoryAddress() {\r
+        return oldMemoryAddress;\r
+    }\r
+\r
+    /**\r
+     * This method returns the sdna index.\r
+     * @return the sdna index\r
+     */\r
+    public int getSdnaIndex() {\r
+        return sdnaIndex;\r
+    }\r
+\r
+    /**\r
+     * This data returns the number of structure stored in the data block after this header.\r
+     * @return the number of structure stored in the data block after this header\r
+     */\r
+    public int getCount() {\r
+        return count;\r
+    }\r
+\r
+    /**\r
+     * This method returns the start position of the data block in the blend file stream.\r
+     * @return the start position of the data block\r
+     */\r
+    public int getBlockPosition() {\r
+        return blockPosition;\r
+    }\r
+\r
+    /**\r
+     * This method indicates if the block is the last block in the file.\r
+     * @return true if this block is the last one in the file nad false otherwise\r
+     */\r
+    public boolean isLastBlock() {\r
+        return FileBlockHeader.BLOCK_ENDB == code;\r
+    }\r
+\r
+    /**\r
+     * This method indicates if the block is the SDNA block.\r
+     * @return true if this block is the SDNA block and false otherwise\r
+     */\r
+    public boolean isDnaBlock() {\r
+        return FileBlockHeader.BLOCK_DNA1 == code;\r
+    }\r
+\r
+    @Override\r
+    public String toString() {\r
+        return "FILE BLOCK HEADER [" + this.codeToString(code) + " : " + size + " : " + oldMemoryAddress + " : " + sdnaIndex + " : " + count + "]";\r
+    }\r
+\r
+    /**\r
+     * This method transforms the coded bloch id into a string value.\r
+     * @param code\r
+     *        the id of the block\r
+     * @return the string value of the block id\r
+     */\r
+    protected String codeToString(int code) {\r
+        char c1 = (char) ((code & 0xFF000000) >> 24);\r
+        char c2 = (char) ((code & 0xFF0000) >> 16);\r
+        char c3 = (char) ((code & 0xFF00) >> 8);\r
+        char c4 = (char) (code & 0xFF);\r
+        return String.valueOf(c1) + c2 + c3 + c4;\r
+    }\r
 }\r
index 340a018..6e9aff1 100644 (file)
@@ -46,266 +46,269 @@ import com.jme3.scene.plugins.blender.utils.Pointer;
  * @author Marcin Roguski\r
  */\r
 public class Structure implements Cloneable {\r
-       /** The data repository. */\r
-       private DataRepository  dataRepository;\r
-       /** The address of the block that fills the structure. */\r
-       private transient Long  oldMemoryAddress;\r
-       /** The type of the structure. */\r
-       private String                  type;\r
-       /**\r
-        * The fields of the structure. Each field consists of a pair: name-type.\r
-        */\r
-       private Field[]                 fields;\r
 \r
-       /**\r
-        * Constructor that copies the data of the structure.\r
-        * @param structure\r
-        *        the structure to copy.\r
-        * @param dataRepository\r
-        *        the data repository of the structure\r
-        * @throws CloneNotSupportedException\r
-        *         this exception should never be thrown\r
-        */\r
-       private Structure(Structure structure, DataRepository dataRepository) throws CloneNotSupportedException {\r
-               type = structure.type;\r
-               fields = new Field[structure.fields.length];\r
-               for(int i = 0; i < fields.length; ++i) {\r
-                       fields[i] = (Field)structure.fields[i].clone();\r
-               }\r
-               this.dataRepository = dataRepository;\r
-               this.oldMemoryAddress = structure.oldMemoryAddress;\r
-       }\r
+    /** The data repository. */\r
+    private DataRepository dataRepository;\r
+    /** The address of the block that fills the structure. */\r
+    private transient Long oldMemoryAddress;\r
+    /** The type of the structure. */\r
+    private String type;\r
+    /**\r
+     * The fields of the structure. Each field consists of a pair: name-type.\r
+     */\r
+    private Field[] fields;\r
 \r
-       /**\r
-        * Constructor. Loads the structure from the given stream during instance creation.\r
-        * @param inputStream\r
-        *        the stream we read the structure from\r
-        * @param names\r
-        *        the names from which the name of structure and its fields will be taken\r
-        * @param types\r
-        *        the names of types for the structure\r
-        * @param dataRepository\r
-        *        the data repository\r
-        * @throws BlenderFileException\r
-        *         this exception occurs if the amount of fields, defined in the file, is negative\r
-        */\r
-       public Structure(BlenderInputStream inputStream, String[] names, String[] types, DataRepository dataRepository) throws BlenderFileException {\r
-               int nameIndex = inputStream.readShort();\r
-               type = types[nameIndex];\r
-               this.dataRepository = dataRepository;\r
-               int fieldsAmount = inputStream.readShort();\r
-               if(fieldsAmount < 0) {\r
-                       throw new BlenderFileException("The amount of fields of " + this.type + " structure cannot be negative!");\r
-               }\r
-               if(fieldsAmount > 0) {\r
-                       fields = new Field[fieldsAmount];\r
-                       for(int i = 0; i < fieldsAmount; ++i) {\r
-                               int typeIndex = inputStream.readShort();\r
-                               nameIndex = inputStream.readShort();\r
-                               fields[i] = new Field(names[nameIndex], types[typeIndex], dataRepository);\r
-                       }\r
-               }\r
-               this.oldMemoryAddress = Long.valueOf(-1L);\r
-       }\r
+    /**\r
+     * Constructor that copies the data of the structure.\r
+     * @param structure\r
+     *        the structure to copy.\r
+     * @param dataRepository\r
+     *        the data repository of the structure\r
+     * @throws CloneNotSupportedException\r
+     *         this exception should never be thrown\r
+     */\r
+    private Structure(Structure structure, DataRepository dataRepository) throws CloneNotSupportedException {\r
+        type = structure.type;\r
+        fields = new Field[structure.fields.length];\r
+        for (int i = 0; i < fields.length; ++i) {\r
+            fields[i] = (Field) structure.fields[i].clone();\r
+        }\r
+        this.dataRepository = dataRepository;\r
+        this.oldMemoryAddress = structure.oldMemoryAddress;\r
+    }\r
 \r
-       /**\r
-        * This method fills the structure with data.\r
-        * @param inputStream\r
-        *        the stream we read data from, its read cursor should be placed at the start position of the data for the\r
-        *        structure\r
-        * @throws BlenderFileException\r
-        *         an exception is thrown when the blend file is somehow invalid or corrupted\r
-        */\r
-       public void fill(BlenderInputStream inputStream) throws BlenderFileException {\r
-               int position = inputStream.getPosition();\r
-               inputStream.setPosition(position - 8 - inputStream.getPointerSize());\r
-               this.oldMemoryAddress = Long.valueOf(inputStream.readPointer());\r
-               inputStream.setPosition(position);\r
-               for(Field field : fields) {\r
-                       field.fill(inputStream);\r
-               }\r
-       }\r
+    /**\r
+     * Constructor. Loads the structure from the given stream during instance creation.\r
+     * @param inputStream\r
+     *        the stream we read the structure from\r
+     * @param names\r
+     *        the names from which the name of structure and its fields will be taken\r
+     * @param types\r
+     *        the names of types for the structure\r
+     * @param dataRepository\r
+     *        the data repository\r
+     * @throws BlenderFileException\r
+     *         this exception occurs if the amount of fields, defined in the file, is negative\r
+     */\r
+    public Structure(BlenderInputStream inputStream, String[] names, String[] types, DataRepository dataRepository) throws BlenderFileException {\r
+        int nameIndex = inputStream.readShort();\r
+        type = types[nameIndex];\r
+        this.dataRepository = dataRepository;\r
+        int fieldsAmount = inputStream.readShort();\r
+        if (fieldsAmount < 0) {\r
+            throw new BlenderFileException("The amount of fields of " + this.type + " structure cannot be negative!");\r
+        }\r
+        if (fieldsAmount > 0) {\r
+            fields = new Field[fieldsAmount];\r
+            for (int i = 0; i < fieldsAmount; ++i) {\r
+                int typeIndex = inputStream.readShort();\r
+                nameIndex = inputStream.readShort();\r
+                fields[i] = new Field(names[nameIndex], types[typeIndex], dataRepository);\r
+            }\r
+        }\r
+        this.oldMemoryAddress = Long.valueOf(-1L);\r
+    }\r
 \r
-       /**\r
-        * This method returns the value of the filed with a given name.\r
-        * @param fieldName\r
-        *        the name of the field\r
-        * @return the value of the field or null if no field with a given name is found\r
-        */\r
-       public Object getFieldValue(String fieldName) {\r
-               for(Field field : fields) {\r
-                       if(field.name.equalsIgnoreCase(fieldName)) {\r
-                               return field.value;\r
-                       }\r
-               }\r
-               return null;\r
-       }\r
+    /**\r
+     * This method fills the structure with data.\r
+     * @param inputStream\r
+     *        the stream we read data from, its read cursor should be placed at the start position of the data for the\r
+     *        structure\r
+     * @throws BlenderFileException\r
+     *         an exception is thrown when the blend file is somehow invalid or corrupted\r
+     */\r
+    public void fill(BlenderInputStream inputStream) throws BlenderFileException {\r
+        int position = inputStream.getPosition();\r
+        inputStream.setPosition(position - 8 - inputStream.getPointerSize());\r
+        this.oldMemoryAddress = Long.valueOf(inputStream.readPointer());\r
+        inputStream.setPosition(position);\r
+        for (Field field : fields) {\r
+            field.fill(inputStream);\r
+        }\r
+    }\r
 \r
-       /**\r
-        * This method returns the value of the filed with a given name. The structure is considered to have flat fields\r
-        * only (no substructures).\r
-        * @param fieldName\r
-        *        the name of the field\r
-        * @return the value of the field or null if no field with a given name is found\r
-        */\r
-       public Object getFlatFieldValue(String fieldName) {\r
-               for(Field field : fields) {\r
-                       Object value = field.value;\r
-                       if(field.name.equalsIgnoreCase(fieldName)) {\r
-                               return value;\r
-                       } else if(value instanceof Structure) {\r
-                               value = ((Structure)value).getFlatFieldValue(fieldName);\r
-                               if(value != null) {//we can compare references here, since we use one static object as a NULL field value\r
-                                       return value;\r
-                               }\r
-                       }\r
-               }\r
-               return null;\r
-       }\r
+    /**\r
+     * This method returns the value of the filed with a given name.\r
+     * @param fieldName\r
+     *        the name of the field\r
+     * @return the value of the field or null if no field with a given name is found\r
+     */\r
+    public Object getFieldValue(String fieldName) {\r
+        for (Field field : fields) {\r
+            if (field.name.equalsIgnoreCase(fieldName)) {\r
+                return field.value;\r
+            }\r
+        }\r
+        return null;\r
+    }\r
 \r
-       /**\r
-        * This methos should be used on structures that are of a 'ListBase' type. It creates a List of structures that are\r
-        * held by this structure within the blend file.\r
-        * @param dataRepository\r
-        *        the data repository\r
-        * @return a list of filled structures\r
-        * @throws BlenderFileException\r
-        *         this exception is thrown when the blend file structure is somehow invalid or corrupted\r
-        * @throws IllegalArgumentException\r
-        *         this exception is thrown if the type of the structure is not 'ListBase'\r
-        */\r
-       public List<Structure> evaluateListBase(DataRepository dataRepository) throws BlenderFileException {\r
-               if(!"ListBase".equals(this.type)) {\r
-                       throw new IllegalStateException("This structure is not of type: 'ListBase'");\r
-               }\r
-               Pointer first = (Pointer)this.getFieldValue("first");\r
-               Pointer last = (Pointer)this.getFieldValue("last");\r
-               long currentAddress = 0;\r
-               long lastAddress = last.getOldMemoryAddress();\r
-               List<Structure> result = new LinkedList<Structure>();\r
-               while(currentAddress != lastAddress) {\r
-                       currentAddress = first.getOldMemoryAddress();\r
-                       Structure structure = first.fetchData(dataRepository.getInputStream()).get(0);\r
-                       result.add(structure);\r
-                       first = (Pointer)structure.getFlatFieldValue("next");\r
-               }\r
-               return result;\r
-       }\r
+    /**\r
+     * This method returns the value of the filed with a given name. The structure is considered to have flat fields\r
+     * only (no substructures).\r
+     * @param fieldName\r
+     *        the name of the field\r
+     * @return the value of the field or null if no field with a given name is found\r
+     */\r
+    public Object getFlatFieldValue(String fieldName) {\r
+        for (Field field : fields) {\r
+            Object value = field.value;\r
+            if (field.name.equalsIgnoreCase(fieldName)) {\r
+                return value;\r
+            } else if (value instanceof Structure) {\r
+                value = ((Structure) value).getFlatFieldValue(fieldName);\r
+                if (value != null) {//we can compare references here, since we use one static object as a NULL field value\r
+                    return value;\r
+                }\r
+            }\r
+        }\r
+        return null;\r
+    }\r
 \r
-       /**\r
-        * This method returns the type of the structure.\r
-        * @return the type of the structure\r
-        */\r
-       public String getType() {\r
-               return type;\r
-       }\r
+    /**\r
+     * This methos should be used on structures that are of a 'ListBase' type. It creates a List of structures that are\r
+     * held by this structure within the blend file.\r
+     * @param dataRepository\r
+     *        the data repository\r
+     * @return a list of filled structures\r
+     * @throws BlenderFileException\r
+     *         this exception is thrown when the blend file structure is somehow invalid or corrupted\r
+     * @throws IllegalArgumentException\r
+     *         this exception is thrown if the type of the structure is not 'ListBase'\r
+     */\r
+    public List<Structure> evaluateListBase(DataRepository dataRepository) throws BlenderFileException {\r
+        if (!"ListBase".equals(this.type)) {\r
+            throw new IllegalStateException("This structure is not of type: 'ListBase'");\r
+        }\r
+        Pointer first = (Pointer) this.getFieldValue("first");\r
+        Pointer last = (Pointer) this.getFieldValue("last");\r
+        long currentAddress = 0;\r
+        long lastAddress = last.getOldMemoryAddress();\r
+        List<Structure> result = new LinkedList<Structure>();\r
+        while (currentAddress != lastAddress) {\r
+            currentAddress = first.getOldMemoryAddress();\r
+            Structure structure = first.fetchData(dataRepository.getInputStream()).get(0);\r
+            result.add(structure);\r
+            first = (Pointer) structure.getFlatFieldValue("next");\r
+        }\r
+        return result;\r
+    }\r
 \r
-       /**\r
-        * This method returns the amount of fields for the current structure.\r
-        * @return the amount of fields for the current structure\r
-        */\r
-       public int getFieldsAmount() {\r
-               return fields.length;\r
-       }\r
+    /**\r
+     * This method returns the type of the structure.\r
+     * @return the type of the structure\r
+     */\r
+    public String getType() {\r
+        return type;\r
+    }\r
 \r
-       /**\r
-        * This method returns the field name of the given index.\r
-        * @param fieldIndex\r
-        *        the index of the field\r
-        * @return the field name of the given index\r
-        */\r
-       public String getFieldName(int fieldIndex) {\r
-               return fields[fieldIndex].name;\r
-       }\r
+    /**\r
+     * This method returns the amount of fields for the current structure.\r
+     * @return the amount of fields for the current structure\r
+     */\r
+    public int getFieldsAmount() {\r
+        return fields.length;\r
+    }\r
 \r
-       /**\r
-        * This method returns the field type of the given index.\r
-        * @param fieldIndex\r
-        *        the index of the field\r
-        * @return the field type of the given index\r
-        */\r
-       public String getFieldType(int fieldIndex) {\r
-               return fields[fieldIndex].type;\r
-       }\r
+    /**\r
+     * This method returns the field name of the given index.\r
+     * @param fieldIndex\r
+     *        the index of the field\r
+     * @return the field name of the given index\r
+     */\r
+    public String getFieldName(int fieldIndex) {\r
+        return fields[fieldIndex].name;\r
+    }\r
 \r
-       /**\r
-        * This method returns the address of the structure. The strucutre should be filled with data otherwise an exception\r
-        * is thrown.\r
-        * @return the address of the feature stored in this structure\r
-        */\r
-       public Long getOldMemoryAddress() {\r
-               if(oldMemoryAddress.longValue() == -1L) {\r
-                       throw new IllegalStateException("Call the 'fill' method and fill the structure with data first!");\r
-               }\r
-               return oldMemoryAddress;\r
-       }\r
+    /**\r
+     * This method returns the field type of the given index.\r
+     * @param fieldIndex\r
+     *        the index of the field\r
+     * @return the field type of the given index\r
+     */\r
+    public String getFieldType(int fieldIndex) {\r
+        return fields[fieldIndex].type;\r
+    }\r
 \r
-       /**\r
-        * This method returns the name of the structure. If the structure has an ID field then the name is returned.\r
-        * Otherwise the name does not exists and the method returns null.\r
-        * @return the name of the structure read from the ID field or null\r
-        */\r
-       public String getName() {\r
-               Structure id = (Structure)this.getFieldValue("ID");\r
-               return id == null ? null : id.getFieldValue("name").toString().substring(2);//blender adds 2-charactes as a name prefix\r
-       }\r
+    /**\r
+     * This method returns the address of the structure. The strucutre should be filled with data otherwise an exception\r
+     * is thrown.\r
+     * @return the address of the feature stored in this structure\r
+     */\r
+    public Long getOldMemoryAddress() {\r
+        if (oldMemoryAddress.longValue() == -1L) {\r
+            throw new IllegalStateException("Call the 'fill' method and fill the structure with data first!");\r
+        }\r
+        return oldMemoryAddress;\r
+    }\r
 \r
-       @Override\r
-       public String toString() {\r
-               StringBuilder result = new StringBuilder("struct ").append(type).append(" {\n");\r
-               for(int i = 0; i < fields.length; ++i) {\r
-                       result.append(fields[i].toString()).append('\n');\r
-               }\r
-               return result.append('}').toString();\r
-       }\r
+    /**\r
+     * This method returns the name of the structure. If the structure has an ID field then the name is returned.\r
+     * Otherwise the name does not exists and the method returns null.\r
+     * @return the name of the structure read from the ID field or null\r
+     */\r
+    public String getName() {\r
+        Structure id = (Structure) this.getFieldValue("ID");\r
+        return id == null ? null : id.getFieldValue("name").toString().substring(2);//blender adds 2-charactes as a name prefix\r
+    }\r
 \r
-       @Override\r
-       public Object clone() throws CloneNotSupportedException {\r
-               return new Structure(this, dataRepository);\r
-       }\r
+    @Override\r
+    public String toString() {\r
+        StringBuilder result = new StringBuilder("struct ").append(type).append(" {\n");\r
+        for (int i = 0; i < fields.length; ++i) {\r
+            result.append(fields[i].toString()).append('\n');\r
+        }\r
+        return result.append('}').toString();\r
+    }\r
 \r
-       /**\r
-        * This enum enumerates all known data types that can be found in the blend file.\r
-        * @author Marcin Roguski\r
-        */\r
-       /*package*/static enum DataType {\r
-               CHARACTER, SHORT, INTEGER, LONG, FLOAT, DOUBLE, VOID, STRUCTURE, POINTER;\r
+    @Override\r
+    public Object clone() throws CloneNotSupportedException {\r
+        return new Structure(this, dataRepository);\r
+    }\r
 \r
-               /** The map containing the known primary types. */\r
-               private static final Map<String, DataType>      PRIMARY_TYPES   = new HashMap<String, DataType>(10);\r
-               static {\r
-                       PRIMARY_TYPES.put("char", CHARACTER);\r
-                       PRIMARY_TYPES.put("uchar", CHARACTER);\r
-                       PRIMARY_TYPES.put("short", SHORT);\r
-                       PRIMARY_TYPES.put("ushort", SHORT);\r
-                       PRIMARY_TYPES.put("int", INTEGER);\r
-                       PRIMARY_TYPES.put("long", LONG);\r
-                       PRIMARY_TYPES.put("ulong", LONG);\r
-                       PRIMARY_TYPES.put("float", FLOAT);\r
-                       PRIMARY_TYPES.put("double", DOUBLE);\r
-                       PRIMARY_TYPES.put("void", VOID);\r
-               }\r
+    /**\r
+     * This enum enumerates all known data types that can be found in the blend file.\r
+     * @author Marcin Roguski\r
+     */\r
+    /*package*/\r
+    static enum DataType {\r
 \r
-               /**\r
-                * This method returns the data type that is appropriate to the given type name. WARNING! The type recognition\r
-                * is case sensitive!\r
-                * @param type\r
-                *        the type name of the data\r
-                * @param dataRepository\r
-                *        the data repository\r
-                * @return appropriate enum value to the given type name\r
-                * @throws BlenderFileException\r
-                *         this exception is thrown if the given type name does not exist in the blend file\r
-                */\r
-               public static DataType getDataType(String type, DataRepository dataRepository) throws BlenderFileException {\r
-                       DataType result = PRIMARY_TYPES.get(type);\r
-                       if(result != null) {\r
-                               return result;\r
-                       }\r
-                       if(dataRepository.getDnaBlockData().hasStructure(type)) {\r
-                               return STRUCTURE;\r
-                       }\r
-                       throw new BlenderFileException("Unknown data type: " + type);\r
-               }\r
-       }\r
+        CHARACTER, SHORT, INTEGER, LONG, FLOAT, DOUBLE, VOID, STRUCTURE, POINTER;\r
+        /** The map containing the known primary types. */\r
+        private static final Map<String, DataType> PRIMARY_TYPES = new HashMap<String, DataType>(10);\r
+\r
+        static {\r
+            PRIMARY_TYPES.put("char", CHARACTER);\r
+            PRIMARY_TYPES.put("uchar", CHARACTER);\r
+            PRIMARY_TYPES.put("short", SHORT);\r
+            PRIMARY_TYPES.put("ushort", SHORT);\r
+            PRIMARY_TYPES.put("int", INTEGER);\r
+            PRIMARY_TYPES.put("long", LONG);\r
+            PRIMARY_TYPES.put("ulong", LONG);\r
+            PRIMARY_TYPES.put("float", FLOAT);\r
+            PRIMARY_TYPES.put("double", DOUBLE);\r
+            PRIMARY_TYPES.put("void", VOID);\r
+        }\r
+\r
+        /**\r
+         * This method returns the data type that is appropriate to the given type name. WARNING! The type recognition\r
+         * is case sensitive!\r
+         * @param type\r
+         *        the type name of the data\r
+         * @param dataRepository\r
+         *        the data repository\r
+         * @return appropriate enum value to the given type name\r
+         * @throws BlenderFileException\r
+         *         this exception is thrown if the given type name does not exist in the blend file\r
+         */\r
+        public static DataType getDataType(String type, DataRepository dataRepository) throws BlenderFileException {\r
+            DataType result = PRIMARY_TYPES.get(type);\r
+            if (result != null) {\r
+                return result;\r
+            }\r
+            if (dataRepository.getDnaBlockData().hasStructure(type)) {\r
+                return STRUCTURE;\r
+            }\r
+            throw new BlenderFileException("Unknown data type: " + type);\r
+        }\r
+    }\r
 }\r
index 7b1b522..378cedd 100644 (file)
@@ -36,39 +36,41 @@ package com.jme3.scene.plugins.blender.exception;
  * @author Marcin Roguski\r
  */\r
 public class BlenderFileException extends Exception {\r
-       private static final long       serialVersionUID        = 7573482836437866767L;\r
 \r
-       /**\r
-        * Constructor. Creates an exception with no description.\r
-        */\r
-       public BlenderFileException() {}\r
+    private static final long serialVersionUID = 7573482836437866767L;\r
 \r
-       /**\r
-        * Constructor. Creates an exception containing the given message.\r
-        * @param message\r
-        *        the message describing the problem that occured\r
-        */\r
-       public BlenderFileException(String message) {\r
-               super(message);\r
-       }\r
+    /**\r
+     * Constructor. Creates an exception with no description.\r
+     */\r
+    public BlenderFileException() {\r
+    }\r
 \r
-       /**\r
-        * Constructor. Creates an exception that is based upon other thrown object. It contains the whole stacktrace then.\r
-        * @param throwable\r
-        *        an exception/error that occured\r
-        */\r
-       public BlenderFileException(Throwable throwable) {\r
-               super(throwable);\r
-       }\r
+    /**\r
+     * Constructor. Creates an exception containing the given message.\r
+     * @param message\r
+     *        the message describing the problem that occured\r
+     */\r
+    public BlenderFileException(String message) {\r
+        super(message);\r
+    }\r
 \r
-       /**\r
-        * Constructor. Creates an exception with both a message and stacktrace.\r
-        * @param message\r
-        *        the message describing the problem that occured\r
-        * @param throwable\r
-        *        an exception/error that occured\r
-        */\r
-       public BlenderFileException(String message, Throwable throwable) {\r
-               super(message, throwable);\r
-       }\r
+    /**\r
+     * Constructor. Creates an exception that is based upon other thrown object. It contains the whole stacktrace then.\r
+     * @param throwable\r
+     *        an exception/error that occured\r
+     */\r
+    public BlenderFileException(Throwable throwable) {\r
+        super(throwable);\r
+    }\r
+\r
+    /**\r
+     * Constructor. Creates an exception with both a message and stacktrace.\r
+     * @param message\r
+     *        the message describing the problem that occured\r
+     * @param throwable\r
+     *        an exception/error that occured\r
+     */\r
+    public BlenderFileException(String message, Throwable throwable) {\r
+        super(message, throwable);\r
+    }\r
 }\r
index 3312784..ec01a51 100644 (file)
@@ -46,87 +46,87 @@ import com.jme3.scene.plugins.blender.utils.BlenderInputStream;
 import com.jme3.scene.plugins.blender.utils.DataRepository;\r
 import com.jme3.scene.plugins.blender.utils.Pointer;\r
 \r
-\r
 /**\r
  * This class defines the methods to calculate certain aspects of animation and armature functionalities.\r
  * @author Marcin Roguski\r
  */\r
 public class ArmatureHelper extends com.jme3.scene.plugins.blender.helpers.v249.ArmatureHelper {\r
-       private static final Logger                             LOGGER                  = Logger.getLogger(ArmatureHelper.class.getName());\r
-       \r
-       /**\r
-        * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
-        * different blender versions.\r
-        * @param blenderVersion\r
-        *        the version read from the blend file\r
-        */\r
-       public ArmatureHelper(String blenderVersion) {\r
-               super(blenderVersion);\r
-       }\r
-       \r
-       @Override\r
-       public BoneTrack[] getTracks(Structure actionStructure, DataRepository dataRepository, String objectName, String animationName) throws BlenderFileException {\r
-               if(blenderVersion<250) {\r
-                       return super.getTracks(actionStructure, dataRepository, objectName, animationName);\r
-               }\r
-               LOGGER.log(Level.INFO, "Getting tracks!");\r
-               int fps = dataRepository.getBlenderKey().getFps();\r
-               int[] animationFrames = dataRepository.getBlenderKey().getAnimationFrames(objectName, animationName);\r
-               Structure groups = (Structure)actionStructure.getFieldValue("groups");\r
-               List<Structure> actionGroups = groups.evaluateListBase(dataRepository);//bActionGroup\r
-               if(actionGroups != null && actionGroups.size() > 0 && (bonesMap == null || bonesMap.size() == 0)) {\r
-                       throw new IllegalStateException("No bones found! Cannot proceed to calculating tracks!");\r
-               }\r
-               \r
-               List<BoneTrack> tracks = new ArrayList<BoneTrack>();\r
-               for(Structure actionGroup : actionGroups) {\r
-                       String name = actionGroup.getFieldValue("name").toString();\r
-                       Integer boneIndex = bonesMap.get(name);\r
-                       if(boneIndex != null) {\r
-                               List<Structure> channels = ((Structure)actionGroup.getFieldValue("channels")).evaluateListBase(dataRepository);\r
-                               BezierCurve[] bezierCurves = new BezierCurve[channels.size()];\r
-                               int channelCounter = 0;\r
-                               for(Structure c : channels) {\r
-                                       //reading rna path first\r
-                                       BlenderInputStream bis = dataRepository.getInputStream();\r
-                                       int currentPosition = bis.getPosition();\r
-                                       Pointer pRnaPath = (Pointer) c.getFieldValue("rna_path");\r
-                                       FileBlockHeader dataFileBlock = dataRepository.getFileBlock(pRnaPath.getOldMemoryAddress());\r
-                                       bis.setPosition(dataFileBlock.getBlockPosition());\r
-                                       String rnaPath = bis.readString();\r
-                                       bis.setPosition(currentPosition);\r
-                                       int arrayIndex = ((Number)c.getFieldValue("array_index")).intValue();\r
-                                       int type = this.getCurveType(rnaPath, arrayIndex);\r
 \r
-                                       Pointer pBezTriple = (Pointer)c.getFieldValue("bezt");\r
-                                       List<Structure> bezTriples = pBezTriple.fetchData(dataRepository.getInputStream());\r
-                                       bezierCurves[channelCounter++] = new BezierCurve(type, bezTriples, 2);\r
-                               }\r
+    private static final Logger LOGGER = Logger.getLogger(ArmatureHelper.class.getName());\r
+\r
+    /**\r
+     * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
+     * different blender versions.\r
+     * @param blenderVersion\r
+     *        the version read from the blend file\r
+     */\r
+    public ArmatureHelper(String blenderVersion) {\r
+        super(blenderVersion);\r
+    }\r
+\r
+    @Override\r
+    public BoneTrack[] getTracks(Structure actionStructure, DataRepository dataRepository, String objectName, String animationName) throws BlenderFileException {\r
+        if (blenderVersion < 250) {\r
+            return super.getTracks(actionStructure, dataRepository, objectName, animationName);\r
+        }\r
+        LOGGER.log(Level.INFO, "Getting tracks!");\r
+        int fps = dataRepository.getBlenderKey().getFps();\r
+        int[] animationFrames = dataRepository.getBlenderKey().getAnimationFrames(objectName, animationName);\r
+        Structure groups = (Structure) actionStructure.getFieldValue("groups");\r
+        List<Structure> actionGroups = groups.evaluateListBase(dataRepository);//bActionGroup\r
+        if (actionGroups != null && actionGroups.size() > 0 && (bonesMap == null || bonesMap.size() == 0)) {\r
+            throw new IllegalStateException("No bones found! Cannot proceed to calculating tracks!");\r
+        }\r
+\r
+        List<BoneTrack> tracks = new ArrayList<BoneTrack>();\r
+        for (Structure actionGroup : actionGroups) {\r
+            String name = actionGroup.getFieldValue("name").toString();\r
+            Integer boneIndex = bonesMap.get(name);\r
+            if (boneIndex != null) {\r
+                List<Structure> channels = ((Structure) actionGroup.getFieldValue("channels")).evaluateListBase(dataRepository);\r
+                BezierCurve[] bezierCurves = new BezierCurve[channels.size()];\r
+                int channelCounter = 0;\r
+                for (Structure c : channels) {\r
+                    //reading rna path first\r
+                    BlenderInputStream bis = dataRepository.getInputStream();\r
+                    int currentPosition = bis.getPosition();\r
+                    Pointer pRnaPath = (Pointer) c.getFieldValue("rna_path");\r
+                    FileBlockHeader dataFileBlock = dataRepository.getFileBlock(pRnaPath.getOldMemoryAddress());\r
+                    bis.setPosition(dataFileBlock.getBlockPosition());\r
+                    String rnaPath = bis.readString();\r
+                    bis.setPosition(currentPosition);\r
+                    int arrayIndex = ((Number) c.getFieldValue("array_index")).intValue();\r
+                    int type = this.getCurveType(rnaPath, arrayIndex);\r
+\r
+                    Pointer pBezTriple = (Pointer) c.getFieldValue("bezt");\r
+                    List<Structure> bezTriples = pBezTriple.fetchData(dataRepository.getInputStream());\r
+                    bezierCurves[channelCounter++] = new BezierCurve(type, bezTriples, 2);\r
+                }\r
+\r
+                Ipo ipo = new Ipo(bezierCurves);\r
+                tracks.add(ipo.calculateTrack(boneIndex.intValue(), animationFrames[0], animationFrames[1], fps));\r
+            }\r
+        }\r
+        return tracks.toArray(new BoneTrack[tracks.size()]);\r
+    }\r
 \r
-                               Ipo ipo = new Ipo(bezierCurves);\r
-                               tracks.add(ipo.calculateTrack(boneIndex.intValue(), animationFrames[0], animationFrames[1], fps));\r
-                       }\r
-               }\r
-               return tracks.toArray(new BoneTrack[tracks.size()]);\r
-       }\r
-       \r
-       /**\r
-        * This method parses the information stored inside the curve rna path and returns the proper type\r
-        * of the curve.\r
-        * @param rnaPath the curve's rna path\r
-        * @param arrayIndex the array index of the stored data\r
-        * @return the type of the curve\r
-        */\r
-       protected int getCurveType(String rnaPath, int arrayIndex) {\r
-               if(rnaPath.endsWith(".location")) {\r
-                       return Ipo.AC_LOC_X + arrayIndex;\r
-               }\r
-               if(rnaPath.endsWith(".rotation_quaternion")) {\r
-                       return Ipo.AC_QUAT_W + arrayIndex;\r
-               }\r
-               if(rnaPath.endsWith(".scale")) {\r
-                       return Ipo.AC_SIZE_X + arrayIndex;\r
-               }\r
-               throw new IllegalStateException("Unknown curve rna path: " + rnaPath);\r
-       }\r
+    /**\r
+     * This method parses the information stored inside the curve rna path and returns the proper type\r
+     * of the curve.\r
+     * @param rnaPath the curve's rna path\r
+     * @param arrayIndex the array index of the stored data\r
+     * @return the type of the curve\r
+     */\r
+    protected int getCurveType(String rnaPath, int arrayIndex) {\r
+        if (rnaPath.endsWith(".location")) {\r
+            return Ipo.AC_LOC_X + arrayIndex;\r
+        }\r
+        if (rnaPath.endsWith(".rotation_quaternion")) {\r
+            return Ipo.AC_QUAT_W + arrayIndex;\r
+        }\r
+        if (rnaPath.endsWith(".scale")) {\r
+            return Ipo.AC_SIZE_X + arrayIndex;\r
+        }\r
+        throw new IllegalStateException("Unknown curve rna path: " + rnaPath);\r
+    }\r
 }\r
index 1576419..30829b0 100644 (file)
@@ -12,40 +12,41 @@ import com.jme3.scene.plugins.blender.exception.BlenderFileException;
  * @author Marcin Roguski\r
  */\r
 public class CameraHelper extends com.jme3.scene.plugins.blender.helpers.v249.CameraHelper {\r
-       private static final Logger                     LOGGER          = Logger.getLogger(CameraHelper.class.getName());\r
-       \r
-       /**\r
-        * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
-        * different blender versions.\r
-        * @param blenderVersion\r
-        *        the version read from the blend file\r
-        */\r
-       public CameraHelper(String blenderVersion) {\r
-               super(blenderVersion);\r
-       }\r
-       \r
-       @Override\r
-       public Camera toCamera(Structure structure) throws BlenderFileException {\r
-               if(blenderVersion<250) {\r
-                       return super.toCamera(structure);\r
-               }\r
-               Camera result = new Camera(DEFAULT_CAM_WIDTH, DEFAULT_CAM_HEIGHT);\r
-               int type = ((Number)structure.getFieldValue("type")).intValue();\r
-               if(type != 0 && type != 1) {\r
-                       LOGGER.log(Level.WARNING, "Unknown camera type: " + type + ". Perspective camera is being used!");\r
-                       type = 0;\r
-               }\r
-               //type==0 - perspective; type==1 - orthographic; perspective is used as default\r
-               result.setParallelProjection(type == 1);\r
-               float aspect = 0;\r
-               float clipsta = ((Number)structure.getFieldValue("clipsta")).floatValue();\r
-               float clipend = ((Number)structure.getFieldValue("clipend")).floatValue();\r
-               if(type == 0) {\r
-                       aspect = ((Number)structure.getFieldValue("lens")).floatValue();\r
-               } else {\r
-                       aspect = ((Number)structure.getFieldValue("ortho_scale")).floatValue();\r
-               }\r
-               result.setFrustumPerspective(45, aspect, clipsta, clipend);\r
-               return result;\r
-       }\r
+\r
+    private static final Logger LOGGER = Logger.getLogger(CameraHelper.class.getName());\r
+\r
+    /**\r
+     * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
+     * different blender versions.\r
+     * @param blenderVersion\r
+     *        the version read from the blend file\r
+     */\r
+    public CameraHelper(String blenderVersion) {\r
+        super(blenderVersion);\r
+    }\r
+\r
+    @Override\r
+    public Camera toCamera(Structure structure) throws BlenderFileException {\r
+        if (blenderVersion < 250) {\r
+            return super.toCamera(structure);\r
+        }\r
+        Camera result = new Camera(DEFAULT_CAM_WIDTH, DEFAULT_CAM_HEIGHT);\r
+        int type = ((Number) structure.getFieldValue("type")).intValue();\r
+        if (type != 0 && type != 1) {\r
+            LOGGER.log(Level.WARNING, "Unknown camera type: {0}. Perspective camera is being used!", type);\r
+            type = 0;\r
+        }\r
+        //type==0 - perspective; type==1 - orthographic; perspective is used as default\r
+        result.setParallelProjection(type == 1);\r
+        float aspect = 0;\r
+        float clipsta = ((Number) structure.getFieldValue("clipsta")).floatValue();\r
+        float clipend = ((Number) structure.getFieldValue("clipend")).floatValue();\r
+        if (type == 0) {\r
+            aspect = ((Number) structure.getFieldValue("lens")).floatValue();\r
+        } else {\r
+            aspect = ((Number) structure.getFieldValue("ortho_scale")).floatValue();\r
+        }\r
+        result.setFrustumPerspective(45, aspect, clipsta, clipend);\r
+        return result;\r
+    }\r
 }\r
index 4847310..d60da53 100644 (file)
@@ -11,27 +11,28 @@ import com.jme3.scene.plugins.blender.utils.DataRepository;
  * @author Marcin Roguski\r
  */\r
 public class ConstraintHelper extends com.jme3.scene.plugins.blender.helpers.v249.ConstraintHelper {\r
-       private static final Logger LOGGER = Logger.getLogger(ConstraintHelper.class.getName());\r
-       \r
-       /**\r
-        * Helper constructor. It's main task is to generate the affection functions. These functions are common to all\r
-        * ConstraintHelper instances. Unfortunately this constructor might grow large. If it becomes too large - I shall\r
-        * consider refactoring. The constructor parses the given blender version and stores the result. Some\r
-        * functionalities may differ in different blender versions.\r
-        * @param blenderVersion\r
-        *        the version read from the blend file\r
-        */\r
-       public ConstraintHelper(String blenderVersion, DataRepository dataRepository) {\r
-               super(blenderVersion, dataRepository);\r
-       }\r
-       \r
-       @Override\r
-       public void loadConstraints(Structure objectStructure, DataRepository dataRepository) throws BlenderFileException {\r
-               if(blenderVersion<250) {\r
-                       super.loadConstraints(objectStructure, dataRepository);\r
-               } else {\r
-                       LOGGER.warning("Loading of constraints not yet implemented for version 2.5x !");\r
-                       //TODO: to implement\r
-               }\r
-       }\r
+\r
+    private static final Logger LOGGER = Logger.getLogger(ConstraintHelper.class.getName());\r
+\r
+    /**\r
+     * Helper constructor. It's main task is to generate the affection functions. These functions are common to all\r
+     * ConstraintHelper instances. Unfortunately this constructor might grow large. If it becomes too large - I shall\r
+     * consider refactoring. The constructor parses the given blender version and stores the result. Some\r
+     * functionalities may differ in different blender versions.\r
+     * @param blenderVersion\r
+     *        the version read from the blend file\r
+     */\r
+    public ConstraintHelper(String blenderVersion, DataRepository dataRepository) {\r
+        super(blenderVersion, dataRepository);\r
+    }\r
+\r
+    @Override\r
+    public void loadConstraints(Structure objectStructure, DataRepository dataRepository) throws BlenderFileException {\r
+        if (blenderVersion < 250) {\r
+            super.loadConstraints(objectStructure, dataRepository);\r
+        } else {\r
+            LOGGER.warning("Loading of constraints not yet implemented for version 2.5x !");\r
+            //TODO: to implement\r
+        }\r
+    }\r
 }\r
index 1f3f38d..cb4f42d 100644 (file)
@@ -5,13 +5,14 @@ package com.jme3.scene.plugins.blender.helpers;
  * @author Marcin Roguski\r
  */\r
 public class CurvesHelper extends com.jme3.scene.plugins.blender.helpers.v249.CurvesHelper {\r
-       /**\r
-        * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
-        * different blender versions.\r
-        * @param blenderVersion\r
-        *        the version read from the blend file\r
-        */\r
-       public CurvesHelper(String blenderVersion) {\r
-               super(blenderVersion);\r
-       }\r
+\r
+    /**\r
+     * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
+     * different blender versions.\r
+     * @param blenderVersion\r
+     *        the version read from the blend file\r
+     */\r
+    public CurvesHelper(String blenderVersion) {\r
+        super(blenderVersion);\r
+    }\r
 }\r
index 65d5f61..96ab48a 100644 (file)
@@ -6,13 +6,14 @@ package com.jme3.scene.plugins.blender.helpers;
  * @author Marcin Roguski\r
  */\r
 public class IpoHelper extends com.jme3.scene.plugins.blender.helpers.v249.IpoHelper {\r
-       /**\r
-        * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
-        * different blender versions.\r
-        * @param blenderVersion\r
-        *        the version read from the blend file\r
-        */\r
-       public IpoHelper(String blenderVersion) {\r
-               super(blenderVersion);\r
-       }\r
+\r
+    /**\r
+     * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
+     * different blender versions.\r
+     * @param blenderVersion\r
+     *        the version read from the blend file\r
+     */\r
+    public IpoHelper(String blenderVersion) {\r
+        super(blenderVersion);\r
+    }\r
 }\r
index fe11d1c..8cdcf5b 100644 (file)
@@ -36,13 +36,14 @@ package com.jme3.scene.plugins.blender.helpers;
  * @author Marcin Roguski\r
  */\r
 public class LightHelper extends com.jme3.scene.plugins.blender.helpers.v249.LightHelper {\r
-       /**\r
-        * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
-        * different blender versions.\r
-        * @param blenderVersion\r
-        *        the version read from the blend file\r
-        */\r
-       public LightHelper(String blenderVersion) {\r
-               super(blenderVersion);\r
-       }\r
+\r
+    /**\r
+     * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
+     * different blender versions.\r
+     * @param blenderVersion\r
+     *        the version read from the blend file\r
+     */\r
+    public LightHelper(String blenderVersion) {\r
+        super(blenderVersion);\r
+    }\r
 }\r
index a10590c..b2b1177 100644 (file)
 package com.jme3.scene.plugins.blender.helpers;\r
 \r
 public class MaterialHelper extends com.jme3.scene.plugins.blender.helpers.v249.MaterialHelper {\r
-       /**\r
-        * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
-        * different blender versions.\r
-        * @param blenderVersion\r
-        *        the version read from the blend file\r
-        */\r
-       public MaterialHelper(String blenderVersion) {\r
-               super(blenderVersion);\r
-       }\r
+\r
+    /**\r
+     * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
+     * different blender versions.\r
+     * @param blenderVersion\r
+     *        the version read from the blend file\r
+     */\r
+    public MaterialHelper(String blenderVersion) {\r
+        super(blenderVersion);\r
+    }\r
 }\r
index 904af02..58b2e04 100644 (file)
@@ -36,13 +36,14 @@ package com.jme3.scene.plugins.blender.helpers;
  * @author Marcin Roguski\r
  */\r
 public class MeshHelper extends com.jme3.scene.plugins.blender.helpers.v249.MeshHelper {\r
-       /**\r
-        * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
-        * different blender versions.\r
-        * @param blenderVersion\r
-        *        the version read from the blend file\r
-        */\r
-       public MeshHelper(String blenderVersion) {\r
-               super(blenderVersion);\r
-       }\r
+\r
+    /**\r
+     * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
+     * different blender versions.\r
+     * @param blenderVersion\r
+     *        the version read from the blend file\r
+     */\r
+    public MeshHelper(String blenderVersion) {\r
+        super(blenderVersion);\r
+    }\r
 }\r
index 4c39b93..821c907 100644 (file)
@@ -36,13 +36,14 @@ package com.jme3.scene.plugins.blender.helpers;
  * @author Marcin Roguski\r
  */\r
 public class ModifierHelper extends com.jme3.scene.plugins.blender.helpers.v249.ModifierHelper {\r
-       /**\r
-        * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
-        * different blender versions.\r
-        * @param blenderVersion\r
-        *        the version read from the blend file\r
-        */\r
-       public ModifierHelper(String blenderVersion) {\r
-               super(blenderVersion);\r
-       }\r
+\r
+    /**\r
+     * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
+     * different blender versions.\r
+     * @param blenderVersion\r
+     *        the version read from the blend file\r
+     */\r
+    public ModifierHelper(String blenderVersion) {\r
+        super(blenderVersion);\r
+    }\r
 }\r
index 6403499..babd416 100644 (file)
@@ -39,13 +39,14 @@ package com.jme3.scene.plugins.blender.helpers;
  * @author Marcin Roguski (Kaelthas)\r
  */\r
 public class NoiseHelper extends com.jme3.scene.plugins.blender.helpers.v249.NoiseHelper {\r
-       /**\r
-        * Constructor. Stores the blender version number and loads the constants needed for computations.\r
-        * \r
-        * @param blenderVersion\r
-        *            the number of blender version\r
-        */\r
-       public NoiseHelper(String blenderVersion) {\r
-               super(blenderVersion);\r
-       }\r
+\r
+    /**\r
+     * Constructor. Stores the blender version number and loads the constants needed for computations.\r
+     * \r
+     * @param blenderVersion\r
+     *            the number of blender version\r
+     */\r
+    public NoiseHelper(String blenderVersion) {\r
+        super(blenderVersion);\r
+    }\r
 }\r
index b469a9e..a735067 100644 (file)
@@ -36,13 +36,14 @@ package com.jme3.scene.plugins.blender.helpers;
  * @author Marcin Roguski\r
  */\r
 public class ObjectHelper extends com.jme3.scene.plugins.blender.helpers.v249.ObjectHelper {\r
-       /**\r
-        * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
-        * different blender versions.\r
-        * @param blenderVersion\r
-        *        the version read from the blend file\r
-        */\r
-       public ObjectHelper(String blenderVersion) {\r
-               super(blenderVersion);\r
-       }\r
+\r
+    /**\r
+     * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
+     * different blender versions.\r
+     * @param blenderVersion\r
+     *        the version read from the blend file\r
+     */\r
+    public ObjectHelper(String blenderVersion) {\r
+        super(blenderVersion);\r
+    }\r
 }\r
index c0c1612..9993d75 100644 (file)
@@ -5,13 +5,14 @@ package com.jme3.scene.plugins.blender.helpers;
  * @author Marcin Roguski (Kaelthas)\r
  */\r
 public class ParticlesHelper extends com.jme3.scene.plugins.blender.helpers.v249.ParticlesHelper {\r
-       /**\r
-        * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
-        * different blender versions.\r
-        * @param blenderVersion\r
-        *        the version read from the blend file\r
-        */\r
-       public ParticlesHelper(String blenderVersion) {\r
-               super(blenderVersion);\r
-       }\r
+\r
+    /**\r
+     * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
+     * different blender versions.\r
+     * @param blenderVersion\r
+     *        the version read from the blend file\r
+     */\r
+    public ParticlesHelper(String blenderVersion) {\r
+        super(blenderVersion);\r
+    }\r
 }\r
index 7f9c399..a29801b 100644 (file)
@@ -44,39 +44,41 @@ import com.jme3.texture.Texture;
  * @author Marcin Roguski\r
  */\r
 public class TextureHelper extends com.jme3.scene.plugins.blender.helpers.v249.TextureHelper {\r
-       private static final Logger     LOGGER                  = Logger.getLogger(TextureHelper.class.getName());\r
-       public static final int         TEX_POINTDENSITY        = 14;\r
-       public static final int         TEX_VOXELDATA           = 15;\r
-       /**\r
-        * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
-        * different blender versions.\r
-        * @param blenderVersion\r
-        *        the version read from the blend file\r
-        */\r
-       public TextureHelper(String blenderVersion) {\r
-               super(blenderVersion);\r
-       }\r
-       \r
-       @Override\r
-       public Texture getTexture(Structure tex, DataRepository dataRepository) throws BlenderFileException {\r
-               if(blenderVersion<250) {\r
-                       return super.getTexture(tex, dataRepository);\r
-               }\r
-               Texture result = (Texture) dataRepository.getLoadedFeature(tex.getOldMemoryAddress(), LoadedFeatureDataType.LOADED_FEATURE);\r
-               if (result != null) {\r
-                       return result;\r
-               }\r
-               int type = ((Number)tex.getFieldValue("type")).intValue();\r
-               switch(type) {\r
-                       case TEX_POINTDENSITY:\r
-                               LOGGER.warning("Point density texture loading currently not supported!");\r
-                               break;\r
-                       case TEX_VOXELDATA:\r
-                               LOGGER.warning("Voxel data texture loading currently not supported!");\r
-                               break;\r
-                       default:\r
-                               result = super.getTexture(tex, dataRepository);\r
-               }\r
-               return result;\r
-       }\r
+\r
+    private static final Logger LOGGER = Logger.getLogger(TextureHelper.class.getName());\r
+    public static final int TEX_POINTDENSITY = 14;\r
+    public static final int TEX_VOXELDATA = 15;\r
+\r
+    /**\r
+     * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
+     * different blender versions.\r
+     * @param blenderVersion\r
+     *        the version read from the blend file\r
+     */\r
+    public TextureHelper(String blenderVersion) {\r
+        super(blenderVersion);\r
+    }\r
+\r
+    @Override\r
+    public Texture getTexture(Structure tex, DataRepository dataRepository) throws BlenderFileException {\r
+        if (blenderVersion < 250) {\r
+            return super.getTexture(tex, dataRepository);\r
+        }\r
+        Texture result = (Texture) dataRepository.getLoadedFeature(tex.getOldMemoryAddress(), LoadedFeatureDataType.LOADED_FEATURE);\r
+        if (result != null) {\r
+            return result;\r
+        }\r
+        int type = ((Number) tex.getFieldValue("type")).intValue();\r
+        switch (type) {\r
+            case TEX_POINTDENSITY:\r
+                LOGGER.warning("Point density texture loading currently not supported!");\r
+                break;\r
+            case TEX_VOXELDATA:\r
+                LOGGER.warning("Voxel data texture loading currently not supported!");\r
+                break;\r
+            default:\r
+                result = super.getTexture(tex, dataRepository);\r
+        }\r
+        return result;\r
+    }\r
 }\r
index 1118e6b..bec0324 100644 (file)
@@ -60,311 +60,312 @@ import com.jme3.scene.plugins.blender.utils.Pointer;
  * @author Marcin Roguski\r
  */\r
 public class ArmatureHelper extends AbstractBlenderHelper {\r
-       private static final Logger                             LOGGER                  = Logger.getLogger(ArmatureHelper.class.getName());\r
 \r
-       /**\r
-        * The map of the bones. Maps a bone name to its index in the armature. Should be cleared after the object had been\r
-        * read. TODO: probably bones can have identical names in different armatures\r
-        */\r
-       protected Map<String, Integer>                          bonesMap                = new HashMap<String, Integer>();\r
-       /** A map of bones and their old memory addresses. */\r
-       protected Map<Bone, Long>                                       bonesOMAs               = new HashMap<Bone, Long>();\r
-       /** This list contains bones hierarchy and their matrices. It is later converted into jme bones. */\r
-       protected List<BoneTransformationData>          boneDataRoots   = new ArrayList<BoneTransformationData>();\r
-       \r
-       /**\r
-        * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
-        * different blender versions.\r
-        * @param blenderVersion\r
-        *        the version read from the blend file\r
-        */\r
-       public ArmatureHelper(String blenderVersion) {\r
-               super(blenderVersion);\r
-       }\r
+    private static final Logger LOGGER = Logger.getLogger(ArmatureHelper.class.getName());\r
+    /**\r
+     * The map of the bones. Maps a bone name to its index in the armature. Should be cleared after the object had been\r
+     * read. TODO: probably bones can have identical names in different armatures\r
+     */\r
+    protected Map<String, Integer> bonesMap = new HashMap<String, Integer>();\r
+    /** A map of bones and their old memory addresses. */\r
+    protected Map<Bone, Long> bonesOMAs = new HashMap<Bone, Long>();\r
+    /** This list contains bones hierarchy and their matrices. It is later converted into jme bones. */\r
+    protected List<BoneTransformationData> boneDataRoots = new ArrayList<BoneTransformationData>();\r
 \r
-       /**\r
-        * This method returns the old memory address of a bone. If the bone does not exist in the blend file - zero is\r
-        * returned.\r
-        * @param bone\r
-        *        the bone whose old memory address we seek\r
-        * @return the old memory address of the given bone\r
-        */\r
-       public Long getBoneOMA(Bone bone) {\r
-               Long result = bonesOMAs.get(bone);\r
-               if(result == null) {\r
-                       result = Long.valueOf(0);\r
-               }\r
-               return result;\r
-       }\r
+    /**\r
+     * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
+     * different blender versions.\r
+     * @param blenderVersion\r
+     *        the version read from the blend file\r
+     */\r
+    public ArmatureHelper(String blenderVersion) {\r
+        super(blenderVersion);\r
+    }\r
 \r
-       /**\r
-        * This method reads the bones and returns an empty skeleton. Bones should be assigned later.\r
-        * @param structure\r
-        *        armature structure\r
-        * @param dataRepository\r
-        *        the data repository\r
-        * @return an empty skeleton, bones are stored within the helper object\r
-        * @throws BlenderFileException\r
-        *         this exception is thrown when the blender file is somehow corrupted\r
-        */\r
-       public Skeleton toArmature(Structure structure, DataRepository dataRepository) throws BlenderFileException {\r
-               LOGGER.log(Level.INFO, "Converting structure to Armature!");\r
-               Structure bonebase = (Structure)structure.getFieldValue("bonebase");\r
-               List<Structure> bonesStructures = bonebase.evaluateListBase(dataRepository);\r
-               for(Structure boneStructure : bonesStructures) {\r
-                       BoneTransformationData rootBoneTransformationData = this.readBoneAndItsChildren(boneStructure, null, dataRepository);\r
-                       boneDataRoots.add(rootBoneTransformationData);\r
-               }\r
-               return new Skeleton();//bones are assigned later\r
-       }\r
+    /**\r
+     * This method returns the old memory address of a bone. If the bone does not exist in the blend file - zero is\r
+     * returned.\r
+     * @param bone\r
+     *        the bone whose old memory address we seek\r
+     * @return the old memory address of the given bone\r
+     */\r
+    public Long getBoneOMA(Bone bone) {\r
+        Long result = bonesOMAs.get(bone);\r
+        if (result == null) {\r
+            result = Long.valueOf(0);\r
+        }\r
+        return result;\r
+    }\r
 \r
-       /**\r
-        * This method returns a map where the key is the object's group index that is used by a bone and the key is the\r
-        * bone index in the armature.\r
-        * @param poseStructure\r
-        *        a bPose structure of the object\r
-        * @return bone group-to-index map\r
-        * @throws BlenderFileException\r
-        *         this exception is thrown when the blender file is somehow corrupted\r
-        */\r
-       public Map<Integer, Integer> getGroupToBoneIndexMap(Structure defBaseStructure, DataRepository dataRepository) throws BlenderFileException {\r
-               Map<Integer, Integer> result = null;\r
-               if(bonesMap != null && bonesMap.size() != 0) {\r
-                       result = new HashMap<Integer, Integer>();\r
-                       List<Structure> deformGroups = defBaseStructure.evaluateListBase(dataRepository);//bDeformGroup\r
-                       int groupIndex = 0;//TODO: consider many armatures attached to one object in the future !!!\r
-                       for(Structure deformGroup : deformGroups) {\r
-                               String deformGroupName = deformGroup.getFieldValue("name").toString();\r
-                               Integer boneIndex = bonesMap.get(deformGroupName);\r
-                               if(boneIndex != null) {\r
-                                       result.put(Integer.valueOf(groupIndex), boneIndex);\r
-                               }\r
-                               ++groupIndex;\r
-                       }\r
-               }\r
-               return result;\r
-       }\r
+    /**\r
+     * This method reads the bones and returns an empty skeleton. Bones should be assigned later.\r
+     * @param structure\r
+     *        armature structure\r
+     * @param dataRepository\r
+     *        the data repository\r
+     * @return an empty skeleton, bones are stored within the helper object\r
+     * @throws BlenderFileException\r
+     *         this exception is thrown when the blender file is somehow corrupted\r
+     */\r
+    public Skeleton toArmature(Structure structure, DataRepository dataRepository) throws BlenderFileException {\r
+        LOGGER.log(Level.INFO, "Converting structure to Armature!");\r
+        Structure bonebase = (Structure) structure.getFieldValue("bonebase");\r
+        List<Structure> bonesStructures = bonebase.evaluateListBase(dataRepository);\r
+        for (Structure boneStructure : bonesStructures) {\r
+            BoneTransformationData rootBoneTransformationData = this.readBoneAndItsChildren(boneStructure, null, dataRepository);\r
+            boneDataRoots.add(rootBoneTransformationData);\r
+        }\r
+        return new Skeleton();//bones are assigned later\r
+    }\r
 \r
-       /**\r
-        * This method reads the tracks of the armature object.\r
-        * @param actionStructure\r
-        * @param dataRepository\r
-        *        the data repository\r
-        * @param objectName\r
-        *        the name of animation owner\r
-        * @param animationName\r
-        *        the name of the animation\r
-        * @return a list of tracks for the armature\r
-        * @throws BlenderFileException\r
-        *         this exception is thrown when the blender file is somehow corrupted\r
-        */\r
-       public BoneTrack[] getTracks(Structure actionStructure, DataRepository dataRepository, String objectName, String animationName) throws BlenderFileException {\r
-               LOGGER.log(Level.INFO, "Getting tracks!");\r
-               IpoHelper ipoHelper = dataRepository.getHelper(IpoHelper.class);\r
-               int fps = dataRepository.getBlenderKey().getFps();\r
-               int[] animationFrames = dataRepository.getBlenderKey().getAnimationFrames(objectName, animationName);\r
-               Structure chanbase = (Structure)actionStructure.getFieldValue("chanbase");\r
-               List<Structure> actionChannels = chanbase.evaluateListBase(dataRepository);//bActionChannel\r
-               if(actionChannels != null && actionChannels.size() > 0 && (bonesMap == null || bonesMap.size() == 0)) {\r
-                       throw new IllegalStateException("No bones found! Cannot proceed to calculating tracks!");\r
-               }\r
-               List<BoneTrack> tracks = new ArrayList<BoneTrack>();\r
-               for(Structure bActionChannel : actionChannels) {\r
-                       String name = bActionChannel.getFieldValue("name").toString();\r
-                       Integer boneIndex = bonesMap.get(name);\r
-                       if(boneIndex != null) {\r
-                               Pointer p = (Pointer)bActionChannel.getFieldValue("ipo");\r
-                               if(!p.isNull()) {\r
-                                       Structure ipoStructure = p.fetchData(dataRepository.getInputStream()).get(0);\r
-                                       Ipo ipo = ipoHelper.createIpo(ipoStructure, dataRepository);\r
-                                       tracks.add(ipo.calculateTrack(boneIndex.intValue(), animationFrames[0], animationFrames[1], fps));\r
-                               }\r
-                       }\r
-               }\r
-               return tracks.toArray(new BoneTrack[tracks.size()]);\r
-       }\r
+    /**\r
+     * This method returns a map where the key is the object's group index that is used by a bone and the key is the\r
+     * bone index in the armature.\r
+     * @param poseStructure\r
+     *        a bPose structure of the object\r
+     * @return bone group-to-index map\r
+     * @throws BlenderFileException\r
+     *         this exception is thrown when the blender file is somehow corrupted\r
+     */\r
+    public Map<Integer, Integer> getGroupToBoneIndexMap(Structure defBaseStructure, DataRepository dataRepository) throws BlenderFileException {\r
+        Map<Integer, Integer> result = null;\r
+        if (bonesMap != null && bonesMap.size() != 0) {\r
+            result = new HashMap<Integer, Integer>();\r
+            List<Structure> deformGroups = defBaseStructure.evaluateListBase(dataRepository);//bDeformGroup\r
+            int groupIndex = 0;//TODO: consider many armatures attached to one object in the future !!!\r
+            for (Structure deformGroup : deformGroups) {\r
+                String deformGroupName = deformGroup.getFieldValue("name").toString();\r
+                Integer boneIndex = bonesMap.get(deformGroupName);\r
+                if (boneIndex != null) {\r
+                    result.put(Integer.valueOf(groupIndex), boneIndex);\r
+                }\r
+                ++groupIndex;\r
+            }\r
+        }\r
+        return result;\r
+    }\r
 \r
-       /**\r
-        * This bone returns transformation matrix of the bone that is relative to\r
-        * its armature object.\r
-        * @param boneStructure the bone's structure\r
-        * @return bone's transformation matrix in armature space\r
-        */\r
-       @SuppressWarnings("unchecked")\r
-       protected Matrix4f getArmatureMatrix(Structure boneStructure) {\r
-               DynamicArray<Number> boneMat = (DynamicArray<Number>)boneStructure.getFieldValue("arm_mat");\r
-               Matrix4f m = new Matrix4f();\r
-               for(int i = 0; i < 4; ++i) {\r
-                       for(int j = 0; j < 4; ++j) {\r
-                               m.set(i, j, boneMat.get(j, i).floatValue());\r
-                       }\r
-               }\r
-               return m;\r
-       }\r
+    /**\r
+     * This method reads the tracks of the armature object.\r
+     * @param actionStructure\r
+     * @param dataRepository\r
+     *        the data repository\r
+     * @param objectName\r
+     *        the name of animation owner\r
+     * @param animationName\r
+     *        the name of the animation\r
+     * @return a list of tracks for the armature\r
+     * @throws BlenderFileException\r
+     *         this exception is thrown when the blender file is somehow corrupted\r
+     */\r
+    public BoneTrack[] getTracks(Structure actionStructure, DataRepository dataRepository, String objectName, String animationName) throws BlenderFileException {\r
+        LOGGER.log(Level.INFO, "Getting tracks!");\r
+        IpoHelper ipoHelper = dataRepository.getHelper(IpoHelper.class);\r
+        int fps = dataRepository.getBlenderKey().getFps();\r
+        int[] animationFrames = dataRepository.getBlenderKey().getAnimationFrames(objectName, animationName);\r
+        Structure chanbase = (Structure) actionStructure.getFieldValue("chanbase");\r
+        List<Structure> actionChannels = chanbase.evaluateListBase(dataRepository);//bActionChannel\r
+        if (actionChannels != null && actionChannels.size() > 0 && (bonesMap == null || bonesMap.size() == 0)) {\r
+            throw new IllegalStateException("No bones found! Cannot proceed to calculating tracks!");\r
+        }\r
+        List<BoneTrack> tracks = new ArrayList<BoneTrack>();\r
+        for (Structure bActionChannel : actionChannels) {\r
+            String name = bActionChannel.getFieldValue("name").toString();\r
+            Integer boneIndex = bonesMap.get(name);\r
+            if (boneIndex != null) {\r
+                Pointer p = (Pointer) bActionChannel.getFieldValue("ipo");\r
+                if (!p.isNull()) {\r
+                    Structure ipoStructure = p.fetchData(dataRepository.getInputStream()).get(0);\r
+                    Ipo ipo = ipoHelper.createIpo(ipoStructure, dataRepository);\r
+                    tracks.add(ipo.calculateTrack(boneIndex.intValue(), animationFrames[0], animationFrames[1], fps));\r
+                }\r
+            }\r
+        }\r
+        return tracks.toArray(new BoneTrack[tracks.size()]);\r
+    }\r
 \r
-       /**\r
-        * This method reads the bone with its children.\r
-        * @param boneStructure\r
-        *        a structure containing the bone data\r
-        * @param parent\r
-        *        the bone parent; if null then we read the root bone\r
-        * @param dataRepository\r
-        *        the data repository\r
-        * @return the bone transformation data; contains bone chierarchy and the bone's matrices\r
-        * @throws BlenderFileException\r
-        *         this exception is thrown when the blender file is somehow corrupted\r
-        */\r
-       @SuppressWarnings("unchecked")\r
-       protected BoneTransformationData readBoneAndItsChildren(Structure boneStructure, BoneTransformationData parent, DataRepository dataRepository) throws BlenderFileException {\r
-               String name = boneStructure.getFieldValue("name").toString();\r
-               Bone bone = new Bone(name);\r
-               int bonesAmount = bonesOMAs.size();\r
-               bonesOMAs.put(bone, boneStructure.getOldMemoryAddress());\r
-               if(bonesAmount == bonesOMAs.size()) {\r
-                       throw new IllegalStateException("Two bones has the same hash value and thereforw a bone was overriden in the bones<->OMA map! Improve the hash algorithm!");\r
-               }\r
-               Matrix4f boneArmatureMatrix = this.getArmatureMatrix(boneStructure);\r
-               DynamicArray<Float> sizeArray = (DynamicArray<Float>) boneStructure.getFieldValue("size");\r
-               Vector3f size = new Vector3f(sizeArray.get(0), sizeArray.get(1), sizeArray.get(2));\r
-               BoneTransformationData boneTransformationData = new BoneTransformationData(boneArmatureMatrix, size, bone, parent);\r
-               dataRepository.addLoadedFeatures(boneStructure.getOldMemoryAddress(), name, boneStructure, bone);\r
+    /**\r
+     * This bone returns transformation matrix of the bone that is relative to\r
+     * its armature object.\r
+     * @param boneStructure the bone's structure\r
+     * @return bone's transformation matrix in armature space\r
+     */\r
+    @SuppressWarnings("unchecked")\r
+    protected Matrix4f getArmatureMatrix(Structure boneStructure) {\r
+        DynamicArray<Number> boneMat = (DynamicArray<Number>) boneStructure.getFieldValue("arm_mat");\r
+        Matrix4f m = new Matrix4f();\r
+        for (int i = 0; i < 4; ++i) {\r
+            for (int j = 0; j < 4; ++j) {\r
+                m.set(i, j, boneMat.get(j, i).floatValue());\r
+            }\r
+        }\r
+        return m;\r
+    }\r
 \r
-               Structure childbase = (Structure)boneStructure.getFieldValue("childbase");\r
-               List<Structure> children = childbase.evaluateListBase(dataRepository);//Bone\r
-               for(Structure boneChild : children) {\r
-                       this.readBoneAndItsChildren(boneChild, boneTransformationData, dataRepository);\r
-               }\r
-               return boneTransformationData;\r
-       }\r
+    /**\r
+     * This method reads the bone with its children.\r
+     * @param boneStructure\r
+     *        a structure containing the bone data\r
+     * @param parent\r
+     *        the bone parent; if null then we read the root bone\r
+     * @param dataRepository\r
+     *        the data repository\r
+     * @return the bone transformation data; contains bone chierarchy and the bone's matrices\r
+     * @throws BlenderFileException\r
+     *         this exception is thrown when the blender file is somehow corrupted\r
+     */\r
+    @SuppressWarnings("unchecked")\r
+    protected BoneTransformationData readBoneAndItsChildren(Structure boneStructure, BoneTransformationData parent, DataRepository dataRepository) throws BlenderFileException {\r
+        String name = boneStructure.getFieldValue("name").toString();\r
+        Bone bone = new Bone(name);\r
+        int bonesAmount = bonesOMAs.size();\r
+        bonesOMAs.put(bone, boneStructure.getOldMemoryAddress());\r
+        if (bonesAmount == bonesOMAs.size()) {\r
+            throw new IllegalStateException("Two bones has the same hash value and thereforw a bone was overriden in the bones<->OMA map! Improve the hash algorithm!");\r
+        }\r
+        Matrix4f boneArmatureMatrix = this.getArmatureMatrix(boneStructure);\r
+        DynamicArray<Float> sizeArray = (DynamicArray<Float>) boneStructure.getFieldValue("size");\r
+        Vector3f size = new Vector3f(sizeArray.get(0), sizeArray.get(1), sizeArray.get(2));\r
+        BoneTransformationData boneTransformationData = new BoneTransformationData(boneArmatureMatrix, size, bone, parent);\r
+        dataRepository.addLoadedFeatures(boneStructure.getOldMemoryAddress(), name, boneStructure, bone);\r
 \r
-       /**\r
-        * This method assigns transformations to the bone.\r
-        * @param btd\r
-        *        the bone data containing the bone we assign transformation to\r
-        * @param additionalRootBoneTransformation\r
-        *        additional bone transformation which indicates it's mesh parent and armature object transformations\r
-        * @param boneList\r
-        *        a list of all read bones\r
-        */\r
-       protected void assignBonesMatrices(BoneTransformationData btd, Matrix4f additionalRootBoneTransformation, List<Bone> boneList) {\r
-               LOGGER.info("[" + btd.bone.getName() + "]  additionalRootBoneTransformation =\n" + additionalRootBoneTransformation);\r
-               Matrix4f totalInverseParentMatrix = btd.parent != null ? btd.parent.totalInverseBoneParentMatrix : Matrix4f.IDENTITY;\r
-               LOGGER.info("[" + btd.bone.getName() + "]  totalInverseParentMatrix =\n" + totalInverseParentMatrix);\r
-               Matrix4f restMatrix = additionalRootBoneTransformation.mult(btd.boneArmatureMatrix);\r
-               LOGGER.info("[" + btd.bone.getName() + "]  restMatrix =\n" + restMatrix);\r
-               btd.totalInverseBoneParentMatrix = restMatrix.clone().invert();\r
-               restMatrix = totalInverseParentMatrix.mult(restMatrix);\r
-               LOGGER.info("[" + btd.bone.getName() + "]  resultMatrix =\n" + restMatrix);\r
-               btd.bone.setBindTransforms(restMatrix.toTranslationVector(), restMatrix.toRotationQuat(), btd.size);\r
-               boneList.add(btd.bone);\r
-               bonesMap.put(btd.bone.getName(), Integer.valueOf(boneList.size() - 1));\r
-               if(btd.children != null && btd.children.size() > 0) {\r
-                       for(BoneTransformationData child : btd.children) {\r
-                               this.assignBonesMatrices(child, additionalRootBoneTransformation, boneList);\r
-                               btd.bone.addChild(child.bone);\r
-                       }\r
-               }\r
-       }\r
+        Structure childbase = (Structure) boneStructure.getFieldValue("childbase");\r
+        List<Structure> children = childbase.evaluateListBase(dataRepository);//Bone\r
+        for (Structure boneChild : children) {\r
+            this.readBoneAndItsChildren(boneChild, boneTransformationData, dataRepository);\r
+        }\r
+        return boneTransformationData;\r
+    }\r
 \r
-       /**\r
-        * This method returns bone transformation data for the bone of a given name.\r
-        * @param boneName\r
-        *        the name of the bone\r
-        * @return bone's transformation data\r
-        */\r
-       public BoneTransformationData getBoneTransformationDataRoot(int index) {\r
-               return boneDataRoots.get(index);\r
-       }\r
+    /**\r
+     * This method assigns transformations to the bone.\r
+     * @param btd\r
+     *        the bone data containing the bone we assign transformation to\r
+     * @param additionalRootBoneTransformation\r
+     *        additional bone transformation which indicates it's mesh parent and armature object transformations\r
+     * @param boneList\r
+     *        a list of all read bones\r
+     */\r
+    protected void assignBonesMatrices(BoneTransformationData btd, Matrix4f additionalRootBoneTransformation, List<Bone> boneList) {\r
+        LOGGER.info("[" + btd.bone.getName() + "]  additionalRootBoneTransformation =\n" + additionalRootBoneTransformation);\r
+        Matrix4f totalInverseParentMatrix = btd.parent != null ? btd.parent.totalInverseBoneParentMatrix : Matrix4f.IDENTITY;\r
+        LOGGER.info("[" + btd.bone.getName() + "]  totalInverseParentMatrix =\n" + totalInverseParentMatrix);\r
+        Matrix4f restMatrix = additionalRootBoneTransformation.mult(btd.boneArmatureMatrix);\r
+        LOGGER.info("[" + btd.bone.getName() + "]  restMatrix =\n" + restMatrix);\r
+        btd.totalInverseBoneParentMatrix = restMatrix.clone().invert();\r
+        restMatrix = totalInverseParentMatrix.mult(restMatrix);\r
+        LOGGER.info("[" + btd.bone.getName() + "]  resultMatrix =\n" + restMatrix);\r
+        btd.bone.setBindTransforms(restMatrix.toTranslationVector(), restMatrix.toRotationQuat(), btd.size);\r
+        boneList.add(btd.bone);\r
+        bonesMap.put(btd.bone.getName(), Integer.valueOf(boneList.size() - 1));\r
+        if (btd.children != null && btd.children.size() > 0) {\r
+            for (BoneTransformationData child : btd.children) {\r
+                this.assignBonesMatrices(child, additionalRootBoneTransformation, boneList);\r
+                btd.bone.addChild(child.bone);\r
+            }\r
+        }\r
+    }\r
 \r
-       /**\r
-        * This method returns the amount of bones transformations roots.\r
-        * @return the amount of bones transformations roots\r
-        */\r
-       public int getBoneTransformationDataRootsSize() {\r
-               return boneDataRoots.size();\r
-       }\r
+    /**\r
+     * This method returns bone transformation data for the bone of a given name.\r
+     * @param boneName\r
+     *        the name of the bone\r
+     * @return bone's transformation data\r
+     */\r
+    public BoneTransformationData getBoneTransformationDataRoot(int index) {\r
+        return boneDataRoots.get(index);\r
+    }\r
 \r
-       /**\r
-        * This class holds the data needed later for bone transformation calculation and to bind parent with children.\r
-        * @author Marcin Roguski\r
-        */\r
-       private static class BoneTransformationData {\r
-               /** Inverse matrix of bone's parent bone. */\r
-               private Matrix4f                                                totalInverseBoneParentMatrix;\r
-               /** Bone's matrix in armature's space. */\r
-               private Matrix4f                                                boneArmatureMatrix;\r
-               /** Bone's size (apparently it is held outside the transformation matrix. */\r
-               private Vector3f                                                size;\r
-               /** The bone the data applies to. */\r
-               private Bone                                                    bone;\r
-               /** The parent of the above mentioned bone (not assigned yet). */\r
-               private BoneTransformationData                  parent;\r
-               /** The children of the current bone. */\r
-               private List<BoneTransformationData>    children;\r
+    /**\r
+     * This method returns the amount of bones transformations roots.\r
+     * @return the amount of bones transformations roots\r
+     */\r
+    public int getBoneTransformationDataRootsSize() {\r
+        return boneDataRoots.size();\r
+    }\r
 \r
-               /**\r
-                * Private constructor creates the object and assigns the given data.\r
-                * @param boneArmatureMatrix\r
-                *        the matrix of the current bone\r
-                * @param size\r
-                *                the bone's size\r
-                * @param bone\r
-                *        the current bone\r
-                * @param parent\r
-                *        the parent structure of the bone\r
-                */\r
-               private BoneTransformationData(Matrix4f boneArmatureMatrix, Vector3f size, Bone bone, BoneTransformationData parent) {\r
-                       this.boneArmatureMatrix = boneArmatureMatrix;\r
-                       this.size = size;\r
-                       this.bone = bone;\r
-                       this.parent = parent;\r
-                       this.children = new ArrayList<ArmatureHelper.BoneTransformationData>();\r
-                       if(this.parent != null) {\r
-                               this.parent.children.add(this);\r
-                       }\r
-               }\r
-       }\r
+    /**\r
+     * This class holds the data needed later for bone transformation calculation and to bind parent with children.\r
+     * @author Marcin Roguski\r
+     */\r
+    private static class BoneTransformationData {\r
 \r
-       /**\r
-        * This method creates the whole bones structure. Assignes transformations to bones and combines children with\r
-        * parents.\r
-        * @param armatureOMA\r
-        *        old memory address of bones' armature object\r
-        * @param additionalRootBoneTransformation\r
-        *        additional bone transformation which indicates it's mesh parent and armature object transformations\r
-        * @return\r
-        */\r
-       public Bone[] buildBonesStructure(Long armatureOMA, Matrix4f additionalRootBoneTransformation) {//TODO: uwzglÄ™dnić wiele szkieletów\r
-               List<Bone> bones = new ArrayList<Bone>(boneDataRoots.size() + 1);\r
-               bones.add(new Bone(null));\r
-               for(BoneTransformationData btd : boneDataRoots) {\r
-                       this.assignBonesMatrices(btd, additionalRootBoneTransformation, bones);\r
-               }\r
-               return bones.toArray(new Bone[bones.size()]);\r
-       }\r
-       \r
-       /**\r
-        * This method assigns an immovable bone to vertices that have no bone assigned. They have the bone index with the\r
-        * value -1.\r
-        * @param immovableBoneIndex\r
-        *        the ondex of immovable bone\r
-        * @param meshes\r
-        *        a list of meshes whose vertices will be assigned to immovable bone\r
-        */\r
-       public void assignBoneToOrphanedVertices(byte immovableBoneIndex, Mesh[] meshes) {\r
-               //bone indices are common for all the object's meshes (vertex indices specify which are to be used)\r
-               VertexBuffer boneIndices = meshes[0].getBuffer(Type.BoneIndex);//common buffer to all the meshes\r
-               ByteBuffer data = (ByteBuffer)boneIndices.getData();\r
-               for(int i = 0; i < boneIndices.getNumElements(); ++i) {\r
-                       if(data.get(i) == -1) {\r
-                               data.put(i, immovableBoneIndex);\r
-                       }\r
-               }\r
-       }\r
+        /** Inverse matrix of bone's parent bone. */\r
+        private Matrix4f totalInverseBoneParentMatrix;\r
+        /** Bone's matrix in armature's space. */\r
+        private Matrix4f boneArmatureMatrix;\r
+        /** Bone's size (apparently it is held outside the transformation matrix. */\r
+        private Vector3f size;\r
+        /** The bone the data applies to. */\r
+        private Bone bone;\r
+        /** The parent of the above mentioned bone (not assigned yet). */\r
+        private BoneTransformationData parent;\r
+        /** The children of the current bone. */\r
+        private List<BoneTransformationData> children;\r
 \r
-       @Override\r
-       public void clearState() {\r
-               bonesMap.clear();\r
-               boneDataRoots.clear();\r
-       }\r
+        /**\r
+         * Private constructor creates the object and assigns the given data.\r
+         * @param boneArmatureMatrix\r
+         *        the matrix of the current bone\r
+         * @param size\r
+         *               the bone's size\r
+         * @param bone\r
+         *        the current bone\r
+         * @param parent\r
+         *        the parent structure of the bone\r
+         */\r
+        private BoneTransformationData(Matrix4f boneArmatureMatrix, Vector3f size, Bone bone, BoneTransformationData parent) {\r
+            this.boneArmatureMatrix = boneArmatureMatrix;\r
+            this.size = size;\r
+            this.bone = bone;\r
+            this.parent = parent;\r
+            this.children = new ArrayList<ArmatureHelper.BoneTransformationData>();\r
+            if (this.parent != null) {\r
+                this.parent.children.add(this);\r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
+     * This method creates the whole bones structure. Assignes transformations to bones and combines children with\r
+     * parents.\r
+     * @param armatureOMA\r
+     *        old memory address of bones' armature object\r
+     * @param additionalRootBoneTransformation\r
+     *        additional bone transformation which indicates it's mesh parent and armature object transformations\r
+     * @return\r
+     */\r
+    public Bone[] buildBonesStructure(Long armatureOMA, Matrix4f additionalRootBoneTransformation) {//TODO: uwzglÄ™dnić wiele szkieletów\r
+        List<Bone> bones = new ArrayList<Bone>(boneDataRoots.size() + 1);\r
+        bones.add(new Bone(null));\r
+        for (BoneTransformationData btd : boneDataRoots) {\r
+            this.assignBonesMatrices(btd, additionalRootBoneTransformation, bones);\r
+        }\r
+        return bones.toArray(new Bone[bones.size()]);\r
+    }\r
+\r
+    /**\r
+     * This method assigns an immovable bone to vertices that have no bone assigned. They have the bone index with the\r
+     * value -1.\r
+     * @param immovableBoneIndex\r
+     *        the ondex of immovable bone\r
+     * @param meshes\r
+     *        a list of meshes whose vertices will be assigned to immovable bone\r
+     */\r
+    public void assignBoneToOrphanedVertices(byte immovableBoneIndex, Mesh[] meshes) {\r
+        //bone indices are common for all the object's meshes (vertex indices specify which are to be used)\r
+        VertexBuffer boneIndices = meshes[0].getBuffer(Type.BoneIndex);//common buffer to all the meshes\r
+        ByteBuffer data = (ByteBuffer) boneIndices.getData();\r
+        for (int i = 0; i < boneIndices.getNumElements(); ++i) {\r
+            if (data.get(i) == -1) {\r
+                data.put(i, immovableBoneIndex);\r
+            }\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public void clearState() {\r
+        bonesMap.clear();\r
+        boneDataRoots.clear();\r
+    }\r
 }\r
index 04b00d1..25ceb3f 100644 (file)
@@ -13,45 +13,46 @@ import com.jme3.scene.plugins.blender.utils.AbstractBlenderHelper;
  * @author Marcin Roguski\r
  */\r
 public class CameraHelper extends AbstractBlenderHelper {\r
-       private static final Logger                     LOGGER          = Logger.getLogger(CameraHelper.class.getName());\r
-       \r
-       protected static final int              DEFAULT_CAM_WIDTH                       = 100;\r
-       protected static final int              DEFAULT_CAM_HEIGHT                      = 100;\r
-       /**\r
-        * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
-        * different blender versions.\r
-        * @param blenderVersion\r
-        *        the version read from the blend file\r
-        */\r
-       public CameraHelper(String blenderVersion) {\r
-               super(blenderVersion);\r
-       }\r
 \r
-       /**\r
-        * This method reads the camera object.\r
-        * @param structure the structure containing the camera data\r
-        * @return the camera object\r
-        * @throws BlenderFileException\r
-        */\r
-       public Camera toCamera(Structure structure) throws BlenderFileException {\r
-               Camera result = new Camera(DEFAULT_CAM_WIDTH, DEFAULT_CAM_HEIGHT);\r
-               int type = ((Number)structure.getFieldValue("type")).intValue();\r
-               if(type != 0 && type != 1) {\r
-                       LOGGER.log(Level.WARNING, "Unknown camera type: " + type + ". Perspective camera is being used!");\r
-                       type = 0;\r
-               }\r
-               //type==0 - perspective; type==1 - orthographic; perspective is used as default\r
-               result.setParallelProjection(type == 1);\r
-               float angle = ((Number)structure.getFieldValue("angle")).floatValue();\r
-               float aspect = 0;\r
-               float clipsta = ((Number)structure.getFieldValue("clipsta")).floatValue();\r
-               float clipend = ((Number)structure.getFieldValue("clipend")).floatValue();\r
-               if(type == 0) {\r
-                       aspect = ((Number)structure.getFieldValue("lens")).floatValue();\r
-               } else {\r
-                       aspect = ((Number)structure.getFieldValue("ortho_scale")).floatValue();\r
-               }\r
-               result.setFrustumPerspective(angle, aspect, clipsta, clipend);\r
-               return result;\r
-       }       \r
+    private static final Logger LOGGER = Logger.getLogger(CameraHelper.class.getName());\r
+    protected static final int DEFAULT_CAM_WIDTH = 100;\r
+    protected static final int DEFAULT_CAM_HEIGHT = 100;\r
+\r
+    /**\r
+     * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
+     * different blender versions.\r
+     * @param blenderVersion\r
+     *        the version read from the blend file\r
+     */\r
+    public CameraHelper(String blenderVersion) {\r
+        super(blenderVersion);\r
+    }\r
+\r
+    /**\r
+     * This method reads the camera object.\r
+     * @param structure the structure containing the camera data\r
+     * @return the camera object\r
+     * @throws BlenderFileException\r
+     */\r
+    public Camera toCamera(Structure structure) throws BlenderFileException {\r
+        Camera result = new Camera(DEFAULT_CAM_WIDTH, DEFAULT_CAM_HEIGHT);\r
+        int type = ((Number) structure.getFieldValue("type")).intValue();\r
+        if (type != 0 && type != 1) {\r
+            LOGGER.log(Level.WARNING, "Unknown camera type: {0}. Perspective camera is being used!", type);\r
+            type = 0;\r
+        }\r
+        //type==0 - perspective; type==1 - orthographic; perspective is used as default\r
+        result.setParallelProjection(type == 1);\r
+        float angle = ((Number) structure.getFieldValue("angle")).floatValue();\r
+        float aspect = 0;\r
+        float clipsta = ((Number) structure.getFieldValue("clipsta")).floatValue();\r
+        float clipend = ((Number) structure.getFieldValue("clipend")).floatValue();\r
+        if (type == 0) {\r
+            aspect = ((Number) structure.getFieldValue("lens")).floatValue();\r
+        } else {\r
+            aspect = ((Number) structure.getFieldValue("ortho_scale")).floatValue();\r
+        }\r
+        result.setFrustumPerspective(angle, aspect, clipsta, clipend);\r
+        return result;\r
+    }\r
 }\r
index 2792b0f..6e4a547 100644 (file)
@@ -24,711 +24,732 @@ import com.jme3.scene.plugins.blender.structures.Ipo;
 import com.jme3.scene.plugins.blender.utils.AbstractBlenderHelper;\r
 import com.jme3.scene.plugins.blender.utils.DataRepository;\r
 import com.jme3.scene.plugins.blender.utils.Pointer;\r
+import java.util.logging.Level;\r
 \r
 /**\r
  * This class should be used for constraint calculations.\r
  * @author Marcin Roguski\r
  */\r
 public class ConstraintHelper extends AbstractBlenderHelper {\r
-       /**\r
-        * A table containing implementations of influence functions for constraints. It should contain functions for\r
-        * blender at least 249 and higher.\r
-        */\r
-       protected static AbstractInfluenceFunction[]    influenceFunctions;\r
-\r
-       /**\r
-        * Constraints stored for object with the given old memory address.\r
-        */\r
-       protected Map<Long, Constraint[]>                               constraints     = new HashMap<Long, Constraint[]>();\r
-\r
-       /**\r
-        * Helper constructor. It's main task is to generate the affection functions. These functions are common to all\r
-        * ConstraintHelper instances. Unfortunately this constructor might grow large. If it becomes too large - I shall\r
-        * consider refactoring. The constructor parses the given blender version and stores the result. Some\r
-        * functionalities may differ in different blender versions.\r
-        * @param blenderVersion\r
-        *        the version read from the blend file\r
-        */\r
-       public ConstraintHelper(String blenderVersion, DataRepository dataRepository) {\r
-               super(blenderVersion);\r
-               if(influenceFunctions == null) {\r
-                       //TODO: synchronization\r
-                       influenceFunctions = new AbstractInfluenceFunction[ConstraintType.getLastDefinedTypeValue() + 1];\r
-                       //ACTION constraint (TODO: to implement)\r
-                       influenceFunctions[ConstraintType.CONSTRAINT_TYPE_ACTION.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_ACTION, dataRepository) {};\r
-\r
-                       //CHILDOF constraint (TODO: to implement)\r
-                       influenceFunctions[ConstraintType.CONSTRAINT_TYPE_CHILDOF.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_CHILDOF, dataRepository) {};\r
-\r
-                       //CLAMPTO constraint\r
-                       influenceFunctions[ConstraintType.CONSTRAINT_TYPE_CLAMPTO.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_CLAMPTO, dataRepository) {\r
-                               @Override\r
-                               public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {\r
-                                       this.validateConstraintType(constraint.getData());\r
-                                       LOGGER.info(constraint.getName() + " not active! Curves not yet implemented!");//TODO: implement when curves are implemented\r
-                               }\r
-                       };\r
-\r
-                       //DISTLIMIT constraint\r
-                       influenceFunctions[ConstraintType.CONSTRAINT_TYPE_DISTLIMIT.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_DISTLIMIT, dataRepository) {\r
-                               @Override\r
-                               public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {\r
-                                       Structure constraintStructure = constraint.getData();\r
-                                       this.validateConstraintType(constraintStructure);\r
-                                       Vector3f targetLocation = this.getTargetLocation(constraint);\r
-                                       BoneTrack boneTrack = this.getBoneTrack(skeleton, boneAnimation, constraint);\r
-                                       if(boneTrack != null) {\r
-                                               //TODO: target vertex group !!!\r
-                                               float dist = ((Number)constraintStructure.getFieldValue("dist")).floatValue();\r
-                                               int mode = ((Number)constraintStructure.getFieldValue("mode")).intValue();\r
-\r
-                                               int maxFrames = boneTrack.getTimes().length;\r
-                                               Vector3f[] translations = boneTrack.getTranslations();\r
-                                               for(int frame = 0; frame < maxFrames; ++frame) {\r
-                                                       Vector3f v = translations[frame].subtract(targetLocation);\r
-                                                       float currentDistance = v.length();\r
-                                                       float influence = constraint.getIpo().calculateValue(frame);\r
-                                                       float modifier = 0.0f;\r
-                                                       switch(mode) {\r
-                                                               case LIMITDIST_INSIDE:\r
-                                                                       if(currentDistance >= dist) {\r
-                                                                               modifier = (dist - currentDistance) / currentDistance;\r
-                                                                       }\r
-                                                                       break;\r
-                                                               case LIMITDIST_ONSURFACE:\r
-                                                                       modifier = (dist - currentDistance) / currentDistance;\r
-                                                                       break;\r
-                                                               case LIMITDIST_OUTSIDE:\r
-                                                                       if(currentDistance <= dist) {\r
-                                                                               modifier = (dist - currentDistance) / currentDistance;\r
-                                                                       }\r
-                                                                       break;\r
-                                                               default:\r
-                                                                       throw new IllegalStateException("Unknown distance limit constraint mode: " + mode);\r
-                                                       }\r
-                                                       translations[frame].addLocal(v.multLocal(modifier * influence));\r
-                                               }\r
-                                               boneTrack.setKeyframes(boneTrack.getTimes(), translations, boneTrack.getRotations(), boneTrack.getScales());\r
-                                       }\r
-                               }\r
-                       };\r
-\r
-                       //FOLLOWPATH constraint\r
-                       influenceFunctions[ConstraintType.CONSTRAINT_TYPE_FOLLOWPATH.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_FOLLOWPATH, dataRepository) {\r
-                               @Override\r
-                               public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {\r
-                                       this.validateConstraintType(constraint.getData());\r
-                                       LOGGER.info(constraint.getName() + " not active! Curves not yet implemented!");//TODO: implement when curves are implemented\r
-                               }\r
-                       };\r
-\r
-                       //KINEMATIC constraint (TODO: to implement)\r
-                       influenceFunctions[ConstraintType.CONSTRAINT_TYPE_KINEMATIC.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_KINEMATIC, dataRepository) {\r
-                               @Override\r
-                               public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {\r
-                                       Structure constraintStructure = constraint.getData();\r
-                                       this.validateConstraintType(constraintStructure);\r
-                                       /*Long boneOMA = constraint.getBoneOMA();\r
-                                       //IK solver is only attached to bones\r
-                                       Bone ownerBone = (Bone)dataRepository.getLoadedFeature(boneOMA, LoadedFeatureDataType.LOADED_FEATURE);\r
-\r
-                                       //get the target point\r
-                                       Object targetObject = this.getTarget(constraint, LoadedFeatureDataType.LOADED_FEATURE);\r
-                                       Vector3f pt = null;//Point Target\r
-                                       if(targetObject instanceof Bone) {\r
-                                               pt = ((Bone)targetObject).getModelSpacePosition();\r
-                                       } else if(targetObject instanceof Node) {\r
-                                               pt = ((Node)targetObject).getWorldTranslation();\r
-                                       } else if(targetObject instanceof Skeleton) {\r
-                                               Structure armatureNodeStructure = (Structure)this.getTarget(constraint, LoadedFeatureDataType.LOADED_STRUCTURE);\r
-                                               ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);\r
-                                               Transform transform = objectHelper.getTransformation(armatureNodeStructure);\r
-                                               pt = transform.getTranslation();\r
-                                       } else {\r
-                                               throw new IllegalStateException("Unknown target object type! Should be Node, Bone or Skeleton and there is: " + targetObject.getClass().getName());\r
-                                       }\r
-                                       //preparing data\r
-                                       int maxIterations = ((Number)constraintStructure.getFieldValue("iterations")).intValue();\r
-                                       CalculationBone[] bones = this.getBonesToCalculate(ownerBone, skeleton, boneAnimation);\r
-                                       for(int i=0;i<bones.length;++i) {\r
-                                               System.out.println(Arrays.toString(bones[i].track.getTranslations()));\r
-                                               System.out.println(Arrays.toString(bones[i].track.getRotations()));\r
-                                               System.out.println("===============================");\r
-                                       }\r
-                                       Quaternion rotation = new Quaternion();\r
-                                       int maxFrames = bones[0].track.getTimes().length;//all tracks should have the same amount of frames\r
-\r
-                                       for(int frame = 0; frame < maxFrames; ++frame) {\r
-                                               float error = IK_SOLVER_ERROR;\r
-                                               int iteration = 0;\r
-                                               while(error >= IK_SOLVER_ERROR && iteration <= maxIterations) {\r
-                                                       //rotating the bones\r
-                                                       for(int i = 0; i < bones.length - 1; ++i) {\r
-                                                               Vector3f pe = bones[i].getEndPoint();\r
-                                                               Vector3f pc = bones[i + 1].getWorldTranslation().clone();\r
-\r
-                                                               Vector3f peSUBpc = pe.subtract(pc).normalizeLocal();\r
-                                                               Vector3f ptSUBpc = pt.subtract(pc).normalizeLocal();\r
-\r
-                                                               float theta = FastMath.acos(peSUBpc.dot(ptSUBpc));\r
-                                                               Vector3f direction = peSUBpc.cross(ptSUBpc).normalizeLocal();\r
-                                                               bones[i].rotate(rotation.fromAngleAxis(theta, direction), frame);\r
-                                                       }\r
-                                                       error = pt.subtract(bones[0].getEndPoint()).length();\r
-                                                       ++iteration;\r
-                                               }\r
-                                               System.out.println("error = " + error + "   iterations = " + iteration);\r
-                                       }\r
-                                       \r
-                                       for(CalculationBone bone : bones) {\r
-                                               bone.applyCalculatedTracks();\r
-                                       }\r
-                                       \r
-                                       System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");\r
-                                       for(int i=0;i<bones.length;++i) {\r
-                                               System.out.println(Arrays.toString(bones[i].track.getTranslations()));\r
-                                               System.out.println(Arrays.toString(bones[i].track.getRotations()));\r
-                                               System.out.println("===============================");\r
-                                       }*/\r
-                               }\r
-\r
-                               /**\r
-                                * This method returns bones used for rotation calculations.\r
-                                * @param bone\r
-                                *        the bone to which the constraint is applied\r
-                                * @param skeleton\r
-                                *        the skeleton owning the bone and its ancestors\r
-                                * @param boneAnimation\r
-                                *        the bone animation data that stores the traces for the skeleton's bones\r
-                                * @return a list of bones to imitate the bone's movement during IK solving\r
-                                */\r
-                               private CalculationBone[] getBonesToCalculate(Bone bone, Skeleton skeleton, BoneAnimation boneAnimation) {\r
-                                       List<CalculationBone> bonesList = new ArrayList<CalculationBone>();\r
-                                       Bone currentBone = bone;\r
-                                       do {\r
-                                               int boneIndex = skeleton.getBoneIndex(currentBone);\r
-                                               for(int i = 0; i < boneAnimation.getTracks().length; ++i) {\r
-                                                       if(boneAnimation.getTracks()[i].getTargetBoneIndex() == boneIndex) {\r
-                                                               bonesList.add(new CalculationBone(currentBone, boneAnimation.getTracks()[i]));\r
-                                                               break;\r
-                                                       }\r
-                                               }\r
-                                               currentBone = currentBone.getParent();\r
-                                       } while(currentBone != null);\r
-                                       //attaching children\r
-                                       CalculationBone[] result = bonesList.toArray(new CalculationBone[bonesList.size()]);\r
-                                       for(int i = result.length - 1; i > 0; --i) {\r
-                                               result[i].attachChild(result[i - 1]);\r
-                                       }\r
-                                       return result;\r
-                               }\r
-                       };\r
-\r
-                       //LOCKTRACK constraint (TODO: to implement)\r
-                       influenceFunctions[ConstraintType.CONSTRAINT_TYPE_LOCKTRACK.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_LOCKTRACK, dataRepository) {};\r
-\r
-                       //LOCLIKE constraint\r
-                       influenceFunctions[ConstraintType.CONSTRAINT_TYPE_LOCLIKE.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_LOCLIKE, dataRepository) {\r
-                               @Override\r
-                               public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {\r
-                                       Structure constraintData = constraint.getData();\r
-                                       this.validateConstraintType(constraintData);\r
-                                       BoneTrack boneTrack = this.getBoneTrack(skeleton, boneAnimation, constraint);\r
-                                       if(boneTrack != null) {\r
-                                               Vector3f targetLocation = this.getTargetLocation(constraint);\r
-                                               int flag = ((Number)constraintData.getFieldValue("flag")).intValue();\r
-                                               Vector3f[] translations = boneTrack.getTranslations();\r
-                                               int maxFrames = translations.length;\r
-                                               for(int frame = 0; frame < maxFrames; ++frame) {\r
-                                                       Vector3f offset = Vector3f.ZERO;\r
-                                                       if((flag & LOCLIKE_OFFSET) != 0) {//we add the original location to the copied location\r
-                                                               offset = translations[frame].clone();\r
-                                                       }\r
-\r
-                                                       if((flag & LOCLIKE_X) != 0) {\r
-                                                               translations[frame].x = targetLocation.x;\r
-                                                               if((flag & LOCLIKE_X_INVERT) != 0) {\r
-                                                                       translations[frame].x = -translations[frame].x;\r
-                                                               }\r
-                                                       } else if((flag & LOCLIKE_Y) != 0) {\r
-                                                               translations[frame].y = targetLocation.y;\r
-                                                               if((flag & LOCLIKE_Y_INVERT) != 0) {\r
-                                                                       translations[frame].y = -translations[frame].y;\r
-                                                               }\r
-                                                       } else if((flag & LOCLIKE_Z) != 0) {\r
-                                                               translations[frame].z = targetLocation.z;\r
-                                                               if((flag & LOCLIKE_Z_INVERT) != 0) {\r
-                                                                       translations[frame].z = -translations[frame].z;\r
-                                                               }\r
-                                                       }\r
-                                                       translations[frame].addLocal(offset);//TODO: ipo influence\r
-                                               }\r
-                                               boneTrack.setKeyframes(boneTrack.getTimes(), translations, boneTrack.getRotations(), boneTrack.getScales());\r
-                                       }\r
-                               }\r
-                       };\r
-\r
-                       //LOCLIMIT constraint\r
-                       influenceFunctions[ConstraintType.CONSTRAINT_TYPE_LOCLIMIT.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_LOCLIMIT, dataRepository) {\r
-                               @Override\r
-                               public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {\r
-                                       Structure constraintStructure = constraint.getData();\r
-                                       this.validateConstraintType(constraintStructure);\r
-                                       BoneTrack boneTrack = this.getBoneTrack(skeleton, boneAnimation, constraint);\r
-                                       if(boneTrack != null) {\r
-                                               int flag = ((Number)constraintStructure.getFieldValue("flag")).intValue();\r
-                                               Vector3f[] translations = boneTrack.getTranslations();\r
-                                               int maxFrames = translations.length;\r
-                                               for(int frame = 0; frame < maxFrames; ++frame) {\r
-                                                       float influence = constraint.getIpo().calculateValue(frame);\r
-                                                       if((flag & LIMIT_XMIN) != 0) {\r
-                                                               float xmin = ((Number)constraintStructure.getFieldValue("xmin")).floatValue();\r
-                                                               if(translations[frame].x < xmin) {\r
-                                                                       translations[frame].x -= (translations[frame].x - xmin) * influence;\r
-                                                               }\r
-                                                       }\r
-                                                       if((flag & LIMIT_XMAX) != 0) {\r
-                                                               float xmax = ((Number)constraintStructure.getFieldValue("xmax")).floatValue();\r
-                                                               if(translations[frame].x > xmax) {\r
-                                                                       translations[frame].x -= (translations[frame].x - xmax) * influence;\r
-                                                               }\r
-                                                       }\r
-                                                       if((flag & LIMIT_YMIN) != 0) {\r
-                                                               float ymin = ((Number)constraintStructure.getFieldValue("ymin")).floatValue();\r
-                                                               if(translations[frame].y < ymin) {\r
-                                                                       translations[frame].y -= (translations[frame].y - ymin) * influence;\r
-                                                               }\r
-                                                       }\r
-                                                       if((flag & LIMIT_YMAX) != 0) {\r
-                                                               float ymax = ((Number)constraintStructure.getFieldValue("ymax")).floatValue();\r
-                                                               if(translations[frame].y > ymax) {\r
-                                                                       translations[frame].y -= (translations[frame].y - ymax) * influence;\r
-                                                               }\r
-                                                       }\r
-                                                       if((flag & LIMIT_ZMIN) != 0) {\r
-                                                               float zmin = ((Number)constraintStructure.getFieldValue("zmin")).floatValue();\r
-                                                               if(translations[frame].z < zmin) {\r
-                                                                       translations[frame].z -= (translations[frame].z - zmin) * influence;\r
-                                                               }\r
-                                                       }\r
-                                                       if((flag & LIMIT_ZMAX) != 0) {\r
-                                                               float zmax = ((Number)constraintStructure.getFieldValue("zmax")).floatValue();\r
-                                                               if(translations[frame].z > zmax) {\r
-                                                                       translations[frame].z -= (translations[frame].z - zmax) * influence;\r
-                                                               }\r
-                                                       }//TODO: consider constraint space !!!\r
-                                               }\r
-                                               boneTrack.setKeyframes(boneTrack.getTimes(), translations, boneTrack.getRotations(), boneTrack.getScales());\r
-                                       }\r
-                               }\r
-                       };\r
-\r
-                       //MINMAX constraint (TODO: to implement)\r
-                       influenceFunctions[ConstraintType.CONSTRAINT_TYPE_MINMAX.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_MINMAX, dataRepository) {};\r
-\r
-                       //NULL constraint - does nothing\r
-                       influenceFunctions[ConstraintType.CONSTRAINT_TYPE_NULL.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_NULL, dataRepository) {};\r
-\r
-                       //PYTHON constraint (TODO: to implement)\r
-                       influenceFunctions[ConstraintType.CONSTRAINT_TYPE_PYTHON.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_PYTHON, dataRepository) {};\r
-\r
-                       //RIGIDBODYJOINT constraint (TODO: to implement)\r
-                       influenceFunctions[ConstraintType.CONSTRAINT_TYPE_RIGIDBODYJOINT.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_RIGIDBODYJOINT, dataRepository) {};\r
-\r
-                       //ROTLIKE constraint\r
-                       influenceFunctions[ConstraintType.CONSTRAINT_TYPE_ROTLIKE.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_ROTLIKE, dataRepository) {\r
-                               @Override\r
-                               public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {\r
-                                       Structure constraintData = constraint.getData();\r
-                                       this.validateConstraintType(constraintData);\r
-                                       BoneTrack boneTrack = this.getBoneTrack(skeleton, boneAnimation, constraint);\r
-                                       if(boneTrack != null) {\r
-                                               Quaternion targetRotation = this.getTargetRotation(constraint);\r
-                                               int flag = ((Number)constraintData.getFieldValue("flag")).intValue();\r
-                                               float[] targetAngles = targetRotation.toAngles(null);\r
-                                               Quaternion[] rotations = boneTrack.getRotations();\r
-                                               int maxFrames = rotations.length;\r
-                                               for(int frame = 0; frame < maxFrames; ++frame) {\r
-                                                       float[] angles = rotations[frame].toAngles(null);\r
-\r
-                                                       Quaternion offset = Quaternion.IDENTITY;\r
-                                                       if((flag & ROTLIKE_OFFSET) != 0) {//we add the original rotation to the copied rotation\r
-                                                               offset = rotations[frame].clone();\r
-                                                       }\r
-\r
-                                                       if((flag & ROTLIKE_X) != 0) {\r
-                                                               angles[0] = targetAngles[0];\r
-                                                               if((flag & ROTLIKE_X_INVERT) != 0) {\r
-                                                                       angles[0] = -angles[0];\r
-                                                               }\r
-                                                       } else if((flag & ROTLIKE_Y) != 0) {\r
-                                                               angles[1] = targetAngles[1];\r
-                                                               if((flag & ROTLIKE_Y_INVERT) != 0) {\r
-                                                                       angles[1] = -angles[1];\r
-                                                               }\r
-                                                       } else if((flag & ROTLIKE_Z) != 0) {\r
-                                                               angles[2] = targetAngles[2];\r
-                                                               if((flag & ROTLIKE_Z_INVERT) != 0) {\r
-                                                                       angles[2] = -angles[2];\r
-                                                               }\r
-                                                       }\r
-                                                       rotations[frame].fromAngles(angles).multLocal(offset);//TODO: ipo influence\r
-                                               }\r
-                                               boneTrack.setKeyframes(boneTrack.getTimes(), boneTrack.getTranslations(), rotations, boneTrack.getScales());\r
-                                       }\r
-                               }\r
-                       };\r
-\r
-                       //ROTLIMIT constraint\r
-                       influenceFunctions[ConstraintType.CONSTRAINT_TYPE_ROTLIMIT.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_ROTLIMIT, dataRepository) {\r
-                               @Override\r
-                               public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {\r
-                                       Structure constraintStructure = constraint.getData();\r
-                                       this.validateConstraintType(constraintStructure);\r
-                                       BoneTrack boneTrack = this.getBoneTrack(skeleton, boneAnimation, constraint);\r
-                                       if(boneTrack != null) {\r
-                                               int flag = ((Number)constraintStructure.getFieldValue("flag")).intValue();\r
-                                               Quaternion[] rotations = boneTrack.getRotations();\r
-                                               int maxFrames = rotations.length;\r
-                                               for(int frame = 0; frame < maxFrames; ++frame) {\r
-                                                       float[] angles = rotations[frame].toAngles(null);\r
-                                                       float influence = constraint.getIpo().calculateValue(frame);\r
-                                                       if((flag & LIMIT_XROT) != 0) {\r
-                                                               float xmin = ((Number)constraintStructure.getFieldValue("xmin")).floatValue() * FastMath.DEG_TO_RAD;\r
-                                                               float xmax = ((Number)constraintStructure.getFieldValue("xmax")).floatValue() * FastMath.DEG_TO_RAD;\r
-                                                               float difference = 0.0f;\r
-                                                               if(angles[0] < xmin) {\r
-                                                                       difference = (angles[0] - xmin) * influence;\r
-                                                               } else if(angles[0] > xmax) {\r
-                                                                       difference = (angles[0] - xmax) * influence;\r
-                                                               }\r
-                                                               angles[0] -= difference;\r
-                                                       }\r
-                                                       if((flag & LIMIT_YROT) != 0) {\r
-                                                               float ymin = ((Number)constraintStructure.getFieldValue("ymin")).floatValue() * FastMath.DEG_TO_RAD;\r
-                                                               float ymax = ((Number)constraintStructure.getFieldValue("ymax")).floatValue() * FastMath.DEG_TO_RAD;\r
-                                                               float difference = 0.0f;\r
-                                                               if(angles[1] < ymin) {\r
-                                                                       difference = (angles[1] - ymin) * influence;\r
-                                                               } else if(angles[1] > ymax) {\r
-                                                                       difference = (angles[1] - ymax) * influence;\r
-                                                               }\r
-                                                               angles[1] -= difference;\r
-                                                       }\r
-                                                       if((flag & LIMIT_ZROT) != 0) {\r
-                                                               float zmin = ((Number)constraintStructure.getFieldValue("zmin")).floatValue() * FastMath.DEG_TO_RAD;\r
-                                                               float zmax = ((Number)constraintStructure.getFieldValue("zmax")).floatValue() * FastMath.DEG_TO_RAD;\r
-                                                               float difference = 0.0f;\r
-                                                               if(angles[2] < zmin) {\r
-                                                                       difference = (angles[2] - zmin) * influence;\r
-                                                               } else if(angles[2] > zmax) {\r
-                                                                       difference = (angles[2] - zmax) * influence;\r
-                                                               }\r
-                                                               angles[2] -= difference;\r
-                                                       }\r
-                                                       rotations[frame].fromAngles(angles);//TODO: consider constraint space !!!\r
-                                               }\r
-                                               boneTrack.setKeyframes(boneTrack.getTimes(), boneTrack.getTranslations(), rotations, boneTrack.getScales());\r
-                                       }\r
-                               }\r
-                       };\r
-\r
-                       //SHRINKWRAP constraint (TODO: to implement)\r
-                       influenceFunctions[ConstraintType.CONSTRAINT_TYPE_SHRINKWRAP.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_SHRINKWRAP, dataRepository) {};\r
-\r
-                       //SIZELIKE constraint\r
-                       influenceFunctions[ConstraintType.CONSTRAINT_TYPE_SIZELIKE.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_SIZELIKE, dataRepository) {\r
-                               @Override\r
-                               public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {\r
-                                       Structure constraintData = constraint.getData();\r
-                                       this.validateConstraintType(constraintData);\r
-                                       Vector3f targetScale = this.getTargetLocation(constraint);\r
-                                       BoneTrack boneTrack = this.getBoneTrack(skeleton, boneAnimation, constraint);\r
-                                       if(boneTrack != null) {\r
-                                               int flag = ((Number)constraintData.getFieldValue("flag")).intValue();\r
-                                               Vector3f[] scales = boneTrack.getScales();\r
-                                               int maxFrames = scales.length;\r
-                                               for(int frame = 0; frame < maxFrames; ++frame) {\r
-                                                       Vector3f offset = Vector3f.ZERO;\r
-                                                       if((flag & LOCLIKE_OFFSET) != 0) {//we add the original scale to the copied scale\r
-                                                               offset = scales[frame].clone();\r
-                                                       }\r
-\r
-                                                       if((flag & SIZELIKE_X) != 0) {\r
-                                                               scales[frame].x = targetScale.x;\r
-                                                       } else if((flag & SIZELIKE_Y) != 0) {\r
-                                                               scales[frame].y = targetScale.y;\r
-                                                       } else if((flag & SIZELIKE_Z) != 0) {\r
-                                                               scales[frame].z = targetScale.z;\r
-                                                       }\r
-                                                       scales[frame].addLocal(offset);//TODO: ipo influence\r
-                                                       //TODO: add or multiply???\r
-                                               }\r
-                                               boneTrack.setKeyframes(boneTrack.getTimes(), boneTrack.getTranslations(), boneTrack.getRotations(), scales);\r
-                                       }\r
-                               }\r
-                       };\r
-\r
-                       //SIZELIMIT constraint\r
-                       influenceFunctions[ConstraintType.CONSTRAINT_TYPE_SIZELIMIT.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_SIZELIMIT, dataRepository) {\r
-                               @Override\r
-                               public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {\r
-                                       Structure constraintStructure = constraint.getData();\r
-                                       this.validateConstraintType(constraintStructure);\r
-                                       BoneTrack boneTrack = this.getBoneTrack(skeleton, boneAnimation, constraint);\r
-                                       if(boneTrack != null) {\r
-                                               int flag = ((Number)constraintStructure.getFieldValue("flag")).intValue();\r
-                                               Vector3f[] scales = boneTrack.getScales();\r
-                                               int maxFrames = scales.length;\r
-                                               for(int frame = 0; frame < maxFrames; ++frame) {\r
-                                                       float influence = constraint.getIpo().calculateValue(frame);\r
-                                                       if((flag & LIMIT_XMIN) != 0) {\r
-                                                               float xmin = ((Number)constraintStructure.getFieldValue("xmin")).floatValue();\r
-                                                               if(scales[frame].x < xmin) {\r
-                                                                       scales[frame].x -= (scales[frame].x - xmin) * influence;\r
-                                                               }\r
-                                                       }\r
-                                                       if((flag & LIMIT_XMAX) != 0) {\r
-                                                               float xmax = ((Number)constraintStructure.getFieldValue("xmax")).floatValue();\r
-                                                               if(scales[frame].x > xmax) {\r
-                                                                       scales[frame].x -= (scales[frame].x - xmax) * influence;\r
-                                                               }\r
-                                                       }\r
-                                                       if((flag & LIMIT_YMIN) != 0) {\r
-                                                               float ymin = ((Number)constraintStructure.getFieldValue("ymin")).floatValue();\r
-                                                               if(scales[frame].y < ymin) {\r
-                                                                       scales[frame].y -= (scales[frame].y - ymin) * influence;\r
-                                                               }\r
-                                                       }\r
-                                                       if((flag & LIMIT_YMAX) != 0) {\r
-                                                               float ymax = ((Number)constraintStructure.getFieldValue("ymax")).floatValue();\r
-                                                               if(scales[frame].y > ymax) {\r
-                                                                       scales[frame].y -= (scales[frame].y - ymax) * influence;\r
-                                                               }\r
-                                                       }\r
-                                                       if((flag & LIMIT_ZMIN) != 0) {\r
-                                                               float zmin = ((Number)constraintStructure.getFieldValue("zmin")).floatValue();\r
-                                                               if(scales[frame].z < zmin) {\r
-                                                                       scales[frame].z -= (scales[frame].z - zmin) * influence;\r
-                                                               }\r
-                                                       }\r
-                                                       if((flag & LIMIT_ZMAX) != 0) {\r
-                                                               float zmax = ((Number)constraintStructure.getFieldValue("zmax")).floatValue();\r
-                                                               if(scales[frame].z > zmax) {\r
-                                                                       scales[frame].z -= (scales[frame].z - zmax) * influence;\r
-                                                               }\r
-                                                       }//TODO: consider constraint space !!!\r
-                                               }\r
-                                               boneTrack.setKeyframes(boneTrack.getTimes(), boneTrack.getTranslations(), boneTrack.getRotations(), scales);\r
-                                       }\r
-                               }\r
-                       };\r
-\r
-                       //STRETCHTO constraint (TODO: to implement)\r
-                       influenceFunctions[ConstraintType.CONSTRAINT_TYPE_STRETCHTO.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_STRETCHTO, dataRepository) {};\r
-\r
-                       //TRANSFORM constraint (TODO: to implement)\r
-                       influenceFunctions[ConstraintType.CONSTRAINT_TYPE_TRANSFORM.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_TRANSFORM, dataRepository) {};\r
-               }\r
-       }\r
-\r
-       /**\r
-        * This method reads constraints for for the given structure. The constraints are loaded only once for object/bone.\r
-        * @param ownerOMA\r
-        *        the owner's old memory address\r
-        * @param objectStructure\r
-        *        the structure we read constraint's for\r
-        * @param dataRepository\r
-        *        the data repository\r
-        * @throws BlenderFileException\r
-        */\r
-       public void loadConstraints(Structure objectStructure, DataRepository dataRepository) throws BlenderFileException {\r
-               // reading influence ipos for the constraints\r
-               IpoHelper ipoHelper = dataRepository.getHelper(IpoHelper.class);\r
-               Map<String, Map<String, Ipo>> constraintsIpos = new HashMap<String, Map<String, Ipo>>();\r
-               Pointer pActions = (Pointer)objectStructure.getFieldValue("action");\r
-               if(!pActions.isNull()) {\r
-                       List<Structure> actions = pActions.fetchData(dataRepository.getInputStream());\r
-                       for(Structure action : actions) {\r
-                               Structure chanbase = (Structure)action.getFieldValue("chanbase");\r
-                               List<Structure> actionChannels = chanbase.evaluateListBase(dataRepository);\r
-                               for(Structure actionChannel : actionChannels) {\r
-                                       Map<String, Ipo> ipos = new HashMap<String, Ipo>();\r
-                                       Structure constChannels = (Structure)actionChannel.getFieldValue("constraintChannels");\r
-                                       List<Structure> constraintChannels = constChannels.evaluateListBase(dataRepository);\r
-                                       for(Structure constraintChannel : constraintChannels) {\r
-                                               Pointer pIpo = (Pointer)constraintChannel.getFieldValue("ipo");\r
-                                               if(!pIpo.isNull()) {\r
-                                                       String constraintName = constraintChannel.getFieldValue("name").toString();\r
-                                                       Ipo ipo = ipoHelper.createIpo(pIpo.fetchData(dataRepository.getInputStream()).get(0), dataRepository);\r
-                                                       ipos.put(constraintName, ipo);\r
-                                               }\r
-                                       }\r
-                                       String actionName = actionChannel.getFieldValue("name").toString();\r
-                                       constraintsIpos.put(actionName, ipos);\r
-                               }\r
-                       }\r
-               }\r
-\r
-               //loading constraints connected with the object's bones\r
-               List<Constraint> constraintsList = new ArrayList<Constraint>();\r
-               Pointer pPose = (Pointer)objectStructure.getFieldValue("pose");//TODO: what if the object has two armatures ????\r
-               if(!pPose.isNull()) {\r
-                       //getting pose channels\r
-                       List<Structure> poseChannels = ((Structure)pPose.fetchData(dataRepository.getInputStream()).get(0).getFieldValue("chanbase")).evaluateListBase(dataRepository);\r
-                       for(Structure poseChannel : poseChannels) {\r
-                               Long boneOMA = Long.valueOf(((Pointer)poseChannel.getFieldValue("bone")).getOldMemoryAddress());\r
-                               //the name is read directly from structure because bone might not yet be loaded\r
-                               String name = dataRepository.getFileBlock(boneOMA).getStructure(dataRepository).getFieldValue("name").toString();\r
-                               List<Structure> constraints = ((Structure)poseChannel.getFieldValue("constraints")).evaluateListBase(dataRepository);\r
-                               for(Structure constraint : constraints) {\r
-                                       int type = ((Number)constraint.getFieldValue("type")).intValue();\r
-                                       String constraintName = constraint.getFieldValue("name").toString();\r
-                                       Ipo ipo = constraintsIpos.get(name).get(constraintName);\r
-                                       if(ipo == null) {\r
-                                               float enforce = ((Number)constraint.getFieldValue("enforce")).floatValue();\r
-                                               ipo = ipoHelper.createIpo(enforce);\r
-                                       }\r
-                                       Space ownerSpace = Space.valueOf(((Number)constraint.getFieldValue("ownspace")).byteValue());\r
-                                       Space targetSpace = Space.valueOf(((Number)constraint.getFieldValue("tarspace")).byteValue());\r
-                                       Constraint c = new Constraint(constraint, influenceFunctions[type], boneOMA, ownerSpace, targetSpace, ipo, dataRepository);\r
-                                       constraintsList.add(c);\r
-                               }\r
-                       }\r
-               }\r
-               /* TODO: reading constraints for objects (implement when object's animation will be available)\r
-               List<Structure> constraintChannels = ((Structure)objectStructure.getFieldValue("constraintChannels")).evaluateListBase(dataRepository);\r
-               for(Structure constraintChannel : constraintChannels) {\r
-                       System.out.println(constraintChannel);\r
-               }\r
-\r
-               //loading constraints connected with the object itself (TODO: test this)\r
-               if(!this.constraints.containsKey(objectStructure.getOldMemoryAddress())) {\r
-                       List<Structure> constraints = ((Structure)objectStructure.getFieldValue("constraints")).evaluateListBase(dataRepository);\r
-                       Constraint[] result = new Constraint[constraints.size()];\r
-                       int i = 0;\r
-                       for(Structure constraint : constraints) {\r
-                               int type = ((Number)constraint.getFieldValue("type")).intValue();\r
-                               String name = constraint.getFieldValue("name").toString();\r
-                               result[i++] = new Constraint(constraint, influenceFunctions[type], null, dataRepository);//TODO: influence ipos for object animation\r
-                       }\r
-                       this.constraints.put(objectStructure.getOldMemoryAddress(), result);\r
-               }\r
-               */\r
-               if(constraintsList.size() > 0) {\r
-                       this.constraints.put(objectStructure.getOldMemoryAddress(), constraintsList.toArray(new Constraint[constraintsList.size()]));\r
-               }\r
-       }\r
-\r
-       /**\r
-        * This method returns a list of constraints of the feature's constraints. The order of constraints is important.\r
-        * @param ownerOMA\r
-        *        the owner's old memory address\r
-        * @return a table of constraints for the feature specified by old memory address\r
-        */\r
-       public Constraint[] getConstraints(Long ownerOMA) {\r
-               return constraints.get(ownerOMA);\r
-       }\r
-\r
-       @Override\r
-       public void clearState() {\r
-               constraints.clear();\r
-       }\r
-\r
-       /**\r
-        * The purpose of this class is to imitate bone's movement when calculating inverse kinematics.\r
-        * @author Marcin Roguski\r
-        */\r
-       private static class CalculationBone extends Node {\r
-               /** The name of the bone. Only to be used in toString method. */\r
-               private String          boneName;\r
-               /** The bone's tracks. Will be altered at the end of calculation process. */\r
-               private BoneTrack       track;\r
-               /** The starting position of the bone. */\r
-               private Vector3f        startTranslation;\r
-               /** The starting rotation of the bone. */\r
-               private Quaternion      startRotation;\r
-               /** The starting scale of the bone. */\r
-               private Vector3f        startScale;\r
-               \r
-               private Vector3f[] translations;\r
-               private Quaternion[] rotations;\r
-               private Vector3f[] scales;\r
-\r
-               /**\r
-                * Constructor. Stores the track, starting transformation and sets the transformation to the starting positions.\r
-                * @param bone\r
-                *        the bone this class will imitate\r
-                * @param track\r
-                *        the bone's tracks\r
-                */\r
-               public CalculationBone(Bone bone, BoneTrack track) {\r
-                       this.boneName = bone.getName();\r
-                       this.track = track;\r
-                       this.startRotation = bone.getModelSpaceRotation().clone();\r
-                       this.startTranslation = bone.getModelSpacePosition().clone();\r
-                       this.startScale = bone.getModelSpaceScale().clone();\r
-                       this.translations = track.getTranslations();\r
-                       this.rotations = track.getRotations();\r
-                       this.scales = track.getScales();\r
-                       this.reset();\r
-               }\r
-\r
-               /**\r
-                * This method returns the end point of the bone. If the bone has parent it is calculated from the start point\r
-                * of parent to the start point of this bone. If the bone doesn't have a parent the end location is considered\r
-                * to be 1 point up along Y axis (scale is applied if set to != 1.0);\r
-                * @return the end point of this bone\r
-                */\r
-               //TODO: set to Z axis if user defined it this way\r
-               public Vector3f getEndPoint() {\r
-                       if(this.getParent() == null) {\r
-                               return new Vector3f(0, this.getLocalScale().y, 0);\r
-                       } else {\r
-                               Node parent = this.getParent();\r
-                               return parent.getWorldTranslation().subtract(this.getWorldTranslation()).multLocal(this.getWorldScale());\r
-                       }\r
-               }\r
-\r
-               /**\r
-                * This method resets the calculation bone to the starting position.\r
-                */\r
-               public void reset() {\r
-                       this.setLocalTranslation(startTranslation);\r
-                       this.setLocalRotation(startRotation);\r
-                       this.setLocalScale(startScale);\r
-               }\r
-\r
-               @Override\r
-               public int attachChild(Spatial child) {\r
-                       if(this.getChildren() != null && this.getChildren().size() > 1) {\r
-                               throw new IllegalStateException(this.getClass().getName() + " class instance can only have one child!");\r
-                       }\r
-                       return super.attachChild(child);\r
-               }\r
-               \r
-               public Spatial rotate(Quaternion rot, int frame) {\r
-                       Spatial spatial = super.rotate(rot);\r
-                       this.updateWorldTransforms();\r
-                       if(this.getChildren()!=null && this.getChildren().size()>0) {\r
-                               CalculationBone child = (CalculationBone)this.getChild(0);\r
-                               child.updateWorldTransforms();\r
-                       }\r
-                       rotations[frame].set(this.getLocalRotation());\r
-                       translations[frame].set(this.getLocalTranslation());\r
-                       if(scales!=null) {\r
-                               scales[frame].set(this.getLocalScale());\r
-                       }\r
-                       return spatial;\r
-               }\r
-               \r
-               public void applyCalculatedTracks() {\r
-                       track.setKeyframes(track.getTimes(), translations, rotations);//TODO:scales\r
-               }\r
-               \r
-               @Override\r
-               public String toString() {\r
-                       return boneName+ ": " + this.getLocalRotation() + " " + this.getLocalTranslation();\r
-               }\r
-       }\r
+\r
+    /**\r
+     * A table containing implementations of influence functions for constraints. It should contain functions for\r
+     * blender at least 249 and higher.\r
+     */\r
+    protected static AbstractInfluenceFunction[] influenceFunctions;\r
+    /**\r
+     * Constraints stored for object with the given old memory address.\r
+     */\r
+    protected Map<Long, Constraint[]> constraints = new HashMap<Long, Constraint[]>();\r
+\r
+    /**\r
+     * Helper constructor. It's main task is to generate the affection functions. These functions are common to all\r
+     * ConstraintHelper instances. Unfortunately this constructor might grow large. If it becomes too large - I shall\r
+     * consider refactoring. The constructor parses the given blender version and stores the result. Some\r
+     * functionalities may differ in different blender versions.\r
+     * @param blenderVersion\r
+     *        the version read from the blend file\r
+     */\r
+    public ConstraintHelper(String blenderVersion, DataRepository dataRepository) {\r
+        super(blenderVersion);\r
+        if (influenceFunctions == null) {\r
+            //TODO: synchronization\r
+            influenceFunctions = new AbstractInfluenceFunction[ConstraintType.getLastDefinedTypeValue() + 1];\r
+            //ACTION constraint (TODO: to implement)\r
+            influenceFunctions[ConstraintType.CONSTRAINT_TYPE_ACTION.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_ACTION, dataRepository) {\r
+            };\r
+\r
+            //CHILDOF constraint (TODO: to implement)\r
+            influenceFunctions[ConstraintType.CONSTRAINT_TYPE_CHILDOF.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_CHILDOF, dataRepository) {\r
+            };\r
+\r
+            //CLAMPTO constraint\r
+            influenceFunctions[ConstraintType.CONSTRAINT_TYPE_CLAMPTO.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_CLAMPTO, dataRepository) {\r
+\r
+                @Override\r
+                public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {\r
+                    this.validateConstraintType(constraint.getData());\r
+                    LOGGER.log(Level.INFO, "{0} not active! Curves not yet implemented!", constraint.getName());//TODO: implement when curves are implemented\r
+                }\r
+            };\r
+\r
+            //DISTLIMIT constraint\r
+            influenceFunctions[ConstraintType.CONSTRAINT_TYPE_DISTLIMIT.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_DISTLIMIT, dataRepository) {\r
+\r
+                @Override\r
+                public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {\r
+                    Structure constraintStructure = constraint.getData();\r
+                    this.validateConstraintType(constraintStructure);\r
+                    Vector3f targetLocation = this.getTargetLocation(constraint);\r
+                    BoneTrack boneTrack = this.getBoneTrack(skeleton, boneAnimation, constraint);\r
+                    if (boneTrack != null) {\r
+                        //TODO: target vertex group !!!\r
+                        float dist = ((Number) constraintStructure.getFieldValue("dist")).floatValue();\r
+                        int mode = ((Number) constraintStructure.getFieldValue("mode")).intValue();\r
+\r
+                        int maxFrames = boneTrack.getTimes().length;\r
+                        Vector3f[] translations = boneTrack.getTranslations();\r
+                        for (int frame = 0; frame < maxFrames; ++frame) {\r
+                            Vector3f v = translations[frame].subtract(targetLocation);\r
+                            float currentDistance = v.length();\r
+                            float influence = constraint.getIpo().calculateValue(frame);\r
+                            float modifier = 0.0f;\r
+                            switch (mode) {\r
+                                case LIMITDIST_INSIDE:\r
+                                    if (currentDistance >= dist) {\r
+                                        modifier = (dist - currentDistance) / currentDistance;\r
+                                    }\r
+                                    break;\r
+                                case LIMITDIST_ONSURFACE:\r
+                                    modifier = (dist - currentDistance) / currentDistance;\r
+                                    break;\r
+                                case LIMITDIST_OUTSIDE:\r
+                                    if (currentDistance <= dist) {\r
+                                        modifier = (dist - currentDistance) / currentDistance;\r
+                                    }\r
+                                    break;\r
+                                default:\r
+                                    throw new IllegalStateException("Unknown distance limit constraint mode: " + mode);\r
+                            }\r
+                            translations[frame].addLocal(v.multLocal(modifier * influence));\r
+                        }\r
+                        boneTrack.setKeyframes(boneTrack.getTimes(), translations, boneTrack.getRotations(), boneTrack.getScales());\r
+                    }\r
+                }\r
+            };\r
+\r
+            //FOLLOWPATH constraint\r
+            influenceFunctions[ConstraintType.CONSTRAINT_TYPE_FOLLOWPATH.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_FOLLOWPATH, dataRepository) {\r
+\r
+                @Override\r
+                public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {\r
+                    this.validateConstraintType(constraint.getData());\r
+                    LOGGER.log(Level.INFO, "{0} not active! Curves not yet implemented!", constraint.getName());//TODO: implement when curves are implemented\r
+                }\r
+            };\r
+\r
+            //KINEMATIC constraint (TODO: to implement)\r
+            influenceFunctions[ConstraintType.CONSTRAINT_TYPE_KINEMATIC.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_KINEMATIC, dataRepository) {\r
+\r
+                @Override\r
+                public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {\r
+                    Structure constraintStructure = constraint.getData();\r
+                    this.validateConstraintType(constraintStructure);\r
+                    /*Long boneOMA = constraint.getBoneOMA();\r
+                    //IK solver is only attached to bones\r
+                    Bone ownerBone = (Bone)dataRepository.getLoadedFeature(boneOMA, LoadedFeatureDataType.LOADED_FEATURE);\r
+                    \r
+                    //get the target point\r
+                    Object targetObject = this.getTarget(constraint, LoadedFeatureDataType.LOADED_FEATURE);\r
+                    Vector3f pt = null;//Point Target\r
+                    if(targetObject instanceof Bone) {\r
+                    pt = ((Bone)targetObject).getModelSpacePosition();\r
+                    } else if(targetObject instanceof Node) {\r
+                    pt = ((Node)targetObject).getWorldTranslation();\r
+                    } else if(targetObject instanceof Skeleton) {\r
+                    Structure armatureNodeStructure = (Structure)this.getTarget(constraint, LoadedFeatureDataType.LOADED_STRUCTURE);\r
+                    ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);\r
+                    Transform transform = objectHelper.getTransformation(armatureNodeStructure);\r
+                    pt = transform.getTranslation();\r
+                    } else {\r
+                    throw new IllegalStateException("Unknown target object type! Should be Node, Bone or Skeleton and there is: " + targetObject.getClass().getName());\r
+                    }\r
+                    //preparing data\r
+                    int maxIterations = ((Number)constraintStructure.getFieldValue("iterations")).intValue();\r
+                    CalculationBone[] bones = this.getBonesToCalculate(ownerBone, skeleton, boneAnimation);\r
+                    for(int i=0;i<bones.length;++i) {\r
+                    System.out.println(Arrays.toString(bones[i].track.getTranslations()));\r
+                    System.out.println(Arrays.toString(bones[i].track.getRotations()));\r
+                    System.out.println("===============================");\r
+                    }\r
+                    Quaternion rotation = new Quaternion();\r
+                    int maxFrames = bones[0].track.getTimes().length;//all tracks should have the same amount of frames\r
+                    \r
+                    for(int frame = 0; frame < maxFrames; ++frame) {\r
+                    float error = IK_SOLVER_ERROR;\r
+                    int iteration = 0;\r
+                    while(error >= IK_SOLVER_ERROR && iteration <= maxIterations) {\r
+                    //rotating the bones\r
+                    for(int i = 0; i < bones.length - 1; ++i) {\r
+                    Vector3f pe = bones[i].getEndPoint();\r
+                    Vector3f pc = bones[i + 1].getWorldTranslation().clone();\r
+                    \r
+                    Vector3f peSUBpc = pe.subtract(pc).normalizeLocal();\r
+                    Vector3f ptSUBpc = pt.subtract(pc).normalizeLocal();\r
+                    \r
+                    float theta = FastMath.acos(peSUBpc.dot(ptSUBpc));\r
+                    Vector3f direction = peSUBpc.cross(ptSUBpc).normalizeLocal();\r
+                    bones[i].rotate(rotation.fromAngleAxis(theta, direction), frame);\r
+                    }\r
+                    error = pt.subtract(bones[0].getEndPoint()).length();\r
+                    ++iteration;\r
+                    }\r
+                    System.out.println("error = " + error + "   iterations = " + iteration);\r
+                    }\r
+                    \r
+                    for(CalculationBone bone : bones) {\r
+                    bone.applyCalculatedTracks();\r
+                    }\r
+                    \r
+                    System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");\r
+                    for(int i=0;i<bones.length;++i) {\r
+                    System.out.println(Arrays.toString(bones[i].track.getTranslations()));\r
+                    System.out.println(Arrays.toString(bones[i].track.getRotations()));\r
+                    System.out.println("===============================");\r
+                    }*/\r
+                }\r
+\r
+                /**\r
+                 * This method returns bones used for rotation calculations.\r
+                 * @param bone\r
+                 *        the bone to which the constraint is applied\r
+                 * @param skeleton\r
+                 *        the skeleton owning the bone and its ancestors\r
+                 * @param boneAnimation\r
+                 *        the bone animation data that stores the traces for the skeleton's bones\r
+                 * @return a list of bones to imitate the bone's movement during IK solving\r
+                 */\r
+                private CalculationBone[] getBonesToCalculate(Bone bone, Skeleton skeleton, BoneAnimation boneAnimation) {\r
+                    List<CalculationBone> bonesList = new ArrayList<CalculationBone>();\r
+                    Bone currentBone = bone;\r
+                    do {\r
+                        int boneIndex = skeleton.getBoneIndex(currentBone);\r
+                        for (int i = 0; i < boneAnimation.getTracks().length; ++i) {\r
+                            if (boneAnimation.getTracks()[i].getTargetBoneIndex() == boneIndex) {\r
+                                bonesList.add(new CalculationBone(currentBone, boneAnimation.getTracks()[i]));\r
+                                break;\r
+                            }\r
+                        }\r
+                        currentBone = currentBone.getParent();\r
+                    } while (currentBone != null);\r
+                    //attaching children\r
+                    CalculationBone[] result = bonesList.toArray(new CalculationBone[bonesList.size()]);\r
+                    for (int i = result.length - 1; i > 0; --i) {\r
+                        result[i].attachChild(result[i - 1]);\r
+                    }\r
+                    return result;\r
+                }\r
+            };\r
+\r
+            //LOCKTRACK constraint (TODO: to implement)\r
+            influenceFunctions[ConstraintType.CONSTRAINT_TYPE_LOCKTRACK.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_LOCKTRACK, dataRepository) {\r
+            };\r
+\r
+            //LOCLIKE constraint\r
+            influenceFunctions[ConstraintType.CONSTRAINT_TYPE_LOCLIKE.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_LOCLIKE, dataRepository) {\r
+\r
+                @Override\r
+                public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {\r
+                    Structure constraintData = constraint.getData();\r
+                    this.validateConstraintType(constraintData);\r
+                    BoneTrack boneTrack = this.getBoneTrack(skeleton, boneAnimation, constraint);\r
+                    if (boneTrack != null) {\r
+                        Vector3f targetLocation = this.getTargetLocation(constraint);\r
+                        int flag = ((Number) constraintData.getFieldValue("flag")).intValue();\r
+                        Vector3f[] translations = boneTrack.getTranslations();\r
+                        int maxFrames = translations.length;\r
+                        for (int frame = 0; frame < maxFrames; ++frame) {\r
+                            Vector3f offset = Vector3f.ZERO;\r
+                            if ((flag & LOCLIKE_OFFSET) != 0) {//we add the original location to the copied location\r
+                                offset = translations[frame].clone();\r
+                            }\r
+\r
+                            if ((flag & LOCLIKE_X) != 0) {\r
+                                translations[frame].x = targetLocation.x;\r
+                                if ((flag & LOCLIKE_X_INVERT) != 0) {\r
+                                    translations[frame].x = -translations[frame].x;\r
+                                }\r
+                            } else if ((flag & LOCLIKE_Y) != 0) {\r
+                                translations[frame].y = targetLocation.y;\r
+                                if ((flag & LOCLIKE_Y_INVERT) != 0) {\r
+                                    translations[frame].y = -translations[frame].y;\r
+                                }\r
+                            } else if ((flag & LOCLIKE_Z) != 0) {\r
+                                translations[frame].z = targetLocation.z;\r
+                                if ((flag & LOCLIKE_Z_INVERT) != 0) {\r
+                                    translations[frame].z = -translations[frame].z;\r
+                                }\r
+                            }\r
+                            translations[frame].addLocal(offset);//TODO: ipo influence\r
+                        }\r
+                        boneTrack.setKeyframes(boneTrack.getTimes(), translations, boneTrack.getRotations(), boneTrack.getScales());\r
+                    }\r
+                }\r
+            };\r
+\r
+            //LOCLIMIT constraint\r
+            influenceFunctions[ConstraintType.CONSTRAINT_TYPE_LOCLIMIT.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_LOCLIMIT, dataRepository) {\r
+\r
+                @Override\r
+                public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {\r
+                    Structure constraintStructure = constraint.getData();\r
+                    this.validateConstraintType(constraintStructure);\r
+                    BoneTrack boneTrack = this.getBoneTrack(skeleton, boneAnimation, constraint);\r
+                    if (boneTrack != null) {\r
+                        int flag = ((Number) constraintStructure.getFieldValue("flag")).intValue();\r
+                        Vector3f[] translations = boneTrack.getTranslations();\r
+                        int maxFrames = translations.length;\r
+                        for (int frame = 0; frame < maxFrames; ++frame) {\r
+                            float influence = constraint.getIpo().calculateValue(frame);\r
+                            if ((flag & LIMIT_XMIN) != 0) {\r
+                                float xmin = ((Number) constraintStructure.getFieldValue("xmin")).floatValue();\r
+                                if (translations[frame].x < xmin) {\r
+                                    translations[frame].x -= (translations[frame].x - xmin) * influence;\r
+                                }\r
+                            }\r
+                            if ((flag & LIMIT_XMAX) != 0) {\r
+                                float xmax = ((Number) constraintStructure.getFieldValue("xmax")).floatValue();\r
+                                if (translations[frame].x > xmax) {\r
+                                    translations[frame].x -= (translations[frame].x - xmax) * influence;\r
+                                }\r
+                            }\r
+                            if ((flag & LIMIT_YMIN) != 0) {\r
+                                float ymin = ((Number) constraintStructure.getFieldValue("ymin")).floatValue();\r
+                                if (translations[frame].y < ymin) {\r
+                                    translations[frame].y -= (translations[frame].y - ymin) * influence;\r
+                                }\r
+                            }\r
+                            if ((flag & LIMIT_YMAX) != 0) {\r
+                                float ymax = ((Number) constraintStructure.getFieldValue("ymax")).floatValue();\r
+                                if (translations[frame].y > ymax) {\r
+                                    translations[frame].y -= (translations[frame].y - ymax) * influence;\r
+                                }\r
+                            }\r
+                            if ((flag & LIMIT_ZMIN) != 0) {\r
+                                float zmin = ((Number) constraintStructure.getFieldValue("zmin")).floatValue();\r
+                                if (translations[frame].z < zmin) {\r
+                                    translations[frame].z -= (translations[frame].z - zmin) * influence;\r
+                                }\r
+                            }\r
+                            if ((flag & LIMIT_ZMAX) != 0) {\r
+                                float zmax = ((Number) constraintStructure.getFieldValue("zmax")).floatValue();\r
+                                if (translations[frame].z > zmax) {\r
+                                    translations[frame].z -= (translations[frame].z - zmax) * influence;\r
+                                }\r
+                            }//TODO: consider constraint space !!!\r
+                        }\r
+                        boneTrack.setKeyframes(boneTrack.getTimes(), translations, boneTrack.getRotations(), boneTrack.getScales());\r
+                    }\r
+                }\r
+            };\r
+\r
+            //MINMAX constraint (TODO: to implement)\r
+            influenceFunctions[ConstraintType.CONSTRAINT_TYPE_MINMAX.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_MINMAX, dataRepository) {\r
+            };\r
+\r
+            //NULL constraint - does nothing\r
+            influenceFunctions[ConstraintType.CONSTRAINT_TYPE_NULL.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_NULL, dataRepository) {\r
+            };\r
+\r
+            //PYTHON constraint (TODO: to implement)\r
+            influenceFunctions[ConstraintType.CONSTRAINT_TYPE_PYTHON.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_PYTHON, dataRepository) {\r
+            };\r
+\r
+            //RIGIDBODYJOINT constraint (TODO: to implement)\r
+            influenceFunctions[ConstraintType.CONSTRAINT_TYPE_RIGIDBODYJOINT.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_RIGIDBODYJOINT, dataRepository) {\r
+            };\r
+\r
+            //ROTLIKE constraint\r
+            influenceFunctions[ConstraintType.CONSTRAINT_TYPE_ROTLIKE.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_ROTLIKE, dataRepository) {\r
+\r
+                @Override\r
+                public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {\r
+                    Structure constraintData = constraint.getData();\r
+                    this.validateConstraintType(constraintData);\r
+                    BoneTrack boneTrack = this.getBoneTrack(skeleton, boneAnimation, constraint);\r
+                    if (boneTrack != null) {\r
+                        Quaternion targetRotation = this.getTargetRotation(constraint);\r
+                        int flag = ((Number) constraintData.getFieldValue("flag")).intValue();\r
+                        float[] targetAngles = targetRotation.toAngles(null);\r
+                        Quaternion[] rotations = boneTrack.getRotations();\r
+                        int maxFrames = rotations.length;\r
+                        for (int frame = 0; frame < maxFrames; ++frame) {\r
+                            float[] angles = rotations[frame].toAngles(null);\r
+\r
+                            Quaternion offset = Quaternion.IDENTITY;\r
+                            if ((flag & ROTLIKE_OFFSET) != 0) {//we add the original rotation to the copied rotation\r
+                                offset = rotations[frame].clone();\r
+                            }\r
+\r
+                            if ((flag & ROTLIKE_X) != 0) {\r
+                                angles[0] = targetAngles[0];\r
+                                if ((flag & ROTLIKE_X_INVERT) != 0) {\r
+                                    angles[0] = -angles[0];\r
+                                }\r
+                            } else if ((flag & ROTLIKE_Y) != 0) {\r
+                                angles[1] = targetAngles[1];\r
+                                if ((flag & ROTLIKE_Y_INVERT) != 0) {\r
+                                    angles[1] = -angles[1];\r
+                                }\r
+                            } else if ((flag & ROTLIKE_Z) != 0) {\r
+                                angles[2] = targetAngles[2];\r
+                                if ((flag & ROTLIKE_Z_INVERT) != 0) {\r
+                                    angles[2] = -angles[2];\r
+                                }\r
+                            }\r
+                            rotations[frame].fromAngles(angles).multLocal(offset);//TODO: ipo influence\r
+                        }\r
+                        boneTrack.setKeyframes(boneTrack.getTimes(), boneTrack.getTranslations(), rotations, boneTrack.getScales());\r
+                    }\r
+                }\r
+            };\r
+\r
+            //ROTLIMIT constraint\r
+            influenceFunctions[ConstraintType.CONSTRAINT_TYPE_ROTLIMIT.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_ROTLIMIT, dataRepository) {\r
+\r
+                @Override\r
+                public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {\r
+                    Structure constraintStructure = constraint.getData();\r
+                    this.validateConstraintType(constraintStructure);\r
+                    BoneTrack boneTrack = this.getBoneTrack(skeleton, boneAnimation, constraint);\r
+                    if (boneTrack != null) {\r
+                        int flag = ((Number) constraintStructure.getFieldValue("flag")).intValue();\r
+                        Quaternion[] rotations = boneTrack.getRotations();\r
+                        int maxFrames = rotations.length;\r
+                        for (int frame = 0; frame < maxFrames; ++frame) {\r
+                            float[] angles = rotations[frame].toAngles(null);\r
+                            float influence = constraint.getIpo().calculateValue(frame);\r
+                            if ((flag & LIMIT_XROT) != 0) {\r
+                                float xmin = ((Number) constraintStructure.getFieldValue("xmin")).floatValue() * FastMath.DEG_TO_RAD;\r
+                                float xmax = ((Number) constraintStructure.getFieldValue("xmax")).floatValue() * FastMath.DEG_TO_RAD;\r
+                                float difference = 0.0f;\r
+                                if (angles[0] < xmin) {\r
+                                    difference = (angles[0] - xmin) * influence;\r
+                                } else if (angles[0] > xmax) {\r
+                                    difference = (angles[0] - xmax) * influence;\r
+                                }\r
+                                angles[0] -= difference;\r
+                            }\r
+                            if ((flag & LIMIT_YROT) != 0) {\r
+                                float ymin = ((Number) constraintStructure.getFieldValue("ymin")).floatValue() * FastMath.DEG_TO_RAD;\r
+                                float ymax = ((Number) constraintStructure.getFieldValue("ymax")).floatValue() * FastMath.DEG_TO_RAD;\r
+                                float difference = 0.0f;\r
+                                if (angles[1] < ymin) {\r
+                                    difference = (angles[1] - ymin) * influence;\r
+                                } else if (angles[1] > ymax) {\r
+                                    difference = (angles[1] - ymax) * influence;\r
+                                }\r
+                                angles[1] -= difference;\r
+                            }\r
+                            if ((flag & LIMIT_ZROT) != 0) {\r
+                                float zmin = ((Number) constraintStructure.getFieldValue("zmin")).floatValue() * FastMath.DEG_TO_RAD;\r
+                                float zmax = ((Number) constraintStructure.getFieldValue("zmax")).floatValue() * FastMath.DEG_TO_RAD;\r
+                                float difference = 0.0f;\r
+                                if (angles[2] < zmin) {\r
+                                    difference = (angles[2] - zmin) * influence;\r
+                                } else if (angles[2] > zmax) {\r
+                                    difference = (angles[2] - zmax) * influence;\r
+                                }\r
+                                angles[2] -= difference;\r
+                            }\r
+                            rotations[frame].fromAngles(angles);//TODO: consider constraint space !!!\r
+                        }\r
+                        boneTrack.setKeyframes(boneTrack.getTimes(), boneTrack.getTranslations(), rotations, boneTrack.getScales());\r
+                    }\r
+                }\r
+            };\r
+\r
+            //SHRINKWRAP constraint (TODO: to implement)\r
+            influenceFunctions[ConstraintType.CONSTRAINT_TYPE_SHRINKWRAP.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_SHRINKWRAP, dataRepository) {\r
+            };\r
+\r
+            //SIZELIKE constraint\r
+            influenceFunctions[ConstraintType.CONSTRAINT_TYPE_SIZELIKE.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_SIZELIKE, dataRepository) {\r
+\r
+                @Override\r
+                public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {\r
+                    Structure constraintData = constraint.getData();\r
+                    this.validateConstraintType(constraintData);\r
+                    Vector3f targetScale = this.getTargetLocation(constraint);\r
+                    BoneTrack boneTrack = this.getBoneTrack(skeleton, boneAnimation, constraint);\r
+                    if (boneTrack != null) {\r
+                        int flag = ((Number) constraintData.getFieldValue("flag")).intValue();\r
+                        Vector3f[] scales = boneTrack.getScales();\r
+                        int maxFrames = scales.length;\r
+                        for (int frame = 0; frame < maxFrames; ++frame) {\r
+                            Vector3f offset = Vector3f.ZERO;\r
+                            if ((flag & LOCLIKE_OFFSET) != 0) {//we add the original scale to the copied scale\r
+                                offset = scales[frame].clone();\r
+                            }\r
+\r
+                            if ((flag & SIZELIKE_X) != 0) {\r
+                                scales[frame].x = targetScale.x;\r
+                            } else if ((flag & SIZELIKE_Y) != 0) {\r
+                                scales[frame].y = targetScale.y;\r
+                            } else if ((flag & SIZELIKE_Z) != 0) {\r
+                                scales[frame].z = targetScale.z;\r
+                            }\r
+                            scales[frame].addLocal(offset);//TODO: ipo influence\r
+                            //TODO: add or multiply???\r
+                        }\r
+                        boneTrack.setKeyframes(boneTrack.getTimes(), boneTrack.getTranslations(), boneTrack.getRotations(), scales);\r
+                    }\r
+                }\r
+            };\r
+\r
+            //SIZELIMIT constraint\r
+            influenceFunctions[ConstraintType.CONSTRAINT_TYPE_SIZELIMIT.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_SIZELIMIT, dataRepository) {\r
+\r
+                @Override\r
+                public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {\r
+                    Structure constraintStructure = constraint.getData();\r
+                    this.validateConstraintType(constraintStructure);\r
+                    BoneTrack boneTrack = this.getBoneTrack(skeleton, boneAnimation, constraint);\r
+                    if (boneTrack != null) {\r
+                        int flag = ((Number) constraintStructure.getFieldValue("flag")).intValue();\r
+                        Vector3f[] scales = boneTrack.getScales();\r
+                        int maxFrames = scales.length;\r
+                        for (int frame = 0; frame < maxFrames; ++frame) {\r
+                            float influence = constraint.getIpo().calculateValue(frame);\r
+                            if ((flag & LIMIT_XMIN) != 0) {\r
+                                float xmin = ((Number) constraintStructure.getFieldValue("xmin")).floatValue();\r
+                                if (scales[frame].x < xmin) {\r
+                                    scales[frame].x -= (scales[frame].x - xmin) * influence;\r
+                                }\r
+                            }\r
+                            if ((flag & LIMIT_XMAX) != 0) {\r
+                                float xmax = ((Number) constraintStructure.getFieldValue("xmax")).floatValue();\r
+                                if (scales[frame].x > xmax) {\r
+                                    scales[frame].x -= (scales[frame].x - xmax) * influence;\r
+                                }\r
+                            }\r
+                            if ((flag & LIMIT_YMIN) != 0) {\r
+                                float ymin = ((Number) constraintStructure.getFieldValue("ymin")).floatValue();\r
+                                if (scales[frame].y < ymin) {\r
+                                    scales[frame].y -= (scales[frame].y - ymin) * influence;\r
+                                }\r
+                            }\r
+                            if ((flag & LIMIT_YMAX) != 0) {\r
+                                float ymax = ((Number) constraintStructure.getFieldValue("ymax")).floatValue();\r
+                                if (scales[frame].y > ymax) {\r
+                                    scales[frame].y -= (scales[frame].y - ymax) * influence;\r
+                                }\r
+                            }\r
+                            if ((flag & LIMIT_ZMIN) != 0) {\r
+                                float zmin = ((Number) constraintStructure.getFieldValue("zmin")).floatValue();\r
+                                if (scales[frame].z < zmin) {\r
+                                    scales[frame].z -= (scales[frame].z - zmin) * influence;\r
+                                }\r
+                            }\r
+                            if ((flag & LIMIT_ZMAX) != 0) {\r
+                                float zmax = ((Number) constraintStructure.getFieldValue("zmax")).floatValue();\r
+                                if (scales[frame].z > zmax) {\r
+                                    scales[frame].z -= (scales[frame].z - zmax) * influence;\r
+                                }\r
+                            }//TODO: consider constraint space !!!\r
+                        }\r
+                        boneTrack.setKeyframes(boneTrack.getTimes(), boneTrack.getTranslations(), boneTrack.getRotations(), scales);\r
+                    }\r
+                }\r
+            };\r
+\r
+            //STRETCHTO constraint (TODO: to implement)\r
+            influenceFunctions[ConstraintType.CONSTRAINT_TYPE_STRETCHTO.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_STRETCHTO, dataRepository) {\r
+            };\r
+\r
+            //TRANSFORM constraint (TODO: to implement)\r
+            influenceFunctions[ConstraintType.CONSTRAINT_TYPE_TRANSFORM.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_TRANSFORM, dataRepository) {\r
+            };\r
+        }\r
+    }\r
+\r
+    /**\r
+     * This method reads constraints for for the given structure. The constraints are loaded only once for object/bone.\r
+     * @param ownerOMA\r
+     *        the owner's old memory address\r
+     * @param objectStructure\r
+     *        the structure we read constraint's for\r
+     * @param dataRepository\r
+     *        the data repository\r
+     * @throws BlenderFileException\r
+     */\r
+    public void loadConstraints(Structure objectStructure, DataRepository dataRepository) throws BlenderFileException {\r
+        // reading influence ipos for the constraints\r
+        IpoHelper ipoHelper = dataRepository.getHelper(IpoHelper.class);\r
+        Map<String, Map<String, Ipo>> constraintsIpos = new HashMap<String, Map<String, Ipo>>();\r
+        Pointer pActions = (Pointer) objectStructure.getFieldValue("action");\r
+        if (!pActions.isNull()) {\r
+            List<Structure> actions = pActions.fetchData(dataRepository.getInputStream());\r
+            for (Structure action : actions) {\r
+                Structure chanbase = (Structure) action.getFieldValue("chanbase");\r
+                List<Structure> actionChannels = chanbase.evaluateListBase(dataRepository);\r
+                for (Structure actionChannel : actionChannels) {\r
+                    Map<String, Ipo> ipos = new HashMap<String, Ipo>();\r
+                    Structure constChannels = (Structure) actionChannel.getFieldValue("constraintChannels");\r
+                    List<Structure> constraintChannels = constChannels.evaluateListBase(dataRepository);\r
+                    for (Structure constraintChannel : constraintChannels) {\r
+                        Pointer pIpo = (Pointer) constraintChannel.getFieldValue("ipo");\r
+                        if (!pIpo.isNull()) {\r
+                            String constraintName = constraintChannel.getFieldValue("name").toString();\r
+                            Ipo ipo = ipoHelper.createIpo(pIpo.fetchData(dataRepository.getInputStream()).get(0), dataRepository);\r
+                            ipos.put(constraintName, ipo);\r
+                        }\r
+                    }\r
+                    String actionName = actionChannel.getFieldValue("name").toString();\r
+                    constraintsIpos.put(actionName, ipos);\r
+                }\r
+            }\r
+        }\r
+\r
+        //loading constraints connected with the object's bones\r
+        List<Constraint> constraintsList = new ArrayList<Constraint>();\r
+        Pointer pPose = (Pointer) objectStructure.getFieldValue("pose");//TODO: what if the object has two armatures ????\r
+        if (!pPose.isNull()) {\r
+            //getting pose channels\r
+            List<Structure> poseChannels = ((Structure) pPose.fetchData(dataRepository.getInputStream()).get(0).getFieldValue("chanbase")).evaluateListBase(dataRepository);\r
+            for (Structure poseChannel : poseChannels) {\r
+                Long boneOMA = Long.valueOf(((Pointer) poseChannel.getFieldValue("bone")).getOldMemoryAddress());\r
+                //the name is read directly from structure because bone might not yet be loaded\r
+                String name = dataRepository.getFileBlock(boneOMA).getStructure(dataRepository).getFieldValue("name").toString();\r
+                List<Structure> constraints = ((Structure) poseChannel.getFieldValue("constraints")).evaluateListBase(dataRepository);\r
+                for (Structure constraint : constraints) {\r
+                    int type = ((Number) constraint.getFieldValue("type")).intValue();\r
+                    String constraintName = constraint.getFieldValue("name").toString();\r
+                    Ipo ipo = constraintsIpos.get(name).get(constraintName);\r
+                    if (ipo == null) {\r
+                        float enforce = ((Number) constraint.getFieldValue("enforce")).floatValue();\r
+                        ipo = ipoHelper.createIpo(enforce);\r
+                    }\r
+                    Space ownerSpace = Space.valueOf(((Number) constraint.getFieldValue("ownspace")).byteValue());\r
+                    Space targetSpace = Space.valueOf(((Number) constraint.getFieldValue("tarspace")).byteValue());\r
+                    Constraint c = new Constraint(constraint, influenceFunctions[type], boneOMA, ownerSpace, targetSpace, ipo, dataRepository);\r
+                    constraintsList.add(c);\r
+                }\r
+            }\r
+        }\r
+        /* TODO: reading constraints for objects (implement when object's animation will be available)\r
+        List<Structure> constraintChannels = ((Structure)objectStructure.getFieldValue("constraintChannels")).evaluateListBase(dataRepository);\r
+        for(Structure constraintChannel : constraintChannels) {\r
+        System.out.println(constraintChannel);\r
+        }\r
+        \r
+        //loading constraints connected with the object itself (TODO: test this)\r
+        if(!this.constraints.containsKey(objectStructure.getOldMemoryAddress())) {\r
+        List<Structure> constraints = ((Structure)objectStructure.getFieldValue("constraints")).evaluateListBase(dataRepository);\r
+        Constraint[] result = new Constraint[constraints.size()];\r
+        int i = 0;\r
+        for(Structure constraint : constraints) {\r
+        int type = ((Number)constraint.getFieldValue("type")).intValue();\r
+        String name = constraint.getFieldValue("name").toString();\r
+        result[i++] = new Constraint(constraint, influenceFunctions[type], null, dataRepository);//TODO: influence ipos for object animation\r
+        }\r
+        this.constraints.put(objectStructure.getOldMemoryAddress(), result);\r
+        }\r
+         */\r
+        if (constraintsList.size() > 0) {\r
+            this.constraints.put(objectStructure.getOldMemoryAddress(), constraintsList.toArray(new Constraint[constraintsList.size()]));\r
+        }\r
+    }\r
+\r
+    /**\r
+     * This method returns a list of constraints of the feature's constraints. The order of constraints is important.\r
+     * @param ownerOMA\r
+     *        the owner's old memory address\r
+     * @return a table of constraints for the feature specified by old memory address\r
+     */\r
+    public Constraint[] getConstraints(Long ownerOMA) {\r
+        return constraints.get(ownerOMA);\r
+    }\r
+\r
+    @Override\r
+    public void clearState() {\r
+        constraints.clear();\r
+    }\r
+\r
+    /**\r
+     * The purpose of this class is to imitate bone's movement when calculating inverse kinematics.\r
+     * @author Marcin Roguski\r
+     */\r
+    private static class CalculationBone extends Node {\r
+\r
+        /** The name of the bone. Only to be used in toString method. */\r
+        private String boneName;\r
+        /** The bone's tracks. Will be altered at the end of calculation process. */\r
+        private BoneTrack track;\r
+        /** The starting position of the bone. */\r
+        private Vector3f startTranslation;\r
+        /** The starting rotation of the bone. */\r
+        private Quaternion startRotation;\r
+        /** The starting scale of the bone. */\r
+        private Vector3f startScale;\r
+        private Vector3f[] translations;\r
+        private Quaternion[] rotations;\r
+        private Vector3f[] scales;\r
+\r
+        /**\r
+         * Constructor. Stores the track, starting transformation and sets the transformation to the starting positions.\r
+         * @param bone\r
+         *        the bone this class will imitate\r
+         * @param track\r
+         *        the bone's tracks\r
+         */\r
+        public CalculationBone(Bone bone, BoneTrack track) {\r
+            this.boneName = bone.getName();\r
+            this.track = track;\r
+            this.startRotation = bone.getModelSpaceRotation().clone();\r
+            this.startTranslation = bone.getModelSpacePosition().clone();\r
+            this.startScale = bone.getModelSpaceScale().clone();\r
+            this.translations = track.getTranslations();\r
+            this.rotations = track.getRotations();\r
+            this.scales = track.getScales();\r
+            this.reset();\r
+        }\r
+\r
+        /**\r
+         * This method returns the end point of the bone. If the bone has parent it is calculated from the start point\r
+         * of parent to the start point of this bone. If the bone doesn't have a parent the end location is considered\r
+         * to be 1 point up along Y axis (scale is applied if set to != 1.0);\r
+         * @return the end point of this bone\r
+         */\r
+        //TODO: set to Z axis if user defined it this way\r
+        public Vector3f getEndPoint() {\r
+            if (this.getParent() == null) {\r
+                return new Vector3f(0, this.getLocalScale().y, 0);\r
+            } else {\r
+                Node parent = this.getParent();\r
+                return parent.getWorldTranslation().subtract(this.getWorldTranslation()).multLocal(this.getWorldScale());\r
+            }\r
+        }\r
+\r
+        /**\r
+         * This method resets the calculation bone to the starting position.\r
+         */\r
+        public void reset() {\r
+            this.setLocalTranslation(startTranslation);\r
+            this.setLocalRotation(startRotation);\r
+            this.setLocalScale(startScale);\r
+        }\r
+\r
+        @Override\r
+        public int attachChild(Spatial child) {\r
+            if (this.getChildren() != null && this.getChildren().size() > 1) {\r
+                throw new IllegalStateException(this.getClass().getName() + " class instance can only have one child!");\r
+            }\r
+            return super.attachChild(child);\r
+        }\r
+\r
+        public Spatial rotate(Quaternion rot, int frame) {\r
+            Spatial spatial = super.rotate(rot);\r
+            this.updateWorldTransforms();\r
+            if (this.getChildren() != null && this.getChildren().size() > 0) {\r
+                CalculationBone child = (CalculationBone) this.getChild(0);\r
+                child.updateWorldTransforms();\r
+            }\r
+            rotations[frame].set(this.getLocalRotation());\r
+            translations[frame].set(this.getLocalTranslation());\r
+            if (scales != null) {\r
+                scales[frame].set(this.getLocalScale());\r
+            }\r
+            return spatial;\r
+        }\r
+\r
+        public void applyCalculatedTracks() {\r
+            track.setKeyframes(track.getTimes(), translations, rotations);//TODO:scales\r
+        }\r
+\r
+        @Override\r
+        public String toString() {\r
+            return boneName + ": " + this.getLocalRotation() + " " + this.getLocalTranslation();\r
+        }\r
+    }\r
 }\r
index f5ca3c9..343fc1b 100644 (file)
@@ -39,552 +39,552 @@ import com.jme3.util.BufferUtils;
  * @author Marcin Roguski\r
  */\r
 public class CurvesHelper extends AbstractBlenderHelper {\r
-       private static final Logger                     LOGGER          = Logger.getLogger(CurvesHelper.class.getName());\r
-       \r
-       /** This variable indicates if the Y asxis is the UP axis or not. */\r
-       protected boolean                               fixUpAxis;\r
-       /** Minimum basis U function degree for NURBS curves and surfaces. */\r
-       protected int                                   minimumBasisUFunctionDegree = 4;\r
-       /** Minimum basis V function degree for NURBS curves and surfaces. */\r
-       protected int                                   minimumBasisVFunctionDegree = 4;\r
-       \r
-       /**\r
-        * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
-        * different blender versions.\r
-        * @param blenderVersion\r
-        *        the version read from the blend file\r
-        */\r
-       public CurvesHelper(String blenderVersion) {\r
-               super(blenderVersion);\r
-       }\r
-       \r
-       /**\r
-        * This method sets the Y is UP axis. By default the UP axis is Z (just like in blender).\r
-        * @param fixUpAxis\r
-        *        a variable that indicates if the Y asxis is the UP axis or not\r
-        */\r
-       public void setyIsUpAxis(boolean fixUpAxis) {\r
-               this.fixUpAxis = fixUpAxis;\r
-       }\r
-\r
-       /**\r
-        * This method converts given curve structure into a list of geometries representing the curve. The list is used here because on object\r
-        * can have several separate curves.\r
-        * @param curveStructure\r
-        *            the curve structure\r
-        * @param dataRepository\r
-        *            the data repository\r
-        * @return a list of geometries repreenting a single curve object\r
-        * @throws BlenderFileException\r
-        */\r
-       public List<Geometry> toCurve(Structure curveStructure, DataRepository dataRepository) throws BlenderFileException {\r
-               String name = curveStructure.getName();\r
-               int flag = ((Number)curveStructure.getFieldValue("flag")).intValue();\r
-               boolean is3D = (flag & 0x01) != 0;\r
-               boolean isFront = (flag & 0x02) != 0 && !is3D;\r
-               boolean isBack = (flag & 0x04) != 0 && !is3D;\r
-               if(isFront) {\r
-                       LOGGER.warning("No front face in curve implemented yet!");//TODO: implement front face\r
-               }\r
-               if(isBack) {\r
-                       LOGGER.warning("No back face in curve implemented yet!");//TODO: implement back face\r
-               }\r
-               \r
-               //reading nurbs (and sorting them by material)\r
-               List<Structure> nurbStructures = ((Structure)curveStructure.getFieldValue("nurb")).evaluateListBase(dataRepository);\r
-               Map<Number, List<Structure>> nurbs = new HashMap<Number, List<Structure>>();\r
-               for(Structure nurb : nurbStructures) {\r
-                       Number matNumber = (Number) nurb.getFieldValue("mat_nr");\r
-                       List<Structure> nurbList = nurbs.get(matNumber);\r
-                       if(nurbList==null) {\r
-                               nurbList = new ArrayList<Structure>();\r
-                               nurbs.put(matNumber, nurbList);\r
-                       }\r
-                       nurbList.add(nurb);\r
-               }\r
-               \r
-               //getting materials\r
-               MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);\r
-               Material[] materials = materialHelper.getMaterials(curveStructure, dataRepository);\r
-               if(materials==null) {\r
-                       materials = new Material[] { dataRepository.getDefaultMaterial().clone() };\r
-               }\r
-               for(Material material : materials) {\r
-                       material.getAdditionalRenderState().setFaceCullMode(FaceCullMode.Off);\r
-               }\r
-               \r
-               //getting or creating bevel object\r
-               List<Geometry> bevelObject = null;\r
-               Pointer pBevelObject = (Pointer) curveStructure.getFieldValue("bevobj");\r
-               if(!pBevelObject.isNull()) {\r
-                       Pointer pBevelStructure = (Pointer) pBevelObject.fetchData(dataRepository.getInputStream()).get(0).getFieldValue("data");\r
-                       Structure bevelStructure = pBevelStructure.fetchData(dataRepository.getInputStream()).get(0);\r
-                       bevelObject = this.toCurve(bevelStructure, dataRepository);\r
-               } else {\r
-                       int bevResol = ((Number)curveStructure.getFieldValue("bevresol")).intValue();\r
-                       float extrude = ((Number)curveStructure.getFieldValue("ext1")).floatValue();\r
-                       float bevelDepth = ((Number)curveStructure.getFieldValue("ext2")).floatValue();\r
-                       if(bevelDepth>0.0f) {\r
-                               float handlerLength = bevelDepth/2.0f;\r
-                               \r
-                               List<Vector3f> conrtolPoints = new ArrayList<Vector3f>(extrude>0.0f ? 19 : 13);\r
-                               conrtolPoints.add(new Vector3f(-bevelDepth,extrude,0));\r
-                               conrtolPoints.add(new Vector3f(-bevelDepth,handlerLength+extrude,0));\r
-                               \r
-                               conrtolPoints.add(new Vector3f(-handlerLength,bevelDepth+extrude,0));\r
-                               conrtolPoints.add(new Vector3f(0,bevelDepth+extrude,0));\r
-                               conrtolPoints.add(new Vector3f(handlerLength,bevelDepth+extrude,0));\r
-                               \r
-                               conrtolPoints.add(new Vector3f(bevelDepth,extrude + handlerLength,0));\r
-                               conrtolPoints.add(new Vector3f(bevelDepth,extrude,0));\r
-                               conrtolPoints.add(new Vector3f(bevelDepth,extrude - handlerLength,0));\r
-                               \r
-                               if(extrude>0.0f) {\r
-                                       conrtolPoints.add(new Vector3f(bevelDepth,-extrude + handlerLength,0));\r
-                                       conrtolPoints.add(new Vector3f(bevelDepth,-extrude,0));\r
-                                       conrtolPoints.add(new Vector3f(bevelDepth,-extrude-handlerLength,0));\r
-                               }\r
-                               \r
-                               conrtolPoints.add(new Vector3f(handlerLength,-bevelDepth-extrude,0));\r
-                               conrtolPoints.add(new Vector3f(0,-bevelDepth-extrude,0));\r
-                               conrtolPoints.add(new Vector3f(-handlerLength,-bevelDepth-extrude,0));\r
-                               \r
-                               conrtolPoints.add(new Vector3f(-bevelDepth,-handlerLength - extrude,0));\r
-                               conrtolPoints.add(new Vector3f(-bevelDepth,-extrude,0));\r
-                               \r
-                               if(extrude>0.0f) {\r
-                                       conrtolPoints.add(new Vector3f(-bevelDepth,handlerLength - extrude,0));\r
-                                       \r
-                                       conrtolPoints.add(new Vector3f(-bevelDepth,-handlerLength + extrude,0));\r
-                                       conrtolPoints.add(new Vector3f(-bevelDepth,extrude,0));\r
-                               }\r
-                               \r
-                               Spline bevelSpline = new Spline(SplineType.Bezier, conrtolPoints, 0, false);\r
-                               Curve bevelCurve = new Curve(bevelSpline, bevResol);\r
-                               bevelObject = new ArrayList<Geometry>(1);\r
-                               bevelObject.add(new Geometry("", bevelCurve));\r
-                       } else if(extrude>0.0f) {\r
-                               Spline bevelSpline = new Spline(SplineType.Linear, new Vector3f[] {\r
-                                               new Vector3f(0, extrude, 0), new Vector3f(0, -extrude, 0)\r
-                               }, 1, false);\r
-                               Curve bevelCurve = new Curve(bevelSpline, bevResol);\r
-                               bevelObject = new ArrayList<Geometry>(1);\r
-                               bevelObject.add(new Geometry("", bevelCurve));\r
-                       }\r
-               }\r
-               \r
-               //getting taper object\r
-               Curve taperObject = null;\r
-               Pointer pTaperObject = (Pointer) curveStructure.getFieldValue("taperobj");\r
-               if(bevelObject!=null && !pTaperObject.isNull()) {\r
-                       Pointer pTaperStructure = (Pointer) pTaperObject.fetchData(dataRepository.getInputStream()).get(0).getFieldValue("data");\r
-                       Structure taperStructure = pTaperStructure.fetchData(dataRepository.getInputStream()).get(0);\r
-                       taperObject = this.loadTaperObject(taperStructure, dataRepository);\r
-               }\r
-               \r
-               Vector3f loc = this.getLoc(curveStructure);\r
-               //creating the result curves\r
-               List<Geometry> result = new ArrayList<Geometry>(nurbs.size());\r
-               for(Entry<Number, List<Structure>> nurbEntry : nurbs.entrySet()) {\r
-                       for(Structure nurb : nurbEntry.getValue()) {\r
-                               int type = ((Number)nurb.getFieldValue("type")).intValue();\r
-                               List<Geometry> nurbGeoms = null;\r
-                               if((type & 0x01)!=0) {//Bezier curve\r
-                                       nurbGeoms = this.loadBezierCurve(loc, nurb, bevelObject, taperObject, dataRepository);\r
-                               } else if((type & 0x04)!=0) {//NURBS\r
-                                       nurbGeoms = this.loadNurb(loc, nurb, bevelObject, taperObject, dataRepository);\r
-                               }\r
-                               if(nurbGeoms!=null) {//setting the name and assigning materials\r
-                                       for(Geometry nurbGeom : nurbGeoms) {\r
-                                               nurbGeom.setMaterial(materials[nurbEntry.getKey().intValue()]);\r
-                                               nurbGeom.setName(name);\r
-                                               result.add(nurbGeom);\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-               return result;\r
-       }\r
-       \r
-       /**\r
-        * This method loads the bezier curve.\r
-        * @param loc\r
-        *            the translation of the curve\r
-        * @param nurb\r
-        *            the nurb structure\r
-        * @param bevelObject\r
-        *            the bevel object\r
-        * @param taperObject\r
-        *            the taper object\r
-        * @param dataRepository\r
-        *            the data repository\r
-        * @return a list of geometries representing the curves\r
-        * @throws BlenderFileException\r
-        *             an exception is thrown when there are problems with the blender file\r
-        */\r
-       protected List<Geometry> loadBezierCurve(Vector3f loc, Structure nurb, List<Geometry> bevelObject, Curve taperObject, \r
-                                                                                        DataRepository dataRepository) throws BlenderFileException {\r
-               Pointer pBezierTriple = (Pointer) nurb.getFieldValue("bezt");\r
-               List<Geometry> result = new ArrayList<Geometry>();\r
-               if(!pBezierTriple.isNull()) {\r
-                       boolean smooth = (((Number)nurb.getFlatFieldValue("flag")).intValue() & 0x01) !=0;\r
-                       int resolution = ((Number)nurb.getFieldValue("resolu")).intValue();\r
-                       boolean cyclic = (((Number)nurb.getFieldValue("flagu")).intValue() & 0x01) != 0;\r
-                       \r
-                       //creating the curve object\r
-                       BezierCurve bezierCurve = new BezierCurve(0, pBezierTriple.fetchData(dataRepository.getInputStream()), 3);\r
-                       List<Vector3f> controlPoints = bezierCurve.getControlPoints();\r
-                       if(cyclic) {\r
-                               //copy the first three points at the end\r
-                               for(int i=0;i<3;++i) {\r
-                                       controlPoints.add(controlPoints.get(i));\r
-                               }\r
-                       }\r
-                       //removing the first and last handles\r
-                       controlPoints.remove(0);\r
-                       controlPoints.remove(controlPoints.size()-1);\r
-\r
-                       //creating curve\r
-                       Spline spline = new Spline(SplineType.Bezier, controlPoints, 0, false);\r
-                       Curve curve = new Curve(spline, resolution);\r
-                       if(bevelObject==null) {//creating a normal curve\r
-                               Geometry curveGeometry = new Geometry(null, curve);\r
-                               result.add(curveGeometry);\r
-                               //TODO: use front and back flags; surface excluding algorithm for bezier circles should be added\r
-                       } else {//creating curve with bevel and taper shape\r
-                               result = this.applyBevelAndTaper(curve, bevelObject, taperObject, smooth, dataRepository);\r
-                       }\r
-               }\r
-               return result;\r
-       }\r
-       \r
-       /**\r
-        * This method loads the NURBS curve or surface.\r
-        * @param loc\r
-        *            object's location\r
-        * @param nurb\r
-        *            the NURBS data structure\r
-        * @param bevelObject\r
-        *            the bevel object to be applied\r
-        * @param taperObject\r
-        *            the taper object to be applied\r
-        * @param dataRepository\r
-        *            the data repository\r
-        * @return a list of geometries that represents the loaded NURBS curve or surface\r
-        * @throws BlenderFileException\r
-        *             an exception is throw when problems with blender loaded data occurs\r
-        */\r
-       @SuppressWarnings("unchecked")\r
-       protected List<Geometry> loadNurb(Vector3f loc, Structure nurb, List<Geometry> bevelObject, Curve taperObject, \r
-                                                                         DataRepository dataRepository) throws BlenderFileException {\r
-               //loading the knots\r
-               List<Float>[] knots = new List[2];\r
-               Pointer[] pKnots = new Pointer[] { (Pointer) nurb.getFieldValue("knotsu"), (Pointer) nurb.getFieldValue("knotsv") };\r
-               for(int i=0;i<knots.length; ++i) {\r
-                       if(!pKnots[i].isNull()) {\r
-                               FileBlockHeader fileBlockHeader = dataRepository.getFileBlock(pKnots[i].getOldMemoryAddress());\r
-                               BlenderInputStream blenderInputStream = dataRepository.getInputStream();\r
-                               blenderInputStream.setPosition(fileBlockHeader.getBlockPosition());\r
-                               int knotsAmount = fileBlockHeader.getCount() * fileBlockHeader.getSize() / 4;\r
-                               knots[i] = new ArrayList<Float>(knotsAmount);\r
-                               for(int j=0;j<knotsAmount;++j) {\r
-                                       knots[i].add(Float.valueOf(blenderInputStream.readFloat()));\r
-                               }\r
-                       }\r
-               }\r
-               \r
-               //loading the flags and orders (basis functions degrees)\r
-               int flagU = ((Number)nurb.getFieldValue("flagu")).intValue();\r
-               int flagV = ((Number)nurb.getFieldValue("flagv")).intValue();\r
-               int orderU = ((Number)nurb.getFieldValue("orderu")).intValue();\r
-               int orderV = ((Number)nurb.getFieldValue("orderv")).intValue();\r
-               \r
-               //loading control points and their weights\r
-               int pntsU = ((Number)nurb.getFieldValue("pntsu")).intValue();\r
-               int pntsV = ((Number)nurb.getFieldValue("pntsv")).intValue();\r
-               List<Structure> bPoints = ((Pointer)nurb.getFieldValue("bp")).fetchData(dataRepository.getInputStream());\r
-               List<List<Vector4f>> controlPoints = new ArrayList<List<Vector4f>>(pntsV);\r
-               for(int i=0;i<pntsV;++i) {\r
-                       List<Vector4f> uControlPoints = new ArrayList<Vector4f>(pntsU);\r
-                       for(int j=0;j<pntsU;++j) {\r
-                               DynamicArray<Float> vec = (DynamicArray<Float>)bPoints.get(j + i*pntsU).getFieldValue("vec");\r
-                               if(fixUpAxis) {\r
-                                       uControlPoints.add(new Vector4f(vec.get(0).floatValue(), vec.get(2).floatValue(), -vec.get(1).floatValue(), vec.get(3).floatValue()));\r
-                               } else {\r
-                                       uControlPoints.add(new Vector4f(vec.get(0).floatValue(), vec.get(1).floatValue(), vec.get(2).floatValue(), vec.get(3).floatValue()));\r
-                               }\r
-                       }\r
-                       if((flagU & 0x01) != 0) {\r
-                               for(int k=0;k<orderU - 1;++k) {\r
-                                       uControlPoints.add(uControlPoints.get(k));\r
-                               }\r
-                       }\r
-                       controlPoints.add(uControlPoints);\r
-               }\r
-               if((flagV & 0x01) != 0) {\r
-                       for(int k=0;k<orderV - 1;++k) {\r
-                               controlPoints.add(controlPoints.get(k));\r
-                       }\r
-               }\r
-               \r
-               int resolu = ((Number)nurb.getFieldValue("resolu")).intValue() + 1;\r
-               List<Geometry> result;\r
-               if(knots[1]==null) {//creating the curve\r
-                       Spline nurbSpline = new Spline(controlPoints.get(0), knots[0]);\r
-                       Curve nurbCurve = new Curve(nurbSpline, resolu);\r
-                       if(bevelObject!=null) {\r
-                               result = this.applyBevelAndTaper(nurbCurve, bevelObject, taperObject, true, dataRepository);//TODO: smooth\r
-                       } else {\r
-                               result = new ArrayList<Geometry>(1);\r
-                               Geometry nurbGeometry = new Geometry("", nurbCurve);\r
-                               result.add(nurbGeometry);\r
-                       }\r
-               } else {//creating the nurb surface\r
-                       int resolv = ((Number)nurb.getFieldValue("resolv")).intValue() + 1;\r
-                       Surface nurbSurface = Surface.createNurbsSurface(controlPoints, knots, resolu, resolv, orderU, orderV);\r
-                       Geometry nurbGeometry = new Geometry("", nurbSurface);\r
-                       result = new ArrayList<Geometry>(1);\r
-                       result.add(nurbGeometry);\r
-               }\r
-               return result;\r
-       }\r
-       \r
-       /**\r
-        * This method returns the taper scale that should be applied to the object.\r
-        * @param taperPoints\r
-        *            the taper points\r
-        * @param taperLength\r
-        *            the taper curve length\r
-        * @param percent\r
-        *            the percent of way along the whole taper curve\r
-        * @param store\r
-        *            the vector where the result will be stored\r
-        */\r
-       protected float getTaperScale(float[] taperPoints, float taperLength, float percent) {\r
-               float length = taperLength * percent;\r
-               float currentLength = 0;\r
-               Vector3f p = new Vector3f();\r
-               int i;\r
-               for(i=0;i<taperPoints.length-6 && currentLength < length; i += 3) {\r
-                       p.set(taperPoints[i], taperPoints[i+1], taperPoints[i+2]);\r
-                       p.subtractLocal(taperPoints[i+3], taperPoints[i+4], taperPoints[i+5]);\r
-                       currentLength += p.length();\r
-               }\r
-               currentLength -= p.length();\r
-               float leftLength = length - currentLength;\r
-               float percentOnSegment = p.length()==0 ? 0 : leftLength / p.length();\r
-               Vector3f store = FastMath.interpolateLinear(percentOnSegment, \r
-                                                                                                       new Vector3f(taperPoints[i], taperPoints[i+1], taperPoints[i+2]), \r
-                                                                                                       new Vector3f(taperPoints[i+3], taperPoints[i+4], taperPoints[i+5]));\r
-               return store.y;\r
-       }\r
-       \r
-       /**\r
-        * This method applies bevel and taper objects to the curve.\r
-        * @param curve\r
-        *            the curve we apply the objects to\r
-        * @param bevelObject\r
-        *            the bevel object\r
-        * @param taperObject\r
-        *            the taper object\r
-        * @param smooth\r
-        *                        the smooth flag\r
-        * @param dataRepository\r
-        *            the data repository\r
-        * @return a list of geometries representing the beveled and/or tapered curve\r
-        */\r
-       protected List<Geometry> applyBevelAndTaper(Curve curve, List<Geometry> bevelObject, Curve taperObject, \r
-                                                                                               boolean smooth, DataRepository dataRepository) {\r
-               float[] curvePoints = BufferUtils.getFloatArray(curve.getFloatBuffer(Type.Position));\r
-               MeshHelper meshHelper = dataRepository.getHelper(MeshHelper.class);\r
-               float curveLength = curve.getLength();\r
-               //TODO: use the smooth var\r
-               \r
-               //taper data\r
-               float[] taperPoints = null;\r
-               float taperLength = 0;\r
-               if(taperObject!=null) {\r
-                       taperPoints = BufferUtils.getFloatArray(taperObject.getFloatBuffer(Type.Position));\r
-                       taperLength = taperObject.getLength();\r
-               }\r
-               \r
-               //several objects can be allocated only once\r
-               Vector3f p = new Vector3f();\r
-               Vector3f z = new Vector3f(0,0,1);\r
-               Vector3f negativeY = new Vector3f(0, -1, 0);\r
-               Matrix4f m = new Matrix4f();\r
-               float lengthAlongCurve = 0, taperScale = 1.0f;\r
-               Quaternion planeRotation = new Quaternion();\r
-               Quaternion zRotation = new Quaternion();\r
-               float[] temp = new float[] {0,0,0,1};\r
-               Map<Vector3f, Vector3f> normalMap = new HashMap<Vector3f, Vector3f>();//normalMap merges normals of faces that will be rendered smooth\r
-               \r
-               FloatBuffer[] vertexBuffers = new FloatBuffer[bevelObject.size()];\r
-               FloatBuffer[] normalBuffers = new FloatBuffer[bevelObject.size()];\r
-               IntBuffer[] indexBuffers = new IntBuffer[bevelObject.size()];\r
-               for(int geomIndex = 0;geomIndex<bevelObject.size();++geomIndex) {\r
-                       Mesh mesh = bevelObject.get(geomIndex).getMesh();\r
-                       FloatBuffer positions = mesh.getFloatBuffer(Type.Position);\r
-                       float[] vertices = BufferUtils.getFloatArray(positions);\r
-                       \r
-                       for(int i=0;i<curvePoints.length;i+=3) {\r
-                               p.set(curvePoints[i], curvePoints[i+1], curvePoints[i+2]);\r
-                               Vector3f v;\r
-                               if(i==0) {\r
-                                       v = new Vector3f(curvePoints[3] - p.x, curvePoints[4] - p.y, curvePoints[5] - p.z);\r
-                               } else if(i+3>=curvePoints.length) {\r
-                                       v = new Vector3f(p.x - curvePoints[i-3], p.y - curvePoints[i-2], p.z - curvePoints[i-1]);\r
-                                       lengthAlongCurve += v.length();\r
-                               } else {\r
-                                       v = new Vector3f(curvePoints[i+3] - curvePoints[i-3],\r
-                                                        curvePoints[i+4] - curvePoints[i-2],\r
-                                                        curvePoints[i+5] - curvePoints[i-1]);\r
-                                       lengthAlongCurve += new Vector3f(curvePoints[i+3] - p.x, curvePoints[i+4] - p.y, curvePoints[i+5] - p.z).length();\r
-                               }\r
-                               v.normalizeLocal();\r
-                               \r
-                               float angle = FastMath.acos(v.dot(z));\r
-                               v.crossLocal(z).normalizeLocal();//v is the rotation axis now\r
-                               planeRotation.fromAngleAxis(angle, v);\r
-                               \r
-                               Vector3f zAxisRotationVector = negativeY.cross(v).normalizeLocal();\r
-                               float zAxisRotationAngle = FastMath.acos(negativeY.dot(v));\r
-                               zRotation.fromAngleAxis(zAxisRotationAngle, zAxisRotationVector);\r
-                               \r
-                               //point transformation matrix\r
-                               if(taperPoints!=null) {\r
-                                       taperScale = this.getTaperScale(taperPoints, taperLength, lengthAlongCurve / curveLength);\r
-                               }\r
-                               m.set(Matrix4f.IDENTITY);\r
-                               m.setRotationQuaternion(planeRotation.multLocal(zRotation));\r
-                               m.setTranslation(p);\r
-                               \r
-                               //these vertices need to be thrown on XY plane\r
-                               //and moved to the origin of [p1.x, p1.y] on the plane\r
-                               Vector3f[] verts = new Vector3f[vertices.length/3];\r
-                               for(int j=0;j<verts.length;++j) {\r
-                                        temp[0] = vertices[j*3] * taperScale;\r
-                                        temp[1] = vertices[j*3+1] * taperScale;\r
-                                        temp[2] = 0;\r
-                                        m.mult(temp);//the result is stored in the array\r
-                                        if(fixUpAxis) {\r
-                                                verts[j] = new Vector3f(temp[0], temp[1], temp[2]);\r
-                                        } else {\r
-                                                verts[j] = new Vector3f(temp[0], temp[2], -temp[1]);\r
-                                        }\r
-                               }\r
-                               if(vertexBuffers[geomIndex]==null) {\r
-                                       vertexBuffers[geomIndex] = BufferUtils.createFloatBuffer(verts.length * curvePoints.length);\r
-                               }\r
-                               FloatBuffer buffer = BufferUtils.createFloatBuffer(verts);\r
-                               vertexBuffers[geomIndex].put(buffer);\r
-                               \r
-                               //adding indexes\r
-                               IntBuffer indexBuffer = indexBuffers[geomIndex];\r
-                               if(indexBuffer==null) {\r
-                                       //the amount of faces in the final mesh is the amount of edges in the bevel curve\r
-                                       //(which is less by 1 than its number of vertices)\r
-                                       //multiplied by 2 (because each edge has two faces assigned on both sides)\r
-                                       //and multiplied by the amount of bevel curve repeats which is equal to the amount of vertices on the target curve\r
-                                       //finally we need to subtract the bevel edges amount 2 times because the border edges have only one face attached\r
-                                       //and at last multiply everything by 3 because each face needs 3 indexes to be described\r
-                                       int bevelCurveEdgesAmount = verts.length-1;\r
-                                       indexBuffer = BufferUtils.createIntBuffer(((bevelCurveEdgesAmount << 1) * curvePoints.length - bevelCurveEdgesAmount << 1) * 3);\r
-                                       indexBuffers[geomIndex] = indexBuffer;\r
-                               }\r
-                               int pointOffset = i/3 * verts.length;\r
-                               if(i+3<curvePoints.length) {\r
-                                       for(int index=0;index<verts.length-1;++index) {\r
-                                               indexBuffer.put(index + pointOffset);\r
-                                               indexBuffer.put(index + pointOffset + 1);\r
-                                               indexBuffer.put(verts.length + index + pointOffset);\r
-                                               indexBuffer.put(verts.length + index + pointOffset);\r
-                                               indexBuffer.put(index + pointOffset + 1);\r
-                                               indexBuffer.put(verts.length + index + pointOffset + 1);\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-               \r
-               //calculating the normals\r
-               for(int geomIndex = 0;geomIndex<bevelObject.size();++geomIndex) {\r
-                       Vector3f[] allVerts = BufferUtils.getVector3Array(vertexBuffers[geomIndex]);\r
-                       int[] allIndices = BufferUtils.getIntArray(indexBuffers[geomIndex]);\r
-                       for(int i=0;i<allIndices.length-3;i+=3) {\r
-                               Vector3f n = FastMath.computeNormal(allVerts[allIndices[i]], allVerts[allIndices[i + 1]], allVerts[allIndices[i + 2]]);\r
-                               meshHelper.addNormal(n, normalMap, smooth, allVerts[allIndices[i]], allVerts[allIndices[i + 1]], allVerts[allIndices[i + 2]]);\r
-                       }\r
-                       if(normalBuffers[geomIndex]==null) {\r
-                               normalBuffers[geomIndex] = BufferUtils.createFloatBuffer(allVerts.length * 3);\r
-                       }\r
-                       for(Vector3f v : allVerts) {\r
-                               Vector3f n = normalMap.get(v);\r
-                               normalBuffers[geomIndex].put(n.x);\r
-                               normalBuffers[geomIndex].put(n.y);\r
-                               normalBuffers[geomIndex].put(n.z);\r
-                       }\r
-               }\r
-\r
-               List<Geometry> result = new ArrayList<Geometry>(vertexBuffers.length);\r
-               for(int i=0;i<vertexBuffers.length;++i) {\r
-                       Mesh mesh = new Mesh();\r
-                       mesh.setBuffer(Type.Position, 3, vertexBuffers[i]);\r
-                       mesh.setBuffer(Type.Index, 3, indexBuffers[i]);\r
-                       mesh.setBuffer(Type.Normal, 3, normalBuffers[i]);\r
-                       Geometry g = new Geometry("g" + i, mesh);\r
-                       g.updateModelBound();\r
-                       result.add(g);\r
-               }\r
-               \r
-               return result;\r
-       }\r
-       \r
-       /**\r
-        * This method loads the taper object.\r
-        * @param taperStructure\r
-        *            the taper structure\r
-        * @param dataRepository\r
-        *            the data repository\r
-        * @return the taper object\r
-        * @throws BlenderFileException\r
-        */\r
-       protected Curve loadTaperObject(Structure taperStructure, DataRepository dataRepository) throws BlenderFileException {\r
-               //reading nurbs\r
-               List<Structure> nurbStructures = ((Structure)taperStructure.getFieldValue("nurb")).evaluateListBase(dataRepository);\r
-               for(Structure nurb : nurbStructures) {\r
-                       Pointer pBezierTriple = (Pointer) nurb.getFieldValue("bezt");\r
-                       if(!pBezierTriple.isNull()) {\r
-                               //creating the curve object\r
-                               BezierCurve bezierCurve = new BezierCurve(0, pBezierTriple.fetchData(dataRepository.getInputStream()), 3);\r
-                               List<Vector3f> controlPoints = bezierCurve.getControlPoints();\r
-                               //removing the first and last handles\r
-                               controlPoints.remove(0);\r
-                               controlPoints.remove(controlPoints.size()-1);\r
-                               \r
-                               //return the first taper curve that has more than 3 control points\r
-                               if(controlPoints.size()>3) {\r
-                                       Spline spline =  new Spline(SplineType.Bezier, controlPoints, 0, false);\r
-                                       int resolution = ((Number)taperStructure.getFieldValue("resolu")).intValue();\r
-                                       return new Curve(spline, resolution);\r
-                               }\r
-                       }\r
-               }\r
-               return null;\r
-       }\r
-       \r
-       /**\r
-        * This method returns the translation of the curve. The UP axis is taken into account here.\r
-        * @param curveStructure\r
-        *            the curve structure\r
-        * @return curve translation\r
-        */\r
-       @SuppressWarnings("unchecked")\r
-       protected Vector3f getLoc(Structure curveStructure) {\r
-               DynamicArray<Number> locArray = (DynamicArray<Number>)curveStructure.getFieldValue("loc");\r
-               if(fixUpAxis) {\r
-                       return new Vector3f(locArray.get(0).floatValue(), locArray.get(1).floatValue(), -locArray.get(2).floatValue());\r
-               } else {\r
-                       return new Vector3f(locArray.get(0).floatValue(), locArray.get(2).floatValue(), locArray.get(1).floatValue());\r
-               }\r
-       }\r
+\r
+    private static final Logger LOGGER = Logger.getLogger(CurvesHelper.class.getName());\r
+    /** This variable indicates if the Y asxis is the UP axis or not. */\r
+    protected boolean fixUpAxis;\r
+    /** Minimum basis U function degree for NURBS curves and surfaces. */\r
+    protected int minimumBasisUFunctionDegree = 4;\r
+    /** Minimum basis V function degree for NURBS curves and surfaces. */\r
+    protected int minimumBasisVFunctionDegree = 4;\r
+\r
+    /**\r
+     * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
+     * different blender versions.\r
+     * @param blenderVersion\r
+     *        the version read from the blend file\r
+     */\r
+    public CurvesHelper(String blenderVersion) {\r
+        super(blenderVersion);\r
+    }\r
+\r
+    /**\r
+     * This method sets the Y is UP axis. By default the UP axis is Z (just like in blender).\r
+     * @param fixUpAxis\r
+     *        a variable that indicates if the Y asxis is the UP axis or not\r
+     */\r
+    public void setyIsUpAxis(boolean fixUpAxis) {\r
+        this.fixUpAxis = fixUpAxis;\r
+    }\r
+\r
+    /**\r
+     * This method converts given curve structure into a list of geometries representing the curve. The list is used here because on object\r
+     * can have several separate curves.\r
+     * @param curveStructure\r
+     *            the curve structure\r
+     * @param dataRepository\r
+     *            the data repository\r
+     * @return a list of geometries repreenting a single curve object\r
+     * @throws BlenderFileException\r
+     */\r
+    public List<Geometry> toCurve(Structure curveStructure, DataRepository dataRepository) throws BlenderFileException {\r
+        String name = curveStructure.getName();\r
+        int flag = ((Number) curveStructure.getFieldValue("flag")).intValue();\r
+        boolean is3D = (flag & 0x01) != 0;\r
+        boolean isFront = (flag & 0x02) != 0 && !is3D;\r
+        boolean isBack = (flag & 0x04) != 0 && !is3D;\r
+        if (isFront) {\r
+            LOGGER.warning("No front face in curve implemented yet!");//TODO: implement front face\r
+        }\r
+        if (isBack) {\r
+            LOGGER.warning("No back face in curve implemented yet!");//TODO: implement back face\r
+        }\r
+\r
+        //reading nurbs (and sorting them by material)\r
+        List<Structure> nurbStructures = ((Structure) curveStructure.getFieldValue("nurb")).evaluateListBase(dataRepository);\r
+        Map<Number, List<Structure>> nurbs = new HashMap<Number, List<Structure>>();\r
+        for (Structure nurb : nurbStructures) {\r
+            Number matNumber = (Number) nurb.getFieldValue("mat_nr");\r
+            List<Structure> nurbList = nurbs.get(matNumber);\r
+            if (nurbList == null) {\r
+                nurbList = new ArrayList<Structure>();\r
+                nurbs.put(matNumber, nurbList);\r
+            }\r
+            nurbList.add(nurb);\r
+        }\r
+\r
+        //getting materials\r
+        MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);\r
+        Material[] materials = materialHelper.getMaterials(curveStructure, dataRepository);\r
+        if (materials == null) {\r
+            materials = new Material[]{dataRepository.getDefaultMaterial().clone()};\r
+        }\r
+        for (Material material : materials) {\r
+            material.getAdditionalRenderState().setFaceCullMode(FaceCullMode.Off);\r
+        }\r
+\r
+        //getting or creating bevel object\r
+        List<Geometry> bevelObject = null;\r
+        Pointer pBevelObject = (Pointer) curveStructure.getFieldValue("bevobj");\r
+        if (!pBevelObject.isNull()) {\r
+            Pointer pBevelStructure = (Pointer) pBevelObject.fetchData(dataRepository.getInputStream()).get(0).getFieldValue("data");\r
+            Structure bevelStructure = pBevelStructure.fetchData(dataRepository.getInputStream()).get(0);\r
+            bevelObject = this.toCurve(bevelStructure, dataRepository);\r
+        } else {\r
+            int bevResol = ((Number) curveStructure.getFieldValue("bevresol")).intValue();\r
+            float extrude = ((Number) curveStructure.getFieldValue("ext1")).floatValue();\r
+            float bevelDepth = ((Number) curveStructure.getFieldValue("ext2")).floatValue();\r
+            if (bevelDepth > 0.0f) {\r
+                float handlerLength = bevelDepth / 2.0f;\r
+\r
+                List<Vector3f> conrtolPoints = new ArrayList<Vector3f>(extrude > 0.0f ? 19 : 13);\r
+                conrtolPoints.add(new Vector3f(-bevelDepth, extrude, 0));\r
+                conrtolPoints.add(new Vector3f(-bevelDepth, handlerLength + extrude, 0));\r
+\r
+                conrtolPoints.add(new Vector3f(-handlerLength, bevelDepth + extrude, 0));\r
+                conrtolPoints.add(new Vector3f(0, bevelDepth + extrude, 0));\r
+                conrtolPoints.add(new Vector3f(handlerLength, bevelDepth + extrude, 0));\r
+\r
+                conrtolPoints.add(new Vector3f(bevelDepth, extrude + handlerLength, 0));\r
+                conrtolPoints.add(new Vector3f(bevelDepth, extrude, 0));\r
+                conrtolPoints.add(new Vector3f(bevelDepth, extrude - handlerLength, 0));\r
+\r
+                if (extrude > 0.0f) {\r
+                    conrtolPoints.add(new Vector3f(bevelDepth, -extrude + handlerLength, 0));\r
+                    conrtolPoints.add(new Vector3f(bevelDepth, -extrude, 0));\r
+                    conrtolPoints.add(new Vector3f(bevelDepth, -extrude - handlerLength, 0));\r
+                }\r
+\r
+                conrtolPoints.add(new Vector3f(handlerLength, -bevelDepth - extrude, 0));\r
+                conrtolPoints.add(new Vector3f(0, -bevelDepth - extrude, 0));\r
+                conrtolPoints.add(new Vector3f(-handlerLength, -bevelDepth - extrude, 0));\r
+\r
+                conrtolPoints.add(new Vector3f(-bevelDepth, -handlerLength - extrude, 0));\r
+                conrtolPoints.add(new Vector3f(-bevelDepth, -extrude, 0));\r
+\r
+                if (extrude > 0.0f) {\r
+                    conrtolPoints.add(new Vector3f(-bevelDepth, handlerLength - extrude, 0));\r
+\r
+                    conrtolPoints.add(new Vector3f(-bevelDepth, -handlerLength + extrude, 0));\r
+                    conrtolPoints.add(new Vector3f(-bevelDepth, extrude, 0));\r
+                }\r
+\r
+                Spline bevelSpline = new Spline(SplineType.Bezier, conrtolPoints, 0, false);\r
+                Curve bevelCurve = new Curve(bevelSpline, bevResol);\r
+                bevelObject = new ArrayList<Geometry>(1);\r
+                bevelObject.add(new Geometry("", bevelCurve));\r
+            } else if (extrude > 0.0f) {\r
+                Spline bevelSpline = new Spline(SplineType.Linear, new Vector3f[]{\r
+                            new Vector3f(0, extrude, 0), new Vector3f(0, -extrude, 0)\r
+                        }, 1, false);\r
+                Curve bevelCurve = new Curve(bevelSpline, bevResol);\r
+                bevelObject = new ArrayList<Geometry>(1);\r
+                bevelObject.add(new Geometry("", bevelCurve));\r
+            }\r
+        }\r
+\r
+        //getting taper object\r
+        Curve taperObject = null;\r
+        Pointer pTaperObject = (Pointer) curveStructure.getFieldValue("taperobj");\r
+        if (bevelObject != null && !pTaperObject.isNull()) {\r
+            Pointer pTaperStructure = (Pointer) pTaperObject.fetchData(dataRepository.getInputStream()).get(0).getFieldValue("data");\r
+            Structure taperStructure = pTaperStructure.fetchData(dataRepository.getInputStream()).get(0);\r
+            taperObject = this.loadTaperObject(taperStructure, dataRepository);\r
+        }\r
+\r
+        Vector3f loc = this.getLoc(curveStructure);\r
+        //creating the result curves\r
+        List<Geometry> result = new ArrayList<Geometry>(nurbs.size());\r
+        for (Entry<Number, List<Structure>> nurbEntry : nurbs.entrySet()) {\r
+            for (Structure nurb : nurbEntry.getValue()) {\r
+                int type = ((Number) nurb.getFieldValue("type")).intValue();\r
+                List<Geometry> nurbGeoms = null;\r
+                if ((type & 0x01) != 0) {//Bezier curve\r
+                    nurbGeoms = this.loadBezierCurve(loc, nurb, bevelObject, taperObject, dataRepository);\r
+                } else if ((type & 0x04) != 0) {//NURBS\r
+                    nurbGeoms = this.loadNurb(loc, nurb, bevelObject, taperObject, dataRepository);\r
+                }\r
+                if (nurbGeoms != null) {//setting the name and assigning materials\r
+                    for (Geometry nurbGeom : nurbGeoms) {\r
+                        nurbGeom.setMaterial(materials[nurbEntry.getKey().intValue()]);\r
+                        nurbGeom.setName(name);\r
+                        result.add(nurbGeom);\r
+                    }\r
+                }\r
+            }\r
+        }\r
+        return result;\r
+    }\r
+\r
+    /**\r
+     * This method loads the bezier curve.\r
+     * @param loc\r
+     *            the translation of the curve\r
+     * @param nurb\r
+     *            the nurb structure\r
+     * @param bevelObject\r
+     *            the bevel object\r
+     * @param taperObject\r
+     *            the taper object\r
+     * @param dataRepository\r
+     *            the data repository\r
+     * @return a list of geometries representing the curves\r
+     * @throws BlenderFileException\r
+     *             an exception is thrown when there are problems with the blender file\r
+     */\r
+    protected List<Geometry> loadBezierCurve(Vector3f loc, Structure nurb, List<Geometry> bevelObject, Curve taperObject,\r
+            DataRepository dataRepository) throws BlenderFileException {\r
+        Pointer pBezierTriple = (Pointer) nurb.getFieldValue("bezt");\r
+        List<Geometry> result = new ArrayList<Geometry>();\r
+        if (!pBezierTriple.isNull()) {\r
+            boolean smooth = (((Number) nurb.getFlatFieldValue("flag")).intValue() & 0x01) != 0;\r
+            int resolution = ((Number) nurb.getFieldValue("resolu")).intValue();\r
+            boolean cyclic = (((Number) nurb.getFieldValue("flagu")).intValue() & 0x01) != 0;\r
+\r
+            //creating the curve object\r
+            BezierCurve bezierCurve = new BezierCurve(0, pBezierTriple.fetchData(dataRepository.getInputStream()), 3);\r
+            List<Vector3f> controlPoints = bezierCurve.getControlPoints();\r
+            if (cyclic) {\r
+                //copy the first three points at the end\r
+                for (int i = 0; i < 3; ++i) {\r
+                    controlPoints.add(controlPoints.get(i));\r
+                }\r
+            }\r
+            //removing the first and last handles\r
+            controlPoints.remove(0);\r
+            controlPoints.remove(controlPoints.size() - 1);\r
+\r
+            //creating curve\r
+            Spline spline = new Spline(SplineType.Bezier, controlPoints, 0, false);\r
+            Curve curve = new Curve(spline, resolution);\r
+            if (bevelObject == null) {//creating a normal curve\r
+                Geometry curveGeometry = new Geometry(null, curve);\r
+                result.add(curveGeometry);\r
+                //TODO: use front and back flags; surface excluding algorithm for bezier circles should be added\r
+            } else {//creating curve with bevel and taper shape\r
+                result = this.applyBevelAndTaper(curve, bevelObject, taperObject, smooth, dataRepository);\r
+            }\r
+        }\r
+        return result;\r
+    }\r
+\r
+    /**\r
+     * This method loads the NURBS curve or surface.\r
+     * @param loc\r
+     *            object's location\r
+     * @param nurb\r
+     *            the NURBS data structure\r
+     * @param bevelObject\r
+     *            the bevel object to be applied\r
+     * @param taperObject\r
+     *            the taper object to be applied\r
+     * @param dataRepository\r
+     *            the data repository\r
+     * @return a list of geometries that represents the loaded NURBS curve or surface\r
+     * @throws BlenderFileException\r
+     *             an exception is throw when problems with blender loaded data occurs\r
+     */\r
+    @SuppressWarnings("unchecked")\r
+    protected List<Geometry> loadNurb(Vector3f loc, Structure nurb, List<Geometry> bevelObject, Curve taperObject,\r
+            DataRepository dataRepository) throws BlenderFileException {\r
+        //loading the knots\r
+        List<Float>[] knots = new List[2];\r
+        Pointer[] pKnots = new Pointer[]{(Pointer) nurb.getFieldValue("knotsu"), (Pointer) nurb.getFieldValue("knotsv")};\r
+        for (int i = 0; i < knots.length; ++i) {\r
+            if (!pKnots[i].isNull()) {\r
+                FileBlockHeader fileBlockHeader = dataRepository.getFileBlock(pKnots[i].getOldMemoryAddress());\r
+                BlenderInputStream blenderInputStream = dataRepository.getInputStream();\r
+                blenderInputStream.setPosition(fileBlockHeader.getBlockPosition());\r
+                int knotsAmount = fileBlockHeader.getCount() * fileBlockHeader.getSize() / 4;\r
+                knots[i] = new ArrayList<Float>(knotsAmount);\r
+                for (int j = 0; j < knotsAmount; ++j) {\r
+                    knots[i].add(Float.valueOf(blenderInputStream.readFloat()));\r
+                }\r
+            }\r
+        }\r
+\r
+        //loading the flags and orders (basis functions degrees)\r
+        int flagU = ((Number) nurb.getFieldValue("flagu")).intValue();\r
+        int flagV = ((Number) nurb.getFieldValue("flagv")).intValue();\r
+        int orderU = ((Number) nurb.getFieldValue("orderu")).intValue();\r
+        int orderV = ((Number) nurb.getFieldValue("orderv")).intValue();\r
+\r
+        //loading control points and their weights\r
+        int pntsU = ((Number) nurb.getFieldValue("pntsu")).intValue();\r
+        int pntsV = ((Number) nurb.getFieldValue("pntsv")).intValue();\r
+        List<Structure> bPoints = ((Pointer) nurb.getFieldValue("bp")).fetchData(dataRepository.getInputStream());\r
+        List<List<Vector4f>> controlPoints = new ArrayList<List<Vector4f>>(pntsV);\r
+        for (int i = 0; i < pntsV; ++i) {\r
+            List<Vector4f> uControlPoints = new ArrayList<Vector4f>(pntsU);\r
+            for (int j = 0; j < pntsU; ++j) {\r
+                DynamicArray<Float> vec = (DynamicArray<Float>) bPoints.get(j + i * pntsU).getFieldValue("vec");\r
+                if (fixUpAxis) {\r
+                    uControlPoints.add(new Vector4f(vec.get(0).floatValue(), vec.get(2).floatValue(), -vec.get(1).floatValue(), vec.get(3).floatValue()));\r
+                } else {\r
+                    uControlPoints.add(new Vector4f(vec.get(0).floatValue(), vec.get(1).floatValue(), vec.get(2).floatValue(), vec.get(3).floatValue()));\r
+                }\r
+            }\r
+            if ((flagU & 0x01) != 0) {\r
+                for (int k = 0; k < orderU - 1; ++k) {\r
+                    uControlPoints.add(uControlPoints.get(k));\r
+                }\r
+            }\r
+            controlPoints.add(uControlPoints);\r
+        }\r
+        if ((flagV & 0x01) != 0) {\r
+            for (int k = 0; k < orderV - 1; ++k) {\r
+                controlPoints.add(controlPoints.get(k));\r
+            }\r
+        }\r
+\r
+        int resolu = ((Number) nurb.getFieldValue("resolu")).intValue() + 1;\r
+        List<Geometry> result;\r
+        if (knots[1] == null) {//creating the curve\r
+            Spline nurbSpline = new Spline(controlPoints.get(0), knots[0]);\r
+            Curve nurbCurve = new Curve(nurbSpline, resolu);\r
+            if (bevelObject != null) {\r
+                result = this.applyBevelAndTaper(nurbCurve, bevelObject, taperObject, true, dataRepository);//TODO: smooth\r
+            } else {\r
+                result = new ArrayList<Geometry>(1);\r
+                Geometry nurbGeometry = new Geometry("", nurbCurve);\r
+                result.add(nurbGeometry);\r
+            }\r
+        } else {//creating the nurb surface\r
+            int resolv = ((Number) nurb.getFieldValue("resolv")).intValue() + 1;\r
+            Surface nurbSurface = Surface.createNurbsSurface(controlPoints, knots, resolu, resolv, orderU, orderV);\r
+            Geometry nurbGeometry = new Geometry("", nurbSurface);\r
+            result = new ArrayList<Geometry>(1);\r
+            result.add(nurbGeometry);\r
+        }\r
+        return result;\r
+    }\r
+\r
+    /**\r
+     * This method returns the taper scale that should be applied to the object.\r
+     * @param taperPoints\r
+     *            the taper points\r
+     * @param taperLength\r
+     *            the taper curve length\r
+     * @param percent\r
+     *            the percent of way along the whole taper curve\r
+     * @param store\r
+     *            the vector where the result will be stored\r
+     */\r
+    protected float getTaperScale(float[] taperPoints, float taperLength, float percent) {\r
+        float length = taperLength * percent;\r
+        float currentLength = 0;\r
+        Vector3f p = new Vector3f();\r
+        int i;\r
+        for (i = 0; i < taperPoints.length - 6 && currentLength < length; i += 3) {\r
+            p.set(taperPoints[i], taperPoints[i + 1], taperPoints[i + 2]);\r
+            p.subtractLocal(taperPoints[i + 3], taperPoints[i + 4], taperPoints[i + 5]);\r
+            currentLength += p.length();\r
+        }\r
+        currentLength -= p.length();\r
+        float leftLength = length - currentLength;\r
+        float percentOnSegment = p.length() == 0 ? 0 : leftLength / p.length();\r
+        Vector3f store = FastMath.interpolateLinear(percentOnSegment,\r
+                new Vector3f(taperPoints[i], taperPoints[i + 1], taperPoints[i + 2]),\r
+                new Vector3f(taperPoints[i + 3], taperPoints[i + 4], taperPoints[i + 5]));\r
+        return store.y;\r
+    }\r
+\r
+    /**\r
+     * This method applies bevel and taper objects to the curve.\r
+     * @param curve\r
+     *            the curve we apply the objects to\r
+     * @param bevelObject\r
+     *            the bevel object\r
+     * @param taperObject\r
+     *            the taper object\r
+     * @param smooth\r
+     *                           the smooth flag\r
+     * @param dataRepository\r
+     *            the data repository\r
+     * @return a list of geometries representing the beveled and/or tapered curve\r
+     */\r
+    protected List<Geometry> applyBevelAndTaper(Curve curve, List<Geometry> bevelObject, Curve taperObject,\r
+            boolean smooth, DataRepository dataRepository) {\r
+        float[] curvePoints = BufferUtils.getFloatArray(curve.getFloatBuffer(Type.Position));\r
+        MeshHelper meshHelper = dataRepository.getHelper(MeshHelper.class);\r
+        float curveLength = curve.getLength();\r
+        //TODO: use the smooth var\r
+\r
+        //taper data\r
+        float[] taperPoints = null;\r
+        float taperLength = 0;\r
+        if (taperObject != null) {\r
+            taperPoints = BufferUtils.getFloatArray(taperObject.getFloatBuffer(Type.Position));\r
+            taperLength = taperObject.getLength();\r
+        }\r
+\r
+        //several objects can be allocated only once\r
+        Vector3f p = new Vector3f();\r
+        Vector3f z = new Vector3f(0, 0, 1);\r
+        Vector3f negativeY = new Vector3f(0, -1, 0);\r
+        Matrix4f m = new Matrix4f();\r
+        float lengthAlongCurve = 0, taperScale = 1.0f;\r
+        Quaternion planeRotation = new Quaternion();\r
+        Quaternion zRotation = new Quaternion();\r
+        float[] temp = new float[]{0, 0, 0, 1};\r
+        Map<Vector3f, Vector3f> normalMap = new HashMap<Vector3f, Vector3f>();//normalMap merges normals of faces that will be rendered smooth\r
+\r
+        FloatBuffer[] vertexBuffers = new FloatBuffer[bevelObject.size()];\r
+        FloatBuffer[] normalBuffers = new FloatBuffer[bevelObject.size()];\r
+        IntBuffer[] indexBuffers = new IntBuffer[bevelObject.size()];\r
+        for (int geomIndex = 0; geomIndex < bevelObject.size(); ++geomIndex) {\r
+            Mesh mesh = bevelObject.get(geomIndex).getMesh();\r
+            FloatBuffer positions = mesh.getFloatBuffer(Type.Position);\r
+            float[] vertices = BufferUtils.getFloatArray(positions);\r
+\r
+            for (int i = 0; i < curvePoints.length; i += 3) {\r
+                p.set(curvePoints[i], curvePoints[i + 1], curvePoints[i + 2]);\r
+                Vector3f v;\r
+                if (i == 0) {\r
+                    v = new Vector3f(curvePoints[3] - p.x, curvePoints[4] - p.y, curvePoints[5] - p.z);\r
+                } else if (i + 3 >= curvePoints.length) {\r
+                    v = new Vector3f(p.x - curvePoints[i - 3], p.y - curvePoints[i - 2], p.z - curvePoints[i - 1]);\r
+                    lengthAlongCurve += v.length();\r
+                } else {\r
+                    v = new Vector3f(curvePoints[i + 3] - curvePoints[i - 3],\r
+                            curvePoints[i + 4] - curvePoints[i - 2],\r
+                            curvePoints[i + 5] - curvePoints[i - 1]);\r
+                    lengthAlongCurve += new Vector3f(curvePoints[i + 3] - p.x, curvePoints[i + 4] - p.y, curvePoints[i + 5] - p.z).length();\r
+                }\r
+                v.normalizeLocal();\r
+\r
+                float angle = FastMath.acos(v.dot(z));\r
+                v.crossLocal(z).normalizeLocal();//v is the rotation axis now\r
+                planeRotation.fromAngleAxis(angle, v);\r
+\r
+                Vector3f zAxisRotationVector = negativeY.cross(v).normalizeLocal();\r
+                float zAxisRotationAngle = FastMath.acos(negativeY.dot(v));\r
+                zRotation.fromAngleAxis(zAxisRotationAngle, zAxisRotationVector);\r
+\r
+                //point transformation matrix\r
+                if (taperPoints != null) {\r
+                    taperScale = this.getTaperScale(taperPoints, taperLength, lengthAlongCurve / curveLength);\r
+                }\r
+                m.set(Matrix4f.IDENTITY);\r
+                m.setRotationQuaternion(planeRotation.multLocal(zRotation));\r
+                m.setTranslation(p);\r
+\r
+                //these vertices need to be thrown on XY plane\r
+                //and moved to the origin of [p1.x, p1.y] on the plane\r
+                Vector3f[] verts = new Vector3f[vertices.length / 3];\r
+                for (int j = 0; j < verts.length; ++j) {\r
+                    temp[0] = vertices[j * 3] * taperScale;\r
+                    temp[1] = vertices[j * 3 + 1] * taperScale;\r
+                    temp[2] = 0;\r
+                    m.mult(temp);//the result is stored in the array\r
+                    if (fixUpAxis) {\r
+                        verts[j] = new Vector3f(temp[0], temp[1], temp[2]);\r
+                    } else {\r
+                        verts[j] = new Vector3f(temp[0], temp[2], -temp[1]);\r
+                    }\r
+                }\r
+                if (vertexBuffers[geomIndex] == null) {\r
+                    vertexBuffers[geomIndex] = BufferUtils.createFloatBuffer(verts.length * curvePoints.length);\r
+                }\r
+                FloatBuffer buffer = BufferUtils.createFloatBuffer(verts);\r
+                vertexBuffers[geomIndex].put(buffer);\r
+\r
+                //adding indexes\r
+                IntBuffer indexBuffer = indexBuffers[geomIndex];\r
+                if (indexBuffer == null) {\r
+                    //the amount of faces in the final mesh is the amount of edges in the bevel curve\r
+                    //(which is less by 1 than its number of vertices)\r
+                    //multiplied by 2 (because each edge has two faces assigned on both sides)\r
+                    //and multiplied by the amount of bevel curve repeats which is equal to the amount of vertices on the target curve\r
+                    //finally we need to subtract the bevel edges amount 2 times because the border edges have only one face attached\r
+                    //and at last multiply everything by 3 because each face needs 3 indexes to be described\r
+                    int bevelCurveEdgesAmount = verts.length - 1;\r
+                    indexBuffer = BufferUtils.createIntBuffer(((bevelCurveEdgesAmount << 1) * curvePoints.length - bevelCurveEdgesAmount << 1) * 3);\r
+                    indexBuffers[geomIndex] = indexBuffer;\r
+                }\r
+                int pointOffset = i / 3 * verts.length;\r
+                if (i + 3 < curvePoints.length) {\r
+                    for (int index = 0; index < verts.length - 1; ++index) {\r
+                        indexBuffer.put(index + pointOffset);\r
+                        indexBuffer.put(index + pointOffset + 1);\r
+                        indexBuffer.put(verts.length + index + pointOffset);\r
+                        indexBuffer.put(verts.length + index + pointOffset);\r
+                        indexBuffer.put(index + pointOffset + 1);\r
+                        indexBuffer.put(verts.length + index + pointOffset + 1);\r
+                    }\r
+                }\r
+            }\r
+        }\r
+\r
+        //calculating the normals\r
+        for (int geomIndex = 0; geomIndex < bevelObject.size(); ++geomIndex) {\r
+            Vector3f[] allVerts = BufferUtils.getVector3Array(vertexBuffers[geomIndex]);\r
+            int[] allIndices = BufferUtils.getIntArray(indexBuffers[geomIndex]);\r
+            for (int i = 0; i < allIndices.length - 3; i += 3) {\r
+                Vector3f n = FastMath.computeNormal(allVerts[allIndices[i]], allVerts[allIndices[i + 1]], allVerts[allIndices[i + 2]]);\r
+                meshHelper.addNormal(n, normalMap, smooth, allVerts[allIndices[i]], allVerts[allIndices[i + 1]], allVerts[allIndices[i + 2]]);\r
+            }\r
+            if (normalBuffers[geomIndex] == null) {\r
+                normalBuffers[geomIndex] = BufferUtils.createFloatBuffer(allVerts.length * 3);\r
+            }\r
+            for (Vector3f v : allVerts) {\r
+                Vector3f n = normalMap.get(v);\r
+                normalBuffers[geomIndex].put(n.x);\r
+                normalBuffers[geomIndex].put(n.y);\r
+                normalBuffers[geomIndex].put(n.z);\r
+            }\r
+        }\r
+\r
+        List<Geometry> result = new ArrayList<Geometry>(vertexBuffers.length);\r
+        for (int i = 0; i < vertexBuffers.length; ++i) {\r
+            Mesh mesh = new Mesh();\r
+            mesh.setBuffer(Type.Position, 3, vertexBuffers[i]);\r
+            mesh.setBuffer(Type.Index, 3, indexBuffers[i]);\r
+            mesh.setBuffer(Type.Normal, 3, normalBuffers[i]);\r
+            Geometry g = new Geometry("g" + i, mesh);\r
+            g.updateModelBound();\r
+            result.add(g);\r
+        }\r
+\r
+        return result;\r
+    }\r
+\r
+    /**\r
+     * This method loads the taper object.\r
+     * @param taperStructure\r
+     *            the taper structure\r
+     * @param dataRepository\r
+     *            the data repository\r
+     * @return the taper object\r
+     * @throws BlenderFileException\r
+     */\r
+    protected Curve loadTaperObject(Structure taperStructure, DataRepository dataRepository) throws BlenderFileException {\r
+        //reading nurbs\r
+        List<Structure> nurbStructures = ((Structure) taperStructure.getFieldValue("nurb")).evaluateListBase(dataRepository);\r
+        for (Structure nurb : nurbStructures) {\r
+            Pointer pBezierTriple = (Pointer) nurb.getFieldValue("bezt");\r
+            if (!pBezierTriple.isNull()) {\r
+                //creating the curve object\r
+                BezierCurve bezierCurve = new BezierCurve(0, pBezierTriple.fetchData(dataRepository.getInputStream()), 3);\r
+                List<Vector3f> controlPoints = bezierCurve.getControlPoints();\r
+                //removing the first and last handles\r
+                controlPoints.remove(0);\r
+                controlPoints.remove(controlPoints.size() - 1);\r
+\r
+                //return the first taper curve that has more than 3 control points\r
+                if (controlPoints.size() > 3) {\r
+                    Spline spline = new Spline(SplineType.Bezier, controlPoints, 0, false);\r
+                    int resolution = ((Number) taperStructure.getFieldValue("resolu")).intValue();\r
+                    return new Curve(spline, resolution);\r
+                }\r
+            }\r
+        }\r
+        return null;\r
+    }\r
+\r
+    /**\r
+     * This method returns the translation of the curve. The UP axis is taken into account here.\r
+     * @param curveStructure\r
+     *            the curve structure\r
+     * @return curve translation\r
+     */\r
+    @SuppressWarnings("unchecked")\r
+    protected Vector3f getLoc(Structure curveStructure) {\r
+        DynamicArray<Number> locArray = (DynamicArray<Number>) curveStructure.getFieldValue("loc");\r
+        if (fixUpAxis) {\r
+            return new Vector3f(locArray.get(0).floatValue(), locArray.get(1).floatValue(), -locArray.get(2).floatValue());\r
+        } else {\r
+            return new Vector3f(locArray.get(0).floatValue(), locArray.get(2).floatValue(), locArray.get(1).floatValue());\r
+        }\r
+    }\r
 }\r
index 1a6eacd..280299e 100644 (file)
@@ -17,98 +17,98 @@ import com.jme3.scene.plugins.blender.utils.Pointer;
  * @author Marcin Roguski\r
  */\r
 public class IpoHelper extends AbstractBlenderHelper {\r
-       /**\r
-        * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
-        * different blender versions.\r
-        * @param blenderVersion\r
-        *        the version read from the blend file\r
-        */\r
-       public IpoHelper(String blenderVersion) {\r
-               super(blenderVersion);\r
-       }\r
 \r
-       /**\r
-        * This method creates an ipo object used for interpolation calculations.\r
-        * @param ipoStructure\r
-        *        the structure with ipo definition\r
-        * @param dataRepository\r
-        *        the data repository\r
-        * @return the ipo object\r
-        * @throws BlenderFileException\r
-        *         this exception is thrown when the blender file is somehow corrupted\r
-        */\r
-       public Ipo createIpo(Structure ipoStructure, DataRepository dataRepository) throws BlenderFileException {\r
-               Structure curvebase = (Structure)ipoStructure.getFieldValue("curve");\r
+    /**\r
+     * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
+     * different blender versions.\r
+     * @param blenderVersion\r
+     *        the version read from the blend file\r
+     */\r
+    public IpoHelper(String blenderVersion) {\r
+        super(blenderVersion);\r
+    }\r
 \r
-               //preparing bezier curves\r
-               Ipo result = null;\r
-               List<Structure> curves = curvebase.evaluateListBase(dataRepository);//IpoCurve\r
-               if(curves.size() > 0) {\r
-                       BezierCurve[] bezierCurves = new BezierCurve[curves.size()];\r
-                       int frame = 0;\r
-                       for(Structure curve : curves) {\r
-                               Pointer pBezTriple = (Pointer)curve.getFieldValue("bezt");\r
-                               List<Structure> bezTriples = pBezTriple.fetchData(dataRepository.getInputStream());\r
-                               int type = ((Number)curve.getFieldValue("adrcode")).intValue();\r
-                               bezierCurves[frame++] = new BezierCurve(type, bezTriples, 2);\r
-                       }\r
-                       curves.clear();\r
-                       result = new Ipo(bezierCurves);\r
-                       dataRepository.addLoadedFeatures(ipoStructure.getOldMemoryAddress(), ipoStructure.getName(), ipoStructure, result);\r
-               }\r
-               return result;\r
-       }\r
+    /**\r
+     * This method creates an ipo object used for interpolation calculations.\r
+     * @param ipoStructure\r
+     *        the structure with ipo definition\r
+     * @param dataRepository\r
+     *        the data repository\r
+     * @return the ipo object\r
+     * @throws BlenderFileException\r
+     *         this exception is thrown when the blender file is somehow corrupted\r
+     */\r
+    public Ipo createIpo(Structure ipoStructure, DataRepository dataRepository) throws BlenderFileException {\r
+        Structure curvebase = (Structure) ipoStructure.getFieldValue("curve");\r
 \r
-       /**\r
-        * This method creates an ipo with only a single value. No track type is specified so do not use it for calculating\r
-        * tracks.\r
-        * @param constValue\r
-        *        the value of this ipo\r
-        * @return constant ipo\r
-        */\r
-       public Ipo createIpo(float constValue) {\r
-               return new ConstIpo(constValue);\r
-       }\r
+        //preparing bezier curves\r
+        Ipo result = null;\r
+        List<Structure> curves = curvebase.evaluateListBase(dataRepository);//IpoCurve\r
+        if (curves.size() > 0) {\r
+            BezierCurve[] bezierCurves = new BezierCurve[curves.size()];\r
+            int frame = 0;\r
+            for (Structure curve : curves) {\r
+                Pointer pBezTriple = (Pointer) curve.getFieldValue("bezt");\r
+                List<Structure> bezTriples = pBezTriple.fetchData(dataRepository.getInputStream());\r
+                int type = ((Number) curve.getFieldValue("adrcode")).intValue();\r
+                bezierCurves[frame++] = new BezierCurve(type, bezTriples, 2);\r
+            }\r
+            curves.clear();\r
+            result = new Ipo(bezierCurves);\r
+            dataRepository.addLoadedFeatures(ipoStructure.getOldMemoryAddress(), ipoStructure.getName(), ipoStructure, result);\r
+        }\r
+        return result;\r
+    }\r
 \r
-       \r
+    /**\r
+     * This method creates an ipo with only a single value. No track type is specified so do not use it for calculating\r
+     * tracks.\r
+     * @param constValue\r
+     *        the value of this ipo\r
+     * @return constant ipo\r
+     */\r
+    public Ipo createIpo(float constValue) {\r
+        return new ConstIpo(constValue);\r
+    }\r
 \r
-       /**\r
-        * Ipo constant curve. This is a curve with only one value and no specified type. This type of ipo cannot be used to\r
-        * calculate tracks. It should only be used to calculate single value for a given frame.\r
-        * @author Marcin Roguski\r
-        */\r
-       private class ConstIpo extends Ipo {\r
-               /** The constant value of this ipo. */\r
-               private float   constValue;\r
+    /**\r
+     * Ipo constant curve. This is a curve with only one value and no specified type. This type of ipo cannot be used to\r
+     * calculate tracks. It should only be used to calculate single value for a given frame.\r
+     * @author Marcin Roguski\r
+     */\r
+    private class ConstIpo extends Ipo {\r
 \r
-               /**\r
-                * Constructor. Stores the constant value of this ipo.\r
-                * @param constValue\r
-                *        the constant value of this ipo\r
-                */\r
-               public ConstIpo(float constValue) {\r
-                       super(null);\r
-                       this.constValue = constValue;\r
-               }\r
+        /** The constant value of this ipo. */\r
+        private float constValue;\r
 \r
-               @Override\r
-               public float calculateValue(int frame) {\r
-                       return constValue;\r
-               }\r
+        /**\r
+         * Constructor. Stores the constant value of this ipo.\r
+         * @param constValue\r
+         *        the constant value of this ipo\r
+         */\r
+        public ConstIpo(float constValue) {\r
+            super(null);\r
+            this.constValue = constValue;\r
+        }\r
 \r
-               @Override\r
-               public float calculateValue(int frame, int curveIndex) {\r
-                       return constValue;\r
-               }\r
+        @Override\r
+        public float calculateValue(int frame) {\r
+            return constValue;\r
+        }\r
 \r
-               @Override\r
-               public int getCurvesAmount() {\r
-                       return 0;\r
-               }\r
-               \r
-               @Override\r
-               public BoneTrack calculateTrack(int boneIndex, int startFrame, int stopFrame, int fps) {\r
-                       throw new IllegalStateException("Constatnt ipo object cannot be used for calculating bone tracks!");\r
-               }\r
-       }\r
+        @Override\r
+        public float calculateValue(int frame, int curveIndex) {\r
+            return constValue;\r
+        }\r
+\r
+        @Override\r
+        public int getCurvesAmount() {\r
+            return 0;\r
+        }\r
+\r
+        @Override\r
+        public BoneTrack calculateTrack(int boneIndex, int startFrame, int stopFrame, int fps) {\r
+            throw new IllegalStateException("Constatnt ipo object cannot be used for calculating bone tracks!");\r
+        }\r
+    }\r
 }\r
index ce9da9f..9587890 100644 (file)
@@ -49,51 +49,52 @@ import com.jme3.scene.plugins.blender.utils.DataRepository.LoadedFeatureDataType
  * @author Marcin Roguski\r
  */\r
 public class LightHelper extends AbstractBlenderHelper {\r
-       private static final Logger                     LOGGER          = Logger.getLogger(LightHelper.class.getName());\r
-       \r
-       /**\r
-        * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
-        * different blender versions.\r
-        * @param blenderVersion\r
-        *        the version read from the blend file\r
-        */\r
-       public LightHelper(String blenderVersion) {\r
-               super(blenderVersion);\r
-       }\r
 \r
-       public Light toLight(Structure structure, DataRepository dataRepository) throws BlenderFileException {\r
-               Light result = (Light)dataRepository.getLoadedFeature(structure.getOldMemoryAddress(), LoadedFeatureDataType.LOADED_FEATURE);\r
-               if(result != null) {\r
-                       return result;\r
-               }\r
-               int type = ((Number)structure.getFieldValue("type")).intValue();\r
-               switch(type) {\r
-                       case 0://Lamp\r
-                               result = new PointLight();\r
-                               float distance = ((Number)structure.getFieldValue("dist")).floatValue();\r
-                               ((PointLight)result).setRadius(distance);\r
-                               break;\r
-                       case 1://Sun\r
-                               LOGGER.log(Level.WARNING, "'Sun' lamp is not supported in jMonkeyEngine.");\r
-                               break;\r
-                       case 2://Spot\r
-                               LOGGER.log(Level.WARNING, "'Spot' lamp is not supported in jMonkeyEngine.");\r
-                               break;\r
-                       case 3://Hemi\r
-                               LOGGER.log(Level.WARNING, "'Hemi' lamp is not supported in jMonkeyEngine.");\r
-                               break;\r
-                       case 4://Area\r
-                               result = new DirectionalLight();\r
-                               break;\r
-                       default:\r
-                               throw new BlenderFileException("Unknown light source type: " + type);\r
-               }\r
-               if(result != null) {\r
-                       float r = ((Number)structure.getFieldValue("r")).floatValue();\r
-                       float g = ((Number)structure.getFieldValue("g")).floatValue();\r
-                       float b = ((Number)structure.getFieldValue("b")).floatValue();\r
-                       result.setColor(new ColorRGBA(r, g, b, 0.0f));//TODO: 0 czy 1 ???\r
-               }\r
-               return result;\r
-       }\r
+    private static final Logger LOGGER = Logger.getLogger(LightHelper.class.getName());\r
+\r
+    /**\r
+     * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
+     * different blender versions.\r
+     * @param blenderVersion\r
+     *        the version read from the blend file\r
+     */\r
+    public LightHelper(String blenderVersion) {\r
+        super(blenderVersion);\r
+    }\r
+\r
+    public Light toLight(Structure structure, DataRepository dataRepository) throws BlenderFileException {\r
+        Light result = (Light) dataRepository.getLoadedFeature(structure.getOldMemoryAddress(), LoadedFeatureDataType.LOADED_FEATURE);\r
+        if (result != null) {\r
+            return result;\r
+        }\r
+        int type = ((Number) structure.getFieldValue("type")).intValue();\r
+        switch (type) {\r
+            case 0://Lamp\r
+                result = new PointLight();\r
+                float distance = ((Number) structure.getFieldValue("dist")).floatValue();\r
+                ((PointLight) result).setRadius(distance);\r
+                break;\r
+            case 1://Sun\r
+                LOGGER.log(Level.WARNING, "'Sun' lamp is not supported in jMonkeyEngine.");\r
+                break;\r
+            case 2://Spot\r
+                LOGGER.log(Level.WARNING, "'Spot' lamp is not supported in jMonkeyEngine.");\r
+                break;\r
+            case 3://Hemi\r
+                LOGGER.log(Level.WARNING, "'Hemi' lamp is not supported in jMonkeyEngine.");\r
+                break;\r
+            case 4://Area\r
+                result = new DirectionalLight();\r
+                break;\r
+            default:\r
+                throw new BlenderFileException("Unknown light source type: " + type);\r
+        }\r
+        if (result != null) {\r
+            float r = ((Number) structure.getFieldValue("r")).floatValue();\r
+            float g = ((Number) structure.getFieldValue("g")).floatValue();\r
+            float b = ((Number) structure.getFieldValue("b")).floatValue();\r
+            result.setColor(new ColorRGBA(r, g, b, 0.0f));//TODO: 0 czy 1 ???\r
+        }\r
+        return result;\r
+    }\r
 }\r
index c2882b9..bbe107a 100644 (file)
@@ -62,640 +62,646 @@ import com.jme3.texture.Texture.WrapMode;
 import com.jme3.util.BufferUtils;\r
 \r
 public class MaterialHelper extends AbstractBlenderHelper {\r
-       private static final Logger                                     LOGGER                                  = Logger.getLogger(MaterialHelper.class.getName());\r
-       protected static final float                            DEFAULT_SHININESS               = 20.0f;\r
-\r
-       public static final String                                      TEXTURE_TYPE_COLOR              = "ColorMap";\r
-       public static final String                                      TEXTURE_TYPE_DIFFUSE    = "DiffuseMap";\r
-       public static final String                                      TEXTURE_TYPE_NORMAL             = "NormalMap";\r
-       public static final String                                      TEXTURE_TYPE_SPECULAR   = "SpecularMap";\r
-       public static final String                                      TEXTURE_TYPE_GLOW               = "GlowMap";\r
-       public static final String                                      TEXTURE_TYPE_ALPHA              = "AlphaMap";\r
-\r
-       public static final Integer                                     ALPHA_MASK_NONE                 = Integer.valueOf(0);\r
-       public static final Integer                                     ALPHA_MASK_CIRCLE               = Integer.valueOf(1);\r
-       public static final Integer                                     ALPHA_MASK_CONE                 = Integer.valueOf(2);\r
-       public static final Integer                                     ALPHA_MASK_HYPERBOLE    = Integer.valueOf(3);\r
-       protected final Map<Integer, IAlphaMask>        alphaMasks                              = new HashMap<Integer, IAlphaMask>();\r
-\r
-       /**\r
-        * The type of the material's diffuse shader.\r
-        */\r
-       public static enum DiffuseShader {\r
-               LAMBERT, ORENNAYAR, TOON, MINNAERT, FRESNEL\r
-       }\r
-\r
-       /**\r
-        * The type of the material's specular shader.\r
-        */\r
-       public static enum SpecularShader {\r
-               COOKTORRENCE, PHONG, BLINN, TOON, WARDISO\r
-       }\r
-\r
-       /** Face cull mode. Should be excplicitly set before this helper is used. */\r
-       protected FaceCullMode  faceCullMode;\r
-\r
-       /**\r
-        * This constructor parses the given blender version and stores the result. Some functionalities may differ in different blender\r
-        * versions.\r
-        * \r
-        * @param blenderVersion\r
-        *        the version read from the blend file\r
-        */\r
-       public MaterialHelper(String blenderVersion) {\r
-               super(blenderVersion);\r
-               // setting alpha masks\r
-               alphaMasks.put(ALPHA_MASK_NONE, new IAlphaMask() {\r
-                       @Override\r
-                       public void setImageSize(int width, int height) {}\r
-\r
-                       @Override\r
-                       public byte getAlpha(float x, float y) {\r
-                               return (byte) 255;\r
-                       }\r
-               });\r
-               alphaMasks.put(ALPHA_MASK_CIRCLE, new IAlphaMask() {\r
-                       private float   r;\r
-                       private float[] center;\r
-\r
-                       @Override\r
-                       public void setImageSize(int width, int height) {\r
-                               r = Math.min(width, height) * 0.5f;\r
-                               center = new float[] { width * 0.5f, height * 0.5f };\r
-                       }\r
-\r
-                       @Override\r
-                       public byte getAlpha(float x, float y) {\r
-                               float d = FastMath.abs(FastMath.sqrt((x - center[0]) * (x - center[0]) + (y - center[1]) * (y - center[1])));\r
-                               return (byte) (d >= r ? 0 : 255);\r
-                       }\r
-               });\r
-               alphaMasks.put(ALPHA_MASK_CONE, new IAlphaMask() {\r
-                       private float   r;\r
-                       private float[] center;\r
-\r
-                       @Override\r
-                       public void setImageSize(int width, int height) {\r
-                               r = Math.min(width, height) * 0.5f;\r
-                               center = new float[] { width * 0.5f, height * 0.5f };\r
-                       }\r
-\r
-                       @Override\r
-                       public byte getAlpha(float x, float y) {\r
-                               float d = FastMath.abs(FastMath.sqrt((x - center[0]) * (x - center[0]) + (y - center[1]) * (y - center[1])));\r
-                               return (byte) (d >= r ? 0 : -255.0f * d / r + 255.0f);\r
-                       }\r
-               });\r
-               alphaMasks.put(ALPHA_MASK_HYPERBOLE, new IAlphaMask() {\r
-                       private float   r;\r
-                       private float[] center;\r
-\r
-                       @Override\r
-                       public void setImageSize(int width, int height) {\r
-                               r = Math.min(width, height) * 0.5f;\r
-                               center = new float[] { width * 0.5f, height * 0.5f };\r
-                       }\r
-\r
-                       @Override\r
-                       public byte getAlpha(float x, float y) {\r
-                               float d = FastMath.abs(FastMath.sqrt((x - center[0]) * (x - center[0]) + (y - center[1]) * (y - center[1]))) / r;\r
-                               return d >= 1.0f ? 0 : (byte) ((-FastMath.sqrt((2.0f - d) * d) + 1.0f) * 255.0f);\r
-                       }\r
-               });\r
-       }\r
-\r
-       /**\r
-        * This method sets the face cull mode to be used with every loaded material.\r
-        * \r
-        * @param faceCullMode\r
-        *        the face cull mode\r
-        */\r
-       public void setFaceCullMode(FaceCullMode faceCullMode) {\r
-               this.faceCullMode = faceCullMode;\r
-       }\r
-\r
-       @SuppressWarnings("unchecked")\r
-       public Material toMaterial(Structure structure, DataRepository dataRepository) throws BlenderFileException {\r
-               LOGGER.log(Level.INFO, "Loading material.");\r
-               if (structure == null) {\r
-                       return dataRepository.getDefaultMaterial();\r
-               }\r
-               Material result = (Material) dataRepository.getLoadedFeature(structure.getOldMemoryAddress(), LoadedFeatureDataType.LOADED_FEATURE);\r
-               if (result != null) {\r
-                       return result;\r
-               }\r
-\r
-               int mode = ((Number) structure.getFieldValue("mode")).intValue();\r
-               boolean shadeless = (mode & 0x4) != 0;\r
-               boolean vertexColor = (mode & 0x16) != 0;\r
-               boolean transparent = (mode & 0x64) != 0;\r
-\r
-               if (shadeless) {\r
-                       result = new Material(dataRepository.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");\r
-               } else {\r
-                       result = new Material(dataRepository.getAssetManager(), "Common/MatDefs/Light/Lighting.j3md");\r
-               }\r
-\r
-               result.getAdditionalRenderState().setFaceCullMode(faceCullMode);\r
-\r
-               if (transparent) {\r
-                       result.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);\r
-               }\r
-\r
-               String name = structure.getName();\r
-               LOGGER.log(Level.INFO, "Material's name: {0}", name);\r
-               if (vertexColor) {\r
-                       if (shadeless) {\r
-                               result.setBoolean("VertexColor", true);\r
-                       } else {\r
-                               result.setBoolean("UseVertexColor", true);\r
-                       }\r
-               }\r
-\r
-               MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);\r
-               ColorRGBA diffuseColor = null;\r
-               if (shadeless) {\r
-                       // color of shadeless? doesn't seem to work in blender ..\r
-               } else {\r
-                       result.setBoolean("UseMaterialColors", true);\r
-\r
-                       // setting the colors\r
-                       DiffuseShader diffuseShader = materialHelper.getDiffuseShader(structure);\r
-                       result.setBoolean("Minnaert", diffuseShader == DiffuseShader.MINNAERT);\r
-                       diffuseColor = materialHelper.getDiffuseColor(structure, diffuseShader);\r
-                       result.setColor("Diffuse", diffuseColor);\r
-\r
-                       SpecularShader specularShader = materialHelper.getSpecularShader(structure);\r
-                       result.setBoolean("WardIso", specularShader == SpecularShader.WARDISO);\r
-                       result.setColor("Specular", materialHelper.getSpecularColor(structure, specularShader));\r
-\r
-                       result.setColor("Ambient", materialHelper.getAmbientColor(structure));\r
-                       result.setFloat("Shininess", materialHelper.getShininess(structure));\r
-               }\r
-\r
-               // texture\r
-               if ((dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.TEXTURES) != 0) {\r
-                       TextureHelper textureHelper = dataRepository.getHelper(TextureHelper.class);\r
-                       DynamicArray<Pointer> mtexs = (DynamicArray<Pointer>) structure.getFieldValue("mtex");\r
-                       for (int i = 0; i < mtexs.getTotalSize(); ++i) {\r
-                               Pointer p = mtexs.get(i);\r
-                               if (!p.isNull()) {\r
-                                       List<Structure> mtex = p.fetchData(dataRepository.getInputStream());\r
-                                       if (mtex.size() == 1) {\r
-                                               Structure textureLink = mtex.get(0);\r
-                                               int texflag = ((Number) textureLink.getFieldValue("texflag")).intValue();\r
-                                               // int texco = ((Number) textureLink.getFieldValue("texco")).intValue();\r
-                                               boolean negateTexture = (texflag & 0x04) == 0;\r
-\r
-                                               // if(texco == 0x10) {//TEXCO_UV (this is only supported now)\r
-                                               int mapto = ((Number) textureLink.getFieldValue("mapto")).intValue();\r
-                                               if (mapto != 0) {\r
-                                                       Pointer pTex = (Pointer) textureLink.getFieldValue("tex");\r
-                                                       Structure tex = pTex.fetchData(dataRepository.getInputStream()).get(0);\r
-                                                       Texture texture = textureHelper.getTexture(tex, dataRepository);\r
-                                                       if (texture != null) {\r
-                                                               if ((mapto & 0x01) != 0) {// Col\r
-                                                                       result.setBoolean("UseMaterialColors", Boolean.FALSE);\r
-                                                                       // blending the texture with material color and texture's defined color\r
-                                                                       int blendType = ((Number) textureLink.getFieldValue("blendtype")).intValue();\r
-                                                                       float[] color = new float[] { ((Number) textureLink.getFieldValue("r")).floatValue(), ((Number) textureLink.getFieldValue("g")).floatValue(), ((Number) textureLink.getFieldValue("b")).floatValue() };\r
-                                                                       float colfac = ((Number) textureLink.getFieldValue("colfac")).floatValue();\r
-                                                                       texture = textureHelper.blendTexture(diffuseColor.getColorArray(), texture, color, colfac, blendType, negateTexture, dataRepository);\r
-                                                                       texture.setWrap(WrapMode.Repeat);\r
-                                                                       if (shadeless) {\r
-                                                                               result.setTexture(TEXTURE_TYPE_COLOR, texture);\r
-                                                                       } else {\r
-                                                                               result.setTexture(TEXTURE_TYPE_DIFFUSE, texture);\r
-                                                                       }\r
-                                                               }\r
-                                                               if ((mapto & 0x02) != 0) {// Nor\r
-                                                                       result.setTexture(TEXTURE_TYPE_NORMAL, texture);\r
-                                                               }\r
-                                                               if ((mapto & 0x20) != 0) {// Spec\r
-                                                                       result.setTexture(TEXTURE_TYPE_SPECULAR, texture);\r
-                                                               }\r
-                                                               if ((mapto & 0x40) != 0) {// Emit\r
-                                                                       result.setTexture(TEXTURE_TYPE_GLOW, texture);\r
-                                                               }\r
-                                                               if ((mapto & 0x80) != 0) {// Alpha\r
-                                                                       result.setTexture(TEXTURE_TYPE_ALPHA, texture);\r
-                                                               }\r
-                                                       } else {\r
-                                                               LOGGER.log(Level.WARNING, "Texture not found!");\r
-                                                       }\r
-                                               }\r
-                                               // } else {\r
-                                               // Pointer pTex = (Pointer)textureLink.getFieldValue("tex");\r
-                                               // List<Structure> texs = pTex.fetchData(dataRepository.getInputStream());\r
-                                               // Structure tex = texs.get(0);\r
-                                               // LOGGER.log(Level.WARNING, "Unsupported texture type: " + texco);\r
-                                               // }\r
-                                       } else {\r
-                                               LOGGER.log(Level.WARNING, "Many textures. Not solved yet!");// TODO\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-               dataRepository.addLoadedFeatures(structure.getOldMemoryAddress(), structure.getName(), structure, result);\r
-               return result;\r
-       }\r
-\r
-       /**\r
-        * This method returns a material similar to the one given but without textures. If the material has no textures it is not cloned but\r
-        * returned itself.\r
-        * \r
-        * @param material\r
-        *        a material to be cloned without textures\r
-        * @param imageType\r
-        *        type of image defined by blender; the constants are defined in TextureHelper\r
-        * @return material without textures of a specified type\r
-        */\r
-       public Material getNonTexturedMaterial(Material material, int imageType) {\r
-               String[] textureParamNames = new String[] { TEXTURE_TYPE_DIFFUSE, TEXTURE_TYPE_NORMAL, TEXTURE_TYPE_GLOW, TEXTURE_TYPE_SPECULAR, TEXTURE_TYPE_ALPHA };\r
-               Map<String, Texture> textures = new HashMap<String, Texture>(textureParamNames.length);\r
-               for (String textureParamName : textureParamNames) {\r
-                       MatParamTexture matParamTexture = material.getTextureParam(textureParamName);\r
-                       if (matParamTexture != null) {\r
-                               textures.put(textureParamName, matParamTexture.getTextureValue());\r
-                       }\r
-               }\r
-               if (textures.isEmpty()) {\r
-                       return material;\r
-               } else {\r
-                       // clear all textures first so that wo de not waste resources cloning them\r
-                       for (Entry<String, Texture> textureParamName : textures.entrySet()) {\r
-                               String name = textureParamName.getValue().getName();\r
-                               try {\r
-                                       int type = Integer.parseInt(name);\r
-                                       if (type == imageType) {\r
-                                               material.clearParam(textureParamName.getKey());\r
-                                       }\r
-                               } catch (NumberFormatException e) {\r
-                                       LOGGER.log(Level.WARNING, "The name of the texture does not contain the texture type value! {0} will not be removed!", name);\r
-                               }\r
-                       }\r
-                       Material result = material.clone();\r
-                       // put the textures back in place\r
-                       for (Entry<String, Texture> textureEntry : textures.entrySet()) {\r
-                               material.setTexture(textureEntry.getKey(), textureEntry.getValue());\r
-                       }\r
-                       return result;\r
-               }\r
-       }\r
-\r
-       /**\r
-        * This method converts the given material into particles-usable material.\r
-        * The texture and glow color are being copied.\r
-        * The method assumes it receives the Lighting type of material.\r
-        * @param material\r
-        *        the source material\r
-        * @param dataRepository\r
-        *        the data repository\r
-        * @return material converted into particles-usable material\r
-        */\r
-       public Material getParticlesMaterial(Material material, Integer alphaMaskIndex, DataRepository dataRepository) {\r
-               Material result = new Material(dataRepository.getAssetManager(), "Common/MatDefs/Misc/Particle.j3md");\r
-\r
-               // copying texture\r
-               MatParam diffuseMap = material.getParam("DiffuseMap");\r
-               if (diffuseMap != null) {\r
-                       Texture texture = ((Texture) diffuseMap.getValue()).clone();\r
-\r
-                       // applying alpha mask to the texture\r
-                       Image image = texture.getImage();\r
-                       ByteBuffer sourceBB = image.getData(0);\r
-                       sourceBB.rewind();\r
-                       int w = image.getWidth();\r
-                       int h = image.getHeight();\r
-                       ByteBuffer bb = BufferUtils.createByteBuffer(w * h * 4);\r
-                       IAlphaMask iAlphaMask = alphaMasks.get(alphaMaskIndex);\r
-                       iAlphaMask.setImageSize(w, h);\r
-\r
-                       for (int x = 0; x < w; ++x) {\r
-                               for (int y = 0; y < h; ++y) {\r
-                                       bb.put(sourceBB.get());\r
-                                       bb.put(sourceBB.get());\r
-                                       bb.put(sourceBB.get());\r
-                                       bb.put(iAlphaMask.getAlpha(x, y));\r
-                               }\r
-                       }\r
-\r
-                       image = new Image(Format.RGBA8, w, h, bb);\r
-                       texture.setImage(image);\r
-\r
-                       result.setTextureParam("Texture", VarType.Texture2D, texture);\r
-               }\r
-\r
-               // copying glow color\r
-               MatParam glowColor = material.getParam("GlowColor");\r
-               if (glowColor != null) {\r
-                       ColorRGBA color = (ColorRGBA) glowColor.getValue();\r
-                       result.setParam("GlowColor", VarType.Vector3, color);\r
-               }\r
-               return result;\r
-       }\r
-\r
-       /**\r
-        * This method indicates if the material has a texture of a specified type.\r
-        * \r
-        * @param material\r
-        *        the material\r
-        * @param textureType\r
-        *        the type of the texture\r
-        * @return <b>true</b> if the texture exists in the material and <B>false</b> otherwise\r
-        */\r
-       public boolean hasTexture(Material material, String textureType) {\r
-               if (material != null) {\r
-                       return material.getTextureParam(textureType) != null;\r
-               }\r
-               return false;\r
-       }\r
-\r
-       /**\r
-        * This method returns the diffuse color\r
-        * \r
-        * @param materialStructure\r
-        * @param diffuseShader\r
-        * @return\r
-        */\r
-       public ColorRGBA getDiffuseColor(Structure materialStructure, DiffuseShader diffuseShader) {\r
-               // bitwise 'or' of all textures mappings\r
-               int commonMapto = ((Number) materialStructure.getFieldValue("mapto")).intValue();\r
-\r
-               // diffuse color\r
-               float r = ((Number) materialStructure.getFieldValue("r")).floatValue();\r
-               float g = ((Number) materialStructure.getFieldValue("g")).floatValue();\r
-               float b = ((Number) materialStructure.getFieldValue("b")).floatValue();\r
-               float alpha = ((Number) materialStructure.getFieldValue("alpha")).floatValue();\r
-               if ((commonMapto & 0x01) == 0x01) {// Col\r
-                       return new ColorRGBA(r, g, b, alpha);\r
-               } else {\r
-                       switch (diffuseShader) {\r
-                               case FRESNEL:\r
-                               case ORENNAYAR:\r
-                               case TOON:\r
-                                       break;// TODO: find what is the proper modification\r
-                               case MINNAERT:\r
-                               case LAMBERT:// TODO: check if that is correct\r
-                                       float ref = ((Number) materialStructure.getFieldValue("ref")).floatValue();\r
-                                       r *= ref;\r
-                                       g *= ref;\r
-                                       b *= ref;\r
-                                       break;\r
-                               default:\r
-                                       throw new IllegalStateException("Unknown diffuse shader type: " + diffuseShader.toString());\r
-                       }\r
-                       return new ColorRGBA(r, g, b, alpha);\r
-               }\r
-       }\r
-\r
-       /**\r
-        * This method returns an enum describing the type of a diffuse shader used by this material.\r
-        * \r
-        * @param materialStructure\r
-        *        the material structure filled with data\r
-        * @return an enum describing the type of a diffuse shader used by this material\r
-        */\r
-       public DiffuseShader getDiffuseShader(Structure materialStructure) {\r
-               int diff_shader = ((Number) materialStructure.getFieldValue("diff_shader")).intValue();\r
-               return DiffuseShader.values()[diff_shader];\r
-       }\r
-\r
-       /**\r
-        * This method returns an ambient color used by the material.\r
-        * \r
-        * @param materialStructure\r
-        *        the material structure filled with data\r
-        * @return an ambient color used by the material\r
-        */\r
-       public ColorRGBA getAmbientColor(Structure materialStructure) {\r
-               float r = ((Number) materialStructure.getFieldValue("ambr")).floatValue();\r
-               float g = ((Number) materialStructure.getFieldValue("ambg")).floatValue();\r
-               float b = ((Number) materialStructure.getFieldValue("ambb")).floatValue();\r
-               float alpha = ((Number) materialStructure.getFieldValue("alpha")).floatValue();\r
-               return new ColorRGBA(r, g, b, alpha);\r
-       }\r
-\r
-       /**\r
-        * This method returns an enum describing the type of a specular shader used by this material.\r
-        * \r
-        * @param materialStructure\r
-        *        the material structure filled with data\r
-        * @return an enum describing the type of a specular shader used by this material\r
-        */\r
-       public SpecularShader getSpecularShader(Structure materialStructure) {\r
-               int spec_shader = ((Number) materialStructure.getFieldValue("spec_shader")).intValue();\r
-               return SpecularShader.values()[spec_shader];\r
-       }\r
-\r
-       /**\r
-        * This method returns a specular color used by the material.\r
-        * \r
-        * @param materialStructure\r
-        *        the material structure filled with data\r
-        * @return a specular color used by the material\r
-        */\r
-       public ColorRGBA getSpecularColor(Structure materialStructure, SpecularShader specularShader) {\r
-               float r = ((Number) materialStructure.getFieldValue("specr")).floatValue();\r
-               float g = ((Number) materialStructure.getFieldValue("specg")).floatValue();\r
-               float b = ((Number) materialStructure.getFieldValue("specb")).floatValue();\r
-               float alpha = ((Number) materialStructure.getFieldValue("alpha")).floatValue();\r
-               switch (specularShader) {\r
-                       case BLINN:\r
-                       case COOKTORRENCE:\r
-                       case TOON:\r
-                       case WARDISO:// TODO: find what is the proper modification\r
-                               break;\r
-                       case PHONG:// TODO: check if that is correct\r
-                               float spec = ((Number) materialStructure.getFieldValue("spec")).floatValue();\r
-                               r *= spec * 0.5f;\r
-                               g *= spec * 0.5f;\r
-                               b *= spec * 0.5f;\r
-                               break;\r
-                       default:\r
-                               throw new IllegalStateException("Unknown specular shader type: " + specularShader.toString());\r
-               }\r
-               return new ColorRGBA(r, g, b, alpha);\r
-       }\r
-\r
-       /**\r
-        * This method returns the sihiness of this material or DEFAULT_SHININESS value if not present.\r
-        * \r
-        * @param materialStructure\r
-        *        the material structure filled with data\r
-        * @return the sihiness of this material or DEFAULT_SHININESS value if not present\r
-        */\r
-       public float getShininess(Structure materialStructure) {\r
-               float shininess = ((Number) materialStructure.getFieldValue("emit")).floatValue();\r
-               return shininess > 0.0f ? shininess : DEFAULT_SHININESS;\r
-       }\r
-\r
-       /**\r
-        * This method returns the table of materials connected to the specified structure. The given structure can be of any type (ie. mesh or\r
-        * curve) but needs to have 'mat' field/\r
-        * \r
-        * @param structureWithMaterials\r
-        *        the structure containing the mesh data\r
-        * @param dataRepository\r
-        *        the data repository\r
-        * @return a list of vertices colors, each color belongs to a single vertex\r
-        * @throws BlenderFileException\r
-        *         this exception is thrown when the blend file structure is somehow invalid or corrupted\r
-        */\r
-       public Material[] getMaterials(Structure structureWithMaterials, DataRepository dataRepository) throws BlenderFileException {\r
-               Pointer ppMaterials = (Pointer) structureWithMaterials.getFieldValue("mat");\r
-               Material[] materials = null;\r
-               if (!ppMaterials.isNull()) {\r
-                       List<Structure> materialStructures = ppMaterials.fetchData(dataRepository.getInputStream());\r
-                       if (materialStructures != null && materialStructures.size() > 0) {\r
-                               MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);\r
-                               materials = new Material[materialStructures.size()];\r
-                               int i = 0;\r
-                               for (Structure s : materialStructures) {\r
-                                       Material material = (Material) dataRepository.getLoadedFeature(s.getOldMemoryAddress(), LoadedFeatureDataType.LOADED_FEATURE);\r
-                                       if (material == null) {\r
-                                               material = materialHelper.toMaterial(s, dataRepository);\r
-                                       }\r
-                                       materials[i++] = material;\r
-                               }\r
-                       }\r
-               }\r
-               return materials;\r
-       }\r
-\r
-       /**\r
-        * This method converts rgb values to hsv values.\r
-        * \r
-        * @param rgb\r
-        *        rgb values of the color\r
-        * @param hsv\r
-        *        hsv values of a color (this table contains the result of the transformation)\r
-        */\r
-       public void rgbToHsv(float r, float g, float b, float[] hsv) {\r
-               float cmax = r;\r
-               float cmin = r;\r
-               cmax = g > cmax ? g : cmax;\r
-               cmin = g < cmin ? g : cmin;\r
-               cmax = b > cmax ? b : cmax;\r
-               cmin = b < cmin ? b : cmin;\r
-\r
-               hsv[2] = cmax; /* value */\r
-               if (cmax != 0.0) {\r
-                       hsv[1] = (cmax - cmin) / cmax;\r
-               } else {\r
-                       hsv[1] = 0.0f;\r
-                       hsv[0] = 0.0f;\r
-               }\r
-               if (hsv[1] == 0.0) {\r
-                       hsv[0] = -1.0f;\r
-               } else {\r
-                       float cdelta = cmax - cmin;\r
-                       float rc = (cmax - r) / cdelta;\r
-                       float gc = (cmax - g) / cdelta;\r
-                       float bc = (cmax - b) / cdelta;\r
-                       if (r == cmax) {\r
-                               hsv[0] = bc - gc;\r
-                       } else if (g == cmax) {\r
-                               hsv[0] = 2.0f + rc - bc;\r
-                       } else {\r
-                               hsv[0] = 4.0f + gc - rc;\r
-                       }\r
-                       hsv[0] *= 60.0f;\r
-                       if (hsv[0] < 0.0f) {\r
-                               hsv[0] += 360.0f;\r
-                       }\r
-               }\r
-\r
-               hsv[0] /= 360.0f;\r
-               if (hsv[0] < 0.0f) {\r
-                       hsv[0] = 0.0f;\r
-               }\r
-       }\r
-\r
-       /**\r
-        * This method converts rgb values to hsv values.\r
-        * \r
-        * @param h\r
-        *        hue\r
-        * @param s\r
-        *        saturation\r
-        * @param v\r
-        *        value\r
-        * @param rgb\r
-        *        rgb result vector (should have 3 elements)\r
-        */\r
-       public void hsvToRgb(float h, float s, float v, float[] rgb) {\r
-               h *= 360.0f;\r
-               if (s == 0.0) {\r
-                       rgb[0] = rgb[1] = rgb[2] = v;\r
-               } else {\r
-                       if (h == 360) {\r
-                               h = 0;\r
-                       } else {\r
-                               h /= 60;\r
-                       }\r
-                       int i = (int) Math.floor(h);\r
-                       float f = h - i;\r
-                       float p = v * (1.0f - s);\r
-                       float q = v * (1.0f - s * f);\r
-                       float t = v * (1.0f - s * (1.0f - f));\r
-                       switch (i) {\r
-                               case 0:\r
-                                       rgb[0] = v;\r
-                                       rgb[1] = t;\r
-                                       rgb[2] = p;\r
-                                       break;\r
-                               case 1:\r
-                                       rgb[0] = q;\r
-                                       rgb[1] = v;\r
-                                       rgb[2] = p;\r
-                                       break;\r
-                               case 2:\r
-                                       rgb[0] = p;\r
-                                       rgb[1] = v;\r
-                                       rgb[2] = t;\r
-                                       break;\r
-                               case 3:\r
-                                       rgb[0] = p;\r
-                                       rgb[1] = q;\r
-                                       rgb[2] = v;\r
-                                       break;\r
-                               case 4:\r
-                                       rgb[0] = t;\r
-                                       rgb[1] = p;\r
-                                       rgb[2] = v;\r
-                                       break;\r
-                               case 5:\r
-                                       rgb[0] = v;\r
-                                       rgb[1] = p;\r
-                                       rgb[2] = q;\r
-                                       break;\r
-                       }\r
-               }\r
-       }\r
-\r
-       /**\r
-        * An interface used in calculating alpha mask during particles' texture calculations.\r
-        * @author Marcin Roguski (Kaelthas)\r
-        */\r
-       protected static interface IAlphaMask {\r
-               /**\r
-                * This method sets the size of the texture's image.\r
-                * @param width\r
-                *        the width of the image\r
-                * @param height\r
-                *        the height of the image\r
-                */\r
-               void setImageSize(int width, int height);\r
-\r
-               /**\r
-                * This method returns the alpha value for the specified texture position.\r
-                * @param x\r
-                *        the X coordinate of the texture position\r
-                * @param y\r
-                *        the Y coordinate of the texture position\r
-                * @return the alpha value for the specified texture position\r
-                */\r
-               byte getAlpha(float x, float y);\r
-       }\r
+\r
+    private static final Logger LOGGER = Logger.getLogger(MaterialHelper.class.getName());\r
+    protected static final float DEFAULT_SHININESS = 20.0f;\r
+    public static final String TEXTURE_TYPE_COLOR = "ColorMap";\r
+    public static final String TEXTURE_TYPE_DIFFUSE = "DiffuseMap";\r
+    public static final String TEXTURE_TYPE_NORMAL = "NormalMap";\r
+    public static final String TEXTURE_TYPE_SPECULAR = "SpecularMap";\r
+    public static final String TEXTURE_TYPE_GLOW = "GlowMap";\r
+    public static final String TEXTURE_TYPE_ALPHA = "AlphaMap";\r
+    public static final Integer ALPHA_MASK_NONE = Integer.valueOf(0);\r
+    public static final Integer ALPHA_MASK_CIRCLE = Integer.valueOf(1);\r
+    public static final Integer ALPHA_MASK_CONE = Integer.valueOf(2);\r
+    public static final Integer ALPHA_MASK_HYPERBOLE = Integer.valueOf(3);\r
+    protected final Map<Integer, AlphaMask> alphaMasks = new HashMap<Integer, AlphaMask>();\r
+\r
+    /**\r
+     * The type of the material's diffuse shader.\r
+     */\r
+    public static enum DiffuseShader {\r
+\r
+        LAMBERT, ORENNAYAR, TOON, MINNAERT, FRESNEL\r
+    }\r
+\r
+    /**\r
+     * The type of the material's specular shader.\r
+     */\r
+    public static enum SpecularShader {\r
+\r
+        COOKTORRENCE, PHONG, BLINN, TOON, WARDISO\r
+    }\r
+    /** Face cull mode. Should be excplicitly set before this helper is used. */\r
+    protected FaceCullMode faceCullMode;\r
+\r
+    /**\r
+     * This constructor parses the given blender version and stores the result. Some functionalities may differ in different blender\r
+     * versions.\r
+     * \r
+     * @param blenderVersion\r
+     *        the version read from the blend file\r
+     */\r
+    public MaterialHelper(String blenderVersion) {\r
+        super(blenderVersion);\r
+        // setting alpha masks\r
+        alphaMasks.put(ALPHA_MASK_NONE, new AlphaMask() {\r
+\r
+            @Override\r
+            public void setImageSize(int width, int height) {\r
+            }\r
+\r
+            @Override\r
+            public byte getAlpha(float x, float y) {\r
+                return (byte) 255;\r
+            }\r
+        });\r
+        alphaMasks.put(ALPHA_MASK_CIRCLE, new AlphaMask() {\r
+\r
+            private float r;\r
+            private float[] center;\r
+\r
+            @Override\r
+            public void setImageSize(int width, int height) {\r
+                r = Math.min(width, height) * 0.5f;\r
+                center = new float[]{width * 0.5f, height * 0.5f};\r
+            }\r
+\r
+            @Override\r
+            public byte getAlpha(float x, float y) {\r
+                float d = FastMath.abs(FastMath.sqrt((x - center[0]) * (x - center[0]) + (y - center[1]) * (y - center[1])));\r
+                return (byte) (d >= r ? 0 : 255);\r
+            }\r
+        });\r
+        alphaMasks.put(ALPHA_MASK_CONE, new AlphaMask() {\r
+\r
+            private float r;\r
+            private float[] center;\r
+\r
+            @Override\r
+            public void setImageSize(int width, int height) {\r
+                r = Math.min(width, height) * 0.5f;\r
+                center = new float[]{width * 0.5f, height * 0.5f};\r
+            }\r
+\r
+            @Override\r
+            public byte getAlpha(float x, float y) {\r
+                float d = FastMath.abs(FastMath.sqrt((x - center[0]) * (x - center[0]) + (y - center[1]) * (y - center[1])));\r
+                return (byte) (d >= r ? 0 : -255.0f * d / r + 255.0f);\r
+            }\r
+        });\r
+        alphaMasks.put(ALPHA_MASK_HYPERBOLE, new AlphaMask() {\r
+\r
+            private float r;\r
+            private float[] center;\r
+\r
+            @Override\r
+            public void setImageSize(int width, int height) {\r
+                r = Math.min(width, height) * 0.5f;\r
+                center = new float[]{width * 0.5f, height * 0.5f};\r
+            }\r
+\r
+            @Override\r
+            public byte getAlpha(float x, float y) {\r
+                float d = FastMath.abs(FastMath.sqrt((x - center[0]) * (x - center[0]) + (y - center[1]) * (y - center[1]))) / r;\r
+                return d >= 1.0f ? 0 : (byte) ((-FastMath.sqrt((2.0f - d) * d) + 1.0f) * 255.0f);\r
+            }\r
+        });\r
+    }\r
+\r
+    /**\r
+     * This method sets the face cull mode to be used with every loaded material.\r
+     * \r
+     * @param faceCullMode\r
+     *        the face cull mode\r
+     */\r
+    public void setFaceCullMode(FaceCullMode faceCullMode) {\r
+        this.faceCullMode = faceCullMode;\r
+    }\r
+\r
+    @SuppressWarnings("unchecked")\r
+    public Material toMaterial(Structure structure, DataRepository dataRepository) throws BlenderFileException {\r
+        LOGGER.log(Level.INFO, "Loading material.");\r
+        if (structure == null) {\r
+            return dataRepository.getDefaultMaterial();\r
+        }\r
+        Material result = (Material) dataRepository.getLoadedFeature(structure.getOldMemoryAddress(), LoadedFeatureDataType.LOADED_FEATURE);\r
+        if (result != null) {\r
+            return result;\r
+        }\r
+\r
+        int mode = ((Number) structure.getFieldValue("mode")).intValue();\r
+        boolean shadeless = (mode & 0x4) != 0;\r
+        boolean vertexColor = (mode & 0x16) != 0;\r
+        boolean transparent = (mode & 0x64) != 0;\r
+\r
+        if (shadeless) {\r
+            result = new Material(dataRepository.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");\r
+        } else {\r
+            result = new Material(dataRepository.getAssetManager(), "Common/MatDefs/Light/Lighting.j3md");\r
+        }\r
+\r
+        result.getAdditionalRenderState().setFaceCullMode(faceCullMode);\r
+\r
+        if (transparent) {\r
+            result.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);\r
+        }\r
+\r
+        String name = structure.getName();\r
+        LOGGER.log(Level.INFO, "Material's name: {0}", name);\r
+        if (vertexColor) {\r
+            if (shadeless) {\r
+                result.setBoolean("VertexColor", true);\r
+            } else {\r
+                result.setBoolean("UseVertexColor", true);\r
+            }\r
+        }\r
+\r
+        MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);\r
+        ColorRGBA diffuseColor = null;\r
+        if (shadeless) {\r
+            // color of shadeless? doesn't seem to work in blender ..\r
+        } else {\r
+            result.setBoolean("UseMaterialColors", true);\r
+\r
+            // setting the colors\r
+            DiffuseShader diffuseShader = materialHelper.getDiffuseShader(structure);\r
+            result.setBoolean("Minnaert", diffuseShader == DiffuseShader.MINNAERT);\r
+            diffuseColor = materialHelper.getDiffuseColor(structure, diffuseShader);\r
+            result.setColor("Diffuse", diffuseColor);\r
+\r
+            SpecularShader specularShader = materialHelper.getSpecularShader(structure);\r
+            result.setBoolean("WardIso", specularShader == SpecularShader.WARDISO);\r
+            result.setColor("Specular", materialHelper.getSpecularColor(structure, specularShader));\r
+\r
+            result.setColor("Ambient", materialHelper.getAmbientColor(structure));\r
+            result.setFloat("Shininess", materialHelper.getShininess(structure));\r
+        }\r
+\r
+        // texture\r
+        if ((dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.TEXTURES) != 0) {\r
+            TextureHelper textureHelper = dataRepository.getHelper(TextureHelper.class);\r
+            DynamicArray<Pointer> mtexs = (DynamicArray<Pointer>) structure.getFieldValue("mtex");\r
+            for (int i = 0; i < mtexs.getTotalSize(); ++i) {\r
+                Pointer p = mtexs.get(i);\r
+                if (!p.isNull()) {\r
+                    List<Structure> mtex = p.fetchData(dataRepository.getInputStream());\r
+                    if (mtex.size() == 1) {\r
+                        Structure textureLink = mtex.get(0);\r
+                        int texflag = ((Number) textureLink.getFieldValue("texflag")).intValue();\r
+                        // int texco = ((Number) textureLink.getFieldValue("texco")).intValue();\r
+                        boolean negateTexture = (texflag & 0x04) == 0;\r
+\r
+                        // if(texco == 0x10) {//TEXCO_UV (this is only supported now)\r
+                        int mapto = ((Number) textureLink.getFieldValue("mapto")).intValue();\r
+                        if (mapto != 0) {\r
+                            Pointer pTex = (Pointer) textureLink.getFieldValue("tex");\r
+                            Structure tex = pTex.fetchData(dataRepository.getInputStream()).get(0);\r
+                            Texture texture = textureHelper.getTexture(tex, dataRepository);\r
+                            if (texture != null) {\r
+                                if ((mapto & 0x01) != 0) {// Col\r
+                                    result.setBoolean("UseMaterialColors", Boolean.FALSE);\r
+                                    // blending the texture with material color and texture's defined color\r
+                                    int blendType = ((Number) textureLink.getFieldValue("blendtype")).intValue();\r
+                                    float[] color = new float[]{((Number) textureLink.getFieldValue("r")).floatValue(), ((Number) textureLink.getFieldValue("g")).floatValue(), ((Number) textureLink.getFieldValue("b")).floatValue()};\r
+                                    float colfac = ((Number) textureLink.getFieldValue("colfac")).floatValue();\r
+                                    texture = textureHelper.blendTexture(diffuseColor.getColorArray(), texture, color, colfac, blendType, negateTexture, dataRepository);\r
+                                    texture.setWrap(WrapMode.Repeat);\r
+                                    if (shadeless) {\r
+                                        result.setTexture(TEXTURE_TYPE_COLOR, texture);\r
+                                    } else {\r
+                                        result.setTexture(TEXTURE_TYPE_DIFFUSE, texture);\r
+                                    }\r
+                                }\r
+                                if ((mapto & 0x02) != 0) {// Nor\r
+                                    result.setTexture(TEXTURE_TYPE_NORMAL, texture);\r
+                                }\r
+                                if ((mapto & 0x20) != 0) {// Spec\r
+                                    result.setTexture(TEXTURE_TYPE_SPECULAR, texture);\r
+                                }\r
+                                if ((mapto & 0x40) != 0) {// Emit\r
+                                    result.setTexture(TEXTURE_TYPE_GLOW, texture);\r
+                                }\r
+                                if ((mapto & 0x80) != 0) {// Alpha\r
+                                    result.setTexture(TEXTURE_TYPE_ALPHA, texture);\r
+                                }\r
+                            } else {\r
+                                LOGGER.log(Level.WARNING, "Texture not found!");\r
+                            }\r
+                        }\r
+                        // } else {\r
+                        // Pointer pTex = (Pointer)textureLink.getFieldValue("tex");\r
+                        // List<Structure> texs = pTex.fetchData(dataRepository.getInputStream());\r
+                        // Structure tex = texs.get(0);\r
+                        // LOGGER.log(Level.WARNING, "Unsupported texture type: " + texco);\r
+                        // }\r
+                    } else {\r
+                        LOGGER.log(Level.WARNING, "Many textures. Not solved yet!");// TODO\r
+                    }\r
+                }\r
+            }\r
+        }\r
+        dataRepository.addLoadedFeatures(structure.getOldMemoryAddress(), structure.getName(), structure, result);\r
+        return result;\r
+    }\r
+\r
+    /**\r
+     * This method returns a material similar to the one given but without textures. If the material has no textures it is not cloned but\r
+     * returned itself.\r
+     * \r
+     * @param material\r
+     *        a material to be cloned without textures\r
+     * @param imageType\r
+     *        type of image defined by blender; the constants are defined in TextureHelper\r
+     * @return material without textures of a specified type\r
+     */\r
+    public Material getNonTexturedMaterial(Material material, int imageType) {\r
+        String[] textureParamNames = new String[]{TEXTURE_TYPE_DIFFUSE, TEXTURE_TYPE_NORMAL, TEXTURE_TYPE_GLOW, TEXTURE_TYPE_SPECULAR, TEXTURE_TYPE_ALPHA};\r
+        Map<String, Texture> textures = new HashMap<String, Texture>(textureParamNames.length);\r
+        for (String textureParamName : textureParamNames) {\r
+            MatParamTexture matParamTexture = material.getTextureParam(textureParamName);\r
+            if (matParamTexture != null) {\r
+                textures.put(textureParamName, matParamTexture.getTextureValue());\r
+            }\r
+        }\r
+        if (textures.isEmpty()) {\r
+            return material;\r
+        } else {\r
+            // clear all textures first so that wo de not waste resources cloning them\r
+            for (Entry<String, Texture> textureParamName : textures.entrySet()) {\r
+                String name = textureParamName.getValue().getName();\r
+                try {\r
+                    int type = Integer.parseInt(name);\r
+                    if (type == imageType) {\r
+                        material.clearParam(textureParamName.getKey());\r
+                    }\r
+                } catch (NumberFormatException e) {\r
+                    LOGGER.log(Level.WARNING, "The name of the texture does not contain the texture type value! {0} will not be removed!", name);\r
+                }\r
+            }\r
+            Material result = material.clone();\r
+            // put the textures back in place\r
+            for (Entry<String, Texture> textureEntry : textures.entrySet()) {\r
+                material.setTexture(textureEntry.getKey(), textureEntry.getValue());\r
+            }\r
+            return result;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * This method converts the given material into particles-usable material.\r
+     * The texture and glow color are being copied.\r
+     * The method assumes it receives the Lighting type of material.\r
+     * @param material\r
+     *        the source material\r
+     * @param dataRepository\r
+     *        the data repository\r
+     * @return material converted into particles-usable material\r
+     */\r
+    public Material getParticlesMaterial(Material material, Integer alphaMaskIndex, DataRepository dataRepository) {\r
+        Material result = new Material(dataRepository.getAssetManager(), "Common/MatDefs/Misc/Particle.j3md");\r
+\r
+        // copying texture\r
+        MatParam diffuseMap = material.getParam("DiffuseMap");\r
+        if (diffuseMap != null) {\r
+            Texture texture = ((Texture) diffuseMap.getValue()).clone();\r
+\r
+            // applying alpha mask to the texture\r
+            Image image = texture.getImage();\r
+            ByteBuffer sourceBB = image.getData(0);\r
+            sourceBB.rewind();\r
+            int w = image.getWidth();\r
+            int h = image.getHeight();\r
+            ByteBuffer bb = BufferUtils.createByteBuffer(w * h * 4);\r
+            AlphaMask iAlphaMask = alphaMasks.get(alphaMaskIndex);\r
+            iAlphaMask.setImageSize(w, h);\r
+\r
+            for (int x = 0; x < w; ++x) {\r
+                for (int y = 0; y < h; ++y) {\r
+                    bb.put(sourceBB.get());\r
+                    bb.put(sourceBB.get());\r
+                    bb.put(sourceBB.get());\r
+                    bb.put(iAlphaMask.getAlpha(x, y));\r
+                }\r
+            }\r
+\r
+            image = new Image(Format.RGBA8, w, h, bb);\r
+            texture.setImage(image);\r
+\r
+            result.setTextureParam("Texture", VarType.Texture2D, texture);\r
+        }\r
+\r
+        // copying glow color\r
+        MatParam glowColor = material.getParam("GlowColor");\r
+        if (glowColor != null) {\r
+            ColorRGBA color = (ColorRGBA) glowColor.getValue();\r
+            result.setParam("GlowColor", VarType.Vector3, color);\r
+        }\r
+        return result;\r
+    }\r
+\r
+    /**\r
+     * This method indicates if the material has a texture of a specified type.\r
+     * \r
+     * @param material\r
+     *        the material\r
+     * @param textureType\r
+     *        the type of the texture\r
+     * @return <b>true</b> if the texture exists in the material and <B>false</b> otherwise\r
+     */\r
+    public boolean hasTexture(Material material, String textureType) {\r
+        if (material != null) {\r
+            return material.getTextureParam(textureType) != null;\r
+        }\r
+        return false;\r
+    }\r
+\r
+    /**\r
+     * This method returns the diffuse color\r
+     * \r
+     * @param materialStructure\r
+     * @param diffuseShader\r
+     * @return\r
+     */\r
+    public ColorRGBA getDiffuseColor(Structure materialStructure, DiffuseShader diffuseShader) {\r
+        // bitwise 'or' of all textures mappings\r
+        int commonMapto = ((Number) materialStructure.getFieldValue("mapto")).intValue();\r
+\r
+        // diffuse color\r
+        float r = ((Number) materialStructure.getFieldValue("r")).floatValue();\r
+        float g = ((Number) materialStructure.getFieldValue("g")).floatValue();\r
+        float b = ((Number) materialStructure.getFieldValue("b")).floatValue();\r
+        float alpha = ((Number) materialStructure.getFieldValue("alpha")).floatValue();\r
+        if ((commonMapto & 0x01) == 0x01) {// Col\r
+            return new ColorRGBA(r, g, b, alpha);\r
+        } else {\r
+            switch (diffuseShader) {\r
+                case FRESNEL:\r
+                case ORENNAYAR:\r
+                case TOON:\r
+                    break;// TODO: find what is the proper modification\r
+                case MINNAERT:\r
+                case LAMBERT:// TODO: check if that is correct\r
+                    float ref = ((Number) materialStructure.getFieldValue("ref")).floatValue();\r
+                    r *= ref;\r
+                    g *= ref;\r
+                    b *= ref;\r
+                    break;\r
+                default:\r
+                    throw new IllegalStateException("Unknown diffuse shader type: " + diffuseShader.toString());\r
+            }\r
+            return new ColorRGBA(r, g, b, alpha);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * This method returns an enum describing the type of a diffuse shader used by this material.\r
+     * \r
+     * @param materialStructure\r
+     *        the material structure filled with data\r
+     * @return an enum describing the type of a diffuse shader used by this material\r
+     */\r
+    public DiffuseShader getDiffuseShader(Structure materialStructure) {\r
+        int diff_shader = ((Number) materialStructure.getFieldValue("diff_shader")).intValue();\r
+        return DiffuseShader.values()[diff_shader];\r
+    }\r
+\r
+    /**\r
+     * This method returns an ambient color used by the material.\r
+     * \r
+     * @param materialStructure\r
+     *        the material structure filled with data\r
+     * @return an ambient color used by the material\r
+     */\r
+    public ColorRGBA getAmbientColor(Structure materialStructure) {\r
+        float r = ((Number) materialStructure.getFieldValue("ambr")).floatValue();\r
+        float g = ((Number) materialStructure.getFieldValue("ambg")).floatValue();\r
+        float b = ((Number) materialStructure.getFieldValue("ambb")).floatValue();\r
+        float alpha = ((Number) materialStructure.getFieldValue("alpha")).floatValue();\r
+        return new ColorRGBA(r, g, b, alpha);\r
+    }\r
+\r
+    /**\r
+     * This method returns an enum describing the type of a specular shader used by this material.\r
+     * \r
+     * @param materialStructure\r
+     *        the material structure filled with data\r
+     * @return an enum describing the type of a specular shader used by this material\r
+     */\r
+    public SpecularShader getSpecularShader(Structure materialStructure) {\r
+        int spec_shader = ((Number) materialStructure.getFieldValue("spec_shader")).intValue();\r
+        return SpecularShader.values()[spec_shader];\r
+    }\r
+\r
+    /**\r
+     * This method returns a specular color used by the material.\r
+     * \r
+     * @param materialStructure\r
+     *        the material structure filled with data\r
+     * @return a specular color used by the material\r
+     */\r
+    public ColorRGBA getSpecularColor(Structure materialStructure, SpecularShader specularShader) {\r
+        float r = ((Number) materialStructure.getFieldValue("specr")).floatValue();\r
+        float g = ((Number) materialStructure.getFieldValue("specg")).floatValue();\r
+        float b = ((Number) materialStructure.getFieldValue("specb")).floatValue();\r
+        float alpha = ((Number) materialStructure.getFieldValue("alpha")).floatValue();\r
+        switch (specularShader) {\r
+            case BLINN:\r
+            case COOKTORRENCE:\r
+            case TOON:\r
+            case WARDISO:// TODO: find what is the proper modification\r
+                break;\r
+            case PHONG:// TODO: check if that is correct\r
+                float spec = ((Number) materialStructure.getFieldValue("spec")).floatValue();\r
+                r *= spec * 0.5f;\r
+                g *= spec * 0.5f;\r
+                b *= spec * 0.5f;\r
+                break;\r
+            default:\r
+                throw new IllegalStateException("Unknown specular shader type: " + specularShader.toString());\r
+        }\r
+        return new ColorRGBA(r, g, b, alpha);\r
+    }\r
+\r
+    /**\r
+     * This method returns the sihiness of this material or DEFAULT_SHININESS value if not present.\r
+     * \r
+     * @param materialStructure\r
+     *        the material structure filled with data\r
+     * @return the sihiness of this material or DEFAULT_SHININESS value if not present\r
+     */\r
+    public float getShininess(Structure materialStructure) {\r
+        float shininess = ((Number) materialStructure.getFieldValue("emit")).floatValue();\r
+        return shininess > 0.0f ? shininess : DEFAULT_SHININESS;\r
+    }\r
+\r
+    /**\r
+     * This method returns the table of materials connected to the specified structure. The given structure can be of any type (ie. mesh or\r
+     * curve) but needs to have 'mat' field/\r
+     * \r
+     * @param structureWithMaterials\r
+     *        the structure containing the mesh data\r
+     * @param dataRepository\r
+     *        the data repository\r
+     * @return a list of vertices colors, each color belongs to a single vertex\r
+     * @throws BlenderFileException\r
+     *         this exception is thrown when the blend file structure is somehow invalid or corrupted\r
+     */\r
+    public Material[] getMaterials(Structure structureWithMaterials, DataRepository dataRepository) throws BlenderFileException {\r
+        Pointer ppMaterials = (Pointer) structureWithMaterials.getFieldValue("mat");\r
+        Material[] materials = null;\r
+        if (!ppMaterials.isNull()) {\r
+            List<Structure> materialStructures = ppMaterials.fetchData(dataRepository.getInputStream());\r
+            if (materialStructures != null && materialStructures.size() > 0) {\r
+                MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);\r
+                materials = new Material[materialStructures.size()];\r
+                int i = 0;\r
+                for (Structure s : materialStructures) {\r
+                    Material material = (Material) dataRepository.getLoadedFeature(s.getOldMemoryAddress(), LoadedFeatureDataType.LOADED_FEATURE);\r
+                    if (material == null) {\r
+                        material = materialHelper.toMaterial(s, dataRepository);\r
+                    }\r
+                    materials[i++] = material;\r
+                }\r
+            }\r
+        }\r
+        return materials;\r
+    }\r
+\r
+    /**\r
+     * This method converts rgb values to hsv values.\r
+     * \r
+     * @param rgb\r
+     *        rgb values of the color\r
+     * @param hsv\r
+     *        hsv values of a color (this table contains the result of the transformation)\r
+     */\r
+    public void rgbToHsv(float r, float g, float b, float[] hsv) {\r
+        float cmax = r;\r
+        float cmin = r;\r
+        cmax = g > cmax ? g : cmax;\r
+        cmin = g < cmin ? g : cmin;\r
+        cmax = b > cmax ? b : cmax;\r
+        cmin = b < cmin ? b : cmin;\r
+\r
+        hsv[2] = cmax; /* value */\r
+        if (cmax != 0.0) {\r
+            hsv[1] = (cmax - cmin) / cmax;\r
+        } else {\r
+            hsv[1] = 0.0f;\r
+            hsv[0] = 0.0f;\r
+        }\r
+        if (hsv[1] == 0.0) {\r
+            hsv[0] = -1.0f;\r
+        } else {\r
+            float cdelta = cmax - cmin;\r
+            float rc = (cmax - r) / cdelta;\r
+            float gc = (cmax - g) / cdelta;\r
+            float bc = (cmax - b) / cdelta;\r
+            if (r == cmax) {\r
+                hsv[0] = bc - gc;\r
+            } else if (g == cmax) {\r
+                hsv[0] = 2.0f + rc - bc;\r
+            } else {\r
+                hsv[0] = 4.0f + gc - rc;\r
+            }\r
+            hsv[0] *= 60.0f;\r
+            if (hsv[0] < 0.0f) {\r
+                hsv[0] += 360.0f;\r
+            }\r
+        }\r
+\r
+        hsv[0] /= 360.0f;\r
+        if (hsv[0] < 0.0f) {\r
+            hsv[0] = 0.0f;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * This method converts rgb values to hsv values.\r
+     * \r
+     * @param h\r
+     *        hue\r
+     * @param s\r
+     *        saturation\r
+     * @param v\r
+     *        value\r
+     * @param rgb\r
+     *        rgb result vector (should have 3 elements)\r
+     */\r
+    public void hsvToRgb(float h, float s, float v, float[] rgb) {\r
+        h *= 360.0f;\r
+        if (s == 0.0) {\r
+            rgb[0] = rgb[1] = rgb[2] = v;\r
+        } else {\r
+            if (h == 360) {\r
+                h = 0;\r
+            } else {\r
+                h /= 60;\r
+            }\r
+            int i = (int) Math.floor(h);\r
+            float f = h - i;\r
+            float p = v * (1.0f - s);\r
+            float q = v * (1.0f - s * f);\r
+            float t = v * (1.0f - s * (1.0f - f));\r
+            switch (i) {\r
+                case 0:\r
+                    rgb[0] = v;\r
+                    rgb[1] = t;\r
+                    rgb[2] = p;\r
+                    break;\r
+                case 1:\r
+                    rgb[0] = q;\r
+                    rgb[1] = v;\r
+                    rgb[2] = p;\r
+                    break;\r
+                case 2:\r
+                    rgb[0] = p;\r
+                    rgb[1] = v;\r
+                    rgb[2] = t;\r
+                    break;\r
+                case 3:\r
+                    rgb[0] = p;\r
+                    rgb[1] = q;\r
+                    rgb[2] = v;\r
+                    break;\r
+                case 4:\r
+                    rgb[0] = t;\r
+                    rgb[1] = p;\r
+                    rgb[2] = v;\r
+                    break;\r
+                case 5:\r
+                    rgb[0] = v;\r
+                    rgb[1] = p;\r
+                    rgb[2] = q;\r
+                    break;\r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
+     * An interface used in calculating alpha mask during particles' texture calculations.\r
+     * @author Marcin Roguski (Kaelthas)\r
+     */\r
+    protected static interface AlphaMask {\r
+\r
+        /**\r
+         * This method sets the size of the texture's image.\r
+         * @param width\r
+         *        the width of the image\r
+         * @param height\r
+         *        the height of the image\r
+         */\r
+        void setImageSize(int width, int height);\r
+\r
+        /**\r
+         * This method returns the alpha value for the specified texture position.\r
+         * @param x\r
+         *        the X coordinate of the texture position\r
+         * @param y\r
+         *        the Y coordinate of the texture position\r
+         * @return the alpha value for the specified texture position\r
+         */\r
+        byte getAlpha(float x, float y);\r
+    }\r
 }\r
index 9dd35f5..0644a93 100644 (file)
@@ -67,533 +67,534 @@ import com.jme3.util.BufferUtils;
  * @author Marcin Roguski (Kaelthas)\r
  */\r
 public class MeshHelper extends AbstractBlenderHelper {\r
-       protected static final int      MAXIMUM_WEIGHTS_PER_VERTEX      = 4;    // have no idea why 4, could someone please explain ?\r
-\r
-       /**\r
-        * This constructor parses the given blender version and stores the result. Some functionalities may differ in different blender\r
-        * versions.\r
-        * \r
-        * @param blenderVersion\r
-        *            the version read from the blend file\r
-        */\r
-       public MeshHelper(String blenderVersion) {\r
-               super(blenderVersion);\r
-       }\r
-\r
-       /**\r
-        * This method reads converts the given structure into mesh. The given structure needs to be filled with the appropriate data.\r
-        * \r
-        * @param structure\r
-        *            the structure we read the mesh from\r
-        * @return the mesh feature\r
-        * @throws BlenderFileException\r
-        */\r
-       @SuppressWarnings("unchecked")\r
-       public List<Geometry> toMesh(Structure structure, DataRepository dataRepository) throws BlenderFileException {\r
-               List<Geometry> geometries = (List<Geometry>) dataRepository.getLoadedFeature(structure.getOldMemoryAddress(),\r
-                               LoadedFeatureDataType.LOADED_FEATURE);\r
-               if (geometries != null) {\r
-                       List<Geometry> copiedGeometries = new ArrayList<Geometry>(geometries.size());\r
-                       for (Geometry geometry : geometries) {\r
-                               copiedGeometries.add(geometry.clone());\r
-                       }\r
-                       return copiedGeometries;\r
-               }\r
-\r
-               // helpers\r
-               TextureHelper textureHelper = dataRepository.getHelper(TextureHelper.class);\r
-\r
-               // reading mesh data\r
-               String name = structure.getName();\r
-\r
-               // reading vertices\r
-               Vector3f[] vertices = this.getVertices(structure, dataRepository);\r
-               int verticesAmount = vertices.length;\r
-\r
-               // vertices Colors\r
-               List<float[]> verticesColors = this.getVerticesColors(structure, dataRepository);\r
-\r
-               // reading faces\r
-               // the following map sorts faces by material number (because in jme Mesh can have only one material)\r
-               Map<Integer, List<Integer>> meshesMap = new HashMap<Integer, List<Integer>>();\r
-               Pointer pMFace = (Pointer) structure.getFieldValue("mface");\r
-               List<Structure> mFaces = pMFace.fetchData(dataRepository.getInputStream());\r
-\r
-               Pointer pMTFace = (Pointer) structure.getFieldValue("mtface");\r
-               List<Vector2f> uvCoordinates = null;\r
-               List<Structure> mtFaces = null;\r
-\r
-               if (!pMTFace.isNull()) {\r
-                       mtFaces = pMTFace.fetchData(dataRepository.getInputStream());\r
-                       int facesAmount = ((Number) structure.getFieldValue("totface")).intValue();\r
-                       if (mtFaces.size() != facesAmount) {\r
-                               throw new BlenderFileException("The amount of faces uv coordinates is not equal to faces amount!");\r
-                       }\r
-                       uvCoordinates = new ArrayList<Vector2f>();// TODO: calculate the amount of coordinates if possible\r
-               }\r
-\r
-               // normalMap merges normals of faces that will be rendered smooth\r
-               Map<Vector3f, Vector3f> normalMap = new HashMap<Vector3f, Vector3f>(verticesAmount);\r
-\r
-               List<Vector3f> normalList = new ArrayList<Vector3f>();\r
-               List<Vector3f> vertexList = new ArrayList<Vector3f>();\r
-               Map<Integer, Texture> materialNumberToTexture = new HashMap<Integer, Texture>();// indicates if the material with the specified\r
-                                                                                                                                                                               // number should have a texture attached\r
-               // this map's key is the vertex index from 'vertices 'table and the value are indices from 'vertexList'\r
-               // positions (it simply tells which vertex is referenced where in the result list)\r
-               Map<Integer, List<Integer>> vertexReferenceMap = new HashMap<Integer, List<Integer>>(verticesAmount);\r
-               int vertexColorIndex = 0;\r
-               for (int i = 0; i < mFaces.size(); ++i) {\r
-                       Structure mFace = mFaces.get(i);\r
-                       boolean smooth = (((Number) mFace.getFieldValue("flag")).byteValue() & 0x01) != 0x00;\r
-                       DynamicArray<Number> uvs = null;\r
-                       boolean materialWithoutTextures = false;\r
-                       Pointer pImage = null;\r
-                       if (mtFaces != null) {\r
-                               Structure mtFace = mtFaces.get(i);\r
-                               pImage = (Pointer) mtFace.getFieldValue("tpage");\r
-                               materialWithoutTextures = pImage.isNull();\r
-                               // uvs always must be added wheater we have texture or not\r
-                               uvs = (DynamicArray<Number>) mtFace.getFieldValue("uv");\r
-                               uvCoordinates.add(new Vector2f(uvs.get(0, 0).floatValue(), uvs.get(0, 1).floatValue()));\r
-                               uvCoordinates.add(new Vector2f(uvs.get(1, 0).floatValue(), uvs.get(1, 1).floatValue()));\r
-                               uvCoordinates.add(new Vector2f(uvs.get(2, 0).floatValue(), uvs.get(2, 1).floatValue()));\r
-                       }\r
-                       int matNr = ((Number) mFace.getFieldValue("mat_nr")).intValue();\r
-                       Integer materialNumber = Integer.valueOf(materialWithoutTextures ? -1 * matNr - 1 : matNr);\r
-                       List<Integer> indexList = meshesMap.get(materialNumber);\r
-                       if (indexList == null) {\r
-                               indexList = new ArrayList<Integer>();\r
-                               meshesMap.put(materialNumber, indexList);\r
-                       }\r
-                       if (pImage != null && !pImage.isNull() && !materialNumberToTexture.containsKey(materialNumber)) {// attaching image to texture\r
-                                                                                                                                                                                                                               // (face can have UV's and\r
-                                                                                                                                                                                                                               // image whlie its material\r
-                                                                                                                                                                                                                               // may have no texture\r
-                                                                                                                                                                                                                               // attached)\r
-                               Texture texture = textureHelper.getTextureFromImage(pImage.fetchData(dataRepository.getInputStream()).get(0),\r
-                                               dataRepository);\r
-                               if (texture != null) {\r
-                                       materialNumberToTexture.put(materialNumber, texture);\r
-                               }\r
-                       }\r
-\r
-                       int v1 = ((Number) mFace.getFieldValue("v1")).intValue();\r
-                       int v2 = ((Number) mFace.getFieldValue("v2")).intValue();\r
-                       int v3 = ((Number) mFace.getFieldValue("v3")).intValue();\r
-                       int v4 = ((Number) mFace.getFieldValue("v4")).intValue();\r
-\r
-                       Vector3f n = FastMath.computeNormal(vertices[v1], vertices[v2], vertices[v3]);\r
-                       this.addNormal(n, normalMap, smooth, vertices[v1], vertices[v2], vertices[v3]);\r
-                       normalList.add(normalMap.get(vertices[v1]));\r
-                       normalList.add(normalMap.get(vertices[v2]));\r
-                       normalList.add(normalMap.get(vertices[v3]));\r
-\r
-                       this.appendVertexReference(v1, vertexList.size(), vertexReferenceMap);\r
-                       indexList.add(vertexList.size());\r
-                       vertexList.add(vertices[v1]);\r
-\r
-                       this.appendVertexReference(v2, vertexList.size(), vertexReferenceMap);\r
-                       indexList.add(vertexList.size());\r
-                       vertexList.add(vertices[v2]);\r
-\r
-                       this.appendVertexReference(v3, vertexList.size(), vertexReferenceMap);\r
-                       indexList.add(vertexList.size());\r
-                       vertexList.add(vertices[v3]);\r
-\r
-                       if (v4 > 0) {\r
-                               if (uvs != null) {\r
-                                       uvCoordinates.add(new Vector2f(uvs.get(0, 0).floatValue(), uvs.get(0, 1).floatValue()));\r
-                                       uvCoordinates.add(new Vector2f(uvs.get(2, 0).floatValue(), uvs.get(2, 1).floatValue()));\r
-                                       uvCoordinates.add(new Vector2f(uvs.get(3, 0).floatValue(), uvs.get(3, 1).floatValue()));\r
-                               }\r
-                               this.appendVertexReference(v1, vertexList.size(), vertexReferenceMap);\r
-                               indexList.add(vertexList.size());\r
-                               vertexList.add(vertices[v1]);\r
-\r
-                               this.appendVertexReference(v3, vertexList.size(), vertexReferenceMap);\r
-                               indexList.add(vertexList.size());\r
-                               vertexList.add(vertices[v3]);\r
-\r
-                               this.appendVertexReference(v4, vertexList.size(), vertexReferenceMap);\r
-                               indexList.add(vertexList.size());\r
-                               vertexList.add(vertices[v4]);\r
-\r
-                               this.addNormal(n, normalMap, smooth, vertices[v4]);\r
-                               normalList.add(normalMap.get(vertices[v1]));\r
-                               normalList.add(normalMap.get(vertices[v3]));\r
-                               normalList.add(normalMap.get(vertices[v4]));\r
-\r
-                               if (verticesColors != null) {\r
-                                       verticesColors.add(vertexColorIndex + 3, verticesColors.get(vertexColorIndex));\r
-                                       verticesColors.add(vertexColorIndex + 4, verticesColors.get(vertexColorIndex + 2));\r
-                               }\r
-                               vertexColorIndex += 6;\r
-                       } else {\r
-                               if (verticesColors != null) {\r
-                                       verticesColors.remove(vertexColorIndex + 3);\r
-                                       vertexColorIndex += 3;\r
-                               }\r
-                       }\r
-               }\r
-               Vector3f[] normals = normalList.toArray(new Vector3f[normalList.size()]);\r
-\r
-               // reading vertices groups (from the parent)\r
-               Structure parent = dataRepository.peekParent();\r
-               Structure defbase = (Structure) parent.getFieldValue("defbase");\r
-               List<Structure> defs = defbase.evaluateListBase(dataRepository);\r
-               String[] verticesGroups = new String[defs.size()];\r
-               int defIndex = 0;\r
-               for (Structure def : defs) {\r
-                       verticesGroups[defIndex++] = def.getFieldValue("name").toString();\r
-               }\r
-\r
-               // vertices bone weights and indices\r
-               ArmatureHelper armatureHelper = dataRepository.getHelper(ArmatureHelper.class);\r
-               Structure defBase = (Structure) parent.getFieldValue("defbase");\r
-               Map<Integer, Integer> groupToBoneIndexMap = armatureHelper.getGroupToBoneIndexMap(defBase, dataRepository);\r
-\r
-               VertexBuffer verticesWeights = null, verticesWeightsIndices = null;\r
-               int[] bonesGroups = new int[] { 0 };\r
-               VertexBuffer[] boneWeightsAndIndex = this.getBoneWeightAndIndexBuffer(structure, vertexList.size(), bonesGroups,\r
-                               vertexReferenceMap, groupToBoneIndexMap, dataRepository);\r
-               verticesWeights = boneWeightsAndIndex[0];\r
-               verticesWeightsIndices = boneWeightsAndIndex[1];\r
-\r
-               // reading materials\r
-               MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);\r
-               Material[] materials = null;\r
-               Material[] nonTexturedMaterials = null;\r
-               if ((dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.MATERIALS) != 0) {\r
-                       materials = materialHelper.getMaterials(structure, dataRepository);\r
-                       nonTexturedMaterials = materials == null ? null : new Material[materials.length];// fill it when needed\r
-               }\r
-\r
-               // creating the result meshes\r
-               geometries = new ArrayList<Geometry>(meshesMap.size());\r
-\r
-               VertexBuffer verticesBuffer = new VertexBuffer(Type.Position);\r
-               verticesBuffer.setupData(Usage.Stream, 3, Format.Float,\r
-                               BufferUtils.createFloatBuffer(vertexList.toArray(new Vector3f[vertexList.size()])));\r
-\r
-               // initial vertex position (used with animation)\r
-               VertexBuffer verticesBind = new VertexBuffer(Type.BindPosePosition);\r
-               verticesBind.setupData(Usage.CpuOnly, 3, Format.Float, BufferUtils.clone(verticesBuffer.getData()));\r
-\r
-               VertexBuffer normalsBuffer = new VertexBuffer(Type.Normal);\r
-               normalsBuffer.setupData(Usage.Stream, 3, Format.Float, BufferUtils.createFloatBuffer(normals));\r
-\r
-               // initial normals position (used with animation)\r
-               VertexBuffer normalsBind = new VertexBuffer(Type.BindPoseNormal);\r
-               normalsBind.setupData(Usage.CpuOnly, 3, Format.Float, BufferUtils.clone(normalsBuffer.getData()));\r
-\r
-               VertexBuffer uvCoordsBuffer = null;\r
-               if (uvCoordinates != null) {\r
-                       uvCoordsBuffer = new VertexBuffer(Type.TexCoord);\r
-                       uvCoordsBuffer.setupData(Usage.Static, 2, Format.Float,\r
-                                       BufferUtils.createFloatBuffer(uvCoordinates.toArray(new Vector2f[uvCoordinates.size()])));\r
-               }\r
-\r
-               // generating meshes\r
-               FloatBuffer verticesColorsBuffer = this.createFloatBuffer(verticesColors);\r
-               for (Entry<Integer, List<Integer>> meshEntry : meshesMap.entrySet()) {\r
-                       Mesh mesh = new Mesh();\r
-\r
-                       // creating vertices indices for this mesh\r
-                       List<Integer> indexList = meshEntry.getValue();\r
-                       short[] indices = new short[indexList.size()];//TODO: check if the model doesn't have more than 32767 vertices\r
-                       for (int i = 0; i < indexList.size(); ++i) {//if yes then mesh.getVertices method must be changed to accept other than ShortBuffer\r
-                               indices[i] = indexList.get(i).shortValue();\r
-                       }\r
-\r
-                       // setting vertices\r
-                       mesh.setBuffer(Type.Index, 1, BufferUtils.createShortBuffer(indices));\r
-                       mesh.setBuffer(verticesBuffer);\r
-                       mesh.setBuffer(verticesBind);\r
-\r
-                       // setting vertices colors\r
-                       if (verticesColorsBuffer != null) {\r
-                               mesh.setBuffer(Type.Color, 4, verticesColorsBuffer);\r
-                       }\r
-\r
-                       // setting weights for bones\r
-                       if (verticesWeights != null) {\r
-                               mesh.setMaxNumWeights(bonesGroups[0]);\r
-                               mesh.setBuffer(verticesWeights);\r
-                               mesh.setBuffer(verticesWeightsIndices);\r
-                       }\r
-\r
-                       // setting faces' normals\r
-                       mesh.setBuffer(normalsBuffer);\r
-                       mesh.setBuffer(normalsBind);\r
-\r
-                       // setting uvCoords\r
-                       if (uvCoordsBuffer != null) {\r
-                               mesh.setBuffer(uvCoordsBuffer);\r
-                       }\r
-\r
-                       // creating the result\r
-                       Geometry geometry = new Geometry(name + (geometries.size() + 1), mesh);\r
-                       if (materials != null) {\r
-                               int materialNumber = meshEntry.getKey().intValue();\r
-                               Material material;\r
-                               if (materialNumber >= 0) {\r
-                                       material = materials[materialNumber];\r
-                                       if (materialNumberToTexture.containsKey(Integer.valueOf(materialNumber))) {\r
-                                               if (material.getMaterialDef().getAssetName().contains("Lighting")) {\r
-                                                       if (!materialHelper.hasTexture(material, MaterialHelper.TEXTURE_TYPE_DIFFUSE)) {\r
-                                                               material = material.clone();\r
-                                                               material.setTexture(MaterialHelper.TEXTURE_TYPE_DIFFUSE,\r
-                                                                               materialNumberToTexture.get(Integer.valueOf(materialNumber)));\r
-                                                       }\r
-                                               } else {\r
-                                                       if (!materialHelper.hasTexture(material, MaterialHelper.TEXTURE_TYPE_COLOR)) {\r
-                                                               material = material.clone();\r
-                                                               material.setTexture(MaterialHelper.TEXTURE_TYPE_COLOR,\r
-                                                                               materialNumberToTexture.get(Integer.valueOf(materialNumber)));\r
-                                                       }\r
-                                               }\r
-                                       }\r
-                               } else {\r
-                                       materialNumber = -1 * (materialNumber + 1);\r
-                                       if (nonTexturedMaterials[materialNumber] == null) {\r
-                                               nonTexturedMaterials[materialNumber] = materialHelper.getNonTexturedMaterial(materials[materialNumber],\r
-                                                               TextureHelper.TEX_IMAGE);\r
-                                       }\r
-                                       material = nonTexturedMaterials[materialNumber];\r
-                               }\r
-                               geometry.setMaterial(material);\r
-                       } else {\r
-                               geometry.setMaterial(dataRepository.getDefaultMaterial());\r
-                       }\r
-                       geometries.add(geometry);\r
-               }\r
-               dataRepository.addLoadedFeatures(structure.getOldMemoryAddress(), structure.getName(), structure, geometries);\r
-               return geometries;\r
-       }\r
-\r
-       /**\r
-        * This method adds a normal to a normals' map. This map is used to merge normals of a vertor that should be rendered smooth.\r
-        * \r
-        * @param normalToAdd\r
-        *            a normal to be added\r
-        * @param normalMap\r
-        *            merges normals of faces that will be rendered smooth; the key is the vertex and the value - its normal vector\r
-        * @param smooth\r
-        *            the variable that indicates wheather to merge normals (creating the smooth mesh) or not\r
-        * @param vertices\r
-        *            a list of vertices read from the blender file\r
-        */\r
-       protected void addNormal(Vector3f normalToAdd, Map<Vector3f, Vector3f> normalMap, boolean smooth, Vector3f... vertices) {\r
-               for (Vector3f v : vertices) {\r
-                       Vector3f n = normalMap.get(v);\r
-                       if (!smooth || n == null) {\r
-                               normalMap.put(v, normalToAdd.clone());\r
-                       } else {\r
-                               n.addLocal(normalToAdd).normalizeLocal();\r
-                       }\r
-               }\r
-       }\r
-\r
-       /**\r
-        * This method fills the vertex reference map. The vertices are loaded once and referenced many times in the model. This map is created\r
-        * to tell where the basic vertices are referenced in the result vertex lists. The key of the map is the basic vertex index, and its key\r
-        * - the reference indices list.\r
-        * \r
-        * @param basicVertexIndex\r
-        *            the index of the vertex from its basic table\r
-        * @param resultIndex\r
-        *            the index of the vertex in its result vertex list\r
-        * @param vertexReferenceMap\r
-        *            the reference map\r
-        */\r
-       protected void appendVertexReference(int basicVertexIndex, int resultIndex, Map<Integer, List<Integer>> vertexReferenceMap) {\r
-               List<Integer> referenceList = vertexReferenceMap.get(Integer.valueOf(basicVertexIndex));\r
-               if (referenceList == null) {\r
-                       referenceList = new ArrayList<Integer>();\r
-                       vertexReferenceMap.put(Integer.valueOf(basicVertexIndex), referenceList);\r
-               }\r
-               referenceList.add(Integer.valueOf(resultIndex));\r
-       }\r
-\r
-       /**\r
-        * This method returns the vertices colors. Each vertex is stored in float[4] array.\r
-        * \r
-        * @param meshStructure\r
-        *            the structure containing the mesh data\r
-        * @param dataRepository\r
-        *            the data repository\r
-        * @return a list of vertices colors, each color belongs to a single vertex\r
-        * @throws BlenderFileException\r
-        *             this exception is thrown when the blend file structure is somehow invalid or corrupted\r
-        */\r
-       public List<float[]> getVerticesColors(Structure meshStructure, DataRepository dataRepository) throws BlenderFileException {\r
-               Pointer pMCol = (Pointer) meshStructure.getFieldValue("mcol");\r
-               List<float[]> verticesColors = null;\r
-               List<Structure> mCol = null;\r
-               if (!pMCol.isNull()) {\r
-                       verticesColors = new LinkedList<float[]>();\r
-                       mCol = pMCol.fetchData(dataRepository.getInputStream());\r
-                       for (Structure color : mCol) {\r
-                               float r = ((Number) color.getFieldValue("r")).byteValue() / 256.0f;\r
-                               float g = ((Number) color.getFieldValue("g")).byteValue() / 256.0f;\r
-                               float b = ((Number) color.getFieldValue("b")).byteValue() / 256.0f;\r
-                               float a = ((Number) color.getFieldValue("a")).byteValue() / 256.0f;\r
-                               verticesColors.add(new float[] { b, g, r, a });\r
-                       }\r
-               }\r
-               return verticesColors;\r
-       }\r
-\r
-       /**\r
-        * This method returns the vertices.\r
-        * \r
-        * @param meshStructure\r
-        *            the structure containing the mesh data\r
-        * @param dataRepository\r
-        *            the data repository\r
-        * @return a list of vertices colors, each color belongs to a single vertex\r
-        * @throws BlenderFileException\r
-        *             this exception is thrown when the blend file structure is somehow invalid or corrupted\r
-        */\r
-       @SuppressWarnings("unchecked")\r
-       public Vector3f[] getVertices(Structure meshStructure, DataRepository dataRepository) throws BlenderFileException {\r
-               int verticesAmount = ((Number) meshStructure.getFieldValue("totvert")).intValue();\r
-               Vector3f[] vertices = new Vector3f[verticesAmount];\r
-               Pointer pMVert = (Pointer) meshStructure.getFieldValue("mvert");\r
-               List<Structure> mVerts = pMVert.fetchData(dataRepository.getInputStream());\r
-               for (int i = 0; i < verticesAmount; ++i) {\r
-                       DynamicArray<Number> coordinates = (DynamicArray<Number>) mVerts.get(i).getFieldValue("co");\r
-                       vertices[i] = new Vector3f(coordinates.get(0).floatValue(), coordinates.get(1).floatValue(), coordinates.get(2).floatValue());\r
-               }\r
-               return vertices;\r
-       }\r
-\r
-       /**\r
-        * This method returns an array of size 2. The first element is a vertex buffer holding bone weights for every vertex in the model. The\r
-        * second element is a vertex buffer holding bone indices for vertices (the indices of bones the vertices are assigned to).\r
-        * \r
-        * @param meshStructure\r
-        *            the mesh structure object\r
-        * @param vertexListSize\r
-        *            a number of vertices in the model\r
-        * @param bonesGroups\r
-        *            this is an output parameter, it should be a one-sized array; the maximum amount of weights per vertex (up to\r
-        *            MAXIMUM_WEIGHTS_PER_VERTEX) is stored there\r
-        * @param vertexReferenceMap\r
-        *            this reference map allows to map the original vertices read from blender to vertices that are really in the model; one\r
-        *            vertex may appear several times in the result model\r
-        * @param groupToBoneIndexMap\r
-        *            this object maps the group index (to which a vertices in blender belong) to bone index of the model\r
-        * @param dataRepository\r
-        *            the data repository\r
-        * @return arrays of vertices weights and their bone indices and (as an outpot parameter) the maximum amount of weights for a vertex\r
-        * @throws BlenderFileException\r
-        *             this exception is thrown when the blend file structure is somehow invalid or corrupted\r
-        */\r
-       public VertexBuffer[] getBoneWeightAndIndexBuffer(Structure meshStructure, int vertexListSize, int[] bonesGroups,\r
-                       Map<Integer, List<Integer>> vertexReferenceMap, Map<Integer, Integer> groupToBoneIndexMap, DataRepository dataRepository)\r
-                       throws BlenderFileException {\r
-               Pointer pDvert = (Pointer) meshStructure.getFieldValue("dvert");// dvert = DeformVERTices\r
-               FloatBuffer weightsFloatData = BufferUtils.createFloatBuffer(vertexListSize * MAXIMUM_WEIGHTS_PER_VERTEX);\r
-               ByteBuffer indicesData = BufferUtils.createByteBuffer(vertexListSize * MAXIMUM_WEIGHTS_PER_VERTEX);\r
-               if (!pDvert.isNull()) {// assigning weights and bone indices\r
-                       List<Structure> dverts = pDvert.fetchData(dataRepository.getInputStream());// dverts.size() == verticesAmount (one dvert per\r
-                                                                                                                                                                               // vertex in blender)\r
-                       int vertexIndex = 0;\r
-                       for (Structure dvert : dverts) {\r
-                               int totweight = ((Number) dvert.getFieldValue("totweight")).intValue();// total amount of weights assignet to the vertex\r
-                                                                                                                                                                               // (max. 4 in JME)\r
-                               Pointer pDW = (Pointer) dvert.getFieldValue("dw");\r
-                               List<Integer> vertexIndices = vertexReferenceMap.get(Integer.valueOf(vertexIndex));// we fetch the referenced vertices here\r
-                               if (totweight > 0 && !pDW.isNull()) {// pDW should never be null here, but I check it just in case :)\r
-                                       int weightIndex = 0;\r
-                                       List<Structure> dw = pDW.fetchData(dataRepository.getInputStream());\r
-                                       for (Structure deformWeight : dw) {\r
-                                               Integer boneIndex = groupToBoneIndexMap.get(((Number) deformWeight.getFieldValue("def_nr")).intValue());\r
-                                               if (boneIndex != null) {// null here means that we came accross group that has no bone attached to\r
-                                                       float weight = ((Number) deformWeight.getFieldValue("weight")).floatValue();\r
-                                                       if (weight == 0.0f) {\r
-                                                               weight = 1;\r
-                                                               boneIndex = Integer.valueOf(0);\r
-                                                       }\r
-                                                       // we apply the weight to all referenced vertices\r
-                                                       for (Integer index : vertexIndices) {\r
-                                                               // all indices are always assigned to 0-indexed bone\r
-                                                               // weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + weightIndex, 1.0f);\r
-                                                               // indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + weightIndex, (byte)0);\r
-                                                               // if(weight != 0.0f) {\r
-                                                               weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + weightIndex, weight);\r
-                                                               indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + weightIndex, boneIndex.byteValue());\r
-                                                               // }\r
-                                                       }\r
-                                               }\r
-                                               ++weightIndex;\r
-                                       }\r
-                               } else {\r
-                                       for (Integer index : vertexIndices) {\r
-                                               weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX, 1.0f);\r
-                                               indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX, (byte) 0);\r
-                                       }\r
-                               }\r
-                               ++vertexIndex;\r
-                       }\r
-               } else {\r
-                       // always bind all vertices to 0-indexed bone\r
-                       // this bone makes the model look normally if vertices have no bone assigned\r
-                       // and it is used in object animation, so if we come accross object animation\r
-                       // we can use the 0-indexed bone for this\r
-                       for (List<Integer> vertexIndexList : vertexReferenceMap.values()) {\r
-                               // we apply the weight to all referenced vertices\r
-                               for (Integer index : vertexIndexList) {\r
-                                       weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX, 1.0f);\r
-                                       indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX, (byte) 0);\r
-                               }\r
-                       }\r
-               }\r
-\r
-               bonesGroups[0] = this.endBoneAssigns(vertexListSize, weightsFloatData);\r
-               VertexBuffer verticesWeights = new VertexBuffer(Type.BoneWeight);\r
-               verticesWeights.setupData(Usage.CpuOnly, bonesGroups[0], Format.Float, weightsFloatData);\r
-\r
-               VertexBuffer verticesWeightsIndices = new VertexBuffer(Type.BoneIndex);\r
-               verticesWeightsIndices.setupData(Usage.CpuOnly, bonesGroups[0], Format.UnsignedByte, indicesData);\r
-               return new VertexBuffer[] { verticesWeights, verticesWeightsIndices };\r
-       }\r
-\r
-       /**\r
-        * Normalizes weights if needed and finds largest amount of weights used for all vertices in the buffer.\r
-        */\r
-       protected int endBoneAssigns(int vertCount, FloatBuffer weightsFloatData) {\r
-               int maxWeightsPerVert = 0;\r
-               weightsFloatData.rewind();\r
-               for (int v = 0; v < vertCount; ++v) {\r
-                       float w0 = weightsFloatData.get(), w1 = weightsFloatData.get(), w2 = weightsFloatData.get(), w3 = weightsFloatData.get();\r
-\r
-                       if (w3 != 0) {\r
-                               maxWeightsPerVert = Math.max(maxWeightsPerVert, 4);\r
-                       } else if (w2 != 0) {\r
-                               maxWeightsPerVert = Math.max(maxWeightsPerVert, 3);\r
-                       } else if (w1 != 0) {\r
-                               maxWeightsPerVert = Math.max(maxWeightsPerVert, 2);\r
-                       } else if (w0 != 0) {\r
-                               maxWeightsPerVert = Math.max(maxWeightsPerVert, 1);\r
-                       }\r
-\r
-                       float sum = w0 + w1 + w2 + w3;\r
-                       if (sum != 1f && sum != 0.0f) {\r
-                               weightsFloatData.position(weightsFloatData.position() - 4);\r
-                               // compute new vals based on sum\r
-                               float sumToB = 1f / sum;\r
-                               weightsFloatData.put(w0 * sumToB);\r
-                               weightsFloatData.put(w1 * sumToB);\r
-                               weightsFloatData.put(w2 * sumToB);\r
-                               weightsFloatData.put(w3 * sumToB);\r
-                       }\r
-               }\r
-               weightsFloatData.rewind();\r
-\r
-               // mesh.setMaxNumWeights(maxWeightsPerVert);\r
-               return maxWeightsPerVert;\r
-       }\r
+\r
+    protected static final int MAXIMUM_WEIGHTS_PER_VERTEX = 4; // have no idea why 4, could someone please explain ?\r
+\r
+    /**\r
+     * This constructor parses the given blender version and stores the result. Some functionalities may differ in different blender\r
+     * versions.\r
+     * \r
+     * @param blenderVersion\r
+     *            the version read from the blend file\r
+     */\r
+    public MeshHelper(String blenderVersion) {\r
+        super(blenderVersion);\r
+    }\r
+\r
+    /**\r
+     * This method reads converts the given structure into mesh. The given structure needs to be filled with the appropriate data.\r
+     * \r
+     * @param structure\r
+     *            the structure we read the mesh from\r
+     * @return the mesh feature\r
+     * @throws BlenderFileException\r
+     */\r
+    @SuppressWarnings("unchecked")\r
+    public List<Geometry> toMesh(Structure structure, DataRepository dataRepository) throws BlenderFileException {\r
+        List<Geometry> geometries = (List<Geometry>) dataRepository.getLoadedFeature(structure.getOldMemoryAddress(),\r
+                LoadedFeatureDataType.LOADED_FEATURE);\r
+        if (geometries != null) {\r
+            List<Geometry> copiedGeometries = new ArrayList<Geometry>(geometries.size());\r
+            for (Geometry geometry : geometries) {\r
+                copiedGeometries.add(geometry.clone());\r
+            }\r
+            return copiedGeometries;\r
+        }\r
+\r
+        // helpers\r
+        TextureHelper textureHelper = dataRepository.getHelper(TextureHelper.class);\r
+\r
+        // reading mesh data\r
+        String name = structure.getName();\r
+\r
+        // reading vertices\r
+        Vector3f[] vertices = this.getVertices(structure, dataRepository);\r
+        int verticesAmount = vertices.length;\r
+\r
+        // vertices Colors\r
+        List<float[]> verticesColors = this.getVerticesColors(structure, dataRepository);\r
+\r
+        // reading faces\r
+        // the following map sorts faces by material number (because in jme Mesh can have only one material)\r
+        Map<Integer, List<Integer>> meshesMap = new HashMap<Integer, List<Integer>>();\r
+        Pointer pMFace = (Pointer) structure.getFieldValue("mface");\r
+        List<Structure> mFaces = pMFace.fetchData(dataRepository.getInputStream());\r
+\r
+        Pointer pMTFace = (Pointer) structure.getFieldValue("mtface");\r
+        List<Vector2f> uvCoordinates = null;\r
+        List<Structure> mtFaces = null;\r
+\r
+        if (!pMTFace.isNull()) {\r
+            mtFaces = pMTFace.fetchData(dataRepository.getInputStream());\r
+            int facesAmount = ((Number) structure.getFieldValue("totface")).intValue();\r
+            if (mtFaces.size() != facesAmount) {\r
+                throw new BlenderFileException("The amount of faces uv coordinates is not equal to faces amount!");\r
+            }\r
+            uvCoordinates = new ArrayList<Vector2f>();// TODO: calculate the amount of coordinates if possible\r
+        }\r
+\r
+        // normalMap merges normals of faces that will be rendered smooth\r
+        Map<Vector3f, Vector3f> normalMap = new HashMap<Vector3f, Vector3f>(verticesAmount);\r
+\r
+        List<Vector3f> normalList = new ArrayList<Vector3f>();\r
+        List<Vector3f> vertexList = new ArrayList<Vector3f>();\r
+        Map<Integer, Texture> materialNumberToTexture = new HashMap<Integer, Texture>();// indicates if the material with the specified\r
+        // number should have a texture attached\r
+        // this map's key is the vertex index from 'vertices 'table and the value are indices from 'vertexList'\r
+        // positions (it simply tells which vertex is referenced where in the result list)\r
+        Map<Integer, List<Integer>> vertexReferenceMap = new HashMap<Integer, List<Integer>>(verticesAmount);\r
+        int vertexColorIndex = 0;\r
+        for (int i = 0; i < mFaces.size(); ++i) {\r
+            Structure mFace = mFaces.get(i);\r
+            boolean smooth = (((Number) mFace.getFieldValue("flag")).byteValue() & 0x01) != 0x00;\r
+            DynamicArray<Number> uvs = null;\r
+            boolean materialWithoutTextures = false;\r
+            Pointer pImage = null;\r
+            if (mtFaces != null) {\r
+                Structure mtFace = mtFaces.get(i);\r
+                pImage = (Pointer) mtFace.getFieldValue("tpage");\r
+                materialWithoutTextures = pImage.isNull();\r
+                // uvs always must be added wheater we have texture or not\r
+                uvs = (DynamicArray<Number>) mtFace.getFieldValue("uv");\r
+                uvCoordinates.add(new Vector2f(uvs.get(0, 0).floatValue(), uvs.get(0, 1).floatValue()));\r
+                uvCoordinates.add(new Vector2f(uvs.get(1, 0).floatValue(), uvs.get(1, 1).floatValue()));\r
+                uvCoordinates.add(new Vector2f(uvs.get(2, 0).floatValue(), uvs.get(2, 1).floatValue()));\r
+            }\r
+            int matNr = ((Number) mFace.getFieldValue("mat_nr")).intValue();\r
+            Integer materialNumber = Integer.valueOf(materialWithoutTextures ? -1 * matNr - 1 : matNr);\r
+            List<Integer> indexList = meshesMap.get(materialNumber);\r
+            if (indexList == null) {\r
+                indexList = new ArrayList<Integer>();\r
+                meshesMap.put(materialNumber, indexList);\r
+            }\r
+            if (pImage != null && !pImage.isNull() && !materialNumberToTexture.containsKey(materialNumber)) {// attaching image to texture\r
+                // (face can have UV's and\r
+                // image whlie its material\r
+                // may have no texture\r
+                // attached)\r
+                Texture texture = textureHelper.getTextureFromImage(pImage.fetchData(dataRepository.getInputStream()).get(0),\r
+                        dataRepository);\r
+                if (texture != null) {\r
+                    materialNumberToTexture.put(materialNumber, texture);\r
+                }\r
+            }\r
+\r
+            int v1 = ((Number) mFace.getFieldValue("v1")).intValue();\r
+            int v2 = ((Number) mFace.getFieldValue("v2")).intValue();\r
+            int v3 = ((Number) mFace.getFieldValue("v3")).intValue();\r
+            int v4 = ((Number) mFace.getFieldValue("v4")).intValue();\r
+\r
+            Vector3f n = FastMath.computeNormal(vertices[v1], vertices[v2], vertices[v3]);\r
+            this.addNormal(n, normalMap, smooth, vertices[v1], vertices[v2], vertices[v3]);\r
+            normalList.add(normalMap.get(vertices[v1]));\r
+            normalList.add(normalMap.get(vertices[v2]));\r
+            normalList.add(normalMap.get(vertices[v3]));\r
+\r
+            this.appendVertexReference(v1, vertexList.size(), vertexReferenceMap);\r
+            indexList.add(vertexList.size());\r
+            vertexList.add(vertices[v1]);\r
+\r
+            this.appendVertexReference(v2, vertexList.size(), vertexReferenceMap);\r
+            indexList.add(vertexList.size());\r
+            vertexList.add(vertices[v2]);\r
+\r
+            this.appendVertexReference(v3, vertexList.size(), vertexReferenceMap);\r
+            indexList.add(vertexList.size());\r
+            vertexList.add(vertices[v3]);\r
+\r
+            if (v4 > 0) {\r
+                if (uvs != null) {\r
+                    uvCoordinates.add(new Vector2f(uvs.get(0, 0).floatValue(), uvs.get(0, 1).floatValue()));\r
+                    uvCoordinates.add(new Vector2f(uvs.get(2, 0).floatValue(), uvs.get(2, 1).floatValue()));\r
+                    uvCoordinates.add(new Vector2f(uvs.get(3, 0).floatValue(), uvs.get(3, 1).floatValue()));\r
+                }\r
+                this.appendVertexReference(v1, vertexList.size(), vertexReferenceMap);\r
+                indexList.add(vertexList.size());\r
+                vertexList.add(vertices[v1]);\r
+\r
+                this.appendVertexReference(v3, vertexList.size(), vertexReferenceMap);\r
+                indexList.add(vertexList.size());\r
+                vertexList.add(vertices[v3]);\r
+\r
+                this.appendVertexReference(v4, vertexList.size(), vertexReferenceMap);\r
+                indexList.add(vertexList.size());\r
+                vertexList.add(vertices[v4]);\r
+\r
+                this.addNormal(n, normalMap, smooth, vertices[v4]);\r
+                normalList.add(normalMap.get(vertices[v1]));\r
+                normalList.add(normalMap.get(vertices[v3]));\r
+                normalList.add(normalMap.get(vertices[v4]));\r
+\r
+                if (verticesColors != null) {\r
+                    verticesColors.add(vertexColorIndex + 3, verticesColors.get(vertexColorIndex));\r
+                    verticesColors.add(vertexColorIndex + 4, verticesColors.get(vertexColorIndex + 2));\r
+                }\r
+                vertexColorIndex += 6;\r
+            } else {\r
+                if (verticesColors != null) {\r
+                    verticesColors.remove(vertexColorIndex + 3);\r
+                    vertexColorIndex += 3;\r
+                }\r
+            }\r
+        }\r
+        Vector3f[] normals = normalList.toArray(new Vector3f[normalList.size()]);\r
+\r
+        // reading vertices groups (from the parent)\r
+        Structure parent = dataRepository.peekParent();\r
+        Structure defbase = (Structure) parent.getFieldValue("defbase");\r
+        List<Structure> defs = defbase.evaluateListBase(dataRepository);\r
+        String[] verticesGroups = new String[defs.size()];\r
+        int defIndex = 0;\r
+        for (Structure def : defs) {\r
+            verticesGroups[defIndex++] = def.getFieldValue("name").toString();\r
+        }\r
+\r
+        // vertices bone weights and indices\r
+        ArmatureHelper armatureHelper = dataRepository.getHelper(ArmatureHelper.class);\r
+        Structure defBase = (Structure) parent.getFieldValue("defbase");\r
+        Map<Integer, Integer> groupToBoneIndexMap = armatureHelper.getGroupToBoneIndexMap(defBase, dataRepository);\r
+\r
+        VertexBuffer verticesWeights = null, verticesWeightsIndices = null;\r
+        int[] bonesGroups = new int[]{0};\r
+        VertexBuffer[] boneWeightsAndIndex = this.getBoneWeightAndIndexBuffer(structure, vertexList.size(), bonesGroups,\r
+                vertexReferenceMap, groupToBoneIndexMap, dataRepository);\r
+        verticesWeights = boneWeightsAndIndex[0];\r
+        verticesWeightsIndices = boneWeightsAndIndex[1];\r
+\r
+        // reading materials\r
+        MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);\r
+        Material[] materials = null;\r
+        Material[] nonTexturedMaterials = null;\r
+        if ((dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.MATERIALS) != 0) {\r
+            materials = materialHelper.getMaterials(structure, dataRepository);\r
+            nonTexturedMaterials = materials == null ? null : new Material[materials.length];// fill it when needed\r
+        }\r
+\r
+        // creating the result meshes\r
+        geometries = new ArrayList<Geometry>(meshesMap.size());\r
+\r
+        VertexBuffer verticesBuffer = new VertexBuffer(Type.Position);\r
+        verticesBuffer.setupData(Usage.Stream, 3, Format.Float,\r
+                BufferUtils.createFloatBuffer(vertexList.toArray(new Vector3f[vertexList.size()])));\r
+\r
+        // initial vertex position (used with animation)\r
+        VertexBuffer verticesBind = new VertexBuffer(Type.BindPosePosition);\r
+        verticesBind.setupData(Usage.CpuOnly, 3, Format.Float, BufferUtils.clone(verticesBuffer.getData()));\r
+\r
+        VertexBuffer normalsBuffer = new VertexBuffer(Type.Normal);\r
+        normalsBuffer.setupData(Usage.Stream, 3, Format.Float, BufferUtils.createFloatBuffer(normals));\r
+\r
+        // initial normals position (used with animation)\r
+        VertexBuffer normalsBind = new VertexBuffer(Type.BindPoseNormal);\r
+        normalsBind.setupData(Usage.CpuOnly, 3, Format.Float, BufferUtils.clone(normalsBuffer.getData()));\r
+\r
+        VertexBuffer uvCoordsBuffer = null;\r
+        if (uvCoordinates != null) {\r
+            uvCoordsBuffer = new VertexBuffer(Type.TexCoord);\r
+            uvCoordsBuffer.setupData(Usage.Static, 2, Format.Float,\r
+                    BufferUtils.createFloatBuffer(uvCoordinates.toArray(new Vector2f[uvCoordinates.size()])));\r
+        }\r
+\r
+        // generating meshes\r
+        FloatBuffer verticesColorsBuffer = this.createFloatBuffer(verticesColors);\r
+        for (Entry<Integer, List<Integer>> meshEntry : meshesMap.entrySet()) {\r
+            Mesh mesh = new Mesh();\r
+\r
+            // creating vertices indices for this mesh\r
+            List<Integer> indexList = meshEntry.getValue();\r
+            short[] indices = new short[indexList.size()];//TODO: check if the model doesn't have more than 32767 vertices\r
+            for (int i = 0; i < indexList.size(); ++i) {//if yes then mesh.getVertices method must be changed to accept other than ShortBuffer\r
+                indices[i] = indexList.get(i).shortValue();\r
+            }\r
+\r
+            // setting vertices\r
+            mesh.setBuffer(Type.Index, 1, BufferUtils.createShortBuffer(indices));\r
+            mesh.setBuffer(verticesBuffer);\r
+            mesh.setBuffer(verticesBind);\r
+\r
+            // setting vertices colors\r
+            if (verticesColorsBuffer != null) {\r
+                mesh.setBuffer(Type.Color, 4, verticesColorsBuffer);\r
+            }\r
+\r
+            // setting weights for bones\r
+            if (verticesWeights != null) {\r
+                mesh.setMaxNumWeights(bonesGroups[0]);\r
+                mesh.setBuffer(verticesWeights);\r
+                mesh.setBuffer(verticesWeightsIndices);\r
+            }\r
+\r
+            // setting faces' normals\r
+            mesh.setBuffer(normalsBuffer);\r
+            mesh.setBuffer(normalsBind);\r
+\r
+            // setting uvCoords\r
+            if (uvCoordsBuffer != null) {\r
+                mesh.setBuffer(uvCoordsBuffer);\r
+            }\r
+\r
+            // creating the result\r
+            Geometry geometry = new Geometry(name + (geometries.size() + 1), mesh);\r
+            if (materials != null) {\r
+                int materialNumber = meshEntry.getKey().intValue();\r
+                Material material;\r
+                if (materialNumber >= 0) {\r
+                    material = materials[materialNumber];\r
+                    if (materialNumberToTexture.containsKey(Integer.valueOf(materialNumber))) {\r
+                        if (material.getMaterialDef().getAssetName().contains("Lighting")) {\r
+                            if (!materialHelper.hasTexture(material, MaterialHelper.TEXTURE_TYPE_DIFFUSE)) {\r
+                                material = material.clone();\r
+                                material.setTexture(MaterialHelper.TEXTURE_TYPE_DIFFUSE,\r
+                                        materialNumberToTexture.get(Integer.valueOf(materialNumber)));\r
+                            }\r
+                        } else {\r
+                            if (!materialHelper.hasTexture(material, MaterialHelper.TEXTURE_TYPE_COLOR)) {\r
+                                material = material.clone();\r
+                                material.setTexture(MaterialHelper.TEXTURE_TYPE_COLOR,\r
+                                        materialNumberToTexture.get(Integer.valueOf(materialNumber)));\r
+                            }\r
+                        }\r
+                    }\r
+                } else {\r
+                    materialNumber = -1 * (materialNumber + 1);\r
+                    if (nonTexturedMaterials[materialNumber] == null) {\r
+                        nonTexturedMaterials[materialNumber] = materialHelper.getNonTexturedMaterial(materials[materialNumber],\r
+                                TextureHelper.TEX_IMAGE);\r
+                    }\r
+                    material = nonTexturedMaterials[materialNumber];\r
+                }\r
+                geometry.setMaterial(material);\r
+            } else {\r
+                geometry.setMaterial(dataRepository.getDefaultMaterial());\r
+            }\r
+            geometries.add(geometry);\r
+        }\r
+        dataRepository.addLoadedFeatures(structure.getOldMemoryAddress(), structure.getName(), structure, geometries);\r
+        return geometries;\r
+    }\r
+\r
+    /**\r
+     * This method adds a normal to a normals' map. This map is used to merge normals of a vertor that should be rendered smooth.\r
+     * \r
+     * @param normalToAdd\r
+     *            a normal to be added\r
+     * @param normalMap\r
+     *            merges normals of faces that will be rendered smooth; the key is the vertex and the value - its normal vector\r
+     * @param smooth\r
+     *            the variable that indicates wheather to merge normals (creating the smooth mesh) or not\r
+     * @param vertices\r
+     *            a list of vertices read from the blender file\r
+     */\r
+    protected void addNormal(Vector3f normalToAdd, Map<Vector3f, Vector3f> normalMap, boolean smooth, Vector3f... vertices) {\r
+        for (Vector3f v : vertices) {\r
+            Vector3f n = normalMap.get(v);\r
+            if (!smooth || n == null) {\r
+                normalMap.put(v, normalToAdd.clone());\r
+            } else {\r
+                n.addLocal(normalToAdd).normalizeLocal();\r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
+     * This method fills the vertex reference map. The vertices are loaded once and referenced many times in the model. This map is created\r
+     * to tell where the basic vertices are referenced in the result vertex lists. The key of the map is the basic vertex index, and its key\r
+     * - the reference indices list.\r
+     * \r
+     * @param basicVertexIndex\r
+     *            the index of the vertex from its basic table\r
+     * @param resultIndex\r
+     *            the index of the vertex in its result vertex list\r
+     * @param vertexReferenceMap\r
+     *            the reference map\r
+     */\r
+    protected void appendVertexReference(int basicVertexIndex, int resultIndex, Map<Integer, List<Integer>> vertexReferenceMap) {\r
+        List<Integer> referenceList = vertexReferenceMap.get(Integer.valueOf(basicVertexIndex));\r
+        if (referenceList == null) {\r
+            referenceList = new ArrayList<Integer>();\r
+            vertexReferenceMap.put(Integer.valueOf(basicVertexIndex), referenceList);\r
+        }\r
+        referenceList.add(Integer.valueOf(resultIndex));\r
+    }\r
+\r
+    /**\r
+     * This method returns the vertices colors. Each vertex is stored in float[4] array.\r
+     * \r
+     * @param meshStructure\r
+     *            the structure containing the mesh data\r
+     * @param dataRepository\r
+     *            the data repository\r
+     * @return a list of vertices colors, each color belongs to a single vertex\r
+     * @throws BlenderFileException\r
+     *             this exception is thrown when the blend file structure is somehow invalid or corrupted\r
+     */\r
+    public List<float[]> getVerticesColors(Structure meshStructure, DataRepository dataRepository) throws BlenderFileException {\r
+        Pointer pMCol = (Pointer) meshStructure.getFieldValue("mcol");\r
+        List<float[]> verticesColors = null;\r
+        List<Structure> mCol = null;\r
+        if (!pMCol.isNull()) {\r
+            verticesColors = new LinkedList<float[]>();\r
+            mCol = pMCol.fetchData(dataRepository.getInputStream());\r
+            for (Structure color : mCol) {\r
+                float r = ((Number) color.getFieldValue("r")).byteValue() / 256.0f;\r
+                float g = ((Number) color.getFieldValue("g")).byteValue() / 256.0f;\r
+                float b = ((Number) color.getFieldValue("b")).byteValue() / 256.0f;\r
+                float a = ((Number) color.getFieldValue("a")).byteValue() / 256.0f;\r
+                verticesColors.add(new float[]{b, g, r, a});\r
+            }\r
+        }\r
+        return verticesColors;\r
+    }\r
+\r
+    /**\r
+     * This method returns the vertices.\r
+     * \r
+     * @param meshStructure\r
+     *            the structure containing the mesh data\r
+     * @param dataRepository\r
+     *            the data repository\r
+     * @return a list of vertices colors, each color belongs to a single vertex\r
+     * @throws BlenderFileException\r
+     *             this exception is thrown when the blend file structure is somehow invalid or corrupted\r
+     */\r
+    @SuppressWarnings("unchecked")\r
+    public Vector3f[] getVertices(Structure meshStructure, DataRepository dataRepository) throws BlenderFileException {\r
+        int verticesAmount = ((Number) meshStructure.getFieldValue("totvert")).intValue();\r
+        Vector3f[] vertices = new Vector3f[verticesAmount];\r
+        Pointer pMVert = (Pointer) meshStructure.getFieldValue("mvert");\r
+        List<Structure> mVerts = pMVert.fetchData(dataRepository.getInputStream());\r
+        for (int i = 0; i < verticesAmount; ++i) {\r
+            DynamicArray<Number> coordinates = (DynamicArray<Number>) mVerts.get(i).getFieldValue("co");\r
+            vertices[i] = new Vector3f(coordinates.get(0).floatValue(), coordinates.get(1).floatValue(), coordinates.get(2).floatValue());\r
+        }\r
+        return vertices;\r
+    }\r
+\r
+    /**\r
+     * This method returns an array of size 2. The first element is a vertex buffer holding bone weights for every vertex in the model. The\r
+     * second element is a vertex buffer holding bone indices for vertices (the indices of bones the vertices are assigned to).\r
+     * \r
+     * @param meshStructure\r
+     *            the mesh structure object\r
+     * @param vertexListSize\r
+     *            a number of vertices in the model\r
+     * @param bonesGroups\r
+     *            this is an output parameter, it should be a one-sized array; the maximum amount of weights per vertex (up to\r
+     *            MAXIMUM_WEIGHTS_PER_VERTEX) is stored there\r
+     * @param vertexReferenceMap\r
+     *            this reference map allows to map the original vertices read from blender to vertices that are really in the model; one\r
+     *            vertex may appear several times in the result model\r
+     * @param groupToBoneIndexMap\r
+     *            this object maps the group index (to which a vertices in blender belong) to bone index of the model\r
+     * @param dataRepository\r
+     *            the data repository\r
+     * @return arrays of vertices weights and their bone indices and (as an outpot parameter) the maximum amount of weights for a vertex\r
+     * @throws BlenderFileException\r
+     *             this exception is thrown when the blend file structure is somehow invalid or corrupted\r
+     */\r
+    public VertexBuffer[] getBoneWeightAndIndexBuffer(Structure meshStructure, int vertexListSize, int[] bonesGroups,\r
+            Map<Integer, List<Integer>> vertexReferenceMap, Map<Integer, Integer> groupToBoneIndexMap, DataRepository dataRepository)\r
+            throws BlenderFileException {\r
+        Pointer pDvert = (Pointer) meshStructure.getFieldValue("dvert");// dvert = DeformVERTices\r
+        FloatBuffer weightsFloatData = BufferUtils.createFloatBuffer(vertexListSize * MAXIMUM_WEIGHTS_PER_VERTEX);\r
+        ByteBuffer indicesData = BufferUtils.createByteBuffer(vertexListSize * MAXIMUM_WEIGHTS_PER_VERTEX);\r
+        if (!pDvert.isNull()) {// assigning weights and bone indices\r
+            List<Structure> dverts = pDvert.fetchData(dataRepository.getInputStream());// dverts.size() == verticesAmount (one dvert per\r
+            // vertex in blender)\r
+            int vertexIndex = 0;\r
+            for (Structure dvert : dverts) {\r
+                int totweight = ((Number) dvert.getFieldValue("totweight")).intValue();// total amount of weights assignet to the vertex\r
+                // (max. 4 in JME)\r
+                Pointer pDW = (Pointer) dvert.getFieldValue("dw");\r
+                List<Integer> vertexIndices = vertexReferenceMap.get(Integer.valueOf(vertexIndex));// we fetch the referenced vertices here\r
+                if (totweight > 0 && !pDW.isNull()) {// pDW should never be null here, but I check it just in case :)\r
+                    int weightIndex = 0;\r
+                    List<Structure> dw = pDW.fetchData(dataRepository.getInputStream());\r
+                    for (Structure deformWeight : dw) {\r
+                        Integer boneIndex = groupToBoneIndexMap.get(((Number) deformWeight.getFieldValue("def_nr")).intValue());\r
+                        if (boneIndex != null) {// null here means that we came accross group that has no bone attached to\r
+                            float weight = ((Number) deformWeight.getFieldValue("weight")).floatValue();\r
+                            if (weight == 0.0f) {\r
+                                weight = 1;\r
+                                boneIndex = Integer.valueOf(0);\r
+                            }\r
+                            // we apply the weight to all referenced vertices\r
+                            for (Integer index : vertexIndices) {\r
+                                // all indices are always assigned to 0-indexed bone\r
+                                // weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + weightIndex, 1.0f);\r
+                                // indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + weightIndex, (byte)0);\r
+                                // if(weight != 0.0f) {\r
+                                weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + weightIndex, weight);\r
+                                indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + weightIndex, boneIndex.byteValue());\r
+                                // }\r
+                            }\r
+                        }\r
+                        ++weightIndex;\r
+                    }\r
+                } else {\r
+                    for (Integer index : vertexIndices) {\r
+                        weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX, 1.0f);\r
+                        indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX, (byte) 0);\r
+                    }\r
+                }\r
+                ++vertexIndex;\r
+            }\r
+        } else {\r
+            // always bind all vertices to 0-indexed bone\r
+            // this bone makes the model look normally if vertices have no bone assigned\r
+            // and it is used in object animation, so if we come accross object animation\r
+            // we can use the 0-indexed bone for this\r
+            for (List<Integer> vertexIndexList : vertexReferenceMap.values()) {\r
+                // we apply the weight to all referenced vertices\r
+                for (Integer index : vertexIndexList) {\r
+                    weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX, 1.0f);\r
+                    indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX, (byte) 0);\r
+                }\r
+            }\r
+        }\r
+\r
+        bonesGroups[0] = this.endBoneAssigns(vertexListSize, weightsFloatData);\r
+        VertexBuffer verticesWeights = new VertexBuffer(Type.BoneWeight);\r
+        verticesWeights.setupData(Usage.CpuOnly, bonesGroups[0], Format.Float, weightsFloatData);\r
+\r
+        VertexBuffer verticesWeightsIndices = new VertexBuffer(Type.BoneIndex);\r
+        verticesWeightsIndices.setupData(Usage.CpuOnly, bonesGroups[0], Format.UnsignedByte, indicesData);\r
+        return new VertexBuffer[]{verticesWeights, verticesWeightsIndices};\r
+    }\r
+\r
+    /**\r
+     * Normalizes weights if needed and finds largest amount of weights used for all vertices in the buffer.\r
+     */\r
+    protected int endBoneAssigns(int vertCount, FloatBuffer weightsFloatData) {\r
+        int maxWeightsPerVert = 0;\r
+        weightsFloatData.rewind();\r
+        for (int v = 0; v < vertCount; ++v) {\r
+            float w0 = weightsFloatData.get(), w1 = weightsFloatData.get(), w2 = weightsFloatData.get(), w3 = weightsFloatData.get();\r
+\r
+            if (w3 != 0) {\r
+                maxWeightsPerVert = Math.max(maxWeightsPerVert, 4);\r
+            } else if (w2 != 0) {\r
+                maxWeightsPerVert = Math.max(maxWeightsPerVert, 3);\r
+            } else if (w1 != 0) {\r
+                maxWeightsPerVert = Math.max(maxWeightsPerVert, 2);\r
+            } else if (w0 != 0) {\r
+                maxWeightsPerVert = Math.max(maxWeightsPerVert, 1);\r
+            }\r
+\r
+            float sum = w0 + w1 + w2 + w3;\r
+            if (sum != 1f && sum != 0.0f) {\r
+                weightsFloatData.position(weightsFloatData.position() - 4);\r
+                // compute new vals based on sum\r
+                float sumToB = 1f / sum;\r
+                weightsFloatData.put(w0 * sumToB);\r
+                weightsFloatData.put(w1 * sumToB);\r
+                weightsFloatData.put(w2 * sumToB);\r
+                weightsFloatData.put(w3 * sumToB);\r
+            }\r
+        }\r
+        weightsFloatData.rewind();\r
+\r
+        // mesh.setMaxNumWeights(maxWeightsPerVert);\r
+        return maxWeightsPerVert;\r
+    }\r
 }\r
index 09ec8e2..8799454 100644 (file)
@@ -77,465 +77,466 @@ import com.jme3.scene.plugins.ogre.AnimData;
  * @author Marcin Roguski\r
  */\r
 public class ModifierHelper extends AbstractBlenderHelper {\r
-       private static final Logger                     LOGGER          = Logger.getLogger(ModifierHelper.class.getName());\r
-       \r
-       /**\r
-        * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
-        * different blender versions.\r
-        * @param blenderVersion\r
-        *        the version read from the blend file\r
-        */\r
-       public ModifierHelper(String blenderVersion) {\r
-               super(blenderVersion);\r
-       }\r
-\r
-       /**\r
-        * This method applies modifier to the object.\r
-        * @param node\r
-        *        the loaded object\r
-        * @param modifier\r
-        *        the modifier to apply\r
-        * @param dataRepository\r
-        *        the data repository\r
-        * @return the node to whom the modifier was applied\r
-        */\r
-       public Node applyModifier(Node node, Modifier modifier, DataRepository dataRepository) {\r
-               if(Modifier.ARMATURE_MODIFIER_DATA.equals(modifier.getType())) {\r
-                       return this.applyArmatureModifierData(node, modifier, dataRepository);\r
-               } else if(Modifier.ARRAY_MODIFIER_DATA.equals(modifier.getType())) {\r
-                       return this.applyArrayModifierData(node, modifier, dataRepository);\r
-               } else if(Modifier.PARTICLE_MODIFIER_DATA.equals(modifier.getType())) {\r
-                       return this.applyParticleSystemModifierData(node, modifier, dataRepository);\r
-               } else {\r
-                       LOGGER.warning("Modifier: " + modifier.getType() + " not yet implemented!!!");\r
-                       return node;\r
-               }\r
-       }\r
-       \r
-       /**\r
-        * This method reads the given object's modifiers.\r
-        * @param objectStructure\r
-        *        the object structure\r
-        * @param dataRepository\r
-        *        the data repository\r
-        * @param converter\r
-        *        the converter object (in some cases we need to read an object first before loading the modifier)\r
-        * @throws BlenderFileException\r
-        *         this exception is thrown when the blender file is somehow corrupted\r
-        */\r
-       @SuppressWarnings("unchecked")\r
-       public void readModifiers(Structure objectStructure, DataRepository dataRepository) throws BlenderFileException {\r
-               Structure modifiersListBase = (Structure)objectStructure.getFieldValue("modifiers");\r
-               List<Structure> modifiers = modifiersListBase.evaluateListBase(dataRepository);\r
-               for(Structure modifier : modifiers) {\r
-                       Object loadedModifier = null;\r
-                       Object modifierAdditionalData = null;\r
-                       if(Modifier.ARRAY_MODIFIER_DATA.equals(modifier.getType())) {//****************ARRAY MODIFIER\r
-                               Map<String, Object> params = new HashMap<String, Object>();\r
-                               \r
-                               Number fittype = (Number) modifier.getFieldValue("fit_type");\r
-                               params.put("fittype", fittype);\r
-                               switch(fittype.intValue()) {\r
-                                       case 0://FIXED COUNT\r
-                                               params.put("count", modifier.getFieldValue("count"));\r
-                                               break;\r
-                                       case 1://FIXED LENGTH\r
-                                               params.put("length", modifier.getFieldValue("length"));\r
-                                               break;\r
-                                       case 2://FITCURVE\r
-                                               //TODO: implement after loading curves is added; warning will be generated during modifier applying\r
-                                               break;\r
-                                       default:\r
-                                               assert false : "Unknown array modifier fit type: " + fittype;\r
-                               }\r
-                               \r
-                               //offset parameters\r
-                               int offsettype = ((Number) modifier.getFieldValue("offset_type")).intValue();\r
-                               if((offsettype & 0x01) != 0) {//Constant offset\r
-                                       DynamicArray<Number> offsetArray = (DynamicArray<Number>)modifier.getFieldValue("offset");\r
-                                       float[] offset = new float[] {offsetArray.get(0).floatValue(), offsetArray.get(1).floatValue(), offsetArray.get(2).floatValue()};\r
-                                       params.put("offset", offset);\r
-                               }\r
-                               if((offsettype & 0x02) != 0) {//Relative offset\r
-                                       DynamicArray<Number> scaleArray = (DynamicArray<Number>)modifier.getFieldValue("scale");\r
-                                       float[] scale = new float[] {scaleArray.get(0).floatValue(), scaleArray.get(1).floatValue(), scaleArray.get(2).floatValue()};\r
-                                       params.put("scale", scale);\r
-                               }\r
-                               if((offsettype & 0x04) != 0) {//Object offset\r
-                                       Pointer pOffsetObject = (Pointer)modifier.getFieldValue("offset_ob");\r
-                                       if(!pOffsetObject.isNull()) {\r
-                                               params.put("offsetob", pOffsetObject);\r
-                                       }\r
-                               }\r
-                               \r
-                               //start cap and end cap\r
-                               Pointer pStartCap = (Pointer)modifier.getFieldValue("start_cap");\r
-                               if(!pStartCap.isNull()) {\r
-                                       params.put("startcap", pStartCap);\r
-                               }\r
-                               Pointer pEndCap = (Pointer)modifier.getFieldValue("end_cap");\r
-                               if(!pEndCap.isNull()) {\r
-                                       params.put("endcap", pEndCap);\r
-                               }\r
-                               loadedModifier = params;\r
-                       } else if(Modifier.ARMATURE_MODIFIER_DATA.equals(modifier.getType())) {//****************ARMATURE MODIFIER\r
-                               Pointer pArmatureObject = (Pointer)modifier.getFieldValue("object");\r
-                               if(!pArmatureObject.isNull()) {\r
-                                       ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);\r
-                                       Structure armatureObject = (Structure)dataRepository.getLoadedFeature(pArmatureObject.getOldMemoryAddress(), LoadedFeatureDataType.LOADED_STRUCTURE);\r
-                                       if(armatureObject == null) {//we check this first not to fetch the structure unnecessary\r
-                                               armatureObject = pArmatureObject.fetchData(dataRepository.getInputStream()).get(0);\r
-                                               objectHelper.toObject(armatureObject, dataRepository);\r
-                                       }\r
-                                       modifierAdditionalData = armatureObject.getOldMemoryAddress();\r
-                                       ArmatureHelper armatureHelper = dataRepository.getHelper(ArmatureHelper.class);\r
-\r
-                                       //changing bones matrices so that they fit the current object (taht is why we need a copy of a skeleton)\r
-                                       Matrix4f armatureObjectMatrix = objectHelper.getTransformationMatrix(armatureObject);\r
-                                       Matrix4f inverseMeshObjectMatrix = objectHelper.getTransformationMatrix(objectStructure).invert();\r
-                                       Matrix4f additionalRootBoneTransformation = inverseMeshObjectMatrix.multLocal(armatureObjectMatrix);\r
-                                       Bone[] bones = armatureHelper.buildBonesStructure(Long.valueOf(0L), additionalRootBoneTransformation);\r
-\r
-                                       String objectName = objectStructure.getName();\r
-                                       Set<String> animationNames = dataRepository.getBlenderKey().getAnimationNames(objectName);\r
-                                       if(animationNames != null && animationNames.size() > 0) {\r
-                                               ArrayList<BoneAnimation> animations = new ArrayList<BoneAnimation>();\r
-                                               List<FileBlockHeader> actionHeaders = dataRepository.getFileBlocks(Integer.valueOf(FileBlockHeader.BLOCK_AC00));\r
-                                               for(FileBlockHeader header : actionHeaders) {\r
-                                                       Structure actionStructure = header.getStructure(dataRepository);\r
-                                                       String actionName = actionStructure.getName();\r
-                                                       if(animationNames.contains(actionName)) {\r
-                                                               int[] animationFrames = dataRepository.getBlenderKey().getAnimationFrames(objectName, actionName);\r
-                                                               int fps = dataRepository.getBlenderKey().getFps();\r
-                                                               float start = (float)animationFrames[0] / (float)fps;\r
-                                                               float stop = (float)animationFrames[1] / (float)fps;\r
-                                                               BoneAnimation boneAnimation = new BoneAnimation(actionName, stop - start);\r
-                                                               boneAnimation.setTracks(armatureHelper.getTracks(actionStructure, dataRepository, objectName, actionName));\r
-                                                               animations.add(boneAnimation);\r
-                                                       }\r
-                                               }\r
-                                               loadedModifier = new AnimData(new Skeleton(bones), animations);\r
-                                       }\r
-                               } else {\r
-                                       LOGGER.warning("Unsupported modifier type: " + modifier.getType());\r
-                               }\r
-                       } else if(Modifier.PARTICLE_MODIFIER_DATA.equals(modifier.getType())) {//****************PARTICLES MODIFIER\r
-                               Pointer pParticleSystem = (Pointer) modifier.getFieldValue("psys");\r
-                               if(!pParticleSystem.isNull()) {\r
-                                       ParticlesHelper particlesHelper = dataRepository.getHelper(ParticlesHelper.class);\r
-                                       Structure particleSystem = pParticleSystem.fetchData(dataRepository.getInputStream()).get(0);\r
-                                       loadedModifier = particlesHelper.toParticleEmitter(particleSystem, dataRepository);\r
-                               }\r
-                       }\r
-                       //adding modifier to the modifier's lists\r
-                       if(loadedModifier != null) {\r
-                               dataRepository.addModifier(objectStructure.getOldMemoryAddress(), modifier.getType(), loadedModifier, modifierAdditionalData);\r
-                               modifierAdditionalData = null;\r
-                       }\r
-               }\r
-       }\r
-       \r
-       /**\r
-        * This method applies particles emitter to the given node.\r
-        * @param node the particles emitter node\r
-        * @param modifier the modifier containing the emitter data\r
-        * @param dataRepository the data repository\r
-        * @return node with particles' emitter applied\r
-        */\r
-       protected Node applyParticleSystemModifierData(Node node, Modifier modifier, DataRepository dataRepository) {\r
-               MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);\r
-               ParticleEmitter emitter = (ParticleEmitter) modifier.getJmeModifierRepresentation();\r
-               emitter = emitter.clone();\r
-\r
-               //veryfying the alpha function for particles' texture\r
-               Integer alphaFunction = MaterialHelper.ALPHA_MASK_HYPERBOLE;\r
-               char nameSuffix = emitter.getName().charAt(emitter.getName().length()-1);\r
-               if(nameSuffix=='B' || nameSuffix=='N') {\r
-                       alphaFunction = MaterialHelper.ALPHA_MASK_NONE;\r
-               }\r
-               //removing the type suffix from the name\r
-               emitter.setName(emitter.getName().substring(0, emitter.getName().length()-1));\r
-               \r
-               //applying emitter shape\r
-               EmitterShape emitterShape = emitter.getShape();\r
-               List<Mesh> meshes = new ArrayList<Mesh>();\r
-               for(Spatial spatial : node.getChildren()) {\r
-                       if(spatial instanceof Geometry) {\r
-                               Mesh mesh = ((Geometry) spatial).getMesh();\r
-                               if(mesh != null) {\r
-                                       meshes.add(mesh);\r
-                                       Material material = materialHelper.getParticlesMaterial(((Geometry) spatial).getMaterial(), alphaFunction, dataRepository);\r
-                                       emitter.setMaterial(material);//TODO: divide into several pieces\r
-                               }\r
-                       }\r
-               }\r
-               if(meshes.size()>0 && emitterShape instanceof EmitterMeshVertexShape) {\r
-                       ((EmitterMeshVertexShape) emitterShape).setMeshes(meshes);\r
-               }\r
-               \r
-               node.attachChild(emitter);\r
-               return node;\r
-       }\r
-       \r
-       /**\r
-        * This method applies ArmatureModifierData to the loaded object.\r
-        * @param node\r
-        *        the loaded object\r
-        * @param modifier\r
-        *        the modifier to apply\r
-        * @param dataRepository\r
-        *        the data repository\r
-        * @return the node to whom the modifier was applied\r
-        */\r
-       protected Node applyArmatureModifierData(Node node, Modifier modifier, DataRepository dataRepository) {\r
-               AnimData ad = (AnimData)modifier.getJmeModifierRepresentation();\r
-               ArrayList<BoneAnimation> animList = ad.anims;\r
-               Long modifierArmatureObject = (Long)modifier.getAdditionalData();\r
-               if(animList != null && animList.size() > 0) {\r
-                       ConstraintHelper constraintHelper = dataRepository.getHelper(ConstraintHelper.class);\r
-                       Constraint[] constraints = constraintHelper.getConstraints(modifierArmatureObject);\r
-                       HashMap<String, BoneAnimation> anims = new HashMap<String, BoneAnimation>();\r
-                       for(int i = 0; i < animList.size(); ++i) {\r
-                               BoneAnimation boneAnimation = this.cloneBoneAnimation(animList.get(i));\r
-\r
-                               //baking constraints into animations\r
-                               if(constraints != null && constraints.length > 0) {\r
-                                       for(Constraint constraint : constraints) {\r
-                                               constraint.affectAnimation(ad.skeleton, boneAnimation);\r
-                                       }\r
-                               }\r
-\r
-                               anims.put(boneAnimation.getName(), boneAnimation);\r
-                       }\r
-\r
-                       //getting meshes\r
-                       Mesh[] meshes = null;\r
-                       List<Mesh> meshesList = new ArrayList<Mesh>();\r
-                       List<Spatial> children = node.getChildren();\r
-                       for(Spatial child : children) {\r
-                               if(child instanceof Geometry) {\r
-                                       meshesList.add(((Geometry)child).getMesh());\r
-                               }\r
-                       }\r
-                       if(meshesList.size() > 0) {\r
-                               meshes = meshesList.toArray(new Mesh[meshesList.size()]);\r
-                       }\r
-\r
-                       //applying the control to the node\r
-                       SkeletonControl skeletonControl = new SkeletonControl(meshes, ad.skeleton);\r
-                       AnimControl control = node.getControl(AnimControl.class);\r
-                       \r
-                       if(control == null) {\r
-                               control = new AnimControl(ad.skeleton);\r
-                       } else {\r
-                               //merging skeletons\r
-                               Skeleton controlSkeleton = control.getSkeleton();\r
-                               int boneIndexIncrease = controlSkeleton.getBoneCount();\r
-                               Skeleton skeleton = this.merge(controlSkeleton, ad.skeleton);\r
-\r
-                               //merging animations\r
-                               HashMap<String, BoneAnimation> animations = new HashMap<String, BoneAnimation>();\r
-                               for(String animationName : control.getAnimationNames()) {\r
-                                       animations.put(animationName, control.getAnim(animationName));\r
-                               }\r
-                               for(Entry<String, BoneAnimation> animEntry : anims.entrySet()) {\r
-                                       BoneAnimation ba = animEntry.getValue();\r
-                                       for(int i = 0; i < ba.getTracks().length; ++i) {\r
-                                               BoneTrack bt = ba.getTracks()[i];\r
-                                               int newBoneIndex = bt.getTargetBoneIndex() + boneIndexIncrease;\r
-                                               ba.getTracks()[i] = new BoneTrack(newBoneIndex, bt.getTimes(), bt.getTranslations(), bt.getRotations(), bt.getScales());\r
-                                       }\r
-                                       animations.put(animEntry.getKey(), animEntry.getValue());\r
-                               }\r
-\r
-                               //replacing the control\r
-                               node.removeControl(control);\r
-                               control = new AnimControl(skeleton);\r
-                       }\r
-                       control.setAnimations(anims);\r
-                       node.addControl(control);\r
-                       node.addControl(skeletonControl);\r
-               }\r
-               return node;\r
-       }\r
-       \r
-       /**\r
-        * This method applies the array modifier to the node.\r
-        * @param node\r
-        *            the object the modifier will be applied to\r
-        * @param modifier\r
-        *            the modifier to be applied\r
-        * @param dataRepository\r
-        *            the data repository\r
-        * @return object node with arry modifier applied\r
-        */\r
-       @SuppressWarnings("unchecked")\r
-       protected Node applyArrayModifierData(Node node, Modifier modifier, DataRepository dataRepository) {\r
-               Map<String, Object> modifierData = (Map<String, Object>) modifier.getJmeModifierRepresentation();\r
-               int fittype = ((Number)modifierData.get("fittype")).intValue();\r
-               float[] offset = (float[])modifierData.get("offset");\r
-               if(offset==null) {//the node will be repeated several times in the same place\r
-                       offset = new float[] {0.0f, 0.0f, 0.0f};\r
-               }\r
-               float[] scale = (float[])modifierData.get("scale");\r
-               if(scale==null) {//the node will be repeated several times in the same place\r
-                       scale = new float[] {0.0f, 0.0f, 0.0f};\r
-               } else {\r
-                       //getting bounding box\r
-                       node.updateModelBound();\r
-                       BoundingVolume boundingVolume = node.getWorldBound();\r
-                       if(boundingVolume instanceof BoundingBox) {\r
-                               scale[0] *= ((BoundingBox) boundingVolume).getXExtent() * 2.0f;\r
-                               scale[1] *= ((BoundingBox) boundingVolume).getYExtent() * 2.0f;\r
-                               scale[2] *= ((BoundingBox) boundingVolume).getZExtent() * 2.0f;\r
-                       } else if(boundingVolume instanceof BoundingSphere) {\r
-                               float radius = ((BoundingSphere) boundingVolume).getRadius();\r
-                               scale[0] *= radius * 2.0f;\r
-                               scale[1] *= radius * 2.0f;\r
-                               scale[2] *= radius * 2.0f;\r
-                       } else {\r
-                               throw new IllegalStateException("Unknown bounding volume type: " + boundingVolume.getClass().getName());\r
-                       }\r
-               }\r
-               \r
-               //adding object's offset\r
-               float[] objectOffset = new float[] {0.0f, 0.0f, 0.0f};\r
-               Pointer pOffsetObject = (Pointer) modifierData.get("offsetob");\r
-               if(pOffsetObject!=null) {\r
-                       FileBlockHeader offsetObjectBlock = dataRepository.getFileBlock(pOffsetObject.getOldMemoryAddress());\r
-                       ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);\r
-                       try {//we take the structure in case the object was not yet loaded\r
-                               Structure offsetStructure = offsetObjectBlock.getStructure(dataRepository);\r
-                               Vector3f translation = objectHelper.getTransformation(offsetStructure).getTranslation();\r
-                               objectOffset[0] = translation.x;\r
-                               objectOffset[1] = translation.y;\r
-                               objectOffset[2] = translation.z;\r
-                       } catch (BlenderFileException e) {\r
-                               LOGGER.warning("Problems in blender file structure! Object offset cannot be applied! The problem: " + e.getMessage());\r
-                       }\r
-               }\r
-               \r
-               //getting start and end caps\r
-               Node[] caps = new Node[] {null, null};\r
-               Pointer[] pCaps = new Pointer[] {(Pointer) modifierData.get("startcap"), (Pointer) modifierData.get("endcap")};\r
-               for(int i=0;i<pCaps.length;++i) {\r
-                       if(pCaps[i]!=null) {\r
-                               caps[i] = (Node) dataRepository.getLoadedFeature(pCaps[i].getOldMemoryAddress(), LoadedFeatureDataType.LOADED_FEATURE);\r
-                               if(caps[i]!=null) {\r
-                                       caps[i] = (Node) caps[i].clone();\r
-                               } else {\r
-                                       FileBlockHeader capBlock = dataRepository.getFileBlock(pOffsetObject.getOldMemoryAddress());\r
-                                       try {//we take the structure in case the object was not yet loaded\r
-                                               Structure capStructure = capBlock.getStructure(dataRepository);\r
-                                               ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);\r
-                                               caps[i] = (Node) objectHelper.toObject(capStructure, dataRepository);\r
-                                               if(caps[i]==null) {\r
-                                                       LOGGER.warning("Cap object '" + capStructure.getName() + "' couldn't be loaded!");\r
-                                               }\r
-                                       } catch (BlenderFileException e) {\r
-                                               LOGGER.warning("Problems in blender file structure! Cap object cannot be applied! The problem: " + e.getMessage());\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-               \r
-               Vector3f translationVector = new Vector3f(offset[0] + scale[0] + objectOffset[0], \r
-                                                                                                 offset[1] + scale[1] + objectOffset[1], \r
-                                                                                                 offset[2] + scale[2] + objectOffset[2]);\r
-               \r
-               //getting/calculating repeats amount\r
-               int count = 0;\r
-               if(fittype==0) {//Fixed count\r
-                       count = ((Number)modifierData.get("count")).intValue() - 1;\r
-               } else if(fittype==1) {//Fixed length\r
-                       float length = ((Number)modifierData.get("length")).floatValue();\r
-                       if(translationVector.length()>0.0f) {\r
-                               count = (int)(length / translationVector.length()) - 1;\r
-                       }\r
-               } else if(fittype==2) {//Fit curve\r
-                       LOGGER.warning("Fit curve mode in array modifier not yet implemented!");//TODO: implement fit curve\r
-               } else {\r
-                       throw new IllegalStateException("Unknown fit type: " + fittype);\r
-               }\r
-               \r
-               //adding translated nodes and caps\r
-               if(count>0) {\r
-                       Node[] arrayNodes = new Node[count];\r
-                       Vector3f newTranslation = node.getLocalTranslation().clone();\r
-                       for(int i=0;i<count;++i) {\r
-                               newTranslation.addLocal(translationVector);\r
-                               Node nodeClone = (Node) node.clone();\r
-                               nodeClone.setLocalTranslation(newTranslation);\r
-                               arrayNodes[i] = nodeClone;\r
-                       }\r
-                       for(Node nodeClone : arrayNodes) {\r
-                               node.attachChild(nodeClone);\r
-                       }\r
-                       if(caps[0]!=null) {\r
-                               caps[0].getLocalTranslation().set(node.getLocalTranslation()).subtractLocal(translationVector);\r
-                               node.attachChild(caps[0]);\r
-                       }\r
-                       if(caps[1]!=null) {\r
-                               caps[1].getLocalTranslation().set(newTranslation).addLocal(translationVector);\r
-                               node.attachChild(caps[1]);\r
-                       }\r
-               }\r
-               return node;\r
-       }\r
-       \r
-       /**\r
-        * This class clones the bone animation data.\r
-        * @param source\r
-        *        the source that is to be cloned\r
-        * @return the copy of the given bone animation\r
-        */\r
-       protected BoneAnimation cloneBoneAnimation(BoneAnimation source) {\r
-               BoneAnimation result = new BoneAnimation(source.getName(), source.getLength());\r
-\r
-               //copying tracks and applying constraints\r
-               BoneTrack[] sourceTracks = source.getTracks();\r
-               BoneTrack[] boneTracks = new BoneTrack[sourceTracks.length];\r
-               for(int i = 0; i < sourceTracks.length; ++i) {\r
-                       int tablesLength = sourceTracks[i].getTimes().length;\r
-\r
-                       Vector3f[] sourceTranslations = sourceTracks[i].getTranslations();\r
-                       Quaternion[] sourceRotations = sourceTracks[i].getRotations();\r
-                       Vector3f[] sourceScales = sourceTracks[i].getScales();\r
-\r
-                       Vector3f[] translations = new Vector3f[tablesLength];\r
-                       Quaternion[] rotations = new Quaternion[tablesLength];\r
-                       Vector3f[] scales = sourceScales == null ? null : new Vector3f[tablesLength];\r
-                       for(int j = 0; j < tablesLength; ++j) {\r
-                               translations[j] = sourceTranslations[j].clone();\r
-                               rotations[j] = sourceRotations[j].clone();\r
-                               if(sourceScales != null) {//only scales may not be applied\r
-                                       scales[j] = sourceScales[j].clone();\r
-                               }\r
-                       }\r
-                       boneTracks[i] = new BoneTrack(sourceTracks[i].getTargetBoneIndex(), sourceTracks[i].getTimes(),//times do not change, no need to clone them,\r
-                                       translations, rotations, scales);\r
-               }\r
-               result.setTracks(boneTracks);\r
-               return result;\r
-       }\r
-       \r
-       /**\r
-        * This method merges two skeletons into one. I assume that each skeleton's 0-indexed bone is objectAnimationBone so\r
-        * only one such bone should be placed in the result\r
-        * @param s1\r
-        *        first skeleton\r
-        * @param s2\r
-        *        second skeleton\r
-        * @return merged skeleton\r
-        */\r
-       protected Skeleton merge(Skeleton s1, Skeleton s2) {\r
-               List<Bone> bones = new ArrayList<Bone>(s1.getBoneCount() + s2.getBoneCount());\r
-               for(int i = 0; i < s1.getBoneCount(); ++i) {\r
-                       bones.add(s1.getBone(i));\r
-               }\r
-               for(int i = 1; i < s2.getBoneCount(); ++i) {//ommit objectAnimationBone\r
-                       bones.add(s2.getBone(i));\r
-               }\r
-               return new Skeleton(bones.toArray(new Bone[bones.size()]));\r
-       }\r
+\r
+    private static final Logger LOGGER = Logger.getLogger(ModifierHelper.class.getName());\r
+\r
+    /**\r
+     * This constructor parses the given blender version and stores the result. Some functionalities may differ in\r
+     * different blender versions.\r
+     * @param blenderVersion\r
+     *        the version read from the blend file\r
+     */\r
+    public ModifierHelper(String blenderVersion) {\r
+        super(blenderVersion);\r
+    }\r
+\r
+    /**\r
+     * This method applies modifier to the object.\r
+     * @param node\r
+     *        the loaded object\r
+     * @param modifier\r
+     *        the modifier to apply\r
+     * @param dataRepository\r
+     *        the data repository\r
+     * @return the node to whom the modifier was applied\r
+     */\r
+    public Node applyModifier(Node node, Modifier modifier, DataRepository dataRepository) {\r
+        if (Modifier.ARMATURE_MODIFIER_DATA.equals(modifier.getType())) {\r
+            return this.applyArmatureModifierData(node, modifier, dataRepository);\r
+        } else if (Modifier.ARRAY_MODIFIER_DATA.equals(modifier.getType())) {\r
+            return this.applyArrayModifierData(node, modifier, dataRepository);\r
+        } else if (Modifier.PARTICLE_MODIFIER_DATA.equals(modifier.getType())) {\r
+            return this.applyParticleSystemModifierData(node, modifier, dataRepository);\r
+        } else {\r
+            LOGGER.warning("Modifier: " + modifier.getType() + " not yet implemented!!!");\r
+            return node;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * This method reads the given object's modifiers.\r
+     * @param objectStructure\r
+     *        the object structure\r
+     * @param dataRepository\r
+     *        the data repository\r
+     * @param converter\r
+     *        the converter object (in some cases we need to read an object first before loading the modifier)\r
+     * @throws BlenderFileException\r
+     *         this exception is thrown when the blender file is somehow corrupted\r
+     */\r
+    @SuppressWarnings("unchecked")\r
+    public void readModifiers(Structure objectStructure, DataRepository dataRepository) throws BlenderFileException {\r
+        Structure modifiersListBase = (Structure) objectStructure.getFieldValue("modifiers");\r
+        List<Structure> modifiers = modifiersListBase.evaluateListBase(dataRepository);\r
+        for (Structure modifier : modifiers) {\r
+            Object loadedModifier = null;\r
+            Object modifierAdditionalData = null;\r
+            if (Modifier.ARRAY_MODIFIER_DATA.equals(modifier.getType())) {//****************ARRAY MODIFIER\r
+                Map<String, Object> params = new HashMap<String, Object>();\r
+\r
+                Number fittype = (Number) modifier.getFieldValue("fit_type");\r
+                params.put("fittype", fittype);\r
+                switch (fittype.intValue()) {\r
+                    case 0://FIXED COUNT\r
+                        params.put("count", modifier.getFieldValue("count"));\r
+                        break;\r
+                    case 1://FIXED LENGTH\r
+                        params.put("length", modifier.getFieldValue("length"));\r
+                        break;\r
+                    case 2://FITCURVE\r
+                        //TODO: implement after loading curves is added; warning will be generated during modifier applying\r
+                        break;\r
+                    default:\r
+                        assert false : "Unknown array modifier fit type: " + fittype;\r
+                }\r
+\r
+                //offset parameters\r
+                int offsettype = ((Number) modifier.getFieldValue("offset_type")).intValue();\r
+                if ((offsettype & 0x01) != 0) {//Constant offset\r
+                    DynamicArray<Number> offsetArray = (DynamicArray<Number>) modifier.getFieldValue("offset");\r
+                    float[] offset = new float[]{offsetArray.get(0).floatValue(), offsetArray.get(1).floatValue(), offsetArray.get(2).floatValue()};\r
+                    params.put("offset", offset);\r
+                }\r
+                if ((offsettype & 0x02) != 0) {//Relative offset\r
+                    DynamicArray<Number> scaleArray = (DynamicArray<Number>) modifier.getFieldValue("scale");\r
+                    float[] scale = new float[]{scaleArray.get(0).floatValue(), scaleArray.get(1).floatValue(), scaleArray.get(2).floatValue()};\r
+                    params.put("scale", scale);\r
+                }\r
+                if ((offsettype & 0x04) != 0) {//Object offset\r
+                    Pointer pOffsetObject = (Pointer) modifier.getFieldValue("offset_ob");\r
+                    if (!pOffsetObject.isNull()) {\r
+                        params.put("offsetob", pOffsetObject);\r
+                    }\r
+                }\r
+\r
+                //start cap and end cap\r
+                Pointer pStartCap = (Pointer) modifier.getFieldValue("start_cap");\r
+                if (!pStartCap.isNull()) {\r
+                    params.put("startcap", pStartCap);\r
+                }\r
+                Pointer pEndCap = (Pointer) modifier.getFieldValue("end_cap");\r
+                if (!pEndCap.isNull()) {\r
+                    params.put("endcap", pEndCap);\r
+                }\r
+                loadedModifier = params;\r
+            } else if (Modifier.ARMATURE_MODIFIER_DATA.equals(modifier.getType())) {//****************ARMATURE MODIFIER\r
+                Pointer pArmatureObject = (Pointer) modifier.getFieldValue("object");\r
+                if (!pArmatureObject.isNull()) {\r
+                    ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);\r
+                    Structure armatureObject = (Structure) dataRepository.getLoadedFeature(pArmatureObject.getOldMemoryAddress(), LoadedFeatureDataType.LOADED_STRUCTURE);\r
+                    if (armatureObject == null) {//we check this first not to fetch the structure unnecessary\r
+                        armatureObject = pArmatureObject.fetchData(dataRepository.getInputStream()).get(0);\r
+                        objectHelper.toObject(armatureObject, dataRepository);\r
+                    }\r
+                    modifierAdditionalData = armatureObject.getOldMemoryAddress();\r
+                    ArmatureHelper armatureHelper = dataRepository.getHelper(ArmatureHelper.class);\r
+\r
+                    //changing bones matrices so that they fit the current object (taht is why we need a copy of a skeleton)\r
+                    Matrix4f armatureObjectMatrix = objectHelper.getTransformationMatrix(armatureObject);\r
+                    Matrix4f inverseMeshObjectMatrix = objectHelper.getTransformationMatrix(objectStructure).invert();\r
+                    Matrix4f additionalRootBoneTransformation = inverseMeshObjectMatrix.multLocal(armatureObjectMatrix);\r
+                    Bone[] bones = armatureHelper.buildBonesStructure(Long.valueOf(0L), additionalRootBoneTransformation);\r
+\r
+                    String objectName = objectStructure.getName();\r
+                    Set<String> animationNames = dataRepository.getBlenderKey().getAnimationNames(objectName);\r
+                    if (animationNames != null && animationNames.size() > 0) {\r
+                        ArrayList<BoneAnimation> animations = new ArrayList<BoneAnimation>();\r
+                        List<FileBlockHeader> actionHeaders = dataRepository.getFileBlocks(Integer.valueOf(FileBlockHeader.BLOCK_AC00));\r
+                        for (FileBlockHeader header : actionHeaders) {\r
+                            Structure actionStructure = header.getStructure(dataRepository);\r
+                            String actionName = actionStructure.getName();\r
+                            if (animationNames.contains(actionName)) {\r
+                                int[] animationFrames = dataRepository.getBlenderKey().getAnimationFrames(objectName, actionName);\r
+                                int fps = dataRepository.getBlenderKey().getFps();\r
+                                float start = (float) animationFrames[0] / (float) fps;\r
+                                float stop = (float) animationFrames[1] / (float) fps;\r
+                                BoneAnimation boneAnimation = new BoneAnimation(actionName, stop - start);\r
+                                boneAnimation.setTracks(armatureHelper.getTracks(actionStructure, dataRepository, objectName, actionName));\r
+                                animations.add(boneAnimation);\r
+                            }\r
+                        }\r
+                        loadedModifier = new AnimData(new Skeleton(bones), animations);\r
+                    }\r
+                } else {\r
+                    LOGGER.warning("Unsupported modifier type: " + modifier.getType());\r
+                }\r
+            } else if (Modifier.PARTICLE_MODIFIER_DATA.equals(modifier.getType())) {//****************PARTICLES MODIFIER\r
+                Pointer pParticleSystem = (Pointer) modifier.getFieldValue("psys");\r
+                if (!pParticleSystem.isNull()) {\r
+                    ParticlesHelper particlesHelper = dataRepository.getHelper(ParticlesHelper.class);\r
+                    Structure particleSystem = pParticleSystem.fetchData(dataRepository.getInputStream()).get(0);\r
+                    loadedModifier = particlesHelper.toParticleEmitter(particleSystem, dataRepository);\r
+                }\r
+            }\r
+            //adding modifier to the modifier's lists\r
+            if (loadedModifier != null) {\r
+                dataRepository.addModifier(objectStructure.getOldMemoryAddress(), modifier.getType(), loadedModifier, modifierAdditionalData);\r
+                modifierAdditionalData = null;\r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
+     * This method applies particles emitter to the given node.\r
+     * @param node the particles emitter node\r
+     * @param modifier the modifier containing the emitter data\r
+     * @param dataRepository the data repository\r
+     * @return node with particles' emitter applied\r
+     */\r
+    protected Node applyParticleSystemModifierData(Node node, Modifier modifier, DataRepository dataRepository) {\r
+        MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);\r
+        ParticleEmitter emitter = (ParticleEmitter) modifier.getJmeModifierRepresentation();\r
+        emitter = emitter.clone();\r
+\r
+        //veryfying the alpha function for particles' texture\r
+        Integer alphaFunction = MaterialHelper.ALPHA_MASK_HYPERBOLE;\r
+        char nameSuffix = emitter.getName().charAt(emitter.getName().length() - 1);\r
+        if (nameSuffix == 'B' || nameSuffix == 'N') {\r
+            alphaFunction = MaterialHelper.ALPHA_MASK_NONE;\r
+        }\r
+        //removing the type suffix from the name\r
+        emitter.setName(emitter.getName().substring(0, emitter.getName().length() - 1));\r
+\r
+        //applying emitter shape\r
+        EmitterShape emitterShape = emitter.getShape();\r
+        List<Mesh> meshes = new ArrayList<Mesh>();\r
+        for (Spatial spatial : node.getChildren()) {\r
+            if (spatial instanceof Geometry) {\r
+                Mesh mesh = ((Geometry) spatial).getMesh();\r
+                if (mesh != null) {\r
+                    meshes.add(mesh);\r
+                    Material material = materialHelper.getParticlesMaterial(((Geometry) spatial).getMaterial(), alphaFunction, dataRepository);\r
+                    emitter.setMaterial(material);//TODO: divide into several pieces\r
+                }\r
+            }\r
+        }\r
+        if (meshes.size() > 0 && emitterShape instanceof EmitterMeshVertexShape) {\r
+            ((EmitterMeshVertexShape) emitterShape).setMeshes(meshes);\r
+        }\r
+\r
+        node.attachChild(emitter);\r
+        return node;\r
+    }\r
+\r
+    /**\r
+     * This method applies ArmatureModifierData to the loaded object.\r
+     * @param node\r
+     *        the loaded object\r
+     * @param modifier\r
+     *        the modifier to apply\r
+     * @param dataRepository\r
+     *        the data repository\r
+     * @return the node to whom the modifier was applied\r
+     */\r
+    protected Node applyArmatureModifierData(Node node, Modifier modifier, DataRepository dataRepository) {\r
+        AnimData ad = (AnimData) modifier.getJmeModifierRepresentation();\r
+        ArrayList<BoneAnimation> animList = ad.anims;\r
+        Long modifierArmatureObject = (Long) modifier.getAdditionalData();\r
+        if (animList != null && animList.size() > 0) {\r
+            ConstraintHelper constraintHelper = dataRepository.getHelper(ConstraintHelper.class);\r
+            Constraint[] constraints = constraintHelper.getConstraints(modifierArmatureObject);\r
+            HashMap<String, BoneAnimation> anims = new HashMap<String, BoneAnimation>();\r
+            for (int i = 0; i < animList.size(); ++i) {\r
+                BoneAnimation boneAnimation = this.cloneBoneAnimation(animList.get(i));\r
+\r
+                //baking constraints into animations\r
+                if (constraints != null && constraints.length > 0) {\r
+                    for (Constraint constraint : constraints) {\r
+                        constraint.affectAnimation(ad.skeleton, boneAnimation);\r
+                    }\r
+                }\r
+\r
+                anims.put(boneAnimation.getName(), boneAnimation);\r
+            }\r
+\r
+            //getting meshes\r
+            Mesh[] meshes = null;\r
+            List<Mesh> meshesList = new ArrayList<Mesh>();\r
+            List<Spatial> children = node.getChildren();\r
+            for (Spatial child : children) {\r
+                if (child instanceof Geometry) {\r
+                    meshesList.add(((Geometry) child).getMesh());\r
+                }\r
+            }\r
+            if (meshesList.size() > 0) {\r
+                meshes = meshesList.toArray(new Mesh[meshesList.size()]);\r
+            }\r
+\r
+            //applying the control to the node\r
+            SkeletonControl skeletonControl = new SkeletonControl(meshes, ad.skeleton);\r
+            AnimControl control = node.getControl(AnimControl.class);\r
+\r
+            if (control == null) {\r
+                control = new AnimControl(ad.skeleton);\r
+            } else {\r
+                //merging skeletons\r
+                Skeleton controlSkeleton = control.getSkeleton();\r
+                int boneIndexIncrease = controlSkeleton.getBoneCount();\r
+                Skeleton skeleton = this.merge(controlSkeleton, ad.skeleton);\r
+\r
+                //merging animations\r
+                HashMap<String, BoneAnimation> animations = new HashMap<String, BoneAnimation>();\r
+                for (String animationName : control.getAnimationNames()) {\r
+                    animations.put(animationName, control.getAnim(animationName));\r
+                }\r
+                for (Entry<String, BoneAnimation> animEntry : anims.entrySet()) {\r
+                    BoneAnimation ba = animEntry.getValue();\r
+                    for (int i = 0; i < ba.getTracks().length; ++i) {\r
+                        BoneTrack bt = ba.getTracks()[i];\r
+                        int newBoneIndex = bt.getTargetBoneIndex() + boneIndexIncrease;\r
+                        ba.getTracks()[i] = new BoneTrack(newBoneIndex, bt.getTimes(), bt.getTranslations(), bt.getRotations(), bt.getScales());\r
+                    }\r
+                    animations.put(animEntry.getKey(), animEntry.getValue());\r
+                }\r
+\r
+                //replacing the control\r
+                node.removeControl(control);\r
+                control = new AnimControl(skeleton);\r
+            }\r
+            control.setAnimations(anims);\r
+            node.addControl(control);\r
+            node.addControl(skeletonControl);\r
+        }\r
+        return node;\r
+    }\r
+\r
+    /**\r
+     * This method applies the array modifier to the node.\r
+     * @param node\r
+     *            the object the modifier will be applied to\r
+     * @param modifier\r
+     *            the modifier to be applied\r
+     * @param dataRepository\r
+     *            the data repository\r
+     * @return object node with arry modifier applied\r
+     */\r
+    @SuppressWarnings("unchecked")\r
+    protected Node applyArrayModifierData(Node node, Modifier modifier, DataRepository dataRepository) {\r
+        Map<String, Object> modifierData = (Map<String, Object>) modifier.getJmeModifierRepresentation();\r
+        int fittype = ((Number) modifierData.get("fittype")).intValue();\r
+        float[] offset = (float[]) modifierData.get("offset");\r
+        if (offset == null) {//the node will be repeated several times in the same place\r
+            offset = new float[]{0.0f, 0.0f, 0.0f};\r
+        }\r
+        float[] scale = (float[]) modifierData.get("scale");\r
+        if (scale == null) {//the node will be repeated several times in the same place\r
+            scale = new float[]{0.0f, 0.0f, 0.0f};\r
+        } else {\r
+            //getting bounding box\r
+            node.updateModelBound();\r
+            BoundingVolume boundingVolume = node.getWorldBound();\r
+            if (boundingVolume instanceof BoundingBox) {\r
+                scale[0] *= ((BoundingBox) boundingVolume).getXExtent() * 2.0f;\r
+                scale[1] *= ((BoundingBox) boundingVolume).getYExtent() * 2.0f;\r
+                scale[2] *= ((BoundingBox) boundingVolume).getZExtent() * 2.0f;\r
+            } else if (boundingVolume instanceof BoundingSphere) {\r
+                float radius = ((BoundingSphere) boundingVolume).getRadius();\r
+                scale[0] *= radius * 2.0f;\r
+                scale[1] *= radius * 2.0f;\r
+                scale[2] *= radius * 2.0f;\r
+            } else {\r
+                throw new IllegalStateException("Unknown bounding volume type: " + boundingVolume.getClass().getName());\r
+            }\r
+        }\r
+\r
+        //adding object's offset\r
+        float[] objectOffset = new float[]{0.0f, 0.0f, 0.0f};\r
+        Pointer pOffsetObject = (Pointer) modifierData.get("offsetob");\r
+        if (pOffsetObject != null) {\r
+            FileBlockHeader offsetObjectBlock = dataRepository.getFileBlock(pOffsetObject.getOldMemoryAddress());\r
+            ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);\r
+            try {//we take the structure in case the object was not yet loaded\r
+                Structure offsetStructure = offsetObjectBlock.getStructure(dataRepository);\r
+                Vector3f translation = objectHelper.getTransformation(offsetStructure).getTranslation();\r
+                objectOffset[0] = translation.x;\r
+                objectOffset[1] = translation.y;\r
+                objectOffset[2] = translation.z;\r
+            } catch (BlenderFileException e) {\r
+                LOGGER.warning("Problems in blender file structure! Object offset cannot be applied! The problem: " + e.getMessage());\r
+            }\r
+        }\r
+\r
+        //getting start and end caps\r
+        Node[] caps = new Node[]{null, null};\r
+        Pointer[] pCaps = new Pointer[]{(Pointer) modifierData.get("startcap"), (Pointer) modifierData.get("endcap")};\r
+        for (int i = 0; i < pCaps.length; ++i) {\r
+            if (pCaps[i] != null) {\r
+                caps[i] = (Node) dataRepository.getLoadedFeature(pCaps[i].getOldMemoryAddress(), LoadedFeatureDataType.LOADED_FEATURE);\r
+                if (caps[i] != null) {\r
+                    caps[i] = (Node) caps[i].clone();\r
+                } else {\r
+                    FileBlockHeader capBlock = dataRepository.getFileBlock(pOffsetObject.getOldMemoryAddress());\r
+                    try {//we take the structure in case the object was not yet loaded\r
+                        Structure capStructure = capBlock.getStructure(dataRepository);\r
+                        ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);\r
+                        caps[i] = (Node) objectHelper.toObject(capStructure, dataRepository);\r
+                        if (caps[i] == null) {\r
+                            LOGGER.warning("Cap object '" + capStructure.getName() + "' couldn't be loaded!");\r
+                        }\r
+                    } catch (BlenderFileException e) {\r
+                        LOGGER.warning("Problems in blender file structure! Cap object cannot be applied! The problem: " + e.getMessage());\r
+                    }\r
+                }\r
+            }\r
+        }\r
+\r
+        Vector3f translationVector = new Vector3f(offset[0] + scale[0] + objectOffset[0],\r
+                offset[1] + scale[1] + objectOffset[1],\r
+                offset[2] + scale[2] + objectOffset[2]);\r
+\r
+        //getting/calculating repeats amount\r
+        int count = 0;\r
+        if (fittype == 0) {//Fixed count\r
+            count = ((Number) modifierData.get("count")).intValue() - 1;\r
+        } else if (fittype == 1) {//Fixed length\r
+            float length = ((Number) modifierData.get("length")).floatValue();\r
+            if (translationVector.length() > 0.0f) {\r
+                count = (int) (length / translationVector.length()) - 1;\r
+            }\r
+        } else if (fittype == 2) {//Fit curve\r
+            LOGGER.warning("Fit curve mode in array modifier not yet implemented!");//TODO: implement fit curve\r
+        } else {\r
+            throw new IllegalStateException("Unknown fit type: " + fittype);\r
+        }\r
+\r
+        //adding translated nodes and caps\r
+        if (count > 0) {\r
+            Node[] arrayNodes = new Node[count];\r
+            Vector3f newTranslation = node.getLocalTranslation().clone();\r
+            for (int i = 0; i < count; ++i) {\r
+                newTranslation.addLocal(translationVector);\r
+                Node nodeClone = (Node) node.clone();\r
+                nodeClone.setLocalTranslation(newTranslation);\r
+                arrayNodes[i] = nodeClone;\r
+            }\r
+            for (Node nodeClone : arrayNodes) {\r
+                node.attachChild(nodeClone);\r
+            }\r
+            if (caps[0] != null) {\r
+                caps[0].getLocalTranslation().set(node.getLocalTranslation()).subtractLocal(translationVector);\r
+                node.attachChild(caps[0]);\r
+            }\r
+            if (caps[1] != null) {\r
+                caps[1].getLocalTranslation().set(newTranslation).addLocal(translationVector);\r
+                node.attachChild(caps[1]);\r
+            }\r
+        }\r
+        return node;\r
+    }\r
+\r
+    /**\r
+     * This class clones the bone animation data.\r
+     * @param source\r
+     *        the source that is to be cloned\r
+     * @return the copy of the given bone animation\r
+     */\r
+    protected BoneAnimation cloneBoneAnimation(BoneAnimation source) {\r
+        BoneAnimation result = new BoneAnimation(source.getName(), source.getLength());\r
+\r
+        //copying tracks and applying constraints\r
+        BoneTrack[] sourceTracks = source.getTracks();\r
+        BoneTrack[] boneTracks = new BoneTrack[sourceTracks.length];\r
+        for (int i = 0; i < sourceTracks.length; ++i) {\r
+            int tablesLength = sourceTracks[i].getTimes().length;\r
+\r
+            Vector3f[] sourceTranslations = sourceTracks[i].getTranslations();\r
+            Quaternion[] sourceRotations = sourceTracks[i].getRotations();\r
+            Vector3f[] sourceScales = sourceTracks[i].getScales();\r
+\r
+            Vector3f[] translations = new Vector3f[tablesLength];\r
+            Quaternion[] rotations = new Quaternion[tablesLength];\r
+            Vector3f[] scales = sourceScales == null ? null : new Vector3f[tablesLength];\r
+            for (int j = 0; j < tablesLength; ++j) {\r
+                translations[j] = sourceTranslations[j].clone();\r
+                rotations[j] = sourceRotations[j].clone();\r
+                if (sourceScales != null) {//only scales may not be applied\r
+                    scales[j] = sourceScales[j].clone();\r
+                }\r
+            }\r
+            boneTracks[i] = new BoneTrack(sourceTracks[i].getTargetBoneIndex(), sourceTracks[i].getTimes(),//times do not change, no need to clone them,\r
+                    translations, rotations, scales);\r
+        }\r
+        result.setTracks(boneTracks);\r
+        return result;\r
+    }\r
+\r
+    /**\r
+     * This method merges two skeletons into one. I assume that each skeleton's 0-indexed bone is objectAnimationBone so\r
+     * only one such bone should be placed in the result\r
+     * @param s1\r
+     *        first skeleton\r
+     * @param s2\r
+     *        second skeleton\r
+     * @return merged skeleton\r
+     */\r
+    protected Skeleton merge(Skeleton s1, Skeleton s2) {\r
+        List<Bone> bones = new ArrayList<Bone>(s1.getBoneCount() + s2.getBoneCount());\r
+        for (int i = 0; i < s1.getBoneCount(); ++i) {\r
+            bones.add(s1.getBone(i));\r
+        }\r
+        for (int i = 1; i < s2.getBoneCount(); ++i) {//ommit objectAnimationBone\r
+            bones.add(s2.getBone(i));\r
+        }\r
+        return new Skeleton(bones.toArray(new Bone[bones.size()]));\r
+    }\r
 }\r
index 75c6a04..7110540 100644 (file)
@@ -28,7 +28,6 @@
  * ***** END GPL LICENSE BLOCK *****\r
  *\r
  */\r
-\r
 package com.jme3.scene.plugins.blender.helpers.v249;\r
 \r
 import java.io.IOException;\r
@@ -56,1476 +55,1504 @@ import com.jme3.scene.plugins.blender.utils.DataRepository;
  * @author Marcin Roguski (Kaelthas)\r
  */\r
 public class NoiseHelper extends AbstractBlenderHelper {\r
-       private static final Logger     LOGGER                          = Logger.getLogger(NoiseHelper.class.getName());\r
-\r
-       /* return value */\r
-       protected static final int      TEX_INT                         = 0;\r
-       protected static final int      TEX_RGB                         = 1;\r
-       protected static final int      TEX_NOR                         = 2;\r
-\r
-       /* noisetype */\r
-       protected static final int      TEX_NOISESOFT           = 0;\r
-       protected static final int      TEX_NOISEPERL           = 1;\r
-\r
-       /* tex->stype in texture.c - cloud types */\r
-       protected static final int      TEX_DEFAULT                     = 0;\r
-       protected static final int      TEX_COLOR                       = 1;\r
-\r
-       /* flag */\r
-       protected static final int      TEX_COLORBAND           = 1;\r
-       protected static final int      TEX_FLIPBLEND           = 2;\r
-       protected static final int      TEX_NEGALPHA            = 4;\r
-       protected static final int      TEX_CHECKER_ODD         = 8;\r
-       protected static final int      TEX_CHECKER_EVEN        = 16;\r
-       protected static final int      TEX_PRV_ALPHA           = 32;\r
-       protected static final int      TEX_PRV_NOR                     = 64;\r
-       protected static final int      TEX_REPEAT_XMIR         = 128;\r
-       protected static final int      TEX_REPEAT_YMIR         = 256;\r
-       protected static final int      TEX_FLAG_MASK           = TEX_COLORBAND | TEX_FLIPBLEND | TEX_NEGALPHA | TEX_CHECKER_ODD | TEX_CHECKER_EVEN | TEX_PRV_ALPHA | TEX_PRV_NOR | TEX_REPEAT_XMIR | TEX_REPEAT_YMIR;\r
-\r
-       /* tex->noisebasis2 in texture.c - wood waveforms */\r
-       protected static final int      TEX_SIN                         = 0;\r
-       protected static final int      TEX_SAW                         = 1;\r
-       protected static final int      TEX_TRI                         = 2;\r
-\r
-       /* tex->stype in texture.c - marble types */\r
-       protected static final int      TEX_SOFT                        = 0;\r
-       protected static final int      TEX_SHARP                       = 1;\r
-       protected static final int      TEX_SHARPER                     = 2;\r
-\r
-       /* tex->stype in texture.c - wood types */\r
-       protected static final int      TEX_BAND                        = 0;\r
-       protected static final int      TEX_RING                        = 1;\r
-       protected static final int      TEX_BANDNOISE           = 2;\r
-       protected static final int      TEX_RINGNOISE           = 3;\r
-\r
-       /* tex->stype in texture.c - blend types */\r
-       protected static final int      TEX_LIN                         = 0;\r
-       protected static final int      TEX_QUAD                        = 1;\r
-       protected static final int      TEX_EASE                        = 2;\r
-       protected static final int      TEX_DIAG                        = 3;\r
-       protected static final int      TEX_SPHERE                      = 4;\r
-       protected static final int      TEX_HALO                        = 5;\r
-       protected static final int      TEX_RAD                         = 6;\r
-\r
-       /* tex->stype in texture.c - stucci types */\r
-       protected static final int      TEX_PLASTIC                     = 0;\r
-       protected static final int      TEX_WALLIN                      = 1;\r
-       protected static final int      TEX_WALLOUT                     = 2;\r
-\r
-       /* musgrave stype */\r
-       protected static final int      TEX_MFRACTAL            = 0;\r
-       protected static final int      TEX_RIDGEDMF            = 1;\r
-       protected static final int      TEX_HYBRIDMF            = 2;\r
-       protected static final int      TEX_FBM                         = 3;\r
-       protected static final int      TEX_HTERRAIN            = 4;\r
-\r
-       /* keyblock->type */\r
-       protected static final int      KEY_LINEAR                      = 0;\r
-       protected static final int      KEY_CARDINAL            = 1;\r
-       protected static final int      KEY_BSPLINE                     = 2;\r
-\r
-       /* CONSTANTS (read from file) */\r
-       protected static float[]        hashpntf;\r
-       protected static short[]        hash;\r
-       protected static float[]        hashvectf;\r
-       protected static short[]        p;\r
-       protected static float[][]      g;\r
-\r
-       /**\r
-        * Constructor. Stores the blender version number and loads the constants needed for computations.\r
-        * @param blenderVersion\r
-        *        the number of blender version\r
-        */\r
-       public NoiseHelper(String blenderVersion) {\r
-               super(blenderVersion);\r
-               this.loadConstants();\r
-       }\r
-\r
-       /**\r
-        * This method loads the constants needed for computations. They are exactly like the ones the blender uses. Each\r
-        * deriving class should override this method and load its own constraints. Be carefult with overriding though, if\r
-        * an exception will be thrown the class will not be instantiated.\r
-        */\r
-       protected void loadConstants() {\r
-               InputStream is = NoiseHelper.class.getResourceAsStream("noiseconstants.dat");\r
-               try {\r
-                       ObjectInputStream ois = new ObjectInputStream(is);\r
-                       hashpntf = (float[])ois.readObject();\r
-                       hash = (short[])ois.readObject();\r
-                       hashvectf = (float[])ois.readObject();\r
-                       p = (short[])ois.readObject();\r
-                       g = (float[][])ois.readObject();\r
-               } catch(IOException e) {\r
-                       LOGGER.log(Level.SEVERE, e.getLocalizedMessage(), e);\r
-               } catch(ClassNotFoundException e) {\r
-                       assert false : "Constants' classes should be arrays of primitive types, so they are ALWAYS known!";\r
-               } finally {\r
-                       if(is != null) {\r
-                               try {\r
-                                       is.close();\r
-                               } catch(IOException e) {\r
-                                       LOGGER.log(Level.WARNING, e.getLocalizedMessage());\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-\r
-       protected static Map<Integer, AbstractNoiseFunc>        noiseFunctions          = new HashMap<Integer, AbstractNoiseFunc>();\r
-       static {\r
-               // orgBlenderNoise (*Was BLI_hnoise(), removed noisesize, so other functions can call it without scaling.*)\r
-               noiseFunctions.put(Integer.valueOf(0), new AbstractNoiseFunc() {\r
-                       @Override\r
-                       public float execute(float x, float y, float z) {\r
-                               return this.orgBlenderNoise(x, y, z);\r
-                       }\r
-\r
-                       @Override\r
-                       public float executeS(float x, float y, float z) {\r
-                               return 2.0f * this.orgBlenderNoise(x, y, z) - 1.0f;\r
-                       }\r
-               });\r
-               // orgPerlinNoise (*For use with BLI_gNoise/gTurbulence, returns signed noise.*)\r
-               noiseFunctions.put(Integer.valueOf(1), new AbstractNoiseFunc() {\r
-                       @Override\r
-                       public float execute(float x, float y, float z) {\r
-                               return 0.5f + 0.5f * this.noise3Perlin(new float[] {x, y, z});\r
-                       }\r
-\r
-                       @Override\r
-                       public float executeS(float x, float y, float z) {\r
-                               return this.noise3Perlin(new float[] {x, y, z});\r
-                       }\r
-               });\r
-               // newPerlin (* for use with BLI_gNoise()/BLI_gTurbulence(), returns unsigned improved perlin noise *)\r
-               noiseFunctions.put(Integer.valueOf(2), new AbstractNoiseFunc() {\r
-                       @Override\r
-                       public float execute(float x, float y, float z) {\r
-                               return 0.5f + 0.5f * this.newPerlin(x, y, z);\r
-                       }\r
-\r
-                       @Override\r
-                       public float executeS(float x, float y, float z) {\r
-                               return this.execute(x, y, z);\r
-                       }\r
-               });\r
-               // voronoi_F1\r
-               noiseFunctions.put(Integer.valueOf(3), new AbstractNoiseFunc() {\r
-                       @Override\r
-                       public float execute(float x, float y, float z) {\r
-                               float[] da = new float[4], pa = new float[12];\r
-                               AbstractNoiseFunc.voronoi(x, y, z, da, pa, 1, 0);\r
-                               return da[0];\r
-                       }\r
-\r
-                       @Override\r
-                       public float executeS(float x, float y, float z) {\r
-                               float[] da = new float[4], pa = new float[12];\r
-                               AbstractNoiseFunc.voronoi(x, y, z, da, pa, 1, 0);\r
-                               return 2.0f * da[0] - 1.0f;\r
-                       }\r
-               });\r
-               // voronoi_F2\r
-               noiseFunctions.put(Integer.valueOf(4), new AbstractNoiseFunc() {\r
-                       @Override\r
-                       public float execute(float x, float y, float z) {\r
-                               float[] da = new float[4], pa = new float[12];\r
-                               AbstractNoiseFunc.voronoi(x, y, z, da, pa, 1, 0);\r
-                               return da[1];\r
-                       }\r
-\r
-                       @Override\r
-                       public float executeS(float x, float y, float z) {\r
-                               float[] da = new float[4], pa = new float[12];\r
-                               AbstractNoiseFunc.voronoi(x, y, z, da, pa, 1, 0);\r
-                               return 2.0f * da[1] - 1.0f;\r
-                       }\r
-               });\r
-               // voronoi_F3\r
-               noiseFunctions.put(Integer.valueOf(5), new AbstractNoiseFunc() {\r
-                       @Override\r
-                       public float execute(float x, float y, float z) {\r
-                               float[] da = new float[4], pa = new float[12];\r
-                               AbstractNoiseFunc.voronoi(x, y, z, da, pa, 1, 0);\r
-                               return da[2];\r
-                       }\r
-\r
-                       @Override\r
-                       public float executeS(float x, float y, float z) {\r
-                               float[] da = new float[4], pa = new float[12];\r
-                               AbstractNoiseFunc.voronoi(x, y, z, da, pa, 1, 0);\r
-                               return 2.0f * da[2] - 1.0f;\r
-                       }\r
-               });\r
-               // voronoi_F4\r
-               noiseFunctions.put(Integer.valueOf(6), new AbstractNoiseFunc() {\r
-                       @Override\r
-                       public float execute(float x, float y, float z) {\r
-                               float[] da = new float[4], pa = new float[12];\r
-                               AbstractNoiseFunc.voronoi(x, y, z, da, pa, 1, 0);\r
-                               return da[3];\r
-                       }\r
-\r
-                       @Override\r
-                       public float executeS(float x, float y, float z) {\r
-                               float[] da = new float[4], pa = new float[12];\r
-                               AbstractNoiseFunc.voronoi(x, y, z, da, pa, 1, 0);\r
-                               return 2.0f * da[3] - 1.0f;\r
-                       }\r
-               });\r
-               // voronoi_F1F2\r
-               noiseFunctions.put(Integer.valueOf(7), new AbstractNoiseFunc() {\r
-                       @Override\r
-                       public float execute(float x, float y, float z) {\r
-                               float[] da = new float[4], pa = new float[12];\r
-                               AbstractNoiseFunc.voronoi(x, y, z, da, pa, 1, 0);\r
-                               return da[1] - da[0];\r
-                       }\r
-\r
-                       @Override\r
-                       public float executeS(float x, float y, float z) {\r
-                               float[] da = new float[4], pa = new float[12];\r
-                               AbstractNoiseFunc.voronoi(x, y, z, da, pa, 1, 0);\r
-                               return 2.0f * (da[1] - da[0]) - 1.0f;\r
-                       }\r
-               });\r
-               // voronoi_Cr\r
-               noiseFunctions.put(Integer.valueOf(8), new AbstractNoiseFunc() {\r
-                       @Override\r
-                       public float execute(float x, float y, float z) {\r
-                               float t = 10 * noiseFunctions.get(Integer.valueOf(7)).execute(x, y, z);// voronoi_F1F2\r
-                               return t > 1.0f ? 1.0f : t;\r
-                       }\r
-\r
-                       @Override\r
-                       public float executeS(float x, float y, float z) {\r
-                               float t = 10.0f * noiseFunctions.get(Integer.valueOf(7)).execute(x, y, z);// voronoi_F1F2\r
-                               return t > 1.0f ? 1.0f : 2.0f * t - 1.0f;\r
-                       }\r
-               });\r
-               // cellNoise\r
-               noiseFunctions.put(Integer.valueOf(14), new AbstractNoiseFunc() {\r
-                       @Override\r
-                       public float execute(float x, float y, float z) {\r
-                               int xi = (int)Math.floor(x);\r
-                               int yi = (int)Math.floor(y);\r
-                               int zi = (int)Math.floor(z);\r
-                               long n = xi + yi * 1301 + zi * 314159;\r
-                               n ^= n << 13;\r
-                               return (n * (n * n * 15731 + 789221) + 1376312589) / 4294967296.0f;\r
-                       }\r
-\r
-                       @Override\r
-                       public float executeS(float x, float y, float z) {\r
-                               return 2.0f * this.execute(x, y, z) - 1.0f;\r
-                       }\r
-               });\r
-       }\r
-\r
-       /** Distance metrics for voronoi. e parameter only used in Minkovsky. */\r
-       protected static Map<Integer, IDistanceFunc>            distanceFunctions       = new HashMap<Integer, NoiseHelper.IDistanceFunc>();\r
-       static {\r
-               // real distance\r
-               distanceFunctions.put(Integer.valueOf(0), new IDistanceFunc() {\r
-                       @Override\r
-                       public float execute(float x, float y, float z, float e) {\r
-                               return (float)Math.sqrt(x * x + y * y + z * z);\r
-                       }\r
-               });\r
-               // distance squared\r
-               distanceFunctions.put(Integer.valueOf(1), new IDistanceFunc() {\r
-                       @Override\r
-                       public float execute(float x, float y, float z, float e) {\r
-                               return x * x + y * y + z * z;\r
-                       }\r
-               });\r
-               // manhattan/taxicab/cityblock distance\r
-               distanceFunctions.put(Integer.valueOf(2), new IDistanceFunc() {\r
-                       @Override\r
-                       public float execute(float x, float y, float z, float e) {\r
-                               return FastMath.abs(x) + FastMath.abs(y) + FastMath.abs(z);\r
-                       }\r
-               });\r
-               // Chebychev\r
-               distanceFunctions.put(Integer.valueOf(3), new IDistanceFunc() {\r
-                       @Override\r
-                       public float execute(float x, float y, float z, float e) {\r
-                               x = FastMath.abs(x);\r
-                               y = FastMath.abs(y);\r
-                               z = FastMath.abs(z);\r
-                               float t = x > y ? x : y;\r
-                               return z > t ? z : t;\r
-                       }\r
-               });\r
-               // minkovsky preset exponent 0.5 (MinkovskyH)\r
-               distanceFunctions.put(Integer.valueOf(4), new IDistanceFunc() {\r
-                       @Override\r
-                       public float execute(float x, float y, float z, float e) {\r
-                               float d = (float)(Math.sqrt(FastMath.abs(x)) + Math.sqrt(FastMath.abs(y)) + Math.sqrt(FastMath.abs(z)));\r
-                               return d * d;\r
-                       }\r
-               });\r
-               // minkovsky preset exponent 4 (Minkovsky4)\r
-               distanceFunctions.put(Integer.valueOf(5), new IDistanceFunc() {\r
-                       @Override\r
-                       public float execute(float x, float y, float z, float e) {\r
-                               x *= x;\r
-                               y *= y;\r
-                               z *= z;\r
-                               return (float)Math.sqrt(Math.sqrt(x * x + y * y + z * z));\r
-                       }\r
-               });\r
-               // Minkovsky, general case, slow, maybe too slow to be useful\r
-               distanceFunctions.put(Integer.valueOf(6), new IDistanceFunc() {\r
-                       @Override\r
-                       public float execute(float x, float y, float z, float e) {\r
-                               return (float)Math.pow(Math.pow(FastMath.abs(x), e) + Math.pow(FastMath.abs(y), e) + Math.pow(FastMath.abs(z), e), 1.0f / e);\r
-                       }\r
-               });\r
-       }\r
-\r
-       protected static Map<Integer, IMusgraveFunction>        musgraveFunctions       = new HashMap<Integer, NoiseHelper.IMusgraveFunction>();\r
-       static {\r
-               musgraveFunctions.put(Integer.valueOf(TEX_MFRACTAL), new IMusgraveFunction() {\r
-                       @Override\r
-                       public float execute(Structure tex, float x, float y, float z) {\r
-                               float mg_H = ((Number)tex.getFieldValue("mg_H")).floatValue();\r
-                               float mg_lacunarity = ((Number)tex.getFieldValue("mg_lacunarity")).floatValue();\r
-                               float mg_octaves = ((Number)tex.getFieldValue("mg_octaves")).floatValue();\r
-                               int noisebasis = ((Number)tex.getFieldValue("noisebasis")).intValue();\r
-\r
-                               float rmd, value = 1.0f, pwr = 1.0f, pwHL = (float)Math.pow(mg_lacunarity, -mg_H);\r
-                               AbstractNoiseFunc abstractNoiseFunc = noiseFunctions.get(Integer.valueOf(noisebasis));\r
-                               if(abstractNoiseFunc == null) {\r
-                                       abstractNoiseFunc = noiseFunctions.get(Integer.valueOf(0));\r
-                               }\r
-\r
-                               for(int i = 0; i < (int)mg_octaves; ++i) {\r
-                                       value *= pwr * abstractNoiseFunc.executeS(x, y, z) + 1.0f;\r
-                                       pwr *= pwHL;\r
-                                       x *= mg_lacunarity;\r
-                                       y *= mg_lacunarity;\r
-                                       z *= mg_lacunarity;\r
-                               }\r
-                               rmd = (float)(mg_octaves - Math.floor(mg_octaves));\r
-                               if(rmd != 0.0f) {\r
-                                       value *= rmd * abstractNoiseFunc.executeS(x, y, z) * pwr + 1.0f;\r
-                               }\r
-                               return value;\r
-                       }\r
-               });\r
-               musgraveFunctions.put(Integer.valueOf(TEX_RIDGEDMF), new IMusgraveFunction() {\r
-                       @Override\r
-                       public float execute(Structure tex, float x, float y, float z) {\r
-                               float mg_H = ((Number)tex.getFieldValue("mg_H")).floatValue();\r
-                               float mg_lacunarity = ((Number)tex.getFieldValue("mg_lacunarity")).floatValue();\r
-                               float mg_octaves = ((Number)tex.getFieldValue("mg_octaves")).floatValue();\r
-                               float mg_offset = ((Number)tex.getFieldValue("mg_offset")).floatValue();\r
-                               int noisebasis = ((Number)tex.getFieldValue("noisebasis")).intValue();\r
-                               float mg_gain = ((Number)tex.getFieldValue("mg_gain")).floatValue();\r
-                               float result, signal, weight;\r
-                               float pwHL = (float)Math.pow(mg_lacunarity, -mg_H);\r
-                               float pwr = pwHL; /* starts with i=1 instead of 0 */\r
-\r
-                               AbstractNoiseFunc abstractNoiseFunc = noiseFunctions.get(Integer.valueOf(noisebasis));\r
-                               if(abstractNoiseFunc == null) {\r
-                                       abstractNoiseFunc = noiseFunctions.get(Integer.valueOf(0));\r
-                               }\r
-\r
-                               signal = mg_offset - FastMath.abs(abstractNoiseFunc.executeS(x, y, z));\r
-                               signal *= signal;\r
-                               result = signal;\r
-                               weight = 1.0f;\r
-\r
-                               for(int i = 1; i < (int)mg_octaves; ++i) {\r
-                                       x *= mg_lacunarity;\r
-                                       y *= mg_lacunarity;\r
-                                       z *= mg_lacunarity;\r
-                                       weight = signal * mg_gain;\r
-                                       if(weight > 1.0f) {\r
-                                               weight = 1.0f;\r
-                                       } else if(weight < 0.0) {\r
-                                               weight = 0.0f;\r
-                                       }\r
-                                       signal = mg_offset - FastMath.abs(abstractNoiseFunc.executeS(x, y, z));\r
-                                       signal *= signal;\r
-                                       signal *= weight;\r
-                                       result += signal * pwr;\r
-                                       pwr *= pwHL;\r
-                               }\r
-                               return result;\r
-                       }\r
-               });\r
-               musgraveFunctions.put(Integer.valueOf(TEX_HYBRIDMF), new IMusgraveFunction() {\r
-                       @Override\r
-                       public float execute(Structure tex, float x, float y, float z) {\r
-                               float mg_H = ((Number)tex.getFieldValue("mg_H")).floatValue();\r
-                               float mg_lacunarity = ((Number)tex.getFieldValue("mg_lacunarity")).floatValue();\r
-                               float mg_octaves = ((Number)tex.getFieldValue("mg_octaves")).floatValue();\r
-                               float mg_offset = ((Number)tex.getFieldValue("mg_offset")).floatValue();\r
-                               int noisebasis = ((Number)tex.getFieldValue("noisebasis")).intValue();\r
-                               float mg_gain = ((Number)tex.getFieldValue("mg_gain")).floatValue();\r
-                               float result, signal, weight, rmd;\r
-                               float pwHL = (float)Math.pow(mg_lacunarity, -mg_H);\r
-                               float pwr = pwHL; /* starts with i=1 instead of 0 */\r
-                               AbstractNoiseFunc abstractNoiseFunc = noiseFunctions.get(Integer.valueOf(noisebasis));\r
-                               if(abstractNoiseFunc == null) {\r
-                                       abstractNoiseFunc = noiseFunctions.get(Integer.valueOf(0));\r
-                               }\r
-\r
-                               result = abstractNoiseFunc.executeS(x, y, z) + mg_offset;\r
-                               weight = mg_gain * result;\r
-                               x *= mg_lacunarity;\r
-                               y *= mg_lacunarity;\r
-                               z *= mg_lacunarity;\r
-\r
-                               for(int i = 1; weight > 0.001f && i < (int)mg_octaves; ++i) {\r
-                                       if(weight > 1.0f) {\r
-                                               weight = 1.0f;\r
-                                       }\r
-                                       signal = (abstractNoiseFunc.executeS(x, y, z) + mg_offset) * pwr;\r
-                                       pwr *= pwHL;\r
-                                       result += weight * signal;\r
-                                       weight *= mg_gain * signal;\r
-                                       x *= mg_lacunarity;\r
-                                       y *= mg_lacunarity;\r
-                                       z *= mg_lacunarity;\r
-                               }\r
-\r
-                               rmd = mg_octaves - (float)Math.floor(mg_octaves);\r
-                               if(rmd != 0.0f) {\r
-                                       result += rmd * (abstractNoiseFunc.executeS(x, y, z) + mg_offset) * pwr;\r
-                               }\r
-                               return result;\r
-                       }\r
-               });\r
-               musgraveFunctions.put(Integer.valueOf(TEX_FBM), new IMusgraveFunction() {\r
-                       @Override\r
-                       public float execute(Structure tex, float x, float y, float z) {\r
-                               float mg_H = ((Number)tex.getFieldValue("mg_H")).floatValue();\r
-                               float mg_lacunarity = ((Number)tex.getFieldValue("mg_lacunarity")).floatValue();\r
-                               float mg_octaves = ((Number)tex.getFieldValue("mg_octaves")).floatValue();\r
-                               int noisebasis = ((Number)tex.getFieldValue("noisebasis")).intValue();\r
-                               float rmd, value = 0.0f, pwr = 1.0f, pwHL = (float)Math.pow(mg_lacunarity, -mg_H);\r
-\r
-                               AbstractNoiseFunc abstractNoiseFunc = noiseFunctions.get(Integer.valueOf(noisebasis));\r
-                               if(abstractNoiseFunc == null) {\r
-                                       abstractNoiseFunc = noiseFunctions.get(Integer.valueOf(0));\r
-                               }\r
-\r
-                               for(int i = 0; i < (int)mg_octaves; ++i) {\r
-                                       value += abstractNoiseFunc.executeS(x, y, z) * pwr;\r
-                                       pwr *= pwHL;\r
-                                       x *= mg_lacunarity;\r
-                                       y *= mg_lacunarity;\r
-                                       z *= mg_lacunarity;\r
-                               }\r
-\r
-                               rmd = (float)(mg_octaves - Math.floor(mg_octaves));\r
-                               if(rmd != 0.f) {\r
-                                       value += rmd * abstractNoiseFunc.executeS(x, y, z) * pwr;\r
-                               }\r
-                               return value;\r
-                       }\r
-               });\r
-               musgraveFunctions.put(Integer.valueOf(TEX_HTERRAIN), new IMusgraveFunction() {\r
-                       @Override\r
-                       public float execute(Structure tex, float x, float y, float z) {\r
-                               float mg_H = ((Number)tex.getFieldValue("mg_H")).floatValue();\r
-                               float mg_lacunarity = ((Number)tex.getFieldValue("mg_lacunarity")).floatValue();\r
-                               float mg_octaves = ((Number)tex.getFieldValue("mg_octaves")).floatValue();\r
-                               int noisebasis = ((Number)tex.getFieldValue("noisebasis")).intValue();\r
-                               float mg_offset = ((Number)tex.getFieldValue("mg_offset")).floatValue();\r
-                               float value, increment, rmd;\r
-                               float pwHL = (float)Math.pow(mg_lacunarity, -mg_H);\r
-                               float pwr = pwHL; /* starts with i=1 instead of 0 */\r
-                               AbstractNoiseFunc abstractNoiseFunc = noiseFunctions.get(Integer.valueOf(noisebasis));\r
-                               if(abstractNoiseFunc == null) {\r
-                                       abstractNoiseFunc = noiseFunctions.get(Integer.valueOf(0));\r
-                               }\r
-\r
-                               /* first unscaled octave of function; later octaves are scaled */\r
-                               value = mg_offset + abstractNoiseFunc.executeS(x, y, z);\r
-                               x *= mg_lacunarity;\r
-                               y *= mg_lacunarity;\r
-                               z *= mg_lacunarity;\r
-\r
-                               for(int i = 1; i < (int)mg_octaves; ++i) {\r
-                                       increment = (abstractNoiseFunc.executeS(x, y, z) + mg_offset) * pwr * value;\r
-                                       value += increment;\r
-                                       pwr *= pwHL;\r
-                                       x *= mg_lacunarity;\r
-                                       y *= mg_lacunarity;\r
-                                       z *= mg_lacunarity;\r
-                               }\r
-\r
-                               rmd = mg_octaves - (float)Math.floor(mg_octaves);\r
-                               if(rmd != 0.0) {\r
-                                       increment = (abstractNoiseFunc.executeS(x, y, z) + mg_offset) * pwr * value;\r
-                                       value += rmd * increment;\r
-                               }\r
-                               return value;\r
-                       }\r
-               });\r
-       }\r
-\r
-       /**\r
-        * THE FOLLOWING METHODS HELP IN COMPUTATION OF THE TEXTURES.\r
-        */\r
-       protected void brightnesAndContrast(TexResult texres, float contrast, float brightness) {\r
-               texres.tin = (texres.tin - 0.5f) * contrast + brightness - 0.5f;\r
-               if(texres.tin < 0.0f) {\r
-                       texres.tin = 0.0f;\r
-               } else if(texres.tin > 1.0f) {\r
-                       texres.tin = 1.0f;\r
-               }\r
-       }\r
-\r
-       protected void brightnesAndContrastRGB(Structure tex, TexResult texres) {\r
-               float contrast = ((Number)tex.getFieldValue("contrast")).floatValue();\r
-               float bright = ((Number)tex.getFieldValue("bright")).floatValue();\r
-               float rfac = ((Number)tex.getFieldValue("rfac")).floatValue();\r
-               float gfac = ((Number)tex.getFieldValue("gfac")).floatValue();\r
-               float bfac = ((Number)tex.getFieldValue("bfac")).floatValue();\r
-\r
-               texres.tr = rfac * ((texres.tr - 0.5f) * contrast + bright - 0.5f);\r
-               if(texres.tr < 0.0f) {\r
-                       texres.tr = 0.0f;\r
-               }\r
-               texres.tg = gfac * ((texres.tg - 0.5f) * contrast + bright - 0.5f);\r
-               if(texres.tg < 0.0f) {\r
-                       texres.tg = 0.0f;\r
-               }\r
-               texres.tb = bfac * ((texres.tb - 0.5f) * contrast + bright - 0.5f);\r
-               if(texres.tb < 0.0f) {\r
-                       texres.tb = 0.0f;\r
-               }\r
-       }\r
-\r
-       /* this allows colorbanded textures to control normals as well */\r
-       public void texNormalDerivate(ColorBand colorBand, TexResult texres, DataRepository dataRepository) {\r
-               if(texres.nor != null) {\r
-                       TexResult fakeTexresult;\r
-                       try {\r
-                               fakeTexresult = (TexResult)texres.clone();\r
-                       } catch(CloneNotSupportedException e) {\r
-                               throw new IllegalStateException("Texture result class MUST support cloning!", e);\r
-                       }\r
-\r
-                       float fac0 = fakeTexresult.tr + fakeTexresult.tg + fakeTexresult.tb;\r
-                       fakeTexresult.tin = texres.nor[0];\r
-                       this.doColorband(colorBand, fakeTexresult, dataRepository);\r
-\r
-                       float fac1 = fakeTexresult.tr + fakeTexresult.tg + fakeTexresult.tb;\r
-                       fakeTexresult.tin = texres.nor[1];\r
-                       this.doColorband(colorBand, fakeTexresult, dataRepository);\r
-\r
-                       float fac2 = fakeTexresult.tr + fakeTexresult.tg + fakeTexresult.tb;\r
-                       fakeTexresult.tin = texres.nor[2];\r
-                       this.doColorband(colorBand, fakeTexresult, dataRepository);\r
-\r
-                       float fac3 = fakeTexresult.tr + fakeTexresult.tg + fakeTexresult.tb;\r
-\r
-                       texres.nor[0] = 0.3333f * (fac0 - fac1);\r
-                       texres.nor[1] = 0.3333f * (fac0 - fac2);\r
-                       texres.nor[2] = 0.3333f * (fac0 - fac3);\r
-\r
-                       texres.nor[0] = texres.tin - texres.nor[0];\r
-                       texres.nor[1] = texres.tin - texres.nor[1];\r
-                       texres.nor[2] = texres.tin - texres.nor[2];\r
-               }\r
-       }\r
-\r
-       /**\r
-        * This method calculates the colorband for the texture.\r
-        * @param colorBand\r
-        *        the colorband data\r
-        * @param texres\r
-        *        the texture pixel result\r
-        * @param dataRepository\r
-        *        the data repository\r
-        * @return <b>true</b> if calculation suceedess and <b>false</b> otherwise\r
-        */\r
-       public boolean doColorband(ColorBand colorBand, TexResult texres, DataRepository dataRepository) {\r
-               CBData cbd1, cbd2, cbd0, cbd3;\r
-               int i1 = 0, i2 = 0, a;\r
-               float fac, mfac;\r
-               float[] t = new float[4];\r
-\r
-               if(colorBand == null || colorBand.tot == 0) {\r
-                       return true;\r
-               }\r
-\r
-               cbd1 = colorBand.data[0];\r
-               if(colorBand.tot == 1) {\r
-                       texres.tr = cbd1.r;\r
-                       texres.tg = cbd1.g;\r
-                       texres.tb = cbd1.b;\r
-                       texres.ta = cbd1.a;\r
-               } else {\r
-                       if(texres.tin <= cbd1.pos && colorBand.ipotype < 2) {\r
-                               texres.tr = cbd1.r;\r
-                               texres.tg = cbd1.g;\r
-                               texres.tb = cbd1.b;\r
-                               texres.ta = cbd1.a;\r
-                       } else {\r
-                               /* we're looking for first pos > in */\r
-                               for(a = 0; a < colorBand.tot; ++a, ++i1) {\r
-                                       cbd1 = colorBand.data[i1];\r
-                                       if(cbd1.pos > texres.tin) {\r
-                                               break;\r
-                                       }\r
-                               }\r
-\r
-                               if(a == colorBand.tot) {\r
-                                       cbd2 = colorBand.data[i1 - 1];\r
-                                       try {\r
-                                               cbd1 = (CBData)cbd2.clone();\r
-                                       } catch(CloneNotSupportedException e) {\r
-                                               throw new IllegalStateException("Clone not supported for " + CBData.class.getName() + " class! Fix that!");\r
-                                       }\r
-                                       cbd1.pos = 1.0f;\r
-                               } else if(a == 0) {\r
-                                       try {\r
-                                               cbd2 = (CBData)cbd1.clone();\r
-                                       } catch(CloneNotSupportedException e) {\r
-                                               throw new IllegalStateException("Clone not supported for " + CBData.class.getName() + " class! Fix that!");\r
-                                       }\r
-                                       cbd2.pos = 0.0f;\r
-                               } else {\r
-                                       cbd2 = colorBand.data[i1 - 1];\r
-                               }\r
-\r
-                               if(texres.tin >= cbd1.pos && colorBand.ipotype < 2) {\r
-                                       texres.tr = cbd1.r;\r
-                                       texres.tg = cbd1.g;\r
-                                       texres.tb = cbd1.b;\r
-                                       texres.ta = cbd1.a;\r
-                               } else {\r
-\r
-                                       if(cbd2.pos != cbd1.pos) {\r
-                                               fac = (texres.tin - cbd1.pos) / (cbd2.pos - cbd1.pos);\r
-                                       } else {\r
-                                               fac = 0.0f;\r
-                                       }\r
-\r
-                                       if(colorBand.ipotype == 4) {\r
-                                               /* constant */\r
-                                               texres.tr = cbd2.r;\r
-                                               texres.tg = cbd2.g;\r
-                                               texres.tb = cbd2.b;\r
-                                               texres.ta = cbd2.a;\r
-                                               return true;\r
-                                       }\r
-\r
-                                       if(colorBand.ipotype >= 2) {\r
-                                               /* ipo from right to left: 3 2 1 0 */\r
-\r
-                                               if(a >= colorBand.tot - 1) {\r
-                                                       cbd0 = cbd1;\r
-                                               } else {\r
-                                                       cbd0 = colorBand.data[i1 + 1];\r
-                                               }\r
-                                               if(a < 2) {\r
-                                                       cbd3 = cbd2;\r
-                                               } else {\r
-                                                       cbd3 = colorBand.data[i2 - 1];\r
-                                               }\r
-\r
-                                               fac = FastMath.clamp(fac, 0.0f, 1.0f);\r
-\r
-                                               if(colorBand.ipotype == 3) {\r
-                                                       this.setFourIpo(fac, t, KEY_CARDINAL);\r
-                                               } else {\r
-                                                       this.setFourIpo(fac, t, KEY_BSPLINE);\r
-                                               }\r
-\r
-                                               texres.tr = t[3] * cbd3.r + t[2] * cbd2.r + t[1] * cbd1.r + t[0] * cbd0.r;\r
-                                               texres.tg = t[3] * cbd3.g + t[2] * cbd2.g + t[1] * cbd1.g + t[0] * cbd0.g;\r
-                                               texres.tb = t[3] * cbd3.b + t[2] * cbd2.b + t[1] * cbd1.b + t[0] * cbd0.b;\r
-                                               texres.ta = t[3] * cbd3.a + t[2] * cbd2.a + t[1] * cbd1.a + t[0] * cbd0.a;\r
-                                               texres.tr = FastMath.clamp(texres.tr, 0.0f, 1.0f);\r
-                                               texres.tg = FastMath.clamp(texres.tg, 0.0f, 1.0f);\r
-                                               texres.tb = FastMath.clamp(texres.tb, 0.0f, 1.0f);\r
-                                               texres.ta = FastMath.clamp(texres.ta, 0.0f, 1.0f);\r
-                                       } else {\r
-\r
-                                               if(colorBand.ipotype == 1) { /* EASE */\r
-                                                       mfac = fac * fac;\r
-                                                       fac = 3.0f * mfac - 2.0f * mfac * fac;\r
-                                               }\r
-                                               mfac = 1.0f - fac;\r
-\r
-                                               texres.tr = mfac * cbd1.r + fac * cbd2.r;\r
-                                               texres.tg = mfac * cbd1.g + fac * cbd2.g;\r
-                                               texres.tb = mfac * cbd1.b + fac * cbd2.b;\r
-                                               texres.ta = mfac * cbd1.a + fac * cbd2.a;\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-               return true;\r
-       }\r
-\r
-       protected void setFourIpo(float d, float[] data, int type) {\r
-               if(type == KEY_LINEAR) {\r
-                       data[0] = 0.0f;\r
-                       data[1] = 1.0f - d;\r
-                       data[2] = d;\r
-                       data[3] = 0.0f;\r
-               } else {\r
-                       float d2 = d * d;\r
-                       float d3 = d2 * d;\r
-                       if(type == KEY_CARDINAL) {\r
-                               float fc = 0.71f;\r
-                               data[0] = -fc * d3 + 2.0f * fc * d2 - fc * d;\r
-                               data[1] = (2.0f - fc) * d3 + (fc - 3.0f) * d2 + 1.0f;\r
-                               data[2] = (fc - 2.0f) * d3 + (3.0f - 2.0f * fc) * d2 + fc * d;\r
-                               data[3] = fc * d3 - fc * d2;\r
-                       } else if(type == KEY_BSPLINE) {\r
-                               data[0] = -0.16666666f * d3 + 0.5f * d2 - 0.5f * d + 0.16666666f;\r
-                               data[1] = 0.5f * d3 - d2 + 0.6666666f;\r
-                               data[2] = -0.5f * d3 + 0.5f * d2 + 0.5f * d + 0.16666666f;\r
-                               data[3] = 0.16666666f * d3;\r
-                       }\r
-               }\r
-       }\r
-\r
-       interface IWaveForm {\r
-               float execute(float x);\r
-       }\r
-\r
-       protected static IWaveForm[]    waveformFunctions       = new IWaveForm[3];\r
-       static {\r
-               waveformFunctions[0] = new IWaveForm() {// tex_sin\r
-                       @Override\r
-                       public float execute(float x) {\r
-                               return 0.5f + 0.5f * (float)Math.sin(x);\r
-                       }\r
-               };\r
-               waveformFunctions[1] = new IWaveForm() {// tex_saw\r
-                       @Override\r
-                       public float execute(float x) {\r
-                               int n = (int)(x / FastMath.TWO_PI);\r
-                               x -= n * FastMath.TWO_PI;\r
-                               if(x < 0.0f) {\r
-                                       x += FastMath.TWO_PI;\r
-                               }\r
-                               return x / FastMath.TWO_PI;\r
-                       }\r
-               };\r
-               waveformFunctions[2] = new IWaveForm() {// tex_tri\r
-                       @Override\r
-                       public float execute(float x) {\r
-                               return 1.0f - 2.0f * FastMath.abs((float)Math.floor(x * 1.0f / FastMath.TWO_PI + 0.5f) - x * 1.0f / FastMath.TWO_PI);\r
-                       }\r
-               };\r
-       }\r
-\r
-       /* computes basic wood intensity value at x,y,z */\r
-       public float woodInt(Structure tex, float x, float y, float z, DataRepository dataRepository) {\r
-               int noisebasis2 = ((Number)tex.getFieldValue("noisebasis2")).intValue();\r
-               int noisebasis = ((Number)tex.getFieldValue("noisebasis")).intValue();\r
-               int stype = ((Number)tex.getFieldValue("stype")).intValue();\r
-               float noisesize = ((Number)tex.getFieldValue("noisesize")).floatValue();\r
-               float turbul = ((Number)tex.getFieldValue("turbul")).floatValue();\r
-               int noiseType = ((Number)tex.getFieldValue("noisetype")).intValue();\r
-               float wi = 0;\r
-               int waveform = noisebasis2; /* wave form: TEX_SIN=0, TEX_SAW=1, TEX_TRI=2 */\r
-               int wt = stype; /* wood type: TEX_BAND=0, TEX_RING=1, TEX_BANDNOISE=2, TEX_RINGNOISE=3 */\r
-\r
-               if(waveform > TEX_TRI || waveform < TEX_SIN) {\r
-                       waveform = 0; /* check to be sure noisebasis2 is initialized ahead of time */\r
-               }\r
-\r
-               if(wt == TEX_BAND) {\r
-                       wi = waveformFunctions[waveform].execute((x + y + z) * 10.0f);\r
-               } else if(wt == TEX_RING) {\r
-                       wi = waveformFunctions[waveform].execute((float)Math.sqrt(x * x + y * y + z * z) * 20.0f);\r
-               } else if(wt == TEX_BANDNOISE) {\r
-                       wi = turbul * this.bliGNoise(noisesize, x, y, z, noiseType != TEX_NOISESOFT, noisebasis);\r
-                       wi = waveformFunctions[waveform].execute((x + y + z) * 10.0f + wi);\r
-               } else if(wt == TEX_RINGNOISE) {\r
-                       wi = turbul * this.bliGNoise(noisesize, x, y, z, noiseType != TEX_NOISESOFT, noisebasis);\r
-                       wi = waveformFunctions[waveform].execute((float)Math.sqrt(x * x + y * y + z * z) * 20.0f + wi);\r
-               }\r
-               return wi;\r
-       }\r
-\r
-       /* computes basic marble intensity at x,y,z */\r
-       public float marbleInt(Structure tex, float x, float y, float z, DataRepository dataRepository) {\r
-               float noisesize = ((Number)tex.getFieldValue("noisesize")).floatValue();\r
-               int noisebasis = ((Number)tex.getFieldValue("noisebasis")).intValue();\r
-               int noisedepth = ((Number)tex.getFieldValue("noisedepth")).intValue();\r
-               int stype = ((Number)tex.getFieldValue("stype")).intValue();/* marble type: TEX_SOFT=0, TEX_SHARP=1,TEX_SHAPER=2 */\r
-               float turbul = ((Number)tex.getFieldValue("turbul")).floatValue();\r
-               int noisetype = ((Number)tex.getFieldValue("noisetype")).intValue();\r
-               int waveform = ((Number)tex.getFieldValue("noisebasis2")).intValue(); /* wave form: TEX_SIN=0, TEX_SAW=1, TEX_TRI=2 */\r
-\r
-               if(waveform > TEX_TRI || waveform < TEX_SIN) {\r
-                       waveform = 0; /* check to be sure noisebasis2 isn't initialized ahead of time */\r
-               }\r
-\r
-               float n = 5.0f * (x + y + z);\r
-               float mi = n + turbul * this.bliGTurbulence(noisesize, x, y, z, noisedepth, noisetype != TEX_NOISESOFT, noisebasis);\r
-\r
-               if(stype >= NoiseHelper.TEX_SOFT) { /* TEX_SOFT always true */\r
-                       mi = waveformFunctions[waveform].execute(mi);\r
-                       if(stype == TEX_SHARP) {\r
-                               mi = (float)Math.sqrt(mi);\r
-                       } else if(stype == TEX_SHARPER) {\r
-                               mi = (float)Math.sqrt(Math.sqrt(mi));\r
-                       }\r
-               }\r
-               return mi;\r
-       }\r
-\r
-       public void voronoi(float x, float y, float z, float[] da, float[] pa, float me, int dtype) {\r
-               AbstractNoiseFunc.voronoi(x, y, z, da, pa, me, dtype);\r
-       }\r
-\r
-       public void cellNoiseV(float x, float y, float z, float[] ca) {\r
-               AbstractNoiseFunc.cellNoiseV(x, y, z, ca);\r
-       }\r
-\r
-       /**\r
-        * THE FOLLOWING METHODS HELP IN NOISE COMPUTATIONS\r
-        */\r
-\r
-       /**\r
-        * Separated from orgBlenderNoise above, with scaling.\r
-        * @param noisesize\r
-        * @param x\r
-        * @param y\r
-        * @param z\r
-        * @return\r
-        */\r
-       private float bliHnoise(float noisesize, float x, float y, float z) {\r
-               if(noisesize == 0.0) {\r
-                       return 0.0f;\r
-               }\r
-               x = (1.0f + x) / noisesize;\r
-               y = (1.0f + y) / noisesize;\r
-               z = (1.0f + z) / noisesize;\r
-               return noiseFunctions.get(0).execute(x, y, z);\r
-       }\r
-\r
-       /**\r
-        * @param noisesize\r
-        * @param x\r
-        * @param y\r
-        * @param z\r
-        * @param nr\r
-        * @return\r
-        */\r
-       public float bliTurbulence(float noisesize, float x, float y, float z, int nr) {\r
-               float d = 0.5f, div = 1.0f;\r
-\r
-               float s = this.bliHnoise(noisesize, x, y, z);\r
-               while(nr > 0) {\r
-                       s += d * this.bliHnoise(noisesize * d, x, y, z);\r
-                       div += d;\r
-                       d *= 0.5;\r
-                       --nr;\r
-               }\r
-               return s / div;\r
-       }\r
-\r
-       /**\r
-        * @param noisesize\r
-        * @param x\r
-        * @param y\r
-        * @param z\r
-        * @param nr\r
-        * @return\r
-        */\r
-       public float bliTurbulence1(float noisesize, float x, float y, float z, int nr) {\r
-               float s, d = 0.5f, div = 1.0f;\r
-\r
-               s = FastMath.abs((-1.0f + 2.0f * this.bliHnoise(noisesize, x, y, z)));\r
-               while(nr > 0) {\r
-                       s += Math.abs(d * (-1.0f + 2.0f * this.bliHnoise(noisesize * d, x, y, z)));\r
-                       div += d;\r
-                       d *= 0.5;\r
-                       --nr;\r
-               }\r
-               return s / div;\r
-       }\r
-\r
-       /**\r
-        * @param noisesize\r
-        * @param x\r
-        * @param y\r
-        * @param z\r
-        * @return\r
-        */\r
-       public float bliHnoisep(float noisesize, float x, float y, float z) {\r
-               return noiseFunctions.get(Integer.valueOf(0)).noise3Perlin(new float[] {x / noisesize, y / noisesize, z / noisesize});\r
-       }\r
-\r
-       /**\r
-        * @param point\r
-        * @param lofreq\r
-        * @param hifreq\r
-        * @return\r
-        */\r
-       public float turbulencePerlin(float[] point, float lofreq, float hifreq) {\r
-               float freq, t = 0, p[] = new float[] {point[0] + 123.456f, point[1], point[2]};\r
-               for(freq = lofreq; freq < hifreq; freq *= 2.) {\r
-                       t += Math.abs(noiseFunctions.get(Integer.valueOf(0)).noise3Perlin(p)) / freq;\r
-                       p[0] *= 2.0f;\r
-                       p[1] *= 2.0f;\r
-                       p[2] *= 2.0f;\r
-               }\r
-               return t - 0.3f; /* readjust to make mean value = 0.0 */\r
-       }\r
-\r
-       /**\r
-        * @param noisesize\r
-        * @param x\r
-        * @param y\r
-        * @param z\r
-        * @param nr\r
-        * @return\r
-        */\r
-       public float turbulencep(float noisesize, float x, float y, float z, int nr) {\r
-               float[] vec = new float[] {x / noisesize, y / noisesize, z / noisesize};\r
-               ++nr;\r
-               return this.turbulencePerlin(vec, 1.0f, (1 << nr));\r
-       }\r
-\r
-       /**\r
-        * Newnoise: generic noise function for use with different noisebases\r
-        * @param x\r
-        * @param y\r
-        * @param z\r
-        * @param oct\r
-        * @param isHard\r
-        * @param noisebasis\r
-        * @return\r
-        */\r
-       public float bliGNoise(float noisesize, float x, float y, float z, boolean isHard, int noisebasis) {\r
-               AbstractNoiseFunc abstractNoiseFunc = noiseFunctions.get(Integer.valueOf(noisebasis));\r
-               if(abstractNoiseFunc == null) {\r
-                       abstractNoiseFunc = noiseFunctions.get(0);\r
-                       noisebasis = 0;\r
-               }\r
-               if(noisebasis == 0) {// add one to make return value same as BLI_hnoise\r
-                       x += 1;\r
-                       y += 1;\r
-                       z += 1;\r
-               }\r
-\r
-               if(noisesize != 0.0) {\r
-                       noisesize = 1.0f / noisesize;\r
-                       x *= noisesize;\r
-                       y *= noisesize;\r
-                       z *= noisesize;\r
-               }\r
-               if(isHard) {\r
-                       return Math.abs(2.0f * abstractNoiseFunc.execute(x, y, z) - 1.0f);\r
-               }\r
-               return abstractNoiseFunc.execute(x, y, z);\r
-       }\r
-\r
-       /**\r
-        * Newnoise: generic turbulence function for use with different noisebasis\r
-        * @param x\r
-        * @param y\r
-        * @param z\r
-        * @param oct\r
-        * @param isHard\r
-        * @param noisebasis\r
-        * @return\r
-        */\r
-       public float bliGTurbulence(float noisesize, float x, float y, float z, int oct, boolean isHard, int noisebasis) {\r
-               AbstractNoiseFunc abstractNoiseFunc = noiseFunctions.get(Integer.valueOf(noisebasis));\r
-               if(abstractNoiseFunc == null) {\r
-                       abstractNoiseFunc = noiseFunctions.get(0);\r
-                       noisebasis = 0;\r
-               }\r
-               if(noisebasis == 0) {// add one to make return value same as BLI_hnoise\r
-                       x += 1;\r
-                       y += 1;\r
-                       z += 1;\r
-               }\r
-               float sum = 0, t, amp = 1, fscale = 1;\r
-\r
-               if(noisesize != 0.0) {\r
-                       noisesize = 1.0f / noisesize;\r
-                       x *= noisesize;\r
-                       y *= noisesize;\r
-                       z *= noisesize;\r
-               }\r
-               for(int i = 0; i <= oct; ++i, amp *= 0.5, fscale *= 2) {\r
-                       t = abstractNoiseFunc.execute(fscale * x, fscale * y, fscale * z);\r
-                       if(isHard) {\r
-                               t = FastMath.abs(2.0f * t - 1.0f);\r
-                       }\r
-                       sum += t * amp;\r
-               }\r
-\r
-               sum *= (float)(1 << oct) / (float)((1 << oct + 1) - 1);\r
-               return sum;\r
-       }\r
-\r
-       /**\r
-        * "Variable Lacunarity Noise" A distorted variety of Perlin noise. This method is used to calculate distorted noise\r
-        * texture.\r
-        * @param x\r
-        * @param y\r
-        * @param z\r
-        * @param distortion\r
-        * @param nbas1\r
-        * @param nbas2\r
-        * @return\r
-        */\r
-       public float mgVLNoise(float x, float y, float z, float distortion, int nbas1, int nbas2) {\r
-               AbstractNoiseFunc abstractNoiseFunc1 = noiseFunctions.get(Integer.valueOf(nbas1));\r
-               if(abstractNoiseFunc1 == null) {\r
-                       abstractNoiseFunc1 = noiseFunctions.get(Integer.valueOf(0));\r
-               }\r
-               AbstractNoiseFunc abstractNoiseFunc2 = noiseFunctions.get(Integer.valueOf(nbas2));\r
-               if(abstractNoiseFunc2 == null) {\r
-                       abstractNoiseFunc2 = noiseFunctions.get(Integer.valueOf(0));\r
-               }\r
-               // get a random vector and scale the randomization\r
-               float rx = abstractNoiseFunc1.execute(x + 13.5f, y + 13.5f, z + 13.5f) * distortion;\r
-               float ry = abstractNoiseFunc1.execute(x, y, z) * distortion;\r
-               float rz = abstractNoiseFunc1.execute(x - 13.5f, y - 13.5f, z - 13.5f) * distortion;\r
-               return abstractNoiseFunc2.executeS(x + rx, y + ry, z + rz); //distorted-domain noise\r
-       }\r
-\r
-       public void mgMFractalOrfBmTex(Structure tex, float[] texvec, ColorBand colorBand, TexResult texres, DataRepository dataRepository) {\r
-               int stype = ((Number)tex.getFieldValue("stype")).intValue();\r
-               float nsOutscale = ((Number)tex.getFieldValue("ns_outscale")).floatValue();\r
-               float nabla = ((Number)tex.getFieldValue("nabla")).floatValue();\r
-               float noisesize = ((Number)tex.getFieldValue("noisesize")).floatValue();\r
-               float contrast = ((Number)tex.getFieldValue("contrast")).floatValue();\r
-               float brightness = ((Number)tex.getFieldValue("bright")).floatValue();\r
-\r
-               IMusgraveFunction mgravefunc = stype == TEX_MFRACTAL ? musgraveFunctions.get(Integer.valueOf(stype)) : musgraveFunctions.get(Integer.valueOf(TEX_FBM));\r
-\r
-               texres.tin = nsOutscale * mgravefunc.execute(tex, texvec[0], texvec[1], texvec[2]);\r
-               if(texres.nor != null) {\r
-                       float offs = nabla / noisesize; // also scaling of texvec\r
-                       // calculate bumpnormal\r
-                       texres.nor[0] = nsOutscale * mgravefunc.execute(tex, texvec[0] + offs, texvec[1], texvec[2]);\r
-                       texres.nor[1] = nsOutscale * mgravefunc.execute(tex, texvec[0], texvec[1] + offs, texvec[2]);\r
-                       texres.nor[2] = nsOutscale * mgravefunc.execute(tex, texvec[0], texvec[1], texvec[2] + offs);\r
-                       this.texNormalDerivate(colorBand, texres, dataRepository);\r
-               }\r
-               this.brightnesAndContrast(texres, contrast, brightness);\r
-       }\r
-\r
-       public void mgRidgedOrHybridMFTex(Structure tex, float[] texvec, ColorBand colorBand, TexResult texres, DataRepository dataRepository) {\r
-               int stype = ((Number)tex.getFieldValue("stype")).intValue();\r
-               float nsOutscale = ((Number)tex.getFieldValue("ns_outscale")).floatValue();\r
-               float nabla = ((Number)tex.getFieldValue("nabla")).floatValue();\r
-               float noisesize = ((Number)tex.getFieldValue("noisesize")).floatValue();\r
-               float contrast = ((Number)tex.getFieldValue("contrast")).floatValue();\r
-               float brightness = ((Number)tex.getFieldValue("bright")).floatValue();\r
-\r
-               IMusgraveFunction mgravefunc = stype == TEX_RIDGEDMF ? musgraveFunctions.get(Integer.valueOf(stype)) : musgraveFunctions.get(Integer.valueOf(TEX_HYBRIDMF));\r
-\r
-               texres.tin = nsOutscale * mgravefunc.execute(tex, texvec[0], texvec[1], texvec[2]);\r
-               if(texres.nor != null) {\r
-                       float offs = nabla / noisesize; // also scaling of texvec\r
-                       // calculate bumpnormal\r
-                       texres.nor[0] = nsOutscale * mgravefunc.execute(tex, texvec[0] + offs, texvec[1], texvec[2]);\r
-                       texres.nor[1] = nsOutscale * mgravefunc.execute(tex, texvec[0], texvec[1] + offs, texvec[2]);\r
-                       texres.nor[2] = nsOutscale * mgravefunc.execute(tex, texvec[0], texvec[1], texvec[2] + offs);\r
-                       this.texNormalDerivate(colorBand, texres, dataRepository);\r
-               }\r
-               this.brightnesAndContrast(texres, contrast, brightness);\r
-       }\r
-\r
-       public void mgHTerrainTex(Structure tex, float[] texvec, ColorBand colorBand, TexResult texres, DataRepository dataRepository) {\r
-               float nsOutscale = ((Number)tex.getFieldValue("ns_outscale")).floatValue();\r
-               float nabla = ((Number)tex.getFieldValue("nabla")).floatValue();\r
-               float noisesize = ((Number)tex.getFieldValue("noisesize")).floatValue();\r
-               float contrast = ((Number)tex.getFieldValue("contrast")).floatValue();\r
-               float brightness = ((Number)tex.getFieldValue("bright")).floatValue();\r
-\r
-               IMusgraveFunction musgraveFunction = musgraveFunctions.get(Integer.valueOf(TEX_HTERRAIN));\r
-               texres.tin = nsOutscale * musgraveFunction.execute(tex, texvec[0], texvec[1], texvec[2]);\r
-               if(texres.nor != null) {\r
-                       float offs = nabla / noisesize; // also scaling of texvec\r
-                       // calculate bumpnormal\r
-                       texres.nor[0] = nsOutscale * musgraveFunction.execute(tex, texvec[0] + offs, texvec[1], texvec[2]);\r
-                       texres.nor[1] = nsOutscale * musgraveFunction.execute(tex, texvec[0], texvec[1] + offs, texvec[2]);\r
-                       texres.nor[2] = nsOutscale * musgraveFunction.execute(tex, texvec[0], texvec[1], texvec[2] + offs);\r
-                       this.texNormalDerivate(colorBand, texres, dataRepository);\r
-               }\r
-               this.brightnesAndContrast(texres, contrast, brightness);\r
-       }\r
-\r
-       /**\r
-        * This class is abstract to the noise functions computations. It has two methods. One calculates the Signed (with\r
-        * 'S' at the end) and the other Unsigned value.\r
-        * @author Marcin Roguski (Kaelthas)\r
-        */\r
-       protected static abstract class AbstractNoiseFunc {\r
-               /**\r
-                * This method calculates the unsigned value of the noise.\r
-                * @param x\r
-                *        the x texture coordinate\r
-                * @param y\r
-                *        the y texture coordinate\r
-                * @param z\r
-                *        the z texture coordinate\r
-                * @return value of the noise\r
-                */\r
-               public abstract float execute(float x, float y, float z);\r
-\r
-               /**\r
-                * This method calculates the signed value of the noise.\r
-                * @param x\r
-                *        the x texture coordinate\r
-                * @param y\r
-                *        the y texture coordinate\r
-                * @param z\r
-                *        the z texture coordinate\r
-                * @return value of the noise\r
-                */\r
-               public abstract float executeS(float x, float y, float z);\r
-\r
-               /*\r
-                * Not 'pure' Worley, but the results are virtually the same. Returns distances in da and point coords in pa\r
-                */\r
-               protected static void voronoi(float x, float y, float z, float[] da, float[] pa, float me, int dtype) {\r
-                       float xd, yd, zd, d, p[];\r
-\r
-                       IDistanceFunc distanceFunc = distanceFunctions.get(Integer.valueOf(dtype));\r
-                       if(distanceFunc == null) {\r
-                               distanceFunc = distanceFunctions.get(Integer.valueOf(0));\r
-                       }\r
-\r
-                       int xi = (int)FastMath.floor(x);\r
-                       int yi = (int)FastMath.floor(y);\r
-                       int zi = (int)FastMath.floor(z);\r
-                       da[0] = da[1] = da[2] = da[3] = 1e10f;\r
-                       for(int xx = xi - 1; xx <= xi + 1; ++xx) {\r
-                               for(int yy = yi - 1; yy <= yi + 1; ++yy) {\r
-                                       for(int zz = zi - 1; zz <= zi + 1; ++zz) {\r
-                                               p = AbstractNoiseFunc.hashPoint(xx, yy, zz);\r
-                                               xd = x - (p[0] + xx);\r
-                                               yd = y - (p[1] + yy);\r
-                                               zd = z - (p[2] + zz);\r
-                                               d = distanceFunc.execute(xd, yd, zd, me);\r
-                                               if(d < da[0]) {\r
-                                                       da[3] = da[2];\r
-                                                       da[2] = da[1];\r
-                                                       da[1] = da[0];\r
-                                                       da[0] = d;\r
-                                                       pa[9] = pa[6];\r
-                                                       pa[10] = pa[7];\r
-                                                       pa[11] = pa[8];\r
-                                                       pa[6] = pa[3];\r
-                                                       pa[7] = pa[4];\r
-                                                       pa[8] = pa[5];\r
-                                                       pa[3] = pa[0];\r
-                                                       pa[4] = pa[1];\r
-                                                       pa[5] = pa[2];\r
-                                                       pa[0] = p[0] + xx;\r
-                                                       pa[1] = p[1] + yy;\r
-                                                       pa[2] = p[2] + zz;\r
-                                               } else if(d < da[1]) {\r
-                                                       da[3] = da[2];\r
-                                                       da[2] = da[1];\r
-                                                       da[1] = d;\r
-                                                       pa[9] = pa[6];\r
-                                                       pa[10] = pa[7];\r
-                                                       pa[11] = pa[8];\r
-                                                       pa[6] = pa[3];\r
-                                                       pa[7] = pa[4];\r
-                                                       pa[8] = pa[5];\r
-                                                       pa[3] = p[0] + xx;\r
-                                                       pa[4] = p[1] + yy;\r
-                                                       pa[5] = p[2] + zz;\r
-                                               } else if(d < da[2]) {\r
-                                                       da[3] = da[2];\r
-                                                       da[2] = d;\r
-                                                       pa[9] = pa[6];\r
-                                                       pa[10] = pa[7];\r
-                                                       pa[11] = pa[8];\r
-                                                       pa[6] = p[0] + xx;\r
-                                                       pa[7] = p[1] + yy;\r
-                                                       pa[8] = p[2] + zz;\r
-                                               } else if(d < da[3]) {\r
-                                                       da[3] = d;\r
-                                                       pa[9] = p[0] + xx;\r
-                                                       pa[10] = p[1] + yy;\r
-                                                       pa[11] = p[2] + zz;\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-\r
-               // #define HASHVEC(x,y,z) hashvectf+3*hash[ (hash[ (hash[(z) & 255]+(y)) & 255]+(x)) & 255]\r
-\r
-               /* needed for voronoi */\r
-               // #define HASHPNT(x,y,z) hashpntf+3*hash[ (hash[ (hash[(z) & 255]+(y)) & 255]+(x)) & 255]\r
-               protected static float[] hashPoint(int x, int y, int z) {\r
-                       float[] result = new float[3];\r
-                       result[0] = hashpntf[3 * hash[hash[hash[z & 255] + y & 255] + x & 255]];\r
-                       result[1] = hashpntf[3 * hash[hash[hash[z & 255] + y & 255] + x & 255] + 1];\r
-                       result[2] = hashpntf[3 * hash[hash[hash[z & 255] + y & 255] + x & 255] + 2];\r
-                       return result;\r
-               }\r
-\r
-               // #define setup(i,b0,b1,r0,r1) \\r
-               // t = vec[i] + 10000.; \\r
-               // b0 = ((int)t) & 255; \\r
-               // b1 = (b0+1) & 255; \\r
-               // r0 = t - (int)t; \\r
-               // r1 = r0 - 1.;\r
-\r
-               // vec[3]\r
-               public float noise3Perlin(float[] vec) {\r
-                       int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11;\r
-                       float rx0, rx1, ry0, ry1, rz0, rz1, sx, sy, sz, a, b, c, d, t, u, v;\r
-                       int i, j;\r
-\r
-                       // setup(0, bx0,bx1, rx0,rx1);\r
-                       t = vec[0] + 10000.0f;\r
-                       bx0 = (int)t & 255;\r
-                       bx1 = bx0 + 1 & 255;\r
-                       rx0 = t - (int)t;\r
-                       rx1 = rx0 - 1.0f;\r
-                       // setup(1, by0,by1, ry0,ry1);\r
-                       t = vec[0] + 10000.0f;\r
-                       by0 = (int)t & 255;\r
-                       by1 = by0 + 1 & 255;\r
-                       ry0 = t - (int)t;\r
-                       ry1 = ry0 - 1.0f;\r
-                       // setup(2, bz0,bz1, rz0,rz1);\r
-                       t = vec[0] + 10000.0f;\r
-                       bz0 = (int)t & 255;\r
-                       bz1 = bz0 + 1 & 255;\r
-                       rz0 = t - (int)t;\r
-                       rz1 = rz0 - 1.0f;\r
-\r
-                       i = p[bx0];\r
-                       j = p[bx1];\r
-\r
-                       b00 = p[i + by0];\r
-                       b10 = p[j + by0];\r
-                       b01 = p[i + by1];\r
-                       b11 = p[j + by1];\r
-\r
-                       /* lerp moved to improved perlin above */\r
-\r
-                       sx = this.surve(rx0);\r
-                       sy = this.surve(ry0);\r
-                       sz = this.surve(rz0);\r
-\r
-                       float[] q = new float[3];\r
-                       q = g[b00 + bz0];\r
-                       u = this.at(rx0, ry0, rz0, q);\r
-                       q = g[b10 + bz0];\r
-                       v = this.at(rx1, ry0, rz0, q);\r
-                       a = this.lerp(sx, u, v);\r
-\r
-                       q = g[b01 + bz0];\r
-                       u = this.at(rx0, ry1, rz0, q);\r
-                       q = g[b11 + bz0];\r
-                       v = this.at(rx1, ry1, rz0, q);\r
-                       b = this.lerp(sx, u, v);\r
-\r
-                       c = this.lerp(sy, a, b); /* interpolate in y at lo x */\r
-\r
-                       q = g[b00 + bz1];\r
-                       u = this.at(rx0, ry0, rz1, q);\r
-                       q = g[b10 + bz1];\r
-                       v = this.at(rx1, ry0, rz1, q);\r
-                       a = this.lerp(sx, u, v);\r
-\r
-                       q = g[b01 + bz1];\r
-                       u = this.at(rx0, ry1, rz1, q);\r
-                       q = g[b11 + bz1];\r
-                       v = this.at(rx1, ry1, rz1, q);\r
-                       b = this.lerp(sx, u, v);\r
-\r
-                       d = this.lerp(sy, a, b); /* interpolate in y at hi x */\r
-\r
-                       return 1.5f * this.lerp(sz, c, d); /* interpolate in z */\r
-               }\r
-\r
-               public float orgBlenderNoise(float x, float y, float z) {\r
-                       float cn1, cn2, cn3, cn4, cn5, cn6, i;\r
-                       float ox, oy, oz, jx, jy, jz;\r
-                       float n = 0.5f;\r
-                       int ix, iy, iz, b00, b01, b10, b11, b20, b21;\r
-\r
-                       ox = x - (ix = (int)Math.floor(x));\r
-                       oy = y - (iy = (int)Math.floor(y));\r
-                       oz = z - (iz = (int)Math.floor(z));\r
-\r
-                       jx = ox - 1;\r
-                       jy = oy - 1;\r
-                       jz = oz - 1;\r
-\r
-                       cn1 = ox * ox;\r
-                       cn2 = oy * oy;\r
-                       cn3 = oz * oz;\r
-                       cn4 = jx * jx;\r
-                       cn5 = jy * jy;\r
-                       cn6 = jz * jz;\r
-\r
-                       cn1 = 1.0f - 3.0f * cn1 + 2.0f * cn1 * ox;\r
-                       cn2 = 1.0f - 3.0f * cn2 + 2.0f * cn2 * oy;\r
-                       cn3 = 1.0f - 3.0f * cn3 + 2.0f * cn3 * oz;\r
-                       cn4 = 1.0f - 3.0f * cn4 - 2.0f * cn4 * jx;\r
-                       cn5 = 1.0f - 3.0f * cn5 - 2.0f * cn5 * jy;\r
-                       cn6 = 1.0f - 3.0f * cn6 - 2.0f * cn6 * jz;\r
-\r
-                       b00 = hash[hash[ix & 255] + (iy & 255)];\r
-                       b10 = hash[hash[ix + 1 & 255] + (iy & 255)];\r
-                       b01 = hash[hash[ix & 255] + (iy + 1 & 255)];\r
-                       b11 = hash[hash[ix + 1 & 255] + (iy + 1 & 255)];\r
-\r
-                       b20 = iz & 255;\r
-                       b21 = iz + 1 & 255;\r
-\r
-                       /* 0 */\r
-                       i = cn1 * cn2 * cn3;\r
-                       int hIndex = 3 * hash[b20 + b00];\r
-                       n += i * (hashvectf[hIndex] * ox + hashvectf[hIndex + 1] * oy + hashvectf[hIndex + 2] * oz);\r
-                       /* 1 */\r
-                       i = cn1 * cn2 * cn6;\r
-                       hIndex = 3 * hash[b21 + b00];\r
-                       n += i * (hashvectf[hIndex] * ox + hashvectf[hIndex + 1] * oy + hashvectf[hIndex + 2] * jz);\r
-                       /* 2 */\r
-                       i = cn1 * cn5 * cn3;\r
-                       hIndex = 3 * hash[b20 + b01];\r
-                       n += i * (hashvectf[hIndex] * ox + hashvectf[hIndex + 1] * jy + hashvectf[hIndex + 2] * oz);\r
-                       /* 3 */\r
-                       i = cn1 * cn5 * cn6;\r
-                       hIndex = 3 * hash[b21 + b01];\r
-                       n += i * (hashvectf[hIndex] * ox + hashvectf[hIndex + 1] * jy + hashvectf[hIndex + 2] * jz);\r
-                       /* 4 */\r
-                       i = cn4 * cn2 * cn3;\r
-                       hIndex = 3 * hash[b20 + b10];\r
-                       n += i * (hashvectf[hIndex] * jx + hashvectf[hIndex + 1] * oy + hashvectf[hIndex + 2] * oz);\r
-                       /* 5 */\r
-                       i = cn4 * cn2 * cn6;\r
-                       hIndex = 3 * hash[b21 + b10];\r
-                       n += i * (hashvectf[hIndex] * jx + hashvectf[hIndex + 1] * oy + hashvectf[hIndex + 2] * jz);\r
-                       /* 6 */\r
-                       i = cn4 * cn5 * cn3;\r
-                       hIndex = 3 * hash[b20 + b11];\r
-                       n += i * (hashvectf[hIndex] * jx + hashvectf[hIndex + 1] * jy + hashvectf[hIndex + 2] * oz);\r
-                       /* 7 */\r
-                       i = cn4 * cn5 * cn6;\r
-                       hIndex = 3 * hash[b21 + b11];\r
-                       n += i * (hashvectf[hIndex] * jx + hashvectf[hIndex + 1] * jy + hashvectf[hIndex + 2] * jz);\r
-\r
-                       if(n < 0.0f) {\r
-                               n = 0.0f;\r
-                       } else if(n > 1.0f) {\r
-                               n = 1.0f;\r
-                       }\r
-                       return n;\r
-               }\r
-\r
-               /* instead of adding another permutation array, just use hash table defined above */\r
-               public float newPerlin(float x, float y, float z) {\r
-                       int A, AA, AB, B, BA, BB;\r
-                       float u = (float)Math.floor(x), v = (float)Math.floor(y), w = (float)Math.floor(z);\r
-                       int X = (int)u & 255, Y = (int)v & 255, Z = (int)w & 255; // FIND UNIT CUBE THAT CONTAINS POINT\r
-                       x -= u; // FIND RELATIVE X,Y,Z\r
-                       y -= v; // OF POINT IN CUBE.\r
-                       z -= w;\r
-                       u = this.npfade(x); // COMPUTE FADE CURVES\r
-                       v = this.npfade(y); // FOR EACH OF X,Y,Z.\r
-                       w = this.npfade(z);\r
-                       A = hash[X] + Y;\r
-                       AA = hash[A] + Z;\r
-                       AB = hash[A + 1] + Z; // HASH COORDINATES OF\r
-                       B = hash[X + 1] + Y;\r
-                       BA = hash[B] + Z;\r
-                       BB = hash[B + 1] + Z; // THE 8 CUBE CORNERS,\r
-                       return this.lerp(w, this.lerp(v, this.lerp(u, this.grad(hash[AA], x, y, z), // AND ADD\r
-                                       this.grad(hash[BA], x - 1, y, z)), // BLENDED\r
-                                       this.lerp(u, this.grad(hash[AB], x, y - 1, z), // RESULTS\r
-                                                       this.grad(hash[BB], x - 1, y - 1, z))),// FROM 8\r
-                                       this.lerp(v, this.lerp(u, this.grad(hash[AA + 1], x, y, z - 1), // CORNERS\r
-                                                       this.grad(hash[BA + 1], x - 1, y, z - 1)), // OF CUBE\r
-                                                       this.lerp(u, this.grad(hash[AB + 1], x, y - 1, z - 1), this.grad(hash[BB + 1], x - 1, y - 1, z - 1))));\r
-               }\r
-\r
-               /**\r
-                * Returns a vector/point/color in ca, using point hasharray directly\r
-                */\r
-               protected static void cellNoiseV(float x, float y, float z, float[] ca) {\r
-                       int xi = (int)Math.floor(x);\r
-                       int yi = (int)Math.floor(y);\r
-                       int zi = (int)Math.floor(z);\r
-                       float[] p = AbstractNoiseFunc.hashPoint(xi, yi, zi);\r
-                       ca[0] = p[0];\r
-                       ca[1] = p[1];\r
-                       ca[2] = p[2];\r
-               }\r
-\r
-               protected float lerp(float t, float a, float b) {\r
-                       return a + t * (b - a);\r
-               }\r
-\r
-               protected float npfade(float t) {\r
-                       return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f);\r
-               }\r
-\r
-               protected float grad(int hash, float x, float y, float z) {\r
-                       int h = hash & 0x0F; // CONVERT LO 4 BITS OF HASH CODE\r
-                       float u = h < 8 ? x : y, // INTO 12 GRADIENT DIRECTIONS.\r
-                       v = h < 4 ? y : h == 12 || h == 14 ? x : z;\r
-                       return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);\r
-               }\r
-\r
-               /**\r
-                * Dot product of two vectors.\r
-                * @param a\r
-                *        the first vector\r
-                * @param b\r
-                *        the second vector\r
-                * @return the dot product of two vectors\r
-                */\r
-               protected float dot(float[] a, float[] b) {\r
-                       return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];\r
-               }\r
-\r
-               protected float surve(float t) {\r
-                       return t * t * (3.0f - 2.0f * t);\r
-               }\r
-\r
-               protected float at(float rx, float ry, float rz, float[] q) {\r
-                       return rx * q[0] + ry * q[1] + rz * q[2];\r
-               }\r
-       }\r
-\r
-       /**\r
-        * This interface is used for distance calculation classes. Distance metrics for voronoi. e parameter only used in\r
-        * Minkovsky.\r
-        */\r
-       interface IDistanceFunc {\r
-               /**\r
-                * This method calculates the distance for voronoi algorithms.\r
-                * @param x\r
-                *        the x coordinate\r
-                * @param y\r
-                *        the y coordinate\r
-                * @param z\r
-                *        the z coordinate\r
-                * @param e\r
-                *        this parameter used in Monkovsky (no idea what it really is ;)\r
-                * @return\r
-                */\r
-               float execute(float x, float y, float z, float e);\r
-       }\r
-\r
-       interface IMusgraveFunction {\r
-               float execute(Structure tex, float x, float y, float z);\r
-       }\r
+\r
+    private static final Logger LOGGER = Logger.getLogger(NoiseHelper.class.getName());\r
+\r
+    /* return value */\r
+    protected static final int TEX_INT = 0;\r
+    protected static final int TEX_RGB = 1;\r
+    protected static final int TEX_NOR = 2;\r
+\r
+    /* noisetype */\r
+    protected static final int TEX_NOISESOFT = 0;\r
+    protected static final int TEX_NOISEPERL = 1;\r
+\r
+    /* tex->stype in texture.c - cloud types */\r
+    protected static final int TEX_DEFAULT = 0;\r
+    protected static final int TEX_COLOR = 1;\r
+\r
+    /* flag */\r
+    protected static final int TEX_COLORBAND = 1;\r
+    protected static final int TEX_FLIPBLEND = 2;\r
+    protected static final int TEX_NEGALPHA = 4;\r
+    protected static final int TEX_CHECKER_ODD = 8;\r
+    protected static final int TEX_CHECKER_EVEN = 16;\r
+    protected static final int TEX_PRV_ALPHA = 32;\r
+    protected static final int TEX_PRV_NOR = 64;\r
+    protected static final int TEX_REPEAT_XMIR = 128;\r
+    protected static final int TEX_REPEAT_YMIR = 256;\r
+    protected static final int TEX_FLAG_MASK = TEX_COLORBAND | TEX_FLIPBLEND | TEX_NEGALPHA | TEX_CHECKER_ODD | TEX_CHECKER_EVEN | TEX_PRV_ALPHA | TEX_PRV_NOR | TEX_REPEAT_XMIR | TEX_REPEAT_YMIR;\r
+\r
+    /* tex->noisebasis2 in texture.c - wood waveforms */\r
+    protected static final int TEX_SIN = 0;\r
+    protected static final int TEX_SAW = 1;\r
+    protected static final int TEX_TRI = 2;\r
+\r
+    /* tex->stype in texture.c - marble types */\r
+    protected static final int TEX_SOFT = 0;\r
+    protected static final int TEX_SHARP = 1;\r
+    protected static final int TEX_SHARPER = 2;\r
+\r
+    /* tex->stype in texture.c - wood types */\r
+    protected static final int TEX_BAND = 0;\r
+    protected static final int TEX_RING = 1;\r
+    protected static final int TEX_BANDNOISE = 2;\r
+    protected static final int TEX_RINGNOISE = 3;\r
+\r
+    /* tex->stype in texture.c - blend types */\r
+    protected static final int TEX_LIN = 0;\r
+    protected static final int TEX_QUAD = 1;\r
+    protected static final int TEX_EASE = 2;\r
+    protected static final int TEX_DIAG = 3;\r
+    protected static final int TEX_SPHERE = 4;\r
+    protected static final int TEX_HALO = 5;\r
+    protected static final int TEX_RAD = 6;\r
+\r
+    /* tex->stype in texture.c - stucci types */\r
+    protected static final int TEX_PLASTIC = 0;\r
+    protected static final int TEX_WALLIN = 1;\r
+    protected static final int TEX_WALLOUT = 2;\r
+\r
+    /* musgrave stype */\r
+    protected static final int TEX_MFRACTAL = 0;\r
+    protected static final int TEX_RIDGEDMF = 1;\r
+    protected static final int TEX_HYBRIDMF = 2;\r
+    protected static final int TEX_FBM = 3;\r
+    protected static final int TEX_HTERRAIN = 4;\r
+\r
+    /* keyblock->type */\r
+    protected static final int KEY_LINEAR = 0;\r
+    protected static final int KEY_CARDINAL = 1;\r
+    protected static final int KEY_BSPLINE = 2;\r
+\r
+    /* CONSTANTS (read from file) */\r
+    protected static float[] hashpntf;\r
+    protected static short[] hash;\r
+    protected static float[] hashvectf;\r
+    protected static short[] p;\r
+    protected static float[][] g;\r
+\r
+    /**\r
+     * Constructor. Stores the blender version number and loads the constants needed for computations.\r
+     * @param blenderVersion\r
+     *        the number of blender version\r
+     */\r
+    public NoiseHelper(String blenderVersion) {\r
+        super(blenderVersion);\r
+        this.loadConstants();\r
+    }\r
+\r
+    /**\r
+     * This method loads the constants needed for computations. They are exactly like the ones the blender uses. Each\r
+     * deriving class should override this method and load its own constraints. Be carefult with overriding though, if\r
+     * an exception will be thrown the class will not be instantiated.\r
+     */\r
+    protected void loadConstants() {\r
+        InputStream is = NoiseHelper.class.getResourceAsStream("noiseconstants.dat");\r
+        try {\r
+            ObjectInputStream ois = new ObjectInputStream(is);\r
+            hashpntf = (float[]) ois.readObject();\r
+            hash = (short[]) ois.readObject();\r
+            hashvectf = (float[]) ois.readObject();\r
+            p = (short[]) ois.readObject();\r
+            g = (float[][]) ois.readObject();\r
+        } catch (IOException e) {\r
+            LOGGER.log(Level.SEVERE, e.getLocalizedMessage(), e);\r
+        } catch (ClassNotFoundException e) {\r
+            assert false : "Constants' classes should be arrays of primitive types, so they are ALWAYS known!";\r
+        } finally {\r
+            if (is != null) {\r
+                try {\r
+                    is.close();\r
+                } catch (IOException e) {\r
+                    LOGGER.log(Level.WARNING, e.getLocalizedMessage());\r
+                }\r
+            }\r
+        }\r
+    }\r
+    protected static Map<Integer, AbstractNoiseFunc> noiseFunctions = new HashMap<Integer, AbstractNoiseFunc>();\r
+\r
+    static {\r
+        // orgBlenderNoise (*Was BLI_hnoise(), removed noisesize, so other functions can call it without scaling.*)\r
+        noiseFunctions.put(Integer.valueOf(0), new AbstractNoiseFunc() {\r
+\r
+            @Override\r
+            public float execute(float x, float y, float z) {\r
+                return this.orgBlenderNoise(x, y, z);\r
+            }\r
+\r
+            @Override\r
+            public float executeS(float x, float y, float z) {\r
+                return 2.0f * this.orgBlenderNoise(x, y, z) - 1.0f;\r
+            }\r
+        });\r
+        // orgPerlinNoise (*For use with BLI_gNoise/gTurbulence, returns signed noise.*)\r
+        noiseFunctions.put(Integer.valueOf(1), new AbstractNoiseFunc() {\r
+\r
+            @Override\r
+            public float execute(float x, float y, float z) {\r
+                return 0.5f + 0.5f * this.noise3Perlin(new float[]{x, y, z});\r
+            }\r
+\r
+            @Override\r
+            public float executeS(float x, float y, float z) {\r
+                return this.noise3Perlin(new float[]{x, y, z});\r
+            }\r
+        });\r
+        // newPerlin (* for use with BLI_gNoise()/BLI_gTurbulence(), returns unsigned improved perlin noise *)\r
+        noiseFunctions.put(Integer.valueOf(2), new AbstractNoiseFunc() {\r
+\r
+            @Override\r
+            public float execute(float x, float y, float z) {\r
+                return 0.5f + 0.5f * this.newPerlin(x, y, z);\r
+            }\r
+\r
+            @Override\r
+            public float executeS(float x, float y, float z) {\r
+                return this.execute(x, y, z);\r
+            }\r
+        });\r
+        // voronoi_F1\r
+        noiseFunctions.put(Integer.valueOf(3), new AbstractNoiseFunc() {\r
+\r
+            @Override\r
+            public float execute(float x, float y, float z) {\r
+                float[] da = new float[4], pa = new float[12];\r
+                AbstractNoiseFunc.voronoi(x, y, z, da, pa, 1, 0);\r
+                return da[0];\r
+            }\r
+\r
+            @Override\r
+            public float executeS(float x, float y, float z) {\r
+                float[] da = new float[4], pa = new float[12];\r
+                AbstractNoiseFunc.voronoi(x, y, z, da, pa, 1, 0);\r
+                return 2.0f * da[0] - 1.0f;\r
+            }\r
+        });\r
+        // voronoi_F2\r
+        noiseFunctions.put(Integer.valueOf(4), new AbstractNoiseFunc() {\r
+\r
+            @Override\r
+            public float execute(float x, float y, float z) {\r
+                float[] da = new float[4], pa = new float[12];\r
+                AbstractNoiseFunc.voronoi(x, y, z, da, pa, 1, 0);\r
+                return da[1];\r
+            }\r
+\r
+            @Override\r
+            public float executeS(float x, float y, float z) {\r
+                float[] da = new float[4], pa = new float[12];\r
+                AbstractNoiseFunc.voronoi(x, y, z, da, pa, 1, 0);\r
+                return 2.0f * da[1] - 1.0f;\r
+            }\r
+        });\r
+        // voronoi_F3\r
+        noiseFunctions.put(Integer.valueOf(5), new AbstractNoiseFunc() {\r
+\r
+            @Override\r
+            public float execute(float x, float y, float z) {\r
+                float[] da = new float[4], pa = new float[12];\r
+                AbstractNoiseFunc.voronoi(x, y, z, da, pa, 1, 0);\r
+                return da[2];\r
+            }\r
+\r
+            @Override\r
+            public float executeS(float x, float y, float z) {\r
+                float[] da = new float[4], pa = new float[12];\r
+                AbstractNoiseFunc.voronoi(x, y, z, da, pa, 1, 0);\r
+                return 2.0f * da[2] - 1.0f;\r
+            }\r
+        });\r
+        // voronoi_F4\r
+        noiseFunctions.put(Integer.valueOf(6), new AbstractNoiseFunc() {\r
+\r
+            @Override\r
+            public float execute(float x, float y, float z) {\r
+                float[] da = new float[4], pa = new float[12];\r
+                AbstractNoiseFunc.voronoi(x, y, z, da, pa, 1, 0);\r
+                return da[3];\r
+            }\r
+\r
+            @Override\r
+            public float executeS(float x, float y, float z) {\r
+                float[] da = new float[4], pa = new float[12];\r
+                AbstractNoiseFunc.voronoi(x, y, z, da, pa, 1, 0);\r
+                return 2.0f * da[3] - 1.0f;\r
+            }\r
+        });\r
+        // voronoi_F1F2\r
+        noiseFunctions.put(Integer.valueOf(7), new AbstractNoiseFunc() {\r
+\r
+            @Override\r
+            public float execute(float x, float y, float z) {\r
+                float[] da = new float[4], pa = new float[12];\r
+                AbstractNoiseFunc.voronoi(x, y, z, da, pa, 1, 0);\r
+                return da[1] - da[0];\r
+            }\r
+\r
+            @Override\r
+            public float executeS(float x, float y, float z) {\r
+                float[] da = new float[4], pa = new float[12];\r
+                AbstractNoiseFunc.voronoi(x, y, z, da, pa, 1, 0);\r
+                return 2.0f * (da[1] - da[0]) - 1.0f;\r
+            }\r
+        });\r
+        // voronoi_Cr\r
+        noiseFunctions.put(Integer.valueOf(8), new AbstractNoiseFunc() {\r
+\r
+            @Override\r
+            public float execute(float x, float y, float z) {\r
+                float t = 10 * noiseFunctions.get(Integer.valueOf(7)).execute(x, y, z);// voronoi_F1F2\r
+                return t > 1.0f ? 1.0f : t;\r
+            }\r
+\r
+            @Override\r
+            public float executeS(float x, float y, float z) {\r
+                float t = 10.0f * noiseFunctions.get(Integer.valueOf(7)).execute(x, y, z);// voronoi_F1F2\r
+                return t > 1.0f ? 1.0f : 2.0f * t - 1.0f;\r
+            }\r
+        });\r
+        // cellNoise\r
+        noiseFunctions.put(Integer.valueOf(14), new AbstractNoiseFunc() {\r
+\r
+            @Override\r
+            public float execute(float x, float y, float z) {\r
+                int xi = (int) Math.floor(x);\r
+                int yi = (int) Math.floor(y);\r
+                int zi = (int) Math.floor(z);\r
+                long n = xi + yi * 1301 + zi * 314159;\r
+                n ^= n << 13;\r
+                return (n * (n * n * 15731 + 789221) + 1376312589) / 4294967296.0f;\r
+            }\r
+\r
+            @Override\r
+            public float executeS(float x, float y, float z) {\r
+                return 2.0f * this.execute(x, y, z) - 1.0f;\r
+            }\r
+        });\r
+    }\r
+    /** Distance metrics for voronoi. e parameter only used in Minkovsky. */\r
+    protected static Map<Integer, DistanceFunc> distanceFunctions = new HashMap<Integer, NoiseHelper.DistanceFunc>();\r
+\r
+    static {\r
+        // real distance\r
+        distanceFunctions.put(Integer.valueOf(0), new DistanceFunc() {\r
+\r
+            @Override\r
+            public float execute(float x, float y, float z, float e) {\r
+                return (float) Math.sqrt(x * x + y * y + z * z);\r
+            }\r
+        });\r
+        // distance squared\r
+        distanceFunctions.put(Integer.valueOf(1), new DistanceFunc() {\r
+\r
+            @Override\r
+            public float execute(float x, float y, float z, float e) {\r
+                return x * x + y * y + z * z;\r
+            }\r
+        });\r
+        // manhattan/taxicab/cityblock distance\r
+        distanceFunctions.put(Integer.valueOf(2), new DistanceFunc() {\r
+\r
+            @Override\r
+            public float execute(float x, float y, float z, float e) {\r
+                return FastMath.abs(x) + FastMath.abs(y) + FastMath.abs(z);\r
+            }\r
+        });\r
+        // Chebychev\r
+        distanceFunctions.put(Integer.valueOf(3), new DistanceFunc() {\r
+\r
+            @Override\r
+            public float execute(float x, float y, float z, float e) {\r
+                x = FastMath.abs(x);\r
+                y = FastMath.abs(y);\r
+                z = FastMath.abs(z);\r
+                float t = x > y ? x : y;\r
+                return z > t ? z : t;\r
+            }\r
+        });\r
+        // minkovsky preset exponent 0.5 (MinkovskyH)\r
+        distanceFunctions.put(Integer.valueOf(4), new DistanceFunc() {\r
+\r
+            @Override\r
+            public float execute(float x, float y, float z, float e) {\r
+                float d = (float) (Math.sqrt(FastMath.abs(x)) + Math.sqrt(FastMath.abs(y)) + Math.sqrt(FastMath.abs(z)));\r
+                return d * d;\r
+            }\r
+        });\r
+        // minkovsky preset exponent 4 (Minkovsky4)\r
+        distanceFunctions.put(Integer.valueOf(5), new DistanceFunc() {\r
+\r
+            @Override\r
+            public float execute(float x, float y, float z, float e) {\r
+                x *= x;\r
+                y *= y;\r
+                z *= z;\r
+                return (float) Math.sqrt(Math.sqrt(x * x + y * y + z * z));\r
+            }\r
+        });\r
+        // Minkovsky, general case, slow, maybe too slow to be useful\r
+        distanceFunctions.put(Integer.valueOf(6), new DistanceFunc() {\r
+\r
+            @Override\r
+            public float execute(float x, float y, float z, float e) {\r
+                return (float) Math.pow(Math.pow(FastMath.abs(x), e) + Math.pow(FastMath.abs(y), e) + Math.pow(FastMath.abs(z), e), 1.0f / e);\r
+            }\r
+        });\r
+    }\r
+    protected static Map<Integer, MusgraveFunction> musgraveFunctions = new HashMap<Integer, NoiseHelper.MusgraveFunction>();\r
+\r
+    static {\r
+        musgraveFunctions.put(Integer.valueOf(TEX_MFRACTAL), new MusgraveFunction() {\r
+\r
+            @Override\r
+            public float execute(Structure tex, float x, float y, float z) {\r
+                float mg_H = ((Number) tex.getFieldValue("mg_H")).floatValue();\r
+                float mg_lacunarity = ((Number) tex.getFieldValue("mg_lacunarity")).floatValue();\r
+                float mg_octaves = ((Number) tex.getFieldValue("mg_octaves")).floatValue();\r
+                int noisebasis = ((Number) tex.getFieldValue("noisebasis")).intValue();\r
+\r
+                float rmd, value = 1.0f, pwr = 1.0f, pwHL = (float) Math.pow(mg_lacunarity, -mg_H);\r
+                AbstractNoiseFunc abstractNoiseFunc = noiseFunctions.get(Integer.valueOf(noisebasis));\r
+                if (abstractNoiseFunc == null) {\r
+                    abstractNoiseFunc = noiseFunctions.get(Integer.valueOf(0));\r
+                }\r
+\r
+                for (int i = 0; i < (int) mg_octaves; ++i) {\r
+                    value *= pwr * abstractNoiseFunc.executeS(x, y, z) + 1.0f;\r
+                    pwr *= pwHL;\r
+                    x *= mg_lacunarity;\r
+                    y *= mg_lacunarity;\r
+                    z *= mg_lacunarity;\r
+                }\r
+                rmd = (float) (mg_octaves - Math.floor(mg_octaves));\r
+                if (rmd != 0.0f) {\r
+                    value *= rmd * abstractNoiseFunc.executeS(x, y, z) * pwr + 1.0f;\r
+                }\r
+                return value;\r
+            }\r
+        });\r
+        musgraveFunctions.put(Integer.valueOf(TEX_RIDGEDMF), new MusgraveFunction() {\r
+\r
+            @Override\r
+            public float execute(Structure tex, float x, float y, float z) {\r
+                float mg_H = ((Number) tex.getFieldValue("mg_H")).floatValue();\r
+                float mg_lacunarity = ((Number) tex.getFieldValue("mg_lacunarity")).floatValue();\r
+                float mg_octaves = ((Number) tex.getFieldValue("mg_octaves")).floatValue();\r
+                float mg_offset = ((Number) tex.getFieldValue("mg_offset")).floatValue();\r
+                int noisebasis = ((Number) tex.getFieldValue("noisebasis")).intValue();\r
+                float mg_gain = ((Number) tex.getFieldValue("mg_gain")).floatValue();\r
+                float result, signal, weight;\r
+                float pwHL = (float) Math.pow(mg_lacunarity, -mg_H);\r
+                float pwr = pwHL; /* starts with i=1 instead of 0 */\r
+\r
+                AbstractNoiseFunc abstractNoiseFunc = noiseFunctions.get(Integer.valueOf(noisebasis));\r
+                if (abstractNoiseFunc == null) {\r
+                    abstractNoiseFunc = noiseFunctions.get(Integer.valueOf(0));\r
+                }\r
+\r
+                signal = mg_offset - FastMath.abs(abstractNoiseFunc.executeS(x, y, z));\r
+                signal *= signal;\r
+                result = signal;\r
+                weight = 1.0f;\r
+\r
+                for (int i = 1; i < (int) mg_octaves; ++i) {\r
+                    x *= mg_lacunarity;\r
+                    y *= mg_lacunarity;\r
+                    z *= mg_lacunarity;\r
+                    weight = signal * mg_gain;\r
+                    if (weight > 1.0f) {\r
+                        weight = 1.0f;\r
+                    } else if (weight < 0.0) {\r
+                        weight = 0.0f;\r
+                    }\r
+                    signal = mg_offset - FastMath.abs(abstractNoiseFunc.executeS(x, y, z));\r
+                    signal *= signal;\r
+                    signal *= weight;\r
+                    result += signal * pwr;\r
+                    pwr *= pwHL;\r
+                }\r
+                return result;\r
+            }\r
+        });\r
+        musgraveFunctions.put(Integer.valueOf(TEX_HYBRIDMF), new MusgraveFunction() {\r
+\r
+            @Override\r
+            public float execute(Structure tex, float x, float y, float z) {\r
+                float mg_H = ((Number) tex.getFieldValue("mg_H")).floatValue();\r
+                float mg_lacunarity = ((Number) tex.getFieldValue("mg_lacunarity")).floatValue();\r
+                float mg_octaves = ((Number) tex.getFieldValue("mg_octaves")).floatValue();\r
+                float mg_offset = ((Number) tex.getFieldValue("mg_offset")).floatValue();\r
+                int noisebasis = ((Number) tex.getFieldValue("noisebasis")).intValue();\r
+                float mg_gain = ((Number) tex.getFieldValue("mg_gain")).floatValue();\r
+                float result, signal, weight, rmd;\r
+                float pwHL = (float) Math.pow(mg_lacunarity, -mg_H);\r
+                float pwr = pwHL; /* starts with i=1 instead of 0 */\r
+                AbstractNoiseFunc abstractNoiseFunc = noiseFunctions.get(Integer.valueOf(noisebasis));\r
+                if (abstractNoiseFunc == null) {\r
+                    abstractNoiseFunc = noiseFunctions.get(Integer.valueOf(0));\r
+                }\r
+\r
+                result = abstractNoiseFunc.executeS(x, y, z) + mg_offset;\r
+                weight = mg_gain * result;\r
+                x *= mg_lacunarity;\r
+                y *= mg_lacunarity;\r
+                z *= mg_lacunarity;\r
+\r
+                for (int i = 1; weight > 0.001f && i < (int) mg_octaves; ++i) {\r
+                    if (weight > 1.0f) {\r
+                        weight = 1.0f;\r
+                    }\r
+                    signal = (abstractNoiseFunc.executeS(x, y, z) + mg_offset) * pwr;\r
+                    pwr *= pwHL;\r
+                    result += weight * signal;\r
+                    weight *= mg_gain * signal;\r
+                    x *= mg_lacunarity;\r
+                    y *= mg_lacunarity;\r
+                    z *= mg_lacunarity;\r
+                }\r
+\r
+                rmd = mg_octaves - (float) Math.floor(mg_octaves);\r
+                if (rmd != 0.0f) {\r
+                    result += rmd * (abstractNoiseFunc.executeS(x, y, z) + mg_offset) * pwr;\r
+                }\r
+                return result;\r
+            }\r
+        });\r
+        musgraveFunctions.put(Integer.valueOf(TEX_FBM), new MusgraveFunction() {\r
+\r
+            @Override\r
+            public float execute(Structure tex, float x, float y, float z) {\r
+                float mg_H = ((Number) tex.getFieldValue("mg_H")).floatValue();\r
+                float mg_lacunarity = ((Number) tex.getFieldValue("mg_lacunarity")).floatValue();\r
+                float mg_octaves = ((Number) tex.getFieldValue("mg_octaves")).floatValue();\r
+                int noisebasis = ((Number) tex.getFieldValue("noisebasis")).intValue();\r
+                float rmd, value = 0.0f, pwr = 1.0f, pwHL = (float) Math.pow(mg_lacunarity, -mg_H);\r
+\r
+                AbstractNoiseFunc abstractNoiseFunc = noiseFunctions.get(Integer.valueOf(noisebasis));\r
+                if (abstractNoiseFunc == null) {\r
+                    abstractNoiseFunc = noiseFunctions.get(Integer.valueOf(0));\r
+                }\r
+\r
+                for (int i = 0; i < (int) mg_octaves; ++i) {\r
+                    value += abstractNoiseFunc.executeS(x, y, z) * pwr;\r
+                    pwr *= pwHL;\r
+                    x *= mg_lacunarity;\r
+                    y *= mg_lacunarity;\r
+                    z *= mg_lacunarity;\r
+                }\r
+\r
+                rmd = (float) (mg_octaves - Math.floor(mg_octaves));\r
+                if (rmd != 0.f) {\r
+                    value += rmd * abstractNoiseFunc.executeS(x, y, z) * pwr;\r
+                }\r
+                return value;\r
+            }\r
+        });\r
+        musgraveFunctions.put(Integer.valueOf(TEX_HTERRAIN), new MusgraveFunction() {\r
+\r
+            @Override\r
+            public float execute(Structure tex, float x, float y, float z) {\r
+                float mg_H = ((Number) tex.getFieldValue("mg_H")).floatValue();\r
+                float mg_lacunarity = ((Number) tex.getFieldValue("mg_lacunarity")).floatValue();\r
+                float mg_octaves = ((Number) tex.getFieldValue("mg_octaves")).floatValue();\r
+                int noisebasis = ((Number) tex.getFieldValue("noisebasis")).intValue();\r
+                float mg_offset = ((Number) tex.getFieldValue("mg_offset")).floatValue();\r
+                float value, increment, rmd;\r
+                float pwHL = (float) Math.pow(mg_lacunarity, -mg_H);\r
+                float pwr = pwHL; /* starts with i=1 instead of 0 */\r
+                AbstractNoiseFunc abstractNoiseFunc = noiseFunctions.get(Integer.valueOf(noisebasis));\r
+                if (abstractNoiseFunc == null) {\r
+                    abstractNoiseFunc = noiseFunctions.get(Integer.valueOf(0));\r
+                }\r
+\r
+                /* first unscaled octave of function; later octaves are scaled */\r
+                value = mg_offset + abstractNoiseFunc.executeS(x, y, z);\r
+                x *= mg_lacunarity;\r
+                y *= mg_lacunarity;\r
+                z *= mg_lacunarity;\r
+\r
+                for (int i = 1; i < (int) mg_octaves; ++i) {\r
+                    increment = (abstractNoiseFunc.executeS(x, y, z) + mg_offset) * pwr * value;\r
+                    value += increment;\r
+                    pwr *= pwHL;\r
+                    x *= mg_lacunarity;\r
+                    y *= mg_lacunarity;\r
+                    z *= mg_lacunarity;\r
+                }\r
+\r
+                rmd = mg_octaves - (float) Math.floor(mg_octaves);\r
+                if (rmd != 0.0) {\r
+                    increment = (abstractNoiseFunc.executeS(x, y, z) + mg_offset) * pwr * value;\r
+                    value += rmd * increment;\r
+                }\r
+                return value;\r
+            }\r
+        });\r
+    }\r
+\r
+    /**\r
+     * THE FOLLOWING METHODS HELP IN COMPUTATION OF THE TEXTURES.\r
+     */\r
+    protected void brightnesAndContrast(TexResult texres, float contrast, float brightness) {\r
+        texres.tin = (texres.tin - 0.5f) * contrast + brightness - 0.5f;\r
+        if (texres.tin < 0.0f) {\r
+            texres.tin = 0.0f;\r
+        } else if (texres.tin > 1.0f) {\r
+            texres.tin = 1.0f;\r
+        }\r
+    }\r
+\r
+    protected void brightnesAndContrastRGB(Structure tex, TexResult texres) {\r
+        float contrast = ((Number) tex.getFieldValue("contrast")).floatValue();\r
+        float bright = ((Number) tex.getFieldValue("bright")).floatValue();\r
+        float rfac = ((Number) tex.getFieldValue("rfac")).floatValue();\r
+        float gfac = ((Number) tex.getFieldValue("gfac")).floatValue();\r
+        float bfac = ((Number) tex.getFieldValue("bfac")).floatValue();\r
+\r
+        texres.tr = rfac * ((texres.tr - 0.5f) * contrast + bright - 0.5f);\r
+        if (texres.tr < 0.0f) {\r
+            texres.tr = 0.0f;\r
+        }\r
+        texres.tg = gfac * ((texres.tg - 0.5f) * contrast + bright - 0.5f);\r
+        if (texres.tg < 0.0f) {\r
+            texres.tg = 0.0f;\r
+        }\r
+        texres.tb = bfac * ((texres.tb - 0.5f) * contrast + bright - 0.5f);\r
+        if (texres.tb < 0.0f) {\r
+            texres.tb = 0.0f;\r
+        }\r
+    }\r
+\r
+    /* this allows colorbanded textures to control normals as well */\r
+    public void texNormalDerivate(ColorBand colorBand, TexResult texres, DataRepository dataRepository) {\r
+        if (texres.nor != null) {\r
+            TexResult fakeTexresult;\r
+            try {\r
+                fakeTexresult = (TexResult) texres.clone();\r
+            } catch (CloneNotSupportedException e) {\r
+                throw new IllegalStateException("Texture result class MUST support cloning!", e);\r
+            }\r
+\r
+            float fac0 = fakeTexresult.tr + fakeTexresult.tg + fakeTexresult.tb;\r
+            fakeTexresult.tin = texres.nor[0];\r
+            this.doColorband(colorBand, fakeTexresult, dataRepository);\r
+\r
+            float fac1 = fakeTexresult.tr + fakeTexresult.tg + fakeTexresult.tb;\r
+            fakeTexresult.tin = texres.nor[1];\r
+            this.doColorband(colorBand, fakeTexresult, dataRepository);\r
+\r
+            float fac2 = fakeTexresult.tr + fakeTexresult.tg + fakeTexresult.tb;\r
+            fakeTexresult.tin = texres.nor[2];\r
+            this.doColorband(colorBand, fakeTexresult, dataRepository);\r
+\r
+            float fac3 = fakeTexresult.tr + fakeTexresult.tg + fakeTexresult.tb;\r
+\r
+            texres.nor[0] = 0.3333f * (fac0 - fac1);\r
+            texres.nor[1] = 0.3333f * (fac0 - fac2);\r
+            texres.nor[2] = 0.3333f * (fac0 - fac3);\r
+\r
+            texres.nor[0] = texres.tin - texres.nor[0];\r
+            texres.nor[1] = texres.tin - texres.nor[1];\r
+            texres.nor[2] = texres.tin - texres.nor[2];\r
+        }\r
+    }\r
+\r
+    /**\r
+     * This method calculates the colorband for the texture.\r
+     * @param colorBand\r
+     *        the colorband data\r
+     * @param texres\r
+     *        the texture pixel result\r
+     * @param dataRepository\r
+     *        the data repository\r
+     * @return <b>true</b> if calculation suceedess and <b>false</b> otherwise\r
+     */\r
+    public boolean doColorband(ColorBand colorBand, TexResult texres, DataRepository dataRepository) {\r
+        CBData cbd1, cbd2, cbd0, cbd3;\r
+        int i1 = 0, i2 = 0, a;\r
+        float fac, mfac;\r
+        float[] t = new float[4];\r
+\r
+        if (colorBand == null || colorBand.tot == 0) {\r
+            return true;\r
+        }\r
+\r
+        cbd1 = colorBand.data[0];\r
+        if (colorBand.tot == 1) {\r
+            texres.tr = cbd1.r;\r
+            texres.tg = cbd1.g;\r
+            texres.tb = cbd1.b;\r
+            texres.ta = cbd1.a;\r
+        } else {\r
+            if (texres.tin <= cbd1.pos && colorBand.ipotype < 2) {\r
+                texres.tr = cbd1.r;\r
+                texres.tg = cbd1.g;\r
+                texres.tb = cbd1.b;\r
+                texres.ta = cbd1.a;\r
+            } else {\r
+                /* we're looking for first pos > in */\r
+                for (a = 0; a < colorBand.tot; ++a, ++i1) {\r
+                    cbd1 = colorBand.data[i1];\r
+                    if (cbd1.pos > texres.tin) {\r
+                        break;\r
+                    }\r
+                }\r
+\r
+                if (a == colorBand.tot) {\r
+                    cbd2 = colorBand.data[i1 - 1];\r
+                    try {\r
+                        cbd1 = (CBData) cbd2.clone();\r
+                    } catch (CloneNotSupportedException e) {\r
+                        throw new IllegalStateException("Clone not supported for " + CBData.class.getName() + " class! Fix that!");\r
+                    }\r
+                    cbd1.pos = 1.0f;\r
+                } else if (a == 0) {\r
+                    try {\r
+                        cbd2 = (CBData) cbd1.clone();\r
+                    } catch (CloneNotSupportedException e) {\r
+                        throw new IllegalStateException("Clone not supported for " + CBData.class.getName() + " class! Fix that!");\r
+                    }\r
+                    cbd2.pos = 0.0f;\r
+                } else {\r
+                    cbd2 = colorBand.data[i1 - 1];\r
+                }\r
+\r
+                if (texres.tin >= cbd1.pos && colorBand.ipotype < 2) {\r
+                    texres.tr = cbd1.r;\r
+                    texres.tg = cbd1.g;\r
+                    texres.tb = cbd1.b;\r
+                    texres.ta = cbd1.a;\r
+                } else {\r
+\r
+                    if (cbd2.pos != cbd1.pos) {\r
+                        fac = (texres.tin - cbd1.pos) / (cbd2.pos - cbd1.pos);\r
+                    } else {\r
+                        fac = 0.0f;\r
+                    }\r
+\r
+                    if (colorBand.ipotype == 4) {\r
+                        /* constant */\r
+                        texres.tr = cbd2.r;\r
+                        texres.tg = cbd2.g;\r
+                        texres.tb = cbd2.b;\r
+                        texres.ta = cbd2.a;\r
+                        return true;\r
+                    }\r
+\r
+                    if (colorBand.ipotype >= 2) {\r
+                        /* ipo from right to left: 3 2 1 0 */\r
+\r
+                        if (a >= colorBand.tot - 1) {\r
+                            cbd0 = cbd1;\r
+                        } else {\r
+                            cbd0 = colorBand.data[i1 + 1];\r
+                        }\r
+                        if (a < 2) {\r
+                            cbd3 = cbd2;\r
+                        } else {\r
+                            cbd3 = colorBand.data[i2 - 1];\r
+                        }\r
+\r
+                        fac = FastMath.clamp(fac, 0.0f, 1.0f);\r
+\r
+                        if (colorBand.ipotype == 3) {\r
+                            this.setFourIpo(fac, t, KEY_CARDINAL);\r
+                        } else {\r
+                            this.setFourIpo(fac, t, KEY_BSPLINE);\r
+                        }\r
+\r
+                        texres.tr = t[3] * cbd3.r + t[2] * cbd2.r + t[1] * cbd1.r + t[0] * cbd0.r;\r
+                        texres.tg = t[3] * cbd3.g + t[2] * cbd2.g + t[1] * cbd1.g + t[0] * cbd0.g;\r
+                        texres.tb = t[3] * cbd3.b + t[2] * cbd2.b + t[1] * cbd1.b + t[0] * cbd0.b;\r
+                        texres.ta = t[3] * cbd3.a + t[2] * cbd2.a + t[1] * cbd1.a + t[0] * cbd0.a;\r
+                        texres.tr = FastMath.clamp(texres.tr, 0.0f, 1.0f);\r
+                        texres.tg = FastMath.clamp(texres.tg, 0.0f, 1.0f);\r
+                        texres.tb = FastMath.clamp(texres.tb, 0.0f, 1.0f);\r
+                        texres.ta = FastMath.clamp(texres.ta, 0.0f, 1.0f);\r
+                    } else {\r
+\r
+                        if (colorBand.ipotype == 1) { /* EASE */\r
+                            mfac = fac * fac;\r
+                            fac = 3.0f * mfac - 2.0f * mfac * fac;\r
+                        }\r
+                        mfac = 1.0f - fac;\r
+\r
+                        texres.tr = mfac * cbd1.r + fac * cbd2.r;\r
+                        texres.tg = mfac * cbd1.g + fac * cbd2.g;\r
+                        texres.tb = mfac * cbd1.b + fac * cbd2.b;\r
+                        texres.ta = mfac * cbd1.a + fac * cbd2.a;\r
+                    }\r
+                }\r
+            }\r
+        }\r
+        return true;\r
+    }\r
+\r
+    protected void setFourIpo(float d, float[] data, int type) {\r
+        if (type == KEY_LINEAR) {\r
+            data[0] = 0.0f;\r
+            data[1] = 1.0f - d;\r
+            data[2] = d;\r
+            data[3] = 0.0f;\r
+        } else {\r
+            float d2 = d * d;\r
+            float d3 = d2 * d;\r
+            if (type == KEY_CARDINAL) {\r
+                float fc = 0.71f;\r
+                data[0] = -fc * d3 + 2.0f * fc * d2 - fc * d;\r
+                data[1] = (2.0f - fc) * d3 + (fc - 3.0f) * d2 + 1.0f;\r
+                data[2] = (fc - 2.0f) * d3 + (3.0f - 2.0f * fc) * d2 + fc * d;\r
+                data[3] = fc * d3 - fc * d2;\r
+            } else if (type == KEY_BSPLINE) {\r
+                data[0] = -0.16666666f * d3 + 0.5f * d2 - 0.5f * d + 0.16666666f;\r
+                data[1] = 0.5f * d3 - d2 + 0.6666666f;\r
+                data[2] = -0.5f * d3 + 0.5f * d2 + 0.5f * d + 0.16666666f;\r
+                data[3] = 0.16666666f * d3;\r
+            }\r
+        }\r
+    }\r
+\r
+    interface IWaveForm {\r
+\r
+        float execute(float x);\r
+    }\r
+    protected static IWaveForm[] waveformFunctions = new IWaveForm[3];\r
+\r
+    static {\r
+        waveformFunctions[0] = new IWaveForm() {// tex_sin\r
+\r
+            @Override\r
+            public float execute(float x) {\r
+                return 0.5f + 0.5f * (float) Math.sin(x);\r
+            }\r
+        };\r
+        waveformFunctions[1] = new IWaveForm() {// tex_saw\r
+\r
+            @Override\r
+            public float execute(float x) {\r
+                int n = (int) (x / FastMath.TWO_PI);\r
+                x -= n * FastMath.TWO_PI;\r
+                if (x < 0.0f) {\r
+                    x += FastMath.TWO_PI;\r
+                }\r
+                return x / FastMath.TWO_PI;\r
+            }\r
+        };\r
+        waveformFunctions[2] = new IWaveForm() {// tex_tri\r
+\r
+            @Override\r
+            public float execute(float x) {\r
+                return 1.0f - 2.0f * FastMath.abs((float) Math.floor(x * 1.0f / FastMath.TWO_PI + 0.5f) - x * 1.0f / FastMath.TWO_PI);\r
+            }\r
+        };\r
+    }\r
+\r
+    /* computes basic wood intensity value at x,y,z */\r
+    public float woodInt(Structure tex, float x, float y, float z, DataRepository dataRepository) {\r
+        int noisebasis2 = ((Number) tex.getFieldValue("noisebasis2")).intValue();\r
+        int noisebasis = ((Number) tex.getFieldValue("noisebasis")).intValue();\r
+        int stype = ((Number) tex.getFieldValue("stype")).intValue();\r
+        float noisesize = ((Number) tex.getFieldValue("noisesize")).floatValue();\r
+        float turbul = ((Number) tex.getFieldValue("turbul")).floatValue();\r
+        int noiseType = ((Number) tex.getFieldValue("noisetype")).intValue();\r
+        float wi = 0;\r
+        int waveform = noisebasis2; /* wave form: TEX_SIN=0, TEX_SAW=1, TEX_TRI=2 */\r
+        int wt = stype; /* wood type: TEX_BAND=0, TEX_RING=1, TEX_BANDNOISE=2, TEX_RINGNOISE=3 */\r
+\r
+        if (waveform > TEX_TRI || waveform < TEX_SIN) {\r
+            waveform = 0; /* check to be sure noisebasis2 is initialized ahead of time */\r
+        }\r
+\r
+        if (wt == TEX_BAND) {\r
+            wi = waveformFunctions[waveform].execute((x + y + z) * 10.0f);\r
+        } else if (wt == TEX_RING) {\r
+            wi = waveformFunctions[waveform].execute((float) Math.sqrt(x * x + y * y + z * z) * 20.0f);\r
+        } else if (wt == TEX_BANDNOISE) {\r
+            wi = turbul * this.bliGNoise(noisesize, x, y, z, noiseType != TEX_NOISESOFT, noisebasis);\r
+            wi = waveformFunctions[waveform].execute((x + y + z) * 10.0f + wi);\r
+        } else if (wt == TEX_RINGNOISE) {\r
+            wi = turbul * this.bliGNoise(noisesize, x, y, z, noiseType != TEX_NOISESOFT, noisebasis);\r
+            wi = waveformFunctions[waveform].execute((float) Math.sqrt(x * x + y * y + z * z) * 20.0f + wi);\r
+        }\r
+        return wi;\r
+    }\r
+\r
+    /* computes basic marble intensity at x,y,z */\r
+    public float marbleInt(Structure tex, float x, float y, float z, DataRepository dataRepository) {\r
+        float noisesize = ((Number) tex.getFieldValue("noisesize")).floatValue();\r
+        int noisebasis = ((Number) tex.getFieldValue("noisebasis")).intValue();\r
+        int noisedepth = ((Number) tex.getFieldValue("noisedepth")).intValue();\r
+        int stype = ((Number) tex.getFieldValue("stype")).intValue();/* marble type: TEX_SOFT=0, TEX_SHARP=1,TEX_SHAPER=2 */\r
+        float turbul = ((Number) tex.getFieldValue("turbul")).floatValue();\r
+        int noisetype = ((Number) tex.getFieldValue("noisetype")).intValue();\r
+        int waveform = ((Number) tex.getFieldValue("noisebasis2")).intValue(); /* wave form: TEX_SIN=0, TEX_SAW=1, TEX_TRI=2 */\r
+\r
+        if (waveform > TEX_TRI || waveform < TEX_SIN) {\r
+            waveform = 0; /* check to be sure noisebasis2 isn't initialized ahead of time */\r
+        }\r
+\r
+        float n = 5.0f * (x + y + z);\r
+        float mi = n + turbul * this.bliGTurbulence(noisesize, x, y, z, noisedepth, noisetype != TEX_NOISESOFT, noisebasis);\r
+\r
+        if (stype >= NoiseHelper.TEX_SOFT) { /* TEX_SOFT always true */\r
+            mi = waveformFunctions[waveform].execute(mi);\r
+            if (stype == TEX_SHARP) {\r
+                mi = (float) Math.sqrt(mi);\r
+            } else if (stype == TEX_SHARPER) {\r
+                mi = (float) Math.sqrt(Math.sqrt(mi));\r
+            }\r
+        }\r
+        return mi;\r
+    }\r
+\r
+    public void voronoi(float x, float y, float z, float[] da, float[] pa, float me, int dtype) {\r
+        AbstractNoiseFunc.voronoi(x, y, z, da, pa, me, dtype);\r
+    }\r
+\r
+    public void cellNoiseV(float x, float y, float z, float[] ca) {\r
+        AbstractNoiseFunc.cellNoiseV(x, y, z, ca);\r
+    }\r
+\r
+    /**\r
+     * THE FOLLOWING METHODS HELP IN NOISE COMPUTATIONS\r
+     */\r
+    /**\r
+     * Separated from orgBlenderNoise above, with scaling.\r
+     * @param noisesize\r
+     * @param x\r
+     * @param y\r
+     * @param z\r
+     * @return\r
+     */\r
+    private float bliHnoise(float noisesize, float x, float y, float z) {\r
+        if (noisesize == 0.0) {\r
+            return 0.0f;\r
+        }\r
+        x = (1.0f + x) / noisesize;\r
+        y = (1.0f + y) / noisesize;\r
+        z = (1.0f + z) / noisesize;\r
+        return noiseFunctions.get(0).execute(x, y, z);\r
+    }\r
+\r
+    /**\r
+     * @param noisesize\r
+     * @param x\r
+     * @param y\r
+     * @param z\r
+     * @param nr\r
+     * @return\r
+     */\r
+    public float bliTurbulence(float noisesize, float x, float y, float z, int nr) {\r
+        float d = 0.5f, div = 1.0f;\r
+\r
+        float s = this.bliHnoise(noisesize, x, y, z);\r
+        while (nr > 0) {\r
+            s += d * this.bliHnoise(noisesize * d, x, y, z);\r
+            div += d;\r
+            d *= 0.5;\r
+            --nr;\r
+        }\r
+        return s / div;\r
+    }\r
+\r
+    /**\r
+     * @param noisesize\r
+     * @param x\r
+     * @param y\r
+     * @param z\r
+     * @param nr\r
+     * @return\r
+     */\r
+    public float bliTurbulence1(float noisesize, float x, float y, float z, int nr) {\r
+        float s, d = 0.5f, div = 1.0f;\r
+\r
+        s = FastMath.abs((-1.0f + 2.0f * this.bliHnoise(noisesize, x, y, z)));\r
+        while (nr > 0) {\r
+            s += Math.abs(d * (-1.0f + 2.0f * this.bliHnoise(noisesize * d, x, y, z)));\r
+            div += d;\r
+            d *= 0.5;\r
+            --nr;\r
+        }\r
+        return s / div;\r
+    }\r
+\r
+    /**\r
+     * @param noisesize\r
+     * @param x\r
+     * @param y\r
+     * @param z\r
+     * @return\r
+     */\r
+    public float bliHnoisep(float noisesize, float x, float y, float z) {\r
+        return noiseFunctions.get(Integer.valueOf(0)).noise3Perlin(new float[]{x / noisesize, y / noisesize, z / noisesize});\r
+    }\r
+\r
+    /**\r
+     * @param point\r
+     * @param lofreq\r
+     * @param hifreq\r
+     * @return\r
+     */\r
+    public float turbulencePerlin(float[] point, float lofreq, float hifreq) {\r
+        float freq, t = 0, p[] = new float[]{point[0] + 123.456f, point[1], point[2]};\r
+        for (freq = lofreq; freq < hifreq; freq *= 2.) {\r
+            t += Math.abs(noiseFunctions.get(Integer.valueOf(0)).noise3Perlin(p)) / freq;\r
+            p[0] *= 2.0f;\r
+            p[1] *= 2.0f;\r
+            p[2] *= 2.0f;\r
+        }\r
+        return t - 0.3f; /* readjust to make mean value = 0.0 */\r
+    }\r
+\r
+    /**\r
+     * @param noisesize\r
+     * @param x\r
+     * @param y\r
+     * @param z\r
+     * @param nr\r
+     * @return\r
+     */\r
+    public float turbulencep(float noisesize, float x, float y, float z, int nr) {\r
+        float[] vec = new float[]{x / noisesize, y / noisesize, z / noisesize};\r
+        ++nr;\r
+        return this.turbulencePerlin(vec, 1.0f, (1 << nr));\r
+    }\r
+\r
+    /**\r
+     * Newnoise: generic noise function for use with different noisebases\r
+     * @param x\r
+     * @param y\r
+     * @param z\r
+     * @param oct\r
+     * @param isHard\r
+     * @param noisebasis\r
+     * @return\r
+     */\r
+    public float bliGNoise(float noisesize, float x, float y, float z, boolean isHard, int noisebasis) {\r
+        AbstractNoiseFunc abstractNoiseFunc = noiseFunctions.get(Integer.valueOf(noisebasis));\r
+        if (abstractNoiseFunc == null) {\r
+            abstractNoiseFunc = noiseFunctions.get(0);\r
+            noisebasis = 0;\r
+        }\r
+        if (noisebasis == 0) {// add one to make return value same as BLI_hnoise\r
+            x += 1;\r
+            y += 1;\r
+            z += 1;\r
+        }\r
+\r
+        if (noisesize != 0.0) {\r
+            noisesize = 1.0f / noisesize;\r
+            x *= noisesize;\r
+            y *= noisesize;\r
+            z *= noisesize;\r
+        }\r
+        if (isHard) {\r
+            return Math.abs(2.0f * abstractNoiseFunc.execute(x, y, z) - 1.0f);\r
+        }\r
+        return abstractNoiseFunc.execute(x, y, z);\r
+    }\r
+\r
+    /**\r
+     * Newnoise: generic turbulence function for use with different noisebasis\r
+     * @param x\r
+     * @param y\r
+     * @param z\r
+     * @param oct\r
+     * @param isHard\r
+     * @param noisebasis\r
+     * @return\r
+     */\r
+    public float bliGTurbulence(float noisesize, float x, float y, float z, int oct, boolean isHard, int noisebasis) {\r
+        AbstractNoiseFunc abstractNoiseFunc = noiseFunctions.get(Integer.valueOf(noisebasis));\r
+        if (abstractNoiseFunc == null) {\r
+            abstractNoiseFunc = noiseFunctions.get(0);\r
+            noisebasis = 0;\r
+        }\r
+        if (noisebasis == 0) {// add one to make return value same as BLI_hnoise\r
+            x += 1;\r
+            y += 1;\r
+            z += 1;\r
+        }\r
+        float sum = 0, t, amp = 1, fscale = 1;\r
+\r
+        if (noisesize != 0.0) {\r
+            noisesize = 1.0f / noisesize;\r
+            x *= noisesize;\r
+            y *= noisesize;\r
+            z *= noisesize;\r
+        }\r
+        for (int i = 0; i <= oct; ++i, amp *= 0.5, fscale *= 2) {\r
+            t = abstractNoiseFunc.execute(fscale * x, fscale * y, fscale * z);\r
+            if (isHard) {\r
+                t = FastMath.abs(2.0f * t - 1.0f);\r
+            }\r
+            sum += t * amp;\r
+        }\r
+\r
+        sum *= (float) (1 << oct) / (float) ((1 << oct + 1) - 1);\r
+        return sum;\r
+    }\r
+\r
+    /**\r
+     * "Variable Lacunarity Noise" A distorted variety of Perlin noise. This method is used to calculate distorted noise\r
+     * texture.\r
+     * @param x\r
+     * @param y\r
+     * @param z\r
+     * @param distortion\r
+     * @param nbas1\r
+     * @param nbas2\r
+     * @return\r
+     */\r
+    public float mgVLNoise(float x, float y, float z, float distortion, int nbas1, int nbas2) {\r
+        AbstractNoiseFunc abstractNoiseFunc1 = noiseFunctions.get(Integer.valueOf(nbas1));\r
+        if (abstractNoiseFunc1 == null) {\r
+            abstractNoiseFunc1 = noiseFunctions.get(Integer.valueOf(0));\r
+        }\r
+        AbstractNoiseFunc abstractNoiseFunc2 = noiseFunctions.get(Integer.valueOf(nbas2));\r
+        if (abstractNoiseFunc2 == null) {\r
+            abstractNoiseFunc2 = noiseFunctions.get(Integer.valueOf(0));\r
+        }\r
+        // get a random vector and scale the randomization\r
+        float rx = abstractNoiseFunc1.execute(x + 13.5f, y + 13.5f, z + 13.5f) * distortion;\r
+        float ry = abstractNoiseFunc1.execute(x, y, z) * distortion;\r
+        float rz = abstractNoiseFunc1.execute(x - 13.5f, y - 13.5f, z - 13.5f) * distortion;\r
+        return abstractNoiseFunc2.executeS(x + rx, y + ry, z + rz); //distorted-domain noise\r
+    }\r
+\r
+    public void mgMFractalOrfBmTex(Structure tex, float[] texvec, ColorBand colorBand, TexResult texres, DataRepository dataRepository) {\r
+        int stype = ((Number) tex.getFieldValue("stype")).intValue();\r
+        float nsOutscale = ((Number) tex.getFieldValue("ns_outscale")).floatValue();\r
+        float nabla = ((Number) tex.getFieldValue("nabla")).floatValue();\r
+        float noisesize = ((Number) tex.getFieldValue("noisesize")).floatValue();\r
+        float contrast = ((Number) tex.getFieldValue("contrast")).floatValue();\r
+        float brightness = ((Number) tex.getFieldValue("bright")).floatValue();\r
+\r
+        MusgraveFunction mgravefunc = stype == TEX_MFRACTAL ? musgraveFunctions.get(Integer.valueOf(stype)) : musgraveFunctions.get(Integer.valueOf(TEX_FBM));\r
+\r
+        texres.tin = nsOutscale * mgravefunc.execute(tex, texvec[0], texvec[1], texvec[2]);\r
+        if (texres.nor != null) {\r
+            float offs = nabla / noisesize; // also scaling of texvec\r
+            // calculate bumpnormal\r
+            texres.nor[0] = nsOutscale * mgravefunc.execute(tex, texvec[0] + offs, texvec[1], texvec[2]);\r
+            texres.nor[1] = nsOutscale * mgravefunc.execute(tex, texvec[0], texvec[1] + offs, texvec[2]);\r
+            texres.nor[2] = nsOutscale * mgravefunc.execute(tex, texvec[0], texvec[1], texvec[2] + offs);\r
+            this.texNormalDerivate(colorBand, texres, dataRepository);\r
+        }\r
+        this.brightnesAndContrast(texres, contrast, brightness);\r
+    }\r
+\r
+    public void mgRidgedOrHybridMFTex(Structure tex, float[] texvec, ColorBand colorBand, TexResult texres, DataRepository dataRepository) {\r
+        int stype = ((Number) tex.getFieldValue("stype")).intValue();\r
+        float nsOutscale = ((Number) tex.getFieldValue("ns_outscale")).floatValue();\r
+        float nabla = ((Number) tex.getFieldValue("nabla")).floatValue();\r
+        float noisesize = ((Number) tex.getFieldValue("noisesize")).floatValue();\r
+        float contrast = ((Number) tex.getFieldValue("contrast")).floatValue();\r
+        float brightness = ((Number) tex.getFieldValue("bright")).floatValue();\r
+\r
+        MusgraveFunction mgravefunc = stype == TEX_RIDGEDMF ? musgraveFunctions.get(Integer.valueOf(stype)) : musgraveFunctions.get(Integer.valueOf(TEX_HYBRIDMF));\r
+\r
+        texres.tin = nsOutscale * mgravefunc.execute(tex, texvec[0], texvec[1], texvec[2]);\r
+        if (texres.nor != null) {\r
+            float offs = nabla / noisesize; // also scaling of texvec\r
+            // calculate bumpnormal\r
+            texres.nor[0] = nsOutscale * mgravefunc.execute(tex, texvec[0] + offs, texvec[1], texvec[2]);\r
+            texres.nor[1] = nsOutscale * mgravefunc.execute(tex, texvec[0], texvec[1] + offs, texvec[2]);\r
+            texres.nor[2] = nsOutscale * mgravefunc.execute(tex, texvec[0], texvec[1], texvec[2] + offs);\r
+            this.texNormalDerivate(colorBand, texres, dataRepository);\r
+        }\r
+        this.brightnesAndContrast(texres, contrast, brightness);\r
+    }\r
+\r
+    public void mgHTerrainTex(Structure tex, float[] texvec, ColorBand colorBand, TexResult texres, DataRepository dataRepository) {\r
+        float nsOutscale = ((Number) tex.getFieldValue("ns_outscale")).floatValue();\r
+        float nabla = ((Number) tex.getFieldValue("nabla")).floatValue();\r
+        float noisesize = ((Number) tex.getFieldValue("noisesize")).floatValue();\r
+        float contrast = ((Number) tex.getFieldValue("contrast")).floatValue();\r
+        float brightness = ((Number) tex.getFieldValue("bright")).floatValue();\r
+\r
+        MusgraveFunction musgraveFunction = musgraveFunctions.get(Integer.valueOf(TEX_HTERRAIN));\r
+        texres.tin = nsOutscale * musgraveFunction.execute(tex, texvec[0], texvec[1], texvec[2]);\r
+        if (texres.nor != null) {\r
+            float offs = nabla / noisesize; // also scaling of texvec\r
+            // calculate bumpnormal\r
+            texres.nor[0] = nsOutscale * musgraveFunction.execute(tex, texvec[0] + offs, texvec[1], texvec[2]);\r
+            texres.nor[1] = nsOutscale * musgraveFunction.execute(tex, texvec[0], texvec[1] + offs, texvec[2]);\r
+            texres.nor[2] = nsOutscale * musgraveFunction.execute(tex, texvec[0], texvec[1], texvec[2] + offs);\r
+            this.texNormalDerivate(colorBand, texres, dataRepository);\r
+        }\r
+        this.brightnesAndContrast(texres, contrast, brightness);\r
+    }\r
+\r
+    /**\r
+     * This class is abstract to the noise functions computations. It has two methods. One calculates the Signed (with\r
+     * 'S' at the end) and the other Unsigned value.\r
+     * @author Marcin Roguski (Kaelthas)\r
+     */\r
+    protected static abstract class AbstractNoiseFunc {\r
+\r
+        /**\r
+         * This method calculates the unsigned value of the noise.\r
+         * @param x\r
+         *        the x texture coordinate\r
+         * @param y\r
+         *        the y texture coordinate\r
+         * @param z\r
+         *        the z texture coordinate\r
+         * @return value of the noise\r
+         */\r
+        public abstract float execute(float x, float y, float z);\r
+\r
+        /**\r
+         * This method calculates the signed value of the noise.\r
+         * @param x\r
+         *        the x texture coordinate\r
+         * @param y\r
+         *        the y texture coordinate\r
+         * @param z\r
+         *        the z texture coordinate\r
+         * @return value of the noise\r
+         */\r
+        public abstract float executeS(float x, float y, float z);\r
+\r
+        /*\r
+         * Not 'pure' Worley, but the results are virtually the same. Returns distances in da and point coords in pa\r
+         */\r
+        protected static void voronoi(float x, float y, float z, float[] da, float[] pa, float me, int dtype) {\r
+            float xd, yd, zd, d, p[];\r
+\r
+            DistanceFunc distanceFunc = distanceFunctions.get(Integer.valueOf(dtype));\r
+            if (distanceFunc == null) {\r
+                distanceFunc = distanceFunctions.get(Integer.valueOf(0));\r
+            }\r
+\r
+            int xi = (int) FastMath.floor(x);\r
+            int yi = (int) FastMath.floor(y);\r
+            int zi = (int) FastMath.floor(z);\r
+            da[0] = da[1] = da[2] = da[3] = 1e10f;\r
+            for (int xx = xi - 1; xx <= xi + 1; ++xx) {\r
+                for (int yy = yi - 1; yy <= yi + 1; ++yy) {\r
+                    for (int zz = zi - 1; zz <= zi + 1; ++zz) {\r
+                        p = AbstractNoiseFunc.hashPoint(xx, yy, zz);\r
+                        xd = x - (p[0] + xx);\r
+                        yd = y - (p[1] + yy);\r
+                        zd = z - (p[2] + zz);\r
+                        d = distanceFunc.execute(xd, yd, zd, me);\r
+                        if (d < da[0]) {\r
+                            da[3] = da[2];\r
+                            da[2] = da[1];\r
+                            da[1] = da[0];\r
+                            da[0] = d;\r
+                            pa[9] = pa[6];\r
+                            pa[10] = pa[7];\r
+                            pa[11] = pa[8];\r
+                            pa[6] = pa[3];\r
+                            pa[7] = pa[4];\r
+                            pa[8] = pa[5];\r
+                            pa[3] = pa[0];\r
+                            pa[4] = pa[1];\r
+                            pa[5] = pa[2];\r
+                            pa[0] = p[0] + xx;\r
+                            pa[1] = p[1] + yy;\r
+                            pa[2] = p[2] + zz;\r
+                        } else if (d < da[1]) {\r
+                            da[3] = da[2];\r
+                            da[2] = da[1];\r
+                            da[1] = d;\r
+                            pa[9] = pa[6];\r
+                            pa[10] = pa[7];\r
+                            pa[11] = pa[8];\r
+                            pa[6] = pa[3];\r
+                            pa[7] = pa[4];\r
+                            pa[8] = pa[5];\r
+                            pa[3] = p[0] + xx;\r
+                            pa[4] = p[1] + yy;\r
+                            pa[5] = p[2] + zz;\r
+                        } else if (d < da[2]) {\r
+                            da[3] = da[2];\r
+                            da[2] = d;\r
+                            pa[9] = pa[6];\r
+                            pa[10] = pa[7];\r
+                            pa[11] = pa[8];\r
+                            pa[6] = p[0] + xx;\r
+                            pa[7] = p[1] + yy;\r
+                            pa[8] = p[2] + zz;\r
+                        } else if (d < da[3]) {\r
+                            da[3] = d;\r
+                            pa[9] = p[0] + xx;\r
+                            pa[10] = p[1] + yy;\r
+                            pa[11] = p[2] + zz;\r
+                        }\r
+                    }\r
+                }\r
+            }\r
+        }\r
+\r
+        // #define HASHVEC(x,y,z) hashvectf+3*hash[ (hash[ (hash[(z) & 255]+(y)) & 255]+(x)) & 255]\r
+\r
+        /* needed for voronoi */\r
+        // #define HASHPNT(x,y,z) hashpntf+3*hash[ (hash[ (hash[(z) & 255]+(y)) & 255]+(x)) & 255]\r
+        protected static float[] hashPoint(int x, int y, int z) {\r
+            float[] result = new float[3];\r
+            result[0] = hashpntf[3 * hash[hash[hash[z & 255] + y & 255] + x & 255]];\r
+            result[1] = hashpntf[3 * hash[hash[hash[z & 255] + y & 255] + x & 255] + 1];\r
+            result[2] = hashpntf[3 * hash[hash[hash[z & 255] + y & 255] + x & 255] + 2];\r
+            return result;\r
+        }\r
+\r
+        // #define setup(i,b0,b1,r0,r1) \\r
+        // t = vec[i] + 10000.; \\r
+        // b0 = ((int)t) & 255; \\r
+        // b1 = (b0+1) & 255; \\r
+        // r0 = t - (int)t; \\r
+        // r1 = r0 - 1.;\r
+        // vec[3]\r
+        public float noise3Perlin(float[] vec) {\r
+            int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11;\r
+            float rx0, rx1, ry0, ry1, rz0, rz1, sx, sy, sz, a, b, c, d, t, u, v;\r
+            int i, j;\r
+\r
+            // setup(0, bx0,bx1, rx0,rx1);\r
+            t = vec[0] + 10000.0f;\r
+            bx0 = (int) t & 255;\r
+            bx1 = bx0 + 1 & 255;\r
+            rx0 = t - (int) t;\r
+            rx1 = rx0 - 1.0f;\r
+            // setup(1, by0,by1, ry0,ry1);\r
+            t = vec[0] + 10000.0f;\r
+            by0 = (int) t & 255;\r
+            by1 = by0 + 1 & 255;\r
+            ry0 = t - (int) t;\r
+            ry1 = ry0 - 1.0f;\r
+            // setup(2, bz0,bz1, rz0,rz1);\r
+            t = vec[0] + 10000.0f;\r
+            bz0 = (int) t & 255;\r
+            bz1 = bz0 + 1 & 255;\r
+            rz0 = t - (int) t;\r
+            rz1 = rz0 - 1.0f;\r
+\r
+            i = p[bx0];\r
+            j = p[bx1];\r
+\r
+            b00 = p[i + by0];\r
+            b10 = p[j + by0];\r
+            b01 = p[i + by1];\r
+            b11 = p[j + by1];\r
+\r
+            /* lerp moved to improved perlin above */\r
+\r
+            sx = this.surve(rx0);\r
+            sy = this.surve(ry0);\r
+            sz = this.surve(rz0);\r
+\r
+            float[] q = new float[3];\r
+            q = g[b00 + bz0];\r
+            u = this.at(rx0, ry0, rz0, q);\r
+            q = g[b10 + bz0];\r
+            v = this.at(rx1, ry0, rz0, q);\r
+            a = this.lerp(sx, u, v);\r
+\r
+            q = g[b01 + bz0];\r
+            u = this.at(rx0, ry1, rz0, q);\r
+            q = g[b11 + bz0];\r
+            v = this.at(rx1, ry1, rz0, q);\r
+            b = this.lerp(sx, u, v);\r
+\r
+            c = this.lerp(sy, a, b); /* interpolate in y at lo x */\r
+\r
+            q = g[b00 + bz1];\r
+            u = this.at(rx0, ry0, rz1, q);\r
+            q = g[b10 + bz1];\r
+            v = this.at(rx1, ry0, rz1, q);\r
+            a = this.lerp(sx, u, v);\r
+\r
+            q = g[b01 + bz1];\r
+            u = this.at(rx0, ry1, rz1, q);\r
+            q = g[b11 + bz1];\r
+            v = this.at(rx1, ry1, rz1, q);\r
+            b = this.lerp(sx, u, v);\r
+\r
+            d = this.lerp(sy, a, b); /* interpolate in y at hi x */\r
+\r
+            return 1.5f * this.lerp(sz, c, d); /* interpolate in z */\r
+        }\r
+\r
+        public float orgBlenderNoise(float x, float y, float z) {\r
+            float cn1, cn2, cn3, cn4, cn5, cn6, i;\r
+            float ox, oy, oz, jx, jy, jz;\r
+            float n = 0.5f;\r
+            int ix, iy, iz, b00, b01, b10, b11, b20, b21;\r
+\r
+            ox = x - (ix = (int) Math.floor(x));\r
+            oy = y - (iy = (int) Math.floor(y));\r
+            oz = z - (iz = (int) Math.floor(z));\r
+\r
+            jx = ox - 1;\r
+            jy = oy - 1;\r
+            jz = oz - 1;\r
+\r
+            cn1 = ox * ox;\r
+            cn2 = oy * oy;\r
+            cn3 = oz * oz;\r
+            cn4 = jx * jx;\r
+            cn5 = jy * jy;\r
+            cn6 = jz * jz;\r
+\r
+            cn1 = 1.0f - 3.0f * cn1 + 2.0f * cn1 * ox;\r
+            cn2 = 1.0f - 3.0f * cn2 + 2.0f * cn2 * oy;\r
+            cn3 = 1.0f - 3.0f * cn3 + 2.0f * cn3 * oz;\r
+            cn4 = 1.0f - 3.0f * cn4 - 2.0f * cn4 * jx;\r
+            cn5 = 1.0f - 3.0f * cn5 - 2.0f * cn5 * jy;\r
+            cn6 = 1.0f - 3.0f * cn6 - 2.0f * cn6 * jz;\r
+\r
+            b00 = hash[hash[ix & 255] + (iy & 255)];\r
+            b10 = hash[hash[ix + 1 & 255] + (iy & 255)];\r
+            b01 = hash[hash[ix & 255] + (iy + 1 & 255)];\r
+            b11 = hash[hash[ix + 1 & 255] + (iy + 1 & 255)];\r
+\r
+            b20 = iz & 255;\r
+            b21 = iz + 1 & 255;\r
+\r
+            /* 0 */\r
+            i = cn1 * cn2 * cn3;\r
+            int hIndex = 3 * hash[b20 + b00];\r
+            n += i * (hashvectf[hIndex] * ox + hashvectf[hIndex + 1] * oy + hashvectf[hIndex + 2] * oz);\r
+            /* 1 */\r
+            i = cn1 * cn2 * cn6;\r
+            hIndex = 3 * hash[b21 + b00];\r
+            n += i * (hashvectf[hIndex] * ox + hashvectf[hIndex + 1] * oy + hashvectf[hIndex + 2] * jz);\r
+            /* 2 */\r
+            i = cn1 * cn5 * cn3;\r
+            hIndex = 3 * hash[b20 + b01];\r
+            n += i * (hashvectf[hIndex] * ox + hashvectf[hIndex + 1] * jy + hashvectf[hIndex + 2] * oz);\r
+            /* 3 */\r
+            i = cn1 * cn5 * cn6;\r
+            hIndex = 3 * hash[b21 + b01];\r
+            n += i * (hashvectf[hIndex] * ox + hashvectf[hIndex + 1] * jy + hashvectf[hIndex + 2] * jz);\r
+            /* 4 */\r
+            i = cn4 * cn2 * cn3;\r
+            hIndex = 3 * hash[b20 + b10];\r
+            n += i * (hashvectf[hIndex] * jx + hashvectf[hIndex + 1] * oy + hashvectf[hIndex + 2] * oz);\r
+            /* 5 */\r
+            i = cn4 * cn2 * cn6;\r
+            hIndex = 3 * hash[b21 + b10];\r
+            n += i * (hashvectf[hIndex] * jx + hashvectf[hIndex + 1] * oy + hashvectf[hIndex + 2] * jz);\r
+            /* 6 */\r
+            i = cn4 * cn5 * cn3;\r
+            hIndex = 3 * hash[b20 + b11];\r
+            n += i * (hashvectf[hIndex] * jx + hashvectf[hIndex + 1] * jy + hashvectf[hIndex + 2] * oz);\r
+            /* 7 */\r
+            i = cn4 * cn5 * cn6;\r
+            hIndex = 3 * hash[b21 + b11];\r
+            n += i * (hashvectf[hIndex] * jx + hashvectf[hIndex + 1] * jy + hashvectf[hIndex + 2] * jz);\r
+\r
+            if (n < 0.0f) {\r
+                n = 0.0f;\r
+            } else if (n > 1.0f) {\r
+                n = 1.0f;\r
+            }\r
+            return n;\r
+        }\r
+\r
+        /* instead of adding another permutation array, just use hash table defined above */\r
+        public float newPerlin(float x, float y, float z) {\r
+            int A, AA, AB, B, BA, BB;\r
+            float u = (float) Math.floor(x), v = (float) Math.floor(y), w = (float) Math.floor(z);\r
+            int X = (int) u & 255, Y = (int) v & 255, Z = (int) w & 255; // FIND UNIT CUBE THAT CONTAINS POINT\r
+            x -= u; // FIND RELATIVE X,Y,Z\r
+            y -= v; // OF POINT IN CUBE.\r
+            z -= w;\r
+            u = this.npfade(x); // COMPUTE FADE CURVES\r
+            v = this.npfade(y); // FOR EACH OF X,Y,Z.\r
+            w = this.npfade(z);\r
+            A = hash[X] + Y;\r
+            AA = hash[A] + Z;\r
+            AB = hash[A + 1] + Z; // HASH COORDINATES OF\r
+            B = hash[X + 1] + Y;\r
+            BA = hash[B] + Z;\r
+            BB = hash[B + 1] + Z; // THE 8 CUBE CORNERS,\r
+            return this.lerp(w, this.lerp(v, this.lerp(u, this.grad(hash[AA], x, y, z), // AND ADD\r
+                    this.grad(hash[BA], x - 1, y, z)), // BLENDED\r
+                    this.lerp(u, this.grad(hash[AB], x, y - 1, z), // RESULTS\r
+                    this.grad(hash[BB], x - 1, y - 1, z))),// FROM 8\r
+                    this.lerp(v, this.lerp(u, this.grad(hash[AA + 1], x, y, z - 1), // CORNERS\r
+                    this.grad(hash[BA + 1], x - 1, y, z - 1)), // OF CUBE\r
+                    this.lerp(u, this.grad(hash[AB + 1], x, y - 1, z - 1), this.grad(hash[BB + 1], x - 1, y - 1, z - 1))));\r
+        }\r
+\r
+        /**\r
+         * Returns a vector/point/color in ca, using point hasharray directly\r
+         */\r
+        protected static void cellNoiseV(float x, float y, float z, float[] ca) {\r
+            int xi = (int) Math.floor(x);\r
+            int yi = (int) Math.floor(y);\r
+            int zi = (int) Math.floor(z);\r
+            float[] p = AbstractNoiseFunc.hashPoint(xi, yi, zi);\r
+            ca[0] = p[0];\r
+            ca[1] = p[1];\r
+            ca[2] = p[2];\r
+        }\r
+\r
+        protected float lerp(float t, float a, float b) {\r
+            return a + t * (b - a);\r
+        }\r
+\r
+        protected float npfade(float t) {\r
+            return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f);\r
+        }\r
+\r
+        protected float grad(int hash, float x, float y, float z) {\r
+            int h = hash & 0x0F; // CONVERT LO 4 BITS OF HASH CODE\r
+            float u = h < 8 ? x : y, // INTO 12 GRADIENT DIRECTIONS.\r
+                    v = h < 4 ? y : h == 12 || h == 14 ? x : z;\r
+            return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);\r
+        }\r
+\r
+        /**\r
+         * Dot product of two vectors.\r
+         * @param a\r
+         *        the first vector\r
+         * @param b\r
+         *        the second vector\r
+         * @return the dot product of two vectors\r
+         */\r
+        protected float dot(float[] a, float[] b) {\r
+            return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];\r
+        }\r
+\r
+        protected float surve(float t) {\r
+            return t * t * (3.0f - 2.0f * t);\r
+        }\r
+\r
+        protected float at(float rx, float ry, float rz, float[] q) {\r
+            return rx * q[0] + ry * q[1] + rz * q[2];\r
+        }\r
+    }\r
+\r
+    /**\r
+     * This interface is used for distance calculation classes. Distance metrics for voronoi. e parameter only used in\r
+     * Minkovsky.\r
+     */\r
+    interface DistanceFunc {\r
+\r
+        /**\r
+         * This method calculates the distance for voronoi algorithms.\r
+         * @param x\r
+         *        the x coordinate\r
+         * @param y\r
+         *        the y coordinate\r
+         * @param z\r
+         *        the z coordinate\r
+         * @param e\r
+         *        this parameter used in Monkovsky (no idea what it really is ;)\r
+         * @return\r
+         */\r
+        float execute(float x, float y, float z, float e);\r
+    }\r
+\r
+    interface MusgraveFunction {\r
+\r
+        float execute(Structure tex, float x, float y, float z);\r
+    }\r
 }\r
index 5216cf3..4fbe0fe 100644 (file)
@@ -21,205 +21,199 @@ import com.jme3.scene.plugins.blender.utils.Pointer;
  * @author Marcin Roguski\r
  */\r
 public abstract class AbstractInfluenceFunction {\r
-       protected static final Logger   LOGGER                          = Logger.getLogger(AbstractInfluenceFunction.class.getName());\r
 \r
-       protected static final float    IK_SOLVER_ERROR         = 0.5f;\r
-\r
-       //DISTLIMIT\r
-       protected static final int              LIMITDIST_INSIDE        = 0;\r
-       protected static final int              LIMITDIST_OUTSIDE       = 1;\r
-       protected static final int              LIMITDIST_ONSURFACE     = 2;\r
-\r
-       //CONSTRAINT_TYPE_LOCLIKE\r
-       protected static final int              LOCLIKE_X                       = 0x01;\r
-       protected static final int              LOCLIKE_Y                       = 0x02;\r
-       protected static final int              LOCLIKE_Z                       = 0x04;\r
-\r
-       //ROTLIKE\r
-       protected static final int              ROTLIKE_X                       = 0x01;\r
-       protected static final int              ROTLIKE_Y                       = 0x02;\r
-       protected static final int              ROTLIKE_Z                       = 0x04;\r
-       protected static final int              ROTLIKE_X_INVERT        = 0x10;\r
-       protected static final int              ROTLIKE_Y_INVERT        = 0x20;\r
-       protected static final int              ROTLIKE_Z_INVERT        = 0x40;\r
-       protected static final int              ROTLIKE_OFFSET          = 0x80;\r
-\r
-       //SIZELIKE\r
-       protected static final int              SIZELIKE_X                      = 0x01;\r
-       protected static final int              SIZELIKE_Y                      = 0x02;\r
-       protected static final int              SIZELIKE_Z                      = 0x04;\r
-       protected static final int              SIZELIKE_OFFSET         = 0x80;\r
-\r
-       /* LOCLIKE_TIP is a depreceated option... use headtail=1.0f instead */\r
-       //protected static final int LOCLIKE_TIP = 0x08;\r
-       protected static final int              LOCLIKE_X_INVERT        = 0x10;\r
-       protected static final int              LOCLIKE_Y_INVERT        = 0x20;\r
-       protected static final int              LOCLIKE_Z_INVERT        = 0x40;\r
-       protected static final int              LOCLIKE_OFFSET          = 0x80;\r
-\r
-       //LOCLIMIT, SIZELIMIT\r
-       protected static final int              LIMIT_XMIN                      = 0x01;\r
-       protected static final int              LIMIT_XMAX                      = 0x02;\r
-       protected static final int              LIMIT_YMIN                      = 0x04;\r
-       protected static final int              LIMIT_YMAX                      = 0x08;\r
-       protected static final int              LIMIT_ZMIN                      = 0x10;\r
-       protected static final int              LIMIT_ZMAX                      = 0x20;\r
-\r
-       //ROTLIMIT\r
-       protected static final int              LIMIT_XROT                      = 0x01;\r
-       protected static final int              LIMIT_YROT                      = 0x02;\r
-       protected static final int              LIMIT_ZROT                      = 0x04;\r
-\r
-       /** The type of the constraint. */\r
-       protected ConstraintType                constraintType;\r
-       /** The data repository. */\r
-       protected DataRepository                dataRepository;\r
-\r
-       /**\r
-        * Constructor.\r
-        * @param constraintType\r
-        *        the type of the current constraint\r
-        * @param dataRepository\r
-        *        the data repository\r
-        */\r
-       public AbstractInfluenceFunction(ConstraintType constraintType, DataRepository dataRepository) {\r
-               this.constraintType = constraintType;\r
-               this.dataRepository = dataRepository;\r
-       }\r
-\r
-       /**\r
-        * This method validates the constraint type. It throws an IllegalArgumentException if the constraint type of the\r
-        * given structure is invalid.\r
-        * @param constraintStructure\r
-        *        the structure with constraint data\r
-        */\r
-       protected void validateConstraintType(Structure constraintStructure) {\r
-               if(!constraintType.getClassName().equalsIgnoreCase(constraintStructure.getType())) {\r
-                       throw new IllegalArgumentException("Invalud structure type (" + constraintStructure.getType() + ") for the constraint: " + constraintType.getClassName() + '!');\r
-               }\r
-       }\r
-\r
-       /**\r
-        * This method affects the bone animation tracks for the given skeleton.\r
-        * @param skeleton\r
-        *        the skeleton containing the affected bones by constraint\r
-        * @param boneAnimation\r
-        *        the bone animation baked traces\r
-        * @param constraint\r
-        *        the constraint\r
-        */\r
-       public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {}\r
-\r
-       /**\r
-        * This method returns the bone traces for the bone that is affected by the given constraint.\r
-        * @param skeleton\r
-        *        the skeleton containing bones\r
-        * @param boneAnimation\r
-        *        the bone animation that affects the skeleton\r
-        * @param constraint\r
-        *        the affecting constraint\r
-        * @return the bone track for the bone that is being affected by the constraint\r
-        */\r
-       protected BoneTrack getBoneTrack(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {\r
-               Long boneOMA = constraint.getBoneOMA();\r
-               Bone bone = (Bone)dataRepository.getLoadedFeature(boneOMA, LoadedFeatureDataType.LOADED_FEATURE);\r
-               int boneIndex = skeleton.getBoneIndex(bone);\r
-               if(boneIndex != -1) {\r
-                       //searching for track for this bone\r
-                       for(BoneTrack boneTrack : boneAnimation.getTracks()) {\r
-                               if(boneTrack.getTargetBoneIndex() == boneIndex) {\r
-                                       return boneTrack;\r
-                               }\r
-                       }\r
-               }\r
-               return null;\r
-       }\r
-\r
-       /**\r
-        * This method returns the target or subtarget object (if specified).\r
-        * @param constraint\r
-        *        the constraint instance\r
-        * @return target or subtarget feature\r
-        */\r
-       protected Object getTarget(Constraint constraint, LoadedFeatureDataType loadedFeatureDataType) {\r
-               Long targetOMA = ((Pointer)constraint.getData().getFieldValue("tar")).getOldMemoryAddress();\r
-               Object targetObject = dataRepository.getLoadedFeature(targetOMA, loadedFeatureDataType);\r
-               String subtargetName = constraint.getData().getFieldValue("subtarget").toString();\r
-               if(subtargetName.length() > 0) {\r
-                       return dataRepository.getLoadedFeature(subtargetName, loadedFeatureDataType);\r
-               }\r
-               return targetObject;\r
-       }\r
-\r
-       /**\r
-        * This method returns target's object location.\r
-        * @param constraint\r
-        *        the constraint instance\r
-        * @return target's object location\r
-        */\r
-       protected Vector3f getTargetLocation(Constraint constraint) {\r
-               Long targetOMA = ((Pointer)constraint.getData().getFieldValue("tar")).getOldMemoryAddress();\r
-               Space targetSpace = constraint.getTargetSpace();\r
-               Node targetObject = (Node)dataRepository.getLoadedFeature(targetOMA, LoadedFeatureDataType.LOADED_FEATURE);\r
-               switch(targetSpace) {\r
-                       case CONSTRAINT_SPACE_LOCAL:\r
-                               return targetObject.getLocalTranslation();\r
-                       case CONSTRAINT_SPACE_WORLD:\r
-                               return targetObject.getWorldTranslation();\r
-                       default:\r
-                               throw new IllegalStateException("Invalid space type for target object: " + targetSpace.toString());\r
-               }\r
-       }\r
-       \r
-       /**\r
-        * This method returns target's object location in the specified frame.\r
-        * @param constraint\r
-        *        the constraint instance\r
-        * @param frame\r
-        *        the frame number\r
-        * @return target's object location\r
-        */\r
-       protected Vector3f getTargetLocation(Constraint constraint, int frame) {\r
-               return this.getTargetLocation(constraint);//TODO: implement getting location in a specified frame\r
-       }\r
-\r
-       /**\r
-        * This method returns target's object rotation.\r
-        * @param constraint\r
-        *        the constraint instance\r
-        * @return target's object rotation\r
-        */\r
-       protected Quaternion getTargetRotation(Constraint constraint) {\r
-               Long targetOMA = ((Pointer)constraint.getData().getFieldValue("tar")).getOldMemoryAddress();\r
-               Space targetSpace = constraint.getTargetSpace();\r
-               Node targetObject = (Node)dataRepository.getLoadedFeature(targetOMA, LoadedFeatureDataType.LOADED_FEATURE);\r
-               switch(targetSpace) {\r
-                       case CONSTRAINT_SPACE_LOCAL:\r
-                               return targetObject.getLocalRotation();\r
-                       case CONSTRAINT_SPACE_WORLD:\r
-                               return targetObject.getWorldRotation();\r
-                       default:\r
-                               throw new IllegalStateException("Invalid space type for target object: " + targetSpace.toString());\r
-               }\r
-       }\r
-\r
-       /**\r
-        * This method returns target's object scale.\r
-        * @param constraint\r
-        *        the constraint instance\r
-        * @return target's object scale\r
-        */\r
-       protected Vector3f getTargetScale(Constraint constraint) {\r
-               Long targetOMA = ((Pointer)constraint.getData().getFieldValue("tar")).getOldMemoryAddress();\r
-               Space targetSpace = constraint.getTargetSpace();\r
-               Node targetObject = (Node)dataRepository.getLoadedFeature(targetOMA, LoadedFeatureDataType.LOADED_FEATURE);\r
-               switch(targetSpace) {\r
-                       case CONSTRAINT_SPACE_LOCAL:\r
-                               return targetObject.getLocalScale();\r
-                       case CONSTRAINT_SPACE_WORLD:\r
-                               return targetObject.getWorldScale();\r
-                       default:\r
-                               throw new IllegalStateException("Invalid space type for target object: " + targetSpace.toString());\r
-               }\r
-       }\r
+    protected static final Logger LOGGER = Logger.getLogger(AbstractInfluenceFunction.class.getName());\r
+    protected static final float IK_SOLVER_ERROR = 0.5f;\r
+    //DISTLIMIT\r
+    protected static final int LIMITDIST_INSIDE = 0;\r
+    protected static final int LIMITDIST_OUTSIDE = 1;\r
+    protected static final int LIMITDIST_ONSURFACE = 2;\r
+    //CONSTRAINT_TYPE_LOCLIKE\r
+    protected static final int LOCLIKE_X = 0x01;\r
+    protected static final int LOCLIKE_Y = 0x02;\r
+    protected static final int LOCLIKE_Z = 0x04;\r
+    //ROTLIKE\r
+    protected static final int ROTLIKE_X = 0x01;\r
+    protected static final int ROTLIKE_Y = 0x02;\r
+    protected static final int ROTLIKE_Z = 0x04;\r
+    protected static final int ROTLIKE_X_INVERT = 0x10;\r
+    protected static final int ROTLIKE_Y_INVERT = 0x20;\r
+    protected static final int ROTLIKE_Z_INVERT = 0x40;\r
+    protected static final int ROTLIKE_OFFSET = 0x80;\r
+    //SIZELIKE\r
+    protected static final int SIZELIKE_X = 0x01;\r
+    protected static final int SIZELIKE_Y = 0x02;\r
+    protected static final int SIZELIKE_Z = 0x04;\r
+    protected static final int SIZELIKE_OFFSET = 0x80;\r
+\r
+    /* LOCLIKE_TIP is a depreceated option... use headtail=1.0f instead */\r
+    //protected static final int LOCLIKE_TIP = 0x08;\r
+    protected static final int LOCLIKE_X_INVERT = 0x10;\r
+    protected static final int LOCLIKE_Y_INVERT = 0x20;\r
+    protected static final int LOCLIKE_Z_INVERT = 0x40;\r
+    protected static final int LOCLIKE_OFFSET = 0x80;\r
+    //LOCLIMIT, SIZELIMIT\r
+    protected static final int LIMIT_XMIN = 0x01;\r
+    protected static final int LIMIT_XMAX = 0x02;\r
+    protected static final int LIMIT_YMIN = 0x04;\r
+    protected static final int LIMIT_YMAX = 0x08;\r
+    protected static final int LIMIT_ZMIN = 0x10;\r
+    protected static final int LIMIT_ZMAX = 0x20;\r
+    //ROTLIMIT\r
+    protected static final int LIMIT_XROT = 0x01;\r
+    protected static final int LIMIT_YROT = 0x02;\r
+    protected static final int LIMIT_ZROT = 0x04;\r
+    /** The type of the constraint. */\r
+    protected ConstraintType constraintType;\r
+    /** The data repository. */\r
+    protected DataRepository dataRepository;\r
+\r
+    /**\r
+     * Constructor.\r
+     * @param constraintType\r
+     *        the type of the current constraint\r
+     * @param dataRepository\r
+     *        the data repository\r
+     */\r
+    public AbstractInfluenceFunction(ConstraintType constraintType, DataRepository dataRepository) {\r
+        this.constraintType = constraintType;\r
+        this.dataRepository = dataRepository;\r
+    }\r
+\r
+    /**\r
+     * This method validates the constraint type. It throws an IllegalArgumentException if the constraint type of the\r
+     * given structure is invalid.\r
+     * @param constraintStructure\r
+     *        the structure with constraint data\r
+     */\r
+    protected void validateConstraintType(Structure constraintStructure) {\r
+        if (!constraintType.getClassName().equalsIgnoreCase(constraintStructure.getType())) {\r
+            throw new IllegalArgumentException("Invalud structure type (" + constraintStructure.getType() + ") for the constraint: " + constraintType.getClassName() + '!');\r
+        }\r
+    }\r
+\r
+    /**\r
+     * This method affects the bone animation tracks for the given skeleton.\r
+     * @param skeleton\r
+     *        the skeleton containing the affected bones by constraint\r
+     * @param boneAnimation\r
+     *        the bone animation baked traces\r
+     * @param constraint\r
+     *        the constraint\r
+     */\r
+    public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {\r
+    }\r
+\r
+    /**\r
+     * This method returns the bone traces for the bone that is affected by the given constraint.\r
+     * @param skeleton\r
+     *        the skeleton containing bones\r
+     * @param boneAnimation\r
+     *        the bone animation that affects the skeleton\r
+     * @param constraint\r
+     *        the affecting constraint\r
+     * @return the bone track for the bone that is being affected by the constraint\r
+     */\r
+    protected BoneTrack getBoneTrack(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {\r
+        Long boneOMA = constraint.getBoneOMA();\r
+        Bone bone = (Bone) dataRepository.getLoadedFeature(boneOMA, LoadedFeatureDataType.LOADED_FEATURE);\r
+        int boneIndex = skeleton.getBoneIndex(bone);\r
+        if (boneIndex != -1) {\r
+            //searching for track for this bone\r
+            for (BoneTrack boneTrack : boneAnimation.getTracks()) {\r
+                if (boneTrack.getTargetBoneIndex() == boneIndex) {\r
+                    return boneTrack;\r
+                }\r
+            }\r
+        }\r
+        return null;\r
+    }\r
+\r
+    /**\r
+     * This method returns the target or subtarget object (if specified).\r
+     * @param constraint\r
+     *        the constraint instance\r
+     * @return target or subtarget feature\r
+     */\r
+    protected Object getTarget(Constraint constraint, LoadedFeatureDataType loadedFeatureDataType) {\r
+        Long targetOMA = ((Pointer) constraint.getData().getFieldValue("tar")).getOldMemoryAddress();\r
+        Object targetObject = dataRepository.getLoadedFeature(targetOMA, loadedFeatureDataType);\r
+        String subtargetName = constraint.getData().getFieldValue("subtarget").toString();\r
+        if (subtargetName.length() > 0) {\r
+            return dataRepository.getLoadedFeature(subtargetName, loadedFeatureDataType);\r
+        }\r
+        return targetObject;\r
+    }\r
+\r
+    /**\r
+     * This method returns target's object location.\r
+     * @param constraint\r
+     *        the constraint instance\r
+     * @return target's object location\r
+     */\r
+    protected Vector3f getTargetLocation(Constraint constraint) {\r
+        Long targetOMA = ((Pointer) constraint.getData().getFieldValue("tar")).getOldMemoryAddress();\r
+        Space targetSpace = constraint.getTargetSpace();\r
+        Node targetObject = (Node) dataRepository.getLoadedFeature(targetOMA, LoadedFeatureDataType.LOADED_FEATURE);\r
+        switch (targetSpace) {\r
+            case CONSTRAINT_SPACE_LOCAL:\r
+                return targetObject.getLocalTranslation();\r
+            case CONSTRAINT_SPACE_WORLD:\r
+                return targetObject.getWorldTranslation();\r
+            default:\r
+                throw new IllegalStateException("Invalid space type for target object: " + targetSpace.toString());\r
+        }\r
+    }\r
+\r
+    /**\r
+     * This method returns target's object location in the specified frame.\r
+     * @param constraint\r
+     *        the constraint instance\r
+     * @param frame\r
+     *        the frame number\r
+     * @return target's object location\r
+     */\r
+    protected Vector3f getTargetLocation(Constraint constraint, int frame) {\r
+        return this.getTargetLocation(constraint);//TODO: implement getting location in a specified frame\r
+    }\r
+\r
+    /**\r
+     * This method returns target's object rotation.\r
+     * @param constraint\r
+     *        the constraint instance\r
+     * @return target's object rotation\r
+     */\r
+    protected Quaternion getTargetRotation(Constraint constraint) {\r
+        Long targetOMA = ((Pointer) constraint.getData().getFieldValue("tar")).getOldMemoryAddress();\r
+        Space targetSpace = constraint.getTargetSpace();\r
+        Node targetObject = (Node) dataRepository.getLoadedFeature(targetOMA, LoadedFeatureDataType.LOADED_FEATURE);\r
+        switch (targetSpace) {\r
+            case CONSTRAINT_SPACE_LOCAL:\r
+                return targetObject.getLocalRotation();\r
+            case CONSTRAINT_SPACE_WORLD:\r
+                return targetObject.getWorldRotation();\r
+            default:\r
+                throw new IllegalStateException("Invalid space type for target object: " + targetSpace.toString());\r
+        }\r
+    }\r
+\r
+    /**\r
+     * This method returns target's object scale.\r
+     * @param constraint\r
+     *        the constraint instance\r
+     * @return target's object scale\r
+     */\r
+    protected Vector3f getTargetScale(Constraint constraint) {\r
+        Long targetOMA = ((Pointer) constraint.getData().getFieldValue("tar")).getOldMemoryAddress();\r
+        Space targetSpace = constraint.getTargetSpace();\r
+        Node targetObject = (Node) dataRepository.getLoadedFeature(targetOMA, LoadedFeatureDataType.LOADED_FEATURE);\r
+        switch (targetSpace) {\r
+            case CONSTRAINT_SPACE_LOCAL:\r
+                return targetObject.getLocalScale();\r
+            case CONSTRAINT_SPACE_WORLD:\r
+                return targetObject.getWorldScale();\r
+            default:\r
+                throw new IllegalStateException("Invalid space type for target object: " + targetSpace.toString());\r
+        }\r
+    }\r
 }\r
index bf7b43c..9826d9a 100644 (file)
@@ -13,125 +13,125 @@ import com.jme3.scene.plugins.blender.utils.DynamicArray;
  * @author Marcin Roguski\r
  */\r
 public class BezierCurve {\r
-       public static final int X_VALUE = 0;\r
-       public static final int Y_VALUE = 1;\r
-       public static final int Z_VALUE = 2;\r
 \r
-       /** \r
-        * The type of the curve. Describes the data it modifies. \r
-        * Used in ipos calculations.\r
-        */\r
-       private int                             type;\r
-       /** The dimension of the curve. */\r
-       private int                     dimension;\r
-       /** A table of the bezier points. */\r
-       private float[][][]     bezierPoints;\r
+    public static final int X_VALUE = 0;\r
+    public static final int Y_VALUE = 1;\r
+    public static final int Z_VALUE = 2;\r
+    /** \r
+     * The type of the curve. Describes the data it modifies. \r
+     * Used in ipos calculations.\r
+     */\r
+    private int type;\r
+    /** The dimension of the curve. */\r
+    private int dimension;\r
+    /** A table of the bezier points. */\r
+    private float[][][] bezierPoints;\r
 \r
-       @SuppressWarnings("unchecked")\r
-       public BezierCurve(final int type, final List<Structure> bezTriples, final int dimension) {\r
-               if(dimension != 2 && dimension != 3) {\r
-                       throw new IllegalArgumentException("The dimension of the curve should be 2 or 3!");\r
-               }\r
-               this.type = type;\r
-               this.dimension = dimension;\r
-               //first index of the bezierPoints table has the length of triples amount\r
-               //the second index points to a table od three points of a bezier triple (handle, point, handle)\r
-               //the third index specifies the coordinates of the specific point in a bezier triple\r
-               bezierPoints = new float[bezTriples.size()][3][dimension];\r
-               int i = 0, j, k;\r
-               for(Structure bezTriple : bezTriples) {\r
-                       DynamicArray<Number> vec = (DynamicArray<Number>)bezTriple.getFieldValue("vec");\r
-                       for(j = 0; j < 3; ++j) {\r
-                               for(k = 0; k < dimension; ++k) {\r
-                                       bezierPoints[i][j][k] = vec.get(j, k).floatValue();\r
-                               }\r
-                       }\r
-                       ++i;\r
-               }\r
-       }\r
+    @SuppressWarnings("unchecked")\r
+    public BezierCurve(final int type, final List<Structure> bezTriples, final int dimension) {\r
+        if (dimension != 2 && dimension != 3) {\r
+            throw new IllegalArgumentException("The dimension of the curve should be 2 or 3!");\r
+        }\r
+        this.type = type;\r
+        this.dimension = dimension;\r
+        //first index of the bezierPoints table has the length of triples amount\r
+        //the second index points to a table od three points of a bezier triple (handle, point, handle)\r
+        //the third index specifies the coordinates of the specific point in a bezier triple\r
+        bezierPoints = new float[bezTriples.size()][3][dimension];\r
+        int i = 0, j, k;\r
+        for (Structure bezTriple : bezTriples) {\r
+            DynamicArray<Number> vec = (DynamicArray<Number>) bezTriple.getFieldValue("vec");\r
+            for (j = 0; j < 3; ++j) {\r
+                for (k = 0; k < dimension; ++k) {\r
+                    bezierPoints[i][j][k] = vec.get(j, k).floatValue();\r
+                }\r
+            }\r
+            ++i;\r
+        }\r
+    }\r
 \r
-       /**\r
-        * This method evaluates the data for the specified frame. The Y value is returned.\r
-        * @param frame\r
-        *        the frame for which the value is being calculated\r
-        * @param valuePart\r
-        *        this param specifies wheather we should return the X, Y or Z part of the result value; it should have\r
-        *        one of the following values: X_VALUE - the X factor of the result Y_VALUE - the Y factor of the result\r
-        *        Z_VALUE - the Z factor of the result\r
-        * @return the value of the curve\r
-        */\r
-       public float evaluate(int frame, int valuePart) {\r
-               for(int i = 0; i < bezierPoints.length - 1; ++i) {\r
-                       if(frame >= bezierPoints[i][1][0] && frame <= bezierPoints[i + 1][1][0]) {\r
-                               float t = (frame - bezierPoints[i][1][0]) / (bezierPoints[i + 1][1][0] - bezierPoints[i][1][0]);\r
-                               float oneMinusT = 1.0f - t;\r
-                               float oneMinusT2 = oneMinusT * oneMinusT;\r
-                               float t2 = t * t;\r
-                               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;\r
-                       }\r
-               }\r
-               if(frame < bezierPoints[0][1][0]) {\r
-                       return bezierPoints[0][1][1];\r
-               } else { //frame>bezierPoints[bezierPoints.length-1][1][0]\r
-                       return bezierPoints[bezierPoints.length - 1][1][1];\r
-               }\r
-       }\r
+    /**\r
+     * This method evaluates the data for the specified frame. The Y value is returned.\r
+     * @param frame\r
+     *        the frame for which the value is being calculated\r
+     * @param valuePart\r
+     *        this param specifies wheather we should return the X, Y or Z part of the result value; it should have\r
+     *        one of the following values: X_VALUE - the X factor of the result Y_VALUE - the Y factor of the result\r
+     *        Z_VALUE - the Z factor of the result\r
+     * @return the value of the curve\r
+     */\r
+    public float evaluate(int frame, int valuePart) {\r
+        for (int i = 0; i < bezierPoints.length - 1; ++i) {\r
+            if (frame >= bezierPoints[i][1][0] && frame <= bezierPoints[i + 1][1][0]) {\r
+                float t = (frame - bezierPoints[i][1][0]) / (bezierPoints[i + 1][1][0] - bezierPoints[i][1][0]);\r
+                float oneMinusT = 1.0f - t;\r
+                float oneMinusT2 = oneMinusT * oneMinusT;\r
+                float t2 = t * t;\r
+                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;\r
+            }\r
+        }\r
+        if (frame < bezierPoints[0][1][0]) {\r
+            return bezierPoints[0][1][1];\r
+        } else { //frame>bezierPoints[bezierPoints.length-1][1][0]\r
+            return bezierPoints[bezierPoints.length - 1][1][1];\r
+        }\r
+    }\r
 \r
-       /**\r
-        * This method returns the frame where last bezier triple center point of the bezier curve is located.\r
-        * @return the frame number of the last defined bezier triple point for the curve\r
-        */\r
-       public int getLastFrame() {\r
-               return (int)bezierPoints[bezierPoints.length - 1][1][0];\r
-       }\r
-       \r
-       /**\r
-        * This method returns the type of the bezier curve. The type describes the parameter that this curve modifies\r
-        * (ie. LocationX or rotationW of the feature).\r
-        * @return the type of the bezier curve\r
-        */\r
-       public int getType() {\r
-               return type;\r
-       }\r
-       \r
-       /**\r
-        * This method returns a list of control points for this curve.\r
-        * @return a list of control points for this curve.\r
-        */\r
-       public List<Vector3f> getControlPoints() {\r
-               List<Vector3f> controlPoints = new ArrayList<Vector3f>(bezierPoints.length * 3);\r
-               for(int i = 0;i<bezierPoints.length;++i) {\r
-                       controlPoints.add(new Vector3f(bezierPoints[i][0][0], bezierPoints[i][0][1], bezierPoints[i][0][2]));\r
-                       controlPoints.add(new Vector3f(bezierPoints[i][1][0], bezierPoints[i][1][1], bezierPoints[i][1][2]));\r
-                       controlPoints.add(new Vector3f(bezierPoints[i][2][0], bezierPoints[i][2][1], bezierPoints[i][2][2]));\r
-               }\r
-               return controlPoints;\r
-       }\r
+    /**\r
+     * This method returns the frame where last bezier triple center point of the bezier curve is located.\r
+     * @return the frame number of the last defined bezier triple point for the curve\r
+     */\r
+    public int getLastFrame() {\r
+        return (int) bezierPoints[bezierPoints.length - 1][1][0];\r
+    }\r
 \r
-       @Override\r
-       public String toString() {\r
-               StringBuilder sb = new StringBuilder("Bezier curve: ").append(type).append('\n');\r
-               for(int i = 0; i < bezierPoints.length; ++i) {\r
-                       sb.append(this.toStringBezTriple(i)).append('\n');\r
-               }\r
-               return sb.toString();\r
-       }\r
+    /**\r
+     * This method returns the type of the bezier curve. The type describes the parameter that this curve modifies\r
+     * (ie. LocationX or rotationW of the feature).\r
+     * @return the type of the bezier curve\r
+     */\r
+    public int getType() {\r
+        return type;\r
+    }\r
 \r
-       /**\r
-        * This method converts the bezier triple of a specified index into text.\r
-        * @param tripleIndex\r
-        *        index of the triple\r
-        * @return text representation of the triple\r
-        */\r
-       private String toStringBezTriple(int tripleIndex) {\r
-               if(this.dimension==2) {\r
-                       return "[(" + bezierPoints[tripleIndex][0][0] + ", " + bezierPoints[tripleIndex][0][1] + ") (" \r
-                                               + bezierPoints[tripleIndex][1][0] + ", " + bezierPoints[tripleIndex][1][1] + ") (" \r
-                                               + bezierPoints[tripleIndex][2][0] + ", " + bezierPoints[tripleIndex][2][1] + ")]";\r
-               } else {\r
-                       return "[(" + bezierPoints[tripleIndex][0][0] + ", " + bezierPoints[tripleIndex][0][1] + ", " + bezierPoints[tripleIndex][0][2] + ") (" \r
-                                               + bezierPoints[tripleIndex][1][0] + ", " + bezierPoints[tripleIndex][1][1] + ", " + bezierPoints[tripleIndex][1][2] + ") (" \r
-                                               + bezierPoints[tripleIndex][2][0] + ", " + bezierPoints[tripleIndex][2][1] + ", " + bezierPoints[tripleIndex][2][2] + ")]";\r
-               }\r
-       }\r
+    /**\r
+     * This method returns a list of control points for this curve.\r
+     * @return a list of control points for this curve.\r
+     */\r
+    public List<Vector3f> getControlPoints() {\r
+        List<Vector3f> controlPoints = new ArrayList<Vector3f>(bezierPoints.length * 3);\r
+        for (int i = 0; i < bezierPoints.length; ++i) {\r
+            controlPoints.add(new Vector3f(bezierPoints[i][0][0], bezierPoints[i][0][1], bezierPoints[i][0][2]));\r
+            controlPoints.add(new Vector3f(bezierPoints[i][1][0], bezierPoints[i][1][1], bezierPoints[i][1][2]));\r
+            controlPoints.add(new Vector3f(bezierPoints[i][2][0], bezierPoints[i][2][1], bezierPoints[i][2][2]));\r
+        }\r
+        return controlPoints;\r
+    }\r
+\r
+    @Override\r
+    public String toString() {\r
+        StringBuilder sb = new StringBuilder("Bezier curve: ").append(type).append('\n');\r
+        for (int i = 0; i < bezierPoints.length; ++i) {\r
+            sb.append(this.toStringBezTriple(i)).append('\n');\r
+        }\r
+        return sb.toString();\r
+    }\r
+\r
+    /**\r
+     * This method converts the bezier triple of a specified index into text.\r
+     * @param tripleIndex\r
+     *        index of the triple\r
+     * @return text representation of the triple\r
+     */\r
+    private String toStringBezTriple(int tripleIndex) {\r
+        if (this.dimension == 2) {\r
+            return "[(" + bezierPoints[tripleIndex][0][0] + ", " + bezierPoints[tripleIndex][0][1] + ") ("\r
+                    + bezierPoints[tripleIndex][1][0] + ", " + bezierPoints[tripleIndex][1][1] + ") ("\r
+                    + bezierPoints[tripleIndex][2][0] + ", " + bezierPoints[tripleIndex][2][1] + ")]";\r
+        } else {\r
+            return "[(" + bezierPoints[tripleIndex][0][0] + ", " + bezierPoints[tripleIndex][0][1] + ", " + bezierPoints[tripleIndex][0][2] + ") ("\r
+                    + bezierPoints[tripleIndex][1][0] + ", " + bezierPoints[tripleIndex][1][1] + ", " + bezierPoints[tripleIndex][1][2] + ") ("\r
+                    + bezierPoints[tripleIndex][2][0] + ", " + bezierPoints[tripleIndex][2][1] + ", " + bezierPoints[tripleIndex][2][2] + ")]";\r
+        }\r
+    }\r
 }
\ No newline at end of file
index 6aa7ba8..6f2c645 100644 (file)
@@ -12,151 +12,151 @@ import com.jme3.scene.plugins.blender.utils.Pointer;
  * @author Marcin Roguski\r
  */\r
 public class Constraint {\r
-       /** The type of this constraint. */\r
-       private final ConstraintType                    type;\r
-       /** The name of this constraint. */\r
-       private final String                                    name;\r
-       /** The old memory address of the constraint's owner. */\r
-       private final Long                                              boneOMA;\r
 \r
-       private final Space                                             ownerSpace;\r
+    /** The type of this constraint. */\r
+    private final ConstraintType type;\r
+    /** The name of this constraint. */\r
+    private final String name;\r
+    /** The old memory address of the constraint's owner. */\r
+    private final Long boneOMA;\r
+    private final Space ownerSpace;\r
+    private final Space targetSpace;\r
+    /** The structure with constraint's data. */\r
+    private final Structure data;\r
+    /** The ipo object defining influence. */\r
+    private final Ipo ipo;\r
+    /** The influence function of this constraint. */\r
+    private final AbstractInfluenceFunction influenceFunction;\r
 \r
-       private final Space                                             targetSpace;\r
-       /** The structure with constraint's data. */\r
-       private final Structure                                 data;\r
-       /** The ipo object defining influence. */\r
-       private final Ipo                                               ipo;\r
-       /** The influence function of this constraint. */\r
-       private final AbstractInfluenceFunction influenceFunction;\r
+    /**\r
+     * This constructor creates the constraint instance.\r
+     * @param constraintStructure\r
+     *        the constraint's structure (bConstraint clss in blender 2.49).\r
+     * @param influenceFunction\r
+     *        the constraint's influence function (taken from ConstraintHelper)\r
+     * @param boneOMA\r
+     *        the old memory address of the constraint owner\r
+     * @param influenceIpo\r
+     *        the ipo curve of the influence factor\r
+     * @param dataRepository\r
+     *        the data repository\r
+     * @throws BlenderFileException\r
+     */\r
+    public Constraint(Structure constraintStructure, AbstractInfluenceFunction influenceFunction, Long boneOMA, Space ownerSpace, Space targetSpace, Ipo influenceIpo, DataRepository dataRepository) throws BlenderFileException {\r
+        if (influenceFunction == null) {\r
+            throw new IllegalArgumentException("Influence function is not defined!");\r
+        }\r
+        Pointer pData = (Pointer) constraintStructure.getFieldValue("data");\r
+        if (!pData.isNull()) {\r
+            data = pData.fetchData(dataRepository.getInputStream()).get(0);\r
+        } else {\r
+            throw new BlenderFileException("The constraint has no data specified!");\r
+        }\r
+        this.boneOMA = boneOMA;\r
+        this.type = ConstraintType.valueOf(((Number) constraintStructure.getFieldValue("type")).intValue());\r
+        this.name = constraintStructure.getFieldValue("name").toString();\r
+        this.ownerSpace = ownerSpace;\r
+        this.targetSpace = targetSpace;\r
+        this.ipo = influenceIpo;\r
+        this.influenceFunction = influenceFunction;\r
+    }\r
 \r
-       /**\r
-        * This constructor creates the constraint instance.\r
-        * @param constraintStructure\r
-        *        the constraint's structure (bConstraint clss in blender 2.49).\r
-        * @param influenceFunction\r
-        *        the constraint's influence function (taken from ConstraintHelper)\r
-        * @param boneOMA\r
-        *        the old memory address of the constraint owner\r
-        * @param influenceIpo\r
-        *        the ipo curve of the influence factor\r
-        * @param dataRepository\r
-        *        the data repository\r
-        * @throws BlenderFileException\r
-        */\r
-       public Constraint(Structure constraintStructure, AbstractInfluenceFunction influenceFunction, Long boneOMA, Space ownerSpace, Space targetSpace, Ipo influenceIpo, DataRepository dataRepository) throws BlenderFileException {\r
-               if(influenceFunction == null) {\r
-                       throw new IllegalArgumentException("Influence function is not defined!");\r
-               }\r
-               Pointer pData = (Pointer)constraintStructure.getFieldValue("data");\r
-               if(!pData.isNull()) {\r
-                       data = pData.fetchData(dataRepository.getInputStream()).get(0);\r
-               } else {\r
-                       throw new BlenderFileException("The constraint has no data specified!");\r
-               }\r
-               this.boneOMA = boneOMA;\r
-               this.type = ConstraintType.valueOf(((Number)constraintStructure.getFieldValue("type")).intValue());\r
-               this.name = constraintStructure.getFieldValue("name").toString();\r
-               this.ownerSpace = ownerSpace;\r
-               this.targetSpace = targetSpace;\r
-               this.ipo = influenceIpo;\r
-               this.influenceFunction = influenceFunction;\r
-       }\r
+    /**\r
+     * This method returns the name of the constraint.\r
+     * @return the name of the constraint\r
+     */\r
+    public String getName() {\r
+        return name;\r
+    }\r
 \r
-       /**\r
-        * This method returns the name of the constraint.\r
-        * @return the name of the constraint\r
-        */\r
-       public String getName() {\r
-               return name;\r
-       }\r
+    /**\r
+     * This method returns the old memoty address of the bone this constraint affects.\r
+     * @return the old memory address of the bone this constraint affects\r
+     */\r
+    public Long getBoneOMA() {\r
+        return boneOMA;\r
+    }\r
 \r
-       /**\r
-        * This method returns the old memoty address of the bone this constraint affects.\r
-        * @return the old memory address of the bone this constraint affects\r
-        */\r
-       public Long getBoneOMA() {\r
-               return boneOMA;\r
-       }\r
+    /**\r
+     * This method returns owner's transform space.\r
+     * @return owner's transform space\r
+     */\r
+    public Space getOwnerSpace() {\r
+        return ownerSpace;\r
+    }\r
 \r
-       /**\r
-        * This method returns owner's transform space.\r
-        * @return owner's transform space\r
-        */\r
-       public Space getOwnerSpace() {\r
-               return ownerSpace;\r
-       }\r
+    /**\r
+     * This method returns target's transform space.\r
+     * @return target's transform space\r
+     */\r
+    public Space getTargetSpace() {\r
+        return targetSpace;\r
+    }\r
 \r
-       /**\r
-        * This method returns target's transform space.\r
-        * @return target's transform space\r
-        */\r
-       public Space getTargetSpace() {\r
-               return targetSpace;\r
-       }\r
+    /**\r
+     * This method returns the type of the constraint.\r
+     * @return the type of the constraint\r
+     */\r
+    public ConstraintType getType() {\r
+        return type;\r
+    }\r
 \r
-       /**\r
-        * This method returns the type of the constraint.\r
-        * @return the type of the constraint\r
-        */\r
-       public ConstraintType getType() {\r
-               return type;\r
-       }\r
+    /**\r
+     * This method returns the constraint's data structure.\r
+     * @return the constraint's data structure\r
+     */\r
+    public Structure getData() {\r
+        return data;\r
+    }\r
 \r
-       /**\r
-        * This method returns the constraint's data structure.\r
-        * @return the constraint's data structure\r
-        */\r
-       public Structure getData() {\r
-               return data;\r
-       }\r
+    /**\r
+     * This method returns the constraint's influcence curve.\r
+     * @return the constraint's influcence curve\r
+     */\r
+    public Ipo getIpo() {\r
+        return ipo;\r
+    }\r
 \r
-       /**\r
-        * This method returns the constraint's influcence curve.\r
-        * @return the constraint's influcence curve\r
-        */\r
-       public Ipo getIpo() {\r
-               return ipo;\r
-       }\r
+    /**\r
+     * This method affects the bone animation tracks for the given skeleton.\r
+     * @param skeleton\r
+     *        the skeleton containing the affected bones by constraint\r
+     * @param boneAnimation\r
+     *        the bone animation baked traces\r
+     * @param constraint\r
+     *        the constraint\r
+     */\r
+    public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation) {\r
+        influenceFunction.affectAnimation(skeleton, boneAnimation, this);\r
+    }\r
 \r
-       /**\r
-        * This method affects the bone animation tracks for the given skeleton.\r
-        * @param skeleton\r
-        *        the skeleton containing the affected bones by constraint\r
-        * @param boneAnimation\r
-        *        the bone animation baked traces\r
-        * @param constraint\r
-        *        the constraint\r
-        */\r
-       public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation) {\r
-               influenceFunction.affectAnimation(skeleton, boneAnimation, this);\r
-       }\r
+    /**\r
+     * The space of target or owner transformation.\r
+     * @author Marcin Roguski\r
+     */\r
+    public static enum Space {\r
 \r
-       /**\r
-        * The space of target or owner transformation.\r
-        * @author Marcin Roguski\r
-        */\r
-       public static enum Space {\r
-               CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_PARLOCAL, CONSTRAINT_SPACE_INVALID;\r
+        CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_PARLOCAL, CONSTRAINT_SPACE_INVALID;\r
 \r
-               /**\r
-                * This method returns the enum instance when given the appropriate value from the blend file.\r
-                * @param c\r
-                *        the blender's value of the space modifier\r
-                * @return the scape enum instance\r
-                */\r
-               public static Space valueOf(byte c) {\r
-                       switch(c) {\r
-                               case 0:\r
-                                       return CONSTRAINT_SPACE_WORLD;\r
-                               case 1:\r
-                                       return CONSTRAINT_SPACE_LOCAL;\r
-                               case 2:\r
-                                       return CONSTRAINT_SPACE_POSE;\r
-                               case 3:\r
-                                       return CONSTRAINT_SPACE_PARLOCAL;\r
-                               default:\r
-                                       return CONSTRAINT_SPACE_INVALID;\r
-                       }\r
-               }\r
-       }\r
+        /**\r
+         * This method returns the enum instance when given the appropriate value from the blend file.\r
+         * @param c\r
+         *        the blender's value of the space modifier\r
+         * @return the scape enum instance\r
+         */\r
+        public static Space valueOf(byte c) {\r
+            switch (c) {\r
+                case 0:\r
+                    return CONSTRAINT_SPACE_WORLD;\r
+                case 1:\r
+                    return CONSTRAINT_SPACE_LOCAL;\r
+                case 2:\r
+                    return CONSTRAINT_SPACE_POSE;\r
+                case 3:\r
+                    return CONSTRAINT_SPACE_PARLOCAL;\r
+                default:\r
+                    return CONSTRAINT_SPACE_INVALID;\r
+            }\r
+        }\r
+    }\r
 }
\ No newline at end of file
index 0fd2313..db486b5 100644 (file)
@@ -10,134 +10,136 @@ import java.util.Map;
  * @author Marcin Roguski\r
  */\r
 public enum ConstraintType {\r
-       /* Invalid/legacy constraint */\r
-       CONSTRAINT_TYPE_NULL(0, "bNullConstraint"),\r
-       /* Unimplemented non longer :) - during constraints recode, Aligorith */\r
-       CONSTRAINT_TYPE_CHILDOF(1, "bChildOfConstraint"), \r
-       CONSTRAINT_TYPE_KINEMATIC(3, "bKinematicConstraint"), \r
-       CONSTRAINT_TYPE_FOLLOWPATH(4, "bFollowPathConstraint"),\r
-       /* Unimplemented no longer :) - Aligorith */\r
-       CONSTRAINT_TYPE_ROTLIMIT(5, "bRotLimitConstraint"),\r
-       /* Unimplemented no longer :) - Aligorith */\r
-       CONSTRAINT_TYPE_LOCLIMIT(6, "bLocLimitConstraint"),\r
-       /* Unimplemented no longer :) - Aligorith */\r
-       CONSTRAINT_TYPE_SIZELIMIT(7, "bSizeLimitConstraint"), \r
-       CONSTRAINT_TYPE_ROTLIKE(8, "bRotateLikeConstraint"), \r
-       CONSTRAINT_TYPE_LOCLIKE(9, "bLocateLikeConstraint"), \r
-       CONSTRAINT_TYPE_SIZELIKE(10, "bSizeLikeConstraint"),\r
-       /* Unimplemented no longer :) - Aligorith. Scripts */\r
-       CONSTRAINT_TYPE_PYTHON(11, "bPythonConstraint"), \r
-       CONSTRAINT_TYPE_ACTION(12, "bActionConstraint"),\r
-       /* New Tracking constraint that locks an axis in place - theeth */\r
-       CONSTRAINT_TYPE_LOCKTRACK(13, "bLockTrackConstraint"),\r
-       /* limit distance */\r
-       CONSTRAINT_TYPE_DISTLIMIT(14, "bDistLimitConstraint"),\r
-       /* claiming this to be mine :) is in tuhopuu bjornmose */\r
-       CONSTRAINT_TYPE_STRETCHTO(15, "bStretchToConstraint"),\r
-       /* floor constraint */\r
-       CONSTRAINT_TYPE_MINMAX(16, "bMinMaxConstraint"),\r
-       /* rigidbody constraint */\r
-       CONSTRAINT_TYPE_RIGIDBODYJOINT(17, "bRigidBodyConstraint"),\r
-       /* clampto constraint */\r
-       CONSTRAINT_TYPE_CLAMPTO(18, "bClampToConstraint"),\r
-       /* transformation (loc/rot/size -> loc/rot/size) constraint */\r
-       CONSTRAINT_TYPE_TRANSFORM(19, "bTransformConstraint"),\r
-       /* shrinkwrap (loc/rot) constraint */\r
-       CONSTRAINT_TYPE_SHRINKWRAP(20, "bShrinkwrapConstraint");\r
+    /* Invalid/legacy constraint */\r
 \r
-       /** The constraint's id (in blender known as 'type'). */\r
-       private int                                                                     constraintId;\r
-       /** The name of constraint class used by blender. */\r
-       private String                                                          className;\r
-       /** The map containing class names and types of constraints. */\r
-       private static Map<String, ConstraintType>      typesMap        = new HashMap<String, ConstraintType>(ConstraintType.values().length);\r
-       /** The map containing class names and types of constraints. */\r
-       private static Map<Integer, ConstraintType>     idsMap  = new HashMap<Integer, ConstraintType>(ConstraintType.values().length);\r
-       static {\r
-               idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_NULL.constraintId), CONSTRAINT_TYPE_NULL);\r
-               idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_CHILDOF.constraintId), CONSTRAINT_TYPE_CHILDOF);\r
-               idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_KINEMATIC.constraintId), CONSTRAINT_TYPE_KINEMATIC);\r
-               idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_FOLLOWPATH.constraintId), CONSTRAINT_TYPE_FOLLOWPATH);\r
-               idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_ROTLIMIT.constraintId), CONSTRAINT_TYPE_ROTLIMIT);\r
-               idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_LOCLIMIT.constraintId), CONSTRAINT_TYPE_LOCLIMIT);\r
-               idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_SIZELIMIT.constraintId), CONSTRAINT_TYPE_SIZELIMIT);\r
-               idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_ROTLIKE.constraintId), CONSTRAINT_TYPE_ROTLIKE);\r
-               idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_LOCLIKE.constraintId), CONSTRAINT_TYPE_LOCLIKE);\r
-               idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_SIZELIKE.constraintId), CONSTRAINT_TYPE_SIZELIKE);\r
-               idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_PYTHON.constraintId), CONSTRAINT_TYPE_PYTHON);\r
-               idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_ACTION.constraintId), CONSTRAINT_TYPE_ACTION);\r
-               idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_LOCKTRACK.constraintId), CONSTRAINT_TYPE_LOCKTRACK);\r
-               idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_DISTLIMIT.constraintId), CONSTRAINT_TYPE_DISTLIMIT);\r
-               idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_STRETCHTO.constraintId), CONSTRAINT_TYPE_STRETCHTO);\r
-               idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_MINMAX.constraintId), CONSTRAINT_TYPE_MINMAX);\r
-               idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_RIGIDBODYJOINT.constraintId), CONSTRAINT_TYPE_RIGIDBODYJOINT);\r
-               idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_CLAMPTO.constraintId), CONSTRAINT_TYPE_CLAMPTO);\r
-               idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_TRANSFORM.constraintId), CONSTRAINT_TYPE_TRANSFORM);\r
-               idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_SHRINKWRAP.constraintId), CONSTRAINT_TYPE_SHRINKWRAP);\r
-       }\r
-       /**\r
-        * Constructor. Stores constraint type and class name.\r
-        * @param constraintId\r
-        *        the constraint's type\r
-        * @param className\r
-        *        the constraint's type name\r
-        */\r
-       private ConstraintType(int constraintId, String className) {\r
-               this.constraintId = constraintId;\r
-               this.className = className;\r
-       }\r
+    CONSTRAINT_TYPE_NULL(0, "bNullConstraint"),\r
+    /* Unimplemented non longer :) - during constraints recode, Aligorith */\r
+    CONSTRAINT_TYPE_CHILDOF(1, "bChildOfConstraint"),\r
+    CONSTRAINT_TYPE_KINEMATIC(3, "bKinematicConstraint"),\r
+    CONSTRAINT_TYPE_FOLLOWPATH(4, "bFollowPathConstraint"),\r
+    /* Unimplemented no longer :) - Aligorith */\r
+    CONSTRAINT_TYPE_ROTLIMIT(5, "bRotLimitConstraint"),\r
+    /* Unimplemented no longer :) - Aligorith */\r
+    CONSTRAINT_TYPE_LOCLIMIT(6, "bLocLimitConstraint"),\r
+    /* Unimplemented no longer :) - Aligorith */\r
+    CONSTRAINT_TYPE_SIZELIMIT(7, "bSizeLimitConstraint"),\r
+    CONSTRAINT_TYPE_ROTLIKE(8, "bRotateLikeConstraint"),\r
+    CONSTRAINT_TYPE_LOCLIKE(9, "bLocateLikeConstraint"),\r
+    CONSTRAINT_TYPE_SIZELIKE(10, "bSizeLikeConstraint"),\r
+    /* Unimplemented no longer :) - Aligorith. Scripts */\r
+    CONSTRAINT_TYPE_PYTHON(11, "bPythonConstraint"),\r
+    CONSTRAINT_TYPE_ACTION(12, "bActionConstraint"),\r
+    /* New Tracking constraint that locks an axis in place - theeth */\r
+    CONSTRAINT_TYPE_LOCKTRACK(13, "bLockTrackConstraint"),\r
+    /* limit distance */\r
+    CONSTRAINT_TYPE_DISTLIMIT(14, "bDistLimitConstraint"),\r
+    /* claiming this to be mine :) is in tuhopuu bjornmose */\r
+    CONSTRAINT_TYPE_STRETCHTO(15, "bStretchToConstraint"),\r
+    /* floor constraint */\r
+    CONSTRAINT_TYPE_MINMAX(16, "bMinMaxConstraint"),\r
+    /* rigidbody constraint */\r
+    CONSTRAINT_TYPE_RIGIDBODYJOINT(17, "bRigidBodyConstraint"),\r
+    /* clampto constraint */\r
+    CONSTRAINT_TYPE_CLAMPTO(18, "bClampToConstraint"),\r
+    /* transformation (loc/rot/size -> loc/rot/size) constraint */\r
+    CONSTRAINT_TYPE_TRANSFORM(19, "bTransformConstraint"),\r
+    /* shrinkwrap (loc/rot) constraint */\r
+    CONSTRAINT_TYPE_SHRINKWRAP(20, "bShrinkwrapConstraint");\r
+    /** The constraint's id (in blender known as 'type'). */\r
+    private int constraintId;\r
+    /** The name of constraint class used by blender. */\r
+    private String className;\r
+    /** The map containing class names and types of constraints. */\r
+    private static final Map<String, ConstraintType> typesMap = new HashMap<String, ConstraintType>(ConstraintType.values().length);\r
+    /** The map containing class names and types of constraints. */\r
+    private static final Map<Integer, ConstraintType> idsMap = new HashMap<Integer, ConstraintType>(ConstraintType.values().length);\r
 \r
-       /**\r
-        * This method returns the type by given constraint id.\r
-        * @param constraintId\r
-        *        the id of the constraint\r
-        * @return the constraint type enum value\r
-        */\r
-       public static ConstraintType valueOf(int constraintId) {\r
-               return idsMap.get(Integer.valueOf(constraintId));\r
-       }\r
+    static {\r
+        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_NULL.constraintId), CONSTRAINT_TYPE_NULL);\r
+        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_CHILDOF.constraintId), CONSTRAINT_TYPE_CHILDOF);\r
+        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_KINEMATIC.constraintId), CONSTRAINT_TYPE_KINEMATIC);\r
+        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_FOLLOWPATH.constraintId), CONSTRAINT_TYPE_FOLLOWPATH);\r
+        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_ROTLIMIT.constraintId), CONSTRAINT_TYPE_ROTLIMIT);\r
+        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_LOCLIMIT.constraintId), CONSTRAINT_TYPE_LOCLIMIT);\r
+        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_SIZELIMIT.constraintId), CONSTRAINT_TYPE_SIZELIMIT);\r
+        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_ROTLIKE.constraintId), CONSTRAINT_TYPE_ROTLIKE);\r
+        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_LOCLIKE.constraintId), CONSTRAINT_TYPE_LOCLIKE);\r
+        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_SIZELIKE.constraintId), CONSTRAINT_TYPE_SIZELIKE);\r
+        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_PYTHON.constraintId), CONSTRAINT_TYPE_PYTHON);\r
+        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_ACTION.constraintId), CONSTRAINT_TYPE_ACTION);\r
+        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_LOCKTRACK.constraintId), CONSTRAINT_TYPE_LOCKTRACK);\r
+        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_DISTLIMIT.constraintId), CONSTRAINT_TYPE_DISTLIMIT);\r
+        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_STRETCHTO.constraintId), CONSTRAINT_TYPE_STRETCHTO);\r
+        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_MINMAX.constraintId), CONSTRAINT_TYPE_MINMAX);\r
+        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_RIGIDBODYJOINT.constraintId), CONSTRAINT_TYPE_RIGIDBODYJOINT);\r
+        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_CLAMPTO.constraintId), CONSTRAINT_TYPE_CLAMPTO);\r
+        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_TRANSFORM.constraintId), CONSTRAINT_TYPE_TRANSFORM);\r
+        idsMap.put(Integer.valueOf(CONSTRAINT_TYPE_SHRINKWRAP.constraintId), CONSTRAINT_TYPE_SHRINKWRAP);\r
+    }\r
 \r
-       /**\r
-        * This method returns the constraint's id (type).\r
-        * @return the constraint's id (type)\r
-        */\r
-       public int getConstraintId() {\r
-               return constraintId;\r
-       }\r
+    /**\r
+     * Constructor. Stores constraint type and class name.\r
+     * @param constraintId\r
+     *        the constraint's type\r
+     * @param className\r
+     *        the constraint's type name\r
+     */\r
+    private ConstraintType(int constraintId, String className) {\r
+        this.constraintId = constraintId;\r
+        this.className = className;\r
+    }\r
 \r
-       /**\r
-        * This method returns the constraint's class name.\r
-        * @return the constraint's class name\r
-        */\r
-       public String getClassName() {\r
-               return className;\r
-       }\r
+    /**\r
+     * This method returns the type by given constraint id.\r
+     * @param constraintId\r
+     *        the id of the constraint\r
+     * @return the constraint type enum value\r
+     */\r
+    public static ConstraintType valueOf(int constraintId) {\r
+        return idsMap.get(Integer.valueOf(constraintId));\r
+    }\r
 \r
-       /**\r
-        * This method returns constraint enum type by the given class name.\r
-        * @param className\r
-        *        the blender's constraint class name\r
-        * @return the constraint enum type of the specified class name\r
-        */\r
-       public static ConstraintType getByBlenderClassName(String className) {\r
-               ConstraintType result = typesMap.get(className);\r
-               if(result == null) {\r
-                       ConstraintType[] constraints = ConstraintType.values();\r
-                       for(ConstraintType constraint : constraints) {\r
-                               if(constraint.className.equals(className)) {\r
-                                       return constraint;\r
-                               }\r
-                       }\r
-               }\r
-               return result;\r
-       }\r
+    /**\r
+     * This method returns the constraint's id (type).\r
+     * @return the constraint's id (type)\r
+     */\r
+    public int getConstraintId() {\r
+        return constraintId;\r
+    }\r
 \r
-       /**\r
-        * This method returns the type value of the last defined constraint. It can be used for allocating tables for\r
-        * storing constraint procedures since not all type values from 0 to the last value are used.\r
-        * @return the type value of the last defined constraint\r
-        */\r
-       public static int getLastDefinedTypeValue() {\r
-               return CONSTRAINT_TYPE_SHRINKWRAP.getConstraintId();\r
-       }\r
+    /**\r
+     * This method returns the constraint's class name.\r
+     * @return the constraint's class name\r
+     */\r
+    public String getClassName() {\r
+        return className;\r
+    }\r
+\r
+    /**\r
+     * This method returns constraint enum type by the given class name.\r
+     * @param className\r
+     *        the blender's constraint class name\r
+     * @return the constraint enum type of the specified class name\r
+     */\r
+    public static ConstraintType getByBlenderClassName(String className) {\r
+        ConstraintType result = typesMap.get(className);\r
+        if (result == null) {\r
+            ConstraintType[] constraints = ConstraintType.values();\r
+            for (ConstraintType constraint : constraints) {\r
+                if (constraint.className.equals(className)) {\r
+                    return constraint;\r
+                }\r
+            }\r
+        }\r
+        return result;\r
+    }\r
+\r
+    /**\r
+     * This method returns the type value of the last defined constraint. It can be used for allocating tables for\r
+     * storing constraint procedures since not all type values from 0 to the last value are used.\r
+     * @return the type value of the last defined constraint\r
+     */\r
+    public static int getLastDefinedTypeValue() {\r
+        return CONSTRAINT_TYPE_SHRINKWRAP.getConstraintId();\r
+    }\r
 }\r
index d75e5d7..d098774 100644 (file)
@@ -10,167 +10,167 @@ import com.jme3.math.Vector3f;
  * @author Marcin Roguski\r
  */\r
 public class Ipo {\r
-       public static final int AC_LOC_X = 1;\r
-       public static final int AC_LOC_Y = 2;\r
-       public static final int AC_LOC_Z = 3;\r
-       public static final int OB_ROT_X = 7;\r
-       public static final int OB_ROT_Y = 8;\r
-       public static final int OB_ROT_Z = 9;\r
-       public static final int AC_SIZE_X = 13;\r
-       public static final int AC_SIZE_Y = 14;\r
-       public static final int AC_SIZE_Z = 15;\r
-       public static final int AC_QUAT_W = 25;\r
-       public static final int AC_QUAT_X = 26;\r
-       public static final int AC_QUAT_Y = 27;\r
-       public static final int AC_QUAT_Z = 28;\r
-       \r
-       /** A list of bezier curves for this interpolation object. */\r
-       private BezierCurve[]   bezierCurves;\r
-       /** Each ipo contains one bone track. */\r
-       private BoneTrack calculatedTrack;\r
 \r
-       /**\r
-        * Constructor. Stores the bezier curves.\r
-        * @param bezierCurves\r
-        *        a table of bezier curves\r
-        */\r
-       public Ipo(BezierCurve[] bezierCurves) {\r
-               this.bezierCurves = bezierCurves;\r
-       }\r
+    public static final int AC_LOC_X = 1;\r
+    public static final int AC_LOC_Y = 2;\r
+    public static final int AC_LOC_Z = 3;\r
+    public static final int OB_ROT_X = 7;\r
+    public static final int OB_ROT_Y = 8;\r
+    public static final int OB_ROT_Z = 9;\r
+    public static final int AC_SIZE_X = 13;\r
+    public static final int AC_SIZE_Y = 14;\r
+    public static final int AC_SIZE_Z = 15;\r
+    public static final int AC_QUAT_W = 25;\r
+    public static final int AC_QUAT_X = 26;\r
+    public static final int AC_QUAT_Y = 27;\r
+    public static final int AC_QUAT_Z = 28;\r
+    /** A list of bezier curves for this interpolation object. */\r
+    private BezierCurve[] bezierCurves;\r
+    /** Each ipo contains one bone track. */\r
+    private BoneTrack calculatedTrack;\r
 \r
-       /**\r
-        * This method calculates the ipo value for the first curve.\r
-        * @param frame\r
-        *        the frame for which the value is calculated\r
-        * @return calculated ipo value\r
-        */\r
-       public float calculateValue(int frame) {\r
-               return this.calculateValue(frame, 0);\r
-       }\r
+    /**\r
+     * Constructor. Stores the bezier curves.\r
+     * @param bezierCurves\r
+     *        a table of bezier curves\r
+     */\r
+    public Ipo(BezierCurve[] bezierCurves) {\r
+        this.bezierCurves = bezierCurves;\r
+    }\r
 \r
-       /**\r
-        * This method calculates the ipo value for the curve of the specified index. Make sure you do not exceed the\r
-        * curves amount. Alway chech the amount of curves before calling this method.\r
-        * @param frame\r
-        *        the frame for which the value is calculated\r
-        * @param curveIndex\r
-        *        the index of the curve\r
-        * @return calculated ipo value\r
-        */\r
-       public float calculateValue(int frame, int curveIndex) {\r
-               return bezierCurves[curveIndex].evaluate(frame, BezierCurve.Y_VALUE);\r
-       }\r
+    /**\r
+     * This method calculates the ipo value for the first curve.\r
+     * @param frame\r
+     *        the frame for which the value is calculated\r
+     * @return calculated ipo value\r
+     */\r
+    public float calculateValue(int frame) {\r
+        return this.calculateValue(frame, 0);\r
+    }\r
 \r
-       /**\r
-        * This method returns the curves amount.\r
-        * @return the curves amount\r
-        */\r
-       public int getCurvesAmount() {\r
-               return bezierCurves.length;\r
-       }\r
+    /**\r
+     * This method calculates the ipo value for the curve of the specified index. Make sure you do not exceed the\r
+     * curves amount. Alway chech the amount of curves before calling this method.\r
+     * @param frame\r
+     *        the frame for which the value is calculated\r
+     * @param curveIndex\r
+     *        the index of the curve\r
+     * @return calculated ipo value\r
+     */\r
+    public float calculateValue(int frame, int curveIndex) {\r
+        return bezierCurves[curveIndex].evaluate(frame, BezierCurve.Y_VALUE);\r
+    }\r
 \r
-       /**\r
-        * This method returns the frame where last bezier triple center point of the specified bezier curve is located.\r
-        * @return the frame number of the last defined bezier triple point for the specified ipo\r
-        */\r
-       public int getLastFrame() {\r
-               int result = 1;\r
-               for(int i = 0; i < bezierCurves.length; ++i) {\r
-                       int tempResult = bezierCurves[i].getLastFrame();\r
-                       if(tempResult > result) {\r
-                               result = tempResult;\r
-                       }\r
-               }\r
-               return result;\r
-       }\r
-       \r
-       public void modifyTranslation(int frame, Vector3f translation) {\r
-               if(calculatedTrack!=null) {\r
-                       calculatedTrack.getTranslations()[frame].set(translation);\r
-               }\r
-       }\r
-       \r
-       public void modifyRotation(int frame, Quaternion rotation) {\r
-               if(calculatedTrack!=null) {\r
-                       calculatedTrack.getRotations()[frame].set(rotation);\r
-               }\r
-       }\r
-       \r
-       public void modifyScale(int frame, Vector3f scale) {\r
-               if(calculatedTrack!=null) {\r
-                       calculatedTrack.getScales()[frame].set(scale);\r
-               }\r
-       }\r
-       \r
-       /**\r
-        * This method calculates the value of the curves as a bone track between the specified frames.\r
-        * @param boneIndex\r
-        *        the index of the bone for which the method calculates the tracks\r
-        * @param startFrame\r
-        *        the firs frame of tracks (inclusive)\r
-        * @param stopFrame\r
-        *        the last frame of the tracks (inclusive)\r
-        * @param fps\r
-        *        frame rate (frames per second)\r
-        * @return bone track for the specified bone\r
-        */\r
-       public BoneTrack calculateTrack(int boneIndex, int startFrame, int stopFrame, int fps) {\r
-               //preparing data for track\r
-               int framesAmount = stopFrame - startFrame;\r
-               float start = (startFrame - 1.0f) / fps;\r
-               float timeBetweenFrames = 1.0f / fps;\r
+    /**\r
+     * This method returns the curves amount.\r
+     * @return the curves amount\r
+     */\r
+    public int getCurvesAmount() {\r
+        return bezierCurves.length;\r
+    }\r
 \r
-               float[] times = new float[framesAmount + 1];\r
-               Vector3f[] translations = new Vector3f[framesAmount + 1];\r
-               float[] translation = new float[3];\r
-               Quaternion[] rotations = new Quaternion[framesAmount + 1];\r
-               float[] quaternionRotation = new float[4];\r
-               float[] objectRotation = new float[3];\r
-               boolean bObjectRotation = false;\r
-               Vector3f[] scales = new Vector3f[framesAmount + 1];\r
-               float[] scale = new float[3];\r
+    /**\r
+     * This method returns the frame where last bezier triple center point of the specified bezier curve is located.\r
+     * @return the frame number of the last defined bezier triple point for the specified ipo\r
+     */\r
+    public int getLastFrame() {\r
+        int result = 1;\r
+        for (int i = 0; i < bezierCurves.length; ++i) {\r
+            int tempResult = bezierCurves[i].getLastFrame();\r
+            if (tempResult > result) {\r
+                result = tempResult;\r
+            }\r
+        }\r
+        return result;\r
+    }\r
 \r
-               //calculating track data\r
-               for(int frame = startFrame; frame <= stopFrame; ++frame) {\r
-                       int index = frame - startFrame;\r
-                       times[index] = start + (frame - 1) * timeBetweenFrames;\r
-                       for(int j = 0; j < bezierCurves.length; ++j) {\r
-                               double value = bezierCurves[j].evaluate(frame, BezierCurve.Y_VALUE);\r
-                               switch(bezierCurves[j].getType()) {\r
-                                       case AC_LOC_X:\r
-                                       case AC_LOC_Y:\r
-                                       case AC_LOC_Z:\r
-                                               translation[bezierCurves[j].getType() - 1] = (float)value;\r
-                                               break;\r
-                                       case OB_ROT_X:\r
-                                       case OB_ROT_Y:\r
-                                       case OB_ROT_Z:\r
-                                               objectRotation[bezierCurves[j].getType() - 7] = (float)value;\r
-                                               bObjectRotation = true;\r
-                                               break;\r
-                                       case AC_SIZE_X:\r
-                                       case AC_SIZE_Y:\r
-                                       case AC_SIZE_Z:\r
-                                               scale[bezierCurves[j].getType() - 13] = (float)value;\r
-                                               break;\r
-                                       case AC_QUAT_W:\r
-                                               quaternionRotation[3] = (float)value;\r
-                                               break;\r
-                                       case AC_QUAT_X:\r
-                                       case AC_QUAT_Y:\r
-                                       case AC_QUAT_Z:\r
-                                               quaternionRotation[bezierCurves[j].getType() - 26] = (float)value;\r
-                                               break;\r
-                                       default:\r
-                                               //TODO: error? info? warning?\r
-                               }\r
-                       }\r
-                       translations[index] = new Vector3f(translation[0], translation[1], translation[2]);\r
-                       rotations[index] = bObjectRotation ? new Quaternion().fromAngles(objectRotation) : \r
-                                                               new Quaternion(quaternionRotation[0], quaternionRotation[1], quaternionRotation[2], quaternionRotation[3]);\r
-                       scales[index] = new Vector3f(scale[0], scale[1], scale[2]);\r
-               }\r
-               calculatedTrack = new BoneTrack(boneIndex, times, translations, rotations, scales);\r
-               return calculatedTrack;\r
-       }\r
+    public void modifyTranslation(int frame, Vector3f translation) {\r
+        if (calculatedTrack != null) {\r
+            calculatedTrack.getTranslations()[frame].set(translation);\r
+        }\r
+    }\r
+\r
+    public void modifyRotation(int frame, Quaternion rotation) {\r
+        if (calculatedTrack != null) {\r
+            calculatedTrack.getRotations()[frame].set(rotation);\r
+        }\r
+    }\r
+\r
+    public void modifyScale(int frame, Vector3f scale) {\r
+        if (calculatedTrack != null) {\r
+            calculatedTrack.getScales()[frame].set(scale);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * This method calculates the value of the curves as a bone track between the specified frames.\r
+     * @param boneIndex\r
+     *        the index of the bone for which the method calculates the tracks\r
+     * @param startFrame\r
+     *        the firs frame of tracks (inclusive)\r
+     * @param stopFrame\r
+     *        the last frame of the tracks (inclusive)\r
+     * @param fps\r
+     *        frame rate (frames per second)\r
+     * @return bone track for the specified bone\r
+     */\r
+    public BoneTrack calculateTrack(int boneIndex, int startFrame, int stopFrame, int fps) {\r
+        //preparing data for track\r
+        int framesAmount = stopFrame - startFrame;\r
+        float start = (startFrame - 1.0f) / fps;\r
+        float timeBetweenFrames = 1.0f / fps;\r
+\r
+        float[] times = new float[framesAmount + 1];\r
+        Vector3f[] translations = new Vector3f[framesAmount + 1];\r
+        float[] translation = new float[3];\r
+        Quaternion[] rotations = new Quaternion[framesAmount + 1];\r
+        float[] quaternionRotation = new float[4];\r
+        float[] objectRotation = new float[3];\r
+        boolean bObjectRotation = false;\r
+        Vector3f[] scales = new Vector3f[framesAmount + 1];\r
+        float[] scale = new float[3];\r
+\r
+        //calculating track data\r
+        for (int frame = startFrame; frame <= stopFrame; ++frame) {\r
+            int index = frame - startFrame;\r
+            times[index] = start + (frame - 1) * timeBetweenFrames;\r
+            for (int j = 0; j < bezierCurves.length; ++j) {\r
+                double value = bezierCurves[j].evaluate(frame, BezierCurve.Y_VALUE);\r
+                switch (bezierCurves[j].getType()) {\r
+                    case AC_LOC_X:\r
+                    case AC_LOC_Y:\r
+                    case AC_LOC_Z:\r
+                        translation[bezierCurves[j].getType() - 1] = (float) value;\r
+                        break;\r
+                    case OB_ROT_X:\r
+                    case OB_ROT_Y:\r
+                    case OB_ROT_Z:\r
+                        objectRotation[bezierCurves[j].getType() - 7] = (float) value;\r
+                        bObjectRotation = true;\r
+                        break;\r
+                    case AC_SIZE_X:\r
+                    case AC_SIZE_Y:\r
+                    case AC_SIZE_Z:\r
+                        scale[bezierCurves[j].getType() - 13] = (float) value;\r
+                        break;\r
+                    case AC_QUAT_W:\r
+                        quaternionRotation[3] = (float) value;\r
+                        break;\r
+                    case AC_QUAT_X:\r
+                    case AC_QUAT_Y:\r
+                    case AC_QUAT_Z:\r
+                        quaternionRotation[bezierCurves[j].getType() - 26] = (float) value;\r
+                        break;\r
+                    default:\r
+                    //TODO: error? info? warning?\r
+                }\r
+            }\r
+            translations[index] = new Vector3f(translation[0], translation[1], translation[2]);\r
+            rotations[index] = bObjectRotation ? new Quaternion().fromAngles(objectRotation)\r
+                    : new Quaternion(quaternionRotation[0], quaternionRotation[1], quaternionRotation[2], quaternionRotation[3]);\r
+            scales[index] = new Vector3f(scale[0], scale[1], scale[2]);\r
+        }\r
+        calculatedTrack = new BoneTrack(boneIndex, times, translations, rotations, scales);\r
+        return calculatedTrack;\r
+    }\r
 }
\ No newline at end of file
index f53fdde..a3184ab 100644 (file)
@@ -7,50 +7,51 @@ package com.jme3.scene.plugins.blender.structures;
  * @author Marcin Roguski (Kaelthas)\r
  */\r
 public class Modifier {\r
-       public static final String      ARRAY_MODIFIER_DATA             = "ArrayModifierData";\r
-       public static final String      ARMATURE_MODIFIER_DATA  = "ArmatureModifierData";\r
-       public static final String      PARTICLE_MODIFIER_DATA  = "ParticleSystemModifierData";\r
 \r
-       /** Blender's type of modifier. */\r
-       private String                          type;\r
-       /** JME modifier representation object. */\r
-       private Object                          jmeModifierRepresentation;\r
-       /** Various additional data used by modifiers.*/\r
-       private Object                          additionalData;\r
-       /**\r
-        * Constructor. Creates modifier object.\r
-        * @param type\r
-        *        blender's type of modifier\r
-        * @param modifier\r
-        *        JME modifier representation object\r
-        */\r
-       public Modifier(String type, Object modifier, Object additionalData) {\r
-               this.type = type;\r
-               this.jmeModifierRepresentation = modifier;\r
-               this.additionalData = additionalData;\r
-       }\r
+    public static final String ARRAY_MODIFIER_DATA = "ArrayModifierData";\r
+    public static final String ARMATURE_MODIFIER_DATA = "ArmatureModifierData";\r
+    public static final String PARTICLE_MODIFIER_DATA = "ParticleSystemModifierData";\r
+    /** Blender's type of modifier. */\r
+    private String type;\r
+    /** JME modifier representation object. */\r
+    private Object jmeModifierRepresentation;\r
+    /** Various additional data used by modifiers.*/\r
+    private Object additionalData;\r
 \r
-       /**\r
-        * This method returns JME modifier representation object.\r
-        * @return JME modifier representation object\r
-        */\r
-       public Object getJmeModifierRepresentation() {\r
-               return jmeModifierRepresentation;\r
-       }\r
+    /**\r
+     * Constructor. Creates modifier object.\r
+     * @param type\r
+     *        blender's type of modifier\r
+     * @param modifier\r
+     *        JME modifier representation object\r
+     */\r
+    public Modifier(String type, Object modifier, Object additionalData) {\r
+        this.type = type;\r
+        this.jmeModifierRepresentation = modifier;\r
+        this.additionalData = additionalData;\r
+    }\r
 \r
-       /**\r
-        * This method returns blender's type of modifier.\r
-        * @return blender's type of modifier\r
-        */\r
-       public String getType() {\r
-               return type;\r
-       }\r
-       \r
-       /**\r
-        * This method returns additional data stored in the modifier.\r
-        * @return the additional data stored in the modifier\r
-        */\r
-       public Object getAdditionalData() {\r
-               return additionalData;\r
-       }\r
+    /**\r
+     * This method returns JME modifier representation object.\r
+     * @return JME modifier representation object\r
+     */\r
+    public Object getJmeModifierRepresentation() {\r
+        return jmeModifierRepresentation;\r
+    }\r
+\r
+    /**\r
+     * This method returns blender's type of modifier.\r
+     * @return blender's type of modifier\r
+     */\r
+    public String getType() {\r
+        return type;\r
+    }\r
+\r
+    /**\r
+     * This method returns additional data stored in the modifier.\r
+     * @return the additional data stored in the modifier\r
+     */\r
+    public Object getAdditionalData() {\r
+        return additionalData;\r
+    }\r
 }
\ No newline at end of file
index efa507d..3bf0f08 100644 (file)
@@ -42,61 +42,63 @@ import com.jme3.util.BufferUtils;
  * @author Marcin Roguski\r
  */\r
 public abstract class AbstractBlenderHelper {\r
-       /** The version of the blend file. */\r
-       protected final int blenderVersion;\r
 \r
-       /**\r
-        * This constructor parses the given blender version and stores the result. Some functionalities may differ in different blender\r
-        * versions.\r
-        * @param blenderVersion\r
-        *            the version read from the blend file\r
-        */\r
-       public AbstractBlenderHelper(String blenderVersion) {\r
-               this.blenderVersion = Integer.parseInt(blenderVersion);\r
-       }\r
-       \r
-       /**\r
-        * This method clears the state of the helper so that it can be used for different calculations of another feature.\r
-        */\r
-       public void clearState() { }\r
+    /** The version of the blend file. */\r
+    protected final int blenderVersion;\r
 \r
-       /**\r
-        * This method should be used to check if the text is blank. Avoid using text.trim().length()==0. This causes that more strings are\r
-        * being created and stored in the memory. It can be unwise especially inside loops.\r
-        * @param text\r
-        *            the text to be checked\r
-        * @return <b>true</b> if the text is blank and <b>false</b> otherwise\r
-        */\r
-       protected boolean isBlank(String text) {\r
-               if (text != null) {\r
-                       for (int i = 0; i < text.length(); ++i) {\r
-                               if (!Character.isWhitespace(text.charAt(i))) {\r
-                                       return false;\r
-                               }\r
-                       }\r
-               }\r
-               return true;\r
-       }\r
-       \r
-       /**\r
-        * Generate a new FloatBuffer using the given array of float[4] objects. The FloatBuffer will be 4 * data.length\r
-        * long and contain the vector data as data[0][0], data[0][1], data[0][2], data[0][3], data[1][0]... etc.\r
-        * @param data\r
-        *        list of float[4] objects to place into a new FloatBuffer\r
-        */\r
-       protected FloatBuffer createFloatBuffer(List<float[]> data) {\r
-               if(data == null) {\r
-                       return null;\r
-               }\r
-               FloatBuffer buff = BufferUtils.createFloatBuffer(4 * data.size());\r
-               for(float[] v : data) {\r
-                       if(v != null) {\r
-                               buff.put(v[0]).put(v[1]).put(v[2]).put(v[3]);\r
-                       } else {\r
-                               buff.put(0).put(0).put(0).put(0);\r
-                       }\r
-               }\r
-               buff.flip();\r
-               return buff;\r
-       }\r
+    /**\r
+     * This constructor parses the given blender version and stores the result. Some functionalities may differ in different blender\r
+     * versions.\r
+     * @param blenderVersion\r
+     *            the version read from the blend file\r
+     */\r
+    public AbstractBlenderHelper(String blenderVersion) {\r
+        this.blenderVersion = Integer.parseInt(blenderVersion);\r
+    }\r
+\r
+    /**\r
+     * This method clears the state of the helper so that it can be used for different calculations of another feature.\r
+     */\r
+    public void clearState() {\r
+    }\r
+\r
+    /**\r
+     * This method should be used to check if the text is blank. Avoid using text.trim().length()==0. This causes that more strings are\r
+     * being created and stored in the memory. It can be unwise especially inside loops.\r
+     * @param text\r
+     *            the text to be checked\r
+     * @return <b>true</b> if the text is blank and <b>false</b> otherwise\r
+     */\r
+    protected boolean isBlank(String text) {\r
+        if (text != null) {\r
+            for (int i = 0; i < text.length(); ++i) {\r
+                if (!Character.isWhitespace(text.charAt(i))) {\r
+                    return false;\r
+                }\r
+            }\r
+        }\r
+        return true;\r
+    }\r
+\r
+    /**\r
+     * Generate a new FloatBuffer using the given array of float[4] objects. The FloatBuffer will be 4 * data.length\r
+     * long and contain the vector data as data[0][0], data[0][1], data[0][2], data[0][3], data[1][0]... etc.\r
+     * @param data\r
+     *        list of float[4] objects to place into a new FloatBuffer\r
+     */\r
+    protected FloatBuffer createFloatBuffer(List<float[]> data) {\r
+        if (data == null) {\r
+            return null;\r
+        }\r
+        FloatBuffer buff = BufferUtils.createFloatBuffer(4 * data.size());\r
+        for (float[] v : data) {\r
+            if (v != null) {\r
+                buff.put(v[0]).put(v[1]).put(v[2]).put(v[3]);\r
+            } else {\r
+                buff.put(0).put(0).put(0).put(0);\r
+            }\r
+        }\r
+        buff.flip();\r
+        return buff;\r
+    }\r
 }\r
@@ -52,58 +52,59 @@ import com.jme3.scene.plugins.blender.exception.BlenderFileException;
  *        the type of material element\r
  */\r
 //TODO: ujednolicić wyrzucane wyjÄ…tki\r
-public interface IBlenderConverter<NodeType, CameraType, LightType, ObjectType, MeshType, MaterialType> {\r
-       /**\r
-        * This method reads converts the given structure into scene. The given structure needs to be filled with the\r
-        * appropriate data.\r
-        * @param structure\r
-        *        the structure we read the scene from\r
-        * @return the scene feature\r
-        */\r
-       NodeType toScene(Structure structure);\r
+public interface BlenderConverter<NodeType, CameraType, LightType, ObjectType, MeshType, MaterialType> {\r
 \r
-       /**\r
-        * This method reads converts the given structure into camera. The given structure needs to be filled with the\r
-        * appropriate data.\r
-        * @param structure\r
-        *        the structure we read the camera from\r
-        * @return the camera feature\r
-        */\r
-       CameraType toCamera(Structure structure) throws BlenderFileException;\r
+    /**\r
+     * This method reads converts the given structure into scene. The given structure needs to be filled with the\r
+     * appropriate data.\r
+     * @param structure\r
+     *        the structure we read the scene from\r
+     * @return the scene feature\r
+     */\r
+    NodeType toScene(Structure structure);\r
 \r
-       /**\r
-        * This method reads converts the given structure into light. The given structure needs to be filled with the\r
-        * appropriate data.\r
-        * @param structure\r
-        *        the structure we read the light from\r
-        * @return the light feature\r
-        */\r
-       LightType toLight(Structure structure) throws BlenderFileException;\r
+    /**\r
+     * This method reads converts the given structure into camera. The given structure needs to be filled with the\r
+     * appropriate data.\r
+     * @param structure\r
+     *        the structure we read the camera from\r
+     * @return the camera feature\r
+     */\r
+    CameraType toCamera(Structure structure) throws BlenderFileException;\r
 \r
-       /**\r
-        * This method reads converts the given structure into objct. The given structure needs to be filled with the\r
-        * appropriate data.\r
-        * @param structure\r
-        *        the structure we read the object from\r
-        * @return the object feature\r
-        */\r
-       ObjectType toObject(Structure structure) throws BlenderFileException;\r
+    /**\r
+     * This method reads converts the given structure into light. The given structure needs to be filled with the\r
+     * appropriate data.\r
+     * @param structure\r
+     *        the structure we read the light from\r
+     * @return the light feature\r
+     */\r
+    LightType toLight(Structure structure) throws BlenderFileException;\r
 \r
-       /**\r
-        * This method reads converts the given structure into mesh. The given structure needs to be filled with the\r
-        * appropriate data.\r
-        * @param structure\r
-        *        the structure we read the mesh from\r
-        * @return the mesh feature\r
-        */\r
-       MeshType toMesh(Structure structure) throws BlenderFileException;\r
+    /**\r
+     * This method reads converts the given structure into objct. The given structure needs to be filled with the\r
+     * appropriate data.\r
+     * @param structure\r
+     *        the structure we read the object from\r
+     * @return the object feature\r
+     */\r
+    ObjectType toObject(Structure structure) throws BlenderFileException;\r
 \r
-       /**\r
-        * This method reads converts the given structure into material. The given structure needs to be filled with the\r
-        * appropriate data.\r
-        * @param structure\r
-        *        the structure we read the material from\r
-        * @return the material feature\r
-        */\r
-       MaterialType toMaterial(Structure structure) throws BlenderFileException;\r
+    /**\r
+     * This method reads converts the given structure into mesh. The given structure needs to be filled with the\r
+     * appropriate data.\r
+     * @param structure\r
+     *        the structure we read the mesh from\r
+     * @return the mesh feature\r
+     */\r
+    MeshType toMesh(Structure structure) throws BlenderFileException;\r
+\r
+    /**\r
+     * This method reads converts the given structure into material. The given structure needs to be filled with the\r
+     * appropriate data.\r
+     * @param structure\r
+     *        the structure we read the material from\r
+     * @return the material feature\r
+     */\r
+    MaterialType toMaterial(Structure structure) throws BlenderFileException;\r
 }
\ No newline at end of file
index 73b74da..e5fe0a8 100644 (file)
@@ -46,337 +46,337 @@ import com.jme3.scene.plugins.blender.exception.BlenderFileException;
  * @author Marcin Roguski\r
  */\r
 public class BlenderInputStream extends InputStream {\r
-       private static final Logger     LOGGER                          = Logger.getLogger(BlenderInputStream.class.getName());\r
 \r
-       /** The default size of the blender buffer. */\r
-       private static final int        DEFAULT_BUFFER_SIZE     = 1048576;                                                                                              //1MB\r
-       /** The application's asset manager. */\r
-       private AssetManager            assetManager;\r
-       /**\r
-        * Size of a pointer; all pointers in the file are stored in this format. '_' means 4 bytes and '-' means 8 bytes.\r
-        */\r
-       private int                                     pointerSize;\r
-       /**\r
-        * Type of byte ordering used; 'v' means little endian and 'V' means big endian.\r
-        */\r
-       private char                            endianess;\r
-       /** Version of Blender the file was created in; '248' means version 2.48. */\r
-       private String                          versionNumber;\r
-       /** The buffer we store the read data to. */\r
-       protected byte[]                        cachedBuffer;\r
-       /** The total size of the stored data. */\r
-       protected int                           size;\r
-       /** The current position of the read cursor. */\r
-       protected int                           position;\r
+    private static final Logger LOGGER = Logger.getLogger(BlenderInputStream.class.getName());\r
+    /** The default size of the blender buffer. */\r
+    private static final int DEFAULT_BUFFER_SIZE = 1048576;                                                                                            //1MB\r
+    /** The application's asset manager. */\r
+    private AssetManager assetManager;\r
+    /**\r
+     * Size of a pointer; all pointers in the file are stored in this format. '_' means 4 bytes and '-' means 8 bytes.\r
+     */\r
+    private int pointerSize;\r
+    /**\r
+     * Type of byte ordering used; 'v' means little endian and 'V' means big endian.\r
+     */\r
+    private char endianess;\r
+    /** Version of Blender the file was created in; '248' means version 2.48. */\r
+    private String versionNumber;\r
+    /** The buffer we store the read data to. */\r
+    protected byte[] cachedBuffer;\r
+    /** The total size of the stored data. */\r
+    protected int size;\r
+    /** The current position of the read cursor. */\r
+    protected int position;\r
 \r
-       /**\r
-        * Constructor. The input stream is stored and used to read data.\r
-        * @param inputStream\r
-        *        the stream we read data from\r
-        * @param assetManager\r
-        *        the application's asset manager\r
-        * @param endianess\r
-        *        type of byte ordering used; 'v' means little endian and 'V' means big endian\r
-        * @throws BlenderFileException\r
-        *         this exception is thrown if the file header has some invalid data\r
-        */\r
-       public BlenderInputStream(InputStream inputStream, AssetManager assetManager) throws BlenderFileException {\r
-               this.assetManager = assetManager;\r
-               //the size value will canche while reading the file; the available() method cannot be counted on\r
-               try {\r
-                       size = inputStream.available();\r
-               } catch (IOException e) {\r
-                       size = 0;\r
-               }\r
-               if(size <= 0) {\r
-                       size = BlenderInputStream.DEFAULT_BUFFER_SIZE;\r
-               }\r
+    /**\r
+     * Constructor. The input stream is stored and used to read data.\r
+     * @param inputStream\r
+     *        the stream we read data from\r
+     * @param assetManager\r
+     *        the application's asset manager\r
+     * @param endianess\r
+     *        type of byte ordering used; 'v' means little endian and 'V' means big endian\r
+     * @throws BlenderFileException\r
+     *         this exception is thrown if the file header has some invalid data\r
+     */\r
+    public BlenderInputStream(InputStream inputStream, AssetManager assetManager) throws BlenderFileException {\r
+        this.assetManager = assetManager;\r
+        //the size value will canche while reading the file; the available() method cannot be counted on\r
+        try {\r
+            size = inputStream.available();\r
+        } catch (IOException e) {\r
+            size = 0;\r
+        }\r
+        if (size <= 0) {\r
+            size = BlenderInputStream.DEFAULT_BUFFER_SIZE;\r
+        }\r
 \r
-               //buffered input stream is used here for much faster file reading\r
-               BufferedInputStream bufferedInputStream;\r
-               if(inputStream instanceof BufferedInputStream) {\r
-                       bufferedInputStream = (BufferedInputStream)inputStream;\r
-               } else {\r
-                       bufferedInputStream = new BufferedInputStream(inputStream);\r
-               }\r
+        //buffered input stream is used here for much faster file reading\r
+        BufferedInputStream bufferedInputStream;\r
+        if (inputStream instanceof BufferedInputStream) {\r
+            bufferedInputStream = (BufferedInputStream) inputStream;\r
+        } else {\r
+            bufferedInputStream = new BufferedInputStream(inputStream);\r
+        }\r
 \r
-               try {\r
-                       this.readStreamToCache(bufferedInputStream);\r
-               } catch (IOException e) {\r
-                       throw new BlenderFileException("Problems occured while caching the file!", e);\r
-               }\r
+        try {\r
+            this.readStreamToCache(bufferedInputStream);\r
+        } catch (IOException e) {\r
+            throw new BlenderFileException("Problems occured while caching the file!", e);\r
+        }\r
 \r
-               try {\r
-                       this.readFileHeader();\r
-               } catch(BlenderFileException e) {//the file might be packed, don't panic, try one more time ;)\r
-                       this.decompressFile();\r
-                       this.position = 0;\r
-                       this.readFileHeader();\r
-               }\r
-       }\r
+        try {\r
+            this.readFileHeader();\r
+        } catch (BlenderFileException e) {//the file might be packed, don't panic, try one more time ;)\r
+            this.decompressFile();\r
+            this.position = 0;\r
+            this.readFileHeader();\r
+        }\r
+    }\r
 \r
-       /**\r
-        * This method reads the whole stream into a buffer.\r
-        * @param inputStream\r
-        *        the stream to read the file data from\r
-        * @throws IOException \r
-        *                 an exception is thrown when data read from the stream is invalid or there are problems with i/o\r
-        *         operations\r
-        */\r
-       private void readStreamToCache(InputStream inputStream) throws IOException {\r
-               int data = inputStream.read();\r
-               cachedBuffer = new byte[size];\r
-               size = 0;//this will count the actual size\r
-               while(data != -1) {\r
-                       cachedBuffer[size++] = (byte)data;\r
-                       if(size >= cachedBuffer.length) {//widen the cached array\r
-                               byte[] newBuffer = new byte[cachedBuffer.length + (cachedBuffer.length >> 1)];\r
-                               System.arraycopy(cachedBuffer, 0, newBuffer, 0, cachedBuffer.length);\r
-                               cachedBuffer = newBuffer;\r
-                       }\r
-                       data = inputStream.read();\r
-               }\r
-       }\r
+    /**\r
+     * This method reads the whole stream into a buffer.\r
+     * @param inputStream\r
+     *        the stream to read the file data from\r
+     * @throws IOException \r
+     *                    an exception is thrown when data read from the stream is invalid or there are problems with i/o\r
+     *         operations\r
+     */\r
+    private void readStreamToCache(InputStream inputStream) throws IOException {\r
+        int data = inputStream.read();\r
+        cachedBuffer = new byte[size];\r
+        size = 0;//this will count the actual size\r
+        while (data != -1) {\r
+            cachedBuffer[size++] = (byte) data;\r
+            if (size >= cachedBuffer.length) {//widen the cached array\r
+                byte[] newBuffer = new byte[cachedBuffer.length + (cachedBuffer.length >> 1)];\r
+                System.arraycopy(cachedBuffer, 0, newBuffer, 0, cachedBuffer.length);\r
+                cachedBuffer = newBuffer;\r
+            }\r
+            data = inputStream.read();\r
+        }\r
+    }\r
 \r
-       /**\r
-        * This method is used when the blender file is gzipped. It decompresses the data and stores it back into the\r
-        * cachedBuffer field.\r
-        */\r
-       private void decompressFile() {\r
-               GZIPInputStream gis = null;\r
-               try {\r
-                       gis = new GZIPInputStream(new ByteArrayInputStream(cachedBuffer));\r
-                       this.readStreamToCache(gis);\r
-               } catch (IOException e) {\r
-                       throw new IllegalStateException("IO errors occured where they should NOT! " +\r
-                                                                                       "The data is already buffered at this point!", e);\r
-               } finally {\r
-                       try {\r
-                               if(gis!=null) {\r
-                                       gis.close();\r
-                               }\r
-                       } catch(IOException e) {\r
-                               LOGGER.warning(e.getMessage());\r
-                       }\r
-               }\r
-       }\r
+    /**\r
+     * This method is used when the blender file is gzipped. It decompresses the data and stores it back into the\r
+     * cachedBuffer field.\r
+     */\r
+    private void decompressFile() {\r
+        GZIPInputStream gis = null;\r
+        try {\r
+            gis = new GZIPInputStream(new ByteArrayInputStream(cachedBuffer));\r
+            this.readStreamToCache(gis);\r
+        } catch (IOException e) {\r
+            throw new IllegalStateException("IO errors occured where they should NOT! "\r
+                    + "The data is already buffered at this point!", e);\r
+        } finally {\r
+            try {\r
+                if (gis != null) {\r
+                    gis.close();\r
+                }\r
+            } catch (IOException e) {\r
+                LOGGER.warning(e.getMessage());\r
+            }\r
+        }\r
+    }\r
 \r
-       /**\r
-        * This method loads the header from the given stream during instance creation.\r
-        * @param inputStream\r
-        *        the stream we read the header from\r
-        * @throws BlenderFileException\r
-        *         this exception is thrown if the file header has some invalid data\r
-        */\r
-       private void readFileHeader() throws BlenderFileException {\r
-               byte[] identifier = new byte[7];\r
-               int bytesRead = this.readBytes(identifier);\r
-               if(bytesRead != 7) {\r
-                       throw new BlenderFileException("Error reading header identifier. Only " + bytesRead + " bytes read and there should be 7!");\r
-               }\r
-               String strIdentifier = new String(identifier);\r
-               if(!"BLENDER".equals(strIdentifier)) {\r
-                       throw new BlenderFileException("Wrong file identifier: " + strIdentifier + "! Should be 'BLENDER'!");\r
-               }\r
-               char pointerSizeSign = (char)this.readByte();\r
-               if(pointerSizeSign == '-') {\r
-                       pointerSize = 8;\r
-               } else if(pointerSizeSign == '_') {\r
-                       pointerSize = 4;\r
-               } else {\r
-                       throw new BlenderFileException("Invalid pointer size character! Should be '_' or '-' and there is: " + pointerSizeSign);\r
-               }\r
-               endianess = (char)this.readByte();\r
-               if(endianess != 'v' && endianess != 'V') {\r
-                       throw new BlenderFileException("Unknown endianess value! 'v' or 'V' expected and found: " + endianess);\r
-               }\r
-               byte[] versionNumber = new byte[3];\r
-               bytesRead = this.readBytes(versionNumber);\r
-               if(bytesRead != 3) {\r
-                       throw new BlenderFileException("Error reading version numberr. Only " + bytesRead + " bytes read and there should be 3!");\r
-               }\r
-               this.versionNumber = new String(versionNumber);\r
-       }\r
+    /**\r
+     * This method loads the header from the given stream during instance creation.\r
+     * @param inputStream\r
+     *        the stream we read the header from\r
+     * @throws BlenderFileException\r
+     *         this exception is thrown if the file header has some invalid data\r
+     */\r
+    private void readFileHeader() throws BlenderFileException {\r
+        byte[] identifier = new byte[7];\r
+        int bytesRead = this.readBytes(identifier);\r
+        if (bytesRead != 7) {\r
+            throw new BlenderFileException("Error reading header identifier. Only " + bytesRead + " bytes read and there should be 7!");\r
+        }\r
+        String strIdentifier = new String(identifier);\r
+        if (!"BLENDER".equals(strIdentifier)) {\r
+            throw new BlenderFileException("Wrong file identifier: " + strIdentifier + "! Should be 'BLENDER'!");\r
+        }\r
+        char pointerSizeSign = (char) this.readByte();\r
+        if (pointerSizeSign == '-') {\r
+            pointerSize = 8;\r
+        } else if (pointerSizeSign == '_') {\r
+            pointerSize = 4;\r
+        } else {\r
+            throw new BlenderFileException("Invalid pointer size character! Should be '_' or '-' and there is: " + pointerSizeSign);\r
+        }\r
+        endianess = (char) this.readByte();\r
+        if (endianess != 'v' && endianess != 'V') {\r
+            throw new BlenderFileException("Unknown endianess value! 'v' or 'V' expected and found: " + endianess);\r
+        }\r
+        byte[] versionNumber = new byte[3];\r
+        bytesRead = this.readBytes(versionNumber);\r
+        if (bytesRead != 3) {\r
+            throw new BlenderFileException("Error reading version numberr. Only " + bytesRead + " bytes read and there should be 3!");\r
+        }\r
+        this.versionNumber = new String(versionNumber);\r
+    }\r
 \r
-       @Override\r
-       public int read() throws IOException {\r
-               return this.readByte();\r
-       }\r
-       \r
-       /**\r
-        * This method reads 1 byte from the stream.\r
-        * It works just in the way the read method does.\r
-        * It just not throw an exception because at this moment the whole file\r
-        * is loaded into buffer, so no need for IOException to be thrown.\r
-        * @return a byte from the stream (1 bytes read)\r
-        */\r
-       public int readByte() {\r
-               return cachedBuffer[position++] & 0xFF;\r
-       }\r
-       \r
-       /**\r
-        * This method reads a bytes number big enough to fill the table. \r
-        * It does not throw exceptions so it is for internal use only.\r
-        * @param bytes\r
-        *            an array to be filled with data\r
-        * @return number of read bytes (a length of array actually)\r
-        */\r
-       private int readBytes(byte[] bytes) {\r
-               for(int i=0;i<bytes.length;++i) {\r
-                       bytes[i] = (byte) this.readByte();\r
-               }\r
-               return bytes.length;\r
-       }\r
-       \r
-       /**\r
-        * This method reads 2-byte number from the stream.\r
-        * @return a number from the stream (2 bytes read)\r
-        */\r
-       public int readShort() {\r
-               int part1 = this.readByte();\r
-               int part2 = this.readByte();\r
-               if(endianess == 'v') {\r
-                       return (part2 << 8) + part1;\r
-               } else {\r
-                       return (part1 << 8) + part2;\r
-               }\r
-       }\r
+    @Override\r
+    public int read() throws IOException {\r
+        return this.readByte();\r
+    }\r
 \r
-       /**\r
-        * This method reads 4-byte number from the stream.\r
-        * @return a number from the stream (4 bytes read)\r
-        */\r
-       public int readInt() {\r
-               int part1 = this.readByte();\r
-               int part2 = this.readByte();\r
-               int part3 = this.readByte();\r
-               int part4 = this.readByte();\r
-               if(endianess == 'v') {\r
-                       return (part4 << 24) + (part3 << 16) + (part2 << 8) + part1;\r
-               } else {\r
-                       return (part1 << 24) + (part2 << 16) + (part3 << 8) + part4;\r
-               }\r
-       }\r
+    /**\r
+     * This method reads 1 byte from the stream.\r
+     * It works just in the way the read method does.\r
+     * It just not throw an exception because at this moment the whole file\r
+     * is loaded into buffer, so no need for IOException to be thrown.\r
+     * @return a byte from the stream (1 bytes read)\r
+     */\r
+    public int readByte() {\r
+        return cachedBuffer[position++] & 0xFF;\r
+    }\r
 \r
-       /**\r
-        * This method reads 4-byte floating point number (float) from the stream.\r
-        * @return a number from the stream (4 bytes read)\r
-        */\r
-       public float readFloat() {\r
-               int intValue = this.readInt();\r
-               return Float.intBitsToFloat(intValue);\r
-       }\r
+    /**\r
+     * This method reads a bytes number big enough to fill the table. \r
+     * It does not throw exceptions so it is for internal use only.\r
+     * @param bytes\r
+     *            an array to be filled with data\r
+     * @return number of read bytes (a length of array actually)\r
+     */\r
+    private int readBytes(byte[] bytes) {\r
+        for (int i = 0; i < bytes.length; ++i) {\r
+            bytes[i] = (byte) this.readByte();\r
+        }\r
+        return bytes.length;\r
+    }\r
 \r
-       /**\r
-        * This method reads 8-byte number from the stream.\r
-        * @return a number from the stream (8 bytes read)\r
-        */\r
-       public long readLong() {\r
-               long part1 = this.readInt();\r
-               long part2 = this.readInt();\r
-               long result = -1;\r
-               if(endianess == 'v') {\r
-                       result = part2 << 32 | part1;\r
-               } else {\r
-                       result = part1 << 32 | part2;\r
-               }\r
-               return result;\r
-       }\r
+    /**\r
+     * This method reads 2-byte number from the stream.\r
+     * @return a number from the stream (2 bytes read)\r
+     */\r
+    public int readShort() {\r
+        int part1 = this.readByte();\r
+        int part2 = this.readByte();\r
+        if (endianess == 'v') {\r
+            return (part2 << 8) + part1;\r
+        } else {\r
+            return (part1 << 8) + part2;\r
+        }\r
+    }\r
 \r
-       /**\r
-        * This method reads 8-byte floating point number (double) from the stream.\r
-        * @return a number from the stream (8 bytes read)\r
-        */\r
-       public double readDouble() {\r
-               long longValue = this.readLong();\r
-               return Double.longBitsToDouble(longValue);\r
-       }\r
+    /**\r
+     * This method reads 4-byte number from the stream.\r
+     * @return a number from the stream (4 bytes read)\r
+     */\r
+    public int readInt() {\r
+        int part1 = this.readByte();\r
+        int part2 = this.readByte();\r
+        int part3 = this.readByte();\r
+        int part4 = this.readByte();\r
+        if (endianess == 'v') {\r
+            return (part4 << 24) + (part3 << 16) + (part2 << 8) + part1;\r
+        } else {\r
+            return (part1 << 24) + (part2 << 16) + (part3 << 8) + part4;\r
+        }\r
+    }\r
 \r
-       /**\r
-        * This method reads the pointer value. Depending on the pointer size defined in the header, the stream reads either\r
-        * 4 or 8 bytes of data.\r
-        * @return the pointer value\r
-        */\r
-       public long readPointer() {\r
-               if(pointerSize == 4) {\r
-                       return this.readInt();\r
-               }\r
-               return this.readLong();\r
-       }\r
+    /**\r
+     * This method reads 4-byte floating point number (float) from the stream.\r
+     * @return a number from the stream (4 bytes read)\r
+     */\r
+    public float readFloat() {\r
+        int intValue = this.readInt();\r
+        return Float.intBitsToFloat(intValue);\r
+    }\r
 \r
-       /**\r
-        * This method reads the string. It assumes the string is terminated with zero in the stream.\r
-        * @return the string read from the stream\r
-        */\r
-       public String readString() {\r
-               StringBuilder stringBuilder = new StringBuilder();\r
-               int data = this.readByte();\r
-               while(data != 0) {\r
-                       stringBuilder.append((char)data);\r
-                       data = this.readByte();\r
-               }\r
-               return stringBuilder.toString();\r
-       }\r
+    /**\r
+     * This method reads 8-byte number from the stream.\r
+     * @return a number from the stream (8 bytes read)\r
+     */\r
+    public long readLong() {\r
+        long part1 = this.readInt();\r
+        long part2 = this.readInt();\r
+        long result = -1;\r
+        if (endianess == 'v') {\r
+            result = part2 << 32 | part1;\r
+        } else {\r
+            result = part1 << 32 | part2;\r
+        }\r
+        return result;\r
+    }\r
 \r
-       /**\r
-        * This method sets the current position of the read cursor.\r
-        * @param position\r
-        *        the position of the read cursor\r
-        */\r
-       public void setPosition(int position) {\r
-               this.position = position;\r
-       }\r
+    /**\r
+     * This method reads 8-byte floating point number (double) from the stream.\r
+     * @return a number from the stream (8 bytes read)\r
+     */\r
+    public double readDouble() {\r
+        long longValue = this.readLong();\r
+        return Double.longBitsToDouble(longValue);\r
+    }\r
 \r
-       /**\r
-        * This method returns the position of the read cursor.\r
-        * @return the position of the read cursor\r
-        */\r
-       public int getPosition() {\r
-               return position;\r
-       }\r
+    /**\r
+     * This method reads the pointer value. Depending on the pointer size defined in the header, the stream reads either\r
+     * 4 or 8 bytes of data.\r
+     * @return the pointer value\r
+     */\r
+    public long readPointer() {\r
+        if (pointerSize == 4) {\r
+            return this.readInt();\r
+        }\r
+        return this.readLong();\r
+    }\r
 \r
-       /**\r
-        * This method returns the blender version number where the file was created.\r
-        * @return blender version number\r
-        */\r
-       public String getVersionNumber() {\r
-               return versionNumber;\r
-       }\r
+    /**\r
+     * This method reads the string. It assumes the string is terminated with zero in the stream.\r
+     * @return the string read from the stream\r
+     */\r
+    public String readString() {\r
+        StringBuilder stringBuilder = new StringBuilder();\r
+        int data = this.readByte();\r
+        while (data != 0) {\r
+            stringBuilder.append((char) data);\r
+            data = this.readByte();\r
+        }\r
+        return stringBuilder.toString();\r
+    }\r
 \r
-       /**\r
-        * This method returns the size of the pointer.\r
-        * @return the size of the pointer\r
-        */\r
-       public int getPointerSize() {\r
-               return pointerSize;\r
-       }\r
+    /**\r
+     * This method sets the current position of the read cursor.\r
+     * @param position\r
+     *        the position of the read cursor\r
+     */\r
+    public void setPosition(int position) {\r
+        this.position = position;\r
+    }\r
 \r
-       /**\r
-        * This method returns the application's asset manager.\r
-        * @return the application's asset manager\r
-        */\r
-       public AssetManager getAssetManager() {\r
-               return assetManager;\r
-       }\r
+    /**\r
+     * This method returns the position of the read cursor.\r
+     * @return the position of the read cursor\r
+     */\r
+    public int getPosition() {\r
+        return position;\r
+    }\r
 \r
-       /**\r
-        * This method aligns cursor position forward to a given amount of bytes.\r
-        * @param bytesAmount\r
-        *        the byte amount to which we aligh the cursor\r
-        */\r
-       public void alignPosition(int bytesAmount) {\r
-               if(bytesAmount <= 0) {\r
-                       throw new IllegalArgumentException("Alignment byte number shoulf be positivbe!");\r
-               }\r
-               long move = position % bytesAmount;\r
-               if(move > 0) {\r
-                       position += bytesAmount - move;\r
-               }\r
-       }\r
+    /**\r
+     * This method returns the blender version number where the file was created.\r
+     * @return blender version number\r
+     */\r
+    public String getVersionNumber() {\r
+        return versionNumber;\r
+    }\r
 \r
-       @Override\r
-       public void close() throws IOException {\r
+    /**\r
+     * This method returns the size of the pointer.\r
+     * @return the size of the pointer\r
+     */\r
+    public int getPointerSize() {\r
+        return pointerSize;\r
+    }\r
+\r
+    /**\r
+     * This method returns the application's asset manager.\r
+     * @return the application's asset manager\r
+     */\r
+    public AssetManager getAssetManager() {\r
+        return assetManager;\r
+    }\r
+\r
+    /**\r
+     * This method aligns cursor position forward to a given amount of bytes.\r
+     * @param bytesAmount\r
+     *        the byte amount to which we aligh the cursor\r
+     */\r
+    public void alignPosition(int bytesAmount) {\r
+        if (bytesAmount <= 0) {\r
+            throw new IllegalArgumentException("Alignment byte number shoulf be positivbe!");\r
+        }\r
+        long move = position % bytesAmount;\r
+        if (move > 0) {\r
+            position += bytesAmount - move;\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public void close() throws IOException {\r
 //             cachedBuffer = null;\r
 //             size = position = 0;\r
-       }\r
+    }\r
 }\r
index 83fefab..31db11f 100644 (file)
@@ -54,347 +54,347 @@ import com.jme3.scene.plugins.blender.structures.Modifier;
  * @author Marcin Roguski\r
  */\r
 public class DataRepository {\r
-       /** The blender key. */\r
-       private BlenderKey                                                              blenderKey;\r
-       /** The header of the file block. */\r
-       private DnaBlockData                                                    dnaBlockData;\r
-       /** The input stream of the blend file. */\r
-       private BlenderInputStream                                              inputStream;\r
-       /** The asset manager. */\r
-       private AssetManager                                                    assetManager;\r
-       /** A map containing the file block headers. The key is the old pointer address. */\r
-       private Map<Long, FileBlockHeader>                              fileBlockHeadersByOma   = new HashMap<Long, FileBlockHeader>();\r
-       /** A map containing the file block headers. The key is the block code. */\r
-       private Map<Integer, List<FileBlockHeader>>             fileBlockHeadersByCode  = new HashMap<Integer, List<FileBlockHeader>>();\r
-       /**\r
-        * This map stores the loaded features by their old memory address. The first object in the value table is the\r
-        * loaded structure and the second - the structure already converted into proper data.\r
-        */\r
-       private Map<Long, Object[]>                                             loadedFeatures                  = new HashMap<Long, Object[]>();\r
-       /**\r
-        * This map stores the loaded features by their name. Only features with ID structure can be stored here.\r
-        * The first object in the value table is the\r
-        * loaded structure and the second - the structure already converted into proper data.\r
-        */\r
-       private Map<String, Object[]>                                   loadedFeaturesByName    = new HashMap<String, Object[]>();\r
-       /** A stack that hold the parent structure of currently loaded feature. */\r
-       private Stack<Structure>                                                parentStack                             = new Stack<Structure>();\r
-       /** A map storing loaded ipos. The key is the ipo's owner old memory address and the value is the ipo. */\r
-       private Map<Long, Ipo>                                                  loadedIpos                              = new HashMap<Long, Ipo>();\r
-       /** A list of modifiers for the specified object. */\r
-       protected Map<Long, List<Modifier>>                             modifiers                               = new HashMap<Long, List<Modifier>>();\r
-       /** A map og helpers that perform loading. */\r
-       private Map<String, AbstractBlenderHelper>              helpers                                 = new HashMap<String, AbstractBlenderHelper>();\r
-       \r
-       /**\r
-        * This method sets the blender key.\r
-        * @param blenderKey\r
-        *                the blender key\r
-        */\r
-       public void setBlenderKey(BlenderKey blenderKey) {\r
-               this.blenderKey = blenderKey;\r
-       }\r
-       \r
-       /**\r
-        * This method returns the blender key.\r
-        * @return the blender key\r
-        */\r
-       public BlenderKey getBlenderKey() {\r
-               return blenderKey;\r
-       }\r
-       \r
-       /**\r
-        * This method sets the dna block data.\r
-        * @param dnaBlockData\r
-        *        the dna block data\r
-        */\r
-       public void setBlockData(DnaBlockData dnaBlockData) {\r
-               this.dnaBlockData = dnaBlockData;\r
-       }\r
-\r
-       /**\r
-        * This method returns the dna block data.\r
-        * @return the dna block data\r
-        */\r
-       public DnaBlockData getDnaBlockData() {\r
-               return dnaBlockData;\r
-       }\r
-\r
-       /**\r
-        * This method returns the asset manager.\r
-        * @return the asset manager\r
-        */\r
-       public AssetManager getAssetManager() {\r
-               return assetManager;\r
-       }\r
-\r
-       /**\r
-        * This method sets the asset manager.\r
-        * @param assetManager\r
-        *        the asset manager\r
-        */\r
-       public void setAssetManager(AssetManager assetManager) {\r
-               this.assetManager = assetManager;\r
-       }\r
-       \r
-       /**\r
-        * This method returns the input stream of the blend file.\r
-        * @return the input stream of the blend file\r
-        */\r
-       public BlenderInputStream getInputStream() {\r
-               return inputStream;\r
-       }\r
-\r
-       /**\r
-        * This method sets the input stream of the blend file.\r
-        * @param inputStream\r
-        *        the input stream of the blend file\r
-        */\r
-       public void setInputStream(BlenderInputStream inputStream) {\r
-               this.inputStream = inputStream;\r
-       }\r
-\r
-       /**\r
-        * This method adds a file block header to the map. Its old memory address is the key.\r
-        * @param oldMemoryAddress\r
-        *        the address of the block header\r
-        * @param fileBlockHeader\r
-        *        the block header to store\r
-        */\r
-       public void addFileBlockHeader(Long oldMemoryAddress, FileBlockHeader fileBlockHeader) {\r
-               fileBlockHeadersByOma.put(oldMemoryAddress, fileBlockHeader);\r
-               List<FileBlockHeader> headers = fileBlockHeadersByCode.get(Integer.valueOf(fileBlockHeader.getCode()));\r
-               if(headers == null) {\r
-                       headers = new ArrayList<FileBlockHeader>();\r
-                       fileBlockHeadersByCode.put(Integer.valueOf(fileBlockHeader.getCode()), headers);\r
-               }\r
-               headers.add(fileBlockHeader);\r
-       }\r
-\r
-       /**\r
-        * This method returns the block header of a given memory address. If the header is not present then null is\r
-        * returned.\r
-        * @param oldMemoryAddress\r
-        *        the address of the block header\r
-        * @return loaded header or null if it was not yet loaded\r
-        */\r
-       public FileBlockHeader getFileBlock(Long oldMemoryAddress) {\r
-               return fileBlockHeadersByOma.get(oldMemoryAddress);\r
-       }\r
-\r
-       /**\r
-        * This method returns a list of file blocks' headers of a specified code.\r
-        * @param code\r
-        *        the code of file blocks\r
-        * @return a list of file blocks' headers of a specified code\r
-        */\r
-       public List<FileBlockHeader> getFileBlocks(Integer code) {\r
-               return fileBlockHeadersByCode.get(code);\r
-       }\r
-\r
-       /**\r
-        * This method clears the saved block headers stored in the features map.\r
-        */\r
-       public void clearFileBlocks() {\r
-               fileBlockHeadersByOma.clear();\r
-               fileBlockHeadersByCode.clear();\r
-       }\r
-\r
-       /**\r
-        * This method adds a helper instance to the helpers' map.\r
-        * @param <T>\r
-        *        the type of the helper\r
-        * @param clazz\r
-        *        helper's class definition\r
-        * @param helper\r
-        *        the helper instance\r
-        */\r
-       public <T> void putHelper(Class<T> clazz, AbstractBlenderHelper helper) {\r
-               helpers.put(clazz.getSimpleName(), helper);\r
-       }\r
-\r
-       @SuppressWarnings("unchecked")\r
-       public <T> T getHelper(Class<?> clazz) {\r
-               return (T)helpers.get(clazz.getSimpleName());\r
-       }\r
-       \r
-\r
-       /**\r
-        * This method adds a loaded feature to the map. The key is its unique old memory address.\r
-        * @param oldMemoryAddress\r
-        *        the address of the feature\r
-        * @param featureName the name of the feature\r
-        * @param structure\r
-        *        the filled structure of the feature\r
-        * @param feature\r
-        *        the feature we want to store\r
-        */\r
-       public void addLoadedFeatures(Long oldMemoryAddress, String featureName, Structure structure, Object feature) {\r
-               if(oldMemoryAddress == null || structure == null || feature == null) {\r
-                       throw new IllegalArgumentException("One of the given arguments is null!");\r
-               }\r
-               Object[] storedData = new Object[] {structure, feature};\r
-               loadedFeatures.put(oldMemoryAddress, storedData);\r
-               if(featureName!=null) {\r
-                       loadedFeaturesByName.put(featureName, storedData);\r
-               }\r
-       }\r
-\r
-       /**\r
-        * This method returns the feature of a given memory address. If the feature is not yet loaded then null is\r
-        * returned.\r
-        * @param oldMemoryAddress\r
-        *        the address of the feature\r
-        * @param loadedFeatureDataType\r
-        *        the type of data we want to retreive it can be either filled structure or already converted feature\r
-        * @return loaded feature or null if it was not yet loaded\r
-        */\r
-       public Object getLoadedFeature(Long oldMemoryAddress, LoadedFeatureDataType loadedFeatureDataType) {\r
-               Object[] result = loadedFeatures.get(oldMemoryAddress);\r
-               if(result != null) {\r
-                       return result[loadedFeatureDataType.getIndex()];\r
-               }\r
-               return null;\r
-       }\r
-       \r
-       /**\r
-        * This method returns the feature of a given name. If the feature is not yet loaded then null is\r
-        * returned.\r
-        * @param featureName\r
-        *        the name of the feature\r
-        * @param loadedFeatureDataType\r
-        *        the type of data we want to retreive it can be either filled structure or already converted feature\r
-        * @return loaded feature or null if it was not yet loaded\r
-        */\r
-       public Object getLoadedFeature(String featureName, LoadedFeatureDataType loadedFeatureDataType) {\r
-               Object[] result = loadedFeaturesByName.get(featureName);\r
-               if(result != null) {\r
-                       return result[loadedFeatureDataType.getIndex()];\r
-               }\r
-               return null;\r
-       }\r
-\r
-       /**\r
-        * This method clears the saved features stored in the features map.\r
-        */\r
-       public void clearLoadedFeatures() {\r
-               loadedFeatures.clear();\r
-       }\r
-\r
-       /**\r
-        * This method adds the structure to the parent stack.\r
-        * @param parent\r
-        *        the structure to be added to the stack\r
-        */\r
-       public void pushParent(Structure parent) {\r
-               parentStack.push(parent);\r
-       }\r
-\r
-       /**\r
-        * This method removes the structure from the top of the parent's stack.\r
-        * @return the structure that was removed from the stack\r
-        */\r
-       public Structure popParent() {\r
-               try {\r
-                       return parentStack.pop();\r
-               } catch(EmptyStackException e) {\r
-                       return null;\r
-               }\r
-       }\r
-\r
-       /**\r
-        * This method retreives the structure at the top of the parent's stack but does not remove it.\r
-        * @return the structure from the top of the stack\r
-        */\r
-       public Structure peekParent() {\r
-               try {\r
-                       return parentStack.peek();\r
-               } catch(EmptyStackException e) {\r
-                       return null;\r
-               }\r
-       }\r
-\r
-       public void addIpo(Long ownerOMA, Ipo ipo) {\r
-               loadedIpos.put(ownerOMA, ipo);\r
-       }\r
-       \r
-       public Ipo removeIpo(Long ownerOma) {\r
-               return loadedIpos.remove(ownerOma);\r
-       }\r
-       \r
-       public Ipo getIpo(Long ownerOMA) {\r
-               return loadedIpos.get(ownerOMA);\r
-       }\r
-       \r
-       /**\r
-        * This method adds a new modifier to the list.\r
-        * @param ownerOMA\r
-        *        the owner's old memory address\r
-        * @param modifierType\r
-        *        the type of the modifier\r
-        * @param loadedModifier\r
-        *        the loaded modifier object\r
-        */\r
-       public void addModifier(Long ownerOMA, String modifierType, Object loadedModifier, Object additionalModifierData) {\r
-               List<Modifier> objectModifiers = this.modifiers.get(ownerOMA);\r
-               if(objectModifiers == null) {\r
-                       objectModifiers = new ArrayList<Modifier>();\r
-                       this.modifiers.put(ownerOMA, objectModifiers);\r
-               }\r
-               objectModifiers.add(new Modifier(modifierType, loadedModifier, additionalModifierData));\r
-       }\r
-       \r
-       /**\r
-        * This method returns modifiers for the object specified by its old memory address and the modifier type. If no\r
-        * modifiers are found - empty list is returned. If the type is null - all modifiers for the object are returned.\r
-        * @param objectOMA\r
-        *        object's old memory address\r
-        * @param type\r
-        *        the type of the modifier\r
-        * @return the list of object's modifiers\r
-        */\r
-       public List<Modifier> getModifiers(Long objectOMA, String type) {\r
-               List<Modifier> result = new ArrayList<Modifier>();\r
-               List<Modifier> readModifiers = modifiers.get(objectOMA);\r
-               if(readModifiers != null && readModifiers.size() > 0) {\r
-                       for(Modifier modifier : readModifiers) {\r
-                               if(type==null || type.isEmpty() || modifier.getType().equals(type)) {\r
-                                       result.add(modifier);\r
-                               }\r
-                       }\r
-               }\r
-               return result;\r
-       }\r
-       \r
-       /**\r
-        * This metod returns the default material.\r
-        * @return the default material\r
-        */\r
-       public synchronized Material getDefaultMaterial() {\r
-               if(blenderKey.getDefaultMaterial() == null) {\r
-                       Material defaultMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");\r
-                       defaultMaterial.setColor("Color", ColorRGBA.DarkGray);\r
-                       blenderKey.setDefaultMaterial(defaultMaterial);\r
-               }\r
-               return blenderKey.getDefaultMaterial();\r
-       }\r
-\r
-       /**\r
-        * This enum defines what loaded data type user wants to retreive. It can be either filled structure or already\r
-        * converted data.\r
-        * @author Marcin Roguski\r
-        */\r
-       public static enum LoadedFeatureDataType {\r
-               LOADED_STRUCTURE(0), LOADED_FEATURE(1);\r
-\r
-               private int     index;\r
-\r
-               private LoadedFeatureDataType(int index) {\r
-                       this.index = index;\r
-               }\r
-\r
-               public int getIndex() {\r
-                       return index;\r
-               }\r
-       }\r
+\r
+    /** The blender key. */\r
+    private BlenderKey blenderKey;\r
+    /** The header of the file block. */\r
+    private DnaBlockData dnaBlockData;\r
+    /** The input stream of the blend file. */\r
+    private BlenderInputStream inputStream;\r
+    /** The asset manager. */\r
+    private AssetManager assetManager;\r
+    /** A map containing the file block headers. The key is the old pointer address. */\r
+    private Map<Long, FileBlockHeader> fileBlockHeadersByOma = new HashMap<Long, FileBlockHeader>();\r
+    /** A map containing the file block headers. The key is the block code. */\r
+    private Map<Integer, List<FileBlockHeader>> fileBlockHeadersByCode = new HashMap<Integer, List<FileBlockHeader>>();\r
+    /**\r
+     * This map stores the loaded features by their old memory address. The first object in the value table is the\r
+     * loaded structure and the second - the structure already converted into proper data.\r
+     */\r
+    private Map<Long, Object[]> loadedFeatures = new HashMap<Long, Object[]>();\r
+    /**\r
+     * This map stores the loaded features by their name. Only features with ID structure can be stored here.\r
+     * The first object in the value table is the\r
+     * loaded structure and the second - the structure already converted into proper data.\r
+     */\r
+    private Map<String, Object[]> loadedFeaturesByName = new HashMap<String, Object[]>();\r
+    /** A stack that hold the parent structure of currently loaded feature. */\r
+    private Stack<Structure> parentStack = new Stack<Structure>();\r
+    /** A map storing loaded ipos. The key is the ipo's owner old memory address and the value is the ipo. */\r
+    private Map<Long, Ipo> loadedIpos = new HashMap<Long, Ipo>();\r
+    /** A list of modifiers for the specified object. */\r
+    protected Map<Long, List<Modifier>> modifiers = new HashMap<Long, List<Modifier>>();\r
+    /** A map og helpers that perform loading. */\r
+    private Map<String, AbstractBlenderHelper> helpers = new HashMap<String, AbstractBlenderHelper>();\r
+\r
+    /**\r
+     * This method sets the blender key.\r
+     * @param blenderKey\r
+     *                   the blender key\r
+     */\r
+    public void setBlenderKey(BlenderKey blenderKey) {\r
+        this.blenderKey = blenderKey;\r
+    }\r
+\r
+    /**\r
+     * This method returns the blender key.\r
+     * @return the blender key\r
+     */\r
+    public BlenderKey getBlenderKey() {\r
+        return blenderKey;\r
+    }\r
+\r
+    /**\r
+     * This method sets the dna block data.\r
+     * @param dnaBlockData\r
+     *        the dna block data\r
+     */\r
+    public void setBlockData(DnaBlockData dnaBlockData) {\r
+        this.dnaBlockData = dnaBlockData;\r
+    }\r
+\r
+    /**\r
+     * This method returns the dna block data.\r
+     * @return the dna block data\r
+     */\r
+    public DnaBlockData getDnaBlockData() {\r
+        return dnaBlockData;\r
+    }\r
+\r
+    /**\r
+     * This method returns the asset manager.\r
+     * @return the asset manager\r
+     */\r
+    public AssetManager getAssetManager() {\r
+        return assetManager;\r
+    }\r
+\r
+    /**\r
+     * This method sets the asset manager.\r
+     * @param assetManager\r
+     *        the asset manager\r
+     */\r
+    public void setAssetManager(AssetManager assetManager) {\r
+        this.assetManager = assetManager;\r
+    }\r
+\r
+    /**\r
+     * This method returns the input stream of the blend file.\r
+     * @return the input stream of the blend file\r
+     */\r
+    public BlenderInputStream getInputStream() {\r
+        return inputStream;\r
+    }\r
+\r
+    /**\r
+     * This method sets the input stream of the blend file.\r
+     * @param inputStream\r
+     *        the input stream of the blend file\r
+     */\r
+    public void setInputStream(BlenderInputStream inputStream) {\r
+        this.inputStream = inputStream;\r
+    }\r
+\r
+    /**\r
+     * This method adds a file block header to the map. Its old memory address is the key.\r
+     * @param oldMemoryAddress\r
+     *        the address of the block header\r
+     * @param fileBlockHeader\r
+     *        the block header to store\r
+     */\r
+    public void addFileBlockHeader(Long oldMemoryAddress, FileBlockHeader fileBlockHeader) {\r
+        fileBlockHeadersByOma.put(oldMemoryAddress, fileBlockHeader);\r
+        List<FileBlockHeader> headers = fileBlockHeadersByCode.get(Integer.valueOf(fileBlockHeader.getCode()));\r
+        if (headers == null) {\r
+            headers = new ArrayList<FileBlockHeader>();\r
+            fileBlockHeadersByCode.put(Integer.valueOf(fileBlockHeader.getCode()), headers);\r
+        }\r
+        headers.add(fileBlockHeader);\r
+    }\r
+\r
+    /**\r
+     * This method returns the block header of a given memory address. If the header is not present then null is\r
+     * returned.\r
+     * @param oldMemoryAddress\r
+     *        the address of the block header\r
+     * @return loaded header or null if it was not yet loaded\r
+     */\r
+    public FileBlockHeader getFileBlock(Long oldMemoryAddress) {\r
+        return fileBlockHeadersByOma.get(oldMemoryAddress);\r
+    }\r
+\r
+    /**\r
+     * This method returns a list of file blocks' headers of a specified code.\r
+     * @param code\r
+     *        the code of file blocks\r
+     * @return a list of file blocks' headers of a specified code\r
+     */\r
+    public List<FileBlockHeader> getFileBlocks(Integer code) {\r
+        return fileBlockHeadersByCode.get(code);\r
+    }\r
+\r
+    /**\r
+     * This method clears the saved block headers stored in the features map.\r
+     */\r
+    public void clearFileBlocks() {\r
+        fileBlockHeadersByOma.clear();\r
+        fileBlockHeadersByCode.clear();\r
+    }\r
+\r
+    /**\r
+     * This method adds a helper instance to the helpers' map.\r
+     * @param <T>\r
+     *        the type of the helper\r
+     * @param clazz\r
+     *        helper's class definition\r
+     * @param helper\r
+     *        the helper instance\r
+     */\r
+    public <T> void putHelper(Class<T> clazz, AbstractBlenderHelper helper) {\r
+        helpers.put(clazz.getSimpleName(), helper);\r
+    }\r
+\r
+    @SuppressWarnings("unchecked")\r
+    public <T> T getHelper(Class<?> clazz) {\r
+        return (T) helpers.get(clazz.getSimpleName());\r
+    }\r
+\r
+    /**\r
+     * This method adds a loaded feature to the map. The key is its unique old memory address.\r
+     * @param oldMemoryAddress\r
+     *        the address of the feature\r
+     * @param featureName the name of the feature\r
+     * @param structure\r
+     *        the filled structure of the feature\r
+     * @param feature\r
+     *        the feature we want to store\r
+     */\r
+    public void addLoadedFeatures(Long oldMemoryAddress, String featureName, Structure structure, Object feature) {\r
+        if (oldMemoryAddress == null || structure == null || feature == null) {\r
+            throw new IllegalArgumentException("One of the given arguments is null!");\r
+        }\r
+        Object[] storedData = new Object[]{structure, feature};\r
+        loadedFeatures.put(oldMemoryAddress, storedData);\r
+        if (featureName != null) {\r
+            loadedFeaturesByName.put(featureName, storedData);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * This method returns the feature of a given memory address. If the feature is not yet loaded then null is\r
+     * returned.\r
+     * @param oldMemoryAddress\r
+     *        the address of the feature\r
+     * @param loadedFeatureDataType\r
+     *        the type of data we want to retreive it can be either filled structure or already converted feature\r
+     * @return loaded feature or null if it was not yet loaded\r
+     */\r
+    public Object getLoadedFeature(Long oldMemoryAddress, LoadedFeatureDataType loadedFeatureDataType) {\r
+        Object[] result = loadedFeatures.get(oldMemoryAddress);\r
+        if (result != null) {\r
+            return result[loadedFeatureDataType.getIndex()];\r
+        }\r
+        return null;\r
+    }\r
+\r
+    /**\r
+     * This method returns the feature of a given name. If the feature is not yet loaded then null is\r
+     * returned.\r
+     * @param featureName\r
+     *        the name of the feature\r
+     * @param loadedFeatureDataType\r
+     *        the type of data we want to retreive it can be either filled structure or already converted feature\r
+     * @return loaded feature or null if it was not yet loaded\r
+     */\r
+    public Object getLoadedFeature(String featureName, LoadedFeatureDataType loadedFeatureDataType) {\r
+        Object[] result = loadedFeaturesByName.get(featureName);\r
+        if (result != null) {\r
+            return result[loadedFeatureDataType.getIndex()];\r
+        }\r
+        return null;\r
+    }\r
+\r
+    /**\r
+     * This method clears the saved features stored in the features map.\r
+     */\r
+    public void clearLoadedFeatures() {\r
+        loadedFeatures.clear();\r
+    }\r
+\r
+    /**\r
+     * This method adds the structure to the parent stack.\r
+     * @param parent\r
+     *        the structure to be added to the stack\r
+     */\r
+    public void pushParent(Structure parent) {\r
+        parentStack.push(parent);\r
+    }\r
+\r
+    /**\r
+     * This method removes the structure from the top of the parent's stack.\r
+     * @return the structure that was removed from the stack\r
+     */\r
+    public Structure popParent() {\r
+        try {\r
+            return parentStack.pop();\r
+        } catch (EmptyStackException e) {\r
+            return null;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * This method retreives the structure at the top of the parent's stack but does not remove it.\r
+     * @return the structure from the top of the stack\r
+     */\r
+    public Structure peekParent() {\r
+        try {\r
+            return parentStack.peek();\r
+        } catch (EmptyStackException e) {\r
+            return null;\r
+        }\r
+    }\r
+\r
+    public void addIpo(Long ownerOMA, Ipo ipo) {\r
+        loadedIpos.put(ownerOMA, ipo);\r
+    }\r
+\r
+    public Ipo removeIpo(Long ownerOma) {\r
+        return loadedIpos.remove(ownerOma);\r
+    }\r
+\r
+    public Ipo getIpo(Long ownerOMA) {\r
+        return loadedIpos.get(ownerOMA);\r
+    }\r
+\r
+    /**\r
+     * This method adds a new modifier to the list.\r
+     * @param ownerOMA\r
+     *        the owner's old memory address\r
+     * @param modifierType\r
+     *        the type of the modifier\r
+     * @param loadedModifier\r
+     *        the loaded modifier object\r
+     */\r
+    public void addModifier(Long ownerOMA, String modifierType, Object loadedModifier, Object additionalModifierData) {\r
+        List<Modifier> objectModifiers = this.modifiers.get(ownerOMA);\r
+        if (objectModifiers == null) {\r
+            objectModifiers = new ArrayList<Modifier>();\r
+            this.modifiers.put(ownerOMA, objectModifiers);\r
+        }\r
+        objectModifiers.add(new Modifier(modifierType, loadedModifier, additionalModifierData));\r
+    }\r
+\r
+    /**\r
+     * This method returns modifiers for the object specified by its old memory address and the modifier type. If no\r
+     * modifiers are found - empty list is returned. If the type is null - all modifiers for the object are returned.\r
+     * @param objectOMA\r
+     *        object's old memory address\r
+     * @param type\r
+     *        the type of the modifier\r
+     * @return the list of object's modifiers\r
+     */\r
+    public List<Modifier> getModifiers(Long objectOMA, String type) {\r
+        List<Modifier> result = new ArrayList<Modifier>();\r
+        List<Modifier> readModifiers = modifiers.get(objectOMA);\r
+        if (readModifiers != null && readModifiers.size() > 0) {\r
+            for (Modifier modifier : readModifiers) {\r
+                if (type == null || type.isEmpty() || modifier.getType().equals(type)) {\r
+                    result.add(modifier);\r
+                }\r
+            }\r
+        }\r
+        return result;\r
+    }\r
+\r
+    /**\r
+     * This metod returns the default material.\r
+     * @return the default material\r
+     */\r
+    public synchronized Material getDefaultMaterial() {\r
+        if (blenderKey.getDefaultMaterial() == null) {\r
+            Material defaultMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");\r
+            defaultMaterial.setColor("Color", ColorRGBA.DarkGray);\r
+            blenderKey.setDefaultMaterial(defaultMaterial);\r
+        }\r
+        return blenderKey.getDefaultMaterial();\r
+    }\r
+\r
+    /**\r
+     * This enum defines what loaded data type user wants to retreive. It can be either filled structure or already\r
+     * converted data.\r
+     * @author Marcin Roguski\r
+     */\r
+    public static enum LoadedFeatureDataType {\r
+\r
+        LOADED_STRUCTURE(0), LOADED_FEATURE(1);\r
+        private int index;\r
+\r
+        private LoadedFeatureDataType(int index) {\r
+            this.index = index;\r
+        }\r
+\r
+        public int getIndex() {\r
+            return index;\r
+        }\r
+    }\r
 }\r
index 845a434..20ed7e3 100644 (file)
@@ -40,117 +40,118 @@ import com.jme3.scene.plugins.blender.exception.BlenderFileException;
  *        the type of stored data in the array\r
  */\r
 public class DynamicArray<T> implements Cloneable {\r
-       /** An array object that holds the required data. */\r
-       private T[]             array;\r
-       /**\r
-        * This table holds the sizes of dimetions of the dynamic table. It's length specifies the table dimension or a\r
-        * pointer level. For example: if tableSizes.length == 3 then it either specifies a dynamic table of fixed lengths:\r
-        * dynTable[a][b][c], where a,b,c are stored in the tableSizes table.\r
-        */\r
-       private int[]   tableSizes;\r
 \r
-       /**\r
-        * Constructor. Builds an empty array of the specified sizes.\r
-        * @param tableSizes\r
-        *        the sizes of the table\r
-        * @throws BlenderFileException\r
-        *         an exception is thrown if one of the sizes is not a positive number\r
-        */\r
-       @SuppressWarnings("unchecked")\r
-       public DynamicArray(int[] tableSizes) throws BlenderFileException {\r
-               this.tableSizes = tableSizes;\r
-               int totalSize = 1;\r
-               for(int size : tableSizes) {\r
-                       if(size <= 0) {\r
-                               throw new BlenderFileException("The size of the table must be positive!");\r
-                       }\r
-                       totalSize *= size;\r
-               }\r
-               this.array = (T[])new Object[totalSize];\r
-       }\r
+    /** An array object that holds the required data. */\r
+    private T[] array;\r
+    /**\r
+     * This table holds the sizes of dimetions of the dynamic table. It's length specifies the table dimension or a\r
+     * pointer level. For example: if tableSizes.length == 3 then it either specifies a dynamic table of fixed lengths:\r
+     * dynTable[a][b][c], where a,b,c are stored in the tableSizes table.\r
+     */\r
+    private int[] tableSizes;\r
 \r
-       /**\r
-        * Constructor. Builds an empty array of the specified sizes.\r
-        * @param tableSizes\r
-        *        the sizes of the table\r
-        * @throws BlenderFileException\r
-        *         an exception is thrown if one of the sizes is not a positive number\r
-        */\r
-       public DynamicArray(int[] tableSizes, T[] data) throws BlenderFileException {\r
-               this.tableSizes = tableSizes;\r
-               int totalSize = 1;\r
-               for(int size : tableSizes) {\r
-                       if(size <= 0) {\r
-                               throw new BlenderFileException("The size of the table must be positive!");\r
-                       }\r
-                       totalSize *= size;\r
-               }\r
-               if(totalSize != data.length) {\r
-                       throw new IllegalArgumentException("The size of the table does not match the size of the given data!");\r
-               }\r
-               this.array = data;\r
-       }\r
+    /**\r
+     * Constructor. Builds an empty array of the specified sizes.\r
+     * @param tableSizes\r
+     *        the sizes of the table\r
+     * @throws BlenderFileException\r
+     *         an exception is thrown if one of the sizes is not a positive number\r
+     */\r
+    @SuppressWarnings("unchecked")\r
+    public DynamicArray(int[] tableSizes) throws BlenderFileException {\r
+        this.tableSizes = tableSizes;\r
+        int totalSize = 1;\r
+        for (int size : tableSizes) {\r
+            if (size <= 0) {\r
+                throw new BlenderFileException("The size of the table must be positive!");\r
+            }\r
+            totalSize *= size;\r
+        }\r
+        this.array = (T[]) new Object[totalSize];\r
+    }\r
 \r
-       @Override\r
-       public Object clone() throws CloneNotSupportedException {\r
-               return super.clone();\r
-       }\r
+    /**\r
+     * Constructor. Builds an empty array of the specified sizes.\r
+     * @param tableSizes\r
+     *        the sizes of the table\r
+     * @throws BlenderFileException\r
+     *         an exception is thrown if one of the sizes is not a positive number\r
+     */\r
+    public DynamicArray(int[] tableSizes, T[] data) throws BlenderFileException {\r
+        this.tableSizes = tableSizes;\r
+        int totalSize = 1;\r
+        for (int size : tableSizes) {\r
+            if (size <= 0) {\r
+                throw new BlenderFileException("The size of the table must be positive!");\r
+            }\r
+            totalSize *= size;\r
+        }\r
+        if (totalSize != data.length) {\r
+            throw new IllegalArgumentException("The size of the table does not match the size of the given data!");\r
+        }\r
+        this.array = data;\r
+    }\r
 \r
-       /**\r
-        * This method returns a value on the specified position. The dimension of the table is not taken into\r
-        * consideration.\r
-        * @param position\r
-        *        the position of the data\r
-        * @return required data\r
-        */\r
-       public T get(int position) {\r
-               return array[position];\r
-       }\r
+    @Override\r
+    public Object clone() throws CloneNotSupportedException {\r
+        return super.clone();\r
+    }\r
 \r
-       /**\r
-        * This method returns a value on the specified position in multidimensional array. Be careful not to exceed the\r
-        * table boundaries. Check the table's dimension first.\r
-        * @param position\r
-        *        the position of the data indices of data position\r
-        * @return required data required data\r
-        */\r
-       public T get(int... position) {\r
-               if(position.length != tableSizes.length) {\r
-                       throw new ArrayIndexOutOfBoundsException("The table accepts " + tableSizes.length + " indexing number(s)!");\r
-               }\r
-               int index = 0;\r
-               for(int i = 0; i < position.length - 1; ++i) {\r
-                       index += position[i] * tableSizes[i + 1];\r
-               }\r
-               index += position[position.length - 1];\r
-               return array[index];\r
-       }\r
+    /**\r
+     * This method returns a value on the specified position. The dimension of the table is not taken into\r
+     * consideration.\r
+     * @param position\r
+     *        the position of the data\r
+     * @return required data\r
+     */\r
+    public T get(int position) {\r
+        return array[position];\r
+    }\r
 \r
-       /**\r
-        * This method returns the total amount of data stored in the array.\r
-        * @return the total amount of data stored in the array\r
-        */\r
-       public int getTotalSize() {\r
-               return array.length;\r
-       }\r
+    /**\r
+     * This method returns a value on the specified position in multidimensional array. Be careful not to exceed the\r
+     * table boundaries. Check the table's dimension first.\r
+     * @param position\r
+     *        the position of the data indices of data position\r
+     * @return required data required data\r
+     */\r
+    public T get(int... position) {\r
+        if (position.length != tableSizes.length) {\r
+            throw new ArrayIndexOutOfBoundsException("The table accepts " + tableSizes.length + " indexing number(s)!");\r
+        }\r
+        int index = 0;\r
+        for (int i = 0; i < position.length - 1; ++i) {\r
+            index += position[i] * tableSizes[i + 1];\r
+        }\r
+        index += position[position.length - 1];\r
+        return array[index];\r
+    }\r
 \r
-       @Override\r
-       public String toString() {\r
-               StringBuilder result = new StringBuilder();\r
-               if(array instanceof Character[]) {//in case of character array we convert it to String\r
-                       for(int i = 0; i < array.length && (Character)array[i] != '\0'; ++i) {//strings are terminater with '0'\r
-                               result.append(array[i]);\r
-                       }\r
-               } else {\r
-                       result.append('[');\r
-                       for(int i = 0; i < array.length; ++i) {\r
-                               result.append(array[i].toString());\r
-                               if(i + 1 < array.length) {\r
-                                       result.append(',');\r
-                               }\r
-                       }\r
-                       result.append(']');\r
-               }\r
-               return result.toString();\r
-       }\r
+    /**\r
+     * This method returns the total amount of data stored in the array.\r
+     * @return the total amount of data stored in the array\r
+     */\r
+    public int getTotalSize() {\r
+        return array.length;\r
+    }\r
+\r
+    @Override\r
+    public String toString() {\r
+        StringBuilder result = new StringBuilder();\r
+        if (array instanceof Character[]) {//in case of character array we convert it to String\r
+            for (int i = 0; i < array.length && (Character) array[i] != '\0'; ++i) {//strings are terminater with '0'\r
+                result.append(array[i]);\r
+            }\r
+        } else {\r
+            result.append('[');\r
+            for (int i = 0; i < array.length; ++i) {\r
+                result.append(array[i].toString());\r
+                if (i + 1 < array.length) {\r
+                    result.append(',');\r
+                }\r
+            }\r
+            result.append(']');\r
+        }\r
+        return result.toString();\r
+    }\r
 }
\ No newline at end of file
index 7b60f4e..f7c7af4 100644 (file)
@@ -55,115 +55,115 @@ import com.jme3.scene.plugins.blender.helpers.ObjectHelper;
  * This class converts blender file blocks into jMonkeyEngine data structures.\r
  * @author Marcin Roguski\r
  */\r
-public class JmeConverter implements IBlenderConverter<Node, Camera, Light, Object, List<Geometry>, Material> {\r
-       private static final Logger             LOGGER                                          = Logger.getLogger(JmeConverter.class.getName());\r
+public class JmeConverter implements BlenderConverter<Node, Camera, Light, Object, List<Geometry>, Material> {\r
 \r
-       private final DataRepository    dataRepository;\r
+    private static final Logger LOGGER = Logger.getLogger(JmeConverter.class.getName());\r
+    private final DataRepository dataRepository;\r
 \r
-       /**\r
-        * Constructor. Creates the loader and checks if the given data is correct.\r
-        * @param dataRepository\r
-        *        the data repository; it should have the following field set: - asset manager - blender key - dna block\r
-        *        data - blender input stream Otherwise IllegalArgumentException will be thrown.\r
-        * @param featuresToLoad\r
-        *        bitwise flag describing what features are to be loaded\r
-        * @see FeaturesToLoad FeaturesToLoad\r
-        */\r
-       public JmeConverter(DataRepository dataRepository) {\r
-               //validating the given data first\r
-               if(dataRepository.getAssetManager() == null) {\r
-                       throw new IllegalArgumentException("Cannot find asset manager!");\r
-               }\r
-               if(dataRepository.getBlenderKey() == null) {\r
-                       throw new IllegalArgumentException("Cannot find blender key!");\r
-               }\r
-               if(dataRepository.getDnaBlockData() == null) {\r
-                       throw new IllegalArgumentException("Cannot find dna block!");\r
-               }\r
-               if(dataRepository.getInputStream() == null) {\r
-                       throw new IllegalArgumentException("Cannot find blender file stream!");\r
-               }\r
-               this.dataRepository = dataRepository;\r
-       }\r
+    /**\r
+     * Constructor. Creates the loader and checks if the given data is correct.\r
+     * @param dataRepository\r
+     *        the data repository; it should have the following field set: - asset manager - blender key - dna block\r
+     *        data - blender input stream Otherwise IllegalArgumentException will be thrown.\r
+     * @param featuresToLoad\r
+     *        bitwise flag describing what features are to be loaded\r
+     * @see FeaturesToLoad FeaturesToLoad\r
+     */\r
+    public JmeConverter(DataRepository dataRepository) {\r
+        //validating the given data first\r
+        if (dataRepository.getAssetManager() == null) {\r
+            throw new IllegalArgumentException("Cannot find asset manager!");\r
+        }\r
+        if (dataRepository.getBlenderKey() == null) {\r
+            throw new IllegalArgumentException("Cannot find blender key!");\r
+        }\r
+        if (dataRepository.getDnaBlockData() == null) {\r
+            throw new IllegalArgumentException("Cannot find dna block!");\r
+        }\r
+        if (dataRepository.getInputStream() == null) {\r
+            throw new IllegalArgumentException("Cannot find blender file stream!");\r
+        }\r
+        this.dataRepository = dataRepository;\r
+    }\r
 \r
-       @Override\r
-       public Node toScene(Structure structure) {//TODO: poprawny import sceny\r
-               if((dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.SCENES) == 0) {\r
-                       return null;\r
-               }\r
-               Structure id = (Structure)structure.getFieldValue("id");\r
-               String sceneName = id.getFieldValue("name").toString();\r
-               \r
-               //veryfying layers to be loaded\r
-               if(dataRepository.getBlenderKey().getLayersToLoad()<0) {\r
-                       int lay = ((Number)structure.getFieldValue("lay")).intValue();\r
-                       dataRepository.getBlenderKey().setLayersToLoad(lay);//load only current layer\r
-               }\r
-               return new Node(sceneName);\r
-       }\r
+    @Override\r
+    public Node toScene(Structure structure) {//TODO: poprawny import sceny\r
+        if ((dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.SCENES) == 0) {\r
+            return null;\r
+        }\r
+        Structure id = (Structure) structure.getFieldValue("id");\r
+        String sceneName = id.getFieldValue("name").toString();\r
 \r
-       @Override\r
-       public Camera toCamera(Structure structure) throws BlenderFileException {\r
-               if((dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.CAMERAS) == 0) {\r
-                       return null;\r
-               }\r
-               CameraHelper cameraHelper = dataRepository.getHelper(CameraHelper.class);\r
-               return cameraHelper.toCamera(structure);\r
-       }\r
+        //veryfying layers to be loaded\r
+        if (dataRepository.getBlenderKey().getLayersToLoad() < 0) {\r
+            int lay = ((Number) structure.getFieldValue("lay")).intValue();\r
+            dataRepository.getBlenderKey().setLayersToLoad(lay);//load only current layer\r
+        }\r
+        return new Node(sceneName);\r
+    }\r
 \r
-       @Override\r
-       public Light toLight(Structure structure) throws BlenderFileException {\r
-               if((dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.LIGHTS) == 0) {\r
-                       return null;\r
-               }\r
-               LightHelper lightHelper = dataRepository.getHelper(LightHelper.class);\r
-               return lightHelper.toLight(structure, dataRepository);\r
-       }\r
+    @Override\r
+    public Camera toCamera(Structure structure) throws BlenderFileException {\r
+        if ((dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.CAMERAS) == 0) {\r
+            return null;\r
+        }\r
+        CameraHelper cameraHelper = dataRepository.getHelper(CameraHelper.class);\r
+        return cameraHelper.toCamera(structure);\r
+    }\r
 \r
-       @Override\r
-       public Object toObject(Structure structure) throws BlenderFileException {\r
-               int lay = ((Number)structure.getFieldValue("lay")).intValue();\r
-               if((lay & dataRepository.getBlenderKey().getLayersToLoad()) == 0 ||\r
-                  (dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.OBJECTS) == 0) {\r
-                       return null;\r
-               }\r
-               ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);\r
-               return objectHelper.toObject(structure, dataRepository);\r
-       }\r
+    @Override\r
+    public Light toLight(Structure structure) throws BlenderFileException {\r
+        if ((dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.LIGHTS) == 0) {\r
+            return null;\r
+        }\r
+        LightHelper lightHelper = dataRepository.getHelper(LightHelper.class);\r
+        return lightHelper.toLight(structure, dataRepository);\r
+    }\r
 \r
-       @Override\r
-       public List<Geometry> toMesh(Structure structure) throws BlenderFileException {\r
-               MeshHelper meshHelper = dataRepository.getHelper(MeshHelper.class);\r
-               return meshHelper.toMesh(structure, dataRepository);\r
-       }\r
+    @Override\r
+    public Object toObject(Structure structure) throws BlenderFileException {\r
+        int lay = ((Number) structure.getFieldValue("lay")).intValue();\r
+        if ((lay & dataRepository.getBlenderKey().getLayersToLoad()) == 0\r
+                || (dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.OBJECTS) == 0) {\r
+            return null;\r
+        }\r
+        ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);\r
+        return objectHelper.toObject(structure, dataRepository);\r
+    }\r
 \r
-       @Override\r
-       public Material toMaterial(Structure structure) throws BlenderFileException {\r
-               if((dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.MATERIALS) == 0) {\r
-                       return null;\r
-               }\r
-               MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);\r
-               return materialHelper.toMaterial(structure, dataRepository);\r
-       }\r
+    @Override\r
+    public List<Geometry> toMesh(Structure structure) throws BlenderFileException {\r
+        MeshHelper meshHelper = dataRepository.getHelper(MeshHelper.class);\r
+        return meshHelper.toMesh(structure, dataRepository);\r
+    }\r
 \r
-       /**\r
-        * This method returns the data read from the WORLD file block. The block contains data that can be stored as\r
-        * separate jme features and therefore cannot be returned as a single jME scene feature.\r
-        * @param structure\r
-        *        the structure with WORLD block data\r
-        * @return data read from the WORLD block that can be added to the scene\r
-        */\r
-       public WorldData toWorldData(Structure structure) {\r
-               WorldData result = new WorldData();\r
+    @Override\r
+    public Material toMaterial(Structure structure) throws BlenderFileException {\r
+        if ((dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.MATERIALS) == 0) {\r
+            return null;\r
+        }\r
+        MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);\r
+        return materialHelper.toMaterial(structure, dataRepository);\r
+    }\r
 \r
-               //reading ambient light\r
-               AmbientLight ambientLight = new AmbientLight();\r
-               float ambr = ((Number)structure.getFieldValue("ambr")).floatValue();\r
-               float ambg = ((Number)structure.getFieldValue("ambg")).floatValue();\r
-               float ambb = ((Number)structure.getFieldValue("ambb")).floatValue();\r
-               ambientLight.setColor(new ColorRGBA(ambr, ambg, ambb, 0.0f));\r
-               result.setAmbientLight(ambientLight);\r
+    /**\r
+     * This method returns the data read from the WORLD file block. The block contains data that can be stored as\r
+     * separate jme features and therefore cannot be returned as a single jME scene feature.\r
+     * @param structure\r
+     *        the structure with WORLD block data\r
+     * @return data read from the WORLD block that can be added to the scene\r
+     */\r
+    public WorldData toWorldData(Structure structure) {\r
+        WorldData result = new WorldData();\r
 \r
-               return result;\r
-       }\r
+        //reading ambient light\r
+        AmbientLight ambientLight = new AmbientLight();\r
+        float ambr = ((Number) structure.getFieldValue("ambr")).floatValue();\r
+        float ambg = ((Number) structure.getFieldValue("ambg")).floatValue();\r
+        float ambb = ((Number) structure.getFieldValue("ambb")).floatValue();\r
+        ambientLight.setColor(new ColorRGBA(ambr, ambg, ambb, 0.0f));\r
+        result.setAmbientLight(ambientLight);\r
+\r
+        return result;\r
+    }\r
 }\r
index dd82c6f..fd04843 100644 (file)
@@ -43,133 +43,134 @@ import com.jme3.scene.plugins.blender.exception.BlenderFileException;
  * @author Marcin Roguski\r
  */\r
 public class Pointer {\r
-       /** The data repository. */\r
-       private DataRepository  dataRepository;\r
-       /** The level of the pointer. */\r
-       private int                             pointerLevel;\r
-       /** The address in file it points to. */\r
-       private long                    oldMemoryAddress;\r
-       /** This variable indicates if the field is a function pointer. */\r
-       public boolean                  function;\r
 \r
-       /**\r
-        * Constructr. Stores the basic data about the pointer.\r
-        * @param pointerLevel\r
-        *        the level of the pointer\r
-        * @param function\r
-        *        this variable indicates if the field is a function pointer\r
-        * @param dataRepository\r
-        *        the repository f data; used in fetching the value that the pointer points\r
-        */\r
-       public Pointer(int pointerLevel, boolean function, DataRepository dataRepository) {\r
-               this.pointerLevel = pointerLevel;\r
-               this.function = function;\r
-               this.dataRepository = dataRepository;\r
-       }\r
+    /** The data repository. */\r
+    private DataRepository dataRepository;\r
+    /** The level of the pointer. */\r
+    private int pointerLevel;\r
+    /** The address in file it points to. */\r
+    private long oldMemoryAddress;\r
+    /** This variable indicates if the field is a function pointer. */\r
+    public boolean function;\r
 \r
-       /**\r
-        * This method fills the pointer with its address value (it doesn't get the actual data yet. Use the 'fetch' method\r
-        * for this.\r
-        * @param inputStream\r
-        *        the stream we read the pointer value from\r
-        */\r
-       public void fill(BlenderInputStream inputStream) {\r
-               oldMemoryAddress = inputStream.readPointer();\r
-       }\r
+    /**\r
+     * Constructr. Stores the basic data about the pointer.\r
+     * @param pointerLevel\r
+     *        the level of the pointer\r
+     * @param function\r
+     *        this variable indicates if the field is a function pointer\r
+     * @param dataRepository\r
+     *        the repository f data; used in fetching the value that the pointer points\r
+     */\r
+    public Pointer(int pointerLevel, boolean function, DataRepository dataRepository) {\r
+        this.pointerLevel = pointerLevel;\r
+        this.function = function;\r
+        this.dataRepository = dataRepository;\r
+    }\r
 \r
-       /**\r
-        * This method fetches the data stored under the given address.\r
-        * @param inputStream\r
-        *        the stream we read data from\r
-        * @param dataIndices\r
-        *        the offset of the data in the table pointed by the pointer\r
-        * @return the data read from the file\r
-        * @throws BlenderFileException\r
-        *         this exception is thrown when the blend file structure is somehow invalid or corrupted\r
-        */\r
-       public List<Structure> fetchData(BlenderInputStream inputStream) throws BlenderFileException {\r
-               if(oldMemoryAddress == 0) {\r
-                       throw new NullPointerException("The pointer points to nothing!");\r
-               }\r
-               List<Structure> structures = null;\r
-               FileBlockHeader dataFileBlock = dataRepository.getFileBlock(oldMemoryAddress);\r
-               if(pointerLevel > 1) {\r
-                       int pointersAmount = dataFileBlock.getSize() / inputStream.getPointerSize() * dataFileBlock.getCount();\r
-                       for(int i = 0; i < pointersAmount; ++i) {\r
-                               inputStream.setPosition(dataFileBlock.getBlockPosition() + inputStream.getPointerSize() * i);\r
-                               long oldMemoryAddress = inputStream.readPointer();\r
-                               if(oldMemoryAddress != 0L) {\r
-                                       Pointer p = new Pointer(pointerLevel - 1, this.function, dataRepository);\r
-                                       p.oldMemoryAddress = oldMemoryAddress;\r
-                                       if(structures == null) {\r
-                                               structures = p.fetchData(inputStream);\r
-                                       } else {\r
-                                               structures.addAll(p.fetchData(inputStream));\r
-                                       }\r
-                               }\r
-                       }\r
-               } else {\r
-                       inputStream.setPosition(dataFileBlock.getBlockPosition());\r
-                       structures = new ArrayList<Structure>(dataFileBlock.getCount());\r
-                       for(int i = 0; i < dataFileBlock.getCount(); ++i) {\r
-                               Structure structure = dataRepository.getDnaBlockData().getStructure(dataFileBlock.getSdnaIndex());\r
-                               structure.fill(inputStream);\r
-                               structures.add(structure);\r
-                       }\r
-                       return structures;\r
-               }\r
-               return structures;\r
-       }\r
+    /**\r
+     * This method fills the pointer with its address value (it doesn't get the actual data yet. Use the 'fetch' method\r
+     * for this.\r
+     * @param inputStream\r
+     *        the stream we read the pointer value from\r
+     */\r
+    public void fill(BlenderInputStream inputStream) {\r
+        oldMemoryAddress = inputStream.readPointer();\r
+    }\r
 \r
-       /**\r
-        * This method indicates if this pointer points to a function.\r
-        * @return <b>true</b> if this is a function pointer and <b>false</b> otherwise\r
-        */\r
-       public boolean isFunction() {\r
-               return function;\r
-       }\r
+    /**\r
+     * This method fetches the data stored under the given address.\r
+     * @param inputStream\r
+     *        the stream we read data from\r
+     * @param dataIndices\r
+     *        the offset of the data in the table pointed by the pointer\r
+     * @return the data read from the file\r
+     * @throws BlenderFileException\r
+     *         this exception is thrown when the blend file structure is somehow invalid or corrupted\r
+     */\r
+    public List<Structure> fetchData(BlenderInputStream inputStream) throws BlenderFileException {\r
+        if (oldMemoryAddress == 0) {\r
+            throw new NullPointerException("The pointer points to nothing!");\r
+        }\r
+        List<Structure> structures = null;\r
+        FileBlockHeader dataFileBlock = dataRepository.getFileBlock(oldMemoryAddress);\r
+        if (pointerLevel > 1) {\r
+            int pointersAmount = dataFileBlock.getSize() / inputStream.getPointerSize() * dataFileBlock.getCount();\r
+            for (int i = 0; i < pointersAmount; ++i) {\r
+                inputStream.setPosition(dataFileBlock.getBlockPosition() + inputStream.getPointerSize() * i);\r
+                long oldMemoryAddress = inputStream.readPointer();\r
+                if (oldMemoryAddress != 0L) {\r
+                    Pointer p = new Pointer(pointerLevel - 1, this.function, dataRepository);\r
+                    p.oldMemoryAddress = oldMemoryAddress;\r
+                    if (structures == null) {\r
+                        structures = p.fetchData(inputStream);\r
+                    } else {\r
+                        structures.addAll(p.fetchData(inputStream));\r
+                    }\r
+                }\r
+            }\r
+        } else {\r
+            inputStream.setPosition(dataFileBlock.getBlockPosition());\r
+            structures = new ArrayList<Structure>(dataFileBlock.getCount());\r
+            for (int i = 0; i < dataFileBlock.getCount(); ++i) {\r
+                Structure structure = dataRepository.getDnaBlockData().getStructure(dataFileBlock.getSdnaIndex());\r
+                structure.fill(inputStream);\r
+                structures.add(structure);\r
+            }\r
+            return structures;\r
+        }\r
+        return structures;\r
+    }\r
 \r
-       /**\r
-        * This method indicates if this is a null-pointer or not.\r
-        * @return <b>true</b> if the pointer is null and <b>false</b> otherwise\r
-        */\r
-       public boolean isNull() {\r
-               return oldMemoryAddress == 0;\r
-       }\r
+    /**\r
+     * This method indicates if this pointer points to a function.\r
+     * @return <b>true</b> if this is a function pointer and <b>false</b> otherwise\r
+     */\r
+    public boolean isFunction() {\r
+        return function;\r
+    }\r
 \r
-       /**\r
-        * This method returns the old memory address of the structure pointed by the pointer.\r
-        * @return the old memory address of the structure pointed by the pointer\r
-        */\r
-       public long getOldMemoryAddress() {\r
-               return oldMemoryAddress;\r
-       }\r
+    /**\r
+     * This method indicates if this is a null-pointer or not.\r
+     * @return <b>true</b> if the pointer is null and <b>false</b> otherwise\r
+     */\r
+    public boolean isNull() {\r
+        return oldMemoryAddress == 0;\r
+    }\r
 \r
-       @Override\r
-       public String toString() {\r
-               return oldMemoryAddress == 0 ? "{$null$}" : "{$" + oldMemoryAddress + "$}";\r
-       }\r
+    /**\r
+     * This method returns the old memory address of the structure pointed by the pointer.\r
+     * @return the old memory address of the structure pointed by the pointer\r
+     */\r
+    public long getOldMemoryAddress() {\r
+        return oldMemoryAddress;\r
+    }\r
 \r
-       @Override\r
-       public int hashCode() {\r
-               return 31 + (int)(oldMemoryAddress ^ oldMemoryAddress >>> 32);\r
-       }\r
+    @Override\r
+    public String toString() {\r
+        return oldMemoryAddress == 0 ? "{$null$}" : "{$" + oldMemoryAddress + "$}";\r
+    }\r
 \r
-       @Override\r
-       public boolean equals(Object obj) {\r
-               if(this == obj) {\r
-                       return true;\r
-               }\r
-               if(obj == null) {\r
-                       return false;\r
-               }\r
-               if(this.getClass() != obj.getClass()) {\r
-                       return false;\r
-               }\r
-               Pointer other = (Pointer)obj;\r
-               if(oldMemoryAddress != other.oldMemoryAddress) {\r
-                       return false;\r
-               }\r
-               return true;\r
-       }\r
+    @Override\r
+    public int hashCode() {\r
+        return 31 + (int) (oldMemoryAddress ^ oldMemoryAddress >>> 32);\r
+    }\r
+\r
+    @Override\r
+    public boolean equals(Object obj) {\r
+        if (this == obj) {\r
+            return true;\r
+        }\r
+        if (obj == null) {\r
+            return false;\r
+        }\r
+        if (this.getClass() != obj.getClass()) {\r
+            return false;\r
+        }\r
+        Pointer other = (Pointer) obj;\r
+        if (oldMemoryAddress != other.oldMemoryAddress) {\r
+            return false;\r
+        }\r
+        return true;\r
+    }\r
 }\r
index f5059eb..30e1b53 100644 (file)
@@ -347,7 +347,6 @@ public final class Bone implements Savable {
     /**
      * Set user transform.
      * Combine the given transforms to bone's current transforms
-     * @see setUserControl
      */
     public void setUserTransforms(Vector3f translation, Quaternion rotation, Vector3f scale) {
         if (!userControl) {
@@ -378,10 +377,9 @@ public final class Bone implements Savable {
     }
     
     /**
-     * Returns teh local transform of this bone combined with the given position and rotation
+     * Returns the local transform of this bone combined with the given position and rotation
      * @param position a position
      * @param rotation a rotation
-     * @return 
      */
     public Transform getCombinedTransform(Vector3f position, Quaternion rotation){
             rotation.mult(localPos, tmpTransform.getTranslation()).addLocal(position);
index cf24844..686d253 100644 (file)
@@ -234,13 +234,11 @@ public abstract class CompactArray<T> {
      * deserialize object\r
      * @param compactIndex compacted object index\r
      * @param store\r
-     * @return\r
      */\r
     protected abstract T deserialize(int compactIndex, T store);\r
 \r
     /**\r
      * serialized size of one object element\r
-     * @return\r
      */\r
     protected abstract int getTupleSize();\r
     \r
index 1f6e68d..472ef61 100644 (file)
@@ -10,7 +10,7 @@
 The <code>com.jme3.application</code> provides a toolset for jME3 applications
 to interact with various components of the engine. Typically, the
 {@link com.jme3.app.Application} class will be extended and the update() method
-implemented to provide functionality for the main loop. <br/>
+implemented to provide functionality for the main loop. <br>
 <p>
 An <code>Application</code> will typically provide the following services:
 <ul>
@@ -37,42 +37,42 @@ An <code>Application</code> will typically provide the following services:
 
 <h3>Usage</h3>
 
-An example use of the Application class is as follows<br/>
-<br/>
+An example use of the Application class is as follows<br>
+<br>
 
 <code>
-public class ExampleUse extends Application {<br/>
-<br/>
-    private Node rootNode = new Node("Root Node");<br/>
-<br/>
-    public static void main(String[] args){<br/>
-        ExampleUse app = new ExampleUse();<br/>
-        app.start();<br/>
-    }<br/>
-<br/>
-    @Override<br/>
-    public void initialize(){<br/>
-        super.initialize();<br/>
-<br/>
-        // attach root node to viewport<br/>
-        viewPort.attachScene(rootNode);<br/>
-    }<br/>
-<br/>
-    @Override<br/>
-    public void update(){<br/>
-        super.update();<br/>
-<br/>
-        float tpf = timer.getTimePerFrame();<br/>
-<br/>
-        // update rootNode<br/>
-        rootNode.updateLogicalState(tpf);<br/>
-        rootNode.updateGeometricState();<br/>
-<br/>
-        // render the viewports<br/>
-        renderManager.render(tpf);<br/>
-    }<br/>
-}<br/>
-<br/>
+public class ExampleUse extends Application {<br>
+<br>
+    private Node rootNode = new Node("Root Node");<br>
+<br>
+    public static void main(String[] args){<br>
+        ExampleUse app = new ExampleUse();<br>
+        app.start();<br>
+    }<br>
+<br>
+    @Override<br>
+    public void initialize(){<br>
+        super.initialize();<br>
+<br>
+        // attach root node to viewport<br>
+        viewPort.attachScene(rootNode);<br>
+    }<br>
+<br>
+    @Override<br>
+    public void update(){<br>
+        super.update();<br>
+<br>
+        float tpf = timer.getTimePerFrame();<br>
+<br>
+        // update rootNode<br>
+        rootNode.updateLogicalState(tpf);<br>
+        rootNode.updateGeometricState();<br>
+<br>
+        // render the viewports<br>
+        renderManager.render(tpf);<br>
+    }<br>
+}<br>
+<br>
 </code>
 
 </body>
index 6fe0e9c..76c4047 100644 (file)
@@ -173,7 +173,6 @@ public class AppStateManager {
 \r
     /**\r
      * Calls render for all attached states, do not call directly.\r
-     * @param rm The RenderManager\r
      */\r
     public void postRender(){\r
         AppState[] array = getArray();\r
index c0cb831..561e372 100644 (file)
@@ -54,7 +54,7 @@ public interface AssetLocator {
      * 
      * @param manager
      * @param key
-     * @return
+     * @return The {@link AssetInfo} that was located, or null if not found.
      */
     public AssetInfo locate(AssetManager manager, AssetKey key);
 }
index ad44c51..c57bb1b 100644 (file)
@@ -159,7 +159,7 @@ public interface AssetManager {
      * TGA and DDS.
      *
      * @param name The name of the texture to load.
-     * @return
+     * @return The texture that was loaded
      *
      * @see AssetManager#loadAsset(com.jme3.asset.AssetKey)
      */
@@ -168,7 +168,7 @@ public interface AssetManager {
     /**
      * Load audio file, supported types are WAV or OGG.
      * @param key
-     * @return
+     * @return The audio data loaded
      *
      * @see AssetManager#loadAsset(com.jme3.asset.AssetKey)
      */
@@ -178,7 +178,7 @@ public interface AssetManager {
      * Load audio file, supported types are WAV or OGG.
      * The file is loaded without stream-mode.
      * @param name
-     * @return
+     * @return The audio data loaded
      *
      * @see AssetManager#loadAsset(com.jme3.asset.AssetKey)
      */
@@ -188,7 +188,7 @@ public interface AssetManager {
      * Loads a named model. Models can be jME3 object files (J3O) or
      * OgreXML/OBJ files.
      * @param key
-     * @return
+     * @return The model that was loaded
      *
      * @see AssetManager#loadAsset(com.jme3.asset.AssetKey)
      */
@@ -198,7 +198,7 @@ public interface AssetManager {
      * Loads a named model. Models can be jME3 object files (J3O) or
      * OgreXML/OBJ files.
      * @param name
-     * @return
+     * @return The model that was loaded
      *
      * @see AssetManager#loadAsset(com.jme3.asset.AssetKey)
      */
@@ -207,7 +207,7 @@ public interface AssetManager {
     /**
      * Load a material (J3M) file.
      * @param name
-     * @return
+     * @return The material that was loaded
      *
      * @see AssetManager#loadAsset(com.jme3.asset.AssetKey)
      */
@@ -225,7 +225,7 @@ public interface AssetManager {
      * and are with the extension "fnt".
      *
      * @param name
-     * @return
+     * @return The font loaded
      *
      * @see AssetManager#loadAsset(com.jme3.asset.AssetKey) 
      */
index 8f87570..5abb529 100644 (file)
@@ -70,7 +70,7 @@ public class TextureKey extends AssetKey<Texture> {
 
     /**
      * Enable smart caching for textures
-     * @return
+     * @return true to enable smart cache
      */
     @Override
     public boolean useSmartCache(){
index 468b6ae..20fa2be 100644 (file)
@@ -48,7 +48,7 @@ public interface AudioRenderer {
     /**
      * Sets the environment, used for reverb effects.
      *
-     * @see PointAudioSource#setReverbEnabled(boolean)
+     * @see AudioNode#setReverbEnabled(boolean)
      * @param env The environment to set.
      */
     public void setEnvironment(Environment env);
index 6d98949..1e1440a 100644 (file)
@@ -259,12 +259,8 @@ public class BoundingBox extends BoundingVolume {
      * <code>transform</code> modifies the center of the box to reflect the\r
      * change made via a rotation, translation and scale.\r
      * \r
-     * @param rotate\r
-     *            the rotation change.\r
-     * @param translate\r
-     *            the translation change.\r
-     * @param scale\r
-     *            the size change.\r
+     * @param trans \r
+     *            the transform to apply\r
      * @param store\r
      *            box to store result in\r
      */\r
@@ -570,7 +566,7 @@ public class BoundingBox extends BoundingVolume {
      * intersects determines if this Bounding Box intersects with another given\r
      * bounding volume. If so, true is returned, otherwise, false is returned.\r
      * \r
-     * @see com.jme.bounding.BoundingVolume#intersects(com.jme.bounding.BoundingVolume)\r
+     * @see BoundingVolume#intersects(com.jme3.bounding.BoundingVolume) \r
      */\r
     public boolean intersects(BoundingVolume bv) {\r
         return bv.intersectsBoundingBox(this);\r
@@ -579,7 +575,7 @@ public class BoundingBox extends BoundingVolume {
     /**\r
      * determines if this bounding box intersects a given bounding sphere.\r
      * \r
-     * @see com.jme.bounding.BoundingVolume#intersectsSphere(com.jme.bounding.BoundingSphere)\r
+     * @see BoundingVolume#intersectsSphere(com.jme3.bounding.BoundingSphere)\r
      */\r
     public boolean intersectsSphere(BoundingSphere bs) {\r
         assert Vector3f.isValidVector(center) && Vector3f.isValidVector(bs.center);\r
@@ -600,7 +596,7 @@ public class BoundingBox extends BoundingVolume {
      * two boxes intersect in any way, true is returned. Otherwise, false is\r
      * returned.\r
      * \r
-     * @see com.jme.bounding.BoundingVolume#intersectsBoundingBox(com.jme.bounding.BoundingBox)\r
+     * @see BoundingVolume#intersectsBoundingBox(com.jme3.bounding.BoundingBox)\r
      */\r
     public boolean intersectsBoundingBox(BoundingBox bb) {\r
         assert Vector3f.isValidVector(center) && Vector3f.isValidVector(bb.center);\r
@@ -632,7 +628,7 @@ public class BoundingBox extends BoundingVolume {
      * determines if this bounding box intersects with a given ray object. If an\r
      * intersection has occurred, true is returned, otherwise false is returned.\r
      * \r
-     * @see com.jme.bounding.BoundingVolume#intersects(com.jme.math.Ray)\r
+     * @see BoundingVolume#intersects(com.jme3.math.Ray) \r
      */\r
     public boolean intersects(Ray ray) {\r
         assert Vector3f.isValidVector(center);\r
@@ -766,10 +762,11 @@ public class BoundingBox extends BoundingVolume {
     /**\r
      * C code ported from http://www.cs.lth.se/home/Tomas_Akenine_Moller/code/tribox3.txt\r
      *\r
-     * @param v1\r
-     * @param v2\r
-     * @param v3\r
-     * @return\r
+     * @param v1 The first point in the triangle\r
+     * @param v2 The second point in the triangle\r
+     * @param v3 The third point in the triangle\r
+     * @return True if the bounding box intersects the triangle, false\r
+     * otherwise.\r
      */\r
     public boolean intersects(Vector3f v1, Vector3f v2, Vector3f v3){\r
        return Intersection.intersect(this, v1, v2, v3);\r
index 3d0df13..6725a44 100644 (file)
@@ -387,12 +387,8 @@ public class BoundingSphere extends BoundingVolume {
      * <code>transform</code> modifies the center of the sphere to reflect the\r
      * change made via a rotation, translation and scale.\r
      *\r
-     * @param rotate\r
-     *            the rotation change.\r
-     * @param translate\r
-     *            the translation change.\r
-     * @param scale\r
-     *            the size change.\r
+     * @param trans\r
+     *            the transform to apply\r
      * @param store\r
      *            sphere to store result in\r
      * @return BoundingVolume\r
index 303a54e..ff013d6 100644 (file)
@@ -32,6 +32,8 @@
 
 package com.jme3.input.controls;
 
+import com.jme3.input.MouseInput;
+
 /**
  * A <code>MouseButtonTrigger</code> is used as a mapping to receive events
  * from mouse buttons. It is generally expected for a mouse to have at least
index 712c45a..009e21e 100644 (file)
@@ -160,7 +160,8 @@ public abstract class Light implements Savable, Cloneable {
         this.color.set(color);
     }
 
-    /**
+    
+    /*
      * Returns true if the light is enabled
      * 
      * @return true if the light is enabled
index 8a6f395..2e14055 100644 (file)
@@ -193,8 +193,7 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
     }
 
     /**
-     * Clones this material. The result 
-     * @return 
+     * Clones this material. The result is returned.
      */
     @Override
     public Material clone() {
@@ -219,10 +218,27 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
         }
     }
 
+    /**
+     * Returns the currently active technique.
+     * <p>
+     * The technique is selected automatically by the {@link RenderManager}
+     * based on system capabilities. Users may select their own
+     * technique by using 
+     * {@link #selectTechnique(java.lang.String, com.jme3.renderer.RenderManager) }.
+     * 
+     * @return the currently active technique.
+     * 
+     * @see #selectTechnique(java.lang.String, com.jme3.renderer.RenderManager) 
+     */
     public Technique getActiveTechnique() {
         return technique;
     }
 
+    /**
+     * Check if the transparent value marker is set on this material.
+     * @return True if the transparent value marker is set on this material.
+     * @see #setTransparent(boolean) 
+     */
     public boolean isTransparent() {
         return transparent;
     }
@@ -296,6 +312,13 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
         return def;
     }
 
+    /**
+     * Returns the parameter set on this material with the given name,
+     * returns <code>null</code> if the parameter is not set.
+     * 
+     * @param name The parameter name to look up.
+     * @return The MatParam if set, or null if not set.
+     */
     public MatParam getParam(String name) {
         MatParam param = paramValues.get(name);
         if (param instanceof MatParam) {
@@ -304,6 +327,13 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
         return null;
     }
 
+    /**
+     * Returns the texture parameter set on this material with the given name,
+     * returns <code>null</code> if the parameter is not set.
+     * 
+     * @param name The parameter name to look up.
+     * @return The MatParamTexture if set, or null if not set.
+     */
     public MatParamTexture getTextureParam(String name) {
         MatParam param = paramValues.get(name);
         if (param instanceof MatParamTexture) {
@@ -312,6 +342,13 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
         return null;
     }
 
+    /**
+     * Returns a collection of all parameters set on this material.
+     * 
+     * @return a collection of all parameters set on this material.
+     * 
+     * @see #setParam(java.lang.String, com.jme3.shader.VarType, java.lang.Object) 
+     */
     public Collection<MatParam> getParams() {
         return paramValues.values();
     }
@@ -342,10 +379,11 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
     }
 
     /**
-     * Pass a parameter to the material shader
+     * Pass a parameter to the material shader.
+     * 
      * @param name the name of the parameter defined in the material definition (j3md)
-     * @param type the type of the parameter @see com.jme3.shaderVarType
-     * @param value the value of the param
+     * @param type the type of the parameter {@link VarType}
+     * @param value the value of the parameter
      */
     public void setParam(String name, VarType type, Object value) {
         name = checkSetParam(type, name);
@@ -363,7 +401,7 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
     }
 
     /**
-     * Clear a parameter from this material. The param must exist
+     * Clear a parameter from this material. The parameter must exist
      * @param name the name of the parameter to clear
      */
     public void clearParam(String name) {
@@ -416,9 +454,18 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
         sortingId = -1;
     }
 
+    /**
+     * Set a texture parameter.
+     * 
+     * @param name The name of the parameter
+     * @param type The variable type {@link VarType}
+     * @param value The texture value of the parameter.
+     * 
+     * @throws IllegalArgumentException is value is null
+     */
     public void setTextureParam(String name, VarType type, Texture value) {
         if (value == null) {
-            throw new NullPointerException();
+            throw new IllegalArgumentException();
         }
 
         name = checkSetParam(type, name);
@@ -438,8 +485,10 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
     }
 
     /**
-     * Pass a texture to the material shader
-     * @param name the name of the texture defined in the material definition (j3md) (for example Texture for Lighting.j3md)
+     * Pass a texture to the material shader.
+     * 
+     * @param name the name of the texture defined in the material definition 
+     * (j3md) (for example Texture for Lighting.j3md)
      * @param value the Texture object previously loaded by the asset manager
      */
     public void setTexture(String name, Texture value) {
@@ -471,7 +520,8 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
     }
 
     /**
-     * Pass a Matrix4f to the material shader
+     * Pass a Matrix4f to the material shader.
+     * 
      * @param name the name of the matrix defined in the material definition (j3md)
      * @param value the Matrix4f object
      */
@@ -480,7 +530,8 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
     }
 
     /**
-     * Pass a boolean to the material shader
+     * Pass a boolean to the material shader.
+     * 
      * @param name the name of the boolean defined in the material definition (j3md)
      * @param value the boolean value
      */
@@ -489,7 +540,8 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
     }
 
     /**
-     * Pass a float to the material shader
+     * Pass a float to the material shader.
+     * 
      * @param name the name of the float defined in the material definition (j3md)
      * @param value the float value
      */
@@ -498,7 +550,8 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
     }
 
     /**
-     * Pass an int to the material shader
+     * Pass an int to the material shader.
+     * 
      * @param name the name of the int defined in the material definition (j3md)
      * @param value the int value
      */
@@ -507,7 +560,8 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
     }
 
     /**
-     * Pass a Color to the material shader
+     * Pass a Color to the material shader.
+     * 
      * @param name the name of the color defined in the material definition (j3md)
      * @param value the ColorRGBA value
      */
@@ -516,7 +570,8 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
     }
 
     /**
-     * Pass a Vector2f to the material shader
+     * Pass a Vector2f to the material shader.
+     * 
      * @param name the name of the Vector2f defined in the material definition (j3md)
      * @param value the Vector2f value
      */
@@ -525,7 +580,8 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
     }
 
     /**
-     * Pass a Vector3f to the material shader
+     * Pass a Vector3f to the material shader.
+     * 
      * @param name the name of the Vector3f defined in the material definition (j3md)
      * @param value the Vector3f value
      */
@@ -534,7 +590,8 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
     }
 
     /**
-     * Pass a Vector4f to the material shader
+     * Pass a Vector4f to the material shader.
+     * 
      * @param name the name of the Vector4f defined in the material definition (j3md)
      * @param value the Vector4f value
      */
@@ -567,9 +624,6 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
      * // or the direction of the light (for directional lights).<br/>
      * // g_LightPosition.w is the inverse radius (1/r) of the light (for attenuation) <br/>
      * </p>
-     *
-     * @param shader
-     * @param lightList
      */
     protected void updateLightListUniforms(Shader shader, Geometry g, int numLights) {
         if (numLights == 0){ // this shader does not do lighting, ignore.
@@ -719,6 +773,29 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
         }
     }
 
+    /**
+     * Select the technique to use for rendering this material.
+     * <p>
+     * If <code>name</code> is "Default", then one of the 
+     * {@link MaterialDef#getDefaultTechniques() default techniques}
+     * on the material will be selected. Otherwise, the named technique
+     * will be found in the material definition.
+     * <p>
+     * Any candidate technique for selection (either default or named)
+     * must be verified to be compatible with the system, for that, the
+     * <code>renderManager</code> is queried for capabilities.
+     * 
+     * @param name The name of the technique to select, pass "Default" to
+     * select one of the default techniques.
+     * @param renderManager The {@link RenderManager render manager}
+     * to query for capabilities.
+     * 
+     * @throws IllegalArgumentException If "Default" is passed and no default 
+     * techniques are available on the material definition, or if a name
+     * is passed but there's no technique by that name.
+     * @throws UnsupportedOperationException If no candidate technique supports
+     * the system capabilities.
+     */
     public void selectTechnique(String name, RenderManager renderManager) {
         // check if already created
         Technique tech = techniques.get(name);
@@ -730,7 +807,7 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
             if (name.equals("Default")) {
                 List<TechniqueDef> techDefs = def.getDefaultTechniques();
                 if (techDefs == null || techDefs.isEmpty()) {
-                    throw new IllegalStateException("No default techniques are available on material '" + def.getName() + "'");
+                    throw new IllegalArgumentException("No default techniques are available on material '" + def.getName() + "'");
                 }
 
                 TechniqueDef lastTech = null;
@@ -794,8 +871,13 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
     }
 
     /**
-     * "Pre-load" the material, including textures and shaders, to the 
-     * renderer.
+     * Preloads this material for the given render manager.
+     * <p>
+     * Preloading the material can ensure that when the material is first
+     * used for rendering, there won't be any delay since the material has
+     * been already been setup for rendering.
+     * 
+     * @param rm The render manager to preload for
      */
     public void preload(RenderManager rm) {
         autoSelectTechnique(rm);
@@ -844,9 +926,11 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
     }
 
     /**
-     * Should be called after selectTechnique()
-     * @param geom
-     * @param r
+     * Called by {@link RenderManager} to render the geometry by
+     * using this material.
+     * 
+     * @param geom The geometry to render
+     * @param rm The render manager requesting the rendering
      */
     public void render(Geometry geom, RenderManager rm) {
         autoSelectTechnique(rm);
index 51ea4ca..be6be58 100644 (file)
@@ -176,6 +176,15 @@ public class Technique implements Savable {
         updateUniformParam(paramName, type, value, false);\r
     }\r
 \r
+    /**\r
+     * Returns true if the technique must be reloaded.\r
+     * <p>\r
+     * If a technique needs to reload, then the {@link Material} should\r
+     * call {@link #makeCurrent(com.jme3.asset.AssetManager) } on this\r
+     * technique.\r
+     * \r
+     * @return true if the technique must be reloaded.\r
+     */\r
     public boolean isNeedReload() {\r
         return needReload;\r
     }\r
@@ -183,8 +192,10 @@ public class Technique implements Savable {
     /**\r
      * Prepares the technique for use by loading the shader and setting\r
      * the proper defines based on material parameters.\r
+     * \r
+     * @param assetManager The asset manager to use for loading shaders.\r
      */\r
-    public void makeCurrent(AssetManager manager) {\r
+    public void makeCurrent(AssetManager assetManager) {\r
         // check if reload is needed..\r
         if (def.isUsingShaders()) {\r
             DefineList newDefines = new DefineList();\r
@@ -203,7 +214,7 @@ public class Technique implements Savable {
                 defines.clear();\r
                 defines.addFrom(newDefines);\r
                 // defines changed, recompile needed\r
-                loadShader(manager);\r
+                loadShader(assetManager);\r
             }\r
         }\r
     }\r
@@ -214,8 +225,8 @@ public class Technique implements Savable {
         allDefines.addFrom(def.getShaderPresetDefines());\r
         allDefines.addFrom(defines);\r
 \r
-        ShaderKey key = new ShaderKey(def.getVertName(),\r
-                def.getFragName(),\r
+        ShaderKey key = new ShaderKey(def.getVertexShaderName(),\r
+                def.getFragmentShaderName(),\r
                 allDefines,\r
                 def.getShaderLanguage());\r
         shader = manager.loadShader(key);\r
index f888069..6a9a56f 100644 (file)
@@ -38,6 +38,7 @@ import com.jme3.export.InputCapsule;
 import com.jme3.export.OutputCapsule;
 import com.jme3.export.Savable;
 import com.jme3.renderer.Caps;
+import com.jme3.renderer.Renderer;
 import com.jme3.shader.DefineList;
 import com.jme3.shader.UniformBinding;
 import com.jme3.shader.VarType;
@@ -47,12 +48,49 @@ import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.List;
 
+/**
+ * Describes a technique definition.
+ * 
+ * @author Kirill Vainer
+ */
 public class TechniqueDef implements Savable {
 
+    /**
+     * Describes light rendering mode.
+     */
     public enum LightMode {
+        /**
+         * Disable light-based rendering
+         */
         Disable,
+        
+        /**
+         * Enable light rendering by using a single pass. 
+         * <p>
+         * An array of light positions and light colors is passed to the shader
+         * containing the world light list for the geometry being rendered.
+         */
         SinglePass,
+        
+        /**
+         * Enable light rendering by using multi-pass rendering.
+         * <p>
+         * The geometry will be rendered once for each light. Each time the
+         * light position and light color uniforms are updated to contain
+         * the values for the current light. The ambient light color uniform
+         * is only set to the ambient light color on the first pass, future
+         * passes have it set to black.
+         */
         MultiPass,
+        
+        /**
+         * Enable light rendering by using the 
+         * {@link Renderer#setLighting(com.jme3.light.LightList) renderer's setLighting} 
+         * method.
+         * <p>
+         * The specific details of rendering the lighting is up to the 
+         * renderer implementation.
+         */
         FixedPipeline,
     }
 
@@ -78,97 +116,140 @@ public class TechniqueDef implements Savable {
     private HashMap<String, String> defineParams;
     private ArrayList<UniformBinding> worldBinds;
 
+    /**
+     * Creates a new technique definition.
+     * <p>
+     * Used internally by the J3M/J3MD loader.
+     * 
+     * @param name The name of the technique, should be set to <code>null</code>
+     * for default techniques.
+     */
     public TechniqueDef(String name){
         this.name = name == null ? "Default" : name;
     }
 
     /**
-     * Do not use this constructor.
+     * Serialization only. Do not use.
      */
     public TechniqueDef(){
     }
 
-    public void write(JmeExporter ex) throws IOException{
-        OutputCapsule oc = ex.getCapsule(this);
-        oc.write(name, "name", null);
-        oc.write(vertName, "vertName", null);
-        oc.write(fragName, "fragName", null);
-        oc.write(shaderLang, "shaderLang", null);
-        oc.write(presetDefines, "presetDefines", null);
-        oc.write(lightMode, "lightMode", LightMode.Disable);
-        oc.write(shadowMode, "shadowMode", ShadowMode.Disable);
-        oc.write(renderState, "renderState", null);
-        oc.write(usesShaders, "usesShaders", false);
-        // TODO: Finish this when Map<String, String> export is available
-//        oc.write(defineParams, "defineParams", null);
-        // TODO: Finish this when List<Enum> export is available
-//        oc.write(worldBinds, "worldBinds", null);
-    }
-
-    public void read(JmeImporter im) throws IOException{
-        InputCapsule ic = im.getCapsule(this);
-        name = ic.readString("name", null);
-        vertName = ic.readString("vertName", null);
-        fragName = ic.readString("fragName", null);
-        shaderLang = ic.readString("shaderLang", null);
-        presetDefines = (DefineList) ic.readSavable("presetDefines", null);
-        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);
-    }
-
+    /**
+     * Returns the name of this technique as specified in the J3MD file.
+     * Default techniques have the name "Default".
+     * 
+     * @return the name of this technique
+     */
     public String getName(){
         return name;
     }
 
+    /**
+     * Returns the light mode.
+     * @return the light mode.
+     * @see LightMode
+     */
     public LightMode getLightMode() {
         return lightMode;
     }
 
+    /**
+     * Set the light mode
+     * 
+     * @param lightMode the light mode
+     * 
+     * @see LightMode
+     */
     public void setLightMode(LightMode lightMode) {
         this.lightMode = lightMode;
     }
 
+    /**
+     * Returns the shadow mode.
+     * @return the shadow mode.
+     */
     public ShadowMode getShadowMode() {
         return shadowMode;
     }
 
+    /**
+     * Set the shadow mode.
+     * 
+     * @param shadowMode the shadow mode.
+     * 
+     * @see ShadowMode
+     */
     public void setShadowMode(ShadowMode shadowMode) {
         this.shadowMode = shadowMode;
     }
 
+    /**
+     * Returns the render state that this technique is using
+     * @return the render state that this technique is using
+     * @see #setRenderState(com.jme3.material.RenderState) 
+     */
     public RenderState getRenderState() {
         return renderState;
     }
 
+    /**
+     * Sets the render state that this technique is using.
+     * 
+     * @param renderState the render state that this technique is using.
+     * 
+     * @see RenderState
+     */
     public void setRenderState(RenderState renderState) {
         this.renderState = renderState;
     }
 
+    /**
+     * Returns true if this technique uses shaders, false otherwise.
+     * 
+     * @return true if this technique uses shaders, false otherwise.
+     * 
+     * @see #setShaderFile(java.lang.String, java.lang.String, java.lang.String) 
+     */
     public boolean isUsingShaders(){
         return usesShaders;
     }
 
+    /**
+     * Gets the {@link Caps renderer capabilities} that are required
+     * by this technique.
+     * 
+     * @return the required renderer capabilities
+     */
     public EnumSet<Caps> getRequiredCaps() {
         return requiredCaps;
     }
 
-    public void setShaderFile(String vert, String frag, String lang){
-        this.vertName = vert;
-        this.fragName = frag;
-        this.shaderLang = lang;
+    /**
+     * Sets the shaders that this technique definition will use.
+     * 
+     * @param vertexShader The name of the vertex shader
+     * @param fragmentShader The name of the fragment shader
+     * @param shaderLanguage The shader language
+     */
+    public void setShaderFile(String vertexShader, String fragmentShader, String shaderLanguage){
+        this.vertName = vertexShader;
+        this.fragName = fragmentShader;
+        this.shaderLang = shaderLanguage;
 
-        Caps langCap = Caps.valueOf(lang);
+        Caps langCap = Caps.valueOf(shaderLanguage);
         requiredCaps.add(langCap);
 
         usesShaders = true;
     }
 
-    public DefineList getShaderPresetDefines() {
-        return presetDefines;
-    }
-
+    /**
+     * Returns the define name which the given material parameter influences.
+     * 
+     * @param paramName The parameter name to look up
+     * @return The define name
+     * 
+     * @see #addShaderParamDefine(java.lang.String, java.lang.String) 
+     */
     public String getShaderParamDefine(String paramName){
         if (defineParams == null)
             return null;
@@ -176,6 +257,18 @@ public class TechniqueDef implements Savable {
         return defineParams.get(paramName);
     }
 
+    /**
+     * Adds a define linked to a material parameter.
+     * <p>
+     * Any time the material parameter on the parent material is altered,
+     * the appropriate define on the technique will be modified as well. 
+     * See the method 
+     * {@link DefineList#set(java.lang.String, com.jme3.shader.VarType, java.lang.Object) }
+     * on the exact details of how the material parameter changes the define.
+     * 
+     * @param paramName The name of the material parameter to link to.
+     * @param defineName The name of the define parameter, e.g. USE_LIGHTING
+     */
     public void addShaderParamDefine(String paramName, String defineName){
         if (defineParams == null)
             defineParams = new HashMap<String, String>();
@@ -183,6 +276,30 @@ public class TechniqueDef implements Savable {
         defineParams.put(paramName, defineName);
     }
 
+    /**
+     * Returns the {@link DefineList} for the preset defines.
+     * 
+     * @return the {@link DefineList} for the preset defines.
+     * 
+     * @see #addShaderPresetDefine(java.lang.String, com.jme3.shader.VarType, java.lang.Object) 
+     */
+    public DefineList getShaderPresetDefines() {
+        return presetDefines;
+    }
+    
+    /**
+     * Adds a preset define. 
+     * <p>
+     * Preset defines do not depend upon any parameters to be activated,
+     * they are always passed to the shader as long as this technique is used.
+     * 
+     * @param defineName The name of the define parameter, e.g. USE_LIGHTING
+     * @param type The type of the define. See 
+     * {@link DefineList#set(java.lang.String, com.jme3.shader.VarType, java.lang.Object) }
+     * to see why it matters.
+     * 
+     * @param value The value of the define
+     */
     public void addShaderPresetDefine(String defineName, VarType type, Object value){
         if (presetDefines == null)
             presetDefines = new DefineList();
@@ -190,33 +307,94 @@ public class TechniqueDef implements Savable {
         presetDefines.set(defineName, type, value);
     }
 
-    public String getFragName() {
+    /**
+     * Returns the name of the fragment shader used by the technique, or null
+     * if no fragment shader is specified.
+     * 
+     * @return the name of the fragment shader to be used.
+     */
+    public String getFragmentShaderName() {
         return fragName;
     }
 
-    public String getVertName() {
+    
+    /**
+     * Returns the name of the vertex shader used by the technique, or null
+     * if no vertex shader is specified.
+     * 
+     * @return the name of the vertex shader to be used.
+     */
+    public String getVertexShaderName() {
         return vertName;
     }
 
+    /**
+     * Returns the shader language of the shaders used in this technique.
+     * 
+     * @return the shader language of the shaders used in this technique.
+     */
     public String getShaderLanguage() {
         return shaderLang;
     }
 
+    /**
+     * Adds a new world parameter by the given name.
+     * 
+     * @param name The world parameter to add.
+     * @return True if the world parameter name was found and added
+     * to the list of world parameters, false otherwise.
+     */
     public boolean addWorldParam(String name) {
         if (worldBinds == null){
             worldBinds = new ArrayList<UniformBinding>();
         }
-        for (UniformBinding binding : UniformBinding.values()) {
-            if (binding.name().equals(name)) {
-                worldBinds.add(binding);
-                return true;
-            }
+        
+        try {
+            worldBinds.add( UniformBinding.valueOf(name) );
+            return true;
+        } catch (IllegalArgumentException ex){
+            return false;
         }
-        return false;
     }
 
+    /**
+     * Returns a list of world parameters that are used by this
+     * technique definition.
+     * 
+     * @return The list of world parameters
+     */
     public List<UniformBinding> getWorldBindings() {
         return worldBinds;
     }
 
+    public void write(JmeExporter ex) throws IOException{
+        OutputCapsule oc = ex.getCapsule(this);
+        oc.write(name, "name", null);
+        oc.write(vertName, "vertName", null);
+        oc.write(fragName, "fragName", null);
+        oc.write(shaderLang, "shaderLang", null);
+        oc.write(presetDefines, "presetDefines", null);
+        oc.write(lightMode, "lightMode", LightMode.Disable);
+        oc.write(shadowMode, "shadowMode", ShadowMode.Disable);
+        oc.write(renderState, "renderState", null);
+        oc.write(usesShaders, "usesShaders", false);
+        // TODO: Finish this when Map<String, String> export is available
+//        oc.write(defineParams, "defineParams", null);
+        // TODO: Finish this when List<Enum> export is available
+//        oc.write(worldBinds, "worldBinds", null);
+    }
+
+    public void read(JmeImporter im) throws IOException{
+        InputCapsule ic = im.getCapsule(this);
+        name = ic.readString("name", null);
+        vertName = ic.readString("vertName", null);
+        fragName = ic.readString("fragName", null);
+        shaderLang = ic.readString("shaderLang", null);
+        presetDefines = (DefineList) ic.readSavable("presetDefines", null);
+        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);
+    }
+    
 }
index adfb66a..9af9cc8 100644 (file)
@@ -9,7 +9,7 @@
 
 The <code>com.jme3.material</code> package contains classes for manipulating
 jMonkeyEngine materials.
-Materials are applied to {@link com.jme3.scene.Geoemtry geometries} in the
+Materials are applied to {@link com.jme3.scene.Geometry geometries} in the
 scene. 
 Each geometry has a single material which is used to render that
 geometry.
index 13367a4..abd329d 100644 (file)
@@ -1197,8 +1197,7 @@ public final class Matrix4f implements Savable, Cloneable {
      *\r
      * @param vec\r
      *            vec to multiply against.\r
-     * @param store\r
-     *            a vector to store the result in.  created if null is passed.\r
+     * \r
      * @return the rotated vector.\r
      */\r
     public Vector4f multAcross(Vector4f vec) {\r
index a70d9c9..5f3c53b 100644 (file)
@@ -455,7 +455,8 @@ public final class Ray implements Savable, Cloneable, Collidable {
      * <code>getLimit</code> returns the limit or the ray, aka the length.\r
      * If the limit is not infinity, then this ray is a line with length <code>\r
      * limit</code>.\r
-     * @return\r
+     * \r
+     * @return the limit or the ray, aka the length.\r
      */\r
     public float getLimit(){\r
         return limit;\r
index 942ad39..d08d4f7 100644 (file)
@@ -277,7 +277,6 @@ public class Spline implements Savable {
 
     /**
      * returns the curve tension
-     * @return
      */
     public float getCurveTension() {
         return curveTension;
@@ -297,7 +296,6 @@ public class Spline implements Savable {
 
     /**
      * returns true if the spline cycle
-     * @return
      */
     public boolean isCycle() {
         return cycle;
@@ -326,7 +324,6 @@ public class Spline implements Savable {
 
     /**
      * return the total lenght of the spline
-     * @return
      */
     public float getTotalLength() {
         return totalLength;
@@ -334,7 +331,6 @@ public class Spline implements Savable {
 
     /**
      * return the type of the spline
-     * @return
      */
     public SplineType getType() {
         return type;
@@ -351,7 +347,6 @@ public class Spline implements Savable {
 
     /**
      * returns this spline control points
-     * @return
      */
     public List<Vector3f> getControlPoints() {
         return controlPoints;
@@ -359,7 +354,6 @@ public class Spline implements Savable {
 
     /**
      * returns a list of float representing the segments lenght
-     * @return
      */
     public List<Float> getSegmentsLength() {
         return segmentsLength;
index 81028b0..0c05a3b 100644 (file)
@@ -29,7 +29,6 @@
  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
  */\r
-\r
 package com.jme3.math;\r
 \r
 import com.jme3.export.JmeExporter;\r
@@ -50,15 +49,13 @@ public class Triangle extends AbstractTriangle implements Savable {
     private Vector3f pointa = new Vector3f();\r
     private Vector3f pointb = new Vector3f();\r
     private Vector3f pointc = new Vector3f();\r
-    \r
     private transient Vector3f center;\r
     private transient Vector3f normal;\r
-    \r
     private float projection;\r
-    \r
     private int index;\r
-    \r
-    public Triangle() {} \r
+\r
+    public Triangle() {\r
+    }\r
 \r
     /**\r
      * Constructor instantiates a new <Code>Triangle</code> object with the\r
@@ -84,25 +81,29 @@ public class Triangle extends AbstractTriangle implements Savable {
      */\r
     public Vector3f get(int i) {\r
         switch (i) {\r
-        case 0: return pointa;\r
-        case 1: return pointb;\r
-        case 2: return pointc;\r
-        default: return null;\r
+            case 0:\r
+                return pointa;\r
+            case 1:\r
+                return pointb;\r
+            case 2:\r
+                return pointc;\r
+            default:\r
+                return null;\r
         }\r
     }\r
 \r
-    public Vector3f get1(){\r
+    public Vector3f get1() {\r
         return pointa;\r
     }\r
 \r
-    public Vector3f get2(){\r
+    public Vector3f get2() {\r
         return pointb;\r
     }\r
 \r
-    public Vector3f get3(){\r
+    public Vector3f get3() {\r
         return pointc;\r
     }\r
-    \r
+\r
     /**\r
      *\r
      * <code>set</code> sets one of the triangles points to that specified as\r
@@ -112,9 +113,15 @@ public class Triangle extends AbstractTriangle implements Savable {
      */\r
     public void set(int i, Vector3f point) {\r
         switch (i) {\r
-        case 0: pointa.set(point); break;\r
-        case 1: pointb.set(point); break;\r
-        case 2: pointc.set(point); break;\r
+            case 0:\r
+                pointa.set(point);\r
+                break;\r
+            case 1:\r
+                pointb.set(point);\r
+                break;\r
+            case 2:\r
+                pointc.set(point);\r
+                break;\r
         }\r
     }\r
 \r
@@ -123,68 +130,77 @@ public class Triangle extends AbstractTriangle implements Savable {
      * <code>set</code> sets one of the triangles points to that specified as\r
      * a parameter.\r
      * @param i the index to place the point.\r
-     * @param point the point to set.\r
      */\r
     public void set(int i, float x, float y, float z) {\r
         switch (i) {\r
-        case 0: pointa.set(x,y,z); break;\r
-        case 1: pointb.set(x,y,z); break;\r
-        case 2: pointc.set(x,y,z); break;\r
+            case 0:\r
+                pointa.set(x, y, z);\r
+                break;\r
+            case 1:\r
+                pointb.set(x, y, z);\r
+                break;\r
+            case 2:\r
+                pointc.set(x, y, z);\r
+                break;\r
         }\r
     }\r
 \r
-    public void set1(Vector3f v){\r
+    public void set1(Vector3f v) {\r
         pointa.set(v);\r
     }\r
 \r
-    public void set2(Vector3f v){\r
+    public void set2(Vector3f v) {\r
         pointb.set(v);\r
     }\r
 \r
-    public void set3(Vector3f v){\r
+    public void set3(Vector3f v) {\r
         pointc.set(v);\r
     }\r
 \r
-    public void set(Vector3f v1, Vector3f v2, Vector3f v3){\r
+    public void set(Vector3f v1, Vector3f v2, Vector3f v3) {\r
         pointa.set(v1);\r
         pointb.set(v2);\r
         pointc.set(v3);\r
     }\r
-    \r
+\r
     /**\r
      * calculateCenter finds the average point of the triangle. \r
      *\r
      */\r
     public void calculateCenter() {\r
-        if (center == null)\r
+        if (center == null) {\r
             center = new Vector3f(pointa);\r
-        else center.set(pointa);\r
+        } else {\r
+            center.set(pointa);\r
+        }\r
         center.addLocal(pointb).addLocal(pointc).multLocal(FastMath.ONE_THIRD);\r
     }\r
-    \r
+\r
     /**\r
      * calculateCenter finds the average point of the triangle. \r
      *\r
      */\r
     public void calculateNormal() {\r
-        if (normal == null)\r
+        if (normal == null) {\r
             normal = new Vector3f(pointb);\r
-        else normal.set(pointb);\r
-        normal.subtractLocal(pointa).crossLocal(pointc.x-pointa.x, pointc.y-pointa.y, pointc.z-pointa.z);\r
+        } else {\r
+            normal.set(pointb);\r
+        }\r
+        normal.subtractLocal(pointa).crossLocal(pointc.x - pointa.x, pointc.y - pointa.y, pointc.z - pointa.z);\r
         normal.normalizeLocal();\r
     }\r
-    \r
+\r
     /**\r
      * obtains the center point of this triangle (average of the three triangles)\r
      * @return the center point.\r
      */\r
     public Vector3f getCenter() {\r
-       if(center == null) {\r
-               calculateCenter();\r
-       }\r
+        if (center == null) {\r
+            calculateCenter();\r
+        }\r
         return center;\r
     }\r
-    \r
+\r
     /**\r
      * sets the center point of this triangle (average of the three triangles)\r
      * @param center the center point.\r
@@ -192,7 +208,7 @@ public class Triangle extends AbstractTriangle implements Savable {
     public void setCenter(Vector3f center) {\r
         this.center = center;\r
     }\r
-    \r
+\r
     /**\r
      * obtains the unit length normal vector of this triangle, if set or\r
      * calculated\r
@@ -200,12 +216,12 @@ public class Triangle extends AbstractTriangle implements Savable {
      * @return the normal vector\r
      */\r
     public Vector3f getNormal() {\r
-       if(normal == null) {\r
-               calculateNormal();\r
-       }\r
+        if (normal == null) {\r
+            calculateNormal();\r
+        }\r
         return normal;\r
     }\r
-    \r
+\r
     /**\r
      * sets the normal vector of this triangle (to conform, must be unit length)\r
      * @param normal the normal vector.\r
@@ -213,7 +229,7 @@ public class Triangle extends AbstractTriangle implements Savable {
     public void setNormal(Vector3f normal) {\r
         this.normal = normal;\r
     }\r
-    \r
+\r
     /**\r
      * obtains the projection of the vertices relative to the line origin.\r
      * @return the projection of the triangle.\r
@@ -221,7 +237,7 @@ public class Triangle extends AbstractTriangle implements Savable {
     public float getProjection() {\r
         return this.projection;\r
     }\r
-    \r
+\r
     /**\r
      * sets the projection of the vertices relative to the line origin.\r
      * @param projection the projection of the triangle.\r
@@ -229,7 +245,7 @@ public class Triangle extends AbstractTriangle implements Savable {
     public void setProjection(float projection) {\r
         this.projection = projection;\r
     }\r
-    \r
+\r
     /**\r
      * obtains an index that this triangle represents if it is contained in a OBBTree.\r
      * @return the index in an OBBtree\r
@@ -237,7 +253,7 @@ public class Triangle extends AbstractTriangle implements Savable {
     public int getIndex() {\r
         return index;\r
     }\r
-    \r
+\r
     /**\r
      * sets an index that this triangle represents if it is contained in a OBBTree.\r
      * @param index the index in an OBBtree\r
@@ -246,13 +262,14 @@ public class Triangle extends AbstractTriangle implements Savable {
         this.index = index;\r
     }\r
 \r
-    public static Vector3f computeTriangleNormal(Vector3f v1, Vector3f v2, Vector3f v3, Vector3f store){\r
-        if (store == null)\r
+    public static Vector3f computeTriangleNormal(Vector3f v1, Vector3f v2, Vector3f v3, Vector3f store) {\r
+        if (store == null) {\r
             store = new Vector3f(v2);\r
-        else\r
+        } else {\r
             store.set(v2);\r
+        }\r
 \r
-        store.subtractLocal(v1).crossLocal(v3.x-v1.x, v3.y-v1.y, v3.z-v1.z);\r
+        store.subtractLocal(v1).crossLocal(v3.x - v1.x, v3.y - v1.y, v3.z - v1.z);\r
         return store.normalizeLocal();\r
     }\r
 \r
@@ -263,11 +280,11 @@ public class Triangle extends AbstractTriangle implements Savable {
     }\r
 \r
     public void read(JmeImporter e) throws IOException {\r
-        pointa = (Vector3f)e.getCapsule(this).readSavable("pointa", Vector3f.ZERO.clone());\r
-        pointb = (Vector3f)e.getCapsule(this).readSavable("pointb", Vector3f.ZERO.clone());\r
-        pointc = (Vector3f)e.getCapsule(this).readSavable("pointc", Vector3f.ZERO.clone());\r
+        pointa = (Vector3f) e.getCapsule(this).readSavable("pointa", Vector3f.ZERO.clone());\r
+        pointb = (Vector3f) e.getCapsule(this).readSavable("pointb", Vector3f.ZERO.clone());\r
+        pointc = (Vector3f) e.getCapsule(this).readSavable("pointc", Vector3f.ZERO.clone());\r
     }\r
-    \r
+\r
     @Override\r
     public Triangle clone() {\r
         try {\r
index 05a0974..fd745a5 100644 (file)
@@ -320,7 +320,8 @@ public final class Vector2f implements Savable, Cloneable {
      * <code>distanceSquared</code> calculates the distance squared between
      * this vector and vector v.
      *
-     * @param v the second vector to determine the distance squared.
+     * @param otherX The X coordinate of the v vector
+     * @param otherY The Y coordinate of the v vector
      * @return the distance squared between the two vectors.
      */
     public float distanceSquared(float otherX, float otherY) {
index 8069088..d71ebcb 100644 (file)
@@ -677,7 +677,7 @@ public final class Vector4f implements Savable, Cloneable {
      *            the y value to subtract.
      * @param subtractZ
      *            the z value to subtract.
-     * @param subtract@
+     * @param subtractW
      *            the w value to subtract.
      * @return this
      */
index 382935b..93e65b2 100644 (file)
@@ -189,9 +189,10 @@ public abstract class Filter implements Savable {
     public abstract void cleanUpFilter(Renderer r);
 
     /**
-     * this method should return the material used for this filter.
-     * this method is called every frames
-     * @return
+     * Returns the material used for this filter.
+     * this method is called every frame.
+     * 
+     * @return the material used for this filter.
      */
     public abstract Material getMaterial();
 
@@ -232,16 +233,14 @@ public abstract class Filter implements Savable {
     }
 
     /**
-     * Override this method if you want to load extra properties when the filter is loaded else only basic properties of the filter will be loaded
-     * This method should always begin by super.read(ex);
-     * @param ex
-     * @throws IOException
+     * Override this method if you want to load extra properties when the filter 
+     * is loaded else only basic properties of the filter will be loaded
+     * This method should always begin by super.read(im);
      */
     public void read(JmeImporter im) throws IOException {
         InputCapsule ic = im.getCapsule(this);
         name = ic.readString("name", "");
         enabled = ic.readBoolean("enabled", true);
-
     }
 
     public String getName() {
@@ -269,8 +268,9 @@ public abstract class Filter implements Savable {
     }
 
     /**
-     * Override this method and retrun true if your Filter need the depth texture
-     * @return
+     * Override this method and return true if your Filter need the depth texture
+     * 
+     * @return true if your Filter need the depth texture
      */
     public boolean isRequiresDepthTexture() {
         return false;
@@ -278,7 +278,8 @@ public abstract class Filter implements Savable {
     
      /**
      * Override this method and return false if your Filter does not need the scene texture
-     * @return
+     * 
+     * @return false if your Filter does not need the scene texture
      */
     public boolean isRequiresSceneTexture() {
         return true;
index 75b2b28..982e630 100644 (file)
@@ -599,7 +599,6 @@ public class Camera implements Savable, Cloneable {
      * <code>setLocation</code> sets the position of the camera.
      *
      * @param location the position of the camera.
-     * @see Camera#setLocation(com.jme.math.Vector3f)
      */
     public void setLocation(Vector3f location) {
         this.location.set(location);
@@ -660,7 +659,8 @@ public class Camera implements Savable, Cloneable {
      * @param left      the left axis of the camera.
      * @param up        the up axis of the camera.
      * @param direction the direction the camera is facing.
-     * @see Camera#setAxes(com.jme.math.Vector3f,com.jme.math.Vector3f,com.jme.math.Vector3f)
+     * 
+     * @see Camera#setAxes(com.jme3.math.Quaternion) 
      */
     public void setAxes(Vector3f left, Vector3f up, Vector3f direction) {
         this.rotation.fromAxes(left, up, direction);
index 0db7473..43c928b 100644 (file)
@@ -154,9 +154,8 @@ public abstract class GLObject implements Cloneable {
     /**
      * This should create a deep clone. For a shallow clone, use
      * createDestructableClone().
-     *
-     * @return
      */
+    @Override
     protected GLObject clone(){
         try{
             GLObject obj = (GLObject) super.clone();
index f9cecbf..54108e7 100644 (file)
@@ -181,9 +181,6 @@ public class RenderManager {
     /**
      * Creates a new viewport, to display the given camera's content.
      * The view will be processed before the primary viewport.
-     * @param viewName
-     * @param cam
-     * @return
      */
     public ViewPort createPreView(String viewName, Camera cam) {
         ViewPort vp = new ViewPort(viewName, cam);
@@ -491,9 +488,6 @@ public class RenderManager {
 
     /**
      * Render scene graph
-     * @param s
-     * @param r
-     * @param cam
      */
     public void renderScene(Spatial scene, ViewPort vp) {
         if (scene.getParent() == null) {
index 88202a0..83ca856 100644 (file)
@@ -99,7 +99,7 @@ public interface Renderer {
     public void onFrame();
 
     /**
-     * @param transform The world transform to use. This changes
+     * @param worldMatrix The world transform to use. This changes
      * the world matrix given in the shader.
      */
     public void setWorldMatrix(Matrix4f worldMatrix);
@@ -171,7 +171,6 @@ public interface Renderer {
 
     /**
      * Deletes a texture from the GPU.
-     * @param tex
      */
     public void deleteImage(Image image);
 
index 858b4f6..0254d26 100644 (file)
@@ -70,10 +70,10 @@ public class GeometryList {
     }
 
     /**
-     * Adds a spatial to the list. List size is doubled if there is no room.
+     * Adds a geometry to the list. List size is doubled if there is no room.
      *
-     * @param s
-     *            The spatial to add.
+     * @param g
+     *            The geometry to add.
      */
     public void add(Geometry g) {
         if (size == geometries.length) {
index afa143f..a9635f5 100644 (file)
@@ -177,7 +177,7 @@ public class Geometry extends Spatial {
      * this geometry. The location of the geometry is based on the location of
      * all this node's parents.
      *
-     * @see com.jme.scene.Spatial#updateWorldBound()
+     * @see Spatial#updateWorldBound()
      */
     @Override
     protected void updateWorldBound() {
@@ -282,7 +282,6 @@ public class Geometry extends Spatial {
      * Exception: if the mesh is marked as being a software
      * animated mesh, (bind pose is set) then the positions
      * and normals are deep copied.
-     * @return
      */
     @Override
     public Geometry clone(boolean cloneMaterial){
@@ -308,8 +307,8 @@ public class Geometry extends Spatial {
      * Exception: if the mesh is marked as being a software
      * animated mesh, (bind pose is set) then the positions
      * and normals are deep copied.
-     * @return
      */
+    @Override
     public Geometry clone(){
         return clone(true);
     }
@@ -318,7 +317,6 @@ public class Geometry extends Spatial {
      * Creates a deep clone of the geometry,
      * this creates an identical copy of the mesh
      * with the vertexbuffer data duplicated.
-     * @return
      */
     @Override
     public Spatial deepClone(){
index a9a54fd..46142ed 100644 (file)
@@ -526,7 +526,7 @@ public class Node extends Spatial implements Savable {
      * @return Non-null, but possibly 0-element, list of matching Spatials (also Instances extending Spatials).
      *
      * @see java.util.regex.Pattern
-     * @see Spatial#matches(Class<? extends Spatial>, String)
+     * @see Spatial#matches(java.lang.Class, java.lang.String) 
      */
     @SuppressWarnings("unchecked")
     public <T extends Spatial>List<T> descendantMatches(
@@ -546,7 +546,7 @@ public class Node extends Spatial implements Savable {
     /**
      * Convenience wrapper.
      *
-     * @see #descendantMatches(Class<? extends Spatial>, String)
+     * @see #descendantMatches(java.lang.Class, java.lang.String) 
      */
     public <T extends Spatial>List<T> descendantMatches(
             Class<T> spatialSubclass) {
@@ -556,7 +556,7 @@ public class Node extends Spatial implements Savable {
     /**
      * Convenience wrapper.
      *
-     * @see #descendantMatches(Class<? extends Spatial>, String)
+     * @see #descendantMatches(java.lang.Class, java.lang.String) 
      */
     public <T extends Spatial>List<T> descendantMatches(String nameRegex) {
         return descendantMatches(null, nameRegex);
index 75189ef..b78e0bf 100644 (file)
@@ -784,9 +784,6 @@ public abstract class Spatial implements Savable, Cloneable, Collidable {
 
     /**
      * <code>setLocalScale</code> sets the local scale of this node.
-     *
-     * @param localScale
-     *            the new local scale
      */
     public void setLocalScale(float x, float y, float z) {
         localTransform.setScale(x, y, z);
index 7526708..858b05d 100644 (file)
@@ -664,11 +664,6 @@ public class VertexBuffer extends GLObject implements Savable, Cloneable {
      * of the parameters. The buffer will be of the type specified by
      * {@link Format format} and would be able to contain the given number
      * of elements with the given number of components in each element.
-     *
-     * @param format
-     * @param components
-     * @param numElements
-     * @return
      */
     public static Buffer createBuffer(Format format, int components, int numElements){
         if (components < 1 || components > 4)
index c54fb34..6be46a3 100644 (file)
@@ -48,7 +48,7 @@ public interface Control extends Savable {
      * Creates a clone of the Control, the given Spatial is the cloned
      * version of the spatial to which this control is attached to.
      * @param spatial
-     * @return
+     * @return A clone of this control for the spatial
      */
     public Control cloneForSpatial(Spatial spatial);
 
index a0fcfca..2265159 100644 (file)
@@ -76,14 +76,14 @@ public class LightControl extends AbstractControl {
     }
 
     /**
-     * @param camera The Camera to be synced.
+     * @param light The light to be synced.
      */
     public LightControl(Light light) {
         this.light = light;
     }
 
     /**
-     * @param camera The Camera to be synced.
+     * @param light The light to be synced.
      */
     public LightControl(Light light, ControlDirection controlDir) {
         this.light = light;
index 2670e4c..6c6109b 100644 (file)
@@ -380,7 +380,6 @@ public final class Shader extends GLObject implements Savable {
     /**\r
      * Returns true if this program and all it's shaders have been compiled,\r
      * linked and validated successfuly.\r
-     * @return\r
      */\r
     public boolean isUsable(){\r
         return usable;\r
@@ -417,7 +416,6 @@ public final class Shader extends GLObject implements Savable {
     /**\r
      * Called by the object manager to reset all object IDs. This causes\r
      * the shader to be reuploaded to the GPU incase the display was restarted.\r
-     * @param r\r
      */\r
     @Override\r
     public void resetObject() {\r
index 37283a5..57a341e 100644 (file)
@@ -37,6 +37,7 @@ import com.jme3.input.KeyInput;
 import com.jme3.input.MouseInput;
 import com.jme3.input.TouchInput;
 import com.jme3.renderer.Renderer;
+import com.jme3.system.JmeCanvasContext;
 
 /**
  * Represents a rendering context within the engine.