[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[freetype2-demos] GSoC-2020-anuj b2d2eba 5/5: [ftsdf] Added function to
From: |
Anuj Verma |
Subject: |
[freetype2-demos] GSoC-2020-anuj b2d2eba 5/5: [ftsdf] Added function to draw SDF to the display. |
Date: |
Sat, 22 Aug 2020 01:37:49 -0400 (EDT) |
branch: GSoC-2020-anuj
commit b2d2eba62aa9dd5461f5d7415a068a668a5b5b3f
Author: Anuj Verma <anujv@iitbhilai.ac.in>
Commit: Anuj Verma <anujv@iitbhilai.ac.in>
[ftsdf] Added function to draw SDF to the display.
* src/ftsdf.c (draw): The function draws the SDF data to the display
buffer. It also
takes care of filtering and certain property values.
* src/ftsdf.c (clamp, smoothstep): A few helper functions for `draw'.
---
src/ftsdf.c | 221 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 221 insertions(+)
diff --git a/src/ftsdf.c b/src/ftsdf.c
index 304a9f9..8cd43c3 100644
--- a/src/ftsdf.c
+++ b/src/ftsdf.c
@@ -340,4 +340,225 @@
return ret;
}
+ float
+ clamp(float x, float lower_limit, float upper_limit) {
+ /* The function clamps the value `x' between `lowerlimit' */
+ /* and `upperlimit'. */
+ if (x < lower_limit)
+ x = lower_limit;
+ if (x > upper_limit)
+ x = upper_limit;
+ return x;
+ }
+
+ float
+ smoothstep(float edge0, float edge1, float x) {
+ /* The function interpolate the value of `x' between */
+ /* `edge0' and `edge1' smoothly using a polynomial */
+ /* function. */
+
+ /* This implementation is taken from Wikipedia. */
+ /* https://en.wikipedia.org/wiki/Smoothstep */
+
+ // Scale, bias and saturate x to 0..1 range
+ x = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
+ // Evaluate polynomial
+ return x * x * (3 - 2 * x);
+ }
+
+ static FT_Error
+ draw()
+ {
+ /* The function draws a SDF image to the display. */
+
+ FT_Bitmap* bitmap = &status.face->glyph->bitmap;
+ Box draw_region;
+ Box sample_region;
+ Vec2 center;
+ FT_Short* buffer;
+
+
+ if ( !bitmap || !bitmap->buffer )
+ return FT_Err_Invalid_Argument;
+
+ /* compute the center of the display */
+ center.x = display->bitmap->width / 2;
+ center.y = display->bitmap->rows / 2;
+
+ /* compute the draw reigon around the `center' */
+ draw_region.xMin = center.x - ( bitmap->width * status.scale) / 2;
+ draw_region.xMax = center.x + ( bitmap->width * status.scale) / 2;
+ draw_region.yMin = center.y - ( bitmap->rows * status.scale) / 2;
+ draw_region.yMax = center.y + ( bitmap->rows * status.scale) / 2;
+
+ /* add the position offset so that we can move the image */
+ draw_region.xMin += status.x_offset;
+ draw_region.xMax += status.x_offset;
+ draw_region.yMin += status.y_offset;
+ draw_region.yMax += status.y_offset;
+
+ /* Sample region is the region of the bitmap that will */
+ /* be sampled to the display buffer. */
+ sample_region.xMin = 0;
+ sample_region.xMax = bitmap->width * status.scale;
+ sample_region.yMin = 0;
+ sample_region.yMax = bitmap->rows * status.scale;
+
+ /* Adjust the sample region in case our draw region */
+ /* goes outiside the dislpay. */
+
+ /* adjust in -y */
+ if ( draw_region.yMin < 0 )
+ {
+ sample_region.yMax -= draw_region.yMin;
+ draw_region.yMin = 0;
+ }
+
+ /* adjust in +y */
+ if ( draw_region.yMax > display->bitmap->rows )
+ {
+ sample_region.yMin += draw_region.yMax - display->bitmap->rows;
+ draw_region.yMax = display->bitmap->rows;
+ }
+
+ /* adjust in -x */
+ if ( draw_region.xMin < 0 )
+ {
+ sample_region.xMin -= draw_region.xMin;
+ draw_region.xMin = 0;
+ }
+
+ /* adjust in +x */
+ if ( draw_region.xMax > display->bitmap->width )
+ {
+ sample_region.xMax += draw_region.xMax - display->bitmap->width;
+ draw_region.xMax = display->bitmap->width;
+ }
+
+ buffer = (FT_Short*)bitmap->buffer;
+
+ /* Finally loop the pixels inside the draw region and copy the */
+ /* pixel from the sample region to the draw region. */
+ for ( FT_Int j = draw_region.yMax - 1, y = sample_region.yMin; j >=
draw_region.yMin; j--, y++ )
+ {
+ for ( FT_Int i = draw_region.xMin, x = sample_region.xMin; i <
draw_region.xMax; i++, x++ )
+ {
+ FT_UInt display_index = j * display->bitmap->width + i;
+ float min_dist;
+
+ if ( status.nearest_filtering )
+ {
+ FT_UInt bitmap_index = ( y / status.scale ) * bitmap->width + ( x
/ status.scale );
+ FT_Short pixel_value = buffer[bitmap_index];
+
+ /* If nearest filtering then simply take the value of the */
+ /* nearest sampling pixel. */
+ min_dist = (float)pixel_value / 1024.0f;
+ }
+ else
+ {
+ /* for simplicity use floats */
+ float bi_x;
+ float bi_y;
+
+ float nbi_x;
+ float nbi_y;
+
+ int indc[4]; /* [0,0] [0,1] [1,0] [1,1] */
+ float dist[4];
+
+ float m1, m2;
+
+ /* If bilinear filtering then compute the bilinear */
+ /* interpolation of the current draw pixel using */
+ /* the nearby sampling pixel values. */
+
+ /* Again the concept is taken from Wikipedia. */
+ /* https://en.wikipedia.org/wiki/Bilinear_interpolation */
+
+ bi_x = (float)x / (float)status.scale;
+ bi_y = (float)y / (float)status.scale;
+
+ nbi_x = bi_x - (int)bi_x;
+ nbi_y = bi_y - (int)bi_y;
+
+ indc[0] = (int)bi_y * bitmap->width + (int)bi_x;
+ indc[1] = ( (int)bi_y + 1 ) * bitmap->width + (int)bi_x;
+ indc[2] = (int)bi_y * bitmap->width + (int)bi_x + 1;
+ indc[3] = ( (int)bi_y + 1 ) * bitmap->width + (int)bi_x + 1;
+
+ dist[0] = (float)buffer[indc[0]] / 1024.0f;
+
+ if ( indc[1] >= bitmap->width * bitmap->rows )
+ dist[1] = -status.spread;
+ else
+ dist[1] = (float)buffer[indc[1]] / 1024.0f;
+
+ if ( indc[2] >= bitmap->width * bitmap->rows )
+ dist[2] = -status.spread;
+ else
+ dist[2] = (float)buffer[indc[2]] / 1024.0f;
+
+ if ( indc[3] >= bitmap->width * bitmap->rows )
+ dist[3] = -status.spread;
+ else
+ dist[3] = (float)buffer[indc[3]] / 1024.0f;
+
+ m1 = dist[0] * ( 1.0f - nbi_y ) + dist[1] * nbi_y;
+ m2 = dist[2] * ( 1.0f - nbi_y ) + dist[3] * nbi_y;
+
+ /* This is our final display after bilinear interpolation. */
+ min_dist = ( 1.0f - nbi_x ) * m1 +
+ ( nbi_x ) * m2;
+ }
+
+
+ if ( status.reconstruct )
+ {
+ float alpha;
+
+
+ /* If we are reconstructing then discard the values outside the */
+ /* range defined by `status.width' and use the `status.edge' to */
+ /* make smooth anti-aliased edges. */
+
+ /* This is exactly similar to a OpenGL implementation to draw SDF. */
+ alpha = 1.0f - smoothstep( status.width, status.width +
status.edge, -min_dist );
+ alpha *= 255;
+
+ /* finally copy the target value to the display buffer */
+ display_index *= 3;
+ display->bitmap->buffer[display_index + 0] = (unsigned char)alpha;
+ display->bitmap->buffer[display_index + 1] = (unsigned char)alpha;
+ display->bitmap->buffer[display_index + 2] = (unsigned char)alpha;
+ }
+ else
+ {
+ float final_dist = min_dist;
+
+
+ /* If not reconstructing then normalize the values between [0, 255]
*/
+ /* and copy to the display buffer.
*/
+
+ /* normalize using `status.spread' */
+ final_dist = final_dist < 0 ? -final_dist : final_dist;
+ final_dist /= (float)status.spread;
+
+ /* invert the values */
+ final_dist = 1.0f - final_dist;
+ final_dist *= 255;
+
+ /* finally copy the target value to the display buffer */
+ display_index *= 3;
+ display->bitmap->buffer[display_index + 0] = (unsigned
char)final_dist;
+ display->bitmap->buffer[display_index + 1] = (unsigned
char)final_dist;
+ display->bitmap->buffer[display_index + 2] = (unsigned
char)final_dist;
+ }
+ }
+ }
+
+ return FT_Err_Ok;
+ }
+
+
/* END */
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [freetype2-demos] GSoC-2020-anuj b2d2eba 5/5: [ftsdf] Added function to draw SDF to the display.,
Anuj Verma <=