Project

General

Profile

« Previous | Next » 

Revision 80b3acf6

Added by Leszek Koltunski over 7 years ago

Remove DistortedEffectsPostprocess and unify it with DistortedEffects.

Job not finished - doesn't compile now!

View differences:

src/main/java/org/distorted/library/main/Distorted.java
147 147
    DistortedObject.onDestroy();
148 148
    DistortedNode.onDestroy();
149 149
    DistortedEffects.onDestroy();
150
    DistortedEffectsPostprocess.onDestroy();
151 150
    DistortedMaster.onDestroy();
152 151
    EffectQueue.onDestroy();
153 152
    EffectMessageSender.stopSending();
src/main/java/org/distorted/library/main/DistortedEffects.java
47 47
 * <p>
48 48
 * The queues hold actual effects to be applied to a given (DistortedTexture,MeshObject) combo.
49 49
 */
50
public class DistortedEffects
50
public class DistortedEffects implements DistortedSlave
51 51
  {
52
  private static final int MIPMAP = 0;
53

  
52 54
  /// MAIN PROGRAM ///
53 55
  private static DistortedProgram mMainProgram;
54 56
  private static int mMainTextureH;
......
93 95
  private EffectQueueMatrix mM;
94 96
  private EffectQueueFragment mF;
95 97
  private EffectQueueVertex mV;
98
  private EffectQueuePostprocess mP;
99

  
100
  private boolean matrixCloned, vertexCloned, fragmentCloned, postprocessCloned;
96 101

  
97
  private boolean matrixCloned, vertexCloned, fragmentCloned;
102
  private class Job
103
    {
104
    int type;
105
    int level;
106

  
107
    Job(int t, int l)
108
      {
109
      type = t;
110
      level= l;
111
      }
112
    }
113

  
114
  private ArrayList<Job> mJobs = new ArrayList<>();
98 115

  
99 116
///////////////////////////////////////////////////////////////////////////////////////////////////
100 117

  
......
243 260
      mF = new EffectQueueFragment(mID);
244 261
      fragmentCloned = false;
245 262
      }
263

  
264
    if( (flags & Distorted.CLONE_POSTPROCESS) != 0 )
265
      {
266
      mP = d.mP;
267
      postprocessCloned = true;
268
      }
269
    else
270
      {
271
      mP = new EffectQueuePostprocess(mID);
272
      postprocessCloned = false;
273
      }
274
    }
275

  
276
///////////////////////////////////////////////////////////////////////////////////////////////////
277

  
278
  int postprocess(long time, DistortedOutputSurface surface)
279
    {
280
    return mP.postprocess(time,surface);
281
    }
282

  
283
///////////////////////////////////////////////////////////////////////////////////////////////////
284

  
285
  long getBucket()
286
    {
287
    return mP.getBucket();
288
    }
289

  
290
///////////////////////////////////////////////////////////////////////////////////////////////////
291

  
292
  int getQuality()
293
    {
294
    return mP.mQualityLevel;
295
    }
296

  
297
///////////////////////////////////////////////////////////////////////////////////////////////////
298

  
299
  int getHalo()
300
    {
301
    return mP.getHalo();
302
    }
303

  
304
///////////////////////////////////////////////////////////////////////////////////////////////////
305
/**
306
 * This is not really part of the public API. Has to be public only because it is a part of the
307
 * DistortedSlave interface, which should really be a class that we extend here instead but
308
 * Java has no multiple inheritance.
309
 *
310
 * @y.exclude
311
 */
312
  public void doWork()
313
    {
314
    int num = mJobs.size();
315
    Job job;
316

  
317
    for(int i=0; i<num; i++)
318
      {
319
      job = mJobs.remove(0);
320

  
321
      switch(job.type)
322
        {
323
        case MIPMAP: int level = job.level;
324
                     mP.mQualityLevel = level;
325
                     mP.mQualityScale = 1.0f;
326
                     for(int j=0; j<level; j++) mP.mQualityScale*=EffectQuality.MULTIPLIER;
327
                     break;
328
        }
329
      }
246 330
    }
247 331

  
248 332
///////////////////////////////////////////////////////////////////////////////////////////////////
......
339 423
   
