| 1 | using System; | 
 
 
 
 
 | 2 | using System.Collections.Generic; | 
 
 
 
 
 | 3 |  | 
 
 
 
 
 | 4 | namespace Oni.Dae | 
 
 
 
 
 | 5 | { | 
 
 
 
 
 | 6 | internal class Sampler : Entity | 
 
 
 
 
 | 7 | { | 
 
 
 
 
 | 8 | private readonly List<Input> inputs = new List<Input>(); | 
 
 
 
 
 | 9 | private float outputScale = 1.0f; | 
 
 
 
 
 | 10 |  | 
 
 
 
 
 | 11 | public List<Input> Inputs => inputs; | 
 
 
 
 
 | 12 |  | 
 
 
 
 
 | 13 | public int FrameCount | 
 
 
 
 
 | 14 | { | 
 
 
 
 
 | 15 | get | 
 
 
 
 
 | 16 | { | 
 
 
 
 
 | 17 | var input = inputs.Find(i => i.Semantic == Semantic.Input); | 
 
 
 
 
 | 18 |  | 
 
 
 
 
 | 19 | if (input == null) | 
 
 
 
 
 | 20 | return 0; | 
 
 
 
 
 | 21 |  | 
 
 
 
 
 | 22 | return FMath.RoundToInt32(input.Source.FloatData.Last() * 60.0f) + 1; | 
 
 
 
 
 | 23 | } | 
 
 
 
 
 | 24 | } | 
 
 
 
 
 | 25 |  | 
 
 
 
 
 | 26 | public Sampler Scale(float scale) | 
 
 
 
 
 | 27 | { | 
 
 
 
 
 | 28 | var newSampler = new Sampler | 
 
 
 
 
 | 29 | { | 
 
 
 
 
 | 30 | outputScale = scale | 
 
 
 
 
 | 31 | }; | 
 
 
 
 
 | 32 |  | 
 
 
 
 
 | 33 | newSampler.inputs.AddRange(inputs); | 
 
 
 
 
 | 34 |  | 
 
 
 
 
 | 35 | return newSampler; | 
 
 
 
 
 | 36 | } | 
 
 
 
 
 | 37 |  | 
 
 
 
 
 | 38 | public Sampler Split(int offset) | 
 
 
 
 
 | 39 | { | 
 
 
 
 
 | 40 | var newSampler = new Sampler(); | 
 
 
 
 
 | 41 |  | 
 
 
 
 
 | 42 | foreach (var input in inputs) | 
 
 
 
 
 | 43 | { | 
 
 
 
 
 | 44 | var source = input.Source; | 
 
 
 
 
 | 45 |  | 
 
 
 
 
 | 46 | switch (input.Semantic) | 
 
 
 
 
 | 47 | { | 
 
 
 
 
 | 48 | case Semantic.Input: | 
 
 
 
 
 | 49 | newSampler.inputs.Add(input); | 
 
 
 
 
 | 50 | break; | 
 
 
 
 
 | 51 |  | 
 
 
 
 
 | 52 | case Semantic.Interpolation: | 
 
 
 
 
 | 53 | newSampler.inputs.Add(input); | 
 
 
 
 
 | 54 | break; | 
 
 
 
 
 | 55 |  | 
 
 
 
 
 | 56 | case Semantic.Output: | 
 
 
 
 
 | 57 | { | 
 
 
 
 
 | 58 | var data = new float[source.Count]; | 
 
 
 
 
 | 59 |  | 
 
 
 
 
 | 60 | for (int i = 0; i < data.Length; i++) | 
 
 
 
 
 | 61 | data[i] = source.FloatData[i * source.Stride + offset]; | 
 
 
 
 
 | 62 |  | 
 
 
 
 
 | 63 | newSampler.inputs.Add(new Input | 
 
 
 
 
 | 64 | { | 
 
 
 
 
 | 65 | Source = new Source(data, 1), | 
 
 
 
 
 | 66 | Semantic = input.Semantic | 
 
 
 
 
 | 67 | }); | 
 
 
 
 
 | 68 | } | 
 
 
 
 
 | 69 | break; | 
 
 
 
 
 | 70 |  | 
 
 
 
 
 | 71 | case Semantic.InTangent: | 
 
 
 
 
 | 72 | case Semantic.OutTangent: | 
 
 
 
 
 | 73 | { | 
 
 
 
 
 | 74 | var data = new float[source.Count * 2]; | 
 
 
 
 
 | 75 |  | 
 
 
 
 
 | 76 | for (int i = 0; i < data.Length; i++) | 
 
 
 
 
 | 77 | { | 
 
 
 
 
 | 78 | data[i + 0] = source.FloatData[i * source.Stride]; | 
 
 
 
 
 | 79 | data[i + 1] = source.FloatData[i * source.Stride + (offset + 1)]; | 
 
 
 
 
 | 80 | } | 
 
 
 
 
 | 81 |  | 
 
 
 
 
 | 82 | newSampler.inputs.Add(new Input | 
 
 
 
 
 | 83 | { | 
 
 
 
 
 | 84 | Source = new Source(data, 2), | 
 
 
 
 
 | 85 | Semantic = input.Semantic | 
 
 
 
 
 | 86 | }); | 
 
 
 
 
 | 87 | } | 
 
 
 
 
 | 88 | break; | 
 
 
 
 
 | 89 | } | 
 
 
 
 
 | 90 | } | 
 
 
 
 
 | 91 |  | 
 
 
 
 
 | 92 | return newSampler; | 
 
 
 
 
 | 93 | } | 
 
 
 
 
 | 94 |  | 
 
 
 
 
 | 95 | public float[] Sample() => Sample(0, FrameCount - 1); | 
 
 
 
 
 | 96 |  | 
 
 
 
 
 | 97 | public float[] Sample(int start, int end) | 
 
 
 
 
 | 98 | { | 
 
 
 
 
 | 99 | var result = Sample(start, end, 0); | 
 
 
 
 
 | 100 |  | 
 
 
 
 
 | 101 | if (outputScale != 1.0f) | 
 
 
 
 
 | 102 | { | 
 
 
 
 
 | 103 | for (int i = 0; i < result.Length; i++) | 
 
 
 
 
 | 104 | result[i] *= outputScale; | 
 
 
 
 
 | 105 | } | 
 
 
 
 
 | 106 |  | 
 
 
 
 
 | 107 | return result; | 
 
 
 
 
 | 108 | } | 
 
 
 
 
 | 109 |  | 
 
 
 
 
 | 110 | private float[] Sample(int start, int end, int offset) | 
 
 
 
 
 | 111 | { | 
 
 
 
 
 | 112 | float[] input = null; | 
 
 
 
 
 | 113 | float[] output = null; | 
 
 
 
 
 | 114 | int outputStride = 1; | 
 
 
 
 
 | 115 | Vector2[] inTangent = null; | 
 
 
 
 
 | 116 | Vector2[] outTangent = null; | 
 
 
 
 
 | 117 | string[] interpolation = null; | 
 
 
 
 
 | 118 |  | 
 
 
 
 
 | 119 | foreach (var i in inputs) | 
 
 
 
 
 | 120 | { | 
 
 
 
 
 | 121 | switch (i.Semantic) | 
 
 
 
 
 | 122 | { | 
 
 
 
 
 | 123 | case Semantic.Input: | 
 
 
 
 
 | 124 | input = i.Source.FloatData; | 
 
 
 
 
 | 125 | break; | 
 
 
 
 
 | 126 |  | 
 
 
 
 
 | 127 | case Semantic.Output: | 
 
 
 
 
 | 128 | output = i.Source.FloatData; | 
 
 
 
 
 | 129 | outputStride = i.Source.Stride; | 
 
 
 
 
 | 130 | break; | 
 
 
 
 
 | 131 |  | 
 
 
 
 
 | 132 | case Semantic.InTangent: | 
 
 
 
 
 | 133 | inTangent = FloatArrayToVector2Array(i.Source.FloatData); | 
 
 
 
 
 | 134 | break; | 
 
 
 
 
 | 135 |  | 
 
 
 
 
 | 136 | case Semantic.OutTangent: | 
 
 
 
 
 | 137 | outTangent = FloatArrayToVector2Array(i.Source.FloatData); | 
 
 
 
 
 | 138 | break; | 
 
 
 
 
 | 139 |  | 
 
 
 
 
 | 140 | case Semantic.Interpolation: | 
 
 
 
 
 | 141 | interpolation = i.Source.NameData; | 
 
 
 
 
 | 142 | break; | 
 
 
 
 
 | 143 | } | 
 
 
 
 
 | 144 | } | 
 
 
 
 
 | 145 |  | 
 
 
 
 
 | 146 | if (offset >= outputStride) | 
 
 
 
 
 | 147 | throw new ArgumentException("The offset must be less than the output stride", "offset"); | 
 
 
 
 
 | 148 |  | 
 
 
 
 
 | 149 | float[] result = new float[end - start + 1]; | 
 
 
 
 
 | 150 |  | 
 
 
 
 
 | 151 | if (input == null || output == null || interpolation == null) | 
 
 
 
 
 | 152 | { | 
 
 
 
 
 | 153 | // | 
 
 
 
 
 | 154 | // If we don't have enough data to sample then we just return 0 for all frames. | 
 
 
 
 
 | 155 | // | 
 
 
 
 
 | 156 |  | 
 
 
 
 
 | 157 | return result; | 
 
 
 
 
 | 158 | } | 
 
 
 
 
 | 159 |  | 
 
 
 
 
 | 160 | if (output.Length == outputStride) | 
 
 
 
 
 | 161 | { | 
 
 
 
 
 | 162 | // | 
 
 
 
 
 | 163 | // If the output contains only one element then use that for all frames. | 
 
 
 
 
 | 164 | // | 
 
 
 
 
 | 165 |  | 
 
 
 
 
 | 166 | for (int i = 0; i < result.Length; i++) | 
 
 
 
 
 | 167 | result[i] = output[offset]; | 
 
 
 
 
 | 168 |  | 
 
 
 
 
 | 169 | return result; | 
 
 
 
 
 | 170 | } | 
 
 
 
 
 | 171 |  | 
 
 
 
 
 | 172 | float inputFirst = input.First(); | 
 
 
 
 
 | 173 | float outputFirst = output[offset]; | 
 
 
 
 
 | 174 |  | 
 
 
 
 
 | 175 | float inputLast = input.Last(); | 
 
 
 
 
 | 176 | float outputLast = output[output.Length - outputStride + offset]; | 
 
 
 
 
 | 177 |  | 
 
 
 
 
 | 178 | for (int frame = 0; frame < result.Length; frame++) | 
 
 
 
 
 | 179 | { | 
 
 
 
 
 | 180 | float t = (frame + start) / 60.0f; | 
 
 
 
 
 | 181 |  | 
 
 
 
 
 | 182 | if (t <= inputFirst) | 
 
 
 
 
 | 183 | { | 
 
 
 
 
 | 184 | result[frame] = outputFirst; | 
 
 
 
 
 | 185 | continue; | 
 
 
 
 
 | 186 | } | 
 
 
 
 
 | 187 |  | 
 
 
 
 
 | 188 | if (t >= inputLast) | 
 
 
 
 
 | 189 | { | 
 
 
 
 
 | 190 | result[frame] = outputLast; | 
 
 
 
 
 | 191 | continue; | 
 
 
 
 
 | 192 | } | 
 
 
 
 
 | 193 |  | 
 
 
 
 
 | 194 | int index = Array.BinarySearch(input, t); | 
 
 
 
 
 | 195 |  | 
 
 
 
 
 | 196 | if (index >= 0) | 
 
 
 
 
 | 197 | { | 
 
 
 
 
 | 198 | result[frame] = output[index * outputStride + offset]; | 
 
 
 
 
 | 199 | continue; | 
 
 
 
 
 | 200 | } | 
 
 
 
 
 | 201 |  | 
 
 
 
 
 | 202 | index = ~index; | 
 
 
 
 
 | 203 |  | 
 
 
 
 
 | 204 | if (index == 0) | 
 
 
 
 
 | 205 | { | 
 
 
 
 
 | 206 | result[frame] = outputFirst; | 
 
 
 
 
 | 207 | continue; | 
 
 
 
 
 | 208 | } | 
 
 
 
 
 | 209 |  | 
 
 
 
 
 | 210 | if (index * outputStride + offset >= output.Length) | 
 
 
 
 
 | 211 | { | 
 
 
 
 
 | 212 | result[frame] = outputLast; | 
 
 
 
 
 | 213 | continue; | 
 
 
 
 
 | 214 | } | 
 
 
 
 
 | 215 |  | 
 
 
 
 
 | 216 | var p0 = new Vector2(input[index - 1], output[(index - 1) * outputStride + offset]); | 
 
 
 
 
 | 217 | var p1 = new Vector2(input[index], output[index * outputStride + offset]); | 
 
 
 
 
 | 218 |  | 
 
 
 
 
 | 219 | float s = (t - p0.X) / (p1.X - p0.X); | 
 
 
 
 
 | 220 |  | 
 
 
 
 
 | 221 | switch (interpolation[index - 1]) | 
 
 
 
 
 | 222 | { | 
 
 
 
 
 | 223 | default: | 
 
 
 
 
 | 224 | Console.Error.WriteLine("Interpolation type '{0}' is not supported, using LINEAR", interpolation[index - 1]); | 
 
 
 
 
 | 225 | goto case "LINEAR"; | 
 
 
 
 
 | 226 |  | 
 
 
 
 
 | 227 | case "LINEAR": | 
 
 
 
 
 | 228 | result[frame] = p0.Y + s * (p1.Y - p0.Y); | 
 
 
 
 
 | 229 | break; | 
 
 
 
 
 | 230 |  | 
 
 
 
 
 | 231 | case "BEZIER": | 
 
 
 
 
 | 232 | if (inTangent == null || outTangent == null) | 
 
 
 
 
 | 233 | throw new System.IO.InvalidDataException("Bezier interpolation was specified but in/out tangents are not present"); | 
 
 
 
 
 | 234 |  | 
 
 
 
 
 | 235 | var c0 = outTangent[index - 1]; | 
 
 
 
 
 | 236 | var c1 = inTangent[index]; | 
 
 
 
 
 | 237 |  | 
 
 
 
 
 | 238 | float invS = 1.0f - s; | 
 
 
 
 
 | 239 |  | 
 
 
 
 
 | 240 | result[frame] = | 
 
 
 
 
 | 241 | p0.Y * invS * invS * invS | 
 
 
 
 
 | 242 | + 3.0f * c0.Y * invS * invS * s | 
 
 
 
 
 | 243 | + 3.0f * c1.Y * invS * s * s | 
 
 
 
 
 | 244 | + p1.Y * s * s * s; | 
 
 
 
 
 | 245 |  | 
 
 
 
 
 | 246 | break; | 
 
 
 
 
 | 247 | } | 
 
 
 
 
 | 248 | } | 
 
 
 
 
 | 249 |  | 
 
 
 
 
 | 250 | return result; | 
 
 
 
 
 | 251 | } | 
 
 
 
 
 | 252 |  | 
 
 
 
 
 | 253 | private static Vector2[] FloatArrayToVector2Array(float[] array) | 
 
 
 
 
 | 254 | { | 
 
 
 
 
 | 255 | var result = new Vector2[array.Length / 2]; | 
 
 
 
 
 | 256 |  | 
 
 
 
 
 | 257 | for (int i = 0; i < result.Length; i++) | 
 
 
 
 
 | 258 | { | 
 
 
 
 
 | 259 | result[i].X = array[i * 2 + 0]; | 
 
 
 
 
 | 260 | result[i].Y = array[i * 2 + 1]; | 
 
 
 
 
 | 261 | } | 
 
 
 
 
 | 262 |  | 
 
 
 
 
 | 263 | return result; | 
 
 
 
 
 | 264 | } | 
 
 
 
 
 | 265 | } | 
 
 
 
 
 | 266 | } |