fActorD.pas 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. unit fActorD;
  2. interface
  3. uses
  4. Winapi.OpenGL,
  5. System.Types,
  6. System.SysUtils,
  7. System.Classes,
  8. System.Math,
  9. Vcl.StdCtrls,
  10. Vcl.Buttons,
  11. Vcl.Controls,
  12. Vcl.ExtCtrls,
  13. Vcl.Imaging.Jpeg,
  14. Vcl.ComCtrls,
  15. Vcl.Forms,
  16. GLS.Cadencer,
  17. GLS.VectorFileObjects,
  18. GLS.Scene,
  19. GLS.Objects,
  20. GLScene.VectorGeometry,
  21. GLS.SceneViewer,
  22. GLS.FileMD2,
  23. GLS.GeomObjects,
  24. GLS.Coordinates,
  25. GLS.BaseClasses,
  26. GLScene.Utils;
  27. type
  28. TFormActor = class(TForm)
  29. GLScene1: TGLScene;
  30. Camera: TGLCamera;
  31. LightSource: TGLLightSource;
  32. DummyCube: TGLDummyCube;
  33. DiskRing: TGLDisk;
  34. GLSceneViewer1: TGLSceneViewer;
  35. Actor1: TGLActor;
  36. Actor2: TGLActor;
  37. GLCadencer1: TGLCadencer;
  38. StatusBar1: TStatusBar;
  39. Panel1: TPanel;
  40. SBPlay: TSpeedButton;
  41. SBStop: TSpeedButton;
  42. cbxAnimations: TComboBox;
  43. BBLoadWeapon: TBitBtn;
  44. SBFrameToFrame: TSpeedButton;
  45. lblAnimation: TLabel;
  46. chbSmooth: TCheckBox;
  47. Timer1: TTimer;
  48. lblDiskSlices: TLabel;
  49. cbxDiskSlices: TComboBox;
  50. procedure GLSceneViewer1MouseDown(Sender: TObject; Button: TMouseButton;
  51. Shift: TShiftState; X, Y: Integer);
  52. procedure GLSceneViewer1MouseMove(Sender: TObject; Shift: TShiftState;
  53. X, Y: Integer);
  54. procedure FormMouseWheel(Sender: TObject; Shift: TShiftState;
  55. WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
  56. procedure SBPlayClick(Sender: TObject);
  57. procedure SBStopClick(Sender: TObject);
  58. procedure FormCreate(Sender: TObject);
  59. procedure BBLoadWeaponClick(Sender: TObject);
  60. procedure cbxAnimationsChange(Sender: TObject);
  61. procedure SBFrameToFrameClick(Sender: TObject);
  62. procedure Actor1FrameChanged(Sender: TObject);
  63. procedure chbSmoothClick(Sender: TObject);
  64. procedure Timer1Timer(Sender: TObject);
  65. procedure GLCadencer1Progress(Sender: TObject;
  66. const deltaTime, newTime: Double);
  67. procedure cbxDiskSlicesChange(Sender: TObject);
  68. private
  69. mdx, mdy: Integer;
  70. public
  71. end;
  72. var
  73. FormActor: TFormActor;
  74. i: Integer;
  75. //--------------------------------------
  76. implementation
  77. //--------------------------------------
  78. {$R *.DFM}
  79. procedure TFormActor.FormCreate(Sender: TObject);
  80. begin
  81. var Path: TFileName := GetCurrentAssetPath();
  82. SetCurrentDir(Path + '\texture');
  83. // Load Texture for ground disk
  84. DiskRing.Material.Texture.Disabled := False;
  85. DiskRing.Material.Texture.Image.LoadFromFile('clover.jpg');
  86. // Load dynamic model of Actor with animation
  87. SetCurrentDir(Path + '\modelext');
  88. Actor1.LoadFromFile('waste.md2');
  89. // Load Texture for Actor1 and Weapon
  90. Actor1.Material.Texture.Disabled := False;
  91. Actor1.Material.Texture.Image.LoadFromFile('Waste.jpg');
  92. Actor2.Material.Texture.Disabled := False;
  93. Actor2.Material.Texture.Image.LoadFromFile('WeaponWaste.jpg');
  94. // Load Quake2 animations defaults, for "waste.md2", this is not required
  95. // since the author did not renamed the frames, and thus, GLScene can
  96. // recover them from the .MD2, but other authors just made a mess...
  97. // Loading the default animations takes care of that
  98. Actor1.Animations.LoadFromFile('Quake2Animations.aaf');
  99. // Scale Actor for put in the Scene
  100. Actor1.Scale.SetVector(0.04, 0.04, 0.04, 0);
  101. // Send animation names to the combo, to allow user selection
  102. Actor1.Animations.SetToStrings(cbxAnimations.Items);
  103. // Force state to stand (first in list)
  104. cbxAnimations.ItemIndex := 0;
  105. cbxAnimationsChange(Self);
  106. cbxDiskSlices.ItemIndex := 5; // 64
  107. cbxDiskSlicesChange(Self);
  108. end;
  109. procedure TFormActor.SBPlayClick(Sender: TObject);
  110. begin
  111. // start playing
  112. Actor1.AnimationMode := aamLoop;
  113. Actor2.AnimationMode := aamLoop;
  114. // update buttons
  115. SBPlay.Enabled := False;
  116. SBStop.Enabled := True;
  117. SBFrameToFrame.Enabled := False;
  118. end;
  119. procedure TFormActor.SBStopClick(Sender: TObject);
  120. begin
  121. // stop playing
  122. Actor1.AnimationMode := aamNone;
  123. Actor2.AnimationMode := aamNone;
  124. // update buttons
  125. SBPlay.Enabled := True;
  126. SBStop.Enabled := False;
  127. SBFrameToFrame.Enabled := True;
  128. end;
  129. procedure TFormActor.BBLoadWeaponClick(Sender: TObject);
  130. begin
  131. // Load weapon model and texture
  132. Actor2.LoadFromFile('WeaponWaste.md2');
  133. // Get animations frames from the main actor
  134. Actor2.Animations.Assign(Actor1.Animations);
  135. // Synch both actors
  136. Actor2.Synchronize(Actor1);
  137. end;
  138. // Combo Box with Animations
  139. procedure TFormActor.cbxAnimationsChange(Sender: TObject);
  140. begin
  141. // Change animation
  142. Actor1.SwitchToAnimation(cbxAnimations.Text, True);
  143. // Normally actors for Quake II Model have one number of frames
  144. // for all states 198 for actors and 172 for weapon,
  145. // frames 173 to 198 are for death. We use this for Hide and show weapon.
  146. Actor2.Visible := (Actor1.NextFrameIndex < 173);
  147. if Actor2.Visible then
  148. Actor2.Synchronize(Actor1);
  149. end;
  150. procedure TFormActor.cbxDiskSlicesChange(Sender: TObject);
  151. begin
  152. // DiskRing.Slices := StrToInt(cbxDiskSlices.Items[cbxDiskSlices.ItemIndex]);
  153. // (* the same
  154. case cbxDiskSlices.ItemIndex of
  155. 0: DiskRing.Slices := StrToInt(cbxDiskSlices.Items[0]); // 3
  156. 1: DiskRing.Slices := StrToInt(cbxDiskSlices.Items[1]); // 4
  157. 2: DiskRing.Slices := StrToInt(cbxDiskSlices.Items[2]); // 5
  158. 3: DiskRing.Slices := StrToInt(cbxDiskSlices.Items[3]); // 6
  159. 4: DiskRing.Slices := StrToInt(cbxDiskSlices.Items[4]); // 12;
  160. 5: DiskRing.Slices := StrToInt(cbxDiskSlices.Items[5]); // 64;
  161. end;
  162. // *)
  163. end;
  164. procedure TFormActor.SBFrameToFrameClick(Sender: TObject);
  165. begin
  166. // Animate Frame to Frame
  167. Actor1.NextFrame;
  168. Actor2.NextFrame;
  169. end;
  170. procedure TFormActor.chbSmoothClick(Sender: TObject);
  171. begin
  172. // Smooth movement is achieved by using linear frame interpolation
  173. if chbSmooth.Checked then
  174. begin
  175. Actor1.FrameInterpolation := afpLinear;
  176. Actor2.FrameInterpolation := afpLinear;
  177. end
  178. else
  179. begin
  180. Actor1.FrameInterpolation := afpNone;
  181. Actor2.FrameInterpolation := afpNone;
  182. end;
  183. end;
  184. procedure TFormActor.Actor1FrameChanged(Sender: TObject);
  185. begin
  186. StatusBar1.SimpleText := 'CurrentFrame = ' + IntToStr(Actor1.CurrentFrame);
  187. end;
  188. // events that follow handle camera movements and FPS rate
  189. procedure TFormActor.GLSceneViewer1MouseDown(Sender: TObject; Button: TMouseButton;
  190. Shift: TShiftState; X, Y: Integer);
  191. begin
  192. // store mouse coordinates when a button went down
  193. mdx := X;
  194. mdy := Y;
  195. end;
  196. procedure TFormActor.GLSceneViewer1MouseMove(Sender: TObject; Shift: TShiftState;
  197. X, Y: Integer);
  198. begin
  199. // (we're moving around the parent and target dummycube)
  200. if Shift <> [] then
  201. Camera.MoveAroundTarget(mdy - Y, mdx - X);
  202. mdx := X;
  203. mdy := Y;
  204. end;
  205. procedure TFormActor.FormMouseWheel(Sender: TObject; Shift: TShiftState;
  206. WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
  207. begin
  208. // Note that 1 wheel-step induces a WheelDelta of 120,
  209. // this code adjusts the distance to target with a 10% per wheel-step ratio
  210. Camera.AdjustDistanceToTarget(Power(1.1, WheelDelta / 120));
  211. end;
  212. procedure TFormActor.Timer1Timer(Sender: TObject);
  213. begin
  214. StatusBar1.Panels[0].Text := Format(' FPS ' + '%.1f', [GLSceneViewer1.FramesPerSecond]);
  215. GLSceneViewer1.ResetPerformanceMonitor;
  216. end;
  217. procedure TFormActor.GLCadencer1Progress(Sender: TObject;
  218. const deltaTime, newTime: Double);
  219. begin
  220. GLSceneViewer1.Invalidate;
  221. end;
  222. end.