Project

General

Profile

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

library / src / main / java / org / distorted / library / DistortedObjectTree.java @ 6537ba91

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 6a06a912 Leszek Koltunski
    boolean mRendered;
55
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 bd3da5b2 Leszek Koltunski
      mRendered       = false;
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
  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 ed13a5de Leszek Koltunski
  private void drawRecursive(long currTime, DistortedFramebuffer df)
88 6a06a912 Leszek Koltunski
    {
89 1942537e Leszek Koltunski
    mTexture.createTexture();
90
91 6a06a912 Leszek Koltunski
    if( mNumChildren[0]<=0 )
92
      {
93 4e2382f3 Leszek Koltunski
      GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexture.mTextureDataH[0]);
94 6a06a912 Leszek Koltunski
      }
95
    else
96
      {
97 8e34674e Leszek Koltunski
      if( !mData.mRendered )
98 6a06a912 Leszek Koltunski
        {
99
        mData.mRendered = true;
100 71c3fecc Leszek Koltunski
        mData.mDF.setAsOutput();
101 bd3da5b2 Leszek Koltunski
102 6a06a912 Leszek Koltunski
        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 4e2382f3 Leszek Koltunski
        if( mTexture.mBitmapSet[0] )
106 6a06a912 Leszek Koltunski
          {
107 4e2382f3 Leszek Koltunski
          GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexture.mTextureDataH[0]);
108
          mQueues.drawNoEffectsPriv(mTexture, mGrid, mData.mDF);
109 6a06a912 Leszek Koltunski
          }
110
      
111
        synchronized(this)
112
          {
113
          for(int i=0; i<mNumChildren[0]; i++)
114
            {
115 ed13a5de Leszek Koltunski
            mChildren.get(i).drawRecursive(currTime, mData.mDF);
116 6a06a912 Leszek Koltunski
            }
117
          }
118
        }
119 bd3da5b2 Leszek Koltunski
120 71c3fecc Leszek Koltunski
      df.setAsOutput();
121
      mData.mDF.setAsInput();
122 6a06a912 Leszek Koltunski
      }
123
    
124 4e2382f3 Leszek Koltunski
    mQueues.drawPriv(currTime, mTexture, mGrid, df);
125 6a06a912 Leszek Koltunski
    }
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 9361b337 Leszek Koltunski
    ArrayList<Long> ret = new ArrayList<>();
151 6a06a912 Leszek Koltunski
     
152 1942537e Leszek Koltunski
    ret.add( mTexture.getID() );
153 b455eb48 Leszek Koltunski
    DistortedObjectTree node;
154 6a06a912 Leszek Koltunski
   
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 fee0865c Leszek Koltunski
    boolean otherNodesPoint = (mData.numPointingNodes>1);
169
170
    if( otherNodesPoint ) mData.numPointingNodes--;
171
    else                  mMapNodeID.remove(oldList);
172 1942537e Leszek Koltunski
173 6a06a912 Leszek Koltunski
    NodeData newData = mMapNodeID.get(newList);
174
    
175
    if( newData==null )
176
      {
177 fee0865c Leszek Koltunski
      if( otherNodesPoint )  mData = new NodeData(++mNextNodeID);
178
      else                   mData.ID = ++mNextNodeID;  // numPointingNodes must be 1 already
179
180 16d8b8f3 Leszek Koltunski
      if( newList.size()>1 )
181
        {
182
        if( mData.mDF==null )
183 4e2382f3 Leszek Koltunski
          mData.mDF = new DistortedFramebuffer(mTexture.getWidth(), mTexture.getHeight());
184 16d8b8f3 Leszek Koltunski
        }
185
      else
186
        {
187
        if( mData.mDF!=null )
188
          {
189
          mData.mDF.markForDeletion();
190
          mData.mDF = null;
191
          }
192
        else
193
          {
194 b455eb48 Leszek Koltunski
          android.util.Log.e("DistortedObjectTree", "adjustNodeData: impossible situation??");
195 16d8b8f3 Leszek Koltunski
          }
196
        }
197 bd3da5b2 Leszek Koltunski
198 6a06a912 Leszek Koltunski
      mMapNodeID.put(newList, mData);
199
      }
200
    else
201 fee0865c Leszek Koltunski
      {
202 6a06a912 Leszek Koltunski
      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 ed13a5de Leszek Koltunski
      if( tmp.mDF != null )
220 6a06a912 Leszek Koltunski
        {
221 ed13a5de Leszek Koltunski
    	  tmp.mDF.reset();
222 6a06a912 Leszek Koltunski
        tmp.mRendered  = false;
223
        }
224
      }
