Project

General

Profile

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

library / src / main / java / org / distorted / library / DistortedTree.java @ d6e94c84

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 05403bba Leszek Koltunski
 * Class which represents a Node in a Tree of (Texture,Mesh,Effects) objects.
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 421c2728 Leszek Koltunski
public class DistortedTree
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 05403bba Leszek Koltunski
  private MeshObject mMesh;
40 07d8ef09 Leszek Koltunski
  private DistortedEffects mEffects;
41 4e2382f3 Leszek Koltunski
  private DistortedTexture mTexture;
42 6a06a912 Leszek Koltunski
  private NodeData mData;
43 bd3da5b2 Leszek Koltunski
44 421c2728 Leszek Koltunski
  private DistortedTree mParent;
45
  private ArrayList<DistortedTree> 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 d620ff06 Leszek Koltunski
    int numRendered;
53 8c327653 Leszek Koltunski
    DistortedFramebuffer mFBO;
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 d620ff06 Leszek Koltunski
      numRendered     = 0;
60 8c327653 Leszek Koltunski
      mFBO            = null;
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
// 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 9361b337 Leszek Koltunski
    ArrayList<Long> ret = new ArrayList<>();
96 6a06a912 Leszek Koltunski
     
97 1942537e Leszek Koltunski
    ret.add( mTexture.getID() );
98 421c2728 Leszek Koltunski
    DistortedTree node;
99 6a06a912 Leszek Koltunski
   
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 fee0865c Leszek Koltunski
    boolean otherNodesPoint = (mData.numPointingNodes>1);
114
115
    if( otherNodesPoint ) mData.numPointingNodes--;
116
    else                  mMapNodeID.remove(oldList);
117 1942537e Leszek Koltunski
118 6a06a912 Leszek Koltunski
    NodeData newData = mMapNodeID.get(newList);
119
    
120
    if( newData==null )
121
      {
122 fee0865c Leszek Koltunski
      if( otherNodesPoint )  mData = new NodeData(++mNextNodeID);
123
      else                   mData.ID = ++mNextNodeID;  // numPointingNodes must be 1 already
124
125 16d8b8f3 Leszek Koltunski
      if( newList.size()>1 )
126
        {
127 8c327653 Leszek Koltunski
        if( mData.mFBO ==null )
128
          mData.mFBO = new DistortedFramebuffer(mTexture.getWidth(), mTexture.getHeight());
129 16d8b8f3 Leszek Koltunski
        }
130
      else
131
        {
132 8c327653 Leszek Koltunski
        if( mData.mFBO !=null )
133 16d8b8f3 Leszek Koltunski
          {
134 8c327653 Leszek Koltunski
          mData.mFBO.markForDeletion();
135
          mData.mFBO = null;
136 16d8b8f3 Leszek Koltunski
          }
137
        else
138
          {
139 421c2728 Leszek Koltunski
          android.util.Log.e("DistortedTree", "adjustNodeData: impossible situation??");
140 16d8b8f3 Leszek Koltunski
          }
141
        }
142 bd3da5b2 Leszek Koltunski
143 6a06a912 Leszek Koltunski
      mMapNodeID.put(newList, mData);
144
      }
145
    else
