// Jean-Charles BADOCHE - 2010
// http://astro.estaca.free.fr
#ifndef __TRACER__
#define __TRACER__
// Dotted methods
#define FULL 0
#define DOTTED 2
#define DASHED 5
// Size of a point
#define POINT_SIZE 4
// Sets a pixel on x,y position on a color on the map:
// If the position is out of map, nothing is done
// Returns: void
void setPixel(int, int, Uint32, SDL_Surface*);
// Getter for a pixel color on x,y position on the map
// The r, g, b, a pointer are set to the red, green, blue and alpha value of the pixel
// If the position is out of map, nothing is done
// Returns: void
void getPixelColor(int, int, SDL_Surface*, Uint8*, Uint8*, Uint8*, Uint8*);
// Sets a pixel on x,y position on a color on the map:
// y is float, so antialising is done (pixel position x,y & x,y+1)
// If the position is out of map, nothing is done
// Returns: void
void setAAPixel_X_Y(int, float, Uint32, SDL_Surface*);
// Sets a pixel on x,y position on a color on the map:
// x is float, so antialising is done (pixel position x,y & x+1,y)
// If the position is out of map, nothing is done
// Returns: void
void setAAPixel_Y_X(float, int, Uint32, SDL_Surface*);
// Sets a point on x,y position on the map on a color, of the map
// If the position is out of map, nothing is done
// Returns: void
void setPoint(int, int, Uint32, SDL_Surface*);
// Switchs the values of the x and y integers
// Returns: void
void int_switch(int*, int*);
// Returns the fractionary part of the x float
// Returns: the frav value (float) [0,1]
float frac(float);
// Returns the missing part to 1 from the fract. part of the x float
// Returns: the invfrac value (float) [0,1]
float invfrac(float);
// Traces an antialiased line from x1,y1 to x2,y2 on the specified color, on the map, with the dotted method
// Returns: void
void line_trace(int, int, int, int, Uint32, SDL_Surface*, int);
// Traces an antialiased circle with the specified raduis R on the center x,y on the specified color, on the map, with the dotted method
// Returns: void
void circle_trace(int, int, int, Uint32, SDL_Surface*, int);
// Traces a line perpendicular to the (x1,y1);(x2;y2) line, on point (x0,y0), on the spedicifed color, on the map surface, with the dotted method
// If x0 or y0 is UNSET, then the perpendicular line is drawn from point 2
// Length of the line is d1 in 1 direction (than direction than (x1,y1)->(x2;y2), d2 in the 2nd direction (opposite direction).
// If the d1 is UNSET, then the line is drawn on the whole half plan surface
// Same thing for d2
// Returns: void
void perdendicular_trace(int, int, int, int, int, int, int, int, Uint32, SDL_Surface*, int);
// Traces a line parallele to the (x1,y1);(x2;y2) line, on point (x0,y0), on the spedicifed color, on the map surface, with the dotted method
// If x0 or y0 is UNSET, then the parallele line is drawn from point 2
// Length of the line is d1 in 1 direction (clockwise), d2 in the 2nd direction (anticlockwise).
// If the d1 is UNSET, then the line is drawn on the whole half plan surface
// Same thing for d2
// Returns: void
void parallele_trace(int, int, int, int, int, int, int, int, Uint32, SDL_Surface*, int);
// Getter for the distance between 2 points x1,y1 & x2,y2
// Returns the distance (float)
float getDistance(int, int, int, int);
#endif // __TRACER__
// Jean-Charles BADOCHE - 2010
// http://astro.estaca.free.fr
#ifndef __TRACERC__
#define __TRACERC__
#include "tracer.h"
// Sets a pixel on x,y position on a color on the map:
// If the position is out of map, nothing is done
// Returns: void
void setPixel(int x, int y, Uint32 color, SDL_Surface *map)
{
if(x>0 && y>0 && x<map->w && y<map->h)
*((Uint32*)(map->pixels) + x + y * map->w) = color;
}
// Getter for a pixel color on x,y position on the map
// The r, g, b, a pointer are set to the red, green, blue and alpha value of the pixel
// If the position is out of map, nothing is done
// Returns: void
void getPixelColor(int x, int y, SDL_Surface *map, Uint8 *r, Uint8 *g, Uint8 *b, Uint8 *a)
{
if(x>0 && y>0 && x<map->w && y<map->h)
SDL_GetRGBA(*((Uint32 *)map->pixels + x + y * map->w),map->format,r,g,b,a);
}
// Sets a pixel on x,y position on a color on the map:
// y is float, so antialising is done (pixel position x,y & x,y+1)
// If the position is out of map, nothing is done
// Returns: void
void setAAPixel_X_Y(int x, float y, Uint32 color, SDL_Surface *map)
{
Uint8 r1,g1,b1,a1,r2,g2,b2,a2,r,g,b,a;
Uint32 colorAA1,colorAA2;
SDL_GetRGBA(color,map->format,&r1,&g1,&b1,&a1);
// Getting the color of current (background) pixel
getPixelColor(x, (int)y, map, &r2,&g2,&b2,&a2);
// For the antialising 2 pixels are drawn, one one top (x,y+1), the other below (x,y)
// The color is a mix of:
// - the color of background
// - the color of the line
// The amount of each color (bg & line color), on the 2 pixels is 100% (e.g. 10% on one, 90% on the other)
r=(Uint8)(frac(y)*r1+invfrac(y)*r2);
g=(Uint8)(frac(y)*g1+invfrac(y)*g2);
b=(Uint8)(frac(y)*b1+invfrac(y)*b2);
a=(Uint8)(frac(y)*a1+invfrac(y)*a2);
colorAA1=SDL_MapRGBA(map->format,r,g,b,a); // Color for pixel one (x,y+1)
r=(Uint8)(frac(y)*r2+invfrac(y)*r1);
g=(Uint8)(frac(y)*g2+invfrac(y)*g1);
b=(Uint8)(frac(y)*b2+invfrac(y)*b1);
a=(Uint8)(frac(y)*a2+invfrac(y)*a1);
colorAA2=SDL_MapRGBA(map->format,r,g,b,a); // Color for the 2nd pixel (x,y)
// Blitting
setPixel(x, (int)y, colorAA2, map);
setPixel(x, (int)y+1, colorAA1, map);
}
// Sets a pixel on x,y position on a color on the map:
// x is float, so antialising is done (pixel position x,y & x+1,y)
// If the position is out of map, nothing is done
// Returns: void
void setAAPixel_Y_X(float x, int y, Uint32 color, SDL_Surface *map)
{
Uint8 r1,g1,b1,a1,r2,g2,b2,a2,r,g,b,a;
Uint32 colorAA1,colorAA2;
SDL_GetRGBA(color,map->format,&r1,&g1,&b1,&a1);
// Getting the color of current (background) pixel
getPixelColor((int)x, y, map, &r2,&g2,&b2,&a2);
// For the antialising 2 pixels are drawn, one one top (x+1,y), the other below (x,y)
// The color is a mix of:
// - the color of background
// - the color of the line
// The amount of each color (bg & line color), on the 2 pixels is 100% (e.g. 10% on one, 90% on the other)
r=(Uint8)(frac(x)*r1+invfrac(x)*r2);
g=(Uint8)(frac(x)*g1+invfrac(x)*g2);
b=(Uint8)(frac(x)*b1+invfrac(x)*b2);
a=(Uint8)(frac(x)*a1+invfrac(x)*a2);
colorAA1=SDL_MapRGBA(map->format,r,g,b,a); // Color for pixel one (x+1,y)
r=(Uint8)(frac(x)*r2+invfrac(x)*r1);
g=(Uint8)(frac(x)*g2+invfrac(x)*g1);
b=(Uint8)(frac(x)*b2+invfrac(x)*b1);
a=(Uint8)(frac(x)*a2+invfrac(x)*a1);
colorAA2=SDL_MapRGBA(map->format,r,g,b,a); // Color for pixel one (x,y)
setPixel((int)x, y, colorAA2, map);
setPixel((int)x+1, y, colorAA1, map);
}
// Sets a point on x,y position on the map on a color, of the map
// Point's size if 2*POINT_SIZE
// If the position is out of map, nothing is done
// Returns: void
void setPoint(int x, int y, Uint32 color, SDL_Surface *map)
{
int i,j;
for(i=-POINT_SIZE;i<=POINT_SIZE;i++)
for(j=-POINT_SIZE;j<=POINT_SIZE;j++)
setPixel(x+i, y+j, color, map);
}
// Switchs the values of the x and y integers
// Returns: void
void int_switch(int* x, int* y)
{
int t = *x;
*x = *y;
*y = t;
}
// Returns the fractionary part of the x float
// Returns: the frav value (float) [0,1]
float frac(float x)
{
return x - (int)x;
}
// Returns the missing part to 1 from the fract. part of the x float
// Returns: the invfrac value (float) [0,1]
float invfrac(float x)
{
return 1 - frac(x);
}
// Traces an antialiased line from x1,y1 to x2,y2 on the specified color, on the map, with the dotted method
// Returns: void
void line_trace(int x1, int y1, int x2, int y2, Uint32 color, SDL_Surface *map, int dotted)
{
int xd, yd, x, y, to_dot = 0;
float grad,xf,yf;
Uint8 r1,g1,b1,a1,r2,g2,b2,a2,r,g,b,a;
Uint32 colorAA1,colorAA2;
// Getting the r,g,b,a values of the specified color
SDL_GetRGBA(color,map->format,&r1,&g1,&b1,&a1);
xd = (x2-x1);
yd = (y2-y1);
if (abs(xd) > abs(yd)) // The line angle is smaller than 45°
{
if (x1 > x2) // Because of the FOR, going from the smallest to the greatest value
{
int_switch(&x1, &x2);
int_switch(&y1, &y2);
xd = (x2-x1);
yd = (y2-y1);
}
grad = (float)yd/(float)xd; // Line slope
yf = (float)y1+grad;
// Start and arrival points
setPixel(x1, y1, color, map);
setPixel(x2, y2, color, map);
for (x = x1+1; x <= x2; x++)
{
if((!dotted || (to_dot%dotted)) && x>0 && x<map->w && yf>0 && yf<map->h) // If not outside of the map surface
{
// Getting the color of current (background) pixel
getPixelColor(x, (int)yf, map, &r2,&g2,&b2,&a2);
// For the antialising 2 pixels are drawn, one one top (x,y+1), the other below (x,y)
// The color is a mix of:
// - the color of background
// - the color of the line
// The amount of each color (bg & line color), on the 2 pixels is 100% (e.g. 10% on one, 90% on the other)
r=(Uint8)(frac(yf)*r1+invfrac(yf)*r2);
g=(Uint8)(frac(yf)*g1+invfrac(yf)*g2);
b=(Uint8)(frac(yf)*b1+invfrac(yf)*b2);
a=(Uint8)(frac(yf)*a1+invfrac(yf)*a2);
colorAA1=SDL_MapRGBA(map->format,r,g,b,a); // Color for pixel one (x,y+1)
r=(Uint8)(frac(yf)*r2+invfrac(yf)*r1);
g=(Uint8)(frac(yf)*g2+invfrac(yf)*g1);
b=(Uint8)(frac(yf)*b2+invfrac(yf)*b1);
a=(Uint8)(frac(yf)*a2+invfrac(yf)*a1);
colorAA2=SDL_MapRGBA(map->format,r,g,b,a); // Color for the 2nd pixel (x,y)
// Blitting
setPixel(x, (int)yf, colorAA2, map);
setPixel(x, (int)yf+1, colorAA1, map);
}
to_dot++;
yf += grad; // Go to next point (x => x+1 / yf => yf + grad)
}
}
else // Same thing if the line angle is greater the 45°
{
if (y1 > y2)
{
int_switch(&x1, &x2);
int_switch(&y1, &y2);
xd = (x2-x1);
yd = (y2-y1);
}
grad = (float)xd/(float)yd;
xf = (float)x1+grad;
setPixel(x1, y1, color, map);
setPixel(x2, y2, color, map);
for (y = y1+1; y <= y2; y++)
{
if((!dotted || (to_dot%dotted)) && xf>0 && xf<map->w && y>0 && y<map->h)
{
getPixelColor((int)xf, y, map, &r2,&g2,&b2,&a2);
r=(Uint8)(frac(xf)*r1+invfrac(xf)*r2);
g=(Uint8)(frac(xf)*g1+invfrac(xf)*g2);
b=(Uint8)(frac(xf)*b1+invfrac(xf)*b2);
a=(Uint8)(frac(xf)*a1+invfrac(xf)*a2);
colorAA1=SDL_MapRGBA(map->format,r,g,b,a);
r=(Uint8)(frac(xf)*r2+invfrac(xf)*r1);
g=(Uint8)(frac(xf)*g2+invfrac(xf)*g1);
b=(Uint8)(frac(xf)*b2+invfrac(xf)*b1);
a=(Uint8)(frac(xf)*a2+invfrac(xf)*a1);
colorAA2=SDL_MapRGBA(map->format,r,g,b,a);
setPixel((int)xf, y, colorAA2, map);
setPixel((int)xf+1, y, colorAA1, map);
}
to_dot++;
xf += grad;
}
}
}
// Traces an antialiased circle with the specified raduis R on the center x,y on the specified color, on the map, with the dotted method
// Returns: void
void circle_trace(int x, int y, int R, Uint32 color, SDL_Surface *map, int dotted)
{
int raduis, to_dot;
float real_y;
float real_x;
Uint8 r1,g1,b1,a1,r2,g2,b2,a2,r,g,b,a;
Uint32 colorAA1,colorAA2;
SDL_GetRGBA(color,map->format,&r1,&g1,&b1,&a1);
R = abs(R); // To be sure that R>0 (or with the FOR, we'll get some problems!)
// NB: From -R*0.71 to R*0.71 because we only make 90° of the circle (from -45° to 45°)
// and the sin(45°) = 0.707 (=sqrt(2)/2)
// The same algorithme is used for the 4 quarters of the circle
// TOP FOR X
for(raduis=-(int)(R*0.71); raduis<=(int)(R*0.71); raduis++)
{
real_y = y+sqrt(R*R-raduis*raduis); // Go to next point
if((!dotted || (to_dot%dotted)) && x>0 && x<map->w && y>0 && y<map->h) // If not outside of the map surface
{
// For the antialising 2 pixels are drawn, one one top (x,y+1), the other below (x,y)
// The color is a mix of:
// - the color of background
// - the color of the line
// The amount of each color (bg & line color), on the 2 pixels is 100% (e.g. 10% on one, 90% on the other)
getPixelColor(x-raduis, (int)real_y, map, &r2,&g2,&b2,&a2);
r=(Uint8)(frac(real_y)*r1+invfrac(real_y)*r2);
g=(Uint8)(frac(real_y)*g1+invfrac(real_y)*g2);
b=(Uint8)(frac(real_y)*b1+invfrac(real_y)*b2);
a=(Uint8)(frac(real_y)*a1+invfrac(real_y)*a2);
colorAA1=SDL_MapRGBA(map->format,r,g,b,a);
r=(Uint8)(frac(real_y)*r2+invfrac(real_y)*r1);
g=(Uint8)(frac(real_y)*g2+invfrac(real_y)*g1);
b=(Uint8)(frac(real_y)*b2+invfrac(real_y)*b1);
a=(Uint8)(frac(real_y)*a2+invfrac(real_y)*a1);
colorAA2=SDL_MapRGBA(map->format,r,g,b,a);
setPixel(x-raduis, (int)real_y, colorAA2, map);
setPixel(x-raduis, (int)real_y+1, colorAA1, map);
}
to_dot++;
}
// BOTTOM FOR X
for(raduis=-(int)(R*0.71); raduis<=(int)(R*0.71); raduis++)
{
real_y = y-sqrt(R*R-raduis*raduis);
if((!dotted || (to_dot%dotted)) && x>0 && x<map->w && y>0 && y<map->h)
{
getPixelColor(x-raduis, (int)real_y, map, &r2,&g2,&b2,&a2);
r=(Uint8)(frac(real_y)*r1+invfrac(real_y)*r2);
g=(Uint8)(frac(real_y)*g1+invfrac(real_y)*g2);
b=(Uint8)(frac(real_y)*b1+invfrac(real_y)*b2);
a=(Uint8)(frac(real_y)*a1+invfrac(real_y)*a2);
colorAA1=SDL_MapRGBA(map->format,r,g,b,a);
r=(Uint8)(frac(real_y)*r2+invfrac(real_y)*r1);
g=(Uint8)(frac(real_y)*g2+invfrac(real_y)*g1);
b=(Uint8)(frac(real_y)*b2+invfrac(real_y)*b1);
a=(Uint8)(frac(real_y)*a2+invfrac(real_y)*a1);
colorAA2=SDL_MapRGBA(map->format,r,g,b,a);
setPixel(x-raduis, (int)real_y, colorAA2, map);
setPixel(x-raduis, (int)real_y+1, colorAA1, map);
}
to_dot++;
}
// TOP FOR Y
for(raduis=-(int)(R*0.71); raduis<=(int)(R*0.71); raduis++)
{
real_x = x+sqrt(R*R-raduis*raduis);
if((!dotted || (to_dot%dotted)) && x>0 && x<map->w && y>0 && y<map->h)
{
getPixelColor((int)real_x, y-raduis, map, &r2,&g2,&b2,&a2);
r=(Uint8)(frac(real_x)*r1+invfrac(real_x)*r2);
g=(Uint8)(frac(real_x)*g1+invfrac(real_x)*g2);
b=(Uint8)(frac(real_x)*b1+invfrac(real_x)*b2);
a=(Uint8)(frac(real_x)*a1+invfrac(real_x)*a2);
colorAA1=SDL_MapRGBA(map->format,r,g,b,a);
r=(Uint8)(frac(real_x)*r2+invfrac(real_x)*r1);
g=(Uint8)(frac(real_x)*g2+invfrac(real_x)*g1);
b=(Uint8)(frac(real_x)*b2+invfrac(real_x)*b1);
a=(Uint8)(frac(real_x)*a2+invfrac(real_x)*a1);
colorAA2=SDL_MapRGBA(map->format,r,g,b,a);
setPixel((int)real_x, (y-raduis), colorAA2, map);
setPixel((int)real_x+1, (y-raduis), colorAA1, map);
}
to_dot++;
}
// BOTTOM FOR Y
for(raduis=-(int)(R*0.71); raduis<=(int)(R*0.71); raduis++)
{
real_x = x-sqrt(R*R-raduis*raduis);
if((!dotted || (to_dot%dotted)) && x>0 && x<map->w && y>0 && y<map->h)
{
getPixelColor((int)real_x, y-raduis, map, &r2,&g2,&b2,&a2);
r=(Uint8)(frac(real_x)*r1+invfrac(real_x)*r2);
g=(Uint8)(frac(real_x)*g1+invfrac(real_x)*g2);
b=(Uint8)(frac(real_x)*b1+invfrac(real_x)*b2);
a=(Uint8)(frac(real_x)*a1+invfrac(real_x)*a2);
colorAA1=SDL_MapRGBA(map->format,r,g,b,a);
r=(Uint8)(frac(real_x)*r2+invfrac(real_x)*r1);
g=(Uint8)(frac(real_x)*g2+invfrac(real_x)*g1);
b=(Uint8)(frac(real_x)*b2+invfrac(real_x)*b1);
a=(Uint8)(frac(real_x)*a2+invfrac(real_x)*a1);
colorAA2=SDL_MapRGBA(map->format,r,g,b,a);
setPixel((int)real_x, (y-raduis), colorAA2, map);
setPixel((int)real_x+1, (y-raduis), colorAA1, map);
}
to_dot++;
}
}
// Traces a line perpendicular to the (x1,y1);(x2;y2) line, on point (x0,y0), on the spedicifed color, on the map surface, with the dotted method
// If x0 or y0 is UNSET, then the perpendicular line is drawn from point 2
// Length of the line is d1 in 1 direction (than direction than (x1,y1)->(x2;y2), d2 in the 2nd direction (opposite direction).
// If the d1 is UNSET, then the line is drawn on the whole half plan surface
// Same thing for d2
// Returns: void
void perdendicular_trace(int x1, int y1, int x2, int y2, int x0, int y0, int d1, int d2, Uint32 color, SDL_Surface *map, int dotted)
{
int x_1, y_1, x_2, y_2;
float distance1, distance2, d;
if(d1==UNSET && d2==UNSET)
{
d1 = getDistance(0, 0, map->w, map->h);
d2 = d1; // less calculation
}
else if(d1==UNSET)
d1 = getDistance(0, 0, map->w, map->h);
else if(d2==UNSET)
d2 = getDistance(0, 0, map->w, map->h);
d = getDistance(x1, y1, x2, y2);
distance1 = (float)d1/d;
distance2 = (float)d2/d;
if(x0==UNSET||y0==UNSET)
{
x0 = x2;
y0 = y2;
}
x_1 = x0 - distance1*(y2 - y1);
y_1 = y0 + distance1*(x2 - x1);
x_2 = x0 + distance2*(y2 - y1);
y_2 = y0 - distance2*(x2 - x1);
line_trace(x_1, y_1, x_2, y_2, color, map, dotted);
}
// Traces a line parallele to the (x1,y1);(x2;y2) line, on point (x0,y0), on the spedicifed color, on the map surface, with the dotted method
// If x0 or y0 is UNSET, then the parallele line is drawn from point 2
// Length of the line is d1 in 1 direction (clockwise), d2 in the 2nd direction (anticlockwise).
// If the d1 is UNSET, then the line is drawn on the whole half plan surface
// Same thing for d2
// Returns: void
void parallele_trace(int x1, int y1, int x2, int y2, int x0, int y0, int d1, int d2, Uint32 color, SDL_Surface *map, int dotted)
{
int x_1, y_1, x_2, y_2;
float distance1, distance2, d;
if(d1==UNSET && d2==UNSET)
{
d1 = getDistance(0, 0, map->w, map->h);
d2 = d1; // less calculation
}
else if(d1==UNSET)
d1 = getDistance(0, 0, map->w, map->h);
else if(d2==UNSET)
d2 = getDistance(0, 0, map->w, map->h);
d = getDistance(x1, y1, x2, y2);
distance1 = (float)d1/d;
distance2 = (float)d2/d;
if(x0==UNSET||y0==UNSET)
{
x0 = x2;
y0 = y2;
}
x_1 = x0 - distance1*(x2 - x1);
y_1 = y0 - distance1*(y2 - y1);
x_2 = x0 + distance2*(x2 - x1);
y_2 = y0 + distance2*(y2 - y1);
line_trace(x_1, y_1, x_2, y_2, color, map, dotted);
}
// Getter for the distance between 2 points x1,y1 & x2,y2
// Returns the distance (float)
float getDistance(int x1, int y1, int x2, int y2)
{
return sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2));
}
#endif // __TRACERC__
Voilà, j'espère que cela vous aura aidé à comprendre la principe de l'anti-aliasing!