2
0

pixtools.pp 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2003 by the Free Pascal development team
  4. Pixel drawing routines.
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$mode objfpc}{$h+}
  12. unit PixTools;
  13. interface
  14. uses classes, FPCanvas, FPimage;
  15. procedure DrawSolidLine (Canv : TFPCustomCanvas; x1,y1, x2,y2:integer; const color:TFPColor);
  16. procedure DrawPatternLine (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; Pattern:TPenPattern; const color:TFPColor);
  17. procedure FillRectangleColor (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; const color:TFPColor);
  18. procedure FillRectanglePattern (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; const pattern:TBrushPattern; const color:TFPColor);
  19. procedure FillRectangleHashHorizontal (Canv:TFPCustomCanvas; const rect:TRect; width:integer; const c:TFPColor);
  20. procedure FillRectangleHashVertical (Canv:TFPCustomCanvas; const rect:TRect; width:integer; const c:TFPColor);
  21. procedure FillRectangleHashDiagonal (Canv:TFPCustomCanvas; const rect:TRect; width:integer; const c:TFPColor);
  22. procedure FillRectangleHashBackDiagonal (Canv:TFPCustomCanvas; const rect:TRect; width:integer; const c:TFPColor);
  23. procedure FillFloodColor (Canv:TFPCustomCanvas; x,y:integer; const color:TFPColor);
  24. procedure FillFloodPattern (Canv:TFPCustomCanvas; x,y:integer; const pattern:TBrushPattern; const color:TFPColor);
  25. procedure FillFloodHashHorizontal (Canv:TFPCustomCanvas; x,y:integer; width:integer; const c:TFPColor);
  26. procedure FillFloodHashVertical (Canv:TFPCustomCanvas; x,y:integer; width:integer; const c:TFPColor);
  27. procedure FillFloodHashDiagonal (Canv:TFPCustomCanvas; x,y:integer; width:integer; const c:TFPColor);
  28. procedure FillFloodHashBackDiagonal (Canv:TFPCustomCanvas; x,y:integer; width:integer; const c:TFPColor);
  29. procedure FillFloodHashDiagCross (Canv:TFPCustomCanvas; x,y:integer; width:integer; const c:TFPColor);
  30. procedure FillFloodHashCross (Canv:TFPCustomCanvas; x,y:integer; width:integer; const c:TFPColor);
  31. procedure DrawSolidLine (Canv : TFPCustomCanvas; x1,y1, x2,y2:integer);
  32. procedure DrawPatternLine (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; Pattern:TPenPattern);
  33. procedure FillRectanglePattern (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; const pattern:TBrushPattern);
  34. procedure FillRectangleColor (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer);
  35. procedure FillRectangleHashHorizontal (Canv:TFPCustomCanvas; const rect:TRect; width:integer);
  36. procedure FillRectangleHashVertical (Canv:TFPCustomCanvas; const rect:TRect; width:integer);
  37. procedure FillRectangleHashDiagonal (Canv:TFPCustomCanvas; const rect:TRect; width:integer);
  38. procedure FillRectangleHashBackDiagonal (Canv:TFPCustomCanvas; const rect:TRect; width:integer);
  39. procedure FillFloodColor (Canv:TFPCustomCanvas; x,y:integer);
  40. procedure FillFloodPattern (Canv:TFPCustomCanvas; x,y:integer; const pattern:TBrushPattern);
  41. procedure FillFloodHashHorizontal (Canv:TFPCustomCanvas; x,y:integer; width:integer);
  42. procedure FillFloodHashVertical (Canv:TFPCustomCanvas; x,y:integer; width:integer);
  43. procedure FillFloodHashDiagonal (Canv:TFPCustomCanvas; x,y:integer; width:integer);
  44. procedure FillFloodHashBackDiagonal (Canv:TFPCustomCanvas; x,y:integer; width:integer);
  45. procedure FillFloodHashDiagCross (Canv:TFPCustomCanvas; x,y:integer; width:integer);
  46. procedure FillFloodHashCross (Canv:TFPCustomCanvas; x,y:integer; width:integer);
  47. procedure FillRectangleImage (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; const Image:TFPCustomImage);
  48. procedure FillRectangleImageRel (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; const Image:TFPCustomImage);
  49. procedure FillFloodImage (Canv:TFPCustomCanvas; x,y :integer; const Image:TFPCustomImage);
  50. procedure FillFloodImageRel (Canv:TFPCustomCanvas; x,y :integer; const Image:TFPCustomImage);
  51. implementation
  52. uses clipping, ellipses;
  53. procedure FillRectangleColor (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer);
  54. begin
  55. FillRectangleColor (Canv, x1,y1, x2,y2, Canv.Brush.FPColor);
  56. end;
  57. procedure FillRectangleColor (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; const color:TFPColor);
  58. var x,y : integer;
  59. begin
  60. SortRect (x1,y1, x2,y2);
  61. with Canv do
  62. begin
  63. for x := x1 to x2 do
  64. for y := y1 to y2 do
  65. colors[x,y] := color;
  66. end;
  67. end;
  68. {procedure DrawSolidPolyLine (Canv : TFPCustomCanvas; points:array of TPoint; close:boolean);
  69. var i,a, r : integer;
  70. p : TPoint;
  71. begin
  72. i := low(points);
  73. a := high(points);
  74. p := points[i];
  75. with Canv do
  76. begin
  77. for r := i+1 to a do
  78. begin
  79. Line (p.x, p.y, points[r].x, points[r].y);
  80. p := points[r];
  81. end;
  82. if close then
  83. Line (p.x,p.y, points[i].x,points[i].y);
  84. end;
  85. end;
  86. }
  87. type
  88. TPutPixelProc = procedure (Canv:TFPCustomCanvas; x,y:integer; color:TFPColor);
  89. procedure PutPixelCopy(Canv:TFPCustomCanvas; x,y:integer; color:TFPColor);
  90. begin
  91. with Canv do
  92. Colors[x,y] := color;
  93. end;
  94. procedure PutPixelXor(Canv:TFPCustomCanvas; x,y:integer; color:TFPColor);
  95. begin
  96. with Canv do
  97. Colors[x,y] := Colors[x,y] xor color;
  98. end;
  99. procedure PutPixelOr(Canv:TFPCustomCanvas; x,y:integer; color:TFPColor);
  100. begin
  101. with Canv do
  102. Colors[x,y] := Colors[x,y] or color;
  103. end;
  104. procedure PutPixelAnd(Canv:TFPCustomCanvas; x,y:integer; color:TFPColor);
  105. begin
  106. with Canv do
  107. Colors[x,y] := Colors[x,y] and color;
  108. end;
  109. procedure DrawSolidLine (Canv : TFPCustomCanvas; x1,y1, x2,y2:integer);
  110. begin
  111. DrawSolidLine (Canv, x1,y1, x2,y2, Canv.Pen.FPColor);
  112. end;
  113. procedure DrawSolidLine (Canv : TFPCustomCanvas; x1,y1, x2,y2:integer; const color:TFPColor);
  114. var PutPixelProc : TPutPixelProc;
  115. procedure HorizontalLine (x1,x2,y:integer);
  116. var x : integer;
  117. begin
  118. for x := x1 to x2 do
  119. PutPixelProc (Canv, x,y, color);
  120. end;
  121. procedure VerticalLine (x,y1,y2:integer);
  122. var y : integer;
  123. begin
  124. for y := y1 to y2 do
  125. PutPixelProc (Canv, x,y, color);
  126. end;
  127. procedure SlopedLine;
  128. var npixels,xinc1,yinc1,xinc2,yinc2,dx,dy,d,dinc1,dinc2 : integer;
  129. procedure initialize;
  130. begin // precalculations
  131. dx := abs(x2-x1);
  132. dy := abs(y2-y1);
  133. if dx > dy then // determining independent variable
  134. begin // x is independent
  135. npixels := dx + 1;
  136. d := (2 * dy) - dx;
  137. dinc1 := dy * 2;
  138. dinc2:= (dy - dx) * 2;
  139. xinc1 := 1;
  140. xinc2 := 1;
  141. yinc1 := 0;
  142. yinc2 := 1;
  143. end
  144. else
  145. begin // y is independent
  146. npixels := dy + 1;
  147. d := (2 * dx) - dy;
  148. dinc1 := dx * 2;
  149. dinc2:= (dx - dy) * 2;
  150. xinc1 := 0;
  151. xinc2 := 1;
  152. yinc1 := 1;
  153. yinc2 := 1;
  154. end;
  155. // going into the correct direction
  156. if x1 > x2 then
  157. begin
  158. xinc1 := - xinc1;
  159. xinc2 := - xinc2;
  160. end;
  161. if y1 > y2 then
  162. begin
  163. yinc1 := - yinc1;
  164. yinc2 := - yinc2;
  165. end;
  166. end;
  167. var r,x,y : integer;
  168. begin
  169. initialize;
  170. x := x1;
  171. y := y1;
  172. for r := 1 to nPixels do
  173. begin
  174. PutPixelProc (Canv, x,y, color);
  175. if d < 0 then
  176. begin
  177. d := d + dinc1;
  178. x := x + xinc1;
  179. y := y + yinc1;
  180. end
  181. else
  182. begin
  183. d := d + dinc2;
  184. x := x + xinc2;
  185. y := y + yinc2;
  186. end;
  187. end;
  188. end;
  189. begin
  190. with canv.pen do
  191. case mode of
  192. pmMerge : PutPixelProc := @PutPixelAnd;
  193. pmMask : PutPixelProc := @PutPixelOr;
  194. pmXor : PutPixelProc := @PutPixelXor;
  195. else PutPixelProc := @PutPixelCopy;
  196. end;
  197. if x1 = x2 then // vertical line
  198. if y1 < y2 then
  199. VerticalLine (x1, y1, y2)
  200. else
  201. VerticalLine (x1, y2, y1)
  202. else if y1 = y2 then
  203. if x1 < x2 then
  204. HorizontalLine (x1, x2, y1)
  205. else
  206. HorizontalLine (x2, x1, y1)
  207. else // sloped line
  208. SlopedLine;
  209. end;
  210. type
  211. TLinePoints = array[0..PatternBitCount-1] of boolean;
  212. PLinePoints = ^TLinePoints;
  213. procedure PatternToPoints (const APattern:TPenPattern; LinePoints:PLinePoints);
  214. var r : integer;
  215. i : longword;
  216. begin
  217. i := 1;
  218. for r := PatternBitCount-1 downto 1 do
  219. begin
  220. LinePoints^[r] := (APattern and i) <> 0;
  221. i := i shl 1;
  222. end;
  223. LinePoints^[0] := (APattern and i) <> 0;
  224. end;
  225. procedure DrawPatternLine (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; Pattern:TPenPattern);
  226. begin
  227. DrawPatternLine (Canv, x1,y1, x2,y2, pattern, Canv.Pen.FPColor);
  228. end;
  229. procedure DrawPatternLine (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; Pattern:TPenPattern; const color:TFPColor);
  230. // Is copy of DrawSolidLine with paterns added. Not the same procedure for faster solid lines
  231. var LinePoints : TLinePoints;
  232. PutPixelProc : TPutPixelProc;
  233. procedure HorizontalLine (x1,x2,y:integer);
  234. var x : integer;
  235. begin
  236. for x := x1 to x2 do
  237. if LinePoints[x mod PatternBitCount] then
  238. PutPixelProc (Canv, x,y, color);
  239. end;
  240. procedure VerticalLine (x,y1,y2:integer);
  241. var y : integer;
  242. begin
  243. for y := y1 to y2 do
  244. if LinePoints[y mod PatternBitCount] then
  245. PutPixelProc (Canv, x,y, color);
  246. end;
  247. procedure SlopedLine;
  248. var npixels,xinc1,yinc1,xinc2,yinc2,dx,dy,d,dinc1,dinc2 : integer;
  249. procedure initialize;
  250. begin // precalculations
  251. dx := abs(x2-x1);
  252. dy := abs(y2-y1);
  253. if dx > dy then // determining independent variable
  254. begin // x is independent
  255. npixels := dx + 1;
  256. d := (2 * dy) - dx;
  257. dinc1 := dy * 2;
  258. dinc2:= (dy - dx) * 2;
  259. xinc1 := 1;
  260. xinc2 := 1;
  261. yinc1 := 0;
  262. yinc2 := 1;
  263. end
  264. else
  265. begin // y is independent
  266. npixels := dy + 1;
  267. d := (2 * dx) - dy;
  268. dinc1 := dx * 2;
  269. dinc2:= (dx - dy) * 2;
  270. xinc1 := 0;
  271. xinc2 := 1;
  272. yinc1 := 1;
  273. yinc2 := 1;
  274. end;
  275. // going into the correct direction
  276. if x1 > x2 then
  277. begin
  278. xinc1 := - xinc1;
  279. xinc2 := - xinc2;
  280. end;
  281. if y1 > y2 then
  282. begin
  283. yinc1 := - yinc1;
  284. yinc2 := - yinc2;
  285. end;
  286. end;
  287. var r,x,y : integer;
  288. begin
  289. initialize;
  290. x := x1;
  291. y := y1;
  292. for r := 1 to nPixels do
  293. begin
  294. if LinePoints[r mod PatternBitCount] then
  295. PutPixelProc (Canv, x,y, color);
  296. if d < 0 then
  297. begin
  298. d := d + dinc1;
  299. x := x + xinc1;
  300. y := y + yinc1;
  301. end
  302. else
  303. begin
  304. d := d + dinc2;
  305. x := x + xinc2;
  306. y := y + yinc2;
  307. end;
  308. end;
  309. end;
  310. begin
  311. PatternToPoints (pattern, @LinePoints);
  312. with canv.pen do
  313. case mode of
  314. pmMask : PutPixelProc := @PutPixelAnd;
  315. pmMerge : PutPixelProc := @PutPixelOr;
  316. pmXor : PutPixelProc := @PutPixelXor;
  317. else PutPixelProc := @PutPixelCopy;
  318. end;
  319. if x1 = x2 then // vertical line
  320. if y1 < y2 then
  321. VerticalLine (x1, y1, y2)
  322. else
  323. VerticalLine (x1, y2, y1)
  324. else if y1 = y2 then
  325. if x1 < x2 then
  326. HorizontalLine (x1, x2, y1)
  327. else
  328. HorizontalLine (x2, x1, y1)
  329. else // sloped line
  330. SlopedLine;
  331. end;
  332. procedure FillRectangleHashHorizontal (Canv:TFPCustomCanvas; const rect:TRect; width:integer);
  333. begin
  334. FillRectangleHashHorizontal (Canv, rect, width, Canv.Brush.FPColor);
  335. end;
  336. procedure FillRectangleHashHorizontal (Canv:TFPCustomCanvas; const rect:TRect; width:integer; const c:TFPColor);
  337. var y : integer;
  338. begin
  339. with rect do
  340. begin
  341. y := Width + top;
  342. while y <= bottom do
  343. begin
  344. DrawSolidLine (Canv, left,y, right,y, c);
  345. inc (y,Width);
  346. end
  347. end;
  348. end;
  349. procedure FillRectangleHashVertical (Canv:TFPCustomCanvas; const rect:TRect; width:integer);
  350. begin
  351. FillRectangleHashVertical (Canv, rect, width, Canv.Brush.FPColor);
  352. end;
  353. procedure FillRectangleHashVertical (Canv:TFPCustomCanvas; const rect:TRect; width:integer; const c:TFPColor);
  354. var x : integer;
  355. begin
  356. with rect do
  357. begin
  358. x := Width + left;
  359. while x <= right do
  360. begin
  361. DrawSolidLine (Canv, x,top, x,bottom, c);
  362. inc (x, Width);
  363. end;
  364. end;
  365. end;
  366. procedure FillRectangleHashDiagonal (Canv:TFPCustomCanvas; const rect:TRect; width:integer);
  367. begin
  368. FillRectangleHashDiagonal (Canv, rect, width, Canv.Brush.FPColor);
  369. end;
  370. procedure FillRectangleHashDiagonal (Canv:TFPCustomCanvas; const rect:TRect; width:integer; const c:TFPColor);
  371. function CheckCorner (Current, max, start : integer) : integer;
  372. begin
  373. if Current > max then
  374. result := Start + current - max
  375. else
  376. result := Start;
  377. end;
  378. var r, rx, ry : integer;
  379. begin
  380. with rect do
  381. begin
  382. // draw from bottom-left corner away
  383. ry := top + Width;
  384. rx := left + Width;
  385. while (rx < right) and (ry < bottom) do
  386. begin
  387. DrawSolidLine (Canv, left,ry, rx,top, c);
  388. inc (rx, Width);
  389. inc (ry, Width);
  390. end;
  391. // check which turn need to be taken: left-bottom, right-top, or both
  392. if (rx >= right) then
  393. begin
  394. if (ry >= bottom) then
  395. begin // Both corners reached
  396. r := CheckCorner (rx, right, top);
  397. rx := CheckCorner (ry, bottom, left);
  398. ry := r;
  399. end
  400. else
  401. begin // fill vertical
  402. r := CheckCorner (rx, right, top);
  403. while (ry < bottom) do
  404. begin
  405. DrawSolidLine (Canv, left,ry, right,r, c);
  406. inc (r, Width);
  407. inc (ry, Width);
  408. end;
  409. rx := CheckCorner (ry, bottom, left);
  410. ry := r;
  411. end
  412. end
  413. else
  414. if (ry >= bottom) then
  415. begin // fill horizontal
  416. r := checkCorner (ry, bottom, left);
  417. while (rx <= right) do
  418. begin
  419. DrawSolidLine (Canv, r,bottom, rx,top, c);
  420. inc (r, Width);
  421. inc (rx, Width);
  422. end;
  423. ry := CheckCorner (rx, right, top);
  424. rx := r;
  425. end;
  426. while (rx < right) do // fill lower right corner
  427. begin
  428. DrawSolidLine (Canv, rx,bottom, right,ry, c);
  429. inc (rx, Width);
  430. inc (ry, Width);
  431. end;
  432. end;
  433. end;
  434. procedure FillRectangleHashBackDiagonal (Canv:TFPCustomCanvas; const rect:TRect; width:integer);
  435. begin
  436. FillRectangleHashBackDiagonal (Canv, rect, width, Canv.Brush.FPColor);
  437. end;
  438. procedure FillRectangleHashBackDiagonal (Canv:TFPCustomCanvas; const rect:TRect; width:integer; const c:TFPColor);
  439. function CheckInversCorner (Current, min, start : integer) : integer;
  440. begin
  441. if Current < min then
  442. result := Start - current + min
  443. else
  444. result := Start;
  445. end;
  446. function CheckCorner (Current, max, start : integer) : integer;
  447. begin
  448. if Current > max then
  449. result := Start - current + max
  450. else
  451. result := Start;
  452. end;
  453. var r, rx, ry : integer;
  454. begin
  455. with rect do
  456. begin
  457. // draw from bottom-left corner away
  458. ry := bottom - Width;
  459. rx := left + Width;
  460. while (rx < right) and (ry > top) do
  461. begin
  462. DrawSolidLine (Canv, left,ry, rx,bottom, c);
  463. inc (rx, Width);
  464. dec (ry, Width);
  465. end;
  466. // check which turn need to be taken: left-top, right-bottom, or both
  467. if (rx >= right) then
  468. begin
  469. if (ry <= top) then
  470. begin // Both corners reached
  471. r := CheckCorner (rx, right, bottom);
  472. rx := CheckInversCorner (ry, top, left);
  473. ry := r;
  474. end
  475. else
  476. begin // fill vertical
  477. r := CheckCorner (rx, right, bottom);
  478. while (ry > top) do
  479. begin
  480. DrawSolidLine (Canv, left,ry, right,r, c);
  481. dec (r, Width);
  482. dec (ry, Width);
  483. end;
  484. rx := CheckInversCorner (ry, top, left);
  485. ry := r;
  486. end
  487. end
  488. else
  489. if (ry <= top) then
  490. begin // fill horizontal
  491. r := checkInversCorner (ry, top, left);
  492. while (rx < right) do
  493. begin
  494. DrawSolidLine (Canv, r,top, rx,bottom, c);
  495. inc (r, Width);
  496. inc (rx, Width);
  497. end;
  498. ry := CheckCorner (rx, right, bottom);
  499. rx := r;
  500. end;
  501. while (rx < right) do // fill upper right corner
  502. begin
  503. DrawSolidLine (Canv, rx,top, right,ry, c);
  504. inc (rx, Width);
  505. dec (ry, Width);
  506. end;
  507. end;
  508. end;
  509. procedure FillRectanglePattern (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; const pattern:TBrushPattern);
  510. begin
  511. FillRectanglePattern (Canv, x1,y1, x2,y2, pattern, Canv.Brush.FPColor);
  512. end;
  513. procedure FillRectanglePattern (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; const pattern:TBrushPattern; const color:TFPColor);
  514. var r : integer;
  515. begin
  516. for r := y1 to y2 do
  517. DrawPatternLine (Canv, x1,r, x2,r, pattern[r mod PatternBitCount], color);
  518. end;
  519. procedure FillRectangleImage (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; const Image:TFPCustomImage);
  520. var x,y : integer;
  521. begin
  522. with image do
  523. for x := x1 to x2 do
  524. for y := y1 to y2 do
  525. Canv.colors[x,y] := colors[x mod width, y mod height];
  526. end;
  527. procedure FillRectangleImageRel (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; const Image:TFPCustomImage);
  528. var x,y : integer;
  529. begin
  530. with image do
  531. for x := x1 to x2 do
  532. for y := y1 to y2 do
  533. Canv.colors[x,y] := colors[(x-x1) mod width, (y-y1) mod height];
  534. end;
  535. type
  536. TFuncSetColor = procedure (Canv:TFPCustomCanvas; x,y:integer; data:pointer);
  537. PDoneRec = ^TDoneRec;
  538. TDoneRec = record
  539. x, min, max : integer;
  540. next : PDoneRec;
  541. end;
  542. PFloodFillData = ^TFloodFillData;
  543. TFloodFillData = record
  544. Canv : TFPCustomCanvas;
  545. ReplColor : TFPColor;
  546. SetColor : TFuncSetColor;
  547. ExtraData : pointer;
  548. DoneList : TList;
  549. end;
  550. function FindDoneIndex (const data:PFloodFillData; x:integer; var index:integer):boolean;
  551. begin
  552. with data^.DoneList do
  553. begin
  554. index := 0;
  555. while (index < count) and (PDoneRec(items[index])^.x <> x) do
  556. inc (index);
  557. result := (index < count) and (PDoneRec(items[index])^.x = x);
  558. end;
  559. end;
  560. procedure FreeDoneList (const data:TFloodFillData);
  561. procedure FreeList (p:PDoneRec);
  562. var n : PDoneRec;
  563. begin
  564. while assigned(p) do
  565. begin
  566. n := p^.Next;
  567. dispose (p);
  568. p := n;
  569. end;
  570. end;
  571. var r : integer;
  572. begin
  573. with data do
  574. for r := 0 to DoneList.Count-1 do
  575. FreeList (PDoneRec(DoneList[r]));
  576. end;
  577. procedure CheckFloodFillColor (x,top,bottom,Direction:integer; data:PFloodFillData);
  578. procedure CheckRange;
  579. var r,t,b : integer;
  580. begin
  581. t := top;
  582. b := top -1;
  583. for r := top to bottom do
  584. with data^ do
  585. begin
  586. if canv.colors[x,r] = ReplColor then
  587. begin
  588. b := r;
  589. SetColor(Canv,x,r,ExtraData);
  590. end
  591. else
  592. begin
  593. if t < r then
  594. CheckFloodFillColor (x+Direction, t, r-1, Direction, data);
  595. t := r + 1;
  596. end;
  597. end;
  598. if t <= b then
  599. CheckFloodFillColor (x+Direction, t, b, Direction, data);
  600. end;
  601. procedure CheckAboveRange;
  602. var t,b : integer;
  603. begin
  604. with data^ do
  605. begin
  606. t := top - 1;
  607. while (t >= 0) and (Canv.colors[x,t]=ReplColor) do
  608. begin
  609. SetColor(Canv, x,t, ExtraData);
  610. dec (t);
  611. end;
  612. t := t + 1;
  613. b := top - 1;
  614. if t <= b then
  615. begin
  616. CheckFloodFillColor (x-1, t, b, -1, data);
  617. CheckFloodFillColor (x+1, t, b, 1, data);
  618. end;
  619. end;
  620. end;
  621. procedure CheckBelowRange;
  622. var r,t,b : integer;
  623. begin
  624. with data^ do
  625. begin
  626. r := Canv.Height;
  627. b := bottom + 1;
  628. t := b;
  629. while (b < r) and (Canv.colors[x,b]=ReplColor) do
  630. begin
  631. SetColor (Canv,x,b,ExtraData);
  632. inc (b);
  633. end;
  634. b := b - 1;
  635. if t <= b then
  636. begin
  637. CheckFloodFillColor (x-1, t, b, -1, data);
  638. CheckFloodFillColor (x+1, t, b, 1, data);
  639. end;
  640. end;
  641. end;
  642. var DoAbove, DoBelow : boolean;
  643. begin
  644. with data^ do
  645. begin
  646. if (x >= Canv.width) or (x < 0) then
  647. Exit;
  648. if top < 0 then
  649. top := 0;
  650. if bottom >= Canv.Height then
  651. bottom := Canv.Height-1;
  652. DoAbove := (Canv.colors[x,top] = ReplColor);
  653. DoBelow := (Canv.colors[x,bottom] = ReplColor);
  654. end;
  655. CheckRange;
  656. if DoAbove then
  657. CheckAboveRange;
  658. if DoBelow then
  659. CheckBelowRange;
  660. end;
  661. procedure CheckFloodFill (x,top,bottom,Direction:integer; data:PFloodFillData);
  662. var beforetop, ontop, chain, myrec : PDoneRec;
  663. doneindex : integer;
  664. procedure CheckRange;
  665. var r,t,b : integer;
  666. n : PDoneRec;
  667. begin
  668. ontop := nil;
  669. beforetop := nil;
  670. n := chain;
  671. while (n <> nil) and (n^.min <= top) do
  672. begin
  673. beforetop := ontop;
  674. ontop := n;
  675. n := n^.next;
  676. end;
  677. if assigned(ontop) and (ontop^.max < top) then
  678. begin
  679. beforetop := ontop;
  680. ontop := nil;
  681. end;
  682. // ontop is: nil OR rec before top OR rec containing top
  683. if assigned(ontop) then
  684. begin
  685. t := ontop^.max + 1;
  686. myrec := ontop;
  687. end
  688. else
  689. begin
  690. t := top;
  691. new(myrec);
  692. myrec^.x := x;
  693. myrec^.min := top;
  694. myrec^.max := top;
  695. myrec^.Next := n;
  696. if assigned(beforetop) then
  697. beforetop^.next := myrec
  698. else
  699. begin
  700. with data^.DoneList do
  701. if DoneIndex < Count then
  702. Items[DoneIndex] := myrec
  703. else
  704. Add (myrec);
  705. chain := myrec;
  706. end;
  707. end;
  708. ontop := myrec;
  709. // ontop is rec containing the top
  710. b := t-1;
  711. r := t;
  712. while (r <= bottom) do
  713. begin
  714. with data^ do
  715. begin
  716. if canv.colors[x,r] = ReplColor then
  717. begin
  718. b := r;
  719. SetColor(Canv,x,r,ExtraData);
  720. end
  721. else
  722. begin
  723. if t < r then
  724. begin
  725. myrec^.max := r;
  726. CheckFloodFill (x+Direction, t, r-1, Direction, data);
  727. end;
  728. t := r + 1;
  729. end;
  730. inc (r);
  731. end;
  732. if assigned(n) and (r >= n^.min) then
  733. begin
  734. if t < r then
  735. begin
  736. myrec^.max := n^.min-1;
  737. CheckFloodFill (x+Direction, t, r-1, Direction, data);
  738. end;
  739. while assigned(n) and (r >= n^.min) do
  740. begin
  741. myrec := n;
  742. r := myrec^.max + 1;
  743. n := n^.next;
  744. end;
  745. t := r;
  746. end;
  747. end;
  748. myrec^.max := r - 1;
  749. if t <= b then
  750. CheckFloodFill (x+Direction, t, b, Direction, data);
  751. end;
  752. procedure CheckAboveRange (highest:integer);
  753. var t,b : integer;
  754. begin
  755. with data^ do
  756. begin
  757. t := top - 1;
  758. while (t >= highest) and (Canv.colors[x,t]=ReplColor) do
  759. begin
  760. SetColor(Canv, x,t, ExtraData);
  761. dec (t);
  762. end;
  763. t := t + 1;
  764. b := top - 1;
  765. if t <= b then
  766. begin
  767. ontop^.min := t - 1;
  768. CheckFloodFill (x-1, t, b, -1, data);
  769. CheckFloodFill (x+1, t, b, 1, data);
  770. end;
  771. end;
  772. end;
  773. procedure CheckBelowRange (lowest : integer);
  774. var t,b : integer;
  775. begin
  776. with data^ do
  777. begin
  778. b := bottom + 1;
  779. t := b;
  780. while (b <= lowest) and (Canv.colors[x,b]=ReplColor) do
  781. begin
  782. SetColor (Canv,x,b,ExtraData);
  783. inc (b);
  784. end;
  785. b := b - 1;
  786. if t <= b then
  787. begin
  788. myrec^.max := b+1;
  789. CheckFloodFill (x-1, t, b, -1, data);
  790. CheckFloodFill (x+1, t, b, 1, data);
  791. end;
  792. end;
  793. end;
  794. var DoAbove, DoBelow : boolean;
  795. m : integer;
  796. begin
  797. with data^ do
  798. begin
  799. if (x >= Canv.width) or (x < 0) then
  800. Exit;
  801. if top < 0 then
  802. top := 0;
  803. if bottom >= Canv.Height then
  804. bottom := Canv.Height-1;
  805. DoAbove := (Canv.colors[x,top] = ReplColor);
  806. DoBelow := (Canv.colors[x,bottom] = ReplColor);
  807. end;
  808. if FindDoneIndex (data, x, DoneIndex) then
  809. begin
  810. chain := PDoneRec(data^.DoneList[DoneIndex]);
  811. myrec := chain;
  812. while assigned(myrec) do
  813. with myrec^ do
  814. myrec := next;
  815. end
  816. else
  817. chain := nil;
  818. CheckRange;
  819. // ontop: rec containing top
  820. // myrec: rec containing bottom
  821. if DoAbove and (ontop^.min = top) then
  822. begin
  823. if assigned (beforetop) then
  824. m := beforetop^.max + 1
  825. else
  826. m := 0;
  827. CheckAboveRange (m);
  828. end;
  829. if DoBelow and (myrec^.max = bottom) then
  830. begin
  831. if assigned (myrec^.next) then
  832. m := myrec^.next^.min - 1
  833. else
  834. m := data^.Canv.Height - 1;
  835. CheckBelowRange (m);
  836. end;
  837. end;
  838. procedure SetFloodColor (Canv:TFPCustomCanvas; x,y:integer; data:pointer);
  839. begin
  840. Canv.colors[x,y] := PFPColor(data)^;
  841. end;
  842. procedure FillFloodColor (Canv:TFPCustomCanvas; x,y:integer; const color:TFPColor);
  843. var d : TFloodFillData;
  844. begin
  845. d.Canv := canv;
  846. d.ReplColor := Canv.colors[x,y];
  847. d.SetColor := @SetFloodColor;
  848. d.ExtraData := @color;
  849. CheckFloodFillColor (x, y, y, 1, @d);
  850. end;
  851. procedure FillFloodColor (Canv:TFPCustomCanvas; x,y:integer);
  852. begin
  853. FillFloodColor (Canv, x, y, Canv.Brush.FPColor);
  854. end;
  855. type
  856. TBoolPlane = array[0..PatternBitCount-1] of TLinePoints;
  857. TFloodPatternRec = record
  858. plane : TBoolPlane;
  859. color : TFPColor;
  860. end;
  861. PFloodPatternRec = ^TFloodPatternRec;
  862. procedure SetFloodPattern (Canv:TFPCustomCanvas; x,y:integer; data:pointer);
  863. var p : PFloodPatternRec;
  864. begin
  865. p := PFloodPatternRec(data);
  866. if p^.plane[x mod PatternBitCount, y mod PatternBitCount] then
  867. Canv.colors[x,y] := p^.color;
  868. end;
  869. procedure FillFloodPattern (Canv:TFPCustomCanvas; x,y:integer; const pattern:TBrushPattern; const color:TFPColor);
  870. var rec : TFloodPatternRec;
  871. d : TFloodFillData;
  872. procedure FillPattern;
  873. var r : integer;
  874. begin
  875. for r := 0 to PatternBitCount-1 do
  876. PatternToPoints (pattern[r], @rec.plane[r]);
  877. end;
  878. begin
  879. d.Canv := canv;
  880. d.ReplColor := Canv.colors[x,y];
  881. d.SetColor := @SetFloodPattern;
  882. d.ExtraData := @rec;
  883. d.DoneList := TList.Create;
  884. try
  885. FillPattern;
  886. rec.color := Color;
  887. CheckFloodFill (x, y, y, 1, @d);
  888. finally
  889. FreeDoneList (d);
  890. end;
  891. end;
  892. procedure FillFloodPattern (Canv:TFPCustomCanvas; x,y:integer; const pattern:TBrushPattern);
  893. begin
  894. FillFloodPattern (Canv, x, y, pattern, Canv.Brush.FPColor);
  895. end;
  896. type
  897. TFloodHashRec = record
  898. color : TFPColor;
  899. width : integer;
  900. end;
  901. PFloodHashRec = ^TFloodHashRec;
  902. procedure SetFloodHashHor(Canv:TFPCustomCanvas; x,y:integer; data:pointer);
  903. var r : PFloodHashRec;
  904. begin
  905. r := PFloodHashRec(data);
  906. if (y mod r^.width) = 0 then
  907. Canv.colors[x,y] := r^.color;
  908. end;
  909. procedure SetFloodHashVer(Canv:TFPCustomCanvas; x,y:integer; data:pointer);
  910. var r : PFloodHashRec;
  911. begin
  912. r := PFloodHashRec(data);
  913. if (x mod r^.width) = 0 then
  914. Canv.colors[x,y] := r^.color;
  915. end;
  916. procedure SetFloodHashDiag(Canv:TFPCustomCanvas; x,y:integer; data:pointer);
  917. var r : PFloodHashRec;
  918. w : integer;
  919. begin
  920. r := PFloodHashRec(data);
  921. w := r^.width;
  922. if ((x mod w) + (y mod w)) = (w - 1) then
  923. Canv.colors[x,y] := r^.color;
  924. end;
  925. procedure SetFloodHashBDiag(Canv:TFPCustomCanvas; x,y:integer; data:pointer);
  926. var r : PFloodHashRec;
  927. w : 0..PatternBitCount-1;
  928. begin
  929. r := PFloodHashRec(data);
  930. w := r^.width;
  931. if (x mod w) = (y mod w) then
  932. Canv.colors[x,y] := r^.color;
  933. end;
  934. procedure SetFloodHashCross(Canv:TFPCustomCanvas; x,y:integer; data:pointer);
  935. var r : PFloodHashRec;
  936. w : 0..PatternBitCount-1;
  937. begin
  938. r := PFloodHashRec(data);
  939. w := r^.width;
  940. if ((x mod w) = 0) or ((y mod w) = 0) then
  941. Canv.colors[x,y] := r^.color;
  942. end;
  943. procedure SetFloodHashDiagCross(Canv:TFPCustomCanvas; x,y:integer; data:pointer);
  944. var r : PFloodHashRec;
  945. w : 0..PatternBitCount-1;
  946. begin
  947. r := PFloodHashRec(data);
  948. w := r^.width;
  949. if ( (x mod w) = (y mod w) ) or
  950. ( ((x mod w) + (y mod w)) = (w - 1) ) then
  951. Canv.colors[x,y] := r^.color;
  952. end;
  953. procedure FillFloodHash (Canv:TFPCustomCanvas; x,y:integer; width:integer; SetHashColor:TFuncSetColor; const c:TFPColor);
  954. var rec : TFloodHashRec;
  955. d : TFloodFillData;
  956. begin
  957. d.Canv := canv;
  958. d.ReplColor := Canv.colors[x,y];
  959. d.SetColor := SetHashColor;
  960. d.ExtraData := @rec;
  961. d.DoneList := TList.Create;
  962. rec.color := c;
  963. rec.width := Width;
  964. try
  965. CheckFloodFill (x, y, y, 1, @d);
  966. finally
  967. FreeDoneList (d);
  968. end;
  969. end;
  970. procedure FillFloodHashHorizontal (Canv:TFPCustomCanvas; x,y:integer; width:integer; const c:TFPColor);
  971. begin
  972. FillFloodHash (canv, x, y, width, @SetFloodHashHor, c);
  973. end;
  974. procedure FillFloodHashHorizontal (Canv:TFPCustomCanvas; x,y:integer; width:integer);
  975. begin
  976. FillFloodHashHorizontal (Canv, x, y, width, Canv.Brush.FPColor);
  977. end;
  978. procedure FillFloodHashVertical (Canv:TFPCustomCanvas; x,y:integer; width:integer; const c:TFPColor);
  979. begin
  980. FillFloodHash (canv, x, y, width, @SetFloodHashVer, c);
  981. end;
  982. procedure FillFloodHashVertical (Canv:TFPCustomCanvas; x,y:integer; width:integer);
  983. begin
  984. FillFloodHashVertical (Canv, x, y, width, Canv.Brush.FPColor);
  985. end;
  986. procedure FillFloodHashDiagonal (Canv:TFPCustomCanvas; x,y:integer; width:integer; const c:TFPColor);
  987. begin
  988. FillFloodHash (canv, x, y, width, @SetFloodHashDiag, c);
  989. end;
  990. procedure FillFloodHashDiagonal (Canv:TFPCustomCanvas; x,y:integer; width:integer);
  991. begin
  992. FillFloodHashDiagonal (Canv, x, y, width, Canv.Brush.FPColor);
  993. end;
  994. procedure FillFloodHashBackDiagonal (Canv:TFPCustomCanvas; x,y:integer; width:integer; const c:TFPColor);
  995. begin
  996. FillFloodHash (canv, x, y, width, @SetFloodHashBDiag, c);
  997. end;
  998. procedure FillFloodHashBackDiagonal (Canv:TFPCustomCanvas; x,y:integer; width:integer);
  999. begin
  1000. FillFloodHashBackDiagonal (Canv, x, y, width, Canv.Brush.FPColor);
  1001. end;
  1002. procedure FillFloodHashDiagCross (Canv:TFPCustomCanvas; x,y:integer; width:integer; const c:TFPColor);
  1003. begin
  1004. FillFloodHash (canv, x, y, width, @SetFloodHashDiagCross, c);
  1005. end;
  1006. procedure FillFloodHashDiagCross (Canv:TFPCustomCanvas; x,y:integer; width:integer);
  1007. begin
  1008. FillFloodHashDiagCross (Canv, x, y, width, Canv.Brush.FPColor);
  1009. end;
  1010. procedure FillFloodHashCross (Canv:TFPCustomCanvas; x,y:integer; width:integer; const c:TFPColor);
  1011. begin
  1012. FillFloodHash (canv, x, y, width, @SetFloodHashCross, c);
  1013. end;
  1014. procedure FillFloodHashCross (Canv:TFPCustomCanvas; x,y:integer; width:integer);
  1015. begin
  1016. FillFloodHashCross (Canv, x, y, width, Canv.Brush.FPColor);
  1017. end;
  1018. type
  1019. TFloodImageRec = record
  1020. xo,yo : integer;
  1021. image : TFPCustomImage;
  1022. end;
  1023. PFloodImageRec = ^TFloodImageRec;
  1024. procedure SetFloodImage (Canv:TFPCustomCanvas; x,y:integer; data:pointer);
  1025. var r : PFloodImageRec;
  1026. begin
  1027. r := PFloodImageRec(data);
  1028. with r^.image do
  1029. Canv.colors[x,y] := colors[x mod width, y mod height];
  1030. end;
  1031. procedure FillFloodImage (Canv:TFPCustomCanvas; x,y :integer; const Image:TFPCustomImage);
  1032. var rec : TFloodImageRec;
  1033. d : TFloodFillData;
  1034. begin
  1035. d.Canv := canv;
  1036. d.ReplColor := Canv.colors[x,y];
  1037. d.SetColor := @SetFloodImage;
  1038. d.ExtraData := @rec;
  1039. d.DoneList := Tlist.Create;
  1040. rec.image := image;
  1041. try
  1042. CheckFloodFill (x, y, y, 1, @d);
  1043. finally
  1044. FreeDoneList (d);
  1045. end;
  1046. end;
  1047. procedure SetFloodImageRel (Canv:TFPCustomCanvas; x,y:integer; data:pointer);
  1048. var r : PFloodImageRec;
  1049. xi, yi : integer;
  1050. begin
  1051. r := PFloodImageRec(data);
  1052. with r^, image do
  1053. begin
  1054. xi := (x - xo) mod width;
  1055. if xi < 0 then
  1056. xi := width - xi;
  1057. yi := (y - yo) mod height;
  1058. if yi < 0 then
  1059. yi := height - yi;
  1060. Canv.colors[x,y] := colors[xi,yi];
  1061. end;
  1062. end;
  1063. procedure FillFloodImageRel (Canv:TFPCustomCanvas; x,y :integer; const Image:TFPCustomImage);
  1064. var rec : TFloodImageRec;
  1065. d : TFloodFillData;
  1066. begin
  1067. d.Canv := canv;
  1068. d.ReplColor := Canv.colors[x,y];
  1069. d.SetColor := @SetFloodImageRel;
  1070. d.ExtraData := @rec;
  1071. d.DoneList := TList.Create;
  1072. rec.image := image;
  1073. rec.xo := x;
  1074. rec.yo := y;
  1075. try
  1076. CheckFloodFill (x, y, y, 1, @d);
  1077. finally
  1078. FreeDoneList (d);
  1079. end;
  1080. end;
  1081. end.