| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 |
- unit FlatWatet;
- interface
- {$I FlatStyle.inc}
- uses
- Windows, SysUtils, Graphics, Math;
- const
- csDefDamping = 20;
- RAND_MAX = $7FFF;
- type
- PIntArray = ^TIntArray;
- TIntArray = array[0..65535] of Integer;
-
- PPIntArray = ^TPIntArray;
- TPIntArray = array[0..65535] of PIntArray;
- PRGBArray = ^TRGBArray;
- TRGBArray = array[0..65535] of TRGBTriple;
- PPRGBArray = ^TPRGBArray;
- TPRGBArray = array[0..65535] of PRGBArray;
- TWaterDamping = 1..99;
- TDefineWatet = class(TObject)
- private
- FWaterWidth: Integer;
- FWaterHeight: Integer;
- FWaterBuff1: Pointer;
- FWaterBuff2: Pointer;
- FScanLine1: PPIntArray;
- FScanLine2: PPIntArray;
- FScanLineSrc: PPRGBArray;
- FDamping: TWaterDamping;
- protected
- procedure CalcWater;
- procedure SetDamping(Value: TWaterDamping);
- procedure ClearWater;
- public
- constructor Create;
- destructor Destroy; override;
- procedure SetSize(Bitmap: TBitmap);
- procedure Render(Src, Dst: TBitmap);
- procedure Blob(x, y: Integer; ARadius, AHeight: Integer);
- property Damping: TWaterDamping read FDamping write SetDamping;
- end;
- implementation
- { TWater }
- procedure TDefineWatet.Blob(x, y, ARadius, AHeight: Integer);
- var
- Rquad: Integer;
- cx, cy, cyq: Integer;
- WaterLeft, WaterTop, WaterRight, WaterBottom: Integer;
- begin
- if (x < 0) or (x > FWaterWidth - 1) then
- x := 1 + ARadius + Random(RAND_MAX) mod (FWaterWidth - 2 * ARadius - 1);
- if (y < 0) or (y > FWaterHeight - 1) then
- y := 1 + ARadius + Random(RAND_MAX) mod (FWaterHeight - 2 * ARadius - 1);
- WaterLeft := -Min(x, ARadius);
- WaterRight := Min(FWaterWidth - 1 - x, ARadius);
- WaterTop := -Min(y, ARadius);
- WaterBottom := Min(FWaterHeight - 1 - y, ARadius);
- Rquad := ARadius * ARadius;
- for cy := WaterTop to WaterBottom do
- begin
- cyq := cy * cy;
- for cx := WaterLeft to WaterRight do
- begin
- if (cx * cx + cyq <= Rquad) then
- begin
- Inc(FScanLine1[cy + y][cx + x], AHeight);
- end;
- end;
- end;
- end;
- procedure TDefineWatet.CalcWater;
- var
- x, y, xl, xr: Integer;
- NewH: Integer;
- P, P1, P2, P3: PIntArray;
- PT: Pointer;
- Rate: Integer;
- begin
- Rate := (100 - FDamping) * 256 div 100;
- for y := 0 to FWaterHeight - 1 do
- begin
- P := FScanLine2[y];
- P1 := FScanLine1[Max(y - 1, 0)];
- P2 := FScanLine1[y];
- P3 := FScanLine1[Min(y + 1, FWaterHeight - 1)];
- for x := 0 to FWaterWidth - 1 do
- begin
- xl := Max(x - 1, 0);
- xr := Min(x + 1, FWaterWidth - 1);
- NewH := (P1[xl] + P1[x] + P1[xr] + P2[xl] + P2[xr] + P3[xl] + P3[x] + P3[xr]) div 4 - P[x];
- P[x] := NewH * Rate div 256;
- end;
- end;
-
- PT := FWaterBuff1;
- FWaterBuff1 := FWaterBuff2;
- FWaterBuff2 := PT;
- PT := FScanLine1;
- FScanLine1 := FScanLine2;
- FScanLine2 := PT;
- end;
- procedure TDefineWatet.ClearWater;
- begin
- if FWaterBuff1 <> nil then
- ZeroMemory(FWaterBuff1, (FWaterWidth * FWaterHeight) * SizeOf(Integer));
- if FWaterBuff2 <> nil then
- ZeroMemory(FWaterBuff2, (FWaterWidth * FWaterHeight) * SizeOf(Integer));
- end;
- constructor TDefineWatet.Create;
- begin
- inherited;
- FDamping := csDefDamping;
- end;
- destructor TDefineWatet.Destroy;
- begin
- if FWaterBuff1 <> nil then
- FreeMem(FWaterBuff1);
- if FWaterBuff2 <> nil then
- FreeMem(FWaterBuff2);
- if FScanLine1 <> nil then
- FreeMem(FScanLine1);
- if FScanLine2 <> nil then
- FreeMem(FScanLine2);
- if FScanLineSrc <> nil then
- FreeMem(FScanLineSrc);
- inherited Destroy;
- end;
- procedure TDefineWatet.Render(Src, Dst: TBitmap);
- var
- dx, dy: Integer;
- i, c, x, y: Integer;
- P1, P2, P3: PIntArray;
- PSrc, PDst: PRGBArray;
- PSrcDot, PDstDot: PRGBTriple;
- BytesPerLine1, BytesPerLine2: Integer;
- begin
- CalcWater;
- Src.PixelFormat := pf24bit;
- Dst.PixelFormat := pf24bit;
-
- FScanLineSrc[0] := Src.ScanLine[0];
- BytesPerLine1 := Integer(Src.ScanLine[1]) - Integer(FScanLineSrc[0]);
- for i := 1 to FWaterHeight - 1 do
- FScanLineSrc[i] := PRGBArray(Integer(FScanLineSrc[i - 1]) + BytesPerLine1);
- PDst := Dst.ScanLine[0];
- BytesPerLine2 := Integer(Dst.ScanLine[1]) - Integer(PDst);
- for y := 0 to FWaterHeight - 1 do
- begin
- PSrc := FScanLineSrc[y];
- P1 := FScanLine1[Max(y - 1, 0)];
- P2 := FScanLine1[y];
- P3 := FScanLine1[Min(y + 1, FWaterHeight - 1)];
- for x := 0 to FWaterWidth - 1 do
- begin
- dx := P2[Max(x - 1, 0)] - P2[Min(x + 1, FWaterWidth - 1)];
- dy := P1[x] - P3[x];
- if (x + dx >= 0) and (x + dx < FWaterWidth) and (y + dy >= 0) and
- (y + dy < FWaterHeight) then
- begin
- PSrcDot := @FScanLineSrc[y + dy][x + dx];
- PDstDot := @PDst[x];
- c := PSrcDot.rgbtBlue - dx;
- if c < 0 then
- PDstDot.rgbtBlue := 0
- else if c > 255 then
- PDstDot.rgbtBlue := 255
- else
- PDstDot.rgbtBlue := c;
- c := PSrcDot.rgbtGreen - dx;
- if c < 0 then
- PDstDot.rgbtGreen := 0
- else if c > 255 then
- PDstDot.rgbtGreen := 255
- else
- PDstDot.rgbtGreen := c;
-
- c := PSrcDot.rgbtRed - dx;
- if c < 0 then
- PDstDot.rgbtRed := 0
- else if c > 255 then
- PDstDot.rgbtRed := 255
- else
- PDstDot.rgbtRed := c;
- end
- else
- begin
- PDst[x] := PSrc[x];
- end;
- end;
- PDst := PRGBArray(Integer(PDst) + BytesPerLine2);
- end;
- end;
- procedure TDefineWatet.SetDamping(Value: TWaterDamping);
- begin
- if (Value >= Low(TWaterDamping)) and (Value <= High(TWaterDamping)) then
- FDamping := Value;
- end;
- procedure TDefineWatet.SetSize;
- var
- i: Integer;
- begin
- FWaterWidth := Bitmap.Width;
- FWaterHeight := Bitmap.Height;
- if (FWaterWidth <= 0) or (FWaterHeight <= 0) then
- begin
- FWaterWidth := 0;
- FWaterHeight := 0;
- end;
- ReallocMem(FWaterBuff1, FWaterWidth * FWaterHeight * SizeOf(Integer));
- ReallocMem(FWaterBuff2, FWaterWidth * FWaterHeight * SizeOf(Integer));
- ReallocMem(FScanLine1, FWaterHeight * SizeOf(PIntArray));
- ReallocMem(FScanLine2, FWaterHeight * SizeOf(PIntArray));
- ReallocMem(FScanLineSrc, FWaterHeight * SizeOf(PRGBArray));
- ClearWater;
- if (FWaterHeight > 0)and(FWaterWidth > 0) then
- begin
- FScanLine1[0] := FWaterBuff1;
- FScanLine2[0] := FWaterBuff2;
- for i := 1 to FWaterHeight - 1 do
- begin
- //FScanLine1[i] := PIntArray(@FScanLine1[i - 1][FWaterWidth]);
- //FScanLine2[i] := PIntArray(@FScanLine2[i - 1][FWaterWidth]);
- FScanLine1[i] := @FScanLine1[i - 1][FWaterWidth];
- FScanLine2[i] := @FScanLine2[i - 1][FWaterWidth];
- end;
- end;
- end;
- end.
|