FlatWatet.pas 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. unit FlatWatet;
  2. interface
  3. {$I FlatStyle.inc}
  4. uses
  5. Windows, SysUtils, Graphics, Math;
  6. const
  7. csDefDamping = 20;
  8. RAND_MAX = $7FFF;
  9. type
  10. PIntArray = ^TIntArray;
  11. TIntArray = array[0..65535] of Integer;
  12. PPIntArray = ^TPIntArray;
  13. TPIntArray = array[0..65535] of PIntArray;
  14. PRGBArray = ^TRGBArray;
  15. TRGBArray = array[0..65535] of TRGBTriple;
  16. PPRGBArray = ^TPRGBArray;
  17. TPRGBArray = array[0..65535] of PRGBArray;
  18. TWaterDamping = 1..99;
  19. TDefineWatet = class(TObject)
  20. private
  21. FWaterWidth: Integer;
  22. FWaterHeight: Integer;
  23. FWaterBuff1: Pointer;
  24. FWaterBuff2: Pointer;
  25. FScanLine1: PPIntArray;
  26. FScanLine2: PPIntArray;
  27. FScanLineSrc: PPRGBArray;
  28. FDamping: TWaterDamping;
  29. protected
  30. procedure CalcWater;
  31. procedure SetDamping(Value: TWaterDamping);
  32. procedure ClearWater;
  33. public
  34. constructor Create;
  35. destructor Destroy; override;
  36. procedure SetSize(Bitmap: TBitmap);
  37. procedure Render(Src, Dst: TBitmap);
  38. procedure Blob(x, y: Integer; ARadius, AHeight: Integer);
  39. property Damping: TWaterDamping read FDamping write SetDamping;
  40. end;
  41. implementation
  42. { TWater }
  43. procedure TDefineWatet.Blob(x, y, ARadius, AHeight: Integer);
  44. var
  45. Rquad: Integer;
  46. cx, cy, cyq: Integer;
  47. WaterLeft, WaterTop, WaterRight, WaterBottom: Integer;
  48. begin
  49. if (x < 0) or (x > FWaterWidth - 1) then
  50. x := 1 + ARadius + Random(RAND_MAX) mod (FWaterWidth - 2 * ARadius - 1);
  51. if (y < 0) or (y > FWaterHeight - 1) then
  52. y := 1 + ARadius + Random(RAND_MAX) mod (FWaterHeight - 2 * ARadius - 1);
  53. WaterLeft := -Min(x, ARadius);
  54. WaterRight := Min(FWaterWidth - 1 - x, ARadius);
  55. WaterTop := -Min(y, ARadius);
  56. WaterBottom := Min(FWaterHeight - 1 - y, ARadius);
  57. Rquad := ARadius * ARadius;
  58. for cy := WaterTop to WaterBottom do
  59. begin
  60. cyq := cy * cy;
  61. for cx := WaterLeft to WaterRight do
  62. begin
  63. if (cx * cx + cyq <= Rquad) then
  64. begin
  65. Inc(FScanLine1[cy + y][cx + x], AHeight);
  66. end;
  67. end;
  68. end;
  69. end;
  70. procedure TDefineWatet.CalcWater;
  71. var
  72. x, y, xl, xr: Integer;
  73. NewH: Integer;
  74. P, P1, P2, P3: PIntArray;
  75. PT: Pointer;
  76. Rate: Integer;
  77. begin
  78. Rate := (100 - FDamping) * 256 div 100;
  79. for y := 0 to FWaterHeight - 1 do
  80. begin
  81. P := FScanLine2[y];
  82. P1 := FScanLine1[Max(y - 1, 0)];
  83. P2 := FScanLine1[y];
  84. P3 := FScanLine1[Min(y + 1, FWaterHeight - 1)];
  85. for x := 0 to FWaterWidth - 1 do
  86. begin
  87. xl := Max(x - 1, 0);
  88. xr := Min(x + 1, FWaterWidth - 1);
  89. NewH := (P1[xl] + P1[x] + P1[xr] + P2[xl] + P2[xr] + P3[xl] + P3[x] + P3[xr]) div 4 - P[x];
  90. P[x] := NewH * Rate div 256;
  91. end;
  92. end;
  93. PT := FWaterBuff1;
  94. FWaterBuff1 := FWaterBuff2;
  95. FWaterBuff2 := PT;
  96. PT := FScanLine1;
  97. FScanLine1 := FScanLine2;
  98. FScanLine2 := PT;
  99. end;
  100. procedure TDefineWatet.ClearWater;
  101. begin
  102. if FWaterBuff1 <> nil then
  103. ZeroMemory(FWaterBuff1, (FWaterWidth * FWaterHeight) * SizeOf(Integer));
  104. if FWaterBuff2 <> nil then
  105. ZeroMemory(FWaterBuff2, (FWaterWidth * FWaterHeight) * SizeOf(Integer));
  106. end;
  107. constructor TDefineWatet.Create;
  108. begin
  109. inherited;
  110. FDamping := csDefDamping;
  111. end;
  112. destructor TDefineWatet.Destroy;
  113. begin
  114. if FWaterBuff1 <> nil then
  115. FreeMem(FWaterBuff1);
  116. if FWaterBuff2 <> nil then
  117. FreeMem(FWaterBuff2);
  118. if FScanLine1 <> nil then
  119. FreeMem(FScanLine1);
  120. if FScanLine2 <> nil then
  121. FreeMem(FScanLine2);
  122. if FScanLineSrc <> nil then
  123. FreeMem(FScanLineSrc);
  124. inherited Destroy;
  125. end;
  126. procedure TDefineWatet.Render(Src, Dst: TBitmap);
  127. var
  128. dx, dy: Integer;
  129. i, c, x, y: Integer;
  130. P1, P2, P3: PIntArray;
  131. PSrc, PDst: PRGBArray;
  132. PSrcDot, PDstDot: PRGBTriple;
  133. BytesPerLine1, BytesPerLine2: Integer;
  134. begin
  135. CalcWater;
  136. Src.PixelFormat := pf24bit;
  137. Dst.PixelFormat := pf24bit;
  138. FScanLineSrc[0] := Src.ScanLine[0];
  139. BytesPerLine1 := Integer(Src.ScanLine[1]) - Integer(FScanLineSrc[0]);
  140. for i := 1 to FWaterHeight - 1 do
  141. FScanLineSrc[i] := PRGBArray(Integer(FScanLineSrc[i - 1]) + BytesPerLine1);
  142. PDst := Dst.ScanLine[0];
  143. BytesPerLine2 := Integer(Dst.ScanLine[1]) - Integer(PDst);
  144. for y := 0 to FWaterHeight - 1 do
  145. begin
  146. PSrc := FScanLineSrc[y];
  147. P1 := FScanLine1[Max(y - 1, 0)];
  148. P2 := FScanLine1[y];
  149. P3 := FScanLine1[Min(y + 1, FWaterHeight - 1)];
  150. for x := 0 to FWaterWidth - 1 do
  151. begin
  152. dx := P2[Max(x - 1, 0)] - P2[Min(x + 1, FWaterWidth - 1)];
  153. dy := P1[x] - P3[x];
  154. if (x + dx >= 0) and (x + dx < FWaterWidth) and (y + dy >= 0) and
  155. (y + dy < FWaterHeight) then
  156. begin
  157. PSrcDot := @FScanLineSrc[y + dy][x + dx];
  158. PDstDot := @PDst[x];
  159. c := PSrcDot.rgbtBlue - dx;
  160. if c < 0 then
  161. PDstDot.rgbtBlue := 0
  162. else if c > 255 then
  163. PDstDot.rgbtBlue := 255
  164. else
  165. PDstDot.rgbtBlue := c;
  166. c := PSrcDot.rgbtGreen - dx;
  167. if c < 0 then
  168. PDstDot.rgbtGreen := 0
  169. else if c > 255 then
  170. PDstDot.rgbtGreen := 255
  171. else
  172. PDstDot.rgbtGreen := c;
  173. c := PSrcDot.rgbtRed - dx;
  174. if c < 0 then
  175. PDstDot.rgbtRed := 0
  176. else if c > 255 then
  177. PDstDot.rgbtRed := 255
  178. else
  179. PDstDot.rgbtRed := c;
  180. end
  181. else
  182. begin
  183. PDst[x] := PSrc[x];
  184. end;
  185. end;
  186. PDst := PRGBArray(Integer(PDst) + BytesPerLine2);
  187. end;
  188. end;
  189. procedure TDefineWatet.SetDamping(Value: TWaterDamping);
  190. begin
  191. if (Value >= Low(TWaterDamping)) and (Value <= High(TWaterDamping)) then
  192. FDamping := Value;
  193. end;
  194. procedure TDefineWatet.SetSize;
  195. var
  196. i: Integer;
  197. begin
  198. FWaterWidth := Bitmap.Width;
  199. FWaterHeight := Bitmap.Height;
  200. if (FWaterWidth <= 0) or (FWaterHeight <= 0) then
  201. begin
  202. FWaterWidth := 0;
  203. FWaterHeight := 0;
  204. end;
  205. ReallocMem(FWaterBuff1, FWaterWidth * FWaterHeight * SizeOf(Integer));
  206. ReallocMem(FWaterBuff2, FWaterWidth * FWaterHeight * SizeOf(Integer));
  207. ReallocMem(FScanLine1, FWaterHeight * SizeOf(PIntArray));
  208. ReallocMem(FScanLine2, FWaterHeight * SizeOf(PIntArray));
  209. ReallocMem(FScanLineSrc, FWaterHeight * SizeOf(PRGBArray));
  210. ClearWater;
  211. if (FWaterHeight > 0)and(FWaterWidth > 0) then
  212. begin
  213. FScanLine1[0] := FWaterBuff1;
  214. FScanLine2[0] := FWaterBuff2;
  215. for i := 1 to FWaterHeight - 1 do
  216. begin
  217. //FScanLine1[i] := PIntArray(@FScanLine1[i - 1][FWaterWidth]);
  218. //FScanLine2[i] := PIntArray(@FScanLine2[i - 1][FWaterWidth]);
  219. FScanLine1[i] := @FScanLine1[i - 1][FWaterWidth];
  220. FScanLine2[i] := @FScanLine2[i - 1][FWaterWidth];
  221. end;
  222. end;
  223. end;
  224. end.