1

我是德尔福学习者。我已经从下载了一个delphi表单效果项目

http://www.gamedev.net/page/resources/_/technical/graphics-programming-and-theory/the-water-effect-explained-r915

具有“DXDraw01”、“DXDIB01”、“DXDIB02”、“背景”和一些“BitBtn”。实际项目是*Bit Color 操作。我试图在 32Bit Color 中实现它。我已经实现了以下代码:

  private
    { Private declarations }
  public
    { Public declarations }
   procedure FrameFadeIn(DIB01, DIB02: TDIB; Step: Byte);
   procedure FrameFadeOut(DIB01, DIB02: TDIB; Step: Byte);
   procedure FrameFill(DIB: TDIB; Color: Byte);
   procedure WaterFrameUpdate;
   procedure WaterFrameInitialize;
   procedure WaterFramePrepare;
   procedure WaterFrameRender(DIB: TDIB);
   procedure WaterBubleDrop(X, Y, W, SplashStrength: Integer);
  end;
  PLongArray = ^TLongArray;
  TLongArray = Array[0..32767] of LongInt;
  TWaterFrame = Array[0..1,0..FrameWidth,0..FrameHeight] of Smallint;
var
  MainForm: TMainForm;
  CT, NW: Byte;
  Closing: Boolean;
  WaterFrame: TWaterFrame;
  TSin, TCos: Array[0..511] of Single;
  UltimateDisplacement: Array[0..511] of Byte;
implementation
{$R *.DFM}

procedure TMainForm.FrameFill(DIB: TDIB; Color: Byte);
var
  P: PByteArray;
  W, H: Integer;
begin
  P := DIB.ScanLine[DIB.Height-1];
  W := DIB.WidthBytes;
  H := DIB.Height;
  asm
    PUSH ESI
    MOV ESI, P
    MOV EDX, W
    MOV EAX, H
    IMUL EDX
    MOV ECX, EAX
    MOV AL, Color
    @@1:
    MOV [ESI], AL
    INC ESI
    DEC ECX
    JNZ @@1
    POP ESI
  end;
end;
procedure TMainForm.FrameFadeIn(DIB01, DIB02: TDIB; Step: Byte);
var
  W, H: Integer;
  P1, P2: PByteArray;
begin
  P1 := DIB01.ScanLine[DIB02.Height-1];
  P2 := DIB02.ScanLine[DIB02.Height-1];
  W := DIB01.WidthBytes;
  H := DIB01.Height;
  asm
    PUSH ESI
    PUSH EDI
    MOV ESI, P1
    MOV EDI, P2
    MOV EDX, W
    MOV EAX, H
    IMUL EDX
    MOV ECX, EAX
    @@1:
    MOV AL, Step
    MOV AH, [ESI]
    CMP AL, AH
    JB @@2
    MOV AL, AH
@@2:
    MOV [EDI], AL
    INC ESI
    INC EDI
    DEC ECX
    JNZ @@1
    POP EDI
    POP ESI
  end;
end;
procedure TMainForm.FrameFadeOut(DIB01, DIB02: TDIB; Step: Byte);
var
  W, H: Integer;
  P1, P2: PByteArray;
begin
  P1 := DIB01.ScanLine[DIB02.Height-1];
  P2 := DIB02.ScanLine[DIB02.Height-1];
  W := DIB01.WidthBytes;
  H := DIB01.Height;
  asm
    PUSH ESI
    PUSH EDI
    MOV ESI, P1
    MOV EDI, P2
    MOV EDX, W
    MOV EAX, H
    IMUL EDX
    MOV ECX, EAX
    @@1:
    MOV AL, Step
    MOV AH, [ESI]
    CMP AL, AH
    JA @@2
    MOV AL, AH
@@2:
    MOV [EDI], AL
    INC ESI
    INC EDI
    DEC ECX
    JNZ @@1
    POP EDI
    POP ESI
  end;
end;
procedure TMainForm.BitBtn01Click(Sender: TObject);
var
  Opacity: Integer;
  SystemTime01, SystemTime02: TSystemTime;
