static FT_Vector GetMidPoint(FT_Vector v1, FT_Vector v2) { return(new FT_Vector( (v1.x + v2.x) / 2, (v1.y + v2.y) / 2)); }
unsafe internal static void BuildGlyphOutline(FontGlyph fontGlyph, ExportGlyph *exportTypeFace) { FT_Outline outline = (*(FT_Outline *)exportTypeFace->outline); //outline version //------------------------------ int npoints = outline.n_points; List <PixelFarm.VectorMath.Vector2> points = new List <PixelFarm.VectorMath.Vector2>(npoints); int startContour = 0; int cpoint_index = 0; int todoContourCount = outline.n_contours; PixelFarm.Agg.VertexSource.PathWriter ps = new Agg.VertexSource.PathWriter(); fontGlyph.originalVxs = ps.Vxs; const int resize = 64; int controlPointCount = 0; while (todoContourCount > 0) { int nextContour = outline.contours[startContour] + 1; bool isFirstPoint = true; FT_Vector secondControlPoint = new FT_Vector(); FT_Vector thirdControlPoint = new FT_Vector(); bool justFromCurveMode = false; //FT_Vector vpoint = new FT_Vector(); for (; cpoint_index < nextContour; ++cpoint_index) { FT_Vector vpoint = outline.points[cpoint_index]; byte vtag = outline.tags[cpoint_index]; bool has_dropout = (((vtag >> 2) & 0x1) != 0); int dropoutMode = vtag >> 3; if ((vtag & 0x1) != 0) { //on curve if (justFromCurveMode) { switch (controlPointCount) { case 1: { ps.Curve3(secondControlPoint.x / resize, secondControlPoint.y / resize, vpoint.x / resize, vpoint.y / resize); } break; case 2: { ps.Curve4(secondControlPoint.x / resize, secondControlPoint.y / resize, thirdControlPoint.x / resize, thirdControlPoint.y / resize, vpoint.x / resize, vpoint.y / resize); } break; default: { throw new NotSupportedException(); } } controlPointCount = 0; justFromCurveMode = false; } else { if (isFirstPoint) { isFirstPoint = false; ps.MoveTo(vpoint.x / resize, vpoint.y / resize); } else { ps.LineTo(vpoint.x / resize, vpoint.y / resize); } if (has_dropout) { //printf("[%d] on,dropoutMode=%d: %d,y:%d \n", mm, dropoutMode, vpoint.x, vpoint.y); } else { //printf("[%d] on,x: %d,y:%d \n", mm, vpoint.x, vpoint.y); } } } else { switch (controlPointCount) { case 0: { //bit 1 set=> off curve, this is a control point //if this is a 2nd order or 3rd order control point if (((vtag >> 1) & 0x1) != 0) { //printf("[%d] bzc3rd, x: %d,y:%d \n", mm, vpoint.x, vpoint.y); thirdControlPoint = vpoint; } else { //printf("[%d] bzc2nd, x: %d,y:%d \n", mm, vpoint.x, vpoint.y); secondControlPoint = vpoint; } } break; case 1: { if (((vtag >> 1) & 0x1) != 0) { //printf("[%d] bzc3rd, x: %d,y:%d \n", mm, vpoint.x, vpoint.y); thirdControlPoint = vpoint; } else { //we already have prev second control point //so auto calculate line to //between 2 point var mid = GetMidPoint(secondControlPoint, vpoint); //---------- //generate curve3 ps.Curve3(secondControlPoint.x / resize, secondControlPoint.y / resize, mid.x / resize, mid.y / resize); //------------------------ controlPointCount--; //------------------------ //printf("[%d] bzc2nd, x: %d,y:%d \n", mm, vpoint.x, vpoint.y); secondControlPoint = vpoint; } } break; default: { throw new NotSupportedException(); } break; } controlPointCount++; justFromCurveMode = true; } } //-------- //close figure //if in curve mode if (justFromCurveMode) { switch (controlPointCount) { case 0: break; case 1: { ps.Curve3(secondControlPoint.x / resize, secondControlPoint.y / resize, ps.LastMoveX, ps.LastMoveY); } break; case 2: { ps.Curve4(secondControlPoint.x / resize, secondControlPoint.y / resize, thirdControlPoint.x / resize, thirdControlPoint.y / resize, ps.LastMoveX, ps.LastMoveY); } break; default: { throw new NotSupportedException(); } } justFromCurveMode = false; controlPointCount = 0; } ps.CloseFigure(); //-------- startContour++; todoContourCount--; } fontGlyph.flattenVxs = curveFlattener.MakeVxs(fontGlyph.originalVxs); }