Esempio n. 1
0
        public static void SetupMaterialWithOutlineMode(Material material, OutlineMode outlineMode)
        {
            switch ((OutlineMode)material.GetFloat("_OutlineMode"))
            {
            case OutlineMode.None:
                material.EnableKeyword("NO_OUTLINE");
                material.DisableKeyword("TINTED_OUTLINE");
                material.DisableKeyword("COLORED_OUTLINE");
                break;

            case OutlineMode.Tinted:
                material.DisableKeyword("NO_OUTLINE");
                material.EnableKeyword("TINTED_OUTLINE");
                material.DisableKeyword("COLORED_OUTLINE");
                break;

            case OutlineMode.Colored:
                material.DisableKeyword("NO_OUTLINE");
                material.DisableKeyword("TINTED_OUTLINE");
                material.EnableKeyword("COLORED_OUTLINE");
                break;

            default:
                break;
            }
        }
Esempio n. 2
0
        public void Draw(GUIStyle toolbarstyle, Material mat)
        {
            Color cachedColor = GUI.color;

            GUI.color = new Color(cachedColor.r, cachedColor.g, cachedColor.b, 0.5f);
            EditorGUILayout.BeginHorizontal(toolbarstyle);
            GUI.color = cachedColor;
            EditorVariablesManager.OutlineActiveMode.Value = GUILayout.Toggle(EditorVariablesManager.OutlineActiveMode.Value, EditorVariablesManager.OutlineActiveMode.LabelName, "foldout", GUILayout.ExpandWidth(true));
            EditorGUI.BeginChangeCheck();
            m_enabled = EditorGUILayout.Toggle("", m_enabled, (EditorGUIUtility.isProSkin ? "OL ToggleWhite" : "OL Toggle"), GUILayout.Width(16));
            if (EditorGUI.EndChangeCheck() && m_enabled)
            {
                UpdateToMaterial(mat);
            }
            EditorGUILayout.EndHorizontal();

            if (EditorVariablesManager.OutlineActiveMode.Value)
            {
                cachedColor = GUI.color;
                GUI.color   = new Color(cachedColor.r, cachedColor.g, cachedColor.b, (EditorGUIUtility.isProSkin ? 0.5f : 0.25f));
                EditorGUILayout.BeginVertical("TE NodeBackground");
                GUI.color = cachedColor;

                EditorGUILayout.Separator();
                EditorGUI.BeginDisabledGroup(!m_enabled);

                EditorGUI.indentLevel += 1;
                {
                    m_mode = ( OutlineMode )EditorGUILayout.EnumPopup(ModePropertyStr, m_mode);

                    EditorGUI.BeginChangeCheck();
                    m_outlineColor = EditorGUILayout.ColorField(OutlineColorLabel, m_outlineColor);
                    if (EditorGUI.EndChangeCheck() && mat != null)
                    {
                        if (mat.HasProperty(ColorPropertyName))
                        {
                            mat.SetColor(ColorPropertyName, m_outlineColor);
                        }
                    }

                    EditorGUI.BeginChangeCheck();
                    m_outlineWidth = EditorGUILayout.FloatField(OutlineWidthLabel, m_outlineWidth);
                    if (EditorGUI.EndChangeCheck() && mat != null)
                    {
                        if (mat.HasProperty(WidthPropertyName))
                        {
                            mat.SetFloat(WidthPropertyName, m_outlineWidth);
                        }
                    }
                }
                EditorGUI.indentLevel -= 1;
                EditorGUI.EndDisabledGroup();
                EditorGUILayout.Separator();
                EditorGUILayout.EndVertical();
            }
        }
Esempio n. 3
0
 public void ReadFromString(ref uint index, ref string[] nodeParams)
 {
     m_enabled      = Convert.ToBoolean(nodeParams[index++]);
     m_outlineWidth = Convert.ToSingle(nodeParams[index++]);
     m_outlineColor = IOUtils.StringToColor(nodeParams[index++]);
     if (UIUtils.CurrentShaderVersion() > 5004)
     {
         m_mode = ( OutlineMode )Enum.Parse(typeof(OutlineMode), nodeParams[index++]);
     }
 }