begin
  Closing := True;
  Application.ProcessMessages;
  Closing := False;
  GetLocalTime(SystemTime01);
  DXDIB01.DIB.SetSize(Background.DIB.Width, Background.DIB.Height, Background.DIB.BitCount);
  Opacity := 0;
  while Opacity < 255 do
    begin
      FrameFill(DXDIB01.DIB, Byte(Opacity));
      if DXDraw01.CanDraw then
        begin
          DXDraw01.Surface.Assign(DXDIB01.DIB);
          DXDraw01.Flip;
        end;
      Opacity := Opacity + 5;
      Application.ProcessMessages;
      if Closing then Exit;
    end;
  GetLocalTime(SystemTime02);
end;
procedure TMainForm.BitBtn02Click(Sender: TObject);
var
  Opacity: Integer;
begin
  Closing := True;
  Application.ProcessMessages;
  Closing := False;

  DXDIB01.DIB.SetSize(Background.DIB.Width, Background.DIB.Height, Background.DIB.BitCount);
  FrameFill(DXDIB01.DIB, 0);
  for Opacity := 0 to 255 do
    begin
      FrameFadeIn(BackGround.DIB, DXDIB01.DIB, Opacity);
      if DXDraw01.CanDraw then
        begin
          DXDraw01.Surface.Assign(DXDIB01.DIB);
          DXDraw01.Flip;
        end;
      Application.ProcessMessages;
      if Closing then Exit;
    end;
end;
procedure TMainForm.BitBtn03Click(Sender: TObject);
var
  Opacity: Integer;
begin
  Closing := True;
  Application.ProcessMessages;
  Closing := False;
  DXDIB01.DIB.SetSize(Background.DIB.Width, Background.DIB.Height, Background.DIB.BitCount);
  FrameFill(DXDIB01.DIB, 255);
  for Opacity := 255 downto 0 do
    begin
      FrameFadeOut(BackGround.DIB, DXDIB01.DIB, Opacity);
      if DXDraw01.CanDraw then
        begin
          DXDraw01.Surface.Assign(DXDIB01.DIB);
          DXDraw01.Flip;
        end;
      Application.ProcessMessages;
      if Closing then Exit;
    end;
end;
procedure TMainForm.BitBtn04Click(Sender: TObject);
const
  NumberOfRotation = 10;
var
  CosY,SinY: real;
  P1,P2: PByteArray;
  X1, Y1, X2, Y2, FrameHorizontalCenter, FrameVerticalCenter, RotationSpeed, RotationAngle: Integer;
begin
  Closing := True;
  Application.ProcessMessages;
  Closing := False;
  DXDIB01.DIB.SetSize(Background.DIB.Width, Background.DIB.Height, Background.DIB.BitCount);
  FrameHorizontalCenter := Background.DIB.Width div 2;
  FrameVerticalCenter := Background.DIB.Height div 2;
  for RotationSpeed := 0 to 64 do
    begin
      RotationAngle := 384 + (RotationSpeed*NumberOfRotation);
      for Y1 := 0 to BackGround.DIB.Height -1 do
        begin
          P1 := DXDIB01.DIB.ScanLine[Y1];
          CosY := (Y1 - FrameVerticalCenter) * TCos[RotationAngle and $1ff];
          SinY := (Y1 - FrameVerticalCenter) * TSin[RotationAngle and $1ff];
          for X1 := 0 to Background.DIB.Width-1 do
            begin
              X2 := Trunc((X1 - FrameHorizontalCenter) * TSin[RotationAngle and $1ff] + CosY) + FrameHorizontalCenter;
              Y2 := Trunc((X1 - FrameHorizontalCenter) * TCos[RotationAngle and $1ff] - SinY) + FrameVerticalCenter;
              {  Required Logic if Background.DIB.BitCount=32  }
              if (Y2 >= 0) and (Y2 < Background.DIB.Height) and (X2 >= 0) and (X2 < Background.DIB.Width) then
                begin
                  PLongArray(P2) := Background.DIB.ScanLine[Y2];
                  PLongArray(P1)[X1] := PLongArray(P2)[FrameWidth - x2];
                end
              else
                begin
                  if PLongArray(P1)[X1] > 4 then PLongArray(P1)[X1] := PLongArray(P1)[X1] - 4 else PLongArray(P1)[X1] := 0;
                end;
              {  Required Logic if Background.DIB.BitCount=32  }
            end
        end;
      if DXDraw01.CanDraw then
        begin
          DXDraw01.Surface.Assign(DXDIB01.DIB);
          DXDraw01.Flip;
        end;
      Application.ProcessMessages;
      if Closing then Exit;
    end;
  BitBtn11Click(Sender);
