unit lights;

interface

uses routines,playmods,map;

const vidseg = $a000;
      points = 24;
      zc = 256;
      xc = 160;
      yc = 100;
      xsize = 32;
      ysize = 32;
      xrange = 160;
      yrange = 160;
      zrange = 160;
      skip = 4;

      xinc = 0;
      yinc = 128;
      zinc = 512;
      sinsize = 360;

      gap = 80;

var panseg,panseg2,virseg,flareseg : word;
    panscr,panscr2,virscr,flarescr : pointer;
    loop : word;
    x,y,z : integer;
    p : word;
    stab,ctab : array[0..sinsize] of real;
    point : array[1..points,1..3] of integer;
    trans : array[1..points,1..3] of integer;
    pal : array[0..255,1..3] of byte;
    palOK : boolean;
    frames : word;
    loppu : boolean;
    trackstatus : miscdata;
    xphi,yphi,zphi : longint;

procedure do_lights(nosound:boolean);

implementation

procedure do_lights(nosound:boolean);

procedure sprite(x,y:integer;col:word); assembler;
var sy,sx:integer;
asm
  push ds

  mov cx,[x] { ds:si = piste flaressa }
  mov dx,[y]
  sub cx,16
  sub dx,16 { flaren keskipiste = x,y }
  mov [sx],cx
  mov [sy],dx { es:di (sx,sy) = piste virsegiss„ }

  mov ax,[virseg]
  mov es,ax
  mov ax,[flareseg]
  mov ds,ax

  mov ax,dx { di = sy*320+sx }
  shl ax,6
  mov di,ax
  shl ax,2
  add di,ax
  add di,cx
  xor si,si { si = 0 }
  xor dx,dx { dx pit„„ kirjaa flare X:st„ }

@inner:
  cmp [sy],199 { inscreen check (sx,sy) }
  jg @noPixel
  cmp [sy],0
  jl @noPixel
  cmp [sx],319
  jg @noPixel
  cmp [sx],0
  jl @noPixel

  xor bx,bx      { ynn„t„„n ruutu, flareseg ja col }
  mov bl,[ds:si] { flareseg pixel }
  mov ax,[col]
  sub bx,ax
  cmp bx,0
  jg @positive
  xor bx,bx
@positive:
  mov al,[es:di] { virseg pixel }
  add ax,bx      { ax = v„ri }

  cmp ax,256     { v„rin byte-chekki }
  jl @skip1
  mov ax,255
@skip1:
  mov [es:di],al { ...ja piirret„„n al }

@noPixel:
  inc si { p„ivitet„„n indexit sun muut muuttujat }
  inc di
  inc dx
  inc [sx]
  cmp dx,32
  jnz @skip3 { jos rivi ei lopu viel„, hypp„„ @skip3 }

  xor dx,dx { jos dx = 32 (rivin loppu) niin... }
  mov ax,[x] { sx = x-16 }
  sub ax,16
  mov [sx],ax
  inc [sy]
  add di,320-32 { di hypp„„ rivin alasp„in }

@skip3:
  cmp si,32*32 { jos flaren offsetti on 32*32, lopeta }
  jnz @inner

  pop ds
end;

{ rotate object [XYZ], fixed point sinit }
procedure rotate;

var x,y,z : integer;
    sinix,kosix,
    siniy,kosiy,
    siniz,kosiz : real;

begin
  for loop:=1 to points do begin
    x := point[loop,1];
    y := point[loop,2];
    z := point[loop,3];
    sinix := stab[xphi shr 8];
    kosix := ctab[xphi shr 8];
    siniy := stab[yphi shr 8];
    kosiy := ctab[yphi shr 8];
    siniz := stab[zphi shr 8];
    kosiz := ctab[zphi shr 8];
{ 3Dica:
                   Ú                                      ¿
                   ³ cy*cz          cy*sz          -sy    ³
     [X]*[Y]*[Z] = ³ sx*sy*cz-cx*sz sx*sy*sz+cx*cz  sx*cy ³
                   ³ cx*sy*cz+sx*sz cx*sy*sz-sx*cz  cx*cy ³
                   À                                      Ù
}
    trans[loop,1]:=round((kosiy*kosiz*x)+((sinix*siniy*kosiz*y)-(kosix*siniz*y))+
                         ((kosix*siniy*kosiz*z)+(sinix*siniz*z)));
    trans[loop,2]:=round((kosiy*siniz*x)+((sinix*siniy*siniz*y)+(kosix*kosiz*y))+
                         ((kosix*siniy*siniz*z)-(sinix*kosiz*z)));
    trans[loop,3]:=round((-siniy*x)+(sinix*kosiy*y)+(kosix*kosiy*z));

  end;
  if xphi shr 8<sinsize then xphi:=xphi+xinc else xphi:=0;
  if yphi shr 8<sinsize then yphi:=yphi+yinc else yphi:=0;
  if zphi shr 8<sinsize then zphi:=zphi+zinc else zphi:=0;
