Project

General

Profile

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

library / src / main / java / org / distorted / library / DistortedObject.java @ e4878781

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;
21

    
22
import android.graphics.Bitmap;
23
import android.graphics.Matrix;
24
import android.opengl.GLES20;
25
import android.opengl.GLUtils;
26

    
27
import org.distorted.library.message.EffectListener;
28
import org.distorted.library.type.Data1D;
29
import org.distorted.library.type.Data2D;
30
import org.distorted.library.type.Data3D;
31
import org.distorted.library.type.Data4D;
32
import org.distorted.library.type.Static3D;
33

    
34
///////////////////////////////////////////////////////////////////////////////////////////////////
35
/**
36
 * All Objects to which Distorted Graphics effects can be applied need to be extended from here.
37
 */
38
public abstract class DistortedObject 
39
  {
40
  private static float[] mViewMatrix   = new float[16];
41
   
42
  protected EffectQueueMatrix    mM;
43
  protected EffectQueueFragment  mF;
44
  protected EffectQueueVertex    mV;
45

    
46
  protected boolean matrixCloned, vertexCloned, fragmentCloned;
47
 
48
  protected DistortedObjectGrid mGrid = null;
49
  protected long mID;
50
  protected int mSizeX, mSizeY, mSizeZ; // in screen space
51

    
52
  protected Bitmap[] mBmp= null; //
53
  int[] mTextureDataH;           // have to be shared among all the cloned Objects
54
  boolean[] mBitmapSet;          //
55

    
56
///////////////////////////////////////////////////////////////////////////////////////////////////
57
// We have to flip vertically every single Bitmap that we get fed with.
58
//
59
// Reason: textures read from files are the only objects in OpenGL which have their origins at the
60
// upper-left corner. Everywhere else the origin is in the lower-left corner. Thus we have to flip.
61
// The alternative solution, namely inverting the y-coordinate of the TexCoord does not really work-
62
// i.e. it works only in case of rendering directly to the screen, but if we render to an FBO and
63
// then take the FBO and render to screen, (DistortedNode does so!) things get inverted as textures
64
// created from FBO have their origins in the lower-left... Mindfuck!
65

    
66
  private static Bitmap flipBitmap(Bitmap src)
67
    {
68
    Matrix matrix = new Matrix();
69
    matrix.preScale(1.0f,-1.0f);
70

    
71
    return Bitmap.createBitmap(src,0,0,src.getWidth(),src.getHeight(), matrix,true);
72
    }
73

    
74
///////////////////////////////////////////////////////////////////////////////////////////////////
75

    
76
  protected abstract DistortedObject deepCopy(int flags);
77

    
78
///////////////////////////////////////////////////////////////////////////////////////////////////
79

    
80
  protected void initializeData()
81
    {
82
    mID             = DistortedObjectList.add(this);
83
    mTextureDataH   = new int[1];
84
    mTextureDataH[0]= 0;
85
    mBmp            = new Bitmap[1];
86
    mBmp[0]         = null;
87
    mBitmapSet      = new boolean[1];
88
    mBitmapSet[0]   = false;
89
      
90
    initializeEffectLists(this,0);
91
      
92
    if( Distorted.isInitialized() ) resetTexture();
93
    }
94
    
95
///////////////////////////////////////////////////////////////////////////////////////////////////
96
    
97
  protected void initializeEffectLists(DistortedObject d, int flags)
98
    {
99
    if( (flags & Distorted.CLONE_MATRIX) != 0 )
100
      {
101
      mM = d.mM;
102
      matrixCloned = true;
103
      }
104
    else
105
      {
106
      mM = new EffectQueueMatrix(d);
107
      matrixCloned = false;
108
      }
109
    
110
    if( (flags & Distorted.CLONE_VERTEX) != 0 )
111
      {
112
      mV = d.mV;
113
      vertexCloned = true;
114
      }
115
    else
116
      {
117
      mV = new EffectQueueVertex(d);
118
      vertexCloned = false;
119
      }
120
    
121
    if( (flags & Distorted.CLONE_FRAGMENT) != 0 )
122
      {
123
      mF = d.mF;
124
      fragmentCloned = true;
125
      }
126
    else
127
      {
128
      mF = new EffectQueueFragment(d);
129
      fragmentCloned = false;
130
      }
131
    }
132
    
133
///////////////////////////////////////////////////////////////////////////////////////////////////
134
// this will be called on startup and every time OpenGL context has been lost
135
// also call this from the constructor if the OpenGL context has been created already.
136
    
137
  void resetTexture()
138
    {
139
    if( mTextureDataH!=null )
140
      {
141
      if( mTextureDataH[0]==0 ) GLES20.glGenTextures(1, mTextureDataH, 0);
142

    
143
      GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataH[0]);
144
      GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR );
145
      GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR );
146
      GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE );
147
      GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE );
148
       
149
      if( mBmp!=null && mBmp[0]!=null)
150
        {
151
        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, flipBitmap(mBmp[0]), 0);
152
        mBmp[0] = null;
153
        }
154
      }
155
    }
156
  
157
///////////////////////////////////////////////////////////////////////////////////////////////////
158
   
159
  void drawPriv(long currTime, DistortedProjection dp)
160
    {
161
    GLES20.glViewport(0, 0, dp.width, dp.height);
162
      
163
    mM.compute(currTime);
164
    mM.send(mViewMatrix, dp);
165
      
166
    mV.compute(currTime);
167
    mV.postprocess();
168
    mV.send();
169
        
170
    mF.compute(currTime);
171
    mF.send();
172
       
173
    mGrid.draw();
174
    }
175

    
176
///////////////////////////////////////////////////////////////////////////////////////////////////
177
   
178
  void drawNoEffectsPriv(DistortedProjection dp)
179
    {
180
    GLES20.glViewport(0, 0, dp.width, dp.height);
181
    mM.sendNoEffects(dp);
182
    mV.sendZero();
183
    mF.sendZero();
184
    mGrid.draw();
185
    }
186
    
187
///////////////////////////////////////////////////////////////////////////////////////////////////
188
   
189
  void releasePriv()
190
    {
191
    if( matrixCloned  ==false) mM.abortAll(false);
192
    if( vertexCloned  ==false) mV.abortAll(false);
193
    if( fragmentCloned==false) mF.abortAll(false);
194

    
195
    mBmp          = null;
196
    mGrid         = null;
197
    mM            = null;
198
    mV            = null;
199
    mF            = null;
200
    mTextureDataH = null;
201
    }
202
 
203
///////////////////////////////////////////////////////////////////////////////////////////////////
204

    
205
  long getBitmapID()
206
      {
207
      return mBmp==null ? 0 : mBmp.hashCode();
208
      }
209

    
210
///////////////////////////////////////////////////////////////////////////////////////////////////
211
/**
212
 * Default empty constructor so that derived classes can call it
213
 */
214
  public DistortedObject()
215
    {
216

    
217
    }
218

    
219
///////////////////////////////////////////////////////////////////////////////////////////////////
220
/**
221
 * Copy constructor used to create a DistortedObject based on various parts of another object.
222
 * <p>
223
 * Whatever we do not clone gets created just like in the default constructor.
224
 * We only call this from the descendant's classes' constructors where we have to pay attention
225
 * to give it the appropriate type of a DistortedObject!
226
 *
227
 * @param dc    Source object to create our object from
228
 * @param flags A bitmask of values specifying what to copy.
229
 *              For example, CLONE_BITMAP | CLONE_MATRIX.
230
 */
231
  public DistortedObject(DistortedObject dc, int flags)
