TweeningFm.pas 5.5 KB

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