@ -4,6 +4,8 @@
@@ -4,6 +4,8 @@
# include <string.h>
# include <stdbool.h>
# include <wchar.h>
# include <assert.h>
# include <unistd.h>
@ -24,8 +26,6 @@
@@ -24,8 +26,6 @@
# define F32EPS 1e-5f
# define MAX_CONTOURS 16
# define PER_PIXEL 0
# define PER_ROW 0
# define DEBUG_SHOW_POINTS 0
/*
@ -82,6 +82,17 @@ struct line_contour {
@@ -82,6 +82,17 @@ struct line_contour {
struct line * data ;
} ;
struct intersection {
f32 x ;
int dir ;
} ;
enum rgb_channel {
RED = 0x000000FF ,
GREEN = 0x0000FF00 ,
BLUE = 0x00FF0000 ,
} ;
struct font_buffer {
u8 * data ;
u64 offset ;
@ -139,6 +150,8 @@ struct head_table {
@@ -139,6 +150,8 @@ struct head_table {
struct hhea_table {
int ascent ;
int descent ;
int line_gap ;
int max_advance ;
} ;
struct glyph_point {
@ -218,27 +231,25 @@ round_f32(f32 v)
@@ -218,27 +231,25 @@ round_f32(f32 v)
}
static int
scanline_intersects_line ( f32 x , f32 y , struct v2f p0 , struct v2f p1 , f32 lasty )
scanline_intersects_line ( f32 y , struct v2f p0 , struct v2f p1 , f32 lasty , f32 * vx )
{
bool goes_up = ( p0 . y > p1 . y ) ;
f32 t1 = ( y - p0 . y ) / ( p1 . y - p0 . y ) ; /* NOTE(aolo2): no horizontal lines by design */
if ( t1 = = 0 ) {
f32 x1 = p0 . x + ( p1 . x - p0 . x ) * t1 ;
if ( x1 > x ) {
if ( ( lasty < p0 . y ) & & ( p0 . y > p1 . y ) ) return ( 0 ) ;
if ( ( lasty > p0 . y ) & & ( p0 . y < p1 . y ) ) return ( 0 ) ;
int result = ( goes_up ? 1 : - 1 ) ;
return ( result ) ;
}
if ( ( lasty < p0 . y ) & & ( p0 . y > p1 . y ) ) return ( 0 ) ;
if ( ( lasty > p0 . y ) & & ( p0 . y < p1 . y ) ) return ( 0 ) ;
int result = ( goes_up ? 1 : - 1 ) ;
* vx = x1 ;
return ( result ) ;
}
if ( 0 < t1 & & t1 < 1.0f ) {
f32 x1 = p0 . x + ( p1 . x - p0 . x ) * t1 ;
if ( x1 > x ) {
int result = ( goes_up ? 1 : - 1 ) ;
return ( result ) ;
}
* vx = x1 ;
int result = ( goes_up ? 1 : - 1 ) ;
return ( result ) ;
}
return ( 0 ) ;
@ -341,9 +352,9 @@ render_grid(int x_step, int y_step, u32 *pixels, int width, int height)
@@ -341,9 +352,9 @@ render_grid(int x_step, int y_step, u32 *pixels, int width, int height)
}
static int
intersect_glyph ( struct line_contour * lines , f32 x , f32 y )
intersect_glyph ( struct line_contour * lines , f32 y , struct intersection * intersections )
{
int result = 0 ;
int nints = 0 ;
for ( int c = 0 ; c < lines - > ncontours ; + + c ) {
int from = lines - > from [ c ] ;
@ -352,12 +363,18 @@ intersect_glyph(struct line_contour *lines, f32 x, f32 y)
@@ -352,12 +363,18 @@ intersect_glyph(struct line_contour *lines, f32 x, f32 y)
for ( int i = from ; i < to ; + + i ) {
int lasti = ( i > from ? i - 1 : to - 1 ) ;
f32 lasty = lines - > data [ lasti ] . a . y ;
int r = scanline_intersects_line ( x , y , lines - > data [ i ] . a , lines - > data [ i ] . b , lasty ) ;
result + = r ;
f32 vx ;
int r = scanline_intersects_line ( y , lines - > data [ i ] . a , lines - > data [ i ] . b , lasty , & vx ) ;
if ( r ) {
intersections [ nints ] . x = vx ;
intersections [ nints ] . dir = r ;
+ + nints ;
}
}
}
return ( result ) ;
return ( nints ) ;
}
static void
@ -396,83 +413,64 @@ _D_render_glyph_points(struct glyph g, f32 scale, u32 *pixels, int width, int he
@@ -396,83 +413,64 @@ _D_render_glyph_points(struct glyph g, f32 scale, u32 *pixels, int width, int he
}
static void
render_glyph ( struct glyph g , struct line_contour * lines ,
struct ttf_font font , int px_size , u32 * pixels , int width , int height )
sort_intersections ( struct intersection * intersections , int size )
{
f32 scale = ( f32 ) px_size / ( ( f32 ) ( font . hhea . ascent - font . hhea . descent ) ) ;
//int npoints = g.end_pts_of_contours[g.ncontours - 1] + 1;
if ( g . advance < 0 ) {
g . advance * = - 1 ;
}
int x0 = 0 ; // g.xmin * scale;
int gwidth = ( g . xmax - g . xmin ) * scale ;
int gheight = ( g . ymax - g . ymin ) * scale + 1 ;
pixels = pixels + width * 100 + 100 ;
# if 1
for ( int y = 0 ; y < gheight ; + + y ) {
//u32 ncross = intersect_glyph(g, scale, x0 - 999.0f, y + 0.5f, width, intersections, &nints);
//if (ncross) {
//continue;
//}
for ( int x = x0 ; x < x0 + gwidth ; + + x ) {
u32 ncross = intersect_glyph ( lines , x + 0.5f , y + 0.5f ) ;
if ( ncross ) {
pixels [ y * width + x ] = 0x00 ;
} else {
pixels [ y * width + x ] = 0xFFFF0000 ;
bool swapped = true ;
while ( swapped ) {
swapped = false ;
for ( int i = 0 ; i < size - 1 ; + + i ) {
f32 x1 = intersections [ i ] . x ;
f32 x2 = intersections [ i + 1 ] . x ;
if ( x1 > x2 ) {
struct intersection tmp = intersections [ i ] ;
intersections [ i ] = intersections [ i + 1 ] ;
intersections [ i + 1 ] = tmp ;
swapped = true ;
}
# if PER_PIXEL
XPutImage ( display , window , default_gc , xwindow_buffer , 0 , 0 , 0 , 0 , width , height ) ;
# endif
}
# if PER_ROW
XPutImage ( display , window , default_gc , xwindow_buffer , 0 , 0 , 0 , 0 , width , height ) ;
# endif
}
# else
int oversample_x = 4 ;
int oversample_y = 4 ;
f32 norm_x = 1.0f / ( oversample_x + 1 ) ;
f32 norm_y = 1.0f / ( oversample_y + 1 ) ;
int nints ;
for ( int y = 0 ; y < gheight ; + + y ) {
for ( int x = x0 ; x < x0 + gwidth ; + + x ) {
}
static void
render_glyph ( struct glyph g , struct line_contour * lines ,
f32 scale , u32 * pixels , int width , int height , int at_x , int at_y )
{
int gwidth = round_f32 ( ( g . xmax - g . xmin ) * scale ) + 1 ;
int gheight = round_f32 ( ( g . ymax - g . ymin ) * scale ) + 1 ;
struct intersection * intersections = malloc ( lines - > from [ lines - > ncontours ] * sizeof ( struct intersection ) ) ;
for ( int y = 0 ; y < gheight & & ( at_y + y < height ) ; + + y ) {
u32 ncross = intersect_glyph ( lines , y , intersections ) ;
if ( ncross ) {
sort_intersections ( intersections , ncross ) ;
int total_hits = 0 ;
int state = 0 ;
for ( int yy = 1 ; yy < = oversample_y ; + + yy ) {
for ( int xx = 1 ; xx < = oversample_x ; + + xx ) {
u32 ncross = intersect_glyph ( lines , nlines , x + norm_x * xx , y + norm_y * yy ) ;
if ( ncross ) {
+ + total_hits ;
for ( int i = 0 ; i < ncross - 1 ; + + i ) {
struct intersection inter = intersections [ i ] ;
struct intersection next_inter = intersections [ i + 1 ] ;
state + = inter . dir ;
if ( state ! = 0 ) {
f32 x0 = inter . x ;
f32 x1 = next_inter . x ;
for ( int x = x0 ; x < x1 ; + + x ) {
pixels [ ( y + at_y ) * width + ( at_x + x ) ] = 0x00 ;
}
}
}
if ( total_hits ) {
u32 brightness = ( 256 - total_hits * 256 / ( oversample_x * oversample_y ) ) * 0.99f ;
pixels [ y * width + x ] = 0xFF000000 | brightness < < 16 | brightness < < 8 | brightness ;
} else {
//pixels[y * width + x - 1] = 0xFFFF0000;
}
}
}
# endif
# if DEBUG_SHOW_POINTS
_D_render_glyph_points ( g , scale , pixels , width , height ) ;
_D_render_glyph_points ( g , scale , pixels , width , height ) ;
# endif
}
free ( intersections ) ;
}
static void
@ -493,11 +491,11 @@ outline_to_lines(struct glyph g, f32 scale, struct line_contour *dest, int *cnt)
@@ -493,11 +491,11 @@ outline_to_lines(struct glyph g, f32 scale, struct line_contour *dest, int *cnt)
continue ;
}
f32 x1 = ( gp . x - g . xmin ) * scale ;
f32 y1 = gp . y * scale ;
f32 x1 = round_f32 ( ( gp . x - g . xmin ) * scale ) ;
f32 y1 = round_f32 ( gp . y * scale ) ;
f32 x2 = ( nextgp . x - g . xmin ) * scale ;
f32 y2 = nextgp . y * scale ;
f32 x2 = round_f32 ( ( nextgp . x - g . xmin ) * scale ) ;
f32 y2 = round_f32 ( nextgp . y * scale ) ;
if ( nextgp . on_curve ) {
if ( gp . y ! = nextgp . y ) {
@ -511,8 +509,8 @@ outline_to_lines(struct glyph g, f32 scale, struct line_contour *dest, int *cnt)
@@ -511,8 +509,8 @@ outline_to_lines(struct glyph g, f32 scale, struct line_contour *dest, int *cnt)
int nextnexti = ( nexti + 1 < g . end_pts_of_contours [ c ] + 1 ? nexti + 1 : points_from ) ;
struct glyph_point nextnextgp = g . points [ nextnexti ] ;
f32 x3 = ( nextnextgp . x - g . xmin ) * scale ;
f32 y3 = nextnextgp . y * scale ;
f32 x3 = round_f32 ( ( nextnextgp . x - g . xmin ) * scale ) ;
f32 y3 = round_f32 ( nextnextgp . y * scale ) ;
/* P(t) = P0*t^2 + P1*2*t*(1-t) + P2*(1-t)^2 */
f32 t_step = 1.0f / curve_segments ;
@ -567,6 +565,40 @@ outline_to_lines(struct glyph g, f32 scale, struct line_contour *dest, int *cnt)
@@ -567,6 +565,40 @@ outline_to_lines(struct glyph g, f32 scale, struct line_contour *dest, int *cnt)
}
}
static void
render_utf_string ( struct ttf_font font , int px_size , u32 * pixels , u32 width , u32 height , wchar_t * string , int at_x , int at_y )
{
u32 offset_x = at_x ;
u32 offset_y = at_y ;
f32 scale = ( f32 ) px_size / ( ( f32 ) ( font . hhea . ascent - font . hhea . descent ) ) ;
u32 len = wcslen ( string ) ;
for ( u32 i = 0 ; i < len ; + + i ) {
u16 codepoint = string [ i ] ;
if ( codepoint ! = ' ' ) {
struct glyph g = get_outline ( & font , codepoint ) ;
struct line_contour lines = { 0 } ;
int nlines = 0 ;
outline_to_lines ( g , scale , & lines , & nlines ) ;
lines . data = malloc ( nlines * sizeof ( struct line ) ) ;
outline_to_lines ( g , scale , & lines , 0 ) ;
int baseline_correction = round_f32 ( scale * g . ymax ) ;
render_glyph ( g , & lines , scale , pixels , width , height , offset_x + g . lsb * scale , offset_y - baseline_correction ) ;
offset_x + = scale * g . advance ;
free ( lines . data ) ;
} else {
offset_x + = px_size / 3 ;
}
//XPutImage(display, window, default_gc, xwindow_buffer, 0, 0, 0, 0, width, height);
//sleep(1);
}
}
int
main ( int argc , char * * argv )
{
@ -625,50 +657,16 @@ main(int argc, char **argv)
@@ -625,50 +657,16 @@ main(int argc, char **argv)
struct ttf_font font = parse_ttf_file ( argv [ 1 ] , " Inter " ) ;
printf ( " Loaded font \n " ) ;
//struct glyph g = get_outline(&font, 0x046C);
int codepoint = 0x0020 ;
struct glyph g = get_outline ( & font , codepoint ) ;
int nlines = 0 ;
u32 px_size = 20 ;
u32 * pixels = hc_vram ;
int t = 0 ;
f32 scale = ( f32 ) px_size / ( ( f32 ) ( font . hhea . ascent - font . hhea . descent ) ) ;
struct line_contour lines = { 0 } ;
outline_to_lines ( g , scale , & lines , & nlines ) ;
lines . data = malloc ( nlines * sizeof ( struct line ) ) ;
outline_to_lines ( g , scale , & lines , 0 ) ;
memset ( pixels , 0xFFFFFFFF , width * height * 4 ) ;
render_grid ( 10 , 10 , pixels , width , height ) ;
for ( ; ; ) {
memset ( pixels , 0xFFFFFFFF , width * height * 4 ) ;
render_grid ( 10 , 10 , pixels , width , height ) ;
render_glyph ( g , & lines , font , px_size , pixels , width , height ) ;
XPutImage ( display , window , default_gc , xwindow_buffer , 0 , 0 , 0 , 0 , width , height ) ;
# if 1
//printf("%d\n", px_size);
+ + px_size ;
render_utf_string ( font , 32 , pixels , width , height , L " Привет, батя! Как поживаешь? Hello, Batya. Wazzaaap " , 100 , 100 ) ;
render_utf_string ( font , 32 , pixels , width , height , L " QQQQqqqqq " , 100 , 200 ) ;
scale = ( f32 ) px_size / ( ( f32 ) ( font . hhea . ascent - font . hhea . descent ) ) ;
free ( lines . data ) ;
lines . data = 0 ;
outline_to_lines ( g , scale , & lines , & nlines ) ;
lines . data = malloc ( nlines * sizeof ( struct line ) ) ;
outline_to_lines ( g , scale , & lines , 0 ) ;
if ( px_size > 200 ) {
+ + codepoint ;
g = get_outline ( & font , codepoint ) ;
printf ( " Loaded codepoint %#x \n " , codepoint ) ;
px_size = 20 ;
}
# endif
XPutImage ( display , window , default_gc , xwindow_buffer , 0 , 0 , 0 , 0 , width , height ) ;
//sleep(1);