Project

General

Profile

« Previous | Next » 

Revision a09ada4c

Added by Leszek Koltunski almost 8 years ago

Preparation for change of the render API.

View differences:

src/main/java/org/distorted/library/Distorted.java
68 68
   */
69 69
  public static final int CLONE_POSTPROCESS= 0x10;
70 70
  /**
71
   * When creating an instance of a DistortedTree from another instance, clone the children Nodes.
71
   * When creating an instance of a DistortedNode from another instance, clone the children Nodes.
72 72
   * <p>
73 73
   * This is mainly useful for creating many similar sub-trees and rendering then at different places
74 74
   * on the screen with (optionally) different Effects.
......
121 121
    DistortedEffects.createProgram(resources);
122 122
    EffectQueuePostprocess.createProgram(resources);
123 123

  
124
    DistortedTree.reset();
124
    DistortedNode.reset();
125 125
    EffectMessageSender.startSending();
126 126

  
127 127
    mInitialized = true;
......
135 135
  public static void onDestroy()
136 136
    {
137 137
    DistortedSurface.onDestroy();
138
    DistortedTree.onDestroy();
138
    DistortedNode.onDestroy();
139 139
    EffectQueue.onDestroy();
140 140
    DistortedEffects.onDestroy();
141 141
    EffectMessageSender.stopSending();
src/main/java/org/distorted/library/DistortedNode.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 java.util.ArrayList;
23
import java.util.HashMap;
24

  
25
import android.opengl.GLES30;
26

  
27
///////////////////////////////////////////////////////////////////////////////////////////////////
28
/**
29
 * Class which represents a Node in a Tree of (InputSurface,Mesh,Effects) triplets.
30
 *  
31
 * Having organized such sets into a Tree, we can then render any Node to any OutputSurface.
32
 * That recursively renders the set held in the Node and all its children.
33
 */