end;
procedure TMainForm.BitBtn05Click(Sender: TObject);
var
  P1,P2: PByteArray;
  ActualDistance, Distance, CosY, SinY: real;
  X1, Y1, X2, Y2, HorizontalCenter, VerticalCenter, A, B, Angle, DistortionFactor: Integer;
begin
  Closing := True;
  Application.ProcessMessages;
  Closing := False;
  DXDIB01.DIB.SetSize(Background.DIB.Width, Background.DIB.Height, Background.DIB.BitCount);
  HorizontalCenter := Background.DIB.Width div 2;
  VerticalCenter := Background.DIB.Height div 2;
  Distance := sqrt(sqr(HorizontalCenter) + sqr(VerticalCenter));
  for A := 0 to 16 do
    begin
      B := A*8;
      for Y1 := 0 to DXDIB01.DIB.Height - 1 do
        begin
        P1 := DXDIB01.DIB.ScanLine[Y1];
        DistortionFactor := sqr(Y1-VerticalCenter);
        for X1 := 0 to (DXDIB01.DIB.Width) - 1 do
          begin
            ActualDistance := (sqrt((sqr(X1 - HorizontalCenter) + DistortionFactor))/Distance);
            ActualDistance := TSin[ (Trunc(ActualDistance*1024)) and $1ff ];
            Angle := 384 + Trunc( (ActualDistance)* B );
            CosY := (Y1 - VerticalCenter) * TCos[Angle and $1ff];
            SinY := (Y1 - VerticalCenter) * TSin[Angle and $1ff];
            X2 := Trunc((X1 - HorizontalCenter) * TSin[Angle and $1ff] + CosY) + HorizontalCenter;
            Y2 := Trunc((X1 - HorizontalCenter) * TCos[Angle and $1ff] - SinY) + VerticalCenter;
            {  Required Logic if Background.DIB.BitCount=32  }
            if (Y2 >= 0) and (Y2 < Background.DIB.Height) and (X2 >= 0) and (X2 < Background.DIB.Width) then
              begin
                PLongArray(P2) := Background.DIB.ScanLine[Y2];
                PLongArray(P1)[X1] := PLongArray(P2)[FrameWidth - X2];
              end
            else
              begin
                if P1[X1] > 2 then PLongArray(P1)[X1] := PLongArray(P1)[X1] - 2 else PLongArray(P1)[X1] := 0;
              end;
            {  Required Logic if Background.DIB.BitCount=32  }
          end;
        end;
      if DXDraw01.CanDraw then
        begin
          DXDraw01.Surface.Assign(DXDIB01.DIB);
          DXDraw01.Flip;
        end;
      Application.ProcessMessages;
      if Closing then Exit;
    end;
  for A := 16 downto 0 do
    begin
      B := A*8;
      for Y1 := 0 to DXDIB01.DIB.Height - 1 do
        begin
          P1 := DXDIB01.DIB.ScanLine[Y1];
          DistortionFactor := sqr(Y1 - VerticalCenter);
          for X1 := 0 to (DXDIB01.DIB.Width) - 1 do
            begin
              ActualDistance := (sqrt((sqr(X1 - HorizontalCenter) + DistortionFactor))/Distance);
              ActualDistance := TSin[ (Trunc(ActualDistance*1024)) and $1ff ];
              Angle := 384 + Trunc( (ActualDistance)* B );
              CosY := (Y1 - VerticalCenter) * TCos[Angle and $1ff];
              SinY := (Y1 - VerticalCenter) * TSin[Angle and $1ff];
              X2 := Trunc((X1 - HorizontalCenter) * TSin[Angle and $1ff] + CosY) + HorizontalCenter;
              Y2 := Trunc((X1 - HorizontalCenter) * TCos[Angle and $1ff] - SinY) + VerticalCenter;
              {  Required Logic if Background.DIB.BitCount=32  }
              if (Y2 >= 0) and (Y2 < Background.DIB.Height) and (X2 >= 0) and (X2 < Background.DIB.Width) then
                begin
                  PLongArray(P2) := Background.DIB.ScanLine[Y2];
                  PLongArray(P1)[X1] := PLongArray(P2)[FrameWidth - X2];
                end
              else
                begin
                  if P1[X1] > 2 then PLongArray(P1)[X1] := PLongArray(P1)[X1] - 2 else PLongArray(P1)[X1] := 0;
                end;
              {  Required Logic if Background.DIB.BitCount=32  }
            end;
        end;
      if DXDraw01.CanDraw then
        begin
          DXDraw01.Surface.Assign(DXDIB01.DIB);
          DXDraw01.Flip;
        end;
      Application.ProcessMessages;
      if Closing then Exit;
    end;
  BitBtn11Click(Sender);
