Delphi:Sierpinski三角形:程序没有完全运行

时间:2014-11-04 22:28:59

标签: delphi

我不明白为什么这段代码会这样:

enter image description here 只有左下角的三角形似乎在绘制,但内三角形只出现在顶部和右下三角形的第一个深度。我希望程序是递归的,但它是某种原因导致我的糟糕的编程技巧不是递归的。我真的想要了解我做错了什么。

implementation

{$R *.dfm}

var
  count : integer = 0;

procedure DrawTriangle(aCanvas: TCanvas;x,y,size : extended;n : integer);
var
  h : extended;
  w : extended;
  i : integer;
  x1,x2,x3,y1,y2,y3 : extended;
begin
    w := size;
    h := size;
    x1 := x;
    y1 := y;
    //ShowMessage(FloatToStr(w)+' '+FloatToStr(h));
  if aCanvas<>nil then
  try
    //1st - left
    aCanvas.MoveTo(Round(x1),Round(y1));
    aCanvas.LineTo(Round(x1+w*2),Round(y1));
    aCanvas.LineTo(Round(x1+w),Round(y1-h));
    aCanvas.LineTo(Round(x1),Round(y1));
    //2nd - right
    x2 := x1+w*2;
    y2 := y1;
    aCanvas.MoveTo(Round(x2),Round(y2));
    aCanvas.LineTo(Round(x2+w*2),Round(y2));
    aCanvas.LineTo(Round(x2+w),Round(y2-h));
    aCanvas.LineTo(Round(x2),Round(y2));
    //3rd - top
    x3 := x2-w;
    y3 := y2-h;
    aCanvas.MoveTo(Round(x3),Round(y3));
    aCanvas.LineTo(Round(x3+w*2),Round(y3));
    aCanvas.LineTo(Round(x3+w),Round(y3-h));
    aCanvas.LineTo(Round(x3),Round(y3));

    //Run itself
    inc(count);
    if count < n then
    begin
      DrawTriangle(aCanvas,x1,y1,size/2,n);
      DrawTriangle(aCanvas,x2,y2,size/2,n);
      DrawTriangle(aCanvas,x3,y3,size/2,n);
    end;
  except
    on e: exception do raise e;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  size : extended;
  i : integer;
  x,y : extended;
begin
  size := 100;
  x := 100;
  y := 400;
  DrawTriangle(Image1.Canvas,x,y,size,10);
end;
end.

4 个答案:

答案 0 :(得分:8)

问题在于您绘制了第一个三角形,然后调用DrawTriangle绘制左下角部分,然后调用DrawTriangle绘制新的左下角部分,依此类推,直到count达到n。然后我们一次将一个过程返回到原始过程,并且在每个步骤中我们仅绘制剩余的两个三角形。

以下逻辑按预期工作。 (删除全局count变量。)

procedure DrawTriangle(aCanvas: TCanvas; x, y, size: extended; n: integer);
var
  h: extended;
  w: extended;
  x1, x2, x3, y1, y2, y3: extended;
begin
  w := size;
  h := size;
  x1 := x;
  y1 := y;

  //1st - left
  aCanvas.MoveTo(Round(x1), Round(y1));
  aCanvas.LineTo(Round(x1+w*2), Round(y1));
  aCanvas.LineTo(Round(x1+w), Round(y1-h));
  aCanvas.LineTo(Round(x1), Round(y1));
  //2nd - right
  x2 := x1+w*2;
  y2 := y1;
  aCanvas.MoveTo(Round(x2), Round(y2));
  aCanvas.LineTo(Round(x2+w*2), Round(y2));
  aCanvas.LineTo(Round(x2+w), Round(y2-h));
  aCanvas.LineTo(Round(x2), Round(y2));
  //3rd - top
  x3 := x2-w;
  y3 := y2-h;
  aCanvas.MoveTo(Round(x3), Round(y3));
  aCanvas.LineTo(Round(x3+w*2), Round(y3));
  aCanvas.LineTo(Round(x3+w), Round(y3-h));
  aCanvas.LineTo(Round(x3), Round(y3));

  //Run itself
  if n > 0 then
  begin
    DrawTriangle(aCanvas, x1, y1, size/2, n-1);
    DrawTriangle(aCanvas, x2, y2, size/2, n-1);
    DrawTriangle(aCanvas, x3, y3, size/2, n-1);
  end;
end;

我把它作为练习来弄明白为什么它起作用。

另请注意,我删除了完全不必要的try..except块。

最后,你可以更有效地编写代码,如Rufo爵士的demonstrated

答案 1 :(得分:6)

您尝试限制递归深度包含错误。

您绘制3个内部三角形中的每一个并增加计数,然后再次调用 DrawTriangle 以在这些三角形内绘制三角形。每次调用都会再次增加计数 ,这意味着计数不会反映递归的深度,而只会反映 DrawTriangle 被调用的次数。指定限制为10后,您会发现在结果中已绘制了10组三角形。

除了增加计数以跟踪递归深度,您应该为每次调用减少 n ,直到 n = 0

为了使这个意图更清楚,你可以使用一个嵌套过程,其中外部调用接受内部嵌套过程指定的最大递归级别数,执行实际递归,指示剩余的级别数,并递减此递归的数字自称:

