Exemple #1
0
        static void init_wipcells(
            fd_Outline o,
            fd_WIPCell[] cells)
        {
            float w = o.bbox.max_x - o.bbox.min_x;
            float h = o.bbox.max_y - o.bbox.min_y;

            for (uint y = 0; y < o.cell_count_y; y++)
            {
                for (uint x = 0; x < o.cell_count_x; x++)
                {
                    var bbox = new fd_Rect
                    {
                        min_x = o.bbox.min_x + ((float)x / o.cell_count_x) * w,
                        min_y = o.bbox.min_y + ((float)y / o.cell_count_y) * h,
                        max_x = o.bbox.min_x + ((float)(x + 1) / o.cell_count_x) * w,
                        max_y = o.bbox.min_y + ((float)(y + 1) / o.cell_count_y) * h,
                    };

                    uint i = y * o.cell_count_x + x;
                    cells[i].bbox      = bbox;
                    cells[i].from      = uint.MaxValue;
                    cells[i].to        = uint.MaxValue;
                    cells[i].value     = 0;
                    cells[i].start_len = 0;
                }
            }
        }
Exemple #2
0
        static void copy_wipcell_values(
            fd_Outline u,
            ref fd_WIPCell[] cells)
        {
            u.cells = new uint[u.cell_count_x * u.cell_count_y];

            for (uint y = 0; y < u.cell_count_y; y++)
            {
                for (uint x = 0; x < u.cell_count_x; x++)
                {
                    uint i = y * u.cell_count_x + x;
                    u.cells[i] = cells[i].value;
                }
            }
        }
Exemple #3
0
        static bool for_each_wipcell_add_bezier(
            fd_Outline o,
            fd_Outline u,
            uint i,
            uint j,
            uint contour_index,
            fd_WIPCell[] cells)
        {
            fd_Rect bezier_bbox;

            Geometry.fd_bezier2_bbox(o.points, (int)i, out bezier_bbox);

            float outline_bbox_w = o.bbox.max_x - o.bbox.min_x;
            float outline_bbox_h = o.bbox.max_y - o.bbox.min_y;

            uint min_x = (uint)((bezier_bbox.min_x - o.bbox.min_x) / outline_bbox_w * o.cell_count_x);
            uint min_y = (uint)((bezier_bbox.min_y - o.bbox.min_y) / outline_bbox_h * o.cell_count_y);
            uint max_x = (uint)((bezier_bbox.max_x - o.bbox.min_x) / outline_bbox_w * o.cell_count_x);
            uint max_y = (uint)((bezier_bbox.max_y - o.bbox.min_y) / outline_bbox_h * o.cell_count_y);

            if (max_x >= o.cell_count_x)
            {
                max_x = o.cell_count_x - 1;
            }
            if (max_y >= o.cell_count_y)
            {
                max_y = o.cell_count_y - 1;
            }

            bool ret = true;

            for (uint y = min_y; y <= max_y; y++)
            {
                for (uint x = min_x; x <= max_x; x++)
                {
                    var cell = cells[y * o.cell_count_x + x];
                    if (Geometry.fd_bbox_bezier2_intersect(cell.bbox, o.points, (int)i))
                    {
                        ret &= wipcell_add_bezier(o, u, i, j, contour_index, cell);
                    }
                }
            }

            return(ret);
        }
Exemple #4
0
        static bool wipcell_add_bezier(
            fd_Outline o,
            fd_Outline u,
            uint i,
            uint j,
            uint contour_index,
            fd_WIPCell cell)
        {
            bool ret            = true;
            uint ucontour_begin = u.contours[(int)contour_index].begin;

            if (cell.to != uint.MaxValue && cell.to != j)
            {
                Debug.Assert(cell.to < j);

                if (cell.from == ucontour_begin)
                {
                    Debug.Assert(cell.to % 2 == 0);
                    Debug.Assert(cell.from % 2 == 0);

                    cell.start_len = (cell.to - cell.from) / 2;
                }
                else
                {
                    cell.value = cell_add_range(cell.value, cell.from, cell.to);
                    if (cell.value == 0)
                    {
                        ret = false;
                    }
                }

                cell.from = j;
            }
            else
            {
                if (cell.from == uint.MaxValue)
                {
                    cell.from = j;
                }
            }

            cell.to = j + 2;
            return(ret);
        }
