Project

General

Profile

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

library / src / main / java / org / distorted / library / DistortedObjectTree.java @ 1942537e

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.GLES20;
26

    
27
///////////////////////////////////////////////////////////////////////////////////////////////////
28
/**
29
 * Class which represents a Node in a Tree of DistortedObjects.
30
 *  
31
 * Having organized a set of DistortedObjects into a Tree, we can then render any Node to any Framebuffer.
32
 * That recursively renders the Object held in the Node and all its children, along with whatever effects
33
 * each one of them has. 
34
 */
35
public class DistortedObjectTree
36
  {
37
  private static HashMap<ArrayList<Long>,NodeData> mMapNodeID = new HashMap<>();
38
  private static long mNextNodeID =0;
39

    
40
  private GridObject mGrid;
41
  private DistortedEffectQueues mQueues;
42
  private DistortedTexture mTexture;
43
  private NodeData mData;
44

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

    
49
  private class NodeData
50
    {
51
    long ID;
52
    int numPointingNodes;
53
    DistortedFramebuffer mDF;
54
    boolean mRendered;
55

    
56
    NodeData(long id)
57
      {
58
      ID              = id;
59
      numPointingNodes= 1;
60
      mDF             = null;
61
      mRendered       = false;
62
      }
63
    }
64
 
65
///////////////////////////////////////////////////////////////////////////////////////////////////
66

    
67
  static void release()
68
    {
69
    mNextNodeID = 0;
70
    mMapNodeID.clear();
71
    }
72

    
73
///////////////////////////////////////////////////////////////////////////////////////////////////
74

    
75
  private void markRecursive()
76
    {
77
    mData.mRendered = false;
78
   
79
    synchronized(this)
80
      {
81
      for(int i=0; i<mNumChildren[0]; i++) mChildren.get(i).markRecursive();
82
      }
83
    }
84
  
85
///////////////////////////////////////////////////////////////////////////////////////////////////
86
  
87
  private void drawRecursive(long currTime, DistortedFramebuffer df)
88
    {
89
    mTexture.createTexture();
90

    
91
    if( mNumChildren[0]<=0 )
92
      {
93
      GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexture.mTextureDataH[0]);
94
      }
95
    else
96
      {
97
      if( !mData.mRendered )
98
        {
99
        mData.mRendered = true;
100
        mData.mDF.setAsOutput();
101

    
102
        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
103
        GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
104
      
105
        if( mTexture.mBitmapSet[0] )
106
          {
107
          GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexture.mTextureDataH[0]);
108
          mQueues.drawNoEffectsPriv(mTexture, mGrid, mData.mDF);
109
          }
110
      
111
        synchronized(this)
112
          {
113
          for(int i=0; i<mNumChildren[0]; i++)
114
            {
115
            mChildren.get(i).drawRecursive(currTime, mData.mDF);
116
            }
117
          }
118
        }
119

    
120
      df.setAsOutput();
121
      mData.mDF.setAsInput();
122
      }
123
    
124
    mQueues.drawPriv(currTime, mTexture, mGrid, df);
125
    }
126
  
127
///////////////////////////////////////////////////////////////////////////////////////////////////
128
// tree isomorphism
129
  
130
  private void RecomputeNodeID(ArrayList<Long> prev)
131
    {
132
    ArrayList<Long> curr = generateIDList();
133
     
134
    if( mParent==null )
135
      {
136
      adjustNodeData(prev,curr);
137
      }
138
    else
139
      {
140
      ArrayList<Long> parentPrev = mParent.generateIDList();
141
      adjustNodeData(prev,curr);
142
      mParent.RecomputeNodeID(parentPrev);
143
      }
144
    }
145

    
146
///////////////////////////////////////////////////////////////////////////////////////////////////
147

    
148
  private ArrayList<Long> generateIDList()
149
    {
150
    ArrayList<Long> ret = new ArrayList<>();
151
     
152
    ret.add( mTexture.getID() );
153
    DistortedObjectTree node;
154
   
155
    for(int i=0; i<mNumChildren[0]; i++)
156
      {
157
      node = mChildren.get(i);
158
      ret.add(node.mData.ID);
159
      }
160
   
161
    return ret;
162
    }
163

    
164
///////////////////////////////////////////////////////////////////////////////////////////////////
165

    
166
  private void adjustNodeData(ArrayList<Long> oldList, ArrayList<Long> newList)
