| 1 | using System; | 
 
 
 
 
 | 2 | using System.Collections.Generic; | 
 
 
 
 
 | 3 | using Oni.Akira; | 
 
 
 
 
 | 4 | using Oni.Motoko; | 
 
 
 
 
 | 5 |  | 
 
 
 
 
 | 6 | namespace Oni.Physics | 
 
 
 
 
 | 7 | { | 
 
 
 
 
 | 8 | internal class ObjectDaeImporter | 
 
 
 
 
 | 9 | { | 
 
 
 
 
 | 10 | private readonly TextureImporter3 textureImporter; | 
 
 
 
 
 | 11 | private readonly Dictionary<string, AkiraDaeNodeProperties> properties; | 
 
 
 
 
 | 12 | private readonly List<ObjectNode> nodes = new List<ObjectNode>(); | 
 
 
 
 
 | 13 |  | 
 
 
 
 
 | 14 | public ObjectDaeImporter(TextureImporter3 textureImporter, Dictionary<string, AkiraDaeNodeProperties> properties) | 
 
 
 
 
 | 15 | { | 
 
 
 
 
 | 16 | this.textureImporter = textureImporter; | 
 
 
 
 
 | 17 | this.properties = properties; | 
 
 
 
 
 | 18 | } | 
 
 
 
 
 | 19 |  | 
 
 
 
 
 | 20 | public List<ObjectNode> Nodes | 
 
 
 
 
 | 21 | { | 
 
 
 
 
 | 22 | get { return nodes; } | 
 
 
 
 
 | 23 | } | 
 
 
 
 
 | 24 |  | 
 
 
 
 
 | 25 | public void Import(Dae.Scene scene) | 
 
 
 
 
 | 26 | { | 
 
 
 
 
 | 27 | ImportNode(scene, null, GetNodeProperties(scene)); | 
 
 
 
 
 | 28 | } | 
 
 
 
 
 | 29 |  | 
 
 
 
 
 | 30 | private void ImportNode(Dae.Node node, List<ObjectAnimationKey> parentAnimation, ObjectDaeNodeProperties parentNodeProperties) | 
 
 
 
 
 | 31 | { | 
 
 
 
 
 | 32 | Console.WriteLine("\t{0}", node.Id); | 
 
 
 
 
 | 33 |  | 
 
 
 
 
 | 34 | var animation = ImportNodeAnimation(node, parentAnimation); | 
 
 
 
 
 | 35 | var nodeProperties = GetNodeProperties(node); | 
 
 
 
 
 | 36 |  | 
 
 
 
 
 | 37 | if (nodeProperties == null && parentNodeProperties != null) | 
 
 
 
 
 | 38 | { | 
 
 
 
 
 | 39 | nodeProperties = new ObjectDaeNodeProperties | 
 
 
 
 
 | 40 | { | 
 
 
 
 
 | 41 | HasPhysics = parentNodeProperties.HasPhysics, | 
 
 
 
 
 | 42 | ScriptId = parentNodeProperties.ScriptId, | 
 
 
 
 
 | 43 | ObjectFlags = parentNodeProperties.ObjectFlags | 
 
 
 
 
 | 44 | }; | 
 
 
 
 
 | 45 |  | 
 
 
 
 
 | 46 | // | 
 
 
 
 
 | 47 | // We can't use the same anim name when we inherit the properties of the parent, | 
 
 
 
 
 | 48 | // generate a name by appending "_anim" to the node name. | 
 
 
 
 
 | 49 | // | 
 
 
 
 
 | 50 |  | 
 
 
 
 
 | 51 | nodeProperties.Animations.AddRange( | 
 
 
 
 
 | 52 | from a in parentNodeProperties.Animations | 
 
 
 
 
 | 53 | select new ObjectAnimationClip | 
 
 
 
 
 | 54 | { | 
 
 
 
 
 | 55 | Name = node.Name + "_anim", | 
 
 
 
 
 | 56 | Start = a.Start, | 
 
 
 
 
 | 57 | Stop = a.Stop, | 
 
 
 
 
 | 58 | End = a.End, | 
 
 
 
 
 | 59 | Flags = a.Flags | 
 
 
 
 
 | 60 | }); | 
 
 
 
 
 | 61 | } | 
 
 
 
 
 | 62 |  | 
 
 
 
 
 | 63 | if (nodeProperties != null && nodeProperties.HasPhysics) | 
 
 
 
 
 | 64 | { | 
 
 
 
 
 | 65 | var geometries = GeometryDaeReader.Read(node, textureImporter).ToList(); | 
 
 
 
 
 | 66 |  | 
 
 
 
 
 | 67 | if (animation.Count > 0 || geometries.Count > 0) | 
 
 
 
 
 | 68 | { | 
 
 
 
 
 | 69 | nodes.Add(new ObjectNode(from g in geometries select new ObjectGeometry(g)) | 
 
 
 
 
 | 70 | { | 
 
 
 
 
 | 71 | Name = node.Name, | 
 
 
 
 
 | 72 | FileName = node.FileName, | 
 
 
 
 
 | 73 | Animations = CreateAnimations(animation, nodeProperties), | 
 
 
 
 
 | 74 | ScriptId = nodeProperties.ScriptId, | 
 
 
 
 
 | 75 | Flags = nodeProperties.ObjectFlags | 
 
 
 
 
 | 76 | }); | 
 
 
 
 
 | 77 | } | 
 
 
 
 
 | 78 | } | 
 
 
 
 
 | 79 |  | 
 
 
 
 
 | 80 | foreach (var child in node.Nodes) | 
 
 
 
 
 | 81 | { | 
 
 
 
 
 | 82 | ImportNode(child, animation, nodeProperties); | 
 
 
 
 
 | 83 | } | 
 
 
 
 
 | 84 | } | 
 
 
 
 
 | 85 |  | 
 
 
 
 
 | 86 | private List<ObjectAnimationKey> ImportNodeAnimation(Dae.Node node, List<ObjectAnimationKey> parentAnimation) | 
 
 
 
 
 | 87 | { | 
 
 
 
 
 | 88 | var scale = Vector3.One; | 
 
 
 
 
 | 89 | var scaleTransform = node.Transforms.OfType<Dae.TransformScale>().FirstOrDefault(); | 
 
 
 
 
 | 90 |  | 
 
 
 
 
 | 91 | if (scaleTransform != null) | 
 
 
 
 
 | 92 | { | 
 
 
 
 
 | 93 | scale.X = scaleTransform.Values[0]; | 
 
 
 
 
 | 94 | scale.Y = scaleTransform.Values[1]; | 
 
 
 
 
 | 95 | scale.Z = scaleTransform.Values[2]; | 
 
 
 
 
 | 96 | } | 
 
 
 
 
 | 97 |  | 
 
 
 
 
 | 98 | if (parentAnimation != null && parentAnimation.Count > 0) | 
 
 
 
 
 | 99 | { | 
 
 
 
 
 | 100 | scale *= parentAnimation[0].Scale; | 
 
 
 
 
 | 101 | } | 
 
 
 
 
 | 102 |  | 
 
 
 
 
 | 103 | var rotateTransforms = new List<Dae.TransformRotate>(); | 
 
 
 
 
 | 104 | var angles = new List<float[]>(); | 
 
 
 
 
 | 105 |  | 
 
 
 
 
 | 106 | foreach (var rotate in node.Transforms.OfType<Dae.TransformRotate>()) | 
 
 
 
 
 | 107 | { | 
 
 
 
 
 | 108 | rotateTransforms.Add(rotate); | 
 
 
 
 
 | 109 |  | 
 
 
 
 
 | 110 | var angleAnimation = rotate.AngleAnimation; | 
 
 
 
 
 | 111 |  | 
 
 
 
 
 | 112 | if (angleAnimation != null) | 
 
 
 
 
 | 113 | angles.Add(angleAnimation.Sample()); | 
 
 
 
 
 | 114 | else | 
 
 
 
 
 | 115 | angles.Add(new[] { rotate.Angle }); | 
 
 
 
 
 | 116 | } | 
 
 
 
 
 | 117 |  | 
 
 
 
 
 | 118 | var translateTransforms = node.Transforms.OfType<Dae.TransformTranslate>().FirstOrDefault(); | 
 
 
 
 
 | 119 | var positions = new List<float[]>(); | 
 
 
 
 
 | 120 |  | 
 
 
 
 
 | 121 | if (translateTransforms != null) | 
 
 
 
 
 | 122 | { | 
 
 
 
 
 | 123 | for (int i = 0; i < 3; i++) | 
 
 
 
 
 | 124 | { | 
 
 
 
 
 | 125 | var positionAnimation = translateTransforms.Animations[i]; | 
 
 
 
 
 | 126 |  | 
 
 
 
 
 | 127 | if (positionAnimation != null) | 
 
 
 
 
 | 128 | positions.Add(positionAnimation.Sample()); | 
 
 
 
 
 | 129 | else | 
 
 
 
 
 | 130 | positions.Add(new[] { translateTransforms.Translation[i] }); | 
 
 
 
 
 | 131 | } | 
 
 
 
 
 | 132 | } | 
 
 
 
 
 | 133 |  | 
 
 
 
 
 | 134 | var frames = new List<ObjectAnimationKey>(); | 
 
 
 
 
 | 135 | int frameCount = Math.Max(angles.Max(a => a.Length), positions.Max(a => a.Length)); | 
 
 
 
 
 | 136 |  | 
 
 
 
 
 | 137 | for (int time = 0; time < frameCount; time++) | 
 
 
 
 
 | 138 | { | 
 
 
 
 
 | 139 | var rotation = Quaternion.Identity; | 
 
 
 
 
 | 140 |  | 
 
 
 
 
 | 141 | for (int i = 0; i < rotateTransforms.Count; i++) | 
 
 
 
 
 | 142 | { | 
 
 
 
 
 | 143 | float angle; | 
 
 
 
 
 | 144 |  | 
 
 
 
 
 | 145 | float[] values = angles[i]; | 
 
 
 
 
 | 146 |  | 
 
 
 
 
 | 147 | if (time >= values.Length) | 
 
 
 
 
 | 148 | angle = values.Last(); | 
 
 
 
 
 | 149 | else | 
 
 
 
 
 | 150 | angle = values[time]; | 
 
 
 
 
 | 151 |  | 
 
 
 
 
 | 152 | rotation *= Quaternion.CreateFromAxisAngle(rotateTransforms[i].Axis, MathHelper.ToRadians(angle)); | 
 
 
 
 
 | 153 | } | 
 
 
 
 
 | 154 |  | 
 
 
 
 
 | 155 | var translation = Vector3.Zero; | 
 
 
 
 
 | 156 |  | 
 
 
 
 
 | 157 | if (translateTransforms != null) | 
 
 
 
 
 | 158 | { | 
 
 
 
 
 | 159 | translation.X = positions[0][MathHelper.Clamp(time, 0, positions[0].Length - 1)]; | 
 
 
 
 
 | 160 | translation.Y = positions[1][MathHelper.Clamp(time, 0, positions[1].Length - 1)]; | 
 
 
 
 
 | 161 | translation.Z = positions[2][MathHelper.Clamp(time, 0, positions[2].Length - 1)]; | 
 
 
 
 
 | 162 | } | 
 
 
 
 
 | 163 |  | 
 
 
 
 
 | 164 | if (parentAnimation != null) | 
 
 
 
 
 | 165 | { | 
 
 
 
 
 | 166 | var parentFrame = time < parentAnimation.Count ? parentAnimation[time] : parentAnimation.LastOrDefault(); | 
 
 
 
 
 | 167 |  | 
 
 
 
 
 | 168 | if (parentFrame != null) | 
 
 
 
 
 | 169 | { | 
 
 
 
 
 | 170 | rotation = parentFrame.Rotation * rotation; | 
 
 
 
 
 | 171 | translation = parentFrame.Translation + Vector3.Transform(translation * parentFrame.Scale, parentFrame.Rotation); | 
 
 
 
 
 | 172 | } | 
 
 
 
 
 | 173 | } | 
 
 
 
 
 | 174 |  | 
 
 
 
 
 | 175 | frames.Add(new ObjectAnimationKey | 
 
 
 
 
 | 176 | { | 
 
 
 
 
 | 177 | Time = time, | 
 
 
 
 
 | 178 | Scale = scale, | 
 
 
 
 
 | 179 | Rotation = rotation, | 
 
 
 
 
 | 180 | Translation = translation | 
 
 
 
 
 | 181 | }); | 
 
 
 
 
 | 182 | } | 
 
 
 
 
 | 183 |  | 
 
 
 
 
 | 184 | return frames; | 
 
 
 
 
 | 185 | } | 
 
 
 
 
 | 186 |  | 
 
 
 
 
 | 187 | private ObjectAnimation[] CreateAnimations(List<ObjectAnimationKey> allFrames, ObjectDaeNodeProperties props) | 
 
 
 
 
 | 188 | { | 
 
 
 
 
 | 189 | var anims = new List<ObjectAnimation>(); | 
 
 
 
 
 | 190 |  | 
 
 
 
 
 | 191 | foreach (var clip in props.Animations) | 
 
 
 
 
 | 192 | { | 
 
 
 
 
 | 193 | int start = clip.Start; | 
 
 
 
 
 | 194 | int end = clip.End != int.MaxValue ? clip.End : allFrames.Last().Time; | 
 
 
 
 
 | 195 |  | 
 
 
 
 
 | 196 | var clipFrames = (from f in allFrames | 
 
 
 
 
 | 197 | where start <= f.Time && f.Time <= end | 
 
 
 
 
 | 198 | select new ObjectAnimationKey | 
 
 
 
 
 | 199 | { | 
 
 
 
 
 | 200 | Time = f.Time - start, | 
 
 
 
 
 | 201 | Scale = f.Scale, | 
 
 
 
 
 | 202 | Rotation = f.Rotation, | 
 
 
 
 
 | 203 | Translation = f.Translation | 
 
 
 
 
 | 204 | }).ToArray(); | 
 
 
 
 
 | 205 |  | 
 
 
 
 
 | 206 | if (clipFrames.Length == 0) | 
 
 
 
 
 | 207 | continue; | 
 
 
 
 
 | 208 |  | 
 
 
 
 
 | 209 | anims.Add(new ObjectAnimation | 
 
 
 
 
 | 210 | { | 
 
 
 
 
 | 211 | Name = clip.Name, | 
 
 
 
 
 | 212 | Flags = clip.Flags, | 
 
 
 
 
 | 213 | Stop = clip.Stop, | 
 
 
 
 
 | 214 | Length = end - start + 1, | 
 
 
 
 
 | 215 | Keys = clipFrames | 
 
 
 
 
 | 216 | }); | 
 
 
 
 
 | 217 | } | 
 
 
 
 
 | 218 |  | 
 
 
 
 
 | 219 | return anims.ToArray(); | 
 
 
 
 
 | 220 | } | 
 
 
 
 
 | 221 |  | 
 
 
 
 
 | 222 | private ObjectDaeNodeProperties GetNodeProperties(Dae.Node node) | 
 
 
 
 
 | 223 | { | 
 
 
 
 
 | 224 | AkiraDaeNodeProperties nodeProperties; | 
 
 
 
 
 | 225 |  | 
 
 
 
 
 | 226 | if (properties == null || !properties.TryGetValue(node.Id, out nodeProperties)) | 
 
 
 
 
 | 227 | return null; | 
 
 
 
 
 | 228 |  | 
 
 
 
 
 | 229 | return nodeProperties as ObjectDaeNodeProperties; | 
 
 
 
 
 | 230 | } | 
 
 
 
 
 | 231 | } | 
 
 
 
 
 | 232 | } |