; Date:     Wed, 15 May 1996 22:27:55 -0400 (EDT)
; From:     Jingyang Xu  [br00416@bingsuns.cc.binghamton.edu]
; Subject:  LZ: Trig Routines: SIN/COS/TAN

; Someone asked me about these and here are the bug-free version of my
; sin/cos/tan routines:

; Note that sin and cos uses the same table and tan uses its own table.
; The arguments to sinx and cosx are: a=multiplier bc=angle
; and the return is now in bc: b=integer part c=fractional part.
; So bc is a 16 bit signed number, the key here is signed - if the high bit
; of b is set, that means bc is the twos complement of the positive value
; of bc.
; For the tangent routine. de is the multiplier (this is a 16 bit
; multiplier) and hl is the angle. I think it returns the result in hl, in
; the same format as that for bc.

AdjustAngleinBC:
	xor     a
	cp      b
	jr      z,Alldone
	ld      h,b
	ld      l,c
	ld      bc,360
	and     a
	sbc     hl,bc
	jr      nc,AAHalfDone
	add     hl,bc
AAHalfDone:
	ld      b,h
	ld      c,l
	jr      Alldone
Alldone:
	ret

sinx:
	push    af              ;save argument
	ld      d,1             ;d=1, use for later
	ld      hl,180
	and     a               ;clear carry
	sbc     hl,bc
	jr      nc,LessE180    ;is angle greater than 180 degrees?

Great180:            
	ld      h,b             ;
	ld      l,c             ;load bc into hl
	ld      bc,180          ;
	and     a               ; bc=bc-180
	sbc     hl,bc           ;
	ld      b,h             ; 
	ld      c,l             ;load hl into bc
	inc     d               ; d=2, remember negated
LessE180:          ;0<=bc<=180 -> 0 is in b and 0<=c<=180
	ld      a,d             ;save d
	ld      de,(PROGRAM_ADDR)
	ld      hl,Trig_Look_Up ;hl=addr of table
	add     hl,de
	ld      d,a             ;restore d
	ld      a,c             ;load angle into accumulator
	cp      90              ;is it 90 degrees?
	jr      nz,not90
	ld      a,128           ;if 90 degrees, sin90=1
	jr      sinloaded
not90:
	sub     90
	jr      nc,Greater90    ;is angle less than or greater than 90
Less90:
	add     hl,bc           ;if less than, go directly to table
	ld      a,(hl)
	jr      sinloaded
Greater90:
	ld      a,180           ;if greater, sin(x)=sin(180-x)
	sub     c               ;subtract from 180
	ld      c,a
	add     hl,bc           ;read from table
	ld      a,(hl)
sinloaded:                      ;x/128 is in a, d will determine sign
	ld      b,a             ;save result
	pop     af              ;get multiplicand back
	bit     7,a             ;test to see if a is negative
	jr      z,apositive
	neg                     ;if negative, negate
	inc     d               ;store negative memory in d
apositive:                      ;now we want a*b/128
	ld      e,a             ;save a
	ld      a,b             ;
	cp      0               ;see if e=0
	jr      z,multiplyby0   ;
	ld      c,0
	xor     a
sinmultiplyloop:
	add     a,e
	jr      nc,nocarry      ;multipy a by b
	inc     c               ;16bit result in ca
nocarry:
	djnz    sinmultiplyloop         
	rl      a               ;shift ca to the left
	rl      c               ;ca/128 now in c
	ld      b,c
	ld      c,a
	dec     d
        jr      z,sinxend
        and     a
        ld      hl,0
        sbc     hl,bc
        ld      b,h
        ld      c,l
	dec     d
        jr      z,sinxend
        and     a
        ld      hl,0
        sbc     hl,bc
        ld      b,h
        ld      c,l
	dec     d
	jr      z,sinxend
multiplyby0:
	ld      bc,0
sinxend:
	ret

cosx:
	ld      hl,90
	add     hl,bc
	ld      b,h
	ld      c,l
	ld      d,a
	CALL_(AdjustAngleinBC)
	ld      a,d
	CALL_(sinx)
	ret           

Trig_Look_Up:
	.db     0,2,4,6,8,11,13,15,17,20
	.db     22,24,26,28,30,33,35,37,39,41
	.db     43,45,47,50,52,54,56,58,60,62
	.db     64,65,67,69,71,73,75,77,78,80
	.db     82,83,85,87,88,90,92,93,95,96
	.db     98,99,100,102,103,104,106,107,108,109
	.db     110,111,113,114,115,116,116,117,118,119
	.db     120,121,121,122,123,123,124,124,125,125
	.db     126,126,126,127,127,127,127,127,127,127

