GXS.Perlin.pas 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976
  1. //
  2. // The graphics engine GXScene https://github.com/glscene
  3. //
  4. unit GXS.Perlin;
  5. (*
  6. Classes for generating perlin noise.
  7. The components and classes in the unit are a base to generate textures and heightmaps from,
  8. A Perlin Height Data Source have been included as an example.
  9. Use this combined with a terrain renderer for an infinite random landscape
  10. *)
  11. interface
  12. {$I Stage.Defines.inc}
  13. uses
  14. System.Classes,
  15. System.SysUtils,
  16. System.Math,
  17. FMX.Graphics,
  18. Stage.VectorGeometry,
  19. GXS.ImageUtils,
  20. GXS.HeightData;
  21. Type
  22. T1DPerlinArray = array of Double;
  23. T2DPerlinArray = array of T1DPerlinArray;
  24. TgxPerlinInterpolation = (pi_none, pi_simple, pi_linear, pi_Smoothed,
  25. pi_Cosine, pi_cubic);
  26. TgxBasePerlinOctav = class
  27. private
  28. FAmplitude: Double;
  29. FScale: Double;
  30. FInterpolation: TgxPerlinInterpolation;
  31. FSmoothing: TgxPerlinInterpolation;
  32. public
  33. procedure Generate; virtual; abstract;
  34. property Interpolation: TgxPerlinInterpolation read FInterpolation
  35. write FInterpolation;
  36. property Smoothing: TgxPerlinInterpolation read FSmoothing write FSmoothing;
  37. property Amplitude: Double read FAmplitude write FAmplitude;
  38. property Scale: Double read FScale write FScale;
  39. end;
  40. TgxPerlinOctav = class of TgxBasePerlinOctav;
  41. TgxBasePerlin = class(TComponent)
  42. private
  43. FPersistence: Double;
  44. FNumber_Of_Octaves: Integer;
  45. FOctaves: TList;
  46. FOctavClass: TgxPerlinOctav;
  47. FInterpolation: TgxPerlinInterpolation;
  48. FSmoothing: TgxPerlinInterpolation;
  49. protected
  50. function PerlinNoise_1D(x: Double): Double;
  51. function PerlinNoise_2D(x, y: Double): Double;
  52. function GetOctave(index: Integer): TgxBasePerlinOctav;
  53. procedure SetPersistence(val: Double);
  54. procedure Set_Number_Of_Octaves(val: Integer);
  55. public
  56. Constructor Create(AOwner: TComponent); override;
  57. Procedure Generate; virtual; abstract;
  58. Property Octaves[index: Integer]: TgxBasePerlinOctav read GetOctave;
  59. published
  60. property Smoothing: TgxPerlinInterpolation read FSmoothing write FSmoothing;
  61. property Interpolation: TgxPerlinInterpolation read FInterpolation
  62. write FInterpolation;
  63. property Persistence: Double read FPersistence write SetPersistence;
  64. property Number_Of_Octaves: Integer read FNumber_Of_Octaves
  65. write Set_Number_Of_Octaves;
  66. end;
  67. Tgx1DPerlin = class(TgxBasePerlin)
  68. function GetPerlinValue_1D(x: Double): Double;
  69. published
  70. end;
  71. Tgx2DPerlinOctav = class(TgxBasePerlinOctav)
  72. public
  73. Data: T2DPerlinArray;
  74. Width, Height: Integer;
  75. XStart, YStart: Integer;
  76. XStep, YStep: Integer;
  77. YRate: Integer;
  78. procedure Generate; override;
  79. function GetDataSmoothed(x, y: Integer): Double;
  80. function GetData(x, y: Integer): Double;
  81. function GetCubic(x, y: Double): Double;
  82. function GetCosine(x, y: Double): Double;
  83. function GetPerling(x, y: Double): Double;
  84. procedure Generate_CubicInterpolate;
  85. procedure Generate_SmoothInterpolate;
  86. procedure Generate_NonInterpolated;
  87. end;
  88. Tgx2DPerlin = class(TgxBasePerlin)
  89. private
  90. public
  91. Width, Height: Integer;
  92. XStart, YStart: Integer;
  93. XStep, YStep: Integer;
  94. MaxValue, MinValue: Double;
  95. Constructor Create(AOwner: TComponent); override;
  96. Procedure Generate; override;
  97. Function GetPerlinValue_2D(x, y: Double): Double;
  98. Procedure MakeBitmap(Param: TBitmap);
  99. Procedure SetHeightData(heightData: TgxHeightData);
  100. end;
  101. TgxPerlinHDS = class(TgxHeightDataSource)
  102. private
  103. FInterpolation: TgxPerlinInterpolation;
  104. FSmoothing: TgxPerlinInterpolation;
  105. FPersistence: Double;
  106. FNumber_Of_Octaves: Integer;
  107. FLines: TStrings;
  108. FLinesChanged: Boolean;
  109. FXStart, FYStart: Integer;
  110. public
  111. MaxValue, MinValue: Double;
  112. Stall: Boolean;
  113. Constructor Create(AOwner: TComponent); override;
  114. procedure StartPreparingData(heightData: TgxHeightData); override;
  115. procedure WaitFor;
  116. property Lines: TStrings read FLines;
  117. property LinesChanged: Boolean read FLinesChanged write FLinesChanged;
  118. published
  119. property Interpolation: TgxPerlinInterpolation read FInterpolation
  120. write FInterpolation;
  121. property Smoothing: TgxPerlinInterpolation read FSmoothing write FSmoothing;
  122. property Persistence: Double read FPersistence write FPersistence;
  123. property Number_Of_Octaves: Integer read FNumber_Of_Octaves
  124. write FNumber_Of_Octaves;
  125. property MaxPoolSize;
  126. property XStart: Integer read FXStart write FXStart;
  127. property YStart: Integer read FYStart write FYStart;
  128. end;
  129. TgxPerlinHDSThread = class(TgxHeightDataThread)
  130. Perlin: Tgx2DPerlin;
  131. PerlinSource: TgxPerlinHDS;
  132. Procedure OpdateOutSide;
  133. Procedure Execute; override;
  134. end;
  135. // Useless for final output! Usefull for after interpolation, as its FAST!
  136. function Linear_Interpolate(const a, b, x: Double): Double;
  137. // does a cubic interpolation
  138. function Cubic_Interpolate(v0, v1, v2, v3, x: Double): Double;
  139. // does a cosine interpolation
  140. function Cosine_Interpolate(const a, b, x: Double): Double;
  141. // just a random controlled by X
  142. function Perlin_Random1(x: Integer): Double;
  143. // just a random controlled by X,Y
  144. function Perlin_Random2(Const x, Y: Integer): Double;
  145. // generates a random strip
  146. procedure Perlin_Random1DStrip(x, Width, Step: Integer; Amp: Double; Res: T1DPerlinArray);
  147. // cubic interpolate 4 strips into one...
  148. procedure Cubic_Interpolate_Strip(B1, B2, B3, B4, Res: T1DPerlinArray; Width: Integer);
  149. // smooth interpolate 3 strips into one...
  150. procedure Smooth_Interpolate_Strip(B1, B2, B3, Res: T1DPerlinArray; Width: Integer);
  151. (* The function returning some integer based on the root^exponant concept,
  152. result is crap and is only for "random" usage... eg perlin. *)
  153. function ExponateCrap(root, exponant: Integer): Integer;
  154. //----------------------------------------------------------------
  155. implementation
  156. //----------------------------------------------------------------
  157. function ExponateCrap(root, exponant: Integer): Integer;
  158. var
  159. D: Extended;
  160. begin
  161. if root <= 0 then
  162. Result := 0
  163. else
  164. begin
  165. D := exp(ln(root) * exponant);
  166. If D >= 1E30 then // = Infinity then
  167. D := root * exponant;
  168. // if you got a better(faster) way of carving some integer value out of a double let me know!
  169. if D > maxInt then
  170. Result := maxInt
  171. else
  172. Result := Round(D);
  173. end;
  174. end;
  175. function Perlin_Random1(x: Integer): Double;
  176. begin
  177. x := ExponateCrap((x shl 13) + (x shr 9), x);
  178. // mess up the number real good!
  179. // X X X those three number can be played with, primes are incouraged!
  180. x := ((x * (x * x * 15731 + 789221) + 1376312589) And $7FFFFFFF);
  181. Result := 1.0 - x / 1073741824.0 // make it a [-1;1] affair!
  182. end;
  183. function Perlin_Random2(const x, Y: Integer): Double;
  184. begin
  185. // it works! I guess any prime will do!
  186. Result := Perlin_Random1(x + Y * 57);
  187. end;
  188. procedure Perlin_Random1DStrip(x, Width, Step: Integer; Amp: Double;
  189. Res: T1DPerlinArray);
  190. var
  191. Posi: PDouble;
  192. XC: Integer;
  193. begin
  194. Posi := @Res[0];
  195. For XC := 0 to Width - 1 do
  196. begin
  197. Posi^ := Perlin_Random1(x) * Amp;
  198. inc(Posi);
  199. inc(x, Step);
  200. end;
  201. end;
  202. procedure Smooth_Interpolate_Strip(B1, B2, B3, Res: T1DPerlinArray;
  203. Width: Integer);
  204. var
  205. Posi: PDouble;
  206. T1: PDouble;
  207. T2: PDouble;
  208. T3: PDouble;
  209. C1: PDouble;
  210. C2: PDouble;
  211. C3: PDouble;
  212. L1: PDouble;
  213. L2: PDouble;
  214. L3: PDouble;
  215. XC: Integer;
  216. begin
  217. Posi := @Res[0];
  218. T1 := @B1[0];
  219. C1 := @B2[0];
  220. L1 := @B3[0];
  221. T2 := Pointer(Cardinal(T1) + SizeOf(Double));
  222. C2 := Pointer(Cardinal(C1) + SizeOf(Double));
  223. L2 := Pointer(Cardinal(L1) + SizeOf(Double));
  224. T3 := Pointer(Cardinal(T2) + SizeOf(Double));
  225. C3 := Pointer(Cardinal(C2) + SizeOf(Double));
  226. L3 := Pointer(Cardinal(L2) + SizeOf(Double));
  227. for XC := 0 to Width - 1 do
  228. begin
  229. Posi^ := (T1^ + T3^ + L1^ + L3^) / 16 + (T2^ + C1^ + C3^ + L2^) / 8
  230. + C2^ / 4;
  231. inc(Posi);
  232. T1 := T2;
  233. C1 := C2;
  234. L1 := L2;
  235. T2 := T3;
  236. C2 := C3;
  237. L2 := L3;
  238. inc(T3);
  239. inc(C3);
  240. inc(L3);
  241. end;
  242. end;
  243. procedure Cubic_Interpolate_Strip(B1, B2, B3, B4, Res: T1DPerlinArray;
  244. Width: Integer);
  245. var
  246. Posi: PDouble;
  247. v1: PDouble;
  248. v2: PDouble;
  249. v3: PDouble;
  250. V4: PDouble;
  251. H1: PDouble;
  252. H2: PDouble;
  253. H3: PDouble;
  254. H4: PDouble;
  255. XC: Integer;
  256. begin
  257. Posi := @Res[0];
  258. v1 := @B1[1];
  259. v2 := @B2[1];
  260. v3 := @B3[1];
  261. V4 := @B4[1];
  262. H1 := @B2[0];
  263. H2 := @B2[1];
  264. H3 := @B2[2];
  265. H4 := @B2[3];
  266. for XC := 0 to Width - 1 do
  267. begin
  268. Posi^ := Cubic_Interpolate(v1^, v2^, v3^, V4^, 0.5) / 2 +
  269. Cubic_Interpolate(H1^, H2^, H3^, H4^, 0.5) / 2;
  270. inc(Posi);
  271. H1 := H2;
  272. H2 := H3;
  273. H3 := H4;
  274. inc(H4);
  275. inc(v1);
  276. inc(v2);
  277. inc(v3);
  278. inc(V4);
  279. end;
  280. end;
  281. function Linear_Interpolate(const a, b, x: Double): Double;
  282. begin
  283. Result := a * (1 - x) + b * x
  284. end;
  285. function Cosine_Interpolate(const a, b, x: Double): Double;
  286. var
  287. ft: Double;
  288. f: Double;
  289. begin
  290. ft := x * pi;
  291. f := (1 - cos(ft)) * 0.5;
  292. Result := a * (1 - f) + b * f;
  293. end;
  294. function Cubic_Interpolate(v0, v1, v2, v3, x: Double): Double;
  295. var
  296. P, Q, R, S: Double;
  297. begin
  298. (* Result := Cosine_Interpolate(v1,v2,x);
  299. Exit;
  300. v0 := -0.5;
  301. v1 := 0;
  302. v2 := 0;
  303. v3 := -0.5; *)
  304. P := (v3 - v2) - (v0 - v1);
  305. Q := (v0 - v1) - P;
  306. R := v2 - v0;
  307. S := v1;
  308. Result := (P * x * x * x + Q * x * x + R * x + S);
  309. // If (Abs(Result) > 1) then
  310. // Raise exception.create('Cubic_Interpolate result to high, '+FloatToStr(Result)+' values ['+FloatToStr(v0)+';'+FloatToStr(v1)+';'+FloatToStr(v2)+';'+FloatToStr(v3)+']');{}
  311. end;
  312. //-----------------------------------
  313. // TgxBasePerlin
  314. //-----------------------------------
  315. function TgxBasePerlin.PerlinNoise_1D(x: Double): Double;
  316. var
  317. int_x: Integer;
  318. frac_x: Double;
  319. begin
  320. int_x := Round(Int(x));
  321. frac_x := x - int_x;
  322. case Interpolation of
  323. pi_none:
  324. Result := 0;
  325. pi_simple:
  326. Result := Perlin_Random1(int_x);
  327. pi_linear:
  328. Result := Linear_Interpolate(Perlin_Random1(int_x),
  329. Perlin_Random1(int_x + 1), frac_x);
  330. pi_cubic:
  331. Result := Cubic_Interpolate(Perlin_Random1(int_x - 1),
  332. Perlin_Random1(int_x), Perlin_Random1(int_x + 1),
  333. Perlin_Random1(int_x + 2), frac_x);
  334. pi_Cosine:
  335. Result := Cosine_Interpolate(Perlin_Random1(int_x),
  336. Perlin_Random1(int_x + 1), frac_x);
  337. else
  338. raise exception.Create
  339. ('PerlinNoise_1D, Interpolation not implemented!');
  340. End;
  341. end;
  342. function TgxBasePerlin.PerlinNoise_2D(x, y: Double): Double;
  343. Var
  344. int_x, int_y: Integer;
  345. // frac_y,
  346. frac_x: Double;
  347. Begin
  348. int_x := Round(Int(x));
  349. int_y := Round(Int(y));
  350. frac_x := x - int_x;
  351. // frac_y := y-int_y;
  352. case Interpolation of
  353. pi_none:
  354. Result := 0;
  355. pi_simple:
  356. Result := Perlin_Random2(int_x, int_y);
  357. pi_linear:
  358. Result := Linear_Interpolate(Perlin_Random1(int_x),
  359. Perlin_Random1(int_x + 1), frac_x);
  360. pi_cubic:
  361. Result := Cubic_Interpolate(Perlin_Random1(int_x - 1),
  362. Perlin_Random1(int_x), Perlin_Random1(int_x + 1),
  363. Perlin_Random1(int_x + 2), frac_x);
  364. pi_Cosine:
  365. Result := Cosine_Interpolate(Perlin_Random1(int_x),
  366. Perlin_Random1(int_x + 1), frac_x);
  367. else
  368. raise exception.Create
  369. ('PerlinNoise_1D, Interpolation not implemented!');
  370. End;
  371. End;
  372. function TgxBasePerlin.GetOctave(index: Integer): TgxBasePerlinOctav;
  373. begin
  374. Result := TgxBasePerlinOctav(FOctaves[index]);
  375. end;
  376. procedure TgxBasePerlin.Set_Number_Of_Octaves(val: Integer);
  377. var
  378. XC: Integer;
  379. NewScale: Integer;
  380. Octav: TgxBasePerlinOctav;
  381. begin
  382. If val <> FNumber_Of_Octaves then
  383. begin
  384. FNumber_Of_Octaves := val;
  385. For XC := FOctaves.Count to FNumber_Of_Octaves - 1 do
  386. begin
  387. Octav := FOctavClass.Create;
  388. If FPersistence = 0 then
  389. Octav.FAmplitude := 0
  390. else
  391. Octav.FAmplitude := exp(ln(FPersistence) * (XC + 1));
  392. Octav.FInterpolation := Interpolation;
  393. Octav.FSmoothing := Smoothing;
  394. FOctaves.Add(Octav);
  395. end;
  396. For XC := FOctaves.Count - 1 downto FNumber_Of_Octaves do
  397. begin
  398. Octav := Octaves[XC];
  399. FOctaves.Delete(XC);
  400. Octav.Free;
  401. end;
  402. NewScale := 1;
  403. For XC := FOctaves.Count - 1 downto 0 do
  404. begin
  405. Octaves[XC].Scale := NewScale;
  406. NewScale := NewScale shl 1;
  407. end;
  408. end;
  409. end;
  410. procedure TgxBasePerlin.SetPersistence(val: Double);
  411. var
  412. XC: Integer;
  413. begin
  414. If FPersistence <> val then
  415. begin
  416. FPersistence := val;
  417. For XC := FOctaves.Count to FNumber_Of_Octaves - 1 do
  418. begin
  419. Octaves[XC].FAmplitude := exp(ln(FPersistence) * XC);
  420. end;
  421. end;
  422. end;
  423. constructor TgxBasePerlin.Create(AOwner: TComponent);
  424. begin
  425. inherited;
  426. FOctaves := TList.Create;
  427. FNumber_Of_Octaves := 0;
  428. FInterpolation := pi_Cosine;
  429. FSmoothing := pi_cubic;
  430. end;
  431. function Tgx1DPerlin.GetPerlinValue_1D(x: Double): Double;
  432. var
  433. total, p, frequency, Amplitude: Double;
  434. n, i: Integer;
  435. begin
  436. total := 0;
  437. p := Persistence;
  438. n := Number_Of_Octaves - 1;
  439. For i := 0 to n do
  440. begin
  441. frequency := 2 * i;
  442. Amplitude := p * i;
  443. total := total + PerlinNoise_1D(x * frequency) * Amplitude;
  444. end;
  445. Result := total;
  446. end;
  447. procedure Tgx2DPerlinOctav.Generate;
  448. var
  449. YC: Integer;
  450. begin
  451. SetLength(Data, Height + 3); // needed for smoothing
  452. For YC := 0 to Height + 2 do
  453. SetLength(Data[YC], Width + 3); // needed for smoothing
  454. case Smoothing of
  455. pi_cubic:
  456. begin
  457. Generate_CubicInterpolate;
  458. end;
  459. pi_Smoothed:
  460. begin
  461. Generate_SmoothInterpolate;
  462. end;
  463. pi_none:
  464. ;
  465. pi_simple:
  466. begin
  467. Generate_NonInterpolated;
  468. end;
  469. end;
  470. end;
  471. Function Tgx2DPerlinOctav.GetPerling(x, y: Double): Double;
  472. begin
  473. Result := 0;
  474. case Interpolation of
  475. pi_cubic:
  476. begin
  477. Result := GetCubic(x, y);
  478. end;
  479. pi_Smoothed:
  480. begin
  481. end;
  482. pi_Cosine:
  483. begin
  484. Result := GetCosine(x, y);
  485. end;
  486. end;
  487. end;
  488. procedure Tgx2DPerlinOctav.Generate_CubicInterpolate;
  489. var
  490. B1, B2, B3, B4, T1: T1DPerlinArray;
  491. StripWidth: Integer;
  492. Offset: Integer;
  493. YC: Integer;
  494. begin
  495. T1 := Nil;
  496. StripWidth := Width + 6;
  497. SetLength(B1, StripWidth);
  498. SetLength(B2, StripWidth);
  499. SetLength(B3, StripWidth);
  500. SetLength(B4, StripWidth);
  501. Offset := (XStart - 1) + (YStart - 1) * YStep * YRate;
  502. Perlin_Random1DStrip(Offset, StripWidth, XStep, FAmplitude, B1);
  503. inc(Offset, YRate * YStep);
  504. Perlin_Random1DStrip(Offset, StripWidth, XStep, FAmplitude, B2);
  505. inc(Offset, YRate * YStep);
  506. Perlin_Random1DStrip(Offset, StripWidth, XStep, FAmplitude, B3);
  507. inc(Offset, YRate * YStep);
  508. For YC := 0 to Height + 2 do
  509. begin
  510. Perlin_Random1DStrip(Offset, StripWidth, XStep, FAmplitude, B4);
  511. inc(Offset, YRate * YStep);
  512. Cubic_Interpolate_Strip(B1, B2, B3, B4, Data[YC], Width + 3);
  513. T1 := B1;
  514. B1 := B2;
  515. B2 := B3;
  516. B3 := B4;
  517. B4 := T1;
  518. end;
  519. SetLength(B1, 0);
  520. SetLength(B2, 0);
  521. SetLength(B3, 0);
  522. SetLength(B4, 0);
  523. end;
  524. procedure Tgx2DPerlinOctav.Generate_SmoothInterpolate;
  525. var
  526. B1, B2, B3, T1: T1DPerlinArray;
  527. StripWidth: Integer;
  528. Offset: Integer;
  529. YC: Integer;
  530. begin
  531. T1 := Nil;
  532. StripWidth := Width + 5;
  533. SetLength(B1, StripWidth);
  534. SetLength(B2, StripWidth);
  535. SetLength(B3, StripWidth);
  536. Offset := (XStart - 1) + (YStart - 1) * YStep * YRate;
  537. Perlin_Random1DStrip(Offset, StripWidth, XStep, FAmplitude, B1);
  538. inc(Offset, YRate * YStep);
  539. Perlin_Random1DStrip(Offset, StripWidth, XStep, FAmplitude, B2);
  540. inc(Offset, YRate * YStep);
  541. For YC := 0 to Height + 2 do
  542. begin
  543. Perlin_Random1DStrip(Offset, StripWidth, XStep, FAmplitude, B3);
  544. inc(Offset, YRate * YStep);
  545. Smooth_Interpolate_Strip(B1, B2, B3, Data[YC], Width + 3);
  546. T1 := B1;
  547. B1 := B2;
  548. B2 := B3;
  549. B3 := T1;
  550. end;
  551. SetLength(B1, 0);
  552. SetLength(B2, 0);
  553. SetLength(B3, 0);
  554. end;
  555. procedure Tgx2DPerlinOctav.Generate_NonInterpolated;
  556. var
  557. Offset: Integer;
  558. YC: Integer;
  559. begin
  560. Offset := XStart + YStart * YStep * YRate;
  561. For YC := 0 to Height + 2 do
  562. begin
  563. Perlin_Random1DStrip(Offset, Width + 3, XStep, FAmplitude, Data[YC]);
  564. inc(Offset, YRate * YStep);
  565. end;
  566. end;
  567. function Tgx2DPerlinOctav.GetDataSmoothed(x, y: Integer): Double;
  568. begin
  569. Result := (Data[y][x] + Data[y][x + 2] + Data[y + 2][x] + Data[y + 2][x + 2])
  570. / 16 + (Data[y + 1][x] + Data[y + 1][x + 2] + Data[y][x + 1] + Data[y + 2]
  571. [x + 1]) / 8 + Data[y + 1][x + 1] / 4; { }
  572. end;
  573. function Tgx2DPerlinOctav.GetData(x, y: Integer): Double;
  574. begin
  575. Result := Data[y][x];
  576. end;
  577. function Tgx2DPerlinOctav.GetCubic(x, y: Double): Double;
  578. Var
  579. X_Int: Integer;
  580. Y_Int: Integer;
  581. X_Frac, Y_Frac: Double;
  582. begin
  583. X_Int := Round(Int(x));
  584. Y_Int := Round(Int(y));
  585. X_Frac := x - X_Int;
  586. Y_Frac := y - Y_Int;
  587. Result := (Cubic_Interpolate(GetData(X_Int, Y_Int + 1), GetData(X_Int + 1,
  588. Y_Int + 1), GetData(X_Int + 2, Y_Int + 1), GetData(X_Int + 3, Y_Int + 1),
  589. X_Frac) + Cubic_Interpolate(GetData(X_Int + 1, Y_Int), GetData(X_Int + 1,
  590. Y_Int + 1), GetData(X_Int + 1, Y_Int + 2), GetData(X_Int + 1, Y_Int + 3),
  591. Y_Frac)) / 2;
  592. end;
  593. function Tgx2DPerlinOctav.GetCosine(x, y: Double): Double;
  594. var
  595. X_Int: Integer;
  596. Y_Int: Integer;
  597. X_Frac, Y_Frac: Double;
  598. begin
  599. X_Int := Round(Int(x));
  600. Y_Int := Round(Int(y));
  601. X_Frac := x - X_Int;
  602. Y_Frac := y - Y_Int;
  603. Result := Cosine_Interpolate(Cosine_Interpolate(GetData(X_Int, Y_Int),
  604. GetData(X_Int + 1, Y_Int), X_Frac),
  605. Cosine_Interpolate(GetData(X_Int, Y_Int + 1), GetData(X_Int + 1, Y_Int + 1),
  606. X_Frac), Y_Frac);
  607. end;
  608. constructor Tgx2DPerlin.Create(AOwner: TComponent);
  609. begin
  610. inherited;
  611. Width := 256;
  612. Height := 256;
  613. XStart := 0;
  614. YStart := 0;
  615. XStep := 1;
  616. YStep := 1;
  617. FOctavClass := Tgx2DPerlinOctav;
  618. end;
  619. Procedure Tgx2DPerlin.Generate;
  620. var
  621. i: Integer;
  622. begin
  623. For i := 0 to Number_Of_Octaves - 1 do
  624. With Tgx2DPerlinOctav(Octaves[i]) do
  625. begin
  626. Width := Round(Ceil(self.Width / Scale));
  627. Height := Round(Ceil(self.Height / Scale));
  628. XStart := Round(self.XStart / Scale);
  629. YStart := Round(self.YStart / Scale);
  630. XStep := self.XStep;
  631. YStep := self.YStep;
  632. YRate := 243 * 57 * 57;
  633. Generate;
  634. end;
  635. end;
  636. function Tgx2DPerlin.GetPerlinValue_2D(x, y: Double): Double;
  637. var
  638. total, frequency, Amplitude: Double;
  639. i: Integer;
  640. begin
  641. total := 0;
  642. For i := 0 to Number_Of_Octaves - 1 do
  643. begin
  644. frequency := 2 * i;
  645. Amplitude := Persistence * i;
  646. total := total + PerlinNoise_2D(x * frequency, y * frequency) * Amplitude;
  647. end;
  648. Result := total;
  649. end;
  650. procedure Tgx2DPerlin.MakeBitmap(Param: TBitmap);
  651. var
  652. XC, YC: Integer;
  653. Octaver: Integer;
  654. Posi: PByte;
  655. B: Integer;
  656. Value: Double;
  657. S: String;
  658. begin
  659. MaxValue := -1;
  660. MinValue := 100;
  661. Param.Width := Width;
  662. Param.Height := Height;
  663. for YC := 0 to Height - 1 do
  664. begin
  665. Posi := BitmapScanline(Param, YC);
  666. For XC := 0 to Width - 1 do
  667. begin
  668. Value := 0;
  669. For Octaver := 0 to FNumber_Of_Octaves - 1 do
  670. With Tgx2DPerlinOctav(Octaves[Octaver]) do
  671. Value := Value + GetPerling(XC / Scale, YC / Scale);
  672. Value := Value + 0.5;
  673. If MaxValue < Value then
  674. MaxValue := Value;
  675. If MinValue > Value then
  676. MinValue := Value;
  677. If Value > 1.0 then
  678. begin
  679. S := '';
  680. For Octaver := 0 to FNumber_Of_Octaves - 1 do
  681. With Tgx2DPerlinOctav(Octaves[Octaver]) do
  682. S := S + FloatToStr(GetPerling(XC / Scale, YC / Scale)) + ' ,';
  683. Delete(S, Length(S) - 1, 2);
  684. // raise Exception.create('In Cubic_Interpolate_Strip a value greater than 1 occured! value = '+FloatToStr(Value)+' values=['+S+']');
  685. end;
  686. B := Round(Value * $FF) and $FF;
  687. Posi^ := B;
  688. inc(Posi);
  689. end;
  690. end;
  691. end;
  692. procedure Tgx2DPerlin.SetHeightData(heightData: TgxHeightData);
  693. var
  694. XC, YC: Integer;
  695. Octaver: Integer;
  696. Posi: PSmallInt;
  697. Value: Double;
  698. S: String;
  699. begin
  700. MaxValue := -1;
  701. MinValue := 100;
  702. heightData.Allocate(hdtSmallInt);
  703. Posi := @heightData.SmallIntData^[0];
  704. For YC := 0 to Height - 1 do
  705. begin
  706. For XC := 0 to Width - 1 do
  707. begin
  708. Value := 0;
  709. For Octaver := 0 to FNumber_Of_Octaves - 1 do
  710. With Tgx2DPerlinOctav(Octaves[Octaver]) do
  711. Value := Value + GetPerling(XC / Scale, YC / Scale);
  712. // value = [-0,5 .. 0,5]
  713. Posi^ := Round(Value * 256 * 100);
  714. // 100 instead of 128 to keep it well in range!
  715. If MaxValue < Value then
  716. MaxValue := Value;
  717. If MinValue > Value then
  718. MinValue := Value;
  719. If Value > 1.0 then
  720. begin
  721. S := '';
  722. For Octaver := 0 to FNumber_Of_Octaves - 1 do
  723. With Tgx2DPerlinOctav(Octaves[Octaver]) do
  724. S := S + FloatToStr(GetPerling(XC / Scale, YC / Scale)) + ' ,';
  725. Delete(S, Length(S) - 1, 2);
  726. // raise Exception.create('In Cubic_Interpolate_Strip a value greater than 1 occured! value = '+FloatToStr(Value)+' values=['+S+']');
  727. end;
  728. inc(Posi);
  729. end;
  730. end;
  731. end;
  732. constructor TgxPerlinHDS.Create(AOwner: TComponent);
  733. begin
  734. inherited;
  735. FLines := TStringList.Create;
  736. FInterpolation := pi_Cosine;
  737. FSmoothing := pi_cubic;
  738. FPersistence := 0.4;
  739. FNumber_Of_Octaves := 6;
  740. MaxValue := -MaxInt;
  741. MinValue := MaxInt;
  742. MaxThreads := 1;
  743. end;
  744. procedure TgxPerlinHDS.StartPreparingData(heightData: TgxHeightData);
  745. var
  746. Perlin: Tgx2DPerlin;
  747. Thread: TgxPerlinHDSThread;
  748. begin
  749. If Stall then
  750. heightData.DataState := hdsNone
  751. else
  752. heightData.DataState := hdsPreparing;
  753. Perlin := Tgx2DPerlin.Create(self);
  754. Perlin.Width := heightData.Size;
  755. Perlin.Height := heightData.Size;
  756. Perlin.XStart := heightData.XLeft + XStart;
  757. Perlin.YStart := heightData.YTop + YStart;
  758. Perlin.Interpolation := Interpolation;
  759. Perlin.Smoothing := Smoothing;
  760. Perlin.Persistence := Persistence;
  761. Perlin.Number_Of_Octaves := Number_Of_Octaves;
  762. If MaxThreads > 1 then
  763. begin
  764. Thread := TgxPerlinHDSThread.Create(True);
  765. Thread.FreeOnTerminate := True;
  766. heightData.Thread := Thread;
  767. Thread.FHeightData := HeightData;
  768. Thread.Perlin := Perlin;
  769. Thread.PerlinSource := self;
  770. Thread.Start;
  771. End
  772. else
  773. begin
  774. Perlin.Generate;
  775. Perlin.SetHeightData(heightData);
  776. heightData.DataState := hdsReady;
  777. If MaxValue < Perlin.MaxValue then
  778. MaxValue := Perlin.MaxValue;
  779. If MinValue < Perlin.MinValue then
  780. MinValue := Perlin.MinValue;
  781. Perlin.Free;
  782. end;
  783. Lines.Add('Prepared Perlin (' + IntToStr(Perlin.XStart) + ',' +
  784. IntToStr(Perlin.YStart) + ') size ' + IntToStr(Perlin.Width));
  785. LinesChanged := True;
  786. end;
  787. procedure TgxPerlinHDS.WaitFor;
  788. var
  789. HDList: TList;
  790. HD: TgxHeightData;
  791. XC: Integer;
  792. begin
  793. repeat
  794. HDList := Data.LockList;
  795. try
  796. HD := Nil;
  797. For XC := 0 to HDList.Count - 1 do
  798. begin
  799. HD := TgxHeightData(HDList[XC]);
  800. If HD.DataState <> hdsReady then
  801. Break;
  802. end;
  803. If Assigned(HD) then
  804. If HD.DataState = hdsReady then
  805. Break;
  806. finally
  807. Data.UnlockList;
  808. end;
  809. Sleep(10);
  810. until False;
  811. end;
  812. procedure TgxPerlinHDSThread.Execute;
  813. begin
  814. Perlin.Generate;
  815. Perlin.SetHeightData(FHeightData);
  816. FHeightData.DataState := hdsReady;
  817. If PerlinSource.MaxValue < Perlin.MaxValue then
  818. PerlinSource.MaxValue := Perlin.MaxValue;
  819. If PerlinSource.MinValue < Perlin.MinValue then
  820. PerlinSource.MinValue := Perlin.MinValue;
  821. Perlin.Free;
  822. end;
  823. procedure TgxPerlinHDSThread.OpdateOutSide;
  824. begin
  825. end;
  826. //-----------------------------------------------
  827. initialization
  828. //-----------------------------------------------
  829. RegisterClasses([TgxPerlinHDS]);
  830. end.