Metropoli BBS
VIEWER: rotate3.asm MODE: TEXT (CP437)
; Realtime Bitmap Rotation Routine
; Handles approx. 0.5 million pixels / second on a 386
; by Soeren Holstebroe (seap)
; no group but available if you are interested. (code / algorithms + music)
;
; Last edited: 10/10-1993
;
; I would really appreciate if you would send some of your own source-codes
; or/and anything you use this piece of code in or/and any improvement of
; this routine.
; Note: This is freeware. You may do with this code whatever you want, but
; hey! please leave a greeting in your program. You greet me, I greet you.
; If any problems turn up or if you want to exchange more sources or if you
; just want to say "Hi! nice/lame piece of code you have made" or if you
; actually used this piece of asm, please write.
;
; Write to:
; Internet: seap@diku.dk
; Fidonet : 2:230/159.16
; Snailnet: Hjortekærbakken 1
;           2800 Lyngby
;           Denmark
; NB! Don't write to the snailnet address too long after release-date.

.286
cseg    segment
        assume  cs:cseg;ds:dseg
        org     0100h           ; stak
start:  jmp     main

        oldmode DB ?

opengfx:
                mov     ah,0fh
                int     10h
                mov     oldmode,al
                mov     ah,0h
                mov     al,13h
                int     10h
		ret

closegfx:
                mov     ah,0h
                mov     al,oldmode
                int     10h
		ret

makemulstab:    xor     di,di
                xor     ax,ax
                mov     cx,(iwidth*iheight)
mulsloop:       mov     mulstab [di],ax
                add     ax,iwidth
                inc     di
                inc     di
                loop    mulsloop
                ret


retrace:        mov     dx,3dah         ; wait for vertical retrace
ventl:          in      al,dx
                and     al,8
                jz      ventl
venth:          in      al,dx
                and     al,8
                jne     venth
                ret



tempX           dw      0
tempY           dw      0
cosvx           dw      0
sinvx           dw      0
cosvy           dw      0
sinvy           dw      0
cosv            dw      0
sinv            dw      0


rotate          proc    near
                mov     bp,angle        ; bp = rotation-angle
                mov     ax,cos[bp]      ; get cos(bp) and sin(bp) (for speed)
                mov     cosv,ax
                mov     ax,sin[bp]
                mov     sinv,ax

                mov     cx,iheight       ; image-iheight
                mov     bx,(-(iheight/2)); bx = -iheight/2
                mov     di,0

                ; pre-calc all multiplications

                mov     ax,-(iwidth/2)
                imul    cosv
                mov     cosvx,ax        ; cosvx = cos v * X

                mov     ax,-(iwidth/2)
                imul    sinv
                mov     sinvx,ax        ; sinvx = sin v * X

                mov     ax,-(iheight/2)
                imul    cosv
                mov     cosvy,ax        ; cosvy = cos v * Y

                mov     ax,-(iheight/2)
                imul    sinv
                mov     sinvy,ax        ; sinvy = sin v * Y

@ry:            push    cx
                mov     cx,iwidth       ; image iwidth

                ; dx = sin v * Y + cos v * X
                mov     dx,sinvy
                add     dx,cosvx

                ; dx = cos v * Y - sin v * X
                mov     si,cosvy
                sub     si,sinvx

                ; Place rotation origin in center of sourceimage
                add     dx,(iwidth/2)*256
                add     si,(iheight/2)*256

@rx:
                                        ; Xo = sin v * Y + cos v * X
                                        ; Yo = cos v * Y - sin v * X


                cmp     dx,(iwidth)*256   ; check if x is within source
                jae     blackout

                cmp     si,(iwidth)*256   ; the same for y
                jae     blackout


                ; Get-pixel
                ; calculate source-image offset
getpixel:
                mov     bx,si            ; y = y/128 (fixed point)
                xchg    bh,bl
                xor     bh,bh
                add     bx,bx
                mov     ax,mulstab[bx]   ; get y offset
                xor     bx,bx            ; x = x/256 (fixed point)
                mov     bl,dh
                add     bx,ax            ; si = source = iwidth * Yo + Xo
                mov     al,ds:image2[bx] ; al = pixel color
                                         ; change the above line if
                                         ; you want another image.
                                         ; Remember to change iwidth and
                                         ; iheight as well
                jmp     plot_pixel
blackout:
                mov     al,0             ; black pixel

plot_pixel:
                mov     es:[di],al       ; display pixel
                inc     di               ; next dest. pixel
                                         ; NOTE!!!!
                                         ; This will run faster
                                         ; if two colors are computed
                                         ; before the video-card is
                                         ; being accesed.
                                         ; When two colors are computed
                                         ; you can use a word-write
                                         ; instead of the byte-write.
                                         ; If you own a 386 DX, you can
                                         ; even wait until you have
                                         ; computed 4 colors before you
                                         ; acces the video-ram.
                                         ; I have made byte-writes
                                         ; to make it more compatible, but...
                                         ; Well, please mail me any
                                         ; improvements.
                ; update tempX
                add     dx,cosv
                                        ; bx = sin v * Y + cos v * X
                ; update tempY
                sub     si,sinv
                                        ; si = cos v * Y - sin v * X

                loop    @jrx

                ; update screen coord
                add     di,(320-iwidth) ; next dest. line

                ; update sinvy & cosvy
                mov     ax,cosv
                add     cosvy,ax
                mov     ax,sinv
                add     sinvy,ax

                pop     cx
                loop    @jry
                ret

; the far jumps below can easily be removed to gain speed.
; They are only there for compatibility (gosh, that word was hard to spell).

@jrx:           jmp     @rx
@jry:           jmp     @ry

rotate          endp


main:

                mov     ah,0ch          ; kill keyboard buffer
                mov     al,-1
                int     21h

                call    opengfx         ; open mode 13
                                        ; precalculate image-y-offsets
                call    makemulstab
                push    cs
                pop     ds
                mov     ax,0a000h
                mov     es,ax

mloop:
                call    rotate
                add     angle,2
                and     angle,1feh
                ; Angle goes from 0 to 255 degree. Remember to double
                ; the offset. (for wordsize).

                call    retrace ; wait for v-blank
                mov     ah,1    ; check if kb-buffer is empty
                int     16h
                jz      mloop   ; nope, loop again

                call    closegfx

                mov     ah,4ch          ; return to dos
		int	21h

                mulstab DW (iwidth*iheight) DUP(?)

                angle  dw      0            ; rotation angle
                iwidth   = 100              ; image width
                iheight  = 100              ; image height
                                            ; the two constants above
                                            ; can easily be changed
                                            ; into declarations.
; test-pattern nr. 1

image1  db      0,0,0,0,12,14,15,16,17,18,0,0,0,0,0,0
        db      0,0,0,11,13,19,0,0,0,20,21,22,0,0,0,0
        db      0,0,9,10,0,0,0,0,0,0,23,24,0,0,0,0
        db      0,0,8,0,0,0,0,0,0,0,0,25,0,0,0,0
        db      0,0,7,6,0,0,0,0,0,0,0,26,27,0,0,0
        db      0,0,0,5,4,0,0,0,0,0,0,28,29,0,0,0
        db      0,0,0,0,3,2,1,0,0,0,0,30,31,0,0,0
        db      0,0,0,0,0,0,0,0,0,0,32,33,0,0,0,0
        db      0,0,0,0,0,0,0,0,0,34,35,36,0,0,0,0
        db      0,0,0,0,0,0,0,0,37,38,39,0,0,0,0,0
        db      0,0,0,0,0,0,0,40,41,42,43,0,0,0,0,0
        db      0,0,0,0,0,0,44,45,46,47,0,0,0,0,0,0
        db      0,0,0,0,48,49,50,51,52,0,0,0,0,0,0,0
        db      0,0,0,53,54,55,56,57,0,0,0,0,0,0,0,0
        db      0,0,58,59,60,61,62,63,0,0,0,0,0,0,0,0
        db      0,64,65,66,67,68,69,70,71,0,0,0,0,0,0,0

; test-pattern nr. 2 (compiles a bit slow)

image2  label byte
        rept    (100*25)
        db      0,0,0,40
        endm

; precalculated sin/cos table
; table-size: 256+64=320


