MainUnit.pas 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. unit MainUnit;
  2. (* ***** BEGIN LICENSE BLOCK *****
  3. * Version: MPL 1.1 or LGPL 2.1 with linking exception
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. * http://www.mozilla.org/MPL/
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. *
  15. * Alternatively, the contents of this file may be used under the terms of the
  16. * Free Pascal modified version of the GNU Lesser General Public License
  17. * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
  18. * of this license are applicable instead of those above.
  19. * Please see the file LICENSE.txt for additional information concerning this
  20. * license.
  21. *
  22. * The Original Code is Sprites Example
  23. *
  24. * The Initial Developer of the Original Code is
  25. * Alex A. Denisov
  26. *
  27. * Portions created by the Initial Developer are Copyright (C) 2000-2005
  28. * the Initial Developer. All Rights Reserved.
  29. *
  30. * Contributor(s):
  31. * Andre Beckedorf - metaException OHG
  32. *
  33. * ***** END LICENSE BLOCK ***** *)
  34. interface
  35. {$include GR32.inc}
  36. uses
  37. {$IFDEF FPC} LCLIntf, LResources, Variants, {$ENDIF}
  38. {$IFNDEF FPC} AppEvnts, {$ENDIF} {$ifdef MSWINDOWS}Windows,{$ENDIF}
  39. SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls,
  40. Math, Buttons,
  41. GR32,
  42. GR32_System,
  43. GR32_Transforms,
  44. GR32_Image,
  45. GR32_Layers;
  46. const
  47. MAX_RUNS = 3;
  48. // Note: The tiled background is scaled on purpose in order to make
  49. // it expensive to draw. This exacerbate the penalty of drawing too
  50. // much and thus better demonstrate the gains offered by the redraw
  51. // optimizations.
  52. type
  53. TMainForm = class(TForm)
  54. BtnAdd: TButton;
  55. BtnBenchmark: TButton;
  56. BtnClearAll: TButton;
  57. BitmapList: TBitmap32List;
  58. BtnRemove: TButton;
  59. CbxUseRepaintOpt: TCheckBox;
  60. EdtLayerCount: TEdit;
  61. Image32: TImage32;
  62. LblDimension: TLabel;
  63. LblFPS: TLabel;
  64. LblTotal: TLabel;
  65. Memo: TMemo;
  66. TimerFPS: TTimer;
  67. CheckBoxBatch: TCheckBox;
  68. procedure FormCreate(Sender: TObject);
  69. procedure FormDestroy(Sender: TObject);
  70. procedure BtnAddClick(Sender: TObject);
  71. procedure BtnBenchmarkClick(Sender: TObject);
  72. procedure BtnClearAllClick(Sender: TObject);
  73. procedure BtnRemoveClick(Sender: TObject);
  74. procedure CbxUseRepaintOptClick(Sender: TObject);
  75. procedure Image32Resize(Sender: TObject);
  76. procedure TimerFPSTimer(Sender: TObject);
  77. procedure CheckBoxBatchClick(Sender: TObject);
  78. private
  79. Velocities: TArrayOfFloatPoint;
  80. FramesDrawn: Integer;
  81. FFramerateStopwatch: TStopwatch;
  82. LastSeed: Integer;
  83. PriorityClass, Priority: Integer;
  84. BatchUpdates: boolean;
  85. BenchmarkMode: Boolean;
  86. TerminateOnCompletion: boolean;
  87. BenchmarkRun: Cardinal;
  88. BenchmarkList: TStringList;
  89. procedure IdleHandler(Sender: TObject; var Done: Boolean);
  90. procedure AddLayers(Count: Integer);
  91. end;
  92. var
  93. MainForm: TMainForm;
  94. implementation
  95. {$R *.dfm}
  96. uses
  97. Types,
  98. System.UITypes,
  99. {$IFDEF Darwin}
  100. MacOSAll,
  101. {$ENDIF}
  102. GR32.ImageFormats.PNG32;
  103. { TMainForm }
  104. procedure TMainForm.FormCreate(Sender: TObject);
  105. var
  106. TempBitmap: TBitmap32;
  107. begin
  108. TempBitmap := TBitmap32.Create;
  109. try
  110. Image32.Bitmap.LoadFromResourceName(Hinstance, 'SpriteTexture', 'PNG');
  111. BitmapList.Bitmap[0].LoadFromResourceName(Hinstance, 'Sprite1');
  112. BitmapList.Bitmap[1].LoadFromResourceName(Hinstance, 'Sprite2');
  113. BitmapList.Bitmap[2].LoadFromResourceName(Hinstance, 'Sprite3');
  114. finally
  115. TempBitmap.Free;
  116. end;
  117. LastSeed := 0;
  118. BenchmarkList := TStringList.Create;
  119. Application.OnIdle := IdleHandler;
  120. if (FindCmdLineSwitch('benchmark')) then
  121. begin
  122. TerminateOnCompletion := True;
  123. BtnBenchmark.Click;
  124. end;
  125. end;
  126. procedure TMainForm.AddLayers(Count: Integer);
  127. var
  128. Layer: TBitmapLayer;
  129. L: TFloatRect;
  130. i: Integer;
  131. begin
  132. TimerFPS.Enabled := False;
  133. // make sure, we're creating reproducible randoms...
  134. RandSeed := LastSeed;
  135. Image32.BeginUpdate;
  136. for i := 1 to Count do
  137. begin
  138. // create a new layer...
  139. Layer := TBitmapLayer.Create(Image32.Layers);
  140. Layer.Bitmap := BitmapList.Bitmaps[System.Random(BitmapList.Bitmaps.Count)].Bitmap;
  141. Layer.Bitmap.DrawMode := dmBlend;
  142. Layer.Bitmap.MasterAlpha := System.Random(255);
  143. // put it somethere
  144. L.Left := System.Random(Image32.Width);
  145. L.Top := System.Random(Image32.Height);
  146. L.Right := L.Left + Layer.Bitmap.Width;
  147. L.Bottom := L.Top + Layer.Bitmap.Height;
  148. Layer.Location := L;
  149. SetLength(Velocities, Length(Velocities) + 1);
  150. Velocities[High(Velocities)] := FloatPoint(Random - 0.5, Random - 0.5);
  151. end;
  152. Image32.EndUpdate;
  153. EdtLayerCount.Text := IntToStr(Image32.Layers.Count) + ' layers';
  154. // save current seed, so we can continue at this seed later...
  155. LastSeed := RandSeed;
  156. FramesDrawn := 0;
  157. TimerFPS.Enabled := True;
  158. end;
  159. procedure TMainForm.IdleHandler(Sender: TObject; var Done: Boolean);
  160. var
  161. i: Integer;
  162. R: TFloatRect;
  163. Layer: TBitmapLayer;
  164. Alpha: Cardinal;
  165. begin
  166. if Image32.Layers.Count = 0 then
  167. Exit;
  168. if (BatchUpdates) then
  169. Image32.BeginUpdate;
  170. for i := 0 to Image32.Layers.Count - 1 do
  171. begin
  172. Layer := TBitmapLayer(Image32.Layers[i]);
  173. Alpha := Layer.Bitmap.MasterAlpha;
  174. if (Alpha = 0) then
  175. Layer.Tag := 0
  176. else
  177. if (Alpha >= 255) then
  178. Layer.Tag := 1;
  179. if (Layer.Tag = 0) then
  180. Inc(Alpha)
  181. else
  182. Dec(Alpha);
  183. if (BatchUpdates) then
  184. Layer.BeginUpdate;
  185. Layer.Bitmap.MasterAlpha := Alpha;
  186. R := Layer.Location;
  187. with Velocities[i] do
  188. begin
  189. GR32.OffsetRect(R, X, Y);
  190. X := X + (Random - 0.5) * 0.9;
  191. Y := Y + (Random - 0.5) * 0.9;
  192. if (R.Left < 0) and (X < 0) then X := 1;
  193. if (R.Top < 0) and (Y < 0) then Y := 1;
  194. if (R.Right > Image32.Width) and (X > 0) then X := -1;
  195. if (R.Bottom > Image32.Height) and (Y > 0) then Y := -1;
  196. end;
  197. Layer.Location := R;
  198. if (BatchUpdates) then
  199. Layer.EndUpdate;
  200. end;
  201. if (BatchUpdates) then
  202. Image32.EndUpdate;
  203. // because we're doing Invalidate in the IdleHandler and Invalidate has
  204. // higher priority, we can count the frames here, because we can be sure that
  205. // the deferred repaint is triggered once this method is exited.
  206. Inc(FramesDrawn);
  207. end;
  208. procedure TMainForm.BtnClearAllClick(Sender: TObject);
  209. begin
  210. Image32.Layers.Clear;
  211. Velocities := nil;
  212. EdtLayerCount.Text := '0 layers';
  213. end;
  214. procedure TMainForm.BtnRemoveClick(Sender: TObject);
  215. var
  216. I: Integer;
  217. begin
  218. for I := Image32.Layers.Count - 1 downto Max(0, Image32.Layers.Count - 10) do
  219. Image32.Layers.Delete(I);
  220. EdtLayerCount.Text := IntToStr(Image32.Layers.Count) + ' layers';
  221. end;
  222. procedure TMainForm.CbxUseRepaintOptClick(Sender: TObject);
  223. begin
  224. if CbxUseRepaintOpt.Checked then
  225. Image32.RepaintMode := rmOptimizer
  226. else
  227. Image32.RepaintMode := rmFull;
  228. end;
  229. procedure TMainForm.CheckBoxBatchClick(Sender: TObject);
  230. begin
  231. BatchUpdates := CheckBoxBatch.Checked;
  232. end;
  233. procedure TMainForm.TimerFPSTimer(Sender: TObject);
  234. var
  235. Diff: Integer;
  236. FPS: Single;
  237. LocalFormatSettings: TFormatSettings;
  238. begin
  239. FFramerateStopwatch.Stop;
  240. TimerFPS.Enabled := False;
  241. LocalFormatSettings := FormatSettings;
  242. LocalFormatSettings.DecimalSeparator := '.';
  243. if (FFramerateStopwatch.ElapsedMilliseconds <> 0) then
  244. FPS := 1000 * FramesDrawn / FFramerateStopwatch.ElapsedMilliseconds
  245. else
  246. FPS := 0;
  247. LblFPS.Caption := Format('%.2f fps', [FPS], LocalFormatSettings);
  248. if BenchmarkMode then
  249. begin
  250. BenchmarkList.Add(Format('%d ' + #9 + '%.2f', [Image32.Layers.Count, FPS], LocalFormatSettings));
  251. Diff := 0; // stop complaining, ye my evil compiler!
  252. if Image32.Layers.Count = 10 then
  253. Diff := 4
  254. else
  255. if Image32.Layers.Count = 14 then
  256. Diff := 6
  257. else
  258. if Image32.Layers.Count < 100 then
  259. Diff := 10
  260. else
  261. if Image32.Layers.Count = 100 then
  262. Diff := 40
  263. else
  264. if Image32.Layers.Count = 140 then
  265. Diff := 60
  266. else
  267. if Image32.Layers.Count < 1000 then
  268. Diff := 100
  269. else
  270. if Image32.Layers.Count < 2000 then
  271. Diff := 500
  272. else
  273. if Image32.Layers.Count >= 2000 then
  274. begin
  275. BtnBenchmarkClick(nil);
  276. Exit;
  277. end;
  278. AddLayers(Diff);
  279. end;
  280. FramesDrawn := 0;
  281. TimerFPS.Enabled := True;
  282. FFramerateStopwatch := TStopwatch.StartNew;
  283. end;
  284. procedure TMainForm.Image32Resize(Sender: TObject);
  285. begin
  286. LblDimension.Caption := IntToStr(Image32.Width) + ' x ' + IntToStr(Image32.Height);
  287. end;
  288. procedure TMainForm.BtnAddClick(Sender: TObject);
  289. begin
  290. AddLayers(10);
  291. end;
  292. procedure TMainForm.BtnBenchmarkClick(Sender: TObject);
  293. begin
  294. if (BenchmarkMode) then
  295. begin
  296. SetThreadPriority(GetCurrentThread, Priority);
  297. SetPriorityClass(GetCurrentProcess, PriorityClass);
  298. BtnBenchmark.Caption := 'Benchmark';
  299. CbxUseRepaintOpt.Enabled := True;
  300. BtnAdd.Enabled := True;
  301. BtnRemove.Enabled := True;
  302. BtnClearAll.Enabled := True;
  303. BenchmarkMode := False;
  304. TimerFPS.Interval := 5000;
  305. BenchmarkList.SaveToFile('Results.txt');
  306. if (TerminateOnCompletion) then
  307. Application.Terminate; // Queue termination
  308. TerminateOnCompletion := False;
  309. exit;
  310. end;
  311. if (not TerminateOnCompletion) then
  312. begin
  313. if (MessageDlg('Do you really want to start benchmarking? ' +
  314. 'This will take a considerable amount of time.' + #13#13 +
  315. 'Benchmarking runs with a higher task priority. Your system might become unresponsive for several seconds.'+#13#13+
  316. 'The applicartion will terminate after the benchmark completes.',
  317. mtConfirmation, [mbYes, mbNo], 0) <> mrYes) then
  318. exit;
  319. end;
  320. PriorityClass := GetPriorityClass(GetCurrentProcess);
  321. Priority := GetThreadPriority(GetCurrentThread);
  322. SetPriorityClass(GetCurrentProcess, HIGH_PRIORITY_CLASS);
  323. SetThreadPriority(GetCurrentThread, THREAD_PRIORITY_TIME_CRITICAL);
  324. BtnBenchmark.Caption := 'Stop';
  325. CbxUseRepaintOpt.Enabled := False;
  326. BtnAdd.Enabled := False;
  327. BtnRemove.Enabled := False;
  328. BtnClearAll.Enabled := False;
  329. BenchmarkMode := True;
  330. BenchmarkList.Clear;
  331. BtnClearAllClick(nil);
  332. AddLayers(10);
  333. TimerFPS.Interval := MAX_RUNS * 5000;
  334. FFramerateStopwatch := TStopwatch.StartNew;
  335. end;
  336. procedure TMainForm.FormDestroy(Sender: TObject);
  337. begin
  338. BenchmarkList.Free;
  339. end;
  340. end.