2012-07-16 117 views
1

我是一個delphi學習者。我從Delphi DirectX 32位顏色

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

有 「DXDraw01」 下載一個Delphi的形式作用的項目, 「DXDIB01」, 「DXDIB02」, 「背景」,有的 「BitBtn」 S。實際項目是*位彩色操作。我試圖在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是一個32Bit的圖像。 Plaese幫助我。據我所知,問題是在以下過程定義:

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

我認爲一個或多個程序定義是有8Bit顏色操作。我無法理解哪一個是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,請幫助我。

回答

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; 
+0

我已經按照您的解決方案,但在「SUB再次「E2107操作數大小不匹配」的錯誤嘗試N,ESI'。請幫幫我。 – 2012-07-17 07:04:27

+0

這是同一類問題。由於N是一個SmallInt(帶符號的16位整數)SUB N,因此ESI會從16位數中減去一個32位數並將結果存儲在一個16位數中。這不是直接支持。您需要將N值加載到具有16位半值(EAX,EBX,ECX或EDX)的寄存器中,在那裏進行相減,然後將結果的16位部分存回N. - 使用已有的16位版本更容易。 – 2012-07-17 17:11:37

+1

現在我已經使用所有變量作爲Integer而不是SmallInt並使用以下命令。 'asm PUSH ESI MOV ESI,N SAR ESI,DampingCoefficient SUB N,ESI POP ESI end;'感謝大家的寶貴意見。 – 2012-07-26 19:02:39