GR32_Blend.pas 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095
  1. unit GR32_Blend;
  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. * Contributor(s):
  31. * Mattias Andersson
  32. * - 2004/07/07 - MMX Blendmodes
  33. * - 2004/12/10 - _MergeReg, M_MergeReg
  34. *
  35. * Michael Hansen <[email protected]>
  36. * - 2004/07/07 - Pascal Blendmodes, function setup
  37. * - 2005/08/19 - New merge table concept and reference implementations
  38. *
  39. * Bob Voigt
  40. * - 2004/08/25 - ColorDiv
  41. *
  42. * Christian-W. Budde
  43. * - 2019/04/01 - Refactoring
  44. *
  45. * ***** END LICENSE BLOCK ***** *)
  46. interface
  47. {$I GR32.inc}
  48. uses
  49. GR32, GR32_Bindings, SysUtils;
  50. var
  51. MMX_ACTIVE: Boolean;
  52. type
  53. { Function Prototypes }
  54. TBlendReg = function(F, B: TColor32): TColor32;
  55. TBlendMem = procedure(F: TColor32; var B: TColor32);
  56. TBlendMems = procedure(F: TColor32; B: PColor32; Count: Integer);
  57. TBlendRegEx = function(F, B: TColor32; M: Cardinal): TColor32;
  58. TBlendMemEx = procedure(F: TColor32; var B: TColor32; M: Cardinal);
  59. TBlendRegRGB = function(F, B: TColor32; W: Cardinal): TColor32;
  60. TBlendMemRGB = procedure(F: TColor32; var B: TColor32; W: Cardinal);
  61. {$IFDEF TEST_BLENDMEMRGB128SSE4}
  62. TBlendMemRGB128 = procedure(F: TColor32; var B: TColor32; W: UInt64);
  63. {$ENDIF}
  64. TBlendLine = procedure(Src, Dst: PColor32; Count: Integer);
  65. TBlendLineEx = procedure(Src, Dst: PColor32; Count: Integer; M: Cardinal);
  66. TBlendLine1 = procedure(Src: TColor32; Dst: PColor32; Count: Integer);
  67. TCombineReg = function(X, Y: TColor32; W: Cardinal): TColor32;
  68. TCombineMem = procedure(X: TColor32; var Y: TColor32; W: Cardinal);
  69. TCombineLine = procedure(Src, Dst: PColor32; Count: Integer; W: Cardinal);
  70. TLightenReg = function(C: TColor32; Amount: Integer): TColor32;
  71. var
  72. {$IFNDEF OMIT_MMX}
  73. EMMS: procedure;
  74. {$ENDIF}
  75. { Function Variables }
  76. BlendReg: TBlendReg;
  77. BlendMem: TBlendMem;
  78. BlendMems: TBlendMems;
  79. BlendRegEx: TBlendRegEx;
  80. BlendMemEx: TBlendMemEx;
  81. BlendRegRGB: TBlendRegRGB;
  82. BlendMemRGB: TBlendMemRGB;
  83. {$IFDEF TEST_BLENDMEMRGB128SSE4}
  84. BlendMemRGB128: TBlendMemRGB128;
  85. {$ENDIF}
  86. BlendLine: TBlendLine;
  87. BlendLineEx: TBlendLineEx;
  88. BlendLine1: TBlendLine1;
  89. CombineReg: TCombineReg;
  90. CombineMem: TCombineMem;
  91. CombineLine: TCombineLine;
  92. MergeReg: TBlendReg;
  93. MergeMem: TBlendMem;
  94. MergeRegEx: TBlendRegEx;
  95. MergeMemEx: TBlendMemEx;
  96. MergeLine: TBlendLine;
  97. MergeLineEx: TBlendLineEx;
  98. MergeLine1: TBlendLine1;
  99. { Color algebra functions }
  100. ColorAdd: TBlendReg;
  101. ColorSub: TBlendReg;
  102. ColorDiv: TBlendReg;
  103. ColorModulate: TBlendReg;
  104. ColorMax: TBlendReg;
  105. ColorMin: TBlendReg;
  106. ColorDifference: TBlendReg;
  107. ColorAverage: TBlendReg;
  108. ColorExclusion: TBlendReg;
  109. ColorScale: TBlendReg;
  110. ColorScreen: TBlendReg;
  111. ColorDodge: TBlendReg;
  112. ColorBurn: TBlendReg;
  113. { Blended color algebra functions }
  114. BlendColorAdd: TBlendReg;
  115. BlendColorModulate: TBlendReg;
  116. { Special LUT pointers }
  117. AlphaTable: Pointer;
  118. bias_ptr: Pointer;
  119. alpha_ptr: Pointer;
  120. { Misc stuff }
  121. LightenReg: TLightenReg;
  122. function Lighten(C: TColor32; Amount: Integer): TColor32; {$IFDEF USEINLINING} inline; {$ENDIF}
  123. { Access to alpha composite functions corresponding to a combine mode }
  124. type
  125. PBlendReg = ^TBlendReg;
  126. PBlendMem = ^TBlendMem;
  127. PBlendRegEx = ^TBlendRegEx;
  128. PBlendMemEx = ^TBlendMemEx;
  129. PBlendLine = ^TBlendLine;
  130. PBlendLineEx = ^TBlendLineEx;
  131. TBlendRegCombineModeArray = array[TCombineMode] of PBlendReg;
  132. TBlendMemCombineModeArray = array[TCombineMode] of PBlendMem;
  133. TBlendRegExCombineModeArray = array[TCombineMode] of PBlendRegEx;
  134. TBlendMemExCombineModeArray = array[TCombineMode] of PBlendMemEx;
  135. TBlendLineCombineModeArray = array[TCombineMode] of PBlendLine;
  136. TBlendLineExCombineModeArray = array[TCombineMode] of PBlendLineEx;
  137. const
  138. BLEND_REG: TBlendRegCombineModeArray = ((@@BlendReg),(@@MergeReg));
  139. BLEND_MEM: TBlendMemCombineModeArray = ((@@BlendMem),(@@MergeMem));
  140. BLEND_REG_EX: TBlendRegExCombineModeArray = ((@@BlendRegEx),(@@MergeRegEx));
  141. BLEND_MEM_EX: TBlendMemExCombineModeArray = ((@@BlendMemEx),(@@MergeMemEx));
  142. BLEND_LINE: TBlendLineCombineModeArray = ((@@BlendLine),(@@MergeLine));
  143. BLEND_LINE_EX: TBlendLineExCombineModeArray = ((@@BlendLineEx),(@@MergeLineEx));
  144. function BlendRegistry: TFunctionRegistry;
  145. const
  146. FID_EMMS = 0;
  147. FID_MERGEREG = 1;
  148. FID_MERGEMEM = 2;
  149. FID_MERGELINE = 3;
  150. FID_MERGELINE1 = 4;
  151. FID_MERGEREGEX = 5;
  152. FID_MERGEMEMEX = 6;
  153. FID_MERGELINEEX = 7;
  154. FID_COMBINEREG = 8;
  155. FID_COMBINEMEM = 9;
  156. FID_COMBINELINE = 10;
  157. FID_BLENDREG = 11;
  158. FID_BLENDMEM = 12;
  159. FID_BLENDMEMS = 13;
  160. FID_BLENDLINE = 14;
  161. FID_BLENDREGEX = 15;
  162. FID_BLENDMEMEX = 16;
  163. FID_BLENDLINEEX = 17;
  164. FID_BLENDLINE1 = 18;
  165. FID_COLORMAX = 19;
  166. FID_COLORMIN = 20;
  167. FID_COLORAVERAGE = 21;
  168. FID_COLORADD = 22;
  169. FID_COLORSUB = 23;
  170. FID_COLORDIV = 24;
  171. FID_COLORMODULATE = 25;
  172. FID_COLORDIFFERENCE = 26;
  173. FID_COLOREXCLUSION = 27;
  174. FID_COLORSCALE = 28;
  175. FID_COLORSCREEN = 29;
  176. FID_COLORDODGE = 30;
  177. FID_COLORBURN = 31;
  178. FID_BLENDCOLORADD = 32;
  179. FID_BLENDCOLORMODULATE= 33;
  180. FID_LIGHTEN = 34;
  181. FID_BLENDREGRGB = 35;
  182. FID_BLENDMEMRGB = 36;
  183. {$IFDEF TEST_BLENDMEMRGB128SSE4}
  184. FID_BLENDMEMRGB128 = 37;
  185. {$ENDIF}
  186. const
  187. BlendBindingFlagPascal = $0001;
  188. {$IFDEF OMIT_MMX}
  189. procedure EMMS; {$IFDEF USEINLINING} inline; {$ENDIF}
  190. {$ENDIF}
  191. var
  192. RcTable: array [Byte, Byte] of Byte;
  193. DivTable: array [Byte, Byte] of Byte;
  194. implementation
  195. uses
  196. GR32_LowLevel,
  197. {$IFNDEF PUREPASCAL}
  198. GR32_BlendASM,
  199. {$IFNDEF OMIT_MMX}
  200. GR32_BlendMMX,
  201. {$ENDIF}
  202. {$IFNDEF OMIT_SSE2}
  203. GR32_BlendSSE2,
  204. {$ENDIF}
  205. {$ENDIF}
  206. GR32_System;
  207. {$IFDEF OMIT_MMX}
  208. procedure EMMS;
  209. begin
  210. end;
  211. {$ENDIF}
  212. { Pure Pascal }
  213. function BlendReg_Pas(F, B: TColor32): TColor32;
  214. var
  215. FX: TColor32Entry absolute F;
  216. BX: TColor32Entry absolute B;
  217. Af, Ab: PByteArray;
  218. FA : Byte;
  219. begin
  220. FA := FX.A;
  221. if FA = 0 then
  222. begin
  223. Result := B;
  224. Exit;
  225. end;
  226. if FA = $FF then
  227. begin
  228. Result := F;
  229. Exit;
  230. end;
  231. Af := @DivTable[FA];
  232. Ab := @DivTable[not FA];
  233. with BX do
  234. begin
  235. R := Af[FX.R] + Ab[R];
  236. G := Af[FX.G] + Ab[G];
  237. B := Af[FX.B] + Ab[B];
  238. A := $FF;
  239. end;
  240. Result := B;
  241. end;
  242. procedure BlendMem_Pas(F: TColor32; var B: TColor32);
  243. var
  244. FX: TColor32Entry absolute F;
  245. BX: TColor32Entry absolute B;
  246. Af, Ab: PByteArray;
  247. FA : Byte;
  248. begin
  249. FA := FX.A;
  250. if FA = 0 then Exit;
  251. if FA = $FF then
  252. begin
  253. B := F;
  254. Exit;
  255. end;
  256. Af := @DivTable[FA];
  257. Ab := @DivTable[not FA];
  258. with BX do
  259. begin
  260. R := Af[FX.R] + Ab[R];
  261. G := Af[FX.G] + Ab[G];
  262. B := Af[FX.B] + Ab[B];
  263. A := $FF;
  264. end;
  265. end;
  266. procedure BlendMems_Pas(F: TColor32; B: PColor32; Count: Integer);
  267. begin
  268. while Count > 0 do
  269. begin
  270. BlendMem(F, B^);
  271. Inc(B);
  272. Dec(Count);
  273. end;
  274. end;
  275. function BlendRegEx_Pas(F, B: TColor32; M: Cardinal): TColor32;
  276. var
  277. FX: TColor32Entry absolute F;
  278. BX: TColor32Entry absolute B;
  279. Af, Ab: PByteArray;
  280. begin
  281. Af := @DivTable[M];
  282. M := Af[FX.A];
  283. if (M = 0) then
  284. begin
  285. Result := B;
  286. Exit;
  287. end;
  288. if (M = $FF) then
  289. begin
  290. Result := F;
  291. Exit;
  292. end;
  293. Af := @DivTable[M];
  294. Ab := @DivTable[255 - M];
  295. TColor32Entry(Result).R := Af[FX.R] + Ab[BX.R];
  296. TColor32Entry(Result).G := Af[FX.G] + Ab[BX.G];
  297. TColor32Entry(Result).B := Af[FX.B] + Ab[BX.B];
  298. TColor32Entry(Result).A := $FF;
  299. end;
  300. procedure BlendMemEx_Pas(F: TColor32; var B: TColor32; M: Cardinal);
  301. var
  302. FX: TColor32Entry absolute F;
  303. BX: TColor32Entry absolute B;
  304. Af, Ab: PByteArray;
  305. begin
  306. Af := @DivTable[M];
  307. M := Af[FX.A]; // M = (M / 255) * (FX.A / 255)
  308. if (M = 0) then
  309. Exit;
  310. if (M = $FF) then
  311. begin
  312. B := F;
  313. Exit;
  314. end;
  315. Af := @DivTable[M];
  316. Ab := @DivTable[255 - M];
  317. BX.R := Af[FX.R] + Ab[BX.R];
  318. BX.G := Af[FX.G] + Ab[BX.G];
  319. BX.B := Af[FX.B] + Ab[BX.B];
  320. BX.A := $FF;
  321. end;
  322. function BlendRegRGB_Pas(F, B: TColor32; W: Cardinal): TColor32;
  323. var
  324. FX: TColor32Entry absolute F;
  325. BX: TColor32Entry absolute B;
  326. WX: TColor32Entry absolute W;
  327. RX: TColor32Entry absolute Result;
  328. begin
  329. RX.R := (FX.R - BX.R) * WX.B div 255 + BX.R;
  330. RX.G := (FX.G - BX.G) * WX.G div 255 + BX.G;
  331. RX.B := (FX.B - BX.B) * WX.R div 255 + BX.B;
  332. end;
  333. procedure BlendMemRGB_Pas(F: TColor32; var B: TColor32; W: Cardinal);
  334. var
  335. FX: TColor32Entry absolute F;
  336. BX: TColor32Entry absolute B;
  337. WX: TColor32Entry absolute W;
  338. begin
  339. BX.R := (FX.R - BX.R) * WX.B div 255 + BX.R;
  340. BX.G := (FX.G - BX.G) * WX.G div 255 + BX.G;
  341. BX.B := (FX.B - BX.B) * WX.R div 255 + BX.B;
  342. end;
  343. procedure BlendLine1_Pas(Src: TColor32; Dst: PColor32; Count: Integer);
  344. begin
  345. while Count > 0 do
  346. begin
  347. BlendMem(Src, Dst^);
  348. Inc(Dst);
  349. Dec(Count);
  350. end;
  351. end;
  352. procedure BlendLine_Pas(Src, Dst: PColor32; Count: Integer);
  353. begin
  354. while Count > 0 do
  355. begin
  356. BlendMem(Src^, Dst^);
  357. Inc(Src);
  358. Inc(Dst);
  359. Dec(Count);
  360. end;
  361. end;
  362. procedure BlendLineEx_Pas(Src, Dst: PColor32; Count: Integer; M: Cardinal);
  363. begin
  364. while Count > 0 do
  365. begin
  366. BlendMemEx(Src^, Dst^, M);
  367. Inc(Src);
  368. Inc(Dst);
  369. Dec(Count);
  370. end;
  371. end;
  372. function CombineReg_Pas(X, Y: TColor32; W: Cardinal): TColor32;
  373. var
  374. Xe: TColor32Entry absolute X;
  375. Ye: TColor32Entry absolute Y;
  376. Af, Ab: PByteArray;
  377. begin
  378. if W = 0 then
  379. begin
  380. Result := Y;
  381. Exit;
  382. end;
  383. if W >= $FF then
  384. begin
  385. Result := X;
  386. Exit;
  387. end;
  388. Af := @DivTable[W];
  389. Ab := @DivTable[255 - W];
  390. with Xe do
  391. begin
  392. R := Ab[Ye.R] + Af[R];
  393. G := Ab[Ye.G] + Af[G];
  394. B := Ab[Ye.B] + Af[B];
  395. A := Ab[Ye.A] + Af[A];
  396. end;
  397. Result := X;
  398. end;
  399. procedure CombineMem_Pas(X: TColor32; var Y: TColor32; W: Cardinal);
  400. var
  401. Xe: TColor32Entry absolute X;
  402. Ye: TColor32Entry absolute Y;
  403. Af, Ab: PByteArray;
  404. begin
  405. if W = 0 then
  406. begin
  407. Exit;
  408. end;
  409. if W >= $FF then
  410. begin
  411. Y := X;
  412. Exit;
  413. end;
  414. Af := @DivTable[W];
  415. Ab := @DivTable[255 - W];
  416. with Xe do
  417. begin
  418. R := Ab[Ye.R] + Af[R];
  419. G := Ab[Ye.G] + Af[G];
  420. B := Ab[Ye.B] + Af[B];
  421. A := Ab[Ye.A] + Af[A];
  422. end;
  423. Y := X;
  424. end;
  425. procedure CombineLine_Pas(Src, Dst: PColor32; Count: Integer; W: Cardinal);
  426. begin
  427. while Count > 0 do
  428. begin
  429. CombineMem(Src^, Dst^, W);
  430. Inc(Src);
  431. Inc(Dst);
  432. Dec(Count);
  433. end;
  434. end;
  435. function MergeReg_Pas(F, B: TColor32): TColor32;
  436. var
  437. Fa, Ba, Wa: TColor32;
  438. Fw, Bw: PByteArray;
  439. Fx: TColor32Entry absolute F;
  440. Bx: TColor32Entry absolute B;
  441. Rx: TColor32Entry absolute Result;
  442. begin
  443. Fa := F shr 24;
  444. Ba := B shr 24;
  445. if Fa = $FF then
  446. Result := F
  447. else if Fa = $0 then
  448. Result := B
  449. else if Ba = $0 then
  450. Result := F
  451. else
  452. begin
  453. Rx.A := not DivTable[Fa xor 255, Ba xor 255]; // "xor 255" is faster than "not" for the indices because the asm is shorter
  454. Wa := RcTable[Rx.A, Fa];
  455. Fw := @DivTable[Wa];
  456. Bw := @DivTable[Wa xor $FF];
  457. Rx.R := Fw[Fx.R] + Bw[Bx.R];
  458. Rx.G := Fw[Fx.G] + Bw[Bx.G];
  459. Rx.B := Fw[Fx.B] + Bw[Bx.B];
  460. end;
  461. end;
  462. function MergeRegEx_Pas(F, B: TColor32; M: Cardinal): TColor32;
  463. begin
  464. Result := MergeReg(DivTable[M, F shr 24] shl 24 or F and $00FFFFFF, B);
  465. end;
  466. procedure MergeMem_Pas(F: TColor32; var B: TColor32);
  467. begin
  468. B := MergeReg(F, B);
  469. end;
  470. procedure MergeMemEx_Pas(F: TColor32; var B: TColor32; M: Cardinal);
  471. begin
  472. B := MergeReg(DivTable[M, F shr 24] shl 24 or F and $00FFFFFF, B);
  473. end;
  474. procedure MergeLine1_Pas(Src: TColor32; Dst: PColor32; Count: Integer);
  475. begin
  476. while Count > 0 do
  477. begin
  478. Dst^ := MergeReg(Src, Dst^);
  479. Inc(Dst);
  480. Dec(Count);
  481. end;
  482. end;
  483. procedure MergeLine_Pas(Src, Dst: PColor32; Count: Integer);
  484. begin
  485. while Count > 0 do
  486. begin
  487. Dst^ := MergeReg(Src^, Dst^);
  488. Inc(Src);
  489. Inc(Dst);
  490. Dec(Count);
  491. end;
  492. end;
  493. procedure MergeLineEx_Pas(Src, Dst: PColor32; Count: Integer; M: Cardinal);
  494. var
  495. PM: PByteArray;
  496. begin
  497. PM := @DivTable[M];
  498. while Count > 0 do
  499. begin
  500. Dst^ := MergeReg((PM[Src^ shr 24] shl 24) or (Src^ and $00FFFFFF), Dst^);
  501. Inc(Src);
  502. Inc(Dst);
  503. Dec(Count);
  504. end;
  505. end;
  506. procedure EMMS_Pas;
  507. begin
  508. // Dummy
  509. end;
  510. function LightenReg_Pas(C: TColor32; Amount: Integer): TColor32;
  511. var
  512. r, g, b: Integer;
  513. CX: TColor32Entry absolute C;
  514. RX: TColor32Entry absolute Result;
  515. begin
  516. r := CX.R;
  517. g := CX.G;
  518. b := CX.B;
  519. Inc(r, Amount);
  520. Inc(g, Amount);
  521. Inc(b, Amount);
  522. if r > 255 then r := 255 else if r < 0 then r := 0;
  523. if g > 255 then g := 255 else if g < 0 then g := 0;
  524. if b > 255 then b := 255 else if b < 0 then b := 0;
  525. // preserve alpha
  526. RX.A := CX.A;
  527. RX.R := r;
  528. RX.G := g;
  529. RX.B := b;
  530. end;
  531. { Color algebra }
  532. function ColorAdd_Pas(C1, C2: TColor32): TColor32;
  533. var
  534. Xe: TColor32Entry absolute C1;
  535. Ye: TColor32Entry absolute C2;
  536. R: TColor32Entry absolute Result;
  537. begin
  538. R.A := Clamp(Xe.A + Ye.A, 255);
  539. R.R := Clamp(Xe.R + Ye.R, 255);
  540. R.G := Clamp(Xe.G + Ye.G, 255);
  541. R.B := Clamp(Xe.B + Ye.B, 255);
  542. end;
  543. function ColorSub_Pas(C1, C2: TColor32): TColor32;
  544. var
  545. Xe: TColor32Entry absolute C1;
  546. Ye: TColor32Entry absolute C2;
  547. R: TColor32Entry absolute Result;
  548. Temp: SmallInt;
  549. begin
  550. Temp := Xe.A - Ye.A;
  551. if Temp < 0 then
  552. R.A := 0
  553. else
  554. R.A := Temp;
  555. Temp := Xe.R - Ye.R;
  556. if Temp < 0 then
  557. R.R := 0
  558. else
  559. R.R := Temp;
  560. Temp := Xe.G - Ye.G;
  561. if Temp < 0 then
  562. R.G := 0
  563. else
  564. R.G := Temp;
  565. Temp := Xe.B - Ye.B;
  566. if Temp < 0 then
  567. R.B := 0
  568. else
  569. R.B := Temp;
  570. end;
  571. function ColorDiv_Pas(C1, C2: TColor32): TColor32;
  572. var
  573. C1e: TColor32Entry absolute C1;
  574. C2e: TColor32Entry absolute C2;
  575. Re: TColor32Entry absolute Result;
  576. Temp: Word;
  577. begin
  578. if C1e.A = 0 then
  579. Re.A := $FF
  580. else
  581. begin
  582. Temp := (C2e.A shl 8) div C1e.A;
  583. if Temp > $FF then
  584. Re.A := $FF
  585. else
  586. Re.A := Temp;
  587. end;
  588. if C1e.R = 0 then
  589. Re.R := $FF
  590. else
  591. begin
  592. Temp := (C2e.R shl 8) div C1e.R;
  593. if Temp > $FF then
  594. Re.R := $FF
  595. else
  596. Re.R := Temp;
  597. end;
  598. if C1e.G = 0 then
  599. Re.G := $FF
  600. else
  601. begin
  602. Temp := (C2e.G shl 8) div C1e.G;
  603. if Temp > $FF then
  604. Re.G := $FF
  605. else
  606. Re.G := Temp;
  607. end;
  608. if C1e.B = 0 then
  609. Re.B := $FF
  610. else
  611. begin
  612. Temp := (C2e.B shl 8) div C1e.B;
  613. if Temp > $FF then
  614. Re.B := $FF
  615. else
  616. Re.B := Temp;
  617. end;
  618. end;
  619. function ColorModulate_Pas(C1, C2: TColor32): TColor32;
  620. var
  621. C1e: TColor32Entry absolute C1;
  622. C2e: TColor32Entry absolute C2;
  623. Re: TColor32Entry absolute Result;
  624. begin
  625. Re.A := (C2e.A * C1e.A + $80) shr 8;
  626. Re.R := (C2e.R * C1e.R + $80) shr 8;
  627. Re.G := (C2e.G * C1e.G + $80) shr 8;
  628. Re.B := (C2e.B * C1e.B + $80) shr 8;
  629. end;
  630. function ColorMax_Pas(C1, C2: TColor32): TColor32;
  631. var
  632. REnt: TColor32Entry absolute Result;
  633. C2Ent: TColor32Entry absolute C2;
  634. begin
  635. Result := C1;
  636. with C2Ent do
  637. begin
  638. if A > REnt.A then REnt.A := A;
  639. if R > REnt.R then REnt.R := R;
  640. if G > REnt.G then REnt.G := G;
  641. if B > REnt.B then REnt.B := B;
  642. end;
  643. end;
  644. function ColorMin_Pas(C1, C2: TColor32): TColor32;
  645. var
  646. REnt: TColor32Entry absolute Result;
  647. C2Ent: TColor32Entry absolute C2;
  648. begin
  649. Result := C1;
  650. with C2Ent do
  651. begin
  652. if A < REnt.A then REnt.A := A;
  653. if R < REnt.R then REnt.R := R;
  654. if G < REnt.G then REnt.G := G;
  655. if B < REnt.B then REnt.B := B;
  656. end;
  657. end;
  658. function ColorDifference_Pas(C1, C2: TColor32): TColor32;
  659. var
  660. Xe: TColor32Entry absolute C1;
  661. Ye: TColor32Entry absolute C2;
  662. R: TColor32Entry absolute Result;
  663. begin
  664. R.A := Abs(Xe.A - Ye.A);
  665. R.R := Abs(Xe.R - Ye.R);
  666. R.G := Abs(Xe.G - Ye.G);
  667. R.B := Abs(Xe.B - Ye.B);
  668. end;
  669. function ColorExclusion_Pas(C1, C2: TColor32): TColor32;
  670. var
  671. Xe: TColor32Entry absolute C1;
  672. Ye: TColor32Entry absolute C2;
  673. R: TColor32Entry absolute Result;
  674. begin
  675. R.A := Xe.A + Ye.A - ((Xe.A * Ye.A) shl 7);
  676. R.R := Xe.R + Ye.R - ((Xe.R * Ye.R) shr 7);
  677. R.G := Xe.G + Ye.G - ((Xe.G * Ye.G) shr 7);
  678. R.B := Xe.B + Ye.B - ((Xe.B * Ye.B) shr 7);
  679. end;
  680. function ColorAverage_Pas(C1, C2: TColor32): TColor32;
  681. //(A + B)/2 = (A and B) + (A xor B)/2
  682. var
  683. C3 : TColor32;
  684. begin
  685. C3 := C1;
  686. C1 := C1 xor C2;
  687. C1 := C1 shr 1;
  688. C1 := C1 and $7F7F7F7F;
  689. C3 := C3 and C2;
  690. Result := C3 + C1;
  691. end;
  692. function ColorScale_Pas(C: TColor32; W: Cardinal): TColor32;
  693. var
  694. Ce: TColor32Entry absolute C;
  695. var
  696. r1, g1, b1, a1: Cardinal;
  697. begin
  698. a1 := Ce.A * W shr 8;
  699. r1 := Ce.R * W shr 8;
  700. g1 := Ce.G * W shr 8;
  701. b1 := Ce.B * W shr 8;
  702. if a1 > 255 then a1 := 255;
  703. if r1 > 255 then r1 := 255;
  704. if g1 > 255 then g1 := 255;
  705. if b1 > 255 then b1 := 255;
  706. Result := a1 shl 24 + r1 shl 16 + g1 shl 8 + b1;
  707. end;
  708. function ColorScreen_Pas(B, S: TColor32): TColor32;
  709. var
  710. Be: TColor32Entry absolute B;
  711. Se: TColor32Entry absolute S;
  712. R: TColor32Entry absolute Result;
  713. begin
  714. R.A := Be.A + Se.A - (Be.A * Se.A) div 255;
  715. R.R := Be.R + Se.R - (Be.R * Se.R) div 255;
  716. R.G := Be.G + Se.G - (Be.G * Se.G) div 255;
  717. R.B := Be.B + Se.B - (Be.B * Se.B) div 255;
  718. end;
  719. function ColorDodge_Pas(B, S: TColor32): TColor32;
  720. function Dodge(B, S: Byte): Byte;
  721. begin
  722. if B = 0 then
  723. Result := 0
  724. else
  725. if S = 255 then
  726. Result := 255
  727. else
  728. Result := Clamp((255 * B) div (255 - S), 255);
  729. end;
  730. var
  731. Be: TColor32Entry absolute B;
  732. Se: TColor32Entry absolute S;
  733. R: TColor32Entry absolute Result;
  734. begin
  735. R.A := Dodge(Be.A, Se.A);
  736. R.R := Dodge(Be.R, Se.R);
  737. R.G := Dodge(Be.G, Se.G);
  738. R.B := Dodge(Be.B, Se.B);
  739. end;
  740. function ColorBurn_Pas(B, S: TColor32): TColor32;
  741. function Burn(B, S: Byte): Byte;
  742. begin
  743. if B = 255 then
  744. Result := 255
  745. else
  746. if S = 0 then
  747. Result := 0
  748. else
  749. Result := 255 - Clamp(255 * (255 - B) div S, 255);
  750. end;
  751. var
  752. Be: TColor32Entry absolute B;
  753. Se: TColor32Entry absolute S;
  754. R: TColor32Entry absolute Result;
  755. begin
  756. R.A := Burn(Be.A, Se.A);
  757. R.R := Burn(Be.R, Se.R);
  758. R.G := Burn(Be.G, Se.G);
  759. R.B := Burn(Be.B, Se.B);
  760. end;
  761. { Blended color algebra }
  762. function BlendColorAdd_Pas(C1, C2: TColor32): TColor32;
  763. var
  764. Xe: TColor32Entry absolute C1;
  765. Ye: TColor32Entry absolute C2;
  766. R: TColor32Entry absolute Result;
  767. Af, Ab: PByteArray;
  768. begin
  769. Af := @DivTable[Xe.A];
  770. Ab := @DivTable[not Xe.A];
  771. R.A := Af[Clamp(Xe.A + Ye.A, 255)] + Ab[Ye.A];
  772. R.R := Af[Clamp(Xe.R + Ye.R, 255)] + Ab[Ye.R];
  773. R.G := Af[Clamp(Xe.G + Ye.G, 255)] + Ab[Ye.G];
  774. R.B := Af[Clamp(Xe.B + Ye.B, 255)] + Ab[Ye.B];
  775. end;
  776. function BlendColorModulate_Pas(C1, C2: TColor32): TColor32;
  777. var
  778. C1e: TColor32Entry absolute C1;
  779. C2e: TColor32Entry absolute C2;
  780. R: TColor32Entry absolute Result;
  781. Af, Ab: PByteArray;
  782. begin
  783. Af := @DivTable[C1e.A];
  784. Ab := @DivTable[not C1e.A];
  785. R.A := Af[(C2e.A * C1e.A + $80) shr 8] + Ab[C2e.A];
  786. R.R := Af[(C2e.R * C1e.R + $80) shr 8] + Ab[C2e.R];
  787. R.G := Af[(C2e.G * C1e.G + $80) shr 8] + Ab[C2e.G];
  788. R.B := Af[(C2e.B * C1e.B + $80) shr 8] + Ab[C2e.B];
  789. end;
  790. {$IFNDEF PUREPASCAL}
  791. procedure GenAlphaTable;
  792. var
  793. I: Integer;
  794. L: LongWord;
  795. P: PLongWord;
  796. begin
  797. GetMem(AlphaTable, 257 * 8 * SizeOf(Cardinal));
  798. {$IFDEF HAS_NATIVEINT}
  799. alpha_ptr := Pointer(NativeUInt(AlphaTable) and (not $F));
  800. if NativeUInt(alpha_ptr) < NativeUInt(AlphaTable) then
  801. alpha_ptr := Pointer(NativeUInt(alpha_ptr) + 16);
  802. {$ELSE}
  803. alpha_ptr := Pointer(Cardinal(AlphaTable) and (not $F));
  804. if Cardinal(alpha_ptr) < Cardinal(AlphaTable) then
  805. Inc(Cardinal(alpha_ptr), 16);
  806. {$ENDIF}
  807. P := alpha_ptr;
  808. for I := 0 to 255 do
  809. begin
  810. L := I + I shl 16;
  811. P^ := L;
  812. Inc(P);
  813. P^ := L;
  814. Inc(P);
  815. P^ := L;
  816. Inc(P);
  817. P^ := L;
  818. Inc(P);
  819. end;
  820. bias_ptr := alpha_ptr;
  821. Inc(PLongWord(bias_ptr), 4 * $80);
  822. end;
  823. procedure FreeAlphaTable;
  824. begin
  825. FreeMem(AlphaTable);
  826. end;
  827. {$ENDIF}
  828. { Misc stuff }
  829. function Lighten(C: TColor32; Amount: Integer): TColor32;
  830. begin
  831. Result := LightenReg(C, Amount);
  832. end;
  833. procedure MakeMergeTables;
  834. var
  835. i, j: Integer;
  836. begin
  837. for i := 0 to 255 do
  838. begin
  839. DivTable[0, i] := 0; // Yes, [0,0] is set twice but who cares
  840. DivTable[i, 0] := 0;
  841. RcTable[0, i] := 0;
  842. RcTable[i, 0] := 0;
  843. end;
  844. for j := 1 to 255 do
  845. for i := 1 to 255 do
  846. begin
  847. DivTable[i, j] := Round(i * j * COne255th);
  848. if i > j then
  849. RcTable[i, j] := Round(j * 255 / i)
  850. else
  851. RcTable[i, j] := 255;
  852. end;
  853. end;
  854. procedure RegisterBindings;
  855. begin
  856. {$IFNDEF OMIT_MMX}
  857. BlendRegistry.RegisterBinding(FID_EMMS, @@EMMS);
  858. {$ENDIF}
  859. BlendRegistry.RegisterBinding(FID_MERGEREG, @@MergeReg);
  860. BlendRegistry.RegisterBinding(FID_MERGEMEM, @@MergeMem);
  861. BlendRegistry.RegisterBinding(FID_MERGELINE, @@MergeLine);
  862. BlendRegistry.RegisterBinding(FID_MERGEREGEX, @@MergeRegEx);
  863. BlendRegistry.RegisterBinding(FID_MERGEMEMEX, @@MergeMemEx);
  864. BlendRegistry.RegisterBinding(FID_MERGELINEEX, @@MergeLineEx);
  865. BlendRegistry.RegisterBinding(FID_COMBINEREG, @@CombineReg);
  866. BlendRegistry.RegisterBinding(FID_COMBINEMEM, @@CombineMem);
  867. BlendRegistry.RegisterBinding(FID_COMBINELINE, @@CombineLine);
  868. BlendRegistry.RegisterBinding(FID_BLENDREG, @@BlendReg);
  869. BlendRegistry.RegisterBinding(FID_BLENDMEM, @@BlendMem);
  870. BlendRegistry.RegisterBinding(FID_BLENDMEMS, @@BlendMems);
  871. BlendRegistry.RegisterBinding(FID_BLENDLINE, @@BlendLine);
  872. BlendRegistry.RegisterBinding(FID_BLENDREGEX, @@BlendRegEx);
  873. BlendRegistry.RegisterBinding(FID_BLENDMEMEX, @@BlendMemEx);
  874. BlendRegistry.RegisterBinding(FID_BLENDLINEEX, @@BlendLineEx);
  875. BlendRegistry.RegisterBinding(FID_BLENDLINE1, @@BlendLine1);
  876. BlendRegistry.RegisterBinding(FID_COLORMAX, @@ColorMax);
  877. BlendRegistry.RegisterBinding(FID_COLORMIN, @@ColorMin);
  878. BlendRegistry.RegisterBinding(FID_COLORAVERAGE, @@ColorAverage);
  879. BlendRegistry.RegisterBinding(FID_COLORADD, @@ColorAdd);
  880. BlendRegistry.RegisterBinding(FID_COLORSUB, @@ColorSub);
  881. BlendRegistry.RegisterBinding(FID_COLORDIV, @@ColorDiv);
  882. BlendRegistry.RegisterBinding(FID_COLORMODULATE, @@ColorModulate);
  883. BlendRegistry.RegisterBinding(FID_COLORDIFFERENCE, @@ColorDifference);
  884. BlendRegistry.RegisterBinding(FID_COLOREXCLUSION, @@ColorExclusion);
  885. BlendRegistry.RegisterBinding(FID_COLORSCALE, @@ColorScale);
  886. BlendRegistry.RegisterBinding(FID_COLORSCREEN, @@ColorScreen);
  887. BlendRegistry.RegisterBinding(FID_COLORDODGE, @@ColorDodge);
  888. BlendRegistry.RegisterBinding(FID_COLORBURN, @@ColorBurn);
  889. BlendRegistry.RegisterBinding(FID_BLENDCOLORADD, @@BlendColorAdd);
  890. BlendRegistry.RegisterBinding(FID_BLENDCOLORMODULATE, @@BlendColorModulate);
  891. BlendRegistry.RegisterBinding(FID_LIGHTEN, @@LightenReg);
  892. BlendRegistry.RegisterBinding(FID_BLENDREGRGB, @@BlendRegRGB);
  893. BlendRegistry.RegisterBinding(FID_BLENDMEMRGB, @@BlendMemRGB);
  894. {$IFDEF TEST_BLENDMEMRGB128SSE4}
  895. BlendRegistry.RegisterBinding(FID_BLENDMEMRGB128, @@BlendMemRGB128);
  896. {$ENDIF}
  897. end;
  898. procedure RegisterBindingFunctions;
  899. begin
  900. // pure pascal
  901. BlendRegistry.Add(FID_EMMS, @EMMS_Pas, [], BlendBindingFlagPascal);
  902. BlendRegistry.Add(FID_MERGEREG, @MergeReg_Pas, [], BlendBindingFlagPascal);
  903. BlendRegistry.Add(FID_MERGEMEM, @MergeMem_Pas, [], BlendBindingFlagPascal);
  904. BlendRegistry.Add(FID_MERGEMEMEX, @MergeMemEx_Pas, [], BlendBindingFlagPascal);
  905. BlendRegistry.Add(FID_MERGEREGEX, @MergeRegEx_Pas, [], BlendBindingFlagPascal);
  906. BlendRegistry.Add(FID_MERGELINE, @MergeLine_Pas, [], BlendBindingFlagPascal);
  907. BlendRegistry.Add(FID_MERGELINEEX, @MergeLineEx_Pas, [], BlendBindingFlagPascal);
  908. BlendRegistry.Add(FID_MERGELINE1, @MergeLine1_Pas, [], BlendBindingFlagPascal);
  909. BlendRegistry.Add(FID_COLORDIV, @ColorDiv_Pas, [], BlendBindingFlagPascal);
  910. BlendRegistry.Add(FID_COLORAVERAGE, @ColorAverage_Pas, [], BlendBindingFlagPascal);
  911. BlendRegistry.Add(FID_COMBINEREG, @CombineReg_Pas, [], BlendBindingFlagPascal);
  912. BlendRegistry.Add(FID_COMBINEMEM, @CombineMem_Pas, [], BlendBindingFlagPascal);
  913. BlendRegistry.Add(FID_COMBINELINE, @CombineLine_Pas, [], BlendBindingFlagPascal);
  914. BlendRegistry.Add(FID_BLENDREG, @BlendReg_Pas, [], BlendBindingFlagPascal);
  915. BlendRegistry.Add(FID_BLENDMEM, @BlendMem_Pas, [], BlendBindingFlagPascal);
  916. BlendRegistry.Add(FID_BLENDMEMS, @BlendMems_Pas, [], BlendBindingFlagPascal);
  917. BlendRegistry.Add(FID_BLENDLINE, @BlendLine_Pas, [], BlendBindingFlagPascal);
  918. BlendRegistry.Add(FID_BLENDREGEX, @BlendRegEx_Pas, [], BlendBindingFlagPascal);
  919. BlendRegistry.Add(FID_BLENDMEMEX, @BlendMemEx_Pas, [], BlendBindingFlagPascal);
  920. BlendRegistry.Add(FID_BLENDLINEEX, @BlendLineEx_Pas, [], BlendBindingFlagPascal);
  921. BlendRegistry.Add(FID_BLENDLINE1, @BlendLine1_Pas, [], BlendBindingFlagPascal);
  922. BlendRegistry.Add(FID_COLORMAX, @ColorMax_Pas, [], BlendBindingFlagPascal);
  923. BlendRegistry.Add(FID_COLORMIN, @ColorMin_Pas, [], BlendBindingFlagPascal);
  924. BlendRegistry.Add(FID_COLORADD, @ColorAdd_Pas, [], BlendBindingFlagPascal);
  925. BlendRegistry.Add(FID_COLORSUB, @ColorSub_Pas, [], BlendBindingFlagPascal);
  926. BlendRegistry.Add(FID_COLORMODULATE, @ColorModulate_Pas, [], BlendBindingFlagPascal);
  927. BlendRegistry.Add(FID_COLORDIFFERENCE, @ColorDifference_Pas, [], BlendBindingFlagPascal);
  928. BlendRegistry.Add(FID_COLOREXCLUSION, @ColorExclusion_Pas, [], BlendBindingFlagPascal);
  929. BlendRegistry.Add(FID_COLORSCALE, @ColorScale_Pas, [], BlendBindingFlagPascal);
  930. BlendRegistry.Add(FID_COLORSCREEN, @ColorScreen_Pas, [], BlendBindingFlagPascal);
  931. BlendRegistry.Add(FID_COLORDODGE, @ColorDodge_Pas, [], BlendBindingFlagPascal);
  932. BlendRegistry.Add(FID_COLORBURN, @ColorBurn_Pas, [], BlendBindingFlagPascal);
  933. BlendRegistry.Add(FID_BLENDCOLORADD, @BlendColorAdd_Pas, [], BlendBindingFlagPascal);
  934. BlendRegistry.Add(FID_BLENDCOLORMODULATE, @BlendColorModulate_Pas, [], BlendBindingFlagPascal);
  935. BlendRegistry.Add(FID_LIGHTEN, @LightenReg_Pas, [], BlendBindingFlagPascal);
  936. BlendRegistry.Add(FID_BLENDREGRGB, @BlendRegRGB_Pas, [], BlendBindingFlagPascal);
  937. BlendRegistry.Add(FID_BLENDMEMRGB, @BlendMemRGB_Pas, [], BlendBindingFlagPascal);
  938. end;
  939. var
  940. FBlendRegistry: TFunctionRegistry = nil;
  941. function BlendRegistry: TFunctionRegistry;
  942. begin
  943. if (FBlendRegistry = nil) then
  944. begin
  945. FBlendRegistry := NewRegistry('GR32_Blend bindings');
  946. RegisterBindings;
  947. end;
  948. Result := FBlendRegistry;
  949. end;
  950. initialization
  951. BlendColorAdd := BlendColorAdd_Pas;
  952. RegisterBindingFunctions;
  953. BlendRegistry.RebindAll;
  954. MakeMergeTables;
  955. {$IFNDEF PUREPASCAL}
  956. MMX_ACTIVE := (ciMMX in CPUFeatures);
  957. if [ciMMX, ciSSE2] * CPUFeatures <> [] then
  958. GenAlphaTable;
  959. {$ELSE}
  960. MMX_ACTIVE := False;
  961. {$ENDIF}
  962. finalization
  963. {$IFNDEF PUREPASCAL}
  964. if [ciMMX, ciSSE2] * CPUFeatures <> [] then
  965. FreeAlphaTable;
  966. {$ENDIF}
  967. end.