Inheritance: IDisposable
Beispiel #1
0
        public QFont(string fileName, float size, FontStyle style, QFontBuilderConfiguration config)
        {
            PrivateFontCollection pfc = new PrivateFontCollection();
            pfc.AddFontFile(fileName);
            var fontFamily = pfc.Families[0];

            if (!fontFamily.IsStyleAvailable(style))
                throw new ArgumentException("Font file: " + fileName + " does not support style: " +  style );

            if (config == null)
                config = new QFontBuilderConfiguration();

            TransformViewport? transToVp = null;
            float fontScale = 1f;
            if (config.TransformToCurrentOrthogProjection)
                transToVp = OrthogonalTransform(out fontScale);

            using(var font = new Font(fontFamily, size * fontScale * config.SuperSampleLevels, style)){
                fontData = BuildFont(font, config, null);
            }

            if (config.ShadowConfig != null)
                Options.DropShadowActive = true;
            if (transToVp != null)
                Options.TransformToViewport = transToVp;

            if(config.UseVertexBuffer)
                InitVBOs();
        }
Beispiel #2
0
        public QFont(string fileName, float size, FontStyle style, QFontBuilderConfiguration config, QFontShadowConfiguration shadowConfig)
        {
            PrivateFontCollection pfc = new PrivateFontCollection();

            pfc.AddFontFile(fileName);
            var fontFamily = pfc.Families[0];

            if (!fontFamily.IsStyleAvailable(style))
            {
                throw new ArgumentException("Font file: " + fileName + " does not support style: " + style);
            }

            if (config == null)
            {
                config = new QFontBuilderConfiguration();
            }

            using (var font = new Font(fontFamily, size * config.SuperSampleLevels, style))
            {
                fontData = BuildFont(font, config, shadowConfig, null);
            }

            if (shadowConfig != null)
            {
                options.DropShadowActive = true;
            }
        }
Beispiel #3
0
        public static void CreateTextureFontFiles(string fileName, float size, FontStyle style, QFontBuilderConfiguration config, string newFontName)
        {
            QFontData fontData = null;

            if (config == null)
            {
                config = new QFontBuilderConfiguration();
            }

            //dont move this into a separate method - it needs to stay in scope!
            PrivateFontCollection pfc = new PrivateFontCollection();

            pfc.AddFontFile(fileName);
            var fontFamily = pfc.Families[0];

            if (!fontFamily.IsStyleAvailable(style))
            {
                throw new ArgumentException("Font file: " + fileName + " does not support style: " + style);
            }

            var font = new Font(fontFamily, size * config.SuperSampleLevels, style);

            //var font = ObtainFont(fileName, size * config.SuperSampleLevels, style);
            try {
                fontData = BuildFont(font, config, newFontName);
            } finally {
                if (font != null)
                {
                    font.Dispose();
                }
            }

            Builder.SaveQFontDataToFile(fontData, newFontName);
        }
Beispiel #4
0
        public static void CreateTextureFontFiles(string fileName, float size, FontStyle style, QFontBuilderConfiguration config, string newFontName)
        {
            PrivateFontCollection pfc = new PrivateFontCollection();

            pfc.AddFontFile(fileName);
            var fontFamily = pfc.Families[0];

            if (!fontFamily.IsStyleAvailable(style))
            {
                throw new ArgumentException("Font file: " + fileName + " does not support style: " + style);
            }

            QFontData fontData = null;

            if (config == null)
            {
                config = new QFontBuilderConfiguration();
            }


            using (var font = new Font(fontFamily, size * config.SuperSampleLevels, style))
            {
                fontData = BuildFont(font, config, newFontName);
            }

            Builder.SaveQFontDataToFile(fontData, newFontName);
        }
Beispiel #5
0
        private void LoadQFontFromQFontFile(FontLoadDescription loadDescription)
        {
            var loaderConfig     = loadDescription.LoaderConfig;
            var filePath         = loadDescription.Path;
            var downSampleFactor = loadDescription.DownSampleFactor;


            if (loaderConfig == null)
            {
                loaderConfig = new QFontLoaderConfiguration();
            }

            TransformViewport?transToVp = null;
            float             fontScale = 1f;

            if (loaderConfig.TransformToCurrentOrthogProjection)
            {
                transToVp = OrthogonalTransform(out fontScale);
            }

            fontData = Builder.LoadQFontDataFromFile(filePath, downSampleFactor * fontScale, loaderConfig);
            fontData.scaleDueToTransformToViewport = fontScale;

            if (loaderConfig.ShadowConfig != null)
            {
                Options.DropShadowActive = true;
            }
            if (transToVp != null)
            {
                Options.TransformToViewport = transToVp;
            }
        }
Beispiel #6
0
 public void Dispose()
 {
     foreach (var v in fontData.Pages)
     {
         v.Dispose();
     }
     fontData = null;
 }
Beispiel #7
0
        private static QFont BuildDropShadow(List <QBitmap> sourceFontSheets, QFontGlyph[] sourceFontGlyphs, QFontShadowConfiguration shadowConfig, char[] charSet, byte alphaTolerance)
        {
            QFontGlyph[] newGlyphs;

            var sourceBitmapData = new List <BitmapData>();

            foreach (var sourceSheet in sourceFontSheets)
            {
                sourceBitmapData.Add(sourceSheet.bitmapData);
            }

            //GenerateBitmapSheetsAndRepack(QFontGlyph[] sourceGlyphs, BitmapData[] sourceBitmaps, int destSheetWidth, int destSheetHeight, out QFontGlyph[] destGlyphs, int destMargin, bool usePowerOfTwo)

            var bitmapSheets = GenerateBitmapSheetsAndRepack(sourceFontGlyphs, sourceBitmapData.ToArray(), shadowConfig.PageWidth, shadowConfig.PageHeight, out newGlyphs, shadowConfig.GlyphMargin + shadowConfig.blurRadius * 3, shadowConfig.ForcePowerOfTwo);

            //scale up in case we wanted bigger/smaller shadows
            if (shadowConfig.Scale != 1.0f)
            {
                ScaleSheetsAndGlyphs(bitmapSheets, newGlyphs, shadowConfig.Scale); //no point in retargeting yet, since we will do it after blur
            }
            //blacken and blur
            foreach (var bitmapSheet in bitmapSheets)
            {
                bitmapSheet.Colour32(0, 0, 0);
                bitmapSheet.BlurAlpha(shadowConfig.blurRadius, shadowConfig.blurPasses);
            }

            //retarget after blur and scale
            RetargetAllGlyphs(bitmapSheets, newGlyphs, alphaTolerance);

            //create list of texture pages
            var newTextureSheets = new List <TexturePage>();

            foreach (var page in bitmapSheets)
            {
                newTextureSheets.Add(new TexturePage(page.bitmapData));
            }

            var fontData = new QFontData();

            fontData.CharSetMapping = new Dictionary <char, QFontGlyph>();
            for (int i = 0; i < charSet.Length; i++)
            {
                fontData.CharSetMapping.Add(charSet[i], newGlyphs[i]);
            }

            fontData.Pages = newTextureSheets.ToArray();
            fontData.CalculateMeanWidth();
            fontData.CalculateMaxHeight();

            foreach (var sheet in bitmapSheets)
            {
                sheet.Free();
            }

            return(new QFont(fontData));
        }
Beispiel #8
0
 public void MeasureNodes(QFontData fontData, QFontRenderOptions options)
 {
     foreach (TextNode node in this)
     {
         if (node.Length == 0f)
         {
             node.Length = MeasureTextNodeLength(node, fontData, options);
         }
     }
 }
Beispiel #9
0
        public static void SaveQFontDataToFile(QFontData data, string filePath)
        {
            var lines = data.Serialize();
            StreamWriter writer = new StreamWriter(filePath + ".qfont");
            foreach (var line in lines)
                writer.WriteLine(line);
            
            writer.Close();

        }
Beispiel #10
0
 /// <summary>
 /// Measures each text node using the specified font data and render options
 /// </summary>
 /// <param name="fontData">The font data to use for measuring</param>
 /// <param name="options">The render options</param>
 public void MeasureNodes(QFontData fontData, QFontRenderOptions options)
 {
     foreach (TextNode node in this)
     {
         if (Math.Abs(node.Length) < float.Epsilon)
         {
             node.Length = MeasureTextNodeLength(node, fontData, options);
         }
     }
 }
Beispiel #11
0
        public QFont(Font font, QFontBuilderConfiguration config)
        {
            if (config == null)
                config = new QFontBuilderConfiguration();

            fontData = BuildFont(font, config, null);

            if (config.ShadowConfig != null)
                Options.DropShadowActive = true;
        }
Beispiel #12
0
        public QFont(IFontRenderer renderer, Font font, QFontBuilderConfiguration config = null)
            : this(renderer)
        {
            if (config == null)
                config = new QFontBuilderConfiguration();

            fontData = BuildFont(font, config, null);
            LoadTextures(fontData);

            if (config.ShadowConfig != null)
                Options.DropShadowActive = true;
        }
Beispiel #13
0
        public QFont(Font font, QFontBuilderConfiguration config)
        {
            if (config == null)
            {
                config = new QFontBuilderConfiguration();
            }

            fontData = BuildFont(font, config, null);

            if (config.ShadowConfig != null)
            {
                Options.DropShadowActive = true;
            }
        }