146 fee0865c Leszek Koltunski
      {
147 6a06a912 Leszek Koltunski
      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 d620ff06 Leszek Koltunski
155 6a06a912 Leszek Koltunski
  static void reset()
156
    {
157
    NodeData tmp;   
158
     
159
    for(ArrayList<Long> key: mMapNodeID.keySet())
160
      {
161
      tmp = mMapNodeID.get(key);
162
          
163 8c327653 Leszek Koltunski
      if( tmp.mFBO != null )
164 6a06a912 Leszek Koltunski
        {
165 8c327653 Leszek Koltunski
    	  tmp.mFBO.reset();
166 d620ff06 Leszek Koltunski
        tmp.numRendered = 0;
167 6a06a912 Leszek Koltunski
        }
168
      }
169
    }
170 fee0865c Leszek Koltunski
171
///////////////////////////////////////////////////////////////////////////////////////////////////
172
// Debug - print all the Node IDs
173 ab12f06b Leszek Koltunski
/*
174 fee0865c Leszek Koltunski
  void debug(int depth)
175
    {
176
    String tmp="";
177
    int i;
178
179
    for(i=0; i<depth; i++) tmp +="   ";
180 1942537e Leszek Koltunski
    tmp += (mData.ID+" (nodes: "+mData.numPointingNodes+")");
181 fee0865c Leszek Koltunski
182 1942537e Leszek Koltunski
    android.util.Log.e("NODE", tmp);
183 fee0865c Leszek Koltunski
184
    for(i=0; i<mNumChildren[0]; i++)
185
      mChildren.get(i).debug(depth+1);
186
    }
187
188
///////////////////////////////////////////////////////////////////////////////////////////////////
189
// Debug - print contents of the HashMap
190
191
  static void debugMap()
192
    {
193
    NodeData tmp;
194
195
    for(ArrayList<Long> key: mMapNodeID.keySet())
196
      {
197
      tmp = mMapNodeID.get(key);
198
199
      android.util.Log.e("NODE", "key="+key+" NodeID: "+tmp.ID);
200
      }
201
    }
202 ab12f06b Leszek Koltunski
*/
203 a0f644b7 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
204
205
  void drawRecursive(long currTime, DistortedFramebuffer df)
206
    {
207
    mTexture.createTexture();
208
209
    if( mNumChildren[0]<=0 )
210
      {
211 e7a20702 Leszek Koltunski
      mTexture.setAsInput();
212 a0f644b7 Leszek Koltunski
      }
213
    else
214
      {
215 8c327653 Leszek Koltunski
      mData.mFBO.createFBO();
216 a0f644b7 Leszek Koltunski
217
      if( mData.numRendered==0 )
218
        {
219 8c327653 Leszek Koltunski
        mData.mFBO.setAsOutput();
220 a0f644b7 Leszek Koltunski
221
        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
222
        GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
223
224 e7a20702 Leszek Koltunski
        if( mTexture.setAsInput() )
225 d6e94c84 Leszek Koltunski
          DistortedEffects.drawNoEffectsPriv(mTexture.mHalfX, mTexture.mHalfY, mMesh, mData.mFBO);
226 a0f644b7 Leszek Koltunski
227
        synchronized(this)
228
          {
229
          for(int i=0; i<mNumChildren[0]; i++)
230
            {
231 8c327653 Leszek Koltunski
            mChildren.get(i).drawRecursive(currTime, mData.mFBO);
232 a0f644b7 Leszek Koltunski
            }
233
          }
234
        }
235
236
      mData.numRendered++;
237
      mData.numRendered %= mData.numPointingNodes;
238
239 da99dd30 Leszek Koltunski
      df.setAsOutput();
240 8c327653 Leszek Koltunski
      mData.mFBO.setAsInput();
241 a0f644b7 Leszek Koltunski
      }
242
243 05403bba Leszek Koltunski
    mEffects.drawPriv(mTexture.mHalfX, mTexture.mHalfY, mMesh, df, currTime);
244 a0f644b7 Leszek Koltunski
    }
245
246 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
247
// PUBLIC API
248
///////////////////////////////////////////////////////////////////////////////////////////////////
249
/**
250
 * Constructs new Node of the Tree.
251
 *     
252 4e2382f3 Leszek Koltunski
 * @param texture DistortedTexture to put into the new Node.
253 07d8ef09 Leszek Koltunski
 * @param effects DistortedEffects to put into the new Node.
254 05403bba Leszek Koltunski
 * @param mesh MeshObject to put into the new Node.
255 6a06a912 Leszek Koltunski
 */
256 05403bba Leszek Koltunski
  public DistortedTree(DistortedTexture texture, DistortedEffects effects, MeshObject mesh)
257 6a06a912 Leszek Koltunski
    {
258 4e2382f3 Leszek Koltunski
    mTexture= texture;
259 07d8ef09 Leszek Koltunski
    mEffects= effects;
260 05403bba Leszek Koltunski
    mMesh   = mesh;
261 6a06a912 Leszek Koltunski
    mParent = null;
262
    mChildren = null;
263
    mNumChildren = new int[1];
264
    mNumChildren[0] = 0;
265
   
266 9361b337 Leszek Koltunski
    ArrayList<Long> list = new ArrayList<>();
267 1942537e Leszek Koltunski
    list.add(mTexture.getID());
268
269 6a06a912 Leszek Koltunski
    mData = mMapNodeID.get(list);
270
   
271
    if( mData!=null )
272
      {
273
      mData.numPointingNodes++;
274
      }
275
    else
276
      {
277
      mData = new NodeData(++mNextNodeID);   
278 1942537e Leszek Koltunski
      mMapNodeID.put(list, mData);
279 6a06a912 Leszek Koltunski
      }
280
    }
281
282
///////////////////////////////////////////////////////////////////////////////////////////////////  
283
/**
284
 * Copy-constructs new Node of the Tree from another Node.
285
 *     
286 421c2728 Leszek Koltunski
 * @param node The DistortedTree to copy data from.
287 6a06a912 Leszek Koltunski
 * @param flags bit field composed of a subset of the following:
288 015642fb Leszek Koltunski
 *        {@link Distorted#CLONE_BITMAP},  {@link Distorted#CLONE_MATRIX}, {@link Distorted#CLONE_VERTEX},
289 6a06a912 Leszek Koltunski
 *        {@link Distorted#CLONE_FRAGMENT} and {@link Distorted#CLONE_CHILDREN}.
290
 *        For example flags = CLONE_BITMAP | CLONE_CHILDREN.
291
 */
292 421c2728 Leszek Koltunski
  public DistortedTree(DistortedTree node, int flags)
293 6a06a912 Leszek Koltunski
    {
294 9361b337 Leszek Koltunski
    mParent = null;
295 432442f9 Leszek Koltunski
    mEffects= new DistortedEffects(node.mEffects,flags);
296 05403bba Leszek Koltunski
    mMesh = node.mMesh;
297 9361b337 Leszek Koltunski
298 e7a20702 Leszek Koltunski
    if( (flags & Distorted.CLONE_BITMAP) != 0 )
299
      {
300
      mTexture = node.mTexture;
301
      }
302
    else
303
      {
304
      mTexture = new DistortedTexture(node.mTexture.getWidth(), node.mTexture.getHeight());
305
      }
306 9361b337 Leszek Koltunski
    if( (flags & Distorted.CLONE_CHILDREN) != 0 )
307 6a06a912 Leszek Koltunski
      {
308
      mChildren = node.mChildren;
309
      mNumChildren = node.mNumChildren;
310
      }
311
    else
312
      {
313
      mChildren = null;
314
      mNumChildren = new int[1];
315
      mNumChildren[0] = 0;
316
      }
317
   
318
    ArrayList<Long> list = generateIDList();
319
   
320
    mData = mMapNodeID.get(list);
321
   
322
    if( mData!=null )
323
      {
324
      mData.numPointingNodes++;
325
      }
326
    else
327
      {
328
      mData = new NodeData(++mNextNodeID);   
329
      mMapNodeID.put(list, mData);
330
      }
331
    }
332
  
333
///////////////////////////////////////////////////////////////////////////////////////////////////
334
/**
335
 * Adds a new child to the last position in the list of our Node's children.
336
 * 
337
 * @param node The new Node to add.
338
 */
339 421c2728 Leszek Koltunski
  public synchronized void attach(DistortedTree node)
340 6a06a912 Leszek Koltunski
    {
341
    ArrayList<Long> prev = generateIDList(); 
342
   
343 9361b337 Leszek Koltunski
    if( mChildren==null ) mChildren = new ArrayList<>(2);
344 6a06a912 Leszek Koltunski
     
345
    node.mParent = this;
346
    mChildren.add(node);
347
    mNumChildren[0]++;
348
     
349
    RecomputeNodeID(prev);
350
    }
351
   
352
///////////////////////////////////////////////////////////////////////////////////////////////////
353
/**
354
 * Adds a new child to the last position in the list of our Node's children.
355
 * 
356 4e2382f3 Leszek Koltunski
 * @param texture DistortedTexture to initialize our child Node with.
357 07d8ef09 Leszek Koltunski
 * @param effects DistortedEffects to initialize our child Node with.
358 05403bba Leszek Koltunski
 * @param mesh MeshObject to initialize our child Node with.
359 6a06a912 Leszek Koltunski
 * @return the newly constructed child Node, or null if we couldn't allocate resources.
360
 */
361 05403bba Leszek Koltunski
  public synchronized DistortedTree attach(DistortedTexture texture, DistortedEffects effects, MeshObject mesh)
362 6a06a912 Leszek Koltunski
    {
363
    ArrayList<Long> prev = generateIDList(); 
364
      
365 9361b337 Leszek Koltunski
    if( mChildren==null ) mChildren = new ArrayList<>(2);
366 05403bba Leszek Koltunski
    DistortedTree node = new DistortedTree(texture,effects,mesh);
367 6a06a912 Leszek Koltunski
    node.mParent = this;
368
    mChildren.add(node);
369
    mNumChildren[0]++;
370
   
371
    RecomputeNodeID(prev);
372 fee0865c Leszek Koltunski
373 6a06a912 Leszek Koltunski
    return node;
374
    }
375
  
376
///////////////////////////////////////////////////////////////////////////////////////////////////
377
/**
378
 * Removes the first occurrence of a specified child from the list of children of our Node.
379
 * 
380
 * @param node The Node to remove.
381
 * @return <code>true</code> if the child was successfully removed.
382
 */
383 421c2728 Leszek Koltunski
  public synchronized boolean detach(DistortedTree node)
384 6a06a912 Leszek Koltunski
    {
385
    if( mNumChildren[0]>0 )
386
      {
387
      ArrayList<Long> prev = generateIDList();  
388
         
389
      if( mChildren.remove(node) )
390
        {
391
        node.mParent = null;  
392
        mNumChildren[0]--;
393
     
394
        RecomputeNodeID(prev);
395
     
396
        return true;
397
        }
398
      }
399
   
400
    return false;
401
    }
402
  
403
///////////////////////////////////////////////////////////////////////////////////////////////////
404
/**
405
 * Removes the first occurrence of a specified child from the list of children of our Node.
406
 * 
407 07d8ef09 Leszek Koltunski
 * @param effects DistortedEffects to remove.
408 6a06a912 Leszek Koltunski
 * @return <code>true</code> if the child was successfully removed.
409
 */
410 07d8ef09 Leszek Koltunski
  public synchronized boolean detach(DistortedEffects effects)
411 6a06a912 Leszek Koltunski
    {
412 07d8ef09 Leszek Koltunski
    long id = effects.getID();
413 421c2728 Leszek Koltunski
    DistortedTree node;
414 6a06a912 Leszek Koltunski
   
415
    for(int i=0; i<mNumChildren[0]; i++)
416
      {
417
      node = mChildren.get(i);
418
     
419 07d8ef09 Leszek Koltunski
      if( node.mEffects.getID()==id )
420 6a06a912 Leszek Koltunski
        {
421
        ArrayList<Long> prev = generateIDList();   
422
     
423
        node.mParent = null;  
424
        mChildren.remove(i);
425
        mNumChildren[0]--;
426
      
427
        RecomputeNodeID(prev);
428
      
429
        return true;
430
        }
431
      }
432
   
433
    return false;
434
    }
435
    
436
///////////////////////////////////////////////////////////////////////////////////////////////////
437
/**
438
 * Removes all children Nodes.
439
 */
440
  public synchronized void detachAll()
441
    {
442
    for(int i=0; i<mNumChildren[0]; i++)
443
      {
444
      mChildren.get(i).mParent = null;
445
      }
446
   
447
    if( mNumChildren[0]>0 )
448
      {
449
      ArrayList<Long> prev = generateIDList();  
450
      
451
      mNumChildren[0] = 0;
452
      mChildren.clear();
453
      RecomputeNodeID(prev);
454
      }
455
    }
456 d1e740c5 Leszek Koltunski
457 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
458
/**
459 421c2728 Leszek Koltunski
 * Returns the DistortedEffects object that's in the Node.
460 6a06a912 Leszek Koltunski
 * 
461 421c2728 Leszek Koltunski
 * @return The DistortedEffects contained in the Node.
462 6a06a912 Leszek Koltunski
 */
463 421c2728 Leszek Koltunski
  public DistortedEffects getEffects()
464 6a06a912 Leszek Koltunski
    {
465 07d8ef09 Leszek Koltunski
    return mEffects;
466 4e2382f3 Leszek Koltunski
    }
467
468
///////////////////////////////////////////////////////////////////////////////////////////////////
469
/**
470
 * Returns the DistortedTexture object that's in the Node.
471
 *
472
 * @return The DistortedTexture contained in the Node.
473
 */
474
  public DistortedTexture getTexture()
475
    {
476
    return mTexture;
477 6a06a912 Leszek Koltunski
    }
478
479 8c327653 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
480
/**
481
 * Returns the DistortedFramebuffer object that's in the Node.
482
 *
483
 * @return The DistortedFramebuffer contained in the Node.
484
 */
485
  public DistortedFramebuffer getFramebuffer()
486
    {
487
    return mData.mFBO;
488
    }
489 6a06a912 Leszek Koltunski
490 8c327653 Leszek Koltunski
  }