34
public class DistortedNode
35
  {
36
  private static HashMap<ArrayList<Long>,NodeData> mMapNodeID = new HashMap<>();
37
  private static long mNextNodeID =0;
38

  
39
  private MeshObject mMesh;
40
  private DistortedEffects mEffects;
41
  private DistortedInputSurface mSurface;
42
  private NodeData mData;
43

  
44
  private DistortedNode mParent;
45
  private ArrayList<DistortedNode> mChildren;
46
  private int[] mNumChildren;  // ==mChildren.length(), but we only create mChildren if the first one gets added
47

  
48
  private class NodeData
49
    {
50
    long ID;
51
    int numPointingNodes;
52
    int numRendered;
53
    DistortedFramebuffer mFBO;
54

  
55
    NodeData(long id)
56
      {
57
      ID              = id;
58
      numPointingNodes= 1;
59
      numRendered     = 0;
60
      mFBO            = null;
61
      }
62
    }
63
 
64
///////////////////////////////////////////////////////////////////////////////////////////////////
65

  
66
  static synchronized void onDestroy()
67
    {
68
    mNextNodeID = 0;
69
    mMapNodeID.clear();
70
    }
71

  
72
///////////////////////////////////////////////////////////////////////////////////////////////////
73
// tree isomorphism
74
  
75
  private void RecomputeNodeID(ArrayList<Long> prev)
76
    {
77
    ArrayList<Long> curr = generateIDList();
78
     
79
    if( mParent==null )
80
      {
81
      adjustNodeData(prev,curr);
82
      }
83
    else
84
      {
85
      ArrayList<Long> parentPrev = mParent.generateIDList();
86
      adjustNodeData(prev,curr);
87
      mParent.RecomputeNodeID(parentPrev);
88
      }
89
    }
90

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

  
93
  private ArrayList<Long> generateIDList()
94
    {
95
    ArrayList<Long> ret = new ArrayList<>();
96
     
97
    ret.add( mSurface.getID() );
98
    DistortedNode node;
99
   
100
    for(int i=0; i<mNumChildren[0]; i++)
101
      {
102
      node = mChildren.get(i);
103
      ret.add(node.mData.ID);
104
      }
105
   
106
    return ret;
107
    }
108

  
109
///////////////////////////////////////////////////////////////////////////////////////////////////
110

  
111
  private void adjustNodeData(ArrayList<Long> oldList, ArrayList<Long> newList)
112
    {
113
    boolean otherNodesPoint = (mData.numPointingNodes>1);
114

  
115
    if( otherNodesPoint ) mData.numPointingNodes--;
116
    else                  mMapNodeID.remove(oldList);
117

  
118
    NodeData newData = mMapNodeID.get(newList);
119
    
120
    if( newData==null )
121
      {
122
      if( otherNodesPoint )  mData = new NodeData(++mNextNodeID);
123
      else                   mData.ID = ++mNextNodeID;  // numPointingNodes must be 1 already
124

  
125
      if( newList.size()>1 )
126
        {
127
        if( mData.mFBO ==null )
128
          mData.mFBO = new DistortedFramebuffer(mSurface.getWidth(), mSurface.getHeight());
129
        }
130
      else
131
        {
132
        if( mData.mFBO !=null )
133
          {
134
          mData.mFBO.markForDeletion();
135
          mData.mFBO = null;
136
          }
137
        else
138
          {
139
          android.util.Log.e("DistortedNode", "adjustNodeData: impossible situation??");
140
          }
141
        }
142

  
143
      mMapNodeID.put(newList, mData);
144
      }
145
    else
146
      {
147
      newData.numPointingNodes++;
148
      mData = newData;
149
      }
150
    }
151

  
152
///////////////////////////////////////////////////////////////////////////////////////////////////  
153
// this will be called on startup and every time OpenGL context has been lost
154

  
155
  static void reset()
156
    {
157
    NodeData tmp;   
158
     
159
    for(ArrayList<Long> key: mMapNodeID.keySet())
160
      {
161
      tmp = mMapNodeID.get(key);
162
          
163
      if( tmp.mFBO != null ) tmp.numRendered = 0;
164
      }
165
    }
166

  
167
///////////////////////////////////////////////////////////////////////////////////////////////////
168
// Debug - print all the Node IDs
169
/*
170
  void debug(int depth)
171
    {
172
    String tmp="";
173
    int i;
174

  
175
    for(i=0; i<depth; i++) tmp +="   ";
176
    tmp += (mData.ID+" (nodes: "+mData.numPointingNodes+")");
177

  
178
    android.util.Log.e("NODE", tmp);
179

  
180
    for(i=0; i<mNumChildren[0]; i++)
181
      mChildren.get(i).debug(depth+1);
182
    }
183

  
184
///////////////////////////////////////////////////////////////////////////////////////////////////
185
// Debug - print contents of the HashMap
186

  
187
  static void debugMap()
188
    {
189
    NodeData tmp;
190

  
191
    for(ArrayList<Long> key: mMapNodeID.keySet())
192
      {
193
      tmp = mMapNodeID.get(key);
194

  
195
      android.util.Log.e("NODE", "key="+key+" NodeID: "+tmp.ID);
196
      }
197
    }
198
*/
199
///////////////////////////////////////////////////////////////////////////////////////////////////
200

  
201
  void drawRecursive(long currTime, DistortedOutputSurface surface)
202
    {
203
    mSurface.create();
204
    float halfX = mSurface.getWidth()/2.0f;
205
    float halfY = mSurface.getHeight()/2.0f;
206

  
207
    if( mNumChildren[0]<=0 )
208
      {
209
      mSurface.setAsInput();
210
      }
211
    else
212
      {
213
      mData.mFBO.create();
214

  
215
      if( mData.numRendered==0 )
216
        {
217
        mData.mFBO.setAsOutput();
218

  
219
        GLES30.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
220
        GLES30.glClear( GLES30.GL_DEPTH_BUFFER_BIT | GLES30.GL_COLOR_BUFFER_BIT);
221

  
222
        if( mSurface.setAsInput() )
223
          DistortedEffects.drawNoEffectsPriv(halfX, halfY, mMesh, mData.mFBO );
224

  
225
        for(int i=0; i<mNumChildren[0]; i++)
226
          {
227
          mChildren.get(i).drawRecursive(currTime, mData.mFBO);
228
          }
229
        }
230

  
231
      mData.numRendered++;
232
      mData.numRendered %= mData.numPointingNodes;
233
      mData.mFBO.setAsInput();
234
      }
235

  
236
    mEffects.drawPriv(halfX, halfY, mMesh, surface, currTime);
237
    }
238

  
239
///////////////////////////////////////////////////////////////////////////////////////////////////
240
// PUBLIC API
241
///////////////////////////////////////////////////////////////////////////////////////////////////
242
/**
243
 * Constructs new Node.
244
 *     
245
 * @param surface InputSurface to put into the new Node.
246
 * @param effects DistortedEffects to put into the new Node.
247
 * @param mesh MeshObject to put into the new Node.
248
 */
249
  public DistortedNode(DistortedInputSurface surface, DistortedEffects effects, MeshObject mesh)
250
    {
251
    mSurface       = surface;
252
    mEffects       = effects;
253
    mMesh          = mesh;
254
    mParent        = null;
255
    mChildren      = null;
256
    mNumChildren   = new int[1];
257
    mNumChildren[0]= 0;
258
   
259
    ArrayList<Long> list = new ArrayList<>();
260
    list.add(mSurface.getID());
261

  
262
    mData = mMapNodeID.get(list);
263
   
264
    if( mData!=null )
265
      {
266
      mData.numPointingNodes++;
267
      }
268
    else
269
      {
270
      mData = new NodeData(++mNextNodeID);   
271
      mMapNodeID.put(list, mData);
272
      }
273
    }
274

  
275
///////////////////////////////////////////////////////////////////////////////////////////////////  
276
/**
277
 * Copy-constructs new Node from another Node.
278
 *     
279
 * @param node The DistortedNode to copy data from.
280
 * @param flags bit field composed of a subset of the following:
281
 *        {@link Distorted#CLONE_SURFACE},  {@link Distorted#CLONE_MATRIX}, {@link Distorted#CLONE_VERTEX},
282
 *        {@link Distorted#CLONE_FRAGMENT} and {@link Distorted#CLONE_CHILDREN}.
283
 *        For example flags = CLONE_SURFACE | CLONE_CHILDREN.
284
 */
285
  public DistortedNode(DistortedNode node, int flags)
286
    {
287
    mParent = null;
288
    mEffects= new DistortedEffects(node.mEffects,flags);
289
    mMesh = node.mMesh;
290

  
291
    if( (flags & Distorted.CLONE_SURFACE) != 0 )
292
      {
293
      mSurface = node.mSurface;
294
      }
295
    else
296
      {
297
      int w = node.mSurface.getWidth();
298
      int h = node.mSurface.getHeight();
299

  
300
      if( node.mSurface instanceof DistortedTexture )
301
        {
302
        mSurface = new DistortedTexture(w,h);
303
        }
304
      else if( node.mSurface instanceof DistortedFramebuffer )
305
        {
306
        boolean hasDepth = ((DistortedFramebuffer) node.mSurface).hasDepth();
307
        mSurface = new DistortedFramebuffer(w,h,hasDepth);
308
        }
309
      }
310
    if( (flags & Distorted.CLONE_CHILDREN) != 0 )
311
      {
312
      mChildren = node.mChildren;
313
      mNumChildren = node.mNumChildren;
314
      }
315
    else
316
      {
317
      mChildren = null;
318
      mNumChildren = new int[1];
319
      mNumChildren[0] = 0;
320
      }
321
   
322
    ArrayList<Long> list = generateIDList();
323
   
324
    mData = mMapNodeID.get(list);
325
   
326
    if( mData!=null )
327
      {
328
      mData.numPointingNodes++;
329
      }
330
    else
331
      {
332
      mData = new NodeData(++mNextNodeID);   
333
      mMapNodeID.put(list, mData);
334
      }
335
    }
336
  
337
///////////////////////////////////////////////////////////////////////////////////////////////////
338
/**
339
 * Adds a new child to the last position in the list of our Node's children.
340
 * 
341
 * @param node The new Node to add.
342
 */
343
  public synchronized void attach(DistortedNode node)
344
    {
345
    ArrayList<Long> prev = generateIDList(); 
346
   
347
    if( mChildren==null ) mChildren = new ArrayList<>(2);
348
     
349
    node.mParent = this;
350
    mChildren.add(node);
351
    mNumChildren[0]++;
352
     
353
    RecomputeNodeID(prev);
354
    }
355
   
356
///////////////////////////////////////////////////////////////////////////////////////////////////
357
/**
358
 * Adds a new child to the last position in the list of our Node's children.
359
 * 
360
 * @param surface InputSurface to initialize our child Node with.
361
 * @param effects DistortedEffects to initialize our child Node with.
362
 * @param mesh MeshObject to initialize our child Node with.
363
 * @return the newly constructed child Node, or null if we couldn't allocate resources.
364
 */
365
  public synchronized DistortedNode attach(DistortedInputSurface surface, DistortedEffects effects, MeshObject mesh)
366
    {
367
    ArrayList<Long> prev = generateIDList(); 
368
      
369
    if( mChildren==null ) mChildren = new ArrayList<>(2);
370
    DistortedNode node = new DistortedNode(surface,effects,mesh);
371
    node.mParent = this;
372
    mChildren.add(node);
373
    mNumChildren[0]++;
374
   
375
    RecomputeNodeID(prev);
376

  
377
    return node;
378
    }
379
  
380
///////////////////////////////////////////////////////////////////////////////////////////////////
381
/**
382
 * Removes the first occurrence of a specified child from the list of children of our Node.
383
 * 
384
 * @param node The Node to remove.
385
 * @return <code>true</code> if the child was successfully removed.
386
 */
387
  public synchronized boolean detach(DistortedNode node)
388
    {
389
    if( mNumChildren[0]>0 )
390
      {
391
      ArrayList<Long> prev = generateIDList();  
392
         
393
      if( mChildren.remove(node) )
394
        {
395
        node.mParent = null;  
396
        mNumChildren[0]--;
397
     
398
        RecomputeNodeID(prev);
399
     
400
        return true;
401
        }
402
      }
403
   
404
    return false;
405
    }
406

  
407
///////////////////////////////////////////////////////////////////////////////////////////////////
408
/**
409
 * Removes the first occurrence of a specified child from the list of children of our Node.
410
 * <p>
411
 * A bit questionable method as there can be many different Nodes attached as children, some
412
 * of them having the same Effects but - for instance - different Mesh. Use with care.
413
 *
414
 * @param effects DistortedEffects to remove.
415
 * @return <code>true</code> if the child was successfully removed.
416
 */
417
  public synchronized boolean detach(DistortedEffects effects)
418
    {
419
    long id = effects.getID();
420
    DistortedNode node;
421

  
422
    for(int i=0; i<mNumChildren[0]; i++)
423
      {
424
      node = mChildren.get(i);
425

  
426
      if( node.mEffects.getID()==id )
427
        {
428
        ArrayList<Long> prev = generateIDList();
429

  
430
        node.mParent = null;
431
        mChildren.remove(i);
432
        mNumChildren[0]--;
433

  
434
        RecomputeNodeID(prev);
435

  
436
        return true;
437
        }
438
      }
439

  
440
    return false;
441
    }
442

  
443
///////////////////////////////////////////////////////////////////////////////////////////////////
444
/**
445
 * Removes all children Nodes.
446
 */
447
  public synchronized void detachAll()
448
    {
449
    for(int i=0; i<mNumChildren[0]; i++)
450
      {
451
      mChildren.get(i).mParent = null;
452
      }
453
   
454
    if( mNumChildren[0]>0 )
455
      {
456
      ArrayList<Long> prev = generateIDList();  
457
      
458
      mNumChildren[0] = 0;
459
      mChildren.clear();
460
      RecomputeNodeID(prev);
461
      }
462
    }
463

  
464
///////////////////////////////////////////////////////////////////////////////////////////////////
465
/**
466
 * Returns the DistortedEffects object that's in the Node.
467
 * 
468
 * @return The DistortedEffects contained in the Node.
469
 */
470
  public DistortedEffects getEffects()
471
    {
472
    return mEffects;
473
    }
474

  
475
///////////////////////////////////////////////////////////////////////////////////////////////////
476
/**
477
 * Returns the DistortedInputSurface object that's in the Node.
478
 *
479
 * @return The DistortedInputSurface contained in the Node.
480
 */
481
  public DistortedInputSurface getSurface()
482
    {
483
    return mSurface;
484
    }
485

  
486
///////////////////////////////////////////////////////////////////////////////////////////////////
487
/**
488
 * Returns the DistortedFramebuffer object that's in the Node.
489
 *
490
 * @return The DistortedFramebuffer contained in the Node.
491
 */
492
  public DistortedFramebuffer getFramebuffer()
493
    {
494
    return mData.mFBO;
495
    }
496

  
497
  }
