********************************************************************
*
*       Landscape_Calc
*
*       Calculation routines for 'landscape' (68K)
*
*       assemble with:
*       phxass Landscape_Calc.s to Landscape_Calc.o smallcode
*
*       link with smalldata and smallcode enabled
*
*       © 1997 HAAGE&PARTNER Computer GmbH
*
********************************************************************


                include landscape.i
                include debug.i

DB_DEBUG        set     DB_OFF
;// XDEF / XREF
                xdef    CreateLandscape

                xref    PrepareFlight
                xref    _PowerPCBase
                xref    ChunkyBuffer
                xref    MapSize
                xref    MapSizeExp
                xref    MapMem
                xref    MapMemEnd
                xref    MapScale
                xref    browntab
                xref    Code
                xref    H
                xref    Iterations
                xref    Variation
                xref    Water
                xref    Shadow
                xref    LightDir
                xref    LightAngle
                xref    RanCount
                xref    Highest
                xref    Lowest
                xref    tantab
                xref    AreaWidth
                xref    AreaHeight
                xref    BitmapWidth
                xref    MapDim
                xref    MapHeight
;;/

                mc68020
                fpu
                section "Landscape_Code_Calc",code

* landscape generator

;// CreateLandscape (creates the landscape)
******************************************************************************
*
*       CreateLandscape
*
*       creates the landscape
*
******************************************************************************
CreateLandscape
                movem.l d2-d7,-(sp)
                fmovem.x        fp0-fp2,-(sp)
                bsr     SetRNDModeRZ            ;enable rounding mode RZ
                move.l  d0,d7                   ;save old FPCR
                move.l  MapMem,a0               ;-> map space
                lea     browntab,a1             ;-> math table
                moveq   #0,d0
                moveq   #0,d1
                moveq   #0,d2
                moveq   #0,d3
                move.b  MapSizeExp,d0           ;map size exponential
                move.b  Iterations,d1           ;iterations for subdivision
                move.b  H,d2                    ;fractal parameter
                move.b  RanCount,d3
                bsr     BuildLandscape          ;build landscape
                move.l  MapMem,a0               ;-> map space
                move.l  MapSize,d0              ;map size
                moveq   #0,d1
                move.b  Water,d1                ;water area
                bsr     ScaleLandscape          ;scale landscape
                move.l  MapMem,a0               ;-> map space
                move.l  MapSize,d0              ;map size
                moveq   #0,d1
                moveq   #0,d2
                move.b  Variation,d1            ;color variation
                move.b  RanCount,d2
                bsr     CreateColors            ;define colors
                tst.b   Shadow                  ;Shadow enabled?
                beq.b   .noshadow               ;no -> jump
                move.l  MapMem,a0               ;-> map space
                move.l  MapSize,d0              ;map size
                lea     tantab,a1               ;tangens table
                moveq   #0,d1
                moveq   #0,d2
                move.b  LightDir,d1             ;light direction
                move.b  LightAngle,d2           ;light angle
                bsr     CreateShadow            ;create shadow
.noshadow
                move.l  d7,d0                   ;get FPCR
                bsr     RestoreRNDMode          ;restore FPCR
                fmovem.x        (sp)+,fp0-fp2
                movem.l (sp)+,d2-d7
                rts
