; POINTS -- Display, shift, rotate and morph points in 3D with
;           color fading.
;           Written by Arno W. Brouwer
;
; Thanks go to the authors of XLIB for their Mode X screen routines.


        IDEAL
        DOSSEG
        MODEL   small
        STACK   256


mx      EQU     160             ; middle of screen (project point
my      EQU     100             ; of [0, 0, 0] )
maxx    EQU     319             ; max. screen x coord.
maxy    EQU     199             ; max. screen y coord.
numpts  EQU     120             ; number of points
point_color EQU 46              ; color of points

        DATASEG

returncode      db      0
ex              dw      0       ; eye x-coord.
ey              dw      0       ; eye y-coord.
ez              dw      256     ; distance eye-screen
esz             dw      8       ; (ez = 2 ^ esz)
sz              dw      30000   ; screen z coord.
                                ; (distance screen <-> [0, 0, 0] )
rot_x           dw      0       ; current rotation around x axis
rot_y           dw      0       ;                         y axis
rot_z           dw      0       ;                         z axis
delta_x         dw      0       ; delta rotation x axis
delta_y         dw      0       ;                y axis
delta_z         dw      0       ;                z axis

morph1_ofs      dw      0       ; offset shape 1 for morphing
morph2_ofs      dw      0       ;        shape 2
morph_steps     dw      0       ; number of steps needed for morphing
curr_morph_step dw      0       ; current morph step [0 ... morph_steps]

points          dw      0       ; offset of point-table for DrawPoints

label Sin256    ; sine tabel 256 * sin(x); x = 2*pi*i/256; i = [0, 255]

        dw     0,    6,   12,   18,   25,   31,   37,   43,   49,   56,   62
        dw    68,   74,   80,   86,   92,   97,  103,  109,  115,  120,  126
        dw   131,  136,  142,  147,  152,  157,  162,  167,  171,  176,  181
        dw   185,  189,  193,  197,  201,  205,  209,  212,  216,  219,  222
        dw   225,  228,  231,  234,  236,  238,  241,  243,  244,  246,  248
        dw   249,  251,  252,  253,  254,  254,  255,  255,  255,  256,  255
        dw   255,  255,  254,  254,  253,  252,  251,  249,  248,  246,  244
        dw   243,  241,  238,  236,  234,  231,  228,  225,  222,  219,  216
        dw   212,  209,  205,  201,  197,  193,  189,  185,  181,  176,  171
        dw   167,  162,  157,  152,  147,  142,  136,  131,  126,  120,  115
        dw   109,  103,   97,   92,   86,   80,   74,   68,   62,   56,   49
        dw    43,   37,   31,   25,   18,   12,    6,    0,   -6,  -12,  -18
        dw   -25,  -31,  -37,  -43,  -49,  -56,  -62,  -68,  -74,  -80,  -86
        dw   -92,  -97, -103, -109, -115, -120, -126, -131, -136, -142, -147
        dw  -152, -157, -162, -167, -171, -176, -181, -185, -189, -193, -197
        dw  -201, -205, -209, -212, -216, -219, -222, -225, -228, -231, -234
        dw  -236, -238, -241, -243, -244, -246, -248, -249, -251, -252, -253
        dw  -254, -254, -255, -255, -255, -255, -255, -255, -255, -254, -254
        dw  -253, -252, -251, -249, -248, -246, -244, -243, -241, -238, -236
        dw  -234, -231, -228, -225, -222, -219, -216, -212, -209, -205, -201
        dw  -197, -193, -189, -185, -181, -176, -171, -167, -162, -157, -152
        dw  -147, -142, -136, -131, -126, -120, -115, -109, -103,  -97,  -92
        dw   -86,  -80,  -74,  -68,  -62,  -56,  -49,  -43,  -37,  -31,  -25
        dw   -18,  -12,   -6

label cube              ; points for cube

INCLUDE 'CUBE.INC'

label ball              ; points for ball

INCLUDE 'BALL.INC'

