fTweeningD.pas 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. unit fTweeningD;
  2. interface
  3. uses
  4. Winapi.Windows,
  5. Winapi.Messages,
  6. System.SysUtils,
  7. System.Variants,
  8. System.Classes,
  9. System.TypInfo,
  10. Vcl.Graphics,
  11. Vcl.Forms,
  12. Vcl.Dialogs,
  13. Vcl.Controls,
  14. Vcl.StdCtrls,
  15. Vcl.ExtCtrls,
  16. Vcl.Samples.Spin,
  17. GLS.Scene,
  18. Stage.VectorTypes,
  19. GLS.Objects,
  20. GLS.Coordinates,
  21. GLS.SceneViewer,
  22. GLS.BaseClasses,
  23. GLS.Cadencer,
  24. Stage.AnimationUtils,
  25. Stage.VectorGeometry,
  26. GLS.BitmapFont,
  27. GLS.WindowsFont;
  28. type
  29. TSinglePoint = record
  30. X: single;
  31. Y: single;
  32. end;
  33. // You can customize TAnimationState for your own purpose, you can add states or rename them, etc.
  34. TAnimationState = (asWaiting, asGoToStateA, asGoToStateB);
  35. TAnimationTime = record
  36. Current: Double;
  37. Initial: Double;
  38. Diff: Double;
  39. end;
  40. (*
  41. You can customize TAnimation for your own purpose,
  42. you can add InitialXValue for your custom data (Matrix or anything else).
  43. Note that you will maybe have to create your own Tweener function
  44. to use your custom Current/Target type.
  45. *)
  46. TAnimation = record
  47. State: TAnimationState;
  48. Time: TAnimationTime;
  49. Init: Boolean;
  50. Initial1iValue: Integer;
  51. Initial1sValue: single;
  52. Initial3fValue: TAffineVector;
  53. Initial4fValue: TGLVector;
  54. InitialPtValue: TSinglePoint;
  55. end;
  56. TFormTweening = class(TForm)
  57. GLScene1: TGLScene;
  58. GLSceneViewer1: TGLSceneViewer;
  59. GLCamera1: TGLCamera;
  60. GLPlane1: TGLPlane;
  61. Panel1: TPanel;
  62. Button1: TButton;
  63. GLCadencer1: TGLCadencer;
  64. Button2: TButton;
  65. PointA: TGLPoints;
  66. GLFlatText1: TGLFlatText;
  67. GLWindowsBitmapFont1: TGLWindowsBitmapFont;
  68. PointB: TGLPoints;
  69. GLFlatText2: TGLFlatText;
  70. UseCurrentPosition: TCheckBox;
  71. EaseTypeA: TComboBox;
  72. EaseTypeB: TComboBox;
  73. TimeA: TSpinEdit;
  74. TimeB: TSpinEdit;
  75. Label2: TLabel;
  76. Label1: TLabel;
  77. Label3: TLabel;
  78. Label4: TLabel;
  79. Label5: TLabel;
  80. procedure GLPlane1Progress(Sender: TObject; const deltaTime, newTime: Double);
  81. procedure Button1Click(Sender: TObject);
  82. procedure Button2Click(Sender: TObject);
  83. procedure GLSceneViewer1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  84. procedure FormCreate(Sender: TObject);
  85. private
  86. FGLPlane1AnimationData: TAnimation;
  87. public
  88. end;
  89. var
  90. FormTweening: TFormTweening;
  91. implementation
  92. {$R *.dfm}
  93. procedure TFormTweening.Button1Click(Sender: TObject);
  94. begin
  95. FGLPlane1AnimationData.State := asGoToStateA;
  96. FGLPlane1AnimationData.Init := True;
  97. end;
  98. procedure TFormTweening.Button2Click(Sender: TObject);
  99. begin
  100. FGLPlane1AnimationData.State := asGoToStateB;
  101. FGLPlane1AnimationData.Init := True;
  102. end;
  103. procedure TFormTweening.FormCreate(Sender: TObject);
  104. var
  105. EaseName: string;
  106. i: integer;
  107. begin
  108. // Fill combobox with human readable data from TEaseType
  109. for i := Ord(etLinear) to Ord(etBounceOutIn) do
  110. begin
  111. EaseName := GetEnumName(TypeInfo(TEaseType), Ord(TEaseType(i)));
  112. EaseTypeA.Items.Add(EaseName);
  113. EaseTypeB.Items.Add(EaseName);
  114. end;
  115. EaseTypeA.ItemIndex := Ord(etLinear);
  116. EaseTypeB.ItemIndex := Ord(etLinear);
  117. end;
  118. procedure TFormTweening.GLPlane1Progress(Sender: TObject; const deltaTime, newTime: Double);
  119. begin
  120. // Execute following code only if we are in state asGoToStateA
  121. if FGLPlane1AnimationData.State = asGoToStateA then
  122. begin
  123. // First we initialize value if requested
  124. if FGLPlane1AnimationData.Init = True then
  125. with FGLPlane1AnimationData do
  126. begin
  127. Init := False;
  128. Time.Initial := newTime;
  129. if UseCurrentPosition.Checked then
  130. Initial3fValue := GLPlane1.Position.AsAffineVector
  131. else
  132. Initial3fValue := PointB.Position.AsAffineVector;
  133. end;
  134. // Then we use the Tweener function to compute interpolation based on Initial values (time and position) and current ones
  135. with FGLPlane1AnimationData do
  136. begin
  137. Time.Diff := newTime - Time.Initial;
  138. GLPlane1.Position.AsAffineVector := Tweener(Initial3fValue, PointA.Position.AsAffineVector, Time.Diff, TimeA.Value/1000, TEaseType(EaseTypeA.ItemIndex));
  139. if Time.Diff >= TimeA.Value/1000 then
  140. State := asWaiting;
  141. end;
  142. end;
  143. // Execute following code only if we are in state asGoToStateB
  144. if FGLPlane1AnimationData.State = asGoToStateB then
  145. begin
  146. // First we initialize value if requested
  147. if FGLPlane1AnimationData.Init = True then
  148. with FGLPlane1AnimationData do
  149. begin
  150. Init := False;
  151. Time.Initial := newTime;
  152. if UseCurrentPosition.Checked then
  153. Initial3fValue := GLPlane1.Position.AsAffineVector
  154. else
  155. Initial3fValue := PointA.Position.AsAffineVector;
  156. end;
  157. // Then we use the Tweener function to compute interpolation based on Initial values (time and position) and current ones
  158. with FGLPlane1AnimationData do
  159. begin
  160. Time.Diff := newTime - Time.Initial;
  161. GLPlane1.Position.AsAffineVector := Tweener(Initial3fValue, PointB.Position.AsAffineVector, Time.Diff, TimeB.Value/1000, TEaseType(EaseTypeB.ItemIndex));
  162. if Time.Diff >= TimeB.Value/1000 then
  163. State := asWaiting;
  164. end;
  165. end;
  166. end;
  167. procedure TFormTweening.GLSceneViewer1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  168. begin
  169. if ssCtrl in Shift then
  170. begin
  171. if (Button = TMouseButton.mbLeft) then
  172. begin
  173. PointA.Position.X := X;
  174. PointA.Position.Y := GLSceneViewer1.Height-Y;
  175. end
  176. else if (Button = TMouseButton.mbRight) then
  177. begin
  178. PointB.Position.X := X;
  179. PointB.Position.Y := GLSceneViewer1.Height-Y;
  180. end;
  181. end;
  182. end;
  183. end.