randomize '33
static shared perm(0 TO 255) AS LONG

' Init mit LONG
DIM AS LONG i, j
FOR i = 0 TO 255: perm(i) = i: next
FOR i = 255 TO 1 STEP -1
  j = INT(RND * (i + 1))
  SWAP perm(i), perm(j)
NEXT

const iScale = 1024 , iScaleOffset = 100000

' FAKE-RANDOM: Gibt Wert 0-1000 zurueck statt 0.0-1.0
FUNCTION Random256(x as ulong, y AS ulong) AS ulong
  ' Hash ohne Floats
  DIM hash AS ulong = perm((x and 255) xor perm(y AND 255))
  RETURN (hash * iScale) shr 8 ' 0 bis 1000
end function
#define Random256perm( _X , _permY ) ((perm((_X) xor (_permY))*iScale) shr 8)

static shared as ulong FadeInt(iScale)
' FAKE-FADE: 0-1000 -> 0-1000 mit S-Kurve
FUNCTION FadeIntCalc(t AS long) AS ulong ' t ist 0-1000
  ' t*t*t*(t*(t*6-15)+10) aber in Integer
  ' Trick: Rechne in 64bit, skaliere runter
  DIM AS LONGINT t2 = t * t       ' 0 bis 1.000.000
  DIM AS LONGINT t3 = t2 * t      ' 0 bis 1.000.000.000
  DIM AS LONGINT t4 = t3 * t      ' 0 bis 1.000.000.000.000
  DIM AS LONGINT t5 = t4 * t      ' 0 bis 1.000.000.000.000.000
  ' 6t^5 - 15t^4 + 10t^3, alles /1000^4
  RETURN (6 * t5 - 15 * t4 * iScale + 10 * t3 * clngint(iScale*iScale)) \ (clngint(iScale)*iScale*iScale*iScale)  
END function
for N as long = 0 to iScale
  FadeInt(N) = FadeIntCalc(N)
next

#define is_power_of_two(x) ((x <> 0) andalso ((x and (x - 1)) = 0))

' FAKE-LERP: Lerp mit 0-1000 Werten
function LerpInt(a AS long, b as long, t as long) AS long ' t ist 0-1000
  return a + (((b - a) * t)\iScale) '\1000
end function
#define _LerpInt(_a, _b, _t) ((_a) + ((((_b) - (_a)) * (_t))\iScale))

#if 1
  function ValueNoiseInt(x as ulong, y as ulong) as ulong ' Return 0-1000
    ' Input: x,y sind Welt-Koords * 1000 fuer Praezision
    ' Beispiel: x=100.5 wird 100500
    
    static as ulong permY0,permY1,oldY=-1
    static as long v
    
    if y<>oldy then
      oldY = y
      permY0 = (y\iScale) and 255
      permY1 = perm((permY0 + 1) and 255)
      permY0 = perm(permY0)
      #if is_power_of_two(iScale)
        v = FadeInt(y and (iScale-1))
      #else
        v = FadeInt(y mod iScale)
      #endif    
    end if
            
    dim as ulong X0 = (x\iScale) and 255    
    dim as ulong X1 = (X0 + 1) and 255 ' 0-1000      
    
    dim aa as long = Random256perm(X0, permY0)
    dim ba as long = Random256perm(X1, permY0)
    dim ab as long = Random256perm(X0, permY1)
    dim bb as long = Random256perm(X1, permY1)
    
    #if is_power_of_two(iScale)
      dim u as long = FadeInt(x and (iScale-1)) ' iScale ' 0-999 Nachkomma
    #else
      dim u as long = FadeInt(x mod iScale) ' iScale ' 0-999 Nachkomma
    #endif  
      
    return LerpInt( _LerpInt(aa, ba, u) , _LerpInt(ab, bb, u), v) ' 0-1000
  end function
  function ValueNoiseInt2(x as ulong, y as ulong) as ulong ' Return 0-1000
    ' Input: x,y sind Welt-Koords * 1000 fuer Praezision
    ' Beispiel: x=100.5 wird 100500
    
    static as ulong permY0,permY1,oldY=-1
    static as long v
    
    if y<>oldy then
      oldY = y
      permY0 = (y\iScale) and 255
      permY1 = perm((permY0 + 1) and 255)
      permY0 = perm(permY0)
      #if is_power_of_two(iScale)
        v = FadeInt(y and (iScale-1))
      #else
        v = FadeInt(y mod iScale)
      #endif    
    end if
            
    dim as ulong X0 = (x\iScale) and 255    
    dim as ulong X1 = (X0 + 1) and 255 ' 0-1000      
    
    dim aa as long = Random256perm(X0, permY0)
    dim ba as long = Random256perm(X1, permY0)
    dim ab as long = Random256perm(X0, permY1)
    dim bb as long = Random256perm(X1, permY1)
    
    #if is_power_of_two(iScale)
      dim u as long = FadeInt(x and (iScale-1)) ' iScale ' 0-999 Nachkomma
    #else
      dim u as long = FadeInt(x mod iScale) ' iScale ' 0-999 Nachkomma
    #endif  
      
    return LerpInt( _LerpInt(aa, ba, u) , _LerpInt(ab, bb, u), v) ' 0-1000
  end function
#else
  #define ValueNoiseInt2 ValueNoiseInt
  function ValueNoiseInt(x as ulong, y as ulong) as ulong ' Return 0-1000
    ' Input: x,y sind Welt-Koords * 1000 fuer Praezision
    ' Beispiel: x=100.5 wird 100500
    
    dim x0 as ulong = (x\iScale) and 255 '\1024
    dim y0 as ulong = (y\iScale) and 255 '\1024
    dim x1 as ulong = (x0 + 1) and 255
    dim y1 as ulong = (y0 + 1) and 255
    
    #if is_power_of_two(iScale)
      dim u as ulong = FadeInt(x and (iScale-1)) ' iScale ' 0-999 Nachkomma
      dim v as ulong = FadeInt(y and (iScale-1)) ' iScale
    #else
      dim u as ulong = FadeInt(x mod iScale) ' iScale ' 0-999 Nachkomma
      dim v as ulong = FadeInt(y mod iScale) ' iScale
    #endif
      
    dim aa as ulong = Random256(x0, y0)
    dim ba as ulong = Random256(x1, y0)
    dim ab as ulong = Random256(x0, y1)
    dim bb as ulong = Random256(x1, y1)  
    
    return LerpInt( LerpInt(aa, ba, u) , LerpInt(ab, bb, u) , v) ' 0-1000
  end function
#endif