http://www.intpowertechcorp.com/GDC03.pdf
C'est bien rigolo, mais pour le moment ce n'est qu'un code qui refait absolument la même chose,
j'espère pouvoir vous faire une petite personnalisation plus tard
 
 Le code de mise en œuvre est assez sale, mais la partie de simulation est super propre
 
 [EDIT] Version 2, mise à jour
Code : Tout sélectionner
;{######################################
; Programme : 		Dynamique des Fluides, GAME ENGINE DEMO
#VERSION = "2.00"
;	
; Description : 	- Mets en place quelques fonctions simples et rapide permettant la simulation d'un fluide et de particules
;									- L'interface permets de tester ces fonctions rapidement
;									
; Détails & TODOs réalisés:
;									- Version 1.00
;									- Moteur de simulation
;									- Interface, clavier / souris
;									
;									- Version 2.00
;									- Ajout de sources flux / particules
;									- MAJ de l'interface : + de fluidité
;									- Multiples conditions limites : Boite / Libre
;									
;	Ajouts prévus :	
;									- Champ de particules de taille != du fluide
;									- Image à la place des particules
;									- Heigth map des vecteurs vitesse
;									- Tracé de lignes de flux continues
;									
;	Bug trouvés :		
;									- 
;									
; Bug corrigés :	
;									- 
;									
; Sources :
;									- Réalisé à partir de l'article de Jos Stam
;											"Real-Time Fluid Dynamics for Games"
;									- Plus de document du même auteur : 
;											http://www.dgp.toronto.edu/people/stam/reality/index.html
;	Compilateur :
;									- PureBasic 5.22LTS
;									- x86 / x64
;									- Window / Linux / Mac
;									- Pas d'usage d'API
;									
; Auteur : graph100 alias Kriek106
;}######################################
DisableDebugger
;{ initialisation
Structure POINT_d
	x.d
	y.d
EndStructure
Structure tableau
	Array tab.d(0, 0)
EndStructure
Macro Tableau_init(_adr_, _struct_)
	_adr_ = AllocateMemory(SizeOf(_struct_))
	InitializeStructure(_adr_, _struct_)
EndMacro
Macro Tableau_Free(_adr_, _struct_)
	ClearStructure(_adr_, _struct_)
	FreeMemory(_adr_)
EndMacro
Structure Fluide
	
	; Paramètres
	
	W.l
	H.l
	
	Viscosite.d
	
	; Calculs
	dim_w.l ; = w + 1 ; Dim 0 et n+1 sont là pour les conditions limites
	dim_h.l ; = h + 1
	max_wh.d ; max(W, H)
	
	; Tableaux des vitesses du fluide
	*u.tableau
	*v.tableau
	
	*u_prec.tableau
	*v_prec.tableau
	
EndStructure
Structure Densite
	diffusion.d ; taux de diffusion de la densité (entre 0 et 1)
	
	*densite.tableau
	*densite_prec.tableau
EndStructure
Structure Source_Vitesse
	Pos.POINT
	dir.POINT_d ; pixels / seconde
	
	vitesse.d ; indicatif, ne sert pas dans les calculs, mais pour affichage
EndStructure
Structure Source_Particule
	Pos.POINT
	
	Debit.d ; particules / seconde
EndStructure
Structure SIM_FL
	Fluide.Fluide
	Densite.Densite
	
	dt.d ; s entre chaque simulation
	
	List Source_Vitesses.Source_Vitesse()
	List Source_Particules.Source_Particule()
	
EndStructure
Procedure Fluide_Init(*obj.Fluide, Largeur.l, Hauteur.l, Viscosite.d)
	With *obj
		
		\W = Largeur
		\H = Hauteur
		
		If \W < \H
			\max_wh = \W
		Else
			\max_wh = \H
		EndIf
		
		\Viscosite = Viscosite
		
		\Dim_w = \w + 1
		\Dim_h = \h + 1
		
		Tableau_init(\u, tableau)
		Tableau_init(\v, tableau)
		
		Tableau_init(\u_prec, tableau)
		Tableau_init(\v_prec, tableau)
		
		Dim \u\tab(\Dim_w, \Dim_h)
		Dim \v\tab(\Dim_w, \Dim_h)
		Dim \u_prec\tab(\Dim_w, \Dim_h)
		Dim \v_prec\tab(\Dim_w, \Dim_h)
		
	EndWith
EndProcedure
Procedure Densite_Init(*obj.Densite, *fluide.Fluide, Diffusion.d)
	With *obj
		
		\diffusion = Diffusion
		
		Tableau_init(\densite, tableau)
		Tableau_init(\densite_prec, tableau)
		
		Dim \densite\tab(*fluide\Dim_w, *fluide\Dim_h)
		Dim \densite_prec\tab(*fluide\Dim_w, *fluide\Dim_h)
		
	EndWith
EndProcedure
Procedure.i AjouterSource_Flux(*obj.SIM_FL, x.l, y.l, dir_x.d, dir_y.d)
	Protected *new_vit.Source_Vitesse = AddElement(*obj\Source_Vitesses())
	
	*new_vit\Pos\x = x
	*new_vit\Pos\y =y
	
	*new_vit\dir\x = dir_x
	*new_vit\dir\y = dir_y
	
	*new_vit\vitesse = Sqr(*new_vit\dir\x * *new_vit\dir\x + *new_vit\dir\y * *new_vit\dir\y)
	
	ProcedureReturn *new_vit
EndProcedure
Procedure.i AjouterSource_Particules(*obj.SIM_FL, x.l, y.l, debit.d)
	Protected *new_part.Source_Particule = AddElement(*obj\Source_Particules())
	
	*new_part\Pos\x = x
	*new_part\Pos\y = y
	
	*new_part\Debit = debit
	
	ProcedureReturn *new_part
EndProcedure
;}
;{ Simulation
Procedure FS_SetBoundaryCondition_Boite(*obj.SIM_FL, MODE.l, Array x.d(2))
	With *obj
		
		; MODE = 0 : lorsque x() = dens()
		; MODE = 1 : lorsque x() = u()
		; MODE = 2 : lorsque x() = v()
		
		Protected i
		
		If MODE = 2
			For i = 1 To \Fluide\W
				
				x(i, 0) = - x(i, 1)
				x(i, \Fluide\dim_h) = - x(i, \Fluide\H)
				
			Next
		Else
			For i = 1 To \Fluide\W
				
				x(i, 0) = x(i, 1)
				x(i, \Fluide\dim_h) = x(i, \Fluide\H)
				
			Next
		EndIf
		
		If MODE = 1
			For i = 1 To \Fluide\H
				
				x(0, i) = - x(1, i)
				x(\Fluide\dim_w, i) = - x(\Fluide\W, i)
				
			Next
		Else
			For i = 1 To \Fluide\H
				
				x(0, i) = x(1, i)
				x(\Fluide\dim_w, i) = x(\Fluide\W, i)
				
			Next
		EndIf
		
		; Les coins
		x(0, 0) = 0.5 * (x(1, 0) + x(0, 1))
		x(0, \Fluide\dim_h) = 0.5 * (x(1, \Fluide\dim_h) + x(0, \Fluide\H))
		x(\Fluide\dim_w, 0) = 0.5 * (x(\Fluide\W, 0) + x(\Fluide\dim_w, 1))
		x(\Fluide\dim_w, \Fluide\dim_h) = 0.5 * (x(\Fluide\W, \Fluide\dim_h) + x(\Fluide\dim_w, \Fluide\H))
		
	EndWith
EndProcedure
Procedure FS_SetBoundaryCondition_Libre(*obj.SIM_FL, MODE.l, Array x.d(2))
	With *obj
		
		Protected i
		
		For i = 1 To \Fluide\W
			
			x(i, 0) = x(i, 1)
			x(i, \Fluide\dim_h) = x(i, \Fluide\H)
			
		Next
		
		For i = 1 To \Fluide\H
			
			x(0, i) = x(1, i)
			x(\Fluide\dim_w, i) = x(\Fluide\W, i)
			
		Next
		
		; Les coins
		x(0, 0) = 0.5 * (x(1, 0) + x(0, 1))
		x(0, \Fluide\dim_h) = 0.5 * (x(1, \Fluide\dim_h) + x(0, \Fluide\H))
		x(\Fluide\dim_w, 0) = 0.5 * (x(\Fluide\W, 0) + x(\Fluide\dim_w, 1))
		x(\Fluide\dim_w, \Fluide\dim_h) = 0.5 * (x(\Fluide\W, \Fluide\dim_h) + x(\Fluide\dim_w, \Fluide\H))
		
	EndWith
EndProcedure
Prototype FS_SetBoundaryCondition(*obj.SIM_FL, MODE.l, Array x.d(2))
Global FS_SetBoundaryCondition.FS_SetBoundaryCondition = @FS_SetBoundaryCondition_Boite()
Procedure FS_LinSolve(*obj.SIM_FL, MODE.l, Array x.d(2), Array x0.d(2), a.d, c.d)
	With *obj
		
		Protected.l i, j, k
		
		For k = 0 To 20
			
			For i = 1 To \Fluide\W
				For j = 1 To \Fluide\H
					
					x(i, j) = (x0(i, j) + a * (x(i-1, j) + x(i+1, j) + x(i, j-1) + x(i, j+1))) / c
					
				Next
			Next
			
			FS_SetBoundaryCondition(*obj, MODE, x())
			
		Next
		
	EndWith
EndProcedure
Procedure FS_AddSource(*obj.SIM_FL, Array x.d(2), Array source.d(2))
	With *obj
		
		Protected i, j
		
		
		For i = 0 To \Fluide\dim_w
			For j = 0 To \Fluide\dim_h
				
				x(i, j) = x(i, j) + \dt * source(i, j)
				
			Next
		Next
		
	EndWith
EndProcedure
Procedure FS_Diffusion(*obj.SIM_FL, MODE.l, Array x.d(2), Array x0.d(2), diffusion.d, dt.d)
	With *obj
		
		Protected.d a = dt * diffusion * \Fluide\W * \Fluide\H
		
		FS_LinSolve(*obj, MODE, x(), x0(), a, 1 + 4  * a)
		
	EndWith
EndProcedure
Procedure FS_Advection(*obj.SIM_FL, MODE.l, Array d.d(2), Array d0.d(2), Array u.d(2), Array v.d(2), dt.d)
	With *obj
		
		Protected.l i, j, i0, j0, i1, j1
		Protected.d x, y, s0, t0, s1, t1, dt0_u, dt0_v
		
		; dt0 = dt * N ; mais ici j'ai pris un rectangle et non pas un carré !
		dt0_u = dt * \Fluide\W
		dt0_v = dt * \Fluide\H
		
		
		For i = 1 To \Fluide\W
			For j = 1 To \Fluide\H
				
				x = i - dt0_u * u(i, j)
				y = j - dt0_v * v(i, j)
				
				If x < 0.5 : x = 0.5 : EndIf
				If x > \Fluide\W + 0.5 : x = \Fluide\W + 0.5 : EndIf
				i0 = Round(x, #PB_Round_Down)
				i1 = i0 + 1
				
				If y < 0.5 : y = 0.5 : EndIf
				If y > \Fluide\H + 0.5 : y = \Fluide\H + 0.5 : EndIf
				j0 = Round(y, #PB_Round_Down)
				j1 = j0 + 1
				
				s1 = x - i0
				s0 = 1 - s1
				t1 = y - j0
				t0 = 1 - t1
				
				d(i, j) = s0 * (t0 * d0(i0, j0) + t1 * d0(i0, j1)) + s1 * (t0 * d0(i1, j0) + t1 * d0(i1, j1))
				
			Next
		Next
		
		FS_SetBoundaryCondition(*obj, MODE, d())
		
		
	EndWith
EndProcedure
Procedure FS_Projection(*obj.SIM_FL, Array u.d(2), Array v.d(2), Array p.d(2), Array div.d(2))
	With *obj
		
		Protected.l i, j
		
		For i = 1 To \Fluide\W
			For j = 1 To \Fluide\H
				
				; ici on change le /N qui apparait dans le code original, pour voir comment ça se comporte avec un rectangle
; 				div(i, j) = -0.5 * ((u(i+1, j) - u(i-1, j)) / *obj\Fluide\W + (v(i, j+1) - v(i, j-1)) / *obj\Fluide\H)
				div(i, j) = -0.5 * ((u(i+1, j) - u(i-1, j) + v(i, j+1) - v(i, j-1)) / *obj\Fluide\max_wh)
				
				p(i, j) = 0
			Next
		Next
		
		FS_SetBoundaryCondition(*obj, 0, div())
		FS_SetBoundaryCondition(*obj, 0, p())
		
		
		FS_LinSolve(*obj, 0, p(), div(), 1, 4) ; boom !! prend ça !
		
		
		For i = 1 To \Fluide\W
			For j = 1 To \Fluide\H
				
				u(i, j) = u(i, j) - 0.5 * \Fluide\W * (p(i+1, j) - p(i-1, j))
				v(i, j) = v(i, j) - 0.5 * \Fluide\H * (p(i, j+1) - p(i, j-1))
				
			Next
		Next
		
		FS_SetBoundaryCondition(*obj, 1, u())
		FS_SetBoundaryCondition(*obj, 2, v())
		
	EndWith
EndProcedure
Procedure Fluide_Sim_Densite(*obj.SIM_FL)
	
	FS_AddSource(*obj, *obj\Densite\densite\tab(), *obj\Densite\densite_prec\tab())
	
	Swap *obj\Densite\densite_prec, *obj\Densite\densite
	FS_Diffusion(*obj, 0, *obj\Densite\densite\tab(), *obj\Densite\densite_prec\tab(), *obj\Densite\diffusion, *obj\dt)
	
	Swap *obj\Densite\densite_prec, *obj\Densite\densite
	FS_Advection(*obj, 0, *obj\Densite\densite\tab(), *obj\Densite\densite_prec\tab(), *obj\Fluide\u\tab(), *obj\Fluide\v\tab(), *obj\dt)
	
EndProcedure
Procedure Fluide_Sim_Velocite(*obj.SIM_FL)
	
	FS_AddSource(*obj, *obj\Fluide\u\tab(), *obj\Fluide\u_prec\tab())
	FS_AddSource(*obj, *obj\Fluide\v\tab(), *obj\Fluide\v_prec\tab())
	
	Swap *obj\Fluide\u_prec, *obj\Fluide\u
	Swap *obj\Fluide\v_prec, *obj\Fluide\v
	
	FS_Diffusion(*obj, 1, *obj\Fluide\u\tab(), *obj\Fluide\u_prec\tab(), *obj\Fluide\Viscosite, *obj\dt)
	FS_Diffusion(*obj, 2, *obj\Fluide\v\tab(), *obj\Fluide\v_prec\tab(), *obj\Fluide\Viscosite, *obj\dt)
	
	FS_Projection(*obj, *obj\Fluide\u\tab(), *obj\Fluide\v\tab(), *obj\Fluide\u_prec\tab(), *obj\Fluide\v_prec\tab())
	
	Swap *obj\Fluide\u_prec, *obj\Fluide\u
	Swap *obj\Fluide\v_prec, *obj\Fluide\v
	
	FS_Advection(*obj, 1, *obj\Fluide\u\tab(), *obj\Fluide\u_prec\tab(), *obj\Fluide\u_prec\tab(), *obj\Fluide\v_prec\tab(), *obj\dt)
	FS_Advection(*obj, 2, *obj\Fluide\v\tab(), *obj\Fluide\v_prec\tab(), *obj\Fluide\u_prec\tab(), *obj\Fluide\v_prec\tab(), *obj\dt)
	
	FS_Projection(*obj, *obj\Fluide\u\tab(), *obj\Fluide\v\tab(), *obj\Fluide\u_prec\tab(), *obj\Fluide\v_prec\tab())
	
EndProcedure
;}
Define Var.SIM_FL : InitializeStructure(Var, SIM_FL)
Define souris.POINT, souris_case.POINT, *Obj_sous_souris, Type_sous_souris.l
Define mouse.POINT, mouse_old.POINT
Enumeration 1
	#OBJ_Source_VITESSE
	#OBJ_Source_PARTICULE
EndEnumeration
SIMUL = #True
Macro INIT_SIM
	Fluide_Init(Var\fluide, 100, 100, 0)
	
	Densite_Init(Var\Densite, Var\Fluide, 0.0)
EndMacro
;{ scénario : la chandelle
INIT_SIM
AjouterSource_Flux(Var, Var\Fluide\dim_w >> 1 - 1, Var\Fluide\dim_h - 5, 0, -50)
AjouterSource_Particules(Var, Var\Fluide\dim_w >> 1, Var\Fluide\dim_h - 20, 1800 / 20)
;}
;{ Démo
;{ fenetre
width = 7
width_sur2moins1 = width >> 1 - 1
width_sur2 = width >> 1
width_moins1 = width - 1
draw_info_h = (Var\Fluide\dim_h + 1) * width +1
draw_info_w = (Var\Fluide\dim_w +1) * width +1
DRAW_CASE = #False
DRAW_VITESSE = #True
DRAW_PARTICULES = #True
DRAW_SOURCES = #True
Tps_Loop_mini.d = 0.040 ; s
OpenWindow(0, 0, 0, draw_info_w, draw_info_h + 200, "", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
CanvasGadget(0, 0, 0, WindowWidth(0), WindowHeight(0), #PB_Canvas_Keyboard)
SetActiveGadget(0)
;}
time = ElapsedMilliseconds()
Repeat
	
	FLAG_MOUSE_RIGHT = #False
	FLAG_MOUSE_LEFT = #False
	
	Repeat
		event = WindowEvent()
		
		;{ event
		
		If event = #PB_Event_Gadget And EventGadget() = 0
			
			;{ souris
			
			souris\x = GetGadgetAttribute(0, #PB_Canvas_MouseX)
			souris\y = GetGadgetAttribute(0, #PB_Canvas_MouseY)
			
			souris_case\x = souris\x / width
			souris_case\y = souris\y / width
			
			If souris_case\x < 1 : souris_case\x = 1 : EndIf
			If souris_case\x > Var\Fluide\W : souris_case\x = Var\Fluide\W :EndIf
			If souris_case\y < 1 : souris_case\y = 1 : EndIf
			If souris_case\y > Var\Fluide\H : souris_case\y = Var\Fluide\H :EndIf
			
			;}
			
			
			;{ Touche D
			If GetGadgetAttribute(0, #PB_Canvas_Key) = #PB_Shortcut_D
				
				If *Obj_sous_souris And Type_sous_souris = #OBJ_Source_PARTICULE
					ChangeCurrentElement(var\Source_Particules(), *Obj_sous_souris)
					
					With var\Source_Particules()
						
						x = souris\x - (\Pos\x  * width + width_sur2)
						y = souris\y - (\Pos\y  * width + width_sur2)
						
						\Debit = Sqr(x * x + y * y)
						
					EndWith
					
				ElseIf *Obj_sous_souris And Type_sous_souris = #OBJ_Source_VITESSE
					ChangeCurrentElement(var\Source_Vitesses(), *Obj_sous_souris)
					
					With var\Source_Vitesses()
						
						\dir\x = souris\x - (\Pos\x  * width + width_sur2)
						\dir\y = souris\y - (\Pos\y  * width + width_sur2)
						
						\vitesse = Sqr(\dir\x * \dir\x + \dir\y * \dir\y)
					EndWith
					
				EndIf
				
			EndIf
			;}
			
			;{ Touche E
			If GetGadgetAttribute(0, #PB_Canvas_Key) = #PB_Shortcut_E
				
				If *Obj_sous_souris And Type_sous_souris = #OBJ_Source_PARTICULE
					ChangeCurrentElement(var\Source_Particules(), *Obj_sous_souris)
					
					With var\Source_Particules()
						
						\Pos\x = souris_case\x
						\Pos\y = souris_case\y
						
					EndWith
					
				ElseIf *Obj_sous_souris And Type_sous_souris = #OBJ_Source_VITESSE
					ChangeCurrentElement(var\Source_Vitesses(), *Obj_sous_souris)
					
					With var\Source_Vitesses()
						
						\Pos\x = souris_case\x
						\Pos\y = souris_case\y
						
					EndWith
					
				EndIf
				
			EndIf
			;}
			
			If EventType() = #PB_EventType_KeyUp
				
				;{ Key
				
				If GetGadgetAttribute(0, #PB_Canvas_Key) = #PB_Shortcut_Escape
					event = #PB_Event_CloseWindow
					
				ElseIf GetGadgetAttribute(0, #PB_Canvas_Key) = #PB_Shortcut_C
					
					INIT_SIM
					
				ElseIf GetGadgetAttribute(0, #PB_Canvas_Key) = #PB_Shortcut_Delete
					
					If *Obj_sous_souris And Type_sous_souris = #OBJ_Source_PARTICULE
						ChangeCurrentElement(var\Source_Particules(), *Obj_sous_souris)
						DeleteElement(var\Source_Particules())
						
						*Obj_sous_souris = 0
						Type_sous_souris = 0
						
					ElseIf *Obj_sous_souris And Type_sous_souris = #OBJ_Source_VITESSE
						ChangeCurrentElement(var\Source_Vitesses(), *Obj_sous_souris)
						DeleteElement(var\Source_Vitesses())
						
						*Obj_sous_souris = 0
						Type_sous_souris = 0
						
					EndIf
					
					
				ElseIf GetGadgetAttribute(0, #PB_Canvas_Key) = #PB_Shortcut_X
					
					; ajouter ici les autres conditions si besoin
					If FS_SetBoundaryCondition = @FS_SetBoundaryCondition_Boite()
						FS_SetBoundaryCondition = @FS_SetBoundaryCondition_Libre()
					ElseIf FS_SetBoundaryCondition = @FS_SetBoundaryCondition_Libre()
						FS_SetBoundaryCondition = @FS_SetBoundaryCondition_Boite()
					EndIf
					
				ElseIf GetGadgetAttribute(0, #PB_Canvas_Key) = #PB_Shortcut_V
					
					If DRAW_VITESSE : DRAW_VITESSE = #False
					Else : DRAW_VITESSE = #True
					EndIf
					
				ElseIf GetGadgetAttribute(0, #PB_Canvas_Key) = #PB_Shortcut_G
					
					If DRAW_CASE : DRAW_CASE = #False
					Else : DRAW_CASE = #True
					EndIf
					
				ElseIf GetGadgetAttribute(0, #PB_Canvas_Key) = #PB_Shortcut_P
					
					If DRAW_PARTICULES : DRAW_PARTICULES = #False
					Else : DRAW_PARTICULES = #True
					EndIf
					
				ElseIf GetGadgetAttribute(0, #PB_Canvas_Key) = #PB_Shortcut_S
					
					If DRAW_SOURCES : DRAW_SOURCES = #False
					Else : DRAW_SOURCES = #True
					EndIf
					
				ElseIf GetGadgetAttribute(0, #PB_Canvas_Key) = #PB_Shortcut_Space
					
					If SIMUL = #True : SIMUL = #False
					Else : SIMUL = #True
					EndIf
					
				ElseIf GetGadgetAttribute(0, #PB_Canvas_Key) = #PB_Shortcut_N
					
					If EDIT = #True : EDIT = #False
					Else : EDIT = #True
					EndIf
					
				EndIf
				
				;}
				
			ElseIf EventType() = #PB_EventType_LeftButtonUp
				;{ Ajout source permanente de vitesse
				
				
				;{ détection d'objet sous la souris
				
				*Obj_sous_souris = 0
				Type_sous_souris = 0
				
				; vitesse
				ForEach var\Source_Vitesses()
					With var\Source_Vitesses()
						
						If \Pos\x = souris_case\x And \Pos\y = souris_case\y
							*Obj_sous_souris = Var\Source_Vitesses()
							
							Type_sous_souris = #OBJ_Source_VITESSE
						EndIf
						
					EndWith
				Next
				
				; particules
				ForEach var\Source_Particules()
					With var\Source_Particules()
						
						If \Pos\x = souris_case\x And \Pos\y = souris_case\y
							*Obj_sous_souris = Var\Source_Particules()
							
							Type_sous_souris = #OBJ_Source_PARTICULE
						EndIf
						
					EndWith
				Next
				
				;}
				
				
				If EDIT And *Obj_sous_souris = 0
					*Obj_sous_souris = AjouterSource_Flux(Var, souris_case\x, souris_case\y, 20, 0)
					Type_sous_souris = #OBJ_Source_VITESSE
				EndIf
				
				;}
				
			ElseIf EventType() = #PB_EventType_RightButtonUp
				;{ Ajout source permanente de particules
				
				If EDIT
					*Obj_sous_souris = AjouterSource_Particules(Var, souris_case\x, souris_case\y, 10)
					Type_sous_souris = #OBJ_Source_PARTICULE
				EndIf
				
				;}
				
			EndIf
			
			;{ AJOUT à la souris
			If EDIT = #False
				If GetGadgetAttribute(0, #PB_Canvas_Buttons) & #PB_Canvas_RightButton = #PB_Canvas_RightButton
					FLAG_MOUSE_RIGHT = #True
				EndIf
				If GetGadgetAttribute(0, #PB_Canvas_Buttons) & #PB_Canvas_LeftButton = #PB_Canvas_LeftButton
					FLAG_MOUSE_LEFT = #True
				Else
					REINIT = #True
					
				EndIf
			EndIf
			;}
			
		EndIf
		;}
		
	Until event = 0 Or event = #PB_Event_CloseWindow
	
	
	;{ mise à jour du delta de temps et stabilisation des FPS
	
	Var\dt = (ElapsedMilliseconds() - time) / 1000
	
	If var\dt < Tps_Loop_mini
		Delay(1000 * (Tps_Loop_mini - Var\dt))
	EndIf
	
	Var\dt = (ElapsedMilliseconds() - time) / 1000 ; on reprend le temps total de la boucle, delay compris
	time = ElapsedMilliseconds()
	
	;}
	
	
	;{ SIMULATION
	
	If SIMUL
		
		tps = ElapsedMilliseconds()
		
		; reset des anciens tableaux
		Dim Var\Densite\densite_prec\tab(Var\Fluide\dim_w, Var\Fluide\dim_h)
		Dim Var\Fluide\u_prec\tab(Var\Fluide\dim_w, Var\Fluide\dim_h)
		Dim Var\Fluide\v_prec\tab(Var\Fluide\dim_w, Var\Fluide\dim_h)
		
		If EDIT = #False
			
			;{ ajout a la souris de particules
			If FLAG_MOUSE_RIGHT
				var\Densite\densite_prec\tab(souris_case\x, souris_case\y) = 10000 * Var\dt
			EndIf	
			;}
			
			;{ ajout a la souris de vitesse
			If FLAG_MOUSE_LEFT
				If REINIT
					REINIT = #False
					
					mouse_old = souris
				EndIf
				
				mouse\x = (souris\x - mouse_old\x) * 50
				mouse\y = (souris\y - mouse_old\y) * 50
				
				mouse_old = souris
				
				var\Fluide\u_prec\tab(souris_case\x, souris_case\y) = mouse\x
				var\Fluide\v_prec\tab(souris_case\x, souris_case\y) = mouse\y
			EndIf	
			;}
			
			;{ Ajout des sources de particules
			
			ForEach Var\Source_Particules()
				With var\Source_Particules()
					var\Densite\densite_prec\tab(\Pos\x, \Pos\y) = 20*\Debit * Var\dt
				EndWith
			Next
			
			;}
			
			;{ Ajout des sources de vitesse
			
			ForEach Var\Source_Vitesses()
				With var\Source_Vitesses()
					var\Fluide\u_prec\tab(\Pos\x, \Pos\y) = \dir\x
					var\Fluide\v_prec\tab(\Pos\x, \Pos\y) = \dir\y
				EndWith
			Next
			
			;}
			
		EndIf
		
		;For i = 1 To 10
		; Simulation
		Fluide_Sim_Velocite(Var)
		Fluide_Sim_Densite(Var)
		;Next
		
		tps = ElapsedMilliseconds() - tps
		
	EndIf
	
	
	;}
	
	
	;{ Affichage
	
	If StartDrawing(CanvasOutput(0))
		
		Box(0, 0, OutputWidth(), OutputHeight(), 0)
		
		;{ particules / Grille / vitesse
		If DRAW_PARTICULES
			; dessin de la densité
			
			NB_particules.d = 0
			
			For i = 0 To Var\Fluide\dim_w
				For j = 0 To Var\Fluide\dim_h
					x = i * width + width >> 1
					y = j * width + width >> 1
					
					c.d = 255*(Var\Densite\densite\tab(i, j))
					
					NB_particules + Var\Densite\densite\tab(i, j)
					
					If c > 255 : c = 255 : EndIf
					
; 					Box(x - width_sur2moins1, y - width_sur2moins1, width_moins1, width_moins1, RGB(c, c, c))
					Box(x - width_sur2moins1, y - width_sur2moins1, width, width, RGB(c, c, c))
				Next
			Next
		EndIf
		
		If DRAW_CASE
			; grille
			For i = 0 To Var\Fluide\dim_w +1
				Line(i * width, 0, 1, draw_info_h, $003F00)
			Next
			For i = 0 To Var\Fluide\dim_h +1
				Line(0, i * width, draw_info_w, 1, $003F00)
			Next
		EndIf
		
		
		If DRAW_VITESSE
			; dessin des vecteur vitesse
			
			For i = 0 To Var\Fluide\dim_w
				For j = 0 To Var\Fluide\dim_h
					x = i * width + width >> 1
					y = j * width + width >> 1
					
					LineXY(x, y, x + Var\Fluide\u\tab(i, j) * 10, y + Var\Fluide\v\tab(i, j) * 10, #Red)
				Next
			Next
		EndIf
		;}
		
		;{ sources
		If DRAW_SOURCES Or EDIT
			
			; vitesse
			ForEach var\Source_Vitesses()
				With var\Source_Vitesses()
					x = \Pos\x  * width + width_sur2
					y = \Pos\y * width + width_sur2
					
					Circle(x, y, width_sur2, $007AFF)
					
					If *Obj_sous_souris = Var\Source_Vitesses()
						DrawingMode(#PB_2DDrawing_Outlined)
						
						Circle(x, y, width_sur2 + 3, #Blue)
						Circle(x, y, width_sur2 + 2, #Blue)
						
						DrawingMode(#PB_2DDrawing_Default)
					EndIf
					
					
					LineXY(x, y, x + \dir\x, y + \dir\y, #Green)
				EndWith
			Next
			
			
			; particules
			ForEach var\Source_Particules()
				With var\Source_Particules()
					x = \Pos\x  * width + width_sur2
					y = \Pos\y * width + width_sur2
					
					Circle(x, y, width_sur2, #White)
					
					If *Obj_sous_souris = Var\Source_Particules()
						DrawingMode(#PB_2DDrawing_Outlined)
						
						Circle(x, y, width_sur2 + 3, #Blue)
						Circle(x, y, width_sur2 + 2, #Blue)
						
						DrawingMode(#PB_2DDrawing_Default)
					EndIf
					
					DrawingMode(#PB_2DDrawing_Outlined)
					
					Circle(x, y, \Debit, $007AFF)
					
					DrawingMode(#PB_2DDrawing_Default)
					
				EndWith
			Next
			
		EndIf
		;}
		
		;{ INFO
		
		
		If EDIT
			Circle(souris_case\x  * width + width_sur2, souris_case\y * width + width_sur2, width_sur2, #Blue)
		EndIf
		
		; info
		
		If SIMUL
			DrawText(10, draw_info_h + 5, "Simulation : En cours", #White, 0)
		Else
			DrawText(10, draw_info_h + 5, "Simulation : En pause", #White, 0)
		EndIf
		
		If EDIT
			DrawText(200, draw_info_h + 5, "EDITION des SOURCES", #White, 0)
		Else
			; DrawText(200, draw_info_h + 5, "", #White, 0)
		EndIf
		
		DrawText(10, draw_info_h + 25, "dt = " + StrD(Var\dt, 3), #White, 0)
		DrawText(100, draw_info_h + 25, "NB_part = " + StrD(NB_particules, 3), #White, 0)
		
		DrawText(10, draw_info_h + 50, "[Souris Gauche] ajouter du flux", #White, 0)
		DrawText(10, draw_info_h + 70, "[Souris Droite] ajouter des particules", #White, 0)
		DrawText(10, draw_info_h + 90, "[N] MODE Sources permanentes", #White, 0)
		DrawText(10, draw_info_h + 110, "[Clic sur source] Selectionne une source", #White, 0)
		DrawText(10, draw_info_h + 130, "[SUPPR] Supprime une source", #White, 0)
		DrawText(10, draw_info_h + 150, "[D] Modifier le niveau des sources", #White, 0)
		DrawText(10, draw_info_h + 170, "[E] Déplacer une sources", #White, 0)
		
		DrawText(280, draw_info_h + 30, "[C] réinitialiser", #White, 0)
		DrawText(280, draw_info_h + 50, "[ESPACE] pause", #White, 0)
		DrawText(280, draw_info_h + 70, "[ECHAP] quitter", #White, 0)
		
		DrawText(280, draw_info_h + 90, "[G] Affiche la grille", #White, 0)
		DrawText(280, draw_info_h + 110, "[P] Affiche les particules", #White, 0)
		DrawText(280, draw_info_h + 130, "[V] Affiche les vecteurs vitesse", #White, 0)
		DrawText(280, draw_info_h + 130, "[S] Affiche les Sources", #White, 0)
		DrawText(280, draw_info_h + 150, "[X] Change les conditions aux limites", #White, 0)
		
		DrawText(500, draw_info_h + 10, "INFO Object", #White, 0)
		
		If *Obj_sous_souris
			If Type_sous_souris = #OBJ_Source_PARTICULE
				DrawText(500, draw_info_h + 35, "Type : Source de Particule", #White, 0)
				
				ChangeCurrentElement(var\Source_Particules(), *Obj_sous_souris)
				DrawText(500, draw_info_h + 55, "Débit : " + StrD(var\Source_Particules()\Debit * 20, 3), #White, 0)
				
			Else
				DrawText(500, draw_info_h + 35, "Type : Source de Flux", #White, 0)
				
				ChangeCurrentElement(var\Source_Vitesses(), *Obj_sous_souris)
				DrawText(500, draw_info_h + 55, "Vitesse : " + StrD(var\Source_Vitesses()\vitesse, 3), #White, 0)
			EndIf
		Else
			DrawText(500, draw_info_h + 30, "Pas de sélection", #White, 0)
		EndIf
		
		If FS_SetBoundaryCondition = @FS_SetBoundaryCondition_Boite()
			DrawText(500, draw_info_h + 80, "Condition Limite : Boite", #White, 0)
		ElseIf FS_SetBoundaryCondition = @FS_SetBoundaryCondition_Libre()
			DrawText(500, draw_info_h + 80, "Condition Limite : Libre", #White, 0)
		EndIf
		
		
		;}
		
		StopDrawing()
	EndIf
	
	;}
	
Until event = #PB_Event_CloseWindow
;}
End

 )
)




 
  
 
   (sources de vitesse / particules)
  (sources de vitesse / particules) 
 

