Project

General

Profile

Download (14.8 KB) Statistics
| Branch: | Revision:

library / src / main / java / org / distorted / library / type / Dynamic1D.java @ 07037b8a

1
///////////////////////////////////////////////////////////////////////////////////////////////////
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
package org.distorted.library.type;
21

    
22
import java.util.Vector;
23

    
24
///////////////////////////////////////////////////////////////////////////////////////////////////
25
/** 
26
* A 1-dimensional implementation of the Dynamic class to interpolate between a list
27
* of Static1Ds.
28
*/
29

    
30
public class Dynamic1D extends Dynamic implements Data1D
31
  {
32
  private Vector<Static1D> vv;
33
  private Static1D prev, curr, next;
34

    
35
///////////////////////////////////////////////////////////////////////////////////////////////////
36
// no array bounds checking!
37
  
38
  private void vec(int c)
39
    {
40
    int p = c>0 ? c-1: numPoints-1;
41
    int n = c<numPoints-1 ? c+1: 0;
42
    
43
    prev = vv.elementAt(p);
44
    curr = vv.elementAt(c);
45
    next = vv.elementAt(n);
46

    
47
    tmp1 = vc.elementAt(c);
48
    
49
    float px = curr.x - prev.x;
50
    float nx = next.x - curr.x;
51
     
52
    float d = nx*nx;
53
    
54
    if( d>0 )
55
      {
56
      float q = (float)Math.sqrt((px*px)/d);
57
      
58
      if( q>1 )
59
        {
60
        tmp1.tangent[0] = nx+px/q;
61
        }
62
      else
63
        {
64
        tmp1.tangent[0] = px+nx*q;
65
        }
66
      }
67
    else
68
      {
69
      tmp1.tangent[0] = 0.0f;
70
      }
71
    }
72
      
73
///////////////////////////////////////////////////////////////////////////////////////////////////
74
  
75
  private void recomputeCache()
76
    {  
77
    if( numPoints==1 )
78
      {
79
      tmp1= vc.elementAt(0);
80
      curr= vv.elementAt(0);
81
        
82
      tmp1.a[0] = 0.0f;
83
      tmp1.b[0] = 0.0f;
84
      tmp1.c[0] = curr.x;
85
      tmp1.d[0] = 0.0f;
86
      }
87
    else if( numPoints==2 )
88
      {
89
      tmp1= vc.elementAt(0);
90
      tmp2= vc.elementAt(1);
91
      curr= vv.elementAt(0);
92
      next= vv.elementAt(1);
93
          
94
      tmp1.a[0] = 0.0f;
95
      tmp1.b[0] = 0.0f;
96
      tmp1.c[0] = next.x - curr.x;
97
      tmp1.d[0] = curr.x;
98
      
99
      tmp2.a[0] = 0.0f;
100
      tmp2.b[0] = 0.0f;
101
      tmp2.c[0] = curr.x - next.x;
102
      tmp2.d[0] = next.x;
103
      }
104
    else
105
      {
106
      int i, n;  
107
         
108
      for(i=0; i<numPoints; i++) vec(i);
109
   
110
      for(i=0; i<numPoints; i++)
111
        {
112
        n = i<numPoints-1 ? i+1:0;  
113
      
114
        tmp1= vc.elementAt(i);
115
        tmp2= vc.elementAt(n);
116
        curr= vv.elementAt(i);
117
        next= vv.elementAt(n);
118
    
119
        tmp1.cached[0] = curr.x;
120
        
121
        tmp1.a[0] =  2*curr.x +   tmp1.tangent[0] - 2*next.x + tmp2.tangent[0];
122
        tmp1.b[0] = -3*curr.x - 2*tmp1.tangent[0] + 3*next.x - tmp2.tangent[0];
123
        tmp1.c[0] = tmp1.tangent[0];
124
        tmp1.d[0] = curr.x;
125
        }
126
      }
127
   
128
    cacheDirty = false;
129
    }
130

    
131
///////////////////////////////////////////////////////////////////////////////////////////////////
132
// PUBLIC API
133
///////////////////////////////////////////////////////////////////////////////////////////////////
134
/**
135
 * Default constructor.
136
 */
137
  public Dynamic1D()
138
    {
139
    super(0,0.5f,1);
140
    vv = new Vector<>();
141
    }
142

    
143
///////////////////////////////////////////////////////////////////////////////////////////////////
144

    
145
/**
146
 * Default constructor.
147
 *
148
 * @param duration number of milliseconds it takes to do a full loop/path from first vector to the
149
 *                 last and back to the first
150
 * @param count    number of loops/paths we will do; mCount = 1.5 means we go from the first vector
151
 *                 to the last, back to first, and to the last again.
152
 */
153
  public Dynamic1D(int duration, float count)
154
    {
155
    super(duration,count,1);
156
    vv = new Vector<>();
157
    }
158

    
159
///////////////////////////////////////////////////////////////////////////////////////////////////
160
/**
161
 * Returns the location'th Static1D.
162
 *   
163
 * @param location the index of the Point we are interested in.
164
 * @return The Static1D, if 0<=location&lt;getNumPoints(), or null otherwise.
165
 */
166
  public synchronized Static1D getPoint(int location)
167
    {
168
    return (location>=0 && location<numPoints) ? vv.elementAt(location) : null;  
169
    }
170
  
171
///////////////////////////////////////////////////////////////////////////////////////////////////
172
/**
173
 * Resets the location'th Point.
174
 * 
175
 * @param location the index of the Point we are setting.
176
 * @param x New value of its first float.
177
 */
178
  public synchronized void setPoint(int location, float x)
179
    {
180
    if( location>=0 && location<numPoints )
181
      {
182
      curr = vv.elementAt(location);
183
   
184
      if( curr!=null )
185
        {
186
        curr.set(x);
187
        cacheDirty=true;
188
        }
189
      }
190
    }
191
 
192
///////////////////////////////////////////////////////////////////////////////////////////////////
193
/**
194
 * Adds a new Static1D to the end of our list of Points to interpolate through.
195
 * <p>   
196
 * Only a reference to the Point gets added to the List; this means that one can add a Point 
197
 * here, and later on {@link Static1D#set(float)} it to some new value and the change will
198
 * be seamlessly reflected in the interpolated path.  
199
 * <p>
200
 * A Point can be added multiple times.
201
 *   
202
 * @param v The Point to add.
203
 */
204
  public synchronized void add(Static1D v)
205
    {
206
    if( v!=null )
207
      {
208
      vv.add(v);
209
     
210
      if( vn!=null ) vn.add(new VectorNoise());
211
       
212
      switch(numPoints)
213
        {
214
        case 0: 
215
        case 1: break;
216
        case 2: vc.add(new VectorCache());
217
                vc.add(new VectorCache());
218
                vc.add(new VectorCache());
219
                cacheDirty = true;
220
                break;
221
        default:vc.add(new VectorCache());
222
                cacheDirty = true;
223
        }
224
     
225
      numPoints++;
226
      }
227
    }
228

    
229
///////////////////////////////////////////////////////////////////////////////////////////////////
230
/**
231
 * Adds a new Static1D to the location'th place in our List of Points to interpolate through.
232
 *   
233
 * @param location Index in our List to add the new Point at.
234
 * @param v The Point to add.
235
 */
236
  public synchronized void add(int location, Static1D v)
237
    {
238
    if( v!=null )
239
      {
240
      vv.add(location, v);
241
      
242
      if( vn!=null ) vn.add(new VectorNoise());
243
             
244
      switch(numPoints)
245
        {
246
        case 0:
247
        case 1: break;
248
        case 2: vc.add(new VectorCache());
249
                vc.add(new VectorCache());
250
                vc.add(new VectorCache());
251
                cacheDirty = true;
252
                break;
253
        default:vc.add(location,new VectorCache());
254
                cacheDirty = true;
255
        }
256
      
257
      numPoints++;
258
      }
259
    }
260
  
261
///////////////////////////////////////////////////////////////////////////////////////////////////
262
/**
263
 * Removes all occurrences of Point v from the List of Points to interpolate through.  
264
 * 
265
 * @param v The Point to remove.
266
 * @return <code>true</code> if we have removed at least one Point.
267
 */
268
  public synchronized boolean remove(Static1D v)
269
    {
270
    int n = vv.indexOf(v);
271
    boolean found = false;
272
   
273
    while( n>=0 ) 
274
      {
275
      vv.remove(n);
276
     
277
      if( vn!=null ) vn.remove(0);
278
     
279
      switch(numPoints)
280
        {
281
        case 0:
282
        case 1:
283
        case 2: break;
284
        case 3: vc.removeAllElements();
285
                break;
286
        default:vc.remove(n);
287
                cacheDirty=true;
288
        }
289

    
290
      numPoints--;
291
      found = true;
292
      n = vv.indexOf(v);
293
      }
294
   
295
    return found;
296
    }
297

    
298
///////////////////////////////////////////////////////////////////////////////////////////////////
299
/**
300
 * Removes a location'th Point from the List of Points we interpolate through.
301
 * 
302
 * @param location index of the Point we want to remove. 
303
 * @return <code>true</code> if location is valid, i.e. if 0<=location&lt;getNumPoints().
304
 */
305
  public synchronized boolean remove(int location)
306
    {
307
    if( location>=0 && location<numPoints ) 
308
      {
309
      vv.removeElementAt(location);
310
      
311
      if( vn!=null ) vn.remove(0);
312
     
313
      switch(numPoints)
314
        {
315
        case 0:
316
        case 1: 
317
        case 2: break;
318
        case 3: vc.removeAllElements();
319
                break;
320
        default:vc.removeElementAt(location);
321
        }
322

    
323
      numPoints--;
324
      cacheDirty = true; 
325
      return true;
326
      }
327

    
328
   return false;
329
   }
330
  
331
///////////////////////////////////////////////////////////////////////////////////////////////////
332
/**
333
 * Removes all Points.
334
 */
335
  public synchronized void removeAll()
336
    {
337
    numPoints = 0;
338
    vv.removeAllElements();
339
    vc.removeAllElements();
340
    cacheDirty = false;
341
   
342
    if( vn!=null ) vn.removeAllElements();
343
    }
344

    
345
///////////////////////////////////////////////////////////////////////////////////////////////////
346
/**
347
 * Sets the 'smoothness' of interpolation.
348
 * <p>
349
 * When Noise=0 (the default), we interpolate between our Points through the most smooth path possible.
350
 * Increasing noise makes the Dynamic increasingly deviate from this path, pseudo-randomly speeding
351
 * up and slowing down, etc.
352
 *
353
 * @param noise The noise level. Permitted range: 0 <= noise <= 1.
354
 */
355

    
356
  public synchronized void setNoise(Static1D noise)
357
    {
358
    if( vn==null )
359
      {
360
      vn = new Vector<>();
361
      for(int i=0; i<numPoints; i++) vn.add(new VectorNoise());
362

    
363
      if( mDimension>=2 )
364
        {
365
        mFactor = new float[mDimension-1];
366
        }
367

    
368
      mNoise = new float[mDimension];
369
      }
370

    
371
    if( noise.x<0.0f ) noise.x = 0.0f;
372
    if( noise.x>1.0f ) noise.x = 1.0f;
373

    
374
    mNoise[0] = noise.x;
375
    }
376

    
377
///////////////////////////////////////////////////////////////////////////////////////////////////
378

    
379
  synchronized void interpolate(float[] buffer, int offset, float time)
380
    {
381
    switch(numPoints)
382
      {
383
      case 0: buffer[offset] = 0.0f;
384
              break;
385
      case 1: curr = vv.elementAt(0);
386
              buffer[offset] = curr.x;
387
              break;
388
      case 2: curr = vv.elementAt(0);
389
              next = vv.elementAt(1);
390

    
391
              int segment2= (int)(2*time);
392

    
393
              if( mMode==MODE_LOOP || mMode==MODE_PATH ) time = (time>0.5f ? 2-2*time : 2*time);
394

    
395
              if( vn!=null )
396
                {
397
                if( segment2 != mSegment )
398
                  {
399
                  if(mMode!=MODE_JUMP || mSegment==1) vn.elementAt(0).computeNoise();
400
                  mSegment = segment2;
401
                  }
402

    
403
                time = noise(time,0);
404
                }
405
             
406
              buffer[offset] = (next.x-curr.x)*time + curr.x;
407
              break;
408
      default:float t = time;
409
              int vecCurr, segment;
410

    
411
              switch(mMode)
412
                {
413
                case MODE_LOOP: time = time*numPoints;
414
                                segment = (int)time;
415
                                vecCurr = segment;
416
                                break;
417
                case MODE_PATH: segment = (int)(2*t*(numPoints-1));
418

    
419
                                if( t<=0.5f )  // this has to be <= (otherwise when effect ends at t=0.5, then time=1.0
420
                                  {            // and end position is slightly not equal to the end point => might not get autodeleted!
421
                                  time = 2*t*(numPoints-1);
422
                                  vecCurr = segment;
423
                                  }
424
                                else
425
                                  {
426
                                  time = 2*(1-t)*(numPoints-1);
427
                                  vecCurr = 2*numPoints-3-segment;
428
                                  }
429
                                break;
430
                case MODE_JUMP: time = time*(numPoints-1);
431
                                segment = (int)time;
432
                                vecCurr = segment;
433
                                break;
434
                default       : vecCurr = 0;
435
                                segment = 0;
436
                }
437

    
438
              if( vecCurr>=0 && vecCurr<numPoints )
439
                {
440
                if( cacheDirty ) recomputeCache();  // recompute cache if we have added or remove vectors since last computation
441
                else if( mSegment!= segment )       // ...or if we have just passed a vector and the vector we are currently flying to has changed
442
                  {
443
                  int vecNext;
444

    
445
                  switch(mMode)
446
                    {
447
                    case MODE_LOOP: vecNext = vecCurr==numPoints-1 ? 0:vecCurr+1;
448
                                    break;
449
                    case MODE_PATH: if( t<=0.5f ) vecNext = vecCurr==numPoints-1 ? numPoints-2: vecCurr+1;
450
                                    else          vecNext = vecCurr==0 ? 1 : vecCurr-1;
451
                                    break;
452
                    case MODE_JUMP: vecNext = vecCurr==numPoints-1 ? 1:vecCurr+1;
453
                                    break;
454
                    default       : vecNext = 0;
455
                    }
456
              
457
                  next = vv.elementAt(vecNext);
458
                  tmp2 = vc.elementAt(vecNext);
459
              
460
                  if( tmp2.cached[0]!=next.x ) recomputeCache();
461
                  }
462

    
463
                if( mSegment!= segment && vn!=null ) vn.elementAt(vecCurr).computeNoise();
464

    
465
                mSegment = segment;
466

    
467
                time = time-vecCurr;
468

    
469
                tmp1 = vc.elementAt(vecCurr);
470

    
471
                if( vn!=null )
472
                  {
473
                  time = noise(time,vecCurr);
474
                  }
475
            
476
                buffer[offset] = ((tmp1.a[0]*time+tmp1.b[0])*time+tmp1.c[0])*time+tmp1.d[0];
477
                break;
478
                }
479
        }
480
     }  
481
  
482
  }
483
///////////////////////////////////////////////////////////////////////////////////////////////////
484
//
(7-7/17)