RotateSprite() » dreht 2D Sprites um 90°, 180° oder 270°

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
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

RotateSprite() » dreht 2D Sprites um 90°, 180° oder 270°

Beitrag von AND51 »

Hallo!

Hat mich etwas mehr Knobelarbeit gekostet als ich dachte, dafür liefere ich euch (m)eine Prozedur, die 2D Sprites um 90°, 180° und 270° drehten kann!
Pures PureBasic, es läuft also auf Windows und Linux (DrawingBuffer() wird auf Mac nicht unterstützt).
  • Parameter
  • 90, 180, 270 dreht jeweils X Grad nach rechts
  • -90, -180, -270 dreht jeweils X Grad nach links
    einfacher zu merken:
  • 3 dreht das Bild auf "3 Uhr" = 90°
  • 6 dreht das Bild auf "6 Uhr" = 180°
  • 9 dreht das Bild auf "9 Uhr" = 270°
  • Verbesserung:
    Man kann jetzt auch um x*90 Grad drehen, also zum Beispiel um 450° (=90°) oder -1260° (= -180°)
  • Bei 0°, 360° und "12 Uhr" pasiert nichts
  • Bei allen anderen Winkelangaben passiert auch nichts
  • Rückgabewert
  • Konnte das Sprite erfolgreich gedreht werden, ist der Rückgabewert <> 0
  • Der Rückgabewert ist die Adresse des DrawingBuffers
Wichtig: Das Sprite muss quadratisch sein!

Code: Alles auswählen

Procedure RotateSprite(SpriteID, Rotate=90) ; AND51, Feb/2008
	Protected *buffer, x, y, border=SpriteWidth(SpriteID)-1, bytesPerPixel=1, *px1.Long, *px2.Long
	*buffer=DrawingBuffer()
	If *buffer
		Select DrawingBufferPixelFormat()
			Case #PB_PixelFormat_32Bits_BGR, #PB_PixelFormat_32Bits_RGB
				bytesPerPixel=4
			Case #PB_PixelFormat_15Bits, #PB_PixelFormat_16Bits
				bytesPerPixel=2
			Case #PB_PixelFormat_24Bits_BGR, #PB_PixelFormat_24Bits_RGB
				bytesPerPixel=3
		EndSelect
		Select rotate%360
			Case 90, 3, -270 ; turn right
				For y=0 To border/2
					For x=0 To border/2
						*px1=*buffer+x*bytesPerPixel+y*DrawingBufferPitch()
						*px2=*buffer+(border-y)*bytesPerPixel+x*DrawingBufferPitch()
						Swap *px1\l, *px2\l
						*px2=*buffer+(border-x)*bytesPerPixel+(border-y)*DrawingBufferPitch()
						Swap *px1\l, *px2\l
						*px2=*buffer+y*bytesPerPixel+(border-x)*DrawingBufferPitch()
						Swap *px1\l, *px2\l
					Next
				Next
			Case 180, 6, -180 ; turn around
				For y=0 To border/2
					For x=0 To border
						*px1=*buffer+x*bytesPerPixel+y*DrawingBufferPitch()
						*px2=*buffer+(border-y)*DrawingBufferPitch()+(border-x)*bytesPerPixel
						Swap *px1\l, *px2\l
					Next
				Next
			Case 270, 9, -90 ; turn left
				For y=0 To border/2
					For x=0 To border/2
						*px1=*buffer+x*bytesPerPixel+y*DrawingBufferPitch()
						*px2=*buffer+y*bytesPerPixel+(border-x)*DrawingBufferPitch()
						Swap *px1\l, *px2\l
						*px2=*buffer+(border-x)*bytesPerPixel+(border-y)*DrawingBufferPitch()
						Swap *px1\l, *px2\l
						*px2=*buffer+(border-y)*bytesPerPixel+x*DrawingBufferPitch()
						Swap *px1\l, *px2\l
					Next
				Next
		EndSelect
	EndIf
	ProcedureReturn *buffer
EndProcedure
Zuletzt geändert von AND51 am 02.02.2008 14:45, insgesamt 4-mal geändert.
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Benutzeravatar
hardfalcon
Beiträge: 3447
Registriert: 29.08.2004 20:46

Beitrag von hardfalcon »

Warum nicht Winkel%360 ? :wink:
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag von AND51 »

Hm... Ich verstehe nicht, was du meinst?
Meinst du, es gibt eine effizientere Methode, den Rotationswinkel zu bestimmen?
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
DarkDragon
Beiträge: 6291
Registriert: 29.08.2004 08:37
Computerausstattung: Hoffentlich bald keine mehr
Kontaktdaten:

Beitrag von DarkDragon »