;;/
;// BuildLandscape (creates the landscape using a fractal algorithm)
******************************************************************************
*
*       BuildLandscape (a0,a1,d0,d1,d2,d3,d4)
*
*       creates the landscape using a fractal algorithm
*       height = average_height + random * 0.5^(Iterations*H)
*
*       In: a0 -> map memory
*           a1 -> math table for fractal computation
*           d0 = map border size (exp.)
*           d1 = number of iterations for subdivision
*           d2 = H (fractal parameter)
*           d3 = number of uniform random numbers for one normal random number
*
******************************************************************************
BuildLandscape
                movem.l d2-d7/a2-a6,-(sp)
                move.l  d3,d4
                move.l  d2,d3
                move.l  d1,d5
                lsl.l   #5,d5                   ;calc offset into math table
                add.l   d5,a1                   ;a1 -> current entry
                add.l   d3,d3                   ;calc offset for H parameter
                add.l   d3,a1                   ;a1 -> 0.5^(It.*H)<<14
                move.l  d4,a6
                move.l  d0,d5                   ;calculate number of iterations
                sub.l   d1,d5
                subq.l  #1,d5                   ;d5 = iteration loop count
                moveq   #1,d6                   ;calc map border size
                lsl.l   d0,d6
                move.l  d6,d0                   ;d0 = map border size
                moveq   #1,d6                   ;calc matrix loop counter
                moveq   #1,d7
                lsl.l   d1,d6                   ;d6 = vertical loop counter
                lsl.l   d1,d7                   ;d7 = horizontal loop counter
                move.l  d6,a2
                move.l  d5,d6
                move.l  d7,a3
                move.l  d0,d4                   ;calc map step value
                lsr.l   d1,d4
                add.l   d4,d4                   ;d4 = horizontal step value
                move.l  d4,d2
                mulu.l  d0,d2                   ;d2 = vertical step value
                move.l  d0,d5                   ;calc map mask values
                add.l   d0,d0
                mulu.l  d0,d5
                subq.l  #1,d0                   ;d0 = horizontal map mask
                subq.l  #1,d5                   ;d5 = vertical map mask
.loop
                move.l  d6,a5                   ;save iteration counter
                move.l  a2,d6                   ;restore vertical loop counter
                subq    #1,d6
                moveq   #0,d1                   ;reset vertical position
.loop2
                move.l  a3,d7                   ;restore horizontal loop counter
                subq    #1,d7
                moveq   #0,d3                   ;reset horizontal position
.loop3
                exg     a6,d6
                bsr     SetCenter               ;calc height of center field
                exg     a6,d6
                add.l   d4,d3                   ;increase horizontal position
                dbra    d7,.loop3
                add.l   d2,d1                   ;increase vertical position
                dbra    d6,.loop2
                lea     32(a1),a1               ;next math table entry
                move.l  a2,d6                   ;restore vertical loop counter
                subq    #1,d6
                moveq   #0,d1                   ;reset vertical position
.loop4
                move.l  a3,d7                   ;restore horizontal loop counter
                subq    #1,d7
                moveq   #0,d3                   ;reset horizontal position
.loop5
                exg     a6,d6
                bsr     SetUpper                ;calc height of upper field
                bsr     SetLeft                 ;calc height of left field
                exg     a6,d6
                add.l   d4,d3                   ;increase horizontal position
                dbra    d7,.loop5
                add.l   d2,d1                   ;increase vertical position
                dbra    d6,.loop4
                lea     32(a1),a1               ;next math table entry
                add.l   a3,a3                   ;double horizontal counter
                add.l   a2,a2                   ;double vertical counter
                lsr.l   #1,d4                   ;halve horizontal step value
                lsr.l   #1,d2                   ;halve vertical step value
                move.l  a5,d6                   ;restore iteration counter
                dbra    d6,.loop                ;next iteration
                movem.l (sp)+,d2-d7/a2-a6
                rts
