{$F+,R-}
unit Eyes;
interface

uses graph,mouse;

type EyeDataRec = record
       BColor : byte;    {eye background color}
       EColor : byte;    {eye rim color}
       PColor : byte;    {pupil color}
       Style  : integer; {eye style}
       Xasp   : word;    {screen X aspect}
       Yasp   : word;    {screen Y aspect}

       Exr   : integer; {Eyeball X range}
       Eyr   : integer; {Eyeball Y range}
       Bpsx  : integer; {Pupil X size}
       Bpsy  : integer; {Pupil Y size}

       Lesx : integer; {Left eyeball X start pos}
       Lesy : integer; {Left eyeball Y start pos}
       Lecx : integer; {Left eyeball X center pos}
       Lecy : integer; {Left eyeball Y center pos}
       Leex : integer; {Left eyeball X end pos}
       Leey : integer; {Left eyeball Y end pos}

       Resx : integer; {Right eyeball X start pos}
       Resy : integer; {Right eyeball Y start pos}
       Recx : integer; {Right eyeball X center pos}
       Recy : integer; {Right eyeball Y center pos}
       Reex : integer; {Right eyeball X end pos}
       Reey : integer; {Right eyeball Y end pos}

       Pexl : integer; {Left eye X Position}
       Peyl : integer; {Left eye Y Position}
       Pexr : integer; {Right eye X Position}
       Peyr : integer; {Right eye Y Position}
       TPexl : integer; {Temp Left eye X Position}
       TPeyl : integer; {Temp Left eye Y Position}
       TPexr : integer; {Temp Right eye X Position}
       TPeyr : integer; {Temp Right eye Y Position}

     end;


procedure MakeEyes(var EyeData:EyeDataRec;
                   Xp,Yp,Size,How:integer; Eye,Edge,Pupil:byte);
procedure LookAt(var EyeData:EyeDataRec; Xp,Yp:integer);