procedure DrawTriangle(aCanvas: TCanvas;x,y,size : extended; maxLevels: integer);

  procedure Draw(x,y,size: extended; levelsLeft: integer);
  var
    h : extended;
    w : extended;
    i : integer;
    x1,x2,x3,y1,y2,y3 : extended;
  begin
    w := size;
    h := size;
    x1 := x;
    y1 := y;

    //1st - left
    aCanvas.MoveTo(Round(x1),Round(y1));
    aCanvas.LineTo(Round(x1+w*2),Round(y1));
    aCanvas.LineTo(Round(x1+w),Round(y1-h));
    aCanvas.LineTo(Round(x1),Round(y1));

    //2nd - right
    x2 := x1+w*2;
    y2 := y1;
    aCanvas.MoveTo(Round(x2),Round(y2));
    aCanvas.LineTo(Round(x2+w*2),Round(y2));
    aCanvas.LineTo(Round(x2+w),Round(y2-h));
    aCanvas.LineTo(Round(x2),Round(y2));

    //3rd - top
    x3 := x2-w;
    y3 := y2-h;
    aCanvas.MoveTo(Round(x3),Round(y3));
    aCanvas.LineTo(Round(x3+w*2),Round(y3));
    aCanvas.LineTo(Round(x3+w),Round(y3-h));
    aCanvas.LineTo(Round(x3),Round(y3));

    //Run itself
    if (levelsLeft > 0) then
    begin
      Draw(x1, y1, size/2, levelsLeft - 1);
      Draw(x2, y2, size/2, levelsLeft - 1);
      Draw(x3, y3, size/2, levelsLeft - 1);
    end;
  end;

begin
  if Assigned(aCanvas) then
    Draw(x, y, size, maxLevels);
end;

这也允许以更清晰的方式测试前置条件,在这种情况下,当前限制为确保已指定画布,但也可能涉及在启动递归调用之前规范化或验证可能需要的其他参数。

由于原始参数保留在嵌套过程的作用域中,因此也意味着您可以将对递归过程的调用中的参数限制为仅在每次调用时实际更改的参数。 (我已在我的答案中更新了代码以加入此代码)。

顺便提一下,只是引发任何捕获的异常的try..except完全等同于根本没有try..except块,所以我将其从此实现中删除。

如果 size 的值达到某个最小值(内部三角形不明显,例如 size&lt; 2 )。

答案 2 :(得分:4)

作为给定答案的补充,这里是DRY版本:

procedure DrawTriangleDRY( aCanvas: TCanvas; CenterX, CenterY, Width, Height: extended; n: integer );
begin
  aCanvas.MoveTo( Round( CenterX ), Round( CenterY - Height / 2 ) ); // top
  aCanvas.LineTo( Round( CenterX + Width / 2 ), Round( CenterY + Height / 2 ) ); // bottom right
  aCanvas.LineTo( Round( CenterX - Width / 2 ), Round( CenterY + Height / 2 ) ); // bottom left
  aCanvas.LineTo( Round( CenterX ), Round( CenterY - Height / 2 ) ); // top

  // draw childs
  if n > 0
  then
    begin
      // top
      DrawTriangleDRY( aCanvas, CenterX, CenterY - Height / 4, Width / 2, Height / 2, n - 1 );
      // left
      DrawTriangleDRY( aCanvas, CenterX - Width / 4, CenterY + Height / 4, Width / 2, Height / 2, n - 1 );
      // right
      DrawTriangleDRY( aCanvas, CenterX + Width / 4, CenterY + Height / 4, Width / 2, Height / 2, n - 1 );
    end;
end;

<强>更新

我刚刚意识到,这可以优化为仅绘制最后一个孩子

procedure DrawTriangleDRY( aCanvas: TCanvas; CenterX, CenterY, Width, Height: extended; n: integer );
begin
  // draw childs
  if n > 0
  then
    begin
      DrawTriangleDRY( aCanvas, CenterX, CenterY - Height / 4, Width / 2, Height / 2, n - 1 ); // top
      DrawTriangleDRY( aCanvas, CenterX - Width / 4, CenterY + Height / 4, Width / 2, Height / 2, n - 1 ); // left
      DrawTriangleDRY( aCanvas, CenterX + Width / 4, CenterY + Height / 4, Width / 2, Height / 2, n - 1 ); // right
    end
  else
    begin
      aCanvas.MoveTo( Round( CenterX ), Round( CenterY - Height / 2 ) ); // top
      aCanvas.LineTo( Round( CenterX + Width / 2 ), Round( CenterY + Height / 2 ) ); // bottom right
      aCanvas.LineTo( Round( CenterX - Width / 2 ), Round( CenterY + Height / 2 ) ); // bottom left
      aCanvas.LineTo( Round( CenterX ), Round( CenterY - Height / 2 ) ); // top
    end
end;

答案 3 :(得分:-1)

我不知道我是否正确理解了您的问题,也不知道Sierpinski算法。但是,要表示实心三角形,则可以使用创建的用于表示实心多边形的函数(例如:四边形),因为它们始终可以划分为三角形,因此必须能够排除边的表示,否则,则可能发生三角形的一侧被相邻三角形的一侧覆盖的问题(显示透明多边形的问题)。 我向您建议的这是我的算法的Delphi实现,用于表示任何类型的三角形;不幸的是,如果您想使用Sierpinski算法,我的答案可能没有意义。我建议您尝试一下,因为它虽然非常复杂且有效,但速度却很快。这是我的Bresenham算法的变体。代表水平线段的例程的实现,我还是留给您使用(只需用Put替换对水平线段表示的HorizLine ()(阴影)Line ()的调用指令)。

这是数据类型:

Const R_OBP_Al=16; {16 Byte alignment; it must always be 2^N}
      DimOBP_H=16; {16 Byte of OBP HEADER; it must always be >=4}

Type TShadowTable=Array[0..255] Of Byte; {Array for shadows}

     T_Shadow_Table_Ptr=^TShadowTable; {Pointer to an array for shadows}

     T_Coord_XY=Record {Coordinates of a point}
      X
      Y :SmallInt;
     End;

     T_Pos_Coord_XY=Record {Coordinates of the clipping-region}
      X,
      Y :Word;
     End;

     T_Dim_XY=Record {Dimensions of the clipping-region}
      DimX,
      DimY :Word;
     End;

     T_Clipp_Rect=Record {Clipping-region's type}
      XY {Coordinates of the clipping-region} :T_Pos_Coord_XY;
      Dim_XY {Dimensions of the clipping-region} :T_Dim_XY;
     End;

     T_Clipp_Rect_Ptr=^T_Clipp_Rect; {Pointer to clipping-region's type}

     T_Rect=Record {Rectangle type}
      XY {Coordinates of the rectangle} :T_Coord_XY;
      Dim_XY {Dimensions of the rectangle} :T_Dim_XY;
     End;

     T_Rect_Ptr=^T_Rect; {Tipo PUNTATORE a RECORD RETTANGOLO}

这是三角形例程的主体:

Procedure Triangle_Wind(X1,Y1,X2,Y2,X3,Y3,
                        FillColor,BrdColAB,BrdColBC,BrdColCA:SmallInt;
                        ShadowTable:T_Shadow_Table_Ptr;
                        OBPVBuff:Pointer;
                        Clipp:T_Clipp_Rect_Ptr);

(* AVVERTENZA: Nonostante gli irrilevanti problemi
               nella visualizzazione del bordo, solido o trasparente,
               del triangolo, tuttora esistenti, dato che questa funzione
               è molto complessa, VIETATO APPORTARE MODIFICHE:
               FUNZIONE OTTIMIZZATA (HA RICHIESTO 60 ORE DI TEMPO,
               tra studio, sviluppo di un valido ALGORITMO, implementazione,
               beta-testing, realizzazione del programma
               di debugging ("TstQd.DPR") e debugging) ! *)

Var A,B,C, (* Identificatori vertici triangoli per ordinamento dei colori *)

    C1,C2,C3, (* VAR. temp.: contengono i colori BrdColAB, BrdColBC, BrdColCA *)

    XT, (* X1-XT è il SEGMENTO orizzontale da disegnare *)

    OY2, (* Valore iniziale della coordinata Y del 2° vertice del triangolo *)

    B1L,B1H, (* Coordinata X 1° e ultimo PUNTO del 1° bordo (Segm. orizz.) *)
    B2L,B2H, (* Coordinata X 1° e ultimo PUNTO del 2° bordo (Segm. orizz.) *)

    D0, (* Dimensione 1° bordo (Segm. orizz.) *)
    D1, (* Dimensione parte centrale Segm. orizz. *)
    D2, (* Dimensione 2° bordo (Segm. orizz.) *)

    Tmp, (* Variabile temporanea x scambio di 2 variabili *)

    Col1, (* Colore 1° bordo Segm. orizz. *)
    Col2, (* Colore 2° bordo Segm. orizz. *)

    CntX1, (* Contat. per coord. X 1° PUNTO Segm. orizz. (Bresenham) *)
    IncX1, (* Increm. contat. per coord. X 1° PUNTO Segm. OR. (Bresenham) *)
    CntY1, (* Contat. per coord. Y 1° PUNTO Segm. orizz. (Bresenham) *)
    Lim1, (* Limite per contat. coord. X e Y 1° PUNTO Segm. OR. (Bresenham) *)
    DirX1, (* Increm. coord. X 1° PUNTO Segm. orizz. *)
    IncY1, (* Increm. contat. per coord. Y 1° PUNTO Segm. OR. (Bresenham) *)
    FX1, (* Valore iniziale coord. X1 Segm. orizz. X1-XT *)

    CntXT, (* Contat. per coord. X 2° PUNTO Segm. orizz. (Bresenham) *)
    IncXT, (* Increm. contat. per coord. X 2° PUNTO Segm. OR. (Bresenham) *)
    CntYT, (* Contat. per coord. Y 2° PUNTO Segm. orizz. (Bresenham) *)
    LimT, (* Limite per contat. coord. X e Y 2° PUNTO Segm. OR. (Bresenham) *)
    DirXT, (* Increm. coord. X 2° PUNTO Segm. orizz. *)
    IncYT, (* Increm. contat. per coord. Y 2° PUNTO Segm. OR. (Bresenham) *)
    FXT (* Valore iniziale coord. XT Segm. orizz. X1-XT *):SmallInt;

    Segm (* RECORD per la rappresentazione di un Segm. orizz. *):T_Rect;
    F1, (* 1° condizione iniziale (eccezione), rappresentaz. triang. *)
    F24, (* 2° condizione iniziale (eccezione), rappresentaz. triang. *)
    Overflow, (* FALSE: Sta calc. il Segm. orizz.; TRUE: Ha finito *)
    Internal, (* Variabile temp. che salva il valore iniziale di OVERFLOW *)
    Finished (* FALSE: 2° semi-triang.; TRUE: 1° semi-triang. *) :Boolean;

Begin

 A:=0;
 B:=1;
 C:=2;

 (* Ordina i vertici IN base alla coordinata Y *)

 If Y1>Y2 Then
  Begin
   Tmp:=X1;
   X1:=X2;
   X2:=Tmp;
   Tmp:=Y1;
   Y1:=Y2;
   Y2:=Tmp;
   Tmp:=A;
   A:=B;
   B:=Tmp;
  End;

 If Y2>Y3 Then
  Begin
   Tmp:=X2;
   X2:=X3;
   X3:=Tmp;
   Tmp:=Y2;
   Y2:=Y3;
   Y3:=Tmp;
   Tmp:=B;
   B:=C;
   C:=Tmp;
  End;

 If Y1>Y2 Then
  Begin
   Tmp:=X1;
   X1:=X2;
   X2:=Tmp;
   Tmp:=Y1;
   Y1:=Y2;
   Y2:=Tmp;
   Tmp:=A;
   A:=B;
   B:=Tmp;
  End;

 (* Calcola il colore effettivo dei lati A-B, B-C e C-A del triangolo *)

 C1:=BrdColAB;
 C2:=BrdColBC;
 C3:=BrdColCA;

 Case 27*A+9*B+C Of
   19:Begin
       BrdColAB:=C3;
       BrdColCA:=C1;
      End;
   29:Begin
       BrdColBC:=C3;
       BrdColCA:=C2;
      End;
   45:Begin
       BrdColAB:=C2;
       BrdColBC:=C3;
       BrdColCA:=C1;
      End;
   55:Begin
       BrdColAB:=C3;
       BrdColBC:=C1;
       BrdColCA:=C2;
      End;
   63:Begin
       BrdColAB:=C2;
       BrdColBC:=C1;
      End;
 End;

 (* Calc. gli Incr. e i limiti, inizial. i cont. per il lato A-C (Bresenham) *)

 DirXT:=-1;
 IncXT:=X1-X3;
 If X1<X3 Then
  Begin
   DirXT:=1;
   IncXT:=-IncXT;
  End;
 Inc(IncXT);
 CntXT:=IncXT ShR 1;

 IncYT:=Y3-Y1+1;
 CntYT:=IncYT ShR 1;

 LimT:=IncXT;
 If IncXT<IncYT Then
  LimT:=IncYT;

 (* Imposta i valori iniziali delle VAR. locali *)

 XT:=X1;
 OY2:=Y2;

 Finished:=True;
 F1:=(Y1>=Y2) Or (Y2<>Y3);
 F24:=((Y1<>Y2) Or (Y2>=Y3)) And
      ((Y1>=Y2) Or (Y2>=Y3));

 (* Disegna il primo vertice del triangolo *)

 If (X1=X2) And (X2=X3) And
    (Y1=Y2) And (Y2=Y3) Then
  Begin
   Segm.XY.X:=X1;
   Segm.XY.Y:=Y1;
   Segm.Dim_XY.DimX:=1;
   Col1:=BrdColAB;
   If Col1<0 Then
    Col1:=BrdColCA;
   If Col1<0 Then
    Col1:=FillColor;
   If Col1>=0 Then
   If Col1<256 Then
    PutHorizLine(@Segm,OBPVBuff,Col1,Clipp)
   Else
    PutShadowHorizLine(@Segm,OBPVBuff,ShadowTable,Clipp);
  End;

 (* Disegna il triangolo *)

 Repeat

  (* Calc. gli Incr. e i limiti, inizial. i cont. per il lato A-B (Bresenham) *)

  DirX1:=-1;
  IncX1:=X1-X2;
  If X1<X2 Then
   Begin
    DirX1:=1;
    IncX1:=-IncX1;
   End;
  Inc(IncX1);
  CntX1:=IncX1 ShR 1;

  IncY1:=Y2-Y1+1;
  CntY1:=IncY1 ShR 1;

  Lim1:=IncX1;
  If IncX1<IncY1 Then
   Lim1:=IncY1;

  FX1:=X1;
  FXT:=XT;
  Overflow:=False;

  (* Rappresenta un semi-triangolo *)

  While (X1<>X2) Or (Y1<>Y2) Do
   Begin

    (* Calcola i 4 estremi del SEGMENTO orizzontale da disegnare *)

    Repeat

     Internal:=Overflow;

     If Overflow Then
      Begin

       Dec(CntY1,Lim1);
       Dec(CntYT,LimT);

       Inc(Y1);

      End;

     Overflow:=True;

     Tmp:=CntY1+IncY1;

     If Tmp<Lim1 Then
      Begin

       CntY1:=Tmp;
       Inc(CntX1,IncX1);

       If CntX1>=Lim1 Then
        Begin
         Dec(CntX1,Lim1);
         Inc(X1,DirX1);
        End;

       Overflow:=False;

      End;

     Tmp:=CntYT+IncYT;

     If Tmp<LimT Then
      Begin

       CntYT:=Tmp;
       Inc(CntXT,IncXT);

       If CntXT>=LimT Then
        Begin
         Dec(CntXT,LimT);
         Inc(XT,DirXT);
        End;

       Overflow:=False;

      End;

     If Internal Then
      Begin
       FX1:=X1;
       FXT:=XT;
      End;

    Until Overflow;

    (* Ordina (ordine ascendente) i 4 estremi del SEGMENTO orizzontale *)

    B1L:=FX1;
    B1H:=X1;

    If B1L>B1H Then
     Begin
      Tmp:=B1L;
      B1L:=B1H;
      B1H:=Tmp;
     End;

    B2L:=FXT;
    B2H:=XT;

    If B2L>B2H Then
     Begin
      Tmp:=B2L;
      B2L:=B2H;
      B2H:=Tmp;
     End;

    Col1:=BrdColAB;
    Col2:=BrdColCA;

    If (B2L<B1L) Or (B2H<B1H) Then
     Begin
      Tmp:=B1L;
      B1L:=B2L;
      B2L:=Tmp;
      Tmp:=B1H;
      B1H:=B2H;
      B2H:=Tmp;
      Tmp:=Col1;
      Col1:=Col2;
      Col2:=Tmp;
     End;

    D1:=B1H-B1L+1;
    D0:=B2L-B1H-1;
    D2:=B2H-B2L+1;

    (* Ove possibile unisce i bordi con la parte centrale del Segm. orizz. *)

    If D0>0 Then
     Begin

      If FillColor=Col2 Then (* Parte0 unita a parte2, parte0 esistente *)
       Begin
        Inc(D0,D2);
        D2:=0;
       End;

      If Col1=FillColor Then (* Parte0 unita a parte1, parte0 esistente *)
       Begin
        B1H:=B1L-1;
        Inc(D0,D1);
        D1:=0;
       End;

     End
    Else
     Begin

      D0:=0;

      If Col1=Col2 Then (* Parte1 unita a parte2, parte0 inesistente *)
       Begin
        D1:=B2H-B1L+1;
        D2:=0;
       End;

     End;

    (* Rappresenta il primo bordo del Segm. orizz. *)

    Segm.XY.Y:=Y1;

    Segm.XY.X:=B1L;
    Segm.Dim_XY.DimX:=D1;
    If Col1>=0 Then
    If Col1<256 Then
     PutHorizLine(@Segm,OBPVBuff,Col1,Clipp)
    Else
     PutShadowHorizLine(@Segm,OBPVBuff,ShadowTable,Clipp);

    (* Rappresenta la parte centrale del Segm. orizz. *)

    If (Y1<>OY2) Or
       (Not Finished Or F1) And (Finished Or F24) Then
     Begin
      Segm.XY.X:=B1H+1;
      Segm.Dim_XY.DimX:=D0;
      If FillColor>=0 Then
      If FillColor<256 Then
       PutHorizLine(@Segm,OBPVBuff,FillColor,Clipp)
      Else
       PutShadowHorizLine(@Segm,OBPVBuff,ShadowTable,Clipp);
     End;

    (* Rappresenta il secondo bordo del Segm. orizz. *)

    Segm.XY.X:=B2L;
    Segm.Dim_XY.DimX:=D2;
    If Col2>=0 Then
    If Col2<256 Then
     PutHorizLine(@Segm,OBPVBuff,Col2,Clipp)
    Else
     PutShadowHorizLine(@Segm,OBPVBuff,ShadowTable,Clipp);

   End;

  X2:=X3;
  Y2:=Y3;

  BrdColAB:=BrdColBC;

  Finished:=Not Finished;

 Until Finished;

End;

这是绘制水平线的例程:

Procedure PutHorizLine(Segm:T_Rect_Ptr;OBPVBuff:Pointer;
                       Color:Cardinal;
                       Clipp:T_Clipp_Rect_Ptr); Assembler;

Asm

     ClD                  {Direzione ascendente stringhe}

     Push  EBX            {Salva il REG. EBX sullo STACK}
     Push  EDI            {Salva il REG. EDI sullo STACK}
     Push  ESI            {Salva il REG. ESI sullo STACK}
     Push  EBP            {Salva il REG. EBP sullo STACK}

    {-----------------------------}

     Mov   ESI,Segm       {EAX}
     Mov   EDI,OBPVBuff   {EDX}
     Mov   EDX,Color      {ECX}
     Mov   EBP,Clipp

    {-----------------------------}

     Sub   ESP,5          {Alloca 2 VAR. locali sullo STACK}

    {[ESP+1]:              ClippY;
     [ESP]:                Color}

    {-----------------------------}

     Mov   [ESP],DL       {Salva Color}

    {-----------------------------}

     XOr   EAX,EAX        {Annulla EAX}

    {-----------------------------}

    {REG. EAX, EBX, ECX e EDX liberi}

     Cmp   EDI,EAX        {Se OBPVBuff = NIL ...}
     JE    @@00           {Allora Esce}

    {-----------------------------}

     Mov   EBX,EAX        {Annulla EBX}
     Mov   EDX,EAX        {Annulla EDX}

     Cmp   EBP,EAX        {Se Clipp=NIL ...}
     JE    @@01           {Allora Vai @@01}

     Mov   BX,[EBP]             {EBX <- ClippX}
     Mov   AX,[EBP+2]           {EAX <- ClippY}
     Mov   DX,[EBP+4]           {EDX <- ClippDimX}
     MovZX EBP,Word Ptr [EBP+6] {EBP <- ClippDimY}

    {-----------------------------}

@@01:Cmp   Word Ptr [EDI],0     {Se DimScrX<=0 ...}
     JLE   @@00                 {ha finito}

     Cmp   BX,0                 {Se ClippX<0 ...}
     JS    @@00                 {ha finito}

     Cmp   DX,0                 {Se ClippDimX<0 ...}
     JS    @@00                 {ha finito}
     JNE   @@02                 {Se ClippDimX=0 ...}

     Mov   DX,[EDI]             {allora ClippDimX <- DimScrX}

@@02:LEA   ECX,[EBX+EDX]        {Se ClippX+ClippDimX ...}
     Cmp   CX,[EDI]             {>DimScrX ...}
     JA    @@00                 {ha finito}

    {-----------------------------}

     Cmp   Word Ptr [EDI+2],0   {Se DimScrY<=0 ...}
     JLE   @@00                 {ha finito}

     Cmp   AX,0                 {Se ClippY<0 ...}
     JS    @@00                 {ha finito}

     Cmp   BP,0                 {Se ClippDimY<0 ...}
     JS    @@00                 {ha finito}
     JNE   @@03                 {Se ClippDimY=0 ...}

     Mov   BP,[EDI+2]           {allora ClippDimY <- DimScrY}

@@03:LEA   ECX,[EAX+EBP]        {Se ClippY+ClippDimY ...}
     Cmp   CX,[EDI+2]           {>DimScrY ...}
     JA    @@00                 {ha finito}

    {-----------------------------}

     Mov   [ESP+1],EAX          {Salva ClippY}

    {REG. EAX e ECX liberi}

    {-----------------------------}

     XOr   AX,AX          {Annulla EAX}
     Mov   ECX,EAX        {Annulla ECX}

     Cmp   ESI,EAX        {Se Segm=NIL ...}
     JE    @@04           {Allora Vai @@04}

     MovSX EAX,Word Ptr [ESI+2] {EAX <- Segm.XY.Y}
     Mov   CX,[ESI+4]           {ECX <- Segm.Dim_XY.DimX (DimX)}
     MovSX ESI,Word Ptr [ESI]   {ESI <- Segm.XY.X}

    {-----------------------------}

@@04:Cmp   AX,BP          {Se (Segm.XY.Y >= ClippDimY) O (Segm.XY.Y < 0) ...}
     JAE   @@00           {Allora Esce}

     Cmp   SI,DX          {Se Segm.XY.X >= ClippDimX ...}
     JGE   @@00           {Allora Esce}

     Or    CX,CX          {Se DimX <= 0 ...}
     JLE   @@00           {Allora Esce}

    {-----------------------------}

     Add   ECX,ESI        {INC (DimX, Segm.XY.X)}
     JLE   @@00           {Se DimX <= 0, Allora Esce}

     Or    SI,SI          {Se Segm.XY.X >= 0 ...}
     JNS   @@05           {Allora Vai @@05}

     XOr   ESI,ESI        {Segm.XY.X <- 0}

@@05:Cmp   CX,DX          {Se DimX <= ClippDimX ...}
     JBE   @@06           {Allora Vai @@06}

     Mov   CX,DX          {DimX <- ClippDimX}

@@06:Sub   ECX,ESI        {DEC (DimX, Segm.XY.X}
(*   JE    @@00           {Se DimX = 0, Allora Esce} *)

    {REG. EDX e EBP liberi}

    {-----------------------------}

     Mov   BP,[EDI]       {Calcola IN EBP la Dim. X di OBPVBuff^ ...}
     And   BP,R_OBP_Al-1
     Neg   BP
     Add   BP,R_OBP_Al
     And   BP,R_OBP_Al-1
     Add   BP,[EDI]       {allineata ai 16 BYTE (ADimX)}

    {-----------------------------}

     Add   EDI,EBX        {OBPVBuff + Clipp.XY.X}

    {-----------------------------}

     Add   EAX,[ESP+1]    {INC (Segm.XY.Y, Clipp.XY.Y)}

     Mul   EBP            {WAddr <- (Clipp.XY.Y + Segm.XY.Y) * ADimX}

     Add   EDI,EAX        {OBPVBuff + WAddr + ...}

     LEA   EDI,[EDI+ESI+DimOBP_H] {Segm.XY.X + DimOBP_H}

    {REG. EAX, EDX, ESI e EBX liberi}

    {-----------------------------}

     Mov   DL,[ESP]       {Ripristina Color dallo STACK}

     Mov   DH,DL          {Carica IN ogni BYTE di EAX ...}
     Mov   AX,DX
     ShL   EAX,16
     Mov   AX,DX          {il colore Color}

    {REG. EDX, ESI e EBX liberi}

    {-----------------------------}

     Mov   DL,CL          {DL <- Lo(DimX)}
     ShR   ECX,2          {ECX= DimX/4}
     Rep   StoSD          {Riempie ECX DoubleWord}
     SetB  CL             {ECX= resto di (DimX/2)/2}
     Rep   StoSW          {Riempie ECX WORD}
     Test  DL,1           {ECX= ...}
     SetNE CL             {resto di DimX/2}
     Rep   StoSB          {Riempie ECX BYTE}

    {-----------------------------}

@@00:Add   ESP,5          {Dealloca 2 VAR. locali dallo STACK}

    {-----------------------------}

     Pop   EBP            {Ripristina il REG. EBP dallo STACK}
     Pop   ESI            {Ripristina il REG. ESI dallo STACK}
     Pop   EDI            {Ripristina il REG. EDI dallo STACK}
     Pop   EBX            {Ripristina il REG. EBX dallo STACK}

End;

这里是透明水平线的表示形式:

Procedure PutShadowHorizLine(Segm:T_Rect_Ptr;OBPVBuff:Pointer;
                             ShadowTable:T_Shadow_Table_Ptr;
                             Clipp:T_Clipp_Rect_Ptr); Assembler;

Asm

     ClD                  {Direzione ascendente stringhe}

     Push  EBX            {Salva il REG. EBX sullo STACK}
     Push  EDI            {Salva il REG. EDI sullo STACK}
     Push  ESI            {Salva il REG. ESI sullo STACK}
     Push  EBP            {Salva il REG. EBP sullo STACK}

    {-----------------------------}

     Mov   ESI,Segm       {EAX}
     Mov   EDI,OBPVBuff   {EDX}
     Mov   EDX,ShadowTable{ECX}
     Mov   EBP,Clipp

    {-----------------------------}

     Sub   ESP,8          {Alloca 2 VAR. locali sullo STACK}

    {[ESP+4]:              ClippY;
     [ESP]:                ShadowTable}

    {-----------------------------}

     Mov   [ESP],EDX      {Salva ShadowTable}

    {-----------------------------}

     XOr   EAX,EAX        {Annulla EAX}

    {-----------------------------}

    {REG. EAX, EBX e ECX liberi}

     Cmp   EDI,EAX        {Se OBPVBuff = NIL ...}
     JE    @@00           {Allora Esce}

    {-----------------------------}

     Cmp   EDX,EAX        {Se ShadowTable = NIL ...}
     JE    @@00           {Allora Esce}

    {-----------------------------}

     Mov   EBX,EAX        {Annulla EBX}
     Mov   EDX,EAX        {Annulla EDX}

     Cmp   EBP,EAX        {Se Clipp=NIL ...}
     JE    @@01           {Allora Vai @@01}

     Mov   BX,[EBP]             {EBX <- ClippX}
     Mov   AX,[EBP+2]           {EAX <- ClippY}
     Mov   DX,[EBP+4]           {EDX <- ClippDimX}
     MovZX EBP,Word Ptr [EBP+6] {EBP <- ClippDimY}

    {-----------------------------}

@@01:Cmp   Word Ptr [EDI],0     {Se DimScrX<=0 ...}
     JLE   @@00                 {ha finito}

     Cmp   BX,0                 {Se ClippX<0 ...}
     JS    @@00                 {ha finito}

     Cmp   DX,0                 {Se ClippDimX<0 ...}
     JS    @@00                 {ha finito}
     JNE   @@02                 {Se ClippDimX=0 ...}

     Mov   DX,[EDI]             {allora ClippDimX <- DimScrX}

@@02:LEA   ECX,[EBX+EDX]        {Se ClippX+ClippDimX ...}
     Cmp   CX,[EDI]             {>DimScrX ...}
     JA    @@00                 {ha finito}

    {-----------------------------}

     Cmp   Word Ptr [EDI+2],0   {Se DimScrY<=0 ...}
     JLE   @@00                 {ha finito}

     Cmp   AX,0                 {Se ClippY<0 ...}
     JS    @@00                 {ha finito}

     Cmp   BP,0                 {Se ClippDimY<0 ...}
     JS    @@00                 {ha finito}
     JNE   @@03                 {Se ClippDimY=0 ...}

     Mov   BP,[EDI+2]           {allora ClippDimY <- DimScrY}

@@03:LEA   ECX,[EAX+EBP]        {Se ClippY+ClippDimY ...}
     Cmp   CX,[EDI+2]           {>DimScrY ...}
     JA    @@00                 {ha finito}

    {-----------------------------}

     Mov   [ESP+4],EAX          {Salva ClippY}

    {REG. EAX e ECX liberi}

    {-----------------------------}

     XOr   AX,AX          {Annulla EAX}
     Mov   ECX,EAX        {Annulla ECX}

     Cmp   ESI,EAX        {Se Segm=NIL ...}
     JE    @@04           {Allora Vai @@04}

     MovSX EAX,Word Ptr [ESI+2] {EAX <- Segm.XY.Y}
     Mov   CX,[ESI+4]           {ECX <- Segm.Dim_XY.DimX (DimX)}
     MovSX ESI,Word Ptr [ESI]   {ESI <- Segm.XY.X}

    {-----------------------------}

@@04:Cmp   AX,BP          {Se (Segm.XY.Y >= ClippDimY) O (Segm.XY.Y < 0) ...}
     JAE   @@00           {Allora Esce}

     Cmp   SI,DX          {Se Segm.XY.X >= ClippDimX ...}
     JGE   @@00           {Allora Esce}

     Or    CX,CX          {Se DimX <= 0 ...}
     JLE   @@00           {Allora Esce}

    {-----------------------------}

     Add   ECX,ESI        {INC (DimX, Segm.XY.X)}
     JLE   @@00           {Se DimX <= 0, Allora Esce}

     Or    SI,SI          {Se Segm.XY.X >= 0 ...}
     JNS   @@05           {Allora Vai @@05}

     XOr   ESI,ESI        {Segm.XY.X <- 0}

@@05:Cmp   CX,DX          {Se DimX <= ClippDimX ...}
     JBE   @@06           {Allora Vai @@06}

     Mov   CX,DX          {DimX <- ClippDimX}

@@06:Sub   ECX,ESI        {DEC (DimX, Segm.XY.X}
(*   JE    @@00           {Se DimX = 0, Allora Esce} *)

    {REG. EDX e EBP liberi}

    {-----------------------------}

     Mov   BP,[EDI]       {Calcola IN EBP la Dim. X di OBPVBuff^ ...}
     And   BP,R_OBP_Al-1
     Neg   BP
     Add   BP,R_OBP_Al
     And   BP,R_OBP_Al-1
     Add   BP,[EDI]       {allineata ai 16 BYTE (ADimX)}

    {-----------------------------}

     Add   EDI,EBX        {OBPVBuff + Clipp.XY.X}

    {-----------------------------}

     Add   EAX,[ESP+4]    {INC (Segm.XY.Y, Clipp.XY.Y)}

     Mul   EBP            {WAddr <- (Clipp.XY.Y + Segm.XY.Y) * ADimX}

     Add   EDI,EAX        {OBPVBuff + WAddr + ...}
     LEA   EDI,[EDI+ESI+DimOBP_H] {Segm.XY.X + DimOBP_H}

    {REG. EAX, EDX, ESI e EBX liberi}

    {-----------------------------}

     Mov   EDX,[ESP]      {Ripristina ShadowTable dallo STACK}
     XOr   EAX,EAX        {EAX <- 0}

    {REG. ESI e EBX liberi}

    {-----------------------------}

@@07:Mov   AL,[EDI]       {[WAddr] <- ...}
     Mov   AL,[EDX+EAX]   {ShadowTable^ ...}
     StoSB                {[[WAddr]]; INC (WAddr)}

     Loop  @@07           {Se DimY <> 0, Allora Ripete Ciclo}

    {-----------------------------}

@@00:Add   ESP,8          {Dealloca 2 VAR. locali dallo STACK}

    {-----------------------------}

     Pop   EBP            {Ripristina il REG. EBP dallo STACK}
     Pop   ESI            {Ripristina il REG. ESI dallo STACK}
     Pop   EDI            {Ripristina il REG. EDI dallo STACK}
     Pop   EBX            {Ripristina il REG. EBX dallo STACK}

End;

在BUFFER VIDEO上以OBP格式表示三角形A(X1,Y1)-B(X2,Y2)-C(X3,Y3),实心或实心,带有边框,实心或透明。

FillColor:三角形的内部颜色:

    -1= No filling;
0..255= Solid FillColor color filler;
   256= Transparent fill (use `ShadowTable^`).

BrdColAB:三角形A-B边的颜色:

    -1= No border;
0..255= Solid `BrdColAB` border color of side A-B;
   256= Transparent border (use `ShadowTable^`).

BrdColBC:三角形的B-C边的颜色:

    -1= No border;
0..255= Solid `BrdColBC` border color of side B-C;
   256= Transparent border (use `ShadowTable^`).

BrdColCA:三角形C-A边的颜色:

    -1= No border;
0..255= Solid `BrdColCA` border color of side C-A;
   256= Transparent border (use `ShadowTable^`).

您必须指定BrdColAB = BrdColBCBrdColAB = BrdColCABrdColAB <> FillColor来代表带边框的三角形。

您必须指定BrdColAB = BrdColBCBrdColAB = BrdColCABrdColAB = FillColor来表示一个完整的三角形。

OBPVBuff必须正确分配并包含“ OBP”格式的屏幕视频缓冲区。

“ OBP”格式(“一个字节,一个像素”)是我的图像格式8位/像素。

前2个字包含从左到右(X +)和从上到下(Y +)定向的图像。 该图像的行与16个字节对齐,因此当维度X不是16的倍数时,它们的最后一部分可以包含零,因为原点是(OBPVBuff + 16) ^。 我以OBPVBuff模式创建了内存的分配函数,返回始终与16个字节对齐。

地址输出到(OBPVBuff + 16) ^

Clipp指定的剪切区域必须始终具有带正坐标的原点,但是其尺寸可能会超出视频缓冲区。它们不允许裁剪区域为负尺寸(在任何情况下,裁剪区域都允许使用不正确的值)。

三角形的顶点的X n和Y n可以为任意坐标。

此函数使用我自己的通用Bresenham算法实现。