Project

General

Profile

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

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

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 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 c5369f1b leszek
    ret.add( mSurface.getID() );
98 a09ada4c Leszek Koltunski
    DistortedNode 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 c5369f1b leszek
          mData.mFBO = new DistortedFramebuffer(mSurface.getWidth(), mSurface.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 a09ada4c Leszek Koltunski
          android.util.Log.e("DistortedNode", "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 02de77c9 Leszek Koltunski
      if( tmp.mFBO != null ) tmp.numRendered = 0;
164 6a06a912 Leszek Koltunski
      }
165
    }
166 fee0865c Leszek Koltunski
167
///////////////////////////////////////////////////////////////////////////////////////////////////
168
// Debug - print all the Node IDs
169 ab12f06b Leszek Koltunski
/*
170 fee0865c Leszek Koltunski
  void debug(int depth)
171
    {
172
    String tmp="";
173
    int i;
174
175
    for(i=0; i<depth; i++) tmp +="   ";
176 1942537e Leszek Koltunski
    tmp += (mData.ID+" (nodes: "+mData.numPointingNodes+")");
177 fee0865c Leszek Koltunski
178 1942537e Leszek Koltunski
    android.util.Log.e("NODE", tmp);
179 fee0865c Leszek Koltunski
180
    for(i=0; i<mNumChildren[0]; i++)
181
      mChildren.get(i).debug(depth+1);
182
    }
183
184
///////////////////////////////////////////////////////////////////////////////////////////////////
185
// Debug - print contents of the HashMap
186
187
  static void debugMap()
188
    {
189
    NodeData tmp;
190
191
    for(ArrayList<Long> key: mMapNodeID.keySet())
192
      {
193
      tmp = mMapNodeID.get(key);
194
195
      android.util.Log.e("NODE", "key="+key+" NodeID: "+tmp.ID);
196
      }
197
    }
198 ab12f06b Leszek Koltunski
*/
199 a0f644b7 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
200
201 c5369f1b leszek
  void drawRecursive(long currTime, DistortedOutputSurface surface)
202 a0f644b7 Leszek Koltunski
    {
203 c5369f1b leszek
    mSurface.create();
204
    float halfX = mSurface.getWidth()/2.0f;
205
    float halfY = mSurface.getHeight()/2.0f;
206 a0f644b7 Leszek Koltunski
207
    if( mNumChildren[0]<=0 )
208
      {
209 c5369f1b leszek
      mSurface.setAsInput();
210 a0f644b7 Leszek Koltunski
      }
211
    else
212
      {
213 133cbb2b Leszek Koltunski
      mData.mFBO.create();
214 a0f644b7 Leszek Koltunski
215
      if( mData.numRendered==0 )
216
        {
217 8c327653 Leszek Koltunski
        mData.mFBO.setAsOutput();
218 a0f644b7 Leszek Koltunski
219 194ab46f Leszek Koltunski
        GLES30.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
220
        GLES30.glClear( GLES30.GL_DEPTH_BUFFER_BIT | GLES30.GL_COLOR_BUFFER_BIT);
221 a0f644b7 Leszek Koltunski
222 c5369f1b leszek
        if( mSurface.setAsInput() )
223 af4cc5db Leszek Koltunski
          DistortedEffects.drawNoEffectsPriv(halfX, halfY, mMesh, mData.mFBO );
224 a0f644b7 Leszek Koltunski
225 a09ada4c Leszek Koltunski
        for(int i=0; i<mNumChildren[0]; i++)
226 a0f644b7 Leszek Koltunski
          {
227 a09ada4c Leszek Koltunski
          mChildren.get(i).drawRecursive(currTime, mData.mFBO);
228 a0f644b7 Leszek Koltunski
          }
229
        }
230
231
      mData.numRendered++;
232
      mData.numRendered %= mData.numPointingNodes;
233 8c327653 Leszek Koltunski
      mData.mFBO.setAsInput();
234 a0f644b7 Leszek Koltunski
      }
235
236 c5369f1b leszek
    mEffects.drawPriv(halfX, halfY, mMesh, surface, currTime);
237 a0f644b7 Leszek Koltunski
    }
