commit 9829a8fdb75895c375b4bb56ba06f7b842e62f7d
Author: LeszekKoltunski <leszek@koltunski.pl>
Date:   Wed Apr 23 15:40:54 2025 +0200

    migrate the 'effect' package.

diff --git a/src/main/java/org/distorted/library/effect/Effect.kt b/src/main/java/org/distorted/library/effect/Effect.kt
index 60aefa2..6b04355 100644
--- a/src/main/java/org/distorted/library/effect/Effect.kt
+++ b/src/main/java/org/distorted/library/effect/Effect.kt
@@ -18,296 +18,197 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.effect;
+package org.distorted.library.effect
 
-import org.distorted.library.effectqueue.EffectQueue;
-import org.distorted.library.main.DistortedLibrary;
-import org.distorted.library.main.InternalStackFrameList;
-import org.distorted.library.message.EffectListener;
-
-import java.lang.reflect.Method;
-import java.util.ArrayList;
+import org.distorted.library.effectqueue.EffectQueue
+import org.distorted.library.main.DistortedLibrary
+import org.distorted.library.main.InternalStackFrameList
+import org.distorted.library.message.EffectListener
+import java.lang.reflect.Method
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Abstract Effect of any type.
  */
-public abstract class Effect
-  {
-  private final static int MAX_UNITY_DIM = 4;
-  private final static int NUM_EFFECTS = EffectName.LENGTH;
-
-  private final long mID;
-  private final EffectType mType;
-  private final EffectName mName;
-  private final int mDimension;
-  private final int mRegionDim;
-  private final int mCenterDim;
-
-  private ArrayList<EffectListener> mListeners =null;
-  private int mNumListeners=0;  // ==mListeners.length(), but we only create mListeners if the first one gets added
-
-  private final static float[] mUnity= new float[MAX_UNITY_DIM*NUM_EFFECTS];
-  private final static int[]   mUnityDim = new int[NUM_EFFECTS];
-
-  int mAndAssociation;
-  int mEquAssociation;
-
-  static boolean[] mEnabled = new boolean[NUM_EFFECTS];
-
-  static
-    {
-    for(int i=0; i<NUM_EFFECTS; i++) mEnabled[i] = false;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public abstract void addQueue(EffectQueue queue);
-  public abstract void remQueue(EffectQueue queue);
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  Effect(EffectName name)
-    {
-    mName      = name;
-    mType      = name.getType();
-    mDimension = name.getEffectDimension();
-    mCenterDim = name.getCenterDimension();
-    mRegionDim = name.getRegionDimension();
-
-    mAndAssociation = 0xffffffff;
-    mEquAssociation = 0;
-
-    int n = name.ordinal();
-    float[] u = name.getUnity();
-    int l = u.length;
-
-    System.arraycopy(u, 0, mUnity, MAX_UNITY_DIM*n, l);
-
-    mUnityDim[n] = l;
-
-    mID = (InternalStackFrameList.getNextEffectID()<<EffectType.LENGTH) + mType.ordinal();
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public static void onPause()
-    {
-    for(int i=0; i<NUM_EFFECTS; i++) mEnabled[i] = false;
-
-    MatrixEffect.destroyStatics();
-    VertexEffect.destroyStatics();
-    FragmentEffect.destroyStatics();
-    PostprocessEffect.destroyStatics();
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public abstract boolean compute(float[] uniforms, int index, long currentDuration, long step );
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public int getNumListeners()
-    {
-    return mNumListeners;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public EffectListener removeFirstListener()
-    {
-    if( mNumListeners>0 )
-      {
-      mNumListeners--;
-      return mListeners.remove(0);
-      }
-
-    return null;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public void writeAssociations(int[] intUniforms, int index1, int index2)
-    {
-    intUniforms[index1] = mAndAssociation;
-    intUniforms[index2] = mEquAssociation;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Do the set of Uniforms written in buffer[index], buffer[index+1], etc represent a Unity, i.e a
- * null Effect?
- */
-  public boolean isUnity(float[] buffer, int index)
-    {
-    int name = mName.ordinal();
-
-    switch(mUnityDim[name])
-      {
-      case 0: return true;
-      case 1: return buffer[index  ]==mUnity[MAX_UNITY_DIM*name  ];
-      case 2: return buffer[index  ]==mUnity[MAX_UNITY_DIM*name  ] &&
-                     buffer[index+1]==mUnity[MAX_UNITY_DIM*name+1];
-      case 3: return buffer[index  ]==mUnity[MAX_UNITY_DIM*name  ] &&
-                     buffer[index+1]==mUnity[MAX_UNITY_DIM*name+1] &&
-                     buffer[index+2]==mUnity[MAX_UNITY_DIM*name+2];
-      case 4: return buffer[index  ]==mUnity[MAX_UNITY_DIM*name  ] &&
-                     buffer[index+1]==mUnity[MAX_UNITY_DIM*name+1] &&
-                     buffer[index+2]==mUnity[MAX_UNITY_DIM*name+2] &&
-                     buffer[index+3]==mUnity[MAX_UNITY_DIM*name+3];
-      }
-
-    return false;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// this will enable() all Fragment Effects twice (once for smooth variant, once for non-smooth)
-// but this shouldn't matter.
-/**
- * Enable all effects of a given type.
- *
- * @param type EffectType to enable.
- */
-  public static void enableEffects(EffectType type)
-    {
-    Method method;
+abstract class Effect internal constructor (val name: EffectName)
+{
+    val iD: Long                                     // unique ID of this Effect.
+    val type: EffectType = name.type                 // EffectType enum corresponding to this Effect.
+    val effectDimension: Int = name.effectDimension  // number of Uniforms needed to describe this effect.
+    val regionDimension: Int = name.regionDimension  // dimension of the Region supported by this effect (0- no region supported at all).
+    val centerDimension: Int = name.centerDimension  // dimension of the Center supported by this effect (0- no center supported at all).
+    var numListeners: Int = 0                        // ==mListeners.length(), but we only create mListeners if the first one gets added
+        private set
+    val string: String get() = name.name             // printable name of this Effect.
+
+    var mAndAssociation: Int = -0x1
+    var mEquAssociation: Int = 0
+    private var mListeners: ArrayList<EffectListener>? = null
+
+    companion object
+    {
+        private const val MAX_UNITY_DIM = 4
+        private val NUM_EFFECTS: Int = EffectName.LENGTH
+        private val mUnity = FloatArray(MAX_UNITY_DIM*NUM_EFFECTS)
+        private val mUnityDim = IntArray(NUM_EFFECTS)
+        var mEnabled: BooleanArray = BooleanArray(NUM_EFFECTS)
+
+        init
+        {
+            for (i in 0 until NUM_EFFECTS) mEnabled[i] = false
+        }
 
-    for(EffectName name: EffectName.values())
-      {
-      if( name.getType() == type )
+        ///////////////////////////////////////////////////////////////////////////////////////////////////
+        /**
+         * Only for use by the library itself.
+         *
+         * @y.exclude
+         */
+        @JvmStatic
+        fun onPause()
         {
-        Class<? extends Effect> cls = name.getEffectClass();
+            for (i in 0 until NUM_EFFECTS) mEnabled[i] = false
 
-        try
-          {
-          method = cls.getMethod("enable");  // getMethod and NOT getDeclaredMethod because enable()
-                                             // is public
-          }
-        catch(NoSuchMethodException ex)
-          {
-          DistortedLibrary.logMessage("Effect: exception getting method: "+ex.getMessage());
-          method = null;
-          }
+            MatrixEffect.destroyStatics()
+            VertexEffect.destroyStatics()
+            FragmentEffect.destroyStatics()
+            PostprocessEffect.destroyStatics()
+        }
 
-        try
-          {
-          if( method!=null ) method.invoke(null);
-          }
-        catch(Exception ex)
-          {
-          DistortedLibrary.logMessage("Effect: exception invoking method: "+ex.getMessage());
-          }
+        ///////////////////////////////////////////////////////////////////////////////////////////////////
+        // this will enable() all Fragment Effects twice (once for smooth variant, once for non-smooth)
+        // but this shouldn't matter.
+        /**
+         * Enable all effects of a given type.
+         *
+         * @param type EffectType to enable.
+         */
+        @JvmStatic
+        fun enableEffects(type: EffectType)
+        {
+            var method: Method?
+
+            for (name in EffectName.entries)
+            {
+                if (name.type==type)
+                {
+                    val cls = name.effectClass
+
+                    try
+                    {
+                        method = cls.getMethod("enable") // getMethod and NOT getDeclaredMethod because enable() is public
+                    }
+                    catch (ex: NoSuchMethodException)
+                    {
+                        DistortedLibrary.logMessage("Effect: exception getting method: "+ex.message)
+                        method = null
+                    }
+
+                    try
+                    {
+                        method?.invoke(null)
+                    }
+                    catch (ex: Exception)
+                    {
+                        DistortedLibrary.logMessage("Effect: exception invoking method: "+ex.message)
+                    }
+                }
+            }
         }
-      }
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Return the EffectType enum corresponding to this Effect.
- *
- * @see EffectType
- */
-  public EffectType getType()
-    {
-    return mType;
-    }
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    abstract fun addQueue(queue: EffectQueue)
+    abstract fun remQueue(queue: EffectQueue)
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    init
+    {
+        val n = name.ordinal
+        val u = name.unity
+        val l = u.size
+        System.arraycopy(u, 0, mUnity, MAX_UNITY_DIM*n, l)
+        mUnityDim[n] = l
+        iD = (InternalStackFrameList.getNextEffectID() shl EffectType.LENGTH)+type.ordinal
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Only for use by the library itself.
+     *
+     * @y.exclude
+     */
+    abstract fun compute(uniforms: FloatArray, index: Int, currentDuration: Long, step: Long): Boolean
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Only for use by the library itself.
+     *
+     * @y.exclude
+     */
+    fun removeFirstListener(): EffectListener?
+    {
+        if (numListeners>0)
+        {
+            numListeners--
+            return mListeners!!.removeAt(0)
+        }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Return the EffectName enum corresponding to this Effect.
- *
- * @see EffectName
- */
-  public EffectName getName()
-    {
-    return mName;
+        return null
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Return the unique ID of this Effect.
- */
-  public long getID()
-    {
-    return mID;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Return a printable name of this Effect.
- */
-  public String getString()
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Only for use by the library itself.
+     *
+     * @y.exclude
+     */
+    fun writeAssociations(intUniforms: IntArray, index1: Int, index2: Int)
     {
-    return mName.name();
+        intUniforms[index1] = mAndAssociation
+        intUniforms[index2] = mEquAssociation
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Return the dimension of the Center supported by this effect (0- no center supported at all).
- */
-  public int getCenterDimension()
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    // PUBLIC API
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Do the set of Uniforms written in buffer[i+(0..dim)] represent a Unity, i.e a null Effect?
+     */
+    fun isUnity(buffer: FloatArray, i: Int): Boolean
     {
-    return mCenterDim;
-    }
+        val n = name.ordinal
+        val d = MAX_UNITY_DIM*n
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Return the dimension of the Region supported by this effect (0- no region supported at all).
- */
-  public int getRegionDimension()
-    {
-    return mRegionDim;
-    }
+        when (mUnityDim[n])
+        {
+            0 -> return true
+            1 -> return buffer[i]==mUnity[d]
+            2 -> return buffer[i]==mUnity[d] && buffer[i+1]==mUnity[d+1]
+            3 -> return buffer[i]==mUnity[d] && buffer[i+1]==mUnity[d+1] && buffer[i+2]==mUnity[d+2]
+            4 -> return buffer[i]==mUnity[d] && buffer[i+1]==mUnity[d+1] && buffer[i+2]==mUnity[d+2] && buffer[i+3]==mUnity[d+3]
+        }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Return the number of Uniforms needed to describe this effect.
- */
-  public int getEffectDimension()
-    {
-    return mDimension;
+        return false
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Adds the calling class to the list of Listeners that get notified when this Effect gets 'finished'
- * i.e. when the Dynamic inside this Effect reaches its final point and stops moving. This will be sent
- * only once, on the first time the Dynamic reaches its final point.
- *
- * If there's no Dynamic, ths message will never be sent.
- *
- * @param el A class implementing the EffectListener interface that wants to get notifications.
- */
-  public void notifyWhenFinished(EffectListener el)
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Adds the calling class to the list of Listeners that get notified when this Effect gets 'finished'
+     * i.e. when the Dynamic inside this Effect reaches its final point and stops moving. This will be sent
+     * only once, on the first time the Dynamic reaches its final point.
+     *
+     * If there's no Dynamic, ths message will never be sent.
+     *
+     * @param el A class implementing the EffectListener interface that wants to get notifications.
+     */
+    fun notifyWhenFinished(el: EffectListener)
     {
-    if( mListeners==null ) mListeners = new ArrayList<>();
+        if (mListeners==null) mListeners = ArrayList()
 
-    if( !mListeners.contains(el) )
-      {
-      mListeners.add(el);
-      mNumListeners++;
-      }
+        if (!mListeners!!.contains(el))
+        {
+            mListeners!!.add(el)
+            numListeners++
+        }
     }
-  }
+}
diff --git a/src/main/java/org/distorted/library/effect/EffectName.kt b/src/main/java/org/distorted/library/effect/EffectName.kt
index a0cf0ee..e6612e2 100644
--- a/src/main/java/org/distorted/library/effect/EffectName.kt
+++ b/src/main/java/org/distorted/library/effect/EffectName.kt
@@ -18,179 +18,111 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.effect;
+package org.distorted.library.effect
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Names of Effects one can add to the DistortedEffects queues.
- * <p>
- * Effect's 'Type' is one of the constants defined in {@link EffectType}.
- * </p>
- * <p>
+ *
+ * Effect's 'Type' is one of the constants defined in [EffectType].
+ *
  * Effect's 'Uniforms' are a vector of 7 (matrix effects) 12 (vertex) or 8 (fragment) floats, which
  * together form full information how to compute a given effect.
  * Typically, some of those values will be Interpolated in CPU (by one of the 'EffectQueueX.compute()'
  * methods) and the effect of such Interpolation sent to the Shaders.
- * </p>
- * <p>
+ *
  * Effect's 'Unity' is such a particular vector of its 'interpolated values' which makes the
  * effect NULL. For example, if the effect is 'MOVE' by a 3-dimensional vector, then a 'NULL
  * MOVE' is a MOVE by vector (0,0,0), thus (0,0,0) is the unity of the MOVE effect.
  * This is used by the EffectQueue classes to decide if the final form of the Effect is NULL - and
  * thus if it can safely be removed from Effect Queues without affecting the visual in any way.
- * </p>
  */
-
-public enum EffectName
-  {
-  // EFFECT NAME /////// EFFECT TYPE ////////// EFFECT UNITY //////////// DIM REGION CENTER // CLASS
-  ROTATE           ( EffectType.MATRIX  ,   new float[] {0.0f}           , 4, 0,     3    , MatrixEffectRotate.class       ),
-  QUATERNION       ( EffectType.MATRIX  ,   new float[] {0.0f,0.0f,0.0f} , 4, 0,     3    , MatrixEffectQuaternion.class   ),
-  MOVE             ( EffectType.MATRIX  ,   new float[] {0.0f,0.0f,0.0f} , 3, 0,     0    , MatrixEffectMove.class         ),
-  SCALE            ( EffectType.MATRIX  ,   new float[] {1.0f,1.0f,1.0f} , 3, 0,     0    , MatrixEffectScale.class        ),
-  SHEAR            ( EffectType.MATRIX  ,   new float[] {0.0f,0.0f,0.0f} , 3, 0,     3    , MatrixEffectShear.class        ),
-
-  DISTORT          ( EffectType.VERTEX  ,   new float[] {0.0f,0.0f,0.0f} , 3, 4,     3    , VertexEffectDistort.class      ),
-  DEFORM           ( EffectType.VERTEX  ,   new float[] {0.0f,0.0f,0.0f} , 4, 4,     3    , VertexEffectDeform.class       ),
-  SINK             ( EffectType.VERTEX  ,   new float[] {1.0f}           , 1, 4,     3    , VertexEffectSink.class         ),
-  PINCH            ( EffectType.VERTEX  ,   new float[] {1.0f}           , 3, 4,     3    , VertexEffectPinch.class        ),
-  SWIRL            ( EffectType.VERTEX  ,   new float[] {0.0f}           , 1, 4,     3    , VertexEffectSwirl.class        ),
-  WAVE             ( EffectType.VERTEX  ,   new float[] {0.0f}           , 5, 4,     3    , VertexEffectWave.class         ),
-  DISAPPEAR        ( EffectType.VERTEX  ,   new float[] {}               , 0, 0,     0    , VertexEffectDisappear.class    ),
-  PIPE             ( EffectType.VERTEX  ,   new float[] {1,0f}           , 5, 0,     3    , VertexEffectPipe.class         ),
-
-  VERTEX_MOVE      ( EffectType.VERTEX  ,   new float[] {0.0f,0.0f,0.0f} , 3, 0,     0    , VertexEffectMove.class         ),
-  VERTEX_QUATERNION( EffectType.VERTEX  ,   new float[] {0.0f,0.0f,0.0f} , 4, 0,     3    , VertexEffectQuaternion.class   ),
-  VERTEX_ROTATE    ( EffectType.VERTEX  ,   new float[] {0.0f}           , 4, 0,     3    , VertexEffectRotate.class       ),
-  VERTEX_SCALE     ( EffectType.VERTEX  ,   new float[] {1.0f,1.0f,1.0f} , 3, 0,     0    , VertexEffectScale.class        ),
-  VERTEX_SHEAR     ( EffectType.VERTEX  ,   new float[] {0.0f,0.0f,0.0f} , 3, 0,     3    , VertexEffectShear.class        ),
-
-  ALPHA            ( EffectType.FRAGMENT,   new float[] {1.0f}           , 1, 3,     3    , FragmentEffectAlpha.class      ),
-  SMOOTH_ALPHA     ( EffectType.FRAGMENT,   new float[] {1.0f}           , 1, 3,     3    , FragmentEffectAlpha.class      ),
-  CHROMA           ( EffectType.FRAGMENT,   new float[] {0.0f}           , 4, 3,     3    , FragmentEffectChroma.class     ),
-  SMOOTH_CHROMA    ( EffectType.FRAGMENT,   new float[] {0.0f}           , 4, 3,     3    , FragmentEffectChroma.class     ),
-  BRIGHTNESS       ( EffectType.FRAGMENT,   new float[] {1.0f}           , 1, 3,     3    , FragmentEffectBrightness.class ),
-  SMOOTH_BRIGHTNESS( EffectType.FRAGMENT,   new float[] {1.0f}           , 1, 3,     3    , FragmentEffectBrightness.class ),
-  SATURATION       ( EffectType.FRAGMENT,   new float[] {1.0f}           , 1, 3,     3    , FragmentEffectSaturation.class ),
-  SMOOTH_SATURATION( EffectType.FRAGMENT,   new float[] {1.0f}           , 1, 3,     3    , FragmentEffectSaturation.class ),
-  CONTRAST         ( EffectType.FRAGMENT,   new float[] {1.0f}           , 1, 3,     3    , FragmentEffectContrast.class   ),
-  SMOOTH_CONTRAST  ( EffectType.FRAGMENT,   new float[] {1.0f}           , 1, 3,     3    , FragmentEffectContrast.class   ),
-
-  BLUR             ( EffectType.POSTPROCESS,new float[] {0.0f}           , 2, 0,     0    , PostprocessEffectBlur.class    ),
-  GLOW             ( EffectType.POSTPROCESS,new float[] {0.0f}           , 6, 0,     0    , PostprocessEffectGlow.class    ),
-  BORDER           ( EffectType.POSTPROCESS,new float[] {0.0f}           , 5, 0,     0    , PostprocessEffectBorder.class  ),
-  ;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public static final int LENGTH = values().length;
-
-  private final EffectType type;
-  private final float[] unity;
-  private final int dimension;
-  private final int regionDim;
-  private final int centerDim;
-  private final Class<? extends Effect> effectClass;
-
-  private static final int[] dimensions;
-  private static final int[] regionDimension;
-  private static final int[] centerDimension;
-  private static final EffectName[] names;  // copy the values() to a local variable so that we
-                                            // don't have to keep recreating the array every time
-  static
+enum class EffectName( type: EffectType, unity: FloatArray, dim: Int, regionDim: Int, centerDim: Int, effectClass: Class<out Effect?>)
+{
+    // EFFECT NAME /////// EFFECT TYPE ////////// EFFECT UNITY //////////// DIM REGION CENTER // CLASS
+    ROTATE           (EffectType.MATRIX,      floatArrayOf(0.0f),             4, 0, 3, MatrixEffectRotate::class.java),
+    QUATERNION       (EffectType.MATRIX,      floatArrayOf(0.0f, 0.0f, 0.0f), 4, 0, 3, MatrixEffectQuaternion::class.java),
+    MOVE             (EffectType.MATRIX,      floatArrayOf(0.0f, 0.0f, 0.0f), 3, 0, 0, MatrixEffectMove::class.java),
+    SCALE            (EffectType.MATRIX,      floatArrayOf(1.0f, 1.0f, 1.0f), 3, 0, 0, MatrixEffectScale::class.java),
+    SHEAR            (EffectType.MATRIX,      floatArrayOf(0.0f, 0.0f, 0.0f), 3, 0, 3, MatrixEffectShear::class.java),
+
+    DISTORT          (EffectType.VERTEX,      floatArrayOf(0.0f, 0.0f, 0.0f), 3, 4, 3, VertexEffectDistort::class.java),
+    DEFORM           (EffectType.VERTEX,      floatArrayOf(0.0f, 0.0f, 0.0f), 4, 4, 3, VertexEffectDeform::class.java),
+    SINK             (EffectType.VERTEX,      floatArrayOf(1.0f),             1, 4, 3, VertexEffectSink::class.java),
+    PINCH            (EffectType.VERTEX,      floatArrayOf(1.0f),             3, 4, 3, VertexEffectPinch::class.java),
+    SWIRL            (EffectType.VERTEX,      floatArrayOf(0.0f),             1, 4, 3, VertexEffectSwirl::class.java),
+    WAVE             (EffectType.VERTEX,      floatArrayOf(0.0f),             5, 4, 3, VertexEffectWave::class.java),
+    DISAPPEAR        (EffectType.VERTEX,      floatArrayOf(),                 0, 0, 0, VertexEffectDisappear::class.java),
+    PIPE             (EffectType.VERTEX,      floatArrayOf(1f, 0f),           5, 0, 3, VertexEffectPipe::class.java),
+
+    VERTEX_MOVE      (EffectType.VERTEX,      floatArrayOf(0.0f, 0.0f, 0.0f), 3, 0, 0, VertexEffectMove::class.java),
+    VERTEX_QUATERNION(EffectType.VERTEX,      floatArrayOf(0.0f, 0.0f, 0.0f), 4, 0, 3, VertexEffectQuaternion::class.java),
+    VERTEX_ROTATE    (EffectType.VERTEX,      floatArrayOf(0.0f),             4, 0, 3, VertexEffectRotate::class.java),
+    VERTEX_SCALE     (EffectType.VERTEX,      floatArrayOf(1.0f, 1.0f, 1.0f), 3, 0, 0, VertexEffectScale::class.java),
+    VERTEX_SHEAR     (EffectType.VERTEX,      floatArrayOf(0.0f, 0.0f, 0.0f), 3, 0, 3, VertexEffectShear::class.java),
+
+    ALPHA            (EffectType.FRAGMENT,    floatArrayOf(1.0f),             1, 3, 3, FragmentEffectAlpha::class.java),
+    SMOOTH_ALPHA     (EffectType.FRAGMENT,    floatArrayOf(1.0f),             1, 3, 3, FragmentEffectAlpha::class.java),
+    CHROMA           (EffectType.FRAGMENT,    floatArrayOf(0.0f),             4, 3, 3, FragmentEffectChroma::class.java),
+    SMOOTH_CHROMA    (EffectType.FRAGMENT,    floatArrayOf(0.0f),             4, 3, 3, FragmentEffectChroma::class.java),
+    BRIGHTNESS       (EffectType.FRAGMENT,    floatArrayOf(1.0f),             1, 3, 3, FragmentEffectBrightness::class.java),
+    SMOOTH_BRIGHTNESS(EffectType.FRAGMENT,    floatArrayOf(1.0f),             1, 3, 3, FragmentEffectBrightness::class.java),
+    SATURATION       (EffectType.FRAGMENT,    floatArrayOf(1.0f),             1, 3, 3, FragmentEffectSaturation::class.java),
+    SMOOTH_SATURATION(EffectType.FRAGMENT,    floatArrayOf(1.0f),             1, 3, 3, FragmentEffectSaturation::class.java),
+    CONTRAST         (EffectType.FRAGMENT,    floatArrayOf(1.0f),             1, 3, 3, FragmentEffectContrast::class.java),
+    SMOOTH_CONTRAST  (EffectType.FRAGMENT,    floatArrayOf(1.0f),             1, 3, 3, FragmentEffectContrast::class.java),
+
+    BLUR             (EffectType.POSTPROCESS, floatArrayOf(0.0f),             2, 0, 0, PostprocessEffectBlur::class.java),
+    GLOW             (EffectType.POSTPROCESS, floatArrayOf(0.0f),             6, 0, 0, PostprocessEffectGlow::class.java),
+    BORDER           (EffectType.POSTPROCESS, floatArrayOf(0.0f),             5, 0, 0, PostprocessEffectBorder::class.java),
+    ;
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+
+    val type: EffectType
+    val unity: FloatArray
+    private val dimension: Int
+    private val regionDim: Int
+    private val centerDim: Int
+    val effectClass: Class<out Effect?>
+
+    val effectDimension: Int get() = dimensions[ordinal]
+    val regionDimension: Int get() = Companion.regionDimension[ordinal]
+    val centerDimension: Int get() = Companion.centerDimension[ordinal]
+
+    companion object
     {
-    int i=0;
-
-    dimensions      = new int[LENGTH];
-    regionDimension = new int[LENGTH];
-    centerDimension = new int[LENGTH];
-    names           = new EffectName[LENGTH];
-
-    for(EffectName name: EffectName.values())
-      {
-      dimensions[i]      = name.dimension;
-      regionDimension[i] = name.regionDim;
-      centerDimension[i] = name.centerDim;
-      names[i]           = name;
-
-      i++;
-      }
+        val LENGTH: Int = entries.size
+        private val dimensions: IntArray
+        private val regionDimension: IntArray
+        private val centerDimension: IntArray
+        private val names: Array<EffectName?> // copy the values() to a local variable so that we
+                                              // don't have to keep recreating the array every time
+        init
+        {
+            dimensions      = IntArray(LENGTH)
+            regionDimension = IntArray(LENGTH)
+            centerDimension = IntArray(LENGTH)
+            names           = arrayOfNulls(LENGTH)
+
+            for ( (i,name) in entries.withIndex() )
+            {
+                dimensions[i]      = name.dimension
+                regionDimension[i] = name.regionDim
+                centerDimension[i] = name.centerDim
+                names[i]           = name
+            }
+        }
     }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  float[] getUnity()
-    {
-    return unity;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  EffectName(EffectType type, float[] unity, int dimension, int regionDim,
-             int centerDim, Class<? extends Effect> effectClass )
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    init
     {
-    this.type        = type;
-    this.unity       = unity;
-    this.dimension   = dimension;
-    this.regionDim   = regionDim;
-    this.centerDim   = centerDim;
-    this.effectClass = effectClass;
+        this.type        = type
+        this.unity       = unity
+        this.dimension   = dim
+        this.regionDim   = regionDim
+        this.centerDim   = centerDim
+        this.effectClass = effectClass
     }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Returns the Type of an individual Effect. For example, EffectName.ROTATE.getType() will
- * return EffectType.MATRIX.
- * @return type of the effect.
- */
-  public EffectType getType()
-    {
-    return type;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Returns the Class of an individual Effect. For example, EffectName.ROTATE.getEffectClass()
- * returns MatrixEffectRotate.class.
- * @return effect class.
- */
-  public Class<? extends Effect> getEffectClass()
-    {
-    return effectClass;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Returns the i-th EffectName.
- * <p>
- * If you want to loop over all possible Effects, you need this.
- */
-  public static EffectName getName(int ordinal)
-    {
-    return names[ordinal];
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Returns the dimension of an Effect (in other words, the number of interpolated values).
- * @return dimension of the Effect.
- */
-  public int getEffectDimension() { return dimensions[ordinal()]; }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * What is the dimension of the Region supported by this effect?
- * @return Dimension of the Region supported (0-region not supported at all).
- */
-  public int getRegionDimension() { return regionDimension[ordinal()]; }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * What is the dimension of the Center supported by this effect?
- * @return Dimension of the Center supported (0-center not supported at all).
- */
-  public int getCenterDimension() { return centerDimension[ordinal()]; }
-  }
-
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    fun getName(ordinal: Int): EffectName? = names[ordinal]
+}
\ No newline at end of file
diff --git a/src/main/java/org/distorted/library/effect/EffectQuality.kt b/src/main/java/org/distorted/library/effect/EffectQuality.kt
index ad443f5..a79074a 100644
--- a/src/main/java/org/distorted/library/effect/EffectQuality.kt
+++ b/src/main/java/org/distorted/library/effect/EffectQuality.kt
@@ -18,73 +18,37 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.effect;
+package org.distorted.library.effect
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-
-import org.distorted.library.main.DistortedEffects;
-
 /**
  * A list of quality levels.
- * <p>
+ *
  * One can set quality of a Postprocessing Effect to one of those. The lower the quality, the faster
  * the rendering will be.
  *
  * @see DistortedEffects
  */
-public enum EffectQuality
-  {
-  HIGHEST  ( 0, 1.000f ),   // has to start from 0
-  HIGH     ( 1, 0.500f ),
-  MEDIUM   ( 2, 0.250f ),
-  LOW      ( 3, 0.125f );
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Numof of possible qualities.
- */
-  public static final int LENGTH = values().length;
-
-  private final int level;
-  private final float mipmap;
-
-  private static final EffectQuality[] qualities;
-
-  static
+enum class EffectQuality(val level: Int, private val mipmap: Float)
+{
+    HIGHEST(0, 1.000f),  // has to start from 0
+    HIGH   (1, 0.500f),
+    MEDIUM (2, 0.250f),
+    LOW    (3, 0.125f);
+
+    companion object
     {
-    int i=0;
-    qualities= new EffectQuality[LENGTH];
-    for(EffectQuality q: EffectQuality.values()) qualities[i++] = q;
-    }
+        @JvmField val LENGTH: Int = entries.size
+        private val qualities: Array<EffectQuality?>
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
+        init
+        {
+            var i=0
+            qualities = arrayOfNulls(LENGTH)
+            for (q in entries) qualities[i++] = q
+        }
 
-  EffectQuality(int level, float mipmap)
-    {
-    this.level = level;
-    this.mipmap= mipmap;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public int getLevel()
-    {
-    return level;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public static float getMipmap(int quality)
-    {
-    return qualities[quality].mipmap;
+        @JvmStatic fun getMipmap(quality: Int): Float = qualities[quality]!!.mipmap
     }
-  }
+}
 
diff --git a/src/main/java/org/distorted/library/effect/EffectType.kt b/src/main/java/org/distorted/library/effect/EffectType.kt
index 264adce..ce0e473 100644
--- a/src/main/java/org/distorted/library/effect/EffectType.kt
+++ b/src/main/java/org/distorted/library/effect/EffectType.kt
@@ -18,77 +18,36 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.effect;
+package org.distorted.library.effect
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-
 /**
  * Types of Effects one can add to the DistortedEffects queues.
- * <p>
+ *
  * Each effect type goes to an independent queue; the queues get executed one-by-one
  * and are each a class descendant from EffectQueue.
  */
-
-public enum EffectType
-  {
-  /**
-   * Effects that change the ModelView matrix: Rotations, Moves, Shears, Scales.
-   */
-  MATRIX,
-  /**
-   * Effects that get executed in the Vertex shader: various distortions of the vertices.
-   */
-  VERTEX,
-  /**
-   * Effects executed in the Fragment shader: changes of color, hue, transparency levels, etc.
-   */
-  FRAGMENT,
-  /**
-   * Postprocessing effects done to the texture the first stage fragment shader created
-   */
-  POSTPROCESS;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Number of effect types.
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public static final int LENGTH = values().length;
-/**
- * Needed when we do bitwise operations on Effect Types.
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public static final int MASK= (1<<LENGTH)-1;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public static void reset(int[] maxtable)
+enum class EffectType
+{
+    MATRIX,      // Effects that change the ModelView matrix: Rotations, Moves, Shears, Scales.
+    VERTEX,      // Effects that get executed in the Vertex shader: various distortions of the vertices.
+    FRAGMENT,    // Effects executed in the Fragment shader: changes of color, hue, transparency levels, etc.
+    POSTPROCESS; // Postprocessing effects done to the texture the first stage fragment shader created
+
+    companion object
     {
-    maxtable[0] =100;  // By default, there can be a maximum 100 MATRIX effects in a single
-                       // EffectQueueMatrix at any given time. This can be changed with a call
-                       // to EffectQueueMatrix.setMax(int)
-    maxtable[1] = 30;  // Max 30 VERTEX Effects
-    maxtable[2] =  5;  // Max 5 FRAGMENT Effects
-    maxtable[3] =  3;  // Max 3 POSTPROCESSING Effects
+        @JvmField val LENGTH: Int = entries.size
+        @JvmField val MASK: Int = (1 shl LENGTH)-1
+        @JvmStatic fun reset(maxtable: IntArray)
+        {
+            maxtable[0] = 100 // By default, there can be a maximum 100 MATRIX effects in a single
+                              // EffectQueueMatrix at any given time. This can be changed with a call
+                              // to EffectQueueMatrix.setMax(int)
+            maxtable[1] = 30  // Max 30 VERTEX Effects
+            maxtable[2] = 5   // Max 5 FRAGMENT Effects
+            maxtable[3] = 3   // Max 3 POSTPROCESSING Effects
+        }
+
+        fun getType(ordinal: Int): EffectType = entries[ordinal]
     }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Returns the i-th EffectType.
- * <p>
- * If you want to loop over all possible effect types, you need this.
- */
-  public static EffectType getType(int ordinal)
-    {
-    return values()[ordinal];
-    }
-
-  }
+}
diff --git a/src/main/java/org/distorted/library/effect/FragmentEffect.kt b/src/main/java/org/distorted/library/effect/FragmentEffect.kt
index 19ec744..0246926 100644
--- a/src/main/java/org/distorted/library/effect/FragmentEffect.kt
+++ b/src/main/java/org/distorted/library/effect/FragmentEffect.kt
@@ -18,117 +18,65 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.effect;
+package org.distorted.library.effect
 
-import org.distorted.library.effectqueue.EffectQueue;
-import org.distorted.library.type.Static3D;
+import org.distorted.library.effectqueue.EffectQueue
+import org.distorted.library.type.Static3D
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Abstract class that represents an Effect that works by injecting certain code into the main Fragment shader.
  */
-public abstract class FragmentEffect extends Effect
-  {
-  /**
-   * 12: 4-per effect interpolated values, 3 dimensional Center (+padding), 3 dimensional Region (+padding).
-   */
-  public static final int NUM_FLOAT_UNIFORMS = 12;
-  /**
-   * 4: the name, unused, unused, unused
-   */
-  public static final int NUM_INT_UNIFORMS = 4;
+abstract class FragmentEffect internal constructor(name: EffectName) : Effect(name)
+{
+    override fun addQueue(queue: EffectQueue) { /* NO OP */ }
+    override fun remQueue(queue: EffectQueue) { /* NO OP */ }
 
-  static final int CENTER_OFFSET = 5;
-  static final int REGION_OFFSET = 8;
-  private static String mGLSL = "";
-  private static int mNumEnabled = 0;
-
-  final static Static3D MAX_REGION = new Static3D(1000000,1000000,1000000);
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  FragmentEffect(EffectName name)
-    {
-    super(name);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// prepare code to be injected into the 'main_fragment_shader' main() function.
-
-  static void addEffect(EffectName not_smooth, EffectName yes_smooth, String code)
-    {
-    int effect1 = not_smooth.ordinal();
-    int effect2 = yes_smooth.ordinal();
-
-    if( mEnabled[effect1] ) return;
-
-    mEnabled[effect1] = true;
-    mNumEnabled ++;
-
-    mGLSL +=
-
-         "if( fProperties[i].x =="+effect1+")\n"
-        +  "{\n"
-        +  "degree = sign(degree); \n"
-        +   code +"\n"
-        +  "}\n"
-        +"else\n"
-        +"if( fProperties[i].x =="+effect2+")\n"
-        +  "{\n"
-        +   code +"\n"
-        +  "}\n"
-        +"else\n";
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public static String getGLSL()
-    {
-    return mGLSL + "{}";
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  static void destroyStatics()
-    {
-    mNumEnabled = 0;
-    mGLSL = "";
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public void addQueue(EffectQueue queue)
-    {
-    // NO OP
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public void remQueue(EffectQueue queue)
-    {
-    // NO OP
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Return the number of Fragment effects enabled.
- */
-  public static int getNumEnabled()
+    companion object
     {
-    return mNumEnabled;
+        const val NUM_FLOAT_UNIFORMS: Int = 12 // 4-per effect interpolated values, 3 dimensional Center (+padding), 3 dimensional Region (+padding).
+        const val NUM_INT_UNIFORMS  : Int = 4  // the name, unused, unused, unused
+        const val CENTER_OFFSET: Int = 5
+        const val REGION_OFFSET: Int = 8
+        private var mGLSL = ""
+        private var numEnabled: Int = 0  //  number of Fragment effects enabled.
+        val MAX_REGION: Static3D = Static3D(1000000f, 1000000f, 1000000f)
+        @JvmStatic val gLSL: String get() = mGLSL+"{}"
+
+        ///////////////////////////////////////////////////////////////////////////////////////////////////
+        // prepare code to be injected into the 'main_fragment_shader' main() function.
+        fun addEffect(notSmooth: EffectName, yesSmooth: EffectName, code: String)
+        {
+            val effect1 = notSmooth.ordinal
+            val effect2 = yesSmooth.ordinal
+
+            if (mEnabled[effect1]) return
+
+            mEnabled[effect1] = true
+            numEnabled++
+
+            mGLSL +=
+                ("""
+                    if( fProperties[i].x ==$effect1)
+                    {
+                    degree = sign(degree); 
+                    $code
+                    }
+                    else
+                    if( fProperties[i].x ==$effect2)
+                    {
+                    $code
+                    }
+                    else
+                    
+                    """.trimIndent())
+        }
+
+        ///////////////////////////////////////////////////////////////////////////////////////////////////
+        fun destroyStatics()
+        {
+            numEnabled = 0
+            mGLSL = ""
+        }
     }
-  }
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/src/main/java/org/distorted/library/effect/FragmentEffectAlpha.kt b/src/main/java/org/distorted/library/effect/FragmentEffectAlpha.kt
index b88b1f1..fadedee 100644
--- a/src/main/java/org/distorted/library/effect/FragmentEffectAlpha.kt
+++ b/src/main/java/org/distorted/library/effect/FragmentEffectAlpha.kt
@@ -18,77 +18,77 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.effect;
+package org.distorted.library.effect
 
-import org.distorted.library.type.Data1D;
-import org.distorted.library.type.Data3D;
-import org.distorted.library.type.Static3D;
+import org.distorted.library.type.Data1D
+import org.distorted.library.type.Data3D
+import org.distorted.library.type.Static3D
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Make a certain Region change its transparency level.
  */
-public class FragmentEffectAlpha extends FragmentEffect
-  {
-  private final Data1D mAlpha;
-  private final Data3D mCenter;
-  private final Data3D mRegion;
+class FragmentEffectAlpha : FragmentEffect
+{
+    private val mAlpha: Data1D
+    private val mCenter: Data3D
+    private val mRegion: Data3D
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public boolean compute(float[] uniforms, int index, long currentDuration, long step )
+    companion object
     {
-    mCenter.get(uniforms, index+CENTER_OFFSET, currentDuration, step);
-    mRegion.get(uniforms, index+REGION_OFFSET, currentDuration, step);
-    return mAlpha.get(uniforms,index, currentDuration, step);
+        /**
+         * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
+         */
+        @JvmStatic
+        fun enable()
+        {
+            addEffect(EffectName.ALPHA, EffectName.SMOOTH_ALPHA,
+                "color.a *= (degree*(fUniforms[effect].x-1.0)+1.0);")
+        }
     }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Makes a certain sub-region of the Object smoothly change its transparency level.
- *
- * @param alpha  level of transparency we want to have at any given moment: pixel.a *= alpha.
- *               Valid range: <0,1>
- * @param center center of the Effect (point in 3D).
- * @param region Region this Effect is limited to (3 radii defining an ellipsoid).
- * @param smooth If true, the level of 'alpha' will smoothly fade out towards the edges of the region.
- */
-  public FragmentEffectAlpha(Data1D alpha, Data3D center, Data3D region, boolean smooth)
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Only for use by the library itself.
+     *
+     * @y.exclude
+     */
+    override fun compute(uniforms: FloatArray, index: Int, currentDuration: Long, step: Long): Boolean
     {
-    super(smooth? EffectName.SMOOTH_ALPHA:EffectName.ALPHA);
-    mAlpha  = alpha;
-    mCenter = center;
-    mRegion = (region==null ? MAX_REGION : region);
+        mCenter.get(uniforms, index+CENTER_OFFSET, currentDuration, step)
+        mRegion.get(uniforms, index+REGION_OFFSET, currentDuration, step)
+        return mAlpha.get(uniforms, index, currentDuration, step)
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Makes the whole Object smoothly change its transparency level.
- *
- * @param alpha  level of transparency we want to have at any given moment: pixel.a *= alpha.
- *               Valid range: <0,1>
- */
-  public FragmentEffectAlpha(Data1D alpha)
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    // PUBLIC API
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Makes a certain sub-region of the Object smoothly change its transparency level.
+     *
+     * @param alpha  level of transparency we want to have at any given moment: pixel.a *= alpha.
+     * Valid range: <0,1>
+     * @param center center of the Effect (point in 3D).
+     * @param region Region this Effect is limited to (3 radii defining an ellipsoid).
+     * @param smooth If true, the level of 'alpha' will smoothly fade out towards the edges of the region.
+     */
+    constructor(alpha: Data1D, center: Data3D, region: Data3D?, smooth: Boolean) : super(if (smooth) EffectName.SMOOTH_ALPHA else EffectName.ALPHA)
     {
-    super(EffectName.ALPHA);
-    mAlpha  = alpha;
-    mCenter = new Static3D(0,0,0);
-    mRegion = MAX_REGION;
+        mAlpha = alpha
+        mCenter = center
+        mRegion = (region ?: MAX_REGION)
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
- */
-  public static void enable()
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Makes the whole Object smoothly change its transparency level.
+     *
+     * @param alpha  level of transparency we want to have at any given moment: pixel.a *= alpha.
+     * Valid range: <0,1>
+     */
+    constructor(alpha: Data1D) : super(EffectName.ALPHA)
     {
-    addEffect( EffectName.ALPHA,EffectName.SMOOTH_ALPHA,
-               "color.a *= (degree*(fUniforms[effect].x-1.0)+1.0);" );
+        mAlpha = alpha
+        mCenter = Static3D(0f,0f,0f)
+        mRegion = MAX_REGION
     }
-  }
+}
diff --git a/src/main/java/org/distorted/library/effect/FragmentEffectBrightness.kt b/src/main/java/org/distorted/library/effect/FragmentEffectBrightness.kt
index 5071bdb..152dcfc 100644
--- a/src/main/java/org/distorted/library/effect/FragmentEffectBrightness.kt
+++ b/src/main/java/org/distorted/library/effect/FragmentEffectBrightness.kt
@@ -18,75 +18,75 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.effect;
+package org.distorted.library.effect
 
-import org.distorted.library.type.Data1D;
-import org.distorted.library.type.Data3D;
-import org.distorted.library.type.Static3D;
+import org.distorted.library.type.Data1D
+import org.distorted.library.type.Data3D
+import org.distorted.library.type.Static3D
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Make a certain Region change its brightness level.
  */
-public class FragmentEffectBrightness extends FragmentEffect
-  {
-  private final Data1D mBrightness;
-  private final Data3D mCenter;
-  private final Data3D mRegion;
+class FragmentEffectBrightness : FragmentEffect
+{
+    private val mBrightness: Data1D
+    private val mCenter: Data3D
+    private val mRegion: Data3D
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public boolean compute(float[] uniforms, int index, long currentDuration, long step )
+    companion object
     {
-    mCenter.get(uniforms, index+CENTER_OFFSET, currentDuration, step);
-    mRegion.get(uniforms, index+REGION_OFFSET, currentDuration, step);
-    return mBrightness.get(uniforms,index,currentDuration,step);
+        /**
+         * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
+         */
+        @JvmStatic
+        fun enable()
+        {
+            addEffect(EffectName.BRIGHTNESS, EffectName.SMOOTH_BRIGHTNESS,
+                "color.rgb = mix(vec3(0.0,0.0,0.0), color.rgb, degree*(fUniforms[effect].x-1.0)+1.0 );")
+        }
     }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Makes a certain sub-region of the Object smoothly change its brightness level.
- *
- * @param brightness level of brightness we want to have at any given moment. Valid range: <0,infinity)
- * @param center center of the Effect (point in 3D).
- * @param region Region this Effect is limited to (3 radii defining an ellipsoid).
- * @param smooth     If true, the level of 'brightness' will smoothly fade out towards the edges of the region.
- */
-  public FragmentEffectBrightness(Data1D brightness, Data3D center, Data3D region, boolean smooth)
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Only for use by the library itself.
+     *
+     * @y.exclude
+     */
+    override fun compute(uniforms: FloatArray, index: Int, currentDuration: Long, step: Long): Boolean
     {
-    super(smooth?EffectName.SMOOTH_BRIGHTNESS:EffectName.BRIGHTNESS);
-    mBrightness = brightness;
-    mCenter = center;
-    mRegion = (region==null ? MAX_REGION : region);
+        mCenter.get(uniforms, index+CENTER_OFFSET, currentDuration, step)
+        mRegion.get(uniforms, index+REGION_OFFSET, currentDuration, step)
+        return mBrightness.get(uniforms, index, currentDuration, step)
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Makes the whole Object smoothly change its brightness level.
- *
- * @param brightness level of brightness we want to have at any given moment. Valid range: <0,infinity)
- */
-  public FragmentEffectBrightness(Data1D brightness)
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    // PUBLIC API
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Makes a certain sub-region of the Object smoothly change its brightness level.
+     *
+     * @param brightness level of brightness we want to have at any given moment. Valid range: <0,infinity)
+     * @param center center of the Effect (point in 3D).
+     * @param region Region this Effect is limited to (3 radii defining an ellipsoid).
+     * @param smooth     If true, the level of 'brightness' will smoothly fade out towards the edges of the region.
+     */
+    constructor(brightness: Data1D, center: Data3D, region: Data3D?, smooth: Boolean) : super(if (smooth) EffectName.SMOOTH_BRIGHTNESS else EffectName.BRIGHTNESS)
     {
-    super(EffectName.BRIGHTNESS);
-    mBrightness = brightness;
-    mCenter = new Static3D(0,0,0);
-    mRegion = MAX_REGION;
+        mBrightness = brightness
+        mCenter = center
+        mRegion = (region ?: MAX_REGION)
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
- */
-  public static void enable()
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Makes the whole Object smoothly change its brightness level.
+     *
+     * @param brightness level of brightness we want to have at any given moment. Valid range: <0,infinity)
+     */
+    constructor(brightness: Data1D) : super(EffectName.BRIGHTNESS)
     {
-    addEffect( EffectName.BRIGHTNESS,EffectName.SMOOTH_BRIGHTNESS,
-               "color.rgb = mix(vec3(0.0,0.0,0.0), color.rgb, degree*(fUniforms[effect].x-1.0)+1.0 );" );
+        mBrightness = brightness
+        mCenter = Static3D(0f,0f,0f)
+        mRegion = MAX_REGION
     }
-  }
+}
diff --git a/src/main/java/org/distorted/library/effect/FragmentEffectChroma.kt b/src/main/java/org/distorted/library/effect/FragmentEffectChroma.kt
index 7e081fe..13f58b1 100644
--- a/src/main/java/org/distorted/library/effect/FragmentEffectChroma.kt
+++ b/src/main/java/org/distorted/library/effect/FragmentEffectChroma.kt
@@ -18,85 +18,84 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.effect;
+package org.distorted.library.effect
 
-import org.distorted.library.type.Data1D;
-import org.distorted.library.type.Data3D;
-import org.distorted.library.type.Static3D;
+import org.distorted.library.type.Data1D
+import org.distorted.library.type.Data3D
+import org.distorted.library.type.Static3D
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Make a certain Region change its color.
  */
-public class FragmentEffectChroma extends FragmentEffect
-  {
-  private final Data1D mBlend;
-  private final Data3D mColor;
-  private final Data3D mCenter;
-  private final Data3D mRegion;
+class FragmentEffectChroma : FragmentEffect
+{
+    private val mBlend: Data1D
+    private val mColor: Data3D
+    private val mCenter: Data3D
+    private val mRegion: Data3D
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public boolean compute(float[] uniforms, int index, long currentDuration, long step )
+    companion object
     {
-    mColor.get(uniforms,index+1,currentDuration,step);
-    mCenter.get(uniforms,index+CENTER_OFFSET,currentDuration,step);
-    mRegion.get(uniforms,index+REGION_OFFSET,currentDuration,step);
-    return mBlend.get(uniforms,index,currentDuration,step);
+        /**
+         * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
+         */
+        fun enable()
+        {
+            addEffect(EffectName.CHROMA, EffectName.SMOOTH_CHROMA,
+                "color.rgb = mix(color.rgb, fUniforms[effect].yzw, degree*fUniforms[effect].x);")
+        }
     }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Makes a certain sub-region of the Object smoothly change all three of its RGB components.
- *
- * @param blend  level of blend a given pixel will be mixed with the next parameter 'color':
- *               pixel = (1-level)*pixel + level*color.
- *               Valid range: <0,1>
- * @param color  Color to mix. (1,0,0) is RED.
- * @param center center of the Effect (point in 3D).
- * @param region Region this Effect is limited to (3 radii defining an ellipsoid).
- * @param smooth If true, the level of 'blend' will smoothly fade out towards the edges of the region.
- */
-  public FragmentEffectChroma(Data1D blend, Data3D color, Data3D center, Data3D region, boolean smooth)
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Only for use by the library itself.
+     *
+     * @y.exclude
+     */
+    override fun compute(uniforms: FloatArray, index: Int, currentDuration: Long, step: Long): Boolean
     {
-    super(smooth?EffectName.SMOOTH_CHROMA:EffectName.CHROMA);
-    mBlend  = blend;
-    mColor  = color;
-    mCenter = center;
-    mRegion = (region==null ? MAX_REGION : region);
+        mColor.get(uniforms, index+1, currentDuration, step)
+        mCenter.get(uniforms, index+CENTER_OFFSET, currentDuration, step)
+        mRegion.get(uniforms, index+REGION_OFFSET, currentDuration, step)
+        return mBlend.get(uniforms, index, currentDuration, step)
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Makes the whole Object smoothly change all three of its RGB components.
- *
- * @param blend  level of blend a given pixel will be mixed with the next parameter 'color':
- *               pixel = (1-level)*pixel + level*color.
- *               Valid range: <0,1>
- * @param color  Color to mix. (1,0,0) is RED.
- */
-  public FragmentEffectChroma(Data1D blend, Data3D color)
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    // PUBLIC API
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Makes a certain sub-region of the Object smoothly change all three of its RGB components.
+     *
+     * @param blend  level of blend a given pixel will be mixed with the next parameter 'color':
+     * pixel = (1-level)*pixel + level*color.
+     * Valid range: <0,1>
+     * @param color  Color to mix. (1,0,0) is RED.
+     * @param center center of the Effect (point in 3D).
+     * @param region Region this Effect is limited to (3 radii defining an ellipsoid).
+     * @param smooth If true, the level of 'blend' will smoothly fade out towards the edges of the region.
+     */
+    constructor(blend: Data1D, color: Data3D, center: Data3D, region: Data3D?, smooth: Boolean) : super(if (smooth) EffectName.SMOOTH_CHROMA else EffectName.CHROMA)
     {
-    super(EffectName.CHROMA);
-    mBlend = blend;
-    mColor = color;
-    mCenter = new Static3D(0,0,0);
-    mRegion = MAX_REGION;
+        mBlend = blend
+        mColor = color
+        mCenter = center
+        mRegion = (region ?: MAX_REGION)
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
- */
-  public static void enable()
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Makes the whole Object smoothly change all three of its RGB components.
+     *
+     * @param blend  level of blend a given pixel will be mixed with the next parameter 'color':
+     * pixel = (1-level)*pixel + level*color.
+     * Valid range: <0,1>
+     * @param color  Color to mix. (1,0,0) is RED.
+     */
+    constructor(blend: Data1D, color: Data3D) : super(EffectName.CHROMA)
     {
-    addEffect( EffectName.CHROMA,EffectName.SMOOTH_CHROMA,
-               "color.rgb = mix(color.rgb, fUniforms[effect].yzw, degree*fUniforms[effect].x);" );
+        mBlend = blend
+        mColor = color
+        mCenter = Static3D(0f,0f,0f)
+        mRegion = MAX_REGION
     }
-  }
+}
diff --git a/src/main/java/org/distorted/library/effect/FragmentEffectContrast.kt b/src/main/java/org/distorted/library/effect/FragmentEffectContrast.kt
index 1652554..ecdb513 100644
--- a/src/main/java/org/distorted/library/effect/FragmentEffectContrast.kt
+++ b/src/main/java/org/distorted/library/effect/FragmentEffectContrast.kt
@@ -17,76 +17,74 @@
 // License along with this library; if not, write to the Free Software                           //
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
+package org.distorted.library.effect
 
-package org.distorted.library.effect;
-
-import org.distorted.library.type.Data1D;
-import org.distorted.library.type.Data3D;
-import org.distorted.library.type.Static3D;
+import org.distorted.library.type.Data1D
+import org.distorted.library.type.Data3D
+import org.distorted.library.type.Static3D
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Make a certain Region change its contrast level.
  */
-public class FragmentEffectContrast extends FragmentEffect
-  {
-  private final Data1D mContrast;
-  private final Data3D mCenter;
-  private final Data3D mRegion;
+class FragmentEffectContrast : FragmentEffect
+{
+    private val mContrast: Data1D
+    private val mCenter: Data3D
+    private val mRegion: Data3D
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public boolean compute(float[] uniforms, int index, long currentDuration, long step )
+    companion object
     {
-    mCenter.get(uniforms,index+CENTER_OFFSET,currentDuration,step);
-    mRegion.get(uniforms,index+REGION_OFFSET,currentDuration,step);
-    return mContrast.get(uniforms,index,currentDuration,step);
+        /**
+         * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
+         */
+        fun enable()
+        {
+            addEffect(EffectName.CONTRAST, EffectName.SMOOTH_CONTRAST,
+                "color.rgb = mix(vec3(0.5,0.5,0.5), color.rgb, degree*(fUniforms[effect].x-1.0)+1.0 );")
+        }
     }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Makes a certain sub-region of the Object smoothly change its contrast level.
- *
- * @param contrast level of contrast we want to have at any given moment. Valid range: <0,infinity)
- * @param center center of the Effect (point in 3D).
- * @param region Region this Effect is limited to (3 radii defining an ellipsoid).
- * @param smooth   If true, the level of 'contrast' will smoothly fade out towards the edges of the region.
- */
-  public FragmentEffectContrast(Data1D contrast, Data3D center, Data3D region, boolean smooth)
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Only for use by the library itself.
+     *
+     * @y.exclude
+     */
+    override fun compute(uniforms: FloatArray, index: Int, currentDuration: Long, step: Long): Boolean
     {
-    super(smooth?EffectName.SMOOTH_CONTRAST:EffectName.CONTRAST);
-    mContrast = contrast;
-    mCenter = center;
-    mRegion = (region==null ? MAX_REGION : region);
+        mCenter.get(uniforms, index+CENTER_OFFSET, currentDuration, step)
+        mRegion.get(uniforms, index+REGION_OFFSET, currentDuration, step)
+        return mContrast.get(uniforms, index, currentDuration, step)
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Makes the whole Object smoothly change its contrast level.
- *
- * @param contrast level of contrast we want to have at any given moment. Valid range: <0,infinity)
- */
-  public FragmentEffectContrast(Data1D contrast)
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    // PUBLIC API
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Makes a certain sub-region of the Object smoothly change its contrast level.
+     *
+     * @param contrast level of contrast we want to have at any given moment. Valid range: <0,infinity)
+     * @param center center of the Effect (point in 3D).
+     * @param region Region this Effect is limited to (3 radii defining an ellipsoid).
+     * @param smooth   If true, the level of 'contrast' will smoothly fade out towards the edges of the region.
+     */
+    constructor(contrast: Data1D, center: Data3D, region: Data3D?, smooth: Boolean) : super(if (smooth) EffectName.SMOOTH_CONTRAST else EffectName.CONTRAST)
     {
-    super(EffectName.CONTRAST);
-    mContrast = contrast;
-    mCenter = new Static3D(0,0,0);
-    mRegion = MAX_REGION;
+        mContrast = contrast
+        mCenter = center
+        mRegion = (region ?: MAX_REGION)
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
- */
-  public static void enable()
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Makes the whole Object smoothly change its contrast level.
+     *
+     * @param contrast level of contrast we want to have at any given moment. Valid range: <0,infinity)
+     */
+    constructor(contrast: Data1D) : super(EffectName.CONTRAST)
     {
-    addEffect( EffectName.CONTRAST,EffectName.SMOOTH_CONTRAST,
-               "color.rgb = mix(vec3(0.5,0.5,0.5), color.rgb, degree*(fUniforms[effect].x-1.0)+1.0 );" );
+        mContrast = contrast
+        mCenter = Static3D(0f, 0f, 0f)
+        mRegion = MAX_REGION
     }
-  }
+}
diff --git a/src/main/java/org/distorted/library/effect/FragmentEffectSaturation.kt b/src/main/java/org/distorted/library/effect/FragmentEffectSaturation.kt
index ae32854..466fa48 100644
--- a/src/main/java/org/distorted/library/effect/FragmentEffectSaturation.kt
+++ b/src/main/java/org/distorted/library/effect/FragmentEffectSaturation.kt
@@ -18,78 +18,77 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.effect;
+package org.distorted.library.effect
 
-import org.distorted.library.type.Data1D;
-import org.distorted.library.type.Data3D;
-import org.distorted.library.type.Static3D;
+import org.distorted.library.type.Data1D
+import org.distorted.library.type.Data3D
+import org.distorted.library.type.Static3D
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Make a certain Region change its color saturation.
  */
-public class FragmentEffectSaturation extends FragmentEffect
-  {
-  private final Data1D mSaturation;
-  private final Data3D mCenter;
-  private final Data3D mRegion;
+class FragmentEffectSaturation : FragmentEffect
+{
+    private val mSaturation: Data1D
+    private val mCenter: Data3D
+    private val mRegion: Data3D
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public boolean compute(float[] uniforms, int index, long currentDuration, long step )
+    companion object
     {
-    mCenter.get(uniforms,index+CENTER_OFFSET,currentDuration,step);
-    mRegion.get(uniforms,index+REGION_OFFSET,currentDuration,step);
-    return mSaturation.get(uniforms,index,currentDuration,step);
+        /**
+         * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
+         */
+        fun enable()
+        {
+            addEffect(EffectName.SATURATION, EffectName.SMOOTH_SATURATION,
+                """
+                    float luminance = dot(vec3( 0.2125, 0.7154, 0.0721 ),color.rgb);
+                    color.rgb = mix(vec3(luminance,luminance,luminance), color.rgb, degree*(fUniforms[effect].x-1.0)+1.0 ); 
+                    """.trimIndent())
+        }
     }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Makes a certain sub-region of the Object smoothly change its saturation level.
- *
- * @param saturation level of saturation we want to have at any given moment. Valid range: <0,infinity)
- * @param center center of the Effect (point in 3D).
- * @param region Region this Effect is limited to (3 radii defining an ellipsoid).
- * @param smooth     If true, the level of 'saturation' will smoothly fade out towards the edges of the region.
- */
-  public FragmentEffectSaturation(Data1D saturation, Data3D center, Data3D region, boolean smooth)
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Only for use by the library itself.
+     *
+     * @y.exclude
+     */
+    override fun compute(uniforms: FloatArray, index: Int, currentDuration: Long, step: Long): Boolean
     {
-    super(smooth?EffectName.SMOOTH_SATURATION:EffectName.SATURATION);
-
-    mSaturation = saturation;
-    mCenter = center;
-    mRegion = (region==null ? MAX_REGION : region);
+        mCenter.get(uniforms, index+CENTER_OFFSET, currentDuration, step)
+        mRegion.get(uniforms, index+REGION_OFFSET, currentDuration, step)
+        return mSaturation.get(uniforms, index, currentDuration, step)
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Makes the whole Object smoothly change its saturation level.
- *
- * @param saturation level of saturation we want to have at any given moment. Valid range: <0,infinity)
- */
-  public FragmentEffectSaturation(Data1D saturation)
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    // PUBLIC API
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Makes a certain sub-region of the Object smoothly change its saturation level.
+     *
+     * @param saturation level of saturation we want to have at any given moment. Valid range: <0,infinity)
+     * @param center center of the Effect (point in 3D).
+     * @param region Region this Effect is limited to (3 radii defining an ellipsoid).
+     * @param smooth     If true, the level of 'saturation' will smoothly fade out towards the edges of the region.
+     */
+    constructor(saturation: Data1D, center: Data3D, region: Data3D?, smooth: Boolean) : super(if (smooth) EffectName.SMOOTH_SATURATION else EffectName.SATURATION)
     {
-    super(EffectName.SATURATION);
-
-    mSaturation = saturation;
-    mCenter = new Static3D(0,0,0);
-    mRegion = MAX_REGION;
+        mSaturation = saturation
+        mCenter = center
+        mRegion = (region ?: MAX_REGION)
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
- */
-  public static void enable()
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Makes the whole Object smoothly change its saturation level.
+     *
+     * @param saturation level of saturation we want to have at any given moment. Valid range: <0,infinity)
+     */
+    constructor(saturation: Data1D) : super(EffectName.SATURATION)
     {
-    addEffect( EffectName.SATURATION,EffectName.SMOOTH_SATURATION,
-               "float luminance = dot(vec3( 0.2125, 0.7154, 0.0721 ),color.rgb);\n" +
-               "color.rgb = mix(vec3(luminance,luminance,luminance), color.rgb, degree*(fUniforms[effect].x-1.0)+1.0 ); " );
+        mSaturation = saturation
+        mCenter = Static3D(0f,0f,0f)
+        mRegion = MAX_REGION
     }
-  }
+}
diff --git a/src/main/java/org/distorted/library/effect/MatrixEffect.kt b/src/main/java/org/distorted/library/effect/MatrixEffect.kt
index afc5369..03a7a45 100644
--- a/src/main/java/org/distorted/library/effect/MatrixEffect.kt
+++ b/src/main/java/org/distorted/library/effect/MatrixEffect.kt
@@ -18,69 +18,25 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.effect;
+package org.distorted.library.effect
 
-import org.distorted.library.effectqueue.EffectQueue;
+import org.distorted.library.effectqueue.EffectQueue
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Abstract class that represents an Effect that works by modifying the ModelView matrix.
  */
-public abstract class MatrixEffect extends Effect
-  {
-  /**
-   * 7: 4 per-effect interpolated values + 3 dimensional center.
-   */
-  public static final int NUM_FLOAT_UNIFORMS = 7;
-  /**
-   * 0: nothing
-   */
-  public static final int NUM_INT_UNIFORMS = 1;
+abstract class MatrixEffect internal constructor(name: EffectName) : Effect(name)
+{
+    abstract fun apply(matrixP: FloatArray, matrixV: FloatArray, uniforms: FloatArray, index: Int)
+    override fun addQueue(queue: EffectQueue) { /* NO OP */ }
+    override fun remQueue(queue: EffectQueue) { /* NO OP */ }
 
-  static final int CENTER_OFFSET = 4;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public abstract void apply(float[] matrixP, float[] matrixV, float[] uniforms, int index);
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public void addQueue(EffectQueue queue)
-    {
-    // NO OP
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public void remQueue(EffectQueue queue)
-    {
-    // NO OP
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// empty function for completeness
-
-  static void destroyStatics()
-    {
-
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MatrixEffect(EffectName name)
+    companion object
     {
-    super(name);
+        const val NUM_FLOAT_UNIFORMS: Int = 7  //  4 per-effect interpolated values + 3 dimensional center.
+        const val NUM_INT_UNIFORMS: Int = 1
+        const val CENTER_OFFSET: Int = 4
+        fun destroyStatics() { /* NO OP */ }
     }
-  }
+}
diff --git a/src/main/java/org/distorted/library/effect/MatrixEffectMove.kt b/src/main/java/org/distorted/library/effect/MatrixEffectMove.kt
index a0092ac..8ecb10c 100644
--- a/src/main/java/org/distorted/library/effect/MatrixEffectMove.kt
+++ b/src/main/java/org/distorted/library/effect/MatrixEffectMove.kt
@@ -18,57 +18,33 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.effect;
+package org.distorted.library.effect
 
-import org.distorted.library.helpers.MatrixHelper;
-import org.distorted.library.type.Data3D;
+import org.distorted.library.helpers.MatrixHelper.translate
+import org.distorted.library.type.Data3D
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Move the Mesh by a 3D vector.
  */
-public class MatrixEffectMove extends MatrixEffect
-  {
-  private final Data3D mVector;
+class MatrixEffectMove(vector: Data3D) : MatrixEffect(EffectName.MOVE)
+{
+    private val mVector = vector
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public boolean compute(float[] uniforms, int index, long currentDuration, long step )
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    override fun compute(uniforms: FloatArray, index: Int, currentDuration: Long, step: Long): Boolean
     {
-    return mVector.get(uniforms,index,currentDuration,step);
+        return mVector.get(uniforms, index, currentDuration, step)
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public void apply(float[] matrixP, float[] matrixV, float[] uniforms, int index)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    override fun apply(matrixP: FloatArray, matrixV: FloatArray, uniforms: FloatArray, index: Int)
     {
-    float sx = uniforms[NUM_FLOAT_UNIFORMS*index  ];
-    float sy = uniforms[NUM_FLOAT_UNIFORMS*index+1];
-    float sz = uniforms[NUM_FLOAT_UNIFORMS*index+2];
-
-    MatrixHelper.translate(matrixP, sx, sy, sz);
-    MatrixHelper.translate(matrixV, sx, sy, sz);
-    }
+        val sx = uniforms[NUM_FLOAT_UNIFORMS*index]
+        val sy = uniforms[NUM_FLOAT_UNIFORMS*index+1]
+        val sz = uniforms[NUM_FLOAT_UNIFORMS*index+2]
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Move the Mesh by a 3D vector.
- *
- * @param vector current coordinates of the vector we want to move the Mesh with.
- */
-  public MatrixEffectMove(Data3D vector)
-    {
-    super(EffectName.MOVE);
-    mVector = vector;
+        translate(matrixP, sx, sy, sz)
+        translate(matrixV, sx, sy, sz)
     }
-  }
+}
diff --git a/src/main/java/org/distorted/library/effect/MatrixEffectQuaternion.kt b/src/main/java/org/distorted/library/effect/MatrixEffectQuaternion.kt
index 60bfdc5..cc4c250 100644
--- a/src/main/java/org/distorted/library/effect/MatrixEffectQuaternion.kt
+++ b/src/main/java/org/distorted/library/effect/MatrixEffectQuaternion.kt
@@ -18,121 +18,100 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.effect;
+package org.distorted.library.effect
 
-import org.distorted.library.helpers.MatrixHelper;
-import org.distorted.library.type.Data3D;
-import org.distorted.library.type.Data4D;
+import org.distorted.library.helpers.MatrixHelper.multiply
+import org.distorted.library.helpers.MatrixHelper.translate
+import org.distorted.library.type.Data3D
+import org.distorted.library.type.Data4D
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Rotate the Mesh by a quaternion.
  */
-public class MatrixEffectQuaternion extends MatrixEffect
-  {
-  private final Data4D mQuaternion;
-  private final Data3D mCenter;
+class MatrixEffectQuaternion(quaternion: Data4D, center: Data3D) : MatrixEffect(EffectName.QUATERNION)
+{
+    private val mQuaternion = quaternion
+    private val mCenter     = center
+    private val mTmpMatrix1 = FloatArray(16)
+    private val mTmpMatrix2 = FloatArray(16)
 
-  private final float[] mTmpMatrix1 = new float[16];
-  private final float[] mTmpMatrix2 = new float[16];
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public boolean compute(float[] uniforms, int index, long currentDuration, long step )
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    override fun compute(uniforms: FloatArray, index: Int, currentDuration: Long, step: Long): Boolean
     {
-    mCenter.get(uniforms,index+CENTER_OFFSET,currentDuration,step);
-    return mQuaternion.get(uniforms,index,currentDuration,step);
+        mCenter.get(uniforms, index+CENTER_OFFSET, currentDuration, step)
+        return mQuaternion.get(uniforms, index, currentDuration, step)
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public void apply(float[] matrixP, float[] matrixV, float[] uniforms, int index)
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    override fun apply(matrixP: FloatArray, matrixV: FloatArray, uniforms: FloatArray, index: Int)
     {
-    float qX = uniforms[NUM_FLOAT_UNIFORMS*index  ];
-    float qY = uniforms[NUM_FLOAT_UNIFORMS*index+1];
-    float qZ = uniforms[NUM_FLOAT_UNIFORMS*index+2];
-    float qW = uniforms[NUM_FLOAT_UNIFORMS*index+3];
+        val i = NUM_FLOAT_UNIFORMS*index
 
-    float x = uniforms[NUM_FLOAT_UNIFORMS*index+CENTER_OFFSET  ];
-    float y = uniforms[NUM_FLOAT_UNIFORMS*index+CENTER_OFFSET+1];
-    float z = uniforms[NUM_FLOAT_UNIFORMS*index+CENTER_OFFSET+2];
+        val qX = uniforms[i]
+        val qY = uniforms[i+1]
+        val qZ = uniforms[i+2]
+        val qW = uniforms[i+3]
+        val x  = uniforms[i+CENTER_OFFSET]
+        val y  = uniforms[i+CENTER_OFFSET+1]
+        val z  = uniforms[i+CENTER_OFFSET+2]
 
-    MatrixHelper.translate(matrixP, x, y, z);
-    multiplyByQuat(matrixP, qX, qY, qZ, qW);
-    MatrixHelper.translate(matrixP,-x,-y,-z);
+        translate(matrixP, x, y, z)
+        multiplyByQuat(matrixP, qX, qY, qZ, qW)
+        translate(matrixP, -x, -y, -z)
 
-    MatrixHelper.translate(matrixV, x, y, z);
-    multiplyByQuat(matrixV, qX, qY, qZ, qW);
-    MatrixHelper.translate(matrixV,-x,-y,-z);
+        translate(matrixV, x, y, z)
+        multiplyByQuat(matrixV, qX, qY, qZ, qW)
+        translate(matrixV, -x, -y, -z)
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private void multiplyByQuat(float[] matrix, float X, float Y, float Z, float W)
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    private fun multiplyByQuat(matrix: FloatArray, X: Float, Y: Float, Z: Float, W: Float)
     {
-    float xx= X * X;
-    float xy= X * Y;
-    float xz= X * Z;
-    float xw= X * W;
-    float yy= Y * Y;
-    float yz= Y * Z;
-    float yw= Y * W;
-    float zz= Z * Z;
-    float zw= Z * W;
+        val xx = X*X
+        val xy = X*Y
+        val xz = X*Z
+        val xw = X*W
+        val yy = Y*Y
+        val yz = Y*Z
+        val yw = Y*W
+        val zz = Z*Z
+        val zw = Z*W
 
-    mTmpMatrix1[0]  = 1 - 2 * ( yy + zz );
-    mTmpMatrix1[1]  =     2 * ( xy - zw );
-    mTmpMatrix1[2]  =     2 * ( xz + yw );
-    mTmpMatrix1[4]  =     2 * ( xy + zw );
-    mTmpMatrix1[5]  = 1 - 2 * ( xx + zz );
-    mTmpMatrix1[6]  =     2 * ( yz - xw );
-    mTmpMatrix1[8]  =     2 * ( xz - yw );
-    mTmpMatrix1[9]  =     2 * ( yz + xw );
-    mTmpMatrix1[10] = 1 - 2 * ( xx + yy );
-    mTmpMatrix1[3]  = mTmpMatrix1[7] = mTmpMatrix1[11] = mTmpMatrix1[12] = mTmpMatrix1[13] = mTmpMatrix1[14] = 0;
-    mTmpMatrix1[15] = 1;
+        mTmpMatrix1[ 0] = 1-2*(yy+zz)
+        mTmpMatrix1[ 1] = 2*(xy-zw)
+        mTmpMatrix1[ 2] = 2*(xz+yw)
+        mTmpMatrix1[ 4] = 2*(xy+zw)
+        mTmpMatrix1[ 5] = 1-2*(xx+zz)
+        mTmpMatrix1[ 6] = 2*(yz-xw)
+        mTmpMatrix1[ 8] = 2*(xz-yw)
+        mTmpMatrix1[ 9] = 2*(yz+xw)
+        mTmpMatrix1[10] = 1-2*(xx+yy)
+        mTmpMatrix1[14] = 0f
+        mTmpMatrix1[13] = mTmpMatrix1[14]
+        mTmpMatrix1[12] = mTmpMatrix1[13]
+        mTmpMatrix1[11] = mTmpMatrix1[12]
+        mTmpMatrix1[ 7] = mTmpMatrix1[11]
+        mTmpMatrix1[ 3] = mTmpMatrix1[7]
+        mTmpMatrix1[15] = 1f
 
-    MatrixHelper.multiply(mTmpMatrix2, matrix, mTmpMatrix1);
+        multiply(mTmpMatrix2, matrix, mTmpMatrix1)
 
-    matrix[ 0] = mTmpMatrix2[ 0];
-    matrix[ 1] = mTmpMatrix2[ 1];
-    matrix[ 2] = mTmpMatrix2[ 2];
-    matrix[ 3] = mTmpMatrix2[ 3];
-    matrix[ 4] = mTmpMatrix2[ 4];
-    matrix[ 5] = mTmpMatrix2[ 5];
-    matrix[ 6] = mTmpMatrix2[ 6];
-    matrix[ 7] = mTmpMatrix2[ 7];
-    matrix[ 8] = mTmpMatrix2[ 8];
-    matrix[ 9] = mTmpMatrix2[ 9];
-    matrix[10] = mTmpMatrix2[10];
-    matrix[11] = mTmpMatrix2[11];
-    matrix[12] = mTmpMatrix2[12];
-    matrix[13] = mTmpMatrix2[13];
-    matrix[14] = mTmpMatrix2[14];
-    matrix[15] = mTmpMatrix2[15];
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Rotate the Mesh by a quaternion.
- *
- * @param quaternion Quaternion describing the rotation.
- * @param center     Coordinates of the Point we are rotating around.
- */
-  public MatrixEffectQuaternion(Data4D quaternion, Data3D center )
-    {
-    super(EffectName.QUATERNION);
-    mQuaternion = quaternion;
-    mCenter = center;
+        matrix[ 0] = mTmpMatrix2[0]
+        matrix[ 1] = mTmpMatrix2[1]
+        matrix[ 2] = mTmpMatrix2[2]
+        matrix[ 3] = mTmpMatrix2[3]
+        matrix[ 4] = mTmpMatrix2[4]
+        matrix[ 5] = mTmpMatrix2[5]
+        matrix[ 6] = mTmpMatrix2[6]
+        matrix[ 7] = mTmpMatrix2[7]
+        matrix[ 8] = mTmpMatrix2[8]
+        matrix[ 9] = mTmpMatrix2[9]
+        matrix[10] = mTmpMatrix2[10]
+        matrix[11] = mTmpMatrix2[11]
+        matrix[12] = mTmpMatrix2[12]
+        matrix[13] = mTmpMatrix2[13]
+        matrix[14] = mTmpMatrix2[14]
+        matrix[15] = mTmpMatrix2[15]
     }
-  }
+}
diff --git a/src/main/java/org/distorted/library/effect/MatrixEffectRotate.kt b/src/main/java/org/distorted/library/effect/MatrixEffectRotate.kt
index f642e39..310c0ca 100644
--- a/src/main/java/org/distorted/library/effect/MatrixEffectRotate.kt
+++ b/src/main/java/org/distorted/library/effect/MatrixEffectRotate.kt
@@ -18,81 +18,63 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.effect;
+package org.distorted.library.effect
 
-import org.distorted.library.helpers.MatrixHelper;
-import org.distorted.library.type.Data1D;
-import org.distorted.library.type.Data3D;
+import org.distorted.library.helpers.MatrixHelper.rotateSinCos
+import org.distorted.library.helpers.MatrixHelper.translate
+import org.distorted.library.type.Data1D
+import org.distorted.library.type.Data3D
+import kotlin.math.cos
+import kotlin.math.sin
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Rotate the Mesh by 'angle' degrees around the center, along an axis.
  */
-public class MatrixEffectRotate extends MatrixEffect
-  {
-  private final Data1D mAngle;
-  private final Data3D mAxis, mCenter;
-  private final float[] mTmp1 = new float[16];
-  private final float[] mTmp2 = new float[16];
+class MatrixEffectRotate(angle: Data1D, axis: Data3D, center: Data3D) : MatrixEffect(EffectName.ROTATE)
+{
+    private val mAngle  = angle
+    private val mAxis   = axis
+    private val mCenter = center
+    private val mTmp1   = FloatArray(16)
+    private val mTmp2   = FloatArray(16)
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public boolean compute(float[] uniforms, int index, long currentDuration, long step )
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    override fun compute(uniforms: FloatArray, index: Int, currentDuration: Long, step: Long): Boolean
     {
-    mCenter.get(uniforms,index+CENTER_OFFSET,currentDuration,step);
-    mAxis.get(uniforms,index+1,currentDuration,step);
-    return mAngle.get(uniforms,index,currentDuration,step);
+        mCenter.get(uniforms, index+CENTER_OFFSET, currentDuration, step)
+        mAxis.get(uniforms, index+1, currentDuration, step)
+        return mAngle.get(uniforms, index, currentDuration, step)
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public void apply(float[] matrixP, float[] matrixV, float[] uniforms, int index)
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    override fun apply(matrixP: FloatArray, matrixV: FloatArray, uniforms: FloatArray, index: Int)
     {
-    float angle = uniforms[NUM_FLOAT_UNIFORMS*index  ];
-    float axisX = uniforms[NUM_FLOAT_UNIFORMS*index+1];
-    float axisY = uniforms[NUM_FLOAT_UNIFORMS*index+2];
-    float axisZ = uniforms[NUM_FLOAT_UNIFORMS*index+3];
+        val i = NUM_FLOAT_UNIFORMS*index
 
-    float x = uniforms[NUM_FLOAT_UNIFORMS*index+CENTER_OFFSET  ];
-    float y = uniforms[NUM_FLOAT_UNIFORMS*index+CENTER_OFFSET+1];
-    float z = uniforms[NUM_FLOAT_UNIFORMS*index+CENTER_OFFSET+2];
+        val angle = uniforms[i]
+        val axisX = uniforms[i+1]
+        val axisY = uniforms[i+2]
+        val axisZ = uniforms[i+3]
 
-    double inRadians = Math.PI*angle/180;
-    float sin = (float)Math.sin(inRadians);
-    float cos = (float)Math.cos(inRadians);
+        val x = uniforms[i+CENTER_OFFSET]
+        val y = uniforms[i+CENTER_OFFSET+1]
+        val z = uniforms[i+CENTER_OFFSET+2]
 
-    MatrixHelper.translate(matrixP, x, y, z);
-    MatrixHelper.rotateSinCos(matrixP, mTmp1, mTmp2, sin,cos, axisX, axisY, axisZ);
-    MatrixHelper.translate(matrixP,-x,-y,-z);
+        val inRadians = Math.PI*angle/180
+        val sin = sin(inRadians) as Float
+        val cos = cos(inRadians) as Float
 
-    MatrixHelper.translate(matrixV, x, y, z);
-    MatrixHelper.rotateSinCos(matrixV, mTmp1, mTmp2, sin,cos, axisX, axisY, axisZ);
-    MatrixHelper.translate(matrixV,-x,-y,-z);
-    }
+        translate(matrixP, x, y, z)
+        rotateSinCos(matrixP, mTmp1, mTmp2, sin, cos, axisX, axisY, axisZ)
+        translate(matrixP, -x, -y, -z)
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Rotate the Mesh by 'angle' degrees around the center, along an axis.
- *
- * @param angle  Angle that we want to rotate the Object to. Unit: degrees
- * @param axis   Axis of rotation
- * @param center Coordinates of the Point we are rotating around.
- */
-  public MatrixEffectRotate(Data1D angle, Data3D axis, Data3D center)
-    {
-    super(EffectName.ROTATE);
-    mAngle = angle;
-    mAxis = axis;
-    mCenter = center;
+        translate(matrixV, x, y, z)
+        rotateSinCos(matrixV, mTmp1, mTmp2, sin, cos, axisX, axisY, axisZ)
+        translate(matrixV, -x, -y, -z)
     }
-  }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    // PUBLIC API
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+}
diff --git a/src/main/java/org/distorted/library/effect/MatrixEffectScale.kt b/src/main/java/org/distorted/library/effect/MatrixEffectScale.kt
index 12960ca..b21e8c9 100644
--- a/src/main/java/org/distorted/library/effect/MatrixEffectScale.kt
+++ b/src/main/java/org/distorted/library/effect/MatrixEffectScale.kt
@@ -18,76 +18,63 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.effect;
+package org.distorted.library.effect
 
-import org.distorted.library.helpers.MatrixHelper;
-import org.distorted.library.type.Data3D;
-import org.distorted.library.type.Static3D;
+import org.distorted.library.helpers.MatrixHelper.scale
+import org.distorted.library.type.Data3D
+import org.distorted.library.type.Static3D
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Scale the Mesh by 3D scale factors.
  */
-public class MatrixEffectScale extends MatrixEffect
-  {
-  private final Data3D mScale;
+class MatrixEffectScale : MatrixEffect
+{
+    private val mScale: Data3D
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public boolean compute(float[] uniforms, int index, long currentDuration, long step )
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    override fun compute(uniforms: FloatArray, index: Int, currentDuration: Long, step: Long): Boolean
     {
-    return mScale.get(uniforms,index,currentDuration,step);
+        return mScale.get(uniforms, index, currentDuration, step)
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- * <p>
- * Here and in Shear we have the whole reason why there are two separate 'P' and 'V' (Point and
- * Vector) matrices - Scale and Shear have to manipulate Points and Normal Vectors differently.
- * <p>
- * Points get multiplied by (sx,sy,sz) - and vectors by (1/sx,1/sy,1/sz) (think about it!) - or
- * better by sx*sy*sz*(1/sx,1/sy,1/sz) to avoid dividing my zero (vectors are normalized after)
- *
- * @y.exclude
- */
-  public void apply(float[] matrixP, float[] matrixV, float[] uniforms, int index)
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Only for use by the library itself.
+     *
+     * Here and in Shear we have the whole reason why there are two separate 'P' and 'V' (Point and
+     * Vector) matrices - Scale and Shear have to manipulate Points and Normal Vectors differently.
+     *
+     * Points get multiplied by (sx,sy,sz) - and vectors by (1/sx,1/sy,1/sz) (think about it!) - or
+     * better by sx*sy*sz*(1/sx,1/sy,1/sz) to avoid dividing my zero (vectors are normalized after)
+     *
+     * @y.exclude
+     */
+    override fun apply(matrixP: FloatArray, matrixV: FloatArray, uniforms: FloatArray, index: Int)
     {
-    float sx = uniforms[NUM_FLOAT_UNIFORMS*index  ];
-    float sy = uniforms[NUM_FLOAT_UNIFORMS*index+1];
-    float sz = uniforms[NUM_FLOAT_UNIFORMS*index+2];
+        val sx = uniforms[NUM_FLOAT_UNIFORMS*index]
+        val sy = uniforms[NUM_FLOAT_UNIFORMS*index+1]
+        val sz = uniforms[NUM_FLOAT_UNIFORMS*index+2]
 
-    MatrixHelper.scale(matrixP, sx, sy, sz);
-    MatrixHelper.scale(matrixV, sy*sz, sx*sz, sx*sy);
+        scale(matrixP, sx, sy, sz)
+        scale(matrixV, sy*sz, sx*sz, sx*sy)
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Scale the Mesh by 3D scale factors.
- *
- * @param scale current x- , y- and z- scale factors.
- */
-  public MatrixEffectScale(Data3D scale)
-    {
-    super(EffectName.SCALE);
-    mScale = scale;
-    }
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    // PUBLIC API
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Scale the Mesh by 3D scale factors.
+     *
+     * @param scale current x- , y- and z- scale factors.
+     */
+    constructor(scale: Data3D) : super(EffectName.SCALE)  { mScale = scale }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Scale the Mesh by 3D scale factors.
- *
- * @param scale Common x,y, and z scale factor.
- */
-  public MatrixEffectScale(float scale)
-    {
-    super(EffectName.SCALE);
-    mScale = new Static3D(scale,scale,scale);
-    }
-  }
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Scale the Mesh by 3D scale factors.
+     *
+     * @param scale Common x,y, and z scale factor.
+     */
+    constructor(scale: Float) : super(EffectName.SCALE) { mScale = Static3D(scale, scale, scale) }
+}
\ No newline at end of file
diff --git a/src/main/java/org/distorted/library/effect/MatrixEffectShear.kt b/src/main/java/org/distorted/library/effect/MatrixEffectShear.kt
index 3a91f87..3f74e6b 100644
--- a/src/main/java/org/distorted/library/effect/MatrixEffectShear.kt
+++ b/src/main/java/org/distorted/library/effect/MatrixEffectShear.kt
@@ -18,104 +18,83 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.effect;
+package org.distorted.library.effect
 
-import org.distorted.library.helpers.MatrixHelper;
-import org.distorted.library.type.Data3D;
+import org.distorted.library.helpers.MatrixHelper.translate
+import org.distorted.library.type.Data3D
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Shear the Mesh.
  */
-public class MatrixEffectShear extends MatrixEffect
-  {
-  private final Data3D mShear, mCenter;
+class MatrixEffectShear(shear: Data3D, center: Data3D) : MatrixEffect(EffectName.SHEAR)
+{
+    private val mShear = shear
+    private val mCenter = center
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public boolean compute(float[] uniforms, int index, long currentDuration, long step )
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    override fun compute(uniforms: FloatArray, index: Int, currentDuration: Long, step: Long): Boolean
     {
-    mCenter.get(uniforms,index+CENTER_OFFSET,currentDuration,step);
-    return mShear.get(uniforms,index,currentDuration,step);
+        mCenter.get(uniforms, index+CENTER_OFFSET, currentDuration, step)
+        return mShear.get(uniforms, index, currentDuration, step)
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- * <p>
- * Here and in Shear we have the whole reason why there are two separate 'P' and 'V' (Point and
- * Vector) matrices - Scale and Shear have to manipulate Points and Normal Vectors differently.
- *
- * @y.exclude
- */
-  public void apply(float[] matrixP, float[] matrixV, float[] uniforms, int index)
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Only for use by the library itself.
+     *
+     * Here and in Shear we have the whole reason why there are two separate 'P' and 'V' (Point and
+     * Vector) matrices - Scale and Shear have to manipulate Points and Normal Vectors differently.
+     *
+     * @y.exclude
+     */
+    override fun apply(matrixP: FloatArray, matrixV: FloatArray, uniforms: FloatArray, index: Int)
     {
-    float sx = uniforms[NUM_FLOAT_UNIFORMS*index  ];
-    float sy = uniforms[NUM_FLOAT_UNIFORMS*index+1];
-    float sz = uniforms[NUM_FLOAT_UNIFORMS*index+2];
-
-    float x  = uniforms[NUM_FLOAT_UNIFORMS*index+CENTER_OFFSET  ];
-    float y  = uniforms[NUM_FLOAT_UNIFORMS*index+CENTER_OFFSET+1];
-    float z  = uniforms[NUM_FLOAT_UNIFORMS*index+CENTER_OFFSET+2];
-
-    MatrixHelper.translate(matrixP, x, y, z);
-
-    matrixP[4] += sx*matrixP[0]; // Multiply viewMatrix by 1 x 0 0 , i.e. X-shear.
-    matrixP[5] += sx*matrixP[1]; //                        0 1 0 0
-    matrixP[6] += sx*matrixP[2]; //                        0 0 1 0
-    matrixP[7] += sx*matrixP[3]; //                        0 0 0 1
-
-    matrixP[0] += sy*matrixP[4]; // Multiply viewMatrix by 1 0 0 0 , i.e. Y-shear.
-    matrixP[1] += sy*matrixP[5]; //                        y 1 0 0
-    matrixP[2] += sy*matrixP[6]; //                        0 0 1 0
-    matrixP[3] += sy*matrixP[7]; //                        0 0 0 1
-
-    matrixP[4] += sz*matrixP[8]; // Multiply viewMatrix by 1 0 0 0 , i.e. Z-shear.
-    matrixP[5] += sz*matrixP[9]; //                        0 1 0 0
-    matrixP[6] += sz*matrixP[10];//                        0 z 1 0
-    matrixP[7] += sz*matrixP[11];//                        0 0 0 1
-
-    MatrixHelper.translate(matrixP,-x,-y,-z);
-    MatrixHelper.translate(matrixV, x, y, z);
-
-    matrixV[0] -= sx*matrixV[4]; // Multiply viewMatrix by 1 0 0 0 , i.e. vector X-shear.
-    matrixV[1] -= sx*matrixV[5]; //                       -x 1 0 0
-    matrixV[2] -= sx*matrixV[6]; //                        0 0 1 0
-    matrixV[3] -= sx*matrixV[7]; //                        0 0 0 1
-
-    matrixV[4] -= sy*matrixV[0]; // Multiply viewMatrix by 1-y 0 0 , i.e. vector Y-shear.
-    matrixV[5] -= sy*matrixV[1]; //                        0 1 0 0
-    matrixV[6] -= sy*matrixV[2]; //                        0 0 1 0
-    matrixV[7] -= sy*matrixV[3]; //                        0 0 0 1
-
-    matrixV[8] -= sz*matrixV[4]; // Multiply viewMatrix by 1 0 0 0 , i.e. vector Z-shear.
-    matrixV[9] -= sz*matrixV[5]; //                        0 1-z 0
-    matrixV[10]-= sz*matrixV[6]; //                        0 0 1 0
-    matrixV[11]-= sz*matrixV[7]; //                        0 0 0 1
-
-    MatrixHelper.translate(matrixV,-x,-y,-z);
-    }
+        val i = NUM_FLOAT_UNIFORMS*index
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Shear the Mesh.
- *
- * @param shear   The 3-tuple of shear factors. The first controls level
- *                of shearing in the X-axis, second - Y-axis and the third -
- *                Z-axis. Each is the tangent of the shear angle, i.e 0 -
- *                no shear, 1 - shear by 45 degrees (tan(45deg)=1) etc.
- * @param center  Center of shearing, i.e. the point which stays unmoved.
- */
-  public MatrixEffectShear(Data3D shear, Data3D center)
-    {
-    super(EffectName.SHEAR);
-    mShear = shear;
-    mCenter = center;
+        val sx = uniforms[i]
+        val sy = uniforms[i+1]
+        val sz = uniforms[i+2]
+
+        val x = uniforms[i+CENTER_OFFSET]
+        val y = uniforms[i+CENTER_OFFSET+1]
+        val z = uniforms[i+CENTER_OFFSET+2]
+
+        translate(matrixP, x, y, z)
+
+        matrixP[4] += sx*matrixP[ 0] // Multiply viewMatrix by 1 x 0 0 , i.e. X-shear.
+        matrixP[5] += sx*matrixP[ 1] //                        0 1 0 0
+        matrixP[6] += sx*matrixP[ 2] //                        0 0 1 0
+        matrixP[7] += sx*matrixP[ 3] //                        0 0 0 1
+
+        matrixP[0] += sy*matrixP[ 4] // Multiply viewMatrix by 1 0 0 0 , i.e. Y-shear.
+        matrixP[1] += sy*matrixP[ 5] //                        y 1 0 0
+        matrixP[2] += sy*matrixP[ 6] //                        0 0 1 0
+        matrixP[3] += sy*matrixP[ 7] //                        0 0 0 1
+
+        matrixP[4] += sz*matrixP[ 8] // Multiply viewMatrix by 1 0 0 0 , i.e. Z-shear.
+        matrixP[5] += sz*matrixP[ 9] //                        0 1 0 0
+        matrixP[6] += sz*matrixP[10] //                        0 z 1 0
+        matrixP[7] += sz*matrixP[11] //                        0 0 0 1
+
+        translate(matrixP,-x,-y,-z)
+        translate(matrixV, x, y, z)
+
+        matrixV[ 0] -= sx*matrixV[4] // Multiply viewMatrix by 1 0 0 0 , i.e. vector X-shear.
+        matrixV[ 1] -= sx*matrixV[5] //                       -x 1 0 0
+        matrixV[ 2] -= sx*matrixV[6] //                        0 0 1 0
+        matrixV[ 3] -= sx*matrixV[7] //                        0 0 0 1
+
+        matrixV[ 4] -= sy*matrixV[0] // Multiply viewMatrix by 1-y 0 0 , i.e. vector Y-shear.
+        matrixV[ 5] -= sy*matrixV[1] //                        0 1 0 0
+        matrixV[ 6] -= sy*matrixV[2] //                        0 0 1 0
+        matrixV[ 7] -= sy*matrixV[3] //                        0 0 0 1
+
+        matrixV[ 8] -= sz*matrixV[4] // Multiply viewMatrix by 1 0 0 0 , i.e. vector Z-shear.
+        matrixV[ 9] -= sz*matrixV[5] //                        0 1-z 0
+        matrixV[10] -= sz*matrixV[6] //                        0 0 1 0
+        matrixV[11] -= sz*matrixV[7] //                        0 0 0 1
+
+        translate(matrixV, -x, -y, -z)
     }
-  }
+}
diff --git a/src/main/java/org/distorted/library/effect/PostprocessEffect.kt b/src/main/java/org/distorted/library/effect/PostprocessEffect.kt
index 5b7e918..0c68500 100644
--- a/src/main/java/org/distorted/library/effect/PostprocessEffect.kt
+++ b/src/main/java/org/distorted/library/effect/PostprocessEffect.kt
@@ -18,301 +18,230 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.effect;
+package org.distorted.library.effect
 
-import org.distorted.library.effectqueue.EffectQueue;
-import org.distorted.library.main.DistortedFramebuffer;
-import org.distorted.library.main.DistortedLibrary;
-import org.distorted.library.main.InternalMaster;
-import org.distorted.library.program.DistortedProgram;
-
-import java.lang.reflect.Method;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.FloatBuffer;
-import java.util.ArrayList;
+import org.distorted.library.effectqueue.EffectQueue
+import org.distorted.library.main.DistortedFramebuffer
+import org.distorted.library.main.DistortedLibrary
+import org.distorted.library.main.InternalMaster
+import org.distorted.library.main.InternalMaster.Slave
+import org.distorted.library.program.DistortedProgram
+import java.lang.reflect.Method
+import java.nio.ByteBuffer
+import java.nio.ByteOrder
+import java.nio.FloatBuffer
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Abstract class that represents an Effect that works by running a certain Shader Program(s) on a Framebuffer.
  */
-public abstract class PostprocessEffect extends Effect implements InternalMaster.Slave
-  {
-  private static final int MIPMAP = 0;
-  /**
-   * 5 per-effect interpolated values.
-   */
-  public static final int NUM_FLOAT_UNIFORMS = 6;
-  /**
-   * 1: the name of the effect
-   */
-  public static final int NUM_INT_UNIFORMS = 1;
-
-  static final int POS_DATA_SIZE= 2;
-  static final int TEX_DATA_SIZE= 2;
-
-  static final FloatBuffer mQuadPositions, mQuadTexture, mQuadTextureInv;
-
-  static
+abstract class PostprocessEffect internal constructor(name: EffectName) : Effect(name), Slave
+{
+    private class Source(name: String, vertex: String, fragment: String)
     {
-    int dataLength      = 4;
-    int bytes_per_float = 4;
-
-    float[] position  = { -0.5f, -0.5f,  -0.5f, 0.5f,  0.5f,-0.5f,  0.5f, 0.5f };
-    float[] textureNor= {  0.0f,  0.0f,   0.0f, 1.0f,  1.0f, 0.0f,  1.0f, 1.0f };
-    float[] textureInv= {  0.0f,  0.0f,   1.0f, 0.0f,  0.0f, 1.0f,  1.0f, 1.0f };
-
-    mQuadPositions = ByteBuffer.allocateDirect(POS_DATA_SIZE*dataLength*bytes_per_float).order(ByteOrder.nativeOrder()).asFloatBuffer();
-    mQuadPositions.put(position).position(0);
-    mQuadTexture   = ByteBuffer.allocateDirect(TEX_DATA_SIZE*dataLength*bytes_per_float).order(ByteOrder.nativeOrder()).asFloatBuffer();
-    mQuadTexture.put(textureNor).position(0);
-    mQuadTextureInv= ByteBuffer.allocateDirect(TEX_DATA_SIZE*dataLength*bytes_per_float).order(ByteOrder.nativeOrder()).asFloatBuffer();
-    mQuadTextureInv.put(textureInv).position(0);
+        val mName: String = name
+        val mVertexShader: String = vertex
+        val mFragmentShader: String = fragment
     }
 
-  private static class Source
+    private class Job(t: Int, l: Int)
     {
-    private final String mName, mVertexShader, mFragmentShader;
-
-    Source(String name, String vertex, String fragment)
-      {
-      mName           = name;
-      mVertexShader   = vertex;
-      mFragmentShader = fragment;
-      }
+        var type: Int = t
+        var level: Int = l
     }
 
-  static ArrayList<DistortedProgram> mPrograms = new ArrayList<>();
-  private final static ArrayList<Source> mSources = new ArrayList<>();
-  private static int mNumSources = 0;
+    private val mJobs = ArrayList<Job>()
+    var quality: Int
+        private set
+    /**
+     * When preprocessing - so drawning the 'halo' - do we also want to write the depth buffer?
+     * If yes, the halo would cover the whole object; if no, it would be just around it (and possibly
+     * could be covered by other similarly postprocessed objects nearby)
+     */
+    var haloDepth: Boolean
 
-  private static class Job
-    {
-    int type;
-    int level;
-
-    Job(int t, int l)
-      {
-      type = t;
-      level= l;
-      }
-    }
+    var mQualityScale: Float
 
-  private final ArrayList<Job> mJobs = new ArrayList<>();
-  private int mQualityLevel;
-  private boolean mUseHaloDepth;
-
-  float mQualityScale;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  static int register(final String name, final String vertexShader, final String fragmentShader)
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    companion object
     {
-    mSources.add(new Source(name,vertexShader,fragmentShader));
+        private const val MIPMAP = 0
+        const val NUM_FLOAT_UNIFORMS: Int = 6 // per-effect interpolated values.
+        const val NUM_INT_UNIFORMS: Int = 1 // the name of the effect
+        const val POS_DATA_SIZE: Int = 2
+        const val TEX_DATA_SIZE: Int = 2
 
-    return mNumSources++;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public static void createPrograms(int GLSL)
-    {
-    Source source;
-    int len = mSources.size();
+        val mQuadPositions: FloatBuffer
+        val mQuadTexture: FloatBuffer
+        val mQuadTextureInv: FloatBuffer
 
-    String version = "#version "+GLSL+" es\n";
+        init
+        {
+            val dataLength = 4*4
+
+            val position   = floatArrayOf(-0.5f,-0.5f,-0.5f, 0.5f, 0.5f,-0.5f, 0.5f, 0.5f)
+            val textureNor = floatArrayOf( 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f)
+            val textureInv = floatArrayOf( 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f)
+
+            mQuadPositions = ByteBuffer.allocateDirect(POS_DATA_SIZE*dataLength).order(ByteOrder.nativeOrder()).asFloatBuffer()
+            mQuadPositions.put(position).position(0)
+            mQuadTexture = ByteBuffer.allocateDirect(TEX_DATA_SIZE*dataLength).order(ByteOrder.nativeOrder()).asFloatBuffer()
+            mQuadTexture.put(textureNor).position(0)
+            mQuadTextureInv = ByteBuffer.allocateDirect(TEX_DATA_SIZE*dataLength).order(ByteOrder.nativeOrder()).asFloatBuffer()
+            mQuadTextureInv.put(textureInv).position(0)
+        }
 
-    for(int i=0; i<len; i++)
-      {
-      source = mSources.remove(0);
+        var mPrograms: ArrayList<DistortedProgram> = ArrayList()
+        private val mSources = ArrayList<Source>()
+        private var mNumSources = 0
 
-      try
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        fun register(name: String, vertexShader: String, fragmentShader: String): Int
         {
-        mPrograms.add (new DistortedProgram(version+source.mVertexShader,version+source.mFragmentShader));
+            mSources.add(Source(name, vertexShader, fragmentShader))
+            return mNumSources++
         }
-      catch(Exception e)
+
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        @JvmStatic fun createPrograms(GLSL: Int)
         {
-        DistortedLibrary.logMessage("PostproocessEffect: exception trying to compile "+source.mName+" program: "+e.getMessage());
-        throw new RuntimeException(e.getMessage());
+            var source: Source
+            val len = mSources.size
+
+            val version = "#version $GLSL es\n"
+
+            for (i in 0 until len)
+            {
+                source = mSources.removeAt(0)
+
+                try
+                {
+                    mPrograms.add(DistortedProgram(version+source.mVertexShader, version+source.mFragmentShader))
+                }
+                catch (e: Exception)
+                {
+                    DistortedLibrary.logMessage("PostproocessEffect: exception trying to compile "+source.mName+" program: "+e.message)
+                    throw RuntimeException(e.message)
+                }
+            }
         }
-      }
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * At this moment the 'buffer' contains a) preprocessed object b) real object rendered 'on top' of
- * the preprocessed one.
- * Postprocess buffer. What this means exactly depends on the effect -
- * <p>
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public abstract int postprocess(float[] uniforms, int index, DistortedFramebuffer buffer);
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-  /**
-   * Do we render the object directly to the final surface, and only postprocess and then blit its
-   * 'halo', or do we render the object along with its halo to the intermediate framebuffer and
-   * postprocess it as well?
-   * <p>
-   * Only for use by the library itself.
-   *
-   * @y.exclude
-   */
-  public abstract boolean getRenderDirectly();
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-  /**
-   * Only for use by the library itself.
-   *
-   * @y.exclude
-   */
-  public int getQuality()
-    {
-    return mQualityLevel;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-  /**
-   * Only for use by the library itself.
-   *
-   * @y.exclude
-   */
-  public boolean getHaloDepth()
-    {
-    return mUseHaloDepth;
-    }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public void addQueue(EffectQueue queue)
-    {
-    // NO OP
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public void remQueue(EffectQueue queue)
-    {
-    // NO OP
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * 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);
-
-      if( job.type==MIPMAP )
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        fun destroyStatics()
         {
-        int level = job.level;
-        mQualityLevel = level;
-        mQualityScale = EffectQuality.getMipmap(level);
+            mPrograms.clear()
+            mSources.clear()
+            mNumSources = 0
+
+            var method: Method?
+
+            for (name in EffectName.entries)
+            {
+                if (name.type==EffectType.POSTPROCESS)
+                {
+                    val cls = name.effectClass
+
+                    try
+                    {
+                        method = cls.getDeclaredMethod("destroyStatics") // destroyStatics not public, thus getDeclaredMethod
+                    }
+                    catch (ex: NoSuchMethodException)
+                    {
+                        DistortedLibrary.logMessage("PostprocessEffect: "+cls.simpleName+": exception getting method: "+ex.message)
+                        method = null
+                    }
+
+                    try
+                    {
+                        method?.invoke(null)
+                    }
+                    catch (ex: Exception)
+                    {
+                        DistortedLibrary.logMessage("PostprocessEffect: exception invoking method: "+ex.message)
+                    }
+                }
+            }
         }
-      }
     }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  static void destroyStatics()
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * At this moment the 'buffer' contains a) preprocessed object b) real object rendered 'on top' of
+     * the preprocessed one.
+     * Postprocess buffer. What this means exactly depends on the effect -
+     *
+     *
+     * Only for use by the library itself.
+     *
+     * @y.exclude
+     */
+    abstract fun postprocess(uniforms: FloatArray, index: Int, buffer: DistortedFramebuffer): Int
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Do we render the object directly to the final surface, and only postprocess and then blit its
+     * 'halo', or do we render the object along with its halo to the intermediate framebuffer and
+     * postprocess it as well?
+     *
+     *
+     * Only for use by the library itself.
+     *
+     * @y.exclude
+     */
+    abstract val renderDirectly: Boolean
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    override fun addQueue(queue: EffectQueue) { /* NO OP */ }
+    override fun remQueue(queue: EffectQueue) { /* NO OP */ }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * 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
+     */
+    override fun doWork()
     {
-    mPrograms.clear();
-    mSources.clear();
-    mNumSources = 0;
-
-    Method method;
+        val num = mJobs.size
+        var job: Job
 
-    for(EffectName name: EffectName.values())
-      {
-      if( name.getType() == EffectType.POSTPROCESS )
+        for (i in 0 until num)
         {
-        Class<? extends Effect> cls = name.getEffectClass();
-
-        try
-          {
-          method = cls.getDeclaredMethod("destroyStatics");  // destroyStatics not public, thus getDeclaredMethod
-          }
-        catch(NoSuchMethodException ex)
-          {
-          DistortedLibrary.logMessage("PostprocessEffect: "+cls.getSimpleName()+": exception getting method: "+ex.getMessage());
-          method = null;
-          }
-
-        try
-          {
-          if( method!=null ) method.invoke(null);
-          }
-        catch(Exception ex)
-          {
-          DistortedLibrary.logMessage("PostprocessEffect: exception invoking method: "+ex.getMessage());
-          }
+            job = mJobs.removeAt(0)
+
+            if (job.type==MIPMAP)
+            {
+                val level = job.level
+                quality = level
+                mQualityScale = EffectQuality.getMipmap(level)
+            }
         }
-      }
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  PostprocessEffect(EffectName name)
-    {
-    super(name);
-
-    mQualityLevel = 0;
-    mQualityScale = 1.0f;
-    mUseHaloDepth = true;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * 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)
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    init
     {
-    mJobs.add(new Job(MIPMAP,quality.getLevel()));
-    InternalMaster.newSlave(this);
+        quality = 0
+        mQualityScale = 1.0f
+        haloDepth = true
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * When preprocessing - so drawning the 'halo' - do we also want to write the depth buffer?
- * If yes, the halo would cover the whole object; if no, it would be just around it (and possibly
- * could be covered by other similarly postprocessed objects nearby)
- *
- * @param depth should the halo around the object cover it or not?
- */
-  public void setHaloDepth(boolean depth)
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    // PUBLIC API
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * The higher the quality, the better the effect will look like and the slower it will be.
+     *
+     * 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.
+     *
+     * We cannot this during mid-render - thus, give it to the Master to assign us back this job on the
+     * next render.
+     */
+    fun setQuality(quality: EffectQuality)
     {
-    mUseHaloDepth = depth;
+        mJobs.add(Job(MIPMAP, quality.level))
+        InternalMaster.newSlave(this)
     }
-  }
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/src/main/java/org/distorted/library/effect/PostprocessEffectBlur.kt b/src/main/java/org/distorted/library/effect/PostprocessEffectBlur.kt
index db88ce3..2e770cd 100644
--- a/src/main/java/org/distorted/library/effect/PostprocessEffectBlur.kt
+++ b/src/main/java/org/distorted/library/effect/PostprocessEffectBlur.kt
@@ -18,79 +18,36 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.effect;
+package org.distorted.library.effect
 
-import org.distorted.library.type.Data2D;
+import org.distorted.library.type.Data2D
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Blur the Framebuffer.
  */
-public class PostprocessEffectBlur extends PostprocessEffectBlurred
-  {
-  private final Data2D mHaloAndRadius;
+class PostprocessEffectBlur(haloAndRadius: Data2D) : PostprocessEffectBlurred(EffectName.BLUR)
+{
+    private val mHaloAndRadius = haloAndRadius
+    override val renderDirectly: Boolean get() = false
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public boolean compute(float[] uniforms, int index, long currentDuration, long step )
-    {
-    return mHaloAndRadius.get(uniforms,index,currentDuration,step);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public boolean getRenderDirectly()
-    {
-    return false;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
- */
-  public static void enable()
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    companion object
     {
-    PostprocessEffectBlurred.enable("BLUR1","BLUR2");
+        /**
+         * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
+         */
+        fun enable() = enable("BLUR1", "BLUR2")
+
+        ///////////////////////////////////////////////////////////////////////////////////////////////////
+        // Clean up of static variables on exit. Called by reflection from super class.
+        @Suppress("unused")
+        fun destroyStatics() = PostprocessEffectBlurred.destroyStatics()
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Clean up of static variables on exit. Called by reflection from super class.
-
-  @SuppressWarnings("unused")
-  static void destroyStatics()
-    {
-    PostprocessEffectBlurred.destroyStatics();
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Blur the Framebuffer.
- *
- * @param haloAndRadius First float: the halo.
- *                      How far beyond the object does the effect stretch to? Unit: Percentage
- *                      of the size of the original object, i.e. Halo=0 --> no halo around, this
- *                      would mean sharp edges around the object; Halo=100 --> halo of the size
- *                      of the object itself around (in case of blur, this would be - in vast
- *                      majority of cases except an object rendered very closely to the near plane-
- *                      an overkill).
- *                      Second float: the radius.
- *                      The 'strength' if the blur of the edges, in pixels. 0 = no blur, 10 =
- *                      blur of roughly 10 pixels around the whole halo.
-
- */
-  public PostprocessEffectBlur(Data2D haloAndRadius)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    override fun compute(uniforms: FloatArray, index: Int, currentDuration: Long, step: Long): Boolean
     {
-    super(EffectName.BLUR);
-    mHaloAndRadius = haloAndRadius;
+        return mHaloAndRadius.get(uniforms, index, currentDuration, step)
     }
-  }
+}
diff --git a/src/main/java/org/distorted/library/effect/PostprocessEffectBlurred.kt b/src/main/java/org/distorted/library/effect/PostprocessEffectBlurred.kt
index 1bd4ee4..1581f93 100644
--- a/src/main/java/org/distorted/library/effect/PostprocessEffectBlurred.kt
+++ b/src/main/java/org/distorted/library/effect/PostprocessEffectBlurred.kt
@@ -18,282 +18,266 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.effect;
+package org.distorted.library.effect
 
-import android.opengl.GLES30;
-
-import org.distorted.library.main.DistortedFramebuffer;
-import org.distorted.library.main.InternalRenderState;
-import org.distorted.library.program.DistortedProgram;
+import android.opengl.GLES30
+import org.distorted.library.main.DistortedFramebuffer
+import org.distorted.library.main.InternalRenderState
+import org.distorted.library.program.DistortedProgram
+import kotlin.math.max
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-
 /**
  * Postprocessed effect in which postprocessing is a Gaussian blur - i.e. Blur or Glow.
  */
-abstract public class PostprocessEffectBlurred extends PostprocessEffect
-  {
-  private static final int MAX_RADIUS = 50;
-
-  private static final float[] GAUSSIAN =   // G(0.00), G(0.03), G(0.06), ..., G(3.00), 0
-    {                                       // where G(x)= (1/(sqrt(2*PI))) * e^(-(x^2)/2). The last 0 terminates.
-    0.398948f, 0.398769f, 0.398231f, 0.397336f, 0.396086f, 0.394485f, 0.392537f, 0.390247f, 0.387622f, 0.384668f,
-    0.381393f, 0.377806f, 0.373916f, 0.369733f, 0.365268f, 0.360532f, 0.355538f, 0.350297f, 0.344823f, 0.339129f,
-    0.333229f, 0.327138f, 0.320868f, 0.314436f, 0.307856f, 0.301142f, 0.294309f, 0.287373f, 0.280348f, 0.273248f,
-    0.266089f, 0.258884f, 0.251648f, 0.244394f, 0.237135f, 0.229886f, 0.222657f, 0.215461f, 0.208311f, 0.201217f,
-    0.194189f, 0.187238f, 0.180374f, 0.173605f, 0.166940f, 0.160386f, 0.153951f, 0.147641f, 0.141462f, 0.135420f,
-    0.129520f, 0.123765f, 0.118159f, 0.112706f, 0.107408f, 0.102266f, 0.097284f, 0.092461f, 0.087797f, 0.083294f,
-    0.078951f, 0.074767f, 0.070741f, 0.066872f, 0.063158f, 0.059596f, 0.056184f, 0.052920f, 0.049801f, 0.046823f,
-    0.043984f, 0.041280f, 0.038707f, 0.036262f, 0.033941f, 0.031740f, 0.029655f, 0.027682f, 0.025817f, 0.024056f,
-    0.022395f, 0.020830f, 0.019357f, 0.017971f, 0.016670f, 0.015450f, 0.014305f, 0.013234f, 0.012232f, 0.011295f,
-    0.010421f, 0.009606f, 0.008847f, 0.008140f, 0.007483f, 0.006873f, 0.006307f, 0.005782f, 0.005296f, 0.004847f,
-    0.004432f, 0.000000f
-    };
-  private static final int NUM_GAUSSIAN = GAUSSIAN.length-2;
-
-  // The (fixed-function-sampled) Gaussian Blur kernels are of the size k0=1, k1=2, k2=2, k3=3, k4=3, k5=4, k6=4,...
-  // i.e. k(i)=floor((i+3)/2).  (the 'i' in k(i) means 'blur taking into account the present pixel and 'i' pixels
-  // in all 4 directions)
-  // We need room for MAX_BLUR of them, and sum(i=0...N, floor((i+3)/2)) = N + floor(N*N/4)
-  private static final float[] weightsCache = new float[MAX_RADIUS + MAX_RADIUS*MAX_RADIUS/4];
-  private static final float[] offsetsCache = new float[MAX_RADIUS + MAX_RADIUS*MAX_RADIUS/4];
-  private static final float[] mWeights = new float[MAX_RADIUS];
-  private static final float[] mOffsets = new float[MAX_RADIUS];
-
-  private static DistortedProgram mProgram1, mProgram2;
-  private static int mIndex1, mIndex2;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  static void destroyStatics()
-    {
-    mProgram1 = null;
-    mProgram2 = null;
-
-    mIndex1 = 0;
-    mIndex2 = 0;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// This implements the 'Better separable implementation using GPU fixed function sampling' from
-// https://software.intel.com/en-us/blogs/2014/07/15/an-investigation-of-fast-real-time-gpu-based-image-blur-algorithms
-
-  private void computeGaussianKernel(int radius)
+abstract class PostprocessEffectBlurred(name: EffectName) : PostprocessEffect(name)
+{
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    // This implements the 'Better separable implementation using GPU fixed function sampling' from
+    // https://software.intel.com/en-us/blogs/2014/07/15/an-investigation-of-fast-real-time-gpu-based-image-blur-algorithms
+    private fun computeGaussianKernel(radius: Int)
     {
-    int offset = radius + radius*radius/4;
-
-    if( weightsCache[offset]==0.0f )
-      {
-      float z, x= 0.0f, P= (float)NUM_GAUSSIAN / Math.max(radius,3);
-      mWeights[0] = GAUSSIAN[0];
-      float sum   = GAUSSIAN[0];
-      int j;
-
-      for(int i=1; i<=radius; i++)
-        {
-        x += P;
-        j = (int)x;
-        z = x-j;
-
-        mWeights[i] = (1-z)*GAUSSIAN[j] + z*GAUSSIAN[j+1];
-        sum += 2*mWeights[i];
-        }
-
-      for(int i=0; i<=radius; i++) mWeights[i] /= sum;
-
-      int numloops = radius/2;
-      weightsCache[offset] = mWeights[0];
-      offsetsCache[offset] = 0.0f;
-
-      for(int i=0; i<numloops; i++)
-        {
-        offsetsCache[offset+i+1] = mWeights[2*i+1]*(2*i+1) + mWeights[2*i+2]*(2*i+2);
-        weightsCache[offset+i+1] = mWeights[2*i+1] + mWeights[2*i+2];
-        offsetsCache[offset+i+1]/= weightsCache[offset+i+1];
-        }
+        val offset = radius+radius*radius/4
 
-      if( radius%2 == 1 )
+        if (weightsCache[offset]==0.0f)
         {
-        int index = offset + radius/2 +1;
-        offsetsCache[index]=radius;
-        weightsCache[index]=mWeights[radius];
+            var z: Float
+            var x = 0.0f
+            val P = (NUM_GAUSSIAN.toFloat()/max(radius.toDouble(), 3.0)).toFloat()
+            mWeights[0] = GAUSSIAN[0]
+            var sum = GAUSSIAN[0]
+            var j: Int
+
+            for (i in 1..radius)
+            {
+                x += P
+                j = x.toInt()
+                z = x-j
+
+                mWeights[i] = (1-z)*GAUSSIAN[j]+z*GAUSSIAN[j+1]
+                sum += 2*mWeights[i]
+            }
+
+            for (i in 0..radius) mWeights[i] /= sum
+
+            val numloops = radius/2
+            weightsCache[offset] = mWeights[0]
+            offsetsCache[offset] = 0.0f
+
+            for (i in 0 until numloops)
+            {
+                offsetsCache[offset+i+1] = mWeights[2*i+1]*(2*i+1)+mWeights[2*i+2]*(2*i+2)
+                weightsCache[offset+i+1] = mWeights[2*i+1]+mWeights[2*i+2]
+                offsetsCache[offset+i+1] /= weightsCache[offset+i+1]
+            }
+
+            if (radius%2==1)
+            {
+                val index = offset+radius/2+1
+                offsetsCache[index] = radius.toFloat()
+                weightsCache[index] = mWeights[radius]
+            }
         }
-      }
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public int postprocess(float[] uniforms, int index, DistortedFramebuffer buffer)
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    override fun postprocess(uniforms: FloatArray, index: Int, buffer: DistortedFramebuffer): Int
     {
-    if( mProgram1 ==null)
-      {
-      try
-        {
-        mProgram1 = mPrograms.get(mIndex1);
-        mProgram2 = mPrograms.get(mIndex2);
-        }
-      catch(Exception ex)
+        if (mProgram1==null)
         {
-        return 0;
+            try
+            {
+                mProgram1 = mPrograms.get(mIndex1)
+                mProgram2 = mPrograms.get(mIndex2)
+            }
+            catch (ex: Exception)
+            {
+                return 0
+            }
         }
-      }
 
-    InternalRenderState.useStencilMark();
+        InternalRenderState.useStencilMark()
 
-    buffer.setAsOutput();
+        buffer.setAsOutput()
 
-    float w= buffer.getWidth();
-    float h= buffer.getHeight();
-    float n= 1.0f - buffer.getNear();
+        val w = buffer.width.toFloat()
+        val h = buffer.height.toFloat()
+        val n = 1.0f-buffer.near
 
-    float corrW = buffer.getWidthCorrection();
-    float corrH = buffer.getHeightCorrection();
-    float offsetCorrW = corrW/w;
-    float offsetCorrH = corrH/h;
+        val corrW = buffer.widthCorrection
+        val corrH = buffer.heightCorrection
+        val offsetCorrW = corrW/w
+        val offsetCorrH = corrH/h
 
-    int radius = (int)(uniforms[index+1]*mQualityScale);
-    if( radius>=MAX_RADIUS ) radius = MAX_RADIUS-1;
-    if( radius<=0          ) radius = 1;
-    computeGaussianKernel(radius);
+        var radius = (uniforms[index+1]*mQualityScale).toInt()
+        if (radius>=MAX_RADIUS) radius = MAX_RADIUS-1
+        if (radius<=0) radius = 1
+        computeGaussianKernel(radius)
 
-    int offset = radius + radius*radius/4;
-    radius = (radius+1)/2;
-    GLES30.glViewport(0, 0, (int)w, (int)h);
+        val offset = radius+radius*radius/4
+        radius = (radius+1)/2
+        GLES30.glViewport(0, 0, w.toInt(), h.toInt())
 
-    // horizontal blur
-    for(int i=0; i<=radius; i++) mOffsets[i] = offsetsCache[offset+i]*offsetCorrW;
+        // horizontal blur
+        for (i in 0..radius) mOffsets[i] = offsetsCache[offset+i]*offsetCorrW
 
-    mProgram1.useProgram();
-    buffer.bindForOutput(1);
-    buffer.setAsInput(0);
+        mProgram1!!.useProgram()
+        buffer.bindForOutput(1)
+        buffer.setAsInput(0)
 
-    GLES30.glTexParameteri( GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_CLAMP_TO_EDGE);
-    GLES30.glTexParameteri( GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_CLAMP_TO_EDGE);
+        GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_CLAMP_TO_EDGE)
+        GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_CLAMP_TO_EDGE)
 
-    GLES30.glColorMask(true,true,true,true);
-    GLES30.glClearColor(1.0f,1.0f,1.0f,0.0f);
-    GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
+        GLES30.glColorMask(true, true, true, true)
+        GLES30.glClearColor(1.0f, 1.0f, 1.0f, 0.0f)
+        GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT)
 
-    GLES30.glUniform1f ( mProgram1.mUniform[0] , n );
-    GLES30.glUniform2f ( mProgram1.mUniform[1] , corrW, corrH );
-    GLES30.glUniform1i ( mProgram1.mUniform[2] , 0 );
-    GLES30.glUniform1fv( mProgram1.mUniform[3] , radius+1, mOffsets,0);
-    GLES30.glUniform1fv( mProgram1.mUniform[4] , radius+1, weightsCache,offset);
-    GLES30.glUniform1i ( mProgram1.mUniform[5] , radius);
-    GLES30.glVertexAttribPointer(mProgram1.mAttribute[0], POS_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mQuadPositions);
-    GLES30.glVertexAttribPointer(mProgram1.mAttribute[1], TEX_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mQuadTexture);
-    GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
-    mProgram1.stopUsingProgram();
+        GLES30.glUniform1f(mProgram1!!.mUniform!![0], n)
+        GLES30.glUniform2f(mProgram1!!.mUniform!![1], corrW, corrH)
+        GLES30.glUniform1i(mProgram1!!.mUniform!![2], 0)
+        GLES30.glUniform1fv(mProgram1!!.mUniform!![3], radius+1, mOffsets, 0)
+        GLES30.glUniform1fv(mProgram1!!.mUniform!![4], radius+1, weightsCache, offset)
+        GLES30.glUniform1i(mProgram1!!.mUniform!![5], radius)
+        GLES30.glVertexAttribPointer(mProgram1!!.mAttribute!![0], POS_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mQuadPositions)
+        GLES30.glVertexAttribPointer(mProgram1!!.mAttribute!![1], TEX_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mQuadTexture)
+        GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4)
+        mProgram1!!.stopUsingProgram()
 
-    // vertical blur
-    for(int i=0; i<=radius; i++) mOffsets[i] = offsetsCache[offset+i]*offsetCorrH;
+        // vertical blur
+        for (i in 0..radius) mOffsets[i] = offsetsCache[offset+i]*offsetCorrH
 
-    mProgram2.useProgram();
-    buffer.bindForOutput(0);
-    buffer.setAsInput(1);
+        mProgram2!!.useProgram()
+        buffer.bindForOutput(0)
+        buffer.setAsInput(1)
 
-    GLES30.glTexParameteri( GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_CLAMP_TO_EDGE);
-    GLES30.glTexParameteri( GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_CLAMP_TO_EDGE);
+        GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_CLAMP_TO_EDGE)
+        GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_CLAMP_TO_EDGE)
 
-    GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
+        GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT)
 
-    GLES30.glUniform1f ( mProgram2.mUniform[0] , n );
-    GLES30.glUniform2f ( mProgram2.mUniform[1] , corrW, corrH );
-    GLES30.glUniform1i ( mProgram2.mUniform[2] , 0 );
-    GLES30.glUniform1fv( mProgram2.mUniform[3] , radius+1, mOffsets,0);
-    GLES30.glUniform1fv( mProgram2.mUniform[4] , radius+1, weightsCache,offset);
-    GLES30.glUniform1i ( mProgram2.mUniform[5] , radius);
-    GLES30.glVertexAttribPointer(mProgram2.mAttribute[0], POS_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mQuadPositions);
-    GLES30.glVertexAttribPointer(mProgram2.mAttribute[1], TEX_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mQuadTexture);
-    GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
-    mProgram1.stopUsingProgram();
+        GLES30.glUniform1f(mProgram2!!.mUniform!![0], n)
+        GLES30.glUniform2f(mProgram2!!.mUniform!![1], corrW, corrH)
+        GLES30.glUniform1i(mProgram2!!.mUniform!![2], 0)
+        GLES30.glUniform1fv(mProgram2!!.mUniform!![3], radius+1, mOffsets, 0)
+        GLES30.glUniform1fv(mProgram2!!.mUniform!![4], radius+1, weightsCache, offset)
+        GLES30.glUniform1i(mProgram2!!.mUniform!![5], radius)
+        GLES30.glVertexAttribPointer(mProgram2!!.mAttribute!![0], POS_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mQuadPositions)
+        GLES30.glVertexAttribPointer(mProgram2!!.mAttribute!![1], TEX_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mQuadTexture)
+        GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4)
+        mProgram1!!.stopUsingProgram()
 
-    InternalRenderState.unuseStencilMark();
+        InternalRenderState.unuseStencilMark()
 
-    return 2;
+        return 2
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
- */
-  public static void enable(String prog1, String prog2)
+    companion object
     {
-    final String vertex =
-
-      "precision lowp float;     \n"+
-      "in vec2 a_Position;       \n"+
-      "in vec2 a_TexCoordinate;  \n"+
-      "out vec2 v_TexCoordinate; \n"+
-      "uniform float u_Depth;    \n"+
-      "uniform vec2 u_TexCorr;   \n"+
-
-      "void main()                                      \n"+
-      "  {                                              \n"+
-      "  v_TexCoordinate = a_TexCoordinate * u_TexCorr; \n"+
-      "  gl_Position= vec4(2.0*a_Position,u_Depth,1.0); \n"+
-      "  }";
-
-    final String fragment1 =
-
-      "#define MAX_BLUR "+MAX_RADIUS+    "\n"+
-      "precision lowp float;              \n"+
-      "in vec2 v_TexCoordinate;           \n"+
-      "out vec4 fragColor;                \n"+
-      "uniform sampler2D u_ColorTexture;  \n"+
-      "uniform float u_Offsets[MAX_BLUR]; \n"+
-      "uniform float u_Weights[MAX_BLUR]; \n"+
-      "uniform int u_Radius;              \n"+
-
-      "void main()                                                                                                     \n"+
-      "  {                                                                                                             \n"+
-      "  vec4 pixel= texture(u_ColorTexture,v_TexCoordinate) * u_Weights[0];                                           \n"+
-      "  for (int i=1; i<=u_Radius; i+=1)                                                                              \n"+
-      "    {                                                                                                           \n"+
-      "    pixel += ( texture(u_ColorTexture,vec2(v_TexCoordinate.x+u_Offsets[i],v_TexCoordinate.y)) +                 \n"+
-      "               texture(u_ColorTexture,vec2(v_TexCoordinate.x-u_Offsets[i],v_TexCoordinate.y)) ) * u_Weights[i]; \n"+
-      "    }                                                                                                           \n"+
-      "  fragColor = pixel;                                                                                            \n"+
-      "  }";
-
-    final String fragment2 =
-
-      "#define MAX_BLUR "+MAX_RADIUS+    "\n"+
-      "precision lowp float;              \n"+
-      "in vec2 v_TexCoordinate;           \n"+
-      "out vec4 fragColor;                \n"+
-      "uniform sampler2D u_ColorTexture;  \n"+
-      "uniform float u_Offsets[MAX_BLUR]; \n"+
-      "uniform float u_Weights[MAX_BLUR]; \n"+
-      "uniform int u_Radius;              \n"+
-
-      "void main()                                                                                                     \n"+
-      "  {                                                                                                             \n"+
-      "  vec4 pixel= texture(u_ColorTexture,v_TexCoordinate) * u_Weights[0];                                           \n"+
-      "  for (int i=1; i<=u_Radius; i+=1)                                                                              \n"+
-      "    {                                                                                                           \n"+
-      "    pixel += ( texture(u_ColorTexture,vec2(v_TexCoordinate.x,v_TexCoordinate.y+u_Offsets[i])) +                 \n"+
-      "               texture(u_ColorTexture,vec2(v_TexCoordinate.x,v_TexCoordinate.y-u_Offsets[i])) ) * u_Weights[i]; \n"+
-      "    }                                                                                                           \n"+
-      "  fragColor = pixel;                                                                                            \n"+
-      "  }";
-
-    mIndex1 = PostprocessEffect.register(prog1, vertex,fragment1);
-    mIndex2 = PostprocessEffect.register(prog2, vertex,fragment2);
-    }
+        private const val MAX_RADIUS = 50
+
+        private val GAUSSIAN =                                // G(0.00), G(0.03), G(0.06), ..., G(3.00), 0
+            floatArrayOf(                                     // where G(x)= (1/(sqrt(2*PI))) * e^(-(x^2)/2). The last 0 terminates.
+                0.398948f, 0.398769f, 0.398231f, 0.397336f, 0.396086f, 0.394485f, 0.392537f, 0.390247f, 0.387622f, 0.384668f,
+                0.381393f, 0.377806f, 0.373916f, 0.369733f, 0.365268f, 0.360532f, 0.355538f, 0.350297f, 0.344823f, 0.339129f,
+                0.333229f, 0.327138f, 0.320868f, 0.314436f, 0.307856f, 0.301142f, 0.294309f, 0.287373f, 0.280348f, 0.273248f,
+                0.266089f, 0.258884f, 0.251648f, 0.244394f, 0.237135f, 0.229886f, 0.222657f, 0.215461f, 0.208311f, 0.201217f,
+                0.194189f, 0.187238f, 0.180374f, 0.173605f, 0.166940f, 0.160386f, 0.153951f, 0.147641f, 0.141462f, 0.135420f,
+                0.129520f, 0.123765f, 0.118159f, 0.112706f, 0.107408f, 0.102266f, 0.097284f, 0.092461f, 0.087797f, 0.083294f,
+                0.078951f, 0.074767f, 0.070741f, 0.066872f, 0.063158f, 0.059596f, 0.056184f, 0.052920f, 0.049801f, 0.046823f,
+                0.043984f, 0.041280f, 0.038707f, 0.036262f, 0.033941f, 0.031740f, 0.029655f, 0.027682f, 0.025817f, 0.024056f,
+                0.022395f, 0.020830f, 0.019357f, 0.017971f, 0.016670f, 0.015450f, 0.014305f, 0.013234f, 0.012232f, 0.011295f,
+                0.010421f, 0.009606f, 0.008847f, 0.008140f, 0.007483f, 0.006873f, 0.006307f, 0.005782f, 0.005296f, 0.004847f,
+                0.004432f, 0.000000f
+            )
+        private val NUM_GAUSSIAN = GAUSSIAN.size-2
+
+        // The (fixed-function-sampled) Gaussian Blur kernels are of the size k0=1, k1=2, k2=2, k3=3, k4=3, k5=4, k6=4,...
+        // i.e. k(i)=floor((i+3)/2).  (the 'i' in k(i) means 'blur taking into account the present pixel and 'i' pixels
+        // in all 4 directions)
+        // We need room for MAX_BLUR of them, and sum(i=0...N, floor((i+3)/2)) = N + floor(N*N/4)
+        private val weightsCache = FloatArray(MAX_RADIUS+MAX_RADIUS*MAX_RADIUS/4)
+        private val offsetsCache = FloatArray(MAX_RADIUS+MAX_RADIUS*MAX_RADIUS/4)
+        private val mWeights = FloatArray(MAX_RADIUS)
+        private val mOffsets = FloatArray(MAX_RADIUS)
+
+        private var mProgram1: DistortedProgram? = null
+        private var mProgram2: DistortedProgram? = null
+        private var mIndex1 = 0
+        private var mIndex2 = 0
+
+        ///////////////////////////////////////////////////////////////////////////////////////////////////
+        fun destroyStatics()
+        {
+            mProgram1 = null
+            mProgram2 = null
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Default constructor.
- */
-  public PostprocessEffectBlurred(EffectName name)
-    {
-    super(name);
+            mIndex1 = 0
+            mIndex2 = 0
+        }
+
+        ///////////////////////////////////////////////////////////////////////////////////////////////////
+        // PUBLIC API
+        ///////////////////////////////////////////////////////////////////////////////////////////////////
+        /**
+         * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
+         */
+        fun enable(prog1: String, prog2: String)
+        {
+            val vertex =
+                """ precision lowp float;     
+                    in vec2 a_Position;       
+                    in vec2 a_TexCoordinate;  
+                    out vec2 v_TexCoordinate; 
+                    uniform float u_Depth;    
+                    uniform vec2 u_TexCorr;   
+                    void main()                                      
+                      {                                              
+                      v_TexCoordinate = a_TexCoordinate * u_TexCorr; 
+                      gl_Position= vec4(2.0*a_Position,u_Depth,1.0); 
+                      }"""
+
+            val fragment1 =
+                 """#define MAX_BLUR $MAX_RADIUS
+                    precision lowp float;              
+                    in vec2 v_TexCoordinate;           
+                    out vec4 fragColor;                
+                    uniform sampler2D u_ColorTexture;  
+                    uniform float u_Offsets[MAX_BLUR]; 
+                    uniform float u_Weights[MAX_BLUR]; 
+                    uniform int u_Radius;              
+                    void main()                                                                                                     
+                      {                                                                                                             
+                      vec4 pixel= texture(u_ColorTexture,v_TexCoordinate) * u_Weights[0];                                           
+                      for (int i=1; i<=u_Radius; i+=1)                                                                              
+                        {                                                                                                           
+                        pixel += ( texture(u_ColorTexture,vec2(v_TexCoordinate.x+u_Offsets[i],v_TexCoordinate.y)) +                 
+                                   texture(u_ColorTexture,vec2(v_TexCoordinate.x-u_Offsets[i],v_TexCoordinate.y)) ) * u_Weights[i]; 
+                        }                                                                                                           
+                      fragColor = pixel;                                                                                            
+                      }"""
+
+            val fragment2 =
+                """#define MAX_BLUR $MAX_RADIUS
+                    precision lowp float;              
+                    in vec2 v_TexCoordinate;           
+                    out vec4 fragColor;                
+                    uniform sampler2D u_ColorTexture;  
+                    uniform float u_Offsets[MAX_BLUR]; 
+                    uniform float u_Weights[MAX_BLUR]; 
+                    uniform int u_Radius;              
+                    void main()                                                                                                     
+                      {                                                                                                             
+                      vec4 pixel= texture(u_ColorTexture,v_TexCoordinate) * u_Weights[0];                                           
+                      for (int i=1; i<=u_Radius; i+=1)                                                                              
+                        {                                                                                                           
+                        pixel += ( texture(u_ColorTexture,vec2(v_TexCoordinate.x,v_TexCoordinate.y+u_Offsets[i])) +                 
+                                   texture(u_ColorTexture,vec2(v_TexCoordinate.x,v_TexCoordinate.y-u_Offsets[i])) ) * u_Weights[i]; 
+                        }                                                                                                           
+                      fragColor = pixel;                                                                                            
+                      }"""
+
+            mIndex1 = register(prog1, vertex, fragment1)
+            mIndex2 = register(prog2, vertex, fragment2)
+        }
     }
-  }
+}
diff --git a/src/main/java/org/distorted/library/effect/PostprocessEffectBorder.kt b/src/main/java/org/distorted/library/effect/PostprocessEffectBorder.kt
index 5db2805..e3dd620 100644
--- a/src/main/java/org/distorted/library/effect/PostprocessEffectBorder.kt
+++ b/src/main/java/org/distorted/library/effect/PostprocessEffectBorder.kt
@@ -18,94 +18,43 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.effect;
+package org.distorted.library.effect
 
-import org.distorted.library.main.DistortedFramebuffer;
-import org.distorted.library.type.Data1D;
-import org.distorted.library.type.Data4D;
+import org.distorted.library.main.DistortedFramebuffer
+import org.distorted.library.type.Data1D
+import org.distorted.library.type.Data4D
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-
 /**
  * Similar effect to Glow, but this one is not blurred and it's entirely behind the object.
  */
-public class PostprocessEffectBorder extends PostprocessEffect
-  {
-  private final Data1D mHalo;
-  private final Data4D mColor;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Clean up of static variables on exit. Called by reflection from super class.
-
-  @SuppressWarnings("unused")
-  static void destroyStatics()
-    {
-
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public boolean compute(float[] uniforms, int index, long currentDuration, long step )
-    {
-    mColor.get(uniforms,index+2,currentDuration,step);
-    return mHalo.get(uniforms,index,currentDuration,step);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public boolean getRenderDirectly()
-    {
-    return true;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public int postprocess(float[] uniforms, int index, DistortedFramebuffer buffer)
-    {
-    return 0;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * No local programs; we do not postprocess anything here. No need to do anything
- */
-  public static void enable()
+class PostprocessEffectBorder(halo: Data1D, color: Data4D) : PostprocessEffect(EffectName.BORDER)
+{
+    private val mHalo = halo
+    private val mColor = color
+    override val renderDirectly: Boolean get() = true
+    override fun postprocess(uniforms: FloatArray, index: Int, buffer: DistortedFramebuffer): Int { return 0 }
+
+    companion object
     {
-
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        // Clean up of static variables on exit. Called by reflection from super class.
+        @Suppress("unused")
+        fun destroyStatics() { }
+
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        // PUBLIC API
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        /**
+         * No local programs; we do not postprocess anything here. No need to do anything
+         */
+        @JvmStatic
+        fun enable() { }
     }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Draw a sharp 'border' around the object.
- * One can decide if the border is around the object or behind it by carefully setting the
- * componentCenters of the object's mesh first.
- *
- * @param halo   How far beyond the object does the effect stretch to? Unit: Percentage of the size
- *               of the original object, i.e. halo=0 --> no effect at all, halo=100 --> border of
- *               size of the object itself.
- *
- * @param color  RGBA of the color with which to draw the border; example: (1.0f,0.0f,0.0f,0.5f) -
- *               half transparent red.
- */
-  public PostprocessEffectBorder(Data1D halo, Data4D color)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    override fun compute(uniforms: FloatArray, index: Int, currentDuration: Long, step: Long): Boolean
     {
-    super(EffectName.BORDER);
-
-    mHalo = halo;
-    mColor= color;
+        mColor.get(uniforms, index+2, currentDuration, step)
+        return mHalo.get(uniforms, index, currentDuration, step)
     }
-  }
+}
diff --git a/src/main/java/org/distorted/library/effect/PostprocessEffectGlow.kt b/src/main/java/org/distorted/library/effect/PostprocessEffectGlow.kt
index a864895..d5c07b9 100644
--- a/src/main/java/org/distorted/library/effect/PostprocessEffectGlow.kt
+++ b/src/main/java/org/distorted/library/effect/PostprocessEffectGlow.kt
@@ -18,83 +18,40 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.effect;
+package org.distorted.library.effect
 
-import org.distorted.library.type.Data2D;
-import org.distorted.library.type.Data4D;
+import org.distorted.library.type.Data2D
+import org.distorted.library.type.Data4D
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Add a (colored) glow around an object.
  */
-public class PostprocessEffectGlow extends PostprocessEffectBlurred
-  {
-  private final Data2D mHaloAndRadius;
-  private final Data4D mColor;
+class PostprocessEffectGlow(haloAndRadius: Data2D, color: Data4D) : PostprocessEffectBlurred(EffectName.GLOW)
+{
+    private val mHaloAndRadius = haloAndRadius
+    private val mColor = color
+    override val renderDirectly: Boolean get() = true
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public boolean compute(float[] uniforms, int index, long currentDuration, long step )
-    {
-    mColor.get(uniforms,index+2,currentDuration,step);
-    return mHaloAndRadius.get(uniforms,index,currentDuration,step);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public boolean getRenderDirectly()
-    {
-    return true;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
- */
-  public static void enable()
+    companion object
     {
-    PostprocessEffectBlurred.enable("GLOW1","GLOW2");
+        ///////////////////////////////////////////////////////////////////////////////////////////////////
+        // PUBLIC API
+        ///////////////////////////////////////////////////////////////////////////////////////////////////
+        /**
+         * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
+         */
+        @JvmStatic fun enable() = enable("GLOW1", "GLOW2")
+
+        ///////////////////////////////////////////////////////////////////////////////////////////////////
+        // Clean up of static variables on exit. Called by reflection from super class.
+        @Suppress("unused")
+        fun destroyStatics() = PostprocessEffectBlurred.destroyStatics()
     }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Clean up of static variables on exit. Called by reflection from super class.
-
-  @SuppressWarnings("unused")
-  static void destroyStatics()
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    override fun compute(uniforms: FloatArray, index: Int, currentDuration: Long, step: Long): Boolean
     {
-    PostprocessEffectBlurred.destroyStatics();
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Make the object glow with a specific color and a halo of specific radius.
- *
- * @param haloAndRadius First float: the halo.
- *                      How far beyond the object does the effect stretch to? Unit: Percentage
- *                      of the size of the original object, i.e. Halo=0 --> no halo around, this
- *                      would mean sharp edges around the object; Halo=100 --> halo of the size
- *                      of the object itself around.
- *                      Second float: the radius.
- *                      The 'strength' of the blur of the edges, in pixels. 0 = no blur, 10 =
- *                      blur of roughly 10 pixels around the whole halo.
- * @param color         RGBA of the color with which to draw the glow; example: (1.0f,0.0f,0.0f,0.5f) -
- *                      half transparent red.
- */
-  public PostprocessEffectGlow(Data2D haloAndRadius, Data4D color)
-    {
-    super(EffectName.GLOW);
-
-    mHaloAndRadius = haloAndRadius;
-    mColor         = color;
+        mColor.get(uniforms, index+2, currentDuration, step)
+        return mHaloAndRadius.get(uniforms, index, currentDuration, step)
     }
-  }
+}
diff --git a/src/main/java/org/distorted/library/effect/VertexEffect.kt b/src/main/java/org/distorted/library/effect/VertexEffect.kt
index c300ab6..99b7221 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffect.kt
+++ b/src/main/java/org/distorted/library/effect/VertexEffect.kt
@@ -18,322 +18,259 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.effect;
+package org.distorted.library.effect
 
-import org.distorted.library.effectqueue.EffectQueue;
-import org.distorted.library.main.DistortedLibrary;
-import org.distorted.library.type.Static1D;
-import org.distorted.library.type.Static3D;
-import org.distorted.library.type.Static4D;
-import org.distorted.library.type.Static5D;
-
-import java.lang.reflect.Method;
-import java.util.ArrayList;
+import org.distorted.library.effectqueue.EffectQueue
+import org.distorted.library.main.DistortedLibrary
+import org.distorted.library.type.Static1D
+import org.distorted.library.type.Static3D
+import org.distorted.library.type.Static4D
+import org.distorted.library.type.Static5D
+import java.lang.reflect.Method
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Abstract class that represents an Effect that works by injecting certain code into the main Vertex shader.
  */
-public abstract class VertexEffect extends Effect
-  {
-  /**
-   * 12: 5 per-effect interpolated values, 3-dimensional center, 4-dimensional Region
-   */
-  public static final int NUM_FLOAT_UNIFORMS = 12;
-  /**
-   * 4: name, AND association, reserved, EQU Association
-   */
-  public static final int NUM_INT_UNIFORMS = 4;
-
-  static final int VALUES_OFFSET = 0;
-  static final int CENTER_OFFSET = 5;
-  static final int REGION_OFFSET = 8;
-  private static String mGLSL = "";
-  private static int mNumEnabled = 0;
-
-  private static String mFullGLSL = "";
-  private static int mFullEnabled = 0;
-  private static boolean mFullPrepared = false;
-
-  final static Static4D MAX_REGION = new Static4D(0,0,0,1000000);
-
-  ArrayList<EffectQueue> mQueues;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
+abstract class VertexEffect internal constructor(name: EffectName) : Effect(name)
+{
+    var mQueues: ArrayList<EffectQueue>? = null
 
-  VertexEffect(EffectName name)
+    companion object
     {
-    super(name);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private static String retSection(int effect, String code)
-    {
-    return
-
-        "if( vProperties[i].x =="+effect+" )\n" +
-          "{\n" +
-           code +"\n" +
-          "}\n" +
-        "else\n";
-    }
+        const val NUM_FLOAT_UNIFORMS = 12 //  5 per-effect interpolated values, 3-dimensional center, 4-dimensional Region
+        const val NUM_INT_UNIFORMS   = 4  // name, AND association, reserved, EQU Association
+
+        const val VALUES_OFFSET = 0
+        const val CENTER_OFFSET = 5
+        const val REGION_OFFSET = 8
+        private var mGLSL = ""
+        private var numEnabled: Int = 0 // number of Vertex effects enabled.
+        private var mFullGLSL = ""
+        private var mFullEnabled = 0
+        private var mFullPrepared = false
+
+        val MAX_REGION: Static4D = Static4D(0f,0f,0f,1000000f)
+
+        @JvmStatic val gLSL: String get() = mGLSL+"{}"
+        @JvmStatic val allGLSL: String
+            get()
+            {
+                if (!mFullPrepared)
+                {
+                    prepareFull()
+                    mFullPrepared = true
+                }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// prepare the code to be injected into the Full program, i.e. code of ALL vertex effects.
+                return mFullGLSL+"{}"
+            }
+        @JvmStatic val allEnabled: Int
+            get()
+            {
+                if (!mFullPrepared)
+                {
+                    prepareFull()
+                    mFullPrepared = true
+                }
 
-  private static void prepareFull()
-    {
-    Method method;
+                return mFullEnabled
+            }
 
-    for(EffectName name: EffectName.values())
-      {
-      if( name.getType() == EffectType.VERTEX )
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        private fun retSection(effect: Int, code: String?): String
         {
-        Class<? extends Effect> cls = name.getEffectClass();
+            return """if( vProperties[i].x ==$effect )
+                        {
+                        $code
+                        }
+                        else
+                        """
+        }
 
-        try
-          {
-          method = cls.getDeclaredMethod("code");
-          }
-        catch(NoSuchMethodException ex)
-          {
-          DistortedLibrary.logMessage("VertexEffect: exception getting method: "+ex.getMessage());
-          method = null;
-          }
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        // prepare the code to be injected into the Full program, i.e. code of ALL vertex effects.
+        private fun prepareFull()
+        {
+            var method: Method?
 
-        try
-          {
-          if( method!=null )
+            for (name in EffectName.entries)
             {
-            Object value = method.invoke(null);
-            String code = (String)value;
-            mFullGLSL += retSection(name.ordinal(),code);
-            mFullEnabled++;
+                if (name.type==EffectType.VERTEX)
+                {
+                    val cls = name.effectClass
+
+                    try
+                    {
+                        method = cls.getDeclaredMethod("code")
+                    }
+                    catch (ex: NoSuchMethodException)
+                    {
+                        DistortedLibrary.logMessage("VertexEffect: exception getting method: "+ex.message)
+                        method = null
+                    }
+
+                    try
+                    {
+                        if (method!=null)
+                        {
+                            val value = method.invoke(null)
+                            val code = value as String
+                            mFullGLSL += retSection(name.ordinal, code)
+                            mFullEnabled++
+                        }
+                    }
+                    catch (ex: Exception)
+                    {
+                        DistortedLibrary.logMessage("VertexEffect: exception invoking method: "+ex.message)
+                    }
+                }
             }
-          }
-        catch(Exception ex)
-          {
-          DistortedLibrary.logMessage("VertexEffect: exception invoking method: "+ex.getMessage());
-          }
         }
-      }
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// prepare code to be injected into the 'main_vertex_shader' main() function.
 
-  static void addEffect(EffectName name, String code)
-    {
-    int effect = name.ordinal();
-
-    if( !mEnabled[effect] )
-      {
-      mEnabled[effect] = true;
-      mNumEnabled ++;
-      mGLSL += retSection(effect,code);
-      }
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public static String getGLSL()
-    {
-    return mGLSL + "{}";
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public static String getAllGLSL()
-    {
-    if( !mFullPrepared )
-      {
-      prepareFull();
-      mFullPrepared = true;
-      }
-
-    return mFullGLSL + "{}";
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public static int getAllEnabled()
-    {
-    if( !mFullPrepared )
-      {
-      prepareFull();
-      mFullPrepared = true;
-      }
-
-    return mFullEnabled;
-    }
+        ///////////////////////////////////////////////////////////////////////////////////////////////////
+        // prepare code to be injected into the 'main_vertex_shader' main() function.
+        fun addEffect(name: EffectName, code: String?)
+        {
+            val effect = name.ordinal
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
+            if (!mEnabled[effect])
+            {
+                mEnabled[effect] = true
+                numEnabled++
+                mGLSL += retSection(effect, code)
+            }
+        }
 
-  static void destroyStatics()
-    {
-    mNumEnabled = 0;
-    mGLSL = "";
-    mFullEnabled= 0;
-    mFullGLSL = "";
-    mFullPrepared = false;
-    }
+        ///////////////////////////////////////////////////////////////////////////////////////////////////
+        fun destroyStatics()
+        {
+            numEnabled    = 0
+            mGLSL         = ""
+            mFullEnabled  = 0
+            mFullGLSL     = ""
+            mFullPrepared = false
+        }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Return the number of Vertex effects enabled.
- */
-  public static int getNumEnabled()
-    {
-    return mNumEnabled;
-    }
+        ///////////////////////////////////////////////////////////////////////////////////////////////////
+        /**
+         * Return a constructed VertexEffect based on its name, the 5 variables, center & region.
+         */
+        @JvmStatic
+        fun constructEffect(name: String, vars: FloatArray, center: FloatArray, region: FloatArray): VertexEffect?
+        {
+            val staCenter = Static3D(center[0], center[1], center[2])
+            val staRegion = Static4D(region[0], region[1], region[2], region[3])
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public void addQueue(EffectQueue queue)
-    {
-    if( mQueues==null ) mQueues = new ArrayList<>();
+            if (name==EffectName.DISTORT.name)
+            {
+                val staVars = Static3D(vars[2], vars[3], vars[4])
+                return VertexEffectDistort(staVars, staCenter, staRegion)
+            }
+            if (name==EffectName.DEFORM.name)
+            {
+                val staVars = Static3D(vars[1], vars[2], vars[3])
+                val staRadius = Static1D(vars[4])
+                return VertexEffectDeform(staVars, staRadius, staCenter, staRegion)
+            }
+            if (name==EffectName.SINK.name)
+            {
+                val staSink = Static1D(vars[4])
+                return VertexEffectSink(staSink, staCenter, staRegion)
+            }
+            if (name==EffectName.PINCH.name)
+            {
+                val staVars = Static3D(vars[2], vars[3], vars[4])
+                return VertexEffectPinch(staVars, staCenter, staRegion)
+            }
+            if (name==EffectName.SWIRL.name)
+            {
+                val staSwirl = Static1D(vars[4])
+                return VertexEffectSwirl(staSwirl, staCenter, staRegion)
+            }
+            if (name==EffectName.WAVE.name)
+            {
+                val staWave = Static5D(vars[0], vars[1], vars[2], vars[3], vars[4])
+                return VertexEffectWave(staWave, staCenter, staRegion)
+            }
+            if (name==EffectName.DISAPPEAR.name)
+            {
+                return VertexEffectDisappear()
+            }
+            if (name==EffectName.VERTEX_MOVE.name)
+            {
+                val staVector = Static3D(vars[2], vars[3], vars[4])
+                return VertexEffectMove(staVector)
+            }
+            if (name==EffectName.VERTEX_QUATERNION.name)
+            {
+                val staQuat = Static4D(vars[1], vars[2], vars[3], vars[4])
+                return VertexEffectQuaternion(staQuat, staCenter)
+            }
+            if (name==EffectName.VERTEX_ROTATE.name)
+            {
+                val staAngle = Static1D(vars[1])
+                val staAxis = Static3D(vars[2], vars[3], vars[4])
+                return VertexEffectRotate(staAngle, staAxis, staCenter)
+            }
+            if (name==EffectName.VERTEX_SCALE.name)
+            {
+                val staScale = Static3D(vars[2], vars[3], vars[4])
+                return VertexEffectScale(staScale)
+            }
+            if (name==EffectName.VERTEX_SHEAR.name)
+            {
+                val staShear = Static3D(vars[2], vars[3], vars[4])
+                return VertexEffectShear(staShear, staCenter)
+            }
+            if (name==EffectName.PIPE.name)
+            {
+                val staPipe = Static5D(vars[0], vars[1], vars[2], vars[3], vars[4])
+                return VertexEffectPipe(staPipe, staCenter)
+            }
 
-    mQueues.add(queue);
+            return null
+        }
     }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public void remQueue(EffectQueue queue)
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    override fun addQueue(queue: EffectQueue)
     {
-    if( mQueues==null ) mQueues = new ArrayList<>();
-
-    mQueues.remove(queue);
+        if (mQueues==null) mQueues = ArrayList()
+        mQueues!!.add(queue)
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Set Mesh association.
- * <p>
- * This creates an association between a Component of a Mesh and this Vertex Effect.
- * One can set two types of associations - an 'logical and' and a 'equal' associations and the Effect
- * will only be active on vertices of Components such that
- * <p>
- * (effect andAssoc) & (component andAssoc) != 0 || (effect equAssoc) == (mesh equAssoc)
- * <p>
- * (see main_vertex_shader)
- * <p>
- * The point: this way we can configure the system so that each Vertex Effect acts only on a certain
- * subset of a Mesh, thus potentially significantly reducing the number of render calls.
- */
-  public void setMeshAssociation(int andAssociation, int equAssociation)
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    override fun remQueue(queue: EffectQueue)
     {
-    mAndAssociation = andAssociation;
-    mEquAssociation = equAssociation;
-
-    long id = getID();
-    int numQueues = mQueues==null ? 0: mQueues.size();
-
-    for(int i=0; i<numQueues; i++)
-      {
-      EffectQueue queue = mQueues.get(i);
-      queue.setAssociation(id);
-      }
+        if (mQueues==null) mQueues = ArrayList()
+        mQueues!!.remove(queue)
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Return a constructed VertexEffect based on its name, the 5 variables, center & region.
- */
-  public static VertexEffect constructEffect(String name,float[] vars, float[] center, float[] region)
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Set Mesh association.
+     *
+     * This creates an association between a Component of a Mesh and this Vertex Effect.
+     * One can set two types of associations - an 'logical and' and a 'equal' associations and the Effect
+     * will only be active on vertices of Components such that
+     *
+     * (effect andAssoc) & (component andAssoc) != 0 || (effect equAssoc) == (mesh equAssoc)
+     *
+     * (see main_vertex_shader)
+     *
+     * The point: this way we can configure the system so that each Vertex Effect acts only on a certain
+     * subset of a Mesh, thus potentially significantly reducing the number of render calls.
+     */
+    fun setMeshAssociation(andAssociation: Int, equAssociation: Int)
     {
-    Static3D staCenter = new Static3D(center[0],center[1],center[2]);
-    Static4D staRegion = new Static4D(region[0],region[1],region[2],region[3]);
+        mAndAssociation = andAssociation
+        mEquAssociation = equAssociation
 
-    if( name.equals(EffectName.DISTORT.name()) )
-      {
-      Static3D staVars = new Static3D(vars[2],vars[3],vars[4]);
-      return new VertexEffectDistort(staVars,staCenter,staRegion);
-      }
-    if( name.equals(EffectName.DEFORM.name()) )
-      {
-      Static3D staVars   = new Static3D(vars[1],vars[2],vars[3]);
-      Static1D staRadius = new Static1D(vars[4]);
-      return new VertexEffectDeform(staVars,staRadius,staCenter,staRegion);
-      }
-    if( name.equals(EffectName.SINK.name()) )
-      {
-      Static1D staSink = new Static1D(vars[4]);
-      return new VertexEffectSink(staSink,staCenter,staRegion);
-      }
-    if( name.equals(EffectName.PINCH.name()) )
-      {
-      Static3D staVars = new Static3D(vars[2],vars[3],vars[4]);
-      return new VertexEffectPinch(staVars,staCenter,staRegion);
-      }
-    if( name.equals(EffectName.SWIRL.name()) )
-      {
-      Static1D staSwirl = new Static1D(vars[4]);
-      return new VertexEffectSwirl(staSwirl,staCenter,staRegion);
-      }
-    if( name.equals(EffectName.WAVE.name()) )
-      {
-      Static5D staWave = new Static5D(vars[0],vars[1],vars[2],vars[3],vars[4]);
-      return new VertexEffectWave(staWave,staCenter,staRegion);
-      }
-    if( name.equals(EffectName.DISAPPEAR.name()) )
-      {
-      return new VertexEffectDisappear();
-      }
-    if( name.equals(EffectName.VERTEX_MOVE.name()) )
-      {
-      Static3D staVector = new Static3D(vars[2],vars[3],vars[4]);
-      return new VertexEffectMove(staVector);
-      }
-    if( name.equals(EffectName.VERTEX_QUATERNION.name()) )
-      {
-      Static4D staQuat = new Static4D(vars[1],vars[2],vars[3],vars[4]);
-      return new VertexEffectQuaternion(staQuat,staCenter);
-      }
-    if( name.equals(EffectName.VERTEX_ROTATE.name()) )
-      {
-      Static1D staAngle = new Static1D(vars[1]);
-      Static3D staAxis  = new Static3D(vars[2],vars[3],vars[4]);
-      return new VertexEffectRotate(staAngle,staAxis,staCenter);
-      }
-    if( name.equals(EffectName.VERTEX_SCALE.name()) )
-      {
-      Static3D staScale = new Static3D(vars[2],vars[3],vars[4]);
-      return new VertexEffectScale(staScale);
-      }
-    if( name.equals(EffectName.VERTEX_SHEAR.name()) )
-      {
-      Static3D staShear = new Static3D(vars[2],vars[3],vars[4]);
-      return new VertexEffectShear(staShear,staCenter);
-      }
-    if( name.equals(EffectName.PIPE.name()) )
-      {
-      Static5D staPipe = new Static5D(vars[0],vars[1],vars[2],vars[3],vars[4]);
-      return new VertexEffectPipe(staPipe,staCenter);
-      }
+        val numQueues = if (mQueues==null) 0 else mQueues!!.size
 
-    return null;
+        for (i in 0 until numQueues)
+        {
+            val queue = mQueues!![i]
+            queue.setAssociation(iD)
+        }
     }
-  }
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/src/main/java/org/distorted/library/effect/VertexEffectDeform.kt b/src/main/java/org/distorted/library/effect/VertexEffectDeform.kt
index f1cb0d7..6c5f7b0 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffectDeform.kt
+++ b/src/main/java/org/distorted/library/effect/VertexEffectDeform.kt
@@ -18,184 +18,173 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.effect;
+package org.distorted.library.effect
 
-import org.distorted.library.type.Data1D;
-import org.distorted.library.type.Data3D;
-import org.distorted.library.type.Data4D;
+import org.distorted.library.type.Data1D
+import org.distorted.library.type.Data3D
+import org.distorted.library.type.Data4D
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Deform the Mesh by applying a 3D vector of force.
  */
-public class VertexEffectDeform extends VertexEffect
-  {
-  private static final EffectName NAME = EffectName.DEFORM;
-
-  private final Data3D mVector, mCenter;
-  private final Data1D mRadius;
-  private final Data4D mRegion;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public boolean compute(float[] uniforms, int index, long currentDuration, long step )
-    {
-    mCenter.get(uniforms,index+CENTER_OFFSET  ,currentDuration,step);
-    mRegion.get(uniforms,index+REGION_OFFSET  ,currentDuration,step);
-    mRadius.get(uniforms,index+VALUES_OFFSET+3,currentDuration,step);
-
-    return mVector.get(uniforms,index+VALUES_OFFSET,currentDuration,step);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Deform the whole shape of the Object by force V. Algorithm is as follows:
-//
-// Suppose we apply force (Vx,Vy) at point (Cx,Cy) (i.e. the center of the effect). Then, first of all,
-// divide the rectangle into 4 smaller rectangles along the 1 horizontal + 1 vertical lines that pass
-// through (Cx,Cy). Now suppose we have already understood the following case:
-//
-// A vertical (0,Vy) force applied to a rectangle (WxH) in size, at center which is the top-left corner
-// of the rectangle.  (*)
-//
-// If we understand (*), then we understand everything, because in order to compute the movement of the
-// whole rectangle we can apply (*) 8 times: for each one of the 4 sub-rectangles, apply (*) twice,
-// once for the vertical component of the force vector, the second time for the horizontal one.
-//
-// Let's then compute (*):
-// 1) the top-left point will move by exactly (0,Vy)
-// 2) we arbitrarily decide that the top-right point will move by (|Vy|/(|Vy|+A*W))*Vy, where A is some
-//    arbitrary constant (const float A below). The F(V,W) = (|Vy|/(|Vy|+A*W)) comes from the following:
-//    a) we want F(V,0) = 1
-//    b) we want lim V->inf (F) = 1
-//    c) we actually want F() to only depend on W/V, which we have here.
-// 3) then the top edge of the rectangle will move along the line Vy*G(x), where G(x) = (1 - (A*W/(|Vy|+A*W))*(x/W)^2)
-// 4) Now we decide that the left edge of the rectangle will move along Vy*H(y), where H(y) = (1 - |y|/(|Vy|+C*|y|))
-//    where C is again an arbitrary constant. Again, H(y) comes from the requirement that no matter how
-//    strong we push the left edge of the rectangle up or down, it can never 'go over itself', but its
-//    length will approach 0 if squeezed very hard.
-// 5) The last point we need to compute is the left-right motion of the top-right corner (i.e. if we push
-//    the top-left corner up very hard, we want to have the top-right corner not only move up, but also to
-//    the left at least a little bit).
-//    We arbitrarily decide that, in addition to moving up-down by Vy*F(V,W), the corner will also move
-//    left-right by I(V,W) = B*W*F(V,W), where B is again an arbitrary constant.
-// 6) combining 3), 4) and 5) together, we arrive at a movement of an arbitrary point (x,y) away from the
-//    top-left corner:
-//    X(x,y) = -B*x * (|Vy|/(|Vy|+A*W)) * (1-(y/H)^2)                               (**)
-//    Y(x,y) = Vy * (1 - |y|/(|Vy|+C*|y|)) * (1 - (A*W/(|Vy|+A*W))*(x/W)^2)         (**)
-//
-// We notice that formulas (**) have been construed so that it is possible to continously mirror them
-// left-right and up-down (i.e. apply not only to the 'bottom-right' rectangle of the 4 subrectangles
-// but to all 4 of them!).
-//
-// Constants:
-// a) A : valid values: (0,infinity). 'Bendiness' if the surface - the higher A is, the more the surface
-//        bends. A<=0 destroys the system.
-// b) B : valid values: <-1,1>. The amount side edges get 'sucked' inwards when we pull the middle of the
-//        top edge up. B=0 --> not at all, B=1: a looot. B=-0.5: the edges will actually be pushed outwards
-//        quite a bit. One can also set it to <-1 or >1, but it will look a bit ridiculous.
-// c) C : valid values: <1,infinity). The derivative of the H(y) function at 0, i.e. the rate of 'squeeze'
-//        surface gets along the force line. C=1: our point gets pulled very closely to points above it
-//        even when we apply only small vertical force to it. The higher C is, the more 'uniform' movement
-//        along the force line is.
-//        0<=C<1 looks completely ridiculous and C<0 destroys the system.
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// 2020-05-03: replaced vec3 'u_Bounding' with a uniform 'vUniforms[effect].w' (i.e. mRadius)
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  static String code()
+class VertexEffectDeform : VertexEffect
+{
+    private val mVector: Data3D
+    private val mCenter: Data3D
+    private val mRadius: Data1D
+    private val mRegion: Data4D
+
+    companion object
     {
-    return
-
-        "const vec3 ONE = vec3(1.0,1.0,1.0);                                 \n"
-      + "const float A = 0.5;                                                \n"
-      + "const float B = 0.2;                                                \n"
-      + "const float C = 5.0;                                                \n"
-
-      + "vec3 center = vUniforms[effect+1].yzw;                              \n"
-      + "vec3 ps     = center-v;                                             \n"
-      + "vec3 aPS    = abs(ps);                                              \n"
-      + "vec3 maxps  = vUniforms[effect].w + abs(center);                    \n"
-      + "float d     = degree(vUniforms[effect+2],ps);                       \n"
-      + "vec3 force  = vUniforms[effect].xyz * d;                            \n"
-      + "vec3 aForce = abs(force);                                           \n"
-      + "float denom = dot(ps+(1.0-d)*force,ps);                             \n"
-      + "float one_over_denom = 1.0/(denom-0.001*(sign(denom)-1.0));         \n"
-      + "vec3 Aw = A*maxps;                                                  \n"
-      + "vec3 quot = ps / maxps;                                             \n"
-      + "quot = quot*quot;                                                   \n"  // ( (x/W)^2 , (y/H)^2 ) where x,y are distances from V to center
-
-      + "float denomV = 1.0 / (aForce.y + Aw.x);                             \n"
-      + "float denomH = 1.0 / (aForce.x + Aw.y);                             \n"
-
-      + "vec3 one_over_aforce = aForce - 0.001*(sign(aForce)-ONE);           \n"  // avoid division by 0 when force and PS both are 0
-      + "vec3 vertCorr= ONE - aPS/(C*aPS + one_over_aforce);                 \n"  // avoid division by 0 when force and PS both are 0
-
-      + "float mvXvert = -B * ps.x * aForce.y * (1.0-quot.y) * denomV;       \n"  // impact the vertical   component of the force vector has on horizontal movement
-      + "float mvYhorz = -B * ps.y * aForce.x * (1.0-quot.x) * denomH;       \n"  // impact the horizontal component of the force vector has on vertical   movement
-      + "float mvYvert = force.y * (1.0-quot.x*Aw.x*denomV) * vertCorr.y;    \n"  // impact the vertical   component of the force vector has on vertical   movement
-      + "float mvXhorz = force.x * (1.0-quot.y*Aw.y*denomH) * vertCorr.x;    \n"  // impact the horizontal component of the force vector has on horizontal movement
-
-      + "v.x += (mvXvert+mvXhorz);                                           \n"
-      + "v.y += (mvYvert+mvYhorz);                                           \n"
-
-      + "v.z += force.z*d*d*(3.0*d*d -8.0*d +6.0);                           \n"  // thick bubble
-      + "float b = -(12.0*force.z*d*(1.0-d)*(1.0-d)*(1.0-d))*one_over_denom; \n"
-
-      + "n.xy += n.z*b*ps.xy;                                                \n"
-      + "n = normalize(n);";
+        private val NAME = EffectName.DEFORM
+
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        // PUBLIC API
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        // Deform the whole shape of the Object by force V. Algorithm is as follows:
+        //
+        // Suppose we apply force (Vx,Vy) at point (Cx,Cy) (i.e. the center of the effect). Then, first of all,
+        // divide the rectangle into 4 smaller rectangles along the 1 horizontal + 1 vertical lines that pass
+        // through (Cx,Cy). Now suppose we have already understood the following case:
+        //
+        // A vertical (0,Vy) force applied to a rectangle (WxH) in size, at center which is the top-left corner
+        // of the rectangle.  (*)
+        //
+        // If we understand (*), then we understand everything, because in order to compute the movement of the
+        // whole rectangle we can apply (*) 8 times: for each one of the 4 sub-rectangles, apply (*) twice,
+        // once for the vertical component of the force vector, the second time for the horizontal one.
+        //
+        // Let's then compute (*):
+        // 1) the top-left point will move by exactly (0,Vy)
+        // 2) we arbitrarily decide that the top-right point will move by (|Vy|/(|Vy|+A*W))*Vy, where A is some
+        //    arbitrary constant (const float A below). The F(V,W) = (|Vy|/(|Vy|+A*W)) comes from the following:
+        //    a) we want F(V,0) = 1
+        //    b) we want lim V->inf (F) = 1
+        //    c) we actually want F() to only depend on W/V, which we have here.
+        // 3) then the top edge of the rectangle will move along the line Vy*G(x), where G(x) = (1 - (A*W/(|Vy|+A*W))*(x/W)^2)
+        // 4) Now we decide that the left edge of the rectangle will move along Vy*H(y), where H(y) = (1 - |y|/(|Vy|+C*|y|))
+        //    where C is again an arbitrary constant. Again, H(y) comes from the requirement that no matter how
+        //    strong we push the left edge of the rectangle up or down, it can never 'go over itself', but its
+        //    length will approach 0 if squeezed very hard.
+        // 5) The last point we need to compute is the left-right motion of the top-right corner (i.e. if we push
+        //    the top-left corner up very hard, we want to have the top-right corner not only move up, but also to
+        //    the left at least a little bit).
+        //    We arbitrarily decide that, in addition to moving up-down by Vy*F(V,W), the corner will also move
+        //    left-right by I(V,W) = B*W*F(V,W), where B is again an arbitrary constant.
+        // 6) combining 3), 4) and 5) together, we arrive at a movement of an arbitrary point (x,y) away from the
+        //    top-left corner:
+        //    X(x,y) = -B*x * (|Vy|/(|Vy|+A*W)) * (1-(y/H)^2)                               (**)
+        //    Y(x,y) = Vy * (1 - |y|/(|Vy|+C*|y|)) * (1 - (A*W/(|Vy|+A*W))*(x/W)^2)         (**)
+        //
+        // We notice that formulas (**) have been construed so that it is possible to continously mirror them
+        // left-right and up-down (i.e. apply not only to the 'bottom-right' rectangle of the 4 subrectangles
+        // but to all 4 of them!).
+        //
+        // Constants:
+        // a) A : valid values: (0,infinity). 'Bendiness' if the surface - the higher A is, the more the surface
+        //        bends. A<=0 destroys the system.
+        // b) B : valid values: <-1,1>. The amount side edges get 'sucked' inwards when we pull the middle of the
+        //        top edge up. B=0 --> not at all, B=1: a looot. B=-0.5: the edges will actually be pushed outwards
+        //        quite a bit. One can also set it to <-1 or >1, but it will look a bit ridiculous.
+        // c) C : valid values: <1,infinity). The derivative of the H(y) function at 0, i.e. the rate of 'squeeze'
+        //        surface gets along the force line. C=1: our point gets pulled very closely to points above it
+        //        even when we apply only small vertical force to it. The higher C is, the more 'uniform' movement
+        //        along the force line is.
+        //        0<=C<1 looks completely ridiculous and C<0 destroys the system.
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        // 2020-05-03: replaced vec3 'u_Bounding' with a uniform 'vUniforms[effect].w' (i.e. mRadius)
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        fun code(): String
+        {
+            return ("""
+                     const vec3 ONE = vec3(1.0,1.0,1.0);                                 
+                     const float A = 0.5;                                                
+                     const float B = 0.2;                                                
+                     const float C = 5.0;                                                
+                     vec3 center = vUniforms[effect+1].yzw;                              
+                     vec3 ps     = center-v;                                             
+                     vec3 aPS    = abs(ps);                                              
+                     vec3 maxps  = vUniforms[effect].w + abs(center);                    
+                     float d     = degree(vUniforms[effect+2],ps);                       
+                     vec3 force  = vUniforms[effect].xyz * d;                            
+                     vec3 aForce = abs(force);                                           
+                     float denom = dot(ps+(1.0-d)*force,ps);                             
+                     float one_over_denom = 1.0/(denom-0.001*(sign(denom)-1.0));         
+                     vec3 Aw = A*maxps;                                                  
+                     vec3 quot = ps / maxps;                                             
+                     quot = quot*quot;                                                   
+                     float denomV = 1.0 / (aForce.y + Aw.x);                             
+                     float denomH = 1.0 / (aForce.x + Aw.y);                             
+                     vec3 one_over_aforce = aForce - 0.001*(sign(aForce)-ONE);           
+                     vec3 vertCorr= ONE - aPS/(C*aPS + one_over_aforce);                 
+                     float mvXvert = -B * ps.x * aForce.y * (1.0-quot.y) * denomV;       
+                     float mvYhorz = -B * ps.y * aForce.x * (1.0-quot.x) * denomH;       
+                     float mvYvert = force.y * (1.0-quot.x*Aw.x*denomV) * vertCorr.y;    
+                     float mvXhorz = force.x * (1.0-quot.y*Aw.y*denomH) * vertCorr.x;    
+                     v.x += (mvXvert+mvXhorz);                                           
+                     v.y += (mvYvert+mvYhorz);                                           
+                     v.z += force.z*d*d*(3.0*d*d -8.0*d +6.0);                           
+                     float b = -(12.0*force.z*d*(1.0-d)*(1.0-d)*(1.0-d))*one_over_denom; 
+                     n.xy += n.z*b*ps.xy;                                                
+                     n = normalize(n);
+                     """.trimIndent())
+        }
+
+        ///////////////////////////////////////////////////////////////////////////////////////////////////
+        /**
+         * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
+         */
+        fun enable() = addEffect(NAME, code())
     }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
- */
-  public static void enable()
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Only for use by the library itself.
+     *
+     * @y.exclude
+     */
+    override fun compute(uniforms: FloatArray, index: Int, currentDuration: Long, step: Long): Boolean
     {
-    addEffect( NAME, code() );
+        mCenter.get(uniforms, index+CENTER_OFFSET, currentDuration, step)
+        mRegion.get(uniforms, index+REGION_OFFSET, currentDuration, step)
+        mRadius.get(uniforms, index+VALUES_OFFSET+3, currentDuration, step)
+        return mVector.get(uniforms, index+VALUES_OFFSET, currentDuration, step)
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Deform the whole Mesh with a (possibly changing in time) vector of force applied to
- * a (possibly changing in time) point on the Mesh.
- *
- * @param vector Vector of force that deforms the Mesh.
- * @param radius How 'bendy' the object is. Don';t set this to 0. Typically set this to the object's
- *               mesh size (i.e. more or less X of the rightmost vertex - X of the leftmost vertex)
- * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
- * @param region Region that masks the Effect.
- */
-  public VertexEffectDeform(Data3D vector, Data1D radius, Data3D center, Data4D region)
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Deform the whole Mesh with a (possibly changing in time) vector of force applied to
+     * a (possibly changing in time) point on the Mesh.
+     *
+     * @param vector Vector of force that deforms the Mesh.
+     * @param radius How 'bendy' the object is. Don';t set this to 0. Typically set this to the object's
+     * mesh size (i.e. more or less X of the rightmost vertex - X of the leftmost vertex)
+     * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
+     * @param region Region that masks the Effect.
+     */
+    constructor(vector: Data3D, radius: Data1D, center: Data3D, region: Data4D?) : super(NAME)
     {
-    super(NAME);
-    mVector = vector;
-    mRadius = radius;
-    mCenter = center;
-    mRegion = (region==null ? MAX_REGION : region);
+        mVector = vector
+        mRadius = radius
+        mCenter = center
+        mRegion = (region ?: MAX_REGION)
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Deform the whole Mesh with a (possibly changing in time) vector of force applied to
- * a (possibly changing in time) point on the Mesh.
- *
- * @param vector Vector of force that deforms the Mesh.
- * @param radius How 'bendy' the object is. Don't set this to 0. Typically set this to the object's
- *               mesh size (i.e. more or less X of the rightmost vertex - X of the leftmost vertex)
- * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
- */
-  public VertexEffectDeform(Data3D vector, Data1D radius, Data3D center)
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Deform the whole Mesh with a (possibly changing in time) vector of force applied to
+     * a (possibly changing in time) point on the Mesh.
+     *
+     * @param vector Vector of force that deforms the Mesh.
+     * @param radius How 'bendy' the object is. Don't set this to 0. Typically set this to the object's
+     * mesh size (i.e. more or less X of the rightmost vertex - X of the leftmost vertex)
+     * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
+     */
+    constructor(vector: Data3D, radius: Data1D, center: Data3D) : super(NAME)
     {
-    super(NAME);
-    mVector = vector;
-    mRadius = radius;
-    mCenter = center;
-    mRegion = MAX_REGION;
+        mVector = vector
+        mRadius = radius
+        mCenter = center
+        mRegion = MAX_REGION
     }
-  }
+}
diff --git a/src/main/java/org/distorted/library/effect/VertexEffectDisappear.kt b/src/main/java/org/distorted/library/effect/VertexEffectDisappear.kt
index 9b2ba52..38a0378 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffectDisappear.kt
+++ b/src/main/java/org/distorted/library/effect/VertexEffectDisappear.kt
@@ -18,54 +18,26 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.effect;
+package org.distorted.library.effect
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-
 /**
  * Make the whole Mesh disappear.
  */
-public class VertexEffectDisappear extends VertexEffect
-  {
-  private static final EffectName NAME = EffectName.DISAPPEAR;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public boolean compute(float[] uniforms, int index, long currentDuration, long step )
-    {
-    return false;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  static String code()
-    {
-    return "v = vec3(0.0, 0.0, 0.0);";
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
- */
-  public static void enable()
+class VertexEffectDisappear : VertexEffect(NAME)
+{
+    companion object
     {
-    addEffect( NAME, code() );
+        private val NAME = EffectName.DISAPPEAR
+        fun code(): String = "v = vec3(0.0, 0.0, 0.0);"
+        fun enable() = addEffect(NAME, code())
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Disappear the whole (component of the) Mesh.
- */
-  public VertexEffectDisappear()
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    override fun compute(uniforms: FloatArray, index: Int, currentDuration: Long, step: Long): Boolean
     {
-    super(NAME);
+        return false
     }
-  }
+}
 
 
diff --git a/src/main/java/org/distorted/library/effect/VertexEffectDistort.kt b/src/main/java/org/distorted/library/effect/VertexEffectDistort.kt
index e53825e..dd3a980 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffectDistort.kt
+++ b/src/main/java/org/distorted/library/effect/VertexEffectDistort.kt
@@ -18,186 +18,164 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.effect;
+package org.distorted.library.effect
 
-import org.distorted.library.type.Data3D;
-import org.distorted.library.type.Data4D;
+import org.distorted.library.type.Data3D
+import org.distorted.library.type.Data4D
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Distort the Mesh by applying a 3D vector of force.
  */
-public class VertexEffectDistort extends VertexEffect
-  {
-  private static final EffectName NAME = EffectName.DISTORT;
+class VertexEffectDistort : VertexEffect
+{
+    private val mVector: Data3D
+    private val mCenter: Data3D
+    private val mRegion: Data4D
 
-  private final Data3D mVector, mCenter;
-  private final Data4D mRegion;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public boolean compute(float[] uniforms, int index, long currentDuration, long step )
+    companion object
     {
-    mCenter.get(uniforms,index+CENTER_OFFSET,currentDuration,step);
-    mRegion.get(uniforms,index+REGION_OFFSET,currentDuration,step);
-
-    return mVector.get(uniforms,index+VALUES_OFFSET,currentDuration,step);
+        private val NAME = EffectName.DISTORT
+
+        ///////////////////////////////////////////////////////////////////////////////////////////////////
+        // PUBLIC API
+        ///////////////////////////////////////////////////////////////////////////////////////////////////
+        // Def: P-current vertex being distorted, S - center of the effect, X- point where half-line SP meets
+        // the region circle (if P is inside the circle); (Vx,Vy,Vz) - force vector.
+        //
+        // horizontal part
+        // Point (Px,Py) gets moved by vector (Wx,Wy) where Wx/Wy = Vx/Vy i.e. Wx=aVx and Wy=aVy where
+        // a=Py/Sy (N --> when (Px,Py) is above (Sx,Sy)) or a=Px/Sx (W) or a=(w-Px)/(w-Sx) (E) or a=(h-Py)/(h-Sy) (S)
+        // It remains to be computed which of the N,W,E or S case we have: answer: a = min[ Px/Sx , Py/Sy , (w-Px)/(w-Sx) , (h-Py)/(h-Sy) ]
+        // Computations above are valid for screen (0,0)x(w,h) but here we have (-w/2,-h/2)x(w/2,h/2)
+        //
+        // vertical part
+        // Let vector PS = (dx,dy), f(x) (0<=x<=|SX|) be the shape of the side of the bubble.
+        // H(Px,Py) = |PS|>|SX| ? 0 : f(|PX|)
+        // N(Px,Py) = |PS|>|SX| ? (0,0,1) : ( -(dx/|PS|)sin(beta), -(dy/|PS|)sin(beta), cos(beta) ) where tan(beta) is f'(|PX|)
+        // ( i.e. normalize( dx, dy, -|PS|/f'(|PX|) )
+        //
+        // Now we also have to take into account the effect horizontal move by V=(Vx,Vy) will have on the normal vector.
+        // Solution:
+        // 1. Decompose the V into two subcomponents, one parallel to SX and another perpendicular.
+        // 2. Convince yourself (draw!) that the perpendicular component has no effect on normals.
+        // 3. The parallel component changes the length of |SX| by the factor of a=(|SX|-|Vpar|)/|SX| (where the length
+        //    can be negative depending on the direction)
+        // 4. that in turn leaves the x and y parts of the normal unchanged and multiplies the z component by a!
+        //
+        // |Vpar| = (Vx*dx-Vy*dy) / sqrt(ps_sq)  (-Vy because y is inverted)
+        // a =  (|SX| - |Vpar|)/|SX| = 1 - |Vpar|/((sqrt(ps_sq)/(1-d)) = 1 - (1-d)*|Vpar|/sqrt(ps_sq) = 1-(1-d)*(Vx*dx-Vy*dy)/ps_sq
+        //
+        // Side of the bubble
+        //
+        // choose from one of the three bubble shapes: the cone, the thin bubble and the thick bubble
+        // Case 1:
+        // f(t) = t, i.e. f(x) = Vz * x/|SX|   (a cone)
+        // -|PS|/f'(|PX|) = -|PS|*|SX|/Vz but since ps_sq=|PS|^2 and d=|PX|/|SX| then |PS|*|SX| = ps_sq/(1-d)
+        // so finally -|PS|/f'(|PX|) = -ps_sq/(Vz*(1-d))
+        //
+        // Case 2:
+        // f(t) = 3t^2 - 2t^3 --> f(0)=0, f'(0)=0, f'(1)=0, f(1)=1 (the bell curve)
+        // here we have t = x/|SX| which makes f'(|PX|) = 6*Vz*|PS|*|PX|/|SX|^3.
+        // so -|PS|/f'(|PX|) = (-|SX|^3)/(6Vz|PX|) =  (-|SX|^2) / (6*Vz*d) but
+        // d = |PX|/|SX| and ps_sq = |PS|^2 so |SX|^2 = ps_sq/(1-d)^2
+        // so finally -|PS|/f'(|PX|) = -ps_sq/ (6Vz*d*(1-d)^2)
+        //
+        // Case 3:
+        // f(t) = 3t^4-8t^3+6t^2 would be better as this satisfies f(0)=0, f'(0)=0, f'(1)=0, f(1)=1,
+        // f(0.5)=0.7 and f'(t)= t(t-1)^2 >=0 for t>=0 so this produces a fuller, thicker bubble!
+        // then -|PS|/f'(|PX|) = (-|PS|*|SX)) / (12Vz*d*(d-1)^2) but |PS|*|SX| = ps_sq/(1-d) (see above!)
+        // so finally -|PS|/f'(|PX|) = -ps_sq/ (12Vz*d*(1-d)^3)
+        //
+        // Now, new requirement: we have to be able to add up normal vectors, i.e. distort already distorted surfaces.
+        // If a surface is given by z = f(x,y), then the normal vector at (x0,y0) is given by (-df/dx (x0,y0), -df/dy (x0,y0), 1 ).
+        // so if we have two surfaces defined by f1(x,y) and f2(x,y) with their normals expressed as (f1x,f1y,1) and (f2x,f2y,1)
+        // then the normal to g = f1+f2 is simply given by (f1x+f2x,f1y+f2y,1), i.e. if the third components are equal, then we
+        // can simply add up the first and second components.
+        //
+        // Thus we actually want to compute N(Px,Py) = a*(-(dx/|PS|)*f'(|PX|), -(dy/|PS|)*f'(|PX|), 1) and keep adding
+        // the first two components. (a is the horizontal part)
+        //
+        // 2019-01-09 fixes for stuff discovered with the Earth testing app
+        // Now, the above stuff works only if the normal vector is close to (0,0,1). To make it work for any situation,
+        // rotate the normal, force and ps vectors along the axis (n.y,-n.x,0) and angle A between the normal and (0,0,1)
+        // then modify the rotated normal (so (0,0,1)) and rotate the modified normal back.
+        //
+        // if we have a vector (vx,vy,vz) that w want to rotate with a rotation that turns the normal into (0,0,1), then
+        // a) axis of rotation = (n.x,n.y,n.z) x (0,0,1) = (n.y,-n.x,0)
+        // b) angle of rotation A: cosA = (n.x,n.y,n.z)*(0,0,1) = n.z     (and sinA = + sqrt(1-n.z^2))
+        //
+        // so normalized axisNor = (n.x/ sinA, -n.y/sinA, 0) and now from Rodrigues rotation formula
+        // Vrot = v*cosA + (axisNor x v)*sinA + axisNor*(axis*v)*(1-cosA)
+        //
+        // which makes Vrot = (a+n.y*c , b-n.y*c , v*n) where
+        // a = vx*nz-vz*nx , b = vy*nz-vz*ny , c = (vx*ny-vy*nx)/(1+nz)    (unless n=(0,0,-1))
+        ///////////////////////////////////////////////////////////////////////////////////////////////////
+        fun code(): String
+        {
+            return (""" vec3 ps = vUniforms[effect+1].yzw - v;                        
+                        vec3 force = vUniforms[effect].xyz;                           
+                        vec4 region= vUniforms[effect+2];                             
+                        float d = degree(region,ps);                                  
+                        if( d>0.0 )                                                   
+                          {                                                           
+                          v += d*force;                                               
+                          float tp = 1.0+n.z;                                         
+                          float tr = 1.0 / (tp - (sign(tp)-1.0));                     
+                          float ap = ps.x*n.z - ps.z*n.x;                             
+                          float bp = ps.y*n.z - ps.z*n.y;                             
+                          float cp =(ps.x*n.y - ps.y*n.x)*tr;                         
+                          vec3 psRot = vec3( ap+n.y*cp , bp-n.x*cp , dot(ps,n) );     
+                          float len = length(psRot);                                  
+                          float corr= sign(len)-1.0;                                  
+                          vec3 N = vec3( -dot(force,n)*psRot.xy, region.w*len-corr ); 
+                          float an = N.x*n.z + N.z*n.x;                               
+                          float bn = N.y*n.z + N.z*n.y;                               
+                          float cn =(N.x*n.y - N.y*n.x)*tr;                           
+                          n = vec3( an+n.y*cn , bn-n.x*cn , -N.x*n.x-N.y*n.y+N.z*n.z);
+                          n = normalize(n);                                           
+                          }""".trimIndent() )
+        }
+
+        ///////////////////////////////////////////////////////////////////////////////////////////////////
+        fun enable() =addEffect(NAME, code())
     }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Def: P-current vertex being distorted, S - center of the effect, X- point where half-line SP meets
-// the region circle (if P is inside the circle); (Vx,Vy,Vz) - force vector.
-//
-// horizontal part
-// Point (Px,Py) gets moved by vector (Wx,Wy) where Wx/Wy = Vx/Vy i.e. Wx=aVx and Wy=aVy where
-// a=Py/Sy (N --> when (Px,Py) is above (Sx,Sy)) or a=Px/Sx (W) or a=(w-Px)/(w-Sx) (E) or a=(h-Py)/(h-Sy) (S)
-// It remains to be computed which of the N,W,E or S case we have: answer: a = min[ Px/Sx , Py/Sy , (w-Px)/(w-Sx) , (h-Py)/(h-Sy) ]
-// Computations above are valid for screen (0,0)x(w,h) but here we have (-w/2,-h/2)x(w/2,h/2)
-//
-// vertical part
-// Let vector PS = (dx,dy), f(x) (0<=x<=|SX|) be the shape of the side of the bubble.
-// H(Px,Py) = |PS|>|SX| ? 0 : f(|PX|)
-// N(Px,Py) = |PS|>|SX| ? (0,0,1) : ( -(dx/|PS|)sin(beta), -(dy/|PS|)sin(beta), cos(beta) ) where tan(beta) is f'(|PX|)
-// ( i.e. normalize( dx, dy, -|PS|/f'(|PX|) )
-//
-// Now we also have to take into account the effect horizontal move by V=(Vx,Vy) will have on the normal vector.
-// Solution:
-// 1. Decompose the V into two subcomponents, one parallel to SX and another perpendicular.
-// 2. Convince yourself (draw!) that the perpendicular component has no effect on normals.
-// 3. The parallel component changes the length of |SX| by the factor of a=(|SX|-|Vpar|)/|SX| (where the length
-//    can be negative depending on the direction)
-// 4. that in turn leaves the x and y parts of the normal unchanged and multiplies the z component by a!
-//
-// |Vpar| = (Vx*dx-Vy*dy) / sqrt(ps_sq)  (-Vy because y is inverted)
-// a =  (|SX| - |Vpar|)/|SX| = 1 - |Vpar|/((sqrt(ps_sq)/(1-d)) = 1 - (1-d)*|Vpar|/sqrt(ps_sq) = 1-(1-d)*(Vx*dx-Vy*dy)/ps_sq
-//
-// Side of the bubble
-//
-// choose from one of the three bubble shapes: the cone, the thin bubble and the thick bubble
-// Case 1:
-// f(t) = t, i.e. f(x) = Vz * x/|SX|   (a cone)
-// -|PS|/f'(|PX|) = -|PS|*|SX|/Vz but since ps_sq=|PS|^2 and d=|PX|/|SX| then |PS|*|SX| = ps_sq/(1-d)
-// so finally -|PS|/f'(|PX|) = -ps_sq/(Vz*(1-d))
-//
-// Case 2:
-// f(t) = 3t^2 - 2t^3 --> f(0)=0, f'(0)=0, f'(1)=0, f(1)=1 (the bell curve)
-// here we have t = x/|SX| which makes f'(|PX|) = 6*Vz*|PS|*|PX|/|SX|^3.
-// so -|PS|/f'(|PX|) = (-|SX|^3)/(6Vz|PX|) =  (-|SX|^2) / (6*Vz*d) but
-// d = |PX|/|SX| and ps_sq = |PS|^2 so |SX|^2 = ps_sq/(1-d)^2
-// so finally -|PS|/f'(|PX|) = -ps_sq/ (6Vz*d*(1-d)^2)
-//
-// Case 3:
-// f(t) = 3t^4-8t^3+6t^2 would be better as this satisfies f(0)=0, f'(0)=0, f'(1)=0, f(1)=1,
-// f(0.5)=0.7 and f'(t)= t(t-1)^2 >=0 for t>=0 so this produces a fuller, thicker bubble!
-// then -|PS|/f'(|PX|) = (-|PS|*|SX)) / (12Vz*d*(d-1)^2) but |PS|*|SX| = ps_sq/(1-d) (see above!)
-// so finally -|PS|/f'(|PX|) = -ps_sq/ (12Vz*d*(1-d)^3)
-//
-// Now, new requirement: we have to be able to add up normal vectors, i.e. distort already distorted surfaces.
-// If a surface is given by z = f(x,y), then the normal vector at (x0,y0) is given by (-df/dx (x0,y0), -df/dy (x0,y0), 1 ).
-// so if we have two surfaces defined by f1(x,y) and f2(x,y) with their normals expressed as (f1x,f1y,1) and (f2x,f2y,1)
-// then the normal to g = f1+f2 is simply given by (f1x+f2x,f1y+f2y,1), i.e. if the third components are equal, then we
-// can simply add up the first and second components.
-//
-// Thus we actually want to compute N(Px,Py) = a*(-(dx/|PS|)*f'(|PX|), -(dy/|PS|)*f'(|PX|), 1) and keep adding
-// the first two components. (a is the horizontal part)
-//
-// 2019-01-09 fixes for stuff discovered with the Earth testing app
-// Now, the above stuff works only if the normal vector is close to (0,0,1). To make it work for any situation,
-// rotate the normal, force and ps vectors along the axis (n.y,-n.x,0) and angle A between the normal and (0,0,1)
-// then modify the rotated normal (so (0,0,1)) and rotate the modified normal back.
-//
-// if we have a vector (vx,vy,vz) that w want to rotate with a rotation that turns the normal into (0,0,1), then
-// a) axis of rotation = (n.x,n.y,n.z) x (0,0,1) = (n.y,-n.x,0)
-// b) angle of rotation A: cosA = (n.x,n.y,n.z)*(0,0,1) = n.z     (and sinA = + sqrt(1-n.z^2))
-//
-// so normalized axisNor = (n.x/ sinA, -n.y/sinA, 0) and now from Rodrigues rotation formula
-// Vrot = v*cosA + (axisNor x v)*sinA + axisNor*(axis*v)*(1-cosA)
-//
-// which makes Vrot = (a+n.y*c , b-n.y*c , v*n) where
-// a = vx*nz-vz*nx , b = vy*nz-vz*ny , c = (vx*ny-vy*nx)/(1+nz)    (unless n=(0,0,-1))
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  static String code()
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    override fun compute(uniforms: FloatArray, index: Int, currentDuration: Long, step: Long): Boolean
     {
-    return
-
-        "vec3 ps = vUniforms[effect+1].yzw - v;                        \n"
-      + "vec3 force = vUniforms[effect].xyz;                           \n"
-      + "vec4 region= vUniforms[effect+2];                             \n"
-      + "float d = degree(region,ps);                                  \n"
-
-      + "if( d>0.0 )                                                   \n"
-      + "  {                                                           \n"
-      + "  v += d*force;                                               \n"
-
-      + "  float tp = 1.0+n.z;                                         \n"
-      + "  float tr = 1.0 / (tp - (sign(tp)-1.0));                     \n"   // proper way to compute 1/x is
-                                                                             // 1/(x-(sign(x)-1)) and NOT 1/(x+1-sign(x))
-
-      + "  float ap = ps.x*n.z - ps.z*n.x;                             \n"   // rotate the ps vector
-      + "  float bp = ps.y*n.z - ps.z*n.y;                             \n"   //
-      + "  float cp =(ps.x*n.y - ps.y*n.x)*tr;                         \n"   //
-      + "  vec3 psRot = vec3( ap+n.y*cp , bp-n.x*cp , dot(ps,n) );     \n"   //
-
-      + "  float len = length(psRot);                                  \n"
-      + "  float corr= sign(len)-1.0;                                  \n"   // make N (0,0,1) if ps=(0,0,0)
-      + "  vec3 N = vec3( -dot(force,n)*psRot.xy, region.w*len-corr ); \n"   // modified rotated normal
-                                                                             // dot(force,n) is rotated force.z
-      + "  float an = N.x*n.z + N.z*n.x;                               \n"   // now create the normal vector
-      + "  float bn = N.y*n.z + N.z*n.y;                               \n"   // back from our modified normal
-      + "  float cn =(N.x*n.y - N.y*n.x)*tr;                           \n"   // rotated back
-      + "  n = vec3( an+n.y*cn , bn-n.x*cn , -N.x*n.x-N.y*n.y+N.z*n.z);\n"   // notice 4 signs change!
-
-      + "  n = normalize(n);                                           \n"
-      + "  }";
-
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
- */
-  public static void enable()
-    {
-    addEffect( NAME, code() );
+        mCenter.get(uniforms, index+CENTER_OFFSET, currentDuration, step)
+        mRegion.get(uniforms, index+REGION_OFFSET, currentDuration, step)
+        return mVector.get(uniforms, index+VALUES_OFFSET, currentDuration, step)
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Distort a (possibly changing in time) part of the Mesh by a (possibly changing in time) vector of force.
- *
- * @param vector vector of force the Center of the Effect is currently being dragged with.
- * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
- * @param region Region that masks the Effect.
- */
-  public VertexEffectDistort(Data3D vector, Data3D center, Data4D region)
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Distort a (possibly changing in time) part of the Mesh by a (possibly changing in time) vector of force.
+     *
+     * @param vector vector of force the Center of the Effect is currently being dragged with.
+     * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
+     * @param region Region that masks the Effect.
+     */
+    constructor(vector: Data3D, center: Data3D, region: Data4D?) : super(NAME)
     {
-    super(NAME);
-    mVector = vector;
-    mCenter = center;
-    mRegion = (region==null ? MAX_REGION : region);
+        mVector = vector
+        mCenter = center
+        mRegion = (region ?: MAX_REGION)
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Distort the whole Mesh by a (possibly changing in time) vector of force.
- *
- * @param vector vector of force the Center of the Effect is currently being dragged with.
- * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
- */
-  public VertexEffectDistort(Data3D vector, Data3D center)
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Distort the whole Mesh by a (possibly changing in time) vector of force.
+     *
+     * @param vector vector of force the Center of the Effect is currently being dragged with.
+     * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
+     */
+    constructor(vector: Data3D, center: Data3D) : super(NAME)
     {
-    super(NAME);
-    mVector = vector;
-    mCenter = center;
-    mRegion = MAX_REGION;
+        mVector = vector
+        mCenter = center
+        mRegion = MAX_REGION
     }
-  }
+}
 
 
diff --git a/src/main/java/org/distorted/library/effect/VertexEffectMove.kt b/src/main/java/org/distorted/library/effect/VertexEffectMove.kt
index 46b907a..f617a82 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffectMove.kt
+++ b/src/main/java/org/distorted/library/effect/VertexEffectMove.kt
@@ -18,59 +18,27 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.effect;
+package org.distorted.library.effect
 
-import org.distorted.library.type.Data3D;
+import org.distorted.library.type.Data3D
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-
 /**
  * Move the Mesh with a given vector.
  */
-public class VertexEffectMove extends VertexEffect
-  {
-  private static final EffectName NAME = EffectName.VERTEX_MOVE;
-
-  private final Data3D mVector;
+class VertexEffectMove(vector: Data3D) : VertexEffect(NAME)
+{
+    private val mVector = vector
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public boolean compute(float[] uniforms, int index, long currentDuration, long step )
+    companion object
     {
-    return mVector.get(uniforms,index+VALUES_OFFSET,currentDuration,step);
+        private val NAME = EffectName.VERTEX_MOVE
+        fun code(): String = "v += vUniforms[effect].xyz;"
+        fun enable() = addEffect(NAME, code())
     }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  static String code()
-    {
-    return "v += vUniforms[effect].xyz;";
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
- */
-  public static void enable()
-    {
-    addEffect( NAME, code() );
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Move the whole Mesh with a (possibly changing in time) vector.
- *
- * @param vector Vector by which to move the Mesh.
- */
-  public VertexEffectMove(Data3D vector)
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    override fun compute(uniforms: FloatArray, index: Int, currentDuration: Long, step: Long): Boolean
     {
-    super(NAME);
-    mVector = vector;
+        return mVector.get(uniforms, index+VALUES_OFFSET, currentDuration, step)
     }
-  }
+}
diff --git a/src/main/java/org/distorted/library/effect/VertexEffectPinch.kt b/src/main/java/org/distorted/library/effect/VertexEffectPinch.kt
index 1143a9d..fefde92 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffectPinch.kt
+++ b/src/main/java/org/distorted/library/effect/VertexEffectPinch.kt
@@ -18,126 +18,111 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.effect;
+package org.distorted.library.effect
 
-import org.distorted.library.type.Data3D;
-import org.distorted.library.type.Data4D;
+import org.distorted.library.type.Data3D
+import org.distorted.library.type.Data4D
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Pull all points around the center of the Effect towards a line passing through the center
  * (that's if degree>=1) or push them away from the line (degree<=1).
- * <p>
+ *
  * Note: this is not a fully 3D effect - the pinching is always within the XY plane; z coordinates
  * of all vertices remain unaffected. If someone wants a fully 3D Pinch effect, we'd probably need
  * to write another VertexEffectPinch3D with 2 more arguments (latitude and longitude angles defining
  * the plane the pinching works on).
  */
-public class VertexEffectPinch extends VertexEffect
-  {
-  private static final EffectName NAME = EffectName.PINCH;
-
-  private final Data3D mPinch;
-  private final Data3D mCenter;
-  private final Data4D mRegion;
+class VertexEffectPinch : VertexEffect
+{
+    private val mPinch: Data3D
+    private val mCenter: Data3D
+    private val mRegion: Data4D
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public boolean compute(float[] uniforms, int index, long currentDuration, long step )
+    companion object
     {
-    mCenter.get(uniforms,index+CENTER_OFFSET,currentDuration,step);
-    mRegion.get(uniforms,index+REGION_OFFSET,currentDuration,step);
-    boolean ret = mPinch.get(uniforms,index+VALUES_OFFSET,currentDuration,step);
+        private val NAME = EffectName.PINCH
 
-    uniforms[index+VALUES_OFFSET+1] = (float)(Math.PI*uniforms[index+1]/180);
-    uniforms[index+VALUES_OFFSET+2] = (float)(Math.PI*uniforms[index+2]/180);
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        // Pull P=(v.x,v.y) along a vector from the center of region sphere to a point on it defined by
+        // the (latitude,longitude) pair of angles with P' = P + (1-h)*dist(line to P)
+        // when h>1 we are pushing points away from S: P' = P + (1/h-1)*dist(line to P)
+        // (where 'line' above passes through the center point and goes along the vector)
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        fun code(): String
+        {
+            return ("""
+                     vec3 ps = vUniforms[effect+1].yzw -v;               
+                     float h         = vUniforms[effect].x;              
+                     float latitude  = vUniforms[effect].y;              
+                     float longitude = vUniforms[effect].z;              
+                     float deg = degree(vUniforms[effect+2],ps);         
+                     float t = deg * (1.0-h)/max(1.0,h);                 
+                     float sinLAT = sin(latitude);                       
+                     float cosLAT = cos(latitude);                       
+                     float sinLON = sin(longitude);                      
+                     float cosLON = cos(longitude);                      
+                     vec3 dir = vec3(sinLON*cosLAT,sinLAT,cosLON*cosLAT);
+                     float dot_dir_ps = dot(dir,ps);                     
+                     v += t*dot_dir_ps*dir;                              
+                     const float A = 1.6;                                
+                     const float B = 10.0;                               
+                     vec3 n_ps = dot(ps,n)*ps;                           
+                     float dot_ps = dot(ps,ps);                          
+                     float sign_ps= sign(dot_ps);                        
+                     n_ps = sign_ps*n_ps/(dot_ps-(sign_ps-1.0));         
+                     float move = deg*(h-1.0)/(h/B+1.0/A);               
+                     n += move * abs(dot(n,dir)) * n_ps;                 
+                     n = normalize(n);
+                     """.trimIndent())
+        }
 
-    return ret;
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        fun enable() = addEffect(NAME, code())
     }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Pull P=(v.x,v.y) along a vector from the center of region sphere to a point on it defined by
-// the (latitude,longitude) pair of angles with P' = P + (1-h)*dist(line to P)
-// when h>1 we are pushing points away from S: P' = P + (1/h-1)*dist(line to P)
-// (where 'line' above passes through the center point and goes along the vector)
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  static String code()
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    override fun compute(uniforms: FloatArray, index: Int, currentDuration: Long, step: Long): Boolean
     {
-    return
+        mCenter.get(uniforms, index+CENTER_OFFSET, currentDuration, step)
+        mRegion.get(uniforms, index+REGION_OFFSET, currentDuration, step)
+        val ret = mPinch.get(uniforms, index+VALUES_OFFSET, currentDuration, step)
 
-        "vec3 ps = vUniforms[effect+1].yzw -v;               \n"
-      + "float h         = vUniforms[effect].x;              \n"
-      + "float latitude  = vUniforms[effect].y;              \n"
-      + "float longitude = vUniforms[effect].z;              \n"
-      + "float deg = degree(vUniforms[effect+2],ps);         \n"
-      + "float t = deg * (1.0-h)/max(1.0,h);                 \n"
-      + "float sinLAT = sin(latitude);                       \n"
-      + "float cosLAT = cos(latitude);                       \n"
-      + "float sinLON = sin(longitude);                      \n"
-      + "float cosLON = cos(longitude);                      \n"
-      + "vec3 dir = vec3(sinLON*cosLAT,sinLAT,cosLON*cosLAT);\n"
-      + "float dot_dir_ps = dot(dir,ps);                     \n"
-      + "v += t*dot_dir_ps*dir;                              \n"
+        uniforms[index+VALUES_OFFSET+1] = (Math.PI*uniforms[index+1]/180).toFloat()
+        uniforms[index+VALUES_OFFSET+2] = (Math.PI*uniforms[index+2]/180).toFloat()
 
-      + "const float A = 1.6;                                \n" // max amount of change in normal vector when pulling
-      + "const float B = 10.0;                               \n" // when pushing
-      + "vec3 n_ps = dot(ps,n)*ps;                           \n" // n_ps = (component of n that's parallel to ps) * |ps|^2 (=dot(ps,ps))
-      + "float dot_ps = dot(ps,ps);                          \n"
-      + "float sign_ps= sign(dot_ps);                        \n"
-      + "n_ps = sign_ps*n_ps/(dot_ps-(sign_ps-1.0));         \n" // uff! now n_ps is the parallel to ps component of n, even if ps==0
-      + "float move = deg*(h-1.0)/(h/B+1.0/A);               \n" // move(0)=-A*deg, move(1)=0, move(inf)=B*deg
-      + "n += move * abs(dot(n,dir)) * n_ps;                 \n"
-      + "n = normalize(n);";
+        return ret
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
- */
-  public static void enable()
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Pull all points around the center of the Effect towards a line passing through the center
+     * (that's if degree>=1) or push them away from the line (degree<=1)
+     *
+     * @param pinch  The current degree of the Effect + (latitude,longitude) pair of angles defining the
+     * *             point towards which (and its antipode) the pinching power is strongest.
+     * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
+     * @param region Region that masks the Effect.
+     */
+    constructor(pinch: Data3D, center: Data3D, region: Data4D?) : super(NAME)
     {
-    addEffect( NAME, code() );
+        mPinch  = pinch
+        mCenter = center
+        mRegion = (region ?: MAX_REGION)
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Pull all points around the center of the Effect towards a line passing through the center
- * (that's if degree>=1) or push them away from the line (degree<=1)
- *
- * @param pinch  The current degree of the Effect + (latitude,longitude) pair of angles defining the
- *  *            point towards which (and its antipode) the pinching power is strongest.
- * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
- * @param region Region that masks the Effect.
- */
-  public VertexEffectPinch(Data3D pinch, Data3D center, Data4D region)
-    {
-    super(NAME);
-    mPinch  = pinch;
-    mCenter = center;
-    mRegion = (region==null ? MAX_REGION : region);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Pull all points around the center of the Effect towards a line passing through the center
- * (that's if degree>=1) or push them away from the line (degree<=1)
- *
- * @param pinch  The current degree of the Effect + (latitude,longitude) pair of angles defining the
- *               point towards which (and its antipode) the pinching power is strongest.
- * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
- */
-  public VertexEffectPinch(Data3D pinch, Data3D center)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Pull all points around the center of the Effect towards a line passing through the center
+     * (that's if degree>=1) or push them away from the line (degree<=1)
+     *
+     * @param pinch  The current degree of the Effect + (latitude,longitude) pair of angles defining the
+     * point towards which (and its antipode) the pinching power is strongest.
+     * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
+     */
+    constructor(pinch: Data3D, center: Data3D) : super(NAME)
     {
-    super(NAME);
-    mPinch  = pinch;
-    mCenter = center;
-    mRegion = MAX_REGION;
+        mPinch  = pinch
+        mCenter = center
+        mRegion = MAX_REGION
     }
-  }
+}
\ No newline at end of file
diff --git a/src/main/java/org/distorted/library/effect/VertexEffectPipe.kt b/src/main/java/org/distorted/library/effect/VertexEffectPipe.kt
index fd23dfb..8062b3d 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffectPipe.kt
+++ b/src/main/java/org/distorted/library/effect/VertexEffectPipe.kt
@@ -18,99 +18,64 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.effect;
+package org.distorted.library.effect
 
-import org.distorted.library.type.Data3D;
-import org.distorted.library.type.Data5D;
+import org.distorted.library.type.Data3D
+import org.distorted.library.type.Data5D
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-
 /**
  * Pull (degree>1) or push away from (degree<1) all points of an infinite 'pipe' shaped region.
  */
-public class VertexEffectPipe extends VertexEffect
-  {
-  private static final EffectName NAME = EffectName.PIPE;
-
-  private final Data5D mPipe;
-  private final Data3D mCenter;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public boolean compute(float[] uniforms, int index, long currentDuration, long step )
-    {
-    mCenter.get(uniforms,index+CENTER_OFFSET,currentDuration,step);
-    return mPipe.get(uniforms,index+VALUES_OFFSET,currentDuration,step);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// here, if one tests this with the 'Generic' examples app - and chooses the 'Cubes 3x3x3' mesh,
-// then adds an 'empty' PIPE effect - then two corners of the mesh turn bright.
-// It turns out this is because the points at those corners are very close to being on the
-// line defined by 'center' and 'vect' (so 'ps' is very small)
-// Then by means of some miracle we have
-// dot_ps>0, (sign_ps-1.0)==0.0 and dot_ps-(sign_ps-1.0) == 0.0 !! so n_ps - undef.
+class VertexEffectPipe(pipe: Data5D, center: Data3D) : VertexEffect(NAME)
+{
+    private val mPipe = pipe
+    private val mCenter = center
 
-  static String code()
+    companion object
     {
-    return
-
-        "vec3 pc = vUniforms[effect+1].yzw - v;            \n"
-      + "vec3 vect = vUniforms[effect].yzw;                \n"
-      + "vec3 ps = pc - dot(pc,vect)*vect;                 \n"
-      + "float radius = vUniforms[effect+1].x;             \n"
-      + "float deg = max( 0.0, 1.0 - length(ps)/radius );  \n"
-
-      + "float h = vUniforms[effect].x;                    \n" // from this point on, having calculated
-      + "float tmp = (1.0-h)*deg;                          \n" // ps and deg, proceed just like in Sink
-      + "float t1 = tmp*(deg+1.0)/h;                       \n"
-      + "float t2 = tmp/(0.618*(0.618+deg));               \n"
-      + "float t = t2 + (t1-t2)*((sign(h-1.0)+1.0)/2.0);   \n"
+        private val NAME = EffectName.PIPE
 
-      + "v += t*ps;                                        \n"
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        // here, if one tests this with the 'Generic' examples app - and chooses the 'Cubes 3x3x3' mesh,
+        // then adds an 'empty' PIPE effect - then two corners of the mesh turn bright.
+        // It turns out this is because the points at those corners are very close to being on the
+        // line defined by 'center' and 'vect' (so 'ps' is very small)
+        // Then by means of some miracle we have
+        // dot_ps>0, (sign_ps-1.0)==0.0 and dot_ps-(sign_ps-1.0) == 0.0 !! so n_ps - undef.
+        fun code(): String
+        {
+            return ("""
+                     vec3 pc = vUniforms[effect+1].yzw - v;            
+                     vec3 vect = vUniforms[effect].yzw;                
+                     vec3 ps = pc - dot(pc,vect)*vect;                 
+                     float radius = vUniforms[effect+1].x;             
+                     float deg = max( 0.0, 1.0 - length(ps)/radius );  
+                     float h = vUniforms[effect].x;                    
+                     float tmp = (1.0-h)*deg;                          
+                     float t1 = tmp*(deg+1.0)/h;                       
+                     float t2 = tmp/(0.618*(0.618+deg));               
+                     float t = t2 + (t1-t2)*((sign(h-1.0)+1.0)/2.0);   
+                     v += t*ps;                                        
+                     const float A = 1.6;                              
+                     const float B = 10.0;                             
+                     vec3 n_ps = dot(ps,n)*ps;                         
+                     float dot_ps = dot(ps,ps);                        
+                     float sign_ps= sign(dot_ps);                      
+                     n_ps = (sign_ps*n_ps)/(dot_ps-(sign_ps-1.0));     
+                     float move = deg*(h-1.0)/(h/B+1.0/A);             
+                     n += move*n_ps;                                   
+                     n = normalize(n);
+                     """.trimIndent())
+        }
 
-      + "const float A = 1.6;                              \n"
-      + "const float B = 10.0;                             \n"
-      + "vec3 n_ps = dot(ps,n)*ps;                         \n"
-      + "float dot_ps = dot(ps,ps);                        \n"
-      + "float sign_ps= sign(dot_ps);                      \n"
-      + "n_ps = (sign_ps*n_ps)/(dot_ps-(sign_ps-1.0));     \n"
-      + "float move = deg*(h-1.0)/(h/B+1.0/A);             \n"
-      + "n += move*n_ps;                                   \n"
-      + "n = normalize(n);";
+        ///////////////////////////////////////////////////////////////////////////////////////////////////
+        fun enable() = addEffect(NAME, code())
     }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
- */
-  public static void enable()
-    {
-    addEffect(NAME, code() );
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Pull (degree>1) or push away from (degree<1) all points of an infinite 'pipe' shaped region. We
- * pull (or push) each point in space towards a point in the center of the pipe which is closest to it.
- * Points located outside of the pipe are not affected (thus this acts kind of like a 'region')
- *
- * @param pipe   5-dimensional data describing the effect and kind of including the region in it as well.
- *               1st: the degree of pull (similar to the one in the sink effect)
- *               (2nd,3rd,4th) -> the vector along which the 'pipe' points to.
- *               5th: the radius of the pipe.
- * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
- */
-  public VertexEffectPipe(Data5D pipe, Data3D center)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    override fun compute(uniforms: FloatArray, index: Int, currentDuration: Long, step: Long): Boolean
     {
-    super(NAME);
-    mPipe   = pipe;
-    mCenter = center;
+        mCenter.get(uniforms, index+CENTER_OFFSET, currentDuration, step)
+        return mPipe.get(uniforms, index+VALUES_OFFSET, currentDuration, step)
     }
-  }
+}
diff --git a/src/main/java/org/distorted/library/effect/VertexEffectQuaternion.kt b/src/main/java/org/distorted/library/effect/VertexEffectQuaternion.kt
index 2bba590..1e4caab 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffectQuaternion.kt
+++ b/src/main/java/org/distorted/library/effect/VertexEffectQuaternion.kt
@@ -18,94 +18,60 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.effect;
+package org.distorted.library.effect
 
-import org.distorted.library.type.Data3D;
-import org.distorted.library.type.Data4D;
+import org.distorted.library.type.Data3D
+import org.distorted.library.type.Data4D
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-
 /**
  * Apply a given quaternion rotation to the Mesh.
  */
-public class VertexEffectQuaternion extends VertexEffect
-  {
-  private static final EffectName NAME = EffectName.VERTEX_QUATERNION;
-
-  private final Data4D mQuaternion;
-  private final Data3D mCenter;
+class VertexEffectQuaternion(quaternion: Data4D, center: Data3D) : VertexEffect(NAME)
+{
+    private val mQuaternion = quaternion
+    private val mCenter = center
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public boolean compute(float[] uniforms, int index, long currentDuration, long step )
+    companion object
     {
-    mCenter.get(uniforms,index+CENTER_OFFSET,currentDuration,step);
-    return mQuaternion.get(uniforms,index+VALUES_OFFSET,currentDuration,step);
+        private val NAME = EffectName.VERTEX_QUATERNION
+
+        ///////////////////////////////////////////////////////////////////////////////////////////////////
+        fun code(): String
+        {
+            return ("""
+                     float qx = vUniforms[effect].x;               
+                     float qy = vUniforms[effect].y;               
+                     float qz = vUniforms[effect].z;               
+                     float qw = vUniforms[effect].w;               
+                     vec3 center = vUniforms[effect+1].yzw;        
+                     v -= center;                                  
+                     float tx = qx - v.z*qy + v.y*qz + v.x*qw;     
+                     float ty = qy + v.z*qx + v.y*qw - v.x*qz;     
+                     float tz = qz + v.z*qw - v.y*qx + v.x*qy;     
+                     float tw = qw - v.z*qz - v.y*qy - v.x*qx;     
+                     v.x = qw*tx + qz*ty - qy*tz - qx*tw;          
+                     v.y = qw*ty - qz*tx - qy*tw + qx*tz;          
+                     v.z = qw*tz - qz*tw + qy*tx - qx*ty;          
+                     v += center;                                  
+                     float nx =  - n.z*qy + n.y*qz + n.x*qw;       
+                     float ny =  + n.z*qx + n.y*qw - n.x*qz;       
+                     float nz =  + n.z*qw - n.y*qx + n.x*qy;       
+                     float nw =  - n.z*qz - n.y*qy - n.x*qx;       
+                     n.x = qw*nx + qz*ny - qy*nz - qx*nw;          
+                     n.y = qw*ny - qz*nx - qy*nw + qx*nz;          
+                     n.z = qw*nz - qz*nw + qy*nx - qx*ny;          
+                     n = normalize(n);
+                     """.trimIndent())
+        }
+
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        @JvmStatic fun enable() = addEffect(NAME, code())
     }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  static String code()
-    {
-    return
-
-       "float qx = vUniforms[effect].x;               \n"
-     + "float qy = vUniforms[effect].y;               \n"
-     + "float qz = vUniforms[effect].z;               \n"
-     + "float qw = vUniforms[effect].w;               \n"
-     + "vec3 center = vUniforms[effect+1].yzw;        \n"
-
-     + "v -= center;                                  \n"
-
-     + "float tx = qx - v.z*qy + v.y*qz + v.x*qw;     \n"
-     + "float ty = qy + v.z*qx + v.y*qw - v.x*qz;     \n"
-     + "float tz = qz + v.z*qw - v.y*qx + v.x*qy;     \n"
-     + "float tw = qw - v.z*qz - v.y*qy - v.x*qx;     \n"
-
-     + "v.x = qw*tx + qz*ty - qy*tz - qx*tw;          \n"
-     + "v.y = qw*ty - qz*tx - qy*tw + qx*tz;          \n"
-     + "v.z = qw*tz - qz*tw + qy*tx - qx*ty;          \n"
-
-     + "v += center;                                  \n"
-
-     + "float nx =  - n.z*qy + n.y*qz + n.x*qw;       \n"
-     + "float ny =  + n.z*qx + n.y*qw - n.x*qz;       \n"
-     + "float nz =  + n.z*qw - n.y*qx + n.x*qy;       \n"
-     + "float nw =  - n.z*qz - n.y*qy - n.x*qx;       \n"
-
-     + "n.x = qw*nx + qz*ny - qy*nz - qx*nw;          \n"
-     + "n.y = qw*ny - qz*nx - qy*nw + qx*nz;          \n"
-     + "n.z = qw*nz - qz*nw + qy*nx - qx*ny;          \n"
-
-     + "n = normalize(n);";
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
- */
-  public static void enable()
-    {
-    addEffect( NAME, code() );
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Rotate the Mesh by a (possibly changing in time) quaternion.
- *
- * @param quaternion Quaternion describing the rotation.
- * @param center     Coordinates of the Point we are rotating around.
- */
-  public VertexEffectQuaternion(Data4D quaternion, Data3D center )
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    override fun compute(uniforms: FloatArray, index: Int, currentDuration: Long, step: Long): Boolean
     {
-    super(NAME);
-    mQuaternion = quaternion;
-    mCenter = center;
+        mCenter.get(uniforms, index+CENTER_OFFSET, currentDuration, step)
+        return mQuaternion.get(uniforms, index+VALUES_OFFSET, currentDuration, step)
     }
-  }
+}
diff --git a/src/main/java/org/distorted/library/effect/VertexEffectRotate.kt b/src/main/java/org/distorted/library/effect/VertexEffectRotate.kt
index da81c05..35829a1 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffectRotate.kt
+++ b/src/main/java/org/distorted/library/effect/VertexEffectRotate.kt
@@ -18,112 +18,78 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.effect;
+package org.distorted.library.effect
 
-import org.distorted.library.type.Data1D;
-import org.distorted.library.type.Data3D;
+import org.distorted.library.type.Data1D
+import org.distorted.library.type.Data3D
+import kotlin.math.sqrt
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-
 /**
  * Rotate the Mesh along a given axis by a given angle.
  */
-public class VertexEffectRotate extends VertexEffect
-  {
-  private static final EffectName NAME = EffectName.VERTEX_ROTATE;
-
-  private final Data1D mAngle;
-  private final Data3D mAxis, mCenter;
+class VertexEffectRotate(angle: Data1D, axis: Data3D, center: Data3D) : VertexEffect(NAME)
+{
+    private val mAngle  = angle
+    private val mAxis   = axis
+    private val mCenter = center
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public boolean compute(float[] uniforms, int index, long currentDuration, long step )
+    companion object
     {
-    mCenter.get(uniforms,index+CENTER_OFFSET,currentDuration,step);
-    mAxis.get(uniforms,index+VALUES_OFFSET+1,currentDuration,step);
-
-    float len = uniforms[index+1]*uniforms[index+1] + uniforms[index+2]*uniforms[index+2] + uniforms[index+3]*uniforms[index+3];
-    len = (float)Math.sqrt(len);
-
-    if( len!=0 )
-      {
-      uniforms[index+VALUES_OFFSET+1] /= len;
-      uniforms[index+VALUES_OFFSET+2] /= len;
-      uniforms[index+VALUES_OFFSET+3] /= len;
-      }
-
-    return mAngle.get(uniforms,index+VALUES_OFFSET,currentDuration,step);
+        private val NAME = EffectName.VERTEX_ROTATE
+
+        ///////////////////////////////////////////////////////////////////////////////////////////////////
+        fun code(): String
+        {
+            return ("""
+                     float angle = vUniforms[effect].x*3.14159265/360.0;
+                     vec3 center = vUniforms[effect+1].yzw;             
+                     float sinHalf =-sin(angle);                        
+                     float cosHalf = cos(angle);                        
+                     float qx = vUniforms[effect].y * sinHalf;          
+                     float qy = vUniforms[effect].z * sinHalf;          
+                     float qz = vUniforms[effect].w * sinHalf;          
+                     float qw = cosHalf;                                
+                     v -= center;                                       
+                     float tx = qx - v.z*qy + v.y*qz + v.x*qw;          
+                     float ty = qy + v.z*qx + v.y*qw - v.x*qz;          
+                     float tz = qz + v.z*qw - v.y*qx + v.x*qy;          
+                     float tw = qw - v.z*qz - v.y*qy - v.x*qx;          
+                     v.x = qw*tx + qz*ty - qy*tz - qx*tw;               
+                     v.y = qw*ty - qz*tx - qy*tw + qx*tz;               
+                     v.z = qw*tz - qz*tw + qy*tx - qx*ty;               
+                     v += center;                                       
+                     float nx =  - n.z*qy + n.y*qz + n.x*qw;            
+                     float ny =  + n.z*qx + n.y*qw - n.x*qz;            
+                     float nz =  + n.z*qw - n.y*qx + n.x*qy;            
+                     float nw =  - n.z*qz - n.y*qy - n.x*qx;            
+                     n.x = qw*nx + qz*ny - qy*nz - qx*nw;               
+                     n.y = qw*ny - qz*nx - qy*nw + qx*nz;               
+                     n.z = qw*nz - qz*nw + qy*nx - qx*ny;               
+                     n = normalize(n);
+                     """.trimIndent())
+        }
+
+        ///////////////////////////////////////////////////////////////////////////////////////////////////
+        @JvmStatic fun enable() = addEffect(NAME, code())
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  static String code()
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    override fun compute(uniforms: FloatArray, index: Int, currentDuration: Long, step: Long): Boolean
     {
-    return
-
-      "float angle = vUniforms[effect].x*3.14159265/360.0;\n"
-    + "vec3 center = vUniforms[effect+1].yzw;             \n"
-    + "float sinHalf =-sin(angle);                        \n"
-    + "float cosHalf = cos(angle);                        \n"
-
-    + "float qx = vUniforms[effect].y * sinHalf;          \n"
-    + "float qy = vUniforms[effect].z * sinHalf;          \n"
-    + "float qz = vUniforms[effect].w * sinHalf;          \n"
-    + "float qw = cosHalf;                                \n"
-
-    + "v -= center;                                       \n"
-
-    + "float tx = qx - v.z*qy + v.y*qz + v.x*qw;          \n"
-    + "float ty = qy + v.z*qx + v.y*qw - v.x*qz;          \n"
-    + "float tz = qz + v.z*qw - v.y*qx + v.x*qy;          \n"
-    + "float tw = qw - v.z*qz - v.y*qy - v.x*qx;          \n"
-
-    + "v.x = qw*tx + qz*ty - qy*tz - qx*tw;               \n"
-    + "v.y = qw*ty - qz*tx - qy*tw + qx*tz;               \n"
-    + "v.z = qw*tz - qz*tw + qy*tx - qx*ty;               \n"
+        mCenter.get(uniforms, index+CENTER_OFFSET, currentDuration, step)
+        mAxis.get(uniforms, index+VALUES_OFFSET+1, currentDuration, step)
 
-    + "v += center;                                       \n"
+        var len = uniforms[index+1]*uniforms[index+1]+uniforms[index+2]*uniforms[index+2]+uniforms[index+3]*uniforms[index+3]
+        len = sqrt(len.toDouble()).toFloat()
 
-    + "float nx =  - n.z*qy + n.y*qz + n.x*qw;            \n"
-    + "float ny =  + n.z*qx + n.y*qw - n.x*qz;            \n"
-    + "float nz =  + n.z*qw - n.y*qx + n.x*qy;            \n"
-    + "float nw =  - n.z*qz - n.y*qy - n.x*qx;            \n"
+        if (len!=0f)
+        {
+            uniforms[index+VALUES_OFFSET+1] /= len
+            uniforms[index+VALUES_OFFSET+2] /= len
+            uniforms[index+VALUES_OFFSET+3] /= len
+        }
 
-    + "n.x = qw*nx + qz*ny - qy*nz - qx*nw;               \n"
-    + "n.y = qw*ny - qz*nx - qy*nw + qx*nz;               \n"
-    + "n.z = qw*nz - qz*nw + qy*nx - qx*ny;               \n"
-
-    + "n = normalize(n);";
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
- */
-  public static void enable()
-    {
-    addEffect( NAME, code() );
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Rotate the Mesh by 'angle' degrees around the center, along an axis.
- *
- * @param angle  Angle that we want to rotate the Object to. Unit: degrees
- * @param axis   Axis of rotation
- * @param center Coordinates of the Point we are rotating around.
- */
-  public VertexEffectRotate(Data1D angle, Data3D axis, Data3D center)
-    {
-    super(NAME);
-    mAngle = angle;
-    mAxis = axis;
-    mCenter = center;
+        return mAngle.get(uniforms, index+VALUES_OFFSET, currentDuration, step)
     }
-  }
+}
diff --git a/src/main/java/org/distorted/library/effect/VertexEffectScale.kt b/src/main/java/org/distorted/library/effect/VertexEffectScale.kt
index 5d4f7f2..3d1b83c 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffectScale.kt
+++ b/src/main/java/org/distorted/library/effect/VertexEffectScale.kt
@@ -18,78 +18,58 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.effect;
+package org.distorted.library.effect
 
-import org.distorted.library.type.Data3D;
-import org.distorted.library.type.Static3D;
+import org.distorted.library.type.Data3D
+import org.distorted.library.type.Static3D
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Scale the Mesh by 3D scale factors.
  */
-public class VertexEffectScale extends VertexEffect
-  {
-  private static final EffectName NAME = EffectName.VERTEX_SCALE;
+class VertexEffectScale : VertexEffect
+{
+    private val mScale: Data3D
 
-  private final Data3D mScale;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public boolean compute(float[] uniforms, int index, long currentDuration, long step )
+    companion object
     {
-    return mScale.get(uniforms,index+VALUES_OFFSET,currentDuration,step);
-    }
+        private val NAME = EffectName.VERTEX_SCALE
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
+        ///////////////////////////////////////////////////////////////////////////////////////////////////
+        fun code(): String
+        {
+            return """
+                 v *= vUniforms[effect].xyz;                        
+                 float X = vUniforms[effect].y*vUniforms[effect].z; 
+                 float Y = vUniforms[effect].x*vUniforms[effect].z; 
+                 float Z = vUniforms[effect].x*vUniforms[effect].y; 
+                 n *= vec3(X,Y,Z);                                  
+                 n = normalize(n);                                      
+                 """.trimIndent()
+        }
 
-  static String code()
-    {
-    return
-
-    "v *= vUniforms[effect].xyz;                        \n" +
-    "float X = vUniforms[effect].y*vUniforms[effect].z; \n" +
-    "float Y = vUniforms[effect].x*vUniforms[effect].z; \n" +
-    "float Z = vUniforms[effect].x*vUniforms[effect].y; \n" +
-    "n *= vec3(X,Y,Z);                                  \n" +
-    "n = normalize(n);                                  \n";
+        ///////////////////////////////////////////////////////////////////////////////////////////////////
+        fun enable() = addEffect(NAME, code())
     }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
- */
-  public static void enable()
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    override fun compute(uniforms: FloatArray, index: Int, currentDuration: Long, step: Long): Boolean
     {
-    addEffect( NAME, code() );
+        return mScale.get(uniforms, index+VALUES_OFFSET, currentDuration, step)
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Scale the Mesh by 3D scale factors.
- *
- * @param scale current x- , y- and z- scale factors.
- */
-  public VertexEffectScale(Data3D scale)
-    {
-    super(NAME);
-    mScale = scale;
-    }
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Scale the Mesh by 3D scale factors.
+     *
+     * @param scale current x- , y- and z- scale factors.
+     */
+    constructor(scale: Data3D) : super(NAME) { mScale = scale }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Scale the Mesh by 3D scale factors.
- *
- * @param scale Common x,y, and z scale factor.
- */
-  public VertexEffectScale(float scale)
-    {
-    super(NAME);
-    mScale = new Static3D(scale,scale,scale);
-    }
-  }
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Scale the Mesh by 3D scale factors.
+     *
+     * @param scale Common x,y, and z scale factor.
+     */
+    constructor(scale: Float) : super(NAME) { mScale = Static3D(scale, scale, scale) }
+}
diff --git a/src/main/java/org/distorted/library/effect/VertexEffectShear.kt b/src/main/java/org/distorted/library/effect/VertexEffectShear.kt
index 9e361cd..7e0ebb3 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffectShear.kt
+++ b/src/main/java/org/distorted/library/effect/VertexEffectShear.kt
@@ -18,90 +18,57 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.effect;
+package org.distorted.library.effect
 
-import org.distorted.library.type.Data3D;
+import org.distorted.library.type.Data3D
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Shear the Mesh.
  */
-public class VertexEffectShear extends VertexEffect
-  {
-  private static final EffectName NAME = EffectName.VERTEX_SHEAR;
+class VertexEffectShear(shear: Data3D, center: Data3D) : VertexEffect(NAME)
+{
+    private val mShear = shear
+    private val mCenter = center
 
-  private final Data3D mShear, mCenter;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public boolean compute(float[] uniforms, int index, long currentDuration, long step )
+    companion object
     {
-    mCenter.get(uniforms,index+CENTER_OFFSET,currentDuration,step);
-    return mShear.get(uniforms,index+VALUES_OFFSET,currentDuration,step);
+        private val NAME = EffectName.VERTEX_SHEAR
+
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        // For explanation (esp. about the way we modify vectors n and i) see MatrixEffectShear.
+        fun code(): String
+        {
+            return ("""
+                     float sx = vUniforms[effect].x;                  
+                     float sy = vUniforms[effect].y;                  
+                     float sz = vUniforms[effect].z;                  
+                     vec3 center = vUniforms[effect+1].yzw;           
+                     float tmp   = sx*sy + 1.0;                       
+                     v -= center;                                     
+                     float new_vx = tmp*v.x + sx*v.y;                 
+                     float new_vy = sy*v.x + v.y;                     
+                     float new_vz = sz*v.y + v.z;                     
+                     v.x = new_vx;                                    
+                     v.y = new_vy;                                    
+                     v.z = new_vz;                                    
+                     v += center;                                     
+                     float new_nx = n.x - sy*n.y + sy*sz*n.z;         
+                     float new_ny =-sx*n.x + tmp*(n.y - sz*n.z);      
+                     n.x = new_nx;                                    
+                     n.y = new_ny;                                    
+                     n = normalize(n);
+                     """.trimIndent())
+        }
+
+        ///////////////////////////////////////////////////////////////////////////////////////////////////
+        fun enable() = addEffect(NAME, code())
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// For explanation (esp. about the way we modify vectors n and i) see MatrixEffectShear.
-
-  static String code()
-    {
-    return
-
-      "float sx = vUniforms[effect].x;                  \n"
-    + "float sy = vUniforms[effect].y;                  \n"
-    + "float sz = vUniforms[effect].z;                  \n"
-    + "vec3 center = vUniforms[effect+1].yzw;           \n"
-    + "float tmp   = sx*sy + 1.0;                       \n"
-
-    + "v -= center;                                     \n"
-
-    + "float new_vx = tmp*v.x + sx*v.y;                 \n"
-    + "float new_vy = sy*v.x + v.y;                     \n"
-    + "float new_vz = sz*v.y + v.z;                     \n"
-
-    + "v.x = new_vx;                                    \n"
-    + "v.y = new_vy;                                    \n"
-    + "v.z = new_vz;                                    \n"
-
-    + "v += center;                                     \n"
-
-    + "float new_nx = n.x - sy*n.y + sy*sz*n.z;         \n"
-    + "float new_ny =-sx*n.x + tmp*(n.y - sz*n.z);      \n"
-    + "n.x = new_nx;                                    \n"
-    + "n.y = new_ny;                                    \n"
-
-    + "n = normalize(n);";
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
- */
-  public static void enable()
-    {
-    addEffect( NAME, code() );
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Shear the Mesh.
- *
- * @param shear   The 3-tuple of shear factors. The first controls level
- *                of shearing in the X-axis, second - Y-axis and the third -
- *                Z-axis. Each is the tangent of the shear angle, i.e 0 -
- *                no shear, 1 - shear by 45 degrees (tan(45deg)=1) etc.
- * @param center  Center of shearing, i.e. the point which stays unmoved.
- */
-  public VertexEffectShear(Data3D shear, Data3D center)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    override fun compute(uniforms: FloatArray, index: Int, currentDuration: Long, step: Long): Boolean
     {
-    super(NAME);
-    mShear = shear;
-    mCenter = center;
+        mCenter.get(uniforms, index+CENTER_OFFSET, currentDuration, step)
+        return mShear.get(uniforms, index+VALUES_OFFSET, currentDuration, step)
     }
-  }
+}
diff --git a/src/main/java/org/distorted/library/effect/VertexEffectSink.kt b/src/main/java/org/distorted/library/effect/VertexEffectSink.kt
index 4cd5967..7d13574 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffectSink.kt
+++ b/src/main/java/org/distorted/library/effect/VertexEffectSink.kt
@@ -18,115 +18,101 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.effect;
+package org.distorted.library.effect
 
-import org.distorted.library.type.Data1D;
-import org.distorted.library.type.Data3D;
-import org.distorted.library.type.Data4D;
+import org.distorted.library.type.Data1D
+import org.distorted.library.type.Data3D
+import org.distorted.library.type.Data4D
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Pull all points around the center of the Effect towards the center point (if degree>=1) or push them
  * away from it (degree<=1).
  */
-public class VertexEffectSink extends VertexEffect
-  {
-  private static final EffectName NAME = EffectName.SINK;
+class VertexEffectSink : VertexEffect
+{
+    private val mSink: Data1D
+    private val mCenter: Data3D
+    private val mRegion: Data4D
 
-  private final Data1D mSink;
-  private final Data3D mCenter;
-  private final Data4D mRegion;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public boolean compute(float[] uniforms, int index, long currentDuration, long step )
-    {
-    mCenter.get(uniforms,index+CENTER_OFFSET,currentDuration,step);
-    mRegion.get(uniforms,index+REGION_OFFSET,currentDuration,step);
-    return mSink.get(uniforms,index+VALUES_OFFSET,currentDuration,step);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// used to be simple:
-// float t = deg * (1.0-h)/max(1.0,h);
-// Changed to the four complicated lines because the previous Sink effect fails to fully inflate the
-// Masterball.
-// Current function inflates and deflates much more as H is at the extremes (close to 0 and inf)
-
-  static String code()
+    companion object
     {
-    return
+        private val NAME = EffectName.SINK
 
-        "vec3 ps = vUniforms[effect+1].yzw - v;            \n"
-      + "float deg = degree(vUniforms[effect+2],ps);       \n"
+        ///////////////////////////////////////////////////////////////////////////////////////////////////
+        // used to be simple:
+        // float t = deg * (1.0-h)/max(1.0,h);
+        // Changed to the four complicated lines because the previous Sink effect fails to fully inflate the
+        // Masterball.
+        // Current function inflates and deflates much more as H is at the extremes (close to 0 and inf)
+        fun code(): String
+        {
+            return ("""
+                     vec3 ps = vUniforms[effect+1].yzw - v;            
+                     float deg = degree(vUniforms[effect+2],ps);       
+                     float h = vUniforms[effect].x;                    
+                     float tmp = (1.0-h)*deg;                          
+                     float t1 = tmp*(deg+1.0)/h;                       
+                     float t2 = tmp/(0.618*(0.618+deg));               
+                     float t = t2 + (t1-t2)*((sign(h-1.0)+1.0)/2.0);   
+                     v += t*ps;                                        
+                     const float A = 1.6;                              
+                     const float B = 10.0;                             
+                     vec3 n_ps = dot(ps,n)*ps;                         
+                     float dot_ps = dot(ps,ps);                        
+                     float sign_ps= sign(dot_ps);                      
+                     n_ps = (sign_ps*n_ps)/(dot_ps-(sign_ps-1.0));     
+                     float move = deg*(h-1.0)/(h/B+1.0/A);             
+                     n += move*n_ps;                                   
+                     n = normalize(n);
+                     """.trimIndent())
+        }
 
-      + "float h = vUniforms[effect].x;                    \n"
-      + "float tmp = (1.0-h)*deg;                          \n"
-      + "float t1 = tmp*(deg+1.0)/h;                       \n"
-      + "float t2 = tmp/(0.618*(0.618+deg));               \n"
-      + "float t = t2 + (t1-t2)*((sign(h-1.0)+1.0)/2.0);   \n"
-
-      + "v += t*ps;                                        \n"
-
-      + "const float A = 1.6;                              \n" // max amount of change in normal vector when pulling
-      + "const float B = 10.0;                             \n" // when pushing
-      + "vec3 n_ps = dot(ps,n)*ps;                         \n" // n_ps = (component of n that's parallel to ps) * |ps|^2 (=dot(ps,ps))
-      + "float dot_ps = dot(ps,ps);                        \n"
-      + "float sign_ps= sign(dot_ps);                      \n"
-      + "n_ps = (sign_ps*n_ps)/(dot_ps-(sign_ps-1.0));     \n" // uff! now n_ps is the parallel to ps component of n, even if ps==0
-      + "float move = deg*(h-1.0)/(h/B+1.0/A);             \n" // move(0)=-A*deg, move(1)=0, move(inf)=B*deg
-      + "n += move*n_ps;                                   \n"
-      + "n = normalize(n);";
+        ///////////////////////////////////////////////////////////////////////////////////////////////////
+        @JvmStatic fun enable() = addEffect(NAME, code())
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Pull P=(v.x,v.y) towards center of the effect with P' = P + (1-h)*dist(S-P)
-// when h>1 we are pushing points away from S: P' = P + (1/h-1)*dist(S-P)
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
- */
-  public static void enable()
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Only for use by the library itself.
+     *
+     * @y.exclude
+     */
+    override fun compute(uniforms: FloatArray, index: Int, currentDuration: Long, step: Long): Boolean
     {
-    addEffect(NAME, code() );
+        mCenter.get(uniforms, index+CENTER_OFFSET, currentDuration, step)
+        mRegion.get(uniforms, index+REGION_OFFSET, currentDuration, step)
+        return mSink.get(uniforms, index+VALUES_OFFSET, currentDuration, step)
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Pull all points around the center of the Effect towards the center point (if degree>=1) or push them
- * away from it (degree<=1)
- *
- * @param sink   The current degree of the Effect.
- * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
- * @param region Region that masks the Effect.
- */
-  public VertexEffectSink(Data1D sink, Data3D center, Data4D region)
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Pull all points around the center of the Effect towards the center point (if degree>=1) or push them
+     * away from it (degree<=1)
+     *
+     * @param sink   The current degree of the Effect.
+     * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
+     * @param region Region that masks the Effect.
+     */
+    constructor(sink: Data1D, center: Data3D, region: Data4D?) : super(NAME)
     {
-    super(NAME);
-    mSink   = sink;
-    mCenter = center;
-    mRegion = (region==null ? MAX_REGION : region);
+        mSink = sink
+        mCenter = center
+        mRegion = (region ?: MAX_REGION)
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Pull all points around the center of the Effect towards the center point(if degree>=1) or push them
- * away from it (degree<=1)
- *
- * @param sink   The current degree of the Effect.
- * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
- */
-  public VertexEffectSink(Data1D sink, Data3D center)
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Pull all points around the center of the Effect towards the center point(if degree>=1) or push them
+     * away from it (degree<=1)
+     *
+     * @param sink   The current degree of the Effect.
+     * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
+     */
+    constructor(sink: Data1D, center: Data3D) : super(NAME)
     {
-    super(NAME);
-    mSink   = sink;
-    mCenter = center;
-    mRegion = MAX_REGION;
+        mSink = sink
+        mCenter = center
+        mRegion = MAX_REGION
     }
-  }
+}
diff --git a/src/main/java/org/distorted/library/effect/VertexEffectSwirl.kt b/src/main/java/org/distorted/library/effect/VertexEffectSwirl.kt
index cab1093..cf6d384 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffectSwirl.kt
+++ b/src/main/java/org/distorted/library/effect/VertexEffectSwirl.kt
@@ -18,111 +18,97 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.effect;
+package org.distorted.library.effect
 
-import org.distorted.library.type.Data1D;
-import org.distorted.library.type.Data3D;
-import org.distorted.library.type.Data4D;
+import org.distorted.library.type.Data1D
+import org.distorted.library.type.Data3D
+import org.distorted.library.type.Data4D
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * 'Swirl' part of the Mesh, i.e rotate part of it around a point.
- * <p>
+ *
  * Note: this is not a fully 3D effect as the swirling happens entirely within the XY plane - z
  * coordinates of all vertices remain unaffected. If someone wants a fully 3D swirling, we'd
  * probably need to write another VertixEffectSwirl3D with two additional parameters: latitude and
  * longitude angles defining the plane swirling is working on.
  */
-public class VertexEffectSwirl extends VertexEffect
-  {
-  private static final EffectName NAME = EffectName.SWIRL;
-
-  private final Data1D mSwirl;
-  private final Data3D mCenter;
-  private final Data4D mRegion;
+class VertexEffectSwirl : VertexEffect
+{
+    private val mSwirl: Data1D
+    private val mCenter: Data3D
+    private val mRegion: Data4D
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public boolean compute(float[] uniforms, int index, long currentDuration, long step )
+    companion object
     {
-    mCenter.get(uniforms,index+CENTER_OFFSET,currentDuration,step);
-    mRegion.get(uniforms,index+REGION_OFFSET,currentDuration,step);
-    boolean ret = mSwirl.get(uniforms,index+VALUES_OFFSET,currentDuration,step);
+        private val NAME = EffectName.SWIRL
 
-    uniforms[index+VALUES_OFFSET] = (float)(Math.PI*uniforms[index]/180);
+        ///////////////////////////////////////////////////////////////////////////////////////////////////
+        // Let d be the degree of the current vertex V with respect to center of the effect S and Region vRegion.
+        // This effect rotates the current vertex V by vInterpolated.x radians clockwise around the circle dilated
+        // by (1-d) around the center of the effect S.
+        ///////////////////////////////////////////////////////////////////////////////////////////////////
+        fun code(): String
+        {
+            return ("""
+                     vec3 center = vUniforms[effect+1].yzw;                             
+                     vec3 PS = center-v.xyz;                                            
+                     vec4 SO = vUniforms[effect+2];                                     
+                     float deg1 = degree(SO,PS);                                        
+                     float alpha = vUniforms[effect].x;                                 
+                     float sinA = sin(alpha);                                           
+                     float cosA = cos(alpha);                                           
+                     vec3 PS2 = vec3( PS.x*cosA+PS.y*sinA,-PS.x*sinA+PS.y*cosA, PS.z ); 
+                     vec4 SG = (1.0-deg1)*SO;                                           
+                     float d2 = max(0.0,degree(SG,PS2));                                
+                     v.xy += deg1 * (PS.xy - PS2.xy/(1.0-d2));                          
+                     
+                     """.trimIndent()) // if d2=1 (i.e P=center) we should have P unchanged. How to do it?
+        }
 
-    return ret;
+        ///////////////////////////////////////////////////////////////////////////////////////////////////
+        fun enable() = addEffect(NAME, code())
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Let d be the degree of the current vertex V with respect to center of the effect S and Region vRegion.
-// This effect rotates the current vertex V by vInterpolated.x radians clockwise around the circle dilated
-// by (1-d) around the center of the effect S.
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  static String code()
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    override fun compute(uniforms: FloatArray, index: Int, currentDuration: Long, step: Long): Boolean
     {
-    return
+        mCenter.get(uniforms, index+CENTER_OFFSET, currentDuration, step)
+        mRegion.get(uniforms, index+REGION_OFFSET, currentDuration, step)
+        val ret = mSwirl.get(uniforms, index+VALUES_OFFSET, currentDuration, step)
 
-        "vec3 center = vUniforms[effect+1].yzw;                             \n"
-      + "vec3 PS = center-v.xyz;                                            \n"
-      + "vec4 SO = vUniforms[effect+2];                                     \n"
-      + "float deg1 = degree(SO,PS);                                        \n"
-      + "float alpha = vUniforms[effect].x;                                 \n"
-      + "float sinA = sin(alpha);                                           \n"
-      + "float cosA = cos(alpha);                                           \n"
+        uniforms[index+VALUES_OFFSET] = (Math.PI*uniforms[index]/180).toFloat()
 
-      + "vec3 PS2 = vec3( PS.x*cosA+PS.y*sinA,-PS.x*sinA+PS.y*cosA, PS.z ); \n" // vector PS rotated by A radians clockwise around center.
-      + "vec4 SG = (1.0-deg1)*SO;                                           \n" // coordinates of the dilated circle P is going to get rotated around
-      + "float d2 = max(0.0,degree(SG,PS2));                                \n" // make it a max(0,deg) because otherwise when center=left edge of the
-                                                                                // object some points end up with d2<0 and they disappear off view.
-      + "v.xy += deg1 * (PS.xy - PS2.xy/(1.0-d2));                          \n";// if d2=1 (i.e P=center) we should have P unchanged. How to do it?
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
- */
-  public static void enable()
-    {
-    addEffect( NAME, code() );
+        return ret
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Rotate part of the Mesh around the Center of the Effect by a certain angle.
- *
- * @param swirl  The angle of Swirl (in degrees). Positive values swirl clockwise.
- * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
- * @param region Region that masks the Effect.
- */
-  public VertexEffectSwirl(Data1D swirl, Data3D center, Data4D region)
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Rotate part of the Mesh around the Center of the Effect by a certain angle.
+     *
+     * @param swirl  The angle of Swirl (in degrees). Positive values swirl clockwise.
+     * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
+     * @param region Region that masks the Effect.
+     */
+    constructor(swirl: Data1D, center: Data3D, region: Data4D?) : super(NAME)
     {
-    super(NAME);
-    mSwirl  = swirl;
-    mCenter = center;
-    mRegion = (region==null ? MAX_REGION : region);
+        mSwirl  = swirl
+        mCenter = center
+        mRegion = (region ?: MAX_REGION)
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Rotate the whole Mesh around the Center of the Effect by a certain angle.
- *
- * @param swirl  The angle of Swirl (in degrees). Positive values swirl clockwise.
- * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
- */
-  public VertexEffectSwirl(Data1D swirl, Data3D center)
+    ///////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Rotate the whole Mesh around the Center of the Effect by a certain angle.
+     *
+     * @param swirl  The angle of Swirl (in degrees). Positive values swirl clockwise.
+     * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
+     */
+    constructor(swirl: Data1D, center: Data3D) : super(NAME)
     {
-    super(NAME);
-    mSwirl  = swirl;
-    mCenter = center;
-    mRegion = MAX_REGION;
+        mSwirl  = swirl
+        mCenter = center
+        mRegion = MAX_REGION
     }
-  }
+}
 
diff --git a/src/main/java/org/distorted/library/effect/VertexEffectWave.kt b/src/main/java/org/distorted/library/effect/VertexEffectWave.kt
index 3b4ef7f..065e54e 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffectWave.kt
+++ b/src/main/java/org/distorted/library/effect/VertexEffectWave.kt
@@ -18,235 +18,207 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.effect;
+package org.distorted.library.effect
 
-import org.distorted.library.type.Data3D;
-import org.distorted.library.type.Data4D;
-import org.distorted.library.type.Data5D;
+import org.distorted.library.type.Data3D
+import org.distorted.library.type.Data4D
+import org.distorted.library.type.Data5D
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Directional, sinusoidal wave effect.
- * <p>
+ *
  * Not a fully 3D effect. To achieve a fully 3D one we'd need another parameter making the whole thing
  * a 6D effect but there's no room in the Vertex Uniforms which assign only 5 floats for interpolated
  * effect values. Rethink this. ATM fully enough for 2.5D meshes like the MeshCubes.
  */
-public class VertexEffectWave extends VertexEffect
-  {
-  private static final EffectName NAME = EffectName.WAVE;
-
-  private final Data5D mWave;
-  private final Data3D mCenter;
-  private final Data4D mRegion;
+class VertexEffectWave : VertexEffect
+{
+    private val mWave: Data5D
+    private val mCenter: Data3D
+    private val mRegion: Data4D
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public boolean compute(float[] uniforms, int index, long currentDuration, long step )
+    companion object
     {
-    mCenter.get(uniforms,index+CENTER_OFFSET,currentDuration,step);
-    mRegion.get(uniforms,index+REGION_OFFSET,currentDuration,step);
-    boolean ret = mWave.get(uniforms,index+VALUES_OFFSET,currentDuration,step);
-
-    uniforms[index+VALUES_OFFSET+2] = (float)(Math.PI*uniforms[index+VALUES_OFFSET+2]/180);
-    uniforms[index+VALUES_OFFSET+3] = (float)(Math.PI*uniforms[index+VALUES_OFFSET+3]/180);
-    uniforms[index+VALUES_OFFSET+4] = (float)(Math.PI*uniforms[index+VALUES_OFFSET+4]/180);
-
-    return ret;
+        private val NAME = EffectName.WAVE
+
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        // Directional sinusoidal wave effect.
+        //
+        // This is an effect from a (hopefully!) generic family of effects of the form (vec3 V: |V|=1 , f(x,y) )  (*)
+        // i.e. effects defined by a unit vector and an arbitrary function. Those effects are defined to move each
+        // point (x,y,0) of the XY plane to the point (x,y,0) + V*f(x,y).
+        //
+        // In this case V is defined by angles A and B (sines and cosines of which are precomputed in
+        // EffectQueueVertex and passed in the uniforms).
+        // Let's move V to start at the origin O, let point C be the endpoint of V, and let C' be C's projection
+        // to the XY plane. Then A is defined to be the angle C0C' and angle B is the angle C'O(axisY).
+        //
+        // Also, in this case f(x,y) = amplitude*sin(x/length), with those 2 parameters passed in uniforms.
+        //
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        // How to compute any generic effect of type (*)
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        //
+        // By definition, the vertices move by f(x,y)*V.
+        //
+        // Normals are much more complicated.
+        // Let angle X be the angle (0,Vy,Vz)(0,Vy,0)(Vx,Vy,Vz).
+        // Let angle Y be the angle (Vx,0,Vz)(Vx,0,0)(Vx,Vy,Vz).
+        //
+        // Then it can be shown that the resulting surface, at point to which point (x0,y0,0) got moved to,
+        // has 2 tangent vectors given by
+        //
+        // SX = (1.0+cosX*fx , cosY*sinX*fx , |sinY|*sinX*fx);  (**)
+        // SY = (cosX*sinY*fy , 1.0+cosY*fy , |sinX|*sinY*fy);  (***)
+        //
+        // and then obviously the normal N is given by N= SX x SY .
+        //
+        // We still need to remember the note from the distort function dialog_about adding up normals:
+        // we first need to 'normalize' the normals to make their third components equal, and then we
+        // simply add up the first and the second component while leaving the third unchanged.
+        //
+        // How to see facts (**) and (***) ? Briefly:
+        // a) compute the 2D analogon and conclude that in this case the tangent SX is given by
+        //    SX = ( cosA*f'(x) +1, sinA*f'(x) )    (where A is the angle vector V makes with X axis )
+        // b) cut the resulting surface with plane P which
+        //    - includes vector V
+        //    - crosses plane XY along line parallel to X axis
+        // c) apply the 2D analogon and notice that the tangent vector to the curve that is the common part of P
+        //    and our surface (I am talking dialog_about the tangent vector which belongs to P) is given by
+        //    (1+cosX*fx,0,sinX*fx) rotated by angle (90-|Y|) (where angles X,Y are defined above) along vector (1,0,0).
+        //
+        //    Matrix of rotation:
+        //
+        //    |sinY|  cosY
+        //    -cosY  |sinY|
+        //
+        // d) compute the above and see that this is equal precisely to SX from (**).
+        // e) repeat points b,c,d in direction Y and come up with (***).
+        //
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        // Note: we should avoid passing certain combinations of parameters to this function. One such known
+        // combination is ( A: small but positive, B: any, amplitude >= length ).
+        // In this case, certain 'unlucky' points have their normals almost horizontal (they got moved by (almost!)
+        // amplitude, and other point length (i.e. <=amplitude) away got moved by 0, so the slope in this point is
+        // very steep). Visual effect is: vast majority of surface pretty much unchanged, but random 'unlucky'
+        // points very dark)
+        //
+        // Generally speaking I'd keep to amplitude < length, as the opposite case has some other problems as well.
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        fun code(): String
+        {
+            return ("""
+                     vec3 center     = vUniforms[effect+1].yzw;                   
+                     float amplitude = vUniforms[effect  ].x;                     
+                     float length    = vUniforms[effect  ].y;                     
+                     vec3 ps = center - v;                                        
+                     float deg = amplitude*degree(vUniforms[effect+2],ps);        
+                     if( deg != 0.0 && length != 0.0 )                            
+                     {                                                          
+                     float phase = vUniforms[effect  ].z;                       
+                     float alpha = vUniforms[effect  ].w;                       
+                     float beta  = vUniforms[effect+1].x;                       
+                     float sinA = sin(alpha);                                   
+                     float cosA = cos(alpha);                                   
+                     float sinB = sin(beta);                                    
+                     float cosB = cos(beta);                                    
+                     float angle= 1.578*(ps.x*cosB-ps.y*sinB) / length + phase; 
+                     vec3 dir= vec3(sinB*cosA,cosB*cosA,sinA);                  
+                     v += sin(angle)*deg*dir;                                   
+                     if( n.z != 0.0 )                                           
+                     {                                                        
+                     float sqrtX = sqrt(dir.y*dir.y + dir.z*dir.z);           
+                     float sqrtY = sqrt(dir.x*dir.x + dir.z*dir.z);           
+                     float sinX = ( sqrtY==0.0 ? 0.0 : dir.z / sqrtY);        
+                     float cosX = ( sqrtY==0.0 ? 1.0 : dir.x / sqrtY);        
+                     float sinY = ( sqrtX==0.0 ? 0.0 : dir.z / sqrtX);        
+                     float cosY = ( sqrtX==0.0 ? 1.0 : dir.y / sqrtX);        
+                     float abs_z = dir.z <0.0 ? -(sinX*sinY) : (sinX*sinY);   
+                     float tmp = 1.578*cos(angle)*deg/length;                 
+                     float fx =-cosB*tmp;                                     
+                     float fy = sinB*tmp;                                     
+                     vec3 sx = vec3 (1.0+cosX*fx,cosY*sinX*fx,abs_z*fx);      
+                     vec3 sy = vec3 (cosX*sinY*fy,1.0+cosY*fy,abs_z*fy);      
+                     vec3 normal = cross(sx,sy);                              
+                     if( normal.z<=0.0 )                                      
+                     {                                                      
+                     normal.x= 0.0;                                         
+                     normal.y= 0.0;                                         
+                     normal.z= 1.0;                                         
+                     }                                                      
+                     n.x = (n.x*normal.z + n.z*normal.x);                     
+                     n.y = (n.y*normal.z + n.z*normal.y);                     
+                     n.z = (n.z*normal.z);                                    
+                     n = normalize(n);                                        
+                     }                                                        
+                     }
+                     """.trimIndent())
+        }
+
+        ///////////////////////////////////////////////////////////////////////////////////////////
+        @JvmStatic fun enable() = addEffect(NAME, code())
     }
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-// Directional sinusoidal wave effect.
-//
-// This is an effect from a (hopefully!) generic family of effects of the form (vec3 V: |V|=1 , f(x,y) )  (*)
-// i.e. effects defined by a unit vector and an arbitrary function. Those effects are defined to move each
-// point (x,y,0) of the XY plane to the point (x,y,0) + V*f(x,y).
-//
-// In this case V is defined by angles A and B (sines and cosines of which are precomputed in
-// EffectQueueVertex and passed in the uniforms).
-// Let's move V to start at the origin O, let point C be the endpoint of V, and let C' be C's projection
-// to the XY plane. Then A is defined to be the angle C0C' and angle B is the angle C'O(axisY).
-//
-// Also, in this case f(x,y) = amplitude*sin(x/length), with those 2 parameters passed in uniforms.
-//
-//////////////////////////////////////////////////////////////////////////////////////////////
-// How to compute any generic effect of type (*)
-//////////////////////////////////////////////////////////////////////////////////////////////
-//
-// By definition, the vertices move by f(x,y)*V.
-//
-// Normals are much more complicated.
-// Let angle X be the angle (0,Vy,Vz)(0,Vy,0)(Vx,Vy,Vz).
-// Let angle Y be the angle (Vx,0,Vz)(Vx,0,0)(Vx,Vy,Vz).
-//
-// Then it can be shown that the resulting surface, at point to which point (x0,y0,0) got moved to,
-// has 2 tangent vectors given by
-//
-// SX = (1.0+cosX*fx , cosY*sinX*fx , |sinY|*sinX*fx);  (**)
-// SY = (cosX*sinY*fy , 1.0+cosY*fy , |sinX|*sinY*fy);  (***)
-//
-// and then obviously the normal N is given by N= SX x SY .
-//
-// We still need to remember the note from the distort function dialog_about adding up normals:
-// we first need to 'normalize' the normals to make their third components equal, and then we
-// simply add up the first and the second component while leaving the third unchanged.
-//
-// How to see facts (**) and (***) ? Briefly:
-// a) compute the 2D analogon and conclude that in this case the tangent SX is given by
-//    SX = ( cosA*f'(x) +1, sinA*f'(x) )    (where A is the angle vector V makes with X axis )
-// b) cut the resulting surface with plane P which
-//    - includes vector V
-//    - crosses plane XY along line parallel to X axis
-// c) apply the 2D analogon and notice that the tangent vector to the curve that is the common part of P
-//    and our surface (I am talking dialog_about the tangent vector which belongs to P) is given by
-//    (1+cosX*fx,0,sinX*fx) rotated by angle (90-|Y|) (where angles X,Y are defined above) along vector (1,0,0).
-//
-//    Matrix of rotation:
-//
-//    |sinY|  cosY
-//    -cosY  |sinY|
-//
-// d) compute the above and see that this is equal precisely to SX from (**).
-// e) repeat points b,c,d in direction Y and come up with (***).
-//
-//////////////////////////////////////////////////////////////////////////////////////////////
-// Note: we should avoid passing certain combinations of parameters to this function. One such known
-// combination is ( A: small but positive, B: any, amplitude >= length ).
-// In this case, certain 'unlucky' points have their normals almost horizontal (they got moved by (almost!)
-// amplitude, and other point length (i.e. <=amplitude) away got moved by 0, so the slope in this point is
-// very steep). Visual effect is: vast majority of surface pretty much unchanged, but random 'unlucky'
-// points very dark)
-//
-// Generally speaking I'd keep to amplitude < length, as the opposite case has some other problems as well.
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  static String code()
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    override fun compute(uniforms: FloatArray, index: Int, currentDuration: Long, step: Long): Boolean
     {
-    return
-
-        "vec3 center     = vUniforms[effect+1].yzw;                   \n"
-      + "float amplitude = vUniforms[effect  ].x;                     \n"
-      + "float length    = vUniforms[effect  ].y;                     \n"
-
-      + "vec3 ps = center - v;                                        \n"
-      + "float deg = amplitude*degree(vUniforms[effect+2],ps);        \n"
-
-      + "if( deg != 0.0 && length != 0.0 )                            \n"
-      +   "{                                                          \n"
-      +   "float phase = vUniforms[effect  ].z;                       \n"
-      +   "float alpha = vUniforms[effect  ].w;                       \n"
-      +   "float beta  = vUniforms[effect+1].x;                       \n"
-
-      +   "float sinA = sin(alpha);                                   \n"
-      +   "float cosA = cos(alpha);                                   \n"
-      +   "float sinB = sin(beta);                                    \n"
-      +   "float cosB = cos(beta);                                    \n"
-
-      +   "float angle= 1.578*(ps.x*cosB-ps.y*sinB) / length + phase; \n"
-      +   "vec3 dir= vec3(sinB*cosA,cosB*cosA,sinA);                  \n"
-      +   "v += sin(angle)*deg*dir;                                   \n"
-
-      +   "if( n.z != 0.0 )                                           \n"
-      +     "{                                                        \n"
-      +     "float sqrtX = sqrt(dir.y*dir.y + dir.z*dir.z);           \n"
-      +     "float sqrtY = sqrt(dir.x*dir.x + dir.z*dir.z);           \n"
-
-      +     "float sinX = ( sqrtY==0.0 ? 0.0 : dir.z / sqrtY);        \n"
-      +     "float cosX = ( sqrtY==0.0 ? 1.0 : dir.x / sqrtY);        \n"
-      +     "float sinY = ( sqrtX==0.0 ? 0.0 : dir.z / sqrtX);        \n"
-      +     "float cosY = ( sqrtX==0.0 ? 1.0 : dir.y / sqrtX);        \n"
-
-      +     "float abs_z = dir.z <0.0 ? -(sinX*sinY) : (sinX*sinY);   \n"
-      +     "float tmp = 1.578*cos(angle)*deg/length;                 \n"
+        mCenter.get(uniforms, index+CENTER_OFFSET, currentDuration, step)
+        mRegion.get(uniforms, index+REGION_OFFSET, currentDuration, step)
+        val ret = mWave.get(uniforms, index+VALUES_OFFSET, currentDuration, step)
 
-      +     "float fx =-cosB*tmp;                                     \n"
-      +     "float fy = sinB*tmp;                                     \n"
+        uniforms[index+VALUES_OFFSET+2] = (Math.PI*uniforms[index+VALUES_OFFSET+2]/180).toFloat()
+        uniforms[index+VALUES_OFFSET+3] = (Math.PI*uniforms[index+VALUES_OFFSET+3]/180).toFloat()
+        uniforms[index+VALUES_OFFSET+4] = (Math.PI*uniforms[index+VALUES_OFFSET+4]/180).toFloat()
 
-      +     "vec3 sx = vec3 (1.0+cosX*fx,cosY*sinX*fx,abs_z*fx);      \n"
-      +     "vec3 sy = vec3 (cosX*sinY*fy,1.0+cosY*fy,abs_z*fy);      \n"
-
-      +     "vec3 normal = cross(sx,sy);                              \n"
-
-      +     "if( normal.z<=0.0 )                                      \n"   // Why this bizarre thing rather than the straightforward
-      +       "{                                                      \n"   //
-      +       "normal.x= 0.0;                                         \n"   // if( normal.z>0.0 )
-      +       "normal.y= 0.0;                                         \n"   //   {
-      +       "normal.z= 1.0;                                         \n"   //   n.x = (n.x*normal.z + n.z*normal.x);
-      +       "}                                                      \n"   //   n.y = (n.y*normal.z + n.z*normal.y);
-                                                                            //   n.z = (n.z*normal.z);
-                                                                            //   }
-      +     "n.x = (n.x*normal.z + n.z*normal.x);                     \n"   //
-      +     "n.y = (n.y*normal.z + n.z*normal.y);                     \n"   // ? Because if we do the above, my Nexus4 crashes
-      +     "n.z = (n.z*normal.z);                                    \n"   // during shader compilation!
-      +     "n = normalize(n);                                        \n"
-      +     "}                                                        \n"
-      +   "}";
+        return ret
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
- */
-  public static void enable()
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Directional, sinusoidal wave effect.
+     *
+     * @param wave   A 5-dimensional data structure describing the wave: first member is the amplitude,
+     * second is the wave length, third is the phase (i.e. when phase = PI/2, the sine
+     * wave at the center does not start from sin(0), but from sin(PI/2) ) and the next two
+     * describe the 'direction' of the wave.
+     *
+     * Wave direction is defined to be a 3D vector of length 1. To define such vectors, we
+     * need 2 floats: thus the fourth member is the angle Alpha (in degrees) which the vector
+     * forms with the XY-plane, and the fifth is the angle Beta (again in degrees) which
+     * the projection of the vector to the XY-plane forms with the Y-axis (counterclockwise).
+     *
+     * Example1: if Alpha = 90, Beta = 90, (then V=(0,0,1) ) and the wave acts 'vertically'
+     * in the X-direction, i.e. cross-sections of the resulting surface with the XZ-plane
+     * will be sine shapes.
+     *
+     * Example2: if Alpha = 90, Beta = 0, the again V=(0,0,1) and the wave is 'vertical',
+     * but this time it waves in the Y-direction, i.e. cross sections of the surface and the
+     * YZ-plane with be sine shapes.
+     *
+     * Example3: if Alpha = 0 and Beta = 45, then V=(sqrt(2)/2, sqrt(2)/2, 0) and the wave
+     * is entirely 'horizontal' and moves point (x,y,0) in direction V by whatever is the
+     * value if sin at this point.
+     * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
+     * @param region Region that masks the Effect.
+     */
+    constructor(wave: Data5D, center: Data3D, region: Data4D?) : super(NAME)
     {
-    addEffect( NAME, code() );
+        mWave   = wave
+        mCenter = center
+        mRegion = (region ?: MAX_REGION)
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Directional, sinusoidal wave effect.
- *
- * @param wave   A 5-dimensional data structure describing the wave: first member is the amplitude,
- *               second is the wave length, third is the phase (i.e. when phase = PI/2, the sine
- *               wave at the center does not start from sin(0), but from sin(PI/2) ) and the next two
- *               describe the 'direction' of the wave.
- *               <p>
- *               Wave direction is defined to be a 3D vector of length 1. To define such vectors, we
- *               need 2 floats: thus the fourth member is the angle Alpha (in degrees) which the vector
- *               forms with the XY-plane, and the fifth is the angle Beta (again in degrees) which
- *               the projection of the vector to the XY-plane forms with the Y-axis (counterclockwise).
- *               <p>
- *               <p>
- *               Example1: if Alpha = 90, Beta = 90, (then V=(0,0,1) ) and the wave acts 'vertically'
- *               in the X-direction, i.e. cross-sections of the resulting surface with the XZ-plane
- *               will be sine shapes.
- *               <p>
- *               Example2: if Alpha = 90, Beta = 0, the again V=(0,0,1) and the wave is 'vertical',
- *               but this time it waves in the Y-direction, i.e. cross sections of the surface and the
- *               YZ-plane with be sine shapes.
- *               <p>
- *               Example3: if Alpha = 0 and Beta = 45, then V=(sqrt(2)/2, sqrt(2)/2, 0) and the wave
- *               is entirely 'horizontal' and moves point (x,y,0) in direction V by whatever is the
- *               value if sin at this point.
- * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
- * @param region Region that masks the Effect.
- */
-  public VertexEffectWave(Data5D wave, Data3D center, Data4D region)
-    {
-    super(NAME);
-    mWave   = wave;
-    mCenter = center;
-    mRegion = (region==null ? MAX_REGION : region);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Directional, sinusoidal wave effect.
- *
- * @param wave   see {@link #VertexEffectWave(Data5D,Data3D,Data4D)}
- * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
- */
-  public VertexEffectWave(Data5D wave, Data3D center)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Directional, sinusoidal wave effect.
+     *
+     * @param wave   see [.VertexEffectWave]
+     * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
+     */
+    constructor(wave: Data5D, center: Data3D) : super(NAME)
     {
-    super(NAME);
-    mWave   = wave;
-    mCenter = center;
-    mRegion = MAX_REGION;
+        mWave   = wave
+        mCenter = center
+        mRegion = MAX_REGION
     }
-  }
+}
diff --git a/src/main/java/org/distorted/library/effectqueue/EffectQueue.kt b/src/main/java/org/distorted/library/effectqueue/EffectQueue.kt
index 35cfa79..c2e2e33 100644
--- a/src/main/java/org/distorted/library/effectqueue/EffectQueue.kt
+++ b/src/main/java/org/distorted/library/effectqueue/EffectQueue.kt
@@ -204,7 +204,7 @@ abstract class EffectQueue : Slave
         {
             val map = InternalStackFrameList.getMap()
             val list = ArrayList<Long>()
-            for (i in 0..<numEffects) list.add(mEffects[i]!!.id)
+            for (i in 0..<numEffects) list.add(mEffects[i]!!.iD)
             val id = map[list]
 
             if (id != null)
@@ -273,7 +273,7 @@ abstract class EffectQueue : Slave
     {
         for (i in 0..<numEffects)
         {
-            if (mEffects[i]!!.id == id)
+            if (mEffects[i]!!.iD == id)
             {
                 mJobs.add( Job(DETACH,0,0,true,mEffects[i]) )
                 InternalMaster.newSlave(this)
@@ -351,7 +351,7 @@ abstract class EffectQueue : Slave
     fun exists(id: Long): Boolean
     {
         for (i in 0..<numEffects)
-            if (mEffects[i]!!.id==id) return true
+            if (mEffects[i]!!.iD==id) return true
 
         return false
     }
@@ -374,7 +374,7 @@ abstract class EffectQueue : Slave
     fun setAssociation(effectID: Long)
     {
         for (i in 0..<numEffects)
-            if (mEffects[i]!!.id == effectID)
+            if (mEffects[i]!!.iD == effectID)
                 mUBI!!.addAssociations(i, mEffects[i]!!)
     }
 
diff --git a/src/main/java/org/distorted/library/main/DistortedEffects.java b/src/main/java/org/distorted/library/main/DistortedEffects.java
index e30ae49..ed8f782 100644
--- a/src/main/java/org/distorted/library/main/DistortedEffects.java
+++ b/src/main/java/org/distorted/library/main/DistortedEffects.java
@@ -159,7 +159,7 @@ public class DistortedEffects
  */
   public int abortByName(EffectName name)
     {
-    int num = name.getType().ordinal();
+    int num = name.type.ordinal();
     return mQueues[num].removeByName(name);
     }
 
