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


                include graphics/gfx.i
;// XREF / XDEF
                xdef    Calculation_PPC
                xdef    FX_PPC
                xdef    ChunkyToPlanar_PPC

                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

;;/
;// Macros

****  citf: Convert Integer to Floating Signed (Double Precision)
*
*       parameters:
*       1: destination FP-Register
*       2: intermediate FP-Register (MUST hold the value $4330000080000000)
*       3: source GP-Register
*
*       Important: this macro does NOT work in Large-Data Model!!


citf            macro
                xoris   trash,\3,$8000
                sw      trash,_CITF_TEMP+4
                lf      \1,_CITF_TEMP
                fsub    \1,\1,\2
                endm

;;/


                section "CyberMand_Calc",code

                cpu     POWERPC
                smalldata
                smallcode

;// 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)
*
*       double AND single precision
******************************************************************************
Calculation_PPC
                prolog  256
                push    r31
                la      r31,TransTable
                lb      r12,WindowMode
                lh      r11,ScrDepth
                lf      f10,_CITF_0
                lw      r6,ChunkyBuffer
                lf      f2,LeftPos              ;f0 = c real part
                fmr     f9,f2                   ;save c real part
                lf      f3,TopPos               ;f1 = c imaginary part
                lf      f4,RightPos
                lf      f5,BottomPos
                fsub    f4,f4,f2                ;calc width of mandel area
                fsub    f5,f5,f3                ;calc height of mandel area
                lh      r4,AreaWidth
                lh      r5,AreaHeight
                citf    f6,f10,r4               ;convert AreaWidth to FPDP
                citf    f7,f10,r5               ;convert AreaHeight to FPDP
                fdiv    f4,f4,f6                ;calc delta x (real)
                fdiv    f5,f5,f7                ;calc delta y (imaginary)
                lf      f6,Radius               ;read termination radius
                lh      r7,Iterations
                lb      r8,Precision
                cmpwi   r8,P_DOUBLE
                beq     .calcdouble

********************  single precision version

.calcsingle
                mr      r8,r4
.Sloop
                mr      r4,r8
.Sloop2
                mtctr   r7
                lf      f0,_0                   ;f0 = z real part
                fmr     f1,f0                   ;f1 = z imaginary part

                fsubs   f12,f6,f2               ;f12 = RADIUS - c real
.Sloop3
                fmsubs  f8,f1,f1,f2             ;f8 = (z imag)^2 - c real
                fadds   f7,f0,f0                ;f7 = 2 * z real
                fmadds  f11,f0,f0,f8            ;f11 = (z real)^2 + f8
                fmsubs  f0,f0,f0,f8             ;z[new] real = (z real)^2 - f8
                fmadds  f1,f1,f7,f3             ;z[new] imag = f7 * z imag + c imag
                fcmpu   f11,f12                 ;f11 > RADIUS - c real?
                bdnzt   LT,.Sloop3
.Sexit
                mfctr   r9                      ;get iteration value
                blt     .Sjump
                addi    r9,r9,1
.Sjump
                slw     r9,r9,r11
                fadds   f2,f2,f4                ;c[new] real = c[old] real + dx
                addi    r10,r7,1
                divw    r9,r9,r10               ;calc colortable offset
                tstw    r12
                beq     .nowin
                slwi    r9,r9,2
                add     r9,r31,r9
                lbz     r9,3(r9)
.nowin
                subic.  r4,r4,1                 ;decrease width counter
                stb     r9,0(r6)                ;and store the pixel
                addi    r6,r6,1                 ;postincrement
                bne     .Sloop2
                subic.  r5,r5,1                 ;decrease height counter
                fmr     f2,f9                   ;restore LeftPos
                fadds   f3,f3,f5                ;c[new] imag = c[old] imag + dy
                bne     .Sloop
                b       .end

********************  double precision version

.calcdouble
                mr      r8,r4
.loop
                mr      r4,r8
.loop2
                mtctr   r7
                lf      f0,_0                   ;f0 = z real part
                fmr     f1,f0                   ;f1 = z imaginary part

                fsub    f12,f6,f2               ;f12 = RADIUS - c real
.loop3
                fmsub   f8,f1,f1,f2             ;f8 = (z imag)^2 - c real
                fadd    f7,f0,f0                ;f7 = 2 * z real
                fmadd   f11,f0,f0,f8            ;f11 = (z real)^2 + f8
                fmsub   f0,f0,f0,f8             ;z[new] real = (z real)^2 - f8
                fmadd   f1,f1,f7,f3             ;z[new] imag = f7 * z imag + c imag
                fcmpu   f11,f12                 ;f11 > RADIUS - c real?
                bdnzt   LT,.loop3
.exit
                mfctr   r9                      ;get iteration value
                blt     .jump
                addi    r9,r9,1