340 424
  private void releasePriv()
341 425
    {
342
    if( !matrixCloned   ) mM.abortAll(false);
343
    if( !vertexCloned   ) mV.abortAll(false);
344
    if( !fragmentCloned ) mF.abortAll(false);
426
    if( !matrixCloned   )   mM.abortAll(false);
427
    if( !vertexCloned   )   mV.abortAll(false);
428
    if( !fragmentCloned )   mF.abortAll(false);
429
    if( !postprocessCloned) mP.abortAll(false);
345 430

  
346 431
    mM = null;
347 432
    mV = null;
348 433
    mF = null;
434
    mP = null;
349 435
    }
350 436

  
351 437
///////////////////////////////////////////////////////////////////////////////////////////////////
......
422 508
    mV.registerForMessages(el);
423 509
    mF.registerForMessages(el);
424 510
    mM.registerForMessages(el);
511
    mP.registerForMessages(el);
425 512
    }
426 513

  
427 514
///////////////////////////////////////////////////////////////////////////////////////////////////
......
436 523
    mV.deregisterForMessages(el);
437 524
    mF.deregisterForMessages(el);
438 525
    mM.deregisterForMessages(el);
526
    mP.deregisterForMessages(el);
439 527
    }
440 528

  
441 529
///////////////////////////////////////////////////////////////////////////////////////////////////
......
462 550
      case MATRIX     : return mM.abortAll(true);
463 551
      case VERTEX     : return mV.abortAll(true);
464 552
      case FRAGMENT   : return mF.abortAll(true);
465
  //  case POSTPROCESS: return mP.abortAll(true);
553
      case POSTPROCESS: return mP.abortAll(true);
466 554
      default         : return 0;
467 555
      }
468 556
    }
......
481 569
    if( type == EffectType.MATRIX.ordinal()      ) return mM.removeById(id);
482 570
    if( type == EffectType.VERTEX.ordinal()      ) return mV.removeById(id);
483 571
    if( type == EffectType.FRAGMENT.ordinal()    ) return mF.removeById(id);
484
//  if( type == EffectType.POSTPROCESS.ordinal() ) return mP.removeById(id);
572
    if( type == EffectType.POSTPROCESS.ordinal() ) return mP.removeById(id);
485 573

  
486 574
    return 0;
487 575
    }
......
500 588
      case MATRIX     : return mM.removeEffect(effect);
501 589
      case VERTEX     : return mV.removeEffect(effect);
502 590
      case FRAGMENT   : return mF.removeEffect(effect);
503
  //  case POSTPROCESS: return mP.removeEffect(effect);
591
      case POSTPROCESS: return mP.removeEffect(effect);
504 592
      default         : return 0;
505 593
      }
506 594
    }
......
519 607
      case MATRIX     : return mM.removeByName(name);
520 608
      case VERTEX     : return mV.removeByName(name);
521 609
      case FRAGMENT   : return mF.removeByName(name);
522
  //  case POSTPROCESS: return mP.removeByName(name);
610
      case POSTPROCESS: return mP.removeByName(name);
523 611
      default                : return 0;
524 612
      }
525 613
    }
......
575 663
    return EffectQueue.getMax(EffectType.FRAGMENT.ordinal());
576 664
    }
577 665

  
666
///////////////////////////////////////////////////////////////////////////////////////////////////
667
/**
668
 * Returns the maximum number of Postprocess effects.
669
 *
670
 * @return The maximum number of Postprocess effects
671
 */
672
  @SuppressWarnings("unused")
673
  public static int getMaxPostprocess()
674
    {
675
    return EffectQueue.getMax(EffectType.POSTPROCESS.ordinal());
676
    }