Beispiel #14
0
        private void LoadQFontFromFontFile(FontLoadDescription loadDescription)
        {
            var config   = loadDescription.BuilderConfig;
            var fileName = loadDescription.Path;
            var size     = loadDescription.Size;
            var style    = loadDescription.Style;

            if (config == null)
            {
                config = new QFontBuilderConfiguration();
            }

            TransformViewport?transToVp = null;
            float             fontScale = 1f;

            if (config.TransformToCurrentOrthogProjection)
            {
                transToVp = OrthogonalTransform(out fontScale);
            }

            //dont move this into a separate method - it needs to stay in scope!
            PrivateFontCollection pfc = new PrivateFontCollection();

            pfc.AddFontFile(fileName);
            var fontFamily = pfc.Families[0];

            if (!fontFamily.IsStyleAvailable(style))
            {
                throw new ArgumentException("Font file: " + fileName + " does not support style: " + style);
            }


            var font = new Font(fontFamily, size * fontScale * config.SuperSampleLevels, style);

            //var font = ObtainFont(fileName, size * fontScale * config.SuperSampleLevels, style)
            fontData = BuildFont(font, config, null);
            fontData.scaleDueToTransformToViewport = fontScale;
            font.Dispose();



            if (config.ShadowConfig != null)
            {
                Options.DropShadowActive = true;
            }
            if (transToVp != null)
            {
                Options.TransformToViewport = transToVp;
            }
        }
Beispiel #15
0
        /// <summary>
        /// Saves the <see cref="QFontData"/> to the specified file
        /// This is used for loading custom texture fonts
        /// </summary>
        /// <param name="data">The <see cref="QFontData"/> to save</param>
        /// <param name="filePath">The filepath</param>
        public static void SaveQFontDataToFile(QFontData data, string filePath)
        {
            // Serialize the font data
            var lines = data.Serialize();

            // Write it to the file
            StreamWriter writer = new StreamWriter(filePath + ".qfont");

            foreach (var line in lines)
            {
                writer.WriteLine(line);
            }

            writer.Close();
        }
Beispiel #16
0
        public QFont(Font font, QFontBuilderConfiguration config)
        {
            optionsStack.Push(new QFontRenderOptions());

            if (config == null)
                config = new QFontBuilderConfiguration();

            fontData = BuildFont(font, config, null);

            if (config.ShadowConfig != null)
                Options.DropShadowActive = true;

            if (config.UseVertexBuffer)
                InitVBOs();
        }
Beispiel #17
0
        public QFont(string fileName, float size, FontStyle style, QFontBuilderConfiguration config)
        {
            PrivateFontCollection pfc = new PrivateFontCollection();

            pfc.AddFontFile(fileName);
            var fontFamily = pfc.Families[0];

            if (!fontFamily.IsStyleAvailable(style))
            {
                throw new ArgumentException("Font file: " + fileName + " does not support style: " + style);
            }

            if (config == null)
            {
                config = new QFontBuilderConfiguration();
            }

            TransformViewport?transToVp = null;
            float             fontScale = 1f;

            if (config.TransformToCurrentOrthogProjection)
            {
                transToVp = OrthogonalTransform(out fontScale);
            }

            using (var font = new Font(fontFamily, size * fontScale * config.SuperSampleLevels, style))
            {
                fontData = BuildFont(font, config, null);
            }

            if (config.ShadowConfig != null)
            {
                Options.DropShadowActive = true;
            }
            if (transToVp != null)
            {
                Options.TransformToViewport = transToVp;
            }

            if (config.UseVertexBuffer)
            {
                InitVBOs();
            }
        }
Beispiel #18
0
        private void InitialiseGlFont(Font font, QFontBuilderConfiguration config, QFontData data = null)
        {
            _fontData = data ?? BuildFont(font, config, null);

            // Check and fail if more than one texture was generated. The original implementation of QFont supported
            // this by choosing them as the come but this ModernOpenGl -implementation would be handycapped by
            // allowing this degree of freedom. It is now possible to call DrawArrays for whole texts (requiring
            // shadows and text to be each 1 texture). This is quite efficient.
            // To cover it from another aspect: OpenGL 3.1 and more easily allow Textures of up to 8129² not
            // necessrily being base2 and square - this generousity should be hapily used and effiency be gained.
            // So there will be no implementation of VAO VBO based "Modern" OpenGL that is limited to 512 textures.
            // So this is a well takeable tradeoff
            if (_fontData.Pages.Length != 1 || (_fontData.dropShadowFont != null && _fontData.dropShadowFont.FontData.Pages.Length != 1))
            {
                throw new NotSupportedException("The implementation of QFontDrawing does not support multiple textures per Font/Shadow. " +
                                                "Thus this font can not be properly rendered in all cases. Reduce number of characters " +
                                                "or increase QFontBuilderConfiguration.MaxTexSize QFontShadowConfiguration.PageMaxTextureSize " +
                                                "to contain all characters/char-shadows in one Bitmap=>Texture.");
            }
        }
Beispiel #19
0
        private float MeasureTextNodeLength(TextNode node, QFontData fontData, QFontRenderOptions options)
        {
            bool  monospaced     = fontData.IsMonospacingActive(options);
            float monospaceWidth = fontData.GetMonoSpaceWidth(options);

            if (node.Type == TextNodeType.Space)
            {
                if (monospaced)
                {
                    return(monospaceWidth);
                }

                return((float)Math.Ceiling(fontData.meanGlyphWidth * options.WordSpacing));
            }

            float length = 0f;
            float height = 0f;

            if (node.Type == TextNodeType.Word)
            {
                for (int i = 0; i < node.Text.Length; i++)
                {
                    char c = node.Text[i];
                    if (fontData.CharSetMapping.ContainsKey(c))
                    {
                        var glyph = fontData.CharSetMapping[c];
                        if (monospaced)
                        {
                            length += monospaceWidth;
                        }
                        else
                        {
                            length += (float)Math.Ceiling(fontData.CharSetMapping[c].rect.Width + fontData.meanGlyphWidth * options.CharacterSpacing + fontData.GetKerningPairCorrection(i, node.Text, node));
                        }
                        height = Math.Max(height, glyph.yOffset + glyph.rect.Height);
                    }
                }
            }
            node.Height = height;
            return(length);
        }
Beispiel #20
0
        public QFont(Font font, QFontBuilderConfiguration config)
        {
            optionsStack.Push(new QFontRenderOptions());

            if (config == null)
            {
                config = new QFontBuilderConfiguration();
            }

            fontData = BuildFont(font, config, null);

            if (config.ShadowConfig != null)
            {
                Options.DropShadowActive = true;
            }

            if (config.UseVertexBuffer)
            {
                InitVBOs();
            }
        }
Beispiel #21
0
        private float MeasureTextNodeLength(TextNode node, QFontData fontData, QFontRenderOptions options)
        {
            bool  monospaced     = fontData.IsMonospacingActive(options);
            float monospaceWidth = fontData.GetMonoSpaceWidth(options);

            if (node.Type == TextNodeType.Space)
            {
                if (monospaced)
                {
                    return(monospaceWidth);
                }

                return((float)Math.Ceiling(fontData.meanGlyphWidth * options.WordSpacing));
            }

            float length = 0f;

            if (node.Type == TextNodeType.Word)
            {
                for (int i = 0; i < node.Text.Length; i++)
                {
                    char       c = node.Text[i];
                    QFontGlyph glyph;
                    if (fontData.CharSetMapping.TryGetValue(c, out glyph))
                    {
                        if (monospaced)
                        {
                            length += monospaceWidth;
                        }
                        else
                        {
                            length += (float)Math.Ceiling(glyph.rect.Width + fontData.meanGlyphWidth * options.CharacterSpacing + fontData.GetKerningPairCorrection(i, node.Text, node));
                        }
                    }
                }
            }
            return(length);
        }
Beispiel #22
0
        public QFont(string fontname, byte[] fontresource, float size, FontStyle style, QFontBuilderConfiguration config, QFontShadowConfiguration shadowConfig)
        {
            // This should be probably a field of some class
            PrivateFontCollection pfc = new PrivateFontCollection();

            // allocate memory and copy byte[] to the location
            IntPtr data = Marshal.AllocCoTaskMem(fontresource.Length);

            Marshal.Copy(fontresource, 0, data, fontresource.Length);

            // pass the font to the font collection
            pfc.AddMemoryFont(data, fontresource.Length);

            var fontFamily = pfc.Families[0];

            if (!fontFamily.IsStyleAvailable(style))
            {
                throw new ArgumentException("Font Resource: " + fontname + " does not support style: " + style);
            }

            if (config == null)
            {
                config = new QFontBuilderConfiguration();
            }

            using (var font = new Font(fontFamily, size * config.SuperSampleLevels, style))
            {
                fontData = BuildFont(font, config, shadowConfig, null);
            }

            if (shadowConfig != null)
            {
                options.DropShadowActive = true;
            }

            // Free the unsafe memory
            Marshal.FreeCoTaskMem(data);
        }
        internal static ProcessedText ProcessText(QFontData font, QFontRenderOptions options, string text, SizeF maxSize, QFontAlignment alignment)
        {
            //TODO: bring justify and alignment calculations in here
            maxSize.Width = TransformWidthToViewport(maxSize.Width, options);

            var nodeList = new TextNodeList(text);

            nodeList.MeasureNodes(font, options);

            //we "crumble" words that are two long so that that can be split up
            var nodesToCrumble = new List <TextNode>();

            foreach (TextNode node in nodeList)
            {
                if ((!options.WordWrap || node.Length >= maxSize.Width) && node.Type == TextNodeType.Word)
                {
                    nodesToCrumble.Add(node);
                }
            }

            foreach (var node in nodesToCrumble)
            {
                nodeList.Crumble(node, 1);
            }

            //need to measure crumbled words
            nodeList.MeasureNodes(font, options);


            var processedText = new ProcessedText {
                textNodeList = nodeList, maxSize = maxSize, alignment = alignment
            };


            return(processedText);
        }
