Compare commits
32 Commits
master
...
gsoc-anura
Author | SHA1 | Date | |
---|---|---|---|
|
08e08f5908 | ||
|
108e5e3e34 | ||
|
467ba66539 | ||
|
17d14a6cef | ||
|
bd9aba933b | ||
|
d257405687 | ||
|
9538d8e798 | ||
|
c03591c48a | ||
|
0b682c5417 | ||
|
3d0e33d2aa | ||
|
f6bd130ba3 | ||
|
5424f47eb9 | ||
|
2fc3e384ed | ||
|
1cf8e2ed5d | ||
|
edd9a84c36 | ||
|
6f86728eb3 | ||
|
94183cf0b6 | ||
|
9aafe98c1d | ||
|
d9c301d35a | ||
|
8af62c3469 | ||
|
8687c459c0 | ||
|
39bcb3a647 | ||
|
bb95b4423e | ||
|
dbf9623ab4 | ||
|
e122ecf1e5 | ||
|
1e0918c41c | ||
|
05c8790008 | ||
|
dee8855a9c | ||
|
9b40ce9cbc | ||
|
63dd924394 | ||
|
f6a2237ff6 | ||
|
7511d64e60 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -5,3 +5,5 @@ src/dlg/dlg.c
|
||||
subprojects/*
|
||||
!subprojects/*.wrap
|
||||
/tests/data/*
|
||||
.cache/*
|
||||
compile_commands.json
|
||||
|
8
.vscode/settings.json
vendored
Normal file
8
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"ftoutln.h": "c",
|
||||
"svprop.h": "c",
|
||||
"ftdebug.h": "c",
|
||||
"tmmintrin.h": "c"
|
||||
}
|
||||
}
|
@ -405,6 +405,7 @@ set(BASE_SRCS
|
||||
src/cache/ftcache.c
|
||||
src/cff/cff.c
|
||||
src/cid/type1cid.c
|
||||
src/dense/dense.c
|
||||
src/gzip/ftgzip.c
|
||||
src/lzw/ftlzw.c
|
||||
src/pcf/pcf.c
|
||||
|
@ -24,6 +24,7 @@ FT_USE_MODULE( FT_Module_Class, psaux_module_class )
|
||||
FT_USE_MODULE( FT_Module_Class, psnames_module_class )
|
||||
FT_USE_MODULE( FT_Module_Class, pshinter_module_class )
|
||||
FT_USE_MODULE( FT_Module_Class, sfnt_module_class )
|
||||
FT_USE_MODULE( FT_Renderer_Class, ft_dense_renderer_class )
|
||||
FT_USE_MODULE( FT_Renderer_Class, ft_smooth_renderer_class )
|
||||
FT_USE_MODULE( FT_Renderer_Class, ft_raster1_renderer_class )
|
||||
FT_USE_MODULE( FT_Renderer_Class, ft_sdf_renderer_class )
|
||||
|
@ -93,9 +93,12 @@ HINTING_MODULES += pshinter
|
||||
#### raster modules -- at least one is required for vector font formats
|
||||
####
|
||||
|
||||
RASTER_MODULES += dense
|
||||
# Anti-aliasing rasterizer.
|
||||
RASTER_MODULES += smooth
|
||||
|
||||
#RASTER_MODULES += dense
|
||||
|
||||
# Monochrome rasterizer.
|
||||
RASTER_MODULES += raster
|
||||
|
||||
|
6
src/dense/dense.c
Normal file
6
src/dense/dense.c
Normal file
@ -0,0 +1,6 @@
|
||||
/** For building a single object of the entire module */
|
||||
#define FT_MAKE_OPTION_SINGLE_OBJECT
|
||||
|
||||
#include "ftdense.c"
|
||||
#include "ftdenserend.c"
|
||||
/* END */
|
613
src/dense/ftdense.c
Normal file
613
src/dense/ftdense.c
Normal file
@ -0,0 +1,613 @@
|
||||
/** The rasterizer for the 'dense' renderer */
|
||||
|
||||
#include <stdio.h>
|
||||
#undef FT_COMPONENT
|
||||
#define FT_COMPONENT dense
|
||||
|
||||
#include <freetype/ftoutln.h>
|
||||
#include <freetype/internal/ftcalc.h>
|
||||
#include <freetype/internal/ftdebug.h>
|
||||
#include <freetype/internal/ftobjs.h>
|
||||
#include "ftdense.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <immintrin.h>
|
||||
#include "ftdenseerrs.h"
|
||||
|
||||
#define PIXEL_BITS 8
|
||||
|
||||
#define ONE_PIXEL ( 1 << PIXEL_BITS )
|
||||
#define TRUNC( x ) (int)( ( x ) >> PIXEL_BITS )
|
||||
|
||||
#define UPSCALE( x ) ( ( x ) * ( ONE_PIXEL >> 6 ) )
|
||||
#define DOWNSCALE( x ) ( ( x ) >> ( PIXEL_BITS - 6 ) )
|
||||
|
||||
// TODO: Fix types
|
||||
#define FT_UDIVPREP( c, b ) \
|
||||
FT26D6 b ## _r = c ? (FT26D6)0xFFFFFFFF / ( b ) : 0
|
||||
#define FT_UDIV( a, b ) \
|
||||
(FT26D6)( ( (FT26D6)( a ) * (FT26D6)( b ## _r ) ) >> 32 )
|
||||
|
||||
typedef struct dense_TRaster_
|
||||
{
|
||||
void* memory;
|
||||
|
||||
} dense_TRaster, *dense_PRaster;
|
||||
|
||||
static FT_Vector
|
||||
Lerp( float aT, FT_Vector aP0, FT_Vector aP1 )
|
||||
{
|
||||
FT_Vector p;
|
||||
p.x = aP0.x + aT * ( aP1.x - aP0.x );
|
||||
p.y = aP0.y + aT * ( aP1.y - aP0.y );
|
||||
return p;
|
||||
}
|
||||
|
||||
static int
|
||||
dense_move_to( const FT_Vector* to, dense_worker* worker )
|
||||
{
|
||||
TPos x, y;
|
||||
|
||||
x = UPSCALE( to->x );
|
||||
y = UPSCALE( to->y );
|
||||
worker->prev_x = x;
|
||||
worker->prev_y = y;
|
||||
// printf( "last point is {%f, %f}", lp.m_x, lp.m_y );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
dense_line_to( const FT_Vector* to, dense_worker* worker )
|
||||
{
|
||||
//printf( "dense_line_to: %d, %d\n", to->x, to->y );
|
||||
dense_render_line( worker, UPSCALE( to->x ), UPSCALE( to->y ) );
|
||||
dense_move_to( to, worker );
|
||||
return 0;
|
||||
}
|
||||
|
||||
FT26D6 max(FT26D6 x, FT26D6 y){
|
||||
if(x > y)
|
||||
return x;
|
||||
return y;
|
||||
}
|
||||
|
||||
FT26D6 min(FT26D6 x, FT26D6 y){
|
||||
if(x < y)
|
||||
return x;
|
||||
return y;
|
||||
}
|
||||
|
||||
void
|
||||
swap( long int* a, long int* b )
|
||||
{
|
||||
long int temp = *a;
|
||||
*a = *b;
|
||||
*b = temp;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
dense_render_line( dense_worker* worker, TPos tox, TPos toy )
|
||||
{
|
||||
|
||||
FT26D6 fx = worker->prev_x>>2;
|
||||
FT26D6 fy = worker->prev_y>>2;
|
||||
|
||||
FT26D6 from_x = fx;
|
||||
FT26D6 from_y = fy;
|
||||
|
||||
FT26D6 tx = tox>>2;
|
||||
FT26D6 ty = toy>>2;
|
||||
|
||||
FT26D6 to_x = tx;
|
||||
FT26D6 to_y = ty;
|
||||
|
||||
// from_x/y and to_x/y are coordinates in 26.6 format
|
||||
if ( from_y == to_y )
|
||||
return;
|
||||
|
||||
//printf("line from: %f, %f to %f, %f\n", from_x, from_y, to_x, to_y);
|
||||
|
||||
int dir = 1;
|
||||
if ( from_y >= to_y )
|
||||
{
|
||||
dir = -1;
|
||||
swap( &from_x, &to_x );
|
||||
swap( &from_y, &to_y );
|
||||
}
|
||||
|
||||
// Clip to the height.
|
||||
if ( from_y >= worker->m_h<<6 || to_y <= 0 )
|
||||
return;
|
||||
|
||||
|
||||
FT26D6 deltax,deltay;
|
||||
deltax = to_x - from_x;
|
||||
deltay = to_y - from_y;
|
||||
|
||||
FT_UDIVPREP(from_x != to_x, deltax);
|
||||
|
||||
FT_UDIVPREP(from_y != to_y, deltay);
|
||||
|
||||
|
||||
if ( from_y < 0 )
|
||||
{
|
||||
from_x -= from_y * deltax/deltay;
|
||||
from_y = 0;
|
||||
}
|
||||
|
||||
// This condition is important apparently
|
||||
if ( to_y > worker->m_h<<6 )
|
||||
{
|
||||
to_x -= (( to_y - worker->m_h<<6 ) * deltax/deltay);
|
||||
to_y = worker->m_h<<6;
|
||||
}
|
||||
|
||||
|
||||
if(deltax == 0){
|
||||
FT26D6 x = from_x;
|
||||
int x0i = x>>6;
|
||||
FT26D6 x0floor = x0i<<6;
|
||||
|
||||
// y-coordinate of first pixel of line
|
||||
int y0 = from_y>>6;
|
||||
|
||||
// y-coordinate of last pixel of line
|
||||
int y_limit = (to_y + 0x3f)>>6;
|
||||
FT20D12* m_a = worker->m_a;
|
||||
|
||||
|
||||
|
||||
for ( int y = y0; y < y_limit; y++ )
|
||||
{
|
||||
int linestart = y * worker->m_w;
|
||||
|
||||
FT26D6 dy = min( (y + 1)<<6, to_y ) - max( y<<6, from_y );
|
||||
|
||||
m_a[linestart + x0i] += dir*dy*(64 - x + x0floor);
|
||||
m_a[linestart + ( x0i + 1 )] += dir*dy*(x-x0floor);
|
||||
|
||||
}
|
||||
|
||||
// int y = y0;
|
||||
|
||||
// int linestart = y * worker->m_w;
|
||||
|
||||
// FT26D6 dy1 = min( (y + 1)<<6, to_y ) - max( y<<6, from_y );
|
||||
// m_a[linestart + x0i] += dir*dy1*(64 - x + x0floor);
|
||||
// m_a[linestart + ( x0i + 1 )] += dir*dy1*(x-x0floor);
|
||||
|
||||
// y = y_limit -1;
|
||||
|
||||
// linestart = y * worker->m_w;
|
||||
|
||||
// FT26D6 dy2 = min( (y + 1)<<6, to_y ) - max( y<<6, from_y );
|
||||
// m_a[linestart + x0i] += dir*dy2*(64 - x + x0floor);
|
||||
// m_a[linestart + ( x0i + 1 )] += dir*dy2*(x-x0floor);
|
||||
|
||||
|
||||
|
||||
}else{
|
||||
|
||||
FT26D6 x = from_x;
|
||||
|
||||
// y-coordinate of first pixel of line
|
||||
int y0 = from_y>>6;
|
||||
|
||||
// y-coordinate of last pixel of line
|
||||
int y_limit = (to_y + 0x3f)>>6;
|
||||
FT20D12* m_a = worker->m_a;
|
||||
|
||||
|
||||
for ( int y = y0; y < y_limit; y++ )
|
||||
{
|
||||
int linestart = y * worker->m_w;
|
||||
|
||||
// dy is the height of the line present in the current scanline
|
||||
FT26D6 dy = min( (y + 1)<<6, to_y ) - max( y<<6, from_y );
|
||||
|
||||
// x coordinate where the line leaves the current scanline
|
||||
FT26D6 xnext = x + FT_UDIV((dy*deltax), deltay);
|
||||
|
||||
|
||||
// height with sign
|
||||
FT26D6 d = dy * dir;
|
||||
|
||||
// x0 is the x coordinate of the start of line in current scanline
|
||||
// x1 is the x coordinate of the end of line in current scanline
|
||||
FT26D6 x0, x1;
|
||||
if ( x < xnext )
|
||||
{
|
||||
x0 = x;
|
||||
x1 = xnext;
|
||||
}
|
||||
else
|
||||
{
|
||||
x0 = xnext;
|
||||
x1 = x;
|
||||
}
|
||||
|
||||
// x coordinate of the leftmost intersected pixel in the scanline
|
||||
int x0i = x0>>6;
|
||||
FT26D6 x0floor = x0i<<6;
|
||||
|
||||
|
||||
// float x1ceil = (float)ceil( x1 );
|
||||
// x coordinate of the rightmost intersected pixel in the scanline
|
||||
int x1i = (x1+0x3f)>>6;
|
||||
FT26D6 x1ceil = x1i <<6;
|
||||
|
||||
if ( x1i <= x0i + 1 )
|
||||
{
|
||||
// average of x coordinates of trapezium with origin at left of pixel
|
||||
FT26D6 xmf = ( ( x + xnext )>>1) - x0floor;
|
||||
|
||||
// average of x coordinates of trapezium with origin at right of pixel
|
||||
m_a[linestart + x0i] += d * ((1<<6) - xmf);
|
||||
m_a[linestart + ( x0i + 1 )] += d * xmf;
|
||||
}
|
||||
else
|
||||
{
|
||||
// total horizontal length of line in current scanline, might be replaced by deltax
|
||||
FT26D6 oneOverS = x1 - x0;
|
||||
|
||||
FT_UDIVPREP(x1 != x0, oneOverS);
|
||||
|
||||
FT26D6 x0f = x0 - x0floor;
|
||||
|
||||
// 64 - x0f is the horizontal length of line in first pixel
|
||||
FT26D6 oneMinusX0f = (1<<6) - x0f;
|
||||
|
||||
// Stores area of triangle in first pixel divided by d
|
||||
FT26D6 a0 = FT_UDIV(((oneMinusX0f * oneMinusX0f) >> 1), oneOverS);
|
||||
|
||||
// x1f is the horizontal length in the last pixel
|
||||
FT26D6 x1f = x1 - x1ceil + (1<<6);
|
||||
FT26D6 am = FT_UDIV(((x1f * x1f) >> 1) , oneOverS);
|
||||
|
||||
// d * a0 is area of triangle in first pixel
|
||||
m_a[linestart + x0i] += d * a0;
|
||||
if ( x1i == x0i + 2 )
|
||||
m_a[linestart + ( x0i + 1 )] += d * ( (1<<6) - a0 - am );
|
||||
else
|
||||
{
|
||||
|
||||
FT26D6 a1 = FT_UDIV((((1<<6) + (1<<5) - x0f) << 6) , oneOverS);
|
||||
|
||||
m_a[linestart + ( x0i + 1 )] += d * ( a1 - a0 );
|
||||
|
||||
FT26D6 dTimesS = FT_UDIV((d << 12) , oneOverS);
|
||||
|
||||
for ( FT26D6 xi = x0i + 2; xi < x1i - 1; xi++ ){
|
||||
// Increase area for successive pixels by dy/dx
|
||||
m_a[linestart + xi] += dTimesS;
|
||||
}
|
||||
|
||||
|
||||
FT26D6 a2 = a1 + FT_UDIV((( x1i - x0i - 3 )<<12),oneOverS);
|
||||
m_a[linestart + ( x1i - 1 )] += d * ( (1<<6) - a2 - am );
|
||||
}
|
||||
// Area in last pixel of scanline
|
||||
m_a[linestart + x1i] += d * am;
|
||||
}
|
||||
|
||||
x = xnext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
dense_conic_to( const FT_Vector* control,
|
||||
const FT_Vector* to,
|
||||
dense_worker* worker )
|
||||
{
|
||||
//printf( "dense_conic_to: %d, %d\n", to->x, to->y );
|
||||
dense_render_quadratic( worker, control, to );
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
dense_render_quadratic( dense_worker* worker,
|
||||
const FT_Vector* control,
|
||||
const FT_Vector* to )
|
||||
{
|
||||
/*
|
||||
Calculate devsq as the square of four times the
|
||||
distance from the control point to the midpoint of the curve.
|
||||
This is the place at which the curve is furthest from the
|
||||
line joining the control points.
|
||||
|
||||
4 x point on curve = p0 + 2p1 + p2
|
||||
4 x midpoint = 4p1
|
||||
|
||||
The division by four is omitted to save time.
|
||||
*/
|
||||
|
||||
FT_Vector aP0 = { DOWNSCALE( worker->prev_x ), DOWNSCALE( worker->prev_y ) };
|
||||
FT_Vector aP1 = { control->x, control->y };
|
||||
FT_Vector aP2 = { to->x, to->y };
|
||||
|
||||
float devx = aP0.x - aP1.x - aP1.x + aP2.x;
|
||||
float devy = aP0.y - aP1.y - aP1.y + aP2.y;
|
||||
float devsq = devx * devx + devy * devy;
|
||||
|
||||
if ( devsq < 0.333f )
|
||||
{
|
||||
dense_line_to( &aP2, worker );
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
According to Raph Levien, the reason for the subdivision by n (instead of
|
||||
recursive division by the Casteljau system) is that "I expect the flatness
|
||||
computation to be semi-expensive (it's done once rather than on each potential
|
||||
subdivision) and also because you'll often get fewer subdivisions. Taking a
|
||||
circular arc as a simplifying assumption, where I get n, a recursive approach
|
||||
would get 2^ceil(lg n), which, if I haven't made any horrible mistakes, is
|
||||
expected to be 33% more in the limit".
|
||||
*/
|
||||
|
||||
const float tol = 3.0f;
|
||||
int n = (int)floor( sqrt( sqrt( tol * devsq ) ) )/8;
|
||||
//printf( "n is %d\n", n );
|
||||
FT_Vector p = aP0;
|
||||
float nrecip = 1.0f / ( n + 1.0f );
|
||||
float t = 0.0f;
|
||||
for ( int i = 0; i < n; i++ )
|
||||
{
|
||||
t += nrecip;
|
||||
FT_Vector next = Lerp( t, Lerp( t, aP0, aP1 ), Lerp( t, aP1, aP2 ) );
|
||||
dense_line_to(&next, worker );
|
||||
p = next;
|
||||
}
|
||||
|
||||
dense_line_to( &aP2, worker );
|
||||
// worker->prev_x = aP2.x;
|
||||
// worker->prev_y = aP2.y;
|
||||
}
|
||||
|
||||
static int
|
||||
dense_cubic_to( const FT_Vector* control1,
|
||||
const FT_Vector* control2,
|
||||
const FT_Vector* to,
|
||||
dense_worker* worker )
|
||||
{
|
||||
dense_render_cubic( worker, control1, control2, to );
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
dense_render_cubic( dense_worker* worker,
|
||||
FT_Vector* aP1,
|
||||
FT_Vector* aP2,
|
||||
FT_Vector* aP3 )
|
||||
{
|
||||
// assert( worker );
|
||||
FT_Vector aP0 = { worker->prev_x, worker->prev_y };
|
||||
float devx = aP0.x - aP1->x - aP1->x + aP2->x;
|
||||
float devy = aP0.y - aP1->y - aP1->y + aP2->y;
|
||||
float devsq0 = devx * devx + devy * devy;
|
||||
devx = aP1->x - aP2->x - aP2->x + aP3->x;
|
||||
devy = aP1->y - aP2->y - aP2->y + aP3->y;
|
||||
float devsq1 = devx * devx + devy * devy;
|
||||
float devsq = fmax( devsq0, devsq1 );
|
||||
|
||||
if ( devsq < 0.333f )
|
||||
{
|
||||
dense_render_line( worker, aP3->x, aP3->y );
|
||||
return;
|
||||
}
|
||||
|
||||
const float tol = 3.0f;
|
||||
int n = (int)floor( sqrt( sqrt( tol * devsq ) ) );
|
||||
FT_Vector p = aP0;
|
||||
float nrecip = 1.0f / ( n + 1.0f );
|
||||
float t = 0.0f;
|
||||
for ( int i = 0; i < n; i++ )
|
||||
{
|
||||
t += nrecip;
|
||||
FT_Vector a = Lerp( t, Lerp( t, aP0, *aP1 ), Lerp( t, *aP1, *aP2 ) );
|
||||
FT_Vector b = Lerp( t, Lerp( t, *aP1, *aP2 ), Lerp( t, *aP2, *aP3 ) );
|
||||
FT_Vector next = Lerp( t, a, b );
|
||||
dense_render_line( worker, next.x, next.y );
|
||||
worker->prev_x = next.x;
|
||||
worker->prev_y = next.y;
|
||||
p = next;
|
||||
}
|
||||
|
||||
dense_render_line( worker, aP3->x, aP3->y );
|
||||
worker->prev_x = aP3->x;
|
||||
worker->prev_y = aP3->y;
|
||||
}
|
||||
|
||||
static int
|
||||
dense_raster_new( FT_Memory memory, dense_PRaster* araster )
|
||||
{
|
||||
FT_Error error;
|
||||
dense_PRaster raster;
|
||||
|
||||
if ( !FT_NEW( raster ) )
|
||||
raster->memory = memory;
|
||||
|
||||
*araster = raster;
|
||||
return error;
|
||||
}
|
||||
|
||||
static void
|
||||
dense_raster_done( FT_Raster raster )
|
||||
{
|
||||
FT_Memory memory = (FT_Memory)( (dense_PRaster)raster )->memory;
|
||||
|
||||
FT_FREE( raster );
|
||||
}
|
||||
|
||||
static void
|
||||
dense_raster_reset( FT_Raster raster,
|
||||
unsigned char* pool_base,
|
||||
unsigned long pool_size )
|
||||
{
|
||||
FT_UNUSED( raster );
|
||||
FT_UNUSED( pool_base );
|
||||
FT_UNUSED( pool_size );
|
||||
}
|
||||
|
||||
static int
|
||||
dense_raster_set_mode( FT_Raster raster, unsigned long mode, void* args )
|
||||
{
|
||||
FT_UNUSED( raster );
|
||||
FT_UNUSED( mode );
|
||||
FT_UNUSED( args );
|
||||
|
||||
return 0; /* nothing to do */
|
||||
}
|
||||
|
||||
FT_DEFINE_OUTLINE_FUNCS( dense_decompose_funcs,
|
||||
|
||||
(FT_Outline_MoveTo_Func)dense_move_to, /* move_to */
|
||||
(FT_Outline_LineTo_Func)dense_line_to, /* line_to */
|
||||
(FT_Outline_ConicTo_Func)dense_conic_to, /* conic_to */
|
||||
(FT_Outline_CubicTo_Func)dense_cubic_to, /* cubic_to */
|
||||
|
||||
0, /* shift */
|
||||
0 /* delta */
|
||||
)
|
||||
|
||||
static int
|
||||
dense_render_glyph( dense_worker* worker, const FT_Bitmap* target )
|
||||
{
|
||||
FT_Error error = FT_Outline_Decompose( &( worker->outline ),
|
||||
&dense_decompose_funcs, worker );
|
||||
// Render into bitmap
|
||||
const FT20D12* source = worker->m_a;
|
||||
|
||||
unsigned char* dest = target->buffer;
|
||||
unsigned char* dest_end = target->buffer + worker->m_w * worker->m_h;
|
||||
|
||||
__m128i offset = _mm_setzero_si128();
|
||||
__m128i mask = _mm_set1_epi32( 0x0c080400 );
|
||||
|
||||
for (int i = 0; i < worker->m_h*worker->m_w; i += 4)
|
||||
{
|
||||
// load 4 floats from source
|
||||
|
||||
__m128i x = _mm_load_si128( (__m128i*)&source[i] );
|
||||
|
||||
// bkc
|
||||
x = _mm_add_epi32( x, _mm_slli_si128( x, 4 ) );
|
||||
|
||||
// more bkc
|
||||
x = _mm_add_epi32(
|
||||
x, _mm_castps_si128( _mm_shuffle_ps( _mm_setzero_ps(),
|
||||
_mm_castsi128_ps( x ), 0x40 ) ) );
|
||||
|
||||
// add the prefsum of previous 4 floats to all current floats
|
||||
x = _mm_add_epi32( x, offset );
|
||||
|
||||
// take absolute value
|
||||
__m128i y = _mm_abs_epi32( x ); // fabs(x)
|
||||
|
||||
// cap max value to 1
|
||||
y = _mm_min_epi32( y, _mm_set1_epi32( 4080 ) );
|
||||
|
||||
// reduce to 255
|
||||
y = _mm_srli_epi32( y, 4 );
|
||||
|
||||
// black magic
|
||||
y = _mm_shuffle_epi8( y, mask );
|
||||
|
||||
// for some reason, storing float in an unsigned char array works fine lol
|
||||
_mm_store_ss( (float*)&dest[i], (__m128)y );
|
||||
|
||||
// store the current prefix sum in offset
|
||||
offset = _mm_castps_si128( _mm_shuffle_ps( _mm_castsi128_ps( x ),
|
||||
_mm_castsi128_ps( x ),
|
||||
_MM_SHUFFLE( 3, 3, 3, 3 ) ) );
|
||||
}
|
||||
|
||||
|
||||
// FT20D12 valnew = 0;
|
||||
// //float value = 0.0f;
|
||||
// while ( dest < dest_end )
|
||||
// {
|
||||
// valnew += *source++;
|
||||
|
||||
// // printf("%d\n", *source);
|
||||
|
||||
// if(valnew > 0){
|
||||
// int nnew = valnew >>4;
|
||||
|
||||
// if(nnew>255)nnew=255;
|
||||
// *dest = (unsigned char)nnew;
|
||||
// }else{
|
||||
// *dest = 0;
|
||||
// }
|
||||
// dest++;
|
||||
// }
|
||||
|
||||
free(worker->m_a);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int
|
||||
dense_raster_render( FT_Raster raster, const FT_Raster_Params* params )
|
||||
{
|
||||
const FT_Outline* outline = (const FT_Outline*)params->source;
|
||||
FT_Bitmap* target_map = params->target;
|
||||
|
||||
// dense_worker* worker = malloc( sizeof( dense_worker ) );
|
||||
dense_worker worker[1];
|
||||
|
||||
if ( !raster )
|
||||
return FT_THROW( Invalid_Argument );
|
||||
|
||||
if ( !outline )
|
||||
return FT_THROW( Invalid_Outline );
|
||||
|
||||
worker->outline = *outline;
|
||||
|
||||
if ( !target_map )
|
||||
return FT_THROW( Invalid_Argument );
|
||||
|
||||
/* nothing to do */
|
||||
if ( !target_map->width || !target_map->rows )
|
||||
return 0;
|
||||
|
||||
if ( !target_map->buffer )
|
||||
return FT_THROW( Invalid_Argument );
|
||||
|
||||
worker->m_origin_x = 0;
|
||||
worker->m_origin_y = 0;
|
||||
worker->m_w = target_map->pitch;
|
||||
worker->m_h = target_map->rows;
|
||||
|
||||
int size = worker->m_w * worker->m_h + 4;
|
||||
|
||||
worker->m_a = malloc( sizeof( FT20D12 ) * size );
|
||||
worker->m_a_size = size;
|
||||
|
||||
memset( worker->m_a, 0, ( sizeof( FT20D12 ) * size ) );
|
||||
/* exit if nothing to do */
|
||||
if ( worker->m_w <= worker->m_origin_x || worker->m_h <= worker->m_origin_y )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Invert the pitch to account for different +ve y-axis direction in dense array
|
||||
// (maybe temporary solution)
|
||||
target_map->pitch *= -1;
|
||||
return dense_render_glyph( worker, target_map );
|
||||
}
|
||||
|
||||
FT_DEFINE_RASTER_FUNCS(
|
||||
ft_dense_raster,
|
||||
|
||||
FT_GLYPH_FORMAT_OUTLINE,
|
||||
|
||||
(FT_Raster_New_Func)dense_raster_new, /* raster_new */
|
||||
(FT_Raster_Reset_Func)dense_raster_reset, /* raster_reset */
|
||||
(FT_Raster_Set_Mode_Func)dense_raster_set_mode, /* raster_set_mode */
|
||||
(FT_Raster_Render_Func)dense_raster_render, /* raster_render */
|
||||
(FT_Raster_Done_Func)dense_raster_done /* raster_done */
|
||||
)
|
||||
|
||||
/* END */
|
84
src/dense/ftdense.h
Normal file
84
src/dense/ftdense.h
Normal file
@ -0,0 +1,84 @@
|
||||
|
||||
#ifndef FTDENSE_H_
|
||||
#define FTDENSE_H_
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_CONFIG_CONFIG_H
|
||||
#include <freetype/ftimage.h>
|
||||
|
||||
FT_BEGIN_HEADER
|
||||
|
||||
#ifndef FT_EXPORT_VAR
|
||||
#define FT_EXPORT_VAR( x ) extern x
|
||||
#endif
|
||||
FT_EXPORT_VAR( const FT_Raster_Funcs ) ft_dense_raster;
|
||||
|
||||
/**
|
||||
RASTER_FP
|
||||
|
||||
A floating-point anti-aliasing renderer.
|
||||
Graham Asher, August 2016.
|
||||
|
||||
Most of this code is derived from Raph Levien's font-rs code in the Rust
|
||||
language, which is licensed under the Apache License, version 2.0.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef signed long TPos;
|
||||
typedef signed long FT26D6;
|
||||
typedef signed int FT20D12;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/** The array used to store signed area differences. */
|
||||
FT20D12* m_a;
|
||||
/** The number of elements in m_a. */
|
||||
int m_a_size;
|
||||
/** The width of the current raster in pixels. */
|
||||
int m_w;
|
||||
/** The height of the current raster in pixels. */
|
||||
int m_h;
|
||||
/** The x origin of the raster. */
|
||||
int m_origin_x;
|
||||
/** The y origin of the raster. */
|
||||
int m_origin_y;
|
||||
|
||||
FT_Pos prev_x, prev_y;
|
||||
|
||||
FT_Outline outline;
|
||||
} dense_worker;
|
||||
|
||||
void dense_render_line( dense_worker* aRasterFP, TPos to_x, TPos to_y );
|
||||
void dense_render_quadratic( dense_worker* aRasterFP,
|
||||
const FT_Vector* control,
|
||||
const FT_Vector* to );
|
||||
void dense_render_cubic( dense_worker* aRasterFP,
|
||||
FT_Vector* aP1,
|
||||
FT_Vector* aP2,
|
||||
FT_Vector* aP3 );
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
FT_END_HEADER
|
||||
|
||||
#endif /* FTDENSE_H_ */
|
||||
|
||||
/* END */
|
17
src/dense/ftdenseerrs.h
Normal file
17
src/dense/ftdenseerrs.h
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
#ifndef FTDENSEERRS_H_
|
||||
#define FTDENSEERRS_H_
|
||||
|
||||
#include <freetype/ftmoderr.h>
|
||||
|
||||
#undef FTERRORS_H_
|
||||
|
||||
#undef FT_ERR_PREFIX
|
||||
#define FT_ERR_PREFIX Dense_Err_
|
||||
#define FT_ERR_BASE FT_Mod_Err_Dense
|
||||
|
||||
#include <freetype/fterrors.h>
|
||||
|
||||
#endif /* FTDENSEERRS_H_ */
|
||||
|
||||
/* END */
|
237
src/dense/ftdenserend.c
Normal file
237
src/dense/ftdenserend.c
Normal file
@ -0,0 +1,237 @@
|
||||
/** The 'dense' renderer */
|
||||
|
||||
#include "ftdenserend.h"
|
||||
#include <freetype/ftbitmap.h>
|
||||
#include <freetype/ftoutln.h>
|
||||
#include <freetype/internal/ftdebug.h>
|
||||
#include <freetype/internal/ftobjs.h>
|
||||
#include <freetype/internal/services/svprop.h>
|
||||
#include "ftdense.h"
|
||||
|
||||
#include "ftdenseerrs.h"
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* The macro FT_COMPONENT is used in trace mode. It is an implicit
|
||||
* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
|
||||
* messages during execution.
|
||||
*/
|
||||
#undef FT_COMPONENT
|
||||
#define FT_COMPONENT dense
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* interface functions
|
||||
*
|
||||
*/
|
||||
|
||||
/* @QUES: So, I think this is used for setting up the
|
||||
initial properties of the renderer ??? */
|
||||
static FT_Error
|
||||
ft_dense_init( FT_Renderer render )
|
||||
{
|
||||
return FT_Err_Ok;
|
||||
}
|
||||
|
||||
/* @QUES: A destructor probably. The smooth renderer doesn't have this
|
||||
so, I guess this is unnecessary ??? */
|
||||
static void
|
||||
ft_dense_done( FT_Renderer render )
|
||||
{
|
||||
FT_UNUSED( render );
|
||||
}
|
||||
|
||||
/* generate bitmap from a glyph's slot image */
|
||||
|
||||
/* @QUES: This method allocates the bitmap buffer, shifts the outlines
|
||||
as required (Why exactly is shifting required?), and finally calls
|
||||
raster_render interface methods with correct params */
|
||||
static FT_Error
|
||||
ft_dense_render( FT_Renderer render,
|
||||
FT_GlyphSlot slot,
|
||||
FT_Render_Mode mode,
|
||||
const FT_Vector* origin )
|
||||
{
|
||||
// printf("ft_dense_render\n");
|
||||
FT_Error error = FT_Err_Ok;
|
||||
FT_Outline* outline = &slot->outline;
|
||||
FT_Bitmap* bitmap = &slot->bitmap;
|
||||
|
||||
/* @QUES: You know, it should be a bit more clear that FT_FREE and FT_ALLOC_MULT macros
|
||||
take a variable named `memory`. It can only be known if you follow the macros 3 level deep.*/
|
||||
FT_Memory memory = render->root.memory;
|
||||
|
||||
FT_Pos x_shift = 0;
|
||||
FT_Pos y_shift = 0;
|
||||
|
||||
FT_Raster_Params params;
|
||||
|
||||
/* check whether slot format is correct before rendering */
|
||||
if ( slot->format != render->glyph_format )
|
||||
{
|
||||
error = FT_THROW( Invalid_Glyph_Format );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
/* check mode */
|
||||
if ( mode != FT_RENDER_MODE_NORMAL &&
|
||||
mode != FT_RENDER_MODE_LIGHT &&
|
||||
mode != FT_RENDER_MODE_LCD &&
|
||||
mode != FT_RENDER_MODE_LCD_V )
|
||||
{
|
||||
error = FT_THROW( Cannot_Render_Glyph );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
/* deallocate the previously allocated bitmap */
|
||||
if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
|
||||
{
|
||||
FT_FREE( bitmap->buffer );
|
||||
slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
|
||||
}
|
||||
|
||||
/* preset the bitmap using the glyph's outline; */
|
||||
if ( ft_glyphslot_preset_bitmap( slot, mode, origin ) )
|
||||
{
|
||||
error = FT_THROW( Raster_Overflow );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if ( !bitmap->rows || !bitmap->pitch )
|
||||
goto Exit;
|
||||
|
||||
|
||||
/* allocate new one */
|
||||
if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) )
|
||||
goto Exit;
|
||||
|
||||
/* @QUES: What does this flag mean ?*/
|
||||
slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
|
||||
|
||||
/* @QUES: Where can I read more about why x and y shift are required */
|
||||
x_shift = 64 * -slot->bitmap_left;
|
||||
y_shift = 64 * -slot->bitmap_top;
|
||||
|
||||
if ( bitmap->pixel_mode == FT_PIXEL_MODE_LCD_V )
|
||||
y_shift += 64 * (FT_Int)bitmap->rows / 3;
|
||||
else
|
||||
y_shift += 64 * (FT_Int)bitmap->rows;
|
||||
|
||||
|
||||
if ( origin )
|
||||
{
|
||||
x_shift += origin->x;
|
||||
y_shift += origin->y;
|
||||
}
|
||||
|
||||
/* translate outline to render it into the bitmap */
|
||||
if ( x_shift || y_shift )
|
||||
FT_Outline_Translate( outline, x_shift, y_shift );
|
||||
|
||||
/* set up parameters */
|
||||
params.target = bitmap;
|
||||
params.source = outline;
|
||||
|
||||
/* @QUES: Why is my final bitmap upside down ??🤔*/
|
||||
|
||||
/* render the outline */
|
||||
error =
|
||||
render->raster_render( render->raster, (const FT_Raster_Params*)¶ms );
|
||||
|
||||
Exit:
|
||||
if ( !error )
|
||||
{
|
||||
/* the glyph is successfully rendered to a bitmap */
|
||||
slot->format = FT_GLYPH_FORMAT_BITMAP;
|
||||
}
|
||||
else if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
|
||||
{
|
||||
FT_FREE( bitmap->buffer );
|
||||
slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
|
||||
}
|
||||
|
||||
if ( x_shift || y_shift )
|
||||
FT_Outline_Translate( outline, -x_shift, -y_shift );
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/* transform the glyph using matrix and/or delta */
|
||||
/* @QUES: This mthod isn't called, atleast in normal ftlint execution.
|
||||
What is it for ?*/
|
||||
static FT_Error
|
||||
ft_dense_transform( FT_Renderer render,
|
||||
FT_GlyphSlot slot,
|
||||
const FT_Matrix* matrix,
|
||||
const FT_Vector* delta )
|
||||
{
|
||||
|
||||
FT_Error error = FT_Err_Ok;
|
||||
|
||||
if ( slot->format != render->glyph_format )
|
||||
{
|
||||
error = FT_THROW( Invalid_Argument );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if ( matrix )
|
||||
FT_Outline_Transform( &slot->outline, matrix );
|
||||
|
||||
if ( delta )
|
||||
FT_Outline_Translate( &slot->outline, delta->x, delta->y );
|
||||
|
||||
Exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
/* return the control box of a glyph's outline */
|
||||
/* @QUES: This method isn't called either in normal ftlint execution*/
|
||||
static void
|
||||
ft_dense_get_cbox( FT_Renderer render, FT_GlyphSlot slot, FT_BBox* cbox )
|
||||
{
|
||||
|
||||
FT_ZERO( cbox );
|
||||
|
||||
if ( slot->format == render->glyph_format )
|
||||
FT_Outline_Get_CBox( &slot->outline, cbox );
|
||||
}
|
||||
|
||||
/* set render specific modes or attributes */
|
||||
/* @QUES: Isn't called in normal ftlint execution*/
|
||||
static FT_Error
|
||||
ft_dense_set_mode( FT_Renderer render, FT_ULong mode_tag, FT_Pointer data )
|
||||
{
|
||||
/* pass it to the rasterizer */
|
||||
return render->clazz->raster_class->raster_set_mode( render->raster, mode_tag,
|
||||
data );
|
||||
}
|
||||
|
||||
FT_DEFINE_RENDERER(
|
||||
ft_dense_renderer_class,
|
||||
|
||||
FT_MODULE_RENDERER,
|
||||
sizeof( FT_RendererRec ),
|
||||
|
||||
"dense",
|
||||
0x10000L,
|
||||
0x20000L,
|
||||
|
||||
NULL,
|
||||
|
||||
(FT_Module_Constructor)ft_dense_init,
|
||||
(FT_Module_Destructor)ft_dense_done,
|
||||
(FT_Module_Requester)NULL,
|
||||
|
||||
FT_GLYPH_FORMAT_OUTLINE,
|
||||
|
||||
(FT_Renderer_RenderFunc)ft_dense_render, /* render_glyph */
|
||||
(FT_Renderer_TransformFunc)ft_dense_transform, /* transform_glyph */
|
||||
(FT_Renderer_GetCBoxFunc)ft_dense_get_cbox, /* get_glyph_cbox */
|
||||
(FT_Renderer_SetModeFunc)ft_dense_set_mode, /* set_mode */
|
||||
|
||||
(FT_Raster_Funcs*)&ft_dense_raster /* raster_class */
|
||||
)
|
||||
|
||||
/* END */
|
27
src/dense/ftdenserend.h
Normal file
27
src/dense/ftdenserend.h
Normal file
@ -0,0 +1,27 @@
|
||||
|
||||
#ifndef FTDENSEREND_H_
|
||||
#define FTDENSEREND_H_
|
||||
|
||||
|
||||
#include <freetype/ftmodapi.h>
|
||||
#include <freetype/ftrender.h>
|
||||
#include <freetype/internal/ftobjs.h>
|
||||
|
||||
FT_BEGIN_HEADER
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* @renderer:
|
||||
* ft_dense_renderer_class
|
||||
*
|
||||
* @description:
|
||||
* Renderer to convert @FT_Outline to bitmaps.
|
||||
*
|
||||
*/
|
||||
FT_DECLARE_RENDERER( ft_dense_renderer_class )
|
||||
|
||||
FT_END_HEADER
|
||||
|
||||
#endif /* FTDENSEREND_H_ */
|
||||
|
||||
/* END */
|
23
src/dense/module.mk
Normal file
23
src/dense/module.mk
Normal file
@ -0,0 +1,23 @@
|
||||
#
|
||||
# FreeType 2 smooth renderer module definition
|
||||
#
|
||||
|
||||
|
||||
# Copyright (C) 1996-2021 by
|
||||
# David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
#
|
||||
# This file is part of the FreeType project, and may only be used, modified,
|
||||
# and distributed under the terms of the FreeType project license,
|
||||
# LICENSE.TXT. By continuing to use, modify, or distribute this file you
|
||||
# indicate that you have read the license and understand and accept it
|
||||
# fully.
|
||||
|
||||
|
||||
FTMODULE_H_COMMANDS += DENSE_RENDERER
|
||||
|
||||
define DENSE_RENDERER
|
||||
$(OPEN_DRIVER) FT_Renderer_Class, ft_dense_renderer_class $(CLOSE_DRIVER)
|
||||
$(ECHO_DRIVER)dense $(ECHO_DRIVER_DESC)anti-aliased dense renderer$(ECHO_DRIVER_DONE)
|
||||
endef
|
||||
|
||||
# EOF
|
74
src/dense/rules.mk
Normal file
74
src/dense/rules.mk
Normal file
@ -0,0 +1,74 @@
|
||||
#
|
||||
# FreeType 2 DENSE renderer module build rules
|
||||
#
|
||||
|
||||
|
||||
# Copyright (C) 1996-2021 by
|
||||
# David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
#
|
||||
# This file is part of the FreeType project, and may only be used, modified,
|
||||
# and distributed under the terms of the FreeType project license,
|
||||
# LICENSE.TXT. By continuing to use, modify, or distribute this file you
|
||||
# indicate that you have read the license and understand and accept it
|
||||
# fully.
|
||||
|
||||
|
||||
# DENSE driver directory
|
||||
#
|
||||
DENSE_DIR := $(SRC_DIR)/dense
|
||||
|
||||
|
||||
# compilation flags for the driver
|
||||
#
|
||||
DENSE_COMPILE := $(CC) $(ANSIFLAGS) \
|
||||
$I$(subst /,$(COMPILER_SEP),$(DENSE_DIR)) \
|
||||
$(INCLUDE_FLAGS) \
|
||||
$(FT_CFLAGS) \
|
||||
"-msse4.1"
|
||||
|
||||
|
||||
# DENSE driver sources (i.e., C files)
|
||||
#
|
||||
DENSE_DRV_SRC := $(DENSE_DIR)/ftdense.c \
|
||||
$(DENSE_DIR)/ftdenserend.c
|
||||
|
||||
|
||||
# DENSE driver headers
|
||||
#
|
||||
DENSE_DRV_H := $(DENSE_DRV_SRC:%c=%h) \
|
||||
$(DENSE_DIR)/ftdenseerrs.h
|
||||
|
||||
|
||||
# DENSE driver object(s)
|
||||
#
|
||||
# DENSE_DRV_OBJ_M is used during `multi' builds.
|
||||
# DENSE_DRV_OBJ_S is used during `single' builds.
|
||||
#
|
||||
DENSE_DRV_OBJ_M := $(DENSE_DRV_SRC:$(DENSE_DIR)/%.c=$(OBJ_DIR)/%.$O)
|
||||
DENSE_DRV_OBJ_S := $(OBJ_DIR)/dense.$O
|
||||
|
||||
# DENSE driver source file for single build
|
||||
#
|
||||
DENSE_DRV_SRC_S := $(DENSE_DIR)/dense.c
|
||||
|
||||
|
||||
# DENSE driver - single object
|
||||
#
|
||||
$(DENSE_DRV_OBJ_S): $(DENSE_DRV_SRC_S) $(DENSE_DRV_SRC) \
|
||||
$(FREETYPE_H) $(DENSE_DRV_H)
|
||||
$(DENSE_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(DENSE_DRV_SRC_S))
|
||||
|
||||
|
||||
# DENSE driver - multiple objects
|
||||
#
|
||||
$(OBJ_DIR)/%.$O: $(DENSE_DIR)/%.c $(FREETYPE_H) $(DENSE_DRV_H)
|
||||
$(DENSE_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<)
|
||||
|
||||
|
||||
# update main driver object lists
|
||||
#
|
||||
DRV_OBJS_S += $(DENSE_DRV_OBJ_S)
|
||||
DRV_OBJS_M += $(DENSE_DRV_OBJ_M)
|
||||
|
||||
|
||||
# EOF
|
Loading…
Reference in New Issue
Block a user