Project

General

Profile

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

library / src / main / java / org / distorted / library / main / DistortedNode.java @ 7a5e538a

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 7a5e538a Leszek Koltunski
361
  EffectQueuePostprocess getPostprocessQueue()
362 70b6a155 Leszek Koltunski
    {
363
    return mEffects.getPostprocess();
364
    }
365
366 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
367
// PUBLIC API
368
///////////////////////////////////////////////////////////////////////////////////////////////////
369
/**
370 a09ada4c Leszek Koltunski
 * Constructs new Node.
371 6a06a912 Leszek Koltunski
 *     
372 c5369f1b leszek
 * @param surface InputSurface to put into the new Node.
373 07d8ef09 Leszek Koltunski
 * @param effects DistortedEffects to put into the new Node.
374 715e7726 Leszek Koltunski
 * @param mesh MeshBase to put into the new Node.
375 6a06a912 Leszek Koltunski
 */
376 715e7726 Leszek Koltunski
  public DistortedNode(DistortedSurface surface, DistortedEffects effects, MeshBase mesh)
377 6a06a912 Leszek Koltunski
    {
378 c5369f1b leszek
    mSurface       = surface;
379 8ca9f899 Leszek Koltunski
    mEffects       = effects;
380
    mMesh          = mesh;
381 c834348d leszek
    mState         = new DistortedRenderState();
382 8ca9f899 Leszek Koltunski
    mChildren      = null;
383
    mNumChildren   = new int[1];
384
    mNumChildren[0]= 0;
385 f28fffc2 Leszek Koltunski
    mParent        = null;
386 be60d4ff leszek
    mSurfaceParent = null;
387 406e2f6b Leszek Koltunski
    mRenderWayOIT  = false;
388 f28fffc2 Leszek Koltunski
389 23eecbd9 Leszek Koltunski
    mFboW            = 0;  // i.e. take this from
390
    mFboH            = 0;  // mSurface's dimensions
391
    mFboDepthStencil = DistortedFramebuffer.DEPTH_NO_STENCIL;
392
393 9361b337 Leszek Koltunski
    ArrayList<Long> list = new ArrayList<>();
394 c5369f1b leszek
    list.add(mSurface.getID());
395 7691a39f leszek
    list.add(-mEffects.getID());
396 1942537e Leszek Koltunski
397 6a06a912 Leszek Koltunski
    mData = mMapNodeID.get(list);
398
   
399
    if( mData!=null )
400
      {
401
      mData.numPointingNodes++;
402
      }
403
    else
404
      {
405 af27df87 leszek
      mData = new NodeData(++mNextNodeID,list);
406 1942537e Leszek Koltunski
      mMapNodeID.put(list, mData);
407 6a06a912 Leszek Koltunski
      }
408 26a4e5f6 leszek
409
    mEffects.newNode(this);
410 6a06a912 Leszek Koltunski
    }
411
412
///////////////////////////////////////////////////////////////////////////////////////////////////  
413
/**
414 a09ada4c Leszek Koltunski
 * Copy-constructs new Node from another Node.
415 6a06a912 Leszek Koltunski
 *     
416 a09ada4c Leszek Koltunski
 * @param node The DistortedNode to copy data from.
417 6a06a912 Leszek Koltunski
 * @param flags bit field composed of a subset of the following:
418 29a06526 Leszek Koltunski
 *        {@link Distorted#CLONE_SURFACE},  {@link Distorted#CLONE_MATRIX}, {@link Distorted#CLONE_VERTEX},
419 6a06a912 Leszek Koltunski
 *        {@link Distorted#CLONE_FRAGMENT} and {@link Distorted#CLONE_CHILDREN}.
420 29a06526 Leszek Koltunski
 *        For example flags = CLONE_SURFACE | CLONE_CHILDREN.
421 6a06a912 Leszek Koltunski
 */
422 a09ada4c Leszek Koltunski
  public DistortedNode(DistortedNode node, int flags)
