/* SDL2 utility functions - ASCII Art assignment version for Eurographics 2017 Education Papers */ /* by Eike Falk Anderson, The National Centre for Computer Animation, Bournemouth University, UK */ typedef struct RGBcolour { Uint8 r; Uint8 g; Uint8 b; } RGBcolour; /* easier than handling 3 separate values */ void line(SDL_Renderer *renderer,int wdth,int hght,int x0,int y0,int xn,int yn,RGBcolour c) /* Bresenham's Line Drawing Algorithm */ { /* SDL renderer, screen width, screen height, line start x/y, line end x/y, drawing colour */ int dx = abs(xn-x0), sx = x0dy ? dx : -dy)/2, e2; SDL_SetRenderDrawColor(renderer,c.r,c.g,c.b,255); while(1) { /* draw point only if coordinate is valid */ if(x0>=0 && x0=0 && y0-dx) { error -= dy; x0 += sx; } if(e2 < dy) { error += dx; y0 += sy; } } } void circle(SDL_Renderer *renderer,int width,int height,int x0,int y0,int radius,RGBcolour col) /* Bresenham Circle */ { /* SDL renderer, screen width, screen height, circle centre x/y, circle radius, drawing colour */ int x = radius, y=0, error = 1-radius; SDL_SetRenderDrawColor(renderer, col.r, col.g, col.b, 255); while(x>=y) { /* 1 draw call for each octant - ensure coordinates are valid before drawing */ if((x+x0)>=0 && (x+x0)=0 && (y+y0)=0 && (y+x0)=0 && (x+y0)=0 && (-x+x0)=0 && (y+y0)=0 && (-y+x0)=0 && (x+y0)=0 && (-x+x0)=0 && (-y+y0)=0 && (-y+x0)=0 && (-x+y0)=0 && (x+x0)=0 && (-y+y0)=0 && (y+x0)=0 && (-x+y0)=0 && x=0 && yformat,&(pcol.r),&(pcol.g),&(pcol.b)); } SDL_FreeSurface(s); /* free helper 1 */ SDL_FreeSurface(ns); /* free helper 2 */ } return pcol; } int sameColour(RGBcolour c1,RGBcolour c2) /* colour comparison */ { /* true if both parameters are the same */ return ((c1.r==c2.r) && (c1.g==c2.g) && (c1.b==c2.b)); } void fill(SDL_Renderer *renderer,int wdth,int hght,int x,int y,RGBcolour src,RGBcolour dst) /* flood fill */ { /* SDL renderer, screen width, screen height, fill start x/y, flood area colour, drawing colour */ RGBcolour pcol; if(sameColour(src,dst)) return; /* terminate if source = destination */ pcol=getPixelColour(renderer,wdth,hght,x,y); if(!sameColour(src,pcol)) return; /* terminate if not source colour */ SDL_SetRenderDrawColor(renderer, dst.r, dst.g, dst.b, 255); /* set drawing colour */ /* draw point if coordinate is valid */ if(x>=0 && x=0 && y=min?(v<=max?v:max):min; } void box(SDL_Renderer *renderer,int w,int h,int x0,int y0,int x2,int y2,RGBcolour col) /* draw a box shape */ { /* draw a rectangle of 4 connected lines */ line(renderer,w,h,clamp(x0,0,w-1),clamp(y0,0,h-1),clamp(x2,0,w-1),clamp(y0,0,h-1),col); line(renderer,w,h,clamp(x2,0,w-1),clamp(y0,0,h-1),clamp(x2,0,w-1),clamp(y2,0,h-1),col); line(renderer,w,h,clamp(x2,0,w-1),clamp(y2,0,h-1),clamp(x0,0,w-1),clamp(y2,0,h-1),col); line(renderer,w,h,clamp(x0,0,w-1),clamp(y2,0,h-1),clamp(x0,0,w-1),clamp(y0,0,h-1),col); } void boxF(SDL_Renderer *renderer,int w,int h,int x0,int y0,int x2,int y2,RGBcolour col) /* draw a filled box shape */ { RGBcolour pcol; int x=x0+(x2-x0)/2,y=y0+(y2-y0)/2; /* calculate centre point of box */ pcol=getPixelColour(renderer,w,h,clamp(x,0,w-1),clamp(y,0,h-1)); /* get base colour */ box(renderer,w,h,x0,y0,x2,y2,col); /* draw box */ fill(renderer,w,h,x,y,pcol,col); /* fill box */ } /* functions below equivalent to the above but drawing on a surface/image rather than the renderer */ void Iline(SDL_Surface *img,int x0,int y0,int xn,int yn,RGBcolour col) { int dx = abs(xn-x0), sx = x0dy ? dx : -dy)/2, e2; Uint32 pixel = SDL_MapRGB(img->format,col.r,col.g,col.b); Uint32 *pixels = (Uint32*)img->pixels; while(1) { /* draw point only if coordinate is valid */ if(x0>=0 && x0w && y0>=0 && y0h) pixels[x0+y0*img->w]=pixel; if(x0==xn && y0==yn) break; e2 = error; if(e2 >-dx) { error -= dy; x0 += sx; } if(e2 < dy) { error += dx; y0 += sy; } } } void Icircle(SDL_Surface *img,int x0,int y0,int radius,RGBcolour col) { int x = radius, y=0, error = 1-radius; Uint32 pixel = SDL_MapRGB(img->format,col.r,col.g,col.b); Uint32 *pixels = (Uint32*)img->pixels; while(x>=y) { /* 1 draw call for each octant - ensure coordinates are valid before drawing */ if((x+x0)>=0 && (x+x0)w && (y+y0)>=0 && (y+y0)h) pixels[(x+x0)+(y+y0)*img->w]=pixel; /* draw point in octant 1 if coordinate is valid */ if((y+x0)>=0 && (y+x0)w && (x+y0)>=0 && (x+y0)h) pixels[(y+x0)+(x+y0)*img->w]=pixel; /* draw point in octant 2 if coordinate is valid */ if((-x+x0)>=0 && (-x+x0)w && (y+y0)>=0 && (y+y0)h) pixels[(-x+x0)+(y+y0)*img->w]=pixel; /* draw point in octant 3 if coordinate is valid */ if((-y+x0)>=0 && (-y+x0)w && (x+y0)>=0 && (x+y0)h) pixels[(-y+x0)+(x+y0)*img->w]=pixel; /* draw point in octant 4 if coordinate is valid */ if((-x+x0)>=0 && (-x+x0)w && (-y+y0)>=0 && (-y+y0)h) pixels[(-x+x0)+(-y+y0)*img->w]=pixel; /* draw point in octant 5 if coordinate is valid */ if((-y+x0)>=0 && (-y+x0)w && (-x+y0)>=0 && (-x+y0)h) pixels[(-y+x0)+(-x+y0)*img->w]=pixel; /* draw point in octant 6 if coordinate is valid */ if((x+x0)>=0 && (x+x0)w && (-y+y0)>=0 && (-y+y0)h) SDL_RenderDrawPoint(renderer,x+x0,-y+y0); /* draw point in octant 7 if coordinate is valid */ if((y+x0)>=0 && (y+x0)w && (-x+y0)>=0 && (-x+y0)h) pixels[(y+x0)+(-x+y0)*img->w]=pixel; /* draw point in octant 8 if coordinate is valid */ y++; /* increment y coordinate */ if(error<0) { error += 2*y+1; } else { x--; error += 2*(y-x)+1; } } } RGBcolour getIPixelColour(SDL_Surface *img,int x,int y) { RGBcolour pcol; Uint32 *pixels = (Uint32*)img->pixels; /* needs the surface to have a 32 bit pixel format */ /* should really test if the coordinates are valid */ SDL_GetRGB(pixels[x+y*img->w],img->format,&(pcol.r),&(pcol.g),&(pcol.b)); return pcol; } void Ifill(SDL_Surface *img,int x,int y,RGBcolour src,RGBcolour dst) { RGBcolour pcol; Uint32 pixel,*pixels = (Uint32*)img->pixels; if(sameColour(src,dst)) return; /* terminate if source = destination */ pcol=getIPixelColour(img,x,y); if(!sameColour(src,pcol)) return; /* terminate if not source colour */ pixel = SDL_MapRGB(img->format,col.r,col.g,col.b); /* draw point if coordinate is valid */ if(x>=0 && xw && y>=0 && yh) pixels[x+y*img->w]=pixel; /* recursively fill neighbouring points */ Ifill(img,x,y+1,src,dst); Ifill(img,x-1,y,src,dst); Ifill(img,x,y-1,src,dst); Ifill(img,x+1,y,src,dst); }