{Magnify glass moving over ANY background, needs 386 machine}
{Jaco van Niekerk, jvn@rkw.rau.ac.za}
{Mail me if you have any questions/ideas/comments about this code}
program magnify_glass;
uses crt;

const r : byte = 40;                  {radius of sphere}
      h : integer = 20;               {distace from plane to focus point}
      d : byte = 80;                  {diameter of magnify glass}

var offs : array[0..22500] of integer; {150x150}
    b, v : pointer;

{This is the easiest mouse routines available!}
function initmouse: word;assembler;
{Initialize mouse driver}
asm mov ax, 0h; int 33h; end;

procedure showmousecursor;assembler;
{Instruct BIOS to show mouse cursor}
asm mov ax, 01h; int 33h; end;

procedure hidemousecursor;assembler;
{Instruct BIOS to hide mouse cursor}
asm mov ax, 02h; int 33h; end;

procedure getmousepos (var x, y, button: word);
{Return the current location of the mouse}
var x1, y1, b : word;
begin
     Asm mov ax, 03h; int 33h; mov [b], bx; mov [x1], cx; mov [y1], dx; end;
     x:=x1; y:=y1; button := b;
end;

Procedure setmousewindow (X1, Y1, X2, Y2: Word);assembler;
{Set the mouse window}
asm mov ax, 07h; mov cx,[x1]; mov dx,[x2]; int 33h; inc ax;
    mov cx,[y1]; mov dx,[y2]; int 33h; end;

procedure copyw(source : pointer; dest : pointer; cnt : word);assembler;
asm {copy [cnt] words from [source] to [dest]}
   les di, [dest]    {[dest] moves into [es:di]}
   push ds           {ds must be preserved}
   lds si, [source]  {[source] moves into [ds:di]}
   mov cx, [cnt]     {cx <- [cnt] : number of words to move}
   cld               {clear the direction flag, si will increment}
   rep movsw         {copies cx words from source to destination}
   pop ds            {restore ds to it's original state}
end;

procedure cls(dest : pointer);assembler;
asm
   les di, [dest]
   mov cx, 16000
   xor ax, ax
   db $66; rep stosw
end;

procedure calc_mask; {a bit of maths!}
{this calculates the pixel mask, to optimize the speed}
var x, y, z : integer;
    ux, uy : integer;
    sx, sy : integer;
begin
     for y:=0 to d do
         for x:=0 to d do
         begin
              ux:=x - d div 2;
              uy:=y - d div 2;
              if (ux*ux+uy*uy < r*r) then {point is defined on sphere}
              begin
                   z:=round(sqrt(r*r-ux*ux-uy*uy));
                   sx:=round((h-z)*(ux/z)); {took me 2 hours to work, these}
                   sy:=round((h-z)*(uy/z)); {two formulas out!!!}
                   {point on "s phere"}
                   offs[x+y*d]:=sy*320+sx;
              end else offs[x+y*d]:=0;
         end;
end;

procedure construct(xp, yp : word);
{if you want to optimize the code, do it in this procedure, since it}
{does all the main thingies, please send me a copy then too ;)  }
var seg1, ofs1, seg2, ofs2 : word;
    x, y : word;
    vp, hp : word;
    ux, uy : integer;
begin
     seg1:=seg(b^); ofs1:=ofs(b^);
     seg2:=seg(v^); ofs2:=ofs(v^);
     copyw(b,v,32000);
     for y:=0 to d do
         for x:=0 to d do
         begin
              ux:=x - d div 2;
              uy:=y - d div 2;
              vp:=y+yp+offs[y*d+x] div 320;
              hp:=x+xp+offs[y*d+x] mod 320;
              if (vp<200) and (vp>0) and (xp<320) and (xp>0) and
                 (sqr(r-1)> ux*ux+uy*uy) then
              begin
                 mem[seg2:ofs2+(y+yp)*320+x+xp]:=
                    mem[seg1:(ofs1+vp*320+hp)];
              end;
         end;
     copyw(v,ptr($a000,000),32000);
end;

procedure background;
{replace this with any background, of your choice, even a dynamic }
{background, like a fire or plasma, just remember to copy it to b^}
var i, j : integer;
begin
     directvideo:=false;
     writeln; writeln; writeln; writeln;
     textcolor(15);
     writeln('  This is a test. Please feel free');
     writeln('  to do anything you wish with this');
     writeln('  code, but please do give credit');
     writeln('  where credit is due.');
     writeln;
     writeln('  Real programmers, do!');
     writeln;
     writeln('  J v Niekerk (jvn@rkw.rau.ac.za)');
     writeln;
     writeln(' O, yes, if nothing is happening,');
     writeln(' now try moving your mouse around!!');
     directvideo:=true;

     for i:=0 to 319 do
         for j:=0 to 199 do
             if mem[$a000:320*j+i]=0 then mem[$a000:320*j+i]:=((i+j) mod 10)+20;

     copyw(ptr($a000,000),b,32000);
end;

var deg : real;
    x, y, but : word;

begin
     clrscr;
     getmem(v,64000); getmem(b,64000);

     asm
        mov ax, 13h
        int 10h
     end;

     background;
     {calc_mask;}
     initmouse;
     setmousewindow(5,5,315-d, 200-d);

     repeat
           getmousepos(x, y, but);
           construct(x,y);
     until but=1;

     freemem(v, 64000);
     freemem(b, 64000);
     asm
        mov ax, 03h
        int 10h
     end;
end.