Esempio n. 4
0
        public override float DrawInner(ref Rect r)
        {
            float prevYpos = r.y;

            r.y = 0;


            r.xMin += 20;
            r.y    += 20;


            cullMode = (CullMode)UndoableLabeledEnumPopup(r, "Face Culling", cullMode, "face culling");
            r.y     += 20;

            GUI.enabled   = ps.catLighting.renderPath == SFPSC_Lighting.RenderPath.Forward;
            normalQuality = (NormalQuality)UndoableContentScaledToolbar(r, "Normal Quality", (int)normalQuality, strNormalQuality, "normal quality");
            GUI.enabled   = true;
            r.y          += 20;

            vertexPositioning = (VertexPositioning)UndoableContentScaledToolbar(r, "Vertex Positioning", (int)vertexPositioning, strVertexPositioning, "vertex positioning");
            r.y += 20;

            GUI.enabled = ps.mOut.normal.IsConnectedEnabledAndAvailable();
            normalSpace = (NormalSpace)UndoableContentScaledToolbar(r, "Normal Space", (int)normalSpace, strNormalSpace, "normal space");
            GUI.enabled = true;
            r.y        += 20;

            vertexOffsetMode = (VertexOffsetMode)UndoableContentScaledToolbar(r, "Vertex offset mode", (int)vertexOffsetMode, vertexOffsetModeStr, "vertex offset mode");
            r.y += 20;

            GUI.enabled      = ps.HasTessellation();
            tessellationMode = (TessellationMode)UndoableLabeledEnumPopupNamed(r, "Tessellation Mode", tessellationMode, tessModeStr, "tessellation mode");
            GUI.enabled      = true;
            r.y += 20;

            GUI.enabled = ps.HasOutline();
            outlineMode = (OutlineMode)UndoableLabeledEnumPopupNamed(r, "Outline Extrude Direction", outlineMode, outlineModeStr, "outline mode");
            GUI.enabled = true;
            r.y        += 20;

            highQualityScreenCoords = UndoableToggle(r, highQualityScreenCoords, "Per-pixel screen coordinates", "per-pixel screen coordinates", null);
            r.y += 20;

            showPixelSnap = UndoableToggle(r, showPixelSnap, "Show 2D sprite pixel snap option in material", "show pixel snap", null);
            r.y          += 20;

            //billboard.
            billboard = (BILLBOARD_TYPE)UndoableContentScaledToolbar(r, "billboard", (int)billboard, strBillboard, "NONE");
            r.y      += 20;

            r.y += prevYpos;

            return((int)r.yMax);
        }
        private void SetMode(OutlineMode mode)
        {
            _mode = mode;

            if (mode == OutlineMode.Solid)
            {
                _vPassMaterial.SetFloat(IntensityNameId, OutlineRenderer.SolidIntensity);
            }
            else
            {
                _vPassMaterial.SetFloat(IntensityNameId, _intensity);
            }
        }
Esempio n. 6
0
 public static FontOutline?GetOutline(string fontFaceName, string text, OutlineMode outlineMode)
 {
     return(Gdi32FontPool.GetPoolingFont(
                faceName: fontFaceName,
                fontSizeUnit: FontSizeUnit.Pixel,
                size: 12,
                weight: FW_NORMAL,
                italic: 0,
                underline: 0,
                strikeOut: 0,
                charSet: 1,
                fontQuality: Gdi32FontQuality.Default
                ).GetOutline(text, outlineMode));
 }
