Project

General

Profile

« Previous | Next » 

Revision fe82a979

Added by Leszek Koltunski over 7 years ago

Progress with support for Effect classes.

View differences:

src/main/java/org/distorted/library/Distorted.java
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.app.ActivityManager;
23
import android.content.Context;
24
import android.content.pm.ConfigurationInfo;
25
import android.content.res.Resources;
26

  
27
import org.distorted.library.effect.EffectMessageSender;
28
import org.distorted.library.effect.EffectQueue;
29
import org.distorted.library.effect.EffectQueuePostprocess;
30
import org.distorted.library.program.*;
31

  
32
///////////////////////////////////////////////////////////////////////////////////////////////////
33
/**
34
 * A singleton class used to control various global settings.
35
 */
36
public class Distorted 
37
  {
38
  static int GLSL;
39
  static String GLSL_VERSION;
40
  /**
41
   * When creating an instance of a DistortedTexture from another instance, clone the Bitmap that's
42
   * backing up our DistortedTexture.
43
   * <p>
44
   * This way we can have two DistortedTextures, both backed up by the same Bitmap, to which we can
45
   * apply different effects. Used in the copy constructor.
46
   */
47
  public static final int CLONE_SURFACE = 0x1;
48
  /**
49
   * When creating an instance of a DistortedEffects from another instance, clone the Matrix Effects.
50
   * <p>
51
   * This way we can have two different DistortedEffects sharing the MATRIX queue.
52
   */
53
  public static final int CLONE_MATRIX = 0x2;
54
  /**
55
   * When creating an instance of a DistortedEffects from another instance, clone the Vertex Effects.
56
   * <p>
57
   * This way we can have two different DistortedEffects sharing the VERTEX queue.
58
   */
59
  public static final int CLONE_VERTEX  = 0x4;
60
  /**
61
   * When creating an instance of a DistortedEffects from another instance, clone the Fragment Effects.
62
   * <p>
63
   * This way we can have two different DistortedEffects sharing the FRAGMENT queue.
64
   */
65
  public static final int CLONE_FRAGMENT= 0x8;
66
   /**
67
   * When creating an instance of a DistortedEffects from another instance, clone the PostProcess Effects.
68
   * <p>
69
   * This way we can have two different DistortedEffects sharing the POSTPROCESS queue.
70
   */
71
  public static final int CLONE_POSTPROCESS= 0x10;
72
  /**
73
   * When creating an instance of a DistortedNode from another instance, clone the children Nodes.
74
   * <p>
75
   * This is mainly useful for creating many similar sub-trees and rendering then at different places
76
   * on the screen with (optionally) different Effects.
77
   */
78
  public static final int CLONE_CHILDREN= 0x20;
79

  
80
  private static boolean mInitialized=false;
81

  
82
///////////////////////////////////////////////////////////////////////////////////////////////////
83
// private: hide this from Javadoc
84

  
85
  private Distorted()
86
    {
87

  
88
    }
89

  
90
///////////////////////////////////////////////////////////////////////////////////////////////////
91
/**
92
 * Have we called onCreate yet, ie have we initialized the library?
93
 * @return <code>true</code> if the library is initilized and ready for action.
94
 */
95
  public static boolean isInitialized()
96
    {
97
    return mInitialized;
98
    }
99

  
100
///////////////////////////////////////////////////////////////////////////////////////////////////
101
/**
102
 * When OpenGL context gets created, you need to call this method so that the library can initialise its internal data structures.
103
 * I.e. best called from GLSurfaceView.onCreate().
104
 * <p>
105
 * Needs to be called from a thread holding the OpenGL context.
106
 *   
107
 * @param context Context of the App using the library - used to open up Resources and read Shader code.
108
 * @throws FragmentCompilationException Fragment Shader failed to compile
109
 * @throws VertexCompilationException   Vertex Shader failed to compile
110
 * @throws VertexUniformsException      Too many uniforms in the Vertex Shader
111
 * @throws FragmentUniformsException    Too many uniforms in the Fragment Shader
112
 * @throws LinkingException             Shader failed to link
113
 */
114
  public static void onCreate(final Context context)
115
  throws FragmentCompilationException,VertexCompilationException,VertexUniformsException,FragmentUniformsException,LinkingException
116
    {
117
    final ActivityManager activityManager     = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
118
    final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
119
    android.util.Log.e("DISTORTED", "Using OpenGL ES "+configurationInfo.getGlEsVersion());
120

  
121
    GLSL = ( (configurationInfo.reqGlEsVersion>>16)>=3 ? 300 : 100 );
122
    GLSL_VERSION= (GLSL==100 ? "#version 100\n" : "#version 300 es\n");
123

  
124
    final Resources resources = context.getResources();
125
    DistortedEffects.createProgram(resources);
126
    EffectQueuePostprocess.createProgram(resources);
127
    EffectMessageSender.startSending();
128

  
129
    mInitialized = true;
130
    }
131

  
132
///////////////////////////////////////////////////////////////////////////////////////////////////
133
/**
134
 * Call this so that the Library can release its internal data structures.
135
 * Must be called from Activity.onPause().
136
 */
137
  public static void onPause()
138
    {
139
    DistortedObject.onPause();
140
    DistortedNode.onPause();
141
    }
142

  
143
///////////////////////////////////////////////////////////////////////////////////////////////////
144
/**
145
 * Call this so that the Library can release its internal data structures.
146
 * Must be called from Activity.onDestroy(). 
147
 */
148
  public static void onDestroy()
149
    {
150
    DistortedObject.onDestroy();
151
    DistortedNode.onDestroy();
152
    DistortedEffects.onDestroy();
153
    DistortedEffectsPostprocess.onDestroy();
154
    DistortedMaster.onDestroy();
155
    EffectQueue.onDestroy();
156
    EffectMessageSender.stopSending();
157

  
158
    mInitialized = false;
159
    }
160
  }
src/main/java/org/distorted/library/DistortedEffects.java
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.content.res.Resources;
23
import android.opengl.GLES30;
24

  
25
import org.distorted.library.effect.EffectQueue;
26
import org.distorted.library.effect.EffectQueueFragment;
27
import org.distorted.library.effect.EffectQueueMatrix;
28
import org.distorted.library.effect.EffectQueueVertex;
29
import org.distorted.library.message.EffectListener;
30
import org.distorted.library.program.DistortedProgram;
31
import org.distorted.library.program.FragmentCompilationException;
32
import org.distorted.library.program.FragmentUniformsException;
33
import org.distorted.library.program.LinkingException;
34
import org.distorted.library.program.VertexCompilationException;
35
import org.distorted.library.program.VertexUniformsException;
36
import org.distorted.library.type.Data1D;
37
import org.distorted.library.type.Data2D;
38
import org.distorted.library.type.Data3D;
39
import org.distorted.library.type.Data4D;
40
import org.distorted.library.type.Data5D;
41
import org.distorted.library.type.Static3D;
42

  
43
import java.io.InputStream;
44
import java.nio.ByteBuffer;
45
import java.nio.ByteOrder;
46
import java.nio.FloatBuffer;
47

  
48
///////////////////////////////////////////////////////////////////////////////////////////////////
49
/**
50
 * Class containing Matrix,Vertex and Fragment effect queues. Postprocessing queue is held in a separate
51
 * class.
52
 * <p>
53
 * The queues hold actual effects to be applied to a given (DistortedTexture,MeshObject) combo.
54
 */
55
public class DistortedEffects
56
  {
57
  /// MAIN PROGRAM ///
58
  private static DistortedProgram mMainProgram;
59
  private static int mMainTextureH;
60
  private static boolean[] mEffectEnabled = new boolean[EffectNames.size()];
61

  
62
  static
63
    {
64
    int len = EffectNames.size();
65

  
66
    for(int i=0; i<len; i++)
67
      {
68
      mEffectEnabled[i] = false;
69
      }
70
    }
71

  
72
  /// BLIT PROGRAM ///
73
  private static DistortedProgram mBlitProgram;
74
  private static int mBlitTextureH;
75
  private static int mBlitDepthH;
76
  private static final FloatBuffer mQuadPositions;
77

  
78
  static
79
    {
80
    float[] positionData= { -0.5f, -0.5f,  -0.5f, 0.5f,  0.5f,-0.5f,  0.5f, 0.5f };
81
    mQuadPositions = ByteBuffer.allocateDirect(32).order(ByteOrder.nativeOrder()).asFloatBuffer();
82
    mQuadPositions.put(positionData).position(0);
83
    }
84

  
85
  /// BLIT DEPTH PROGRAM ///
86
  private static DistortedProgram mBlitDepthProgram;
87
  private static int mBlitDepthTextureH;
88
  private static int mBlitDepthDepthTextureH;
89
  private static int mBlitDepthDepthH;
90

  
91
  /// NORMAL PROGRAM /////
92
  private static DistortedProgram mNormalProgram;
93
  private static int mNormalMVPMatrixH;
94
  /// END PROGRAMS //////
95

  
96
  private static long mNextID =0;
97
  private long mID;
98

  
99
  private EffectQueueMatrix mM;
100
  private EffectQueueFragment mF;
101
  private EffectQueueVertex mV;
102

  
103
  private boolean matrixCloned, vertexCloned, fragmentCloned;
104

  
105
///////////////////////////////////////////////////////////////////////////////////////////////////
106

  
107
  static void createProgram(Resources resources)
108
  throws FragmentCompilationException,VertexCompilationException,VertexUniformsException,FragmentUniformsException,LinkingException
109
    {
110
    // MAIN PROGRAM ////////////////////////////////////
111
    final InputStream mainVertStream = resources.openRawResource(R.raw.main_vertex_shader);
112
    final InputStream mainFragStream = resources.openRawResource(R.raw.main_fragment_shader);
113

  
114
    String mainVertHeader= Distorted.GLSL_VERSION;
115
    String mainFragHeader= Distorted.GLSL_VERSION;
116

  
117
    EffectNames name;
118
    EffectTypes type;
119
    boolean foundF = false;
120
    boolean foundV = false;
121

  
122
    for(int i=0; i<mEffectEnabled.length; i++)
123
      {
124
      if( mEffectEnabled[i] )
125
        {
126
        name = EffectNames.getName(i);
127
        type = EffectNames.getType(i);
128

  
129
        if( type == EffectTypes.VERTEX )
130
          {
131
          mainVertHeader += ("#define "+name.name()+" "+name.ordinal()+"\n");
132
          foundV = true;
133
          }
134
        else if( type == EffectTypes.FRAGMENT )
135
          {
136
          mainFragHeader += ("#define "+name.name()+" "+name.ordinal()+"\n");
137
          foundF = true;
138
          }
139
        }
140
      }
141

  
142
    mainVertHeader += ("#define NUM_VERTEX "   + ( foundV ? getMaxVertex()   : 0 ) + "\n");
143
    mainFragHeader += ("#define NUM_FRAGMENT " + ( foundF ? getMaxFragment() : 0 ) + "\n");
144

  
145
    //android.util.Log.e("Effects", "vertHeader= "+mainVertHeader);
146
    //android.util.Log.e("Effects", "fragHeader= "+mainFragHeader);
147

  
148
    String[] feedback = { "v_Position", "v_endPosition" };
149

  
150
    mMainProgram = new DistortedProgram(mainVertStream,mainFragStream, mainVertHeader, mainFragHeader, Distorted.GLSL, feedback);
151

  
152
    int mainProgramH = mMainProgram.getProgramHandle();
153
    EffectQueueFragment.getUniforms(mainProgramH);
154
    EffectQueueVertex.getUniforms(mainProgramH);
155
    EffectQueueMatrix.getUniforms(mainProgramH);
156
    mMainTextureH= GLES30.glGetUniformLocation( mainProgramH, "u_Texture");
157

  
158
    // BLIT PROGRAM ////////////////////////////////////
159
    final InputStream blitVertStream = resources.openRawResource(R.raw.blit_vertex_shader);
160
    final InputStream blitFragStream = resources.openRawResource(R.raw.blit_fragment_shader);
161

  
162
    String blitVertHeader= (Distorted.GLSL_VERSION + "#define NUM_VERTEX 0\n"  );
163
    String blitFragHeader= (Distorted.GLSL_VERSION + "#define NUM_FRAGMENT 0\n");
164

  
165
    try
166
      {
167
      mBlitProgram = new DistortedProgram(blitVertStream,blitFragStream,blitVertHeader,blitFragHeader, Distorted.GLSL);
168
      }
169
    catch(Exception e)
170
      {
171
      android.util.Log.e("EFFECTS", "exception trying to compile BLIT program: "+e.getMessage());
172
      throw new RuntimeException(e.getMessage());
173
      }
174

  
175
    int blitProgramH = mBlitProgram.getProgramHandle();
176
    mBlitTextureH  = GLES30.glGetUniformLocation( blitProgramH, "u_Texture");
177
    mBlitDepthH    = GLES30.glGetUniformLocation( blitProgramH, "u_Depth");
178

  
179
    // BLIT DEPTH PROGRAM ////////////////////////////////////
180
    final InputStream blitDepthVertStream = resources.openRawResource(R.raw.blit_depth_vertex_shader);
181
    final InputStream blitDepthFragStream = resources.openRawResource(R.raw.blit_depth_fragment_shader);
182

  
183
    try
184
      {
185
      mBlitDepthProgram = new DistortedProgram(blitDepthVertStream,blitDepthFragStream,blitVertHeader,blitFragHeader, Distorted.GLSL);
186
      }
187
    catch(Exception e)
188
      {
189
      android.util.Log.e("EFFECTS", "exception trying to compile BLIT DEPTH program: "+e.getMessage());
190
      throw new RuntimeException(e.getMessage());
191
      }
192

  
193
    int blitDepthProgramH   = mBlitDepthProgram.getProgramHandle();
194
    mBlitDepthTextureH      = GLES30.glGetUniformLocation( blitDepthProgramH, "u_Texture");
195
    mBlitDepthDepthTextureH = GLES30.glGetUniformLocation( blitDepthProgramH, "u_DepthTexture");
196
    mBlitDepthDepthH        = GLES30.glGetUniformLocation( blitDepthProgramH, "u_Depth");
197

  
198
    // NORMAL PROGRAM //////////////////////////////////////
199
    final InputStream normalVertexStream   = resources.openRawResource(R.raw.normal_vertex_shader);
200
    final InputStream normalFragmentStream = resources.openRawResource(R.raw.normal_fragment_shader);
201

  
202
    try
203
      {
204
      mNormalProgram = new DistortedProgram(normalVertexStream,normalFragmentStream, Distorted.GLSL_VERSION, Distorted.GLSL_VERSION, Distorted.GLSL);
205
      }
206
    catch(Exception e)
207
      {
208
      android.util.Log.e("EFFECTS", "exception trying to compile NORMAL program: "+e.getMessage());
209
      throw new RuntimeException(e.getMessage());
210
      }
211

  
212
    int normalProgramH = mNormalProgram.getProgramHandle();
213
    mNormalMVPMatrixH  = GLES30.glGetUniformLocation( normalProgramH, "u_MVPMatrix");
214
    }
215

  
216
///////////////////////////////////////////////////////////////////////////////////////////////////
217

  
218
  private void initializeEffectLists(DistortedEffects d, int flags)
219
    {
220
    if( (flags & Distorted.CLONE_MATRIX) != 0 )
221
      {
222
      mM = d.mM;
223
      matrixCloned = true;
224
      }
225
    else
226
      {
227
      mM = new EffectQueueMatrix(mID);
228
      matrixCloned = false;
229
      }
230
    
231
    if( (flags & Distorted.CLONE_VERTEX) != 0 )
232
      {
233
      mV = d.mV;
234
      vertexCloned = true;
235
      }
236
    else
237
      {
238
      mV = new EffectQueueVertex(mID);
239
      vertexCloned = false;
240
      }
241
    
242
    if( (flags & Distorted.CLONE_FRAGMENT) != 0 )
243
      {
244
      mF = d.mF;
245
      fragmentCloned = true;
246
      }
247
    else
248
      {
249
      mF = new EffectQueueFragment(mID);
250
      fragmentCloned = false;
251
      }
252
    }
253

  
254
///////////////////////////////////////////////////////////////////////////////////////////////////
255

  
256
  private void displayNormals(MeshObject mesh)
257
    {
258
    GLES30.glBindBufferBase(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, mesh.mAttTFO[0]);
259
    GLES30.glBeginTransformFeedback( GLES30.GL_POINTS);
260
    DistortedRenderState.switchOffDrawing();
261
    GLES30.glDrawArrays( GLES30.GL_POINTS, 0, mesh.numVertices);
262
    DistortedRenderState.restoreDrawing();
263
    GLES30.glEndTransformFeedback();
264
    GLES30.glBindBufferBase(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
265

  
266
    mNormalProgram.useProgram();
267
    GLES30.glUniformMatrix4fv(mNormalMVPMatrixH, 1, false, mM.getMVP() , 0);
268
    GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, mesh.mAttTFO[0]);
269
    GLES30.glVertexAttribPointer(mNormalProgram.mAttribute[0], MeshObject.POS_DATA_SIZE, GLES30.GL_FLOAT, false, 0, 0);
270
    GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0);
271
    GLES30.glLineWidth(8.0f);
272
    GLES30.glDrawArrays(GLES30.GL_LINES, 0, 2*mesh.numVertices);
273
    }
274

  
275
///////////////////////////////////////////////////////////////////////////////////////////////////
276

  
277
  void drawPriv(float halfW, float halfH, MeshObject mesh, DistortedOutputSurface surface, long currTime, float marginInPixels)
278
    {
279
    mM.compute(currTime);
280
    mV.compute(currTime);
281
    mF.compute(currTime);
282

  
283
    float halfZ = halfW*mesh.zFactor;
284

  
285
    GLES30.glViewport(0, 0, surface.mWidth, surface.mHeight );
286

  
287
    mMainProgram.useProgram();
288
    GLES30.glUniform1i(mMainTextureH, 0);
289

  
290
    if( Distorted.GLSL >= 300 )
291
      {
292
      GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, mesh.mAttVBO[0]);
293
      GLES30.glVertexAttribPointer(mMainProgram.mAttribute[0], MeshObject.POS_DATA_SIZE, GLES30.GL_FLOAT, false, MeshObject.VERTSIZE, MeshObject.OFFSET0);
294
      GLES30.glVertexAttribPointer(mMainProgram.mAttribute[1], MeshObject.NOR_DATA_SIZE, GLES30.GL_FLOAT, false, MeshObject.VERTSIZE, MeshObject.OFFSET1);
295
      GLES30.glVertexAttribPointer(mMainProgram.mAttribute[2], MeshObject.TEX_DATA_SIZE, GLES30.GL_FLOAT, false, MeshObject.VERTSIZE, MeshObject.OFFSET2);
296
      GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0);
297
      }
298
    else
299
      {
300
      mesh.mVertAttribs.position(0);
301
      GLES30.glVertexAttribPointer(mMainProgram.mAttribute[0], MeshObject.POS_DATA_SIZE, GLES30.GL_FLOAT, false, MeshObject.VERTSIZE, mesh.mVertAttribs);
302
      mesh.mVertAttribs.position(MeshObject.POS_DATA_SIZE);
303
      GLES30.glVertexAttribPointer(mMainProgram.mAttribute[1], MeshObject.NOR_DATA_SIZE, GLES30.GL_FLOAT, false, MeshObject.VERTSIZE, mesh.mVertAttribs);
304
      mesh.mVertAttribs.position(MeshObject.POS_DATA_SIZE+MeshObject.NOR_DATA_SIZE);
305
      GLES30.glVertexAttribPointer(mMainProgram.mAttribute[2], MeshObject.TEX_DATA_SIZE, GLES30.GL_FLOAT, false, MeshObject.VERTSIZE, mesh.mVertAttribs);
306
      }
307

  
308
    mM.send(surface,halfW,halfH,halfZ,marginInPixels);
309
    mV.send(halfW,halfH,halfZ);
310
    mF.send(halfW,halfH);
311

  
312
    GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, mesh.numVertices);
313

  
314
    if( mesh.mShowNormals ) displayNormals(mesh);
315
    }
316

  
317
///////////////////////////////////////////////////////////////////////////////////////////////////
318
   
319
  static void blitPriv(DistortedOutputSurface surface)
320
    {
321
    mBlitProgram.useProgram();
322

  
323
    GLES30.glViewport(0, 0, surface.mWidth, surface.mHeight );
324
    GLES30.glUniform1i(mBlitTextureH, 0);
325
    GLES30.glUniform1f( mBlitDepthH , 1.0f-surface.mNear);
326
    GLES30.glVertexAttribPointer(mBlitProgram.mAttribute[0], 2, GLES30.GL_FLOAT, false, 0, mQuadPositions);
327
    GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
328
    }
329

  
330
///////////////////////////////////////////////////////////////////////////////////////////////////
331

  
332
  static void blitDepthPriv(DistortedOutputSurface surface)
333
    {
334
    mBlitDepthProgram.useProgram();
335

  
336
    GLES30.glViewport(0, 0, surface.mWidth, surface.mHeight );
337
    GLES30.glUniform1i(mBlitDepthTextureH, 0);
338
    GLES30.glUniform1i(mBlitDepthDepthTextureH, 1);
339
    GLES30.glUniform1f( mBlitDepthDepthH , 1.0f-surface.mNear);
340
    GLES30.glVertexAttribPointer(mBlitDepthProgram.mAttribute[0], 2, GLES30.GL_FLOAT, false, 0, mQuadPositions);
341
    GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
342
    }
343

  
344
///////////////////////////////////////////////////////////////////////////////////////////////////
345
   
346
  private void releasePriv()
347
    {
348
    if( !matrixCloned   ) mM.abortAll(false);
349
    if( !vertexCloned   ) mV.abortAll(false);
350
    if( !fragmentCloned ) mF.abortAll(false);
351

  
352
    mM = null;
353
    mV = null;
354
    mF = null;
355
    }
356

  
357
///////////////////////////////////////////////////////////////////////////////////////////////////
358

  
359
  static void onDestroy()
360
    {
361
    mNextID = 0;
362

  
363
    int len = EffectNames.size();
364

  
365
    for(int i=0; i<len; i++)
366
      {
367
      mEffectEnabled[i] = false;
368
      }
369
    }
370

  
371
///////////////////////////////////////////////////////////////////////////////////////////////////
372
// PUBLIC API
373
///////////////////////////////////////////////////////////////////////////////////////////////////
374
/**
375
 * Create empty effect queue.
376
 */