423 6a06a912 Leszek Koltunski
    {
424 be60d4ff leszek
    mEffects      = new DistortedEffects(node.mEffects,flags);
425
    mMesh         = node.mMesh;
426
    mState        = new DistortedRenderState();
427
    mParent       = null;
428
    mSurfaceParent= null;
429 406e2f6b Leszek Koltunski
    mRenderWayOIT = false;
430 9361b337 Leszek Koltunski
431 23eecbd9 Leszek Koltunski
    mFboW            = node.mFboW;
432
    mFboH            = node.mFboH;
433
    mFboDepthStencil = node.mFboDepthStencil;
434
435 29a06526 Leszek Koltunski
    if( (flags & Distorted.CLONE_SURFACE) != 0 )
436 e7a20702 Leszek Koltunski
      {
437 c5369f1b leszek
      mSurface = node.mSurface;
438 e7a20702 Leszek Koltunski
      }
439
    else
440
      {
441 c5369f1b leszek
      int w = node.mSurface.getWidth();
442
      int h = node.mSurface.getHeight();
443 8ca9f899 Leszek Koltunski
444 c5369f1b leszek
      if( node.mSurface instanceof DistortedTexture )
445 8ca9f899 Leszek Koltunski
        {
446 09ab7524 Leszek Koltunski
        mSurface = new DistortedTexture(w,h, DistortedSurface.TYPE_TREE);
447 8ca9f899 Leszek Koltunski
        }
448 c5369f1b leszek
      else if( node.mSurface instanceof DistortedFramebuffer )
449 8ca9f899 Leszek Koltunski
        {
450 23eecbd9 Leszek Koltunski
        int depthStencil = DistortedFramebuffer.NO_DEPTH_NO_STENCIL;
451 89de975c leszek
452
        if( ((DistortedFramebuffer) node.mSurface).hasDepth() )
453
          {
454
          boolean hasStencil = ((DistortedFramebuffer) node.mSurface).hasStencil();
455
          depthStencil = (hasStencil ? DistortedFramebuffer.BOTH_DEPTH_STENCIL:DistortedFramebuffer.DEPTH_NO_STENCIL);
456
          }
457
458 9ed80185 Leszek Koltunski
        mSurface = new DistortedFramebuffer(1,depthStencil,DistortedSurface.TYPE_TREE,w,h);
459 8ca9f899 Leszek Koltunski
        }
460 e7a20702 Leszek Koltunski
      }
461 9361b337 Leszek Koltunski
    if( (flags & Distorted.CLONE_CHILDREN) != 0 )
462 6a06a912 Leszek Koltunski
      {
463 c204c69d leszek
      if( node.mChildren==null )     // do NOT copy over the NULL!
464
        {
465
        node.mChildren = new ArrayList<>(2);
466
        }
467
468 6a06a912 Leszek Koltunski
      mChildren = node.mChildren;
469
      mNumChildren = node.mNumChildren;
470
      }
471
    else
472
      {
473
      mChildren = null;
474
      mNumChildren = new int[1];
475
      mNumChildren[0] = 0;
476
      }
477
   
478
    ArrayList<Long> list = generateIDList();
479
   
480
    mData = mMapNodeID.get(list);
481
   
482
    if( mData!=null )
483
      {
484
      mData.numPointingNodes++;
485
      }
486
    else
487
      {
488 af27df87 leszek
      mData = new NodeData(++mNextNodeID,list);
489 6a06a912 Leszek Koltunski
      mMapNodeID.put(list, mData);
490
      }
491 26a4e5f6 leszek
492
    mEffects.newNode(this);
493 6a06a912 Leszek Koltunski
    }
494 c204c69d leszek
495 406e2f6b Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
496
  /**
497
   * When rendering this Node, should we use the Order Independent Transparency render more?
498
   * <p>
499
   * There are two modes of rendering: the fast 'normal' way, which however renders transparent
500
   * fragments in different ways depending on which fragments get rendered first, or the slower
501
   * 'oit' way, which renders transparent fragments correctly regardless of their order.
502
   *
503
   * @param oit True if we want to render more slowly, but in a way which accounts for transparency.
504
   */
505
  public void setOrderIndependentTransparency(boolean oit)
506
    {
507
    mRenderWayOIT = oit;
508
    }
509
510 12f9e4bb Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
511
  /**
512
   * When rendering this Node, should we use the Order Independent Transparency render more?
513
   * <p>
514
   * There are two modes of rendering: the fast 'normal' way, which however renders transparent
515
   * fragments in different ways depending on which fragments get rendered first, or the slower
516
   * 'oit' way, which renders transparent fragments correctly regardless of their order.
517
   *
518
   * @param oit True if we want to render more slowly, but in a way which accounts for transparency.
519
   * @param initialSize Initial number of transparent fragments we expect, in screenfulls.
520
   *                    I.e '1.0' means 'the scene we are going to render contains about 1 screen
521
   *                    worth of transparent fragments'. Valid values: 0.0 &lt; initialSize &lt; 10.0
522
   *                    Even if you get this wrong, the library will detect that there are more
523
   *                    transparent fragments than it has space for and readjust its internal buffers,
524
   *                    but only after a few frames during which one will probably see missing objects.
525
   */
526
  public void setOrderIndependentTransparency(boolean oit, float initialSize)
527
    {
528
    mRenderWayOIT = oit;
529
530
    if( initialSize>0.0f && initialSize<10.0f )
531
      DistortedEffects.setSSBOSize(initialSize);
532
    }
533
534 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
535
/**
536
 * Adds a new child to the last position in the list of our Node's children.
537 c204c69d leszek
 * <p>
538
 * We cannot do this mid-render - actual attachment will be done just before the next render, by the
539 efe3d8fe leszek
 * DistortedMaster (by calling doWork())
540 c204c69d leszek
 *
541 6a06a912 Leszek Koltunski
 * @param node The new Node to add.
542
 */
543 c204c69d leszek
  public void attach(DistortedNode node)
544 6a06a912 Leszek Koltunski
    {
545 ffbe7ecf Leszek Koltunski
    mJobs.add(new Job(ATTACH,node));
546 efe3d8fe leszek
    DistortedMaster.newSlave(this);
547 6a06a912 Leszek Koltunski
    }
548 c204c69d leszek
549 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
550
/**
551
 * Adds a new child to the last position in the list of our Node's children.
552 c204c69d leszek
 * <p>
553
 * We cannot do this mid-render - actual attachment will be done just before the next render, by the
554 efe3d8fe leszek
 * DistortedMaster (by calling doWork())
555 c204c69d leszek
 *
556 c5369f1b leszek
 * @param surface InputSurface to initialize our child Node with.
557 07d8ef09 Leszek Koltunski
 * @param effects DistortedEffects to initialize our child Node with.
558 715e7726 Leszek Koltunski
 * @param mesh MeshBase to initialize our child Node with.
559 6a06a912 Leszek Koltunski
 * @return the newly constructed child Node, or null if we couldn't allocate resources.
560
 */
561 715e7726 Leszek Koltunski
  public DistortedNode attach(DistortedSurface surface, DistortedEffects effects, MeshBase mesh)
562 6a06a912 Leszek Koltunski
    {
563 c204c69d leszek
    DistortedNode node = new DistortedNode(surface,effects,mesh);
564 ffbe7ecf Leszek Koltunski
    mJobs.add(new Job(ATTACH,node));
565 efe3d8fe leszek
    DistortedMaster.newSlave(this);
566 c204c69d leszek
    return node;
567
    }
568 f8377ef8 leszek
569 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
570
/**
571
 * Removes the first occurrence of a specified child from the list of children of our Node.
572 c204c69d leszek
 * <p>
573
 * We cannot do this mid-render - actual detachment will be done just before the next render, by the
574 efe3d8fe leszek
 * DistortedMaster (by calling doWork())
575 c204c69d leszek
 *
576 6a06a912 Leszek Koltunski
 * @param node The Node to remove.
577
 */
578 c204c69d leszek
  public void detach(DistortedNode node)
579 6a06a912 Leszek Koltunski
    {
580 ffbe7ecf Leszek Koltunski
    mJobs.add(new Job(DETACH,node));
581 efe3d8fe leszek
    DistortedMaster.newSlave(this);
582 6a06a912 Leszek Koltunski
    }
583 a09ada4c Leszek Koltunski
584 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
585
/**
586
 * Removes the first occurrence of a specified child from the list of children of our Node.
587 a09ada4c Leszek Koltunski
 * <p>
588
 * A bit questionable method as there can be many different Nodes attached as children, some
589
 * of them having the same Effects but - for instance - different Mesh. Use with care.
590 c204c69d leszek
 * <p>
591
 * We cannot do this mid-render - actual detachment will be done just before the next render, by the
592 efe3d8fe leszek
 * DistortedMaster (by calling doWork())
593 a09ada4c Leszek Koltunski
 *
594 07d8ef09 Leszek Koltunski
 * @param effects DistortedEffects to remove.
595 6a06a912 Leszek Koltunski
 */
596 c204c69d leszek
  public void detach(DistortedEffects effects)
597 6a06a912 Leszek Koltunski
    {
598 07d8ef09 Leszek Koltunski
    long id = effects.getID();
599 a09ada4c Leszek Koltunski
    DistortedNode node;
600 efe3d8fe leszek
    boolean detached = false;
601 a09ada4c Leszek Koltunski
602 6a06a912 Leszek Koltunski
    for(int i=0; i<mNumChildren[0]; i++)
603
      {
604
      node = mChildren.get(i);
605 a09ada4c Leszek Koltunski
606 efe3d8fe leszek
      if( node.getEffects().getID()==id )
607 6a06a912 Leszek Koltunski
        {
608 efe3d8fe leszek
        detached = true;
609 ffbe7ecf Leszek Koltunski
        mJobs.add(new Job(DETACH,node));
610 efe3d8fe leszek
        DistortedMaster.newSlave(this);
611 c204c69d leszek
        break;
612 6a06a912 Leszek Koltunski
        }
613
      }
614 8baa1fe6 Leszek Koltunski
615
    if( !detached )
616
      {
617
      // if we failed to detach any, it still might be the case that
618 efe3d8fe leszek
      // there's an ATTACH job that we need to cancel.
619
      int num = mJobs.size();
620
      Job job;
621 a09ada4c Leszek Koltunski
622 efe3d8fe leszek
      for(int i=0; i<num; i++)
623
        {
624
        job = mJobs.get(i);
625
626
        if( job.type==ATTACH && job.node.getEffects()==effects )
627
          {
628
          mJobs.remove(i);
629
          break;
630
          }
631
        }
632 6a06a912 Leszek Koltunski
      }
633 c204c69d leszek
    }
634
635
///////////////////////////////////////////////////////////////////////////////////////////////////
636
/**
637
 * Removes all children Nodes.
638
 * <p>
639
 * We cannot do this mid-render - actual detachment will be done just before the next render, by the
640 efe3d8fe leszek
 * DistortedMaster (by calling doWork())
641 c204c69d leszek
 */
642
  public void detachAll()
643
    {
644 ffbe7ecf Leszek Koltunski
    mJobs.add(new Job(DETALL,null));
645 efe3d8fe leszek
    DistortedMaster.newSlave(this);
646 c204c69d leszek
    }
647
648
///////////////////////////////////////////////////////////////////////////////////////////////////
649
/**
650
 * This is not really part of the public API. Has to be public only because it is a part of the
651 efe3d8fe leszek
 * DistortedSlave interface, which should really be a class that we extend here instead but
652 c204c69d leszek
 * Java has no multiple inheritance.
653 d3725071 Leszek Koltunski
 *
654
 * @y.exclude
655 c204c69d leszek
 */
656 efe3d8fe leszek
  public void doWork()
657 c204c69d leszek
    {
658 efe3d8fe leszek
    int num = mJobs.size();
659
    Job job;
660
661
    int numChanges=0;
662
663
    for(int i=0; i<num; i++)
664 6a06a912 Leszek Koltunski
      {
665 efe3d8fe leszek
      job = mJobs.remove(0);
666 af27df87 leszek
667 efe3d8fe leszek
      switch(job.type)
668 af27df87 leszek
        {
669 efe3d8fe leszek
        case ATTACH: numChanges++;
670
                     if( mChildren==null ) mChildren = new ArrayList<>(2);
671
                     job.node.mParent = this;
672 be60d4ff leszek
                     job.node.mSurfaceParent = null;
673 85bfeb7a Leszek Koltunski
                     DistortedMaster.addSortingByBuckets(mChildren,job.node);
674 efe3d8fe leszek
                     mNumChildren[0]++;
675
                     break;
676
        case DETACH: numChanges++;
677
                     if( mNumChildren[0]>0 && mChildren.remove(job.node) )
678
                       {
679
                       job.node.mParent = null;
680 be60d4ff leszek
                       job.node.mSurfaceParent = null;
681 efe3d8fe leszek
                       mNumChildren[0]--;
682
                       }
683
                     break;
684
        case DETALL: numChanges++;
685
                     if( mNumChildren[0]>0 )
686
                       {
687
                       DistortedNode tmp;
688
689
                       for(int j=mNumChildren[0]-1; j>=0; j--)
690
                         {
691
                         tmp = mChildren.remove(j);
692
                         tmp.mParent = null;
693 be60d4ff leszek
                         tmp.mSurfaceParent = null;
694 efe3d8fe leszek
                         }
695
696
                       mNumChildren[0] = 0;
697
                       }
698
                     break;
699 ffbe7ecf Leszek Koltunski
        case SORT  : mChildren.remove(job.node);
700 85bfeb7a Leszek Koltunski
                     DistortedMaster.addSortingByBuckets(mChildren,job.node);
701 efe3d8fe leszek
                     break;
702 af27df87 leszek
        }
703 efe3d8fe leszek
      }
704 f28fffc2 Leszek Koltunski
705 be60d4ff leszek
    if( numChanges>0 ) adjustIsomorphism();
706 6a06a912 Leszek Koltunski
    }
707 13687207 leszek
708 27f42cd6 leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
709 6a06a912 Leszek Koltunski
/**
710 421c2728 Leszek Koltunski
 * Returns the DistortedEffects object that's in the Node.
711 6a06a912 Leszek Koltunski
 * 
712 421c2728 Leszek Koltunski
 * @return The DistortedEffects contained in the Node.
713 6a06a912 Leszek Koltunski
 */
714 421c2728 Leszek Koltunski
  public DistortedEffects getEffects()
715 6a06a912 Leszek Koltunski
    {
716 07d8ef09 Leszek Koltunski
    return mEffects;
717 4e2382f3 Leszek Koltunski
    }
718
719
///////////////////////////////////////////////////////////////////////////////////////////////////
720
/**
721 a13dde77 Leszek Koltunski
 * Returns the DistortedSurface object that's in the Node.
722 4e2382f3 Leszek Koltunski
 *
723 a13dde77 Leszek Koltunski
 * @return The DistortedSurface contained in the Node.
724 4e2382f3 Leszek Koltunski
 */
725 12f9e4bb Leszek Koltunski
  public DistortedSurface getSurface()
726 4e2382f3 Leszek Koltunski
    {
727 c5369f1b leszek
    return mSurface;
728 6a06a912 Leszek Koltunski
    }
729
730 a13dde77 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
731
  /**
732
   * Returns the DistortedSurface object that's in the Node.
733
   *
734
   * @return The DistortedSurface contained in the Node (if a leaf), or the FBO (if an internal Node)
735
   */
736
  public DistortedSurface getInternalSurface()
737
    {
738
    return mNumChildren[0]==0 ? mSurface : mData.mFBO;
739
    }
740
741 f1a82766 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
742
/**
743
 * Returns the Mesh object that's in the Node.
744
 *
745
 * @return Mesh contained in the Node.
746
 */
747 715e7726 Leszek Koltunski
  public MeshBase getMesh()
748 f1a82766 Leszek Koltunski
    {
749
    return mMesh;
750
    }
751
752 8c327653 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
753
/**
754 23eecbd9 Leszek Koltunski
 * Resizes the DistortedFramebuffer object that we render this Node to.
755 8c327653 Leszek Koltunski
 */
756 23eecbd9 Leszek Koltunski
  public void resize(int width, int height)
757 8c327653 Leszek Koltunski
    {
758 23eecbd9 Leszek Koltunski
    mFboW = width;
759
    mFboH = height;
760
761
    if ( mData.mFBO !=null )
762
      {
763
      // TODO: potentially allocate a new NodeData if we have to
764
      mData.mFBO.resize(width,height);
765
      }
766
    }
767
768
///////////////////////////////////////////////////////////////////////////////////////////////////
769
/**
770
 * Enables/disables DEPTH and STENCIL buffers in the Framebuffer object that we render this Node to.
771
 */
772
  public void enableDepthStencil(int depthStencil)
773
    {
774
    mFboDepthStencil = depthStencil;
775
776
    if ( mData.mFBO !=null )
777
      {
778
      // TODO: potentially allocate a new NodeData if we have to
779
      mData.mFBO.enableDepthStencil(depthStencil);
780
      }
781 8c327653 Leszek Koltunski
    }
782 6a06a912 Leszek Koltunski
783 ad16ed3b Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
784
// APIs that control how to set the OpenGL state just before rendering this Node.
785 c834348d leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
786
/**
787
 * When rendering this Node, use ColorMask (r,g,b,a).
788
 *
789
 * @param r Write to the RED color channel when rendering this Node?
790
 * @param g Write to the GREEN color channel when rendering this Node?
791
 * @param b Write to the BLUE color channel when rendering this Node?
792
 * @param a Write to the ALPHA channel when rendering this Node?
793
 */
794 13687207 leszek
  @SuppressWarnings("unused")
795 c834348d leszek
  public void glColorMask(boolean r, boolean g, boolean b, boolean a)
796
    {
797
    mState.glColorMask(r,g,b,a);
798
    }
799
800
///////////////////////////////////////////////////////////////////////////////////////////////////
801
/**
802
 * When rendering this Node, switch on writing to Depth buffer?
803
 *
804
 * @param mask Write to the Depth buffer when rendering this Node?
805
 */
806 13687207 leszek
  @SuppressWarnings("unused")
807 c834348d leszek
  public void glDepthMask(boolean mask)
808
    {
809
    mState.glDepthMask(mask);
810
    }
811
812
///////////////////////////////////////////////////////////////////////////////////////////////////
813
/**
814
 * When rendering this Node, which bits of the Stencil buffer to write to?
815
 *
816
 * @param mask Marks the bits of the Stencil buffer we will write to when rendering this Node.
817
 */
818 13687207 leszek
  @SuppressWarnings("unused")
819 c834348d leszek
  public void glStencilMask(int mask)
820
    {
821
    mState.glStencilMask(mask);
822
    }
823
824
///////////////////////////////////////////////////////////////////////////////////////////////////
825
/**
826
 * When rendering this Node, which Tests to enable?
827
 *
828
 * @param test Valid values: GL_DEPTH_TEST, GL_STENCIL_TEST, GL_BLEND
829
 */
830 13687207 leszek
  @SuppressWarnings("unused")
831 c834348d leszek
  public void glEnable(int test)