Esempio n. 7
0
        public override float DrawInner(ref Rect r)
        {
            float prevYpos = r.y;

            r.y = 0;


            r.xMin += 20;
            r.y    += 20;


            cullMode = (CullMode)UndoableLabeledEnumPopup(r, "面剔除", cullMode, "face culling");
            r.y     += 20;

            GUI.enabled   = ps.catLighting.renderPath == SFPSC_Lighting.RenderPath.Forward;
            normalQuality = (NormalQuality)UndoableContentScaledToolbar(r, "法线质量", (int)normalQuality, strNormalQuality, "normal quality");
            GUI.enabled   = true;
            r.y          += 20;

            vertexPositioning = (VertexPositioning)UndoableContentScaledToolbar(r, "顶点定位", (int)vertexPositioning, strVertexPositioning, "vertex positioning");
            r.y += 20;

            GUI.enabled = ps.mOut.normal.IsConnectedEnabledAndAvailable();
            normalSpace = (NormalSpace)UndoableContentScaledToolbar(r, "法线空间", (int)normalSpace, strNormalSpace, "normal space");
            GUI.enabled = true;
            r.y        += 20;

            vertexOffsetMode = (VertexOffsetMode)UndoableContentScaledToolbar(r, "顶点偏移模式", (int)vertexOffsetMode, vertexOffsetModeStr, "vertex offset mode");
            r.y += 20;

            GUI.enabled      = ps.HasTessellation();
            tessellationMode = (TessellationMode)UndoableLabeledEnumPopupNamed(r, "细分曲面模式", tessellationMode, tessModeStr, "tessellation mode");
            GUI.enabled      = true;
            r.y += 20;

            GUI.enabled = ps.HasOutline();
            outlineMode = (OutlineMode)UndoableLabeledEnumPopupNamed(r, "描边拉伸方向", outlineMode, outlineModeStr, "outline mode");
            GUI.enabled = true;
            r.y        += 20;

            highQualityScreenCoords = UndoableToggle(r, highQualityScreenCoords, "每像素屏幕坐标(开启:像素 关闭:顶点)", "per-pixel screen coordinates", null);
            r.y += 20;

            showPixelSnap = UndoableToggle(r, showPixelSnap, "在材质中显示二维切片 Pixel snap(像素捕捉)选项", "show pixel snap", null);
            r.y          += 20;

            r.y += prevYpos;

            return((int)r.yMax);
        }
 internal void UpdateChanged()
 {
     if (_outlineSettings != null)
     {
         if (_outlineColor != _outlineSettings.OutlineColor ||
             _outlineWidth != _outlineSettings.OutlineWidth ||
             _outlineIntensity != _outlineSettings.OutlineIntensity ||
             _outlineMode != _outlineSettings.OutlineMode)
         {
             _outlineColor     = _outlineSettings.OutlineColor;
             _outlineWidth     = _outlineSettings.OutlineWidth;
             _outlineIntensity = _outlineSettings.OutlineIntensity;
             _outlineMode      = _outlineSettings.OutlineMode;
             _changed          = true;
         }
     }
 }
Esempio n. 9
0
        public override void Deserialize(string key, string value)
        {
            switch (key)
            {
            case "billboard":
                billboard = (BILLBOARD_TYPE)int.Parse(value);
                break;

            case "vtps":
                vertexPositioning = (VertexPositioning)int.Parse(value);
                break;

            case "nrmq":
                normalQuality = (NormalQuality)int.Parse(value);
                break;

            case "nrsp":
                normalSpace = (NormalSpace)int.Parse(value);
                break;

            case "vomd":
                vertexOffsetMode = (VertexOffsetMode)int.Parse(value);
                break;

            case "hqsc":
                highQualityScreenCoords = bool.Parse(value);
                break;

            case "spxs":
                showPixelSnap = bool.Parse(value);
                break;

            case "tesm":
                tessellationMode = (TessellationMode)int.Parse(value);
                break;

            case "olmd":
                outlineMode = (OutlineMode)int.Parse(value);
                break;

            case "culm":
                cullMode = (CullMode)int.Parse(value);
                break;
            }
        }
Esempio n. 10
0
    void DoOutline()
    {
        MaterialProperty outlineMode = FindProperty("_OutlineMode");
        OutlineMode      oMode       = (OutlineMode)outlineMode.floatValue;

        EditorGUI.BeginChangeCheck();
        oMode = (OutlineMode)EditorGUILayout.EnumPopup(MakeLabel("Outline Mode"), oMode);

        if (EditorGUI.EndChangeCheck())
        {
            RecordAction("Outline Mode");
            outlineMode.floatValue = (float)oMode;

            foreach (var obj in outlineMode.targets)
            {
                SetupMaterialShaderSelect((Material)obj);
            }
        }
        EditorGUI.indentLevel += 2;
        switch (oMode)
        {
        case OutlineMode.Artsy:
            DoOutlineArtsy();
            break;

        case OutlineMode.Normal:
        case OutlineMode.Screenspace:
            DoOutlineNormal();
            break;

        case OutlineMode.None:
        default:
            break;
        }
        EditorGUI.indentLevel -= 2;
    }
