Project

General

Profile

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

library / src / main / java / org / distorted / library / type / Dynamic3D.java @ 649544b8

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 3-dimensional implementation of the Dynamic class to interpolate between a list
27
* of Static3Ds.
28
*/
29

    
30
public class Dynamic3D extends Dynamic implements Data3D
31
  {
32
  private Vector<Static3D> vv;
33
  private Static3D 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 py = curr.y - prev.y;
51
    float pz = curr.z - prev.z;
52
    float nx = next.x - curr.x;
53
    float ny = next.y - curr.y;
54
    float nz = next.z - curr.z;
55
     
56
    float d = nx*nx+ny*ny+nz*nz;
57
    
58
    if( d>0 )
59
      {
60
      float q = (float)Math.sqrt((px*px+py*py+pz*pz)/d);
61
      
62
      if( q>1 )
63
        {
64
        tmp1.tangent[0] = nx+px/q;
65
        tmp1.tangent[1] = ny+py/q;
66
        tmp1.tangent[2] = nz+pz/q;
67
        }
68
      else
69
        {
70
        tmp1.tangent[0] = px+nx*q;
71
        tmp1.tangent[1] = py+ny*q;
72
        tmp1.tangent[2] = pz+nz*q;
73
        }
74
      }
75
    else
76
      {
77
      tmp1.tangent[0] = 0.0f;
78
      tmp1.tangent[1] = 0.0f;
79
      tmp1.tangent[2] = 0.0f;
80
      }
81
    }
82
    
83
///////////////////////////////////////////////////////////////////////////////////////////////////
84
  
85
  private void recomputeCache()
86
    {  
87
    if( numPoints==1 )
88
      {
89
      tmp1= vc.elementAt(0);
90
      curr= vv.elementAt(0);
91
        
92
      tmp1.a[0] = tmp1.a[1] = tmp1.a[2] = 0.0f;
93
      tmp1.b[0] = tmp1.b[1] = tmp1.b[2] = 0.0f;
94
      tmp1.c[0] = curr.x;
95
      tmp1.c[1] = curr.y;
96
      tmp1.c[2] = curr.z;
97
      tmp1.d[0] = tmp1.d[1] = tmp1.d[2] = 0.0f;
98
      }
99
    else if( numPoints==2 )
100
      {
101
      tmp1= vc.elementAt(0);
102
      tmp2= vc.elementAt(1);
103
      curr= vv.elementAt(0);
104
      next= vv.elementAt(1);
105
          
106
      tmp1.a[0] = tmp1.a[1] = tmp1.a[2] = 0.0f;
107
      tmp1.b[0] = tmp1.b[1] = tmp1.b[2] = 0.0f;
108
      tmp1.c[0] = next.x - curr.x;
109
      tmp1.c[1] = next.y - curr.y;
110
      tmp1.c[2] = next.z - curr.z;
111
      tmp1.d[0] = curr.x;
112
      tmp1.d[1] = curr.y;
113
      tmp1.d[2] = curr.z;
114
      
115
      tmp2.a[0] = tmp2.a[1] = tmp2.a[2] = 0.0f;
116
      tmp2.b[0] = tmp2.b[1] = tmp2.b[2] = 0.0f;
117
      tmp2.c[0] = curr.x - next.x;
118
      tmp2.c[1] = curr.y - next.y;
119
      tmp2.c[2] = curr.z - next.z;
120
      tmp2.d[0] = next.x;
121
      tmp2.d[1] = next.y;
122
      tmp2.d[2] = next.z;
123
      }
124
    else
125
      {
126
      int i, n;  
127
         
128
      for(i=0; i<numPoints; i++) vec(i);
129
   
130
      for(i=0; i<numPoints; i++)
131
        {
132
        n = i<numPoints-1 ? i+1:0;  
133
      
134
        tmp1= vc.elementAt(i);
135
        tmp2= vc.elementAt(n);
136
        curr= vv.elementAt(i);
137
        next= vv.elementAt(n);
138
      
139
        tmp1.cached[0] = curr.x;
140
        tmp1.cached[1] = curr.y;
141
        tmp1.cached[2] = curr.z;
142
        
143
        tmp1.a[0] =  2*curr.x +   tmp1.tangent[0] - 2*next.x + tmp2.tangent[0];
144
        tmp1.b[0] = -3*curr.x - 2*tmp1.tangent[0] + 3*next.x - tmp2.tangent[0];
145
        tmp1.c[0] = tmp1.tangent[0];
146
        tmp1.d[0] = curr.x;
147
      
148
        tmp1.a[1] =  2*curr.y +   tmp1.tangent[1] - 2*next.y + tmp2.tangent[1];
149
        tmp1.b[1] = -3*curr.y - 2*tmp1.tangent[1] + 3*next.y - tmp2.tangent[1];
150
        tmp1.c[1] = tmp1.tangent[1];
151
        tmp1.d[1] = curr.y;
152
      
153
        tmp1.a[2] =  2*curr.z +   tmp1.tangent[2] - 2*next.z + tmp2.tangent[2];
154
        tmp1.b[2] = -3*curr.z - 2*tmp1.tangent[2] + 3*next.z - tmp2.tangent[2];
155
        tmp1.c[2] = tmp1.tangent[2];
156
        tmp1.d[2] = curr.z;
157
        }
158
      }
159
   
160
    cacheDirty = false;
161
    }