tanx:                                   ;multiplier in de, angle in hl
        push    de
        push    de                      ;save multiplier
        
        ld      b,h                     ;make another copy of angle in bc
        ld      c,l                     ;
        
        ld      de,180                  ;subtract 180 from
        and     a                       ;angle to see if it is
        sbc     hl,de                   ;greater than 180

        jr      c,tanLess180            ;if not, goto tanless180
        
        ld      b,h                     ;if greater than 180, load angle
        ld      c,l                     ;minus 180 into bc
tanLess180:                             ;bc has the semi-reference
        inc     d                       ;load 1 into d
        ld      hl,90                   ;subtract angle from 90
        and     a                       ;to see if it is less than
        sbc     hl,bc                   ;90
        jr      nc,tanLess90            ;if so, jump to tanless90
        ld      hl,180                  ;if greater, load 180 into hl
        and     a                       ;subtract angle from it
        sbc     hl,bc                   ;
        inc     d                       ;load 2 into d
        ld      b,h                     ;save final reference in bc
        ld      c,l                     ;
tanLess90:                              ;already has reference angle
        sla     c                       ;multiply bc by 2
        rl      b                       ;
        ld      a,d                     ;preserves d
        ld      de,(PROGRAM_ADDR)       ;reference the table
        ld      hl,Tan_Table            ;
        add     hl,de                   ;
        add     hl,bc                   ;
        ld      d,(hl)                  ;
        inc     hl                      ;load result into de
        ld      e,(hl)                  ;
        ld      h,a                     ;whatever we had in d before
        dec     h                       ;see if h=1 or 2
        jr      z,tanNotNegative        ;if 1, positive
        set     7,d                     ;if result negative, then tell it so
tanNotNegative:                         ;guess what
        pop     hl                      ;get multiplier
        CALL_(MulDEbyHL)                ;multiply the result by the multiplier
        push    af
        ld      h,c
        ld      l,d
        bit     7,e
        jr      z,TanRoundDown
        inc     hl
TanRoundDown:
        pop     af
        jr      z,ResPositive
        ex      de,hl
        ld      hl,0
        and     a
        sbc     hl,de
        pop     de
        ret
ResPositive:                  
        pop     de
        ret

MulDEbyHL:
        ld      ix,TempLine
        bit     7,d
        jr      z,DEPositive
        res     7,d
        bit     7,h
        jr      z,HLPositive
        res     7,h
        jr      DEPositive
HLPositive:
        set     7,h
DEPositive:
        ld      (ix+0),h
        ld      (ix+1),l
        ld      b,8
        xor     a
        ld      c,a
        ld      hl,0
MulLoop1:        
        rrc     (ix+1)
        jr      nc,NoAdd1
        add     hl,de
        adc     a,c
NoAdd1:
        sla     e
        rl      d
        rl      c
        djnz    MulLoop1
        ld      b,7
        ld      e,d
        ld      d,c
        ld      c,0
        rl      c
        ld      (ix+5),l
        ld      l,h
        ld      h,a
        xor     a
MulLoop2:        
        rrc     (ix+0)
        jr      nc,NoAdd2
        add     hl,de
        adc     a,c
NoAdd2:
        sla     e
        rl      d
        rl      c
        djnz    MulLoop2
        ld      b,a
        ld      c,h
        ld      d,l
        ld      e,(ix+5)
        bit     0,(ix+0)
        ret
        
Tan_Table:
        .db     0,0,0,4,0,9,0,13,0,18,0,22,0,27,0,31,0,36,0,41
        .db     0,45,0,50,0,54,0,59,0,64,0,69,0,73,0,78,0,83,0,88
        .db     0,93,0,98,0,103,0,109,0,114,0,119,0,125,0,130,0,136,0,142
        .db     0,148,0,154,0,160,0,166,0,173,0,179,0,186,0,193,0,200,0,207
        .db     0,215,0,223,0,231,0,239,0,247,1,0,1,9,1,19,1,28,1,38
        .db     1,49,1,60,1,72,1,84,1,96,1,110,1,124,1,138,1,154,1,170
        .db     1,187,1,206,1,225,1,246,2,13,2,37,2,63,2,91,2,122,2,155
        .db     2,191,2,231,3,20,3,69,3,125,3,187,4,3,4,85,4,180,5,37
        .db     5,172,6,80,7,30,8,37,9,132,11,110,14,77,19,21,28,163,57,74