232
    {
233
    initializeEffectLists(dc,flags);
234

    
235
    mID = DistortedObjectList.add(this);
236

    
237
    mSizeX = dc.mSizeX;
238
    mSizeY = dc.mSizeY;
239
    mSizeZ = dc.mSizeZ;
240
    mGrid  = dc.mGrid;
241

    
242
    if( (flags & Distorted.CLONE_BITMAP) != 0 )
243
      {
244
      mTextureDataH = dc.mTextureDataH;
245
      mBmp          = dc.mBmp;
246
      mBitmapSet    = dc.mBitmapSet;
247
      }
248
    else
249
      {
250
      mTextureDataH   = new int[1];
251
      mTextureDataH[0]= 0;
252
      mBitmapSet      = new boolean[1];
253
      mBitmapSet[0]   = false;
254
      mBmp            = new Bitmap[1];
255
      mBmp[0]         = null;
256

    
257
      if( Distorted.isInitialized() ) resetTexture();
258
      }
259
    }
260

    
261
///////////////////////////////////////////////////////////////////////////////////////////////////
262
/**
263
 * Draw the DistortedObject to the location specified by current Matrix effects.    
264
 *     
265
 * @param currTime current time, in milliseconds, as returned by System.currentTimeMillis().
266
 *        This gets passed on to Interpolators inside the Effects that are currently applied to the 
267
 *        Object.
268
 */
269
  public void draw(long currTime)
270
    {
271
    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
272
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
273
    GLES20.glUniform1i(Distorted.mTextureUniformH, 0);
274
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataH[0]);
275
      
276
    drawPriv(currTime, Distorted.mProjection);
277
    }
278
 
279
///////////////////////////////////////////////////////////////////////////////////////////////////
280
/**
281
 * Releases all resources.
282
 */
283
  public synchronized void release()
284
    {
285
    releasePriv();
286
    DistortedObjectList.remove(this);
287
    }
288

    
289
///////////////////////////////////////////////////////////////////////////////////////////////////
290
/**
291
 * Sets the underlying android.graphics.Bitmap object and uploads it to the GPU. 
292
 * <p>
293
 * You can only recycle() the passed Bitmap once the OpenGL context gets created (i.e. after call 
294
 * to onSurfaceCreated) because only after this point can the Library upload it to the GPU!
295
 * 
296
 * @param bmp The android.graphics.Bitmap object to apply effects to and display.
297
 */
298
   
299
  public void setBitmap(Bitmap bmp)
300
    {
301
    mBitmapSet[0] = true;
302
      
303
    if( Distorted.isInitialized() )
304
      {
305
      GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
306
      GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataH[0]);
307
      GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, flipBitmap(bmp), 0);
308
      }
309
    else
310
      {
311
      mBmp[0] = bmp;
312
      }
313
    }
314
    
315
///////////////////////////////////////////////////////////////////////////////////////////////////
316
/**
317
 * Adds the calling class to the list of Listeners that get notified each time some event happens 
318
 * to one of the Effects that are currently applied to the DistortedObject.
319
 * 
320
 * @param el A class implementing the EffectListener interface that wants to get notifications.
321
 */
322
  public void addEventListener(EffectListener el)
323
    {
324
    mV.addListener(el);
325
    mF.addListener(el);
326
    mM.addListener(el);
327
    }
328

    
329
///////////////////////////////////////////////////////////////////////////////////////////////////
330
/**
331
 * Removes the calling class from the list of Listeners.
332
 * 
333
 * @param el A class implementing the EffectListener interface that no longer wants to get notifications.
334
 */
335
  public void removeEventListener(EffectListener el)
336
    {
337
    mV.removeListener(el);
338
    mF.removeListener(el);
339
    mM.removeListener(el);
340
    }
341
   
342
///////////////////////////////////////////////////////////////////////////////////////////////////
343
/**
344
 * Returns the height of the DistortedObject.
345
 *    
346
 * @return height of the object, in pixels.
347
 */
348
  public int getWidth()
349
     {
350
     return mSizeX;   
351
     }
352

    
353
///////////////////////////////////////////////////////////////////////////////////////////////////
354
/**
355
 * Returns the width of the DistortedObject.
356
 * 
357
 * @return width of the Object, in pixels.
358
 */