Exemple #5
0
        static void set_filled_cells(
            fd_Outline u,
            fd_WIPCell[] cells,
            uint filled_cell)
        {
            for (uint y = 0; y < u.cell_count_y; y++)
            {
                for (uint x = 0; x < u.cell_count_x; x++)
                {
                    uint i    = y * u.cell_count_x + x;
                    var  cell = cells[i];

                    if (cell.value == 0 && is_cell_filled(u, cell.bbox))
                    {
                        cell.value = filled_cell;
                    }
                }
            }
        }
Exemple #6
0
        static bool for_each_wipcell_finish_contour(
            fd_Outline o,
            fd_Outline u,
            uint contour_index,
            fd_WIPCell[] cells,
            ref uint max_start_len)
        {
            bool ret = true;

            for (uint y = 0; y < o.cell_count_y; y++)
            {
                for (uint x = 0; x < o.cell_count_x; x++)
                {
                    fd_WIPCell cell = cells[y * o.cell_count_x + x];
                    ret &= wipcell_finish_contour(o, u, contour_index, cell, ref max_start_len);
                }
            }

            return(ret);
        }
Exemple #7
0
        static uint outline_add_filled_line(fd_Outline o)
        {
            o.outline_add_odd_point();

            uint  i  = (uint)o.points.Count;
            float y  = o.bbox.max_y + 1000.0f;
            var   f0 = new Vector2 {
                X = o.bbox.min_x, Y = y
            };
            var f1 = new Vector2 {
                X = o.bbox.min_x + 10.0f, Y = y
            };
            var f2 = new Vector2 {
                X = o.bbox.min_x + 20.0f, Y = y
            };

            o.add_outline_point(f0);
            o.add_outline_point(f1);
            o.add_outline_point(f2);

            return(i);
        }
Exemple #8
0
        fd_Outline fd_outline_decompose(FT_Outline src)
        {
            var o = new fd_Outline();

            if (Form == LongForm.Long4)
            {
                var bbox4 = new FT_BBox4();
                var err   = FT_Outline_Get_BBox_4(ref src, ref bbox4);
                if (err != FT_Error.Ok)
                {
                    throw new InvalidOperationException("FT_Outline_Get_BBox_4 failed");
                }

                o.bbox = new fd_Rect
                {
                    min_x = (float)bbox4.xMin / 64.0f,
                    min_y = (float)bbox4.yMin / 64.0f,
                    max_x = (float)bbox4.xMax / 64.0f,
                    max_y = (float)bbox4.yMax / 64.0f,
                };

                var funcs = new FT_Outline_Funcs_4
                {
                    move_to  = Marshal.GetFunctionPointerForDelegate <MoveToFunc_4>(o.MoveTo_4),
                    line_to  = Marshal.GetFunctionPointerForDelegate <LineToFunc_4>(o.LineTo_4),
                    conic_to = Marshal.GetFunctionPointerForDelegate <ConicToFunc_4>(o.ConicTo_4),
                    cubic_to = Marshal.GetFunctionPointerForDelegate <CubicToFunc_4>(o.CubicTo_4),
                };

                err = FT_Outline_Decompose_4(ref src, ref funcs, IntPtr.Zero);
                if (err != FT_Error.Ok)
                {
                    throw new InvalidOperationException("FT_Outline_Decompose_4 failed");
                }
            }
            else
            {
                var bbox8 = new FT_BBox8();
                var err   = FT_Outline_Get_BBox_8(ref src, ref bbox8);
                if (err != FT_Error.Ok)
                {
                    throw new InvalidOperationException("FT_Outline_Get_BBox_8 failed");
                }

                o.bbox = new fd_Rect
                {
                    min_x = (float)bbox8.xMin / 64.0f,
                    min_y = (float)bbox8.yMin / 64.0f,
                    max_x = (float)bbox8.xMax / 64.0f,
                    max_y = (float)bbox8.yMax / 64.0f,
                };

                var funcs = new FT_Outline_Funcs_8
                {
                    move_to  = Marshal.GetFunctionPointerForDelegate <MoveToFunc_8>(o.MoveTo_8),
                    line_to  = Marshal.GetFunctionPointerForDelegate <LineToFunc_8>(o.LineTo_8),
                    conic_to = Marshal.GetFunctionPointerForDelegate <ConicToFunc_8>(o.ConicTo_8),
                    cubic_to = Marshal.GetFunctionPointerForDelegate <CubicToFunc_8>(o.CubicTo_8),
                };

                err = FT_Outline_Decompose_8(ref src, ref funcs, IntPtr.Zero);

                if (err != FT_Error.Ok)
                {
                    throw new InvalidOperationException("FT_Outline_Decompose_4 failed");
                }
            }

            if (o.contours.Count > 0)
            {
                o.contours[o.contours.Count - 1].end = (uint)o.points.Count - 1;
            }

            return(o);
        }
