Project

General

Profile

« Previous | Next » 

Revision c204c69d

Added by Leszek Koltunski about 7 years ago

New, cleaner way to create/destroy DistortedSurfaces.

Serious regression in StarWars (crashes!). Looks like the Node's internal FBO is being deleted and not re-created in time.

View differences:

src/main/java/org/distorted/library/Distorted.java
138 138
    DistortedNode.onDestroy();
139 139
    EffectQueue.onDestroy();
140 140
    DistortedEffects.onDestroy();
141
    DistortedAttachDaemon.onDestroy();
141 142
    EffectMessageSender.stopSending();
142 143

  
143 144
    mInitialized = false;
src/main/java/org/distorted/library/DistortedAttachDaemon.java
1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2016 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Distorted.                                                               //
5
//                                                                                               //
6
// Distorted is free software: you can redistribute it and/or modify                             //
7
// it under the terms of the GNU General Public License as published by                          //
8
// the Free Software Foundation, either version 2 of the License, or                             //
9
// (at your option) any later version.                                                           //
10
//                                                                                               //
11
// Distorted is distributed in the hope that it will be useful,                                  //
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
14
// GNU General Public License for more details.                                                  //
15
//                                                                                               //
16
// You should have received a copy of the GNU General Public License                             //
17
// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19

  
20
package org.distorted.library;
21

  
22
import java.util.ArrayList;
23

  
24
///////////////////////////////////////////////////////////////////////////////////////////////////
25
/**
26
 * This static class handles changing topology of a Tree in a safe way. I.e. if one wants to
27
 * attach() a new Node somewhere in the Tree, we cannot simply attach it mid-render (detach() is
28
 * even worse!). What we do instead is mark that this job will have to be done and actually do it
29
 * just before the next render. That's what this Daemon does.
30
 */
31
class DistortedAttachDaemon
32
  {
33
  private static final int ATTACH    = 0; //
34
  private static final int DETACH    = 1; // types of jobs that the Daemon can do
35
  private static final int DETACHALL = 2; //
36

  
37
  private static class Job
38
    {
39
    int type;
40
    DistortedAttacheable attacheable;
41
    DistortedNode object;
42

  
43
    Job(int t, DistortedAttacheable a, DistortedNode o)
44
      {
45
      type        = t;
46
      attacheable = a;
47
      object      = o;
48
      }
49
    }
50

  
51
  private static ArrayList<Job> mJobs = new ArrayList<>();
52

  
53
///////////////////////////////////////////////////////////////////////////////////////////////////
54

  
55
  private DistortedAttachDaemon()
56
    {
57

  
58
    }
59

  
60
///////////////////////////////////////////////////////////////////////////////////////////////////
61

  
62
  static boolean toDo()
63
    {
64
    int num = mJobs.size();
65
    Job job;
66

  
67
    for(int i=0; i<num; i++)
68
      {
69
      job = mJobs.remove(0);
70

  
71
      switch(job.type)
72
        {
73
        case ATTACH   : job.attacheable.attachNow(job.object);
74
                        break;
75
        case DETACH   : job.attacheable.detachNow(job.object);
76
                        break;
77
        case DETACHALL: job.attacheable.detachAllNow()       ;
78
                        break;
79
        default       : android.util.Log.e("AttachDaemon", "what?");
80
        }
81
      }
82

  
83
    return ( num>0 );
84
    }
85

  
86
///////////////////////////////////////////////////////////////////////////////////////////////////
87

  
88
  static void attach(DistortedAttacheable a, DistortedNode n)
89
    {
90
    mJobs.add(new Job(ATTACH,a,n));
91
    }
92

  
93
///////////////////////////////////////////////////////////////////////////////////////////////////
94

  
95
  static void detach(DistortedAttacheable a, DistortedNode n)
96
    {
97
    mJobs.add(new Job(DETACH,a,n));
98
    }
99

  
100
///////////////////////////////////////////////////////////////////////////////////////////////////
101

  
102
  static void detachAll(DistortedAttacheable a)
103
    {
104
    mJobs.add(new Job(DETACHALL,a,null));
105
    }
106

  
107
///////////////////////////////////////////////////////////////////////////////////////////////////
108

  
109
  static void onDestroy()
110
    {
111
    mJobs.clear();
112
    }
113
  }