677

  
578 678
///////////////////////////////////////////////////////////////////////////////////////////////////
579 679
/**
580 680
 * Sets the maximum number of Matrix effects that can be stored in a single EffectQueue at one time.
......
641 741
    return EffectQueue.setMax(EffectType.FRAGMENT.ordinal(),max);
642 742
    }
643 743

  
744
///////////////////////////////////////////////////////////////////////////////////////////////////
745
/**
746
 * Sets the maximum number of Postprocess effects that can be stored in a single EffectQueue at one time.
747
 * This can fail if:
748
 * <ul>
749
 * <li>the value of 'max' is outside permitted range (0 &le; max &le; Byte.MAX_VALUE)
750
 * <li>We try to increase the value of 'max' when it is too late to do so already. It needs to be called
751
 *     before the Fragment Shader gets compiled, i.e. before the call to {@link Distorted#onCreate}. After this
752
 *     time only decreasing the value of 'max' is permitted.
753
 * <li>Furthermore, this needs to be called before any instances of the DistortedEffects class get created.
754
 * </ul>
755
 *
756
 * @param max new maximum number of simultaneous Postprocess Effects. Has to be a non-negative number not greater
757
 *            than Byte.MAX_VALUE
758
 * @return <code>true</code> if operation was successful, <code>false</code> otherwise.
759
 */
760
  @SuppressWarnings("unused")
761
  public static boolean setMaxPostprocess(int max)
762
    {
763
    return EffectQueue.setMax(EffectType.POSTPROCESS.ordinal(),max);
764
    }
765

  
766
///////////////////////////////////////////////////////////////////////////////////////////////////
767
/**
768
 * The higher the quality, the better the effect will look like and the slower it will be.
769
 * <p>
770
 * This works by rendering into smaller and smaller intermediate buffers. Each step renders into a
771
 * buffer that's half the size of the previous one.
772
 * <p>
773
 * We cannot this during mid-render - thus, give it to the Master to assign us back this job on the
774
 * next render.
775
 */
776
  public void setQuality(EffectQuality quality)
777
    {
778
    mJobs.add(new Job(MIPMAP,quality.level));
779
    DistortedMaster.newSlave(this);
780
    }
781

  
644 782
///////////////////////////////////////////////////////////////////////////////////////////////////
645 783
/**
646 784
 * Add a new Effect to our queue.
......
655 793
      case VERTEX      : return mV.add(effect);
656 794
      case FRAGMENT    : return mF.add(effect);
657 795
      case MATRIX      : return mM.add(effect);
658
   // case POSTPROCESS : return mP.add(effect);
796
      case POSTPROCESS : return mP.add(effect);
659 797
      }
660 798

  
661 799
    return false;
src/main/java/org/distorted/library/main/DistortedEffectsPostprocess.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.main;
21

  
22
import org.distorted.library.effect.Effect;
23
import org.distorted.library.effect.EffectType;
24
import org.distorted.library.message.EffectListener;
25

  
26
import java.util.ArrayList;
27

  
28
///////////////////////////////////////////////////////////////////////////////////////////////////
29

  
30
/**
31
 * Class containing the queue of postprocessing effects.
32
 * <p>
33
 * This better be separate from the main DistortedEffects class, because we want to be able to apply
34
 * the same postprocessing effects (i.e. not only the same effects, but the very same instance of this
35
 * object) to several Children of a Node. Reason for that: if several children have the same Object,
36
 * it is easy to group them into 'Buckets' where each bucket has the same postprocessing effects and
37
 * is therefore rendered to the same buffer, which is then postprocessed in one go.
38
 * <p>
39
 * The queue holds actual effects to be applied to a given bucket of several (DistortedTexture,MeshObject) combos.
40
 */
