You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

750 lines
22 KiB

  1. unit utsUtils;
  2. {$IFDEF FPC}
  3. {$mode objfpc}{$H+}
  4. {$ENDIF}
  5. interface
  6. uses
  7. Classes, SysUtils, Contnrs,
  8. utsTypes;
  9. type
  10. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  11. TtsRefManager = class(TObject)
  12. private
  13. fMasterRef: TtsRefManager; // master of this object (master will destroy this object)
  14. fSlaveRefs: TObjectList; // slaves of this object (will destroy all slaves when this objects is destroyed)
  15. protected
  16. procedure AddSlave(const aSlave: TtsRefManager); virtual;
  17. function DelSlave(const aSlave: TtsRefManager): Boolean; virtual;
  18. public
  19. constructor Create(const aMaster: TtsRefManager);
  20. destructor Destroy; override;
  21. end;
  22. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  23. TtsMultiMasterRefManager = class(TtsRefManager)
  24. private
  25. fMasterRefs: TObjectList;
  26. public
  27. procedure AddMaster(const aMaster: TtsRefManager); virtual;
  28. procedure DelMaster(const aMaster: TtsRefManager); virtual;
  29. constructor Create(const aMaster: TtsRefManager);
  30. destructor Destroy; override;
  31. end;
  32. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  33. TtsKernel1DItem = packed record
  34. Offset: Integer;
  35. Value: Single;
  36. end;
  37. TtsKernel1D = class
  38. public
  39. Size: Integer;
  40. Items: array of TtsKernel1DItem;
  41. ItemCount: Integer;
  42. constructor Create(const aRadius, aStrength: Single);
  43. end;
  44. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  45. TtsKernel2DItem = packed record
  46. OffsetX: Integer;
  47. OffsetY: Integer;
  48. Value: Double;
  49. DataOffset: Integer;
  50. end;
  51. TtsKernel2D = class
  52. public
  53. SizeX: Integer;
  54. SizeY: Integer;
  55. MidSizeX: Integer;
  56. MidSizeY: Integer;
  57. ValueSum: Double;
  58. Items: array of TtsKernel2DItem;
  59. ItemCount: Integer;
  60. constructor Create(const aRadius, aStrength: Single);
  61. end;
  62. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  63. EtsException = class(Exception);
  64. EtsRenderer = class(EtsException);
  65. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  66. function tsColor4f(r, g, b, a: Single): TtsColor4f;
  67. function tsPosition(const x, y: Integer): TtsPosition;
  68. function tsRect(const l, t, r, b: Integer): TtsRect; overload;
  69. function tsRect(const aTopLeft, aBottomRight: TtsPosition): TtsRect; overload;
  70. function tsVector4f(X, Y, Z, W: Single): TtsVector4f;
  71. function tsMatrix4f(X, Y, Z, P: TtsVector4f): TtsMatrix4f;
  72. function tsFormatSize(const aFormat: TtsFormat): Integer;
  73. procedure tsFormatMap(const aFormat: TtsFormat; var aData: PByte; const aColor: TtsColor4f);
  74. procedure tsFormatUnmap(const aFormat: TtsFormat; var aData: PByte; out aColor: TtsColor4f);
  75. function tsBlendValueIgnore(const aSrc, aDst: Single): Single;
  76. function tsBlendValueReplace(const aSrc, aDst: Single): Single;
  77. function tsBlendValueModulate(const aSrc, aDst: Single): Single;
  78. function tsBlendColorAlpha(const aSrc, aDst: TtsColor4f): TtsColor4f;
  79. function tsBlendColorAdditive(const aSrc, aDst: TtsColor4f): TtsColor4f;
  80. function tsBlendColorAdditiveAlpha(const aSrc, aDst: TtsColor4f): TtsColor4f;
  81. function tsStrAlloc(aSize: Cardinal): PWideChar;
  82. function tsStrNew(const aText: PWideChar): PWideChar;
  83. procedure tsStrDispose(const aText: PWideChar);
  84. function tsStrLength(aText: PWideChar): Cardinal;
  85. function tsStrCopy(aDst, aSrc: PWideChar): PWideChar;
  86. function tsAnsiToWide(aDst: PWideChar; const aSize: Integer; aSrc: PAnsiChar; const aCodePage: TtsCodePage; const aDefaultChar: WideChar): Integer;
  87. function tsISO_8859_1ToWide(aDst: PWideChar; const aSize: Integer; aSrc: PAnsiChar): Integer;
  88. function tsUTF8ToWide(aDst: PWideChar; const aSize: Integer; const aSrc: PAnsiChar; const aDefaultChar: WideChar): Integer;
  89. function tsUTFBE16ToWide(aDst: PWideChar; const aDstSize: Integer; aSrc: PByte; aSrcSize: Integer; const aDefaultChar: WideChar): Integer;
  90. function tsAnsiSBCDToWide(aDst: PWideChar; const aSize: Integer; aSrc: PAnsiChar; const aCodePage: TtsCodePage; const aDefaultChar: WideChar): Integer;
  91. implementation
  92. uses
  93. math,
  94. utsConstants;
  95. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  96. //TtsRefManager/////////////////////////////////////////////////////////////////////////////////////////////////////////
  97. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  98. procedure TtsRefManager.AddSlave(const aSlave: TtsRefManager);
  99. begin
  100. if Assigned(fSlaveRefs) then
  101. fSlaveRefs.Add(aSlave);
  102. end;
  103. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  104. function TtsRefManager.DelSlave(const aSlave: TtsRefManager): Boolean;
  105. begin
  106. result := false;
  107. if Assigned(fSlaveRefs) then
  108. result := (fSlaveRefs.Remove(aSlave) >= 0);
  109. end;
  110. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  111. constructor TtsRefManager.Create(const aMaster: TtsRefManager);
  112. begin
  113. inherited Create;
  114. fMasterRef := aMaster;
  115. fSlaveRefs := TObjectList.Create(false);
  116. if Assigned(fMasterRef) then
  117. fMasterRef.AddSlave(self);
  118. end;
  119. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  120. destructor TtsRefManager.Destroy;
  121. var
  122. m: TtsRefManager;
  123. begin
  124. fSlaveRefs.OwnsObjects := true;
  125. FreeAndNil(fSlaveRefs);
  126. m := fMasterRef;
  127. fMasterRef := nil;
  128. if Assigned(m) then
  129. m.DelSlave(self);
  130. inherited Destroy;
  131. end;
  132. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  133. //TtsMultiMasterRefManager//////////////////////////////////////////////////////////////////////////////////////////////
  134. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  135. procedure TtsMultiMasterRefManager.AddMaster(const aMaster: TtsRefManager);
  136. begin
  137. if Assigned(fMasterRefs) then begin
  138. fMasterRefs.Add(aMaster);
  139. aMaster.AddSlave(self);
  140. end;
  141. end;
  142. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  143. procedure TtsMultiMasterRefManager.DelMaster(const aMaster: TtsRefManager);
  144. begin
  145. if Assigned(fMasterRefs) then begin
  146. if (fMasterRefs.Remove(aMaster) >= 0) then
  147. aMaster.DelSlave(self);
  148. end;
  149. end;
  150. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  151. constructor TtsMultiMasterRefManager.Create(const aMaster: TtsRefManager);
  152. begin
  153. inherited Create(aMaster);
  154. fMasterRefs := TObjectList.Create(false);
  155. end;
  156. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  157. destructor TtsMultiMasterRefManager.Destroy;
  158. var
  159. i: Integer;
  160. begin
  161. for i := fMasterRefs.Count-1 downto 0 do
  162. DelMaster(fMasterRefs[i] as TtsRefManager);
  163. FreeAndNil(fMasterRefs);
  164. inherited Destroy;
  165. end;
  166. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  167. //Helper Methods////////////////////////////////////////////////////////////////////////////////////////////////////////
  168. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  169. function tsColor4f(r, g, b, a: Single): TtsColor4f;
  170. begin
  171. result.r := r;
  172. result.g := g;
  173. result.b := b;
  174. result.a := a;
  175. end;
  176. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  177. function tsPosition(const x, y: Integer): TtsPosition;
  178. begin
  179. result.x := x;
  180. result.y := y;
  181. end;
  182. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  183. function tsRect(const l, t, r, b: Integer): TtsRect;
  184. begin
  185. result.Left := l;
  186. result.Top := t;
  187. result.Right := r;
  188. result.Bottom := b;
  189. end;
  190. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  191. function tsRect(const aTopLeft, aBottomRight: TtsPosition): TtsRect;
  192. begin
  193. result.TopLeft := aTopLeft;
  194. result.BottomRight := aBottomRight;
  195. end;
  196. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  197. function tsVector4f(X, Y, Z, W: Single): TtsVector4f;
  198. begin
  199. result[0] := X;
  200. result[1] := Y;
  201. result[2] := Z;
  202. result[3] := W;
  203. end;
  204. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  205. function tsMatrix4f(X, Y, Z, P: TtsVector4f): TtsMatrix4f;
  206. begin
  207. result[0] := X;
  208. result[1] := Y;
  209. result[2] := Z;
  210. result[3] := P;
  211. end;
  212. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  213. function tsFormatSize(const aFormat: TtsFormat): Integer;
  214. begin
  215. case aFormat of
  216. tsFormatRGBA8: result := 4;
  217. tsFormatLumAlpha8: result := 2;
  218. tsFormatAlpha8: result := 1;
  219. tsFormatLum8: result := 1;
  220. else
  221. result := 0;
  222. end;
  223. end;
  224. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  225. procedure tsFormatMap(const aFormat: TtsFormat; var aData: PByte; const aColor: TtsColor4f);
  226. var
  227. i: Integer;
  228. s: Single;
  229. begin
  230. case aFormat of
  231. tsFormatRGBA8: begin
  232. for i := 0 to 3 do begin
  233. aData^ := Trunc($FF * min(aColor.arr[i], 1.0));
  234. inc(aData);
  235. end;
  236. end;
  237. tsFormatLumAlpha8: begin
  238. s := 0.30 * min(aColor.r, 1.0) +
  239. 0.59 * min(aColor.g, 1.0) +
  240. 0.11 * min(aColor.b, 1.0);
  241. aData^ := Trunc($FF * s);
  242. inc(aData);
  243. aData^ := Trunc($FF * min(aColor.a, 1.0));
  244. inc(aData);
  245. end;
  246. tsFormatAlpha8: begin
  247. aData^ := Trunc($FF * min(aColor.a, 1.0));
  248. inc(aData);
  249. end;
  250. tsFormatLum8: begin
  251. s := 0.30 * min(aColor.r, 1.0) +
  252. 0.59 * min(aColor.g, 1.0) +
  253. 0.11 * min(aColor.b, 1.0);
  254. aData^ := Trunc($FF * s);
  255. inc(aData);
  256. end;
  257. end;
  258. end;
  259. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  260. procedure tsFormatUnmap(const aFormat: TtsFormat; var aData: PByte; out aColor: TtsColor4f);
  261. var
  262. i: Integer;
  263. begin
  264. case aFormat of
  265. tsFormatRGBA8: begin
  266. for i := 0 to 3 do begin
  267. aColor.arr[i] := aData^ / $FF;
  268. inc(aData);
  269. end;
  270. end;
  271. tsFormatLumAlpha8: begin
  272. aColor.r := aData^ / $FF;
  273. aColor.g := aData^ / $FF;
  274. aColor.b := aData^ / $FF;
  275. inc(aData);
  276. aColor.a := aData^ / $FF;
  277. inc(aData);
  278. end;
  279. tsFormatAlpha8: begin
  280. aColor.r := 1.0;
  281. aColor.g := 1.0;
  282. aColor.b := 1.0;
  283. aColor.a := aData^ / $FF;
  284. inc(aData);
  285. end;
  286. tsFormatLum8: begin
  287. aColor.r := aData^ / $FF;
  288. aColor.g := aData^ / $FF;
  289. aColor.b := aData^ / $FF;
  290. aColor.a := 1.0;
  291. inc(aData);
  292. end;
  293. end;
  294. end;
  295. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  296. function tsBlendValueIgnore(const aSrc, aDst: Single): Single;
  297. begin
  298. result := aDst;
  299. end;
  300. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  301. function tsBlendValueReplace(const aSrc, aDst: Single): Single;
  302. begin
  303. result := aSrc;
  304. end;
  305. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  306. function tsBlendValueModulate(const aSrc, aDst: Single): Single;
  307. begin
  308. result := aSrc * aDst;
  309. end;
  310. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  311. function tsBlendColorAlpha(const aSrc, aDst: TtsColor4f): TtsColor4f;
  312. var
  313. i: Integer;
  314. begin
  315. for i := 0 to 2 do
  316. result.arr[i] := aSrc.arr[i] * aSrc.a + aDst.arr[i] * (1 - aSrc.a);
  317. result.a := aSrc.a + aDst.a * (1 - aSrc.a);
  318. end;
  319. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  320. function tsBlendColorAdditive(const aSrc, aDst: TtsColor4f): TtsColor4f;
  321. var
  322. i: Integer;
  323. begin
  324. for i := 0 to 3 do
  325. result.arr[i] := aSrc.arr[i] + aDst.arr[i];
  326. end;
  327. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  328. function tsBlendColorAdditiveAlpha(const aSrc, aDst: TtsColor4f): TtsColor4f;
  329. var
  330. i: Integer;
  331. begin
  332. for i := 0 to 2 do
  333. result.arr[i] := aSrc.arr[i] * aSrc.a + aDst.arr[i];
  334. result.a := aDst.a;
  335. end;
  336. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  337. function tsStrAlloc(aSize: Cardinal): PWideChar;
  338. begin
  339. aSize := (aSize + 1) shl 1;
  340. GetMem(result, aSize);
  341. FillChar(result^, aSize, 0);
  342. end;
  343. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  344. function tsStrNew(const aText: PWideChar): PWideChar;
  345. begin
  346. result := tsStrAlloc(tsStrLength(aText));
  347. tsStrCopy(result, aText);
  348. end;
  349. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  350. procedure tsStrDispose(const aText: PWideChar);
  351. begin
  352. FreeMem(aText);
  353. end;
  354. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  355. function tsStrLength(aText: PWideChar): Cardinal;
  356. begin
  357. result := 0;
  358. if Assigned(aText) then
  359. while (ord(aText^) <> 0) do begin
  360. inc(result);
  361. inc(aText);
  362. end;
  363. end;
  364. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  365. function tsStrCopy(aDst, aSrc: PWideChar): PWideChar;
  366. begin
  367. result := aDst;
  368. if Assigned(aDst) and Assigned(aSrc) then
  369. while ord(aSrc^) <> 0 do begin
  370. aDst^ := aSrc^;
  371. inc(aDst);
  372. inc(aSrc);
  373. end;
  374. end;
  375. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  376. function tsAnsiToWide(aDst: PWideChar; const aSize: Integer; aSrc: PAnsiChar;
  377. const aCodePage: TtsCodePage; const aDefaultChar: WideChar): Integer;
  378. begin
  379. case aCodePage of
  380. tsUTF8:
  381. result := tsUTF8ToWide(aDst, aSize, aSrc, aDefaultChar);
  382. tsISO_8859_1:
  383. result := tsISO_8859_1ToWide(aDst, aSize, aSrc);
  384. else
  385. result := tsAnsiSBCDToWide(aDst, aSize, aSrc, aCodePage, aDefaultChar);
  386. end;
  387. end;
  388. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  389. function tsISO_8859_1ToWide(aDst: PWideChar; const aSize: Integer; aSrc: PAnsiChar): Integer;
  390. begin
  391. result := 0;
  392. if Assigned(aDst) and Assigned(aSrc) then
  393. while (ord(aSrc^) <> 0) and (result < aSize) do begin
  394. aDst^ := WideChar(aSrc^);
  395. inc(aDst);
  396. inc(aSrc);
  397. inc(result);
  398. end;
  399. end;
  400. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  401. function tsUTF8ToWide(aDst: PWideChar; const aSize: Integer; const aSrc: PAnsiChar; const aDefaultChar: WideChar): Integer;
  402. procedure AddToDest(aCharCode: UInt64);
  403. begin
  404. if (aCharCode > $FFFF) then
  405. aCharCode := ord(aDefaultChar);
  406. PWord(aDst)^ := aCharCode;
  407. inc(aDst);
  408. result := result + 1;
  409. end;
  410. const
  411. STATE_STARTBYTE = 0;
  412. STATE_FOLLOWBYTE = 1;
  413. var
  414. cc: UInt64;
  415. len, state, c: Integer;
  416. p: PByte;
  417. tmp: Byte;
  418. begin
  419. result := 0;
  420. if not Assigned(aDst) or not Assigned(aSrc) or (aSize <= 0) then
  421. exit;
  422. c := 0;
  423. cc := 0;
  424. p := PByte(aSrc);
  425. len := Length(aSrc);
  426. state := STATE_STARTBYTE;
  427. while (len > 0) do begin
  428. case state of
  429. STATE_STARTBYTE: begin
  430. if (p^ and $80 = 0) then begin
  431. AddToDest(p^);
  432. end else if (p^ and $40 > 0) then begin
  433. tmp := p^;
  434. c := 0;
  435. while (tmp and $80) > 0 do begin
  436. inc(c);
  437. tmp := tmp shl 1;
  438. end;
  439. cc := p^ and ((1 shl (7 - c)) - 1);
  440. state := STATE_FOLLOWBYTE;
  441. c := c - 1;
  442. end;
  443. end;
  444. STATE_FOLLOWBYTE: begin
  445. if ((p^ and $C0) = $80) then begin
  446. cc := (cc shl 6) or (p^ and $3F);
  447. c := c - 1;
  448. if (c = 0) then begin
  449. AddToDest(cc);
  450. state := STATE_STARTBYTE;
  451. end;
  452. end else
  453. state := STATE_STARTBYTE;
  454. end;
  455. end;
  456. if (result >= aSize) then
  457. exit;
  458. inc(p);
  459. end;
  460. end;
  461. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  462. function tsUTFBE16ToWide(aDst: PWideChar; const aDstSize: Integer; aSrc: PByte; aSrcSize: Integer;
  463. const aDefaultChar: WideChar): Integer;
  464. var
  465. tmp: Word;
  466. procedure AddToDest(aCharCode: Word);
  467. begin
  468. if ((aCharCode and $D800) = $D800) or
  469. ((aCharCode and $DC00) = $DC00) then
  470. aCharCode := Ord(aDefaultChar);
  471. aDst^ := WideChar(aCharCode);
  472. inc(aDst, 1);
  473. result := result + 1;
  474. end;
  475. begin
  476. result := 0;
  477. while (aSrcSize > 1) and (aDstSize > 0) do begin
  478. {$IFDEF FPC}
  479. tmp := (aSrc^ shl 8) or (aSrc + 1)^;
  480. {$ELSE}
  481. tmp := (PByteArray(aSrc)[0] shl 8) or PByteArray(aSrc)[1];
  482. {$ENDIF}
  483. inc(aSrc, 2);
  484. dec(aSrcSize, 2);
  485. AddToDest(tmp);
  486. end;
  487. end;
  488. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  489. function tsAnsiSBCDToWide(aDst: PWideChar; const aSize: Integer; aSrc: PAnsiChar;
  490. const aCodePage: TtsCodePage; const aDefaultChar: WideChar): Integer;
  491. var
  492. tmp: WideChar;
  493. cp: PtsCodePageValues;
  494. begin
  495. result := 0;
  496. cp := TS_CODE_PAGE_LUT[aCodePage];
  497. if not Assigned(aDst) or
  498. not Assigned(aSrc) or
  499. not Assigned(cp) or
  500. (aSize < 0) then exit;
  501. while (Ord(aSrc^) <> 0) and (result < aSize) do begin
  502. tmp := WideChar(cp^[aSrc^]);
  503. if (ord(tmp) = 0) then begin
  504. if (ord(aDefaultChar) <> 0) then begin
  505. aDst^ := aDefaultChar;
  506. inc(aDst);
  507. end;
  508. end else begin
  509. aDst^ := tmp;
  510. inc(aDst);
  511. end;
  512. inc(aSrc);
  513. end;
  514. end;
  515. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  516. //TtsKernel1D///////////////////////////////////////////////////////////////////////////////////////////////////////////
  517. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  518. constructor TtsKernel1D.Create(const aRadius, aStrength: Single);
  519. var
  520. TempRadius, SQRRadius, TempStrength, TempValue: Double;
  521. Idx: Integer;
  522. function CalcValue(const aIndex: Integer): Single;
  523. var
  524. Temp: Double;
  525. begin
  526. Temp := Max(0, Abs(aIndex) - TempStrength);
  527. Temp := Sqr(Temp * TempRadius) / SQRRadius;
  528. result := Exp(-Temp);
  529. end;
  530. begin
  531. inherited Create;
  532. // calculate new radius and strength
  533. TempStrength := Min(aRadius - 1, aRadius * aStrength);
  534. TempRadius := aRadius - TempStrength;
  535. SQRRadius := sqr(TempRadius) * sqr(TempRadius);
  536. // caluculating size of the kernel
  537. Size := Round(TempRadius);
  538. while CalcValue(Size) > 0.001 do
  539. Inc(Size);
  540. Size := Size -1;
  541. ItemCount := Size * 2 +1;
  542. SetLength(Items, ItemCount);
  543. // calculate Value (yes thats right. there is no -1)
  544. for Idx := 0 to Size do begin
  545. TempValue := CalcValue(Idx);
  546. with Items[Size + Idx] do begin
  547. Offset := Idx;
  548. Value := TempValue;
  549. end;
  550. with Items[Size - Idx] do begin
  551. Offset := -Idx;
  552. Value := TempValue;
  553. end;
  554. end;
  555. end;
  556. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  557. //TtsKernel2D///////////////////////////////////////////////////////////////////////////////////////////////////////////
  558. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  559. constructor TtsKernel2D.Create(const aRadius, aStrength: Single);
  560. var
  561. tmpStrenght: Double;
  562. tmpRadius: Double;
  563. tmpValue: Double;
  564. sqrRadius: Double;
  565. x, y, w, h: Integer;
  566. function CalcValue(const aIndex: Double): Double;
  567. begin
  568. result := max(0, Abs(aIndex) - tmpStrenght);
  569. result := Sqr(result * tmpRadius) / sqrRadius;
  570. result := Exp(-result);
  571. end;
  572. procedure CalcSize(var aSize, aMidSize: Integer);
  573. begin
  574. aSize := 0;
  575. aMidSize := 0;
  576. while CalcValue(aSize) > 0.5 do begin
  577. inc(aSize, 1);
  578. inc(aMidSize, 1);
  579. end;
  580. while CalcValue(aSize) > 0.001 do
  581. Inc(aSize, 1);
  582. end;
  583. procedure SetItem(const x, y: Integer);
  584. begin
  585. with Items[(SizeY + y) * w + (SizeX + x)] do begin
  586. OffsetX := x;
  587. OffsetY := y;
  588. Value := tmpValue;
  589. end;
  590. end;
  591. procedure QuickSort(l, r: Integer);
  592. var
  593. _l, _r: Integer;
  594. p, t: TtsKernel2DItem;
  595. begin
  596. repeat
  597. _l := l;
  598. _r := r;
  599. p := Items[(l + r) shr 1];
  600. repeat
  601. while (Items[_l].Value > p.Value) do
  602. inc(_l, 1);
  603. while (Items[_r].Value < p.Value) do
  604. dec(_r, 1);
  605. if (_l <= _r) then begin
  606. t := Items[_l];
  607. Items[_l] := Items[_r];
  608. Items[_r] := t;
  609. inc(_l, 1);
  610. dec(_r, 1);
  611. end;
  612. until (_l > _r);
  613. if (l < _r) then
  614. QuickSort(l, _r);
  615. l := _l;
  616. until (_l >= r);
  617. end;
  618. begin
  619. inherited Create;
  620. tmpStrenght := Min(aRadius - 1.0, aRadius * aStrength);
  621. tmpRadius := aRadius - tmpStrenght;
  622. sqrRadius := sqr(tmpRadius) * sqr(tmpRadius);
  623. CalcSize(SizeX, MidSizeX);
  624. CalcSize(SizeY, MidSizeY);
  625. ValueSum := 0.0;
  626. w := 2 * SizeX + 1;
  627. h := 2 * SizeY + 1;
  628. ItemCount := w * h;
  629. SetLength(Items, ItemCount);
  630. for y := 0 to SizeY do begin
  631. for x := 0 to SizeX do begin
  632. tmpValue := CalcValue(sqrt(Sqr(x) + Sqr(y)));
  633. SetItem( x, y);
  634. SetItem( x, -y);
  635. SetItem(-x, -y);
  636. SetItem(-x, y);
  637. ValueSum := ValueSum + tmpValue;
  638. if (x > 0) and (y > 0) then
  639. ValueSum := ValueSum + tmpValue;
  640. end;
  641. end;
  642. QuickSort(0, ItemCount-1);
  643. while (Items[ItemCount-1].Value < 0.001) do
  644. dec(ItemCount, 1);
  645. SetLength(Items, ItemCount);
  646. end;
  647. end.