我不明白为什么这段代码会这样:
只有左下角的三角形似乎在绘制,但内三角形只出现在顶部和右下三角形的第一个深度。我希望程序是递归的,但它是某种原因导致我的糟糕的编程技巧不是递归的。我真的想要了解我做错了什么。
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.
答案 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
= BrdColBC
,BrdColAB
= BrdColCA
和BrdColAB
<> FillColor
来代表带边框的三角形。
您必须指定BrdColAB
= BrdColBC
,BrdColAB
= BrdColCA
,BrdColAB
= FillColor
来表示一个完整的三角形。
OBPVBuff
必须正确分配并包含“ OBP”格式的屏幕视频缓冲区。
“ OBP”格式(“一个字节,一个像素”)是我的图像格式8位/像素。
前2个字包含从左到右(X +)和从上到下(Y +)定向的图像。
该图像的行与16个字节对齐,因此当维度X不是16的倍数时,它们的最后一部分可以包含零,因为原点是(OBPVBuff + 16) ^
。
我以OBPVBuff模式创建了内存的分配函数,返回始终与16个字节对齐。
地址输出到(OBPVBuff + 16) ^
。
由Clipp
指定的剪切区域必须始终具有带正坐标的原点,但是其尺寸可能会超出视频缓冲区。它们不允许裁剪区域为负尺寸(在任何情况下,裁剪区域都允许使用不正确的值)。
三角形的顶点的X
n和Y
n可以为任意坐标。
此函数使用我自己的通用Bresenham
算法实现。