Beispiel #24
0
        private float MeasureTextNodeLength(TextNode node, QFontData fontData, QFontRenderOptions options)
        {
            bool monospaced = fontData.IsMonospacingActive(options);
            float monospaceWidth = fontData.GetMonoSpaceWidth(options);

            if (node.Type == TextNodeType.Space)
            {
                if (monospaced)
                    return monospaceWidth;

                return (float)Math.Ceiling(fontData.meanGlyphWidth * options.WordSpacing);
            }

            float length = 0f;
            if (node.Type == TextNodeType.Word)
            {

                for (int i = 0; i < node.Text.Length; i++)
                {
                    char c = node.Text[i];
                    if (fontData.CharSetMapping.ContainsKey(c))
                    {
                        if (monospaced)
                            length += monospaceWidth;
                        else
                            length += (float)Math.Ceiling(fontData.CharSetMapping[c].rect.Width + fontData.meanGlyphWidth * options.CharacterSpacing + fontData.GetKerningPairCorrection(i, node.Text, node));
                    }
                }
            }
            return length;
        }
Beispiel #25
0
        private void LoadQFontFromFontFile(FontLoadDescription loadDescription)
        {
            var config = loadDescription.BuilderConfig;
            var fileName = loadDescription.Path;
            var size = loadDescription.Size;
            var style = loadDescription.Style;

            if (config == null)
                config = new QFontBuilderConfiguration();

            TransformViewport? transToVp = null;
            float fontScale = 1f;
            if (config.TransformToCurrentOrthogProjection)
                transToVp = OrthogonalTransform(out fontScale);

            //dont move this into a separate method - it needs to stay in scope!
            PrivateFontCollection pfc = new PrivateFontCollection();
            pfc.AddFontFile(fileName);
            var fontFamily = pfc.Families[0];

            if (!fontFamily.IsStyleAvailable(style))
                throw new ArgumentException("Font file: " + fileName + " does not support style: " + style);


            var font = new Font(fontFamily, size * fontScale * config.SuperSampleLevels, style);
            //var font = ObtainFont(fileName, size * fontScale * config.SuperSampleLevels, style)
            fontData = BuildFont(font, config, null);
            fontData.scaleDueToTransformToViewport = fontScale;
            font.Dispose();



            if (config.ShadowConfig != null)
                Options.DropShadowActive = true;
            if (transToVp != null)
                Options.TransformToViewport = transToVp;
        }
Beispiel #26
0
        public static void CreateTextureFontFiles(string fileName, float size, FontStyle style, QFontBuilderConfiguration config, string newFontName)
        {

            QFontData fontData = null;
            if (config == null)
                config = new QFontBuilderConfiguration();


            //dont move this into a separate method - it needs to stay in scope!
            PrivateFontCollection pfc = new PrivateFontCollection();
            pfc.AddFontFile(fileName);
            var fontFamily = pfc.Families[0];

            if (!fontFamily.IsStyleAvailable(style))
                throw new ArgumentException("Font file: " + fileName + " does not support style: " + style);

            var font = new Font(fontFamily, size * config.SuperSampleLevels, style);
            //var font = ObtainFont(fileName, size * config.SuperSampleLevels, style);
            try
            {
                fontData = BuildFont(font, config, newFontName);
            }
            finally
            {
                if (font != null)
                    font.Dispose();
            }

            Builder.SaveQFontDataToFile(fontData, newFontName);
            
        }
Beispiel #27
0
        public static QFontData LoadQFontDataFromFile(string filePath, float downSampleFactor, QFontConfiguration loaderConfig)
        {
            var          lines  = new List <String>();
            StreamReader reader = new StreamReader(filePath);
            string       line;

            while ((line = reader.ReadLine()) != null)
            {
                lines.Add(line);
            }
            reader.Close();

            var data      = new QFontData();
            int pageCount = 0;

            char[] charSet;
            data.Deserialize(lines, out pageCount, out charSet);

            string namePrefix = filePath.Replace(".qfont", "").Replace(" ", "");

            var bitmapPages = new List <QBitmap>();

            if (pageCount == 1)
            {
                bitmapPages.Add(new QBitmap(namePrefix + ".png"));
            }
            else
            {
                for (int i = 0; i < pageCount; i++)
                {
                    bitmapPages.Add(new QBitmap(namePrefix + "_sheet_" + i));
                }
            }

            foreach (var glyph in data.CharSetMapping.Values)
            {
                RetargetGlyphRectangleOutwards(bitmapPages[glyph.page].bitmapData, glyph, false, loaderConfig.KerningConfig.alphaEmptyPixelTolerance);
            }

            var intercept = FirstIntercept(data.CharSetMapping);

            if (intercept != null)
            {
                throw new Exception("Failed to load font from file. Glyphs '" + intercept[0] + "' and '" + intercept[1] + "' were overlapping. If you are texturing your font without locking pixel opacity, then consider using a larger glyph margin. This can be done by setting QFontBuilderConfiguration myQfontBuilderConfig.GlyphMargin, and passing it into CreateTextureFontFiles.");
            }

            if (downSampleFactor > 1.0f)
            {
                foreach (var page in bitmapPages)
                {
                    page.DownScale32((int)(page.bitmap.Width * downSampleFactor), (int)(page.bitmap.Height * downSampleFactor));
                }

                foreach (var glyph in data.CharSetMapping.Values)
                {
                    glyph.rect = new Rectangle((int)(glyph.rect.X * downSampleFactor),
                                               (int)(glyph.rect.Y * downSampleFactor),
                                               (int)(glyph.rect.Width * downSampleFactor),
                                               (int)(glyph.rect.Height * downSampleFactor));
                    glyph.yOffset = (int)(glyph.yOffset * downSampleFactor);
                }
            }
            else if (downSampleFactor < 1.0f)
            {
                // If we were simply to shrink the entire texture, then at some point we will make glyphs overlap, breaking the font.
                // For this reason it is necessary to copy every glyph to a separate bitmap, and then shrink each bitmap individually.
                QFontGlyph[] shrunkGlyphs;
                QBitmap[]    shrunkBitmapsPerGlyph;
                CreateBitmapPerGlyph(Helper.ToArray(data.CharSetMapping.Values), bitmapPages.ToArray(), out shrunkGlyphs, out shrunkBitmapsPerGlyph);

                //shrink each bitmap
                for (int i = 0; i < shrunkGlyphs.Length; i++)
                {
                    var bmp = shrunkBitmapsPerGlyph[i];
                    bmp.DownScale32(Math.Max((int)(bmp.bitmap.Width * downSampleFactor), 1), Math.Max((int)(bmp.bitmap.Height * downSampleFactor), 1));
                    shrunkGlyphs[i].rect    = new Rectangle(0, 0, bmp.bitmap.Width, bmp.bitmap.Height);
                    shrunkGlyphs[i].yOffset = (int)(shrunkGlyphs[i].yOffset * downSampleFactor);
                }

                var shrunkBitmapData = new BitmapData[shrunkBitmapsPerGlyph.Length];
                for (int i = 0; i < shrunkBitmapsPerGlyph.Length; i++)
                {
                    shrunkBitmapData[i] = shrunkBitmapsPerGlyph[i].bitmapData;
                }

                //use roughly the same number of pages as before..
                int newWidth  = (int)(bitmapPages[0].bitmap.Width * (0.1f + downSampleFactor));
                int newHeight = (int)(bitmapPages[0].bitmap.Height * (0.1f + downSampleFactor));

                //free old bitmap pages since we are about to chuck them away
                for (int i = 0; i < pageCount; i++)
                {
                    bitmapPages[i].Free();
                }

                QFontGlyph[] shrunkRepackedGlyphs;
                bitmapPages         = GenerateBitmapSheetsAndRepack(shrunkGlyphs, shrunkBitmapData, newWidth, newHeight, out shrunkRepackedGlyphs, 4);
                data.CharSetMapping = CreateCharGlyphMapping(shrunkRepackedGlyphs);

                foreach (var bmp in shrunkBitmapsPerGlyph)
                {
                    bmp.Free();
                }

                pageCount = bitmapPages.Count;
            }

            data.Pages = new TexturePage[pageCount];
            for (int i = 0; i < pageCount; i++)
            {
                data.Pages[i] = new TexturePage(bitmapPages[i].bitmapData);
            }

            if (downSampleFactor != 1.0f)
            {
                foreach (var glyph in data.CharSetMapping.Values)
                {
                    RetargetGlyphRectangleOutwards(bitmapPages[glyph.page].bitmapData, glyph, false, loaderConfig.KerningConfig.alphaEmptyPixelTolerance);
                }

                intercept = FirstIntercept(data.CharSetMapping);
                if (intercept != null)
                {
                    throw new Exception("Failed to load font from file. Glyphs '" + intercept[0] + "' and '" + intercept[1] + "' were overlapping. This occurred only after resizing your texture font, implying that there is a bug in QFont. ");
                }
            }

            var glyphList = new List <QFontGlyph>();

            foreach (var c in charSet)
            {
                glyphList.Add(data.CharSetMapping[c]);
            }

            if (loaderConfig.ShadowConfig != null)
            {
                data.dropShadowFont = BuildDropShadow(bitmapPages, glyphList.ToArray(), loaderConfig.ShadowConfig, Helper.ToArray(charSet), loaderConfig.KerningConfig.alphaEmptyPixelTolerance);
            }

            data.KerningPairs = KerningCalculator.CalculateKerning(Helper.ToArray(charSet), glyphList.ToArray(), bitmapPages, loaderConfig.KerningConfig);

            data.CalculateMeanWidth();
            data.CalculateMaxHeight();

            for (int i = 0; i < pageCount; i++)
            {
                bitmapPages[i].Free();
            }

            return(data);
        }
Beispiel #28
0
        public QFontData BuildFontData(string saveName)
        {
            if (config.SuperSampleLevels <= 0 || config.SuperSampleLevels > 8)
            {
                throw new ArgumentOutOfRangeException("SuperSampleLevels = [" + config.SuperSampleLevels + "] is an unsupported value. Please use values in the range [1,8]");
            }

            int margin      = 3; //margin in initial bitmap (don't bother to make configurable - likely to cause confusion
            int glyphMargin = config.GlyphMargin * config.SuperSampleLevels;

            QFontGlyph[] initialGlyphs;
            var          sizes             = GetGlyphSizes(font);
            var          maxSize           = GetMaxGlyphSize(sizes);
            var          initialBmp        = CreateInitialBitmap(font, maxSize, margin, out initialGlyphs, config.TextGenerationRenderHint);
            var          initialBitmapData = initialBmp.LockBits(new Rectangle(0, 0, initialBmp.Width, initialBmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

            int minYOffset = int.MaxValue;

            foreach (var glyph in initialGlyphs)
            {
                RetargetGlyphRectangleInwards(initialBitmapData, glyph, true, config.KerningConfig.alphaEmptyPixelTolerance);
                minYOffset = Math.Min(minYOffset, glyph.yOffset);
            }
            minYOffset--; //give one pixel of breathing room?

            foreach (var glyph in initialGlyphs)
            {
                glyph.yOffset -= minYOffset;
            }

            Size pagesize = GetOptimalPageSize(initialBmp.Width * config.SuperSampleLevels, initialBmp.Height * config.SuperSampleLevels, config.PageMaxTextureSize);

            QFontGlyph[]   glyphs;
            List <QBitmap> bitmapPages = GenerateBitmapSheetsAndRepack(initialGlyphs, new BitmapData[1] {
                initialBitmapData
            }, pagesize.Width, pagesize.Height, out glyphs, glyphMargin);

            initialBmp.UnlockBits(initialBitmapData);
            initialBmp.Dispose();

            if (config.SuperSampleLevels != 1)
            {
                ScaleSheetsAndGlyphs(bitmapPages, glyphs, 1.0f / config.SuperSampleLevels);
                RetargetAllGlyphs(bitmapPages, glyphs, config.KerningConfig.alphaEmptyPixelTolerance);
            }

            //create list of texture pages
            var pages = new List <TexturePage>();

            foreach (var page in bitmapPages)
            {
                pages.Add(new TexturePage(page.bitmapData));
            }

            var fontData = new QFontData();

            fontData.CharSetMapping = CreateCharGlyphMapping(glyphs);
            fontData.Pages          = pages.ToArray();
            fontData.CalculateMeanWidth();
            fontData.CalculateMaxHeight();
            fontData.KerningPairs        = KerningCalculator.CalculateKerning(charSet.ToCharArray(), glyphs, bitmapPages, config.KerningConfig);
            fontData.naturallyMonospaced = IsMonospaced(sizes);

            if (saveName != null)
            {
                if (bitmapPages.Count == 1)
                {
                    bitmapPages[0].bitmap.UnlockBits(bitmapPages[0].bitmapData);
                    bitmapPages[0].bitmap.Save(saveName + ".png", ImageFormat.Png);
                    bitmapPages[0] = new QBitmap(bitmapPages[0].bitmap);
                }
                else
                {
                    for (int i = 0; i < bitmapPages.Count; i++)
                    {
                        bitmapPages[i].bitmap.UnlockBits(bitmapPages[i].bitmapData);
                        bitmapPages[i].bitmap.Save(saveName + "_sheet_" + i + ".png", ImageFormat.Png);
                        bitmapPages[i] = new QBitmap(bitmapPages[i].bitmap);
                    }
                }
            }

            if (config.ShadowConfig != null)
            {
                fontData.dropShadowFont = BuildDropShadow(bitmapPages, glyphs, config.ShadowConfig, charSet.ToCharArray(), config.KerningConfig.alphaEmptyPixelTolerance);
            }

            foreach (var page in bitmapPages)
            {
                page.Free();
            }

            //validate glyphs
            var intercept = FirstIntercept(fontData.CharSetMapping);

            if (intercept != null)
            {
                throw new Exception("Failed to create glyph set. Glyphs '" + intercept[0] + "' and '" + intercept[1] + "' were overlapping. This is could be due to an error in the font, or a bug in Graphics.MeasureString().");
            }

            return(fontData);
        }
        /// <summary>
        ///     Renders the glyph at the position given.
        /// </summary>
        /// <param name="x">The x.</param>
        /// <param name="y">The y.</param>
        /// <param name="c">The character to print.</param>
        /// <param name="font">font used for render</param>
        /// <param name="store">target vertex buffer</param>
        internal void RenderGlyph(float x, float y, char c, QFontData fontdata, List <QVertex> store, ref Rectangle clippingRectangle)
        {
            var glyph = fontdata.CharSetMapping[c];

            //note: it's not immediately obvious, but this combined with the paramteters to
            //RenderGlyph for the shadow mean that we render the shadow centrally (despite it being a different size)
            //under the glyph
            if (fontdata.isDropShadow)
            {
                x -= (int)(glyph.rect.Width * 0.5f);
                y -= (int)(glyph.rect.Height * 0.5f + glyph.yOffset);
            }
            else
            {
                RenderDropShadow(x, y, c, glyph, fontdata.dropShadowFont?.FontData, ref clippingRectangle);
            }

            y = -y;

            var sheet = fontdata.Pages[glyph.page];

            var tx1 = (float)glyph.rect.X / sheet.Width;
            var ty1 = (float)glyph.rect.Y / sheet.Height;
            var tx2 = (float)(glyph.rect.X + glyph.rect.Width) / sheet.Width;
            var ty2 = (float)(glyph.rect.Y + glyph.rect.Height) / sheet.Height;

            var   vx      = x + PrintOffset.X;
            var   vy      = y - glyph.yOffset + PrintOffset.Y;
            float vwidth  = glyph.rect.Width;
            float vheight = glyph.rect.Height;

            if (clippingRectangle != default(Rectangle) && ScissorsTest(ref vx, ref vy, ref vwidth, ref vheight,
                                                                        ref tx1, ref ty1, ref tx2, ref ty2, clippingRectangle))
            {
                return;
            }

            var tv1 = new Vector2(tx1, ty1);
            var tv2 = new Vector2(tx1, ty2);
            var tv3 = new Vector2(tx2, ty2);
            var tv4 = new Vector2(tx2, ty1);

            var v1 = new Vector3(vx, vy, PrintOffset.Z);
            var v2 = new Vector3(vx, vy - vheight, PrintOffset.Z);
            var v3 = new Vector3(vx + vwidth, vy - vheight, PrintOffset.Z);
            var v4 = new Vector3(vx + vwidth, vy, PrintOffset.Z);

            var color = fontdata.isDropShadow ? Options.DropShadowColour : Options.Colour;

            var colour = Helper.ToVector4(color);

            store.Add(new QVertex {
                Position = v1, TextureCoord = tv1, VertexColor = colour
            });
            store.Add(new QVertex {
                Position = v2, TextureCoord = tv2, VertexColor = colour
            });
            store.Add(new QVertex {
                Position = v3, TextureCoord = tv3, VertexColor = colour
            });

            store.Add(new QVertex {
                Position = v1, TextureCoord = tv1, VertexColor = colour
            });
            store.Add(new QVertex {
                Position = v3, TextureCoord = tv3, VertexColor = colour
            });
            store.Add(new QVertex {
                Position = v4, TextureCoord = tv4, VertexColor = colour
            });
        }
Beispiel #30
0
        private void InitialiseGlFont(Font font, QFontBuilderConfiguration config, QFontData data = null)
        {
            _fontData = data ?? BuildFont(font, config, null);

            // Check and fail if more than one texture was generated. The original implementation of QFont supported
            // this by choosing them as the come but this ModernOpenGl -implementation would be handycapped by
            // allowing this degree of freedom. It is now possible to call DrawArrays for whole texts (requiring
            // shadows and text to be each 1 texture). This is quite efficient.
            // To cover it from another aspect: OpenGL 3.1 and more easily allow Textures of up to 8129² not
            // necessrily being base2 and square - this generousity should be hapily used and effiency be gained.
            // So there will be no implementation of VAO VBO based "Modern" OpenGL that is limited to 512 textures.
            // So this is a well takeable tradeoff
            if( _fontData.Pages.Length != 1 || (_fontData.dropShadowFont != null && _fontData.dropShadowFont.FontData.Pages.Length != 1))
            {
                throw new NotSupportedException("The implementation of QFontDrawing does not support multiple textures per Font/Shadow. " +
                                                "Thus this font can not be properly rendered in all cases. Reduce number of characters " +
                                                "or increase QFontBuilderConfiguration.MaxTexSize QFontShadowConfiguration.PageMaxTextureSize " +
                                                "to contain all characters/char-shadows in one Bitmap=>Texture.");
            }
        }
Beispiel #31
0
        public static void CreateTextureFontFiles(Font font, string newFontName, QFontBuilderConfiguration config)
        {
            QFontData fontData = BuildFont(font, config, newFontName);

            Builder.SaveQFontDataToFile(fontData, newFontName);
        }
Beispiel #32
0
        public QFont(string fontname, byte[] fontresource, float size, FontStyle style, QFontBuilderConfiguration config, QFontShadowConfiguration shadowConfig)
        {
            // This should be probably a field of some class
            PrivateFontCollection pfc = new PrivateFontCollection();

            // allocate memory and copy byte[] to the location
            IntPtr data = Marshal.AllocCoTaskMem(fontresource.Length);
            Marshal.Copy(fontresource, 0, data, fontresource.Length);

            // pass the font to the font collection
            pfc.AddMemoryFont(data, fontresource.Length);

            var fontFamily = pfc.Families[0];

            if (!fontFamily.IsStyleAvailable(style))
                throw new ArgumentException("Font Resource: " + fontname + " does not support style: " + style);

            if (config == null)
                config = new QFontBuilderConfiguration();

            using (var font = new Font(fontFamily, size * config.SuperSampleLevels, style))
            {
                fontData = BuildFont(font, config, shadowConfig, null);
            }

            if (shadowConfig != null)
                options.DropShadowActive = true;

            // Free the unsafe memory
            Marshal.FreeCoTaskMem(data);
        }
Beispiel #33
0
        public static QFontData LoadQFontDataFromFile(string filePath, float downSampleFactor, QFontLoaderConfiguration loaderConfig)
        {
            var lines = new List<String>();
            StreamReader reader = new StreamReader(filePath);
            string line;
            while((line = reader.ReadLine()) != null)
                lines.Add(line);
            reader.Close();

            var data = new QFontData();
            int pageCount = 0;
            char[] charSet;
            data.Deserialize(lines, out pageCount, out charSet);

            string namePrefix = filePath.Replace(".qfont","").Replace(" ", "");

            var bitmapPages = new List<QBitmap>();

            if (pageCount == 1)
            {
                bitmapPages.Add(new QBitmap(namePrefix + ".png"));
            }
            else
            {
                for (int i = 0; i < pageCount; i++)
                    bitmapPages.Add(new QBitmap(namePrefix + "_sheet_" + i));
            }

            foreach (var glyph in data.CharSetMapping.Values)
                RetargetGlyphRectangleOutwards(bitmapPages[glyph.page].BitmapData, glyph, false, loaderConfig.KerningConfig.alphaEmptyPixelTolerance);

            var intercept = FirstIntercept(data.CharSetMapping);
            if (intercept != null)
            {
                throw new Exception("Failed to load font from file. Glyphs '" + intercept[0] + "' and '" + intercept[1] + "' were overlapping. If you are texturing your font without locking pixel opacity, then consider using a larger glyph margin. This can be done by setting QFontBuilderConfiguration myQfontBuilderConfig.GlyphMargin, and passing it into CreateTextureFontFiles.");
            }

            if (downSampleFactor > 1.0f)
            {
                foreach (var page in bitmapPages)
                    page.DownScale32((int)(page.Bitmap.Width * downSampleFactor), (int)(page.Bitmap.Height * downSampleFactor));

                foreach (var glyph in data.CharSetMapping.Values)
                {

                    glyph.rect = new Rectangle((int)(glyph.rect.X * downSampleFactor),
                                                (int)(glyph.rect.Y * downSampleFactor),
                                                (int)(glyph.rect.Width * downSampleFactor),
                                                (int)(glyph.rect.Height * downSampleFactor));
                    glyph.yOffset = (int)(glyph.yOffset * downSampleFactor);
                }
            }
            else if (downSampleFactor < 1.0f )
            {
                // If we were simply to shrink the entire texture, then at some point we will make glyphs overlap, breaking the font.
                // For this reason it is necessary to copy every glyph to a separate bitmap, and then shrink each bitmap individually.
                QFontGlyph[] shrunkGlyphs;
                QBitmap[] shrunkBitmapsPerGlyph;
                CreateBitmapPerGlyph(Helper.ToArray(data.CharSetMapping.Values), bitmapPages.ToArray(), out shrunkGlyphs, out shrunkBitmapsPerGlyph);

                //shrink each bitmap
                for (int i = 0; i < shrunkGlyphs.Length; i++)
                {
                    var bmp = shrunkBitmapsPerGlyph[i];
                    bmp.DownScale32(Math.Max((int)(bmp.Bitmap.Width * downSampleFactor),1), Math.Max((int)(bmp.Bitmap.Height * downSampleFactor),1));
                    shrunkGlyphs[i].rect = new Rectangle(0, 0, bmp.Bitmap.Width, bmp.Bitmap.Height);
                    shrunkGlyphs[i].yOffset = (int)(shrunkGlyphs[i].yOffset * downSampleFactor);
                }

                var shrunkBitmapData = new BitmapData[shrunkBitmapsPerGlyph.Length];
                for(int i = 0; i < shrunkBitmapsPerGlyph.Length; i ++ ){
                    shrunkBitmapData[i] = shrunkBitmapsPerGlyph[i].BitmapData;
                }

                //use roughly the same number of pages as before..
                int newWidth = (int)(bitmapPages[0].Bitmap.Width * (0.1f + downSampleFactor));
                int newHeight = (int)(bitmapPages[0].Bitmap.Height * (0.1f + downSampleFactor));

                //free old bitmap pages since we are about to chuck them away
                for (int i = 0; i < pageCount; i++)
                    bitmapPages[i].Free();

                QFontGlyph[] shrunkRepackedGlyphs;
                bitmapPages = GenerateBitmapSheetsAndRepack(shrunkGlyphs, shrunkBitmapData, newWidth, newHeight, out shrunkRepackedGlyphs, 4, false);
                data.CharSetMapping = CreateCharGlyphMapping(shrunkRepackedGlyphs);

                pageCount = bitmapPages.Count;
            }

            data.Pages = bitmapPages.ToArray();

            if (downSampleFactor != 1.0f)
            {
                foreach (var glyph in data.CharSetMapping.Values)
                    RetargetGlyphRectangleOutwards(bitmapPages[glyph.page].BitmapData, glyph, false, loaderConfig.KerningConfig.alphaEmptyPixelTolerance);

                intercept = FirstIntercept(data.CharSetMapping);
                if (intercept != null)
                {
                    throw new Exception("Failed to load font from file. Glyphs '" + intercept[0] + "' and '" + intercept[1] + "' were overlapping. This occurred only after resizing your texture font, implying that there is a bug in QFont. ");
                }
            }

            var glyphList = new List<QFontGlyph>();

            foreach (var c in charSet)
                glyphList.Add(data.CharSetMapping[c]);

            if (loaderConfig.ShadowConfig != null)
                data.dropShadow = BuildDropShadow(bitmapPages, glyphList.ToArray(), loaderConfig.ShadowConfig, Helper.ToArray(charSet),loaderConfig.KerningConfig.alphaEmptyPixelTolerance);

            data.KerningPairs = KerningCalculator.CalculateKerning(Helper.ToArray(charSet), glyphList.ToArray(), bitmapPages, loaderConfig.KerningConfig);

            data.CalculateMeanWidth();
            data.CalculateMaxHeight();

            return data;
        }
Beispiel #34
0
        private static QFontData BuildDropShadow(List<QBitmap> sourceFontSheets, QFontGlyph[] sourceFontGlyphs, QFontShadowConfiguration shadowConfig, char[] charSet, byte alphaTolerance)
        {
            QFontGlyph[] newGlyphs;

            var sourceBitmapData = new List<BitmapData>();
            foreach(var sourceSheet in sourceFontSheets)
                sourceBitmapData.Add(sourceSheet.BitmapData);

            //GenerateBitmapSheetsAndRepack(QFontGlyph[] sourceGlyphs, BitmapData[] sourceBitmaps, int destSheetWidth, int destSheetHeight, out QFontGlyph[] destGlyphs, int destMargin, bool usePowerOfTwo)

            var bitmapSheets = GenerateBitmapSheetsAndRepack(sourceFontGlyphs, sourceBitmapData.ToArray(), shadowConfig.PageWidth, shadowConfig.PageHeight, out newGlyphs, shadowConfig.GlyphMargin + shadowConfig.blurRadius*3, shadowConfig.ForcePowerOfTwo);

            //scale up in case we wanted bigger/smaller shadows
            if (shadowConfig.Scale != 1.0f)
                ScaleSheetsAndGlyphs(bitmapSheets, newGlyphs, shadowConfig.Scale); //no point in retargeting yet, since we will do it after blur

            //blacken and blur
            foreach (var bitmapSheet in bitmapSheets)
            {
                bitmapSheet.Colour32(0, 0, 0);
                bitmapSheet.BlurAlpha(shadowConfig.blurRadius, shadowConfig.blurPasses);

            }

            //retarget after blur and scale
            RetargetAllGlyphs(bitmapSheets, newGlyphs, alphaTolerance);

            var fontData = new QFontData();
            fontData.CharSetMapping = new Dictionary<char, QFontGlyph>();
            for(int i = 0; i < charSet.Length; i++)
                fontData.CharSetMapping.Add(charSet[i],newGlyphs[i]);

            fontData.Pages = bitmapSheets.ToArray();
            fontData.CalculateMeanWidth();
            fontData.CalculateMaxHeight();

            return fontData;
        }
Beispiel #35
0
        public QFontData BuildFontData(string saveName)
        {
            if (config.ForcePowerOfTwo && config.SuperSampleLevels != PowerOfTwo(config.SuperSampleLevels))
            {
                throw new ArgumentOutOfRangeException("SuperSampleLevels must be a power of two when using ForcePowerOfTwo.");
            }

            if (config.SuperSampleLevels <= 0 || config.SuperSampleLevels > 8)
            {
                throw new ArgumentOutOfRangeException("SuperSampleLevels = [" + config.SuperSampleLevels + "] is an unsupported value. Please use values in the range [1,8]");
            }

            int margin = 2; //margin in initial bitmap (don't bother to make configurable - likely to cause confusion
            int pageWidth = config.PageWidth * config.SuperSampleLevels; //texture page width
            int pageHeight = config.PageHeight * config.SuperSampleLevels; //texture page height
            bool usePowerOfTwo = config.ForcePowerOfTwo;
            int glyphMargin = config.GlyphMargin * config.SuperSampleLevels;

            QFontGlyph[] initialGlyphs;
            var sizes = GetGlyphSizes(font);
            var maxSize = GetMaxGlyphSize(sizes);
            var initialBmp = CreateInitialBitmap(font, maxSize, margin, out initialGlyphs,config.TextGenerationRenderHint);
            var initialBitmapData = initialBmp.LockBits(new Rectangle(0, 0, initialBmp.Width, initialBmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

            int minYOffset = int.MaxValue;
            foreach (var glyph in initialGlyphs){
                RetargetGlyphRectangleInwards(initialBitmapData, glyph, true, config.KerningConfig.alphaEmptyPixelTolerance);
                minYOffset = Math.Min(minYOffset,glyph.yOffset);
            }
            minYOffset--; //give one pixel of breathing room?

            foreach (var glyph in initialGlyphs)
                glyph.yOffset -= minYOffset;

            QFontGlyph[] glyphs;
            var bitmapPages = GenerateBitmapSheetsAndRepack( initialGlyphs,new BitmapData[1] { initialBitmapData},pageWidth, pageHeight, out glyphs, glyphMargin, usePowerOfTwo);

            initialBmp.UnlockBits(initialBitmapData);
            initialBmp.Dispose();

            if (config.SuperSampleLevels != 1)
            {
                ScaleSheetsAndGlyphs(bitmapPages, glyphs, 1.0f / config.SuperSampleLevels);
                RetargetAllGlyphs(bitmapPages, glyphs,config.KerningConfig.alphaEmptyPixelTolerance);
            }

            //create list of texture pages
            var fontData = new QFontData();
            fontData.CharSetMapping = CreateCharGlyphMapping(glyphs);
            fontData.Pages = bitmapPages.ToArray();
            fontData.CalculateMeanWidth();
            fontData.CalculateMaxHeight();
            fontData.KerningPairs = KerningCalculator.CalculateKerning(charSet.ToCharArray(), glyphs, bitmapPages,config.KerningConfig);
            fontData.naturallyMonospaced = IsMonospaced(sizes);

            if (saveName != null)
            {
                if (bitmapPages.Count == 1)
                    bitmapPages[0].Bitmap.Save(saveName + ".png", System.Drawing.Imaging.ImageFormat.Png);
                else
                {
                    for (int i = 0; i < bitmapPages.Count; i++)
                        bitmapPages[i].Bitmap.Save(saveName + "_sheet_" + i + ".png", System.Drawing.Imaging.ImageFormat.Png);
                }
            }

            if (config.ShadowConfig != null)
                fontData.dropShadow = BuildDropShadow(bitmapPages, glyphs, config.ShadowConfig, charSet.ToCharArray(),config.KerningConfig.alphaEmptyPixelTolerance);

            //validate glyphs
            var intercept = FirstIntercept(fontData.CharSetMapping);
            if (intercept != null)
                throw new Exception("Failed to create glyph set. Glyphs '" + intercept[0] + "' and '" + intercept[1] + "' were overlapping. This is could be due to an error in the font, or a bug in Graphics.MeasureString().");

            return fontData;
        }
Beispiel #36
0
        public static void SaveQFontDataToFile(QFontData data, string filePath)
        {
            var lines = data.Serialize();
            StreamWriter writer = new StreamWriter(filePath + ".qfont");
            foreach (var line in lines)
                writer.WriteLine(line);

            writer.Close();
        }
Beispiel #37
0
		public void SetData (QFontData data)
		{
			fontData = data;
		}
Beispiel #38
0
        /*
         * public static QFontData LoadQFontDataFromFile(string filePath)
         * {
         *  return LoadQFontDataFromFile(filePath, 1.0f);
         * }*/

        public static QFontData LoadQFontDataFromFile(string filePath, float downSampleFactor, QFontShadowConfiguration shadowConfig)
        {
            var          lines  = new List <String>();
            StreamReader reader = new StreamReader(filePath);
            string       line;

            while ((line = reader.ReadLine()) != null)
            {
                lines.Add(line);
            }
            reader.Close();

            var data      = new QFontData();
            int pageCount = 0;

            char[] charSet;
            data.Deserialize(lines, out pageCount, out charSet);


            string namePrefix = filePath.Replace(".qfont", "").Replace(" ", "");

            data.Pages = new TexturePage[pageCount];
            var bitmapPages = new List <QBitmap>();



            if (pageCount == 1)
            {
                bitmapPages.Add(new QBitmap(namePrefix + ".png"));
            }
            else
            {
                for (int i = 0; i < pageCount; i++)
                {
                    bitmapPages.Add(new QBitmap(namePrefix + "_sheet_" + i));
                }
            }


            if (downSampleFactor != 1.0f)
            {
                foreach (var page in bitmapPages)
                {
                    page.DownScale32((int)(page.bitmap.Width * downSampleFactor), (int)(page.bitmap.Height * downSampleFactor));
                }
            }

            for (int i = 0; i < pageCount; i++)
            {
                data.Pages[i] = new TexturePage(bitmapPages[i].bitmapData);
            }


            foreach (var glyph in data.CharSetMapping.Values)
            {
                glyph.rect = new Rectangle((int)(glyph.rect.X * downSampleFactor),
                                           (int)(glyph.rect.Y * downSampleFactor),
                                           (int)(glyph.rect.Width * downSampleFactor),
                                           (int)(glyph.rect.Height * downSampleFactor));

                RetargetGlyphRectangleOutwards(bitmapPages[glyph.page].bitmapData, glyph, false);
                glyph.yOffset = (int)(glyph.yOffset * downSampleFactor);
            }


            var intercept = FirstIntercept(data.CharSetMapping);

            if (intercept != null)
            {
                throw new Exception("Failed to load font from file. Glyphs '" + intercept[0] + "' and '" + intercept[1] + "' were overlapping. If you are texturing your font without locking pixel opacity, then consider using a larger glyph margin. This can be done by setting QFontBuilderConfiguration myQfontBuilderConfig.GlyphMargin, and passing it into CreateTextureFontFiles.");
            }



            var glyphList = new List <QFontGlyph>();

            foreach (var c in charSet)
            {
                glyphList.Add(data.CharSetMapping[c]);
            }

            if (shadowConfig != null)
            {
                data.dropShadow = BuildDropShadow(bitmapPages, glyphList.ToArray(), shadowConfig, charSet.ToArray());
            }


            data.KerningPairs = KerningCalculator.CalculateKerning(charSet.ToArray(), glyphList.ToArray(), bitmapPages);



            data.CalculateMeanWidth();
            data.CalculateMaxHeight();


            for (int i = 0; i < pageCount; i++)
            {
                bitmapPages[i].Free();
            }


            return(data);
        }
Beispiel #39
0
        /*
        public static QFontData LoadQFontDataFromFile(string filePath)
        {
            return LoadQFontDataFromFile(filePath, 1.0f);
        }*/
        public static QFontData LoadQFontDataFromFile(string filePath, float downSampleFactor, QFontShadowConfiguration shadowConfig)
        {
            var lines = new List<String>();
            StreamReader reader = new StreamReader(filePath);
            string line;
            while((line = reader.ReadLine()) != null)
                lines.Add(line);
            reader.Close();

            var data = new QFontData();
            int pageCount = 0;
            char[] charSet;
            data.Deserialize(lines, out pageCount, out charSet);

            string namePrefix = filePath.Replace(".qfont","").Replace(" ", "");
            data.Pages = new TexturePage[pageCount];
            var bitmapPages = new List<QBitmap>();

            if (pageCount == 1)
            {
                bitmapPages.Add(new QBitmap(namePrefix + ".png"));
            }
            else
            {
                for (int i = 0; i < pageCount; i++)
                    bitmapPages.Add(new QBitmap(namePrefix + "_sheet_" + i));
            }

            if (downSampleFactor != 1.0f)
            {
                foreach (var page in bitmapPages)
                    page.DownScale32((int)(page.bitmap.Width * downSampleFactor), (int)(page.bitmap.Height * downSampleFactor));
            }

            for(int i = 0; i < pageCount; i ++ )
                data.Pages[i] = new TexturePage(bitmapPages[i].bitmapData);

            foreach (var glyph in data.CharSetMapping.Values)
            {

                glyph.rect = new Rectangle((int)(glyph.rect.X * downSampleFactor),
                                           (int)(glyph.rect.Y * downSampleFactor),
                                           (int)(glyph.rect.Width * downSampleFactor),
                                           (int)(glyph.rect.Height * downSampleFactor));

                RetargetGlyphRectangleOutwards(bitmapPages[glyph.page].bitmapData, glyph,false);
                glyph.yOffset = (int)(glyph.yOffset * downSampleFactor);
            }

            var intercept = FirstIntercept(data.CharSetMapping);

            if (intercept != null)
            {
                throw new Exception("Failed to load font from file. Glyphs '" + intercept[0] + "' and '" + intercept[1] + "' were overlapping. If you are texturing your font without locking pixel opacity, then consider using a larger glyph margin. This can be done by setting QFontBuilderConfiguration myQfontBuilderConfig.GlyphMargin, and passing it into CreateTextureFontFiles.");
            }

            var glyphList = new List<QFontGlyph>();

            foreach (var c in charSet)
                glyphList.Add(data.CharSetMapping[c]);

            if (shadowConfig != null)
                data.dropShadow = BuildDropShadow(bitmapPages, glyphList.ToArray(), shadowConfig, charSet.ToArray());

            data.KerningPairs = KerningCalculator.CalculateKerning(charSet.ToArray(), glyphList.ToArray(), bitmapPages);

            data.CalculateMeanWidth();
            data.CalculateMaxHeight();

            for (int i = 0; i < pageCount; i++)
                bitmapPages[i].Free();

            return data;
        }
 public QFontDrawingPimitive(QFont font, QFontRenderOptions options)
 {
     Font    = font.FontData;
     Options = options;
 }
		public NxFont Load(string filePath, float height, float downSampleFactor, NxFontLoaderConfiguration loaderConfig)
		{
			if (loaderConfig == null)
			{
				throw new ArgumentNullException ("loaderConfig");
			}

			float fontScale;
			TransformViewport? transToVp = NxFont.SetupTransformViewport (height, loaderConfig.TransformToCurrentOrthogProjection, loaderConfig.Transform, out fontScale);

			var qfont = new NxFont();
			var internalConfig = new QFontLoaderConfiguration();		
			var fontData = new QFontData ();
			qfont.SetData (fontData);

			QFontDataInformation fontInfo = null;
			using (var fs = File.OpenRead (filePath))
			{
				fontInfo = fontData.LoadFromStream (fs);
			}
			var bitmapFiles = fontInfo.GenerateBitmapPageNames (filePath);

			var bitmapPages = new List<NxBitmap> ();
			foreach (var bitmapFileName in bitmapFiles)
			{
				// TODO : STREAM BASED REPLACEMENT 
				// https://support.microsoft.com/en-us/kb/814675
				// GDI+ require the bitmap files to be locked as indexed image
				// during the lifetime i.e. maybe reloaded from disk				
				using (var fs = File.OpenRead (bitmapFileName))	
				{
					var parent = new Bitmap (fs);
					var data = parent.LockBits (
							new Rectangle(0,0, parent.Width, parent.Height)
							,System.Drawing.Imaging.ImageLockMode.ReadWrite
							,parent.PixelFormat);
					var target = new QBitmapData (data);
					var qb = new NxBitmap (parent, target);
					bitmapPages.Add (qb);
				}
			}
			var glyphList = fontData.InitialiseQFontData (fontInfo, ref bitmapPages, downSampleFactor, internalConfig);

			if (loaderConfig.ShadowConfig != null)
			{
				qfont.DropShadow = Helper.BuildDropShadow<NxFont, NxBitmap> (
					bitmapPages,
					glyphList.ToArray (),
					loaderConfig.ShadowConfig,
					Helper.ToArray (fontInfo.CharSet),
					internalConfig.KerningConfig.alphaEmptyPixelTolerance);
			}
			fontData.InitialiseKerningPairs (fontInfo, bitmapPages, glyphList, internalConfig);

			if (loaderConfig.ShadowConfig != null)
				qfont.Options.DropShadowActive = true;
			if (transToVp != null)
				qfont.Options.TransformToViewport = transToVp;

			qfont.InitialiseGlyphRenderer(loaderConfig.CharacterOutput, loaderConfig.FontGlyphRenderer, loaderConfig.DropShadowRenderer);

			return qfont;
		}
Beispiel #42
0
 internal QFont(QFontData fontData)
 {
     FontData = fontData;
 }
 private void RenderDropShadow(float x, float y, char c, QFontGlyph nonShadowGlyph, QFontData shadowFont,
                               ref Rectangle clippingRectangle)
 {
     //note can cast drop shadow offset to int, but then you can't move the shadow smoothly...
     if (shadowFont != null && Options.DropShadowActive)
     {
         var xOffset = Font.meanGlyphWidth * Options.DropShadowOffset.X +
                       nonShadowGlyph.rect.Width * 0.5f;
         var yOffset = Font.meanGlyphWidth * Options.DropShadowOffset.Y +
                       nonShadowGlyph.rect.Height * 0.5f + nonShadowGlyph.yOffset;
         RenderGlyph(x + xOffset, y + yOffset, c, shadowFont, ShadowVertexRepr, ref clippingRectangle);
     }
 }
Beispiel #44
0
        private static QFont BuildDropShadow(List <QBitmap> sourceFontSheets, QFontGlyph[] sourceFontGlyphs, QFontShadowConfiguration shadowConfig, char[] charSet, byte alphaTolerance)
        {
            QFontGlyph[] newGlyphs;

            var sourceBitmapData = new List <BitmapData>();

            foreach (var sourceSheet in sourceFontSheets)
            {
                sourceBitmapData.Add(sourceSheet.bitmapData);
            }

            var bitmapSheets = GenerateBitmapSheetsAndRepack(sourceFontGlyphs, sourceBitmapData.ToArray(), shadowConfig.PageMaxTextureSize, shadowConfig.PageMaxTextureSize, out newGlyphs, shadowConfig.GlyphMargin + shadowConfig.blurRadius * 3);

            //scale up in case we wanted bigger/smaller shadows
            if (shadowConfig.Scale != 1.0f)
            {
                ScaleSheetsAndGlyphs(bitmapSheets, newGlyphs, shadowConfig.Scale); //no point in retargeting yet, since we will do it after blur
            }
            //whiten and blur
            foreach (var bitmapSheet in bitmapSheets)
            {
                bitmapSheet.Colour32(255, 255, 255);
                if (shadowConfig.Type == ShadowType.Blurred)
                {
                    bitmapSheet.BlurAlpha(shadowConfig.blurRadius, shadowConfig.blurPasses);
                }
                else
                {
                    bitmapSheet.ExpandAlpha(shadowConfig.blurRadius, shadowConfig.blurPasses);
                }
            }

            //retarget after blur and scale
            RetargetAllGlyphs(bitmapSheets, newGlyphs, alphaTolerance);

            //create list of texture pages
            var newTextureSheets = new List <TexturePage>();

            foreach (var page in bitmapSheets)
            {
                newTextureSheets.Add(new TexturePage(page.bitmapData));
            }

            var fontData = new QFontData();

            fontData.CharSetMapping = new Dictionary <char, QFontGlyph>();
            for (int i = 0; i < charSet.Length; i++)
            {
                fontData.CharSetMapping.Add(charSet[i], newGlyphs[i]);
            }

            fontData.Pages = newTextureSheets.ToArray();
            fontData.CalculateMeanWidth();
            fontData.CalculateMaxHeight();

            foreach (var sheet in bitmapSheets)
            {
                sheet.Free();
            }

            fontData.isDropShadow = true;
            return(new QFont(fontData));
        }
 public QFontDrawingPimitive(QFont font)
 {
     Font    = font.FontData;
     Options = new QFontRenderOptions();
 }
Beispiel #46
0
        private void LoadQFontFromQFontFile(FontLoadDescription loadDescription)
        {
            var loaderConfig = loadDescription.LoaderConfig;
            var filePath = loadDescription.Path;
            var downSampleFactor = loadDescription.DownSampleFactor;


            if (loaderConfig == null)
                loaderConfig = new QFontLoaderConfiguration();

            TransformViewport? transToVp = null;
            float fontScale = 1f;
            if (loaderConfig.TransformToCurrentOrthogProjection)
                transToVp = OrthogonalTransform(out fontScale);

            fontData = Builder.LoadQFontDataFromFile(filePath, downSampleFactor * fontScale, loaderConfig);
            fontData.scaleDueToTransformToViewport = fontScale;

            if (loaderConfig.ShadowConfig != null)
                Options.DropShadowActive = true;
            if (transToVp != null)
                Options.TransformToViewport = transToVp;
        }
Beispiel #47
0
 internal QFont(IFontRenderer renderer, QFontData fontData)
     : this(renderer)
 {
     this.fontData = fontData;
 }
Beispiel #48
0
        private void LoadQFontFromFontFile(FontLoadDescription loadDescription)
        {
            var config = loadDescription.BuilderConfig;
            var fileName = loadDescription.Path;
            var size = loadDescription.Size;
            var style = loadDescription.Style;

            if (config == null)
                config = new QFontBuilderConfiguration();

            TransformViewport? transToVp = null;

            float dpiX, dpiY;
            float fontScale = 1.0f;
            using (Graphics graphics = Graphics.FromHwnd(IntPtr.Zero))
            {
                dpiX = graphics.DpiX;
                dpiY = graphics.DpiY;
            }

            float distancefrom120 = 120 - dpiX;
            float percent = (120 - distancefrom120) / 120;

            if (dpiX != 120f)
                if (percent > 1)
                    fontScale = 1 - Math.Abs(percent - 1);
                else
                    fontScale = 1f + (1 - percent);

            fontScale = Math.Abs(fontScale);

            if (config.TransformToCurrentOrthogProjection)
                transToVp = OrthogonalTransform(out fontScale);

            //dont move this into a separate method - it needs to stay in scope!
            PrivateFontCollection pfc = new PrivateFontCollection();
            pfc.AddFontFile(fileName);
            var fontFamily = pfc.Families[0];

            if (!fontFamily.IsStyleAvailable(style))
                throw new ArgumentException("Font file: " + fileName + " does not support style: " + style);


            var font = new Font(fontFamily, size * fontScale * config.SuperSampleLevels, style);
            //var font = ObtainFont(fileName, size * fontScale * config.SuperSampleLevels, style)
            fontData = BuildFont(font, config, null);
            fontData.scaleDueToTransformToViewport = fontScale;
            font.Dispose();

            if (config.ShadowConfig != null)
                Options.DropShadowActive = true;
            if (transToVp != null)
                Options.TransformToViewport = transToVp;
        }
Beispiel #49
0
 internal QFont(QFontData fontData)
 {
     this.fontData = fontData;
 }
Beispiel #50
0
 public void MeasureNodes(QFontData fontData, QFontRenderOptions options)
 {
     foreach(TextNode node in this){
         if(node.Length == 0f)
             node.Length = MeasureTextNodeLength(node,fontData,options);
     }
 }
		public void MeasureNodes(QFontData fontData, QFontRenderOptions options){

			foreach(TextNode node in this){
				if (Math.Abs (node.Length) < float.Epsilon)
					node.Length = fontData.MeasureTextNodeLength (node, options);
			}
		}
Beispiel #52
0
        public static void CreateTextureFontFiles(string fileName, float size, FontStyle style, QFontBuilderConfiguration config, string newFontName)
        {
            PrivateFontCollection pfc = new PrivateFontCollection();
            pfc.AddFontFile(fileName);
            var fontFamily = pfc.Families[0];

            if (!fontFamily.IsStyleAvailable(style))
                throw new ArgumentException("Font file: " + fileName + " does not support style: " + style);

            QFontData fontData = null;
            if (config == null)
                config = new QFontBuilderConfiguration();

            using(var font = new Font(fontFamily, size * config.SuperSampleLevels, style)){
                fontData  = BuildFont(font, config, newFontName);
            }

            Builder.SaveQFontDataToFile(fontData, newFontName);
        }
Beispiel #53
0
 private void RenderDropShadow(float x, float y, char c, QFontGlyph nonShadowGlyph)
 {
     //note can cast drop shadow offset to int, but then you can't move the shadow smoothly...
     if (fontData.dropShadow != null && Options.DropShadowActive)
     {
         var fData = fontData;
         fontData = fontData.dropShadow;
         RenderGlyph(
             x + (fontData.meanGlyphWidth * Options.DropShadowOffset.X + nonShadowGlyph.rect.Width * 0.5f),
             y + (fontData.meanGlyphWidth * Options.DropShadowOffset.Y + nonShadowGlyph.rect.Height * 0.5f + nonShadowGlyph.yOffset), c, true);
         fontData = fData;
     }
 }
Beispiel #54
0
        private void LoadQFontFromQFontFile(FontLoadDescription loadDescription)
        {
            var loaderConfig = loadDescription.LoaderConfig;
            var filePath = loadDescription.Path;
            var downSampleFactor = loadDescription.DownSampleFactor;

            if (loaderConfig == null)
                loaderConfig = new QFontLoaderConfiguration();

            fontData = Builder.LoadQFontDataFromFile(filePath, downSampleFactor, loaderConfig);
            LoadTextures(fontData);
            fontData.scaleDueToTransformToViewport = 1f;

            if (loaderConfig.ShadowConfig != null)
                Options.DropShadowActive = true;
        }
Beispiel #55
0
        public QFont(string fileName, float size, FontStyle style, QFontBuilderConfiguration config, QFontShadowConfiguration shadowConfig)
        {
            PrivateFontCollection pfc = new PrivateFontCollection();
            pfc.AddFontFile(fileName);
            var fontFamily = pfc.Families[0];

            if (!fontFamily.IsStyleAvailable(style))
                throw new ArgumentException("Font file: " + fileName + " does not support style: " +  style );

            if (config == null)
                config = new QFontBuilderConfiguration();

            using (var font = new Font(fontFamily, size * config.SuperSampleLevels, style))
            {
                fontData = BuildFont(font, config, shadowConfig, null);
            }

            if (shadowConfig != null)
                options.DropShadowActive = true;
        }
Beispiel #56
0
 private void LoadTextures(QFontData fdata)
 {
     if (fdata.dropShadow != null) LoadTextures(fdata.dropShadow);
     foreach (var page in fdata.Pages)
     {
         page.Texture = renderer.CreateTexture(page.BitmapData);
         page.Free();
     }
 }
Beispiel #57
0
        private static QFont BuildDropShadow(List<QBitmap> sourceFontSheets, QFontGlyph[] sourceFontGlyphs, QFontShadowConfiguration shadowConfig, char[] charSet, byte alphaTolerance)
        {
            QFontGlyph[] newGlyphs;

            var sourceBitmapData = new List<BitmapData>();
            foreach(var sourceSheet in sourceFontSheets)
                sourceBitmapData.Add(sourceSheet.bitmapData);

            var bitmapSheets = GenerateBitmapSheetsAndRepack(sourceFontGlyphs, sourceBitmapData.ToArray(), shadowConfig.PageMaxTextureSize, shadowConfig.PageMaxTextureSize, out newGlyphs, shadowConfig.GlyphMargin + shadowConfig.blurRadius*3);

            //scale up in case we wanted bigger/smaller shadows
            if (shadowConfig.Scale != 1.0f)
                ScaleSheetsAndGlyphs(bitmapSheets, newGlyphs, shadowConfig.Scale); //no point in retargeting yet, since we will do it after blur

            //whiten and blur
            foreach (var bitmapSheet in bitmapSheets)
            {
                bitmapSheet.Colour32(255, 255, 255);
                if (shadowConfig.Type == ShadowType.Blurred)
                    bitmapSheet.BlurAlpha(shadowConfig.blurRadius, shadowConfig.blurPasses);
                else
                    bitmapSheet.ExpandAlpha(shadowConfig.blurRadius, shadowConfig.blurPasses);
            }

            //retarget after blur and scale
            RetargetAllGlyphs(bitmapSheets, newGlyphs, alphaTolerance);

            //create list of texture pages
            var newTextureSheets = new List<TexturePage>();
            foreach (var page in bitmapSheets)
                newTextureSheets.Add(new TexturePage(page.bitmapData));

            var fontData = new QFontData();
            fontData.CharSetMapping = new Dictionary<char, QFontGlyph>();
            for(int i = 0; i < charSet.Length; i++)
                fontData.CharSetMapping.Add(charSet[i],newGlyphs[i]);

            fontData.Pages = newTextureSheets.ToArray();
            fontData.CalculateMeanWidth();
            fontData.CalculateMaxHeight();

            foreach (var sheet in bitmapSheets)
                sheet.Free();

            fontData.isDropShadow = true;
            return new QFont(fontData);
        }
Beispiel #58
0
 internal QFont(QFontData fontData)
 {
     this._fontData = fontData;
 }
Beispiel #59
0
		public NxFont (string fileName, float size, float height, FontStyle style, NxFontBuilderConfiguration config)
		{
			optionsStack = new ConcurrentStack<QFontRenderOptions> ();
			PrivateFontCollection pfc = new PrivateFontCollection();
			pfc.AddFontFile(fileName);
			var fontFamily = pfc.Families[0];

			if (!fontFamily.IsStyleAvailable(style))
				throw new ArgumentException("Font file: " + fileName + " does not support style: " +  style );

			if (config == null)
			{
				throw new ArgumentNullException ("config");
			}

			float fontScale;
			var transToVp = SetupTransformViewport (height, config.TransformToCurrentOrthogProjection, config.Transform, out fontScale);

			var internalConfig = new QFontBuilderConfiguration (config.AddDropShadow);
			internalConfig.SuperSampleLevels = config.SuperSampleLevels;
			if (internalConfig.ShadowConfig != null)
			{
				internalConfig.ShadowConfig.blurRadius = config.BlurRadius;
			}
			using(var font = new Font(fontFamily, size * fontScale * config.SuperSampleLevels, style)){
				var builder = new Builder<NxFont>(font, internalConfig);
				NxFont dropShadowFont;
				fontData = builder.BuildFontData(null, out dropShadowFont);
				DropShadow = dropShadowFont;
			}

			if (internalConfig.ShadowConfig != null)
				Options.DropShadowActive = true;
			if (transToVp != null)
				Options.TransformToViewport = transToVp;

			InitialiseGlyphRenderer(config.CharacterOutput, config.FontGlyphRenderer, config.DropShadowRenderer);
		}