end;

procedure drawPallot;
var dx,dy,dz : integer;
    col : integer;
    sx,sy : integer;

begin
  for p:=1 to points do begin
    dx:=(x+trans[p,1]) * 256;
    dy:=(y+trans[p,2]) * 256;
    dz:=z-trans[p,3];
    sx:=trunc(dx / (zc+dz)) + xc;
    sy:=trunc(dy / (zc+dz)) + yc;
    if (sx>0)and(sx<320)and
       (sy>0)and(sy<200)then begin
      col:=dz;
      if col<0 then col:=0;
      sprite(sx,sy,col);
    end;
  end;
end;

procedure addfont2vir(source,dest,yOff,xOff,valo:word); assembler;
asm
  push ds          { ds talteen }
  mov ds,[source]
  mov es,[dest]
  mov ax,yOff
  sub ax,21         { menn„„n ihan keskelle }
  shl ax,6
  mov di,ax
  shl ax,2
  add di,ax
  xor si,si
  mov cx,320*42
  sub cx,yOff
@inner:
  xor ax,ax
  xor bx,bx
  mov al,[ds:si]
  cmp ax,0
  jz @over1
  add ax,valo
  cmp ax,0
  jg @over1
  mov ax,0
@over1:
  mov bl,[es:di]
  add ax,bx
  cmp ax,256
  jb @jump
  mov ax,255
@jump:
  mov [es:di],al
  inc di
  inc si
  loop @inner
  pop ds           { palautetaan ds }
end;

procedure blurTxt; assembler; { k3wl! }
    asm
      mov es,[panseg]
      mov di,1
      mov si,320*42-2
      @outer:

          xor ax,ax
          xor bx,bx
          mov al,[es:di+1]
          mov bl,[es:di-1]
          add ax,bx
          shr ax,1
          mov [es:di],al
          inc di

      dec si
      jne @outer
    end;

procedure flipe(src,dest:word); assembler;
asm
  push ds
  mov ax,[src]
  mov ds,ax
  mov ax,[dest]
  mov es,ax
  xor si,si
  xor di,di
  mov cx,320*21
  rep movsw
  pop ds
end;

begin
  randomize;
  getmem(virscr,64000);
  virseg:=seg(virscr^);
  cls(virseg);
  getmem(flarescr,32*32);
  flareseg:=Seg(flarescr^);
  getmem(panscr2,320*42);
  panseg2:=Seg(panscr2^);
  getmem(panscr,320*42);
  panseg:=Seg(panscr^);
  for loop:=0 to sinsize do ctab[loop]:=cos(loop*pi/(sinsize div 2));
  for loop:=0 to sinsize do stab[loop]:=sin(loop*pi/(sinsize div 2));
  loadMAPe(flareseg,'flare.map',32*32);
  loadMAPe(panseg,'paneeli.map',320*42);
  flipe(panseg,panseg2);
  loadPAL('pal1.pal');
  for p:=1 to points do begin
    point[p,1]:=random(xrange)-(xrange div 2);
    point[p,2]:=random(yrange)-(yrange div 2);
    point[p,3]:=random(zrange)-(zrange div 2);
  end;
  x:=0;
  y:=0;
  z:=0;
  frames:=0;
  repeat
    rotate;
    cls(virseg);
    drawPallot;
    addfont2vir(panseg,virseg,100,0,0);
    blurtxt;
    if nosound then begin
      if frames=gap then begin
        frames:=0;
        flipe(panseg2,panseg);
      end;
    end else begin
      get_track_status(19,trackstatus);
      if trackstatus[7]=0 then flip(panseg2,panseg);
      if frames=skip then begin
        get_module_status(trackstatus);
        if trackstatus[0]=12 then loppu:=true;
        frames:=0;
      end;
    end;
    inc(frames);
    retrace;
    flip(virseg,vidseg);
  until keypressed;
  freemem(virscr,64000);
  freemem(flarescr,32*32);
  freemem(panscr,320*42);
  freemem(panscr2,320*42);
end;

end.