sin     DW      00000h,00006h,0000ch,00012h,00018h,0001fh,00025h,0002bh
	DW	00031h,00037h,0003dh,00044h,0004ah,0004fh,00055h,0005bh
	DW	00061h,00067h,0006dh,00072h,00078h,0007dh,00083h,00088h
	DW	0008dh,00092h,00097h,0009ch,000a1h,000a6h,000abh,000afh
	DW	000b4h,000b8h,000bch,000c1h,000c5h,000c9h,000cch,000d0h
	DW	000d4h,000d7h,000dah,000ddh,000e0h,000e3h,000e6h,000e9h
	DW	000ebh,000edh,000f0h,000f2h,000f4h,000f5h,000f7h,000f8h
	DW	000fah,000fbh,000fch,000fdh,000fdh,000feh,000feh,000feh
cos     DW      000ffh,000feh,000feh,000feh,000fdh,000fdh,000fch,000fbh
	DW	000fah,000f8h,000f7h,000f5h,000f4h,000f2h,000f0h,000edh
	DW	000ebh,000e9h,000e6h,000e3h,000e0h,000ddh,000dah,000d7h
	DW	000d4h,000d0h,000cch,000c9h,000c5h,000c1h,000bch,000b8h
	DW	000b4h,000afh,000abh,000a6h,000a1h,0009ch,00097h,00092h
	DW	0008dh,00088h,00083h,0007dh,00078h,00072h,0006dh,00067h
	DW	00061h,0005bh,00055h,0004fh,0004ah,00044h,0003dh,00037h
	DW	00031h,0002bh,00025h,0001fh,00018h,00012h,0000ch,00006h
	DW	00000h,0fffah,0fff4h,0ffeeh,0ffe8h,0ffe1h,0ffdbh,0ffd5h
	DW	0ffcfh,0ffc9h,0ffc3h,0ffbch,0ffb6h,0ffb1h,0ffabh,0ffa5h
	DW	0ff9fh,0ff99h,0ff93h,0ff8eh,0ff88h,0ff83h,0ff7dh,0ff78h
	DW	0ff73h,0ff6eh,0ff69h,0ff64h,0ff5fh,0ff5ah,0ff55h,0ff51h
	DW	0ff4ch,0ff48h,0ff44h,0ff3fh,0ff3bh,0ff37h,0ff34h,0ff30h
	DW	0ff2ch,0ff29h,0ff26h,0ff23h,0ff20h,0ff1dh,0ff1ah,0ff17h
	DW	0ff15h,0ff13h,0ff10h,0ff0eh,0ff0ch,0ff0bh,0ff09h,0ff08h
	DW	0ff06h,0ff05h,0ff04h,0ff03h,0ff03h,0ff02h,0ff02h,0ff02h
	DW	0ff02h,0ff02h,0ff02h,0ff02h,0ff03h,0ff03h,0ff04h,0ff05h
	DW	0ff06h,0ff08h,0ff09h,0ff0bh,0ff0ch,0ff0eh,0ff10h,0ff13h
	DW	0ff15h,0ff17h,0ff1ah,0ff1dh,0ff20h,0ff23h,0ff26h,0ff29h
	DW	0ff2ch,0ff30h,0ff34h,0ff37h,0ff3bh,0ff3fh,0ff44h,0ff48h
	DW	0ff4ch,0ff51h,0ff55h,0ff5ah,0ff5fh,0ff64h,0ff69h,0ff6eh
	DW	0ff73h,0ff78h,0ff7dh,0ff83h,0ff88h,0ff8eh,0ff93h,0ff99h
	DW	0ff9fh,0ffa5h,0ffabh,0ffb1h,0ffb6h,0ffbch,0ffc3h,0ffc9h
	DW	0ffcfh,0ffd5h,0ffdbh,0ffe1h,0ffe8h,0ffeeh,0fff4h,0fffah
	DW	00000h,00006h,0000ch,00012h,00018h,0001fh,00025h,0002bh
	DW	00031h,00037h,0003dh,00044h,0004ah,0004fh,00055h,0005bh
	DW	00061h,00067h,0006dh,00072h,00078h,0007dh,00083h,00088h
	DW	0008dh,00092h,00097h,0009ch,000a1h,000a6h,000abh,000afh
	DW	000b4h,000b8h,000bch,000c1h,000c5h,000c9h,000cch,000d0h
	DW	000d4h,000d7h,000dah,000ddh,000e0h,000e3h,000e6h,000e9h
	DW	000ebh,000edh,000f0h,000f2h,000f4h,000f5h,000f7h,000f8h
	DW	000fah,000fbh,000fch,000fdh,000fdh,000feh,000feh,000feh

cseg            ends
                END start

; seap was here :)


[ RETURN TO DIRECTORY ]