;;/
;// SetCenter (sets the height of the center of a specific square)
******************************************************************************
*
*       SetCenter (a0,a1,d0,d1,d2,d3,d4,d5,d6)
*
*       sets the height of the center of a specific square
*
*       In: a0 -> map memory
*           a1 -> fractal exponent
*           d0 = horizontal map mask
*           d1 = vertical offset of the top border of the square
*           d2 = differential vertical offset
*           d3 = horizontal offset of the left border of the square
*           d4 = differential horizontal offset
*           d5 = vertical map mask
*           d6 = number of uniform random numbers for one normal random number
*
******************************************************************************
SetCenter
                movem.l d0-a2,-(sp)
                move.l  d6,a2
                moveq   #0,d6
                move.l  d3,d7
                add.l   d1,d7
                move    0(a0,d7.l),d7           ;read left top height
                ext.l   d7
                add.l   d7,d6                   ;add to d6
                move.l  d3,d7
                add.l   d4,d7
                and.l   d0,d7
                add.l   d1,d7
                move    0(a0,d7.l),d7           ;read right top height
                ext.l   d7
                add.l   d7,d6                   ;add to d6
                move.l  d1,d7
                add.l   d2,d7
                and.l   d5,d7
                add.l   d3,d7
                move    0(a0,d7.l),d7           ;read left bottom height
                ext.l   d7
                add.l   d7,d6                   ;add to d6
                move.l  d3,d7
                add.l   d4,d7
                and.l   d0,d7
                move.l  d1,d0
                add.l   d2,d0
                and.l   d5,d0
                add.l   d0,d7
                move    0(a0,d7.l),d7           ;read right bottom height
                ext.l   d7
                add.l   d7,d6                   ;add to d6
                asr.l   #2,d6                   ;calc average height
                move.l  d3,d7
                add.l   d1,d7
                lsr.l   #1,d4                   ;halve square width
                lsr.l   #1,d2                   ;halve square height
                add.l   d4,d7
                add.l   d2,d7                   ;calc offset into center
                add.l   d7,a0                   ;a0 -> center field
                move.l  a2,d7                   ;get random number count
                subq    #1,d7
                moveq   #0,d4                   ;init sum value
.loop
                bsr     URN30                   ;get random value
                sub.l   #$3fffffff,d0           ;scale random value
                asr.l   #4,d0
                add.l   d0,d4                   ;add to sum value
                dbra    d7,.loop
                swap    d4
                move    (a1),d0                 ;read fractal exponent
                muls    d0,d4                   ;multiply with random value
                moveq   #12,d0                  ;scale result
                asr.l   d0,d4
                add     d6,d4                   ;add to average height
                move    Highest,d0              ;check if highest point
                cmp     d0,d4
                ble.b   .cont
                move    d4,Highest              ;yes -> replace
.cont
                move    Lowest,d0               ;check if lowest point
                cmp     d0,d4
                bge.b   .cont2
                move    d4,Lowest               ;yes -> replace
.cont2
                move    d4,(a0)                 ;store height into center field
                movem.l (sp)+,d0-a2
                rts
;;/
;// SetUpper (sets the height of the upper point of a specific square)
******************************************************************************
*
*       SetUpper (a0,a1,d0,d1,d2,d3,d4,d5,d6)
*
*       sets the height of the upper point of a specific square
*
*       In: a0 -> map memory
*           a1 -> fractal exponent
*           d0 = horizontal map mask
*           d1 = vertical offset of the top border of the square
*           d2 = differential vertical offset
*           d3 = horizontal offset of the left border of the square
*           d4 = differential horizontal offset
*           d5 = vertical map mask
*           d6 = number of uniform random numbers for one normal random number
*
******************************************************************************
SetUpper
                movem.l d0-a2,-(sp)
                move.l  d6,a2
                moveq   #0,d6
                move.l  d3,d7
                add.l   d1,d7
                move    0(a0,d7.l),d7           ;read left top height
                ext.l   d7
                add.l   d7,d6                   ;add to d6
                move.l  d3,d7
                add.l   d4,d7
                and.l   d0,d7
                add.l   d1,d7
                move    0(a0,d7.l),d7           ;read right top height
                ext.l   d7
                add.l   d7,d6                   ;add to d6
                lsr.l   #1,d2                   ;halve square width
                lsr.l   #1,d4                   ;halve square height
                move.l  d3,d7
                add.l   d4,d7
                move.l  d1,d0
                add.l   d2,d0
                and.l   d5,d0
                add.l   d0,d7
                move    0(a0,d7.l),d7           ;read center bottom height
                ext.l   d7
                add.l   d7,d6                   ;add to d6
                move.l  d3,d7
                add.l   d4,d7
                move.l  d1,d0
                sub.l   d2,d0
                and.l   d5,d0
                add.l   d0,d7
                move    0(a0,d7.l),d7           ;read center top height
                ext.l   d7
                add.l   d7,d6                   ;add to d6
                asr.l   #2,d6                   ;calc average height
                move.l  d3,d7
                add.l   d4,d7
                add.l   d1,d7                   ;calc offset to upper field
                add.l   d7,a0                   ;a0 -> upper field
                move.l  a2,d7
                subq    #1,d7
                moveq   #0,d4