src/main/java/org/distorted/library/DistortedOutputSurface.java
20 20
package org.distorted.library;
21 21

  
22 22
import android.opengl.Matrix;
23
import java.util.ArrayList;
23 24

  
24 25
///////////////////////////////////////////////////////////////////////////////////////////////////
25 26

  
26 27
abstract class DistortedOutputSurface extends DistortedSurface
27 28
{
29
  private ArrayList<DistortedNode> mChildren;
30
  private int mNumChildren;   // ==mChildren.length(), but we only create mChildren if the first one gets added
31

  
28 32
  private float mX, mY, mFOV;
29 33
  int mWidth,mHeight,mDepth;
30 34
  float mDistance;
......
114 118
 * <p>
115 119
 * Must be called from a thread holding OpenGL Context.
116 120
 *
117
 * @param dt DistortedTree to render.
121
 * @param dt DistortedNode to render.
118 122
 * @param time Current time, in milliseconds. This will be passed to all the Effects stored in the Tree.
119 123
 */
120
  public void renderTo(DistortedTree dt, long time)
124
  public void renderTo(DistortedNode dt, long time)
121 125
    {
122 126
    DistortedSurface.deleteAllMarked();
123 127
    create();
......
166 170
      if( mColorH[0]>0 ) markForDeletion();
167 171
      }
168 172
    }
173

  
174
///////////////////////////////////////////////////////////////////////////////////////////////////
175
/**
176
 * Adds a new child to the last position in the list of our Surface's children.
177
 *
178
 * @param node The new Node to add.
179
 */
180
  public synchronized void attach(DistortedNode node)
181
    {
182
    if( mChildren==null ) mChildren = new ArrayList<>(2);
183
    mChildren.add(node);
184
    mNumChildren++;
185
    }
186

  
187
///////////////////////////////////////////////////////////////////////////////////////////////////
188
/**
189
 * Adds a new child to the last position in the list of our Surface's children.
190
 *
191
 * @param surface InputSurface to initialize our child Node with.
192
 * @param effects DistortedEffects to initialize our child Node with.
193
 * @param mesh MeshObject to initialize our child Node with.
194
 * @return the newly constructed child Node, or null if we couldn't allocate resources.
195
 */
196
  public synchronized DistortedNode attach(DistortedInputSurface surface, DistortedEffects effects, MeshObject mesh)
197
    {
198
    if( mChildren==null ) mChildren = new ArrayList<>(2);
199
    DistortedNode node = new DistortedNode(surface,effects,mesh);
200
    mChildren.add(node);
201
    mNumChildren++;
202

  
203
    return node;
204
    }
205

  
206
///////////////////////////////////////////////////////////////////////////////////////////////////
207
/**
208
 * Removes the first occurrence of a specified child from the list of children of our Surface.
209
 *
210
 * @param node The Node to remove.
211
 * @return <code>true</code> if the child was successfully removed.
212
 */
