Project

General

Profile

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

library / src / main / java / org / distorted / library / DistortedObjectTree.java @ d620ff06

1 d333eb6b Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
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 6a06a912 Leszek Koltunski
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 cb0e1940 Leszek Koltunski
 * Class which represents a Node in a Tree of DistortedObjects.
30 6a06a912 Leszek Koltunski
 *  
31 cb0e1940 Leszek Koltunski
 * 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 6a06a912 Leszek Koltunski
 * each one of them has. 
34
 */
35 b455eb48 Leszek Koltunski
public class DistortedObjectTree
36 6a06a912 Leszek Koltunski
  {
37 bd3da5b2 Leszek Koltunski
  private static HashMap<ArrayList<Long>,NodeData> mMapNodeID = new HashMap<>();
38
  private static long mNextNodeID =0;
39
40 b455eb48 Leszek Koltunski
  private GridObject mGrid;
41 4e2382f3 Leszek Koltunski
  private DistortedEffectQueues mQueues;
42
  private DistortedTexture mTexture;
43 6a06a912 Leszek Koltunski
  private NodeData mData;
44 bd3da5b2 Leszek Koltunski
45 b455eb48 Leszek Koltunski
  private DistortedObjectTree mParent;
46
  private ArrayList<DistortedObjectTree> mChildren;
47 6a06a912 Leszek Koltunski
  private int[] mNumChildren;  // ==mChildren.length(), but we only create mChildren if the first one gets added
48
49
  private class NodeData
50
    {
51 bd3da5b2 Leszek Koltunski
    long ID;
52 6a06a912 Leszek Koltunski
    int numPointingNodes;
53 ed13a5de Leszek Koltunski
    DistortedFramebuffer mDF;
54 d620ff06 Leszek Koltunski
    int numRendered;
55 6a06a912 Leszek Koltunski
56 bd3da5b2 Leszek Koltunski
    NodeData(long id)
57 6a06a912 Leszek Koltunski
      {
58 bd3da5b2 Leszek Koltunski
      ID              = id;
59
      numPointingNodes= 1;
60 ed13a5de Leszek Koltunski
      mDF             = null;
61 d620ff06 Leszek Koltunski
      numRendered     = 0;
62 6a06a912 Leszek Koltunski
      }
63 bd3da5b2 Leszek Koltunski
    }
64 6a06a912 Leszek Koltunski
 
65 436899f2 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
66
67 f2a0d837 Leszek Koltunski
  static void release()
68 436899f2 Leszek Koltunski
    {
69
    mNextNodeID = 0;
70
    mMapNodeID.clear();
71
    }
72
73 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
74
  
75 ed13a5de Leszek Koltunski
  private void drawRecursive(long currTime, DistortedFramebuffer df)
76 6a06a912 Leszek Koltunski
    {
77 1942537e Leszek Koltunski
    mTexture.createTexture();
78
79 6a06a912 Leszek Koltunski
    if( mNumChildren[0]<=0 )
80
      {
81 4e2382f3 Leszek Koltunski
      GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexture.mTextureDataH[0]);
82 6a06a912 Leszek Koltunski
      }
83
    else
84
      {
85 d620ff06 Leszek Koltunski
      if( mData.numRendered==0 )
86 6a06a912 Leszek Koltunski
        {
87 71c3fecc Leszek Koltunski
        mData.mDF.setAsOutput();
88 bd3da5b2 Leszek Koltunski
89 6a06a912 Leszek Koltunski
        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
90
        GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
91
      
92 4e2382f3 Leszek Koltunski
        if( mTexture.mBitmapSet[0] )
93 6a06a912 Leszek Koltunski
          {
94 4e2382f3 Leszek Koltunski
          GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexture.mTextureDataH[0]);
95
          mQueues.drawNoEffectsPriv(mTexture, mGrid, mData.mDF);
96 6a06a912 Leszek Koltunski
          }
97
      
98
        synchronized(this)
99
          {
100
          for(int i=0; i<mNumChildren[0]; i++)
101
            {
102 ed13a5de Leszek Koltunski
            mChildren.get(i).drawRecursive(currTime, mData.mDF);
103 6a06a912 Leszek Koltunski
            }
104
          }
105
        }
106 bd3da5b2 Leszek Koltunski
107 d620ff06 Leszek Koltunski
      mData.numRendered++;
108
      mData.numRendered %= mData.numPointingNodes;
109
110 71c3fecc Leszek Koltunski
      df.setAsOutput();
111
      mData.mDF.setAsInput();
112 6a06a912 Leszek Koltunski
      }
113
    
114 4e2382f3 Leszek Koltunski
    mQueues.drawPriv(currTime, mTexture, mGrid, df);
115 6a06a912 Leszek Koltunski
    }
116
  
117
///////////////////////////////////////////////////////////////////////////////////////////////////
118
// tree isomorphism
119
  
120
  private void RecomputeNodeID(ArrayList<Long> prev)
121
    {
122
    ArrayList<Long> curr = generateIDList();
123
     
124
    if( mParent==null )
125
      {
126
      adjustNodeData(prev,curr);
127
      }
128
    else
129
      {
130
      ArrayList<Long> parentPrev = mParent.generateIDList();
131
      adjustNodeData(prev,curr);
132
      mParent.RecomputeNodeID(parentPrev);
133
      }
134
    }
135
136
///////////////////////////////////////////////////////////////////////////////////////////////////
137
138
  private ArrayList<Long> generateIDList()
139
    {
140 9361b337 Leszek Koltunski
    ArrayList<Long> ret = new ArrayList<>();
141 6a06a912 Leszek Koltunski
     
142 1942537e Leszek Koltunski
    ret.add( mTexture.getID() );
143 b455eb48 Leszek Koltunski
    DistortedObjectTree node;
144 6a06a912 Leszek Koltunski
   
145
    for(int i=0; i<mNumChildren[0]; i++)
146
      {
147
      node = mChildren.get(i);
148
      ret.add(node.mData.ID);
149
      }
150
   
151
    return ret;
152
    }
153
154
///////////////////////////////////////////////////////////////////////////////////////////////////
155
156
  private void adjustNodeData(ArrayList<Long> oldList, ArrayList<Long> newList)
157
    {
158 fee0865c Leszek Koltunski
    boolean otherNodesPoint = (mData.numPointingNodes>1);
159
160
    if( otherNodesPoint ) mData.numPointingNodes--;
161
    else                  mMapNodeID.remove(oldList);
162 1942537e Leszek Koltunski
163 6a06a912 Leszek Koltunski
    NodeData newData = mMapNodeID.get(newList);
164
    
165
    if( newData==null )
166
      {
167 fee0865c Leszek Koltunski
      if( otherNodesPoint )  mData = new NodeData(++mNextNodeID);
168
      else                   mData.ID = ++mNextNodeID;  // numPointingNodes must be 1 already
169
170 16d8b8f3 Leszek Koltunski
      if( newList.size()>1 )
171
        {
172
        if( mData.mDF==null )
173 4e2382f3 Leszek Koltunski
          mData.mDF = new DistortedFramebuffer(mTexture.getWidth(), mTexture.getHeight());
174 16d8b8f3 Leszek Koltunski
        }
175
      else
176
        {
177
        if( mData.mDF!=null )
178
          {
179
          mData.mDF.markForDeletion();
180
          mData.mDF = null;
181
          }
182
        else
183
          {
184 b455eb48 Leszek Koltunski
          android.util.Log.e("DistortedObjectTree", "adjustNodeData: impossible situation??");
185 16d8b8f3 Leszek Koltunski
          }
186
        }
187 bd3da5b2 Leszek Koltunski
188 6a06a912 Leszek Koltunski
      mMapNodeID.put(newList, mData);
189
      }
190
    else
191 fee0865c Leszek Koltunski
      {
192 6a06a912 Leszek Koltunski
      newData.numPointingNodes++;
193
      mData = newData;
194
      }
195
    }
196
197
///////////////////////////////////////////////////////////////////////////////////////////////////  
198
// this will be called on startup and every time OpenGL context has been lost
199 d620ff06 Leszek Koltunski
200 6a06a912 Leszek Koltunski
  static void reset()
201
    {
202
    NodeData tmp;   
203
     
204
    for(ArrayList<Long> key: mMapNodeID.keySet())
205
      {
206
      tmp = mMapNodeID.get(key);
207
          
208 ed13a5de Leszek Koltunski
      if( tmp.mDF != null )
209 6a06a912 Leszek Koltunski
        {
210 ed13a5de Leszek Koltunski
    	  tmp.mDF.reset();
211 d620ff06 Leszek Koltunski
        tmp.numRendered = 0;
212 6a06a912 Leszek Koltunski
        }
213
      }
214
    }
