commit 20af7b690409a873e3c505072254ef63e45808f9
Author: Leszek Koltunski <leszek@distorted.org>
Date:   Wed Aug 24 22:31:00 2016 +0100

    Correct an important bug in the vertex shader.
    
    b = 1/a if a!=0, 1 otherwise was incorrectly computed as b = 1.0 / (a+1.0-sign(a)). This, when 0<a<2^-24, suffers from 'round-off error': then a+1.0 = 1.0 (sic!) thus b = 1/0 !.
    
    Correct way: b = 1.0 / ( a - (sign(a)-1.0) )

diff --git a/build.gradle b/build.gradle
index feef24f..f0a2322 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,7 +1,7 @@
 apply plugin: 'com.android.library'
 
 android {
-    compileSdkVersion 22
+    compileSdkVersion 23
     buildToolsVersion "23.0.3"
 
     defaultConfig {
diff --git a/src/main/res/raw/main_vertex_shader.glsl b/src/main/res/raw/main_vertex_shader.glsl
index 1b2e16a..f8d610e 100644
--- a/src/main/res/raw/main_vertex_shader.glsl
+++ b/src/main/res/raw/main_vertex_shader.glsl
@@ -70,7 +70,7 @@ float degree_bitmap(in vec2 S, in vec2 PS)
 
   vec2 signA = sign(A);                           //
   vec2 signA_SQ = signA*signA;                    // div = PS/A if A!=0, 0 otherwise.
-  vec2 div = signA_SQ*PS/(A+signA_SQ-vec2(1,1));  //
+  vec2 div = signA_SQ*PS/(A-(vec2(1,1)-signA_SQ));//
 
   return 1.0-max(div.x,div.y);
   }
@@ -101,7 +101,15 @@ float degree_region(in vec3 region, in vec2 PS)
   if( D<=0.0 ) return 0.0;
 
   float ps_sq = dot(PS,PS);
-  float one_over_ps_sq = 1.0/(ps_sq+1.0-sign(ps_sq));  // return 1.0 if ps_sq = 0.0
+  float one_over_ps_sq = 1.0/(ps_sq-(sign(ps_sq)-1.0));  // return 1.0 if ps_sq = 0.0
+                                                         // Important: if we want to write
+                                                         // b = 1/a if a!=0, b=1 otherwise
+                                                         // we need to write that as
+                                                         // b = 1 / ( a-(sign(a)-1) )
+                                                         // [ and NOT 1 / ( a + 1 - sign(a) ) ]
+                                                         // because the latter, if 0<a<2^-24,
+                                                         // will suffer from round-off error and in this case
+                                                         // a + 1.0 = 1.0 !! so 1 / (a+1-sign(a)) = 1/0 !
   float DOT  = dot(PS,PO)*one_over_ps_sq;
 
   return 1.0 / (1.0 + 1.0/(sqrt(DOT*DOT+D*one_over_ps_sq)-DOT));
@@ -120,11 +128,11 @@ float degree(in vec3 region, in vec2 S, in vec2 PS)
   vec2 A = sign(PS)*u_objD.xy + S;
   vec2 signA = sign(A);
   vec2 signA_SQ = signA*signA;
-  vec2 div = signA_SQ*PS/(A+signA_SQ-vec2(1,1));
+  vec2 div = signA_SQ*PS/(A-(vec2(1,1)-signA_SQ));
   float E = 1.0-max(div.x,div.y);
 
   float ps_sq = dot(PS,PS);
-  float one_over_ps_sq = 1.0/(ps_sq+1.0-sign(ps_sq));  // return 1.0 if ps_sq = 0.0
+  float one_over_ps_sq = 1.0/(ps_sq-(sign(ps_sq)-1.0));  // return 1.0 if ps_sq = 0.0
   float DOT  = dot(PS,PO)*one_over_ps_sq;
 
   return min(1.0/(1.0 + 1.0/(sqrt(DOT*DOT+D*one_over_ps_sq)-DOT)),E);
@@ -281,7 +289,7 @@ void distort(in int effect, inout vec4 v, inout vec4 n)
   vec2 w = vec2(vUniforms[effect].x, -vUniforms[effect].y);
   float uz = vUniforms[effect].z;                                         // height of the bubble
   float denominator = dot(ps+(1.0-d)*w,ps);
-  float one_over_denom = 1.0/(denominator+0.001*(1.0-sign(denominator))); // = denominator==0 ? 1000:1/denominator;
+  float one_over_denom = 1.0/(denominator-0.001*(sign(denominator)-1.0)); // = denominator==0 ? 1000:1/denominator;
 
   //v.z += uz*d;                                                          // cone
   //b = -(uz*(1.0-d))*one_over_denom;                                     //
@@ -326,12 +334,12 @@ void swirl(in int effect, inout vec4 v)
   vec3 SO = vUniforms[effect+1];
   float d1_circle = degree_region(SO,PS);
   float d1_bitmap = degree_bitmap(S,PS);
-  float sinA = vUniforms[effect].y;                            // sin(A) precomputed in EffectListVertex.postprocess                                         
-  float cosA = vUniforms[effect].z;                            // cos(A) precomputed in EffectListVertex.postprocess  
-  vec2 PS2 = vec2( PS.x*cosA+PS.y*sinA,-PS.x*sinA+PS.y*cosA ); // vector PS rotated by A radians clockwise around S.                               
+  float sinA = vUniforms[effect].y;                            // sin(A) precomputed in EffectListVertex.postprocess
+  float cosA = vUniforms[effect].z;                            // cos(A) precomputed in EffectListVertex.postprocess
+  vec2 PS2 = vec2( PS.x*cosA+PS.y*sinA,-PS.x*sinA+PS.y*cosA ); // vector PS rotated by A radians clockwise around S.
   vec3 SG = (1.0-d1_circle)*SO;                                // coordinates of the dilated circle P is going to get rotated around
-  float d2 = max(0.0,degree(SG,S,PS2));                        // make it a max(0,deg) because when S=left edge of the bitmap, otherwise
-                                                               // some points end up with d2<0 and they disappear off view.
+  float d2 = max(0.0,degree(SG,S,PS2));                        // make it a max(0,deg) because otherwise when S=left edge of the
+                                                               // bitmap some points end up with d2<0 and they disappear off view.
   v.xy += min(d1_circle,d1_bitmap)*(PS - PS2/(1.0-d2));        // if d2=1 (i.e P=S) we should have P unchanged. How to do it?
   }
 
