Project

General

Profile

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

library / src / main / java / org / distorted / library / main / DistortedNode.java @ 9a3607b3

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 fe82a979 Leszek Koltunski
package org.distorted.library.main;
21 6a06a912 Leszek Koltunski
22 8dccc3c2 Leszek Koltunski
import android.opengl.GLES31;
23
24 715e7726 Leszek Koltunski
import org.distorted.library.mesh.MeshBase;
25 6c00149d Leszek Koltunski
26 6a06a912 Leszek Koltunski
import java.util.ArrayList;
27 c9f953c2 Leszek Koltunski
import java.util.Collections;
28 6a06a912 Leszek Koltunski
import java.util.HashMap;
29
30
///////////////////////////////////////////////////////////////////////////////////////////////////
31
/**
32 a09ada4c Leszek Koltunski
 * Class which represents a Node in a Tree of (InputSurface,Mesh,Effects) triplets.
33 c204c69d leszek
 * <p>
34 a09ada4c Leszek Koltunski
 * Having organized such sets into a Tree, we can then render any Node to any OutputSurface.
35 7b8086eb Leszek Koltunski
 * That recursively renders the set held in the Node and all its children.
36 c204c69d leszek
 * <p>
37
 * The class takes special care to only render identical sub-trees once. Each Node holds a reference
38
 * to sub-class 'NodeData'. Two identical sub-trees attached at different points of the main tree
39 3a70bd6d leszek
 * will point to the same NodeData; only the first of this is rendered (mData.numRender!).
40 6a06a912 Leszek Koltunski
 */
41 86d322b5 Leszek Koltunski
public class DistortedNode implements DistortedMaster.Slave
42 6a06a912 Leszek Koltunski
  {
43 efe3d8fe leszek
  private static final int ATTACH = 0;
44
  private static final int DETACH = 1;
45
  private static final int DETALL = 2;
46
  private static final int SORT   = 3;
47
48
  private ArrayList<DistortedNode> mChildren;
49
  private int[] mNumChildren;  // ==mChildren.length(), but we only create mChildren if the first one gets added
50
51
  private class Job
52
    {
53
    int type;
54
    DistortedNode node;
55
56 ffbe7ecf Leszek Koltunski
    Job(int t, DistortedNode n)
57 efe3d8fe leszek
      {
58
      type = t;
59
      node = n;
60
      }
61
    }
62
63
  private ArrayList<Job> mJobs = new ArrayList<>();
64
65 bd3da5b2 Leszek Koltunski
  private static HashMap<ArrayList<Long>,NodeData> mMapNodeID = new HashMap<>();
66
  private static long mNextNodeID =0;
67
68 406e2f6b Leszek Koltunski
  private boolean mRenderWayOIT;
69 f28fffc2 Leszek Koltunski
  private DistortedNode mParent;
70 be60d4ff leszek
  private DistortedOutputSurface mSurfaceParent;
71 715e7726 Leszek Koltunski
  private MeshBase mMesh;
72 07d8ef09 Leszek Koltunski
  private DistortedEffects mEffects;
73 12f9e4bb Leszek Koltunski
  private DistortedSurface mSurface;
74 c834348d leszek
  private DistortedRenderState mState;
75 6a06a912 Leszek Koltunski
  private NodeData mData;
76 23eecbd9 Leszek Koltunski
  private int mFboW, mFboH, mFboDepthStencil;
77 bd3da5b2 Leszek Koltunski
78 6a06a912 Leszek Koltunski
  private class NodeData
79
    {
80 bd3da5b2 Leszek Koltunski
    long ID;
81 6a06a912 Leszek Koltunski
    int numPointingNodes;
82 50642a86 Leszek Koltunski
    long currTime;
83 af27df87 leszek
    ArrayList<Long> key;
84 8c327653 Leszek Koltunski
    DistortedFramebuffer mFBO;
85 6a06a912 Leszek Koltunski
86 af27df87 leszek
    NodeData(long id, ArrayList<Long> k)
87 6a06a912 Leszek Koltunski
      {
88 bd3da5b2 Leszek Koltunski
      ID              = id;
89 af27df87 leszek
      key             = k;
90 bd3da5b2 Leszek Koltunski
      numPointingNodes= 1;
91 50642a86 Leszek Koltunski
      currTime        =-1;
92 8c327653 Leszek Koltunski
      mFBO            = null;
93 6a06a912 Leszek Koltunski
      }
94 bd3da5b2 Leszek Koltunski
    }
95 0c303a2c Leszek Koltunski
96 436899f2 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
97
98 7b8086eb Leszek Koltunski
  static synchronized void onDestroy()
99 436899f2 Leszek Koltunski
    {
100
    mNextNodeID = 0;
101
    mMapNodeID.clear();
102
    }
103
104 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
105
106
  private ArrayList<Long> generateIDList()
107
    {
108 9361b337 Leszek Koltunski
    ArrayList<Long> ret = new ArrayList<>();
109 7691a39f leszek
110
    if( mNumChildren[0]==0 )
111
      {
112 c9f953c2 Leszek Koltunski
      // add a negative number so this leaf never gets confused with a internal node
113
      // with a single child that happens to have ID identical to some leaf's Effects ID.
114 7691a39f leszek
      ret.add(-mEffects.getID());
115
      }
116 c9f953c2 Leszek Koltunski
    else
117 6a06a912 Leszek Koltunski
      {
118 c9f953c2 Leszek Koltunski
      DistortedNode node;
119 6a06a912 Leszek Koltunski
   
120 c9f953c2 Leszek Koltunski
      for(int i=0; i<mNumChildren[0]; i++)
121
        {
122
        node = mChildren.get(i);
123
        ret.add(node.mData.ID);
124
        }
125
126
      // A bit questionable decision here - we are sorting the children IDs, which means
127
      // that order in which we draw the children is going to be undefined (well, this is not
128
      // strictly speaking true - when rendering, if no postprocessing and isomorphism are
129
      // involved, we *DO* render the children in order they were added; if however there
130
      // are two internal nodes with the same list of identical children, just added in a
131
      // different order each time, then we consider them isomorphic, i.e. identical and only
132
      // render the first one. If then two children of such 'pseudo-isomorphic' nodes are at
133
      // exactly the same Z-height this might result in some unexpected sights).
134
      //
135
      // Reason: with the children being sorted by postprocessing buckets, the order is
136
      // undefined anyway (although only when postprocessing is applied).
137
      //
138
      // See the consequences in the 'Olympic' app - remove a few leaves and add them back in
139 d5e053a5 Leszek Koltunski
      // different order. You will see the number of renders go back to the original 15.
140 c9f953c2 Leszek Koltunski
      Collections.sort(ret);
141
      }
142
143
    ret.add( 0, mSurface.getID() );
144
145 6a06a912 Leszek Koltunski
    return ret;
146
    }
147
148 fee0865c Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
149
// Debug - print all the Node IDs
150 c204c69d leszek
151 af27df87 leszek
  @SuppressWarnings("unused")
152 fee0865c Leszek Koltunski
  void debug(int depth)
153
    {
154
    String tmp="";
155
    int i;
156
157
    for(i=0; i<depth; i++) tmp +="   ";
158 07037b8a leszek
    tmp += ("NodeID="+mData.ID+" nodes pointing: "+mData.numPointingNodes+" surfaceID="+
159 f28fffc2 Leszek Koltunski
            mSurface.getID()+" FBO="+(mData.mFBO==null ? "null":mData.mFBO.getID()))+
160
            " parent sID="+(mParent==null ? "null": (mParent.mSurface.getID()));
161 fee0865c Leszek Koltunski
162 1942537e Leszek Koltunski
    android.util.Log.e("NODE", tmp);
163 fee0865c Leszek Koltunski
164
    for(i=0; i<mNumChildren[0]; i++)
165
      mChildren.get(i).debug(depth+1);
166
    }
167
168
///////////////////////////////////////////////////////////////////////////////////////////////////
169
// Debug - print contents of the HashMap
170
171 af27df87 leszek
  @SuppressWarnings("unused")
172 fee0865c Leszek Koltunski
  static void debugMap()
173
    {
174
    NodeData tmp;
175
176
    for(ArrayList<Long> key: mMapNodeID.keySet())
177
      {
178
      tmp = mMapNodeID.get(key);
179 c204c69d leszek
      android.util.Log.e("NODE", "NodeID: "+tmp.ID+" <-- "+key);
180
      }
181
    }
182
183
///////////////////////////////////////////////////////////////////////////////////////////////////
184 f28fffc2 Leszek Koltunski
// tree isomorphism algorithm
185 c204c69d leszek
186 f28fffc2 Leszek Koltunski
  private void adjustIsomorphism()
187 c204c69d leszek
    {
188
    ArrayList<Long> newList = generateIDList();
189
    NodeData newData = mMapNodeID.get(newList);
190
191 f28fffc2 Leszek Koltunski
    if( newData!=null )
192
      {
193
      newData.numPointingNodes++;
194
      }
195
    else
196 c204c69d leszek
      {
197 af27df87 leszek
      newData = new NodeData(++mNextNodeID,newList);
198 c204c69d leszek
      mMapNodeID.put(newList,newData);
199
      }
200 07037b8a leszek
201 f28fffc2 Leszek Koltunski
    boolean deleteOldFBO = false;
202
    boolean createNewFBO = false;
203 c204c69d leszek
204 f28fffc2 Leszek Koltunski
    if( --mData.numPointingNodes==0 )
205 c204c69d leszek
      {
206 f28fffc2 Leszek Koltunski
      mMapNodeID.remove(mData.key);
207
      if( mData.mFBO!=null ) deleteOldFBO=true;
208
      }
209
    if( mNumChildren[0]>0 && newData.mFBO==null )
210
      {
211
      createNewFBO = true;
212
      }
213
    if( mNumChildren[0]==0 && newData.mFBO!=null )
214
      {
215
      newData.mFBO.markForDeletion();
216 85bfeb7a Leszek Koltunski
      android.util.Log.e("NODE", "ERROR!! this NodeData cannot possibly contain a non-null FBO!! "+newData.mFBO.getID() );
217 f28fffc2 Leszek Koltunski
      newData.mFBO = null;
218
      }
219 c204c69d leszek
220 f28fffc2 Leszek Koltunski
    if( deleteOldFBO && createNewFBO )
221
      {
222
      newData.mFBO = mData.mFBO;  // just copy over
223 eadf0859 leszek
      //android.util.Log.d("NODE", "copying over FBOs "+mData.mFBO.getID() );
224 f28fffc2 Leszek Koltunski
      }
225
    else if( deleteOldFBO )
226
      {
227
      mData.mFBO.markForDeletion();
228 eadf0859 leszek
      //android.util.Log.d("NODE", "deleting old FBO "+mData.mFBO.getID() );
229 f28fffc2 Leszek Koltunski
      mData.mFBO = null;
230
      }
231
    else if( createNewFBO )
232
      {
233 23eecbd9 Leszek Koltunski
      int width  = mFboW <= 0 ? mSurface.getWidth()  : mFboW;
234
      int height = mFboH <= 0 ? mSurface.getHeight() : mFboH;
235 9ed80185 Leszek Koltunski
      newData.mFBO = new DistortedFramebuffer(1,mFboDepthStencil, DistortedSurface.TYPE_TREE, width, height);
236 eadf0859 leszek
      //android.util.Log.d("NODE", "creating new FBO "+newData.mFBO.getID() );
237 f28fffc2 Leszek Koltunski
      }
238 af27df87 leszek
239 f28fffc2 Leszek Koltunski
    mData = newData;
240 c204c69d leszek
241 f28fffc2 Leszek Koltunski
    if( mParent!=null ) mParent.adjustIsomorphism();
242 fee0865c Leszek Koltunski
    }
243 c204c69d leszek
244 8dccc3c2 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
245
// return the total number of render calls issued
246
247
  int drawNoBlend(long currTime, DistortedOutputSurface surface)
248
    {
249 12f9e4bb Leszek Koltunski
    DistortedSurface input = mNumChildren[0]==0 ? mSurface : mData.mFBO;
250 8dccc3c2 Leszek Koltunski
251
    if( input.setAsInput() )
252
      {
253
      mState.apply();
254
      GLES31.glDisable(GLES31.GL_BLEND);
255 a13dde77 Leszek Koltunski
      mEffects.drawPriv(mSurface.getWidth()/2.0f, mSurface.getHeight()/2.0f, mMesh, surface, currTime);
256 8dccc3c2 Leszek Koltunski
      GLES31.glEnable(GLES31.GL_BLEND);
257
      return 1;
258
      }
259 c1a38ba3 Leszek Koltunski
260
    return 0;
261
    }
262
263
///////////////////////////////////////////////////////////////////////////////////////////////////
264
// Use the Order Independent Transparency method to draw a non-postprocessed child.
265
266
  int drawOIT(long currTime, DistortedOutputSurface surface)
267
    {
268 12f9e4bb Leszek Koltunski
    DistortedSurface input = mNumChildren[0]==0 ? mSurface : mData.mFBO;
269 c1a38ba3 Leszek Koltunski
270
    if( input.setAsInput() )
271
      {
272
      mState.apply();
273 a13dde77 Leszek Koltunski
      mEffects.drawPrivOIT(mSurface.getWidth()/2.0f, mSurface.getHeight()/2.0f, mMesh, surface, currTime);
274 c1a38ba3 Leszek Koltunski
      return 1;
275
      }
276 8dccc3c2 Leszek Koltunski
277
    return 0;
278
    }
279
280 39086ebb leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
281
// return the total number of render calls issued
282
283
  int draw(long currTime, DistortedOutputSurface surface)
284
    {
285 12f9e4bb Leszek Koltunski
    DistortedSurface input = mNumChildren[0]==0 ? mSurface : mData.mFBO;
286 39086ebb leszek
287
    if( input.setAsInput() )
288
      {
289
      mState.apply();
290 a13dde77 Leszek Koltunski
      mEffects.drawPriv(mSurface.getWidth()/2.0f, mSurface.getHeight()/2.0f, mMesh, surface, currTime);
291 39086ebb leszek
      return 1;
292
      }
293
294
    return 0;
295
    }
296
297
///////////////////////////////////////////////////////////////////////////////////////////////////
298
// return the total number of render calls issued
299
300
  int renderRecursive(long currTime)
301
    {
302
    int numRenders = 0;
303
304
    if( mNumChildren[0]>0 && mData.currTime!=currTime )
305
      {
306
      mData.currTime = currTime;
307
308
      for (int i=0; i<mNumChildren[0]; i++)
309
        {
310
        numRenders += mChildren.get(i).renderRecursive(currTime);
311
        }
312
313 0c303a2c Leszek Koltunski
      if( mData.mFBO==null )
314
        {
315 23eecbd9 Leszek Koltunski
        int width  = mFboW <= 0 ? mSurface.getWidth()  : mFboW;
316
        int height = mFboH <= 0 ? mSurface.getHeight() : mFboH;
317 9ed80185 Leszek Koltunski
        mData.mFBO = new DistortedFramebuffer(1,mFboDepthStencil, DistortedSurface.TYPE_TREE, width, height);
318 0c303a2c Leszek Koltunski
        }
319
320 95c441a2 leszek
      mData.mFBO.setAsOutput(currTime);
321 39086ebb leszek
322
      if( mSurface.setAsInput() )
323
        {
324
        numRenders++;
325
        DistortedEffects.blitPriv(mData.mFBO);
326
        }
327
328 406e2f6b Leszek Koltunski
      numRenders += mData.mFBO.renderChildren(currTime,mNumChildren[0],mChildren,0, mRenderWayOIT);
329 39086ebb leszek
      }
330
331
    return numRenders;
332
    }
333
334 be60d4ff leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
335
336
  void setSurfaceParent(DistortedOutputSurface dep)
337
    {
338
    mSurfaceParent = dep;
339
    mParent = null;
340
    }
341
342 26a4e5f6 leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
343
344
  void sort()
345
    {
346
    if( mParent!=null )
347
      {
348
      mParent.mChildren.remove(this);
349 85bfeb7a Leszek Koltunski
      DistortedMaster.addSortingByBuckets(mParent.mChildren,this);
350 26a4e5f6 leszek
      }
351
    else if( mSurfaceParent!=null )
352
      {
353
      ArrayList<DistortedNode> children = mSurfaceParent.getChildren();
354
      children.remove(this);
355 85bfeb7a Leszek Koltunski
      DistortedMaster.addSortingByBuckets(children,this);
356 26a4e5f6 leszek
      }
357
    }
358
359 70b6a155 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
360
/**
361
 * Not part of the Public API.
362
 *
363
 * @y.exclude
364
 */
365
  public EffectQueuePostprocess getPostprocessQueue()
366
    {
367
    return mEffects.getPostprocess();
368
    }
369
370 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
371
// PUBLIC API
372
///////////////////////////////////////////////////////////////////////////////////////////////////
373
/**
374 a09ada4c Leszek Koltunski
 * Constructs new Node.
375 6a06a912 Leszek Koltunski
 *     
376 c5369f1b leszek
 * @param surface InputSurface to put into the new Node.
377 07d8ef09 Leszek Koltunski
 * @param effects DistortedEffects to put into the new Node.
378 715e7726 Leszek Koltunski
 * @param mesh MeshBase to put into the new Node.
379 6a06a912 Leszek Koltunski
 */
380 715e7726 Leszek Koltunski
  public DistortedNode(DistortedSurface surface, DistortedEffects effects, MeshBase mesh)
381 6a06a912 Leszek Koltunski
    {
382 c5369f1b leszek
    mSurface       = surface;
383 8ca9f899 Leszek Koltunski
    mEffects       = effects;
384
    mMesh          = mesh;
385 c834348d leszek
    mState         = new DistortedRenderState();
386 8ca9f899 Leszek Koltunski
    mChildren      = null;
387
    mNumChildren   = new int[1];
388
    mNumChildren[0]= 0;
389 f28fffc2 Leszek Koltunski
    mParent        = null;
390 be60d4ff leszek
    mSurfaceParent = null;
391 406e2f6b Leszek Koltunski
    mRenderWayOIT  = false;
392 f28fffc2 Leszek Koltunski
393 23eecbd9 Leszek Koltunski
    mFboW            = 0;  // i.e. take this from
394
    mFboH            = 0;  // mSurface's dimensions
395
    mFboDepthStencil = DistortedFramebuffer.DEPTH_NO_STENCIL;
396
397 9361b337 Leszek Koltunski
    ArrayList<Long> list = new ArrayList<>();
398 c5369f1b leszek
    list.add(mSurface.getID());
399 7691a39f leszek
    list.add(-mEffects.getID());
400 1942537e Leszek Koltunski
401 6a06a912 Leszek Koltunski
    mData = mMapNodeID.get(list);
402
   
403
    if( mData!=null )
404
      {
405
      mData.numPointingNodes++;
406
      }
407
    else
408
      {
409 af27df87 leszek
      mData = new NodeData(++mNextNodeID,list);
410 1942537e Leszek Koltunski
      mMapNodeID.put(list, mData);
411 6a06a912 Leszek Koltunski
      }
412 26a4e5f6 leszek
413
    mEffects.newNode(this);
414 6a06a912 Leszek Koltunski
    }
415
416
///////////////////////////////////////////////////////////////////////////////////////////////////  
417
/**
418 a09ada4c Leszek Koltunski
 * Copy-constructs new Node from another Node.
419 6a06a912 Leszek Koltunski
 *     
420 a09ada4c Leszek Koltunski
 * @param node The DistortedNode to copy data from.
421 6a06a912 Leszek Koltunski
 * @param flags bit field composed of a subset of the following:
422 29a06526 Leszek Koltunski
 *        {@link Distorted#CLONE_SURFACE},  {@link Distorted#CLONE_MATRIX}, {@link Distorted#CLONE_VERTEX},
423 6a06a912 Leszek Koltunski
 *        {@link Distorted#CLONE_FRAGMENT} and {@link Distorted#CLONE_CHILDREN}.
424 29a06526 Leszek Koltunski
 *        For example flags = CLONE_SURFACE | CLONE_CHILDREN.
425 6a06a912 Leszek Koltunski
 */
426 a09ada4c Leszek Koltunski
  public DistortedNode(DistortedNode node, int flags)
427 6a06a912 Leszek Koltunski
    {
428 be60d4ff leszek
    mEffects      = new DistortedEffects(node.mEffects,flags);
429
    mMesh         = node.mMesh;
430
    mState        = new DistortedRenderState();
431
    mParent       = null;
432
    mSurfaceParent= null;
433 406e2f6b Leszek Koltunski
    mRenderWayOIT = false;
434 9361b337 Leszek Koltunski
435 23eecbd9 Leszek Koltunski
    mFboW            = node.mFboW;
436
    mFboH            = node.mFboH;
437
    mFboDepthStencil = node.mFboDepthStencil;
438
439 29a06526 Leszek Koltunski
    if( (flags & Distorted.CLONE_SURFACE) != 0 )
440 e7a20702 Leszek Koltunski
      {
441 c5369f1b leszek
      mSurface = node.mSurface;
442 e7a20702 Leszek Koltunski
      }
443
    else
444
      {
445 c5369f1b leszek
      int w = node.mSurface.getWidth();
446
      int h = node.mSurface.getHeight();
447 8ca9f899 Leszek Koltunski
448 c5369f1b leszek
      if( node.mSurface instanceof DistortedTexture )
449 8ca9f899 Leszek Koltunski
        {
450 09ab7524 Leszek Koltunski
        mSurface = new DistortedTexture(w,h, DistortedSurface.TYPE_TREE);
451 8ca9f899 Leszek Koltunski
        }
452 c5369f1b leszek
      else if( node.mSurface instanceof DistortedFramebuffer )
453 8ca9f899 Leszek Koltunski
        {
454 23eecbd9 Leszek Koltunski
        int depthStencil = DistortedFramebuffer.NO_DEPTH_NO_STENCIL;
455 89de975c leszek
456
        if( ((DistortedFramebuffer) node.mSurface).hasDepth() )
457
          {
458
          boolean hasStencil = ((DistortedFramebuffer) node.mSurface).hasStencil();
459
          depthStencil = (hasStencil ? DistortedFramebuffer.BOTH_DEPTH_STENCIL:DistortedFramebuffer.DEPTH_NO_STENCIL);
460
          }
461
462 9ed80185 Leszek Koltunski
        mSurface = new DistortedFramebuffer(1,depthStencil,DistortedSurface.TYPE_TREE,w,h);
463 8ca9f899 Leszek Koltunski
        }
464 e7a20702 Leszek Koltunski
      }
465 9361b337 Leszek Koltunski
    if( (flags & Distorted.CLONE_CHILDREN) != 0 )
466 6a06a912 Leszek Koltunski
      {
467 c204c69d leszek
      if( node.mChildren==null )     // do NOT copy over the NULL!
468
        {
469
        node.mChildren = new ArrayList<>(2);
470
        }
471
472 6a06a912 Leszek Koltunski
      mChildren = node.mChildren;
473
      mNumChildren = node.mNumChildren;
474
      }
475
    else
476
      {
477
      mChildren = null;
478
      mNumChildren = new int[1];
479
      mNumChildren[0] = 0;
480
      }
481
   
482
    ArrayList<Long> list = generateIDList();
483
   
484
    mData = mMapNodeID.get(list);
485
   
486
    if( mData!=null )
487
      {
488
      mData.numPointingNodes++;
489
      }
490
    else
491
      {
492 af27df87 leszek
      mData = new NodeData(++mNextNodeID,list);
493 6a06a912 Leszek Koltunski
      mMapNodeID.put(list, mData);
494
      }
495 26a4e5f6 leszek
496
    mEffects.newNode(this);
497 6a06a912 Leszek Koltunski
    }
498 c204c69d leszek
499 406e2f6b Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
500
  /**
501
   * When rendering this Node, should we use the Order Independent Transparency render more?
502
   * <p>
503
   * There are two modes of rendering: the fast 'normal' way, which however renders transparent
504
   * fragments in different ways depending on which fragments get rendered first, or the slower
505
   * 'oit' way, which renders transparent fragments correctly regardless of their order.
506
   *
507
   * @param oit True if we want to render more slowly, but in a way which accounts for transparency.
508
   */
509
  public void setOrderIndependentTransparency(boolean oit)
510
    {
511
    mRenderWayOIT = oit;
512
    }
513
514 12f9e4bb Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
515
  /**
516
   * When rendering this Node, should we use the Order Independent Transparency render more?
517
   * <p>
518
   * There are two modes of rendering: the fast 'normal' way, which however renders transparent
519
   * fragments in different ways depending on which fragments get rendered first, or the slower
520
   * 'oit' way, which renders transparent fragments correctly regardless of their order.
521
   *
522
   * @param oit True if we want to render more slowly, but in a way which accounts for transparency.
523
   * @param initialSize Initial number of transparent fragments we expect, in screenfulls.
524
   *                    I.e '1.0' means 'the scene we are going to render contains about 1 screen
525
   *                    worth of transparent fragments'. Valid values: 0.0 &lt; initialSize &lt; 10.0
526
   *                    Even if you get this wrong, the library will detect that there are more
527
   *                    transparent fragments than it has space for and readjust its internal buffers,
528
   *                    but only after a few frames during which one will probably see missing objects.
529
   */
530
  public void setOrderIndependentTransparency(boolean oit, float initialSize)
531
    {
532
    mRenderWayOIT = oit;
533
534
    if( initialSize>0.0f && initialSize<10.0f )
535
      DistortedEffects.setSSBOSize(initialSize);
536
    }
537
538 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
539
/**
540
 * Adds a new child to the last position in the list of our Node's children.
541 c204c69d leszek
 * <p>
542
 * We cannot do this mid-render - actual attachment will be done just before the next render, by the
543 efe3d8fe leszek
 * DistortedMaster (by calling doWork())
544 c204c69d leszek
 *
545 6a06a912 Leszek Koltunski
 * @param node The new Node to add.
546
 */
547 c204c69d leszek
  public void attach(DistortedNode node)
548 6a06a912 Leszek Koltunski
    {
549 ffbe7ecf Leszek Koltunski
    mJobs.add(new Job(ATTACH,node));
550 efe3d8fe leszek
    DistortedMaster.newSlave(this);
551 6a06a912 Leszek Koltunski
    }
552 c204c69d leszek
553 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
554
/**
555
 * Adds a new child to the last position in the list of our Node's children.
556 c204c69d leszek
 * <p>
557
 * We cannot do this mid-render - actual attachment will be done just before the next render, by the
558 efe3d8fe leszek
 * DistortedMaster (by calling doWork())
559 c204c69d leszek
 *
560 c5369f1b leszek
 * @param surface InputSurface to initialize our child Node with.
561 07d8ef09 Leszek Koltunski
 * @param effects DistortedEffects to initialize our child Node with.
562 715e7726 Leszek Koltunski
 * @param mesh MeshBase to initialize our child Node with.
563 6a06a912 Leszek Koltunski
 * @return the newly constructed child Node, or null if we couldn't allocate resources.
564
 */
565 715e7726 Leszek Koltunski
  public DistortedNode attach(DistortedSurface surface, DistortedEffects effects, MeshBase mesh)
566 6a06a912 Leszek Koltunski
    {
567 c204c69d leszek
    DistortedNode node = new DistortedNode(surface,effects,mesh);
568 ffbe7ecf Leszek Koltunski
    mJobs.add(new Job(ATTACH,node));
569 efe3d8fe leszek
    DistortedMaster.newSlave(this);
570 c204c69d leszek
    return node;
571
    }
572 f8377ef8 leszek
573 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
574
/**
575
 * Removes the first occurrence of a specified child from the list of children of our Node.
576 c204c69d leszek
 * <p>
577
 * We cannot do this mid-render - actual detachment will be done just before the next render, by the
578 efe3d8fe leszek
 * DistortedMaster (by calling doWork())
579 c204c69d leszek
 *
580 6a06a912 Leszek Koltunski
 * @param node The Node to remove.
581
 */
582 c204c69d leszek
  public void detach(DistortedNode node)
583 6a06a912 Leszek Koltunski
    {
584 ffbe7ecf Leszek Koltunski
    mJobs.add(new Job(DETACH,node));
585 efe3d8fe leszek
    DistortedMaster.newSlave(this);
586 6a06a912 Leszek Koltunski
    }
587 a09ada4c Leszek Koltunski
588 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
589
/**
590
 * Removes the first occurrence of a specified child from the list of children of our Node.
591 a09ada4c Leszek Koltunski
 * <p>
592
 * A bit questionable method as there can be many different Nodes attached as children, some
593
 * of them having the same Effects but - for instance - different Mesh. Use with care.
594 c204c69d leszek
 * <p>
595
 * We cannot do this mid-render - actual detachment will be done just before the next render, by the
596 efe3d8fe leszek
 * DistortedMaster (by calling doWork())
597 a09ada4c Leszek Koltunski
 *
598 07d8ef09 Leszek Koltunski
 * @param effects DistortedEffects to remove.
599 6a06a912 Leszek Koltunski
 */
600 c204c69d leszek
  public void detach(DistortedEffects effects)
601 6a06a912 Leszek Koltunski
    {
602 07d8ef09 Leszek Koltunski
    long id = effects.getID();
603 a09ada4c Leszek Koltunski
    DistortedNode node;
604 efe3d8fe leszek
    boolean detached = false;
605 a09ada4c Leszek Koltunski
606 6a06a912 Leszek Koltunski
    for(int i=0; i<mNumChildren[0]; i++)
607
      {
608
      node = mChildren.get(i);
609 a09ada4c Leszek Koltunski
610 efe3d8fe leszek
      if( node.getEffects().getID()==id )
611 6a06a912 Leszek Koltunski
        {
612 efe3d8fe leszek
        detached = true;
613 ffbe7ecf Leszek Koltunski
        mJobs.add(new Job(DETACH,node));
614 efe3d8fe leszek
        DistortedMaster.newSlave(this);
615 c204c69d leszek
        break;
616 6a06a912 Leszek Koltunski
        }
617
      }
618 8baa1fe6 Leszek Koltunski
619
    if( !detached )
620
      {
621
      // if we failed to detach any, it still might be the case that
622 efe3d8fe leszek
      // there's an ATTACH job that we need to cancel.
623
      int num = mJobs.size();
624
      Job job;
625 a09ada4c Leszek Koltunski
626 efe3d8fe leszek
      for(int i=0; i<num; i++)
627
        {
628
        job = mJobs.get(i);
629
630
        if( job.type==ATTACH && job.node.getEffects()==effects )
631
          {
632
          mJobs.remove(i);
633
          break;
634
          }
635
        }
636 6a06a912 Leszek Koltunski
      }
637 c204c69d leszek
    }
638
639
///////////////////////////////////////////////////////////////////////////////////////////////////
640
/**
641
 * Removes all children Nodes.
642
 * <p>
643
 * We cannot do this mid-render - actual detachment will be done just before the next render, by the
644 efe3d8fe leszek
 * DistortedMaster (by calling doWork())
645 c204c69d leszek
 */
646
  public void detachAll()
647
    {
648 ffbe7ecf Leszek Koltunski
    mJobs.add(new Job(DETALL,null));
649 efe3d8fe leszek
    DistortedMaster.newSlave(this);
650 c204c69d leszek
    }
651
652
///////////////////////////////////////////////////////////////////////////////////////////////////
653
/**
654
 * This is not really part of the public API. Has to be public only because it is a part of the
655 efe3d8fe leszek
 * DistortedSlave interface, which should really be a class that we extend here instead but
656 c204c69d leszek
 * Java has no multiple inheritance.
657 d3725071 Leszek Koltunski
 *
658
 * @y.exclude
659 c204c69d leszek
 */
660 efe3d8fe leszek
  public void doWork()
661 c204c69d leszek
    {
662 efe3d8fe leszek
    int num = mJobs.size();
663
    Job job;
664
665
    int numChanges=0;
666
667
    for(int i=0; i<num; i++)
668 6a06a912 Leszek Koltunski
      {
669 efe3d8fe leszek
      job = mJobs.remove(0);
670 af27df87 leszek
671 efe3d8fe leszek
      switch(job.type)
672 af27df87 leszek
        {
673 efe3d8fe leszek
        case ATTACH: numChanges++;
674
                     if( mChildren==null ) mChildren = new ArrayList<>(2);
675
                     job.node.mParent = this;
676 be60d4ff leszek
                     job.node.mSurfaceParent = null;
677 85bfeb7a Leszek Koltunski
                     DistortedMaster.addSortingByBuckets(mChildren,job.node);
678 efe3d8fe leszek
                     mNumChildren[0]++;
679
                     break;
680
        case DETACH: numChanges++;
681
                     if( mNumChildren[0]>0 && mChildren.remove(job.node) )
682
                       {
683
                       job.node.mParent = null;
684 be60d4ff leszek
                       job.node.mSurfaceParent = null;
685 efe3d8fe leszek
                       mNumChildren[0]--;
686
                       }
687
                     break;
688
        case DETALL: numChanges++;
689
                     if( mNumChildren[0]>0 )
690
                       {
691
                       DistortedNode tmp;
692
693
                       for(int j=mNumChildren[0]-1; j>=0; j--)
694
                         {
695
                         tmp = mChildren.remove(j);
696
                         tmp.mParent = null;
697 be60d4ff leszek
                         tmp.mSurfaceParent = null;
698 efe3d8fe leszek
                         }
699
700
                       mNumChildren[0] = 0;
701
                       }
702
                     break;
703 ffbe7ecf Leszek Koltunski
        case SORT  : mChildren.remove(job.node);
704 85bfeb7a Leszek Koltunski
                     DistortedMaster.addSortingByBuckets(mChildren,job.node);
705 efe3d8fe leszek
                     break;
706 af27df87 leszek
        }
707 efe3d8fe leszek
      }
708 f28fffc2 Leszek Koltunski
709 be60d4ff leszek
    if( numChanges>0 ) adjustIsomorphism();
710 6a06a912 Leszek Koltunski
    }
711 13687207 leszek
712 27f42cd6 leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
713 6a06a912 Leszek Koltunski
/**
714 421c2728 Leszek Koltunski
 * Returns the DistortedEffects object that's in the Node.
715 6a06a912 Leszek Koltunski
 * 
716 421c2728 Leszek Koltunski
 * @return The DistortedEffects contained in the Node.
717 6a06a912 Leszek Koltunski
 */
718 421c2728 Leszek Koltunski
  public DistortedEffects getEffects()
719 6a06a912 Leszek Koltunski
    {
720 07d8ef09 Leszek Koltunski
    return mEffects;
721 4e2382f3 Leszek Koltunski
    }
722
723
///////////////////////////////////////////////////////////////////////////////////////////////////
724
/**
725 a13dde77 Leszek Koltunski
 * Returns the DistortedSurface object that's in the Node.
726 4e2382f3 Leszek Koltunski
 *
727 a13dde77 Leszek Koltunski
 * @return The DistortedSurface contained in the Node.
728 4e2382f3 Leszek Koltunski
 */
729 12f9e4bb Leszek Koltunski
  public DistortedSurface getSurface()
730 4e2382f3 Leszek Koltunski
    {
731 c5369f1b leszek
    return mSurface;
732 6a06a912 Leszek Koltunski
    }
733
734 a13dde77 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
735
  /**
736
   * Returns the DistortedSurface object that's in the Node.
737
   *
738
   * @return The DistortedSurface contained in the Node (if a leaf), or the FBO (if an internal Node)
739
   */
740
  public DistortedSurface getInternalSurface()
741
    {
742
    return mNumChildren[0]==0 ? mSurface : mData.mFBO;
743
    }
744
745 f1a82766 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
746
/**
747
 * Returns the Mesh object that's in the Node.
748
 *
749
 * @return Mesh contained in the Node.
750
 */
751 715e7726 Leszek Koltunski
  public MeshBase getMesh()
752 f1a82766 Leszek Koltunski
    {
753
    return mMesh;
754
    }
755
756 8c327653 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
757
/**
758 23eecbd9 Leszek Koltunski
 * Resizes the DistortedFramebuffer object that we render this Node to.
759 8c327653 Leszek Koltunski
 */
760 23eecbd9 Leszek Koltunski
  public void resize(int width, int height)
761 8c327653 Leszek Koltunski
    {
762 23eecbd9 Leszek Koltunski
    mFboW = width;
763
    mFboH = height;
764
765
    if ( mData.mFBO !=null )
766
      {
767
      // TODO: potentially allocate a new NodeData if we have to
768
      mData.mFBO.resize(width,height);
769
      }
770
    }
771
772
///////////////////////////////////////////////////////////////////////////////////////////////////
773
/**
774
 * Enables/disables DEPTH and STENCIL buffers in the Framebuffer object that we render this Node to.
775
 */
776
  public void enableDepthStencil(int depthStencil)
777
    {
778
    mFboDepthStencil = depthStencil;
779
780
    if ( mData.mFBO !=null )
781
      {
782
      // TODO: potentially allocate a new NodeData if we have to
783
      mData.mFBO.enableDepthStencil(depthStencil);
784
      }
785 8c327653 Leszek Koltunski
    }
786 6a06a912 Leszek Koltunski
787 ad16ed3b Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
788
// APIs that control how to set the OpenGL state just before rendering this Node.
789 c834348d leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
790
/**
791
 * When rendering this Node, use ColorMask (r,g,b,a).
792
 *
793
 * @param r Write to the RED color channel when rendering this Node?
794
 * @param g Write to the GREEN color channel when rendering this Node?
795
 * @param b Write to the BLUE color channel when rendering this Node?
796
 * @param a Write to the ALPHA channel when rendering this Node?
797
 */
798 13687207 leszek
  @SuppressWarnings("unused")
799 c834348d leszek
  public void glColorMask(boolean r, boolean g, boolean b, boolean a)
800
    {
801
    mState.glColorMask(r,g,b,a);
802
    }
803
804
///////////////////////////////////////////////////////////////////////////////////////////////////
805
/**
806
 * When rendering this Node, switch on writing to Depth buffer?
807
 *
808
 * @param mask Write to the Depth buffer when rendering this Node?
809
 */
810 13687207 leszek
  @SuppressWarnings("unused")
811 c834348d leszek
  public void glDepthMask(boolean mask)
812
    {
813
    mState.glDepthMask(mask);
814
    }
815
816
///////////////////////////////////////////////////////////////////////////////////////////////////
817
/**
818
 * When rendering this Node, which bits of the Stencil buffer to write to?
819
 *
820
 * @param mask Marks the bits of the Stencil buffer we will write to when rendering this Node.
821
 */
822 13687207 leszek
  @SuppressWarnings("unused")
823 c834348d leszek
  public void glStencilMask(int mask)
824
    {
825
    mState.glStencilMask(mask);
826
    }
827
828
///////////////////////////////////////////////////////////////////////////////////////////////////
829
/**
830
 * When rendering this Node, which Tests to enable?
831
 *
832
 * @param test Valid values: GL_DEPTH_TEST, GL_STENCIL_TEST, GL_BLEND
833
 */
834 13687207 leszek
  @SuppressWarnings("unused")
835 c834348d leszek
  public void glEnable(int test)
836
    {
837
    mState.glEnable(test);
838
    }
839
840
///////////////////////////////////////////////////////////////////////////////////////////////////
841
/**
842
 * When rendering this Node, which Tests to enable?
843
 *
844
 * @param test Valid values: GL_DEPTH_TEST, GL_STENCIL_TEST, GL_BLEND
845
 */
846 13687207 leszek
  @SuppressWarnings("unused")
847 c834348d leszek
  public void glDisable(int test)
848
    {
849
    mState.glDisable(test);
850
    }
851
852
///////////////////////////////////////////////////////////////////////////////////////////////////
853
/**
854
 * When rendering this Node, use the following StencilFunc.
855
 *
856
 * @param func Valid values: GL_NEVER, GL_ALWAYS, GL_LESS, GL_LEQUAL, GL_EQUAL, GL_GEQUAL, GL_GREATER, GL_NOTEQUAL
857
 * @param ref  Reference valut to compare our stencil with.
858
 * @param mask Mask used when comparing.
859
 */
860 13687207 leszek
  @SuppressWarnings("unused")
861 c834348d leszek
  public void glStencilFunc(int func, int ref, int mask)
862
    {
863
    mState.glStencilFunc(func,ref,mask);
864
    }
865
866
///////////////////////////////////////////////////////////////////////////////////////////////////
867
/**
868
 * When rendering this Node, use the following StencilOp.
869
 * <p>
870
 * Valid values of all 3 parameters: GL_KEEP, GL_ZERO, GL_REPLACE, GL_INCR, GL_DECR, GL_INVERT, GL_INCR_WRAP, GL_DECR_WRAP
871
 *
872
 * @param sfail  What to do when Stencil Test fails.
873
 * @param dpfail What to do when Depth Test fails.
874
 * @param dppass What to do when Depth Test passes.
875
 */
876 13687207 leszek
  @SuppressWarnings("unused")
877 c834348d leszek
  public void glStencilOp(int sfail, int dpfail, int dppass)
878
    {
879
    mState.glStencilOp(sfail,dpfail,dppass);
880
    }
881
882
///////////////////////////////////////////////////////////////////////////////////////////////////
883
/**
884
 * When rendering this Node, use the following DepthFunc.
885
 *
886
 * @param func Valid values: GL_NEVER, GL_ALWAYS, GL_LESS, GL_LEQUAL, GL_EQUAL, GL_GEQUAL, GL_GREATER, GL_NOTEQUAL
887
 */
888 13687207 leszek
  @SuppressWarnings("unused")
889 c834348d leszek
  public void glDepthFunc(int func)
890
    {
891
    mState.glDepthFunc(func);
892
    }
893
894
///////////////////////////////////////////////////////////////////////////////////////////////////
895
/**
896
 * When rendering this Node, use the following Blending mode.
897
 * <p>
898
 * Valid values: GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
899
 *               GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_COLOR,
900
 *               GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA, GL_SRC_ALPHA_SATURATE
901
 *
902
 * @param src Source Blend function
903
 * @param dst Destination Blend function
904
 */
905 13687207 leszek
  @SuppressWarnings("unused")
906 c834348d leszek
  public void glBlendFunc(int src, int dst)
907
    {
908
    mState.glBlendFunc(src,dst);
909
    }
910 ad16ed3b Leszek Koltunski
911
///////////////////////////////////////////////////////////////////////////////////////////////////
912
/**
913
 * Before rendering this Node, clear the following buffers.
914
 * <p>
915
 * Valid values: 0, or bitwise OR of one or more values from the set GL_COLOR_BUFFER_BIT,
916
 *               GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT.
917
 * Default: 0
918
 *
919
 * @param mask bitwise OR of BUFFER_BITs to clear.
920
 */
921
  @SuppressWarnings("unused")
922
  public void glClear(int mask)
923
    {
924
    mState.glClear(mask);
925
    }
926 8c327653 Leszek Koltunski
  }