238
239 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
240
// PUBLIC API
241
///////////////////////////////////////////////////////////////////////////////////////////////////
242
/**
243 a09ada4c Leszek Koltunski
 * Constructs new Node.
244 6a06a912 Leszek Koltunski
 *     
245 c5369f1b leszek
 * @param surface InputSurface to put into the new Node.
246 07d8ef09 Leszek Koltunski
 * @param effects DistortedEffects to put into the new Node.
247 05403bba Leszek Koltunski
 * @param mesh MeshObject to put into the new Node.
248 6a06a912 Leszek Koltunski
 */
249 a09ada4c Leszek Koltunski
  public DistortedNode(DistortedInputSurface surface, DistortedEffects effects, MeshObject mesh)
250 6a06a912 Leszek Koltunski
    {
251 c5369f1b leszek
    mSurface       = surface;
252 8ca9f899 Leszek Koltunski
    mEffects       = effects;
253
    mMesh          = mesh;
254
    mParent        = null;
255
    mChildren      = null;
256
    mNumChildren   = new int[1];
257
    mNumChildren[0]= 0;
258 6a06a912 Leszek Koltunski
   
259 9361b337 Leszek Koltunski
    ArrayList<Long> list = new ArrayList<>();
260 c5369f1b leszek
    list.add(mSurface.getID());
261 1942537e Leszek Koltunski
262 6a06a912 Leszek Koltunski
    mData = mMapNodeID.get(list);
263
   
264
    if( mData!=null )
265
      {
266
      mData.numPointingNodes++;
267
      }
268
    else
269
      {
270
      mData = new NodeData(++mNextNodeID);   
271 1942537e Leszek Koltunski
      mMapNodeID.put(list, mData);
272 6a06a912 Leszek Koltunski
      }
273
    }
274
275
///////////////////////////////////////////////////////////////////////////////////////////////////  
276
/**
277 a09ada4c Leszek Koltunski
 * Copy-constructs new Node from another Node.
278 6a06a912 Leszek Koltunski
 *     
279 a09ada4c Leszek Koltunski
 * @param node The DistortedNode to copy data from.
280 6a06a912 Leszek Koltunski
 * @param flags bit field composed of a subset of the following:
281 29a06526 Leszek Koltunski
 *        {@link Distorted#CLONE_SURFACE},  {@link Distorted#CLONE_MATRIX}, {@link Distorted#CLONE_VERTEX},
282 6a06a912 Leszek Koltunski
 *        {@link Distorted#CLONE_FRAGMENT} and {@link Distorted#CLONE_CHILDREN}.
283 29a06526 Leszek Koltunski
 *        For example flags = CLONE_SURFACE | CLONE_CHILDREN.
284 6a06a912 Leszek Koltunski
 */
285 a09ada4c Leszek Koltunski
  public DistortedNode(DistortedNode node, int flags)
286 6a06a912 Leszek Koltunski
    {
287 9361b337 Leszek Koltunski
    mParent = null;
288 432442f9 Leszek Koltunski
    mEffects= new DistortedEffects(node.mEffects,flags);
289 05403bba Leszek Koltunski
    mMesh = node.mMesh;
290 9361b337 Leszek Koltunski
291 29a06526 Leszek Koltunski
    if( (flags & Distorted.CLONE_SURFACE) != 0 )
292 e7a20702 Leszek Koltunski
      {
293 c5369f1b leszek
      mSurface = node.mSurface;
294 e7a20702 Leszek Koltunski
      }
295
    else
296
      {
297 c5369f1b leszek
      int w = node.mSurface.getWidth();
298
      int h = node.mSurface.getHeight();
299 8ca9f899 Leszek Koltunski
300 c5369f1b leszek
      if( node.mSurface instanceof DistortedTexture )
301 8ca9f899 Leszek Koltunski
        {
302 c5369f1b leszek
        mSurface = new DistortedTexture(w,h);
303 8ca9f899 Leszek Koltunski
        }
304 c5369f1b leszek
      else if( node.mSurface instanceof DistortedFramebuffer )
305 8ca9f899 Leszek Koltunski
        {
306 c5369f1b leszek
        boolean hasDepth = ((DistortedFramebuffer) node.mSurface).hasDepth();
307
        mSurface = new DistortedFramebuffer(w,h,hasDepth);
308 8ca9f899 Leszek Koltunski
        }
309 e7a20702 Leszek Koltunski
      }
310 9361b337 Leszek Koltunski
    if( (flags & Distorted.CLONE_CHILDREN) != 0 )
311 6a06a912 Leszek Koltunski
      {
312
      mChildren = node.mChildren;
313
      mNumChildren = node.mNumChildren;
314
      }
315
    else
316
      {
317
      mChildren = null;
318
      mNumChildren = new int[1];
319
      mNumChildren[0] = 0;
320
      }
321
   
322
    ArrayList<Long> list = generateIDList();
323
   
324
    mData = mMapNodeID.get(list);
325
   
326
    if( mData!=null )
327
      {
328
      mData.numPointingNodes++;
329
      }
330
    else
331
      {
332
      mData = new NodeData(++mNextNodeID);   
333
      mMapNodeID.put(list, mData);
334
      }
335
    }
