Project

General

Profile

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

library / src / main / java / org / distorted / library / DistortedObjectTree.java @ 7b8086eb

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