⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 flatwatet.pas

📁 comerose_flatstyle_v4.42.9.0_d7.rar
💻 PAS
字号:
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] := @FScanLine1[i - 1][FWaterWidth];
      FScanLine2[i] := @FScanLine2[i - 1][FWaterWidth];      
    end;
  end;
end;

end.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -