[DEV] better distance field display

This commit is contained in:
Edouard DUPIN 2014-01-08 22:15:01 +01:00
parent d144c0a65f
commit fbca6c4491
5 changed files with 508 additions and 656 deletions

View File

@ -12,37 +12,44 @@ uniform int EW_SoftEdge;
varying vec2 f_texcoord;
varying vec4 f_color;
void main(void) {
vec4 tmpcolor = texture2D(EW_texID, f_texcoord);
vec4 outColor = vec4(0,0,0,0);
// compare distance with 0.5 that represent the middle ...
/*
if (tmpcolor[0]>0.5) {
outColor = f_color;
outColor[3] = 1.0;
} else if (tmpcolor[0]>0.49) {
// antialiasing :
outColor = f_color;
outColor[3] = 0.0;//(tmpcolor[3]-0.49)*1.0/0.02;
}
*/
outColor = f_color;
outColor[3] = smoothstep(0.35, 0.65, tmpcolor[0]);
/*
outColor = f_color;// * tmpcolor[3];
if (1==EW_SoftEdge) {
outColor[3] = smoothstep(EW_SoftEdgeMin, EW_SoftEdgeMax, tmpcolor[3]);
} else {
if (tmpcolor[3]>0.5) {
outColor[3] = 1.0;
} else {
outColor[3] = 0.0;
}
}
*/
//outColor = vec4(0,0,0,0);
//outColor[3] = tmpcolor[3];
gl_FragColor = outColor;
//gl_FragColor = tmpcolor;
}
vec3 glyph_color = vec3(1.0,1.0,1.0);
const float glyph_center = 0.50;
vec3 outline_color = vec3(0.0,0.0,0.0);
const float outline_center = 0.55;
vec3 glow_color = vec3(1.0,1.0,1.0);
const float glow_center = 1.25;
void main(void) {
//vec4 color = texture2D(EW_texID, vec2(int(f_texcoord[0]*256.0)/256.0,int(f_texcoord[1]*256.0)/256.0) );
vec4 color = texture2D(EW_texID, f_texcoord );
float dist = color.r;
float width = fwidth(dist);
float alpha = smoothstep(glyph_center-width, glyph_center+width, dist);
// Smooth
gl_FragColor = vec4(glyph_color, alpha);
// Outline
/*
float mu = smoothstep(outline_center-width, outline_center+width, dist);
vec3 rgb = mix(outline_color, glyph_color, mu);
gl_FragColor = vec4(rgb, max(alpha,mu));
*/
// Glow
/*
vec3 rgb = mix(glow_color, glyph_color, alpha);
float mu = smoothstep(glyph_center, glow_center, sqrt(dist));
gl_FragColor = vec4(rgb, max(alpha,mu));
*/
// Glow + outline
/*
vec3 rgb = mix(glow_color, glyph_color, alpha);
float mu = smoothstep(glyph_center, glow_center, sqrt(dist));
color = vec4(rgb, max(alpha,mu));
float beta = smoothstep(outline_center-width, outline_center+width, dist);
rgb = mix(outline_color, color.rgb, beta);
gl_FragColor = vec4(rgb, max(color.a,beta));
*/
}

View File

