commit 9420f2fe3e84eebe556cc46ae536b3732fd2d124
Author: Leszek Koltunski <leszek@distorted.org>
Date:   Sun Jul 17 00:14:08 2016 +0100

    Fix for Bug 19: SWIRL effect: mess if Center out of Region.

diff --git a/src/main/res/raw/main_vertex_shader.glsl b/src/main/res/raw/main_vertex_shader.glsl
index 5f98bb2..4e32e11 100644
--- a/src/main/res/raw/main_vertex_shader.glsl
+++ b/src/main/res/raw/main_vertex_shader.glsl
@@ -50,21 +50,7 @@ uniform vec3 vUniforms[3*NUM_VERTEX];     // i-th effect is 3 consecutive vec3's
 //////////////////////////////////////////////////////////////////////////////////////////////
 // HELPER FUNCTIONS
 //////////////////////////////////////////////////////////////////////////////////////////////
-// Let (v.x,v.y) be point P (the current vertex).
-// Let vPoint[effect].xy be point S (the center of effect)
-// Let vPoint[effect].xy + vRegion[effect].xy be point O (the center of the Region circle)
-// Let X be the point where the halfline SP meets a) if region is non-null, the region circle b) otherwise, the edge of the bitmap.
-//
-// If P is inside the Region, this function returns |PX|/||SX|, aka the 'degree' of point P. Otherwise, it returns 0.
-//
-// We compute the point where half-line from S to P intersects the edge of the bitmap. If that's inside the circle, end. If not, we solve the
-// the triangle with vertices at O, P and the point of intersection with the circle we are looking for X.
-// We know the lengths |PO|, |OX| and the angle OPX , because cos(OPX) = cos(180-OPS) = -cos(OPS) = -PS*PO/(|PS|*|PO|)
-// then from the law of cosines PX^2 + PO^2 - 2*PX*PO*cos(OPX) = OX^2 so
-// PX = -a + sqrt(a^2 + OX^2 - PO^2) where a = PS*PO/|PS| but we are really looking for d = |PX|/(|PX|+|PS|) = 1/(1+ (|PS|/|PX|) ) and
-// |PX|/|PS| = -b + sqrt(b^2 + (OX^2-PO^2)/PS^2) where b=PS*PO/|PS|^2 which can be computed with only one sqrt.
-//
-// the trick below is the if-less version of the
+// The trick below is the if-less version of the
 //
 // t = dx<0.0 ? (u_objD.x-v.x) / (u_objD.x-ux) : (u_objD.x+v.x) / (u_objD.x+ux);
 // h = dy<0.0 ? (u_objD.y-v.y) / (u_objD.y-uy) : (u_objD.y+v.y) / (u_objD.y+uy);
@@ -90,18 +76,35 @@ float degree_bitmap(in vec2 S, in vec2 PS)
   }
 
 //////////////////////////////////////////////////////////////////////////////////////////////
-// return degree of the point as defined by the Region
-// Currently only supports circles; .xy = vector from center of effect to the center of the circle, .z = radius
+// Return degree of the point as defined by the Region. Currently only supports circular regions.
+//
+// Let 'PS' be the vector from point P (the current vertex) to point S (the center of the effect).
+// Should work regardless if S is inside or outside of the circle.
+// Let region.xy be the vector from point S to point O (the center point of the region circle)
+// Let region.z be the radius of the region circle.
+//
+// If P is outside the circle, return 0.
+// Otherwise, let X be the point where the halfline SP meets the region circle - return |PX|/||SX|,
+// aka the 'degree' of point P.
+//
+// We solve the the triangle OPX.
+// We know the lengths |PO|, |OX| and the angle OPX, because cos(OPX) = cos(180-OPS) = -cos(OPS) = -PS*PO/(|PS|*|PO|)
+// then from the law of cosines PX^2 + PO^2 - 2*PX*PO*cos(OPX) = OX^2 so PX = -a + sqrt(a^2 + OX^2 - PO^2)
+// where a = PS*PO/|PS| but we are really looking for d = |PX|/(|PX|+|PS|) = 1/(1+ (|PS|/|PX|) ) and
+// |PX|/|PS| = -b + sqrt(b^2 + (OX^2-PO^2)/PS^2) where b=PS*PO/|PS|^2 which can be computed with only one sqrt.
 
 float degree_region(in vec3 region, in vec2 PS)
   {
   vec2 PO  = PS + region.xy;
   float D = region.z*region.z-dot(PO,PO);      // D = |OX|^2 - |PO|^2
+
+  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 DOT  = dot(PS,PO)*one_over_ps_sq;
 
-  return max(sign(D),0.0) / (1.0 + 1.0/(sqrt(DOT*DOT+D*one_over_ps_sq)-DOT));  // if D<=0 (i.e p is outside the Region) return 0.
+  return 1.0 / (1.0 + 1.0/(sqrt(DOT*DOT+D*one_over_ps_sq)-DOT));
   }
 
 //////////////////////////////////////////////////////////////////////////////////////////////
@@ -111,6 +114,9 @@ float degree(in vec3 region, in vec2 S, in vec2 PS)
   {
   vec2 PO  = PS + region.xy;
   float D = region.z*region.z-dot(PO,PO);      // D = |OX|^2 - |PO|^2
+
+  if( D<=0.0 ) return 0.0;
+
   vec2 A = sign(PS)*u_objD.xy + S;
   vec2 signA = sign(A);
   vec2 signA_SQ = signA*signA;
@@ -121,7 +127,7 @@ float degree(in vec3 region, in vec2 S, in vec2 PS)
   float one_over_ps_sq = 1.0/(ps_sq+1.0-sign(ps_sq));  // return 1.0 if ps_sq = 0.0
   float DOT  = dot(PS,PO)*one_over_ps_sq;
 
-  return max(sign(D),0.0) * min(1.0/(1.0 + 1.0/(sqrt(DOT*DOT+D*one_over_ps_sq)-DOT)),E);  // if D<=0 (i.e p is outside the Region) return 0.
+  return min(1.0/(1.0 + 1.0/(sqrt(DOT*DOT+D*one_over_ps_sq)-DOT)),E);
   }
 
 //////////////////////////////////////////////////////////////////////////////////////////////