213
  public synchronized boolean detach(DistortedNode node)
214
    {
215
    if( mChildren.remove(node) )
216
      {
217
      mNumChildren--;
218
      return true;
219
      }
220

  
221
    return false;
222
    }
223

  
224
///////////////////////////////////////////////////////////////////////////////////////////////////
225
/**
226
 * Removes all children Nodes.
227
 */
228
  public synchronized void detachAll()
229
    {
230
    mNumChildren = 0;
231
    mChildren.clear();
232
    }
169 233
}
src/main/java/org/distorted/library/DistortedTexture.java
41 41
// upper-left corner. Everywhere else the origin is in the lower-left corner. Thus we have to flip.
42 42
// The alternative solution, namely inverting the y-coordinate of the TexCoord does not really work-
43 43
// i.e. it works only in case of rendering directly to the screen, but if we render to an FBO and
44
// then take the FBO and render to screen, (DistortedTree does so!) things get inverted as textures
44
// then take the FBO and render to screen, (DistortedNode does so!) things get inverted as textures
45 45
// created from FBO have their origins in the lower-left... Mindfuck!
46 46

  
47 47
  private static Bitmap flipBitmap(Bitmap src)
src/main/java/org/distorted/library/DistortedTree.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 java.util.ArrayList;
23
import java.util.HashMap;
24

  
25
import android.opengl.GLES30;
26

  
27
///////////////////////////////////////////////////////////////////////////////////////////////////
28
/**
29
 * Class which represents a Node in a Tree of (Texture,Mesh,Effects) objects.
30
 *  
31
 * Having organized such sets into a Tree, we can then render any Node to any Framebuffer.
32
 * That recursively renders the set held in the Node and all its children.
33
 */
