Sprite H/V-Flip on the fly

Anfängerfragen zum Programmieren mit PureBasic.
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

Beitrag von PureLust »

Kaeru Gaman hat geschrieben:im gegensatz zu dir mache ich mir gedanken über die bedürfnisse der fragenden.
Sorry .... aber zu dem und auch allem weiteren von Dir: OHNE WORTE !!! :lol: :lol: :lol: :lol: :lol:

Nur für den Fall, dass es Dir entgangen ist (könnte ja sein, dass Du vor lauter Kaeru-Postings den Wald nicht mehr siehst :? ):
Du schaffst es gerade abermals einen Thread mit OffTopics zuzumüllen die dem Fragenden in keinster Weise helfen. :roll:
[Dynamic-Dialogs] - komplexe dynamische GUIs einfach erstellen
[DeFlicker] - Fenster flimmerfrei resizen
[WinFX] - Window Effekte (inkl. 'durchklickbares' Window)
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Beitrag von ts-soft »

Hab hier mal ein bissel abgeschnitten, findet ihr im Müll wieder. Der Schnitt
Geschah mehr aus dem Bauch heraus, ohne Schuldzuweisung :mrgreen:
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
Fluid Byte
Beiträge: 3110
Registriert: 27.09.2006 22:06
Wohnort: Berlin, Mitte

Beitrag von Fluid Byte »

beleidigende Userbezeichnung entfernt, werde langsam Sauer hier (ts-soft)

Code: Alles auswählen

DisableDebugger

#SRPITES = 56
#ROWITEMS = 8
#SPACING = 3
#SMF = 64

Tempdir$ = GetTemporaryDirectory()

CreateImage(0,64,64)
StartDrawing(ImageOutput(0))
Box(0,0,32,64,#Red)
Box(32,0,32,64,#Blue)
StopDrawing()

For i=0 To #SRPITES-1
	SaveImage(0,Tempdir$ + "sprite" + Str(i+1) + ".bmp")
Next

InitSprite() : InitKeyboard()

OpenWindow(0,0,0,640,480,"void",#WS_SYSMENU | #WS_CAPTION | 1)
OpenWindowedScreen(WindowID(0),0,0,640,480,0,0,0)

For i=0 To #SRPITES-1
	LoadSprite(i,Tempdir$ + "sprite" + Str(i+1) + ".bmp")
Next

StartTime = ElapsedMilliseconds()

For i=0 To #SRPITES-1
	StartDrawing(SpriteOutput(i))
	
	IW = SpriteWidth(i) : IH = SpriteHeight(i)
	
	BufferPitch = DrawingBufferPitch() / 4	
	
	If IW <> BufferPitch : IW = BufferPitch : EndIf	
	
	*pxData.LONG = DrawingBuffer()

	For px=0 To (IW * IH) - 1
		R = *pxData\l & $FF
		G = *pxData\l >> 8 & $FF
		B = *pxData\l >> 16
		
		*pxData\l = B | G << 8 | R << 16	
		
		*pxData + 4
	Next
	
	StopDrawing()	
Next

MessageRequester("Result","Time: " + Str(ElapsedMilliseconds() - StartTime) + " Ms",64)

Repeat
	EventID = WindowEvent()
	
	ExamineKeyboard()
	
	ClearScreen(0)
			
	For i=0 To #SRPITES-1
		SX = (i/#ROWITEMS) * ((#SMF + #SPACING) * #ROWITEMS)
			
		DisplaySprite(0,5 + i * (#SMF + #SPACING) - SX,5 + (i/#ROWITEMS) * (#SMF + #SPACING))			
	Next	
	
	FlipBuffers()
Until KeyboardPushed(1) Or EventID = 16
Dieser Code schafft es 56 Sprites mit einer Größe von 64x64 in ~875 Ms zu flippen. Wo hingegen der Code von PureDödel es bei mir (Pentium D, 3.0 GHz) mit einem Sprite von 100x100 auf ~406 Ms bringt. Der Code kann mit Sicherheit noch optimiert werden aber ist ein Anfang.
Windows 10 Pro, 64-Bit / Outtakes | Derek
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag von AND51 »

Beitrag wegen TS-Soft wiederhergestellt


Wenn mir jemand erklären kann, wie das mit dem DrawingBuffer() funktioniert, das scheint ein Lichtblick zu sein, dann könnte ich es ja vielleicht auch mal versuchen.

Ich weiß, dass es der Buffer zu dem Sprite/Screen ist. Muss ich da einfach die RGB Farben rein und rauspoken? Desweiteren gibt mir der andere DrawingBuffer-Befehl ja die Länge einer zeile, aber woher weiß ich, wie viele zeilen das Ding hat? SpriteHeight()?
und das mit DrawingBufferPitch() verstehe ich noch nicht 100%ig...

Und vielleicht kann man ja das ganze noch mal beschleubnigen, indem man die Sprites mit dem Flag #PB_Sprite_Texture läd und erstellt? Habe vorhin mit der "Scheiß Board-Suche" (Augenzwinker@Kaeru) mal gesucht und gefunden, dass dieses Flag die Pixelmanipulation verschnellern soll.
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
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

Beitrag von PureLust »

@FB: In der Hoffnung dass Du's jetzt nicht wieder persönlich nimmst und wir mal bei der Sache bleiben können ...

Dein Code flippt nicht das Sprite, sondern macht momentan einfach nur eine Red<>Blue Invertierung jedes Pixels ... nix anderes.
(Wobei jedoch kein Zweifel daran besteht, dass es mit direktem Zugriff auf den DrawBuffer einiges flotter sein wird als mit Point/Plot).

@AND51:
AND51 hat geschrieben:Wenn mir jemand erklären kann, wie das mit dem DrawingBuffer() funktioniert, .....
Ich weiß, dass es der Buffer zu dem Sprite/Screen ist. Muss ich da einfach die RGB Farben rein und rauspoken? Desweiteren gibt mir der andere DrawingBuffer-Befehl ja die Länge einer zeile, aber woher weiß ich, wie viele zeilen das Ding hat? SpriteHeight()?
und das mit DrawingBufferPitch() verstehe ich noch nicht 100%ig...
Durch den DrawingBuffer() kommst Du an den Speicherbereich des Screens/Sprites heran.
DrawingBufferPitch() liefert Dir dir Länge einer Zeile in Bytes, wobei dies nicht unbedingt gleich zu setzen ist mit Screen/Sprite-Breite * BytesProPixel, da sich die interne Breite des Buffers von der angezeigten Breite unterscheiden kann.
Für Berechnungen der genauen Speicheradresse solltest Du also immer DrawingBufferPitch() und nicht die Screen/Sprite-Breite heranziehen.

Die Höhe ist tatsächlich die angegebene Sprite/Screen-Höhe die Du angegeben hast bzw. ja über die einschlägigen Befehle abfragen kannst.
Der gesamte Speicherbereich berechnet sich also aus DrawingBufferPitch * Screen/Sprite-Höhe.
Um nun z.B. die Offset-Adresse eines Pixels bei einem 32bit-Sprite zu berechnen brauchst Du im Grunde nur x*4+y*DrawingBufferPitch() zu berechnen (x*4 deswegen, da 32bit Farbtiefe = 4Byte).
Schwieriger wird es natürlich dann, wenn Du verschiedene Bittiefen von Screen/Sprites berücksichtigen musst. Dass ist dann halt etwas mehr Aufwand.

Um nun z.B. dann solche Dinge wie einen Flip zu realisieren kannst Du auf die berechneten Speicherstellen dann einfach per Peek/Poke oder eben per Pointer zugreifen.

Bei solchen Spritemanipulationen per direktem Speicherzugriffen ist es meist hilfreich, wenn man Sprites mit dem Flag #PB_Sprite_Memory erstellst, da der Speicherbereich des Sprites dann im schnellen Systemspeicher abgelegt wird und der Zugriff des Prozessors schneller erfolgen kann.
Dabei solltest Du jedoch auch bedenken, dass durch dieses Flag die spätere Darstellung auf dem Bildschirm wiederum langsamer von statten geht.

Hoffe ich habs einigermaßen verständlich hinbekommen. ;)
Gruß, PL.
Zuletzt geändert von PureLust am 16.05.2007 20:31, insgesamt 2-mal geändert.
[Dynamic-Dialogs] - komplexe dynamische GUIs einfach erstellen
[DeFlicker] - Fenster flimmerfrei resizen
[WinFX] - Window Effekte (inkl. 'durchklickbares' Window)
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

> brauchst Du im Grunde nur x*4+y*DrawingBufferPitch() zu berechnen (x*4 deswegen, da 32bit Farbtiefe = 4Byte).

anstatt der konstanten 4 würde ich vorschlagen, die rückgabe von DrawingBufferPixelFormat() auszuwerten...
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Benutzeravatar
Fluid Byte
Beiträge: 3110
Registriert: 27.09.2006 22:06
Wohnort: Berlin, Mitte

Beitrag von Fluid Byte »

PureLust hat geschrieben:@FB: In der Hoffnung dass Du's jetzt nicht wieder perönlich nimmst und wir mal bei der Sache bleiben können ...
Ich fühl mich nicht "perönlich" angegriffen, höchstens persönlich.

Aber kack dich nicht zu, solange die Bemerkung angebracht ist kann ich mit leben. Außerdem bin ich dankbar! Ich hatte ein falsches Snippet verwendet (channel swap) und der korrigierte Code bringt nun bei gleichen Bedingungen 0 Ms!

Code: Alles auswählen

DisableDebugger

#SRPITES = 56
#ROWITEMS = 8
#SPACING = 3
#SMF = 64

Tempdir$ = GetTemporaryDirectory()

CreateImage(0,#SMF,#SMF)
StartDrawing(ImageOutput(0))
For i=0 To #SMF-1
	Box(i,0,1,#SMF,RGB(i*225/(#SMF-1)+30,0,0))
Next

StopDrawing()

For i=0 To #SRPITES-1
	SaveImage(0,Tempdir$ + "sprite" + Str(i+1) + ".bmp")
Next

InitSprite() : InitKeyboard()

OpenWindow(0,0,0,640,480,"void",#WS_SYSMENU | #WS_CAPTION | 1)
OpenWindowedScreen(WindowID(0),0,0,640,480,0,0,0)

For i=0 To #SRPITES-1
	LoadSprite(i,Tempdir$ + "sprite" + Str(i+1) + ".bmp",#PB_Sprite_Memory)
Next

StartTime = ElapsedMilliseconds()

For i=0 To #SRPITES-1
	StartDrawing(SpriteOutput(i))
	
	IW = SpriteWidth(i) : IH = SpriteHeight(i)
	
	BufferPitch = DrawingBufferPitch() / 4	
	
	If IW <> BufferPitch : IW = BufferPitch : EndIf
	
	*pxData1.LONG = DrawingBuffer()
	*pxData2.LONG = AllocateMemory(IW * IH * 4)
	
	CopyMemory(*pxData1,*pxData2,IW * IH * 4)
				
	*pxData2 + (IW * IH * 4)	

	For px=0 To (IW * IH) - 1
		R = *pxData2\l & $FF
		G = *pxData2\l >> 8 & $FF
		B = *pxData2\l >> 16
		
		*pxData1\l = R | G << 8 | B << 16	
		
		*pxData1 + 4
		*pxData2 - 4
	Next	

	StopDrawing()	
Next

MessageRequester("Result","Time: " + Str(ElapsedMilliseconds() - StartTime) + " Ms",64)

Repeat
	EventID = WindowEvent()
	
	ExamineKeyboard()
	
	ClearScreen(0)
			
	For i=0 To #SRPITES-1
		SX = (i/#ROWITEMS) * ((#SMF + #SPACING) * #ROWITEMS)
			
		DisplaySprite(0,5 + i * (#SMF + #SPACING) - SX,5 + (i/#ROWITEMS) * (#SMF + #SPACING))			
	Next	
	
	FlipBuffers()
Until KeyboardPushed(1) Or EventID = 16
Zuletzt geändert von Fluid Byte am 16.05.2007 20:29, insgesamt 8-mal geändert.
Windows 10 Pro, 64-Bit / Outtakes | Derek
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

Beitrag von PureLust »

Kaeru Gaman hat geschrieben:> brauchst Du im Grunde nur x*4+y*DrawingBufferPitch() zu berechnen (x*4 deswegen, da 32bit Farbtiefe = 4Byte).

anstatt der konstanten 4 würde ich vorschlagen, die rückgabe von DrawingBufferPixelFormat() auszuwerten...
Korrekt. :allright:

@FB: Sorry, aber auch dein neuester Code macht keinen H- oder V-Flip sondern immer einen kompletten einen HV-Flip.
Nichts desto trotz wird die direkte Routine per DrawBuffer gute 10-15 mal schneller sein als per Plot/Point (natürlich auch abhängig von CPU und GraKa).
Bei mir sind's momentan 1532ms bei Point/Plot zu 151ms beim direkten Zugriff per Pointer (56 mal ein 64x64 Sprite flippen).
[Dynamic-Dialogs] - komplexe dynamische GUIs einfach erstellen
[DeFlicker] - Fenster flimmerfrei resizen
[WinFX] - Window Effekte (inkl. 'durchklickbares' Window)
Benutzeravatar
Fluid Byte
Beiträge: 3110
Registriert: 27.09.2006 22:06
Wohnort: Berlin, Mitte

Beitrag von Fluid Byte »

So! Nu ham was aba. Ich hab das #PB_Sprite_Memory Flag wieder raus genommen. Es sollte optional sein denn es braucht länger zum Laden und außerdem gibts ja Leute die nicht soviel GFKA-Speicher haben. Ergebniss imma noch ~250 Ms:

Code: Alles auswählen

DisableDebugger

#SRPITES = 56
#ROWITEMS = 8
#SPACING = 3
#SMF = 64
#VFLIP = 0

Tempdir$ = GetTemporaryDirectory()

CreateImage(0,#SMF,#SMF)
StartDrawing(ImageOutput(0))
Box(0,0,#SMF,#SMF,#Red)
DrawText(0,0,"1")
DrawText(#SMF-10,0,"2")
DrawText(0,#SMF-15,"3")
DrawText(#SMF-10,#SMF-15,"4")
StopDrawing()

For i=0 To #SRPITES-1
	SaveImage(0,Tempdir$ + "sprite" + Str(i+1) + ".bmp")
Next

InitSprite() : InitKeyboard()

OpenWindow(0,0,0,640,480,"void",#WS_SYSMENU | #WS_CAPTION | 1)
OpenWindowedScreen(WindowID(0),0,0,640,480,0,0,0)

For i=0 To #SRPITES-1
	LoadSprite(i,Tempdir$ + "sprite" + Str(i+1) + ".bmp")
Next

StartTime = ElapsedMilliseconds()

For i=0 To #SRPITES-1
	StartDrawing(SpriteOutput(i))
	
	IW = SpriteWidth(i) : IH = SpriteHeight(i)
	
	BufferPitch = DrawingBufferPitch() / 4	
	
	If IW <> BufferPitch : IW = BufferPitch : EndIf
	
	*pxData1.LONG = DrawingBuffer()
	*pxData2.LONG = AllocateMemory((IW * IH * 4))
	
	CopyMemory(*pxData1,*pxData2,(IW * IH * 4))
	
	For Y=0 To IH-1   
		For X=0 To IW-1
			If #VFLIP
				colref = PeekL(*pxData2 + (Y * IW + X) << 2)
				
				PokeL(*pxData1 + ((IH-Y-1) * IW + X) << 2,colref)   			
			Else
				colref = PeekL(*pxData2 + (Y * IW + X) << 2)
				
				PokeL(*pxData1 + ((IW-X) + (Y * IW-1)) << 2,colref)
			EndIf
		Next
	Next

	StopDrawing()	
Next

MessageRequester("Result","Time: " + Str(ElapsedMilliseconds() - StartTime) + " Ms",64)

Repeat
	EventID = WindowEvent()
	
	ExamineKeyboard()
	
	ClearScreen(0)
			
	For i=0 To #SRPITES-1
		SX = (i/#ROWITEMS) * ((#SMF + #SPACING) * #ROWITEMS)
			
		DisplaySprite(0,5 + i * (#SMF + #SPACING) - SX,5 + (i/#ROWITEMS) * (#SMF + #SPACING))			
	Next	
	
	FlipBuffers()
Until KeyboardPushed(1) Or EventID = 16
Windows 10 Pro, 64-Bit / Outtakes | Derek
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag von AND51 »

Hallo!

Wollte noch melden, dass ich deinen Beitrag gelesen habe, PureLust.
Leider hab ich keine pure Lust mehr, einen eigenen Code zu erstellen, weil mich das alles ein wenig verwirrt, diese ganzen Dinge, auf die man aufpassen muss...

Aber ich traue Fluid Byte's Code, weil ich des öfteren gesehen habe, dass seine Codes schön performant sind. <)


Sollte ich soetwas mal FlipSprite() brauchen und noch kein eigenes haben, dann wisst ihr, wie meine hochkarätigen Spiele ihre Sprites flippen... :lol:
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Antworten