Project

General

Profile

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

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

1
///////////////////////////////////////////////////////////////////////////////////////////////////
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
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
 * Class which represents a Node in a Tree of DistortedObjects.
30
 *  
31
 * 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
 * each one of them has. 
34
 */
35
public class DistortedNode 
36
  {
37
  private static HashMap<ArrayList<Long>,NodeData> mMapNodeID = new HashMap<>();
38
  private static long mNextNodeID =0;
39

    
40
  private DistortedObject mObject;
41
  private NodeData mData;
42

    
43
  private DistortedNode mParent;
44
  private ArrayList<DistortedNode> mChildren;
45
  private int[] mNumChildren;  // ==mChildren.length(), but we only create mChildren if the first one gets added
46

    
47
  private class NodeData
48
    {
49
    long ID;
50
    int numPointingNodes;
51
    DistortedRenderTarget mDRT;
52
    boolean mRendered;
53

    
54
    NodeData(long id)
55
      {
56
      ID              = id;
57
      numPointingNodes= 1;
58
      mDRT            = null;
59
      mRendered       = false;
60
      }
61
    }
62
 
63
///////////////////////////////////////////////////////////////////////////////////////////////////
64

    
65
  static void release()
66
    {
67
    mNextNodeID = 0;
68
    mMapNodeID.clear();
69
    }
70

    
71
///////////////////////////////////////////////////////////////////////////////////////////////////
72

    
73
  private void markRecursive()
74
    {
75
    mData.mRendered = false;
76
   
77
    synchronized(this)
78
      {
79
      for(int i=0; i<mNumChildren[0]; i++) mChildren.get(i).markRecursive();
80
      }
81
    }
82
  
83
///////////////////////////////////////////////////////////////////////////////////////////////////
84
  
85
  private void drawRecursive(long currTime, DistortedRenderTarget drt)
86
    {
87
    if( mNumChildren[0]<=0 )
88
      {
89
      GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mObject.mTextureDataH[0]);
90
      }
91
    else
92
      {
93
      if( mData.mRendered==false )
94
        {
95
        mData.mRendered = true;
96
        mData.mDRT.setOutput();
97

    
98
        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
99
        GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
100
      
101
        if( mObject.mBitmapSet[0] )
102
          {
103
          GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mObject.mTextureDataH[0]);
104
          mObject.drawNoEffectsPriv(mData.mDRT);
105
          }
106
      
107
        synchronized(this)
108
          {
109
          for(int i=0; i<mNumChildren[0]; i++)
110
            {
111
            mChildren.get(i).drawRecursive(currTime, mData.mDRT);
112
            }
113
          }
114
        }
115

    
116
      drt.setOutput();
117
      mData.mDRT.setInput();   // this is safe because we must have called createFBO() above before.
118
      }
119
    
120
    mObject.drawPriv(currTime, drt);
121
    }
122
  
123
///////////////////////////////////////////////////////////////////////////////////////////////////
124
// tree isomorphism
125
  
126
  private void RecomputeNodeID(ArrayList<Long> prev)
127
    {
128
    ArrayList<Long> curr = generateIDList();
129
     
130
    if( mParent==null )
131
      {
132
      adjustNodeData(prev,curr);
133
      }
134
    else
135
      {
136
      ArrayList<Long> parentPrev = mParent.generateIDList();
137
      adjustNodeData(prev,curr);
138
      mParent.RecomputeNodeID(parentPrev);
139
      }
140
    }
141

    
142
///////////////////////////////////////////////////////////////////////////////////////////////////
143

    
144
  private ArrayList<Long> generateIDList()
145
    {
146
    ArrayList<Long> ret = new ArrayList<>();
147
     
148
    ret.add( mNumChildren[0]>0 ? mObject.getBitmapID() : mObject.getID() );
149
    DistortedNode node;
150
   
151
    for(int i=0; i<mNumChildren[0]; i++)
152
      {
153
      node = mChildren.get(i);
154
      ret.add(node.mData.ID);
155
      }
156
   
157
    return ret;
158
    }
159

    
160
///////////////////////////////////////////////////////////////////////////////////////////////////
161

    
162
  private void adjustNodeData(ArrayList<Long> oldList, ArrayList<Long> newList)
163
    {
164
    boolean otherNodesPoint = (mData.numPointingNodes>1);
165

    
166
    if( otherNodesPoint ) mData.numPointingNodes--;
167
    else                  mMapNodeID.remove(oldList);
168
   
169
    NodeData newData = mMapNodeID.get(newList);
170
    
171
    if( newData==null )
172
      {
173
      if( otherNodesPoint )  mData = new NodeData(++mNextNodeID);
174
      else                   mData.ID = ++mNextNodeID;  // numPointingNodes must be 1 already
175

    
176
      if( newList.size()>1 && mData.mDRT==null )
177
        mData.mDRT = new DistortedRenderTarget(mObject.getWidth(), mObject.getHeight());
178

    
179
      mMapNodeID.put(newList, mData);
180
      }
181
    else
182
      {
183
      newData.numPointingNodes++;
184
      mData = newData;
185
      }
186
    }