377
  public DistortedEffects()
378
    {
379
    mID = ++mNextID;
380
    initializeEffectLists(this,0);
381
    }
382

  
383
///////////////////////////////////////////////////////////////////////////////////////////////////
384
/**
385
 * Copy constructor.
386
 * <p>
387
 * Whatever we do not clone gets created just like in the default constructor.
388
 *
389
 * @param dc    Source object to create our object from
390
 * @param flags A bitmask of values specifying what to copy.
391
 *              For example, CLONE_VERTEX | CLONE_MATRIX.
392
 */
393
  public DistortedEffects(DistortedEffects dc, int flags)
394
    {
395
    mID = ++mNextID;
396
    initializeEffectLists(dc,flags);
397
    }
398

  
399
///////////////////////////////////////////////////////////////////////////////////////////////////
400
/**
401
 * Releases all resources. After this call, the queue should not be used anymore.
402
 */
403
  @SuppressWarnings("unused")
404
  public synchronized void delete()
405
    {
406
    releasePriv();
407
    }
408

  
409
///////////////////////////////////////////////////////////////////////////////////////////////////
410
/**
411
 * Returns unique ID of this instance.
412
 *
413
 * @return ID of the object.
414
 */
415
  public long getID()
416
      {
417
      return mID;
418
      }
419

  
420
///////////////////////////////////////////////////////////////////////////////////////////////////
421
/**
422
 * Adds the calling class to the list of Listeners that get notified each time some event happens 
423
 * to one of the Effects in those queues. Nothing will happen if 'el' is already in the list.
424
 * 
425
 * @param el A class implementing the EffectListener interface that wants to get notifications.
426
 */
427
  @SuppressWarnings("unused")
428
  public void registerForMessages(EffectListener el)
429
    {
430
    mV.registerForMessages(el);
431
    mF.registerForMessages(el);
432
    mM.registerForMessages(el);
433
    }
434

  
435
///////////////////////////////////////////////////////////////////////////////////////////////////
436
/**
437
 * Removes the calling class from the list of Listeners.
438
 * 
439
 * @param el A class implementing the EffectListener interface that no longer wants to get notifications.
440
 */
441
  @SuppressWarnings("unused")
442
  public void deregisterForMessages(EffectListener el)
443
    {
444
    mV.deregisterForMessages(el);
445
    mF.deregisterForMessages(el);
446
    mM.deregisterForMessages(el);
447
    }
448

  
449
///////////////////////////////////////////////////////////////////////////////////////////////////
450
/**
451
 * Aborts all Effects.
452
 * @return Number of effects aborted.
453
 */
454
  public int abortAllEffects()
455
    {
456
    return mM.abortAll(true) + mV.abortAll(true) + mF.abortAll(true);
457
    }
458

  
459
///////////////////////////////////////////////////////////////////////////////////////////////////
460
/**
461
 * Aborts all Effects of a given type, for example all MATRIX Effects.
462
 * 
463
 * @param type one of the constants defined in {@link EffectTypes}
464
 * @return Number of effects aborted.
465
 */
466
  public int abortEffects(EffectTypes type)
467
    {
468
    switch(type)
469
      {
470
      case MATRIX     : return mM.abortAll(true);
471
      case VERTEX     : return mV.abortAll(true);
472
      case FRAGMENT   : return mF.abortAll(true);
473
      default         : return 0;
474
      }
475
    }
476
    
477
///////////////////////////////////////////////////////////////////////////////////////////////////
478
/**
479
 * Aborts a single Effect.
480
 * 
481
 * @param id ID of the Effect we want to abort.
482
 * @return number of Effects aborted. Always either 0 or 1.
483
 */
484
  public int abortEffect(long id)
485
    {
486
    int type = (int)(id&EffectTypes.MASK);
487

  
488
    if( type==EffectTypes.MATRIX.type      ) return mM.removeByID(id>>EffectTypes.LENGTH);
489
    if( type==EffectTypes.VERTEX.type      ) return mV.removeByID(id>>EffectTypes.LENGTH);
490
    if( type==EffectTypes.FRAGMENT.type    ) return mF.removeByID(id>>EffectTypes.LENGTH);
491

  
492
    return 0;
493
    }
494

  
495
///////////////////////////////////////////////////////////////////////////////////////////////////
496
/**
497
 * Abort all Effects of a given name, for example all rotations.
498
 * 
499
 * @param name one of the constants defined in {@link EffectNames}
500
 * @return number of Effects aborted.
501
 */
502
  public int abortEffects(EffectNames name)
503
    {
504
    switch(name.getType())
505
      {
506
      case MATRIX     : return mM.removeByType(name);
507
      case VERTEX     : return mV.removeByType(name);
508
      case FRAGMENT   : return mF.removeByType(name);
509
      default         : return 0;
510
      }
511
    }
512
    
513
///////////////////////////////////////////////////////////////////////////////////////////////////
514
/**
515
 * Print some info about a given Effect to Android's standard out. Used for debugging only.
516
 * 
517
 * @param id Effect ID we want to print info about
518
 * @return <code>true</code> if a single Effect of type effectType has been found.
519
 */
520
  @SuppressWarnings("unused")
521
  public boolean printEffect(long id)
522
    {
523
    int type = (int)(id&EffectTypes.MASK);
524

  
525
    if( type==EffectTypes.MATRIX.type  )  return mM.printByID(id>>EffectTypes.LENGTH);
526
    if( type==EffectTypes.VERTEX.type  )  return mV.printByID(id>>EffectTypes.LENGTH);
527
    if( type==EffectTypes.FRAGMENT.type)  return mF.printByID(id>>EffectTypes.LENGTH);
528

  
529
    return false;
530
    }
531

  
532
///////////////////////////////////////////////////////////////////////////////////////////////////
533
/**
534
 * Enables a given Effect.
535
 * <p>
536
 * By default, all effects are disabled. One has to explicitly enable each effect one intends to use.
537
 * This needs to be called BEFORE shaders get compiled, i.e. before the call to Distorted.onCreate().
538
 * The point: by enabling only the effects we need, we can optimize the shaders.
539
 *
540
 * @param name Name of the Effect to enable.
541
 */
542
  public static void enableEffect(EffectNames name)
543
    {
544
    mEffectEnabled[name.ordinal()] = true;
545
    }
546

  
547
///////////////////////////////////////////////////////////////////////////////////////////////////
548
/**
549
 * Returns the maximum number of Matrix effects.
550
 *
551
 * @return The maximum number of Matrix effects
552
 */
553
  @SuppressWarnings("unused")
554
  public static int getMaxMatrix()
555
    {
556
    return EffectQueue.getMax(EffectTypes.MATRIX.ordinal());
557
    }
558

  
559
///////////////////////////////////////////////////////////////////////////////////////////////////
560
/**
561
 * Returns the maximum number of Vertex effects.
562
 *
563
 * @return The maximum number of Vertex effects
564
 */
565
  @SuppressWarnings("unused")
566
  public static int getMaxVertex()
567
    {
568
    return EffectQueue.getMax(EffectTypes.VERTEX.ordinal());
569
    }
570

  
571
///////////////////////////////////////////////////////////////////////////////////////////////////
572
/**
573
 * Returns the maximum number of Fragment effects.
574
 *
575
 * @return The maximum number of Fragment effects
576
 */
577
  @SuppressWarnings("unused")
578
  public static int getMaxFragment()
579
    {
580
    return EffectQueue.getMax(EffectTypes.FRAGMENT.ordinal());
581
    }