tmp_pts1        dw numpts*2 DUP (0)     ; temp. buffer for points
tmp_pts2        dw numpts*2 DUP (0)     ; to speed up clrscr


        CODESEG

;-----------------------------------------------------------------------
HiddenOfs       dw      03e80h                  ; offset hidden page
VisibleOfs      dw      0                       ;        visible
HiddenPoints    dw      offset tmp_pts1         ; offset hidden point-table
VisiblePoints   dw      offset tmp_pts2         ;        visible
C_tabel         db      1, 2, 4, 8              ; needed for plane selection
sin_x           dw      0                       ; current sin for rot. x axis
cos_x           dw      0                       ;         cos          x
sin_y           dw      0                       ;         sin          y
cos_y           dw      0                       ;         cos          y
sin_z           dw      0                       ;         sin          z
cos_z           dw      0                       ;         sin          z

;-----------------------------------------------------------------------

proc   WaitVsyncStart                   ; wait for vertical sync. start

        push    ax
        push    dx

        mov     dx, 03dah
@@11:
        in      al,dx
        test    al,08h
        jnz     @@11
@@22:
        in      al,dx
        test    al,08h
        jz      @@22

        pop     dx
        pop     ax
        ret
ENDP

;--------------------------------------------------------------------------

proc    WaitVsyncEnd                    ; wait for vert. sync end
        mov     dx,03dah
@@33:
        in      al,dx
        test    al,08h
        jz     @@33
@@44:
        in      al,dx
        test    al,08h
        jnz      @@44
        ret
ENDP

;--------------------------------------------------------------------------

PROC    InitScreen                      ; switch to 320 x 200 mode X

        push    ax cx dx es di

        mov     ax, 0013h
        int     10h             ; switch to 320x200x256c (non-tweaked)

        mov     dx, 03c4h
        mov     ax, 0604h
        out     dx, ax          ; disable chain4 mode
        mov     ax, 0100h
        out     dx, ax          ; sync. reset while setting Misc.
        mov     dx, 03c2h
        mov     al, 0e3h
        out     dx, al          ; select dot clock & horiz. scan rate
        mov     dx, 03c4h
        mov     ax, 0300h
        out     dx, ax          ; undo reset (restart sequencer)
        mov     dx, 03d4h
        mov     al, 11h
        out     dx, al
        inc     dx
        in      al, dx
        and     al, 07fh
        out     dx, al          ; clear protection bit
        dec     dx
        mov     ax, 0014h
        out     dx, ax          ; clear dword mode
        mov     ax, 0e317h
        out     dx, ax          ; set byte mode
        mov     dx, 03c4h
        mov     ax, 0f02h       
        out     dx, ax          ; enable writes to all four planes

        mov     dx, 03d4h
        mov     al, 13h
        out     dx, al          ; set logical screen width
        inc     dx
        mov     al, 28h
        out     dx, al          ; to 320 pixels (== 40 bytes == 28h)

        mov     ax, 0a000h
        mov     es, ax
        xor     di, di
        xor     ax, ax
        mov     cx, 08000h
        rep     stosw           ; clear display memory

        pop     di es dx cx ax

        ret

ENDP    InitScreen

;--------------------------------------------------------------------------

PROC    InitPalette             ; fill first 64 colors with grays

        push    ax bx cx dx

        xor     ax, ax
        mov     cx, 64
@@33:
        mov     bx, 10          ; number of colors to set in one retrace
                                ; (10 is a good value for even the slower
                                ;  computers.. like mine)
        call WaitVsyncStart
        mov     dx, 03c9h
@@11:
        push    cx
        push    ax
        dec     dx              ; dx = 03c8h
        out     dx, al          ; select palette entry
        inc     dx
        mov     cx, 3
@@22:
        out     dx, al          ; set red, green and blue to same value
        loop    @@22

        pop     ax
        pop     cx
        inc     al
        dec     cx
        jz      @@00
        dec     bx              ; Time to wait for vert. retrace?
        jz      @@33            ; yes: do so
        jmp     @@11            ; no : next color
