Converted from Ron Valstar / Mario Klingemann's AS3 Class.
Can be useful for particle effects etc, although the aesthetic effects are better when anti-aliasing and filters are available.
Perlin.bi
Code: Select all
TYPE Perlin
' Perlin Noise v.1.2 by Ron Valstar and Mario Klingemann
' Converted from ActionScript3 to FreeBASIC by Tinram (Martin Latter) Jan 4 2011
CONST AS INTEGER iOctaves = 4
PRIVATE:
AS INTEGER p(0 TO 511) = _
{_
151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,_
240,21,10,23,190,6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,_
33,88,237,149,56,87,174,20,125,136,171,168,68,175,74,165,71,134,139,48,27,166,77,146,_
158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,102,143,54,65,25,_
63,161,1,216,80,73,209,76,132,187,208,89,18,169,200,196,135,130,116,188,159,86,164,100,_
109,198,173,186,3,64,52,217,226,250,124,123,5,202,38,147,118,126,255,82,85,212,207,206,_
59,227,47,16,58,17,182,189,28,42,223,183,170,213,119,248,152,2,44,154,163,70,221,153,_
101,155,167,43,172,9,129,22,39,253,19,98,108,110,79,113,224,232,178,185,112,104,218,_
246,97,228,251,34,242,193,238,210,144,12,191,179,162,241,81,51,145,235,249,14,239,_
107,49,192,214,31,181,199,106,157,184,84,204,176,115,121,50,45,127,4,150,254,138,236,_
205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180,151,160,137,91,90,15,_
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,190,6,148,_
247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,88,237,149,56,87,174,_
20,125,136,171,168,68,175,74,165,71,134,139,48,27,166,77,146,158,231,83,111,229,122,60,_
211,133,230,220,105,92,41,55,46,245,40,244,102,143,54,65,25,63,161,1,216,80,73,209,76,_
132,187,208,89,18,169,200,196,135,130,116,188,159,86,164,100,109,198,173,186,3,64,52,217,_
226,250,124,123,5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,_
42,223,183,170,213,119,248,152,2,44,154,163,70,221,153,101,155,167,43,172,9,129,22,39,253,_
19,98,108,110,79,113,224,232,178,185,112,104,218,246,97,228,251,34,242,193,238,210,144,12,_
191,179,162,241,81,51,145,235,249,14,239,107,49,192,214,31,181,199,106,157,184,84,204,176,_
115,121,50,45,127,4,150,254,138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,_
61,156,180}
AS SINGLE aOctFreq(iOctaves) ' frequency per octave
AS SINGLE aOctPers(iOctaves) ' persistence per octave
AS SINGLE fPersistence = 0.5
AS SINGLE fPersMax ' 1 / max persistence
AS SINGLE fXoffset, fYoffset, fZoffset
AS INTEGER iSeed = CINT(RND * 2147483647)
AS INTEGER iInitialized = 0
DECLARE SUB seedOffset()
DECLARE SUB octFreqPers()
PUBLIC:
DECLARE FUNCTION noise(BYVAL fX2 AS SINGLE, BYVAL fY2 AS SINGLE = 1, BYVAL fZ2 AS SINGLE = 1) AS SINGLE
DECLARE DESTRUCTOR()
END TYPE
FUNCTION Perlin.noise(BYVAL fX2 AS SINGLE, BYVAL fY2 AS SINGLE = 1, BYVAL fZ2 AS SINGLE = 1) AS SINGLE
IF NOT iInitialized THEN ' ditched original init fn
this.seedOffset()
this.octFreqPers()
this.iInitialized = 1
END IF
DIM AS SINGLE fFreq, fPers, fX, fY, fZ, fU, fV, fW, fX1, fY1, fZ1, fS = 0
DIM AS SINGLE fG1, fG2, fG3, fG4, fG5, fG6, fG7, fG8
DIM AS INTEGER iX3, iY3, iZ3, iXf, iYf, iZf, iA, iB, iAA, iAB, iBA, iBB, iHash
fX2 += this.fXoffset
fY2 += this.fYoffset
fZ2 += this.fZoffset
FOR i AS INTEGER = 0 TO this.iOctaves
fFreq = this.aOctFreq(i)
fPers = this.aOctPers(i)
fX = fX2 * fFreq
fY = fY2 * fFreq
fZ = fZ2 * fFreq
iXf = INT(fX) ' using INT() as Math.floor(), as in the AS3
iYf = INT(fY)
iZf = INT(fZ)
iX3 = iXf AND 255
iY3 = iYf AND 255
iZ3 = iZf AND 255
fX -= iXf
fY -= iYf
fZ -= iZf
fU = fX * fX * fX * (fX * (fX * 6 - 15) + 10)
fV = fY * fY * fY * (fY * (fY * 6 - 15) + 10)
fW = fZ * fZ * fZ * (fZ * (fZ * 6 - 15) + 10)
iA = p(iX3) + iY3
iAA = p(iA) + iZ3
iAB = p(iA + 1) + iZ3
iB = p(iX3 + 1) + iY3
iBA = p(iB) + iZ3
iBB = p(iB + 1) + iZ3
fX1 = fX - 1
fY1 = fY - 1
fZ1 = fZ - 1
iHash = p(iBB + 1) AND 15
fG1 = ( IIF(iHash AND 1 = 0, IIF(iHash < 8, fX1, fY1), IIF(iHash < 8, -fX1, -fY1)) ) + ( IIF(iHash AND 2 = 0, IIF(iHash < 4, fY1, IIF(iHash = 12, fX1, fZ1)), IIF(iHash < 4, -fY1, IIF(iHash = 14, -fX1, -fZ1))) )
' original: fG1 = ((iHash & 1) == 0 ? (iHash < 8 ? fX1 : fY1) : (iHash < 8 ? -fX1 : -fY1)) + ((iHash & 2) == 0 ? iHash < 4 ? fY1 : (iHash == 12 ? fX1 : fZ1) : iHash < 4 ? -fY1 : (iHash == 14 ? -fX1 : -fZ1));
iHash = p(iAB + 1) AND 15
fG2 = ( IIF(iHash AND 1 = 0, IIF(iHash < 8, fX, fY1), IIF(iHash < 8, -fX, -fY1)) ) + ( IIF(iHash AND 2 = 0, IIF(iHash < 4, fY1, IIF(iHash = 12, fX, fZ1)), IIF(iHash < 4, -fY1, IIF(iHash = 14, -fX, -fZ1))) )
iHash = p(iBA + 1) AND 15
fG3 = ( IIF(iHash AND 1 = 0, IIF(iHash < 8, fX1, fY), IIF(iHash < 8, -fX1, -fY)) ) + ( IIF(iHash AND 2 = 0, IIF(iHash < 4, fY1, IIF(iHash = 12, fX1, fZ1)), IIF(iHash < 4, -fY, IIF(iHash = 14, -fX1, -fZ1))) )
iHash = p(iAA + 1) AND 15
fG4 = ( IIF(iHash AND 1 = 0, IIF(iHash < 8, fX, fY), IIF(iHash < 8, -fX, -fY)) ) + ( IIF(iHash AND 2 = 0, IIF(iHash < 4, fY, IIF(iHash = 12, fX, fZ1)), IIF(iHash < 4, -fY, IIF(iHash = 14, -fX, -fZ1))) )
iHash = p(iBB) AND 15
fG5 = ( IIF(iHash AND 1 = 0, IIF(iHash < 8, fX1, fY1), IIF(iHash < 8, -fX1, -fY1)) ) + ( IIF(iHash AND 2 = 0, IIF(iHash < 4, fY1, IIF(iHash = 12, fX1, fZ)), IIF(iHash < 4, -fY1, IIF(iHash = 14, -fX1, -fZ))) )
iHash = p(iAB) AND 15
fG6 = ( IIF(iHash AND 1 = 0, IIF(iHash < 8, fX, fY1), IIF(iHash < 8, -fX, -fY1)) ) + ( IIF(iHash AND 2 = 0, IIF(iHash < 4, fY1, IIF(iHash = 12, fX, fZ)), IIF(iHash < 4, -fY1, IIF(iHash = 14, -fX, -fZ))) )
iHash = p(iBA) AND 15
fG7 = ( IIF(iHash AND 1 = 0, IIF(iHash < 8, fX1, fY), IIF(iHash < 8, -fX1, -fY)) ) + ( IIF(iHash AND 2 = 0, IIF(iHash < 4, fY, IIF(iHash = 12, fX1, fZ)), IIF(iHash < 4, -fY, IIF(iHash = 14, -fX1, -fZ))) )
iHash = p(iAA) AND 15
fG8 = ( IIF(iHash AND 1 = 0, IIF(iHash < 8, fX, fY), IIF(iHash < 8, -fX, -fY)) ) + ( IIF(iHash AND 2 = 0, IIF(iHash < 4, fY, IIF(iHash = 12, fX, fZ)), IIF(iHash < 4, -fY, IIF(iHash = 14, -fX, -fZ))) )
fG2 += fU * (fG1 - fG2)
fG4 += fU * (fG3 - fG4)
fG6 += fU * (fG5 - fG6)
fG8 += fU * (fG7 - fG8)
fG4 += fV * (fG2 - fG4)
fG8 += fV * (fG6 - fG8)
fS += (fG8 + fW * (fG4 - fG8)) * fPers
NEXT i
RETURN (fS * this.fPersMax + 1) * 0.5
END FUNCTION
SUB Perlin.OctFreqPers()
DIM AS SINGLE fFreq, fPers
this.fPersMax = 0
FOR i AS INTEGER = 1 TO this.iOctaves
fFreq = 2 ^ i
fPers = fPersistence ^ i
this.fPersMax += fPers
aOctFreq(UBOUND(aOctFreq) - i) = fFreq ' was aOctFreq.push(fFreq) ' quick kludge, hmm...
aOctPers(UBOUND(aOctPers) - i) = fPers
NEXT i
this.fPersMax = 1 / this.fPersMax
END SUB
SUB Perlin.seedOffset()
this.fXoffset = this.iSeed = (this.iSeed * 16807) MOD 2147483647
this.fYoffset = this.iSeed = (this.iSeed * 16807) MOD 2147483647
this.fZoffset = this.iSeed = (this.iSeed * 16807) MOD 2147483647
END SUB
DESTRUCTOR Perlin()
ERASE this.p ' erase p array
END DESTRUCTOR
quick example:
Code: Select all
' example Perlin noise field generation based on a Processing script by Kyle McDonald
#include "Perlin.bi"
' -------------------------------------------------------------------------------------
FUNCTION normalize(value AS SINGLE, minimum AS SINGLE, maximum AS SINGLE) AS SINGLE
RETURN (value - minimum) / (maximum - minimum)
END FUNCTION
FUNCTION lerp(minimum AS SINGLE, maximum AS SINGLE, normValue AS SINGLE) AS SINGLE
RETURN minimum + (maximum - minimum) * normValue
END FUNCTION
' from Keith Peters' AS3
' -------------------------------------------------------------------------------------
CONST AS INTEGER iScreenDim = 500
CONST AS SINGLE c2PI = 4 * ATN(1) * 2 ' 2PI to separate u-noise from v-noise
RANDOMIZE (TIMER * 5000), 3
SCREENRES iScreenDim, iScreenDim, 32
DIM AS INTEGER iNumPoints = 3000
DIM AS INTEGER iComplexity = 2 ' wind complexity
DIM AS SINGLE fTimeSpeed = 0.02 ' wind variation speed
DIM SHARED AS SINGLE fMaxMass = 0.8 ' max pollen mass
DIM AS SINGLE fT, fX, fY, fNormX, fNormY, fU, fV, fSpeed
DIM AS STRING XClicked = CHR(255) + "k"
DIM AS Perlin oNoise1, oNoise2, oNoise3
TYPE Particle
AS SINGLE x = RND * iScreenDim
AS SINGLE y = RND * iScreenDim
AS SINGLE mass = RND * fMaxMass
AS UINTEGER col = RGB(RND * 255, RND * 255, RND * 255)
END TYPE
DIM AS Particle aParticles(iNumPoints)
DO
fT = 30 * fTimeSpeed ' was AS3 frameRate
FOR i AS INTEGER = 0 TO iNumPoints
fX = aParticles(i).x
fY = aParticles(i).y
fNormX = normalize(fX, 0, iScreenDim)
fNormY = normalize(fY, 0, iScreenDim)
fU = oNoise1.noise(fT + c2PI, fNormX * iComplexity + c2PI, fNormY * iComplexity + c2PI)
fV = oNoise2.noise(fT - c2PI, fNormX * iComplexity - c2PI, fNormY * iComplexity + c2PI)
fSpeed = (1 + oNoise3.noise(fT, fU, fV)) / aParticles(i).mass
fX += lerp(-fSpeed, fSpeed, fU)
fY += lerp(-fSpeed, fSpeed, fV)
IF fX < 0 THEN fX = RND * iScreenDim : fY = RND * iScreenDim
IF fX > iScreenDim THEN fX = RND * iScreenDim : fY = RND * iScreenDim
IF fY < 0 THEN fX = RND * iScreenDim : fY = RND * iScreenDim
IF fY > iScreenDim THEN fX = RND * iScreenDim : fY = RND * iScreenDim
aParticles(i).x = fX
aParticles(i).y = fY
PSET(fX, fY), aParticles(i).col
NEXT i
LOOP UNTIL MULTIKEY(&h01) OR INKEY = XClicked