10 Comments

User's avatar
Joost's avatar

Drawing a circle is an interesting challenge. I think I came up with an elegant solution. It isn’t particularly difficult, but it does require some aha-moments. My key insights were:

1) If you know one point on the circle, you can only go to one of three pixels from there. For each of these three pixels, calculate the distance to the center of the circle and pick the one that’s closest.

For example, let’s say we’re drawing the upper-right quadrant. We know that the pixel to the right of the center – at (radius, 0) – is on the circle. Since this is the upper-right quadrant, there are only three possible pixels that connect to it, to the left at (radius - 1, 0), to the top at (radius, -1), or to the topleft at (radius - 1, -1). Pick the pixel that’s closest to the center and repeat until you reach to point above the center.

2) You don’t need to use the square root.

Normally, calculating the distance to the center requires a call to sqrt(), but we’re never interested in the distance itself. All we need is to compare distances and squared distances work for that just as well.

3) If you know the distance to the center for the current pixel, it’s easy to calculate the distance when you move one pixel, because it changes by a predictable amount.

Suppose you know that the distance to the center is 0 for pixel (6, 8). Since this is in the bottom-right quadrant, moving one pixel up will get you closer to the center, but by how much? Well, the distance changes from 6^2 + 8^2 to 6 ^2 + 7^2 and the difference between 8^2 and 7^2 is 2 * 8 - 1. In general, if you move from x^2 to (x-1)^2, the difference is 2 * x - 1. You can also go in the other direction: if you move from x^2 to (x+1)^2, the difference is 2 * x + 1.

Coming up with those insights and verifying their correctness was the tricky part. After that, implementing the algorithm was pretty straightforward.

https://gist.github.com/joost-basic-bits/853215920d84fa1796ee5e500c90eda4

Expand full comment
gonutz's avatar

The third question is really interesting. I have this idea: Put the color you are looking for, e.g. binary 01, into a byte byte four times, e.g. 01010101. Then xor this with the byte you are looking at. Now the result will have two zeros where the color was found. E.g.:

01 00 11 01 the four pixels in our buffer

01 01 01 01 the color we look for

00 01 10 00 pixels XOR color

The first and last pixel are the color we are looking for.

I thus need to check whether the first two bits are zero, the second two bits are zero, the third two bits are zero or the last two bits are zero. Also multiple of these can be true, if the color exists more than once in these four pixels.

This could be done with four if-statements but we want to be fast. I just listed all bytes that meet any of these conditions, i.e. that have at least one 00 pair in the four positions. I tried to find a common pattern in these, e.g. every byte <= 84 means we found the color. But I do not really find a nice way to put a fence around these numbers using bit manipulation.

My answer would thus be to have a look-up table of 256 entries, i.e. an array of 256 bytes, and put 1 where there is a match.

The first step, making 01 into 01010101, can also be done with a four-element lookup-table.

I started learning programming with resources from around 1995 and I remember lookup-tables to be used a lot for graphics, so maybe this was the way they beat Borland :-D

The answer for me would then be:

int ContainsColor(char unsigned Pixel, char unsigned Color) {

return Matches[FourTimes[Color] ^ Pixel];

}

Expand full comment
8 more comments...

No posts