@@00:
        pop     dx cx bx ax

        ret

ENDP    InitPalette

;--------------------------------------------------------------------------

PROC    FlipPages                       ; switch hidden and visible page.

        push    ax bx cx dx

        mov     bx, [cs:HiddenPoints]   ; exchange hidden and visible points
        xchg    bx, [cs:VisiblePoints]
        xchg    bx, [cs:HiddenPoints]

        mov     bx, [cs:HiddenOfs]      ; exchange hidden and visible page
        xchg    bx, [cs:VisibleOfs]
        xchg    [cs:HiddenOfs], bx
        mov     ax, bx                  ; ax now contains HiddenOfs
        mov     bh, al
        mov     ch, ah
        mov     bl, 0dh                 ; page address low
        mov     cl, 0ch                 ; page address high

        mov     dx, 03dah               ; wait for trailing edge of Vsync
@@WaitDE:
        in      al, dx
        test    al, 01h
        jnz     @@WaitDE

        mov     dx, 03d4h
        mov     ax, bx
        out     dx, ax                  ; start address low
        mov     ax, cx
        out     dx, ax                  ; start address high

        call    WaitVsyncStart          ; wait for start vert. retrace
                                        ; to avoid screen flickering
        pop     dx cx bx ax
        ret

ENDP    FlipPages

;-----------------------------------------------------------------------

PROC    ClrScr                          ; clear the hidden screen by
                                        ; drawing the hidden pixels in black.
        push    ax bx cx dx es di ds si
        mov     dx, 03c4h
        mov     ax, 0f02h               ; enable write to all four planes
        out     dx, ax
        mov     ax, 0a000h
        mov     es, ax
        mov     ax, [cs:HiddenPoints]
        mov     si, ax                  ; ds:si -> HiddenPoints tabel
        mov     cx, numpts
@@ClrLoop:
        lodsw                           ; get x coord.
        push    ax
        lodsw                           ; get y coord.
        mov     bx, 320
        mul     bx
        mov     di, ax
        pop     ax
        add     di, ax
        shr     di, 1
        shr     di, 1                   ; correction for use of planes
        mov     ax, [cs:HiddenOfs]
        add     di, ax
        xor     ax, ax
        stosb                           ; clear pixel
        loop    @@ClrLoop

        pop     si ds di es dx cx bx ax
        ret

ENDP    ClrScr

;-----------------------------------------------------------------------

PROC    GetSinCos                       ; get sine and cosine values
                                        ; from tabel. ax contains
                                        ; 'angle' (ax = [0 .. 255])
                                        ; returns: ax = sin(ax)
                                        ;          bx = cos(ax)
        push    ds si
        lea     si, [Sin256]
        mov     bx, ax
        push    bx
        shl     bx, 1                   ; bx = bx * 2.. word is 2 bytes
        mov     ax, [ds:si + bx]        ; get sin()
        pop     bx
        push    ax
        add     bx, 64                  ; since sine tabel ranges from
        and     bx, 0ffh                ; [0 .. 255], so cos(x) = sin(x+64)
        shl     bx, 1
        mov     ax, [si + bx]           ; get cos()
        mov     bx, ax
        pop     ax
        pop     si ds
        ret

ENDP    GetSinCos

;-----------------------------------------------------------------------

PROC    SetRotation                     ; specify x, y, z rotation
                                        ; ax = x rot, bx = y rot, cx = z rot
        push    ax bx cx
        and     ax, 0ffh                ; range sine table [0 .. 255]
        and     bx, 0ffh
        and     cx, 0ffh

        push    cx
        push    bx
        call    GetSinCos
        mov     [cs:sin_x], ax
        mov     [cs:cos_x], bx
        pop     ax
        call    GetSinCos
        mov     [cs:sin_y], ax
        mov     [cs:cos_y], bx
        pop     ax
        call    GetSinCos
        mov     [cs:sin_z], ax
        mov     [cs:cos_z], bx

        pop     cx bx ax
        ret

ENDP    SetRotation

;-----------------------------------------------------------------------

PROC    UpdateRotation                  ; update rotation params.
                                        ; add delta_x, delta_y and delta_z
        push    ax bx cx                ; to rot_x, rot_y and rot_z,
                                        ; then calculate the sines and cosines.
        mov     ax, [rot_x]
        mov     bx, [rot_y]
        mov     cx, [rot_z]
        add     ax, [delta_x]
        mov     [rot_x], ax
        add     bx, [delta_y]
        mov     [rot_y], bx
        add     cx, [delta_z]
        mov     [rot_z], cx
        call    SetRotation

        pop     cx bx ax
        ret

ENDP    UpdateRotation

;--------------------------------------------------------------------------

PROC    SetMorph                        ; Set parameters for morphing.
                                        ; Both shapes must have the same
                                        ; number of points.
                                        ; Input: ax = offset shape1.
                                        ;        bx = offset shape2.
                                        ;        cx = total number of steps
        mov     [morph1_ofs], ax
        mov     [morph2_ofs], bx
        mov     [morph_steps], cx
        mov     [curr_morph_step], 0
        ret

ENDP    SetMorph

;--------------------------------------------------------------------------

PROC    project_point                   ; project a point to screen
                                        ; using x,y,z rotations
        ARG     z, y, x: word           ; returns: ax = x coord.
                                        ;          bx = y coord.
                                        ;          cx = distance to screen.
        push    bp
        mov     bp, sp

        push    dx

        ; first rotate around x-axis
        mov     cx, 256
        mov     ax, [y]
        mov     bx, [cos_x]
        imul    bx
        idiv    cx              ; divide by 256 since sin-tabel ranges
                                ; from -256 to 256 instead of -1 to 1.
        cmp     dx, 128         ; Check remainder to decrease integer math
        jl      @@Skip1         ; inaccuracy.
        or      ax, ax
        jl      @@Neg1
        inc     ax
        jmp     @@Skip1
@@Neg1:
        dec     ax
@@Skip1:
        push    ax
        mov     ax, [z]
        mov     bx, [sin_x]
        imul    bx
        idiv    cx
        cmp     dx, 128
        jl      @@Skip2
        or      ax, ax
        jl      @@Neg2
        inc     ax
        jmp     @@Skip2
@@Neg2:
        dec     ax
@@Skip2:
        pop     bx
        sub     bx, ax                  ; bx now contains new y-coord.
        push    bx                      

        mov     ax, [y]
        mov     bx, [sin_x]
        imul    bx
        idiv    cx
        cmp     dx, 128
        jl      @@Skip3
        or      ax, ax
        jl      @@Neg3
        inc     ax
        jmp     @@Skip3
@@Neg3:
        dec     ax
@@Skip3:
        push    ax
        mov     ax, [z]
        mov     bx, [cos_x]
        imul    bx
        idiv    cx
        cmp     dx, 128
        jl      @@Skip4
        or      ax, ax
        jl      @@Neg4
        inc     ax
        jmp     @@Skip4
@@Neg4:
        dec     ax
@@Skip4:
        pop     bx
        add     ax, bx                  
        mov     [z], ax                 ; z = y sin_x + z cos_x
        pop     ax
        mov     [y], ax                 ;  y' = y cos_x - z sin_x

        ; now rotate around y-axis
        mov     cx, 256
        mov     ax, [z]
        mov     bx, [cos_y]
        imul    bx
        idiv    cx
        cmp     dx, 128
        jl      @@Skip5
        or      ax, ax
        jl      @@Neg5
        inc     ax
        jmp     @@Skip5
@@Neg5:
        dec     ax
@@Skip5:
        push    ax
        mov     ax, [x]
        mov     bx, [sin_y]
        imul    bx
        idiv    cx
        cmp     dx, 128
        jl      @@Skip6
        or      ax, ax
        jl      @@Neg6
        inc     ax
        jmp     @@Skip6
@@Neg6:
        dec     ax
@@Skip6:
        pop     bx
        sub     bx, ax                  ; bx now contains new y-coord.
        push    bx

        mov     ax, [z]
        mov     bx, [sin_y]
        imul    bx
        idiv    cx
        cmp     dx, 128
        jl      @@Skip7
        or      ax, ax
        jl      @@Neg7
        inc     ax
        jmp     @@Skip7
@@Neg7:
        dec     ax
@@Skip7:
        push    ax
        mov     ax, [x]
        mov     bx, [cos_y]
        imul    bx
        idiv    cx
        cmp     dx, 128
        jl      @@Skip8
        or      ax, ax
        jl      @@Neg8
        inc     ax
        jmp     @@Skip8
@@Neg8:
        dec     ax
@@Skip8:
        pop     bx
        add     ax, bx
        mov     [x], ax                 ; x' = z sin_y + x cos_y
        pop     ax
        mov     [z], ax                 ; z' = z cos_y - x sin_y

        ; now rotate around z-axis
        mov     cx, 256
        mov     ax, [x]
        mov     bx, [cos_z]
        imul    bx
        idiv    cx
        cmp     dx, 128
        jl      @@Skip9
        or      ax, ax
        jl      @@Neg9
        inc     ax
        jmp     @@Skip9
@@Neg9:
        dec     ax
@@Skip9:
        push    ax
        mov     ax, [y]
        mov     bx, [sin_z]
        imul    bx
        idiv    cx
        cmp     dx, 128
        jl      @@Skip10
        or      ax, ax
        jl      @@Neg10
        inc     ax
        jmp     @@Skip10
@@Neg10:
        dec     ax
@@Skip10:
        pop     bx
        sub     bx, ax                  ; bx now contains new y-coord.
        push    bx

        mov     ax, [x]
        mov     bx, [sin_z]
        imul    bx
        idiv    cx
        cmp     dx, 128
        jl      @@Skip11
        or      ax, ax
        jl      @@Neg11
        inc     ax
        jmp     @@Skip11
@@Neg11:
        dec     ax
@@Skip11:
        push    ax
        mov     ax, [y]
        mov     bx, [cos_z]
        imul    bx
        idiv    cx
        cmp     dx, 128
        jl      @@Skip12
        or      ax, ax
        jl      @@Neg12
        inc     ax
        jmp     @@Skip12
@@Neg12:
        dec     ax
@@Skip12:
        pop     bx
        add     ax, bx
        mov     [y], ax                 ; y' = x sin_z + y cos_z
        pop     ax                      ; x' = x cos_z - y sin_z
        mov     [x], ax

        mov     bx, [sz]
        sub     bx, [z]
        add     bx, [ez]
        mov     cx, [esz]
        mov     ax, [y]                 ; first project y coord.
        sub     ax, [ey]
        pushf
        jge     @@Pos1                  ; is ax < 0?
        neg     ax                      ; yes: ax = -ax
@@Pos1:
        shl     ax, cl                  ; since ax >= 0, we can use
        xor     dx, dx                  ; a shift here instead of a imul.
        idiv    bx                      ; ax = ((y - ey) * ez) / (sz - z)
        push    bx                      ; save bx
        shr     bx, 1
        cmp     dx, bx                  ; again a check to decrease
        jl      @@NoRound1              ; integer math inaccuracy
        inc     ax
@@NoRound1:
        pop     bx
        popf                            ; was ax negative?
        jge     @@Pos1_1
        neg     ax                      ; yes: ax = -ax.
@@Pos1_1:
        add     ax, my                  ; add coords of center of screen
        push    ax
        mov     ax, [x]                 ; now project x coord.
        sub     ax, [ex]
        pushf
        jge     @@Pos2
        neg     ax
@@Pos2:
        shl     ax, cl
        xor     dx, dx
        idiv    bx
        push    bx
        shr     bx, 1
        cmp     dx, bx
        jl      @@NoRound2
        inc     ax
@@NoRound2:
        pop     bx
        popf
        jge     @@Pos2_1
        neg     ax
@@Pos2_1:
        add     ax, mx
        mov     cx, [sz]
        mov     bx, [z]
        sub     cx, bx
        pop     bx
        pop     dx
        pop     bp
        ret

ENDP    project_point           

;-----------------------------------------------------------------------

PROC    plot_point              ; expects that ax = px, bx = py
                                ;              cx = distance point <-> screen
        or      ax, ax
        jl      @@Exit          ; first check wether the point is on the
        cmp     ax, maxx        ; screen.
        jg      @@Exit
        or      bx, bx
        jl      @@Exit
        cmp     bx, maxy
        jg      @@Exit
        or      cx, cx
        jl      @@Exit

        push    ax bx cx dx es di

        push    cx
        push    ax
        push    bx
        mov     ax, 0a000h
        mov     es, ax
        pop     ax              ; ax = y-coord.
        mov     bx, 320
        mul     bx
        mov     di, ax
        pop     ax
        add     di, ax          ; es:di points to position in video RAM
        mov     bx, di
        mov     cl, 2h
        shr     di, cl
        mov     ax, [cs:HiddenOfs]
        add     di, ax
        mov     dx, 03c4h
        mov     al, 02h
        and     bx, 03h         ; filter out plane bits
        mov     ah, [cs:C_tabel + bx]
        out     dx, ax          ; select plane
        pop     ax              ; ax = distance point <-> screen
        sub     ax, 60          ; calculate the color of the pixel
        jge     @@NotNegative
        xor     ax, ax
@@NotNegative:
        xor     bx, bx
@@NotZero:
        inc     bx
        shr     ax, 1
        jnz     @@NotZero
        shl     bx, 1
        shl     bx, 1
        mov     ax, 64
        sub     ax, bx          ; ax contains the color of the pixel
        stosb                   ; plot pixel

        pop     di es dx cx bx ax
@@Exit:
        ret

ENDP    plot_point

;--------------------------------------------------------------------------

PROC    MorphPoints                     ; morph points from shape1
                                        ; to shape2.
        push    cx                      ; Also updates rotation and
        mov     cx, [curr_morph_step]   ; plots points.
        cmp     cx, [morph_steps]       ; Do we still have morph steps
        pop     cx                      ; to go?
        jl      @@StepOk                ; yes: Jump to StepOk
        push    ax                      ; no:  Draw the second image on
        mov     ax, [morph2_ofs]        ;      the screen and return.
        mov     [points], ax
        pop     ax
        call    DrawPoints
        ret

@@StepOk:
        push    ax bx cx dx si es di

        call    UpdateRotation          ; Update rotation params.

        mov     cx, numpts
        mov     si, [morph1_ofs]
        mov     di, [morph2_ofs]
        mov     ax, ds
        mov     es, ax
        mov     dx, [cs:HiddenPoints]   ; use dx as a temp. pointer to
@@MorphLoop:                            ; the HiddenPoints tabel
        push    cx
        push    dx
        mov     cx, 3                           ; morph x, y, z coord.
@@CoordLoop:
        mov     ax, [di]
        mov     bx, [si]
        sub     ax, bx                          ; ax is distance p2 - p1
        mov     bx, [curr_morph_step]
        imul    bx
        mov     bx, [morph_steps]
        idiv    bx              ; ax = ax * curr_morph_step / morph_steps
        add     ax, [si]
        push    ax              ; save value ax
        inc     di
        inc     di
        inc     si
        inc     si
        loop    @@CoordLoop     ; repeat until x, y and z values are morphed.
        call    project_point   ; calculate x and y values of point on screen
        add     sp, 6
        call    plot_point      ; plot 'em.
        pop     dx              ; dx = offset HiddenPoints tabel
        xchg    dx, di          ; exchange dx and di
        stosw                   ; store x coord. in HiddenPoints tabel
        mov     ax, bx
        stosw                   ; store y coord. in HiddenPoints tabel
        xchg    dx, di          ; swap dx and di
        pop     cx
        loop    @@MorphLoop     ; any more points?

        call    FlipPages       ; no: flip the pages.
        call    ClrScr          ; clear the hidden page.

        mov     cx, [curr_morph_step]
        inc     cx                      ; increase the current morph step
        mov     [curr_morph_step], cx

        pop     di es si dx cx bx ax
        ret