359
  public int getHeight()
360
      {
361
      return mSizeY;  
362
      }
363
    
364
///////////////////////////////////////////////////////////////////////////////////////////////////
365
/**
366
 * Returns the depth of the DistortedObject.
367
 * 
368
 * @return depth of the Object, in pixels.
369
 */
370
  public int getDepth()
371
      {
372
      return mSizeZ;  
373
      }
374
        
375
///////////////////////////////////////////////////////////////////////////////////////////////////
376
/**
377
 * Returns unique ID of this instance.
378
 * 
379
 * @return ID of the object.
380
 */
381
  public long getID()
382
      {
383
      return mID;  
384
      }
385
    
386
///////////////////////////////////////////////////////////////////////////////////////////////////
387
/**
388
 * Aborts all Effects.
389
 * @return Number of effects aborted.
390
 */
391
  public int abortAllEffects()
392
      {
393
      return mM.abortAll(true) + mV.abortAll(true) + mF.abortAll(true);
394
      }
395

    
396
///////////////////////////////////////////////////////////////////////////////////////////////////
397
/**
398
 * Aborts all Effects of a given type, for example all MATRIX Effects.
399
 * 
400
 * @param type one of the constants defined in {@link EffectTypes}
401
 * @return Number of effects aborted.
402
 */
403
  public int abortEffects(EffectTypes type)
404
    {
405
    switch(type)
406
      {
407
      case MATRIX  : return mM.abortAll(true);
408
      case VERTEX  : return mV.abortAll(true);
409
      case FRAGMENT: return mF.abortAll(true);
410
      default      : return 0;
411
      }
412
    }
413
    
414
///////////////////////////////////////////////////////////////////////////////////////////////////
415
/**
416
 * Aborts a single Effect.
417
 * 
418
 * @param id ID of the Effect we want to abort.
419
 * @return number of Effects aborted. Always either 0 or 1.
420
 */
421
  public int abortEffect(long id)
422
    {
423
    int type = (int)(id&EffectTypes.MASK);
424

    
425
    if( type==EffectTypes.MATRIX.type   ) return mM.removeByID(id>>EffectTypes.LENGTH);
426
    if( type==EffectTypes.VERTEX.type   ) return mV.removeByID(id>>EffectTypes.LENGTH);
427
    if( type==EffectTypes.FRAGMENT.type ) return mF.removeByID(id>>EffectTypes.LENGTH);
428

    
429
    return 0;
430
    }
431

    
432
///////////////////////////////////////////////////////////////////////////////////////////////////
433
/**
434
 * Abort all Effects of a given name, for example all rotations.
435
 * 
436
 * @param name one of the constants defined in {@link EffectNames}
437
 * @return number of Effects aborted.
438
 */
439
  public int abortEffects(EffectNames name)
440
    {
441
    switch(name.getType())
442
      {
443
      case MATRIX  : return mM.removeByType(name);
444
      case VERTEX  : return mV.removeByType(name);
445
      case FRAGMENT: return mF.removeByType(name);
446
      default      : return 0;
447
      }
448
    }
449
    
450
///////////////////////////////////////////////////////////////////////////////////////////////////
451
/**
452
 * Print some info about a given Effect to Android's standard out. Used for debugging only.
453
 * 
454
 * @param id Effect ID we want to print info about
455
 * @return <code>true</code> if a single Effect of type effectType has been found.
456
 */
457
    
458
  public boolean printEffect(long id)
459
    {
460
    int type = (int)(id&EffectTypes.MASK);
461

    
462
    if( type==EffectTypes.MATRIX.type   )  return mM.printByID(id>>EffectTypes.LENGTH);
463
    if( type==EffectTypes.VERTEX.type   )  return mV.printByID(id>>EffectTypes.LENGTH);
464
    if( type==EffectTypes.FRAGMENT.type )  return mF.printByID(id>>EffectTypes.LENGTH);
465

    
466
    return false;
467
    }
468
   