Exemple #9
0
        static bool try_to_fit_in_cell_count(
            fd_Outline original,
            out fd_Outline replacement)
        {
            bool ret = true;

            var cells = new fd_WIPCell[original.cell_count_x * original.cell_count_y];

            init_wipcells(original, cells);

            var temp = new fd_Outline
            {
                bbox         = original.bbox,
                cell_count_x = original.cell_count_x,
                cell_count_y = original.cell_count_y,
            };

            var num_of_contours = original.contours.Count;

            for (uint contour_index = 0; contour_index < num_of_contours; contour_index++)
            {
                uint contour_begin = original.contours[(int)contour_index].begin;
                uint contour_end   = original.contours[(int)contour_index].end;

                temp.outline_add_odd_point();

                var urange = new fd_ContourRange
                {
                    begin = temp.num_of_points,
                    end   = temp.num_of_points + contour_end - contour_begin
                };
                temp.add_outline_contour(urange);

                for (uint i = contour_begin; i < contour_end; i += 2)
                {
                    var p0 = original.points[(int)i];
                    var p1 = original.points[(int)(i + 1)];
                    //float *p2 = o.points[i + 2];

                    uint j = temp.num_of_points;
                    temp.add_outline_point(p0);
                    temp.add_outline_point(p1);

                    ret &= for_each_wipcell_add_bezier(original, temp, i, j, contour_index, cells);
                }

                uint max_start_len = 0;
                ret &= for_each_wipcell_finish_contour(original, temp, contour_index, cells, ref max_start_len);

                uint continuation_end = contour_begin + max_start_len * 2;
                for (uint i = contour_begin; i < continuation_end; i += 2)
                {
                    temp.add_outline_point(original.points[(int)i]);
                    temp.add_outline_point(original.points[(int)(i + 1)]);
                }

                var plast = original.points[(int)continuation_end];
                temp.add_outline_point(plast);
            }

            if (!ret)
            {
                temp.fd_outline_destroy();
                replacement = null;
                return(ret);
            }

            uint filled_line = outline_add_filled_line(temp);
            uint filled_cell = make_cell_from_single_edge(filled_line);

            set_filled_cells(temp, cells, filled_cell);

            copy_wipcell_values(temp, ref cells);
            original.fd_outline_destroy();
            replacement = temp;
            return(ret);
        }