41
public class DistortedEffectsPostprocess implements DistortedSlave
42
  {
43
  private static final int MIPMAP = 0;
44

  
45
  private static long mNextID =0;
46
  private long mID;
47

  
48
  private EffectQueuePostprocess mP;
49

  
50
  private boolean postprocessCloned;
51

  
52
  private class Job
53
    {
54
    int type;
55
    int level;
56

  
57
    Job(int t, int l)
58
      {
59
      type = t;
60
      level= l;
61
      }
62
    }
63

  
64
  private ArrayList<Job> mJobs = new ArrayList<>();
65

  
66
///////////////////////////////////////////////////////////////////////////////////////////////////
67

  
68
  private void initializeEffectLists(DistortedEffectsPostprocess d, int flags)
69
    {
70
    if( (flags & Distorted.CLONE_POSTPROCESS) != 0 )
71
      {
72
      mP = d.mP;
73
      postprocessCloned = true;
74
      }
75
    else
76
      {
77
      mP = new EffectQueuePostprocess(mID);
78
      postprocessCloned = false;
79
      }
80
    }
81

  
82
///////////////////////////////////////////////////////////////////////////////////////////////////
83

  
84
  int postprocess(long time, DistortedOutputSurface surface)
85
    {
86
    return mP.postprocess(time,surface);
87
    }
88

  
89
///////////////////////////////////////////////////////////////////////////////////////////////////
90

  
91
  long getBucket()
92
    {
93
    return mP.mNumEffects==0 ? 0: mID;
94
    }
95

  
96
///////////////////////////////////////////////////////////////////////////////////////////////////
97

  
98
  private void releasePriv()
99
    {
100
    if( !postprocessCloned) mP.abortAll(false);
101

  
102
    mP = null;
103
    }
104

  
105
///////////////////////////////////////////////////////////////////////////////////////////////////
106

  
107
  int getQuality()
108
    {
109
    return mP.mQualityLevel;
110
    }
111

  
112
///////////////////////////////////////////////////////////////////////////////////////////////////
113

  
114
  int getHalo()
115
    {
116
    return mP.getHalo();
117
    }
118

  
119
///////////////////////////////////////////////////////////////////////////////////////////////////
120

  
121
  static void onDestroy()
122
    {
123
    mNextID = 0;
124
    }
125

  
126
///////////////////////////////////////////////////////////////////////////////////////////////////
127
// PUBLIC API
128
///////////////////////////////////////////////////////////////////////////////////////////////////
129
/**
130
 * Create empty effect queue.
131
 */
132
  public DistortedEffectsPostprocess()
133
    {
134
    mID = ++mNextID;
135
    initializeEffectLists(this,0);
136
    }
137

  
138
///////////////////////////////////////////////////////////////////////////////////////////////////
139
/**
140
 * Copy constructor.
141
 * <p>
142
 * Whatever we do not clone gets created just like in the default constructor.
143
 *
144
 * @param dc    Source object to create our object from
145
 * @param flags A bitmask of values specifying what to copy.
146
 *              Currently the only values possible are CLONE_NOTHING or CLONE_POSTPROCESS.
147
 */
148
  public DistortedEffectsPostprocess(DistortedEffectsPostprocess dc, int flags)
149
    {
150
    mID = ++mNextID;
151
    initializeEffectLists(dc,flags);
152
    }
153

  
154
///////////////////////////////////////////////////////////////////////////////////////////////////
155
/**
156
 * This is not really part of the public API. Has to be public only because it is a part of the
157
 * DistortedSlave interface, which should really be a class that we extend here instead but
158
 * Java has no multiple inheritance.
159
 *
160
 * @y.exclude
161
 */
162
  public void doWork()
163
    {
164
    int num = mJobs.size();
165
    Job job;
166

  
167
    for(int i=0; i<num; i++)
168
      {
169
      job = mJobs.remove(0);
170

  
171
      switch(job.type)
172
        {
173
        case MIPMAP: int level = job.level;
174
                     mP.mQualityLevel = level;
175
                     mP.mQualityScale = 1.0f;
176
                     for(int j=0; j<level; j++) mP.mQualityScale*=EffectQuality.MULTIPLIER;
177
                     break;
178
        }
179
      }
180
    }
181

  
182
///////////////////////////////////////////////////////////////////////////////////////////////////
183
/**
184
 * Releases all resources. After this call, the queue should not be used anymore.
185
 */
186
  @SuppressWarnings("unused")
187
  public synchronized void delete()
188
    {
189
    releasePriv();
190
    }
191

  
192
///////////////////////////////////////////////////////////////////////////////////////////////////
193
/**
194
 * Returns unique ID of this instance.
195
 *
196
 * @return ID of the object.
197
 */
198
  @SuppressWarnings("unused")
199
  public long getID()
200
      {
201
      return mID;
202
      }
203

  
204
///////////////////////////////////////////////////////////////////////////////////////////////////
205
/**
206
 * Adds the calling class to the list of Listeners that get notified each time some event happens 
207
 * to one of the Effects in the queues. Nothing will happen if 'el' is already in the list.
208
 * 
209
 * @param el A class implementing the EffectListener interface that wants to get notifications.
210
 */
211
  @SuppressWarnings("unused")
212
  public void registerForMessages(EffectListener el)
213
    {
214
    mP.registerForMessages(el);
215
    }
216

  
217
///////////////////////////////////////////////////////////////////////////////////////////////////
218
/**
219
 * Removes the calling class from the list of Listeners.
220
 * 
221
 * @param el A class implementing the EffectListener interface that no longer wants to get notifications.
222
 */
223
  @SuppressWarnings("unused")
224
  public void deregisterForMessages(EffectListener el)
225
    {
226
    mP.deregisterForMessages(el);
227
    }
228

  
229

  
230
///////////////////////////////////////////////////////////////////////////////////////////////////
231
/**
232
 * Aborts all Effects.
233
 * @return Number of effects aborted.
234
 */
235
  public int abortAllEffects()
236
    {
237
    return mP.abortAll(true);
238
    }
239

  
240
///////////////////////////////////////////////////////////////////////////////////////////////////
241
/**
242
 * Aborts all Effects of a given type, for example all POSTPROCESS Effects.
243
 *
244
 * @param type one of the constants defined in {@link EffectType}
245
 * @return Number of effects aborted.
246
 */
247
  public int abortByType(EffectType type)
248
    {
249
    switch(type)
250
      {
251
      case POSTPROCESS: return mP.abortAll(true);
252
      default         : return 0;
253
      }
254
    }
255

  
256
///////////////////////////////////////////////////////////////////////////////////////////////////
257
/**
258
 * Aborts a single Effect.
259
 *
260
 * @param effect the Effect we want to abort.
261
 * @return number of Effects aborted. Always either 0 or 1.
262
 */
263
  public int abortEffect(Effect effect)
264
    {
265
    switch(effect.getType())
266
      {
267
      case POSTPROCESS: return mP.removeEffect(effect);
268
      default         : return 0;
269
      }
270
    }
271

  
272
///////////////////////////////////////////////////////////////////////////////////////////////////
273
/**
274
 * Returns the maximum number of Postprocess effects.
275
 *
276
 * @return The maximum number of Postprocess effects
277
 */
278
  @SuppressWarnings("unused")
279
  public static int getMaxPostprocess()
280
    {
281
    return EffectQueue.getMax(EffectType.POSTPROCESS.ordinal());
282
    }
283

  
284
///////////////////////////////////////////////////////////////////////////////////////////////////
285
/**
286
 * Sets the maximum number of Postprocess effects that can be stored in a single EffectQueue at one time.
287
 * This can fail if:
288
 * <ul>
289
 * <li>the value of 'max' is outside permitted range (0 &le; max &le; Byte.MAX_VALUE)
290
 * <li>We try to increase the value of 'max' when it is too late to do so already. It needs to be called
291
 *     before the Fragment Shader gets compiled, i.e. before the call to {@link Distorted#onCreate}. After this
292
 *     time only decreasing the value of 'max' is permitted.
293
 * <li>Furthermore, this needs to be called before any instances of the DistortedEffects class get created.
294
 * </ul>
295
 *
296
 * @param max new maximum number of simultaneous Postprocess Effects. Has to be a non-negative number not greater
297
 *            than Byte.MAX_VALUE
298
 * @return <code>true</code> if operation was successful, <code>false</code> otherwise.
299
 */
300
  @SuppressWarnings("unused")
301
  public static boolean setMaxPostprocess(int max)
302
    {
303
    return EffectQueue.setMax(EffectType.POSTPROCESS.ordinal(),max);
304
    }
305

  
306
///////////////////////////////////////////////////////////////////////////////////////////////////
307
/**
308
 * The higher the quality, the better the effect will look like and the slower it will be.
309
 * <p>
310
 * This works by rendering into smaller and smaller intermediate buffers. Each step renders into a
311
 * buffer that's half the size of the previous one.
312
 * <p>
313
 * We cannot this during mid-render - thus, give it to the Master to assign us back this job on the
314
 * next render.
315
 */
316
  public void setQuality(EffectQuality quality)
317
    {
318
    mJobs.add(new Job(MIPMAP,quality.level));
319
    DistortedMaster.newSlave(this);
320
    }
321

  
322
///////////////////////////////////////////////////////////////////////////////////////////////////
323
/**
324
 * Add a new Effect to our queue.
325
 *
326
 * @param effect The Effect to add.
327
 * <code>true</code> if operation was successful, <code>false</code> otherwise.
328
 */
329
  public boolean apply(Effect effect)
330
    {
331
    switch(effect.getType())
332
      {
333
      case POSTPROCESS : return mP.add(effect);
334
      }
335

  
336
    return false;
337
    }
338
  }
