shithub: freetype+ttf2subf

Download patch

ref: 884e4e67ee434bd99fbf2edac6b77dc1ebd07263
parent: 7cdc77f229dd72517304a770a81f559bbf7117bc
author: Alexei Podtelezhnikov <[email protected]>
date: Mon Jun 29 18:32:05 EDT 2015

[base] Implement fast vector normalization.

The function uses Newton's iterations instead of dividing vector
components by its length, which needs a square root. This is,
literally, a bit less accurate but a lot faster.

* src/base/ftcalc.c (FT_Vector_NormLen): New function.

git/fs: mount .git/fs: mount/attach disallowed
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2015-06-29  Alexei Podtelezhnikov <[email protected]>
+
+	[base] Implement fast vector normalization.
+
+	The function uses Newton's iterations instead of dividing vector
+	components by its length, which needs a square root. This is,
+	literally, a bit less accurate but a lot faster.
+
+	* src/base/ftcalc.c (FT_Vector_NormLen): New function.
+
 2015-06-28  Werner Lemberg  <[email protected]>
 
 	* CMakeLists.txt: Always create `ftconfig.h'.
--- a/include/freetype/internal/ftcalc.h
+++ b/include/freetype/internal/ftcalc.h
@@ -300,6 +300,18 @@
 
 
   /*
+   *  This function normalizes a vector and returns its original length.
+   *  The normalized vector is a 16.16 fixed-point unit vector with length
+   *  close to 0x10000. The accuracy of the returned length is limited to
+   *  16 bits also. The function utilizes quick inverse square root
+   *  aproximation without divisions and square roots relying on Newton's
+   *  iterations instead.
+   */
+  FT_BASE( FT_UInt32 )
+  FT_Vector_NormLen( FT_Vector*  vector );
+
+
+  /*
    *  Return -1, 0, or +1, depending on the orientation of a given corner.
    *  We use the Cartesian coordinate system, with positive vertical values
    *  going upwards.  The function returns +1 if the corner turns to the
--- a/src/base/ftcalc.c
+++ b/src/base/ftcalc.c
@@ -785,6 +785,88 @@
   }
 
 
+  /* documentation is in ftcalc.h */
+
+  FT_BASE_DEF( FT_UInt32 )
+  FT_Vector_NormLen( FT_Vector*  vector )
+  {
+    FT_Int32   x = vector->x;
+    FT_Int32   y = vector->y;
+    FT_Int32   b, z;
+    FT_UInt32  u, v, l;
+    FT_Int     sx = 1, sy = 1, shift;
+
+
+    FT_MOVE_SIGN( x, sx );
+    FT_MOVE_SIGN( y, sy );
+
+    /* trivial cases */
+    if ( x == 0 )
+    {
+      if ( y > 0 )
+        vector->y = sy * 0x10000;
+      return y;
+    }
+    else if ( y == 0 )
+    {
+      if ( x > 0 )
+        vector->x = sx * 0x10000;
+      return x;
+    }
+
+    /* estimate length and prenormalize */
+    l = x > y ? (FT_UInt32)x + ( y >> 1 )
+              : (FT_UInt32)y + ( x >> 1 );
+
+    shift  = 31 - FT_MSB( l );
+    shift -= 15 + ( l >= 0xAAAAAAAAUL >> shift );
+
+    if ( shift > 0 )
+    {
+      x <<= shift;
+      y <<= shift;
+
+      /* reestimate length for tiny vectors */
+      l = x > y ? (FT_UInt32)x + ( y >> 1 )
+                : (FT_UInt32)y + ( x >> 1 );
+    }
+    else
+    {
+      x >>= -shift;
+      y >>= -shift;
+      l >>= -shift;
+    }
+
+    /* lower linear approximation for reciprocal length minus one */
+    b = 0x10000 - (FT_Int32)l;
+
+    /*  Newton's iterations */
+    do
+    {
+      u = (FT_UInt32)( x + ( x * b >> 16 ) );
+      v = (FT_UInt32)( y + ( y * b >> 16 ) );
+
+      /* converting to signed gives difference with 2^32 */
+      z = -(FT_Int32)( u * u + v * v ) / 0x200;
+      z = z * ( ( 0x10000 + b ) >> 8 ) / 0x10000;
+
+      b += z;
+    } while ( z > 0 );
+
+    vector->x = sx < 0 ? -(FT_Pos)u : (FT_Pos)u;
+    vector->y = sy < 0 ? -(FT_Pos)v : (FT_Pos)v;
+
+    /* true length, again taking advantage of signed difference with 2^32 */
+    l = 0x10000 + (FT_Int32)( u * x + v * y ) / 0x10000;
+    if ( shift > 0 )
+      l = ( l + ( 1 << ( shift - 1 ) ) ) >> shift;
+    else
+      l <<= -shift;
+
+    return l;
+  }
+
+
 #if 0
 
   /* documentation is in ftcalc.h */