Large blender importer refactoring:
- bleder features separated between different packages - refactoring of modifier system (each modifier now in a separate class) - refactoring of constraints system (each constraint now in a separate class) - no converter interface - every helper supports versions 2.49 and 2.5+. git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7953 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
This commit is contained in:
parent
21f09ad716
commit
1e7b7860fe
@ -29,14 +29,15 @@
|
|||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
package com.jme3.scene.plugins.blender.utils;
|
package com.jme3.scene.plugins.blender;
|
||||||
|
|
||||||
import java.nio.FloatBuffer;
|
import java.nio.FloatBuffer;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.jme3.scene.plugins.blender.data.Structure;
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
import com.jme3.scene.plugins.blender.exception.BlenderFileException;
|
import com.jme3.scene.plugins.blender.file.Pointer;
|
||||||
import com.jme3.scene.plugins.blender.structures.Properties;
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
import com.jme3.scene.plugins.blender.objects.Properties;
|
||||||
import com.jme3.util.BufferUtils;
|
import com.jme3.util.BufferUtils;
|
||||||
|
|
||||||
/**
|
/**
|
@ -47,25 +47,22 @@ import com.jme3.asset.ModelKey;
|
|||||||
import com.jme3.light.Light;
|
import com.jme3.light.Light;
|
||||||
import com.jme3.renderer.Camera;
|
import com.jme3.renderer.Camera;
|
||||||
import com.jme3.scene.Node;
|
import com.jme3.scene.Node;
|
||||||
import com.jme3.scene.plugins.blender.data.FileBlockHeader;
|
import com.jme3.scene.plugins.blender.animations.ArmatureHelper;
|
||||||
import com.jme3.scene.plugins.blender.data.Structure;
|
import com.jme3.scene.plugins.blender.animations.IpoHelper;
|
||||||
import com.jme3.scene.plugins.blender.exception.BlenderFileException;
|
import com.jme3.scene.plugins.blender.cameras.CameraHelper;
|
||||||
import com.jme3.scene.plugins.blender.helpers.ArmatureHelper;
|
import com.jme3.scene.plugins.blender.constraints.ConstraintHelper;
|
||||||
import com.jme3.scene.plugins.blender.helpers.CameraHelper;
|
import com.jme3.scene.plugins.blender.curves.CurvesHelper;
|
||||||
import com.jme3.scene.plugins.blender.helpers.ConstraintHelper;
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
import com.jme3.scene.plugins.blender.helpers.CurvesHelper;
|
import com.jme3.scene.plugins.blender.file.BlenderInputStream;
|
||||||
import com.jme3.scene.plugins.blender.helpers.IpoHelper;
|
import com.jme3.scene.plugins.blender.file.FileBlockHeader;
|
||||||
import com.jme3.scene.plugins.blender.helpers.LightHelper;
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
import com.jme3.scene.plugins.blender.helpers.MaterialHelper;
|
import com.jme3.scene.plugins.blender.lights.LightHelper;
|
||||||
import com.jme3.scene.plugins.blender.helpers.MeshHelper;
|
import com.jme3.scene.plugins.blender.materials.MaterialHelper;
|
||||||
import com.jme3.scene.plugins.blender.helpers.ModifierHelper;
|
import com.jme3.scene.plugins.blender.meshes.MeshHelper;
|
||||||
import com.jme3.scene.plugins.blender.helpers.NoiseHelper;
|
import com.jme3.scene.plugins.blender.modifiers.ModifierHelper;
|
||||||
import com.jme3.scene.plugins.blender.helpers.ObjectHelper;
|
import com.jme3.scene.plugins.blender.objects.ObjectHelper;
|
||||||
import com.jme3.scene.plugins.blender.helpers.ParticlesHelper;
|
import com.jme3.scene.plugins.blender.particles.ParticlesHelper;
|
||||||
import com.jme3.scene.plugins.blender.helpers.TextureHelper;
|
import com.jme3.scene.plugins.blender.textures.TextureHelper;
|
||||||
import com.jme3.scene.plugins.blender.utils.BlenderInputStream;
|
|
||||||
import com.jme3.scene.plugins.blender.utils.DataRepository;
|
|
||||||
import com.jme3.scene.plugins.blender.utils.JmeConverter;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the main loading class. Have in notice that asset manager needs to have loaders for resources like textures.
|
* This is the main loading class. Have in notice that asset manager needs to have loaders for resources like textures.
|
||||||
@ -111,7 +108,6 @@ public class BlenderLoader implements AssetLoader {
|
|||||||
dataRepository.putHelper(MaterialHelper.class, new MaterialHelper(inputStream.getVersionNumber()));
|
dataRepository.putHelper(MaterialHelper.class, new MaterialHelper(inputStream.getVersionNumber()));
|
||||||
dataRepository.putHelper(ConstraintHelper.class, new ConstraintHelper(inputStream.getVersionNumber(), dataRepository));
|
dataRepository.putHelper(ConstraintHelper.class, new ConstraintHelper(inputStream.getVersionNumber(), dataRepository));
|
||||||
dataRepository.putHelper(IpoHelper.class, new IpoHelper(inputStream.getVersionNumber()));
|
dataRepository.putHelper(IpoHelper.class, new IpoHelper(inputStream.getVersionNumber()));
|
||||||
dataRepository.putHelper(NoiseHelper.class, new NoiseHelper(inputStream.getVersionNumber()));
|
|
||||||
dataRepository.putHelper(ParticlesHelper.class, new ParticlesHelper(inputStream.getVersionNumber()));
|
dataRepository.putHelper(ParticlesHelper.class, new ParticlesHelper(inputStream.getVersionNumber()));
|
||||||
|
|
||||||
//setting additional data to helpers
|
//setting additional data to helpers
|
||||||
|
@ -45,24 +45,21 @@ import com.jme3.asset.BlenderKey.LoadingResults;
|
|||||||
import com.jme3.asset.ModelKey;
|
import com.jme3.asset.ModelKey;
|
||||||
import com.jme3.scene.Node;
|
import com.jme3.scene.Node;
|
||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.scene.plugins.blender.data.FileBlockHeader;
|
import com.jme3.scene.plugins.blender.animations.ArmatureHelper;
|
||||||
import com.jme3.scene.plugins.blender.exception.BlenderFileException;
|
import com.jme3.scene.plugins.blender.animations.IpoHelper;
|
||||||
import com.jme3.scene.plugins.blender.helpers.ArmatureHelper;
|
import com.jme3.scene.plugins.blender.cameras.CameraHelper;
|
||||||
import com.jme3.scene.plugins.blender.helpers.CameraHelper;
|
import com.jme3.scene.plugins.blender.constraints.ConstraintHelper;
|
||||||
import com.jme3.scene.plugins.blender.helpers.ConstraintHelper;
|
import com.jme3.scene.plugins.blender.curves.CurvesHelper;
|
||||||
import com.jme3.scene.plugins.blender.helpers.CurvesHelper;
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
import com.jme3.scene.plugins.blender.helpers.IpoHelper;
|
import com.jme3.scene.plugins.blender.file.BlenderInputStream;
|
||||||
import com.jme3.scene.plugins.blender.helpers.LightHelper;
|
import com.jme3.scene.plugins.blender.file.FileBlockHeader;
|
||||||
import com.jme3.scene.plugins.blender.helpers.MaterialHelper;
|
import com.jme3.scene.plugins.blender.lights.LightHelper;
|
||||||
import com.jme3.scene.plugins.blender.helpers.MeshHelper;
|
import com.jme3.scene.plugins.blender.materials.MaterialHelper;
|
||||||
import com.jme3.scene.plugins.blender.helpers.ModifierHelper;
|
import com.jme3.scene.plugins.blender.meshes.MeshHelper;
|
||||||
import com.jme3.scene.plugins.blender.helpers.NoiseHelper;
|
import com.jme3.scene.plugins.blender.modifiers.ModifierHelper;
|
||||||
import com.jme3.scene.plugins.blender.helpers.ObjectHelper;
|
import com.jme3.scene.plugins.blender.objects.ObjectHelper;
|
||||||
import com.jme3.scene.plugins.blender.helpers.ParticlesHelper;
|
import com.jme3.scene.plugins.blender.particles.ParticlesHelper;
|
||||||
import com.jme3.scene.plugins.blender.helpers.TextureHelper;
|
import com.jme3.scene.plugins.blender.textures.TextureHelper;
|
||||||
import com.jme3.scene.plugins.blender.utils.BlenderInputStream;
|
|
||||||
import com.jme3.scene.plugins.blender.utils.DataRepository;
|
|
||||||
import com.jme3.scene.plugins.blender.utils.JmeConverter;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the main loading class. Have in notice that asset manager needs to have loaders for resources like textures.
|
* This is the main loading class. Have in notice that asset manager needs to have loaders for resources like textures.
|
||||||
@ -104,7 +101,6 @@ public class BlenderModelLoader implements AssetLoader {
|
|||||||
dataRepository.putHelper(MaterialHelper.class, new MaterialHelper(inputStream.getVersionNumber()));
|
dataRepository.putHelper(MaterialHelper.class, new MaterialHelper(inputStream.getVersionNumber()));
|
||||||
dataRepository.putHelper(ConstraintHelper.class, new ConstraintHelper(inputStream.getVersionNumber(), dataRepository));
|
dataRepository.putHelper(ConstraintHelper.class, new ConstraintHelper(inputStream.getVersionNumber(), dataRepository));
|
||||||
dataRepository.putHelper(IpoHelper.class, new IpoHelper(inputStream.getVersionNumber()));
|
dataRepository.putHelper(IpoHelper.class, new IpoHelper(inputStream.getVersionNumber()));
|
||||||
dataRepository.putHelper(NoiseHelper.class, new NoiseHelper(inputStream.getVersionNumber()));
|
|
||||||
dataRepository.putHelper(ParticlesHelper.class, new ParticlesHelper(inputStream.getVersionNumber()));
|
dataRepository.putHelper(ParticlesHelper.class, new ParticlesHelper(inputStream.getVersionNumber()));
|
||||||
|
|
||||||
//setting additional data to helpers
|
//setting additional data to helpers
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
package com.jme3.scene.plugins.blender.utils;
|
package com.jme3.scene.plugins.blender;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.EmptyStackException;
|
import java.util.EmptyStackException;
|
||||||
@ -42,11 +42,13 @@ import com.jme3.asset.AssetManager;
|
|||||||
import com.jme3.asset.BlenderKey;
|
import com.jme3.asset.BlenderKey;
|
||||||
import com.jme3.material.Material;
|
import com.jme3.material.Material;
|
||||||
import com.jme3.math.ColorRGBA;
|
import com.jme3.math.ColorRGBA;
|
||||||
import com.jme3.scene.plugins.blender.data.DnaBlockData;
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
import com.jme3.scene.plugins.blender.data.FileBlockHeader;
|
import com.jme3.scene.plugins.blender.constraints.Constraint;
|
||||||
import com.jme3.scene.plugins.blender.data.Structure;
|
import com.jme3.scene.plugins.blender.file.BlenderInputStream;
|
||||||
import com.jme3.scene.plugins.blender.structures.Ipo;
|
import com.jme3.scene.plugins.blender.file.DnaBlockData;
|
||||||
import com.jme3.scene.plugins.blender.structures.Modifier;
|
import com.jme3.scene.plugins.blender.file.FileBlockHeader;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
import com.jme3.scene.plugins.blender.modifiers.Modifier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The class that stores temporary data and manages it during loading the belnd file. This class is intended to be used
|
* The class that stores temporary data and manages it during loading the belnd file. This class is intended to be used
|
||||||
@ -84,6 +86,8 @@ public class DataRepository {
|
|||||||
private Map<Long, Ipo> loadedIpos = new HashMap<Long, Ipo>();
|
private Map<Long, Ipo> loadedIpos = new HashMap<Long, Ipo>();
|
||||||
/** A list of modifiers for the specified object. */
|
/** A list of modifiers for the specified object. */
|
||||||
protected Map<Long, List<Modifier>> modifiers = new HashMap<Long, List<Modifier>>();
|
protected Map<Long, List<Modifier>> modifiers = new HashMap<Long, List<Modifier>>();
|
||||||
|
/** A list of constraints for the specified object. */
|
||||||
|
protected Map<Long, List<Constraint>> constraints = new HashMap<Long, List<Constraint>>();
|
||||||
/** A map og helpers that perform loading. */
|
/** A map og helpers that perform loading. */
|
||||||
private Map<String, AbstractBlenderHelper> helpers = new HashMap<String, AbstractBlenderHelper>();
|
private Map<String, AbstractBlenderHelper> helpers = new HashMap<String, AbstractBlenderHelper>();
|
||||||
|
|
||||||
@ -330,18 +334,16 @@ public class DataRepository {
|
|||||||
* This method adds a new modifier to the list.
|
* This method adds a new modifier to the list.
|
||||||
* @param ownerOMA
|
* @param ownerOMA
|
||||||
* the owner's old memory address
|
* the owner's old memory address
|
||||||
* @param modifierType
|
* @param modifier
|
||||||
* the type of the modifier
|
* the object's modifier
|
||||||
* @param loadedModifier
|
|
||||||
* the loaded modifier object
|
|
||||||
*/
|
*/
|
||||||
public void addModifier(Long ownerOMA, String modifierType, Object loadedModifier, Object additionalModifierData) {
|
public void addModifier(Long ownerOMA, Modifier modifier) {
|
||||||
List<Modifier> objectModifiers = this.modifiers.get(ownerOMA);
|
List<Modifier> objectModifiers = this.modifiers.get(ownerOMA);
|
||||||
if (objectModifiers == null) {
|
if (objectModifiers == null) {
|
||||||
objectModifiers = new ArrayList<Modifier>();
|
objectModifiers = new ArrayList<Modifier>();
|
||||||
this.modifiers.put(ownerOMA, objectModifiers);
|
this.modifiers.put(ownerOMA, objectModifiers);
|
||||||
}
|
}
|
||||||
objectModifiers.add(new Modifier(modifierType, loadedModifier, additionalModifierData));
|
objectModifiers.add(modifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -365,6 +367,33 @@ public class DataRepository {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method adds a new modifier to the list.
|
||||||
|
* @param ownerOMA
|
||||||
|
* the owner's old memory address
|
||||||
|
* @param constraints
|
||||||
|
* the object's constraints
|
||||||
|
*/
|
||||||
|
public void addConstraints(Long ownerOMA, List<Constraint> constraints) {
|
||||||
|
List<Constraint> objectConstraints = this.constraints.get(ownerOMA);
|
||||||
|
if (objectConstraints == null) {
|
||||||
|
objectConstraints = new ArrayList<Constraint>();
|
||||||
|
this.constraints.put(ownerOMA, objectConstraints);
|
||||||
|
}
|
||||||
|
objectConstraints.addAll(constraints);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns constraints for the object specified by its old memory address. If no
|
||||||
|
* modifiers are found - <b>null</b> is returned.
|
||||||
|
* @param objectOMA
|
||||||
|
* object's old memory address
|
||||||
|
* @return the list of object's modifiers or null
|
||||||
|
*/
|
||||||
|
public List<Constraint> getConstraints(Long objectOMA) {
|
||||||
|
return constraints.get(objectOMA);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This metod returns the default material.
|
* This metod returns the default material.
|
@ -29,7 +29,7 @@
|
|||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
package com.jme3.scene.plugins.blender.utils;
|
package com.jme3.scene.plugins.blender;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -42,19 +42,19 @@ import com.jme3.math.ColorRGBA;
|
|||||||
import com.jme3.renderer.Camera;
|
import com.jme3.renderer.Camera;
|
||||||
import com.jme3.scene.Geometry;
|
import com.jme3.scene.Geometry;
|
||||||
import com.jme3.scene.Node;
|
import com.jme3.scene.Node;
|
||||||
import com.jme3.scene.plugins.blender.data.Structure;
|
import com.jme3.scene.plugins.blender.cameras.CameraHelper;
|
||||||
import com.jme3.scene.plugins.blender.exception.BlenderFileException;
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
import com.jme3.scene.plugins.blender.helpers.CameraHelper;
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
import com.jme3.scene.plugins.blender.helpers.LightHelper;
|
import com.jme3.scene.plugins.blender.lights.LightHelper;
|
||||||
import com.jme3.scene.plugins.blender.helpers.MaterialHelper;
|
import com.jme3.scene.plugins.blender.materials.MaterialHelper;
|
||||||
import com.jme3.scene.plugins.blender.helpers.MeshHelper;
|
import com.jme3.scene.plugins.blender.meshes.MeshHelper;
|
||||||
import com.jme3.scene.plugins.blender.helpers.ObjectHelper;
|
import com.jme3.scene.plugins.blender.objects.ObjectHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class converts blender file blocks into jMonkeyEngine data structures.
|
* This class converts blender file blocks into jMonkeyEngine data structures.
|
||||||
* @author Marcin Roguski
|
* @author Marcin Roguski
|
||||||
*/
|
*/
|
||||||
public class JmeConverter implements BlenderConverter<Node, Camera, Light, Object, List<Geometry>, Material> {
|
/*package*/ class JmeConverter {
|
||||||
|
|
||||||
private final DataRepository dataRepository;
|
private final DataRepository dataRepository;
|
||||||
|
|
||||||
@ -84,7 +84,6 @@ public class JmeConverter implements BlenderConverter<Node, Camera, Light, Objec
|
|||||||
this.dataRepository = dataRepository;
|
this.dataRepository = dataRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Node toScene(Structure structure) {//TODO: poprawny import sceny
|
public Node toScene(Structure structure) {//TODO: poprawny import sceny
|
||||||
if ((dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.SCENES) == 0) {
|
if ((dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.SCENES) == 0) {
|
||||||
return null;
|
return null;
|
||||||
@ -100,7 +99,6 @@ public class JmeConverter implements BlenderConverter<Node, Camera, Light, Objec
|
|||||||
return new Node(sceneName);
|
return new Node(sceneName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Camera toCamera(Structure structure) throws BlenderFileException {
|
public Camera toCamera(Structure structure) throws BlenderFileException {
|
||||||
CameraHelper cameraHelper = dataRepository.getHelper(CameraHelper.class);
|
CameraHelper cameraHelper = dataRepository.getHelper(CameraHelper.class);
|
||||||
if (cameraHelper.shouldBeLoaded(structure, dataRepository)) {
|
if (cameraHelper.shouldBeLoaded(structure, dataRepository)) {
|
||||||
@ -109,7 +107,6 @@ public class JmeConverter implements BlenderConverter<Node, Camera, Light, Objec
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Light toLight(Structure structure) throws BlenderFileException {
|
public Light toLight(Structure structure) throws BlenderFileException {
|
||||||
LightHelper lightHelper = dataRepository.getHelper(LightHelper.class);
|
LightHelper lightHelper = dataRepository.getHelper(LightHelper.class);
|
||||||
if (lightHelper.shouldBeLoaded(structure, dataRepository)) {
|
if (lightHelper.shouldBeLoaded(structure, dataRepository)) {
|
||||||
@ -118,7 +115,6 @@ public class JmeConverter implements BlenderConverter<Node, Camera, Light, Objec
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object toObject(Structure structure) throws BlenderFileException {
|
public Object toObject(Structure structure) throws BlenderFileException {
|
||||||
ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);
|
ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);
|
||||||
if(objectHelper.shouldBeLoaded(structure, dataRepository)) {
|
if(objectHelper.shouldBeLoaded(structure, dataRepository)) {
|
||||||
@ -127,7 +123,6 @@ public class JmeConverter implements BlenderConverter<Node, Camera, Light, Objec
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Geometry> toMesh(Structure structure) throws BlenderFileException {
|
public List<Geometry> toMesh(Structure structure) throws BlenderFileException {
|
||||||
MeshHelper meshHelper = dataRepository.getHelper(MeshHelper.class);
|
MeshHelper meshHelper = dataRepository.getHelper(MeshHelper.class);
|
||||||
if(meshHelper.shouldBeLoaded(structure, dataRepository)) {
|
if(meshHelper.shouldBeLoaded(structure, dataRepository)) {
|
||||||
@ -136,7 +131,6 @@ public class JmeConverter implements BlenderConverter<Node, Camera, Light, Objec
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Material toMaterial(Structure structure) throws BlenderFileException {
|
public Material toMaterial(Structure structure) throws BlenderFileException {
|
||||||
MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);
|
MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);
|
||||||
if (materialHelper.shouldBeLoaded(structure, dataRepository)) {
|
if (materialHelper.shouldBeLoaded(structure, dataRepository)) {
|
@ -29,7 +29,7 @@
|
|||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
package com.jme3.scene.plugins.blender.helpers.v249;
|
package com.jme3.scene.plugins.blender.animations;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -47,13 +47,15 @@ import com.jme3.math.Vector3f;
|
|||||||
import com.jme3.scene.Mesh;
|
import com.jme3.scene.Mesh;
|
||||||
import com.jme3.scene.VertexBuffer;
|
import com.jme3.scene.VertexBuffer;
|
||||||
import com.jme3.scene.VertexBuffer.Type;
|
import com.jme3.scene.VertexBuffer.Type;
|
||||||
import com.jme3.scene.plugins.blender.data.Structure;
|
import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
|
||||||
import com.jme3.scene.plugins.blender.exception.BlenderFileException;
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
import com.jme3.scene.plugins.blender.structures.Ipo;
|
import com.jme3.scene.plugins.blender.curves.BezierCurve;
|
||||||
import com.jme3.scene.plugins.blender.utils.AbstractBlenderHelper;
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
import com.jme3.scene.plugins.blender.utils.DataRepository;
|
import com.jme3.scene.plugins.blender.file.BlenderInputStream;
|
||||||
import com.jme3.scene.plugins.blender.utils.DynamicArray;
|
import com.jme3.scene.plugins.blender.file.DynamicArray;
|
||||||
import com.jme3.scene.plugins.blender.utils.Pointer;
|
import com.jme3.scene.plugins.blender.file.FileBlockHeader;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Pointer;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class defines the methods to calculate certain aspects of animation and armature functionalities.
|
* This class defines the methods to calculate certain aspects of animation and armature functionalities.
|
||||||
@ -62,15 +64,6 @@ import com.jme3.scene.plugins.blender.utils.Pointer;
|
|||||||
public class ArmatureHelper extends AbstractBlenderHelper {
|
public class ArmatureHelper extends AbstractBlenderHelper {
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(ArmatureHelper.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(ArmatureHelper.class.getName());
|
||||||
/**
|
|
||||||
* The map of the bones. Maps a bone name to its index in the armature. Should be cleared after the object had been
|
|
||||||
* read. TODO: probably bones can have identical names in different armatures
|
|
||||||
*/
|
|
||||||
protected Map<String, Integer> bonesMap = new HashMap<String, Integer>();
|
|
||||||
/** A map of bones and their old memory addresses. */
|
|
||||||
protected Map<Bone, Long> bonesOMAs = new HashMap<Bone, Long>();
|
|
||||||
/** This list contains bones hierarchy and their matrices. It is later converted into jme bones. */
|
|
||||||
protected List<BoneTransformationData> boneDataRoots = new ArrayList<BoneTransformationData>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This constructor parses the given blender version and stores the result. Some functionalities may differ in
|
* This constructor parses the given blender version and stores the result. Some functionalities may differ in
|
||||||
@ -82,6 +75,16 @@ public class ArmatureHelper extends AbstractBlenderHelper {
|
|||||||
super(blenderVersion);
|
super(blenderVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The map of the bones. Maps a bone name to its index in the armature. Should be cleared after the object had been
|
||||||
|
* read. TODO: probably bones can have identical names in different armatures
|
||||||
|
*/
|
||||||
|
protected Map<String, Integer> bonesMap = new HashMap<String, Integer>();
|
||||||
|
/** A map of bones and their old memory addresses. */
|
||||||
|
protected Map<Bone, Long> bonesOMAs = new HashMap<Bone, Long>();
|
||||||
|
/** This list contains bones hierarchy and their matrices. It is later converted into jme bones. */
|
||||||
|
protected List<BoneTransformationData> boneDataRoots = new ArrayList<BoneTransformationData>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns the old memory address of a bone. If the bone does not exist in the blend file - zero is
|
* This method returns the old memory address of a bone. If the bone does not exist in the blend file - zero is
|
||||||
* returned.
|
* returned.
|
||||||
@ -145,45 +148,6 @@ public class ArmatureHelper extends AbstractBlenderHelper {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This method reads the tracks of the armature object.
|
|
||||||
* @param actionStructure
|
|
||||||
* @param dataRepository
|
|
||||||
* the data repository
|
|
||||||
* @param objectName
|
|
||||||
* the name of animation owner
|
|
||||||
* @param animationName
|
|
||||||
* the name of the animation
|
|
||||||
* @return a list of tracks for the armature
|
|
||||||
* @throws BlenderFileException
|
|
||||||
* this exception is thrown when the blender file is somehow corrupted
|
|
||||||
*/
|
|
||||||
public BoneTrack[] getTracks(Structure actionStructure, DataRepository dataRepository, String objectName, String animationName) throws BlenderFileException {
|
|
||||||
LOGGER.log(Level.INFO, "Getting tracks!");
|
|
||||||
IpoHelper ipoHelper = dataRepository.getHelper(IpoHelper.class);
|
|
||||||
int fps = dataRepository.getBlenderKey().getFps();
|
|
||||||
int[] animationFrames = dataRepository.getBlenderKey().getAnimationFrames(objectName, animationName);
|
|
||||||
Structure chanbase = (Structure) actionStructure.getFieldValue("chanbase");
|
|
||||||
List<Structure> actionChannels = chanbase.evaluateListBase(dataRepository);//bActionChannel
|
|
||||||
if (actionChannels != null && actionChannels.size() > 0 && (bonesMap == null || bonesMap.size() == 0)) {
|
|
||||||
throw new IllegalStateException("No bones found! Cannot proceed to calculating tracks!");
|
|
||||||
}
|
|
||||||
List<BoneTrack> tracks = new ArrayList<BoneTrack>();
|
|
||||||
for (Structure bActionChannel : actionChannels) {
|
|
||||||
String name = bActionChannel.getFieldValue("name").toString();
|
|
||||||
Integer boneIndex = bonesMap.get(name);
|
|
||||||
if (boneIndex != null) {
|
|
||||||
Pointer p = (Pointer) bActionChannel.getFieldValue("ipo");
|
|
||||||
if (p.isNotNull()) {
|
|
||||||
Structure ipoStructure = p.fetchData(dataRepository.getInputStream()).get(0);
|
|
||||||
Ipo ipo = ipoHelper.createIpo(ipoStructure, dataRepository);
|
|
||||||
tracks.add(ipo.calculateTrack(boneIndex.intValue(), animationFrames[0], animationFrames[1], fps));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return tracks.toArray(new BoneTrack[tracks.size()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This bone returns transformation matrix of the bone that is relative to
|
* This bone returns transformation matrix of the bone that is relative to
|
||||||
* its armature object.
|
* its armature object.
|
||||||
@ -373,4 +337,116 @@ public class ArmatureHelper extends AbstractBlenderHelper {
|
|||||||
public boolean shouldBeLoaded(Structure structure, DataRepository dataRepository) {
|
public boolean shouldBeLoaded(Structure structure, DataRepository dataRepository) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BoneTrack[] getTracks(Structure actionStructure, DataRepository dataRepository, String objectName, String animationName) throws BlenderFileException {
|
||||||
|
if (blenderVersion < 250) {
|
||||||
|
return this.getTracks250(actionStructure, dataRepository, objectName, animationName);
|
||||||
|
} else {
|
||||||
|
return this.getTracks249(actionStructure, dataRepository, objectName, animationName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BoneTrack[] getTracks250(Structure actionStructure, DataRepository dataRepository, String objectName, String animationName) throws BlenderFileException {
|
||||||
|
LOGGER.log(Level.INFO, "Getting tracks!");
|
||||||
|
int fps = dataRepository.getBlenderKey().getFps();
|
||||||
|
int[] animationFrames = dataRepository.getBlenderKey().getAnimationFrames(objectName, animationName);
|
||||||
|
Structure groups = (Structure) actionStructure.getFieldValue("groups");
|
||||||
|
List<Structure> actionGroups = groups.evaluateListBase(dataRepository);//bActionGroup
|
||||||
|
if (actionGroups != null && actionGroups.size() > 0 && (bonesMap == null || bonesMap.size() == 0)) {
|
||||||
|
throw new IllegalStateException("No bones found! Cannot proceed to calculating tracks!");
|
||||||
|
}
|
||||||
|
|
||||||
|
List<BoneTrack> tracks = new ArrayList<BoneTrack>();
|
||||||
|
for (Structure actionGroup : actionGroups) {
|
||||||
|
String name = actionGroup.getFieldValue("name").toString();
|
||||||
|
Integer boneIndex = bonesMap.get(name);
|
||||||
|
if (boneIndex != null) {
|
||||||
|
List<Structure> channels = ((Structure) actionGroup.getFieldValue("channels")).evaluateListBase(dataRepository);
|
||||||
|
BezierCurve[] bezierCurves = new BezierCurve[channels.size()];
|
||||||
|
int channelCounter = 0;
|
||||||
|
for (Structure c : channels) {
|
||||||
|
//reading rna path first
|
||||||
|
BlenderInputStream bis = dataRepository.getInputStream();
|
||||||
|
int currentPosition = bis.getPosition();
|
||||||
|
Pointer pRnaPath = (Pointer) c.getFieldValue("rna_path");
|
||||||
|
FileBlockHeader dataFileBlock = dataRepository.getFileBlock(pRnaPath.getOldMemoryAddress());
|
||||||
|
bis.setPosition(dataFileBlock.getBlockPosition());
|
||||||
|
String rnaPath = bis.readString();
|
||||||
|
bis.setPosition(currentPosition);
|
||||||
|
int arrayIndex = ((Number) c.getFieldValue("array_index")).intValue();
|
||||||
|
int type = this.getCurveType(rnaPath, arrayIndex);
|
||||||
|
|
||||||
|
Pointer pBezTriple = (Pointer) c.getFieldValue("bezt");
|
||||||
|
List<Structure> bezTriples = pBezTriple.fetchData(dataRepository.getInputStream());
|
||||||
|
bezierCurves[channelCounter++] = new BezierCurve(type, bezTriples, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ipo ipo = new Ipo(bezierCurves);
|
||||||
|
tracks.add(ipo.calculateTrack(boneIndex.intValue(), animationFrames[0], animationFrames[1], fps));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tracks.toArray(new BoneTrack[tracks.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BoneTrack[] getTracks249(Structure actionStructure, DataRepository dataRepository, String objectName, String animationName) throws BlenderFileException {
|
||||||
|
LOGGER.log(Level.INFO, "Getting tracks!");
|
||||||
|
int fps = dataRepository.getBlenderKey().getFps();
|
||||||
|
int[] animationFrames = dataRepository.getBlenderKey().getAnimationFrames(objectName, animationName);
|
||||||
|
Structure groups = (Structure) actionStructure.getFieldValue("groups");
|
||||||
|
List<Structure> actionGroups = groups.evaluateListBase(dataRepository);//bActionGroup
|
||||||
|
if (actionGroups != null && actionGroups.size() > 0 && (bonesMap == null || bonesMap.size() == 0)) {
|
||||||
|
throw new IllegalStateException("No bones found! Cannot proceed to calculating tracks!");
|
||||||
|
}
|
||||||
|
|
||||||
|
List<BoneTrack> tracks = new ArrayList<BoneTrack>();
|
||||||
|
for (Structure actionGroup : actionGroups) {
|
||||||
|
String name = actionGroup.getFieldValue("name").toString();
|
||||||
|
Integer boneIndex = bonesMap.get(name);
|
||||||
|
if (boneIndex != null) {
|
||||||
|
List<Structure> channels = ((Structure) actionGroup.getFieldValue("channels")).evaluateListBase(dataRepository);
|
||||||
|
BezierCurve[] bezierCurves = new BezierCurve[channels.size()];
|
||||||
|
int channelCounter = 0;
|
||||||
|
for (Structure c : channels) {
|
||||||
|
//reading rna path first
|
||||||
|
BlenderInputStream bis = dataRepository.getInputStream();
|
||||||
|
int currentPosition = bis.getPosition();
|
||||||
|
Pointer pRnaPath = (Pointer) c.getFieldValue("rna_path");
|
||||||
|
FileBlockHeader dataFileBlock = dataRepository.getFileBlock(pRnaPath.getOldMemoryAddress());
|
||||||
|
bis.setPosition(dataFileBlock.getBlockPosition());
|
||||||
|
String rnaPath = bis.readString();
|
||||||
|
bis.setPosition(currentPosition);
|
||||||
|
int arrayIndex = ((Number) c.getFieldValue("array_index")).intValue();
|
||||||
|
int type = this.getCurveType(rnaPath, arrayIndex);
|
||||||
|
|
||||||
|
Pointer pBezTriple = (Pointer) c.getFieldValue("bezt");
|
||||||
|
List<Structure> bezTriples = pBezTriple.fetchData(dataRepository.getInputStream());
|
||||||
|
bezierCurves[channelCounter++] = new BezierCurve(type, bezTriples, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ipo ipo = new Ipo(bezierCurves);
|
||||||
|
tracks.add(ipo.calculateTrack(boneIndex.intValue(), animationFrames[0], animationFrames[1], fps));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tracks.toArray(new BoneTrack[tracks.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method parses the information stored inside the curve rna path and returns the proper type
|
||||||
|
* of the curve.
|
||||||
|
* @param rnaPath the curve's rna path
|
||||||
|
* @param arrayIndex the array index of the stored data
|
||||||
|
* @return the type of the curve
|
||||||
|
*/
|
||||||
|
protected int getCurveType(String rnaPath, int arrayIndex) {
|
||||||
|
if (rnaPath.endsWith(".location")) {
|
||||||
|
return Ipo.AC_LOC_X + arrayIndex;
|
||||||
|
}
|
||||||
|
if (rnaPath.endsWith(".rotation_quaternion")) {
|
||||||
|
return Ipo.AC_QUAT_W + arrayIndex;
|
||||||
|
}
|
||||||
|
if (rnaPath.endsWith(".scale")) {
|
||||||
|
return Ipo.AC_SIZE_X + arrayIndex;
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("Unknown curve rna path: " + rnaPath);
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package com.jme3.scene.plugins.blender.structures;
|
package com.jme3.scene.plugins.blender.animations;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
@ -11,7 +11,7 @@ import com.jme3.scene.Spatial;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The purpose of this class is to imitate bone's movement when calculating inverse kinematics.
|
* The purpose of this class is to imitate bone's movement when calculating inverse kinematics.
|
||||||
* @author Marcin Roguski
|
* @author Marcin Roguski (Kaelthas)
|
||||||
*/
|
*/
|
||||||
public class CalculationBone extends Node {
|
public class CalculationBone extends Node {
|
||||||
private Bone bone;
|
private Bone bone;
|
@ -1,8 +1,9 @@
|
|||||||
package com.jme3.scene.plugins.blender.structures;
|
package com.jme3.scene.plugins.blender.animations;
|
||||||
|
|
||||||
import com.jme3.animation.BoneTrack;
|
import com.jme3.animation.BoneTrack;
|
||||||
import com.jme3.math.Quaternion;
|
import com.jme3.math.Quaternion;
|
||||||
import com.jme3.math.Vector3f;
|
import com.jme3.math.Vector3f;
|
||||||
|
import com.jme3.scene.plugins.blender.curves.BezierCurve;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is used to calculate bezier curves value for the given frames. The Ipo (interpolation object) consists
|
* This class is used to calculate bezier curves value for the given frames. The Ipo (interpolation object) consists
|
@ -1,15 +1,14 @@
|
|||||||
package com.jme3.scene.plugins.blender.helpers.v249;
|
package com.jme3.scene.plugins.blender.animations;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.jme3.animation.BoneTrack;
|
import com.jme3.animation.BoneTrack;
|
||||||
import com.jme3.scene.plugins.blender.data.Structure;
|
import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
|
||||||
import com.jme3.scene.plugins.blender.exception.BlenderFileException;
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
import com.jme3.scene.plugins.blender.structures.BezierCurve;
|
import com.jme3.scene.plugins.blender.curves.BezierCurve;
|
||||||
import com.jme3.scene.plugins.blender.structures.Ipo;
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
import com.jme3.scene.plugins.blender.utils.AbstractBlenderHelper;
|
import com.jme3.scene.plugins.blender.file.Pointer;
|
||||||
import com.jme3.scene.plugins.blender.utils.DataRepository;
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
import com.jme3.scene.plugins.blender.utils.Pointer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class helps to compute values from interpolation curves for features like animation or constraint influence. The
|
* This class helps to compute values from interpolation curves for features like animation or constraint influence. The
|
||||||
@ -18,7 +17,7 @@ import com.jme3.scene.plugins.blender.utils.Pointer;
|
|||||||
*/
|
*/
|
||||||
public class IpoHelper extends AbstractBlenderHelper {
|
public class IpoHelper extends AbstractBlenderHelper {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This constructor parses the given blender version and stores the result. Some functionalities may differ in
|
* This constructor parses the given blender version and stores the result. Some functionalities may differ in
|
||||||
* different blender versions.
|
* different blender versions.
|
||||||
* @param blenderVersion
|
* @param blenderVersion
|
@ -0,0 +1,118 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.cameras;
|
||||||
|
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import com.jme3.asset.BlenderKey.FeaturesToLoad;
|
||||||
|
import com.jme3.renderer.Camera;
|
||||||
|
import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class that is used to load cameras into the scene.
|
||||||
|
* @author Marcin Roguski
|
||||||
|
*/
|
||||||
|
public class CameraHelper extends AbstractBlenderHelper {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(CameraHelper.class.getName());
|
||||||
|
protected static final int DEFAULT_CAM_WIDTH = 100;
|
||||||
|
protected static final int DEFAULT_CAM_HEIGHT = 100;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor parses the given blender version and stores the result. Some functionalities may differ in
|
||||||
|
* different blender versions.
|
||||||
|
* @param blenderVersion
|
||||||
|
* the version read from the blend file
|
||||||
|
*/
|
||||||
|
public CameraHelper(String blenderVersion) {
|
||||||
|
super(blenderVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method converts the given structure to jme camera.
|
||||||
|
*
|
||||||
|
* @param structure
|
||||||
|
* camera structure
|
||||||
|
* @return jme camera object
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* an exception is thrown when there are problems with the
|
||||||
|
* blender file
|
||||||
|
*/
|
||||||
|
public Camera toCamera(Structure structure) throws BlenderFileException {
|
||||||
|
if (blenderVersion >= 250) {
|
||||||
|
return this.toCamera250(structure);
|
||||||
|
} else {
|
||||||
|
return this.toCamera249(structure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method converts the given structure to jme camera. Should be used form blender 2.5+.
|
||||||
|
*
|
||||||
|
* @param structure
|
||||||
|
* camera structure
|
||||||
|
* @return jme camera object
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* an exception is thrown when there are problems with the
|
||||||
|
* blender file
|
||||||
|
*/
|
||||||
|
public Camera toCamera250(Structure structure) throws BlenderFileException {
|
||||||
|
Camera result = new Camera(DEFAULT_CAM_WIDTH, DEFAULT_CAM_HEIGHT);
|
||||||
|
int type = ((Number) structure.getFieldValue("type")).intValue();
|
||||||
|
if (type != 0 && type != 1) {
|
||||||
|
LOGGER.log(Level.WARNING, "Unknown camera type: {0}. Perspective camera is being used!", type);
|
||||||
|
type = 0;
|
||||||
|
}
|
||||||
|
//type==0 - perspective; type==1 - orthographic; perspective is used as default
|
||||||
|
result.setParallelProjection(type == 1);
|
||||||
|
float aspect = 0;
|
||||||
|
float clipsta = ((Number) structure.getFieldValue("clipsta")).floatValue();
|
||||||
|
float clipend = ((Number) structure.getFieldValue("clipend")).floatValue();
|
||||||
|
if (type == 0) {
|
||||||
|
aspect = ((Number) structure.getFieldValue("lens")).floatValue();
|
||||||
|
} else {
|
||||||
|
aspect = ((Number) structure.getFieldValue("ortho_scale")).floatValue();
|
||||||
|
}
|
||||||
|
result.setFrustumPerspective(45, aspect, clipsta, clipend);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method converts the given structure to jme camera. Should be used form blender 2.49.
|
||||||
|
*
|
||||||
|
* @param structure
|
||||||
|
* camera structure
|
||||||
|
* @return jme camera object
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* an exception is thrown when there are problems with the
|
||||||
|
* blender file
|
||||||
|
*/
|
||||||
|
public Camera toCamera249(Structure structure) throws BlenderFileException {
|
||||||
|
Camera result = new Camera(DEFAULT_CAM_WIDTH, DEFAULT_CAM_HEIGHT);
|
||||||
|
int type = ((Number) structure.getFieldValue("type")).intValue();
|
||||||
|
if (type != 0 && type != 1) {
|
||||||
|
LOGGER.log(Level.WARNING, "Unknown camera type: {0}. Perspective camera is being used!", type);
|
||||||
|
type = 0;
|
||||||
|
}
|
||||||
|
//type==0 - perspective; type==1 - orthographic; perspective is used as default
|
||||||
|
result.setParallelProjection(type == 1);
|
||||||
|
float angle = ((Number) structure.getFieldValue("angle")).floatValue();
|
||||||
|
float aspect = 0;
|
||||||
|
float clipsta = ((Number) structure.getFieldValue("clipsta")).floatValue();
|
||||||
|
float clipend = ((Number) structure.getFieldValue("clipend")).floatValue();
|
||||||
|
if (type == 0) {
|
||||||
|
aspect = ((Number) structure.getFieldValue("lens")).floatValue();
|
||||||
|
} else {
|
||||||
|
aspect = ((Number) structure.getFieldValue("ortho_scale")).floatValue();
|
||||||
|
}
|
||||||
|
result.setFrustumPerspective(angle, aspect, clipsta, clipend);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldBeLoaded(Structure structure, DataRepository dataRepository) {
|
||||||
|
return (dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.CAMERAS) != 0;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,247 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
|
import com.jme3.animation.Bone;
|
||||||
|
import com.jme3.animation.BoneAnimation;
|
||||||
|
import com.jme3.animation.BoneTrack;
|
||||||
|
import com.jme3.animation.Skeleton;
|
||||||
|
import com.jme3.math.Quaternion;
|
||||||
|
import com.jme3.math.Vector3f;
|
||||||
|
import com.jme3.scene.Node;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository.LoadedFeatureDataType;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Pointer;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
import com.jme3.scene.plugins.blender.objects.ObjectHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The implementation of a constraint.
|
||||||
|
*
|
||||||
|
* @author Marcin Roguski
|
||||||
|
*/
|
||||||
|
public abstract class Constraint {
|
||||||
|
|
||||||
|
/** The name of this constraint. */
|
||||||
|
protected final String name;
|
||||||
|
/** The old memory address of the constraint's owner. */
|
||||||
|
protected final Long boneOMA;
|
||||||
|
protected final Space ownerSpace;
|
||||||
|
protected final Space targetSpace;
|
||||||
|
/** The structure with constraint's data. */
|
||||||
|
protected final Structure data;
|
||||||
|
/** The ipo object defining influence. */
|
||||||
|
protected final Ipo ipo;
|
||||||
|
protected DataRepository dataRepository;
|
||||||
|
/**
|
||||||
|
* This constructor creates the constraint instance.
|
||||||
|
*
|
||||||
|
* @param constraintStructure
|
||||||
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
|
* @param boneOMA
|
||||||
|
* the old memory address of the constraint owner
|
||||||
|
* @param influenceIpo
|
||||||
|
* the ipo curve of the influence factor
|
||||||
|
* @param dataRepository
|
||||||
|
* the data repository
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* this exception is thrown when the blender file is somehow
|
||||||
|
* corrupted
|
||||||
|
*/
|
||||||
|
public Constraint(Structure constraintStructure, Long boneOMA,
|
||||||
|
Ipo influenceIpo, DataRepository dataRepository) throws BlenderFileException {
|
||||||
|
this.name = constraintStructure.getFieldValue("name").toString();
|
||||||
|
ConstraintType constraintType = ConstraintType.valueOf(((Number)constraintStructure.getFieldValue("type")).intValue());
|
||||||
|
if(constraintType != this.getType()) {
|
||||||
|
throw new IllegalStateException("Constraint structure does not match its type for constraint: " + name);
|
||||||
|
}
|
||||||
|
Pointer pData = (Pointer) constraintStructure.getFieldValue("data");
|
||||||
|
if (pData.isNotNull()) {
|
||||||
|
data = pData.fetchData(dataRepository.getInputStream()).get(0);
|
||||||
|
} else {
|
||||||
|
throw new BlenderFileException("The constraint has no data specified!");
|
||||||
|
}
|
||||||
|
this.boneOMA = boneOMA;
|
||||||
|
this.ownerSpace = Space.valueOf(((Number) constraintStructure.getFieldValue("ownspace")).byteValue());
|
||||||
|
this.targetSpace = Space.valueOf(((Number) constraintStructure.getFieldValue("tarspace")).byteValue());
|
||||||
|
this.ipo = influenceIpo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the name of the constraint.
|
||||||
|
*
|
||||||
|
* @return the name of the constraint
|
||||||
|
*/
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the old memoty address of the bone this constraint
|
||||||
|
* affects.
|
||||||
|
*
|
||||||
|
* @return the old memory address of the bone this constraint affects
|
||||||
|
*/
|
||||||
|
public Long getBoneOMA() {
|
||||||
|
return boneOMA;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the type of the constraint.
|
||||||
|
*
|
||||||
|
* @return the type of the constraint
|
||||||
|
*/
|
||||||
|
public abstract ConstraintType getType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the bone traces for the bone that is affected by the given constraint.
|
||||||
|
* @param skeleton
|
||||||
|
* the skeleton containing bones
|
||||||
|
* @param boneAnimation
|
||||||
|
* the bone animation that affects the skeleton
|
||||||
|
* @return the bone track for the bone that is being affected by the constraint
|
||||||
|
*/
|
||||||
|
protected BoneTrack getBoneTrack(Skeleton skeleton, BoneAnimation boneAnimation) {
|
||||||
|
Bone bone = (Bone) dataRepository.getLoadedFeature(boneOMA, LoadedFeatureDataType.LOADED_FEATURE);
|
||||||
|
int boneIndex = bone==null ? 0 : skeleton.getBoneIndex(bone);//bone==null may mean the object animation
|
||||||
|
if (boneIndex != -1) {
|
||||||
|
//searching for track for this bone
|
||||||
|
for (BoneTrack boneTrack : boneAnimation.getTracks()) {
|
||||||
|
if (boneTrack.getTargetBoneIndex() == boneIndex) {
|
||||||
|
return boneTrack;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the target or subtarget object (if specified).
|
||||||
|
* @param loadedFeatureDataType
|
||||||
|
* @return target or subtarget feature
|
||||||
|
* @throws BlenderFileException this exception is thrown if the blend file is somehow corrupted
|
||||||
|
*/
|
||||||
|
protected Object getTarget(LoadedFeatureDataType loadedFeatureDataType) throws BlenderFileException {
|
||||||
|
//load the feature through objectHelper, this way we are certain the object loads and has
|
||||||
|
//his own constraints applied to traces
|
||||||
|
ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);
|
||||||
|
//always load the target first
|
||||||
|
Long targetOMA = ((Pointer) data.getFieldValue("tar")).getOldMemoryAddress();
|
||||||
|
Structure objectStructure = dataRepository.getFileBlock(targetOMA).getStructure(dataRepository);
|
||||||
|
Object result = objectHelper.toObject(objectStructure, dataRepository);
|
||||||
|
|
||||||
|
//subtarget should be loaded alogn with target
|
||||||
|
Object subtarget = data.getFieldValue("subtarget");
|
||||||
|
String subtargetName = subtarget==null ? null : subtarget.toString();
|
||||||
|
if (subtargetName!=null && subtargetName.length() > 0) {
|
||||||
|
result = dataRepository.getLoadedFeature(subtargetName, loadedFeatureDataType);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns target's object location.
|
||||||
|
* @return target's object location
|
||||||
|
*/
|
||||||
|
protected Vector3f getTargetLocation() {
|
||||||
|
Long targetOMA = ((Pointer) data.getFieldValue("tar")).getOldMemoryAddress();
|
||||||
|
Node targetObject = (Node) dataRepository.getLoadedFeature(targetOMA, LoadedFeatureDataType.LOADED_FEATURE);
|
||||||
|
switch (targetSpace) {
|
||||||
|
case CONSTRAINT_SPACE_LOCAL:
|
||||||
|
return targetObject.getLocalTranslation();
|
||||||
|
case CONSTRAINT_SPACE_WORLD:
|
||||||
|
return targetObject.getWorldTranslation();
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Invalid space type for target object: " + targetSpace.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns target's object location in the specified frame.
|
||||||
|
* @param frame
|
||||||
|
* the frame number
|
||||||
|
* @return target's object location
|
||||||
|
*/
|
||||||
|
protected Vector3f getTargetLocation(int frame) {
|
||||||
|
return this.getTargetLocation();//TODO: implement getting location in a specified frame
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns target's object rotation.
|
||||||
|
* @return target's object rotation
|
||||||
|
*/
|
||||||
|
protected Quaternion getTargetRotation() {
|
||||||
|
Long targetOMA = ((Pointer) data.getFieldValue("tar")).getOldMemoryAddress();
|
||||||
|
Node targetObject = (Node) dataRepository.getLoadedFeature(targetOMA, LoadedFeatureDataType.LOADED_FEATURE);
|
||||||
|
switch (targetSpace) {
|
||||||
|
case CONSTRAINT_SPACE_LOCAL:
|
||||||
|
return targetObject.getLocalRotation();
|
||||||
|
case CONSTRAINT_SPACE_WORLD:
|
||||||
|
return targetObject.getWorldRotation();
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Invalid space type for target object: " + targetSpace.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns target's object scale.
|
||||||
|
* @return target's object scale
|
||||||
|
*/
|
||||||
|
protected Vector3f getTargetScale() {
|
||||||
|
Long targetOMA = ((Pointer) data.getFieldValue("tar")).getOldMemoryAddress();
|
||||||
|
Node targetObject = (Node) dataRepository.getLoadedFeature(targetOMA, LoadedFeatureDataType.LOADED_FEATURE);
|
||||||
|
switch (targetSpace) {
|
||||||
|
case CONSTRAINT_SPACE_LOCAL:
|
||||||
|
return targetObject.getLocalScale();
|
||||||
|
case CONSTRAINT_SPACE_WORLD:
|
||||||
|
return targetObject.getWorldScale();
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Invalid space type for target object: " + targetSpace.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method affects the bone animation tracks for the given skeleton.
|
||||||
|
*
|
||||||
|
* @param skeleton
|
||||||
|
* the skeleton containing the affected bones by constraint
|
||||||
|
* @param boneAnimation
|
||||||
|
* the bone animation baked traces
|
||||||
|
* @param constraint
|
||||||
|
* the constraint
|
||||||
|
*/
|
||||||
|
public abstract void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The space of target or owner transformation.
|
||||||
|
*
|
||||||
|
* @author Marcin Roguski
|
||||||
|
*/
|
||||||
|
public static enum Space {
|
||||||
|
|
||||||
|
CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_PARLOCAL, CONSTRAINT_SPACE_INVALID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the enum instance when given the appropriate
|
||||||
|
* value from the blend file.
|
||||||
|
*
|
||||||
|
* @param c
|
||||||
|
* the blender's value of the space modifier
|
||||||
|
* @return the scape enum instance
|
||||||
|
*/
|
||||||
|
public static Space valueOf(byte c) {
|
||||||
|
switch (c) {
|
||||||
|
case 0:
|
||||||
|
return CONSTRAINT_SPACE_WORLD;
|
||||||
|
case 1:
|
||||||
|
return CONSTRAINT_SPACE_LOCAL;
|
||||||
|
case 2:
|
||||||
|
return CONSTRAINT_SPACE_POSE;
|
||||||
|
case 3:
|
||||||
|
return CONSTRAINT_SPACE_PARLOCAL;
|
||||||
|
default:
|
||||||
|
return CONSTRAINT_SPACE_INVALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import com.jme3.animation.BoneAnimation;
|
||||||
|
import com.jme3.animation.Skeleton;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents 'Action' constraint type in blender.
|
||||||
|
* @author Marcin Roguski (Kaelthas)
|
||||||
|
*/
|
||||||
|
/*package*/ class ConstraintAction extends Constraint {
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(ConstraintAction.class.getName());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor creates the constraint instance.
|
||||||
|
*
|
||||||
|
* @param constraintStructure
|
||||||
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
|
* @param boneOMA
|
||||||
|
* the old memory address of the constraint owner
|
||||||
|
* @param influenceIpo
|
||||||
|
* the ipo curve of the influence factor
|
||||||
|
* @param dataRepository
|
||||||
|
* the data repository
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* this exception is thrown when the blender file is somehow
|
||||||
|
* corrupted
|
||||||
|
*/
|
||||||
|
public ConstraintAction(Structure constraintStructure, Long boneOMA,
|
||||||
|
Ipo influenceIpo, DataRepository dataRepository) throws BlenderFileException {
|
||||||
|
super(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation) {
|
||||||
|
// TODO: implement 'Action' constraint
|
||||||
|
LOGGER.log(Level.WARNING, "'Action' constraint NOT implemented!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConstraintType getType() {
|
||||||
|
return ConstraintType.CONSTRAINT_TYPE_ACTION;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import com.jme3.animation.BoneAnimation;
|
||||||
|
import com.jme3.animation.Skeleton;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents 'ChildOf' constraint type in blender.
|
||||||
|
* @author Marcin Roguski (Kaelthas)
|
||||||
|
*/
|
||||||
|
/*package*/ class ConstraintChildOf extends Constraint {
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(ConstraintChildOf.class.getName());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor creates the constraint instance.
|
||||||
|
*
|
||||||
|
* @param constraintStructure
|
||||||
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
|
* @param boneOMA
|
||||||
|
* the old memory address of the constraint owner
|
||||||
|
* @param influenceIpo
|
||||||
|
* the ipo curve of the influence factor
|
||||||
|
* @param dataRepository
|
||||||
|
* the data repository
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* this exception is thrown when the blender file is somehow
|
||||||
|
* corrupted
|
||||||
|
*/
|
||||||
|
public ConstraintChildOf(Structure constraintStructure, Long boneOMA,
|
||||||
|
Ipo influenceIpo, DataRepository dataRepository) throws BlenderFileException {
|
||||||
|
super(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation) {
|
||||||
|
// TODO: implement ChildOf constraint
|
||||||
|
LOGGER.log(Level.WARNING, "ChildOf constraint NOT implemented!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConstraintType getType() {
|
||||||
|
return ConstraintType.CONSTRAINT_TYPE_CHILDOF;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import com.jme3.animation.BoneAnimation;
|
||||||
|
import com.jme3.animation.Skeleton;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents 'Clamp to' constraint type in blender.
|
||||||
|
* @author Marcin Roguski (Kaelthas)
|
||||||
|
*/
|
||||||
|
/*package*/ class ConstraintClampTo extends Constraint {
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(ConstraintClampTo.class.getName());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor creates the constraint instance.
|
||||||
|
*
|
||||||
|
* @param constraintStructure
|
||||||
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
|
* @param boneOMA
|
||||||
|
* the old memory address of the constraint owner
|
||||||
|
* @param influenceIpo
|
||||||
|
* the ipo curve of the influence factor
|
||||||
|
* @param dataRepository
|
||||||
|
* the data repository
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* this exception is thrown when the blender file is somehow
|
||||||
|
* corrupted
|
||||||
|
*/
|
||||||
|
public ConstraintClampTo(Structure constraintStructure, Long boneOMA,
|
||||||
|
Ipo influenceIpo, DataRepository dataRepository)
|
||||||
|
throws BlenderFileException {
|
||||||
|
super(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation) {
|
||||||
|
//TODO: implement when curves are implemented
|
||||||
|
LOGGER.log(Level.INFO, "'Clamp to' not yet implemented! Curves not yet implemented!", this.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConstraintType getType() {
|
||||||
|
return ConstraintType.CONSTRAINT_TYPE_CLAMPTO;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
|
import com.jme3.animation.BoneAnimation;
|
||||||
|
import com.jme3.animation.BoneTrack;
|
||||||
|
import com.jme3.animation.Skeleton;
|
||||||
|
import com.jme3.math.Vector3f;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents 'Dist limit' constraint type in blender.
|
||||||
|
* @author Marcin Roguski (Kaelthas)
|
||||||
|
*/
|
||||||
|
/*package*/ class ConstraintDistLimit extends Constraint {
|
||||||
|
private static final int LIMITDIST_INSIDE = 0;
|
||||||
|
private static final int LIMITDIST_OUTSIDE = 1;
|
||||||
|
private static final int LIMITDIST_ONSURFACE = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor creates the constraint instance.
|
||||||
|
*
|
||||||
|
* @param constraintStructure
|
||||||
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
|
* @param boneOMA
|
||||||
|
* the old memory address of the constraint owner
|
||||||
|
* @param influenceIpo
|
||||||
|
* the ipo curve of the influence factor
|
||||||
|
* @param dataRepository
|
||||||
|
* the data repository
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* this exception is thrown when the blender file is somehow
|
||||||
|
* corrupted
|
||||||
|
*/
|
||||||
|
public ConstraintDistLimit(Structure constraintStructure, Long boneOMA,
|
||||||
|
Ipo influenceIpo, DataRepository dataRepository) throws BlenderFileException {
|
||||||
|
super(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation) {
|
||||||
|
Vector3f targetLocation = this.getTargetLocation();
|
||||||
|
BoneTrack boneTrack = this.getBoneTrack(skeleton, boneAnimation);
|
||||||
|
if (boneTrack != null) {
|
||||||
|
//TODO: target vertex group !!!
|
||||||
|
float dist = ((Number) data.getFieldValue("dist")).floatValue();
|
||||||
|
int mode = ((Number) data.getFieldValue("mode")).intValue();
|
||||||
|
|
||||||
|
int maxFrames = boneTrack.getTimes().length;
|
||||||
|
Vector3f[] translations = boneTrack.getTranslations();
|
||||||
|
for (int frame = 0; frame < maxFrames; ++frame) {
|
||||||
|
Vector3f v = translations[frame].subtract(targetLocation);
|
||||||
|
float currentDistance = v.length();
|
||||||
|
float influence = ipo.calculateValue(frame);
|
||||||
|
float modifier = 0.0f;
|
||||||
|
switch (mode) {
|
||||||
|
case LIMITDIST_INSIDE:
|
||||||
|
if (currentDistance >= dist) {
|
||||||
|
modifier = (dist - currentDistance) / currentDistance;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LIMITDIST_ONSURFACE:
|
||||||
|
modifier = (dist - currentDistance) / currentDistance;
|
||||||
|
break;
|
||||||
|
case LIMITDIST_OUTSIDE:
|
||||||
|
if (currentDistance <= dist) {
|
||||||
|
modifier = (dist - currentDistance) / currentDistance;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Unknown distance limit constraint mode: " + mode);
|
||||||
|
}
|
||||||
|
translations[frame].addLocal(v.multLocal(modifier * influence));
|
||||||
|
}
|
||||||
|
boneTrack.setKeyframes(boneTrack.getTimes(), translations, boneTrack.getRotations(), boneTrack.getScales());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConstraintType getType() {
|
||||||
|
return ConstraintType.CONSTRAINT_TYPE_DISTLIMIT;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A factory class to create new instances of constraints depending on the type from the constraint's structure.
|
||||||
|
* This class has a package scope.
|
||||||
|
* @author Marcin Roguski (Kaelthas)
|
||||||
|
*/
|
||||||
|
/*package*/ final class ConstraintFactory {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method creates the constraint instance.
|
||||||
|
*
|
||||||
|
* @param constraintStructure
|
||||||
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
|
* @param boneOMA
|
||||||
|
* the old memory address of the constraint owner
|
||||||
|
* @param influenceIpo
|
||||||
|
* the ipo curve of the influence factor
|
||||||
|
* @param dataRepository
|
||||||
|
* the data repository
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* this exception is thrown when the blender file is somehow
|
||||||
|
* corrupted
|
||||||
|
*/
|
||||||
|
public static Constraint createConstraint(Structure constraintStructure, Long boneOMA, Ipo influenceIpo, DataRepository dataRepository) throws BlenderFileException {
|
||||||
|
int type = ((Number)constraintStructure.getFieldValue("type")).intValue();
|
||||||
|
ConstraintType constraintType = ConstraintType.valueOf(type);
|
||||||
|
switch(constraintType) {
|
||||||
|
case CONSTRAINT_TYPE_ACTION:
|
||||||
|
return new ConstraintAction(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
case CONSTRAINT_TYPE_CHILDOF:
|
||||||
|
return new ConstraintChildOf(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
case CONSTRAINT_TYPE_CLAMPTO:
|
||||||
|
return new ConstraintClampTo(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
case CONSTRAINT_TYPE_DISTLIMIT:
|
||||||
|
return new ConstraintDistLimit(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
case CONSTRAINT_TYPE_FOLLOWPATH:
|
||||||
|
return new ConstraintFollowPath(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
case CONSTRAINT_TYPE_KINEMATIC:
|
||||||
|
return new ConstraintInverseKinematics(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
case CONSTRAINT_TYPE_LOCKTRACK:
|
||||||
|
return new ConstraintLockTrack(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
case CONSTRAINT_TYPE_LOCLIKE:
|
||||||
|
return new ConstraintLocLike(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
case CONSTRAINT_TYPE_LOCLIMIT:
|
||||||
|
return new ConstraintLocLimit(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
case CONSTRAINT_TYPE_MINMAX:
|
||||||
|
return new ConstraintMinMax(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
case CONSTRAINT_TYPE_NULL:
|
||||||
|
return new ConstraintNull(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
case CONSTRAINT_TYPE_PYTHON:
|
||||||
|
return new ConstraintPython(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
case CONSTRAINT_TYPE_RIGIDBODYJOINT:
|
||||||
|
return new ConstraintRigidBodyJoint(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
case CONSTRAINT_TYPE_ROTLIKE:
|
||||||
|
return new ConstraintRotLike(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
case CONSTRAINT_TYPE_ROTLIMIT:
|
||||||
|
return new ConstraintRotLimit(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
case CONSTRAINT_TYPE_SHRINKWRAP:
|
||||||
|
return new ConstraintShrinkWrap(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
case CONSTRAINT_TYPE_SIZELIKE:
|
||||||
|
return new ConstraintSizeLike(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
case CONSTRAINT_TYPE_SIZELIMIT:
|
||||||
|
return new ConstraintSizeLimit(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
case CONSTRAINT_TYPE_STRETCHTO:
|
||||||
|
return new ConstraintStretchTo(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
case CONSTRAINT_TYPE_TRANSFORM:
|
||||||
|
return new ConstraintTransform(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Unknown constraint type: " + constraintType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import com.jme3.animation.BoneAnimation;
|
||||||
|
import com.jme3.animation.Skeleton;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents 'Follow path' constraint type in blender.
|
||||||
|
* @author Marcin Roguski (Kaelthas)
|
||||||
|
*/
|
||||||
|
/*package*/ class ConstraintFollowPath extends Constraint {
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(ConstraintFollowPath.class.getName());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor creates the constraint instance.
|
||||||
|
*
|
||||||
|
* @param constraintStructure
|
||||||
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
|
* @param boneOMA
|
||||||
|
* the old memory address of the constraint owner
|
||||||
|
* @param influenceIpo
|
||||||
|
* the ipo curve of the influence factor
|
||||||
|
* @param dataRepository
|
||||||
|
* the data repository
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* this exception is thrown when the blender file is somehow
|
||||||
|
* corrupted
|
||||||
|
*/
|
||||||
|
public ConstraintFollowPath(Structure constraintStructure, Long boneOMA,
|
||||||
|
Ipo influenceIpo, DataRepository dataRepository) throws BlenderFileException {
|
||||||
|
super(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation) {
|
||||||
|
//TODO: implement when curves are implemented
|
||||||
|
LOGGER.log(Level.INFO, "'Follow path' not implemented! Curves not yet implemented!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConstraintType getType() {
|
||||||
|
return ConstraintType.CONSTRAINT_TYPE_FOLLOWPATH;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,140 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.IpoHelper;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Pointer;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class should be used for constraint calculations.
|
||||||
|
* @author Marcin Roguski
|
||||||
|
*/
|
||||||
|
public class ConstraintHelper extends AbstractBlenderHelper {
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(ConstraintHelper.class.getName());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper constructor. It's main task is to generate the affection functions. These functions are common to all
|
||||||
|
* ConstraintHelper instances. Unfortunately this constructor might grow large. If it becomes too large - I shall
|
||||||
|
* consider refactoring. The constructor parses the given blender version and stores the result. Some
|
||||||
|
* functionalities may differ in different blender versions.
|
||||||
|
* @param blenderVersion
|
||||||
|
* the version read from the blend file
|
||||||
|
*/
|
||||||
|
public ConstraintHelper(String blenderVersion, DataRepository dataRepository) {
|
||||||
|
super(blenderVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method reads constraints for for the given structure. The constraints are loaded only once for object/bone.
|
||||||
|
* @param ownerOMA
|
||||||
|
* the owner's old memory address
|
||||||
|
* @param objectStructure
|
||||||
|
* the structure we read constraint's for
|
||||||
|
* @param dataRepository
|
||||||
|
* the data repository
|
||||||
|
* @throws BlenderFileException
|
||||||
|
*/
|
||||||
|
public Map<Long, List<Constraint>> loadConstraints(Structure objectStructure, DataRepository dataRepository) throws BlenderFileException {
|
||||||
|
if (blenderVersion < 250) {//TODO
|
||||||
|
LOGGER.warning("Loading of constraints not yet implemented for version 2.5x !");
|
||||||
|
return new HashMap<Long, List<Constraint>>(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// reading influence ipos for the constraints
|
||||||
|
IpoHelper ipoHelper = dataRepository.getHelper(IpoHelper.class);
|
||||||
|
Map<String, Map<String, Ipo>> constraintsIpos = new HashMap<String, Map<String, Ipo>>();
|
||||||
|
Pointer pActions = (Pointer) objectStructure.getFieldValue("action");
|
||||||
|
if (pActions.isNotNull()) {
|
||||||
|
List<Structure> actions = pActions.fetchData(dataRepository.getInputStream());
|
||||||
|
for (Structure action : actions) {
|
||||||
|
Structure chanbase = (Structure) action.getFieldValue("chanbase");
|
||||||
|
List<Structure> actionChannels = chanbase.evaluateListBase(dataRepository);
|
||||||
|
for (Structure actionChannel : actionChannels) {
|
||||||
|
Map<String, Ipo> ipos = new HashMap<String, Ipo>();
|
||||||
|
Structure constChannels = (Structure) actionChannel.getFieldValue("constraintChannels");
|
||||||
|
List<Structure> constraintChannels = constChannels.evaluateListBase(dataRepository);
|
||||||
|
for (Structure constraintChannel : constraintChannels) {
|
||||||
|
Pointer pIpo = (Pointer) constraintChannel.getFieldValue("ipo");
|
||||||
|
if (pIpo.isNotNull()) {
|
||||||
|
String constraintName = constraintChannel.getFieldValue("name").toString();
|
||||||
|
Ipo ipo = ipoHelper.createIpo(pIpo.fetchData(dataRepository.getInputStream()).get(0), dataRepository);
|
||||||
|
ipos.put(constraintName, ipo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String actionName = actionChannel.getFieldValue("name").toString();
|
||||||
|
constraintsIpos.put(actionName, ipos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Long, List<Constraint>> result = new HashMap<Long, List<Constraint>>();
|
||||||
|
|
||||||
|
//loading constraints connected with the object's bones
|
||||||
|
Pointer pPose = (Pointer) objectStructure.getFieldValue("pose");//TODO: what if the object has two armatures ????
|
||||||
|
if (pPose.isNotNull()) {
|
||||||
|
List<Structure> poseChannels = ((Structure) pPose.fetchData(dataRepository.getInputStream()).get(0).getFieldValue("chanbase")).evaluateListBase(dataRepository);
|
||||||
|
for (Structure poseChannel : poseChannels) {
|
||||||
|
List<Constraint> constraintsList = new ArrayList<Constraint>();
|
||||||
|
Long boneOMA = Long.valueOf(((Pointer) poseChannel.getFieldValue("bone")).getOldMemoryAddress());
|
||||||
|
|
||||||
|
//the name is read directly from structure because bone might not yet be loaded
|
||||||
|
String name = dataRepository.getFileBlock(boneOMA).getStructure(dataRepository).getFieldValue("name").toString();
|
||||||
|
List<Structure> constraints = ((Structure) poseChannel.getFieldValue("constraints")).evaluateListBase(dataRepository);
|
||||||
|
for (Structure constraint : constraints) {
|
||||||
|
String constraintName = constraint.getFieldValue("name").toString();
|
||||||
|
Map<String, Ipo> ipoMap = constraintsIpos.get(name);
|
||||||
|
Ipo ipo = ipoMap==null ? null : ipoMap.get(constraintName);
|
||||||
|
if (ipo == null) {
|
||||||
|
float enforce = ((Number) constraint.getFieldValue("enforce")).floatValue();
|
||||||
|
ipo = ipoHelper.createIpo(enforce);
|
||||||
|
}
|
||||||
|
constraintsList.add(ConstraintFactory.createConstraint(constraint, boneOMA, ipo, dataRepository));
|
||||||
|
}
|
||||||
|
|
||||||
|
result.put(boneOMA, constraintsList);
|
||||||
|
dataRepository.addConstraints(boneOMA, constraintsList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: reading constraints for objects (implement when object's animation will be available)
|
||||||
|
List<Structure> constraintChannels = ((Structure)objectStructure.getFieldValue("constraintChannels")).evaluateListBase(dataRepository);
|
||||||
|
for(Structure constraintChannel : constraintChannels) {
|
||||||
|
System.out.println(constraintChannel);
|
||||||
|
}
|
||||||
|
|
||||||
|
//loading constraints connected with the object itself (TODO: test this)
|
||||||
|
if(!result.containsKey(objectStructure.getOldMemoryAddress())) {
|
||||||
|
List<Structure> constraints = ((Structure)objectStructure.getFieldValue("constraints")).evaluateListBase(dataRepository);
|
||||||
|
List<Constraint> constraintsList = new ArrayList<Constraint>(constraints.size());
|
||||||
|
|
||||||
|
for(Structure constraint : constraints) {
|
||||||
|
String constraintName = constraint.getFieldValue("name").toString();
|
||||||
|
String objectName = objectStructure.getName();
|
||||||
|
|
||||||
|
Map<String, Ipo> objectConstraintsIpos = constraintsIpos.get(objectName);
|
||||||
|
Ipo ipo = objectConstraintsIpos!=null ? objectConstraintsIpos.get(constraintName) : null;
|
||||||
|
if (ipo == null) {
|
||||||
|
float enforce = ((Number) constraint.getFieldValue("enforce")).floatValue();
|
||||||
|
ipo = ipoHelper.createIpo(enforce);
|
||||||
|
}
|
||||||
|
constraintsList.add(ConstraintFactory.createConstraint(constraint, null, ipo, dataRepository));
|
||||||
|
}
|
||||||
|
result.put(objectStructure.getOldMemoryAddress(), constraintsList);
|
||||||
|
dataRepository.addConstraints(objectStructure.getOldMemoryAddress(), constraintsList);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldBeLoaded(Structure structure, DataRepository dataRepository) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,170 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import com.jme3.animation.Bone;
|
||||||
|
import com.jme3.animation.BoneAnimation;
|
||||||
|
import com.jme3.animation.Skeleton;
|
||||||
|
import com.jme3.math.FastMath;
|
||||||
|
import com.jme3.math.Quaternion;
|
||||||
|
import com.jme3.math.Transform;
|
||||||
|
import com.jme3.math.Vector3f;
|
||||||
|
import com.jme3.scene.Node;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository.LoadedFeatureDataType;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.CalculationBone;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
import com.jme3.scene.plugins.blender.objects.ObjectHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents 'Inverse kinematics' constraint type in blender.
|
||||||
|
* @author Marcin Roguski (Kaelthas)
|
||||||
|
*/
|
||||||
|
/*package*/ class ConstraintInverseKinematics extends Constraint {
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(ConstraintInverseKinematics.class.getName());
|
||||||
|
private static final float IK_SOLVER_ERROR = 0.5f;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor creates the constraint instance.
|
||||||
|
*
|
||||||
|
* @param constraintStructure
|
||||||
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
|
* @param boneOMA
|
||||||
|
* the old memory address of the constraint owner
|
||||||
|
* @param influenceIpo
|
||||||
|
* the ipo curve of the influence factor
|
||||||
|
* @param dataRepository
|
||||||
|
* the data repository
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* this exception is thrown when the blender file is somehow
|
||||||
|
* corrupted
|
||||||
|
*/
|
||||||
|
public ConstraintInverseKinematics(Structure constraintStructure,
|
||||||
|
Long boneOMA, Ipo influenceIpo, DataRepository dataRepository) throws BlenderFileException {
|
||||||
|
super(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation) {
|
||||||
|
try {
|
||||||
|
// IK solver is only attached to bones
|
||||||
|
Bone ownerBone = (Bone) dataRepository.getLoadedFeature(boneOMA, LoadedFeatureDataType.LOADED_FEATURE);
|
||||||
|
|
||||||
|
// get the target point
|
||||||
|
Object targetObject = this.getTarget(LoadedFeatureDataType.LOADED_FEATURE);
|
||||||
|
Vector3f pt = null;// Point Target
|
||||||
|
if (targetObject instanceof Bone) {
|
||||||
|
pt = ((Bone) targetObject).getModelSpacePosition();
|
||||||
|
} else if (targetObject instanceof Node) {
|
||||||
|
pt = ((Node) targetObject).getWorldTranslation();
|
||||||
|
} else if (targetObject instanceof Skeleton) {
|
||||||
|
Structure armatureNodeStructure = (Structure) this.getTarget(LoadedFeatureDataType.LOADED_STRUCTURE);
|
||||||
|
ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);
|
||||||
|
Transform transform = objectHelper.getTransformation(armatureNodeStructure, dataRepository);
|
||||||
|
pt = transform.getTranslation();
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Unknown target object type! Should be Node, Bone or Skeleton and there is: "
|
||||||
|
+ targetObject.getClass().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
//fetching the owner's bone track
|
||||||
|
// BoneTrack ownerBoneTrack = null;
|
||||||
|
// int boneIndex = skeleton.getBoneIndex(ownerBone);
|
||||||
|
// for (int i = 0; i < boneAnimation.getTracks().length; ++i) {
|
||||||
|
// if (boneAnimation.getTracks()[i].getTargetBoneIndex() == boneIndex) {
|
||||||
|
// ownerBoneTrack = boneAnimation.getTracks()[i];
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// int ownerBoneFramesCount = ownerBoneTrack==null ? 0 : ownerBoneTrack.getTimes().length;
|
||||||
|
|
||||||
|
// preparing data
|
||||||
|
int maxIterations = ((Number) data.getFieldValue("iterations")).intValue();
|
||||||
|
CalculationBone[] bones = this.getBonesToCalculate(ownerBone, skeleton, boneAnimation);
|
||||||
|
// for (int i = 0; i < bones.length; ++i) {
|
||||||
|
// System.out.println(Arrays.toString(bones[i].track.getTranslations()));
|
||||||
|
// System.out.println(Arrays.toString(bones[i].track.getRotations()));
|
||||||
|
// System.out.println("===============================");
|
||||||
|
// }
|
||||||
|
Quaternion rotation = new Quaternion();
|
||||||
|
//all tracks should have the same amount of frames
|
||||||
|
int framesCount = bones[0].getBoneFramesCount();
|
||||||
|
assert framesCount >=1;
|
||||||
|
for (int frame = 0; frame < framesCount; ++frame) {
|
||||||
|
float error = IK_SOLVER_ERROR;
|
||||||
|
int iteration = 0;
|
||||||
|
while (error >= IK_SOLVER_ERROR && iteration <= maxIterations) {
|
||||||
|
// rotating the bones
|
||||||
|
for (int i = 0; i < bones.length - 1; ++i) {
|
||||||
|
Vector3f pe = bones[i].getEndPoint();
|
||||||
|
Vector3f pc = bones[i + 1].getWorldTranslation().clone();
|
||||||
|
|
||||||
|
Vector3f peSUBpc = pe.subtract(pc).normalizeLocal();
|
||||||
|
Vector3f ptSUBpc = pt.subtract(pc).normalizeLocal();
|
||||||
|
|
||||||
|
float theta = FastMath.acos(peSUBpc.dot(ptSUBpc));
|
||||||
|
Vector3f direction = peSUBpc.cross(ptSUBpc).normalizeLocal();
|
||||||
|
bones[i].rotate(rotation.fromAngleAxis(theta, direction), frame);
|
||||||
|
}
|
||||||
|
error = pt.subtract(bones[0].getEndPoint()).length();
|
||||||
|
++iteration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (CalculationBone bone : bones) {
|
||||||
|
bone.applyCalculatedTracks();
|
||||||
|
}
|
||||||
|
|
||||||
|
// System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
|
||||||
|
// for (int i = 0; i < bones.length; ++i) {
|
||||||
|
// System.out.println(Arrays.toString(bones[i].track.getTranslations()));
|
||||||
|
// System.out.println(Arrays.toString(bones[i].track.getRotations()));
|
||||||
|
// System.out.println("===============================");
|
||||||
|
// }
|
||||||
|
} catch(BlenderFileException e) {
|
||||||
|
LOGGER.severe(e.getLocalizedMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns bones used for rotation calculations.
|
||||||
|
* @param bone
|
||||||
|
* the bone to which the constraint is applied
|
||||||
|
* @param skeleton
|
||||||
|
* the skeleton owning the bone and its ancestors
|
||||||
|
* @param boneAnimation
|
||||||
|
* the bone animation data that stores the traces for the skeleton's bones
|
||||||
|
* @return a list of bones to imitate the bone's movement during IK solving
|
||||||
|
*/
|
||||||
|
private CalculationBone[] getBonesToCalculate(Bone bone, Skeleton skeleton, BoneAnimation boneAnimation) {
|
||||||
|
List<CalculationBone> bonesList = new ArrayList<CalculationBone>();
|
||||||
|
Bone currentBone = bone;
|
||||||
|
do {
|
||||||
|
bonesList.add(new CalculationBone(currentBone, 1));
|
||||||
|
// int boneIndex = skeleton.getBoneIndex(currentBone);
|
||||||
|
// for (int i = 0; i < boneAnimation.getTracks().length; ++i) {
|
||||||
|
// if (boneAnimation.getTracks()[i].getTargetBoneIndex() == boneIndex) {
|
||||||
|
// bonesList.add(new CalculationBone(currentBone, boneAnimation.getTracks()[i]));
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
currentBone = currentBone.getParent();
|
||||||
|
} while (currentBone != null);
|
||||||
|
//attaching children
|
||||||
|
CalculationBone[] result = bonesList.toArray(new CalculationBone[bonesList.size()]);
|
||||||
|
for (int i = result.length - 1; i > 0; --i) {
|
||||||
|
result[i].attachChild(result[i - 1]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConstraintType getType() {
|
||||||
|
return ConstraintType.CONSTRAINT_TYPE_KINEMATIC;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,87 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
|
import com.jme3.animation.BoneAnimation;
|
||||||
|
import com.jme3.animation.BoneTrack;
|
||||||
|
import com.jme3.animation.Skeleton;
|
||||||
|
import com.jme3.math.Vector3f;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents 'Loc like' constraint type in blender.
|
||||||
|
* @author Marcin Roguski (Kaelthas)
|
||||||
|
*/
|
||||||
|
/*package*/ class ConstraintLocLike extends Constraint {
|
||||||
|
private static final int LOCLIKE_X = 0x01;
|
||||||
|
private static final int LOCLIKE_Y = 0x02;
|
||||||
|
private static final int LOCLIKE_Z = 0x04;
|
||||||
|
/* LOCLIKE_TIP is a depreceated option... use headtail=1.0f instead */
|
||||||
|
//protected static final int LOCLIKE_TIP = 0x08;
|
||||||
|
private static final int LOCLIKE_X_INVERT = 0x10;
|
||||||
|
private static final int LOCLIKE_Y_INVERT = 0x20;
|
||||||
|
private static final int LOCLIKE_Z_INVERT = 0x40;
|
||||||
|
private static final int LOCLIKE_OFFSET = 0x80;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor creates the constraint instance.
|
||||||
|
*
|
||||||
|
* @param constraintStructure
|
||||||
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
|
* @param boneOMA
|
||||||
|
* the old memory address of the constraint owner
|
||||||
|
* @param influenceIpo
|
||||||
|
* the ipo curve of the influence factor
|
||||||
|
* @param dataRepository
|
||||||
|
* the data repository
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* this exception is thrown when the blender file is somehow
|
||||||
|
* corrupted
|
||||||
|
*/
|
||||||
|
public ConstraintLocLike(Structure constraintStructure, Long boneOMA,
|
||||||
|
Ipo influenceIpo, DataRepository dataRepository) throws BlenderFileException {
|
||||||
|
super(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation) {
|
||||||
|
BoneTrack boneTrack = this.getBoneTrack(skeleton, boneAnimation);
|
||||||
|
if (boneTrack != null) {
|
||||||
|
Vector3f targetLocation = this.getTargetLocation();
|
||||||
|
int flag = ((Number) data.getFieldValue("flag")).intValue();
|
||||||
|
Vector3f[] translations = boneTrack.getTranslations();
|
||||||
|
int maxFrames = translations.length;
|
||||||
|
for (int frame = 0; frame < maxFrames; ++frame) {
|
||||||
|
Vector3f offset = Vector3f.ZERO;
|
||||||
|
if ((flag & LOCLIKE_OFFSET) != 0) {//we add the original location to the copied location
|
||||||
|
offset = translations[frame].clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((flag & LOCLIKE_X) != 0) {
|
||||||
|
translations[frame].x = targetLocation.x;
|
||||||
|
if ((flag & LOCLIKE_X_INVERT) != 0) {
|
||||||
|
translations[frame].x = -translations[frame].x;
|
||||||
|
}
|
||||||
|
} else if ((flag & LOCLIKE_Y) != 0) {
|
||||||
|
translations[frame].y = targetLocation.y;
|
||||||
|
if ((flag & LOCLIKE_Y_INVERT) != 0) {
|
||||||
|
translations[frame].y = -translations[frame].y;
|
||||||
|
}
|
||||||
|
} else if ((flag & LOCLIKE_Z) != 0) {
|
||||||
|
translations[frame].z = targetLocation.z;
|
||||||
|
if ((flag & LOCLIKE_Z_INVERT) != 0) {
|
||||||
|
translations[frame].z = -translations[frame].z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
translations[frame].addLocal(offset);//TODO: ipo influence
|
||||||
|
}
|
||||||
|
boneTrack.setKeyframes(boneTrack.getTimes(), translations, boneTrack.getRotations(), boneTrack.getScales());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConstraintType getType() {
|
||||||
|
return ConstraintType.CONSTRAINT_TYPE_LOCLIKE;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,98 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
|
import com.jme3.animation.BoneAnimation;
|
||||||
|
import com.jme3.animation.BoneTrack;
|
||||||
|
import com.jme3.animation.Skeleton;
|
||||||
|
import com.jme3.math.Vector3f;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents 'Loc limit' constraint type in blender.
|
||||||
|
* @author Marcin Roguski (Kaelthas)
|
||||||
|
*/
|
||||||
|
/*package*/ class ConstraintLocLimit extends Constraint {
|
||||||
|
private static final int LIMIT_XMIN = 0x01;
|
||||||
|
private static final int LIMIT_XMAX = 0x02;
|
||||||
|
private static final int LIMIT_YMIN = 0x04;
|
||||||
|
private static final int LIMIT_YMAX = 0x08;
|
||||||
|
private static final int LIMIT_ZMIN = 0x10;
|
||||||
|
private static final int LIMIT_ZMAX = 0x20;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor creates the constraint instance.
|
||||||
|
*
|
||||||
|
* @param constraintStructure
|
||||||
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
|
* @param boneOMA
|
||||||
|
* the old memory address of the constraint owner
|
||||||
|
* @param influenceIpo
|
||||||
|
* the ipo curve of the influence factor
|
||||||
|
* @param dataRepository
|
||||||
|
* the data repository
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* this exception is thrown when the blender file is somehow
|
||||||
|
* corrupted
|
||||||
|
*/
|
||||||
|
public ConstraintLocLimit(Structure constraintStructure, Long boneOMA,
|
||||||
|
Ipo influenceIpo, DataRepository dataRepository) throws BlenderFileException {
|
||||||
|
super(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation) {
|
||||||
|
BoneTrack boneTrack = this.getBoneTrack(skeleton, boneAnimation);
|
||||||
|
if (boneTrack != null) {
|
||||||
|
int flag = ((Number) data.getFieldValue("flag")).intValue();
|
||||||
|
Vector3f[] translations = boneTrack.getTranslations();
|
||||||
|
int maxFrames = translations.length;
|
||||||
|
for (int frame = 0; frame < maxFrames; ++frame) {
|
||||||
|
float influence = ipo.calculateValue(frame);
|
||||||
|
if ((flag & LIMIT_XMIN) != 0) {
|
||||||
|
float xmin = ((Number) data.getFieldValue("xmin")).floatValue();
|
||||||
|
if (translations[frame].x < xmin) {
|
||||||
|
translations[frame].x -= (translations[frame].x - xmin) * influence;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((flag & LIMIT_XMAX) != 0) {
|
||||||
|
float xmax = ((Number) data.getFieldValue("xmax")).floatValue();
|
||||||
|
if (translations[frame].x > xmax) {
|
||||||
|
translations[frame].x -= (translations[frame].x - xmax) * influence;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((flag & LIMIT_YMIN) != 0) {
|
||||||
|
float ymin = ((Number) data.getFieldValue("ymin")).floatValue();
|
||||||
|
if (translations[frame].y < ymin) {
|
||||||
|
translations[frame].y -= (translations[frame].y - ymin) * influence;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((flag & LIMIT_YMAX) != 0) {
|
||||||
|
float ymax = ((Number) data.getFieldValue("ymax")).floatValue();
|
||||||
|
if (translations[frame].y > ymax) {
|
||||||
|
translations[frame].y -= (translations[frame].y - ymax) * influence;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((flag & LIMIT_ZMIN) != 0) {
|
||||||
|
float zmin = ((Number) data.getFieldValue("zmin")).floatValue();
|
||||||
|
if (translations[frame].z < zmin) {
|
||||||
|
translations[frame].z -= (translations[frame].z - zmin) * influence;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((flag & LIMIT_ZMAX) != 0) {
|
||||||
|
float zmax = ((Number) data.getFieldValue("zmax")).floatValue();
|
||||||
|
if (translations[frame].z > zmax) {
|
||||||
|
translations[frame].z -= (translations[frame].z - zmax) * influence;
|
||||||
|
}
|
||||||
|
}//TODO: consider constraint space !!!
|
||||||
|
}
|
||||||
|
boneTrack.setKeyframes(boneTrack.getTimes(), translations, boneTrack.getRotations(), boneTrack.getScales());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConstraintType getType() {
|
||||||
|
return ConstraintType.CONSTRAINT_TYPE_LOCLIMIT;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import com.jme3.animation.BoneAnimation;
|
||||||
|
import com.jme3.animation.Skeleton;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents 'Action' constraint type in blender.
|
||||||
|
* @author Marcin Roguski (Kaelthas)
|
||||||
|
*/
|
||||||
|
/*package*/ class ConstraintLockTrack extends Constraint {
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(ConstraintLockTrack.class.getName());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor creates the constraint instance.
|
||||||
|
*
|
||||||
|
* @param constraintStructure
|
||||||
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
|
* @param boneOMA
|
||||||
|
* the old memory address of the constraint owner
|
||||||
|
* @param influenceIpo
|
||||||
|
* the ipo curve of the influence factor
|
||||||
|
* @param dataRepository
|
||||||
|
* the data repository
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* this exception is thrown when the blender file is somehow
|
||||||
|
* corrupted
|
||||||
|
*/
|
||||||
|
public ConstraintLockTrack(Structure constraintStructure, Long boneOMA,
|
||||||
|
Ipo influenceIpo, DataRepository dataRepository)
|
||||||
|
throws BlenderFileException {
|
||||||
|
super(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation) {
|
||||||
|
// TODO: implement 'Lock track' constraint
|
||||||
|
LOGGER.log(Level.WARNING, "'Lock track' constraint NOT implemented!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConstraintType getType() {
|
||||||
|
return ConstraintType.CONSTRAINT_TYPE_LOCKTRACK;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import com.jme3.animation.BoneAnimation;
|
||||||
|
import com.jme3.animation.Skeleton;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents 'Min max' constraint type in blender.
|
||||||
|
* @author Marcin Roguski (Kaelthas)
|
||||||
|
*/
|
||||||
|
/*package*/ class ConstraintMinMax extends Constraint {
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(ConstraintMinMax.class.getName());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor creates the constraint instance.
|
||||||
|
*
|
||||||
|
* @param constraintStructure
|
||||||
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
|
* @param boneOMA
|
||||||
|
* the old memory address of the constraint owner
|
||||||
|
* @param influenceIpo
|
||||||
|
* the ipo curve of the influence factor
|
||||||
|
* @param dataRepository
|
||||||
|
* the data repository
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* this exception is thrown when the blender file is somehow
|
||||||
|
* corrupted
|
||||||
|
*/
|
||||||
|
public ConstraintMinMax(Structure constraintStructure, Long boneOMA,
|
||||||
|
Ipo influenceIpo, DataRepository dataRepository) throws BlenderFileException {
|
||||||
|
super(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation) {
|
||||||
|
// TODO: implement 'Min max' constraint
|
||||||
|
LOGGER.log(Level.WARNING, "'Min max' constraint NOT implemented!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConstraintType getType() {
|
||||||
|
return ConstraintType.CONSTRAINT_TYPE_MINMAX;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
|
import com.jme3.animation.BoneAnimation;
|
||||||
|
import com.jme3.animation.Skeleton;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents 'Null' constraint type in blender.
|
||||||
|
* @author Marcin Roguski (Kaelthas)
|
||||||
|
*/
|
||||||
|
/*package*/ class ConstraintNull extends Constraint {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor creates the constraint instance.
|
||||||
|
*
|
||||||
|
* @param constraintStructure
|
||||||
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
|
* @param boneOMA
|
||||||
|
* the old memory address of the constraint owner
|
||||||
|
* @param influenceIpo
|
||||||
|
* the ipo curve of the influence factor
|
||||||
|
* @param dataRepository
|
||||||
|
* the data repository
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* this exception is thrown when the blender file is somehow
|
||||||
|
* corrupted
|
||||||
|
*/
|
||||||
|
public ConstraintNull(Structure constraintStructure, Long boneOMA,
|
||||||
|
Ipo influenceIpo, DataRepository dataRepository)
|
||||||
|
throws BlenderFileException {
|
||||||
|
super(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConstraintType getType() {
|
||||||
|
return ConstraintType.CONSTRAINT_TYPE_NULL;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import com.jme3.animation.BoneAnimation;
|
||||||
|
import com.jme3.animation.Skeleton;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents 'Python' constraint type in blender.
|
||||||
|
* @author Marcin Roguski (Kaelthas)
|
||||||
|
*/
|
||||||
|
/*package*/ class ConstraintPython extends Constraint {
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(ConstraintPython.class.getName());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor creates the constraint instance.
|
||||||
|
*
|
||||||
|
* @param constraintStructure
|
||||||
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
|
* @param boneOMA
|
||||||
|
* the old memory address of the constraint owner
|
||||||
|
* @param influenceIpo
|
||||||
|
* the ipo curve of the influence factor
|
||||||
|
* @param dataRepository
|
||||||
|
* the data repository
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* this exception is thrown when the blender file is somehow
|
||||||
|
* corrupted
|
||||||
|
*/
|
||||||
|
public ConstraintPython(Structure constraintStructure, Long boneOMA,
|
||||||
|
Ipo influenceIpo, DataRepository dataRepository) throws BlenderFileException {
|
||||||
|
super(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation) {
|
||||||
|
// TODO: implement 'Python' constraint
|
||||||
|
LOGGER.log(Level.WARNING, "'Python' constraint NOT implemented!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConstraintType getType() {
|
||||||
|
return ConstraintType.CONSTRAINT_TYPE_PYTHON;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import com.jme3.animation.BoneAnimation;
|
||||||
|
import com.jme3.animation.Skeleton;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents 'Rigid body joint' constraint type in blender.
|
||||||
|
* @author Marcin Roguski (Kaelthas)
|
||||||
|
*/
|
||||||
|
/*package*/ class ConstraintRigidBodyJoint extends Constraint {
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(ConstraintRigidBodyJoint.class.getName());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor creates the constraint instance.
|
||||||
|
*
|
||||||
|
* @param constraintStructure
|
||||||
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
|
* @param boneOMA
|
||||||
|
* the old memory address of the constraint owner
|
||||||
|
* @param influenceIpo
|
||||||
|
* the ipo curve of the influence factor
|
||||||
|
* @param dataRepository
|
||||||
|
* the data repository
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* this exception is thrown when the blender file is somehow
|
||||||
|
* corrupted
|
||||||
|
*/
|
||||||
|
public ConstraintRigidBodyJoint(Structure constraintStructure,
|
||||||
|
Long boneOMA, Ipo influenceIpo, DataRepository dataRepository) throws BlenderFileException {
|
||||||
|
super(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation) {
|
||||||
|
// TODO: implement 'Rigid body joint' constraint
|
||||||
|
LOGGER.log(Level.WARNING, "'Rigid body joint' constraint NOT implemented!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConstraintType getType() {
|
||||||
|
return ConstraintType.CONSTRAINT_TYPE_RIGIDBODYJOINT;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,88 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
|
import com.jme3.animation.BoneAnimation;
|
||||||
|
import com.jme3.animation.BoneTrack;
|
||||||
|
import com.jme3.animation.Skeleton;
|
||||||
|
import com.jme3.math.Quaternion;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents 'Rot like' constraint type in blender.
|
||||||
|
* @author Marcin Roguski (Kaelthas)
|
||||||
|
*/
|
||||||
|
/*package*/ class ConstraintRotLike extends Constraint {
|
||||||
|
private static final int ROTLIKE_X = 0x01;
|
||||||
|
private static final int ROTLIKE_Y = 0x02;
|
||||||
|
private static final int ROTLIKE_Z = 0x04;
|
||||||
|
private static final int ROTLIKE_X_INVERT = 0x10;
|
||||||
|
private static final int ROTLIKE_Y_INVERT = 0x20;
|
||||||
|
private static final int ROTLIKE_Z_INVERT = 0x40;
|
||||||
|
private static final int ROTLIKE_OFFSET = 0x80;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor creates the constraint instance.
|
||||||
|
*
|
||||||
|
* @param constraintStructure
|
||||||
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
|
* @param boneOMA
|
||||||
|
* the old memory address of the constraint owner
|
||||||
|
* @param influenceIpo
|
||||||
|
* the ipo curve of the influence factor
|
||||||
|
* @param dataRepository
|
||||||
|
* the data repository
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* this exception is thrown when the blender file is somehow
|
||||||
|
* corrupted
|
||||||
|
*/
|
||||||
|
public ConstraintRotLike(Structure constraintStructure, Long boneOMA,
|
||||||
|
Ipo influenceIpo, DataRepository dataRepository) throws BlenderFileException {
|
||||||
|
super(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation) {
|
||||||
|
BoneTrack boneTrack = this.getBoneTrack(skeleton, boneAnimation);
|
||||||
|
if (boneTrack != null) {
|
||||||
|
Quaternion targetRotation = this.getTargetRotation();
|
||||||
|
int flag = ((Number) data.getFieldValue("flag")).intValue();
|
||||||
|
float[] targetAngles = targetRotation.toAngles(null);
|
||||||
|
Quaternion[] rotations = boneTrack.getRotations();
|
||||||
|
int maxFrames = rotations.length;
|
||||||
|
for (int frame = 0; frame < maxFrames; ++frame) {
|
||||||
|
float[] angles = rotations[frame].toAngles(null);
|
||||||
|
|
||||||
|
Quaternion offset = Quaternion.IDENTITY;
|
||||||
|
if ((flag & ROTLIKE_OFFSET) != 0) {//we add the original rotation to the copied rotation
|
||||||
|
offset = rotations[frame].clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((flag & ROTLIKE_X) != 0) {
|
||||||
|
angles[0] = targetAngles[0];
|
||||||
|
if ((flag & ROTLIKE_X_INVERT) != 0) {
|
||||||
|
angles[0] = -angles[0];
|
||||||
|
}
|
||||||
|
} else if ((flag & ROTLIKE_Y) != 0) {
|
||||||
|
angles[1] = targetAngles[1];
|
||||||
|
if ((flag & ROTLIKE_Y_INVERT) != 0) {
|
||||||
|
angles[1] = -angles[1];
|
||||||
|
}
|
||||||
|
} else if ((flag & ROTLIKE_Z) != 0) {
|
||||||
|
angles[2] = targetAngles[2];
|
||||||
|
if ((flag & ROTLIKE_Z_INVERT) != 0) {
|
||||||
|
angles[2] = -angles[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rotations[frame].fromAngles(angles).multLocal(offset);//TODO: ipo influence
|
||||||
|
}
|
||||||
|
boneTrack.setKeyframes(boneTrack.getTimes(), boneTrack.getTranslations(), rotations, boneTrack.getScales());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConstraintType getType() {
|
||||||
|
return ConstraintType.CONSTRAINT_TYPE_ROTLIKE;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,95 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
|
import com.jme3.animation.BoneAnimation;
|
||||||
|
import com.jme3.animation.BoneTrack;
|
||||||
|
import com.jme3.animation.Skeleton;
|
||||||
|
import com.jme3.math.FastMath;
|
||||||
|
import com.jme3.math.Quaternion;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents 'Rot limit' constraint type in blender.
|
||||||
|
* @author Marcin Roguski (Kaelthas)
|
||||||
|
*/
|
||||||
|
/*package*/ class ConstraintRotLimit extends Constraint {
|
||||||
|
private static final int LIMIT_XROT = 0x01;
|
||||||
|
private static final int LIMIT_YROT = 0x02;
|
||||||
|
private static final int LIMIT_ZROT = 0x04;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor creates the constraint instance.
|
||||||
|
*
|
||||||
|
* @param constraintStructure
|
||||||
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
|
* @param boneOMA
|
||||||
|
* the old memory address of the constraint owner
|
||||||
|
* @param influenceIpo
|
||||||
|
* the ipo curve of the influence factor
|
||||||
|
* @param dataRepository
|
||||||
|
* the data repository
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* this exception is thrown when the blender file is somehow
|
||||||
|
* corrupted
|
||||||
|
*/
|
||||||
|
public ConstraintRotLimit(Structure constraintStructure, Long boneOMA,
|
||||||
|
Ipo influenceIpo, DataRepository dataRepository) throws BlenderFileException {
|
||||||
|
super(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation) {
|
||||||
|
BoneTrack boneTrack = this.getBoneTrack(skeleton, boneAnimation);
|
||||||
|
if (boneTrack != null) {
|
||||||
|
int flag = ((Number) data.getFieldValue("flag")).intValue();
|
||||||
|
Quaternion[] rotations = boneTrack.getRotations();
|
||||||
|
int maxFrames = rotations.length;
|
||||||
|
for (int frame = 0; frame < maxFrames; ++frame) {
|
||||||
|
float[] angles = rotations[frame].toAngles(null);
|
||||||
|
float influence = ipo.calculateValue(frame);
|
||||||
|
if ((flag & LIMIT_XROT) != 0) {
|
||||||
|
float xmin = ((Number) data.getFieldValue("xmin")).floatValue() * FastMath.DEG_TO_RAD;
|
||||||
|
float xmax = ((Number) data.getFieldValue("xmax")).floatValue() * FastMath.DEG_TO_RAD;
|
||||||
|
float difference = 0.0f;
|
||||||
|
if (angles[0] < xmin) {
|
||||||
|
difference = (angles[0] - xmin) * influence;
|
||||||
|
} else if (angles[0] > xmax) {
|
||||||
|
difference = (angles[0] - xmax) * influence;
|
||||||
|
}
|
||||||
|
angles[0] -= difference;
|
||||||
|
}
|
||||||
|
if ((flag & LIMIT_YROT) != 0) {
|
||||||
|
float ymin = ((Number) data.getFieldValue("ymin")).floatValue() * FastMath.DEG_TO_RAD;
|
||||||
|
float ymax = ((Number) data.getFieldValue("ymax")).floatValue() * FastMath.DEG_TO_RAD;
|
||||||
|
float difference = 0.0f;
|
||||||
|
if (angles[1] < ymin) {
|
||||||
|
difference = (angles[1] - ymin) * influence;
|
||||||
|
} else if (angles[1] > ymax) {
|
||||||
|
difference = (angles[1] - ymax) * influence;
|
||||||
|
}
|
||||||
|
angles[1] -= difference;
|
||||||
|
}
|
||||||
|
if ((flag & LIMIT_ZROT) != 0) {
|
||||||
|
float zmin = ((Number) data.getFieldValue("zmin")).floatValue() * FastMath.DEG_TO_RAD;
|
||||||
|
float zmax = ((Number) data.getFieldValue("zmax")).floatValue() * FastMath.DEG_TO_RAD;
|
||||||
|
float difference = 0.0f;
|
||||||
|
if (angles[2] < zmin) {
|
||||||
|
difference = (angles[2] - zmin) * influence;
|
||||||
|
} else if (angles[2] > zmax) {
|
||||||
|
difference = (angles[2] - zmax) * influence;
|
||||||
|
}
|
||||||
|
angles[2] -= difference;
|
||||||
|
}
|
||||||
|
rotations[frame].fromAngles(angles);//TODO: consider constraint space !!!
|
||||||
|
}
|
||||||
|
boneTrack.setKeyframes(boneTrack.getTimes(), boneTrack.getTranslations(), rotations, boneTrack.getScales());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConstraintType getType() {
|
||||||
|
return ConstraintType.CONSTRAINT_TYPE_ROTLIMIT;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,100 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import com.jme3.animation.BoneAnimation;
|
||||||
|
import com.jme3.animation.BoneTrack;
|
||||||
|
import com.jme3.animation.Skeleton;
|
||||||
|
import com.jme3.math.Quaternion;
|
||||||
|
import com.jme3.math.Vector3f;
|
||||||
|
import com.jme3.scene.Geometry;
|
||||||
|
import com.jme3.scene.Mesh;
|
||||||
|
import com.jme3.scene.Node;
|
||||||
|
import com.jme3.scene.Spatial;
|
||||||
|
import com.jme3.scene.VertexBuffer.Type;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository.LoadedFeatureDataType;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents 'Shrink wrap' constraint type in blender.
|
||||||
|
* @author Marcin Roguski (Kaelthas)
|
||||||
|
*/
|
||||||
|
/*package*/ class ConstraintShrinkWrap extends Constraint {
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(ConstraintShrinkWrap.class.getName());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor creates the constraint instance.
|
||||||
|
*
|
||||||
|
* @param constraintStructure
|
||||||
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
|
* @param boneOMA
|
||||||
|
* the old memory address of the constraint owner
|
||||||
|
* @param influenceIpo
|
||||||
|
* the ipo curve of the influence factor
|
||||||
|
* @param dataRepository
|
||||||
|
* the data repository
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* this exception is thrown when the blender file is somehow
|
||||||
|
* corrupted
|
||||||
|
*/
|
||||||
|
public ConstraintShrinkWrap(Structure constraintStructure, Long boneOMA,
|
||||||
|
Ipo influenceIpo, DataRepository dataRepository) throws BlenderFileException {
|
||||||
|
super(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation) {
|
||||||
|
//loading mesh points (blender ensures that the target is a mesh-object)
|
||||||
|
List<Vector3f> pts = new ArrayList<Vector3f>();
|
||||||
|
try {
|
||||||
|
Node node = (Node)this.getTarget(LoadedFeatureDataType.LOADED_FEATURE);
|
||||||
|
for(Spatial spatial : node.getChildren()) {
|
||||||
|
if(spatial instanceof Geometry) {
|
||||||
|
Mesh mesh = ((Geometry) spatial).getMesh();
|
||||||
|
FloatBuffer floatBuffer = mesh.getFloatBuffer(Type.Position);
|
||||||
|
for(int i=0;i<floatBuffer.limit();i+=3) {
|
||||||
|
pts.add(new Vector3f(floatBuffer.get(i), floatBuffer.get(i + 1), floatBuffer.get(i + 2)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//modifying traces
|
||||||
|
BoneTrack boneTrack = this.getBoneTrack(skeleton, boneAnimation);
|
||||||
|
if (boneTrack != null) {
|
||||||
|
Vector3f[] translations = boneTrack.getTranslations();
|
||||||
|
Quaternion[] rotations = boneTrack.getRotations();
|
||||||
|
int maxFrames = translations.length;
|
||||||
|
for (int frame = 0; frame < maxFrames; ++frame) {
|
||||||
|
Vector3f currentTranslation = translations[frame];
|
||||||
|
|
||||||
|
//looking for minimum distanced point
|
||||||
|
Vector3f minDistancePoint = null;
|
||||||
|
float distance = Float.MAX_VALUE;
|
||||||
|
for(Vector3f p : pts) {
|
||||||
|
float temp = currentTranslation.distance(p);
|
||||||
|
if(temp < distance) {
|
||||||
|
distance = temp;
|
||||||
|
minDistancePoint = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
translations[frame] = minDistancePoint.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
boneTrack.setKeyframes(boneTrack.getTimes(), translations, rotations, boneTrack.getScales());
|
||||||
|
}
|
||||||
|
} catch (BlenderFileException e) {
|
||||||
|
LOGGER.severe(e.getLocalizedMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConstraintType getType() {
|
||||||
|
return ConstraintType.CONSTRAINT_TYPE_SHRINKWRAP;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
|
import com.jme3.animation.BoneAnimation;
|
||||||
|
import com.jme3.animation.BoneTrack;
|
||||||
|
import com.jme3.animation.Skeleton;
|
||||||
|
import com.jme3.math.Vector3f;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents 'Size like' constraint type in blender.
|
||||||
|
* @author Marcin Roguski (Kaelthas)
|
||||||
|
*/
|
||||||
|
/*package*/ class ConstraintSizeLike extends Constraint {
|
||||||
|
private static final int SIZELIKE_X = 0x01;
|
||||||
|
private static final int SIZELIKE_Y = 0x02;
|
||||||
|
private static final int SIZELIKE_Z = 0x04;
|
||||||
|
private static final int LOCLIKE_OFFSET = 0x80;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor creates the constraint instance.
|
||||||
|
*
|
||||||
|
* @param constraintStructure
|
||||||
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
|
* @param boneOMA
|
||||||
|
* the old memory address of the constraint owner
|
||||||
|
* @param influenceIpo
|
||||||
|
* the ipo curve of the influence factor
|
||||||
|
* @param dataRepository
|
||||||
|
* the data repository
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* this exception is thrown when the blender file is somehow
|
||||||
|
* corrupted
|
||||||
|
*/
|
||||||
|
public ConstraintSizeLike(Structure constraintStructure, Long boneOMA,
|
||||||
|
Ipo influenceIpo, DataRepository dataRepository) throws BlenderFileException {
|
||||||
|
super(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation) {
|
||||||
|
Vector3f targetScale = this.getTargetLocation();
|
||||||
|
BoneTrack boneTrack = this.getBoneTrack(skeleton, boneAnimation);
|
||||||
|
if (boneTrack != null) {
|
||||||
|
int flag = ((Number) data.getFieldValue("flag")).intValue();
|
||||||
|
Vector3f[] scales = boneTrack.getScales();
|
||||||
|
int maxFrames = scales.length;
|
||||||
|
for (int frame = 0; frame < maxFrames; ++frame) {
|
||||||
|
Vector3f offset = Vector3f.ZERO;
|
||||||
|
if ((flag & LOCLIKE_OFFSET) != 0) {//we add the original scale to the copied scale
|
||||||
|
offset = scales[frame].clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((flag & SIZELIKE_X) != 0) {
|
||||||
|
scales[frame].x = targetScale.x;
|
||||||
|
} else if ((flag & SIZELIKE_Y) != 0) {
|
||||||
|
scales[frame].y = targetScale.y;
|
||||||
|
} else if ((flag & SIZELIKE_Z) != 0) {
|
||||||
|
scales[frame].z = targetScale.z;
|
||||||
|
}
|
||||||
|
scales[frame].addLocal(offset);//TODO: ipo influence
|
||||||
|
//TODO: add or multiply???
|
||||||
|
}
|
||||||
|
boneTrack.setKeyframes(boneTrack.getTimes(), boneTrack.getTranslations(), boneTrack.getRotations(), scales);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConstraintType getType() {
|
||||||
|
return ConstraintType.CONSTRAINT_TYPE_SIZELIKE;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,98 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
|
import com.jme3.animation.BoneAnimation;
|
||||||
|
import com.jme3.animation.BoneTrack;
|
||||||
|
import com.jme3.animation.Skeleton;
|
||||||
|
import com.jme3.math.Vector3f;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents 'Size limit' constraint type in blender.
|
||||||
|
* @author Marcin Roguski (Kaelthas)
|
||||||
|
*/
|
||||||
|
/*package*/ class ConstraintSizeLimit extends Constraint {
|
||||||
|
private static final int LIMIT_XMIN = 0x01;
|
||||||
|
private static final int LIMIT_XMAX = 0x02;
|
||||||
|
private static final int LIMIT_YMIN = 0x04;
|
||||||
|
private static final int LIMIT_YMAX = 0x08;
|
||||||
|
private static final int LIMIT_ZMIN = 0x10;
|
||||||
|
private static final int LIMIT_ZMAX = 0x20;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor creates the constraint instance.
|
||||||
|
*
|
||||||
|
* @param constraintStructure
|
||||||
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
|
* @param boneOMA
|
||||||
|
* the old memory address of the constraint owner
|
||||||
|
* @param influenceIpo
|
||||||
|
* the ipo curve of the influence factor
|
||||||
|
* @param dataRepository
|
||||||
|
* the data repository
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* this exception is thrown when the blender file is somehow
|
||||||
|
* corrupted
|
||||||
|
*/
|
||||||
|
public ConstraintSizeLimit(Structure constraintStructure, Long boneOMA,
|
||||||
|
Ipo influenceIpo, DataRepository dataRepository) throws BlenderFileException {
|
||||||
|
super(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation) {
|
||||||
|
BoneTrack boneTrack = this.getBoneTrack(skeleton, boneAnimation);
|
||||||
|
if (boneTrack != null) {
|
||||||
|
int flag = ((Number) data.getFieldValue("flag")).intValue();
|
||||||
|
Vector3f[] scales = boneTrack.getScales();
|
||||||
|
int maxFrames = scales.length;
|
||||||
|
for (int frame = 0; frame < maxFrames; ++frame) {
|
||||||
|
float influence = ipo.calculateValue(frame);
|
||||||
|
if ((flag & LIMIT_XMIN) != 0) {
|
||||||
|
float xmin = ((Number) data.getFieldValue("xmin")).floatValue();
|
||||||
|
if (scales[frame].x < xmin) {
|
||||||
|
scales[frame].x -= (scales[frame].x - xmin) * influence;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((flag & LIMIT_XMAX) != 0) {
|
||||||
|
float xmax = ((Number) data.getFieldValue("xmax")).floatValue();
|
||||||
|
if (scales[frame].x > xmax) {
|
||||||
|
scales[frame].x -= (scales[frame].x - xmax) * influence;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((flag & LIMIT_YMIN) != 0) {
|
||||||
|
float ymin = ((Number) data.getFieldValue("ymin")).floatValue();
|
||||||
|
if (scales[frame].y < ymin) {
|
||||||
|
scales[frame].y -= (scales[frame].y - ymin) * influence;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((flag & LIMIT_YMAX) != 0) {
|
||||||
|
float ymax = ((Number) data.getFieldValue("ymax")).floatValue();
|
||||||
|
if (scales[frame].y > ymax) {
|
||||||
|
scales[frame].y -= (scales[frame].y - ymax) * influence;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((flag & LIMIT_ZMIN) != 0) {
|
||||||
|
float zmin = ((Number) data.getFieldValue("zmin")).floatValue();
|
||||||
|
if (scales[frame].z < zmin) {
|
||||||
|
scales[frame].z -= (scales[frame].z - zmin) * influence;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((flag & LIMIT_ZMAX) != 0) {
|
||||||
|
float zmax = ((Number) data.getFieldValue("zmax")).floatValue();
|
||||||
|
if (scales[frame].z > zmax) {
|
||||||
|
scales[frame].z -= (scales[frame].z - zmax) * influence;
|
||||||
|
}
|
||||||
|
}//TODO: consider constraint space !!!
|
||||||
|
}
|
||||||
|
boneTrack.setKeyframes(boneTrack.getTimes(), boneTrack.getTranslations(), boneTrack.getRotations(), scales);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConstraintType getType() {
|
||||||
|
return ConstraintType.CONSTRAINT_TYPE_SIZELIMIT;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import com.jme3.animation.BoneAnimation;
|
||||||
|
import com.jme3.animation.Skeleton;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents 'Stretch to' constraint type in blender.
|
||||||
|
* @author Marcin Roguski (Kaelthas)
|
||||||
|
*/
|
||||||
|
/*package*/ class ConstraintStretchTo extends Constraint {
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(ConstraintStretchTo.class.getName());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor creates the constraint instance.
|
||||||
|
*
|
||||||
|
* @param constraintStructure
|
||||||
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
|
* @param boneOMA
|
||||||
|
* the old memory address of the constraint owner
|
||||||
|
* @param influenceIpo
|
||||||
|
* the ipo curve of the influence factor
|
||||||
|
* @param dataRepository
|
||||||
|
* the data repository
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* this exception is thrown when the blender file is somehow
|
||||||
|
* corrupted
|
||||||
|
*/
|
||||||
|
public ConstraintStretchTo(Structure constraintStructure, Long boneOMA,
|
||||||
|
Ipo influenceIpo, DataRepository dataRepository)
|
||||||
|
throws BlenderFileException {
|
||||||
|
super(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation) {
|
||||||
|
// TODO: implement 'Stretch to' constraint
|
||||||
|
LOGGER.log(Level.WARNING, "'Stretch to' constraint NOT implemented!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConstraintType getType() {
|
||||||
|
return ConstraintType.CONSTRAINT_TYPE_STRETCHTO;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import com.jme3.animation.BoneAnimation;
|
||||||
|
import com.jme3.animation.Skeleton;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents 'Transform' constraint type in blender.
|
||||||
|
* @author Marcin Roguski (Kaelthas)
|
||||||
|
*/
|
||||||
|
/*package*/ class ConstraintTransform extends Constraint {
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(ConstraintAction.class.getName());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor creates the constraint instance.
|
||||||
|
*
|
||||||
|
* @param constraintStructure
|
||||||
|
* the constraint's structure (bConstraint clss in blender 2.49).
|
||||||
|
* @param boneOMA
|
||||||
|
* the old memory address of the constraint owner
|
||||||
|
* @param influenceIpo
|
||||||
|
* the ipo curve of the influence factor
|
||||||
|
* @param dataRepository
|
||||||
|
* the data repository
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* this exception is thrown when the blender file is somehow
|
||||||
|
* corrupted
|
||||||
|
*/
|
||||||
|
public ConstraintTransform(Structure constraintStructure, Long boneOMA,
|
||||||
|
Ipo influenceIpo, DataRepository dataRepository) throws BlenderFileException {
|
||||||
|
super(constraintStructure, boneOMA, influenceIpo, dataRepository);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation) {
|
||||||
|
// TODO: implement 'Transform' constraint
|
||||||
|
LOGGER.log(Level.WARNING, "'Transform' constraint NOT implemented!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConstraintType getType() {
|
||||||
|
return ConstraintType.CONSTRAINT_TYPE_TRANSFORM;
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package com.jme3.scene.plugins.blender.structures;
|
package com.jme3.scene.plugins.blender.constraints;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
@ -1,11 +1,11 @@
|
|||||||
package com.jme3.scene.plugins.blender.structures;
|
package com.jme3.scene.plugins.blender.curves;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.jme3.math.Vector3f;
|
import com.jme3.math.Vector3f;
|
||||||
import com.jme3.scene.plugins.blender.data.Structure;
|
import com.jme3.scene.plugins.blender.file.DynamicArray;
|
||||||
import com.jme3.scene.plugins.blender.utils.DynamicArray;
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class that helps to calculate the bezier curves calues. It uses doubles for performing calculations to minimize
|
* A class that helps to calculate the bezier curves calues. It uses doubles for performing calculations to minimize
|
@ -1,4 +1,4 @@
|
|||||||
package com.jme3.scene.plugins.blender.helpers.v249;
|
package com.jme3.scene.plugins.blender.curves;
|
||||||
|
|
||||||
import java.nio.FloatBuffer;
|
import java.nio.FloatBuffer;
|
||||||
import java.nio.IntBuffer;
|
import java.nio.IntBuffer;
|
||||||
@ -21,16 +21,17 @@ import com.jme3.math.Vector4f;
|
|||||||
import com.jme3.scene.Geometry;
|
import com.jme3.scene.Geometry;
|
||||||
import com.jme3.scene.Mesh;
|
import com.jme3.scene.Mesh;
|
||||||
import com.jme3.scene.VertexBuffer.Type;
|
import com.jme3.scene.VertexBuffer.Type;
|
||||||
import com.jme3.scene.plugins.blender.data.FileBlockHeader;
|
import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
|
||||||
import com.jme3.scene.plugins.blender.data.Structure;
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
import com.jme3.scene.plugins.blender.exception.BlenderFileException;
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
import com.jme3.scene.plugins.blender.structures.BezierCurve;
|
import com.jme3.scene.plugins.blender.file.BlenderInputStream;
|
||||||
import com.jme3.scene.plugins.blender.structures.Properties;
|
import com.jme3.scene.plugins.blender.file.DynamicArray;
|
||||||
import com.jme3.scene.plugins.blender.utils.AbstractBlenderHelper;
|
import com.jme3.scene.plugins.blender.file.FileBlockHeader;
|
||||||
import com.jme3.scene.plugins.blender.utils.BlenderInputStream;
|
import com.jme3.scene.plugins.blender.file.Pointer;
|
||||||
import com.jme3.scene.plugins.blender.utils.DataRepository;
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
import com.jme3.scene.plugins.blender.utils.DynamicArray;
|
import com.jme3.scene.plugins.blender.materials.MaterialHelper;
|
||||||
import com.jme3.scene.plugins.blender.utils.Pointer;
|
import com.jme3.scene.plugins.blender.meshes.MeshHelper;
|
||||||
|
import com.jme3.scene.plugins.blender.objects.Properties;
|
||||||
import com.jme3.scene.shape.Curve;
|
import com.jme3.scene.shape.Curve;
|
||||||
import com.jme3.scene.shape.Surface;
|
import com.jme3.scene.shape.Surface;
|
||||||
import com.jme3.util.BufferUtils;
|
import com.jme3.util.BufferUtils;
|
||||||
@ -604,4 +605,4 @@ public class CurvesHelper extends AbstractBlenderHelper {
|
|||||||
public boolean shouldBeLoaded(Structure structure, DataRepository dataRepository) {
|
public boolean shouldBeLoaded(Structure structure, DataRepository dataRepository) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -29,7 +29,7 @@
|
|||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
package com.jme3.scene.plugins.blender.exception;
|
package com.jme3.scene.plugins.blender.exceptions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This exception is thrown when blend file data is somehow invalid.
|
* This exception is thrown when blend file data is somehow invalid.
|
@ -29,7 +29,7 @@
|
|||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
package com.jme3.scene.plugins.blender.utils;
|
package com.jme3.scene.plugins.blender.file;
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
@ -39,7 +39,7 @@ import java.util.logging.Logger;
|
|||||||
import java.util.zip.GZIPInputStream;
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
||||||
import com.jme3.asset.AssetManager;
|
import com.jme3.asset.AssetManager;
|
||||||
import com.jme3.scene.plugins.blender.exception.BlenderFileException;
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An input stream with random access to data.
|
* An input stream with random access to data.
|
@ -29,14 +29,13 @@
|
|||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
package com.jme3.scene.plugins.blender.data;
|
package com.jme3.scene.plugins.blender.file;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.jme3.scene.plugins.blender.exception.BlenderFileException;
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
import com.jme3.scene.plugins.blender.utils.BlenderInputStream;
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
import com.jme3.scene.plugins.blender.utils.DataRepository;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The data block containing the description of the file.
|
* The data block containing the description of the file.
|
@ -29,9 +29,9 @@
|
|||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
package com.jme3.scene.plugins.blender.utils;
|
package com.jme3.scene.plugins.blender.file;
|
||||||
|
|
||||||
import com.jme3.scene.plugins.blender.exception.BlenderFileException;
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An array that can be dynamically modified/
|
* An array that can be dynamically modified/
|
@ -1,14 +1,11 @@
|
|||||||
package com.jme3.scene.plugins.blender.data;
|
package com.jme3.scene.plugins.blender.file;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.jme3.scene.plugins.blender.data.Structure.DataType;
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
import com.jme3.scene.plugins.blender.exception.BlenderFileException;
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
import com.jme3.scene.plugins.blender.utils.BlenderInputStream;
|
import com.jme3.scene.plugins.blender.file.Structure.DataType;
|
||||||
import com.jme3.scene.plugins.blender.utils.DataRepository;
|
|
||||||
import com.jme3.scene.plugins.blender.utils.DynamicArray;
|
|
||||||
import com.jme3.scene.plugins.blender.utils.Pointer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class represents a single field in the structure. It can be either a primitive type or a table or a reference to
|
* This class represents a single field in the structure. It can be either a primitive type or a table or a reference to
|
@ -29,11 +29,10 @@
|
|||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
package com.jme3.scene.plugins.blender.data;
|
package com.jme3.scene.plugins.blender.file;
|
||||||
|
|
||||||
import com.jme3.scene.plugins.blender.exception.BlenderFileException;
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
import com.jme3.scene.plugins.blender.utils.BlenderInputStream;
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
import com.jme3.scene.plugins.blender.utils.DataRepository;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class that holds the header data of a file block. The file block itself is not implemented. This class holds its
|
* A class that holds the header data of a file block. The file block itself is not implemented. This class holds its
|
@ -29,14 +29,13 @@
|
|||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
package com.jme3.scene.plugins.blender.utils;
|
package com.jme3.scene.plugins.blender.file;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.jme3.scene.plugins.blender.data.FileBlockHeader;
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
import com.jme3.scene.plugins.blender.data.Structure;
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
import com.jme3.scene.plugins.blender.exception.BlenderFileException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class that represents a pointer of any level that can be stored in the file.
|
* A class that represents a pointer of any level that can be stored in the file.
|
@ -29,17 +29,15 @@
|
|||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
package com.jme3.scene.plugins.blender.data;
|
package com.jme3.scene.plugins.blender.file;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.jme3.scene.plugins.blender.exception.BlenderFileException;
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
import com.jme3.scene.plugins.blender.utils.BlenderInputStream;
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
import com.jme3.scene.plugins.blender.utils.DataRepository;
|
|
||||||
import com.jme3.scene.plugins.blender.utils.Pointer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class representing a single structure in the file.
|
* A class representing a single structure in the file.
|
@ -1,132 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2009-2010 jMonkeyEngine
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are
|
|
||||||
* met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
*
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
||||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
||||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
package com.jme3.scene.plugins.blender.helpers;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import com.jme3.animation.BoneTrack;
|
|
||||||
import com.jme3.scene.plugins.blender.data.FileBlockHeader;
|
|
||||||
import com.jme3.scene.plugins.blender.data.Structure;
|
|
||||||
import com.jme3.scene.plugins.blender.exception.BlenderFileException;
|
|
||||||
import com.jme3.scene.plugins.blender.structures.BezierCurve;
|
|
||||||
import com.jme3.scene.plugins.blender.structures.Ipo;
|
|
||||||
import com.jme3.scene.plugins.blender.utils.BlenderInputStream;
|
|
||||||
import com.jme3.scene.plugins.blender.utils.DataRepository;
|
|
||||||
import com.jme3.scene.plugins.blender.utils.Pointer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class defines the methods to calculate certain aspects of animation and armature functionalities.
|
|
||||||
* @author Marcin Roguski
|
|
||||||
*/
|
|
||||||
public class ArmatureHelper extends com.jme3.scene.plugins.blender.helpers.v249.ArmatureHelper {
|
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(ArmatureHelper.class.getName());
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This constructor parses the given blender version and stores the result. Some functionalities may differ in
|
|
||||||
* different blender versions.
|
|
||||||
* @param blenderVersion
|
|
||||||
* the version read from the blend file
|
|
||||||
*/
|
|
||||||
public ArmatureHelper(String blenderVersion) {
|
|
||||||
super(blenderVersion);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BoneTrack[] getTracks(Structure actionStructure, DataRepository dataRepository, String objectName, String animationName) throws BlenderFileException {
|
|
||||||
if (blenderVersion < 250) {
|
|
||||||
return super.getTracks(actionStructure, dataRepository, objectName, animationName);
|
|
||||||
}
|
|
||||||
LOGGER.log(Level.INFO, "Getting tracks!");
|
|
||||||
int fps = dataRepository.getBlenderKey().getFps();
|
|
||||||
int[] animationFrames = dataRepository.getBlenderKey().getAnimationFrames(objectName, animationName);
|
|
||||||
Structure groups = (Structure) actionStructure.getFieldValue("groups");
|
|
||||||
List<Structure> actionGroups = groups.evaluateListBase(dataRepository);//bActionGroup
|
|
||||||
if (actionGroups != null && actionGroups.size() > 0 && (bonesMap == null || bonesMap.size() == 0)) {
|
|
||||||
throw new IllegalStateException("No bones found! Cannot proceed to calculating tracks!");
|
|
||||||
}
|
|
||||||
|
|
||||||
List<BoneTrack> tracks = new ArrayList<BoneTrack>();
|
|
||||||
for (Structure actionGroup : actionGroups) {
|
|
||||||
String name = actionGroup.getFieldValue("name").toString();
|
|
||||||
Integer boneIndex = bonesMap.get(name);
|
|
||||||
if (boneIndex != null) {
|
|
||||||
List<Structure> channels = ((Structure) actionGroup.getFieldValue("channels")).evaluateListBase(dataRepository);
|
|
||||||
BezierCurve[] bezierCurves = new BezierCurve[channels.size()];
|
|
||||||
int channelCounter = 0;
|
|
||||||
for (Structure c : channels) {
|
|
||||||
//reading rna path first
|
|
||||||
BlenderInputStream bis = dataRepository.getInputStream();
|
|
||||||
int currentPosition = bis.getPosition();
|
|
||||||
Pointer pRnaPath = (Pointer) c.getFieldValue("rna_path");
|
|
||||||
FileBlockHeader dataFileBlock = dataRepository.getFileBlock(pRnaPath.getOldMemoryAddress());
|
|
||||||
bis.setPosition(dataFileBlock.getBlockPosition());
|
|
||||||
String rnaPath = bis.readString();
|
|
||||||
bis.setPosition(currentPosition);
|
|
||||||
int arrayIndex = ((Number) c.getFieldValue("array_index")).intValue();
|
|
||||||
int type = this.getCurveType(rnaPath, arrayIndex);
|
|
||||||
|
|
||||||
Pointer pBezTriple = (Pointer) c.getFieldValue("bezt");
|
|
||||||
List<Structure> bezTriples = pBezTriple.fetchData(dataRepository.getInputStream());
|
|
||||||
bezierCurves[channelCounter++] = new BezierCurve(type, bezTriples, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ipo ipo = new Ipo(bezierCurves);
|
|
||||||
tracks.add(ipo.calculateTrack(boneIndex.intValue(), animationFrames[0], animationFrames[1], fps));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return tracks.toArray(new BoneTrack[tracks.size()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method parses the information stored inside the curve rna path and returns the proper type
|
|
||||||
* of the curve.
|
|
||||||
* @param rnaPath the curve's rna path
|
|
||||||
* @param arrayIndex the array index of the stored data
|
|
||||||
* @return the type of the curve
|
|
||||||
*/
|
|
||||||
protected int getCurveType(String rnaPath, int arrayIndex) {
|
|
||||||
if (rnaPath.endsWith(".location")) {
|
|
||||||
return Ipo.AC_LOC_X + arrayIndex;
|
|
||||||
}
|
|
||||||
if (rnaPath.endsWith(".rotation_quaternion")) {
|
|
||||||
return Ipo.AC_QUAT_W + arrayIndex;
|
|
||||||
}
|
|
||||||
if (rnaPath.endsWith(".scale")) {
|
|
||||||
return Ipo.AC_SIZE_X + arrayIndex;
|
|
||||||
}
|
|
||||||
throw new IllegalStateException("Unknown curve rna path: " + rnaPath);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,52 +0,0 @@
|
|||||||
package com.jme3.scene.plugins.blender.helpers;
|
|
||||||
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import com.jme3.renderer.Camera;
|
|
||||||
import com.jme3.scene.plugins.blender.data.Structure;
|
|
||||||
import com.jme3.scene.plugins.blender.exception.BlenderFileException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A class that is used in light calculations.
|
|
||||||
* @author Marcin Roguski
|
|
||||||
*/
|
|
||||||
public class CameraHelper extends com.jme3.scene.plugins.blender.helpers.v249.CameraHelper {
|
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(CameraHelper.class.getName());
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This constructor parses the given blender version and stores the result. Some functionalities may differ in
|
|
||||||
* different blender versions.
|
|
||||||
* @param blenderVersion
|
|
||||||
* the version read from the blend file
|
|
||||||
*/
|
|
||||||
public CameraHelper(String blenderVersion) {
|
|
||||||
super(blenderVersion);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Camera toCamera(Structure structure) throws BlenderFileException {
|
|
||||||
if (blenderVersion < 250) {
|
|
||||||
return super.toCamera(structure);
|
|
||||||
}
|
|
||||||
Camera result = new Camera(DEFAULT_CAM_WIDTH, DEFAULT_CAM_HEIGHT);
|
|
||||||
int type = ((Number) structure.getFieldValue("type")).intValue();
|
|
||||||
if (type != 0 && type != 1) {
|
|
||||||
LOGGER.log(Level.WARNING, "Unknown camera type: {0}. Perspective camera is being used!", type);
|
|
||||||
type = 0;
|
|
||||||
}
|
|
||||||
//type==0 - perspective; type==1 - orthographic; perspective is used as default
|
|
||||||
result.setParallelProjection(type == 1);
|
|
||||||
float aspect = 0;
|
|
||||||
float clipsta = ((Number) structure.getFieldValue("clipsta")).floatValue();
|
|
||||||
float clipend = ((Number) structure.getFieldValue("clipend")).floatValue();
|
|
||||||
if (type == 0) {
|
|
||||||
aspect = ((Number) structure.getFieldValue("lens")).floatValue();
|
|
||||||
} else {
|
|
||||||
aspect = ((Number) structure.getFieldValue("ortho_scale")).floatValue();
|
|
||||||
}
|
|
||||||
result.setFrustumPerspective(45, aspect, clipsta, clipend);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
package com.jme3.scene.plugins.blender.helpers;
|
|
||||||
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import com.jme3.scene.plugins.blender.data.Structure;
|
|
||||||
import com.jme3.scene.plugins.blender.exception.BlenderFileException;
|
|
||||||
import com.jme3.scene.plugins.blender.utils.DataRepository;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class should be used for constraint calculations.
|
|
||||||
* @author Marcin Roguski
|
|
||||||
*/
|
|
||||||
public class ConstraintHelper extends com.jme3.scene.plugins.blender.helpers.v249.ConstraintHelper {
|
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(ConstraintHelper.class.getName());
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper constructor. It's main task is to generate the affection functions. These functions are common to all
|
|
||||||
* ConstraintHelper instances. Unfortunately this constructor might grow large. If it becomes too large - I shall
|
|
||||||
* consider refactoring. The constructor parses the given blender version and stores the result. Some
|
|
||||||
* functionalities may differ in different blender versions.
|
|
||||||
* @param blenderVersion
|
|
||||||
* the version read from the blend file
|
|
||||||
*/
|
|
||||||
public ConstraintHelper(String blenderVersion, DataRepository dataRepository) {
|
|
||||||
super(blenderVersion, dataRepository);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void loadConstraints(Structure objectStructure, DataRepository dataRepository) throws BlenderFileException {
|
|
||||||
if (blenderVersion < 250) {
|
|
||||||
super.loadConstraints(objectStructure, dataRepository);
|
|
||||||
} else {
|
|
||||||
LOGGER.warning("Loading of constraints not yet implemented for version 2.5x !");
|
|
||||||
//TODO: to implement
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
package com.jme3.scene.plugins.blender.helpers;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A class that is used in mesh calculations.
|
|
||||||
* @author Marcin Roguski
|
|
||||||
*/
|
|
||||||
public class CurvesHelper extends com.jme3.scene.plugins.blender.helpers.v249.CurvesHelper {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This constructor parses the given blender version and stores the result. Some functionalities may differ in
|
|
||||||
* different blender versions.
|
|
||||||
* @param blenderVersion
|
|
||||||
* the version read from the blend file
|
|
||||||
*/
|
|
||||||
public CurvesHelper(String blenderVersion) {
|
|
||||||
super(blenderVersion);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
package com.jme3.scene.plugins.blender.helpers;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class helps to compute values from interpolation curves for features like animation or constraint influence. The
|
|
||||||
* curves are 3rd degree bezier curves.
|
|
||||||
* @author Marcin Roguski
|
|
||||||
*/
|
|
||||||
public class IpoHelper extends com.jme3.scene.plugins.blender.helpers.v249.IpoHelper {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This constructor parses the given blender version and stores the result. Some functionalities may differ in
|
|
||||||
* different blender versions.
|
|
||||||
* @param blenderVersion
|
|
||||||
* the version read from the blend file
|
|
||||||
*/
|
|
||||||
public IpoHelper(String blenderVersion) {
|
|
||||||
super(blenderVersion);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2009-2010 jMonkeyEngine
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are
|
|
||||||
* met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
*
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
||||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
||||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
package com.jme3.scene.plugins.blender.helpers;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A class that is used in light calculations.
|
|
||||||
* @author Marcin Roguski
|
|
||||||
*/
|
|
||||||
public class LightHelper extends com.jme3.scene.plugins.blender.helpers.v249.LightHelper {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This constructor parses the given blender version and stores the result. Some functionalities may differ in
|
|
||||||
* different blender versions.
|
|
||||||
* @param blenderVersion
|
|
||||||
* the version read from the blend file
|
|
||||||
*/
|
|
||||||
public LightHelper(String blenderVersion) {
|
|
||||||
super(blenderVersion);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2009-2010 jMonkeyEngine
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are
|
|
||||||
* met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
*
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
||||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
||||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
package com.jme3.scene.plugins.blender.helpers;
|
|
||||||
|
|
||||||
public class MaterialHelper extends com.jme3.scene.plugins.blender.helpers.v249.MaterialHelper {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This constructor parses the given blender version and stores the result. Some functionalities may differ in
|
|
||||||
* different blender versions.
|
|
||||||
* @param blenderVersion
|
|
||||||
* the version read from the blend file
|
|
||||||
*/
|
|
||||||
public MaterialHelper(String blenderVersion) {
|
|
||||||
super(blenderVersion);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2009-2010 jMonkeyEngine
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are
|
|
||||||
* met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
*
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
||||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
||||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
package com.jme3.scene.plugins.blender.helpers;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A class that is used in mesh calculations.
|
|
||||||
* @author Marcin Roguski
|
|
||||||
*/
|
|
||||||
public class MeshHelper extends com.jme3.scene.plugins.blender.helpers.v249.MeshHelper {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This constructor parses the given blender version and stores the result. Some functionalities may differ in
|
|
||||||
* different blender versions.
|
|
||||||
* @param blenderVersion
|
|
||||||
* the version read from the blend file
|
|
||||||
*/
|
|
||||||
public MeshHelper(String blenderVersion) {
|
|
||||||
super(blenderVersion);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2009-2010 jMonkeyEngine
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are
|
|
||||||
* met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
*
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
||||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
||||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
package com.jme3.scene.plugins.blender.helpers;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A class that is used in modifiers calculations.
|
|
||||||
* @author Marcin Roguski
|
|
||||||
*/
|
|
||||||
public class ModifierHelper extends com.jme3.scene.plugins.blender.helpers.v249.ModifierHelper {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This constructor parses the given blender version and stores the result. Some functionalities may differ in
|
|
||||||
* different blender versions.
|
|
||||||
* @param blenderVersion
|
|
||||||
* the version read from the blend file
|
|
||||||
*/
|
|
||||||
public ModifierHelper(String blenderVersion) {
|
|
||||||
super(blenderVersion);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,52 +0,0 @@
|
|||||||
/*
|
|
||||||
*
|
|
||||||
* $Id: noise.c 14611 2008-04-29 08:24:33Z campbellbarton $
|
|
||||||
*
|
|
||||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation; either version 2
|
|
||||||
* of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
*
|
|
||||||
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* The Original Code is: all of this file.
|
|
||||||
*
|
|
||||||
* Contributor(s): none yet.
|
|
||||||
*
|
|
||||||
* ***** END GPL LICENSE BLOCK *****
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
package com.jme3.scene.plugins.blender.helpers;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Methods of this class are copied from blender 2.49 source code and modified so that they can be used in java. They are mostly NOT
|
|
||||||
* documented because they are not documented in blender's source code. If I find a proper description or discover what they actually do and
|
|
||||||
* what parameters mean - I shall describe such methods :) If anyone have some hint what these methods are doing please rite the proper
|
|
||||||
* javadoc documentation. These methods should be used to create generated textures.
|
|
||||||
*
|
|
||||||
* @author Marcin Roguski (Kaelthas)
|
|
||||||
*/
|
|
||||||
public class NoiseHelper extends com.jme3.scene.plugins.blender.helpers.v249.NoiseHelper {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor. Stores the blender version number and loads the constants needed for computations.
|
|
||||||
*
|
|
||||||
* @param blenderVersion
|
|
||||||
* the number of blender version
|
|
||||||
*/
|
|
||||||
public NoiseHelper(String blenderVersion) {
|
|
||||||
super(blenderVersion);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2009-2010 jMonkeyEngine
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are
|
|
||||||
* met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
*
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
||||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
||||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
package com.jme3.scene.plugins.blender.helpers;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A class that is used in object calculations.
|
|
||||||
* @author Marcin Roguski
|
|
||||||
*/
|
|
||||||
public class ObjectHelper extends com.jme3.scene.plugins.blender.helpers.v249.ObjectHelper {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This constructor parses the given blender version and stores the result. Some functionalities may differ in
|
|
||||||
* different blender versions.
|
|
||||||
* @param blenderVersion
|
|
||||||
* the version read from the blend file
|
|
||||||
*/
|
|
||||||
public ObjectHelper(String blenderVersion) {
|
|
||||||
super(blenderVersion);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
package com.jme3.scene.plugins.blender.helpers;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class helps to import the special effects from blender file.
|
|
||||||
* @author Marcin Roguski (Kaelthas)
|
|
||||||
*/
|
|
||||||
public class ParticlesHelper extends com.jme3.scene.plugins.blender.helpers.v249.ParticlesHelper {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This constructor parses the given blender version and stores the result. Some functionalities may differ in
|
|
||||||
* different blender versions.
|
|
||||||
* @param blenderVersion
|
|
||||||
* the version read from the blend file
|
|
||||||
*/
|
|
||||||
public ParticlesHelper(String blenderVersion) {
|
|
||||||
super(blenderVersion);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,84 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2009-2010 jMonkeyEngine
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are
|
|
||||||
* met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
*
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
||||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
||||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
package com.jme3.scene.plugins.blender.helpers;
|
|
||||||
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import com.jme3.scene.plugins.blender.data.Structure;
|
|
||||||
import com.jme3.scene.plugins.blender.exception.BlenderFileException;
|
|
||||||
import com.jme3.scene.plugins.blender.utils.DataRepository;
|
|
||||||
import com.jme3.scene.plugins.blender.utils.DataRepository.LoadedFeatureDataType;
|
|
||||||
import com.jme3.texture.Texture;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A class that is used in texture calculations.
|
|
||||||
* @author Marcin Roguski
|
|
||||||
*/
|
|
||||||
public class TextureHelper extends com.jme3.scene.plugins.blender.helpers.v249.TextureHelper {
|
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(TextureHelper.class.getName());
|
|
||||||
public static final int TEX_POINTDENSITY = 14;
|
|
||||||
public static final int TEX_VOXELDATA = 15;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This constructor parses the given blender version and stores the result. Some functionalities may differ in
|
|
||||||
* different blender versions.
|
|
||||||
* @param blenderVersion
|
|
||||||
* the version read from the blend file
|
|
||||||
*/
|
|
||||||
public TextureHelper(String blenderVersion) {
|
|
||||||
super(blenderVersion);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Texture getTexture(Structure tex, DataRepository dataRepository) throws BlenderFileException {
|
|
||||||
if (blenderVersion < 250) {
|
|
||||||
return super.getTexture(tex, dataRepository);
|
|
||||||
}
|
|
||||||
Texture result = (Texture) dataRepository.getLoadedFeature(tex.getOldMemoryAddress(), LoadedFeatureDataType.LOADED_FEATURE);
|
|
||||||
if (result != null) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
int type = ((Number) tex.getFieldValue("type")).intValue();
|
|
||||||
switch (type) {
|
|
||||||
case TEX_POINTDENSITY:
|
|
||||||
LOGGER.warning("Point density texture loading currently not supported!");
|
|
||||||
break;
|
|
||||||
case TEX_VOXELDATA:
|
|
||||||
LOGGER.warning("Voxel data texture loading currently not supported!");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
result = super.getTexture(tex, dataRepository);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,65 +0,0 @@
|
|||||||
package com.jme3.scene.plugins.blender.helpers.v249;
|
|
||||||
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import com.jme3.asset.BlenderKey.FeaturesToLoad;
|
|
||||||
import com.jme3.renderer.Camera;
|
|
||||||
import com.jme3.scene.plugins.blender.data.Structure;
|
|
||||||
import com.jme3.scene.plugins.blender.exception.BlenderFileException;
|
|
||||||
import com.jme3.scene.plugins.blender.utils.AbstractBlenderHelper;
|
|
||||||
import com.jme3.scene.plugins.blender.utils.DataRepository;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A class that is used in light calculations.
|
|
||||||
* @author Marcin Roguski
|
|
||||||
*/
|
|
||||||
public class CameraHelper extends AbstractBlenderHelper {
|
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(CameraHelper.class.getName());
|
|
||||||
protected static final int DEFAULT_CAM_WIDTH = 100;
|
|
||||||
protected static final int DEFAULT_CAM_HEIGHT = 100;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This constructor parses the given blender version and stores the result. Some functionalities may differ in
|
|
||||||
* different blender versions.
|
|
||||||
* @param blenderVersion
|
|
||||||
* the version read from the blend file
|
|
||||||
*/
|
|
||||||
public CameraHelper(String blenderVersion) {
|
|
||||||
super(blenderVersion);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method reads the camera object.
|
|
||||||
* @param structure the structure containing the camera data
|
|
||||||
* @return the camera object
|
|
||||||
* @throws BlenderFileException
|
|
||||||
*/
|
|
||||||
public Camera toCamera(Structure structure) throws BlenderFileException {
|
|
||||||
Camera result = new Camera(DEFAULT_CAM_WIDTH, DEFAULT_CAM_HEIGHT);
|
|
||||||
int type = ((Number) structure.getFieldValue("type")).intValue();
|
|
||||||
if (type != 0 && type != 1) {
|
|
||||||
LOGGER.log(Level.WARNING, "Unknown camera type: {0}. Perspective camera is being used!", type);
|
|
||||||
type = 0;
|
|
||||||
}
|
|
||||||
//type==0 - perspective; type==1 - orthographic; perspective is used as default
|
|
||||||
result.setParallelProjection(type == 1);
|
|
||||||
float angle = ((Number) structure.getFieldValue("angle")).floatValue();
|
|
||||||
float aspect = 0;
|
|
||||||
float clipsta = ((Number) structure.getFieldValue("clipsta")).floatValue();
|
|
||||||
float clipend = ((Number) structure.getFieldValue("clipend")).floatValue();
|
|
||||||
if (type == 0) {
|
|
||||||
aspect = ((Number) structure.getFieldValue("lens")).floatValue();
|
|
||||||
} else {
|
|
||||||
aspect = ((Number) structure.getFieldValue("ortho_scale")).floatValue();
|
|
||||||
}
|
|
||||||
result.setFrustumPerspective(angle, aspect, clipsta, clipend);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shouldBeLoaded(Structure structure, DataRepository dataRepository) {
|
|
||||||
return (dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.CAMERAS) != 0;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,756 +0,0 @@
|
|||||||
package com.jme3.scene.plugins.blender.helpers.v249;
|
|
||||||
|
|
||||||
import java.nio.FloatBuffer;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
import com.jme3.animation.Bone;
|
|
||||||
import com.jme3.animation.BoneAnimation;
|
|
||||||
import com.jme3.animation.BoneTrack;
|
|
||||||
import com.jme3.animation.Skeleton;
|
|
||||||
import com.jme3.math.FastMath;
|
|
||||||
import com.jme3.math.Quaternion;
|
|
||||||
import com.jme3.math.Transform;
|
|
||||||
import com.jme3.math.Vector3f;
|
|
||||||
import com.jme3.scene.Geometry;
|
|
||||||
import com.jme3.scene.Mesh;
|
|
||||||
import com.jme3.scene.Node;
|
|
||||||
import com.jme3.scene.Spatial;
|
|
||||||
import com.jme3.scene.VertexBuffer.Type;
|
|
||||||
import com.jme3.scene.plugins.blender.data.Structure;
|
|
||||||
import com.jme3.scene.plugins.blender.exception.BlenderFileException;
|
|
||||||
import com.jme3.scene.plugins.blender.structures.AbstractInfluenceFunction;
|
|
||||||
import com.jme3.scene.plugins.blender.structures.CalculationBone;
|
|
||||||
import com.jme3.scene.plugins.blender.structures.Constraint;
|
|
||||||
import com.jme3.scene.plugins.blender.structures.Constraint.Space;
|
|
||||||
import com.jme3.scene.plugins.blender.structures.ConstraintType;
|
|
||||||
import com.jme3.scene.plugins.blender.structures.Ipo;
|
|
||||||
import com.jme3.scene.plugins.blender.utils.AbstractBlenderHelper;
|
|
||||||
import com.jme3.scene.plugins.blender.utils.DataRepository;
|
|
||||||
import com.jme3.scene.plugins.blender.utils.DataRepository.LoadedFeatureDataType;
|
|
||||||
import com.jme3.scene.plugins.blender.utils.Pointer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class should be used for constraint calculations.
|
|
||||||
* @author Marcin Roguski
|
|
||||||
*/
|
|
||||||
public class ConstraintHelper extends AbstractBlenderHelper {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A table containing implementations of influence functions for constraints. It should contain functions for
|
|
||||||
* blender at least 249 and higher.
|
|
||||||
*/
|
|
||||||
protected static AbstractInfluenceFunction[] influenceFunctions;
|
|
||||||
/**
|
|
||||||
* Constraints stored for object with the given old memory address.
|
|
||||||
*/
|
|
||||||
protected Map<Long, Constraint[]> constraints = new HashMap<Long, Constraint[]>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper constructor. It's main task is to generate the affection functions. These functions are common to all
|
|
||||||
* ConstraintHelper instances. Unfortunately this constructor might grow large. If it becomes too large - I shall
|
|
||||||
* consider refactoring. The constructor parses the given blender version and stores the result. Some
|
|
||||||
* functionalities may differ in different blender versions.
|
|
||||||
* @param blenderVersion
|
|
||||||
* the version read from the blend file
|
|
||||||
*/
|
|
||||||
public ConstraintHelper(String blenderVersion, DataRepository dataRepository) {
|
|
||||||
super(blenderVersion);
|
|
||||||
this.initializeConstraintFunctions(dataRepository);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method initializes constraint functions for Blender 2.49.
|
|
||||||
* @param dataRepository
|
|
||||||
* the data repository
|
|
||||||
*/
|
|
||||||
private synchronized void initializeConstraintFunctions(DataRepository dataRepository) {
|
|
||||||
if (influenceFunctions == null) {
|
|
||||||
influenceFunctions = new AbstractInfluenceFunction[ConstraintType.getLastDefinedTypeValue() + 1];
|
|
||||||
//ACTION constraint (TODO: to implement)
|
|
||||||
influenceFunctions[ConstraintType.CONSTRAINT_TYPE_ACTION.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_ACTION, dataRepository) {
|
|
||||||
};
|
|
||||||
|
|
||||||
//CHILDOF constraint (TODO: to implement)
|
|
||||||
influenceFunctions[ConstraintType.CONSTRAINT_TYPE_CHILDOF.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_CHILDOF, dataRepository) {
|
|
||||||
};
|
|
||||||
|
|
||||||
//CLAMPTO constraint
|
|
||||||
influenceFunctions[ConstraintType.CONSTRAINT_TYPE_CLAMPTO.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_CLAMPTO, dataRepository) {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {
|
|
||||||
this.validateConstraintType(constraint.getData());
|
|
||||||
LOGGER.log(Level.INFO, "{0} not active! Curves not yet implemented!", constraint.getName());//TODO: implement when curves are implemented
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//DISTLIMIT constraint
|
|
||||||
influenceFunctions[ConstraintType.CONSTRAINT_TYPE_DISTLIMIT.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_DISTLIMIT, dataRepository) {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {
|
|
||||||
Structure constraintStructure = constraint.getData();
|
|
||||||
this.validateConstraintType(constraintStructure);
|
|
||||||
Vector3f targetLocation = this.getTargetLocation(constraint);
|
|
||||||
BoneTrack boneTrack = this.getBoneTrack(skeleton, boneAnimation, constraint);
|
|
||||||
if (boneTrack != null) {
|
|
||||||
//TODO: target vertex group !!!
|
|
||||||
float dist = ((Number) constraintStructure.getFieldValue("dist")).floatValue();
|
|
||||||
int mode = ((Number) constraintStructure.getFieldValue("mode")).intValue();
|
|
||||||
|
|
||||||
int maxFrames = boneTrack.getTimes().length;
|
|
||||||
Vector3f[] translations = boneTrack.getTranslations();
|
|
||||||
for (int frame = 0; frame < maxFrames; ++frame) {
|
|
||||||
Vector3f v = translations[frame].subtract(targetLocation);
|
|
||||||
float currentDistance = v.length();
|
|
||||||
float influence = constraint.getIpo().calculateValue(frame);
|
|
||||||
float modifier = 0.0f;
|
|
||||||
switch (mode) {
|
|
||||||
case LIMITDIST_INSIDE:
|
|
||||||
if (currentDistance >= dist) {
|
|
||||||
modifier = (dist - currentDistance) / currentDistance;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case LIMITDIST_ONSURFACE:
|
|
||||||
modifier = (dist - currentDistance) / currentDistance;
|
|
||||||
break;
|
|
||||||
case LIMITDIST_OUTSIDE:
|
|
||||||
if (currentDistance <= dist) {
|
|
||||||
modifier = (dist - currentDistance) / currentDistance;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IllegalStateException("Unknown distance limit constraint mode: " + mode);
|
|
||||||
}
|
|
||||||
translations[frame].addLocal(v.multLocal(modifier * influence));
|
|
||||||
}
|
|
||||||
boneTrack.setKeyframes(boneTrack.getTimes(), translations, boneTrack.getRotations(), boneTrack.getScales());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//FOLLOWPATH constraint
|
|
||||||
influenceFunctions[ConstraintType.CONSTRAINT_TYPE_FOLLOWPATH.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_FOLLOWPATH, dataRepository) {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {
|
|
||||||
this.validateConstraintType(constraint.getData());
|
|
||||||
LOGGER.log(Level.INFO, "{0} not active! Curves not yet implemented!", constraint.getName());//TODO: implement when curves are implemented
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//KINEMATIC constraint (TODO: to implement)
|
|
||||||
influenceFunctions[ConstraintType.CONSTRAINT_TYPE_KINEMATIC.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_KINEMATIC, dataRepository) {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {
|
|
||||||
try {
|
|
||||||
Structure constraintStructure = constraint.getData();
|
|
||||||
this.validateConstraintType(constraintStructure);
|
|
||||||
Long boneOMA = constraint.getBoneOMA();
|
|
||||||
// IK solver is only attached to bones
|
|
||||||
Bone ownerBone = (Bone) dataRepository.getLoadedFeature(boneOMA, LoadedFeatureDataType.LOADED_FEATURE);
|
|
||||||
|
|
||||||
// get the target point
|
|
||||||
Object targetObject = this.getTarget(constraint, LoadedFeatureDataType.LOADED_FEATURE);
|
|
||||||
Vector3f pt = null;// Point Target
|
|
||||||
if (targetObject instanceof Bone) {
|
|
||||||
pt = ((Bone) targetObject).getModelSpacePosition();
|
|
||||||
} else if (targetObject instanceof Node) {
|
|
||||||
pt = ((Node) targetObject).getWorldTranslation();
|
|
||||||
} else if (targetObject instanceof Skeleton) {
|
|
||||||
Structure armatureNodeStructure = (Structure) this.getTarget(constraint, LoadedFeatureDataType.LOADED_STRUCTURE);
|
|
||||||
ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);
|
|
||||||
Transform transform = objectHelper.getTransformation(armatureNodeStructure, dataRepository);
|
|
||||||
pt = transform.getTranslation();
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Unknown target object type! Should be Node, Bone or Skeleton and there is: "
|
|
||||||
+ targetObject.getClass().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
//fetching the owner's bone track
|
|
||||||
// BoneTrack ownerBoneTrack = null;
|
|
||||||
// int boneIndex = skeleton.getBoneIndex(ownerBone);
|
|
||||||
// for (int i = 0; i < boneAnimation.getTracks().length; ++i) {
|
|
||||||
// if (boneAnimation.getTracks()[i].getTargetBoneIndex() == boneIndex) {
|
|
||||||
// ownerBoneTrack = boneAnimation.getTracks()[i];
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// int ownerBoneFramesCount = ownerBoneTrack==null ? 0 : ownerBoneTrack.getTimes().length;
|
|
||||||
|
|
||||||
// preparing data
|
|
||||||
int maxIterations = ((Number) constraintStructure.getFieldValue("iterations")).intValue();
|
|
||||||
CalculationBone[] bones = this.getBonesToCalculate(ownerBone, skeleton, boneAnimation);
|
|
||||||
// for (int i = 0; i < bones.length; ++i) {
|
|
||||||
// System.out.println(Arrays.toString(bones[i].track.getTranslations()));
|
|
||||||
// System.out.println(Arrays.toString(bones[i].track.getRotations()));
|
|
||||||
// System.out.println("===============================");
|
|
||||||
// }
|
|
||||||
Quaternion rotation = new Quaternion();
|
|
||||||
//all tracks should have the same amount of frames
|
|
||||||
int framesCount = bones[0].getBoneFramesCount();
|
|
||||||
assert framesCount >=1;
|
|
||||||
for (int frame = 0; frame < framesCount; ++frame) {
|
|
||||||
float error = IK_SOLVER_ERROR;
|
|
||||||
int iteration = 0;
|
|
||||||
while (error >= IK_SOLVER_ERROR && iteration <= maxIterations) {
|
|
||||||
// rotating the bones
|
|
||||||
for (int i = 0; i < bones.length - 1; ++i) {
|
|
||||||
Vector3f pe = bones[i].getEndPoint();
|
|
||||||
Vector3f pc = bones[i + 1].getWorldTranslation().clone();
|
|
||||||
|
|
||||||
Vector3f peSUBpc = pe.subtract(pc).normalizeLocal();
|
|
||||||
Vector3f ptSUBpc = pt.subtract(pc).normalizeLocal();
|
|
||||||
|
|
||||||
float theta = FastMath.acos(peSUBpc.dot(ptSUBpc));
|
|
||||||
Vector3f direction = peSUBpc.cross(ptSUBpc).normalizeLocal();
|
|
||||||
bones[i].rotate(rotation.fromAngleAxis(theta, direction), frame);
|
|
||||||
}
|
|
||||||
error = pt.subtract(bones[0].getEndPoint()).length();
|
|
||||||
++iteration;
|
|
||||||
}
|
|
||||||
System.out.println("error = " + error + " iterations = " + iteration);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (CalculationBone bone : bones) {
|
|
||||||
bone.applyCalculatedTracks();
|
|
||||||
}
|
|
||||||
|
|
||||||
// System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
|
|
||||||
// for (int i = 0; i < bones.length; ++i) {
|
|
||||||
// System.out.println(Arrays.toString(bones[i].track.getTranslations()));
|
|
||||||
// System.out.println(Arrays.toString(bones[i].track.getRotations()));
|
|
||||||
// System.out.println("===============================");
|
|
||||||
// }
|
|
||||||
} catch(BlenderFileException e) {
|
|
||||||
LOGGER.severe(e.getLocalizedMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns bones used for rotation calculations.
|
|
||||||
* @param bone
|
|
||||||
* the bone to which the constraint is applied
|
|
||||||
* @param skeleton
|
|
||||||
* the skeleton owning the bone and its ancestors
|
|
||||||
* @param boneAnimation
|
|
||||||
* the bone animation data that stores the traces for the skeleton's bones
|
|
||||||
* @return a list of bones to imitate the bone's movement during IK solving
|
|
||||||
*/
|
|
||||||
private CalculationBone[] getBonesToCalculate(Bone bone, Skeleton skeleton, BoneAnimation boneAnimation) {
|
|
||||||
List<CalculationBone> bonesList = new ArrayList<CalculationBone>();
|
|
||||||
Bone currentBone = bone;
|
|
||||||
do {
|
|
||||||
bonesList.add(new CalculationBone(currentBone, 1));
|
|
||||||
// int boneIndex = skeleton.getBoneIndex(currentBone);
|
|
||||||
// for (int i = 0; i < boneAnimation.getTracks().length; ++i) {
|
|
||||||
// if (boneAnimation.getTracks()[i].getTargetBoneIndex() == boneIndex) {
|
|
||||||
// bonesList.add(new CalculationBone(currentBone, boneAnimation.getTracks()[i]));
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
currentBone = currentBone.getParent();
|
|
||||||
} while (currentBone != null);
|
|
||||||
//attaching children
|
|
||||||
CalculationBone[] result = bonesList.toArray(new CalculationBone[bonesList.size()]);
|
|
||||||
for (int i = result.length - 1; i > 0; --i) {
|
|
||||||
result[i].attachChild(result[i - 1]);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//LOCKTRACK constraint (TODO: to implement)
|
|
||||||
influenceFunctions[ConstraintType.CONSTRAINT_TYPE_LOCKTRACK.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_LOCKTRACK, dataRepository) {
|
|
||||||
};
|
|
||||||
|
|
||||||
//LOCLIKE constraint
|
|
||||||
influenceFunctions[ConstraintType.CONSTRAINT_TYPE_LOCLIKE.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_LOCLIKE, dataRepository) {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {
|
|
||||||
Structure constraintData = constraint.getData();
|
|
||||||
this.validateConstraintType(constraintData);
|
|
||||||
BoneTrack boneTrack = this.getBoneTrack(skeleton, boneAnimation, constraint);
|
|
||||||
if (boneTrack != null) {
|
|
||||||
Vector3f targetLocation = this.getTargetLocation(constraint);
|
|
||||||
int flag = ((Number) constraintData.getFieldValue("flag")).intValue();
|
|
||||||
Vector3f[] translations = boneTrack.getTranslations();
|
|
||||||
int maxFrames = translations.length;
|
|
||||||
for (int frame = 0; frame < maxFrames; ++frame) {
|
|
||||||
Vector3f offset = Vector3f.ZERO;
|
|
||||||
if ((flag & LOCLIKE_OFFSET) != 0) {//we add the original location to the copied location
|
|
||||||
offset = translations[frame].clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((flag & LOCLIKE_X) != 0) {
|
|
||||||
translations[frame].x = targetLocation.x;
|
|
||||||
if ((flag & LOCLIKE_X_INVERT) != 0) {
|
|
||||||
translations[frame].x = -translations[frame].x;
|
|
||||||
}
|
|
||||||
} else if ((flag & LOCLIKE_Y) != 0) {
|
|
||||||
translations[frame].y = targetLocation.y;
|
|
||||||
if ((flag & LOCLIKE_Y_INVERT) != 0) {
|
|
||||||
translations[frame].y = -translations[frame].y;
|
|
||||||
}
|
|
||||||
} else if ((flag & LOCLIKE_Z) != 0) {
|
|
||||||
translations[frame].z = targetLocation.z;
|
|
||||||
if ((flag & LOCLIKE_Z_INVERT) != 0) {
|
|
||||||
translations[frame].z = -translations[frame].z;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
translations[frame].addLocal(offset);//TODO: ipo influence
|
|
||||||
}
|
|
||||||
boneTrack.setKeyframes(boneTrack.getTimes(), translations, boneTrack.getRotations(), boneTrack.getScales());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//LOCLIMIT constraint
|
|
||||||
influenceFunctions[ConstraintType.CONSTRAINT_TYPE_LOCLIMIT.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_LOCLIMIT, dataRepository) {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {
|
|
||||||
Structure constraintStructure = constraint.getData();
|
|
||||||
this.validateConstraintType(constraintStructure);
|
|
||||||
BoneTrack boneTrack = this.getBoneTrack(skeleton, boneAnimation, constraint);
|
|
||||||
if (boneTrack != null) {
|
|
||||||
int flag = ((Number) constraintStructure.getFieldValue("flag")).intValue();
|
|
||||||
Vector3f[] translations = boneTrack.getTranslations();
|
|
||||||
int maxFrames = translations.length;
|
|
||||||
for (int frame = 0; frame < maxFrames; ++frame) {
|
|
||||||
float influence = constraint.getIpo().calculateValue(frame);
|
|
||||||
if ((flag & LIMIT_XMIN) != 0) {
|
|
||||||
float xmin = ((Number) constraintStructure.getFieldValue("xmin")).floatValue();
|
|
||||||
if (translations[frame].x < xmin) {
|
|
||||||
translations[frame].x -= (translations[frame].x - xmin) * influence;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((flag & LIMIT_XMAX) != 0) {
|
|
||||||
float xmax = ((Number) constraintStructure.getFieldValue("xmax")).floatValue();
|
|
||||||
if (translations[frame].x > xmax) {
|
|
||||||
translations[frame].x -= (translations[frame].x - xmax) * influence;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((flag & LIMIT_YMIN) != 0) {
|
|
||||||
float ymin = ((Number) constraintStructure.getFieldValue("ymin")).floatValue();
|
|
||||||
if (translations[frame].y < ymin) {
|
|
||||||
translations[frame].y -= (translations[frame].y - ymin) * influence;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((flag & LIMIT_YMAX) != 0) {
|
|
||||||
float ymax = ((Number) constraintStructure.getFieldValue("ymax")).floatValue();
|
|
||||||
if (translations[frame].y > ymax) {
|
|
||||||
translations[frame].y -= (translations[frame].y - ymax) * influence;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((flag & LIMIT_ZMIN) != 0) {
|
|
||||||
float zmin = ((Number) constraintStructure.getFieldValue("zmin")).floatValue();
|
|
||||||
if (translations[frame].z < zmin) {
|
|
||||||
translations[frame].z -= (translations[frame].z - zmin) * influence;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((flag & LIMIT_ZMAX) != 0) {
|
|
||||||
float zmax = ((Number) constraintStructure.getFieldValue("zmax")).floatValue();
|
|
||||||
if (translations[frame].z > zmax) {
|
|
||||||
translations[frame].z -= (translations[frame].z - zmax) * influence;
|
|
||||||
}
|
|
||||||
}//TODO: consider constraint space !!!
|
|
||||||
}
|
|
||||||
boneTrack.setKeyframes(boneTrack.getTimes(), translations, boneTrack.getRotations(), boneTrack.getScales());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//MINMAX constraint (TODO: to implement)
|
|
||||||
influenceFunctions[ConstraintType.CONSTRAINT_TYPE_MINMAX.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_MINMAX, dataRepository) {
|
|
||||||
};
|
|
||||||
|
|
||||||
//NULL constraint - does nothing
|
|
||||||
influenceFunctions[ConstraintType.CONSTRAINT_TYPE_NULL.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_NULL, dataRepository) {
|
|
||||||
};
|
|
||||||
|
|
||||||
//PYTHON constraint (TODO: to implement)
|
|
||||||
influenceFunctions[ConstraintType.CONSTRAINT_TYPE_PYTHON.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_PYTHON, dataRepository) {
|
|
||||||
};
|
|
||||||
|
|
||||||
//RIGIDBODYJOINT constraint (TODO: to implement)
|
|
||||||
influenceFunctions[ConstraintType.CONSTRAINT_TYPE_RIGIDBODYJOINT.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_RIGIDBODYJOINT, dataRepository) {
|
|
||||||
};
|
|
||||||
|
|
||||||
//ROTLIKE constraint
|
|
||||||
influenceFunctions[ConstraintType.CONSTRAINT_TYPE_ROTLIKE.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_ROTLIKE, dataRepository) {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {
|
|
||||||
Structure constraintData = constraint.getData();
|
|
||||||
this.validateConstraintType(constraintData);
|
|
||||||
BoneTrack boneTrack = this.getBoneTrack(skeleton, boneAnimation, constraint);
|
|
||||||
if (boneTrack != null) {
|
|
||||||
Quaternion targetRotation = this.getTargetRotation(constraint);
|
|
||||||
int flag = ((Number) constraintData.getFieldValue("flag")).intValue();
|
|
||||||
float[] targetAngles = targetRotation.toAngles(null);
|
|
||||||
Quaternion[] rotations = boneTrack.getRotations();
|
|
||||||
int maxFrames = rotations.length;
|
|
||||||
for (int frame = 0; frame < maxFrames; ++frame) {
|
|
||||||
float[] angles = rotations[frame].toAngles(null);
|
|
||||||
|
|
||||||
Quaternion offset = Quaternion.IDENTITY;
|
|
||||||
if ((flag & ROTLIKE_OFFSET) != 0) {//we add the original rotation to the copied rotation
|
|
||||||
offset = rotations[frame].clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((flag & ROTLIKE_X) != 0) {
|
|
||||||
angles[0] = targetAngles[0];
|
|
||||||
if ((flag & ROTLIKE_X_INVERT) != 0) {
|
|
||||||
angles[0] = -angles[0];
|
|
||||||
}
|
|
||||||
} else if ((flag & ROTLIKE_Y) != 0) {
|
|
||||||
angles[1] = targetAngles[1];
|
|
||||||
if ((flag & ROTLIKE_Y_INVERT) != 0) {
|
|
||||||
angles[1] = -angles[1];
|
|
||||||
}
|
|
||||||
} else if ((flag & ROTLIKE_Z) != 0) {
|
|
||||||
angles[2] = targetAngles[2];
|
|
||||||
if ((flag & ROTLIKE_Z_INVERT) != 0) {
|
|
||||||
angles[2] = -angles[2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rotations[frame].fromAngles(angles).multLocal(offset);//TODO: ipo influence
|
|
||||||
}
|
|
||||||
boneTrack.setKeyframes(boneTrack.getTimes(), boneTrack.getTranslations(), rotations, boneTrack.getScales());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//ROTLIMIT constraint
|
|
||||||
influenceFunctions[ConstraintType.CONSTRAINT_TYPE_ROTLIMIT.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_ROTLIMIT, dataRepository) {
|
|
||||||
@Override
|
|
||||||
public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {
|
|
||||||
Structure constraintStructure = constraint.getData();
|
|
||||||
this.validateConstraintType(constraintStructure);
|
|
||||||
BoneTrack boneTrack = this.getBoneTrack(skeleton, boneAnimation, constraint);
|
|
||||||
if (boneTrack != null) {
|
|
||||||
int flag = ((Number) constraintStructure.getFieldValue("flag")).intValue();
|
|
||||||
Quaternion[] rotations = boneTrack.getRotations();
|
|
||||||
int maxFrames = rotations.length;
|
|
||||||
for (int frame = 0; frame < maxFrames; ++frame) {
|
|
||||||
float[] angles = rotations[frame].toAngles(null);
|
|
||||||
float influence = constraint.getIpo().calculateValue(frame);
|
|
||||||
if ((flag & LIMIT_XROT) != 0) {
|
|
||||||
float xmin = ((Number) constraintStructure.getFieldValue("xmin")).floatValue() * FastMath.DEG_TO_RAD;
|
|
||||||
float xmax = ((Number) constraintStructure.getFieldValue("xmax")).floatValue() * FastMath.DEG_TO_RAD;
|
|
||||||
float difference = 0.0f;
|
|
||||||
if (angles[0] < xmin) {
|
|
||||||
difference = (angles[0] - xmin) * influence;
|
|
||||||
} else if (angles[0] > xmax) {
|
|
||||||
difference = (angles[0] - xmax) * influence;
|
|
||||||
}
|
|
||||||
angles[0] -= difference;
|
|
||||||
}
|
|
||||||
if ((flag & LIMIT_YROT) != 0) {
|
|
||||||
float ymin = ((Number) constraintStructure.getFieldValue("ymin")).floatValue() * FastMath.DEG_TO_RAD;
|
|
||||||
float ymax = ((Number) constraintStructure.getFieldValue("ymax")).floatValue() * FastMath.DEG_TO_RAD;
|
|
||||||
float difference = 0.0f;
|
|
||||||
if (angles[1] < ymin) {
|
|
||||||
difference = (angles[1] - ymin) * influence;
|
|
||||||
} else if (angles[1] > ymax) {
|
|
||||||
difference = (angles[1] - ymax) * influence;
|
|
||||||
}
|
|
||||||
angles[1] -= difference;
|
|
||||||
}
|
|
||||||
if ((flag & LIMIT_ZROT) != 0) {
|
|
||||||
float zmin = ((Number) constraintStructure.getFieldValue("zmin")).floatValue() * FastMath.DEG_TO_RAD;
|
|
||||||
float zmax = ((Number) constraintStructure.getFieldValue("zmax")).floatValue() * FastMath.DEG_TO_RAD;
|
|
||||||
float difference = 0.0f;
|
|
||||||
if (angles[2] < zmin) {
|
|
||||||
difference = (angles[2] - zmin) * influence;
|
|
||||||
} else if (angles[2] > zmax) {
|
|
||||||
difference = (angles[2] - zmax) * influence;
|
|
||||||
}
|
|
||||||
angles[2] -= difference;
|
|
||||||
}
|
|
||||||
rotations[frame].fromAngles(angles);//TODO: consider constraint space !!!
|
|
||||||
}
|
|
||||||
boneTrack.setKeyframes(boneTrack.getTimes(), boneTrack.getTranslations(), rotations, boneTrack.getScales());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//SHRINKWRAP constraint (TODO: to implement)
|
|
||||||
influenceFunctions[ConstraintType.CONSTRAINT_TYPE_SHRINKWRAP.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_SHRINKWRAP, dataRepository) {
|
|
||||||
@Override
|
|
||||||
public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {
|
|
||||||
Structure constraintStructure = constraint.getData();
|
|
||||||
this.validateConstraintType(constraintStructure);
|
|
||||||
|
|
||||||
//loading mesh points (blender ensures that the target is a mesh-object)
|
|
||||||
List<Vector3f> pts = new ArrayList<Vector3f>();
|
|
||||||
try {
|
|
||||||
Node node = (Node)this.getTarget(constraint, LoadedFeatureDataType.LOADED_FEATURE);
|
|
||||||
for(Spatial spatial : node.getChildren()) {
|
|
||||||
if(spatial instanceof Geometry) {
|
|
||||||
Mesh mesh = ((Geometry) spatial).getMesh();
|
|
||||||
FloatBuffer floatBuffer = mesh.getFloatBuffer(Type.Position);
|
|
||||||
for(int i=0;i<floatBuffer.limit();i+=3) {
|
|
||||||
pts.add(new Vector3f(floatBuffer.get(i), floatBuffer.get(i + 1), floatBuffer.get(i + 2)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//modifying traces
|
|
||||||
BoneTrack boneTrack = this.getBoneTrack(skeleton, boneAnimation, constraint);
|
|
||||||
if (boneTrack != null) {
|
|
||||||
Vector3f[] translations = boneTrack.getTranslations();
|
|
||||||
Quaternion[] rotations = boneTrack.getRotations();
|
|
||||||
int maxFrames = translations.length;
|
|
||||||
for (int frame = 0; frame < maxFrames; ++frame) {
|
|
||||||
Vector3f currentTranslation = translations[frame];
|
|
||||||
|
|
||||||
//looking for minimum distanced point
|
|
||||||
Vector3f minDistancePoint = null;
|
|
||||||
float distance = Float.MAX_VALUE;
|
|
||||||
for(Vector3f p : pts) {
|
|
||||||
float temp = currentTranslation.distance(p);
|
|
||||||
if(temp < distance) {
|
|
||||||
distance = temp;
|
|
||||||
minDistancePoint = p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
translations[frame] = minDistancePoint.clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
boneTrack.setKeyframes(boneTrack.getTimes(), translations, rotations, boneTrack.getScales());
|
|
||||||
}
|
|
||||||
} catch (BlenderFileException e) {
|
|
||||||
LOGGER.severe(e.getLocalizedMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//SIZELIKE constraint
|
|
||||||
influenceFunctions[ConstraintType.CONSTRAINT_TYPE_SIZELIKE.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_SIZELIKE, dataRepository) {
|
|
||||||
@Override
|
|
||||||
public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {
|
|
||||||
Structure constraintData = constraint.getData();
|
|
||||||
this.validateConstraintType(constraintData);
|
|
||||||
Vector3f targetScale = this.getTargetLocation(constraint);
|
|
||||||
BoneTrack boneTrack = this.getBoneTrack(skeleton, boneAnimation, constraint);
|
|
||||||
if (boneTrack != null) {
|
|
||||||
int flag = ((Number) constraintData.getFieldValue("flag")).intValue();
|
|
||||||
Vector3f[] scales = boneTrack.getScales();
|
|
||||||
int maxFrames = scales.length;
|
|
||||||
for (int frame = 0; frame < maxFrames; ++frame) {
|
|
||||||
Vector3f offset = Vector3f.ZERO;
|
|
||||||
if ((flag & LOCLIKE_OFFSET) != 0) {//we add the original scale to the copied scale
|
|
||||||
offset = scales[frame].clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((flag & SIZELIKE_X) != 0) {
|
|
||||||
scales[frame].x = targetScale.x;
|
|
||||||
} else if ((flag & SIZELIKE_Y) != 0) {
|
|
||||||
scales[frame].y = targetScale.y;
|
|
||||||
} else if ((flag & SIZELIKE_Z) != 0) {
|
|
||||||
scales[frame].z = targetScale.z;
|
|
||||||
}
|
|
||||||
scales[frame].addLocal(offset);//TODO: ipo influence
|
|
||||||
//TODO: add or multiply???
|
|
||||||
}
|
|
||||||
boneTrack.setKeyframes(boneTrack.getTimes(), boneTrack.getTranslations(), boneTrack.getRotations(), scales);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//SIZELIMIT constraint
|
|
||||||
influenceFunctions[ConstraintType.CONSTRAINT_TYPE_SIZELIMIT.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_SIZELIMIT, dataRepository) {
|
|
||||||
@Override
|
|
||||||
public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {
|
|
||||||
Structure constraintStructure = constraint.getData();
|
|
||||||
this.validateConstraintType(constraintStructure);
|
|
||||||
BoneTrack boneTrack = this.getBoneTrack(skeleton, boneAnimation, constraint);
|
|
||||||
if (boneTrack != null) {
|
|
||||||
int flag = ((Number) constraintStructure.getFieldValue("flag")).intValue();
|
|
||||||
Vector3f[] scales = boneTrack.getScales();
|
|
||||||
int maxFrames = scales.length;
|
|
||||||
for (int frame = 0; frame < maxFrames; ++frame) {
|
|
||||||
float influence = constraint.getIpo().calculateValue(frame);
|
|
||||||
if ((flag & LIMIT_XMIN) != 0) {
|
|
||||||
float xmin = ((Number) constraintStructure.getFieldValue("xmin")).floatValue();
|
|
||||||
if (scales[frame].x < xmin) {
|
|
||||||
scales[frame].x -= (scales[frame].x - xmin) * influence;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((flag & LIMIT_XMAX) != 0) {
|
|
||||||
float xmax = ((Number) constraintStructure.getFieldValue("xmax")).floatValue();
|
|
||||||
if (scales[frame].x > xmax) {
|
|
||||||
scales[frame].x -= (scales[frame].x - xmax) * influence;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((flag & LIMIT_YMIN) != 0) {
|
|
||||||
float ymin = ((Number) constraintStructure.getFieldValue("ymin")).floatValue();
|
|
||||||
if (scales[frame].y < ymin) {
|
|
||||||
scales[frame].y -= (scales[frame].y - ymin) * influence;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((flag & LIMIT_YMAX) != 0) {
|
|
||||||
float ymax = ((Number) constraintStructure.getFieldValue("ymax")).floatValue();
|
|
||||||
if (scales[frame].y > ymax) {
|
|
||||||
scales[frame].y -= (scales[frame].y - ymax) * influence;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((flag & LIMIT_ZMIN) != 0) {
|
|
||||||
float zmin = ((Number) constraintStructure.getFieldValue("zmin")).floatValue();
|
|
||||||
if (scales[frame].z < zmin) {
|
|
||||||
scales[frame].z -= (scales[frame].z - zmin) * influence;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((flag & LIMIT_ZMAX) != 0) {
|
|
||||||
float zmax = ((Number) constraintStructure.getFieldValue("zmax")).floatValue();
|
|
||||||
if (scales[frame].z > zmax) {
|
|
||||||
scales[frame].z -= (scales[frame].z - zmax) * influence;
|
|
||||||
}
|
|
||||||
}//TODO: consider constraint space !!!
|
|
||||||
}
|
|
||||||
boneTrack.setKeyframes(boneTrack.getTimes(), boneTrack.getTranslations(), boneTrack.getRotations(), scales);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//STRETCHTO constraint (TODO: to implement)
|
|
||||||
influenceFunctions[ConstraintType.CONSTRAINT_TYPE_STRETCHTO.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_STRETCHTO, dataRepository) {
|
|
||||||
};
|
|
||||||
|
|
||||||
//TRANSFORM constraint (TODO: to implement)
|
|
||||||
influenceFunctions[ConstraintType.CONSTRAINT_TYPE_TRANSFORM.getConstraintId()] = new AbstractInfluenceFunction(ConstraintType.CONSTRAINT_TYPE_TRANSFORM, dataRepository) {
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method reads constraints for for the given structure. The constraints are loaded only once for object/bone.
|
|
||||||
* @param ownerOMA
|
|
||||||
* the owner's old memory address
|
|
||||||
* @param objectStructure
|
|
||||||
* the structure we read constraint's for
|
|
||||||
* @param dataRepository
|
|
||||||
* the data repository
|
|
||||||
* @throws BlenderFileException
|
|
||||||
*/
|
|
||||||
public void loadConstraints(Structure objectStructure, DataRepository dataRepository) throws BlenderFileException {
|
|
||||||
// reading influence ipos for the constraints
|
|
||||||
IpoHelper ipoHelper = dataRepository.getHelper(IpoHelper.class);
|
|
||||||
Map<String, Map<String, Ipo>> constraintsIpos = new HashMap<String, Map<String, Ipo>>();
|
|
||||||
Pointer pActions = (Pointer) objectStructure.getFieldValue("action");
|
|
||||||
if (pActions.isNotNull()) {
|
|
||||||
List<Structure> actions = pActions.fetchData(dataRepository.getInputStream());
|
|
||||||
for (Structure action : actions) {
|
|
||||||
Structure chanbase = (Structure) action.getFieldValue("chanbase");
|
|
||||||
List<Structure> actionChannels = chanbase.evaluateListBase(dataRepository);
|
|
||||||
for (Structure actionChannel : actionChannels) {
|
|
||||||
Map<String, Ipo> ipos = new HashMap<String, Ipo>();
|
|
||||||
Structure constChannels = (Structure) actionChannel.getFieldValue("constraintChannels");
|
|
||||||
List<Structure> constraintChannels = constChannels.evaluateListBase(dataRepository);
|
|
||||||
for (Structure constraintChannel : constraintChannels) {
|
|
||||||
Pointer pIpo = (Pointer) constraintChannel.getFieldValue("ipo");
|
|
||||||
if (pIpo.isNotNull()) {
|
|
||||||
String constraintName = constraintChannel.getFieldValue("name").toString();
|
|
||||||
Ipo ipo = ipoHelper.createIpo(pIpo.fetchData(dataRepository.getInputStream()).get(0), dataRepository);
|
|
||||||
ipos.put(constraintName, ipo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String actionName = actionChannel.getFieldValue("name").toString();
|
|
||||||
constraintsIpos.put(actionName, ipos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//loading constraints connected with the object's bones
|
|
||||||
List<Constraint> constraintsList = new ArrayList<Constraint>();
|
|
||||||
Pointer pPose = (Pointer) objectStructure.getFieldValue("pose");//TODO: what if the object has two armatures ????
|
|
||||||
if (pPose.isNotNull()) {
|
|
||||||
//getting pose channels
|
|
||||||
List<Structure> poseChannels = ((Structure) pPose.fetchData(dataRepository.getInputStream()).get(0).getFieldValue("chanbase")).evaluateListBase(dataRepository);
|
|
||||||
for (Structure poseChannel : poseChannels) {
|
|
||||||
Long boneOMA = Long.valueOf(((Pointer) poseChannel.getFieldValue("bone")).getOldMemoryAddress());
|
|
||||||
//the name is read directly from structure because bone might not yet be loaded
|
|
||||||
String name = dataRepository.getFileBlock(boneOMA).getStructure(dataRepository).getFieldValue("name").toString();
|
|
||||||
List<Structure> constraints = ((Structure) poseChannel.getFieldValue("constraints")).evaluateListBase(dataRepository);
|
|
||||||
for (Structure constraint : constraints) {
|
|
||||||
int type = ((Number) constraint.getFieldValue("type")).intValue();
|
|
||||||
String constraintName = constraint.getFieldValue("name").toString();
|
|
||||||
Map<String, Ipo> ipoMap = constraintsIpos.get(name);
|
|
||||||
Ipo ipo = ipoMap==null ? null : ipoMap.get(constraintName);
|
|
||||||
if (ipo == null) {
|
|
||||||
float enforce = ((Number) constraint.getFieldValue("enforce")).floatValue();
|
|
||||||
ipo = ipoHelper.createIpo(enforce);
|
|
||||||
}
|
|
||||||
Space ownerSpace = Space.valueOf(((Number) constraint.getFieldValue("ownspace")).byteValue());
|
|
||||||
Space targetSpace = Space.valueOf(((Number) constraint.getFieldValue("tarspace")).byteValue());
|
|
||||||
Constraint c = new Constraint(constraint, influenceFunctions[type], boneOMA, ownerSpace, targetSpace, ipo, dataRepository);
|
|
||||||
constraintsList.add(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO: reading constraints for objects (implement when object's animation will be available)
|
|
||||||
List<Structure> constraintChannels = ((Structure)objectStructure.getFieldValue("constraintChannels")).evaluateListBase(dataRepository);
|
|
||||||
for(Structure constraintChannel : constraintChannels) {
|
|
||||||
System.out.println(constraintChannel);
|
|
||||||
}
|
|
||||||
|
|
||||||
//loading constraints connected with the object itself (TODO: test this)
|
|
||||||
if(!this.constraints.containsKey(objectStructure.getOldMemoryAddress())) {
|
|
||||||
List<Structure> constraints = ((Structure)objectStructure.getFieldValue("constraints")).evaluateListBase(dataRepository);
|
|
||||||
Constraint[] result = new Constraint[constraints.size()];
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
for(Structure constraint : constraints) {
|
|
||||||
int type = ((Number)constraint.getFieldValue("type")).intValue();
|
|
||||||
String constraintName = constraint.getFieldValue("name").toString();
|
|
||||||
String objectName = objectStructure.getName();
|
|
||||||
|
|
||||||
Map<String, Ipo> objectConstraintsIpos = constraintsIpos.get(objectName);
|
|
||||||
Ipo ipo = objectConstraintsIpos!=null ? objectConstraintsIpos.get(constraintName) : null;
|
|
||||||
if (ipo == null) {
|
|
||||||
float enforce = ((Number) constraint.getFieldValue("enforce")).floatValue();
|
|
||||||
ipo = ipoHelper.createIpo(enforce);
|
|
||||||
}
|
|
||||||
Space ownerSpace = Space.valueOf(((Number) constraint.getFieldValue("ownspace")).byteValue());
|
|
||||||
Space targetSpace = Space.valueOf(((Number) constraint.getFieldValue("tarspace")).byteValue());
|
|
||||||
result[i++] = new Constraint(constraint, influenceFunctions[type], null,
|
|
||||||
ownerSpace, targetSpace, ipo, dataRepository);//TODO: influence ipos for object animation
|
|
||||||
}
|
|
||||||
this.constraints.put(objectStructure.getOldMemoryAddress(), result);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (constraintsList.size() > 0) {
|
|
||||||
this.constraints.put(objectStructure.getOldMemoryAddress(), constraintsList.toArray(new Constraint[constraintsList.size()]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns a list of constraints of the feature's constraints. The order of constraints is important.
|
|
||||||
* @param ownerOMA
|
|
||||||
* the owner's old memory address
|
|
||||||
* @return a table of constraints for the feature specified by old memory address
|
|
||||||
*/
|
|
||||||
public Constraint[] getConstraints(Long ownerOMA) {
|
|
||||||
return constraints.get(ownerOMA);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearState() {
|
|
||||||
constraints.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shouldBeLoaded(Structure structure, DataRepository dataRepository) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,762 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2009-2010 jMonkeyEngine
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are
|
|
||||||
* met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
*
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
||||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
||||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
package com.jme3.scene.plugins.blender.helpers.v249;
|
|
||||||
|
|
||||||
import java.nio.FloatBuffer;
|
|
||||||
import java.nio.IntBuffer;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import com.jme3.animation.AnimControl;
|
|
||||||
import com.jme3.animation.Bone;
|
|
||||||
import com.jme3.animation.BoneAnimation;
|
|
||||||
import com.jme3.animation.BoneTrack;
|
|
||||||
import com.jme3.animation.Skeleton;
|
|
||||||
import com.jme3.animation.SkeletonControl;
|
|
||||||
import com.jme3.bounding.BoundingBox;
|
|
||||||
import com.jme3.bounding.BoundingSphere;
|
|
||||||
import com.jme3.bounding.BoundingVolume;
|
|
||||||
import com.jme3.effect.ParticleEmitter;
|
|
||||||
import com.jme3.effect.shapes.EmitterMeshVertexShape;
|
|
||||||
import com.jme3.effect.shapes.EmitterShape;
|
|
||||||
import com.jme3.material.Material;
|
|
||||||
import com.jme3.math.Matrix4f;
|
|
||||||
import com.jme3.math.Transform;
|
|
||||||
import com.jme3.math.Vector3f;
|
|
||||||
import com.jme3.scene.Geometry;
|
|
||||||
import com.jme3.scene.Mesh;
|
|
||||||
import com.jme3.scene.Node;
|
|
||||||
import com.jme3.scene.Spatial;
|
|
||||||
import com.jme3.scene.VertexBuffer.Type;
|
|
||||||
import com.jme3.scene.plugins.blender.data.FileBlockHeader;
|
|
||||||
import com.jme3.scene.plugins.blender.data.Structure;
|
|
||||||
import com.jme3.scene.plugins.blender.exception.BlenderFileException;
|
|
||||||
import com.jme3.scene.plugins.blender.helpers.ParticlesHelper;
|
|
||||||
import com.jme3.scene.plugins.blender.structures.Constraint;
|
|
||||||
import com.jme3.scene.plugins.blender.structures.Ipo;
|
|
||||||
import com.jme3.scene.plugins.blender.structures.Modifier;
|
|
||||||
import com.jme3.scene.plugins.blender.utils.AbstractBlenderHelper;
|
|
||||||
import com.jme3.scene.plugins.blender.utils.DataRepository;
|
|
||||||
import com.jme3.scene.plugins.blender.utils.DataRepository.LoadedFeatureDataType;
|
|
||||||
import com.jme3.scene.plugins.blender.utils.DynamicArray;
|
|
||||||
import com.jme3.scene.plugins.blender.utils.Pointer;
|
|
||||||
import com.jme3.scene.plugins.ogre.AnimData;
|
|
||||||
import com.jme3.scene.shape.Curve;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A class that is used in modifiers calculations.
|
|
||||||
* @author Marcin Roguski
|
|
||||||
*/
|
|
||||||
public class ModifierHelper extends AbstractBlenderHelper {
|
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(ModifierHelper.class.getName());
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This constructor parses the given blender version and stores the result. Some functionalities may differ in
|
|
||||||
* different blender versions.
|
|
||||||
* @param blenderVersion
|
|
||||||
* the version read from the blend file
|
|
||||||
*/
|
|
||||||
public ModifierHelper(String blenderVersion) {
|
|
||||||
super(blenderVersion);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method applies modifier to the object.
|
|
||||||
* @param node
|
|
||||||
* the loaded object
|
|
||||||
* @param modifier
|
|
||||||
* the modifier to apply
|
|
||||||
* @param dataRepository
|
|
||||||
* the data repository
|
|
||||||
* @return the node to whom the modifier was applied
|
|
||||||
*/
|
|
||||||
public Node applyModifier(Node node, Modifier modifier, DataRepository dataRepository) {
|
|
||||||
if (Modifier.ARMATURE_MODIFIER_DATA.equals(modifier.getType())) {
|
|
||||||
return this.applyArmatureModifierData(node, modifier, dataRepository);
|
|
||||||
} else if (Modifier.OBJECT_ANIMATION_MODIFIER_DATA.equals(modifier.getType())) {
|
|
||||||
return this.applyObjectAnimationModifier(node, modifier, dataRepository);
|
|
||||||
} else if (Modifier.ARRAY_MODIFIER_DATA.equals(modifier.getType())) {
|
|
||||||
return this.applyArrayModifierData(node, modifier, dataRepository);
|
|
||||||
} else if (Modifier.PARTICLE_MODIFIER_DATA.equals(modifier.getType())) {
|
|
||||||
return this.applyParticleSystemModifierData(node, modifier, dataRepository);
|
|
||||||
} else if (Modifier.MIRROR_MODIFIER_DATA.equals(modifier.getType())) {
|
|
||||||
return this.applyMirrorModifierData(node, modifier, dataRepository);
|
|
||||||
} else {
|
|
||||||
LOGGER.log(Level.WARNING, "Modifier: {0} not yet implemented!!!", modifier.getType());
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method reads the given object's modifiers.
|
|
||||||
* @param objectStructure
|
|
||||||
* the object structure
|
|
||||||
* @param dataRepository
|
|
||||||
* the data repository
|
|
||||||
* @param converter
|
|
||||||
* the converter object (in some cases we need to read an object first before loading the modifier)
|
|
||||||
* @throws BlenderFileException
|
|
||||||
* this exception is thrown when the blender file is somehow corrupted
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void readModifiers(Structure objectStructure, DataRepository dataRepository) throws BlenderFileException {
|
|
||||||
Structure modifiersListBase = (Structure) objectStructure.getFieldValue("modifiers");
|
|
||||||
List<Structure> modifiers = modifiersListBase.evaluateListBase(dataRepository);
|
|
||||||
for (Structure modifier : modifiers) {
|
|
||||||
Object loadedModifier = null;
|
|
||||||
Object modifierAdditionalData = null;
|
|
||||||
if (Modifier.ARRAY_MODIFIER_DATA.equals(modifier.getType())) {// ****************ARRAY MODIFIER
|
|
||||||
Map<String, Object> params = new HashMap<String, Object>();
|
|
||||||
|
|
||||||
Number fittype = (Number) modifier.getFieldValue("fit_type");
|
|
||||||
params.put("fittype", fittype);
|
|
||||||
switch (fittype.intValue()) {
|
|
||||||
case 0:// FIXED COUNT
|
|
||||||
params.put("count", modifier.getFieldValue("count"));
|
|
||||||
break;
|
|
||||||
case 1:// FIXED LENGTH
|
|
||||||
params.put("length", modifier.getFieldValue("length"));
|
|
||||||
break;
|
|
||||||
case 2:// FITCURVE
|
|
||||||
Pointer pCurveOb = (Pointer) modifier.getFieldValue("curve_ob");
|
|
||||||
float length = 0;
|
|
||||||
if (pCurveOb.isNotNull()) {
|
|
||||||
Structure curveStructure = pCurveOb.fetchData(dataRepository.getInputStream()).get(0);
|
|
||||||
ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);
|
|
||||||
Node curveObject = (Node) objectHelper.toObject(curveStructure, dataRepository);
|
|
||||||
Set<Number> referencesToCurveLengths = new HashSet<Number>(curveObject.getChildren().size());
|
|
||||||
for (Spatial spatial : curveObject.getChildren()) {
|
|
||||||
if (spatial instanceof Geometry) {
|
|
||||||
Mesh mesh = ((Geometry) spatial).getMesh();
|
|
||||||
if (mesh instanceof Curve) {
|
|
||||||
length += ((Curve) mesh).getLength();
|
|
||||||
} else {
|
|
||||||
//if bevel object has several parts then each mesh will have the same reference
|
|
||||||
//to length value (and we should use only one)
|
|
||||||
Number curveLength = spatial.getUserData("curveLength");
|
|
||||||
if (curveLength != null && !referencesToCurveLengths.contains(curveLength)) {
|
|
||||||
length += curveLength.floatValue();
|
|
||||||
referencesToCurveLengths.add(curveLength);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
params.put("length", Float.valueOf(length));
|
|
||||||
params.put("fittype", Integer.valueOf(1));// treat it like FIXED LENGTH
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert false : "Unknown array modifier fit type: " + fittype;
|
|
||||||
}
|
|
||||||
|
|
||||||
// offset parameters
|
|
||||||
int offsettype = ((Number) modifier.getFieldValue("offset_type")).intValue();
|
|
||||||
if ((offsettype & 0x01) != 0) {// Constant offset
|
|
||||||
DynamicArray<Number> offsetArray = (DynamicArray<Number>) modifier.getFieldValue("offset");
|
|
||||||
float[] offset = new float[]{offsetArray.get(0).floatValue(), offsetArray.get(1).floatValue(), offsetArray.get(2).floatValue()};
|
|
||||||
params.put("offset", offset);
|
|
||||||
}
|
|
||||||
if ((offsettype & 0x02) != 0) {// Relative offset
|
|
||||||
DynamicArray<Number> scaleArray = (DynamicArray<Number>) modifier.getFieldValue("scale");
|
|
||||||
float[] scale = new float[]{scaleArray.get(0).floatValue(), scaleArray.get(1).floatValue(), scaleArray.get(2).floatValue()};
|
|
||||||
params.put("scale", scale);
|
|
||||||
}
|
|
||||||
if ((offsettype & 0x04) != 0) {// Object offset
|
|
||||||
Pointer pOffsetObject = (Pointer) modifier.getFieldValue("offset_ob");
|
|
||||||
if (pOffsetObject.isNotNull()) {
|
|
||||||
params.put("offsetob", pOffsetObject);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// start cap and end cap
|
|
||||||
Pointer pStartCap = (Pointer) modifier.getFieldValue("start_cap");
|
|
||||||
if (pStartCap.isNotNull()) {
|
|
||||||
params.put("startcap", pStartCap);
|
|
||||||
}
|
|
||||||
Pointer pEndCap = (Pointer) modifier.getFieldValue("end_cap");
|
|
||||||
if (pEndCap.isNotNull()) {
|
|
||||||
params.put("endcap", pEndCap);
|
|
||||||
}
|
|
||||||
loadedModifier = params;
|
|
||||||
} else if (Modifier.MIRROR_MODIFIER_DATA.equals(modifier.getType())) {// ****************MIRROR MODIFIER
|
|
||||||
Map<String, Object> params = new HashMap<String, Object>();
|
|
||||||
|
|
||||||
params.put("flag", modifier.getFieldValue("flag"));
|
|
||||||
params.put("tolerance", modifier.getFieldValue("tolerance"));
|
|
||||||
Pointer pMirrorOb = (Pointer) modifier.getFieldValue("mirror_ob");
|
|
||||||
if (pMirrorOb.isNotNull()) {
|
|
||||||
params.put("mirrorob", pMirrorOb);
|
|
||||||
}
|
|
||||||
loadedModifier = params;
|
|
||||||
} else if (Modifier.ARMATURE_MODIFIER_DATA.equals(modifier.getType())) {// ****************ARMATURE MODIFIER
|
|
||||||
Pointer pArmatureObject = (Pointer) modifier.getFieldValue("object");
|
|
||||||
if (pArmatureObject.isNotNull()) {
|
|
||||||
ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);
|
|
||||||
Structure armatureObject = (Structure) dataRepository.getLoadedFeature(pArmatureObject.getOldMemoryAddress(), LoadedFeatureDataType.LOADED_STRUCTURE);
|
|
||||||
if (armatureObject == null) {// we check this first not to fetch the structure unnecessary
|
|
||||||
armatureObject = pArmatureObject.fetchData(dataRepository.getInputStream()).get(0);
|
|
||||||
objectHelper.toObject(armatureObject, dataRepository);
|
|
||||||
}
|
|
||||||
modifierAdditionalData = armatureObject.getOldMemoryAddress();
|
|
||||||
ArmatureHelper armatureHelper = dataRepository.getHelper(ArmatureHelper.class);
|
|
||||||
|
|
||||||
// changing bones matrices so that they fit the current object (that is why we need a copy of a skeleton)
|
|
||||||
Matrix4f armatureObjectMatrix = objectHelper.getTransformationMatrix(armatureObject);
|
|
||||||
Matrix4f inverseMeshObjectMatrix = objectHelper.getTransformationMatrix(objectStructure).invert();
|
|
||||||
Matrix4f additionalRootBoneTransformation = inverseMeshObjectMatrix.multLocal(armatureObjectMatrix);
|
|
||||||
Bone[] bones = armatureHelper.buildBonesStructure(Long.valueOf(0L), additionalRootBoneTransformation);
|
|
||||||
|
|
||||||
//setting the bones structure inside the skeleton (thus completing its loading)
|
|
||||||
Skeleton skeleton = new Skeleton(bones);
|
|
||||||
dataRepository.addLoadedFeatures(armatureObject.getOldMemoryAddress(), armatureObject.getName(), armatureObject, skeleton);
|
|
||||||
|
|
||||||
String objectName = objectStructure.getName();
|
|
||||||
Set<String> animationNames = dataRepository.getBlenderKey().getAnimationNames(objectName);
|
|
||||||
if (animationNames != null && animationNames.size() > 0) {
|
|
||||||
ArrayList<BoneAnimation> animations = new ArrayList<BoneAnimation>();
|
|
||||||
List<FileBlockHeader> actionHeaders = dataRepository.getFileBlocks(Integer.valueOf(FileBlockHeader.BLOCK_AC00));
|
|
||||||
for (FileBlockHeader header : actionHeaders) {
|
|
||||||
Structure actionStructure = header.getStructure(dataRepository);
|
|
||||||
String actionName = actionStructure.getName();
|
|
||||||
if (animationNames.contains(actionName)) {
|
|
||||||
int[] animationFrames = dataRepository.getBlenderKey().getAnimationFrames(objectName, actionName);
|
|
||||||
int fps = dataRepository.getBlenderKey().getFps();
|
|
||||||
float start = (float) animationFrames[0] / (float) fps;
|
|
||||||
float stop = (float) animationFrames[1] / (float) fps;
|
|
||||||
BoneAnimation boneAnimation = new BoneAnimation(actionName, stop - start);
|
|
||||||
boneAnimation.setTracks(armatureHelper.getTracks(actionStructure, dataRepository, objectName, actionName));
|
|
||||||
animations.add(boneAnimation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
loadedModifier = new AnimData(new Skeleton(bones), animations);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LOGGER.log(Level.WARNING, "Unsupported modifier type: {0}", modifier.getType());
|
|
||||||
}
|
|
||||||
} else if (Modifier.PARTICLE_MODIFIER_DATA.equals(modifier.getType())) {// ****************PARTICLES MODIFIER
|
|
||||||
Pointer pParticleSystem = (Pointer) modifier.getFieldValue("psys");
|
|
||||||
if (pParticleSystem.isNotNull()) {
|
|
||||||
ParticlesHelper particlesHelper = dataRepository.getHelper(ParticlesHelper.class);
|
|
||||||
Structure particleSystem = pParticleSystem.fetchData(dataRepository.getInputStream()).get(0);
|
|
||||||
loadedModifier = particlesHelper.toParticleEmitter(particleSystem, dataRepository);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// adding modifier to the modifier's lists
|
|
||||||
if (loadedModifier != null) {
|
|
||||||
dataRepository.addModifier(objectStructure.getOldMemoryAddress(), modifier.getType(), loadedModifier, modifierAdditionalData);
|
|
||||||
modifierAdditionalData = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//at the end read object's animation modifier
|
|
||||||
Modifier objectAnimationModifier = this.readObjectAnimation(objectStructure, dataRepository);
|
|
||||||
if (objectAnimationModifier != null) {
|
|
||||||
dataRepository.addModifier(objectStructure.getOldMemoryAddress(),
|
|
||||||
objectAnimationModifier.getType(),
|
|
||||||
objectAnimationModifier.getJmeModifierRepresentation(),
|
|
||||||
objectAnimationModifier.getAdditionalData());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method reads animation of the object itself (without bones) and stores it as an ArmatureModifierData
|
|
||||||
* modifier. The animation is returned as a modifier. It should be later applied regardless other modifiers. The
|
|
||||||
* reason for this is that object may not have modifiers added but it's animation should be working.
|
|
||||||
* @param objectStructure
|
|
||||||
* the structure of the object
|
|
||||||
* @param dataRepository
|
|
||||||
* the data repository
|
|
||||||
* @return animation modifier is returned, it should be separately applied when the object is loaded
|
|
||||||
* @throws BlenderFileException
|
|
||||||
* this exception is thrown when the blender file is somehow corrupted
|
|
||||||
*/
|
|
||||||
protected Modifier readObjectAnimation(Structure objectStructure, DataRepository dataRepository) throws BlenderFileException {
|
|
||||||
Pointer pIpo = (Pointer) objectStructure.getFieldValue("ipo");
|
|
||||||
if (pIpo.isNotNull()) {
|
|
||||||
//check if there is an action name connected with this ipo
|
|
||||||
String objectAnimationName = null;
|
|
||||||
List<FileBlockHeader> actionBlocks = dataRepository.getFileBlocks(Integer.valueOf(FileBlockHeader.BLOCK_AC00));
|
|
||||||
for (FileBlockHeader actionBlock : actionBlocks) {
|
|
||||||
Structure action = actionBlock.getStructure(dataRepository);
|
|
||||||
List<Structure> actionChannels = ((Structure) action.getFieldValue("chanbase")).evaluateListBase(dataRepository);
|
|
||||||
if (actionChannels.size() == 1) {//object's animtion action has only one channel
|
|
||||||
Pointer pChannelIpo = (Pointer) actionChannels.get(0).getFieldValue("ipo");
|
|
||||||
if (pChannelIpo.equals(pIpo)) {
|
|
||||||
objectAnimationName = action.getName();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String objectName = objectStructure.getName();
|
|
||||||
if (objectAnimationName == null) {//set the object's animation name to object's name
|
|
||||||
objectAnimationName = objectName;
|
|
||||||
}
|
|
||||||
|
|
||||||
IpoHelper ipoHelper = dataRepository.getHelper(IpoHelper.class);
|
|
||||||
Structure ipoStructure = pIpo.fetchData(dataRepository.getInputStream()).get(0);
|
|
||||||
Ipo ipo = ipoHelper.createIpo(ipoStructure, dataRepository);
|
|
||||||
int[] animationFrames = dataRepository.getBlenderKey().getAnimationFrames(objectName, objectAnimationName);
|
|
||||||
if (animationFrames == null) {//if the name was created here there are no frames set for the animation
|
|
||||||
animationFrames = new int[]{1, ipo.getLastFrame()};
|
|
||||||
}
|
|
||||||
int fps = dataRepository.getBlenderKey().getFps();
|
|
||||||
float start = (float) animationFrames[0] / (float) fps;
|
|
||||||
float stop = (float) animationFrames[1] / (float) fps;
|
|
||||||
|
|
||||||
//calculating track for the only bone in this skeleton
|
|
||||||
BoneTrack[] tracks = new BoneTrack[1];
|
|
||||||
tracks[0] = ipo.calculateTrack(0, animationFrames[0], animationFrames[1], fps);
|
|
||||||
|
|
||||||
BoneAnimation boneAnimation = new BoneAnimation(objectAnimationName, stop - start);
|
|
||||||
boneAnimation.setTracks(tracks);
|
|
||||||
ArrayList<BoneAnimation> animations = new ArrayList<BoneAnimation>(1);
|
|
||||||
animations.add(boneAnimation);
|
|
||||||
|
|
||||||
//preparing the object's bone
|
|
||||||
ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);
|
|
||||||
Transform t = objectHelper.getTransformation(objectStructure, dataRepository);
|
|
||||||
Bone bone = new Bone(null);
|
|
||||||
bone.setBindTransforms(t.getTranslation(), t.getRotation(), t.getScale());
|
|
||||||
|
|
||||||
return new Modifier(Modifier.OBJECT_ANIMATION_MODIFIER_DATA, new AnimData(new Skeleton(new Bone[]{bone}), animations), objectStructure.getOldMemoryAddress());
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method applies particles emitter to the given node.
|
|
||||||
* @param node
|
|
||||||
* the particles emitter node
|
|
||||||
* @param modifier
|
|
||||||
* the modifier containing the emitter data
|
|
||||||
* @param dataRepository
|
|
||||||
* the data repository
|
|
||||||
* @return node with particles' emitter applied
|
|
||||||
*/
|
|
||||||
protected Node applyParticleSystemModifierData(Node node, Modifier modifier, DataRepository dataRepository) {
|
|
||||||
MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);
|
|
||||||
ParticleEmitter emitter = (ParticleEmitter) modifier.getJmeModifierRepresentation();
|
|
||||||
emitter = emitter.clone();
|
|
||||||
|
|
||||||
// veryfying the alpha function for particles' texture
|
|
||||||
Integer alphaFunction = MaterialHelper.ALPHA_MASK_HYPERBOLE;
|
|
||||||
char nameSuffix = emitter.getName().charAt(emitter.getName().length() - 1);
|
|
||||||
if (nameSuffix == 'B' || nameSuffix == 'N') {
|
|
||||||
alphaFunction = MaterialHelper.ALPHA_MASK_NONE;
|
|
||||||
}
|
|
||||||
// removing the type suffix from the name
|
|
||||||
emitter.setName(emitter.getName().substring(0, emitter.getName().length() - 1));
|
|
||||||
|
|
||||||
// applying emitter shape
|
|
||||||
EmitterShape emitterShape = emitter.getShape();
|
|
||||||
List<Mesh> meshes = new ArrayList<Mesh>();
|
|
||||||
for (Spatial spatial : node.getChildren()) {
|
|
||||||
if (spatial instanceof Geometry) {
|
|
||||||
Mesh mesh = ((Geometry) spatial).getMesh();
|
|
||||||
if (mesh != null) {
|
|
||||||
meshes.add(mesh);
|
|
||||||
Material material = materialHelper.getParticlesMaterial(((Geometry) spatial).getMaterial(), alphaFunction, dataRepository);
|
|
||||||
emitter.setMaterial(material);// TODO: divide into several pieces
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (meshes.size() > 0 && emitterShape instanceof EmitterMeshVertexShape) {
|
|
||||||
((EmitterMeshVertexShape) emitterShape).setMeshes(meshes);
|
|
||||||
}
|
|
||||||
|
|
||||||
node.attachChild(emitter);
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method applies ArmatureModifierData to the loaded object.
|
|
||||||
* @param node
|
|
||||||
* the loaded object
|
|
||||||
* @param modifier
|
|
||||||
* the modifier to apply
|
|
||||||
* @param dataRepository
|
|
||||||
* the data repository
|
|
||||||
* @return the node to whom the modifier was applied
|
|
||||||
*/
|
|
||||||
protected Node applyArmatureModifierData(Node node, Modifier modifier, DataRepository dataRepository) {
|
|
||||||
AnimData ad = (AnimData) modifier.getJmeModifierRepresentation();
|
|
||||||
ArrayList<BoneAnimation> animList = ad.anims;
|
|
||||||
Long modifierArmatureObject = (Long) modifier.getAdditionalData();
|
|
||||||
if (animList != null && animList.size() > 0) {
|
|
||||||
ConstraintHelper constraintHelper = dataRepository.getHelper(ConstraintHelper.class);
|
|
||||||
Constraint[] constraints = constraintHelper.getConstraints(modifierArmatureObject);
|
|
||||||
HashMap<String, BoneAnimation> anims = new HashMap<String, BoneAnimation>();
|
|
||||||
for (int i = 0; i < animList.size(); ++i) {
|
|
||||||
BoneAnimation boneAnimation = animList.get(i).clone();
|
|
||||||
|
|
||||||
// baking constraints into animations
|
|
||||||
if (constraints != null && constraints.length > 0) {
|
|
||||||
for (Constraint constraint : constraints) {
|
|
||||||
constraint.affectAnimation(ad.skeleton, boneAnimation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
anims.put(boneAnimation.getName(), boneAnimation);
|
|
||||||
}
|
|
||||||
|
|
||||||
// getting meshes
|
|
||||||
Mesh[] meshes = null;
|
|
||||||
List<Mesh> meshesList = new ArrayList<Mesh>();
|
|
||||||
List<Spatial> children = node.getChildren();
|
|
||||||
for (Spatial child : children) {
|
|
||||||
if (child instanceof Geometry) {
|
|
||||||
meshesList.add(((Geometry) child).getMesh());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (meshesList.size() > 0) {
|
|
||||||
meshes = meshesList.toArray(new Mesh[meshesList.size()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// applying the control to the node
|
|
||||||
SkeletonControl skeletonControl = new SkeletonControl(meshes, ad.skeleton);
|
|
||||||
AnimControl control = node.getControl(AnimControl.class);
|
|
||||||
|
|
||||||
if (control == null) {
|
|
||||||
control = new AnimControl(ad.skeleton);
|
|
||||||
} else {
|
|
||||||
// merging skeletons
|
|
||||||
Skeleton controlSkeleton = control.getSkeleton();
|
|
||||||
int boneIndexIncrease = controlSkeleton.getBoneCount();
|
|
||||||
Skeleton skeleton = this.merge(controlSkeleton, ad.skeleton);
|
|
||||||
|
|
||||||
// merging animations
|
|
||||||
HashMap<String, BoneAnimation> animations = new HashMap<String, BoneAnimation>();
|
|
||||||
for (String animationName : control.getAnimationNames()) {
|
|
||||||
animations.put(animationName, control.getAnim(animationName));
|
|
||||||
}
|
|
||||||
for (Entry<String, BoneAnimation> animEntry : anims.entrySet()) {
|
|
||||||
BoneAnimation ba = animEntry.getValue();
|
|
||||||
for (int i = 0; i < ba.getTracks().length; ++i) {
|
|
||||||
BoneTrack bt = ba.getTracks()[i];
|
|
||||||
int newBoneIndex = bt.getTargetBoneIndex() + boneIndexIncrease;
|
|
||||||
ba.getTracks()[i] = new BoneTrack(newBoneIndex, bt.getTimes(), bt.getTranslations(), bt.getRotations(), bt.getScales());
|
|
||||||
}
|
|
||||||
animations.put(animEntry.getKey(), animEntry.getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
// replacing the control
|
|
||||||
node.removeControl(control);
|
|
||||||
control = new AnimControl(skeleton);
|
|
||||||
}
|
|
||||||
control.setAnimations(anims);
|
|
||||||
node.addControl(control);
|
|
||||||
node.addControl(skeletonControl);
|
|
||||||
}
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Node applyObjectAnimationModifier(Node node, Modifier modifier, DataRepository dataRepository) {
|
|
||||||
AnimData ad = (AnimData) modifier.getJmeModifierRepresentation();
|
|
||||||
|
|
||||||
// TODO: Why is this line here? Why is this needed?
|
|
||||||
// Remove if necessary.
|
|
||||||
//ad.skeleton.getBone(0).setAttachNode(node);
|
|
||||||
|
|
||||||
return this.applyArmatureModifierData(node, modifier, dataRepository);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method applies the array modifier to the node.
|
|
||||||
* @param node
|
|
||||||
* the object the modifier will be applied to
|
|
||||||
* @param modifier
|
|
||||||
* the modifier to be applied
|
|
||||||
* @param dataRepository
|
|
||||||
* the data repository
|
|
||||||
* @return object node with array modifier applied
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected Node applyArrayModifierData(Node node, Modifier modifier, DataRepository dataRepository) {
|
|
||||||
Map<String, Object> modifierData = (Map<String, Object>) modifier.getJmeModifierRepresentation();
|
|
||||||
int fittype = ((Number) modifierData.get("fittype")).intValue();
|
|
||||||
float[] offset = (float[]) modifierData.get("offset");
|
|
||||||
if (offset == null) {// the node will be repeated several times in the same place
|
|
||||||
offset = new float[]{0.0f, 0.0f, 0.0f};
|
|
||||||
}
|
|
||||||
float[] scale = (float[]) modifierData.get("scale");
|
|
||||||
if (scale == null) {// the node will be repeated several times in the same place
|
|
||||||
scale = new float[]{0.0f, 0.0f, 0.0f};
|
|
||||||
} else {
|
|
||||||
// getting bounding box
|
|
||||||
node.updateModelBound();
|
|
||||||
BoundingVolume boundingVolume = node.getWorldBound();
|
|
||||||
if (boundingVolume instanceof BoundingBox) {
|
|
||||||
scale[0] *= ((BoundingBox) boundingVolume).getXExtent() * 2.0f;
|
|
||||||
scale[1] *= ((BoundingBox) boundingVolume).getYExtent() * 2.0f;
|
|
||||||
scale[2] *= ((BoundingBox) boundingVolume).getZExtent() * 2.0f;
|
|
||||||
} else if (boundingVolume instanceof BoundingSphere) {
|
|
||||||
float radius = ((BoundingSphere) boundingVolume).getRadius();
|
|
||||||
scale[0] *= radius * 2.0f;
|
|
||||||
scale[1] *= radius * 2.0f;
|
|
||||||
scale[2] *= radius * 2.0f;
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException("Unknown bounding volume type: " + boundingVolume.getClass().getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// adding object's offset
|
|
||||||
float[] objectOffset = new float[]{0.0f, 0.0f, 0.0f};
|
|
||||||
Pointer pOffsetObject = (Pointer) modifierData.get("offsetob");
|
|
||||||
if (pOffsetObject != null) {
|
|
||||||
FileBlockHeader offsetObjectBlock = dataRepository.getFileBlock(pOffsetObject.getOldMemoryAddress());
|
|
||||||
ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);
|
|
||||||
try {// we take the structure in case the object was not yet loaded
|
|
||||||
Structure offsetStructure = offsetObjectBlock.getStructure(dataRepository);
|
|
||||||
Vector3f translation = objectHelper.getTransformation(offsetStructure, dataRepository).getTranslation();
|
|
||||||
objectOffset[0] = translation.x;
|
|
||||||
objectOffset[1] = translation.y;
|
|
||||||
objectOffset[2] = translation.z;
|
|
||||||
} catch (BlenderFileException e) {
|
|
||||||
LOGGER.log(Level.WARNING, "Problems in blender file structure! Object offset cannot be applied! The problem: {0}", e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// getting start and end caps
|
|
||||||
Node[] caps = new Node[]{null, null};
|
|
||||||
Pointer[] pCaps = new Pointer[]{(Pointer) modifierData.get("startcap"), (Pointer) modifierData.get("endcap")};
|
|
||||||
for (int i = 0; i < pCaps.length; ++i) {
|
|
||||||
if (pCaps[i] != null) {
|
|
||||||
caps[i] = (Node) dataRepository.getLoadedFeature(pCaps[i].getOldMemoryAddress(), LoadedFeatureDataType.LOADED_FEATURE);
|
|
||||||
if (caps[i] != null) {
|
|
||||||
caps[i] = (Node) caps[i].clone();
|
|
||||||
} else {
|
|
||||||
FileBlockHeader capBlock = dataRepository.getFileBlock(pOffsetObject.getOldMemoryAddress());
|
|
||||||
try {// we take the structure in case the object was not yet loaded
|
|
||||||
Structure capStructure = capBlock.getStructure(dataRepository);
|
|
||||||
ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);
|
|
||||||
caps[i] = (Node) objectHelper.toObject(capStructure, dataRepository);
|
|
||||||
if (caps[i] == null) {
|
|
||||||
LOGGER.log(Level.WARNING, "Cap object ''{0}'' couldn''t be loaded!", capStructure.getName());
|
|
||||||
}
|
|
||||||
} catch (BlenderFileException e) {
|
|
||||||
LOGGER.log(Level.WARNING, "Problems in blender file structure! Cap object cannot be applied! The problem: {0}", e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector3f translationVector = new Vector3f(offset[0] + scale[0] + objectOffset[0], offset[1] + scale[1] + objectOffset[1], offset[2] + scale[2] + objectOffset[2]);
|
|
||||||
|
|
||||||
// getting/calculating repeats amount
|
|
||||||
int count = 0;
|
|
||||||
if (fittype == 0) {// Fixed count
|
|
||||||
count = ((Number) modifierData.get("count")).intValue() - 1;
|
|
||||||
} else if (fittype == 1) {// Fixed length
|
|
||||||
float length = ((Number) modifierData.get("length")).floatValue();
|
|
||||||
if (translationVector.length() > 0.0f) {
|
|
||||||
count = (int) (length / translationVector.length()) - 1;
|
|
||||||
}
|
|
||||||
} else if (fittype == 2) {// Fit curve
|
|
||||||
throw new IllegalStateException("Fit curve should be transformed to Fixed Length array type!");
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException("Unknown fit type: " + fittype);
|
|
||||||
}
|
|
||||||
|
|
||||||
// adding translated nodes and caps
|
|
||||||
if (count > 0) {
|
|
||||||
Node[] arrayNodes = new Node[count];
|
|
||||||
Vector3f newTranslation = new Vector3f();
|
|
||||||
for (int i = 0; i < count; ++i) {
|
|
||||||
newTranslation.addLocal(translationVector);
|
|
||||||
Node nodeClone = (Node) node.clone();
|
|
||||||
nodeClone.setLocalTranslation(newTranslation);
|
|
||||||
arrayNodes[i] = nodeClone;
|
|
||||||
}
|
|
||||||
for (Node nodeClone : arrayNodes) {
|
|
||||||
node.attachChild(nodeClone);
|
|
||||||
}
|
|
||||||
if (caps[0] != null) {
|
|
||||||
caps[0].getLocalTranslation().set(node.getLocalTranslation()).subtractLocal(translationVector);
|
|
||||||
node.attachChild(caps[0]);
|
|
||||||
}
|
|
||||||
if (caps[1] != null) {
|
|
||||||
caps[1].getLocalTranslation().set(newTranslation).addLocal(translationVector);
|
|
||||||
node.attachChild(caps[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method applies the mirror modifier to the node.
|
|
||||||
* @param node
|
|
||||||
* the object the modifier will be applied to
|
|
||||||
* @param modifier
|
|
||||||
* the modifier to be applied
|
|
||||||
* @param dataRepository
|
|
||||||
* the data repository
|
|
||||||
* @return object node with mirror modifier applied
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected Node applyMirrorModifierData(Node node, Modifier modifier, DataRepository dataRepository) {
|
|
||||||
Map<String, Object> modifierData = (Map<String, Object>) modifier.getJmeModifierRepresentation();
|
|
||||||
int flag = ((Number) modifierData.get("flag")).intValue();
|
|
||||||
float[] mirrorFactor = new float[]{
|
|
||||||
(flag & 0x08) != 0 ? -1.0f : 1.0f,
|
|
||||||
(flag & 0x10) != 0 ? -1.0f : 1.0f,
|
|
||||||
(flag & 0x20) != 0 ? -1.0f : 1.0f
|
|
||||||
};
|
|
||||||
float[] center = new float[]{0.0f, 0.0f, 0.0f};
|
|
||||||
Pointer pObject = (Pointer) modifierData.get("mirrorob");
|
|
||||||
if (pObject != null) {
|
|
||||||
Structure objectStructure;
|
|
||||||
try {
|
|
||||||
objectStructure = pObject.fetchData(dataRepository.getInputStream()).get(0);
|
|
||||||
ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);
|
|
||||||
Node object = (Node) objectHelper.toObject(objectStructure, dataRepository);
|
|
||||||
if (object != null) {
|
|
||||||
Vector3f translation = object.getWorldTranslation();
|
|
||||||
center[0] = translation.x;
|
|
||||||
center[1] = translation.y;
|
|
||||||
center[2] = translation.z;
|
|
||||||
}
|
|
||||||
} catch (BlenderFileException e) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Cannot load mirror''s reference object. Cause: {0}", e.getLocalizedMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
float tolerance = ((Number) modifierData.get("tolerance")).floatValue();
|
|
||||||
boolean mirrorU = (flag & 0x01) != 0;
|
|
||||||
boolean mirrorV = (flag & 0x02) != 0;
|
|
||||||
// boolean mirrorVGroup = (flag & 0x20) != 0;
|
|
||||||
|
|
||||||
List<Geometry> geometriesToAdd = new ArrayList<Geometry>();
|
|
||||||
for (int mirrorIndex = 0; mirrorIndex < 3; ++mirrorIndex) {
|
|
||||||
if (mirrorFactor[mirrorIndex] == -1.0f) {
|
|
||||||
for (Spatial spatial : node.getChildren()) {
|
|
||||||
if (spatial instanceof Geometry) {
|
|
||||||
Mesh mesh = ((Geometry) spatial).getMesh();
|
|
||||||
Mesh clone = mesh.deepClone();
|
|
||||||
|
|
||||||
// getting buffers
|
|
||||||
FloatBuffer position = mesh.getFloatBuffer(Type.Position);
|
|
||||||
FloatBuffer bindPosePosition = mesh.getFloatBuffer(Type.BindPosePosition);
|
|
||||||
|
|
||||||
FloatBuffer clonePosition = clone.getFloatBuffer(Type.Position);
|
|
||||||
FloatBuffer cloneBindPosePosition = clone.getFloatBuffer(Type.BindPosePosition);
|
|
||||||
FloatBuffer cloneNormals = clone.getFloatBuffer(Type.Normal);
|
|
||||||
FloatBuffer cloneBindPoseNormals = clone.getFloatBuffer(Type.BindPoseNormal);
|
|
||||||
IntBuffer cloneIndexes = (IntBuffer) clone.getBuffer(Type.Index).getData();
|
|
||||||
|
|
||||||
// modyfying data
|
|
||||||
for (int i = mirrorIndex; i < clonePosition.limit(); i += 3) {
|
|
||||||
float value = clonePosition.get(i);
|
|
||||||
float d = center[mirrorIndex] - value;
|
|
||||||
|
|
||||||
if (Math.abs(d) <= tolerance) {
|
|
||||||
clonePosition.put(i, center[mirrorIndex]);
|
|
||||||
cloneBindPosePosition.put(i, center[mirrorIndex]);
|
|
||||||
position.put(i, center[mirrorIndex]);
|
|
||||||
bindPosePosition.put(i, center[mirrorIndex]);
|
|
||||||
} else {
|
|
||||||
clonePosition.put(i, value + 2.0f * d);
|
|
||||||
cloneBindPosePosition.put(i, value + 2.0f * d);
|
|
||||||
}
|
|
||||||
cloneNormals.put(i, -cloneNormals.get(i));
|
|
||||||
cloneBindPoseNormals.put(i, -cloneNormals.get(i));
|
|
||||||
|
|
||||||
//modifying clone indexes
|
|
||||||
int vertexIndex = (i - mirrorIndex) / 3;
|
|
||||||
if (vertexIndex % 3 == 0 && vertexIndex<cloneIndexes.limit()) {
|
|
||||||
int index = cloneIndexes.get(vertexIndex + 2);
|
|
||||||
cloneIndexes.put(vertexIndex + 2, cloneIndexes.get(vertexIndex + 1));
|
|
||||||
cloneIndexes.put(vertexIndex + 1, index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mirrorU) {
|
|
||||||
FloatBuffer cloneUVs = (FloatBuffer) clone.getBuffer(Type.TexCoord).getData();
|
|
||||||
for (int i = 0; i < cloneUVs.limit(); i += 2) {
|
|
||||||
cloneUVs.put(i, 1.0f - cloneUVs.get(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (mirrorV) {
|
|
||||||
FloatBuffer cloneUVs = (FloatBuffer) clone.getBuffer(Type.TexCoord).getData();
|
|
||||||
for (int i = 1; i < cloneUVs.limit(); i += 2) {
|
|
||||||
cloneUVs.put(i, 1.0f - cloneUVs.get(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Geometry geometry = new Geometry(null, clone);
|
|
||||||
geometry.setMaterial(((Geometry) spatial).getMaterial());
|
|
||||||
geometriesToAdd.add(geometry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// adding meshes to node
|
|
||||||
for (Geometry geometry : geometriesToAdd) {
|
|
||||||
node.attachChild(geometry);
|
|
||||||
}
|
|
||||||
geometriesToAdd.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method merges two skeletons into one. I assume that each skeleton's 0-indexed bone is objectAnimationBone so
|
|
||||||
* only one such bone should be placed in the result
|
|
||||||
* @param s1
|
|
||||||
* first skeleton
|
|
||||||
* @param s2
|
|
||||||
* second skeleton
|
|
||||||
* @return merged skeleton
|
|
||||||
*/
|
|
||||||
protected Skeleton merge(Skeleton s1, Skeleton s2) {
|
|
||||||
List<Bone> bones = new ArrayList<Bone>(s1.getBoneCount() + s2.getBoneCount());
|
|
||||||
for (int i = 0; i < s1.getBoneCount(); ++i) {
|
|
||||||
bones.add(s1.getBone(i));
|
|
||||||
}
|
|
||||||
for (int i = 1; i < s2.getBoneCount(); ++i) {// ommit objectAnimationBone
|
|
||||||
bones.add(s2.getBone(i));
|
|
||||||
}
|
|
||||||
return new Skeleton(bones.toArray(new Bone[bones.size()]));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shouldBeLoaded(Structure structure, DataRepository dataRepository) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -29,7 +29,7 @@
|
|||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
package com.jme3.scene.plugins.blender.helpers.v249;
|
package com.jme3.scene.plugins.blender.lights;
|
||||||
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
@ -39,11 +39,11 @@ import com.jme3.light.DirectionalLight;
|
|||||||
import com.jme3.light.Light;
|
import com.jme3.light.Light;
|
||||||
import com.jme3.light.PointLight;
|
import com.jme3.light.PointLight;
|
||||||
import com.jme3.math.ColorRGBA;
|
import com.jme3.math.ColorRGBA;
|
||||||
import com.jme3.scene.plugins.blender.data.Structure;
|
import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
|
||||||
import com.jme3.scene.plugins.blender.exception.BlenderFileException;
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
import com.jme3.scene.plugins.blender.utils.AbstractBlenderHelper;
|
import com.jme3.scene.plugins.blender.DataRepository.LoadedFeatureDataType;
|
||||||
import com.jme3.scene.plugins.blender.utils.DataRepository;
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
import com.jme3.scene.plugins.blender.utils.DataRepository.LoadedFeatureDataType;
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class that is used in light calculations.
|
* A class that is used in light calculations.
|
@ -29,7 +29,7 @@
|
|||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
package com.jme3.scene.plugins.blender.helpers.v249;
|
package com.jme3.scene.plugins.blender.materials;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -48,13 +48,14 @@ import com.jme3.material.RenderState.BlendMode;
|
|||||||
import com.jme3.material.RenderState.FaceCullMode;
|
import com.jme3.material.RenderState.FaceCullMode;
|
||||||
import com.jme3.math.ColorRGBA;
|
import com.jme3.math.ColorRGBA;
|
||||||
import com.jme3.math.FastMath;
|
import com.jme3.math.FastMath;
|
||||||
import com.jme3.scene.plugins.blender.data.Structure;
|
import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
|
||||||
import com.jme3.scene.plugins.blender.exception.BlenderFileException;
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
import com.jme3.scene.plugins.blender.utils.AbstractBlenderHelper;
|
import com.jme3.scene.plugins.blender.DataRepository.LoadedFeatureDataType;
|
||||||
import com.jme3.scene.plugins.blender.utils.DataRepository;
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
import com.jme3.scene.plugins.blender.utils.DataRepository.LoadedFeatureDataType;
|
import com.jme3.scene.plugins.blender.file.DynamicArray;
|
||||||
import com.jme3.scene.plugins.blender.utils.DynamicArray;
|
import com.jme3.scene.plugins.blender.file.Pointer;
|
||||||
import com.jme3.scene.plugins.blender.utils.Pointer;
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
import com.jme3.scene.plugins.blender.textures.TextureHelper;
|
||||||
import com.jme3.shader.VarType;
|
import com.jme3.shader.VarType;
|
||||||
import com.jme3.texture.Image;
|
import com.jme3.texture.Image;
|
||||||
import com.jme3.texture.Image.Format;
|
import com.jme3.texture.Image.Format;
|
@ -29,7 +29,7 @@
|
|||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
package com.jme3.scene.plugins.blender.helpers.v249;
|
package com.jme3.scene.plugins.blender.meshes;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.FloatBuffer;
|
import java.nio.FloatBuffer;
|
||||||
@ -57,14 +57,17 @@ import com.jme3.scene.VertexBuffer;
|
|||||||
import com.jme3.scene.VertexBuffer.Format;
|
import com.jme3.scene.VertexBuffer.Format;
|
||||||
import com.jme3.scene.VertexBuffer.Type;
|
import com.jme3.scene.VertexBuffer.Type;
|
||||||
import com.jme3.scene.VertexBuffer.Usage;
|
import com.jme3.scene.VertexBuffer.Usage;
|
||||||
import com.jme3.scene.plugins.blender.data.Structure;
|
import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
|
||||||
import com.jme3.scene.plugins.blender.exception.BlenderFileException;
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
import com.jme3.scene.plugins.blender.structures.Properties;
|
import com.jme3.scene.plugins.blender.DataRepository.LoadedFeatureDataType;
|
||||||
import com.jme3.scene.plugins.blender.utils.AbstractBlenderHelper;
|
import com.jme3.scene.plugins.blender.animations.ArmatureHelper;
|
||||||
import com.jme3.scene.plugins.blender.utils.DataRepository;
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
import com.jme3.scene.plugins.blender.utils.DataRepository.LoadedFeatureDataType;
|
import com.jme3.scene.plugins.blender.file.DynamicArray;
|
||||||
import com.jme3.scene.plugins.blender.utils.DynamicArray;
|
import com.jme3.scene.plugins.blender.file.Pointer;
|
||||||
import com.jme3.scene.plugins.blender.utils.Pointer;
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
import com.jme3.scene.plugins.blender.materials.MaterialHelper;
|
||||||
|
import com.jme3.scene.plugins.blender.objects.Properties;
|
||||||
|
import com.jme3.scene.plugins.blender.textures.TextureHelper;
|
||||||
import com.jme3.texture.Texture;
|
import com.jme3.texture.Texture;
|
||||||
import com.jme3.util.BufferUtils;
|
import com.jme3.util.BufferUtils;
|
||||||
|
|
||||||
@ -465,7 +468,7 @@ public class MeshHelper extends AbstractBlenderHelper {
|
|||||||
* @param vertices
|
* @param vertices
|
||||||
* a list of vertices read from the blender file
|
* a list of vertices read from the blender file
|
||||||
*/
|
*/
|
||||||
protected void addNormal(Vector3f normalToAdd, Map<Vector3f, Vector3f> normalMap, boolean smooth, Vector3f... vertices) {
|
public void addNormal(Vector3f normalToAdd, Map<Vector3f, Vector3f> normalMap, boolean smooth, Vector3f... vertices) {
|
||||||
for (Vector3f v : vertices) {
|
for (Vector3f v : vertices) {
|
||||||
Vector3f n = normalMap.get(v);
|
Vector3f n = normalMap.get(v);
|
||||||
if (!smooth || n == null) {
|
if (!smooth || n == null) {
|
@ -0,0 +1,216 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.modifiers;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.jme3.animation.AnimControl;
|
||||||
|
import com.jme3.animation.Bone;
|
||||||
|
import com.jme3.animation.BoneAnimation;
|
||||||
|
import com.jme3.animation.BoneTrack;
|
||||||
|
import com.jme3.animation.Skeleton;
|
||||||
|
import com.jme3.animation.SkeletonControl;
|
||||||
|
import com.jme3.math.Matrix4f;
|
||||||
|
import com.jme3.scene.Geometry;
|
||||||
|
import com.jme3.scene.Mesh;
|
||||||
|
import com.jme3.scene.Node;
|
||||||
|
import com.jme3.scene.Spatial;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository.LoadedFeatureDataType;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.ArmatureHelper;
|
||||||
|
import com.jme3.scene.plugins.blender.constraints.Constraint;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.FileBlockHeader;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Pointer;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
import com.jme3.scene.plugins.blender.objects.ObjectHelper;
|
||||||
|
import com.jme3.scene.plugins.ogre.AnimData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This modifier allows to add bone animation to the object.
|
||||||
|
*
|
||||||
|
* @author Marcin Roguski (Kaelthas)
|
||||||
|
*/
|
||||||
|
/* package */class ArmatureModifier extends Modifier {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor is only temporary. It will be removed when object
|
||||||
|
* animation is implemented in jme. TODO!!!!!!!
|
||||||
|
*/
|
||||||
|
/* package */ArmatureModifier() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor reads animation data from the object structore. The
|
||||||
|
* stored data is the AnimData and additional data is armature's OMA.
|
||||||
|
*
|
||||||
|
* @param objectStructure
|
||||||
|
* the structure of the object
|
||||||
|
* @param modifierStructure
|
||||||
|
* the structure of the modifier
|
||||||
|
* @param dataRepository
|
||||||
|
* the data repository
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* this exception is thrown when the blender file is somehow
|
||||||
|
* corrupted
|
||||||
|
*/
|
||||||
|
public ArmatureModifier(Structure objectStructure, Structure modifierStructure, DataRepository dataRepository) throws BlenderFileException {
|
||||||
|
Pointer pArmatureObject = (Pointer) modifierStructure.getFieldValue("object");
|
||||||
|
if (pArmatureObject.isNotNull()) {
|
||||||
|
ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);
|
||||||
|
Structure armatureObject = (Structure) dataRepository.getLoadedFeature(pArmatureObject.getOldMemoryAddress(),
|
||||||
|
LoadedFeatureDataType.LOADED_STRUCTURE);
|
||||||
|
if (armatureObject == null) {// we check this first not to fetch the
|
||||||
|
// structure unnecessary
|
||||||
|
armatureObject = pArmatureObject.fetchData(dataRepository.getInputStream()).get(0);
|
||||||
|
objectHelper.toObject(armatureObject, dataRepository);
|
||||||
|
}
|
||||||
|
additionalData = armatureObject.getOldMemoryAddress();
|
||||||
|
ArmatureHelper armatureHelper = dataRepository
|
||||||
|
.getHelper(ArmatureHelper.class);
|
||||||
|
|
||||||
|
// changing bones matrices so that they fit the current object (that
|
||||||
|
// is why we need a copy of a skeleton)
|
||||||
|
Matrix4f armatureObjectMatrix = objectHelper.getTransformationMatrix(armatureObject);
|
||||||
|
Matrix4f inverseMeshObjectMatrix = objectHelper.getTransformationMatrix(objectStructure).invert();
|
||||||
|
Matrix4f additionalRootBoneTransformation = inverseMeshObjectMatrix.multLocal(armatureObjectMatrix);
|
||||||
|
Bone[] bones = armatureHelper.buildBonesStructure(Long.valueOf(0L), additionalRootBoneTransformation);
|
||||||
|
|
||||||
|
// setting the bones structure inside the skeleton (thus completing
|
||||||
|
// its loading)
|
||||||
|
Skeleton skeleton = new Skeleton(bones);
|
||||||
|
dataRepository.addLoadedFeatures(armatureObject.getOldMemoryAddress(), armatureObject.getName(), armatureObject, skeleton);
|
||||||
|
|
||||||
|
String objectName = objectStructure.getName();
|
||||||
|
Set<String> animationNames = dataRepository.getBlenderKey().getAnimationNames(objectName);
|
||||||
|
if (animationNames != null && animationNames.size() > 0) {
|
||||||
|
ArrayList<BoneAnimation> animations = new ArrayList<BoneAnimation>();
|
||||||
|
List<FileBlockHeader> actionHeaders = dataRepository.getFileBlocks(Integer.valueOf(FileBlockHeader.BLOCK_AC00));
|
||||||
|
for (FileBlockHeader header : actionHeaders) {
|
||||||
|
Structure actionStructure = header.getStructure(dataRepository);
|
||||||
|
String actionName = actionStructure.getName();
|
||||||
|
if (animationNames.contains(actionName)) {
|
||||||
|
int[] animationFrames = dataRepository.getBlenderKey().getAnimationFrames(objectName, actionName);
|
||||||
|
int fps = dataRepository.getBlenderKey().getFps();
|
||||||
|
float start = (float) animationFrames[0] / (float) fps;
|
||||||
|
float stop = (float) animationFrames[1] / (float) fps;
|
||||||
|
BoneAnimation boneAnimation = new BoneAnimation(actionName, stop - start);
|
||||||
|
boneAnimation.setTracks(armatureHelper.getTracks(actionStructure, dataRepository, objectName, actionName));
|
||||||
|
animations.add(boneAnimation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jmeModifierRepresentation = new AnimData(new Skeleton(bones), animations);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Node apply(Node node, DataRepository dataRepository) {
|
||||||
|
if(jmeModifierRepresentation == null) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
AnimData ad = (AnimData) jmeModifierRepresentation;
|
||||||
|
ArrayList<BoneAnimation> animList = ad.anims;
|
||||||
|
Long modifierArmatureObject = (Long) additionalData;
|
||||||
|
if (animList != null && animList.size() > 0) {
|
||||||
|
List<Constraint> constraints = dataRepository.getConstraints(modifierArmatureObject);
|
||||||
|
HashMap<String, BoneAnimation> anims = new HashMap<String, BoneAnimation>();
|
||||||
|
for (int i = 0; i < animList.size(); ++i) {
|
||||||
|
BoneAnimation boneAnimation = animList.get(i).clone();
|
||||||
|
|
||||||
|
// baking constraints into animations
|
||||||
|
if (constraints != null && constraints.size() > 0) {
|
||||||
|
for (Constraint constraint : constraints) {
|
||||||
|
constraint.affectAnimation(ad.skeleton, boneAnimation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
anims.put(boneAnimation.getName(), boneAnimation);
|
||||||
|
}
|
||||||
|
|
||||||
|
// getting meshes
|
||||||
|
Mesh[] meshes = null;
|
||||||
|
List<Mesh> meshesList = new ArrayList<Mesh>();
|
||||||
|
List<Spatial> children = node.getChildren();
|
||||||
|
for (Spatial child : children) {
|
||||||
|
if (child instanceof Geometry) {
|
||||||
|
meshesList.add(((Geometry) child).getMesh());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (meshesList.size() > 0) {
|
||||||
|
meshes = meshesList.toArray(new Mesh[meshesList.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// applying the control to the node
|
||||||
|
SkeletonControl skeletonControl = new SkeletonControl(meshes, ad.skeleton);
|
||||||
|
AnimControl control = node.getControl(AnimControl.class);
|
||||||
|
|
||||||
|
if (control == null) {
|
||||||
|
control = new AnimControl(ad.skeleton);
|
||||||
|
} else {
|
||||||
|
// merging skeletons
|
||||||
|
Skeleton controlSkeleton = control.getSkeleton();
|
||||||
|
int boneIndexIncrease = controlSkeleton.getBoneCount();
|
||||||
|
Skeleton skeleton = this.merge(controlSkeleton, ad.skeleton);
|
||||||
|
|
||||||
|
// merging animations
|
||||||
|
HashMap<String, BoneAnimation> animations = new HashMap<String, BoneAnimation>();
|
||||||
|
for (String animationName : control.getAnimationNames()) {
|
||||||
|
animations.put(animationName,
|
||||||
|
control.getAnim(animationName));
|
||||||
|
}
|
||||||
|
for (Entry<String, BoneAnimation> animEntry : anims.entrySet()) {
|
||||||
|
BoneAnimation ba = animEntry.getValue();
|
||||||
|
for (int i = 0; i < ba.getTracks().length; ++i) {
|
||||||
|
BoneTrack bt = ba.getTracks()[i];
|
||||||
|
int newBoneIndex = bt.getTargetBoneIndex()
|
||||||
|
+ boneIndexIncrease;
|
||||||
|
ba.getTracks()[i] = new BoneTrack(newBoneIndex,
|
||||||
|
bt.getTimes(), bt.getTranslations(),
|
||||||
|
bt.getRotations(), bt.getScales());
|
||||||
|
}
|
||||||
|
animations.put(animEntry.getKey(), animEntry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
// replacing the control
|
||||||
|
node.removeControl(control);
|
||||||
|
control = new AnimControl(skeleton);
|
||||||
|
}
|
||||||
|
control.setAnimations(anims);
|
||||||
|
node.addControl(control);
|
||||||
|
node.addControl(skeletonControl);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return Modifier.ARMATURE_MODIFIER_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method merges two skeletons into one. I assume that each skeleton's
|
||||||
|
* 0-indexed bone is objectAnimationBone so only one such bone should be
|
||||||
|
* placed in the result
|
||||||
|
*
|
||||||
|
* @param s1
|
||||||
|
* first skeleton
|
||||||
|
* @param s2
|
||||||
|
* second skeleton
|
||||||
|
* @return merged skeleton
|
||||||
|
*/
|
||||||
|
protected Skeleton merge(Skeleton s1, Skeleton s2) {
|
||||||
|
List<Bone> bones = new ArrayList<Bone>(s1.getBoneCount()
|
||||||
|
+ s2.getBoneCount());
|
||||||
|
for (int i = 0; i < s1.getBoneCount(); ++i) {
|
||||||
|
bones.add(s1.getBone(i));
|
||||||
|
}
|
||||||
|
for (int i = 1; i < s2.getBoneCount(); ++i) {// ommit
|
||||||
|
// objectAnimationBone
|
||||||
|
bones.add(s2.getBone(i));
|
||||||
|
}
|
||||||
|
return new Skeleton(bones.toArray(new Bone[bones.size()]));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,244 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.modifiers;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import com.jme3.bounding.BoundingBox;
|
||||||
|
import com.jme3.bounding.BoundingSphere;
|
||||||
|
import com.jme3.bounding.BoundingVolume;
|
||||||
|
import com.jme3.math.Vector3f;
|
||||||
|
import com.jme3.scene.Geometry;
|
||||||
|
import com.jme3.scene.Mesh;
|
||||||
|
import com.jme3.scene.Node;
|
||||||
|
import com.jme3.scene.Spatial;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository.LoadedFeatureDataType;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.DynamicArray;
|
||||||
|
import com.jme3.scene.plugins.blender.file.FileBlockHeader;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Pointer;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
import com.jme3.scene.plugins.blender.objects.ObjectHelper;
|
||||||
|
import com.jme3.scene.shape.Curve;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This modifier allows to array modifier to the object.
|
||||||
|
*
|
||||||
|
* @author Marcin Roguski (Kaelthas)
|
||||||
|
*/
|
||||||
|
/*package*/ class ArrayModifier extends Modifier {
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(ArrayModifier.class.getName());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor reads array data from the modifier structure. The
|
||||||
|
* stored data is a map of parameters for array modifier. No additional data
|
||||||
|
* is loaded.
|
||||||
|
*
|
||||||
|
* @param objectStructure
|
||||||
|
* the structure of the object
|
||||||
|
* @param modifierStructure
|
||||||
|
* the structure of the modifier
|
||||||
|
* @param dataRepository
|
||||||
|
* the data repository
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* this exception is thrown when the blender file is somehow
|
||||||
|
* corrupted
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public ArrayModifier(Structure modifier, DataRepository dataRepository) throws BlenderFileException {
|
||||||
|
Map<String, Object> params = new HashMap<String, Object>();
|
||||||
|
|
||||||
|
Number fittype = (Number) modifier.getFieldValue("fit_type");
|
||||||
|
params.put("fittype", fittype);
|
||||||
|
switch (fittype.intValue()) {
|
||||||
|
case 0:// FIXED COUNT
|
||||||
|
params.put("count", modifier.getFieldValue("count"));
|
||||||
|
break;
|
||||||
|
case 1:// FIXED LENGTH
|
||||||
|
params.put("length", modifier.getFieldValue("length"));
|
||||||
|
break;
|
||||||
|
case 2:// FITCURVE
|
||||||
|
Pointer pCurveOb = (Pointer) modifier.getFieldValue("curve_ob");
|
||||||
|
float length = 0;
|
||||||
|
if (pCurveOb.isNotNull()) {
|
||||||
|
Structure curveStructure = pCurveOb.fetchData(dataRepository.getInputStream()).get(0);
|
||||||
|
ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);
|
||||||
|
Node curveObject = (Node) objectHelper.toObject(curveStructure, dataRepository);
|
||||||
|
Set<Number> referencesToCurveLengths = new HashSet<Number>(curveObject.getChildren().size());
|
||||||
|
for (Spatial spatial : curveObject.getChildren()) {
|
||||||
|
if (spatial instanceof Geometry) {
|
||||||
|
Mesh mesh = ((Geometry) spatial).getMesh();
|
||||||
|
if (mesh instanceof Curve) {
|
||||||
|
length += ((Curve) mesh).getLength();
|
||||||
|
} else {
|
||||||
|
//if bevel object has several parts then each mesh will have the same reference
|
||||||
|
//to length value (and we should use only one)
|
||||||
|
Number curveLength = spatial.getUserData("curveLength");
|
||||||
|
if (curveLength != null && !referencesToCurveLengths.contains(curveLength)) {
|
||||||
|
length += curveLength.floatValue();
|
||||||
|
referencesToCurveLengths.add(curveLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
params.put("length", Float.valueOf(length));
|
||||||
|
params.put("fittype", Integer.valueOf(1));// treat it like FIXED LENGTH
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert false : "Unknown array modifier fit type: " + fittype;
|
||||||
|
}
|
||||||
|
|
||||||
|
// offset parameters
|
||||||
|
int offsettype = ((Number) modifier.getFieldValue("offset_type")).intValue();
|
||||||
|
if ((offsettype & 0x01) != 0) {// Constant offset
|
||||||
|
DynamicArray<Number> offsetArray = (DynamicArray<Number>) modifier.getFieldValue("offset");
|
||||||
|
float[] offset = new float[]{offsetArray.get(0).floatValue(), offsetArray.get(1).floatValue(), offsetArray.get(2).floatValue()};
|
||||||
|
params.put("offset", offset);
|
||||||
|
}
|
||||||
|
if ((offsettype & 0x02) != 0) {// Relative offset
|
||||||
|
DynamicArray<Number> scaleArray = (DynamicArray<Number>) modifier.getFieldValue("scale");
|
||||||
|
float[] scale = new float[]{scaleArray.get(0).floatValue(), scaleArray.get(1).floatValue(), scaleArray.get(2).floatValue()};
|
||||||
|
params.put("scale", scale);
|
||||||
|
}
|
||||||
|
if ((offsettype & 0x04) != 0) {// Object offset
|
||||||
|
Pointer pOffsetObject = (Pointer) modifier.getFieldValue("offset_ob");
|
||||||
|
if (pOffsetObject.isNotNull()) {
|
||||||
|
params.put("offsetob", pOffsetObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// start cap and end cap
|
||||||
|
Pointer pStartCap = (Pointer) modifier.getFieldValue("start_cap");
|
||||||
|
if (pStartCap.isNotNull()) {
|
||||||
|
params.put("startcap", pStartCap);
|
||||||
|
}
|
||||||
|
Pointer pEndCap = (Pointer) modifier.getFieldValue("end_cap");
|
||||||
|
if (pEndCap.isNotNull()) {
|
||||||
|
params.put("endcap", pEndCap);
|
||||||
|
}
|
||||||
|
jmeModifierRepresentation = params;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public Node apply(Node node, DataRepository dataRepository) {
|
||||||
|
Map<String, Object> modifierData = (Map<String, Object>) jmeModifierRepresentation;
|
||||||
|
int fittype = ((Number) modifierData.get("fittype")).intValue();
|
||||||
|
float[] offset = (float[]) modifierData.get("offset");
|
||||||
|
if (offset == null) {// the node will be repeated several times in the same place
|
||||||
|
offset = new float[]{0.0f, 0.0f, 0.0f};
|
||||||
|
}
|
||||||
|
float[] scale = (float[]) modifierData.get("scale");
|
||||||
|
if (scale == null) {// the node will be repeated several times in the same place
|
||||||
|
scale = new float[]{0.0f, 0.0f, 0.0f};
|
||||||
|
} else {
|
||||||
|
// getting bounding box
|
||||||
|
node.updateModelBound();
|
||||||
|
BoundingVolume boundingVolume = node.getWorldBound();
|
||||||
|
if (boundingVolume instanceof BoundingBox) {
|
||||||
|
scale[0] *= ((BoundingBox) boundingVolume).getXExtent() * 2.0f;
|
||||||
|
scale[1] *= ((BoundingBox) boundingVolume).getYExtent() * 2.0f;
|
||||||
|
scale[2] *= ((BoundingBox) boundingVolume).getZExtent() * 2.0f;
|
||||||
|
} else if (boundingVolume instanceof BoundingSphere) {
|
||||||
|
float radius = ((BoundingSphere) boundingVolume).getRadius();
|
||||||
|
scale[0] *= radius * 2.0f;
|
||||||
|
scale[1] *= radius * 2.0f;
|
||||||
|
scale[2] *= radius * 2.0f;
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("Unknown bounding volume type: " + boundingVolume.getClass().getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// adding object's offset
|
||||||
|
float[] objectOffset = new float[]{0.0f, 0.0f, 0.0f};
|
||||||
|
Pointer pOffsetObject = (Pointer) modifierData.get("offsetob");
|
||||||
|
if (pOffsetObject != null) {
|
||||||
|
FileBlockHeader offsetObjectBlock = dataRepository.getFileBlock(pOffsetObject.getOldMemoryAddress());
|
||||||
|
ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);
|
||||||
|
try {// we take the structure in case the object was not yet loaded
|
||||||
|
Structure offsetStructure = offsetObjectBlock.getStructure(dataRepository);
|
||||||
|
Vector3f translation = objectHelper.getTransformation(offsetStructure, dataRepository).getTranslation();
|
||||||
|
objectOffset[0] = translation.x;
|
||||||
|
objectOffset[1] = translation.y;
|
||||||
|
objectOffset[2] = translation.z;
|
||||||
|
} catch (BlenderFileException e) {
|
||||||
|
LOGGER.log(Level.WARNING, "Problems in blender file structure! Object offset cannot be applied! The problem: {0}", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getting start and end caps
|
||||||
|
Node[] caps = new Node[]{null, null};
|
||||||
|
Pointer[] pCaps = new Pointer[]{(Pointer) modifierData.get("startcap"), (Pointer) modifierData.get("endcap")};
|
||||||
|
for (int i = 0; i < pCaps.length; ++i) {
|
||||||
|
if (pCaps[i] != null) {
|
||||||
|
caps[i] = (Node) dataRepository.getLoadedFeature(pCaps[i].getOldMemoryAddress(), LoadedFeatureDataType.LOADED_FEATURE);
|
||||||
|
if (caps[i] != null) {
|
||||||
|
caps[i] = (Node) caps[i].clone();
|
||||||
|
} else {
|
||||||
|
FileBlockHeader capBlock = dataRepository.getFileBlock(pOffsetObject.getOldMemoryAddress());
|
||||||
|
try {// we take the structure in case the object was not yet loaded
|
||||||
|
Structure capStructure = capBlock.getStructure(dataRepository);
|
||||||
|
ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);
|
||||||
|
caps[i] = (Node) objectHelper.toObject(capStructure, dataRepository);
|
||||||
|
if (caps[i] == null) {
|
||||||
|
LOGGER.log(Level.WARNING, "Cap object ''{0}'' couldn''t be loaded!", capStructure.getName());
|
||||||
|
}
|
||||||
|
} catch (BlenderFileException e) {
|
||||||
|
LOGGER.log(Level.WARNING, "Problems in blender file structure! Cap object cannot be applied! The problem: {0}", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3f translationVector = new Vector3f(offset[0] + scale[0] + objectOffset[0], offset[1] + scale[1] + objectOffset[1], offset[2] + scale[2] + objectOffset[2]);
|
||||||
|
|
||||||
|
// getting/calculating repeats amount
|
||||||
|
int count = 0;
|
||||||
|
if (fittype == 0) {// Fixed count
|
||||||
|
count = ((Number) modifierData.get("count")).intValue() - 1;
|
||||||
|
} else if (fittype == 1) {// Fixed length
|
||||||
|
float length = ((Number) modifierData.get("length")).floatValue();
|
||||||
|
if (translationVector.length() > 0.0f) {
|
||||||
|
count = (int) (length / translationVector.length()) - 1;
|
||||||
|
}
|
||||||
|
} else if (fittype == 2) {// Fit curve
|
||||||
|
throw new IllegalStateException("Fit curve should be transformed to Fixed Length array type!");
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("Unknown fit type: " + fittype);
|
||||||
|
}
|
||||||
|
|
||||||
|
// adding translated nodes and caps
|
||||||
|
if (count > 0) {
|
||||||
|
Node[] arrayNodes = new Node[count];
|
||||||
|
Vector3f newTranslation = new Vector3f();
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
newTranslation.addLocal(translationVector);
|
||||||
|
Node nodeClone = (Node) node.clone();
|
||||||
|
nodeClone.setLocalTranslation(newTranslation);
|
||||||
|
arrayNodes[i] = nodeClone;
|
||||||
|
}
|
||||||
|
for (Node nodeClone : arrayNodes) {
|
||||||
|
node.attachChild(nodeClone);
|
||||||
|
}
|
||||||
|
if (caps[0] != null) {
|
||||||
|
caps[0].getLocalTranslation().set(node.getLocalTranslation()).subtractLocal(translationVector);
|
||||||
|
node.attachChild(caps[0]);
|
||||||
|
}
|
||||||
|
if (caps[1] != null) {
|
||||||
|
caps[1].getLocalTranslation().set(newTranslation).addLocal(translationVector);
|
||||||
|
node.attachChild(caps[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return ARRAY_MODIFIER_DATA;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,170 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.modifiers;
|
||||||
|
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
import java.nio.IntBuffer;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import com.jme3.math.Vector3f;
|
||||||
|
import com.jme3.scene.Geometry;
|
||||||
|
import com.jme3.scene.Mesh;
|
||||||
|
import com.jme3.scene.Node;
|
||||||
|
import com.jme3.scene.Spatial;
|
||||||
|
import com.jme3.scene.VertexBuffer.Type;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Pointer;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
import com.jme3.scene.plugins.blender.objects.ObjectHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This modifier allows to array modifier to the object.
|
||||||
|
*
|
||||||
|
* @author Marcin Roguski (Kaelthas)
|
||||||
|
*/
|
||||||
|
/*package*/ class MirrorModifier extends Modifier {
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(MirrorModifier.class.getName());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor reads mirror data from the modifier structure. The
|
||||||
|
* stored data is a map of parameters for mirror modifier. No additional data
|
||||||
|
* is loaded.
|
||||||
|
* When the modifier is applied it is necessary to get the newly created node.
|
||||||
|
*
|
||||||
|
* @param objectStructure
|
||||||
|
* the structure of the object
|
||||||
|
* @param modifierStructure
|
||||||
|
* the structure of the modifier
|
||||||
|
* @param dataRepository
|
||||||
|
* the data repository
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* this exception is thrown when the blender file is somehow
|
||||||
|
* corrupted
|
||||||
|
*/
|
||||||
|
public MirrorModifier(Structure modifier, DataRepository dataRepository) {
|
||||||
|
Map<String, Object> params = new HashMap<String, Object>();
|
||||||
|
|
||||||
|
params.put("flag", modifier.getFieldValue("flag"));
|
||||||
|
params.put("tolerance", modifier.getFieldValue("tolerance"));
|
||||||
|
Pointer pMirrorOb = (Pointer) modifier.getFieldValue("mirror_ob");
|
||||||
|
if (pMirrorOb.isNotNull()) {
|
||||||
|
params.put("mirrorob", pMirrorOb);
|
||||||
|
}
|
||||||
|
jmeModifierRepresentation = params;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public Node apply(Node node, DataRepository dataRepository) {
|
||||||
|
Map<String, Object> modifierData = (Map<String, Object>) jmeModifierRepresentation;
|
||||||
|
int flag = ((Number) modifierData.get("flag")).intValue();
|
||||||
|
float[] mirrorFactor = new float[]{
|
||||||
|
(flag & 0x08) != 0 ? -1.0f : 1.0f,
|
||||||
|
(flag & 0x10) != 0 ? -1.0f : 1.0f,
|
||||||
|
(flag & 0x20) != 0 ? -1.0f : 1.0f
|
||||||
|
};
|
||||||
|
float[] center = new float[]{0.0f, 0.0f, 0.0f};
|
||||||
|
Pointer pObject = (Pointer) modifierData.get("mirrorob");
|
||||||
|
if (pObject != null) {
|
||||||
|
Structure objectStructure;
|
||||||
|
try {
|
||||||
|
objectStructure = pObject.fetchData(dataRepository.getInputStream()).get(0);
|
||||||
|
ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);
|
||||||
|
Node object = (Node) objectHelper.toObject(objectStructure, dataRepository);
|
||||||
|
if (object != null) {
|
||||||
|
Vector3f translation = object.getWorldTranslation();
|
||||||
|
center[0] = translation.x;
|
||||||
|
center[1] = translation.y;
|
||||||
|
center[2] = translation.z;
|
||||||
|
}
|
||||||
|
} catch (BlenderFileException e) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Cannot load mirror''s reference object. Cause: {0}", e.getLocalizedMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
float tolerance = ((Number) modifierData.get("tolerance")).floatValue();
|
||||||
|
boolean mirrorU = (flag & 0x01) != 0;
|
||||||
|
boolean mirrorV = (flag & 0x02) != 0;
|
||||||
|
// boolean mirrorVGroup = (flag & 0x20) != 0;
|
||||||
|
|
||||||
|
List<Geometry> geometriesToAdd = new ArrayList<Geometry>();
|
||||||
|
for (int mirrorIndex = 0; mirrorIndex < 3; ++mirrorIndex) {
|
||||||
|
if (mirrorFactor[mirrorIndex] == -1.0f) {
|
||||||
|
for (Spatial spatial : node.getChildren()) {
|
||||||
|
if (spatial instanceof Geometry) {
|
||||||
|
Mesh mesh = ((Geometry) spatial).getMesh();
|
||||||
|
Mesh clone = mesh.deepClone();
|
||||||
|
|
||||||
|
// getting buffers
|
||||||
|
FloatBuffer position = mesh.getFloatBuffer(Type.Position);
|
||||||
|
FloatBuffer bindPosePosition = mesh.getFloatBuffer(Type.BindPosePosition);
|
||||||
|
|
||||||
|
FloatBuffer clonePosition = clone.getFloatBuffer(Type.Position);
|
||||||
|
FloatBuffer cloneBindPosePosition = clone.getFloatBuffer(Type.BindPosePosition);
|
||||||
|
FloatBuffer cloneNormals = clone.getFloatBuffer(Type.Normal);
|
||||||
|
FloatBuffer cloneBindPoseNormals = clone.getFloatBuffer(Type.BindPoseNormal);
|
||||||
|
IntBuffer cloneIndexes = (IntBuffer) clone.getBuffer(Type.Index).getData();
|
||||||
|
|
||||||
|
// modyfying data
|
||||||
|
for (int i = mirrorIndex; i < clonePosition.limit(); i += 3) {
|
||||||
|
float value = clonePosition.get(i);
|
||||||
|
float d = center[mirrorIndex] - value;
|
||||||
|
|
||||||
|
if (Math.abs(d) <= tolerance) {
|
||||||
|
clonePosition.put(i, center[mirrorIndex]);
|
||||||
|
cloneBindPosePosition.put(i, center[mirrorIndex]);
|
||||||
|
position.put(i, center[mirrorIndex]);
|
||||||
|
bindPosePosition.put(i, center[mirrorIndex]);
|
||||||
|
} else {
|
||||||
|
clonePosition.put(i, value + 2.0f * d);
|
||||||
|
cloneBindPosePosition.put(i, value + 2.0f * d);
|
||||||
|
}
|
||||||
|
cloneNormals.put(i, -cloneNormals.get(i));
|
||||||
|
cloneBindPoseNormals.put(i, -cloneNormals.get(i));
|
||||||
|
|
||||||
|
//modifying clone indexes
|
||||||
|
int vertexIndex = (i - mirrorIndex) / 3;
|
||||||
|
if (vertexIndex % 3 == 0 && vertexIndex<cloneIndexes.limit()) {
|
||||||
|
int index = cloneIndexes.get(vertexIndex + 2);
|
||||||
|
cloneIndexes.put(vertexIndex + 2, cloneIndexes.get(vertexIndex + 1));
|
||||||
|
cloneIndexes.put(vertexIndex + 1, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mirrorU) {
|
||||||
|
FloatBuffer cloneUVs = (FloatBuffer) clone.getBuffer(Type.TexCoord).getData();
|
||||||
|
for (int i = 0; i < cloneUVs.limit(); i += 2) {
|
||||||
|
cloneUVs.put(i, 1.0f - cloneUVs.get(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mirrorV) {
|
||||||
|
FloatBuffer cloneUVs = (FloatBuffer) clone.getBuffer(Type.TexCoord).getData();
|
||||||
|
for (int i = 1; i < cloneUVs.limit(); i += 2) {
|
||||||
|
cloneUVs.put(i, 1.0f - cloneUVs.get(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Geometry geometry = new Geometry(null, clone);
|
||||||
|
geometry.setMaterial(((Geometry) spatial).getMaterial());
|
||||||
|
geometriesToAdd.add(geometry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// adding meshes to node
|
||||||
|
for (Geometry geometry : geometriesToAdd) {
|
||||||
|
node.attachChild(geometry);
|
||||||
|
}
|
||||||
|
geometriesToAdd.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return Modifier.MIRROR_MODIFIER_DATA;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.modifiers;
|
||||||
|
|
||||||
|
import com.jme3.scene.Node;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents an object's modifier. The modifier object can be varied
|
||||||
|
* and the user needs to know what is the type of it for the specified type
|
||||||
|
* name. For example "ArmatureModifierData" type specified in blender is
|
||||||
|
* represented by AnimData object from jMonkeyEngine.
|
||||||
|
*
|
||||||
|
* @author Marcin Roguski (Kaelthas)
|
||||||
|
*/
|
||||||
|
public abstract class Modifier {
|
||||||
|
|
||||||
|
public static final String ARRAY_MODIFIER_DATA = "ArrayModifierData";
|
||||||
|
public static final String ARMATURE_MODIFIER_DATA = "ArmatureModifierData";
|
||||||
|
public static final String PARTICLE_MODIFIER_DATA = "ParticleSystemModifierData";
|
||||||
|
public static final String MIRROR_MODIFIER_DATA = "MirrorModifierData";
|
||||||
|
public static final String OBJECT_ANIMATION_MODIFIER_DATA = "ObjectAnimationModifierData";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JME modifier representation object.
|
||||||
|
*/
|
||||||
|
protected Object jmeModifierRepresentation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Various additional data used by modifiers.
|
||||||
|
*/
|
||||||
|
protected Object additionalData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns JME modifier representation object.
|
||||||
|
*
|
||||||
|
* @return JME modifier representation object
|
||||||
|
*/
|
||||||
|
public Object getJmeModifierRepresentation() {
|
||||||
|
return jmeModifierRepresentation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns additional data stored in the modifier.
|
||||||
|
*
|
||||||
|
* @return the additional data stored in the modifier
|
||||||
|
*/
|
||||||
|
public Object getAdditionalData() {
|
||||||
|
return additionalData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method applies the modifier to the given node.
|
||||||
|
*
|
||||||
|
* @param node
|
||||||
|
* the node that will have modifier applied
|
||||||
|
* @param dataRepository
|
||||||
|
* the data repository
|
||||||
|
* @return the node with applied modifier
|
||||||
|
*/
|
||||||
|
public abstract Node apply(Node node, DataRepository dataRepository);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns blender's type of modifier.
|
||||||
|
*
|
||||||
|
* @return blender's type of modifier
|
||||||
|
*/
|
||||||
|
public abstract String getType();
|
||||||
|
}
|
@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2010 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package com.jme3.scene.plugins.blender.modifiers;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Pointer;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class that is used in modifiers calculations.
|
||||||
|
* @author Marcin Roguski
|
||||||
|
*/
|
||||||
|
public class ModifierHelper extends AbstractBlenderHelper {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(ModifierHelper.class.getName());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor parses the given blender version and stores the result. Some functionalities may differ in
|
||||||
|
* different blender versions.
|
||||||
|
* @param blenderVersion
|
||||||
|
* the version read from the blend file
|
||||||
|
*/
|
||||||
|
public ModifierHelper(String blenderVersion) {
|
||||||
|
super(blenderVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method reads the given object's modifiers.
|
||||||
|
* @param objectStructure
|
||||||
|
* the object structure
|
||||||
|
* @param dataRepository
|
||||||
|
* the data repository
|
||||||
|
* @param converter
|
||||||
|
* the converter object (in some cases we need to read an object first before loading the modifier)
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* this exception is thrown when the blender file is somehow corrupted
|
||||||
|
*/
|
||||||
|
public Collection<Modifier> readModifiers(Structure objectStructure, DataRepository dataRepository) throws BlenderFileException {
|
||||||
|
Collection<Modifier> result = new ArrayList<Modifier>();
|
||||||
|
Structure modifiersListBase = (Structure) objectStructure.getFieldValue("modifiers");
|
||||||
|
List<Structure> modifiers = modifiersListBase.evaluateListBase(dataRepository);
|
||||||
|
for (Structure modifierStructure : modifiers) {
|
||||||
|
Modifier modifier = null;
|
||||||
|
if (Modifier.ARRAY_MODIFIER_DATA.equals(modifierStructure.getType())) {
|
||||||
|
modifier = new ArrayModifier(modifierStructure, dataRepository);
|
||||||
|
} else if (Modifier.MIRROR_MODIFIER_DATA.equals(modifierStructure.getType())) {
|
||||||
|
modifier = new MirrorModifier(modifierStructure, dataRepository);
|
||||||
|
} else if (Modifier.ARMATURE_MODIFIER_DATA.equals(modifierStructure.getType())) {
|
||||||
|
modifier = new ArmatureModifier(objectStructure, modifierStructure, dataRepository);
|
||||||
|
} else if (Modifier.PARTICLE_MODIFIER_DATA.equals(modifierStructure.getType())) {
|
||||||
|
modifier = new ParticlesModifier(modifierStructure, dataRepository);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(modifier != null) {
|
||||||
|
result.add(modifier);
|
||||||
|
dataRepository.addModifier(objectStructure.getOldMemoryAddress(), modifier);
|
||||||
|
} else {
|
||||||
|
LOGGER.log(Level.WARNING, "Unsupported modifier type: {0}", modifierStructure.getType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//at the end read object's animation modifier
|
||||||
|
Pointer pIpo = (Pointer) objectStructure.getFieldValue("ipo");
|
||||||
|
if (pIpo.isNotNull()) {
|
||||||
|
Modifier modifier = new ObjectAnimationModifier(objectStructure, dataRepository);
|
||||||
|
result.add(modifier);
|
||||||
|
dataRepository.addModifier(objectStructure.getOldMemoryAddress(), modifier);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldBeLoaded(Structure structure, DataRepository dataRepository) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,122 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.modifiers;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.jme3.animation.Bone;
|
||||||
|
import com.jme3.animation.BoneAnimation;
|
||||||
|
import com.jme3.animation.BoneTrack;
|
||||||
|
import com.jme3.animation.Skeleton;
|
||||||
|
import com.jme3.math.Transform;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.Ipo;
|
||||||
|
import com.jme3.scene.plugins.blender.animations.IpoHelper;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.FileBlockHeader;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Pointer;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
import com.jme3.scene.plugins.blender.objects.ObjectHelper;
|
||||||
|
import com.jme3.scene.plugins.ogre.AnimData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This modifier allows to add animation to the object.
|
||||||
|
*
|
||||||
|
* @author Marcin Roguski (Kaelthas)
|
||||||
|
*/
|
||||||
|
/* package */class ObjectAnimationModifier extends ArmatureModifier {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor reads animation of the object itself (without bones) and
|
||||||
|
* stores it as an ArmatureModifierData modifier. The animation is returned
|
||||||
|
* as a modifier. It should be later applied regardless other modifiers. The
|
||||||
|
* reason for this is that object may not have modifiers added but it's
|
||||||
|
* animation should be working. The stored modifier is an anim data and
|
||||||
|
* additional data is given object's OMA.
|
||||||
|
*
|
||||||
|
* @param objectStructure
|
||||||
|
* the structure of the object
|
||||||
|
* @param dataRepository
|
||||||
|
* the data repository
|
||||||
|
* @return animation modifier is returned, it should be separately applied
|
||||||
|
* when the object is loaded
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* this exception is thrown when the blender file is somehow
|
||||||
|
* corrupted
|
||||||
|
*/
|
||||||
|
public ObjectAnimationModifier(Structure objectStructure,
|
||||||
|
DataRepository dataRepository) throws BlenderFileException {
|
||||||
|
Pointer pIpo = (Pointer) objectStructure.getFieldValue("ipo");
|
||||||
|
if (pIpo.isNotNull()) {
|
||||||
|
// check if there is an action name connected with this ipo
|
||||||
|
String objectAnimationName = null;
|
||||||
|
List<FileBlockHeader> actionBlocks = dataRepository
|
||||||
|
.getFileBlocks(Integer.valueOf(FileBlockHeader.BLOCK_AC00));
|
||||||
|
for (FileBlockHeader actionBlock : actionBlocks) {
|
||||||
|
Structure action = actionBlock.getStructure(dataRepository);
|
||||||
|
List<Structure> actionChannels = ((Structure) action
|
||||||
|
.getFieldValue("chanbase"))
|
||||||
|
.evaluateListBase(dataRepository);
|
||||||
|
if (actionChannels.size() == 1) {// object's animtion action has
|
||||||
|
// only one channel
|
||||||
|
Pointer pChannelIpo = (Pointer) actionChannels.get(0)
|
||||||
|
.getFieldValue("ipo");
|
||||||
|
if (pChannelIpo.equals(pIpo)) {
|
||||||
|
objectAnimationName = action.getName();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String objectName = objectStructure.getName();
|
||||||
|
if (objectAnimationName == null) {// set the object's animation name
|
||||||
|
// to object's name
|
||||||
|
objectAnimationName = objectName;
|
||||||
|
}
|
||||||
|
|
||||||
|
IpoHelper ipoHelper = dataRepository.getHelper(IpoHelper.class);
|
||||||
|
Structure ipoStructure = pIpo.fetchData(
|
||||||
|
dataRepository.getInputStream()).get(0);
|
||||||
|
Ipo ipo = ipoHelper.createIpo(ipoStructure, dataRepository);
|
||||||
|
int[] animationFrames = dataRepository.getBlenderKey()
|
||||||
|
.getAnimationFrames(objectName, objectAnimationName);
|
||||||
|
if (animationFrames == null) {// if the name was created here there
|
||||||
|
// are no frames set for the
|
||||||
|
// animation
|
||||||
|
animationFrames = new int[] { 1, ipo.getLastFrame() };
|
||||||
|
}
|
||||||
|
int fps = dataRepository.getBlenderKey().getFps();
|
||||||
|
float start = (float) animationFrames[0] / (float) fps;
|
||||||
|
float stop = (float) animationFrames[1] / (float) fps;
|
||||||
|
|
||||||
|
// calculating track for the only bone in this skeleton
|
||||||
|
BoneTrack[] tracks = new BoneTrack[1];
|
||||||
|
tracks[0] = ipo.calculateTrack(0, animationFrames[0],
|
||||||
|
animationFrames[1], fps);
|
||||||
|
|
||||||
|
BoneAnimation boneAnimation = new BoneAnimation(
|
||||||
|
objectAnimationName, stop - start);
|
||||||
|
boneAnimation.setTracks(tracks);
|
||||||
|
ArrayList<BoneAnimation> animations = new ArrayList<BoneAnimation>(
|
||||||
|
1);
|
||||||
|
animations.add(boneAnimation);
|
||||||
|
|
||||||
|
// preparing the object's bone
|
||||||
|
ObjectHelper objectHelper = dataRepository
|
||||||
|
.getHelper(ObjectHelper.class);
|
||||||
|
Transform t = objectHelper.getTransformation(objectStructure,
|
||||||
|
dataRepository);
|
||||||
|
Bone bone = new Bone(null);
|
||||||
|
bone.setBindTransforms(t.getTranslation(), t.getRotation(),
|
||||||
|
t.getScale());
|
||||||
|
|
||||||
|
jmeModifierRepresentation = new AnimData(new Skeleton(
|
||||||
|
new Bone[] { bone }), animations);
|
||||||
|
additionalData = objectStructure.getOldMemoryAddress();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return Modifier.OBJECT_ANIMATION_MODIFIER_DATA;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,99 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.modifiers;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.jme3.effect.ParticleEmitter;
|
||||||
|
import com.jme3.effect.shapes.EmitterMeshVertexShape;
|
||||||
|
import com.jme3.effect.shapes.EmitterShape;
|
||||||
|
import com.jme3.material.Material;
|
||||||
|
import com.jme3.scene.Geometry;
|
||||||
|
import com.jme3.scene.Mesh;
|
||||||
|
import com.jme3.scene.Node;
|
||||||
|
import com.jme3.scene.Spatial;
|
||||||
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Pointer;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
import com.jme3.scene.plugins.blender.materials.MaterialHelper;
|
||||||
|
import com.jme3.scene.plugins.blender.particles.ParticlesHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This modifier allows to add particles to the object.
|
||||||
|
*
|
||||||
|
* @author Marcin Roguski (Kaelthas)
|
||||||
|
*/
|
||||||
|
/* package */class ParticlesModifier extends Modifier {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor reads the particles system structure and stores it in
|
||||||
|
* order to apply it later to the node.
|
||||||
|
*
|
||||||
|
* @param modifier
|
||||||
|
* the structure of the modifier
|
||||||
|
* @param dataRepository
|
||||||
|
* the data repository
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* an exception is throw wneh there are problems with the
|
||||||
|
* blender file
|
||||||
|
*/
|
||||||
|
public ParticlesModifier(Structure modifier, DataRepository dataRepository)
|
||||||
|
throws BlenderFileException {
|
||||||
|
Pointer pParticleSystem = (Pointer) modifier.getFieldValue("psys");
|
||||||
|
if (pParticleSystem.isNotNull()) {
|
||||||
|
ParticlesHelper particlesHelper = dataRepository
|
||||||
|
.getHelper(ParticlesHelper.class);
|
||||||
|
Structure particleSystem = pParticleSystem.fetchData(
|
||||||
|
dataRepository.getInputStream()).get(0);
|
||||||
|
jmeModifierRepresentation = particlesHelper.toParticleEmitter(
|
||||||
|
particleSystem, dataRepository);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Node apply(Node node, DataRepository dataRepository) {
|
||||||
|
MaterialHelper materialHelper = dataRepository
|
||||||
|
.getHelper(MaterialHelper.class);
|
||||||
|
ParticleEmitter emitter = (ParticleEmitter) jmeModifierRepresentation;
|
||||||
|
emitter = emitter.clone();
|
||||||
|
|
||||||
|
// veryfying the alpha function for particles' texture
|
||||||
|
Integer alphaFunction = MaterialHelper.ALPHA_MASK_HYPERBOLE;
|
||||||
|
char nameSuffix = emitter.getName().charAt(
|
||||||
|
emitter.getName().length() - 1);
|
||||||
|
if (nameSuffix == 'B' || nameSuffix == 'N') {
|
||||||
|
alphaFunction = MaterialHelper.ALPHA_MASK_NONE;
|
||||||
|
}
|
||||||
|
// removing the type suffix from the name
|
||||||
|
emitter.setName(emitter.getName().substring(0,
|
||||||
|
emitter.getName().length() - 1));
|
||||||
|
|
||||||
|
// applying emitter shape
|
||||||
|
EmitterShape emitterShape = emitter.getShape();
|
||||||
|
List<Mesh> meshes = new ArrayList<Mesh>();
|
||||||
|
for (Spatial spatial : node.getChildren()) {
|
||||||
|
if (spatial instanceof Geometry) {
|
||||||
|
Mesh mesh = ((Geometry) spatial).getMesh();
|
||||||
|
if (mesh != null) {
|
||||||
|
meshes.add(mesh);
|
||||||
|
Material material = materialHelper.getParticlesMaterial(
|
||||||
|
((Geometry) spatial).getMaterial(), alphaFunction,
|
||||||
|
dataRepository);
|
||||||
|
emitter.setMaterial(material);// TODO: divide into several
|
||||||
|
// pieces
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (meshes.size() > 0 && emitterShape instanceof EmitterMeshVertexShape) {
|
||||||
|
((EmitterMeshVertexShape) emitterShape).setMeshes(meshes);
|
||||||
|
}
|
||||||
|
|
||||||
|
node.attachChild(emitter);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return Modifier.PARTICLE_MODIFIER_DATA;
|
||||||
|
}
|
||||||
|
}
|
@ -29,7 +29,7 @@
|
|||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
package com.jme3.scene.plugins.blender.helpers.v249;
|
package com.jme3.scene.plugins.blender.objects;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -51,15 +51,21 @@ import com.jme3.scene.Geometry;
|
|||||||
import com.jme3.scene.Node;
|
import com.jme3.scene.Node;
|
||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.scene.Spatial.CullHint;
|
import com.jme3.scene.Spatial.CullHint;
|
||||||
import com.jme3.scene.plugins.blender.data.Structure;
|
import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
|
||||||
import com.jme3.scene.plugins.blender.exception.BlenderFileException;
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
import com.jme3.scene.plugins.blender.structures.Modifier;
|
import com.jme3.scene.plugins.blender.DataRepository.LoadedFeatureDataType;
|
||||||
import com.jme3.scene.plugins.blender.structures.Properties;
|
import com.jme3.scene.plugins.blender.animations.ArmatureHelper;
|
||||||
import com.jme3.scene.plugins.blender.utils.AbstractBlenderHelper;
|
import com.jme3.scene.plugins.blender.cameras.CameraHelper;
|
||||||
import com.jme3.scene.plugins.blender.utils.DataRepository;
|
import com.jme3.scene.plugins.blender.constraints.ConstraintHelper;
|
||||||
import com.jme3.scene.plugins.blender.utils.DataRepository.LoadedFeatureDataType;
|
import com.jme3.scene.plugins.blender.curves.CurvesHelper;
|
||||||
import com.jme3.scene.plugins.blender.utils.DynamicArray;
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
import com.jme3.scene.plugins.blender.utils.Pointer;
|
import com.jme3.scene.plugins.blender.file.DynamicArray;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Pointer;
|
||||||
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
import com.jme3.scene.plugins.blender.lights.LightHelper;
|
||||||
|
import com.jme3.scene.plugins.blender.meshes.MeshHelper;
|
||||||
|
import com.jme3.scene.plugins.blender.modifiers.Modifier;
|
||||||
|
import com.jme3.scene.plugins.blender.modifiers.ModifierHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class that is used in object calculations.
|
* A class that is used in object calculations.
|
||||||
@ -136,19 +142,15 @@ public class ObjectHelper extends AbstractBlenderHelper {
|
|||||||
dataRepository.pushParent(objectStructure);
|
dataRepository.pushParent(objectStructure);
|
||||||
|
|
||||||
ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);
|
ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);
|
||||||
ModifierHelper modifierHelper = dataRepository.getHelper(ModifierHelper.class);
|
|
||||||
ArmatureHelper armatureHelper = dataRepository.getHelper(ArmatureHelper.class);
|
ArmatureHelper armatureHelper = dataRepository.getHelper(ArmatureHelper.class);
|
||||||
ConstraintHelper constraintHelper = dataRepository.getHelper(ConstraintHelper.class);
|
|
||||||
|
|
||||||
//get object data
|
//get object data
|
||||||
int type = ((Number)objectStructure.getFieldValue("type")).intValue();
|
int type = ((Number)objectStructure.getFieldValue("type")).intValue();
|
||||||
String name = objectStructure.getName();
|
String name = objectStructure.getName();
|
||||||
LOGGER.log(Level.INFO, "Loading obejct: {0}", name);
|
LOGGER.log(Level.INFO, "Loading obejct: {0}", name);
|
||||||
|
|
||||||
//reading modifiers
|
|
||||||
modifierHelper.readModifiers(objectStructure, dataRepository);
|
|
||||||
|
|
||||||
//loading constraints connected with this object
|
//loading constraints connected with this object
|
||||||
|
ConstraintHelper constraintHelper = dataRepository.getHelper(ConstraintHelper.class);
|
||||||
constraintHelper.loadConstraints(objectStructure, dataRepository);
|
constraintHelper.loadConstraints(objectStructure, dataRepository);
|
||||||
|
|
||||||
int restrictflag = ((Number)objectStructure.getFieldValue("restrictflag")).intValue();
|
int restrictflag = ((Number)objectStructure.getFieldValue("restrictflag")).intValue();
|
||||||
@ -187,10 +189,11 @@ public class ObjectHelper extends AbstractBlenderHelper {
|
|||||||
}
|
}
|
||||||
node.setLocalTransform(t);
|
node.setLocalTransform(t);
|
||||||
|
|
||||||
//applying all modifiers
|
//reading and applying all modifiers
|
||||||
List<Modifier> modifiers = dataRepository.getModifiers(objectStructure.getOldMemoryAddress(), null);
|
ModifierHelper modifierHelper = dataRepository.getHelper(ModifierHelper.class);
|
||||||
|
Collection<Modifier> modifiers = modifierHelper.readModifiers(objectStructure, dataRepository);
|
||||||
for(Modifier modifier : modifiers) {
|
for(Modifier modifier : modifiers) {
|
||||||
modifierHelper.applyModifier(node, modifier, dataRepository);
|
modifier.apply(node, dataRepository);
|
||||||
}
|
}
|
||||||
|
|
||||||
//setting the parent
|
//setting the parent
|
@ -1,4 +1,4 @@
|
|||||||
package com.jme3.scene.plugins.blender.structures;
|
package com.jme3.scene.plugins.blender.objects;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -11,12 +11,12 @@ import com.jme3.export.JmeExporter;
|
|||||||
import com.jme3.export.JmeImporter;
|
import com.jme3.export.JmeImporter;
|
||||||
import com.jme3.export.OutputCapsule;
|
import com.jme3.export.OutputCapsule;
|
||||||
import com.jme3.export.Savable;
|
import com.jme3.export.Savable;
|
||||||
import com.jme3.scene.plugins.blender.data.FileBlockHeader;
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
import com.jme3.scene.plugins.blender.data.Structure;
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
import com.jme3.scene.plugins.blender.exception.BlenderFileException;
|
import com.jme3.scene.plugins.blender.file.BlenderInputStream;
|
||||||
import com.jme3.scene.plugins.blender.utils.BlenderInputStream;
|
import com.jme3.scene.plugins.blender.file.FileBlockHeader;
|
||||||
import com.jme3.scene.plugins.blender.utils.DataRepository;
|
import com.jme3.scene.plugins.blender.file.Pointer;
|
||||||
import com.jme3.scene.plugins.blender.utils.Pointer;
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The blender object's custom properties.
|
* The blender object's custom properties.
|
@ -1,4 +1,4 @@
|
|||||||
package com.jme3.scene.plugins.blender.helpers.v249;
|
package com.jme3.scene.plugins.blender.particles;
|
||||||
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@ -11,12 +11,12 @@ import com.jme3.effect.shapes.EmitterMeshConvexHullShape;
|
|||||||
import com.jme3.effect.shapes.EmitterMeshFaceShape;
|
import com.jme3.effect.shapes.EmitterMeshFaceShape;
|
||||||
import com.jme3.effect.shapes.EmitterMeshVertexShape;
|
import com.jme3.effect.shapes.EmitterMeshVertexShape;
|
||||||
import com.jme3.math.ColorRGBA;
|
import com.jme3.math.ColorRGBA;
|
||||||
import com.jme3.scene.plugins.blender.data.Structure;
|
import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
|
||||||
import com.jme3.scene.plugins.blender.exception.BlenderFileException;
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
import com.jme3.scene.plugins.blender.utils.AbstractBlenderHelper;
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
import com.jme3.scene.plugins.blender.utils.DataRepository;
|
import com.jme3.scene.plugins.blender.file.DynamicArray;
|
||||||
import com.jme3.scene.plugins.blender.utils.DynamicArray;
|
import com.jme3.scene.plugins.blender.file.Pointer;
|
||||||
import com.jme3.scene.plugins.blender.utils.Pointer;
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
|
||||||
public class ParticlesHelper extends AbstractBlenderHelper {
|
public class ParticlesHelper extends AbstractBlenderHelper {
|
||||||
private static final Logger LOGGER = Logger.getLogger(ParticlesHelper.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(ParticlesHelper.class.getName());
|
@ -1,230 +0,0 @@
|
|||||||
package com.jme3.scene.plugins.blender.structures;
|
|
||||||
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import com.jme3.animation.Bone;
|
|
||||||
import com.jme3.animation.BoneAnimation;
|
|
||||||
import com.jme3.animation.BoneTrack;
|
|
||||||
import com.jme3.animation.Skeleton;
|
|
||||||
import com.jme3.math.Quaternion;
|
|
||||||
import com.jme3.math.Vector3f;
|
|
||||||
import com.jme3.scene.Node;
|
|
||||||
import com.jme3.scene.plugins.blender.data.Structure;
|
|
||||||
import com.jme3.scene.plugins.blender.exception.BlenderFileException;
|
|
||||||
import com.jme3.scene.plugins.blender.helpers.v249.ObjectHelper;
|
|
||||||
import com.jme3.scene.plugins.blender.structures.Constraint.Space;
|
|
||||||
import com.jme3.scene.plugins.blender.utils.DataRepository;
|
|
||||||
import com.jme3.scene.plugins.blender.utils.DataRepository.LoadedFeatureDataType;
|
|
||||||
import com.jme3.scene.plugins.blender.utils.Pointer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class is used to calculate the constraint. The following methods should be implemented: affectLocation,
|
|
||||||
* affectRotation and affectScale. This class also defines all constants required by known deriving classes.
|
|
||||||
* @author Marcin Roguski
|
|
||||||
*/
|
|
||||||
public abstract class AbstractInfluenceFunction {
|
|
||||||
|
|
||||||
protected static final Logger LOGGER = Logger.getLogger(AbstractInfluenceFunction.class.getName());
|
|
||||||
protected static final float IK_SOLVER_ERROR = 0.5f;
|
|
||||||
//DISTLIMIT
|
|
||||||
protected static final int LIMITDIST_INSIDE = 0;
|
|
||||||
protected static final int LIMITDIST_OUTSIDE = 1;
|
|
||||||
protected static final int LIMITDIST_ONSURFACE = 2;
|
|
||||||
//CONSTRAINT_TYPE_LOCLIKE
|
|
||||||
protected static final int LOCLIKE_X = 0x01;
|
|
||||||
protected static final int LOCLIKE_Y = 0x02;
|
|
||||||
protected static final int LOCLIKE_Z = 0x04;
|
|
||||||
//ROTLIKE
|
|
||||||
protected static final int ROTLIKE_X = 0x01;
|
|
||||||
protected static final int ROTLIKE_Y = 0x02;
|
|
||||||
protected static final int ROTLIKE_Z = 0x04;
|
|
||||||
protected static final int ROTLIKE_X_INVERT = 0x10;
|
|
||||||
protected static final int ROTLIKE_Y_INVERT = 0x20;
|
|
||||||
protected static final int ROTLIKE_Z_INVERT = 0x40;
|
|
||||||
protected static final int ROTLIKE_OFFSET = 0x80;
|
|
||||||
//SIZELIKE
|
|
||||||
protected static final int SIZELIKE_X = 0x01;
|
|
||||||
protected static final int SIZELIKE_Y = 0x02;
|
|
||||||
protected static final int SIZELIKE_Z = 0x04;
|
|
||||||
protected static final int SIZELIKE_OFFSET = 0x80;
|
|
||||||
|
|
||||||
/* LOCLIKE_TIP is a depreceated option... use headtail=1.0f instead */
|
|
||||||
//protected static final int LOCLIKE_TIP = 0x08;
|
|
||||||
protected static final int LOCLIKE_X_INVERT = 0x10;
|
|
||||||
protected static final int LOCLIKE_Y_INVERT = 0x20;
|
|
||||||
protected static final int LOCLIKE_Z_INVERT = 0x40;
|
|
||||||
protected static final int LOCLIKE_OFFSET = 0x80;
|
|
||||||
//LOCLIMIT, SIZELIMIT
|
|
||||||
protected static final int LIMIT_XMIN = 0x01;
|
|
||||||
protected static final int LIMIT_XMAX = 0x02;
|
|
||||||
protected static final int LIMIT_YMIN = 0x04;
|
|
||||||
protected static final int LIMIT_YMAX = 0x08;
|
|
||||||
protected static final int LIMIT_ZMIN = 0x10;
|
|
||||||
protected static final int LIMIT_ZMAX = 0x20;
|
|
||||||
//ROTLIMIT
|
|
||||||
protected static final int LIMIT_XROT = 0x01;
|
|
||||||
protected static final int LIMIT_YROT = 0x02;
|
|
||||||
protected static final int LIMIT_ZROT = 0x04;
|
|
||||||
/** The type of the constraint. */
|
|
||||||
protected ConstraintType constraintType;
|
|
||||||
/** The data repository. */
|
|
||||||
protected DataRepository dataRepository;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor.
|
|
||||||
* @param constraintType
|
|
||||||
* the type of the current constraint
|
|
||||||
* @param dataRepository
|
|
||||||
* the data repository
|
|
||||||
*/
|
|
||||||
public AbstractInfluenceFunction(ConstraintType constraintType, DataRepository dataRepository) {
|
|
||||||
this.constraintType = constraintType;
|
|
||||||
this.dataRepository = dataRepository;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method validates the constraint type. It throws an IllegalArgumentException if the constraint type of the
|
|
||||||
* given structure is invalid.
|
|
||||||
* @param constraintStructure
|
|
||||||
* the structure with constraint data
|
|
||||||
*/
|
|
||||||
protected void validateConstraintType(Structure constraintStructure) {
|
|
||||||
if (!constraintType.getClassName().equalsIgnoreCase(constraintStructure.getType())) {
|
|
||||||
throw new IllegalArgumentException("Invalud structure type (" + constraintStructure.getType() + ") for the constraint: " + constraintType.getClassName() + '!');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method affects the bone animation tracks for the given skeleton.
|
|
||||||
* @param skeleton
|
|
||||||
* the skeleton containing the affected bones by constraint
|
|
||||||
* @param boneAnimation
|
|
||||||
* the bone animation baked traces
|
|
||||||
* @param constraint
|
|
||||||
* the constraint
|
|
||||||
*/
|
|
||||||
public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns the bone traces for the bone that is affected by the given constraint.
|
|
||||||
* @param skeleton
|
|
||||||
* the skeleton containing bones
|
|
||||||
* @param boneAnimation
|
|
||||||
* the bone animation that affects the skeleton
|
|
||||||
* @param constraint
|
|
||||||
* the affecting constraint
|
|
||||||
* @return the bone track for the bone that is being affected by the constraint
|
|
||||||
*/
|
|
||||||
protected BoneTrack getBoneTrack(Skeleton skeleton, BoneAnimation boneAnimation, Constraint constraint) {
|
|
||||||
Long boneOMA = constraint.getBoneOMA();
|
|
||||||
Bone bone = (Bone) dataRepository.getLoadedFeature(boneOMA, LoadedFeatureDataType.LOADED_FEATURE);
|
|
||||||
int boneIndex = bone==null ? 0 : skeleton.getBoneIndex(bone);//bone==null may mean the object animation
|
|
||||||
if (boneIndex != -1) {
|
|
||||||
//searching for track for this bone
|
|
||||||
for (BoneTrack boneTrack : boneAnimation.getTracks()) {
|
|
||||||
if (boneTrack.getTargetBoneIndex() == boneIndex) {
|
|
||||||
return boneTrack;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns the target or subtarget object (if specified).
|
|
||||||
* @param constraint
|
|
||||||
* the constraint instance
|
|
||||||
* @return target or subtarget feature
|
|
||||||
* @throws BlenderFileException this exception is thrown if the blend file is somehow corrupted
|
|
||||||
*/
|
|
||||||
protected Object getTarget(Constraint constraint, LoadedFeatureDataType loadedFeatureDataType) throws BlenderFileException {
|
|
||||||
//load the feature through objectHelper, this way we are certain the object loads and has
|
|
||||||
//his own constraints applied to traces
|
|
||||||
ObjectHelper objectHelper = dataRepository.getHelper(ObjectHelper.class);
|
|
||||||
//always load the target first
|
|
||||||
Long targetOMA = ((Pointer) constraint.getData().getFieldValue("tar")).getOldMemoryAddress();
|
|
||||||
Structure objectStructure = dataRepository.getFileBlock(targetOMA).getStructure(dataRepository);
|
|
||||||
Object result = objectHelper.toObject(objectStructure, dataRepository);
|
|
||||||
|
|
||||||
//subtarget should be loaded alogn with target
|
|
||||||
Object subtarget = constraint.getData().getFieldValue("subtarget");
|
|
||||||
String subtargetName = subtarget==null ? null : subtarget.toString();
|
|
||||||
if (subtargetName!=null && subtargetName.length() > 0) {
|
|
||||||
result = dataRepository.getLoadedFeature(subtargetName, loadedFeatureDataType);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns target's object location.
|
|
||||||
* @param constraint
|
|
||||||
* the constraint instance
|
|
||||||
* @return target's object location
|
|
||||||
*/
|
|
||||||
protected Vector3f getTargetLocation(Constraint constraint) {
|
|
||||||
Long targetOMA = ((Pointer) constraint.getData().getFieldValue("tar")).getOldMemoryAddress();
|
|
||||||
Space targetSpace = constraint.getTargetSpace();
|
|
||||||
Node targetObject = (Node) dataRepository.getLoadedFeature(targetOMA, LoadedFeatureDataType.LOADED_FEATURE);
|
|
||||||
switch (targetSpace) {
|
|
||||||
case CONSTRAINT_SPACE_LOCAL:
|
|
||||||
return targetObject.getLocalTranslation();
|
|
||||||
case CONSTRAINT_SPACE_WORLD:
|
|
||||||
return targetObject.getWorldTranslation();
|
|
||||||
default:
|
|
||||||
throw new IllegalStateException("Invalid space type for target object: " + targetSpace.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns target's object location in the specified frame.
|
|
||||||
* @param constraint
|
|
||||||
* the constraint instance
|
|
||||||
* @param frame
|
|
||||||
* the frame number
|
|
||||||
* @return target's object location
|
|
||||||
*/
|
|
||||||
protected Vector3f getTargetLocation(Constraint constraint, int frame) {
|
|
||||||
return this.getTargetLocation(constraint);//TODO: implement getting location in a specified frame
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns target's object rotation.
|
|
||||||
* @param constraint
|
|
||||||
* the constraint instance
|
|
||||||
* @return target's object rotation
|
|
||||||
*/
|
|
||||||
protected Quaternion getTargetRotation(Constraint constraint) {
|
|
||||||
Long targetOMA = ((Pointer) constraint.getData().getFieldValue("tar")).getOldMemoryAddress();
|
|
||||||
Space targetSpace = constraint.getTargetSpace();
|
|
||||||
Node targetObject = (Node) dataRepository.getLoadedFeature(targetOMA, LoadedFeatureDataType.LOADED_FEATURE);
|
|
||||||
switch (targetSpace) {
|
|
||||||
case CONSTRAINT_SPACE_LOCAL:
|
|
||||||
return targetObject.getLocalRotation();
|
|
||||||
case CONSTRAINT_SPACE_WORLD:
|
|
||||||
return targetObject.getWorldRotation();
|
|
||||||
default:
|
|
||||||
throw new IllegalStateException("Invalid space type for target object: " + targetSpace.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns target's object scale.
|
|
||||||
* @param constraint
|
|
||||||
* the constraint instance
|
|
||||||
* @return target's object scale
|
|
||||||
*/
|
|
||||||
protected Vector3f getTargetScale(Constraint constraint) {
|
|
||||||
Long targetOMA = ((Pointer) constraint.getData().getFieldValue("tar")).getOldMemoryAddress();
|
|
||||||
Space targetSpace = constraint.getTargetSpace();
|
|
||||||
Node targetObject = (Node) dataRepository.getLoadedFeature(targetOMA, LoadedFeatureDataType.LOADED_FEATURE);
|
|
||||||
switch (targetSpace) {
|
|
||||||
case CONSTRAINT_SPACE_LOCAL:
|
|
||||||
return targetObject.getLocalScale();
|
|
||||||
case CONSTRAINT_SPACE_WORLD:
|
|
||||||
return targetObject.getWorldScale();
|
|
||||||
default:
|
|
||||||
throw new IllegalStateException("Invalid space type for target object: " + targetSpace.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,162 +0,0 @@
|
|||||||
package com.jme3.scene.plugins.blender.structures;
|
|
||||||
|
|
||||||
import com.jme3.animation.BoneAnimation;
|
|
||||||
import com.jme3.animation.Skeleton;
|
|
||||||
import com.jme3.scene.plugins.blender.data.Structure;
|
|
||||||
import com.jme3.scene.plugins.blender.exception.BlenderFileException;
|
|
||||||
import com.jme3.scene.plugins.blender.utils.DataRepository;
|
|
||||||
import com.jme3.scene.plugins.blender.utils.Pointer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The implementation of a constraint.
|
|
||||||
* @author Marcin Roguski
|
|
||||||
*/
|
|
||||||
public class Constraint {
|
|
||||||
|
|
||||||
/** The type of this constraint. */
|
|
||||||
private final ConstraintType type;
|
|
||||||
/** The name of this constraint. */
|
|
||||||
private final String name;
|
|
||||||
/** The old memory address of the constraint's owner. */
|
|
||||||
private final Long boneOMA;
|
|
||||||
private final Space ownerSpace;
|
|
||||||
private final Space targetSpace;
|
|
||||||
/** The structure with constraint's data. */
|
|
||||||
private final Structure data;
|
|
||||||
/** The ipo object defining influence. */
|
|
||||||
private final Ipo ipo;
|
|
||||||
/** The influence function of this constraint. */
|
|
||||||
private final AbstractInfluenceFunction influenceFunction;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This constructor creates the constraint instance.
|
|
||||||
* @param constraintStructure
|
|
||||||
* the constraint's structure (bConstraint clss in blender 2.49).
|
|
||||||
* @param influenceFunction
|
|
||||||
* the constraint's influence function (taken from ConstraintHelper)
|
|
||||||
* @param boneOMA
|
|
||||||
* the old memory address of the constraint owner
|
|
||||||
* @param influenceIpo
|
|
||||||
* the ipo curve of the influence factor
|
|
||||||
* @param dataRepository
|
|
||||||
* the data repository
|
|
||||||
* @throws BlenderFileException
|
|
||||||
*/
|
|
||||||
public Constraint(Structure constraintStructure, AbstractInfluenceFunction influenceFunction, Long boneOMA, Space ownerSpace, Space targetSpace, Ipo influenceIpo, DataRepository dataRepository) throws BlenderFileException {
|
|
||||||
if (influenceFunction == null) {
|
|
||||||
throw new IllegalArgumentException("Influence function is not defined!");
|
|
||||||
}
|
|
||||||
Pointer pData = (Pointer) constraintStructure.getFieldValue("data");
|
|
||||||
if (pData.isNotNull()) {
|
|
||||||
data = pData.fetchData(dataRepository.getInputStream()).get(0);
|
|
||||||
} else {
|
|
||||||
throw new BlenderFileException("The constraint has no data specified!");
|
|
||||||
}
|
|
||||||
this.boneOMA = boneOMA;
|
|
||||||
this.type = ConstraintType.valueOf(((Number) constraintStructure.getFieldValue("type")).intValue());
|
|
||||||
this.name = constraintStructure.getFieldValue("name").toString();
|
|
||||||
this.ownerSpace = ownerSpace;
|
|
||||||
this.targetSpace = targetSpace;
|
|
||||||
this.ipo = influenceIpo;
|
|
||||||
this.influenceFunction = influenceFunction;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns the name of the constraint.
|
|
||||||
* @return the name of the constraint
|
|
||||||
*/
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns the old memoty address of the bone this constraint affects.
|
|
||||||
* @return the old memory address of the bone this constraint affects
|
|
||||||
*/
|
|
||||||
public Long getBoneOMA() {
|
|
||||||
return boneOMA;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns owner's transform space.
|
|
||||||
* @return owner's transform space
|
|
||||||
*/
|
|
||||||
public Space getOwnerSpace() {
|
|
||||||
return ownerSpace;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns target's transform space.
|
|
||||||
* @return target's transform space
|
|
||||||
*/
|
|
||||||
public Space getTargetSpace() {
|
|
||||||
return targetSpace;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns the type of the constraint.
|
|
||||||
* @return the type of the constraint
|
|
||||||
*/
|
|
||||||
public ConstraintType getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns the constraint's data structure.
|
|
||||||
* @return the constraint's data structure
|
|
||||||
*/
|
|
||||||
public Structure getData() {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns the constraint's influcence curve.
|
|
||||||
* @return the constraint's influcence curve
|
|
||||||
*/
|
|
||||||
public Ipo getIpo() {
|
|
||||||
return ipo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method affects the bone animation tracks for the given skeleton.
|
|
||||||
* @param skeleton
|
|
||||||
* the skeleton containing the affected bones by constraint
|
|
||||||
* @param boneAnimation
|
|
||||||
* the bone animation baked traces
|
|
||||||
* @param constraint
|
|
||||||
* the constraint
|
|
||||||
*/
|
|
||||||
public void affectAnimation(Skeleton skeleton, BoneAnimation boneAnimation) {
|
|
||||||
influenceFunction.affectAnimation(skeleton, boneAnimation, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The space of target or owner transformation.
|
|
||||||
* @author Marcin Roguski
|
|
||||||
*/
|
|
||||||
public static enum Space {
|
|
||||||
|
|
||||||
CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_PARLOCAL, CONSTRAINT_SPACE_INVALID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns the enum instance when given the appropriate value from the blend file.
|
|
||||||
* @param c
|
|
||||||
* the blender's value of the space modifier
|
|
||||||
* @return the scape enum instance
|
|
||||||
*/
|
|
||||||
public static Space valueOf(byte c) {
|
|
||||||
switch (c) {
|
|
||||||
case 0:
|
|
||||||
return CONSTRAINT_SPACE_WORLD;
|
|
||||||
case 1:
|
|
||||||
return CONSTRAINT_SPACE_LOCAL;
|
|
||||||
case 2:
|
|
||||||
return CONSTRAINT_SPACE_POSE;
|
|
||||||
case 3:
|
|
||||||
return CONSTRAINT_SPACE_PARLOCAL;
|
|
||||||
default:
|
|
||||||
return CONSTRAINT_SPACE_INVALID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,68 +0,0 @@
|
|||||||
package com.jme3.scene.plugins.blender.structures;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class represents an object's modifier. The modifier object can be varied and the user needs to know what is
|
|
||||||
* the type of it for the specified type name. For example "ArmatureModifierData" type specified in blender is
|
|
||||||
* represented by AnimData object from jMonkeyEngine.
|
|
||||||
* @author Marcin Roguski (Kaelthas)
|
|
||||||
*/
|
|
||||||
public class Modifier {
|
|
||||||
|
|
||||||
public static final String ARRAY_MODIFIER_DATA = "ArrayModifierData";
|
|
||||||
public static final String ARMATURE_MODIFIER_DATA = "ArmatureModifierData";
|
|
||||||
public static final String PARTICLE_MODIFIER_DATA = "ParticleSystemModifierData";
|
|
||||||
public static final String MIRROR_MODIFIER_DATA = "MirrorModifierData";
|
|
||||||
public static final String OBJECT_ANIMATION_MODIFIER_DATA = "ObjectAnimationModifierData";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Blender's type of modifier.
|
|
||||||
*/
|
|
||||||
private String type;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JME modifier representation object.
|
|
||||||
*/
|
|
||||||
private Object jmeModifierRepresentation;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Various additional data used by modifiers.
|
|
||||||
*/
|
|
||||||
private Object additionalData;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor. Creates modifier object.
|
|
||||||
* @param type
|
|
||||||
* blender's type of modifier
|
|
||||||
* @param modifier
|
|
||||||
* JME modifier representation object
|
|
||||||
*/
|
|
||||||
public Modifier(String type, Object modifier, Object additionalData) {
|
|
||||||
this.type = type;
|
|
||||||
this.jmeModifierRepresentation = modifier;
|
|
||||||
this.additionalData = additionalData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns JME modifier representation object.
|
|
||||||
* @return JME modifier representation object
|
|
||||||
*/
|
|
||||||
public Object getJmeModifierRepresentation() {
|
|
||||||
return jmeModifierRepresentation;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns blender's type of modifier.
|
|
||||||
* @return blender's type of modifier
|
|
||||||
*/
|
|
||||||
public String getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns additional data stored in the modifier.
|
|
||||||
* @return the additional data stored in the modifier
|
|
||||||
*/
|
|
||||||
public Object getAdditionalData() {
|
|
||||||
return additionalData;
|
|
||||||
}
|
|
||||||
}
|
|
@ -28,7 +28,7 @@
|
|||||||
* ***** END GPL LICENSE BLOCK *****
|
* ***** END GPL LICENSE BLOCK *****
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
package com.jme3.scene.plugins.blender.helpers.v249;
|
package com.jme3.scene.plugins.blender.textures;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@ -39,24 +39,23 @@ import java.util.logging.Level;
|
|||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import com.jme3.math.FastMath;
|
import com.jme3.math.FastMath;
|
||||||
import com.jme3.scene.plugins.blender.data.Structure;
|
import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
|
||||||
import com.jme3.scene.plugins.blender.helpers.v249.TextureHelper.CBData;
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
import com.jme3.scene.plugins.blender.helpers.v249.TextureHelper.ColorBand;
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
import com.jme3.scene.plugins.blender.helpers.v249.TextureHelper.TexResult;
|
import com.jme3.scene.plugins.blender.textures.TextureHelper.CBData;
|
||||||
import com.jme3.scene.plugins.blender.utils.AbstractBlenderHelper;
|
import com.jme3.scene.plugins.blender.textures.TextureHelper.ColorBand;
|
||||||
import com.jme3.scene.plugins.blender.utils.DataRepository;
|
import com.jme3.scene.plugins.blender.textures.TextureHelper.TexResult;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Methods of this class are copied from blender 2.49 source code and modified so that they can be used in java. They
|
* This generator is responsible for creating various noises used to create
|
||||||
* are mostly NOT documented because they are not documented in blender's source code. If I find a proper description or
|
* generated textures loaded from blender.
|
||||||
* discover what they actually do and what parameters mean - I shall describe such methods :) If anyone have some hint
|
* It derives from AbstractBlenderHelper but is not stored in data repository.
|
||||||
* what these methods are doing please rite the proper javadoc documentation. These methods should be used to create
|
* It is only used by TextureHelper.
|
||||||
* generated textures.
|
|
||||||
* @author Marcin Roguski (Kaelthas)
|
* @author Marcin Roguski (Kaelthas)
|
||||||
*/
|
*/
|
||||||
public class NoiseHelper extends AbstractBlenderHelper {
|
/*package*/ class NoiseGenerator extends AbstractBlenderHelper {
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(NoiseHelper.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(NoiseGenerator.class.getName());
|
||||||
|
|
||||||
/* return value */
|
/* return value */
|
||||||
protected static final int TEX_INT = 0;
|
protected static final int TEX_INT = 0;
|
||||||
@ -137,7 +136,7 @@ public class NoiseHelper extends AbstractBlenderHelper {
|
|||||||
* @param blenderVersion
|
* @param blenderVersion
|
||||||
* the number of blender version
|
* the number of blender version
|
||||||
*/
|
*/
|
||||||
public NoiseHelper(String blenderVersion) {
|
public NoiseGenerator(String blenderVersion) {
|
||||||
super(blenderVersion);
|
super(blenderVersion);
|
||||||
this.loadConstants();
|
this.loadConstants();
|
||||||
}
|
}
|
||||||
@ -148,7 +147,7 @@ public class NoiseHelper extends AbstractBlenderHelper {
|
|||||||
* an exception will be thrown the class will not be instantiated.
|
* an exception will be thrown the class will not be instantiated.
|
||||||
*/
|
*/
|
||||||
protected void loadConstants() {
|
protected void loadConstants() {
|
||||||
InputStream is = NoiseHelper.class.getResourceAsStream("noiseconstants.dat");
|
InputStream is = NoiseGenerator.class.getResourceAsStream("noiseconstants.dat");
|
||||||
try {
|
try {
|
||||||
ObjectInputStream ois = new ObjectInputStream(is);
|
ObjectInputStream ois = new ObjectInputStream(is);
|
||||||
hashpntf = (float[]) ois.readObject();
|
hashpntf = (float[]) ois.readObject();
|
||||||
@ -332,7 +331,7 @@ public class NoiseHelper extends AbstractBlenderHelper {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
/** Distance metrics for voronoi. e parameter only used in Minkovsky. */
|
/** Distance metrics for voronoi. e parameter only used in Minkovsky. */
|
||||||
protected static Map<Integer, DistanceFunc> distanceFunctions = new HashMap<Integer, NoiseHelper.DistanceFunc>();
|
protected static Map<Integer, DistanceFunc> distanceFunctions = new HashMap<Integer, NoiseGenerator.DistanceFunc>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
// real distance
|
// real distance
|
||||||
@ -400,7 +399,7 @@ public class NoiseHelper extends AbstractBlenderHelper {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
protected static Map<Integer, MusgraveFunction> musgraveFunctions = new HashMap<Integer, NoiseHelper.MusgraveFunction>();
|
protected static Map<Integer, MusgraveFunction> musgraveFunctions = new HashMap<Integer, NoiseGenerator.MusgraveFunction>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
musgraveFunctions.put(Integer.valueOf(TEX_MFRACTAL), new MusgraveFunction() {
|
musgraveFunctions.put(Integer.valueOf(TEX_MFRACTAL), new MusgraveFunction() {
|
||||||
@ -895,7 +894,7 @@ public class NoiseHelper extends AbstractBlenderHelper {
|
|||||||
float n = 5.0f * (x + y + z);
|
float n = 5.0f * (x + y + z);
|
||||||
float mi = n + turbul * this.bliGTurbulence(noisesize, x, y, z, noisedepth, noisetype != TEX_NOISESOFT, noisebasis);
|
float mi = n + turbul * this.bliGTurbulence(noisesize, x, y, z, noisedepth, noisetype != TEX_NOISESOFT, noisebasis);
|
||||||
|
|
||||||
if (stype >= NoiseHelper.TEX_SOFT) { /* TEX_SOFT always true */
|
if (stype >= NoiseGenerator.TEX_SOFT) { /* TEX_SOFT always true */
|
||||||
mi = waveformFunctions[waveform].execute(mi);
|
mi = waveformFunctions[waveform].execute(mi);
|
||||||
if (stype == TEX_SHARP) {
|
if (stype == TEX_SHARP) {
|
||||||
mi = (float) Math.sqrt(mi);
|
mi = (float) Math.sqrt(mi);
|
@ -29,7 +29,7 @@
|
|||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
package com.jme3.scene.plugins.blender.helpers.v249;
|
package com.jme3.scene.plugins.blender.textures;
|
||||||
|
|
||||||
import java.awt.color.ColorSpace;
|
import java.awt.color.ColorSpace;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
@ -52,16 +52,16 @@ import com.jme3.asset.GeneratedTextureKey;
|
|||||||
import com.jme3.asset.TextureKey;
|
import com.jme3.asset.TextureKey;
|
||||||
import com.jme3.math.FastMath;
|
import com.jme3.math.FastMath;
|
||||||
import com.jme3.math.Vector3f;
|
import com.jme3.math.Vector3f;
|
||||||
import com.jme3.scene.plugins.blender.data.FileBlockHeader;
|
import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
|
||||||
import com.jme3.scene.plugins.blender.data.Structure;
|
import com.jme3.scene.plugins.blender.DataRepository;
|
||||||
import com.jme3.scene.plugins.blender.exception.BlenderFileException;
|
import com.jme3.scene.plugins.blender.DataRepository.LoadedFeatureDataType;
|
||||||
import com.jme3.scene.plugins.blender.helpers.NoiseHelper;
|
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
|
||||||
import com.jme3.scene.plugins.blender.utils.AbstractBlenderHelper;
|
import com.jme3.scene.plugins.blender.file.BlenderInputStream;
|
||||||
import com.jme3.scene.plugins.blender.utils.BlenderInputStream;
|
import com.jme3.scene.plugins.blender.file.DynamicArray;
|
||||||
import com.jme3.scene.plugins.blender.utils.DataRepository;
|
import com.jme3.scene.plugins.blender.file.FileBlockHeader;
|
||||||
import com.jme3.scene.plugins.blender.utils.DataRepository.LoadedFeatureDataType;
|
import com.jme3.scene.plugins.blender.file.Pointer;
|
||||||
import com.jme3.scene.plugins.blender.utils.DynamicArray;
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
import com.jme3.scene.plugins.blender.utils.Pointer;
|
import com.jme3.scene.plugins.blender.materials.MaterialHelper;
|
||||||
import com.jme3.texture.Image;
|
import com.jme3.texture.Image;
|
||||||
import com.jme3.texture.Image.Format;
|
import com.jme3.texture.Image.Format;
|
||||||
import com.jme3.texture.Texture;
|
import com.jme3.texture.Texture;
|
||||||
@ -95,7 +95,9 @@ public class TextureHelper extends AbstractBlenderHelper {
|
|||||||
public static final int TEX_MUSGRAVE = 11;
|
public static final int TEX_MUSGRAVE = 11;
|
||||||
public static final int TEX_VORONOI = 12;
|
public static final int TEX_VORONOI = 12;
|
||||||
public static final int TEX_DISTNOISE = 13;
|
public static final int TEX_DISTNOISE = 13;
|
||||||
|
public static final int TEX_POINTDENSITY = 14;//v. 25+
|
||||||
|
public static final int TEX_VOXELDATA = 15;//v. 25+
|
||||||
|
|
||||||
// mapto
|
// mapto
|
||||||
public static final int MAP_COL = 1;
|
public static final int MAP_COL = 1;
|
||||||
public static final int MAP_NORM = 2;
|
public static final int MAP_NORM = 2;
|
||||||
@ -149,6 +151,8 @@ public class TextureHelper extends AbstractBlenderHelper {
|
|||||||
public static final int MA_RAMP_VAL = 14;
|
public static final int MA_RAMP_VAL = 14;
|
||||||
public static final int MA_RAMP_COLOR = 15;
|
public static final int MA_RAMP_COLOR = 15;
|
||||||
|
|
||||||
|
protected NoiseGenerator noiseHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This constructor parses the given blender version and stores the result. Some functionalities may differ in different blender
|
* This constructor parses the given blender version and stores the result. Some functionalities may differ in different blender
|
||||||
* versions.
|
* versions.
|
||||||
@ -158,6 +162,7 @@ public class TextureHelper extends AbstractBlenderHelper {
|
|||||||
*/
|
*/
|
||||||
public TextureHelper(String blenderVersion) {
|
public TextureHelper(String blenderVersion) {
|
||||||
super(blenderVersion);
|
super(blenderVersion);
|
||||||
|
noiseHelper = new NoiseGenerator(blenderVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -221,6 +226,12 @@ public class TextureHelper extends AbstractBlenderHelper {
|
|||||||
break;
|
break;
|
||||||
case TEX_NONE:// No texture, do nothing
|
case TEX_NONE:// No texture, do nothing
|
||||||
break;
|
break;
|
||||||
|
case TEX_POINTDENSITY:
|
||||||
|
LOGGER.warning("Point density texture loading currently not supported!");
|
||||||
|
break;
|
||||||
|
case TEX_VOXELDATA:
|
||||||
|
LOGGER.warning("Voxel data texture loading currently not supported!");
|
||||||
|
break;
|
||||||
case TEX_PLUGIN:
|
case TEX_PLUGIN:
|
||||||
case TEX_ENVMAP:// TODO: implement envmap texture
|
case TEX_ENVMAP:// TODO: implement envmap texture
|
||||||
LOGGER.log(Level.WARNING, "Unsupported texture type: {0} for texture: {1}", new Object[]{type, tex.getName()});
|
LOGGER.log(Level.WARNING, "Unsupported texture type: {0} for texture: {1}", new Object[]{type, tex.getName()});
|
||||||
@ -253,7 +264,6 @@ public class TextureHelper extends AbstractBlenderHelper {
|
|||||||
*/
|
*/
|
||||||
protected Texture clouds(Structure tex, int width, int height, DataRepository dataRepository) {
|
protected Texture clouds(Structure tex, int width, int height, DataRepository dataRepository) {
|
||||||
// preparing the proper data
|
// preparing the proper data
|
||||||
NoiseHelper noiseHelper = dataRepository.getHelper(NoiseHelper.class);
|
|
||||||
float wDelta = 1.0f / width, hDelta = 1.0f / height;
|
float wDelta = 1.0f / width, hDelta = 1.0f / height;
|
||||||
float[] texvec = new float[] { 0, 0, 0 };
|
float[] texvec = new float[] { 0, 0, 0 };
|
||||||
TexResult texres = new TexResult();
|
TexResult texres = new TexResult();
|
||||||
@ -265,14 +275,14 @@ public class TextureHelper extends AbstractBlenderHelper {
|
|||||||
int noiseType = ((Number) tex.getFieldValue("noisetype")).intValue();
|
int noiseType = ((Number) tex.getFieldValue("noisetype")).intValue();
|
||||||
float contrast = ((Number) tex.getFieldValue("contrast")).floatValue();
|
float contrast = ((Number) tex.getFieldValue("contrast")).floatValue();
|
||||||
float bright = ((Number) tex.getFieldValue("bright")).floatValue();
|
float bright = ((Number) tex.getFieldValue("bright")).floatValue();
|
||||||
boolean isHard = noiseType != com.jme3.scene.plugins.blender.helpers.v249.NoiseHelper.TEX_NOISESOFT;
|
boolean isHard = noiseType != NoiseGenerator.TEX_NOISESOFT;
|
||||||
int sType = ((Number) tex.getFieldValue("stype")).intValue();
|
int sType = ((Number) tex.getFieldValue("stype")).intValue();
|
||||||
int halfW = width, halfH = height;
|
int halfW = width, halfH = height;
|
||||||
width <<= 1;
|
width <<= 1;
|
||||||
height <<= 1;
|
height <<= 1;
|
||||||
ColorBand colorBand = this.readColorband(tex, dataRepository);
|
ColorBand colorBand = this.readColorband(tex, dataRepository);
|
||||||
Format format = sType == com.jme3.scene.plugins.blender.helpers.v249.NoiseHelper.TEX_COLOR || colorBand != null ? Format.RGB8 : Format.Luminance8;
|
Format format = sType == NoiseGenerator.TEX_COLOR || colorBand != null ? Format.RGB8 : Format.Luminance8;
|
||||||
int bytesPerPixel = sType == com.jme3.scene.plugins.blender.helpers.v249.NoiseHelper.TEX_COLOR || colorBand != null ? 3 : 1;
|
int bytesPerPixel = sType == NoiseGenerator.TEX_COLOR || colorBand != null ? 3 : 1;
|
||||||
|
|
||||||
ByteBuffer data = BufferUtils.createByteBuffer(width * height * bytesPerPixel);
|
ByteBuffer data = BufferUtils.createByteBuffer(width * height * bytesPerPixel);
|
||||||
for (int i = -halfW; i < halfW; ++i) {
|
for (int i = -halfW; i < halfW; ++i) {
|
||||||
@ -295,7 +305,7 @@ public class TextureHelper extends AbstractBlenderHelper {
|
|||||||
data.put((byte) (texres.tr * 255.0f));
|
data.put((byte) (texres.tr * 255.0f));
|
||||||
data.put((byte) (texres.tg * 255.0f));
|
data.put((byte) (texres.tg * 255.0f));
|
||||||
data.put((byte) (texres.tb * 255.0f));
|
data.put((byte) (texres.tb * 255.0f));
|
||||||
} else if (sType == com.jme3.scene.plugins.blender.helpers.v249.NoiseHelper.TEX_COLOR) {
|
} else if (sType == NoiseGenerator.TEX_COLOR) {
|
||||||
// in this case, int. value should really be computed from color,
|
// in this case, int. value should really be computed from color,
|
||||||
// and bumpnormal from that, would be too slow, looks ok as is
|
// and bumpnormal from that, would be too slow, looks ok as is
|
||||||
texres.tr = texres.tin;
|
texres.tr = texres.tin;
|
||||||
@ -329,7 +339,6 @@ public class TextureHelper extends AbstractBlenderHelper {
|
|||||||
*/
|
*/
|
||||||
protected Texture wood(Structure tex, int width, int height, DataRepository dataRepository) {
|
protected Texture wood(Structure tex, int width, int height, DataRepository dataRepository) {
|
||||||
// preparing the proper data
|
// preparing the proper data
|
||||||
NoiseHelper noiseHelper = dataRepository.getHelper(NoiseHelper.class);
|
|
||||||
float contrast = ((Number) tex.getFieldValue("contrast")).floatValue();
|
float contrast = ((Number) tex.getFieldValue("contrast")).floatValue();
|
||||||
float bright = ((Number) tex.getFieldValue("bright")).floatValue();
|
float bright = ((Number) tex.getFieldValue("bright")).floatValue();
|
||||||
float nabla = ((Number) tex.getFieldValue("nabla")).floatValue();
|
float nabla = ((Number) tex.getFieldValue("nabla")).floatValue();
|
||||||
@ -386,7 +395,6 @@ public class TextureHelper extends AbstractBlenderHelper {
|
|||||||
*/
|
*/
|
||||||
protected Texture marble(Structure tex, int width, int height, DataRepository dataRepository) {
|
protected Texture marble(Structure tex, int width, int height, DataRepository dataRepository) {
|
||||||
// preparing the proper data
|
// preparing the proper data
|
||||||
NoiseHelper noiseHelper = dataRepository.getHelper(NoiseHelper.class);
|
|
||||||
float contrast = ((Number) tex.getFieldValue("contrast")).floatValue();
|
float contrast = ((Number) tex.getFieldValue("contrast")).floatValue();
|
||||||
float bright = ((Number) tex.getFieldValue("bright")).floatValue();
|
float bright = ((Number) tex.getFieldValue("bright")).floatValue();
|
||||||
float nabla = ((Number) tex.getFieldValue("nabla")).floatValue();
|
float nabla = ((Number) tex.getFieldValue("nabla")).floatValue();
|
||||||
@ -442,7 +450,6 @@ public class TextureHelper extends AbstractBlenderHelper {
|
|||||||
* @return the generated texture
|
* @return the generated texture
|
||||||
*/
|
*/
|
||||||
protected Texture magic(Structure tex, int width, int height, DataRepository dataRepository) {
|
protected Texture magic(Structure tex, int width, int height, DataRepository dataRepository) {
|
||||||
NoiseHelper noiseHelper = dataRepository.getHelper(NoiseHelper.class);
|
|
||||||
float x, y, z, turb;
|
float x, y, z, turb;
|
||||||
int noisedepth = ((Number) tex.getFieldValue("noisedepth")).intValue();
|
int noisedepth = ((Number) tex.getFieldValue("noisedepth")).intValue();
|
||||||
float turbul = ((Number) tex.getFieldValue("turbul")).floatValue() / 5.0f;
|
float turbul = ((Number) tex.getFieldValue("turbul")).floatValue() / 5.0f;
|
||||||
@ -536,7 +543,6 @@ public class TextureHelper extends AbstractBlenderHelper {
|
|||||||
* @return the generated texture
|
* @return the generated texture
|
||||||
*/
|
*/
|
||||||
protected Texture blend(Structure tex, int width, int height, DataRepository dataRepository) {
|
protected Texture blend(Structure tex, int width, int height, DataRepository dataRepository) {
|
||||||
NoiseHelper noiseHelper = dataRepository.getHelper(NoiseHelper.class);
|
|
||||||
int flag = ((Number) tex.getFieldValue("flag")).intValue();
|
int flag = ((Number) tex.getFieldValue("flag")).intValue();
|
||||||
int stype = ((Number) tex.getFieldValue("stype")).intValue();
|
int stype = ((Number) tex.getFieldValue("stype")).intValue();
|
||||||
float contrast = ((Number) tex.getFieldValue("contrast")).floatValue();
|
float contrast = ((Number) tex.getFieldValue("contrast")).floatValue();
|
||||||
@ -556,7 +562,7 @@ public class TextureHelper extends AbstractBlenderHelper {
|
|||||||
texvec[0] = wDelta * i;
|
texvec[0] = wDelta * i;
|
||||||
for (int j = -halfH; j < halfH; ++j) {
|
for (int j = -halfH; j < halfH; ++j) {
|
||||||
texvec[1] = hDelta * j;
|
texvec[1] = hDelta * j;
|
||||||
if ((flag & com.jme3.scene.plugins.blender.helpers.v249.NoiseHelper.TEX_FLIPBLEND) != 0) {
|
if ((flag & NoiseGenerator.TEX_FLIPBLEND) != 0) {
|
||||||
x = texvec[1];
|
x = texvec[1];
|
||||||
y = texvec[0];
|
y = texvec[0];
|
||||||
} else {
|
} else {
|
||||||
@ -564,16 +570,16 @@ public class TextureHelper extends AbstractBlenderHelper {
|
|||||||
y = texvec[1];
|
y = texvec[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stype == com.jme3.scene.plugins.blender.helpers.v249.NoiseHelper.TEX_LIN) { /* lin */
|
if (stype == NoiseGenerator.TEX_LIN) { /* lin */
|
||||||
texres.tin = (1.0f + x) / 2.0f;
|
texres.tin = (1.0f + x) / 2.0f;
|
||||||
} else if (stype == com.jme3.scene.plugins.blender.helpers.v249.NoiseHelper.TEX_QUAD) { /* quad */
|
} else if (stype == NoiseGenerator.TEX_QUAD) { /* quad */
|
||||||
texres.tin = (1.0f + x) / 2.0f;
|
texres.tin = (1.0f + x) / 2.0f;
|
||||||
if (texres.tin < 0.0f) {
|
if (texres.tin < 0.0f) {
|
||||||
texres.tin = 0.0f;
|
texres.tin = 0.0f;
|
||||||
} else {
|
} else {
|
||||||
texres.tin *= texres.tin;
|
texres.tin *= texres.tin;
|
||||||
}
|
}
|
||||||
} else if (stype == com.jme3.scene.plugins.blender.helpers.v249.NoiseHelper.TEX_EASE) { /* ease */
|
} else if (stype == NoiseGenerator.TEX_EASE) { /* ease */
|
||||||
texres.tin = (1.0f + x) / 2.0f;
|
texres.tin = (1.0f + x) / 2.0f;
|
||||||
if (texres.tin <= 0.0f) {
|
if (texres.tin <= 0.0f) {
|
||||||
texres.tin = 0.0f;
|
texres.tin = 0.0f;
|
||||||
@ -583,16 +589,16 @@ public class TextureHelper extends AbstractBlenderHelper {
|
|||||||
t = texres.tin * texres.tin;
|
t = texres.tin * texres.tin;
|
||||||
texres.tin = 3.0f * t - 2.0f * t * texres.tin;
|
texres.tin = 3.0f * t - 2.0f * t * texres.tin;
|
||||||
}
|
}
|
||||||
} else if (stype == com.jme3.scene.plugins.blender.helpers.v249.NoiseHelper.TEX_DIAG) { /* diag */
|
} else if (stype == NoiseGenerator.TEX_DIAG) { /* diag */
|
||||||
texres.tin = (2.0f + x + y) / 4.0f;
|
texres.tin = (2.0f + x + y) / 4.0f;
|
||||||
} else if (stype == com.jme3.scene.plugins.blender.helpers.v249.NoiseHelper.TEX_RAD) { /* radial */
|
} else if (stype == NoiseGenerator.TEX_RAD) { /* radial */
|
||||||
texres.tin = (float) Math.atan2(y, x) / FastMath.TWO_PI + 0.5f;
|
texres.tin = (float) Math.atan2(y, x) / FastMath.TWO_PI + 0.5f;
|
||||||
} else { /* sphere TEX_SPHERE */
|
} else { /* sphere TEX_SPHERE */
|
||||||
texres.tin = 1.0f - (float) Math.sqrt(x * x + y * y + texvec[2] * texvec[2]);
|
texres.tin = 1.0f - (float) Math.sqrt(x * x + y * y + texvec[2] * texvec[2]);
|
||||||
if (texres.tin < 0.0f) {
|
if (texres.tin < 0.0f) {
|
||||||
texres.tin = 0.0f;
|
texres.tin = 0.0f;
|
||||||
}
|
}
|
||||||
if (stype == com.jme3.scene.plugins.blender.helpers.v249.NoiseHelper.TEX_HALO) {
|
if (stype == NoiseGenerator.TEX_HALO) {
|
||||||
texres.tin *= texres.tin;
|
texres.tin *= texres.tin;
|
||||||
} /* halo */
|
} /* halo */
|
||||||
}
|
}
|
||||||
@ -629,10 +635,9 @@ public class TextureHelper extends AbstractBlenderHelper {
|
|||||||
int noisebasis = ((Number) tex.getFieldValue("noisebasis")).intValue();
|
int noisebasis = ((Number) tex.getFieldValue("noisebasis")).intValue();
|
||||||
int noisetype = ((Number) tex.getFieldValue("noisetype")).intValue();
|
int noisetype = ((Number) tex.getFieldValue("noisetype")).intValue();
|
||||||
float turbul = ((Number) tex.getFieldValue("turbul")).floatValue();
|
float turbul = ((Number) tex.getFieldValue("turbul")).floatValue();
|
||||||
boolean isHard = noisetype != com.jme3.scene.plugins.blender.helpers.v249.NoiseHelper.TEX_NOISESOFT;
|
boolean isHard = noisetype != NoiseGenerator.TEX_NOISESOFT;
|
||||||
int stype = ((Number) tex.getFieldValue("stype")).intValue();
|
int stype = ((Number) tex.getFieldValue("stype")).intValue();
|
||||||
|
|
||||||
NoiseHelper noiseHelper = dataRepository.getHelper(NoiseHelper.class);
|
|
||||||
float[] texvec = new float[] { 0, 0, 0 };
|
float[] texvec = new float[] { 0, 0, 0 };
|
||||||
TexResult texres = new TexResult();
|
TexResult texres = new TexResult();
|
||||||
float wDelta = 1.0f / width, hDelta = 1.0f / height, b2, ofs;
|
float wDelta = 1.0f / width, hDelta = 1.0f / height, b2, ofs;
|
||||||
@ -665,7 +670,7 @@ public class TextureHelper extends AbstractBlenderHelper {
|
|||||||
texres.nor[2] = texres.tin;
|
texres.nor[2] = texres.tin;
|
||||||
noiseHelper.texNormalDerivate(colorBand, texres, dataRepository);
|
noiseHelper.texNormalDerivate(colorBand, texres, dataRepository);
|
||||||
|
|
||||||
if (stype == com.jme3.scene.plugins.blender.helpers.v249.NoiseHelper.TEX_WALLOUT) {
|
if (stype == NoiseGenerator.TEX_WALLOUT) {
|
||||||
texres.nor[0] = -texres.nor[0];
|
texres.nor[0] = -texres.nor[0];
|
||||||
texres.nor[1] = -texres.nor[1];
|
texres.nor[1] = -texres.nor[1];
|
||||||
texres.nor[2] = -texres.nor[2];
|
texres.nor[2] = -texres.nor[2];
|
||||||
@ -673,7 +678,7 @@ public class TextureHelper extends AbstractBlenderHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stype == com.jme3.scene.plugins.blender.helpers.v249.NoiseHelper.TEX_WALLOUT) {
|
if (stype == NoiseGenerator.TEX_WALLOUT) {
|
||||||
texres.tin = 1.0f - texres.tin;
|
texres.tin = 1.0f - texres.tin;
|
||||||
}
|
}
|
||||||
if (texres.tin < 0.0f) {
|
if (texres.tin < 0.0f) {
|
||||||
@ -706,7 +711,6 @@ public class TextureHelper extends AbstractBlenderHelper {
|
|||||||
*/
|
*/
|
||||||
// TODO: correct this one, so it looks more like the texture generated by blender
|
// TODO: correct this one, so it looks more like the texture generated by blender
|
||||||
protected Texture texnoise(Structure tex, int width, int height, DataRepository dataRepository) {
|
protected Texture texnoise(Structure tex, int width, int height, DataRepository dataRepository) {
|
||||||
NoiseHelper noiseHelper = dataRepository.getHelper(NoiseHelper.class);
|
|
||||||
float div = 3.0f;
|
float div = 3.0f;
|
||||||
int val, ran, loop;
|
int val, ran, loop;
|
||||||
int noisedepth = ((Number) tex.getFieldValue("noisedepth")).intValue();
|
int noisedepth = ((Number) tex.getFieldValue("noisedepth")).intValue();
|
||||||
@ -762,7 +766,6 @@ public class TextureHelper extends AbstractBlenderHelper {
|
|||||||
* @return the generated texture
|
* @return the generated texture
|
||||||
*/
|
*/
|
||||||
protected Texture musgrave(Structure tex, int width, int height, DataRepository dataRepository) {
|
protected Texture musgrave(Structure tex, int width, int height, DataRepository dataRepository) {
|
||||||
NoiseHelper noiseHelper = dataRepository.getHelper(NoiseHelper.class);
|
|
||||||
int stype = ((Number) tex.getFieldValue("stype")).intValue();
|
int stype = ((Number) tex.getFieldValue("stype")).intValue();
|
||||||
float noisesize = ((Number) tex.getFieldValue("noisesize")).floatValue();
|
float noisesize = ((Number) tex.getFieldValue("noisesize")).floatValue();
|
||||||
TexResult texres = new TexResult();
|
TexResult texres = new TexResult();
|
||||||
@ -781,15 +784,15 @@ public class TextureHelper extends AbstractBlenderHelper {
|
|||||||
for (int j = -halfH; j < halfH; ++j) {
|
for (int j = -halfH; j < halfH; ++j) {
|
||||||
texvec[1] = hDelta * j / noisesize;
|
texvec[1] = hDelta * j / noisesize;
|
||||||
switch (stype) {
|
switch (stype) {
|
||||||
case com.jme3.scene.plugins.blender.helpers.v249.NoiseHelper.TEX_MFRACTAL:
|
case NoiseGenerator.TEX_MFRACTAL:
|
||||||
case com.jme3.scene.plugins.blender.helpers.v249.NoiseHelper.TEX_FBM:
|
case NoiseGenerator.TEX_FBM:
|
||||||
noiseHelper.mgMFractalOrfBmTex(tex, texvec, colorBand, texres, dataRepository);
|
noiseHelper.mgMFractalOrfBmTex(tex, texvec, colorBand, texres, dataRepository);
|
||||||
break;
|
break;
|
||||||
case com.jme3.scene.plugins.blender.helpers.v249.NoiseHelper.TEX_RIDGEDMF:
|
case NoiseGenerator.TEX_RIDGEDMF:
|
||||||
case com.jme3.scene.plugins.blender.helpers.v249.NoiseHelper.TEX_HYBRIDMF:
|
case NoiseGenerator.TEX_HYBRIDMF:
|
||||||
noiseHelper.mgRidgedOrHybridMFTex(tex, texvec, colorBand, texres, dataRepository);
|
noiseHelper.mgRidgedOrHybridMFTex(tex, texvec, colorBand, texres, dataRepository);
|
||||||
break;
|
break;
|
||||||
case com.jme3.scene.plugins.blender.helpers.v249.NoiseHelper.TEX_HTERRAIN:
|
case NoiseGenerator.TEX_HTERRAIN:
|
||||||
noiseHelper.mgHTerrainTex(tex, texvec, colorBand, texres, dataRepository);
|
noiseHelper.mgHTerrainTex(tex, texvec, colorBand, texres, dataRepository);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -822,7 +825,6 @@ public class TextureHelper extends AbstractBlenderHelper {
|
|||||||
* @return the generated texture
|
* @return the generated texture
|
||||||
*/
|
*/
|
||||||
protected Texture voronoi(Structure tex, int width, int height, DataRepository dataRepository) {
|
protected Texture voronoi(Structure tex, int width, int height, DataRepository dataRepository) {
|
||||||
NoiseHelper noiseHelper = dataRepository.getHelper(NoiseHelper.class);
|
|
||||||
float vn_w1 = ((Number) tex.getFieldValue("vn_w1")).floatValue();
|
float vn_w1 = ((Number) tex.getFieldValue("vn_w1")).floatValue();
|
||||||
float vn_w2 = ((Number) tex.getFieldValue("vn_w2")).floatValue();
|
float vn_w2 = ((Number) tex.getFieldValue("vn_w2")).floatValue();
|
||||||
float vn_w3 = ((Number) tex.getFieldValue("vn_w3")).floatValue();
|
float vn_w3 = ((Number) tex.getFieldValue("vn_w3")).floatValue();
|
||||||
@ -944,7 +946,6 @@ public class TextureHelper extends AbstractBlenderHelper {
|
|||||||
* @return the generated texture
|
* @return the generated texture
|
||||||
*/
|
*/
|
||||||
protected Texture distnoise(Structure tex, int width, int height, DataRepository dataRepository) {
|
protected Texture distnoise(Structure tex, int width, int height, DataRepository dataRepository) {
|
||||||
NoiseHelper noiseHelper = dataRepository.getHelper(NoiseHelper.class);
|
|
||||||
float noisesize = ((Number) tex.getFieldValue("noisesize")).floatValue();
|
float noisesize = ((Number) tex.getFieldValue("noisesize")).floatValue();
|
||||||
float nabla = ((Number) tex.getFieldValue("nabla")).floatValue();
|
float nabla = ((Number) tex.getFieldValue("nabla")).floatValue();
|
||||||
float distAmount = ((Number) tex.getFieldValue("dist_amount")).floatValue();
|
float distAmount = ((Number) tex.getFieldValue("dist_amount")).floatValue();
|
||||||
@ -1006,7 +1007,7 @@ public class TextureHelper extends AbstractBlenderHelper {
|
|||||||
protected ColorBand readColorband(Structure tex, DataRepository dataRepository) {
|
protected ColorBand readColorband(Structure tex, DataRepository dataRepository) {
|
||||||
ColorBand result = null;
|
ColorBand result = null;
|
||||||
int flag = ((Number) tex.getFieldValue("flag")).intValue();
|
int flag = ((Number) tex.getFieldValue("flag")).intValue();
|
||||||
if ((flag & com.jme3.scene.plugins.blender.helpers.v249.NoiseHelper.TEX_COLORBAND) != 0) {
|
if ((flag & NoiseGenerator.TEX_COLORBAND) != 0) {
|
||||||
Pointer pColorband = (Pointer) tex.getFieldValue("coba");
|
Pointer pColorband = (Pointer) tex.getFieldValue("coba");
|
||||||
Structure colorbandStructure;
|
Structure colorbandStructure;
|
||||||
try {
|
try {
|
||||||
@ -1965,4 +1966,4 @@ public class TextureHelper extends AbstractBlenderHelper {
|
|||||||
return super.clone();
|
return super.clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,110 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2009-2010 jMonkeyEngine
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are
|
|
||||||
* met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
*
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
||||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
||||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
package com.jme3.scene.plugins.blender.utils;
|
|
||||||
|
|
||||||
import com.jme3.scene.plugins.blender.data.Structure;
|
|
||||||
import com.jme3.scene.plugins.blender.exception.BlenderFileException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This interface provides an abstraction to converting loaded blender structures into data structures. The data
|
|
||||||
* structures can vary and therefore one can use the loader for different kind of engines.
|
|
||||||
* @author Marcin Roguski
|
|
||||||
* @param <NodeType>
|
|
||||||
* the type of the scene node element
|
|
||||||
* @param <CameraType>
|
|
||||||
* the type of camera element
|
|
||||||
* @param <LightType>
|
|
||||||
* the type of light element
|
|
||||||
* @param <ObjectType>
|
|
||||||
* the type of object element
|
|
||||||
* @param <MeshType>
|
|
||||||
* the type of mesh element
|
|
||||||
* @param <MaterialType>
|
|
||||||
* the type of material element
|
|
||||||
*/
|
|
||||||
//TODO: ujednolicić wyrzucane wyjątki
|
|
||||||
public interface BlenderConverter<NodeType, CameraType, LightType, ObjectType, MeshType, MaterialType> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method reads converts the given structure into scene. The given structure needs to be filled with the
|
|
||||||
* appropriate data.
|
|
||||||
* @param structure
|
|
||||||
* the structure we read the scene from
|
|
||||||
* @return the scene feature
|
|
||||||
*/
|
|
||||||
NodeType toScene(Structure structure);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method reads converts the given structure into camera. The given structure needs to be filled with the
|
|
||||||
* appropriate data.
|
|
||||||
* @param structure
|
|
||||||
* the structure we read the camera from
|
|
||||||
* @return the camera feature
|
|
||||||
*/
|
|
||||||
CameraType toCamera(Structure structure) throws BlenderFileException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method reads converts the given structure into light. The given structure needs to be filled with the
|
|
||||||
* appropriate data.
|
|
||||||
* @param structure
|
|
||||||
* the structure we read the light from
|
|
||||||
* @return the light feature
|
|
||||||
*/
|
|
||||||
LightType toLight(Structure structure) throws BlenderFileException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method reads converts the given structure into objct. The given structure needs to be filled with the
|
|
||||||
* appropriate data.
|
|
||||||
* @param structure
|
|
||||||
* the structure we read the object from
|
|
||||||
* @return the object feature
|
|
||||||
*/
|
|
||||||
ObjectType toObject(Structure structure) throws BlenderFileException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method reads converts the given structure into mesh. The given structure needs to be filled with the
|
|
||||||
* appropriate data.
|
|
||||||
* @param structure
|
|
||||||
* the structure we read the mesh from
|
|
||||||
* @return the mesh feature
|
|
||||||
*/
|
|
||||||
MeshType toMesh(Structure structure) throws BlenderFileException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method reads converts the given structure into material. The given structure needs to be filled with the
|
|
||||||
* appropriate data.
|
|
||||||
* @param structure
|
|
||||||
* the structure we read the material from
|
|
||||||
* @return the material feature
|
|
||||||
*/
|
|
||||||
MaterialType toMaterial(Structure structure) throws BlenderFileException;
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user