Exemple #10
0
        internal static fd_Outline fd_outline_fix_thin_lines(fd_Outline src)
        {
            var dst = new fd_Outline
            {
                bbox = src.bbox,
            };

            for (var contour_index = 0; contour_index < src.contours.Count; contour_index++)
            {
                var contour_begin = src.contours[contour_index].begin;
                var contour_end   = src.contours[contour_index].end;

                dst.outline_add_odd_point();

                var urange = new fd_ContourRange
                {
                    begin = (uint)dst.points.Count,
                    end   = uint.MaxValue
                };
                dst.add_outline_contour(urange);

                for (int i = (int)contour_begin; i < contour_end; i += 2)
                {
                    var p0 = src.points[i];
                    var p1 = src.points[i + 1];
                    var p2 = src.points[i + 2];

                    Vector2 mid, midp1;
                    mid   = Vector2.Lerp(p0, p2, 0.5f);
                    midp1 = p1 - mid;

                    var bezier = new List <Vector2> {
                        p0,
                        p1,
                        p2
                    };

                    bezier[1] += midp1;

                    /*
                     * bool subdivide = false;
                     * if (i > 2)
                     * {
                     *  uint jbegin = contour_begin;
                     *  if (i == contour_end - 2) jbegin += 2;
                     *
                     *  for (uint j = jbegin; j < i - 2; j += 2)
                     *  {
                     *      float *q0 = o.points[j];
                     *      float *q2 = o.points[j + 2];
                     *
                     *      if (fd_bezier2_line_is_intersecting(bezier, q0, q2))
                     *          subdivide = true;
                     *  }
                     * }
                     *
                     * uint jend = contour_end;
                     * if (i == contour_begin) jend -= 2;
                     *
                     * for (uint j = i + 2; j < jend; j += 2)
                     * {
                     *  float *q0 = o.points[j];
                     *  float *q2 = o.points[j + 2];
                     *
                     *  if (fd_bezier2_line_is_intersecting(bezier, q0, q2))
                     *      subdivide = true;
                     * }
                     */
                    bool subdivide = false;
                    for (int j = (int)contour_begin; j < contour_end; j += 2)
                    {
                        if (i == contour_begin && j == contour_end - 2)
                        {
                            continue;
                        }
                        if (i == contour_end - 2 && j == contour_begin)
                        {
                            continue;
                        }
                        if (j + 2 >= i && j <= i + 2)
                        {
                            continue;
                        }

                        var q0 = src.points[j];
                        //float *q1 = o.points[j + 1];
                        var q2 = src.points[j + 2];

                        if (Geometry.fd_bezier2_line_is_intersecting(bezier, 0, q0, q2))
                        {
                            subdivide = true;
                        }
                    }

                    if (subdivide)
                    {
                        var newp = new Vector2[3];
                        Geometry.fd_bezier2_split_3p(newp, src.points, i, 0.5f);

                        dst.add_outline_point(p0);
                        dst.add_outline_point(newp[0]);
                        dst.add_outline_point(newp[1]);
                        dst.add_outline_point(newp[2]);
                    }
                    else
                    {
                        dst.add_outline_point(p0);
                        dst.add_outline_point(p1);
                    }
                }

                var temp = dst.contours[(int)contour_index];
                temp.end = (uint)dst.points.Count;
                dst.contours[(int)contour_index] = temp;
                dst.add_outline_point(src.points[(int)contour_end]);
            }

            src.fd_outline_destroy();
            return(dst);
        }
Exemple #11
0
        static bool wipcell_finish_contour(
            fd_Outline o,
            fd_Outline u,
            uint contour_index,
            fd_WIPCell cell,
            ref uint max_start_len)
        {
            bool ret            = true;
            uint ucontour_begin = u.contours[(int)contour_index].begin;
            uint ucontour_end   = u.contours[(int)contour_index].end;

            // max_start_len = uint.MinValue;

            if (cell.to < ucontour_end)
            {
                cell.value = cell_add_range(cell.value, cell.from, cell.to);
                if (cell.value == 0)
                {
                    ret = false;
                }

                cell.from = uint.MaxValue;
                cell.to   = uint.MaxValue;
            }

            Debug.Assert(cell.to == uint.MaxValue || cell.to == ucontour_end);
            cell.to = uint.MaxValue;

            if (cell.from != uint.MaxValue && cell.start_len != 0)
            {
                cell.value = cell_add_range(cell.value, cell.from, ucontour_end + cell.start_len * 2);
                if (cell.value == 0)
                {
                    ret = false;
                }

                max_start_len  = Math.Max(max_start_len, cell.start_len);
                cell.from      = uint.MaxValue;
                cell.start_len = 0;
            }

            if (cell.from != uint.MaxValue)
            {
                cell.value = cell_add_range(cell.value, cell.from, ucontour_end);
                if (cell.value == 0)
                {
                    ret = false;
                }

                cell.from = uint.MaxValue;
            }

            if (cell.start_len != 0)
            {
                cell.value = cell_add_range(cell.value, ucontour_begin, ucontour_begin + cell.start_len * 2);
                if (cell.value == 0)
                {
                    ret = false;
                }

                cell.start_len = 0;
            }

            Debug.Assert(cell.from == uint.MaxValue && cell.to == uint.MaxValue);
            return(ret);
        }