implementation

  {----------------------------------------------------}
  {rounding divide. divides m into d and rounds up result}
  function rdiv(d:longint; m:word):word;
  Inline(
    $5B        { pop bx}
    /$58       { pop ax}
    /$5A       { pop dx}
    /$F7/$F3   { div bx}
    /$01/$D2   { add dx,dx}
    /$39/$D3   { cmp bx,dx}
    /$73/$01   { jnc nornd}
    /$40       { inc ax}
            ); {nornd:}


  {----------------------------------------------------}
  function Limit(Value,Start,Stop:integer):integer;
  Inline(
    $58        { pop ax  ;Stop}
    /$5B       { pop bx  ;Start}
    /$59       { pop cx  ;Value}
    /$39/$C1   { cmp cx,ax}
    /$7F/$08   { JG done}
    /$89/$D8   { mov ax,bx}
    /$39/$C1   { cmp cx,ax}
    /$7C/$02   { JL done}
    /$89/$C8   { mov ax,cx}
            ); {done:}

  {----------------------------------------------------}
  {compute an integer based log2}
  {$F+} function ILog2(Value:longint):word; external;
  {$L INTLOG2}


  {----------------------------------------------------}
  {put the eyes on the screen in the location specified}
  procedure MakeEyes(var EyeData:EyeDataRec;
                     Xp,Yp,Size,How:integer; Eye,Edge,Pupil:byte);
  begin
    with EyeData do
    begin
      Style := How;                   {store away pattern info}
      BColor := Eye;                  {and the colors}
      EColor := Edge;
      PColor := Pupil;

      GetAspectRatio(Xasp,Yasp);      {compute graphics eye X/Y size}
      Eyr  := (Xasp*Size*2)div Yasp;  {adjusted for screen aspect ratio}
      Exr  := Size;

      Lecx := Xp;
      Lesx := Lecx-(Exr div 2);       {compute left eye parameters}
      Leex := Lesx+Exr;
      Lecy := Yp;
      Lesy := Lecy-(Eyr div 2);
      Leey := Lesy+Eyr;

      Recx := Xp+(Exr*3);             {compute right eye parameters}
      Resx := Recx-(Exr div 2);
      Reex := Resx+Exr;
      Recy := Yp;
      Resy := Recy-(Eyr div 2);
      Reey := Resy+Eyr;

      Bpsx := Exr div 5;              {compute pupil X/Y size}
      Bpsy := Eyr div 5;

      Pexl := Lecx;                   {default pupil start to center of eye}
      Peyl := Lecy;
      Pexr := Recx;
      Peyr := Recy;

      HideMouse;                       {hide the mouse while we do this}
      SetFillStyle(SolidFill,BColor);  {draw the eyes on the screen}
      SetColor(EColor);
      FillEllipse(Pexl,Peyl,Exr,Eyr);
      FillEllipse(Pexr,Peyr,Exr,Eyr);

     { Rectangle(Lesx,Lesy,Leex,Leey); }  {show pupil work area}
     { Rectangle(Resx,Resy,Reex,Reey); }  {  (for debugging) }

      SetFillStyle(Solidfill,PColor);   {now draw the pupils }
      SetColor(PColor);                 {(Orphan Anney we ain't!)}
      FillEllipse(Pexl,Peyl,Bpsx,Bpsy);
      FillEllipse(Pexr,Peyr,Bpsx,Bpsy);
      ShowMouse;                {all done, so let 'em have the mouse back}
    end;
  end;


  {----------------------------------------------------}
  {compute where the pupil is placed within the eye}
  function Map(Style,Start,Center,Stop,Max:integer; Pos:longint):integer;
  begin
    case Style of
      1: begin
           if Pos-Center > 0 then  {compute scaled pupil X location}
             Map := Center+rdiv((Stop-Center)*4,rdiv((Max-Center)*4,Pos-Center))
           else if Pos-Center < 0 then
             Map := Center-rdiv((Center-Start)*4,rdiv(Center*4,abs(Pos-Center)))
           else Map := Center;
         end;
      2: begin
           if (Pos-Center) > 0 then  {compute log2 pupil X location}
           begin
             Map := Center+rdiv(longint(ILog2(Pos-Center))*4,
                           rdiv(longint(ILog2(Max-Center))*4,Stop-Center));
           end
           else if (Pos-Center) < 0 then
           begin
             Map := Center-rdiv(longint(ILog2(abs(Pos-Center)))*4,
                           rdiv(longint(ILog2(Center))*4,Center-Start));
           end
           else Map := Center;
         end;
      else Map := Limit(integer(Pos),Start,Stop); {compute clipped X location}
    end; {case}
  end;



  {----------------------------------------------------}
  {point the pupils at the indicated screen location}
  procedure LookAt(var EyeData:EyeDataRec; Xp,Yp:integer);
  begin
    with EyeData do
    begin
      TPexl := Map(Style,Lesx,Lecx,Leex,GetMaxX,Xp);
      TPeyl := Map(Style,Lesy,Lecy,Leey,GetMaxY,Yp);
      TPexr := Map(Style,Resx,Recx,Reex,GetMaxX,Xp);
      TPeyr := Map(Style,Resy,Recy,Reey,GetMaxY,Yp);

      {if the pupil location changed update the pupils}
      if (TPexl<>Pexl) or (TPeyl<>Peyl) or (TPexr<>Pexr) or (TPeyr<>Peyr) then
      begin
        HideMouse;
        SetFillStyle(SolidFill,BColor);  {restore eye background}
        SetColor(BColor);
        FillEllipse(Pexl,Peyl,Bpsx,Bpsy);
        FillEllipse(Pexr,Peyr,Bpsx,Bpsy);
        Pexl := TPexl;
        Peyl := TPeyl;
        Pexr := TPexr;
        Peyr := TPeyr;
        SetFillStyle(Solidfill,PColor);  {draw new pupil}
        SetColor(PColor);
        FillEllipse(Pexl,Peyl,Bpsx,Bpsy);
        FillEllipse(Pexr,Peyr,Bpsx,Bpsy);
        ShowMouse;
      end;
    end;
  end;


{----------------------------------------------------}
{no initialization}
end.

