; ; A L L E 4 s c a . S ; ; Die schnellste Drehroutine auf einem 68000er-Computer, abgewandelt ; für Bilder aus dem Scanner. ; ; (lässt sich nur noch (ein wenig) schneller machen, wenn das BSET/BCLR in ; einem Datenregister auf 32 Bit abläuft, dadurch wird die Routine aber ; auch unflexibler) ; ; Leider eignet sie sich nicht für rechtwinklige Drehungen, ; was aber kein Nachteil ist, denn dafür gibt es von mir ; (bald) eine noch schnellere Routine, zur Not kann aber auch ; bloss mit 65535 statt 65536 multipliziert werden. ; Wenn anstelle von 65535 mit 65535/ZOOM multipliziert wird, vergrössert ; sich das Bild um den Faktor ZOOM. Verkleinerungen sind insofern einge- ; schränkt, dass ZOOM weder kleiner als SIN(phi) noch als COS(phi) werden ; darf. ; ; Aufruf unter GfA-BASIC: ; rotiere%=VARPTR(rotiere$) ; VOID C:rotiere%(L:start_dst_bereich%,L:origo_src%,L:SIN(phi)*65536, ; L:COS(phi)*65536,scr_width%,breite_in_words%-1,hoehe%-1) ; ; PHI ist der Drehwinkel; START_DST_BEREICH% ist die Adresse des 1. Bytes, ; an dem die Ausgabe beginnen soll; ORIGO_SRC% ist die Adresse des Bytes, ; an dessen Ende sich der Koordinatenmittelpunkt befindet. SCRWIDTH% ist ; die Breite des virtuellen Bildschirms in Bytes (zusätzlicher Parameter) ; ; Zu vermeiden ist allerdings JEDE Art von Berechnung im Parameterfeld, da ; GfA-BASIC sonst das höhere Wort von start_dst_bereich% nicht mehr auf dem ; Stack ablegt, was zu Bomben führt. (Ausser AHDI sei geladen; was der aber ; damit zu tun haben sollte ist mir schleierhaft) ; ; (c) by: ; ; Marcel Waldvogel ; Hägetstalstr. 37 ; 8610 Uster ; ; Registerbelegung: ; a0: Destination-Zeiger ; a1: Source-Zeiger ; a2: Source-Mitte ; a3: Breite des Bildschirms in Bytes ; a4: Zeiger auf den zweitobersten Parameter (breite_in_words%) ; a5: Zeiger auf den obersten Parameter im Stack (hoehe%) ; a6: Breite des Bildschirms in Bytes-2 ; ; d0: Berechnung: Breite(Words)-1, nachher Bitzähler für a0 ; d1: Berechnung: Höhe-1, nachher Bitzähler für a1 ; d2: Sinus ; d3: Cosinus ; d4: Berechnung: Zwischenspeicher, nachher Wordzähler pro Zeile ; d5: aktuelle X-Pos (Pixel) relativ zum Ursprung (a2) ; d6: aktuelle Y-Pos " ; d7: Berechnung: Hilfsregister für 1/2 ($8000.L), nachher Zwischenspeicher ; für das Word an (a0) getpar: ; Hole die Parameter, die auf dem Stack liegen ; Die Sinus- und Cosinuswerte werden vorbereitet lea 4(a7),a5 move.l (a5)+,a0 ; 1. Byte, ab dem das Resultat des zu drehenden ; Bereiches hinkommt move.l (a5)+,a2 ; Mittelpunkt des Koordinatensystems, aus dem ; der Bereich kommen soll move.l (a5)+,d2 ; INT(SIN(phi)*65536+0.5) bpl.s dncss ; Do Not Change Sine Sign neg.w d2 ; Bitte beachten: NUR .W, so kann man in der dncss: ; höheren Hälfte weiterhin das Vorzeichen testen move.l (a5)+,d3 ; INT(COS(phi)*65536+0.5) bpl.s dnccs ; Wie oben beim Sinus (d2) wird hier im unteren neg.w d3 ; Wort(!) der Absolutwert gebildet dnccs: move.w (a5)+,a3 ; Breite des virtuellen Bildschirms lea -2(a3),a6 ; Breite des Bildschirms-2 move.l a5,a4 ; a4 ist Zeiger auf die Breite im Stack move.w (a5)+,d0 ; Breite in Words-1 (DBRA-Zähler) move.w (a5),d1 ; Höhe in Linien-1 (DBRA-Zähler) ;################################################################### berechne: ; Berechnet linke obere Ecke des schiefen ; Originalrechtecks. Resultat als Byte+Bit in a1,d1 addq.w #1,d0 ; Vom DBRA-Zähler zur wahren Breite asl.w #3,d0 ; Breite*8 (*16=Bitzähler; /2=Einmitten) asr.w #1,d1 ; Höhe/2 (/2=Einmitten) move.w d0,d5 mulu d3,d5 ; d5=-Breite*4*d3 tst.l d3 bmi.s dnnd5 neg.l d5 dnnd5: move.w d1,d4 mulu d2,d4 tst.l d2 bpl.s dnad4 neg.l d4 dnad4: add.l d4,d5 ; -(-Höhe/2)*d2 move.w d0,d6 mulu d2,d6 ; d6=-Breite*4*d2 tst.l d2 bmi.s dnnd6 neg.l d6 dnnd6: move.w d1,d4 mulu d3,d4 tst.l d3 bpl.s dnsd4 ; Nachbildung von MULS, wobei das eine Vorzeichen neg.l d4 ; erst das .L-Vorzeichen des SRC-Operanden ist dnsd4: sub.l d4,d6 ; +(-Höhe/2)*d3 move.l #$8000,d7 ; Runden ($8000=0.5) add.l d7,d5 add.l d7,d6 swap d5 ; Korrektur (/65536) swap d6 move.b d5,d1 not.b d1 ; Nötig, da Bits in umgekehrter Richtung gezählt and.b #7,d1 ; Jetzt haben wir nur noch die relevanten Bits ; (sicherheitshalber) move.l a2,a1 move.w d5,d4 asr #3,d4 add.w d4,a1 move.w d6,d4 muls a3,d4 add.w d4,a1 ; a2=a1+d5(Zeilenzähler)/8+scrwidth*d6(Spaltenzähler) swap d5 ; Wir brauchen aber die "Ungenauigkeit" swap d6 ; Also wieder zurück move.w (a4),d4 ; Entscheidungsbaum, in welchem Quadranten zu drehen sei tst.l d2 ; Sinus negativ? bmi sinnega tst.l d3 ; Cosinus negativ? (Sinus positiv) bmi.s sinpcosn ;################################################################### ; Diese Routine arbeitet mit SIN+,COS+ sinpcosp: ; Endlich kommen wir zur so lange geheim gehaltenen ; Drehroutine (jetzt bin ich aber gespannt!!) movem.l a1/d1/d5/d6,-(a7) ; Diese Werte brauchen wir für die ; nächste Zeile nextword: moveq #15,d0 clr.w d7 nextbit: btst d1,(a1) ; Get Pixel beq.s setnot ; Put Pixel bset d0,d7 setnot: add.w d3,d5 ; Korrigiere x-Koordinate (falls nötig) bcc.s nnbx ; Nicht nächstes Bit subq.b #1,d1 ; Nächstes Bit im selben Byte bpl.s nnbx moveq #7,d1 addq.l #1,a1 ; Nächstes Byte nnbx: add.w d2,d6 ; Korrigiere y-Koordinate (f. n.) bcc.s nnby add.w a3,a1 nnby: dbra d0,nextbit ; Bearbeite nächstes Bit move.w d7,(a0)+ ; sonst nächstes Word dbra d4,nextword ; Bearbeite nächstes Word move.w (a4),d4 sub.w d4,a0 ; Gehe auf nächste Bildschirmzeile (Dest) sub.w d4,a0 add.w a6,a0 ; +scr_width%-2 movem.l (a7)+,a1/d1/d5/d6 ; Hole wieder zurück sub.w d2,d5 ; x-Korrektur (f. n.) bcc.s nnlx ; Nicht nächste Linie addq.b #1,d1 cmp.b #8,d1 bne.s nnlx clr.b d1 subq.l #1,a1 nnlx: add.w d3,d6 ; y-Korrektur (f. n.) bcc.s nnly add.w a3,a1 nnly: sub.w #1,(a5) ; Nächste Linie? bpl.s sinpcosp bra return ;################################################################### ; SIN+,COS- sinpcosn: movem.l a1/d1/d5/d6,-(a7) cnextword: moveq #15,d0 clr.w d7 cnextbit: btst d1,(a1) beq.s csetnot bset d0,d7 csetnot: sub.w d3,d5 bcc.s cnnbx addq.b #1,d1 cmp.b #8,d1 bne.s cnnbx clr.b d1 subq.l #1,a1 cnnbx: add.w d2,d6 bcc.s cnnby add.w a3,a1 cnnby: dbra d0,cnextbit move.w d7,(a0)+ dbra d4,cnextword move.w (a4),d4 sub.w d4,a0 sub.w d4,a0 add.w a6,a0 movem.l (a7)+,a1/d1/d5/d6 sub.w d2,d5 bcc.s cnnlx addq.b #1,d1 cmp.b #8,d1 bne.s cnnlx clr.b d1 subq.l #1,a1 cnnlx: sub.w d3,d6 bcc.s cnnly sub.w a3,a1 cnnly: sub.w #1,(a5) bpl.s sinpcosn bra return ;################################################################### dc.b "m.a.U.S." ; Copyright, erscheint als: ; blt.s +$2E ; bsr.s +$2E ; subq.b #2,$532e(a6) sinnega: ; Weitere Entscheidung: tst.l d3 bmi.s sinncosn ;################################################################### ; SIN-,COS+ sinncosp: movem.l a1/d1/d5/d6,-(a7) snextword: moveq #15,d0 clr.w d7 snextbit: btst d1,(a1) beq.s ssetnot bset d0,d7 ssetnot: add.w d3,d5 bcc.s snnbx subq.b #1,d1 bpl.s snnbx moveq #7,d1 addq.l #1,a1 snnbx: sub.w d2,d6 bcc.s snnby sub.w a3,a1 snnby: dbra d0,snextbit move.w d7,(a0)+ dbra d4,snextword move.w (a4),d4 sub.w d4,a0 sub.w d4,a0 add.w a6,a0 movem.l (a7)+,a1/d1/d5/d6 add.w d2,d5 bcc.s snnlx subq.b #1,d1 bpl.s snnlx moveq #7,d1 addq.l #1,a1 snnlx: add.w d3,d6 bcc.s snnly add.w a3,a1 snnly: sub.w #1,(a5) bpl.s sinncosp bra.s return ;################################################################### ; SIN-,COS- sinncosn: movem.l a1/d1/d5/d6,-(a7) scnextword: moveq #15,d0 clr.w d7 scnextbit: btst d1,(a1) beq.s scsetnot bset d0,d7 scsetnot: sub.w d3,d5 bcc.s scnnbx addq.b #1,d1 cmp.b #8,d1 bne.s scnnbx clr.b d1 subq.l #1,a1 scnnbx: sub.w d2,d6 bcc.s scnnby sub.w a3,a1 scnnby: dbra d0,scnextbit move.w d7,(a0)+ dbra d4,scnextword move.w (a4),d4 sub.w d4,a0 sub.w d4,a0 add.w a6,a0 movem.l (a7)+,a1/d1/d5/d6 add.w d2,d5 bcc.s scnnlx subq.b #1,d1 bpl.s scnnlx moveq #7,d1 addq.l #1,a1 scnnlx: sub.w d3,d6 bcc.s scnnly sub.w a3,a1 scnnly: sub.w #1,(a5) ; Nächste Linie? bpl.s sinncosn ;#################################################################### return: rts ; Am Ende angelangt! ende: