在装配中绘制完美填充的圆(圆盘)的最简单方法是什么?
What is the easiest way to draw a perfectly filled circle(disc) in assembly?
我想在 320x200 模式下以 100 像素半径在组件中绘制一个完美填充的*圆(圆盘)。 quickest/easiest 方法是什么?
(*:我的意思是,当光盘的颜色为常亮白色且其中没有黑色像素时,光盘就完美填充了。)
如果您所说的最快是指最快的编写速度,这里有一个简单的 DOS 解决方案。
除了退出服务外,它不使用任何 DOS 服务。
它旨在生成一个 COM 文件(带有 NASM 的原始输出很好,只需将其重命名为 COM 扩展名即可)。
BITS 16
ORG 100h
push 0a000h ;Video memory graphics segment
pop es
mov ax, 0013h ;320x200@8bpp
int 10h
push 09h ;Blue
push 159 ;cX
push 99 ;cY
push 60 ;Radius
call drawFilledCircle
;Wait for a key
xor ah, ah
int 16h
;Restore text mode
mov ax, 0003h
int 10h
;Return
mov ax, 4c00h
int 21h
;Color
;cX
;cY
;R
drawFilledCircle:
push bp
mov bp, sp
sub sp, 02h
mov cx, WORD [bp+04h] ;R
mov ax, cx
mul ax ;AX = R^2
mov WORD [bp-02h], ax ;[bp-02h] = R^2
mov ax, WORD [bp+06h]
sub ax, cx ;i = cY-R
mov bx, WORD [bp+08h]
sub bx, cx ;j = cX-R
shl cx, 1
mov dx, cx ;DX = Copy of 2R
.advance_v:
push cx
push bx
mov cx, dx
.advance_h:
;Save values
push bx
push ax
push dx
;Compute (i-y) and (j-x)
sub ax, WORD [bp+06h]
sub bx, WORD [bp+08h]
mul ax ;Compute (i-y)^2
push ax
mov ax, bx
mul ax
pop bx ;Compute (j-x)^2 in ax, (i-y)^2 is in bx now
add ax, bx ;(j-x)^2 + (i-y)^2
cmp ax, WORD [bp-02h] ;;(j-x)^2 + (i-y)^2 <= R^2
;Restore values before jump
pop dx
pop ax
pop bx
ja .continue ;Skip pixel if (j-x)^2 + (i-y)^2 > R^2
;Write pixel
push WORD [bp+0ah]
push bx
push ax
call writePx
.continue:
;Advance j
inc bx
loop .advance_h
;Advance i
inc ax
pop bx ;Restore j
pop cx ;Restore counter
loop .advance_v
add sp, 02h
pop bp
ret 08h
;Color
;X
;Y
writePx:
push bp
mov bp, sp
push ax
push bx
mov bx, WORD [bp+04h]
mov ax, bx
shl bx, 6
shl ax, 8
add bx, ax ;320 = 256 + 64
add bx, WORD [bp+06h]
mov ax, WORD [bp+08h]
;TODO: Clip
mov BYTE [es:bx], al
pop bx
pop ax
pop bp
ret 06h
只是给定一些参数写平面图形的一种常用技术,称为光栅化。
给定圆心 C(x, y) 和半径 R的圆,算法如下
1. For i = y-R to y+R
1.1 For j = x-R to x+R
1.1.1 If (i-y)^2 + (j-x)^2 <= R^2 Then
1.1.1.1 DrawPixel(j, i)
1.1.1 End if
1.1 End For
1. End For
这根本没有针对速度进行优化!
为了清楚起见,我确实创建了多个例程。
我也经常使用堆栈。
注意 writePx
不裁剪坐标!
如果您想加快速度,您需要更具体地满足您的要求。
例如,半径总是固定的吗?如果是的话,你可以使用一个编码四分之一圆的内存块,像这样
0 0 0 0 0 1 1 1
0 0 0 1 1 1 1 1
0 0 1 1 1 1 1 1
0 1 1 1 1 1 1 1
0 1 1 1 1 1 1 1
0 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
其中每个数字可能是一位或一个字节,具体取决于您的速度与内存限制。
然后您可以将此块直接复制到视频内存中或将其用作模板(一种色度键技术)。
要打印圆的其他四分之三,请简单地玩计数器。
如果半径不固定你可以通过
提升上面的代码
- 内联函数调用
- 尽量避免使用栈
- 不要在每个周期都计算距离,而是使用基本微积分根据先前的值计算距离。
- 一次计算超过一个像素并组合文字。
找到关于如何画圆的这篇文章。抱歉,未满。在这里阅读整篇文章:
http://groups.csail.mit.edu/graphics/classes/6.837/F98/Lecture6/circle.html
//Circle
public void circleMidpoint(int xCenter, int yCenter, int radius, Color c)
{
int pix = c.getRGB();
int x = 0;
int y = radius;
int p = (5 - radius*4)/4;
circlePoints(xCenter, yCenter, x, y, pix);
while (x < y) {
x++;
if (p < 0) {
p += 2*x+1;
} else {
y--;
p += 2*(x-y)+1;
}
circlePoints(xCenter, yCenter, x, y, pix);
}
}
//pixel plotter
private final void circlePoints(int cx, int cy, int x, int y, int pix)
{
int act = Color.red.getRGB();
if (x == 0) {
raster.setPixel(act, cx, cy + y);
raster.setPixel(pix, cx, cy - y);
raster.setPixel(pix, cx + y, cy);
raster.setPixel(pix, cx - y, cy);
} else
if (x == y) {
raster.setPixel(act, cx + x, cy + y);
raster.setPixel(pix, cx - x, cy + y);
raster.setPixel(pix, cx + x, cy - y);
raster.setPixel(pix, cx - x, cy - y);
} else
if (x < y) {
raster.setPixel(act, cx + x, cy + y);
raster.setPixel(pix, cx - x, cy + y);
raster.setPixel(pix, cx + x, cy - y);
raster.setPixel(pix, cx - x, cy - y);
raster.setPixel(pix, cx + y, cy + x);
raster.setPixel(pix, cx - y, cy + x);
raster.setPixel(pix, cx + y, cy - x);
raster.setPixel(pix, cx - y, cy - x);
}
}
我想在 320x200 模式下以 100 像素半径在组件中绘制一个完美填充的*圆(圆盘)。 quickest/easiest 方法是什么?
(*:我的意思是,当光盘的颜色为常亮白色且其中没有黑色像素时,光盘就完美填充了。)
如果您所说的最快是指最快的编写速度,这里有一个简单的 DOS 解决方案。
除了退出服务外,它不使用任何 DOS 服务。
它旨在生成一个 COM 文件(带有 NASM 的原始输出很好,只需将其重命名为 COM 扩展名即可)。
BITS 16
ORG 100h
push 0a000h ;Video memory graphics segment
pop es
mov ax, 0013h ;320x200@8bpp
int 10h
push 09h ;Blue
push 159 ;cX
push 99 ;cY
push 60 ;Radius
call drawFilledCircle
;Wait for a key
xor ah, ah
int 16h
;Restore text mode
mov ax, 0003h
int 10h
;Return
mov ax, 4c00h
int 21h
;Color
;cX
;cY
;R
drawFilledCircle:
push bp
mov bp, sp
sub sp, 02h
mov cx, WORD [bp+04h] ;R
mov ax, cx
mul ax ;AX = R^2
mov WORD [bp-02h], ax ;[bp-02h] = R^2
mov ax, WORD [bp+06h]
sub ax, cx ;i = cY-R
mov bx, WORD [bp+08h]
sub bx, cx ;j = cX-R
shl cx, 1
mov dx, cx ;DX = Copy of 2R
.advance_v:
push cx
push bx
mov cx, dx
.advance_h:
;Save values
push bx
push ax
push dx
;Compute (i-y) and (j-x)
sub ax, WORD [bp+06h]
sub bx, WORD [bp+08h]
mul ax ;Compute (i-y)^2
push ax
mov ax, bx
mul ax
pop bx ;Compute (j-x)^2 in ax, (i-y)^2 is in bx now
add ax, bx ;(j-x)^2 + (i-y)^2
cmp ax, WORD [bp-02h] ;;(j-x)^2 + (i-y)^2 <= R^2
;Restore values before jump
pop dx
pop ax
pop bx
ja .continue ;Skip pixel if (j-x)^2 + (i-y)^2 > R^2
;Write pixel
push WORD [bp+0ah]
push bx
push ax
call writePx
.continue:
;Advance j
inc bx
loop .advance_h
;Advance i
inc ax
pop bx ;Restore j
pop cx ;Restore counter
loop .advance_v
add sp, 02h
pop bp
ret 08h
;Color
;X
;Y
writePx:
push bp
mov bp, sp
push ax
push bx
mov bx, WORD [bp+04h]
mov ax, bx
shl bx, 6
shl ax, 8
add bx, ax ;320 = 256 + 64
add bx, WORD [bp+06h]
mov ax, WORD [bp+08h]
;TODO: Clip
mov BYTE [es:bx], al
pop bx
pop ax
pop bp
ret 06h
只是给定一些参数写平面图形的一种常用技术,称为光栅化。
给定圆心 C(x, y) 和半径 R的圆,算法如下
1. For i = y-R to y+R
1.1 For j = x-R to x+R
1.1.1 If (i-y)^2 + (j-x)^2 <= R^2 Then
1.1.1.1 DrawPixel(j, i)
1.1.1 End if
1.1 End For
1. End For
这根本没有针对速度进行优化!
为了清楚起见,我确实创建了多个例程。
我也经常使用堆栈。
注意 writePx
不裁剪坐标!
如果您想加快速度,您需要更具体地满足您的要求。
例如,半径总是固定的吗?如果是的话,你可以使用一个编码四分之一圆的内存块,像这样
0 0 0 0 0 1 1 1
0 0 0 1 1 1 1 1
0 0 1 1 1 1 1 1
0 1 1 1 1 1 1 1
0 1 1 1 1 1 1 1
0 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
其中每个数字可能是一位或一个字节,具体取决于您的速度与内存限制。
然后您可以将此块直接复制到视频内存中或将其用作模板(一种色度键技术)。
要打印圆的其他四分之三,请简单地玩计数器。
如果半径不固定你可以通过
提升上面的代码- 内联函数调用
- 尽量避免使用栈
- 不要在每个周期都计算距离,而是使用基本微积分根据先前的值计算距离。
- 一次计算超过一个像素并组合文字。
找到关于如何画圆的这篇文章。抱歉,未满。在这里阅读整篇文章: http://groups.csail.mit.edu/graphics/classes/6.837/F98/Lecture6/circle.html
//Circle
public void circleMidpoint(int xCenter, int yCenter, int radius, Color c)
{
int pix = c.getRGB();
int x = 0;
int y = radius;
int p = (5 - radius*4)/4;
circlePoints(xCenter, yCenter, x, y, pix);
while (x < y) {
x++;
if (p < 0) {
p += 2*x+1;
} else {
y--;
p += 2*(x-y)+1;
}
circlePoints(xCenter, yCenter, x, y, pix);
}
}
//pixel plotter
private final void circlePoints(int cx, int cy, int x, int y, int pix)
{
int act = Color.red.getRGB();
if (x == 0) {
raster.setPixel(act, cx, cy + y);
raster.setPixel(pix, cx, cy - y);
raster.setPixel(pix, cx + y, cy);
raster.setPixel(pix, cx - y, cy);
} else
if (x == y) {
raster.setPixel(act, cx + x, cy + y);
raster.setPixel(pix, cx - x, cy + y);
raster.setPixel(pix, cx + x, cy - y);
raster.setPixel(pix, cx - x, cy - y);
} else
if (x < y) {
raster.setPixel(act, cx + x, cy + y);
raster.setPixel(pix, cx - x, cy + y);
raster.setPixel(pix, cx + x, cy - y);
raster.setPixel(pix, cx - x, cy - y);
raster.setPixel(pix, cx + y, cy + x);
raster.setPixel(pix, cx - y, cy + x);
raster.setPixel(pix, cx + y, cy - x);
raster.setPixel(pix, cx - y, cy - x);
}
}