{$R-}
unit uwater;

interface

procedure water_init;
procedure water_action;
procedure water_close;

implementation

Uses CRT,Video,USM;

const biglfiles : array[ 0..5 ] of String = ('wlb1.raw','wlb2.raw','wlb3.raw','wlb4.raw','wlb5.raw','wlb6.raw');
const smllfiles : array[ 0..5 ] of String = ('wls1.raw','wls2.raw','wls3.raw','wls4.raw','wls5.raw','wls6.raw');

type biglight = array[ 0..16384 ] of dword;
     lightdata = record
         x     : longint;
         y     : longint;
         z     : longint;
        end;
var
         WaterBuf : array[ 0..127999 ] of Integer; -- two buffers in one
           BufScr : array[ 0..64000 ] of byte; -- picture and screen buffers
           paleta : array[ 1..768 ] of byte;
           datbuf : array[ 0..64000+10*320 ] of dword;
           t2, t1,
  frame, WaterAdr,
   VirScr, DatAdr : LongInt;
         biglightsd : array[ 0..5 ] of biglight;
         smllightsd : array[ 0..5 ] of biglight;
              plik  : file;
    i, nx, ny, lic  : word;
                cp  : byte;
                ch  : char;
          biglights : array[0..5] of lightdata;
          smllights : array[0..5] of lightdata;
  psp_seg: dword;
  music: PUSM;
  TERM:boolean;

  korder,vorder,aorder:byte;

--------------------------------------------------------------
----- Procedures & functions for demo engine start here ------
--------------------------------------------------------------

procedure putimagea(x,y,sx,sy:longint;source:pointer;fade:byte);
label
  quit;
var
  x1,x2,y1,y2:longint;
{  i,j:longint;}
  r,g,b:byte;
begin
  if x>319 then goto quit;
  if y>199 then goto quit;
  if (sx+x)<0 then goto quit;
  if (sy+y)<0 then goto quit;
  if x<0 then x1:=0-x else x1:=0;
  if y<0 then y1:=0-y else y1:=0;
  if (x+sx)>319 then x2:=319-x else x2:=sx-1;
  if (y+sy)>199 then y2:=199-y else y2:=sy-1;
      asm
        mov edx,y1

       @loopy:
        mov ecx,x1
        push edx

        mov esi,[source]
        mov eax,edx
        mul sx
        add eax,ecx
        mov ebx,3
        mul ebx
        add esi,eax

        pop edx
        push edx
        mov edi,[Video_SCREEN]
        mov eax,320
        mov ebx,y
        add ebx,edx
        mul ebx
        add eax,x
        add eax,ecx
        shl eax,2
        add edi,eax

        pop edx
       @loopx:
        mov eax,[esi]
        add esi,3

        mov bl,fade
        sub al,bl
        jnc @ok0
        mov al,0
       @ok0:
        sub ah,bl
        jnc @ok1
        mov ah,0
       @ok1:
        mov bh,ah
        ror eax,16
        sub al,bl
        jnc @ok2
        mov al,0
       @ok2:
        mov ah,bh
        mov ebx,[edi]
        add al,bl
        jnc @ok3
        mov al,255
       @ok3:
        add ah,bh
        jnc @ok4
        mov ah,255
       @ok4:
        ror eax,16
        ror ebx,16
        add al,bl
        jnc @ok5
        mov al,255
       @ok5:
        ror eax,16
        stosd

        inc ecx
        cmp ecx,x2
        jbe @loopx

        inc edx
        cmp edx,y2
        jbe @loopy
      end;
  quit:
end;

procedure convertimage(image:pointer;size:dword);
begin
  asm
    mov esi,[image]
    mov edi,[image]
    mov eax,4
    mov ebx,size
    dec ebx
    mul ebx
    add edi,eax
    mov eax,3
    mul ebx
    add esi,eax
    mov ecx,size
   @loop0:
    mov eax,[esi]
    mov bh,ah
    ror eax,16
    mov ah,bh
    mov [edi],eax
    sub esi,3
    sub edi,4
    loop @loop0
  end;
end;

procedure LoadBitmaps;
var
      n, i : byte;
     Fsize : Dword;
     counter : dword; counter2 : dword;
     loadfile : byte;
