Project

General

Profile

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

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

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