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

{
Well, here is yet another version of my light vector. This time, I
fully tested it on TP7 (I got the blip thing that everybody was saying).
But it really works this time, and it should for you as well.
In case you were wondering, the problem was in the Intensity function.
There was a Longint overflow.
}
Program Display3D;

Const NumColors : Longint = 63;

Type
  ScreenVertType = Record x, y : Integer; End;
  ScreenList = Array[0..7] of ScreenVertType;
  _3DCT = Record x, y, z : Longint; End;
  Coords = Array[0..7] of _3DCT;
  SinglePoly = Array[0..3] of Byte;
  PLT = Array[0..5] of SinglePoly;
  NormCoord = Array[0..2] of Longint;
  Norms = Array[0..5] of NormCoord;
  VScreen = Array[0..63999] of Byte;
  PVScreen = ^VScreen;

Const
  LocalCds : Coords = ((x:50; y:50;  z:50), (x:50; y:-50; z:50),
   (x:-50; y:-50; z:50),(x:-50; y:50; z:50),(x:50; y:50; z:-50),
   (x:50; y:-50; z:-50),(x:-50; y:-50; z:-50),(x:-50; y:50; z:-50));
  PolyDesc:PLT=((0,3,2,1),(5,6,7,4),(1,2,6,5),(2,3,7,6),(3,0,4,7),(0,1,5,4));
  LNormals:Norms=((0,0,4096),(0,0,-4096),(0,-4096,0),(-4096,0,0),
               (0,4096,0),(4096,0,0));

Var
  Time : Longint ABSOLUTE $0:$046c; STime, ETime, Frame : Longint;
  WNormals : Norms; Sine, CoSine : Array[0..511] of Longint;
  WorldCds : Coords; ScreenCoords : ScreenList; Page0, Page1 : PVScreen;

Procedure InitGraph;
Begin New(Page1);Asm Mov AX,13h;Int 10h;End;Page0:=Ptr($A000,0);End;

Procedure CloseGraph;
Begin Dispose(Page1); Asm Mov ax,3; Int 10h; End;End;

Procedure Cls(Var Screen); Assembler;
Asm Les  di,Screen; Xor  ax,ax; Mov  cx,32000; Rep  Stosw; End;

Procedure CopyWin(Var Source, Dest); Assembler;
Asm Push ds; Les di,Dest; Lds si,Source; Mov cx,32000;Rep Movsw;Pop ds;End;

Procedure InitPal;
Var c : Byte;
Begin For c := 0 to NumColors do Begin Port[$3c8] := c;
Port[$3c9] := Round(63*c/NumColors); Port[$3c9] := 0;
Port[$3c9] := Round(63*c/NumColors);End; End;

Procedure CalcSinus;
Var C : Longint;
Begin For C := 0 to 511 do Begin
Sine[C]:=Round(Sin(C*(2*Pi)/512)*4096);
CoSine[C]:=Round(Cos(C*(2*Pi)/512)*4096); End; End;

Function SAR(S, B : Longint) : Longint;
Begin If S<0 Then SAR:=-((-S) Shr B) Else SAR:=(S Shr B); End;

Procedure Rotate3D(Xa, Ya, Za : Word; Num : Word; Var Loc, Wor);
Var Local : Coords Absolute Loc; World : Coords Absolute Wor;
  x,y,z,Xt,Yt,Zt,C : Longint;
Begin For C := 0 to (Num-1) do Begin
  x:=Local[C].x; y:=Local[C].y; z:=Local[C].z;
  Yt:=Sar(Y*CoSine[Xa]-Z*Sine[Xa],12); Zt:=Sar(Y*Sine[Xa]+Z*CoSine[Xa],12);
  Y:=Yt;Z:=Zt; Xt:=Sar(X*CoSine[Ya]-Z*Sine[Ya],12);
  Zt:=Sar(X*Sine[Ya]+Z*CoSine[Ya],12); X:=Xt;Z:=Zt;
  Xt:=Sar(X*CoSine[Za]-Y*Sine[Za],12);Yt:=Sar(X*Sine[Za]+Y*CoSine[Za],12);
  X:=Xt; Y:=Yt; World[C].x:=X; World[C].y:=Y; World[C].z:=Z; End; End;

Procedure Project(World : Coords; Var Screen : ScreenList);
Var C : Integer;
Begin For C := 0 to 7 do Begin
 Screen[C].x := (World[C].X Shl 9) Div (512-World[C].Z) + 160;
 Screen[C].y := (World[C].Y Shl 9) Div (512-World[C].Z) + 100; End;End;

Function Intensity(World:Coords;Poly:SinglePoly;Normal:NormCoord):Word;
Const Viewer : NormCoord = (0,0,4096);
Var Dot : Longint; Temp : Word;
Begin
  Dot := Viewer[2]*Normal[2]; If Dot < 0 Then Temp := $ff00 Else Temp := 0;
  If Hi(Temp) = 0 Then Temp:=Temp+((Dot Shr 12)*NumColors) Shr 12;
  Intensity := Temp; End;

