No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

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