215 fee0865c Leszek Koltunski
216
///////////////////////////////////////////////////////////////////////////////////////////////////
217
// Debug - print all the Node IDs
218 1942537e Leszek Koltunski
219 fee0865c Leszek Koltunski
  void debug(int depth)
220
    {
221
    String tmp="";
222
    int i;
223
224
    for(i=0; i<depth; i++) tmp +="   ";
225 1942537e Leszek Koltunski
    tmp += (mData.ID+" (nodes: "+mData.numPointingNodes+")");
226 fee0865c Leszek Koltunski
227 1942537e Leszek Koltunski
    android.util.Log.e("NODE", tmp);
228 fee0865c Leszek Koltunski
229
    for(i=0; i<mNumChildren[0]; i++)
230
      mChildren.get(i).debug(depth+1);
231
    }
232
233
///////////////////////////////////////////////////////////////////////////////////////////////////
234
// Debug - print contents of the HashMap
235
236
  static void debugMap()
237
    {
238
    NodeData tmp;
239
240
    for(ArrayList<Long> key: mMapNodeID.keySet())
241
      {
242
      tmp = mMapNodeID.get(key);
243
244
      android.util.Log.e("NODE", "key="+key+" NodeID: "+tmp.ID);
245
      }
246
    }
247 1942537e Leszek Koltunski
248 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
249
// PUBLIC API
250
///////////////////////////////////////////////////////////////////////////////////////////////////
251
/**
252
 * Constructs new Node of the Tree.
253
 *     
254 4e2382f3 Leszek Koltunski
 * @param texture DistortedTexture to put into the new Node.
255
 * @param queues  DistortedEffectQueues to put into the new Node.
256
 * @param grid GridObject to put into the new Node.
257 6a06a912 Leszek Koltunski
 */
258 4e2382f3 Leszek Koltunski
  public DistortedObjectTree(DistortedTexture texture, DistortedEffectQueues queues, GridObject grid)
259 6a06a912 Leszek Koltunski
    {
260 4e2382f3 Leszek Koltunski
    mTexture= texture;
261
    mQueues = queues;
262 a56bc359 Leszek Koltunski
    mGrid   = grid;
263 6a06a912 Leszek Koltunski
    mParent = null;
264
    mChildren = null;
265
    mNumChildren = new int[1];
266
    mNumChildren[0] = 0;
267
   
268 9361b337 Leszek Koltunski
    ArrayList<Long> list = new ArrayList<>();
269 1942537e Leszek Koltunski
    list.add(mTexture.getID());
270
271 6a06a912 Leszek Koltunski
    mData = mMapNodeID.get(list);
272
   
273
    if( mData!=null )
274
      {
275
      mData.numPointingNodes++;
276
      }
277
    else
278
      {
279
      mData = new NodeData(++mNextNodeID);   
280 1942537e Leszek Koltunski
      mMapNodeID.put(list, mData);
281 6a06a912 Leszek Koltunski
      }
282
    }
283
284
///////////////////////////////////////////////////////////////////////////////////////////////////  
285
/**
286
 * Copy-constructs new Node of the Tree from another Node.
287
 *     
288 b455eb48 Leszek Koltunski
 * @param node The DistortedObjectTree to copy data from.
289 6a06a912 Leszek Koltunski
 * @param flags bit field composed of a subset of the following:
290 015642fb Leszek Koltunski
 *        {@link Distorted#CLONE_BITMAP},  {@link Distorted#CLONE_MATRIX}, {@link Distorted#CLONE_VERTEX},
291 6a06a912 Leszek Koltunski
 *        {@link Distorted#CLONE_FRAGMENT} and {@link Distorted#CLONE_CHILDREN}.
292
 *        For example flags = CLONE_BITMAP | CLONE_CHILDREN.
293
 */
294 b455eb48 Leszek Koltunski
  public DistortedObjectTree(DistortedObjectTree node, int flags)