@ -21,6 +21,7 @@ void main(void) {
f_color = EW_color;
}
/*
// Distance map contour texturing according to Green (2007),
// implementation by Stefan Gustavson 2009.

View File

@ -5,12 +5,12 @@
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY STEFAN GUSTAVSON ''AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
@ -65,27 +65,27 @@
*/
void computegradient(double *img, int w, int h, double *gx, double *gy)
{
int i,j,k;
double glength;
int i,j,k;
double glength;
#define SQRT2 1.4142136
for(i = 1; i < h-1; i++) { // Avoid edges where the kernels would spill over
for(j = 1; j < w-1; j++) {
k = i*w + j;
if((img[k]>0.0) && (img[k]<1.0)) { // Compute gradient for edge pixels only
gx[k] = -img[k-w-1] - SQRT2*img[k-1] - img[k+w-1] + img[k-w+1] + SQRT2*img[k+1] + img[k+w+1];
gy[k] = -img[k-w-1] - SQRT2*img[k-w] - img[k+w-1] + img[k-w+1] + SQRT2*img[k+w] + img[k+w+1];
glength = gx[k]*gx[k] + gy[k]*gy[k];
if(glength > 0.0) { // Avoid division by zero
glength = sqrt(glength);
gx[k]=gx[k]/glength;
gy[k]=gy[k]/glength;
}
}
}
}
// TODO: Compute reasonable values for gx, gy also around the image edges.
// (These are zero now, which reduces the accuracy for a 1-pixel wide region
// around the image edge.) 2x2 kernels would be suitable for this.
for(i = 1; i < h-1; i++) { // Avoid edges where the kernels would spill over
for(j = 1; j < w-1; j++) {
k = i*w + j;
if((img[k]>0.0) && (img[k]<1.0)) { // Compute gradient for edge pixels only
gx[k] = -img[k-w-1] - SQRT2*img[k-1] - img[k+w-1] + img[k-w+1] + SQRT2*img[k+1] + img[k+w+1];
gy[k] = -img[k-w-1] - SQRT2*img[k-w] - img[k+w-1] + img[k-w+1] + SQRT2*img[k+w] + img[k+w+1];
glength = gx[k]*gx[k] + gy[k]*gy[k];
if(glength > 0.0) { // Avoid division by zero
glength = sqrt(glength);
gx[k]=gx[k]/glength;
gy[k]=gy[k]/glength;
}
}
}
}
// TODO: Compute reasonable values for gx, gy also around the image edges.
// (These are zero now, which reduces the accuracy for a 1-pixel wide region
// around the image edge.) 2x2 kernels would be suitable for this.
}
/*
@ -97,66 +97,69 @@ void computegradient(double *img, int w, int h, double *gx, double *gy)
* accuracy at and near edges, and reduces the error even at distant pixels
* provided that the gradient direction is accurately estimated.
*/
double edgedf(double gx, double gy, double a)
{
double df, glength, temp, a1;
if ((gx == 0) || (gy == 0)) { // Either A) gu or gv are zero, or B) both
df = 0.5-a; // Linear approximation is A) correct or B) a fair guess
} else {
glength = sqrt(gx*gx + gy*gy);
if(glength>0) {
gx = gx/glength;
gy = gy/glength;
}
/* Everything is symmetric wrt sign and transposition,
* so move to first octant (gx>=0, gy>=0, gx>=gy) to
* avoid handling all possible edge directions.
*/
gx = fabs(gx);
gy = fabs(gy);
if(gx<gy) {
temp = gx;
gx = gy;
gy = temp;
}
a1 = 0.5*gy/gx;
if (a < a1) { // 0 <= a < a1
df = 0.5*(gx + gy) - sqrt(2.0*gx*gy*a);
} else if (a < (1.0-a1)) { // a1 <= a <= 1-a1
df = (0.5-a)*gx;
} else { // 1-a1 < a <= 1
df = -0.5*(gx + gy) + sqrt(2.0*gx*gy*(1.0-a));
}
}
return df;
double edgedf(double gx, double gy, double a) {
double df, glength, temp, a1;
if ((gx == 0) || (gy == 0)) { // Either A) gu or gv are zero, or B) both
df = 0.5-a; // Linear approximation is A) correct or B) a fair guess
} else {
glength = sqrt(gx*gx + gy*gy);
if(glength>0) {
gx = gx/glength;
gy = gy/glength;
}
/* Everything is symmetric wrt sign and transposition,
* so move to first octant (gx>=0, gy>=0, gx>=gy) to
* avoid handling all possible edge directions.
*/
gx = fabs(gx);
gy = fabs(gy);
if(gx<gy) {
temp = gx;
gx = gy;
gy = temp;
}
a1 = 0.5*gy/gx;
if (a < a1) { // 0 <= a < a1
df = 0.5*(gx + gy) - sqrt(2.0*gx*gy*a);
} else if (a < (1.0-a1)) { // a1 <= a <= 1-a1
df = (0.5-a)*gx;
} else { // 1-a1 < a <= 1
df = -0.5*(gx + gy) + sqrt(2.0*gx*gy*(1.0-a));
}
}
return df;
}
double distaa3(double *img, double *gximg, double *gyimg, int w, int c, int xc, int yc, int xi, int yi)
{
double di, df, dx, dy, gx, gy, a;
int closest;
double distaa3(double *img, double *gximg, double *gyimg, int w, int c, int xc, int yc, int xi, int yi) {
double di, df, dx, dy, gx, gy, a;
int closest;
closest = c-xc-yc*w; // Index to the edge pixel pointed to from c
a = img[closest]; // Grayscale value at the edge pixel
gx = gximg[closest]; // X gradient component at the edge pixel
gy = gyimg[closest]; // Y gradient component at the edge pixel
closest = c-xc-yc*w; // Index to the edge pixel pointed to from c
a = img[closest]; // Grayscale value at the edge pixel
gx = gximg[closest]; // X gradient component at the edge pixel
gy = gyimg[closest]; // Y gradient component at the edge pixel
if(a > 1.0) a = 1.0;
if(a < 0.0) a = 0.0; // Clip grayscale values outside the range [0,1]
if(a == 0.0) return 1000000.0; // Not an object pixel, return "very far" ("don't know yet")
if(a > 1.0) {
a = 1.0;
}
if(a < 0.0) {
a = 0.0; // Clip grayscale values outside the range [0,1]
}
if(a == 0.0) {
return 1000000.0; // Not an object pixel, return "very far" ("don't know yet")
}
dx = (double)xi;
dy = (double)yi;
di = sqrt(dx*dx + dy*dy); // Length of integer vector, like a traditional EDT
if(di==0) { // Use local gradient only at edges
// Estimate based on local gradient only
df = edgedf(gx, gy, a);
} else {
// Estimate gradient based on direction to edge (accurate for large di)
df = edgedf(dx, dy, a);
}
return di + df; // Same metric as edtaa2, except at edges (where di=0)
dx = (double)xi;
dy = (double)yi;
di = sqrt(dx*dx + dy*dy); // Length of integer vector, like a traditional EDT
if(di==0) { // Use local gradient only at edges
// Estimate based on local gradient only
df = edgedf(gx, gy, a);
} else {
// Estimate gradient based on direction to edge (accurate for large di)
df = edgedf(dx, dy, a);
}
return di + df; // Same metric as edtaa2, except at edges (where di=0)
}
// Shorthand macro: add ubiquitous parameters dist, gx, gy, img and w and call distaa3()
@ -164,414 +167,358 @@ double distaa3(double *img, double *gximg, double *gyimg, int w, int c, int xc,
void edtaa3(double *img, double *gx, double *gy, int w, int h, short *distx, short *disty, double *dist)
{
int x, y, i, c;
int offset_u, offset_ur, offset_r, offset_rd,
offset_d, offset_dl, offset_l, offset_lu;
double olddist, newdist;
int cdistx, cdisty, newdistx, newdisty;
int changed;
double epsilon = 1e-3;
int x, y, i, c;
int offset_u, offset_ur, offset_r, offset_rd,
offset_d, offset_dl, offset_l, offset_lu;
double olddist, newdist;
int cdistx, cdisty, newdistx, newdisty;
int changed;
double epsilon = 1e-3;
/* Initialize index offsets for the current image width */
offset_u = -w;
offset_ur = -w+1;
offset_r = 1;
offset_rd = w+1;
offset_d = w;
offset_dl = w-1;
offset_l = -1;
offset_lu = -w-1;
/* Initialize index offsets for the current image width */
offset_u = -w;
offset_ur = -w+1;
offset_r = 1;
offset_rd = w+1;
offset_d = w;
offset_dl = w-1;
offset_l = -1;
offset_lu = -w-1;
/* Initialize the distance images */
for(i=0; i<w*h; i++) {
distx[i] = 0; // At first, all pixels point to
disty[i] = 0; // themselves as the closest known.
if(img[i] <= 0.0)
{
dist[i]= 1000000.0; // Big value, means "not set yet"
}
else if (img[i]<1.0) {
dist[i] = edgedf(gx[i], gy[i], img[i]); // Gradient-assisted estimate
}
else {
dist[i]= 0.0; // Inside the object
}
}
/* Initialize the distance images */
for(i=0; i<w*h; i++) {
distx[i] = 0; // At first, all pixels point to
disty[i] = 0; // themselves as the closest known.
if(img[i] <= 0.0){
dist[i]= 1000000.0; // Big value, means "not set yet"
} else if (img[i]<1.0) {
dist[i] = edgedf(gx[i], gy[i], img[i]); // Gradient-assisted estimate
} else {
dist[i]= 0.0; // Inside the object
}
}
/* Perform the transformation */
do
{
changed = 0;
/* Perform the transformation */
do {
changed = 0;
/* Scan rows, except first row */
for(y=1; y<h; y++)
{
/* move index to leftmost pixel of current row */
i = y*w;
/* scan right, propagate distances from above & left */
/* Leftmost pixel is special, has no left neighbors */
olddist = dist[i];
if(olddist > 0) // If non-zero distance or not set yet
{
c = i + offset_u; // Index of candidate for testing
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx;
newdisty = cdisty+1;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon)
{
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
olddist=newdist;
changed = 1;
}
c = i+offset_ur;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx-1;
newdisty = cdisty+1;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon)
{
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
changed = 1;
}
}
i++;
/* Middle pixels have all neighbors */
for(x=1; x<w-1; x++, i++)
{
olddist = dist[i];
if(olddist <= 0) continue; // No need to update further
c = i+offset_l;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx+1;
newdisty = cdisty;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon)
{
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
olddist=newdist;
changed = 1;
}
c = i+offset_lu;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx+1;
newdisty = cdisty+1;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon)
{
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
olddist=newdist;
changed = 1;
}
c = i+offset_u;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx;
newdisty = cdisty+1;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon)
{
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
olddist=newdist;
changed = 1;
}
c = i+offset_ur;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx-1;
newdisty = cdisty+1;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon)
{
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
changed = 1;
}
}
/* Rightmost pixel of row is special, has no right neighbors */
olddist = dist[i];
if(olddist > 0) // If not already zero distance
{
c = i+offset_l;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx+1;
newdisty = cdisty;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon)
{
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
olddist=newdist;
changed = 1;
}
c = i+offset_lu;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx+1;
newdisty = cdisty+1;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon)
{
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
olddist=newdist;
changed = 1;
}
c = i+offset_u;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx;
newdisty = cdisty+1;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon)
{
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
changed = 1;
}
}
/* Move index to second rightmost pixel of current row. */
/* Rightmost pixel is skipped, it has no right neighbor. */
i = y*w + w-2;
/* scan left, propagate distance from right */
for(x=w-2; x>=0; x--, i--)
{
olddist = dist[i];
if(olddist <= 0) continue; // Already zero distance
c = i+offset_r;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx-1;
newdisty = cdisty;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon)
{
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
changed = 1;
}
}
}
/* Scan rows in reverse order, except last row */
for(y=h-2; y>=0; y--)
{
/* move index to rightmost pixel of current row */
i = y*w + w-1;
/* Scan left, propagate distances from below & right */
/* Rightmost pixel is special, has no right neighbors */
olddist = dist[i];
if(olddist > 0) // If not already zero distance
{
c = i+offset_d;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx;
newdisty = cdisty-1;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon)
{
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
olddist=newdist;
changed = 1;
}
c = i+offset_dl;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx+1;
newdisty = cdisty-1;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon)
{
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
changed = 1;
}
}
i--;
/* Middle pixels have all neighbors */
for(x=w-2; x>0; x--, i--)
{
olddist = dist[i];
if(olddist <= 0) continue; // Already zero distance
c = i+offset_r;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx-1;
newdisty = cdisty;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon)
{
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
olddist=newdist;
changed = 1;
}
c = i+offset_rd;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx-1;
newdisty = cdisty-1;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon)
{
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
olddist=newdist;
changed = 1;
}
c = i+offset_d;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx;
newdisty = cdisty-1;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon)
{
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
olddist=newdist;
changed = 1;
}
c = i+offset_dl;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx+1;
newdisty = cdisty-1;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon)
{
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
changed = 1;
}
}
/* Leftmost pixel is special, has no left neighbors */
olddist = dist[i];
if(olddist > 0) // If not already zero distance
{
c = i+offset_r;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx-1;
newdisty = cdisty;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon)
{
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
olddist=newdist;
changed = 1;
}
c = i+offset_rd;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx-1;
newdisty = cdisty-1;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon)
{
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
olddist=newdist;
changed = 1;
}
c = i+offset_d;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx;
newdisty = cdisty-1;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon)
{
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
changed = 1;
}
}
/* Move index to second leftmost pixel of current row. */
/* Leftmost pixel is skipped, it has no left neighbor. */
i = y*w + 1;
for(x=1; x<w; x++, i++)
{
/* scan right, propagate distance from left */
olddist = dist[i];
if(olddist <= 0) continue; // Already zero distance
c = i+offset_l;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx+1;
newdisty = cdisty;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon)
{
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
changed = 1;
}
}
}
}
while(changed); // Sweep until no more updates are made
/* The transformation is completed. */
/* Scan rows, except first row */
for(y=1; y<h; y++) {
/* move index to leftmost pixel of current row */
i = y*w;
/* scan right, propagate distances from above & left */
/* Leftmost pixel is special, has no left neighbors */
olddist = dist[i];
if(olddist > 0) { // If non-zero distance or not set yet
c = i + offset_u; // Index of candidate for testing
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx;
newdisty = cdisty+1;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon) {
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
olddist=newdist;
changed = 1;
}
c = i+offset_ur;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx-1;
newdisty = cdisty+1;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon) {
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
changed = 1;
}
}
i++;
/* Middle pixels have all neighbors */
for(x=1; x<w-1; x++, i++) {
olddist = dist[i];
if(olddist <= 0) {
continue; // No need to update further
}
c = i+offset_l;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx+1;
newdisty = cdisty;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon) {
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
olddist=newdist;
changed = 1;
}
c = i+offset_lu;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx+1;
newdisty = cdisty+1;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon) {
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
olddist=newdist;
changed = 1;
}
c = i+offset_u;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx;
newdisty = cdisty+1;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon) {
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
olddist=newdist;
changed = 1;
}
c = i+offset_ur;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx-1;
newdisty = cdisty+1;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon) {
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
changed = 1;
}
}
/* Rightmost pixel of row is special, has no right neighbors */
olddist = dist[i];
if(olddist > 0) {// If not already zero distance
c = i+offset_l;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx+1;
newdisty = cdisty;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon) {
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
olddist=newdist;
changed = 1;
}
c = i+offset_lu;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx+1;
newdisty = cdisty+1;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon) {
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
olddist=newdist;
changed = 1;
}
c = i+offset_u;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx;
newdisty = cdisty+1;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon) {
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
changed = 1;
}
}
/* Move index to second rightmost pixel of current row. */
/* Rightmost pixel is skipped, it has no right neighbor. */
i = y*w + w-2;
/* scan left, propagate distance from right */
for(x=w-2; x>=0; x--, i--) {
olddist = dist[i];
if(olddist <= 0) {
continue; // Already zero distance
}
c = i+offset_r;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx-1;
newdisty = cdisty;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon) {
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
changed = 1;
}
}
}
/* Scan rows in reverse order, except last row */
for(y=h-2; y>=0; y--) {
/* move index to rightmost pixel of current row */
i = y*w + w-1;
/* Scan left, propagate distances from below & right */
/* Rightmost pixel is special, has no right neighbors */
olddist = dist[i];
if(olddist > 0) { // If not already zero distance
c = i+offset_d;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx;
newdisty = cdisty-1;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon) {
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
olddist=newdist;
changed = 1;
}
c = i+offset_dl;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx+1;
newdisty = cdisty-1;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon) {
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
changed = 1;
}
}
i--;
/* Middle pixels have all neighbors */
for(x=w-2; x>0; x--, i--) {
olddist = dist[i];
if(olddist <= 0) {
continue; // Already zero distance
}
c = i+offset_r;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx-1;
newdisty = cdisty;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon) {
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
olddist=newdist;
changed = 1;
}
c = i+offset_rd;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx-1;
newdisty = cdisty-1;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon) {
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
olddist=newdist;
changed = 1;
}
c = i+offset_d;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx;
newdisty = cdisty-1;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon) {
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
olddist=newdist;
changed = 1;
}
c = i+offset_dl;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx+1;
newdisty = cdisty-1;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon) {
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
changed = 1;
}
}
/* Leftmost pixel is special, has no left neighbors */
olddist = dist[i];
if(olddist > 0) { // If not already zero distance
c = i+offset_r;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx-1;
newdisty = cdisty;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon) {
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
olddist=newdist;
changed = 1;
}
c = i+offset_rd;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx-1;
newdisty = cdisty-1;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon) {
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
olddist=newdist;
changed = 1;
}
c = i+offset_d;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx;
newdisty = cdisty-1;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon) {
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
changed = 1;
}
}
/* Move index to second leftmost pixel of current row. */
/* Leftmost pixel is skipped, it has no left neighbor. */
i = y*w + 1;
for(x=1; x<w; x++, i++) {
/* scan right, propagate distance from left */
olddist = dist[i];
if(olddist <= 0) {
continue; // Already zero distance
}
c = i+offset_l;
cdistx = distx[c];
cdisty = disty[c];
newdistx = cdistx+1;
newdisty = cdisty;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon) {
distx[i]=newdistx;
disty[i]=newdisty;
dist[i]=newdist;
changed = 1;
}
}
}
} while(changed); // Sweep until no more updates are made
/* The transformation is completed. */
}

2
external/etk vendored

@ -1 +1 @@
Subproject commit a61639ef292b617a86a07fe30770d8533c17159b
Subproject commit b0e3b31664cab066ea3f5e9c42ba6729f40e95e1

View File

@ -17,6 +17,7 @@
#include <ewol/resource/FontFreeType.h>
#include <ewol/context/Context.h>
#include <ewol/resource/DistanceFieldFont.h>
#include <edtaa3/edtaa3func.h>
#undef __class__
#define __class__ "resource::DistanceFieldFont"
@ -27,7 +28,7 @@ ewol::resource::DistanceFieldFont::DistanceFieldFont(const std::string& _fontNam
m_font = NULL;
m_lastGlyphPos.setValue(1,1);
m_lastRawHeigh = 0;
m_size = 36;
m_size = 70;
std::string localName = _fontName;
std::vector<std::string> folderList;
if (true == ewol::getContext().getFontDefault().getUseExternal()) {
@ -112,45 +113,41 @@ ewol::resource::DistanceFieldFont::~DistanceFieldFont(void) {
ewol::resource::FontFreeType::release(m_font);
}
void ewol::resource::DistanceFieldFont::GenerateSoftDistanceField(const egami::ImageMono& _input, egami::Image& _output) {
unsigned char *img = &_input[0];
unsigned int width = _input.getSize().x();
unsigned int height = _input.getSize().y();
std::vector<short> xdist;
std::vector<short> ydist;
std::vector<double> gx;
std::vector<double> gy;
std::vector<double> data;
std::vector<double> outside;
std::vector<double> inside;
xdist.resize(width*height, 0);
ydist.resize(width*height, 0);
gx.resize(width*height, 0.0);
gy.resize(width*height, 0.0);
data.resize(width*height, 0.0);
outside.resize(width*height, 0.0);
inside.resize(width*height, 0.0);
void ewol::resource::DistanceFieldFont::GenerateDistanceField(const egami::ImageMono& _input, egami::Image& _output) {
int32_t size = _input.getSize().x() * _input.getSize().y();
std::vector<short> xdist(size);
std::vector<short> ydist(size);
std::vector<double> gx(size);
std::vector<double> gy(size);
std::vector<double> data(size);
std::vector<double> outside(size);
std::vector<double> inside(size);
// Convert img into double (data)
double img_min = 255, img_max = -255;
for(size_t iii = 0; iii < data.size(); ++iii) {
double v = img[iii];
data[iii] = v;
if (v > img_max) {
img_max = v;
}
if (v < img_min) {
img_min = v;
for (int32_t yyy = 0; yyy < _input.getSize().y(); ++yyy) {
for (int32_t xxx = 0; xxx < _input.getSize().x(); ++xxx) {
int32_t iii = yyy * _input.getSize().x() + xxx;
double v = _input.get(ivec2(xxx, yyy));
data[iii] = v;
if (v > img_max) {
img_max = v;
}
if (v < img_min) {
img_min = v;
}
}
}
// Rescale image levels between 0 and 1
for(size_t iii = 0; iii < data.size(); ++iii) {
data[iii] = (img[iii]-img_min)/img_max;
for (int32_t yyy = 0; yyy < _input.getSize().y(); ++yyy) {
for (int32_t xxx = 0; xxx < _input.getSize().x(); ++xxx) {
int32_t iii = yyy * _input.getSize().x() + xxx;
data[iii] = (_input.get(ivec2(xxx, yyy))-img_min)/img_max;
}
}
// Compute outside = edtaa3(bitmap); % Transform background (0's)
computegradient(&data[0], _input.getSize().x(), _input.getSize().y(), &gx[0], &gy[0]);
edtaa3(&data[0], &gx[0], &gy[0], _input.getSize().y(), _input.getSize().x(), &xdist[0], &ydist[0], &outside[0]);
edtaa3(&data[0], &gx[0], &gy[0], _input.getSize().x(), _input.getSize().y(), &xdist[0], &ydist[0], &outside[0]);
for(size_t iii = 0; iii < outside.size(); ++iii) {
if( outside[iii] < 0 ) {
outside[iii] = 0.0;
@ -168,7 +165,7 @@ void ewol::resource::DistanceFieldFont::GenerateSoftDistanceField(const egami::I
data[iii] = 1 - data[iii];
}
computegradient( &data[0], _input.getSize().x(), _input.getSize().y(), &gx[0], &gy[0]);
edtaa3(&data[0], &gx[0], &gy[0], _input.getSize().y(), _input.getSize().x(), &xdist[0], &ydist[0], &inside[0]);
edtaa3(&data[0], &gx[0], &gy[0], _input.getSize().x(), _input.getSize().y(), &xdist[0], &ydist[0], &inside[0]);
for(size_t iii = 0; iii < inside.size(); ++iii) {
if( inside[iii] < 0 ) {
inside[iii] = 0.0;
@ -195,106 +192,6 @@ void ewol::resource::DistanceFieldFont::GenerateSoftDistanceField(const egami::I
}
}
class GirdDF {
private:
std::vector<ivec2> m_data;
ivec2 m_size;
ivec2 m_error;
public:
GirdDF(const ivec2& _size, const ivec2& _base = ivec2(0,0), const ivec2& _error = ivec2(0,0)) {
m_size = _size;
m_data.resize(m_size.x()*m_size.y(), _base);
m_error = _error;
}
const ivec2& get(const ivec2& _pos) const {
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 m_error;
}
void set(const ivec2& _pos, const ivec2& _data) {
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()] = _data;
}
}
void compare(ivec2& _data, ivec2 _pos, ivec2 _offset) {
ivec2 other = get(_pos + _offset) + _offset;
if (other.length2() < _data.length2()) {
_data = other;
}
}
void GenerateSoftDistanceField(void) {
// First pass :
for (int32_t yyy = 0; yyy < m_size.y(); ++yyy) {
for (int32_t xxx = 0; xxx < m_size.x(); ++xxx) {
ivec2 data = get(ivec2(xxx, yyy));
compare(data, ivec2(xxx, yyy), ivec2(-1, 0));
compare(data, ivec2(xxx, yyy), ivec2( 0, -1));
compare(data, ivec2(xxx, yyy), ivec2(-1, -1));
compare(data, ivec2(xxx, yyy), ivec2( 1, -1));
set(ivec2(xxx, yyy), data);
}
for (int32_t xxx = m_size.y()-1; xxx >= 0;--xxx) {
ivec2 data = get(ivec2(xxx, yyy));
compare(data, ivec2(xxx, yyy), ivec2(1, 0));
set(ivec2(xxx, yyy), data );
}
}
// Second pass
for (int32_t yyy = m_size.y()-1; yyy >= 0; --yyy) {
for (int32_t xxx = m_size.x()-1; xxx >= 0; --xxx) {
ivec2 data = get(ivec2(xxx, yyy));
compare(data, ivec2(xxx, yyy), ivec2( 1, 0));
compare(data, ivec2(xxx, yyy), ivec2( 0, 1));
compare(data, ivec2(xxx, yyy), ivec2(-1, 1));
compare(data, ivec2(xxx, yyy), ivec2( 1, 1));
set(ivec2(xxx, yyy), data );
}
for (int32_t xxx = 0; xxx < m_size.x(); ++xxx) {
ivec2 data = get(ivec2(xxx, yyy));
compare(data, ivec2(xxx, yyy), ivec2(-1, 0));
set(ivec2(xxx, yyy), data);
}
}
}
};
void ewol::resource::DistanceFieldFont::GenerateDistanceField(const egami::ImageMono& _input, egami::Image& _output) {
GirdDF myGird1(_input.getSize(), ivec2(0,0), ivec2(0, 0));
GirdDF myGird2(_input.getSize(), ivec2(0,0), ivec2(9999, 9999));
// Reformat gird :
for (int32_t xxx = 0; xxx < _input.getSize().x(); ++xxx) {
for (int32_t yyy = 0; yyy < _input.getSize().y(); ++yyy) {
if ( _input.get(ivec2(xxx, yyy)) < 128 ) {
myGird1.set(ivec2(xxx, yyy), ivec2(0, 0));
myGird2.set(ivec2(xxx, yyy), ivec2(9999, 9999));
} else {
myGird1.set(ivec2(xxx, yyy), ivec2(9999, 9999));
myGird2.set(ivec2(xxx, yyy), ivec2(0, 0));
}
}
}
// Create internal distance of the 2 layer mode :
myGird1.GenerateSoftDistanceField();
myGird2.GenerateSoftDistanceField();
// Generate output :
_output.resize(_input.getSize(), etk::Color<>(0));
_output.clear(etk::Color<>(0));
for (int32_t xxx = 0; xxx < _output.getSize().x(); ++xxx) {
for (int32_t yyy = 0; yyy < _output.getSize().y(); ++yyy) {
float dist1 = myGird1.get(ivec2(xxx, yyy)).length();
float dist2 = myGird2.get(ivec2(xxx, yyy)).length();
float dist = dist1 - dist2;
float value = etk_avg(0.0f, dist*15.0f + 128.0f, 256.0f);
_output.set(ivec2(xxx, yyy), etk::Color<>((int32_t)value,(int32_t)value,(int32_t)value,256));
}
}
}
bool ewol::resource::DistanceFieldFont::addGlyph(const char32_t& _val) {
bool hasChange = false;
if (m_font == NULL) {