ENDP    MorphPoints

;-----------------------------------------------------------------------

PROC    DrawPoints                      ; project points, plot'em and update
                                        ; rotation data.
        push    ax bx cx dx ds si es di

        call    UpdateRotation          ; update the rotation params.
        mov     si, [points]            ; ds:si -> point tabel
        mov     ax, ds
        mov     es, ax
        mov     ax, [cs:HiddenPoints]
        mov     di, ax                  ; es:di -> HiddenPoints tabel
        mov     cx, numpts
@@PlotLoop:
        push    cx
        lodsw                           ; get x coord.
        push    ax
        lodsw                           ; get y coord.
        push    ax
        lodsw                           ; get z coord.
        push    ax
        call    project_point           ; project the point onto the screen
        add     sp, 6
        call    plot_point              ; plot the point
        stosw                           ; store x coord. for fast clrscr.
        mov     ax, bx
        stosw                           ; store y coord.
        pop     cx
        loop    @@PlotLoop              ; any more points?

        call    FlipPages               ; no: flip the pages
        call    ClrScr                  ; clear the hidden page.

        pop     di es si ds dx cx bx ax
        ret

ENDP    DrawPoints

;-----------------------------------------------------------------------

Begin:
        mov     ax, @data
        mov     ds, ax

        call    InitScreen              ; initialize the screen
        call    InitPalette             ; and the palette

@@BigLoop:

        mov     ax, offset cube
        mov     [points], ax            ; first draw the cube
        mov     [delta_x], 0            ; halt all rotations
        mov     [delta_y], 0
        mov     [delta_z], 0

        mov     [ex], 0                 ; put the eye x coord. to zero

        mov     cx, 20h                 ; show cube at a VERY large distance
@@RotLoop0:
        call    DrawPoints              ; draw the points
        mov     ah, 1h                  ; check for a keypress
        int     16h
        jz      @@NoPress0
        jmp     RestoreScreen           ; key pressed -> restore screen and
@@NoPress0:                             ; exit.
        loop    @@RotLoop0

        mov     cx, 8                   ; Zoom in
@@LoopLoop3:
        push    cx
        call    DrawPoints

        mov     ah, 01h                 ; check for keypress
        int     16h
        jz      @@NoPress1
        jmp     RestoreScreen

@@NoPress1:
        mov     ax, [sz]                ; move the screen closer to
        shr     ax, 1                   ; (0, 0, 0)
        mov     [sz], ax
        pop     cx
        loop    @@LoopLoop3


        mov     cx, 0a0h                ; let cube rotate round y for a while
        xor     bx, bx
@@RotLoop1:
        call    DrawPoints
        mov     ah, 1h
        int     16h
        jz      @@NoPress2
        jmp     RestoreScreen
@@NoPress2:
        push    bx
        shl     bx, 1
        mov     ax, [cs:Sin256 + bx]    ; get rotation speed from sine tabel
        pop     bx
        shr     ax, 1
        shr     ax, 1
        shr     ax, 1
        shr     ax, 1
        shr     ax, 1                   ; adjust speed a bit
        mov     [delta_y], ax           ; store new speed.
        inc     bx
        and     bx, 0ffh
        loop    @@RotLoop1

        mov     [delta_x], 1            ; add x rotation.
        mov     cx, 80h
@@RotLoop2:
        call    DrawPoints
        mov     ah, 1h
        int     16h
        jz      @@NoPress3
        jmp     RestoreScreen
@@NoPress3:
        loop    @@RotLoop2

        mov     [delta_x], -3
        mov     [delta_z], 2
        mov     cx, 40h                         ; add some more rot's
@@RotLoop3:
        call    DrawPoints
        mov     ah, 1h
        int     16h
        jz      @@NoPress4
        jmp     RestoreScreen