167
    {
168
    boolean otherNodesPoint = (mData.numPointingNodes>1);
169

    
170
    if( otherNodesPoint ) mData.numPointingNodes--;
171
    else                  mMapNodeID.remove(oldList);
172

    
173
    NodeData newData = mMapNodeID.get(newList);
174
    
175
    if( newData==null )
176
      {
177
      if( otherNodesPoint )  mData = new NodeData(++mNextNodeID);
178
      else                   mData.ID = ++mNextNodeID;  // numPointingNodes must be 1 already
179

    
180
      if( newList.size()>1 )
181
        {
182
        if( mData.mDF==null )
183
          mData.mDF = new DistortedFramebuffer(mTexture.getWidth(), mTexture.getHeight());
184
        }
185
      else
186
        {
187
        if( mData.mDF!=null )
188
          {
189
          mData.mDF.markForDeletion();
190
          mData.mDF = null;
191
          }
192
        else
193
          {
194
          android.util.Log.e("DistortedObjectTree", "adjustNodeData: impossible situation??");
195
          }
196
        }
197

    
198
      mMapNodeID.put(newList, mData);
199
      }
200
    else
201
      {
202
      newData.numPointingNodes++;
203
      mData = newData;
204
      }
205
    }
206

    
207
///////////////////////////////////////////////////////////////////////////////////////////////////  
208
// this will be called on startup and every time OpenGL context has been lost
209
// also call this from the constructor if the OpenGL context has been created already.
210
    
211
  static void reset()
212
    {
213
    NodeData tmp;   
214
     
215
    for(ArrayList<Long> key: mMapNodeID.keySet())
216
      {
217
      tmp = mMapNodeID.get(key);
218
          
219
      if( tmp.mDF != null )
220
        {
221
    	  tmp.mDF.reset();
222
        tmp.mRendered  = false;
223
        }
224
      }
225
    }
226

    
227
///////////////////////////////////////////////////////////////////////////////////////////////////
228
// Debug - print all the Node IDs
229

    
230
  void debug(int depth)
231
    {
232
    String tmp="";
233
    int i;
234

    
235
    for(i=0; i<depth; i++) tmp +="   ";
236
    tmp += (mData.ID+" (nodes: "+mData.numPointingNodes+")");
237

    
238
    android.util.Log.e("NODE", tmp);
239

    
240
    for(i=0; i<mNumChildren[0]; i++)
241
      mChildren.get(i).debug(depth+1);
242
    }
243

    
244
///////////////////////////////////////////////////////////////////////////////////////////////////
245
// Debug - print contents of the HashMap
246

    
247
  static void debugMap()
248
    {
249
    NodeData tmp;
250

    
251
    for(ArrayList<Long> key: mMapNodeID.keySet())
252
      {
253
      tmp = mMapNodeID.get(key);
254

    
255
      android.util.Log.e("NODE", "key="+key+" NodeID: "+tmp.ID);
256
      }
257
    }
258

    
259
///////////////////////////////////////////////////////////////////////////////////////////////////
260
// PUBLIC API
261
///////////////////////////////////////////////////////////////////////////////////////////////////
262
/**
263
 * Constructs new Node of the Tree.
264
 *     
265
 * @param texture DistortedTexture to put into the new Node.
266
 * @param queues  DistortedEffectQueues to put into the new Node.
267
 * @param grid GridObject to put into the new Node.
268
 */
269
  public DistortedObjectTree(DistortedTexture texture, DistortedEffectQueues queues, GridObject grid)
270
    {
271
    mTexture= texture;
272
    mQueues = queues;
273
    mGrid   = grid;
274
    mParent = null;
275
    mChildren = null;
276
    mNumChildren = new int[1];
277
    mNumChildren[0] = 0;
278
   
279
    ArrayList<Long> list = new ArrayList<>();
280
    list.add(mTexture.getID());
281

    
282
    mData = mMapNodeID.get(list);
283
   
284
    if( mData!=null )
285
      {
286
      mData.numPointingNodes++;
287
      }
288
    else
289
      {
290
      mData = new NodeData(++mNextNodeID);   
291
      mMapNodeID.put(list, mData);
292
      }
293
    }
294

    
295
///////////////////////////////////////////////////////////////////////////////////////////////////  
296
/**
297
 * Copy-constructs new Node of the Tree from another Node.
298
 *     
299
 * @param node The DistortedObjectTree to copy data from.
300
 * @param flags bit field composed of a subset of the following:
301
 *        {@link Distorted#CLONE_BITMAP},  {@link Distorted#CLONE_MATRIX}, {@link Distorted#CLONE_VERTEX},
302
 *        {@link Distorted#CLONE_FRAGMENT} and {@link Distorted#CLONE_CHILDREN}.
303
 *        For example flags = CLONE_BITMAP | CLONE_CHILDREN.
304
 */
