commit 80b3acf673e62202e9aa6dd87245b7b1a387983a
Author: Leszek Koltunski <leszek@distoretedandroid.org>
Date:   Tue Jun 13 16:47:10 2017 +0100

    Remove DistortedEffectsPostprocess and unify it with DistortedEffects.
    
    Job not finished  - doesn't compile now!

diff --git a/src/main/java/org/distorted/library/main/Distorted.java b/src/main/java/org/distorted/library/main/Distorted.java
index fe5e422..d1118de 100644
--- a/src/main/java/org/distorted/library/main/Distorted.java
+++ b/src/main/java/org/distorted/library/main/Distorted.java
@@ -147,7 +147,6 @@ public class Distorted
     DistortedObject.onDestroy();
     DistortedNode.onDestroy();
     DistortedEffects.onDestroy();
-    DistortedEffectsPostprocess.onDestroy();
     DistortedMaster.onDestroy();
     EffectQueue.onDestroy();
     EffectMessageSender.stopSending();
diff --git a/src/main/java/org/distorted/library/main/DistortedEffects.java b/src/main/java/org/distorted/library/main/DistortedEffects.java
index 6c7f434..fc40657 100644
--- a/src/main/java/org/distorted/library/main/DistortedEffects.java
+++ b/src/main/java/org/distorted/library/main/DistortedEffects.java
@@ -47,8 +47,10 @@ import java.util.ArrayList;
  * <p>
  * The queues hold actual effects to be applied to a given (DistortedTexture,MeshObject) combo.
  */
-public class DistortedEffects
+public class DistortedEffects implements DistortedSlave
   {
+  private static final int MIPMAP = 0;
+
   /// MAIN PROGRAM ///
   private static DistortedProgram mMainProgram;
   private static int mMainTextureH;
@@ -93,8 +95,23 @@ public class DistortedEffects
   private EffectQueueMatrix mM;
   private EffectQueueFragment mF;
   private EffectQueueVertex mV;
+  private EffectQueuePostprocess mP;
+
+  private boolean matrixCloned, vertexCloned, fragmentCloned, postprocessCloned;
 
-  private boolean matrixCloned, vertexCloned, fragmentCloned;
+  private class Job
+    {
+    int type;
+    int level;
+
+    Job(int t, int l)
+      {
+      type = t;
+      level= l;
+      }
+    }
+
+  private ArrayList<Job> mJobs = new ArrayList<>();
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -243,6 +260,73 @@ public class DistortedEffects
       mF = new EffectQueueFragment(mID);
       fragmentCloned = false;
       }
