Compare commits

...

32 Commits

Author SHA1 Message Date
Anurag Thakur
08e08f5908 Fix monochrome crash 2022-10-19 02:18:04 +05:30
Anurag Thakur
108e5e3e34 Optimize Division 2022-10-19 01:50:43 +05:30
Anurag Thakur
467ba66539 Add fontdue optimization 2022-10-19 00:51:07 +05:30
Anurag Thakur
17d14a6cef SIMD with Fixed-Point 2022-10-17 01:58:17 +05:30
Anurag Thakur
bd9aba933b Add comments to raster algorithm and cleanup 2022-10-11 04:47:58 +05:30
Anurag Thakur
d257405687 Fixed point working now 2022-10-09 18:20:49 +05:30
Anurag Thakur
9538d8e798 Fixed first pass 2022-10-06 03:06:00 +05:30
Anurag Thakur
c03591c48a lkw 2022-10-06 01:55:06 +05:30
Anurag Thakur
0b682c5417 Add SIMD 2022-10-04 03:16:11 +05:30
Anurag Thakur
3d0e33d2aa Almost fix rendering 2022-10-04 03:16:11 +05:30
Anurag Thakur
f6bd130ba3 Remove redundant code 2022-10-04 03:16:11 +05:30
Anurag Thakur
5424f47eb9 Invert bitmap pitch 2022-10-04 03:16:11 +05:30
Anurag Thakur
2fc3e384ed Free memory after use 2022-10-04 03:16:11 +05:30
Anurag Thakur
1cf8e2ed5d Fix antialiasing 2022-10-04 03:16:11 +05:30
Anurag Thakur
edd9a84c36 Rebase and cleanup 2022-10-04 03:16:11 +05:30
Anurag Thakur
6f86728eb3 Insert newline at end 2022-10-04 03:16:11 +05:30
Anurag Thakur
94183cf0b6 Revert unrelated changes 2022-10-04 03:16:11 +05:30
Anurag Thakur
9aafe98c1d Use inbuilt data-types 2022-10-04 03:16:11 +05:30
Anurag Thakur
d9c301d35a Fix quadratic rendering 2022-10-04 03:16:11 +05:30
Anurag Thakur
8af62c3469 Partially move parameters to existing types 2022-10-04 03:16:11 +05:30
Anurag Thakur
8687c459c0 Temp fix for upside-down bitmap 2022-10-04 03:16:11 +05:30
Anurag Thakur
39bcb3a647 Logging for testing 2022-10-04 03:16:11 +05:30
Anurag Thakur
bb95b4423e Added commentary 2022-10-04 03:16:11 +05:30
Anurag Thakur
dbf9623ab4 Added cmake build 2022-10-04 03:16:11 +05:30
Anurag Thakur
e122ecf1e5 Remove printfs 2022-10-04 03:16:11 +05:30
Anurag Thakur
1e0918c41c Integration prototype successful 2022-10-04 03:16:11 +05:30
Anurag Thakur
05c8790008 Trying to get it to work attempt #1 2022-10-04 03:16:11 +05:30
Anurag Thakur
dee8855a9c Compilation fix attempt #1 2022-10-04 03:16:11 +05:30
Anurag Thakur
9b40ce9cbc Finish importing code, integration pending 2022-10-04 03:16:11 +05:30
Anurag Thakur
63dd924394 Added things 2022-10-04 03:16:11 +05:30
Anurag Thakur
f6a2237ff6 Populate errors header for 'dense' renderer 2022-10-04 03:16:11 +05:30
Anurag Thakur
7511d64e60 Add files for new 'dense' module 2022-10-04 03:16:11 +05:30
13 changed files with 1096 additions and 0 deletions

2
.gitignore vendored
View File

@ -5,3 +5,5 @@ src/dlg/dlg.c
subprojects/*
!subprojects/*.wrap
/tests/data/*
.cache/*
compile_commands.json

8
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,8 @@
{
"files.associations": {
"ftoutln.h": "c",
"svprop.h": "c",
"ftdebug.h": "c",
"tmmintrin.h": "c"
}
}

View File

@ -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

View File

@ -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 )

View File

@ -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
View 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
View 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
View 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
View 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
View 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*)&params );
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
View 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
View 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
View 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