295 6a06a912 Leszek Koltunski
    {
296 9361b337 Leszek Koltunski
    mParent = null;
297 4e2382f3 Leszek Koltunski
    mTexture= new DistortedTexture(node.mTexture,flags);
298
    mQueues = new DistortedEffectQueues(node.mQueues, flags);
299 a56bc359 Leszek Koltunski
    mGrid   = node.mGrid;
300 9361b337 Leszek Koltunski
301
    if( (flags & Distorted.CLONE_CHILDREN) != 0 )
302 6a06a912 Leszek Koltunski
      {
303
      mChildren = node.mChildren;
304
      mNumChildren = node.mNumChildren;
305
      }
306
    else
307
      {
308
      mChildren = null;
309
      mNumChildren = new int[1];
310
      mNumChildren[0] = 0;
311
      }
312
   
313
    ArrayList<Long> list = generateIDList();
314
   
315
    mData = mMapNodeID.get(list);
316
   
317
    if( mData!=null )
318
      {
319
      mData.numPointingNodes++;
320
      }
321
    else
322
      {
323
      mData = new NodeData(++mNextNodeID);   
324
      mMapNodeID.put(list, mData);
325
      }
326
    }
327
  
328
///////////////////////////////////////////////////////////////////////////////////////////////////
329
/**
330
 * Adds a new child to the last position in the list of our Node's children.
331
 * 
332
 * @param node The new Node to add.
333
 */
334 b455eb48 Leszek Koltunski
  public synchronized void attach(DistortedObjectTree node)
335 6a06a912 Leszek Koltunski
    {
336
    ArrayList<Long> prev = generateIDList(); 
337
   
338 9361b337 Leszek Koltunski
    if( mChildren==null ) mChildren = new ArrayList<>(2);
339 6a06a912 Leszek Koltunski
     
340
    node.mParent = this;
341
    mChildren.add(node);
342
    mNumChildren[0]++;
343
     
344
    RecomputeNodeID(prev);
345
    }
346
   
347
///////////////////////////////////////////////////////////////////////////////////////////////////
348
/**
349
 * Adds a new child to the last position in the list of our Node's children.
350
 * 
351 4e2382f3 Leszek Koltunski
 * @param texture DistortedTexture to initialize our child Node with.
352
 * @param queues DistortedEffectQueues to initialize our child Node with.
353
 * @param grid GridObject to initialize our child Node with.
354 6a06a912 Leszek Koltunski
 * @return the newly constructed child Node, or null if we couldn't allocate resources.
355
 */
356 4e2382f3 Leszek Koltunski
  public synchronized DistortedObjectTree attach(DistortedTexture texture, DistortedEffectQueues queues, GridObject grid)
357 6a06a912 Leszek Koltunski
    {
358
    ArrayList<Long> prev = generateIDList(); 
359
      
360 9361b337 Leszek Koltunski
    if( mChildren==null ) mChildren = new ArrayList<>(2);
361 4e2382f3 Leszek Koltunski
    DistortedObjectTree node = new DistortedObjectTree(texture,queues,grid);
362 6a06a912 Leszek Koltunski
    node.mParent = this;
363
    mChildren.add(node);
364
    mNumChildren[0]++;
365
   
366
    RecomputeNodeID(prev);
367 fee0865c Leszek Koltunski
368 6a06a912 Leszek Koltunski
    return node;
369
    }
370
  
371
///////////////////////////////////////////////////////////////////////////////////////////////////
372
/**
373
 * Removes the first occurrence of a specified child from the list of children of our Node.
374
 * 
375
 * @param node The Node to remove.
376
 * @return <code>true</code> if the child was successfully removed.
377
 */
378 b455eb48 Leszek Koltunski
  public synchronized boolean detach(DistortedObjectTree node)
379 6a06a912 Leszek Koltunski
    {
380
    if( mNumChildren[0]>0 )
381
      {
382
      ArrayList<Long> prev = generateIDList();  
383
         
384
      if( mChildren.remove(node) )
385
        {
386
        node.mParent = null;  
387
        mNumChildren[0]--;
388
     
389
        RecomputeNodeID(prev);
390
     
391
        return true;
392
        }
393
      }
394
   
395
    return false;
396
    }
397
  
398
///////////////////////////////////////////////////////////////////////////////////////////////////
399
/**
400
 * Removes the first occurrence of a specified child from the list of children of our Node.
401
 * 
402 4e2382f3 Leszek Koltunski
 * @param queues DistortedEffectQueues to remove.
403 6a06a912 Leszek Koltunski
 * @return <code>true</code> if the child was successfully removed.
404
 */