162

    
163
///////////////////////////////////////////////////////////////////////////////////////////////////
164
// PUBLIC API
165
///////////////////////////////////////////////////////////////////////////////////////////////////
166
/**
167
 * Default constructor.
168
 */
169
  public Dynamic3D()
170
    {
171
    super(0,0.5f,3);
172
    vv = new Vector<>();
173
    }
174

    
175
///////////////////////////////////////////////////////////////////////////////////////////////////
176

    
177
/**
178
 * Default constructor.
179
 *
180
 * @param duration number of milliseconds it takes to do a full loop/path from first vector to the
181
 *                 last and back to the first
182
 * @param count    number of loops/paths we will do; mCount = 1.5 means we go from the first vector
183
 *                 to the last, back to first, and to the last again.
184
 */
185
  public Dynamic3D(int duration, float count)
186
    {
187
    super(duration,count,3);
188
    vv = new Vector<>();
189
    }
190

    
191
///////////////////////////////////////////////////////////////////////////////////////////////////
192
/**
193
 * Returns the location'th Static3D.
194
 *   
195
 * @param location the index of the Point we are interested in.
196
 * @return The Static3D, if 0<=location&lt;getNumPoints(), or null otherwise.
197
 */  
198
  public synchronized Static3D getPoint(int location)
199
    {
200
    return (location>=0 && location<numPoints) ? vv.elementAt(location) : null;  
201
    }
202
  
203
///////////////////////////////////////////////////////////////////////////////////////////////////
204
/**
205
 * Resets the location'th Point.
206
 * 
207
 * @param location the index of the Point we are setting.
208
 * @param x New value of its first float.
209
 */
210
  public synchronized void setPoint(int location, float x, float y, float z)
211
    {
212
    if( location>=0 && location<numPoints )
213
      {
214
      curr = vv.elementAt(location);
215
   
216
      if( curr!=null )
217
        {
218
        curr.set(x,y,z);
219
        cacheDirty=true;
220
        }
221
      }
222
    }
223

    
224
///////////////////////////////////////////////////////////////////////////////////////////////////
225
/**
226
 * Adds a new Static3D to the end of our list of Points to interpolate through.
227
 * <p>   
228
 * Only a reference to the Point gets added to the List; this means that one can add a Point 
229
 * here, and later on {@link Static3D#set(float,float,float)} it to some new value and the
230
 * change will be seamlessly reflected in the interpolated path.  
231
 * <p>
232
 * A Point can be added multiple times.
233
 *   
234
 * @param v The Point to add.
235
 */    
236
  public synchronized void add(Static3D v)
237
    {
238
    if( v!=null )
239
      {
240
      vv.add(v);
241
        
242
      if( vn!=null ) vn.add(new VectorNoise(3));
243
       
244
      switch(numPoints)
245
        {
246
        case 0: break;
247
        case 1: computeOrthonormalBase2(vv.elementAt(0),v);
248
                break;
249
        case 2: vc.add(new VectorCache(3));
250
                vc.add(new VectorCache(3));
251
                vc.add(new VectorCache(3));
252
                break;
253
        default:vc.add(new VectorCache(3));
254
        }
255

    
256
      numPoints++;
257
      cacheDirty = true;
258
      }
259
    }
260

    
261
///////////////////////////////////////////////////////////////////////////////////////////////////
262
/**
263
 * Adds a new Static3D to the location'th place in our List of Points to interpolate through.
264
 *   
265
 * @param location Index in our List to add the new Point at.
266
 * @param v The Point to add.
267
 */  
268
  public synchronized void add(int location, Static3D v)
