Fluid Dynamics

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
cxAlex
Beiträge: 2111
Registriert: 26.06.2008 10:42

Re: Fluid Dynamics

Beitrag von cxAlex »

Hier dasselbe. Ohne OpenGL Subsystem 3-5 FPS, mit OpenGL 60-75 FPS. Der Sprite Code schafft bei mir ~60-70 FPS. PB 4.6b3, Win7 x64, GeForce GTX 260m

Gruß, Alex
Projekte: IO.pbi, vcpu
Pausierte Projekte: Easy Network Manager, µC Emulator
Aufgegebene Projekte: ECluster

Bild

PB 5.1 x64/x86; OS: Win7 x64/Ubuntu 10.x x86
Sirius-2337
Beiträge: 71
Registriert: 29.05.2010 20:55

Re: Fluid Dynamics

Beitrag von Sirius-2337 »

Habs noch mal mit OpenGL getestet. Da hab ich auch 45 - 50 FPS (Win7 x64, PB4.6b3 x86, GeForce 8600M GS).
Mr.L
Beiträge: 51
Registriert: 05.02.2011 21:04

Re: Fluid Dynamics

Beitrag von Mr.L »

Ich komme mit meinem schlappen Rechner nicht über 25 FPS.
Aber ich habe vor längerer Zeit ein ähnliches Programm geschrieben mit dem ich auf über 60 FPS komme (dank OpenGL).
Läuft wahrscheinlich nur unter Windows.

Code: Alles auswählen

; REALTIME FLUID (OpenGL)
; as described in "Real-Time Fluid Dynamics for Games" by Jos Stam
; press mousebutton & move mouse

EnableExplicit

#GRW									= 500
#GRH									= 500
#SIZE									= 5
#GRX									= (#GRW / #SIZE)
#GRY									= (#GRH / #SIZE)

#PRECISION						= 10
#FLOWSPEED						= 0.1

#GL_TRIANGLE_STRIP		= $0005
#GL_MODELVIEW					= $1700
#GL_PROJECTION				= $1701
#GL_SMOOTH						= $1D01

