Seite 1 von 2

syncronisieren von/mit Window Redraw

Verfasst: 20.08.2009 00:58
von Thorium
Folgendes Problem:
Ich möchte ein Spiel auf ein Window rendern. Dazu verwende ich zum einen DirectX zum anderen möchte ich aber auch einen Softwarerenderer auf Basis der Image-Lib und 2DDrawing-Lib anbieten. Das funktioniert auch dank dem neuen Image Alphachannel recht einfach. Nur ist es so das das Zeichnen auf das Fenster im Softwarerenderer nicht mit dem Redraw des Fensters syncron ist. Dadurch entstehen sehr hässliche Tearing Effekte, die extrem auffallend sind, da der Hintergrund automatisch scrollt. Die exakt gleichen Effekte habe ich, wenn ich mit DirectX ohne VSync rendere, was dort kein Problem ist, da ich VSync mit DirectX ja nutzen kann.

Irgendwelche Ideen wie man dem Herr werden könnte?

Verfasst: 20.08.2009 11:54
von Rokur
Wie zeichnest du denn aufs Fenster? Mit Doublebuffering sollte da doch eigentlich nichts passieren können.

Verfasst: 20.08.2009 13:09
von coder
Genau, du solltest nicht direkt auf das Fenster zeichnen, sondern erst auf ein Image und das dann aufs Windows drawn oder du nutzt ein ImageGadget dazu, was noch ein bisschen mehr Komfort bringt, da du dich dann nicht ums Redraw-Event kümmern musst...

Verfasst: 20.08.2009 14:07
von Fluid Byte
Wie bereits erwähnt lässt sich Doublebuffering bewerkstelligen wenn vor dem Anzeigen erst auf ein Image gezeichnet wird. Ich bin mir aber gerade nicht sicher ob das exakt ist was du meinst. Hier ein kleines Beispiel:

Code: Alles auswählen

Define Frames, Angle.f
     
