//DJX v1.4
unit DJX;

interface

uses
  Windows,
  Classes,
  Controls,
  Graphics,
  SysUtils,
  ZLib,
  DJXPrimitives,
  DJXWnd,
  DJXRender,
  DJXTextures,
  DJXMaterials,
  DJXFonts,
  DJXTexFonts,
  DJXClasses,
  Direct3D9,
  D3DX9;

type
  TDanJetX = class;
  TDJXSwapChain = class;
  TDJXResources = class;
  TDJXRes = class;

  TDanJetX = class(TComponent)
  private
    m_D3D9: IDirect3D9;
    m_Device: IDirect3DDevice9;
    m_DeviceCaps: TD3DCaps9;
    m_VB2D: TDJXVB2D;
    m_VB3D: TDJXVB3D;
    m_D3Dpp: TD3DPresentParameters;
    m_Specs: TDJXSpecs;
    m_PrimaryBackBuffer: IDirect3DSurface9;
    m_DepthStencil: IDirect3DSurface9;
    m_Render: Pointer;
    m_DJXCamera: TDJXCamera;
    m_DJXMatrices3D: TDJXMatrices3D;
    m_DJXMatrices: TDJXMatrices;
    m_DJXMatricesTex: TDJXMatricesTex;
    m_Primitives2D: TDJXPrimitives2D;
    m_Primitives3D: TDJXPrimitives3D;
    m_MultiTexBlends: TDJXMultiTexBlendList;
    m_SwapChains: TList;
    m_LastSwapChain: TDJXSwapChain;
    m_Resources: TDJXResources;
    m_hWnd: HWND;
    m_ComponentList: TList;
    m_Width: integer;
    m_Height: integer;
    m_OwnWindow: boolean;
    m_DJXWC: TWndClassEx;
    m_Initialized: boolean;
    m_States: TDJXStates;
    m_Initialization: TDJXInitialization;
    m_SurfaceDesc: TD3DSURFACE_DESC;
    m_SurfaceRect: TD3DLOCKED_RECT;
    m_BBLocked: boolean;
    m_PrimaryViewPort: TD3DViewport9;
    m_ViewPort: TD3DViewport9;
    m_DeviceLost: boolean;
    m_OnInitialize: TNotifyEvent;
    m_OnFinalize: TNotifyEvent;
    m_OnLostDevice: TNotifyEvent;
    m_OnResetDevice: TNotifyEvent;
    m_Filtering: boolean;
    m_MipMaps: boolean;
    m_BlendMode: TDJXBlendMode;
    m_Vsync: boolean;
    m_Zbuffer: boolean;
    m_TruncatePixel: boolean;
    m_Lights: boolean;
    m_FullScreen: boolean;
    m_Cull: TDJXCullMode;
    m_DepthStencilWidth: integer;
    m_DepthStencilHeight: integer;
  protected
    procedure InitComponents;
    function SetUpDevice: HRESULT;
    procedure CreateSubClasses;
    procedure DestroySubClasses;
    procedure SetDefaultMaterial;
    procedure SetFiltering(Value: boolean);
    procedure SetMipMaps(Value: boolean);
    procedure SetBlendMode(Value: TDJXBlendMode);
    procedure SetFullScreen(Value: boolean);
    procedure SetZbuffer(Value: boolean);
    procedure SetLights(Value: boolean);
    procedure SetAmbient(Value: TDJXColor);
    function GetAmbient: TDJXColor;
    procedure SetCull(Value: TDJXCullMode);
    function GetPixel(X,Y: integer): TDJXColor;
    procedure SetPixel(X,Y: integer; Value: TDJXColor);
    procedure LostDeviceStandard;
    procedure ResetDeviceStandard;
    procedure SetWidth(Value: integer);
    procedure SetHeight(Value: integer);
    procedure SetDepthStencilWidth(Value: integer);
    procedure SetDepthStencilHeight(Value: integer);
    procedure SetSwapChain(Index: integer; Value: TDJXSwapChain);
    function GetSwapChain(Index: integer): TDJXSwapChain;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    property Specs: TDJXSpecs read m_Specs write m_Specs;
    property D3D9: IDirect3D9 read m_D3D9;
    property Device: IDirect3DDevice9 read m_Device write m_Device;
    property DeviceCaps: TD3DCaps9 read m_DeviceCaps;
    property WindowHandle: HWND read m_Hwnd write m_Hwnd;
    property VB2D: TDJXVB2D read m_VB2D write m_VB2D;
    property VB3D: TDJXVB3D read m_VB3D write m_VB3D;
    property Render: Pointer read m_Render write m_Render;
    property Camera: TDJXCamera read m_DJXCamera write m_DJXCamera;
    property Matrices: TDJXMatrices read m_DJXMatrices write m_DJXMatrices;
    property Matrices3D: TDJXMatrices3D read m_DJXMatrices3D write m_DJXMatrices3D;
    property MatricesTex: TDJXMatricesTex read m_DJXMatricesTex write m_DJXMatricesTex;
    property MultiTexBlends: TDJXMultiTexBlendList read m_MultiTexBlends write m_MultiTexBlends;
    property BlendMode: TDJXBlendMode read m_BlendMode write setBlendMode;
    property Lights3D: boolean read m_Lights write SetLights default false;
    property Ambient: TDJXColor read GetAmbient write setAmbient;
    property CullMode: TDJXCullMode read m_Cull write setCull default cullCCW;
    property Zbuffer: boolean read m_Zbuffer write setZbuffer default false;
    property Pixels[X, Y: integer]: TDJXColor read GetPixel write SetPixel;
    property SwapChains[Index: integer]: TDJXSwapChain read GetSwapChain write SetSwapChain;
    property Initialized: boolean read m_Initialized;
    property Primitives2D: TDJXPrimitives2D read m_Primitives2D write m_Primitives2D;
    property Primitives3D: TDJXPrimitives3D read m_Primitives3D write m_Primitives3D;
    property Resources: TDJXResources read m_Resources;
    procedure BBLock;
    procedure BBUnLock;
    function Initialize(hWnd: HWND): HRESULT;
    function Reset: HRESULT;
    procedure Finalize;
    procedure Start(Handle: HWND); overload;
    procedure Start(WndTitle: string; WndProc: TFNWndProc; FullScreen: boolean = true); overload;
    procedure Clear(
      clearStencil: boolean;
      clearZBuffer: boolean;
      clearTarget: boolean = false;
      r:byte=0; g:byte=0; b:byte=0; a:byte=255
    );
    procedure ClearScreen(r,g,b: byte; a:byte=255); overload;
    procedure ClearScreen(Color: TDJXColor); overload;
    procedure ClearTarget(r,g,b: byte; a:byte=255); overload;
    procedure ClearTarget(Color: TDJXColor); overload;
    procedure ClearZBuffer;
    procedure ClearStencil;
    procedure ClearTextureStages;
    function AddSwapChain(Handle: HWND; Width, Height: integer): TDJXSwapChain;
    procedure RemoveSwapChain(SwapChain: TDJXSwapChain);
    procedure RenderToTexture(Texture: TDJXTexture);
    procedure RenderToSwapChain(SwapChain: TDJXSwapChain);
    procedure RenderToSurface(Surface, DepthStencilSurface: IDirect3DSurface9);
    procedure RenderToBackBuffer;
    procedure ResizeBackBuffer(NewWidth, NewHeight: DWORD);
    procedure ResizeDepthStencil(NewWidth, NewHeight: DWORD);
    function BeginRender: boolean;
    procedure EndRender(Present: boolean = true);
    function MousePos: TPoint;
    procedure CenterCursor(var Shift: TPoint);
    function CanRender: boolean;
    property ViewPort: TD3DViewport9 read m_ViewPort;
    procedure SetDefaultVewPort;
    procedure SetViewPort(X, Y, Width, Height: integer);
    function VectorToWorld(Vec: TD3DXVector3): TD3DXVector3;
    property DJXComponentList: TList read m_ComponentList write m_ComponentList;
  published
    property Filtering: boolean read m_Filtering write SetFiltering default false;
    property MipMaps: boolean read m_MipMaps write SetMipMaps default false;
    property Vsync: boolean read m_Vsync write m_Vsync default false;
    property TruncatePixel: boolean read m_TruncatePixel write m_TruncatePixel default false;
    property FullScreen: boolean read m_FullScreen write SetFullScreen default false;
    property States: TDJXStates read m_States write m_States;
    property InitParams: TDJXInitialization read m_Initialization write m_Initialization;
    property Width: integer read m_Width write SetWidth default 800;
    property Height: integer read m_Height write SetHeight default 600;
    property DepthStencilWidth: integer read m_DepthStencilWidth write SetDepthStencilWidth default 800;
    property DepthStencilHeight: integer read m_DepthStencilHeight write SetDepthStencilHeight default 600;
    property OnInitialize: TNotifyEvent read m_OnInitialize write m_OnInitialize;
    property OnFinalize: TNotifyEvent read m_OnFinalize write m_OnFinalize;
    property OnLostDevice: TNotifyEvent read m_OnLostDevice write m_OnLostDevice;
    property OnResetDevice: TNotifyEvent read m_OnResetDevice write m_OnResetDevice;
  end;

  TDJXSwapChain = class(TObject)
  private
    m_DanJetX: Pointer;
    m_SwapChain: IDirect3DSwapChain9;
  public
    constructor Create(DanJetX: Pointer);
    destructor Destroy; override;
    property SwapChain: IDirect3DSwapChain9 read m_SwapChain write m_SwapChain;
  end;

  TDJXResources = class(TObject)
  private
    m_Resources: TList;
  protected
    function GetRes(Index: integer): TDJXRes;
  public
    constructor Create;
    destructor Destroy; override;
    property Resources[Index: integer]: TDJXRes read GetRes;
    function AddResource(Res: TDJXRes): TDJXRes;
    function RemoveResource(Res: TDJXRes): TDJXRes;
    function DeleteResource(Index: integer): TDJXRes;
    procedure FreeAndRemoveResource(Res: TDJXRes);
    procedure FreeAndDeleteResource(Index: integer);
    procedure FreeResources;
    function LinkResource(
      const FileName: string;
      const ResName: string;
      const EncKey: string = ''
    ): TDJXRes;
    function Find(Name: string): TDJXRes;
  end;

  PRes = ^TRes;
  TRes = record
    Name: string;
    DataPos: DWORD;
    DataLength: DWORD;
    Loaded: boolean;
    Bin: array of byte;
  end;

  PResFolder = ^TResFolder;
  TResFolder = record
    Name: string;
    Res: array of PRes;
  end;

  TDJXResBuffer = record
    Data: Pointer;
    Size: DWORD;
  end;

  TDJXRes = class(TObject)
  private
    m_Name: string;
    m_Folders: array of PResFolder;
    m_Linked: boolean;
    m_fs: TFileStream;
    m_ds: TDecompressionStream;
    m_Key: string;
  protected
    procedure PreLoadRes(const r: PRes);
    procedure UnLoadRes(const r: PRes);
    procedure Decrypt(const r: PRes);
    function FindRes(
      const Folder: string;
      const Res: string
    ): PRes;
  public
    constructor Create;
    destructor Destroy; override;
    property Name: string read m_Name;
    procedure Link(const FileName: string);
    procedure UnLink;
    function ResourceExists(
      const Folder: string;
      const Res: string
    ): boolean;
    procedure PreLoadResource(
      const Folder: string;
      const Res: string
    );
    procedure UnLoadResource(
      const Folder: string;
      const Res: string
    );
    function GetResBuffer(
      const Folder: string;
      const Res: string
    ): TDJXResBuffer;
  end;