269
    {
270
    if( v!=null )
271
      {
272
      vv.add(location, v);
273
      
274
      if( vn!=null ) vn.add(new VectorNoise(3));
275
      
276
      switch(numPoints)
277
        {
278
        case 0: break;
279
        case 1: computeOrthonormalBase2(vv.elementAt(0),v);
280
                break;
281
        case 2: vc.add(new VectorCache(3));
282
                vc.add(new VectorCache(3));
283
                vc.add(new VectorCache(3));
284
                break;
285
        default:vc.add(location,new VectorCache(3));
286
        }
287

    
288
      numPoints++;
289
      cacheDirty = true;
290
      }
291
    }
292
  
293
///////////////////////////////////////////////////////////////////////////////////////////////////
294
/**
295
 * Removes all occurrences of Point v from the List of Points to interpolate through.  
296
 * 
297
 * @param v The Point to remove.
298
 * @return <code>true</code> if we have removed at least one Point.
299
 */
300
  public synchronized boolean remove(Static3D v)
301
    {
302
    int n = vv.indexOf(v);
303
    boolean found = false;
304
   
305
    while( n>=0 ) 
306
      {
307
      vv.remove(n);
308
     
309
      if( vn!=null ) vn.remove(0);
310
     
311
      switch(numPoints)
312
        {
313
        case 0:
314
        case 1: 
315
        case 2: break;
316
        case 3: vc.removeAllElements();
317
                computeOrthonormalBase2(vv.elementAt(0),vv.elementAt(1));
318
                break;
319
        default:vc.remove(n);
320
        }
321

    
322
      numPoints--;
323
      found = true;
324
      n = vv.indexOf(v);
325
      }
326
   
327
    if( found ) 
328
      {
329
      cacheDirty=true;
330
      }
331
   
332
    return found;
333
    }
334

    
335
///////////////////////////////////////////////////////////////////////////////////////////////////
336
/**
337
 * Removes a location'th Point from the List of Points we interpolate through.
338
 * 
339
 * @param location index of the Point we want to remove. 
340
 * @return <code>true</code> if location is valid, i.e. if 0<=location&lt;getNumPoints().
341
 */
342
  public synchronized boolean remove(int location)
343
    {
344
    if( location>=0 && location<numPoints ) 
345
      {
346
      vv.removeElementAt(location);
347
       
348
      if( vn!=null ) vn.remove(0);
349
      
350
      switch(numPoints)
351
        {
352
        case 0:
353
        case 1: 
354
        case 2: break;
355
        case 3: vc.removeAllElements();
356
                computeOrthonormalBase2(vv.elementAt(0),vv.elementAt(1));
357
                break;
358
        default:vc.removeElementAt(location);
359
        }
360

    
361
      numPoints--;
362
      cacheDirty = true; 
363
      return true;
364
      }
365

    
366
   return false;
367
   }
368
  
369
///////////////////////////////////////////////////////////////////////////////////////////////////
370
/**
371
 * Removes all Points.
372
 */
373
  public synchronized void removeAll()
374
    {
375
    numPoints = 0;
376
    vv.removeAllElements();
377
    vc.removeAllElements();
378
    cacheDirty = false;
379
   
380
    if( vn!=null ) vn.removeAllElements();
381
    }
382
  
383
///////////////////////////////////////////////////////////////////////////////////////////////////
384
/**
385
 * Writes the results of interpolation between the Points at time 'time' to the passed float buffer.
386
 * <p>
387
 * Since this is a 3-dimensional Dynamic, the resulting interpolated Static3D gets written
388
 * to three locations in the buffer: buffer[offset], buffer[offset+1] and buffer[offset+2]. 
389
 * 
390
 * @param buffer Float buffer we will write the resulting Static3D to.
391
 * @param offset Offset in the buffer where to write the result.
392
 * @param time Time of interpolation. Time=0.0 would return the first Point, Time=0.5 - the last,
393
 *             time=1.0 - the first again, and time 0.1 would be 1/5 of the way between the first and the last Points.
394
 */    
395
  public synchronized void interpolate(float[] buffer, int offset, float time)
