;
;  SURF.ASM  //  ARM 12/93
;

        Ideal
        Model TPascal
        P286
        Radix 10

; Constants:

INCLUDE "meshsize.inc"

        DATASEG

EXTRN   U      : DWord
EXTRN   B      : DWord
EXTRN   CT     : Word
EXTRN   TOPS   : Word
EXTRN   DAMP   : Byte

        CODESEG

PUBLIC UpdateTable;
PUBLIC DrawSurf;

; // UpdateTable : performs one integration step on U[CT]

; Differential equation is:  u  = aý( u  + u  )
;                             tt       xx   yy
;
; Where aý = tension * gravity / surface_density.
;
; Aproximating second derivatives by central differences:
;
;  [ u(t+1)-2u(t)+u(t-1) ] / ëtý = aý (u(x+1)+u(x-1)+u(y+1)+u(y-1)-4u) / hý
;
; (where ët = time step, h=ëx=ëy = mesh resolution
;
; From where u(t+1) may be calculated as:
;                   Ú   1   ¿
; u(t+1) = aýëtý/hý ³ 1 0 1 ³u - u(t-1) + (2-4aýëtý/hý)u
;                   À   1   Ù
;
; When aýëtý/hý = « last term vanishes, giving:
;                   Ú   1   ¿
;        u(t+1) = « ³ 1 0 1 ³u - u(t-1)
;                   À   1   Ù
;
; This needs only 4 ADD/SUB and one SAR operation per mesh point!
;
; (note that u(t-1,x,y) is only used to calculate u(t+1,x,y) so
;  we can use the same array for both t-1 and t+1, needing only
;  two arrays, U[0] and U[1])
;
; Dampening is simulated by subtracting 1/2^n of result.
; n=4 gives best-looking result
; n<4 (eg 2 or 3) thicker consistency, waves die out immediately
; n>4 (eg 8 or 12) more fluid, waves die out slowly
;

       PROC UpdateTable NEAR
       push bp
         mov si, [word ptr U]
         add si, NY*2 - 4
         mov di, si
         add si, NX*NY*2
         test [CT], 1
         jz @@0
         xchg si,di
      @@0:              ; si->next/last, di->this

         mov cl, [Damp]
         mov dx, NX-2

         push ds
         mov ax, [word ptr U+2]
         mov ds, ax

   @@fori:
         add si, 4
         add di, 4
         mov bp, NY-2
      @@forj:
          add si, 2
          add di, 2             ; add up N,S,E,W points :
          mov ax, [di-2*NY]     ; [   u(t,x-1,y)
          add ax, [di+2*NY]     ;   + u(t,x+1,y)
          add ax, [di-2]        ;   + u(t,x,y-1)
          add ax, [di+2]        ;   + u(t,x,y+1) ]
          sar ax,1              ; /2
          sub ax, [si]          ; -u(t-1,x,y)
          mov bx, ax
          sar bx, cl            ; subtract 1/16 of result for dampening
          sub ax, bx
          mov [si],ax           ; save result
          dec bp
         jnz @@forj

         dec dx
       jnz @@fori

       pop ds
       pop bp
       ret
       ENDP


; // DrawSurf : draws water surface in fake 3D
;

       PROC DrawSurf NEAR
P386
        push bp

        mov si, [word ptr U]
        test [CT], 1
        jz @@0
        add si, NX*NY*2
      @@0:                        ; ds:si -> U[CT]

        mov ax, 0a000h
        mov es, ax
        mov di, 199*320           ; es:di -> Screen[199,0]

        mov bx, offset TOPS
        mov cx, NX

        push gs fs ds
        mov ax, ds
        mov fs, ax
        mov ax, [word ptr B+2]
        mov gs, ax
        mov ax, [word ptr U+2]
        mov ds, ax

        @@forX:
          push cx
          push di
          push bx

          mov bx,7                ; highest so far
          mov bp, 200*(101h)
          mov cx, NY
          @@forY:
            sub bx,8              ; each row is 8 (=1 pixel) higher
            mov ax, [si]          ; then the last.
            mov dx, ax
            sub dx, bx
            jng @@1               ; not above current highest
             or ax, 0007          ; round to 7 + a multiple of 8
             mov bx, ax
                          ; dec dx/sar dx,3/.../dec dx/jge @2 (dx+1 times)
             @@2:
              mov [es:di],bp
              sub di,320          ; point to next row, same column
              sub dx,8
              jg @@2      ; (you wouldn't believe how much
                          ;  slower LOOP is on a 486!)
           @@1:
            add si,2              ; point to next column, U[CT,X,Y+1]
            sub bp, 0101h         ; dim color one notch
          dec cx
          jnz @@forY      ; LOOPs suck!

          pop bx
          mov ax, [fs:bx]         ; get last top of column address
          mov [fs:bx], di         ; ...and save current one for next time
          add bx,2                ; (update ptr for next col)

          @@3:
          cmp ax, di
          jae @@4
            mov bp, [gs:di]
            mov [es:di],bp        ; if this column is lower than the
            sub di, 320           ; last one, clear extra rows w/ background
            jmp @@3
          @@4:

          pop di                  ; fetch addr of row 199
          add di,2                ; skip to next column
          pop cx                  ; fetch counter
          dec cx
          jnz @@forX      ; did I mention...?  ;-)

          pop ds fs gs
          pop bp
P286
       ret
       ENDP


       END