end;
procedure TMainForm.BitBtn06Click(Sender: TObject);
var
  P1, P2: PByteArray;
  ActualDistance, Distance,CosY, SinY: real;
  X1, Y1, X2, Y2, HorizontalCenter, VerticalCenter, A, B, Angle, DistortionFactor: Integer;
begin
  Closing := True;
  Application.ProcessMessages;
  Closing := False;
  DXDIB01.DIB.SetSize(Background.DIB.Width, Background.DIB.Height, Background.DIB.BitCount);
  HorizontalCenter := Background.DIB.Width div 2;
  VerticalCenter := Background.DIB.Height div 2;
  Distance := sqrt(sqr(HorizontalCenter) + sqr(VerticalCenter)) * 0.75;
  for A := 0 to 63 do
    begin
      B := A*8;
      for Y1 := 0 to DXDIB01.DIB.Height - 1 do
        begin
          P1 := DXDIB01.DIB.ScanLine[Y1];
          DistortionFactor := sqr(Y1 - VerticalCenter);
          for X1 := 0 to (DXDIB01.DIB.Width) - 1 do
            begin
              ActualDistance := 1 - (sqrt((sqr(X1 - HorizontalCenter) + DistortionFactor))/Distance);
              Angle := 384 + Trunc( (ActualDistance)* B );
              CosY := (Y1 - VerticalCenter) * TCos[Angle and $1ff];
              SinY := (Y1 - VerticalCenter) * TSin[Angle and $1ff];
              X2 := Trunc((X1 - HorizontalCenter) * TSin[Angle and $1ff] + CosY) + HorizontalCenter;
              Y2 := Trunc((X1 - HorizontalCenter) * TCos[Angle and $1ff] - SinY) + VerticalCenter;
              {  Required Logic if Background.DIB.BitCount=32  }
              if (Y2 >= 0) and (Y2 < Background.DIB.Height) and (X2 >= 0) and (X2 < Background.DIB.Width) then
                begin
                  PLongArray(P2) := Background.DIB.ScanLine[Y2];
                  PLongArray(P1)[X1] := PLongArray(P2)[FrameWidth - X2];
                end
              else
                begin
                  if P1[X1] > 2 then PLongArray(P1)[X1] := PLongArray(P1)[X1] - 2 else PLongArray(P1)[X1] := 0;
                end;
              {  Required Logic if Background.DIB.BitCount=32  }
              end;
          end;
        if DXDraw01.CanDraw then
          begin
            DXDraw01.Surface.Assign(DXDIB01.DIB);
            DXDraw01.Flip;
          end;
      Application.ProcessMessages;
      if Closing then Exit;
    end;
  for A := 64 downto 0 do
    begin
      B := A*8;
      for Y1 := 0 to DXDIB01.DIB.Height - 1 do
        begin
          P1 := DXDIB01.DIB.ScanLine[Y1];
          DistortionFactor := sqr(Y1 - VerticalCenter);
          for X1 := 0 to (DXDIB01.DIB.Width)-1 do
            begin
              ActualDistance := 1-(sqrt((sqr(X1 - HorizontalCenter) + DistortionFactor))/Distance);
              Angle := 384 + Trunc( (ActualDistance)* B );
              CosY := (Y1 - VerticalCenter) * TCos[Angle and $1ff];
              SinY := (Y1 - VerticalCenter) * TSin[Angle and $1ff];
              X2 := Trunc((X1 - HorizontalCenter) * TSin[Angle and $1ff] + CosY) + HorizontalCenter;
              Y2 := Trunc((X1 - HorizontalCenter) * TCos[Angle and $1ff] - SinY) + VerticalCenter;
              {  Required Logic if Background.DIB.BitCount=32  }
              if (Y2 >= 0) and (Y2 < Background.DIB.Height) and (X2 >= 0) and (X2 < Background.DIB.Width) then
                begin
                  PLongArray(P2) := Background.DIB.ScanLine[Y2];
                  PLongArray(P1)[X1] := PLongArray(P2)[FrameWidth - X2];
                end
              else
                begin
                  if P1[X1] > 2 then PLongArray(P1)[X1] := PLongArray(P1)[X1] - 2 else PLongArray(P1)[X1] := 0;
                end;
              {  Required Logic if Background.DIB.BitCount=32  }
            end;
        end;
      if DXDraw01.CanDraw then
        begin
          DXDraw01.Surface.Assign(DXDIB01.DIB);
          DXDraw01.Flip;
        end;
      Application.ProcessMessages;
      if Closing then Exit;
    end;
  BitBtn11Click(Sender);