305
  public DistortedObjectTree(DistortedObjectTree node, int flags)
306
    {
307
    mParent = null;
308
    mTexture= new DistortedTexture(node.mTexture,flags);
309
    mQueues = new DistortedEffectQueues(node.mQueues, flags);
310
    mGrid   = node.mGrid;
311

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

    
379
    return node;
380
    }
381
  
382
///////////////////////////////////////////////////////////////////////////////////////////////////
383
/**
384
 * Removes the first occurrence of a specified child from the list of children of our Node.
385
 * 
386
 * @param node The Node to remove.
387
 * @return <code>true</code> if the child was successfully removed.
388
 */
389
  public synchronized boolean detach(DistortedObjectTree node)
390
    {
391
    if( mNumChildren[0]>0 )
392
      {
393
      ArrayList<Long> prev = generateIDList();  
394
         
395
      if( mChildren.remove(node) )
396
        {
397
        node.mParent = null;  
398
        mNumChildren[0]--;
399
     
400
        RecomputeNodeID(prev);
401
     
402
        return true;
403
        }
404
      }
405
   
406
    return false;
407
    }
408
  
409
///////////////////////////////////////////////////////////////////////////////////////////////////
410
/**
411
 * Removes the first occurrence of a specified child from the list of children of our Node.
412
 * 
413
 * @param queues DistortedEffectQueues to remove.
414
 * @return <code>true</code> if the child was successfully removed.
415
 */
416
  public synchronized boolean detach(DistortedEffectQueues queues)
417
    {
418
    long id = queues.getID();
419
    DistortedObjectTree node;
420
   
421
    for(int i=0; i<mNumChildren[0]; i++)
422
      {
423
      node = mChildren.get(i);
424
     
425
      if( node.mQueues.getID()==id )
426
        {
427
        ArrayList<Long> prev = generateIDList();   
428
     
429
        node.mParent = null;  
430
        mChildren.remove(i);
431
        mNumChildren[0]--;
432
      
433
        RecomputeNodeID(prev);
434
      
435
        return true;
436
        }
437
      }
438
   
439
    return false;
440
    }
441
    
442
///////////////////////////////////////////////////////////////////////////////////////////////////
443
/**
444
 * Removes all children Nodes.
445
 */
446
  public synchronized void detachAll()
447
    {
448
    for(int i=0; i<mNumChildren[0]; i++)
449
      {
450
      mChildren.get(i).mParent = null;
451
      }
452
   
453
    if( mNumChildren[0]>0 )
454
      {
455
      ArrayList<Long> prev = generateIDList();  
456
      
457
      mNumChildren[0] = 0;
458
      mChildren.clear();
459
      RecomputeNodeID(prev);
460
      }
461
    }
462
  
463
///////////////////////////////////////////////////////////////////////////////////////////////////
464
/**
465
 * Draws the Node, and all its children, to the default framebuffer 0 (i.e. the screen).
466
 *   
467
 * @param currTime Current time, in milliseconds.
468
 */
469
  public void draw(long currTime)
470
    {  
471
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
472
    markRecursive();
473
    drawRecursive(currTime,Distorted.mFramebuffer);
474
    DistortedFramebuffer.deleteAllMarked();
475
    DistortedTexture.deleteAllMarked();
476
    }
477

    
478
///////////////////////////////////////////////////////////////////////////////////////////////////
479
/**
480
 * Draws the Node, and all its children, to the Framebuffer passed.
481
 *
482
 * @param currTime Current time, in milliseconds.
483
 * @param df       Framebuffer to render this to.
484
 */
485
  public void draw(long currTime, DistortedFramebuffer df)
486
    {
487
    df.setAsOutput();
488
    markRecursive();
489
    drawRecursive(currTime,df);
490
    DistortedFramebuffer.deleteAllMarked();
491
    DistortedTexture.deleteAllMarked();
492
    }
493

    
494
///////////////////////////////////////////////////////////////////////////////////////////////////
495
/**
496
 * Returns the DistortedEffectQueues object that's in the Node.
497
 * 
498
 * @return The DistortedEffectQueues contained in the Node.
499
 */
500
  public DistortedEffectQueues getQueues()
501
    {
502
    return mQueues;
503
    }
504

    
505
///////////////////////////////////////////////////////////////////////////////////////////////////
506
/**
507
 * Returns the DistortedTexture object that's in the Node.
508
 *
509
 * @return The DistortedTexture contained in the Node.
510
 */
511
  public DistortedTexture getTexture()
512
    {
513
    return mTexture;
514
    }
515

    
516
///////////////////////////////////////////////////////////////////////////////////////////////////
517
  }
518

    
(4-4/15)