Procedure HLine(X1, X2, Y : Integer; Color : Byte; P:PVScreen);
Begin
  If Y < 0 Then Exit; If Y > 199 Then Exit;
  If X2 > X1 Then Begin If X1 < 0 Then X1 := 0;
  If X2 > 319 Then X2 := 319;
  FillChar(Mem[Seg(P^):Ofs(P^)+Y*320+X1], X2-X1+1, Color); End;
End;

Procedure DrawPoly(S : ScreenList; P : SinglePoly; Color : Byte; Page:PVScreen);
Var
  x1,y1,x2,y2,x11,y11,x22,y22,StartV1,EndV1,StartV2,EndV2 : Integer;
  Dx1, Dx2,Count1, Count2,XVal1, XVal2,MinY,C, EdgeCount : Integer;
Begin
  EdgeCount := 4; MinY := 22300;
  For C := 0 to (EdgeCount-1) do
   Begin If S[P[c]].Y < MinY Then Begin MinY := S[P[c]].Y; StartV1 := C; End;
    End;
  StartV2:=StartV1; EndV1:=StartV1-1; EndV2:=StartV2+1;
  If EndV1 < 0 Then EndV1 := (4-1); If EndV2 >= 4 Then EndV2 := 0;
  MinY:=S[P[StartV1]].Y; X1:=S[P[StartV1]].X; Y1:=S[P[StartV1]].Y;
  X2:=S[P[EndV1]].X; Y2:=S[P[EndV1]].Y; Dx1:=((X2-X1) Shl 8) Div (Y2-Y1+1);
  Count1:=Y2-Y1; XVal1:=X1 Shl 8; X11:=S[P[StartV2]].X; Y11:=S[P[StartV2]].Y;
  X22:=S[P[EndV2]].X; Y22:=S[P[EndV2]].Y;
  Dx2:=((X22-X11) Shl 8) Div (Y22-Y11+1);
  Count2:=Y22-Y11; XVal2 :=X11 Shl 8;
  While EdgeCount > 1 do
    Begin
      While (Count1 > 0) and (Count2 > 0) do
        Begin HLine(XVal1 Shr 8, XVal2 Shr 8, MinY, Color, Page);
          XVal1 := XVal1 + Dx1; XVal2 := XVal2 + Dx2;
          Count1 := Count1 - 1; Count2 := Count2 - 1; MinY := MinY + 1;
        End;
      If Count1 = 0
        Then Begin
          StartV1:=EndV1;EndV1:=EndV1-1; If EndV1 < 0 Then EndV1:=(4-1);
          EdgeCount := EdgeCount - 1; MinY := S[P[StartV1]].Y;
          If MinY > 319 Then Exit;
          X1 := S[P[StartV1]].X; Y1 := S[P[StartV1]].Y; X2 := S[P[EndV1]].X;
          Y2:=S[P[EndV1]].Y; Dx1:=((X2-X1) Shl 8) Div (Abs(Y2-Y1)+1);
          Count1 := Y2-Y1; XVal1:=X1 Shl 8;
        End;
      If Count2 = 0
        Then Begin
          StartV2:=EndV2;EndV2:=EndV2+1; If EndV2 >= 4 Then EndV2 := 0;
          EdgeCount:=EdgeCount-1; MinY:=S[P[StartV2]].Y;
          If MinY > 319 Then Exit; X11:=S[P[StartV2]].X;Y11:=S[P[StartV2]].Y;
          X22:=S[P[EndV2]].X;Y22:=S[P[EndV2]].Y;
          Dx2:=((X22-X11) Shl 8) Div (Abs(Y22-Y11)+1); Count2 := Y22-Y11;
          XVal2 := X11 Shl 8;
        End;
    End;
End;

Procedure Display(World : Coords; Normals : Norms);
Var x : Integer; Temp : Word;
Begin Project(WorldCds, ScreenCoords);
  For x := 0 to 5 do
    Begin Temp := Intensity(WorldCds, PolyDesc[x], WNormals[x]);
     If Hi(Temp) = 0 Then DrawPoly(ScreenCoords,PolyDesc[x],Lo(Temp),Page1);
    End;
End;
{ ******************** End Display Procedures ******************** }

Var a, b, c : Word;
Begin
  InitGraph; CalcSinus; InitPal; a:=0; b:=0; c:=0; Frame:=0;STime:=Time;
  Repeat Cls(Page1^);
    Rotate3D(a,b,c,8,LocalCds,WorldCds);Rotate3D(a,b,c,6,LNormals,WNormals);
    Display(WorldCds, WNormals); CopyWin(Page1^, Page0^);
    a:=a+1;b:=b+2;c:=c+1;Frame:=Frame+1;
    If a>511 Then a:=0; If b>511 Then b:=0; If c>511 Then c:=0;
  Until Port[$60]=1; ETime := Time;
  CloseGraph; Writeln((Frame*18.2)/(ETime-STime):5:2, ' fps');
End.

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