end;
procedure TMainForm.BitBtn07Click(Sender: TObject);
const
 AmountOfSpray = 500;
var
  X, Y, C: Integer;
  AllBlack: Boolean;
  P1, P2, P3: PByteArray;
begin
  Closing := True;
  Application.ProcessMessages;
  Closing := False;
  DXDIB01.DIB.SetSize(Background.DIB.Width,Background.DIB.Height,Background.DIB.BitCount);
  for C:=0 to AmountOfSpray do begin
    DXDIB01.DIB.Pixels[ random(Background.DIB.Width-1), random(Background.DIB.Height-1)] :=0;
  end;
  repeat
    AllBlack := True;
    for Y:=0 to DXDIB01.DIB.Height -1 do
      begin
        P2 := DXDIB01.DIB.ScanLine[Y];
        for X:=0 to DXDIB01.DIB.Width-1 do
          begin
          {  Required Logic if Background.DIB.BitCount=32  }
            if PLongArray(P2)[X] < 16 then
              begin
                if PLongArray(P2)[X] > 0 then AllBlack := false;
                if Y > 0 then
                  begin
                    PLongArray(P1) := DXDIB01.DIB.ScanLine[Y - 1];
                    if PLongArray(P1)[X] > 4 then PLongArray(P1)[X] := PLongArray(P1)[X] - 4 else PLongArray(P1)[X] := 0;
                    if X > 0 then if PLongArray(P1)[X - 1] > 2 then PLongArray(P1)[X - 1] := PLongArray(P1)[X - 1] - 2 else PLongArray(P1)[X - 1] := 0;
                    if X < (DXDIB01.DIB.Width - 1) then if PLongArray(P1)[X + 1] > 2 then PLongArray(P1)[X + 1] := PLongArray(P1)[X + 1] - 2 else PLongArray(P1)[X + 1] := 0;
                  end;
                if Y < (DXDIB01.DIB.Height - 1) then
                  begin
                    PLongArray(P3) := DXDIB01.DIB.ScanLine[Y + 1];
                    if PLongArray(P3)[X] > 4 then PLongArray(P3)[X] := PLongArray(P3)[X] - 4 else PLongArray(P3)[X] := 0;
                    if X > 0 then if PLongArray(P3)[X - 1] > 2 then PLongArray(P3)[X - 1] := PLongArray(P3)[X - 1] - 2 else PLongArray(P3)[X - 1] := 0;
                    if X < (DXDIB01.DIB.Width - 1) then if PLongArray(P3)[X + 1] > 2 then PLongArray(P3)[X + 1] := PLongArray(P3)[X + 1] - 2 else PLongArray(P3)[X + 1] := 0;
                  end;
                if PLongArray(P2)[X] > 8 then PLongArray(P2)[X] := PLongArray(P2)[X] - 8 else PLongArray(P2)[X] := 0;
                if X > 0 then if PLongArray(P2)[X - 1] > 4 then PLongArray(P2)[X - 1] := PLongArray(P2)[X - 1] - 4 else PLongArray(P2)[X - 1] := 0;
                if X < (DXDIB01.DIB.Width - 1) then if PLongArray(P2)[X + 1] > 4 then PLongArray(P2)[X + 1] := PLongArray(P2)[X + 1] - 4 else PLongArray(P2)[X + 1] := 0;
              end;
          {  Required Logic if Background.DIB.BitCount=32  }
          end;
      end;
    if DXDraw01.CanDraw then
      begin
        DXDraw01.Surface.Assign(DXDIB01.DIB);
        DXDraw01.Flip;
      end;
    Application.ProcessMessages;
  until (AllBlack or Closing);
