绘制和填充圆

时间:2015-02-05 14:50:20

标签: c++ drawing sdl geometry

我刚开始使用c ++和VS 2013社区中的SDL。 我想绘制一个圆圈,所以我在Google上搜索了http://content.gpwiki.org/index.php/SDL:Tutorials:Drawing_and_Filling_Circles。但是当我试图在一个单独的fill_circle.cpp文件中实现它时,将它包含在我的main.cpp中并调用该函数,我得到错误,表示函数fill_circle()已在fill_circle.obj中定义并且存在冲突其他的库。 所以我试着将drawning函数直接实现到我的main.cpp中,但是我得到了一个类似的错误,说在fill_circle.obj中已经定义了void __cdecl fill_circle(struct SDL_Surface *,int,int,int,unsigned int)。

我不知道如何处理这些错误,并希望有人能帮助我:)。

编辑:在完全删除fill_circle.cpp和debug文件夹并在main.cpp中实现Function之后,programm将编译但在运行时抛出错误。

我的main.cpp:

    #include <SDL.h>
#include <iostream>
#include <cmath>

void fill_circle(SDL_Surface *surface, int cx, int cy, int radius, Uint32 pixel)
{
    static const int BPP = 4;

    double r = (double)radius;

    for (double dy = 1; dy <= r; dy += 1.0)
    {
        // This loop is unrolled a bit, only iterating through half of the
        // height of the circle.  The result is used to draw a scan line and
        // its mirror image below it.

        // The following formula has been simplified from our original.  We
        // are using half of the width of the circle because we are provided
        // with a center and we need left/right coordinates.

        double dx = floor(sqrt((2.0 * r * dy) - (dy * dy)));
        int x = cx - dx;

        // Grab a pointer to the left-most pixel for each half of the circle
        Uint8 *target_pixel_a = (Uint8 *)surface->pixels + ((int)(cy + r - dy)) * surface->pitch + x * BPP;
        Uint8 *target_pixel_b = (Uint8 *)surface->pixels + ((int)(cy - r + dy)) * surface->pitch + x * BPP;

        for (; x <= cx + dx; x++)
        {
            *(Uint32 *)target_pixel_a = pixel;
            *(Uint32 *)target_pixel_b = pixel;
            target_pixel_a += BPP;
            target_pixel_b += BPP;
        }
    }
}

int main(int argc, char *argv[])
{
    //Main loop flag
    bool b_Quit = false;
    //Event handler 
    SDL_Event ev;
    //SDL window
    SDL_Window *window = NULL;

    SDL_Surface *windowSurface;

    if (SDL_Init(SDL_INIT_VIDEO) < 0)
    {
        std::cout << "Video Initialisation Error: " << SDL_GetError() << std::endl;
    }
    else
    {
        window = SDL_CreateWindow("SDL_Project", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, SDL_WINDOW_SHOWN);
        if (window == NULL)
        {
            std::cout << "Window Creation Error: " << SDL_GetError() << std::endl;
        }
        else
        {
            windowSurface = SDL_GetWindowSurface(window);

            fill_circle(windowSurface, 10, 10, 20, 0xffffffff);

            //Main loop
            while (!b_Quit)
            {
                //Event Loop
                while (SDL_PollEvent(&ev) != 0)
                {
                    //Quit Event
                    if (ev.type == SDL_QUIT)
                    {
                        b_Quit = true;
                    }
                }
                SDL_UpdateWindowSurface(window);
            }

        }
    }

    SDL_DestroyWindow(window);
    SDL_Quit();

    return 0;
}

3 个答案:

答案 0 :(得分:1)

半径为20的圆圈,其半径为&#39;中心在(10,10),就像你有:

fill_circle(windowSurface, 10, 10, 20, 0xffffffff);

将使您处理分配曲面之外的像素

    ... = (Uint8 *)surface->pixels + ((int)(cy + r - dy)) * surface->pitch + x * BPP;
    ... = (Uint8 *)surface->pixels + ((int)(cy - r + dy)) * surface->pitch + x * BPP;

这会导致崩溃。

我在某些项目中使用了相同的算法,而在SDL 1.2中,它的编写方式并不是很安全。

答案 1 :(得分:1)

这可以帮到你:

void draw_circle(SDL_Point center, 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, center.x + dx, center.y + dy);
            }
        }
    }
}

答案 2 :(得分:1)

我刚刚进入这里寻找一个绘制实心圆的想法,并尝试了Ryozuki解决方案,但是它的成本很高,所以我在这里提出一个替代方案。

"../assets/img1.jpg"

您当然需要创建一个void TextureManager::fillCircle(const fig::cSphere _dst){ SDL_SetRenderDrawColor(Game::renderer, 0x00, 0x00, 0xff, 0xff); int p = std::sqrt(_dst.r * 2) + 4; for (unsigned char ii = 0; ii < p; ii++) { float angle = 2 * M_PI / p; fillTriangle( fig::cTria{ { _dst.pos.x + _dst.r*std::cos(ii * angle), _dst.pos.y + _dst.r*std::sin(ii * angle) }, { _dst.pos.x + _dst.r*std::cos((ii + 1) * angle), _dst.pos.y + _dst.r*std::sin((ii + 1) * angle) }, _dst.pos } ); }; SDL_SetRenderDrawColor(Game::renderer, 0xaa, 0xff, 0xaa, 0xff); } 函数,这将对此有所帮助:

fillTriangle()

关于奇怪的类,它们是:

void TextureManager::fillTriangle(const fig::cTria dst){
    fnc::small drawable = 0;

    for (fnc::small i = 0; i < 3; i++) 
        if (dst.points[i]->x == dst.points[(i + 1) % 3]->x) { drawable = (i + 2) % 3 + 1;  break; }
        else if (dst.points[i]->y == dst.points[(i + 1) % 3]->y) { drawable = (i + 2) % 3 + 4; break; }
    
    if (drawable == 0) {
        std::pair<fig::cTria, fig::cTria> t = dst.subdivide(
            dst.getboundary().siz.x < dst.getboundary().siz.y
        );
        fillTriangle(t.first);
        fillTriangle(t.second);
    }
    else if (drawable < 4){
        short dx = -dst.points[drawable - 1]->x + dst.points[drawable % 2]->x;
        SDL_SetRenderDrawColor(Game::renderer, 0xaa, 0xaa, 0xff, 0xff);
        for (short i = 0; true; i = fnc::aproach((float)i, 1, dx)) {
            SDL_RenderDrawLine(
                Game::renderer,
                dst.points[drawable - 1]->x + i,
                fnc::lerp(dst.points[drawable - 1]->y, dst.points[(drawable + 1) % 3]->y, (float)i / (float)dx),
                dst.points[drawable - 1]->x + i,
                fnc::lerp(dst.points[drawable - 1]->y, dst.points[drawable % 3]->y, (float)i / (float)dx)
            );
            if (i == dx) break;
        }
        SDL_SetRenderDrawColor(Game::renderer, 0xaa, 0xff, 0xaa, 0xff);
    }
    else {
        drawable -= 3;

        short dy = -dst.points[drawable - 1]->y + dst.points[drawable % 2]->y;
        SDL_SetRenderDrawColor(Game::renderer, 0xaa, 0xaa, 0xff, 0xff);
        for (short i = 0; true; i = fnc::aproach((float)i, 1, dy)) {
            SDL_RenderDrawLine(
                Game::renderer,
                fnc::lerp(dst.points[drawable - 1]->x, dst.points[(drawable + 1) % 3]->x, (float)i / (float)dy),
                dst.points[drawable - 1]->y + i,
                fnc::lerp(dst.points[drawable - 1]->x, dst.points[drawable % 3]->x, (float)i / (float)dy),
                dst.points[drawable - 1]->y + i
            );
            if (i == dy) break;
        }
        SDL_SetRenderDrawColor(Game::renderer, 0xaa, 0xff, 0xaa, 0xff);
    }
}

,并且using fnc::small = unsigned char; using fnc::ushort = unsigned short; using fnc::uint = unsigned int; 只是将三角形分为面积可为“可积分”的两个三角形。我的意思是,某种意义上说,一条线要么完全水平,要么完全垂直。 fig::cTria::subdivide()返回其中刻有三角形的fig::cTria::boudary()

在这里,我找到了解决此问题的另一种方法

fig::cRect

我认为它更快。 希望这对某人有帮助。 如果有人提出建议,他们将不胜感激