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.)

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

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

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

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.

```
```

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.

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