SDL2 function to draw a filled circle

I am looking for a function that draws a filled circle using SDL2 without using a renderer at all. I currently have this:

void Circle(int center_x, int center_y, int radius, SDL_Color color) {
  eraseOldCircle();

  uint32_t *pixels = (uint32_t *) windowSurface->pixels;
  SDL_PixelFormat *windowFormat = windowSurface->format;
  SDL_LockSurface(windowSurface); // Lock surface for direct pixel access capability

  int radiussqrd = radius * radius;

  for(int x=center_x-radius; x<=center_x+radius; x++) {
    int dx = center_x - x;
    for(int y=center_y-radius; y<=center_y+radius; y++) {
      int dy = center_y - y;
      if((dy * dy + dx * dx) <= radiussqrd) {
        pixels[(y * WIDTH + x)] = SDL_MapRGB(windowFormat, color.r, color.g, color.b);
      }
    }
  }

  SDL_UnlockSurface(windowSurface);
  SDL_UpdateWindowSurface(window);
}

which has been adapted from another function I found here, it draws the pixels directly to the windowSurface after calling eraseOldCircle (which puts the game's background image back to the previous position of the circle, effectively erasing it from there.) but it is still too slow for what I need (probably the maths?). What would be the fastest way to draw a circle using direct pixel access? I need it to be high speed so I can use it in a 2D game. I haven't been able to find anything until now, everything I see uses SDL_Renderer, but I should strictly never use it.

Here is eraseOldCircle() in case it helps:

void eraseOldCircle() {
  //Calculate previous position of ball
  SDL_Rect pos = {circlePosition.x-(radius+steps), circlePosition.y-(radius+steps), radius*radius, radius*2+steps};
  SDL_BlitSurface(backgroundImage, &pos, windowSurface, &pos);
}

Upvotes: 3

Views: 5888

Answers (2)

Peer Sommerlund
Peer Sommerlund

Reputation: 512

If you draw many circles, I would guess SDL_UpdateWindowSurface is where you spend the most time. Try this instead

  SDL_LockSurface
  // erase and draw all circles (possibly >1000)
  SDL_UnlockSurface
  SDL_UpdateWindowSurface

You can optimize your circle drawing code a bit, but it is probably fast enough. I also think that SDL_Renderer is probably fast enough.

The documentation for SDL_UpdateWindowSurface says it will copy the surface to the screen. You only need to do this once per frame.

Upvotes: 1

Ggsgn Hdjwngnf
Ggsgn Hdjwngnf

Reputation: 171

I'm not too sure how to do it with surfaces and memory management and all that, but if this helps, here is a version using an SDL_Renderer that runs pretty quickly:

void draw_circle(SDL_Renderer *renderer, int x, int y, int radius, SDL_Color color)
{
    SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
    for (int w = 0; w < radius * 2; w++)
    {
        for (int h = 0; h < radius * 2; h++)
        {
            int dx = radius - w; // horizontal offset
            int dy = radius - h; // vertical offset
            if ((dx*dx + dy*dy) <= (radius * radius))
            {
                SDL_RenderDrawPoint(renderer, x + dx, y + dy);
            }
        }
    }
}

Upvotes: 5

Related Questions