396
    {  
397
    switch(numPoints)
398
      {
399
      case 0: buffer[offset  ] = 0.0f;
400
              buffer[offset+1] = 0.0f;
401
              buffer[offset+2] = 0.0f;
402
              break;
403
      case 1: curr = vv.elementAt(0);
404
              buffer[offset  ] = curr.x;
405
              buffer[offset+1] = curr.y;
406
              buffer[offset+2] = curr.z;
407
              break;
408
      case 2: curr = vv.elementAt(0);
409
              next = vv.elementAt(1);
410
             
411
              if( mMode==MODE_LOOP || mMode==MODE_PATH ) time = (time>0.5f ? 2-2*time : 2*time);
412
             
413
              if( vn!=null )
414
                {
415
                time = noise(time,0);
416
            
417
                buffer[offset  ] = (next.x-curr.x)*time + curr.x + (baseV[0][0]*mFactor[0] + baseV[1][0]*mFactor[1]);
418
                buffer[offset+1] = (next.y-curr.y)*time + curr.y + (baseV[0][1]*mFactor[0] + baseV[1][1]*mFactor[1]);
419
                buffer[offset+2] = (next.z-curr.z)*time + curr.z + (baseV[0][2]*mFactor[0] + baseV[1][2]*mFactor[1]);
420
                }
421
              else
422
                {
423
                buffer[offset  ] = (next.x-curr.x)*time + curr.x;
424
                buffer[offset+1] = (next.y-curr.y)*time + curr.y;
425
                buffer[offset+2] = (next.z-curr.z)*time + curr.z;
426
                }
427
             
428
              break;
429
      default:float t = time;
430
        
431
              switch(mMode)
432
                {
433
                case MODE_LOOP: time = time*numPoints;
434
                                break;
435
                case MODE_PATH: time = (time<=0.5f) ? 2*time*(numPoints-1) : 2*(1-time)*(numPoints-1);
436
                                break;
437
                case MODE_JUMP: time = time*(numPoints-1);
438
                                break;
439
                }
440
           
441
              int vecCurr = (int)time;
442
              time = time-vecCurr;
443
      
444
              if( vecCurr>=0 && vecCurr<numPoints )
445
                {
446
                if( cacheDirty ) recomputeCache();    // recompute cache if we have added or remove vectors since last computation
447
                else if( mVecCurr!= vecCurr )         // ...or if we have just passed a vector and the vector we are currently flying to has changed
448
                  {
449
                  int vecNext;   
450
                  mVecCurr = vecCurr;
451
                       
452
                  switch(mMode)
453
                    {
454
                    case MODE_LOOP: vecNext = vecCurr==numPoints-1 ? 0:vecCurr+1; 
455
                                    break;
456
                    case MODE_PATH: if( t<0.5f ) vecNext = vecCurr==numPoints-1 ? numPoints-2: vecCurr+1;  
457
                                    else         vecNext = vecCurr==0 ? 1 : vecCurr-1;  
458
                                    break;
459
                    case MODE_JUMP: vecNext = vecCurr==numPoints-1 ? 1:vecCurr+1;
460
                                    break;
461
                    default       : vecNext = 0;                
462
                    }
463
              
464
                  next = vv.elementAt(vecNext);
465
                  tmp2 = vc.elementAt(vecNext);
466
              
467
                  if( tmp2.cached[0]!=next.x || tmp2.cached[1]!=next.y || tmp2.cached[2]!=next.z ) recomputeCache();
468
                  }
469
            
470
                tmp1 = vc.elementAt(vecCurr);
471
               
472
                if( vn!=null )
473
                  {
474
                  time = noise(time,vecCurr);
475
              
476
                  computeOrthonormalBaseMore(time,tmp1);
477
                 
478
                  buffer[offset  ]= ((tmp1.a[0]*time+tmp1.b[0])*time+tmp1.c[0])*time+tmp1.d[0] + (baseV[0][0]*mFactor[0] + baseV[1][0]*mFactor[1]);
479
                  buffer[offset+1]= ((tmp1.a[1]*time+tmp1.b[1])*time+tmp1.c[1])*time+tmp1.d[1] + (baseV[0][1]*mFactor[0] + baseV[1][1]*mFactor[1]);
480
                  buffer[offset+2]= ((tmp1.a[2]*time+tmp1.b[2])*time+tmp1.c[2])*time+tmp1.d[2] + (baseV[0][2]*mFactor[0] + baseV[1][2]*mFactor[1]);
481
                  }
482
                else
483
                  {
484
                  buffer[offset  ]= ((tmp1.a[0]*time+tmp1.b[0])*time+tmp1.c[0])*time+tmp1.d[0];
485
                  buffer[offset+1]= ((tmp1.a[1]*time+tmp1.b[1])*time+tmp1.c[1])*time+tmp1.d[1];
486
                  buffer[offset+2]= ((tmp1.a[2]*time+tmp1.b[2])*time+tmp1.c[2])*time+tmp1.d[2];
487
                  }
488
               
489
                break;
490
                }
491
       }
492
     }  
493

    
494
  }
495
///////////////////////////////////////////////////////////////////////////////////////////////////
496
//
(9-9/17)