recently i was trying to draw a circle on the canvas of my window. the proc that comes with masm was actually of no use for that. so i made another one. it uses fpu and may therefore be a little slow.
simply copy and paste the code to your project. it's pretty self-explanatory:
* hwnd - handle to window which will contain the circle
* center_x - x-coordinate of center of circle
* center_y - y-coordinate of center of circle
* radius - radius of circle
* clr_circle - color of circle
(this is actually the right way to draw a circle, specifying a center and a radius and then do the drawing. not like specifying a rectangle and doing some circle stuff in it.)


_circle proc hwnd: dword, center_x: dword, center_y: dword, radius: dword, clr_circle: dword
local _px: dword, _py: dword, _i: dword
local _phi: dword
local _dc: dword
; set initial phi
fld1
mov eax, 100
push eax
fild dword ptr [esp]
pop eax
; calc: 1/100
fdiv
; -> phi = 0.01
fstp _phi
; get DC for hwnd
invoke GetDC, hwnd
mov _dc, eax
; loop putting of pixel
; max(i) * phi = 360
mov _i, 01
__loop_circle:
fld _phi
fimul _i ; i * phi
fsin ; sin(i * phi)
fimul radius ; sin(i * phi) * radius
fiadd ; sin(i * phi) * radius + center_x
fistp _px ; _px = ...
fld _phi
fimul _i ; i * phi
fcos ; cos(i * phi)
fimul radius ; cos(i * phi) * radius
fiadd center_y ; cos(i * phi) * radius + center_y
fistp _py ; _py = ...
invoke SetPixel, hdc, _px, _py, clr_circle
inc _i ; increment i
cmp _i, 3601 ; 3600 loops done?
jnz __loop_circle ; if not -> jump
; release DC
invoke ReleaseDC, hwnd, _dc
ret
_circle endp
Posted on 2003-02-22 17:42:21 by ploptor
The first thing which stands out is that you don't have to use the FPU for all 360 degrees. You only have to do it for 90 degrees. This by itself would speed up things by almost a factor of 4.

Secondly, you don't have to use the FPU to add the calculated values to the coordinates of the center. The CPU is a lot faster for additions where only integers are of importance.

Third, even calculating only for 90 degrees involves some 900 computations according to your algorithm. If your circle only has a radius of 100 pixels, you could still draw a perfect circle with at most 200 computations with the FPU, based on the relationship:
y ^2= r^2 - x^2

Fourth, based on that relationship, you could accelerate the whole process even more by using only the CPU for calculations.

(If you need a procedure for extracting square roots with the CPU, you can find one in the Mix.lib library available from Hutch's site. The sqrt32 procedure is probably faster than using the FPU and returns a rounded result.)

Raymond
Posted on 2003-02-22 20:37:53 by Raymond
The first thing which stands out is that you don't have to use the FPU for all 360 degrees. You only have to do it for 90 degrees. This by itself would speed up things by almost a factor of 4.
45 degrees, i.e. a factor of 8. This because there's a further simmetry if you swap x and y.

Anyway, there's no need for sin/cos at all.. circles can be drawn by differential equations.
Posted on 2003-02-23 03:52:50 by Maverick
Posted on 2003-02-23 07:09:28 by JohnFound



mov eax, 100
push eax
fild dword ptr [esp]
pop eax


Strange code... Why do you need eax to push 100? You can just push 100 :)
push 100
fild dword ptr
pop eax

mov eax,100 is 5 bytes instruction. push 100 - 2 bytes.
altogether it's wasting 1 clock and 4 bytes.
Posted on 2003-02-28 18:40:36 by The Svin
Calculate 1/8 of circle points



proc Circle
; ebx-r
; edi-buf
xor eax,eax ; x=0
lea ecx,[eax-3+2*ebx]
neg ecx ; u=3-2r
@@: mov [edi+0],eax
lea ecx,[ecx+4*eax+5]
mov [edi+4],ebx
add edi,8
inc eax ; x=x+1
inc ecx ; u=u+4*x+6
js @@b
lea edx,[4*ebx+4]
dec ebx ; y=y-1
sub ecx,edx ; u=u-4*y-4
@@b: cmp ebx,eax
jg @B
ret
endp

proc Circle2
; ebx-r
; edi-buf
xor eax,eax ; x=0
lea ecx,[eax-3+2*ebx]
neg ecx ; u=3-2r
@@: mov [edi+0],eax
lea ecx,[ecx+2*eax]
mov [edi+4],ebx
add edi,8
inc eax ; x=x+1
inc ecx ; u=u+2y+1
js @@b
lea edx,[2*ebx-1]
dec ebx ; y=y-1
sub ecx,edx ; u=u-2y+1
@@b: cmp ebx,eax
jg @B
ret
endp
Posted on 2003-03-01 03:59:25 by Nexo