GLS.Cadencer.pas 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698
  1. //
  2. // The graphics engine GLScene
  3. //
  4. unit GLS.Cadencer;
  5. (* The cadencer component (ease Progress processing) *)
  6. interface
  7. {$I Stage.Defines.inc}
  8. uses
  9. Winapi.Windows,
  10. Winapi.Messages,
  11. System.Classes,
  12. System.SysUtils,
  13. System.Types,
  14. VCL.Forms,
  15. GLS.Scene,
  16. GLS.BaseClasses;
  17. type
  18. (* Determines how the TGLCadencer operates.
  19. - cmManual : you must trigger progress manually (in your code)
  20. - cmASAP : progress is triggered As Soon As Possible after a previous
  21. progress (uses windows messages).
  22. - cmApplicationIdle : will hook Application.OnIdle, this will overwrite
  23. any previous event handle, and only one cadencer may be in this mode. *)
  24. TGLCadencerMode = (cmManual, cmASAP, cmApplicationIdle);
  25. (* Determines which time reference the TGLCadencer should use.
  26. - cmRTC : the Real Time Clock is used (precise over long periods, but
  27. not accurate to the millisecond, may limit your effective framerate
  28. to less than 50 FPS on some systems)
  29. - cmPerformanceCounter : the windows performance counter is used (nice
  30. precision, may derive over long periods, this is the default option
  31. as it allows the smoothest animation on fast systems)
  32. - cmExternal : the CurrentTime property is used *)
  33. TGLCadencerTimeReference = (cmRTC, cmPerformanceCounter, cmExternal);
  34. (* This component allows auto-progression of animation.
  35. Basicly dropping this component and linking it to your TGLScene will send
  36. it real-time progression events (time will be measured in seconds) while
  37. keeping the CPU 100% busy if possible (ie. if things change in your scene).
  38. The progression time (the one you'll see in you progression events)
  39. is calculated using (CurrentTime-OriginTime)*TimeMultiplier,
  40. CurrentTime being either manually or automatically updated using
  41. TimeReference (setting CurrentTime does NOT trigger progression). *)
  42. TGLCadencer = class(TComponent)
  43. private
  44. FSubscribedCadenceableComponents: TList;
  45. FScene: TGLScene;
  46. FTimeMultiplier: Double;
  47. lastTime, downTime, lastMultiplier: Double;
  48. FEnabled: Boolean;
  49. FSleepLength: Integer;
  50. FMode: TGLCadencerMode;
  51. FTimeReference: TGLCadencerTimeReference;
  52. FCurrentTime: Double;
  53. FOriginTime: Double;
  54. FMaxDeltaTime, FMinDeltaTime, FFixedDeltaTime: Double;
  55. FOnProgress, FOnTotalProgress : TGLProgressEvent;
  56. FProgressing: Integer;
  57. procedure SetCurrentTime(const Value: Double);
  58. protected
  59. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  60. function StoreTimeMultiplier: Boolean;
  61. procedure SetEnabled(const val: Boolean);
  62. procedure SetScene(const val: TGLScene);
  63. procedure SetMode(const val: TGLCadencerMode);
  64. procedure SetTimeReference(const val: TGLCadencerTimeReference);
  65. procedure SetTimeMultiplier(const val: Double);
  66. // Returns raw ref time (no multiplier, no offset)
  67. function GetRawReferenceTime: Double;
  68. procedure RestartASAP;
  69. procedure Loaded; override;
  70. procedure OnIdleEvent(Sender: TObject; var Done: Boolean);
  71. public
  72. constructor Create(AOwner: TComponent); override;
  73. destructor Destroy; override;
  74. procedure Subscribe(aComponent: TGLCadenceAbleComponent);
  75. procedure UnSubscribe(aComponent: TGLCadenceAbleComponent);
  76. (* Allows to manually trigger a progression.
  77. Time stuff is handled automatically.
  78. If cadencer is disabled, this functions does nothing. *)
  79. procedure Progress;
  80. // Adjusts CurrentTime if necessary, then returns its value.
  81. function GetCurrenttime: Double; inline;
  82. (* Returns True if a "Progress" is underway.
  83. Be aware that as long as IsBusy is True, the Cadencer may be
  84. sending messages and progression calls to cadenceable components
  85. and scenes. *)
  86. function IsBusy: Boolean;
  87. // Reset the time parameters and returns to zero.
  88. procedure Reset;
  89. // Value soustracted to current time to obtain progression time.
  90. property OriginTime: Double read FOriginTime write FOriginTime;
  91. // Current time (manually or automatically set, see TimeReference).
  92. property CurrentTime: Double read FCurrentTime write SetCurrentTime;
  93. published
  94. // The TGLScene that will be cadenced (progressed).
  95. property Scene: TGLScene read FScene write SetScene;
  96. (* Enables/Disables cadencing.
  97. Disabling won't cause a jump when restarting, it is working like
  98. a play/pause (ie. may modify OriginTime to keep things smooth). *)
  99. property Enabled: Boolean read FEnabled write SetEnabled default True;
  100. (* Defines how CurrentTime is updated.
  101. See TGLCadencerTimeReference.
  102. Dynamically changeing the TimeReference may cause a "jump". *)
  103. property TimeReference: TGLCadencerTimeReference read FTimeReference write
  104. SetTimeReference default cmPerformanceCounter;
  105. (* Multiplier applied to the time reference.
  106. Zero isn't an allowed value, and be aware that if negative values
  107. are accepted, they may not be supported by other GLScene objects.
  108. Changing the TimeMultiplier will alter OriginTime. *)
  109. property TimeMultiplier: Double read FTimeMultiplier write SetTimeMultiplier
  110. stored StoreTimeMultiplier;
  111. (* Maximum value for deltaTime in progression events.
  112. If null or negative, no max deltaTime is defined, otherwise, whenever
  113. an event whose actual deltaTime would be superior to MaxDeltaTime
  114. occurs, deltaTime is clamped to this max, and the extra time is hidden
  115. by the cadencer (it isn't visible in CurrentTime either).
  116. This option allows to limit progression rate in simulations where
  117. high values would result in errors/random behaviour. *)
  118. property MaxDeltaTime: Double read FMaxDeltaTime write FMaxDeltaTime;
  119. (* Minimum value for deltaTime in progression events.
  120. If superior to zero, this value specifies the minimum time step
  121. between two progression events.
  122. This option allows to limit progression rate in simulations where
  123. low values would result in errors/random behaviour. *)
  124. property MinDeltaTime: Double read FMinDeltaTime write FMinDeltaTime;
  125. (* Fixed time-step value for progression events.
  126. If superior to zero, progression steps will happen with that fixed
  127. delta time. The progression remains time based, so zero to N events
  128. may be fired depending on the actual deltaTime (if deltaTime is
  129. inferior to FixedDeltaTime, no event will be fired, if it is superior
  130. to two times FixedDeltaTime, two events will be fired, etc.).
  131. This option allows to use fixed time steps in simulations (while the
  132. animation and rendering itself may happen at a lower or higher
  133. framerate). *)
  134. property FixedDeltaTime: Double read FFixedDeltaTime write FFixedDeltaTime;
  135. // Adjusts how progression events are triggered. See TGLCadencerMode.
  136. property Mode: TGLCadencerMode read FMode write SetMode default cmASAP;
  137. (* Allows relinquishing time to other threads/processes.
  138. A "sleep" is issued BEFORE each progress if SleepLength>=0 (see
  139. help for the "sleep" procedure in delphi for details). *)
  140. property SleepLength: Integer read FSleepLength write FSleepLength default -1;
  141. // Happens AFTER scene was progressed.
  142. property OnProgress: TGLProgressEvent read FOnProgress write FOnProgress;
  143. // Happens AFTER all iterations with fixed delta time.
  144. property OnTotalProgress : TGLProgressEvent read FOnTotalProgress write FOnTotalProgress;
  145. end;
  146. // Adds a property to connect/subscribe to a cadencer.
  147. TGLCustomCadencedComponent = class(TGLUpdateAbleComponent)
  148. private
  149. FCadencer: TGLCadencer;
  150. protected
  151. procedure SetCadencer(const val: TGLCadencer);
  152. property Cadencer: TGLCadencer read FCadencer write SetCadencer;
  153. public
  154. destructor Destroy; override;
  155. procedure Notification(AComponent: TComponent; Operation: TOperation);
  156. override;
  157. end;
  158. TGLCadencedComponent = class(TGLCustomCadencedComponent)
  159. published
  160. property Cadencer;
  161. end;
  162. // ---------------------------------------------------------------------
  163. implementation
  164. // ---------------------------------------------------------------------
  165. const
  166. cTickGLCadencer = 'TickGLCadencer';
  167. type
  168. TASAPHandler = class
  169. private
  170. FTooFastCounter: Integer;
  171. FTimer: Cardinal;
  172. FWindowHandle: HWND;
  173. procedure WndProc(var Msg: TMessage); inline;
  174. public
  175. constructor Create;
  176. destructor Destroy; override;
  177. end;
  178. var
  179. vWMTickCadencer: Cardinal;
  180. vASAPCadencerList: TList;
  181. vHandler: TASAPHandler;
  182. vCounterFrequency: Int64;
  183. procedure RegisterASAPCadencer(aCadencer: TGLCadencer);
  184. begin
  185. if aCadencer.Mode = cmASAP then
  186. begin
  187. if not Assigned(vASAPCadencerList) then
  188. vASAPCadencerList := TList.Create;
  189. if vASAPCadencerList.IndexOf(aCadencer) < 0 then
  190. begin
  191. vASAPCadencerList.Add(aCadencer);
  192. if not Assigned(vHandler) then
  193. vHandler := TASAPHandler.Create;
  194. end;
  195. end
  196. else if aCadencer.Mode = cmApplicationIdle then
  197. Application.OnIdle := aCadencer.OnIdleEvent;
  198. end;
  199. procedure UnRegisterASAPCadencer(aCadencer: TGLCadencer);
  200. var
  201. i: Integer;
  202. begin
  203. if aCadencer.Mode = cmASAP then
  204. begin
  205. if Assigned(vASAPCadencerList) then
  206. begin
  207. i := vASAPCadencerList.IndexOf(aCadencer);
  208. if i >= 0 then
  209. vASAPCadencerList[i] := nil;
  210. end;
  211. end
  212. else if aCadencer.Mode = cmApplicationIdle then
  213. Application.OnIdle := nil;
  214. end;
  215. // ------------------
  216. // ------------------ TASAPHandler ------------------
  217. // ------------------
  218. constructor TASAPHandler.Create;
  219. begin
  220. inherited Create;
  221. FWindowHandle := AllocateHWnd(WndProc);
  222. PostMessage(FWindowHandle, vWMTickCadencer, 0, 0);
  223. end;
  224. destructor TASAPHandler.Destroy;
  225. begin
  226. if FTimer <> 0 then
  227. KillTimer(FWindowHandle, FTimer);
  228. DeallocateHWnd(FWindowHandle);
  229. inherited Destroy;
  230. end;
  231. var
  232. vWndProcInLoop: Boolean;
  233. procedure TASAPHandler.WndProc(var Msg: TMessage);
  234. var
  235. i: Integer;
  236. cad: TGLCadencer;
  237. begin
  238. // Windows.Beep(440, 10);
  239. with Msg do
  240. begin
  241. if Msg = WM_TIMER then
  242. begin
  243. KillTimer(FWindowHandle, FTimer);
  244. FTimer := 0;
  245. end;
  246. if (Msg <> WM_TIMER) and (Cardinal(GetMessageTime) = GetTickCount) then
  247. begin
  248. // if we're going too fast, "sleep" for 1 msec
  249. Inc(FTooFastCounter);
  250. if FTooFastCounter > 5000 then
  251. begin
  252. if FTimer = 0 then
  253. FTimer := SetTimer(FWindowHandle, 1, 1, nil);
  254. FTooFastCounter := 0;
  255. end;
  256. end
  257. else
  258. FTooFastCounter := 0;
  259. if FTimer <> 0 then
  260. begin
  261. Result := 0;
  262. Exit;
  263. end;
  264. if not vWndProcInLoop then
  265. begin
  266. vWndProcInLoop := True;
  267. try
  268. if (Msg = vWMTickCadencer) or (Msg = WM_TIMER) then
  269. begin
  270. // Progress
  271. for i := vASAPCadencerList.Count - 1 downto 0 do
  272. begin
  273. cad := TGLCadencer(vASAPCadencerList[i]);
  274. if Assigned(cad) and (cad.Mode = cmASAP)
  275. and cad.Enabled and (cad.FProgressing = 0) then
  276. begin
  277. if Application.Terminated then
  278. begin
  279. // force stop
  280. cad.Enabled := False
  281. end
  282. else
  283. begin
  284. try
  285. // do stuff
  286. cad.Progress;
  287. except
  288. Application.HandleException(Self);
  289. // it faulted, stop it
  290. cad.Enabled := False
  291. end
  292. end;
  293. end;
  294. end;
  295. // care for nils
  296. vASAPCadencerList.Pack;
  297. if vASAPCadencerList.Count = 0 then
  298. begin
  299. vASAPCadencerList.Free;
  300. vASAPCadencerList := nil;
  301. vHandler.Free;
  302. vHandler := nil;
  303. end
  304. else
  305. begin
  306. // Prepare the return of the infernal loop...
  307. PostMessage(FWindowHandle, vWMTickCadencer, 0, 0);
  308. end;
  309. end;
  310. finally
  311. vWndProcInLoop := False;
  312. end;
  313. end;
  314. Result := 0;
  315. end;
  316. end;
  317. // ------------------
  318. // ------------------ TGLCadencer ------------------
  319. // ------------------
  320. constructor TGLCadencer.Create(AOwner: TComponent);
  321. begin
  322. inherited Create(AOwner);
  323. FTimeReference := cmPerformanceCounter;
  324. downTime := GetRawReferenceTime;
  325. FOriginTime := downTime;
  326. FTimeMultiplier := 1;
  327. FSleepLength := -1;
  328. Mode := cmASAP;
  329. Enabled := True;
  330. end;
  331. destructor TGLCadencer.Destroy;
  332. begin
  333. Assert(FProgressing = 0);
  334. UnRegisterASAPCadencer(Self);
  335. FSubscribedCadenceableComponents.Free;
  336. FSubscribedCadenceableComponents := nil;
  337. inherited Destroy;
  338. end;
  339. procedure TGLCadencer.Subscribe(aComponent: TGLCadenceAbleComponent);
  340. begin
  341. if not Assigned(FSubscribedCadenceableComponents) then
  342. FSubscribedCadenceableComponents := TList.Create;
  343. if FSubscribedCadenceableComponents.IndexOf(aComponent) < 0 then
  344. begin
  345. FSubscribedCadenceableComponents.Add(aComponent);
  346. aComponent.FreeNotification(Self);
  347. end;
  348. end;
  349. procedure TGLCadencer.UnSubscribe(aComponent: TGLCadenceAbleComponent);
  350. var
  351. i: Integer;
  352. begin
  353. if Assigned(FSubscribedCadenceableComponents) then
  354. begin
  355. i := FSubscribedCadenceableComponents.IndexOf(aComponent);
  356. if i >= 0 then
  357. begin
  358. FSubscribedCadenceableComponents.Delete(i);
  359. aComponent.RemoveFreeNotification(Self);
  360. end;
  361. end;
  362. end;
  363. procedure TGLCadencer.Notification(AComponent: TComponent; Operation:
  364. TOperation);
  365. begin
  366. if Operation = opRemove then
  367. begin
  368. if AComponent = FScene then
  369. FScene := nil;
  370. if Assigned(FSubscribedCadenceableComponents) then
  371. FSubscribedCadenceableComponents.Remove(AComponent);
  372. end;
  373. inherited;
  374. end;
  375. procedure TGLCadencer.Loaded;
  376. begin
  377. inherited Loaded;
  378. RestartASAP;
  379. end;
  380. procedure TGLCadencer.OnIdleEvent(Sender: TObject; var Done: Boolean);
  381. begin
  382. Progress;
  383. Done := False;
  384. end;
  385. procedure TGLCadencer.RestartASAP;
  386. begin
  387. if not (csLoading in ComponentState) then
  388. begin
  389. if (Mode in [cmASAP, cmApplicationIdle]) and (not (csDesigning in
  390. ComponentState))
  391. and Assigned(FScene) and Enabled then
  392. RegisterASAPCadencer(Self)
  393. else
  394. UnRegisterASAPCadencer(Self);
  395. end;
  396. end;
  397. procedure TGLCadencer.SetEnabled(const val: Boolean);
  398. begin
  399. if FEnabled <> val then
  400. begin
  401. FEnabled := val;
  402. if not (csDesigning in ComponentState) then
  403. begin
  404. if Enabled then
  405. FOriginTime := FOriginTime + GetRawReferenceTime - downTime
  406. else
  407. downTime := GetRawReferenceTime;
  408. RestartASAP;
  409. end;
  410. end;
  411. end;
  412. procedure TGLCadencer.SetScene(const val: TGLScene);
  413. begin
  414. if FScene <> val then
  415. begin
  416. if Assigned(FScene) then
  417. FScene.RemoveFreeNotification(Self);
  418. FScene := val;
  419. if Assigned(FScene) then
  420. FScene.FreeNotification(Self);
  421. RestartASAP;
  422. end;
  423. end;
  424. procedure TGLCadencer.SetTimeMultiplier(const val: Double);
  425. var
  426. rawRef: Double;
  427. begin
  428. if val <> FTimeMultiplier then
  429. begin
  430. if val = 0 then
  431. begin
  432. lastMultiplier := FTimeMultiplier;
  433. Enabled := False;
  434. end
  435. else
  436. begin
  437. rawRef := GetRawReferenceTime;
  438. if FTimeMultiplier = 0 then
  439. begin
  440. Enabled := True;
  441. // continuity of time:
  442. // (rawRef-newOriginTime)*val = (rawRef-FOriginTime)*lastMultiplier
  443. FOriginTime := rawRef - (rawRef - FOriginTime) * lastMultiplier / val;
  444. end
  445. else
  446. begin
  447. // continuity of time:
  448. // (rawRef-newOriginTime)*val = (rawRef-FOriginTime)*FTimeMultiplier
  449. FOriginTime := rawRef - (rawRef - FOriginTime) * FTimeMultiplier / val;
  450. end;
  451. end;
  452. FTimeMultiplier := val;
  453. end;
  454. end;
  455. function TGLCadencer.StoreTimeMultiplier: Boolean;
  456. begin
  457. Result := (FTimeMultiplier <> 1);
  458. end;
  459. procedure TGLCadencer.SetMode(const val: TGLCadencerMode);
  460. begin
  461. if FMode <> val then
  462. begin
  463. if FMode <> cmManual then
  464. UnRegisterASAPCadencer(Self);
  465. FMode := val;
  466. RestartASAP;
  467. end;
  468. end;
  469. procedure TGLCadencer.SetTimeReference(const val: TGLCadencerTimeReference);
  470. begin
  471. // nothing more, yet
  472. FTimeReference := val;
  473. end;
  474. procedure TGLCadencer.Progress;
  475. var
  476. deltaTime, newTime, totalDelta: Double;
  477. fullTotalDelta, firstLastTime : Double;
  478. i: Integer;
  479. pt: TGLProgressTimes;
  480. begin
  481. // basic protection against infinite loops,
  482. // shall never happen, unless there is a bug in user code
  483. if FProgressing < 0 then
  484. Exit;
  485. if Enabled then
  486. begin
  487. // avoid stalling everything else...
  488. if SleepLength >= 0 then
  489. Sleep(SleepLength);
  490. // in manual mode, the user is supposed to make sure messages are handled
  491. // in Idle mode, this processing is implicit
  492. if Mode = cmASAP then
  493. begin
  494. Application.ProcessMessages;
  495. if (not Assigned(vASAPCadencerList))
  496. or (vASAPCadencerList.IndexOf(Self) < 0) then
  497. Exit;
  498. end;
  499. end;
  500. Inc(FProgressing);
  501. try
  502. if Enabled then
  503. begin
  504. // One of the processed messages might have disabled us
  505. if Enabled then
  506. begin
  507. // ...and progress !
  508. newTime := GetCurrenttime;
  509. deltaTime := newTime - lastTime;
  510. if (deltaTime >= MinDeltaTime) and (deltaTime >= FixedDeltaTime) then
  511. begin
  512. if FMaxDeltaTime > 0 then
  513. begin
  514. if deltaTime > FMaxDeltaTime then
  515. begin
  516. FOriginTime := FOriginTime + (deltaTime - FMaxDeltaTime) /
  517. FTimeMultiplier;
  518. deltaTime := FMaxDeltaTime;
  519. newTime := lastTime + deltaTime;
  520. end;
  521. end;
  522. totalDelta := deltaTime;
  523. fullTotalDelta := totalDelta;
  524. firstLastTime := lastTime;
  525. if FixedDeltaTime > 0 then
  526. deltaTime := FixedDeltaTime;
  527. while totalDelta >= deltaTime do
  528. begin
  529. lastTime := lastTime + deltaTime;
  530. if Assigned(FScene) and (deltaTime <> 0) then
  531. begin
  532. FProgressing := -FProgressing;
  533. try
  534. FScene.Progress(deltaTime, lastTime);
  535. finally
  536. FProgressing := -FProgressing;
  537. end;
  538. end;
  539. pt.deltaTime := deltaTime;
  540. pt.newTime := lastTime;
  541. i := 0;
  542. while Assigned(FSubscribedCadenceableComponents) and
  543. (i <= FSubscribedCadenceableComponents.Count - 1) do
  544. begin
  545. TGLCadenceAbleComponent(FSubscribedCadenceableComponents[i]).DoProgress(pt);
  546. i := i + 1;
  547. end;
  548. if Assigned(FOnProgress) and (not (csDesigning in ComponentState))
  549. then
  550. FOnProgress(Self, deltaTime, newTime);
  551. if deltaTime <= 0 then
  552. Break;
  553. totalDelta := totalDelta - deltaTime;
  554. end;
  555. if Assigned(FOnTotalProgress)
  556. and (not (csDesigning in ComponentState)) then
  557. FOnTotalProgress(Self, fullTotalDelta, firstLastTime);
  558. end;
  559. end;
  560. end;
  561. finally
  562. Dec(FProgressing);
  563. end;
  564. end;
  565. function TGLCadencer.GetRawReferenceTime: Double;
  566. var
  567. counter: Int64;
  568. begin
  569. case FTimeReference of
  570. cmRTC: // Real Time Clock
  571. Result := Now * (3600 * 24);
  572. cmPerformanceCounter:
  573. begin // HiRes Performance Counter
  574. QueryPerformanceCounter(counter);
  575. Result := counter / vCounterFrequency;
  576. end;
  577. cmExternal: // User defined value
  578. Result := FCurrentTime;
  579. else
  580. Result := 0;
  581. Assert(False);
  582. end;
  583. end;
  584. function TGLCadencer.GetCurrenttime: Double;
  585. begin
  586. Result := (GetRawReferenceTime - FOriginTime) * FTimeMultiplier;
  587. FCurrentTime := Result;
  588. end;
  589. function TGLCadencer.IsBusy: Boolean;
  590. begin
  591. Result := (FProgressing <> 0);
  592. end;
  593. procedure TGLCadencer.Reset;
  594. begin
  595. LastTime := 0;
  596. DownTime := GetRawReferenceTime;
  597. FOriginTime := downTime;
  598. end;
  599. procedure TGLCadencer.SetCurrentTime(const Value: Double);
  600. begin
  601. LastTime := Value - (FCurrentTime - LastTime);
  602. FOriginTime := FOriginTime + (FCurrentTime - Value);
  603. FCurrentTime := Value;
  604. end;
  605. // ------------------
  606. // ------------------ TGLCustomCadencedComponent ------------------
  607. // ------------------
  608. destructor TGLCustomCadencedComponent.Destroy;
  609. begin
  610. Cadencer := nil;
  611. inherited Destroy;
  612. end;
  613. procedure TGLCustomCadencedComponent.Notification(AComponent: TComponent;
  614. Operation: TOperation);
  615. begin
  616. if (Operation = opRemove) and (AComponent = FCadencer) then
  617. Cadencer := nil;
  618. inherited;
  619. end;
  620. procedure TGLCustomCadencedComponent.SetCadencer(const val: TGLCadencer);
  621. begin
  622. if FCadencer <> val then
  623. begin
  624. if Assigned(FCadencer) then
  625. FCadencer.UnSubscribe(Self);
  626. FCadencer := val;
  627. if Assigned(FCadencer) then
  628. FCadencer.Subscribe(Self);
  629. end;
  630. end;
  631. // ---------------------------------------------------------------------
  632. initialization
  633. // ---------------------------------------------------------------------
  634. RegisterClasses([TGLCadencer]);
  635. // Get our Windows message ID
  636. vWMTickCadencer := RegisterWindowMessage(cTickGLCadencer);
  637. // Preparation for high resolution timer
  638. if not QueryPerformanceFrequency(vCounterFrequency) then
  639. vCounterFrequency := 0;
  640. finalization
  641. FreeAndNil(vHandler);
  642. FreeAndNil(vASAPCadencerList);
  643. end.