336
  
337
///////////////////////////////////////////////////////////////////////////////////////////////////
338
/**
339
 * Adds a new child to the last position in the list of our Node's children.
340
 * 
341
 * @param node The new Node to add.
342
 */
343 a09ada4c Leszek Koltunski
  public synchronized void attach(DistortedNode node)
344 6a06a912 Leszek Koltunski
    {
345
    ArrayList<Long> prev = generateIDList(); 
346
   
347 9361b337 Leszek Koltunski
    if( mChildren==null ) mChildren = new ArrayList<>(2);
348 6a06a912 Leszek Koltunski
     
349
    node.mParent = this;
350
    mChildren.add(node);
351
    mNumChildren[0]++;
352
     
353
    RecomputeNodeID(prev);
354
    }
355
   
356
///////////////////////////////////////////////////////////////////////////////////////////////////
357
/**
358
 * Adds a new child to the last position in the list of our Node's children.
359
 * 
360 c5369f1b leszek
 * @param surface InputSurface to initialize our child Node with.
361 07d8ef09 Leszek Koltunski
 * @param effects DistortedEffects to initialize our child Node with.
362 05403bba Leszek Koltunski
 * @param mesh MeshObject to initialize our child Node with.
363 6a06a912 Leszek Koltunski
 * @return the newly constructed child Node, or null if we couldn't allocate resources.
364
 */
365 a09ada4c Leszek Koltunski
  public synchronized DistortedNode attach(DistortedInputSurface surface, DistortedEffects effects, MeshObject mesh)
366 6a06a912 Leszek Koltunski
    {
367
    ArrayList<Long> prev = generateIDList(); 
368
      
369 9361b337 Leszek Koltunski
    if( mChildren==null ) mChildren = new ArrayList<>(2);
370 a09ada4c Leszek Koltunski
    DistortedNode node = new DistortedNode(surface,effects,mesh);
371 6a06a912 Leszek Koltunski
    node.mParent = this;
372
    mChildren.add(node);
373
    mNumChildren[0]++;
374
   
375
    RecomputeNodeID(prev);
376 fee0865c Leszek Koltunski
377 6a06a912 Leszek Koltunski
    return node;
378
    }
379
  
380
///////////////////////////////////////////////////////////////////////////////////////////////////
381
/**
382
 * Removes the first occurrence of a specified child from the list of children of our Node.
383
 * 
384
 * @param node The Node to remove.
385
 * @return <code>true</code> if the child was successfully removed.
386
 */
387 a09ada4c Leszek Koltunski
  public synchronized boolean detach(DistortedNode node)
388 6a06a912 Leszek Koltunski
    {
389
    if( mNumChildren[0]>0 )
390
      {
391
      ArrayList<Long> prev = generateIDList();  
392
         
393
      if( mChildren.remove(node) )
394
        {
395
        node.mParent = null;  
396
        mNumChildren[0]--;
397
     
398
        RecomputeNodeID(prev);
399
     
400
        return true;
401
        }
402
      }
403
   
404
    return false;
405
    }
