; 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 :)