src/main/java/org/distorted/library/main/DistortedMaster.java
81 81
  static void addSorted(ArrayList<DistortedNode> mChildren, DistortedNode newChild)
82 82
    {
83 83
    DistortedNode child;
84
    DistortedEffectsPostprocess dep;
84
    DistortedEffects effects;
85 85
    int i,num = mChildren.size();
86 86
    long bucket, newBucket;
87 87

  
88
    dep = newChild.getEffectsPostprocess();
89
    newBucket = dep==null ? 0 : dep.getBucket();
88
    effects = newChild.getEffects();
89
    newBucket = effects.getBucket();
90 90

  
91 91
    for(i=0; i<num; i++)
92 92
      {
93
      child = mChildren.get(i);
94
      dep   = child.getEffectsPostprocess();
95
      bucket= dep==null ? 0 : dep.getBucket();
93
      child  = mChildren.get(i);
94
      effects= child.getEffects();
95
      bucket = effects.getBucket();
96 96

  
97 97
      if( bucket>newBucket ) break;
98 98
      }
src/main/java/org/distorted/library/main/DistortedNode.java
259 259

  
260 260
///////////////////////////////////////////////////////////////////////////////////////////////////
261 261

  
262
  int markStencilAndDepth(long currTime, DistortedOutputSurface surface, DistortedEffectsPostprocess effects)
262
  int markStencilAndDepth(long currTime, DistortedOutputSurface surface, DistortedEffects effects)
263 263
    {
264 264
    DistortedInputSurface input = mNumChildren[0]==0 ? mSurface : mData.mFBO;
265 265

  
......
680 680
      }
681 681
    }
