1 |
e0a16874
|
Leszek Koltunski
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
2 |
|
|
// Copyright 2016 Leszek Koltunski //
|
3 |
|
|
// //
|
4 |
|
|
// This file is part of Distorted. //
|
5 |
|
|
// //
|
6 |
|
|
// Distorted is free software: you can redistribute it and/or modify //
|
7 |
|
|
// it under the terms of the GNU General Public License as published by //
|
8 |
|
|
// the Free Software Foundation, either version 2 of the License, or //
|
9 |
|
|
// (at your option) any later version. //
|
10 |
|
|
// //
|
11 |
|
|
// Distorted is distributed in the hope that it will be useful, //
|
12 |
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
13 |
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
14 |
|
|
// GNU General Public License for more details. //
|
15 |
|
|
// //
|
16 |
|
|
// You should have received a copy of the GNU General Public License //
|
17 |
|
|
// along with Distorted. If not, see <http://www.gnu.org/licenses/>. //
|
18 |
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
19 |
|
|
|
20 |
a4835695
|
Leszek Koltunski
|
package org.distorted.library.type;
|
21 |
6a06a912
|
Leszek Koltunski
|
|
22 |
|
|
import java.util.Random;
|
23 |
|
|
|
24 |
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
25 |
437bc43e
|
Leszek Koltunski
|
/** A class to interpolate between a List of Float{1,2,3,4}Ds.
|
26 |
6a06a912
|
Leszek Koltunski
|
* <p><ul>
|
27 |
|
|
* <li>if there is only one Point, just jump to it.
|
28 |
|
|
* <li>if there are two Points, linearly bounce between them
|
29 |
|
|
* <li>if there are more, interpolate a loop (or a path!) between them.
|
30 |
|
|
* </ul>
|
31 |
|
|
*/
|
32 |
|
|
|
33 |
|
|
// The way Interpolation between more than 2 Points is done:
|
34 |
|
|
//
|
35 |
|
|
// Def: let w[i] = (w[i](x), w[i](y), w[i](z)) be the direction and speed we have to be flying at Point P[i]
|
36 |
|
|
//
|
37 |
|
|
// time it takes to fly though one segment v[i] --> v[i+1] : 0.0 --> 1.0
|
38 |
|
|
// w[i] should be parallel to v[i+1] - v[i-1] (cyclic notation)
|
39 |
|
|
// |w[i]| proportional to | P[i]-P[i+1] |
|
40 |
|
|
//
|
41 |
|
|
// Given that the flight route (X(t), Y(t), Z(t)) from P(i) to P(i+1) (0<=t<=1) has to satisfy
|
42 |
|
|
// X(0) = P[i ](x), Y(0)=P[i ](y), Z(0)=P[i ](z), X'(0) = w[i ](x), Y'(0) = w[i ](y), Z'(0) = w[i ](z)
|
43 |
|
|
// X(1) = P[i+1](x), Y(1)=P[i+1](y), Z(1)=P[i+1](z), X'(1) = w[i+1](x), Y'(1) = w[i+1](y), Z'(1) = w[i+1](z)
|
44 |
|
|
//
|
45 |
|
|
// we have the solution: X(t) = at^3 + bt^2 + ct + d where
|
46 |
|
|
// a = 2*P[i](x) + w[i](x) - 2*P[i+1](x) + w[i+1](x)
|
47 |
|
|
// b = -3*P[i](x) - 2*w[i](x) + 3*P[i+1](x) - w[i+1](x)
|
48 |
|
|
// c = w[i](x)<br>
|
49 |
|
|
// d = P[i](x)
|
50 |
|
|
//
|
51 |
|
|
// and similarly Y(t) and Z(t).
|
52 |
|
|
|
53 |
568b29d8
|
Leszek Koltunski
|
public abstract class Dynamic
|
54 |
6a06a912
|
Leszek Koltunski
|
{
|
55 |
|
|
/**
|
56 |
|
|
* One revolution takes us from the first vector to the last and back to first through the shortest path.
|
57 |
|
|
*/
|
58 |
|
|
public static final int MODE_LOOP = 0;
|
59 |
|
|
/**
|
60 |
|
|
* We come back from the last to the first vector through the same way we got there.
|
61 |
|
|
*/
|
62 |
|
|
public static final int MODE_PATH = 1;
|
63 |
|
|
/**
|
64 |
|
|
* We just jump back from the last point to the first.
|
65 |
|
|
*/
|
66 |
|
|
public static final int MODE_JUMP = 2;
|
67 |
|
|
|
68 |
|
|
protected static Random mRnd = new Random();
|
69 |
|
|
|
70 |
|
|
protected static final int NUM_NOISE = 5; // used iff mNoise>0.0. Number of intermediary points between each pair of adjacent vectors
|
71 |
|
|
// where we randomize noise factors to make the way between the two vectors not so smooth.
|
72 |
|
|
protected int numPoints;
|
73 |
|
|
protected int mVecCurr;
|
74 |
|
|
protected boolean cacheDirty; // VectorCache not up to date
|
75 |
|
|
protected int mMode; // LOOP, PATH or JUMP
|
76 |
|
|
protected long mDuration; // number of miliseconds it takes to do a full loop/path from first vector to the last and back to the first
|
77 |
|
|
protected float mCount; // number of loops/paths we will do; mCount = 1.5 means we go from the first vector to the last, back to first, and to the last again.
|
78 |
|
|
protected float mNoise; // how 'smooth' our path form each vector to the next is. mNoise = 0.0 (min) --> completely smooth; mNoise==1.0 (max) --> very uneven
|
79 |
|
|
|
80 |
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
81 |
|
|
// hide this from Javadoc
|
82 |
|
|
|
83 |
568b29d8
|
Leszek Koltunski
|
Dynamic()
|
84 |
6a06a912
|
Leszek Koltunski
|
{
|
85 |
|
|
}
|
86 |
|
|
|
87 |
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
88 |
|
|
|
89 |
e0a16874
|
Leszek Koltunski
|
public void interpolateMain(float[] buffer, int offset, long currentDuration)
|
90 |
6a06a912
|
Leszek Koltunski
|
{
|
91 |
|
|
if( mDuration<=0.0f )
|
92 |
|
|
{
|
93 |
|
|
interpolate(buffer,offset,mCount-(int)mCount);
|
94 |
|
|
}
|
95 |
|
|
else
|
96 |
|
|
{
|
97 |
|
|
float x = (float)currentDuration/mDuration;
|
98 |
|
|
|
99 |
|
|
if( x<=mCount || mCount<=0.0f )
|
100 |
|
|
{
|
101 |
|
|
interpolate(buffer,offset,x-(int)x);
|
102 |
|
|
}
|
103 |
|
|
}
|
104 |
|
|
}
|
105 |
|
|
|
106 |
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
107 |
|
|
|
108 |
e0a16874
|
Leszek Koltunski
|
public boolean interpolateMain(float[] buffer, int offset, long currentDuration, long step)
|
109 |
6a06a912
|
Leszek Koltunski
|
{
|
110 |
|
|
if( mDuration<=0.0f )
|
111 |
|
|
{
|
112 |
|
|
interpolate(buffer,offset,mCount-(int)mCount);
|
113 |
|
|
return false;
|
114 |
|
|
}
|
115 |
|
|
|
116 |
|
|
float x = (float)currentDuration/mDuration;
|
117 |
|
|
|
118 |
|
|
if( x<=mCount || mCount<=0.0f )
|
119 |
|
|
{
|
120 |
|
|
interpolate(buffer,offset,x-(int)x);
|
121 |
|
|
|
122 |
|
|
if( currentDuration+step > mDuration*mCount && mCount>0.0f )
|
123 |
|
|
{
|
124 |
|
|
interpolate(buffer,offset,mCount-(int)mCount);
|
125 |
|
|
return true;
|
126 |
|
|
}
|
127 |
|
|
}
|
128 |
|
|
|
129 |
|
|
return false;
|
130 |
|
|
}
|
131 |
|
|
|
132 |
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
133 |
|
|
// internal debugging only!
|
134 |
|
|
|
135 |
a4835695
|
Leszek Koltunski
|
public String print()
|
136 |
6a06a912
|
Leszek Koltunski
|
{
|
137 |
|
|
return "duration="+mDuration+" count="+mCount+" Noise="+mNoise+" numVectors="+numPoints+" mMode="+mMode;
|
138 |
|
|
}
|
139 |
|
|
|
140 |
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
141 |
|
|
|
142 |
|
|
abstract void interpolate(float[] buffer, int offset, float time);
|
143 |
|
|
abstract void createNoise();
|
144 |
|
|
|
145 |
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
146 |
|
|
// PUBLIC API
|
147 |
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
148 |
|
|
/**
|
149 |
|
|
* Sets the mode of the interpolation to Loop, Path or Jump.
|
150 |
|
|
* <ul>
|
151 |
|
|
* <li>Loop is when we go from the first point all the way to the last, and the back to the first through
|
152 |
|
|
* the shortest way.
|
153 |
|
|
* <li>Path is when we come back from the last point back to the first the same way we got there.
|
154 |
|
|
* <li>Jump is when we go from first to last and then jump back to the first.
|
155 |
|
|
* </ul>
|
156 |
|
|
*
|
157 |
568b29d8
|
Leszek Koltunski
|
* @param mode {@link Dynamic#MODE_LOOP}, {@link Dynamic#MODE_PATH} or {@link Dynamic#MODE_JUMP}.
|
158 |
6a06a912
|
Leszek Koltunski
|
*/
|
159 |
|
|
|
160 |
|
|
public void setMode(int mode)
|
161 |
|
|
{
|
162 |
|
|
mMode = mode;
|
163 |
|
|
}
|
164 |
|
|
|
165 |
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
166 |
|
|
/**
|
167 |
568b29d8
|
Leszek Koltunski
|
* Returns the number of Float{1,2,3,4}Ds this Dynamic has been fed with.
|
168 |
6a06a912
|
Leszek Koltunski
|
*
|
169 |
437bc43e
|
Leszek Koltunski
|
* @return the number of Float{1,2,3,4}Ds we are currently interpolating through.
|
170 |
6a06a912
|
Leszek Koltunski
|
*/
|
171 |
|
|
public synchronized int getNumPoints()
|
172 |
|
|
{
|
173 |
|
|
return numPoints;
|
174 |
|
|
}
|
175 |
|
|
|
176 |
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
177 |
|
|
/**
|
178 |
|
|
* Controls how many times we want to interpolate.
|
179 |
|
|
* <p>
|
180 |
437bc43e
|
Leszek Koltunski
|
* Count equal to 1 means 'go from the first Float{1,2,3,4}D to the last and back'. Does not have to be an
|
181 |
6a06a912
|
Leszek Koltunski
|
* integer - i.e. count=1.5 would mean 'start at the first Point, go to the last, come back to the first,
|
182 |
|
|
* go to the last again and stop'.
|
183 |
|
|
* Count<=0 means 'go on interpolating indefinitely'.
|
184 |
|
|
*
|
185 |
437bc43e
|
Leszek Koltunski
|
* @param count the number of times we want to interpolate between our collection of Float{1,2,3,4}Ds.
|
186 |
6a06a912
|
Leszek Koltunski
|
*/
|
187 |
|
|
public void setCount(float count)
|
188 |
|
|
{
|
189 |
|
|
mCount = count;
|
190 |
|
|
}
|
191 |
|
|
|
192 |
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
193 |
|
|
/**
|
194 |
|
|
* Sets the time it takes to do one full interpolation.
|
195 |
|
|
*
|
196 |
|
|
* @param duration Time, in milliseconds, it takes to do one full interpolation, i.e. go from the first
|
197 |
|
|
* Point to the last and back.
|
198 |
|
|
*/
|
199 |
|
|
|
200 |
|
|
public void setDuration(long duration)
|
201 |
|
|
{
|
202 |
|
|
mDuration = duration;
|
203 |
|
|
}
|
204 |
|
|
|
205 |
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
206 |
|
|
/**
|
207 |
|
|
* Sets the 'smoothness' of interpolation.
|
208 |
|
|
* <p>
|
209 |
|
|
* When Noise=0 (the default), we interpolate between our Points through the most smooth path possible.
|
210 |
568b29d8
|
Leszek Koltunski
|
* Increasing noise makes the Dynamic increasingly deviate from this path, pseudo-randomly speeding
|
211 |
6a06a912
|
Leszek Koltunski
|
* up and slowing down, etc.
|
212 |
|
|
*
|
213 |
|
|
* @param noise The noise level. Permitted range: 0 <= noise <= 1.
|
214 |
|
|
*/
|
215 |
|
|
|
216 |
|
|
public void setNoise(float noise)
|
217 |
|
|
{
|
218 |
|
|
if( mNoise==0.0f && noise != 0.0f )
|
219 |
|
|
createNoise();
|
220 |
|
|
|
221 |
|
|
if( mNoise<0.0f ) mNoise = 0.0f;
|
222 |
|
|
if( mNoise>1.0f ) mNoise = 1.0f;
|
223 |
|
|
|
224 |
|
|
mNoise = noise;
|
225 |
|
|
}
|
226 |
|
|
|
227 |
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
228 |
|
|
// end of DistortedInterpolator
|
229 |
|
|
}
|