src/main/java/org/distorted/library/DistortedAttacheable.java
1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2016 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Distorted.                                                               //
5
//                                                                                               //
6
// Distorted is free software: you can redistribute it and/or modify                             //
7
// it under the terms of the GNU General Public License as published by                          //
8
// the Free Software Foundation, either version 2 of the License, or                             //
9
// (at your option) any later version.                                                           //
10
//                                                                                               //
11
// Distorted is distributed in the hope that it will be useful,                                  //
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
14
// GNU General Public License for more details.                                                  //
15
//                                                                                               //
16
// You should have received a copy of the GNU General Public License                             //
17
// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19

  
20
package org.distorted.library;
21

  
22
///////////////////////////////////////////////////////////////////////////////////////////////////
23
/**
24
 * Package-private interface implemented by all objects to which one can attach a Tree-like structure
25
 * of DistortedNodes. (Currently: DistortedNode itself and DistortedOutputSurface).
26
 * <p>
27
 * All the methods below are really meant to be package-local; and this interface should really be a
28
 * package-local class which other classes would extend (but that's impossible because OutputSurface
29
 * already extends other class).
30
 */
31
interface DistortedAttacheable
32
  {
33
  void attachNow(DistortedNode n);
34
  void detachNow(DistortedNode n);
35
  void detachAllNow();
36
  }
src/main/java/org/distorted/library/DistortedNode.java
27 27
///////////////////////////////////////////////////////////////////////////////////////////////////
28 28
/**
29 29
 * Class which represents a Node in a Tree of (InputSurface,Mesh,Effects) triplets.
30
 *  
30
 * <p>
31 31
 * Having organized such sets into a Tree, we can then render any Node to any OutputSurface.
32 32
 * That recursively renders the set held in the Node and all its children.
33
 * <p>
34
 * The class takes special care to only render identical sub-trees once. Each Node holds a reference
35
 * to sub-class 'NodeData'. Two identical sub-trees attached at different points of the main tree
36
 * will point to the same NodeData; only the first of this is rendered (when mData.numRendered==0).
33 37
 */
34
public class DistortedNode
38
public class DistortedNode implements DistortedAttacheable
35 39
  {
36 40
  private static HashMap<ArrayList<Long>,NodeData> mMapNodeID = new HashMap<>();
37 41
  private static long mNextNodeID =0;
......
41 45
  private DistortedInputSurface mSurface;
42 46
  private NodeData mData;
43 47

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

  
......
58 61
      numPointingNodes= 1;
59 62
      numRendered     = 0;
60 63
      mFBO            = null;
61

  
62
      android.util.Log.e("DistortedNode", "new NodeData");
63 64
      }
64 65
    }
65 66
 
......
71 72
    mMapNodeID.clear();
72 73
    }
73 74

  
74
///////////////////////////////////////////////////////////////////////////////////////////////////
75
// tree isomorphism
76
  
77
  private void RecomputeNodeID(ArrayList<Long> prev)
78
    {
79
    ArrayList<Long> curr = generateIDList();
80
     
81
    if( mParent==null )
82
      {
83
      adjustNodeData(prev,curr);
84
      }
85
    else
86
      {
87
      ArrayList<Long> parentPrev = mParent.generateIDList();
88
      adjustNodeData(prev,curr);
89
      mParent.RecomputeNodeID(parentPrev);
90
      }
91
    }
92

  
93 75
///////////////////////////////////////////////////////////////////////////////////////////////////
94 76

  
95 77
  private ArrayList<Long> generateIDList()
......
108 90
    return ret;
109 91
    }
110 92

  
111
///////////////////////////////////////////////////////////////////////////////////////////////////
112

  
113
  private void adjustNodeData(ArrayList<Long> oldList, ArrayList<Long> newList)
114
    {
115
    boolean otherNodesPoint = (mData.numPointingNodes>1);
116

  
117
    if( otherNodesPoint ) mData.numPointingNodes--;
118
    else                  mMapNodeID.remove(oldList);
119

  
120
    NodeData newData = mMapNodeID.get(newList);
121
    
122
    if( newData==null )
123
      {
124
      if( otherNodesPoint )  mData = new NodeData(++mNextNodeID);
125
      else                   mData.ID = ++mNextNodeID;  // numPointingNodes must be 1 already
126

  
127
      if( newList.size()>1 )
128
        {
129
        if( mData.mFBO ==null )
130
          {
131
          android.util.Log.e("DistortedNode", "creating a new FBO");
132

  
133
          mData.mFBO = new DistortedFramebuffer(mSurface.getWidth(), mSurface.getHeight());
134
          }
135
        }
136
      else
137
        {
138
        if( mData.mFBO !=null )
139
          {
140
          android.util.Log.e("DistortedNode", "marking FBO for deletion and setting it to NULL");
141

  
142
          mData.mFBO.markForDeletion();
143
          mData.mFBO = null;
144
          }
145
        else
146
          {
147
          android.util.Log.e("DistortedNode", "adjustNodeData: impossible situation??");
148
          }
149
        }
150

  
151
      mMapNodeID.put(newList, mData);
152
      }
153
    else
154
      {
155
      newData.numPointingNodes++;
156
      mData = newData;
157
      }
158
    }
159

  
160 93
///////////////////////////////////////////////////////////////////////////////////////////////////  
161 94
// this will be called on startup and every time OpenGL context has been lost
162 95

  
......
174 107

  
175 108
///////////////////////////////////////////////////////////////////////////////////////////////////
176 109
// Debug - print all the Node IDs
177
/*
110

  
178 111
  void debug(int depth)
179 112
    {
180 113
    String tmp="";
181 114
    int i;
182 115

  
183 116
    for(i=0; i<depth; i++) tmp +="   ";
184
    tmp += (mData.ID+" (nodes: "+mData.numPointingNodes+")");
117
    tmp += ("NodeID="+mData.ID+" (nodes pointing: "+mData.numPointingNodes+" surfaceID="+mSurface.getID()+")");
185 118

  
186 119
    android.util.Log.e("NODE", tmp);
187 120

  
......
199 132
    for(ArrayList<Long> key: mMapNodeID.keySet())
200 133
      {
201 134
      tmp = mMapNodeID.get(key);
135
      android.util.Log.e("NODE", "NodeID: "+tmp.ID+" <-- "+key);
136
      }
137
    }
138

  
139
///////////////////////////////////////////////////////////////////////////////////////////////////
140

  
141
  void treeIsomorphism()
142
    {
143
    android.util.Log.e("NODE", "begin treeIso for Node Surface ID="+mSurface.getID());
144
    debug(0);
145
    debugMap();
146
    android.util.Log.e("NODE", "begin treeIso for Node Surface ID="+mSurface.getID());
147

  
148
    ArrayList<Long> oldList = generateIDList();
149

  
150
    for(int i=0; i<mNumChildren[0]; i++)
151
      {
152
      mChildren.get(i).treeIsomorphism();
153
      }
154

  
155
    ArrayList<Long> newList = generateIDList();
156
    NodeData newData = mMapNodeID.get(newList);
157

  
158
    if( newData==null )
159
      {
160
      android.util.Log.d("NODE", "  inserted newData to map, newList="+newList);
161

  
162

  
163
      newData = new NodeData(++mNextNodeID);
164
      mMapNodeID.put(newList,newData);
165
      debugMap();
166
      }
167
    else if( newData.ID != mData.ID )
168
      {
169
      newData.numPointingNodes++;
170
      }
171

  
172
    if( newData.ID != mData.ID )
173
      {
174
      boolean fboUsed = false;
175

  
176
      if( mNumChildren[0]>0 && newData.mFBO==null )
177
        {
178
        if( mData.mFBO!=null )
179
          {
180
          newData.mFBO = mData.mFBO;
181
          fboUsed = true;
182
          }
183
        else
184
          {
185
          newData.mFBO = new DistortedFramebuffer(mSurface.getWidth(),mSurface.getHeight());
186
          }
187
        }
188
      if( mNumChildren[0]==0 && newData.mFBO!=null )
189
        {
190
        newData.mFBO.markForDeletion();
191
        newData.mFBO = null;
192
        }
193

  
194
      if( --mData.numPointingNodes==0 )
195
        {
196
        android.util.Log.d("NODE", "  removed oldData to map, oldList="+oldList);
197

  
202 198

  
203
      android.util.Log.e("NODE", "key="+key+" NodeID: "+tmp.ID);
199
        mMapNodeID.remove(oldList);
200
        debugMap();
201

  
202
        if( !fboUsed && mData.mFBO!=null )
203
          {
204
          mData.mFBO.markForDeletion();
205
          mData.mFBO = null;
206
          }
207
        }
208

  
209
      mData = newData;
204 210
      }
211

  
212
    android.util.Log.e("NODE", "end treeIso for Node SurfaceID="+mSurface.getID()+" newList="+newList);
213
    debug(0);
214
    debugMap();
215
    android.util.Log.e("NODE", "end treeIso for Node SurfaceID="+mSurface.getID()+" newList="+newList);
205 216
    }
206
*/
217

  
207 218
///////////////////////////////////////////////////////////////////////////////////////////////////
208 219

  
209 220
  void drawRecursive(long currTime, DistortedOutputSurface surface)