end;
procedure TMainForm.BitBtn08Click(Sender: TObject);
var
  Tmp: Byte;
begin
  Closing := True;
  Application.ProcessMessages;
  Closing := False;
  DXDIB01.DIB.SetSize(Background.DIB.Width, Background.DIB.Height, Background.DIB.BitCount);
  CT := 0;
  NW := 1;
  repeat
    WaterFrameUpdate;
    WaterFrameRender(DXDIB01.DIB);
    Tmp := CT;
    CT := NW;
    NW := Tmp;
    if DXDraw01.CanDraw then begin
      DXDraw01.Surface.Assign(DXDIB01.DIB);
      DXDraw01.Flip;
    end;
    Application.ProcessMessages;
  until (Closing);
end;
procedure TMainForm.BitBtn09Click(Sender: TObject);
var
  Tmp: Byte;
  x,y: Smallint;
begin
  Closing := True;
  Application.ProcessMessages;
  Closing := False;
  DXDIB01.DIB.SetSize(Background.DIB.Width, Background.DIB.Height, Background.DIB.BitCount);
  CT := 0;
  NW := 1;
  repeat
    x := 40 + random(FrameWidth - 40);
    y := 40 + random(FrameHeight - 40);
    WaterBubleDrop(X, Y, 10, 25);
    WaterFrameUpdate;
    WaterFrameRender(DXDIB01.DIB);
    Tmp := CT;
    CT := NW;
    NW := Tmp;
    if DXDraw01.CanDraw then begin
      DXDraw01.Surface.Assign(DXDIB01.DIB);
      DXDraw01.Flip;
    end;
    Application.ProcessMessages;
  until (Closing);
end;
procedure TMainForm.BitBtn10Click(Sender: TObject);
var
  Tmp: Byte;
  CosY, SinY: real;
  X1, Y1, X2, Y2, HorizontalIncrement, VerticalIncrement, HorizontalCenter, VerticalCenter, Angle: Smallint;
const
  HorizontalStartingPoint = 80;
  VerticalStartingPoint = 80;
begin
  Closing := True;
  Application.ProcessMessages;
  Closing := False;
  DXDIB01.DIB.SetSize(Background.DIB.Width, Background.DIB.Height, Background.DIB.BitCount);
  HorizontalCenter := Background.DIB.Width div 2;
  VerticalCenter := Background.DIB.Height div 2;
  CT := 0;
  NW := 1;
  Angle := 0;
  X2 := 4; HorizontalIncrement := 4;
  Y2 := 4; VerticalIncrement := 3;
  WaterBubleDrop(HorizontalCenter,VerticalCenter,40,-100);
  repeat
    CosY := (VerticalStartingPoint - VerticalCenter) * TCos[Angle and $1ff];
    SinY := (VerticalStartingPoint - VerticalCenter) * TSin[Angle and $1ff];
    X1 := Trunc((HorizontalStartingPoint - HorizontalCenter) * TSin[Angle and $1ff] + CosY) + HorizontalCenter;
    Y1 := Trunc((HorizontalStartingPoint - HorizontalCenter) * TCos[Angle and $1ff] - SinY) + VerticalCenter;
    Angle := Angle + 8;
    WaterBubleDrop(X1, Y1, 4, -500);
    WaterBubleDrop(X2, Y2, 4, -500);
    X2 := X2 + HorizontalIncrement;
    Y2 := Y2 + VerticalIncrement;
    if (X2 < 4) or (X2 > FrameWidth - 4) then HorizontalIncrement := -HorizontalIncrement;
    if (Y2 < 4) or (Y2 > FrameHeight - 4) then VerticalIncrement := -VerticalIncrement;
    WaterFrameUpdate;
    WaterFrameRender(DXDIB01.DIB);
    Tmp := CT;
    CT := NW;
    NW := Tmp;
    if DXDraw01.CanDraw then begin
      DXDraw01.Surface.Assign(DXDIB01.DIB);
      DXDraw01.Flip;
    end;
    Application.ProcessMessages;
  until (Closing);
end;
procedure TMainForm.BitBtn11Click(Sender: TObject);
 begin
  DXDIB01.DIB.SetSize(Background.DIB.Width, Background.DIB.Height, Background.DIB.BitCount);
  DXDIB01.DIB.Assign(Background.DIB);
  if DXDraw01.CanDraw then begin
    DXDraw01.Surface.Assign(DXDIB01.DIB);
    DXDraw01.Flip;
  end;
end;
procedure TMainForm.BitBtn12Click(Sender: TObject);
begin
  MainForm.Close;
end;
procedure TMainForm.WaterFrameUpdate;
const
  DampingCoefficient = 4;
var
  X, Y, N: Smallint;
begin
  for Y := 2 to FrameHeight-2 do begin
    for X := 2 to FrameWidth-2 do begin
      N := ( WaterFrame[CT, X-1, Y] + WaterFrame[CT, X-2, Y] + WaterFrame[CT, X+1, Y] + WaterFrame[CT, X+2, Y] +
           WaterFrame[CT, X, Y-1] + WaterFrame[CT, X, Y-2] + WaterFrame[CT, X, Y+1] + WaterFrame[CT, X, Y+2] +
           WaterFrame[CT, X-1, Y-1] + WaterFrame[CT, X+1, Y-1] + WaterFrame[CT, X-1, Y+1] + WaterFrame[CT, X+1, Y+1] )
           div 6 - WaterFrame[NW, X, Y];
      asm
        PUSH BX
        MOV BX, N
        SAR BX, DampingCoefficient
        SUB N, BX
        POP BX
      end;
      WaterFrame[NW, X, Y] := N;
    end;
  end;
end;
procedure TMainForm.WaterFrameInitialize;
var
  X, Y: SmallInt;
begin
  for Y := 0 to FrameHeight do begin
    for X := 0 to FrameWidth do begin
      WaterFrame[CT, X, Y] := 0;
      WaterFrame[NW, X, Y] := 0;
    end;
  end;
end;
procedure TMainForm.WaterFramePrepare;
const
  RefractiveIndex = 4.0;
var
  C, D: SmallInt;
begin
  for C := -256 to 255 do begin
    D := C div 4;
    UltimateDisplacement[C + 256] := Byte(Trunc(Tan(ArcSin((Sin(ArcTan(D)) / RefractiveIndex))) * D));
  end;
  for C := 0 to 511 do begin
    TSin[C] := Sin( ((C * 360) / 511) * Pi / 180 );
    TCos[C] := Cos( ((C * 360) / 511) * Pi / 180 );
  end;
  WaterFrameInitialize;
end;
procedure TMainForm.WaterFrameRender(DIB: TDIB);
var
  X, Y, NewColor, HorizontalDifference, VerticalDifference, HorizontalDisplacement, VerticalDisplacement: Smallint;
begin
  for Y := 0 to FrameHeight do begin
    for X := 0 to FrameWidth do begin
      HorizontalDifference := WaterFrame[NW, X+1, Y] - WaterFrame[NW, X, Y];
      VerticalDifference := WaterFrame[NW, X, Y+1] - WaterFrame[NW, X, Y];
      HorizontalDisplacement := UltimateDisplacement[HorizontalDifference + 256];
      VerticalDisplacement := UltimateDisplacement[VerticalDifference + 256];
      if HorizontalDifference < 0 then begin
        if (VerticalDifference<0) then
          NewColor := Background.DIB.Pixels[X-HorizontalDisplacement,Y-VerticalDisplacement]
        else
          NewColor := Background.DIB.Pixels[X-HorizontalDisplacement,Y+VerticalDisplacement]
      end else begin
        if (VerticalDifference<0) then
          NewColor := Background.DIB.Pixels[X+HorizontalDisplacement,Y-VerticalDisplacement]
        else
          NewColor := Background.DIB.Pixels[X+HorizontalDisplacement,Y+VerticalDisplacement]
      end;
      DIB.Pixels[X, Y] := NewColor;
    end;
  end;
end;
procedure TMainForm.WaterBubleDrop(X,Y,W,SplashStrength: Integer);
var
  U, V: Integer;
  HorizontalDistanceSquare, VerticalDistanceSquare, BubbleWidthSquare: Integer;