AND51 hat geschrieben:Hm... Ich verstehe nicht, was du meinst?
Meinst du, es gibt eine effizientere Methode, den Rotationswinkel zu bestimmen?
Ich denke er meint das so, dass du den Winkel zuerst auf einen Bereich zwischen 0 und 360 bringen solltest. Das geht dann durch Winkel = Winkel % 360. Dann kann man z.B. auch 450° angeben und es rotiert um 90°
Angenommen es gäbe einen Algorithmus mit imaginärer Laufzeit O(i * n), dann gilt O((i * n)^2) = O(-1 * n^2) d.h. wenn man diesen Algorithmus verschachtelt ist er fertig, bevor er angefangen hat.
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag von AND51 »

Achso...

Das ist eine gute Idee, darauf bin ich vorher nicht gekommen.
Ich hatte halt die Idee, dass man auch 3, 6 und 9 angeben kann, damit man sich das mit der "Uhrzeit" besser vorstellen kann.

Ich habe den Code geändert, so ist doch richtig oder? Ich möchte hardy's Idee zwar übernehmen, aber auch, dass man alle Werte zwischen -360 und 360 wie gewohnt einsetzen kann.

// Edit: Jau, scheint zu funktionieren. Danke nochmal für den Tipp!
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Benutzeravatar
remi_meier
Beiträge: 1078
Registriert: 29.08.2004 20:11
Wohnort: Schweiz

Beitrag von remi_meier »

Versuch doch mal unnötige Funktionsaufrufe wie

Code: Alles auswählen

DrawingBufferPitch()
zu ersetzen.
Auch unnötige Berechnungen spielen eine Rolle:

Code: Alles auswählen

*px1=*buffer+x*bytesPerPixel+y*DrawingBufferPitch()
Innerhalb der "For x="-Schleife wird y nie verändert, warum also immer neu
berechnen?
Kleine Aufgabe: Schaffst du es, die beiden Multiplikationen durch durch
Additionen an der richtigen Stelle im Code zu ersetzen?

Übrigens eine lustige Idee mit den Uhrzeiten :allright:
Benutzeravatar
hardfalcon
Beiträge: 3447
Registriert: 29.08.2004 20:46

Beitrag von hardfalcon »

AND51 hat geschrieben:Ich möchte hardy's Idee zwar übernehmen, aber auch, dass man alle Werte zwischen -360 und 360 wie gewohnt einsetzen kann.
Hardy? :wink:
AND51 hat geschrieben:Jau, scheint zu funktionieren. Danke nochmal für den Tipp!
Gern geschehn :) Ich wär selber nie drauf gekommen, dass Ganzzahldivision zu irgendwas von Nutzen sein könnte, bis ich mal in nem Code von NickTheQuick gesehn hab, was man damit für lustige Dinge anstellen kann. :allright:
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag von AND51 »

> Versuch doch mal unnötige Funktionsaufrufe wie DrawingBufferPitch() zu ersetzen
Hatte ich schon, in eigenem Speedtest, aber das brachte keine wirkliche Performancesteigerung.

> Auch unnötige Berechnungen spielen eine Rolle
OK, daran habe ich nicht gedacht. War so beschäftigt damit, die Formeln herauszufinden, weil mich das zugegebenermaßen einige Knobelarbeit eingebracht hat... :oops:

> Übrigens eine lustige Idee mit den Uhrzeiten
Dankeschön! :allright:

> Hardy?
:mrgreen:
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Andreas_S
Beiträge: 787
Registriert: 14.04.2007 16:48
Wohnort: Wien Umgebung
Kontaktdaten:

Beitrag von Andreas_S »

DrawingBufferPitch() wird höchtwarscheinlich nur eine variable aus dem speicher holen... also hast du nur 1-3 (kA wie viele genau) ASM-Befehle mehr...

Du kannst di meisten multiplikationen in deinem code durch reihen-additionen ersetzten...
zB

Code: Alles auswählen

            For y=0 To border/2
               For x=0 To border/2
                  *px1=*buffer+x*bytesPerPixel+y*DrawingBufferPitch()
                  *px2=*buffer+(border-y)*bytesPerPixel+x*DrawingBufferPitch()
                  Swap *px1\l, *px2\l
                  *px2=*buffer+(border-x)*bytesPerPixel+(border-y)*DrawingBufferPitch()
                  Swap *px1\l, *px2\l
                  *px2=*buffer+y*bytesPerPixel+(border-x)*DrawingBufferPitch()
                  Swap *px1\l, *px2\l
               Next
            Next 
Du könntest eine variable machen die den anfangswert y hat un am ende immer mit DrawingBufferPitch() addiert wird...

Andreas
Antworten