Created
February 11, 2016 11:30
-
-
Save derofim/912cfc9161269336f722 to your computer and use it in GitHub Desktop.
SDL2 circle Drawing_and_Filling_Circles
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.