......
256 267
    mSurface       = surface;
257 268
    mEffects       = effects;
258 269
    mMesh          = mesh;
259
    mParent        = null;
260 270
    mChildren      = null;
261 271
    mNumChildren   = new int[1];
262 272
    mNumChildren[0]= 0;
......
289 299
 */
290 300
  public DistortedNode(DistortedNode node, int flags)
291 301
    {
292
    mParent = null;
293 302
    mEffects= new DistortedEffects(node.mEffects,flags);
294 303
    mMesh = node.mMesh;
295 304

  
......
314 323
      }
315 324
    if( (flags & Distorted.CLONE_CHILDREN) != 0 )
316 325
      {
326
      if( node.mChildren==null )     // do NOT copy over the NULL!
327
        {
328
        node.mChildren = new ArrayList<>(2);
329
        }
330

  
317 331
      mChildren = node.mChildren;
318 332
      mNumChildren = node.mNumChildren;
319 333
      }
......
338 352
      mMapNodeID.put(list, mData);
339 353
      }
340 354
    }
341
  
355

  
342 356
///////////////////////////////////////////////////////////////////////////////////////////////////
343 357
/**
344 358
 * Adds a new child to the last position in the list of our Node's children.
345
 * 
359
 * <p>
360
 * We cannot do this mid-render - actual attachment will be done just before the next render, by the
361
 * DistortedAttachDeamon (by calling attachNow())
362
 *
346 363
 * @param node The new Node to add.
347 364
 */
348
  public synchronized void attach(DistortedNode node)
365
  public void attach(DistortedNode node)
349 366
    {
350
    ArrayList<Long> prev = generateIDList(); 
351
   
352
    if( mChildren==null ) mChildren = new ArrayList<>(2);
353

  
354
    android.util.Log.e("DistortedNode", "ATTACH1");
355

  
356

  
357
    node.mParent = this;
358
    mChildren.add(node);
359
    mNumChildren[0]++;
360
     
361
    RecomputeNodeID(prev);
367
    DistortedAttachDaemon.attach(this,node);
362 368
    }
363
   
369

  
364 370
///////////////////////////////////////////////////////////////////////////////////////////////////
365 371
/**
366 372
 * Adds a new child to the last position in the list of our Node's children.
367
 * 
373
 * <p>
374
 * We cannot do this mid-render - actual attachment will be done just before the next render, by the
375
 * DistortedAttachDeamon (by calling attachNow())
376
 *
368 377
 * @param surface InputSurface to initialize our child Node with.
369 378
 * @param effects DistortedEffects to initialize our child Node with.
370 379
 * @param mesh MeshObject to initialize our child Node with.
371 380
 * @return the newly constructed child Node, or null if we couldn't allocate resources.
372 381
 */
373
  public synchronized DistortedNode attach(DistortedInputSurface surface, DistortedEffects effects, MeshObject mesh)
382
  public DistortedNode attach(DistortedInputSurface surface, DistortedEffects effects, MeshObject mesh)
374 383
    {
375
    ArrayList<Long> prev = generateIDList(); 
376

  
377
    android.util.Log.e("DistortedNode", "ATTACH2");
384
    DistortedNode node = new DistortedNode(surface,effects,mesh);
385
    DistortedAttachDaemon.attach(this,node);
386
    return node;
387
    }
378 388

  
389
///////////////////////////////////////////////////////////////////////////////////////////////////
390
/**
391
 * This is not really part of the public API. Has to be public only because it is a part of the
392
 * DistortedAttacheable interface, which should really be a class that we extend here instead but
393
 * Java has no multiple inheritance.
394
 *
395
 * @param node The new Node to add.
396
 */
397
  public void attachNow(DistortedNode node)
398
    {
379 399
    if( mChildren==null ) mChildren = new ArrayList<>(2);
380
    DistortedNode node = new DistortedNode(surface,effects,mesh);
381
    node.mParent = this;
400

  
382 401
    mChildren.add(node);
383 402
    mNumChildren[0]++;
384
   
385
    RecomputeNodeID(prev);
386

  
387
    return node;
388 403
    }
389
  
404

  
390 405
///////////////////////////////////////////////////////////////////////////////////////////////////
391 406
/**
392 407
 * Removes the first occurrence of a specified child from the list of children of our Node.
393
 * 
408
 * <p>
409
 * We cannot do this mid-render - actual detachment will be done just before the next render, by the
410
 * DistortedAttachDeamon (by calling detachNow())
411
 *
394 412
 * @param node The Node to remove.
395
 * @return <code>true</code> if the child was successfully removed.
396 413
 */
397
  public synchronized boolean detach(DistortedNode node)
414
  public void detach(DistortedNode node)
398 415
    {
399
    if( mNumChildren[0]>0 )
400
      {
401
      ArrayList<Long> prev = generateIDList();  
402
         
403
      if( mChildren.remove(node) )
404
        {
405
android.util.Log.e("DistortedNode", "DETACH1");
406

  
407
        node.mParent = null;
408
        mNumChildren[0]--;
409
     
410
        RecomputeNodeID(prev);
411
     
412
        return true;
413
        }
414
      }
415
   
416
    return false;
416
    DistortedAttachDaemon.detach(this,node);
417 417
    }
418 418

  
419 419
///////////////////////////////////////////////////////////////////////////////////////////////////
......
422 422
 * <p>
423 423
 * A bit questionable method as there can be many different Nodes attached as children, some
424 424
 * of them having the same Effects but - for instance - different Mesh. Use with care.
425
 * <p>
426
 * We cannot do this mid-render - actual detachment will be done just before the next render, by the
427
 * DistortedAttachDeamon (by calling detachNow())
425 428
 *
426 429
 * @param effects DistortedEffects to remove.
427
 * @return <code>true</code> if the child was successfully removed.
428 430
 */
429
  public synchronized boolean detach(DistortedEffects effects)
431
  public void detach(DistortedEffects effects)
430 432
    {
431 433
    long id = effects.getID();
432 434
    DistortedNode node;
......
437 439

  
438 440
      if( node.mEffects.getID()==id )
439 441
        {
440
android.util.Log.e("DistortedNode", "DETACH2");
441

  
442

  
443
        ArrayList<Long> prev = generateIDList();
444

  
445
        node.mParent = null;
446
        mChildren.remove(i);
447
        mNumChildren[0]--;
448

  
449
        RecomputeNodeID(prev);
450

  
451
        return true;
442
        DistortedAttachDaemon.detach(this,node);
443
        break;
452 444
        }
453 445
      }
454

  
455
    return false;
456 446
    }
457 447

  
458 448
///////////////////////////////////////////////////////////////////////////////////////////////////
459 449
/**
460
 * Removes all children Nodes.
450
 * This is not really part of the public API. Has to be public only because it is a part of the
451
 * DistortedAttacheable interface, which should really be a class that we extend here instead but
452
 * Java has no multiple inheritance.
453
 *
454
 * @param node The Node to remove.
461 455
 */
462
  public synchronized void detachAll()
456
  public void detachNow(DistortedNode node)
463 457
    {
464
    for(int i=0; i<mNumChildren[0]; i++)
458
    if( mNumChildren[0]>0 && mChildren.remove(node) )
465 459
      {
466
      mChildren.get(i).mParent = null;
460
      mNumChildren[0]--;
467 461
      }
468
   
462
    }
