diff --git a/.gitignore b/.gitignore index cd8d83ebb..68a3a3d76 100644 --- a/.gitignore +++ b/.gitignore @@ -123,3 +123,4 @@ *.so *.jnilib *.dylib +/sdk/dist/ \ No newline at end of file diff --git a/jme3-android/src/main/java/com/jme3/app/state/VideoRecorderAppState.java b/jme3-android/src/main/java/com/jme3/app/state/VideoRecorderAppState.java index 6c9669df1..c915164b3 100644 --- a/jme3-android/src/main/java/com/jme3/app/state/VideoRecorderAppState.java +++ b/jme3-android/src/main/java/com/jme3/app/state/VideoRecorderAppState.java @@ -42,6 +42,7 @@ import com.jme3.renderer.queue.RenderQueue; import com.jme3.system.JmeSystem; import com.jme3.system.Timer; import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Image; import com.jme3.util.AndroidScreenshots; import com.jme3.util.BufferUtils; import java.io.File; @@ -234,7 +235,7 @@ public class VideoRecorderAppState extends AbstractAppState { final WorkItem item = freeItems.take(); usedItems.add(item); item.buffer.clear(); - renderer.readFrameBuffer(out, item.buffer); + renderer.readFrameBufferWithFormat(out, item.buffer, Image.Format.BGRA8); executor.submit(new Callable() { public Void call() throws Exception { diff --git a/jme3-android/src/main/java/com/jme3/renderer/android/OGLESShaderRenderer.java b/jme3-android/src/main/java/com/jme3/renderer/android/OGLESShaderRenderer.java index b12c7fea7..0d906abea 100644 --- a/jme3-android/src/main/java/com/jme3/renderer/android/OGLESShaderRenderer.java +++ b/jme3-android/src/main/java/com/jme3/renderer/android/OGLESShaderRenderer.java @@ -2564,4 +2564,8 @@ public class OGLESShaderRenderer implements Renderer { public void setLinearizeSrgbImages(boolean linearize) { //TODO once opglES3.0 is supported maybe.... } + + public void readFrameBufferWithFormat(FrameBuffer fb, ByteBuffer byteBuf, Image.Format format) { + throw new UnsupportedOperationException("Not supported yet. URA will make that work seamlessly"); + } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/animations/BoneContext.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/animations/BoneContext.java index f21b36f00..0eb50fb65 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/animations/BoneContext.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/animations/BoneContext.java @@ -67,9 +67,9 @@ public class BoneContext { private float length; /** The bone's deform envelope. */ private BoneEnvelope boneEnvelope; - + // The below data is used only for IK constraint computations. - + /** The bone's stretch value. */ private float ikStretch; /** Bone's rotation minimum values. */ @@ -366,6 +366,30 @@ public class BoneContext { return (flag & flagMask) != 0; } + /** + * @return the root bone context of this bone context + */ + public BoneContext getRoot() { + BoneContext result = this; + while (result.parent != null) { + result = result.parent; + } + return result; + } + + /** + * @return a number of bones from this bone to its root + */ + public int getDistanceFromRoot() { + int result = 0; + BoneContext boneContext = this; + while (boneContext.parent != null) { + boneContext = boneContext.parent; + ++result; + } + return result; + } + @Override public String toString() { return "BoneContext: " + boneName; diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/BoneConstraint.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/BoneConstraint.java index bab8f843d..fdba8af3f 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/BoneConstraint.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/BoneConstraint.java @@ -62,7 +62,7 @@ import com.jme3.scene.plugins.blender.objects.ObjectHelper; } } } - return true; + return constraintDefinition == null ? true : constraintDefinition.isTargetRequired(); } @Override @@ -70,4 +70,19 @@ import com.jme3.scene.plugins.blender.objects.ObjectHelper; super.apply(frame); blenderContext.getBoneContext(ownerOMA).getBone().updateModelTransforms(); } + + @Override + public Long getTargetOMA() { + if(targetOMA != null && subtargetName != null && !subtargetName.trim().isEmpty()) { + Spatial nodeTarget = (Spatial) blenderContext.getLoadedFeature(targetOMA, LoadedDataType.FEATURE); + if(nodeTarget != null) { + if(blenderContext.getMarkerValue(ObjectHelper.ARMATURE_NODE_MARKER, nodeTarget) != null) { + BoneContext boneContext = blenderContext.getBoneByName(targetOMA, subtargetName); + return boneContext != null ? boneContext.getBoneOma() : 0L; + } + return targetOMA; + } + } + return 0L; + } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/Constraint.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/Constraint.java index ec220ebdc..91cfd2f3f 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/Constraint.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/Constraint.java @@ -116,14 +116,31 @@ public abstract class Constraint { */ public abstract boolean validate(); + /** + * @return the OMA of the target or 0 if no target is specified for the constraint + */ + public abstract Long getTargetOMA(); + /** * Applies the constraint to owner (and in some cases can alter other bones of the skeleton). * @param frame * the frame of the animation */ public void apply(int frame) { + if (LOGGER.isLoggable(Level.FINEST)) { + LOGGER.log(Level.FINEST, "Applying constraint: {0} for frame {1}", new Object[] { name, frame }); + } Transform targetTransform = targetOMA != null ? constraintHelper.getTransform(targetOMA, subtargetName, targetSpace) : null; - constraintDefinition.bake(ownerSpace, targetSpace, targetTransform, (float)ipo.calculateValue(frame)); + constraintDefinition.bake(ownerSpace, targetSpace, targetTransform, (float) ipo.calculateValue(frame)); + } + + /** + * @return determines if the definition of the constraint will change the bone in any way; in most cases + * it is possible to tell that even before the constraint baking simulation is started, so we can discard such bones from constraint + * computing to improve the computation speed and lower the computations complexity + */ + public boolean isTrackToBeChanged() { + return constraintDefinition == null ? false : constraintDefinition.isTrackToBeChanged(); } @Override @@ -163,4 +180,9 @@ public abstract class Constraint { } return true; } + + @Override + public String toString() { + return "Constraint(name = " + name + ", def = " + constraintDefinition + ")"; + } } \ No newline at end of file diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/ConstraintHelper.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/ConstraintHelper.java index 1624e36cb..6d3058ed2 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/ConstraintHelper.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/ConstraintHelper.java @@ -2,8 +2,10 @@ package com.jme3.scene.plugins.blender.constraints; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.logging.Logger; import com.jme3.animation.Bone; @@ -170,31 +172,24 @@ public class ConstraintHelper extends AbstractBlenderHelper { * the blender context */ public void bakeConstraints(BlenderContext blenderContext) { - List simulationRootNodes = new ArrayList(); + Set owners = new HashSet(); for (Constraint constraint : blenderContext.getAllConstraints()) { - boolean constraintUsed = false; - for (SimulationNode node : simulationRootNodes) { - if (node.contains(constraint)) { - constraintUsed = true; - break; - } - } - - if (!constraintUsed) { - if (constraint instanceof BoneConstraint) { - BoneContext boneContext = blenderContext.getBoneContext(constraint.ownerOMA); - simulationRootNodes.add(new SimulationNode(boneContext.getArmatureObjectOMA(), blenderContext)); - } else if (constraint instanceof SpatialConstraint) { - Spatial spatial = (Spatial) blenderContext.getLoadedFeature(constraint.ownerOMA, LoadedDataType.FEATURE); - while (spatial.getParent() != null) { - spatial = spatial.getParent(); - } - simulationRootNodes.add(new SimulationNode((Long) blenderContext.getMarkerValue(ObjectHelper.OMA_MARKER, spatial), blenderContext)); - } else { - throw new IllegalStateException("Unsupported constraint type: " + constraint); + if(constraint instanceof BoneConstraint) { + BoneContext boneContext = blenderContext.getBoneContext(constraint.ownerOMA); + owners.add(boneContext.getArmatureObjectOMA()); + } else { + Spatial spatial = (Spatial) blenderContext.getLoadedFeature(constraint.ownerOMA, LoadedDataType.FEATURE); + while (spatial.getParent() != null) { + spatial = spatial.getParent(); } + owners.add((Long)blenderContext.getMarkerValue(ObjectHelper.OMA_MARKER, spatial)); } } + + List simulationRootNodes = new ArrayList(owners.size()); + for(Long ownerOMA : owners) { + simulationRootNodes.add(new SimulationNode(ownerOMA, blenderContext)); + } for (SimulationNode node : simulationRootNodes) { node.simulate(); diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/SimulationNode.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/SimulationNode.java index 5f13ad316..031676b94 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/SimulationNode.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/SimulationNode.java @@ -7,7 +7,6 @@ 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.AnimChannel; @@ -41,14 +40,13 @@ import com.jme3.util.TempVars; public class SimulationNode { private static final Logger LOGGER = Logger.getLogger(SimulationNode.class.getName()); + private Long featureOMA; /** The blender context. */ private BlenderContext blenderContext; /** The name of the node (for debugging purposes). */ private String name; /** A list of children for the node (either bones or child spatials). */ private List children = new ArrayList(); - /** A list of constraints that the current node has. */ - private List constraints; /** A list of node's animations. */ private List animations; @@ -66,7 +64,7 @@ public class SimulationNode { private Transform spatialStartTransform; /** Star transformations for bones. Needed to properly reset the bones. */ private Map boneStartTransforms; - + /** * Builds the nodes tree for the given feature. The feature (bone or * spatial) is found by its OMA. The feature must be a root bone or a root @@ -92,6 +90,7 @@ public class SimulationNode { * indicates if the feature is a root bone or root spatial or not */ private SimulationNode(Long featureOMA, BlenderContext blenderContext, boolean rootNode) { + this.featureOMA = featureOMA; this.blenderContext = blenderContext; Node spatial = (Node) blenderContext.getLoadedFeature(featureOMA, LoadedDataType.FEATURE); if (blenderContext.getMarkerValue(ObjectHelper.ARMATURE_NODE_MARKER, spatial) != null) { @@ -115,24 +114,10 @@ public class SimulationNode { name = '>' + spatial.getName() + '<'; - constraints = this.findConstraints(featureOMA, blenderContext); - if (constraints == null) { - constraints = new ArrayList(); - } - // add children nodes if (skeleton != null) { - // bone with index 0 is a root bone and should not be considered - // here - for (int i = 1; i < skeleton.getBoneCount(); ++i) { - BoneContext boneContext = blenderContext.getBoneContext(skeleton.getBone(i)); - List boneConstraints = this.findConstraints(boneContext.getBoneOma(), blenderContext); - if (boneConstraints != null) { - constraints.addAll(boneConstraints); - } - } Node node = blenderContext.getControlledNode(skeleton); - Long animatedNodeOMA = ((Number)blenderContext.getMarkerValue(ObjectHelper.OMA_MARKER, node)).longValue(); + Long animatedNodeOMA = ((Number) blenderContext.getMarkerValue(ObjectHelper.OMA_MARKER, node)).longValue(); animations = blenderContext.getAnimations(animatedNodeOMA); } else { animations = blenderContext.getAnimations(featureOMA); @@ -142,38 +127,6 @@ public class SimulationNode { } } } - - LOGGER.info("Removing invalid constraints."); - List validConstraints = new ArrayList(constraints.size()); - for (Constraint constraint : constraints) { - if (constraint.validate()) { - validConstraints.add(constraint); - } else { - LOGGER.log(Level.WARNING, "Constraint {0} is invalid and will not be applied.", constraint.name); - } - } - constraints = validConstraints; - } - - /** - * Tells if the node already contains the given constraint (so that it is - * not applied twice). - * - * @param constraint - * the constraint to be checked - * @return true if the constraint already is stored in the node and - * false otherwise - */ - public boolean contains(Constraint constraint) { - boolean result = false; - if (constraints != null && constraints.size() > 0) { - for (Constraint c : constraints) { - if (c.equals(constraint)) { - return true; - } - } - } - return result; } /** @@ -189,6 +142,7 @@ public class SimulationNode { for (Entry entry : boneStartTransforms.entrySet()) { Transform t = entry.getValue(); entry.getKey().setBindTransforms(t.getTranslation(), t.getRotation(), t.getScale()); + entry.getKey().updateModelTransforms(); } skeleton.reset(); } @@ -198,7 +152,9 @@ public class SimulationNode { * Simulates the spatial node. */ private void simulateSpatial() { + List constraints = blenderContext.getConstraints(featureOMA); if (constraints != null && constraints.size() > 0) { + LOGGER.fine("Simulating spatial."); boolean applyStaticConstraints = true; if (animations != null) { for (Animation animation : animations) { @@ -206,7 +162,7 @@ public class SimulationNode { int maxFrame = (int) animationTimeBoundaries[0]; float maxTime = animationTimeBoundaries[1]; - VirtualTrack vTrack = new VirtualTrack(maxFrame, maxTime); + VirtualTrack vTrack = new VirtualTrack(spatial.getName(), maxFrame, maxTime); for (Track track : animation.getTracks()) { for (int frame = 0; frame < maxFrame; ++frame) { spatial.setLocalTranslation(((SpatialTrack) track).getTranslations()[frame]); @@ -246,84 +202,86 @@ public class SimulationNode { * Simulates the bone node. */ private void simulateSkeleton() { - if (constraints != null && constraints.size() > 0) { - Set alteredOmas = new HashSet(); - - if (animations != null) { - TempVars vars = TempVars.get(); - AnimChannel animChannel = animControl.createChannel(); - for (Animation animation : animations) { - float[] animationTimeBoundaries = this.computeAnimationTimeBoundaries(animation); - int maxFrame = (int) animationTimeBoundaries[0]; - float maxTime = animationTimeBoundaries[1]; - - Map tracks = new HashMap(); - for (int frame = 0; frame < maxFrame; ++frame) { - // this MUST be done here, otherwise setting next frame of animation will - // lead to possible errors - this.reset(); + LOGGER.fine("Simulating skeleton."); + Set alteredOmas = new HashSet(); + + if (animations != null) { + TempVars vars = TempVars.get(); + AnimChannel animChannel = animControl.createChannel(); + + // List bonesWithConstraints = this.collectBonesWithConstraints(skeleton); + for (Animation animation : animations) { + float[] animationTimeBoundaries = this.computeAnimationTimeBoundaries(animation); + int maxFrame = (int) animationTimeBoundaries[0]; + float maxTime = animationTimeBoundaries[1]; + + Map tracks = new HashMap(); + for (int frame = 0; frame < maxFrame; ++frame) { + // this MUST be done here, otherwise setting next frame of animation will + // lead to possible errors + this.reset(); + + // first set proper time for all bones in all the tracks ... + for (Track track : animation.getTracks()) { + float time = ((BoneTrack) track).getTimes()[frame]; + track.setTime(time, 1, animControl, animChannel, vars); + skeleton.updateWorldVectors(); + } - // first set proper time for all bones in all the tracks ... - for (Track track : animation.getTracks()) { - float time = ((BoneTrack) track).getTimes()[frame]; - track.setTime(time, 1, animControl, animChannel, vars); - skeleton.updateWorldVectors(); + // ... and then apply constraints from the root bone to the last child ... + Set applied = new HashSet(); + for (Bone rootBone : skeleton.getRoots()) { + // ignore the 0-indexed bone + if (skeleton.getBoneIndex(rootBone) > 0) { + this.applyConstraints(rootBone, alteredOmas, applied, frame); } + } - // ... and then apply constraints from the root bone to the last child ... - for (Bone rootBone : skeleton.getRoots()) { - if (skeleton.getBoneIndex(rootBone) > 0) { - // ommit the 0 - indexed root bone as it is the bone added by importer - this.applyConstraints(rootBone, alteredOmas, frame); - } - } - - // ... add virtual tracks if neccessary, for bones that were altered but had no tracks before ... - for (Long boneOMA : alteredOmas) { - BoneContext boneContext = blenderContext.getBoneContext(boneOMA); - int boneIndex = skeleton.getBoneIndex(boneContext.getBone()); - if (!tracks.containsKey(boneIndex)) { - tracks.put(boneIndex, new VirtualTrack(maxFrame, maxTime)); - } - } - alteredOmas.clear(); - - // ... and fill in another frame in the result track - for (Entry trackEntry : tracks.entrySet()) { - Bone bone = skeleton.getBone(trackEntry.getKey()); - Transform startTransform = boneStartTransforms.get(bone); - - // track contains differences between the frame position and bind positions of bones/spatials - Vector3f bonePositionDifference = bone.getLocalPosition().subtract(startTransform.getTranslation()); - Quaternion boneRotationDifference = startTransform.getRotation().inverse().mult(bone.getLocalRotation()).normalizeLocal(); - Vector3f boneScaleDifference = bone.getLocalScale().divide(startTransform.getScale()); - - trackEntry.getValue().setTransform(frame, new Transform(bonePositionDifference, boneRotationDifference, boneScaleDifference)); + // ... add virtual tracks if neccessary, for bones that were altered but had no tracks before ... + for (Long boneOMA : alteredOmas) { + BoneContext boneContext = blenderContext.getBoneContext(boneOMA); + int boneIndex = skeleton.getBoneIndex(boneContext.getBone()); + if (!tracks.containsKey(boneIndex)) { + tracks.put(boneIndex, new VirtualTrack(boneContext.getBone().getName(), maxFrame, maxTime)); } } + alteredOmas.clear(); + // ... and fill in another frame in the result track for (Entry trackEntry : tracks.entrySet()) { - Track newTrack = trackEntry.getValue().getAsBoneTrack(trackEntry.getKey()); - if (newTrack != null) { - boolean trackReplaced = false; - for (Track track : animation.getTracks()) { - if (((BoneTrack) track).getTargetBoneIndex() == trackEntry.getKey().intValue()) { - animation.removeTrack(track); - animation.addTrack(newTrack); - trackReplaced = true; - break; - } - } - if (!trackReplaced) { + Bone bone = skeleton.getBone(trackEntry.getKey()); + Transform startTransform = boneStartTransforms.get(bone); + + // track contains differences between the frame position and bind positions of bones/spatials + Vector3f bonePositionDifference = bone.getLocalPosition().subtract(startTransform.getTranslation()); + Quaternion boneRotationDifference = startTransform.getRotation().inverse().mult(bone.getLocalRotation()).normalizeLocal(); + Vector3f boneScaleDifference = bone.getLocalScale().divide(startTransform.getScale()); + + trackEntry.getValue().setTransform(frame, new Transform(bonePositionDifference, boneRotationDifference, boneScaleDifference)); + } + } + + for (Entry trackEntry : tracks.entrySet()) { + Track newTrack = trackEntry.getValue().getAsBoneTrack(trackEntry.getKey()); + if (newTrack != null) { + boolean trackReplaced = false; + for (Track track : animation.getTracks()) { + if (((BoneTrack) track).getTargetBoneIndex() == trackEntry.getKey().intValue()) { + animation.removeTrack(track); animation.addTrack(newTrack); + trackReplaced = true; + break; } } + if (!trackReplaced) { + animation.addTrack(newTrack); + } } } - vars.release(); - animControl.clearChannels(); - this.reset(); } + vars.release(); + animControl.clearChannels(); + this.reset(); } } @@ -337,20 +295,33 @@ public class SimulationNode { * @param frame * the current frame of the animation */ - private void applyConstraints(Bone bone, Set alteredOmas, int frame) { + private void applyConstraints(Bone bone, Set alteredOmas, Set applied, int frame) { BoneContext boneContext = blenderContext.getBoneContext(bone); - List constraints = this.findConstraints(boneContext.getBoneOma(), blenderContext); - if (constraints != null && constraints.size() > 0) { - for (Constraint constraint : constraints) { - constraint.apply(frame); - if (constraint.getAlteredOmas() != null) { - alteredOmas.addAll(constraint.getAlteredOmas()); + if(!applied.contains(boneContext.getBoneOma())) { + List constraints = this.findConstraints(boneContext.getBoneOma(), blenderContext); + if (constraints != null && constraints.size() > 0) { + // TODO: BEWARE OF INFINITE LOOPS !!!!!!!!!!!!!!!!!!!!!!!!!! + for (Constraint constraint : constraints) { + if (constraint.getTargetOMA() != null && constraint.getTargetOMA() > 0L) { + // first apply constraints of the target bone + BoneContext targetBone = blenderContext.getBoneContext(constraint.getTargetOMA()); + this.applyConstraints(targetBone.getBone(), alteredOmas, applied, frame); + } + constraint.apply(frame); + if (constraint.getAlteredOmas() != null) { + alteredOmas.addAll(constraint.getAlteredOmas()); + } + alteredOmas.add(boneContext.getBoneOma()); } - alteredOmas.add(boneContext.getBoneOma()); } + applied.add(boneContext.getBoneOma()); } - for (Bone child : bone.getChildren()) { - this.applyConstraints(child, alteredOmas, frame); + + List children = bone.getChildren(); + if (children != null && children.size() > 0) { + for (Bone child : bone.getChildren()) { + this.applyConstraints(child, alteredOmas, applied, frame); + } } } @@ -376,7 +347,7 @@ public class SimulationNode { */ private float[] computeAnimationTimeBoundaries(Animation animation) { int maxFrame = Integer.MIN_VALUE; - float maxTime = Float.MIN_VALUE; + float maxTime = -Float.MAX_VALUE; for (Track track : animation.getTracks()) { if (track instanceof BoneTrack) { maxFrame = Math.max(maxFrame, ((BoneTrack) track).getTranslations().length); @@ -405,11 +376,10 @@ public class SimulationNode { List constraints = blenderContext.getConstraints(ownerOMA); if (constraints != null) { for (Constraint constraint : constraints) { - if (constraint.isImplemented() && constraint.validate()) { + if (constraint.isImplemented() && constraint.validate() && constraint.isTrackToBeChanged()) { result.add(constraint); - } else { - LOGGER.log(Level.WARNING, "Constraint named: ''{0}'' of type ''{1}'' is not implemented and will NOT be applied!", new Object[] { constraint.name, constraint.getConstraintTypeName() }); } + // TODO: add proper warnings to some map or set so that they are not logged on every frame } } return result.size() > 0 ? result : null; diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/SkeletonConstraint.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/SkeletonConstraint.java index 98d5562b1..5560bbd43 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/SkeletonConstraint.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/SkeletonConstraint.java @@ -32,4 +32,10 @@ import com.jme3.scene.plugins.blender.file.Structure; public void apply(int frame) { LOGGER.warning("Applying constraints to skeleton is not supported."); } + + @Override + public Long getTargetOMA() { + LOGGER.warning("Constraints for skeleton are not supported."); + return null; + } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/SpatialConstraint.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/SpatialConstraint.java index 5284a800e..91eb5c5c7 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/SpatialConstraint.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/SpatialConstraint.java @@ -22,6 +22,11 @@ import com.jme3.scene.plugins.blender.file.Structure; if (targetOMA != null) { return blenderContext.getLoadedFeature(targetOMA, LoadedDataType.FEATURE) != null; } - return true; + return constraintDefinition == null ? true : constraintDefinition.isTargetRequired(); + } + + @Override + public Long getTargetOMA() { + return targetOMA; } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/VirtualTrack.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/VirtualTrack.java index 944a3fab8..f18222795 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/VirtualTrack.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/VirtualTrack.java @@ -16,6 +16,8 @@ import com.jme3.math.Vector3f; * @author Marcin Roguski (Kaelthas) */ /* package */class VirtualTrack { + /** The name of the track (for debugging purposes). */ + private String name; /** The last frame for the track. */ public int maxFrame; /** The max time for the track. */ @@ -35,7 +37,8 @@ import com.jme3.math.Vector3f; * @param maxTime * the max time for the track */ - public VirtualTrack(int maxFrame, float maxTime) { + public VirtualTrack(String name, int maxFrame, float maxTime) { + this.name = name; this.maxFrame = maxFrame; this.maxTime = maxTime; } @@ -101,7 +104,7 @@ import com.jme3.math.Vector3f; */ private float[] createTimes() { float[] times = new float[maxFrame]; - float dT = maxTime / (float) maxFrame; + float dT = maxTime / maxFrame; float t = 0; for (int i = 0; i < maxFrame; ++i) { times[i] = t; @@ -143,4 +146,20 @@ import com.jme3.math.Vector3f; list.add(element); } } + + @Override + public String toString() { + StringBuilder result = new StringBuilder(2048); + result.append("TRACK: ").append(name).append('\n'); + if (translations != null && translations.size() > 0) { + result.append("TRANSLATIONS: ").append(translations.toString()).append('\n'); + } + if (rotations != null && rotations.size() > 0) { + result.append("ROTATIONS: ").append(rotations.toString()).append('\n'); + } + if (scales != null && scales.size() > 0) { + result.append("SCALES: ").append(scales.toString()).append('\n'); + } + return result.toString(); + } } \ No newline at end of file diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinition.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinition.java index 8b3f9fd15..346554052 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinition.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinition.java @@ -28,6 +28,8 @@ public abstract class ConstraintDefinition { protected Long ownerOMA; /** Stores the OMA addresses of all features whose transform had been altered beside the constraint owner. */ protected Set alteredOmas; + /** The variable that determines if the constraint will alter the track in any way. */ + protected boolean trackToBeChanged = true; /** * Loads a constraint definition based on the constraint definition @@ -52,6 +54,20 @@ public abstract class ConstraintDefinition { this.ownerOMA = ownerOMA; } + /** + * @return determines if the definition of the constraint will change the bone in any way; in most cases + * it is possible to tell that even before the constraint baking simulation is started, so we can discard such bones from constraint + * computing to improve the computation speed and lower the computations complexity + */ + public boolean isTrackToBeChanged() { + return trackToBeChanged; + } + + /** + * @return determines if this constraint definition requires a defined target or not + */ + public abstract boolean isTargetRequired(); + /** * This method is here because we have no guarantee that the owner is loaded * when constraint is being created. So use it to get the owner when it is @@ -132,4 +148,9 @@ public abstract class ConstraintDefinition { * the influence of the constraint (from range <0; 1>) */ public abstract void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence); + + @Override + public String toString() { + return this.getConstraintTypeName(); + } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionDistLimit.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionDistLimit.java index cc4852cca..aaa7e2d97 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionDistLimit.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionDistLimit.java @@ -26,18 +26,17 @@ import com.jme3.scene.plugins.blender.file.Structure; mode = ((Number) constraintData.getFieldValue("mode")).intValue(); dist = ((Number) constraintData.getFieldValue("dist")).floatValue(); } - + @Override public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) { - if (this.getOwner() instanceof Bone && ((Bone) this.getOwner()).getParent() != null && - blenderContext.getBoneContext(ownerOMA).is(BoneContext.CONNECTED_TO_PARENT)) { + if (this.getOwner() instanceof Bone && ((Bone) this.getOwner()).getParent() != null && blenderContext.getBoneContext(ownerOMA).is(BoneContext.CONNECTED_TO_PARENT)) { // distance limit does not work on bones who are connected to their parent return; } - if(influence == 0 || targetTransform == null) { - return ;// no need to do anything + if (influence == 0 || targetTransform == null) { + return;// no need to do anything } - + Transform ownerTransform = this.getOwnerTransform(ownerSpace); Vector3f v = ownerTransform.getTranslation().subtract(targetTransform.getTranslation()); @@ -73,6 +72,11 @@ import com.jme3.scene.plugins.blender.file.Structure; this.applyOwnerTransform(ownerTransform, ownerSpace); } + @Override + public boolean isTargetRequired() { + return true; + } + @Override public String getConstraintTypeName() { return "Limit distance"; diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionIK.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionIK.java index 615291999..1d6139e04 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionIK.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionIK.java @@ -6,13 +6,15 @@ import java.util.HashSet; import java.util.List; import com.jme3.animation.Bone; -import com.jme3.math.Quaternion; import com.jme3.math.Transform; import com.jme3.math.Vector3f; import com.jme3.scene.plugins.blender.BlenderContext; import com.jme3.scene.plugins.blender.animations.BoneContext; import com.jme3.scene.plugins.blender.constraints.ConstraintHelper.Space; import com.jme3.scene.plugins.blender.file.Structure; +import com.jme3.scene.plugins.blender.math.DQuaternion; +import com.jme3.scene.plugins.blender.math.DTransform; +import com.jme3.scene.plugins.blender.math.Vector3d; /** * The Inverse Kinematics constraint. @@ -28,9 +30,7 @@ public class ConstraintDefinitionIK extends ConstraintDefinition { /** The number of affected bones. Zero means that all parent bones of the current bone should take part in baking. */ private int bonesAffected; /** The total length of the bone chain. Useful for optimisation of computations speed in some cases. */ - private float chainLength; - /** Tells if there is anything to compute at all. */ - private boolean needToCompute = true; + private double chainLength; /** Indicates if the tail of the bone should be used or not. */ private boolean useTail; /** The amount of iterations of the algorithm. */ @@ -43,26 +43,26 @@ public class ConstraintDefinitionIK extends ConstraintDefinition { useTail = (flag & FLAG_USE_TAIL) != 0; if ((flag & FLAG_POSITION) == 0) { - needToCompute = false; + trackToBeChanged = false; } - if (needToCompute) { + if (trackToBeChanged) { alteredOmas = new HashSet(); } } @Override public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) { - if (influence == 0 || !needToCompute || targetTransform == null) { + if (influence == 0 || !trackToBeChanged || targetTransform == null) { return;// no need to do anything } - Quaternion q = new Quaternion(); - Vector3f t = targetTransform.getTranslation(); + DQuaternion q = new DQuaternion(); + Vector3d t = new Vector3d(targetTransform.getTranslation()); List bones = this.loadBones(); - if(bones.size() == 0) { + if (bones.size() == 0) { return;// no need to do anything } - float distanceFromTarget = Float.MAX_VALUE; + double distanceFromTarget = Double.MAX_VALUE; int iterations = this.iterations; if (bones.size() == 1) { @@ -72,21 +72,21 @@ public class ConstraintDefinitionIK extends ConstraintDefinition { // in this case only one iteration will be needed, computed from the root to top bone BoneContext rootBone = bones.get(bones.size() - 1); Transform rootBoneTransform = constraintHelper.getTransform(rootBone.getArmatureObjectOMA(), rootBone.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD); - if (t.distance(rootBoneTransform.getTranslation()) >= chainLength) { + if (t.distance(new Vector3d(rootBoneTransform.getTranslation())) >= chainLength) { Collections.reverse(bones); for (BoneContext boneContext : bones) { Bone bone = boneContext.getBone(); - Transform boneTransform = constraintHelper.getTransform(boneContext.getArmatureObjectOMA(), bone.getName(), Space.CONSTRAINT_SPACE_WORLD); + DTransform boneTransform = new DTransform(constraintHelper.getTransform(boneContext.getArmatureObjectOMA(), bone.getName(), Space.CONSTRAINT_SPACE_WORLD)); - Vector3f e = boneTransform.getTranslation().add(boneTransform.getRotation().mult(Vector3f.UNIT_Y).multLocal(boneContext.getLength()));// effector - Vector3f j = boneTransform.getTranslation(); // current join position + Vector3d e = boneTransform.getTranslation().add(boneTransform.getRotation().mult(Vector3d.UNIT_Y).multLocal(boneContext.getLength()));// effector + Vector3d j = boneTransform.getTranslation(); // current join position - Vector3f currentDir = e.subtractLocal(j).normalizeLocal(); - Vector3f target = t.subtract(j).normalizeLocal(); - float angle = currentDir.angleBetween(target); + Vector3d currentDir = e.subtractLocal(j).normalizeLocal(); + Vector3d target = t.subtract(j).normalizeLocal(); + double angle = currentDir.angleBetween(target); if (angle != 0) { - Vector3f cross = currentDir.crossLocal(target).normalizeLocal(); + Vector3d cross = currentDir.crossLocal(target).normalizeLocal(); q.fromAngleAxis(angle, cross); if (boneContext.isLockX()) { q.set(0, q.getY(), q.getZ(), q.getW()); @@ -99,7 +99,7 @@ public class ConstraintDefinitionIK extends ConstraintDefinition { } boneTransform.getRotation().set(q.multLocal(boneTransform.getRotation())); - constraintHelper.applyTransform(boneContext.getArmatureObjectOMA(), bone.getName(), Space.CONSTRAINT_SPACE_WORLD, boneTransform); + constraintHelper.applyTransform(boneContext.getArmatureObjectOMA(), bone.getName(), Space.CONSTRAINT_SPACE_WORLD, boneTransform.toTransform()); } } @@ -111,17 +111,17 @@ public class ConstraintDefinitionIK extends ConstraintDefinition { for (int i = 0; i < iterations && distanceFromTarget > MIN_DISTANCE; ++i) { for (BoneContext boneContext : bones) { Bone bone = boneContext.getBone(); - Transform topBoneTransform = constraintHelper.getTransform(topBone.getArmatureObjectOMA(), topBone.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD); - Transform boneWorldTransform = constraintHelper.getTransform(boneContext.getArmatureObjectOMA(), bone.getName(), Space.CONSTRAINT_SPACE_WORLD); + DTransform topBoneTransform = new DTransform(constraintHelper.getTransform(topBone.getArmatureObjectOMA(), topBone.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD)); + DTransform boneWorldTransform = new DTransform(constraintHelper.getTransform(boneContext.getArmatureObjectOMA(), bone.getName(), Space.CONSTRAINT_SPACE_WORLD)); - Vector3f e = topBoneTransform.getTranslation().addLocal(topBoneTransform.getRotation().mult(Vector3f.UNIT_Y).multLocal(topBone.getLength()));// effector - Vector3f j = boneWorldTransform.getTranslation(); // current join position + Vector3d e = topBoneTransform.getTranslation().addLocal(topBoneTransform.getRotation().mult(Vector3d.UNIT_Y).multLocal(topBone.getLength()));// effector + Vector3d j = boneWorldTransform.getTranslation(); // current join position - Vector3f currentDir = e.subtractLocal(j).normalizeLocal(); - Vector3f target = t.subtract(j).normalizeLocal(); - float angle = currentDir.angleBetween(target); + Vector3d currentDir = e.subtractLocal(j).normalizeLocal(); + Vector3d target = t.subtract(j).normalizeLocal(); + double angle = currentDir.angleBetween(target); if (angle != 0) { - Vector3f cross = currentDir.crossLocal(target).normalizeLocal(); + Vector3d cross = currentDir.crossLocal(target).normalizeLocal(); q.fromAngleAxis(angle, cross); if (boneContext.isLockX()) { @@ -135,12 +135,15 @@ public class ConstraintDefinitionIK extends ConstraintDefinition { } boneWorldTransform.getRotation().set(q.multLocal(boneWorldTransform.getRotation())); - constraintHelper.applyTransform(boneContext.getArmatureObjectOMA(), bone.getName(), Space.CONSTRAINT_SPACE_WORLD, boneWorldTransform); + constraintHelper.applyTransform(boneContext.getArmatureObjectOMA(), bone.getName(), Space.CONSTRAINT_SPACE_WORLD, boneWorldTransform.toTransform()); + } else { + iterations = 0; + break; } } - Transform topBoneTransform = constraintHelper.getTransform(topBone.getArmatureObjectOMA(), topBone.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD); - Vector3f e = topBoneTransform.getTranslation().addLocal(topBoneTransform.getRotation().mult(Vector3f.UNIT_Y).multLocal(topBone.getLength()));// effector + DTransform topBoneTransform = new DTransform(constraintHelper.getTransform(topBone.getArmatureObjectOMA(), topBone.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD)); + Vector3d e = topBoneTransform.getTranslation().addLocal(topBoneTransform.getRotation().mult(Vector3d.UNIT_Y).multLocal(topBone.getLength()));// effector distanceFromTarget = e.distance(t); } } @@ -186,4 +189,20 @@ public class ConstraintDefinitionIK extends ConstraintDefinition { } return bones; } + + @Override + public boolean isTrackToBeChanged() { + if (trackToBeChanged) { + // need to check the bone structure too (when constructor was called not all of the bones might have been loaded yet) + // that is why it is also checked here + List bones = this.loadBones(); + trackToBeChanged = bones.size() > 0; + } + return trackToBeChanged; + } + + @Override + public boolean isTargetRequired() { + return true; + } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionLocLike.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionLocLike.java index 0e2c4d63d..bf6fb39b1 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionLocLike.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionLocLike.java @@ -34,27 +34,30 @@ import com.jme3.scene.plugins.blender.file.Structure; int invZ = flag & LOCLIKE_Z_INVERT; // clear the other flags to swap them flag &= LOCLIKE_X | LOCLIKE_X_INVERT | LOCLIKE_OFFSET; - + flag |= y << 1; flag |= invY << 1; flag |= z >> 1; flag |= invZ >> 1; + + trackToBeChanged = (flag & LOCLIKE_X) != 0 || (flag & LOCLIKE_Y) != 0 || (flag & LOCLIKE_Z) != 0; } } - + + @Override + public boolean isTrackToBeChanged() { + // location copy does not work on bones who are connected to their parent + return trackToBeChanged && !(this.getOwner() instanceof Bone && ((Bone) this.getOwner()).getParent() != null && blenderContext.getBoneContext(ownerOMA).is(BoneContext.CONNECTED_TO_PARENT)); + } + @Override public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) { - if (this.getOwner() instanceof Bone && ((Bone) this.getOwner()).getParent() != null && - blenderContext.getBoneContext(ownerOMA).is(BoneContext.CONNECTED_TO_PARENT)) { - // location copy does not work on bones who are connected to their parent + if (influence == 0 || targetTransform == null || !this.isTrackToBeChanged()) { return; } - if(influence == 0 || targetTransform == null) { - return ;// no need to do anything - } - + Transform ownerTransform = this.getOwnerTransform(ownerSpace); - + Vector3f ownerLocation = ownerTransform.getTranslation(); Vector3f targetLocation = targetTransform.getTranslation(); @@ -88,7 +91,7 @@ import com.jme3.scene.plugins.blender.file.Structure; startLocation.subtractLocal(ownerLocation).normalizeLocal().mult(influence); ownerLocation.addLocal(startLocation); } - + this.applyOwnerTransform(ownerTransform, ownerSpace); } @@ -96,4 +99,9 @@ import com.jme3.scene.plugins.blender.file.Structure; public String getConstraintTypeName() { return "Copy location"; } + + @Override + public boolean isTargetRequired() { + return true; + } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionLocLimit.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionLocLimit.java index 615fb104b..62e92e73b 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionLocLimit.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionLocLimit.java @@ -52,18 +52,24 @@ import com.jme3.scene.plugins.blender.file.Structure; limits[2][0] = ((Number) constraintData.getFieldValue("zmin")).floatValue(); limits[2][1] = ((Number) constraintData.getFieldValue("zmax")).floatValue(); } + + trackToBeChanged = (flag & (LIMIT_XMIN | LIMIT_XMAX | LIMIT_YMIN | LIMIT_YMAX | LIMIT_ZMIN | LIMIT_ZMAX)) != 0; + } + + @Override + public boolean isTrackToBeChanged() { + // location limit does not work on bones who are connected to their parent + return trackToBeChanged && !(this.getOwner() instanceof Bone && ((Bone) this.getOwner()).getParent() != null && blenderContext.getBoneContext(ownerOMA).is(BoneContext.CONNECTED_TO_PARENT)); } - + @Override public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) { - if (this.getOwner() instanceof Bone && ((Bone) this.getOwner()).getParent() != null && - blenderContext.getBoneContext(ownerOMA).is(BoneContext.CONNECTED_TO_PARENT)) { - // location limit does not work on bones who are connected to their parent - return; + if (influence == 0 || !this.isTrackToBeChanged()) { + return;// no need to do anything } - + Transform ownerTransform = this.getOwnerTransform(ownerSpace); - + Vector3f translation = ownerTransform.getTranslation(); if ((flag & LIMIT_XMIN) != 0 && translation.x < limits[0][0]) { @@ -84,7 +90,7 @@ import com.jme3.scene.plugins.blender.file.Structure; if ((flag & LIMIT_ZMAX) != 0 && translation.z > limits[2][1]) { translation.z -= (translation.z - limits[2][1]) * influence; } - + this.applyOwnerTransform(ownerTransform, ownerSpace); } @@ -92,4 +98,9 @@ import com.jme3.scene.plugins.blender.file.Structure; public String getConstraintTypeName() { return "Limit location"; } + + @Override + public boolean isTargetRequired() { + return false; + } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionMaintainVolume.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionMaintainVolume.java index fce99d40f..c8756129e 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionMaintainVolume.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionMaintainVolume.java @@ -6,6 +6,11 @@ import com.jme3.scene.plugins.blender.BlenderContext; import com.jme3.scene.plugins.blender.constraints.ConstraintHelper.Space; import com.jme3.scene.plugins.blender.file.Structure; +/** + * This class represents 'Maintain volume' constraint type in blender. + * + * @author Marcin Roguski (Kaelthas) + */ public class ConstraintDefinitionMaintainVolume extends ConstraintDefinition { private static final int FLAG_MASK_X = 0; private static final int FLAG_MASK_Y = 1; @@ -16,11 +21,12 @@ public class ConstraintDefinitionMaintainVolume extends ConstraintDefinition { public ConstraintDefinitionMaintainVolume(Structure constraintData, Long ownerOMA, BlenderContext blenderContext) { super(constraintData, ownerOMA, blenderContext); volume = (float) Math.sqrt(((Number) constraintData.getFieldValue("volume")).floatValue()); + trackToBeChanged = volume != 1 && (flag & (FLAG_MASK_X | FLAG_MASK_Y | FLAG_MASK_Z)) != 0; } @Override public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) { - if (volume != 1 && influence > 0) { + if (trackToBeChanged && influence > 0) { // the maintain volume constraint is applied directly to object's scale, so no need to do it again // but in case of bones we need to make computations if (this.getOwner() instanceof Bone) { @@ -47,4 +53,9 @@ public class ConstraintDefinitionMaintainVolume extends ConstraintDefinition { public String getConstraintTypeName() { return "Maintain volume"; } + + @Override + public boolean isTargetRequired() { + return false; + } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionNull.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionNull.java index 6744a7884..032909c65 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionNull.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionNull.java @@ -14,6 +14,7 @@ import com.jme3.scene.plugins.blender.file.Structure; public ConstraintDefinitionNull(Structure constraintData, Long ownerOMA, BlenderContext blenderContext) { super(constraintData, ownerOMA, blenderContext); + trackToBeChanged = false; } @Override @@ -25,4 +26,9 @@ import com.jme3.scene.plugins.blender.file.Structure; public String getConstraintTypeName() { return "Null"; } + + @Override + public boolean isTargetRequired() { + return false; + } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionRotLike.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionRotLike.java index 3a363cb4d..280e4e77e 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionRotLike.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionRotLike.java @@ -25,15 +25,16 @@ import com.jme3.scene.plugins.blender.file.Structure; public ConstraintDefinitionRotLike(Structure constraintData, Long ownerOMA, BlenderContext blenderContext) { super(constraintData, ownerOMA, blenderContext); + trackToBeChanged = (flag & (ROTLIKE_X | ROTLIKE_Y | ROTLIKE_Z)) != 0; } @Override public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) { - if(influence == 0 || targetTransform == null) { - return ;// no need to do anything + if (influence == 0 || targetTransform == null || !trackToBeChanged) { + return;// no need to do anything } Transform ownerTransform = this.getOwnerTransform(ownerSpace); - + Quaternion ownerRotation = ownerTransform.getRotation(); ownerAngles = ownerRotation.toAngles(ownerAngles); targetAngles = targetTransform.getRotation().toAngles(targetAngles); @@ -70,7 +71,7 @@ import com.jme3.scene.plugins.blender.file.Structure; // ownerLocation.addLocal(startLocation); // TODO } - + this.applyOwnerTransform(ownerTransform, ownerSpace); } @@ -78,4 +79,9 @@ import com.jme3.scene.plugins.blender.file.Structure; public String getConstraintTypeName() { return "Copy rotation"; } + + @Override + public boolean isTargetRequired() { + return true; + } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionRotLimit.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionRotLimit.java index 55a8f8147..3d569447f 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionRotLimit.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionRotLimit.java @@ -65,12 +65,17 @@ import com.jme3.scene.plugins.blender.file.Structure; * if(limits[i][0] > limits[i][1]) { float temp = limits[i][0]; * limits[i][0] = limits[i][1]; limits[i][1] = temp; } } */ + + trackToBeChanged = (flag & (LIMIT_XROT | LIMIT_YROT | LIMIT_ZROT)) != 0; } - + @Override public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) { + if (influence == 0 || !trackToBeChanged) { + return; + } Transform ownerTransform = this.getOwnerTransform(ownerSpace); - + ownerTransform.getRotation().toAngles(angles); // make sure that the rotations are always in range [0, 2PI) // TODO: same comment as in constructor @@ -108,7 +113,7 @@ import com.jme3.scene.plugins.blender.file.Structure; angles[2] -= difference; } ownerTransform.getRotation().fromAngles(angles); - + this.applyOwnerTransform(ownerTransform, ownerSpace); } @@ -116,4 +121,9 @@ import com.jme3.scene.plugins.blender.file.Structure; public String getConstraintTypeName() { return "Limit rotation"; } + + @Override + public boolean isTargetRequired() { + return false; + } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionSizeLike.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionSizeLike.java index 046801526..b05048af6 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionSizeLike.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionSizeLike.java @@ -27,16 +27,18 @@ import com.jme3.scene.plugins.blender.file.Structure; // them flag |= y << 1; flag |= z >> 1; + + trackToBeChanged = (flag & (SIZELIKE_X | SIZELIKE_Y | SIZELIKE_Z)) != 0; } } - + @Override public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) { - if(influence == 0 || targetTransform == null) { + if (influence == 0 || targetTransform == null || !trackToBeChanged) { return;// no need to do anything } Transform ownerTransform = this.getOwnerTransform(ownerSpace); - + Vector3f ownerScale = ownerTransform.getScale(); Vector3f targetScale = targetTransform.getScale(); @@ -56,7 +58,7 @@ import com.jme3.scene.plugins.blender.file.Structure; ownerScale.z = targetScale.z * influence + (1.0f - influence) * ownerScale.z; } ownerScale.addLocal(offset); - + this.applyOwnerTransform(ownerTransform, ownerSpace); } @@ -64,4 +66,9 @@ import com.jme3.scene.plugins.blender.file.Structure; public String getConstraintTypeName() { return "Copy scale"; } + + @Override + public boolean isTargetRequired() { + return true; + } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionSizeLimit.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionSizeLimit.java index 564f77e70..6c133bf18 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionSizeLimit.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionSizeLimit.java @@ -50,12 +50,17 @@ import com.jme3.scene.plugins.blender.file.Structure; limits[2][0] = ((Number) constraintData.getFieldValue("zmin")).floatValue(); limits[2][1] = ((Number) constraintData.getFieldValue("zmax")).floatValue(); } + + trackToBeChanged = (flag & (LIMIT_XMIN | LIMIT_XMAX | LIMIT_YMIN | LIMIT_YMAX | LIMIT_ZMIN | LIMIT_ZMAX)) != 0; } - + @Override public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) { + if (influence == 0 || !trackToBeChanged) { + return; + } Transform ownerTransform = this.getOwnerTransform(ownerSpace); - + Vector3f scale = ownerTransform.getScale(); if ((flag & LIMIT_XMIN) != 0 && scale.x < limits[0][0]) { scale.x -= (scale.x - limits[0][0]) * influence; @@ -75,7 +80,7 @@ import com.jme3.scene.plugins.blender.file.Structure; if ((flag & LIMIT_ZMAX) != 0 && scale.z > limits[2][1]) { scale.z -= (scale.z - limits[2][1]) * influence; } - + this.applyOwnerTransform(ownerTransform, ownerSpace); } @@ -83,4 +88,9 @@ import com.jme3.scene.plugins.blender.file.Structure; public String getConstraintTypeName() { return "Limit scale"; } + + @Override + public boolean isTargetRequired() { + return false; + } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionTransLike.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionTransLike.java index 5b171b97f..b38857279 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionTransLike.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionTransLike.java @@ -35,8 +35,8 @@ public class ConstraintDefinitionTransLike extends ConstraintDefinition { @Override public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) { - if(influence == 0 || targetTransform == null) { - return ;// no need to do anything + if (influence == 0 || targetTransform == null) { + return;// no need to do anything } Object target = this.getTarget();// Bone or Node Object owner = this.getOwner();// Bone or Node @@ -73,4 +73,9 @@ public class ConstraintDefinitionTransLike extends ConstraintDefinition { public String getConstraintTypeName() { return "Copy transforms"; } + + @Override + public boolean isTargetRequired() { + return true; + } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/UnsupportedConstraintDefinition.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/UnsupportedConstraintDefinition.java index 3002cfb88..e3fa82e9a 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/UnsupportedConstraintDefinition.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/UnsupportedConstraintDefinition.java @@ -16,6 +16,7 @@ import com.jme3.scene.plugins.blender.constraints.ConstraintHelper.Space; public UnsupportedConstraintDefinition(String typeName) { super(null, null, null); this.typeName = typeName; + trackToBeChanged = false; } @Override @@ -31,4 +32,9 @@ import com.jme3.scene.plugins.blender.constraints.ConstraintHelper.Space; public String getConstraintTypeName() { return typeName; } + + @Override + public boolean isTargetRequired() { + return false; + } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/math/DQuaternion.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/math/DQuaternion.java new file mode 100644 index 000000000..359abf057 --- /dev/null +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/math/DQuaternion.java @@ -0,0 +1,453 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.scene.plugins.blender.math; + +import java.io.IOException; + +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; +import com.jme3.export.Savable; +import com.jme3.math.Quaternion; + +/** + * DQuaternion defines a single example of a more general class of + * hypercomplex numbers. DQuaternions extends a rotation in three dimensions to a + * rotation in four dimensions. This avoids "gimbal lock" and allows for smooth + * continuous rotation. + * + * DQuaternion is defined by four double point numbers: {x y z w}. + * + * This class's only purpose is to give better accuracy in floating point operations during computations. + * This is made by copying the original Quaternion class from jme3 core and leaving only required methods and basic computation methods, so that + * the class is smaller and easier to maintain. + * Should any other methods be needed, they will be added. + * + * @author Mark Powell + * @author Joshua Slack + * @author Marcin Roguski (Kaelthas) + */ +public final class DQuaternion implements Savable, Cloneable, java.io.Serializable { + private static final long serialVersionUID = 5009180713885017539L; + + /** + * Represents the identity quaternion rotation (0, 0, 0, 1). + */ + public static final DQuaternion IDENTITY = new DQuaternion(); + public static final DQuaternion DIRECTION_Z = new DQuaternion(); + public static final DQuaternion ZERO = new DQuaternion(0, 0, 0, 0); + protected double x, y, z, w = 1; + + /** + * Constructor instantiates a new DQuaternion object + * initializing all values to zero, except w which is initialized to 1. + * + */ + public DQuaternion() { + } + + /** + * Constructor instantiates a new DQuaternion object from the + * given list of parameters. + * + * @param x + * the x value of the quaternion. + * @param y + * the y value of the quaternion. + * @param z + * the z value of the quaternion. + * @param w + * the w value of the quaternion. + */ + public DQuaternion(double x, double y, double z, double w) { + this.set(x, y, z, w); + } + + public DQuaternion(Quaternion q) { + this(q.getX(), q.getY(), q.getZ(), q.getW()); + } + + public Quaternion toQuaternion() { + return new Quaternion((float) x, (float) y, (float) z, (float) w); + } + + public double getX() { + return x; + } + + public double getY() { + return y; + } + + public double getZ() { + return z; + } + + public double getW() { + return w; + } + + /** + * sets the data in a DQuaternion object from the given list + * of parameters. + * + * @param x + * the x value of the quaternion. + * @param y + * the y value of the quaternion. + * @param z + * the z value of the quaternion. + * @param w + * the w value of the quaternion. + * @return this + */ + public DQuaternion set(double x, double y, double z, double w) { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + return this; + } + + /** + * Sets the data in this DQuaternion object to be equal to the + * passed DQuaternion object. The values are copied producing + * a new object. + * + * @param q + * The DQuaternion to copy values from. + * @return this + */ + public DQuaternion set(DQuaternion q) { + x = q.x; + y = q.y; + z = q.z; + w = q.w; + return this; + } + + /** + * Sets this DQuaternion to {0, 0, 0, 1}. Same as calling set(0,0,0,1). + */ + public void loadIdentity() { + x = y = z = 0; + w = 1; + } + + /** + * fromAngleAxis sets this quaternion to the values specified + * by an angle and an axis of rotation. This method creates an object, so + * use fromAngleNormalAxis if your axis is already normalized. + * + * @param angle + * the angle to rotate (in radians). + * @param axis + * the axis of rotation. + * @return this quaternion + */ + public DQuaternion fromAngleAxis(double angle, Vector3d axis) { + Vector3d normAxis = axis.normalize(); + this.fromAngleNormalAxis(angle, normAxis); + return this; + } + + /** + * fromAngleNormalAxis sets this quaternion to the values + * specified by an angle and a normalized axis of rotation. + * + * @param angle + * the angle to rotate (in radians). + * @param axis + * the axis of rotation (already normalized). + */ + public DQuaternion fromAngleNormalAxis(double angle, Vector3d axis) { + if (axis.x == 0 && axis.y == 0 && axis.z == 0) { + this.loadIdentity(); + } else { + double halfAngle = 0.5f * angle; + double sin = Math.sin(halfAngle); + w = Math.cos(halfAngle); + x = sin * axis.x; + y = sin * axis.y; + z = sin * axis.z; + } + return this; + } + + /** + * add adds the values of this quaternion to those of the + * parameter quaternion. The result is returned as a new quaternion. + * + * @param q + * the quaternion to add to this. + * @return the new quaternion. + */ + public DQuaternion add(DQuaternion q) { + return new DQuaternion(x + q.x, y + q.y, z + q.z, w + q.w); + } + + /** + * add adds the values of this quaternion to those of the + * parameter quaternion. The result is stored in this DQuaternion. + * + * @param q + * the quaternion to add to this. + * @return This DQuaternion after addition. + */ + public DQuaternion addLocal(DQuaternion q) { + x += q.x; + y += q.y; + z += q.z; + w += q.w; + return this; + } + + /** + * subtract subtracts the values of the parameter quaternion + * from those of this quaternion. The result is returned as a new + * quaternion. + * + * @param q + * the quaternion to subtract from this. + * @return the new quaternion. + */ + public DQuaternion subtract(DQuaternion q) { + return new DQuaternion(x - q.x, y - q.y, z - q.z, w - q.w); + } + + /** + * subtract subtracts the values of the parameter quaternion + * from those of this quaternion. The result is stored in this DQuaternion. + * + * @param q + * the quaternion to subtract from this. + * @return This DQuaternion after subtraction. + */ + public DQuaternion subtractLocal(DQuaternion q) { + x -= q.x; + y -= q.y; + z -= q.z; + w -= q.w; + return this; + } + + /** + * mult multiplies this quaternion by a parameter quaternion. + * The result is returned as a new quaternion. It should be noted that + * quaternion multiplication is not commutative so q * p != p * q. + * + * @param q + * the quaternion to multiply this quaternion by. + * @return the new quaternion. + */ + public DQuaternion mult(DQuaternion q) { + return this.mult(q, null); + } + + /** + * mult multiplies this quaternion by a parameter quaternion. + * The result is returned as a new quaternion. It should be noted that + * quaternion multiplication is not commutative so q * p != p * q. + * + * It IS safe for q and res to be the same object. + * It IS NOT safe for this and res to be the same object. + * + * @param q + * the quaternion to multiply this quaternion by. + * @param res + * the quaternion to store the result in. + * @return the new quaternion. + */ + public DQuaternion mult(DQuaternion q, DQuaternion res) { + if (res == null) { + res = new DQuaternion(); + } + double qw = q.w, qx = q.x, qy = q.y, qz = q.z; + res.x = x * qw + y * qz - z * qy + w * qx; + res.y = -x * qz + y * qw + z * qx + w * qy; + res.z = x * qy - y * qx + z * qw + w * qz; + res.w = -x * qx - y * qy - z * qz + w * qw; + return res; + } + + /** + * mult multiplies this quaternion by a parameter vector. The + * result is returned as a new vector. + * + * @param v + * the vector to multiply this quaternion by. + * @return the new vector. + */ + public Vector3d mult(Vector3d v) { + return this.mult(v, null); + } + + /** + * Multiplies this DQuaternion by the supplied quaternion. The result is + * stored in this DQuaternion, which is also returned for chaining. Similar + * to this *= q. + * + * @param q + * The DQuaternion to multiply this one by. + * @return This DQuaternion, after multiplication. + */ + public DQuaternion multLocal(DQuaternion q) { + double x1 = x * q.w + y * q.z - z * q.y + w * q.x; + double y1 = -x * q.z + y * q.w + z * q.x + w * q.y; + double z1 = x * q.y - y * q.x + z * q.w + w * q.z; + w = -x * q.x - y * q.y - z * q.z + w * q.w; + x = x1; + y = y1; + z = z1; + return this; + } + + /** + * mult multiplies this quaternion by a parameter vector. The + * result is returned as a new vector. + * + * @param v + * the vector to multiply this quaternion by. + * @param store + * the vector to store the result in. It IS safe for v and store + * to be the same object. + * @return the result vector. + */ + public Vector3d mult(Vector3d v, Vector3d store) { + if (store == null) { + store = new Vector3d(); + } + if (v.x == 0 && v.y == 0 && v.z == 0) { + store.set(0, 0, 0); + } else { + double vx = v.x, vy = v.y, vz = v.z; + store.x = w * w * vx + 2 * y * w * vz - 2 * z * w * vy + x * x * vx + 2 * y * x * vy + 2 * z * x * vz - z * z * vx - y * y * vx; + store.y = 2 * x * y * vx + y * y * vy + 2 * z * y * vz + 2 * w * z * vx - z * z * vy + w * w * vy - 2 * x * w * vz - x * x * vy; + store.z = 2 * x * z * vx + 2 * y * z * vy + z * z * vz - 2 * w * y * vx - y * y * vz + 2 * w * x * vy - x * x * vz + w * w * vz; + } + return store; + } + + /** + * + * toString creates the string representation of this DQuaternion. The values of the quaternion are displaced (x, + * y, z, w), in the following manner:
+ * (x, y, z, w) + * + * @return the string representation of this object. + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "(" + x + ", " + y + ", " + z + ", " + w + ")"; + } + + /** + * equals determines if two quaternions are logically equal, + * that is, if the values of (x, y, z, w) are the same for both quaternions. + * + * @param o + * the object to compare for equality + * @return true if they are equal, false otherwise. + */ + @Override + public boolean equals(Object o) { + if (!(o instanceof DQuaternion)) { + return false; + } + + if (this == o) { + return true; + } + + DQuaternion comp = (DQuaternion) o; + if (Double.compare(x, comp.x) != 0) { + return false; + } + if (Double.compare(y, comp.y) != 0) { + return false; + } + if (Double.compare(z, comp.z) != 0) { + return false; + } + if (Double.compare(w, comp.w) != 0) { + return false; + } + return true; + } + + /** + * + * hashCode returns the hash code value as an integer and is + * supported for the benefit of hashing based collection classes such as + * Hashtable, HashMap, HashSet etc. + * + * @return the hashcode for this instance of DQuaternion. + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + long hash = 37; + hash = 37 * hash + Double.doubleToLongBits(x); + hash = 37 * hash + Double.doubleToLongBits(y); + hash = 37 * hash + Double.doubleToLongBits(z); + hash = 37 * hash + Double.doubleToLongBits(w); + return (int) hash; + + } + + public void write(JmeExporter e) throws IOException { + OutputCapsule cap = e.getCapsule(this); + cap.write(x, "x", 0); + cap.write(y, "y", 0); + cap.write(z, "z", 0); + cap.write(w, "w", 1); + } + + public void read(JmeImporter e) throws IOException { + InputCapsule cap = e.getCapsule(this); + x = cap.readFloat("x", 0); + y = cap.readFloat("y", 0); + z = cap.readFloat("z", 0); + w = cap.readFloat("w", 1); + } + + @Override + public DQuaternion clone() { + try { + return (DQuaternion) super.clone(); + } catch (CloneNotSupportedException e) { + throw new AssertionError(); // can not happen + } + } +} diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/math/DTransform.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/math/DTransform.java new file mode 100644 index 000000000..ed31a4c98 --- /dev/null +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/math/DTransform.java @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.scene.plugins.blender.math; + +import com.jme3.export.*; +import com.jme3.math.Transform; + +import java.io.IOException; + +/** + * Started Date: Jul 16, 2004
+ *
+ * Represents a translation, rotation and scale in one object. + * + * This class's only purpose is to give better accuracy in floating point operations during computations. + * This is made by copying the original Transfrom class from jme3 core and removing unnecessary methods so that + * the class is smaller and easier to maintain. + * Should any other methods be needed, they will be added. + * + * @author Jack Lindamood + * @author Joshua Slack + * @author Marcin Roguski (Kaelthas) + */ +public final class DTransform implements Savable, Cloneable, java.io.Serializable { + private static final long serialVersionUID = 7812915425940606722L; + + private DQuaternion rotation; + private Vector3d translation; + private Vector3d scale; + + public DTransform(Transform transform) { + translation = new Vector3d(transform.getTranslation()); + rotation = new DQuaternion(transform.getRotation()); + scale = new Vector3d(transform.getScale()); + } + + public Transform toTransform() { + return new Transform(translation.toVector3f(), rotation.toQuaternion(), scale.toVector3f()); + } + + /** + * Sets this translation to the given value. + * @param trans + * The new translation for this matrix. + * @return this + */ + public DTransform setTranslation(Vector3d trans) { + translation.set(trans); + return this; + } + + /** + * Sets this rotation to the given DQuaternion value. + * @param rot + * The new rotation for this matrix. + * @return this + */ + public DTransform setRotation(DQuaternion rot) { + rotation.set(rot); + return this; + } + + /** + * Sets this scale to the given value. + * @param scale + * The new scale for this matrix. + * @return this + */ + public DTransform setScale(Vector3d scale) { + this.scale.set(scale); + return this; + } + + /** + * Sets this scale to the given value. + * @param scale + * The new scale for this matrix. + * @return this + */ + public DTransform setScale(float scale) { + this.scale.set(scale, scale, scale); + return this; + } + + /** + * Return the translation vector in this matrix. + * @return translation vector. + */ + public Vector3d getTranslation() { + return translation; + } + + /** + * Return the rotation quaternion in this matrix. + * @return rotation quaternion. + */ + public DQuaternion getRotation() { + return rotation; + } + + /** + * Return the scale vector in this matrix. + * @return scale vector. + */ + public Vector3d getScale() { + return scale; + } + + @Override + public String toString() { + return this.getClass().getSimpleName() + "[ " + translation.x + ", " + translation.y + ", " + translation.z + "]\n" + "[ " + rotation.x + ", " + rotation.y + ", " + rotation.z + ", " + rotation.w + "]\n" + "[ " + scale.x + " , " + scale.y + ", " + scale.z + "]"; + } + + public void write(JmeExporter e) throws IOException { + OutputCapsule capsule = e.getCapsule(this); + capsule.write(rotation, "rot", new DQuaternion()); + capsule.write(translation, "translation", Vector3d.ZERO); + capsule.write(scale, "scale", Vector3d.UNIT_XYZ); + } + + public void read(JmeImporter e) throws IOException { + InputCapsule capsule = e.getCapsule(this); + + rotation = (DQuaternion) capsule.readSavable("rot", new DQuaternion()); + translation = (Vector3d) capsule.readSavable("translation", Vector3d.ZERO); + scale = (Vector3d) capsule.readSavable("scale", Vector3d.UNIT_XYZ); + } + + @Override + public DTransform clone() { + try { + DTransform tq = (DTransform) super.clone(); + tq.rotation = rotation.clone(); + tq.scale = scale.clone(); + tq.translation = translation.clone(); + return tq; + } catch (CloneNotSupportedException e) { + throw new AssertionError(); + } + } +} diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/math/Vector3d.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/math/Vector3d.java new file mode 100644 index 000000000..f2a3c8075 --- /dev/null +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/math/Vector3d.java @@ -0,0 +1,867 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jme3.scene.plugins.blender.math; + +import java.io.IOException; +import java.io.Serializable; +import java.util.logging.Logger; + +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; +import com.jme3.export.Savable; +import com.jme3.math.FastMath; +import com.jme3.math.Vector3f; + +/* + * -- Added *Local methods to cut down on object creation - JS + */ + +/** + * Vector3d defines a Vector for a three float value tuple. Vector3d can represent any three dimensional value, such as a + * vertex, a normal, etc. Utility methods are also included to aid in + * mathematical calculations. + * + * This class's only purpose is to give better accuracy in floating point operations during computations. + * This is made by copying the original Vector3f class from jme3 core and leaving only required methods and basic computation methods, so that + * the class is smaller and easier to maintain. + * Should any other methods be needed, they will be added. + * + * @author Mark Powell + * @author Joshua Slack + * @author Marcin Roguski (Kaelthas) + */ +public final class Vector3d implements Savable, Cloneable, Serializable { + private static final long serialVersionUID = 3090477054277293078L; + + private static final Logger LOGGER = Logger.getLogger(Vector3d.class.getName()); + + public final static Vector3d ZERO = new Vector3d(); + public final static Vector3d UNIT_XYZ = new Vector3d(1, 1, 1); + public final static Vector3d UNIT_X = new Vector3d(1, 0, 0); + public final static Vector3d UNIT_Y = new Vector3d(0, 1, 0); + public final static Vector3d UNIT_Z = new Vector3d(0, 0, 1); + + /** + * the x value of the vector. + */ + public double x; + + /** + * the y value of the vector. + */ + public double y; + + /** + * the z value of the vector. + */ + public double z; + + /** + * Constructor instantiates a new Vector3d with default + * values of (0,0,0). + * + */ + public Vector3d() { + } + + /** + * Constructor instantiates a new Vector3d with provides + * values. + * + * @param x + * the x value of the vector. + * @param y + * the y value of the vector. + * @param z + * the z value of the vector. + */ + public Vector3d(double x, double y, double z) { + this.x = x; + this.y = y; + this.z = z; + } + + /** + * Constructor instantiates a new Vector3d that is a copy + * of the provided vector + * @param copy + * The Vector3d to copy + */ + public Vector3d(Vector3f vector3f) { + this(vector3f.x, vector3f.y, vector3f.z); + } + + public Vector3f toVector3f() { + return new Vector3f((float) x, (float) y, (float) z); + } + + /** + * set sets the x,y,z values of the vector based on passed + * parameters. + * + * @param x + * the x value of the vector. + * @param y + * the y value of the vector. + * @param z + * the z value of the vector. + * @return this vector + */ + public Vector3d set(double x, double y, double z) { + this.x = x; + this.y = y; + this.z = z; + return this; + } + + /** + * set sets the x,y,z values of the vector by copying the + * supplied vector. + * + * @param vect + * the vector to copy. + * @return this vector + */ + public Vector3d set(Vector3d vect) { + return this.set(vect.x, vect.y, vect.z); + } + + /** + * + * add adds a provided vector to this vector creating a + * resultant vector which is returned. If the provided vector is null, null + * is returned. + * + * @param vec + * the vector to add to this. + * @return the resultant vector. + */ + public Vector3d add(Vector3d vec) { + if (null == vec) { + LOGGER.warning("Provided vector is null, null returned."); + return null; + } + return new Vector3d(x + vec.x, y + vec.y, z + vec.z); + } + + /** + * + * add adds the values of a provided vector storing the + * values in the supplied vector. + * + * @param vec + * the vector to add to this + * @param result + * the vector to store the result in + * @return result returns the supplied result vector. + */ + public Vector3d add(Vector3d vec, Vector3d result) { + result.x = x + vec.x; + result.y = y + vec.y; + result.z = z + vec.z; + return result; + } + + /** + * addLocal adds a provided vector to this vector internally, + * and returns a handle to this vector for easy chaining of calls. If the + * provided vector is null, null is returned. + * + * @param vec + * the vector to add to this vector. + * @return this + */ + public Vector3d addLocal(Vector3d vec) { + if (null == vec) { + LOGGER.warning("Provided vector is null, null returned."); + return null; + } + x += vec.x; + y += vec.y; + z += vec.z; + return this; + } + + /** + * + * add adds the provided values to this vector, creating a + * new vector that is then returned. + * + * @param addX + * the x value to add. + * @param addY + * the y value to add. + * @param addZ + * the z value to add. + * @return the result vector. + */ + public Vector3d add(double addX, double addY, double addZ) { + return new Vector3d(x + addX, y + addY, z + addZ); + } + + /** + * addLocal adds the provided values to this vector + * internally, and returns a handle to this vector for easy chaining of + * calls. + * + * @param addX + * value to add to x + * @param addY + * value to add to y + * @param addZ + * value to add to z + * @return this + */ + public Vector3d addLocal(double addX, double addY, double addZ) { + x += addX; + y += addY; + z += addZ; + return this; + } + + /** + * + * scaleAdd multiplies this vector by a scalar then adds the + * given Vector3d. + * + * @param scalar + * the value to multiply this vector by. + * @param add + * the value to add + */ + public Vector3d scaleAdd(double scalar, Vector3d add) { + x = x * scalar + add.x; + y = y * scalar + add.y; + z = z * scalar + add.z; + return this; + } + + /** + * + * scaleAdd multiplies the given vector by a scalar then adds + * the given vector. + * + * @param scalar + * the value to multiply this vector by. + * @param mult + * the value to multiply the scalar by + * @param add + * the value to add + */ + public Vector3d scaleAdd(double scalar, Vector3d mult, Vector3d add) { + x = mult.x * scalar + add.x; + y = mult.y * scalar + add.y; + z = mult.z * scalar + add.z; + return this; + } + + /** + * + * dot calculates the dot product of this vector with a + * provided vector. If the provided vector is null, 0 is returned. + * + * @param vec + * the vector to dot with this vector. + * @return the resultant dot product of this vector and a given vector. + */ + public double dot(Vector3d vec) { + if (null == vec) { + LOGGER.warning("Provided vector is null, 0 returned."); + return 0; + } + return x * vec.x + y * vec.y + z * vec.z; + } + + /** + * cross calculates the cross product of this vector with a + * parameter vector v. + * + * @param v + * the vector to take the cross product of with this. + * @return the cross product vector. + */ + public Vector3d cross(Vector3d v) { + return this.cross(v, null); + } + + /** + * cross calculates the cross product of this vector with a + * parameter vector v. The result is stored in result + * + * @param v + * the vector to take the cross product of with this. + * @param result + * the vector to store the cross product result. + * @return result, after recieving the cross product vector. + */ + public Vector3d cross(Vector3d v, Vector3d result) { + return this.cross(v.x, v.y, v.z, result); + } + + /** + * cross calculates the cross product of this vector with a + * parameter vector v. The result is stored in result + * + * @param otherX + * x component of the vector to take the cross product of with this. + * @param otherY + * y component of the vector to take the cross product of with this. + * @param otherZ + * z component of the vector to take the cross product of with this. + * @param result + * the vector to store the cross product result. + * @return result, after recieving the cross product vector. + */ + public Vector3d cross(double otherX, double otherY, double otherZ, Vector3d result) { + if (result == null) { + result = new Vector3d(); + } + double resX = y * otherZ - z * otherY; + double resY = z * otherX - x * otherZ; + double resZ = x * otherY - y * otherX; + result.set(resX, resY, resZ); + return result; + } + + /** + * crossLocal calculates the cross product of this vector + * with a parameter vector v. + * + * @param v + * the vector to take the cross product of with this. + * @return this. + */ + public Vector3d crossLocal(Vector3d v) { + return this.crossLocal(v.x, v.y, v.z); + } + + /** + * crossLocal calculates the cross product of this vector + * with a parameter vector v. + * + * @param otherX + * x component of the vector to take the cross product of with this. + * @param otherY + * y component of the vector to take the cross product of with this. + * @param otherZ + * z component of the vector to take the cross product of with this. + * @return this. + */ + public Vector3d crossLocal(double otherX, double otherY, double otherZ) { + double tempx = y * otherZ - z * otherY; + double tempy = z * otherX - x * otherZ; + z = x * otherY - y * otherX; + x = tempx; + y = tempy; + return this; + } + + /** + * length calculates the magnitude of this vector. + * + * @return the length or magnitude of the vector. + */ + public double length() { + return Math.sqrt(this.lengthSquared()); + } + + /** + * lengthSquared calculates the squared value of the + * magnitude of the vector. + * + * @return the magnitude squared of the vector. + */ + public double lengthSquared() { + return x * x + y * y + z * z; + } + + /** + * distanceSquared calculates the distance squared between + * this vector and vector v. + * + * @param v + * the second vector to determine the distance squared. + * @return the distance squared between the two vectors. + */ + public double distanceSquared(Vector3d v) { + double dx = x - v.x; + double dy = y - v.y; + double dz = z - v.z; + return dx * dx + dy * dy + dz * dz; + } + + /** + * distance calculates the distance between this vector and + * vector v. + * + * @param v + * the second vector to determine the distance. + * @return the distance between the two vectors. + */ + public double distance(Vector3d v) { + return Math.sqrt(this.distanceSquared(v)); + } + + /** + * + * mult multiplies this vector by a scalar. The resultant + * vector is returned. + * + * @param scalar + * the value to multiply this vector by. + * @return the new vector. + */ + public Vector3d mult(double scalar) { + return new Vector3d(x * scalar, y * scalar, z * scalar); + } + + /** + * + * mult multiplies this vector by a scalar. The resultant + * vector is supplied as the second parameter and returned. + * + * @param scalar + * the scalar to multiply this vector by. + * @param product + * the product to store the result in. + * @return product + */ + public Vector3d mult(double scalar, Vector3d product) { + if (null == product) { + product = new Vector3d(); + } + + product.x = x * scalar; + product.y = y * scalar; + product.z = z * scalar; + return product; + } + + /** + * multLocal multiplies this vector by a scalar internally, + * and returns a handle to this vector for easy chaining of calls. + * + * @param scalar + * the value to multiply this vector by. + * @return this + */ + public Vector3d multLocal(double scalar) { + x *= scalar; + y *= scalar; + z *= scalar; + return this; + } + + /** + * multLocal multiplies a provided vector to this vector + * internally, and returns a handle to this vector for easy chaining of + * calls. If the provided vector is null, null is returned. + * + * @param vec + * the vector to mult to this vector. + * @return this + */ + public Vector3d multLocal(Vector3d vec) { + if (null == vec) { + LOGGER.warning("Provided vector is null, null returned."); + return null; + } + x *= vec.x; + y *= vec.y; + z *= vec.z; + return this; + } + + /** + * multLocal multiplies this vector by 3 scalars + * internally, and returns a handle to this vector for easy chaining of + * calls. + * + * @param x + * @param y + * @param z + * @return this + */ + public Vector3d multLocal(double x, double y, double z) { + this.x *= x; + this.y *= y; + this.z *= z; + return this; + } + + /** + * multLocal multiplies a provided vector to this vector + * internally, and returns a handle to this vector for easy chaining of + * calls. If the provided vector is null, null is returned. + * + * @param vec + * the vector to mult to this vector. + * @return this + */ + public Vector3d mult(Vector3d vec) { + if (null == vec) { + LOGGER.warning("Provided vector is null, null returned."); + return null; + } + return this.mult(vec, null); + } + + /** + * multLocal multiplies a provided vector to this vector + * internally, and returns a handle to this vector for easy chaining of + * calls. If the provided vector is null, null is returned. + * + * @param vec + * the vector to mult to this vector. + * @param store + * result vector (null to create a new vector) + * @return this + */ + public Vector3d mult(Vector3d vec, Vector3d store) { + if (null == vec) { + LOGGER.warning("Provided vector is null, null returned."); + return null; + } + if (store == null) { + store = new Vector3d(); + } + return store.set(x * vec.x, y * vec.y, z * vec.z); + } + + /** + * divide divides the values of this vector by a scalar and + * returns the result. The values of this vector remain untouched. + * + * @param scalar + * the value to divide this vectors attributes by. + * @return the result Vector. + */ + public Vector3d divide(double scalar) { + scalar = 1f / scalar; + return new Vector3d(x * scalar, y * scalar, z * scalar); + } + + /** + * divideLocal divides this vector by a scalar internally, + * and returns a handle to this vector for easy chaining of calls. Dividing + * by zero will result in an exception. + * + * @param scalar + * the value to divides this vector by. + * @return this + */ + public Vector3d divideLocal(double scalar) { + scalar = 1f / scalar; + x *= scalar; + y *= scalar; + z *= scalar; + return this; + } + + /** + * divide divides the values of this vector by a scalar and + * returns the result. The values of this vector remain untouched. + * + * @param scalar + * the value to divide this vectors attributes by. + * @return the result Vector. + */ + public Vector3d divide(Vector3d scalar) { + return new Vector3d(x / scalar.x, y / scalar.y, z / scalar.z); + } + + /** + * divideLocal divides this vector by a scalar internally, + * and returns a handle to this vector for easy chaining of calls. Dividing + * by zero will result in an exception. + * + * @param scalar + * the value to divides this vector by. + * @return this + */ + public Vector3d divideLocal(Vector3d scalar) { + x /= scalar.x; + y /= scalar.y; + z /= scalar.z; + return this; + } + + /** + * + * negate returns the negative of this vector. All values are + * negated and set to a new vector. + * + * @return the negated vector. + */ + public Vector3d negate() { + return new Vector3d(-x, -y, -z); + } + + /** + * + * negateLocal negates the internal values of this vector. + * + * @return this. + */ + public Vector3d negateLocal() { + x = -x; + y = -y; + z = -z; + return this; + } + + /** + * + * subtract subtracts the values of a given vector from those + * of this vector creating a new vector object. If the provided vector is + * null, null is returned. + * + * @param vec + * the vector to subtract from this vector. + * @return the result vector. + */ + public Vector3d subtract(Vector3d vec) { + return new Vector3d(x - vec.x, y - vec.y, z - vec.z); + } + + /** + * subtractLocal subtracts a provided vector to this vector + * internally, and returns a handle to this vector for easy chaining of + * calls. If the provided vector is null, null is returned. + * + * @param vec + * the vector to subtract + * @return this + */ + public Vector3d subtractLocal(Vector3d vec) { + if (null == vec) { + LOGGER.warning("Provided vector is null, null returned."); + return null; + } + x -= vec.x; + y -= vec.y; + z -= vec.z; + return this; + } + + /** + * + * subtract + * + * @param vec + * the vector to subtract from this + * @param result + * the vector to store the result in + * @return result + */ + public Vector3d subtract(Vector3d vec, Vector3d result) { + if (result == null) { + result = new Vector3d(); + } + result.x = x - vec.x; + result.y = y - vec.y; + result.z = z - vec.z; + return result; + } + + /** + * + * subtract subtracts the provided values from this vector, + * creating a new vector that is then returned. + * + * @param subtractX + * the x value to subtract. + * @param subtractY + * the y value to subtract. + * @param subtractZ + * the z value to subtract. + * @return the result vector. + */ + public Vector3d subtract(double subtractX, double subtractY, double subtractZ) { + return new Vector3d(x - subtractX, y - subtractY, z - subtractZ); + } + + /** + * subtractLocal subtracts the provided values from this vector + * internally, and returns a handle to this vector for easy chaining of + * calls. + * + * @param subtractX + * the x value to subtract. + * @param subtractY + * the y value to subtract. + * @param subtractZ + * the z value to subtract. + * @return this + */ + public Vector3d subtractLocal(double subtractX, double subtractY, double subtractZ) { + x -= subtractX; + y -= subtractY; + z -= subtractZ; + return this; + } + + /** + * normalize returns the unit vector of this vector. + * + * @return unit vector of this vector. + */ + public Vector3d normalize() { + double length = x * x + y * y + z * z; + if (length != 1f && length != 0f) { + length = 1.0f / Math.sqrt(length); + return new Vector3d(x * length, y * length, z * length); + } + return this.clone(); + } + + /** + * normalizeLocal makes this vector into a unit vector of + * itself. + * + * @return this. + */ + public Vector3d normalizeLocal() { + // NOTE: this implementation is more optimized + // than the old jme normalize as this method + // is commonly used. + double length = x * x + y * y + z * z; + if (length != 1f && length != 0f) { + length = 1.0f / Math.sqrt(length); + x *= length; + y *= length; + z *= length; + } + return this; + } + + /** + * angleBetween returns (in radians) the angle between two vectors. + * It is assumed that both this vector and the given vector are unit vectors (iow, normalized). + * + * @param otherVector + * a unit vector to find the angle against + * @return the angle in radians. + */ + public double angleBetween(Vector3d otherVector) { + double dot = this.dot(otherVector); + // the vectors are normalized, but if they are parallel then the dot product migh get a value like: 1.000000000000000002 + // which is caused by floating point operations; in such case, the acos function will return NaN so we need to clamp this value + dot = FastMath.clamp((float) dot, -1, 1); + return Math.acos(dot); + } + + @Override + public Vector3d clone() { + try { + return (Vector3d) super.clone(); + } catch (CloneNotSupportedException e) { + throw new AssertionError(); // can not happen + } + } + + /** + * are these two vectors the same? they are is they both have the same x,y, + * and z values. + * + * @param o + * the object to compare for equality + * @return true if they are equal + */ + @Override + public boolean equals(Object o) { + if (!(o instanceof Vector3d)) { + return false; + } + + if (this == o) { + return true; + } + + Vector3d comp = (Vector3d) o; + if (Double.compare(x, comp.x) != 0) { + return false; + } + if (Double.compare(y, comp.y) != 0) { + return false; + } + if (Double.compare(z, comp.z) != 0) { + return false; + } + return true; + } + + /** + * hashCode returns a unique code for this vector object based + * on it's values. If two vectors are logically equivalent, they will return + * the same hash code value. + * @return the hash code value of this vector. + */ + @Override + public int hashCode() { + long hash = 37; + hash += 37 * hash + Double.doubleToLongBits(x); + hash += 37 * hash + Double.doubleToLongBits(y); + hash += 37 * hash + Double.doubleToLongBits(z); + return (int) hash; + } + + /** + * toString returns the string representation of this vector. + * The format is: + * + * org.jme.math.Vector3d [X=XX.XXXX, Y=YY.YYYY, Z=ZZ.ZZZZ] + * + * @return the string representation of this vector. + */ + @Override + public String toString() { + return "(" + x + ", " + y + ", " + z + ")"; + } + + public void write(JmeExporter e) throws IOException { + OutputCapsule capsule = e.getCapsule(this); + capsule.write(x, "x", 0); + capsule.write(y, "y", 0); + capsule.write(z, "z", 0); + } + + public void read(JmeImporter e) throws IOException { + InputCapsule capsule = e.getCapsule(this); + x = capsule.readDouble("x", 0); + y = capsule.readDouble("y", 0); + z = capsule.readDouble("z", 0); + } +} diff --git a/jme3-core/src/main/java/com/jme3/app/state/ScreenshotAppState.java b/jme3-core/src/main/java/com/jme3/app/state/ScreenshotAppState.java index 10afa47da..90b50a3a9 100644 --- a/jme3-core/src/main/java/com/jme3/app/state/ScreenshotAppState.java +++ b/jme3-core/src/main/java/com/jme3/app/state/ScreenshotAppState.java @@ -44,6 +44,7 @@ import com.jme3.renderer.ViewPort; import com.jme3.renderer.queue.RenderQueue; import com.jme3.system.JmeSystem; import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Image; import com.jme3.util.BufferUtils; import java.io.File; import java.io.FileOutputStream; @@ -229,7 +230,7 @@ public class ScreenshotAppState extends AbstractAppState implements ActionListen int viewHeight = (int) ((curCamera.getViewPortTop() - curCamera.getViewPortBottom()) * curCamera.getHeight()); renderer.setViewPort(0, 0, width, height); - renderer.readFrameBuffer(out, outBuf); + renderer.readFrameBufferWithFormat(out, outBuf, Image.Format.BGRA8); renderer.setViewPort(viewX, viewY, viewWidth, viewHeight); File file; diff --git a/jme3-core/src/main/java/com/jme3/renderer/Renderer.java b/jme3-core/src/main/java/com/jme3/renderer/Renderer.java index a61b2185b..aa06d626e 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/Renderer.java +++ b/jme3-core/src/main/java/com/jme3/renderer/Renderer.java @@ -222,7 +222,7 @@ public interface Renderer { /** * Reads the pixels currently stored in the specified framebuffer * into the given ByteBuffer object. - * Only color pixels are transferred, the format is BGRA with 8 bits + * Only color pixels are transferred, the format is RGBA with 8 bits * per component. The given byte buffer should have at least * fb.getWidth() * fb.getHeight() * 4 bytes remaining. * @@ -230,6 +230,19 @@ public interface Renderer { * @param byteBuf The bytebuffer to transfer color data to */ public void readFrameBuffer(FrameBuffer fb, ByteBuffer byteBuf); + + /** + * Reads the pixels currently stored in the specified framebuffer + * into the given ByteBuffer object. + * Only color pixels are transferred, witht hte given format. + * The given byte buffer should have at least + * fb.getWidth() * fb.getHeight() * 4 bytes remaining. + * + * @param fb The framebuffer to read from + * @param byteBuf The bytebuffer to transfer color data to + * @param format the image format to use when reading the frameBuffer. + */ + public void readFrameBufferWithFormat(FrameBuffer fb, ByteBuffer byteBuf, Image.Format format); /** * Deletes a framebuffer and all attached renderbuffers diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java index 0eef936cb..e6526dce6 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java @@ -1629,6 +1629,10 @@ public class GLRenderer implements Renderer { } public void readFrameBuffer(FrameBuffer fb, ByteBuffer byteBuf) { + readFrameBufferWithGLFormat(fb, byteBuf, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE); + } + + private void readFrameBufferWithGLFormat(FrameBuffer fb, ByteBuffer byteBuf, int glFormat, int dataType) { if (fb != null) { RenderBuffer rb = fb.getColorBuffer(); if (rb == null) { @@ -1647,7 +1651,12 @@ public class GLRenderer implements Renderer { setFrameBuffer(null); } - gl.glReadPixels(vpX, vpY, vpW, vpH, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, byteBuf); + gl.glReadPixels(vpX, vpY, vpW, vpH, glFormat, dataType, byteBuf); + } + + public void readFrameBufferWithFormat(FrameBuffer fb, ByteBuffer byteBuf, Image.Format format) { + GLImageFormat glFormat = texUtil.getImageFormatWithError(format, false); + readFrameBufferWithGLFormat(fb, byteBuf, glFormat.format, glFormat.dataType); } private void deleteRenderBuffer(FrameBuffer fb, RenderBuffer rb) { diff --git a/jme3-core/src/main/java/com/jme3/system/NullRenderer.java b/jme3-core/src/main/java/com/jme3/system/NullRenderer.java index 20a946cee..06015ecd3 100644 --- a/jme3-core/src/main/java/com/jme3/system/NullRenderer.java +++ b/jme3-core/src/main/java/com/jme3/system/NullRenderer.java @@ -161,4 +161,7 @@ public class NullRenderer implements Renderer { public void setLinearizeSrgbImages(boolean linearize) { } + public void readFrameBufferWithFormat(FrameBuffer fb, ByteBuffer byteBuf, Image.Format format) { + } + } diff --git a/jme3-core/src/main/java/com/jme3/util/SkyFactory.java b/jme3-core/src/main/java/com/jme3/util/SkyFactory.java index 7fb70e76f..6104141aa 100644 --- a/jme3-core/src/main/java/com/jme3/util/SkyFactory.java +++ b/jme3-core/src/main/java/com/jme3/util/SkyFactory.java @@ -55,6 +55,32 @@ import java.util.ArrayList; */ public class SkyFactory { + + /** + * The type of map fed to the shader + */ + public enum EnvMapType{ + /** + * The env map is a cube map see {@link TextureCubeMap} or 6 separate images that form a cube map + * The texture is either a {@link TextureCubeMap} or 6 {@link Texture2D}. + * In the latter case, a TextureCubeMap is build from the 6 2d maps. + */ + CubeMap, + /** + * The env map is a Sphere map. The texture is a Texture2D with the pixels arranged for + * sphere + * mapping. + */ + SphereMap, + /** + * The env map is an Equirectangular map. A 2D textures with pixels + * arranged for equirectangular + * projection mapping.. + * + */ + EquirectMap + } + /** * Create a sky with radius=10 using the given cubemap or spheremap texture. * @@ -77,12 +103,33 @@ public class SkyFactory { * * @return a new spatial representing the sky, ready to be attached to the * scene graph + * @deprecated use {@link SkyFactory#createSky(com.jme3.asset.AssetManager, com.jme3.texture.Texture, com.jme3.math.Vector3f, com.jme3.util.SkyFactory.EnvMapType)} */ + @Deprecated public static Spatial createSky(AssetManager assetManager, Texture texture, Vector3f normalScale, boolean sphereMap) { return createSky(assetManager, texture, normalScale, sphereMap, 10); } + /** + * Create a sky with radius=10 using the given cubemap or spheremap texture. + * + * For the sky to be visible, its radius must fall between the near and far + * planes of the camera's frustrum. + * + * @param assetManager from which to load materials + * @param texture to use + * @param normalScale The normal scale is multiplied by the 3D normal to get + * a texture coordinate. Use Vector3f.UNIT_XYZ to not apply and + * transformation to the normal. + * @param envMapType see {@link EnvMapType} + * @return a new spatial representing the sky, ready to be attached to the + * scene graph + */ + public static Spatial createSky(AssetManager assetManager, Texture texture, + Vector3f normalScale, EnvMapType envMapType) { + return createSky(assetManager, texture, normalScale, envMapType, 10); + } /** * Create a sky using the given cubemap or spheremap texture. * @@ -105,9 +152,31 @@ public class SkyFactory { * frustrum * @return a new spatial representing the sky, ready to be attached to the * scene graph + * @deprecated use {@link SkyFactory#createSky(com.jme3.asset.AssetManager, com.jme3.texture.Texture, com.jme3.math.Vector3f, com.jme3.util.SkyFactory.EnvMapType, int)} */ + @Deprecated public static Spatial createSky(AssetManager assetManager, Texture texture, Vector3f normalScale, boolean sphereMap, int sphereRadius) { + return createSky(assetManager, texture, normalScale, sphereMap?EnvMapType.SphereMap:EnvMapType.CubeMap, sphereRadius); + } + + /** + * Create a sky using the given cubemap or spheremap texture. + * + * @param assetManager from which to load materials + * @param texture to use + * @param normalScale The normal scale is multiplied by the 3D normal to get + * a texture coordinate. Use Vector3f.UNIT_XYZ to not apply and + * transformation to the normal. + * @param envMapType see {@link EnvMapType} + * @param sphereRadius the sky sphere's radius: for the sky to be visible, + * its radius must fall between the near and far planes of the camera's + * frustrum + * @return a new spatial representing the sky, ready to be attached to the + * scene graph + */ + public static Spatial createSky(AssetManager assetManager, Texture texture, + Vector3f normalScale, EnvMapType envMapType, int sphereRadius) { if (texture == null) { throw new IllegalArgumentException("texture cannot be null"); } @@ -121,13 +190,19 @@ public class SkyFactory { Material skyMat = new Material(assetManager, "Common/MatDefs/Misc/Sky.j3md"); skyMat.setVector3("NormalScale", normalScale); - if (sphereMap) { - skyMat.setBoolean("SphereMap", sphereMap); - } else if (!(texture instanceof TextureCubeMap)) { - // make sure its a cubemap - Image img = texture.getImage(); - texture = new TextureCubeMap(); - texture.setImage(img); + switch (envMapType){ + case CubeMap : + // make sure its a cubemap + Image img = texture.getImage(); + texture = new TextureCubeMap(); + texture.setImage(img); + break; + case SphereMap : + skyMat.setBoolean("SphereMap", true); + break; + case EquirectMap : + skyMat.setBoolean("EquirectMap", true); + break; } texture.setMagFilter(Texture.MagFilter.Bilinear); texture.setMinFilter(Texture.MinFilter.BilinearNoMipMaps); @@ -136,6 +211,84 @@ public class SkyFactory { return sky; } + + /** + * Create a sky using the given cubemap or spheremap texture. + * + * @param assetManager from which to load materials + * @param texture to use * + * @param sphereMap determines how the texture is used:
+ *
    + *
  • true: The texture is a Texture2D with the pixels arranged for + * sphere + * mapping.
  • + *
  • false: The texture is either a TextureCubeMap or Texture2D. If it is + * a Texture2D then the image is taken from it and is inserted into a + * TextureCubeMap
  • + *
+ * @return a new spatial representing the sky, ready to be attached to the + * scene graph + * @deprecated use {@link SkyFactory#createSky(com.jme3.asset.AssetManager, com.jme3.texture.Texture, com.jme3.math.Vector3f, com.jme3.util.SkyFactory.EnvMapType)} + */ + @Deprecated + public static Spatial createSky(AssetManager assetManager, Texture texture, boolean sphereMap) { + return createSky(assetManager, texture, Vector3f.UNIT_XYZ, sphereMap?EnvMapType.SphereMap:EnvMapType.CubeMap); + } + + /** + * Create a sky using the given cubemap or spheremap texture. + * + * @param assetManager from which to load materials + * @param textureName the path to the texture asset to use + * @param sphereMap determines how the texture is used:
+ *
    + *
  • true: The texture is a Texture2D with the pixels arranged for + * sphere + * mapping.
  • + *
  • false: The texture is either a TextureCubeMap or Texture2D. If it is + * a Texture2D then the image is taken from it and is inserted into a + * TextureCubeMap
  • + *
+ * @return a new spatial representing the sky, ready to be attached to the + * scene graph + * @deprecated use {@link SkyFactory#createSky(com.jme3.asset.AssetManager, java.lang.String, com.jme3.math.Vector3f, com.jme3.util.SkyFactory.EnvMapType)} + */ + @Deprecated + public static Spatial createSky(AssetManager assetManager, String textureName, boolean sphereMap) { + return createSky(assetManager, textureName, sphereMap?EnvMapType.SphereMap:EnvMapType.CubeMap); + } + + /** + * Create a sky using the given cubemap or spheremap texture. + * + * @param assetManager from which to load materials + * @param texture to use + * @param envMapType see {@link EnvMapType} + * @return a new spatial representing the sky, ready to be attached to the + * scene graph + */ + public static Spatial createSky(AssetManager assetManager, Texture texture, EnvMapType envMapType) { + return createSky(assetManager, texture, Vector3f.UNIT_XYZ, envMapType); + } + + /** + * Create a sky using the given cubemap or spheremap texture. + * + * @param assetManager from which to load materials + * @param textureName the path to the texture asset to use + * @param envMapType see {@link EnvMapType} + * @return a new spatial representing the sky, ready to be attached to the + * scene graph + */ + public static Spatial createSky(AssetManager assetManager, String textureName, EnvMapType envMapType) { + TextureKey key = new TextureKey(textureName, true); + key.setGenerateMips(false); + if (envMapType == EnvMapType.CubeMap) { + key.setTextureTypeHint(Texture.Type.CubeMap); + } + Texture tex = assetManager.loadTexture(key); + return createSky(assetManager, tex, envMapType); + } private static void checkImage(Image image) { // if (image.getDepth() != 1) @@ -282,21 +435,20 @@ public class SkyFactory { return sky; } + /** + * Create a cube-mapped sky using six textures. + * + * @param assetManager from which to load materials + * @param west texture for the western face of the cube + * @param east texture for the eastern face of the cube + * @param north texture for the northern face of the cube + * @param south texture for the southern face of the cube + * @param up texture for the top face of the cube + * @param down texture for the bottom face of the cube * + * @return a new spatial representing the sky, ready to be attached to the + * scene graph + */ public static Spatial createSky(AssetManager assetManager, Texture west, Texture east, Texture north, Texture south, Texture up, Texture down) { return createSky(assetManager, west, east, north, south, up, down, Vector3f.UNIT_XYZ); } - - public static Spatial createSky(AssetManager assetManager, Texture texture, boolean sphereMap) { - return createSky(assetManager, texture, Vector3f.UNIT_XYZ, sphereMap); - } - - public static Spatial createSky(AssetManager assetManager, String textureName, boolean sphereMap) { - TextureKey key = new TextureKey(textureName, true); - key.setGenerateMips(false); - if (!sphereMap) { - key.setTextureTypeHint(Texture.Type.CubeMap); - } - Texture tex = assetManager.loadTexture(key); - return createSky(assetManager, tex, sphereMap); - } } diff --git a/jme3-core/src/main/resources/Common/MatDefs/Misc/Sky.j3md b/jme3-core/src/main/resources/Common/MatDefs/Misc/Sky.j3md index 515777428..2e2aa4f8f 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/Misc/Sky.j3md +++ b/jme3-core/src/main/resources/Common/MatDefs/Misc/Sky.j3md @@ -2,6 +2,7 @@ MaterialDef Sky Plane { MaterialParameters { TextureCubeMap Texture Boolean SphereMap + Boolean EquirectMap Vector3 NormalScale } Technique { @@ -20,6 +21,7 @@ MaterialDef Sky Plane { Defines { SPHERE_MAP : SphereMap + EQUIRECT_MAP : EquirectMap } } Technique { diff --git a/jme3-core/src/main/resources/Common/ShaderLib/Optics.glsllib b/jme3-core/src/main/resources/Common/ShaderLib/Optics.glsllib index 5f762434f..642e3fb90 100644 --- a/jme3-core/src/main/resources/Common/ShaderLib/Optics.glsllib +++ b/jme3-core/src/main/resources/Common/ShaderLib/Optics.glsllib @@ -1,4 +1,4 @@ -#ifdef SPHERE_MAP +#if defined(SPHERE_MAP) || defined(EQUIRECT_MAP) #define ENVMAP sampler2D #define TEXENV texture2D #else @@ -23,10 +23,25 @@ vec2 Optics_SphereCoord(in vec3 dir){ return (dir.xy * vec2(inv_two_p)) + vec2(0.5); } +#ifndef PI + #define PI 3.14159265358979323846264 +#endif +//should be vec2(1.0 / (PI * 2.0), 1.0 / PI) but it's precomputed. +const vec2 Optics_Glsllib_Rads = vec2(0.159154943091895, 0.318309886183790); +vec2 Optics_LonLatCoords(in ENVMAP envMap, in vec3 dir){ + float lon = atan(dir.z, dir.x)+ PI; + float lat = acos(dir.y); + return vec2(lon, lat) * Optics_Glsllib_Rads; +} + vec4 Optics_GetEnvColor(in ENVMAP envMap, in vec3 dir){ #ifdef SPHERE_MAP return texture2D(envMap, Optics_SphereCoord(dir)); #else - return textureCube(envMap, dir); + #ifdef EQUIRECT_MAP + return texture2D(envMap, Optics_LonLatCoords(envMap,dir)); + #else + return textureCube(envMap, dir); + #endif #endif -} \ No newline at end of file +} diff --git a/jme3-desktop/src/main/java/com/jme3/app/state/VideoRecorderAppState.java b/jme3-desktop/src/main/java/com/jme3/app/state/VideoRecorderAppState.java index 85c8cb7f6..9466b4a50 100644 --- a/jme3-desktop/src/main/java/com/jme3/app/state/VideoRecorderAppState.java +++ b/jme3-desktop/src/main/java/com/jme3/app/state/VideoRecorderAppState.java @@ -40,6 +40,7 @@ import com.jme3.renderer.ViewPort; import com.jme3.renderer.queue.RenderQueue; import com.jme3.system.Timer; import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Image; import com.jme3.util.BufferUtils; import com.jme3.util.Screenshots; import java.awt.image.BufferedImage; @@ -228,7 +229,7 @@ public class VideoRecorderAppState extends AbstractAppState { final WorkItem item = freeItems.take(); usedItems.add(item); item.buffer.clear(); - renderer.readFrameBuffer(out, item.buffer); + renderer.readFrameBufferWithFormat(out, item.buffer, Image.Format.BGRA8); executor.submit(new Callable() { public Void call() throws Exception { diff --git a/jme3-desktop/src/main/java/com/jme3/system/awt/AwtPanel.java b/jme3-desktop/src/main/java/com/jme3/system/awt/AwtPanel.java index c09d684ff..1bdc1926e 100644 --- a/jme3-desktop/src/main/java/com/jme3/system/awt/AwtPanel.java +++ b/jme3-desktop/src/main/java/com/jme3/system/awt/AwtPanel.java @@ -155,7 +155,7 @@ public class AwtPanel extends Canvas implements SceneProcessor { public void repaintInThread(){ // Convert screenshot. byteBuf.clear(); - rm.getRenderer().readFrameBuffer(fb, byteBuf); + rm.getRenderer().readFrameBufferWithFormat(fb, byteBuf,Format.BGRA8); synchronized (lock){ // All operations on img must be synchronized @@ -168,7 +168,7 @@ public class AwtPanel extends Canvas implements SceneProcessor { public void drawFrameInThread(){ // Convert screenshot. byteBuf.clear(); - rm.getRenderer().readFrameBuffer(fb, byteBuf); + rm.getRenderer().readFrameBufferWithFormat(fb, byteBuf,Format.BGRA8); Screenshots.convertScreenShot2(intBuf, img); synchronized (lock){ diff --git a/jme3-examples/src/main/java/jme3test/post/TestRenderToCubemap.java b/jme3-examples/src/main/java/jme3test/post/TestRenderToCubemap.java index 5eced134e..e5aa79d55 100644 --- a/jme3-examples/src/main/java/jme3test/post/TestRenderToCubemap.java +++ b/jme3-examples/src/main/java/jme3test/post/TestRenderToCubemap.java @@ -97,7 +97,7 @@ public class TestRenderToCubemap extends SimpleApplication { offView.setOutputFrameBuffer(offBuffer); // setup framebuffer's scene - Box boxMesh = new Box(Vector3f.ZERO, 1,1,1); + Box boxMesh = new Box( 1,1,1); Material material = assetManager.loadMaterial("Interface/Logo/Logo.j3m"); offBox = new Geometry("box", boxMesh); offBox.setMaterial(material); diff --git a/jme3-examples/src/main/java/jme3test/post/TestRenderToMemory.java b/jme3-examples/src/main/java/jme3test/post/TestRenderToMemory.java index 550a68949..b8d0f40d4 100644 --- a/jme3-examples/src/main/java/jme3test/post/TestRenderToMemory.java +++ b/jme3-examples/src/main/java/jme3test/post/TestRenderToMemory.java @@ -48,6 +48,7 @@ import com.jme3.scene.shape.Box; import com.jme3.system.AppSettings; import com.jme3.system.JmeContext.Type; import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Image; import com.jme3.texture.Image.Format; import com.jme3.texture.Texture2D; import com.jme3.util.BufferUtils; @@ -158,7 +159,7 @@ public class TestRenderToMemory extends SimpleApplication implements SceneProces public void updateImageContents(){ cpuBuf.clear(); - renderer.readFrameBuffer(offBuffer, cpuBuf); + renderer.readFrameBufferWithFormat(offBuffer, cpuBuf, Image.Format.BGRA8); synchronized (image) { Screenshots.convertScreenShot(cpuBuf, image); diff --git a/jme3-ios/src/main/java/com/jme3/renderer/ios/IGLESShaderRenderer.java b/jme3-ios/src/main/java/com/jme3/renderer/ios/IGLESShaderRenderer.java index 957569ddd..e0b6e0a08 100644 --- a/jme3-ios/src/main/java/com/jme3/renderer/ios/IGLESShaderRenderer.java +++ b/jme3-ios/src/main/java/com/jme3/renderer/ios/IGLESShaderRenderer.java @@ -2593,4 +2593,8 @@ public class IGLESShaderRenderer implements Renderer { public void setLinearizeSrgbImages(boolean linearize) { } + + public void readFrameBufferWithFormat(FrameBuffer fb, ByteBuffer byteBuf, Image.Format format) { + throw new UnsupportedOperationException("Not supported yet. URA will make that work seamlessly"); + } } \ No newline at end of file diff --git a/jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglRenderer.java b/jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglRenderer.java index f04e61a88..8fa9d144a 100644 --- a/jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglRenderer.java +++ b/jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglRenderer.java @@ -2713,4 +2713,8 @@ public class JoglRenderer implements Renderer { public void setLinearizeSrgbImages(boolean linearize) { linearizeSrgbImages = linearize; } + + public void readFrameBufferWithFormat(FrameBuffer fb, ByteBuffer byteBuf, Image.Format format) { + throw new UnsupportedOperationException("Not supported yet. URA will make that work seamlessly"); + } } diff --git a/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglRenderer.java b/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglRenderer.java index 8d74b90cf..74ee6de88 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglRenderer.java +++ b/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglRenderer.java @@ -84,8 +84,13 @@ import static org.lwjgl.opengl.GL15.*; import static org.lwjgl.opengl.GL20.*; import org.lwjgl.opengl.GL30; - -public class LwjglRenderer implements Renderer { +/** + * + * Should not be used, has been replaced by Unified Rendering Architechture. + * @deprecated + */ +@Deprecated +public class LwjglRenderer { private static final Logger logger = Logger.getLogger(LwjglRenderer.class.getName()); private static final boolean VALIDATE_SHADER = false; @@ -135,12 +140,12 @@ public class LwjglRenderer implements Renderer { nameBuf.rewind(); } - @Override +// @Override public Statistics getStatistics() { return statistics; } - @Override + // @Override public EnumSet getCaps() { return caps; } diff --git a/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/TextureUtil.java b/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/TextureUtil.java index ef8ea399a..bcd9cb8de 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/TextureUtil.java +++ b/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/TextureUtil.java @@ -49,7 +49,6 @@ import static org.lwjgl.opengl.ARBTextureMultisample.*; import static org.lwjgl.opengl.EXTPackedDepthStencil.*; import static org.lwjgl.opengl.EXTPackedFloat.*; import static org.lwjgl.opengl.EXTTextureArray.*; -import static org.lwjgl.opengl.EXTTextureCompressionLATC.*; import static org.lwjgl.opengl.EXTTextureCompressionS3TC.*; import static org.lwjgl.opengl.EXTTextureSRGB.*; import static org.lwjgl.opengl.EXTTextureSharedExponent.*; @@ -58,6 +57,12 @@ import static org.lwjgl.opengl.GL12.*; import static org.lwjgl.opengl.GL13.*; import static org.lwjgl.opengl.GL14.*; +/** + * + * Should not be used, has been replaced by Unified Rendering Architechture. + * @deprecated + */ +@Deprecated class TextureUtil { static class GLImageFormat { diff --git a/jme3-plugins/src/ogre/java/com/jme3/scene/plugins/ogre/MaterialLoader.java b/jme3-plugins/src/ogre/java/com/jme3/scene/plugins/ogre/MaterialLoader.java index 03660ae74..36b67b04e 100644 --- a/jme3-plugins/src/ogre/java/com/jme3/scene/plugins/ogre/MaterialLoader.java +++ b/jme3-plugins/src/ogre/java/com/jme3/scene/plugins/ogre/MaterialLoader.java @@ -159,6 +159,11 @@ public class MaterialLoader implements AssetLoader { String[] split = statement.getLine().split(" ", 2); String keyword = split[0]; if (keyword.equals("texture")){ + if (split.length < 2) { + logger.log(Level.WARNING, "Invalid texture directive, no image specified at [{0}]", + statement.getLineNumber()); + return; + } readTextureImage(split[1]); }else if (keyword.equals("tex_address_mode")){ String mode = split[1];