Project

General

Profile

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

library / src / main / java / org / distorted / library / DistortedNode.java @ f8377ef8

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 194ab46f Leszek Koltunski
import android.opengl.GLES30;
26 6a06a912 Leszek Koltunski
27
///////////////////////////////////////////////////////////////////////////////////////////////////
28
/**
29 a09ada4c Leszek Koltunski
 * Class which represents a Node in a Tree of (InputSurface,Mesh,Effects) triplets.
30 6a06a912 Leszek Koltunski
 *  
31 a09ada4c Leszek Koltunski
 * Having organized such sets into a Tree, we can then render any Node to any OutputSurface.
32 7b8086eb Leszek Koltunski
 * That recursively renders the set held in the Node and all its children.
33 6a06a912 Leszek Koltunski
 */
34 a09ada4c Leszek Koltunski
public class DistortedNode
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 c5369f1b leszek
  private DistortedInputSurface mSurface;
42 6a06a912 Leszek Koltunski
  private NodeData mData;
43 bd3da5b2 Leszek Koltunski
44 a09ada4c Leszek Koltunski
  private DistortedNode mParent;
45
  private ArrayList<DistortedNode> 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 f8377ef8 leszek
62
      android.util.Log.e("DistortedNode", "new NodeData");
63 6a06a912 Leszek Koltunski
      }
64 bd3da5b2 Leszek Koltunski
    }
65 6a06a912 Leszek Koltunski
 
66 436899f2 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
67
68 7b8086eb Leszek Koltunski
  static synchronized void onDestroy()
69 436899f2 Leszek Koltunski
    {
70
    mNextNodeID = 0;
71
    mMapNodeID.clear();
72
    }
73
74 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
75
// tree isomorphism
76
  
77
  private void RecomputeNodeID(ArrayList<Long> prev)
78
    {
79
    ArrayList<Long> curr = generateIDList();
80
     
81
    if( mParent==null )
82
      {
83
      adjustNodeData(prev,curr);
84
      }
85
    else
86
      {
87
      ArrayList<Long> parentPrev = mParent.generateIDList();
88
      adjustNodeData(prev,curr);
89
      mParent.RecomputeNodeID(parentPrev);
90
      }
91
    }
92
93
///////////////////////////////////////////////////////////////////////////////////////////////////
94
95
  private ArrayList<Long> generateIDList()
96
    {
97 9361b337 Leszek Koltunski
    ArrayList<Long> ret = new ArrayList<>();
98 6a06a912 Leszek Koltunski
     
99 c5369f1b leszek
    ret.add( mSurface.getID() );
100 a09ada4c Leszek Koltunski
    DistortedNode node;
101 6a06a912 Leszek Koltunski
   
102
    for(int i=0; i<mNumChildren[0]; i++)
103
      {
104
      node = mChildren.get(i);
105
      ret.add(node.mData.ID);
106
      }
107
   
108
    return ret;
109
    }
110
111
///////////////////////////////////////////////////////////////////////////////////////////////////
112
113
  private void adjustNodeData(ArrayList<Long> oldList, ArrayList<Long> newList)
114
    {
115 fee0865c Leszek Koltunski
    boolean otherNodesPoint = (mData.numPointingNodes>1);
116
117
    if( otherNodesPoint ) mData.numPointingNodes--;
118
    else                  mMapNodeID.remove(oldList);
119 1942537e Leszek Koltunski
120 6a06a912 Leszek Koltunski
    NodeData newData = mMapNodeID.get(newList);
121
    
122
    if( newData==null )
123
      {
124 fee0865c Leszek Koltunski
      if( otherNodesPoint )  mData = new NodeData(++mNextNodeID);
125
      else                   mData.ID = ++mNextNodeID;  // numPointingNodes must be 1 already
126
127 16d8b8f3 Leszek Koltunski
      if( newList.size()>1 )
128
        {
129 8c327653 Leszek Koltunski
        if( mData.mFBO ==null )
130 f8377ef8 leszek
          {
131
          android.util.Log.e("DistortedNode", "creating a new FBO");
132
133 c5369f1b leszek
          mData.mFBO = new DistortedFramebuffer(mSurface.getWidth(), mSurface.getHeight());
134 f8377ef8 leszek
          }
135 16d8b8f3 Leszek Koltunski
        }
136
      else
137
        {
138 8c327653 Leszek Koltunski
        if( mData.mFBO !=null )
139 16d8b8f3 Leszek Koltunski
          {
140 f8377ef8 leszek
          android.util.Log.e("DistortedNode", "marking FBO for deletion and setting it to NULL");
141
142 8c327653 Leszek Koltunski
          mData.mFBO.markForDeletion();
143
          mData.mFBO = null;
144 16d8b8f3 Leszek Koltunski
          }
145
        else
146
          {
147 a09ada4c Leszek Koltunski
          android.util.Log.e("DistortedNode", "adjustNodeData: impossible situation??");
148 16d8b8f3 Leszek Koltunski
          }
149
        }
150 bd3da5b2 Leszek Koltunski
151 6a06a912 Leszek Koltunski
      mMapNodeID.put(newList, mData);
152
      }
153
    else
154 fee0865c Leszek Koltunski
      {
155 6a06a912 Leszek Koltunski
      newData.numPointingNodes++;
156
      mData = newData;
157
      }
158
    }
