GR32.Blend.Pascal.pas 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142
  1. unit GR32.Blend.Pascal;
  2. (* ***** BEGIN LICENSE BLOCK *****
  3. * Version: MPL 1.1 or LGPL 2.1 with linking exception
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. * http://www.mozilla.org/MPL/
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. *
  15. * Alternatively, the contents of this file may be used under the terms of the
  16. * Free Pascal modified version of the GNU Lesser General Public License
  17. * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
  18. * of this license are applicable instead of those above.
  19. * Please see the file LICENSE.txt for additional information concerning this
  20. * license.
  21. *
  22. * The Original Code is Graphics32
  23. *
  24. * The Initial Developer of the Original Code is
  25. * Alex A. Denisov
  26. *
  27. * Portions created by the Initial Developer are Copyright (C) 2000-2009
  28. * the Initial Developer. All Rights Reserved.
  29. *
  30. * ***** END LICENSE BLOCK ***** *)
  31. interface
  32. {$include GR32.inc}
  33. uses
  34. GR32;
  35. //------------------------------------------------------------------------------
  36. //
  37. // PUREPASCAL blend implementations
  38. //
  39. //------------------------------------------------------------------------------
  40. //------------------------------------------------------------------------------
  41. // Blend
  42. //------------------------------------------------------------------------------
  43. function BlendReg_Pas(F, B: TColor32): TColor32;
  44. procedure BlendMem_Pas(F: TColor32; var B: TColor32);
  45. procedure BlendMems_Pas(F: TColor32; B: PColor32; Count: Integer);
  46. function BlendRegEx_Pas(F, B: TColor32; M: Cardinal): TColor32;
  47. procedure BlendMemEx_Pas(F: TColor32; var B: TColor32; M: Cardinal);
  48. function BlendRegRGB_Pas(F, B: TColor32; W: Cardinal): TColor32;
  49. procedure BlendMemRGB_Pas(F: TColor32; var B: TColor32; W: Cardinal);
  50. procedure BlendLine_Pas(Src, Dst: PColor32; Count: Integer);
  51. procedure BlendLineEx_Pas(Src, Dst: PColor32; Count: Integer; M: Cardinal);
  52. //------------------------------------------------------------------------------
  53. // Merge
  54. //------------------------------------------------------------------------------
  55. // Note that all Merge functions, except MergeReg_pas, are implemented so they
  56. // call MergeReg to perform the actual merge operation. Because of this the
  57. // functions will benefit from ASM, MMX, SSE2, etc. implementations of MergeReg
  58. // ensures that the rest of the library also does so.
  59. //------------------------------------------------------------------------------
  60. function MergeReg_Pas(F, B: TColor32): TColor32;
  61. function MergeRegEx_Pas(F, B: TColor32; M: Cardinal): TColor32;
  62. procedure MergeMem_Pas(F: TColor32; var B: TColor32);
  63. procedure MergeMems_Pas(F: TColor32; B: PColor32; Count: Integer);
  64. procedure MergeMemEx_Pas(F: TColor32; var B: TColor32; M: Cardinal);
  65. procedure MergeLine_Pas(Src, Dst: PColor32; Count: Integer);
  66. procedure MergeLineEx_Pas(Src, Dst: PColor32; Count: Integer; M: Cardinal);
  67. //------------------------------------------------------------------------------
  68. // Combine
  69. //------------------------------------------------------------------------------
  70. function CombineReg_Pas(X, Y: TColor32; W: Cardinal): TColor32;
  71. procedure CombineMem_Pas_Table(X: TColor32; var Y: TColor32; W: Cardinal);
  72. procedure CombineMem_Pas_Div255(X: TColor32; var Y: TColor32; W: Cardinal);
  73. procedure CombineMem_Pas_Retro(X: TColor32; var Y: TColor32; W: Cardinal);
  74. procedure CombineLine_Pas(Src, Dst: PColor32; Count: Integer; W: Cardinal);
  75. //------------------------------------------------------------------------------
  76. // Color algebra
  77. //------------------------------------------------------------------------------
  78. function ColorAdd_Pas(C1, C2: TColor32): TColor32;
  79. function ColorSub_Pas(C1, C2: TColor32): TColor32;
  80. function ColorDiv_Pas(C1, C2: TColor32): TColor32;
  81. function ColorModulate_Pas(C1, C2: TColor32): TColor32;
  82. function ColorMax_Pas(C1, C2: TColor32): TColor32;
  83. function ColorMin_Pas(C1, C2: TColor32): TColor32;
  84. function ColorDifference_Pas(C1, C2: TColor32): TColor32;
  85. function ColorExclusion_Pas(C1, C2: TColor32): TColor32;
  86. function ColorAverage_Pas(C1, C2: TColor32): TColor32;
  87. function ColorScale_Pas(C: TColor32; W: Cardinal): TColor32;
  88. function ColorScreen_Pas(B, S: TColor32): TColor32;
  89. function ColorDodge_Pas(B, S: TColor32): TColor32;
  90. function ColorBurn_Pas(B, S: TColor32): TColor32;
  91. //------------------------------------------------------------------------------
  92. // Blended color algebra
  93. //------------------------------------------------------------------------------
  94. function BlendColorAdd_Pas(C1, C2: TColor32): TColor32;
  95. function BlendColorModulate_Pas(C1, C2: TColor32): TColor32;
  96. //------------------------------------------------------------------------------
  97. // Misc
  98. //------------------------------------------------------------------------------
  99. function LightenReg_Pas(C: TColor32; Amount: Integer): TColor32;
  100. procedure ScaleMems_Pas(Dst: PColor32; Count: Integer; Weight: Cardinal);
  101. //------------------------------------------------------------------------------
  102. //------------------------------------------------------------------------------
  103. //------------------------------------------------------------------------------
  104. implementation
  105. uses
  106. SysUtils,
  107. GR32_Blend,
  108. GR32_Bindings,
  109. GR32_LowLevel;
  110. //------------------------------------------------------------------------------
  111. //
  112. // Blend
  113. //
  114. //------------------------------------------------------------------------------
  115. //------------------------------------------------------------------------------
  116. // BlendReg
  117. //------------------------------------------------------------------------------
  118. function BlendReg_Pas(F, B: TColor32): TColor32;
  119. var
  120. FX: TColor32Entry absolute F;
  121. BX: TColor32Entry absolute B;
  122. Af, Ab: PByteArray;
  123. FA : Byte;
  124. begin
  125. FA := FX.A;
  126. if FA = 0 then
  127. begin
  128. Result := B;
  129. Exit;
  130. end;
  131. if FA = $FF then
  132. begin
  133. Result := F;
  134. Exit;
  135. end;
  136. Af := @MulDiv255Table[FA];
  137. Ab := @MulDiv255Table[not FA];
  138. with BX do
  139. begin
  140. R := Af[FX.R] + Ab[R];
  141. G := Af[FX.G] + Ab[G];
  142. B := Af[FX.B] + Ab[B];
  143. A := $FF;
  144. end;
  145. Result := B;
  146. end;
  147. //------------------------------------------------------------------------------
  148. // BlendMem
  149. //------------------------------------------------------------------------------
  150. procedure BlendMem_Pas(F: TColor32; var B: TColor32);
  151. var
  152. FX: TColor32Entry absolute F;
  153. BX: TColor32Entry absolute B;
  154. Af, Ab: PByteArray;
  155. FA : Byte;
  156. begin
  157. FA := FX.A;
  158. if FA = 0 then Exit;
  159. if FA = $FF then
  160. begin
  161. B := F;
  162. Exit;
  163. end;
  164. Af := @MulDiv255Table[FA];
  165. Ab := @MulDiv255Table[not FA];
  166. with BX do
  167. begin
  168. R := Af[FX.R] + Ab[R];
  169. G := Af[FX.G] + Ab[G];
  170. B := Af[FX.B] + Ab[B];
  171. A := $FF;
  172. end;
  173. end;
  174. //------------------------------------------------------------------------------
  175. // BlendMems
  176. //------------------------------------------------------------------------------
  177. procedure BlendMems_Pas(F: TColor32; B: PColor32; Count: Integer);
  178. begin
  179. while Count > 0 do
  180. begin
  181. BlendMem(F, B^);
  182. Inc(B);
  183. Dec(Count);
  184. end;
  185. end;
  186. //------------------------------------------------------------------------------
  187. // BlendRegEx
  188. //------------------------------------------------------------------------------
  189. function BlendRegEx_Pas(F, B: TColor32; M: Cardinal): TColor32;
  190. var
  191. FX: TColor32Entry absolute F;
  192. BX: TColor32Entry absolute B;
  193. Af, Ab: PByteArray;
  194. begin
  195. Af := @MulDiv255Table[M];
  196. M := Af[FX.A];
  197. if (M = 0) then
  198. begin
  199. Result := B;
  200. Exit;
  201. end;
  202. if (M = $FF) then
  203. begin
  204. Result := F;
  205. Exit;
  206. end;
  207. Af := @MulDiv255Table[M];
  208. Ab := @MulDiv255Table[255 - M];
  209. TColor32Entry(Result).R := Af[FX.R] + Ab[BX.R];
  210. TColor32Entry(Result).G := Af[FX.G] + Ab[BX.G];
  211. TColor32Entry(Result).B := Af[FX.B] + Ab[BX.B];
  212. TColor32Entry(Result).A := $FF;
  213. end;
  214. //------------------------------------------------------------------------------
  215. // BlendMemEx
  216. //------------------------------------------------------------------------------
  217. procedure BlendMemEx_Pas(F: TColor32; var B: TColor32; M: Cardinal);
  218. var
  219. FX: TColor32Entry absolute F;
  220. BX: TColor32Entry absolute B;
  221. Af, Ab: PByteArray;
  222. begin
  223. Af := @MulDiv255Table[M];
  224. M := Af[FX.A]; // M = (M / 255) * (FX.A / 255)
  225. if (M = 0) then
  226. Exit;
  227. if (M = $FF) then
  228. begin
  229. B := F;
  230. Exit;
  231. end;
  232. Af := @MulDiv255Table[M];
  233. Ab := @MulDiv255Table[255 - M];
  234. BX.R := Af[FX.R] + Ab[BX.R];
  235. BX.G := Af[FX.G] + Ab[BX.G];
  236. BX.B := Af[FX.B] + Ab[BX.B];
  237. BX.A := $FF;
  238. end;
  239. //------------------------------------------------------------------------------
  240. // BlendRegRGB
  241. //------------------------------------------------------------------------------
  242. function BlendRegRGB_Pas(F, B: TColor32; W: Cardinal): TColor32;
  243. var
  244. FX: TColor32Entry absolute F;
  245. BX: TColor32Entry absolute B;
  246. WX: TColor32Entry absolute W;
  247. RX: TColor32Entry absolute Result;
  248. begin
  249. if (W = 0) then
  250. Result := B
  251. else
  252. if (W = $FF) then
  253. Result := F
  254. else
  255. begin
  256. RX.R := (FX.R - BX.R) * WX.B div 255 + BX.R;
  257. RX.G := (FX.G - BX.G) * WX.G div 255 + BX.G;
  258. RX.B := (FX.B - BX.B) * WX.R div 255 + BX.B;
  259. end;
  260. end;
  261. //------------------------------------------------------------------------------
  262. // BlendMemRGB
  263. //------------------------------------------------------------------------------
  264. procedure BlendMemRGB_Pas(F: TColor32; var B: TColor32; W: Cardinal);
  265. var
  266. FX: TColor32Entry absolute F;
  267. BX: TColor32Entry absolute B;
  268. WX: TColor32Entry absolute W;
  269. begin
  270. if (W = 0) then
  271. exit;
  272. if ((W and $FFFFFF) = $FFFFFF) then
  273. B := F
  274. else
  275. begin
  276. BX.R := (FX.R - BX.R) * WX.B div 255 + BX.R;
  277. BX.G := (FX.G - BX.G) * WX.G div 255 + BX.G;
  278. BX.B := (FX.B - BX.B) * WX.R div 255 + BX.B;
  279. end;
  280. end;
  281. //------------------------------------------------------------------------------
  282. // BlendLine
  283. //------------------------------------------------------------------------------
  284. procedure BlendLine_Pas(Src, Dst: PColor32; Count: Integer);
  285. begin
  286. while Count > 0 do
  287. begin
  288. BlendMem(Src^, Dst^);
  289. Inc(Src);
  290. Inc(Dst);
  291. Dec(Count);
  292. end;
  293. end;
  294. //------------------------------------------------------------------------------
  295. // BlendLineEx
  296. //------------------------------------------------------------------------------
  297. procedure BlendLineEx_Pas(Src, Dst: PColor32; Count: Integer; M: Cardinal);
  298. begin
  299. if (M = 0) then
  300. exit;
  301. while Count > 0 do
  302. begin
  303. BlendMemEx(Src^, Dst^, M);
  304. Inc(Src);
  305. Inc(Dst);
  306. Dec(Count);
  307. end;
  308. end;
  309. //------------------------------------------------------------------------------
  310. // CombineReg
  311. //------------------------------------------------------------------------------
  312. function CombineReg_Pas(X, Y: TColor32; W: Cardinal): TColor32;
  313. var
  314. Xe: TColor32Entry absolute X;
  315. Ye: TColor32Entry absolute Y;
  316. Af, Ab: PByteArray;
  317. begin
  318. if W = 0 then
  319. begin
  320. Result := Y;
  321. Exit;
  322. end;
  323. if W >= $FF then
  324. begin
  325. Result := X;
  326. Exit;
  327. end;
  328. Af := @MulDiv255Table[W];
  329. Ab := @MulDiv255Table[255 - W];
  330. with Xe do
  331. begin
  332. R := Ab[Ye.R] + Af[R];
  333. G := Ab[Ye.G] + Af[G];
  334. B := Ab[Ye.B] + Af[B];
  335. A := Ab[Ye.A] + Af[A];
  336. end;
  337. Result := X;
  338. end;
  339. //------------------------------------------------------------------------------
  340. //
  341. // Combine
  342. //
  343. //------------------------------------------------------------------------------
  344. //------------------------------------------------------------------------------
  345. // CombineMem
  346. //------------------------------------------------------------------------------
  347. procedure CombineMem_Pas_Table(X: TColor32; var Y: TColor32; W: Cardinal);
  348. (*
  349. TestCombineMem:
  350. Errors: 32.364 = 24,7 % (Limit: -1)
  351. Differences: 129.456
  352. Average difference: 0,00
  353. Max difference: 1 (Limit: 1)
  354. *)
  355. var
  356. Xe: TColor32Entry absolute X;
  357. Ye: TColor32Entry absolute Y;
  358. Af, Ab: PByteArray;
  359. begin
  360. if W = 0 then
  361. Exit;
  362. if W >= $FF then
  363. begin
  364. Y := X;
  365. Exit;
  366. end;
  367. Af := @MulDiv255Table[W];
  368. Ab := @MulDiv255Table[255 - W];
  369. with Xe do
  370. begin
  371. R := Ab[Ye.R] + Af[R];
  372. G := Ab[Ye.G] + Af[G];
  373. B := Ab[Ye.B] + Af[B];
  374. A := Ab[Ye.A] + Af[A];
  375. end;
  376. Y := X;
  377. end;
  378. //------------------------------------------------------------------------------
  379. procedure CombineMem_Pas_Div255(X: TColor32; var Y: TColor32; W: Cardinal);
  380. (*
  381. Contributed by: Anders Melander
  382. TestCombineMem:
  383. Errors: 56.170 (42,8 %)
  384. Differences: 95.152
  385. Average difference: -1,00
  386. Max error:1
  387. *)
  388. var
  389. Xe: TColor32Entry absolute X;
  390. Ye: TColor32Entry absolute Y;
  391. begin
  392. if W = 0 then
  393. Exit;
  394. if W >= $FF then
  395. begin
  396. Y := X;
  397. Exit;
  398. end;
  399. //
  400. // Magic number division using:
  401. //
  402. // a*b/255 = (a * b * $8081) shr 23
  403. //
  404. // Applied to:
  405. //
  406. // Result := W * (X - Y) + Y
  407. //
  408. // The Div255 function already uses the above method so
  409. // we can just use that directly:
  410. Ye.A := Div255(SmallInt(W) * (Xe.A - Ye.A)) + Ye.A;
  411. Ye.B := Div255(SmallInt(W) * (Xe.B - Ye.B)) + Ye.B;
  412. Ye.G := Div255(SmallInt(W) * (Xe.G - Ye.G)) + Ye.G;
  413. Ye.R := Div255(SmallInt(W) * (Xe.R - Ye.R)) + Ye.R;
  414. end;
  415. //------------------------------------------------------------------------------
  416. procedure CombineMem_Pas_Retro(X: TColor32; var Y: TColor32; W: Cardinal);
  417. (*
  418. Contributed by: Anders Melander
  419. Uses the "Double-blend" technique.
  420. Much faster than CombineMem_Pas_Table but not as precise.
  421. TestCombineMem:
  422. Errors: 55.769 (42,5 %)
  423. Differences: 95.884
  424. Average difference: -1,00
  425. Max error:1
  426. *)
  427. const
  428. MaskAG = $FF00FF00;
  429. MaskRB = $00FF00FF;
  430. FixedOne = 1 shl 8; // 1.0 in 1:8 fixed point = base 256
  431. var
  432. FixedWeight: Word;
  433. Xag, Yag: TColor32;
  434. Xrb, Yrb: TColor32;
  435. ag, rb: TColor32;
  436. begin
  437. if W = 0 then
  438. Exit;
  439. if W >= $FF then
  440. begin
  441. Y := X;
  442. Exit;
  443. end;
  444. // [0..255] -> [0..256]
  445. // FixedWeight := Round(W * FixedOne / 255);
  446. FixedWeight := Div255Round(W * FixedOne);
  447. Xag := (X and MaskAG) shr 8;
  448. Yag := (Y and MaskAG) shr 8;
  449. Xrb := (X and MaskRB);
  450. Yrb := (Y and MaskRB);
  451. // Unsigned multiplication of signed value. Works out because of 2's complement. No worries.
  452. ag := Cardinal(Integer(Xag - Yag) * FixedWeight) shr 8;
  453. rb := Cardinal(Integer(Xrb - Yrb) * FixedWeight) shr 8;
  454. ag := ((ag + Yag) shl 8) and MaskAG;
  455. rb := ((rb + Yrb) ) and MaskRB;
  456. Y := (ag or rb);
  457. end;
  458. //------------------------------------------------------------------------------
  459. // CombineLine
  460. //------------------------------------------------------------------------------
  461. procedure CombineLine_Pas(Src, Dst: PColor32; Count: Integer; W: Cardinal);
  462. begin
  463. if W = 0 then
  464. Exit;
  465. if W >= $FF then
  466. begin
  467. MoveLongword(Src^, Dst^, Count);
  468. Exit;
  469. end;
  470. while Count > 0 do
  471. begin
  472. CombineMem(Src^, Dst^, W);
  473. Inc(Src);
  474. Inc(Dst);
  475. Dec(Count);
  476. end;
  477. end;
  478. //------------------------------------------------------------------------------
  479. //
  480. // Merge
  481. //
  482. //------------------------------------------------------------------------------
  483. //------------------------------------------------------------------------------
  484. // MergeReg
  485. //------------------------------------------------------------------------------
  486. function MergeReg_Pas(F, B: TColor32): TColor32;
  487. var
  488. Fa, Ba, Wa: TColor32;
  489. Fw, Bw: PByteArray;
  490. Fx: TColor32Entry absolute F;
  491. Bx: TColor32Entry absolute B;
  492. Rx: TColor32Entry absolute Result;
  493. begin
  494. Fa := F shr 24;
  495. Ba := B shr 24;
  496. if Fa = $FF then
  497. Result := F
  498. else if Fa = $0 then
  499. Result := B
  500. else if Ba = $0 then
  501. Result := F
  502. else
  503. begin
  504. Rx.A := not MulDiv255Table[Fa xor 255, Ba xor 255]; // "xor 255" is faster than "not" for the indices because the asm is shorter
  505. Wa := DivMul255Table[Rx.A, Fa];
  506. Fw := @MulDiv255Table[Wa];
  507. Bw := @MulDiv255Table[Wa xor $FF];
  508. Rx.R := Fw[Fx.R] + Bw[Bx.R];
  509. Rx.G := Fw[Fx.G] + Bw[Bx.G];
  510. Rx.B := Fw[Fx.B] + Bw[Bx.B];
  511. end;
  512. end;
  513. //------------------------------------------------------------------------------
  514. // MergeRegEx
  515. //------------------------------------------------------------------------------
  516. function MergeRegEx_Pas(F, B: TColor32; M: Cardinal): TColor32;
  517. begin
  518. Result := MergeReg(MulDiv255Table[M, F shr 24] shl 24 or F and $00FFFFFF, B);
  519. end;
  520. //------------------------------------------------------------------------------
  521. // MergeMem
  522. //------------------------------------------------------------------------------
  523. procedure MergeMem_Pas(F: TColor32; var B: TColor32);
  524. begin
  525. B := MergeReg(F, B);
  526. end;
  527. //------------------------------------------------------------------------------
  528. // MergeMemEx
  529. //------------------------------------------------------------------------------
  530. procedure MergeMemEx_Pas(F: TColor32; var B: TColor32; M: Cardinal);
  531. begin
  532. B := MergeReg(MulDiv255Table[M, F shr 24] shl 24 or F and $00FFFFFF, B);
  533. end;
  534. //------------------------------------------------------------------------------
  535. // MergeMems
  536. //------------------------------------------------------------------------------
  537. procedure MergeMems_Pas(F: TColor32; B: PColor32; Count: Integer);
  538. begin
  539. while Count > 0 do
  540. begin
  541. B^ := MergeReg(F, B^);
  542. Inc(B);
  543. Dec(Count);
  544. end;
  545. end;
  546. //------------------------------------------------------------------------------
  547. // MergeLine
  548. //------------------------------------------------------------------------------
  549. procedure MergeLine_Pas(Src, Dst: PColor32; Count: Integer);
  550. begin
  551. while Count > 0 do
  552. begin
  553. Dst^ := MergeReg(Src^, Dst^);
  554. Inc(Src);
  555. Inc(Dst);
  556. Dec(Count);
  557. end;
  558. end;
  559. //------------------------------------------------------------------------------
  560. // MergeLineEx
  561. //------------------------------------------------------------------------------
  562. procedure MergeLineEx_Pas(Src, Dst: PColor32; Count: Integer; M: Cardinal);
  563. var
  564. PM: PByteArray;
  565. begin
  566. PM := @MulDiv255Table[M];
  567. while Count > 0 do
  568. begin
  569. Dst^ := MergeReg((PM[Src^ shr 24] shl 24) or (Src^ and $00FFFFFF), Dst^);
  570. Inc(Src);
  571. Inc(Dst);
  572. Dec(Count);
  573. end;
  574. end;
  575. //------------------------------------------------------------------------------
  576. //
  577. // Color algebra
  578. //
  579. //------------------------------------------------------------------------------
  580. //------------------------------------------------------------------------------
  581. // ColorAdd
  582. //------------------------------------------------------------------------------
  583. function ColorAdd_Pas(C1, C2: TColor32): TColor32;
  584. var
  585. Xe: TColor32Entry absolute C1;
  586. Ye: TColor32Entry absolute C2;
  587. R: TColor32Entry absolute Result;
  588. begin
  589. R.A := Clamp(Xe.A + Ye.A, 255);
  590. R.R := Clamp(Xe.R + Ye.R, 255);
  591. R.G := Clamp(Xe.G + Ye.G, 255);
  592. R.B := Clamp(Xe.B + Ye.B, 255);
  593. end;
  594. //------------------------------------------------------------------------------
  595. // ColorSub
  596. //------------------------------------------------------------------------------
  597. function ColorSub_Pas(C1, C2: TColor32): TColor32;
  598. var
  599. Xe: TColor32Entry absolute C1;
  600. Ye: TColor32Entry absolute C2;
  601. R: TColor32Entry absolute Result;
  602. Temp: SmallInt;
  603. begin
  604. Temp := Xe.A - Ye.A;
  605. if Temp < 0 then
  606. R.A := 0
  607. else
  608. R.A := Temp;
  609. Temp := Xe.R - Ye.R;
  610. if Temp < 0 then
  611. R.R := 0
  612. else
  613. R.R := Temp;
  614. Temp := Xe.G - Ye.G;
  615. if Temp < 0 then
  616. R.G := 0
  617. else
  618. R.G := Temp;
  619. Temp := Xe.B - Ye.B;
  620. if Temp < 0 then
  621. R.B := 0
  622. else
  623. R.B := Temp;
  624. end;
  625. //------------------------------------------------------------------------------
  626. // ColorDiv
  627. //------------------------------------------------------------------------------
  628. function ColorDiv_Pas(C1, C2: TColor32): TColor32;
  629. var
  630. C1e: TColor32Entry absolute C1;
  631. C2e: TColor32Entry absolute C2;
  632. Re: TColor32Entry absolute Result;
  633. Temp: Word;
  634. begin
  635. if C1e.A = 0 then
  636. Re.A := $FF
  637. else
  638. begin
  639. Temp := (C2e.A shl 8) div C1e.A;
  640. if Temp > $FF then
  641. Re.A := $FF
  642. else
  643. Re.A := Temp;
  644. end;
  645. if C1e.R = 0 then
  646. Re.R := $FF
  647. else
  648. begin
  649. Temp := (C2e.R shl 8) div C1e.R;
  650. if Temp > $FF then
  651. Re.R := $FF
  652. else
  653. Re.R := Temp;
  654. end;
  655. if C1e.G = 0 then
  656. Re.G := $FF
  657. else
  658. begin
  659. Temp := (C2e.G shl 8) div C1e.G;
  660. if Temp > $FF then
  661. Re.G := $FF
  662. else
  663. Re.G := Temp;
  664. end;
  665. if C1e.B = 0 then
  666. Re.B := $FF
  667. else
  668. begin
  669. Temp := (C2e.B shl 8) div C1e.B;
  670. if Temp > $FF then
  671. Re.B := $FF
  672. else
  673. Re.B := Temp;
  674. end;
  675. end;
  676. //------------------------------------------------------------------------------
  677. // ColorModulate
  678. //------------------------------------------------------------------------------
  679. function ColorModulate_Pas(C1, C2: TColor32): TColor32;
  680. var
  681. C1e: TColor32Entry absolute C1;
  682. C2e: TColor32Entry absolute C2;
  683. Re: TColor32Entry absolute Result;
  684. begin
  685. Re.A := (C2e.A * C1e.A + $80) shr 8;
  686. Re.R := (C2e.R * C1e.R + $80) shr 8;
  687. Re.G := (C2e.G * C1e.G + $80) shr 8;
  688. Re.B := (C2e.B * C1e.B + $80) shr 8;
  689. end;
  690. //------------------------------------------------------------------------------
  691. // ColorMax
  692. //------------------------------------------------------------------------------
  693. function ColorMax_Pas(C1, C2: TColor32): TColor32;
  694. var
  695. REnt: TColor32Entry absolute Result;
  696. C2Ent: TColor32Entry absolute C2;
  697. begin
  698. Result := C1;
  699. with C2Ent do
  700. begin
  701. if A > REnt.A then REnt.A := A;
  702. if R > REnt.R then REnt.R := R;
  703. if G > REnt.G then REnt.G := G;
  704. if B > REnt.B then REnt.B := B;
  705. end;
  706. end;
  707. //------------------------------------------------------------------------------
  708. // ColorMin
  709. //------------------------------------------------------------------------------
  710. function ColorMin_Pas(C1, C2: TColor32): TColor32;
  711. var
  712. REnt: TColor32Entry absolute Result;
  713. C2Ent: TColor32Entry absolute C2;
  714. begin
  715. Result := C1;
  716. with C2Ent do
  717. begin
  718. if A < REnt.A then REnt.A := A;
  719. if R < REnt.R then REnt.R := R;
  720. if G < REnt.G then REnt.G := G;
  721. if B < REnt.B then REnt.B := B;
  722. end;
  723. end;
  724. //------------------------------------------------------------------------------
  725. // ColorDifference
  726. //------------------------------------------------------------------------------
  727. function ColorDifference_Pas(C1, C2: TColor32): TColor32;
  728. var
  729. Xe: TColor32Entry absolute C1;
  730. Ye: TColor32Entry absolute C2;
  731. R: TColor32Entry absolute Result;
  732. begin
  733. R.A := Abs(Xe.A - Ye.A);
  734. R.R := Abs(Xe.R - Ye.R);
  735. R.G := Abs(Xe.G - Ye.G);
  736. R.B := Abs(Xe.B - Ye.B);
  737. end;
  738. //------------------------------------------------------------------------------
  739. // ColorDifference
  740. //------------------------------------------------------------------------------
  741. function ColorExclusion_Pas(C1, C2: TColor32): TColor32;
  742. var
  743. Xe: TColor32Entry absolute C1;
  744. Ye: TColor32Entry absolute C2;
  745. R: TColor32Entry absolute Result;
  746. begin
  747. R.A := Xe.A + Ye.A - ((Xe.A * Ye.A) shl 7);
  748. R.R := Xe.R + Ye.R - ((Xe.R * Ye.R) shr 7);
  749. R.G := Xe.G + Ye.G - ((Xe.G * Ye.G) shr 7);
  750. R.B := Xe.B + Ye.B - ((Xe.B * Ye.B) shr 7);
  751. end;
  752. //------------------------------------------------------------------------------
  753. // ColorAverage
  754. //------------------------------------------------------------------------------
  755. function ColorAverage_Pas(C1, C2: TColor32): TColor32;
  756. //(A + B)/2 = (A and B) + (A xor B)/2
  757. var
  758. C3 : TColor32;
  759. begin
  760. C3 := C1;
  761. C1 := C1 xor C2;
  762. C1 := C1 shr 1;
  763. C1 := C1 and $7F7F7F7F;
  764. C3 := C3 and C2;
  765. Result := C3 + C1;
  766. end;
  767. //------------------------------------------------------------------------------
  768. // ColorScale
  769. //------------------------------------------------------------------------------
  770. function ColorScale_Pas(C: TColor32; W: Cardinal): TColor32;
  771. var
  772. Ce: TColor32Entry absolute C;
  773. var
  774. r1, g1, b1, a1: Cardinal;
  775. begin
  776. a1 := Ce.A * W shr 8;
  777. r1 := Ce.R * W shr 8;
  778. g1 := Ce.G * W shr 8;
  779. b1 := Ce.B * W shr 8;
  780. if a1 > 255 then a1 := 255;
  781. if r1 > 255 then r1 := 255;
  782. if g1 > 255 then g1 := 255;
  783. if b1 > 255 then b1 := 255;
  784. Result := a1 shl 24 + r1 shl 16 + g1 shl 8 + b1;
  785. end;
  786. //------------------------------------------------------------------------------
  787. // ColorScreen
  788. //------------------------------------------------------------------------------
  789. function ColorScreen_Pas(B, S: TColor32): TColor32;
  790. var
  791. Be: TColor32Entry absolute B;
  792. Se: TColor32Entry absolute S;
  793. R: TColor32Entry absolute Result;
  794. begin
  795. R.A := Be.A + Se.A - (Be.A * Se.A) div 255;
  796. R.R := Be.R + Se.R - (Be.R * Se.R) div 255;
  797. R.G := Be.G + Se.G - (Be.G * Se.G) div 255;
  798. R.B := Be.B + Se.B - (Be.B * Se.B) div 255;
  799. end;
  800. //------------------------------------------------------------------------------
  801. // ColorDodge
  802. //------------------------------------------------------------------------------
  803. function ColorDodge_Pas(B, S: TColor32): TColor32;
  804. function Dodge(B, S: Byte): Byte;
  805. begin
  806. if B = 0 then
  807. Result := 0
  808. else
  809. if S = 255 then
  810. Result := 255
  811. else
  812. Result := Clamp((255 * B) div (255 - S), 255);
  813. end;
  814. var
  815. Be: TColor32Entry absolute B;
  816. Se: TColor32Entry absolute S;
  817. R: TColor32Entry absolute Result;
  818. begin
  819. R.A := Dodge(Be.A, Se.A);
  820. R.R := Dodge(Be.R, Se.R);
  821. R.G := Dodge(Be.G, Se.G);
  822. R.B := Dodge(Be.B, Se.B);
  823. end;
  824. //------------------------------------------------------------------------------
  825. // ColorBurn
  826. //------------------------------------------------------------------------------
  827. function ColorBurn_Pas(B, S: TColor32): TColor32;
  828. function Burn(B, S: Byte): Byte;
  829. begin
  830. if B = 255 then
  831. Result := 255
  832. else
  833. if S = 0 then
  834. Result := 0
  835. else
  836. Result := 255 - Clamp(255 * (255 - B) div S, 255);
  837. end;
  838. var
  839. Be: TColor32Entry absolute B;
  840. Se: TColor32Entry absolute S;
  841. R: TColor32Entry absolute Result;
  842. begin
  843. R.A := Burn(Be.A, Se.A);
  844. R.R := Burn(Be.R, Se.R);
  845. R.G := Burn(Be.G, Se.G);
  846. R.B := Burn(Be.B, Se.B);
  847. end;
  848. //------------------------------------------------------------------------------
  849. //
  850. // Blended color algebra
  851. //
  852. //------------------------------------------------------------------------------
  853. //------------------------------------------------------------------------------
  854. // BlendColorAdd
  855. //------------------------------------------------------------------------------
  856. function BlendColorAdd_Pas(C1, C2: TColor32): TColor32;
  857. var
  858. Xe: TColor32Entry absolute C1;
  859. Ye: TColor32Entry absolute C2;
  860. R: TColor32Entry absolute Result;
  861. Af, Ab: PByteArray;
  862. begin
  863. Af := @MulDiv255Table[Xe.A];
  864. Ab := @MulDiv255Table[not Xe.A];
  865. R.A := Af[Clamp(Xe.A + Ye.A, 255)] + Ab[Ye.A];
  866. R.R := Af[Clamp(Xe.R + Ye.R, 255)] + Ab[Ye.R];
  867. R.G := Af[Clamp(Xe.G + Ye.G, 255)] + Ab[Ye.G];
  868. R.B := Af[Clamp(Xe.B + Ye.B, 255)] + Ab[Ye.B];
  869. end;
  870. //------------------------------------------------------------------------------
  871. // BlendColorModulate
  872. //------------------------------------------------------------------------------
  873. function BlendColorModulate_Pas(C1, C2: TColor32): TColor32;
  874. var
  875. C1e: TColor32Entry absolute C1;
  876. C2e: TColor32Entry absolute C2;
  877. R: TColor32Entry absolute Result;
  878. Af, Ab: PByteArray;
  879. begin
  880. Af := @MulDiv255Table[C1e.A];
  881. Ab := @MulDiv255Table[not C1e.A];
  882. R.A := Af[(C2e.A * C1e.A + $80) shr 8] + Ab[C2e.A];
  883. R.R := Af[(C2e.R * C1e.R + $80) shr 8] + Ab[C2e.R];
  884. R.G := Af[(C2e.G * C1e.G + $80) shr 8] + Ab[C2e.G];
  885. R.B := Af[(C2e.B * C1e.B + $80) shr 8] + Ab[C2e.B];
  886. end;
  887. //------------------------------------------------------------------------------
  888. //
  889. // Misc.
  890. //
  891. //------------------------------------------------------------------------------
  892. //------------------------------------------------------------------------------
  893. // LightenReg
  894. //------------------------------------------------------------------------------
  895. function LightenReg_Pas(C: TColor32; Amount: Integer): TColor32;
  896. var
  897. r, g, b: Integer;
  898. CX: TColor32Entry absolute C;
  899. RX: TColor32Entry absolute Result;
  900. begin
  901. r := CX.R;
  902. g := CX.G;
  903. b := CX.B;
  904. Inc(r, Amount);
  905. Inc(g, Amount);
  906. Inc(b, Amount);
  907. if r > 255 then r := 255 else if r < 0 then r := 0;
  908. if g > 255 then g := 255 else if g < 0 then g := 0;
  909. if b > 255 then b := 255 else if b < 0 then b := 0;
  910. // preserve alpha
  911. RX.A := CX.A;
  912. RX.R := r;
  913. RX.G := g;
  914. RX.B := b;
  915. end;
  916. //------------------------------------------------------------------------------
  917. // ScaleMems
  918. //------------------------------------------------------------------------------
  919. procedure ScaleMems_Pas(Dst: PColor32; Count: Integer; Weight: Cardinal);
  920. begin
  921. while (Count > 0) do
  922. begin
  923. Dst^ := ColorScale(Dst^, Weight);
  924. Inc(Dst);
  925. Dec(Count);
  926. end;
  927. end;
  928. //------------------------------------------------------------------------------
  929. //
  930. // Bindings
  931. //
  932. //------------------------------------------------------------------------------
  933. procedure RegisterBindingFunctions;
  934. begin
  935. // pure pascal
  936. BlendRegistry[@@MergeReg].Add( @MergeReg_Pas, [isPascal]).Name := 'MergeReg_Pas';
  937. BlendRegistry[@@MergeMem].Add( @MergeMem_Pas, [isPascal]).Name := 'MergeMem_Pas';
  938. BlendRegistry[@@MergeMems].Add( @MergeMems_Pas, [isPascal]).Name := 'MergeMems_Pas';
  939. BlendRegistry[@@MergeMemEx].Add( @MergeMemEx_Pas, [isPascal]).Name := 'MergeMemEx_Pas';
  940. BlendRegistry[@@MergeRegEx].Add( @MergeRegEx_Pas, [isPascal]).Name := 'MergeRegEx_Pas';
  941. BlendRegistry[@@MergeLine].Add( @MergeLine_Pas, [isPascal]).Name := 'MergeLine_Pas';
  942. BlendRegistry[@@MergeLineEx].Add( @MergeLineEx_Pas, [isPascal]).Name := 'MergeLineEx_Pas';
  943. BlendRegistry[@@CombineReg].Add( @CombineReg_Pas, [isPascal]).Name := 'CombineReg_Pas';
  944. BlendRegistry[@@CombineMem].Add( @CombineMem_Pas_Retro, [isPascal]).Name := 'CombineMem_Pas_Retro';
  945. {$ifdef BENCHMARK}
  946. BlendRegistry[@@CombineMem].Add( @CombineMem_Pas_Table, [isPascal], BindingPriorityWorse).Name := 'CombineMem_Pas_Table';
  947. BlendRegistry[@@CombineMem].Add( @CombineMem_Pas_Div255, [isPascal], BindingPriorityWorse).Name := 'CombineMem_Pas_Div255';
  948. {$endif BENCHMARK}
  949. BlendRegistry[@@CombineLine].Add( @CombineLine_Pas, [isPascal]).Name := 'CombineLine_Pas';
  950. BlendRegistry[@@BlendReg].Add( @BlendReg_Pas, [isPascal]).Name := 'BlendReg_Pas';
  951. BlendRegistry[@@BlendMem].Add( @BlendMem_Pas, [isPascal]).Name := 'BlendMem_Pas';
  952. BlendRegistry[@@BlendMems].Add( @BlendMems_Pas, [isPascal]).Name := 'BlendMems_Pas';
  953. BlendRegistry[@@BlendLine].Add( @BlendLine_Pas, [isPascal]).Name := 'BlendLine_Pas';
  954. BlendRegistry[@@BlendRegEx].Add( @BlendRegEx_Pas, [isPascal]).Name := 'BlendRegEx_Pas';
  955. BlendRegistry[@@BlendMemEx].Add( @BlendMemEx_Pas, [isPascal]).Name := 'BlendMemEx_Pas';
  956. BlendRegistry[@@BlendLineEx].Add( @BlendLineEx_Pas, [isPascal]).Name := 'BlendLineEx_Pas';
  957. BlendRegistry[@@ColorDiv].Add( @ColorDiv_Pas, [isPascal]).Name := 'ColorDiv_Pas';
  958. BlendRegistry[@@ColorAverage].Add( @ColorAverage_Pas, [isPascal]).Name := 'ColorAverage_Pas';
  959. BlendRegistry[@@ColorMax].Add( @ColorMax_Pas, [isPascal]).Name := 'ColorMax_Pas';
  960. BlendRegistry[@@ColorMin].Add( @ColorMin_Pas, [isPascal]).Name := 'ColorMin_Pas';
  961. BlendRegistry[@@ColorAdd].Add( @ColorAdd_Pas, [isPascal]).Name := 'ColorAdd_Pas';
  962. BlendRegistry[@@ColorSub].Add( @ColorSub_Pas, [isPascal]).Name := 'ColorSub_Pas';
  963. BlendRegistry[@@ColorModulate].Add( @ColorModulate_Pas, [isPascal]).Name := 'ColorModulate_Pas';
  964. BlendRegistry[@@ColorDifference].Add(@ColorDifference_Pas, [isPascal]).Name := 'ColorDifference_Pas';
  965. BlendRegistry[@@ColorExclusion].Add(@ColorExclusion_Pas, [isPascal]).Name := 'ColorExclusion_Pas';
  966. BlendRegistry[@@ColorScale].Add( @ColorScale_Pas, [isPascal]).Name := 'ColorScale_Pas';
  967. BlendRegistry[@@ColorScreen].Add( @ColorScreen_Pas, [isPascal]).Name := 'ColorScreen_Pas';
  968. BlendRegistry[@@ColorDodge].Add( @ColorDodge_Pas, [isPascal]).Name := 'ColorDodge_Pas';
  969. BlendRegistry[@@ColorBurn].Add( @ColorBurn_Pas, [isPascal]).Name := 'ColorBurn_Pas';
  970. BlendRegistry[@@BlendColorAdd].Add( @BlendColorAdd_Pas, [isPascal]).Name := 'BlendColorAdd_Pas';
  971. BlendRegistry[@@BlendColorModulate].Add(@BlendColorModulate_Pas, [isPascal]).Name := 'BlendColorModulate_Pas';
  972. BlendRegistry[@@BlendRegRGB].Add( @BlendRegRGB_Pas, [isPascal]).Name := 'BlendRegRGB_Pas';
  973. BlendRegistry[@@BlendMemRGB].Add( @BlendMemRGB_Pas, [isPascal]).Name := 'BlendMemRGB_Pas';
  974. BlendRegistry[@@LightenReg].Add( @LightenReg_Pas, [isPascal]).Name := 'LightenReg_Pas';
  975. BlendRegistry[@@ScaleMems].Add( @ScaleMems_Pas, [isPascal]).Name := 'ScaleMems_Pas';
  976. end;
  977. //------------------------------------------------------------------------------
  978. //------------------------------------------------------------------------------
  979. //------------------------------------------------------------------------------
  980. initialization
  981. BlendColorAdd := BlendColorAdd_Pas; // TODO : Why?
  982. RegisterBindingFunctions;
  983. finalization
  984. end.