469
///////////////////////////////////////////////////////////////////////////////////////////////////   
470
///////////////////////////////////////////////////////////////////////////////////////////////////
471
// Individual effect functions.
472
///////////////////////////////////////////////////////////////////////////////////////////////////
473
// Matrix-based effects
474
///////////////////////////////////////////////////////////////////////////////////////////////////
475
/**
476
 * Moves the Object by a (possibly changing in time) vector.
477
 * 
478
 * @param vector 3-dimensional Data which at any given time will return a Static3D
479
 *               representing the current coordinates of the vector we want to move the Object with.
480
 * @return       ID of the effect added, or -1 if we failed to add one.
481
 */
482
  public long move(Data3D vector)
483
    {   
484
    return mM.add(EffectNames.MOVE,vector);
485
    }
486

    
487
///////////////////////////////////////////////////////////////////////////////////////////////////
488
/**
489
 * Scales the Object by (possibly changing in time) 3D scale factors.
490
 * 
491
 * @param scale 3-dimensional Dynamic which at any given time returns a Static3D
492
 *              representing the current x- , y- and z- scale factors.
493
 * @return      ID of the effect added, or -1 if we failed to add one.
494
 */
495
  public long scale(Data3D scale)
496
    {   
497
    return mM.add(EffectNames.SCALE,scale);
498
    }
499

    
500
///////////////////////////////////////////////////////////////////////////////////////////////////
501
/**
502
 * Scales the Object by one uniform, constant factor in all 3 dimensions. Convenience function.
503
 *
504
 * @param scale The factor to scale all 3 dimensions with.
505
 * @return      ID of the effect added, or -1 if we failed to add one.
506
 */
507
  public long scale(float scale)
508
    {
509
    return mM.add(EffectNames.SCALE, new Static3D(scale,scale,scale));
510
    }
511

    
512
///////////////////////////////////////////////////////////////////////////////////////////////////
513
/**
514
 * Rotates the Object by 'angle' degrees around the center.
515
 * Static axis of rotation is given by the last parameter.
516
 *
517
 * @param angle  Angle that we want to rotate the Object to. Unit: degrees
518
 * @param axis   Axis of rotation
519
 * @param center Coordinates of the Point we are rotating around.
520
 * @return       ID of the effect added, or -1 if we failed to add one.
521
 */
522
  public long rotate(Data1D angle, Static3D axis, Data3D center )
523
    {   
524
    return mM.add(EffectNames.ROTATE, angle, axis, center);
525
    }
526

    
527
///////////////////////////////////////////////////////////////////////////////////////////////////
528
/**
529
 * Rotates the Object by 'angle' degrees around the center.
530
 * Here both angle and axis can dynamically change.
531
 *
532
 * @param angleaxis Combined 4-tuple representing the (angle,axisX,axisY,axisZ).
533
 * @param center    Coordinates of the Point we are rotating around.
534
 * @return          ID of the effect added, or -1 if we failed to add one.
535
 */
536
  public long rotate(Data4D angleaxis, Data3D center)
537
    {
538
    return mM.add(EffectNames.ROTATE, angleaxis, center);
539
    }
540

    
541
///////////////////////////////////////////////////////////////////////////////////////////////////
542
/**
543
 * Rotates the Object by quaternion.
544
 *
545
 * @param quaternion The quaternion describing the rotation.
546
 * @param center     Coordinates of the Point we are rotating around.
547
 * @return           ID of the effect added, or -1 if we failed to add one.
548
 */
549
  public long quaternion(Data4D quaternion, Data3D center )
550
    {
551
    return mM.add(EffectNames.QUATERNION,quaternion,center);
552
    }
553

    
554
///////////////////////////////////////////////////////////////////////////////////////////////////
555
/**
556
 * Shears the Object.
557
 *
558
 * @param shear   The 3-tuple of shear factors.
559
 * @param center  Center of shearing, i.e. the point which stays unmoved.
560
 * @return        ID of the effect added, or -1 if we failed to add one.
561
 */
