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

游戏引擎

开发平台:

Delphi

  1. (*
  2.  @Abstract(CAST II Engine render 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 API-independent basic renderer classes
  6. *)
  7. {$Include GDefines.inc}
  8. {$Include C2Defines.inc}
  9. unit C2Render;
  10. interface
  11. uses
  12.   SysUtils,
  13.   BaseTypes, BaseMsg, Basics, Base3D, OSUtils, Base2D, Resources,
  14.   TextFile,
  15.   BaseClasses, ItemMsg, C2Types, CAST2, C2Visual, C2Materials, C2DebugTess, C2Res, C2Msg;
  16. const
  17.   // max X coordinate of window to consider it off-screen
  18.   OffScreenX = -10000;
  19.   // max Y coordinate of window to consider it off-screen
  20.   OffScreenY = -10000;
  21.   // Maximum number of vertex buffer with different vertex sizes
  22.   MaxVertexBuffers = 64;
  23.   // Size of indices
  24.   IndicesSize = 2;
  25. type
  26.   { Data structure used to represent a locked rectangular area of some data
  27.     Data  - pointer to actual data
  28.     Pitch - offset in bytes between two rows of data }
  29.   TLockedRectData = record
  30.     Data:  Pointer;
  31.     Pitch: Integer;
  32.   end;
  33.   // Renderer states
  34.   TRendererState = (// Renderer is ready
  35.                     rsOK,
  36.                     // Renderer is in process of initialization
  37.                     rsNotReady,
  38.                     // Renderer has lost device and will try to restore it (DirectX-specific)
  39.                     rsLost,
  40.                     // Renderer has not been initialized
  41.                     rsNotInitialized);
  42. {  // Create viewport results
  43.   TViewportCreateResult = (// Success
  44.                            cvOK,
  45.                            // Device has been lost (DirectX-specific)
  46.                            cvLost,
  47.                            // Error occured
  48.                            cvError);}
  49.   // Hardware acceleration level (DirectX only)
  50.   THWAccelLevel = (// Software vertex processing
  51.                   haSoftwareVP,
  52.                   // Mixed vertex processing
  53.                   haMixedVP,
  54.                   // Hardware vertex processing
  55.                   haHardwareVP,
  56.                   // Pure device
  57.                   haPureDevice);
  58.   TAppRequirementsFlag = (// Use stencil buffering
  59.                           arUseStencil,
  60.                           // Use Z-buffering
  61.                           arUseZBuffer,
  62.                           // Forces vertcial syncronization on
  63.                           arForceVSync,
  64.                           // Forces vertcial syncronization off
  65.                           arForceNoVSync,
  66.                           // Tells API that it will be used from several threads
  67.                           arMultithreadedRender,
  68.                           // Tells API to not change FPU state within its routines
  69.                           arPreserveFPU,
  70.                           // Includes modes with all refresh rates in available video modes list
  71.                           arModesUseRefresh,
  72.                           // Tells API that backbuffer contents should not be changed or discarded between frames. May be slow on some configurations.
  73.                           arPreserveBackBuffer,
  74.                           // Tells API that backbuffer should be lockable
  75.                           arLockableBackBuffer);
  76.   { Application requirements record. These values can be changed before renderer initialization to change its behaviour. <br>
  77.     <b>Flags</b>                - <b>[arUseStencil, arUseZBuffer]</b> by default. <br>
  78.     <b>MinYResolution</b>       - minimal vertical resolution of modes to iclude in available video modes list. <b>480</b> by default. <br>
  79.     <b>HWAccelerationLevel</b>  - level of hardware acceleration required. <b>haMixedVP</b> by default. <br>
  80.     <b>TotalBackBuffers</b>     - number of back buffers required. <b>1</b> by default. }
  81.   TAppRequirements = record
  82.     Flags: set of TAppRequirementsFlag;
  83.     MinYResolution: Cardinal;
  84.     HWAccelerationLevel: THWAccelLevel;
  85.     TotalBackBuffers: Cardinal;
  86.   end;
  87.   { Video mode data structure. <br>
  88.     <b>Width, Height</b> - horizontal and vertical resolution. <br>
  89.     <b>RefreshRate</b>   - refresh rate. <br>
  90.     <b>Format</b>        - pixel format. }
  91.   TVideoMode = packed record
  92.     Width, Height: Integer;
  93.     RefreshRate  : Integer;
  94.     Format       : Integer;
  95.   end;
  96.   // Array of video modes
  97.   TVideoModes = array of TVideoMode;
  98.   // Gamma ramp
  99.   TGammaRamp = record
  100.     R, G, B: array[0..255] of Word;
  101.   end;
  102.   // Viewport
  103.   TViewPort = packed record
  104.     X, Y, Width, Height: Longword;
  105.     MinZ, MaxZ: Single;
  106.   end;
  107.   // Texture option flags
  108.   TTextureOptionFlag = (// Texture should be immediately loaded
  109.                         toImmediateLoad,
  110.                         // Texture is not managed by an API [b](currently unsupported)[/b]
  111.                         toNonAPIManaged,
  112.                         // Texture is a cube map [b](currently unsupported)[/b]
  113.                         toCubeMap,
  114.                         // Texture is procedurally generated at runtime
  115.                         toProcedural);
  116.   // Texture option set
  117.   TTextureOptions = set of TTextureOptionFlag;
  118.   // Texture
  119.   TTexture = record
  120.     Texture: Pointer;
  121.     Format : Cardinal;
  122.     Options: TTextureOptions;
  123.     Width, Height, Depth, Levels: Integer;
  124.     LastUseFrame: Integer;
  125.     Resource: TImageResource;
  126.   end;
  127.   // Render target
  128.   TRenderTarget = record
  129.     ColorBuffer, DepthBuffer, ColorTexture, DepthTexture: Pointer;
  130.     ColorFormat, DepthFormat, ActualColorFormat, ActualDepthFormat: Integer;
  131.     Width, Height: Integer;
  132.     LastUpdateFrame, LastUseFrame: Integer;
  133.     IsDepthTexture: Boolean;
  134.   end;
  135.   TRenderTargets = array of TRenderTarget;
  136.   // Shader
  137.   TShader = record
  138.     Shader: Integer;                                  // API-specific shader ID
  139.     LastUseFrame: Integer;
  140.     Resource: TShaderResource;
  141.   end;
  142.   TShaders = array of TShader;
  143.   // Renderer errors enumeration type
  144.   TRendererError = (// No error
  145.                     reNone,
  146.                     // Number of texture stages in a pass exceeding renderer capabilities (see @Link(MaxTextureStages))
  147.                     reTooManyStages,
  148.                     // Number of textures used in a pass exceeding renderer capabilities (see @Link(MaxTexturesPerPass))
  149.                     reTooManyTextures,
  150.                     // Vertex shader compilation failed
  151.                     reVertexShaderAssembleFail,
  152.                     // Vertex shader creation failed
  153.                     reVertexShaderCreateFail,
  154.                     // Pixel shader compilation failed
  155.                     rePixelShaderAssembleFail,
  156.                     // Pixel shader creation failed
  157.                     rePixelShaderCreateFail,
  158.                     // Depth textures unsupported
  159.                     reNoDepthTextures);
  160.   TRenderer = class;
  161.   // API-specific vertex and index buffers management class
  162.   TAPIBuffers = class
  163.   protected
  164.     // Reference to renderer object
  165.     Renderer: TRenderer;
  166.   public
  167.     constructor Create(ARenderer: TRenderer);
  168.     destructor Destroy; override;
  169.     // Returns a flexible vrtex format code from CAST vertex format
  170. //    function GetFVF(CastVertexFormat: Cardinal): Cardinal; virtual; abstract;
  171.     { Creates a vertex buffer with the given size in bytes and returns its internal index or -1 if creation fails.
  172.       If <b>Static</b> is <b>False</b> the buffer will be optimized to store dynamic geometry. }
  173.     function CreateVertexBuffer(Size: Integer; Static: Boolean): Integer; virtual; abstract;
  174.     { Creates an index buffer with the given size in bytes and returns its internal index or -1 if creation fails
  175.       If <b>Static</b> is <b>False</b> the buffer will be optimized to store dynamic data. }
  176.     function CreateIndexBuffer(Size: Integer; Static: Boolean): Integer; virtual; abstract;
  177.     // Changes size of the given vertex buffer to the given size and returns <b>True</b> if success
  178.     function ResizeVertexBuffer(Index: Integer; NewSize: Integer): Boolean; virtual; abstract;
  179.     // Changes size of the given index buffer to the given size and returns <b>True</b> if success
  180.     function ResizeIndexBuffer(Index: Integer; NewSize: Integer): Boolean; virtual; abstract;
  181.     { Locks the given range in a vertex buffer with the given index and returns a write-only pointer to the range data or <b>nil</b> if lock fails.
  182.       If <b>DiscardExisting</b> is <b>True</b> existing data in the buffer will be discarded to avoid stalls. }
  183.     function LockVertexBuffer(Index: Integer; Offset, Size: Integer; DiscardExisting: Boolean): Pointer; virtual; abstract;
  184.     { Locks the given range in a index buffer with the given index and returns a write-only pointer to the range data or <b>nil</b> if lock fails.
  185.       If <b>DiscardExisting</b> is <b>True</b> existing data in the buffer will be discarded to avoid stalls. }
  186.     function LockIndexBuffer(Index: Integer; Offset, Size: Integer; DiscardExisting: Boolean): Pointer; virtual; abstract;
  187.     // Unlocks a previously locked vertex buffer
  188.     procedure UnlockVertexBuffer(Index: Integer); virtual; abstract;
  189.     // Unlocks a previously locked index buffer
  190.     procedure UnlockIndexBuffer(Index: Integer); virtual; abstract;
  191.     // Attaches a vertex buffer to the specified data stream and returns <b>True</b> if success. <b>VertexSize</b> should match the size of the data in the buffer.
  192.     function AttachVertexBuffer(Index, StreamIndex: Integer; VertexSize: Integer): Boolean; virtual; abstract;
  193.     // Attaches an index buffer and returns <b>True</b> if success. <b>StartingVertex</b> will be added to all indices read from the index buffer.
  194.     function AttachIndexBuffer(Index: Integer; StartingVertex: Integer): Boolean; virtual; abstract;
  195.     // Frees all allocated buffers. All internal indices returned before this call become invalid.
  196.     procedure Clear; virtual; abstract;
  197.   end;
  198.   // API-independent buffer structure
  199.   TBuffer = record
  200.     Index, Size: Integer;
  201.     Position: Integer;
  202.     ResetCounter: Integer;
  203.   end;
  204.   // API independent vertex and index buffers management class
  205.   TBuffers = class
  206.   private
  207.     Buffers: array[TTesselationBuffer, Boolean, 0..MaxVertexBuffers-1] of TBuffer;
  208.     ResetCounter: Integer;
  209.     Renderer: TRenderer;
  210.     procedure ResetBuffers;
  211.   public
  212.     constructor Create(ARenderer: TRenderer);
  213.     destructor Destroy; override;
  214.     // Puts the given tesselator to an appropriate buffer pair
  215.     function Put(Tesselator: TTesselator): Boolean;
  216.     // Clears and reallocates all allocated buffers
  217.     procedure Reset;
  218.   end;
  219.   TTextureArray = array of TTexture;
  220.   TTextures = class
  221.   private
  222.   protected
  223.     Renderer: TRenderer;
  224.     FTextures: TTextureArray;
  225.     // Returns <b>True</b> if the specified texture is not initialized
  226.     function IsEmpty(const Element: TTexture): Boolean;
  227.     // Deletes all textures
  228.     procedure FreeAll;
  229.     // Calls an API to create API-specific texture object 
  230.     function APICreateTexture(Index: Integer): Boolean; virtual; abstract;
  231.     // Calls an API to destroy API-specific texture object
  232.     procedure APIDeleteTexture(Index: Integer); virtual; abstract;
  233.   public
  234.     destructor Destroy; override;
  235.     // Handles some related messages
  236.     procedure HandleMessage(const Msg: TMessage);
  237.     // Adds a new texture entry. Does not create any API-specific objects.
  238.     function NewTexture(Resource: TImageResource; Options: TTextureOptions): Integer;
  239.     // Adds a new procedural texture entry. Does not create any API-specific objects.
  240.     function NewProceduralTexture(AFormat: Cardinal; AWidth, AHeight, ADepth, ALevels: Integer; Options: TTextureOptions): Integer;
  241.     // Loads the specified by index texture from its associated resource. Returns <b>True</b> if success.
  242.     function Load(Index: Integer): Boolean;
  243.     // Unloads the specified by index texture from API. <b>Currently not implemented.</b>
  244.     procedure Unload(Index: Integer); virtual; abstract;
  245.     // Updates the specified rectangle of the specified by index texture in API from the given pointer. Returns <b>True</b> if success.
  246.     function Update(Index: Integer; Src: Pointer; Rect: BaseTypes.PRect3D): Boolean; virtual; abstract;
  247.     // Reads the specified rectangle of the specified by index texture in API to the given pointer. Returns <b>True</b> if success. <b>Currently not implemented.</b>
  248.     function Read(Index: Integer; Dest: Pointer; Rect: BaseTypes.PRect3D): Boolean; virtual; abstract;
  249.     // Removes the specified texture
  250.     procedure Delete(Index: Integer); 
  251.     // Resolves a texture for the given pass. Used internally.
  252.     function Resolve(Pass: TRenderPass; StageIndex: Integer): Boolean;
  253.     // Applies texture with the specified index to the specified API stage
  254.     procedure Apply(Stage, Index: Integer); virtual; abstract;
  255.     // Locks the specified area of the specified level of the specified texture. This call should be accompanied by a corresponding @Link(Unlock) call.
  256.     function Lock(AIndex, AMipLevel: Integer; const ARect: BaseTypes.PRect; out LockRectData: TLockedRectData; LockFlags: TLockFlags): Boolean; virtual; abstract;
  257.     // Unlocks previously locked texture
  258.     procedure UnLock(AIndex, AMipLevel: Integer); virtual; abstract;
  259.   end;
  260.   // API-dependent class which wraps render state
  261.   TAPIStateWrapper = class
  262.   private
  263.     DefaultCamera: TCamera;
  264.     function NewRenderTarget(const Camera: TCamera): Integer;
  265.     function CreateShader(var Shaders: TShaders; Item: TShaderResource): Integer;
  266.     procedure RemoveRenderTarget(Index: Integer);
  267.   protected
  268.     // Reference to renderer
  269.     Renderer: TRenderer;
  270.     // Last renderer error. Used for pass validation.
  271.     LastError: TRendererError;
  272.     //    TotalTextures: Integer;
  273.     // Render targets
  274.     FRenderTargets: TRenderTargets;
  275.     // Shaders
  276.       public                 // ToFix: make it protected
  277.         FVertexShaders, FPixelShaders: TShaders;
  278.       protected
  279.     // Current camera (same as Renderer.@Link(LastAppliedCamera))
  280.     Camera: CAST2.TCamera;
  281.     // True if texture matrix was set for a certain stage
  282.     StageMatrixSet: array[0..7] of Boolean;
  283.     // Clip planes state
  284.     ClipPlanesState: Cardinal;
  285.     // Performance profile
  286.     FPerfProfile: TPerfProfile;
  287.     // Returns <b>True</b> if the specified render target is not initialized
  288.     function IsRenderTargetEmpty(const Element: TRenderTarget): Boolean;
  289.     // Returns <b>True</b> if the specified shader is not initialized
  290.     function IsShaderEmpty(const Element: TShader): Boolean;
  291.     // Calls an API to create a render target with given parameters. DepthStencil surface will be created if <b>ADepthFormat</b> is other than @Link(pfUndefined). Returns <b>True</b> if success.
  292.     function APICreateRenderTarget(Index, Width, Height: Integer; AColorFormat, ADepthFormat: Cardinal): Boolean; virtual; abstract;
  293.     // Ensures that all parameters are correct and supported and calls @Link(APICreateRenderTarget). Returns <b>True</b> if a render target been created.
  294.     function CreateRenderTarget(Index, Width, Height: Integer; AColorFormat, ADepthFormat: Cardinal; ADepthTexture: Boolean): Boolean;
  295.     // Destroys the specified by index render target
  296.     procedure DestroyRenderTarget(Index: Integer); virtual; abstract;
  297.       public        // ToFix: make it protected
  298.         // Return a render target for the given camera. If render target does not exists the function creates it.
  299.         function FindRenderTarget(const ACamera: TCamera): Integer;
  300.         // Returns <b>True</b> if there is no need to update render target texture associated with Camera
  301.         function IsRenderTargetUptoDate(const ACamera: TCamera): Boolean;
  302.       protected
  303.     // Sets current render target to the one associated with <b>Camera</b>. Returns <b>True</b> if actual change was made.
  304.     function SetRenderTarget(const ACamera: TCamera; TextureTarget: Boolean): Boolean; virtual; abstract;
  305.       public        // ToFix: make it protected
  306.         // Resolves a vertex shader for the given pass. Used internally.
  307.         function ResolveVertexShader(Pass: TRenderPass): Boolean;
  308.       protected
  309.     // Resolves a pixel shader for the given pass. Used internally.
  310.     function ResolvePixelShader(Pass: TRenderPass): Boolean;
  311.     // Creates a vertex shader from the resource with the given vertex declaration
  312.     function CreateVertexShader(Item: TShaderResource; Declaration: TVertexDeclaration): Integer; virtual;
  313.     // Creates a pixel shader from the resource
  314.     function CreatePixelShader(Item: TShaderResource): Integer; virtual;
  315.     // Calls an API to set a shader constant
  316.     procedure APISetShaderConstant(const Constant: TShaderConstant); overload; virtual; abstract;
  317.     // Calls an API to set a shader constant. <b>ShaderKind</b> - kind of shader, <b>ShaderRegister</b> - index of 4-component vector register to set, <b>Vector</b> - new value of the register.
  318.     procedure APISetShaderConstant(ShaderKind: TShaderKind; ShaderRegister: Integer; const Vector: TShaderRegisterType); overload; virtual; abstract;
  319.     { Calls an API to validate the specified pass. Returns <b>True</b> if the pass is can be handled by current hardware.
  320.       Otherwise returns <b>False</b> and fills <b>ResultStr</b> a text representation of the error occured. }
  321.     function APIValidatePass(const Pass: TRenderPass; out ResultStr: string): Boolean; virtual; abstract;
  322.     // Applies texture matrix of each texture stage of the specified render pass
  323.     procedure ApplyTextureMatrices(const Pass: TRenderPass); virtual; abstract;
  324.     // Applies current clipping planes
  325.     procedure ApplyClipPlanes;
  326.     // Handle removal or replace of some item from scene
  327.     procedure HandleItemReplace(OldItem, NewItem: TItem); virtual;
  328.     // Handle data change of renderer-related items
  329.     procedure HandleDataChange(Data: Pointer); virtual;
  330.   public
  331.     // Vertex shader usage flag. Used internally.
  332.     VertexShaderFlag,
  333.     // Pixel shader usage flag. Used internally.
  334.     PixelShaderFlag: Boolean;
  335.     constructor Create;
  336.     destructor Destroy; override;
  337.     // Handles some related messages
  338.     procedure HandleMessage(const Msg: TMessage);
  339.     // Sets fog kind, color, start/end and density
  340.     procedure SetFog(Kind: Cardinal; Color: BaseTypes.TColor; AFogStart, AFogEnd, ADensity: Single); virtual; abstract;
  341.     // Sets alpha blending mode and alpha test settings
  342.     procedure SetBlending(Enabled: Boolean; SrcBlend, DestBlend, AlphaRef, ATestFunc, Operation: Integer); virtual; abstract;
  343.     // Sets Z-buffer related values
  344.     procedure SetZBuffer(ZTestFunc, ZBias: Integer; ZWrite: Boolean); virtual; abstract;
  345.     // Sets culling, shading and filling modes as well as color write mask
  346.     procedure SetCullAndFillMode(FillMode, ShadeMode, CullMode: Integer; ColorMask: Cardinal); virtual; abstract;
  347.     // Sets stencil state
  348.     procedure SetStencilState(SFailOp, ZFailOp, PassOp, STestFunc: Integer); virtual; abstract;
  349.     // Sets stencil reference value and masks
  350.     procedure SetStencilValues(SRef, SMask, SWriteMask: Integer); virtual; abstract;
  351.     // Sets texture wrapping mode
  352.     procedure SetTextureWrap(const CoordSet: TTWrapCoordSet); virtual; abstract;
  353.     // Set lighting settings
  354.     procedure SetLighting(Enable: Boolean; AAmbient: BaseTypes.TColor; SpecularMode: Integer; NormalizeNormals: Boolean); virtual; abstract;
  355.     // Sets edge and points settings
  356.     procedure SetEdgePoint(PointSprite, PointScale, EdgeAntialias: Boolean); virtual; abstract;
  357.     // Sets texture factor color
  358.     procedure SetTextureFactor(ATextureFactor: BaseTypes.TColor); virtual; abstract;
  359.     // Sets API-level material (ambient, diffuse, specular and emissive colors and specular power)
  360.     procedure SetMaterial(const AAmbient, ADiffuse, ASpecular, AEmissive: BaseTypes.TColor4S; APower: Single); virtual; abstract;
  361.     // Sets points size parameters
  362.     procedure SetPointValues(APointSize, AMinPointSize, AMaxPointSize, APointScaleA, APointScaleB, APointScaleC: Single); virtual; abstract;
  363.     // Sets line pattern
  364.     procedure SetLinePattern(ALinePattern: Longword); virtual; abstract;
  365.     // Applies a clipping plane
  366.     procedure SetClipPlane(Index: Cardinal; Plane: PPlane); virtual; abstract;
  367.     // Sets a shader constant
  368.     procedure SetShaderConstant(const Constant: TShaderConstant); overload;
  369.     // Sets a shader constant. <b>ShaderKind</b> - kind of shader, <b>ShaderRegister</b> - index of 4-component vector register to set, <b>Vector</b> - new value of the register.
  370.     procedure SetShaderConstant(ShaderKind: TShaderKind; ShaderRegister: Integer; const Vector: TShaderRegisterType); overload;
  371.     // Validate the specified pass. Returns <b>True</b> if the pass is valid
  372.     function ValidatePass(const Pass: TRenderPass): Boolean;
  373.     // Applies the specified render pass
  374.     procedure ApplyPass(const Pass: TRenderPass); virtual; abstract;
  375.     // Applies item-specific custom texture matrix of each texture stage of the specified render pass
  376.     procedure ApplyCustomTextureMatrices(const Pass: TRenderPass; Item: TVisible); virtual; abstract;
  377.   end;
  378.   { @Abstract(Renderer class)
  379.     Contains API-independent routines and an interface fo API-dependent ones }
  380.   TRenderer = class(TSubsystem)
  381.   private
  382.     procedure SetDebugOutput(const Value: Boolean);
  383.     function GetAdapterName(Index: Cardinal): string;
  384.     function GetVideoMode(Index: Cardinal): TVideoMode;
  385.     function GetRenderTargetsAllocated: Integer;
  386.   protected
  387.     // This record passed to tesselators buffer filling methods
  388.     TesselationParams: TTesselationParameters;
  389.     // Performance profile
  390.     FPerfProfile: TPerfProfile;
  391.     // Number of frames rendered
  392.     FFramesRendered: Integer;
  393.     // API-specific buffer management object
  394.     APIBuffers: TAPIBuffers;
  395.     // API-independent buffer management object
  396.     Buffers: TBuffers;
  397.     
  398.     // Reference to items manager
  399.     Manager: TItemsManager;
  400.     // Current video adapter
  401.     FCurrentAdapter,
  402.     // Number of video adapters in system
  403.     FTotalAdapters: Cardinal;
  404.     // Names of video adapters in system
  405.     FAdapterNames: array of string;
  406.     // Current video mode index in @Link(FVideoModes) array
  407.     FCurrentVideoMode,
  408.     // Number of video modes available
  409.     FTotalVideoModes: Cardinal;
  410.     // Video modes available
  411.     FVideoModes: TVideoModes;
  412.     // Current desktop video mde
  413.     DesktopVideoMode: TVideoMode;
  414.     // Handle of render window
  415.     RenderWindowHandle: Cardinal;
  416.     // Current viewport
  417.     ViewPort: TViewPort;
  418.     // Full screen mode state
  419.     FFullScreen,
  420.     // Debug output state
  421.     FDebugOutput: Boolean;
  422.     // Tesselators for primitives used in debug rendering
  423.     DebugTesselators: array of TTesselator;
  424.     // Material for debug rendering
  425.     DebugMaterial: TMaterial;
  426.     // Last applied camera
  427.     FLastAppliedCamera,
  428.     // Top-level camera through which a scene is visible for user
  429.     FMainCamera: CAST2.TCamera;
  430.     // Current gamma ramp
  431.     GammaRamp: TGammaRamp;
  432.     // Current renderer state
  433.     FState: TRendererState;
  434.     // Current depth of Z-buffer
  435.     FCurrentZBufferDepth: Cardinal;
  436.     // Rendering area in windowed mode
  437.     FWindowedRect: TRect;
  438.     // Window style in not full-screen mode
  439.     FNormalWindowStyle: Cardinal;
  440.     // For internal use only
  441.     procedure InternalInit;
  442.     // For internal use only
  443.     procedure InternalDeInit; virtual;
  444.     // For internal use only
  445.     function InternalGetIndexBufferIndex(Static: Boolean; BufferIndex: Integer): Integer;
  446.     // Calls an API to initialize render device for rendering to the specified window or specified video mode
  447.     function APICreateDevice(WindowHandle, AVideoMode: Cardinal; AFullScreen: Boolean): Boolean; virtual; abstract;
  448.     // Calls an API to set item's transformation, some FVF-related states
  449.     procedure APIPrepareFVFStates(Item: TVisible); virtual; abstract;
  450.     { Returns <b>True</b> if a pixel format is available and can be used as a texture, render target or depth-stencil buffer.
  451.       <b>RTFormat</b> is used only with depth-stencil usage to determine whether the supported depth-stencil format can be used with the given render target format. }
  452.     function APICheckFormat(const Format, Usage, RTFormat: Cardinal): Boolean; virtual; abstract;
  453.     // Returns CAST pixel format from an API-specific one
  454.     function APIToPixelFormat(Format: Cardinal): Cardinal;
  455.     // Toggles fullscreen mode
  456.     procedure SetFullScreen(const FScreen: Boolean); virtual;
  457.     // Prepares render window for windowed rendering
  458.     function PrepareWindow: Boolean;
  459.   public
  460.     // Renderer performs rendering only if this variable is <b>True</b>. <b>Active</b> is set automatically in response on window minimization or switching to another application in fullscreen mode.
  461.     Active: Boolean;
  462.     // Current render window width
  463.     RenderWidth,
  464.     // Current render window height
  465.     RenderHeight: Integer;
  466.     // If set to True data existing in vertex/index buffers are always considered as valid and no tesselation will be performed
  467.     DisableTesselation: Boolean;
  468.     // Application requirements record. These values can be changed before renderer initialization to change its behaviour.
  469.     AppRequirements: TAppRequirements;
  470.       // Capabilites
  471.     // Maximum number of light sources simultaneously handled by hardware T&L (fixed function pipeline only)
  472.     MaxHardwareLights,
  473.     // Maximum number of light sources which may be simultaneously set through API
  474.     MaxAPILights: Cardinal;
  475.     // Maximum supported texture width
  476.     MaxTextureWidth,
  477.     // Maximum supported texture height
  478.     MaxTextureHeight: Integer;
  479.     // Maximum number of textures which may be used in a pass
  480.     MaxTexturesPerPass,
  481.     // Maximum number of texture stages which may be used in a pass
  482.     MaxTextureStages: Integer;
  483.     // Maximum number of primitives per single API call (DIP)
  484.     MaxPrimitiveCount,
  485.     // Maximum index value in index buffer
  486.     MaxVertexIndex: Integer;
  487.     // Maximum number of user clipping planes
  488.     MaxClipPlanes: Integer;
  489.     // <b>True</b> if even transformed vertices are clipped by hardware (DirectX only, seems incorrect)
  490.     HardwareClipping,
  491.     // <b>True</b> if w-buffering is supported
  492.     WBuffering,
  493.     // <b>True</b> if only power of two-sized textures are supported
  494.     Power2Textures,
  495.     // <b>True</b> if only square textures are supported
  496.     SquareTextures,
  497.     // <b>True</b> if depth textures are supported
  498.     DepthTextures: Boolean;
  499.     // Maximum point size
  500.     MaxPointSize: Single;
  501.     // Major vertex shader version
  502.     VertexShaderVersionMajor,
  503.     // Minor vertex shader version
  504.     VertexShaderVersionMinor,
  505.     // Major pixel shader version
  506.     PixelShaderVersionMajor,
  507.     // Minor pixel shader version
  508.     PixelShaderVersionMinor: Integer;
  509.     // Max vertex shader constants
  510.     MaxVertexShaderConsts: Integer;
  511.     // Textures
  512.     Textures: TTextures;
  513.     // Reference to API state wrapper object
  514.     APIState: TAPIStateWrapper;
  515.     // Bias matrix used to remap texture coordinates for mirror and shadow map modes
  516.     BiasMat: TMatrix4s;
  517.     constructor Create(AManager: TItemsManager); virtual;
  518.     destructor Destroy; override;
  519.     // Sets performance profile
  520.     procedure SetPerfProfile(APerfProfile: TPerfProfile); virtual;
  521.     // Sets video adapter
  522.     procedure SetVideoAdapter(Adapter: Cardinal);
  523.     // Build available video modes list
  524.     procedure BuildModeList; virtual; abstract;
  525.     // Initializes debug tesselators and material
  526.     procedure InitDebugRender(ADebugMaterial: TMaterial); virtual;
  527.     // Returns <b>True</b> if the renderer is ready to render
  528.     function IsReady: Boolean;
  529.     // Adjusts gamma ramp
  530.     procedure SetGamma(Gamma, Contrast, Brightness: Single); virtual;
  531.     // Default message handling
  532.     procedure HandleMessage(const Msg: TMessage); override;
  533.     // Checks capabilities
  534.     procedure CheckCaps; virtual; abstract;
  535.     // Checks available texture formats
  536.     procedure CheckTextureFormats; virtual; abstract;
  537.     { Checks if the given pixel format is supported for the given usage. RTFormat is used only with depth-stencil
  538.       usage to determine whether the supported depth-stencil format can be used with the given render target format.
  539.       Returns False if the pixel format is unsupported. Also fills NewFormat with suggested substitue or with pfUndefined if no suitable substitution found. }
  540.     function CheckFormat(const Format, Usage, RTFormat: Cardinal; out NewFormat: Integer): Boolean; virtual;
  541.     // Validates all techniques of the given material for current hardware configuration. Returns <b>True</b> if the set of available techniques changed during validation.
  542.     function ValidateMaterial(const Material: TMaterial): Boolean;
  543.     // Initializes render device to render to the specified window or specified mode
  544.     function CreateDevice(WindowHandle, AVideoMode: Cardinal; AFullScreen: Boolean): Boolean;
  545.     // Restores render device with the specified video mode (if fullscreen)
  546.     function RestoreDevice(AVideoMode: Cardinal; AFullScreen: Boolean): Boolean; virtual;
  547.     // Starts a rendering cycle
  548.     procedure StartFrame; virtual;
  549.     // Ends a rendering cycle
  550.     procedure FinishFrame; virtual; abstract;
  551.     // Clear the specified parts of current render target with the specified values
  552.     procedure Clear(Flags: TClearFlagsSet; Color: BaseTypes.TColor; Z: Single; Stencil: Cardinal); virtual; abstract;
  553.     // Apply a light source with the specified index
  554.     procedure ApplyLight(Index: Integer; const ALight: TLight); virtual; abstract;
  555.     // Applies render target settings, transformations, clear settings of the given camera to the renderer
  556.     procedure ApplyCamera(Camera: CAST2.TCamera); virtual;
  557.     // Projects <b>Vector</b> with @Link(MainCamera) and returns the result in <b>Projected</b>
  558.     procedure ProjectToScreen(out Projected: TVector4s; const Vector: TVector3s);
  559.     // Sets render viewport
  560.     procedure SetViewPort(const X, Y, Width, Height: Integer; const MinZ, MaxZ: Single); virtual;
  561.     // Performs necessary API calls to render a piece of triangles
  562.     procedure APIRenderStrip(Tesselator: TTesselator; StripIndex: Integer); virtual; abstract;
  563.     // Performs necessary API calls to render a piece of indexed triangles
  564.     procedure APIRenderIndexedStrip(Tesselator: TTesselator; StripIndex: Integer); virtual; abstract;
  565.     // Renders the specified tesselator
  566.     procedure RenderTesselator(Tesselator: TTesselator);
  567.     // Ensures that vertex/index buffers contains an up-to-date representation of the specified item, calls @Link(APIPrepareItem()) and renders it's tesselator
  568.     procedure RenderItem(Item: TVisible);
  569.     // Renders item's bounding box
  570.     procedure RenderItemBox(Item: CAST2.TProcessing; Color: BaseTypes.TColor); virtual; abstract;
  571.     // Renders item's debug information (currently colliding volumes if present)
  572.     procedure RenderItemDebug(Item: CAST2.TProcessing); virtual; abstract;
  573.     
  574.     // Full screen mode state
  575.     property FullScreen: Boolean read FFullScreen write SetFullScreen;
  576.     // Debug output state
  577.     property DebugOutput: Boolean read FDebugOutput write SetDebugOutput;
  578.     // Number of frames rendered
  579.     property FramesRendered: Integer read FFramesRendered;
  580.     // Camera through which a scene is rendered. Can't be changed during frame visulization.
  581.     property MainCamera:   CAST2.TCamera read FMainCamera write FMainCamera;
  582.     // Currently applyed camera. May change during frame visulization (if render to texture used).
  583.     property LastAppliedCamera: CAST2.TCamera read FLastAppliedCamera;
  584.     // Number of video adapters in system
  585.     property TotalAdapters: Cardinal read FTotalAdapters;
  586.     // Current video adapter
  587.     property CurrentAdapter: Cardinal read FCurrentAdapter;
  588.     // Names of video adapters in system by index
  589.     property AdapterName[Index: Cardinal]: string read GetAdapterName;
  590.     // Number of video modes available
  591.     property TotalVideoModes: Cardinal read FTotalVideoModes;
  592.     // Current video mode index in @Link(FVideoModes) array
  593.     property CurrentVideoMode: Cardinal read FCurrentVideoMode;
  594.     // Video modes available by index
  595.     property VideoMode[Index: Cardinal]: TVideoMode read GetVideoMode;
  596.     // Current renderer state
  597.     property State: TRendererState read FState;
  598.     // Rendering area in windowed mode
  599.     property WindowedRect: TRect read FWindowedRect;
  600.     // Current depth of Z-buffer
  601.     property CurrentZBufferDepth: Cardinal read FCurrentZBufferDepth;
  602.     // Additional render targets currently allocated
  603.     property TotalRenderTargets: Integer read GetRenderTargetsAllocated;
  604.   end;
  605. implementation
  606. const
  607.   // Debug tesselator indices
  608.   dtiBox = 0; dtiSphere = 1;
  609. type
  610.   TRenderTargetEmptyDelegate = function(const Element: TRenderTarget): Boolean of object;
  611.   TTextureEmptyDelegate      = function(const Element: TTexture): Boolean of object;
  612.   TShaderEmptyDelegate       = function(const Element: TShader): Boolean of object;
  613. function ResourceAdd_RenderTarget(var Elements: TRenderTargets; IsEmpty: TRenderTargetEmptyDelegate): Integer;
  614. begin {$Include C2RenderResourceAdd.Inc} end;
  615. function ResourceAdd_Texture(var Elements: TTextureArray; IsEmpty: TTextureEmptyDelegate): Integer;
  616. begin {$Include C2RenderResourceAdd.Inc} end;
  617. function ResourceAdd_Shader(var Elements: TShaders; IsEmpty: TShaderEmptyDelegate): Integer;
  618. begin {$Include C2RenderResourceAdd.Inc} end;
  619. { TAPIBuffers }
  620. constructor TAPIBuffers.Create(ARenderer: TRenderer);
  621. begin
  622.   Renderer := ARenderer;
  623. end;
  624. destructor TAPIBuffers.Destroy;
  625. begin
  626.   Clear;
  627.   inherited;
  628. end;
  629. { TBuffers }
  630. procedure TBuffers.ResetBuffers;
  631. var i: TTesselationBuffer; j: Integer;
  632. begin
  633.   for i := Low(TTesselationBuffer) to High(TTesselationBuffer) do for j := 0 to High(Buffers[i, True]) do begin
  634.     Buffers[i, False, j].Index        :=-1;
  635.     Buffers[i, False, j].Size         := 0;
  636.     Buffers[i, False, j].Position     := 0;
  637.     Buffers[i, False, j].ResetCounter := 0;
  638.     Buffers[i, True, j].Index        :=-1;
  639.     Buffers[i, True, j].Size         := 0;
  640.     Buffers[i, True, j].Position     := 0;
  641.     Buffers[i, True, j].ResetCounter := 0;
  642.   end;
  643. end;
  644. constructor TBuffers.Create(ARenderer: TRenderer);
  645. begin
  646.   ResetCounter := 1;
  647.   Renderer := ARenderer;
  648.   ResetBuffers;
  649. end;
  650. destructor TBuffers.Destroy;
  651. begin
  652. //  Reset;
  653.   inherited;
  654. end;
  655. function TBuffers.Put(Tesselator: TTesselator): Boolean;
  656. const
  657.   BufName: array[TTesselationBuffer] of string[6] = ('vertex',  'index');
  658.   BufTypeName: array[Boolean]         of string[7] = ('dynamic', 'static');
  659.   DefaultBufferSize: array[Boolean, TTesselationBuffer] of Integer = ((4096*4, 4096*4), (4096, 4096));
  660.   MaxBufferSize: array[Boolean, TTesselationBuffer] of Integer = ((65536*8, 65536), (65536*32, 65536*8));
  661. var
  662.   TesselatorMaxAmount, ElementSize: array[TTesselationBuffer] of Integer;
  663.   PTR: PByte; BufIndex, Amount: Integer;
  664.   function PutToBuffer(BufferType: TTesselationBuffer; Static: Boolean): Boolean;
  665.     procedure ResetAndPlaceFirst;
  666.     begin
  667.       Buffers[BufferType, Static, BufIndex].Position := TesselatorMaxAmount[BufferType];    // Increase by max amount of elements
  668.       Inc(Buffers[BufferType, Static, BufIndex].ResetCounter);
  669.       Tesselator.TesselationStatus[BufferType].Offset := 0;
  670.       Tesselator.TesselationStatus[BufferType].LastResetCounter := ResetCounter;
  671.       Tesselator.TesselationStatus[BufferType].LastBufferResetCounter := Buffers[BufferType, Static, BufIndex].ResetCounter;
  672.       Inc(Renderer.FPerfProfile.BuffersProfile[BufferType].BufferResetsCount[Static]);
  673.     end;
  674.     function CreateBuffer: Boolean;
  675.     begin
  676.       case BufferType of
  677.         tbVertex: Buffers[BufferType, Static, BufIndex].Index := Renderer.APIBuffers.CreateVertexBuffer(Buffers[BufferType, Static, BufIndex].Size, Static);
  678.         tbIndex:  Buffers[BufferType, Static, BufIndex].Index := Renderer.APIBuffers.CreateIndexBuffer( Buffers[BufferType, Static, BufIndex].Size, Static);
  679.       end;
  680.       Result := Buffers[BufferType, Static, BufIndex].Index <> -1;
  681.       if Result then Inc(Renderer.FPerfProfile.BuffersProfile[BufferType].BufferSize[Static], Buffers[BufferType, Static, BufIndex].Size);
  682.     end;
  683.     function ResizeBuffer(NewBufferSize: Integer): Boolean;
  684.     begin
  685.       Result := False;
  686.       case BufferType of
  687.         tbVertex: Result := Renderer.APIBuffers.ResizeVertexBuffer(Buffers[BufferType, Static, BufIndex].Index, NewBufferSize);
  688.         tbIndex:  Result := Renderer.APIBuffers.ResizeIndexBuffer( Buffers[BufferType, Static, BufIndex].Index, NewBufferSize);
  689.       end;
  690.       if Result then begin
  691.         Dec(Renderer.FPerfProfile.BuffersProfile[BufferType].BufferSize[Static], Buffers[BufferType, Static, BufIndex].Size);
  692.         Buffers[BufferType, Static, BufIndex].Size := NewBufferSize;
  693.         Inc(Renderer.FPerfProfile.BuffersProfile[BufferType].BufferSize[Static], Buffers[BufferType, Static, BufIndex].Size);
  694.       end;
  695.     end;
  696.   var Discard: Boolean; NewSize: Integer;
  697.   begin
  698.     Result := True;
  699.     // Check if tesselation not needed
  700.     if ( Static and                                                                    // not needed for dynamic buffers
  701.          (Tesselator.TesselationStatus[BufferType].Status = tsTesselated) and
  702.          (Renderer.DisableTesselation or (Tesselator.GetUpdatedElements(BufferType, Renderer.TesselationParams) = 0)) and
  703.          (Tesselator.TesselationStatus[BufferType].LastResetCounter >= ResetCounter) and
  704.          (Tesselator.TesselationStatus[BufferType].LastBufferResetCounter >= Buffers[BufferType, Static, BufIndex].ResetCounter) ) then begin
  705.          Inc(Renderer.FPerfProfile.BuffersProfile[BufferType].TesselationsBypassed);
  706.          Inc(Renderer.FPerfProfile.BuffersProfile[BufferType].BytesBypassed, TesselatorMaxAmount[BufferType] * ElementSize[BufferType]);
  707.          Exit;
  708.        end;
  709.     Result := False;
  710.     // Check if the tesselator never tesselated since last reset/discard or changed its size
  711.     if not Static or
  712.        (Tesselator.TesselationStatus[BufferType].Status = tsMaxSizeChanged) or
  713.        (Tesselator.TesselationStatus[BufferType].LastResetCounter < ResetCounter) or
  714.        (Tesselator.TesselationStatus[BufferType].LastBufferResetCounter < Buffers[BufferType, Static, BufIndex].ResetCounter) then begin
  715.       if Static and (Tesselator.TesselationStatus[BufferType].Status = tsMaxSizeChanged) then begin
  716.         {$IFDEF DEBUGMODE}
  717.         Log.Log('TBuffers.Put: A size-changing tesselator placed in a static buffer. Discarding buffer contents...', lkWarning);
  718.         {$ENDIF}
  719.         ResetAndPlaceFirst;
  720.         Inc(Renderer.FPerfProfile.BuffersProfile[BufferType].TesselationsPerformed[Static]);
  721.       end else begin
  722.         Tesselator.TesselationStatus[BufferType].Offset           := Buffers[BufferType, Static, BufIndex].Position;
  723.         Tesselator.TesselationStatus[BufferType].LastResetCounter := ResetCounter;
  724.         Tesselator.TesselationStatus[BufferType].LastBufferResetCounter := Buffers[BufferType, Static, BufIndex].ResetCounter;
  725.         Inc(Buffers[BufferType, Static, BufIndex].Position, TesselatorMaxAmount[BufferType]);                 // Increase by max amount of elements
  726.         Inc(Renderer.FPerfProfile.BuffersProfile[BufferType].TesselationsPerformed[Static]);
  727.       end;
  728.     end;
  729.     // Allocate a buffer if needed
  730.     if Buffers[BufferType, Static, BufIndex].Index = -1 then begin
  731.       Buffers[BufferType, Static, BufIndex].Size := MaxI(DefaultBufferSize[Static, BufferType], TesselatorMaxAmount[BufferType]) * ElementSize[BufferType];
  732.       if not CreateBuffer then Exit;
  733.     end;
  734.     Discard := False;
  735.     // Check buffer size and remaining space
  736.     if ((Tesselator.TesselationStatus[BufferType].Offset + TesselatorMaxAmount[BufferType]) * ElementSize[BufferType] > Buffers[BufferType, Static, BufIndex].Size) then
  737.       if Static or (TesselatorMaxAmount[BufferType] * ElementSize[BufferType] > Buffers[BufferType, Static, BufIndex].Size) then begin
  738.         // Resize buffer
  739.         NewSize := (Tesselator.TesselationStatus[BufferType].Offset * Ord(Static) + TesselatorMaxAmount[BufferType]) * ElementSize[BufferType];
  740.         Log.Log(Format('TBuffers.Put: Insufficient %S %S buffer size: Buffer: [%D], will try to resize to %D',
  741.                        [BufTypeName[Static], BufName[BufferType], Buffers[BufferType, Static, BufIndex].Size,
  742.                          NewSize]), lkNotice);
  743.         if NewSize <= MaxBufferSize[Static, BufferType] * ElementSize[BufferType] then begin
  744.           if not ResizeBuffer(NewSize) then Exit;
  745.           ResetAndPlaceFirst;
  746.         end else begin
  747.           Log.Log(Format('TBuffers.Put: Resize failed: Maximum %S %S buffer size reached: [%D], needed: [%D]',
  748.                          [BufTypeName[Static], BufName[BufferType], MaxBufferSize[Static, BufferType] * ElementSize[BufferType], NewSize]), lkError);
  749.           Exit;
  750.         end;
  751.       end else begin
  752.         // Reset buffer to beginning
  753.         Discard := True;
  754.         ResetAndPlaceFirst;
  755.       end;
  756.     // Lock and tesselate
  757.     case BufferType of
  758.       tbVertex: begin
  759. //        Log.Log('*** VB lock ***', lkDebug);
  760.         PTR := Renderer.APIBuffers.LockVertexBuffer(Buffers[BufferType, Static, BufIndex].Index,
  761.                                                     Tesselator.TesselationStatus[BufferType].Offset * ElementSize[BufferType],
  762.                                                     TesselatorMaxAmount[BufferType] * ElementSize[BufferType],
  763.                                                     Discard);
  764.         if PTR = nil then Exit;
  765.         Amount := Tesselator.Tesselate(Renderer.TesselationParams, PTR);
  766.         Renderer.APIBuffers.UnlockVertexBuffer(Buffers[BufferType, Static, BufIndex].Index);
  767.         Inc(Renderer.FPerfProfile.BuffersProfile[BufferType].BytesWritten[Static], Amount * ElementSize[BufferType]);
  768. //        Log.Log('*** VB unlock ***', lkdebug);
  769.         Assert(Amount <= TesselatorMaxAmount[BufferType], Format('TBuffers.Put: Tesselated amount %D is greater then maximal %D', [Amount, TesselatorMaxAmount[BufferType]]));
  770.       end;
  771.       tbIndex: begin
  772. //        Log.Log('*** IB lock ***', lkdebug);
  773.         PTR := Renderer.APIBuffers.LockIndexBuffer(Buffers[BufferType, Static, BufIndex].Index,
  774.                                                    Tesselator.TesselationStatus[BufferType].Offset * ElementSize[BufferType],
  775.                                                    TesselatorMaxAmount[BufferType] * ElementSize[BufferType],
  776.                                                    Discard);
  777.         if PTR = nil then Exit;
  778.         Amount := Tesselator.SetIndices(PTR);
  779.         TesselatorMaxAmount[BufferType] := Amount;
  780.         Renderer.APIBuffers.UnlockIndexBuffer(Buffers[BufferType, Static, BufIndex].Index);
  781. //        Log.Log('*** IB unlock ***', lkdebug);
  782.       end;
  783.     end;
  784.     Inc(Renderer.FPerfProfile.BuffersProfile[BufferType].BytesWritten[Static], Amount * ElementSize[BufferType]);
  785.     Result := TesselatorMaxAmount[BufferType] <> 0;
  786.   end;
  787. var i: TTesselationBuffer;
  788. begin
  789.   Tesselator.TesselationStatus[tbVertex].BufferIndex := Tesselator.VertexSize div 4;
  790.   Tesselator.TesselationStatus[tbIndex].BufferIndex  := 0;
  791.   ElementSize[tbVertex] := Tesselator.VertexSize;
  792.   ElementSize[tbIndex]  := IndicesSize;
  793.   for i := Low(TTesselationBuffer) to High(TTesselationBuffer) do begin
  794.     BufIndex := Tesselator.TesselationStatus[i].BufferIndex;
  795.     TesselatorMaxAmount[i] := Tesselator.GetMaxAmount(i);
  796.     if TesselatorMaxAmount[i] <> 0 then
  797.       Result := PutToBuffer(i, Tesselator.TesselationStatus[i].TesselatorType = ttStatic) else
  798.         Result := (i <> tbVertex);                      // No vertices
  799.     if not Result then Break;
  800.   end;
  801.   if Result then
  802.     Renderer.APIBuffers.AttachVertexBuffer(Buffers[tbVertex, Tesselator.TesselationStatus[tbVertex].TesselatorType = ttStatic, Tesselator.TesselationStatus[tbVertex].BufferIndex].Index, 0, Tesselator.VertexSize);
  803. end;
  804. procedure TBuffers.Reset;
  805. begin
  806.   Inc(ResetCounter);
  807.   ResetBuffers;
  808.   Renderer.FPerfProfile.OnBuffersReset;
  809.   Renderer.APIBuffers.Clear;
  810. end;
  811. { TAPIStateWrapper }
  812. function TAPIStateWrapper.CreateShader(var Shaders: TShaders; Item: TShaderResource): Integer;
  813. begin
  814.   Result := tivUnresolved;
  815.   // Check if resource is valid
  816.   if Item = nil then begin
  817.     {$IFDEF LOGGING} Log.Log('TRenderer.CreateShader: no resource specified', lkError); {$ENDIF}
  818.     Exit;
  819.   end;
  820.   Result := High(Shaders);
  821.   while (Result >= 0) and (Shaders[Result].Resource <> Item) do Dec(Result);
  822.   if Result >= 0 then Exit;                            // A shader from the given resource already created
  823.   SetLength(Shaders, Length(Shaders) + 1);
  824.   Result := High(Shaders);
  825.   Shaders[Result].Shader   := tivUnresolved;
  826.   Shaders[Result].Resource := Item;
  827. end;
  828. function TAPIStateWrapper.IsRenderTargetEmpty(const Element: TRenderTarget): Boolean;
  829. begin Result := not Assigned(Element.ColorBuffer) and not Assigned(Element.DepthBuffer); end;
  830. function TAPIStateWrapper.IsShaderEmpty(const Element: TShader): Boolean;
  831. begin Result := not Assigned(Element.Resource); end;
  832. function TAPIStateWrapper.ResolveVertexShader(Pass: TRenderPass): Boolean;
  833. var ShaderResource: TShaderResource;
  834. begin
  835.   Pass.ResolveVertexShader(ShaderResource);
  836.   if (Pass.VertexShaderIndex = sivUnresolved) and Assigned(ShaderResource) then
  837.     Pass.VertexShaderIndex := CreateVertexShader(ShaderResource, Pass.VertexDeclaration);
  838.   Result := Pass.VertexShaderIndex <> tivUnresolved;
  839. end;
  840. function TAPIStateWrapper.ResolvePixelShader(Pass: TRenderPass): Boolean;
  841. var ShaderResource: TShaderResource;
  842. begin
  843.   Pass.ResolvePixelShader(ShaderResource);
  844.   if (Pass.PixelShaderIndex = sivUnresolved) and Assigned(ShaderResource) then
  845.     Pass.PixelShaderIndex := CreatePixelShader(ShaderResource);
  846.   Result := Pass.PixelShaderIndex <> tivUnresolved;
  847. end;
  848. function TAPIStateWrapper.CreateVertexShader(Item: TShaderResource; Declaration: TVertexDeclaration): Integer;
  849. begin
  850.   Result := CreateShader(FVertexShaders, Item);
  851. end;
  852. function TAPIStateWrapper.CreatePixelShader(Item: TShaderResource): Integer;
  853. begin
  854.   Result := CreateShader(FPixelShaders, Item);
  855. end;
  856. procedure TAPIStateWrapper.ApplyClipPlanes;
  857. var i: Integer; m: TMatrix4s; Plane: TPlane;
  858. begin
  859.   if VertexShaderFlag then begin                           // Transform clip planes if programmable vertex pipeline used
  860.     for i := 0 to MaxClipPlanes-1 do
  861.       if Assigned(Renderer.LastAppliedCamera) and Assigned(Renderer.LastAppliedCamera.ClipPlanes[i]) then begin
  862.         Plane := Camera.ClipPlanes[i]^;
  863.         m := Camera.TotalMatrix;
  864.         m := InvertMatrix4s(m);
  865.         m := GetTransposedMatrix4s(m);
  866.         Plane.V := Transform4Vector4s(m, Plane.V);
  867.         SetClipPlane(i, @Plane);
  868.       end else SetClipPlane(i, nil);
  869.   end else if Assigned(Camera) then for i := 0 to MaxClipPlanes-1 do SetClipPlane(i, Camera.ClipPlanes[i]);
  870. end;
  871. procedure TAPIStateWrapper.HandleItemReplace(OldItem, NewItem: TItem);
  872. var i: Integer;
  873. begin
  874.   if not Assigned(OldItem) then Exit;
  875.   for i := High(FVertexShaders) downto 0 do if FVertexShaders[i].Resource = OldItem then FVertexShaders[i].Resource := NewItem as TShaderResource;
  876.   for i := High(FPixelShaders)  downto 0 do if FPixelShaders[i].Resource  = OldItem then FPixelShaders[i].Resource  := NewItem as TShaderResource;
  877.   if OldItem = Camera then if Assigned(NewItem) then Camera := NewItem as TCamera else Camera := DefaultCamera;
  878. end;
  879. procedure TAPIStateWrapper.HandleDataChange(Data: Pointer);
  880. var i: Integer;
  881. begin
  882.   for i := 0 to High(FVertexShaders) do if FVertexShaders[i].Resource = TShaderResource(Data) then
  883. end;
  884. constructor TAPIStateWrapper.Create;
  885. begin
  886.   inherited;
  887.   DefaultCamera := TCamera.Create(nil);
  888.   DefaultCamera.DefaultFillMode := fmSOLID;
  889.   DefaultCamera.DefaultCullMode := cmCCW;
  890. end;
  891. destructor TAPIStateWrapper.Destroy;
  892. begin
  893.   FreeAndNil(DefaultCamera);
  894.   inherited;
  895. end;
  896. procedure TAPIStateWrapper.HandleMessage(const Msg: TMessage);
  897. begin
  898.   if (Msg.ClassType = TSceneClearMsg) then begin
  899.     Camera := DefaultCamera;
  900.   end else if Msg.ClassType = TDataModifyMsg then begin
  901.     HandleDataChange(TDataModifyMsg(Msg).Data);
  902.   end else if (Msg.ClassType = TRemoveFromSceneMsg) or (Msg.ClassType = TDestroyMsg) then HandleItemReplace(TItemNotificationMessage(Msg).Item, nil);
  903. end;
  904. procedure TAPIStateWrapper.SetShaderConstant(const Constant: TShaderConstant);
  905. begin
  906.   APISetShaderConstant(Constant);
  907. end;
  908. procedure TAPIStateWrapper.SetShaderConstant(ShaderKind: TShaderKind; ShaderRegister: Integer; const Vector: TShaderRegisterType);
  909. begin
  910.   APISetShaderConstant(ShaderKind, ShaderRegister, Vector); 
  911. end;
  912. function TAPIStateWrapper.ValidatePass(const Pass: TRenderPass): Boolean;
  913. const ResultID: array[Boolean] of string[4] = ('Fail', 'OK');
  914. var ResultStr: string;
  915. begin
  916.   Result := True;
  917.   if not Assigned(Pass) then Exit;
  918.   ResultStr := '';
  919.   {$IFDEF DEBUGMODE}
  920.   Log.Log('  Validating pass "' + Pass.Name + '"...');
  921.   {$ENDIF}
  922.   LastError := reNone;
  923.   ApplyPass(Pass);
  924.   if LastError <> reNone then begin
  925.     case LastError of
  926.       reTooManyStages:   ResultStr := ' (too many stages)';
  927.       reTooManyTextures: ResultStr := ' (too many textures)';
  928.       reVertexShaderAssembleFail: ResultStr := ' (failed to assemble vertex shader)';
  929.       reVertexShaderCreateFail:   ResultStr := ' (failed to create vertex shader)';
  930.       rePixelShaderAssembleFail:  ResultStr := ' (failed to assemble pixel shader)';
  931.       rePixelShaderCreateFail:    ResultStr := ' (failed to create pixel shader)';
  932.       reNoDepthTextures:          ResultStr := ' (depth textures are not supported)';
  933.     end;
  934.     Result := False;
  935.   end else Result := APIValidatePass(Pass, ResultStr);
  936.   Log.Log('  Pass validation result: ' + ResultID[Result] + ResultStr);
  937. end;
  938. { TRenderer }
  939. function TRenderer.GetAdapterName(Index: Cardinal): string;
  940. begin
  941.   Result := '';
  942.   if Index < FTotalAdapters then Result := FAdapterNames[Index];
  943. end;
  944. function TRenderer.GetVideoMode(Index: Cardinal): TVideoMode;
  945. begin
  946.   Assert(Index < FTotalVideoModes, ClassName + '.GetVideoMode: Invalid index');
  947. //  if Index < FTotalVideoModes then
  948.   Result := FVideoModes[Index];
  949. //   else Result := DesktopVideoMode;
  950. end;
  951. // Render target operations
  952. function TAPIStateWrapper.NewRenderTarget(const Camera: TCamera): Integer;
  953. begin
  954.   Result := ResourceAdd_RenderTarget(FRenderTargets, {$IFDEF OBJFPCEnable}@{$ENDIF}IsRenderTargetEmpty);
  955.   if CreateRenderTarget(Result, Camera.RenderTargetWidth, Camera.RenderTargetHeight, Camera.RTColorFormat, Camera.RTDepthFormat, Camera.IsDepthTexture) then begin
  956.     Camera.ColorFormat := FRenderTargets[Result].ActualColorFormat;
  957.     Camera.DepthFormat := FRenderTargets[Result].ActualDepthFormat;
  958.   end else Result := -1; 
  959. end;
  960. procedure TAPIStateWrapper.RemoveRenderTarget(Index: Integer);
  961. begin
  962.   Assert((Index >= 0) and (Index <= High(FRenderTargets)));
  963.   DestroyRenderTarget(Index);
  964.   FRenderTargets[Index].ColorBuffer  := nil;
  965.   FRenderTargets[Index].DepthBuffer  := nil;
  966.   FRenderTargets[Index].ColorTexture := nil;
  967.   FRenderTargets[Index].DepthTexture := nil;
  968.   FRenderTargets[Index].LastUpdateFrame := -1;
  969.   FRenderTargets[Index].IsDepthTexture := False;
  970. end;
  971. function TAPIStateWrapper.FindRenderTarget(const ACamera: TCamera): Integer;
  972. begin
  973.   Result := ACamera.RenderTargetIndex;
  974.   if (Result <> -1) and
  975.     ((ACamera.RenderTargetWidth <> FRenderTargets[Result].Width)   or (ACamera.RenderTargetHeight <> FRenderTargets[Result].Height) or
  976.      (ACamera.RTColorFormat <> FRenderTargets[Result].ColorFormat) or (ACamera.RTDepthFormat <> FRenderTargets[Result].DepthFormat)) then begin
  977.     RemoveRenderTarget(Result);
  978.     Result := -1;
  979.   end;                                           
  980.   if Result = -1 then Result := NewRenderTarget(ACamera);
  981. end;
  982. function TAPIStateWrapper.IsRenderTargetUptoDate(const ACamera: TCamera): Boolean;
  983. begin
  984.   Result := (ACamera.RenderTargetIndex >= 0) and (ACamera.RenderTargetIndex <= High(FRenderTargets)) and
  985.             (Renderer.FramesRendered - FRenderTargets[ACamera.RenderTargetIndex].LastUpdateFrame <= ACamera.FrameSkip);
  986. end;
  987. function TRenderer.GetRenderTargetsAllocated: Integer;
  988. begin
  989.   if Assigned(APIState) then Result := Length(APIState.FRenderTargets) else Result := 0;
  990. end;
  991. procedure TRenderer.InternalDeInit;
  992. var i: Integer;
  993. begin
  994.   {$IFDEF LOGGING}
  995.   Log.Log('Shutting down ' + ClassName, lkNotice);
  996.   {$ENDIF}
  997.   for i := 0 to Length(DebugTesselators)-1 do DebugTesselators[i].Free;
  998.   DebugTesselators := nil;
  999.   FreeAndNil(Buffers);
  1000.   FreeAndNil(Textures);
  1001.   FreeAndNil(APIState);
  1002. end;
  1003. function TRenderer.InternalGetIndexBufferIndex(Static: Boolean; BufferIndex: Integer): Integer;
  1004. begin
  1005.   Result := Buffers.Buffers[tbIndex, Static, BufferIndex].Index;
  1006. end;
  1007. procedure TRenderer.SetDebugOutput(const Value: Boolean);
  1008. begin
  1009.   FDebugOutput := Value;
  1010.   if FDebugOutput then begin
  1011.     if (DebugTesselators = nil) or (DebugMaterial = nil) then begin
  1012.       FDebugOutput := False;
  1013.       ErrorHandler(TError.Create(ClassName + '.SetDebugOutput: Debug render has not been initialized'));
  1014.     end;
  1015.   end;
  1016. end;
  1017. function TRenderer.APIToPixelFormat(Format: Cardinal): Cardinal;
  1018. var i: Integer;
  1019. begin
  1020.   Result := pfUndefined;
  1021.   for i := 0 to High(PFormats) do if PFormats[i] = Format then begin
  1022.     Result := i;
  1023.     Exit;
  1024.   end;
  1025. end;
  1026. procedure TRenderer.SetFullScreen(const FScreen: Boolean);
  1027. begin
  1028.   if FFullScreen = FScreen then Exit;
  1029.   if State <> rsNotReady then RestoreDevice(FCurrentVideoMode, FScreen);
  1030. end;
  1031. constructor TRenderer.Create(AManager: TItemsManager);
  1032. begin
  1033.   Assert(Assigned(AManager), Format('%S.%S: AManager should be assigned', [ClassName, 'Create']));
  1034.   Manager := AManager;
  1035.   AppRequirements.MinYResolution       := 480;
  1036.   AppRequirements.HWAccelerationLevel  := haMixedVP;
  1037.   AppRequirements.TotalBackBuffers     := 1;
  1038.   AppRequirements.Flags                := [arUseStencil, arUseZBuffer];
  1039.   FCurrentVideoMode := $FFFFFFFF;
  1040.   FFramesRendered   := 0;
  1041.   BiasMat._11 := 0.5; BiasMat._12 := 0.0; BiasMat._13 := 0.0;        BiasMat._14 := 0.0;
  1042.   BiasMat._21 := 0.0; BiasMat._22 :=-0.5; BiasMat._23 := 0.0;        BiasMat._24 := 0.0;
  1043.   BiasMat._31 := 0.0; BiasMat._32 := 0.0; BiasMat._33 := 1 shl 24-1; BiasMat._34 := 0.0;
  1044.   BiasMat._41 := 0.0; BiasMat._42 := 0.0; BiasMat._43 := 0.0;        BiasMat._44 := 1.0;
  1045.   Buffers := TBuffers.Create(Self);
  1046. end;
  1047. procedure TRenderer.SetVideoAdapter(Adapter: Cardinal);
  1048. begin
  1049.   if Adapter >= FTotalAdapters then Exit;                  // ToDo: make error handling
  1050.   FCurrentAdapter := Adapter;
  1051.   BuildModeList;
  1052.   FState          := rsNotReady;
  1053. end;
  1054. procedure TRenderer.InitDebugRender(ADebugMaterial: TMaterial);
  1055. begin
  1056.   SetLength(DebugTesselators, 2);
  1057.   DebugTesselators[dtiBox]    := TBoxTesselator.Create;
  1058.   DebugTesselators[dtiSphere] := TSphereTesselator.Create;
  1059.   DebugMaterial := ADebugMaterial;
  1060.   FDebugOutput := True;
  1061. end;
  1062. function TRenderer.IsReady: Boolean;
  1063. begin
  1064.   Result := State = rsOK;
  1065. end;
  1066. procedure TRenderer.SetGamma(Gamma, Contrast, Brightness: Single);
  1067. var i: Integer; k: Single; Value: Word;
  1068. begin
  1069.   {$IFDEF LOGGING}
  1070.   if (Abs(Gamma - 1) > 0.7) or (Abs(Contrast - 1) > 0.7) or (Abs(Brightness - 1) > 0.7) then
  1071.     Log.Log(Format('%S.SetGamma: Extreme values: Gamma - %F, Contrast - %F, Brightness - %F', [ClassName, Gamma, Contrast, Brightness]), lkWarning);
  1072.   {$ENDIF}
  1073.   for i := 0 to 255 do begin
  1074.     k := i/255.0;
  1075.     if i > 0 then k := Basics.Power(k, 1/Basics.MaxS(BaseTypes.Epsilon, Gamma));
  1076.     Value := Trunc(0.5 + MinS(65535, MaxS(0, (k*Contrast+(Brightness-1))*65535)));
  1077.     GammaRamp.R[i] := Value;
  1078.     GammaRamp.G[i] := Value;
  1079.     GammaRamp.B[i] := Value;
  1080.   end;
  1081. end;
  1082. procedure TRenderer.HandleMessage(const Msg: TMessage);
  1083. begin
  1084.   if (State = rsNotReady) or (State = rsNotInitialized) then Exit;
  1085.   if Msg.ClassType = TWindowActivateMsg then begin
  1086.     if not Active then begin
  1087.       Active := True;
  1088. //      ShowWindow(RenderWindowHandle, SW_SHOWDEFAULT);
  1089.       RestoreDevice(FCurrentVideoMode, FFullScreen);
  1090.     end;
  1091.   end else if Msg.ClassType = TWindowDeactivateMsg then begin
  1092.     if FullScreen then Active := False;
  1093.   end else if Msg.ClassType = TWindowResizeMsg then with TWindowResizeMsg(Msg) do begin
  1094.     if (State <> rsNotReady) then begin
  1095.       if not Active then begin
  1096.         Active := True;
  1097.         RestoreDevice(FCurrentVideoMode, FFullScreen);
  1098.       end else if not FullScreen then begin
  1099.         {if Active then }RestoreDevice(FCurrentVideoMode, FFullScreen)
  1100. //         else PrepareWindow;
  1101.       end;
  1102.       if Assigned(MainCamera) and (NewHeight <> 0) then
  1103.         MainCamera.SetScreenDimensions(Round(NewWidth), Round(NewHeight), True);
  1104.     end;
  1105.   end else if Msg.ClassType = TWindowMoveMsg then begin
  1106.     if not FullScreen then PrepareWindow;
  1107.   end else if Msg.ClassType = TWindowMinimizeMsg then begin
  1108.     Active := False;
  1109.   end else if (Msg.ClassType = TSceneClearMsg) then begin
  1110.     MainCamera := nil;
  1111.     FLastAppliedCamera := nil;
  1112.   end else begin
  1113.     if (Msg.ClassType = TRemoveFromSceneMsg) or (Msg.ClassType = TDestroyMsg) then with TItemNotificationMessage(Msg) do if Item = MainCamera then MainCamera := nil;
  1114.   end;
  1115.   APIState.HandleMessage(Msg);
  1116.   Textures.HandleMessage(Msg);
  1117. end;
  1118. function TRenderer.CheckFormat(const Format, Usage, RTFormat: Cardinal; out NewFormat: Integer): Boolean;
  1119. {  pfUndefined    = 0; pfR8G8B8    = 1; pfA8R8G8B8  = 2; pfX8R8G8B8  = 3;
  1120.   pfR5G6B5       = 4; pfX1R5G5B5  = 5; pfA1R5G5B5  = 6; pfA4R4G4B4  = 7;
  1121.   pfA8           = 8; pfX4R4G4B4  = 9; pfA8P8      = 10; pfP8       = 11; pfL8     = 12; pfA8L8      = 13; pfA4L4 = 14;
  1122.   pfV8U8         = 15; pfL6V5U5   = 16; pfX8L8V8U8 = 17; pfQ8W8V8U8 = 18; pfV16U16 = 19; pfW11V11U10 = 20;
  1123.   pfD16_LOCKABLE = 21; pfD32      = 22; pfD15S1    = 23; pfD24S8    = 24; pfD16    = 25; pfD24X8     = 26; pfD24X4S4 = 27;
  1124.   pfB8G8R8       = 28; pfA8B8G8R8 = 29;
  1125.   pfAuto = $FFFFFFFF;}
  1126. const
  1127.   SubstFormats = 19; SubstVariants = 7;
  1128.   FormatSubst: array[0..SubstFormats-1, 0..SubstVariants-1] of Cardinal = (
  1129.  (pfR8G8B8,       pfX8R8G8B8, pfA8B8G8R8, pfB8G8R8,   pfR5G6B5,   pfX1R5G5B5, pfA4R4G4B4),
  1130.  (pfA8R8G8B8,     pfA8B8G8R8, pfA4R4G4B4, pfA1R5G5B5, pfX8R8G8B8, pfR8G8B8,   pfR5G6B5),
  1131.  (pfX8R8G8B8,     pfA8R8G8B8, pfR8G8B8,   pfB8G8R8,   pfA8B8G8R8, pfR5G6B5,   pfX1R5G5B5),
  1132.  (pfR5G6B5,       pfX1R5G5B5, pfA1R5G5B5, pfX8R8G8B8, pfA8R8G8B8, pfB8G8R8,   pfA4R4G4B4),
  1133.  (pfX1R5G5B5,     pfR5G6B5,   pfA1R5G5B5, pfX8R8G8B8, pfR8G8B8,   pfB8G8R8,   pfA4R4G4B4),
  1134.  (pfA1R5G5B5,     pfA4R4G4B4, pfA8R8G8B8, pfA8B8G8R8, pfR5G6B5,   pfX8R8G8B8, pfR8G8B8),
  1135.  (pfA4R4G4B4,     pfA1R5G5B5, pfA8R8G8B8, pfA8B8G8R8, pfR5G6B5,   pfX8R8G8B8, pfR8G8B8),
  1136.  (pfX4R4G4B4,     pfR5G6B5,   pfA1R5G5B5, pfX8R8G8B8, pfR8G8B8,   pfB8G8R8,   pfA4R4G4B4),
  1137.  (pfB8G8R8,       pfA8B8G8R8, pfR8G8B8,   pfX8R8G8B8, pfR5G6B5,   pfX1R5G5B5, pfA4R4G4B4),
  1138.  (pfA8B8G8R8,     pfA8R8G8B8, pfA4R4G4B4, pfA1R5G5B5, pfX8R8G8B8, pfB8G8R8,   pfR5G6B5),
  1139.  (pfA8,           pfL8,       pfA8L8,     pfA8P8,     pfA8R8G8B8, pfA8B8G8R8, pfA4R4G4B4),
  1140.  (pfL8,           pfA8,       pfA8L8,     pfA8P8,     pfR8G8B8,   pfB8G8R8,   pfR5G6B5),
  1141.  (pfD16_LOCKABLE, pfD16,      pfD15S1,    pfD24X8,    pfD24X4S4,  pfD32,      pfD24S8),
  1142.  (pfD32,          pfD24X8,    pfATIDF24,  pfD24S8,    pfD16,      pfD15S1,    pfD16_LOCKABLE),
  1143.  (pfD15S1,        pfD24X4S4,  pfD24S8,    pfD16,      pfD32,      pfD24X8,    pfD16_LOCKABLE),
  1144.  (pfD24S8,        pfD24X4S4,  pfD15S1,    pfD32,      pfATIDF24,  pfD16,      pfATIDF16),
  1145.  (pfD16,          pfD15S1,    pfD24X8,    pfATIDF16,  pfD32,      pfD24S8,    pfD16_LOCKABLE),
  1146.  (pfD24X8,        pfD32,      pfD24X4S4,  pfD24S8,    pfD16,      pfD15S1,    pfD16_LOCKABLE),
  1147.  (pfD24X4S4,      pfD24S8,    pfD15S1,    pfD32,      pfD24X8,    pfD16,      pfD16_LOCKABLE)
  1148.  );
  1149. var i, j: Integer;
  1150. begin
  1151.   NewFormat := Format;
  1152.   Result := APICheckFormat(NewFormat, Usage, RTFormat);
  1153.   if Result then Exit;
  1154.   NewFormat := pfUndefined;
  1155.   i := SubstFormats-1;
  1156.   while (i >= 0) and not (Format = FormatSubst[i, 0]) do Dec(i);
  1157.   if i < 0 then Exit;
  1158.   j := 0;
  1159.   while (j < SubstVariants) and not APICheckFormat(FormatSubst[i, j], Usage, RTFormat) do Inc(j);
  1160.   if j < SubstVariants then NewFormat := FormatSubst[i, j];
  1161. end;
  1162. function TRenderer.ValidateMaterial(const Material: TMaterial): Boolean;
  1163.   function ValidateTechnique(const Technique: TTechnique): Boolean;
  1164.   var i: Integer;
  1165.   begin
  1166.     i := Technique.TotalPasses-1;
  1167.     while (i >= 0) and APIState.ValidatePass(Technique.Passes[i]) do Dec(i);
  1168.     Result := i < 0;
  1169.     Technique.Valid := Result and (isVisible in Technique.State);
  1170.   end;
  1171. var i: Integer; OldValid: Boolean;
  1172. begin
  1173.   Result := False;
  1174.   Log.Log('Validating material "' + Material.Name + '"...');
  1175.   for i := 0 to Material.TotalTechniques-1 do if Assigned(Material.Technique[i]) then begin
  1176.     OldValid := Material.Technique[i].Valid;
  1177.     if not ValidateTechnique(Material.Technique[i]) then
  1178.       Log.Log('Technique "' + Material.Technique[i].Name + '" did not pass validation', lkWarning);
  1179.     Result := Result or (OldValid <> Material.Technique[i].Valid);
  1180.   end;
  1181. end;
  1182. function TRenderer.PrepareWindow: Boolean;
  1183. var TempRect: OSUtils.TRect;
  1184. begin
  1185.   Assert(not FFullScreen, ClassName + '.PrepareWindow: FullScreen # False');
  1186.   Result := False;
  1187. //  if (WindowedRect.Left = WindowedRect.Right) or (WindowedRect.Top = WindowedRect.Bottom) then
  1188.   GetWindowRect(RenderWindowHandle, TempRect);
  1189.   if (TempRect.Left < OffScreenX) and (TempRect.Right < OffScreenX) or (TempRect.Top < OffScreenY) and (TempRect.Bottom < OffScreenY) then begin
  1190.     {$IFDEF LOGGING} Log.Log(ClassName + '.PrepareWindow: Windowed viewport is off-screen', lkError); {$ENDIF}
  1191.     FState := rsLost;
  1192.     Exit;
  1193.   end;
  1194.   FWindowedRect := TempRect;
  1195.   {$IFNDEF DEBUGMODE}
  1196. //  SetWindowLong(RenderWindowHandle, GWL_STYLE, FNormalWindowStyle);
  1197.   {$ENDIF}
  1198. //  SetWindowPos(RenderWindowHandle, HWND_NOTOPMOST, WindowedRect.Left, WindowedRect.Top, WindowedRect.Right-WindowedRect.Left, WindowedRect.Bottom-WindowedRect.Top, SWP_DRAWFRAME or SWP_NOACTIVATE or SWP_NOSIZE or SWP_NOMOVE);
  1199.   GetClientRect(RenderWindowHandle, TempRect);
  1200.   if (TempRect.Right - TempRect.Left <= 0) or (TempRect.Bottom - TempRect.Top <= 0) then begin
  1201.     {$IFDEF LOGGING}
  1202.     Log.Log(ClassName + '.PrepareWindow: Viewport''s client area is missing', lkError);
  1203.     {$ENDIF}
  1204. //      State := rsTryToRestore;
  1205.     Exit;
  1206.   end;
  1207. //  WindowBorderWidth := ClientRect.Left - WindowedRect.Left + (WindowedRect.Right - ClientRect.Right);
  1208. //  WindowBorderHeight := ClientRect.Top - WindowedRect.Top + (WindowedRect.Bottom - ClientRect.Bottom);
  1209.   RenderWidth  := TempRect.Right;
  1210.   RenderHeight := TempRect.Bottom;
  1211.   if Assigned(MainCamera) then MainCamera.SetScreenDimensions(RenderWidth, RenderHeight, True);
  1212.   Result := True;
  1213. end;
  1214. function TRenderer.CreateDevice(WindowHandle, AVideoMode: Cardinal; AFullScreen: Boolean): Boolean;
  1215. begin
  1216.   Log.Log('Render device creation', lkNotice);
  1217.   if APICreateDevice(WindowHandle, AVideoMode, AFullScreen) then begin
  1218.     Log.Log('Render device succesfully created');
  1219.     CheckCaps;
  1220.     Result := True;
  1221.     Manager.SendMessage(TRenderReinitMsg.Create, nil, [mfCore, mfBroadcast]);
  1222.     Manager.SendMessage(TWindowResizeMsg.Create(0, 0, RenderWidth, RenderHeight), nil, [mfCore]);   // For correct screen and GUI subsystems initialization
  1223.   end else begin
  1224.     Log.Log('Render device creation failed', lkError);
  1225.     Result := False;
  1226.   end;
  1227. end;
  1228. function TRenderer.RestoreDevice(AVideoMode: Cardinal; AFullScreen: Boolean): Boolean;
  1229. begin
  1230.   Result := True;
  1231.   if Assigned(Manager.Root) then Manager.SendMessage(TRenderReinitMsg.Create, nil, [mfCore, mfBroadcast]);
  1232. end;
  1233. procedure TRenderer.ApplyCamera(Camera: CAST2.TCamera);
  1234. begin
  1235.   if Camera <> FLastAppliedCamera then begin
  1236.     APIState.SetRenderTarget(Camera, Camera <> MainCamera);
  1237.     if Camera <> MainCamera then begin
  1238.       Camera.SetScreenDimensions(Camera.RenderTargetWidth, Camera.RenderTargetHeight, False);
  1239. //    Camera.ColorFormat := Camera.RTColorFormat;
  1240. //    Camera.DepthFormat := Camera.RTDepthFormat;
  1241.     end;
  1242.   end;
  1243.   FLastAppliedCamera := Camera;
  1244.   TesselationParams.Camera := FLastAppliedCamera;
  1245.   if Assigned(APIState) then begin
  1246.     APIState.Camera := Camera;
  1247.     APIState.ApplyClipPlanes;
  1248.   end;
  1249.   if Assigned(Camera) then Clear(Camera.ClearSettings.ClearFlags, Camera.ClearSettings.ClearColor, Camera.ClearSettings.ClearZ, Camera.ClearSettings.ClearStencil);
  1250. end;
  1251. procedure TRenderer.ProjectToScreen(out Projected: TVector4s; const Vector: TVector3s);
  1252. var TRHW: Single;
  1253. begin
  1254.   if not Assigned(MainCamera) then Exit;
  1255.   Projected := Transform4Vector3s(MainCamera.TotalMatrix, Vector);
  1256.   if Projected.W = 0 then Projected.W := -0.000001;
  1257.   TRHW := 1/Projected.W;
  1258.   Projected.X := MainCamera.RenderWidth  shr 1 + MainCamera.RenderWidth  shr 1*Projected.X * TRHW;
  1259.   Projected.Y := MainCamera.RenderHeight shr 1 - MainCamera.RenderHeight shr 1*Projected.Y * TRHW;
  1260. end;
  1261. procedure TRenderer.SetViewPort(const X, Y, Width, Height: Integer; const MinZ, MaxZ: Single);
  1262. begin
  1263.   ViewPort.X := X; ViewPort.Y := Y;
  1264.   ViewPort.Width := Width; ViewPort.Height := Height;
  1265.   ViewPort.MinZ := MinZ; ViewPort.MaxZ := MaxZ;
  1266. end;
  1267. procedure TRenderer.RenderTesselator(Tesselator: TTesselator);
  1268. var i: Integer;
  1269. begin
  1270.   if Tesselator.TotalIndices > 0 then begin
  1271.     for i := Tesselator.TotalStrips - 1 downto 0 do APIRenderIndexedStrip(Tesselator, i);
  1272.   end else for i := Tesselator.TotalStrips - 1 downto 0 do APIRenderStrip(Tesselator, i);
  1273. end;
  1274. destructor TRenderer.Destroy;
  1275. begin
  1276.   InternalDeInit;
  1277.   inherited;
  1278. end;
  1279. function TAPIStateWrapper.CreateRenderTarget(Index, Width, Height: Integer; AColorFormat, ADepthFormat: Cardinal; ADepthTexture: Boolean): Boolean;
  1280. const Usage: array[False..True] of Cardinal = (fuDEPTHSTENCIL, fuDEPTHTEXTURE);
  1281. begin
  1282.   Result := True;
  1283.   FRenderTargets[Index].Width           := Width;
  1284.   FRenderTargets[Index].Height          := Height;
  1285.   FRenderTargets[Index].LastUseFrame    := Renderer.FramesRendered;
  1286.   FRenderTargets[Index].LastUpdateFrame := -1;
  1287.   FRenderTargets[Index].ColorFormat     := AColorFormat;
  1288.   FRenderTargets[Index].DepthFormat     := ADepthFormat;
  1289.   FRenderTargets[Index].IsDepthTexture  := ADepthTexture;
  1290.   // Check pixel format
  1291.   if not Renderer.CheckFormat(FRenderTargets[Index].ColorFormat, fuRENDERTARGET, pfUndefined, FRenderTargets[Index].ActualColorFormat) then begin
  1292.     if FRenderTargets[Index].ActualColorFormat = pfUndefined then begin
  1293.       Log.Log('TAPIStateWrapper.AddRenderTarget: Can''t find an appropriate pixel format for render target (initial format "'  + PixelFormatToStr(FRenderTargets[Index].ColorFormat) + '")', lkError);
  1294.       Result := False;
  1295.     end else
  1296.       Log.Log('TAPIStateWrapper.AddRenderTarget: Unsupported pixel format "' + PixelFormatToStr(FRenderTargets[Index].ColorFormat) +
  1297.               '" of a render target. Switching to format "' + PixelFormatToStr(FRenderTargets[Index].ActualColorFormat) + '".', lkWarning);
  1298.   end;
  1299.   // Check depth format
  1300.   if not Renderer.CheckFormat(FRenderTargets[Index].DepthFormat, Usage[ADepthTexture], FRenderTargets[Index].ActualColorFormat, FRenderTargets[Index].ActualDepthFormat) then begin
  1301.     if FRenderTargets[Index].ActualDepthFormat = pfUndefined then begin
  1302.       Log.Log('TAPIStateWrapper.AddRenderTarget: Can''t find an appropriate depth-stencil surface format for render target (initial format "'  + PixelFormatToStr(FRenderTargets[Index].DepthFormat) + '")', lkError);
  1303.     end else
  1304.       Log.Log('TAPIStateWrapper.AddRenderTarget: Unsupported depth-stencil surface format "' + PixelFormatToStr(FRenderTargets[Index].DepthFormat) +
  1305.               '" of a render target. Switching to format "' + PixelFormatToStr(FRenderTargets[Index].ActualDepthFormat) + '".', lkWarning);
  1306.   end;
  1307.   if not Result or not APICreateRenderTarget(Index, FRenderTargets[Index].Width, FRenderTargets[Index].Height, FRenderTargets[Index].ActualColorFormat, FRenderTargets[Index].ActualDepthFormat) then begin
  1308.     Result := False;
  1309.     RemoveRenderTarget(Index);
  1310.   end;// else Log.Log('****************: Created depth-stencil surface format "' + PixelFormatToStr(FRenderTargets[Index].ActualDepthFormat));
  1311. end;
  1312. procedure TRenderer.StartFrame;
  1313. begin
  1314.   Assert(Assigned(MainCamera), 'TRenderer.StartFrame: MainCamera is undefined');
  1315.   MainCamera.SetScreenDimensions(RenderWidth, RenderHeight, True);                         // ToDo: Remove
  1316.   // Zero out statistics
  1317.   Assert(Assigned(FPerfProfile), Format('%S.%S: FPerfProfile should be assigned', [ClassName, 'StartFrame']));
  1318.   FPerfProfile.OnFrameStart;
  1319. //  MainCamera.ColorFormat := FCurrentZBufferDepth
  1320. end;
  1321. procedure TRenderer.InternalInit;
  1322. begin
  1323.   APIState.Renderer := Self;
  1324.   Textures.Renderer := Self;
  1325. end;
  1326. procedure TRenderer.SetPerfProfile(APerfProfile: TPerfProfile);
  1327. begin
  1328.   FPerfProfile := APerfProfile;
  1329.   Assert(Assigned(APIState), Format('%S.%S: APIState should be assigned for this call', [ClassName, 'SetPerfProfile']));
  1330.   APIState.FPerfProfile := APerfProfile;
  1331. end;
  1332. procedure TRenderer.RenderItem(Item: TVisible);
  1333. var i: Integer; ItemShaderConstants: TShaderConstants;
  1334. begin
  1335.   if not IsReady then Exit;
  1336.   if not Assigned(Item.CurrentTesselator) or not Assigned(Item.CurTechnique) or (Item.CurTechnique.TotalPasses = 0) then Exit;
  1337.   TesselationParams.ModelMatrix := Item.Transform;
  1338.   // Buffers switching and setting
  1339.   if not Buffers.Put(Item.CurrentTesselator) or (Item.CurrentTesselator.TotalPrimitives = 0) then Exit;
  1340.   if not APIState.VertexShaderFlag then APIPrepareFVFStates(Item);
  1341.   if APIState.VertexShaderFlag or APIState.PixelShaderFlag then begin
  1342.     Item.RetrieveShaderConstants(ItemShaderConstants);
  1343.     if Assigned(ItemShaderConstants) then
  1344.       for i := 0 to High(ItemShaderConstants) do
  1345.         APIState.SetShaderConstant(ItemShaderConstants[i]);
  1346.   end;
  1347.   if not Item.CurrentTesselator.ManualRender then
  1348.     RenderTesselator(Item.CurrentTesselator)
  1349.   else
  1350.     Item.CurrentTesselator.DoManualRender(Item);
  1351. end;
  1352. { TTextures }
  1353. function TTextures.IsEmpty(const Element: TTexture): Boolean;
  1354. begin Result := Element.Format = pfUndefined; end;// not Assigned(Element.Resource); end;
  1355. function TTextures.NewTexture(Resource: TImageResource; Options: TTextureOptions): Integer;
  1356. begin
  1357.   Result := tivUnresolved;
  1358.   // Check if the resource is valid
  1359.   if not Assigned(Resource) or (Resource.Format = pfUndefined) then begin
  1360.     Log.Log('TTextures.NewTexture: invalid or no resource specified', lkError);
  1361.     Exit;
  1362.   end;
  1363.   if (toProcedural in Options) then begin
  1364.     Log.Log('TTextures.NewTexture: for procedural textures NewProceduralTexture() should be used', lkError);
  1365.     Exit;
  1366.   end;
  1367.   if Assigned(Resource) then begin                                      // Check if the resource already loaded as a texture
  1368.     Result := High(FTextures);
  1369.     while (Result >= 0) and (FTextures[Result].Resource <> Resource) do Dec(Result);
  1370.     if Result >= 0 then Exit;
  1371.     {$IFDEF DEBUG}
  1372.     Log.Log('TRenderer.AddTexture: Loading resource "' + Resource.GetFullName + '" as a texture', lkDebug);
  1373.     {$ENDIF}
  1374.   end;
  1375.   Result := ResourceAdd_Texture(FTextures, {$IFDEF OBJFPCEnable}@{$ENDIF}IsEmpty);
  1376.   FTextures[Result].Format   := Resource.Format;            
  1377.   FTextures[Result].Resource := Resource;
  1378.   FTextures[Result].Options  := Options;
  1379.   FTextures[Result].Texture  := nil;
  1380.   if (toImmediateLoad in Options) and not Load(Result) then begin
  1381.     FTextures[Result].Resource := nil;
  1382.     FTextures[Result].Format   := pfUndefined;
  1383.   end;
  1384. end;
  1385. function TTextures.NewProceduralTexture(AFormat: Cardinal; AWidth, AHeight, ADepth, ALevels: Integer; Options: TTextureOptions): Integer;
  1386. begin
  1387.   Result := ResourceAdd_Texture(FTextures, {$IFDEF OBJFPCEnable}@{$ENDIF}IsEmpty);
  1388.   FTextures[Result].Resource := nil;
  1389.   FTextures[Result].Texture  := nil;
  1390.   FTextures[Result].Options  := Options + [toProcedural];
  1391.   FTextures[Result].Format   := AFormat;
  1392.   FTextures[Result].Width    := AWidth;
  1393.   FTextures[Result].Height   := AHeight;
  1394.   FTextures[Result].Depth    := ADepth;
  1395.   FTextures[Result].Levels   := ALevels;
  1396.   if not APICreateTexture(Result) then Result := tivNull;
  1397. end;
  1398. procedure TTextures.Delete(Index: Integer);
  1399. begin
  1400. //  Dec(TotalTextures);
  1401.   FTextures[Index].Resource := nil;
  1402.   FTextures[Index].Format   := pfUndefined;
  1403. //  if Index < TotalTextures then FTextures[Index] := FTextures[TotalTextures]
  1404. end;
  1405. procedure TTextures.FreeAll;
  1406. var i: Integer;
  1407. begin
  1408.   for i := High(FTextures) downto 0 do if not IsEmpty(FTextures[i]) then Delete(i);
  1409. end;
  1410. destructor TTextures.Destroy;
  1411. begin
  1412.   FreeAll;
  1413.   inherited;
  1414. end;
  1415. procedure TTextures.HandleMessage(const Msg: TMessage);
  1416. var i: Integer;
  1417. begin
  1418.   if (Msg.ClassType = TResourceModifyMsg) then begin
  1419.     for i := 0 to High(FTextures) do if FTextures[i].Resource = TResourceModifyMsg(Msg).Resource then Load(i);
  1420.   end else if (Msg.ClassType = TRemoveFromSceneMsg) or (Msg.ClassType = TDestroyMsg) then
  1421.     for i := High(FTextures) downto 0 do if FTextures[i].Resource = TItemNotificationMessage(Msg).Item then
  1422.       FTextures[i].Resource := nil;
  1423. //  HandleItemReplace(TItemNotificationMessage(Msg).Item, nil);
  1424. end;
  1425. function TTextures.Load(Index: Integer): Boolean;
  1426. var
  1427. {  i, j, k, w, h: Integer;
  1428.   FData, CData: Pointer; DataSize, DataOfs, TextureDataOfs: Integer;
  1429.   MipmapGenFilter: TImageFilterFunction;}
  1430.   Image: TImageResource;
  1431.   Width, Height: Cardinal;
  1432.   TotalPixels: Integer;
  1433.   TargetFormat: Integer;
  1434.   Data: Pointer;
  1435. begin
  1436.   Result := False;
  1437.   // * check dimensions
  1438.   // * check format
  1439.   Image := FTextures[Index].Resource;
  1440.   if not Assigned(Image) then begin
  1441.     Log.Log(Format('%S.%S: Resource of texture #%D is not assigned', [ClassName, 'Load', Index]));
  1442.     Exit;
  1443.   end;
  1444.   // Now check if texture with such dimensions is supported
  1445.   Width  := MinI(Renderer.MaxTextureWidth,  Image.Width);
  1446.   Height := MinI(Renderer.MaxTextureHeight, Image.Height);
  1447.   if Renderer.SquareTextures then begin
  1448.     Width  := MaxI(Width, Height);
  1449.     Height := Width;
  1450.   end;
  1451.   // Compute total size of the texture with mipmaps
  1452.   Assert((Image.DataSize mod GetBytesPerPixel(Image.Format)) = 0);
  1453.   TotalPixels := Image.DataSize div GetBytesPerPixel(Image.Format);
  1454.   // Check if texture with such format is supported
  1455.   if not Renderer.CheckFormat(Image.Format, fuTexture, pfUndefined, TargetFormat) then begin
  1456.     if TargetFormat = pfUndefined then begin
  1457.       Log.Log(Format('%S.%S: Can''t find appropriate texture format (initial format "%S") for resource "%S"',
  1458.                      [ClassName, 'LoadTexture', PixelFormatToStr(Image.Format), Image.GetFullName]), lkError);
  1459. //      if Assigned(CData) then FreeMem(CData);
  1460.       Exit;
  1461.     end else if TargetFormat <> Image.Format then begin
  1462.       Log.Log(Format('%S.%S: Unsupported image format "%S" of resource "%S". Switching to format "%S",',
  1463.                      [ClassName, 'LoadTexture', PixelFormatToStr(Image.Format), Image.GetFullName, PixelFormatToStr(TargetFormat)]), lkWarning);
  1464.     end;
  1465.   end;
  1466.   if Assigned(FTextures[Index].Texture) and                           // Allocated API texture
  1467.    ((FTextures[Index].Width <> Width) or (FTextures[Index].Height <> Height) or
  1468.     (FTextures[Index].Levels <> Image.ActualLevels) or
  1469.     (GetBytesPerPixel(FTextures[Index].Format) <> GetBytesPerPixel(TargetFormat))) then begin
  1470.       Log.Log(Format('%S.%S: Image resource changed. Recreating API texture.',
  1471.                      [ClassName, 'LoadTexture']), lkWarning);
  1472.       APIDeleteTexture(Index);
  1473.     end;
  1474.   FTextures[Index].Width  := Width;
  1475.   FTextures[Index].Height := Height;
  1476.   FTextures[Index].Format := TargetFormat;
  1477.   FTextures[Index].Levels := Image.ActualLevels; 
  1478.   if TargetFormat <> Image.Format then begin
  1479.     GetMem(Data, TotalPixels * GetBytesPerPixel(TargetFormat));
  1480.     ConvertImage(Image.Format, TargetFormat, TotalPixels, Image.Data, 0, nil, Data);
  1481.     Update(Index, Data, nil);
  1482.     FreeMem(Data);
  1483.   end else Update(Index, Image.Data, nil);
  1484.   Result := True;
  1485. end;
  1486. function TTextures.Resolve(Pass: TRenderPass; StageIndex: Integer): Boolean;
  1487. var TextureResource: TImageResource;
  1488. begin
  1489.   Result := False;
  1490.   if Pass.ResolveTexture(StageIndex, TextureResource) then begin
  1491.     if Pass.Stages[StageIndex].TextureIndex = tivUnresolved then
  1492.       Pass.Stages[StageIndex].TextureIndex := NewTexture(TextureResource, []);
  1493.     Result := Pass.Stages[StageIndex].TextureIndex <> tivUnresolved;
  1494.   end;
  1495. end;
  1496. end.