225
    }
226 fee0865c Leszek Koltunski
227
///////////////////////////////////////////////////////////////////////////////////////////////////
228
// Debug - print all the Node IDs
229 1942537e Leszek Koltunski
230 fee0865c Leszek Koltunski
  void debug(int depth)
231
    {
232
    String tmp="";
233
    int i;
234
235
    for(i=0; i<depth; i++) tmp +="   ";
236 1942537e Leszek Koltunski
    tmp += (mData.ID+" (nodes: "+mData.numPointingNodes+")");
237 fee0865c Leszek Koltunski
238 1942537e Leszek Koltunski
    android.util.Log.e("NODE", tmp);
239 fee0865c Leszek Koltunski
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 1942537e Leszek Koltunski
259 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
260
// PUBLIC API
261
///////////////////////////////////////////////////////////////////////////////////////////////////
262
/**
263
 * Constructs new Node of the Tree.
264
 *     
265 4e2382f3 Leszek Koltunski
 * @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 6a06a912 Leszek Koltunski
 */
269 4e2382f3 Leszek Koltunski
  public DistortedObjectTree(DistortedTexture texture, DistortedEffectQueues queues, GridObject grid)
270 6a06a912 Leszek Koltunski
    {
271 4e2382f3 Leszek Koltunski
    mTexture= texture;
272
    mQueues = queues;
273 a56bc359 Leszek Koltunski
    mGrid   = grid;
274 6a06a912 Leszek Koltunski
    mParent = null;
275
    mChildren = null;
276
    mNumChildren = new int[1];
277
    mNumChildren[0] = 0;
278
   
279 9361b337 Leszek Koltunski
    ArrayList<Long> list = new ArrayList<>();
280 1942537e Leszek Koltunski
    list.add(mTexture.getID());
281
282 6a06a912 Leszek Koltunski
    mData = mMapNodeID.get(list);
283
   
284
    if( mData!=null )
285
      {
286
      mData.numPointingNodes++;
287
      }
288
    else
289
      {
290
      mData = new NodeData(++mNextNodeID);   
291 1942537e Leszek Koltunski
      mMapNodeID.put(list, mData);
292 6a06a912 Leszek Koltunski
      }
293
    }
294
295
///////////////////////////////////////////////////////////////////////////////////////////////////  
296
/**
297
 * Copy-constructs new Node of the Tree from another Node.
298
 *     
299 b455eb48 Leszek Koltunski
 * @param node The DistortedObjectTree to copy data from.
300 6a06a912 Leszek Koltunski
 * @param flags bit field composed of a subset of the following:
301 015642fb Leszek Koltunski
 *        {@link Distorted#CLONE_BITMAP},  {@link Distorted#CLONE_MATRIX}, {@link Distorted#CLONE_VERTEX},
302 6a06a912 Leszek Koltunski
 *        {@link Distorted#CLONE_FRAGMENT} and {@link Distorted#CLONE_CHILDREN}.
303
 *        For example flags = CLONE_BITMAP | CLONE_CHILDREN.
304
 */
305 b455eb48 Leszek Koltunski
  public DistortedObjectTree(DistortedObjectTree node, int flags)
306 6a06a912 Leszek Koltunski
    {
307 9361b337 Leszek Koltunski
    mParent = null;
308 4e2382f3 Leszek Koltunski
    mTexture= new DistortedTexture(node.mTexture,flags);
309
    mQueues = new DistortedEffectQueues(node.mQueues, flags);
310 a56bc359 Leszek Koltunski
    mGrid   = node.mGrid;
311 9361b337 Leszek Koltunski
312
    if( (flags & Distorted.CLONE_CHILDREN) != 0 )
313 6a06a912 Leszek Koltunski
      {
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 b455eb48 Leszek Koltunski
  public synchronized void attach(DistortedObjectTree node)
346 6a06a912 Leszek Koltunski
    {
347
    ArrayList<Long> prev = generateIDList(); 
348
   
349 9361b337 Leszek Koltunski
    if( mChildren==null ) mChildren = new ArrayList<>(2);
350 6a06a912 Leszek Koltunski
     
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 4e2382f3 Leszek Koltunski
 * @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 6a06a912 Leszek Koltunski
 * @return the newly constructed child Node, or null if we couldn't allocate resources.
366
 */
367 4e2382f3 Leszek Koltunski
  public synchronized DistortedObjectTree attach(DistortedTexture texture, DistortedEffectQueues queues, GridObject grid)
368 6a06a912 Leszek Koltunski
    {
369
    ArrayList<Long> prev = generateIDList(); 
370
      
371 9361b337 Leszek Koltunski
    if( mChildren==null ) mChildren = new ArrayList<>(2);
372 4e2382f3 Leszek Koltunski
    DistortedObjectTree node = new DistortedObjectTree(texture,queues,grid);
373 6a06a912 Leszek Koltunski
    node.mParent = this;
374
    mChildren.add(node);
375
    mNumChildren[0]++;
376
   
377
    RecomputeNodeID(prev);
378 fee0865c Leszek Koltunski
379 6a06a912 Leszek Koltunski
    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 b455eb48 Leszek Koltunski
  public synchronized boolean detach(DistortedObjectTree node)
390 6a06a912 Leszek Koltunski
    {
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 4e2382f3 Leszek Koltunski
 * @param queues DistortedEffectQueues to remove.
414 6a06a912 Leszek Koltunski
 * @return <code>true</code> if the child was successfully removed.
415
 */
416 4e2382f3 Leszek Koltunski
  public synchronized boolean detach(DistortedEffectQueues queues)
417 6a06a912 Leszek Koltunski
    {
418 4e2382f3 Leszek Koltunski
    long id = queues.getID();
419 b455eb48 Leszek Koltunski
    DistortedObjectTree node;
420 6a06a912 Leszek Koltunski
   
421
    for(int i=0; i<mNumChildren[0]; i++)
422
      {
423
      node = mChildren.get(i);
424
     
425 4e2382f3 Leszek Koltunski
      if( node.mQueues.getID()==id )
426 6a06a912 Leszek Koltunski
        {
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 6537ba91 Leszek Koltunski
 * <p>
467
 * Must be called from a thread holding OpenGL Context
468
 *
469 6a06a912 Leszek Koltunski
 * @param currTime Current time, in milliseconds.
470
 */
471
  public void draw(long currTime)
472
    {  
473
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
474
    markRecursive();
475 ed13a5de Leszek Koltunski
    drawRecursive(currTime,Distorted.mFramebuffer);
476 1942537e Leszek Koltunski
    DistortedFramebuffer.deleteAllMarked();
477
    DistortedTexture.deleteAllMarked();
478 6a06a912 Leszek Koltunski
    }
479 d1e740c5 Leszek Koltunski
480
///////////////////////////////////////////////////////////////////////////////////////////////////
481
/**
482
 * Draws the Node, and all its children, to the Framebuffer passed.
483 6537ba91 Leszek Koltunski
 * <p>
484
 * Must be called from a thread holding OpenGL Context
485 d1e740c5 Leszek Koltunski
 *
486
 * @param currTime Current time, in milliseconds.
487
 * @param df       Framebuffer to render this to.
488
 */
489
  public void draw(long currTime, DistortedFramebuffer df)
490
    {
491
    df.setAsOutput();
492
    markRecursive();
493
    drawRecursive(currTime,df);
494 1942537e Leszek Koltunski
    DistortedFramebuffer.deleteAllMarked();
495
    DistortedTexture.deleteAllMarked();
496 d1e740c5 Leszek Koltunski
    }
497
498 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
499
/**
500 4e2382f3 Leszek Koltunski
 * Returns the DistortedEffectQueues object that's in the Node.
501 6a06a912 Leszek Koltunski
 * 
502 4e2382f3 Leszek Koltunski
 * @return The DistortedEffectQueues contained in the Node.
503 6a06a912 Leszek Koltunski
 */
504 4e2382f3 Leszek Koltunski
  public DistortedEffectQueues getQueues()
505 6a06a912 Leszek Koltunski
    {
506 4e2382f3 Leszek Koltunski
    return mQueues;
507
    }
508
509
///////////////////////////////////////////////////////////////////////////////////////////////////
510
/**
511
 * Returns the DistortedTexture object that's in the Node.
512
 *
513
 * @return The DistortedTexture contained in the Node.
514
 */
515
  public DistortedTexture getTexture()
516
    {
517
    return mTexture;
518 6a06a912 Leszek Koltunski
    }
519
520
///////////////////////////////////////////////////////////////////////////////////////////////////
521
  }