.jump
                slw     r9,r9,r11
                fadd    f2,f2,f4                ;c[new] real = c[old] real + dx
                addi    r10,r7,1
                divw    r9,r9,r10               ;calc colortable offset
                tstw    r12
                beq     .nowin2
                slwi    r9,r9,2
                add     r9,r31,r9
                lbz     r9,3(r9)
.nowin2
                subic.  r4,r4,1                 ;decrease width counter
                stb     r9,0(r6)                ;and store the pixel
                addi    r6,r6,1                 ;postincrement
                bne     .loop2
                subic.  r5,r5,1                 ;decrease height counter
                fmr     f2,f9                   ;restore LeftPos
                fadd    f3,f3,f5                ;c[new] imag = c[old] imag + dy
                bne     .loop
.end
                pop     r31
                epilog
;;/
;// FX (calculates zoom and translation effects)
******************************************************************************
*
*       FX
*
*       calculates zoom and translation effects (only Double Precision)
*
******************************************************************************
FX_PPC
                prolog  256
                lf      f6,_CITF_0
                lb      r4,ZoomIn
                mr.     r4,r4                   ;check if we should zoom in
                beq     .nozoomin
                lb      r4,Zoom                 ;read zoom value
                srwi    r4,r4,1                 ;half zoom value
                citf    f4,f6,r4                ;convert to FPDP
                lf      f0,LeftPos
                lf      f1,RightPos
                fsub    f2,f1,f0                ;calc area width
                fmul    f2,f2,f4
                lf      f3,_100
                fdiv    f2,f2,f3                ;calc offset value
                fadd    f0,f0,f2                ;increase LeftPos
                fsub    f1,f1,f2                ;decrease RightPos
                sf      f0,LeftPos              ;and write back
                sf      f1,RightPos
                lf      f0,TopPos               ;now completely the same
                lf      f1,BottomPos            ;for vertical direction
                fsub    f2,f1,f0
                fmul    f2,f2,f4
                fdiv    f2,f2,f3
                fadd    f0,f0,f2
                fsub    f1,f1,f2
                sf      f0,TopPos
                sf      f1,BottomPos
                b       .mousemove
.nozoomin
                lb      r4,ZoomOut
                mr.     r4,r4                   ;check if we should zoom out
                beq     .mousemove
                lb      r4,Zoom
                li      r5,100
                mullw   r6,r4,r5
                subf    r5,r4,r5
                divw    r4,r6,r5                ;calc zoom value
                srwi    r4,r4,1                 ;half zoom value
                citf    f4,f6,r4                ;convert to FPDP
                lf      f0,LeftPos
                lf      f1,RightPos
                fsub    f2,f1,f0                ;calc area width
                fmul    f2,f2,f4
                lf      f3,_100
                fdiv    f2,f2,f3                ;calc offset value
                fsub    f0,f0,f2                ;decrease LeftPos
                fadd    f1,f1,f2                ;increase RightPos
                sf      f0,LeftPos              ;and write back
                sf      f1,RightPos
                lf      f0,TopPos               ;now completely the same
                lf      f1,BottomPos            ;for vertical direction
                fsub    f2,f1,f0
                fmul    f2,f2,f4
                fdiv    f2,f2,f3
                fsub    f0,f0,f2
                fadd    f1,f1,f2
                sf      f0,TopPos
                sf      f1,BottomPos
.mousemove
                lh      r4,MouseDX
                extsh.  r4,r4
                beq     .mousemoveY             ;check if we should translate
                lf      f0,LeftPos
                lf      f1,RightPos
                fsub    f2,f1,f0                ;calc area width
                citf    f3,f6,r4                ;and convert to FPDP
                fmul    f2,f2,f3
                lh      r7,AreaWidth
                citf    f4,f6,r7
                lb      r8,Translation          ;get speed
                citf    f5,f6,r8
                fmul    f2,f2,f5
                fdiv    f2,f2,f4                ;calc translation value
                fadd    f0,f0,f2                ;do translation
                fadd    f1,f1,f2
                sf      f0,LeftPos              ;and write back
                sf      f1,RightPos
.mousemoveY
                lh      r4,MouseDY
                extsh.  r4,r4
                beq     .end                    ;check if we should translate
                lf      f0,TopPos
                lf      f1,BottomPos
                fsub    f2,f1,f0                ;calc area width
                citf    f3,f6,r4                ;and convert to FPDP
                fmul    f2,f2,f3
                lh      r7,AreaHeight
                citf    f4,f6,r7
                lb      r8,Translation          ;get speed
                citf    f5,f6,r8
                fmul    f2,f2,f5
                fdiv    f2,f2,f4                ;calc translation value
                fadd    f0,f0,f2                ;do translation
                fadd    f1,f1,f2
                sf      f0,TopPos               ;and write back
                sf      f1,BottomPos
.end
                epilog