159
160
///////////////////////////////////////////////////////////////////////////////////////////////////  
161
// this will be called on startup and every time OpenGL context has been lost
162 d620ff06 Leszek Koltunski
163 6a06a912 Leszek Koltunski
  static void reset()
164
    {
165
    NodeData tmp;   
166
     
167
    for(ArrayList<Long> key: mMapNodeID.keySet())
168
      {
169
      tmp = mMapNodeID.get(key);
170
          
171 02de77c9 Leszek Koltunski
      if( tmp.mFBO != null ) tmp.numRendered = 0;
172 6a06a912 Leszek Koltunski
      }
173
    }
174 fee0865c Leszek Koltunski
175
///////////////////////////////////////////////////////////////////////////////////////////////////
176
// Debug - print all the Node IDs
177 ab12f06b Leszek Koltunski
/*
178 fee0865c Leszek Koltunski
  void debug(int depth)
179
    {
180
    String tmp="";
181
    int i;
182
183
    for(i=0; i<depth; i++) tmp +="   ";
184 1942537e Leszek Koltunski
    tmp += (mData.ID+" (nodes: "+mData.numPointingNodes+")");
185 fee0865c Leszek Koltunski
186 1942537e Leszek Koltunski
    android.util.Log.e("NODE", tmp);
187 fee0865c Leszek Koltunski
188
    for(i=0; i<mNumChildren[0]; i++)
189
      mChildren.get(i).debug(depth+1);
190
    }
191
192
///////////////////////////////////////////////////////////////////////////////////////////////////
193
// Debug - print contents of the HashMap
194
195
  static void debugMap()
196
    {
197
    NodeData tmp;
198
199
    for(ArrayList<Long> key: mMapNodeID.keySet())
200
      {
201
      tmp = mMapNodeID.get(key);
202
203
      android.util.Log.e("NODE", "key="+key+" NodeID: "+tmp.ID);
204
      }
205
    }
206 ab12f06b Leszek Koltunski
*/
207 a0f644b7 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
208
209 c5369f1b leszek
  void drawRecursive(long currTime, DistortedOutputSurface surface)
210 a0f644b7 Leszek Koltunski
    {
211 c5369f1b leszek
    float halfX = mSurface.getWidth()/2.0f;
212
    float halfY = mSurface.getHeight()/2.0f;
213 a0f644b7 Leszek Koltunski
214
    if( mNumChildren[0]<=0 )
215
      {
216 c5369f1b leszek
      mSurface.setAsInput();
217 a0f644b7 Leszek Koltunski
      }
218
    else
219
      {
220
      if( mData.numRendered==0 )
221
        {
222 8c327653 Leszek Koltunski
        mData.mFBO.setAsOutput();
223 a0f644b7 Leszek Koltunski
224 194ab46f Leszek Koltunski
        GLES30.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
225
        GLES30.glClear( GLES30.GL_DEPTH_BUFFER_BIT | GLES30.GL_COLOR_BUFFER_BIT);
226 a0f644b7 Leszek Koltunski
227 c5369f1b leszek
        if( mSurface.setAsInput() )
228 af4cc5db Leszek Koltunski
          DistortedEffects.drawNoEffectsPriv(halfX, halfY, mMesh, mData.mFBO );
229 a0f644b7 Leszek Koltunski
230 a09ada4c Leszek Koltunski
        for(int i=0; i<mNumChildren[0]; i++)
231 a0f644b7 Leszek Koltunski
          {
232 a09ada4c Leszek Koltunski
          mChildren.get(i).drawRecursive(currTime, mData.mFBO);
233 a0f644b7 Leszek Koltunski
          }
234
        }
235
236
      mData.numRendered++;
237
      mData.numRendered %= mData.numPointingNodes;
238 8c327653 Leszek Koltunski
      mData.mFBO.setAsInput();
239 a0f644b7 Leszek Koltunski
      }
240
241 c5369f1b leszek
    mEffects.drawPriv(halfX, halfY, mMesh, surface, currTime);
242 a0f644b7 Leszek Koltunski
    }
