Project

General

Profile

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

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

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 9361b337 Leszek Koltunski
  private DistortedObject mObject;
41 6a06a912 Leszek Koltunski
  private NodeData mData;
42 bd3da5b2 Leszek Koltunski
43 6a06a912 Leszek Koltunski
  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 bd3da5b2 Leszek Koltunski
    long ID;
50 6a06a912 Leszek Koltunski
    int numPointingNodes;
51 ed13a5de Leszek Koltunski
    DistortedFramebuffer mDF;
52 6a06a912 Leszek Koltunski
    boolean mRendered;
53
54 bd3da5b2 Leszek Koltunski
    NodeData(long id)
55 6a06a912 Leszek Koltunski
      {
56 bd3da5b2 Leszek Koltunski
      ID              = id;
57
      numPointingNodes= 1;
58 ed13a5de Leszek Koltunski
      mDF             = null;
59 bd3da5b2 Leszek Koltunski
      mRendered       = false;
60 6a06a912 Leszek Koltunski
      }
61 bd3da5b2 Leszek Koltunski
    }
62 6a06a912 Leszek Koltunski
 
63 436899f2 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
64
65 f2a0d837 Leszek Koltunski
  static void release()
66 436899f2 Leszek Koltunski
    {
67
    mNextNodeID = 0;
68
    mMapNodeID.clear();
69
    }
70
71 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
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 ed13a5de Leszek Koltunski
  private void drawRecursive(long currTime, DistortedFramebuffer df)
86 6a06a912 Leszek Koltunski
    {
87
    if( mNumChildren[0]<=0 )
88
      {
89 9361b337 Leszek Koltunski
      GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mObject.mTextureDataH[0]);
90 6a06a912 Leszek Koltunski
      }
91
    else
92
      {
93
      if( mData.mRendered==false )
94
        {
95
        mData.mRendered = true;
96 ed13a5de Leszek Koltunski
        mData.mDF.setOutput();
97 bd3da5b2 Leszek Koltunski
98 6a06a912 Leszek Koltunski
        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 9361b337 Leszek Koltunski
        if( mObject.mBitmapSet[0] )
102 6a06a912 Leszek Koltunski
          {
103 9361b337 Leszek Koltunski
          GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mObject.mTextureDataH[0]);
104 ed13a5de Leszek Koltunski
          mObject.drawNoEffectsPriv(mData.mDF);
105 6a06a912 Leszek Koltunski
          }
106
      
107
        synchronized(this)
108
          {
109
          for(int i=0; i<mNumChildren[0]; i++)
110
            {
111 ed13a5de Leszek Koltunski
            mChildren.get(i).drawRecursive(currTime, mData.mDF);
112 6a06a912 Leszek Koltunski
            }
113
          }
114
        }
115 bd3da5b2 Leszek Koltunski
116 ed13a5de Leszek Koltunski
      df.setOutput();
117
      mData.mDF.setInput();   // this is safe because we must have called createFBO() above before.
118 6a06a912 Leszek Koltunski
      }
119
    
120 ed13a5de Leszek Koltunski
    mObject.drawPriv(currTime, df);
121 6a06a912 Leszek Koltunski
    }
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 9361b337 Leszek Koltunski
    ArrayList<Long> ret = new ArrayList<>();
147 6a06a912 Leszek Koltunski
     
148 9361b337 Leszek Koltunski
    ret.add( mNumChildren[0]>0 ? mObject.getBitmapID() : mObject.getID() );
149 6a06a912 Leszek Koltunski
    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 fee0865c Leszek Koltunski
    boolean otherNodesPoint = (mData.numPointingNodes>1);
165
166
    if( otherNodesPoint ) mData.numPointingNodes--;
167
    else                  mMapNodeID.remove(oldList);
168 6a06a912 Leszek Koltunski
   
169
    NodeData newData = mMapNodeID.get(newList);
170
    
171
    if( newData==null )
172
      {
173 fee0865c Leszek Koltunski
      if( otherNodesPoint )  mData = new NodeData(++mNextNodeID);
174
      else                   mData.ID = ++mNextNodeID;  // numPointingNodes must be 1 already
175
176 ed13a5de Leszek Koltunski
      if( newList.size()>1 && mData.mDF==null )
177
        mData.mDF = new DistortedFramebuffer(mObject.getWidth(), mObject.getHeight());
178 bd3da5b2 Leszek Koltunski
179 6a06a912 Leszek Koltunski
      mMapNodeID.put(newList, mData);
180
      }
181
    else
182 fee0865c Leszek Koltunski
      {
183 6a06a912 Leszek Koltunski
      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 ed13a5de Leszek Koltunski
      if( tmp.mDF != null )
201 6a06a912 Leszek Koltunski
        {
202 ed13a5de Leszek Koltunski
    	  tmp.mDF.reset();
203 6a06a912 Leszek Koltunski
        tmp.mRendered  = false;
204
        }
205
      }
206
    }
207 fee0865c Leszek Koltunski
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 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
241
// PUBLIC API
242
///////////////////////////////////////////////////////////////////////////////////////////////////
243
/**
244
 * Constructs new Node of the Tree.
245
 *     
246 9361b337 Leszek Koltunski
 * @param obj DistortedObject to put into the new Node.
247 6a06a912 Leszek Koltunski
 */
248 9361b337 Leszek Koltunski
  public DistortedNode(DistortedObject obj)
249 6a06a912 Leszek Koltunski
    {
250 9361b337 Leszek Koltunski
    mObject = obj;
251 6a06a912 Leszek Koltunski
    mParent = null;
252
    mChildren = null;
253
    mNumChildren = new int[1];
254
    mNumChildren[0] = 0;
255
   
256 9361b337 Leszek Koltunski
    ArrayList<Long> list = new ArrayList<>();
257
    list.add(obj.getID());
258 6a06a912 Leszek Koltunski
      
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 015642fb Leszek Koltunski
 *        {@link Distorted#CLONE_BITMAP},  {@link Distorted#CLONE_MATRIX}, {@link Distorted#CLONE_VERTEX},
279 6a06a912 Leszek Koltunski
 *        {@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 9361b337 Leszek Koltunski
    mParent = null;
285 ada90d33 Leszek Koltunski
    mObject = node.mObject.deepCopy(flags);
286 9361b337 Leszek Koltunski
287
    if( (flags & Distorted.CLONE_CHILDREN) != 0 )
288 6a06a912 Leszek Koltunski
      {
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 9361b337 Leszek Koltunski
    if( mChildren==null ) mChildren = new ArrayList<>(2);
325 6a06a912 Leszek Koltunski
     
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 cb0e1940 Leszek Koltunski
 * @param obj DistortedObject to initialize our child Node with.
338 6a06a912 Leszek Koltunski
 * @return the newly constructed child Node, or null if we couldn't allocate resources.
339
 */
340 cb0e1940 Leszek Koltunski
  public synchronized DistortedNode attach(DistortedObject obj)
341 6a06a912 Leszek Koltunski
    {
342
    ArrayList<Long> prev = generateIDList(); 
343
      
344 9361b337 Leszek Koltunski
    if( mChildren==null ) mChildren = new ArrayList<>(2);
345 cb0e1940 Leszek Koltunski
    DistortedNode node = new DistortedNode(obj);
346 6a06a912 Leszek Koltunski
    node.mParent = this;
347
    mChildren.add(node);
348
    mNumChildren[0]++;
349
   
350
    RecomputeNodeID(prev);
351 fee0865c Leszek Koltunski
352 6a06a912 Leszek Koltunski
    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 9361b337 Leszek Koltunski
 * @param obj DistortedObject to remove.
387 6a06a912 Leszek Koltunski
 * @return <code>true</code> if the child was successfully removed.
388
 */
389 9361b337 Leszek Koltunski
  public synchronized boolean detach(DistortedObject obj)
390 6a06a912 Leszek Koltunski
    {
391 9361b337 Leszek Koltunski
    long id = obj.getID();
392 6a06a912 Leszek Koltunski
    DistortedNode node;
393
   
394
    for(int i=0; i<mNumChildren[0]; i++)
395
      {
396
      node = mChildren.get(i);
397
     
398 9361b337 Leszek Koltunski
      if( node.mObject.getID()==id )
399 6a06a912 Leszek Koltunski
        {
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 bd3da5b2 Leszek Koltunski
448 6a06a912 Leszek Koltunski
    markRecursive();
449 ed13a5de Leszek Koltunski
    drawRecursive(currTime,Distorted.mFramebuffer);
450 6a06a912 Leszek Koltunski
    }
451
 
452
///////////////////////////////////////////////////////////////////////////////////////////////////
453
/**
454 9361b337 Leszek Koltunski
 * Returns the DistortedObject object that's in the Node.
455 6a06a912 Leszek Koltunski
 * 
456 9361b337 Leszek Koltunski
 * @return The DistortedObject contained in the Node.
457 6a06a912 Leszek Koltunski
 */
458 9361b337 Leszek Koltunski
  public DistortedObject getObject()
459 6a06a912 Leszek Koltunski
    {
460 9361b337 Leszek Koltunski
    return mObject;
461 6a06a912 Leszek Koltunski
    }
462
463
///////////////////////////////////////////////////////////////////////////////////////////////////
464
  }