home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Virtual Reality Zone
/
VRZONE.ISO
/
mac
/
PC
/
REND386
/
VR386
/
INTRIG.ASM
< prev
next >
Wrap
Assembly Source File
|
1994-01-10
|
8KB
|
406 lines
TITLE INTRIG - Triginometric routines in fixed point
COMMENT $
// All code and algorithms used are by Dave Stampe.
// These are some of the fastest integer trig routines
// in 32 bit fixed point around, and are accurate to 3 LSB
// See INTMATH.H for formats
/*
This code is part of the VR-386 project, created by Dave Stampe.
VR-386 is a desendent of REND386, created by Dave Stampe and
Bernie Roehl. Almost all the code has been rewritten by Dave
Stampre for VR-386.
Copyright (c) 1994 by Dave Stampe:
May be freely used to write software for release into the public domain
or for educational use; all commercial endeavours MUST contact Dave Stampe
(dstampe@psych.toronto.edu) for permission to incorporate any part of
this software or source code into their products! Usually there is no
charge for under 50-100 items for low-cost or shareware products, and terms
are reasonable. Any royalties are used for development, so equipment is
often acceptable payment.
ATTRIBUTION: If you use any part of this source code or the libraries
in your projects, you must give attribution to VR-386 and Dave Stampe,
and any other authors in your documentation, source code, and at startup
of your program. Let's keep the freeware ball rolling!
DEVELOPMENT: VR-386 is a effort to develop the process started by
REND386, improving programmer access by rewriting the code and supplying
a standard API. If you write improvements, add new functions rather
than rewriting current functions. This will make it possible to
include you improved code in the next API release. YOU can help advance
VR-386. Comments on the API are welcome.
CONTACT: dstampe@psych.toronto.edu
*/
$
.MODEL large
.CODE INTMATH
;include 3dstruct.inc
.DATA
extrn _sintable ; arrays of 258 dwords
extrn _atantable ; <3.29> args -> <16.16> angle
; # define XFSC 536870912 /* 2**29 for shifting xform coeffs to long */
.CODE INTMATH
; /*************** INTEGER SINE, COSINE **************/
;/* return(XFSC * sin(3.14159/180*angle/65536.0));*/
;long isine(long angle) /* returns <3.29> sine of <16.16> angle */
angle equ [bp+8] ; arguments
PUBLIC _isine
_isine proc far
.386
push ebp
mov ebp,esp
push esi
push edi
push ecx
mov eax,angle
mov edx,5B05B05Bh
imul edx
shrd eax,edx,29 ;/* convert so 90 deg -> 256<<16 */
adc eax,0 ;/* 2 upper bits = quadrant */
mov angle,eax ;/* 16 lsb used to interp. */
mov ebx,eax
mov esi,eax
mov edx,eax
shr ebx,14 ;/* 8 bit 2.84*degree index */
and ebx,03FCh
test esi,01000000h
jz forward
not edx
xor ebx,03FCh
forward:
les di,DWORD PTR _sintable
mov ecx,DWORD PTR es:[bx+di]
mov eax,DWORD PTR es:[bx+di+4] ;/* lookup this, next entry */
sub eax,ecx
and edx,0000FFFFh ;/* compute interp. factor */
mul edx
shrd eax,edx,16
adc ecx,eax ;/* add in */
test esi,02000000h
jz positive
neg ecx
positive:
mov eax,ecx ;return result in dx:ax
shld edx,eax,16 ; dlete to rtn in eax
pop ecx
pop edi
pop esi
mov esp,ebp
pop ebp
ret
_isine endp
; long icosine(long angle)
angle equ [bp+8] ; arguments
PUBLIC _icosine
_icosine proc far
.386
push ebp
mov ebp,esp
mov eax,angle
add eax,005A0000h ; just ask for sine(90+angle)
push eax
call far ptr _isine
add esp,4
mov esp,ebp
pop ebp
ret
_icosine endp
;/************ INVERSE TRIG FUNCTIONS *************/
;long arcsine(long x) /* <3.29> args -> <16.16> angle */
;{ /* have to use table in reverse */
x equ [bp+8] ; arguments
sign equ [bp-2] ; locals
PUBLIC _arcsine
_arcsine proc far
.386
push ebp
mov ebp,esp
sub esp,14
push esi
push edi
push ecx
mov WORD PTR sign,0
mov eax,x
or eax,eax
je ret_eax ; 0->0 mapping common
jg posarg
inc WORD PTR sign ; negative argument
neg eax
posarg:
cmp eax,20000000h ; 1.0 or greater?
jl notone
mov eax,005A0000h ; 90<<16 returned
jmp ret_signed
notone:
les bx,DWORD PTR _sintable ; begin binary search
xor ecx,ecx
cmp eax,es:[bx+512]
jb b1
add ebx,512
or ecx,00800000h
b1:
cmp eax,es:[bx+256]
jb b2
add ebx,256
or ecx,00400000h
b2:
cmp eax,es:[bx+128]
jb b3
add ebx,128
or ecx,00200000h
b3:
cmp eax,es:[bx+64]
jb b4
add ebx,64
or ecx,00100000h
b4:
cmp eax,es:[bx+32]
jb b5
add ebx,32
or ecx,00080000h
b5:
cmp eax,es:[bx+16]
jb b6
add ebx,16
or ecx,00040000h
b6:
cmp eax,es:[bx+8]
jb b7
add ebx,8
or ecx,00020000h
b7:
cmp eax,es:[bx+4]
jb b8
add ebx,4
or ecx,00010000h
b8:
sub eax,es:[bx] ; OK, got entry lower than x
je nointerp ; compute difference
mov esi,es:[bx+4] ; and interpolate
sub esi,es:[bx]
je okinterp
cmp eax,esi
jb okinterp
add ecx,00010000h
jmp nointerp
okinterp:
cdq
shld edx,eax,16
shl eax,16
idiv esi
mov cx,ax
nointerp:
mov eax,05A000000h ;/* convert to <16.16> angle */
imul ecx
mov eax,edx
ret_signed: ; add sign to result
test WORD PTR sign,-1
je ret_eax
neg eax
ret_eax:
shld edx,eax,16 ; eax -> dx:ax
pop ecx
pop edi
pop esi
mov esp,ebp
pop ebp
ret
_arcsine endp
;long arccosine(long x)
x equ [bp+8] ; arguments
PUBLIC _arccosine
_arccosine proc far
.386
push ebp
mov ebp,esp
push DWORD PTR x
call far ptr _arcsine
add esp,4
not dx ; negate dx:ax
not ax
add ax,1
adc dx,90 ; (90*65536L - arcsine(x));
mov esp,ebp
pop ebp
ret
_arccosine endp
; /********** INVERSE TANGENT **********/
;/* we can use a table for atan */
;/* as slope is fairly constant */
;long arctan2(long y, long x)
y equ [bp+8] ; arguments
x equ [bp+12]
sx equ [bp-2] ; locals (quadrant flags)
sy equ [bp-4]
g45 equ [bp-6]
PUBLIC _arctan2
_arctan2 proc far
.386
push ebp
mov ebp,esp
sub esp,12
push esi
push edi
push ecx
mov WORD PTR sx,0
mov WORD PTR sy,0
mov WORD PTR g45,0
mov eax,DWORD PTR x
or eax,eax
jge x_pos
inc WORD PTR sx
neg eax
x_pos:
mov edx,DWORD PTR y
or edx,edx
jge y_pos
inc WORD PTR sy
neg edx
y_pos:
or eax,eax
jne nonzero_x
mov eax,005A0000h ; 90<<16
jmp sign_eax
nonzero_x:
or edx,edx
jne nonzero_y
mov eax,0 ; 0
jmp sign_eax
nonzero_y:
cmp edx,eax
jne not45deg
mov eax,002D0000h ;/* 45 degrees */
jmp sign_eax
not45deg:
jl not_ygtx
inc WORD PTR g45 ; which quadrant?
xchg eax,edx
not_ygtx:
mov ebx,eax ; save abs(x)
xor eax,eax
shrd eax,edx,8 ;/* shift so it will divide OK */
shr edx,8
idiv ebx ;/* y/x << 24 */
mov ebx,eax
shr ebx,14 ;/* top 8 bits are index into table */
and ebx,03FCh
les di, DWORD PTR _atantable
mov ecx,DWORD PTR es:[bx+di]
mov esi,DWORD PTR es:[bx+di+4]
sub esi,ecx
and eax,0000FFFFh ;/* bottom 16 bits interpolate */
mul esi
shr eax,16
add eax,ecx
test WORD PTR g45,-1
je firstquad
neg eax
add eax,005A0000h ; result = 90*65536L - result;
firstquad:
sign_eax:
test WORD PTR sx,-1 ; put result in proper quadrant
je secquad
sub eax,00B40000h
test WORD PTR sy,-1
jne out_eax
neg eax
jmp out_eax
secquad:
test WORD PTR sy,-1
je out_eax
neg eax
out_eax:
shld edx,eax,16 ; eax -> dx:ax
pop ecx
pop edi
pop esi
mov esp,ebp
pop ebp
ret
_arctan2 endp
end