.loop
                bsr     URN30                   ;same as 'SetCenter'
                sub.l   #$3fffffff,d0
                asr.l   #4,d0
                add.l   d0,d4
                dbra    d7,.loop
                swap    d4
                move    (a1),d0
                muls    d0,d4
                moveq   #12,d0
                asr.l   d0,d4
                add     d6,d4
                move    Highest,d0
                cmp     d0,d4
                ble.b   .cont
                move    d4,Highest
.cont
                move    Lowest,d0
                cmp     d0,d4
                bge.b   .cont2
                move    d4,Lowest
.cont2
                move    d4,(a0)                 ;store height into upper field
                movem.l (sp)+,d0-a2
                rts
;;/
;// SetLeft (sets the height of the left point of a specific square)
******************************************************************************
*
*       SetLeft (a0,a1,d0,d1,d2,d3,d4,d5,d6)
*
*       sets the height of the left point of a specific square
*
*       In: a0 -> map memory
*           a1 -> fractal exponent
*           d0 = horizontal map mask
*           d1 = vertical offset of the top border of the square
*           d2 = differential vertical offset
*           d3 = horizontal offset of the left border of the square
*           d4 = differential horizontal offset
*           d5 = vertical map mask
*           d6 = number of uniform random numbers for one normal random number
*
******************************************************************************
SetLeft
                movem.l d0-a2,-(sp)
                move.l  d6,a2
                moveq   #0,d6
                move.l  d3,d7
                add.l   d1,d7
                move    0(a0,d7.l),d7           ;read left top height
                ext.l   d7
                add.l   d7,d6                   ;add to d6
                move.l  d1,d7
                add.l   d2,d7
                and.l   d5,d7
                add.l   d3,d7
                move    0(a0,d7.l),d7           ;read left bottom height
                ext.l   d7
                add.l   d7,d6                   ;add to d6
                lsr.l   #1,d4                   ;halve square width
                lsr.l   #1,d2                   ;halve square height
                move.l  d1,d7
                add.l   d2,d7
                move.l  d3,d5
                add.l   d4,d5
                and.l   d0,d5
                add.l   d5,d7
                move    0(a0,d7.l),d7           ;read center right height
                ext.l   d7
                add.l   d7,d6                   ;add to d6
                move.l  d1,d7
                add.l   d2,d7
                move.l  d3,d5
                sub.l   d4,d5
                and.l   d0,d5
                add.l   d5,d7
                move    0(a0,d7.l),d7           ;read center left height
                ext.l   d7
                add.l   d7,d6                   ;add to d6
                asr.l   #2,d6                   ;calc average height
                move.l  d1,d7
                add.l   d2,d7
                add.l   d3,d7                   ;calc offset to left field
                add.l   d7,a0                   ;a0 -> left field
                move.l  a2,d7
                subq    #1,d7
                moveq   #0,d4
.loop
                bsr     URN30                   ;same as 'SetCenter'
                sub.l   #$3fffffff,d0
                asr.l   #4,d0
                add.l   d0,d4
                dbra    d7,.loop
                swap    d4
                move    (a1),d0
                muls    d0,d4
                moveq   #12,d0
                asr.l   d0,d4
                add     d6,d4
                move    Highest,d0
                cmp     d0,d4
                ble.b   .cont
                move    d4,Highest
.cont
                move    Lowest,d0
                cmp     d0,d4
                bge.b   .cont2
                move    d4,Lowest
.cont2
                move    d4,(a0)                 ;store height into left field
                movem.l (sp)+,d0-a2
                rts
