********************************************************************
*
*       CyberMand_Calc
*
*       calculation routines for CyberMand (68K FPU version)
*
*       assemble with:
*       phxass CyberMand_Calc.s to CyberMand_Calc.o smallcode
*
*       link with smalldata and smallcode enabled
*
*       © 1997 HAAGE&PARTNER Computer GmbH
*
********************************************************************

                include graphics/gfx.i

;// XREF / XDEF
                xref    ScrDepth
                xref    AreaWidth
                xref    AreaHeight
                xref    LeftPos
                xref    TopPos
                xref    RightPos
                xref    BottomPos
                xref    Radius
                xref    Iterations
                xref    Precision
                xref    ChunkyBuffer
                xref    HiddenBitmap
                xref    ActualBitmap
                xref    ZoomIn
                xref    ZoomOut
                xref    Zoom
                xref    MouseDX
                xref    MouseDY
                xref    Translation
                xref    WindowMode
                xref    TransTable
                xref    P_SINGLE
                xref    P_DOUBLE
                xref    _SCREENHEIGHT
                xref    _SCREENWIDTH
                xref    _SCREENDEPTH

                xdef    Calculation
                xdef    ChunkyToPlanar
                xdef    FX
;;/


                section "CyberMand_Calc",code

                near    a4,-1
                mc68020
                fpu

;// Calculation (calculates one mandelbrot frame)
******************************************************************************
*
*       Calculation
*
*       calculates one mandelbrot frame with the formula z=z^2+c
*       the results are written into the chunkybuffer (at the left/top corner)
*
******************************************************************************
Calculation
                movem.l d0-a1,-(sp)
                fmovem  fp0-fp7,-(sp)
                move.l  ChunkyBuffer,a0
                fmove.d LeftPos,fp2             ;fp2 = c real part
                fmove.d TopPos,fp3              ;fp3 = c imaginary part
                fmove.d RightPos,fp4
                fmove.d BottomPos,fp5
                fsub    fp2,fp4                 ;calc width of mandel area
                fsub    fp3,fp5                 ;calc height of mandel area
                fmove.w AreaWidth,fp6
                fmove.w AreaHeight,fp7
                fdiv    fp6,fp4                 ;calc delta x (real)
                fdiv    fp7,fp5                 ;calc delta y (imaginary)
                fmove.d fp4,DeltaX              ;save delta x
                fmove.d fp5,DeltaY              ;save delta y
                fmove.d Radius,fp6              ;read termination radius
                move    Iterations,d5
                subq    #1,d5
                move    d5,d4
                move    AreaHeight,d7
                subq    #1,d7
.loop
                move    AreaWidth,d6
                subq    #1,d6
.loop2
                move    d4,d5
                fmove   #0,fp0                  ;fp0 = z real part
                fmove   #0,fp1                  ;fp1 = z imaginary part
.loop3
                fmove   fp1,fp7                 ;save z imag
                fmul    fp0,fp1                 ;z real * z imag
                fmul    fp0,fp0                 ;(z real)^2
                fmul    fp7,fp7                 ;(z imag)^2
                fmove   fp7,fp5                 ;save (z imag)^2
                fadd    fp0,fp5                 ;fp5 = (z real)^2 + (z imag)^2
                fcmp    fp6,fp5                 ;fp5 >= radius?
                fboge.b .exit                   ;yes -> exit
                fsub    fp7,fp0                 ;fp0 = (z real)^2 - (z imag)^2
                fadd    fp2,fp0                 ;z[new] real = fp0 + c real
                fadd    fp1,fp1                 ;fp1 = 2 * z real * z imag
                fadd    fp3,fp1                 ;z[new] imag = fp1 + c imag
                dbra    d5,.loop3
.exit
                addq    #1,d5                   ;d5 is now in the range 0-100
                ext.l   d5
                move    ScrDepth,d0
                lsl.l   d0,d5
                fmove.d DeltaX,fp0              ;get deltax
                move    Iterations,d0
                addq    #1,d0
                divu    d0,d5                   ;calculate colortable offset
                tst.b   WindowMode
                beq.b   .nowin
                and.l   #$ff,d5
                lea     TransTable,a1
                move.b  3(a1,d5.l*4),d5
.nowin
                move.b  d5,(a0)+                ;and store the pixel
                fadd    fp0,fp2                 ;c[new] real = c[old] real + dx
                dbra    d6,.loop2
                fmove.d LeftPos,fp2             ;restore left position
                fmove.d DeltaY,fp1              ;get deltay
                fadd    fp1,fp3                 ;c[new] imag = c[old] imag + dy
                dbra    d7,.loop
                fmovem  (sp)+,fp0-fp7
                movem.l (sp)+,d0-a1
                rts
