Subversion Repositories spacemission

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. unit DXClass;
  2.  
  3. interface
  4.  
  5. {$INCLUDE DelphiXcfg.inc}
  6.  
  7. uses
  8.   Windows, Messages, SysUtils, Classes, Controls, Forms, MMSystem, DirectX;
  9.  
  10. type
  11.  
  12.   {  EDirectDrawError  }
  13.  
  14.   EDirectXError = class(Exception);
  15.  
  16.   {  TDirectX  }
  17.  
  18.   TDirectX = class(TPersistent)
  19.   private
  20.     procedure SetDXResult(Value: HRESULT);
  21.   protected
  22.     FDXResult: HRESULT;
  23.     procedure Check; virtual;
  24.   public
  25.     property DXResult: HRESULT read FDXResult write SetDXResult;
  26.   end;
  27.  
  28.   {  TDirectXDriver  }
  29.  
  30.   TDirectXDriver = class(TCollectionItem)
  31.   private
  32.     FGUID: PGUID;
  33.     FGUID2: TGUID;
  34.     FDescription: string;
  35.     FDriverName: string;
  36.     procedure SetGUID(Value: PGUID);
  37.   public
  38.     property GUID: PGUID read FGUID write SetGUID;
  39.     property Description: string read FDescription write FDescription;
  40.     property DriverName: string read FDriverName write FDriverName;
  41.   end;
  42.  
  43.   {  TDirectXDrivers  }
  44.  
  45.   TDirectXDrivers = class(TCollection)
  46.   private
  47.     function GetDriver(Index: Integer): TDirectXDriver;
  48.   public
  49.     constructor Create;
  50.     property Drivers[Index: Integer]: TDirectXDriver read GetDriver; default;
  51.   end;
  52.  
  53.   {  TDXForm  }
  54.  
  55.   TDXForm = class(TForm)
  56.   private
  57.     FStoreWindow: Boolean;
  58.     FWindowPlacement: TWindowPlacement;
  59.     procedure WMSYSCommand(var Msg: TWMSYSCommand); message WM_SYSCOMMAND;
  60.   protected
  61.     procedure CreateParams(var Params: TCreateParams); override;
  62.   public
  63.     constructor Create(AOnwer: TComponent); override;
  64.     destructor Destroy; override;
  65.     procedure RestoreWindow;
  66.     procedure StoreWindow;
  67.   end;
  68.  
  69.   {  TCustomDXTimer  }
  70.  
  71.   TDXTimerEvent = procedure(Sender: TObject; LagCount: Integer) of object;
  72.  
  73.   TCustomDXTimer = class(TComponent)
  74.   private
  75.     FActiveOnly: Boolean;
  76.     FEnabled: Boolean;
  77.     FFrameRate: Integer;
  78.     FInitialized: Boolean;
  79.     FInterval: Cardinal;
  80.     FInterval2: Cardinal;
  81.     FNowFrameRate: Integer;
  82.     FOldTime: DWORD;
  83.     FOldTime2: DWORD;
  84.     FOnActivate: TNotifyEvent;
  85.     FOnDeactivate: TNotifyEvent;
  86.     FOnTimer: TDXTimerEvent;
  87.     procedure AppIdle(Sender: TObject; var Done: Boolean);
  88.     function AppProc(var Message: TMessage): Boolean;
  89.     procedure Finalize;
  90.     procedure Initialize;
  91.     procedure Resume;
  92.     procedure SetActiveOnly(Value: Boolean);
  93.     procedure SetEnabled(Value: Boolean);
  94.     procedure SetInterval(Value: Cardinal);
  95.     procedure Suspend;
  96.   protected
  97.     procedure DoActivate; virtual;
  98.     procedure DoDeactivate; virtual;
  99.     procedure DoTimer(LagCount: Integer); virtual;
  100.     procedure Loaded; override;
  101.   public
  102.     constructor Create(AOwner: TComponent); override;
  103.     destructor Destroy; override;
  104.     property ActiveOnly: Boolean read FActiveOnly write SetActiveOnly;
  105.     property Enabled: Boolean read FEnabled write SetEnabled;
  106.     property FrameRate: Integer read FFrameRate;
  107.     property Interval: Cardinal read FInterval write SetInterval;
  108.     property OnActivate: TNotifyEvent read FOnActivate write FOnActivate;
  109.     property OnDeactivate: TNotifyEvent read FOnDeactivate write FOnDeactivate;
  110.     property OnTimer: TDXTimerEvent read FOnTimer write FOnTimer;
  111.   end;
  112.  
  113.   {  TDXTimer  }
  114.  
  115.   TDXTimer = class(TCustomDXTimer)
  116.   published
  117.     property ActiveOnly;
  118.     property Enabled;
  119.     property Interval;
  120.     property OnActivate;
  121.     property OnDeactivate;
  122.     property OnTimer;
  123.   end;
  124.  
  125.   {  TControlSubClass  }
  126.  
  127.   TControlSubClassProc = procedure(var Message: TMessage; DefWindowProc: TWndMethod) of object;
  128.  
  129.   TControlSubClass = class
  130.   private
  131.     FControl: TControl;
  132.     FDefWindowProc: TWndMethod;
  133.     FWindowProc: TControlSubClassProc;
  134.     procedure WndProc(var Message: TMessage);
  135.   public
  136.     constructor Create(Control: TControl; WindowProc: TControlSubClassProc);
  137.     destructor Destroy; override;
  138.   end;
  139.  
  140.   {  THashCollectionItem  }
  141.  
  142.   THashCollectionItem = class(TCollectionItem)
  143.   private
  144.     FHashCode: Integer;
  145.     FIndex: Integer;
  146.     FName: string;
  147.     FLeft: THashCollectionItem;
  148.     FRight: THashCollectionItem;
  149.     procedure SetName(const Value: string);
  150.     procedure AddHash;
  151.     procedure DeleteHash;
  152.   protected
  153.     function GetDisplayName: string; override;
  154.     procedure SetIndex(Value: Integer); override;
  155.   public
  156.     constructor Create(Collection: TCollection); override;
  157.     destructor Destroy; override;
  158.     procedure Assign(Source: TPersistent); override;
  159.     property Index: Integer read FIndex write SetIndex;
  160.   published
  161.     property Name: string read FName write SetName;
  162.   end;
  163.  
  164.   {  THashCollection  }
  165.  
  166.   THashCollection = class(TCollection)
  167.   private
  168.     FHash: array[0..255] of THashCollectionItem;
  169.   public
  170.     function IndexOf(const Name: string): Integer;
  171.   end;
  172.  
  173. function Max(Val1, Val2: Integer): Integer;
  174. function Min(Val1, Val2: Integer): Integer;
  175.  
  176. function Cos256(i: Integer): Double;
  177. function Sin256(i: Integer): Double;
  178.  
  179. function PointInRect(const Point: TPoint; const Rect: TRect): Boolean;
  180. function RectInRect(const Rect1, Rect2: TRect): Boolean;
  181. function OverlapRect(const Rect1, Rect2: TRect): Boolean;
  182.  
  183. function WideRect(ALeft, ATop, AWidth, AHeight: Integer): TRect;
  184. procedure ReleaseCom(out Com);
  185. function DXLoadLibrary(const FileName, FuncName: string): TFarProc;
  186.  
  187. implementation
  188.  
  189. uses DXConsts;
  190.  
  191. function Max(Val1, Val2: Integer): Integer;
  192. begin
  193.   if Val1>=Val2 then Result := Val1 else Result := Val2;
  194. end;
  195.  
  196. function Min(Val1, Val2: Integer): Integer;
  197. begin
  198.   if Val1<=Val2 then Result := Val1 else Result := Val2;
  199. end;
  200.  
  201. function PointInRect(const Point: TPoint; const Rect: TRect): Boolean;
  202. begin
  203.   Result := (Point.X >= Rect.Left) and
  204.             (Point.X <= Rect.Right) and
  205.             (Point.Y >= Rect.Top) and
  206.             (Point.Y <= Rect.Bottom);
  207. end;
  208.  
  209. function RectInRect(const Rect1, Rect2: TRect): Boolean;
  210. begin
  211.   Result := (Rect1.Left >= Rect2.Left) and
  212.             (Rect1.Right <= Rect2.Right) and
  213.             (Rect1.Top >= Rect2.Top) and
  214.             (Rect1.Bottom <= Rect2.Bottom);
  215. end;
  216.  
  217. function OverlapRect(const Rect1, Rect2: TRect): Boolean;
  218. begin
  219.   Result := (Rect1.Left < Rect2.Right) and
  220.             (Rect1.Right > Rect2.Left) and
  221.             (Rect1.Top < Rect2.Bottom) and
  222.             (Rect1.Bottom > Rect2.Top);
  223. end;
  224.  
  225. function WideRect(ALeft, ATop, AWidth, AHeight: Integer): TRect;
  226. begin
  227.   with Result do
  228.   begin
  229.     Left := ALeft;
  230.     Top := ATop;
  231.     Right := ALeft+AWidth;
  232.     Bottom := ATop+AHeight;
  233.   end;
  234. end;
  235.  
  236. var
  237.   CosinTable: array[0..255] of Double;
  238.  
  239. procedure InitCosinTable;
  240. var
  241.   i: Integer;
  242. begin
  243.   for i:=0 to 255 do
  244.     CosinTable[i] := Cos((i/256)*2*PI);
  245. end;
  246.  
  247. function Cos256(i: Integer): Double;
  248. begin
  249.   Result := CosinTable[i and 255];
  250. end;
  251.  
  252. function Sin256(i: Integer): Double;
  253. begin
  254.   Result := CosinTable[(i+192) and 255];
  255. end;
  256.  
  257. procedure ReleaseCom(out Com);
  258. begin
  259. end;
  260.  
  261. var
  262.   LibList: TStringList;
  263.  
  264. function DXLoadLibrary(const FileName, FuncName: string): Pointer;
  265. var
  266.   i: Integer;
  267.   h: THandle;
  268. begin
  269.   if LibList=nil then
  270.     LibList := TStringList.Create;
  271.  
  272.   i := LibList.IndexOf(AnsiLowerCase(FileName));
  273.   if i=-1 then
  274.   begin
  275.     {  DLL is loaded.  }
  276.     h := LoadLibrary(PChar(FileName));
  277.     if h=0 then
  278.       raise Exception.CreateFmt(SDLLNotLoaded, [FileName]);
  279.     LibList.AddObject(AnsiLowerCase(FileName), Pointer(h));
  280.   end else
  281.   begin
  282.     {  DLL has already been loaded.  }
  283.     h := THandle(LibList.Objects[i]);
  284.   end;
  285.  
  286.   Result := GetProcAddress(h, PChar(FuncName));
  287.   if Result=nil then
  288.     raise Exception.CreateFmt(SDLLNotLoaded, [FileName]);
  289. end;
  290.  
  291. procedure FreeLibList;
  292. var
  293.   i: Integer;
  294. begin
  295.   if LibList<>nil then
  296.   begin
  297.     for i:=0 to LibList.Count-1 do
  298.       FreeLibrary(THandle(LibList.Objects[i]));
  299.     LibList.Free;
  300.   end;
  301. end;
  302.  
  303. {  TDirectX  }
  304.  
  305. procedure TDirectX.Check;
  306. begin
  307. end;
  308.  
  309. procedure TDirectX.SetDXResult(Value: HRESULT);
  310. begin
  311.   FDXResult := Value;
  312.   if FDXResult<>0 then Check;
  313. end;
  314.  
  315. {  TDirectXDriver  }
  316.  
  317. procedure TDirectXDriver.SetGUID(Value: PGUID);
  318. begin
  319.   if not IsBadHugeReadPtr(Value, SizeOf(TGUID)) then
  320.   begin
  321.     FGUID2 := Value^;
  322.     FGUID := @FGUID2;
  323.   end else
  324.     FGUID := Value;
  325. end;
  326.  
  327. {  TDirectXDrivers  }
  328.  
  329. constructor TDirectXDrivers.Create;
  330. begin
  331.   inherited Create(TDirectXDriver);
  332. end;
  333.  
  334. function TDirectXDrivers.GetDriver(Index: Integer): TDirectXDriver;
  335. begin
  336.   Result := (inherited Items[Index]) as TDirectXDriver;
  337. end;
  338.  
  339. {  TDXForm  }
  340.  
  341. var
  342.   SetAppExStyleCount: Integer;
  343.  
  344. constructor TDXForm.Create(AOnwer: TComponent);
  345. var
  346.   ExStyle: Integer;
  347. begin
  348.   inherited Create(AOnwer);
  349.   Inc(SetAppExStyleCount);
  350.   ExStyle := GetWindowLong(Application.Handle, GWL_EXSTYLE);
  351.   ExStyle := ExStyle or WS_EX_TOOLWINDOW;
  352.   SetWindowLong(Application.Handle, GWL_EXSTYLE, ExStyle);
  353. end;
  354.  
  355. destructor TDXForm.Destroy;
  356. var
  357.   ExStyle: Integer;
  358. begin
  359.   Dec(SetAppExStyleCount);
  360.   if SetAppExStyleCount=0 then
  361.   begin
  362.     ExStyle := GetWindowLong(Application.Handle, GWL_EXSTYLE);
  363.     ExStyle := ExStyle and (not WS_EX_TOOLWINDOW);
  364.     SetWindowLong(Application.Handle, GWL_EXSTYLE, ExStyle);
  365.   end;
  366.   inherited Destroy;
  367. end;
  368.  
  369. procedure TDXForm.CreateParams(var Params: TCreateParams);
  370. begin
  371.   inherited CreateParams(Params);
  372.   Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
  373. end;
  374.  
  375. procedure TDXForm.RestoreWindow;
  376. begin
  377.   if FStoreWindow then
  378.   begin
  379.     SetWindowPlacement(Handle, @FWindowPlacement);
  380.     FStoreWindow := False;
  381.   end;
  382. end;
  383.  
  384. procedure TDXForm.StoreWindow;
  385. begin
  386.   FWindowPlacement.Length := SizeOf(FWindowPlacement);
  387.   FStoreWindow := GetWindowPlacement(Handle, @FWindowPlacement);
  388. end;
  389.  
  390. procedure TDXForm.WMSYSCommand(var Msg: TWMSYSCommand);
  391. begin
  392.   if Msg.CmdType = SC_MINIMIZE then
  393.   begin
  394.     DefaultHandler(Msg);
  395.     WindowState := wsMinimized;
  396.   end else
  397.     inherited;
  398. end;
  399.  
  400. {  TCustomDXTimer  }
  401.  
  402. constructor TCustomDXTimer.Create(AOwner: TComponent);
  403. begin
  404.   inherited Create(AOwner);
  405.   FActiveOnly := True;
  406.   FEnabled := True;
  407.   Interval := 1000;
  408.   Application.HookMainWindow(AppProc);
  409. end;
  410.  
  411. destructor TCustomDXTimer.Destroy;
  412. begin
  413.   Finalize;
  414.   Application.UnHookMainWindow(AppProc);
  415.   inherited Destroy;
  416. end;
  417.  
  418. procedure TCustomDXTimer.AppIdle(Sender: TObject; var Done: Boolean);
  419. var
  420.   t, t2: DWORD;
  421.   LagCount, i: Integer;
  422. begin
  423.   Done := False;
  424.  
  425.   t := TimeGetTime;
  426.   t2 := t-FOldTime;
  427.   if t2>=FInterval then
  428.   begin
  429.     FOldTime := t;
  430.  
  431.     LagCount := t2 div FInterval2;
  432.     if LagCount<1 then LagCount := 1;
  433.  
  434.     Inc(FNowFrameRate);
  435.  
  436.     i := Max(t-FOldTime2, 1);
  437.     if i>=1000 then
  438.     begin
  439.       FFrameRate := Round(FNowFrameRate*1000/i);
  440.       FNowFrameRate := 0;
  441.       FOldTime2 := t;
  442.     end;
  443.  
  444.     DoTimer(LagCount);
  445.   end;
  446. end;
  447.  
  448. function TCustomDXTimer.AppProc(var Message: TMessage): Boolean;
  449. begin
  450.   Result := False;
  451.   case Message.Msg of
  452.     CM_ACTIVATE:
  453.         begin
  454.           DoActivate;
  455.           if FInitialized and FActiveOnly then Resume;
  456.         end;
  457.     CM_DEACTIVATE:
  458.         begin
  459.           DoDeactivate;
  460.           if FInitialized and FActiveOnly then Suspend;
  461.         end;
  462.   end;
  463. end;
  464.  
  465. procedure TCustomDXTimer.DoActivate;
  466. begin
  467.   if Assigned(FOnActivate) then FOnActivate(Self);
  468. end;
  469.  
  470. procedure TCustomDXTimer.DoDeactivate;
  471. begin
  472.   if Assigned(FOnDeactivate) then FOnDeactivate(Self);
  473. end;
  474.  
  475. procedure TCustomDXTimer.DoTimer(LagCount: Integer);
  476. begin
  477.   if Assigned(FOnTimer) then FOnTimer(Self, LagCount);
  478. end;
  479.  
  480. procedure TCustomDXTimer.Finalize;
  481. begin
  482.   if FInitialized then
  483.   begin
  484.     Suspend;
  485.     FInitialized := False;
  486.   end;
  487. end;
  488.  
  489. procedure TCustomDXTimer.Initialize;
  490. begin
  491.   Finalize;
  492.  
  493.   if ActiveOnly then
  494.   begin
  495.     if Application.Active then
  496.       Resume;
  497.   end else
  498.     Resume;
  499.   FInitialized := True;
  500. end;
  501.  
  502. procedure TCustomDXTimer.Loaded;
  503. begin
  504.   inherited Loaded;
  505.   if (not (csDesigning in ComponentState)) and FEnabled then
  506.     Initialize;
  507. end;
  508.  
  509. procedure TCustomDXTimer.Resume;
  510. begin
  511.   FOldTime := TimeGetTime;
  512.   FOldTime2 := TimeGetTime;
  513.   Application.OnIdle := AppIdle;
  514. end;
  515.  
  516. procedure TCustomDXTimer.SetActiveOnly(Value: Boolean);
  517. begin
  518.   if FActiveOnly<>Value then
  519.   begin
  520.     FActiveOnly := Value;
  521.  
  522.     if Application.Active and FActiveOnly then
  523.       if FInitialized and FActiveOnly then Suspend;
  524.   end;
  525. end;
  526.  
  527. procedure TCustomDXTimer.SetEnabled(Value: Boolean);
  528. begin
  529.   if FEnabled<>Value then
  530.   begin
  531.     FEnabled := Value;
  532.     if ComponentState*[csReading, csLoading]=[] then
  533.       if FEnabled then Initialize else Finalize;
  534.   end;
  535. end;
  536.  
  537. procedure TCustomDXTimer.SetInterval(Value: Cardinal);
  538. begin
  539.   if FInterval<>Value then
  540.   begin
  541.     FInterval := Max(Value, 0);
  542.     FInterval2 := Max(Value, 1);
  543.   end;
  544. end;
  545.  
  546. procedure TCustomDXTimer.Suspend;
  547. begin
  548.   Application.OnIdle := nil;
  549. end;
  550.  
  551. {  TControlSubClass  }
  552.  
  553. constructor TControlSubClass.Create(Control: TControl;
  554.   WindowProc: TControlSubClassProc);
  555. begin
  556.   inherited Create;
  557.   FControl := Control;
  558.   FDefWindowProc := FControl.WindowProc;
  559.   FControl.WindowProc := WndProc;
  560.   FWindowProc := WindowProc;
  561. end;
  562.  
  563. destructor TControlSubClass.Destroy;
  564. begin
  565.   FControl.WindowProc := FDefWindowProc;
  566.   inherited Destroy;
  567. end;
  568.  
  569. procedure TControlSubClass.WndProc(var Message: TMessage);
  570. begin
  571.   FWindowProc(Message, FDefWindowProc);
  572. end;
  573.  
  574. {  THashCollectionItem  }
  575.  
  576. function MakeHashCode(const Str: string): Integer;
  577. var
  578.   s: string;
  579. begin
  580.   s := AnsiLowerCase(Str);
  581.   Result := Length(s)*16;
  582.   if Length(s)>=2 then
  583.     Result := Result + (Ord(s[1]) + Ord(s[Length(s)-1]));
  584.   Result := Result and 255;
  585. end;
  586.                
  587. constructor THashCollectionItem.Create(Collection: TCollection);
  588. begin
  589.   inherited Create(Collection);
  590.   FIndex := inherited Index;
  591.   AddHash;
  592. end;
  593.  
  594. destructor THashCollectionItem.Destroy;
  595. var
  596.   i: Integer;
  597. begin
  598.   for i:=FIndex+1 to Collection.Count-1 do
  599.     Dec(THashCollectionItem(Collection.Items[i]).FIndex);
  600.   DeleteHash;
  601.   inherited Destroy;
  602. end;
  603.  
  604. procedure THashCollectionItem.Assign(Source: TPersistent);
  605. begin
  606.   if Source is THashCollectionItem then
  607.   begin
  608.     Name := THashCollectionItem(Source).Name;
  609.   end else
  610.     inherited Assign(Source);
  611. end;
  612.  
  613. procedure THashCollectionItem.AddHash;
  614. var
  615.   Item: THashCollectionItem;
  616. begin
  617.   FHashCode := MakeHashCode(FName);
  618.  
  619.   Item := THashCollection(Collection).FHash[FHashCode];
  620.   if Item<>nil then
  621.   begin
  622.     Item.FLeft := Self;
  623.     Self.FRight := Item;
  624.   end;
  625.  
  626.   THashCollection(Collection).FHash[FHashCode] := Self;
  627. end;
  628.  
  629. procedure THashCollectionItem.DeleteHash;
  630. begin
  631.   if FLeft<>nil then
  632.   begin
  633.     FLeft.FRight := FRight;
  634.     if FRight<>nil then
  635.       FRight.FLeft := FLeft;
  636.   end else
  637.   begin
  638.     if FHashCode<>-1 then
  639.     begin
  640.       THashCollection(Collection).FHash[FHashCode] := FRight;
  641.       if FRight<>nil then
  642.         FRight.FLeft := nil;
  643.     end;
  644.   end;
  645.   FLeft := nil;
  646.   FRight := nil;
  647. end;
  648.  
  649. function THashCollectionItem.GetDisplayName: string;
  650. begin
  651.   Result := Name;
  652.   if Result='' then Result := inherited GetDisplayName;
  653. end;
  654.  
  655. procedure THashCollectionItem.SetIndex(Value: Integer);
  656. begin
  657.   if FIndex<>Value then
  658.   begin
  659.     FIndex := Value;
  660.     inherited SetIndex(Value);
  661.   end;
  662. end;
  663.  
  664. procedure THashCollectionItem.SetName(const Value: string);
  665. begin
  666.   if FName<>Value then
  667.   begin
  668.     FName := Value;
  669.     DeleteHash;
  670.     AddHash;
  671.   end;
  672. end;
  673.  
  674. {  THashCollection  }
  675.  
  676. function THashCollection.IndexOf(const Name: string): Integer;
  677. var
  678.   Item: THashCollectionItem;
  679. begin
  680.   Item := FHash[MakeHashCode(Name)];
  681.   while Item<>nil do
  682.   begin
  683.     if AnsiCompareText(Item.Name, Name)=0 then
  684.     begin
  685.       Result := Item.FIndex;
  686.       Exit;
  687.     end;
  688.     Item := Item.FRight;
  689.   end;
  690.   Result := -1;
  691. end;
  692.  
  693. initialization
  694.   InitCosinTable;
  695. finalization
  696.   FreeLibList;
  697. end.
  698.