Exemple #1
0
            private GlyphPage FindPage(int width, int height, out int packX, out int packY)
            {
                foreach (var page in pages)
                {
                    if (page.Pack(width, height, out var rect))
                    {
                        packX = rect.X;
                        packY = rect.Y;
                        return(page);
                    }
                }

                //  none found, make a new page
                {
                    var result = new GlyphPage(graphicsDevice, TextureSize);
                    pages.Add(result);
                    if (!result.Pack(width, height, out var rect))
                    {
                        throw new Exception("Failed to pack item even in new page");
                    }

                    packX = rect.X;
                    packY = rect.Y;
                    return(result);
                }
            }
        // load one single glyph into the cache
        private GlyphData Load(char glyph, FormatOptions formatOptions)
        {
            int fontId = GetFontId(IsAnsiChar(glyph) ? formatOptions.AnsiFont : formatOptions.Font);
            var font = m_registeredFonts[fontId];
            uint glyphId = ((uint)fontId << 16) + glyph;

            GlyphData glyphData;
            if (m_loadedGlyphs.TryGetValue(glyphId, out glyphData))
            {
                glyphData.m_timeStamp = m_timeStamp;
                return glyphData;
            }

            var str = glyph.ToString();
            var chRect = MeasureCharacter(glyph, m_registeredFonts[fontId].m_fontObject);
            chRect.Inflate(font.m_outlineThickness * 0.5f, font.m_outlineThickness * 0.5f);

            int width = Math.Max((int)Math.Ceiling(chRect.Width), 1);
            int height = Math.Max((int)Math.Ceiling(chRect.Height), 1);
            int pagesInX = (width - 1) / PageSize + 1;
            int pagesInY = (height - 1) / PageSize + 1;

            GlyphPage[] pages = new GlyphPage[pagesInX * pagesInY];
            for (int i = 0; i < pages.Length; ++i)
            {
                pages[i].m_x = i % pagesInX;
                pages[i].m_y = i / pagesInX;
                pages[i].m_pageIndex = RequestPage();
            }

            using (var bmp = new SystemDrawing.Bitmap(pagesInX * PageSize, pagesInY * PageSize))
            using (var g = SystemDrawing.Graphics.FromImage(bmp))
            using (var memStream = new MemoryStream())
            {
                // draw text using GDI+
                g.TextRenderingHint = SystemDrawing.Text.TextRenderingHint.AntiAliasGridFit;
                g.SmoothingMode = SystemDrawing.Drawing2D.SmoothingMode.AntiAlias;
                g.InterpolationMode = SystemDrawing.Drawing2D.InterpolationMode.HighQualityBicubic;

                if (font.m_outlineThickness > 0)
                {
                    SystemDrawing.Pen outlinePen;
                    if (!m_outlinePensWithWidths.TryGetValue(font.m_outlineThickness, out outlinePen))
                    {
                        outlinePen = new SystemDrawing.Pen(SystemDrawing.Color.Gray, font.m_outlineThickness);
                        outlinePen.MiterLimit = font.m_outlineThickness;
                        m_outlinePensWithWidths.Add(font.m_outlineThickness, outlinePen);
                    }

                    // draw outline
                    using (var outlinePath = new SystemDrawing.Drawing2D.GraphicsPath())
                    {
                        outlinePath.AddString(str,
                            font.m_fontObject.FontFamily,
                            (int)font.m_fontObject.Style,
                            g.DpiX * font.m_fontObject.SizeInPoints / 72,
                            new SystemDrawing.PointF(-chRect.Left, -chRect.Top),
                            SystemDrawing.StringFormat.GenericDefault);
                        g.DrawPath(outlinePen, outlinePath);
                        g.FillPath(m_whiteBrush, outlinePath);
                    }
                }
                else
                {
                    g.DrawString(str, font.m_fontObject, m_whiteBrush, new SystemDrawing.PointF(-chRect.Left, -chRect.Top));
                }

                bmp.Save(memStream, System.Drawing.Imaging.ImageFormat.Png);
                using (var tmpTexture = Texture2D.FromStream(GameApp.Instance.GraphicsDevice, memStream))
                {
                    var device = GameApp.Instance.GraphicsDevice;
                    device.DepthStencilState = DepthStencilState.None;
                    device.RasterizerState = RasterizerState.CullCounterClockwise;
                    device.Indices = null;

                    m_effect.CurrentTechnique = m_techBlit;
                    m_paramTexture.SetValue(tmpTexture);

                    foreach (var batch in pages.GroupBy(page => page.m_pageIndex / PagesInOneCacheTexture))
                    {
                        var textureId = batch.Key;
                        device.SetRenderTarget(m_cacheTextures[textureId].m_physicalRTTexture);
                        device.BlendState = m_channelMasks[textureId % 4];

                        var pagesInBatch = batch.ToArray();
                        var vertices = new VertexDataBlit[pagesInBatch.Length * 6];
                        for (int i = 0; i < pagesInBatch.Length; ++i)
                        {
                            var page = pagesInBatch[i];
                            var dstRectLeft = (page.m_pageIndex % PagesInOneCacheTexture) % PagesInOneRow * PageSize;
                            var dstRectTop = (page.m_pageIndex % PagesInOneCacheTexture) / PagesInOneRow * PageSize;

                            float posLeft = (dstRectLeft - 0.5f) / CacheTextureSize * 2 - 1;
                            float posTop = 1 - (dstRectTop - 0.5f) / CacheTextureSize * 2;
                            float posWidth = PageSize / (float)CacheTextureSize * 2;
                            float posHeight = -PageSize / (float)CacheTextureSize * 2;

                            float uvLeft = page.m_x / (float)pagesInX;
                            float uvTop = page.m_y / (float)pagesInY;
                            float uvWidth = 1.0f / pagesInX;
                            float uvHeight = 1.0f / pagesInY;

                            // left-top
                            vertices[i * 6 + 0].pos = new Vector2(posLeft, posTop);
                            vertices[i * 6 + 0].uv = new Vector2(uvLeft, uvTop);

                            // right-top
                            vertices[i * 6 + 1].pos = vertices[i * 6 + 4].pos = new Vector2(posLeft + posWidth, posTop);
                            vertices[i * 6 + 1].uv = vertices[i * 6 + 4].uv = new Vector2(uvLeft + uvWidth, uvTop);

                            // left-bottom
                            vertices[i * 6 + 2].pos = vertices[i * 6 + 3].pos = new Vector2(posLeft, posTop + posHeight);
                            vertices[i * 6 + 2].uv = vertices[i * 6 + 3].uv = new Vector2(uvLeft, uvTop + uvHeight);

                            // right-bottom
                            vertices[i * 6 + 5].pos = new Vector2(posLeft + posWidth, posTop + posHeight);
                            vertices[i * 6 + 5].uv = new Vector2(uvLeft + uvWidth, uvTop + uvHeight);
                        }

                        foreach (var pass in m_techBlit.Passes)
                        {
                            pass.Apply();
                            device.DrawUserPrimitives(PrimitiveType.TriangleList, vertices, 0, pagesInBatch.Length * 2);
                        }
                    }

                    device.SetRenderTarget(null);
                }
            }

            glyphData = new GlyphData();
            glyphData.m_pageIndices = new int[pagesInX, pagesInY];
            pages.ForEach(page => glyphData.m_pageIndices[page.m_x, page.m_y] = page.m_pageIndex);
            glyphData.m_glyphSize = chRect.Size;
            glyphData.m_timeStamp = m_timeStamp;
            m_loadedGlyphs.Add(glyphId, glyphData);
            return glyphData;
        }