;;/
;// FX (calculates zoom and translation effects)
******************************************************************************
*
*       FX
*
*       calculates zoom and translation effects
*
******************************************************************************
FX
                move.l  d0,-(sp)
                fmovem  fp0-fp4,-(sp)
                tst.b   ZoomIn                  ;check if we should zoom in
                beq.w   .nozoomin
                moveq   #0,d0
                move.b  Zoom,d0                 ;read zoom value
                lsr     #1,d0                   ;half zoom value
                fmove.d LeftPos,fp0
                fmove.d RightPos,fp1
                fmove   fp0,fp2
                fmove   fp1,fp3
                fsub    fp0,fp1                 ;calc area width
                fmove.b d0,fp4
                fmul    fp4,fp1
                fdiv    #100,fp1                ;calc offset value
                fadd    fp1,fp2                 ;increase LeftPos
                fsub    fp1,fp3                 ;decrease RightPos
                fmove.d fp2,LeftPos             ;and write back
                fmove.d fp3,RightPos
                fmove.d TopPos,fp0              ;now completely the same
                fmove.d BottomPos,fp1           ;for vertical direction
                fmove   fp0,fp2
                fmove   fp1,fp3
                fsub    fp0,fp1
                fmul    fp4,fp1
                fdiv    #100,fp1
                fadd    fp1,fp2
                fsub    fp1,fp3
                fmove.d fp2,TopPos
                fmove.d fp3,BottomPos
                bra.w   .mousemove
.nozoomin
                tst.b   ZoomOut                 ;check if we should zoom out
                beq.w   .mousemove
                moveq   #0,d0
                move.b  Zoom,d0
                move.l  #100,d2
                move.l  d2,d1
                sub.l   d0,d1
                mulu    d2,d0
                divu    d1,d0                   ;calc zoom value
                lsr     #1,d0                   ;half zoom value
                fmove.d LeftPos,fp0
                fmove.d RightPos,fp1
                fmove   fp0,fp2
                fmove   fp1,fp3
                fsub    fp0,fp1                 ;calc area width
                fmove.b d0,fp4
                fmul    fp4,fp1
                fdiv    #100,fp1                ;calc offset
                fsub    fp1,fp2                 ;decrease LeftPos
                fadd    fp1,fp3                 ;increase RightPos
                fmove.d fp2,LeftPos             ;and write back
                fmove.d fp3,RightPos
                fmove.d TopPos,fp0              ;and now completely the same
                fmove.d BottomPos,fp1           ;for vertical direction
                fmove   fp0,fp2
                fmove   fp1,fp3
                fsub    fp0,fp1
                fmul    fp4,fp1
                fdiv    #100,fp1
                fsub    fp1,fp2
                fadd    fp1,fp3
                fmove.d fp2,TopPos
                fmove.d fp3,BottomPos
.mousemove
                tst     MouseDX                 ;check if we should translate
                beq.b   .mousemoveY
                fmove.d LeftPos,fp0
                fmove.d RightPos,fp1
                fmove   fp0,fp2
                fmove   fp1,fp3
                fsub    fp0,fp1                 ;calc area width
                fmove.w MouseDX,fp0             ;get mouse movement
                fmul    fp0,fp1
                fmove.w AreaWidth,fp0
                fmove.b Translation,fp4         ;get speed
                fmul    fp4,fp1
                fdiv    fp0,fp1                 ;calc translation value
                fadd    fp1,fp2                 ;do translation
                fadd    fp1,fp3
                fmove.d fp2,LeftPos             ;and write back
                fmove.d fp3,RightPos
.mousemoveY
                tst     MouseDY                 ;check if we should translate
                beq.w   .end
                fmove.d TopPos,fp0
                fmove.d BottomPos,fp1
                fmove   fp0,fp2
                fmove   fp1,fp3
                fsub    fp0,fp1                 ;calc area height
                fmove.w MouseDY,fp0             ;get mouse movement
                fmul    fp0,fp1
                fmove.w AreaHeight,fp0
                fmove.b Translation,fp4         ;get speed
                fmul    fp4,fp1
                fdiv    fp0,fp1                 ;calc translation value
                fadd    fp1,fp2                 ;do translation
                fadd    fp1,fp3
                fmove.d fp2,TopPos              ;and write back
                fmove.d fp3,BottomPos
.end
                fmovem  (sp)+,fp0-fp4
                move.l  (sp)+,d0
                rts
;;/
;// ChunkyToPlanar (converts chunky data to bitplane data)

merge           macro
                move.l  \2,\4
                move.l  #\5,\3
                and.l   \3,\2
                and.l   \1,\3
                eor.l   \3,\1
                eor.l   \2,\4
                ifeq    \6-1
                add.l   \3,\3
                else
                lsl.l   #\6,\3
                endc
                lsr.l   #\6,\4
                or.l    \3,\2
                or.l    \4,\1
                endm

merge4          macro
                move.l  #\5,\3
                and.l   \3,\2
                and.l   \1,\3
                lsl.l   #4,\3
                or.l    \3,\2
                endm

