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

游戏引擎

开发平台:

Delphi

  1. (*
  2.  @Abstract(CAST II Engine core unit)
  3.  (C) 2006 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.  Unit contains engine core classes
  6. *)
  7. {$Include GDefines.inc}
  8. {$Include C2Defines.inc}
  9. unit C2Core;
  10. interface
  11. uses
  12.   TextFile,
  13.   SysUtils,
  14.   BaseTypes, Basics, Base3D, Timer, OSUtils, BaseClasses, BaseMsg, ItemMsg, BaseGraph, Resources,
  15.   OTypes,
  16.   C2Types, C2Msg, C2Res, CAST2, C2Visual, C2Render, C2Materials, Input;
  17. const
  18.     // script data types
  19.   // 4x4 matrix
  20.   tidMatrix4x4 = 0;
  21.   // Vector
  22.   tidVector4 = 1;
  23. type
  24.   // Sorted items data structure for internal use
  25.   TVisItem = record
  26.     PassIndex, ItemIndex: Word;
  27.   end;
  28.   TSortedItems = array of TVisItem;
  29.   // Temporary class to parse shader constant definitions. Should be replaced with fully-featured script-based implementation.
  30.   TSimpleParser = class(TAbstractCompiler)
  31.     // Simply recognizes some predefined keywords
  32.     function Compile(const Source: AnsiString): OTypes.TRTData; override;
  33.   end;
  34.   // Core class reference
  35.   CCore = class of TCore;
  36.   { @Abstract(Engine core class)
  37.     This class manages subsystems, controls items processing and rendering.
  38.     Its <b>Process()</b> method should be called in main application cycle. }
  39.   TCore = class(TBaseCore)
  40.   private
  41.     FRenderer: C2Render.TRenderer;
  42.     FInput: Input.TController;
  43.     RenderItems: TItems; TotalRenderItems: Integer;
  44.     Lights: TItems; TotalLights: Integer;
  45.     FPSCountEventID: TEventID;
  46.     FFPSCountTimeout, OneOverFPSCountTimeout, LastFPSCountFrame: TTimeUnit;
  47.     LastProcessingTime: array of TTimeUnit;
  48.     SortedItems: TSortedItems;
  49.     Passes: array of TRenderPass; TotalPasses: Integer;                // Sorted passes
  50.     procedure FPSCountEvent(EventID: Integer; const ErrorDelta: TTimeUnit);
  51.     procedure SetFPSCountTimeout(const Value: TTimeUnit);
  52.     procedure SetInput(const Value: Input.TController);
  53.     procedure SetRenderer(const Value: C2Render.TRenderer);
  54.     
  55.     procedure SetShaderConstants(const Pass: TRenderPass; Item: TVisible);
  56.     procedure ResetTechnique(const AMaterial: TMaterial);
  57.     procedure Render(const ThroughCamera, Camera: TCamera; RecursionCounter: Integer);
  58.   protected
  59.     // Clears garbage data. Called automatically
  60.     procedure CollectGarbage; override;
  61.     // Performs clean-up before destruction
  62.     procedure OnDestroy; override;
  63.   public
  64.     // Default material
  65.     DefaultMaterial: TMaterial;
  66.     // If <b>True</b> all input item generate messages not only explicitly bound ones
  67.     CatchAllInput: Boolean;
  68.     constructor Create; override;
  69.     // For internal use only.
  70.     procedure AddPass(const Item: TItem); override;
  71.     // For internal use only.
  72.     procedure RemovePass(const Item: TItem); override;
  73.     procedure HandleMessage(const Msg: TMessage); override;
  74.     // Finds in current scene and applies first found camera with <b>Default</b> property set to <b>True</b>
  75.     procedure ApplyDefaultCamera;
  76.     // Clears current scene
  77.     procedure ClearItems; override;
  78.     // Traces the given ray with the given depth and returns a list of items hit sorted by distance <b>not implemented yet</b>
  79.     function TraceRay(const Ray: TVector3s; Depth: Single; out Items: TItems): Integer;
  80.     // Performs main engine cycle. Items processing, rendering, collision, input, etc. Should be called from main application cycle.
  81.     procedure Process;
  82.     // Renderer subsystem
  83.     property Renderer: C2Render.TRenderer read FRenderer write SetRenderer;
  84.     // Input subsystem
  85.     property Input: Input.TController     read FInput    write SetInput;
  86.     // Time to average frame rate through
  87.     property FPSCountTimeout: TTimeUnit read FFPSCountTimeout write SetFPSCountTimeout;
  88.   end;
  89.   // Returns list of classes introduced by the unit
  90.   function GetUnitClassList: TClassArray;
  91. implementation
  92. function GetUnitClassList: TClassArray;
  93. begin
  94.   Result := GetClassList([TProcessing, TCamera, TMirrorCamera, TLookAtCamera, TLight,
  95.                           TMaterial, TTechnique, TRenderPass]);
  96. end;
  97. { TCore }
  98. const PassesCapacityStep = 4;
  99. procedure TCore.OnDestroy;
  100. var i: Integer;
  101. begin
  102.   if Assigned(DefaultMaterial) then begin
  103.     for i := 0 to DefaultMaterial.TotalTechniques-1 do begin
  104.       DefaultMaterial.Technique[i].Passes[0].Free;
  105.       DefaultMaterial.Technique[i].Free;
  106.     end;
  107.     FreeAndNil(DefaultMaterial);
  108.   end;
  109.   FreeAndNil(FTempItems);
  110.   FreeAndNil(Compiler);
  111.   inherited;
  112. end;
  113. procedure TCore.FPSCountEvent(EventID: Integer; const ErrorDelta: TTimeUnit);
  114. begin
  115.   PerfProfile.FramesPerSecond := (Renderer.FramesRendered - LastFPSCountFrame) * OneOverFPSCountTimeout;
  116.   LastFPSCountFrame := Renderer.FramesRendered;
  117. end;
  118. procedure TCore.SetFPSCountTimeout(const Value: TTimeUnit);
  119. begin
  120.   FFPSCountTimeout       := Value;
  121.   OneOverFPSCountTimeout := 1/Value;
  122.   if FPSCountEventID = eIDNone then
  123.     FPSCountEventID := Timer.SetRecurringEvent(FFPSCountTimeout, FPSCountEvent, 0)
  124.   else
  125.     Timer.SetRecurringEventInterval(FPSCountEventID, FFPSCountTimeout);
  126. end;
  127. procedure TCore.SetInput(const Value: Input.TController);
  128. begin
  129.   if Assigned(FInput) then RemoveSubsystem(FInput);
  130.   FInput := Value;
  131.   if Assigned(FInput) then AddSubsystem(FInput);
  132. end;
  133. procedure TCore.SetRenderer(const Value: C2Render.TRenderer);
  134. begin
  135.   if Assigned(FRenderer) then RemoveSubsystem(FRenderer);
  136.   FRenderer := Value;
  137.   if Assigned(FRenderer) then begin
  138.     AddSubsystem(FRenderer);
  139.     FRenderer.SetPerfProfile(PerfProfile);
  140.   end;
  141.   FTempItems := TTemporaryVisible.Create(Self);
  142. end;
  143. procedure TCore.SetShaderConstants(const Pass: TRenderPass; Item: TVisible);
  144. var i, RegI: Integer;
  145.   function SetConstant(ShaderKind: TShaderKind; BaseRegIndex: Integer; DataDesc: Integer): Integer;            // Dummy code to replace with fully-functional script
  146.   const ZeroPosition: TVector4s = (X: 0; Y: 0; Z: 0; W: 1);
  147.   const ZeroVector:   TVector4s = (X: 0; Y: 0; Z: 0; W: 0);
  148.   var M: TMatrix4s;
  149.   begin
  150.     Result := 1;
  151.     case DataDesc of
  152.       0: begin              // Model matrix
  153.         Renderer.APIState.SetShaderConstant(ShaderKind, BaseRegIndex+0, GetVector4s(Item.Transform._11, Item.Transform._21, Item.Transform._31, Item.Transform._41));
  154.         Renderer.APIState.SetShaderConstant(ShaderKind, BaseRegIndex+1, GetVector4s(Item.Transform._12, Item.Transform._22, Item.Transform._32, Item.Transform._42));
  155.         Renderer.APIState.SetShaderConstant(ShaderKind, BaseRegIndex+2, GetVector4s(Item.Transform._13, Item.Transform._23, Item.Transform._33, Item.Transform._43));
  156.         Renderer.APIState.SetShaderConstant(ShaderKind, BaseRegIndex+3, GetVector4s(Item.Transform._14, Item.Transform._24, Item.Transform._34, Item.Transform._44));
  157.         Result := 4;
  158.       end;
  159.       1: begin              // View matrix
  160.         Renderer.APIState.SetShaderConstant(ShaderKind, BaseRegIndex+0, GetVector4s(Renderer.LastAppliedCamera.ViewMatrix._11, Renderer.LastAppliedCamera.ViewMatrix._21, Renderer.LastAppliedCamera.ViewMatrix._31, Renderer.LastAppliedCamera.ViewMatrix._41));
  161.         Renderer.APIState.SetShaderConstant(ShaderKind, BaseRegIndex+1, GetVector4s(Renderer.LastAppliedCamera.ViewMatrix._12, Renderer.LastAppliedCamera.ViewMatrix._22, Renderer.LastAppliedCamera.ViewMatrix._32, Renderer.LastAppliedCamera.ViewMatrix._42));
  162.         Renderer.APIState.SetShaderConstant(ShaderKind, BaseRegIndex+2, GetVector4s(Renderer.LastAppliedCamera.ViewMatrix._13, Renderer.LastAppliedCamera.ViewMatrix._23, Renderer.LastAppliedCamera.ViewMatrix._33, Renderer.LastAppliedCamera.ViewMatrix._43));
  163.         Renderer.APIState.SetShaderConstant(ShaderKind, BaseRegIndex+3, GetVector4s(Renderer.LastAppliedCamera.ViewMatrix._14, Renderer.LastAppliedCamera.ViewMatrix._24, Renderer.LastAppliedCamera.ViewMatrix._34, Renderer.LastAppliedCamera.ViewMatrix._44));
  164.         Result := 4;
  165.       end;
  166.       2: begin              // Projection matrix
  167.         Renderer.APIState.SetShaderConstant(ShaderKind, BaseRegIndex+0, GetVector4s(Renderer.LastAppliedCamera.ProjMatrix._11, Renderer.LastAppliedCamera.ProjMatrix._21, Renderer.LastAppliedCamera.ProjMatrix._31, Renderer.LastAppliedCamera.ProjMatrix._41));
  168.         Renderer.APIState.SetShaderConstant(ShaderKind, BaseRegIndex+1, GetVector4s(Renderer.LastAppliedCamera.ProjMatrix._12, Renderer.LastAppliedCamera.ProjMatrix._22, Renderer.LastAppliedCamera.ProjMatrix._32, Renderer.LastAppliedCamera.ProjMatrix._42));
  169.         Renderer.APIState.SetShaderConstant(ShaderKind, BaseRegIndex+2, GetVector4s(Renderer.LastAppliedCamera.ProjMatrix._13, Renderer.LastAppliedCamera.ProjMatrix._23, Renderer.LastAppliedCamera.ProjMatrix._33, Renderer.LastAppliedCamera.ProjMatrix._43));
  170.         Renderer.APIState.SetShaderConstant(ShaderKind, BaseRegIndex+3, GetVector4s(Renderer.LastAppliedCamera.ProjMatrix._14, Renderer.LastAppliedCamera.ProjMatrix._24, Renderer.LastAppliedCamera.ProjMatrix._34, Renderer.LastAppliedCamera.ProjMatrix._44));
  171.         Result := 4;
  172.       end;
  173.       3: begin              // Model*View matrix
  174.         M := GetTransposedMatrix4s(MulMatrix4s(Item.Transform, Renderer.LastAppliedCamera.ViewMatrix));
  175.         Renderer.APIState.SetShaderConstant(ShaderKind, BaseRegIndex+0, M.Rows[0]);
  176.         Renderer.APIState.SetShaderConstant(ShaderKind, BaseRegIndex+1, M.Rows[1]);
  177.         Renderer.APIState.SetShaderConstant(ShaderKind, BaseRegIndex+2, M.Rows[2]);
  178.         Renderer.APIState.SetShaderConstant(ShaderKind, BaseRegIndex+3, M.Rows[3]);
  179.         Result := 4;
  180.       end;
  181.       4: begin              // Model*View*Projection matrix
  182.         M := GetTransposedMatrix4s(MulMatrix4s(Item.Transform, Renderer.LastAppliedCamera.TotalMatrix));
  183.         Renderer.APIState.SetShaderConstant(ShaderKind, BaseRegIndex+0, M.Rows[0]);
  184.         Renderer.APIState.SetShaderConstant(ShaderKind, BaseRegIndex+1, M.Rows[1]);
  185.         Renderer.APIState.SetShaderConstant(ShaderKind, BaseRegIndex+2, M.Rows[2]);
  186.         Renderer.APIState.SetShaderConstant(ShaderKind, BaseRegIndex+3, M.Rows[3]);
  187.         Result := 4;
  188.       end;
  189.       5: if TotalLights > 0 then        // Light[0].Position
  190.         Renderer.APIState.SetShaderConstant(ShaderKind, BaseRegIndex, TLight(Lights[0]).Transform.ViewTranslate4s) else
  191.           Renderer.APIState.SetShaderConstant(ShaderKind, BaseRegIndex, ZeroPosition);
  192.       6: if TotalLights > 0 then        // Light[0].Direction
  193.         Renderer.APIState.SetShaderConstant(ShaderKind, BaseRegIndex, TLight(Lights[0]).Transform.ViewForward4s) else
  194.           Renderer.APIState.SetShaderConstant(ShaderKind, BaseRegIndex, ZeroVector);
  195.       7: if TotalLights > 0 then        // Light[0].Ambient
  196.         Renderer.APIState.SetShaderConstant(ShaderKind, BaseRegIndex, TLight(Lights[0]).Ambient.RGBA) else
  197.           Renderer.APIState.SetShaderConstant(ShaderKind, BaseRegIndex, ZeroVector);
  198.       8: if TotalLights > 0 then        // Light[0].Diffuse
  199.         Renderer.APIState.SetShaderConstant(ShaderKind, BaseRegIndex, TLight(Lights[0]).Diffuse.RGBA) else
  200.           Renderer.APIState.SetShaderConstant(ShaderKind, BaseRegIndex, ZeroVector);
  201.       9: if TotalLights > 0 then        // Light[0].Specular
  202.         Renderer.APIState.SetShaderConstant(ShaderKind, BaseRegIndex, TLight(Lights[0]).Specular.RGBA) else
  203.           Renderer.APIState.SetShaderConstant(ShaderKind, BaseRegIndex, ZeroVector);
  204.       10: Renderer.APIState.SetShaderConstant(ShaderKind, BaseRegIndex, Pass.Ambient.RGBA); // Material.Ambient
  205.       11: Renderer.APIState.SetShaderConstant(ShaderKind, BaseRegIndex, Pass.Diffuse.RGBA); // Material.Diffuse
  206.       12: Renderer.APIState.SetShaderConstant(ShaderKind, BaseRegIndex, Pass.Specular.RGBA); // Material.Specular
  207.     end;
  208.   end;
  209. begin
  210.   RegI := 0;
  211.   for i := 0 to Pass.TotalVertexShaderConstants-1 do if Assigned(Pass.CompiledVertexShaderConstants[i]) then
  212.     Inc(RegI, SetConstant(skVertex, RegI, Pass.CompiledVertexShaderConstants[i].PIN[0]));
  213.   RegI := 0;
  214.   for i := 0 to Pass.TotalPixelShaderConstants-1 do if Assigned(Pass.CompiledPixelShaderConstants[i]) then
  215.     Inc(RegI, SetConstant(skPixel, RegI, Pass.CompiledPixelShaderConstants[i].PIN[0]));
  216. end;
  217. procedure TCore.Render(const ThroughCamera, Camera: TCamera; RecursionCounter: Integer);
  218. var PassIndex, FirstSortedPass, LastSortedPass: Integer; 
  219.   procedure RenderItem(APass: TRenderPass; AItem: TVisible);
  220.   var l, CurLight: Integer;
  221.   begin
  222.     Inc(PerfProfile.FrustumPassedItems);
  223.     CurLight := 0;
  224.     if APass.LightingState.Enabled and not AItem.CustomLighting then begin
  225.       for l := 0 to TotalLights-1 do
  226.         if TLight(Lights[l]).Enabled and (APass.Group in TLight(Lights[l]).GroupMask) and
  227.            (Sqr(TLight(Lights[l]).Range + AItem.BoundingSphereRadius) >
  228.             SqrMagnitude(SubVector3s(TLight(Lights[l]).GetAbsLocation, AItem.GetAbsLocation))) then begin
  229.           Renderer.ApplyLight(CurLight, TLight(Lights[l]));
  230.           Inc(CurLight);
  231.           if CurLight >= SimultaneousLightSources then Break;
  232.         end;
  233.       for l := CurLight to Renderer.MaxAPILights-1 do Renderer.ApplyLight(l, nil);
  234.     end else if AItem.CustomLighting then begin
  235.       AItem.BeginLighting;
  236.       for l := 0 to TotalLights-1 do
  237.         if TLight(Lights[l]).Enabled and (APass.Group in TLight(Lights[l]).GroupMask) and
  238.            (Sqr(TLight(Lights[l]).Range + AItem.BoundingSphereRadius) >
  239.             SqrMagnitude(SubVector3s(TLight(Lights[l]).GetAbsLocation, AItem.GetAbsLocation))) then begin
  240.           if AItem.CalculateLighting(TLight(Lights[l])) then Inc(CurLight);
  241.           if CurLight >= SimultaneousLightSources then Break;
  242.         end;
  243.     end;
  244.     Renderer.APIState.ApplyCustomTextureMatrices(APass, AItem);
  245.     SetShaderConstants(APass, AItem);
  246.     Renderer.RenderItem(AItem);
  247.     Assert(isVisible in AItem.State, ClassName + '.Render: Rendering an invisible item "' + AItem.GetFullName + '"');
  248.   end;
  249.   procedure AddSortedPass(APass: TRenderPass);
  250.   begin
  251.     if FirstSortedPass < 0 then FirstSortedPass := PassIndex;
  252.     LastSortedPass := PassIndex;
  253.   end;
  254.   procedure DrawSortedPasses;
  255.   var TotalSortedItems: Integer;
  256.     type _QSDataType = TVisItem; _QSValueType = Single;
  257.     procedure SortItems(N: Integer; Values: TSortedItems);
  258.       function _QSGetValue(const V: _QSDataType): _QSValueType;
  259.       begin
  260.         Result := TVisible(Passes[V.PassIndex].Items[V.ItemIndex]).SortValue;
  261.       end;
  262.     {$DEFINE COMPUTABLE}                                 // Set a sort algorithm on computable items
  263.     {$I basics_quicksort.inc}                            // Include the quick sort algorithm
  264.     {$IFNDEF ForCodeNavigationWork} begin end; {$ENDIF}  // Needed for code navigation features to work in Delphi 7
  265.   var i, j: Integer;
  266.   begin
  267.     TotalSortedItems := 0;
  268.     for i := FirstSortedPass to LastSortedPass do for j := 0 to Passes[i].TotalItems-1 do if TVisible(Passes[i].Items[j]).VisibilityCheck(Camera) then begin
  269.       TVisible(Passes[i].Items[j]).CalcSortValue(Camera);
  270.       TVisible(Passes[i].Items[j]).SortValue := TVisible(Passes[i].Items[j]).SortValue + Passes[i].SortBias;
  271.       if Length(SortedItems) <= TotalSortedItems then SetLength(SortedItems, Length(SortedItems) + ItemsCapacityStep);
  272.       with SortedItems[TotalSortedItems] do begin
  273.         PassIndex := i;
  274.         ItemIndex := j;
  275.       end;
  276.       Inc(TotalSortedItems);
  277.     end else Inc(PerfProfile.FrustumCulledItems);
  278.     SortItems(TotalSortedItems, SortedItems);
  279.     Inc(PerfProfile.SortedItems, TotalSortedItems);
  280.     for i := TotalSortedItems-1 downto 0 do begin
  281.       Renderer.APIState.ApplyPass(Passes[SortedItems[i].PassIndex]);
  282.       RenderItem(Passes[SortedItems[i].PassIndex], TVisible(Passes[SortedItems[i].PassIndex].Items[SortedItems[i].ItemIndex]));
  283.     end;
  284.   end;
  285. var LastClearOrder, i, j: Integer; SortedPassesCollect: Boolean; ClearSettings: TClearSettings;
  286. begin
  287.   // Render visible through camera textures
  288. //            if RecursionCounter = 0 then                                         // ToDo: remove it
  289.   for PassIndex := 0 to TotalPasses-1 do if (isVisible in Passes[PassIndex].State) and (Passes[PassIndex].Group in Camera.GroupMask) then begin
  290.     Passes[PassIndex].State := Passes[PassIndex].State - [isVisible];                     // Do not draw this pass within its camera
  291.     for j := 0 to Passes[PassIndex].TotalStages-1 do
  292.       if  (Passes[PassIndex].Stages[j].TextureIndex <> tivNull) and
  293.          ((Passes[PassIndex].Stages[j].TextureIndex <> tivUnresolved) or Renderer.Textures.Resolve(Passes[PassIndex], j)) then
  294.         if (Passes[PassIndex].Stages[j].TextureIndex = tivRenderTarget) and
  295.            (Passes[PassIndex].Stages[j].Camera <> Renderer.MainCamera) and (isVisible in Passes[PassIndex].Stages[j].Camera.State) and
  296.            not Renderer.APIState.IsRenderTargetUptoDate(Passes[PassIndex].Stages[j].Camera) then begin
  297.              Passes[PassIndex].Stages[j].Camera.RenderTargetIndex := Renderer.APIState.FindRenderTarget(Passes[PassIndex].Stages[j].Camera);
  298.              if Passes[PassIndex].Stages[j].Camera.RenderTargetIndex <> -1 then
  299.                Render(Camera, Passes[PassIndex].Stages[j].Camera, RecursionCounter+1);
  300.            end;
  301.     Passes[PassIndex].State := Passes[PassIndex].State + [isVisible];
  302.   end;
  303.   // Render objects by PBR
  304.   Camera.OnApply(ThroughCamera);
  305.   Renderer.ApplyCamera(Camera);
  306.   SortedPassesCollect := False;
  307.   FirstSortedPass := -1;
  308.   LastSortedPass  := -2;
  309.   LastClearOrder  := poPreprocess;
  310.   ClearSettings.ClearFlags := [];
  311.   for PassIndex := 0 to TotalPasses-1 do begin
  312.     Assert(Passes[PassIndex].Order >= LastClearOrder, '');
  313.     // Handle render stage (order) clear settings
  314.     if (Passes[PassIndex].TotalItems > 0) and                                    // Is really need to clear and draw?
  315.        (isVisible in Passes[PassIndex].State) and
  316.        (Passes[PassIndex].Group in Camera.GroupMask) then begin
  317.       for i := LastClearOrder+1 to Passes[PassIndex].Order do begin                // Collect clear settings for all passed render stages
  318.         ClearSettings.ClearFlags   := ClearSettings.ClearFlags + TCASTRootItem(Root).StageSettings[i].ClearFlags;
  319.         ClearSettings.ClearColor   := TCASTRootItem(Root).StageSettings[i].ClearColor;
  320.         ClearSettings.ClearStencil := TCASTRootItem(Root).StageSettings[i].ClearStencil;
  321.         ClearSettings.ClearZ       := TCASTRootItem(Root).StageSettings[i].ClearZ;
  322.       end;
  323.       Renderer.Clear(ClearSettings.ClearFlags, ClearSettings.ClearColor, ClearSettings.ClearZ, ClearSettings.ClearStencil);
  324.       Inc(PerfProfile.ClearCalls, Ord(ClearSettings.ClearFlags <> []));
  325.       LastClearOrder := Passes[PassIndex].Order;
  326.       ClearSettings.ClearFlags := [];                                            // Reset clear settings
  327.       if Passes[PassIndex].Order = SortedPassOrder then begin                    // Sorted passes need to collect
  328.         SortedPassesCollect := True;
  329.         AddSortedPass(Passes[PassIndex]);
  330.       end else begin
  331.         Renderer.APIState.ApplyPass(Passes[PassIndex]);
  332.         for j := 0 to Passes[PassIndex].TotalItems-1 do if TVisible(Passes[PassIndex].Items[j]).VisibilityCheck(Camera) then
  333.           RenderItem(Passes[PassIndex], TVisible(Passes[PassIndex].Items[j])) else
  334.             Inc(PerfProfile.FrustumCulledItems);
  335.       end;
  336.     end;
  337.     // Draw all accumulated sorted items if no more
  338.     if SortedPassesCollect and ((PassIndex >= TotalPasses-1) or (Passes[PassIndex+1].Order <> SortedPassOrder)) then begin
  339.       DrawSortedPasses;                                                      // Draw sorted passes
  340.       SortedPassesCollect := False;
  341.     end;
  342.   end;
  343. end;
  344. constructor TCore.Create;
  345. begin
  346.   inherited;
  347.   FPSCountEventID := eIDNone;
  348.   // Register item classes
  349.   RegisterItemClasses(GlobalClassList.Classes);
  350.   Compiler := TSimpleParser.Create;
  351.   FSharedTesselators := TSharedTesselators.Create;
  352.   FSharedTesselators.Core := Self;
  353.   if Assigned(Screen) then AddSubsystem(Screen);
  354.   if not Assigned(DefaultMaterial) then begin
  355.     DefaultMaterial := TMaterial.Create(Self);
  356.     DefaultMaterial.TotalTechniques := 1;
  357.     DefaultMaterial.Technique[0] := TTechnique.Create(Self);
  358.     DefaultMaterial.Technique[0].TotalPasses := 1;
  359.     DefaultMaterial.Technique[0].Valid := True;
  360.     DefaultMaterial.Technique[0].Passes[0] := TRenderPass.Create(Self);
  361.     DefaultMaterial.Technique[0].Passes[0].Group         := 0;
  362.     DefaultMaterial.Technique[0].Passes[0].ZBufferState  := GetZBufferState(False, tfAlways, 0);
  363.     DefaultMaterial.Technique[0].Passes[0].Order         := poPostProcess;
  364.     DefaultMaterial.Technique[0].Passes[0].LightingState := GetLightingState(slNONE, False, False, GetColor($40404040));
  365.     DefaultMaterial.Technique[0].Passes[0].FillShadeMode := GetFillShadeMode(fmSOLID, smGOURAUD, cmNONE, $FFFFFFFF);
  366.     DefaultMaterial.Technique[0].Passes[0].FogKind       := fkNone;
  367.     DefaultMaterial.Technique[0].Passes[0].TotalStages   := 1;
  368.     DefaultMaterial.Technique[0].Passes[0].Stages[0].ColorArg0 := taDIFFUSE;
  369.     DefaultMaterial.Technique[0].Passes[0].Stages[0].ColorOp := toARG2;
  370.     DefaultMaterial.Technique[0].Passes[0].State := DefaultMaterial.Technique[0].Passes[0].State + [isVisible];
  371.   end;
  372.   CatchAllInput := False;
  373.   FPSCountTimeout := 0.5;
  374. end;
  375. procedure TCore.AddPass(const Item: TItem);
  376. var i: Integer;
  377. begin
  378.   Assert(Item is TRenderPass, Format('%S.%S: Item "%S" of class "%S" is not a render pass', [ClassName, 'AddPass', Item.Name, Item.ClassName]));
  379.   Inc(TotalPasses);
  380.   if Length(Passes) < TotalPasses then SetLength(Passes, Length(Passes) + PassesCapacityStep);
  381.   i := TotalPasses-1;
  382.   while i > 0 do begin
  383.     if TRenderPass(Item).Order >= Passes[i-1].Order then Break;
  384.     Passes[i] := Passes[i-1];
  385.     Dec(i);
  386.   end;
  387.   Passes[i] := TRenderPass(Item);
  388. end;
  389. procedure TCore.RemovePass(const Item: TItem);
  390. var i, RemovedCount: Integer;
  391. begin
  392.   RemovedCount := 0;
  393.   for i := 0 to TotalPasses-1 do begin
  394.     if Passes[i] = Item then Inc(RemovedCount);
  395.     if (RemovedCount > 0) and (i < TotalPasses-1) then Passes[i] := Passes[i + RemovedCount];
  396.   end;
  397.   Dec(TotalPasses, RemovedCount);
  398.   Assert(RemovedCount > 0, ClassName + '.RemovePass: Pass not found');
  399. end;
  400. procedure TCore.HandleMessage(const Msg: TMessage);
  401. begin
  402. //  if Msg = nil then Exit;
  403.   inherited;  
  404. //  if Assigned(Screen)   then Screen.HandleMessage(Msg);
  405. //  if Assigned(Renderer) then Renderer.HandleMessage(Msg);
  406. //  if Assigned(Input)    then Input.HandleMessage(Msg);
  407.   if Msg.ClassType = ItemMsg.TReplaceMsg then with ItemMsg.TReplaceMsg(Msg) do begin
  408. //    if (OldItem is TVisible) and (TVisible(OldItem).Colliding <> nil) then Collidings.Remove(TProcessing(OldItem).Colliding);
  409.   end else if Msg.ClassType = TRequestValidationMsg then begin
  410.     Assert(TRequestValidationMsg(Msg).Item is TMaterial);
  411.     if Assigned(Renderer) and Renderer.ValidateMaterial(TRequestValidationMsg(Msg).Item as TMaterial) then begin
  412. //      ResetTechnique(TMaterial(TRequestValidationMsg(Msg).Item));
  413.       SendMessage(TValidationResultChangedMsg.Create(TRequestValidationMsg(Msg).Item), nil, [mfBroadcast]);
  414.     end;
  415.   end else if Msg.ClassType = ItemMsg.TSceneLoadedMsg then ApplyDefaultCamera;
  416. end;
  417. procedure TCore.ClearItems;
  418. begin
  419.   Lights    := nil;
  420.   RenderItems        := nil;
  421.   LastProcessingTime := nil;
  422.   inherited;
  423.   Passes := nil; TotalPasses := 0;
  424. end;
  425. function TCore.TraceRay(const Ray: TVector3s; Depth: Single; out Items: TItems): Integer;
  426. begin
  427.   Result := 0;
  428. end;
  429. procedure TCore.Process;
  430. var i: Integer; CASTRoot: TCASTRootItem;
  431. begin
  432.   {$IFDEF PROFILE}
  433.   PerfProfile.BeginTiming(Timer, ptFrame);
  434.   {$ENDIF}
  435.   if Assigned(Root) then begin
  436.     Assert(Root is TCASTRootItem, ClassName + '.Process: Root should be an instance of TCASTRootItem or one of its descendants');
  437.     CastRoot := TCASTRootItem(Root);
  438.   // Collision
  439.     {$IFDEF PROFILE} PerfProfile.BeginTiming(Timer, ptCollision); {$ENDIF}
  440.     CastRoot.Collide;
  441.     {$IFDEF PROFILE} PerfProfile.EndTiming(Timer, ptCollision); {$ENDIF}
  442.   // Input
  443.     if Assigned(Input) then begin
  444.       if CatchAllInput then begin
  445.         Input.ProcessInput([ifBound, ifNotBound]);
  446.         Input.InputEventsToMessages;
  447.       end else Input.ProcessInput([ifBound]);
  448.     end;  
  449.   // Processing
  450.     {$IFDEF PROFILE} PerfProfile.BeginTiming(Timer, ptProcessing); {$ENDIF}
  451.     TotalProcessingItems := Root.ExtractByMask([isProcessing], True, ProcessingItems);
  452.     Timer.Process;
  453.     ProcessDeltaTimeBased(Timer.GetInterval(DeltaTimeBasedTimeMark, True) * TimeScale);
  454. {    l := Length(LastProcessingTime);
  455.     if l < Length(ProcessingClasses) then begin
  456.       SetLength(LastProcessingTime, Length(ProcessingClasses));
  457.       for i := l to Length(ProcessingClasses)-1 do LastProcessingTime[i] := LastProcessTime;
  458.     end;
  459.     for i := 0 to Length(ProcessingClasses)-1 do if not Paused or (pfIgnorePause in ProcessingClasses[i].Flags) then begin
  460.       if pfDeltaTimeBased in ProcessingClasses[i].Flags then begin
  461.         for j := 0 to TotalProcessingItems-1 do begin
  462.           Assert(ProcessingItems[j] is TBaseProcessing, ProcessingItems[j].Name + ' is not a descendant of TBaseProcessing');
  463.           if TBaseProcessing(ProcessingItems[j]).ProcessingClass = i then
  464.             TBaseProcessing(ProcessingItems[j]).Process(Timer.LastTime - LastProcessTime);
  465.         end;
  466.       end else begin
  467.         if ThisProcessTime - LastProcessingTime[i] > MaxInterval then LastProcessingTime[i] := ThisProcessTime - MaxInterval;
  468.         while LastProcessingTime[i] + ProcessingClasses[i].Interval <= ThisProcessTime do begin
  469.           for j := 0 to TotalProcessingItems-1 do if ProcessingItems[j] is TBaseProcessing then begin
  470.             Assert(ProcessingItems[j] is TBaseProcessing, ProcessingItems[j].Name + ' is not a descendant of TBaseProcessing');
  471.             if TBaseProcessing(ProcessingItems[j]).ProcessingClass = i then
  472.               TBaseProcessing(ProcessingItems[j]).Process(ProcessingClasses[i].Interval);
  473.           end;
  474.           LastProcessingTime[i] := LastProcessingTime[i] + ProcessingClasses[i].Interval;
  475.         end;
  476.       end;
  477.     end else LastProcessingTime[i] := ThisProcessTime;}
  478.     {$IFDEF PROFILE} PerfProfile.EndTiming(Timer, ptProcessing); {$ENDIF}
  479.   // Render
  480.     {$IFDEF PROFILE} PerfProfile.BeginTiming(Timer, ptRender); {$ENDIF}
  481.     if Assigned(Renderer) and Assigned(Renderer.MainCamera) and Renderer.Active then begin
  482.       // Prepare lights
  483.       if SimultaneousLightSources > 0 then
  484.         TotalLights := Root.ExtractByClass(TLight, Lights) else
  485.           TotalLights := 0;
  486.   //    SimultaneousLightSources := MinI(SimultaneousLightSources, Renderer.MaxAPILights);
  487.       Renderer.StartFrame;
  488.       // Render shared tesselator
  489.       SharedTesselators.Render;
  490.       Render(nil, Renderer.MainCamera, 0);
  491.       SharedTesselators.Reset;
  492.   //    if Screen <> nil then Screen.Render(Renderer);
  493.   {    TotalRenderItems := Root.Extract([tmRender], RenderItems);
  494.       for i := 0 to TotalRenderItems-1 do begin
  495.         (RenderItems[i] as TVisible).OnRender(Renderer.LastAppliedCamera);
  496.         Renderer.RenderItem(RenderItems[i] as TVisible);
  497.       end;}
  498.       if Renderer.DebugOutput then begin
  499.         // Render bounding volumes
  500.         TotalRenderItems := Root.ExtractByMask([isDrawVolumes], False, RenderItems);
  501.         for i := 0 to TotalRenderItems-1 do if RenderItems[i] is TProcessing then begin
  502.           Renderer.RenderItemBox(TProcessing(RenderItems[i]), GetColor($FFFF0000));
  503.           Renderer.RenderItemDebug(TProcessing(RenderItems[i]));
  504.         end;
  505.         // Render picked objects boxes
  506.         TotalRenderItems := Root.ExtractByMask([isPicked], False, RenderItems);
  507.         for i := 0 to TotalRenderItems-1 do if RenderItems[i] is TProcessing then
  508.          Renderer.RenderItemBox(TProcessing(RenderItems[i]), GetColor($FFFFFF00));
  509.       end;
  510.       Renderer.FinishFrame;
  511.     end;
  512.     {$IFDEF PROFILE} PerfProfile.EndTiming(Timer, ptRender); {$ENDIF}
  513.   end;
  514.   ProcessAsyncMessages;
  515.   if Assigned(Root) then CollectGarbage;
  516.   {$IFDEF PROFILE} PerfProfile.EndTiming(Timer, ptFrame); {$ENDIF}
  517. end;
  518. procedure TCore.CollectGarbage;
  519. begin
  520.   Assert(TempItems is TTemporaryVisible);
  521.   TTemporaryVisible(TempItems).Clear;
  522.   inherited;
  523. end;
  524. procedure TCore.ApplyDefaultCamera;
  525. var i, Count: Integer; Cameras: TItems;
  526. begin
  527.   if Renderer = nil then Exit;
  528.   Count := Root.ExtractByClass(TCamera, Cameras);
  529.   i := 0;
  530.   while (i < Count){ and not (Cameras[i] as TCamera).Default} do Inc(i);
  531.   if i < Count then
  532.     Renderer.MainCamera := Cameras[i] as TCamera
  533.   else if Cameras <> nil then
  534.     Renderer.MainCamera := Cameras[0] as TCamera;
  535. end;
  536. procedure TCore.ResetTechnique(const AMaterial: TMaterial);
  537. var i, j, OldTotalPasses, OldTotalItems: Integer;
  538. begin
  539.   i := 0;
  540.   OldTotalPasses := TotalPasses;
  541.   while i < TotalPasses do begin
  542.     j := 0;
  543.     OldTotalItems := Passes[i].TotalItems;
  544.     while j < Passes[i].TotalItems do begin
  545.       if TVIsible(Passes[i].Items[j]).Material = AMaterial then
  546.         TVIsible(Passes[i].Items[j]).CurrentLOD := TVIsible(Passes[i].Items[j]).CurrentLOD;     // To reset current technique
  547.       if Passes[i].TotalItems < OldTotalItems then begin                  // Some items has been removed from the pass
  548.         j := MaxI(0, j - (OldTotalItems - Passes[i].TotalItems));
  549.         OldTotalItems := Passes[i].TotalItems;
  550.       end;
  551.       Inc(j);
  552.     end;
  553.     if TotalPasses < OldTotalPasses then begin                  // Some passes has been removed
  554.       i := MaxI(0, i - (OldTotalPasses - TotalPasses));
  555.       OldTotalPasses := TotalPasses;
  556.     end;
  557.     Inc(i);
  558.   end;
  559. end;
  560. { TSimpleParser }
  561. function TSimpleParser.Compile(const Source: AnsiString): OTypes.TRTData;
  562. begin
  563.   Result := TRTData.Create;
  564.   SetLength(Result.Variables, 13);
  565.   Result.Variables[0].Name   := 'Model';
  566.   Result.Variables[0].TypeID := tidMatrix4x4;
  567.   Result.Variables[1].Name   := 'View';
  568.   Result.Variables[1].TypeID := tidMatrix4x4;
  569.   Result.Variables[2].Name   := 'Projection';
  570.   Result.Variables[2].TypeID := tidMatrix4x4;
  571.   Result.Variables[3].Name   := 'ModelView';
  572.   Result.Variables[3].TypeID := tidMatrix4x4;
  573.   Result.Variables[4].Name   := 'MVP';
  574.   Result.Variables[4].TypeID := tidMatrix4x4;
  575.   Result.Variables[5].Name   := 'Light[0].Position';
  576.   Result.Variables[5].TypeID := tidVector4;
  577.   Result.Variables[6].Name   := 'Light[0].Direction';
  578.   Result.Variables[6].TypeID := tidVector4;
  579.   Result.Variables[7].Name   := 'Light[0].Ambient';
  580.   Result.Variables[7].TypeID := tidVector4;
  581.   Result.Variables[8].Name   := 'Light[0].Diffuse';
  582.   Result.Variables[8].TypeID := tidVector4;
  583.   Result.Variables[9].Name   := 'Light[0].Specular';
  584.   Result.Variables[9].TypeID := tidVector4;
  585.   Result.Variables[10].Name   := 'Material.Ambient';
  586.   Result.Variables[10].TypeID := tidVector4;
  587.   Result.Variables[11].Name   := 'Material.Diffuse';
  588.   Result.Variables[11].TypeID := tidVector4;
  589.   Result.Variables[12].Name   := 'Material.Specular';
  590.   Result.Variables[12].TypeID := tidVector4;
  591.   SetLength(Result.PIN, 1);
  592.   Result.PIN[0] := High(Result.Variables);
  593.   while (Result.PIN[0] >= 0) and (Source <> Result.Variables[Result.PIN[0]].Name) do Dec(Result.PIN[0]);
  594.   if Result.PIN[0] <= 0 then begin
  595.     FreeAndNil(Result);
  596.     LastError := 'Unknown identifier: ' + Source;
  597.     Log.Log(Format('%S.%S: The following error occured while compiling mini-script: "%S"', [ClassName, 'Compile', LastError]), lkError);
  598.   end;
  599. end;
  600. begin
  601.   GlobalClassList.Add('C2Core', GetUnitClassList);
  602. end.