PageRenderTime 55ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/GR32Ex/GR_Animation.pas

http://gr32ex.googlecode.com/
Pascal | 594 lines | 490 code | 64 blank | 40 comment | 40 complexity | 7cfa72c1d2123decbf21ac5a3018f44b MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception
  1. (* ***** BEGIN LICENSE BLOCK *****
  2. * Version: MPL 1.1
  3. *
  4. * The contents of this file are subject to the Mozilla Public License Version
  5. * 1.1 (the "License"); you may not use this file except in compliance with
  6. * the License. You may obtain a copy of the License at
  7. * http://www.mozilla.org/MPL/
  8. *
  9. * Software distributed under the License is distributed on an "AS IS" basis,
  10. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11. * for the specific language governing rights and limitations under the
  12. * License.
  13. *
  14. * The Original Code is GR_Animation
  15. *
  16. * The Initial Developer of the Original Code is Riceball LEE
  17. * Portions created by Riceball LEE are Copyright (C) 2008
  18. * Portions created by Michael Faust - http://www.alpha-interactive.de/ are Copyright (C) 2000-2005
  19. * All Rights Reserved.
  20. *
  21. * Contributor(s):
  22. *
  23. * ***** END LICENSE BLOCK ***** *)
  24. unit GR_Animation;
  25. {$I Setting.inc}
  26. interface
  27. uses
  28. {$ifdef Debug}
  29. DbugIntf,
  30. {$endif}
  31. Windows,
  32. SysUtils, Classes
  33. , Graphics
  34. , GR32
  35. , GR32_Layers
  36. , GR32_Transforms
  37. , GR32_Filters
  38. //, GR_Graphics
  39. //, GR_FilterEx
  40. //, GR_GraphUtils
  41. //, PNGImage
  42. //, GR32_PNG
  43. ;
  44. type
  45. TGRSpeed = 10..1000;
  46. TGRAnimationFrameClass = class of TGRAnimationFrame;
  47. TGRAnimationFrame = class(TCollectionItem)
  48. protected
  49. //for transparent
  50. FBackgroundColor: TColor;
  51. FBitmap: TBitmap32;
  52. FDelayTime: LongWord;
  53. procedure SetBitmap(const aBitmap: TBitmap32);
  54. public
  55. constructor Create(Collection: TCollection); override;
  56. destructor Destroy; override;
  57. published
  58. property BackgroundColor: TColor read FBackgroundColor write FBackgroundColor;
  59. property Bitmap: TBitmap32 read FBitmap write SetBitmap;
  60. property DelayTime: LongWord read FDelayTime write FDelayTime;
  61. end;
  62. TGRAnimationFrames = class(TCollection)
  63. private
  64. FOwner: TPersistent;
  65. function GetItem(Index: Integer): TGRAnimationFrame;
  66. procedure SetItem(Index: Integer; Value: TGRAnimationFrame);
  67. protected
  68. function GetOwner: TPersistent; override;
  69. public
  70. constructor Create(aOwner: TPersistent);
  71. function Add: TGRAnimationFrame;
  72. property Items[Index: Integer]: TGRAnimationFrame read GetItem write SetItem; default;
  73. end;
  74. TGRAniDisplayFrameEvent = procedure(Sender: TObject; aFrame: TGRAnimationFrame) of object;
  75. TGRAnimationDirection = (adForward, adRewind);
  76. TGRAniLoopEvent = procedure(Sender: TObject; var Continued: Boolean) of object;
  77. TGRAnimationClass = class of TGRAnimation;
  78. //the abstract animation class
  79. TGRAnimation = class(TPersistent)
  80. protected
  81. FOwner: TPersistent;
  82. FFrames: TGRAnimationFrames;
  83. FSpeed: TGRSpeed;
  84. FLooped: Boolean;
  85. FRunning: Boolean;
  86. FEnabled: Boolean;
  87. FFlipAlpha: Boolean;
  88. FCurrentIndex: Integer;
  89. FDirection: TGRAnimationDirection;
  90. FBackgroundColor: TColor;
  91. FOnLoop: TGRAniLoopEvent;
  92. FOnDisplayFrame: TGRAniDisplayFrameEvent;
  93. procedure SetFrames(const Value: TGRAnimationFrames);
  94. function GetOwner: TPersistent;override;
  95. function GetInterval(const FrameIndex: Integer): Integer; virtual;
  96. procedure SetSpeed(const Value: TGRSpeed);
  97. function GetFrameDelay(const FrameIndex: Integer; const SafeMode: Boolean=True): Integer;virtual;
  98. function GetNextIndex(var aIndex: Integer; const CanLoop: Boolean): Boolean;
  99. function IndexIsValid(const aIndex: Integer): Boolean;
  100. procedure DoLoop(var aContinued: Boolean);
  101. procedure DoFlipAlphaChannel(BMP32: TBitmap32);
  102. procedure DoFlipAlphaChannels;
  103. public
  104. procedure RequestFlipAlphaChannel;
  105. function DisplayFirstFrame(): Boolean;
  106. function DisplayFrame(const FrameIndex: Integer): Boolean;
  107. procedure LoadFromFile(const Filename: string);
  108. procedure SaveToFile(const Filename: string);
  109. procedure LoadFromStream(const aStream: TStream);virtual;abstract;
  110. procedure SaveToStream(const aStream: TStream);virtual;abstract;
  111. procedure Assign(Source: TPersistent);override;
  112. constructor Create(aOwner: TPersistent);virtual;
  113. destructor Destroy; override;
  114. property BackgroundColor: TColor read FBackgroundColor write FBackgroundColor;
  115. property Enabled: Boolean read FEnabled write FEnabled;
  116. property Frames: TGRAnimationFrames read FFrames write SetFrames;
  117. property FlipAlphaChannel: Boolean read FFlipAlpha write FFlipAlpha;
  118. property IsRunning: Boolean read FRunning;
  119. property Owner: TPersistent read FOwner;
  120. property Speed: TGRSpeed read FSpeed write SetSpeed;
  121. property Looped: Boolean read FLooped write FLooped;
  122. property OnLoop: TGRAniLoopEvent read FOnLoop write FOnLoop;
  123. property OnDisplayFrame: TGRAniDisplayFrameEvent read FOnDisplayFrame write FOnDisplayFrame;
  124. end;
  125. //to play the TGRAnimation frames.
  126. // abondon, use the New Animator-Effects Arch Framework.
  127. TGRAnimationThread = class(TThread)
  128. protected
  129. FInterval: LongWord;
  130. FAni: TGRAnimation;
  131. FStop: THandle;
  132. FEnabled: Boolean;
  133. procedure SetEnabled(const Value: Boolean);
  134. procedure SetInterval(const Value: LongWord);
  135. procedure Execute; override;
  136. public
  137. constructor Create(const aAnimation: TGRAnimation);
  138. destructor Destroy; override;
  139. property Enabled: Boolean read FEnabled write SetEnabled;
  140. property Interval: LongWord read FInterval write SetInterval;
  141. end;
  142. type
  143. PAniFileFormat = ^TAniFileFormat;
  144. TAniFileFormat = record
  145. AnimationClass: TGRAnimationClass;
  146. Extension: string;
  147. Description: string;
  148. DescResID: Integer;
  149. end;
  150. TAniFileFormatsList = class(TList)
  151. public
  152. constructor Create;
  153. destructor Destroy; override;
  154. procedure Add(const Ext, Desc: String; DescID: Integer; AClass: TGRAnimationClass);
  155. function FindExt(Ext: string): TGRAnimationClass;
  156. function FindClassName(const Classname: string): TGRAnimationClass;
  157. procedure Remove(AClass: TGRAnimationClass);
  158. procedure BuildFilterStrings(AnimationClass: TGRAnimationClass;
  159. var Descriptions, Filters: string);
  160. end;
  161. procedure RegisterAnimation(const AExtension, ADescription: string; const aClass: TGRAnimationClass);
  162. function GAniFileFormats: TAniFileFormatsList;
  163. implementation
  164. uses
  165. Consts;
  166. const
  167. G32DefaultDelay: ShortInt = 100; // Time in ms.
  168. G32MinimumDelay: ShortInt = 10; // Time in ms.
  169. { TAniFileFormatsList }
  170. constructor TAniFileFormatsList.Create;
  171. begin
  172. inherited Create;
  173. end;
  174. destructor TAniFileFormatsList.Destroy;
  175. var
  176. I: Integer;
  177. begin
  178. for I := 0 to Count-1 do
  179. Dispose(PAniFileFormat(Items[I]));
  180. inherited Destroy;
  181. end;
  182. procedure TAniFileFormatsList.Add(const Ext, Desc: String; DescID: Integer;
  183. AClass: TGRAnimationClass);
  184. var
  185. NewRec: PAniFileFormat;
  186. begin
  187. New(NewRec);
  188. with NewRec^ do
  189. begin
  190. Extension := AnsiLowerCase(Ext);
  191. AnimationClass := AClass;
  192. Description := Desc;
  193. DescResID := DescID;
  194. end;
  195. inherited Add(NewRec);
  196. end;
  197. function TAniFileFormatsList.FindExt(Ext: string): TGRAnimationClass;
  198. var
  199. I: Integer;
  200. begin
  201. Ext := AnsiLowerCase(Ext);
  202. for I := Count-1 downto 0 do
  203. with PAniFileFormat(Items[I])^ do
  204. if Extension = Ext then
  205. begin
  206. Result := AnimationClass;
  207. Exit;
  208. end;
  209. Result := nil;
  210. end;
  211. function TAniFileFormatsList.FindClassName(const ClassName: string): TGRAnimationClass;
  212. var
  213. I: Integer;
  214. begin
  215. for I := Count-1 downto 0 do
  216. begin
  217. Result := PAniFileFormat(Items[I])^.AnimationClass;
  218. if Result.ClassName = Classname then Exit;
  219. end;
  220. Result := nil;
  221. end;
  222. procedure TAniFileFormatsList.Remove(AClass: TGRAnimationClass);
  223. var
  224. I: Integer;
  225. P: PAniFileFormat;
  226. begin
  227. for I := Count-1 downto 0 do
  228. begin
  229. P := PAniFileFormat(Items[I]);
  230. if P^.AnimationClass.InheritsFrom(AClass) then
  231. begin
  232. Dispose(P);
  233. Delete(I);
  234. end;
  235. end;
  236. end;
  237. procedure TAniFileFormatsList.BuildFilterStrings(AnimationClass: TGRAnimationClass;
  238. var Descriptions, Filters: string);
  239. var
  240. C, I: Integer;
  241. P: PAniFileFormat;
  242. begin
  243. Descriptions := '';
  244. Filters := '';
  245. C := 0;
  246. for I := Count-1 downto 0 do
  247. begin
  248. P := PAniFileFormat(Items[I]);
  249. if P^.AnimationClass.InheritsFrom(AnimationClass) and (P^.Extension <> '') then
  250. with P^ do
  251. begin
  252. if C <> 0 then
  253. begin
  254. Descriptions := Descriptions + '|';
  255. Filters := Filters + ';';
  256. end;
  257. if (Description = '') and (DescResID <> 0) then
  258. Description := LoadStr(DescResID);
  259. FmtStr(Descriptions, '%s%s (*.%s)|*.%2:s', [Descriptions, Description, Extension]);
  260. FmtStr(Filters, '%s*.%s', [Filters, Extension]);
  261. Inc(C);
  262. end;
  263. end;
  264. if C > 1 then
  265. FmtStr(Descriptions, '%s (%s)|%1:s|%s', [sAllFilter, Filters, Descriptions]);
  266. end;
  267. var
  268. FAniFileFormats: TAniFileFormatsList = nil;
  269. function GAniFileFormats: TAniFileFormatsList;
  270. begin
  271. if FAniFileFormats = nil then FAniFileFormats := TAniFileFormatsList.Create;
  272. Result := FAniFileFormats;
  273. end;
  274. procedure RegisterAnimation(const AExtension, ADescription: string; const aClass: TGRAnimationClass);
  275. begin
  276. GAniFileFormats.Add(AExtension, ADescription, 0, aClass);
  277. end;
  278. { TGRAnimationFrame }
  279. constructor TGRAnimationFrame.Create(Collection: TCollection);
  280. begin
  281. inherited;
  282. FBitmap := TBitmap32.Create;
  283. end;
  284. destructor TGRAnimationFrame.Destroy;
  285. begin
  286. FBitmap.Free;
  287. inherited;
  288. end;
  289. procedure TGRAnimationFrame.SetBitmap(const aBitmap: TBitmap32);
  290. begin
  291. FBitmap.Assign(aBitmap);
  292. end;
  293. { TGRAnimationFrames }
  294. function TGRAnimationFrames.Add: TGRAnimationFrame;
  295. begin
  296. Result := TGRAnimationFrame(inherited Add);
  297. end;
  298. constructor TGRAnimationFrames.Create(aOwner: TPersistent);
  299. begin
  300. inherited Create(TGRAnimationFrame);
  301. FOwner := aOwner;
  302. end;
  303. function TGRAnimationFrames.GetItem(Index: Integer): TGRAnimationFrame;
  304. begin
  305. Result := TGRAnimationFrame(inherited GetItem(Index));
  306. end;
  307. function TGRAnimationFrames.GetOwner: TPersistent;
  308. begin
  309. Result := FOwner;
  310. end;
  311. procedure TGRAnimationFrames.SetItem(Index: Integer; Value: TGRAnimationFrame);
  312. begin
  313. inherited SetItem(Index, Value);
  314. end;
  315. { TGRAnimation }
  316. constructor TGRAnimation.Create(aOwner: TPersistent);
  317. begin
  318. inherited Create();
  319. FOwner := aOwner;
  320. FFrames := TGRAnimationFrames.Create(Self);
  321. FSpeed := 100;
  322. end;
  323. destructor TGRAnimation.Destroy;
  324. begin
  325. FFrames.Free;
  326. inherited;
  327. end;
  328. procedure TGRAnimation.Assign(Source: TPersistent);
  329. begin
  330. if Source is TGRAnimation then
  331. with Source as TGRAnimation do
  332. begin
  333. Self.FFrames.Assign(FFrames);
  334. Self.FSpeed := FSpeed;
  335. end;
  336. inherited;
  337. end;
  338. function TGRAnimation.DisplayFirstFrame(): Boolean;
  339. begin
  340. Result := DisplayFrame(0);
  341. end;
  342. function TGRAnimation.DisplayFrame(const FrameIndex: Integer): Boolean;
  343. begin
  344. Result := FEnabled and IndexIsValid(FrameIndex);
  345. if Result then
  346. begin
  347. if Assigned(FOnDisplayFrame) then
  348. FOnDisplayFrame(Self, FFrames[FrameIndex]);
  349. if Frames.Count > 1 then
  350. GetNextIndex(FCurrentIndex, FLooped);
  351. end;
  352. end;
  353. procedure TGRAnimation.DoLoop(var aContinued: Boolean);
  354. begin
  355. if Assigned(FOnLoop) then
  356. FOnLoop(Self, aContinued);
  357. end;
  358. function TGRAnimation.GetFrameDelay(const FrameIndex: Integer; const SafeMode: Boolean): Integer;
  359. begin
  360. Result := 0;
  361. if IndexIsValid(FrameIndex) then
  362. Result := Frames.Items[FrameIndex].DelayTime;
  363. if (Result < G32MinimumDelay) and SafeMode then
  364. begin
  365. if (Result = 0) then
  366. Result := G32DefaultDelay
  367. else
  368. Result := G32MinimumDelay;
  369. end;
  370. end;
  371. function TGRAnimation.GetInterval(const FrameIndex: Integer): Integer;
  372. begin
  373. Result := GetFrameDelay(FrameIndex);
  374. Result := Result * 100 div FSpeed;
  375. end;
  376. function TGRAnimation.GetNextIndex(var aIndex: Integer; const CanLoop: Boolean): Boolean;
  377. begin
  378. Result := False;
  379. if (Frames.Count > 0) then
  380. begin
  381. if (FDirection = adForward) then
  382. begin
  383. if (aIndex < Frames.Count -1) then
  384. begin
  385. inc(aIndex);
  386. Result := true;
  387. end
  388. else begin
  389. aIndex := 0;
  390. Result := CanLoop and (Frames.Count > 1);
  391. if Result then DoLoop(Result);
  392. end;
  393. end
  394. else begin
  395. if (aIndex > 0) then
  396. begin
  397. dec(aIndex);
  398. Result := true;
  399. end
  400. else begin
  401. aIndex := Frames.Count -1; // decrement it right here !
  402. Result := CanLoop and (Frames.Count > 1);
  403. if Result then DoLoop(Result);
  404. end;
  405. end;
  406. end;
  407. end;
  408. function TGRAnimation.GetOwner: TPersistent;
  409. begin
  410. Result := FOwner;
  411. end;
  412. function TGRAnimation.IndexIsValid(const aIndex: Integer): Boolean;
  413. begin
  414. Result := (aIndex >= 0) and (aIndex < Frames.Count);
  415. end;
  416. procedure TGRAnimation.LoadFromFile(const Filename: string);
  417. var
  418. Stream: TStream;
  419. begin
  420. Stream := TFileStream.Create(Filename, fmOpenRead or fmShareDenyWrite);
  421. try
  422. LoadFromStream(Stream);
  423. finally
  424. Stream.Free;
  425. end;
  426. end;
  427. procedure TGRAnimation.DoFlipAlphaChannel(BMP32: TBitmap32);
  428. var
  429. X: Integer;
  430. P: PColor32;
  431. begin
  432. P := @(BMP32).Bits[0];
  433. for X := 0 to BMP32.Width * BMP32.Height -1 do
  434. begin
  435. P^ := P^ XOR $FF000000;
  436. inc(P);
  437. end;
  438. end;
  439. procedure TGRAnimation.DoFlipAlphaChannels;
  440. var
  441. I: Integer;
  442. begin
  443. for I := 0 to FFrames.Count -1 do
  444. DoFlipAlphaChannel( FFrames.Items[I].Bitmap );
  445. end;
  446. procedure TGRAnimation.RequestFlipAlphaChannel;
  447. begin
  448. if FFlipAlpha then
  449. DoFlipAlphaChannels;
  450. end;
  451. procedure TGRAnimation.SaveToFile(const Filename: string);
  452. var
  453. Stream: TStream;
  454. begin
  455. Stream := TFileStream.Create(Filename, fmCreate or fmShareDenyWrite);
  456. try
  457. SaveToStream(Stream);
  458. finally
  459. Stream.Free;
  460. end;
  461. end;
  462. procedure TGRAnimation.SetFrames(const Value: TGRAnimationFrames);
  463. begin
  464. FFrames.Assign(Value);
  465. end;
  466. procedure TGRAnimation.SetSpeed(const Value: TGRSpeed);
  467. begin
  468. if (FSpeed <> Value) then
  469. begin
  470. FSpeed := Value;
  471. end;
  472. end;
  473. { TGRAnimationThread }
  474. constructor TGRAnimationThread.Create(const aAnimation: TGRAnimation);
  475. begin
  476. inherited Create(true);
  477. FStop := CreateEvent(nil, False, False, nil);
  478. FAni := aAnimation;
  479. Enabled := false;
  480. FreeOnTerminate:= false;
  481. FInterval := G32DefaultDelay;
  482. end;
  483. destructor TGRAnimationThread.Destroy;
  484. begin
  485. Enabled := false;
  486. CloseHandle(FStop);
  487. Terminate;
  488. inherited Destroy;
  489. end;
  490. procedure TGRAnimationThread.SetEnabled(const Value: Boolean);
  491. begin
  492. if (Value <> FEnabled) and (not Terminated) then
  493. begin
  494. FEnabled := Value;
  495. if FEnabled and (FInterval > 0) then
  496. Resume
  497. else
  498. Suspend;
  499. end;
  500. end;
  501. procedure TGRAnimationThread.SetInterval(const Value: LongWord);
  502. var
  503. WasEnabled: Boolean;
  504. begin
  505. if (Value <> FInterval) and (not Terminated) then
  506. begin
  507. WasEnabled := FEnabled;
  508. FInterval := Value;
  509. Enabled := WasEnabled and (FInterval > 0);
  510. end;
  511. end;
  512. procedure TGRAnimationThread.Execute;
  513. begin
  514. repeat
  515. if (WaitForSingleObject(FStop, FInterval) = WAIT_TIMEOUT) and (not Terminated) then
  516. begin
  517. if FAni.Enabled then
  518. begin
  519. FAni.DisplayFrame(FAni.FCurrentIndex);
  520. FAni.FRunning := FAni.GetNextIndex(FAni.FCurrentIndex, FAni.FLooped);
  521. if FAni.IsRunning then
  522. begin
  523. Interval := FAni.GetInterval(FAni.FCurrentIndex);
  524. end;
  525. Enabled := FAni.IsRunning;
  526. end;
  527. end;
  528. until Terminated;
  529. end;
  530. end.