GLS.Perlin.pas 23 KB

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