2
0

MainUnit.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  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 Visualization Example
  23. *
  24. * The Initial Developers of the Original Code is:
  25. * Michael Hansen <[email protected]>
  26. *
  27. * Portions created by the Initial Developer are Copyright (C) 2005
  28. * the Initial Developer. All Rights Reserved.
  29. *
  30. * Contributor(s):
  31. * Mattias Andersson <[email protected]>
  32. *
  33. * ***** END LICENSE BLOCK ***** *)
  34. interface
  35. {$include GR32.inc}
  36. uses
  37. {$IFDEF FPC} LCLIntf, LResources, {$ENDIF}
  38. SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Menus, StdCtrls,
  39. ExtCtrls, GR32, GR32_Image, GR32_VectorMaps, GR32_ExtImage, GR32_Rasterizers;
  40. type
  41. TMainForm = class(TForm)
  42. ColorTimer: TTimer;
  43. FPSTimer: TTimer;
  44. MovementTimer: TTimer;
  45. RenderTimer: TTimer;
  46. procedure FormCreate(Sender: TObject);
  47. procedure FormClose(Sender: TObject; var Action: TCloseAction);
  48. procedure FormResize(Sender: TObject);
  49. procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X,
  50. Y: Integer);
  51. procedure FormKeyDown(Sender: TObject; var Key: Word;
  52. Shift: TShiftState);
  53. procedure MovementTimerTimer(Sender: TObject);
  54. procedure RenderTimerTimer(Sender: TObject);
  55. procedure ColorTimerTimer(Sender: TObject);
  56. procedure FPSTimerTimer(Sender: TObject);
  57. public
  58. CurrentBuffer : Boolean;
  59. Buffers: array [Boolean] of TBitmap32;
  60. CurrentMap : Boolean;
  61. VectorMap: TVectorMap;
  62. RenderThread: TRenderThread;
  63. LastPoint: array [0..15] of array [0..1] of TPoint;
  64. procedure RenderMovement;
  65. procedure TransformFrame(Sender: TObject; var Done: Boolean);
  66. procedure BufferFeedBack(Feedback, BlendContrast: Byte; BlendBrightness,
  67. BufferBrightness: Integer);
  68. procedure ToggleTimers(Enabled: Boolean);
  69. procedure RenderHelpScreen;
  70. end;
  71. // Callback prototype procedure following Winamps Vis. Studio naming and usage
  72. // See 'Movement' under 'Trans' in Winamps Vis. Studio
  73. // Sw, Sh: Display width and height (read only)
  74. // X,Y: Cartesian/Rectangular coordinate in range [-1..1]
  75. // D, R: Polar coordinate, D in range 0..1, R in range 0..2Pi
  76. TMovementProc = procedure(Sw, Sh: Single; var X, Y, D, R : Single);
  77. var
  78. MainForm: TMainForm;
  79. implementation
  80. {$R *.dfm}
  81. uses
  82. Math, GR32_Lowlevel, GR32_Math, GR32_Blend;
  83. var
  84. MovementIndex : Integer = 9;
  85. vShowHelp: Boolean = True;
  86. vShowFPS: Boolean = False;
  87. FPS : Integer = 0;
  88. FPSMeasure: Integer = 0;
  89. IsClosing : Boolean = false;
  90. CX, CY, NX, NY: Integer;
  91. PathAngle : Single = 0;
  92. PathRadius: Single;
  93. PathStep: Single = 0.1;
  94. PathRadiusStep : Single = 2;
  95. // This number is randomized frequently, and used to control various factors
  96. // in rendering and movement
  97. ARandomNumber : Single;
  98. // Hue, Saturation & Lightness cycler vars, ensures coherent color variations
  99. Hue: Single;
  100. HueIncreaser : Single = 3/360;
  101. Sat: Single;
  102. SatIncreaser : Single = 1/10;
  103. Lns: Single;
  104. LnsIncreaser : Single = 1/10;
  105. // Variables used to control balanced drawing of the different render types
  106. Render_Worms : Single = 0;
  107. Render_PathSpots : Single = 0;
  108. Render_RandomSpots : Single = 0;
  109. Render_Noise : Single = 0;
  110. Feedback : Single = 0.7;
  111. BlendLevel : Byte = 0;
  112. BlendContrast : Byte = 0;
  113. BlendBrightness : Integer = 0;
  114. TimeDarkening : Integer = -1;
  115. // Rough FPS controlled movement speed..
  116. // MovementSpeed controls desired movement FPS
  117. MovementSpeed : Single = 75;
  118. FPS_Adaption : Single = 1;
  119. FixedMouseX, FixedMouseY: TFixed;
  120. // Movements, some formulas were inspired by those present in winamp
  121. procedure Movement1(Sw, Sh: Single; var X, Y, D, R : Single);
  122. begin
  123. d := d * (0.96 + Cos(d * PI) * 0.05);
  124. r := r + (ARandomNumber - 0.5) * 0.05;
  125. end;
  126. procedure Movement2(Sw, Sh: Single; var X, Y, D, R : Single);
  127. begin
  128. d := d * (0.94 + (Cos((r - Pi * 0.5) * 32 * ARandomNumber) * 0.06));
  129. r := r + (ARandomNumber - 0.5) * 0.05;
  130. end;
  131. procedure Movement3(Sw, Sh: Single; var X, Y, D, R : Single);
  132. begin
  133. d := d * (1 - (Sin((r - Pi * 0.5) * 7) * 0.03)) * (0.96 + Cos(d * Pi) * 0.05);
  134. r := r + (Cos(d * 12) * 0.03) + 0.04;
  135. end;
  136. procedure Movement4(Sw, Sh: Single; var X, Y, D, R : Single);
  137. begin
  138. d := d * Trunc(((1 - (sin((x - Pi * 0.5) * 7) * 0.03)) *
  139. (0.96 + Cos(y * Pi) * 0.05)) * 11) / 11;
  140. r := r + (Cos(Abs(y) * 10) * 0.03) + 0.04;
  141. end;
  142. procedure Movement5(Sw, Sh: Single; var X, Y, D, R : Single);
  143. begin
  144. r := r + 0.01 - 0.02 * d;
  145. d := d * 0.96;
  146. x := Cos(r) * d + 8/120 - (ARandomNumber - 0.5) * 0.1;
  147. end;
  148. procedure Movement6(Sw, Sh: Single; var X, Y, D, R : Single);
  149. var
  150. p,w: Single;
  151. begin
  152. p := d * Round(((1 - (Sin((r - Pi * 0.5) * 7) * 0.01)) *
  153. (0.96 + Cos(GR32_Math.Hypot(x, y) * Pi) * 0.05)) * 11) / 11;
  154. d := d * (0.96 + Cos(d * Pi) * 0.05);
  155. w := 1 - abs(x * y);
  156. d := d + (p - d) * w;
  157. p := x + (Cos(y * 18) * x * 0.01);
  158. x := x + (p - x) * w;
  159. p := y + (Sin(x * 14) * y * 0.01);
  160. y := y + (p - y) * w;
  161. r := r - 0.005;
  162. end;
  163. procedure Movement7(Sw, Sh: Single; var X, Y, D, R : Single);
  164. var
  165. t: Single;
  166. begin
  167. t := Cos(d * Pi * 0.5) + x * y * 0.1;
  168. r := r - 0.1 * t * t * t;
  169. x := x / (0.9 + ARandomNumber);
  170. y := y / (0.9 + ARandomNumber);
  171. end;
  172. procedure Movement8(Sw, Sh: Single; var X, Y, D, R : Single);
  173. begin
  174. x := x + (Cos(y * 18) * ARandomNumber * 0.05);
  175. y := y + (Sin(x * 14) * (ARandomNumber * 0.05 + 0.01));
  176. end;
  177. procedure Movement9(Sw, Sh: Single; var X, Y, D, R : Single);
  178. begin
  179. d := d * (0.9974 - (Cos(Min(d * Pi, Pi)) + ARandomNumber) * 0.03);
  180. end;
  181. const
  182. Movements : array [1..9] of TMovementProc = (Movement1, Movement2, Movement3,
  183. Movement4, Movement5, Movement6, Movement7, Movement8, Movement9);
  184. { Delphi 5 compatibility }
  185. {$IFNDEF DELPHI6}
  186. function InRange(const AValue, AMin, AMax: Double): Boolean;
  187. begin
  188. Result := (AValue >= AMin) and (AValue <= AMax);
  189. end;
  190. function TryStrToInt(const S: string; out Value: Integer): Boolean;
  191. var
  192. E: Integer;
  193. begin
  194. Val(S, Value, E);
  195. Result := E = 0;
  196. end;
  197. {$ENDIF}
  198. procedure FastRemap(Src, Dst: TBitmap32; VectorMap: TVectorMap);
  199. var
  200. I, J, W, H: Integer;
  201. DstPtr: PColor32;
  202. MapPtr: PFixedPoint;
  203. begin
  204. W := Src.Width - 1;
  205. H := Src.Height - 1;
  206. DstPtr:= @Dst.PixelPtr[0, 0]^;
  207. MapPtr:= @VectorMap.Vectors[0];
  208. with Src do
  209. for J:= 0 to H do
  210. for I:= 0 to W do
  211. begin
  212. DstPtr^:= PixelXS[MapPtr.X + I shl 16 - FixedMouseX,
  213. MapPtr.Y + J shl 16 - FixedMouseY];
  214. Inc(DstPtr);
  215. Inc(MapPtr);
  216. end;
  217. end;
  218. { TMainForm }
  219. procedure TMainForm.FormCreate(Sender: TObject);
  220. var
  221. B: Boolean;
  222. begin
  223. for B := False to True do Buffers[B] := TBitmap32.Create;
  224. VectorMap := TVectorMap.Create;
  225. CurrentBuffer := True;
  226. CurrentMap := True;
  227. Application.OnIdle:= TransformFrame;
  228. DoubleBuffered := True; // avoid flicker
  229. Canvas.Brush.Style := bsClear;
  230. Canvas.Font.Color := clWhite;
  231. Hue := Random;
  232. Sat := Random;
  233. Lns := Random;
  234. end;
  235. procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
  236. var
  237. B: Boolean;
  238. begin
  239. ToggleTimers(False);
  240. IsClosing := True;
  241. for B := False to True do Buffers[B].Free;
  242. VectorMap.Free;
  243. end;
  244. procedure TMainForm.FormResize(Sender: TObject);
  245. const
  246. Line1 = 'Graphics32';
  247. Line2 = '----visualization example----';
  248. var
  249. w, h, I: Integer;
  250. B: Boolean;
  251. begin
  252. if IsClosing then Exit;
  253. ToggleTimers(False);
  254. w := ClientWidth;
  255. h := ClientHeight;
  256. NX := w - 1;
  257. NY := h - 1;
  258. CX := NX div 2;
  259. CY := NY div 2;
  260. FixedMouseX := 0;
  261. FixedMouseY := 0;
  262. for B := False to True do with Buffers[B] do
  263. begin
  264. SetSize(w, h);
  265. Font.Size := 30;
  266. RenderText(CX - TextWidth(Line1) div 2, CY - 120, Line1, $DEADBEEF);
  267. Font.Size := 20;
  268. RenderText(CX - TextWidth(Line2) div 2, CY + 60, Line2, $DEADF00D);
  269. end;
  270. VectorMap.SetSize(w, h);
  271. PathRadius := Min(Width, Height) / 2;
  272. PathRadius := Max(1, PathRadius - PathRadius / 2);
  273. for I := 0 to High(LastPoint) do
  274. begin
  275. LastPoint[I][0].X := CX;
  276. LastPoint[I][0].Y := CY;
  277. LastPoint[I][1].X := CX;
  278. LastPoint[I][1].Y := CY;
  279. end;
  280. ToggleTimers(True);
  281. end;
  282. procedure TMainForm.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
  283. Y: Integer);
  284. begin
  285. FixedMouseX := Fixed((X - Width div 2) / 10);
  286. FixedMouseY := Fixed((Y - Height div 2) / 10);
  287. Buffers[CurrentBuffer].FrameRectS(X - 10, Y - 10, X + 10, Y + 10,
  288. HSLtoRGB(Hue + X / Clientwidth, Y / ClientHeight, 0.5));
  289. end;
  290. procedure TMainForm.FormKeyDown(Sender: TObject; var Key: Word;
  291. Shift: TShiftState);
  292. var
  293. C: Char;
  294. I: Integer;
  295. begin
  296. {$IFNDEF FPC}
  297. C := Lowercase(Char(Key))[1];
  298. {$ELSE}
  299. C := Lowercase(Char(Key));
  300. {$ENDIF}
  301. if TryStrToInt(C, I) and InRange(I, 1, 9) then
  302. begin
  303. if ssShift in Shift then
  304. Feedback := I / 10
  305. else
  306. begin
  307. MovementIndex := I;
  308. RenderMovement;
  309. end;
  310. end
  311. else
  312. case C of
  313. 'f': vShowFPS := not vShowFPS;
  314. 'h': vShowHelp := not vShowHelp;
  315. 'r': MovementTimer.Enabled := not MovementTimer.Enabled;
  316. end;
  317. end;
  318. procedure TMainForm.RenderHelpScreen;
  319. const
  320. Line1 = 'HELP';
  321. Line2 = '1..9: Chooses different movements';
  322. Line3 = 'F: Toggles FPS counter';
  323. Line4 = 'H: Toggles this help';
  324. Line5 = 'R: Toggles random movement change';
  325. var
  326. T, L, R, B, H, W: Integer;
  327. begin
  328. with Buffers[CurrentBuffer] do
  329. begin
  330. R := 280;
  331. B := 100;
  332. L := CX - R div 2;
  333. T := CY - B div 2;
  334. R := CX + R div 2;
  335. B := CY + B div 2;
  336. H := 5;
  337. W := 5;
  338. Font.Size := 10;
  339. Font.Name := 'Courier New';
  340. FillRectTS(L, T, R, B, $FF9F9F9F);
  341. FrameRectTS(L, T, R, B, $FFFFFFFF);
  342. RenderText(L + W, T + H, Line1, clBlack32);
  343. Inc(H, TextHeight(Line1));
  344. RenderText(L + W, T + H, Line2, clBlack32);
  345. Inc(H, TextHeight(Line2));
  346. RenderText(L + W, T + H, Line3, clBlack32);
  347. Inc(H, TextHeight(Line3));
  348. RenderText(L + W, T + H, Line4, clBlack32);
  349. Inc(H, TextHeight(Line4));
  350. RenderText(L + W, T + H, Line5, clBlack32);
  351. end;
  352. end;
  353. procedure TMainForm.BufferFeedBack(Feedback, BlendContrast: Byte;
  354. BlendBrightness, BufferBrightness: Integer);
  355. var
  356. I, L: Integer;
  357. PSrc, PDst: PColor32;
  358. C, S, D: TColor32;
  359. begin
  360. PSrc := Buffers[not CurrentBuffer].PixelPtr[0,0];
  361. PDst := Buffers[CurrentBuffer].PixelPtr[0,0];
  362. C := FeedBack shl 24;
  363. for I := 0 to Buffers[CurrentBuffer].Width * Buffers[CurrentBuffer].Height - 1 do
  364. begin
  365. D := PDst^;
  366. S := ColorAverage(PSrc^, D);
  367. L := S and $FF + S shr 8 and $FF + S shr 16 and $FF;
  368. L := L - 382;
  369. L := SAR_9(L * BlendContrast) + BlendBrightness;
  370. S := Lighten(S, L) and $00FFFFFF;
  371. D := BlendReg(C + S, D);
  372. PDst^ := Lighten(D, BufferBrightness);
  373. Inc(PSrc);
  374. Inc(PDst);
  375. end;
  376. end;
  377. procedure TMainForm.TransformFrame(Sender: TObject; var Done: Boolean);
  378. begin
  379. if FPS <> 0 then
  380. FPS_Adaption := MovementSpeed / FPS;
  381. if vShowHelp then
  382. RenderHelpScreen
  383. else
  384. FastRemap(Buffers[CurrentBuffer], Buffers[not CurrentBuffer], VectorMap);
  385. CurrentBuffer := not CurrentBuffer; //Swap Buffer Index
  386. Buffers[CurrentBuffer].DrawTo(MainForm.Canvas.Handle, 0,0);
  387. if vShowFPS then
  388. begin
  389. Canvas.TextOut(3, 3, IntToStr(FPS) + ' FPS');
  390. Inc(FPSMeasure);
  391. end;
  392. if Random > Feedback then
  393. BufferFeedBack(BlendLevel, BlendContrast, BlendBrightness, TimeDarkening);
  394. Done := False;
  395. end;
  396. procedure RenderSpot(Dst: TBitmap32; Size, X,Y: Integer; Color: TColor32; Additive: Boolean);
  397. // Use a crude, but fast approach to spot rendering
  398. var
  399. I, J, L: Integer;
  400. S: Single;
  401. C1, C2: TColor32;
  402. Table: array of TFixed;
  403. begin
  404. X := X - Size shr 1;
  405. Y := Y - Size shr 1;
  406. S := 1 / Max(1, Size - 1);
  407. SetLength(Table, Size);
  408. for I := 0 to Size - 1 do
  409. Table[I] := Fixed(255 * (1 - (1 + Cos((I * S) * PI * 2)) * 0.5));
  410. for J := 0 to Size - 1 do
  411. for I := 0 to Size - 1 do
  412. begin
  413. L := FixedMul(Table[I], Table[J]) and $FF000000;
  414. C1 := Dst.PixelS[X + I, Y + J];
  415. if Additive then
  416. C2 := ColorAdd(Color, C1) and $00FFFFFF + Cardinal(L)
  417. else
  418. C2 := Color and $00FFFFFF + Cardinal(L);
  419. Dst.PixelS[X + I, Y + J] := BlendReg(C2, C1);
  420. end;
  421. end;
  422. procedure TMainForm.RenderMovement;
  423. const
  424. Jit = 1/8; //Jitter level: adds random displacement
  425. var
  426. I, J: Integer;
  427. x,y, rx, ry, nrx, nry, sx, sy,
  428. r, d, CosV, SinV: Single;
  429. begin
  430. with VectorMap do
  431. begin
  432. rx := Width - 1;
  433. ry := Height - 1;
  434. nrx := 2 / rx;
  435. nry := 2 / ry;
  436. for J := 0 to Height - 1 do
  437. for I := 0 to Width - 1 do
  438. begin
  439. // normalize dimensions
  440. x := I * nrx - 1;
  441. y := J * nry - 1;
  442. // back up x & y
  443. sx := x;
  444. sy := y;
  445. // Switch to radial space
  446. d := GR32_Math.Hypot(x, y);
  447. r := ArcTan2(y, x);
  448. // Callback to the current movement, this is what actually creates the displacement
  449. Movements[MovementIndex](rx, ry, x, y, d, r);
  450. // Switch to rectangular space, and add potential x,y difference
  451. GR32_Math.SinCos(r, SinV, CosV);
  452. x := d * CosV + (x - sx);
  453. y := d * SinV + (y - sy);
  454. // Scale result for transformationmap, we make displacement relative by subtracting I,J
  455. x := (x + 1) * rx * 0.5 - I;
  456. y := (y + 1) * ry * 0.5 - J;
  457. // Write values to transformationmap
  458. FixedVector[I, J] := FixedPoint(x * FPS_Adaption + (random - 0.5) * Jit, y * FPS_Adaption
  459. + (random - 0.5) * Jit);
  460. end;
  461. end;
  462. CurrentMap := not CurrentMap;
  463. end;
  464. procedure TMainForm.MovementTimerTimer(Sender: TObject);
  465. // Here we change the perceptual look of the visualization
  466. // by setting up most parameters from a few random numbers
  467. // The actual code here, is the result of a few minutes of
  468. // experimentation - go ahead and fiddle with the setup :)
  469. var
  470. Activity: Single;
  471. begin
  472. if CurrentMap = False then
  473. begin
  474. Render_Worms := Random;
  475. Render_PathSpots := (1 - Render_Worms) * ARandomNumber;
  476. Render_RandomSpots := 1 - Render_Worms;
  477. Render_Noise := Random;
  478. Activity := (Render_Worms + Render_PathSpots + Render_RandomSpots
  479. + Render_Noise)/4;
  480. BlendLevel := Round(10 + (100 * Activity) + 100 * ARandomNumber);
  481. BlendContrast := Round(32 * Activity + 5 * (ARandomNumber - 0.5));
  482. BlendBrightness := Round(Activity * 10 + 5 * (ARandomNumber - 0.5));
  483. TimeDarkening := - Round(7 * Activity);
  484. FeedBack := Activity;
  485. end;
  486. MovementIndex := Constrain(Random(10), 1, 9);
  487. RenderMovement;
  488. vShowHelp := False;
  489. end;
  490. procedure TMainForm.RenderTimerTimer(Sender: TObject);
  491. const
  492. PI2 = 2 * PI;
  493. MaxCount = 50;
  494. var
  495. x,y :Single;
  496. Count, Size: Integer;
  497. CosV, SinV, PathCX, PathCY: Single;
  498. OX, OY, I: Integer;
  499. C: TColor32;
  500. L1: TPoint;
  501. Additive: Boolean;
  502. begin
  503. with Buffers[CurrentBuffer] do
  504. begin
  505. if Random < Render_Noise then
  506. begin
  507. C := HSLtoRGB(Hue + 0.1, Sat, Lns);
  508. for I := 0 to 10 do
  509. begin
  510. OX := CX + Random(200) - 100;
  511. OY := CY + Random(200) - 100;
  512. PixelS[OX, OY] := C;
  513. end;
  514. end;
  515. if Random < Render_RandomSpots then
  516. begin
  517. Count := Random(MaxCount);
  518. Size := MaxCount - Count;
  519. Additive := Boolean(Random(2));
  520. for I:= 0 to Count do
  521. begin
  522. GR32_Math.SinCos(Random * PI * 2, SinV, CosV);
  523. x := CX + Size * 5 * SinV;
  524. y := CY + Size * 5 * CosV;
  525. RenderSpot(Buffers[CurrentBuffer], 1 + Size + Random(5), Round(x),
  526. Round(y), HSLtoRGB(ARandomNumber + Random * 0.1, ARandomNumber, 0.5),
  527. Additive);
  528. end;
  529. end;
  530. if Random < Render_PathSpots then
  531. begin
  532. C := HSLtoRGB(PathAngle/PI2, 1 - Sat, 1 - Lns);
  533. GR32_Math.SinCos(PathAngle, SinV, CosV);
  534. PathCX := CX + PathRadius * SinV;
  535. PathCY := CY + PathRadius * CosV;
  536. RenderSpot(Buffers[CurrentBuffer], Round(1 + PathRadius/5),
  537. Round(PathCX), Round(PathCY), C, True);
  538. GR32_Math.SinCos(PathAngle - PI, SinV, CosV);
  539. PathCX := CX + PathRadius * SinV;
  540. PathCY := CY + PathRadius * CosV;
  541. RenderSpot(Buffers[CurrentBuffer], Round(1 + PathRadius/5),
  542. Round(PathCX), Round(PathCY), C, True);
  543. PathAngle := PathAngle - PathStep;
  544. if not InRange(PathAngle, 0, PI2) then
  545. begin
  546. Constrain(PathAngle, 0, PI2);
  547. PathStep := - PathStep;
  548. end;
  549. PathRadius := PathRadius - PathRadiusStep;
  550. if not InRange(Abs(PathRadius), 1, Min(CX, CY) * Random) then
  551. begin
  552. Constrain(PathRadius, 1, Min(CX, CY));
  553. PathRadiusStep := - PathRadiusStep;
  554. end;
  555. end;
  556. if Random < Render_Worms then
  557. begin
  558. for I := 0 to High(LastPoint) do
  559. begin
  560. L1 := LastPoint[I][1];
  561. with LastPoint[I][0] do
  562. begin
  563. OX := Constrain(X - L1.X, -2, 2) + Random(3) - 1 + X;
  564. OY := Constrain(Y - L1.Y, -2, 2) + Random(3) - 1 + Y;
  565. OX := Constrain(OX, CX - 60, CX + 80);
  566. OY := Constrain(OY, CY - 40, CY + 60);
  567. LineS(X, Y, OX, OY, HSLtoRGB(Hue - 0.2 * random, Sat, 0));
  568. LineS(X, Y+1, OX, OY+1, HSLtoRGB(Hue, Sat, 0.4));
  569. LineS(X, Y-1, OX, OY-1, HSLtoRGB(Hue, Sat, 0.6));
  570. LineS(X+1, Y, OX + 1, OY, HSLtoRGB(Hue + 0.2 * random, Sat, 1));
  571. end;
  572. LastPoint[I][1] := LastPoint[I][0];
  573. LastPoint[I][0].X := OX;
  574. LastPoint[I][0].Y := OY;
  575. end;
  576. end;
  577. end;
  578. end;
  579. procedure TMainForm.ColorTimerTimer(Sender: TObject);
  580. begin
  581. Hue := Hue + (Random - 0.15) * HueIncreaser;
  582. if (Hue > 1) or (Hue < 0) then
  583. begin
  584. Hue := Constrain(Hue, 0, 1);
  585. HueIncreaser := - HueIncreaser;
  586. end;
  587. Sat := Sat + (Random - 0.15) * SatIncreaser;
  588. if (Sat > 0.75) or (Sat < 0.25) then
  589. begin
  590. Sat := Constrain(Sat, 0.25, 0.75);
  591. SatIncreaser := - SatIncreaser;
  592. end;
  593. Lns := Lns + (Random - 0.15) * LnsIncreaser;
  594. if (Lns > 1) or (Lns < 0) then
  595. begin
  596. Lns := Constrain(Lns, 0, 1);
  597. LnsIncreaser := - LnsIncreaser;
  598. end;
  599. ARandomNumber := Random;
  600. end;
  601. procedure TMainForm.FPSTimerTimer(Sender: TObject);
  602. begin
  603. FPS := FPSMeasure;
  604. FPSMeasure := 0;
  605. end;
  606. procedure TMainForm.ToggleTimers(Enabled: Boolean);
  607. var
  608. I: Integer;
  609. begin
  610. for I := 0 to ComponentCount - 1 do
  611. if Components[I] is TTimer then
  612. TTimer(Components[I]).Enabled := Enabled;
  613. end;
  614. end.