Compare commits

...

13 Commits

Author SHA1 Message Date
Anurag Thakur 7d097d692c Partially move parameters to existing types 2022-07-13 01:06:15 +05:30
Anurag Thakur 7996f488e5 Temp fix for upside-down bitmap 2022-07-12 18:31:20 +05:30
Anurag Thakur 171a542175 Logging for testing 2022-07-12 17:19:37 +05:30
Anurag Thakur b66a91728b Added commentary 2022-07-12 16:38:40 +05:30
Anurag Thakur 9fd24008ae Added cmake build 2022-07-12 16:38:40 +05:30
Anurag Thakur dffb269d06 Remove printfs 2022-07-12 16:38:40 +05:30
Anurag Thakur 44892f8212 Integration prototype successful 2022-07-12 16:38:40 +05:30
Anurag Thakur 43a66f774c Trying to get it to work attempt #1 2022-07-12 16:38:40 +05:30
Anurag Thakur e66db7ec5c Compilation fix attempt #1 2022-07-12 16:38:38 +05:30
Anurag Thakur d019c05e9f Finish importing code, integration pending 2022-07-12 16:37:51 +05:30
Anurag Thakur 12ffde24a1 Added things 2022-07-12 16:37:01 +05:30
Anurag Thakur e68cdd5f9e Populate errors header for 'dense' renderer 2022-07-12 16:37:01 +05:30
Anurag Thakur a4cf05ea5c Add files for new 'dense' module 2022-07-12 16:37:01 +05:30
16 changed files with 1115 additions and 4 deletions

2
.gitignore vendored
View File

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

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

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

View File

@ -395,6 +395,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

@ -4,8 +4,13 @@
/* */
/* Amiga-specific FreeType module selection. */
/* */
<<<<<<< HEAD
/* Copyright (C) 2005-2022 by */
/* Werner Lemberg and Detlef Würkner. */
=======
/* Copyright (C) 2005-2021 by */
/* Werner Lemberg and Detlef W<>rkner. */
>>>>>>> d9fdb2202 (Compilation fix attempt #1)
/* */
/* This file is part of the FreeType project, and may only be used, */
/* modified, and distributed under the terms of the FreeType project */
@ -135,6 +140,10 @@ FT_USE_MODULE( FT_Renderer_Class, ft_raster1_renderer_class )
FT_USE_MODULE( FT_Module_Class, sfnt_module_class )
#endif
#ifdef FT_USE_DENSE
FT_USE_MODULE( FT_Renderer_Class, ft_dense_renderer_class )
#endif
#ifdef FT_USE_SMOOTH
FT_USE_MODULE( FT_Renderer_Class, ft_smooth_renderer_class )
#endif

View File

@ -75,9 +75,9 @@
#undef OS_INLINE
#define OS_INLINE static __inline__
#endif
#include <CoreServices/CoreServices.h>
#include <ApplicationServices/ApplicationServices.h>
#include <sys/syslimits.h> /* PATH_MAX */
// #include <CoreServices/CoreServices.h>
// #include <ApplicationServices/ApplicationServices.h>
// #include <sys/syslimits.h> /* PATH_MAX */
#else
#include <Resources.h>
#include <Fonts.h>

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 */

574
src/dense/ftdense.c Normal file
View File

@ -0,0 +1,574 @@
/** The rasterizer for the 'dense' renderer */
#include <stdio.h>
#undef FT_COMPONENT
#define FT_COMPONENT dense
#include "ftdense.h"
#include <freetype/ftoutln.h>
#include <freetype/internal/ftcalc.h>
#include <freetype/internal/ftdebug.h>
#include <freetype/internal/ftobjs.h>
#include <math.h>
#include "ftdenseerrs.h"
/* @QUES: Please explain all these defines. Why is PIXEL_BITS 8??*/
#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 ) )
typedef struct dense_TRaster_
{
void* memory;
} dense_TRaster, *dense_PRaster;
static RasterFP_Point
Lerp( float aT, RasterFP_Point aP0, RasterFP_Point aP1 )
{
RasterFP_Point p;
p.m_x = aP0.m_x + aT * ( aP1.m_x - aP0.m_x );
p.m_y = aP0.m_y + aT * ( aP1.m_y - aP0.m_y );
return p;
}
static int
dense_move_to( const FT_Vector* to, RasterFP* aRasterFP )
{
TPos x, y;
x = UPSCALE( to->x );
y = UPSCALE( to->y );
aRasterFP->prev_x = x;
aRasterFP->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, RasterFP* aRasterFP )
{
printf("dense_line_to: %d, %d\n", to->x, to->y);
RasterFP_Point tp = {UPSCALE(to->x), UPSCALE(to->y)};
RasterFP_DrawLine( aRasterFP, tp.m_x, tp.m_y );
dense_move_to( to, aRasterFP );
return 0;
}
void swap(long int *a, long int *b){
long int temp = *a;
*a = *b;
*b = temp;
}
void swapold(unsigned char *a, unsigned char *b){
unsigned char temp = *a;
*a = *b;
*b = temp;
}
void
RasterFP_DrawLine( RasterFP* aRasterFP, TPos to_x, TPos to_y )
{
TPos from_x = aRasterFP->prev_x;
TPos from_y = aRasterFP->prev_y;
if ( from_y == to_y )
return;
/* @QUES: What is this code that I commented out, supposed to do?*/
// aP0.m_x -= aRasterFP->m_origin_x;
// aP0.m_y -= aRasterFP->m_origin_y;
// aP1.m_x -= aRasterFP->m_origin_x;
// aP1.m_y -= aRasterFP->m_origin_y;
from_x = TRUNC((int)from_x );
from_y = TRUNC((int)from_y );
to_x = TRUNC((int)to_x );
to_y = TRUNC((int)to_y );
float dir;
if ( from_y < to_y )
dir = 1;
else
{
dir = -1;
swap(&from_x, &to_x);
swap(&from_y, &to_y);
}
// Clip to the height.
if ( from_y >= aRasterFP->m_h || to_y <= 0 )
return;
float dxdy = ( to_x - from_x ) / (float)( to_y - from_y );
if ( from_y < 0 )
{
from_x -= from_y * dxdy;
from_y = 0;
}
if ( to_y > aRasterFP->m_h )
{
to_x -= ( to_y - aRasterFP->m_h ) * dxdy;
to_y = (float)aRasterFP->m_h;
}
/**
Handle parts of the line outside the clip rectangle by
snapping them to the left or right edge, or, if they intersect the clip area,
by recursive calls.
*/
/* @QUES: This code isn't present in font-rs. It was added later by graham asher
I have a very strong feeling that this isn't necessary.
Since probably the outline is already fitted in the bounding box. I tested
this code a little, removing it doesn't seem to make any difference*/
RasterFP_Point intersect = { 0, 0 };
int recursive = 0;
if ( from_x >= aRasterFP->m_w && to_x >= aRasterFP->m_w )
{
from_x = to_x = (float)aRasterFP->m_w;
dxdy = 0;
}
else if ( from_x <= 0 && to_x <= 0 )
{
from_x = to_x = 0;
dxdy = 0;
}
else if ( ( from_x < 0 ) != ( to_x < 0 ) )
{
intersect.m_x = 0;
intersect.m_y = to_y - to_x / dxdy;
recursive = 1;
}
else if ( ( from_x > aRasterFP->m_w ) != ( to_x > aRasterFP->m_w ) )
{
intersect.m_x = (float)aRasterFP->m_w;
intersect.m_y = from_y + ( aRasterFP->m_w - from_x ) / dxdy;
recursive = 1;
}
if ( recursive )
{
from_x += aRasterFP->m_origin_x;
from_y += aRasterFP->m_origin_y;
to_x += aRasterFP->m_origin_x;
to_y += aRasterFP->m_origin_y;
intersect.m_x += aRasterFP->m_origin_x;
intersect.m_y += aRasterFP->m_origin_y;
if ( dir == 1 )
{
RasterFP_DrawLine( aRasterFP, intersect.m_x, intersect.m_y );
RasterFP_DrawLine( aRasterFP, to_x, to_y );
}
else
{
RasterFP_DrawLine( aRasterFP, intersect.m_x, intersect.m_y );
RasterFP_DrawLine( aRasterFP, from_x, from_y );
}
return;
}
/* @QUES: I am still trying to understand this code */
float x = from_x;
int y0 = (int)from_y;
int y_limit = (int)ceil( to_y );
float* m_a = aRasterFP->m_a;
for ( int y = y0; y < y_limit; y++ )
{
int linestart = y * aRasterFP->m_w;
float dy = fmin( y + 1.0f, to_y ) - fmax( (float)y, from_y );
float xnext = x + dxdy * dy;
float d = dy * dir;
float x0, x1;
if ( x < xnext )
{
x0 = x;
x1 = xnext;
}
else
{
x0 = xnext;
x1 = x;
}
/*
It's possible for x0 to be negative on the last scanline because of
floating-point inaccuracy That would cause an out-of-bounds array access at
index -1.
*/
float x0floor = x0 <= 0.0f ? 0.0f : (float)floor( x0 );
int x0i = (int)x0floor;
float x1ceil = (float)ceil( x1 );
int x1i = (int)x1ceil;
if ( x1i <= x0i + 1 )
{
float xmf = 0.5f * ( x + xnext ) - x0floor;
m_a[linestart + x0i] += d - d * xmf;
m_a[linestart + ( x0i + 1 )] += d * xmf;
}
else
{
float s = 1.0f / ( x1 - x0 );
float x0f = x0 - x0floor;
float a0 = 0.5f * s * ( 1.0f - x0f ) * ( 1.0f - x0f );
float x1f = x1 - x1ceil + 1.0f;
float am = 0.5f * s * x1f * x1f;
m_a[linestart + x0i] += d * a0;
if ( x1i == x0i + 2 )
m_a[linestart + ( x0i + 1 )] += d * ( 1.0f - a0 - am );
else
{
float a1 = s * ( 1.5f - x0f );
m_a[linestart + ( x0i + 1 )] += d * ( a1 - a0 );
for ( int xi = x0i + 2; xi < x1i - 1; xi++ )
m_a[linestart + xi] += d * s;
float a2 = a1 + ( x1i - x0i - 3 ) * s;
m_a[linestart + ( x1i - 1 )] += d * ( 1.0f - a2 - am );
}
m_a[linestart + x1i] += d * am;
}
x = xnext;
}
}
static int
dense_conic_to( const FT_Vector* control,
const FT_Vector* to,
RasterFP* aRasterFP )
{
// RasterFP_Point controlP = { UPSCALE(control->x), UPSCALE(control->y) };
// RasterFP_Point toP = { UPSCALE(to->x), UPSCALE(to->y) };
// RasterFP_Point lP = { aRasterFP->prev_x, aRasterFP->prev_y };
RasterFP_DrawQuadratic( aRasterFP, control, to );
return 0;
}
void
RasterFP_DrawQuadratic( RasterFP* aRasterFP,
const FT_Vector* control,
const FT_Vector* to )
{
// assert( aRasterFP );
/*
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.
*/
RasterFP_Point aP0 = {aRasterFP->prev_x, aRasterFP->prev_y};
RasterFP_Point aP1 = {UPSCALE(control->x), UPSCALE(control->y)};
RasterFP_Point aP2 = {UPSCALE(to->x), UPSCALE(to->y)};
float devx = aP0.m_x - aP1.m_x - aP1.m_x + aP2.m_x;
float devy = aP0.m_y - aP1.m_y - aP1.m_y + aP2.m_y;
float devsq = devx * devx + devy * devy;
if ( devsq < 0.333f )
{
RasterFP_DrawLine(aRasterFP, aP2.m_x, aP2.m_y );
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 ) ) );
// RasterFP_Point p = aP0;
float nrecip = 1.0f / ( n + 1.0f );
float t = 0.0f;
for ( int i = 0; i < n; i++ )
{
t += nrecip;
RasterFP_Point next = Lerp( t, Lerp( t, aP0, aP1 ), Lerp( t, aP1, aP2 ) );
RasterFP_DrawLine(aRasterFP , next.m_x, next.m_y);
//p = next;
}
RasterFP_DrawLine( aRasterFP, aP2.m_x, aP2.m_y);
}
static int
dense_cubic_to( const FT_Vector* control1,
const FT_Vector* control2,
const FT_Vector* to,
RasterFP* aRasterFP )
{
RasterFP_Point ap1 = { UPSCALE(control1->x), UPSCALE(control1->y) };
RasterFP_Point ap2 = { UPSCALE(control2->x), UPSCALE(control2->y) };
RasterFP_Point ap3 = { UPSCALE(to->x), UPSCALE(to->y) };
RasterFP_Point lP = {aRasterFP->prev_x, aRasterFP->prev_y};
RasterFP_DrawCubic( aRasterFP, lP, ap1, ap2, ap3 );
return 0;
}
void
RasterFP_DrawCubic( RasterFP* aRasterFP,
RasterFP_Point aP0,
RasterFP_Point aP1,
RasterFP_Point aP2,
RasterFP_Point aP3 )
{
// assert( aRasterFP );
float devx = aP0.m_x - aP1.m_x - aP1.m_x + aP2.m_x;
float devy = aP0.m_y - aP1.m_y - aP1.m_y + aP2.m_y;
float devsq0 = devx * devx + devy * devy;
devx = aP1.m_x - aP2.m_x - aP2.m_x + aP3.m_x;
devy = aP1.m_y - aP2.m_y - aP2.m_y + aP3.m_y;
float devsq1 = devx * devx + devy * devy;
float devsq = fmax( devsq0, devsq1 );
if ( devsq < 0.333f )
{
RasterFP_DrawLine( aRasterFP, aP3.m_x , aP3.m_y);
return;
}
const float tol = 3.0f;
int n = (int)floor( sqrt( sqrt( tol * devsq ) ) );
RasterFP_Point p = aP0;
float nrecip = 1.0f / ( n + 1.0f );
float t = 0.0f;
for ( int i = 0; i < n; i++ )
{
t += nrecip;
RasterFP_Point a = Lerp( t, Lerp( t, aP0, aP1 ), Lerp( t, aP1, aP2 ) );
RasterFP_Point b = Lerp( t, Lerp( t, aP1, aP2 ), Lerp( t, aP2, aP3 ) );
RasterFP_Point next = Lerp( t, a, b );
RasterFP_DrawLine( aRasterFP, next.m_x, next.m_y );
p = next;
}
RasterFP_DrawLine( aRasterFP, aP3.m_x, aP3.m_y );
}
/* @QUES: This is the first method called on the module. I suspect
this only initializes the memory for it*/
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;
printf("dense_raster_new\n");
return error;
}
/* @QUES: This is a simple method, only frees memory*/
static void
dense_raster_done( FT_Raster raster )
{
printf( "dense_raster_done\n" );
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 );
printf("dense_raster_reset\n");
}
/* @QUES: This methodisnt't called in normal ftlint execution*/
static int
dense_raster_set_mode( FT_Raster raster, unsigned long mode, void* args )
{
FT_UNUSED( raster );
FT_UNUSED( mode );
FT_UNUSED( args );
printf("dense_raster_set_mode\n");
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 */
)
/* @QUES: So, this calls FT_Outline_Decompose, that calls the move to,
line to, conic to, cubic to interface methods. The aRasterFP structure stores the
well, stuff in its m_a and finally renders it to the target->buffer*/
static int
dense_render_glyph( RasterFP* aRasterFP, const FT_Bitmap* target )
{
FT_Error error = FT_Outline_Decompose( &( aRasterFP->outline ),
&dense_decompose_funcs, aRasterFP );
// Render into bitmap
const float* source = aRasterFP->m_a;
//printf( "Outputting bitmap\n" );
// for ( int i = 0; i < aRasterFP->m_h; i++ )
// {
// printf( "\n" );
// for ( int j = 0; j < aRasterFP->m_w; j++ )
// {
// float strength = *( source + ( i * aRasterFP->m_w + j ) );
// if ( strength > 0.90 )
// {
// printf( "@|" );
// }
// else if ( strength > 0.70 )
// {
// printf( "#|" );
// }
// else if ( strength > 0.45 )
// {
// printf( "+|" );
// }
// else if ( strength > 0.20 )
// {
// printf( "*|" );
// }
// else
// {
// printf( ".|" );
// }
// }
// }
// printf( "\n" );
unsigned char* dest = target->buffer;
unsigned char* dest_end = target->buffer + aRasterFP->m_w * aRasterFP->m_h;
float value = 0.0f;
while ( dest < dest_end )
{
value += *source++;
if ( value > 0.0f )
{
int n = (int)( fabs( value ) * 255.0f + 0.5f );
if ( n > 255 )
n = 255;
*dest = (unsigned char)n;
}
else
*dest = 0;
dest++;
}
for (int col = 0; col < aRasterFP->m_w; col++)
{
for (int row = 0; row < aRasterFP->m_h/2; row++)
{
//printf("Swapping position: %d, %d with %d, %d with rows = %d, cols = %d",row,col, aRasterFP->m_h-row, col, aRasterFP->m_h, aRasterFP->m_w);
swapold(target->buffer + aRasterFP->m_w*row + col, target->buffer + (aRasterFP->m_h-row-1)*aRasterFP->m_w + col);
}
}
return error;
}
/* @QUES: The main rasterizing method, params.->target->buffer gets the
rendered pixels*/
static int
dense_raster_render( FT_Raster raster, const FT_Raster_Params* params )
{
printf( "dense_raster_render\n" );
const FT_Outline* outline = (const FT_Outline*)params->source;
const FT_Bitmap* target_map = params->target;
RasterFP* aRasterFP = malloc( sizeof( RasterFP ) );
if ( !raster )
return FT_THROW( Invalid_Argument );
if ( !outline )
return FT_THROW( Invalid_Outline );
aRasterFP->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 );
aRasterFP->m_origin_x = 0;
aRasterFP->m_origin_y = 0;
/* @QUES: Why are my bitmaps upsied down 😭*/
aRasterFP->m_w = target_map->pitch;
aRasterFP->m_h = target_map->rows;
int size = aRasterFP->m_w * aRasterFP->m_h + 4;
aRasterFP->m_a = malloc( sizeof( float ) * size );
aRasterFP->m_a_size = size;
memset( aRasterFP->m_a, 0, ( sizeof( float ) * size ) );
/* exit if nothing to do */
if ( aRasterFP->m_w <= aRasterFP->m_origin_x ||
aRasterFP->m_h <= aRasterFP->m_origin_y )
{
return 0;
}
return dense_render_glyph( aRasterFP, 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 */

137
src/dense/ftdense.h Normal file
View File

@ -0,0 +1,137 @@
#ifndef FTDENSE_H_
#define FTDENSE_H_
#include <ft2build.h>
#include FT_CONFIG_CONFIG_H
#include <freetype/ftimage.h>
FT_BEGIN_HEADER
/**************************************************************************
*
* @struct:
* SDF_Raster_Params
*
* @description:
* This struct must be passed to the raster render function
* @FT_Raster_RenderFunc instead of @FT_Raster_Params because the
* rasterizer requires some additional information to render properly.
*
* @fields:
* root ::
* The native raster parameters structure.
*
* spread ::
* This is an essential parameter/property required by the renderer.
* `spread` defines the maximum unsigned value that is present in the
* final SDF output. For the default value check file
* `ftsdfcommon.h`.
*
* flip_sign ::
* By default positive values indicate positions inside of contours,
* i.e., filled by a contour. If this property is true then that
* output will be the opposite of the default, i.e., negative values
* indicate positions inside of contours.
*
* flip_y ::
* Setting this parameter to true maked the output image flipped
* along the y-axis.
*
* overlaps ::
* Set this to true to generate SDF for glyphs having overlapping
* contours. The overlapping support is limited to glyphs that do not
* have self-intersecting contours. Also, removing overlaps require a
* considerable amount of extra memory; additionally, it will not work
* if generating SDF from bitmap.
*
* @note:
* All properties are valid for both the 'sdf' and 'bsdf' renderers; the
* exception is `overlaps`, which gets ignored by the 'bsdf' renderer.
*
*/
/* rasterizer to convert outline to SDF */
#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 long TPos;
typedef struct
{
float m_x;
float m_y;
} RasterFP_Point;
typedef struct
{
/** The array used to store signed area differences. */
float* 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;
} RasterFP;
void RasterFP_Create( RasterFP* aRasterFP );
void RasterFP_Destroy( RasterFP* aRasterFP );
void RasterFP_DrawLine( RasterFP* aRasterFP, TPos to_x, TPos to_y );
void RasterFP_DrawQuadratic( RasterFP* aRasterFP,
const FT_Vector* control,
const FT_Vector* to );
void RasterFP_DrawCubic( RasterFP* aRasterFP,
RasterFP_Point aP0,
RasterFP_Point aP1,
RasterFP_Point aP2,
RasterFP_Point aP3 );
void RasterFP_GetBitmap( RasterFP* aRasterFP, unsigned char* aBitmap );
#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 */

227
src/dense/ftdenserend.c Normal file
View File

@ -0,0 +1,227 @@
/** 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 )
{
printf( "ft_dense_init\n" );
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 )
{
printf( "ft_dense_done\n" );
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;
}
/* 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: 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;
/* @QUES: What does this flag mean ?*/
slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
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 )
{
printf( "ft_dense_transform\n" );
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 )
{
printf( "ft_dense_get_cbox\n" );
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

73
src/dense/rules.mk Normal file
View File

@ -0,0 +1,73 @@
#
# 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)
# 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

View File

@ -876,10 +876,13 @@ typedef ptrdiff_t FT_PtrDist;
TCoord fx1, fy1, fx2, fy2;
TCoord ex1, ey1, ex2, ey2;
// printf( "Line from {%li, %li} to {%li, %li}, with a maximum dimensions of %d by %d\n", ras.x, ras.y, to_x,
// to_y, ras.max_ex, ras.max_ey );
ey1 = TRUNC( ras.y );
ey2 = TRUNC( to_y );
// printf("Truncation reduced prev y from %ld to %d\n", ras.y, ey1);
/* perform vertical clipping */
if ( ( ey1 >= ras.max_ey && ey2 >= ras.max_ey ) ||
( ey1 < ras.min_ey && ey2 < ras.min_ey ) )
@ -1448,6 +1451,7 @@ typedef ptrdiff_t FT_PtrDist;
gray_line_to( const FT_Vector* to,
gray_PWorker worker )
{
printf("gray_line_to: %d, %d\n", to->x, to->y);
gray_render_line( RAS_VAR_ UPSCALE( to->x ), UPSCALE( to->y ) );
return 0;
}