begin
  assign( plik, 'lopots.raw' );
  reset( plik, 1 );
  BlockRead( plik, DatBuf[320*5], 192000);
  convertimage(@datbuf+320*5*4,64000);
  For Counter2:=0 To 4 Do
   For Counter:=0 To 319 Do DatBuf[Counter2*320+Counter]:=DatBuf[320*5+Counter];
  For Counter2:=0 To 4 Do
   For Counter:=0 To 319 Do DatBuf[(Counter2+205)*320+Counter]:=DatBuf[320*199+Counter];
  close(plik);
  For Counter:=0 To 5 Do Begin
   Assign(plik,biglfiles[counter]);
   Reset(plik,1);
   BlockRead(plik,biglightsd[counter],128*128*3);
   Close(plik);
   Assign(plik,smllfiles[counter]);
   Reset(plik,1);
   BlockRead(plik,smllightsd[counter],64*64*3);
   Close(plik);
  End;
end;

procedure SetPal; assembler;
asm
  xor  AL, AL
  mov  DX, $3C8
  out  DX, AL
  mov  ESI, offset paleta
  mov  CX, 768
  mov  DX, $3C9
  rep  outsb
end;

procedure ShowWater( Cpg : byte ); assembler;
var
     Cpage, Spage : dword;            -- offsets of buffers
     currwoffs    : dword;
 asm
            mov  AL, [Cpg]
            and  AL, $01                 -- which page ?
             jz  @setp1
            mov  [Cpage], 128000        -- Cpage set as the second page
            mov  [Spage], 0
            jmp  @setp2
   @setp1:
            mov  [Cpage], 0             -- Cpage set as the first page
            mov  [Spage], 128000
   @setp2:
            mov  DX, 1                  -- Y counter
            xor  EBX, EBX
            mov  EBX, 640               -- EBX:=( Y*320 )*2
            mov  EDI, [WaterAdr]
            add  EDI, EBX               -- "WaterAdr" = ofs of our buffers
            mov  ESI, EDI               -- to this point EDI = ESI
            add  EDI, [Cpage]
            add  ESI, [Spage]           -- here is the difference
            mov  CX, 318                -- X counter: screen size-2
   @1stlp:                              -- main loop is here !!!
            add  ESI, 2
            add  EDI, 2                 -- use integers so all *2
            mov  AX, [EDI-2]
            add  AX, [EDI-638]
            add  AX, [EDI-640]
            add  AX, [EDI-642]
            add  AX, [EDI+2]
            add  AX, [EDI+638]
            add  AX, [EDI+640]
            add  AX, [EDI+642] -- eight pixel method. Slower but looks better
            sar  AX, 2
            mov  BX, [ESI]
            sub  AX, BX
            mov  BX, AX
            sar  BX, 8                 -- density of water
            sub  AX, BX
            mov  [ESI], AX             -- done. move value to dest. buffer
            dec  CX
            jnz  @1stlp                -- end of "little" loop
            add  ESI, 4                -- add 4 up to 320 (*2 of course)
            add  EDI, 4                -- use integers so all *2
            mov  CX, 318               -- restore X counter
            inc  DX
            cmp  DX, 198
             jb  @1stlp                -- end of "calculate water"
            mov  i, 198            -- i = counter. Y size of screen: 200-2
            mov  EDI, [WaterAdr]
            add  EDI, [Spage]
            mov currwoffs,EDI
            mov  ESI, [Video_Screen]
            mov  EBX, 63360        -- ( Y size of screen-2 )*320
            push ebx
            shl  ebx, 2
            add  ESI, EBX          -- ESI:=Ofs( mem[ VirScr+i*320 ] )
            pop  ebx
            shl  EBX, 1
            add  EDI, EBX          -- EDI:=Ofs( WaterBuf[ Spage+i*320 ] )
            xor  CX, CX
    @lloop:                        -- main loop starts here !!!
            inc  CX
            xor  EBX, EBX
            inc  EDI
            inc  EDI               -- use integers, so all *2
            mov  BX, [EDI]         -- BX:=WaterBuf[ Spage+i*320+j ]
            mov  AX, [EDI+2]       -- DX:=WaterBuf[ Spage+i*320+j+1 ]
            sub  BX, AX            -- BX:=BX-DX   (dy)
            mov  DX, [EDI]         -- DX:=WaterBuf[ Spage+i*320+j ]
            mov  AX, [EDI+640]     -- AX:=WaterBuf[ Spage+i*320+j+320 ]
            sub  DX, AX            -- DX:=DX-AX   (dx)
            sar  DX, 3
            add  DX, CX            -- DX: ofsx = ( wdx SHR 3 ) + CX(X)
            sar  BX, 3
            add  BX, [i]           -- BX: ofsy = ( wdy SHR 3 ) + i (Y)
            shl  BX, 6
            mov  AX, BX
            shl  BX, 2
            add  BX, AX            -- BX:= ofsy*320
            add  BX, DX            -- BX = ofsx+ofsy*320
            push ebx
            shl  ebx,2
            add  EBX, [DatAdr]
            mov  eax, [EBX]         -- AL:=mem[ DatAdr+BX ]
            pop  ebx
            add  ESI,4
            mov  [ESI], EAX         -- mem[ VirScr+i*320+j ]:=AL
            cmp  CX, 318           -- X size of screen: 320-2
             jb  @lloop
            xor  CX, CX
            sub  ESI, 638*4          -- sub X screen size and all "inc ESI" in lloop
            sub  EDI, 1276         -- sub 2*X screen size and all "inc EDI"*2 in lloop
            dec  i
            and  [i], $FF
            jnz  @lloop            -- end of "paint water"
