add distance field calculation for the Image draw absraction system

This commit is contained in:
Edouard Dupin 2012-09-06 02:50:38 +02:00
parent 80585116ed
commit bfba3999b5
2 changed files with 174 additions and 0 deletions

View File

@ -259,3 +259,98 @@ void draw::Image::Disc(Vector2D<float> pos, float radius, float angleStart, floa
}
void GenerateSDF( Grid &g )
{
// Pass 0
Vector2D<int32_t> tmpPos;
for (tmpPos.y=1 ; tmpPos.y<g.m_size.y-1 ; tmpPos.y++) {
for (tmpPos.x=1 ; tmpPos.x<g.m_size.x-1 ; tmpPos.x++) {
Vector2D<int32_t> p = g.Get(tmpPos);
g.Compare(p, tmpPos, -1, 0 );
g.Compare(p, tmpPos, 0, -1 );
g.Compare(p, tmpPos, -1, -1 );
g.Compare(p, tmpPos, 1, -1 );
g.Set(tmpPos, p);
}
for (tmpPos.x=g.m_size.x-2 ; tmpPos.x>0 ; tmpPos.x--) {
Vector2D<int32_t> p = g.Get(tmpPos);
g.Compare(p, tmpPos, 1, 0 );
g.Set(tmpPos, p );
}
}
// Pass 1
for (tmpPos.y=g.m_size.y-2 ; tmpPos.y>0 ; tmpPos.y--) {
for (tmpPos.x=g.m_size.x-2 ; tmpPos.x>0 ; tmpPos.x--) {
Vector2D<int32_t> p = g.Get(tmpPos);
g.Compare(p, tmpPos, 1, 0 );
g.Compare(p, tmpPos, 0, 1 );
g.Compare(p, tmpPos, -1, 1 );
g.Compare(p, tmpPos, 1, 1 );
g.Set(tmpPos, p);
}
for (tmpPos.x=1 ; tmpPos.x<g.m_size.x-1 ; tmpPos.x++) {
Vector2D<int32_t> p = g.Get(tmpPos);
g.Compare(p, tmpPos, -1, 0 );
g.Set(tmpPos, p);
}
}
}
// see : http://www.codersnotes.com/notes/signed-distance-fields
void draw::Image::DistanceField(void)
{
DistanceField(Vector2D<int32_t>(0,0), m_size);
}
void draw::Image::DistanceField(Vector2D<int32_t> pos, Vector2D<int32_t> size)
{
Grid grid1(size);
Grid grid2(size);
grid1.SetOutsideVal(50);
grid2.SetOutsideVal(50);
Vector2D<int32_t> tmpPos;
for(tmpPos.y=0 ; tmpPos.y<size.x ; tmpPos.y++ ) {
for(tmpPos.x=0 ; tmpPos.x<size.y ; tmpPos.x++ ) {
draw::Color tmpColor = Get(pos+tmpPos);
// Points inside get marked with a x/y of zero.
// Points outside get marked with an infinitely large distance.
if (tmpColor.a<=0x7F) {
grid1.SetInide(tmpPos);
grid2.SetOutside(tmpPos);
} else {
grid2.SetInide(tmpPos);
grid1.SetOutside(tmpPos);
}
}
}
// Generate the SDF:
GenerateSDF( grid1 );
GenerateSDF( grid2 );
for(tmpPos.y=0 ; tmpPos.y<size.x ; tmpPos.y++ ) {
for(tmpPos.x=0 ; tmpPos.x<size.y ; tmpPos.x++ ) {
Vector2D<int32_t> elem1 = grid1.Get(tmpPos);
Vector2D<int32_t> elem2 = grid2.Get(tmpPos);
// Calculate the actual distance from the x/y
float dist1 = sqrt( (double)elem1.QuadDist() );
float dist2 = sqrt( (double)elem2.QuadDist() );
float dist = dist1 - dist2;
/*
if (tmpPos.y < 32) {
if (tmpPos.x < 32) {
DRAW_DEBUG( "generate Distance : " << dist1 << "," << dist2 << " ==> " << (dist*3 + 128));
} else if (tmpPos.x == 32) {
DRAW_DEBUG( " ---" );
}
}
*/
draw::Color tmpColor = Get(pos+tmpPos);
// Clamp and scale it, just for display purposes.
tmpColor.a = etk_avg(0, (dist*3 + 128), 255);
Set(pos+tmpPos, tmpColor);
}
}
}

View File

@ -42,6 +42,79 @@
#include <agg/agg_color_rgba.h>
#include <agg/agg_pixfmt_rgba.h>
class Grid
{
public:
Vector2D<int32_t> m_size;
etk::Vector<Vector2D<int32_t> > m_data;
int32_t m_outsideVal;
Grid(Vector2D<int32_t> size)
{
m_size = size;
m_outsideVal = 20;
// basic element :
Vector2D<int32_t> tmpPoint(0,0);
// preallocate data with a basic bg elements :
m_data.ReSize(m_size.x*m_size.y, tmpPoint);
};
~Grid(void) { };
void SetOutsideVal(int32_t newVal)
{
m_outsideVal = newVal;
}
void SetInide(Vector2D<int32_t> pos)
{
if( pos.x>=0 && pos.x<m_size.x
&& pos.y>=0 && pos.y<m_size.y) {
m_data[pos.x+pos.y*m_size.x].x=0;
m_data[pos.x+pos.y*m_size.x].y=0;
}
};
void SetOutside(Vector2D<int32_t> pos)
{
if( pos.x>=0 && pos.x<m_size.x
&& pos.y>=0 && pos.y<m_size.y) {
m_data[pos.x+pos.y*m_size.x].x=m_outsideVal;
m_data[pos.x+pos.y*m_size.x].y=m_outsideVal;
}
};
Vector2D<int32_t> Get(Vector2D<int32_t> pos)
{
;
if( pos.x>0 && pos.x<m_size.x
&& pos.y>0 && pos.y<m_size.y) {
return m_data[pos.x+pos.y*m_size.x];
}
return Vector2D<int32_t>(0,0);
};
void Set(Vector2D<int32_t> pos, Vector2D<int32_t> val)
{
if( pos.x>0 && pos.x<m_size.x
&& pos.y>0 && pos.y<m_size.y) {
m_data[pos.x+pos.y*m_size.x] = val;
}
};
void Compare(Vector2D<int32_t> &p, Vector2D<int32_t> pos, int32_t offsetx, int32_t offsety )
{
pos.x += offsetx;
pos.y += offsety;
Vector2D<int32_t> other = Get(pos);
other.x += offsetx;
other.y += offsety;
if (other.QuadDist() < p.QuadDist()) {
p = other;
}
};
};
namespace draw
{
@ -162,6 +235,12 @@ namespace draw
void Rectangle(Vector2D<float> pos, Vector2D<float> size);
void Circle(Vector2D<float> pos, float radius, float angleStart=0, float angleStop=2*M_PI);
void Disc(Vector2D<float> pos, float radius, float angleStart=0, float angleStop=2*M_PI);
// generate the distant field from the alpha value of the Image
void DistanceField(void);
void DistanceField(Vector2D<int32_t> pos, Vector2D<int32_t> size);
private:
};
};