582

  
583
///////////////////////////////////////////////////////////////////////////////////////////////////
584
/**
585
 * Sets the maximum number of Matrix effects that can be stored in a single EffectQueue at one time.
586
 * This can fail if:
587
 * <ul>
588
 * <li>the value of 'max' is outside permitted range (0 &le; max &le; Byte.MAX_VALUE)
589
 * <li>We try to increase the value of 'max' when it is too late to do so already. It needs to be called
590
 *     before the Vertex Shader gets compiled, i.e. before the call to {@link Distorted#onCreate}. After this
591
 *     time only decreasing the value of 'max' is permitted.
592
 * <li>Furthermore, this needs to be called before any instances of the DistortedEffects class get created.
593
 * </ul>
594
 *
595
 * @param max new maximum number of simultaneous Matrix Effects. Has to be a non-negative number not greater
596
 *            than Byte.MAX_VALUE
597
 * @return <code>true</code> if operation was successful, <code>false</code> otherwise.
598
 */
599
  @SuppressWarnings("unused")
600
  public static boolean setMaxMatrix(int max)
601
    {
602
    return EffectQueue.setMax(EffectTypes.MATRIX.ordinal(),max);
603
    }
604

  
605
///////////////////////////////////////////////////////////////////////////////////////////////////
606
/**
607
 * Sets the maximum number of Vertex effects that can be stored in a single EffectQueue at one time.
608
 * This can fail if:
609
 * <ul>
610
 * <li>the value of 'max' is outside permitted range (0 &le; max &le; Byte.MAX_VALUE)
611
 * <li>We try to increase the value of 'max' when it is too late to do so already. It needs to be called
612
 *     before the Vertex Shader gets compiled, i.e. before the call to {@link Distorted#onCreate}. After this
613
 *     time only decreasing the value of 'max' is permitted.
614
* <li>Furthermore, this needs to be called before any instances of the DistortedEffects class get created.
615
 * </ul>
616
 *
617
 * @param max new maximum number of simultaneous Vertex Effects. Has to be a non-negative number not greater
618
 *            than Byte.MAX_VALUE
619
 * @return <code>true</code> if operation was successful, <code>false</code> otherwise.
620
 */
621
  @SuppressWarnings("unused")
622
  public static boolean setMaxVertex(int max)
623
    {
624
    return EffectQueue.setMax(EffectTypes.VERTEX.ordinal(),max);
625
    }
626

  
627
///////////////////////////////////////////////////////////////////////////////////////////////////
628
/**
629
 * Sets the maximum number of Fragment effects that can be stored in a single EffectQueue at one time.
630
 * This can fail if:
631
 * <ul>
632
 * <li>the value of 'max' is outside permitted range (0 &le; max &le; Byte.MAX_VALUE)
633
 * <li>We try to increase the value of 'max' when it is too late to do so already. It needs to be called
634
 *     before the Fragment Shader gets compiled, i.e. before the call to {@link Distorted#onCreate}. After this
635
 *     time only decreasing the value of 'max' is permitted.
636
 * <li>Furthermore, this needs to be called before any instances of the DistortedEffects class get created.
637
 * </ul>
638
 *
639
 * @param max new maximum number of simultaneous Fragment Effects. Has to be a non-negative number not greater
640
 *            than Byte.MAX_VALUE
641
 * @return <code>true</code> if operation was successful, <code>false</code> otherwise.
642
 */
643
  @SuppressWarnings("unused")
644
  public static boolean setMaxFragment(int max)
645
    {
646
    return EffectQueue.setMax(EffectTypes.FRAGMENT.ordinal(),max);
647
    }
648

  
649
///////////////////////////////////////////////////////////////////////////////////////////////////   
650
///////////////////////////////////////////////////////////////////////////////////////////////////
651
// Individual effect functions.
652
///////////////////////////////////////////////////////////////////////////////////////////////////
653
// Matrix-based effects
654
///////////////////////////////////////////////////////////////////////////////////////////////////
655
/**
656
 * Moves the Object by a (possibly changing in time) vector.
657
 * 
658
 * @param vector 3-dimensional Data which at any given time will return a Static3D
659
 *               representing the current coordinates of the vector we want to move the Object with.
660
 * @return       ID of the effect added, or -1 if we failed to add one.
661
 */
662
  public long move(Data3D vector)
663
    {   
664
    return mM.add(EffectNames.MOVE,vector);
665
    }
666

  
667
///////////////////////////////////////////////////////////////////////////////////////////////////
668
/**
669
 * Scales the Object by (possibly changing in time) 3D scale factors.
670
 * 
671
 * @param scale 3-dimensional Data which at any given time returns a Static3D
672
 *              representing the current x- , y- and z- scale factors.
673
 * @return      ID of the effect added, or -1 if we failed to add one.
674
 */
675
  public long scale(Data3D scale)
676
    {   
677
    return mM.add(EffectNames.SCALE,scale);
678
    }
679

  
680
///////////////////////////////////////////////////////////////////////////////////////////////////
681
/**
682
 * Scales the Object by one uniform, constant factor in all 3 dimensions. Convenience function.
683
 *
684
 * @param scale The factor to scale all 3 dimensions with.
685
 * @return      ID of the effect added, or -1 if we failed to add one.
686
 */
687
  public long scale(float scale)
688
    {
689
    return mM.add(EffectNames.SCALE, new Static3D(scale,scale,scale));
690
    }
691

  
692
///////////////////////////////////////////////////////////////////////////////////////////////////
693
/**
694
 * Rotates the Object by 'angle' degrees around the center.
695
 * Static axis of rotation is given by the last parameter.
696
 *
697
 * @param angle  Angle that we want to rotate the Object to. Unit: degrees
698
 * @param axis   Axis of rotation
699
 * @param center Coordinates of the Point we are rotating around.
700
 * @return       ID of the effect added, or -1 if we failed to add one.
701
 */
702
  public long rotate(Data1D angle, Static3D axis, Data3D center )
703
    {   
704
    return mM.add(EffectNames.ROTATE, angle, axis, center);
705
    }
706

  
707
///////////////////////////////////////////////////////////////////////////////////////////////////
708
/**
709
 * Rotates the Object by 'angle' degrees around the center.
710
 * Here both angle and axis can dynamically change.
711
 *
712
 * @param angleaxis Combined 4-tuple representing the (angle,axisX,axisY,axisZ).
713
 * @param center    Coordinates of the Point we are rotating around.
714
 * @return          ID of the effect added, or -1 if we failed to add one.
715
 */
716
  public long rotate(Data4D angleaxis, Data3D center)
717
    {
718
    return mM.add(EffectNames.ROTATE, angleaxis, center);
719
    }
720

  
721
///////////////////////////////////////////////////////////////////////////////////////////////////
722
/**
723
 * Rotates the Object by quaternion.
724
 *
725
 * @param quaternion The quaternion describing the rotation.
726
 * @param center     Coordinates of the Point we are rotating around.
727
 * @return           ID of the effect added, or -1 if we failed to add one.
728
 */
729
  public long quaternion(Data4D quaternion, Data3D center )
730
    {
731
    return mM.add(EffectNames.QUATERNION,quaternion,center);
732
    }
733

  
734
///////////////////////////////////////////////////////////////////////////////////////////////////
735
/**
736
 * Shears the Object.
737
 *
738
 * @param shear   The 3-tuple of shear factors. The first controls level
739
 *                of shearing in the X-axis, second - Y-axis and the third -
740
 *                Z-axis. Each is the tangens of the shear angle, i.e 0 -
741
 *                no shear, 1 - shear by 45 degrees (tan(45deg)=1) etc.
742
 * @param center  Center of shearing, i.e. the point which stays unmoved.
743
 * @return        ID of the effect added, or -1 if we failed to add one.
744
 */