OpenWindow(0,0,0,340,240,"void",#WS_SYSMENU | #WS_CAPTION | #WS_MINIMIZEBOX | 1)
ImageGadget(0,0,0,0,0,CreateImage(0,340,240))
AddWindowTimer(0,0,30)

Repeat
	EventID = WaitWindowEvent()

	If EventID = #PB_Event_Timer      
		Angle + 0.05 : Frames + 1 : Radius = 80
		
		BackColor = GetSysColor_(#COLOR_3DSHADOW)
		
		; ---> DRAW BACKGROUND  
		StartDrawing(ImageOutput(0))
		DrawingMode(1)        
		              
		Box(0,0,350,250,BackColor)
		
		For BX = 0 To 239 Step 2
		   Box(0,BX,338,1,RGB(135,135,135))
		Next
		
		; ---> DRAW CIRCLES #1 
		Ellipse(165,120,Abs((Cos(Angle - 1) * 30)),Abs((Cos(Angle) * 30)),0)
		Ellipse(165,120,Abs((Cos(Angle - 1) * 30)) - 2,Abs((Cos(Angle) * 30)) - 2,RGB(100,220,50))
		
		; ---> DRAW CIRCLES #2
		For i=0 To 4            
		   Ellipse(165 + (Sin(Angle + (1.25 * i)) * Radius),120 + (Cos(Angle+(1.25 * i)) * Radius),32,32,0)
		   Ellipse(165 + (Sin(Angle + (1.25 * i)) * Radius),120 + (Cos(Angle+(1.25 * i)) * Radius),30,30,$0090FF)
		Next
		
		; ---> DRAW CIRCLES #3
		Ellipse(166,119 + (Cos(Angle) * 100),16,16,$0)
		Ellipse(166,119 + (Cos(Angle) * 100),14,14,$FFFFFF)        
		Ellipse(166,119 + (-Cos(Angle) * 100),16,16,$0)
		Ellipse(166,119 + (-Cos(Angle) * 100),14,14,$FFFFFF)        
		
		Ellipse(169 + (Cos(Angle) * 150),116,16,16,$0)
		Ellipse(169 + (Cos(Angle) * 150),116,14,14,$FFFFFF)        
		Ellipse(169 + (-Cos(Angle) * 150),116,16,16,$0)
		Ellipse(169 + (-Cos(Angle) * 150),116,14,14,$FFFFFF)
		StopDrawing()
		
 		SetGadgetState(0,ImageID(0))  
	EndIf
Until EventID = #PB_Event_CloseWindow

Verfasst: 20.08.2009 14:18
von Kaeru Gaman
ich hatte vor einiger Zeit mal ein kleines Beispiel für ein getimetes ImageGadget gepostet:
http://www.purebasic.fr/german/viewtopic.php?t=19394

je nach komplexität des Inhalts könnte es natürlich etwas eng werden mit dem timing.

Verfasst: 20.08.2009 14:43
von Thorium
Doublebuffering verwende ich sowieso. Es kommt trotzdem zu Tearing, da das Zeichnen des Images nicht syncron läuft mit dem neuzeichnen des Fensters.
Das Problem ist es das Zeichnen des Sprites mit dem Redraw des Fensters zu syncronisieren oder eben umgekehrt.

Ich schau mir jetzt erstmal Kaeru Code an.

Verfasst: 20.08.2009 14:55
von Fluid Byte
Ich denke ein kleiner Beispielcode würde hier helfen dein Problem etwas besser zu verstehen.

Verfasst: 20.08.2009 15:37
von Thorium
Fluid Byte hat geschrieben:Ich denke ein kleiner Beispielcode würde hier helfen dein Problem etwas besser zu verstehen.
OK

Dein Beispiel etwas umgebaut. Hier wird nun ein Foto hoch und runtergescrollt. Dabei entstehen Tearing Effekte wie Wellenbewegungen im Bild.

Das Foto kann hier runtergeladen werden: http://www.gametreasure.de/Temp/test.png

Code: Alles auswählen

Define.i YPos, YDirection

timeBeginPeriod_(1)

UsePNGImageDecoder()
LoadImage(5, "d:\test.png")
OpenWindow(0,0,0,1024,768,"void",#WS_SYSMENU | #WS_CAPTION | #WS_MINIMIZEBOX | 1)
ImageGadget(0,0,0,1024,768,CreateImage(0,1024,768))
AddWindowTimer(0,0,10)

Repeat
   EventID = WaitWindowEvent()

   If EventID = #PB_Event_Timer
      
      StartDrawing(ImageOutput(0))
      Box(0,0,1024,768,0)
      DrawImage(ImageID(5), 0, YPos)
      StopDrawing()
      
      If YPos < 1
        YPos = 1
        YDirection = 1
      ElseIf YPos > 300
        YPos = 300
        YDirection = -1
      Else
        YPos + YDirection
      EndIf
      
      SetGadgetState(0,ImageID(0)) 
   EndIf
Until EventID = #PB_Event_CloseWindow

Verfasst: 20.08.2009 16:17
von Fluid Byte
Also ob nun dein Beispiel mit GDI oder per Screen

Code: Alles auswählen

Define.i YPos, YDirection

InitSprite()
UsePNGImageDecoder()
OpenWindow(0,0,0,1024,768,"void",#WS_SYSMENU | #WS_CAPTION | #WS_MINIMIZEBOX | 1)
OpenWindowedScreen(WindowID(0),0,0,1024,768,0,0,0)
LoadSprite(0,"test.png")

Repeat
	EventID = WindowEvent()
	
	ClearScreen(0)
	
	If YPos < 1
		YPos = 1
		YDirection = 1
	ElseIf YPos > 300
		YPos = 300
		YDirection = -1
	Else
		YPos + YDirection
	EndIf
		
	DisplaySprite(0,0,YPos)	
	
	FlipBuffers()
Until EventID = #PB_Event_CloseWindow 
Macht bei mir keinen Unterschied. Es ruckelt ab und an aber kein Tearing.

Verfasst: 20.08.2009 16:45
von Thorium
Fluid Byte hat geschrieben: Macht bei mir keinen Unterschied. Es ruckelt ab und an aber kein Tearing.
Merkwürdig. Bei mir sehe ich sehr deutlich wie sich das Bild öfter von unten nach oben "durchwellt"