243
244 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
245
// PUBLIC API
246
///////////////////////////////////////////////////////////////////////////////////////////////////
247
/**
248 a09ada4c Leszek Koltunski
 * Constructs new Node.
249 6a06a912 Leszek Koltunski
 *     
250 c5369f1b leszek
 * @param surface InputSurface to put into the new Node.
251 07d8ef09 Leszek Koltunski
 * @param effects DistortedEffects to put into the new Node.
252 05403bba Leszek Koltunski
 * @param mesh MeshObject to put into the new Node.
253 6a06a912 Leszek Koltunski
 */
254 a09ada4c Leszek Koltunski
  public DistortedNode(DistortedInputSurface surface, DistortedEffects effects, MeshObject mesh)
255 6a06a912 Leszek Koltunski
    {
256 c5369f1b leszek
    mSurface       = surface;
257 8ca9f899 Leszek Koltunski
    mEffects       = effects;
258
    mMesh          = mesh;
259
    mParent        = null;
260
    mChildren      = null;
261
    mNumChildren   = new int[1];
262
    mNumChildren[0]= 0;
263 6a06a912 Leszek Koltunski
   
264 9361b337 Leszek Koltunski
    ArrayList<Long> list = new ArrayList<>();
265 c5369f1b leszek
    list.add(mSurface.getID());
266 1942537e Leszek Koltunski
267 6a06a912 Leszek Koltunski
    mData = mMapNodeID.get(list);
268
   
269
    if( mData!=null )
270
      {
271
      mData.numPointingNodes++;
272
      }
273
    else
274
      {
275
      mData = new NodeData(++mNextNodeID);   
276 1942537e Leszek Koltunski
      mMapNodeID.put(list, mData);
277 6a06a912 Leszek Koltunski
      }
278
    }
279
280
///////////////////////////////////////////////////////////////////////////////////////////////////  
281
/**
282 a09ada4c Leszek Koltunski
 * Copy-constructs new Node from another Node.
283 6a06a912 Leszek Koltunski
 *     
284 a09ada4c Leszek Koltunski
 * @param node The DistortedNode to copy data from.
285 6a06a912 Leszek Koltunski
 * @param flags bit field composed of a subset of the following:
286 29a06526 Leszek Koltunski
 *        {@link Distorted#CLONE_SURFACE},  {@link Distorted#CLONE_MATRIX}, {@link Distorted#CLONE_VERTEX},
287 6a06a912 Leszek Koltunski
 *        {@link Distorted#CLONE_FRAGMENT} and {@link Distorted#CLONE_CHILDREN}.
288 29a06526 Leszek Koltunski
 *        For example flags = CLONE_SURFACE | CLONE_CHILDREN.
289 6a06a912 Leszek Koltunski
 */
290 a09ada4c Leszek Koltunski
  public DistortedNode(DistortedNode node, int flags)
