C'est utile pour créer des textures, ou des terrains.
Code : Tout sélectionner
#Taille = 256
CreateImage(0,#taille,#Taille)
OpenWindow(0,0,0,#Taille,#Taille,"Perlin")
If CreateGadgetList(WindowID(0))
ImageGadget(0,0,0,#taille,#taille,ImageID(0))
EndIf
Structure s_Colonne
y.l[#Taille]
EndStructure
Structure s_Calque
x.s_Colonne[#Taille]
persistance.f
EndStructure
Declare generer_calque(frequence, octaves, persistance.f, liss,*c.s_Calque)
Declare interpolate(y1, y2, n, delta)
Declare valeur_interpolee(i, j, frequence, *r.s_Calque)
Declare enregistrer_bmp(*c.s_Calque, filename.s)
Procedure init_calque(p.f)
*s.s_Calque = AllocateMemory(SizeOf(s_calque))
If *s=0
MessageRequester("Oups!","erreur d'alloc",#PB_MessageRequester_Ok)
ProcedureReturn #Null
EndIf
*s\persistance = p
ProcedureReturn *s
EndProcedure
Procedure generer_calque(frequence, octaves, persistance.f, liss,*c.s_Calque)
; itératif
Define i,j,n,f_courante
Define x,y,k,l
Define a
Define.f pas, sum_persistances,persistance_courante
pas = #taille/frequence
persistance_courante = persistance
; calque aléatoire
Define.s_Calque *random
*random = init_calque(1)
For i=0 To #taille-1
For j=0 To #taille-1
*random\x[i]\y[j]=Random(255)
Next j
Next i
enregistrer_bmp(*random, "alea.bmp")
; calques de travail
Dim *mes_calques.s_Calque(octaves-1)
For i=0 To octaves-1
*mes_calques(i)=init_calque(persistance_courante)
persistance_courante * persistance
Next i
f_courante = frequence
; remplissage de calque
For n=0 To octaves-1
For i=0 To #taille-1
For j=0 To #taille-1
a = valeur_interpolee(i, j, f_courante, *random)
*mes_calques(n)\x[i]\y[j]=a
Next j
Next i
f_courante * frequence
Next n
sum_persistances = 0
For i=0 To octaves-1
sum_persistances + *mes_calques(i)\persistance
Next i
; ajout des calques successifs
For i=0 To #taille-1
For j=0 To #taille-1
For n=0 To octaves-1
*c\x[i]\y[j] + *mes_calques(n)\x[i]\y[j] * *mes_calques(n)\persistance
Next n
;normalisation
*c\x[i]\y[j] = *c\x[i]\y[j] / sum_persistances
Next j
Next i
;lissage
Define *lissage.s_Calque
*lissage = init_calque(0)
For x=0 To #taille-1
For y=0 To #taille-1
a=0
n=0
For k=x-liss To x+liss
For l=y-liss To y+liss
If ((k>=0) And (k<#taille) And (l>=0) And (l<#taille))
n + 1
a + *c\x[k]\y[l]
EndIf
Next l
Next k
*lissage\x[x]\y[y] = a/n
Next y
Next x
enregistrer_bmp(*lissage, "lisse.bmp")
EndProcedure
Procedure interpolate(y1, y2, n, delta)
; interpolation non linéaire
If n=0
ProcedureReturn y1
EndIf
If n=1
ProcedureReturn y2
EndIf
a.f = delta/n
fac1.f = 3*Pow(1-a, 2) - 2*Pow(1-a,3)
fac2.f = 3*Pow(a, 2) - 2*Pow(a, 3)
ProcedureReturn y1*fac1 + y2*fac2
EndProcedure
Procedure valeur_interpolee(i, j, frequence, *r.s_Calque)
; valeurs des bornes
Define borne1x, borne1y, borne2x, borne2y, q
Define.l pas
pas = #taille/frequence
If pas = 0 : pas = 1 : EndIf
q = i/pas
borne1x = q*pas
borne2x = (q+1)*pas
If borne2x >= #taille
borne2x = #taille-1
EndIf
q = j/pas
borne1y = q*pas
borne2y = (q+1)*pas
If borne2y >= #taille
borne2y = #taille-1
EndIf
Define b00,b01,b10,b11
b00 = *r\x[borne1x]\y[borne1y]
b01 = *r\x[borne1x]\y[borne2y]
b10 = *r\x[borne2x]\y[borne1y]
b11 = *r\x[borne2x]\y[borne2y]
v1 = interpolate(b00, b01, borne2y-borne1y, j-borne1y)
v2 = interpolate(b10, b11, borne2y-borne1y, j-borne1y)
fin = interpolate(v1, v2, borne2x-borne1x , i-borne1x)
ProcedureReturn fin
EndProcedure
Procedure aleatoire(a.f)
ProcedureReturn Random(256)
EndProcedure
Procedure enregistrer_bmp(*c.s_Calque, filename.s)
CreateImage(0,#taille, #taille, 32)
If StartDrawing(ImageOutput(0))
For i=0 To #taille-1
For j=0 To #taille-1
Plot(i,j,RGB(*c\x[i]\y[j],*c\x[i]\y[j],*c\x[i]\y[j]))
Next j
Next i
StopDrawing()
SaveImage(0,filename)
EndIf
EndProcedure
Procedure main()
;valeurs d'entrée
octaves=3
frequence=5
persistance.f=0.3
lissage = 9
;création de calque
Define.s_Calque *s
*s = init_calque(persistance)
generer_calque(frequence, octaves, persistance,lissage, *s)
;enregistrer_bmp(*s, "resultat.bmp")
EndProcedure
main()
SetGadgetState(0,ImageID(0))
SetClipboardImage(0)
Repeat
EventID = WaitWindowEvent()
If EventID = #PB_Event_CloseWindow
Quit = 1
EndIf
Until Quit = 1