187

    
188
///////////////////////////////////////////////////////////////////////////////////////////////////  
189
// this will be called on startup and every time OpenGL context has been lost
190
// also call this from the constructor if the OpenGL context has been created already.
191
    
192
  static void reset()
193
    {
194
    NodeData tmp;   
195
     
196
    for(ArrayList<Long> key: mMapNodeID.keySet())
197
      {
198
      tmp = mMapNodeID.get(key);
199
          
200
      if( tmp.mDRT != null )
201
        {
202
    	  tmp.mDRT.reset();
203
        tmp.mRendered  = false;
204
        }
205
      }
206
    }
207

    
208
///////////////////////////////////////////////////////////////////////////////////////////////////
209
// Debug - print all the Node IDs
210

    
211
  void debug(int depth)
212
    {
213
    String tmp="";
214
    int i;
215

    
216
    for(i=0; i<depth; i++) tmp +="   ";
217
    tmp += (""+mData.ID);
218

    
219
    android.util.Log.e("node", tmp);
220

    
221
    for(i=0; i<mNumChildren[0]; i++)
222
      mChildren.get(i).debug(depth+1);
223
    }
224

    
225
///////////////////////////////////////////////////////////////////////////////////////////////////
226
// Debug - print contents of the HashMap
227

    
228
  static void debugMap()
229
    {
230
    NodeData tmp;
231

    
232
    for(ArrayList<Long> key: mMapNodeID.keySet())
233
      {
234
      tmp = mMapNodeID.get(key);
235

    
236
      android.util.Log.e("NODE", "key="+key+" NodeID: "+tmp.ID);
237
      }
238
    }
239

    
240
///////////////////////////////////////////////////////////////////////////////////////////////////
241
// PUBLIC API
242
///////////////////////////////////////////////////////////////////////////////////////////////////
243
/**
244
 * Constructs new Node of the Tree.
245
 *     
246
 * @param obj DistortedObject to put into the new Node.
247
 */
248
  public DistortedNode(DistortedObject obj)
249
    {
250
    mObject = obj;
251
    mParent = null;
252
    mChildren = null;
253
    mNumChildren = new int[1];
254
    mNumChildren[0] = 0;
255
   
256
    ArrayList<Long> list = new ArrayList<>();
257
    list.add(obj.getID());
258
      
259
    mData = mMapNodeID.get(list);
260
   
261
    if( mData!=null )
262
      {
263
      mData.numPointingNodes++;
264
      }
265
    else
266
      {
267
      mData = new NodeData(++mNextNodeID);   
268
      mMapNodeID.put(list, mData);  
269
      }
270
    }
271

    
272
///////////////////////////////////////////////////////////////////////////////////////////////////  
273
/**
274
 * Copy-constructs new Node of the Tree from another Node.
275
 *     
276
 * @param node The DistortedNode to copy data from.
277
 * @param flags bit field composed of a subset of the following:
278
 *        {@link Distorted#CLONE_BITMAP},  {@link Distorted#CLONE_MATRIX}, {@link Distorted#CLONE_VERTEX},
279
 *        {@link Distorted#CLONE_FRAGMENT} and {@link Distorted#CLONE_CHILDREN}.
280
 *        For example flags = CLONE_BITMAP | CLONE_CHILDREN.
281
 */
282
  public DistortedNode(DistortedNode node, int flags)
283
    {
284
    mParent = null;
285
    mObject = node.mObject.deepCopy(flags);
286

    
287
    if( (flags & Distorted.CLONE_CHILDREN) != 0 )
288
      {
289
      mChildren = node.mChildren;
290
      mNumChildren = node.mNumChildren;
291
      }
292
    else
293
      {
294
      mChildren = null;
295
      mNumChildren = new int[1];
296
      mNumChildren[0] = 0;
297
      }
298
   
299
    ArrayList<Long> list = generateIDList();
300
   
301
    mData = mMapNodeID.get(list);
302
   
303
    if( mData!=null )
304
      {
305
      mData.numPointingNodes++;
306
      }
307
    else
308
      {
309
      mData = new NodeData(++mNextNodeID);   
310
      mMapNodeID.put(list, mData);
311
      }
312
    }
313
  
314
///////////////////////////////////////////////////////////////////////////////////////////////////
315
/**
316
 * Adds a new child to the last position in the list of our Node's children.
317
 * 
318
 * @param node The new Node to add.
319
 */
320
  public synchronized void attach(DistortedNode node)
321
    {
322
    ArrayList<Long> prev = generateIDList(); 
323
   
324
    if( mChildren==null ) mChildren = new ArrayList<>(2);
325
     
326
    node.mParent = this;
327
    mChildren.add(node);
328
    mNumChildren[0]++;
329
     
330
    RecomputeNodeID(prev);
331
    }
332
   
333
///////////////////////////////////////////////////////////////////////////////////////////////////
334
/**
335
 * Adds a new child to the last position in the list of our Node's children.
336
 * 
337
 * @param obj DistortedObject to initialize our child Node with.
338
 * @return the newly constructed child Node, or null if we couldn't allocate resources.
339
 */
340
  public synchronized DistortedNode attach(DistortedObject obj)
341
    {
342
    ArrayList<Long> prev = generateIDList(); 
343
      
344
    if( mChildren==null ) mChildren = new ArrayList<>(2);
345
    DistortedNode node = new DistortedNode(obj);
346
    node.mParent = this;
347
    mChildren.add(node);
348
    mNumChildren[0]++;
349
   
350
    RecomputeNodeID(prev);
351

    
352
    return node;
353
    }
354
  
355
///////////////////////////////////////////////////////////////////////////////////////////////////
356
/**
357
 * Removes the first occurrence of a specified child from the list of children of our Node.
358
 * 
359
 * @param node The Node to remove.
360
 * @return <code>true</code> if the child was successfully removed.
361
 */
362
  public synchronized boolean detach(DistortedNode node)
363
    {
364
    if( mNumChildren[0]>0 )
365
      {
366
      ArrayList<Long> prev = generateIDList();  
367
         
368
      if( mChildren.remove(node) )
369
        {
370
        node.mParent = null;  
371
        mNumChildren[0]--;
372
     
373
        RecomputeNodeID(prev);
374
     
375
        return true;
376
        }
377
      }
378
   
379
    return false;
380
    }
381
  
382
///////////////////////////////////////////////////////////////////////////////////////////////////
383
/**
384
 * Removes the first occurrence of a specified child from the list of children of our Node.
385
 * 
386
 * @param obj DistortedObject to remove.
387
 * @return <code>true</code> if the child was successfully removed.
388
 */
389
  public synchronized boolean detach(DistortedObject obj)
390
    {
391
    long id = obj.getID();
392
    DistortedNode node;
393
   
394
    for(int i=0; i<mNumChildren[0]; i++)
395
      {
396
      node = mChildren.get(i);
397
     
398
      if( node.mObject.getID()==id )
399
        {
400
        ArrayList<Long> prev = generateIDList();   
401
     
402
        node.mParent = null;  
403
        mChildren.remove(i);
404
        mNumChildren[0]--;
405
      
406
        RecomputeNodeID(prev);
407
      
408
        return true;
409
        }
410
      }
411
   
412
    return false;
413
    }
414
    
415
///////////////////////////////////////////////////////////////////////////////////////////////////
416
/**
417
 * Removes all children Nodes.
418
 */
419
  public synchronized void detachAll()
420
    {
421
    for(int i=0; i<mNumChildren[0]; i++)
422
      {
423
      mChildren.get(i).mParent = null;
424
      }
425
   
426
    if( mNumChildren[0]>0 )
427
      {
428
      ArrayList<Long> prev = generateIDList();  
429
      
430
      mNumChildren[0] = 0;
431
      mChildren.clear();
432
      RecomputeNodeID(prev);
433
      }
434
    }
435
  
436
///////////////////////////////////////////////////////////////////////////////////////////////////
437
/**
438
 * Draws the Node, and all its children, to the default framebuffer 0 (i.e. the screen).
439
 *   
440
 * @param currTime Current time, in milliseconds.
441
 */
442
  public void draw(long currTime)
443
    {  
444
    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
445
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
446
    GLES20.glUniform1i(Distorted.mTextureUniformH, 0);  
447

    
448
    DistortedRenderTargetList.deleteAllMarked();
449

    
450
    markRecursive();
451
    drawRecursive(currTime,Distorted.mRenderTarget);
452
    }
453
 
454
///////////////////////////////////////////////////////////////////////////////////////////////////
455
/**
456
 * Returns the DistortedObject object that's in the Node.
457
 * 
458
 * @return The DistortedObject contained in the Node.
459
 */
460
  public DistortedObject getObject()
461
    {
462
    return mObject;
463
    }
464

    
465
///////////////////////////////////////////////////////////////////////////////////////////////////
466
  }
467

    
(7-7/19)