+
+    if( (flags & Distorted.CLONE_POSTPROCESS) != 0 )
+      {
+      mP = d.mP;
+      postprocessCloned = true;
+      }
+    else
+      {
+      mP = new EffectQueuePostprocess(mID);
+      postprocessCloned = false;
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int postprocess(long time, DistortedOutputSurface surface)
+    {
+    return mP.postprocess(time,surface);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  long getBucket()
+    {
+    return mP.getBucket();
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int getQuality()
+    {
+    return mP.mQualityLevel;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int getHalo()
+    {
+    return mP.getHalo();
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * This is not really part of the public API. Has to be public only because it is a part of the
+ * DistortedSlave interface, which should really be a class that we extend here instead but
+ * Java has no multiple inheritance.
+ *
+ * @y.exclude
+ */
+  public void doWork()
+    {
+    int num = mJobs.size();
+    Job job;
+
+    for(int i=0; i<num; i++)
+      {
+      job = mJobs.remove(0);
+
+      switch(job.type)
+        {
+        case MIPMAP: int level = job.level;
+                     mP.mQualityLevel = level;
+                     mP.mQualityScale = 1.0f;
+                     for(int j=0; j<level; j++) mP.mQualityScale*=EffectQuality.MULTIPLIER;
+                     break;
+        }
+      }
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -339,13 +423,15 @@ public class DistortedEffects
    
   private void releasePriv()
     {
-    if( !matrixCloned   ) mM.abortAll(false);
-    if( !vertexCloned   ) mV.abortAll(false);
-    if( !fragmentCloned ) mF.abortAll(false);
+    if( !matrixCloned   )   mM.abortAll(false);
+    if( !vertexCloned   )   mV.abortAll(false);
+    if( !fragmentCloned )   mF.abortAll(false);
+    if( !postprocessCloned) mP.abortAll(false);
 
     mM = null;
     mV = null;
     mF = null;
+    mP = null;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -422,6 +508,7 @@ public class DistortedEffects
     mV.registerForMessages(el);
     mF.registerForMessages(el);
     mM.registerForMessages(el);
+    mP.registerForMessages(el);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -436,6 +523,7 @@ public class DistortedEffects
     mV.deregisterForMessages(el);
     mF.deregisterForMessages(el);
     mM.deregisterForMessages(el);
+    mP.deregisterForMessages(el);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -462,7 +550,7 @@ public class DistortedEffects
       case MATRIX     : return mM.abortAll(true);
       case VERTEX     : return mV.abortAll(true);
       case FRAGMENT   : return mF.abortAll(true);
-  //  case POSTPROCESS: return mP.abortAll(true);
+      case POSTPROCESS: return mP.abortAll(true);
       default         : return 0;
       }
     }
@@ -481,7 +569,7 @@ public class DistortedEffects
     if( type == EffectType.MATRIX.ordinal()      ) return mM.removeById(id);
     if( type == EffectType.VERTEX.ordinal()      ) return mV.removeById(id);
     if( type == EffectType.FRAGMENT.ordinal()    ) return mF.removeById(id);
-//  if( type == EffectType.POSTPROCESS.ordinal() ) return mP.removeById(id);
+    if( type == EffectType.POSTPROCESS.ordinal() ) return mP.removeById(id);
 
     return 0;
     }
@@ -500,7 +588,7 @@ public class DistortedEffects
       case MATRIX     : return mM.removeEffect(effect);
       case VERTEX     : return mV.removeEffect(effect);
       case FRAGMENT   : return mF.removeEffect(effect);
-  //  case POSTPROCESS: return mP.removeEffect(effect);
+      case POSTPROCESS: return mP.removeEffect(effect);
       default         : return 0;
       }
     }
@@ -519,7 +607,7 @@ public class DistortedEffects
       case MATRIX     : return mM.removeByName(name);
       case VERTEX     : return mV.removeByName(name);
       case FRAGMENT   : return mF.removeByName(name);
-  //  case POSTPROCESS: return mP.removeByName(name);
+      case POSTPROCESS: return mP.removeByName(name);
       default                : return 0;
       }
     }
