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.

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