pixtools.pp 31 KB

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