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

游戏引擎

开发平台:

Delphi

  1. (*
  2.  @Abstract(CAST II Engine main unit)
  3.  (C) 2006-2009 George "Mirage" Bakhtadze. <a href="http://www.casteng.com">www.casteng.com</a> <br>
  4.  The source code may be used under either MPL 1.1 or LGPL 2.1 license. See included license.txt file <br>
  5.  Started Jan 15, 2006 <br>
  6.  Unit contains basic engine classes
  7. *)
  8. {$Include GDefines.inc}
  9. {$Include C2Defines.inc}
  10. unit Cast2;
  11. interface
  12. uses
  13.   TextFile, Timer,
  14.   BaseTypes, Basics, BaseCont, Models, BaseClasses, Base3D, BaseMsg, ItemMsg, Collisions, Props, C2Types;
  15. const
  16.   EngineVersionMajor = '0';
  17.   EngineVersionMinor = '992';
  18.   // Bounding volume kinds enumeration string
  19.   VolumeKindsEnum = 'OOBB&Sphere';
  20.   // Items processing interval by default
  21.   DefaultProcessingInterval = 30/1000;
  22.   // Pass ordering enumeration string
  23.   PassOrdersEnum = 'Preprocess&Background&Farest&Normal&Sorted&Nearest&Foreground&PostProcess';
  24.   // This order used for preprocess passes
  25.   poPreprocess = 0;
  26.   // This order used for passes that should be at background
  27.   poBackground = 1;
  28.   // This order used for passes that should be farest
  29.   poFarest = 2;
  30.   // This order used for usual passes
  31.   poNormal = 3;
  32.   // This order used for passes that should render corresponding items in a particular order (usually transparent items)
  33.   poSorted = 4;
  34.   // This order used for passes that should be neartest
  35.   poNearest = 5;
  36.   // This order used for passes that should be at foreground
  37.   poForeground = 6;
  38.   // This order used for postprocess passes
  39.   poPostProcess = 7;
  40.   // Order corresponding to passes with sorted items
  41.   SortedPassOrder = poSorted;
  42.   // Number of pass groups currently supported by the engine
  43.   PassGroupsCount = 16;
  44.   // Pass groups enumeration string
  45.   PassGroupsEnum = 'Group 01&Group 02&Group 03&Group 04&Group 05&Group 06&Group 07&Group 08&' +
  46.                    'Group 09&Group 10&Group 11&Group 12&Group 13&Group 14&Group 15&Group 16';
  47.   // Set of all pass groups
  48.   gmAll     = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
  49.   // Default set of pass groups
  50.   gmDefault = [0, 1, 2, 3, 4, 5, 6, 7];
  51.   // Maximum of texture coordinates sets
  52.   MaxTextureCoordSets = 8;
  53.   // Maximum of user-defined clipping planes currently supported by the engine
  54.   MaxClipPlanes       = 6;
  55. type
  56.   // Type to specify location of an object in 3D space. Additional component can be used to work with floating coordinates, space partitioning, etc.
  57.   TLocation = TVector4s;
  58.   // Traverse callback results
  59.   TTraverseResult = (// Continue traversal
  60.                      trContinue,
  61.                      // Skip traversal for childs of the current item
  62.                      trSkip,
  63.                      // Stop traversal
  64.                      trStop);
  65.   // Frustum planes
  66.   TFrustumPlane = (fpLeft, fpRight, fpTop, fpBottom, fpNear, fpFar);
  67.   TFrustumCheckResult = (// An item is completely outside of the frustum
  68.                          fcOutside,
  69.                          // An item is completely inside the frustum
  70.                          fcInside,
  71.                          // An item is partially inside the frustum
  72.                          fcPartially);
  73.   // Pass groups range
  74.   TPassGroup = 0..PassGroupsCount-1;
  75.   // Pass groups set. Groups used to perform some operations (lighting, render) for one set of passes and not to perform for other set of passes
  76.   TPassGroupSet = set of TPassGroup;
  77.   // User-defined clipping planes
  78.   TClipPlanes      = array[0..MaxClipPlanes-1] of PPlane;
  79.   // Traverse mask
  80.   TTraverseMask = BaseTypes.TSet32;
  81.   // Class containing collision-related information for an item
  82.   TColliding = class(BaseCont.TBaseUniqueItem)
  83.     // The item to which the collision information belongs
  84.     Owner: BaseClasses.TItem;
  85.     // Bounding volumes set
  86.     Volumes: Collisions.TBoundingVolumes;
  87.     constructor Create; override;
  88.     destructor Destroy; override;
  89.   end;
  90.   // Tesselation buffers enumeration
  91.   TTesselationBuffer = (// Vertex buffer
  92.                         tbVertex,
  93.                         // Index buffer
  94.                         tbIndex);
  95.   // Set of tesselation buffers                      
  96.   TTesselationBufferSet = set of TTesselationBuffer;
  97.   // Vertex/index buffers performace profile
  98.   TBuffersPerfProfile = record
  99.     // Number of tesselation calls for static and dynamic meshes in current frame. Normally should be zero for static meshes
  100.     TesselationsPerformed,
  101.     // Amount of data written to buffers during tesselation
  102.     BytesWritten,
  103.     // Number of resets of static and dynamic buffers in current frame. Normally should be zero for static buffers
  104.     BufferResetsCount,
  105.     // Current size of the buffer in bytes
  106.     BufferSize: array[Boolean] of Integer;
  107.     // Number of items rendered without tesselations of a certain buffer (vertex/index)
  108.     TesselationsBypassed,
  109.     // Number of buffer bytes reused
  110.     BytesBypassed: Integer;
  111.   end;
  112.   TPerfTimer = (// Entire frame time
  113.                 ptFrame,
  114.                 // Render time
  115.                 ptRender,
  116.                 // Objects processing time
  117.                 ptProcessing,
  118.                 // Collision detection
  119.                 ptCollision);
  120.   // Engine performance profile data
  121.   TPerfProfile = class
  122.   private
  123.     TimeMarks: array[TPerfTimer] of TTimeMark;
  124.     FFramesPerSecond, FMinFramesPerSecond, FMaxFramesPerSecond: Single;
  125.     procedure SetFramesPerSecond(const Value: Single);
  126.     function GetPrimitivesPerSecond: Single;
  127.   public
  128.     Times: array[TPerfTimer] of TTimeUnit;
  129.     // Number of render target changes during rendering a frame
  130.     RenderTargetChanges,
  131.     // Number of primitives (triangles) rendered in current frame
  132.     PrimitivesRendered,
  133.     // Number of draw calls (DrawIndexedPrimitive etc) in current frame
  134.     DrawCalls,
  135.     // Number of clear calls during rendering a frame
  136.     ClearCalls: Integer;
  137.     // Number of items culled out with frustum culling in current frame
  138.     FrustumCulledItems,
  139.     // Number of items passed frustum culling (and probably actually drawn) in current frame
  140.     FrustumPassedItems: Integer;
  141.     // Number of sorted items in current frame
  142.     SortedItems: Integer;
  143.     // Vertex/index buffers performace profile
  144.     BuffersProfile: array[TTesselationBuffer] of TBuffersPerfProfile;
  145.     // Sets values which should be zeroed-out at frame render start
  146.     procedure OnFrameStart;
  147.     // Sets values which should be resetted at render buffers reset
  148.     procedure OnBuffersReset;
  149.     // Starts timing of the specified performance timer using the specified timer class
  150.     procedure BeginTiming(Timer: TTimer; PerfTimer: TPerfTimer);
  151.     // Stops timing and returns the specified performance timer value using the specified timer class
  152.     function EndTiming(Timer: TTimer; PerfTimer: TPerfTimer): TTimeUnit;
  153.     // Frame rate averaged through some time
  154.     property FramesPerSecond: Single read FFramesPerSecond write SetFramesPerSecond;
  155.     // Number of primitives per second
  156.     property PrimitivesPerSecond: Single read GetPrimitivesPerSecond;
  157.     // Minimal averaged frame rate
  158.     property MinFramesPerSecond: Single read FMinFramesPerSecond;
  159.     // Maximal averaged frame rate
  160.     property MaxFramesPerSecond: Single read FMaxFramesPerSecond;
  161.   end;
  162.   TBaseCore = class;
  163.   // Base class of shared tesselators manager
  164.   TBaseSharedTesselators = class
  165.     // Engine core (items manager)
  166.     Core: TBaseCore;
  167.     // Makes items associated with shared tesselators visible
  168.     procedure Render; virtual; abstract;
  169.     // Makes items associated with shared tesselators invisible
  170.     procedure Reset; virtual; abstract;
  171.     // Clears items associated with shared tesselators
  172.     procedure Clear; virtual; abstract;
  173.   end;
  174.   // Engine base core class
  175.   TBaseCore = class(TItemsManager)
  176.   private
  177.     FTesselatorManager: BaseCont.TReferencedItemManager;
  178.     Subsystems: array of TSubsystem;
  179.     FTimer, DefaultTimer: Timer.TTimer;
  180.     procedure SetTimer(const Value: Timer.TTimer);
  181.     procedure SetTotalProcessingClasses(const Value: Integer);
  182.   protected
  183.     // Time mark for delta time based items processing
  184.     DeltaTimeBasedTimeMark: TTimeMark;
  185.     // Number of items to process
  186.     ProcessingItems: TItems;
  187.     // Items to process
  188.     TotalProcessingItems: Integer;
  189.     // Shared tesselators manager. For internal use only
  190.     FSharedTesselators: TBaseSharedTesselators;
  191.     // Temporary items container. Used internally for shared tesselators visualization etc.
  192.     FTempItems: BaseClasses.TItem;
  193.     // Performance profile
  194.     FPerfProfile: TPerfProfile;
  195.     // Performs delta time based items processing
  196.     procedure ProcessDeltaTimeBased(const DeltaTime: TTimeUnit);
  197.     // Performs items processing
  198.     procedure ProcessingEvent(EventID: Integer; const ErrorDelta: TTimeUnit);
  199.     procedure OnDestroy; override;
  200.   public
  201.     // If <b>Paused</b> is <b>True</b> @Link(Process) methods will be called only for items which processing class includes the @Link(pfIgnorePause) flag
  202.     Paused: Boolean;
  203.     // Delta time scale factor for all processing classes
  204.     TimeScale: Single;
  205.     // Maximum of simultaneous light sources
  206.     SimultaneousLightSources: Integer;
  207.     // Random numbers generator
  208.     RandomGen: Basics.TRandomGenerator;
  209.     // By assigning this handler reference an additional message handler can be included into the message handling chain
  210.     MessageHandler: BaseMsg.TMessageHandler;
  211.     constructor Create; override;
  212.     procedure HandleMessage(const Msg: TMessage); override;
  213.     // Register a subsystem. All registered subsystems will receive all messages received by the core.
  214.     procedure AddSubsystem(const Subsystem: TSubsystem);
  215.     // Unregister a subsystem
  216.     procedure RemoveSubsystem(const Subsystem: TSubsystem);
  217.     // Returns a registered subsystem of the specified class or successor
  218.     function QuerySubsystem(SubsystemClass: CSubsystem): TSubsystem;
  219.     // Sets parameters of a processing class.
  220.     procedure SetProcessingClass(Index: Integer; Interval: Single; IgnorePause, DeltaTimeBased: Boolean);
  221.     // For internal use only.
  222.     procedure AddPass(const Item: BaseClasses.TItem); virtual; abstract;
  223.     // For internal use only.
  224.     procedure RemovePass(const Item: BaseClasses.TItem); virtual; abstract;
  225.     // Clears current scene
  226.     procedure ClearItems; override;
  227.     // Shared tesselators manager. For internal use only.
  228.     property SharedTesselators: TBaseSharedTesselators read FSharedTesselators;
  229.     // Tesselators manager. For internal use only.
  230.     property TesselatorManager: BaseCont.TReferencedItemManager read FTesselatorManager;
  231.     // Temporary items container. Used internally for shared tesselators visualization etc.
  232.     property TempItems: BaseClasses.TItem read FTempItems;
  233.     // Timer subsystem. Must be assigned.
  234.     property Timer: Timer.TTimer read FTimer write SetTimer;
  235.     // Performance profile
  236.     property PerfProfile: TPerfProfile read FPerfProfile;
  237.     // Number of processing classes
  238.     property TotalProcessingClasses: Integer read GetTotalProcessingClasses write SetTotalProcessingClasses;
  239.   end;
  240.   CProcessing = class of TProcessing;
  241.   // Base class of all processing (updateable) objects
  242.   TProcessing = class(TBaseProcessing)
  243.   private
  244.   public
  245.     TransformValid: Boolean;
  246.     function GetTransform: TMatrix4s;
  247.     procedure SetTransform(const ATransform: TMatrix4s);
  248.     function GetForwardVector: TVector3s;
  249.     function GetRightVector: TVector3s;
  250.     function GetUpVector: TVector3s;
  251.     function GetPosition: TVector3s;
  252.     procedure SetPosition(const Value: TVector3s);
  253.     function GetScale: TVector3s;
  254.     procedure SetScale(const Value: TVector3s);
  255.     function GetLocation: TLocation;
  256.     procedure SetLocation(ALocation: TLocation);
  257.     function GetOrientation: TQuaternion;
  258.     procedure SetOrientation(AOrientation: TQuaternion);
  259.     function GetDimensions: TVector3s;
  260.     function GetBoundingSphereRadius: Single;
  261.   protected
  262.     // Transformation matrix of the item
  263.     FTransform: TMatrix4s;
  264.     // Current orientation of the item
  265.     FOrientation: TQuaternion;
  266.     // Current location of the item
  267.     FLocation: TLocation;
  268.     // Current scale of the item
  269.     FScale: TVector3s;
  270.     { In CAST II engine a lazy evaluation scheme used for transformation computations.
  271.       This method will compute current transformation matrix when and only when it is necessary. }
  272.     procedure ComputeTransform; virtual;
  273.     // Calling this method will tell the engine that @Link(FTransform) became invalid and should be recomputed before next use
  274.     procedure InvalidateTransform; virtual;       // try to avoid virtuality
  275.     // Returns AItem if OK or nil if index is invalid or impossible to set a child
  276.     function SetChild(Index: Integer; AItem: BaseClasses.TItem): BaseClasses.TItem; override;
  277.   public
  278.     // Contains information about bounding volumes of the item which will be used for collision tests
  279.     Colliding: TColliding;
  280.     // Returns bounding box of the item
  281.     BoundingBox: Base3D.TBoundingBox;
  282. //    FullBoundingBox: Base3D.TBoundingBox;
  283.     constructor Create(AManager: TItemsManager); override;
  284.     destructor Destroy; override;
  285.     // Called when a collision of the item with another items was detected
  286.     procedure OnCollision(Item: TProcessing; const ColRes: Collisions.TCollisionResult); virtual;
  287.     { This procedure is called (by editor for example) to retrieve a list of item's properties and their values.
  288.       Any TItem descendant class should override this method in order to add its own properties. }
  289.     procedure AddProperties(const Result: Props.TProperties); override;
  290.     { This procedure is called (by editor for example) to set values of item's properties.
  291.       Any TItem descendant class should override this method to allow its own properties to be set. }
  292.     procedure SetProperties(Properties: Props.TProperties); override;
  293.     // Returns position of the item in world's coordinate space
  294.     function GetAbsLocation: TVector3s;
  295.     // Returns orientation of the item in world's coordinate space
  296.     function GetAbsOrientation: TQuaternion;
  297.     // Transforms a point from local model's coordinate space to world's coordinate space
  298.     function ModelToWorld(const APoint: TVector3s): TVector3s;
  299.     // Transforms a point from world's coordinate space to local model's coordinate space
  300.     function WorldToModel(const APoint: TVector3s): TVector3s;
  301.     // Transformation matrix of the item
  302.     property Transform: TMatrix4s         read GetTransform   write SetTransform;
  303.     // 4-component position of the item within parent's coordinate space
  304.     property Location: TLocation          read GetLocation    write SetLocation;
  305.     // Position of the item within parent's coordinate space
  306.     property Position: TVector3s          read GetPosition    write SetPosition;
  307.     // Scale of the item within parent's coordinate space
  308.     property Scale: TVector3s             read GetScale       write SetScale;
  309.     // Orientation of the item within parent's coordinate space
  310.     property Orientation: TQuaternion     read GetOrientation write SetOrientation;
  311.     // Forward direction for the item
  312.     property ForwardVector: TVector3s     read GetForwardVector;
  313.     // Right direction for the item
  314.     property RightVector: TVector3s       read GetRightVector;
  315.     // Up direction for the item
  316.     property UpVector: TVector3s          read GetUpVector;
  317.     // Dimensions of the item based on its bounding box (see @Link(BoundingBox))
  318.     property Dimensions: TVector3s        read GetDimensions;
  319.     // The item's bounding sphere radius based on @Link(Dimensions)
  320.     property BoundingSphereRadius: Single read GetBoundingSphereRadius;
  321.   end;
  322.   // Item move operation
  323.   TItemMoveOp = class(Models.TOperation)
  324.   private
  325.     AffectedProcessing: TProcessing;
  326.     Location: TLocation;
  327.   protected
  328.     // Applies the operation
  329.     procedure DoApply; override;
  330.     // Merges together two move operations
  331.     function DoMerge(AOperation: Models.TOperation): Boolean; override;
  332.   public
  333.     // Inits the operation with the specified processing item and its new location
  334.     function Init(AAffectedProcessing: TProcessing; ALocation: TLocation): Boolean;
  335.   end;
  336.   // Item orientation change operation
  337.   TItemRotateOp = class(Models.TOperation)
  338.   private
  339.     AffectedProcessing: TProcessing;
  340.     Orientation: TQuaternion;
  341.   protected
  342.     // Applies the operation
  343.     procedure DoApply; override;
  344.     // Merges together two orientation change operations
  345.     function DoMerge(AOperation: Models.TOperation): Boolean; override;
  346.   public
  347.     // Inits the operation with the specified processing item and its new orientation
  348.     function Init(AAffectedProcessing: TProcessing; AOrientation: TQuaternion): Boolean;
  349.   end;
  350.   // Callback function used to traverse through items hierarchy
  351.   TTraverseCallback = function(Item: BaseClasses.TItem): TTraverseResult;
  352.   // Collection of items
  353.   TItemCollection = record
  354.     TraverseMask: TTraverseMask;
  355.     TotalItems: Integer;
  356.     Items: array of BaseClasses.TItem;
  357.   end;
  358.   { Specifies clear settings.
  359.     <b>ClearFlags</b> - what to clear
  360.     <b>ClearColor</b> - clear color
  361.     <b>ClearStencil</b> - a stencil value to clear with
  362.     <b>ClearZ</b> - a Z value to clear with  }
  363.   TClearSettings = record
  364.     ClearFlags: TClearFlagsSet;
  365.     ClearColor: BaseTypes.TColor;
  366.     ClearStencil: Longword;
  367.     ClearZ: Single;
  368.   end;
  369.   // Camera
  370.   TCamera = class(TProcessing)
  371.   private
  372.     FOrthographic: Boolean;
  373.     FCurrentAspectRatio,
  374.     FZNear,
  375.     FZFar,
  376.     FWidth,
  377.     FAspectRatio,
  378.     FHFoV: Single;
  379.     FFrustumPlanes: array[TFrustumPlane] of TPlane;
  380.     ViewValid: Boolean;
  381.     FRTColorFormat, FRTDepthFormat: Integer;
  382.     function GetViewMatrix: TMatrix4s;
  383.     procedure SetViewMatrix(const Value: TMatrix4s);
  384.     function GetInvViewMatrix: TMatrix4s;
  385.     function GetTotalMatrix: TMatrix4s;
  386.     function GetViewOrigin: TVector3s;
  387.     function GetLookDir: TVector3s;
  388.     function GetRightDir: TVector3s;
  389.     function GetUpDir: TVector3s;
  390.     procedure SetAspectRatio(const Value: Single);
  391.     procedure ComputeFrustumPlanes;
  392.   protected
  393.     // View matrix
  394.     FViewMatrix,
  395.     // Inverse view matrix
  396.     FInvViewMatrix,
  397.     // Projection matrix
  398.     FProjMatrix,
  399.     // View * projection matrix
  400.     FTotalMatrix: TMatrix4s;
  401.     // Current render width
  402.     FRenderWidth,
  403.     // Current render height
  404.     FRenderHeight: Integer;
  405.     // Calling this method will tell the engine that @Link(FTransform) became invalid and should be recomputed before next use
  406.     procedure InvalidateTransform; override;
  407.     procedure ComputeViewMatrix; virtual;
  408.   public
  409.     // Default cameras can
  410. //    Default: Boolean;
  411.     // Default fill mode for the camera
  412.     DefaultFillMode: TFillMode;
  413.     // Default cull mode for the camera
  414.     DefaultCullMode: TCullMode;
  415.     // Determines what and when should be cleared
  416.     ClearSettings: TClearSettings;
  417.     // private
  418.       RenderTargetIndex: Integer;
  419.     // User-defined clip planes
  420.     ClipPlanes: TClipPlanes;
  421.     // Determines which passes can be visible through the camera
  422.     GroupMask: TPassGroupSet;
  423.     // Current rendering color format. Updated by renderer
  424.     ColorFormat,
  425.     // Current rendering depth format. Updated by renderer
  426.     DepthFormat: Integer;
  427.     // Width of a render target texture used if the camera will be used as a texture
  428.     RenderTargetWidth,
  429.     // Height of a render target texture used if the camera will be used as a texture
  430.     RenderTargetHeight: Integer;
  431.     // Determines how many frames should be skipped between render target texture updates
  432.     FrameSkip: Integer;
  433.     // Cameras can render scene in higher or lower detail which is controlled by this parameter 
  434.     LODBias: Single;
  435.     // Determines if a depth-stencil surface instead of color surface should be used when the camera applied as a texture
  436.     IsDepthTexture: Boolean;
  437.     constructor Create(AManager: TItemsManager); override;
  438.     destructor Destroy; override;
  439.     { This procedure is called (by editor for example) to retrieve a list of item's properties and their values.
  440.       Any TItem descendant class should override this method in order to add its own properties. }
  441.     procedure AddProperties(const Result: Props.TProperties); override;
  442.     { This procedure is called (by editor for example) to set values of item's properties.
  443.       Any TItem descendant class should override this method to allow its own properties to be set. }
  444.     procedure SetProperties(Properties: Props.TProperties); override;
  445.     // Sets up the camera's projection matrix with the given near and far Z planes, horizontal field of view and aspect ratio
  446.     procedure InitProjMatrix(AZNear, AZFar, AHFoV, AAspectRatio: Single); virtual;
  447.     // Sets up the camera's orthographic projection matrix with the given near and far Z planes, width of view and aspect ratio
  448.     procedure InitOrthoProjMatrix(AZNear, AZFar, VisibleWidth, AAspectRatio: Single); virtual;
  449.     // Sets the @Link(ClearSettings)
  450.     procedure SetClearState(AClearFlags: TClearFlagsSet; AClearColor: BaseTypes.TColor; AClearZ: Single; AClearStencil: Cardinal); virtual;
  451.     // Sets render dimensions and recalculates projection matrix. Normally called by renderer when render window size changes.
  452.     procedure SetScreenDimensions(Width, Height: Integer; AdjustAspectRatio: Boolean);
  453.     // Rotates the camera by the specified angles
  454.     procedure Rotate(XA, YA, ZA: Single); virtual;
  455.     // Moves the camera by the specified distance in camera space
  456.     procedure Move(XD, YD, ZD: Single); virtual;
  457.     // Returns not normalized direction of a ray in view space which starts from the camera and passes through the given point on screen
  458.     function GetPickRay(ScreenX, ScreenY: Single): TVector3s; virtual;
  459.     // Returns not normalized direction of a ray in world space which starts from the camera and passes through the given point on screen
  460.     function GetPickRayInWorld(ScreenX, ScreenY: Single): TVector3s; virtual;
  461.     // Returns the given vector after projection with the camera
  462.     function Project(const Vec: TVector3s): TVector4s;
  463.     // Renderer calls this event right before the camera apply
  464.     procedure OnApply(const OldCamera: TCamera); virtual;
  465.     // Performs a frustrum visibility check against a sphere with the given center and radius
  466.     function IsSpehereVisible(const Center: TVector3s; Radius: Single): TFrustumCheckResult;
  467.     // Near Z plane distance
  468.     property ZNear: Single read FZNear;
  469.     // Far Z plane distance
  470.     property ZFar: Single read FZFar;
  471.     // Initial aspect ratio. Can change
  472.     property AspectRatio: Single read FAspectRatio write SetAspectRatio;
  473.     // Current aspect ratio
  474.     property CurrentAspectRatio: Single read FCurrentAspectRatio;
  475.     // Horizontal field of view in radians
  476.     property HFoV: Single read FHFoV;
  477.     // Current render width
  478.     property RenderWidth: Integer read FRenderWidth;
  479.     // Current render height
  480.     property RenderHeight: Integer read FRenderHeight;
  481.     // Color format which will be used in case of use of this camera as a texture
  482.     property RTColorFormat: Integer read FRTColorFormat;
  483.     // Depth format which will be used in case of use of this camera as a texture
  484.     property RTDepthFormat: Integer read FRTDepthFormat;
  485.     // View matrix
  486.     property ViewMatrix: TMatrix4s read GetViewMatrix write SetViewMatrix;
  487.     // Inverse view matrix
  488.     property InvViewMatrix: TMatrix4s read GetInvViewMatrix;
  489.     // Projection matrix
  490.     property ProjMatrix: TMatrix4s read FProjMatrix write FProjMatrix;
  491.     // View * projection matrix
  492.     property TotalMatrix: TMatrix4s read GetTotalMatrix;
  493.     // Position of the camera's view point in world space
  494.     property ViewOrigin: TVector3s read GetViewOrigin;
  495.     // View direction of the camera in world space
  496.     property LookDir: TVector3s read GetLookDir;
  497.     // Right direction of the camera in world space
  498.     property RightDir: TVector3s read GetRightDir;
  499.     // Up direction of the camera in world space
  500.     property UpDir: TVector3s read GetUpDir;
  501.   end;
  502.   // An item of this class should be the root of items hierarchy
  503.   TCASTRootItem = class(TRootItem)
  504.   private
  505.     // collection for various sets of items from scene (e.g. renderable, processing etc)
  506.     Collections: array of TItemCollection;
  507.     TotalCollections: Integer;
  508.     Collidings: TUniqueItemCollection;
  509. //    ModifyingCollectionIndex: Integer;
  510. //    procedure IncludeItem(Item: BaseClasses.TItem; Mask: TTraverseMask);
  511. //    procedure ExcludeItem(Item: BaseClasses.TItem; Mask: TTraverseMask);
  512.     // Internal function used as callback only
  513. //    function AddToCollectionCallback(Item: BaseClasses.TItem): TTraverseResult;
  514. //    procedure AddToCollection(CollectionIndex: Integer; Item: BaseClasses.TItem); virtual;
  515. //    procedure RemoveFromCollection(CollectionIndex: Integer; Item: BaseClasses.TItem); virtual;
  516.   protected
  517.     // Adds item's collision info to a collision manager
  518.     procedure AddColliding(AItem: TProcessing);
  519.     // Removes item's collision info from a collision manager
  520.     procedure RemoveColliding(AItem: TProcessing);
  521.   public
  522.     // Clear settings for all render stages
  523.     StageSettings: array[poPreprocess..poPostProcess] of TClearSettings;
  524.     constructor Create(AManager: TItemsManager); override;
  525.     destructor Destroy; override;
  526.     function GetItemSize(CountChilds: Boolean): Integer; override;
  527.     { This procedure is called (by editor for example) to retrieve a list of item's properties and their values.
  528.       Any TItem descendant class should override this method in order to add its own properties. }
  529.     procedure AddProperties(const Result: Props.TProperties); override;
  530.     { This procedure is called (by editor for example) to set values of item's properties.
  531.       Any TItem descendant class should override this method to allow its own properties to be set. }
  532.     procedure SetProperties(Properties: Props.TProperties); override;
  533.     { Traverses through the items hierarchy and adds to Items all items matching the following:       <br>
  534.       the item is an instance of the given class or a descendant, its State field has matches Mask and
  535.       the item is within the given range from the given origin.
  536.       Childs of items with non-matching State are not considered.
  537.       Returns number of items in Items. }
  538.     function ExtractByMaskClassInRadius(Mask: TItemFlags; AClass: CProcessing; out Items: TItems; Origin: TLocation; Range: Single): Integer;
  539.     { Traverses through the items hierarchy and adds to Items all items matching the following:       <br>
  540.       the item is an instance of the given class or a descendant, its State field has matches Mask and
  541.       the item is within visibility frustum of the given camera.
  542.       Childs of items with non-matching State are not considered.
  543.       Returns number of items in Items. }
  544.     function ExtractByMaskClassInCamera(Mask: TItemFlags; AClass: CProcessing; out Items: TItems; ACamera: TCamera): Integer;
  545.     procedure HandleMessage(const Msg: TMessage); override;
  546.     // Adds a collection of items with the specified state
  547.     function AddCollection(Mask: TTraverseMask): Integer;
  548.     // Removes collection specified by the index
  549.     procedure DeleteCollection(Index: Integer);
  550.     // Traverses through the items hierarchy and calls Callback for all items
  551.     procedure TraverseTree(Callback: TTraverseCallback);
  552.     // Performs a collision test. ToDo: move to core
  553.     procedure Collide;
  554.     // Frees all childs
  555.     procedure FreeChilds; override;
  556.   end;
  557.   { @Abstract(Camera class for mirror surfaces)
  558.     The camera constructs its view matrix as a reflection of view matrix of previous camera by XY plane if the camera's transform}
  559.   TMirrorCamera = class(TCamera)
  560.   private
  561.     FOldCamera: TCamera;
  562.   public
  563.     // Reflects previous applyed camera view matrix by its own XY plane and assigns the result to view matrix
  564.     procedure ComputeViewMatrix; override;
  565.     // OnApply event overridden to assign previous camera variable and setup clipping plane
  566.     procedure OnApply(const OldCamera: TCamera); override;
  567.   end;
  568. {  TRenderParameters = record
  569.     MainCamera, ActiveCamera: TCamera;
  570.   end;
  571.   PRenderParameters = ^TRenderParameters;}
  572.   // Returns a location from 3D vector
  573.   function GetLocationFromVec3s(V: TVector3s): TLocation;
  574.   // Retuns True if the locations are equal
  575.   function EqualLocations(V1, V2: TLocation): Boolean;
  576.   // Retuns squared distance between the locations
  577.   function LocationSqDistance(V1, V2: TLocation): Single;
  578.   // Helper functions for adding/setting properties of a certain type
  579.   // Adds a string property named "Error" with the value contained in <b>Msg</b>
  580.   procedure AddErrorProperty(Properties: Props.TProperties; const Msg: string);
  581.   // Adds a 3-component vector and each its component as properties
  582.   procedure AddVector3sProperty(Properties: Props.TProperties; const Name: string; const Vec: TVector3s);
  583.   // Adds a 4-component vector and each its component as properties
  584.   procedure AddVector4sProperty(Properties: Props.TProperties; const Name: string; const Vec: TVector4s);
  585.   // Adds a quaternion and each its component as properties
  586.   procedure AddQuaternionProperty(Properties: Props.TProperties; const Name: string; const Quat: TQuaternion);
  587.   // Reads a 3-component vector from properties. If its not equivalent to the one contained in <b>Res</b> assigns it to <b>Res</b> and returns <b>True</b>.
  588.   function SetVector3sProperty(Properties: Props.TProperties; const Name: string; var Res: TVector3s): Boolean;
  589.   // Reads a 4-component vector from properties. If its not equivalent to the one contained in <b>Res</b> assigns it to <b>Res</b> and returns <b>True</b>.
  590.   function SetVector4sProperty(Properties: Props.TProperties; const Name: string; var Res: TVector4s): Boolean;
  591.   // Reads a quaternion from properties. If its not equivalent to the one contained in <b>Res</b> assigns it to <b>Res</b> and returns <b>True</b>.
  592.   function SetQuaternionProperty(Properties: Props.TProperties; const Name: string; var Res: TQuaternion): Boolean;
  593. implementation
  594. uses SysUtils;
  595. function GetLocationFromVec3s(V: TVector3s): TLocation;
  596. begin
  597.   Result.X := V.X;
  598.   Result.Y := V.Y;
  599.   Result.Z := V.Z;
  600.   Result.W := 1;
  601. end;
  602. function EqualLocations(V1, V2: TLocation): Boolean;
  603. begin
  604.   Result := (V1.X = V2.X) and (V1.Y = V2.Y) and (V1.Z = V2.Z) and (V1.W = V2.W);
  605. end;
  606. function LocationSqDistance(V1, V2: TLocation): Single;
  607. begin
  608.   Result := Sqr(V2.X-V1.X) + Sqr(V2.Y-V1.Y)+  Sqr(V2.Z-V1.Z);
  609. end;
  610. procedure AddErrorProperty(Properties: Props.TProperties; const Msg: string);
  611. begin
  612.   Properties.Add('Error', vtString, [poReadonly], Msg, '');
  613. end;
  614. procedure AddVector3sProperty(Properties: Props.TProperties; const Name: string; const Vec: TVector3s);
  615. begin
  616.   Properties.Add(Name,        vtString, [poReadOnly], Format('(%3.3F, %3.3F, %3.3F)', [Vec.X, Vec.Y, Vec.Z]), '');
  617.   Properties.Add(Name + 'X', vtSingle, [], FloatToStr(Vec.X), '');
  618.   Properties.Add(Name + 'Y', vtSingle, [], FloatToStr(Vec.Y), '');
  619.   Properties.Add(Name + 'Z', vtSingle, [], FloatToStr(Vec.Z), '');
  620. end;
  621. procedure AddVector4sProperty(Properties: Props.TProperties; const Name: string; const Vec: TVector4s);
  622. begin
  623.   AddVector3sProperty(Properties, Name, Vec.XYZ);
  624.   Properties.Add(Name + 'W', vtSingle, [], FloatToStr(Vec.W), '');
  625.   Properties.Add(Name,        vtString, [poReadOnly], Format('(%3.3F, %3.3F, %3.3F, %3.3F)', [Vec.X, Vec.Y, Vec.Z, Vec.W]), '');
  626. end;
  627. procedure AddQuaternionProperty(Properties: Props.TProperties; const Name: string; const Quat: TQuaternion);
  628. var Angle: Single;
  629. begin
  630.   AddVector3sProperty(Properties, Name, GetVector3s(Quat[1], Quat[2], Quat[3]));
  631.   Angle := ArcTan2(Sqrt(1 - Quat[0] * Quat[0]), Quat[0])*2 * 180/pi;
  632.   Properties.Add(Name + 'Angle', vtSingle, [], FloatToStr(Angle), '');
  633.   Properties.Add(Name,            vtString, [poReadOnly], Format('(%3.3F, (%3.3F, %3.3F, %3.3F))', [Angle, Quat[1], Quat[2], Quat[3]]), '');
  634. end;
  635. function SetVector3sProperty(Properties: Props.TProperties; const Name: string; var Res: TVector3s): Boolean; overload;
  636. var NewVec: TVector3s;
  637. begin
  638.   NewVec := Res;
  639.   if Properties.Valid(Name + 'X') then NewVec.X := StrToFloatDef(Properties[Name + 'X'], 0);
  640.   if Properties.Valid(Name + 'Y') then NewVec.Y := StrToFloatDef(Properties[Name + 'Y'], 0);
  641.   if Properties.Valid(Name + 'Z') then NewVec.Z := StrToFloatDef(Properties[Name + 'Z'], 0);
  642.   Result := isNan(Res.X) or isNan(Res.Y) or isNan(Res.Z) or
  643.            (NewVec.X <> Res.X) or (NewVec.Y <> Res.Y) or (NewVec.Z <> Res.Z);
  644.   if Result then Res := NewVec;
  645. end;
  646. function SetVector4sProperty(Properties: Props.TProperties; const Name: string; var Res: TVector4s): Boolean; overload;
  647. var NewVec: TVector3s; W: Single;
  648. begin
  649.   NewVec := Res.XYZ;
  650.   W := Res.W;
  651.   Result := SetVector3sProperty(Properties, Name, NewVec);
  652.   if Properties.Valid(Name + 'W') then W := StrToFloatDef(Properties[Name + 'W'], 0);
  653.   Result := Result or isNan(Res.W) or (W <> Res.W);
  654.   if Result then begin
  655.     Res := ExpandVector3s(NewVec);
  656.     Res.W := W;
  657.   end;
  658. end;
  659. function SetQuaternionProperty(Properties: Props.TProperties; const Name: string; var Res: TQuaternion): Boolean; 
  660. var NewVec: TVector3s; Angle: Single;
  661. begin
  662.   NewVec.X := Res[1]; NewVec.Y := Res[2]; NewVec.Z := Res[3];
  663.   Result := SetVector3sProperty(Properties, Name, NewVec);
  664.   if Properties.Valid(Name + 'Angle') then Angle := StrToFloatDef(Properties[Name + 'Angle'], 0)*pi/180 else
  665.     Angle := ArcTan2(Sqrt(1 - Res[0] * Res[0]), Res[0])*2;
  666.   Result := Result or isNan(Res[0]) or (Angle <> Res[0]);
  667.   if Result then Res := GetQuaternion(Angle, NewVec);
  668. end;
  669. { TPerfProfile }
  670. procedure TPerfProfile.SetFramesPerSecond(const Value: Single);
  671. begin
  672.   FFramesPerSecond := Value;
  673.   if (FMinFramesPerSecond = 0) or (FFramesPerSecond < FMinFramesPerSecond) then FMinFramesPerSecond := FFramesPerSecond;
  674.   if FFramesPerSecond > FMaxFramesPerSecond then FMaxFramesPerSecond := FFramesPerSecond;
  675. end;
  676. function TPerfProfile.GetPrimitivesPerSecond: Single;
  677. begin
  678.   Result := PrimitivesRendered * FramesPerSecond;
  679. end;
  680. procedure TPerfProfile.OnFrameStart;
  681. var BufType: TTesselationBuffer;
  682. begin
  683.   RenderTargetChanges := 0;
  684.   PrimitivesRendered  := 0;
  685.   DrawCalls           := 0;
  686.   ClearCalls          := 0;
  687.   FrustumCulledItems  := 0;
  688.   FrustumPassedItems  := 0;
  689.   SortedItems         := 0;
  690.   for BufType := Low(TTesselationBuffer) to High(TTesselationBuffer) do begin
  691.     BuffersProfile[BufType].TesselationsPerformed[True]  := 0;
  692.     BuffersProfile[BufType].BytesWritten[True]           := 0;
  693.     BuffersProfile[BufType].TesselationsPerformed[False] := 0;
  694.     BuffersProfile[BufType].BytesWritten[False]          := 0;
  695.     BuffersProfile[BufType].BufferResetsCount[True]      := 0;
  696.     BuffersProfile[BufType].BufferResetsCount[False]     := 0;
  697.     BuffersProfile[BufType].TesselationsBypassed         := 0;
  698.     BuffersProfile[BufType].BytesBypassed                := 0;
  699.   end;
  700. end;
  701. procedure TPerfProfile.OnBuffersReset;
  702. var BufType: TTesselationBuffer;
  703. begin
  704.   for BufType := Low(TTesselationBuffer) to High(TTesselationBuffer) do begin
  705.     BuffersProfile[BufType].BufferSize[True]  := 0;
  706.     BuffersProfile[BufType].BufferSize[False] := 0;
  707.   end;
  708. end;
  709. procedure TPerfProfile.BeginTiming(Timer: TTimer; PerfTimer: TPerfTimer);
  710. begin
  711.   Timer.GetInterval(TimeMarks[PerfTimer], True);
  712. end;
  713. function TPerfProfile.EndTiming(Timer: TTimer; PerfTimer: TPerfTimer): TTimeUnit;
  714. begin
  715.   Times[PerfTimer] := Timer.GetInterval(TimeMarks[PerfTimer], True);
  716.   Result := Times[PerfTimer];
  717. end;
  718. { TColliding }
  719. constructor TColliding.Create;
  720. begin
  721.   inherited;
  722.   Owner := Owner;
  723. end;
  724. destructor TColliding.Destroy;
  725. begin
  726.   Volumes := nil;
  727.   inherited;
  728. end;
  729. { TCASTRootItem }
  730. constructor TCASTRootItem.Create(AManager: TItemsManager);
  731. begin
  732.   inherited;
  733.   Collidings := TUniqueItemCollection.Create;
  734. end;
  735. destructor TCASTRootItem.Destroy;
  736. var i: Integer;
  737. begin
  738.   for i := 0 to High(Collections) do DeleteCollection(i);
  739.   inherited;
  740.   FreeAndNil(Collidings);
  741. end;
  742. function TCASTRootItem.GetItemSize(CountChilds: Boolean): Integer;
  743. var i: Integer;
  744. begin
  745.   Result := inherited GetItemSize(CountChilds);
  746.   Inc(Result, TotalCollections * SizeOf(TItemCollection));
  747.   for i := 0 to TotalCollections-1 do if Collections[i].Items <> nil then Inc(Result, Collections[i].TotalItems * SizeOf(BaseClasses.TItem));
  748. end;
  749. procedure TCASTRootItem.AddProperties(const Result: Props.TProperties);
  750. var i: Integer; Core: TBaseCore; s: string;
  751. begin
  752.   inherited;
  753.   if not Assigned(Result) then Exit;
  754.   if FManager is TBaseCore then Core := (FManager as TBaseCore) else begin
  755.     {$IFDEF LOGGING} Log.Log(ClassName + '.AddProperties: Items manager must be an instance of TBaseCore', lkError); {$ENDIF}
  756.     Exit;
  757.   end;
  758.   if (Parent = nil) and (FManager.Root = Self) then begin
  759.     Result.Add('RendererBefore backgroundClearFrame buffer',   vtBoolean, [], OnOffStr[ClearFrameBuffer   in StageSettings[poBackground].ClearFlags], '');
  760.     Result.Add('RendererBefore backgroundClearZ buffer',       vtBoolean, [], OnOffStr[ClearZBuffer       in StageSettings[poBackground].ClearFlags], '');
  761.     Result.Add('RendererBefore backgroundClearStencil buffer', vtBoolean, [], OnOffStr[ClearStencilBuffer in StageSettings[poBackground].ClearFlags], '');
  762.     Result.Add('RendererBefore backgroundClearZ value',        vtSingle,  [], FloatToStr(StageSettings[poBackground].ClearZ),             '');
  763.     Result.Add('RendererBefore backgroundClearStencil value',  vtNat,     [], IntToStr(StageSettings[poBackground].ClearStencil),        '');
  764.     AddColorProperty(Result, 'RendererBefore backgroundClearColor value', StageSettings[poBackground].ClearColor);
  765.     Result.Add('RendererBefore nearestClearFrame buffer',   vtBoolean, [], OnOffStr[ClearFrameBuffer   in StageSettings[poNearest].ClearFlags], '');
  766.     Result.Add('RendererBefore nearestClearZ buffer',       vtBoolean, [], OnOffStr[ClearZBuffer       in StageSettings[poNearest].ClearFlags], '');
  767.     Result.Add('RendererBefore nearestClearStencil buffer', vtBoolean, [], OnOffStr[ClearStencilBuffer in StageSettings[poNearest].ClearFlags], '');
  768.     Result.Add('RendererBefore nearestClearZ value',        vtSingle,  [], FloatToStr(StageSettings[poNearest].ClearZ),             '');
  769.     Result.Add('RendererBefore nearestClearStencil value',  vtNat,     [], IntToStr(StageSettings[poNearest].ClearStencil),        '');
  770.     AddColorProperty(Result, 'RendererBefore nearestClearColor value', StageSettings[poNearest].ClearColor);
  771.     Result.Add('RendererBefore postprocessClearFrame buffer',   vtBoolean, [], OnOffStr[ClearFrameBuffer   in StageSettings[poPostprocess].ClearFlags], '');
  772.     Result.Add('RendererBefore postprocessClearZ buffer',       vtBoolean, [], OnOffStr[ClearZBuffer       in StageSettings[poPostprocess].ClearFlags], '');
  773.     Result.Add('RendererBefore postprocessClearStencil buffer', vtBoolean, [], OnOffStr[ClearStencilBuffer in StageSettings[poPostprocess].ClearFlags], '');
  774.     Result.Add('RendererBefore postprocessClearZ value',        vtSingle,  [], FloatToStr(StageSettings[poPostprocess].ClearZ),             '');
  775.     Result.Add('RendererBefore postprocessClearStencil value',  vtNat,     [], IntToStr(StageSettings[poPostprocess].ClearStencil),        '');
  776.     AddColorProperty(Result, 'RendererBefore postprocessClearColor value', StageSettings[poPostprocess].ClearColor);
  777.     Result.Add('RendererSimultaneous light sources', vtInt, [], IntToStr(Core.SimultaneousLightSources), '');
  778.     Result.Add('ProcessingNumber of classes', vtInt, [], IntToStr(Core.TotalProcessingClasses), '');
  779.     for i := 0 to Core.TotalProcessingClasses-1 do begin
  780.       s := Format('ProcessingClass %D', [i]);
  781.       Result.Add(s + 'Interval, ms',     vtNat,     [], IntToStr(Round(Core.ProcessingClasses[i].Interval*1000)), '');
  782.       Result.Add(s + 'Delta time-based', vtBoolean, [], OnOffStr[pfDeltaTimeBased in Core.ProcessingClasses[i].Flags], '');
  783.       Result.Add(s + 'Ignore pause',     vtBoolean, [], OnOffStr[pfIgnorePause    in Core.ProcessingClasses[i].Flags], '');
  784.     end;
  785.   end;
  786. end;
  787. procedure TCASTRootItem.SetProperties(Properties: Props.TProperties);
  788. var
  789.   i, l, Newl: Integer; Core: TBaseCore; s: string;
  790.   NewIgnorePause, NewDeltaTimeMode: Boolean;
  791. begin
  792.   inherited;
  793.   if FManager is TBaseCore then Core := (FManager as TBaseCore) else begin
  794.     {$IFDEF LOGGING} Log.Log(ClassName + '.SetProperties: Items manager must be an instance of TBaseCore', lkError); {$ENDIF}
  795.     Exit;
  796.   end;
  797.   if (Parent = nil) and (FManager.Root = Self) then begin
  798.   if Properties.Valid('RendererBefore backgroundClearFrame buffer')   then if Properties.GetAsInteger('RendererBefore backgroundClearFrame buffer')   > 0 then
  799.     Include(StageSettings[poBackground].ClearFlags, ClearFrameBuffer)   else Exclude(StageSettings[poBackground].ClearFlags, ClearFrameBuffer);
  800.   if Properties.Valid('RendererBefore backgroundClearZ buffer')       then if Properties.GetAsInteger('RendererBefore backgroundClearZ buffer')       > 0 then
  801.     Include(StageSettings[poBackground].ClearFlags, ClearZBuffer)       else Exclude(StageSettings[poBackground].ClearFlags, ClearZBuffer);
  802.   if Properties.Valid('RendererBefore backgroundClearStencil buffer') then if Properties.GetAsInteger('RendererBefore backgroundClearStencil buffer') > 0 then
  803.     Include(StageSettings[poBackground].ClearFlags, ClearStencilBuffer) else Exclude(StageSettings[poBackground].ClearFlags, ClearStencilBuffer);
  804.   if Properties.Valid('RendererBefore nearestClearFrame buffer')   then if Properties.GetAsInteger('RendererBefore nearestClearFrame buffer')   > 0 then
  805.     Include(StageSettings[poNearest].ClearFlags, ClearFrameBuffer)   else Exclude(StageSettings[poNearest].ClearFlags, ClearFrameBuffer);
  806.   if Properties.Valid('RendererBefore nearestClearZ buffer')       then if Properties.GetAsInteger('RendererBefore nearestClearZ buffer')       > 0 then
  807.     Include(StageSettings[poNearest].ClearFlags, ClearZBuffer)       else Exclude(StageSettings[poNearest].ClearFlags, ClearZBuffer);
  808.   if Properties.Valid('RendererBefore nearestClearStencil buffer') then if Properties.GetAsInteger('RendererBefore nearestClearStencil buffer') > 0 then
  809.     Include(StageSettings[poNearest].ClearFlags, ClearStencilBuffer) else Exclude(StageSettings[poNearest].ClearFlags, ClearStencilBuffer);
  810.   if Properties.Valid('RendererBefore postprocessClearFrame buffer')   then if Properties.GetAsInteger('RendererBefore postprocessClearFrame buffer')   > 0 then
  811.     Include(StageSettings[poPostprocess].ClearFlags, ClearFrameBuffer)   else Exclude(StageSettings[poPostprocess].ClearFlags, ClearFrameBuffer);
  812.   if Properties.Valid('RendererBefore postprocessClearZ buffer')       then if Properties.GetAsInteger('RendererBefore postprocessClearZ buffer')       > 0 then
  813.     Include(StageSettings[poPostprocess].ClearFlags, ClearZBuffer)       else Exclude(StageSettings[poPostprocess].ClearFlags, ClearZBuffer);
  814.   if Properties.Valid('RendererBefore postprocessClearStencil buffer') then if Properties.GetAsInteger('RendererBefore postprocessClearStencil buffer') > 0 then
  815.     Include(StageSettings[poPostprocess].ClearFlags, ClearStencilBuffer) else Exclude(StageSettings[poPostprocess].ClearFlags, ClearStencilBuffer);
  816.     SetColorProperty(Properties, 'RendererBefore backgroundClearColor value', StageSettings[poBackground].ClearColor);
  817.     if Properties.Valid('RendererBefore backgroundClearZ value')        then StageSettings[poBackground].ClearZ             := StrToFloatDef(Properties['RendererBefore backgroundClearZ value'], 1);
  818.     if Properties.Valid('RendererBefore backgroundClearStencil value')  then StageSettings[poBackground].ClearStencil       := Longword(Properties.GetAsInteger('RendererBefore backgroundClearStencil value'));
  819.     SetColorProperty(Properties, 'RendererBefore nearestClearColor value', StageSettings[poNearest].ClearColor);
  820.     if Properties.Valid('RendererBefore nearestClearZ value')        then StageSettings[poNearest].ClearZ             := StrToFloatDef(Properties['RendererBefore nearestClearZ value'], 1);
  821.     if Properties.Valid('RendererBefore nearestClearStencil value')  then StageSettings[poNearest].ClearStencil       := Longword(Properties.GetAsInteger('RendererBefore nearestClearStencil value'));
  822.     SetColorProperty(Properties, 'RendererBefore postprocessClearColor value', StageSettings[poPostprocess].ClearColor);
  823.     if Properties.Valid('RendererBefore postprocessClearZ value')        then StageSettings[poPostprocess].ClearZ             := StrToFloatDef(Properties['RendererBefore postprocessClearZ value'], 1);
  824.     if Properties.Valid('RendererBefore postprocessClearStencil value')  then StageSettings[poPostprocess].ClearStencil       := Longword(Properties.GetAsInteger('RendererBefore postprocessClearStencil value'));
  825.     if Properties.Valid('RendererSimultaneous light sources') then Core.SimultaneousLightSources := Properties.GetAsInteger('RendererSimultaneous light sources');
  826.     if Properties.Valid('ProcessingNumber of classes') then begin
  827.       Core.TotalProcessingClasses := MaxI(1, StrToIntDef(Properties['ProcessingNumber of classes'], 1));
  828.     end;
  829.     for i := 0 to Core.TotalProcessingClasses-1 do begin
  830.       s := Format('ProcessingClass %D', [i]);
  831.       if Properties.Valid(s + 'Interval, ms') then
  832.         Core.ProcessingClasses[i].Interval := Cardinal(StrToIntDef(Properties[s + 'Interval, ms'], 30)) / 1000;
  833.       if Properties.Valid(s + 'Ignore pause') then
  834.         NewIgnorePause := Properties.GetAsInteger(s + 'Ignore pause') > 0
  835.       else
  836.         NewIgnorePause := pfIgnorePause in Core.ProcessingClasses[i].Flags;
  837.       if Properties.Valid(s + 'Delta time-based') then
  838.         NewDeltaTimeMode := Properties.GetAsInteger(s + 'Delta time-based') > 0
  839.       else
  840.         NewDeltaTimeMode := pfDeltaTimeBased in Core.ProcessingClasses[i].Flags;
  841.       Core.SetProcessingClass(i, Core.ProcessingClasses[i].Interval, NewIgnorePause, NewDeltaTimeMode);
  842.     end;
  843.   end;
  844. end;
  845. procedure TCASTRootItem.TraverseTree(Callback: TTraverseCallback);
  846.   function TraverseCallback(Item: BaseClasses.TItem): TTraverseResult;
  847.   var i: Integer;
  848.   begin
  849.     Result := Callback(Item);
  850.     if Result = trContinue then for i := 0 to Item.TotalChilds-1 do begin
  851.       {$IFDEF DEBUGMODE} Assert(Item.Childs[i] <> nil, ClassName + '.TraverseTree.Traverse: Childs[i] cannot be nil'); {$ENDIF}
  852.       Result := TraverseCallBack(Item.Childs[i]);
  853.       if Result = trStop then Exit;
  854.     end;
  855.   end;
  856. begin
  857.   if @Callback <> nil then TraverseCallback(Self);
  858. end;
  859. {procedure TCASTRootItem.IncludeItem(Item: BaseClasses.TItem; Mask: TTraverseMask);
  860. var i: Integer;
  861. begin
  862.   for i := 0 to TotalCollections-1 do if Mask = Collections[i].TraverseMask then AddToCollection(i, Item);
  863. end;
  864. procedure TCASTRootItem.ExcludeItem(Item: BaseClasses.TItem; Mask: TTraverseMask);
  865. var i: Integer;
  866. begin
  867.   for i := 0 to TotalCollections-1 do if Mask = Collections[i].TraverseMask then RemoveFromCollection(i, Item);
  868. end;}
  869. function TCASTRootItem.AddCollection(Mask: TTraverseMask): Integer;
  870. var i: Integer;
  871. begin
  872.  Result := -1;
  873.   for i := 0 to High(Collections) do if Collections[i].Items = nil then Result := i;
  874.   Inc(TotalCollections);
  875.   if Result = -1 then begin
  876.     Result := Length(Collections);
  877.     SetLength(Collections, Result+1);
  878.   end;
  879.   Collections[Result].TraverseMask := Mask;
  880.   Collections[Result].TotalItems   := 0;
  881.   SetLength(Collections[Result].Items, CollectionsCapacityStep);
  882. end;
  883. procedure TCASTRootItem.DeleteCollection(Index: Integer);
  884. begin
  885.   if (Index >= Length(Collections)) or (Collections[Index].Items = nil) then Exit;
  886.   Dec(TotalCollections);
  887.   Collections[Index].Items := nil;
  888. end;
  889. {function TCASTRootItem.AddToCollectionCallback(Item: BaseClasses.TItem): TTraverseResult;
  890. begin
  891.   AddToCollection(ModifyingCollectionIndex, Item);
  892.   Result := trContinue;
  893. end;}
  894. (*procedure TCASTRootItem.AddToCollection(CollectionIndex: Integer; Item: BaseClasses.TItem);
  895. begin
  896. {$IFDEF DEBUGMODE}
  897.   Assert((CollectionIndex < TotalCollections) and (Collections[CollectionIndex].Items <> nil), ClassName + '.AddToCollection: Invalid collection');
  898. {$ENDIF}
  899.   if (CollectionIndex < TotalCollections) and (Collections[CollectionIndex].Items <> nil) and (Item <> nil) then begin
  900.     if Length(Collections[CollectionIndex].Items) <= Collections[CollectionIndex].TotalItems then
  901.      SetLength(Collections[CollectionIndex].Items, Length(Collections[CollectionIndex].Items) + ChildsCapacityStep);
  902.     Collections[CollectionIndex].Items[Collections[CollectionIndex].TotalItems] := Item;
  903.     Inc(Collections[CollectionIndex].TotalItems);
  904.   end;
  905. end;
  906. procedure TCASTRootItem.RemoveFromCollection(CollectionIndex: Integer; Item: BaseClasses.TItem);
  907. var i: Integer;
  908. begin
  909.   {$IFDEF DEBUGMODE}
  910.   Assert((CollectionIndex < TotalCollections) and (Collections[CollectionIndex].Items <> nil), ClassName + '.RemoveFromCollection: Invalid collection');
  911.   {$ENDIF}
  912.   if (CollectionIndex < TotalCollections) and (Collections[CollectionIndex].Items <> nil) and (Item <> nil) then
  913.    for i := 0 to Collections[CollectionIndex].TotalItems-1 do if Collections[CollectionIndex].Items[i] = Item then begin
  914.      Collections[CollectionIndex].Items[i] := Collections[CollectionIndex].Items[Collections[CollectionIndex].TotalItems-1];
  915.      Collections[CollectionIndex].Items[Collections[CollectionIndex].TotalItems-1] := nil;
  916.      Dec(Collections[CollectionIndex].TotalItems);
  917.      Exit;
  918.    end;
  919. {$IFDEF DEBUGMODE}
  920.   Assert(False, ClassName + '.RemoveFromCollection: Item not found');
  921. {$ENDIF}
  922. end;    *)
  923. procedure TCASTRootItem.AddColliding(AItem: TProcessing);
  924. begin
  925.   Collidings.Add(AItem.Colliding);
  926. end;
  927. procedure TCASTRootItem.RemoveColliding(AItem: TProcessing);
  928. begin
  929.   Collidings.Remove(AItem.Colliding);
  930. end;
  931. procedure TCASTRootItem.Collide;
  932. var i, j: Integer; ColRes: Collisions.TCollisionResult; P: Pointer;
  933. begin
  934.   for i := 0 to Collidings.TotalItems-2 do for j := i+1 to Collidings.TotalItems-1 do
  935.     if Assigned(TColliding(Collidings.Items[i]).Owner) and (isProcessing in TColliding(Collidings.Items[i]).Owner.State) and
  936.        Assigned(TColliding(Collidings.Items[j]).Owner) and (isProcessing in TColliding(Collidings.Items[j]).Owner.State) then begin
  937.     ColRes := VolumeColDet(TColliding(Collidings.Items[i]).Volumes, TColliding(Collidings.Items[j]).Volumes,
  938.                            TProcessing(TColliding(Collidings.Items[i]).Owner).Transform, TProcessing(TColliding(Collidings.Items[j]).Owner).Transform);
  939.     if ColRes.Vol1 <> nil then begin
  940.       TProcessing(TColliding(Collidings.Items[i]).Owner).OnCollision(TProcessing(TColliding(Collidings.Items[j]).Owner), ColRes);
  941.       P := ColRes.Vol1;
  942.       ColRes.Vol1 := ColRes.Vol2;
  943.       ColRes.Vol2 := P;
  944.       TProcessing(TColliding(Collidings.Items[j]).Owner).OnCollision(TProcessing(TColliding(Collidings.Items[i]).Owner), ColRes);
  945.     end;
  946.   end;
  947. end;
  948. procedure TCASTRootItem.FreeChilds;
  949. var i: Integer;
  950. begin
  951.   for i := 0 to High(Collections) do Collections[i].TotalItems := 0;
  952.   Collidings.Clear;
  953.   inherited;
  954. end;
  955. function TCASTRootItem.ExtractByMaskClassInRadius(Mask: TItemFlags; AClass: CProcessing; out Items: TItems; Origin: TLocation; Range: Single): Integer;
  956. var i: Integer; SQRange: Single;
  957. begin
  958.   Result := 0;
  959.   SQRange := Sqr(Range);
  960.   if AClass.InheritsFrom(TProcessing) then begin
  961.     for i := 0 to ExtractByMaskClass(Mask, AClass, Items)-1 do
  962.       if LocationSqDistance(TProcessing(Items[i]).Location, Origin) < SQRange then begin
  963.         Items[Result] := Items[i];
  964.         Inc(Result);
  965.       end;
  966.   end else
  967.     ErrorHandler(TInvalidArgument.Create('TCASTRootItem.ExtractByMaskClassInRadius: Spatial query class argument should be TProcessing or one of its descendant class'));
  968.   {$IFDEF DEBUGMODE}
  969.   SetLength(Items, Result);
  970.   {$ENDIF}  
  971. end;
  972. function TCASTRootItem.ExtractByMaskClassInCamera(Mask: TItemFlags; AClass: CProcessing; out Items: TItems; ACamera: TCamera): Integer;
  973. var i: Integer;
  974. begin
  975.   Result := 0;
  976.   if AClass.InheritsFrom(TProcessing) then begin
  977.     for i := 0 to ExtractByMaskClass(Mask, AClass, Items)-1 do
  978.       if ACamera.IsSpehereVisible(TProcessing(Items[i]).GetAbsLocation, TProcessing(Items[i]).BoundingSphereRadius) <> fcOutside then begin
  979.         Items[Result] := Items[i];
  980.         Inc(Result);
  981.       end;
  982.   end else
  983.     ErrorHandler(TInvalidArgument.Create('TCASTRootItem.ExtractByMaskClassInRadius: Spatial query class argument should be TProcessing or one of its descendant class'));
  984.   {$IFDEF DEBUGMODE}
  985.   SetLength(Items, Result);
  986.   {$ENDIF}
  987. end;
  988. procedure TCASTRootItem.HandleMessage(const Msg: TMessage);
  989. begin
  990.   inherited;
  991.   if Msg.ClassType = ItemMsg.TAddToSceneMsg then with ItemMsg.TAddToSceneMsg(Msg) do begin
  992.     if (Item is TProcessing) and (TProcessing(Item).Colliding <> nil) then Collidings.Add(TProcessing(Item).Colliding);
  993.   end else if Msg.ClassType = ItemMsg.TReplaceMsg then with ItemMsg.TReplaceMsg(Msg) do begin
  994.     if (OldItem is TProcessing) and (TProcessing(OldItem).Colliding <> nil) then Collidings.Remove(TProcessing(OldItem).Colliding);
  995.   end else if Msg.ClassType = ItemMsg.TRemoveFromSceneMsg then with ItemMsg.TRemoveFromSceneMsg(Msg) do begin
  996.     if (Item is TProcessing) and (TProcessing(Item).Colliding <> nil) then Collidings.Remove(TProcessing(Item).Colliding);
  997.   end
  998. end;
  999. { TProcessing }
  1000. constructor TProcessing.Create(AManager: TItemsManager);
  1001. begin
  1002.   Colliding := TColliding.Create;
  1003.   Colliding.Owner := Self;
  1004.   Colliding.Volumes := nil;
  1005.   inherited;
  1006.   FState := FState + [isProcessing];
  1007.   FScale := GetVector3s(1, 1, 1);
  1008.   Orientation := GetQuaternion(0, GetVector3s(0, 1, 0));
  1009.   ProcessingClass := 0;
  1010.   BoundingBox.P1 := GetVector3s(-1, -1, -1);
  1011.   BoundingBox.P2 := GetVector3s( 1,  1,  1);
  1012. end;
  1013. destructor TProcessing.Destroy;
  1014. begin
  1015.   if Assigned(FManager) and Assigned(FManager.Root) then (FManager.Root as TCASTRootItem).RemoveColliding(Self);
  1016.   FreeAndNil(Colliding);
  1017.   inherited;
  1018. end;
  1019. function TProcessing.SetChild(Index: Integer; AItem: BaseClasses.TItem): BaseClasses.TItem;
  1020. begin
  1021.   Result := inherited SetChild(Index, AItem);
  1022.   if (Result <> nil) and (AItem is TProcessing) then (AItem as TProcessing).InvalidateTransform;
  1023. end;
  1024. procedure TProcessing.OnCollision(Item: TProcessing; const ColRes: Collisions.TCollisionResult);
  1025. begin
  1026.   {$IFDEF LOGGING}
  1027. //  Log.Log('Collision "' + Name +'" with "' + Item.GetFullName + '"');
  1028.   {$ENDIF}
  1029. end;
  1030. procedure TProcessing.AddProperties(const Result: Props.TProperties);
  1031. var i: Integer; Str: string;
  1032. begin
  1033.   inherited;
  1034.   if not Assigned(Result) then Exit;
  1035. //  Result.AddEnumerated('Processing class', [], ProcessingClass+1, (FManager as TBaseCore).GetProcClassesEnum);
  1036.   AddVector4sProperty(Result, 'TransformLocation', Location);
  1037.   AddQuaternionProperty(Result, 'TransformOrientation', FOrientation);
  1038. {  Angle := ArcTan2(Sqrt(1 - Orientation[0] * Orientation[0]), Orientation[0])*2 * 180/pi;
  1039.   Str := 'TransformOrientation';
  1040.   Result.Add(Str,            vtString, [poReadOnly], Format('(%3.3F, (%3.3F, %3.3F, %3.3F))', [Angle, Orientation[1], Orientation[2], Orientation[3]]), '');
  1041.   Result.Add(Str + 'Angle', vtSingle, [], FloatToStr(Angle), '');
  1042.   Result.Add(Str + 'X',     vtSingle, [], FloatToStr(Orientation[1]), '');
  1043.   Result.Add(Str + 'Y',     vtSingle, [], FloatToStr(Orientation[2]), '');
  1044.   Result.Add(Str + 'Z',     vtSingle, [], FloatToStr(Orientation[3]), '');}
  1045.   AddVector3sProperty(Result, 'TransformScale', Scale);
  1046.   Result.Add('BoundsTotal volumes', vtInt, [], IntToStr(Length(Colliding.Volumes)), '');
  1047.   for i := 0 to High(Colliding.Volumes) do begin
  1048.     Str := 'BoundsVolume #' + IntToStr(i+1) + '';
  1049.     Result.AddEnumerated(Str + 'Kind', [], Ord(Colliding.Volumes[i].VolumeKind), VolumeKindsEnum);
  1050.     AddVector3sProperty(Result, Str + 'Offset', Colliding.Volumes[i].Offset);
  1051.     AddVector3sProperty(Result, 'BoundsVolume #' + IntToStr(i+1) + 'Dimensions', Colliding.Volumes[i].Dimensions);
  1052.   end;
  1053. end;
  1054. procedure TProcessing.SetProperties(Properties: Props.TProperties);
  1055. var i, TotalVolumes: Integer; Str: string; 
  1056. begin
  1057.   inherited;
  1058.   if SetVector4sProperty(Properties, 'TransformLocation', FLocation) then SetLocation(FLocation);
  1059.   if SetQuaternionProperty(Properties, 'TransformOrientation', FOrientation) then SetOrientation(FOrientation);
  1060.   if SetVector3sProperty(Properties, 'TransformScale', FScale) then SetScale(FScale);
  1061.   if Properties.Valid('BoundsTotal volumes') then begin
  1062.     TotalVolumes := Length(Colliding.Volumes);
  1063.     SetLength(Colliding.Volumes, StrToIntDef(Properties['BoundsTotal volumes'], Length(Colliding.Volumes)));
  1064.     if (TotalVolumes =  0) and (High(Colliding.Volumes) >= 0) then (FManager.Root as TCASTRootItem).AddColliding(Self);
  1065.     if (TotalVolumes <> 0) and (High(Colliding.Volumes)  < 0) then (FManager.Root as TCASTRootItem).RemoveColliding(Self);
  1066.     for i := TotalVolumes to High(Colliding.Volumes) do begin
  1067.       Colliding.Volumes[i].VolumeKind := bvkOOBB;
  1068.       Colliding.Volumes[i].Offset     := ScaleVector3s(AddVector3s(BoundingBox.P2, BoundingBox.P1), 0.5);
  1069.       Colliding.Volumes[i].Dimensions := ScaleVector3s(SubVector3s(BoundingBox.P2, BoundingBox.P1), 0.5);
  1070.     end;
  1071.   end;
  1072.   for i := 0 to High(Colliding.Volumes) do begin
  1073.     Str := 'BoundsVolume #' + IntToStr(i+1) + '';
  1074.     if Properties.Valid(Str + 'Kind') then Colliding.Volumes[i].VolumeKind := TBoundingVolumeKind(Properties.GetAsInteger(Str + 'Kind'));
  1075.     SetVector3sProperty(Properties, Str + 'Offset', Colliding.Volumes[i].Offset);
  1076.     SetVector3sProperty(Properties, 'BoundsVolume #' + IntToStr(i+1) + 'Dimensions', Colliding.Volumes[i].Dimensions);
  1077.   end;
  1078. end;
  1079. function TProcessing.GetAbsLocation: TVector3s;
  1080. begin
  1081.   Result.X := Transform._41; Result.Y := FTransform._42; Result.Z := FTransform._43;
  1082. end;
  1083. function TProcessing.GetAbsOrientation: TQuaternion;
  1084. // Multiply orientation quaternions upward to first non-processing parent
  1085. var ParItem: BaseClasses.TItem;
  1086. begin
  1087.   Result := Orientation;
  1088.   ParItem := Parent;
  1089.   while ParItem is TDummyItem do ParItem := ParItem.Parent;                        // Skip dummy items
  1090.   if ParItem is TProcessing then Result := MulQuaternion(TProcessing(ParItem).GetAbsOrientation, Result);
  1091. end;
  1092. procedure TProcessing.SetTransform(const ATransform: TMatrix4s);
  1093. begin
  1094.   FTransform := ATransform;
  1095.   TransformValid := True;
  1096. end;
  1097. function TProcessing.GetTransform: TMatrix4s;
  1098. begin
  1099.   if not TransformValid then ComputeTransform;
  1100.   Result := FTransform;
  1101. end;                     
  1102. function TProcessing.GetLocation: TVector4s;
  1103. begin
  1104.   Result := FLocation;
  1105. end;
  1106. procedure TProcessing.SetLocation(ALocation: TVector4s);
  1107. begin
  1108.   FLocation := ALocation;
  1109.   InvalidateTransform;
  1110. end;
  1111. function TProcessing.GetPosition: TVector3s;
  1112. begin
  1113.   Result := FLocation.XYZ;
  1114. end;
  1115. procedure TProcessing.SetPosition(const Value: TVector3s);
  1116. begin
  1117.   SetLocation(GetVector4s(Value.X, Value.Y, Value.Z, FLocation.W));
  1118. end;
  1119. function TProcessing.GetOrientation: TQuaternion;
  1120. begin
  1121.   Result := FOrientation;
  1122. end;
  1123. procedure TProcessing.SetOrientation(AOrientation: TQuaternion);
  1124. begin
  1125.   FOrientation := AOrientation;
  1126.   InvalidateTransform;
  1127. end;
  1128. function TProcessing.GetScale: TVector3s;
  1129. begin
  1130.   Result := FScale;
  1131. end;
  1132. procedure TProcessing.SetScale(const Value: TVector3s);
  1133. begin
  1134.   FScale := Value;
  1135.   InvalidateTransform;
  1136. end;
  1137. procedure TProcessing.InvalidateTransform;
  1138. {  procedure InvalidateChilds(Item: BaseClasses.TItem);
  1139.   var i: Integer;
  1140.   begin
  1141.     for i := 0 to Item.TotalChilds-1 do begin
  1142.       if (Item.Childs[i] is TProcessing) then begin
  1143.         TProcessing(Item.Childs[i]).TransformValid := False;
  1144.         InvalidateChilds(Item.Childs[i]);
  1145.       end;
  1146.       if (Item.Childs[i] is TDummyItem) then InvalidateChilds(Item.Childs[i]);
  1147.     end;
  1148.   end;}
  1149.   procedure InvalidateChilds(Item: BaseClasses.TItem);
  1150.   var i: Integer;
  1151.   begin
  1152.     for i := 0 to Item.TotalChilds-1 do
  1153.       if (Item.Childs[i] is TProcessing) then
  1154.         TProcessing(Item.Childs[i]).InvalidateTransform else
  1155.           if (Item.Childs[i] is TDummyItem) then InvalidateChilds(Item.Childs[i]);
  1156.   end;
  1157. begin
  1158.   TransformValid := False;
  1159.   InvalidateChilds(Self);
  1160. end;
  1161. procedure TProcessing.ComputeTransform;
  1162. var ParItem: BaseClasses.TItem;
  1163. begin
  1164.   TranslationMatrix4s(FTransform, FLocation.X, FLocation.Y, FLocation.Z);
  1165.   Matrix4sByQuat(FTransform, FOrientation);
  1166.   MulMatrix4s(FTransform, ScaleMatrix4s(FScale.X, FScale.Y, FScale.Z), FTransform);
  1167.   ParItem := Parent;
  1168.   while ParItem is TDummyItem do ParItem := ParItem.Parent;                        // Skip dummy items
  1169.   if ParItem is TProcessing then FTransform := MulMatrix4s(FTransform, TProcessing(ParItem).Transform);
  1170.   TransformValid := True;
  1171. end;
  1172. function TProcessing.GetForwardVector: TVector3s;
  1173. begin
  1174.   Result := GetVector3s(Transform._31, Transform._32, Transform._33);
  1175. end;
  1176. function TProcessing.GetRightVector: TVector3s;
  1177. begin
  1178.   Result := GetVector3s(Transform._11, Transform._12, Transform._13);
  1179. end;
  1180. function TProcessing.GetUpVector: TVector3s;
  1181. begin
  1182.   Result := GetVector3s(Transform._21, Transform._22, Transform._23);
  1183. end;
  1184. function TProcessing.GetDimensions: TVector3s;
  1185. begin
  1186.   ScaleVector3s(Result, SubVector3s(BoundingBox.P2, BoundingBox.P1), 0.5);
  1187. end;
  1188. function TProcessing.GetBoundingSphereRadius: Single;
  1189. var D: Single;
  1190. begin
  1191.   D := MaxS(SqrMagnitude(BoundingBox.P1), SqrMagnitude(BoundingBox.P2));
  1192.   Result := Sqrt(D);
  1193. end;
  1194. function TProcessing.ModelToWorld(const APoint: TVector3s): TVector3s;
  1195. begin
  1196.   Result := Transform4Vector33s(Transform, APoint);
  1197. end;
  1198. function TProcessing.WorldToModel(const APoint: TVector3s): TVector3s;
  1199. begin
  1200.   Result := Transform4Vector33s(InvertAffineMatrix4s(Transform), APoint);
  1201. end;
  1202. { TCamera }
  1203. constructor TCamera.Create(AManager: TItemsManager);
  1204. var i: Integer;
  1205. begin
  1206.   inherited;
  1207.   InitProjMatrix(1, 100000, 90, 1);
  1208.   FCurrentAspectRatio := FAspectRatio;
  1209.   RenderTargetIndex   := -1;
  1210.   FState    := FState + [isVisible];
  1211.   GroupMask := gmDefault;
  1212.   for i := 0 to MaxClipPlanes-1 do ClipPlanes[i] := nil;
  1213.   DefaultFillMode := fmSolid;
  1214.   DefaultCullMode := cmCCW;
  1215.   ClearSettings.ClearFlags := [ClearFrameBuffer, ClearZBuffer];
  1216.   ClearSettings.ClearColor.C := 0;
  1217.   ClearSettings.ClearZ       := 1;
  1218. end;
  1219. destructor TCamera.Destroy;
  1220. var i: Integer;
  1221. begin
  1222.   for i := 0 to MaxClipPlanes-1 do if Assigned(ClipPlanes[i]) then FreeMem(ClipPlanes[i]);
  1223.   inherited;
  1224. end;
  1225. procedure TCamera.AddProperties(const Result: Props.TProperties);
  1226. var i: Integer;
  1227. begin
  1228.   inherited;
  1229.   if not Assigned(Result) then Exit;
  1230. //  Result.Add('Default', vtBoolean, [], OnOffStr[Default], '');
  1231.   for i := 0 to PassGroupsCount-1 do Result.Add(Format('Pass groupsGroup %D', [i+1]), vtBoolean, [], OnOffStr[i in GroupMask], '');
  1232.   Result.Add('RenderWidth',  vtInt, [poReadonly, poDerivative], IntToStr(RenderWidth),  '');
  1233.   Result.Add('RenderHeight', vtInt, [poReadonly, poDerivative], IntToStr(RenderHeight), '');
  1234.   Result.AddEnumerated('RenderColor format', [poReadonly, poDerivative], ColorFormat, PixelFormatsEnum);
  1235.   Result.AddEnumerated('RenderDepth format', [poReadonly, poDerivative], DepthFormat, PixelFormatsEnum);
  1236.   Result.Add('RenderCurrent aspect ratio', vtSingle,  [poReadonly, poDerivative], FloatToStr(CurrentAspectRatio),  '');
  1237.   Result.Add('RenderLOD bias', vtSingle,  [], FloatToStr(LODBias),  '');
  1238.   // Render to texture related properties
  1239.   Result.Add('RenderRender targetWidth',  vtInt, [], IntToStr(RenderTargetWidth),  '');
  1240.   Result.Add('RenderRender targetHeight', vtInt, [], IntToStr(RenderTargetHeight), '');
  1241.   Result.AddEnumerated('RenderRender targetColor format',   [], FRTColorFormat, PixelFormatsEnum);
  1242.   Result.AddEnumerated('RenderRender targetDepth format',   [], FRTDepthFormat, PixelFormatsEnum);
  1243.   Result.Add('RenderRender targetFrame skip', vtInt,        [], IntToStr(FrameSkip), '');
  1244.   Result.Add('RenderRender targetDepth texture', vtBoolean, [], OnOffStr[IsDepthTexture], '');
  1245.   Result.Add('ProjectionOrthographic', vtBoolean, [], OnOffStr[FOrthographic], '');
  1246.   Result.Add('ProjectionZ near',         vtSingle,  [], FloatToStr(FZNear),              '');
  1247.   Result.Add('ProjectionZ far',          vtSingle,  [], FloatToStr(FZFar),               '');
  1248.   Result.Add('ProjectionHorizontal FoV', vtInt,     [], IntToStr(Round(FHFoV * RadToDeg)), '0-180');
  1249.   Result.Add('ProjectionVisible width',  vtSingle,  [], FloatToStr(FWidth), '');
  1250.   Result.Add('ProjectionAspect ratio',   vtSingle,  [], FloatToStr(FAspectRatio),        '0.125-8');
  1251.   Result.Add('ClearFrame buffer',        vtBoolean, [], OnOffStr[ClearFrameBuffer   in ClearSettings.ClearFlags], '');
  1252.   Result.Add('ClearZ buffer',            vtBoolean, [], OnOffStr[ClearZBuffer       in ClearSettings.ClearFlags], '');
  1253.   Result.Add('ClearStencil buffer',      vtBoolean, [], OnOffStr[ClearStencilBuffer in ClearSettings.ClearFlags], '');
  1254.   AddColorProperty(Result, 'ClearColor value', ClearSettings.ClearColor);
  1255.   Result.Add('ClearZ value',             vtSingle,  [], FloatToStr(ClearSettings.ClearZ),            '');
  1256.   Result.Add('ClearStencil value',       vtNat,     [], IntToStr(ClearSettings.ClearStencil),        '');
  1257.   Result.AddEnumerated('RenderDefault face culling', [], DefaultCullMode, CameraCullModesEnum);
  1258.   Result.AddEnumerated('RenderDefault fill mode',    [], DefaultFillMode, CameraFillModesEnum);
  1259. end;
  1260. procedure TCamera.SetProperties(Properties: Props.TProperties);
  1261. var i: Integer;
  1262. begin
  1263.   inherited;
  1264. //  if Properties.Valid('Default') then Default := Properties.GetAsInteger('Default') > 0;
  1265.   for i := 0 to PassGroupsCount-1 do
  1266.     if Properties.Valid(Format('Pass groupsGroup %D', [i+1])) then
  1267.       if Properties.GetAsInteger(Format('Pass groupsGroup %D', [i+1])) > 0 then
  1268.         GroupMask := GroupMask + [i] else
  1269.           GroupMask := GroupMask - [i];
  1270.   if Properties.Valid('RenderRender targetWidth')  then RenderTargetWidth  := StrToIntDef(Properties['RenderRender targetWidth'],  0);
  1271.   if Properties.Valid('RenderRender targetHeight') then RenderTargetHeight := StrToIntDef(Properties['RenderRender targetHeight'], 0);
  1272.   if Properties.Valid('RenderRender targetColor format')  then FRTColorFormat    := Properties.GetAsInteger('RenderRender targetColor format');
  1273.   if Properties.Valid('RenderRender targetDepth format')  then FRTDepthFormat    := Properties.GetAsInteger('RenderRender targetDepth format');
  1274.   if Properties.Valid('RenderRender targetFrame skip')    then FrameSkip         := StrToIntDef(Properties['RenderRender targetFrame skip'], 0);
  1275.   if Properties.Valid('RenderRender targetDepth texture') then IsDepthTexture      := Properties.GetAsInteger('RenderRender targetDepth texture') > 0;
  1276.   if Properties.Valid('ProjectionOrthographic') then FOrthographic := Properties.GetAsInteger('ProjectionOrthographic') > 0;
  1277.   if Properties.Valid('ProjectionZ near')         then FZNear := StrToFloatDef(Properties['ProjectionZ near'],        1);
  1278.   if Properties.Valid('ProjectionZ far')          then FZFar  := StrToFloatDef(Properties['ProjectionZ far'],         100000);
  1279.   if Properties.Valid('ProjectionHorizontal FoV') then FHFoV  := StrToIntDef(Properties['ProjectionHorizontal FoV'], 90) * DegToRad;
  1280.   if Properties.Valid('ProjectionVisible width')  then FWidth := StrToFloatDef(Properties['ProjectionVisible width'], 0);
  1281.   if Properties.Valid('ProjectionAspect ratio') then begin
  1282.     FAspectRatio := StrToFloatDef(Properties['ProjectionAspect ratio'], 1);
  1283.     FCurrentAspectRatio := FAspectRatio;
  1284.   end;
  1285.   if Properties.Valid('RenderLOD bias') then LODBias := StrToFloatDef(Properties['RenderLOD bias'], 0);
  1286.   if Properties.Valid('ClearFrame buffer')   then if Properties.GetAsInteger('ClearFrame buffer')   > 0 then
  1287.     Include(ClearSettings.ClearFlags, ClearFrameBuffer) else Exclude(ClearSettings.ClearFlags, ClearFrameBuffer);
  1288.   if Properties.Valid('ClearZ buffer')       then if Properties.GetAsInteger('ClearZ buffer')       > 0 then
  1289.     Include(ClearSettings.ClearFlags, ClearZBuffer) else Exclude(ClearSettings.ClearFlags, ClearZBuffer);
  1290.   if Properties.Valid('ClearStencil buffer') then if Properties.GetAsInteger('ClearStencil buffer') > 0 then
  1291.     Include(ClearSettings.ClearFlags, ClearStencilBuffer) else Exclude(ClearSettings.ClearFlags, ClearStencilBuffer);
  1292.   SetColorProperty(Properties, 'ClearColor value', ClearSettings.ClearColor);
  1293.   if Properties.Valid('ClearZ value')        then ClearSettings.ClearZ       := StrToFloatDef(Properties['ClearZ value'], 1);
  1294.   if Properties.Valid('ClearStencil value')  then ClearSettings.ClearStencil := Longword(Properties.GetAsInteger('ClearStencil value'));
  1295.   if Properties.Valid('RenderDefault face culling') then DefaultCullMode := Properties.GetAsInteger('RenderDefault face culling');
  1296.   if Properties.Valid('RenderDefault fill mode')    then DefaultFillMode := Properties.GetAsInteger('RenderDefault fill mode');
  1297.   InitProjMatrix(FZNear, FZFar, FHFoV, FAspectRatio);
  1298. end;
  1299. procedure TCamera.InvalidateTransform;
  1300. begin
  1301.   inherited;
  1302.   ViewValid := False;
  1303. end;
  1304. procedure TCamera.ComputeViewMatrix;
  1305. begin
  1306. {  FViewMatrix     :=  ExpandMatrix3s(GetTransposedMatrix3s(CutMatrix3s(Transform)));
  1307.   Pos := GetAbsLocation;
  1308.   FViewMatrix._41 := -DotProductVector3s(FTransform.ViewRight,   Pos);
  1309.   FViewMatrix._42 := -DotProductVector3s(FTransform.ViewUp,      Pos);
  1310.   FViewMatrix._43 := -DotProductVector3s(FTransform.ViewForward, Pos);}
  1311.   FInvViewMatrix := Transform;
  1312.   FViewMatrix := InvertAffineMatrix4s(FInvViewMatrix);
  1313.   MulMatrix4s(FTotalMatrix, FViewMatrix, ProjMatrix);
  1314.   ComputeFrustumPlanes;
  1315.   ViewValid := True;
  1316. end;
  1317. procedure TCamera.InitProjMatrix(AZNear, AZFar, AHFoV, AAspectRatio: Single);
  1318. var w, h, q: Single; Cen: TVector3s;
  1319. begin
  1320.   FZNear       := AZNear;
  1321.   FZFar        := AZFar;
  1322.   FHFoV        := AHFoV;
  1323.   AspectRatio  := AAspectRatio;
  1324.   FillChar(FProjMatrix, SizeOf(FProjMatrix), 0);
  1325.   if FOrthographic then begin
  1326.     FProjMatrix := IdentityMatrix4s;
  1327.     w := FWidth;
  1328.     h := w * CurrentAspectRatio;
  1329. //    FProjMatrix.m[0, 0] := 2/w; FProjMatrix.m[1, 1] := 2/h; FProjMatrix.m[2, 2] := 2/(FZFar - FZNear);
  1330. //    MulMatrix4s(FProjMatrix, ScaleMatrix4s(2/w, 2/h, 2/(FZFar - FZNear)), TranslationMatrix4s(-GetAbsLocation.x, -GetAbsLocation.y, -GetAbsLocation.z));
  1331.     Cen := GetAbsLocation;
  1332. //    MulMatrix4s(FProjMatrix, TranslationMatrix4s(-Cen.x, -Cen.y, -Cen.z), ScaleMatrix4s(2/w, 2/h, 2/(FZFar - FZNear)));
  1333.     FProjMatrix := ScaleMatrix4s(2/w, 2/h, 2/(FZFar - FZNear));
  1334.   end else begin
  1335.     w := Cos(FHFov * 0.5) / Sin(FHFov * 0.5);
  1336.     h := w * CurrentAspectRatio;
  1337.     q := FZFar / (FZFar - FZNear);
  1338.     FProjMatrix.m[0, 0] := w; FProjMatrix.m[1, 1] := h; FProjMatrix.m[2, 2] := q;
  1339.     FProjMatrix.m[3, 2] := -q*FZNear; FProjMatrix.m[2, 3] := 1;
  1340.   end;
  1341. //  ViewValid := False;
  1342. end;
  1343. procedure TCamera.InitOrthoProjMatrix(AZNear, AZFar, VisibleWidth, AAspectRatio: Single);
  1344. begin
  1345.   FOrthographic := True;
  1346.   FWidth := VisibleWidth;
  1347.   InitProjMatrix(AZNear, AZFar, FHFoV, AAspectRatio);
  1348. end;
  1349. procedure TCamera.SetClearState(AClearFlags: TClearFlagsSet; AClearColor: BaseTypes.TColor; AClearZ: Single; AClearStencil: Cardinal);
  1350. begin
  1351.   ClearSettings.ClearFlags   := AClearFlags;
  1352.   ClearSettings.ClearColor   := AClearColor;
  1353.   ClearSettings.ClearZ       := AClearZ;
  1354.   ClearSettings.ClearStencil := AClearStencil;
  1355. end;
  1356. procedure TCamera.SetScreenDimensions(Width, Height: Integer; AdjustAspectRatio: Boolean);
  1357. begin
  1358.   if (Width = FRenderWidth) and (Height = FRenderHeight) then Exit;
  1359.   FRenderWidth  := Width;
  1360.   FRenderHeight := Height;
  1361.   if AdjustAspectRatio then begin
  1362.     FCurrentAspectRatio := Width / Height * AspectRatio;
  1363.   end;
  1364.   InitProjMatrix(FZNear, FZFar, FHFoV, FAspectRatio);
  1365. end;
  1366. procedure TCamera.Rotate(XA, YA, ZA: Single);
  1367. begin
  1368.   Orientation := MulQuaternion(GetQuaternion(XA, RightVector), MulQuaternion(GetQuaternion(YA, UpVector), MulQuaternion(GetQuaternion(ZA, ForwardVector), Orientation)));
  1369. end;
  1370. procedure TCamera.Move(XD, YD, ZD: Single);
  1371. begin
  1372. {  if Core.Renderer.MainCamera is TLookAtCamera then begin
  1373.     with (Core.Renderer.MainCamera as TLookAtCamera) do
  1374.       LookTarget := AddVector3s(LookTarget, AddVector3s(ScaleVector3s(RightVector, -(NewMouseX - LastMouseX)*0.10), ScaleVector3s(UpVector, (NewMouseY - LastMouseY)*0.10)));}
  1375.   Position := AddVector3s(Position, AddVector3s(AddVector3s(ScaleVector3s(RightVector, XD), ScaleVector3s(UpVector, YD)), ScaleVector3s(ForwardVector, ZD)));
  1376. end;
  1377. function TCamera.GetPickRay(ScreenX, ScreenY: Single): TVector3s;
  1378. var d: Single;
  1379. begin
  1380.   d := 0.5*RenderWidth / Sin(FHFoV/2)*Cos(FHFoV/2);
  1381.   Result.X := -0.5*RenderWidth  + ScreenX;
  1382.   if RenderHeight > epsilon then
  1383.     Result.Y := (0.5*RenderHeight - ScreenY)*RenderWidth/RenderHeight/CurrentAspectRatio else
  1384.       Result.Y := 0;
  1385.   Result.Z := d;
  1386. end;
  1387. function TCamera.GetPickRayInWorld(ScreenX, ScreenY: Single): TVector3s;
  1388. begin
  1389.   Transform3Vector3s(Result, CutMatrix3s(InvertAffineMatrix4s(ViewMatrix)), GetPickRay(ScreenX, ScreenY));
  1390. end;
  1391. function TCamera.Project(const Vec: TVector3s): TVector4s;
  1392. var TRHW: Single;
  1393. begin
  1394.   Result := Transform4Vector3s(TotalMatrix, Vec);
  1395.   TRHW := 1/Result.W;
  1396.   Result.X := RenderWidth  shr 1 + Result.X * (RenderWidth  shr 1) * TRHW;
  1397.   Result.Y := RenderHeight shr 1 - Result.Y * (RenderHeight shr 1) * TRHW;
  1398. //  Result.Z := (ZFar/(ZFar-ZNear))*(1-ZNear/(Result.Z));          // ToFix: Optimize it
  1399. end;
  1400. function TCamera.GetViewMatrix: TMatrix4s;
  1401. begin
  1402.   if not ViewValid then ComputeViewMatrix;
  1403.   Result := FViewMatrix;
  1404. end;
  1405. procedure TCamera.SetViewMatrix(const Value: TMatrix4s);
  1406. begin
  1407.   FViewMatrix := Value;
  1408.   FInvViewMatrix := InvertAffineMatrix4s(FViewMatrix);;
  1409.   MulMatrix4s(FTotalMatrix, FViewMatrix, ProjMatrix);
  1410.   ComputeFrustumPlanes;
  1411.   ViewValid := True;
  1412. end;
  1413. function TCamera.GetInvViewMatrix: TMatrix4s;
  1414. begin
  1415.   if not ViewValid then ComputeViewMatrix;
  1416.   Result := FInvViewMatrix;
  1417. end;
  1418. function TCamera.GetTotalMatrix: TMatrix4s;
  1419. begin
  1420.   if not ViewValid then ComputeViewMatrix;
  1421.   Result := FTotalMatrix;
  1422. end;
  1423. function TCamera.GetViewOrigin: TVector3s;
  1424. begin
  1425.   Result := GetVector3s(InvViewMatrix._41, InvViewMatrix._42, InvViewMatrix._43);
  1426. end;
  1427. function TCamera.GetLookDir: TVector3s;
  1428. begin
  1429.   Result := GetVector3s(InvViewMatrix._31, InvViewMatrix._32, InvViewMatrix._33);
  1430. end;
  1431. function TCamera.GetRightDir: TVector3s;
  1432. begin
  1433.   Result := GetVector3s(InvViewMatrix._11, InvViewMatrix._12, InvViewMatrix._13);
  1434. end;
  1435. function TCamera.GetUpDir: TVector3s;
  1436. begin
  1437.   Result := GetVector3s(InvViewMatrix._21, InvViewMatrix._22, InvViewMatrix._23);
  1438. end;
  1439. procedure TCamera.SetAspectRatio(const Value: Single);
  1440. begin
  1441.   FAspectRatio := Value;
  1442.   if FRenderHeight <> 0 then
  1443.     FCurrentAspectRatio := FRenderWidth / FRenderHeight * FAspectRatio
  1444.       else FCurrentAspectRatio := 0;
  1445. end;
  1446. procedure TCamera.ComputeFrustumPlanes;
  1447. var i: Integer; M: Tmatrix4s;
  1448. begin
  1449.   M := FTotalMatrix;
  1450.   // Left clipping plane
  1451.   FFrustumPlanes[fpLeft].a := M._14 + M._11;
  1452.   FFrustumPlanes[fpLeft].b := M._24 + M._21;
  1453.   FFrustumPlanes[fpLeft].c := M._34 + M._31;
  1454.   FFrustumPlanes[fpLeft].d := M._44 + M._41;
  1455.   // Right clipping plane
  1456.   FFrustumPlanes[fpRight].a := M._14 - M._11;
  1457.   FFrustumPlanes[fpRight].b := M._24 - M._21;
  1458.   FFrustumPlanes[fpRight].c := M._34 - M._31;
  1459.   FFrustumPlanes[fpRight].d := M._44 - M._41;
  1460.   // Top clipping plane
  1461.   FFrustumPlanes[fpTop].a := M._14 - M._12;
  1462.   FFrustumPlanes[fpTop].b := M._24 - M._22;
  1463.   FFrustumPlanes[fpTop].c := M._34 - M._32;
  1464.   FFrustumPlanes[fpTop].d := M._44 - M._42;
  1465.   // Bottom clipping plane
  1466.   FFrustumPlanes[fpBottom].a := M._14 + M._12;
  1467.   FFrustumPlanes[fpBottom].b := M._24 + M._22;
  1468.   FFrustumPlanes[fpBottom].c := M._34 + M._32;
  1469.   FFrustumPlanes[fpBottom].d := M._44 + M._42;
  1470.   // Near clipping plane
  1471.   FFrustumPlanes[fpNear].a := M._13;
  1472.   FFrustumPlanes[fpNear].b := M._23;
  1473.   FFrustumPlanes[fpNear].c := M._33;
  1474.   FFrustumPlanes[fpNear].d := M._43;
  1475.   // Far clipping plane
  1476.   FFrustumPlanes[fpFar].a := M._14 - M._13;
  1477.   FFrustumPlanes[fpFar].b := M._24 - M._23;
  1478.   FFrustumPlanes[fpFar].c := M._34 - M._33;
  1479.   FFrustumPlanes[fpFar].d := M._44 - M._43;
  1480.   // Normalize
  1481.   for i := Ord(Low(TFrustumPlane)) to Ord(High(TFrustumPlane)) do NormalizePlane(FFrustumPlanes[TFrustumPlane(i)]);
  1482. end;
  1483. procedure TCamera.OnApply(const OldCamera: TCamera);
  1484. begin
  1485.   ClipPlanes[0] := nil;
  1486. end;
  1487. function TCamera.IsSpehereVisible(const Center: TVector3s; Radius: Single): TFrustumCheckResult;
  1488. var i: Integer; d: Single;
  1489. begin
  1490.   if not ViewValid then ComputeViewMatrix;
  1491.   Result := fcOutside;
  1492.   for i := Ord(Low(TFrustumPlane)) to Ord(High(TFrustumPlane)) do begin
  1493.     d := DotProductVector3s(FFrustumPlanes[TFrustumPlane(i)].Normal, Center) + FFrustumPlanes[TFrustumPlane(i)].D;
  1494.     if d < -Radius then Exit;                                     // Sphere is out of frustum
  1495.     if Abs(d) < Radius then begin                                 // Sphere intersects frustum
  1496.       Result := fcPartially; Exit;
  1497.     end;
  1498.   end;
  1499.   Result := fcInside;                                             // Sphere completely inside frustum
  1500. end;
  1501. { TBaseCore }
  1502. procedure TBaseCore.SetTimer(const Value: Timer.TTimer);
  1503. begin
  1504.   Assert(Assigned(Value), 'TCore.SetTimer: Timer should be defined');
  1505.   if Assigned(FTimer) then RemoveSubsystem(FTimer);
  1506.   if (FTimer = DefaultTimer) and (Value <> DefaultTimer) then FreeAndNil(DefaultTimer);
  1507.   FTimer := Value;
  1508.   if Assigned(FTimer) then AddSubsystem(FTimer);
  1509. end;
  1510. procedure TBaseCore.SetTotalProcessingClasses(const Value: Integer);
  1511. var l, i: Integer;
  1512. begin
  1513.   l := Length(ProcessingClasses);
  1514.   for i := l-1 downto Value do
  1515.     FTimer.RemoveRecurringEvent(ProcessingClasses[i].TimerEventID);
  1516.   SetLength(ProcessingClasses, Value);
  1517.   for i := l to Value-1 do begin
  1518.     ProcessingClasses[i].Interval := DefaultProcessingInterval;
  1519.     ProcessingClasses[i].Flags    := [];
  1520.     ProcessingClasses[i].TimerEventID := Timer.SetRecurringEvent(ProcessingClasses[i].Interval, ProcessingEvent, i);
  1521.   end;
  1522. end;
  1523. procedure TBaseCore.ProcessDeltaTimeBased(const DeltaTime: TTimeUnit);
  1524. var i, j: Integer;
  1525. begin
  1526.   for j := 0 to TotalProcessingItems-1 do begin
  1527.     Assert(ProcessingItems[j] is TBaseProcessing, ProcessingItems[j].Name + ' is not a descendant of TBaseProcessing');
  1528.     i := TBaseProcessing(ProcessingItems[j]).ProcessingClass;
  1529.     if (i >= 0) and (pfDeltaTimeBased in ProcessingClasses[i].Flags) and
  1530.        (not Paused or (pfIgnorePause in ProcessingClasses[i].Flags)) then
  1531.       TBaseProcessing(ProcessingItems[j]).Process(DeltaTime);
  1532.   end;
  1533. end;
  1534. procedure TBaseCore.ProcessingEvent(EventID: Integer; const ErrorDelta: TTimeUnit);
  1535. var j: Integer;
  1536. begin
  1537.   if Paused and not (pfIgnorePause in ProcessingClasses[EventID].Flags) then Exit;
  1538.   for j := 0 to TotalProcessingItems-1 do begin
  1539.     Assert(ProcessingItems[j] is TBaseProcessing, ProcessingItems[j].Name + ' is not a descendant of TBaseProcessing');
  1540.     if TBaseProcessing(ProcessingItems[j]).ProcessingClass = EventID then
  1541.       TBaseProcessing(ProcessingItems[j]).Process((ProcessingClasses[EventID].Interval + ErrorDelta) * TimeScale);
  1542.   end;
  1543. end;
  1544. procedure TBaseCore.OnDestroy;
  1545. begin
  1546.   Log.Log('Engine shut down');
  1547.   FreeAndNil(FTesselatorManager);
  1548.   FreeAndNil(FSharedTesselators);
  1549.   FreeAndNil(RandomGen);
  1550.   FreeAndNil(FPerfProfile);
  1551.   inherited;
  1552.   Subsystems := nil;
  1553.   FreeAndNil(DefaultTimer);
  1554. end;
  1555. constructor TBaseCore.Create;
  1556. begin
  1557.   inherited;
  1558.   Log.Log('CAST II v' + EngineVersionMajor + '.' + EngineVersionMinor + ' starting up', lkInfo);
  1559.   {$IFDEF EDITORMODE}
  1560.   FEditorMode := True;
  1561.   Log.Log('World editing capabilities are On', lkWarning);
  1562.   {$ELSE}
  1563.   FEditorMode := False;
  1564.   Log.Log('World editing capabilities are Off', lkWarning);
  1565.   {$ENDIF}
  1566.   DefaultTimer := TTimer.Create({$IFDEF OBJFPCEnable}@{$ENDIF}HandleMessage);
  1567.   Timer        := DefaultTimer;
  1568.   Timer.MaxInterval := 5;                                    // Process recurring events for 5 last seconds only
  1569.   Timer.GetInterval(DeltaTimeBasedTimeMark, True);           // Initialize the time mark
  1570.   RegisterItemClass(TCASTRootItem);
  1571.   RandomGen := Basics.TRandomGenerator.Create;
  1572.   FTesselatorManager := BaseCont.TReferencedItemManager.Create;
  1573.   FPerfProfile := TPerfProfile.Create;
  1574.   TotalProcessingClasses := 1;
  1575.   SetProcessingClass(0, 30/1000, False, True);
  1576.   
  1577.   TimeScale := 1;
  1578. end;
  1579. procedure TBaseCore.HandleMessage(const Msg: TMessage);
  1580. var i: Integer;
  1581. begin
  1582.   inherited;
  1583.   if Msg.ClassType = TSubsystemMsg then with TSubsystemMsg(Msg) do begin
  1584.     case Action of
  1585.       saConnect: AddSubsystem(Subsystem);
  1586.       saDisconnect: RemoveSubsystem(Subsystem);
  1587.     end;  
  1588.   end;
  1589.   for i := 0 to High(Subsystems) do Subsystems[i].HandleMessage(Msg);
  1590.   if Assigned(MessageHandler) then MessageHandler(Msg);
  1591. end;
  1592. procedure TBaseCore.AddSubsystem(const Subsystem: TSubsystem);
  1593. begin
  1594.   Assert(Assigned(Subsystem), Format('%S.%S: Subsystem is undefined(nil)', [ClassName, 'AddSubsystem']));
  1595.   SetLength(Subsystems, Length(Subsystems)+1);
  1596.   Subsystems[High(Subsystems)] := Subsystem;
  1597.   Log.Log(Format('Subsystem of class %S connected', [Subsystem.ClassName])); 
  1598. end;
  1599. procedure TBaseCore.RemoveSubsystem(const Subsystem: TSubsystem);
  1600. var i: Integer;
  1601. begin
  1602.   i := High(Subsystems);
  1603.   while (i >= 0) and (Subsystems[i] <> Subsystem) do Dec(i);
  1604.   Assert(i >= 0, Format('%S.%S: Subsystem of class %S not found', [ClassName, 'RemoveSubsystem', Subsystem.ClassName]));
  1605.   if i >= 0 then begin
  1606.     Subsystems[i] := Subsystems[Length(Subsystems)-1];
  1607.     SetLength(Subsystems, Length(Subsystems)-1);
  1608.   end;
  1609.   {$IFDEF LOGGING} Log.Log(Format('Subsystem of class %S disconnected', [Subsystem.ClassName])); {$ENDIF}
  1610. end;
  1611. function TBaseCore.QuerySubsystem(SubsystemClass: CSubsystem): TSubsystem;
  1612. var i: Integer;
  1613. begin
  1614.   Result := nil;
  1615.   i := High(Subsystems);
  1616.   while (i >= 0) and not Subsystems[i].InheritsFrom(SubsystemClass) do Dec(i);
  1617.   if i >= 0 then Result := Subsystems[i];  
  1618. end;
  1619. procedure TBaseCore.SetProcessingClass(Index: Integer; Interval: Single; IgnorePause, DeltaTimeBased: Boolean);
  1620. var OldFlags: TProcessingFlags;
  1621. begin
  1622.   if (Index < 0) or (Index >= TotalProcessingClasses) then begin
  1623.     Log.Log(ClassName + '.SetProcessingClass: Invalid index', lkError);
  1624.     Exit;
  1625.   end;
  1626.   OldFlags := ProcessingClasses[Index].Flags;
  1627.   ProcessingClasses[Index].Interval := Interval;
  1628.   ProcessingClasses[Index].Flags := [];
  1629.   if IgnorePause    then Include(ProcessingClasses[Index].Flags, pfIgnorePause)    else Exclude(ProcessingClasses[Index].Flags, pfIgnorePause);
  1630.   if DeltaTimeBased then Include(ProcessingClasses[Index].Flags, pfDeltaTimeBased) else Exclude(ProcessingClasses[Index].Flags, pfDeltaTimeBased);
  1631.   if DeltaTimeBased then begin
  1632.     if ProcessingClasses[Index].TimerEventID <> -1 then Timer.RemoveRecurringEvent(ProcessingClasses[Index].TimerEventID);
  1633.     ProcessingClasses[Index].TimerEventID := -1;
  1634.   end else begin
  1635.     if ProcessingClasses[Index].TimerEventID = -1 then
  1636.       ProcessingClasses[Index].TimerEventID := Timer.SetRecurringEvent(ProcessingClasses[Index].Interval, ProcessingEvent, Index)
  1637.     else
  1638.       Timer.SetRecurringEventInterval(ProcessingClasses[Index].TimerEventID, ProcessingClasses[Index].Interval);
  1639.   end;
  1640. end;
  1641. procedure TBaseCore.ClearItems;
  1642. begin
  1643.   inherited;
  1644.   if Assigned(FTesselatorManager) then FTesselatorManager.Clear;
  1645.   if Assigned(FSharedTesselators) then FSharedTesselators.Clear;
  1646. end;
  1647. {procedure TBaseCore.SetRoot(ARoot: TRootItem);
  1648. begin
  1649.   FRoot := ARoot;
  1650.   if Root <> nil then Root.FManager := Self;
  1651. end;}
  1652. { TMirrorCamera }
  1653. procedure TMirrorCamera.ComputeViewMatrix;
  1654. begin
  1655.   if Assigned(FOldCamera) and (FOldCamera <> Self) then begin
  1656.     FViewMatrix := FOldCamera.GetViewMatrix;
  1657.     FViewMatrix := MulMatrix4s(ReflectionMatrix4s(GetAbsLocation, NormalizeVector3s(Transform.ViewForward)), FViewMatrix);
  1658.     MulMatrix4s(FTotalMatrix, FViewMatrix, ProjMatrix);
  1659.     ViewValid := True;
  1660.     FOldCamera := nil;
  1661.     ComputeFrustumPlanes;
  1662.   end else inherited;
  1663. end;
  1664. procedure TMirrorCamera.OnApply(const OldCamera: TCamera);
  1665. begin
  1666.   FOldCamera := OldCamera;
  1667.   ViewValid  := False;
  1668.   if not Assigned(ClipPlanes[0]) then GetMem(ClipPlanes[0], SizeOf(ClipPlanes[0]^));
  1669.   ClipPlanes[0]^ := GetPlaneFromPointNormal(GetAbsLocation, ScaleVector3s(Transform.ViewForward, 1));
  1670. end;
  1671. { TItemMoveOp }
  1672. procedure TItemMoveOp.DoApply;
  1673. var t: TLocation;
  1674. begin
  1675.   t := Location;
  1676.   Location := AffectedProcessing.Location;
  1677.   AffectedProcessing.Location := t;
  1678. end;
  1679. function TItemMoveOp.DoMerge(AOperation: TOperation): Boolean;
  1680. begin
  1681.   Result := (AOperation is TItemMoveOp) and (TItemMoveOp(AOperation).AffectedProcessing = AffectedProcessing);
  1682.   if Result and not (ofApplied in Flags) then Location := TItemMoveOp(AOperation).Location;
  1683. end;
  1684. function TItemMoveOp.Init(AAffectedProcessing: TProcessing; ALocation: TLocation): Boolean;
  1685. begin
  1686.   Result := False;
  1687.   Assert(Assigned(AAffectedProcessing));
  1688.   if EqualLocations(ALocation, AAffectedProcessing.Location) then Exit;
  1689.   AffectedProcessing := AAffectedProcessing;
  1690.   Location := ALocation;
  1691.   Result := True;
  1692. end;
  1693. { TItemRotateOp }
  1694. procedure TItemRotateOp.DoApply;
  1695. var t: TQuaternion;
  1696. begin
  1697.   t := Orientation;
  1698.   Orientation := AffectedProcessing.Orientation;
  1699.   AffectedProcessing.Orientation := t;
  1700. end;
  1701. function TItemRotateOp.DoMerge(AOperation: TOperation): Boolean;
  1702. begin
  1703.   Result := (AOperation is TItemRotateOp) and (TItemRotateOp(AOperation).AffectedProcessing = AffectedProcessing);
  1704.   if Result and not (ofApplied in Flags) then Orientation := TItemRotateOp(AOperation).Orientation;
  1705. end;
  1706. function TItemRotateOp.Init(AAffectedProcessing: TProcessing; AOrientation: TQuaternion): Boolean;
  1707. begin
  1708.   Result := False;
  1709.   Assert(Assigned(AAffectedProcessing));
  1710.   if EqualsQuaternions(AAffectedProcessing.Orientation, AOrientation) then Exit;
  1711.   AffectedProcessing := AAffectedProcessing;
  1712.   Orientation := AOrientation;
  1713.   Result := True;
  1714. end;
  1715. end.