405 4e2382f3 Leszek Koltunski
  public synchronized boolean detach(DistortedEffectQueues queues)
406 6a06a912 Leszek Koltunski
    {
407 4e2382f3 Leszek Koltunski
    long id = queues.getID();
408 b455eb48 Leszek Koltunski
    DistortedObjectTree node;
409 6a06a912 Leszek Koltunski
   
410
    for(int i=0; i<mNumChildren[0]; i++)
411
      {
412
      node = mChildren.get(i);
413
     
414 4e2382f3 Leszek Koltunski
      if( node.mQueues.getID()==id )
415 6a06a912 Leszek Koltunski
        {
416
        ArrayList<Long> prev = generateIDList();   
417
     
418
        node.mParent = null;  
419
        mChildren.remove(i);
420
        mNumChildren[0]--;
421
      
422
        RecomputeNodeID(prev);
423
      
424
        return true;
425
        }
426
      }
427
   
428
    return false;
429
    }
430
    
431
///////////////////////////////////////////////////////////////////////////////////////////////////
432
/**
433
 * Removes all children Nodes.
434
 */
435
  public synchronized void detachAll()
436
    {
437
    for(int i=0; i<mNumChildren[0]; i++)
438
      {
439
      mChildren.get(i).mParent = null;
440
      }
441
   
442
    if( mNumChildren[0]>0 )
443
      {
444
      ArrayList<Long> prev = generateIDList();  
445
      
446
      mNumChildren[0] = 0;
447
      mChildren.clear();
448
      RecomputeNodeID(prev);
449
      }
450
    }
451
  
452
///////////////////////////////////////////////////////////////////////////////////////////////////
453
/**
454
 * Draws the Node, and all its children, to the default framebuffer 0 (i.e. the screen).
455 6537ba91 Leszek Koltunski
 * <p>
456
 * Must be called from a thread holding OpenGL Context
457
 *
458 6a06a912 Leszek Koltunski
 * @param currTime Current time, in milliseconds.
459
 */
460
  public void draw(long currTime)
461
    {  
462
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
463 ed13a5de Leszek Koltunski
    drawRecursive(currTime,Distorted.mFramebuffer);
464 1942537e Leszek Koltunski
    DistortedFramebuffer.deleteAllMarked();
465
    DistortedTexture.deleteAllMarked();
466 6a06a912 Leszek Koltunski
    }
467 d1e740c5 Leszek Koltunski
468
///////////////////////////////////////////////////////////////////////////////////////////////////
469
/**
470
 * Draws the Node, and all its children, to the Framebuffer passed.
471 6537ba91 Leszek Koltunski
 * <p>
472
 * Must be called from a thread holding OpenGL Context
473 d1e740c5 Leszek Koltunski
 *
474
 * @param currTime Current time, in milliseconds.
475
 * @param df       Framebuffer to render this to.
476
 */
477
  public void draw(long currTime, DistortedFramebuffer df)
478
    {
479
    df.setAsOutput();
480
    drawRecursive(currTime,df);
481 1942537e Leszek Koltunski
    DistortedFramebuffer.deleteAllMarked();
482
    DistortedTexture.deleteAllMarked();
483 d1e740c5 Leszek Koltunski
    }
484
485 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
486
/**
487 4e2382f3 Leszek Koltunski
 * Returns the DistortedEffectQueues object that's in the Node.
488 6a06a912 Leszek Koltunski
 * 
489 4e2382f3 Leszek Koltunski
 * @return The DistortedEffectQueues contained in the Node.
490 6a06a912 Leszek Koltunski
 */
491 4e2382f3 Leszek Koltunski
  public DistortedEffectQueues getQueues()
492 6a06a912 Leszek Koltunski
    {
493 4e2382f3 Leszek Koltunski
    return mQueues;
494
    }
495
496
///////////////////////////////////////////////////////////////////////////////////////////////////
497
/**
498
 * Returns the DistortedTexture object that's in the Node.
499
 *
500
 * @return The DistortedTexture contained in the Node.
501
 */
502
  public DistortedTexture getTexture()
503
    {
504
    return mTexture;
505 6a06a912 Leszek Koltunski
    }
506
507
///////////////////////////////////////////////////////////////////////////////////////////////////
508
  }