CnWaterEffect.pas 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. {******************************************************************************}
  2. { CnPack For Delphi/C++Builder }
  3. { 中国人自己的开放源码第三方开发包 }
  4. { (C)Copyright 2001-2018 CnPack 开发组 }
  5. { ------------------------------------ }
  6. { }
  7. { 本开发包是开源的自由软件,您可以遵照 CnPack 的发布协议来修 }
  8. { 改和重新发布这一程序。 }
  9. { }
  10. { 发布这一开发包的目的是希望它有用,但没有任何担保。甚至没有 }
  11. { 适合特定目的而隐含的担保。更详细的情况请参阅 CnPack 发布协议。 }
  12. { }
  13. { 您应该已经和开发包一起收到一份 CnPack 发布协议的副本。如果 }
  14. { 还没有,可访问我们的网站: }
  15. { }
  16. { 网站地址:http://www.cnpack.org }
  17. { 电子邮件:master@cnpack.org }
  18. { }
  19. {******************************************************************************}
  20. {******************************************************************************}
  21. { Unit Note: }
  22. { The formulas used in this class I found on a website }
  23. { http://freespace.virgin.net/hugo.elias/graphics/x_water.htm }
  24. { Reference: }
  25. { TortoiseSVN Source }
  26. { http://tortoisesvn.tigris.org/ }
  27. {******************************************************************************}
  28. unit CnWaterEffect;
  29. {* |<PRE>
  30. ================================================================================
  31. * 软件名称:界面控件包
  32. * 单元名称:水波效果处理单元
  33. * 单元作者:周劲羽 (zjy@cnpack.org)
  34. * 备 注:
  35. * 开发平台:PWinXP SP2 + Delphi 5.0
  36. * 兼容测试:PWin9X/2000/XP + Delphi 5/6
  37. * 本 地 化:该单元中的字符串均符合本地化处理方式
  38. * 单元标识:$Id$
  39. * 修改记录:2005.06.28
  40. 创建单元
  41. ================================================================================
  42. |</PRE>}
  43. interface
  44. {$I CnPack.inc}
  45. uses
  46. Windows, SysUtils, Graphics, Math;
  47. const
  48. csDefDamping = 20;
  49. type
  50. PIntArray = ^TIntArray;
  51. TIntArray = array[0..65535] of Integer;
  52. PPIntArray = ^TPIntArray;
  53. TPIntArray = array[0..65535] of PIntArray;
  54. PRGBArray = ^TRGBArray;
  55. TRGBArray = array[0..65535] of TRGBTriple;
  56. PPRGBArray = ^TPRGBArray;
  57. TPRGBArray = array[0..65535] of PRGBArray;
  58. TWaterDamping = 1..99;
  59. TCnWaterEffect = class(TObject)
  60. private
  61. FLightModifier: Integer;
  62. FWidth: Integer;
  63. FHeight: Integer;
  64. FBuff1: Pointer;
  65. FBuff2: Pointer;
  66. FScanLine1: PPIntArray;
  67. FScanLine2: PPIntArray;
  68. FScanLineSrc: PPRGBArray;
  69. FXLeft: PIntArray;
  70. FXRight: PIntArray;
  71. FYUp: PIntArray;
  72. FYDown: PIntArray;
  73. FDamping: TWaterDamping;
  74. procedure SetDamping(Value: TWaterDamping);
  75. protected
  76. procedure CalcWater;
  77. procedure DrawWater(ALightModifier: Integer; Src, Dst: TBitmap);
  78. public
  79. constructor Create;
  80. destructor Destroy; override;
  81. procedure ClearWater;
  82. procedure SetSize(AWidth, AHeight: Integer);
  83. procedure Render(Src, Dst: TBitmap);
  84. procedure Blob(x, y: Integer; ARadius, AHeight: Integer);
  85. property Damping: TWaterDamping read FDamping write SetDamping;
  86. end;
  87. implementation
  88. { TCnWaterEffect }
  89. const
  90. RAND_MAX = $7FFF;
  91. procedure TCnWaterEffect.Blob(x, y: Integer; ARadius, AHeight: Integer);
  92. var
  93. Rquad: Integer;
  94. cx, cy, cyq: Integer;
  95. Left, Top, Right, Bottom: Integer;
  96. begin
  97. if (x < 0) or (x > FWidth - 1) then
  98. x := 1 + ARadius + Random(RAND_MAX) mod (FWidth - 2 * ARadius - 1);
  99. if (y < 0) or (y > FHeight - 1) then
  100. y := 1 + ARadius + Random(RAND_MAX) mod (FHeight - 2 * ARadius - 1);
  101. Left := -Min(x, ARadius);
  102. Right := Min(FWidth - 1 - x, ARadius);
  103. Top := -Min(y, ARadius);
  104. Bottom := Min(FHeight - 1 - y, ARadius);
  105. Rquad := ARadius * ARadius;
  106. for cy := Top to Bottom do
  107. begin
  108. cyq := cy * cy;
  109. for cx := Left to Right do
  110. begin
  111. if (cx * cx + cyq <= Rquad) then
  112. begin
  113. Inc(FScanLine1[cy + y][cx + x], AHeight);
  114. end;
  115. end;
  116. end;
  117. end;
  118. procedure TCnWaterEffect.CalcWater;
  119. var
  120. x, y, xl, xr: Integer;
  121. NewH: Integer;
  122. P, P1, P2, P3: PIntArray;
  123. PT: Pointer;
  124. Rate: Integer;
  125. begin
  126. Rate := (100 - FDamping) * 256 div 100;
  127. for y := 0 to FHeight - 1 do
  128. begin
  129. P := FScanLine2[y];
  130. P1 := FScanLine1[FYUp[y]];
  131. P2 := FScanLine1[y];
  132. P3 := FScanLine1[FYDown[y]];
  133. for x := 0 to FWidth - 1 do
  134. begin
  135. xl := FXLeft[x];
  136. xr := FXRight[x];
  137. NewH := (P1[xl] + P1[x] + P1[xr] + P2[xl] + P2[xr] + P3[xl] + P3[x] +
  138. P3[xr]) div 4 - P[x];
  139. P[x] := NewH * Rate div 256;
  140. end;
  141. end;
  142. PT := FBuff1;
  143. FBuff1 := FBuff2;
  144. FBuff2 := PT;
  145. PT := FScanLine1;
  146. FScanLine1 := FScanLine2;
  147. FScanLine2 := PT;
  148. end;
  149. procedure TCnWaterEffect.ClearWater;
  150. begin
  151. if FBuff1 <> nil then
  152. ZeroMemory(FBuff1, (FWidth * FHeight) * SizeOf(Integer));
  153. if FBuff2 <> nil then
  154. ZeroMemory(FBuff2, (FWidth * FHeight) * SizeOf(Integer));
  155. end;
  156. constructor TCnWaterEffect.Create;
  157. begin
  158. inherited;
  159. FLightModifier := 10;
  160. FDamping := csDefDamping;
  161. end;
  162. destructor TCnWaterEffect.Destroy;
  163. begin
  164. if FBuff1 <> nil then
  165. FreeMem(FBuff1);
  166. if FBuff2 <> nil then
  167. FreeMem(FBuff2);
  168. if FScanLine1 <> nil then
  169. FreeMem(FScanLine1);
  170. if FScanLine2 <> nil then
  171. FreeMem(FScanLine2);
  172. if FScanLineSrc <> nil then
  173. FreeMem(FScanLineSrc);
  174. if FXLeft <> nil then
  175. FreeMem(FXLeft);
  176. if FXRight <> nil then
  177. FreeMem(FXRight);
  178. if FYUp <> nil then
  179. FreeMem(FYUp);
  180. if FYDown <> nil then
  181. FreeMem(FYDown);
  182. inherited;
  183. end;
  184. procedure TCnWaterEffect.DrawWater(ALightModifier: Integer; Src, Dst:
  185. TBitmap);
  186. var
  187. dx, dy: Integer;
  188. i, c, x, y: Integer;
  189. P1, P2, P3: PIntArray;
  190. PDst: PRGBArray;
  191. PSrcDot, PDstDot: PRGBTriple;
  192. BytesPerLine1, BytesPerLine2: Integer;
  193. begin
  194. // 先将源图复制到目标图,如果有变化的再在后面按点处理
  195. Src.PixelFormat := pf24bit;
  196. Dst.PixelFormat := pf24bit;
  197. BitBlt(Dst.Canvas.Handle, 0, 0, Src.Width, Src.Height, Src.Canvas.Handle, 0, 0, SRCCOPY);
  198. FScanLineSrc[0] := Src.ScanLine[0];
  199. BytesPerLine1 := Integer(Src.ScanLine[1]) - Integer(FScanLineSrc[0]);
  200. for i := 1 to FHeight - 1 do
  201. FScanLineSrc[i] := PRGBArray(Integer(FScanLineSrc[i - 1]) + BytesPerLine1);
  202. PDst := Dst.ScanLine[0];
  203. BytesPerLine2 := Integer(Dst.ScanLine[1]) - Integer(PDst);
  204. for y := 0 to FHeight - 1 do
  205. begin
  206. P1 := FScanLine1[FYUp[y]];
  207. P2 := FScanLine1[y];
  208. P3 := FScanLine1[FYDown[y]];
  209. for x := 0 to FWidth - 1 do
  210. begin
  211. dx := P2[FXLeft[x]] - P2[FXRight[x]];
  212. dy := P1[x] - P3[x];
  213. if (dx = 0) and (dy = 0) then
  214. begin
  215. Continue;
  216. end;
  217. if (x + dx >= 0) and (x + dx < FWidth) and (y + dy >= 0) and
  218. (y + dy < FHeight) then
  219. begin
  220. PSrcDot := @FScanLineSrc[y + dy][x + dx];
  221. PDstDot := @PDst[x];
  222. c := PSrcDot.rgbtBlue - dx;
  223. if c < 0 then
  224. PDstDot.rgbtBlue := 0
  225. else if c > 255 then
  226. PDstDot.rgbtBlue := 255
  227. else
  228. PDstDot.rgbtBlue := c;
  229. c := PSrcDot.rgbtGreen - dx;
  230. if c < 0 then
  231. PDstDot.rgbtGreen := 0
  232. else if c > 255 then
  233. PDstDot.rgbtGreen := 255
  234. else
  235. PDstDot.rgbtGreen := c;
  236. c := PSrcDot.rgbtRed - dx;
  237. if c < 0 then
  238. PDstDot.rgbtRed := 0
  239. else if c > 255 then
  240. PDstDot.rgbtRed := 255
  241. else
  242. PDstDot.rgbtRed := c;
  243. end;
  244. end;
  245. PDst := PRGBArray(Integer(PDst) + BytesPerLine2);
  246. end;
  247. end;
  248. procedure TCnWaterEffect.Render(Src, Dst: TBitmap);
  249. begin
  250. if (FWidth > 0) and (FHeight > 0) then
  251. begin
  252. CalcWater;
  253. DrawWater(FLightModifier, Src, Dst);
  254. end;
  255. end;
  256. procedure TCnWaterEffect.SetDamping(Value: TWaterDamping);
  257. begin
  258. if (Value >= Low(TWaterDamping)) and (Value <= High(TWaterDamping)) then
  259. FDamping := Value;
  260. end;
  261. procedure TCnWaterEffect.SetSize(AWidth, AHeight: Integer);
  262. var
  263. i: Integer;
  264. begin
  265. if (AWidth <= 0) or (AHeight <= 0) then
  266. begin
  267. AWidth := 0;
  268. AHeight := 0;
  269. end;
  270. FWidth := AWidth;
  271. FHeight := AHeight;
  272. ReallocMem(FBuff1, FWidth * FHeight * SizeOf(Integer));
  273. ReallocMem(FBuff2, FWidth * FHeight * SizeOf(Integer));
  274. ReallocMem(FScanLine1, FHeight * SizeOf(PIntArray));
  275. ReallocMem(FScanLine2, FHeight * SizeOf(PIntArray));
  276. ReallocMem(FScanLineSrc, FHeight * SizeOf(PRGBArray));
  277. ReallocMem(FXLeft, FWidth * SizeOf(Integer));
  278. ReallocMem(FXRight, FWidth * SizeOf(Integer));
  279. ReallocMem(FYUp, FHeight * SizeOf(Integer));
  280. ReallocMem(FYDown, FHeight * SizeOf(Integer));
  281. ClearWater;
  282. if FHeight > 0 then
  283. begin
  284. FScanLine1[0] := FBuff1;
  285. FScanLine2[0] := FBuff2;
  286. for i := 1 to FHeight - 1 do
  287. begin
  288. FScanLine1[i] := @FScanLine1[i - 1][FWidth];
  289. FScanLine2[i] := @FScanLine2[i - 1][FWidth];
  290. end;
  291. for i := 0 to FHeight - 1 do
  292. begin
  293. FYUp[i] := Max(i - 1, 0);
  294. FYDown[i] := Min(i + 1, FHeight - 1);
  295. end;
  296. end;
  297. if FWidth > 0 then
  298. begin
  299. for i := 0 to FWidth - 1 do
  300. begin
  301. FXLeft[i] := Max(i - 1, 0);
  302. FXRight[i] := Min(i + 1, FWidth - 1);
  303. end;
  304. end;
  305. end;
  306. end.