745
  public long shear(Data3D shear, Data3D center)
746
    {
747
    return mM.add(EffectNames.SHEAR, shear, center);
748
    }
749

  
750
///////////////////////////////////////////////////////////////////////////////////////////////////
751
// Fragment-based effects  
752
///////////////////////////////////////////////////////////////////////////////////////////////////
753
/**
754
 * Makes a certain sub-region of the Object smoothly change all three of its RGB components.
755
 *        
756
 * @param blend  1-dimensional Data that returns the level of blend a given pixel will be
757
 *               mixed with the next parameter 'color': pixel = (1-level)*pixel + level*color.
758
 *               Valid range: <0,1>
759
 * @param color  Color to mix. (1,0,0) is RED.
760
 * @param region Region this Effect is limited to.
761
 * @param smooth If true, the level of 'blend' will smoothly fade out towards the edges of the region.
762
 * @return       ID of the effect added, or -1 if we failed to add one.
763
 */
764
  public long chroma(Data1D blend, Data3D color, Data4D region, boolean smooth)
765
    {
766
    return mF.add( smooth? EffectNames.SMOOTH_CHROMA:EffectNames.CHROMA, blend, color, region);
767
    }
768

  
769
///////////////////////////////////////////////////////////////////////////////////////////////////
770
/**
771
 * Makes the whole Object smoothly change all three of its RGB components.
772
 *
773
 * @param blend  1-dimensional Data that returns the level of blend a given pixel will be
774
 *               mixed with the next parameter 'color': pixel = (1-level)*pixel + level*color.
775
 *               Valid range: <0,1>
776
 * @param color  Color to mix. (1,0,0) is RED.
777
 * @return       ID of the effect added, or -1 if we failed to add one.
778
 */
779
  public long chroma(Data1D blend, Data3D color)
780
    {
781
    return mF.add(EffectNames.CHROMA, blend, color);
782
    }
783

  
784
///////////////////////////////////////////////////////////////////////////////////////////////////
785
/**
786
 * Makes a certain sub-region of the Object smoothly change its transparency level.
787
 *        
788
 * @param alpha  1-dimensional Data that returns the level of transparency we want to have at any given
789
 *               moment: pixel.a *= alpha.
790
 *               Valid range: <0,1>
791
 * @param region Region this Effect is limited to. 
792
 * @param smooth If true, the level of 'alpha' will smoothly fade out towards the edges of the region.
793
 * @return       ID of the effect added, or -1 if we failed to add one. 
794
 */
795
  public long alpha(Data1D alpha, Data4D region, boolean smooth)
796
    {
797
    return mF.add( smooth? EffectNames.SMOOTH_ALPHA:EffectNames.ALPHA, alpha, region);
798
    }
799

  
800
///////////////////////////////////////////////////////////////////////////////////////////////////
801
/**
802
 * Makes the whole Object smoothly change its transparency level.
803
 *
804
 * @param alpha  1-dimensional Data that returns the level of transparency we want to have at any
805
 *               given moment: pixel.a *= alpha.
806
 *               Valid range: <0,1>
807
 * @return       ID of the effect added, or -1 if we failed to add one.
808
 */
809
  public long alpha(Data1D alpha)
810
    {
811
    return mF.add(EffectNames.ALPHA, alpha);
812
    }
813

  
814
///////////////////////////////////////////////////////////////////////////////////////////////////
815
/**
816
 * Makes a certain sub-region of the Object smoothly change its brightness level.
817
 *        
818
 * @param brightness 1-dimensional Data that returns the level of brightness we want to have
819
 *                   at any given moment. Valid range: <0,infinity)
820
 * @param region     Region this Effect is limited to.
821
 * @param smooth     If true, the level of 'brightness' will smoothly fade out towards the edges of the region.
822
 * @return           ID of the effect added, or -1 if we failed to add one.
823
 */
824
  public long brightness(Data1D brightness, Data4D region, boolean smooth)
825
    {
826
    return mF.add( smooth ? EffectNames.SMOOTH_BRIGHTNESS: EffectNames.BRIGHTNESS, brightness, region);
827
    }
828

  
829
///////////////////////////////////////////////////////////////////////////////////////////////////
830
/**
831
 * Makes the whole Object smoothly change its brightness level.
832
 *
833
 * @param brightness 1-dimensional Data that returns the level of brightness we want to have
834
 *                   at any given moment. Valid range: <0,infinity)
835
 * @return           ID of the effect added, or -1 if we failed to add one.
836
 */
837
  public long brightness(Data1D brightness)
838
    {
839
    return mF.add(EffectNames.BRIGHTNESS, brightness);
840
    }
841

  
842
///////////////////////////////////////////////////////////////////////////////////////////////////
843
/**
844
 * Makes a certain sub-region of the Object smoothly change its contrast level.
845
 *        
846
 * @param contrast 1-dimensional Data that returns the level of contrast we want to have
847
 *                 at any given moment. Valid range: <0,infinity)
848
 * @param region   Region this Effect is limited to.
849
 * @param smooth   If true, the level of 'contrast' will smoothly fade out towards the edges of the region.
850
 * @return         ID of the effect added, or -1 if we failed to add one.
851
 */
852
  public long contrast(Data1D contrast, Data4D region, boolean smooth)
853
    {
854
    return mF.add( smooth ? EffectNames.SMOOTH_CONTRAST:EffectNames.CONTRAST, contrast, region);
855
    }
856

  
857
///////////////////////////////////////////////////////////////////////////////////////////////////
858
/**
859
 * Makes the whole Object smoothly change its contrast level.
860
 *
861
 * @param contrast 1-dimensional Data that returns the level of contrast we want to have
862
 *                 at any given moment. Valid range: <0,infinity)
863
 * @return         ID of the effect added, or -1 if we failed to add one.
864
 */
865
  public long contrast(Data1D contrast)
866
    {
867
    return mF.add(EffectNames.CONTRAST, contrast);
868
    }
869

  
870
///////////////////////////////////////////////////////////////////////////////////////////////////
871
/**
872
 * Makes a certain sub-region of the Object smoothly change its saturation level.
873
 *        
874
 * @param saturation 1-dimensional Data that returns the level of saturation we want to have
875
 *                   at any given moment. Valid range: <0,infinity)
876
 * @param region     Region this Effect is limited to.
877
 * @param smooth     If true, the level of 'saturation' will smoothly fade out towards the edges of the region.
878
 * @return           ID of the effect added, or -1 if we failed to add one.
879
 */
880
  public long saturation(Data1D saturation, Data4D region, boolean smooth)
881
    {
882
    return mF.add( smooth ? EffectNames.SMOOTH_SATURATION:EffectNames.SATURATION, saturation, region);
883
    }
884

  
885
///////////////////////////////////////////////////////////////////////////////////////////////////
886
/**
887
 * Makes the whole Object smoothly change its saturation level.
888
 *
889
 * @param saturation 1-dimensional Data that returns the level of saturation we want to have
890
 *                   at any given moment. Valid range: <0,infinity)
891
 * @return           ID of the effect added, or -1 if we failed to add one.
892
 */
893
  public long saturation(Data1D saturation)
894
    {
895
    return mF.add(EffectNames.SATURATION, saturation);
896
    }
