[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 vec2 f_texcoord;
varying vec4 f_color; varying vec4 f_color;
void main(void) { vec3 glyph_color = vec3(1.0,1.0,1.0);
vec4 tmpcolor = texture2D(EW_texID, f_texcoord); const float glyph_center = 0.50;
vec4 outColor = vec4(0,0,0,0); vec3 outline_color = vec3(0.0,0.0,0.0);
// compare distance with 0.5 that represent the middle ... const float outline_center = 0.55;
/* vec3 glow_color = vec3(1.0,1.0,1.0);
if (tmpcolor[0]>0.5) { const float glow_center = 1.25;
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;
}
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; f_color = EW_color;
} }
/* /*
// Distance map contour texturing according to Green (2007), // Distance map contour texturing according to Green (2007),
// implementation by Stefan Gustavson 2009. // implementation by Stefan Gustavson 2009.

View File

@ -5,12 +5,12 @@
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* *
* 1. Redistributions of source code must retain the above copyright notice, * 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. * this list of conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above copyright * 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* *
* THIS SOFTWARE IS PROVIDED BY STEFAN GUSTAVSON ''AS IS'' AND ANY EXPRESS OR * THIS SOFTWARE IS PROVIDED BY STEFAN GUSTAVSON ''AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * 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) void computegradient(double *img, int w, int h, double *gx, double *gy)
{ {
int i,j,k; int i,j,k;
double glength; double glength;
#define SQRT2 1.4142136 #define SQRT2 1.4142136
for(i = 1; i < h-1; i++) { // Avoid edges where the kernels would spill over for(i = 1; i < h-1; i++) { // Avoid edges where the kernels would spill over
for(j = 1; j < w-1; j++) { for(j = 1; j < w-1; j++) {
k = i*w + j; k = i*w + j;
if((img[k]>0.0) && (img[k]<1.0)) { // Compute gradient for edge pixels only 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]; 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]; 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]; glength = gx[k]*gx[k] + gy[k]*gy[k];
if(glength > 0.0) { // Avoid division by zero if(glength > 0.0) { // Avoid division by zero
glength = sqrt(glength); glength = sqrt(glength);
gx[k]=gx[k]/glength; gx[k]=gx[k]/glength;
gy[k]=gy[k]/glength; gy[k]=gy[k]/glength;
} }
} }
} }
} }
// TODO: Compute reasonable values for gx, gy also around the image edges. // 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 // (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. // 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 * accuracy at and near edges, and reduces the error even at distant pixels
* provided that the gradient direction is accurately estimated. * provided that the gradient direction is accurately estimated.
*/ */
double edgedf(double gx, double gy, double a) double edgedf(double gx, double gy, double a) {
{ double df, glength, temp, a1;
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
if ((gx == 0) || (gy == 0)) { // Either A) gu or gv are zero, or B) both } else {
df = 0.5-a; // Linear approximation is A) correct or B) a fair guess glength = sqrt(gx*gx + gy*gy);
} else { if(glength>0) {
glength = sqrt(gx*gx + gy*gy); gx = gx/glength;
if(glength>0) { gy = gy/glength;
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
/* Everything is symmetric wrt sign and transposition, * avoid handling all possible edge directions.
* so move to first octant (gx>=0, gy>=0, gx>=gy) to */
* avoid handling all possible edge directions. gx = fabs(gx);
*/ gy = fabs(gy);
gx = fabs(gx); if(gx<gy) {
gy = fabs(gy); temp = gx;
if(gx<gy) { gx = gy;
temp = gx; gy = temp;
gx = gy; }
gy = temp; a1 = 0.5*gy/gx;
} if (a < a1) { // 0 <= a < a1
a1 = 0.5*gy/gx; df = 0.5*(gx + gy) - sqrt(2.0*gx*gy*a);
if (a < a1) { // 0 <= a < a1 } else if (a < (1.0-a1)) { // a1 <= a <= 1-a1
df = 0.5*(gx + gy) - sqrt(2.0*gx*gy*a); df = (0.5-a)*gx;
} else if (a < (1.0-a1)) { // a1 <= a <= 1-a1 } else { // 1-a1 < a <= 1
df = (0.5-a)*gx; df = -0.5*(gx + gy) + sqrt(2.0*gx*gy*(1.0-a));
} else { // 1-a1 < a <= 1 }
df = -0.5*(gx + gy) + sqrt(2.0*gx*gy*(1.0-a)); }
} return df;
}
return df;
} }
double distaa3(double *img, double *gximg, double *gyimg, int w, int c, int xc, int yc, int xi, int yi) 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;
double di, df, dx, dy, gx, gy, a; int closest;
int closest;
closest = c-xc-yc*w; // Index to the edge pixel pointed to from c
closest = c-xc-yc*w; // Index to the edge pixel pointed to from c a = img[closest]; // Grayscale value at the edge pixel
a = img[closest]; // Grayscale value at the edge pixel gx = gximg[closest]; // X gradient component at the edge pixel
gx = gximg[closest]; // X gradient component at the edge pixel gy = gyimg[closest]; // Y gradient component at the edge pixel
gy = gyimg[closest]; // Y gradient component at the edge pixel
if(a > 1.0) {
if(a > 1.0) 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 < 0.0) {
a = 0.0; // Clip grayscale values outside the range [0,1]
dx = (double)xi; }
dy = (double)yi; if(a == 0.0) {
di = sqrt(dx*dx + dy*dy); // Length of integer vector, like a traditional EDT return 1000000.0; // Not an object pixel, return "very far" ("don't know yet")
if(di==0) { // Use local gradient only at edges }
// Estimate based on local gradient only
df = edgedf(gx, gy, a); dx = (double)xi;
} else { dy = (double)yi;
// Estimate gradient based on direction to edge (accurate for large di) di = sqrt(dx*dx + dy*dy); // Length of integer vector, like a traditional EDT
df = edgedf(dx, dy, a); if(di==0) { // Use local gradient only at edges
} // Estimate based on local gradient only
return di + df; // Same metric as edtaa2, except at edges (where di=0) 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() // 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) void edtaa3(double *img, double *gx, double *gy, int w, int h, short *distx, short *disty, double *dist)
{ {
int x, y, i, c; int x, y, i, c;
int offset_u, offset_ur, offset_r, offset_rd, int offset_u, offset_ur, offset_r, offset_rd,
offset_d, offset_dl, offset_l, offset_lu; offset_d, offset_dl, offset_l, offset_lu;
double olddist, newdist; double olddist, newdist;
int cdistx, cdisty, newdistx, newdisty; int cdistx, cdisty, newdistx, newdisty;
int changed; int changed;
double epsilon = 1e-3; 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 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 index offsets for the current image width */ /* Perform the transformation */
offset_u = -w; do {
offset_ur = -w+1; changed = 0;
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 */ /* Scan rows, except first row */
for(i=0; i<w*h; i++) { for(y=1; y<h; y++) {
distx[i] = 0; // At first, all pixels point to /* move index to leftmost pixel of current row */
disty[i] = 0; // themselves as the closest known. i = y*w;
if(img[i] <= 0.0) /* scan right, propagate distances from above & left */
{ /* Leftmost pixel is special, has no left neighbors */
dist[i]= 1000000.0; // Big value, means "not set yet" olddist = dist[i];
} if(olddist > 0) { // If non-zero distance or not set yet
else if (img[i]<1.0) { c = i + offset_u; // Index of candidate for testing
dist[i] = edgedf(gx[i], gy[i], img[i]); // Gradient-assisted estimate cdistx = distx[c];
} cdisty = disty[c];
else { newdistx = cdistx;
dist[i]= 0.0; // Inside the object newdisty = cdisty+1;
} newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
} if(newdist < olddist-epsilon) {
distx[i]=newdistx;
/* Perform the transformation */ disty[i]=newdisty;
do dist[i]=newdist;
{ olddist=newdist;
changed = 0; changed = 1;
}
/* Scan rows, except first row */ c = i+offset_ur;
for(y=1; y<h; y++) cdistx = distx[c];
{ cdisty = disty[c];
newdistx = cdistx-1;
/* move index to leftmost pixel of current row */ newdisty = cdisty+1;
i = y*w; newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon) {
/* scan right, propagate distances from above & left */ distx[i]=newdistx;
disty[i]=newdisty;
/* Leftmost pixel is special, has no left neighbors */ dist[i]=newdist;
olddist = dist[i]; changed = 1;
if(olddist > 0) // If non-zero distance or not set yet }
{ }
c = i + offset_u; // Index of candidate for testing i++;
cdistx = distx[c]; /* Middle pixels have all neighbors */
cdisty = disty[c]; for(x=1; x<w-1; x++, i++) {
newdistx = cdistx; olddist = dist[i];
newdisty = cdisty+1; if(olddist <= 0) {
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); continue; // No need to update further
if(newdist < olddist-epsilon) }
{ c = i+offset_l;
distx[i]=newdistx; cdistx = distx[c];
disty[i]=newdisty; cdisty = disty[c];
dist[i]=newdist; newdistx = cdistx+1;
olddist=newdist; newdisty = cdisty;
changed = 1; newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
} if(newdist < olddist-epsilon) {
distx[i]=newdistx;
c = i+offset_ur; disty[i]=newdisty;
cdistx = distx[c]; dist[i]=newdist;
cdisty = disty[c]; olddist=newdist;
newdistx = cdistx-1; changed = 1;
newdisty = cdisty+1; }
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); c = i+offset_lu;
if(newdist < olddist-epsilon) cdistx = distx[c];
{ cdisty = disty[c];
distx[i]=newdistx; newdistx = cdistx+1;
disty[i]=newdisty; newdisty = cdisty+1;
dist[i]=newdist; newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
changed = 1; if(newdist < olddist-epsilon) {
} distx[i]=newdistx;
} disty[i]=newdisty;
i++; dist[i]=newdist;
olddist=newdist;
/* Middle pixels have all neighbors */ changed = 1;
for(x=1; x<w-1; x++, i++) }
{ c = i+offset_u;
olddist = dist[i]; cdistx = distx[c];
if(olddist <= 0) continue; // No need to update further cdisty = disty[c];
newdistx = cdistx;
c = i+offset_l; newdisty = cdisty+1;
cdistx = distx[c]; newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
cdisty = disty[c]; if(newdist < olddist-epsilon) {
newdistx = cdistx+1; distx[i]=newdistx;
newdisty = cdisty; disty[i]=newdisty;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); dist[i]=newdist;
if(newdist < olddist-epsilon) olddist=newdist;
{ changed = 1;
distx[i]=newdistx; }
disty[i]=newdisty; c = i+offset_ur;
dist[i]=newdist; cdistx = distx[c];
olddist=newdist; cdisty = disty[c];
changed = 1; newdistx = cdistx-1;
} newdisty = cdisty+1;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
c = i+offset_lu; if(newdist < olddist-epsilon) {
cdistx = distx[c]; distx[i]=newdistx;
cdisty = disty[c]; disty[i]=newdisty;
newdistx = cdistx+1; dist[i]=newdist;
newdisty = cdisty+1; changed = 1;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); }
if(newdist < olddist-epsilon) }
{ /* Rightmost pixel of row is special, has no right neighbors */
distx[i]=newdistx; olddist = dist[i];
disty[i]=newdisty; if(olddist > 0) {// If not already zero distance
dist[i]=newdist; c = i+offset_l;
olddist=newdist; cdistx = distx[c];
changed = 1; cdisty = disty[c];
} newdistx = cdistx+1;
newdisty = cdisty;
c = i+offset_u; newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
cdistx = distx[c]; if(newdist < olddist-epsilon) {
cdisty = disty[c]; distx[i]=newdistx;
newdistx = cdistx; disty[i]=newdisty;
newdisty = cdisty+1; dist[i]=newdist;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); olddist=newdist;
if(newdist < olddist-epsilon) changed = 1;
{ }
distx[i]=newdistx; c = i+offset_lu;
disty[i]=newdisty; cdistx = distx[c];
dist[i]=newdist; cdisty = disty[c];
olddist=newdist; newdistx = cdistx+1;
changed = 1; newdisty = cdisty+1;
} newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
if(newdist < olddist-epsilon) {
c = i+offset_ur; distx[i]=newdistx;
cdistx = distx[c]; disty[i]=newdisty;
cdisty = disty[c]; dist[i]=newdist;
newdistx = cdistx-1; olddist=newdist;
newdisty = cdisty+1; changed = 1;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); }
if(newdist < olddist-epsilon) c = i+offset_u;
{ cdistx = distx[c];
distx[i]=newdistx; cdisty = disty[c];
disty[i]=newdisty; newdistx = cdistx;
dist[i]=newdist; newdisty = cdisty+1;
changed = 1; newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
} if(newdist < olddist-epsilon) {
} distx[i]=newdistx;
disty[i]=newdisty;
/* Rightmost pixel of row is special, has no right neighbors */ dist[i]=newdist;
olddist = dist[i]; changed = 1;
if(olddist > 0) // If not already zero distance }
{ }
c = i+offset_l; /* Move index to second rightmost pixel of current row. */
cdistx = distx[c]; /* Rightmost pixel is skipped, it has no right neighbor. */
cdisty = disty[c]; i = y*w + w-2;
newdistx = cdistx+1; /* scan left, propagate distance from right */
newdisty = cdisty; for(x=w-2; x>=0; x--, i--) {
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); olddist = dist[i];
if(newdist < olddist-epsilon) if(olddist <= 0) {
{ continue; // Already zero distance
distx[i]=newdistx; }
disty[i]=newdisty; c = i+offset_r;
dist[i]=newdist; cdistx = distx[c];
olddist=newdist; cdisty = disty[c];
changed = 1; newdistx = cdistx-1;
} newdisty = cdisty;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
c = i+offset_lu; if(newdist < olddist-epsilon) {
cdistx = distx[c]; distx[i]=newdistx;
cdisty = disty[c]; disty[i]=newdisty;
newdistx = cdistx+1; dist[i]=newdist;
newdisty = cdisty+1; changed = 1;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); }
if(newdist < olddist-epsilon) }
{ }
distx[i]=newdistx; /* Scan rows in reverse order, except last row */
disty[i]=newdisty; for(y=h-2; y>=0; y--) {
dist[i]=newdist; /* move index to rightmost pixel of current row */
olddist=newdist; i = y*w + w-1;
changed = 1; /* Scan left, propagate distances from below & right */
} /* Rightmost pixel is special, has no right neighbors */
olddist = dist[i];
c = i+offset_u; if(olddist > 0) { // If not already zero distance
cdistx = distx[c]; c = i+offset_d;
cdisty = disty[c]; cdistx = distx[c];
newdistx = cdistx; cdisty = disty[c];
newdisty = cdisty+1; newdistx = cdistx;
newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); newdisty = cdisty-1;
if(newdist < olddist-epsilon) newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty);
{ if(newdist < olddist-epsilon) {
distx[i]=newdistx; distx[i]=newdistx;
disty[i]=newdisty; disty[i]=newdisty;
dist[i]=newdist; dist[i]=newdist;
changed = 1; olddist=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. */
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/resource/FontFreeType.h>
#include <ewol/context/Context.h> #include <ewol/context/Context.h>
#include <ewol/resource/DistanceFieldFont.h> #include <ewol/resource/DistanceFieldFont.h>
#include <edtaa3/edtaa3func.h>
#undef __class__ #undef __class__
#define __class__ "resource::DistanceFieldFont" #define __class__ "resource::DistanceFieldFont"
@ -27,7 +28,7 @@ ewol::resource::DistanceFieldFont::DistanceFieldFont(const std::string& _fontNam
m_font = NULL; m_font = NULL;
m_lastGlyphPos.setValue(1,1); m_lastGlyphPos.setValue(1,1);
m_lastRawHeigh = 0; m_lastRawHeigh = 0;
m_size = 36; m_size = 70;
std::string localName = _fontName; std::string localName = _fontName;
std::vector<std::string> folderList; std::vector<std::string> folderList;
if (true == ewol::getContext().getFontDefault().getUseExternal()) { if (true == ewol::getContext().getFontDefault().getUseExternal()) {
@ -112,45 +113,41 @@ ewol::resource::DistanceFieldFont::~DistanceFieldFont(void) {
ewol::resource::FontFreeType::release(m_font); ewol::resource::FontFreeType::release(m_font);
} }
void ewol::resource::DistanceFieldFont::GenerateSoftDistanceField(const egami::ImageMono& _input, egami::Image& _output) { void ewol::resource::DistanceFieldFont::GenerateDistanceField(const egami::ImageMono& _input, egami::Image& _output) {
unsigned char *img = &_input[0]; int32_t size = _input.getSize().x() * _input.getSize().y();
unsigned int width = _input.getSize().x(); std::vector<short> xdist(size);
unsigned int height = _input.getSize().y(); std::vector<short> ydist(size);
std::vector<short> xdist; std::vector<double> gx(size);
std::vector<short> ydist; std::vector<double> gy(size);
std::vector<double> gx; std::vector<double> data(size);
std::vector<double> gy; std::vector<double> outside(size);
std::vector<double> data; std::vector<double> inside(size);
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);
// Convert img into double (data) // Convert img into double (data)
double img_min = 255, img_max = -255; double img_min = 255, img_max = -255;
for(size_t iii = 0; iii < data.size(); ++iii) { for (int32_t yyy = 0; yyy < _input.getSize().y(); ++yyy) {
double v = img[iii]; for (int32_t xxx = 0; xxx < _input.getSize().x(); ++xxx) {
data[iii] = v; int32_t iii = yyy * _input.getSize().x() + xxx;
if (v > img_max) { double v = _input.get(ivec2(xxx, yyy));
img_max = v; data[iii] = v;
} if (v > img_max) {
if (v < img_min) { img_max = v;
img_min = v; }
if (v < img_min) {
img_min = v;
}
} }
} }
// Rescale image levels between 0 and 1 // Rescale image levels between 0 and 1
for(size_t iii = 0; iii < data.size(); ++iii) { for (int32_t yyy = 0; yyy < _input.getSize().y(); ++yyy) {
data[iii] = (img[iii]-img_min)/img_max; 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) // Compute outside = edtaa3(bitmap); % Transform background (0's)
computegradient(&data[0], _input.getSize().x(), _input.getSize().y(), &gx[0], &gy[0]); 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) { for(size_t iii = 0; iii < outside.size(); ++iii) {
if( outside[iii] < 0 ) { if( outside[iii] < 0 ) {
outside[iii] = 0.0; outside[iii] = 0.0;
@ -168,7 +165,7 @@ void ewol::resource::DistanceFieldFont::GenerateSoftDistanceField(const egami::I
data[iii] = 1 - data[iii]; data[iii] = 1 - data[iii];
} }
computegradient( &data[0], _input.getSize().x(), _input.getSize().y(), &gx[0], &gy[0]); 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) { for(size_t iii = 0; iii < inside.size(); ++iii) {
if( inside[iii] < 0 ) { if( inside[iii] < 0 ) {
inside[iii] = 0.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 ewol::resource::DistanceFieldFont::addGlyph(const char32_t& _val) {
bool hasChange = false; bool hasChange = false;
if (m_font == NULL) { if (m_font == NULL) {