116#define FT_COMPONENT sdf
134#ifndef USE_NEWTON_FOR_CONIC
135#define USE_NEWTON_FOR_CONIC 1
142#define MAX_NEWTON_DIVISIONS 4
152#define MAX_NEWTON_STEPS 4
159#define CORNER_CHECK_EPSILON 32
176#define MUL_26D6( a, b ) ( ( ( a ) * ( b ) ) / 64 )
177#define VEC_26D6_DOT( p, q ) ( MUL_26D6( p.x, q.x ) + \
178 MUL_26D6( p.y, q.y ) )
207 } SDF_TRaster, *SDF_PRaster;
233 typedef enum SDF_Edge_Type_
235 SDF_EDGE_UNDEFINED = 0,
269 typedef enum SDF_Contour_Orientation_
271 SDF_ORIENTATION_NONE = 0,
272 SDF_ORIENTATION_CW = 1,
273 SDF_ORIENTATION_CCW = 2
275 } SDF_Contour_Orientation;
311 FT_26D6_Vec start_pos;
313 FT_26D6_Vec control_a;
314 FT_26D6_Vec control_b;
316 SDF_Edge_Type edge_type;
347 FT_26D6_Vec last_pos;
375 SDF_Contour* contours;
416 } SDF_Signed_Distance;
451 FT_Orientation orientation;
455 FT_Int overload_sign;
467 const FT_Vector zero_vector = { 0, 0 };
470 const SDF_Edge null_edge = { { 0, 0 }, { 0, 0 },
472 SDF_EDGE_UNDEFINED, NULL };
475 const SDF_Contour null_contour = { { 0, 0 }, NULL, NULL };
478 const SDF_Shape null_shape = { NULL, NULL };
481 const SDF_Signed_Distance max_sdf = { INT_MAX, 0, 0 };
487 sdf_edge_new( FT_Memory memory,
490 FT_Error error = FT_Err_Ok;
491 SDF_Edge* ptr = NULL;
494 if ( !memory || !edge )
496 error = FT_THROW( Invalid_Argument );
500 if ( !FT_QNEW( ptr ) )
513 sdf_edge_done( FT_Memory memory,
516 if ( !memory || !edge || !*edge )
526 sdf_contour_new( FT_Memory memory,
527 SDF_Contour** contour )
529 FT_Error error = FT_Err_Ok;
530 SDF_Contour* ptr = NULL;
533 if ( !memory || !contour )
535 error = FT_THROW( Invalid_Argument );
539 if ( !FT_QNEW( ptr ) )
553 sdf_contour_done( FT_Memory memory,
554 SDF_Contour** contour )
560 if ( !memory || !contour || !*contour )
563 edges = (*contour)->edges;
571 sdf_edge_done( memory, &temp );
581 sdf_shape_new( FT_Memory memory,
584 FT_Error error = FT_Err_Ok;
585 SDF_Shape* ptr = NULL;
588 if ( !memory || !shape )
590 error = FT_THROW( Invalid_Argument );
594 if ( !FT_QNEW( ptr ) )
597 ptr->memory = memory;
609 sdf_shape_done( SDF_Shape** shape )
612 SDF_Contour* contours;
616 if ( !shape || !*shape )
619 memory = (*shape)->memory;
620 contours = (*shape)->contours;
629 contours = contours->next;
631 sdf_contour_done( memory, &temp );
648 sdf_move_to(
const FT_26D6_Vec* to,
651 SDF_Shape* shape = ( SDF_Shape* )user;
652 SDF_Contour* contour = NULL;
654 FT_Error error = FT_Err_Ok;
655 FT_Memory memory = shape->memory;
660 error = FT_THROW( Invalid_Argument );
664 FT_CALL( sdf_contour_new( memory, &contour ) );
666 contour->last_pos = *to;
667 contour->next = shape->contours;
668 shape->contours = contour;
679 sdf_line_to(
const FT_26D6_Vec* to,
682 SDF_Shape* shape = ( SDF_Shape* )user;
683 SDF_Edge* edge = NULL;
684 SDF_Contour* contour = NULL;
686 FT_Error error = FT_Err_Ok;
687 FT_Memory memory = shape->memory;
692 error = FT_THROW( Invalid_Argument );
696 contour = shape->contours;
698 if ( contour->last_pos.x == to->x &&
699 contour->last_pos.y == to->y )
702 FT_CALL( sdf_edge_new( memory, &edge ) );
704 edge->edge_type = SDF_EDGE_LINE;
705 edge->start_pos = contour->last_pos;
708 edge->next = contour->edges;
709 contour->edges = edge;
710 contour->last_pos = *to;
721 sdf_conic_to(
const FT_26D6_Vec* control_1,
722 const FT_26D6_Vec* to,
725 SDF_Shape* shape = ( SDF_Shape* )user;
726 SDF_Edge* edge = NULL;
727 SDF_Contour* contour = NULL;
729 FT_Error error = FT_Err_Ok;
730 FT_Memory memory = shape->memory;
733 if ( !control_1 || !to || !user )
735 error = FT_THROW( Invalid_Argument );
739 contour = shape->contours;
744 if ( ( contour->last_pos.x == control_1->x &&
745 contour->last_pos.y == control_1->y ) ||
746 ( control_1->x == to->x &&
747 control_1->y == to->y ) )
749 sdf_line_to( to, user );
753 FT_CALL( sdf_edge_new( memory, &edge ) );
755 edge->edge_type = SDF_EDGE_CONIC;
756 edge->start_pos = contour->last_pos;
757 edge->control_a = *control_1;
760 edge->next = contour->edges;
761 contour->edges = edge;
762 contour->last_pos = *to;
774 sdf_cubic_to(
const FT_26D6_Vec* control_1,
775 const FT_26D6_Vec* control_2,
776 const FT_26D6_Vec* to,
779 SDF_Shape* shape = ( SDF_Shape* )user;
780 SDF_Edge* edge = NULL;
781 SDF_Contour* contour = NULL;
783 FT_Error error = FT_Err_Ok;
784 FT_Memory memory = shape->memory;
787 if ( !control_2 || !control_1 || !to || !user )
789 error = FT_THROW( Invalid_Argument );
793 contour = shape->contours;
795 FT_CALL( sdf_edge_new( memory, &edge ) );
797 edge->edge_type = SDF_EDGE_CUBIC;
798 edge->start_pos = contour->last_pos;
799 edge->control_a = *control_1;
800 edge->control_b = *control_2;
803 edge->next = contour->edges;
804 contour->edges = edge;
805 contour->last_pos = *to;
814 FT_DEFINE_OUTLINE_FUNCS(
817 (FT_Outline_MoveTo_Func) sdf_move_to,
818 (FT_Outline_LineTo_Func) sdf_line_to,
819 (FT_Outline_ConicTo_Func)sdf_conic_to,
820 (FT_Outline_CubicTo_Func)sdf_cubic_to,
829 sdf_outline_decompose( FT_Outline* outline,
832 FT_Error error = FT_Err_Ok;
835 if ( !outline || !shape )
837 error = FT_THROW( Invalid_Argument );
841 error = FT_Outline_Decompose( outline,
842 &sdf_decompose_funcs,
859 get_control_box( SDF_Edge edge )
861 FT_CBox cbox = { 0, 0, 0, 0 };
865 switch ( edge.edge_type )
868 cbox.xMin = edge.control_b.x;
869 cbox.xMax = edge.control_b.x;
870 cbox.yMin = edge.control_b.y;
871 cbox.yMax = edge.control_b.y;
879 cbox.xMin = edge.control_a.x < cbox.xMin
882 cbox.xMax = edge.control_a.x > cbox.xMax
886 cbox.yMin = edge.control_a.y < cbox.yMin
889 cbox.yMax = edge.control_a.y > cbox.yMax
895 cbox.xMin = edge.control_a.x;
896 cbox.xMax = edge.control_a.x;
897 cbox.yMin = edge.control_a.y;
898 cbox.yMax = edge.control_a.y;
907 cbox.xMin = edge.start_pos.x < cbox.xMin
910 cbox.xMax = edge.start_pos.x > cbox.xMax
914 cbox.yMin = edge.start_pos.y < cbox.yMin
917 cbox.yMax = edge.start_pos.y > cbox.yMax
923 cbox.xMin = edge.start_pos.x;
924 cbox.xMax = edge.start_pos.x;
925 cbox.yMin = edge.start_pos.y;
926 cbox.yMax = edge.start_pos.y;
929 cbox.xMin = edge.end_pos.x < cbox.xMin
932 cbox.xMax = edge.end_pos.x > cbox.xMax
936 cbox.yMin = edge.end_pos.y < cbox.yMin
939 cbox.yMax = edge.end_pos.y > cbox.yMax
957 static SDF_Contour_Orientation
958 get_contour_orientation ( SDF_Contour* contour )
960 SDF_Edge* head = NULL;
965 if ( !contour || !contour->edges )
966 return SDF_ORIENTATION_NONE;
968 head = contour->edges;
973 switch ( head->edge_type )
976 area += MUL_26D6( ( head->end_pos.x - head->start_pos.x ),
977 ( head->end_pos.y + head->start_pos.y ) );
981 area += MUL_26D6( head->control_a.x - head->start_pos.x,
982 head->control_a.y + head->start_pos.y );
983 area += MUL_26D6( head->end_pos.x - head->control_a.x,
984 head->end_pos.y + head->control_a.y );
988 area += MUL_26D6( head->control_a.x - head->start_pos.x,
989 head->control_a.y + head->start_pos.y );
990 area += MUL_26D6( head->control_b.x - head->control_a.x,
991 head->control_b.y + head->control_a.y );
992 area += MUL_26D6( head->end_pos.x - head->control_b.x,
993 head->end_pos.y + head->control_b.y );
997 return SDF_ORIENTATION_NONE;
1006 return SDF_ORIENTATION_CW;
1008 return SDF_ORIENTATION_CCW;
1016 split_conic( FT_26D6_Vec* base )
1021 base[4].x = base[2].x;
1022 a = base[0].x + base[1].x;
1023 b = base[1].x + base[2].x;
1025 base[2].x = ( a + b ) / 4;
1028 base[4].y = base[2].y;
1029 a = base[0].y + base[1].y;
1030 b = base[1].y + base[2].y;
1032 base[2].y = ( a + b ) / 4;
1041 split_cubic( FT_26D6_Vec* base )
1046 base[6].x = base[3].x;
1047 a = base[0].x + base[1].x;
1048 b = base[1].x + base[2].x;
1049 c = base[2].x + base[3].x;
1056 base[3].x = ( a + c ) / 8;
1058 base[6].y = base[3].y;
1059 a = base[0].y + base[1].y;
1060 b = base[1].y + base[2].y;
1061 c = base[2].y + base[3].y;
1068 base[3].y = ( a + c ) / 8;
1078 split_sdf_conic( FT_Memory memory,
1079 FT_26D6_Vec* control_points,
1083 FT_Error error = FT_Err_Ok;
1084 FT_26D6_Vec cpos[5];
1085 SDF_Edge* left,* right;
1088 if ( !memory || !out )
1090 error = FT_THROW( Invalid_Argument );
1095 cpos[0] = control_points[0];
1096 cpos[1] = control_points[1];
1097 cpos[2] = control_points[2];
1099 split_conic( cpos );
1104 if ( max_splits <= 2 )
1108 FT_CALL( split_sdf_conic( memory, &cpos[0], max_splits / 2, out ) );
1109 FT_CALL( split_sdf_conic( memory, &cpos[2], max_splits / 2, out ) );
1121 FT_CALL( sdf_edge_new( memory, &left ) );
1122 FT_CALL( sdf_edge_new( memory, &right ) );
1124 left->start_pos = cpos[0];
1125 left->end_pos = cpos[2];
1126 left->edge_type = SDF_EDGE_LINE;
1128 right->start_pos = cpos[2];
1129 right->end_pos = cpos[4];
1130 right->edge_type = SDF_EDGE_LINE;
1133 right->next = (*out);
1147 split_sdf_cubic( FT_Memory memory,
1148 FT_26D6_Vec* control_points,
1152 FT_Error error = FT_Err_Ok;
1153 FT_26D6_Vec cpos[7];
1154 SDF_Edge* left, *right;
1155 const FT_26D6 threshold = ONE_PIXEL / 4;
1158 if ( !memory || !out )
1160 error = FT_THROW( Invalid_Argument );
1165 cpos[0] = control_points[0];
1166 cpos[1] = control_points[1];
1167 cpos[2] = control_points[2];
1168 cpos[3] = control_points[3];
1175 if ( FT_ABS( 2 * cpos[0].x - 3 * cpos[1].x + cpos[3].x ) < threshold &&
1176 FT_ABS( 2 * cpos[0].y - 3 * cpos[1].y + cpos[3].y ) < threshold &&
1177 FT_ABS( cpos[0].x - 3 * cpos[2].x + 2 * cpos[3].x ) < threshold &&
1178 FT_ABS( cpos[0].y - 3 * cpos[2].y + 2 * cpos[3].y ) < threshold )
1180 split_cubic( cpos );
1184 split_cubic( cpos );
1189 if ( max_splits <= 2 )
1193 FT_CALL( split_sdf_cubic( memory, &cpos[0], max_splits / 2, out ) );
1194 FT_CALL( split_sdf_cubic( memory, &cpos[3], max_splits / 2, out ) );
1206 FT_CALL( sdf_edge_new( memory, &left) );
1207 FT_CALL( sdf_edge_new( memory, &right) );
1209 left->start_pos = cpos[0];
1210 left->end_pos = cpos[3];
1211 left->edge_type = SDF_EDGE_LINE;
1213 right->start_pos = cpos[3];
1214 right->end_pos = cpos[6];
1215 right->edge_type = SDF_EDGE_LINE;
1218 right->next = (*out);
1230 split_sdf_shape( SDF_Shape* shape )
1232 FT_Error error = FT_Err_Ok;
1235 SDF_Contour* contours;
1236 SDF_Contour* new_contours = NULL;
1239 if ( !shape || !shape->memory )
1241 error = FT_THROW( Invalid_Argument );
1245 contours = shape->contours;
1246 memory = shape->memory;
1251 SDF_Edge* edges = contours->edges;
1252 SDF_Edge* new_edges = NULL;
1260 SDF_Edge* edge = edges;
1263 switch ( edge->edge_type )
1268 FT_CALL( sdf_edge_new( memory, &temp ) );
1270 ft_memcpy( temp, edge,
sizeof ( *edge ) );
1272 temp->next = new_edges;
1276 case SDF_EDGE_CONIC:
1279 FT_26D6_Vec ctrls[3];
1284 ctrls[0] = edge->start_pos;
1285 ctrls[1] = edge->control_a;
1286 ctrls[2] = edge->end_pos;
1288 dx = FT_ABS( ctrls[2].x + ctrls[0].x - 2 * ctrls[1].x );
1289 dy = FT_ABS( ctrls[2].y + ctrls[0].y - 2 * ctrls[1].y );
1299 while ( dx > ONE_PIXEL / 8 )
1305 error = split_sdf_conic( memory, ctrls, num_splits, &new_edges );
1309 case SDF_EDGE_CUBIC:
1312 FT_26D6_Vec ctrls[4];
1315 ctrls[0] = edge->start_pos;
1316 ctrls[1] = edge->control_a;
1317 ctrls[2] = edge->control_b;
1318 ctrls[3] = edge->end_pos;
1320 error = split_sdf_cubic( memory, ctrls, 32, &new_edges );
1325 error = FT_THROW( Invalid_Argument );
1328 if ( error != FT_Err_Ok )
1331 edges = edges->next;
1335 FT_CALL( sdf_contour_new( memory, &tempc ) );
1337 tempc->next = new_contours;
1338 tempc->edges = new_edges;
1339 new_contours = tempc;
1344 contours = contours->next;
1346 sdf_contour_done( memory, &tempc );
1349 shape->contours = new_contours;
1362#ifdef FT_DEBUG_LEVEL_TRACE
1365 sdf_shape_dump( SDF_Shape* shape )
1367 FT_UInt num_contours = 0;
1369 FT_UInt total_edges = 0;
1370 FT_UInt total_lines = 0;
1371 FT_UInt total_conic = 0;
1372 FT_UInt total_cubic = 0;
1374 SDF_Contour* contour_list;
1379 FT_TRACE5((
"sdf_shape_dump: null shape\n" ));
1383 contour_list = shape->contours;
1385 FT_TRACE5((
"sdf_shape_dump (values are in 26.6 format):\n" ));
1387 while ( contour_list )
1389 FT_UInt num_edges = 0;
1390 SDF_Edge* edge_list;
1391 SDF_Contour* contour = contour_list;
1394 FT_TRACE5((
" Contour %u\n", num_contours ));
1396 edge_list = contour->edges;
1400 SDF_Edge* edge = edge_list;
1403 FT_TRACE5((
" %3u: ", num_edges ));
1405 switch ( edge->edge_type )
1408 FT_TRACE5((
"Line: (%ld, %ld) -- (%ld, %ld)\n",
1409 edge->start_pos.x, edge->start_pos.y,
1410 edge->end_pos.x, edge->end_pos.y ));
1414 case SDF_EDGE_CONIC:
1415 FT_TRACE5((
"Conic: (%ld, %ld) .. (%ld, %ld) .. (%ld, %ld)\n",
1416 edge->start_pos.x, edge->start_pos.y,
1417 edge->control_a.x, edge->control_a.y,
1418 edge->end_pos.x, edge->end_pos.y ));
1422 case SDF_EDGE_CUBIC:
1423 FT_TRACE5((
"Cubic: (%ld, %ld) .. (%ld, %ld)"
1424 " .. (%ld, %ld) .. (%ld %ld)\n",
1425 edge->start_pos.x, edge->start_pos.y,
1426 edge->control_a.x, edge->control_a.y,
1427 edge->control_b.x, edge->control_b.y,
1428 edge->end_pos.x, edge->end_pos.y ));
1438 edge_list = edge_list->next;
1442 contour_list = contour_list->next;
1445 FT_TRACE5((
"\n" ));
1446 FT_TRACE5((
" total number of contours = %u\n", num_contours ));
1447 FT_TRACE5((
" total number of edges = %u\n", total_edges ));
1448 FT_TRACE5((
" |__lines = %u\n", total_lines ));
1449 FT_TRACE5((
" |__conic = %u\n", total_conic ));
1450 FT_TRACE5((
" |__cubic = %u\n", total_cubic ));
1462#if !USE_NEWTON_FOR_CONIC
1471 cube_root( FT_16D16 val )
1481 val == -FT_INT_16D16( 1 ) ||
1482 val == FT_INT_16D16( 1 ) )
1485 v = val < 0 ? -val : val;
1486 g = square_root( v );
1491 c = FT_MulFix( FT_MulFix( g, g ), g ) - v;
1492 c = FT_DivFix( c, 3 * FT_MulFix( g, g ) );
1496 if ( ( c < 0 ? -c : c ) < 30 )
1500 return val < 0 ? -g : g;
1507 arc_cos( FT_16D16 val )
1511 FT_16D16 one = FT_INT_16D16( 1 );
1519 p = one - FT_MulFix( b, b );
1520 p = square_root( p );
1522 return FT_Atan2( b, p );
1533 solve_quadratic_equation( FT_26D6 a,
1538 FT_16D16 discriminant = 0;
1541 a = FT_26D6_16D16( a );
1542 b = FT_26D6_16D16( b );
1543 c = FT_26D6_16D16( c );
1551 out[0] = FT_DivFix( -c, b );
1557 discriminant = FT_MulFix( b, b ) - 4 * FT_MulFix( a, c );
1559 if ( discriminant < 0 )
1561 else if ( discriminant == 0 )
1563 out[0] = FT_DivFix( -b, 2 * a );
1569 discriminant = square_root( discriminant );
1571 out[0] = FT_DivFix( -b + discriminant, 2 * a );
1572 out[1] = FT_DivFix( -b - discriminant, 2 * a );
1586 solve_cubic_equation( FT_26D6 a,
1607 if ( a == 0 || FT_ABS( a ) < 16 )
1608 return solve_quadratic_equation( b, c, d, out );
1614 return solve_quadratic_equation( a, b, c, out + 1 ) + 1;
1618 a2 = FT_DivFix( a2, a );
1619 a1 = FT_DivFix( a1, a );
1620 a0 = FT_DivFix( a0, a );
1623 a1x2 = FT_MulFix( a1, a2 );
1624 a22 = FT_MulFix( a2, a2 );
1625 a23 = FT_MulFix( a22, a2 );
1627 q = ( 3 * a1 - a22 ) / 9;
1628 r = ( 9 * a1x2 - 27 * a0 - 2 * a23 ) / 54;
1632 q3 = FT_MulFix( q, q );
1633 q3 = FT_MulFix( q3, q );
1635 r2 = FT_MulFix( r, r );
1637 if ( q3 < 0 && r2 < -q3 )
1642 q3 = square_root( -q3 );
1643 t = FT_DivFix( r, q3 );
1645 if ( t > ( 1 << 16 ) )
1647 if ( t < -( 1 << 16 ) )
1652 q = 2 * square_root( -q );
1654 out[0] = FT_MulFix( q, FT_Cos( t / 3 ) ) - a2;
1655 out[1] = FT_MulFix( q, FT_Cos( ( t + FT_ANGLE_PI * 2 ) / 3 ) ) - a2;
1656 out[2] = FT_MulFix( q, FT_Cos( ( t + FT_ANGLE_PI * 4 ) / 3 ) ) - a2;
1661 else if ( r2 == -q3 )
1669 out[0] = a2 + ( 2 * s );
1685 dis = square_root( q3 + r2 );
1687 s = cube_root( r + dis );
1688 t = cube_root( r - dis );
1690 out[0] = ( a2 + ( s + t ) );
1796 static SDF_Signed_Distance
1797 resolve_corner( SDF_Signed_Distance sdf1,
1798 SDF_Signed_Distance sdf2 )
1800 return FT_ABS( sdf1.cross ) > FT_ABS( sdf2.cross ) ? sdf1 : sdf2;
1832 get_min_distance_line( SDF_Edge* line,
1834 SDF_Signed_Distance* out )
1893 FT_Error error = FT_Err_Ok;
1899 FT_26D6_Vec line_segment;
1900 FT_26D6_Vec p_sub_a;
1902 FT_26D6 sq_line_length;
1906 FT_16D16_Vec nearest_point;
1907 FT_16D16_Vec nearest_vector;
1910 if ( !line || !out )
1912 error = FT_THROW( Invalid_Argument );
1916 if ( line->edge_type != SDF_EDGE_LINE )
1918 error = FT_THROW( Invalid_Argument );
1922 a = line->start_pos;
1926 line_segment.x = b.x - a.x;
1927 line_segment.y = b.y - a.y;
1929 p_sub_a.x = p.x - a.x;
1930 p_sub_a.y = p.y - a.y;
1932 sq_line_length = ( line_segment.x * line_segment.x ) / 64 +
1933 ( line_segment.y * line_segment.y ) / 64;
1936 factor = ( p_sub_a.x * line_segment.x ) / 64 +
1937 ( p_sub_a.y * line_segment.y ) / 64;
1940 factor = FT_DivFix( factor, sq_line_length );
1943 if ( factor > FT_INT_16D16( 1 ) )
1944 factor = FT_INT_16D16( 1 );
1948 nearest_point.x = FT_MulFix( FT_26D6_16D16( line_segment.x ),
1950 nearest_point.y = FT_MulFix( FT_26D6_16D16( line_segment.y ),
1953 nearest_point.x = FT_26D6_16D16( a.x ) + nearest_point.x;
1954 nearest_point.y = FT_26D6_16D16( a.y ) + nearest_point.y;
1956 nearest_vector.x = nearest_point.x - FT_26D6_16D16( p.x );
1957 nearest_vector.y = nearest_point.y - FT_26D6_16D16( p.y );
1959 cross = FT_MulFix( nearest_vector.x, line_segment.y ) -
1960 FT_MulFix( nearest_vector.y, line_segment.x );
1963 out->sign = cross < 0 ? 1 : -1;
1964 out->distance = VECTOR_LENGTH_16D16( nearest_vector );
1970 if ( factor != 0 && factor != FT_INT_16D16( 1 ) )
1971 out->cross = FT_INT_16D16( 1 );
1976 FT_Vector_NormLen( &line_segment );
1977 FT_Vector_NormLen( &nearest_vector );
1979 out->cross = FT_MulFix( line_segment.x, nearest_vector.y ) -
1980 FT_MulFix( line_segment.y, nearest_vector.x );
2018#if !USE_NEWTON_FOR_CONIC
2026 get_min_distance_conic( SDF_Edge* conic,
2028 SDF_Signed_Distance* out )
2109 FT_Error error = FT_Err_Ok;
2112 FT_26D6_Vec nearest_point = { 0, 0 };
2114 FT_26D6_Vec direction;
2116 FT_26D6_Vec p0, p1, p2;
2121 FT_16D16 roots[3] = { 0, 0, 0 };
2122 FT_16D16 min_factor;
2124 FT_16D16 min = FT_INT_MAX;
2126 FT_UShort num_roots;
2130 if ( !conic || !out )
2132 error = FT_THROW( Invalid_Argument );
2136 if ( conic->edge_type != SDF_EDGE_CONIC )
2138 error = FT_THROW( Invalid_Argument );
2142 p0 = conic->start_pos;
2143 p1 = conic->control_a;
2144 p2 = conic->end_pos;
2148 aA.x = p0.x - 2 * p1.x + p2.x;
2149 aA.y = p0.y - 2 * p1.y + p2.y;
2155 a = VEC_26D6_DOT( aA, aA );
2157 b = 3 * VEC_26D6_DOT( aA, bB );
2159 c = 2 * VEC_26D6_DOT( bB, bB ) +
2160 VEC_26D6_DOT( aA, p0 ) -
2161 VEC_26D6_DOT( aA, p );
2163 d = VEC_26D6_DOT( p0, bB ) -
2164 VEC_26D6_DOT( p, bB );
2167 num_roots = solve_cubic_equation( a, b, c, d, roots );
2169 if ( num_roots == 0 )
2172 roots[1] = FT_INT_16D16( 1 );
2180 aA.x = FT_26D6_16D16( aA.x );
2181 aA.y = FT_26D6_16D16( aA.y );
2183 bB.x = FT_26D6_16D16( bB.x );
2184 bB.y = FT_26D6_16D16( bB.y );
2186 p0.x = FT_26D6_16D16( p0.x );
2187 p0.y = FT_26D6_16D16( p0.y );
2189 p.x = FT_26D6_16D16( p.x );
2190 p.y = FT_26D6_16D16( p.y );
2192 for ( i = 0; i < num_roots; i++ )
2194 FT_16D16 t = roots[i];
2198 FT_16D16_Vec curve_point;
2199 FT_16D16_Vec dist_vector;
2226 if ( t > FT_INT_16D16( 1 ) )
2227 t = FT_INT_16D16( 1 );
2229 t2 = FT_MulFix( t, t );
2232 curve_point.x = FT_MulFix( aA.x, t2 ) +
2233 2 * FT_MulFix( bB.x, t ) + p0.x;
2234 curve_point.y = FT_MulFix( aA.y, t2 ) +
2235 2 * FT_MulFix( bB.y, t ) + p0.y;
2238 dist_vector.x = curve_point.x - p.x;
2239 dist_vector.y = curve_point.y - p.y;
2241 dist = VECTOR_LENGTH_16D16( dist_vector );
2246 nearest_point = curve_point;
2252 direction.x = 2 * FT_MulFix( aA.x, min_factor ) + 2 * bB.x;
2253 direction.y = 2 * FT_MulFix( aA.y, min_factor ) + 2 * bB.y;
2256 cross = FT_MulFix( nearest_point.x - p.x, direction.y ) -
2257 FT_MulFix( nearest_point.y - p.y, direction.x );
2260 out->distance = min;
2261 out->sign = cross < 0 ? 1 : -1;
2263 if ( min_factor != 0 && min_factor != FT_INT_16D16( 1 ) )
2264 out->cross = FT_INT_16D16( 1 );
2268 nearest_point.x -= FT_26D6_16D16( p.x );
2269 nearest_point.y -= FT_26D6_16D16( p.y );
2272 FT_Vector_NormLen( &direction );
2273 FT_Vector_NormLen( &nearest_point );
2275 out->cross = FT_MulFix( direction.x, nearest_point.y ) -
2276 FT_MulFix( direction.y, nearest_point.x );
2291 get_min_distance_conic( SDF_Edge* conic,
2293 SDF_Signed_Distance* out )
2406 FT_Error error = FT_Err_Ok;
2408 FT_26D6_Vec aA, bB, cC;
2409 FT_26D6_Vec nearest_point = { 0, 0 };
2411 FT_26D6_Vec direction;
2413 FT_26D6_Vec p0, p1, p2;
2416 FT_16D16 min_factor = 0;
2418 FT_16D16 min = FT_INT_MAX;
2420 FT_UShort iterations;
2424 if ( !conic || !out )
2426 error = FT_THROW( Invalid_Argument );
2430 if ( conic->edge_type != SDF_EDGE_CONIC )
2432 error = FT_THROW( Invalid_Argument );
2436 p0 = conic->start_pos;
2437 p1 = conic->control_a;
2438 p2 = conic->end_pos;
2442 aA.x = p0.x - 2 * p1.x + p2.x;
2443 aA.y = p0.y - 2 * p1.y + p2.y;
2445 bB.x = 2 * ( p1.x - p0.x );
2446 bB.y = 2 * ( p1.y - p0.y );
2452 for ( iterations = 0; iterations <= MAX_NEWTON_DIVISIONS; iterations++ )
2454 FT_16D16 factor = FT_INT_16D16( iterations ) / MAX_NEWTON_DIVISIONS;
2458 FT_16D16_Vec curve_point;
2459 FT_16D16_Vec dist_vector;
2468 for ( steps = 0; steps < MAX_NEWTON_STEPS; steps++ )
2470 factor2 = FT_MulFix( factor, factor );
2473 curve_point.x = FT_MulFix( aA.x, factor2 ) +
2474 FT_MulFix( bB.x, factor ) + cC.x;
2475 curve_point.y = FT_MulFix( aA.y, factor2 ) +
2476 FT_MulFix( bB.y, factor ) + cC.y;
2479 curve_point.x = FT_26D6_16D16( curve_point.x );
2480 curve_point.y = FT_26D6_16D16( curve_point.y );
2483 dist_vector.x = curve_point.x - FT_26D6_16D16( p.x );
2484 dist_vector.y = curve_point.y - FT_26D6_16D16( p.y );
2486 length = VECTOR_LENGTH_16D16( dist_vector );
2491 min_factor = factor;
2492 nearest_point = curve_point;
2501 d1.x = FT_MulFix( aA.x, 2 * factor ) + bB.x;
2502 d1.y = FT_MulFix( aA.y, 2 * factor ) + bB.y;
2508 dist_vector.x /= 1024;
2509 dist_vector.y /= 1024;
2512 temp1 = VEC_26D6_DOT( dist_vector, d1 );
2515 temp2 = VEC_26D6_DOT( d1, d1 ) +
2516 VEC_26D6_DOT( dist_vector, d2 );
2518 factor -= FT_DivFix( temp1, temp2 );
2520 if ( factor < 0 || factor > FT_INT_16D16( 1 ) )
2526 direction.x = 2 * FT_MulFix( aA.x, min_factor ) + bB.x;
2527 direction.y = 2 * FT_MulFix( aA.y, min_factor ) + bB.y;
2530 cross = FT_MulFix( nearest_point.x - FT_26D6_16D16( p.x ),
2532 FT_MulFix( nearest_point.y - FT_26D6_16D16( p.y ),
2536 out->distance = min;
2537 out->sign = cross < 0 ? 1 : -1;
2539 if ( min_factor != 0 && min_factor != FT_INT_16D16( 1 ) )
2540 out->cross = FT_INT_16D16( 1 );
2544 nearest_point.x -= FT_26D6_16D16( p.x );
2545 nearest_point.y -= FT_26D6_16D16( p.y );
2548 FT_Vector_NormLen( &direction );
2549 FT_Vector_NormLen( &nearest_point );
2551 out->cross = FT_MulFix( direction.x, nearest_point.y ) -
2552 FT_MulFix( direction.y, nearest_point.x );
2596 get_min_distance_cubic( SDF_Edge* cubic,
2598 SDF_Signed_Distance* out )
2719 FT_Error error = FT_Err_Ok;
2721 FT_26D6_Vec aA, bB, cC, dD;
2722 FT_16D16_Vec nearest_point = { 0, 0 };
2724 FT_16D16_Vec direction;
2726 FT_26D6_Vec p0, p1, p2, p3;
2729 FT_16D16 min_factor = 0;
2730 FT_16D16 min_factor_sq = 0;
2732 FT_16D16 min = FT_INT_MAX;
2734 FT_UShort iterations;
2738 if ( !cubic || !out )
2740 error = FT_THROW( Invalid_Argument );
2744 if ( cubic->edge_type != SDF_EDGE_CUBIC )
2746 error = FT_THROW( Invalid_Argument );
2750 p0 = cubic->start_pos;
2751 p1 = cubic->control_a;
2752 p2 = cubic->control_b;
2753 p3 = cubic->end_pos;
2757 aA.x = -p0.x + 3 * ( p1.x - p2.x ) + p3.x;
2758 aA.y = -p0.y + 3 * ( p1.y - p2.y ) + p3.y;
2760 bB.x = 3 * ( p0.x - 2 * p1.x + p2.x );
2761 bB.y = 3 * ( p0.y - 2 * p1.y + p2.y );
2763 cC.x = 3 * ( p1.x - p0.x );
2764 cC.y = 3 * ( p1.y - p0.y );
2769 for ( iterations = 0; iterations <= MAX_NEWTON_DIVISIONS; iterations++ )
2771 FT_16D16 factor = FT_INT_16D16( iterations ) / MAX_NEWTON_DIVISIONS;
2777 FT_16D16_Vec curve_point;
2778 FT_16D16_Vec dist_vector;
2787 for ( steps = 0; steps < MAX_NEWTON_STEPS; steps++ )
2789 factor2 = FT_MulFix( factor, factor );
2790 factor3 = FT_MulFix( factor2, factor );
2793 curve_point.x = FT_MulFix( aA.x, factor3 ) +
2794 FT_MulFix( bB.x, factor2 ) +
2795 FT_MulFix( cC.x, factor ) + dD.x;
2796 curve_point.y = FT_MulFix( aA.y, factor3 ) +
2797 FT_MulFix( bB.y, factor2 ) +
2798 FT_MulFix( cC.y, factor ) + dD.y;
2801 curve_point.x = FT_26D6_16D16( curve_point.x );
2802 curve_point.y = FT_26D6_16D16( curve_point.y );
2805 dist_vector.x = curve_point.x - FT_26D6_16D16( p.x );
2806 dist_vector.y = curve_point.y - FT_26D6_16D16( p.y );
2808 length = VECTOR_LENGTH_16D16( dist_vector );
2813 min_factor = factor;
2814 min_factor_sq = factor2;
2815 nearest_point = curve_point;
2824 d1.x = FT_MulFix( aA.x, 3 * factor2 ) +
2825 FT_MulFix( bB.x, 2 * factor ) + cC.x;
2826 d1.y = FT_MulFix( aA.y, 3 * factor2 ) +
2827 FT_MulFix( bB.y, 2 * factor ) + cC.y;
2830 d2.x = FT_MulFix( aA.x, 6 * factor ) + 2 * bB.x;
2831 d2.y = FT_MulFix( aA.y, 6 * factor ) + 2 * bB.y;
2833 dist_vector.x /= 1024;
2834 dist_vector.y /= 1024;
2837 temp1 = VEC_26D6_DOT( dist_vector, d1 );
2840 temp2 = VEC_26D6_DOT( d1, d1 ) +
2841 VEC_26D6_DOT( dist_vector, d2 );
2843 factor -= FT_DivFix( temp1, temp2 );
2845 if ( factor < 0 || factor > FT_INT_16D16( 1 ) )
2851 direction.x = FT_MulFix( aA.x, 3 * min_factor_sq ) +
2852 FT_MulFix( bB.x, 2 * min_factor ) + cC.x;
2853 direction.y = FT_MulFix( aA.y, 3 * min_factor_sq ) +
2854 FT_MulFix( bB.y, 2 * min_factor ) + cC.y;
2857 cross = FT_MulFix( nearest_point.x - FT_26D6_16D16( p.x ),
2859 FT_MulFix( nearest_point.y - FT_26D6_16D16( p.y ),
2863 out->distance = min;
2864 out->sign = cross < 0 ? 1 : -1;
2866 if ( min_factor != 0 && min_factor != FT_INT_16D16( 1 ) )
2867 out->cross = FT_INT_16D16( 1 );
2871 nearest_point.x -= FT_26D6_16D16( p.x );
2872 nearest_point.y -= FT_26D6_16D16( p.y );
2875 FT_Vector_NormLen( &direction );
2876 FT_Vector_NormLen( &nearest_point );
2878 out->cross = FT_MulFix( direction.x, nearest_point.y ) -
2879 FT_MulFix( direction.y, nearest_point.x );
2913 sdf_edge_get_min_distance( SDF_Edge* edge,
2915 SDF_Signed_Distance* out )
2917 FT_Error error = FT_Err_Ok;
2920 if ( !edge || !out )
2922 error = FT_THROW( Invalid_Argument );
2927 switch ( edge->edge_type )
2930 get_min_distance_line( edge, point, out );
2933 case SDF_EDGE_CONIC:
2934 get_min_distance_conic( edge, point, out );
2937 case SDF_EDGE_CUBIC:
2938 get_min_distance_cubic( edge, point, out );
2942 error = FT_THROW( Invalid_Argument );
2953 #error "DO NOT USE THIS!"
2954 #error "The function still outputs 16-bit data, which might cause memory"
2955 #error "corruption. If required I will add this later."
2987 sdf_contour_get_min_distance( SDF_Contour* contour,
2989 SDF_Signed_Distance* out )
2991 FT_Error error = FT_Err_Ok;
2992 SDF_Signed_Distance min_dist = max_sdf;
2993 SDF_Edge* edge_list;
2996 if ( !contour || !out )
2998 error = FT_THROW( Invalid_Argument );
3002 edge_list = contour->edges;
3007 SDF_Signed_Distance current_dist = max_sdf;
3011 FT_CALL( sdf_edge_get_min_distance( edge_list,
3015 if ( current_dist.distance >= 0 )
3017 diff = current_dist.distance - min_dist.distance;
3020 if ( FT_ABS( diff ) < CORNER_CHECK_EPSILON )
3021 min_dist = resolve_corner( min_dist, current_dist );
3022 else if ( diff < 0 )
3023 min_dist = current_dist;
3026 FT_TRACE0((
"sdf_contour_get_min_distance: Overflow.\n" ));
3028 edge_list = edge_list->next;
3071 sdf_generate(
const SDF_Params internal_params,
3072 const SDF_Shape* shape,
3074 const FT_Bitmap* bitmap )
3076 FT_Error error = FT_Err_Ok;
3087 if ( !shape || !bitmap )
3089 error = FT_THROW( Invalid_Argument );
3093 if ( spread < MIN_SPREAD || spread > MAX_SPREAD )
3095 error = FT_THROW( Invalid_Argument );
3099 width = bitmap->width;
3100 rows = bitmap->rows;
3101 buffer = (FT_Short*)bitmap->buffer;
3103 if ( USE_SQUARED_DISTANCES )
3104 sp_sq = FT_INT_16D16( spread * spread );
3106 sp_sq = FT_INT_16D16( spread );
3108 if ( width == 0 || rows == 0 )
3110 FT_TRACE0((
"sdf_generate:"
3111 " Cannot render glyph with width/height == 0\n" ));
3113 " (width, height provided [%d, %d])\n",
3116 error = FT_THROW( Cannot_Render_Glyph );
3121 for ( y = 0; y < rows; y++ )
3124 for ( x = 0; x < width; x++ )
3129 FT_26D6_Vec grid_point = zero_vector;
3130 SDF_Signed_Distance min_dist = max_sdf;
3131 SDF_Contour* contour_list;
3137 grid_point.x = FT_INT_26D6( x );
3138 grid_point.y = FT_INT_26D6( y );
3142 grid_point.x += FT_INT_26D6( 1 ) / 2;
3143 grid_point.y += FT_INT_26D6( 1 ) / 2;
3145 contour_list = shape->contours;
3148 while ( contour_list )
3150 SDF_Signed_Distance current_dist = max_sdf;
3153 FT_CALL( sdf_contour_get_min_distance( contour_list,
3157 if ( current_dist.distance < min_dist.distance )
3158 min_dist = current_dist;
3160 contour_list = contour_list->next;
3167 if ( min_dist.distance > sp_sq )
3168 min_dist.distance = sp_sq;
3171 if ( USE_SQUARED_DISTANCES )
3172 min_dist.distance = square_root( min_dist.distance );
3174 if ( internal_params.orientation == FT_ORIENTATION_FILL_LEFT )
3175 min_dist.sign = -min_dist.sign;
3176 if ( internal_params.flip_sign )
3177 min_dist.sign = -min_dist.sign;
3179 min_dist.distance /= 64;
3181 value = min_dist.distance & 0x0000FFFF;
3182 value *= min_dist.sign;
3184 if ( internal_params.flip_y )
3185 index = y * width + x;
3187 index = ( rows - y - 1 ) * width + x;
3189 buffer[index] = value;
3241 sdf_generate_bounding_box(
const SDF_Params internal_params,
3242 const SDF_Shape* shape,
3244 const FT_Bitmap* bitmap )
3246 FT_Error error = FT_Err_Ok;
3247 FT_Memory memory = NULL;
3249 FT_Int width, rows, i, j;
3252 SDF_Contour* contours;
3253 FT_SDFFormat* buffer;
3260 SDF_Signed_Distance* dists = NULL;
3262 const FT_16D16 fixed_spread = (FT_16D16)FT_INT_16D16( spread );
3265 if ( !shape || !bitmap )
3267 error = FT_THROW( Invalid_Argument );
3271 if ( spread < MIN_SPREAD || spread > MAX_SPREAD )
3273 error = FT_THROW( Invalid_Argument );
3277 memory = shape->memory;
3280 error = FT_THROW( Invalid_Argument );
3284 if ( FT_ALLOC( dists,
3285 bitmap->width * bitmap->rows * sizeof ( *dists ) ) )
3288 contours = shape->contours;
3289 width = (FT_Int)bitmap->width;
3290 rows = (FT_Int)bitmap->rows;
3291 buffer = (FT_SDFFormat*)bitmap->buffer;
3293 if ( USE_SQUARED_DISTANCES )
3294 sp_sq = FT_INT_16D16( (FT_Int)( spread * spread ) );
3296 sp_sq = fixed_spread;
3298 if ( width == 0 || rows == 0 )
3300 FT_TRACE0((
"sdf_generate:"
3301 " Cannot render glyph with width/height == 0\n" ));
3303 " (width, height provided [%d, %d])", width, rows ));
3305 error = FT_THROW( Cannot_Render_Glyph );
3312 SDF_Edge* edges = contours->edges;
3323 cbox = get_control_box( *edges );
3325 cbox.xMin = ( cbox.xMin - 63 ) / 64 - ( FT_Pos )spread;
3326 cbox.xMax = ( cbox.xMax + 63 ) / 64 + ( FT_Pos )spread;
3327 cbox.yMin = ( cbox.yMin - 63 ) / 64 - ( FT_Pos )spread;
3328 cbox.yMax = ( cbox.yMax + 63 ) / 64 + ( FT_Pos )spread;
3331 for ( y = cbox.yMin; y < cbox.yMax; y++ )
3333 for ( x = cbox.xMin; x < cbox.xMax; x++ )
3335 FT_26D6_Vec grid_point = zero_vector;
3336 SDF_Signed_Distance dist = max_sdf;
3341 if ( x < 0 || x >= width )
3343 if ( y < 0 || y >= rows )
3346 grid_point.x = FT_INT_26D6( x );
3347 grid_point.y = FT_INT_26D6( y );
3351 grid_point.x += FT_INT_26D6( 1 ) / 2;
3352 grid_point.y += FT_INT_26D6( 1 ) / 2;
3354 FT_CALL( sdf_edge_get_min_distance( edges,
3358 if ( internal_params.orientation == FT_ORIENTATION_FILL_LEFT )
3359 dist.sign = -dist.sign;
3363 if ( dist.distance > sp_sq )
3367 if ( USE_SQUARED_DISTANCES )
3368 dist.distance = square_root( dist.distance );
3370 if ( internal_params.flip_y )
3371 index = (FT_UInt)( y * width + x );
3373 index = (FT_UInt)( ( rows - y - 1 ) * width + x );
3376 if ( dists[index].sign == 0 )
3377 dists[index] = dist;
3380 diff = FT_ABS( dists[index].distance - dist.distance );
3382 if ( diff <= CORNER_CHECK_EPSILON )
3383 dists[index] = resolve_corner( dists[index], dist );
3384 else if ( dists[index].distance > dist.distance )
3385 dists[index] = dist;
3390 edges = edges->next;
3393 contours = contours->next;
3397 for ( j = 0; j < rows; j++ )
3400 FT_Char current_sign = -1;
3404 if ( internal_params.overload_sign != 0 )
3405 current_sign = internal_params.overload_sign < 0 ? -1 : 1;
3407 for ( i = 0; i < width; i++ )
3409 index = (FT_UInt)( j * width + i );
3413 if ( dists[index].sign == 0 )
3414 dists[index].distance = fixed_spread;
3416 current_sign = dists[index].sign;
3419 if ( dists[index].distance > fixed_spread )
3420 dists[index].distance = fixed_spread;
3423 dists[index].distance *= internal_params.flip_sign ? -current_sign
3427 buffer[index] = map_fixed_to_sdf( dists[index].distance,
3470 sdf_generate_subdivision(
const SDF_Params internal_params,
3473 const FT_Bitmap* bitmap )
3497 FT_Error error = FT_Err_Ok;
3500 FT_CALL( split_sdf_shape( shape ) );
3501 FT_CALL( sdf_generate_bounding_box( internal_params,
3502 shape, spread, bitmap ) );
3548 sdf_generate_with_overlaps( SDF_Params internal_params,
3551 const FT_Bitmap* bitmap )
3553 FT_Error error = FT_Err_Ok;
3555 FT_Int num_contours;
3560 SDF_Contour* contour;
3561 SDF_Contour* temp_contour;
3563 SDF_Shape temp_shape;
3570 SDF_Contour_Orientation* orientations;
3574 orientations = NULL;
3577 if ( !shape || !bitmap || !shape->memory )
3578 return FT_THROW( Invalid_Argument );
3582 flip_sign = internal_params.flip_sign;
3583 internal_params.flip_sign = 0;
3585 contour = shape->contours;
3586 memory = shape->memory;
3587 temp_shape.memory = memory;
3588 width = (FT_Int)bitmap->width;
3589 rows = (FT_Int)bitmap->rows;
3596 contour = contour->next;
3600 if ( FT_ALLOC( bitmaps,
3601 (FT_UInt)num_contours *
sizeof ( *bitmaps ) ) )
3605 if ( FT_ALLOC( orientations,
3606 (FT_UInt)num_contours *
sizeof ( *orientations ) ) )
3609 contour = shape->contours;
3612 for ( i = 0; i < num_contours; i++ )
3615 FT_Bitmap_Init( &bitmaps[i] );
3617 bitmaps[i].width = bitmap->width;
3618 bitmaps[i].rows = bitmap->rows;
3619 bitmaps[i].pitch = bitmap->pitch;
3620 bitmaps[i].num_grays = bitmap->num_grays;
3621 bitmaps[i].pixel_mode = bitmap->pixel_mode;
3624 if ( FT_ALLOC( bitmaps[i].buffer,
3625 bitmap->rows * (FT_UInt)bitmap->pitch ) )
3629 orientations[i] = get_contour_orientation( contour );
3636 if ( orientations[i] == SDF_ORIENTATION_CCW &&
3637 internal_params.orientation == FT_ORIENTATION_FILL_RIGHT )
3638 internal_params.overload_sign = 1;
3639 else if ( orientations[i] == SDF_ORIENTATION_CW &&
3640 internal_params.orientation == FT_ORIENTATION_FILL_LEFT )
3641 internal_params.overload_sign = 1;
3643 internal_params.overload_sign = 0;
3649 temp_contour = contour->next;
3650 contour->next = NULL;
3654 temp_shape.contours = contour;
3657 FT_CALL( sdf_generate_subdivision( internal_params,
3663 contour->next = temp_contour;
3668 temp_shape.contours->next = head;
3669 head = temp_shape.contours;
3673 if ( internal_params.orientation == FT_ORIENTATION_FILL_LEFT )
3675 if ( orientations[i] == SDF_ORIENTATION_CW )
3676 orientations[i] = SDF_ORIENTATION_CCW;
3677 else if ( orientations[i] == SDF_ORIENTATION_CCW )
3678 orientations[i] = SDF_ORIENTATION_CW;
3681 contour = contour->next;
3685 shape->contours = head;
3688 t = (FT_SDFFormat*)bitmap->buffer;
3699 for ( j = 0; j < rows; j++ )
3701 for ( i = 0; i < width; i++ )
3703 FT_Int
id = j * width + i;
3706 FT_SDFFormat val_c = 0;
3707 FT_SDFFormat val_ac = UCHAR_MAX;
3711 for ( c = 0; c < num_contours; c++ )
3714 FT_SDFFormat temp = ( (FT_SDFFormat*)bitmaps[c].buffer )[id];
3717 if ( orientations[c] == SDF_ORIENTATION_CW )
3718 val_c = FT_MAX( val_c, temp );
3720 val_ac = FT_MIN( val_ac, temp );
3725 t[id] = FT_MIN( val_c, val_ac );
3728 t[id] = invert_sign( t[
id] );
3735 FT_FREE( orientations );
3740 if ( num_contours == 0 )
3741 error = FT_THROW( Raster_Corrupted );
3744 for ( i = 0; i < num_contours; i++ )
3745 FT_FREE( bitmaps[i].buffer );
3752 internal_params.flip_sign = flip_sign;
3765 sdf_raster_new(
void* memory_,
3766 FT_Raster* araster_ )
3768 FT_Memory memory = (FT_Memory)memory_;
3769 SDF_PRaster* araster = (SDF_PRaster*)araster_;
3773 SDF_PRaster raster = NULL;
3776 if ( !FT_NEW( raster ) )
3777 raster->memory = memory;
3786 sdf_raster_reset( FT_Raster raster,
3787 unsigned char* pool_base,
3788 unsigned long pool_size )
3790 FT_UNUSED( raster );
3791 FT_UNUSED( pool_base );
3792 FT_UNUSED( pool_size );
3797 sdf_raster_set_mode( FT_Raster raster,
3801 FT_UNUSED( raster );
3810 sdf_raster_render( FT_Raster raster,
3811 const FT_Raster_Params* params )
3813 FT_Error error = FT_Err_Ok;
3814 SDF_TRaster* sdf_raster = (SDF_TRaster*)raster;
3815 FT_Outline* outline = NULL;
3816 const SDF_Raster_Params* sdf_params = (
const SDF_Raster_Params*)params;
3818 FT_Memory memory = NULL;
3819 SDF_Shape* shape = NULL;
3820 SDF_Params internal_params;
3824 if ( !sdf_raster || !sdf_params )
3826 error = FT_THROW( Invalid_Argument );
3830 outline = (FT_Outline*)sdf_params->root.source;
3835 error = FT_THROW( Invalid_Outline );
3840 if ( outline->n_points == 0 || outline->n_contours == 0 )
3844 if ( !outline->contours || !outline->points )
3846 error = FT_THROW( Invalid_Outline );
3851 if ( sdf_params->spread > MAX_SPREAD ||
3852 sdf_params->spread < MIN_SPREAD )
3854 FT_TRACE0((
"sdf_raster_render:"
3855 " The `spread' field of `SDF_Raster_Params' is invalid,\n" ));
3857 " the value of this field must be within [%d, %d].\n",
3858 MIN_SPREAD, MAX_SPREAD ));
3860 " Also, you must pass `SDF_Raster_Params' instead of\n" ));
3862 " the default `FT_Raster_Params' while calling\n" ));
3864 " this function and set the fields properly.\n" ));
3866 error = FT_THROW( Invalid_Argument );
3870 memory = sdf_raster->memory;
3873 FT_TRACE0((
"sdf_raster_render:"
3874 " Raster not setup properly,\n" ));
3876 " unable to find memory handle.\n" ));
3878 error = FT_THROW( Invalid_Handle );
3883 internal_params.orientation = FT_Outline_Get_Orientation( outline );
3884 internal_params.flip_sign = sdf_params->flip_sign;
3885 internal_params.flip_y = sdf_params->flip_y;
3886 internal_params.overload_sign = 0;
3888 FT_CALL( sdf_shape_new( memory, &shape ) );
3890 FT_CALL( sdf_outline_decompose( outline, shape ) );
3892 if ( sdf_params->overlaps )
3893 FT_CALL( sdf_generate_with_overlaps( internal_params,
3894 shape, sdf_params->spread,
3895 sdf_params->root.target ) );
3897 FT_CALL( sdf_generate_subdivision( internal_params,
3898 shape, sdf_params->spread,
3899 sdf_params->root.target ) );
3902 sdf_shape_done( &shape );
3910 sdf_raster_done( FT_Raster raster )
3912 FT_Memory memory = (FT_Memory)((SDF_TRaster*)raster)->memory;
3919 FT_DEFINE_RASTER_FUNCS(
3922 FT_GLYPH_FORMAT_OUTLINE,
3924 (FT_Raster_New_Func) sdf_raster_new,
3925 (FT_Raster_Reset_Func) sdf_raster_reset,
3926 (FT_Raster_Set_Mode_Func)sdf_raster_set_mode,
3927 (FT_Raster_Render_Func) sdf_raster_render,
3928 (FT_Raster_Done_Func) sdf_raster_done