implementation

uses
  DJXMeshes, DJXLights, DJXUtils, Types;

//TDanJetX BEGIN
procedure TDanJetX.SetMipMaps(Value: boolean);
var
  i: integer;
begin
  m_MipMaps := Value;
  if not m_Initialized then exit;
  for i := 0 to m_DeviceCaps.MaxTextureBlendStages - 1 do
  begin
    if m_MipMaps then
    begin
      m_States.SamplerStates.MipFilter[i] := D3DTEXF_LINEAR;
    end
    else
    begin
      m_States.SamplerStates.MipFilter[i] := D3DTEXF_NONE;
    end;
  end;
end;
procedure TDanJetX.SetFiltering(Value: boolean);
var
  i: integer;
begin
  m_Filtering := Value;
  if not m_Initialized then exit;
  for i := 0 to m_DeviceCaps.MaxTextureBlendStages - 1 do
  begin
    if m_Filtering then
    begin
      m_States.SamplerStates.MagFilter[i] := D3DTEXF_LINEAR;
      m_States.SamplerStates.MinFilter[i] := D3DTEXF_LINEAR;
    end
    else
    begin
      m_States.SamplerStates.MagFilter[i] := D3DTEXF_NONE;
      m_States.SamplerStates.MinFilter[i] := D3DTEXF_NONE;
    end;
  end;
end;
procedure TDanJetX.SetLights(Value: boolean);
begin
  m_Lights := Value;
  if not m_Initialized then exit;
  if m_Lights then
  begin
    m_States.RenderStates.Lighting := true;
  end
  else
  begin
    m_States.RenderStates.Lighting := false;
  end;
end;
procedure TDanJetX.setAmbient(Value: TDJXColor);
begin
  if not m_Initialized then exit;
  m_States.RenderStates.Ambient := Value;
end;
function TDanJetX.GetAmbient: TDJXColor;
var
  DWD: DWORD;
begin
  result := 0;
  if not m_Initialized then exit;
  result := m_States.RenderStates.Ambient;
end;
procedure TDanJetX.SetZbuffer(Value: boolean);
begin
  m_ZBuffer := Value;
  if not m_Initialized then exit;
  if m_Zbuffer then
  m_States.RenderStates.ZEnable := D3DZB_True
  else
  m_States.RenderStates.ZEnable := D3DZB_False;
end;

constructor TDanJetX.Create(AOwner: TComponent);
begin
  inherited create(AOwner);
  m_Width := 800;
  m_Height := 600;
  m_DepthStencilWidth := m_Width;
  m_DepthStencilHeight := m_Height;
  m_Initialized := false;
  m_Zbuffer := false;
  m_FullScreen := false;
  m_Filtering := false;
  m_MipMaps := false;
  m_BlendMode := bmNormal;
  m_Lights := false;
  m_Cull := cullCCW;
  m_TruncatePixel := false;
  m_Initialization := TDJXInitialization.Create;
  m_Initialization.DepthStencil := dsD16;
  m_Initialization.BBufferFormat := bbR5G6B5;
  m_Initialization.DeviceType := dtHAL;
  m_Initialization.VertexProcessing := vpSoftware;
  m_States := TDJXStates.Create;
  m_States.DanJetX := self;
  m_States.RenderStates := TDJXRenderStates.Create;
  m_States.RenderStates.States := m_States;
  m_States.SamplerStates := TDJXSamplerStates.Create;
  m_States.SamplerStates.States := m_States;
  m_States.TextureStageStates := TDJXTextureStageStates.Create;
  m_States.TextureStageStates.States := m_States;
  m_States.SetDefaults;
  m_ComponentList := TList.Create;
  m_Specs := TDJXSpecs.Create;
  m_LastSwapChain := nil;
end;
destructor TDanJetX.Destroy;
begin
  m_Specs.Free;
  m_ComponentList.Clear;
  m_ComponentList.Free;
  Finalize;
  inherited Destroy;
end;
procedure TDanJetX.Start(Handle: HWND);
begin
  m_hWnd := Handle;
  m_OwnWindow := false;
  CreateSubClasses;
  InitComponents;
  Initialize(m_hWnd);
end;
procedure TDanJetX.Start(WndTitle: string; WndProc: TFNWndProc; FullScreen: boolean = true);
var
  sw,sh: integer;
begin
  with m_DJXWC do
  begin
    cbSize := SizeOf(TWndClassEx);
    style := CS_CLASSDC;
    lpfnWndProc := WndProc;
    cbClsExtra := 0;
    cbWndExtra := 0;
    hInstance := 0;
    hIcon := 0;
    hCursor := 0;
    hbrBackground := 0;
    lpszMenuName := nil;
    lpszClassName := 'DanJetX';
    hIconSm := 0;
  end;

  RegisterClassEx(m_DJXWC);
  m_OwnWindow := true;

  sw := GetSystemMetrics(SM_CXSCREEN);
  sh := GetSystemMetrics(SM_CYSCREEN);
  m_Width := 800;
  m_Height := 600;
  
  m_hWnd := CreateWindow(
    'DanJetX', PChar(WndTitle),
    WS_POPUP or WS_EX_TOPMOST,
    (sw-800)div 2, (sh-600) div 2, 800, 600,
    GetDesktopWindow, 0, m_DJXWC.hInstance, nil
  );

  if FullScreen then
  begin
    ShowCursor(false);
    ShowWindow(m_hWnd, SW_SHOWMAXIMIZED);
    m_FullScreen := true;
  end
  else
  begin
    ShowCursor(true);
    ShowWindow(m_hWnd, SW_SHOWNORMAL);
    m_FullScreen := false;
  end;
  UpdateWindow(m_hWnd);
  createSubClasses;

  Initialize(m_hWnd);
end;
procedure TDanJetX.InitComponents;
var
  Parent: TComponent;
  i: integer;
begin
  Parent := Owner;
  while Parent <> nil do
  begin
    for i := 0 to Parent.ComponentCount - 1 do
    begin
      if Parent.Components[i] is TDJXComponent then
      TDJXComponent(Parent.Components[i]).Init(self);
    end;
    Parent := Parent.Owner;
  end;
end;
procedure TDanJetX.CreateSubClasses;
begin
  m_Render := TDJXRender.Create(self);
  m_Primitives2D := TDJXPrimitives2D.Create;
  m_Primitives3D := TDJXPrimitives3D.Create;
  m_Primitives2D.DanJetX := self;
  m_Primitives3D.DanJetX := self;
  m_DJXCamera := TDJXCamera.Create(self);
  m_DJXMatrices3D := TDJXMatrices3D.Create(self);
  m_DJXMatrices := TDJXMatrices.Create(self);
  m_DJXMatricesTex := TDJXMatricesTex.Create(self);
  m_MultiTexBlends := TDJXMultiTexBlendList.Create(self);
  m_SwapChains := TList.Create;
  m_Primitives2D.Filled := true;
  m_Primitives3D.Filled := true;
  m_VB3D := TDJXVB3D.Create(Self);
  m_VB2D := TDJXVB2D.Create(Self);
  m_Resources := TDJXResources.Create;
end;
procedure TDanJetX.DestroySubClasses;
begin
  m_Resources.Free;
  TDJXRender(m_Render).Free;
  m_DJXCamera.Free;
  m_DJXMatrices3D.Free;
  m_DJXMatrices.Free;
  m_DJXMatricesTex.Free;
  m_MultiTexBlends.Free;
  while m_SwapChains.Count > 0 do
  begin
    TDJXSwapChain(m_SwapChains.Items[0]).Free;
    m_SwapChains.Delete(0);
  end;
  m_SwapChains.Free;
  m_States.RenderStates.Free;
  m_States.SamplerStates.Free;
  m_States.TextureStageStates.Free;
  m_States.Free;
  m_Initialization.Free;
  m_Primitives2D.Free;
  m_Primitives3D.Free;
  m_VB3D.Free;
  m_VB2D.Free;
end;
function TDanJetX.SetUpDevice: HRESULT;
var
  DevType: _D3DDEVTYPE;
  BehaviorFlags: DWORD;
  hr: HRESULT;
  DisplayMode: TD3DDisplayMode;
  procedure SetFullScreenMode;
  var
    AdapterModeCount: integer;
    DisplayModes: array of TD3DDisplayMode;
    DisplayModeFound: boolean;
    DisplayModeSearchAbort: boolean;
    AdjustBBSize: boolean;
    i: integer;
    NewHeight: integer;
    NewWidth: integer;
  begin
    DisplayModeFound := false;
    DisplayModeSearchAbort := false;
    AdjustBBSize := false;
    AdapterModeCount := m_D3D9.GetAdapterModeCount(D3DADAPTER_DEFAULT, m_d3dpp.BackBufferFormat);
    SetLength(DisplayModes, AdapterModeCount);
    while not DisplayModeFound and not DisplayModeSearchAbort do
    begin
      for i := 0 to AdapterModeCount - 1 do
      begin
        m_D3D9.EnumAdapterModes(D3DADAPTER_DEFAULT, m_d3dpp.BackBufferFormat, i, DisplayModes[i]);
        if (DisplayModes[i].Width = m_Width)
        and (DisplayModes[i].Height = m_Height)
        and (DisplayModes[i].Format = m_d3dpp.BackBufferFormat) then
        begin
          move(DisplayModes[i], DisplayMode, sizeof(TD3DDisplayMode));
          DisplayModeFound := true;
        end;
      end;
      if not DisplayModeFound then
      begin
        if m_d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8 then
        begin
          m_d3dpp.BackBufferFormat := D3DFMT_X8R8G8B8;
          AdapterModeCount := m_D3D9.GetAdapterModeCount(D3DADAPTER_DEFAULT, m_d3dpp.BackBufferFormat);
          SetLength(DisplayModes, AdapterModeCount);
        end
        else if m_d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8 then
        begin
          m_d3dpp.BackBufferFormat := D3DFMT_R5G6B5;
          AdapterModeCount := m_D3D9.GetAdapterModeCount(D3DADAPTER_DEFAULT, m_d3dpp.BackBufferFormat);
          SetLength(DisplayModes, AdapterModeCount);
        end
        else
        begin
          if not AdjustBBSize then
          begin
            AdjustBBSize := true;
            m_d3dpp.BackBufferFormat := D3DFMT_A8R8G8B8;
            AdapterModeCount := m_D3D9.GetAdapterModeCount(D3DADAPTER_DEFAULT, m_d3dpp.BackBufferFormat);
            SetLength(DisplayModes, AdapterModeCount);
            NewWidth := -1; NewHeight := -1;
            for i := 0 to AdapterModeCount - 1 do
            begin
              m_D3D9.EnumAdapterModes(D3DADAPTER_DEFAULT, m_d3dpp.BackBufferFormat, i, DisplayModes[i]);
              if ((NewWidth = -1) or (NewHeight = -1))
              or (
                abs(m_Width - DisplayModes[i].Width) + abs(m_Height - DisplayModes[i].Height) <
                abs(m_Width - NewWidth) + abs(m_Height - NewHeight)
              ) then
              begin
                NewWidth := DisplayModes[i].Width;
              end;
            end;
            m_Width := NewWidth;
            m_Height := NewHeight;
          end
          else
          begin
            DisplayModeSearchAbort := true;
            if AdapterModeCount > 0 then
            move(DisplayModes[0], DisplayMode, sizeof(TD3DDisplayMode))
            else
            begin
              DisplayMode.Width := 800;
              DisplayMode.Height := 600;
              DisplayMode.Format := D3DFMT_X8R8G8B8;
            end;
          end;
        end;
      end;
    end;
  end;
var
  AAFormat: TD3DFormat;
begin
  Result := E_FAIL;

  m_D3D9.GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_DeviceCaps);

  FillChar(m_d3dpp, SizeOf(m_d3dpp), 0);
  m_d3dpp.Windowed := not m_FullScreen;

  if m_VSync then
  m_d3dpp.PresentationInterval := D3DPRESENT_INTERVAL_ONE
  else
  m_d3dpp.PresentationInterval := D3DPRESENT_INTERVAL_IMMEDIATE;

  m_d3dpp.EnableAutoDepthStencil := true;
  m_d3dpp.BackBufferCount := 1;    

  case m_Initialization.DepthStencil of
    dsD16:   m_d3dpp.AutoDepthStencilFormat := D3DFMT_D16;
    dsD24S8: m_d3dpp.AutoDepthStencilFormat := D3DFMT_D24S8;
  end; 

  if m_Initialization.Antialiasing = aaNone then
  m_d3dpp.Flags := D3DPRESENTFLAG_LOCKABLE_BACKBUFFER
  else
  m_d3dpp.Flags := 0;

  if m_FullScreen then
  begin
    case m_Initialization.BBufferFormat of
      bbA8R8G8B8:
      m_d3dpp.BackBufferFormat := D3DFMT_A8R8G8B8;
      bbX8R8G8B8:
      m_d3dpp.BackBufferFormat := D3DFMT_X8R8G8B8;
      bbR5G6B5:
      m_d3dpp.BackBufferFormat := D3DFMT_R5G6B5;
    end;
    SetFullScreenMode;
    m_d3dpp.SwapEffect := D3DSWAPEFFECT_DISCARD;
    m_d3dpp.BackBufferFormat := DisplayMode.Format;
    m_d3dpp.BackBufferWidth := DisplayMode.Width;
    m_d3dpp.BackBufferHeight := DisplayMode.Height;
  end
  else
  begin
    if (not m_VSync) or (not (m_Initialization.Antialiasing = aaNone)) then
    m_d3dpp.SwapEffect := D3DSWAPEFFECT_DISCARD
    else
    m_d3dpp.SwapEffect := D3DSWAPEFFECT_COPY;
    m_d3dpp.BackBufferWidth := m_Width;
    m_d3dpp.BackBufferHeight := m_Height;
    m_d3dpp.BackBufferFormat := D3DFMT_UNKNOWN;
  end;  

  case m_Initialization.Antialiasing of
    aaNone:
    begin
      m_d3dpp.MultiSampleType := D3DMULTISAMPLE_NONE;
      m_d3dpp.MultiSampleQuality := 0;
    end;
    aaNonMaskable:
    begin
      m_d3dpp.MultiSampleType := D3DMULTISAMPLE_NONMASKABLE;
      m_d3dpp.MultiSampleQuality := m_Initialization.AAQuality;
    end;
    aa2_Samples:
    begin
      m_d3dpp.MultiSampleType := D3DMULTISAMPLE_2_SAMPLES;
      m_d3dpp.MultiSampleQuality := 0;
    end;
    aa4_Samples:
    begin
      m_d3dpp.MultiSampleType := D3DMULTISAMPLE_4_SAMPLES;
      m_d3dpp.MultiSampleQuality := 0;
    end;
    aa6_Samples:
    begin
      m_d3dpp.MultiSampleType := D3DMULTISAMPLE_6_SAMPLES;
      m_d3dpp.MultiSampleQuality := 0;
    end;
  end;

  if m_Fullscreen then
  AAFormat := m_d3dpp.BackBufferFormat
  else
  AAFormat := D3DFMT_X8R8G8B8;

  while FAILED(
    m_D3D9.CheckDeviceMultiSampleType(
      m_DeviceCaps.AdapterOrdinal,
      m_DeviceCaps.DeviceType,
      AAFormat,
      m_d3dpp.Windowed,
      m_d3dpp.MultiSampleType,
      nil
    )
  )
  and (m_d3dpp.MultiSampleType <> D3DMULTISAMPLE_NONE) do     
  begin
    case m_d3dpp.MultiSampleType of
      D3DMULTISAMPLE_6_SAMPLES: m_d3dpp.MultiSampleType := D3DMULTISAMPLE_4_SAMPLES;
      D3DMULTISAMPLE_4_SAMPLES: m_d3dpp.MultiSampleType := D3DMULTISAMPLE_2_SAMPLES;
      D3DMULTISAMPLE_2_SAMPLES: m_d3dpp.MultiSampleType := D3DMULTISAMPLE_NONE;
      D3DMULTISAMPLE_NONMASKABLE:
      begin
        if m_d3dpp.MultiSampleQuality <= 0 then
        m_d3dpp.MultiSampleType := D3DMULTISAMPLE_6_SAMPLES
        else
        m_d3dpp.MultiSampleQuality := m_d3dpp.MultiSampleQuality - 1;
      end;
    end;
  end;

  if not m_Initialized then
  begin
    case m_Initialization.DeviceType of
      dtHAL: DevType := D3DDEVTYPE_HAL;
      dtREF: DevType := D3DDEVTYPE_REF;
      dtSW:  DevType := D3DDEVTYPE_SW;
    end;

    if (m_DeviceCaps.DevCaps and D3DDEVCAPS_HWTRANSFORMANDLIGHT = 0)
    or (m_DeviceCaps.VertexProcessingCaps = 0) then
    m_Initialization.VertexProcessing := vpSoftware;

    BehaviorFlags := 0;
    case m_Initialization.VertexProcessing of
      vpSoftware: BehaviorFlags := BehaviorFlags or D3DCREATE_SOFTWARE_VERTEXPROCESSING;
      vpHardware: BehaviorFlags := BehaviorFlags or D3DCREATE_HARDWARE_VERTEXPROCESSING;
      vpMixed: BehaviorFlags := BehaviorFlags or D3DCREATE_MIXED_VERTEXPROCESSING;
    end;

    Result := m_D3D9.CreateDevice(
      D3DADAPTER_DEFAULT,
      DevType,
      m_hWnd,
      BehaviorFlags,
      @m_d3dpp,
      m_Device
    );

    if FAILED(Result) then Exit;

    m_Initialized := true;
  end
  else
  begin
    safe_release(m_PrimaryBackBuffer);
    safe_release(m_DepthStencil);
    Result := m_Device.Reset(m_D3Dpp);

    if FAILED(Result) then exit;
  end;

  m_Device.GetDeviceCaps(m_DeviceCaps);

  m_Device.GetRenderTarget(0, m_PrimaryBackBuffer);

  m_Device.GetDepthStencilSurface(m_DepthStencil);
  if (m_DepthStencilWidth > m_Width)
  or (m_DepthStencilHeight > m_Height) then
  ResizeDepthStencil(m_DepthStencilWidth, m_DepthStencilHeight);

  
  m_Device.GetViewport(m_PrimaryViewPort);
  m_ViewPort := m_PrimaryViewPort;

  m_States.SetFromMemory;

  Zbuffer := m_Zbuffer;

  Filtering := m_Filtering;

  mipMaps := m_MipMaps;

  BlendMode := m_BlendMode;

  Lights3D := m_Lights;

  CullMode := m_Cull;

  SetDefaultMaterial;

  m_DeviceLost := false;

  m_DJXMatrices3D.ClearWorldMatrix;
  m_DJXMatrices3D.ApplyWorldMatrix;

  Result := S_OK;
end;
function TDanJetX.Initialize(hWnd: HWND): HRESULT;
begin
  Result := E_FAIL;

  m_D3D9 := Direct3DCreate9(D3D_SDK_VERSION);
  if (m_D3D9 = nil) then Exit;

  if m_OwnWindow then
  begin
    m_Zbuffer := false;
    m_Filtering := false;
    m_MipMaps := false;
    m_BlendMode := bmNormal;
    m_Lights := false;
    m_Cull := cullCCW;
  end;

  m_hWnd := hWnd;

  Result := SetUpDevice;
  if FAILED(Result) then exit;

  TDJXRender(m_Render).Init;
  Primitives2D.Init;
  Primitives3D.Init;

  if assigned(m_OnInitialize) and SUCCEEDED(Result) then
  m_OnInitialize(self);
end;
function TDanJetX.Reset: HRESULT;
var
  wRect: TRect;
  adjustWindow: boolean;
begin
  if not m_DeviceLost then
  begin
    LostDeviceStandard;
    if Assigned(m_OnLostDevice) then m_OnLostDevice(Self);
  end;
  getWindowRect(m_hWnd,wRect);
  if not m_d3dpp.Windowed and not m_Fullscreen and m_ownWindow then
  adjustwindow := true
  else
  adjustwindow := false;

  Result := SetUpDevice;

  if adjustwindow then
  setWindowPos(
    m_hWnd,0,
    (GetSystemMetrics(SM_CXSCREEN) - m_Width) div 2,
    (GetSystemMetrics(SM_CYSCREEN) - m_Height) div 2,
    m_Width, m_Height, SWP_SHOWWINDOW
  );

  if SUCCEEDED(Result) then
  ResetDeviceStandard;
end;

procedure TDanJetX.Finalize;
var
  i: integer;
begin
  if m_Initialized then
  begin
    for i := 0 to m_DeviceCaps.MaxTextureBlendStages - 1 do
    m_Device.SetTexture(i, nil);
    m_Primitives2D.UnInit;
    m_Primitives3D.UnInit;
    DestroySubClasses;
    if m_Device <> nil then
    m_Device := nil;
    if m_OwnWindow then
    begin
      UnregClass('DanJetX', m_DJXWC.hInstance);
    end;
    m_Initialized := false;
    if assigned(m_OnFinalize) then m_OnFinalize(self);
  end;
end;

function TDanJetX.CanRender: boolean;
var
  HRes: HRESULT;
begin
  result := false;
  if not m_Initialized then exit;
  hres := m_Device.TestCooperativeLevel;
  if SUCCEEDED(hres) then
  begin
    result := true;
    exit;
  end;
  if hres = D3DERR_DEVICENOTRESET then
  hres := Reset;
  if FAILED(hres) then
  begin
    if not m_DeviceLost then
    LostDeviceStandard;
    m_DeviceLost := true;
    result := false;
    exit;
  end
  else
  begin
    result := true;
    m_DeviceLost:=false;
  end;
end;

procedure TDanJetX.LostDeviceStandard;
var
  i: integer;
begin
  for i:=0 to m_ComponentList.Count - 1 do
  TDJXComponent(m_ComponentList.Items[i]).OnLostDevice;
  TDJXRender(m_Render).Shaders.OnLostDevice;
  if assigned(m_OnLostDevice) then m_OnLostDevice(self);
end;
procedure TDanJetX.ResetDeviceStandard;
var
  i: integer;
begin
  m_Device.SetTransform(D3DTS_PROJECTION, TDJXRender(m_Render).MatProj^);
  m_Device.SetTransform(D3DTS_VIEW, TDJXRender(m_Render).MatView^);
  m_Device.SetTransform(D3DTS_WORLD, TDJXRender(m_Render).MatWorld^);
  for i := 0 to m_ComponentList.Count - 1 do
  TDJXComponent(m_ComponentList.Items[i]).OnResetDevice;
  TDJXRender(m_Render).Shaders.OnResetDevice;
  if assigned(m_OnResetDevice) then m_OnResetDevice(self);
end;
procedure TDanJetX.SetWidth(Value: integer);
begin
  m_Width := Value;
  if m_DepthStencilWidth < m_Width then m_DepthStencilWidth := m_Width;
end;
procedure TDanJetX.SetHeight(Value: integer);
begin
  m_Height := Value;
  if m_DepthStencilHeight < m_Height then m_DepthStencilHeight := m_Height;
end;
procedure TDanJetX.SetDepthStencilWidth(Value: integer);
begin
  m_DepthStencilWidth := Value;
  if m_DepthStencilWidth < m_Width then m_DepthStencilWidth := m_Width;
end;
procedure TDanJetX.SetDepthStencilHeight(Value: integer);
begin
  m_DepthStencilHeight := Value;
  if m_DepthStencilHeight < m_Height then m_DepthStencilHeight := m_Height;
end;
procedure TDanJetX.SetSwapChain(Index: integer; Value: TDJXSwapChain);
begin
  if (Index < 0) or (Index > m_SwapChains.Count - 1) then exit;
  m_SwapChains.Items[Index] := Value;
end;
function TDanJetX.GetSwapChain(Index: integer): TDJXSwapChain;
begin
  if (Index < 0) or (Index > m_SwapChains.Count - 1) then
  begin
    Result := nil;
    exit;
  end;
  Result := TDJXSwapChain(m_SwapChains.Items[Index]);
end;

procedure TDanJetX.BBLock;
begin
  if (FAILED(m_PrimaryBackBuffer.GetDesc(m_SurfaceDesc))) then exit;
  if (FAILED(m_PrimaryBackBuffer.LockRect(m_SurfaceRect, nil, 0))) then exit;
  m_BBLocked := true;
end;

procedure TDanJetX.BBUnLock;
begin
  if not m_BBLocked then exit;
  m_PrimaryBackBuffer.UnlockRect;
  m_BBLocked := false;
end;

function TDanJetX.GetPixel(X,Y: integer): TDJXColor;
var
  t1, t2, tmp: word;
  pb: pbyte;
  r,g,b,a: byte;
begin
  Result := DJXColor(0,0,0);
  if not m_BBLocked then exit;
  case m_SurfaceDesc.Format of
    D3DFMT_X8R8G8B8,D3DFMT_A8R8G8B8:
    begin
      pb := pbyte(longint(m_SurfaceRect.pBits) + y * m_SurfaceRect.pitch + x * 4);
      b := pb^; inc(pb);
      g := pb^; inc(pb);
      r := pb^; inc(pb);
      a := pb^;
      result := DJXColor(r, g, b, a);
    end;
    D3DFMT_R8G8B8:
    begin
      pb := pbyte(longint(m_SurfaceRect.pBits) + y * m_SurfaceRect.pitch + x * 3);
      b := pb^; inc(pb);
      g := pb^; inc(pb);
      r := pb^;
      result:=DJXColor(r, g, b);
    end;
    D3DFMT_A4R4G4B4:
    begin
      pb := pbyte(longint(m_SurfaceRect.pBits) + y * m_SurfaceRect.pitch + x * 2);
      t2 := pb^; inc(pb);
      t1 := pb^;
      tmp:= t1 shl 8 + t2;
      b := (tmp and $0F) shl 4;
      g := ((tmp shr 4)  and $0F) shl 4;
      r := ((tmp shr 8)  and $0F) shl 4;
      a := ((tmp shr 12) and $0F) shl 4;
      result := DJXColor(r, g, b, a);
    end;
    D3DFMT_R5G6B5:
    begin
      pb := pbyte(longint(m_SurfaceRect.pBits) + y * m_SurfaceRect.pitch + x * 2);
      t2 := pb^; inc(pb);
      t1 := pb^;
      tmp := t1 shl 8 + t2;
      b := (tmp and $1F) shl 3;
      g := ((tmp shr 5)  and $3F) shl 2;
      r := ((tmp shr 11) and $1F) shl 3;
      result := DJXColor(r, g, b);
    end;
  end;
end;
procedure TDanJetX.SetPixel(X,Y: integer; Value: TDJXColor);
var
  r,g,b,a: byte;
  pb: pbyte;
  tmp: word;
begin
  if not m_BBLocked then exit;
  r := DJXColorR(Value);
  g := DJXColorG(Value);
  b := DJXColorB(Value);
  a := DJXColorA(Value);
  case m_SurfaceDesc.Format of
    D3DFMT_X8R8G8B8,D3DFMT_A8R8G8B8:
    begin
      pb := pbyte(longint(m_SurfaceRect.pBits) + y * m_SurfaceRect.pitch + x * 4);
      pb^ := b; inc(pb);
      pb^ := g; inc(pb);
      pb^ := r; inc(pb);
      pb^ := a;
    end;
    D3DFMT_R8G8B8:
    begin
      pb := pbyte(longint(m_SurfaceRect.pBits) + y * m_SurfaceRect.pitch + x * 3);
      pb^ := b; inc(pb);
      pb^ := g; inc(pb);
      pb^ := r;
    end;
    D3DFMT_A4R4G4B4:
    begin
      pb := pbyte(longint(m_SurfaceRect.pBits) + y * m_SurfaceRect.pitch + x * 2);
      tmp := (a shr 4) shl 12 + (r shr 4) shl 8 + (g shr 4) shl 4 + (b shr 4);
      pb^ := lo(tmp); inc(pb);
      pb^ := hi(tmp);
    end;
    D3DFMT_R5G6B5:
    begin
      pb := pbyte(longint(m_SurfaceRect.pBits) + y * m_SurfaceRect.pitch + x * 2);
      tmp := (r shr 3) shl 11 + (g shr 2) shl 5 + (b shr 3);
      pb^ := lo(tmp); inc(pb);
      pb^ := hi(tmp);
    end;
  end;
end;

procedure TDanJetX.SetDefaultMaterial;
var
  mtrl: TD3DMaterial9;
begin
  m_Device.GetMaterial(mtrl);
  mtrl.Diffuse.r := 1;
  mtrl.Diffuse.g := 1;
  mtrl.Diffuse.b := 1;
  mtrl.Diffuse.a := 1;
  mtrl.Ambient.r := 1;
  mtrl.Ambient.g := 1;
  mtrl.Ambient.b := 1;
  mtrl.Ambient.a := 1;
  m_Device.SetMaterial(mtrl);
end;

function TDanJetX.MousePos: TPoint;
var
  wRect: TRect;
  cRect: TRect;
begin
  GetWindowRect(m_hWnd, wRect);
  GetClientRect(m_hWnd, cRect);
  cRect.Left := cRect.Left + wRect.Left;
  cRect.Top := cRect.Top + wRect.Top;
  cRect.Right := cRect.Right + wRect.Left;
  cRect.Bottom := cRect.Bottom + wRect.Top;
  if not m_Initialized then
  begin
    Result.X := Mouse.CursorPos.X - cRect.Left;
    Result.Y := Mouse.CursorPos.Y - cRect.Top;
  end
  else
  begin
    Result.X := round((Mouse.CursorPos.X - (cRect.Left + m_ViewPort.X)) * (Width / (cRect.Right - cRect.Left)));
    Result.Y := round((Mouse.CursorPos.Y - (cRect.Top + m_ViewPort.Y)) * (Height / (cRect.Bottom - cRect.Top)));
  end;
end;
procedure TDanJetX.CenterCursor(var Shift: TPoint);
var
  sx,sy: integer;
  wRect: TRect;
begin
  if not m_Initialized then exit;
  getWindowRect(m_hWnd, wRect);
  sx := Mouse.CursorPos.X - (wRect.Left + m_ViewPort.Width div 2);
  sy := Mouse.CursorPos.Y - (wRect.Top + m_ViewPort.Height div 2);
  Shift := Point(sx, sy);
  Mouse.CursorPos := Point(
    wRect.Left + m_ViewPort.Width div 2,
    wRect.Top + m_ViewPort.Height div 2
  );
end;
procedure TDanJetX.SetDefaultVewPort;
begin
  m_Device.SetViewport(m_PrimaryViewPort);
end;
procedure TDanJetX.SetViewPort(X, Y, Width, Height: integer);
begin
  m_ViewPort.X := X;
  m_ViewPort.Y := Y;
  m_ViewPort.Width := Width;
  m_ViewPort.Height := Height;
  m_Device.SetViewport(m_ViewPort);
end;
function TDanJetX.VectorToWorld(Vec: TD3DXVector3): TD3DXVector3;
begin
  D3DXVec3TransformCoord(
    result, Vec,
    TDJXRender(m_Render).MatWorld^
  );
end;
function TDanJetX.BeginRender: boolean;
begin
  result := SUCCEEDED(m_Device.BeginScene);
end;
procedure TDanJetX.EndRender(Present: boolean = true);
var
  ZB: boolean;
begin
  if not States.RenderStates.ZEnable <> D3DZB_TRUE then
  begin
    ZB := m_Zbuffer;
    ZBuffer := true;
    m_Device.EndScene;
    ZBuffer := ZB;
  end
  else
  m_Device.EndScene;
  if Present then
  begin
    if m_LastSwapChain <> nil then
    m_LastSwapChain.SwapChain.Present(nil, nil, 0, nil, 0)
    else
    m_Device.Present(nil, nil, 0, nil);
  end;
end;
procedure TDanJetX.ClearTextureStages;
var
  i: integer;
begin
  for i := 0 to m_DeviceCaps.MaxTextureBlendStages - 1 do
  Device.SetTexture(i, nil);
end;
function TDanJetX.AddSwapChain(Handle: HWND; Width, Height: integer): TDJXSwapChain;
var
  d3dpp: TD3DPresentParameters;
begin
  if m_FullScreen then exit;
  ZeroMemory(@d3dpp, sizeof(TD3DPresentParameters));
  d3dpp.BackBufferWidth := Width;
  d3dpp.BackBufferHeight := Height;
  d3dpp.BackBufferFormat := m_d3dpp.BackBufferFormat;
  d3dpp.BackBufferCount := 1;
  d3dpp.MultiSampleType := m_d3dpp.MultiSampleType;
  d3dpp.MultiSampleQuality := m_d3dpp.MultiSampleQuality;
  d3dpp.SwapEffect := m_d3dpp.SwapEffect;
  d3dpp.hDeviceWindow := Handle;
  d3dpp.Windowed := true;
  d3dpp.EnableAutoDepthStencil := m_d3dpp.EnableAutoDepthStencil;
  d3dpp.AutoDepthStencilFormat := m_d3dpp.AutoDepthStencilFormat;
  d3dpp.Flags := m_d3dpp.Flags;
  d3dpp.PresentationInterval := m_d3dpp.PresentationInterval;
  Result := TDJXSwapChain.Create(Self);
  m_Device.CreateAdditionalSwapChain(d3dpp, Result.m_SwapChain);
  m_SwapChains.Add(Result);
end;
procedure TDanJetX.RemoveSwapChain(SwapChain: TDJXSwapChain);
begin
  m_SwapChains.Remove(SwapChain);
  SwapChain.Free;
end;
procedure TDanJetX.ClearScreen(r,g,b: byte; a: byte = 255);
begin
  m_Device.Clear(0, nil, D3DCLEAR_TARGET or D3DCLEAR_ZBUFFER, D3DCOLOR_RGBA(r, g, b, a), 1.0, 0);
end;
procedure TDanJetX.ClearScreen(Color: TDJXColor);
begin
  m_Device.Clear(0, nil, D3DCLEAR_TARGET or D3DCLEAR_ZBUFFER, Color, 1.0, 0);
end;
procedure TDanJetX.Clear(
  clearStencil: boolean;
  clearZBuffer: boolean;
  clearTarget: boolean = false;
  r: byte = 0; g: byte = 0; b: byte = 0; a: byte = 255
);
var
  clearObject: byte;
begin
  clearObject := 0;
  if clearStencil then
  clearObject := clearObject or D3DCLEAR_STENCIL;
  if clearZBuffer then
  clearObject := clearObject or D3DCLEAR_ZBUFFER;
  if clearTarget then
  clearObject := clearObject or D3DCLEAR_TARGET;
  m_Device.Clear(0, nil, clearObject, D3DCOLOR_RGBA(r, g, b, a), 1.0, 0);
end;
procedure TDanJetX.ClearStencil;
begin
  m_Device.Clear(0, nil, D3DCLEAR_STENCIL, 0, 0, 0);
end;
procedure TDanJetX.ClearTarget(r,g,b: byte; a: byte = 255);
begin
  m_Device.Clear(0, nil, D3DCLEAR_TARGET , D3DCOLOR_RGBA(r, g, b, a), 0, 0);
end;
procedure TDanJetX.ClearTarget(Color: TDJXColor);
begin
  m_Device.Clear(0, nil, D3DCLEAR_TARGET , Color, 0, 0);
end;
procedure TDanJetX.ClearZBuffer;
begin
  m_Device.Clear(0, nil, D3DCLEAR_ZBUFFER , 0, 1.0, 0);
end;
procedure TDanJetX.RenderToTexture(Texture: TDJXTexture);
var
  TextureSurface: IDirect3DSurface9;
begin
  Texture.Texture.GetSurfaceLevel(0, TextureSurface);
  RenderToSurface(TextureSurface, Texture.DepthStencil);
  safe_release(TextureSurface);
  m_LastSwapChain := nil;
end;
procedure TDanJetX.RenderToSwapChain(SwapChain: TDJXSwapChain);
var
  Surface: IDirect3DSurface9;
begin
  SwapChain.m_SwapChain.GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, Surface);
  RenderToSurface(Surface, nil);
  safe_release(Surface);
  m_LastSwapChain := SwapChain;
end;
procedure TDanJetX.RenderToSurface(Surface, DepthStencilSurface: IDirect3DSurface9);
begin
  m_Device.SetRenderTarget(0, Surface);
  if DepthStencilSurface <> nil then
  m_Device.SetDepthStencilSurface(DepthStencilSurface);
  m_Device.GetViewport(m_ViewPort);
end;
procedure TDanJetX.RenderToBackBuffer;
begin
  m_Device.SetRenderTarget(0, m_PrimaryBackBuffer);
  m_Device.SetDepthStencilSurface(m_DepthStencil);
  m_Device.GetViewport(m_ViewPort);
  m_LastSwapChain := nil;
end;
procedure TDanJetX.ResizeBackBuffer(NewWidth, NewHeight: DWORD);
begin
  Width := NewWidth;
  Height := NewHeight;
  Reset;
  if (m_DepthStencilWidth < m_Width)
  or (m_DepthStencilHeight < m_Height) then
  ResizeDepthStencil(m_Width, m_Height);
end;
procedure TDanJetX.ResizeDepthStencil(NewWidth, NewHeight: DWORD);
var
  DepthStencilDesc: TD3DSurfaceDesc;
begin
  m_DepthStencil.GetDesc(DepthStencilDesc);
  DepthStencilWidth := NewWidth;
  DepthStencilHeight := NewHeight;
  safe_release(m_DepthStencil);
  m_Device.CreateDepthStencilSurface(
    NewWidth, NewHeight,
    DepthStencilDesc.Format,
    DepthStencilDesc.MultiSampleType,
    DepthStencilDesc.MultiSampleQuality,
    false,
    m_DepthStencil,
    nil
  );
  m_Device.SetDepthStencilSurface(m_DepthStencil);
end;
procedure TDanJetX.SetFullScreen(Value: boolean);
begin
  m_FullScreen := Value;
  if not m_Initialized then exit;
  Reset;
end;
procedure TDanJetX.SetCull(Value: TDJXCullMode);
begin
  m_Cull := value;
  if not m_Initialized then exit;
  m_States.RenderStates.CullMode := DWORD(Value);
end;
procedure TDanJetX.SetBlendMode(Value: TDJXBlendMode);
begin
  m_BlendMode := TDJXBlendMode(byte(Value) mod (cardinal(high(TDJXBlendMode)) + 1));
  if not m_Initialized then exit;
  case m_BlendMode of
    bmNormal:
    begin
      m_States.RenderStates.SrcBlend := D3DBLEND_SRCALPHA;
      m_States.RenderStates.DestBlend := D3DBLEND_INVSRCALPHA;
    end;
    bmAdd:
    begin
      m_States.RenderStates.SrcBlend := D3DBLEND_ONE;
      m_States.RenderStates.DestBlend := D3DBLEND_ONE;
    end;
    bmSrcAdd:
    begin
      m_States.RenderStates.SrcBlend := D3DBLEND_SRCALPHA;
      m_States.RenderStates.DestBlend := D3DBLEND_ONE;
    end;
    bmSrcCol:
    begin
      m_States.RenderStates.SrcBlend := D3DBLEND_SRCCOLOR;
      m_States.RenderStates.DestBlend := D3DBLEND_INVSRCCOLOR;
    end;
    bmSrcColAdd:
    begin
      m_States.RenderStates.SrcBlend := D3DBLEND_SRCCOLOR;
      m_States.RenderStates.DestBlend := D3DBLEND_ONE;
    end;
    bmMultiply:
    begin
      m_States.RenderStates.SrcBlend := D3DBLEND_ZERO;
      m_States.RenderStates.DestBlend := D3DBLEND_SRCCOLOR;
    end;
    bmMultiplyAlpha:
    begin
      m_States.RenderStates.SrcBlend := D3DBLEND_ZERO;
      m_States.RenderStates.DestBlend := D3DBLEND_SRCALPHA;
    end;
    bmInvMultiply:
    begin
      m_States.RenderStates.SrcBlend := D3DBLEND_ZERO;
      m_States.RenderStates.DestBlend := D3DBLEND_INVSRCCOLOR;
    end;
    bmInvMultiplyAlpha:
    begin
      m_States.RenderStates.SrcBlend := D3DBLEND_ZERO;
      m_States.RenderStates.DestBlend := D3DBLEND_INVSRCALPHA;
    end;
    bmInvert:
    begin
      m_States.RenderStates.SrcBlend := D3DBLEND_INVDESTCOLOR;
      m_States.RenderStates.DestBlend := D3DBLEND_ZERO;
    end;
    bmSrcBright:
    begin
      m_States.RenderStates.SrcBlend := D3DBLEND_SRCCOLOR;
      m_States.RenderStates.DestBlend := D3DBLEND_SRCCOLOR;
    end;
    bmDestBright:
    begin
      m_States.RenderStates.SrcBlend := D3DBLEND_DESTCOLOR;
      m_States.RenderStates.DestBlend := D3DBLEND_DESTCOLOR;
    end;
    bmInvSrcBright:
    begin
      m_States.RenderStates.SrcBlend := D3DBLEND_INVSRCCOLOR;
      m_States.RenderStates.DestBlend := D3DBLEND_INVSRCCOLOR;
    end;
    bmInvDestBright:
    begin
      m_States.RenderStates.SrcBlend := D3DBLEND_INVDESTCOLOR;
      m_States.RenderStates.DestBlend := D3DBLEND_INVDESTCOLOR;
    end;
    bmNoFrameRender:
    begin
      m_States.RenderStates.SrcBlend := D3DBLEND_ZERO;
      m_States.RenderStates.DestBlend := D3DBLEND_ONE;
    end
  else
    m_States.RenderStates.SrcBlend := D3DBLEND_SRCALPHA;
    m_States.RenderStates.DestBlend := D3DBLEND_INVSRCALPHA;
  end;
end;
//TDanJetX END

//TDJXSwapChain BEGIN
constructor TDJXSwapChain.Create(DanJetX: Pointer);
begin
  inherited Create;
  m_DanJetX := DanJetX;
end;
destructor TDJXSwapChain.Destroy;
begin
  safe_release(m_SwapChain);
  inherited Destroy;
end;
//TDJXSwapChain END

//TDJXResources BEGIN
constructor TDJXResources.Create;
begin
  inherited Create;
  m_Resources := TList.Create;
end;

destructor TDJXResources.Destroy;
begin
  FreeResources;
  m_Resources.Free;
  inherited Destroy;
end;

function TDJXResources.GetRes(Index: integer): TDJXRes;
begin
  Result := TDJXRes(m_Resources.Items[Index]);
end;

function TDJXResources.AddResource(Res: TDJXRes): TDJXRes;
begin
  m_Resources.Add(Res);
  Result := Res;
end;

function TDJXResources.RemoveResource(Res: TDJXRes): TDJXRes;
begin
  Result := Res;
  m_Resources.Remove(Res);
end;

function TDJXResources.DeleteResource(Index: integer): TDJXRes;   
begin
  Result := TDJXRes(m_Resources.Items[Index]);
  m_Resources.Delete(Index);
end;

procedure TDJXResources.FreeAndRemoveResource(Res: TDJXRes);   
begin
  RemoveResource(Res).Free;
end;

procedure TDJXResources.FreeAndDeleteResource(Index: integer); 
begin
  DeleteResource(Index).Free;
end;

procedure TDJXResources.FreeResources;
begin
  while m_Resources.Count > 0 do
  begin
    TDJXRes(m_Resources.Items[0]).Free;
    m_Resources.Delete(0);
  end;
end;

function TDJXResources.LinkResource(
      const FileName: string;
      const ResName: string;
      const EncKey: string = ''
    ): TDJXRes;
begin
  Result := TDJXRes.Create;
  Result.m_Name := ResName;
  Result.m_Key := EncKey;
  Result.Link(FileName);
  AddResource(Result);
end;

function TDJXResources.Find(Name: string): TDJXRes;
var
  i: integer;
begin
  Result := nil;
  for i := 0 to m_Resources.Count - 1 do
  if LowerCase(TDJXRes(m_Resources.Items[i]).Name) = LowerCase(Name) then
  begin
    Result := TDJXRes(m_Resources.Items[i]);
    Break;
  end;
end;
//TDJXResources END

//TDJXRes BEGIN
constructor TDJXRes.Create;
begin
  inherited Create;
  m_Linked := false;
end;

destructor TDJXRes.Destroy;
begin
  if m_Linked then
  UnLink;
  inherited Destroy;
end;

procedure TDJXRes.PreLoadRes(const r: PRes);
begin
  if not m_Linked then Exit;
  m_ds.Seek(r^.DataPos, soFromCurrent);
  SetLength(r^.Bin, r^.DataLength);
  m_ds.Read(r^.Bin[0], r^.DataLength);
  m_ds.Position := 0;
  if Length(m_Key) > 0 then
  Decrypt(r);
  r^.Loaded := true;
end;

procedure TDJXRes.UnLoadRes(const r: PRes);
begin
  SetLength(r^.Bin, 0);
  r^.Loaded := false;
end;

procedure TDJXRes.Decrypt(const r: PRes);
var
  i: integer;
begin
  for i := 0 to r^.DataLength - 1 do
  r^.Bin[i] := r^.Bin[i] xor Ord(m_Key[(i mod Length(m_Key)) + 1]);
end;

function TDJXRes.FindRes(
      const Folder: string;
      const Res: string
    ): PRes;
var
  f: PResFolder;
  r: PRes;
begin
  Result := nil;
  if not m_Linked then Exit;
  for f in m_Folders do
  if LowerCase(f^.Name) = LowerCase(Folder) then
  begin
    for r in f^.Res do
    if LowerCase(r^.Name) = LowerCase(Res) then
    begin
      Result := r;
      Break;
    end;
  end;
end;

procedure TDJXRes.Link(const FileName: string);
type
  TFileHeader = packed record
    Definition: string[4];
    Version: DWORD;
    FolderCount: DWORD;
    DataPos: DWORD;
  end;
  TFileFolder = packed record
    Name: string[32];
    ResCount: DWORD;
  end;
  TFileRes = packed record
    Name: string[32];
    FName: string[255];
    DataPos: DWORD;
    DataLength: DWORD;
  end;
const
  Definition = 'DJXR';
  Version = 1;
var
  FHeader: TFileHeader;
  FFolder: TFileFolder;
  FRes: TFileRes;
  f, r: integer;
begin
  if not FileExists(FileName) then Exit;
  m_fs := TFileStream.Create(FileName, fmOpenRead);
  m_ds := TDEcompressionStream.Create(m_fs);
  m_ds.Read(FHeader, SizeOf(TFileHeader));
  if (FHeader.Definition <> Definition)
  or (FHeader.Version <> Version) then
  begin
    m_ds.Free;
    m_fs.Free;
    Exit;
  end;
  SetLength(m_Folders, FHeader.FolderCount);
  for f := 0 to High(m_Folders) do
  begin
    m_ds.Read(FFolder, SizeOf(TFileFolder));
    New(m_Folders[f]);
    m_Folders[f]^.Name := FFolder.Name;
    SetLength(m_Folders[f]^.Res, FFolder.ResCount);
    for r := 0 to High(m_Folders[f]^.Res) do
    begin
      m_ds.Read(FRes, SizeOf(TFileRes));
      New(m_Folders[f]^.Res[r]);
      m_Folders[f]^.Res[r]^.Name := FRes.Name;
      m_Folders[f]^.Res[r]^.DataPos := FRes.DataPos;
      m_Folders[f]^.Res[r]^.DataLength := FRes.DataLength;
      m_Folders[f]^.Res[r]^.Loaded := false;
    end;
  end;
  m_Linked := true;
  m_ds.Position := 0;
end;

procedure TDJXRes.UnLink;
var
  f: PResFolder;
  r: PRes;
begin
  m_ds.Free;
  m_fs.Free;
  for f in m_Folders do
  begin
    for r in f^.Res do
    begin
      if r^.Loaded then SetLength(r^.Bin, 0);
      Dispose(r);
    end;
    SetLength(f^.Res, 0);
    Dispose(f);
  end;
  SetLength(m_Folders, 0);
end;

function TDJXRes.ResourceExists(
      const Folder: string;
      const Res: string
    ): boolean;
begin
  Result := Assigned(FindRes(Folder, Res));
end;

procedure TDJXRes.PreLoadResource(
      const Folder: string;
      const Res: string
    );
var
  r: PRes;
begin
  r := FindRes(Folder, Res);
  if Assigned(r) then
  PreLoadRes(r);
end;

procedure TDJXRes.UnLoadResource(
      const Folder: string;
      const Res: string
    );
var
  r: PRes;
begin
  r := FindRes(Folder, Res);
  if Assigned(r) then
  UnLoadRes(r);
end;

function TDJXRes.GetResBuffer(const Folder: string; const Res: string): TDJXResBuffer;
var
  r: PRes;
begin
  r := FindRes(Folder, Res);
  if Assigned(r) then
  begin
    if not r^.Loaded then PreLoadRes(r);
    Result.Size := r^.DataLength;
    Result.Data := @r^.Bin[0];
  end;
end;
//TDJXRes END

end.
 