end; { of procedure "ShowWater" }

procedure calcbiglights;
begin
  biglights[0].x:=round( cos( lic/40 )*110+160 );
  biglights[0].y:=round( sin( lic/20 )*80+100 );
  biglights[0].z:=round( sin( lic/30 )*80 );

  biglights[1].x:=round(-cos( lic/20 )*110+160 );
  biglights[1].y:=round(-sin( lic/40 )*80+100 );
  biglights[1].z:=round(-sin( lic/30 )*80 );

  biglights[2].x:=round(sin( lic/25)*70+160);
  biglights[2].y:=round(cos( lic/30)*70+100);
  biglights[2].z:=round(-sin( lic/25)*70);

  biglights[3].x:=round(sin( lic/40)*30+140);
  biglights[3].y:=round(cos( lic/25)*70+100);
  biglights[3].z:=round(-sin( lic/30)*90);

  biglights[4].x:=round(sin( lic/25)*50+160);
  biglights[4].y:=round(cos( lic/35)*60+100);
  biglights[4].z:=round(-sin( lic/30)*70);

  biglights[5].x:=round(sin( lic/45)*80+160);
  biglights[5].y:=round(cos( lic/25)*30+100);
  biglights[5].z:=round(-sin( lic/25)*70);
end;

procedure calcsmllights;
begin
  smllights[0].x:=round(- cos( lic/40 )*110+160 );
  smllights[0].y:=round(- sin( lic/20 )*80+140 );
  smllights[0].z:=round(- sin( lic/30 )*80 );

  smllights[1].x:=round(cos( lic/20 )*110+160 );
  smllights[1].y:=round(sin( lic/40 )*80+140 );
  smllights[1].z:=round(sin( lic/30 )*80 );

  smllights[2].x:=round(-sin( lic/25)*70+160);
  smllights[2].y:=round(-cos( lic/30)*70+140);
  smllights[2].z:=round(sin( lic/25)*70);

  smllights[3].x:=round(-sin( lic/40)*30+140);
  smllights[3].y:=round(-cos( lic/25)*70+140);
  smllights[3].z:=round(sin( lic/30)*90);

  smllights[4].x:=round(-sin( lic/25)*50+160);
  smllights[4].y:=round(-cos( lic/35)*60+140);
  smllights[4].z:=round(sin( lic/30)*70);

  smllights[5].x:=round(-sin( lic/45)*80+160);
  smllights[5].y:=round(-cos( lic/25)*30+140);
  smllights[5].z:=round(sin( lic/25)*70);
end;

procedure newint;
begin
 inc(counter);
end;

procedure water_init;
begin
 VirScr:=Ofs( BufScr );
 DatAdr:=Ofs( DatBuf )+320*5*4;
 WaterAdr:=Ofs( WaterBuf );
 FillChar(WaterBuf,256000,$00);
 cp:=0;  lic:=0;
 LoadBitmaps;
end;

procedure water_close;
begin
end;

procedure water_action;
begin
 lic:=0;
 counter:=0;
  asm
   mov al,[_order]
   mov korder,al
  end;
  term:=false;
  vorder:=korder+4;
  repeat
    ShowWater( cp );
    inc(lic);
    calcbiglights; calcsmllights;
    for counter:=0 to 5 do putimagea(biglights[counter].x-64,biglights[counter].y-64,128,128,@biglightsd[counter],64);
    for counter:=0 to 5 do putimagea(smllights[counter].x-64,smllights[counter].y-64,64,64,@smllightsd[counter],64);
    for counter:=0 to 5 do if biglights[counter].z<0 then WaterBuf[biglights[counter].x+biglights[counter].y*320]:=500;
    asm
     mov al,[_order]
     mov aorder,al
    end;
    if (aorder=vorder) then term:=true;

    Video_Copy;

    cp:=cp XOR $01;
    if TerminateDemo Then ExitDemo;
    
  until{ (KeyPressed) or} (term);
end;

BEGIN
END.