Exemple #12
0
        // TODO: optimize
        static bool is_cell_filled(
            fd_Outline o,
            fd_Rect bbox)
        {
            var p = new Vector2
            {
                X = (bbox.max_x + bbox.min_x) / 2.0f,
                Y = (bbox.max_y + bbox.min_y) / 2.0f,
            };

            float mindist = float.MaxValue;
            float v       = float.MaxValue;
            uint  j       = uint.MaxValue;

            var num_of_contours = o.contours.Count;

            for (int contour_index = 0; contour_index < num_of_contours; contour_index++)
            {
                uint contour_begin = o.contours[contour_index].begin;
                uint contour_end   = o.contours[contour_index].end;

                for (int i = (int)contour_begin; i < contour_end; i += 2)
                {
                    var p0 = o.points[i];
                    var p1 = o.points[i + 1];
                    var p2 = o.points[i + 2];

                    float t = Geometry.fd_line_calculate_t(p0, p2, p);

                    Vector2 p02;
                    p02 = Vector2.Lerp(p0, p2, t);

                    float udist = Vector2.Distance(p02, p);

                    if (udist < mindist + 0.0001f)
                    {
                        float d = Geometry.fd_line_signed_distance(p0, p2, p);

                        if (udist >= mindist && i > contour_begin)
                        {
                            float lastd = i == contour_end - 2 && j == contour_begin
                                ? Geometry.fd_line_signed_distance(p0, p2, o.points[(int)(contour_begin + 2)])
                                : Geometry.fd_line_signed_distance(p0, p2, o.points[i - 2]);

                            if (lastd < 0.0)
                            {
                                v = Math.Max(d, v);
                            }
                            else
                            {
                                v = Math.Min(d, v);
                            }
                        }
                        else
                        {
                            v = d;
                        }

                        mindist = Math.Min(mindist, udist);
                        j       = (uint)i;
                    }
                }
            }

            return(v > 0.0f);
        }
Exemple #13
0
        internal static fd_Outline fd_outline_make_cells(fd_Outline original)
        {
            const int FD_OUTLINE_MAX_POINTS = (255 * 2);

            int no_of_points = original.points.Count;

            if (no_of_points > FD_OUTLINE_MAX_POINTS)
            {
                return(original);
            }

            float w = original.bbox.max_x - original.bbox.min_x;
            float h = original.bbox.max_y - original.bbox.min_y;

            float multiplier = 0.5f;

            if (h > w * 1.8f || w > h * 1.8f)
            {
                multiplier = 1.0f;
            }

            uint c = uint32_to_pow2((uint)Math.Sqrt(no_of_points * 0.75f));

            original.cell_count_x = c;
            original.cell_count_y = c;

            if (h > w * 1.8f)
            {
                original.cell_count_x /= 2;
            }
            if (w > h * 1.8f)
            {
                original.cell_count_y /= 2;
            }

            while (true)
            {
                if (try_to_fit_in_cell_count(original, out fd_Outline replacement))
                {
                    return(replacement);
                }

                if (original.cell_count_x > 64 || original.cell_count_y > 64)
                {
                    original.cell_count_x = 0;
                    original.cell_count_y = 0;
                    return(original);
                }

                if (original.cell_count_x == original.cell_count_y)
                {
                    if (w > h)
                    {
                        original.cell_count_x *= 2;
                    }
                    else
                    {
                        original.cell_count_y *= 2;
                    }
                }
                else
                {
                    if (original.cell_count_x < original.cell_count_y)
                    {
                        original.cell_count_x *= 2;
                    }
                    else
                    {
                        original.cell_count_y *= 2;
                    }
                }
            }
        }