897

  
898
///////////////////////////////////////////////////////////////////////////////////////////////////
899
// Vertex-based effects  
900
///////////////////////////////////////////////////////////////////////////////////////////////////
901
/**
902
 * Distort a (possibly changing in time) part of the Object by a (possibly changing in time) vector of force.
903
 *
904
 * @param vector 3-dimensional Vector which represents the force the Center of the Effect is
905
 *               currently being dragged with.
906
 * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
907
 * @param region Region that masks the Effect.
908
 * @return       ID of the effect added, or -1 if we failed to add one.
909
 */
910
  public long distort(Data3D vector, Data3D center, Data4D region)
911
    {  
912
    return mV.add(EffectNames.DISTORT, vector, center, region);
913
    }
914

  
915
///////////////////////////////////////////////////////////////////////////////////////////////////
916
/**
917
 * Distort the whole Object by a (possibly changing in time) vector of force.
918
 *
919
 * @param vector 3-dimensional Vector which represents the force the Center of the Effect is
920
 *               currently being dragged with.
921
 * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
922
 * @return       ID of the effect added, or -1 if we failed to add one.
923
 */
924
  public long distort(Data3D vector, Data3D center)
925
    {
926
    return mV.add(EffectNames.DISTORT, vector, center, null);
927
    }
928

  
929
///////////////////////////////////////////////////////////////////////////////////////////////////
930
/**
931
 * Deform the shape of the whole Object with a (possibly changing in time) vector of force applied to
932
 * a (possibly changing in time) point on the Object.
933
 *
934
 * @param vector Vector of force that deforms the shape of the whole Object.
935
 * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
936
 * @param region Region that masks the Effect.
937
 * @return       ID of the effect added, or -1 if we failed to add one.
938
 */
939
  public long deform(Data3D vector, Data3D center, Data4D region)
940
    {
941
    return mV.add(EffectNames.DEFORM, vector, center, region);
942
    }
943

  
944
///////////////////////////////////////////////////////////////////////////////////////////////////
945
/**
946
 * Deform the shape of the whole Object with a (possibly changing in time) vector of force applied to
947
 * a (possibly changing in time) point on the Object.
948
 *     
949
 * @param vector Vector of force that deforms the shape of the whole Object.
950
 * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
951
 * @return       ID of the effect added, or -1 if we failed to add one.
952
 */
953
  public long deform(Data3D vector, Data3D center)
954
    {  
955
    return mV.add(EffectNames.DEFORM, vector, center, null);
956
    }
957

  
958
///////////////////////////////////////////////////////////////////////////////////////////////////  
959
/**
960
 * Pull all points around the center of the Effect towards the center (if degree>=1) or push them
961
 * away from the center (degree<=1)
962
 *
963
 * @param sink   The current degree of the Effect.
964
 * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
965
 * @param region Region that masks the Effect.
966
 * @return       ID of the effect added, or -1 if we failed to add one.
967
 */
968
  public long sink(Data1D sink, Data3D center, Data4D region)
969
    {
970
    return mV.add(EffectNames.SINK, sink, center, region);
971
    }
972

  
973
///////////////////////////////////////////////////////////////////////////////////////////////////
974
/**
975
 * Pull all points around the center of the Effect towards the center (if degree>=1) or push them
976
 * away from the center (degree<=1)
977
 *
978
 * @param sink   The current degree of the Effect.
979
 * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
980
 * @return       ID of the effect added, or -1 if we failed to add one.
981
 */
982
  public long sink(Data1D sink, Data3D center)
983
    {
984
    return mV.add(EffectNames.SINK, sink, center);
985
    }
986

  
987
///////////////////////////////////////////////////////////////////////////////////////////////////
988
/**
989
 * Pull all points around the center of the Effect towards a line passing through the center
990
 * (that's if degree>=1) or push them away from the line (degree<=1)
991
 *
992
 * @param pinch  The current degree of the Effect + angle the line forms with X-axis
993
 * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
994
 * @param region Region that masks the Effect.
995
 * @return       ID of the effect added, or -1 if we failed to add one.
996
 */
997
  public long pinch(Data2D pinch, Data3D center, Data4D region)
998
    {
999
    return mV.add(EffectNames.PINCH, pinch, center, region);
1000
    }
1001

  
1002
///////////////////////////////////////////////////////////////////////////////////////////////////
1003
/**
1004
 * Pull all points around the center of the Effect towards a line passing through the center
1005
 * (that's if degree>=1) or push them away from the line (degree<=1)
1006
 *
1007
 * @param pinch  The current degree of the Effect + angle the line forms with X-axis
1008
 * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
1009
 * @return       ID of the effect added, or -1 if we failed to add one.
1010
 */
1011
  public long pinch(Data2D pinch, Data3D center)
1012
    {
1013
    return mV.add(EffectNames.PINCH, pinch, center);
1014
    }
1015

  
1016
///////////////////////////////////////////////////////////////////////////////////////////////////  
1017
/**
1018
 * Rotate part of the Object around the Center of the Effect by a certain angle.
1019
 *
1020
 * @param swirl  The angle of Swirl (in degrees). Positive values swirl clockwise.
1021
 * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
1022
 * @param region Region that masks the Effect.
1023
 * @return       ID of the effect added, or -1 if we failed to add one.
1024
 */
1025
  public long swirl(Data1D swirl, Data3D center, Data4D region)
1026
    {    
1027
    return mV.add(EffectNames.SWIRL, swirl, center, region);
1028
    }
1029

  
1030
///////////////////////////////////////////////////////////////////////////////////////////////////
1031
/**
1032
 * Rotate the whole Object around the Center of the Effect by a certain angle.
1033
 *
1034
 * @param swirl  The angle of Swirl (in degrees). Positive values swirl clockwise.
1035
 * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
1036
 * @return       ID of the effect added, or -1 if we failed to add one.
1037
 */
1038
  public long swirl(Data1D swirl, Data3D center)
1039
    {
1040
    return mV.add(EffectNames.SWIRL, swirl, center);
1041
    }
1042

  
1043
///////////////////////////////////////////////////////////////////////////////////////////////////
1044
/**
1045
 * Directional, sinusoidal wave effect.
1046
 *
1047
 * @param wave   A 5-dimensional data structure describing the wave: first member is the amplitude,
1048
 *               second is the wave length, third is the phase (i.e. when phase = PI/2, the sine
1049
 *               wave at the center does not start from sin(0), but from sin(PI/2) ) and the next two
1050
 *               describe the 'direction' of the wave.
1051
 *               <p>
1052
 *               Wave direction is defined to be a 3D vector of length 1. To define such vectors, we
1053
 *               need 2 floats: thus the third member is the angle Alpha (in degrees) which the vector
1054
 *               forms with the XY-plane, and the fourth is the angle Beta (again in degrees) which
1055
 *               the projection of the vector to the XY-plane forms with the Y-axis (counterclockwise).
1056
 *               <p>
1057
 *               <p>
1058
 *               Example1: if Alpha = 90, Beta = 90, (then V=(0,0,1) ) and the wave acts 'vertically'
1059
 *               in the X-direction, i.e. cross-sections of the resulting surface with the XZ-plane
1060
 *               will be sine shapes.
1061
 *               <p>
1062
 *               Example2: if Alpha = 90, Beta = 0, the again V=(0,0,1) and the wave is 'vertical',
1063
 *               but this time it waves in the Y-direction, i.e. cross sections of the surface and the
1064
 *               YZ-plane with be sine shapes.
1065
 *               <p>
1066
 *               Example3: if Alpha = 0 and Beta = 45, then V=(sqrt(2)/2, -sqrt(2)/2, 0) and the wave
1067
 *               is entirely 'horizontal' and moves point (x,y,0) in direction V by whatever is the
1068
 *               value if sin at this point.
1069
 * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
1070
 * @return       ID of the effect added, or -1 if we failed to add one.
1071
 */
