如果你所说的最快是指最快的编写,这里有一个简单的 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
每个数字可能是位或字节,具体取决于您的速度与内存限制。
然后,您可以将此块直接复制到视频内存中或将其用作模板(一种色度键技术)。
为了打印圆的其他四分之三,只需使用计数器即可。
如果半径不固定,您可以将上面的代码提升
- 内联函数调用
- 尽量避免使用栈
- 不要在每个周期计算距离,而是使用基本微积分从先前的值计算距离。
- 一次计算多于一个像素并结合文字。