463

  
464
///////////////////////////////////////////////////////////////////////////////////////////////////
465
/**
466
 * Removes all children Nodes.
467
 * <p>
468
 * We cannot do this mid-render - actual detachment will be done just before the next render, by the
469
 * DistortedAttachDeamon (by calling detachAllNow())
470
 */
471
  public void detachAll()
472
    {
473
    DistortedAttachDaemon.detachAll(this);
474
    }
475

  
476
///////////////////////////////////////////////////////////////////////////////////////////////////
477
/**
478
 * This is not really part of the public API. Has to be public only because it is a part of the
479
 * DistortedAttacheable interface, which should really be a class that we extend here instead but
480
 * Java has no multiple inheritance.
481
 */
482
  public void detachAllNow()
483
    {
469 484
    if( mNumChildren[0]>0 )
470 485
      {
471
      ArrayList<Long> prev = generateIDList();  
472
      
473 486
      mNumChildren[0] = 0;
474 487
      mChildren.clear();
475
      RecomputeNodeID(prev);
476 488
      }
477 489
    }
478 490

  
src/main/java/org/distorted/library/DistortedOutputSurface.java
24 24

  
25 25
///////////////////////////////////////////////////////////////////////////////////////////////////
26 26

  
27
abstract class DistortedOutputSurface extends DistortedSurface
27
abstract class DistortedOutputSurface extends DistortedSurface implements DistortedAttacheable
28 28
{
29 29
  private ArrayList<DistortedNode> mChildren;
30 30
  private int mNumChildren;   // ==mChildren.length(), but we only create mChildren if the first one gets added
......
99 99
 */
100 100
  public void render(long time)
101 101
    {
102
    // change tree topology (attach and detach children)
103
    // create and delete all underlying OpenGL resources
104
    // Watch out: FIRST change topology, only then deal
105
    // with OpenGL resources. That's because changing Tree
106
    // can result in additional Framebuffers that would need
107
    // to be created immediately, before the calls to drawRecursive()
108

  
109
    if( DistortedAttachDaemon.toDo() )
110
      {
111
      for(int i=0; i<mNumChildren; i++)
112
        {
113
        mChildren.get(i).treeIsomorphism();
114
        }
115
      }
116

  
102 117
    toDo();
103 118

  
104 119
    for(int i=0; i<mNumChildren; i++)
......
159 174
///////////////////////////////////////////////////////////////////////////////////////////////////
160 175
/**
161 176
 * Adds a new child to the last position in the list of our Surface's children.
177
 * <p>
178
 * We cannot do this mid-render - actual attachment will be done just before the next render, by the
179
 * DistortedAttachDeamon (by calling attachNow())
162 180
 *
163 181
 * @param node The new Node to add.
164 182
 */
165
  public synchronized void attach(DistortedNode node)
183
  public void attach(DistortedNode node)
166 184
    {
167
    if( mChildren==null ) mChildren = new ArrayList<>(2);
168
    mChildren.add(node);
169
    mNumChildren++;
185
    DistortedAttachDaemon.attach(this,node);
170 186
    }
171 187

  
172 188
///////////////////////////////////////////////////////////////////////////////////////////////////
173 189
/**
174 190
 * Adds a new child to the last position in the list of our Surface's children.
191
 * <p>
192
 * We cannot do this mid-render - actual attachment will be done just before the next render, by the
193
 * DistortedAttachDeamon (by calling attachNow())
175 194
 *
176 195
 * @param surface InputSurface to initialize our child Node with.
177 196
 * @param effects DistortedEffects to initialize our child Node with.
178 197
 * @param mesh MeshObject to initialize our child Node with.
179 198
 * @return the newly constructed child Node, or null if we couldn't allocate resources.
180 199
 */
181
  public synchronized DistortedNode attach(DistortedInputSurface surface, DistortedEffects effects, MeshObject mesh)
200
  public DistortedNode attach(DistortedInputSurface surface, DistortedEffects effects, MeshObject mesh)
182 201
    {
183
    if( mChildren==null ) mChildren = new ArrayList<>(2);
184 202
    DistortedNode node = new DistortedNode(surface,effects,mesh);
203
    DistortedAttachDaemon.attach(this,node);
204
    return node;
205
    }
206

  
207
///////////////////////////////////////////////////////////////////////////////////////////////////
208
/**
209
 * This is not really part of the public API. Has to be public only because it is a part of the
210
 * DistortedAttacheable interface, which should really be a class that we extend here instead but
211
 * Java has no multiple inheritance.
212
 *
213
 * @param node new Node to add.
214
 */
215
  public void attachNow(DistortedNode node)
216
    {
217
    if( mChildren==null ) mChildren = new ArrayList<>(2);
185 218
    mChildren.add(node);
186 219
    mNumChildren++;
187

  
188
    return node;
189 220
    }
190 221

  
191 222
///////////////////////////////////////////////////////////////////////////////////////////////////
192 223
/**
193 224
 * Removes the first occurrence of a specified child from the list of children of our Surface.
225
 * <p>
226
 * We cannot do this mid-render - actual attachment will be done just before the next render, by the
227
 * DistortedAttachDeamon (by calling detachNow())
228
 *
229
 * @param node The Node to remove.
230
 */
231
  public void detach(DistortedNode node)
232
    {
233
    DistortedAttachDaemon.detach(this,node);
234
    }
235

  
236
///////////////////////////////////////////////////////////////////////////////////////////////////
237
/**
238
 * This is not really part of the public API. Has to be public only because it is a part of the
239
 * DistortedAttacheable interface, which should really be a class that we extend here instead but
240
 * Java has no multiple inheritance.
194 241
 *
195 242
 * @param node The Node to remove.
196
 * @return <code>true</code> if the child was successfully removed.
197 243
 */
198
  public synchronized boolean detach(DistortedNode node)
244
  public void detachNow(DistortedNode node)
199 245
    {
200 246
    if( mNumChildren>0 && mChildren.remove(node) )
201 247
      {
202 248
      mNumChildren--;
203
      return true;
204 249
      }
205

  
206
    return false;
207 250
    }
208 251

  
209 252
///////////////////////////////////////////////////////////////////////////////////////////////////
210 253
/**
211 254
 * Removes all children Nodes.
255
 * <p>
256
 * We cannot do this mid-render - actual attachment will be done just before the next render, by the
257
 * DistortedAttachDeamon (by calling detachAllNow())
258
 */
259
  public void detachAll()
260
    {
261
    DistortedAttachDaemon.detachAll(this);
262
    }
263

  
264
///////////////////////////////////////////////////////////////////////////////////////////////////
265
/**
266
 * This is not really part of the public API. Has to be public only because it is a part of the
267
 * DistortedAttacheable interface, which should really be a class that we extend here instead but
268
 * Java has no multiple inheritance.
212 269
 */
213
  public synchronized void detachAll()
270
  public void detachAllNow()
214 271
    {
215 272
    if( mNumChildren>0 )
216 273
      {
src/main/java/org/distorted/library/DistortedSurface.java
38 38
  private static boolean mToDo = false;
39 39
  private static LinkedList<DistortedSurface> mDoneList = new LinkedList<>();
40 40
  private static LinkedList<DistortedSurface> mToDoList = new LinkedList<>();
41
  private static long mNextID = 0;
41 42

  
43
  private long mID;
42 44
  private boolean mMarked;
43 45
  int[] mColorH = new int[1];
44 46
  int mSizeX, mSizeY;  // in screen space
......
100 102
      }
101 103

  
102 104
    mToDo = true;
105
    mNextID = 0;
103 106
    }
104 107

  
105 108
///////////////////////////////////////////////////////////////////////////////////////////////////
......
121 124
    mSizeY    = height;
122 125
    mColorH[0]= color;
123 126
    mMarked   = false;
127
    mID       = mNextID++;
124 128

  
125 129
    if( color!=DONT_CREATE )
126 130
      {
......
152 156
 */
153 157
  public long getID()
154 158
    {
155
    return mColorH[0];
159
    return mID;
156 160
    }
157 161

  
158 162
///////////////////////////////////////////////////////////////////////////////////////////////////

Also available in: Unified diff