Esempio n. 11
0
        public void Draw(ParentNode owner, GUIStyle toolbarstyle, Material mat)
        {
            Color cachedColor = GUI.color;

            GUI.color = new Color(cachedColor.r, cachedColor.g, cachedColor.b, 0.5f);
            EditorGUILayout.BeginHorizontal(toolbarstyle);
            GUI.color = cachedColor;
            owner.ContainerGraph.ParentWindow.InnerWindowVariables.OutlineActiveMode = owner.GUILayoutToggle(owner.ContainerGraph.ParentWindow.InnerWindowVariables.OutlineActiveMode, EditorVariablesManager.OutlineActiveMode.LabelName, UIUtils.MenuItemToggleStyle, GUILayout.ExpandWidth(true));
            EditorGUI.BeginChangeCheck();
            m_enabled = owner.EditorGUILayoutToggle(string.Empty, m_enabled, UIUtils.MenuItemEnableStyle, GUILayout.Width(16));
            if (EditorGUI.EndChangeCheck())
            {
                if (m_enabled)
                {
                    UpdateToMaterial(mat);
                }

                UIUtils.RequestSave();
            }
            EditorGUILayout.EndHorizontal();

            if (owner.ContainerGraph.ParentWindow.InnerWindowVariables.OutlineActiveMode)
            {
                cachedColor = GUI.color;
                GUI.color   = new Color(cachedColor.r, cachedColor.g, cachedColor.b, (EditorGUIUtility.isProSkin ? 0.5f : 0.25f));
                EditorGUILayout.BeginVertical(UIUtils.MenuItemBackgroundStyle);
                GUI.color = cachedColor;

                EditorGUILayout.Separator();
                EditorGUI.BeginDisabledGroup(!m_enabled);

                EditorGUI.indentLevel += 1;
                {
                    m_mode = (OutlineMode)owner.EditorGUILayoutEnumPopup(ModePropertyStr, m_mode);

                    EditorGUI.BeginChangeCheck();
                    m_outlineColor = owner.EditorGUILayoutColorField(OutlineColorLabel, m_outlineColor);
                    if (EditorGUI.EndChangeCheck() && mat != null)
                    {
                        if (mat.HasProperty(ColorPropertyName))
                        {
                            mat.SetColor(ColorPropertyName, m_outlineColor);
                        }
                    }

                    EditorGUI.BeginChangeCheck();
                    m_outlineWidth = owner.EditorGUILayoutFloatField(OutlineWidthLabel, m_outlineWidth);
                    if (EditorGUI.EndChangeCheck() && mat != null)
                    {
                        if (mat.HasProperty(WidthPropertyName))
                        {
                            mat.SetFloat(WidthPropertyName, m_outlineWidth);
                        }
                    }

                    m_noFog = owner.EditorGUILayoutToggle(NoFogStr, m_noFog);
                }

                EditorGUI.indentLevel -= 1;
                EditorGUI.EndDisabledGroup();
                EditorGUILayout.Separator();
                EditorGUILayout.EndVertical();
            }
        }
        public static void DrawOutline(Rect rect, Color color, float borderWidth = 1f, OutlineMode mode = OutlineMode.Outside)
        {
            if (Event.current.type == EventType.Repaint)
            {
                Texture2D tex = EditorGUIUtility.whiteTexture;
                GUI.color = color;

                switch (mode)
                {
                case OutlineMode.Outside:
                    GUI.DrawTexture(new Rect(rect.xMin - borderWidth, rect.yMin - borderWidth, borderWidth, rect.height + borderWidth * 2), tex); // left
                    GUI.DrawTexture(new Rect(rect.xMax, rect.yMin - borderWidth, borderWidth, rect.height + borderWidth * 2), tex);               // right
                    GUI.DrawTexture(new Rect(rect.xMin, rect.yMin - borderWidth, rect.width, borderWidth), tex);                                  // top
                    GUI.DrawTexture(new Rect(rect.xMin, rect.yMax, rect.width + borderWidth, borderWidth), tex);                                  // bottom
                    break;

                case OutlineMode.Centered:
                    GUI.DrawTexture(new Rect(rect.xMin - borderWidth / 2, rect.yMin - borderWidth / 2, borderWidth, rect.height + borderWidth), tex);    // left
                    GUI.DrawTexture(new Rect(rect.xMax - borderWidth / 2, rect.yMin - borderWidth / 2, borderWidth, rect.height + borderWidth), tex);    // right
                    GUI.DrawTexture(new Rect(rect.xMin - borderWidth / 2, rect.yMin - borderWidth / 2, rect.width + borderWidth, borderWidth), tex);     // top
                    GUI.DrawTexture(new Rect(rect.xMin - borderWidth / 2, rect.yMax - borderWidth / 2, rect.width + borderWidth, borderWidth), tex);     // bottom
                    break;

                case OutlineMode.Inside:
                    GUI.DrawTexture(new Rect(rect.xMin, rect.yMin, borderWidth, rect.height), tex);               // left
                    GUI.DrawTexture(new Rect(rect.xMax - borderWidth, rect.yMin, borderWidth, rect.height), tex); // right
                    GUI.DrawTexture(new Rect(rect.xMin, rect.yMin, rect.width, borderWidth), tex);                // top
                    GUI.DrawTexture(new Rect(rect.xMin, rect.yMax - borderWidth, rect.width, borderWidth), tex);  // bottom
                    break;

                default:
                    throw new ArgumentOutOfRangeException("mode", mode, null);
                }

                GUI.color = Color.white;
            }
        }
