source: OniSplit/Dae/Sampler.cs@ 1194

Last change on this file since 1194 was 1114, checked in by iritscen, 5 years ago

Adding OniSplit source code (v0.9.99.0). Many thanks to Neo for all his work over the years.

File size: 8.3 KB
RevLine 
[1114]1using System;
2using System.Collections.Generic;
3
4namespace 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}
Note: See TracBrowser for help on using the repository browser.