291 6a06a912 Leszek Koltunski
    {
292 9361b337 Leszek Koltunski
    mParent = null;
293 432442f9 Leszek Koltunski
    mEffects= new DistortedEffects(node.mEffects,flags);
294 05403bba Leszek Koltunski
    mMesh = node.mMesh;
295 9361b337 Leszek Koltunski
296 29a06526 Leszek Koltunski
    if( (flags & Distorted.CLONE_SURFACE) != 0 )
297 e7a20702 Leszek Koltunski
      {
298 c5369f1b leszek
      mSurface = node.mSurface;
299 e7a20702 Leszek Koltunski
      }
300
    else
301
      {
302 c5369f1b leszek
      int w = node.mSurface.getWidth();
303
      int h = node.mSurface.getHeight();
304 8ca9f899 Leszek Koltunski
305 c5369f1b leszek
      if( node.mSurface instanceof DistortedTexture )
306 8ca9f899 Leszek Koltunski
        {
307 c5369f1b leszek
        mSurface = new DistortedTexture(w,h);
308 8ca9f899 Leszek Koltunski
        }
309 c5369f1b leszek
      else if( node.mSurface instanceof DistortedFramebuffer )
310 8ca9f899 Leszek Koltunski
        {
311 c5369f1b leszek
        boolean hasDepth = ((DistortedFramebuffer) node.mSurface).hasDepth();
312
        mSurface = new DistortedFramebuffer(w,h,hasDepth);
313 8ca9f899 Leszek Koltunski
        }
314 e7a20702 Leszek Koltunski
      }
315 9361b337 Leszek Koltunski
    if( (flags & Distorted.CLONE_CHILDREN) != 0 )
316 6a06a912 Leszek Koltunski
      {
317
      mChildren = node.mChildren;
318
      mNumChildren = node.mNumChildren;
319
      }
320
    else
321
      {
322
      mChildren = null;
323
      mNumChildren = new int[1];
324
      mNumChildren[0] = 0;
325
      }
326
   
327
    ArrayList<Long> list = generateIDList();
328
   
329
    mData = mMapNodeID.get(list);
330
   
331
    if( mData!=null )
332
      {
333
      mData.numPointingNodes++;
334
      }
335
    else
336
      {
337
      mData = new NodeData(++mNextNodeID);   
338
      mMapNodeID.put(list, mData);
339
      }
340
    }
341
  
342
///////////////////////////////////////////////////////////////////////////////////////////////////
343
/**
344
 * Adds a new child to the last position in the list of our Node's children.
345
 * 
346
 * @param node The new Node to add.
347
 */
348 a09ada4c Leszek Koltunski
  public synchronized void attach(DistortedNode node)
349 6a06a912 Leszek Koltunski
    {
350
    ArrayList<Long> prev = generateIDList(); 
351
   
352 9361b337 Leszek Koltunski
    if( mChildren==null ) mChildren = new ArrayList<>(2);
353 f8377ef8 leszek
354
    android.util.Log.e("DistortedNode", "ATTACH1");
355
356
357 6a06a912 Leszek Koltunski
    node.mParent = this;
358
    mChildren.add(node);
359
    mNumChildren[0]++;
360
     
361
    RecomputeNodeID(prev);
362
    }
363
   
364
///////////////////////////////////////////////////////////////////////////////////////////////////
365
/**
366
 * Adds a new child to the last position in the list of our Node's children.
367
 * 
368 c5369f1b leszek
 * @param surface InputSurface to initialize our child Node with.
369 07d8ef09 Leszek Koltunski
 * @param effects DistortedEffects to initialize our child Node with.
370 05403bba Leszek Koltunski
 * @param mesh MeshObject to initialize our child Node with.
371 6a06a912 Leszek Koltunski
 * @return the newly constructed child Node, or null if we couldn't allocate resources.
372
 */
373 a09ada4c Leszek Koltunski
  public synchronized DistortedNode attach(DistortedInputSurface surface, DistortedEffects effects, MeshObject mesh)
374 6a06a912 Leszek Koltunski
    {
375
    ArrayList<Long> prev = generateIDList(); 
376 f8377ef8 leszek
377
    android.util.Log.e("DistortedNode", "ATTACH2");
378
379 9361b337 Leszek Koltunski
    if( mChildren==null ) mChildren = new ArrayList<>(2);
380 a09ada4c Leszek Koltunski
    DistortedNode node = new DistortedNode(surface,effects,mesh);
381 6a06a912 Leszek Koltunski
    node.mParent = this;
382
    mChildren.add(node);
383
    mNumChildren[0]++;
384
   
385
    RecomputeNodeID(prev);
386 fee0865c Leszek Koltunski
387 6a06a912 Leszek Koltunski
    return node;
388
    }
389
  
390
///////////////////////////////////////////////////////////////////////////////////////////////////
391
/**
392
 * Removes the first occurrence of a specified child from the list of children of our Node.
393
 * 
394
 * @param node The Node to remove.
395
 * @return <code>true</code> if the child was successfully removed.
396
 */
397 a09ada4c Leszek Koltunski
  public synchronized boolean detach(DistortedNode node)
398 6a06a912 Leszek Koltunski
    {
399
    if( mNumChildren[0]>0 )
400
      {
401
      ArrayList<Long> prev = generateIDList();  
402
         
403
      if( mChildren.remove(node) )
404
        {
405 f8377ef8 leszek
android.util.Log.e("DistortedNode", "DETACH1");
406
407
        node.mParent = null;
408 6a06a912 Leszek Koltunski
        mNumChildren[0]--;
409
     
410
        RecomputeNodeID(prev);
411
     
412
        return true;
413
        }
414
      }
415
   
416
    return false;
417
    }