;;/
;// ScaleLandscape (scales the landscape)
******************************************************************************
*
*       ScaleLandscape (a0,d0,d1)
*
*       scales the landscape
*
*       In: a0 -> map memory
*           d0 = map border size
*           d1 = water area
*
******************************************************************************
ScaleLandscape
                movem.l d2-d7,-(sp)
                move    Highest,d2              ;read highest point
                move    d2,d4
                move    Lowest,d3               ;read lowest point
                sub     d3,d2                   ;calc difference
                mulu    d1,d2
                divu    #100,d2
                add     d2,d3                   ;d3 = water NULL height
                sub     d3,d4                   ;d4 = height above water
                move    d0,d6
                move    d0,d7
                subq    #1,d6                   ;create loop counters
                subq    #1,d7
                move    d7,d5
.loop
                move    d5,d7
.loop2
                move    (a0),d0                 ;read height
                sub     d3,d0                   ;shift up/down height
                muls    #255,d0                 ;scale height
                divs    d4,d0
                move    d0,(a0)+                ;write new height
                dbra    d7,.loop2
                dbra    d6,.loop
                movem.l (sp)+,d2-d7
                rts
;;/
;// CreateColors (defines the color values for each zone)
******************************************************************************
*
*       CreateColors (a0,d0,d1,d2)
*
*       defines the color values for each zone
*
*       In: a0 -> map memory
*           d0 = map border size
*           d1 = variation parameter (0 = standard)
*           d2 = number of uniform random numbers for one normal random number
*
******************************************************************************
CreateColors
                movem.l d2-d7,-(sp)
                move.l  d2,a1
                move.l  d0,d7
                move.l  d0,d2
                mulu.l  d2,d2
                add.l   d2,d2                   ;d2 = map full size (in bytes)
                move.l  d0,d4
                add.l   d4,d4                   ;d4 = line size in bytes
                sub.l   d4,d2                   ;d2 = offset from last to first
                neg.l   d2                      ;line
                move.l  d4,d3                   ;d3 = offset from rightmost
                neg.l   d3                      ;to leftmost point
                subq    #2,d7                   ;create loop counters (one less
                move    d7,d5                   ;than usual)
                move.l  d0,d6
                subq    #2,d6
                exg     d2,a1
.loop
                move    d5,d7
.loop2
                moveq   #0,d0
                add     (a0),d0                 ;calc average height of
                add     2(a0),d0                ;corresponding polygon
                add     0(a0,d4.l),d0
                add     2(a0,d4.l),d0
                asr     #2,d0                   ;d0 = average height
                bsr     DefineColor             ;assign color
                addq.l  #2,a0                   ;next height
                dbra    d7,.loop2
                moveq   #0,d0                   ;special case: polygon between
                add     (a0),d0                 ;rightmost and leftmost point
                add     2(a0),d0
                add     0(a0,d4.l),d0
                add     2(a0,d3.l),d0
                asr     #2,d0
                bsr     DefineColor
                addq.l  #2,a0
                dbra    d6,.loop
                move    d5,d7
.loop3
                moveq   #0,d0                   ;special case: polygons between
                add     (a0),d0                 ;bottom line and top line
                add     2(a0),d0
                add     0(a0,a1.l),d0
                add     2(a0,a1.l),d0
                asr     #2,d0
                bsr     DefineColor
                addq.l  #2,a0
                dbra    d7,.loop3
                moveq   #0,d0                   ;special case: polygon between
                add     (a0),d0                 ;right-bottom point and left-top
                add     2(a0,d3.l),d0           ;point
                add     0(a0,a1.l),d0
                add.l   a1,d3
                add     0(a0,d3.l),d0
                asr     #2,d0
                bsr     DefineColor
                movem.l (sp)+,d2-d7
                rts