Global Dim VelX1.f(#GRX , #GRY) , Dim VelX2.f(#GRX , #GRY)
Global Dim VelY1.f(#GRX , #GRY) , Dim VelY2.f(#GRX , #GRY)
Global Dim cRed1.f(#GRX , #GRY) , Dim cRed2.f(#GRX , #GRY)
Global Dim cGrn1.f(#GRX , #GRY) , Dim cGrn2.f(#GRX , #GRY)
Global Dim cBlu1.f(#GRX , #GRY) , Dim cBlu2.f(#GRX , #GRY)

Define glContext , hdc
Define lButton,xo,yo,x,y,sx,sy,color,fps,fpt

Procedure InitOpenGL(hdc)
  Protected pfd.PIXELFORMATDESCRIPTOR
  Protected glContext
  Protected Dim glFloat.f(4)
  
  pfd\nSize        = SizeOf(PIXELFORMATDESCRIPTOR)
  pfd\nVersion     = 1
  pfd\dwFlags      = #PFD_SUPPORT_OPENGL | #PFD_DOUBLEBUFFER | #PFD_DRAW_TO_WINDOW
  pfd\dwLayerMask  = #PFD_MAIN_PLANE
  pfd\iPixelType   = #PFD_TYPE_RGBA
  pfd\cColorBits   = 16
  pfd\cDepthBits   = 16
  
  SetPixelFormat_(hdc , ChoosePixelFormat_(hdc, pfd) , pfd)
  glContext = wglCreateContext_(hdc)
  If glContext
    wglMakeCurrent_(hdc , glContext)
    glMatrixMode_(#GL_PROJECTION)
    glLoadIdentity_()
    glMatrixMode_ (#GL_MODELVIEW)
    glTranslatef_(-1.0, 1.0, -1.0)
    glScalef_(2.0/(#GRX-1),-2.0/(#GRY-1),0.0)  
    glShadeModel_ (#GL_SMOOTH)
  EndIf
  
  ProcedureReturn glContext
EndProcedure

Procedure AddVelocity(x , y , vx.f , vy.f , radius)
  Protected xa,ya,xx,yy
  For ya = -radius To radius
    For xa = -radius To radius
      xx = x + xa
      yy = y + ya
      If xx > 0 And xx < #GRX - 1 And yy > 0 And yy < #GRY - 1
        If (xa*xa+ya*ya) <= (radius * radius)
          VelX1(xx , yy) + vx
          VelY1(xx , yy) + vy
        EndIf
      EndIf
    Next
  Next	
EndProcedure

Procedure AddColor(x , y , r.f , g.f , b.f , radius)
  Protected xa,ya,xx,yy
  For ya = -radius To radius
    For xa = -radius To radius
      xx = x + xa
      yy = y + ya
      If xx > 0 And xx < #GRX - 1 And yy > 0 And yy < #GRY - 1
        If (xa*xa+ya*ya) <= (radius * radius)
          cRed1(xx , yy) = r
          cGrn1(xx , yy) = g
          cBlu1(xx , yy) = b
        EndIf
      EndIf
    Next
  Next		
EndProcedure

Procedure TestBounds(Array vx1.f(2) , Array vy1.f(2) , Array vx2.f(2) , Array vy2.f(2))
  Protected x,y
  For x = 1 To #GRX-2
    vy1(x , 0       ) = -vy2(x , 1       )
    vy1(x , #GRY - 1) = -vy2(x , #GRY - 2)
  Next
  For y = 1 To #GRY-2
    vx1(0        , y) = -vx2(1        , y)
    vx1(#GRX - 1 , y) = -vx2(#GRX - 2 , y)
  Next
  ;  	vx(0 , 0) = 0.5 * (vx(1, 0) + vx(0, 1))
  ;  	vy(0 , 0) = 0.5 * (vy(1, 0) + vy(0, 1))
  ;  	vx(#GRX - 1 , 0) = 0.5 * (vx(#GRX - 2, 0) + vx(#GRX - 1, 1))
  ;  	vy(#GRX - 1 , 0) = 0.5 * (vy(#GRX - 2, 0) + vy(#GRX - 1, 1))
  ;  	vx(#GRX - 1 , #GRY - 1) = 0.5 * (vx(#GRX - 2, #GRY - 1) + vx(#GRX - 1, #GRY - 2))
  ;  	vy(#GRX - 1 , #GRY - 1) = 0.5 * (vy(#GRX - 2, #GRY - 1) + vy(#GRX - 1, #GRY - 2))
  ;  	vx(0 , #GRY - 1) = 0.5 * (vx(1, #GRY - 1) + vx(0, #GRY - 2))
  ;  	vy(0 , #GRY - 1) = 0.5 * (vy(1, #GRY - 1) + vy(0, #GRY - 2))
  
EndProcedure

Procedure Update()
  Protected.l	h			= (#GRX * #GRY) , x,y,x0,y0,x1,y1,p
  Protected.f	hh		= 1.0 / h , a
  Protected.f	speed	= h * #FLOWSPEED
  Protected.f	xx , yy , s0 , s1 , t0 , t1
  
  ; Advect
  For y = 0 To #GRY - 1
    For x = 0 To #GRX - 1
      xx = x - speed * VelX2(x , y)	
      yy = y - speed * VelY2(x , y)
      
      If xx < 0 : xx = 0 : ElseIf xx > #GRX-1 : xx = #GRX-1 : EndIf
      If yy < 0 : yy = 0 : ElseIf yy > #GRY-1 : yy = #GRY-1 : EndIf
      
      x0 = Int(xx) : x1 = x0 + 1
      y0 = Int(yy) : y1 = y0 + 1
      
      s1 = xx - x0 : s0 = 1.0 - s1
      t1 = yy - y0 : t0 = 1.0 - t1
      
      VelX2(x , y) = s0 * (t0 * VelX1(x0 , y0) + t1 * VelX1(x0 , y1)) + s1 * (t0 * VelX1(x1 , y0) + t1 * VelX1(x1 , y1))
      VelY2(x , y) = s0 * (t0 * VelY1(x0 , y0) + t1 * VelY1(x0 , y1)) + s1 * (t0 * VelY1(x1 , y0) + t1 * VelY1(x1 , y1))
      
      cRed2(x , y) = s0 * (t0 * cRed1(x0 , y0) + t1 * cRed1(x0 , y1)) + s1 * (t0 * cRed1(x1 , y0) + t1 * cRed1(x1 , y1))
      cGrn2(x , y) = s0 * (t0 * cGrn1(x0 , y0) + t1 * cGrn1(x0 , y1)) + s1 * (t0 * cGrn1(x1 , y0) + t1 * cGrn1(x1 , y1))
      cBlu2(x , y) = s0 * (t0 * cBlu1(x0 , y0) + t1 * cBlu1(x0 , y1)) + s1 * (t0 * cBlu1(x1 , y0) + t1 * cBlu1(x1 , y1))
    Next
  Next
  
  ; Project
  a = -0.5 * h
  For y = 1 To #GRY - 2
    For x = 1 To #GRX - 2
      VelY1(x , y) =  a * (VelX2(x + 1 , y) - VelX2(x - 1 , y) + VelY2(x , y + 1) - VelY2(x , y - 1))
      VelX1(x , y) = 0
    Next
  Next
  For p = 1 To #PRECISION
    For y = 1 To #GRY - 2
      For x = 1 To #GRX - 2
        VelX1(x , y) = (VelY1(x , y) + VelX1(x - 1 , y) + VelX1(x + 1 , y) + VelX1(x , y - 1) + VelX1(x , y + 1)) * 0.25
      Next
    Next		
  Next
  a = 0.5 * hh
  For y = 1 To #GRY - 2
    For x = 1 To #GRX - 2
      VelX2(x , y) - (VelX1(x + 1 , y) - VelX1(x - 1 , y)) * hh
      VelY2(x , y) - (Velx1(x , y + 1) - VelX1(x , y - 1)) * hh
    Next
  Next
  
  ; Diffuse
  For y = 1 To #GRY - 2
    For x = 1 To #GRX - 2
      VelX1(x , y) = (VelX2(x , y) + VelX2(x - 1 , y) + VelX2(x + 1 , y) + VelX2(x , y - 1) + VelX2(x , y + 1)) * 0.2
      VelY1(x , y) = (VelY2(x , y) + VelY2(x - 1 , y) + VelY2(x + 1 , y) + VelY2(x , y - 1) + VelY2(x , y + 1)) * 0.2
    Next
  Next	
  TestBounds(VelX1() , VelY1() , VelX2() , VelY2())
  
  
  Swap cRed1(),cRed2()
  Swap cGrn1(),cGrn2()
  Swap cBlu1(),cBlu2()
EndProcedure

Procedure DrawMesh(hdc)
  Protected x,y,x1,y1
  For y = 0 To #GRY - 2
    glBegin_(#GL_TRIANGLE_STRIP)
    y1 = y + 1
    For x = 0 To #GRX - 1
      glColor3f_(cRed1(x ,y ),cGrn1(x ,y ),cBlu1(x ,y ))
      glVertex3i_(x  ,y , 0)			
      glColor3f_(cRed1(x ,y1),cGrn1(x ,y1),cBlu1(x ,y1))
      glVertex3i_(x  ,y1, 0)
    Next	
    glEnd_()
  Next
  SwapBuffers_(hdc)	
EndProcedure

If OpenWindow(0, 0, 0, #GRW, #GRH, "Fluid" , #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
  hdc				= GetDC_(WindowID(0))
  glContext = InitOpenGL(hdc)	
  If glContext
    Repeat			
      Select WindowEvent()
        Case #PB_Event_CloseWindow
          wglDeleteContext_(glContext)
          End
        Case #WM_LBUTTONDOWN	: lButton = 1
          color = RGB(Random(255) , Random(255) , Random(255))
        Case #WM_LBUTTONUP		: lButton = 0
        Case #WM_MOUSEMOVE
          x =  WindowMouseX(0) / #SIZE
          y =  WindowMouseY(0) / #SIZE
          sx = (x - xo)
          sy = (y - yo)
          xo=x
          yo=y
          If lButton
            AddVelocity(x , y , sx * 0.001 , sy * 0.001 , 3)
          EndIf
      EndSelect
      
      AddColor		(#GRX/2 , #GRY-2 , 0.6,0.7,0.9 , 3)
      AddVelocity	(#GRX/2 , #GRY-2 , 0 , -0.002 , 3)
      
      If lButton
        AddColor (x , y , Red(color) / 255.0 ,Green(color) / 255.0 , Blue(color) / 255.0 , 3)
      EndIf
      
      Update()
      DrawMesh(hdc)
      
      fps + 1
      If ElapsedMilliseconds() > fpt
        SetWindowTitle(0,Str(fps) + " fps  -  press mousebutton & move mouse")
        fps = 0
        fpt = ElapsedMilliseconds() + 1000
      EndIf
      
    ForEver
  Else
    MessageRequester("Error" , "no OpenGL")
  EndIf
EndIf
[/size]
Benutzeravatar
PureLust
Beiträge: 1145
Registriert: 21.07.2005 00:02
Computerausstattung: Hab aktuell im Grunde nur noch 'nen Lenovo Yoga 2 Pro im Einsatz.
Wohnort: am schönen Niederrhein

Re: Fluid Dynamics

Beitrag von PureLust »

Hab mir das Teilchen auch nochmal zur Brust genommen
und sowohl nochmals ein wenig an der Geschwindigkeitsschraube gedreht
als auch die Funktionen und die GUI ein wenig aufgebohrt.
(So kann man nun z.B. die Maus releasen um z.B. das Fenster zu verschieben oder zu schließen.)

Einen interessanten Effekt finde ich z.B. die Stepmotion-Funktion bei gedrückter Pause-Taste (Space).

Mit DX9-Subsystem komme ich jetzt bei mir auf 80-90 FPS (statt ~35 FPS in der vorherigen Version).
Mit DX7-Subsystem funnz es nun, jedoch wird die Framerate scheinbar auf 60 Hz begrenzt (trotz #PB_Screen_NoSynchronization). /:->
Unter OpenGL komme ich zwar auch auf 80-80 FPS, allerdings scheint der AutoStretch des Screens
nicht zu funktionieren, so dass hier nur 1/5tel des Screens genutzt wird. :freak:

An sich sollte es nun auch unter OSX und Linux funktionieren.
Auf Grund der Probleme beim OpenGL-Subsystem unter Windows bin ich mir da aber nicht ganz sicher wie sich die Screen-Befehle unter Linux und OS-X verhalten.
Wäre nett, wenn das vielleicht noch jemand testen könnte.

[Edit:] Hab den Code nochmals so angepasst, dass er nun auch die Probleme mit dem OpenGL-Subsystem ausgleichen sollte.
(Momentan getestet unter WinXP, mit PB 4.51, SubSysteme: DX9, DX7, OpenGL)


Code: Alles auswählen

; Program: Fluid Dynamics

; Author: (the great) remi_meier (1st changes by 'pphjs', final GUI improvements and speed-up by 'PureLust')
; Date: 25. February 2007 - last changes: 04.07.2011
; OS: Windows (should work on other OS as well)
; Demo: No
; German forum: http://www.purebasic.fr/german/viewtopic.php?t=9894&start=20

EnableExplicit 
DisableDebugger

#N = 100                     ; Anzahl der Gitterpunkte, die berechnet werden 
#DSTEP = 1;5                   ; Pixel per Gitterpunkt in der Darstellung 
#Zoom  = 5
#SIZE = (#N + 2) * (#N + 2) 
#MouseSpeed = 5              ; Geschwindigkeit der Mausbewegung (je kleiner, desto schneller)
#Stream     = 10             ; Stärke der Strömung unten rechts
#LineHeight1 = 20
#xGui		= #N * #Zoom
#xPos1	= 10
#xPos2	= 25
Define GuiWidth = 230

Define YPos=278, LH=15, LS=7  ; Variablen für Gadget Anordnung
Define n
Global pause
Global plot.l = 0           ; 0 - zeichnet Dichtefeld, sonst Geschwindigkeitsfeld 
Global dense.f=0.18, grav.f=0.31     ;dense - Diche des Anfangsfeldes und am Rand, grav - Gravitationskonstante 
Global visc.f = 0.0001, dt.f = 0.01, diff.f = 0.00018   ; visc - (turbulente) Vikosität 
Global xdense.f = 1/dense                                 ; dt   - Zeitschritt 
Global Viscosity = 5         ; (Originalwert = 19)      ; diff - (turbulente) Diffusionskonstante 
Global DensityChange.f = 4.2
Global im.l, jm.l            ; aktuelle Mouse-Position
Global StreamActive = #True
Global MouseCatched = #True

Structure FArray                                      
	f.f[0] 
EndStructure 


Macro IX(i, j) 
	(i) + (n + 2) * (j) 
EndMacro 

Declare set_bnd(n.l, b.l, *x.FArray) 
Declare project(n.l, *u.FArray, *v.FArray, *p.FArray, *div.FArray) 

Procedure add_source_gravity(n.l, *x.FArray, *s.FArray, *d.FArray, dt.f) 
	Define.l i, j 
	
	For i = 0 To n+1 
		For j = 0 To n+1 
			*x\f[IX(i, j)] + dt* (*s\f[IX(i, j)] - grav * (dense-*d\f[IX(i, j)])*xdense) 
		Next 
	Next 
EndProcedure 

Procedure add_source(n.l, *x.FArray, *s.FArray, dt.f) 
	Define.l i, Size = (n + 2) * (n + 2) 
	
	For i = 0 To Size - 1 
		*x\f[i] + dt * *s\f[i] 
	Next 
EndProcedure 

Procedure diffuse(n.l, b.l, *x.FArray, *x0.FArray, diff.f, dt.f) 
	Define.l i, j, k 
	Define.f a,xa
	a = dt * diff * n * n 
	xa = 1 / (1.0 + 4.0 * a)
	
	For k = 0 To Viscosity 
		For i = 1 To n 
			For j = 1 To n 
				*x\f[IX(i, j)] = (*x0\f[IX(i, j)] + a * (*x\f[IX(i-1, j)] + *x\f[IX(i+1, j)] + *x\f[IX(i, j-1)] + *x\f[IX(i, j+1)])) * xa 
				;        *x\f[IX(i, j)] = (*x0\f[IX(i, j)] + a * (*x\f[IX(i-1, j)] + *x\f[IX(i+1, j)] + *x\f[IX(i, j-1)] + *x\f[IX(i, j+1)])) / (1.0 + 4.0 * a) 
				;        *x\f[IX(i, j)] = *x0\f[IX(i, j)] + a * (*x0\f[IX(i-1, j)] + *x0\f[IX(i+1, j)] + *x0\f[IX(i, j-1)] + *x0\f[IX(i, j+1)] - 4 * *x0\f[IX(i, j)]) 
			Next 
		Next 
		set_bnd(n, b, *x) 
	Next 
EndProcedure 

Procedure advect (n.l, b.l, *d.FArray, *d0.FArray, *u.FArray, *v.FArray, dt.f) 
	Define.l i, j, i0, j0, i1, j1 
	Define.f x, y, s0, t0, s1, t1, dt0 
	dt0 = dt * n 
	
	For i = 1 To n 
		For j = 1 To n 
			x = i - dt0 * *u\f[IX(i, j)] 
			y = j - dt0 * *v\f[IX(i, j)] 
			
			If (x < 0.5) 
				x = 0.5 
			ElseIf (x > n + 0.5) 
				x = n + 0.5 
			EndIf 
			i0 = Int(x) 
			i1 = i0 + 1 
			
			If (y < 0.5) 
				y = 0.5  
			ElseIf (y > n + 0.5) 
				y = n + 0.5 
			EndIf 
			j0 = Int(y) 
			j1 = j0 + 1 
			
			s1 = x - i0 : s0 = 1 - s1 : t1 = y - j0 : t0 = 1 - t1 
			*d\f[IX(i, j)] = s0 * (t0 * *d0\f[IX(i0, j0)] + t1 * *d0\f[IX(i0, j1)]) + s1 * (t0 * *d0\f[IX(i1, j0)] + t1 * *d0\f[IX(i1, j1)]) 
			
		Next 
	Next 
	set_bnd(n, b, *d) 
EndProcedure 

Procedure dens_step(n.l, *x.FArray, *x0.FArray, *u.FArray, *v.FArray, diff.f, dt.f) 
	add_source(n, *x, *x0, dt) 
	diffuse(n, 0, *x0, *x, diff, dt ) 
	advect(n, 0, *x, *x0, *u, *v, dt ) 
EndProcedure 

Procedure vel_step(n.l, *u.FArray, *v.FArray, *u0.FArray, *v0.FArray, *d.FArray, visc.f, dt.f) 
	add_source(n, *u, *u0, dt) : add_source_gravity(n, *v, *v0, *d, dt); add_source(n, *v, *v0, dt) 
	diffuse(n, 1, *u0, *u, visc, dt) 
	diffuse(n, 2, *v0, *v, visc, dt) 
	project(n, *u0, *v0, *u, *v) 
	
	advect(n, 1, *u, *u0, *u0, *v0, dt) : advect(n, 2, *v, *v0, *u0, *v0, dt) 
	project(n, *u, *v, *u0, *v0) 
EndProcedure 

Procedure project(n.l, *u.FArray, *v.FArray, *p.FArray, *div.FArray) 
	Define.l i, j, k 
	Define.f h = 1.0 / n
	Define.f xh = 1/h
	Define.f hh = -0.5 * h
	
	For i = 1 To n 
		For j = 1 To n 
			*div\f[IX(i, j)] = hh * (*u\f[IX(i+1, j)] - *u\f[IX(i-1, j)] + *v\f[IX(i, j+1)] - *v\f[IX(i, j-1)]) 
			*p\f[IX(i, j)] = 0 
		Next 
	Next 
	set_bnd(n, 3, *div) : set_bnd(n, 3, *p) 
	
	For k = 0 To Viscosity 
		For i = 1 To n 
			For j = 1 To n 
				*p\f[IX(i, j)] = (*div\f[IX(i, j)] + *p\f[IX(i-1, j)] + *p\f[IX(i+1, j)] + *p\f[IX(i, j-1)] + *p\f[IX(i, j+1)]) * 0.25 
			Next 
		Next 
		set_bnd(n, 3, *p) 
	Next 
	
	For i = 1 To n 
		For j = 1 To n 
			*u\f[IX(i, j)] - (0.5 * (*p\f[IX(i+1, j)] - *p\f[IX(i-1, j)]) * xh) 
			*v\f[IX(i, j)] - (0.5 * (*p\f[IX(i, j+1)] - *p\f[IX(i, j-1)]) * xh) 
		Next 
	Next 
	set_bnd(n, 1, *u) : set_bnd(n, 2, *v) 
EndProcedure 

Procedure set_bnd(n.l, b.l, *x.FArray) 
	Define.l i 
	
	Select b 
			
		Case 0      ; Dichte Rand 
			For i = 0 To n+1 
				*x\f[IX(0,   i)] = dense 
				*x\f[IX(n+1, i)] = dense 
				*x\f[IX(i,   0)] = dense 
				*x\f[IX(i, n+1)] = dense 
			Next      
			
		Case 1      ; Ost- bzw. Westrand, fester Rand u=0 
			For i = 0 To n+1 
				*x\f[IX(0,   i)] = 0.0 
				*x\f[IX(n+1, i)] = 0.0 
			Next      
			
		Case 2      ; Nord- bzw. Suedrand, fester Rand v=0 
			For i = 0 To n+1 
				*x\f[IX(i,   0)] = 0.0 
				*x\f[IX(i, n+1)] = 0.0 
			Next      
			
		Case 3      ; Raender fuer die Naeherungsverfahren 
			For i = 0 To n+1 
				*x\f[IX(0,   i)] = 0 
				*x\f[IX(n+1, i)] = 0 
				*x\f[IX(i,   0)] = 0 
				*x\f[IX(i, n+1)] = 0 
			Next 
			
	EndSelect 
	
EndProcedure 

;- End Simulation 

Procedure.l color_gr( f1.d,f2.d) 
	Protected r.l, g.l, b.l,v.f 
	v=$500*Sqr(f1*f1+f2*f2)  
	g=$FF 
	b=$80 
	r = $FF -v 
	If r < 0 : g + r : r=0    
		If g < 0 :    r - g  : g=0 
			If g <  $80 : b + g            : EndIf    
			If g >= $80 : b +$FF-g         : EndIf 
			If r <  $80 : b + r            : EndIf    
			If r >= $80 
				If r < $17F  
					b =$17F-r : r = $80 
				Else 
					r-$FF : b=0  
					If r>=$1FF:r=$FF:g=$FF:b=$FF   :EndIf 
					If r>$FF :g=r-$FF:b=r-$FF:r=$FF:EndIf 
				EndIf 
			EndIf    
		EndIf 
	EndIf 
	ProcedureReturn RGB(r, g, b) 
EndProcedure 

Procedure draw_(n.l, *u.FArray, *v.FArray, im.l, jm.l) 
	Protected.l i, j , xi, xj
	Protected.f um, vm 
	Protected.s info
	
	If StartDrawing(ScreenOutput())
		xi = 0
		CompilerIf Subsystem("OpenGL")
			
			Protected xn = (n-1) * #Zoom
			
			For i = 0 To xn Step #Zoom
				xi + 1 
				xj = 0
				For j = 0 To xn Step #Zoom
					xj + 1
					Box(i,j,#Zoom,#Zoom,color_gr(*u\f[IX(xi, xj)],*v\f[IX(xi, xj)]))
				Next 
			Next
			If MouseCatched
				Line(im*#Zoom-8,jm*#Zoom-3,11, 1,RGB(255,255,255)) 
				Line(im*#Zoom-3,jm*#Zoom-8, 1,11,RGB(255,255,255)) 
			EndIf
			
		CompilerElse
			
			Protected xn = (n-1) * #DSTEP
			For i = 0 To xn Step #DSTEP
				xi + 1 
				xj = 0
				For j = 0 To xn Step #DSTEP
					xj + 1
					Plot(i,j,color_gr(*u\f[IX(xi, xj)],*v\f[IX(xi, xj)]))
				Next 
			Next
			If MouseCatched
				Line(im-2,jm  ,5,1,RGB(255,255,255)) 
				Line(im  ,jm-2,1,5,RGB(255,255,255)) 
			EndIf
			
		CompilerEndIf
		
		StopDrawing()
	EndIf
	FlipBuffers() 
	
	If plot = 0 
		SetGadgetText(1,"Akt.Density : "+StrF(*u\f[IX(im, jm)],3)+" kg/m³")
	Else 
		um=*u\f[IX(im, jm)] 
		vm=*v\f[IX(im, jm)] 
		SetGadgetText(2,"u = "+StrF(um,3)+" m/s")
		SetGadgetText(3,"v = "+StrF(vm,3)+" m/s")
		SetGadgetText(4,"Sqrt(u²+v²) = "+StrF(Sqr(um*um+vm*vm),3)+" m/s")
	EndIf 
	SetGadgetText(5,"RGB Color Value = $"+Hex(color_gr(*u\f[IX(im, jm)],*v\f[IX(im, jm)])))
EndProcedure 

Procedure set_dens (n.l, *d.FArray) 
	Define.l i, Size = (n + 2) * (n + 2) 
	
	For i = 0 To Size - 1 
		*d\f[i]= dense 
	Next 
EndProcedure 

Procedure set_datas(n.l,  *dens0.FArray, *u0.FArray, *v0.FArray, im.l, jm.l) 
	Define.l z, Size = (n + 2) * (n + 2) 
	
	fillmemory_(*dens0, (n + 2) * (n + 2) * SizeOf(Float), 0) 
	If MouseButton(1) 
		SetGadgetColor(10,#PB_Gadget_FrontColor,$ff)
		If KeyboardPushed(#PB_Key_LeftShift) Or KeyboardPushed(#PB_Key_RightShift)
			*dens0\f[IX(im+z, jm)] = - DensityChange / dt ;Dichteaenderung pro Zeitschritt 
		Else
			*dens0\f[IX(im+z, jm)] = DensityChange / dt ;Dichteaenderung pro Zeitschritt 
		EndIf
	Else
		SetGadgetColor(10,#PB_Gadget_FrontColor,$00)
	EndIf 
	If MouseButton(2) 
		SetGadgetColor(11,#PB_Gadget_FrontColor,$ff)
		If KeyboardPushed(#PB_Key_LeftShift) Or KeyboardPushed(#PB_Key_RightShift)
			*u0\f[IX(im+z, jm)] = -10/dt  ;Geschwindigkeitsaenderung pro Zeitschritt 
			*v0\f[IX(im+z, jm)] = -8 /dt  ;Geschwindigkeitsaenderung pro Zeitschritt 
		Else
			*u0\f[IX(im+z, jm)] = 10/dt  ;Geschwindigkeitsaenderung pro Zeitschritt 
			*v0\f[IX(im+z, jm)] = 8 /dt  ;Geschwindigkeitsaenderung pro Zeitschritt 
		EndIf
	Else
		SetGadgetColor(11,#PB_Gadget_FrontColor,$00)
	EndIf 
	If KeyboardPushed(#PB_Key_LeftShift) Or KeyboardPushed(#PB_Key_RightShift)
		SetGadgetColor(12,#PB_Gadget_FrontColor,$ff00)
	Else
		SetGadgetColor(12,#PB_Gadget_FrontColor,$00)
	EndIf
	If StreamActive
		*u0\f[IX(90, 90)] = - (#Stream /dt) ; hier ist ein Quirl eingebaut, rausnehmen 
		*v0\f[IX(90, 90)] = - (#Stream /dt)
	EndIf
EndProcedure 

Procedure main() 
	Protected *u.FArray = AllocateMemory(#SIZE * SizeOf(Float)) 
	Protected *v.FArray = AllocateMemory(#SIZE * SizeOf(Float)) 
	Protected *u_prev.FArray = AllocateMemory(#SIZE * SizeOf(Float)) 
	Protected *v_prev.FArray = AllocateMemory(#SIZE * SizeOf(Float)) 
	Protected *dens.FArray = AllocateMemory(#SIZE * SizeOf(Float)) 
	Protected *dens_prev.FArray = AllocateMemory(#SIZE * SizeOf(Float)) 
	Protected Drawstart.l, FrameCounter.l, KeyPressed.l, Event.l, n
	Static imf.f, jmf.f, Quit.l, oldgrav.f
	Protected LastMouseX, LastMouseY, LastPressed.l
	
	set_dens(#N, *dens) ; Dichtefeld fuer den Anfang belegen 
	
	Repeat
		If FrameCounter = 30 : Drawstart = ElapsedMilliseconds() : FrameCounter = 0 : EndIf
		FrameCounter + 1
		ExamineMouse() 
		imf = imf + MouseDeltaX() / #MouseSpeed
		jmf = jmf + MouseDeltaY() / #MouseSpeed
		If imf > #N : imf = #N : EndIf 
		If imf < 1 :  imf = 1  : EndIf ; 0 ist Randpunkt, darf nicht gesetzt werden 
		If jmf > #N : jmf = #N : EndIf 
		If jmf < 1  : jmf = 1  : EndIf
		im = imf
		jm = jmf
		
		If Not pause Or MouseButton(1) | MouseButton(2)
			ExamineKeyboard()
			set_datas(#N,  *dens_prev, *u_prev, *v_prev, im, jm) 
			If Not pause
				vel_step(#N, *u, *v, *u_prev, *v_prev, *dens, visc, dt)
				dens_step(#N, *dens, *dens_prev, *u, *v, diff, dt) 
			Else
				vel_step(#N, *u, *v, *u_prev, *v_prev, *dens, visc/10, dt/10)
				dens_step(#N, *dens, *dens_prev, *u, *v, diff*10, dt/10) 
			EndIf
		EndIf      
		If plot = 0  
			draw_(#N, *dens,*dens, im, jm) 
		Else 
			draw_(#N, *u,*v, im, jm) 
		EndIf 
		If FrameCounter = 30 : SetWindowTitle(0,"Fluid Dynamics  ("+StrF(30000/(ElapsedMilliseconds()-Drawstart),1)+"fps)") : EndIf
		If MouseCatched
		ExamineKeyboard()
		If KeyPressed < ElapsedMilliseconds()
			
			If KeyboardPushed(#PB_Key_Comma)
				
				oldgrav = grav
				If KeyboardPushed(#PB_Key_LeftControl) Or KeyboardPushed(#PB_Key_RightControl)
					grav + 0.01
				ElseIf KeyboardPushed(#PB_Key_LeftShift) Or KeyboardPushed(#PB_Key_RightShift)
					grav + 0.1
				Else
					grav + 1
				EndIf
				If grav > 20 : grav = oldgrav : EndIf
				SetGadgetText(9,"(G)ravity : "+StrF(grav,2)+" m/sec²")
				KeyPressed = ElapsedMilliseconds()+150
				
			ElseIf KeyboardPushed(#PB_Key_Period)
				
				oldgrav = grav
				If KeyboardPushed(#PB_Key_LeftControl) Or KeyboardPushed(#PB_Key_RightControl)
					grav - 0.01
				ElseIf KeyboardPushed(#PB_Key_LeftShift) Or KeyboardPushed(#PB_Key_RightShift)
					grav - 0.1
				Else
					grav - 1
				EndIf
				If grav < -20 : grav = oldgrav : EndIf
				SetGadgetText(9,"(G)ravity : "+StrF(grav,2)+" m/sec²")
				KeyPressed = ElapsedMilliseconds()+150
				
			ElseIf KeyboardPushed(#PB_Key_Add)
				
				If Viscosity < 30 : Viscosity +1 : EndIf
				SetGadgetText(6,"Viscositylevel : "+Str(Viscosity))
				KeyPressed = ElapsedMilliseconds()+150
				
			ElseIf KeyboardPushed(#PB_Key_Subtract)
				
				If Viscosity > 1 : Viscosity -1 : EndIf
				SetGadgetText(6,"Viscositylevel : "+Str(Viscosity))
				KeyPressed = ElapsedMilliseconds()+150
				
			ElseIf KeyboardPushed(#PB_Key_Down)
				
				If DensityChange < 4.9 : DensityChange + 0.1 : EndIf
				SetGadgetText(7,"Injected Density : "+StrF(DensityChange,1)+" kg/m³")
				KeyPressed = ElapsedMilliseconds()+60
				
			ElseIf KeyboardPushed(#PB_Key_Up)
				
				If DensityChange > - 4.9 : DensityChange - 0.1 : EndIf
				SetGadgetText(7,"Injected Density : "+StrF(DensityChange,1)+" kg/m³")
				KeyPressed = ElapsedMilliseconds()+60
				
			ElseIf KeyboardPushed(#PB_Key_D)
				
				plot = 1-plot
				DisableGadget(1,plot)
				DisableGadget(2,1-plot)
				DisableGadget(3,1-plot)
				DisableGadget(4,1-plot)
				If plot = 0
					SetGadgetText(8,"Act. (D)isplay  =>  Density Field")
				Else
					SetGadgetText(8,"Act. (D)isplay  =>  Flow Velocity")
				EndIf
				KeyPressed = ElapsedMilliseconds()+150
				
			ElseIf KeyboardPushed(#PB_Key_S)
				
				StreamActive = 1-StreamActive
				SetGadgetColor(17, #PB_Gadget_FrontColor, StreamActive * $ff00)
				KeyPressed = ElapsedMilliseconds()+150
				
			ElseIf KeyboardPushed(#PB_Key_C)
				
				FillMemory(*u, #SIZE * SizeOf(Float))
				FillMemory(*v, #SIZE * SizeOf(Float))
				FillMemory(*u_prev, #SIZE * SizeOf(Float))
				FillMemory(*v_prev, #SIZE * SizeOf(Float))
				FillMemory(*dens, #SIZE * SizeOf(Float))
				FillMemory(*dens_prev, #SIZE * SizeOf(Float))
				set_dens(#N, *dens)
				KeyPressed = ElapsedMilliseconds()+150
				
			ElseIf KeyboardPushed(#PB_Key_G)
				
				If grav = 9.81
					grav = 0
				Else
					grav = 9.81
				EndIf
				SetGadgetText(9,"Gravity : "+StrF(grav,2)+" m/sec²")
				KeyPressed = ElapsedMilliseconds()+150
				
			ElseIf KeyboardPushed(#PB_Key_Space)
				
				pause = 1-pause
				
				If ElapsedMilliseconds() - LastPressed > 1000
					KeyPressed = ElapsedMilliseconds()+500
				Else
					If pause > 0
						KeyPressed = ElapsedMilliseconds()+100
					Else
						KeyPressed = ElapsedMilliseconds()+20
					EndIf
				EndIf
				
				LastPressed = ElapsedMilliseconds()
				
			ElseIf KeyboardPushed(#PB_Key_Escape) 
				
				ReleaseMouse(#True)
				HideGadget(18, #True)
				HideGadget(25, #False)
				MouseCatched = #False
				
				For n = 10 To 23
					DisableGadget(n, #True)
				Next
				
				CompilerIf #PB_Compiler_OS = #PB_OS_Windows
					If LastMouseX Or LastMouseY
						SetCursorPos_(LastMouseX, LastMouseY)
					EndIf
				CompilerEndIf
				
			EndIf
		ElseIf Not KeyboardPushed(#PB_Key_All)
			KeyPressed = 0
		EndIf
	EndIf
	
		Repeat
			Event = WindowEvent()
			If Event = #PB_Event_CloseWindow
				Quit = #True
			ElseIf Event = #PB_Event_Gadget
				ReleaseMouse(#False)
				HideGadget(18, #False)
				HideGadget(25, #True)
				MouseCatched = #True
				LastMouseX = DesktopMouseX()
				LastMouseY = DesktopMouseY()
				
				For n = 10 To 23
					DisableGadget(n, #False)
				Next
				
			EndIf
		Until Not Event
		
	Until Quit 
EndProcedure 

InitSprite() 
InitMouse() 
InitKeyboard() 

OpenWindow(0, 100, 100, #xGui+GuiWidth, #N * #Zoom, "Fluid Dynamics", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
TextGadget(1,0,0,10,10,"Dummy")
If StartDrawing(WindowOutput(0))
	DrawingFont(GetGadgetFont(1))
	GuiWidth = TextWidth("+ <Shift>  =  Invert Density && Twirl") + 2 * #xPos2
	ResizeWindow(0, #PB_Ignore, #PB_Ignore, #xGui+GuiWidth, #PB_Ignore)
	StopDrawing()
EndIf
Frame3DGadget(0,#xGui+#xPos1,10,GuiWidth-#xPos1*2,20+#LineHeight1*9,"Actual Values")
TextGadget(1,#xGui+#xPos2,28 + #LineHeight1 * 0, GuiWidth-#xPos2*2, 18,"Dichte : 0.000 kg/m³")
TextGadget(2,#xGui+#xPos2,28 + #LineHeight1 * 1, GuiWidth-#xPos2*2, 18,"u = 0.000 m/s")
TextGadget(3,#xGui+#xPos2,28 + #LineHeight1 * 2, GuiWidth-#xPos2*2, 18,"v = 0.000 m/s")
TextGadget(4,#xGui+#xPos2,28 + #LineHeight1 * 3, GuiWidth-#xPos2*2, 18,"Sqrt(u²+v²) = 0.000 m/s")
TextGadget(5,#xGui+#xPos2,28 + #LineHeight1 * 4, GuiWidth-#xPos2*2, 18,"")
TextGadget(9,#xGui+#xPos2,28 + #LineHeight1 * 5, GuiWidth-#xPos2*2, 18,"(G)ravity : "+StrF(grav,2)+" m/sec²")
TextGadget(6,#xGui+#xPos2,28 + #LineHeight1 * 6, GuiWidth-#xPos2*2, 18,"Viscositylevel : "+Str(Viscosity))
TextGadget(7,#xGui+#xPos2,28 + #LineHeight1 * 7, GuiWidth-#xPos2*2, 18,"Injected Density : "+StrF(DensityChange,1)+" kg/m³")
TextGadget(8,#xGui+#xPos2,28 + #LineHeight1 * 8, GuiWidth-#xPos2*2, 18,"Act. (D)isplay  =>  Density Field")
DisableGadget(2,1)
DisableGadget(3,1)
DisableGadget(4,1)
YPos = 55 + #LineHeight1*9
Frame3DGadget(26,#xGui+#xPos1,YPos-20,GuiWidth-#xPos1*2,#N * #Zoom - YPos + 13,"Control Keys")
TextGadget(10,#xGui+#xPos2, YPos+ 0*LH+0*LS		,GuiWidth-#xPos2*2, 18, "Left-MB   =  Inject Density")
TextGadget(11,#xGui+#xPos2, YPos+ 1*LH+0*LS		,GuiWidth-#xPos2*2, 18, "Right-MB =  Add Twirl")
TextGadget(12,#xGui+#xPos2, YPos+ 2*LH+0*LS		,GuiWidth-#xPos2*2, 18, "+ <Shift>  =  Invert Density && Twirl")
TextGadget(13,#xGui+#xPos2, YPos+ 3*LH+1*LS		,GuiWidth-#xPos2*2, 16, "< . | , > = Gravity +/- 1.00",#PB_Text_Right)
TextGadget(14,#xGui+#xPos2, YPos+ 4*LH+1*LS		,GuiWidth-#xPos2*2, 16, "<Shift> < . | , > = Gravity +/- 0.10",#PB_Text_Right)
TextGadget(15,#xGui+#xPos2, YPos+ 5*LH+1*LS		,GuiWidth-#xPos2*2, 16, "<Ctrl> < . | , > = Gravity +/- 0.01",#PB_Text_Right)
TextGadget(16,#xGui+#xPos2, YPos+ 6*LH+2*LS		,GuiWidth-#xPos2*2, 16, "<+|-> = Viscosity +/- 1.00",#PB_Text_Right)
TextGadget(20,#xGui+#xPos2, YPos+ 7*LH+2*LS		,GuiWidth-#xPos2*2, 16, "<Shift> <+|-> = Viscosity +/- 0.10",#PB_Text_Right)
TextGadget(21,#xGui+#xPos2, YPos+ 8*LH+3*LS		,GuiWidth-#xPos2*2, 16, "<Csr Up> =  Density   +   0.10",#PB_Text_Right)
TextGadget(19,#xGui+#xPos2, YPos+ 9*LH+3*LS		,GuiWidth-#xPos2*2, 16, "<Csr Dn> =  Density   -    0.10",#PB_Text_Right)
TextGadget(17,#xGui+#xPos2, YPos+10*LH+4*LS		,GuiWidth-#xPos2*2, 18, "<S> = bottom right Stream on/off",#PB_Text_Center)
TextGadget(22,#xGui+#xPos2, YPos+11*LH+5*LS-4	,GuiWidth-#xPos2*2, 18, "<D> = Change Display type",#PB_Text_Center)
TextGadget(23,#xGui+#xPos2, YPos+12*LH+6*LS-8	,GuiWidth-#xPos2*2, 18, "<Space> = Pause / Stepmotion",#PB_Text_Center)
TextGadget(18,#xGui+#xPos2, YPos+13*LH+7*LS-12	,GuiWidth-#xPos2*2, 18, "<ESC> = Release Mouse && Kbd",#PB_Text_Center)

ButtonGadget(25,#xGui+#xPos2,YPos+13*LH+7*LS-3-12, GuiWidth-#xPos2*2,22,"Grab Mouse && Keyboard")
HideGadget(25, #True)
SetGadgetColor(17, #PB_Gadget_FrontColor, StreamActive * $ff00)

CompilerIf Subsystem("OpenGL")
	OpenWindowedScreen(WindowID(0), 0, 0, #N * #Zoom, #N * #Zoom, #False, 0, 0, #PB_Screen_NoSynchronization)
CompilerElse
	OpenWindowedScreen(WindowID(0), 0, 0, #N * #DSTEP, #N * #DSTEP, #True, GuiWidth, 0, #PB_Screen_NoSynchronization)
CompilerEndIf

While WindowEvent() : Wend

main() 

CloseScreen()
CloseWindow(0)
End
[/size]
Zuletzt geändert von PureLust am 04.07.2011 22:44, insgesamt 2-mal geändert.
[Dynamic-Dialogs] - komplexe dynamische GUIs einfach erstellen
[DeFlicker] - Fenster flimmerfrei resizen
[WinFX] - Window Effekte (inkl. 'durchklickbares' Window)
Benutzeravatar
Macros
Beiträge: 1361
Registriert: 23.12.2005 15:00
Wohnort: Olching(bei FFB)
Kontaktdaten:

Re: Fluid Dynamics

Beitrag von Macros »

Hi,

Freut mich, dass du dich dem Programm nochmal gewidmet hast.
Es läuft unter Linux aber die Framerate ist noch nicht gleichauf mit der Boxmethode auf meinem PC.

Das Problem mit Autostretch gibt es hier auch, stellt man DSTEP auf 5 führt das zu unschönen Artefakten (siehe)

Schön, dass du meinen Vorschlag mit Release Mouse angenommen hast.
Nur solltest du nicht die Taste zum Beenden damit überschreiben, denn unter Linux kann ein zu großer Screen
dazu führen, dass die Maus nicht richtig freigegeben wird, und man in deinem Programm gefangen ist.
Man kann auch die Maus nicht freigeben und wieder einfangen. Verwende doch eine Toggle Variable,
wie ich es auch in meinem Code gemacht hab. Die Stelle ist durch ;- markiert.

Und zu guter letzt: Es ärgert mich, jedes mal den Unterschrich nach FillMememory zu entfernen ;)

Hier nochmal ein Screenshot mit der BoxZeichemethode,
eingefügt in deinen neuen Quellcode und DSTEP auf 5 gesetzt.
Du könntest ja im Programm die Auswahl zwischen beiden Zeichenmethoden bieten,
dann bekommen sowohl Linuxer als auch Windowsnutzer den jeweils höchsten Grafikgenuss.

Hier nochmal der relevante Codeteil:

Code: Alles auswählen

If StartDrawing(ScreenOutput())
   xi = 0
   For i = 0 To xn Step #DSTEP
      xi + 1 
      xj = 0
      For j = 0 To xn Step #DSTEP
        xj + 1
        ;- Draw Boxes instead of a sprite
        Box(i,j,#DSTEP,#DSTEP,color_gr(*u\f[IX(xi, xj)],*v\f[IX(xi, xj)])) 
        
      Next 
   Next
   
   ;display cross-hair at Mouse position 
   ;- Xor the Cursor
   DrawingMode(#PB_2DDrawing_XOr)
   Line(im*#DSTEP-#DSTEP/2-1,jm*#DSTEP-2*#DSTEP-1,1,3.5*#DSTEP,$ffffff) 
   Line(im*#DSTEP-2*#DSTEP-1,jm*#DSTEP-#DSTEP/2-1,3.5*#DSTEP,1,$ffffff) 
   
   StopDrawing()
   EndIf
   FlipBuffers() 
Äh hups ich seh gerade, du bist ja eh von Sprites auf Plot umgestiegen... ist das echt schneller als Box unter DX9?
Bild
Benutzeravatar
PureLust
Beiträge: 1145
Registriert: 21.07.2005 00:02
Computerausstattung: Hab aktuell im Grunde nur noch 'nen Lenovo Yoga 2 Pro im Einsatz.
Wohnort: am schönen Niederrhein

Re: Fluid Dynamics

Beitrag von PureLust »

Nachdem ich auf Deinen Linux-Screenshots gesehen habe, wie katastrophal die GUI unter Lunix aussieht,
hab ich mich nochmals dran gesetzt und den Code in meinem letzten Post nochmal geändert.

Changes:
- Die Breite der "GUI" (rechts) passt sich nun auf die für den Systemfont benötigte Breite an (sollte sie zumindest - nur gestetet unter WinXP)
- Wenn OpenGL als Subsystem benutzt wird, dann wird der Screen anders geöffnet und die Grafik anders gezeichnet, so dass nun alles unter DX9, DX7 und OpenGL funktionieren sollte.

Und wenn ich mir diesen Messie-Code so anschaue wird mir ganz anders. :freak:
Der müsste echt mal ins reine gebracht werden. :twisted:
[Dynamic-Dialogs] - komplexe dynamische GUIs einfach erstellen
[DeFlicker] - Fenster flimmerfrei resizen
[WinFX] - Window Effekte (inkl. 'durchklickbares' Window)
jamirokwai
Beiträge: 65
Registriert: 02.06.2008 16:10

Re: Fluid Dynamics

Beitrag von jamirokwai »

Hey,

das Teil läuft super unter Mac OS X 10.6.8, PB 4.6b3 und einem C2D 2.3 GHz mit 4GB.
Ich bekomme hier Frameraten zwischen 60 und 80 fps bei eine Größe von 100 x 100 px.
Bei 200 x 200 px sind es dann eher 20 fps...

Grüsse
J.
Benutzeravatar
PureLust
Beiträge: 1145
Registriert: 21.07.2005 00:02
Computerausstattung: Hab aktuell im Grunde nur noch 'nen Lenovo Yoga 2 Pro im Einsatz.
Wohnort: am schönen Niederrhein

Re: Fluid Dynamics

Beitrag von PureLust »

jamirokwai hat geschrieben:... das Teil läuft super unter Mac OS X 10.6.8, PB 4.6b3 und einem C2D 2.3 GHz mit 4GB.
Super ... vielen Dank für's Testen und das Feedback. :allright:
[Dynamic-Dialogs] - komplexe dynamische GUIs einfach erstellen
[DeFlicker] - Fenster flimmerfrei resizen
[WinFX] - Window Effekte (inkl. 'durchklickbares' Window)
Antworten