Esempio n. 13
0
        public FontOutline?GetOutline(string text, OutlineMode outlineMode)
        {
            if (SharedFont.OutlineTextMetric is null)
            {
                return(null);
            }

            // 参考文献
            // http://marupeke296.com/TIPS_Main.html
            // http://marupeke296.com/WINT_GetGlyphOutline.html
            // http://marupeke296.com/DXG_No67_NewFont.html
            // https://msdn.microsoft.com/ja-jp/library/cc410385.aspx
            // https://msdn.microsoft.com/ja-jp/library/cc428640.aspx
            // https://www11.atwiki.jp/slice/pages/78.html
            // http://dendrocopos.jp/tips/win32.html
            // http://www.geocities.co.jp/Playtown-Dice/9391/program/win04.html
            // http://misohena.jp/article/ggo_trap/index.html
            // https://oshiete.goo.ne.jp/qa/4743793.html
            // http://eternalwindows.jp/graphics/bitmap/bitmap12.html
            // https://social.msdn.microsoft.com/Forums/ja-JP/3442d813-823a-449a-993e-7fc073aea949/opentype?forum=vcgeneralja
            // http://phys.cool.coocan.jp/physjpn/htextmetric.htm
            // https://docs.microsoft.com/ja-jp/windows/desktop/api/wingdi/ns-wingdi-_outlinetextmetricw
            //
            // 参考資料
            // https://support.microsoft.com/en-us/help/87115/how-to-getglyphoutline-native-buffer-format
            // http://kone.vis.ne.jp/diary/diaryb08.html
            // https://msdn.microsoft.com/ja-jp/library/windows/desktop/dd144891(v=vs.85).aspx
            //

            try
            {
                GLYPHMETRICS metrics = new GLYPHMETRICS();
                MAT2         matrix  = new MAT2();
                matrix.eM11.value = 1;
                matrix.eM12.value = 0;
                matrix.eM21.value = 0;
                matrix.eM22.value = 1;

                using (var hdc = DeviceContextSafeHandle.CreateMesurementDeviceContext())
                {
                    // アウトライン取得用のフォントを生成。この時フォントサイズは制御店のメッシュサイズと一致させる。
                    // 一致しない場合は取得されるアウトラインの精度が著しく低下する場合がある。
                    var outlineAccessFont = Gdi32FontPool.GetPoolingFont(Key.FaceName, FontSizeUnit.Pixel, SharedFont.OutlineTextMetric.Value.otmEMSquare, Key.Weight, Key.Italic, Key.Underline, Key.StrikeOut, Key.CharSet, Key.FontQuality);

                    if (outlineAccessFont.SharedFont.OutlineTextMetric is null)
                    {
                        return(null);
                    }

                    var selectResult = NativeApi.SelectObject(hdc, outlineAccessFont.Handle);

                    if (selectResult == IntPtr.Zero)
                    {
                        throw new Win32Exception();
                    }

                    NativeApi.GetCharacterPlacement(hdc, text, GCPFlags.GCP_GLYPHSHAPE, out var characterPlacement);

                    if (characterPlacement.Glyphs is null || characterPlacement.Glyphs.Length == 0)
                    {
                        return(null);
                    }

                    var size = NativeApi.GetTextExtentPoint(hdc, text);

                    uint glyphIndex = (uint)characterPlacement.Glyphs[0];

                    uint format = GGO_GLYPH_INDEX | (outlineMode == OutlineMode.Bezier ? GGO_BEZIER : GGO_NATIVE);

                    int bufferSize = (int)NativeApi.GetGlyphOutline(hdc, glyphIndex, format, out metrics, 0, IntPtr.Zero, ref matrix);

                    if (bufferSize <= 0)
                    {
                        return(null);
                    }

                    IntPtr buffer = Marshal.AllocHGlobal(bufferSize);

                    List <TtPolygon> ttPolygons = new List <TtPolygon>();
                    try
                    {
                        uint ret = NativeApi.GetGlyphOutline(hdc, glyphIndex, format, out metrics, (uint)bufferSize, buffer, ref matrix);

                        if (ret == GDI_ERROR)
                        {
                            throw new Win32Exception(Marshal.GetLastWin32Error());
                        }

                        int polygonHeaderSize = Marshal.SizeOf(typeof(TTPOLYGONHEADER));
                        int curveHeaderSize   = Marshal.SizeOf(typeof(TTPOLYCURVEHEADER));
                        int pointFxSize       = Marshal.SizeOf(typeof(POINTFX));

                        int index = 0;
                        while (index < bufferSize)
                        {
                            TTPOLYGONHEADER header = (TTPOLYGONHEADER)Marshal.PtrToStructure(new IntPtr(buffer.ToInt64() + index), typeof(TTPOLYGONHEADER));

                            POINTFX startPoint = header.pfxStart;

                            // サイズをfontEmSquareで指定して内部メッシュと一致させているので、正しくできている限り端数は生じない。
                            Debug.Assert(startPoint.x.fract == 0);
                            Debug.Assert(startPoint.y.fract == 0);

                            int endCurvesIndex = index + header.cb;
                            index += polygonHeaderSize;

                            List <TtPolygonCurve> ttPolygonCurves = new List <TtPolygonCurve>();

                            while (index < endCurvesIndex)
                            {
                                TTPOLYCURVEHEADER curveHeader = (TTPOLYCURVEHEADER)Marshal.PtrToStructure(new IntPtr(buffer.ToInt64() + index), typeof(TTPOLYCURVEHEADER));
                                index += curveHeaderSize;

                                TtPolygonPoint[] curvePoints = new TtPolygonPoint[curveHeader.cpfx];

                                for (int i = 0; i < curveHeader.cpfx; i++)
                                {
                                    var curvePoint = (POINTFX)Marshal.PtrToStructure(new IntPtr(buffer.ToInt64() + index), typeof(POINTFX));

                                    // サイズをfontEmSquareで指定して内部メッシュと一致させているので、正しくできている限り端数は生じない。
                                    // ただし、ベジェ曲線に変換している場合は制御店の創出により端数が生じる。
                                    Debug.Assert(outlineMode != OutlineMode.Native || curvePoint.x.fract == 0);
                                    Debug.Assert(outlineMode != OutlineMode.Native || curvePoint.y.fract == 0);

                                    curvePoints[i] = curvePoint.ToTtPolygonPoint(outlineAccessFont.SharedFont.OutlineTextMetric.Value, metrics);

                                    index += pointFxSize;
                                }

                                TtPrimitiveTypes type;
                                switch (curveHeader.wType)
                                {
                                case TT_PRIM_LINE:
                                    type = TtPrimitiveTypes.Line;
                                    break;

                                case TT_PRIM_QSPLINE:
                                    Debug.Assert(outlineMode == OutlineMode.Native);
                                    type = TtPrimitiveTypes.QuadraticBezierSpline;
                                    break;

                                case TT_PRIM_CSPLINE:
                                    Debug.Assert(outlineMode == OutlineMode.Bezier);
                                    type = TtPrimitiveTypes.CubicBezierSpline;
                                    break;

                                default: throw new FormatException();
                                }

                                ttPolygonCurves.Add(new TtPolygonCurve(type, curvePoints.ToImmutableArray()));
                            }

                            ttPolygons.Add(new TtPolygon(startPoint.ToTtPolygonPoint(outlineAccessFont.SharedFont.OutlineTextMetric.Value, metrics), ttPolygonCurves.ToImmutableArray()));
                        }
                    }
                    finally
                    {
                        Marshal.FreeHGlobal(buffer);
                    }

                    Debug.Assert(metrics.gmCellIncX >= 0);
                    Debug.Assert(metrics.gmCellIncY >= 0);

                    var glyphMetrics = new GlyphMetrics(metrics.gmBlackBoxX, metrics.gmBlackBoxY, metrics.gmptGlyphOrigin.x, metrics.gmptGlyphOrigin.y, metrics.gmCellIncX, metrics.gmCellIncY);

                    return(new FontOutline(
                               outlineAccessFont.SharedFont.OutlineTextMetric.Value.otmEMSquare,
                               outlineAccessFont.SharedFont.OutlineTextMetric.Value.otmMacAscent,
                               glyphMetrics,
                               ttPolygons.ToImmutableArray()
                               ));
                }
            }
            catch (Win32Exception ex)
            {
                Debug.WriteLine(ex);
                return(null);
            }
        }