@@ -575,6 +663,18 @@ public class DistortedEffects
     return EffectQueue.getMax(EffectType.FRAGMENT.ordinal());
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Returns the maximum number of Postprocess effects.
+ *
+ * @return The maximum number of Postprocess effects
+ */
+  @SuppressWarnings("unused")
+  public static int getMaxPostprocess()
+    {
+    return EffectQueue.getMax(EffectType.POSTPROCESS.ordinal());
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Sets the maximum number of Matrix effects that can be stored in a single EffectQueue at one time.
@@ -641,6 +741,44 @@ public class DistortedEffects
     return EffectQueue.setMax(EffectType.FRAGMENT.ordinal(),max);
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Sets the maximum number of Postprocess effects that can be stored in a single EffectQueue at one time.
+ * This can fail if:
+ * <ul>
+ * <li>the value of 'max' is outside permitted range (0 &le; max &le; Byte.MAX_VALUE)
+ * <li>We try to increase the value of 'max' when it is too late to do so already. It needs to be called
+ *     before the Fragment Shader gets compiled, i.e. before the call to {@link Distorted#onCreate}. After this
+ *     time only decreasing the value of 'max' is permitted.
+ * <li>Furthermore, this needs to be called before any instances of the DistortedEffects class get created.
+ * </ul>
+ *
+ * @param max new maximum number of simultaneous Postprocess Effects. Has to be a non-negative number not greater
+ *            than Byte.MAX_VALUE
+ * @return <code>true</code> if operation was successful, <code>false</code> otherwise.
+ */
+  @SuppressWarnings("unused")
+  public static boolean setMaxPostprocess(int max)
+    {
+    return EffectQueue.setMax(EffectType.POSTPROCESS.ordinal(),max);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * The higher the quality, the better the effect will look like and the slower it will be.
+ * <p>
+ * This works by rendering into smaller and smaller intermediate buffers. Each step renders into a
+ * buffer that's half the size of the previous one.
+ * <p>
+ * We cannot this during mid-render - thus, give it to the Master to assign us back this job on the
+ * next render.
+ */
+  public void setQuality(EffectQuality quality)
+    {
+    mJobs.add(new Job(MIPMAP,quality.level));
+    DistortedMaster.newSlave(this);
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Add a new Effect to our queue.
@@ -655,7 +793,7 @@ public class DistortedEffects
       case VERTEX      : return mV.add(effect);
       case FRAGMENT    : return mF.add(effect);
       case MATRIX      : return mM.add(effect);
-   // case POSTPROCESS : return mP.add(effect);
+      case POSTPROCESS : return mP.add(effect);
       }
 
     return false;
diff --git a/src/main/java/org/distorted/library/main/DistortedEffectsPostprocess.java b/src/main/java/org/distorted/library/main/DistortedEffectsPostprocess.java
deleted file mode 100644
index a2f215e..0000000
--- a/src/main/java/org/distorted/library/main/DistortedEffectsPostprocess.java
+++ /dev/null
@@ -1,338 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Copyright 2016 Leszek Koltunski                                                               //
-//                                                                                               //
-// This file is part of Distorted.                                                               //
-//                                                                                               //
-// Distorted is free software: you can redistribute it and/or modify                             //
-// it under the terms of the GNU General Public License as published by                          //
-// the Free Software Foundation, either version 2 of the License, or                             //
-// (at your option) any later version.                                                           //
-//                                                                                               //
-// Distorted is distributed in the hope that it will be useful,                                  //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
-// GNU General Public License for more details.                                                  //
-//                                                                                               //
-// You should have received a copy of the GNU General Public License                             //
-// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-package org.distorted.library.main;
-
-import org.distorted.library.effect.Effect;
-import org.distorted.library.effect.EffectType;
-import org.distorted.library.message.EffectListener;
-
-import java.util.ArrayList;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-/**
- * Class containing the queue of postprocessing effects.
- * <p>
- * This better be separate from the main DistortedEffects class, because we want to be able to apply
- * the same postprocessing effects (i.e. not only the same effects, but the very same instance of this
- * object) to several Children of a Node. Reason for that: if several children have the same Object,
- * it is easy to group them into 'Buckets' where each bucket has the same postprocessing effects and
- * is therefore rendered to the same buffer, which is then postprocessed in one go.
- * <p>
- * The queue holds actual effects to be applied to a given bucket of several (DistortedTexture,MeshObject) combos.
- */
-public class DistortedEffectsPostprocess implements DistortedSlave
-  {
-  private static final int MIPMAP = 0;
-
-  private static long mNextID =0;
-  private long mID;
-
-  private EffectQueuePostprocess mP;
-
-  private boolean postprocessCloned;
-
-  private class Job
-    {
-    int type;
-    int level;
-
-    Job(int t, int l)
-      {
-      type = t;
-      level= l;
-      }
-    }
-
-  private ArrayList<Job> mJobs = new ArrayList<>();
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private void initializeEffectLists(DistortedEffectsPostprocess d, int flags)
-    {
-    if( (flags & Distorted.CLONE_POSTPROCESS) != 0 )
-      {
-      mP = d.mP;
-      postprocessCloned = true;
-      }
-    else
-      {
-      mP = new EffectQueuePostprocess(mID);
-      postprocessCloned = false;
-      }
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  int postprocess(long time, DistortedOutputSurface surface)
-    {
-    return mP.postprocess(time,surface);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  long getBucket()
-    {
-    return mP.mNumEffects==0 ? 0: mID;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private void releasePriv()
-    {
-    if( !postprocessCloned) mP.abortAll(false);
-
-    mP = null;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  int getQuality()
-    {
-    return mP.mQualityLevel;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  int getHalo()
-    {
-    return mP.getHalo();
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  static void onDestroy()
-    {
-    mNextID = 0;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Create empty effect queue.
- */
-  public DistortedEffectsPostprocess()
-    {
-    mID = ++mNextID;
-    initializeEffectLists(this,0);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Copy constructor.
- * <p>
- * Whatever we do not clone gets created just like in the default constructor.
- *
- * @param dc    Source object to create our object from
- * @param flags A bitmask of values specifying what to copy.
- *              Currently the only values possible are CLONE_NOTHING or CLONE_POSTPROCESS.
- */
-  public DistortedEffectsPostprocess(DistortedEffectsPostprocess dc, int flags)
-    {
-    mID = ++mNextID;
-    initializeEffectLists(dc,flags);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * This is not really part of the public API. Has to be public only because it is a part of the
- * DistortedSlave interface, which should really be a class that we extend here instead but
- * Java has no multiple inheritance.
- *
- * @y.exclude
- */
-  public void doWork()
-    {
-    int num = mJobs.size();
-    Job job;
-
-    for(int i=0; i<num; i++)
-      {
-      job = mJobs.remove(0);
-
-      switch(job.type)
-        {
-        case MIPMAP: int level = job.level;
-                     mP.mQualityLevel = level;
-                     mP.mQualityScale = 1.0f;
-                     for(int j=0; j<level; j++) mP.mQualityScale*=EffectQuality.MULTIPLIER;
-                     break;
-        }
-      }
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Releases all resources. After this call, the queue should not be used anymore.
- */
-  @SuppressWarnings("unused")
-  public synchronized void delete()
-    {
-    releasePriv();
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Returns unique ID of this instance.
- *
- * @return ID of the object.
- */
-  @SuppressWarnings("unused")
-  public long getID()
-      {
-      return mID;
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Adds the calling class to the list of Listeners that get notified each time some event happens 
- * to one of the Effects in the queues. Nothing will happen if 'el' is already in the list.
- * 
- * @param el A class implementing the EffectListener interface that wants to get notifications.
- */
-  @SuppressWarnings("unused")
-  public void registerForMessages(EffectListener el)
-    {
-    mP.registerForMessages(el);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Removes the calling class from the list of Listeners.
- * 
- * @param el A class implementing the EffectListener interface that no longer wants to get notifications.
- */
-  @SuppressWarnings("unused")
-  public void deregisterForMessages(EffectListener el)
-    {
-    mP.deregisterForMessages(el);
-    }
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Aborts all Effects.
- * @return Number of effects aborted.
- */
-  public int abortAllEffects()
-    {
-    return mP.abortAll(true);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Aborts all Effects of a given type, for example all POSTPROCESS Effects.
- *
- * @param type one of the constants defined in {@link EffectType}
- * @return Number of effects aborted.
- */
-  public int abortByType(EffectType type)
-    {
-    switch(type)
-      {
-      case POSTPROCESS: return mP.abortAll(true);
-      default         : return 0;
-      }
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Aborts a single Effect.
- *
- * @param effect the Effect we want to abort.
- * @return number of Effects aborted. Always either 0 or 1.
- */
-  public int abortEffect(Effect effect)
-    {
-    switch(effect.getType())
-      {
-      case POSTPROCESS: return mP.removeEffect(effect);
-      default         : return 0;
-      }
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Returns the maximum number of Postprocess effects.
- *
- * @return The maximum number of Postprocess effects
- */
-  @SuppressWarnings("unused")
-  public static int getMaxPostprocess()
-    {
-    return EffectQueue.getMax(EffectType.POSTPROCESS.ordinal());
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Sets the maximum number of Postprocess effects that can be stored in a single EffectQueue at one time.
- * This can fail if:
- * <ul>
- * <li>the value of 'max' is outside permitted range (0 &le; max &le; Byte.MAX_VALUE)
- * <li>We try to increase the value of 'max' when it is too late to do so already. It needs to be called
- *     before the Fragment Shader gets compiled, i.e. before the call to {@link Distorted#onCreate}. After this
- *     time only decreasing the value of 'max' is permitted.
- * <li>Furthermore, this needs to be called before any instances of the DistortedEffects class get created.
- * </ul>
- *
- * @param max new maximum number of simultaneous Postprocess Effects. Has to be a non-negative number not greater
- *            than Byte.MAX_VALUE
- * @return <code>true</code> if operation was successful, <code>false</code> otherwise.
- */
-  @SuppressWarnings("unused")
-  public static boolean setMaxPostprocess(int max)
-    {
-    return EffectQueue.setMax(EffectType.POSTPROCESS.ordinal(),max);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * The higher the quality, the better the effect will look like and the slower it will be.
- * <p>
- * This works by rendering into smaller and smaller intermediate buffers. Each step renders into a
- * buffer that's half the size of the previous one.
- * <p>
- * We cannot this during mid-render - thus, give it to the Master to assign us back this job on the
- * next render.
- */
-  public void setQuality(EffectQuality quality)
-    {
-    mJobs.add(new Job(MIPMAP,quality.level));
-    DistortedMaster.newSlave(this);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Add a new Effect to our queue.
- *
- * @param effect The Effect to add.
- * <code>true</code> if operation was successful, <code>false</code> otherwise.
- */
-  public boolean apply(Effect effect)
-    {
-    switch(effect.getType())
-      {
-      case POSTPROCESS : return mP.add(effect);
-      }
-
-    return false;
-    }
-  }
diff --git a/src/main/java/org/distorted/library/main/DistortedMaster.java b/src/main/java/org/distorted/library/main/DistortedMaster.java
index 4c9ad77..d39fcc0 100644
--- a/src/main/java/org/distorted/library/main/DistortedMaster.java
+++ b/src/main/java/org/distorted/library/main/DistortedMaster.java
@@ -81,18 +81,18 @@ class DistortedMaster
   static void addSorted(ArrayList<DistortedNode> mChildren, DistortedNode newChild)
     {
     DistortedNode child;
-    DistortedEffectsPostprocess dep;
+    DistortedEffects effects;
     int i,num = mChildren.size();
     long bucket, newBucket;
 
-    dep = newChild.getEffectsPostprocess();
-    newBucket = dep==null ? 0 : dep.getBucket();
+    effects = newChild.getEffects();
+    newBucket = effects.getBucket();
 
     for(i=0; i<num; i++)
       {
-      child = mChildren.get(i);
-      dep   = child.getEffectsPostprocess();
-      bucket= dep==null ? 0 : dep.getBucket();
+      child  = mChildren.get(i);
+      effects= child.getEffects();
+      bucket = effects.getBucket();
 
       if( bucket>newBucket ) break;
       }
diff --git a/src/main/java/org/distorted/library/main/DistortedNode.java b/src/main/java/org/distorted/library/main/DistortedNode.java
index 08627ee..5a11a99 100644
--- a/src/main/java/org/distorted/library/main/DistortedNode.java
+++ b/src/main/java/org/distorted/library/main/DistortedNode.java
@@ -259,7 +259,7 @@ public class DistortedNode implements DistortedSlave
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  int markStencilAndDepth(long currTime, DistortedOutputSurface surface, DistortedEffectsPostprocess effects)
+  int markStencilAndDepth(long currTime, DistortedOutputSurface surface, DistortedEffects effects)
     {
     DistortedInputSurface input = mNumChildren[0]==0 ? mSurface : mData.mFBO;
 
@@ -680,17 +680,6 @@ public class DistortedNode implements DistortedSlave
       }
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Returns the DistortedEffectsPostprocess object that's in the Node.
- *
- * @return The DistortedEffectsPostprocess contained in the Node.
- */
-  public DistortedEffectsPostprocess getEffectsPostprocess()
-    {
-    return mPostprocess;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Returns the DistortedEffects object that's in the Node.
diff --git a/src/main/java/org/distorted/library/main/DistortedOutputSurface.java b/src/main/java/org/distorted/library/main/DistortedOutputSurface.java
index 2cb4105..ca2447b 100644
--- a/src/main/java/org/distorted/library/main/DistortedOutputSurface.java
+++ b/src/main/java/org/distorted/library/main/DistortedOutputSurface.java
@@ -253,7 +253,7 @@ private String sLast="", sCurr="";
     {
     int numRenders = 0;
     DistortedNode child1, child2;
-    DistortedEffectsPostprocess lastP=null, currP;
+    DistortedEffects lastP=null, currP;
     long lastB=0, currB;
     int bucketChange=0;
     int lastQ=0, currQ;
@@ -263,7 +263,7 @@ sCurr = "";
     for(int i=0; i<num; i++)
       {
       child1 = children.get(i);
-      currP = child1.getEffectsPostprocess();
+      currP = child1.getEffects();
       currB = currP==null ? 0 : currP.getBucket();
       currQ = currP==null ? 0 : currP.getQuality();
 
diff --git a/src/main/java/org/distorted/library/main/EffectQueuePostprocess.java b/src/main/java/org/distorted/library/main/EffectQueuePostprocess.java
index e981b03..caf85a3 100644
--- a/src/main/java/org/distorted/library/main/EffectQueuePostprocess.java
+++ b/src/main/java/org/distorted/library/main/EffectQueuePostprocess.java
@@ -250,6 +250,13 @@ class EffectQueuePostprocess extends EffectQueue
       }
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  long getBucket()
+    {
+    return mNumEffects>0 ? mEffects[0].getID() : 0;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   int getHalo()