418 a09ada4c Leszek Koltunski
419 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
420
/**
421
 * Removes the first occurrence of a specified child from the list of children of our Node.
422 a09ada4c Leszek Koltunski
 * <p>
423
 * A bit questionable method as there can be many different Nodes attached as children, some
424
 * of them having the same Effects but - for instance - different Mesh. Use with care.
425
 *
426 07d8ef09 Leszek Koltunski
 * @param effects DistortedEffects to remove.
427 6a06a912 Leszek Koltunski
 * @return <code>true</code> if the child was successfully removed.
428
 */
429 07d8ef09 Leszek Koltunski
  public synchronized boolean detach(DistortedEffects effects)
430 6a06a912 Leszek Koltunski
    {
431 07d8ef09 Leszek Koltunski
    long id = effects.getID();
432 a09ada4c Leszek Koltunski
    DistortedNode node;
433
434 6a06a912 Leszek Koltunski
    for(int i=0; i<mNumChildren[0]; i++)
435
      {
436
      node = mChildren.get(i);
437 a09ada4c Leszek Koltunski
438 07d8ef09 Leszek Koltunski
      if( node.mEffects.getID()==id )
439 6a06a912 Leszek Koltunski
        {
440 f8377ef8 leszek
android.util.Log.e("DistortedNode", "DETACH2");
441
442
443 a09ada4c Leszek Koltunski
        ArrayList<Long> prev = generateIDList();
444
445
        node.mParent = null;
446 6a06a912 Leszek Koltunski
        mChildren.remove(i);
447
        mNumChildren[0]--;
448 a09ada4c Leszek Koltunski
449 6a06a912 Leszek Koltunski
        RecomputeNodeID(prev);
450 a09ada4c Leszek Koltunski
451 6a06a912 Leszek Koltunski
        return true;
452
        }
453
      }
454 a09ada4c Leszek Koltunski
455 6a06a912 Leszek Koltunski
    return false;
456
    }
457 a09ada4c Leszek Koltunski
458 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
459
/**
460
 * Removes all children Nodes.
461
 */
462
  public synchronized void detachAll()
463
    {
464
    for(int i=0; i<mNumChildren[0]; i++)
465
      {
466
      mChildren.get(i).mParent = null;
467
      }
468
   
469
    if( mNumChildren[0]>0 )
470
      {
471
      ArrayList<Long> prev = generateIDList();  
472
      
473
      mNumChildren[0] = 0;
474
      mChildren.clear();
475
      RecomputeNodeID(prev);
476
      }
477
    }
478 d1e740c5 Leszek Koltunski
479 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
480
/**
481 421c2728 Leszek Koltunski
 * Returns the DistortedEffects object that's in the Node.
482 6a06a912 Leszek Koltunski
 * 
483 421c2728 Leszek Koltunski
 * @return The DistortedEffects contained in the Node.
484 6a06a912 Leszek Koltunski
 */
485 421c2728 Leszek Koltunski
  public DistortedEffects getEffects()
486 6a06a912 Leszek Koltunski
    {
487 07d8ef09 Leszek Koltunski
    return mEffects;
488 4e2382f3 Leszek Koltunski
    }
489
490
///////////////////////////////////////////////////////////////////////////////////////////////////
491
/**
492 c5369f1b leszek
 * Returns the DistortedInputSurface object that's in the Node.
493 4e2382f3 Leszek Koltunski
 *
494 c5369f1b leszek
 * @return The DistortedInputSurface contained in the Node.
495 4e2382f3 Leszek Koltunski
 */
496 c5369f1b leszek
  public DistortedInputSurface getSurface()
497 4e2382f3 Leszek Koltunski
    {
498 c5369f1b leszek
    return mSurface;
499 6a06a912 Leszek Koltunski
    }
500
501 8c327653 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
502
/**
503
 * Returns the DistortedFramebuffer object that's in the Node.
504
 *
505
 * @return The DistortedFramebuffer contained in the Node.
506
 */
507
  public DistortedFramebuffer getFramebuffer()
508
    {
509
    return mData.mFBO;
510
    }
511 6a06a912 Leszek Koltunski
512 8c327653 Leszek Koltunski
  }