******************************************************************************
*
*       ChunkyToPlanar
*
*       converts chunky data into bitplane data (using Bitmap Structure)
*       works ONLY with a depth of 4!
*
*       original algorithm by James McCoull (I found the source somewhere
*       on the AMINET CD's)
*
******************************************************************************
ChunkyToPlanar
                movem.l d0-a6,-(sp)
                moveq   #0,d1
                moveq   #0,d2
                move    AreaHeight,d2
                move    #_SCREENDEPTH,d0        ;security check
                cmp     #4,d0                   ;if depth <> 4 then exit
                bne.w   .end
                move    d1,d4
                move    d2,d5
                add     d4,d5
                move.l  ChunkyBuffer,a0
                move.l  HiddenBitmap,a1
                lea     bm_Planes(a1),a1        ;a1 -> planeptrs
                move.l  (a1)+,a6                ;read 4 planeptrs
                move.l  (a1)+,a5
                move.l  (a1)+,a3
                move.l  (a1)+,a2
                move    #_SCREENHEIGHT,d0
                move    AreaHeight,d7           ;d7 -> number of rows
                sub     d7,d0
                subq    #1,d7
                lsr     #1,d0                   ;d0 = starting row
                move.l  #_SCREENWIDTH,d1
                move.l  d1,d3
                lsr.l   #3,d3                   ;d3 = screen width [bytes]
                mulu    d3,d0                   ;d0 = vertical offset
                moveq   #0,d2
                move    AreaWidth,d2            ;d2 = number of columns
                sub.l   d2,d1
                lsr.l   #4,d1                   ;d1 = horizontal offset
                add.l   d1,d0                   ;d0 = offset of the 1st pixel
                add.l   d1,d1
                move.l  d1,Modulo               ;d1 = modulo value
                lsr.l   #5,d2                   ;d2 = number of columns / 32
                subq    #1,d2                   ; -> inner loop counter
                move    d2,d6
                add.l   d0,a2                   ;increase planeptrs
                add.l   d0,a3
                add.l   d0,a5
                add.l   d0,a6

                sub     d7,d4
                sub     d7,d5
                neg     d4
                neg     d5
.loop
                cmp     d4,d7
                bgt.w   .loopend
                cmp     d5,d7
                ble.w   .loopend
                movem   d4-d7,-(sp)             ;save loop counters
.loop2
                move    d2,-(sp)                ;save loop counter
                move.l  (a0),d1                 ;now the magic stuff...
                move.l  4(a0),d3                ;first read chunky data
                move.l  8(a0),d0
                move.l  12(a0),d2
                move.l  2(a0),d4
                move.l  10(a0),d5
                move.l  6(a0),d6
                move.l  14(a0),d7
                move    16(a0),d1
                move    24(a0),d0
                move    20(a0),d3
                move    28(a0),d2
                move    18(a0),d4
                move    26(a0),d5
                move    22(a0),d6
                move    30(a0),d7
                lea     32(a0),a0
                move.l  d6,-(sp)
                move.l  d7,-(sp)
                merge   d1,d0,d6,d7,$00ff00ff,8 ;now convert it
                merge   d3,d2,d6,d7,$00ff00ff,8
                merge4  d1,d3,d6,d7,$0f0f0f0f,4
                merge4  d0,d2,d6,d7,$0f0f0f0f,4
                move.l  (sp)+,d0
                move.l  (sp)+,d1
                merge   d4,d5,d6,d7,$00ff00ff,8
                merge   d1,d0,d6,d7,$00ff00ff,8
                merge4  d4,d1,d6,d7,$0f0f0f0f,4
                merge4  d5,d0,d6,d7,$0f0f0f0f,4
                merge   d3,d1,d6,d7,$33333333,2
                merge   d2,d0,d6,d7,$33333333,2
                merge   d3,d2,d6,d7,$55555555,1
                merge   d1,d0,d6,d7,$55555555,1
                move.l  d3,(a2)+                ;and store it into the planes
                move.l  d2,(a3)+
                move.l  d1,(a5)+
                move.l  d0,(a6)+
                move    (sp)+,d2                ;restore loop counter
                dbra    d2,.loop2
                movem   (sp)+,d4-d7             ;restore loop counters
                bra.b   .cont
.loopend
                move    d6,d0
                addq    #1,d0
                lsl     #2,d0
                add     d0,a2
                add     d0,a3
                add     d0,a5
                add     d0,a6
                lsl     #3,d0
                add     d0,a0
.cont
                move.l  Modulo,d0               ;get modulo value
                add.l   d0,a2                   ;increase planeptrs
                add.l   d0,a3
                add.l   d0,a5
                add.l   d0,a6
                move    d6,d2
                dbra    d7,.loop
.end
                movem.l (sp)+,d0-a6
                rts
;;/

                section "CyberMand_Bss",bss
DeltaX          ds.d    1
DeltaY          ds.d    1
Modulo          ds.l    1