562
  public long shear(Data3D shear, Data3D center)
563
    {
564
    return mM.add(EffectNames.SHEAR, shear, center);
565
    }
566

    
567
///////////////////////////////////////////////////////////////////////////////////////////////////
568
// Fragment-based effects  
569
///////////////////////////////////////////////////////////////////////////////////////////////////
570
/**
571
 * Makes a certain sub-region of the Object smoothly change all three of its RGB components.
572
 *        
573
 * @param blend  1-dimensional Data that returns the level of blend a given pixel will be
574
 *               mixed with the next parameter 'color': pixel = (1-level)*pixel + level*color.
575
 *               Valid range: <0,1>
576
 * @param color  Color to mix. (1,0,0) is RED.
577
 * @param region Region this Effect is limited to.
578
 * @param smooth If true, the level of 'blend' will smoothly fade out towards the edges of the region.
579
 * @return       ID of the effect added, or -1 if we failed to add one.
580
 */
581
  public long chroma(Data1D blend, Data3D color, Data4D region, boolean smooth)
582
    {
583
    return mF.add( smooth? EffectNames.SMOOTH_CHROMA:EffectNames.CHROMA, blend, color, region);
584
    }
585

    
586
///////////////////////////////////////////////////////////////////////////////////////////////////
587
/**
588
 * Makes the whole Object smoothly change all three of its RGB components.
589
 *
590
 * @param blend  1-dimensional Data that returns the level of blend a given pixel will be
591
 *               mixed with the next parameter 'color': pixel = (1-level)*pixel + level*color.
592
 *               Valid range: <0,1>
593
 * @param color  Color to mix. (1,0,0) is RED.
594
 * @return       ID of the effect added, or -1 if we failed to add one.
595
 */
596
  public long chroma(Data1D blend, Data3D color)
597
    {
598
    return mF.add(EffectNames.CHROMA, blend, color);
599
    }
600

    
601
///////////////////////////////////////////////////////////////////////////////////////////////////
602
/**
603
 * Makes a certain sub-region of the Object smoothly change its transparency level.
604
 *        
605
 * @param alpha  1-dimensional Data that returns the level of transparency we want to have at any given
606
 *               moment: pixel.a *= alpha.
607
 *               Valid range: <0,1>
608
 * @param region Region this Effect is limited to. 
609
 * @param smooth If true, the level of 'alpha' will smoothly fade out towards the edges of the region.
610
 * @return       ID of the effect added, or -1 if we failed to add one. 
611
 */
612
  public long alpha(Data1D alpha, Data4D region, boolean smooth)
613
    {
614
    return mF.add( smooth? EffectNames.SMOOTH_ALPHA:EffectNames.ALPHA, alpha, region);
615
    }
616

    
617
///////////////////////////////////////////////////////////////////////////////////////////////////
618
/**
619
 * Makes the whole Object smoothly change its transparency level.
620
 *
621
 * @param alpha  1-dimensional Data that returns the level of transparency we want to have at any
622
 *               given moment: pixel.a *= alpha.
623
 *               Valid range: <0,1>
624
 * @return       ID of the effect added, or -1 if we failed to add one.
625
 */
626
  public long alpha(Data1D alpha)
627
    {
628
    return mF.add(EffectNames.ALPHA, alpha);
629
    }
630

    
631
///////////////////////////////////////////////////////////////////////////////////////////////////
632
/**
633
 * Makes a certain sub-region of the Object smoothly change its brightness level.
634
 *        
635
 * @param brightness 1-dimensional Data that returns the level of brightness we want to have
636
 *                   at any given moment. Valid range: <0,infinity)
637
 * @param region     Region this Effect is limited to.
638
 * @param smooth     If true, the level of 'brightness' will smoothly fade out towards the edges of the region.
639
 * @return           ID of the effect added, or -1 if we failed to add one.
640
 */
641
  public long brightness(Data1D brightness, Data4D region, boolean smooth)
642
    {
643
    return mF.add( smooth ? EffectNames.SMOOTH_BRIGHTNESS: EffectNames.BRIGHTNESS, brightness, region);
644
    }
645

    
646
///////////////////////////////////////////////////////////////////////////////////////////////////
647
/**
648
 * Makes the whole Object smoothly change its brightness level.
649
 *
650
 * @param brightness 1-dimensional Data that returns the level of brightness we want to have
651
 *                   at any given moment. Valid range: <0,infinity)
652
 * @return           ID of the effect added, or -1 if we failed to add one.
653
 */
654
  public long brightness(Data1D brightness)
655
    {
656
    return mF.add(EffectNames.BRIGHTNESS, brightness);
657
    }
658

    
659
///////////////////////////////////////////////////////////////////////////////////////////////////
660
/**
661
 * Makes a certain sub-region of the Object smoothly change its contrast level.
662
 *        
663
 * @param contrast 1-dimensional Data that returns the level of contrast we want to have
664
 *                 at any given moment. Valid range: <0,infinity)
665
 * @param region   Region this Effect is limited to.
666
 * @param smooth   If true, the level of 'contrast' will smoothly fade out towards the edges of the region.
667
 * @return         ID of the effect added, or -1 if we failed to add one.
668
 */
669
  public long contrast(Data1D contrast, Data4D region, boolean smooth)
670
    {
671
    return mF.add( smooth ? EffectNames.SMOOTH_CONTRAST:EffectNames.CONTRAST, contrast, region);
672
    }
673

    
674
///////////////////////////////////////////////////////////////////////////////////////////////////
675
/**
676
 * Makes the whole Object smoothly change its contrast level.
677
 *
678
 * @param contrast 1-dimensional Data that returns the level of contrast we want to have
679
 *                 at any given moment. Valid range: <0,infinity)
680
 * @return         ID of the effect added, or -1 if we failed to add one.
681
 */
682
  public long contrast(Data1D contrast)
683
    {
684
    return mF.add(EffectNames.CONTRAST, contrast);
685
    }
686

    
687
///////////////////////////////////////////////////////////////////////////////////////////////////
688
/**
689
 * Makes a certain sub-region of the Object smoothly change its saturation level.
690
 *        
691
 * @param saturation 1-dimensional Data that returns the level of saturation we want to have
692
 *                   at any given moment. Valid range: <0,infinity)
693
 * @param region     Region this Effect is limited to.
694
 * @param smooth     If true, the level of 'saturation' will smoothly fade out towards the edges of the region.
695
 * @return           ID of the effect added, or -1 if we failed to add one.
696
 */
697
  public long saturation(Data1D saturation, Data4D region, boolean smooth)
698
    {
699
    return mF.add( smooth ? EffectNames.SMOOTH_SATURATION:EffectNames.SATURATION, saturation, region);
700
    }
701

    
702
///////////////////////////////////////////////////////////////////////////////////////////////////
703
/**
704
 * Makes the whole Object smoothly change its saturation level.
705
 *
706
 * @param saturation 1-dimensional Data that returns the level of saturation we want to have
707
 *                   at any given moment. Valid range: <0,infinity)
708
 * @return           ID of the effect added, or -1 if we failed to add one.
709
 */
710
  public long saturation(Data1D saturation)
711
    {
712
    return mF.add(EffectNames.SATURATION, saturation);
713
    }
714

    
715
///////////////////////////////////////////////////////////////////////////////////////////////////
716
// Vertex-based effects  
717
///////////////////////////////////////////////////////////////////////////////////////////////////
718
/**
719
 * Distort a (possibly changing in time) part of the Object by a (possibly changing in time) vector of force.
720
 *
721
 * @param vector 3-dimensional Vector which represents the force the Center of the Effect is
722
 *               currently being dragged with.
723
 * @param center 2-dimensional Data that, at any given time, returns the Center of the Effect.
724
 * @param region Region that masks the Effect.
725
 * @return       ID of the effect added, or -1 if we failed to add one.
726
 */