682 682

  
683
///////////////////////////////////////////////////////////////////////////////////////////////////
684
/**
685
 * Returns the DistortedEffectsPostprocess object that's in the Node.
686
 *
687
 * @return The DistortedEffectsPostprocess contained in the Node.
688
 */
689
  public DistortedEffectsPostprocess getEffectsPostprocess()
690
    {
691
    return mPostprocess;
692
    }
693

  
694 683
///////////////////////////////////////////////////////////////////////////////////////////////////
695 684
/**
696 685
 * Returns the DistortedEffects object that's in the Node.
src/main/java/org/distorted/library/main/DistortedOutputSurface.java
253 253
    {
254 254
    int numRenders = 0;
255 255
    DistortedNode child1, child2;
256
    DistortedEffectsPostprocess lastP=null, currP;
256
    DistortedEffects lastP=null, currP;
257 257
    long lastB=0, currB;
258 258
    int bucketChange=0;
259 259
    int lastQ=0, currQ;
......
263 263
    for(int i=0; i<num; i++)
264 264
      {
265 265
      child1 = children.get(i);
266
      currP = child1.getEffectsPostprocess();
266
      currP = child1.getEffects();
267 267
      currB = currP==null ? 0 : currP.getBucket();
268 268
      currQ = currP==null ? 0 : currP.getQuality();
269 269

  
src/main/java/org/distorted/library/main/EffectQueuePostprocess.java
250 250
      }
251 251
    }
252 252

  
253
///////////////////////////////////////////////////////////////////////////////////////////////////
254

  
255
  long getBucket()
256
    {
257
    return mNumEffects>0 ? mEffects[0].getID() : 0;
258
    }
259

  
253 260
///////////////////////////////////////////////////////////////////////////////////////////////////
254 261

  
255 262
  int getHalo()

Also available in: Unified diff