1072
  public long wave(Data5D wave, Data3D center)
1073
    {
1074
    return mV.add(EffectNames.WAVE, wave, center, null);
1075
    }
1076

  
1077
///////////////////////////////////////////////////////////////////////////////////////////////////
1078
/**
1079
 * Directional, sinusoidal wave effect.
1080
 *
1081
 * @param wave   see {@link DistortedEffects#wave(Data5D,Data3D)}
1082
 * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
1083
 * @param region Region that masks the Effect.
1084
 * @return       ID of the effect added, or -1 if we failed to add one.
1085
 */
1086
  public long wave(Data5D wave, Data3D center, Data4D region)
1087
    {
1088
    return mV.add(EffectNames.WAVE, wave, center, region);
1089
    }
1090
  }
src/main/java/org/distorted/library/DistortedEffectsPostprocess.java
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 org.distorted.library.effect.EffectQueue;
23
import org.distorted.library.effect.EffectQueuePostprocess;
24
import org.distorted.library.message.EffectListener;
25
import org.distorted.library.type.Data1D;
26
import org.distorted.library.type.Data4D;
27

  
28
import java.util.ArrayList;
29

  
30
///////////////////////////////////////////////////////////////////////////////////////////////////
31

  
32
/**
33
 * Class containing the queue of postprocessing effects.
34
 * <p>
35
 * This better be separate from the main DistortedEffects class, because we want to be able to apply
36
 * the same postprocessing effects (i.e. not only the same effects, but the very same instance of this
37
 * object) to several Children of a Node. Reason for that: if several children have the same Object,
38
 * it is easy to group them into 'Buckets' where each bucket has the same postprocessing effects and
39
 * is therefore rendered to the same buffer, which is then postprocessed in one go.
40
 * <p>
41
 * The queue holds actual effects to be applied to a given bucket of several (DistortedTexture,MeshObject) combos.
42
 */
43
public class DistortedEffectsPostprocess implements DistortedSlave
44
  {
45
  private static final int MIPMAP = 0;
46

  
47
  private static long mNextID =0;
48
  private long mID;
49

  
50
  private EffectQueuePostprocess mP;
51

  
52
  private boolean postprocessCloned;
53

  
54
  private class Job
55
    {
56
    int type;
57
    int level;
58

  
59
    Job(int t, int l)
60
      {
61
      type = t;
62
      level= l;
63
      }
64
    }
65

  
66
  private ArrayList<Job> mJobs = new ArrayList<>();
67

  
68
///////////////////////////////////////////////////////////////////////////////////////////////////
69

  
70
  private void initializeEffectLists(DistortedEffectsPostprocess d, int flags)
71
    {
72
    if( (flags & Distorted.CLONE_POSTPROCESS) != 0 )
73
      {
74
      mP = d.mP;
75
      postprocessCloned = true;
76
      }
77
    else
78
      {
79
      mP = new EffectQueuePostprocess(mID);
80
      postprocessCloned = false;
81
      }
82
    }
83

  
84
///////////////////////////////////////////////////////////////////////////////////////////////////
85

  
86
  int postprocess(long time, DistortedOutputSurface surface)
87
    {
88
    return mP.postprocess(time,surface);
89
    }
90

  
91
///////////////////////////////////////////////////////////////////////////////////////////////////
92

  
93
  long getBucket()
94
    {
95
    return mP.mNumEffects==0 ? 0: mID;
96
    }
97

  
98
///////////////////////////////////////////////////////////////////////////////////////////////////
99

  
100
  private void releasePriv()
101
    {
102
    if( !postprocessCloned) mP.abortAll(false);
103

  
104
    mP = null;
105
    }
106

  
107
///////////////////////////////////////////////////////////////////////////////////////////////////
108

  
109
  int getQuality()
110
    {
111
    return mP.mQualityLevel;
112
    }
113

  
114
///////////////////////////////////////////////////////////////////////////////////////////////////
115

  
116
  int getHalo()
117
    {
118
    return mP.getHalo();
119
    }
120

  
121
///////////////////////////////////////////////////////////////////////////////////////////////////
122

  
123
  static void onDestroy()
124
    {
125
    mNextID = 0;
126
    }
127

  
128
///////////////////////////////////////////////////////////////////////////////////////////////////
129
// PUBLIC API
130
///////////////////////////////////////////////////////////////////////////////////////////////////
131
/**
132
 * Create empty effect queue.
133
 */
134
  public DistortedEffectsPostprocess()
135
    {
136
    mID = ++mNextID;
137
    initializeEffectLists(this,0);
138
    }
139

  
140
///////////////////////////////////////////////////////////////////////////////////////////////////
141
/**
142
 * Copy constructor.
143
 * <p>
144
 * Whatever we do not clone gets created just like in the default constructor.
145
 *
146
 * @param dc    Source object to create our object from
147
 * @param flags A bitmask of values specifying what to copy.
148
 *              Currently the only values possible are CLONE_NOTHING or CLONE_POSTPROCESS.
149
 */
150
  public DistortedEffectsPostprocess(DistortedEffectsPostprocess dc, int flags)
151
    {
152
    mID = ++mNextID;
153
    initializeEffectLists(dc,flags);
154
    }
155

  
156
///////////////////////////////////////////////////////////////////////////////////////////////////
157
/**
158
 * This is not really part of the public API. Has to be public only because it is a part of the
159
 * DistortedSlave interface, which should really be a class that we extend here instead but
160
 * Java has no multiple inheritance.
161
 *
162
 * @y.exclude
163
 */
164
  public void doWork()
165
    {
166
    int num = mJobs.size();
167
    Job job;
168

  
169
    for(int i=0; i<num; i++)
170
      {
171
      job = mJobs.remove(0);
172

  
173
      switch(job.type)
174
        {
175
        case MIPMAP: int level = job.level;
176
                     mP.mQualityLevel = level;
177
                     mP.mQualityScale = 1.0f;
178
                     for(int j=0; j<level; j++) mP.mQualityScale*=EffectQuality.MULTIPLIER;
179
                     break;
180
        }
181
      }
182
    }
183

  
184
///////////////////////////////////////////////////////////////////////////////////////////////////
185
/**
186
 * Releases all resources. After this call, the queue should not be used anymore.
187
 */
188
  @SuppressWarnings("unused")
189
  public synchronized void delete()
190
    {
191
    releasePriv();
192
    }
193

  
194
///////////////////////////////////////////////////////////////////////////////////////////////////
195
/**
196
 * Returns unique ID of this instance.
197
 *
198
 * @return ID of the object.
199
 */
200
  @SuppressWarnings("unused")
201
  public long getID()
202
      {
203
      return mID;
204
      }
205

  
206
///////////////////////////////////////////////////////////////////////////////////////////////////
207
/**
208
 * Adds the calling class to the list of Listeners that get notified each time some event happens 
209
 * to one of the Effects in the queues. Nothing will happen if 'el' is already in the list.
210
 * 
211
 * @param el A class implementing the EffectListener interface that wants to get notifications.
212
 */
213
  @SuppressWarnings("unused")
214
  public void registerForMessages(EffectListener el)
215
    {
216
    mP.registerForMessages(el);
217
    }
218

  
219
///////////////////////////////////////////////////////////////////////////////////////////////////
220
/**
221
 * Removes the calling class from the list of Listeners.
222
 * 
223
 * @param el A class implementing the EffectListener interface that no longer wants to get notifications.
224
 */
225
  @SuppressWarnings("unused")
226
  public void deregisterForMessages(EffectListener el)
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff