Frenchy Pilou a écrit :La 2D est à l'honneur!![]()
Tiens je pensais à un petit truc, qui n'a pas trop de rapport avec ce début de programme mais qui est graphique quand même!![]()
Plutôt du genre transformation!
On prend une image, chaque pixel devient un "grain de matière liquide" coloré non soluble
(il peut y avoir des variantes de solubilité de couleur)
On perce "un trou(s)" au milieu de la partie basse de l'image
Les grains s'écoulent dans une boîte de surface équivalente située en dessous
(comme un dans un sablier)
Variante : on supprime une certaine longueur de la partie haute et on bascule l'image de 90°
qui va s'écouler dans une boîte de surface équivalente située en dessous en diagonale
(ici j'ai carrément supprimé toute la paroi, il faudrait peut-être garder un peu de montant
sur la partie ouverte pour bloquer la dégoulinade)
Evidemment il y a peu de chance d'avoir à l'arrivée quelque chose de très cohérent!
Tiens, je viens d'essayer...et le résultat me semble pas trop mal

Pour l'utiliser changez juste l'image du code, puis suivez les instructions !
Il me reste à modifier le code de façon à atténuer l'effet du traitement par tableau...
Et à ajouter un test de collision sur le trajet des grains plus poussé que celui actuel qui ne teste que le point d'arrivé.
C'est sympa avec cette image de test :

On retrouve les couleurs arrangées un minimum !
Il faut désactiver le débugger, qui ralentis le code d'environ 500%, compiler en mode Threadsafe.
Code : Tout sélectionner
; image$ = "D:\Documents\Images\pin-ups\pinupcool.jpg"
image$ = "fractale_2.png"
UseJPEGImageDecoder()
UsePNGImageDecoder()
;{ paramètres, structures
CompilerIf #PB_Compiler_OS <> #PB_OS_Windows
#White = 16777215
CompilerEndIf
Structure GrainDeMatiereLiquide
couleur.l
Type.l ; 0 = Vide, 1 = grain de matière, 2 = mur
PasseDessin.l
vitesse_X.d
vitesse_Y.d
EndStructure
Structure Image_DATA
Array Display.GrainDeMatiereLiquide(1, 1)
Array_L.l
Array_H.l
List RandomDisplay.POINT()
IMG.i
L.l
H.l
DelayTimer.l
Largeur_Trou.l
Gravite.d
PasseDessin.l
ThreadID.i
EndStructure
Global Param_l.l = 300, Screen.POINT, Mode.l, Avancement.l
Screen\x = 1000
Screen\y = 700
;}
;{ Chargement image départ
IMG = LoadImage(#PB_Any, image$)
ratio.d = ImageWidth(img) / ImageHeight(img)
If ImageHeight(img) > Param_l
If ratio > 1
ResizeImage(img, Param_l, Param_l / ratio)
Else
ResizeImage(img, Param_l * ratio, Param_l)
EndIf
ElseIf ImageWidth(img) > Param_l
If ratio < 1
ResizeImage(img, Param_l, Param_l / ratio)
Else
ResizeImage(img, Param_l * ratio, Param_l)
EndIf
EndIf
;}
;{ procedure et Thread
Procedure Mode_0_Chargement(*obj.Image_DATA)
Protected x.l, y.l
*obj\Array_L = 4 + *obj\L - 1
*obj\Array_H = 2 * (*obj\H - 1) + 50 + 2
Dim *obj\Display(*obj\Array_L, *obj\Array_H)
; chargement de l'image
StartDrawing(ImageOutput(*obj\IMG))
For x = 0 To *obj\L - 1
For y = 0 To *obj\H - 1
*obj\Display(x + 2, y)\couleur = Point(x, y)
*obj\Display(x + 2, y)\Type = 1
Next
Avancement = 10 * x / *obj\L
Next
StopDrawing()
Avancement = 10
; Ajout des bordures verticales
For y = 0 To *obj\H - 1 + 2
*obj\Display(0, y)\couleur = #White
*obj\Display(1, y)\couleur = #White
*obj\Display(*obj\L + 2, y)\couleur = #White
*obj\Display(*obj\L + 3, y)\couleur = #White
*obj\Display(0, y + *obj\H - 1 + 50)\couleur = #White
*obj\Display(1, y + *obj\H - 1 + 50)\couleur = #White
*obj\Display(*obj\L + 2, y + *obj\H - 1 + 50)\couleur = #White
*obj\Display(*obj\L + 3, y + *obj\H - 1 + 50)\couleur = #White
*obj\Display(0, y)\Type = 2
*obj\Display(1, y)\Type = 2
*obj\Display(*obj\L + 2, y)\Type = 2
*obj\Display(*obj\L + 3, y)\Type = 2
*obj\Display(0, y + *obj\H - 1 + 50)\Type = 2
*obj\Display(1, y + *obj\H - 1 + 50)\Type = 2
*obj\Display(*obj\L + 2, y + *obj\H - 1 + 50)\Type = 2
*obj\Display(*obj\L + 3, y + *obj\H - 1 + 50)\Type = 2
Next
For y = 0 To 50
*obj\Display(0, y + *obj\H - 1)\Type = 2
*obj\Display(1, y + *obj\H - 1)\Type = 2
*obj\Display(*obj\L + 2, y + *obj\H - 1)\Type = 2
*obj\Display(*obj\L + 3, y + *obj\H - 1)\Type = 2
Next
Avancement = 11
; Ajout des bordures horizonales
For x = 0 To *obj\Array_L
*obj\Display(x, *obj\H)\couleur = #White
*obj\Display(x, *obj\H + 1)\couleur = #White
*obj\Display(x, *obj\Array_H - 1)\couleur = #White
*obj\Display(x, *obj\Array_H)\couleur = #White
*obj\Display(x, *obj\H)\Type = 2
*obj\Display(x, *obj\H + 1)\Type = 2
*obj\Display(x, *obj\Array_H - 1)\Type = 2
*obj\Display(x, *obj\Array_H)\Type = 2
Next
Avancement = 12
For x = 0 To *obj\Array_L
For y = 0 To *obj\Array_H
AddElement(*obj\RandomDisplay())
*obj\RandomDisplay()\x = x
*obj\RandomDisplay()\y = y
Next
Next
RandomizeList(*obj\RandomDisplay())
; Protected NewList Grain.POINT()
;
; For x = 0 To *obj\Array_L
; For y = 0 To *obj\Array_H
; AddElement(Grain())
; Grain()\x = x
; Grain()\y = y
; Next
; Next
;
; Avancement = 13
;
; Protected mem_listsize = ListSize(Grain())
;
; ; randomization :
; While ListSize(Grain()) > 0
; SelectElement(Grain(), Random(ListSize(Grain()) - 1))
;
; AddElement(*obj\RandomDisplay())
; *obj\RandomDisplay() = Grain()
;
; DeleteElement(Grain())
;
; Avancement = 87 * (mem_listsize - ListSize(Grain())) / mem_listsize + 13
; Wend
Avancement = 100
EndProcedure
Procedure.i InitializeImageData(Image.l)
Protected *obj.Image_DATA
*obj = AllocateMemory(SizeOf(Image_DATA))
InitializeStructure(*obj, Image_DATA)
*obj\IMG = Image
*obj\L = ImageWidth(Image)
*obj\H = ImageHeight(Image)
*obj\DelayTimer = 5
*obj\Largeur_Trou = 100
*obj\Gravite = 1
*obj\ThreadID = CreateThread(@Mode_0_Chargement(), *obj)
AddWindowTimer(0, 0, 50)
ProcedureReturn *obj
EndProcedure
;}
;{ fenêtre
If OpenWindow(0, 0, 0, Screen\x, Screen\y, "Image Liquide", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
CanvasGadget(0, 0, 0, Screen\x, Screen\y, #PB_Canvas_Keyboard)
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
SetFocus_(GadgetID(0))
CompilerEndIf
Else
End
EndIf
;}
; lancement
*ImageData.Image_DATA = InitializeImageData(img)
Repeat
event = WaitWindowEvent()
;{ Clavier
If event = #PB_Event_Gadget And EventType() = #PB_EventType_KeyDown
Select GetGadgetAttribute(0, #PB_Canvas_Key)
Case #PB_Shortcut_Escape
event = #PB_Event_CloseWindow
Case #PB_Shortcut_Space
If mode = 2
; perçage du trou dans le réservoir du dessus
For x = (*ImageData\Array_L - *ImageData\Largeur_Trou) / 2 To (*ImageData\Array_L + *ImageData\Largeur_Trou) / 2
*ImageData\Display(x, *ImageData\H)\couleur = 0
*ImageData\Display(x, *ImageData\H)\Type = 0
*ImageData\Display(x, *ImageData\H + 1)\couleur = 0
*ImageData\Display(x, *ImageData\H + 1)\Type = 0
Next
Mode = 3
AddWindowTimer(0, 0, *ImageData\DelayTimer)
EndIf
Case #PB_Shortcut_Left
If mode = 2
ToucheEnfonce + 1
If ToucheEnfonce < 15
*ImageData\Largeur_Trou - 1
Else
*ImageData\Largeur_Trou - 10
EndIf
If *ImageData\Largeur_Trou < 2 : *ImageData\Largeur_Trou = 2 : EndIf
ElseIf Mode = 3
*ImageData\DelayTimer - 5
If *ImageData\DelayTimer < -5 : *ImageData\DelayTimer = -5 : EndIf
RemoveWindowTimer(0, 0)
AddWindowTimer(0, 0, *ImageData\DelayTimer)
EndIf
Case #PB_Shortcut_Right
If mode = 2
ToucheEnfonce + 1
If ToucheEnfonce < 15
*ImageData\Largeur_Trou + 1
Else
*ImageData\Largeur_Trou + 10
EndIf
If *ImageData\Largeur_Trou > *ImageData\Array_L - 4 : *ImageData\Largeur_Trou = *ImageData\Array_L - 4 : EndIf
ElseIf Mode = 3
*ImageData\DelayTimer + 5
If *ImageData\DelayTimer > 100 : *ImageData\DelayTimer = 100 : EndIf
RemoveWindowTimer(0, 0)
AddWindowTimer(0, 0, *ImageData\DelayTimer)
EndIf
Default
If mode = 2
ToucheEnfonce = 0
EndIf
EndSelect
ElseIf EventType() = #PB_EventType_KeyUp
If mode = 2
ToucheEnfonce = 0
EndIf
EndIf
;}
;{ Dessin&Traitement en fonction du mode
Select mode
Case 0
;{ chargement de l'image dans le tableau, et ajout des autres préparations
If StartDrawing(CanvasOutput(0))
Box(0, 0, Screen\x, Screen\y, 0)
DrawText(500, 10, "Conversion de l'image en grain coloré de matière liquide non soluble... " + Avancement + "%")
StopDrawing()
EndIf
If Avancement = 100 ; Chargement terminé ! on passe à la suite...
Mode = 1
Avancement = 0
EndIf
;}
Case 1, 3
;{ Attente du perçage du trou
If StartDrawing(CanvasOutput(0))
Box(0, 0, Screen\x, Screen\y, 0)
time = ElapsedMilliseconds()
;{ Gestion de la physique des Grains
If mode = 3
MODIF = #False
; For x = 0 To *ImageData\Array_L
; For y = 0 To *ImageData\Array_H
ForEach *ImageData\RandomDisplay()
x = *ImageData\RandomDisplay()\x
y = *ImageData\RandomDisplay()\y
If x > 0 And y > 0 And x < *ImageData\Array_L And y < *ImageData\Array_H And *ImageData\Display(x, y)\Type = 1 And *ImageData\PasseDessin = *ImageData\Display(x, y)\PasseDessin
With *ImageData\Display(x, y)
; mouvement vertical
\vitesse_Y + *ImageData\Gravite
; mouvement horizontal
If *ImageData\Display(x, y + 1)\Type = 1
Signe.b = (2*Random(1) - 1)
If *ImageData\Display(x + Signe, y)\Type = 1 And *ImageData\Display(x - Signe, y)\Type = 0
\vitesse_X = \vitesse_X - Signe ;- Signe * (*ImageData\Display(x + Signe, y)\vitesse_X)
ElseIf *ImageData\Display(x - Signe, y)\Type = 1 And *ImageData\Display(x + Signe, y)\Type = 0
\vitesse_X = \vitesse_X + Signe ;+ Signe * (*ImageData\Display(x - Signe, y)\vitesse_X)
EndIf
EndIf
; Test si des obstacles sont présents sur le mouvement du grain
x1 = x + \vitesse_X
y1 = y + \vitesse_Y
If y1 < 0 : y1 = 0 : EndIf
If x1 < 0 : x1 = 0 : EndIf
If y1 > *ImageData\Array_H : y1 = *ImageData\Array_H : EndIf
If x1 > *ImageData\Array_L : x1 = *ImageData\Array_L : EndIf
Deplacement.b = #False
If *ImageData\Display(x1, y1)\Type = 0
Deplacement = #True
ElseIf *ImageData\Display(x1, y)\Type = 0
y1 = y
\vitesse_Y = 0
Deplacement = #True
ElseIf *ImageData\Display(x, y1)\Type = 0
x1 = x
\vitesse_X = 0
Deplacement = #True
EndIf
If Deplacement = #True
*ImageData\Display(x1, y1) = *ImageData\Display(x, y)
*ImageData\Display(x1, y1)\PasseDessin = *ImageData\PasseDessin + 1
Plot(x1 + 100, y1 + 25, *ImageData\Display(x1, y1)\couleur)
*ImageData\Display(x, y)\couleur = 0
; *ImageData\Display(x, y)\vitesse_X = 0
; *ImageData\Display(x, y)\vitesse_Y = 0
*ImageData\Display(x, y)\Type = 0
; *ImageData\Display(x, y)\PasseDessin = *ImageData\PasseDessin ;+ 1
MODIF = #True
Else
\vitesse_X = 0
\vitesse_Y = 0
\PasseDessin + 1
EndIf
EndWith
EndIf
Plot(x + 100, y + 25, *ImageData\Display(x, y)\couleur)
Next
; Next
; Next
If MODIF = #False
Mode = 4 ; équilibre des grains
EndIf
*ImageData\PasseDessin + 1
;}
Else
;{ juste le dessin
For x = 0 To *ImageData\Array_L
For y = 0 To *ImageData\Array_H
Plot(x + 100, y + 25, *ImageData\Display(x, y)\couleur)
Next
Next
;}
RemoveWindowTimer(0, 0)
mode = 2
EndIf
If mode < 4
DrawText(500, 10, "Temps mis pour dessiner les grains de matière liquide : " + Str(ElapsedMilliseconds() - time) + "ms")
If mode <> 3
DrawText(500, 40, "Appuyer sur [Espace] pour faire un trou dans le fond du contenant du haut !")
DrawText(500, 60, "Appuyer sur [<] et [>] pour ajuster la largeur du trou :")
Else
DrawText(500, 60, "Appuyer sur [<] et [>] pour ajuster le delay du timer de dessin :")
DrawText(500, 90, "Delay du Timer = " + *ImageData\DelayTimer + "ms")
EndIf
EndIf
StopDrawing()
EndIf
;}
Case 2
;{ Modification de la largeur du trou
If StartDrawing(CanvasOutput(0))
Box(500, 90, 150, 20, 0)
DrawText(500, 90, "Largeur du Trou = " + *ImageData\Largeur_Trou)
StopDrawing()
mode = 2
EndIf
;}
Case 4
;{ Equilibre des grains
If StartDrawing(CanvasOutput(0))
Box(Param_l + 110, 0, Screen\x - Param_l - 100, Screen\y, 0)
DrawText(500, 10, "Equilibre des grains de matière liquide atteint.")
StopDrawing()
EndIf
;}
EndSelect
;}
Until event = #PB_Event_CloseWindow
End