-
Notifications
You must be signed in to change notification settings - Fork 1
/
Engine3D_Rotate.p
757 lines (631 loc) · 18.8 KB
/
Engine3D_Rotate.p
1
unit Engine3D_Rotate; { Dimensione delle variabili globali: 0 }interfaceuses quickdraw, Dream3Display_Tipi;const Distance = 30; Coefficient1 = 2048; Coefficient140 = 2048 * $40; Coefficient40 = $80; Distance40 = 1920; DistanceN40 = -1440;var MaxVWall : integer; LightPoints : array [1..15] of DoublePoint; NLightPoints : integer; TheTick : longint; procedure RotatePolys;procedure RotatePolysTr;procedure RotateNPC;procedure SortPolys;procedure SortPolysTr;procedure OpenDoor (TheDoor : DoorWallPtr);implementation{$R-} uses fixmath, segload, events, Engine3D_Globals, Engine3D_DrawProc, Engine3D_CIconArray, Dream3Display_Tools;{$S Engine3D_FastRotate}procedure RotatePolys;label 100;const LimiteX = 1000; var I : integer; Index : integer; Help : FixedPoint; Tmp0h, Tmp0v, Tmp1h, Tmp1v : longint; PN_1, Tmp : integer; LocalPolys : PolyArrayPtr; LocalBase : PolyBaseArrayPtr; TheSin, TheCos : integer; LocalPolyN : integer; WallHeight16 : longint; VPointH, VPointV : longint; {$S Engine3D_FastRotate}procedure RotateFrontal ( Index : integer);var TheDist : integer; TheObj : DisplayObjectPtr; begin with Environment do with LocalBase^ [Index] do with LocalPolys^ [LocalPolyN] do begin ProjCorner0.Z := - Tmp0h * TheSin + Tmp0v * TheCos; if (ProjCorner0.Z < DistanceN40) or (ProjCorner0.Z > Environment.RayCastingDepth) then exit (RotateFrontal); ProjCorner0.X := Tmp0h * TheCos + Tmp0v * TheSin; ProjCorner0.X := (bsl (ProjCorner0.X, 9)) div (ProjCorner0.Z + Distance40); if LocalBase^ [Index].PoType = BaseSqFrontal then TheDist := PlaceDim else case LocalBase^ [Index].RealCorner [1].h of 1 : TheDist := PlaceDim; 2 : TheDist := (3 * PlaceDim) div 5; 3 : TheDist := (2 * PlaceDim) div 5; otherwise; end; ProjCorner0.X := ProjCorner0.X - bsl (TheDist, 16) div (ProjCorner0.Z + Distance40); if ProjCorner0.X > WindowXCenter then exit (RotateFrontal); ProjCorner1.X := ProjCorner0.X + bsl (TheDist, 17) div (ProjCorner0.Z + Distance40); if ProjCorner1.X < -WindowXCenter then exit (RotateFrontal); MiddleZ := bsl (ProjCorner0.Z, 1); Dir := 0; XDist := ProjCorner1.X - ProjCorner0.X; PN_1 := LocalPolyN; LocalPolyN := LocalPolyN + 1; if LocalBase^ [Index].PoType = BaseSqFrontal then begin LocalPolys^ [PN_1].CIcon := LocalBase^ [Index].CIcon; LocalPolys^ [PN_1].LightSource := false; end else begin TheObj := GetObjectInListPtr (LocalBase^ [Index].CIcon); if TheObj = nil then begin LocalPolyN := LocalPolyN - 1; exit (RotateFrontal); end; case ViewAngle of 0..15 : LocalPolys^ [PN_1].CIcon := longint (TheObj^.FramePtrs [1, TheObj^.CurrentFrame]); 16..45 : LocalPolys^ [PN_1].CIcon := longint (TheObj^.FramePtrs [6, TheObj^.CurrentFrame]); 46..75 : LocalPolys^ [PN_1].CIcon := longint (TheObj^.FramePtrs [5, TheObj^.CurrentFrame]); 76..105 : LocalPolys^ [PN_1].CIcon := longint (TheObj^.FramePtrs [4, TheObj^.CurrentFrame]); 106..135 : LocalPolys^ [PN_1].CIcon := longint (TheObj^.FramePtrs [3, TheObj^.CurrentFrame]); 136..165 : LocalPolys^ [PN_1].CIcon := longint (TheObj^.FramePtrs [2, TheObj^.CurrentFrame]); 166..179 : LocalPolys^ [PN_1].CIcon := longint (TheObj^.FramePtrs [1, TheObj^.CurrentFrame]); end; TheObj^.CurrentFrame := TheObj^.CurrentFrame + 1; if TheObj^.CurrentFrame = TheObj^.AnimFrames + 1 then TheObj^.CurrentFrame := 1; LocalPolys^ [PN_1].LightSource := TheObj^.LightSource; LocalPolys^ [PN_1].parameter := (WallHeight16 - bsl (theObj^.lightH, 16)) div (ProjCorner0.Z + Distance40); end; LocalPolys^ [PN_1].FullMask := LocalBase^ [Index].FullMask; LocalPolys^ [PN_1].Animated := false; YEnd0 := (WallHeight16) div (ProjCorner0.Z + Distance40); YEnd1 := YEnd0; YStart0 := - YEnd0; YStart1 := - YEnd1; DYStart := 0; DYEnd := 0; LocalPolys^ [PN_1].PoType := LocalBase^ [Index].PoType; LocalPolys^ [PN_1].BaseRef := Index; PolysTr^ [PolyNTr] := LocalPolys^ [PN_1]; LocalPolyN := PN_1; PolyNTr := PolyNTr + 1 end;end;begin MaxVWall := 1; WallHeight16 := bsl (Environment.StdWallHeight, 16); VPointH := Environment.ViewPoint.h; VPointV := Environment.ViewPoint.v; LocalPolys := Polys; LocalBase := Base; LocalPolyN := 1; PolyNTr := 1; TheSin := DiscreteSin [Environment.ViewAngle]; TheCos := DiscreteCos [Environment.ViewAngle]; for I := BaseN downto 1 do begin with LocalBase^ [I] do if MustIBeShown then with LocalPolys^ [LocalPolyN] do begin Tmp0h := RealCorner [0].h - VPointH; Tmp0v := RealCorner [0].v - VPointV; if LocalBase^ [I].PoType in [BaseSqFrontal, BaseObject] then RotateFrontal (I) else begin Tmp1h := RealCorner [1].h - VPointH; Tmp1v := RealCorner [1].v - VPointV; ProjCorner0.Z := - Tmp0h * TheSin + Tmp0v * TheCos; if (ProjCorner0.Z < DistanceN40) or (ProjCorner0.Z > Environment.RayCastingDepth) then goto 100; ProjCorner1.Z := - Tmp1h * TheSin + Tmp1v * TheCos; if (ProjCorner1.Z < DistanceN40) or (ProjCorner1.Z > Environment.RayCastingDepth) then goto 100; ProjCorner0.X := Tmp0h * TheCos + Tmp0v * TheSin; ProjCorner1.X := Tmp1h * TheCos + Tmp1v * TheSin; ProjCorner0.X := (bsl (ProjCorner0.X, 9)) div (ProjCorner0.Z + Distance40); if (abs (ProjCorner0.X) > LimiteX) then goto 100; ProjCorner1.X := (bsl (ProjCorner1.X, 9)) div (ProjCorner1.Z + Distance40); if (abs (ProjCorner1.X) > LimiteX) then goto 100; MiddleZ := ProjCorner0.Z + ProjCorner1.Z; PN_1 := LocalPolyN; LocalPolyN := LocalPolyN + 1; if ProjCorner1.X < ProjCorner0.X then begin if (ProjCorner0.X < - WindowXCenter) or (ProjCorner1.X > WindowXCenter) then begin LocalPolyN := LocalPolyN - 1; goto 100; end; Help := ProjCorner1; ProjCorner1 := ProjCorner0; ProjCorner0 := Help; Dir := -1; end else begin if (ProjCorner0.X = ProjCorner1.X) or (ProjCorner1.X < - WindowXCenter) or (ProjCorner0.X > WindowXCenter) then begin LocalPolyN := LocalPolyN - 1; goto 100; end; Dir := 0; end; XDist := ProjCorner1.X - ProjCorner0.X; Tmp := LocalBase^ [I].CIcon; if Tmp > 0 then begin LocalPolys^ [PN_1].CIcon := Tmp; Animated := false; end else begin with ATextureList [-Tmp]^ do begin if TheTick > LastTick + IntervalTicks then begin LastTick := TheTick; Frame := Frame + 1; if Frame > NFrames then Frame := 0; end; LocalPolys^ [PN_1].CIcon := CIconId [Frame]; end; Animated := true; end; LocalPolys^ [PN_1].FullMask := LocalBase^ [I].FullMask; YEnd0 := (WallHeight16) div (ProjCorner0.Z + Distance40); YEnd1 := (WallHeight16) div (ProjCorner1.Z + Distance40); YStart0 := - YEnd0; YStart1 := - YEnd1; DYStart := fixdiv ((YStart1 - YStart0), XDist);{ DYEnd := fixdiv ((YEnd1 - YEnd0), XDist);} DYEnd := - DYStart; LocalPolys^ [PN_1].PoType := LocalBase^ [I].PoType; LocalPolys^ [PN_1].Next := LocalBase^ [I].Next; LocalPolys^ [PN_1].Levels := 1; LocalPolys^ [PN_1].BaseRef := I; if LocalBase^ [I].Next <> 0 then begin LocalPolys^ [PN_1].Levels := 2; Index := BaseLevels^ [LocalBase^ [I].Next].Next; while Index <> 0 do begin LocalPolys^ [PN_1].Levels := LocalPolys^ [PN_1].Levels + 1; Index := BaseLevels^ [Index].Next end; if LocalPolys^ [PN_1].Levels > MaxVWall then MaxVWall := LocalPolys^ [PN_1].Levels; end; if not FullMask then begin PolysTr^ [PolyNTr] := LocalPolys^ [PN_1]; PolysTr^ [PolyNTr].PoType := -1; PolyNTr := PolyNTr + 1; PolyN := PolyN - 1; end; end; end;100 : end; PolyN := LocalPolyN - 1; PolyNTr := PolyNTr - 1;end;{$S Engine3D_FastRotate}procedure RotatePolysTr;const LimiteX = 1000; var I : integer; Tmp0h, Tmp0v : longint; PN_1 : integer; LocalBase : PolyBaseArrayPtr; LocalPolys : PolyArrayPtr; TheSin, TheCos : integer; WallHeight16 : longint; {$S Engine3D_FastRotate}procedure RotateFrontal ( Index : integer);var TheDist : integer; TheObj : DisplayObjectPtr; begin with Environment do with LocalBase^ [Index] do with PolysTr^ [PolyNTr] do begin ProjCorner0.Z := - Tmp0h * TheSin + Tmp0v * TheCos; if (ProjCorner0.Z < DistanceN40) or (ProjCorner0.Z > Environment.RayCastingDepth) then exit (RotateFrontal); ProjCorner0.X := Tmp0h * TheCos + Tmp0v * TheSin; ProjCorner0.X := (bsl (ProjCorner0.X, 9)) div (ProjCorner0.Z + Distance40); if LocalBase^ [Index].PoType = BaseSqFrontal then TheDist := PlaceDim else case LocalBase^ [Index].RealCorner [1].h of 1 : TheDist := PlaceDim; 2 : TheDist := (3 * PlaceDim) div 5; 3 : TheDist := (2 * PlaceDim) div 5; otherwise; end; ProjCorner0.X := ProjCorner0.X - bsl (TheDist, 16) div (ProjCorner0.Z + Distance40); if ProjCorner0.X > WindowXCenter then exit (RotateFrontal); ProjCorner1.X := ProjCorner0.X + bsl (TheDist, 17) div (ProjCorner0.Z + Distance40); if ProjCorner1.X < -WindowXCenter then exit (RotateFrontal); MiddleZ := bsl (ProjCorner0.Z, 1); Dir := 0; XDist := ProjCorner1.X - ProjCorner0.X; PN_1 := PolyNTr; PolyNTr := PolyNTr + 1; if LocalBase^ [Index].PoType = BaseSqFrontal then begin PolysTr^ [PN_1].CIcon := LocalBase^ [Index].CIcon; PolysTr^ [PN_1].LightSource := false; end else begin TheObj := GetObjectInListPtr (LocalBase^ [Index].CIcon); if TheObj = nil then begin PolyNTr := PolyNTr - 1; exit (RotateFrontal); end; case ViewAngle of 0..15 : PolysTr^ [PN_1].CIcon := longint (TheObj^.FramePtrs [1, TheObj^.CurrentFrame]); 16..45 : PolysTr^ [PN_1].CIcon := longint (TheObj^.FramePtrs [6, TheObj^.CurrentFrame]); 46..75 : PolysTr^ [PN_1].CIcon := longint (TheObj^.FramePtrs [5, TheObj^.CurrentFrame]); 76..105 : PolysTr^ [PN_1].CIcon := longint (TheObj^.FramePtrs [4, TheObj^.CurrentFrame]); 106..135 : PolysTr^ [PN_1].CIcon := longint (TheObj^.FramePtrs [3, TheObj^.CurrentFrame]); 136..165 : PolysTr^ [PN_1].CIcon := longint (TheObj^.FramePtrs [2, TheObj^.CurrentFrame]); 166..179 : PolysTr^ [PN_1].CIcon := longint (TheObj^.FramePtrs [1, TheObj^.CurrentFrame]); end; TheObj^.CurrentFrame := TheObj^.CurrentFrame + 1; if TheObj^.CurrentFrame = TheObj^.AnimFrames + 1 then TheObj^.CurrentFrame := 1; PolysTr^ [PN_1].LightSource := TheObj^.LightSource; PolysTr^ [PN_1].parameter := (WallHeight16 - bsl (theObj^.lightH, 16)) div (ProjCorner0.Z + Distance40); end; PolysTr^ [PN_1].FullMask := LocalBase^ [Index].FullMask; PolysTr^ [PN_1].Animated := false; YEnd0 := (WallHeight16) div (ProjCorner0.Z + Distance40); YEnd1 := YEnd0; YStart0 := - YEnd0; YStart1 := - YEnd1; DYStart := 0; DYEnd := 0; PolysTr^ [PN_1].PoType := LocalBase^ [Index].PoType; PolysTr^ [PN_1].BaseRef := Index; end;end;begin WallHeight16 := bsl (Environment.StdWallHeight, 16); LocalBase := Base; PolyNTr := 1; TheSin := DiscreteSin [Environment.ViewAngle]; TheCos := DiscreteCos [Environment.ViewAngle]; for I := BaseN downto 1 do begin with LocalBase^ [I] do if MustIBeShown then if (LocalBase^ [I].PoType = BaseSqFrontal) or (LocalBase^ [I].PoType = BaseObject) then begin Tmp0h := RealCorner [0].h - Environment.ViewPoint.h; Tmp0v := RealCorner [0].v - Environment.ViewPoint.v; RotateFrontal (I); end; end; PolyNTr := PolyNTr - 1; LocalPolys := Polys; for I := PolyN downto 1 do with LocalPolys^ [I] do if Animated then with ATextureList [-Base^ [BaseRef].Cicon]^ do begin if TheTick > LastTick + IntervalTicks then begin LastTick := TheTick; Frame := Frame + 1; if Frame > NFrames then Frame := 0; end; CIcon := CIconId [Frame]; end else if not FullMask then begin PolyNTr := PolyNTr + 1; PolysTr^ [PolyNTr] := LocalPolys^ [I]; PolysTr^ [PolyNTr].PoType := -1; end;end;{$S Engine3D}procedure RotateNPC;label 100;const LimiteX = 1000; var I : integer; Tmp0h, Tmp0v : longint; LocalPolys : PolyArrayPtr; TheSin, TheCos : integer; WallHeight16 : longint; TheDist : integer; TheNPC : NPCPtr; begin WallHeight16 := bsl (Environment.StdWallHeight, 16); TheSin := DiscreteSin [Environment.ViewAngle]; TheCos := DiscreteCos [Environment.ViewAngle]; LocalPolys := PolysTr; for I := 1 to NPCN do begin TheNPC := NPCList^ [I]; with TheNPC^ do with LocalPolys^ [PolyNTr + 1] do begin Tmp0h := Position.h - Environment.ViewPoint.h; Tmp0v := Position.v - Environment.ViewPoint.v; ProjCorner0.Z := - Tmp0h * TheSin + Tmp0v * TheCos; if (ProjCorner0.Z < DistanceN40) or (ProjCorner0.Z > Environment.RayCastingDepth) then goto 100; ProjCorner0.X := Tmp0h * TheCos + Tmp0v * TheSin; ProjCorner0.X := (bsl (ProjCorner0.X, 9)) div (ProjCorner0.Z + Distance40); TheDist := bsl (Dimensions.right + 1, 6) div (Dimensions.bottom + 1); ProjCorner0.X := ProjCorner0.X - bsl (TheDist, 14) div (ProjCorner0.Z + Distance40); if (ProjCorner0.X < -LimiteX) or (ProjCorner0.X > LimiteX) then goto 100; ProjCorner1.X := ProjCorner0.X + bsl (TheDist, 14) div (ProjCorner0.Z + Distance40); if (ProjCorner1.X < -LimiteX) or (ProjCorner1.X > LimiteX) then goto 100; MiddleZ := bsl (ProjCorner0.Z, 1); if (ProjCorner1.X < - WindowXCenter) or (ProjCorner0.X > WindowXCenter) then begin goto 100; end; Dir := 0; XDist := ProjCorner1.X - ProjCorner0.X; YEnd0 := bsl (10 - hisBase, 16) div (ProjCorner0.Z + Distance40); YEnd1 := YEnd0; YStart0 := - bsl (hisHeight, 16) div (ProjCorner0.Z + Distance40); YStart1 := - YStart0; DYStart := 0; DYEnd := 0; PolyNTr := PolyNTr + 1; BaseRef := I; LocalPolys^ [PolyNTr].PoType := NPCType; LocalPolys^ [PolyNTr].Animated := false; end;100 : end;end;{$S Engine3D_FastRotate}procedure SortPolys;{$S Engine3D_FastRotate}procedure QuickSortPolys ( S, D : integer);var I, J : integer; X, Z, W : Poly3D; LocalPolys : PolyArrayPtr; ThaZ1 : longint; begin LocalPolys := Polys; if S + 1 = D then begin if LocalPolys^ [S].MiddleZ > LocalPolys^ [D].MiddleZ then begin W := LocalPolys^ [S]; LocalPolys^ [S] := LocalPolys^ [D]; LocalPolys^ [D] := W; end; exit (QuickSortPolys); end else if S + 1 = D - 1 then begin X := LocalPolys^ [S]; W := LocalPolys^ [S + 1]; Z := LocalPolys^ [D]; if X.MiddleZ < W.MiddleZ then if X.MiddleZ < Z.MiddleZ then if W.MiddleZ < Z.MiddleZ then exit (QuickSortPolys) else begin LocalPolys^ [S + 1] := Z; LocalPolys^ [D] := W; exit (QuickSortPolys) end else begin LocalPolys^ [S] := Z; LocalPolys^ [S + 1] := X; LocalPolys^ [D] := W; exit (QuickSortPolys) end else if X.MiddleZ < Z.MiddleZ then begin LocalPolys^ [S] := W; LocalPolys^ [S + 1] := X; exit (QuickSortPolys) end else if W.MiddleZ < Z.MiddleZ then begin LocalPolys^ [S] := W; LocalPolys^ [S + 1] := Z; LocalPolys^ [D] := X; exit (QuickSortPolys) end else begin LocalPolys^ [S] := Z; LocalPolys^ [D] := X; exit (QuickSortPolys) end; end; I := S; J := D; ThaZ1 := LocalPolys^ [bsr (S + D, 1)].MiddleZ; repeat while LocalPolys^ [I].MiddleZ < ThaZ1 do I := I + 1; while ThaZ1 < LocalPolys^ [J].MiddleZ do J := J - 1; if I <= J then begin if I < J then begin W := LocalPolys^ [I]; LocalPolys^ [I] := LocalPolys^ [J]; LocalPolys^ [J] := W; end; I := I + 1; J := J - 1; end; until I > J; if S < J then QuickSortPolys (S, J); if I < D then QuickSortPolys (I, D);end;begin if PolyN > 0 then QuickSortPolys (1, PolyN);end;{$S Engine3D_FastRotate}procedure SortPolysTr; {$S Engine3D_FastRotate}procedure QuickSortPolysTr (S, D : integer);var I, J : integer; X, W : Poly3D; LocalPolys : PolyArrayPtr;begin LocalPolys := PolysTr; if S = D - 1 then begin if LocalPolys^ [S].MiddleZ > LocalPolys^ [D].MiddleZ then begin W := LocalPolys^ [S]; LocalPolys^ [S] := LocalPolys^ [D]; LocalPolys^ [D] := W; end; exit (QuickSortPolysTr); end; I := S; J := D; X := LocalPolys^ [bsr (S + D, 1)]; repeat while LocalPolys^ [I].MiddleZ < X.MiddleZ do I := I + 1; while X.MiddleZ < LocalPolys^ [J].MiddleZ do J := J - 1; if I <= J then begin if I < J then begin W := LocalPolys^ [I]; LocalPolys^ [I] := LocalPolys^ [J]; LocalPolys^ [J] := W; end; I := I + 1; J := J - 1; end; until I > J; if S < J then QuickSortPolysTr (S, J); if I < D then QuickSortPolysTr (I, D);end;begin if PolyNTr > 0 then QuickSortPolysTr (1, PolyNTr);{ NLightPoints := 0; for I := 1 to PolyNTr do with PolysTr^ [I] do if LightSource then begin NLightPoints := NLightPoints + 1; with LightPoints [I] do begin H := ProjCorner0.X; V := YEnd0; end; end;}end;{$S Engine3D}procedure OpenDoor (TheDoor : DoorWallPtr);const Pi = 3.1415926;var TheStart, TheEnd : DoublePoint; TheLength : integer; TheAngle : real; TheRef, TheRef2 : integer; TStart, TEnd : integer; begin with TheDoor^ do begin TheAngle := Angle * CurrentFrame * Pi / NFrames / 180; TheRef := DoorTexture; TheRef2 := CloseTexture; TStart := StartBy; TEnd := EndBy; end; if TheDoor^.WallKind = 2 then begin TheStart := Base^ [TheRef2].RealCorner [0]; TheStart.V := TheStart.V - round (TStart * 2 * Environment.PlaceDim / 64); TheLength := round ((TEnd - TStart) * 2 * Environment.PlaceDim / 64); TheEnd.H := TheStart.H - round (TheLength * sin (TheAngle)); TheEnd.V := TheStart.V - round (TheLength * cos (TheAngle)); end else begin TheStart := Base^ [TheRef2].RealCorner [0]; TheStart.H := TheStart.H + round (TStart * 2 * Environment.PlaceDim / 64); TheLength := round ((TEnd - TStart) * 2 * Environment.PlaceDim / 64); TheEnd.H := TheStart.H + round (TheLength * cos (TheAngle)); TheEnd.V := TheStart.V - round (TheLength * sin (TheAngle)); end; Base^ [TheRef].RealCorner [0] := TheStart; Base^ [TheRef].RealCorner [1] := TheEnd;end;end.