34
public class DistortedTree
35
  {
36
  private static HashMap<ArrayList<Long>,NodeData> mMapNodeID = new HashMap<>();
37
  private static long mNextNodeID =0;
38

  
39
  private MeshObject mMesh;
40
  private DistortedEffects mEffects;
41
  private DistortedInputSurface mSurface;
42
  private NodeData mData;
43

  
44
  private DistortedTree mParent;
45
  private ArrayList<DistortedTree> mChildren;
46
  private int[] mNumChildren;  // ==mChildren.length(), but we only create mChildren if the first one gets added
47

  
48
  private class NodeData
49
    {
50
    long ID;
51
    int numPointingNodes;
52
    int numRendered;
53
    DistortedFramebuffer mFBO;
54

  
55
    NodeData(long id)
56
      {
57
      ID              = id;
58
      numPointingNodes= 1;
59
      numRendered     = 0;
60
      mFBO            = null;
61
      }
62
    }
63
 
64
///////////////////////////////////////////////////////////////////////////////////////////////////
65

  
66
  static synchronized void onDestroy()
67
    {
68
    mNextNodeID = 0;
69
    mMapNodeID.clear();
70
    }
71

  
72
///////////////////////////////////////////////////////////////////////////////////////////////////
73
// tree isomorphism
74
  
75
  private void RecomputeNodeID(ArrayList<Long> prev)
76
    {
77
    ArrayList<Long> curr = generateIDList();
78
     
79
    if( mParent==null )
80
      {
81
      adjustNodeData(prev,curr);
82
      }
83
    else
84
      {
85
      ArrayList<Long> parentPrev = mParent.generateIDList();
86
      adjustNodeData(prev,curr);
87
      mParent.RecomputeNodeID(parentPrev);
88
      }
89
    }
90

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

  
93
  private ArrayList<Long> generateIDList()
94
    {
95
    ArrayList<Long> ret = new ArrayList<>();
96
     
97
    ret.add( mSurface.getID() );
98
    DistortedTree node;
99
   
100
    for(int i=0; i<mNumChildren[0]; i++)
101
      {
102
      node = mChildren.get(i);
103
      ret.add(node.mData.ID);
104
      }
105
   
106
    return ret;
107
    }
108

  
109
///////////////////////////////////////////////////////////////////////////////////////////////////
110

  
111
  private void adjustNodeData(ArrayList<Long> oldList, ArrayList<Long> newList)
112
    {
113
    boolean otherNodesPoint = (mData.numPointingNodes>1);
114

  
115
    if( otherNodesPoint ) mData.numPointingNodes--;
116
    else                  mMapNodeID.remove(oldList);
117

  
118
    NodeData newData = mMapNodeID.get(newList);
119
    
120
    if( newData==null )
121
      {
122
      if( otherNodesPoint )  mData = new NodeData(++mNextNodeID);
123
      else                   mData.ID = ++mNextNodeID;  // numPointingNodes must be 1 already
124

  
125
      if( newList.size()>1 )
126
        {
127
        if( mData.mFBO ==null )
128
          mData.mFBO = new DistortedFramebuffer(mSurface.getWidth(), mSurface.getHeight());
129
        }
130
      else
131
        {
132
        if( mData.mFBO !=null )
133
          {
134
          mData.mFBO.markForDeletion();
135
          mData.mFBO = null;
136
          }
137
        else
138
          {
139
          android.util.Log.e("DistortedTree", "adjustNodeData: impossible situation??");
140
          }
141
        }
142

  
143
      mMapNodeID.put(newList, mData);
144
      }
145
    else
146
      {
147
      newData.numPointingNodes++;
148
      mData = newData;
149
      }
150
    }
151

  
152
///////////////////////////////////////////////////////////////////////////////////////////////////  
153
// this will be called on startup and every time OpenGL context has been lost
154

  
155
  static void reset()
156
    {
157
    NodeData tmp;   
158
     
159
    for(ArrayList<Long> key: mMapNodeID.keySet())
160
      {
161
      tmp = mMapNodeID.get(key);
162
          
163
      if( tmp.mFBO != null ) tmp.numRendered = 0;
164
      }
165
    }
166

  
167
///////////////////////////////////////////////////////////////////////////////////////////////////
168
// Debug - print all the Node IDs
169
/*
170
  void debug(int depth)
171
    {
172
    String tmp="";
173
    int i;
174

  
175
    for(i=0; i<depth; i++) tmp +="   ";
176
    tmp += (mData.ID+" (nodes: "+mData.numPointingNodes+")");
177

  
178
    android.util.Log.e("NODE", tmp);
179

  
180
    for(i=0; i<mNumChildren[0]; i++)
181
      mChildren.get(i).debug(depth+1);
182
    }
183

  
184
///////////////////////////////////////////////////////////////////////////////////////////////////
185
// Debug - print contents of the HashMap
186

  
187
  static void debugMap()
188
    {
189
    NodeData tmp;
190

  
191
    for(ArrayList<Long> key: mMapNodeID.keySet())
192
      {
193
      tmp = mMapNodeID.get(key);
194

  
195
      android.util.Log.e("NODE", "key="+key+" NodeID: "+tmp.ID);
196
      }
197
    }
198
*/
199
///////////////////////////////////////////////////////////////////////////////////////////////////
200

  
201
  void drawRecursive(long currTime, DistortedOutputSurface surface)
202
    {
203
    mSurface.create();
204
    float halfX = mSurface.getWidth()/2.0f;
205
    float halfY = mSurface.getHeight()/2.0f;
206

  
207
    if( mNumChildren[0]<=0 )
208
      {
209
      mSurface.setAsInput();
210
      }
211
    else
212
      {
213
      mData.mFBO.create();
214

  
215
      if( mData.numRendered==0 )
216
        {
217
        mData.mFBO.setAsOutput();
218

  
219
        GLES30.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
220
        GLES30.glClear( GLES30.GL_DEPTH_BUFFER_BIT | GLES30.GL_COLOR_BUFFER_BIT);
221

  
222
        if( mSurface.setAsInput() )
223
          DistortedEffects.drawNoEffectsPriv(halfX, halfY, mMesh, mData.mFBO );
224

  
225
        synchronized(this)
226
          {
227
          for(int i=0; i<mNumChildren[0]; i++)
228
            {
229
            mChildren.get(i).drawRecursive(currTime, mData.mFBO);
230
            }
231
          }
232
        }
233

  
234
      mData.numRendered++;
235
      mData.numRendered %= mData.numPointingNodes;
236
      mData.mFBO.setAsInput();
237
      }
238

  
239
    mEffects.drawPriv(halfX, halfY, mMesh, surface, currTime);
240
    }
241

  
242
///////////////////////////////////////////////////////////////////////////////////////////////////
243
// PUBLIC API
244
///////////////////////////////////////////////////////////////////////////////////////////////////
245
/**
246
 * Constructs new Node of the Tree.
247
 *     
248
 * @param surface InputSurface to put into the new Node.
249
 * @param effects DistortedEffects to put into the new Node.
250
 * @param mesh MeshObject to put into the new Node.
251
 */
252
  public DistortedTree(DistortedInputSurface surface, DistortedEffects effects, MeshObject mesh)
253
    {
254
    mSurface       = surface;
255
    mEffects       = effects;
256
    mMesh          = mesh;
257
    mParent        = null;
258
    mChildren      = null;
259
    mNumChildren   = new int[1];
260
    mNumChildren[0]= 0;
261
   
262
    ArrayList<Long> list = new ArrayList<>();
263
    list.add(mSurface.getID());
264

  
265
    mData = mMapNodeID.get(list);
266
   
267
    if( mData!=null )
268
      {
269
      mData.numPointingNodes++;
270
      }
271
    else
272
      {
273
      mData = new NodeData(++mNextNodeID);   
274
      mMapNodeID.put(list, mData);
275
      }
276
    }
277

  
278
///////////////////////////////////////////////////////////////////////////////////////////////////  
279
/**
280
 * Copy-constructs new Node of the Tree from another Node.
281
 *     
282
 * @param node The DistortedTree to copy data from.
283
 * @param flags bit field composed of a subset of the following:
284
 *        {@link Distorted#CLONE_SURFACE},  {@link Distorted#CLONE_MATRIX}, {@link Distorted#CLONE_VERTEX},
285
 *        {@link Distorted#CLONE_FRAGMENT} and {@link Distorted#CLONE_CHILDREN}.
286
 *        For example flags = CLONE_SURFACE | CLONE_CHILDREN.
287
 */
288
  public DistortedTree(DistortedTree node, int flags)
289
    {
290
    mParent = null;
291
    mEffects= new DistortedEffects(node.mEffects,flags);
292
    mMesh = node.mMesh;
293

  
294
    if( (flags & Distorted.CLONE_SURFACE) != 0 )
295
      {
296
      mSurface = node.mSurface;
297
      }
298
    else
299
      {
300
      int w = node.mSurface.getWidth();
301
      int h = node.mSurface.getHeight();
302

  
303
      if( node.mSurface instanceof DistortedTexture )
304
        {
305
        mSurface = new DistortedTexture(w,h);
306
        }
307
      else if( node.mSurface instanceof DistortedFramebuffer )
308
        {
309
        boolean hasDepth = ((DistortedFramebuffer) node.mSurface).hasDepth();
310
        mSurface = new DistortedFramebuffer(w,h,hasDepth);
311
        }
312
      }
313
    if( (flags & Distorted.CLONE_CHILDREN) != 0 )
314
      {
315
      mChildren = node.mChildren;
316
      mNumChildren = node.mNumChildren;
317
      }
318
    else
319
      {
320
      mChildren = null;
321
      mNumChildren = new int[1];
322
      mNumChildren[0] = 0;
323
      }
324
   
325
    ArrayList<Long> list = generateIDList();
326
   
327
    mData = mMapNodeID.get(list);
328
   
329
    if( mData!=null )
330
      {
331
      mData.numPointingNodes++;
332
      }
333
    else
334
      {
335
      mData = new NodeData(++mNextNodeID);   
336
      mMapNodeID.put(list, mData);
337
      }
338
    }
339
  
340
///////////////////////////////////////////////////////////////////////////////////////////////////
341
/**
342
 * Adds a new child to the last position in the list of our Node's children.
343
 * 
344
 * @param node The new Node to add.
345
 */
346
  public synchronized void attach(DistortedTree node)
347
    {
348
    ArrayList<Long> prev = generateIDList(); 
349
   
350
    if( mChildren==null ) mChildren = new ArrayList<>(2);
351
     
352
    node.mParent = this;
353
    mChildren.add(node);
354
    mNumChildren[0]++;
355
     
356
    RecomputeNodeID(prev);
357
    }
358
   
359
///////////////////////////////////////////////////////////////////////////////////////////////////
360
/**
361
 * Adds a new child to the last position in the list of our Node's children.
362
 * 
363
 * @param surface InputSurface to initialize our child Node with.
364
 * @param effects DistortedEffects to initialize our child Node with.
365
 * @param mesh MeshObject to initialize our child Node with.
366
 * @return the newly constructed child Node, or null if we couldn't allocate resources.
367
 */
368
  public synchronized DistortedTree attach(DistortedInputSurface surface, DistortedEffects effects, MeshObject mesh)
369
    {
370
    ArrayList<Long> prev = generateIDList(); 
371
      
372
    if( mChildren==null ) mChildren = new ArrayList<>(2);
373
    DistortedTree node = new DistortedTree(surface,effects,mesh);
374
    node.mParent = this;
375
    mChildren.add(node);
376
    mNumChildren[0]++;
377
   
378
    RecomputeNodeID(prev);
379

  
380
    return node;
381
    }
382
  
383
///////////////////////////////////////////////////////////////////////////////////////////////////
384
/**
385
 * Removes the first occurrence of a specified child from the list of children of our Node.
386
 * 
387
 * @param node The Node to remove.
388
 * @return <code>true</code> if the child was successfully removed.
389
 */
390
  public synchronized boolean detach(DistortedTree node)
391
    {
392
    if( mNumChildren[0]>0 )
393
      {
394
      ArrayList<Long> prev = generateIDList();  
395
         
396
      if( mChildren.remove(node) )
397
        {
398
        node.mParent = null;  
399
        mNumChildren[0]--;
400
     
401
        RecomputeNodeID(prev);
402
     
403
        return true;
404
        }
405
      }
406
   
407
    return false;
408
    }
409
  
410
///////////////////////////////////////////////////////////////////////////////////////////////////
411
/**
412
 * Removes the first occurrence of a specified child from the list of children of our Node.
413
 * 
414
 * @param effects DistortedEffects to remove.
415
 * @return <code>true</code> if the child was successfully removed.
416
 */
417
  public synchronized boolean detach(DistortedEffects effects)
418
    {
419
    long id = effects.getID();
420
    DistortedTree node;
421
   
422
    for(int i=0; i<mNumChildren[0]; i++)
423
      {
424
      node = mChildren.get(i);
425
     
426
      if( node.mEffects.getID()==id )
427
        {
428
        ArrayList<Long> prev = generateIDList();   
429
     
430
        node.mParent = null;  
431
        mChildren.remove(i);
432
        mNumChildren[0]--;
433
      
434
        RecomputeNodeID(prev);
435
      
436
        return true;
437
        }
438
      }
439
   
440
    return false;
441
    }
442
    
443
///////////////////////////////////////////////////////////////////////////////////////////////////
444
/**
445
 * Removes all children Nodes.
446
 */
447
  public synchronized void detachAll()
448
    {
449
    for(int i=0; i<mNumChildren[0]; i++)
450
      {
451
      mChildren.get(i).mParent = null;
452
      }
453
   
454
    if( mNumChildren[0]>0 )
455
      {
456
      ArrayList<Long> prev = generateIDList();  
457
      
458
      mNumChildren[0] = 0;
459
      mChildren.clear();
460
      RecomputeNodeID(prev);
461
      }
462
    }
463

  
464
///////////////////////////////////////////////////////////////////////////////////////////////////
465
/**
466
 * Returns the DistortedEffects object that's in the Node.
467
 * 
468
 * @return The DistortedEffects contained in the Node.
469
 */
470
  public DistortedEffects getEffects()
471
    {
472
    return mEffects;
473
    }
474

  
475
///////////////////////////////////////////////////////////////////////////////////////////////////
476
/**
477
 * Returns the DistortedInputSurface object that's in the Node.
478
 *
479
 * @return The DistortedInputSurface contained in the Node.
480
 */
481
  public DistortedInputSurface getSurface()
482
    {
483
    return mSurface;
484
    }
485

  
486
///////////////////////////////////////////////////////////////////////////////////////////////////
487
/**
488
 * Returns the DistortedFramebuffer object that's in the Node.
489
 *
490
 * @return The DistortedFramebuffer contained in the Node.
491
 */
492
  public DistortedFramebuffer getFramebuffer()
493
    {
494
    return mData.mFBO;
495
    }
496

  
497
  }

Also available in: Unified diff