Skip to content

Instantly share code, notes, and snippets.

@derofim
Created February 11, 2016 11:30
Show Gist options
  • Save derofim/912cfc9161269336f722 to your computer and use it in GitHub Desktop.
Save derofim/912cfc9161269336f722 to your computer and use it in GitHub Desktop.
SDL2 circle Drawing_and_Filling_Circles
// emcc source.cpp -s USE_SDL=2 -s FULL_ES2=1 --preload-file res/img -o publish\emsripten\index.html -O2 -s ALLOW_MEMORY_GROWTH=1 -s USE_SDL_IMAGE=2 -s SDL2_IMAGE_FORMATS="['png']" -std=c++11
// Ported SDL2 : http://content.gpwiki.org/index.php/SDL:Tutorials:Drawing_and_Filling_Circles
#include <chrono>
#include <thread>
#include <future>
#include <SDL.h>
#include <stdio.h>
#include <string>
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#include <SDL/SDL_image.h>
#else
#include <SDL_image.h>
#endif
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
//Starts up SDL and creates window
bool init();
//Loads media
bool loadMedia();
//Frees media and shuts down SDL
void close();
//The window we'll be rendering to
SDL_Window* gWindow = NULL;
//The window renderer
SDL_Renderer* gRenderer = NULL;
SDL_Event e;
bool quit = false;
void set_pixel(SDL_Renderer *rend, int x, int y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
SDL_SetRenderDrawColor(rend, r,g,b,a);
SDL_RenderDrawPoint(rend, x, y);
}
void draw_circle(SDL_Renderer *surface, int n_cx, int n_cy, int radius, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
// if the first pixel in the screen is represented by (0,0) (which is in sdl)
// remember that the beginning of the circle is not in the middle of the pixel
// but to the left-top from it:
double error = (double)-radius;
double x = (double)radius - 0.5;
double y = (double)0.5;
double cx = n_cx - 0.5;
double cy = n_cy - 0.5;
while (x >= y)
{
set_pixel(surface, (int)(cx + x), (int)(cy + y), r, g, b, a);
set_pixel(surface, (int)(cx + y), (int)(cy + x), r, g, b, a);
if (x != 0)
{
set_pixel(surface, (int)(cx - x), (int)(cy + y), r, g, b, a);
set_pixel(surface, (int)(cx + y), (int)(cy - x), r, g, b, a);
}
if (y != 0)
{
set_pixel(surface, (int)(cx + x), (int)(cy - y), r, g, b, a);
set_pixel(surface, (int)(cx - y), (int)(cy + x), r, g, b, a);
}
if (x != 0 && y != 0)
{
set_pixel(surface, (int)(cx - x), (int)(cy - y), r, g, b, a);
set_pixel(surface, (int)(cx - y), (int)(cy - x), r, g, b, a);
}
error += y;
++y;
error += y;
if (error >= 0)
{
--x;
error -= x;
error -= x;
}
/*
// sleep for debug
SDL_RenderPresent(gRenderer);
std::this_thread::sleep_for(std::chrono::milliseconds{ 100 });
*/
}
}
void fill_circle(SDL_Renderer *surface, int cx, int cy, int radius, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
// Note that there is more to altering the bitrate of this
// method than just changing this value. See how pixels are
// altered at the following web page for tips:
// http://www.libsdl.org/intro.en/usingvideo.html
static const int BPP = 4;
//double ra = (double)radius;
for (double dy = 1; dy <= radius; 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 * radius * dy) - (dy * dy)));
int x = cx - dx;
SDL_SetRenderDrawColor(gRenderer, r, g, b, a);
SDL_RenderDrawLine(gRenderer, cx - dx, cy + dy - radius, cx + dx, cy + dy - radius);
SDL_RenderDrawLine(gRenderer, cx - dx, cy - dy + radius, cx + dx, cy - dy + radius);
// 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;
}*/
/*
// sleep for debug
SDL_RenderPresent(gRenderer);
std::this_thread::sleep_for(std::chrono::milliseconds{ 100 });
*/
}
}
SDL_Texture* loadTexture(std::string path)
{
//The final texture
SDL_Texture* newTexture = NULL;
//Load image at specified path
SDL_Surface* loadedSurface = IMG_Load(path.c_str());
if (loadedSurface == NULL)
{
printf("Unable to load image %s! SDL_image Error: %s\n", path.c_str(), IMG_GetError());
}
else
{
//Create texture from surface pixels
newTexture = SDL_CreateTextureFromSurface(gRenderer, loadedSurface);
if (newTexture == NULL)
{
printf("Unable to create texture from %s! SDL Error: %s\n", path.c_str(), SDL_GetError());
}
//Get rid of old loaded surface
SDL_FreeSurface(loadedSurface);
}
return newTexture;
}
bool init()
{
//Initialization flag
bool success = true;
//Initialize SDL
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());
success = false;
}
else
{
//Create window
gWindow = SDL_CreateWindow("SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
if (gWindow == NULL)
{
printf("Window could not be created! SDL Error: %s\n", SDL_GetError());
success = false;
}
else
{
//Create renderer for window
gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED);
if (gRenderer == NULL)
{
printf("Renderer could not be created! SDL Error: %s\n", SDL_GetError());
success = false;
}
else
{
//Initialize renderer color
SDL_SetRenderDrawColor(gRenderer, 0xFF, 0xFF, 0xFF, 0xFF);
//Initialize PNG loading
int imgFlags = IMG_INIT_PNG;
if (!(IMG_Init(imgFlags) & imgFlags))
{
printf("SDL_image could not initialize! SDL_image Error: %s\n", IMG_GetError());
success = false;
}
}
}
}
return success;
}
bool loadMedia()
{
//Loading success flag
bool success = true;
return success;
}
void close()
{
//Free loaded images
//gSpriteSheetTexture.free();
//Destroy window
SDL_DestroyRenderer(gRenderer);
SDL_DestroyWindow(gWindow);
gWindow = NULL;
gRenderer = NULL;
//Quit SDL subsystems
IMG_Quit();
SDL_Quit();
}
void main_loop()
{
//Handle events on queue
while (SDL_PollEvent(&e) != 0)
{
//User requests quit
if (e.type == SDL_QUIT)
{
quit = true;
}
}
//Clear screen
SDL_SetRenderDrawColor(gRenderer, 0xFF, 0xFF, 0xFF, 0xFF);
SDL_RenderClear(gRenderer);
draw_circle(gRenderer, 300, 200, 50, 0x00, 0x00, 0xFF, 0xFF);
fill_circle(gRenderer, 100, 100, 50, 0xFF, 0x00, 0xFF, 0xFF);
//Update screen
SDL_RenderPresent(gRenderer);
}
int main(int argc, char* args[])
{
//Start up SDL and create window
if (!init())
{
printf("Failed to initialize!\n");
}
else
{
//Load media
if (!loadMedia())
{
printf("Failed to load media!\n");
}
else
{
#ifdef __EMSCRIPTEN__
emscripten_set_main_loop(main_loop, 0, 1);
#else
//While application is running
while (!quit)
{
main_loop();
}
#endif
}
}
//Free resources and close SDL
close();
return 0;
}
@AntonioCS
Copy link

Hey,

I can see that this is based on the Midpoint Circle Algorithm.
Can you give a few more insights on some of the changes you did?
The variables (of draw_circle) are different from that in the example and also the error correction.
I have implemented this in my own code and it seems to work fine as is.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment