I just started with SDL in c++ and VS 2013 Community. I want to draw a circle and so i searched on Google and found http://content.gpwiki.org/index.php/SDL:Tutorials:Drawing_and_Filling_Circles. But as I tried to implement it in a seperate fill_circle.cpp file, include this in my main.cpp and call the function, I get the Error that said function fill_circle() is already defined in fill_circle.obj and that there are conflicts with other libs. So I tried to implement the drawning function directly into my main.cpp but i get a similar error, saying that void __cdecl fill_circle(struct SDL_Surface *,int,int,int,unsigned int) is already defined in fill_circle.obj.
I dont know what to do with those errors and hope someone of you can help me :)
EDIT: After completly removing the fill_circle.cpp and debug folder and implementing the Function in main.cpp the programm will compile but throw an error at runtime.
My 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;
}
A circle with a radius of 20 with its' center at (10, 10) like you have:
fill_circle(windowSurface, 10, 10, 20, 0xffffffff);
Will make you address pixels outside of the allocated surface
... = (Uint8 *)surface->pixels + ((int)(cy + r - dy)) * surface->pitch + x * BPP;
... = (Uint8 *)surface->pixels + ((int)(cy - r + dy)) * surface->pitch + x * BPP;
This should cause a crash.
I have used the same algorithm in some projects and with SDL 1.2 it is not very safe the way it is written.
This can help you:
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);
}
}
}
}
i just entered here to search for an idea to draw a filled Circle and tried Ryozuki solution but its cost is inmense so i present here an alternative.
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);
}
You, of course, will need to create a fillTriangle()
function and this will help with that:
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);
}
}
and about the weird classes, they're:
using fnc::small = unsigned char;
using fnc::ushort = unsigned short;
using fnc::uint = unsigned int;
and also, the fig::cTria::subdivide()
just divide the triangle in two triangles whose area can be "integrable". I mean, in a way there is a line that's either totally horizontal or totally vertical. the fig::cTria::boudary()
returns the fig::cRect
in which the triangle is inscribed.
here, i've found another way to solve this problem
void TextureManager::fillCircle(const fig::cSphere _dst){
SDL_SetRenderDrawColor(Game::renderer, 0x00, 0x00, 0xff, 0xff);
for (fnc::uint dx = 0; dx < _dst.r * 2; dx++) {
SDL_RenderDrawLine(Game::renderer,
_dst.pos.x - _dst.r + dx,
_dst.pos.y + std::sqrtf(std::powf(_dst.r, 2) - std::powf(dx - _dst.r, 2)),
_dst.pos.x - _dst.r + dx,
_dst.pos.y - std::sqrtf(std::powf(_dst.r, 2) - std::powf(dx - _dst.r, 2))
);
}
SDL_SetRenderDrawColor(Game::renderer, 0xaa, 0xff, 0xaa, 0xff);
}
And i think it's faster. Hope this helps somebody. if someone have suggestions, they'll be appreciated
User contributions licensed under CC BY-SA 3.0