;;/
;// DefineColor (calulates one color value)
******************************************************************************
*
*       DefineColor (a0,d0,d1,d2)
*
*       defines the color values for each zone
*
*       In: a0 -> 16 bit height element
*           d0 = average height of corresponding polygon
*           d1 = variation parameter
*           d2 = number of uniform random numbers for one normal random number
*
******************************************************************************
DefineColor
                movem.l d1-d7/a1,-(sp)
                move    (a0),d0                 ;read height
                move    d0,d4
                move    d0,d5
                move    d1,d6
                tst     d6                      ;any variation wanted?
                beq     .novariation            ;no -> jump
                move    d2,d7                   ;number of random numbers
                subq    #1,d7
                sub.l   a1,a1                   ;init sum value
.loop
                bsr     URN30                   ;calc random value
                sub.l   #$3fffffff,d0           ;scale random value
                asr.l   #4,d0
                add.l   d0,a1                   ;add to sum
                dbra    d7,.loop
                move.l  a1,d0
                swap    d0
                muls    d0,d6                   ;multiply with variation value
                asr.l   #8,d6                   ;scale result
                asr.l   #6,d6
                tst     d5                      ;polygon in water?
                ble.b   .water1                 ;yes -> jump
                add     d6,d4                   ;add variation to height
                bgt.b   .cont                   ;still over water? -> jump
                moveq   #1,d4                   ;lowest point above water
                bra.b   .novariation
.cont
                cmp     #255,d4                 ;overflow?
                ble.b   .novariation            ;no -> jump
                move    #255,d4                 ;limit to highest point
                bra.b   .novariation
.water1
                add     d6,d4                   ;add variation to height
                ble.b   .novariation            ;still under water? -> jump
                moveq   #0,d4                   ;least deep water
.novariation
                tst     d5                      ;polygon in water?
                ble.b   .water                  ;yes -> jump
                sub     #255,d4
                neg     d4
                move.b  d5,(a0)                 ;store height in first byte
                asr     #2,d4                   ;calc color value
                bne.b   .cont2                  ;not zero?
                moveq   #1,d4                   ;if zero than one (no water)
.cont2
                move.b  d4,1(a0)                ;store color into second byte
                bra.b   .end
.water
                neg     d4
                asr     #2,d4
                add     #64,d4                  ;calc color value
                clr.b   (a0)                    ;height = 0
                cmp     #127,d4                 ;if water too deep
                ble.b   .cont3
                moveq   #127,d4                 ;limit to darkest blue
.cont3
                move.b  d4,1(a0)                ;store color
.end
                movem.l (sp)+,d1-d7/a1
                rts
;;/
;// CreateShadow (calculates the shadow)
******************************************************************************
*
*       CreateShadow (a0,a1,d0,d1,d2)
*
*       divides the landscape in smaller parts
*
*       In: a0 -> map memory
*           a1 -> tangens table for tangens calculation
*           d0 = map border size
*           d1 = light direction (0-3)
*           d2 = light angle (0-89)
*
******************************************************************************
CreateShadow
                movem.l d2-d7,-(sp)
                moveq   #8,d3                   ;calc tan (lightangle)
                lsl     d3,d2
                ext.l   d2
                divu    #90,d2
                add     d2,d2
                move    0(a1,d2.w),d4           ;d4 = tan (angle) << 7
                move.l  d0,d3
                mulu.l  d0,d0
                add.l   d0,d0                   ;d0 = map size in bytes
                tst     d1                      ;case direction
                beq.b   .left
                cmp     #1,d1
                beq.b   .top
                cmp     #2,d1
                beq.b   .right
.bottom
                add.l   d0,a0                   ;rays from bottom
                lea     -2(a0),a0               ;a0 -> last element in map
                move.l  d3,d6
                add.l   d6,d6
                neg.l   d6                      ;vertical step value
                moveq   #-2,d5                  ;horizontal line step value
                bra.b   .cont
.right
                add.l   d0,a0                   ;rays from right
                lea     -2(a0),a0               ;a0 -> last element in map
                move.l  d3,d5
                add.l   d5,d5
                neg.l   d5                      ;horizontal step value
                moveq   #-2,d6                  ;vertical line step value
                bra.b   .cont
.top
                move.l  d3,d6
                add.l   d6,d6
                moveq   #2,d5
                bra.b   .cont