@@NoPress4:
        loop    @@RotLoop3

        mov     [delta_x], 0
        mov     [delta_y], 2
        mov     [delta_z], -1
        xor     bx, bx                  ; index in sine tabel
        mov     cx, 256                 ; let the cube move from
@@RotLoop4:                             ; left to right
        call    DrawPoints
        mov     ah, 1h
        int     16h
        jz      @@NoPress5
        jmp     RestoreScreen
@@NoPress5:
        mov     ax, [cs:Sin256 + bx]    ; ax = [-256 .. 256]
        add     ax, 256                 ; ax = [   0 .. 512]
        shr     ax, 1                   ; ax = [   0 .. 256]
        sub     ax, 128                 ; ax = [-128 .. 128]
        mov     [ex], ax                ; store new eye x coord.
        inc     bx
        inc     bx                      ; set bx to new entry in sine tabel
        and     bx, 01ffh
        loop    @@RotLoop4

        push    bx                      ; save the value of bx
        mov     ax, offset cube
        mov     bx, offset ball
        mov     cx, 100h                ; 256 morph steps
        call    SetMorph                ; set morphing params.

        mov     cx, 256
@@MorphLoop:
        call    MorphPoints             ; morph and draw the points.
        mov     ah, 1h
        int     16h
        jz      @@NoPress6
        jmp     RestoreScreen
@@NoPress6:
        loop    @@MorphLoop

        mov     ax, offset ball
        mov     [points], ax            ; set points tabel to ball
        pop     bx                      ; restore the value of bx
        mov     cx, 512
        mov     [delta_x], 1
        mov     [delta_y], -2           ; add a up-down movement
@@RotLoop5:                             ; + fancy rotation
        push    cx
        call    DrawPoints              ; draw the points
        mov     ah, 1h
        int     16h
        jz      @@NoPress7
        jmp     RestoreScreen
@@NoPress7:
        mov     ax, [cs:Sin256 + bx]
        add     ax, 256
        shr     ax, 1
        sub     ax, 128
        mov     [ex], ax                ; set new eye x coord.
        push    bx
        shl     bx, 1                   ; y movement = twice as fast as
        and     bx, 01ffh               ; x movement
        mov     ax, [cs:Sin256 + bx]    ; ax = [-256 .. 256]
        add     ax, 256                 ; ax = [   0 .. 512]
        shr     ax, 1                   ; ax = [   0 .. 256]
        shr     ax, 1                   ; ax = [   0 .. 128]
        sub     ax, 64                  ; ax = [ -64 ..  64]
        mov     [ey], ax                ; store new eye y coord.
        pop     bx
        mov     ax, [cs:Sin256 + bx]
        add     ax, 256
        shr     ax, 1
        shr     ax, 1
        shr     ax, 1
        shr     ax, 1
        shr     ax, 1
        sub     ax, 8                   ; ax = [-8 .. 8]
        mov     [delta_z], ax           ; set new z rotation delta.
        inc     bx
        inc     bx
        and     bx, 01ffh               ; bx = new entry in sine tabel
        pop     cx
        loop    @@RotLoop5

        mov     cx, 8                   ; Zoom out
@@LoopLoop4:
        push    cx
        call    DrawPoints

        mov     ah, 01h                 ; check for keypress
        int     16h
        jz      @@NoPress8
        jmp     RestoreScreen

@@NoPress8:
        mov     ax, [sz]                ; reverse of zoom in
        shl     ax, 1
        mov     [sz], ax
        pop     cx
        loop    @@LoopLoop4

        jmp     @@BigLoop


RestoreScreen:
        mov     ax, 0003h               ; set text mode (80 x 25, 16c)
        int     10h

Uitgang:

@@CheckForKeys:
        mov     ah, 01h                 ; clear the keybuffer
        int     16h
        jz      @@NoKeyWaiting
        xor     ah, ah
        int     16h                     ; get key
        jmp     @@CheckForKeys
@@NoKeyWaiting:
        mov     ah, 04ch
        mov     al, [returncode]
        int     21h                     ; and done.

        END     Begin

