LandMain.pas
上传用户:yj_qiu
上传日期:2022-08-08
资源大小:23636k
文件大小:25k
源码类别:

游戏引擎

开发平台:

Delphi

  1. (*
  2.  CAST II Engine landscape demo main unit
  3.  The source code may be used under either MPL 1.1 or LGPL 2.1 license. See included license.txt file <br>
  4.  (C) 2007 George "Mirage" Bakhtadze
  5. *)
  6. {$I GDefines.inc}
  7. {$I C2Defines.inc}
  8. unit LandMain;
  9. interface
  10. uses
  11.   SysUtils,
  12.   TextFile, Basics, AppsInit, Props, OSUtils, Base2D,
  13.   Resources, BaseGraph, BaseTypes, BaseMsg, Base3D, BaseClasses,
  14.   CAST2, C2Visual, C2Res, C2VisItems, C2Anim, C22D, C2FX, C2Land, C2TileMaps, C2Flora,
  15.   ACS, ACSAdv, C2GUI,
  16.   C2Affectors, C2ParticleAdv,
  17.   C2Grass,
  18.   C2Render, {$IFDEF DIRECT3D8} C2DX8Render, {$ENDIF}
  19.   Input, WInput,
  20.   C2Core,
  21.   Timer;
  22. const
  23.   // These constants can be adjusted
  24.   RunFullScreen = False;                      // Fullscreen mode
  25.   SceneFileName = 'Land.cbf';                 // Scene to load
  26.   CameraRotateSpeed = 0.003;                  // Camera rotation sensitivity
  27.   CameraMoveAccel   = 0.0315;                 // Camera movement sensitivity
  28.   MinCameraAlt      = 7.0;                    // Min camera altitude
  29.   BreakFactor       = 0.95;                   // How far camera can move
  30.   CameraMoveRadius  = 2000;
  31.   TimerDelay        = 1/60;                   // Delay between timer events
  32.   DetailLowXStr        = '100';                  // Landscape grid X resolution for low detail
  33.   DetailLowYZStr       = '120';                  // Landscape grid YZ resolution for low detail
  34.   DetailLowClipMapStr  = '256';                  // Landscape megatexture clipmap size for low detail
  35.   DetailLowSMRes       = 512;                    // Shadow map resolution for low detail
  36.   DetailMedXStr        = '180';                  // Landscape grid X resolution for medium detail
  37.   DetailMedYZStr       = '350';                  // Landscape grid YZ resolution for medium detail
  38.   DetailMedClipMapStr  = '512';                  // Landscape megatexture clipmap size for medium detail
  39.   DetailMedSMRes       = 1024;                   // Shadow map resolution for medium detail
  40.   DetailHighXStr       = '300';                  // Landscape grid X resolution for high detail
  41.   DetailHighYZStr      = '600';                  // Landscape grid YZ resolution for high detail
  42.   DetailHighClipMapStr = '1024';                 // Landscape megatexture clipmap size for high detail
  43.   DetailHighSMRes      = 2048;                   // Shadow map resolution for high detail
  44.   BaseDetail = 500.0;
  45.   KeyLeftBind    = 'A';                       // Key binding to move camera left
  46.   KeyRightBind   = 'D';                       // Key binding to move camera right
  47.   KeyUpBind      = 'Q';                       // Key binding to move camera up
  48.   KeyDownBind    = 'E';                       // Key binding to move camera down
  49.   KeyBackBind    = 'W';                       // Key binding to move camera back
  50.   KeyForwardBind = 'S';                       // Key binding to move camera forward
  51.   // Do not change
  52.   keyLeft    = 0;                             // Left key
  53.   keyRight   = 1;                             // Right key
  54.   keyUp      = 2;                             // Up key
  55.   keyDown    = 3;                             // Down key
  56.   keyBack    = 4;                             // Back key
  57.   keyForward = 5;                             // Forward key
  58.   keyMax     = 5;                             // Max key index
  59. type
  60.   // Message class for detail switching
  61.   TDetailLowMsg = class(TMessage)
  62.   end;
  63.   // Message class for detail switching
  64.   TDetailMedMsg = class(TMessage)
  65.   end;
  66.   // Message class for detail switching
  67.   TDetailHighMsg = class(TMessage)
  68.   end;
  69.   TLandDemo = class
  70.   private
  71.     OldFramesRendered: Integer;
  72.     VideoMode: Integer;
  73.     KeyPressed: array[0..keyMax] of Boolean;  // Bound keys current state
  74.     Velocity: TVector3s;                      // Current movement speed
  75.     Core: TCore;
  76.     Landscape: TMappedItem;
  77.     FPSLabel: TLabel;
  78.     MainCamera, PostProcessCamera, BloomCamera, ShadowCamera: TCamera;
  79.     Light: TLight;
  80.     LightOrigOrient: TQuaternion;
  81.     function LoadScene(const FileName: string): Boolean;
  82.   public
  83.     constructor Create;
  84.     destructor Destroy; override;
  85.     procedure Process;
  86.     procedure ToggleBloom(EventData: Integer; CustomData: SmallInt);
  87.     procedure HandleMouse(EventData: Integer; CustomData: SmallInt);
  88.     procedure HandleTimer(EventID: Integer; const ErrorDelta: TTimeUnit);     // Timer event
  89.     procedure HandleMessage(const Msg: TMessage);                             // Message handler
  90.     procedure HandleKeys(EventData: Integer; CustomData: Smallint);           // Keys handle delegate
  91.   end;
  92. var
  93.   Starter: TAppStarter;                                        // Application starter
  94. implementation
  95. function TLandDemo.LoadScene(const FileName: string): Boolean;
  96.   function FindItem(const ItemName: string; ItemClass: CItem; Mandatory: Boolean): TItem;
  97.   const LogFlag: array[Boolean] of TLogLevel = (lkWarning, lkFatalError);
  98.   begin
  99.     Result := Core.Root.GetChildByName(ItemName, True);
  100.     if not (Result is ItemClass) then begin
  101.       Starter.PrintError('Item "' + ItemName + '" not found in scene', LogFlag[Mandatory]);
  102.       Exit;
  103.     end;
  104.   end;
  105.   function PrepareMegatexture: Boolean;
  106.   const RandomCount = 5;     // number of random pictures placed on megatexture
  107.   var
  108.     i, x, y: Integer;
  109.     MT: TMegaImageResource;
  110.     Stream: TFileStream;
  111.     Header: TImageHeader;
  112.     CData: Pointer;
  113.   begin
  114.     Result := False;
  115.     // Retrieve and setup items related to megatexturing
  116.     MT := FindItem('MegaTexture', TMegaImageResource, True) as TMegaImageResource;
  117.     if not Assigned(MT) then Exit;
  118.     if FileExists('mega.bmp') then begin
  119.       Stream := TFileStream.Create('mega.bmp');
  120.       if LoadBitmapHeader(Stream, Header) then
  121.         MT.SetDimensions(Header.Width, Header.Height);
  122.       Stream.Free;
  123.     end;
  124.     if not FileExists('mega.dat') then begin
  125.       Log.Log('No megatexture data stream found. Creating...');
  126.       MT.SetProperty('ReinitSource file', 'mega.bmp');
  127.       MT.SetProperty('Store file', 'mega.dat');
  128.       MT.SetProperty('Reinit', OnOffStr[True]);
  129.     end;
  130.     MT.SetProperty('Store file', 'mega.dat');
  131.     Landscape.SetProperty('TextureDiffuse scale', FloatToStr(MT.Width/(Landscape.Map.Width * Landscape.Map.CellWidthScale)));
  132.     // Place a random picture on megatexture several times
  133.     if FileExists('random.bmp') then begin
  134.       Stream := TFileStream.Create('random.bmp');
  135.       Base2D.LoadBitmap(Stream, Header);
  136.       Stream.Free;
  137.       GetMem(CData, Header.Width * Header.Height * GetBytesPerPixel(MT.Format));
  138.       ConvertImage(Header.Format, MT.Format, Header.Width * Header.Height, Header.Data, Header.PaletteSize, Header.Palette, CData);
  139.       if Assigned(Header.Data) then FreeMem(Header.Data);
  140.       if Assigned(Header.Palette) then FreeMem(Header.Palette);
  141.       for i := 0 to RandomCount-1 do begin
  142.         x := Random(MT.Width  - Header.Width);
  143.         y := Random(MT.Height - Header.Height);
  144.         MT.SaveRect(GetRectWH(x, y, Header.Width, Header.Height), 0, CData, Header.Width, True);
  145.       end;
  146.       if Assigned(CData) then FreeMem(CData);
  147.     end;
  148.     
  149.     Result := True;
  150.   end;
  151. var Stream: TFileStream;
  152. begin
  153.   Stream := TFileStream.Create(Filename);
  154.   Result := Core.LoadScene(Stream);
  155.   Stream.Free;
  156.   if Result then begin
  157.     MainCamera := Core.Renderer.MainCamera;
  158.     if Assigned(MainCamera) then begin
  159.       // Retrieve some needed items
  160.       Landscape   := FindItem('Landscape',   TMappedItem, True)  as TMappedItem;
  161.       FPSLabel    := FindItem('FPSCounter',  TLabel,      False) as TLabel;
  162.       Light       := FindItem('Light',       TLight,      False) as TLight;
  163.       // Camera of light source for shadow mapping
  164.       ShadowCamera := FindItem('ShadowCamera', TCamera,     False) as TCamera;
  165.       // Camera through which a quad with bloom effect is rendered
  166.       BloomCamera := FindItem('BloomCamera', TCamera,     False) as TCamera;
  167.       // Camera which used to render scene for post processing in case of main camera can not be used for this
  168.       PostProcessCamera := FindItem('PostProcessCamera', TCamera, False) as TCamera;
  169.       if Assigned(PostProcessCamera) then begin
  170.         PostProcessCamera.Position    := MainCamera.Position;
  171.         PostProcessCamera.Orientation := MainCamera.Orientation;
  172.       end;  
  173.       if Assigned(Light) then LightOrigOrient := Light.Orientation;
  174.       PrepareMegatexture;
  175.     end else begin
  176.       Starter.PrintError('Camera not found', lkError);
  177.       Result := False;
  178.     end;
  179.   end;
  180. end;
  181. constructor TLandDemo.Create;
  182. var HandleKeysProc: TInputDelegate; 
  183. begin
  184.   Starter.Terminated := True;                                      // Terminate the application if an error occurs
  185.   VideoMode := StrToIntDef(ParamStr(1), -1);
  186.   // Create engine core
  187.   Core := TCore.Create;
  188.   Core.RegisterItemClass(TGrass);
  189.   Core.MessageHandler    := {$IFDEF OBJFPCEnable}@{$ENDIF}HandleMessage;      // Set message handler
  190.   Starter.MessageHandler := {$IFDEF OBJFPCEnable}@{$ENDIF}Core.HandleMessage; // Redirect window messages to engine
  191.   // Create renderer
  192.   {$IFDEF DIRECT3D8}
  193.   Core.Renderer := TDX8Renderer.Create(Core);
  194.   Core.Renderer.AppRequirements.HWAccelerationLevel := haPureDevice; 
  195.   {$ENDIF}
  196.   if not Assigned(Core.Renderer) or (Core.Renderer.State = rsNotInitialized) then begin             // Error
  197.     Starter.PrintError('Can''t start renderer', lkFatalError);
  198.     Exit;
  199.   end;
  200.   ActivateWindow(Starter.WindowHandle);                            // Bring the application to foreground
  201.   // Initialize render device
  202.   if not Core.Renderer.CreateDevice(Starter.WindowHandle, MaxI(0, VideoMode), VideoMode <> -1) then begin
  203.     Starter.PrintError('Failed to initiaize render device', lkFatalError);
  204.     Exit;
  205.   end;
  206.   // Initialize input subsystem
  207.   Core.Input := TOSController.Create(Starter.WindowHandle, {$IFDEF OBJFPCEnable}@{$ENDIF}Core.HandleMessage);
  208.   Core.Input.BindCommand('ESC',   TForceQuitMsg);                  // Bind exit to ESC key
  209.   Core.Input.BindCommand('ALT+Q', TForceQuitMsg);                  // Bind exit to ALT+Q key combination
  210.   Core.Input.BindCommand('RMB+MouseStrokeDown^MouseStrokeRight^RMB-', TForceQuitMsg);      // Bind exit to mouse gesture like in Opera browser
  211.   Core.Input.BindCommand('1', TDetailLowMsg);                      // Bind "1" key to switch to low detail
  212.   Core.Input.BindCommand('2', TDetailMedMsg);                      // Bind "1" key to switch to medium detail
  213.   Core.Input.BindCommand('3', TDetailHighMsg);                     // Bind "1" key to switch to high detail
  214.   Core.Input.BindDelegate('B', ToggleBloom, 0);
  215.   Core.Input.BindPointer('F1', atBooleanToggle, @Core.Renderer.DisableTesselation);
  216.   // Bind movements keys to delegate supplying in custom data key index with set 8-th bit if key was pressed down.
  217.   HandleKeysProc := {$IFDEF OBJFPCEnable}@{$ENDIF}HandleKeys;
  218.   Core.Input.BindDelegate(KeyLeftBind  + '+', HandleKeysProc, keyLeft  or $100);
  219.   Core.Input.BindDelegate(KeyLeftBind  + '-', HandleKeysProc, keyLeft);
  220.   Core.Input.BindDelegate(KeyRightBind + '+', HandleKeysProc, keyRight or $100);
  221.   Core.Input.BindDelegate(KeyRightBind + '-', HandleKeysProc, keyRight);
  222.   Core.Input.BindDelegate(KeyUpBind   + '+', HandleKeysProc, keyUp   or $100);
  223.   Core.Input.BindDelegate(KeyUpBind   + '-', HandleKeysProc, keyUp);
  224.   Core.Input.BindDelegate(KeyDownBind + '+', HandleKeysProc, keyDown or $100);
  225.   Core.Input.BindDelegate(KeyDownBind + '-', HandleKeysProc, keyDown);
  226.   Core.Input.BindDelegate(KeyBackBind    + '+', HandleKeysProc, keyBack    or $100);
  227.   Core.Input.BindDelegate(KeyBackBind    + '-', HandleKeysProc, keyBack);
  228.   Core.Input.BindDelegate(KeyForwardBind + '+', HandleKeysProc, keyForward or $100);
  229.   Core.Input.BindDelegate(KeyForwardBind + '-', HandleKeysProc, keyForward);
  230.   Core.Input.MouseCapture := True;
  231. //  Core.CatchAllInput := True;
  232.   Core.Input.BindDelegate('MouseMove^', {$IFDEF OBJFPCEnable}@{$ENDIF}HandleMouse, 0);
  233.   Log.Log('******Loading scene');
  234.   // Load scene
  235.   if not LoadScene(Starter.ProgramExeDir + SceneFileName) then begin
  236.     Starter.PrintError('Error loading scene from file "' + SceneFileName + '"', lkFatalError);
  237.     Exit;
  238.   end;
  239.   Log.Log('******Loaded scene');
  240.   Starter.Terminated := False;                                     // No errors
  241.   Core.Timer.SetEvent(TimerDelay, {$IFDEF OBJFPCEnable}@{$ENDIF}HandleTimer, 0);                 // Launch timer events chain
  242.   Log.Log('******Init OK');
  243. end;
  244. destructor TLandDemo.Destroy;
  245. var SubSystem: TSubSystem;
  246. begin
  247.   SubSystem := Core.Input;
  248.   Core.Input := nil;
  249.   FreeAndNil(SubSystem);
  250.   SubSystem := Core.Renderer;
  251.   Core.Renderer := nil;
  252.   FreeAndNil(SubSystem);
  253.   FreeAndNil(Core);
  254.   inherited;
  255. end;
  256. // PerfHUD
  257. const
  258.   Stride = 4;
  259.   Width = 100 * Stride; Height = 100;
  260.   X = -Width; Y = -Height;
  261.   viFrame = 0; viRender = 1;
  262. var
  263.   Ofs: Integer = 0;
  264.   MaxValue: Single = epsilon;
  265.   Values: array[0..3, 0..Width-1] of Single;
  266.   Count: Integer = 0;
  267. procedure TLandDemo.Process;
  268.   procedure DrawPerfHUD;
  269.   var i: Integer;
  270.   begin
  271.     if Count >= Width div Stride then begin
  272.       Count := 0;
  273.       MaxValue := epsilon;
  274.     end;
  275.     Values[viFrame, Count]  := Core.PerfProfile.Times[ptFrame];
  276.     Values[viRender, Count] := Core.PerfProfile.Times[ptRender];
  277.     if Values[viFrame, Count] > MaxValue then MaxValue := Values[viFrame, Count];
  278.     Inc(Count);
  279.     Screen.ResetViewport;
  280.     Screen.Clear;
  281.   //  Screen.MoveTo(Scree, 0);
  282.   //  Screen.LineTo(100, 100);
  283.   //  Screen.LineTo(100, 200);
  284.     Screen.Color.C := $40000080;
  285.     Screen.Bar(Screen.Width + X, Screen.Height + Y, Screen.Width + X + Width, Screen.Height + Y + Height);
  286.     Screen.Color.C := $40F00000;
  287.     for i := 0 to Count-1 do Screen.Bar(Screen.Width + X+i*Stride, Screen.Height + Y + Height,
  288.                                         Screen.Width + X+i*Stride+Stride-1, Screen.Height + Y + Height - Values[viRender, i]/MaxValue*Height);
  289.     Screen.Color.C := $4000F000;
  290.     for i := 0 to Count-1 do Screen.Bar(Screen.Width + X+i*Stride, Screen.Height + Y + Height - Values[viRender, i]/MaxValue*Height,
  291.                                         Screen.Width + X+i*Stride+Stride-1, Screen.Height + Y + Height - Values[viFrame, i]/MaxValue*Height);
  292.   end;
  293. begin
  294.   Core.Process;
  295. //  DrawPerfHUD;
  296. end;
  297. procedure TLandDemo.HandleMessage(const Msg: TMessage);
  298. var CapMX, CapMY: Integer;
  299. begin
  300.   ObtainCursorPos(CapMX, CapMY);
  301.   if Msg.ClassType = TForceQuitMsg then Starter.Terminate else
  302.   if Msg.ClassType = TDetailLowMsg then begin
  303.     Landscape.SetProperty('X resolution',  DetailLowXStr);
  304.     Landscape.SetProperty('YZ resolution', DetailLowYZStr);
  305.     Landscape.SetProperty('Mip scale', FloatToStr(BaseDetail/StrToFloatDef(DetailLowXStr, BaseDetail)));
  306.     Landscape.SetProperty('TextureClipmap size', DetailLowClipMapStr);
  307.     ShadowCamera.RenderTargetWidth  := DetailLowSMRes;
  308.     ShadowCamera.RenderTargetHeight := DetailLowSMRes;
  309.   end;
  310.   if Msg.ClassType = TDetailMedMsg then begin
  311.     Landscape.SetProperty('X resolution',  DetailMedXStr);
  312.     Landscape.SetProperty('YZ resolution', DetailMedYZStr);
  313.     Landscape.SetProperty('Mip scale', FloatToStr(BaseDetail/StrToFloatDef(DetailMedXStr, BaseDetail)));
  314.     Landscape.SetProperty('TextureClipmap size', DetailMedClipMapStr);
  315.     ShadowCamera.RenderTargetWidth  := DetailMedSMRes;
  316.     ShadowCamera.RenderTargetHeight := DetailMedSMRes;
  317.   end;
  318.   if Msg.ClassType = TDetailHighMsg then begin
  319.     Landscape.SetProperty('X resolution',  DetailHighXStr);
  320.     Landscape.SetProperty('YZ resolution', DetailHighYZStr);
  321.     Landscape.SetProperty('Mip scale', FloatToStr(BaseDetail/StrToFloatDef(DetailHighXStr, BaseDetail)));
  322.     Landscape.SetProperty('TextureClipmap size', DetailHighClipMapStr);
  323.     ShadowCamera.RenderTargetWidth  := DetailHighSMRes;
  324.     ShadowCamera.RenderTargetHeight := DetailHighSMRes;
  325.   end;
  326. end;
  327. procedure TLandDemo.HandleKeys(EventData: Integer; CustomData: Smallint);
  328. begin
  329.   KeyPressed[CustomData and $FF] := CustomData and $100 > 0;
  330. end;
  331. procedure TLandDemo.HandleTimer(EventID: Integer; const ErrorDelta: TTimeUnit);
  332. var Scale, h, t: Single; CameraPos, CameraInLand: TVector3s; Items: TItems; TotalItems: Integer;
  333.   procedure InitShadowCamera;
  334.   const
  335.     ShadowMaxDist = 500;
  336.   var
  337.     Pnts, TPnts: TQuadPoints;
  338.     i: Integer;
  339.     MinP, MaxP: TVector3s;
  340.     M: TMatrix4s;
  341.     d: Single;
  342.   begin
  343.     if Landscape is TProjectedLandscape then TProjectedLandscape(Landscape).ProjectGrid(MainCamera, Pnts);
  344.     M := IdentityMatrix4s;
  345.     Matrix4sByQuat(M, Light.Orientation);
  346.     M := InvertAffineMatrix4s(M);
  347.     ShadowCamera.Orientation := Light.Orientation;
  348.     ShadowCamera.Position := GetVector3s(0, 0, 0);
  349.     for i := 0 to 3 do begin
  350.       d := Sqr(Pnts[i].X - MainCamera.Position.X) + Sqr(Pnts[i].Z - MainCamera.Position.Z);
  351.       if d > Sqr(ShadowMaxDist) then begin
  352.         Pnts[i].X := MainCamera.Position.X + (Pnts[i].X - MainCamera.Position.X)/Sqrt(d) * ShadowMaxDist;
  353.         Pnts[i].Z := MainCamera.Position.Z + (Pnts[i].Z - MainCamera.Position.Z)/Sqrt(d) * ShadowMaxDist;
  354.       end;
  355. //      Pnts[i].Y := 0;
  356.       Transform4Vector33s(TPnts[i], M, Pnts[i]);
  357.     end;
  358.     MinP := TPnts[0];
  359.     MaxP := TPnts[0];
  360.     for i := 1 to 3 do begin
  361.       MinP.X := MinS(MinP.X, TPnts[i].X);
  362.       MinP.Y := MinS(MinP.Y, TPnts[i].Y);
  363.       MinP.Z := MinS(MinP.Z, TPnts[i].Z);
  364.       MaxP.X := MaxS(MaxP.X, TPnts[i].X);
  365.       MaxP.Y := MaxS(MaxP.Y, TPnts[i].Y);
  366.       MaxP.Z := MaxS(MaxP.Z, TPnts[i].Z);
  367.     end;
  368.     ShadowCamera.InitOrthoProjMatrix(0.1, MaxS(4000, (100+MaxP.Z-MinP.Z)*2), MaxS(MaxP.X-MinP.X, MaxP.Y-MinP.Y), 1);
  369.     MulMatrix4s(M, M, TranslationMatrix4s(-(MinP.X+MaxP.X)*0.5, -(Minp.Y+MaxP.Y)*0.5, -MinP.Z+100));
  370.     ShadowCamera.ViewMatrix := M;
  371.     for i := 0 to 3 do begin
  372.       Transform4Vector33s(TPnts[i], M, Pnts[i]);
  373.     end;
  374.     MinP := TPnts[0];
  375.     MaxP := TPnts[0];
  376.     for i := 1 to 3 do begin
  377.       MinP.X := MinS(MinP.X, TPnts[i].X);
  378.       MinP.Y := MinS(MinP.Y, TPnts[i].Y);
  379.       MinP.Z := MinS(MinP.Z, TPnts[i].Z);
  380.       MaxP.X := MaxS(MaxP.X, TPnts[i].X);
  381.       MaxP.Y := MaxS(MaxP.Y, TPnts[i].Y);
  382.       MaxP.Z := MaxS(MaxP.Z, TPnts[i].Z);
  383.     end;
  384.   end;
  385.   procedure InitShadowCamera2;
  386.   var
  387.     i: Integer;
  388.     MinP, MaxP, TPnt: TVector3s;
  389.     M: TMatrix4s;
  390.     d: Single;
  391.   begin
  392.     TotalItems := TCASTRootItem(Core.Root).ExtractByMaskClassInCamera([isVisible], TMesh, Items, MainCamera);
  393.     M := IdentityMatrix4s;
  394.     Matrix4sByQuat(M, Light.Orientation);
  395.     M := InvertAffineMatrix4s(M);
  396.     ShadowCamera.Orientation := Light.Orientation;
  397.     ShadowCamera.Position := GetVector3s(0, 0, 0);
  398.     for i := 0 to TotalItems-1 do if TVisible(Items[i]).Material.Technique[0].Passes[0].Group = 1 then begin
  399.       d := TVisible(Items[i]).BoundingSphereRadius;
  400.       Transform4Vector33s(TPnt, M, TProcessing(Items[i]).GetAbsLocation);
  401.       if i = 0 then begin
  402.         MinP := SubVector3s(TPnt, GetVector3s(d, d, d));
  403.         MaxP := AddVector3s(TPnt, GetVector3s(d, d, d));
  404.       end else begin
  405.         MinP.X := MinS(MinP.X, TPnt.X-d);
  406.         MinP.Y := MinS(MinP.Y, TPnt.Y-d);
  407.         MinP.Z := MinS(MinP.Z, TPnt.Z-d);
  408.         MaxP.X := MaxS(MaxP.X, TPnt.X+d);
  409.         MaxP.Y := MaxS(MaxP.Y, TPnt.Y+d);
  410.         MaxP.Z := MaxS(MaxP.Z, TPnt.Z+d);
  411.       end;
  412.     end;
  413.     ShadowCamera.InitOrthoProjMatrix(0.1, MaxS(4000, (100+MaxP.Z-MinP.Z)*2), MaxS(MaxP.X-MinP.X, MaxP.Y-MinP.Y), 1);
  414.     MulMatrix4s(M, M, TranslationMatrix4s(-(MinP.X+MaxP.X)*0.5, -(Minp.Y+MaxP.Y)*0.5, -MinP.Z+200));
  415.     ShadowCamera.ViewMatrix := M;
  416.   end;
  417.   procedure InitShadowCamera3;
  418.   const
  419.     ShadowMaxDist = 500;
  420.   var
  421.     Pnts, TPnts: array[0..7] of TVector3s;
  422.     i: Integer;
  423.     MinP, MaxP: TVector3s;
  424.     M: TMatrix4s;
  425.     zf: Single;
  426.   begin
  427.     zf := 500;//MainCamera.ZFar*0.01;
  428.     Pnts[0].x := -2 * (Sin(MainCamera.HFoV / 2)/Cos(MainCamera.HFoV / 2)) * MainCamera.ZNear;
  429.     Pnts[0].y := Pnts[0].X * MainCamera.CurrentAspectRatio;
  430.     Pnts[0].Z := MainCamera.ZNear;
  431.     Pnts[1] := Pnts[0];
  432.     Pnts[1].Y := -Pnts[1].Y;
  433.     Pnts[2] := Pnts[1];
  434.     Pnts[2].X := -Pnts[2].X;
  435.     Pnts[3] := Pnts[2];
  436.     Pnts[3].Y := -Pnts[3].Y;
  437.     Pnts[4].x := -2 * (Sin(MainCamera.HFoV / 2)/Cos(MainCamera.HFoV / 2)) * zf;
  438.     Pnts[4].y := Pnts[0].X * MainCamera.CurrentAspectRatio;
  439.     Pnts[4].Z := zf;
  440.     Pnts[5] := Pnts[4];
  441.     Pnts[5].Y := -Pnts[5].Y;
  442.     Pnts[6] := Pnts[5];
  443.     Pnts[6].X := -Pnts[6].X;
  444.     Pnts[7] := Pnts[6];
  445.     Pnts[7].Y := -Pnts[7].Y;
  446.     M := IdentityMatrix4s;
  447.     Matrix4sByQuat(M, Light.Orientation);
  448.     M := InvertAffineMatrix4s(M);
  449.     ShadowCamera.Orientation := Light.Orientation;
  450.     ShadowCamera.Position := GetVector3s(0, 0, 0);
  451.     for i := 0 to 7 do begin
  452.       Pnts[i] := Transform4Vector33s(InvertAffineMatrix4s(MainCamera.ViewMatrix), Pnts[i]);
  453.       Transform4Vector33s(TPnts[i], M, Pnts[i]);
  454.     end;
  455.     MinP := TPnts[0];
  456.     MaxP := TPnts[0];
  457.     for i := 1 to 7 do begin
  458.       MinP.X := MinS(MinP.X, TPnts[i].X);
  459.       MinP.Y := MinS(MinP.Y, TPnts[i].Y);
  460.       MinP.Z := MinS(MinP.Z, TPnts[i].Z);
  461.       MaxP.X := MaxS(MaxP.X, TPnts[i].X);
  462.       MaxP.Y := MaxS(MaxP.Y, TPnts[i].Y);
  463.       MaxP.Z := MaxS(MaxP.Z, TPnts[i].Z);
  464.     end;
  465.     ShadowCamera.InitOrthoProjMatrix(0.1, MaxS(4000, (100+MaxP.Z-MinP.Z)*2), MaxS(MaxP.X-MinP.X, MaxP.Y-MinP.Y), 1);
  466.     MulMatrix4s(M, M, TranslationMatrix4s(-(MinP.X+MaxP.X)*0.5, -(Minp.Y+MaxP.Y)*0.5, -MinP.Z+100));
  467.     ShadowCamera.ViewMatrix := M;
  468.   end;
  469. begin
  470.   Scale := (TimerDelay + ErrorDelta)/TimerDelay;
  471.   MainCamera.Position := AddVector3s(MainCamera.Position, ScaleVector3s(Velocity, Scale));
  472.   CameraPos := MainCamera.Position;
  473.   Velocity := ScaleVector3s(Velocity, 1-(1-BreakFactor)*scale);
  474.   Velocity := AddVector3s(Velocity,
  475.                           Transform3Vector3s(CutMatrix3s(MainCamera.Transform),
  476.                                     GetVector3s( (Ord(KeyPressed[keyRight]) - Ord(KeyPressed[keyLeft]))    * CameraMoveAccel * Scale,
  477.                                                  (Ord(KeyPressed[keyUp])    - Ord(KeyPressed[keyDown]))    * CameraMoveAccel * Scale,
  478.                                                  (Ord(KeyPressed[keyBack])  - Ord(KeyPressed[keyForward])) * CameraMoveAccel * Scale)) );
  479.   if Sqr(CameraPos.X) + Sqr(CameraPos.Z) > Sqr(CameraMoveRadius) then begin
  480.     t := Sqrt(Sqr(CameraPos.X) + Sqr(CameraPos.Z));
  481.     CameraPos.X := CameraPos.X / t * CameraMoveRadius;
  482.     CameraPos.Z := CameraPos.Z / t * CameraMoveRadius;
  483.   end;
  484.   CameraInLand := Transform4Vector33s(InvertAffineMatrix4s(Landscape.Transform), CameraPos);
  485.   h := Landscape.Map.GetHeight(CameraInLand.X, CameraInLand.Z);
  486.   if h + MinCameraAlt > CameraInLand.Y then begin
  487.     CameraPos.Y := CameraPos.Y + h + MinCameraAlt - CameraInLand.Y;
  488.   end;
  489. //  Velocity := AddVector3s(Velocity, ScaleVector3s(SubVector3s(CameraPos, MainCamera.Position), 1));
  490.   MainCamera.Position := CameraPos;
  491.   PostProcessCamera.Position := MainCamera.Position;
  492.   Core.Timer.SetEvent(TimerDelay, {$IFDEF OBJFPCEnable}@{$ENDIF}HandleTimer, 0);
  493. //  FPS := (Core.Renderer.FramesRendered - OldFramesRendered) / (TimerDelay + ErrorDelta);
  494.   OldFramesRendered := Core.Renderer.FramesRendered;
  495. //  OSUtils.SetWindowCaption(Starter.WindowHandle, Format('%3.3F - %3.3F, %3.3F', [Core.PerfProfile.FramesPerSecond, FPS, Scale]));
  496.   FPSLabel.Text := 'FPS: ' + FloatToStrF(Core.PerfProfile.FramesPerSecond,    ffGeneral, 5, 3) +
  497.                    '. PPS: ' + FloatToStrF(Core.PerfProfile.PrimitivesRendered * Core.PerfProfile.FramesPerSecond/1000000, ffNumber, 8, 2) + 'M';
  498.   if Assigned(Light) then begin
  499.     Light.Orientation := MulQuaternion(GetQuaternion(Light.TimeProcessed*CameraRotateSpeed*50, GetVector3s(0, 1, 0)),
  500.                                                LightOrigOrient);
  501.     InitShadowCamera;
  502.   end;
  503. end;
  504. procedure TLandDemo.HandleMouse(EventData: Integer; CustomData: SmallInt);
  505. var MX, MY: Integer;
  506. begin
  507.   MX := Smallint(EventData and $FFFF);
  508.   MY := Smallint((EventData div $10000) and $FFFF);
  509.   with MainCamera do
  510.     Orientation := MulQuaternion(GetQuaternion(MX*CameraRotateSpeed, GetVector3s(0, 1, 0)),
  511.                                  MulQuaternion(GetQuaternion(MY*CameraRotateSpeed, RightVector),
  512.                                                Orientation));
  513.   PostProcessCamera.Orientation := MainCamera.Orientation;
  514. //  BloomCamera.AspectRatio := 1/MainCamera.AspectRatio;
  515. end;
  516. procedure TLandDemo.ToggleBloom(EventData: Integer; CustomData: SmallInt);
  517. begin
  518.   if Assigned(BloomCamera) and (Core.Renderer.MainCamera = MainCamera) then begin
  519.     Core.Renderer.MainCamera := BloomCamera;
  520.     MainCamera.AspectRatio := MainCamera.CurrentAspectRatio;
  521. //    Core.Renderer.MainCamera := ShadowCamera
  522.   end else begin
  523.     Core.Renderer.MainCamera := MainCamera;
  524.     MainCamera.AspectRatio := 1;
  525.   end;  
  526. end;
  527. end.