727
  public long distort(Data3D vector, Data2D center, Data4D region)
728
    {  
729
    return mV.add(EffectNames.DISTORT, vector, center, region);
730
    }
731

    
732
///////////////////////////////////////////////////////////////////////////////////////////////////
733
/**
734
 * Distort the whole Object by a (possibly changing in time) vector of force.
735
 *
736
 * @param vector 3-dimensional Vector which represents the force the Center of the Effect is
737
 *               currently being dragged with.
738
 * @param center 2-dimensional Data that, at any given time, returns the Center of the Effect.
739
 * @return       ID of the effect added, or -1 if we failed to add one.
740
 */
741
  public long distort(Data3D vector, Data2D center)
742
    {
743
    return mV.add(EffectNames.DISTORT, vector, center);
744
    }
745

    
746
///////////////////////////////////////////////////////////////////////////////////////////////////
747
/**
748
 * Deform the shape of the whole Object with a (possibly changing in time) vector of force applied to
749
 * a (possibly changing in time) point on the Object.
750
 *     
751
 * @param vector Vector of force that deforms the shape of the whole Object.
752
 * @param center 2-dimensional Data that, at any given time, returns the Center of the Effect.
753
 * @return       ID of the effect added, or -1 if we failed to add one.
754
 */
755
  public long deform(Data3D vector, Data2D center)
756
    {  
757
    return mV.add(EffectNames.DEFORM, vector, center);
758
    }
759

    
760
///////////////////////////////////////////////////////////////////////////////////////////////////  
761
/**
762
 * Pull all points around the center of the Effect towards the center (if degree>=1) or push them
763
 * away from the center (degree<=1)
764
 *
765
 * @param sink   The current degree of the Effect.
766
 * @param center 2-dimensional Data that, at any given time, returns the Center of the Effect.
767
 * @param region Region that masks the Effect.
768
 * @return       ID of the effect added, or -1 if we failed to add one.
769
 */
770
  public long sink(Data1D sink, Data2D center, Data4D region)
771
    {
772
    return mV.add(EffectNames.SINK, sink, center, region);
773
    }
774

    
775
///////////////////////////////////////////////////////////////////////////////////////////////////
776
/**
777
 * Pull all points around the center of the Effect towards the center (if degree>=1) or push them
778
 * away from the center (degree<=1)
779
 *
780
 * @param sink   The current degree of the Effect.
781
 * @param center 2-dimensional Data that, at any given time, returns the Center of the Effect.
782
 * @return       ID of the effect added, or -1 if we failed to add one.
783
 */
784
  public long sink(Data1D sink, Data2D center)
785
    {
786
    return mV.add(EffectNames.SINK, sink, center);
787
    }
788

    
789
///////////////////////////////////////////////////////////////////////////////////////////////////  
790
/**
791
 * Rotate part of the Object around the Center of the Effect by a certain angle.
792
 *
793
 * @param swirl  The degree of Swirl. Positive values swirl clockwise.
794
 * @param center 2-dimensional Data that, at any given time, returns the Center of the Effect.
795
 * @param region Region that masks the Effect.
796
 * @return       ID of the effect added, or -1 if we failed to add one.
797
 */
798
  public long swirl(Data1D swirl, Data2D center, Data4D region)
799
    {    
800
    return mV.add(EffectNames.SWIRL, swirl, center, region);
801
    }
802

    
803
///////////////////////////////////////////////////////////////////////////////////////////////////
804
/**
805
 * Rotate the whole Object around the Center of the Effect by a certain angle.
806
 *
807
 * @param swirl  The degree of Swirl. Positive values swirl clockwise.
808
 * @param center 2-dimensional Data that, at any given time, returns the Center of the Effect.
809
 * @return       ID of the effect added, or -1 if we failed to add one.
810
 */
811
  public long swirl(Data1D swirl, Data2D center)
812
    {
813
    return mV.add(EffectNames.SWIRL, swirl, center);
814
    }
815
  }
(8-8/18)