832
    {
833
    mState.glEnable(test);
834
    }
835
836
///////////////////////////////////////////////////////////////////////////////////////////////////
837
/**
838
 * When rendering this Node, which Tests to enable?
839
 *
840
 * @param test Valid values: GL_DEPTH_TEST, GL_STENCIL_TEST, GL_BLEND
841
 */
842 13687207 leszek
  @SuppressWarnings("unused")
843 c834348d leszek
  public void glDisable(int test)
844
    {
845
    mState.glDisable(test);
846
    }
847
848
///////////////////////////////////////////////////////////////////////////////////////////////////
849
/**
850
 * When rendering this Node, use the following StencilFunc.
851
 *
852
 * @param func Valid values: GL_NEVER, GL_ALWAYS, GL_LESS, GL_LEQUAL, GL_EQUAL, GL_GEQUAL, GL_GREATER, GL_NOTEQUAL
853
 * @param ref  Reference valut to compare our stencil with.
854
 * @param mask Mask used when comparing.
855
 */
856 13687207 leszek
  @SuppressWarnings("unused")
857 c834348d leszek
  public void glStencilFunc(int func, int ref, int mask)
858
    {
859
    mState.glStencilFunc(func,ref,mask);
860
    }
861
862
///////////////////////////////////////////////////////////////////////////////////////////////////
863
/**
864
 * When rendering this Node, use the following StencilOp.
865
 * <p>
866
 * Valid values of all 3 parameters: GL_KEEP, GL_ZERO, GL_REPLACE, GL_INCR, GL_DECR, GL_INVERT, GL_INCR_WRAP, GL_DECR_WRAP
867
 *
868
 * @param sfail  What to do when Stencil Test fails.
869
 * @param dpfail What to do when Depth Test fails.
870
 * @param dppass What to do when Depth Test passes.
871
 */
872 13687207 leszek
  @SuppressWarnings("unused")
873 c834348d leszek
  public void glStencilOp(int sfail, int dpfail, int dppass)
874
    {
875
    mState.glStencilOp(sfail,dpfail,dppass);
876
    }
877
878
///////////////////////////////////////////////////////////////////////////////////////////////////
879
/**
880
 * When rendering this Node, use the following DepthFunc.
881
 *
882
 * @param func Valid values: GL_NEVER, GL_ALWAYS, GL_LESS, GL_LEQUAL, GL_EQUAL, GL_GEQUAL, GL_GREATER, GL_NOTEQUAL
883
 */
884 13687207 leszek
  @SuppressWarnings("unused")
885 c834348d leszek
  public void glDepthFunc(int func)
886
    {
887
    mState.glDepthFunc(func);
888
    }
889
890
///////////////////////////////////////////////////////////////////////////////////////////////////
891
/**
892
 * When rendering this Node, use the following Blending mode.
893
 * <p>
894
 * Valid values: GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
895
 *               GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_COLOR,
896
 *               GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA, GL_SRC_ALPHA_SATURATE
897
 *
898
 * @param src Source Blend function
899
 * @param dst Destination Blend function
900
 */
901 13687207 leszek
  @SuppressWarnings("unused")
902 c834348d leszek
  public void glBlendFunc(int src, int dst)
903
    {
904
    mState.glBlendFunc(src,dst);
905
    }
906 ad16ed3b Leszek Koltunski
907
///////////////////////////////////////////////////////////////////////////////////////////////////
908
/**
909
 * Before rendering this Node, clear the following buffers.
910
 * <p>
911
 * Valid values: 0, or bitwise OR of one or more values from the set GL_COLOR_BUFFER_BIT,
912
 *               GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT.
913
 * Default: 0
914
 *
915
 * @param mask bitwise OR of BUFFER_BITs to clear.
916
 */
917
  @SuppressWarnings("unused")
918
  public void glClear(int mask)
919
    {
920
    mState.glClear(mask);
921
    }
922 8c327653 Leszek Koltunski
  }