406 a09ada4c Leszek Koltunski
407 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
408
/**
409
 * Removes the first occurrence of a specified child from the list of children of our Node.
410 a09ada4c Leszek Koltunski
 * <p>
411
 * A bit questionable method as there can be many different Nodes attached as children, some
412
 * of them having the same Effects but - for instance - different Mesh. Use with care.
413
 *
414 07d8ef09 Leszek Koltunski
 * @param effects DistortedEffects to remove.
415 6a06a912 Leszek Koltunski
 * @return <code>true</code> if the child was successfully removed.
416
 */
417 07d8ef09 Leszek Koltunski
  public synchronized boolean detach(DistortedEffects effects)
418 6a06a912 Leszek Koltunski
    {
419 07d8ef09 Leszek Koltunski
    long id = effects.getID();
420 a09ada4c Leszek Koltunski
    DistortedNode node;
421
422 6a06a912 Leszek Koltunski
    for(int i=0; i<mNumChildren[0]; i++)
423
      {
424
      node = mChildren.get(i);
425 a09ada4c Leszek Koltunski
426 07d8ef09 Leszek Koltunski
      if( node.mEffects.getID()==id )
427 6a06a912 Leszek Koltunski
        {
428 a09ada4c Leszek Koltunski
        ArrayList<Long> prev = generateIDList();
429
430
        node.mParent = null;
431 6a06a912 Leszek Koltunski
        mChildren.remove(i);
432
        mNumChildren[0]--;
433 a09ada4c Leszek Koltunski
434 6a06a912 Leszek Koltunski
        RecomputeNodeID(prev);
435 a09ada4c Leszek Koltunski
436 6a06a912 Leszek Koltunski
        return true;
437
        }
438
      }
439 a09ada4c Leszek Koltunski
440 6a06a912 Leszek Koltunski
    return false;
441
    }
442 a09ada4c Leszek Koltunski
443 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
444
/**
445
 * Removes all children Nodes.
446
 */
447
  public synchronized void detachAll()
448
    {
449
    for(int i=0; i<mNumChildren[0]; i++)
450
      {
451
      mChildren.get(i).mParent = null;
452
      }
453
   
454
    if( mNumChildren[0]>0 )
455
      {
456
      ArrayList<Long> prev = generateIDList();  
457
      
458
      mNumChildren[0] = 0;
459
      mChildren.clear();
460
      RecomputeNodeID(prev);
461
      }
462
    }
463 d1e740c5 Leszek Koltunski
464 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
465
/**
466 421c2728 Leszek Koltunski
 * Returns the DistortedEffects object that's in the Node.
467 6a06a912 Leszek Koltunski
 * 
468 421c2728 Leszek Koltunski
 * @return The DistortedEffects contained in the Node.
469 6a06a912 Leszek Koltunski
 */
470 421c2728 Leszek Koltunski
  public DistortedEffects getEffects()
471 6a06a912 Leszek Koltunski
    {
472 07d8ef09 Leszek Koltunski
    return mEffects;
473 4e2382f3 Leszek Koltunski
    }
474
475
///////////////////////////////////////////////////////////////////////////////////////////////////
476
/**
477 c5369f1b leszek
 * Returns the DistortedInputSurface object that's in the Node.
478 4e2382f3 Leszek Koltunski
 *
479 c5369f1b leszek
 * @return The DistortedInputSurface contained in the Node.
480 4e2382f3 Leszek Koltunski
 */
481 c5369f1b leszek
  public DistortedInputSurface getSurface()
482 4e2382f3 Leszek Koltunski
    {
483 c5369f1b leszek
    return mSurface;
484 6a06a912 Leszek Koltunski
    }
485
486 8c327653 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
487
/**
488
 * Returns the DistortedFramebuffer object that's in the Node.
489
 *
490
 * @return The DistortedFramebuffer contained in the Node.
491
 */
492
  public DistortedFramebuffer getFramebuffer()
493
    {
494
    return mData.mFBO;
495
    }
496 6a06a912 Leszek Koltunski
497 8c327653 Leszek Koltunski
  }