AsphyreDevices.pas
上传用户:ctlcnc
上传日期:2021-12-10
资源大小:4933k
文件大小:32k
源码类别:

2D图形编程

开发平台:

Delphi

  1. unit AsphyreDevices;
  2. //---------------------------------------------------------------------------
  3. // AsphyreDevices.pas                                   Modified: 25-Apr-2007
  4. // Asphyre Device encapsulating Direct3D functionality           Version 4.02
  5. //---------------------------------------------------------------------------
  6. // Important Notice:
  7. //
  8. // If you modify/use this code or one of its parts either in original or
  9. // modified form, you must comply with Mozilla Public License v1.1,
  10. // specifically section 3, "Distribution Obligations". Failure to do so will
  11. // result in the license breach, which will be resolved in the court.
  12. // Remember that violating author's rights is considered a serious crime in
  13. // many countries. Thank you!
  14. //
  15. // !! Please *read* Mozilla Public License 1.1 document located at:
  16. //  http://www.mozilla.org/MPL/
  17. //
  18. // If you require any clarifications about the license, feel free to contact
  19. // us or post your question on our forums at: http://www.afterwarp.net
  20. //---------------------------------------------------------------------------
  21. // The contents of this file are subject to the Mozilla Public License
  22. // Version 1.1 (the "License"); you may not use this file except in
  23. // compliance with the License. You may obtain a copy of the License at
  24. // http://www.mozilla.org/MPL/
  25. //
  26. // Software distributed under the License is distributed on an "AS IS"
  27. // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
  28. // License for the specific language governing rights and limitations
  29. // under the License.
  30. //
  31. // The Original Code is AsphyreDevices.pas.
  32. //
  33. // The Initial Developer of the Original Code is M. Sc. Yuriy Kotsarenko.
  34. // Portions created by M. Sc. Yuriy Kotsarenko are Copyright (C) 2007,
  35. // Afterwarp Interactive. All Rights Reserved.
  36. //---------------------------------------------------------------------------
  37. interface
  38. //---------------------------------------------------------------------------
  39. uses
  40.  Windows, Direct3D9, AsphyreEvents, AsphyreCanvas, AsphyreImages,
  41.  AsphyreSystemFonts, AsphyreFonts;
  42. //---------------------------------------------------------------------------
  43. type
  44.  TDepthStencilType = (dsNone, dsDepthOnly, dsDepthStencil);
  45. //---------------------------------------------------------------------------
  46.  TBitDepthType = (bd15bit, bd16bit, bd24bit, bd30bit);
  47. //---------------------------------------------------------------------------
  48.  TDisplayInfo = record
  49.   Adapter        : Integer;
  50.   Driver         : string;
  51.   Description    : string;
  52.   DeviceName     : string;
  53.   DriverVersionLo: Longword;
  54.   DriverVersionHi: Longword;
  55.   VendorID       : Longword;
  56.   DeviceID       : Longword;
  57.   SubSysID       : Longword;
  58.   Revision       : Longword;
  59.   DeviceGuid     : TGuid;
  60.  end;
  61. //---------------------------------------------------------------------------
  62.  TScreenConfig = record
  63.   Adapter      : Integer;
  64.   Width        : Integer;
  65.   Height       : Integer;
  66.   Windowed     : Boolean;
  67.   VSync        : Boolean;
  68.   BitDepth     : TBitDepthType;
  69.   WindowHandle : THandle;
  70.   HardwareTL   : Boolean;
  71.   DepthStencil : TDepthStencilType;
  72.   MultiSamples : Integer;
  73.  end;
  74. //---------------------------------------------------------------------------
  75.  TAsphyreDevice = class;
  76. //---------------------------------------------------------------------------
  77.  TAsphyreDevices = class;
  78. //---------------------------------------------------------------------------
  79.  TScreenConfigEvent = procedure(Sender: TAsphyreDevice; Tag: TObject;
  80.   var Config: TScreenConfig) of object;
  81. //---------------------------------------------------------------------------
  82.  TScreenConfigExEvent = procedure(Sender: TAsphyreDevice; Tag: TObject;
  83.   var Adapter, WindowHandle: Integer; var UsingDepthBuffer, UsingStencilBuffer,
  84.   HardwareTL: Boolean; var Params: TD3DPresentParameters) of object;
  85. //---------------------------------------------------------------------------
  86.  TDeviceResetEvent = procedure(Sender: TAsphyreDevice; Tag: TObject;
  87.   var Params: TD3DPresentParameters) of object;
  88. //---------------------------------------------------------------------------
  89.  TDeviceTagEvent = procedure(Sender: TAsphyreDevice; Tag: TObject) of object;
  90. //---------------------------------------------------------------------------
  91.  TDevicePureEvent = procedure(Sender: TAsphyreDevice) of object;
  92. //---------------------------------------------------------------------------
  93.  TAsphyreDevice = class
  94.  private
  95.   FOwner : TAsphyreDevices;
  96.   FIndex : Integer;
  97.   FDev9  : IDirect3DDevice9;
  98.   FCaps9 : TD3DCaps9;
  99.   FParams: TD3DPresentParameters;
  100.   FCanvas: TAsphyreCanvas;
  101.   FImages: TAsphyreImages;
  102.   FFonts : TAsphyreFonts;
  103.   FSysFonts: TAsphyreSystemFonts;
  104.   FInitialized : Boolean;
  105.   IsLostState  : Boolean;
  106.   UsingDepthBuf: Boolean;
  107.   UsingStencil : Boolean;
  108.   function FindNearestMultisample(MultiSamples: Integer;
  109.    Adapter: Cardinal; SurfaceFormat, DepthFormat: TD3DFormat;
  110.    Windowed: Boolean): TD3DMultisampleType;
  111.   procedure MoveIntoLostState();
  112.   function AttemptRecoverState(): Boolean;
  113.   function HandleDriverError(): Boolean;
  114.  protected
  115.   function GetDefaultConfig(): TScreenConfig;
  116.   function ConfigToParams(const Config: TScreenConfig): TD3DPresentParameters;
  117.   function GetDefaultParams(): TD3DPresentParameters;
  118.   function CheckLostScenario(): Boolean;
  119.  public
  120.   property Owner: TAsphyreDevices read FOwner;
  121.   property Index: Integer read FIndex;
  122.   property Dev9  : IDirect3DDevice9 read FDev9;
  123.   property Caps9 : TD3DCaps9 read FCaps9;
  124.   property Params: TD3DPresentParameters read FParams;
  125.   property Canvas: TAsphyreCanvas read FCanvas;
  126.   property Images: TAsphyreImages read FImages;
  127.   property Fonts : TAsphyreFonts read FFonts;
  128.   property SysFonts: TAsphyreSystemFonts read FSysFonts;
  129.   property Initialized: Boolean read FInitialized;
  130.   function FindBackFormat(Depth: TBitDepthType; Adapter, Width,
  131.    Height: Integer): TD3DFormat;
  132.   function FindDepthFormat(Depth: TDepthStencilType; BackFormat: TD3DFormat;
  133.    Adapter: Integer): TD3DFormat;
  134.   function Reset(Event: TDeviceResetEvent; Tag: TObject): Boolean;
  135.   function Flip(): Boolean; overload;
  136.   function Flip(WindowHandle: THandle): Boolean; overload;
  137.   procedure Clear(Color: Cardinal; DepthValue: Single; StencilValue: Cardinal);
  138.   procedure BeginScene();
  139.   procedure EndScene();
  140.   function Initialize(CfgEvent: TScreenConfigEvent; Tag: TObject): Boolean;
  141.   function InitializeEx(Event: TScreenConfigExEvent; Tag: TObject): Boolean;
  142.   procedure Finalize();
  143.   function ChangeParams(NewWidth, NewHeight: Integer;
  144.    Windowed: Boolean): Boolean;
  145.   function RenderTo(ImageIndex: Integer; Event: TDeviceTagEvent;
  146.    Tag: TObject): Boolean; overload;
  147.   function RenderTo(ImageIndex: Integer; Event: TDeviceTagEvent;
  148.    Tag: TObject; Bkgrnd: Cardinal; DepthValue: Single;
  149.    StencilValue: Cardinal): Boolean; overload;
  150.   function RenderTo(const SurfName: string; Event: TDeviceTagEvent;
  151.    Tag: TObject): Boolean; overload;
  152.   function RenderTo(const SurfName: string; Event: TDeviceTagEvent;
  153.    Tag: TObject; Bkgrnd: Cardinal; DepthValue: Single;
  154.    StencilValue: Cardinal): Boolean; overload;
  155.   procedure Render(WindowHandle: THandle; Event: TDeviceTagEvent;
  156.    Tag: TObject); overload;
  157.   procedure Render(WindowHandle: THandle; Event: TDeviceTagEvent; Tag: TObject;
  158.    Bkgrnd: Cardinal); overload;
  159.   procedure Render(WindowHandle: THandle; Event: TDeviceTagEvent; Tag: TObject;
  160.    Bkgrnd: Cardinal; DepthValue: Real; StencilValue: Cardinal); overload;
  161.   procedure Render(Event: TDeviceTagEvent; Tag: TObject); overload;
  162.   procedure Render(Event: TDeviceTagEvent; Tag: TObject;
  163.    Bkgrnd: Cardinal); overload;
  164.   procedure Render(Event: TDeviceTagEvent; Tag: TObject; Bkgrnd: Cardinal;
  165.    DepthValue: Real; StencilValue: Cardinal); overload;
  166.   constructor Create(AOwner: TAsphyreDevices; AIndex: Integer);
  167.   destructor Destroy(); override;
  168.  end;
  169. //---------------------------------------------------------------------------
  170.  TAsphyreDevices = class
  171.  private
  172.   Data: array of TAsphyreDevice;
  173.   FDirect3D9: IDirect3D9;
  174.   function GetCount(): Integer;
  175.   function GetDevice(Num: Integer): TAsphyreDevice;
  176.   procedure SetCount(const Value: Integer);
  177.   function Insert(): Integer;
  178.   procedure Remove(Num: Integer);
  179.   procedure RemoveAll();
  180.   function GetDisplayCount(): Integer;
  181.   function GetDisplayInfo(Num: Integer): TDisplayInfo;
  182.  public
  183.   property Count: Integer read GetCount write SetCount;
  184.   property Device[Num: Integer]: TAsphyreDevice read GetDevice; default;
  185.   property Direct3D9: IDirect3D9 read FDirect3D9;
  186.   property DisplayCount: Integer read GetDisplayCount;
  187.   property DisplayInfo[Num: Integer]: TDisplayInfo read GetDisplayInfo;
  188.   // initialize the screen using intuitive parameters
  189.   function Initialize(CfgEvent: TScreenConfigEvent; Tag: TObject): Boolean;
  190.   // initialize the screen using user-defined Direct3D parameters
  191.   function InitializeEx(Event: TScreenConfigExEvent; Tag: TObject): Boolean;
  192.   procedure Finalize();
  193.   constructor Create();
  194.   destructor Destroy(); override;
  195.  end;
  196. //---------------------------------------------------------------------------
  197. var
  198.  Devices: TAsphyreDevices = nil;
  199.  // The reference to the default device. 
  200.  DefDevice: TAsphyreDevice = nil;
  201. //---------------------------------------------------------------------------
  202. implementation
  203. //---------------------------------------------------------------------------
  204. const
  205.  BackFormats: array[0..5] of TD3DFormat = (
  206.   {  0 } D3DFMT_A2R10G10B10,
  207.   {  1 } D3DFMT_A8R8G8B8,
  208.   {  2 } D3DFMT_X8R8G8B8,
  209.   {  3 } D3DFMT_A1R5G5B5,
  210.   {  4 } D3DFMT_X1R5G5B5,
  211.   {  5 } D3DFMT_R5G6B5);
  212. //---------------------------------------------------------------------------
  213.  DepthStencilFormats: array[0..6] of TD3DFormat = (
  214.   {  0 } D3DFMT_D24S8,
  215.   {  1 } D3DFMT_D24FS8,
  216.   {  2 } D3DFMT_D24X4S4,
  217.   {  3 } D3DFMT_D15S1,
  218.   {  4 } D3DFMT_D32,
  219.   {  5 } D3DFMT_D24X8,
  220.   {  6 } D3DFMT_D16);
  221. //---------------------------------------------------------------------------
  222. constructor TAsphyreDevice.Create(AOwner: TAsphyreDevices; AIndex: Integer);
  223. begin
  224.  inherited Create();
  225.  FOwner := AOwner;
  226.  FIndex := AIndex;
  227.  FCanvas:= TAsphyreCanvas.Create(Self);
  228.  FImages:= TAsphyreImages.Create(Self);
  229.  FFonts := TAsphyreFonts.Create(Self);
  230.  FSysFonts:= TAsphyreSystemFonts.Create(Self);
  231.  FInitialized:= False;
  232. end;
  233. //---------------------------------------------------------------------------
  234. destructor TAsphyreDevice.Destroy();
  235. begin
  236.  if (FInitialized) then Finalize();
  237.  FSysFonts.Free();
  238.  FFonts.Free();
  239.  FImages.Free();
  240.  FCanvas.Free();
  241.  inherited;
  242. end;
  243. //---------------------------------------------------------------------------
  244. function TAsphyreDevice.GetDefaultConfig(): TScreenConfig;
  245. begin
  246.  Result.Adapter := D3DADAPTER_DEFAULT;
  247.  Result.Width   := 640;
  248.  Result.Height  := 480;
  249.  Result.Windowed:= True;
  250.  Result.VSync   := False;
  251.  Result.BitDepth:= bd24bit;
  252.  Result.WindowHandle:= 0;
  253.  Result.HardwareTL  := True;
  254.  Result.DepthStencil:= dsDepthStencil;
  255.  Result.MultiSamples:= 1;
  256. end;
  257. //---------------------------------------------------------------------------
  258. function TAsphyreDevice.FindBackFormat(Depth: TBitDepthType; Adapter, Width,
  259.  Height: Integer): TD3DFormat;
  260. const
  261.  FormatIndexes: array[TBitDepthType, 0..5] of Integer = ((4, 3, 5, 1, 2, 0),
  262.   (3, 4, 5, 1, 2, 0), (1, 2, 0, 5, 3, 4), (0, 1, 2, 5, 3, 4));
  263. var
  264.  FormatNo : Integer;
  265.  Format   : TD3DFormat;
  266.  ModeCount: Integer;
  267.  ModeNo   : Integer;
  268.  Mode     : TD3DDisplayMode;
  269. begin
  270.  Result:= D3DFMT_UNKNOWN;
  271.  // search through the list of available back-buffer formats
  272.  for FormatNo:= 0 to 5 do
  273.   begin
  274.    // determine Direct3D back-buffer format
  275.    Format:= BackFormats[FormatIndexes[Depth, FormatNo]];
  276.    // check all existing modes for the specified format
  277.    ModeCount:= FOwner.Direct3D9.GetAdapterModeCount(Adapter, Format);
  278.    for ModeNo:= 0 to ModeCount - 1 do
  279.     begin
  280.      // verify whether the specified mode is compatible
  281.      if (Succeeded(FOwner.Direct3D9.EnumAdapterModes(Adapter, Format, ModeNo, Mode)))and
  282.       (Integer(Mode.Width) = Width)and(Integer(Mode.Height) = Height) then
  283.       begin
  284.        Result:= Format;
  285.        Exit;
  286.       end;
  287.     end;
  288.   end;
  289. end;
  290. //---------------------------------------------------------------------------
  291. function TAsphyreDevice.FindDepthFormat(Depth: TDepthStencilType;
  292.  BackFormat: TD3DFormat; Adapter: Integer): TD3DFormat;
  293. const
  294.  FormatIndexes: array[TDepthStencilType, 0..6] of Integer = (
  295.   (-1, -1, -1, -1, -1, -1, -1), (4, 5, 0, 2, 1, 6, 3), (0, 1, 2, 3, 4, 5, 6));
  296. var
  297.  FormatNo : Integer;
  298.  Format   : TD3DFormat;
  299.  ModeCount: Integer;
  300.  ModeNo   : Integer;
  301. begin
  302.  Result:= D3DFMT_UNKNOWN;
  303.  if (Depth = dsNone) then Exit;
  304.  // search through the list of available depth-buffer formats
  305.  for FormatNo:= 0 to 6 do
  306.   begin
  307.    // determine Direct3D back-buffer format
  308.    Format:= DepthStencilFormats[FormatIndexes[Depth, FormatNo]];
  309.    // check all existing modes for the specified format
  310.    ModeCount:= FOwner.Direct3D9.GetAdapterModeCount(Adapter, BackFormat);
  311.    for ModeNo:= 0 to ModeCount - 1 do
  312.     begin
  313.      // verify whether the specified mode is compatible
  314.      if (Succeeded(FOwner.Direct3D9.CheckDeviceFormat(Adapter, D3DDEVTYPE_HAL,
  315.       BackFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, Format))) then
  316.       begin
  317.        Result:= Format;
  318.        Exit;
  319.       end;
  320.     end;
  321.   end;
  322. end;
  323. //---------------------------------------------------------------------------
  324. function TAsphyreDevice.FindNearestMultisample(MultiSamples: Integer;
  325.  Adapter: Cardinal; SurfaceFormat, DepthFormat: TD3DFormat;
  326.  Windowed: Boolean): TD3DMultisampleType;
  327. var
  328.  MType: TD3DMultisampleType;
  329.  Allowed: Boolean;
  330.  i: Integer;
  331. begin
  332.  Result:= D3DMULTISAMPLE_NONE;
  333.  for i:= MultiSamples downto 2 do
  334.   begin
  335.    MType:= TD3DMultisampleType(i);
  336.    Allowed:= Succeeded(FOwner.Direct3D9.CheckDeviceMultiSampleType(Adapter,
  337.     D3DDEVTYPE_HAL, SurfaceFormat, Windowed, MType, nil));
  338.    if (Allowed)and(DepthFormat <> D3DFMT_UNKNOWN) then
  339.     Allowed:= Succeeded(FOwner.Direct3D9.CheckDeviceMultiSampleType(Adapter,
  340.      D3DDEVTYPE_HAL, DepthFormat, Windowed, MType, nil));
  341.    if (Allowed) then
  342.     begin
  343.      Result:= MType;
  344.      Break;
  345.     end;
  346.   end;
  347. end;
  348. //---------------------------------------------------------------------------
  349. function TAsphyreDevice.ConfigToParams(const Config: TScreenConfig): TD3DPresentParameters;
  350. var
  351.  Mode: TD3DDisplayMode;
  352. begin
  353.  FillChar(Result, SizeOf(TD3DPresentParameters), 0);
  354.  Result.BackBufferWidth := Config.Width;
  355.  Result.BackBufferHeight:= Config.Height;
  356.  Result.Windowed        := Config.Windowed;
  357.  Result.hDeviceWindow   := Config.WindowHandle;
  358.  Result.SwapEffect      := D3DSWAPEFFECT_DISCARD;
  359.  // specify Presentation Interval
  360.  Result.PresentationInterval:= D3DPRESENT_INTERVAL_IMMEDIATE;
  361.  if (Config.VSync) then Result.PresentationInterval:= D3DPRESENT_INTERVAL_ONE;
  362.  // specify Back Buffer Format
  363.  if (Config.Windowed) then
  364.   begin
  365.    Result.BackBufferFormat:= D3DFMT_UNKNOWN;
  366.    if (Succeeded(FOwner.Direct3D9.GetAdapterDisplayMode(Config.Adapter, Mode))) then
  367.     Result.BackBufferFormat:= Mode.Format;
  368.   end else Result.BackBufferFormat:= FindBackFormat(Config.BitDepth,
  369.    Config.Adapter, Config.Width, Config.Height);
  370.  // specify Depth Stencil Buffer Format
  371.  if (Config.DepthStencil <> dsNone) then
  372.   begin
  373.    Result.EnableAutoDepthStencil:= True;
  374.    Result.Flags:= D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;
  375.    Result.AutoDepthStencilFormat:= FindDepthFormat(Config.DepthStencil,
  376.     Result.BackBufferFormat, Config.Adapter);
  377.   end;
  378.  if (Config.DepthStencil <> dsNone) then
  379.   begin
  380.    Result.MultiSampleType:= FindNearestMultisample(Config.MultiSamples,
  381.     Config.Adapter, Result.BackBufferFormat, Result.AutoDepthStencilFormat,
  382.     Result.Windowed);
  383.   end else
  384.   begin
  385.    Result.MultiSampleType:= FindNearestMultisample(Config.MultiSamples,
  386.     Config.Adapter, Result.BackBufferFormat, D3DFMT_UNKNOWN, Result.Windowed);
  387.   end;
  388. end;
  389. //---------------------------------------------------------------------------
  390. function TAsphyreDevice.Initialize(CfgEvent: TScreenConfigEvent;
  391.  Tag: TObject): Boolean;
  392. var
  393.  Res: Integer;
  394.  Config: TScreenConfig;
  395. begin
  396.  // (1) Check if the device is already created.
  397.  Result:= (FDev9 <> nil);
  398.  if (Result) then Exit;
  399.  // (2) Check if the owner and Direct3D are valid references.
  400.  Result:= (FOwner <> nil)and(FOwner.Direct3D9 <> nil);
  401.  if (not Result) then Exit;
  402.  // (3) Retreive configuration.
  403.  Config:= GetDefaultConfig();
  404.  CfgEvent(Self, Tag, Config);
  405.  // (4) Make present parameters.
  406.  FParams:= ConfigToParams(Config);
  407.  UsingDepthBuf := (Config.DepthStencil <> dsNone);
  408.  UsingStencil  := (Config.DepthStencil = dsDepthStencil);
  409.  // (5) Attempt to use hardware vertex processing.
  410.  if (Config.HardwareTL) then
  411.   begin
  412.    Res:= FOwner.Direct3D9.CreateDevice(Config.Adapter, D3DDEVTYPE_HAL,
  413.     Config.WindowHandle, D3DCREATE_HARDWARE_VERTEXPROCESSING,
  414.     @FParams, FDev9);
  415.   end else Res:= D3D_OK; // for the next call
  416.  // -> if FAILED, try software vertex processing
  417.  if (Failed(Res))or(not Config.HardwareTL) then
  418.   Res:= FOwner.Direct3D9.CreateDevice(Config.Adapter, D3DDEVTYPE_HAL,
  419.    Config.WindowHandle, D3DCREATE_SOFTWARE_VERTEXPROCESSING,
  420.    @FParams, FDev9);
  421.  // -> if STILL FAILED, then we cannot proceed
  422.  Result:= Succeeded(Res);
  423.  // (6) Retreive device capabilities.
  424.  if (Result) then
  425.   Result:= Succeeded(FDev9.GetDeviceCaps(FCaps9));
  426.  // (7) Mark that we have not lost the device.
  427.  IsLostState:= False;
  428.  // (8) Update initialized status and broadcast events.
  429.  FInitialized:= Result;
  430.  if (Result) then
  431.   begin
  432.    Result:= EventDeviceCreate.Notify(Self, Self, nil);
  433.    if (Result) then EventDeviceReset.Notify(Self, Self, nil);
  434.    if (not Result) then Finalize();
  435.   end;
  436. end;
  437. //---------------------------------------------------------------------------
  438. function TAsphyreDevice.GetDefaultParams(): TD3DPresentParameters;
  439. begin
  440.  FillChar(Result, SizeOf(TD3DPresentParameters), 0);
  441.  Result.BackBufferWidth := 640;
  442.  Result.BackBufferHeight:= 480;
  443.  Result.BackBufferFormat:= D3DFMT_UNKNOWN;
  444.  Result.BackBufferCount := 1;
  445.  Result.SwapEffect      := D3DSWAPEFFECT_DISCARD;
  446.  Result.Windowed        := True;
  447.  Result.Flags           := D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;
  448.  Result.PresentationInterval:= D3DPRESENT_INTERVAL_DEFAULT;
  449. end;
  450. //---------------------------------------------------------------------------
  451. function TAsphyreDevice.InitializeEx(Event: TScreenConfigExEvent;
  452.  Tag: TObject): Boolean;
  453. var
  454.  Res: Integer;
  455.  Adapter, WindowHandle: Integer;
  456.  HardwareTL: Boolean;
  457. begin
  458.  // (1) Check if the device is already created.
  459.  Result:= (FDev9 <> nil);
  460.  if (Result) then Exit;
  461.  // (2) Check if the owner and Direct3D are valid references.
  462.  Result:= (FOwner <> nil)and(FOwner.Direct3D9 <> nil);
  463.  if (not Result) then Exit;
  464.  // (3) Retreive present parameters.
  465.  FParams:= GetDefaultParams();
  466.  Event(Self, Tag, Adapter, WindowHandle, UsingDepthBuf, UsingStencil,
  467.   HardwareTL, FParams);
  468.  // (4) Attempt to use hardware vertex processing.
  469.  if (HardwareTL) then
  470.   begin
  471.    Res:= FOwner.Direct3D9.CreateDevice(Adapter, D3DDEVTYPE_HAL,
  472.     WindowHandle, D3DCREATE_HARDWARE_VERTEXPROCESSING, @FParams, FDev9);
  473.   end else Res:= D3D_OK; // for the next call
  474.  // -> if FAILED, try software vertex processing
  475.  if (Failed(Res))or(not HardwareTL) then
  476.   Res:= FOwner.Direct3D9.CreateDevice(Adapter, D3DDEVTYPE_HAL, WindowHandle,
  477.    D3DCREATE_SOFTWARE_VERTEXPROCESSING, @FParams, FDev9);
  478.  // -> if STILL FAILED, then we cannot proceed
  479.  Result:= Succeeded(Res);
  480.  // (5) Retreive device capabilities.
  481.  if (Result) then
  482.   Result:= Succeeded(FDev9.GetDeviceCaps(FCaps9));
  483.  // (6) Mark that we have not lost the device.
  484.  IsLostState:= False;
  485.  // (7) Update initialized status and broadcast events.
  486.  FInitialized:= Result;
  487.  if (Result) then
  488.   begin
  489.    Result:= EventDeviceCreate.Notify(Self, Self, nil);
  490.    if (Result) then EventDeviceReset.Notify(Self, Self, nil);
  491.    if (not Result) then Finalize();
  492.   end;
  493. end;
  494. //---------------------------------------------------------------------------
  495. procedure TAsphyreDevice.Finalize();
  496. begin
  497.  if (FDev9 <> nil) then
  498.   begin
  499.    EventDeviceLost.Notify(Self, Self, nil);
  500.    EventDeviceDestroy.Notify(Self, Self, nil);
  501.    FDev9:= nil;
  502.   end;
  503.  FInitialized:= False;
  504. end;
  505. //---------------------------------------------------------------------------
  506. procedure TAsphyreDevice.Render(WindowHandle: THandle; Event: TDeviceTagEvent;
  507.  Tag: TObject; Bkgrnd: Cardinal; DepthValue: Real; StencilValue: Cardinal);
  508. begin
  509.  if (CheckLostScenario()) then
  510.   begin
  511.    Clear(Bkgrnd, DepthValue, StencilValue);
  512.    BeginScene();
  513.    Event(Self, Tag);
  514.    EndScene();
  515.    Flip(WindowHandle);
  516.   end else SleepEx(8, True);
  517. end;
  518. //---------------------------------------------------------------------------
  519. procedure TAsphyreDevice.Render(WindowHandle: THandle; Event: TDeviceTagEvent;
  520.  Tag: TObject; Bkgrnd: Cardinal);
  521. begin
  522.  Render(WindowHandle, Event, Tag, Bkgrnd, 1.0, 0);
  523. end;
  524. //---------------------------------------------------------------------------
  525. procedure TAsphyreDevice.Render(WindowHandle: THandle; Event: TDeviceTagEvent;
  526.  Tag: TObject);
  527. begin
  528.  if (CheckLostScenario()) then
  529.   begin
  530.    BeginScene();
  531.    Event(Self, Tag);
  532.    EndScene();
  533.    Flip(WindowHandle);
  534.   end else SleepEx(8, True);
  535. end;
  536. //---------------------------------------------------------------------------
  537. procedure TAsphyreDevice.Render(Event: TDeviceTagEvent; Tag: TObject;
  538.  Bkgrnd: Cardinal; DepthValue: Real; StencilValue: Cardinal);
  539. begin
  540.  Render(0, Event, Tag, Bkgrnd, DepthValue, StencilValue);
  541. end;
  542. //---------------------------------------------------------------------------
  543. procedure TAsphyreDevice.Render(Event: TDeviceTagEvent; Tag: TObject;
  544.  Bkgrnd: Cardinal);
  545. begin
  546.  Render(0, Event, Tag, Bkgrnd, 1.0, 0);
  547. end;
  548. //---------------------------------------------------------------------------
  549. procedure TAsphyreDevice.Render(Event: TDeviceTagEvent; Tag: TObject);
  550. begin
  551.  Render(0, Event, Tag);
  552. end;
  553. //---------------------------------------------------------------------------
  554. function TAsphyreDevice.Reset(Event: TDeviceResetEvent; Tag: TObject): Boolean;
  555. begin
  556.  Result:= (FDev9 <> nil);
  557.  if (not Result) then Exit;
  558.  MoveIntoLostState();
  559.  if (Assigned(Event)) then Event(Self, Tag, FParams);
  560.  Result:= AttemptRecoverState();
  561. end;
  562. //---------------------------------------------------------------------------
  563. function TAsphyreDevice.Flip(): Boolean;
  564. begin
  565.  Result:= Flip(0);
  566. end;
  567. //---------------------------------------------------------------------------
  568. function TAsphyreDevice.Flip(WindowHandle: THandle): Boolean;
  569. begin
  570.  Result:= (FDev9 <> nil);
  571.  if (not Result) then Exit;
  572.  Result:= Succeeded(FDev9.Present(nil, nil, WindowHandle, nil));
  573. end;
  574. //---------------------------------------------------------------------------
  575. procedure TAsphyreDevice.Clear(Color: Cardinal; DepthValue: Single;
  576.  StencilValue: Cardinal);
  577. var
  578.  Flags: Cardinal;
  579. begin
  580.  if (FDev9 = nil) then Exit;
  581.  Flags:= D3DCLEAR_TARGET;
  582.  if (UsingDepthBuf) then
  583.   begin
  584.    Flags:= Flags or D3DCLEAR_ZBUFFER;
  585.    if (UsingStencil) then Flags:= Flags or D3DCLEAR_STENCIL;
  586.   end;
  587.  FDev9.Clear(0, nil, Flags, Color, DepthValue, StencilValue);
  588. end;
  589. //---------------------------------------------------------------------------
  590. procedure TAsphyreDevice.BeginScene();
  591. begin
  592.  if (FDev9 <> nil)and(Succeeded(FDev9.BeginScene())) then
  593.   EventBeginScene.Notify(Self, Self, nil);
  594. end;
  595. //---------------------------------------------------------------------------
  596. procedure TAsphyreDevice.EndScene();
  597. begin
  598.  if (FDev9 <> nil) then
  599.   begin
  600.    EventEndScene.Notify(Self, Self, nil);
  601.    FDev9.EndScene();
  602.   end;
  603. end;
  604. //---------------------------------------------------------------------------
  605. function TAsphyreDevice.RenderTo(ImageIndex: Integer; Event: TDeviceTagEvent;
  606.  Tag: TObject; Bkgrnd: Cardinal; DepthValue: Single;
  607.  StencilValue: Cardinal): Boolean;
  608. var
  609.  Image: TAsphyreCustomImage;
  610. begin
  611.  Result:= CheckLostScenario();
  612.  if (not Result) then Exit;
  613.  Image:= Images[ImageIndex];
  614.  Result:= (Image <> nil)and(Image is TAsphyreSurface);
  615.  if (not Result) then Exit;
  616.  with Image as TAsphyreSurface do
  617.   begin
  618.    Result:= (RenderTarget <> nil)and(RenderTarget.BeginDraw());
  619.    if (not Result) then Exit;
  620.    Clear(Bkgrnd, DepthValue, StencilValue);
  621.    BeginScene();
  622.    Event(Self, Tag);
  623.    EndScene();
  624.    RenderTarget.EndDraw();
  625.   end;
  626. end;
  627. //---------------------------------------------------------------------------
  628. function TAsphyreDevice.RenderTo(ImageIndex: Integer; Event: TDeviceTagEvent;
  629.  Tag: TObject): Boolean;
  630. var
  631.  Image: TAsphyreCustomImage;
  632. begin
  633.  Result:= CheckLostScenario();
  634.  if (not Result) then Exit;
  635.  Image:= Images[ImageIndex];
  636.  Result:= (Image <> nil)and(Image is TAsphyreSurface);
  637.  if (not Result) then Exit;
  638.  with Image as TAsphyreSurface do
  639.   begin
  640.    Result:= (RenderTarget <> nil)and(RenderTarget.BeginDraw());
  641.    if (not Result) then Exit;
  642.    BeginScene();
  643.    Event(Self, Tag);
  644.    EndScene();
  645.    RenderTarget.EndDraw();
  646.   end;
  647. end;
  648. //---------------------------------------------------------------------------
  649. function TAsphyreDevice.RenderTo(const SurfName: string;
  650.  Event: TDeviceTagEvent; Tag: TObject; Bkgrnd: Cardinal; DepthValue: Single;
  651.  StencilValue: Cardinal): Boolean;
  652. var
  653.  ImageIndex: Integer;
  654. begin
  655.  ImageIndex:= Images.ResolveImage(SurfName);
  656.  Result:= (ImageIndex <> -1);
  657.  if (Result) then Result:= RenderTo(ImageIndex, Event, Tag, Bkgrnd,
  658.   DepthValue, StencilValue);
  659. end;
  660. //---------------------------------------------------------------------------
  661. function TAsphyreDevice.RenderTo(const SurfName: string;
  662.  Event: TDeviceTagEvent; Tag: TObject): Boolean;
  663. var
  664.  ImageIndex: Integer;
  665. begin
  666.  ImageIndex:= Images.ResolveImage(SurfName);
  667.  Result:= (ImageIndex <> -1);
  668.  if (Result) then Result:= RenderTo(ImageIndex, Event, Tag);
  669. end;
  670. //---------------------------------------------------------------------------
  671. function TAsphyreDevice.ChangeParams(NewWidth, NewHeight: Integer;
  672.  Windowed: Boolean): Boolean;
  673. begin
  674.  Result:= (FDev9 <> nil);
  675.  if (not Result) then Exit;
  676.  MoveIntoLostState();
  677.  FParams.BackBufferWidth := NewWidth;
  678.  FParams.BackBufferHeight:= NewHeight;
  679.  FParams.Windowed        := Windowed;
  680.  Result:= AttemptRecoverState();
  681. end;
  682. //---------------------------------------------------------------------------
  683. procedure TAsphyreDevice.MoveIntoLostState();
  684. begin
  685.  if (not IsLostState) then
  686.   begin
  687.    EventDeviceLost.Notify(Self, Self, nil);
  688.    IsLostState:= True;
  689.   end;
  690. end;
  691. //---------------------------------------------------------------------------
  692. function TAsphyreDevice.AttemptRecoverState(): Boolean;
  693. var
  694.  Res: HResult;
  695. begin
  696.  Res:= FDev9.Reset(FParams);
  697.  Result:= Succeeded(Res);
  698.  if (Result) then
  699.   begin
  700.    IsLostState:= False;
  701.    EventDeviceReset.Notify(Self, Self, nil);
  702.   end;
  703. end;
  704. //---------------------------------------------------------------------------
  705. function TAsphyreDevice.HandleDriverError(): Boolean;
  706. var
  707.  Res: HResult;
  708. begin
  709.  Res:= FDev9.Reset(FParams);
  710.  Result:= Succeeded(Res);
  711.  if (not Result) then EventDeviceFault.Notify(Self, Self, nil);
  712. end;
  713. //---------------------------------------------------------------------------
  714. function TAsphyreDevice.CheckLostScenario(): Boolean;
  715. var
  716.  Res: HResult;
  717. begin
  718.  Result:= (FDev9 <> nil);
  719.  if (not Result) then Exit;
  720.  Res:= FDev9.TestCooperativeLevel();
  721.  case Res of
  722.   D3DERR_DEVICELOST:
  723.    begin
  724.     MoveIntoLostState();
  725.     Result:= False;
  726.    end;
  727.   D3DERR_DEVICENOTRESET:
  728.    Result:= AttemptRecoverState();
  729.   D3DERR_DRIVERINTERNALERROR:
  730.    Result:= HandleDriverError();
  731.   D3D_OK:
  732.    Result:= True;
  733.   else Result:= False;
  734.  end;
  735. end;
  736. //---------------------------------------------------------------------------
  737. constructor TAsphyreDevices.Create();
  738. begin
  739.  inherited;
  740.  FDirect3D9:= Direct3DCreate9(D3D_SDK_VERSION);
  741. end;
  742. //---------------------------------------------------------------------------
  743. destructor TAsphyreDevices.Destroy();
  744. begin
  745.  RemoveAll();
  746.  if (FDirect3D9 <> nil) then FDirect3D9:= nil;
  747.  inherited;
  748. end;
  749. //---------------------------------------------------------------------------
  750. function TAsphyreDevices.GetCount(): Integer;
  751. begin
  752.  Result:= Length(Data);
  753. end;
  754. //---------------------------------------------------------------------------
  755. procedure TAsphyreDevices.SetCount(const Value: Integer);
  756. begin
  757.  while (Length(Data) > Value)and(Length(Data) > 0) do
  758.   Remove(Length(Data) - 1);
  759.  while (Length(Data) < Value) do Insert();
  760.  if (Length(Data) > 0) then DefDevice:= Data[0] else DefDevice:= nil;
  761. end;
  762. //---------------------------------------------------------------------------
  763. function TAsphyreDevices.GetDevice(Num: Integer): TAsphyreDevice;
  764. begin
  765.  if (Num >= 0)and(Num < Length(Data)) then
  766.   Result:= Data[Num] else Result:= nil;
  767. end;
  768. //---------------------------------------------------------------------------
  769. function TAsphyreDevices.Insert(): Integer;
  770. var
  771.  Index: Integer;
  772. begin
  773.  Index:= Length(Data);
  774.  SetLength(Data, Index + 1);
  775.  Data[Index]:= TAsphyreDevice.Create(Self, Index);
  776.  Result:= Index;
  777. end;
  778. //---------------------------------------------------------------------------
  779. procedure TAsphyreDevices.Remove(Num: Integer);
  780. var
  781.  i: Integer;
  782. begin
  783.  if (Num < 0)or(Num >= Length(Data)) then Exit;
  784.  Data[Num].Free();
  785.  for i:= Num to Length(Data) - 2 do
  786.   Data[i]:= Data[i + 1];
  787.  SetLength(Data, Length(Data) - 1);
  788. end;
  789. //---------------------------------------------------------------------------
  790. procedure TAsphyreDevices.RemoveAll();
  791. var
  792.  i: Integer;
  793. begin
  794.  for i:= 0 to Length(Data) - 1 do
  795.   Data[i].Free();
  796.  SetLength(Data, 0);
  797. end;
  798. //---------------------------------------------------------------------------
  799. function TAsphyreDevices.GetDisplayCount(): Integer;
  800. begin
  801.  if (FDirect3D9 <> nil) then Result:= FDirect3D9.GetAdapterCount()
  802.   else Result:= 0;
  803. end;
  804. //---------------------------------------------------------------------------
  805. function TAsphyreDevices.GetDisplayInfo(Num: Integer): TDisplayInfo;
  806. var
  807.  Identifier: TD3DAdapterIdentifier9;
  808. begin
  809.  if (FDirect3D9 = nil)or(Failed(FDirect3D9.GetAdapterIdentifier(Num, 0,
  810.   Identifier))) then
  811.   begin
  812.    FillChar(Result, SizeOf(TDisplayInfo), 0);
  813.    Exit;
  814.   end;
  815.  Result.Adapter        := Num;
  816.  Result.Driver         := Identifier.Driver;
  817.  Result.Description    := Identifier.Description;
  818.  Result.DeviceName     := Identifier.DeviceName;
  819.  Result.DriverVersionLo:= Identifier.DriverVersion and $FFFFFFFF;
  820.  Result.DriverVersionHi:= Identifier.DriverVersion shr 32;
  821.  Result.VendorID       := Identifier.VendorId;
  822.  Result.DeviceID       := Identifier.DeviceId;
  823.  Result.SubSysID       := Identifier.SubSysId;
  824.  Result.Revision       := Identifier.Revision;
  825.  Result.DeviceGuid     := Identifier.DeviceIdentifier;
  826. end;
  827. //---------------------------------------------------------------------------
  828. function TAsphyreDevices.Initialize(CfgEvent: TScreenConfigEvent;
  829.  Tag: TObject): Boolean;
  830. var
  831.  i: Integer;
  832. begin
  833.  Result:= False;
  834.  for i:= 0 to Length(Data) - 1 do
  835.   if (not Data[i].Initialized) then
  836.    begin
  837.     Result:= Data[i].Initialize(CfgEvent, Tag);
  838.     if (not Result) then Break;
  839.    end;
  840. end;
  841. //---------------------------------------------------------------------------
  842. function TAsphyreDevices.InitializeEx(Event: TScreenConfigExEvent;
  843.  Tag: TObject): Boolean;
  844. var
  845.  i: Integer;
  846. begin
  847.  Result:= False;
  848.  for i:= 0 to Length(Data) - 1 do
  849.   if (not Data[i].Initialized) then
  850.    begin
  851.     Result:= Data[i].InitializeEx(Event, Tag);
  852.     if (not Result) then Break;
  853.    end;
  854. end;
  855. //---------------------------------------------------------------------------
  856. procedure TAsphyreDevices.Finalize();
  857. var
  858.  i: Integer;
  859. begin
  860.  for i:= 0 to Length(Data) - 1 do
  861.   if (Data[i].Initialized) then Data[i].Finalize();
  862. end;
  863. //---------------------------------------------------------------------------
  864. initialization
  865.  Devices:= TAsphyreDevices.Create();
  866.  Devices.Count:= 1;
  867. //---------------------------------------------------------------------------
  868. finalization
  869.  Devices.Free();
  870.  Devices:= nil;
  871. //---------------------------------------------------------------------------
  872. end.