begin
  BubbleWidthSquare := sqr(W);
  if (X > W) and (X < FrameWidth - W) and (Y > W) and (Y < FrameHeight - W) then begin
    for V := Y - W to Y + W do begin
      VerticalDistanceSquare := sqr(V - Y);
      for U := X - W to X + W do begin
        HorizontalDistanceSquare := sqr(U - X);
        if (HorizontalDistanceSquare + VerticalDistanceSquare) <= BubbleWidthSquare then begin
          WaterFrame[CT, U, V] := SplashStrength*Trunc(W - sqrt(HorizontalDistanceSquare + VerticalDistanceSquare));
        end;
      end;
    end;
  end;
end;
procedure TMainForm.FormCreate(Sender: TObject);
begin
  WaterFramePrepare;
end;
procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  DXTimer01.Enabled := true;
  Closing := True;
end;
procedure TMainForm.DXDraw01Finalize(Sender: TObject);
begin
  DXTimer01.Enabled := false;
end;
procedure TMainForm.DXDraw01Initialize(Sender: TObject);
begin
  DXTimer01.Enabled := true;
end;
procedure TMainForm.DXDraw01MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  WaterBubleDrop(X, Y, 15, -4);
end;
procedure TMainForm.DXDraw01MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
  if (X > 0) and (X < FrameWidth) and (Y > 0) and (Y < FrameHeight) then begin
    WaterBubleDrop(X, Y, 8, -64);
  end;
end;
procedure TMainForm.DXTimer01Timer(Sender: TObject; LagCount: Integer);
begin
  if not DXDraw01.CanDraw then exit;
  DXDraw01.Surface.Fill(0);
  DXDIB01.DIB.SetSize(Background.DIB.Width,Background.DIB.Height,Background.DIB.BitCount);
  DXDIB01.DIB.Assign(Background.DIB);
  if DXDraw01.CanDraw then
  begin
    DXDraw01.Surface.Assign(DXDIB01.DIB);
    with DXDraw01.Surface.Canvas do
      begin
        Brush.Style := bsClear;
        Font.Color := $efefef;
        Font.Size := 30;
        Textout((Background.DIB.Width - TextWidth('M/DD/YY HH:MM:SS AM')) div 2, (Background.DIB.Height - 30) div 2, DateTimeToStr(Now));
        Release;
      end;
  end;
  DXDraw01.Flip;
end;
end.

我的问题是除了水和雨效果之外的所有效果都正常工作。在我的项目中,Background.DIB 是一个 32 位图像。请帮帮我。据我所知,问题出在以下过程定义中:

procedure WaterFrameUpdate;
procedure WaterFrameInitialize;
procedure WaterFramePrepare;
procedure WaterFrameRender(DIB: TDIB);
procedure WaterBubleDrop(X, Y, W, SplashStrength: Integer);

我认为一个或多个程序定义具有 8Bit Color 操作。我不明白哪一个是 8Bit Color 操作。我也尝试过实现 LongArray 但它也给出了错误。然后我试过了

  asm
    PUSH BX
    MOV BX, N
    SAR BX, DampingCoefficient
    SUB N, BX
    POP BX
  end;

作为

  asm
    PUSH ESI
    MOV ESI, N
    SAR ESI, DampingCoefficient
    SUB N, ESI
    POP ESI
  end;

或者

  asm
    PUSH EDI
    MOV EDI, N
    SAR EDI, DampingCoefficient
    SUB N, EDI
    POP EDI
  end;

但它给出了一个错误,告诉“操作数大小不匹配”。Plaese,请帮帮我。

4

1 回答 1

0

至于操作数大小错误,为了将 N 的 16 位值加载到 32 位寄存器(在您的情况下为 ESI 或 EDI),您不能使用 MOV。您需要使用符号扩展操作 MOVSX(符号扩展)或 MOVZX(零扩展)之一:

  asm
    PUSH ESI
    //MOV ESI, N - not valid - you probably want:
    MOVZX ESI, N // load N into ESI with zero extend - or else:
    MOVSX ESI, N // load N into ESI with sign extend
    SAR ESI, DampingCoefficient
    SUB N, ESI
    POP ESI
  end;
于 2012-07-16T21:05:32.047 回答