Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

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