;;/
;// ChunkyToPlanar (converts chunky data to bitplane data)

merge           macro
                and     r8,\1,\3
                xor     \1,r8,\1
                and     r9,\2,\3
                xor     \2,r9,\2
                slwi    r8,r8,\4
                srwi    \2,\2,\4
                or      \1,\1,\2
                or      \2,r9,r8
                endm

merge4          macro
                and     r8,\1,\3
                and     \2,\2,\3
                slwi    r8,r8,4
                or      \2,\2,r8
                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_PPC
                prolog  256
                pushgpr r14-r30
                li      r29,0
                lh      r30,AreaHeight
                add     r30,r29,r30

                li      r4,_SCREENDEPTH         ;security check
                cmpwi   r4,4                    ;if depth <> 4 then exit
                bne     .end

                liw     r4,$00ff00ff            ;load mask values
                liw     r5,$0f0f0f0f
                liw     r6,$33333333
                liw     r7,$55555555
                lw      r10,ChunkyBuffer
                lw      r11,HiddenBitmap
                la      r11,bm_Planes+16(r11)   ;a1 -> after 4 plane ptrs
                lwzu    r12,-4(r11)             ;read 4 plane ptrs
                lwzu    r13,-4(r11)
                lwzu    r14,-4(r11)
                lwzu    r15,-4(r11)
                lh      r16,AreaHeight          ;r16 = number of rows
                li      r18,_SCREENHEIGHT
                subf    r18,r16,r18
                srwi    r18,r18,1               ;r18 = starting row
                li      r19,_SCREENWIDTH
                srwi    r20,r19,3               ;r20 = screen width [bytes]
                mullw   r18,r18,r20             ;r18 = vertical offset
                lh      r17,AreaWidth           ;r17 = number of columns
                subf    r19,r17,r19
                srwi    r19,r19,4               ;r19 = horizontal offset
                add     r18,r18,r19             ;r18 = offset to the 1st pixel
                add     r19,r19,r19             ;r19 = modulo value
                srwi    r17,r17,5               ;r17 = number of columns / 32
                add     r12,r12,r18             ;increase planeptrs
                add     r13,r13,r18
                add     r14,r14,r18
                add     r15,r15,r18
                subf    r29,r29,r16
                subf    r30,r30,r16
.loop
                cmplw   r16,r29
                bgt     .loopend
                cmplw   r16,r30
                ble     .loopend
                mtctr   r17                     ;inner loop counter
.loop2
                lwz     r21,0(r10)              ;now the magic stuff...
                lwz     r23,4(r10)              ;first read chunky data
                lwz     r20,8(r10)
                lwz     r22,12(r10)
                lwz     r24,2(r10)
                lwz     r25,10(r10)
                lwz     r26,6(r10)
                lwz     r27,14(r10)
                lhz     r18,16(r10)
                mh      r21,r18
                lhz     r18,24(r10)
                mh      r20,r18
                lhz     r18,20(r10)
                mh      r23,r18
                lhz     r18,28(r10)
                mh      r22,r18
                lhz     r18,18(r10)
                mh      r24,r18
                lhz     r18,26(r10)
                mh      r25,r18
                lhz     r18,22(r10)
                mh      r26,r18
                lhz     r18,30(r10)
                mh      r27,r18
                addi    r10,r10,32
                merge   r21,r20,r4,8            ;now convert it
                merge   r23,r22,r4,8
                merge4  r21,r23,r5
                merge4  r20,r22,r5
                merge   r24,r25,r4,8
                merge   r26,r27,r4,8
                merge4  r24,r26,r5
                merge4  r25,r27,r5
                merge   r23,r26,r6,2
                merge   r22,r27,r6,2
                merge   r23,r22,r7,1
                merge   r26,r27,r7,1
                stw     r23,0(r12)              ;and store it into the planes
                addi    r12,r12,4
                stw     r22,0(r13)
                addi    r13,r13,4
                stw     r26,0(r14)
                addi    r14,r14,4
                stw     r27,0(r15)
                addi    r15,r15,4
                bdnz    .loop2
                b       .cont
.loopend
                slwi    r21,r17,2
                add     r12,r12,r21
                add     r13,r13,r21
                add     r14,r14,r21
                add     r15,r15,r21
                slwi    r21,r21,3
                add     r10,r10,r21
.cont
                subic.  r16,r16,1
                add     r12,r12,r19             ;get modulo value and
                add     r13,r13,r19             ;increase planeptrs
                add     r14,r14,r19
                add     r15,r15,r19
                bne     .loop
.end
                popgpr
                epilog
;;/

                section "CyberMand_Data",data

                dcb.b   32
_100            dc.d    100
_0              dc.d    0
_CITF_0         dc.l    $43300000,$80000000
_CITF_TEMP      dc.l    $43300000,0
dy              dc.d    0
                dcb.b   32
