HOWTO draw circles, arcs and vector graphics in SDL?

前端 未结 4 2041
一个人的身影
一个人的身影 2021-02-02 15:43

(I\'m using SDL2)

SDL is a relatively small library for \"low level access to audio, keyboard, mouse, joystick, and graphics hardware via OpenGL and Direct3D\" It\'s us

相关标签:
4条回答
  • 2021-02-02 15:59

    If you want to write your own circle drawing function, then I'd suggest adapting the midpoint algorithm to SDL2 by drawing pixels.

    Curves would be done similarly, but would use more of an ellipses drawing algorithm.

    Actual vector graphics start to get much more complicated, and you'd probably have to find something that renders SVG files, which I'm not sure there are many options for SDL2.

    However, if you would rather simply have functions that you can work with I'd suggest going straight to SDL2_gfx instead. It has many more functions already implemented for you to work with.

    0 讨论(0)
  • 2021-02-02 15:59

    If you want to do a circle or ellipse without 3rd party libraries, include math.h and use the function below I wrote. It will draw aliased ellipse or circles very well. Tested on SDL 2.0.2 and works. It draws one quadrant arc, and mirrors the other arcs, reducing calls to cosf and sinf.

    //draw one quadrant arc, and mirror the other 4 quadrants
    void sdl_ellipse(SDL_Renderer* r, int x0, int y0, int radiusX, int radiusY)
    {
        float pi  = 3.14159265358979323846264338327950288419716939937510;
        float pih = pi / 2.0; //half of pi
    
        //drew  28 lines with   4x4  circle with precision of 150 0ms
        //drew 132 lines with  25x14 circle with precision of 150 0ms
        //drew 152 lines with 100x50 circle with precision of 150 3ms
        const int prec = 27; // precision value; value of 1 will draw a diamond, 27 makes pretty smooth circles.
        float theta = 0;     // angle that will be increased each loop
    
        //starting point
        int x  = (float)radiusX * cos(theta);//start point
        int y  = (float)radiusY * sin(theta);//start point
        int x1 = x;
        int y1 = y;
    
        //repeat until theta >= 90;
        float step = pih/(float)prec; // amount to add to theta each time (degrees)
        for(theta=step;  theta <= pih;  theta+=step)//step through only a 90 arc (1 quadrant)
        {
            //get new point location
            x1 = (float)radiusX * cosf(theta) + 0.5; //new point (+.5 is a quick rounding method)
            y1 = (float)radiusY * sinf(theta) + 0.5; //new point (+.5 is a quick rounding method)
    
            //draw line from previous point to new point, ONLY if point incremented
            if( (x != x1) || (y != y1) )//only draw if coordinate changed
            {
                SDL_RenderDrawLine(r, x0 + x, y0 - y,    x0 + x1, y0 - y1 );//quadrant TR
                SDL_RenderDrawLine(r, x0 - x, y0 - y,    x0 - x1, y0 - y1 );//quadrant TL
                SDL_RenderDrawLine(r, x0 - x, y0 + y,    x0 - x1, y0 + y1 );//quadrant BL
                SDL_RenderDrawLine(r, x0 + x, y0 + y,    x0 + x1, y0 + y1 );//quadrant BR
            }
            //save previous points
            x = x1;//save new previous point
            y = y1;//save new previous point
        }
        //arc did not finish because of rounding, so finish the arc
        if(x!=0)
        {
            x=0;
            SDL_RenderDrawLine(r, x0 + x, y0 - y,    x0 + x1, y0 - y1 );//quadrant TR
            SDL_RenderDrawLine(r, x0 - x, y0 - y,    x0 - x1, y0 - y1 );//quadrant TL
            SDL_RenderDrawLine(r, x0 - x, y0 + y,    x0 - x1, y0 + y1 );//quadrant BL
            SDL_RenderDrawLine(r, x0 + x, y0 + y,    x0 + x1, y0 + y1 );//quadrant BR
        }
    }
    
    0 讨论(0)
  • 2021-02-02 16:08

    This is an example of the Midpoint Circle Algorithm as referenced above. It doesn't require a math library and is very fast. (Renders in about 500 microseconds) This is what Windows uses/used to rasterize circles.

    void DrawCircle(SDL_Renderer * renderer, int32_t centreX, int32_t centreY, int32_t radius)
    {
       const int32_t diameter = (radius * 2);
    
       int32_t x = (radius - 1);
       int32_t y = 0;
       int32_t tx = 1;
       int32_t ty = 1;
       int32_t error = (tx - diameter);
    
       while (x >= y)
       {
          //  Each of the following renders an octant of the circle
          SDL_RenderDrawPoint(renderer, centreX + x, centreY - y);
          SDL_RenderDrawPoint(renderer, centreX + x, centreY + y);
          SDL_RenderDrawPoint(renderer, centreX - x, centreY - y);
          SDL_RenderDrawPoint(renderer, centreX - x, centreY + y);
          SDL_RenderDrawPoint(renderer, centreX + y, centreY - x);
          SDL_RenderDrawPoint(renderer, centreX + y, centreY + x);
          SDL_RenderDrawPoint(renderer, centreX - y, centreY - x);
          SDL_RenderDrawPoint(renderer, centreX - y, centreY + x);
    
          if (error <= 0)
          {
             ++y;
             error += ty;
             ty += 2;
          }
    
          if (error > 0)
          {
             --x;
             tx += 2;
             error += (tx - diameter);
          }
       }
    }
    
    0 讨论(0)
  • 2021-02-02 16:15

    SDL allows for third party libs to draw on a texture. If cairo was desirable, it could be used in a function like this:

    cairo_t*cb(cairo_t*cr)
    {cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
     cairo_rectangle(cr, 10, 20, 128, 128);
     cairo_stroke(cr);
     return cr;
    }
    

    then cb can be passed to this function:

    cairo_t*cai(SDL_Window*w,SDL_Renderer*r,cairo_t*(*f)(cairo_t*))
    {int width, height, pitch;void *pixels;
     SDL_GetWindowSize(w, &width, &height);
     SDL_Texture*t=SDL_CreateTexture(r,SDL_PIXELFORMAT_ARGB8888,SDL_TEXTUREACCESS_STREAMING,width,height);
     SDL_LockTexture(t, NULL, &pixels, &pitch);
     cairo_surface_t *cs=cairo_image_surface_create_for_data(pixels,CAIRO_FORMAT_ARGB32,width,height,pitch);
     cairo_t*s=cairo_create(cs);
     cairo_t*fr=f(s);SDL_UnlockTexture(t);SDL_RenderCopy(r,t,NULL,NULL);SDL_RenderPresent(r);
     return fr;
    }
    
    0 讨论(0)
提交回复
热议问题