Seite 1 von 1

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

Verfasst: 02.02.2008 02:22
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

Verfasst: 02.02.2008 03:07
von hardfalcon
Warum nicht Winkel%360 ? :wink:

Verfasst: 02.02.2008 11:43
von AND51
Hm... Ich verstehe nicht, was du meinst?
Meinst du, es gibt eine effizientere Methode, den Rotationswinkel zu bestimmen?

Verfasst: 02.02.2008 11:53
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°

Verfasst: 02.02.2008 14:39
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!

Verfasst: 04.02.2008 21:17
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:

Verfasst: 04.02.2008 22:41
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:

Verfasst: 04.02.2008 23:10
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:

Verfasst: 04.02.2008 23:23
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