[Back to EGAVGA SWAG index] [Back to Main SWAG index] [Original]

    { Updated EGAVGA.SWG on May 26, 1995 }

    {
    From: Scott Stone <Scott.Stone@m.cc.utah.edu>

    Ok, here's that 3-D starfield code that I promised.  (it works)
    }

    Program Starfield_3D;
    Uses dos,crt;
    Const
      NumStars=100;
      StarSpeed=20;
    {change these to change the # of stars/speed, then recompile}
    Type
      Starrec=record
        x : integer;
        y : integer;
        z : integer
      end;
    Var
      a,b,c : integer;
      ch : char;
      stars : array [1..numstars] of starrec;
      p2,p3 : pointer; {Pointers to "virtual" VGA screens}

    Procedure InitVGA;
    Begin
      asm
        mov ax,13h
        int 10h
      end;
    end; {Moves the 320x200x256 mode identifier, 13 hexadecimal, into
          the AX system register then calls interrupt 10 hex, which handles
          the video card.  Basically, it sets up the video mode}

    Procedure Restoretext;
    begin
      asm
        mov ax,03h
        int 10h
      end;
    end; {restores textmode - text mode is mode 03 hex}

    Procedure AllocatePages;
    Begin
      getmem(p2,64000);
      getmem(p3,64000);
    End; {gets 64k for each of the 2 pointer variables, p2 and p3}
         {These pointers represent "imaginary" vga pages, for swapping}

    Procedure ClearPage3;
    var
      i : longint;
    Begin
      for i:=0 to 63999 do
      begin
        mem[seg(p3^):i]:=0;
      end;
    end;

    Procedure Deallocatepages;
    begin
      freemem(p2,64000);
      freemem(p3,64000);
    End; {frees system memory so you don't get a heap overflow later}

    Procedure SwapPages;
    Begin
      move(mem[seg(p2^):0],mem[$A000:0],64000);
      move(mem[seg(p3^):0],mem[seg(p2^):0],64000);
    End;
        {Moves the data from the imaginary "page 2" to the visible page #1,}
        {Then moves the blank page 3 over to page 2, to start over.  this}
        {is how you do smooth animation.}

    Procedure PutPixel(x,y : integer; c : integer);
    Begin
      mem[$A000:((320*y)+x)]:=c;
    End;
        {A000 Hex is the VGA segment address - the thing after the colon is
         the offset - imagine a 320x200 array, that's how you'd find the
         "linear" address in the array.  After finding the right byte, it simply
         sets it equal to c, the color of the pixel you want}

    Procedure PP2(x,y : integer; c: integer);
    begin
      mem[seg(p2^):((320*y)+x)]:=c;
    End;
        {Same as putpixel, but puts it on the imaginary page #2 instead of the
         visual page}

    Procedure CalculateStars;
    Begin
      for a:=1 to numstars do
      begin
        stars[a].x:=(random(2000)-1000);
        {this produces a range from -1000 to +1000}
        stars[a].y:=(random(2000)-1000);
        stars[a].z:=(random(400)+1); {don't want Z to ever be negative -you'll see}
      end;
    end;
        {Basically, we've calculated the stars' initial positions}

    Procedure DisplayStars;
    Const
      expf=75; {local constant} {play with this value for some interesting FX}
    Var
      sx,sy : integer; {these are variables defined only for THIS procedure}
      tempcolor : integer;
      okshow : boolean;
    Begin
      for a:=1 to numstars do
      begin
        okshow:=true;
        {remember - positive Z is AWAY from you}
        if (stars[a].z<200) then tempcolor:=7;  {light gray}
        if (stars[a].z<100) then tempcolor:=15; {white}
        if (stars[a].z>=200) then tempcolor:=8; {dark gray}
        if (stars[a].z>0) then {have to do this or get div by 0 error}
        begin
          sx:=round((stars[a].x*expf)/stars[a].z);
          sy:=round((stars[a].y*expf)/stars[a].z);
          sx:=sx+160;
          sy:=sy+100; {put the origin at the center, not upper-left}
          if (sx<0) then okshow:=false;
          if (sx>319) then okshow:=false;
          if (sy<0) then okshow:=false;
          if (sy>199) then okshow:=false;
          if (okshow=true) then pp2(sx,sy,tempcolor);
        end;
      end;
    end; {Displays one frame of the starfield, basically}

    Procedure MoveStars;
    Begin
      for a:=1 to numstars do
      begin
        stars[a].z:=(stars[a].z-starspeed);
        if (stars[a].z<=0) then stars[a].z:=400; {can't have 0 or negative value}
      end;
    End; {Updates the position of the stars}

    Begin {main program execution begins here}
      initvga; {first, setup the screen - we have lots of predef procedures now!}
      allocatepages; {get the virtual pages set up}
      clearpage3; {make sure page 3 is blank}
      calculatestars; {setup initial positions}
      repeat
        displaystars; {display one frame}
        swappages; {copy frame to visual page and erase working page}
        movestars; {update star data}
      until keypressed; {repeats the loop until you hit a key}
      restoretext; {put the video card back in 80x25 text mode}
      deallocatepages; {free up the system RAM we used}
    End. {end the program execution}

[Back to EGAVGA SWAG index] [Back to Main SWAG index] [Original]