.left
                moveq   #2,d6
                move.l  d3,d5
                add.l   d5,d5
.cont
                move.l  d3,d7
                subq    #1,d7
                move.l  d3,d0
                move.l  d4,d1
                ext.l   d1
                move.l  d6,d2
.loop
                bsr     ShadowLine              ;shadow one line
                add     d5,a0                   ;go to next line
                dbra    d7,.loop
                movem.l (sp)+,d2-d7
                rts
;;/
;// ShadowLine (shadows one map line)
******************************************************************************
*
*       ShadowLine (a0,d0,d1,d2)
*
*       shadows one map line
*
*       In: a0 -> map memory (or last element)
*           d0 = map border size
*           d1 = vertical difference
*           d2 = map step value
*
******************************************************************************
ShadowLine
                movem.l d0-a2,-(sp)
                move.l  a0,a1
                move.l  d0,d7
                move.l  d1,d4
                move.l  d2,d6
                moveq   #0,d2                   ;init point counter
.loop
                moveq   #0,d0
                move.b  (a0),d0                 ;read height
                lsl     #7,d0                   ;shift left
                sub     d4,d0                   ;subtract tangens
.entry
                add     d6,a0                   ;goto next point
                addq    #1,d2
                cmp     d7,d2                   ;wrap around?
                bne.b   .cont                   ;no -> jump
                move.l  a1,a0                   ;begin again
.cont
                moveq   #0,d1
                move.b  (a0),d1                 ;read height of next pixel
                lsl     #7,d1
                cmp     d0,d1                   ;below shadow line?
                blt.b   .shade                  ;yes -> shade point
                cmp     d7,d2                   ;if no shadow and line done
                bgt.w   .end                    ;-> exit
                bra.w   .loop                   ;try next point
.shade
                moveq   #0,d3
                move.b  1(a0),d3                ;read color value
                cmp     #127,d3                 ;already shaded?
                bgt.b   .next                   ;yes -> jump
                add     #128,d3                 ;shade point
                move.b  d3,1(a0)                ;store new color value
.next
                sub     d4,d0                   ;subtract tangens
                bra.w   .entry                  ;shade next point
.end
                movem.l (sp)+,d0-a2
                rts
;;/
;// SetRNDModeRZ (set rounding mode for the FPU to 'round to zero')
******************************************************************************
*
*       d0 = SetRNDModeRZ
*
*       set rounding mode for the FPU to 'round to zero'
*
*       Out: d0 = old FPCR value
*
******************************************************************************
SetRNDModeRZ
                fmove.l fpcr,d0
                move.l  d0,d1
                or.l    #$00000010,d1
                fmove.l d1,fpcr
                rts
;;/
;// RestoreRNDMode (restores rounding mode for the FPU)
******************************************************************************
*
*       RestoreRNDMode (d0)
*
*       restores rounding mode for the FPU
*
*       In:  d0 = FPCR value to be restored
*
******************************************************************************
RestoreRNDMode
                fmove.l d0,fpcr
                rts
;;/
;// URN30 (calculates one uniform random number)
******************************************************************************
*
*       d0 = URN30
*
*       calculates one uniform random number (rounding mode for the FPU
*       MUST be set to 'round to zero')
*       'Code' must hold a start random value if it's first used
*       URN30 algorithm is taken: Xn+1 = 630360016 * Xn mod $7fffffff
*       d1-d3,fp0-fp2 are trashed
*
*       Out: d0 = new random number (0-$7ffffffe)
*
******************************************************************************
URN30
                move.l  Code,d0                 ;get previous result/start res.
                move.l  #630360016,d1
                move.l  #$7fffffff,d2
                fmove.l d1,fp0
                fmove.l d2,fp1
                fmove.l d0,fp2
                fmul    fp0,fp2
                mulu.l  d1,d0
                fdiv    fp1,fp2
                fmove.l fp2,d3
                mulu.l  d2,d3
                sub.l   d3,d0                   ;d0 = new random number
                move.l  d0,Code                 ;store actual result
                rts
;;/

