Example #1
0
        public TexturePage(string filePath)
        {
            var bitmap = new QBitmap(filePath);

            CreateTexture(bitmap.BitmapData);
            bitmap.Free();
        }
Example #2
0
        private static void RetargetGlyphRectangleInwards(BitmapData bitmapData, QFontGlyph glyph, bool setYOffset, byte alphaTolerance)
        {
            int startX, endX;
            int startY, endY;

            var rect = glyph.rect;

            EmptyDel emptyPix;

            if (bitmapData.PixelFormat == PixelFormat.Format32bppArgb)
                emptyPix = delegate(BitmapData data, int x, int y) { return QBitmap.EmptyAlphaPixel(data, x, y, alphaTolerance); };
            else
                emptyPix = delegate(BitmapData data, int x, int y) { return QBitmap.EmptyPixel(data, x, y); };


            unsafe
            {

                for (startX = rect.X; startX < bitmapData.Width; startX++)
                    for (int j = rect.Y; j < rect.Y + rect.Height; j++)
                        if (!emptyPix(bitmapData, startX, j))
                            goto Done1;
                Done1:

                for (endX = rect.X + rect.Width; endX >= 0; endX--)
                    for (int j = rect.Y; j < rect.Y + rect.Height; j++)
                        if (!emptyPix(bitmapData, endX, j))
                            goto Done2;
                Done2:

                for (startY = rect.Y; startY < bitmapData.Height; startY++)
                    for (int i = startX; i < endX; i++)
                        if (!emptyPix(bitmapData, i, startY))
                            goto Done3;
                            
                Done3:

                for (endY = rect.Y + rect.Height; endY >= 0; endY--)
                    for (int i = startX; i < endX; i++)
                        if (!emptyPix(bitmapData, i, endY))
                            goto Done4;
                Done4:;


            }

            if (endY < startY)
                startY = endY = rect.Y;

            if (endX < startX)
                startX = endX = rect.X;

            glyph.rect = new Rectangle(startX, startY, endX - startX + 1, endY - startY + 1);

            if (setYOffset)
                glyph.yOffset = glyph.rect.Y;

        }
Example #3
0
 public static void CreateBitmapPerGlyph(QFontGlyph[] sourceGlyphs, QBitmap[] sourceBitmaps, out QFontGlyph[]  destGlyphs, out QBitmap[] destBitmaps){
     destBitmaps = new QBitmap[sourceGlyphs.Length];
     destGlyphs = new QFontGlyph[sourceGlyphs.Length];
     for(int i = 0; i < sourceGlyphs.Length; i++){
         var sg = sourceGlyphs[i];
         destGlyphs[i] = new QFontGlyph(i,new Rectangle(0,0,sg.rect.Width,sg.rect.Height),sg.yOffset,sg.character);
         destBitmaps[i] = new QBitmap(new Bitmap(sg.rect.Width,sg.rect.Height,PixelFormat.Format32bppArgb));
         QBitmap.Blit(sourceBitmaps[sg.page].bitmapData,destBitmaps[i].bitmapData,sg.rect,0,0);
     }
 }
Example #4
0
 public static void CreateBitmapPerGlyph(QFontGlyph[] sourceGlyphs, QBitmap[] sourceBitmaps, out QFontGlyph[]  destGlyphs, out QBitmap[] destBitmaps)
 {
     destBitmaps = new QBitmap[sourceGlyphs.Length];
     destGlyphs = new QFontGlyph[sourceGlyphs.Length];
     for(int i = 0; i < sourceGlyphs.Length; i++){
         var sg = sourceGlyphs[i];
         destGlyphs[i] = new QFontGlyph(i,new Rectangle(0,0,sg.rect.Width,sg.rect.Height),sg.yOffset,sg.character);
         destBitmaps[i] = new QBitmap(new Bitmap(sg.rect.Width,sg.rect.Height,PixelFormat.Format32bppArgb));
         QBitmap.Blit(sourceBitmaps[sg.page].BitmapData,destBitmaps[i].BitmapData,sg.rect,0,0);
     }
 }
		public QFont Load(string path, float downSampleFactor, QFontLoaderConfiguration loaderConfig)
		{
			if (loaderConfig == null)
				loaderConfig = new QFontLoaderConfiguration();

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

			QFont qfont = new QFont();
			qfont.fontData = new QFontData ();

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

			var bitmapPages = new List<QBitmap> ();
			foreach (var bitmapFileName in bitmapFiles)
			{
				// TODO : 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))
				using (var b = new Bitmap(fs))				
				{
					var qb = new QBitmap (bitmapFileName);
					bitmapPages.Add (qb);
				}
			}
			var glyphList = qfont.fontData.InitialiseQFontData (fontInfo, ref bitmapPages, downSampleFactor, loaderConfig);

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

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

			return qfont;
		}
Example #6
0
 public TexturePage(string filePath)
 {
     var bitmap = new QBitmap(filePath);
     CreateTexture(bitmap.bitmapData);
     bitmap.Free();
 }
Example #7
0
        private static List<QBitmap> GenerateBitmapSheetsAndRepack(QFontGlyph[] sourceGlyphs, BitmapData[] sourceBitmaps, int destSheetWidth, int destSheetHeight, out QFontGlyph[] destGlyphs, int destMargin, bool usePowerOfTwo)
        {
            var pages = new List<QBitmap>();
            destGlyphs = new QFontGlyph[sourceGlyphs.Length];

            QBitmap currentPage = null;

            int maxY = 0;
            foreach (var glph in sourceGlyphs)
                maxY = Math.Max(glph.rect.Height, maxY);

            int finalPageIndex = 0;
            int finalPageRequiredWidth = 0;
            int finalPageRequiredHeight = 0;

            for (int k = 0; k < 2; k++)
            {
                bool pre = k == 0;  //first iteration is simply to determine the required size of the final page, so that we can crop it in advance

                int xPos = 0;
                int yPos = 0;
                int maxYInRow = 0;
                int totalTries = 0;

                for (int i = 0; i < sourceGlyphs.Length; i++)
                {

                    if(!pre && currentPage == null){

                        if (finalPageIndex == pages.Count)
                        {
                            int width = Math.Min(destSheetWidth, usePowerOfTwo ? PowerOfTwo(finalPageRequiredWidth) : finalPageRequiredWidth);
                            int height = Math.Min(destSheetHeight, usePowerOfTwo ? PowerOfTwo(finalPageRequiredHeight) : finalPageRequiredHeight);

                            currentPage = new QBitmap(new Bitmap(width, height, PixelFormat.Format32bppArgb));
                            currentPage.Clear32(255, 255, 255, 0); //clear to white, but totally transparent
                        }
                        else
                        {
                            currentPage = new QBitmap(new Bitmap(destSheetWidth, destSheetHeight, PixelFormat.Format32bppArgb));
                            currentPage.Clear32(255, 255, 255, 0); //clear to white, but totally transparent
                        }
                        pages.Add(currentPage);

                    }

                    totalTries++;

                    if (totalTries > 10 * sourceGlyphs.Length)
                        throw new Exception("Failed to fit font into texture pages");

                    var rect = sourceGlyphs[i].rect;

                    if (xPos + rect.Width + 2 * destMargin <= destSheetWidth && yPos + rect.Height + 2 * destMargin <= destSheetHeight)
                    {
                        if (!pre)
                        {
                            //add to page
                            if(sourceBitmaps[sourceGlyphs[i].page].PixelFormat == PixelFormat.Format32bppArgb)
                                QBitmap.Blit(sourceBitmaps[sourceGlyphs[i].page], currentPage.BitmapData, rect.X, rect.Y, rect.Width, rect.Height, xPos + destMargin, yPos + destMargin);
                            else
                                QBitmap.BlitMask(sourceBitmaps[sourceGlyphs[i].page], currentPage.BitmapData, rect.X, rect.Y, rect.Width, rect.Height, xPos + destMargin, yPos + destMargin);

                            destGlyphs[i] = new QFontGlyph(pages.Count - 1, new Rectangle(xPos + destMargin, yPos + destMargin, rect.Width, rect.Height), sourceGlyphs[i].yOffset, sourceGlyphs[i].character);
                        }
                        else
                        {
                            finalPageRequiredWidth = Math.Max(finalPageRequiredWidth, xPos + rect.Width + 2 * destMargin);
                            finalPageRequiredHeight = Math.Max(finalPageRequiredHeight, yPos + rect.Height + 2 * destMargin);
                        }

                        xPos += rect.Width + 2 * destMargin;
                        maxYInRow = Math.Max(maxYInRow, rect.Height);

                        continue;
                    }

                    if (xPos + rect.Width + 2 * destMargin > destSheetWidth)
                    {
                        i--;

                        yPos += maxYInRow + 2 * destMargin;
                        xPos = 0;

                        if (yPos + maxY + 2 * destMargin > destSheetHeight)
                        {
                            yPos = 0;

                            if (!pre)
                            {
                                currentPage = null;
                            }
                            else
                            {
                                finalPageRequiredWidth = 0;
                                finalPageRequiredHeight = 0;
                                finalPageIndex++;
                            }
                        }
                        continue;
                    }

                }

            }

            return pages;
        }
Example #8
0
        /// <summary>
        /// Builds the font data
        /// </summary>
        /// <param name="saveName">The filename to save the font texture files too. If null, the texture files are not saved</param>
        /// <returns>A <see cref="QFontData"/></returns>
        public QFontData BuildFontData(string saveName = null)
        {
            // Check super sample level range
            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);

#if DEBUG
            // print bitmap with bounds to debug it
            var debugBmp = initialBmp.Clone() as Bitmap;
            var graphics = Graphics.FromImage(debugBmp);
            var pen      = new Pen(Color.Red, 1);

            foreach (var g in initialGlyphs)
            {
                graphics.DrawRectangle(pen, g.Rect);
            }

            graphics.Flush();
            graphics.Dispose();

            debugBmp.Save(_font + "-DEBUG.png", ImageFormat.Png);
#endif

            var initialBitmapData = initialBmp.LockBits(new Rectangle(0, 0, initialBmp.Width, initialBmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

            int minYOffset = int.MaxValue;

            // Retarget each glyph rectangle to get minimum bounding box
            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?

            // Update glyph y offsets
            foreach (var glyph in initialGlyphs)
            {
                glyph.YOffset -= minYOffset;
            }

            // Find the optimal page size for the font
            Size         pagesize = GetOptimalPageSize(initialBmp.Width * _config.SuperSampleLevels, initialBmp.Height * _config.SuperSampleLevels, _config.PageMaxTextureSize);
            QFontGlyph[] glyphs;

            // Generate the final bitmap pages
            List <QBitmap> bitmapPages = GenerateBitmapSheetsAndRepack(initialGlyphs, new[] { initialBitmapData }, pagesize.Width, pagesize.Height, out glyphs, glyphMargin);

            // Clean up
            initialBmp.UnlockBits(initialBitmapData);
            initialBmp.Dispose();

            // Scale and retarget glyphs if needed
            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));
            }


            // Build the QFontData
            var fontData = new QFontData
            {
                CharSetMapping = CreateCharGlyphMapping(glyphs),
                Pages          = pages.ToArray()
            };
            fontData.CalculateMeanWidth();
            fontData.CalculateMaxHeight();
            fontData.KerningPairs        = KerningCalculator.CalculateKerning(_charSet.ToCharArray(), glyphs, bitmapPages, _config.KerningConfig, _font);
            fontData.NaturallyMonospaced = IsMonospaced(sizes);

            // Save the font texture files if required
            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);
                    }
                }
            }

            // Build the font drop shadow if required
            if (_config.ShadowConfig != null)
            {
                fontData.DropShadowFont = BuildDropShadow(bitmapPages, glyphs, _config.ShadowConfig, _charSet.ToCharArray(), _config.KerningConfig.AlphaEmptyPixelTolerance);
            }

            // Clean up resources
            foreach (var page in bitmapPages)
            {
                page.Free();
            }

            // Check that no glyphs are overlapping
            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);
        }
Example #9
0
        /// <summary>
        /// Calculates the kerning values for the given character set
        /// </summary>
        /// <param name="charSet">The character set to calculate kerning values for</param>
        /// <param name="glyphs">The glyphs used for kerning</param>
        /// <param name="bitmapPages">The bitmap pages of the glyphs</param>
        /// <param name="config">The kerning configuration</param>
        /// <param name="font">The <see cref="IFont"/> used to create the glyphs and bitmaps</param>
        /// <returns>A <see cref="Dictionary{TKey,TValue}"/> mapping of every glyph pair to a kerning amount</returns>
        public static Dictionary <string, int> CalculateKerning(char[] charSet, QFontGlyph[] glyphs, List <QBitmap> bitmapPages, QFontKerningConfiguration config, IFont font = null)
        {
            var kerningPairs = new Dictionary <string, int>();

            //we start by computing the index of the first and last non-empty pixel in each row of each glyph
            XLimits[][] limits    = new XLimits[charSet.Length][];
            int         maxHeight = 0;

            for (int n = 0; n < charSet.Length; n++)
            {
                var rect = glyphs[n].Rect;
                var page = bitmapPages[glyphs[n].Page];

                limits[n] = new XLimits[rect.Height + 1];

                maxHeight = Math.Max(rect.Height, maxHeight);

                int yStart = rect.Y;
                int yEnd   = rect.Y + rect.Height;
                int xStart = rect.X;
                int xEnd   = rect.X + rect.Width;

                for (int j = yStart; j <= yEnd; j++)
                {
                    int last = xStart;

                    bool yetToFindFirst = true;
                    for (int i = xStart; i <= xEnd; i++)
                    {
                        if (!QBitmap.EmptyAlphaPixel(page.BitmapData, i, j, config.AlphaEmptyPixelTolerance))
                        {
                            if (yetToFindFirst)
                            {
                                limits[n][j - yStart].Min = i - xStart;
                                yetToFindFirst            = false;
                            }
                            last = i;
                        }
                    }

                    limits[n][j - yStart].Max = last - xStart;

                    if (yetToFindFirst)
                    {
                        limits[n][j - yStart].Min = xEnd - 1;
                    }
                }
            }

            //we now bring up each row to the max (or min) of it's two adjacent rows, this is to stop glyphs sliding together too closely
            var tmp = new XLimits[maxHeight + 1];

            for (int n = 0; n < charSet.Length; n++)
            {
                //clear tmp
                for (int j = 0; j < limits[n].Length; j++)
                {
                    tmp[j] = limits[n][j];
                }

                for (int j = 0; j < limits[n].Length; j++)
                {
                    if (j != 0)
                    {
                        tmp[j].Min = Math.Min(limits[n][j - 1].Min, tmp[j].Min);
                        tmp[j].Max = Math.Max(limits[n][j - 1].Max, tmp[j].Max);
                    }

                    if (j != limits[n].Length - 1)
                    {
                        tmp[j].Min = Math.Min(limits[n][j + 1].Min, tmp[j].Min);
                        tmp[j].Max = Math.Max(limits[n][j + 1].Max, tmp[j].Max);
                    }
                }

                for (int j = 0; j < limits[n].Length; j++)
                {
                    limits[n][j] = tmp[j];
                }
            }

            // For each character in the character set,
            // combine it with every other character and add it to the kerning pair dictionary
            for (int i = 0; i < charSet.Length; i++)
            {
                for (int j = 0; j < charSet.Length; j++)
                {
                    kerningPairs.Add("" + charSet[i] + charSet[j], Kerning(glyphs[i], glyphs[j], limits[i], limits[j], config, font));
                }
            }

            return(kerningPairs);
        }
Example #10
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);
        }
Example #11
0
        private static void RetargetGlyphRectangleOutwards(BitmapData bitmapData, QFontGlyph glyph, bool setYOffset, byte alphaTolerance)
        {
            int startX, endX;
            int startY, endY;

            var rect = glyph.rect;

            EmptyDel emptyPix;

            if (bitmapData.PixelFormat == PixelFormat.Format32bppArgb)
            {
                emptyPix = delegate(BitmapData data, int x, int y) { return(QBitmap.EmptyAlphaPixel(data, x, y, alphaTolerance)); }
            }
            ;
            else
            {
                emptyPix = delegate(BitmapData data, int x, int y) { return(QBitmap.EmptyPixel(data, x, y)); }
            };

            unsafe
            {
                for (startX = rect.X; startX >= 0; startX--)
                {
                    bool foundPix = false;
                    for (int j = rect.Y; j <= rect.Y + rect.Height; j++)
                    {
                        if (!emptyPix(bitmapData, startX, j))
                        {
                            foundPix = true;
                            break;
                        }
                    }

                    if (!foundPix)
                    {
                        startX++;
                        break;
                    }
                }

                for (endX = rect.X + rect.Width; endX < bitmapData.Width; endX++)
                {
                    bool foundPix = false;
                    for (int j = rect.Y; j <= rect.Y + rect.Height; j++)
                    {
                        if (!emptyPix(bitmapData, endX, j))
                        {
                            foundPix = true;
                            break;
                        }
                    }

                    if (!foundPix)
                    {
                        endX--;
                        break;
                    }
                }

                for (startY = rect.Y; startY >= 0; startY--)
                {
                    bool foundPix = false;
                    for (int i = startX; i <= endX; i++)
                    {
                        if (!emptyPix(bitmapData, i, startY))
                        {
                            foundPix = true;
                            break;
                        }
                    }

                    if (!foundPix)
                    {
                        startY++;
                        break;
                    }
                }

                for (endY = rect.Y + rect.Height; endY < bitmapData.Height; endY++)
                {
                    bool foundPix = false;
                    for (int i = startX; i <= endX; i++)
                    {
                        if (!emptyPix(bitmapData, i, endY))
                        {
                            foundPix = true;
                            break;
                        }
                    }

                    if (!foundPix)
                    {
                        endY--;
                        break;
                    }
                }
            }

            glyph.rect = new Rectangle(startX, startY, endX - startX + 1, endY - startY + 1);

            if (setYOffset)
            {
                glyph.yOffset = glyph.rect.Y;
            }
        }
Example #12
0
		private void Form1_Paint(object _sender, PaintEventArgs _e)
		{
            m_allEdges.Clear();
            for (var i = 0; i < Map.SIZE; ++i)
            {
                for (var j = 0; j < Map.SIZE; ++j)
                {
                    if (m_map[i, j] > 0)
                    {
                        var rectEdges = GetRectEdges(new Rectangle((int)(i * SZ), (int)(j * SZ), (int)SZ, (int)SZ), m_map[i, j]);
                        if (j > 0 && m_map[i, j - 1] == 0)
                        {
                            m_allEdges.Add(rectEdges[0]);
                        }
                        if (i < (Map.SIZE - 1) && m_map[i + 1, j] == 0)
                        {
                            m_allEdges.Add(rectEdges[1]);
                        }
                        if (j < (Map.SIZE - 1) && m_map[i, j + 1] == 0)
                        {
                            m_allEdges.Add(rectEdges[2]);
                        }
                        if (i > 0 && m_map[i - 1, j] == 0)
                        {
                            m_allEdges.Add(rectEdges[3]);
                        }
                    }
                }
            }

			#region зона видимости

			using (var g = Graphics.FromImage(m_buf3))
			{
				g.SmoothingMode = SmoothingMode.AntiAlias;
				g.Clear(Color.Empty);

				Draw(_e, new PointF(Map.SIZE * SZ / 2 , Map.SIZE * SZ / 2 ), Color.White, 0, g);
			}

			#endregion


			using (var g = Graphics.FromImage(m_buf1))
			{
				//g.CompositingQuality = CompositingQuality.GammaCorrected;
				g.SmoothingMode = SmoothingMode.AntiAlias;
				g.Clear(Color.Empty);

				Draw(_e, new PointF(_mousePnt.X * SZ, _mousePnt.Y * SZ), Color.FromArgb(255, 255, 0, 0), 0, g);
			}
			using (var g = Graphics.FromImage(m_buf2))
			{
				//g.CompositingQuality = CompositingQuality.GammaCorrected;
				g.SmoothingMode = SmoothingMode.AntiAlias;
				g.Clear(Color.Empty);

				Draw(_e, new PointF(_mousePnt.Y * SZ, _mousePnt.X * SZ), Color.FromArgb(255, 0, 0, 255), 0, g);
			}
			using (var g = Graphics.FromImage(m_buf0))
			{
				//g.CompositingQuality = CompositingQuality.GammaCorrected;
				g.SmoothingMode = SmoothingMode.AntiAlias;
				g.Clear(Color.Empty);

				Draw(_e, new PointF(_mousePnt.Y * SZ, _mousePnt.Y * SZ), Color.FromArgb(255, 0, 255, 0), 0, g);
			}
			//DrawWalls(m_buf2);

			using (var t= new QBitmap(m_buf3))
			{
				t.ApplyLightMaps(new[] { m_buf0, m_buf1, m_buf2 });
			}

			//_e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
			_e.Graphics.CompositingMode = CompositingMode.SourceCopy;
			//_e.Graphics.InterpolationMode = InterpolationMode.Bilinear;
			_e.Graphics.DrawImage(m_buf3, new RectangleF(0, 0, Map.SIZE , Map.SIZE ), new RectangleF(0, 0, Map.SIZE * SZ, Map.SIZE * SZ), GraphicsUnit.Pixel);
			
			//Draw(_e, new PointF(_mousePnt.Y - m_offset.Y, _mousePnt.X - m_offset.X), Color.FromArgb(180, 255, 0), Map.SIZE);
            //Draw(_e, new PointF(_mousePnt.X - m_offset.X, _mousePnt.Y - m_offset.Y), Color.FromArgb(255, 180, 0), Map.SIZE * 2);
        }
Example #13
0
        /*

        public void Blur(int radius, int passes)
        {
            QBitmap tmp = new QBitmap(new Bitmap(this.bitmap.Width, this.bitmap.Height, bitmap.PixelFormat));

            byte r=0,g=0,b=0,a=0;
            int summedR, summedG, summedB, summedA;
            int weight = 0;
            int xpos, ypos, x, y, kx, ky;

            for (int pass = 0; pass < passes; pass++)
            {

                //horizontal pass
                for (y = 0; y < bitmap.Height; y++)
                {
                    for (x = 0; x < bitmap.Width; x++)
                    {
                        summedR = summedG = summedB = summedA = weight = 0;
                        for (kx = -radius; kx <= radius; kx++)
                        {
                            xpos = x + kx;
                            if (xpos >= 0 && xpos < bitmap.Width)
                            {
                                GetPixel32(xpos, y, ref r, ref g, ref b, ref a);

                                summedR += r;
                                summedG += g;
                                summedB += b;
                                summedA += a;
                                weight++;
                            }

                        }

                        summedR /= weight;
                        summedG /= weight;
                        summedB /= weight;
                        summedA /= weight;

                        tmp.PutPixel32(x, y, (byte)summedR, (byte)summedG, (byte)summedB, (byte)summedA);
                    }
                }

                //vertical pass
                for (x = 0; x < bitmap.Width; ++x)
                {
                    for (y = 0; y < bitmap.Height; ++y)
                    {
                        summedR = summedG = summedB = summedA = weight = 0;
                        for (ky = -radius; ky <= radius; ky++)
                        {
                            ypos = y + ky;
                            if (ypos >= 0 && ypos < bitmap.Height)
                            {
                                tmp.GetPixel32(x, ypos, ref r, ref g, ref b, ref a);

                                summedR += r;
                                summedG += g;
                                summedB += b;
                                summedA += a;
                                weight++;
                            }
                        }

                        summedR /= weight;
                        summedG /= weight;
                        summedB /= weight;
                        summedA /= weight;

                        PutPixel32(x, y, (byte)summedR, (byte)summedG, (byte)summedB, (byte)summedA);

                    }
                }

            }

            tmp.Free();

        }*/
        public void ExpandAlpha(int radius, int passes)
        {
            QBitmap tmp = new QBitmap(new Bitmap(this.bitmap.Width, this.bitmap.Height, bitmap.PixelFormat));

            byte a = 0;
            byte max;
            int xpos, ypos, x, y, kx, ky;
            int width = bitmap.Width;
            int height = bitmap.Height;

            for (int pass = 0; pass < passes; pass++)
            {

                //horizontal pass
                for (y = 0; y < height; y++)
                {
                    for (x = 0; x < width; x++)
                    {
                        max = 0;
                        for (kx = -radius; kx <= radius; kx++)
                        {
                            xpos = x + kx;
                            if (xpos >= 0 && xpos < width)
                            {
                                GetAlpha32(xpos, y, ref a);
                                if (a > max)
                                    max = a;
                            }
                        }

                        tmp.PutAlpha32(x, y, max);
                    }
                }

                //vertical pass
                for (x = 0; x < width; ++x)
                {
                    for (y = 0; y < height; ++y)
                    {
                        max = 0;
                        for (ky = -radius; ky <= radius; ky++)
                        {
                            ypos = y + ky;
                            if (ypos >= 0 && ypos < height)
                            {
                                tmp.GetAlpha32(x, ypos, ref a);
                                if (a > max)
                                    max = a;
                            }
                        }

                        PutAlpha32(x, y, max);

                    }
                }

            }

            tmp.Free();
        }
Example #14
0
        public void ApplyLightMaps(Bitmap[] _lightmaps)
        {
            unsafe
            {
                var lightQMaps = new QBitmap[_lightmaps.Length];
                var ptrs       = new byte *[_lightmaps.Length];
                for (var index = 0; index < _lightmaps.Length; index++)
                {
                    lightQMaps[index] = new QBitmap(_lightmaps[index]);
                    ptrs[index]       = (byte *)(lightQMaps[index].m_bitmapData.Scan0);
                }

                var sourcePtr = (byte *)(m_bitmapData.Scan0);

                byte r, g, b;
                byte vr, vg, vb;
                for (var i = 0; i < m_bitmapData.Height; i++)
                {
                    for (var j = 0; j < m_bitmapData.Width; j++)
                    {
                        vr = *(sourcePtr + 2);
                        vg = *(sourcePtr + 1);
                        vb = *(sourcePtr + 0);

                        r = 0;
                        g = 0;
                        b = 0;
                        for (var index = 0; index < _lightmaps.Length; index++)
                        {
                            r            = Math.Max(r, *(ptrs[index] + 2));
                            g            = Math.Max(g, *(ptrs[index] + 1));
                            b            = Math.Max(b, *(ptrs[index] + 0));
                            ptrs[index] += 4;
                        }

                        r = (byte)(r * vr / 255);
                        g = (byte)(g * vg / 255);
                        b = (byte)(b * vb / 255);


                        //if (vr > 0 && r>0)
                        //{
                        //	vr += 1;
                        //}

                        *(sourcePtr)     = b;
                        *(sourcePtr + 1) = g;
                        *(sourcePtr + 2) = r;
                        //*(sourcePtr + 3) = _a;

                        sourcePtr += 4;
                    }
                    sourcePtr += m_bitmapData.Stride - m_bitmapData.Width * 4;                     //move to the end of the line (past unused space)
                    for (var index = 0; index < _lightmaps.Length; index++)
                    {
                        ptrs[index] += m_bitmapData.Stride - m_bitmapData.Width * 4;                         //move to the end of the line (past unused space)
                    }
                }

                for (var index = 0; index < _lightmaps.Length; index++)
                {
                    lightQMaps[index].Dispose();
                }
            }
        }
Example #15
0
	    public void ApplyLightMaps(Bitmap[] _lightmaps)
	    {

			
			unsafe
			{

				var lightQMaps = new QBitmap[_lightmaps.Length];
				var ptrs = new byte*[_lightmaps.Length];
				for (var index = 0; index < _lightmaps.Length; index++)
				{
					lightQMaps[index] = new QBitmap(_lightmaps[index]);
					ptrs[index] = (byte*)(lightQMaps[index].m_bitmapData.Scan0);
				}

				var sourcePtr = (byte*)(m_bitmapData.Scan0);

				byte r, g, b;
				byte vr, vg, vb;
				for (var i = 0; i < m_bitmapData.Height; i++)
				{
					for (var j = 0; j < m_bitmapData.Width; j++)
					{
						vr = *(sourcePtr + 2);
						vg = *(sourcePtr + 1);
						vb = *(sourcePtr + 0);

						r = 0;
						g = 0;
						b = 0;
						for (var index = 0; index < _lightmaps.Length; index++)
						{
							r = Math.Max(r, *(ptrs[index] + 2));
							g = Math.Max(g,*(ptrs[index] + 1));
							b = Math.Max(b,*(ptrs[index] + 0));
							ptrs[index] += 4;
						}

						r = (byte)(r * vr / 255);
						g = (byte)(g*vg/255);
						b = (byte)(b*vb/255);


						//if (vr > 0 && r>0)
						//{
						//	vr += 1;
						//}

						*(sourcePtr) = b;
						*(sourcePtr + 1) = g;
						*(sourcePtr + 2) = r;
						//*(sourcePtr + 3) = _a;

						sourcePtr += 4;
					}
					sourcePtr += m_bitmapData.Stride - m_bitmapData.Width * 4; //move to the end of the line (past unused space)
					for (var index = 0; index < _lightmaps.Length; index++)
					{
						ptrs[index] += m_bitmapData.Stride - m_bitmapData.Width * 4; //move to the end of the line (past unused space)
					}
				}

				for (var index = 0; index < _lightmaps.Length; index++)
				{
					lightQMaps[index].Dispose();
				}
			}
		}
Example #16
0
        public void DownScale32(int newWidth, int newHeight)
        {
            QBitmap newBitmap = new QBitmap(new Bitmap(newWidth, newHeight, bitmap.PixelFormat));

            if (bitmap.PixelFormat != PixelFormat.Format32bppArgb)
            {
                throw new Exception("DownsScale32 only works on 32 bit images");
            }

            float xscale = (float)bitmapData.Width / newWidth;
            float yscale = (float)bitmapData.Height / newHeight;

            byte  r = 0, g = 0, b = 0, a = 0;
            float summedR = 0f;
            float summedG = 0f;
            float summedB = 0f;
            float summedA = 0f;

            int left, right, top, bottom;  //the area of old pixels covered by the new bitmap


            float targetStartX, targetEndX;
            float targetStartY, targetEndY;

            float leftF, rightF, topF, bottomF; //edges of new pixel in old pixel coords
            float weight;
            float weightScale       = xscale * yscale;
            float totalColourWeight = 0f;

            for (int m = 0; m < newHeight; m++)
            {
                for (int n = 0; n < newWidth; n++)
                {
                    leftF  = n * xscale;
                    rightF = (n + 1) * xscale;

                    topF    = m * yscale;
                    bottomF = (m + 1) * yscale;

                    left  = (int)leftF;
                    right = (int)rightF;

                    top    = (int)topF;
                    bottom = (int)bottomF;

                    if (left < 0)
                    {
                        left = 0;
                    }
                    if (top < 0)
                    {
                        top = 0;
                    }
                    if (right >= bitmapData.Width)
                    {
                        right = bitmapData.Width - 1;
                    }
                    if (bottom >= bitmapData.Height)
                    {
                        bottom = bitmapData.Height - 1;
                    }

                    summedR           = 0f;
                    summedG           = 0f;
                    summedB           = 0f;
                    summedA           = 0f;
                    totalColourWeight = 0f;

                    for (int j = top; j <= bottom; j++)
                    {
                        for (int i = left; i <= right; i++)
                        {
                            targetStartX = Math.Max(leftF, i);
                            targetEndX   = Math.Min(rightF, i + 1);

                            targetStartY = Math.Max(topF, j);
                            targetEndY   = Math.Min(bottomF, j + 1);

                            weight = (targetEndX - targetStartX) * (targetEndY - targetStartY);

                            GetPixel32(i, j, ref r, ref g, ref b, ref a);

                            summedA += weight * a;

                            if (a != 0)
                            {
                                summedR           += weight * r;
                                summedG           += weight * g;
                                summedB           += weight * b;
                                totalColourWeight += weight;
                            }
                        }
                    }

                    summedR /= totalColourWeight;
                    summedG /= totalColourWeight;
                    summedB /= totalColourWeight;
                    summedA /= weightScale;

                    if (summedR < 0)
                    {
                        summedR = 0f;
                    }
                    if (summedG < 0)
                    {
                        summedG = 0f;
                    }
                    if (summedB < 0)
                    {
                        summedB = 0f;
                    }
                    if (summedA < 0)
                    {
                        summedA = 0f;
                    }

                    if (summedR >= 256)
                    {
                        summedR = 255;
                    }
                    if (summedG >= 256)
                    {
                        summedG = 255;
                    }
                    if (summedB >= 256)
                    {
                        summedB = 255;
                    }
                    if (summedA >= 256)
                    {
                        summedA = 255;
                    }

                    newBitmap.PutPixel32(n, m, (byte)summedR, (byte)summedG, (byte)summedB, (byte)summedA);
                }
            }


            this.Free();

            this.bitmap     = newBitmap.bitmap;
            this.bitmapData = newBitmap.bitmapData;
        }
Example #17
0
        /*
         *
         * public void Blur(int radius, int passes)
         * {
         *  QBitmap tmp = new QBitmap(new Bitmap(this.bitmap.Width, this.bitmap.Height, bitmap.PixelFormat));
         *
         *  byte r=0,g=0,b=0,a=0;
         *  int summedR, summedG, summedB, summedA;
         *  int weight = 0;
         *  int xpos, ypos, x, y, kx, ky;
         *
         *
         *  for (int pass = 0; pass < passes; pass++)
         *  {
         *
         *      //horizontal pass
         *      for (y = 0; y < bitmap.Height; y++)
         *      {
         *          for (x = 0; x < bitmap.Width; x++)
         *          {
         *              summedR = summedG = summedB = summedA = weight = 0;
         *              for (kx = -radius; kx <= radius; kx++)
         *              {
         *                  xpos = x + kx;
         *                  if (xpos >= 0 && xpos < bitmap.Width)
         *                  {
         *                      GetPixel32(xpos, y, ref r, ref g, ref b, ref a);
         *
         *
         *                      summedR += r;
         *                      summedG += g;
         *                      summedB += b;
         *                      summedA += a;
         *                      weight++;
         *                  }
         *
         *              }
         *
         *              summedR /= weight;
         *              summedG /= weight;
         *              summedB /= weight;
         *              summedA /= weight;
         *
         *              tmp.PutPixel32(x, y, (byte)summedR, (byte)summedG, (byte)summedB, (byte)summedA);
         *          }
         *      }
         *
         *
         *
         *
         *      //vertical pass
         *      for (x = 0; x < bitmap.Width; ++x)
         *      {
         *          for (y = 0; y < bitmap.Height; ++y)
         *          {
         *              summedR = summedG = summedB = summedA = weight = 0;
         *              for (ky = -radius; ky <= radius; ky++)
         *              {
         *                  ypos = y + ky;
         *                  if (ypos >= 0 && ypos < bitmap.Height)
         *                  {
         *                      tmp.GetPixel32(x, ypos, ref r, ref g, ref b, ref a);
         *
         *                      summedR += r;
         *                      summedG += g;
         *                      summedB += b;
         *                      summedA += a;
         *                      weight++;
         *                  }
         *              }
         *
         *              summedR /= weight;
         *              summedG /= weight;
         *              summedB /= weight;
         *              summedA /= weight;
         *
         *              PutPixel32(x, y, (byte)summedR, (byte)summedG, (byte)summedB, (byte)summedA);
         *
         *          }
         *      }
         *
         *  }
         *
         *  tmp.Free();
         *
         * }*/



        public void BlurAlpha(int radius, int passes)
        {
            QBitmap tmp = new QBitmap(new Bitmap(this.bitmap.Width, this.bitmap.Height, bitmap.PixelFormat));

            byte a = 0;
            int  summedA;
            int  weight = 0;
            int  xpos, ypos, x, y, kx, ky;
            int  width  = bitmap.Width;
            int  height = bitmap.Height;

            for (int pass = 0; pass < passes; pass++)
            {
                //horizontal pass
                for (y = 0; y < height; y++)
                {
                    for (x = 0; x < width; x++)
                    {
                        summedA = weight = 0;
                        for (kx = -radius; kx <= radius; kx++)
                        {
                            xpos = x + kx;
                            if (xpos >= 0 && xpos < width)
                            {
                                GetAlpha32(xpos, y, ref a);
                                summedA += a;
                                weight++;
                            }
                        }

                        summedA /= weight;
                        tmp.PutAlpha32(x, y, (byte)summedA);
                    }
                }



                //vertical pass
                for (x = 0; x < width; ++x)
                {
                    for (y = 0; y < height; ++y)
                    {
                        summedA = weight = 0;
                        for (ky = -radius; ky <= radius; ky++)
                        {
                            ypos = y + ky;
                            if (ypos >= 0 && ypos < height)
                            {
                                tmp.GetAlpha32(x, ypos, ref a);
                                summedA += a;
                                weight++;
                            }
                        }

                        summedA /= weight;

                        PutAlpha32(x, y, (byte)summedA);
                    }
                }
            }

            tmp.Free();
        }
Example #18
0
        /*
         *
         * public void Blur(int radius, int passes)
         * {
         *  QBitmap tmp = new QBitmap(new Bitmap(this.bitmap.Width, this.bitmap.Height, bitmap.PixelFormat));
         *
         *  byte r=0,g=0,b=0,a=0;
         *  int summedR, summedG, summedB, summedA;
         *  int weight = 0;
         *  int xpos, ypos, x, y, kx, ky;
         *
         *
         *  for (int pass = 0; pass < passes; pass++)
         *  {
         *
         *      //horizontal pass
         *      for (y = 0; y < bitmap.Height; y++)
         *      {
         *          for (x = 0; x < bitmap.Width; x++)
         *          {
         *              summedR = summedG = summedB = summedA = weight = 0;
         *              for (kx = -radius; kx <= radius; kx++)
         *              {
         *                  xpos = x + kx;
         *                  if (xpos >= 0 && xpos < bitmap.Width)
         *                  {
         *                      GetPixel32(xpos, y, ref r, ref g, ref b, ref a);
         *
         *
         *                      summedR += r;
         *                      summedG += g;
         *                      summedB += b;
         *                      summedA += a;
         *                      weight++;
         *                  }
         *
         *              }
         *
         *              summedR /= weight;
         *              summedG /= weight;
         *              summedB /= weight;
         *              summedA /= weight;
         *
         *              tmp.PutPixel32(x, y, (byte)summedR, (byte)summedG, (byte)summedB, (byte)summedA);
         *          }
         *      }
         *
         *
         *
         *
         *      //vertical pass
         *      for (x = 0; x < bitmap.Width; ++x)
         *      {
         *          for (y = 0; y < bitmap.Height; ++y)
         *          {
         *              summedR = summedG = summedB = summedA = weight = 0;
         *              for (ky = -radius; ky <= radius; ky++)
         *              {
         *                  ypos = y + ky;
         *                  if (ypos >= 0 && ypos < bitmap.Height)
         *                  {
         *                      tmp.GetPixel32(x, ypos, ref r, ref g, ref b, ref a);
         *
         *                      summedR += r;
         *                      summedG += g;
         *                      summedB += b;
         *                      summedA += a;
         *                      weight++;
         *                  }
         *              }
         *
         *              summedR /= weight;
         *              summedG /= weight;
         *              summedB /= weight;
         *              summedA /= weight;
         *
         *              PutPixel32(x, y, (byte)summedR, (byte)summedG, (byte)summedB, (byte)summedA);
         *
         *          }
         *      }
         *
         *  }
         *
         *  tmp.Free();
         *
         * }*/

        public void ExpandAlpha(int radius, int passes)
        {
            QBitmap tmp = new QBitmap(new Bitmap(this.bitmap.Width, this.bitmap.Height, bitmap.PixelFormat));

            byte a = 0;
            byte max;
            int  xpos, ypos, x, y, kx, ky;
            int  width  = bitmap.Width;
            int  height = bitmap.Height;

            for (int pass = 0; pass < passes; pass++)
            {
                //horizontal pass
                for (y = 0; y < height; y++)
                {
                    for (x = 0; x < width; x++)
                    {
                        max = 0;
                        for (kx = -radius; kx <= radius; kx++)
                        {
                            xpos = x + kx;
                            if (xpos >= 0 && xpos < width)
                            {
                                GetAlpha32(xpos, y, ref a);
                                if (a > max)
                                {
                                    max = a;
                                }
                            }
                        }

                        tmp.PutAlpha32(x, y, max);
                    }
                }

                //vertical pass
                for (x = 0; x < width; ++x)
                {
                    for (y = 0; y < height; ++y)
                    {
                        max = 0;
                        for (ky = -radius; ky <= radius; ky++)
                        {
                            ypos = y + ky;
                            if (ypos >= 0 && ypos < height)
                            {
                                tmp.GetAlpha32(x, ypos, ref a);
                                if (a > max)
                                {
                                    max = a;
                                }
                            }
                        }

                        PutAlpha32(x, y, max);
                    }
                }
            }

            tmp.Free();
        }
Example #19
0
        private static List <QBitmap> GenerateBitmapSheetsAndRepack(QFontGlyph[] sourceGlyphs, BitmapData[] sourceBitmaps, int destSheetWidth, int destSheetHeight, out QFontGlyph[] destGlyphs, int destMargin)
        {
            var pages = new List <QBitmap>();

            destGlyphs = new QFontGlyph[sourceGlyphs.Length];

            QBitmap currentPage = null;

            int maxY = 0;

            foreach (var glph in sourceGlyphs)
            {
                maxY = Math.Max(glph.rect.Height, maxY);
            }

            int finalPageIndex          = 0;
            int finalPageRequiredWidth  = 0;
            int finalPageRequiredHeight = 0;

            for (int k = 0; k < 2; k++)
            {
                bool pre = k == 0;  //first iteration is simply to determine the required size of the final page, so that we can crop it in advance

                int xPos       = 0;
                int yPos       = 0;
                int maxYInRow  = 0;
                int totalTries = 0;

                for (int i = 0; i < sourceGlyphs.Length; i++)
                {
                    if (!pre && currentPage == null)
                    {
                        if (finalPageIndex == pages.Count)
                        {
                            int width  = Math.Min(destSheetWidth, finalPageRequiredWidth);
                            int height = Math.Min(destSheetHeight, finalPageRequiredHeight);

                            currentPage = new QBitmap(new Bitmap(width, height, PixelFormat.Format32bppArgb));
                            currentPage.Clear32(255, 255, 255, 0); //clear to white, but totally transparent
                        }
                        else
                        {
                            currentPage = new QBitmap(new Bitmap(destSheetWidth, destSheetHeight, PixelFormat.Format32bppArgb));
                            currentPage.Clear32(255, 255, 255, 0); //clear to white, but totally transparent
                        }
                        pages.Add(currentPage);
                    }

                    totalTries++;

                    if (totalTries > 10 * sourceGlyphs.Length)
                    {
                        throw new Exception("Failed to fit font into texture pages");
                    }

                    var rect = sourceGlyphs[i].rect;

                    if (xPos + rect.Width + 2 * destMargin <= destSheetWidth && yPos + rect.Height + 2 * destMargin <= destSheetHeight)
                    {
                        if (!pre)
                        {
                            //add to page
                            if (sourceBitmaps[sourceGlyphs[i].page].PixelFormat == PixelFormat.Format32bppArgb)
                            {
                                QBitmap.Blit(sourceBitmaps[sourceGlyphs[i].page], currentPage.bitmapData, rect.X, rect.Y, rect.Width, rect.Height, xPos + destMargin, yPos + destMargin);
                            }
                            else
                            {
                                QBitmap.BlitMask(sourceBitmaps[sourceGlyphs[i].page], currentPage.bitmapData, rect.X, rect.Y, rect.Width, rect.Height, xPos + destMargin, yPos + destMargin);
                            }

                            destGlyphs[i] = new QFontGlyph(pages.Count - 1, new Rectangle(xPos + destMargin, yPos + destMargin, rect.Width, rect.Height), sourceGlyphs[i].yOffset, sourceGlyphs[i].character);
                        }
                        else
                        {
                            finalPageRequiredWidth  = Math.Max(finalPageRequiredWidth, xPos + rect.Width + 2 * destMargin);
                            finalPageRequiredHeight = Math.Max(finalPageRequiredHeight, yPos + rect.Height + 2 * destMargin);
                        }

                        xPos     += rect.Width + 2 * destMargin;
                        maxYInRow = Math.Max(maxYInRow, rect.Height);

                        continue;
                    }

                    if (xPos + rect.Width + 2 * destMargin > destSheetWidth)
                    {
                        i--;

                        yPos += maxYInRow + 2 * destMargin;
                        xPos  = 0;

                        if (yPos + maxY + 2 * destMargin > destSheetHeight)
                        {
                            yPos = 0;

                            if (!pre)
                            {
                                currentPage = null;
                            }
                            else
                            {
                                finalPageRequiredWidth  = 0;
                                finalPageRequiredHeight = 0;
                                finalPageIndex++;
                            }
                        }
                        continue;
                    }
                }
            }

            return(pages);
        }
Example #20
0
        public void DownScale32(int newWidth, int newHeight)
        {
            

            QBitmap newBitmap = new QBitmap(new Bitmap(newWidth, newHeight, bitmap.PixelFormat));

            if (bitmap.PixelFormat != PixelFormat.Format32bppArgb)
                throw new Exception("DownsScale32 only works on 32 bit images");

            float xscale = (float)bitmapData.Width / newWidth;
            float yscale = (float)bitmapData.Height / newHeight;

            byte r = 0, g = 0, b = 0, a = 0;
            float summedR = 0f;
            float summedG = 0f;
            float summedB = 0f;
            float summedA = 0f;

            int left, right, top, bottom;  //the area of old pixels covered by the new bitmap


            float targetStartX, targetEndX;
            float targetStartY, targetEndY;

            float leftF, rightF, topF, bottomF; //edges of new pixel in old pixel coords
            float weight;
            float weightScale = xscale * yscale;
            float totalColourWeight = 0f;

            for (int m = 0; m < newHeight; m++)
            {
                for (int n = 0; n < newWidth; n++)
                {

                    leftF = n * xscale;
                    rightF = (n + 1) * xscale;

                    topF = m * yscale;
                    bottomF = (m + 1) * yscale;

                    left = (int)leftF;
                    right = (int)rightF;

                    top = (int)topF;
                    bottom = (int)bottomF;

                    if (left < 0) left = 0;
                    if (top < 0) top = 0;
                    if (right >= bitmapData.Width) right = bitmapData.Width - 1;
                    if (bottom >= bitmapData.Height) bottom = bitmapData.Height - 1;

                    summedR = 0f;
                    summedG = 0f;
                    summedB = 0f;
                    summedA = 0f;
                    totalColourWeight = 0f;

                    for (int j = top; j <= bottom; j++)
                    {
                        for (int i = left; i <= right; i++)
                        {
                            targetStartX = Math.Max(leftF, i);
                            targetEndX = Math.Min(rightF, i + 1);

                            targetStartY = Math.Max(topF, j);
                            targetEndY = Math.Min(bottomF, j + 1);

                            weight = (targetEndX - targetStartX) * (targetEndY - targetStartY);

                            GetPixel32(i, j, ref r, ref g, ref b, ref a);

                            summedA += weight * a;

                            if (a != 0)
                            {
                                summedR += weight * r;
                                summedG += weight * g;
                                summedB += weight * b;
                                totalColourWeight += weight;
                            }

                        }
                    }

                    summedR /= totalColourWeight;
                    summedG /= totalColourWeight;
                    summedB /= totalColourWeight;
                    summedA /= weightScale;

                    if (summedR < 0) summedR = 0f;
                    if (summedG < 0) summedG = 0f;
                    if (summedB < 0) summedB = 0f;
                    if (summedA < 0) summedA = 0f;

                    if (summedR >= 256) summedR = 255;
                    if (summedG >= 256) summedG = 255;
                    if (summedB >= 256) summedB = 255;
                    if (summedA >= 256) summedA = 255;

                    newBitmap.PutPixel32(n, m, (byte)summedR, (byte)summedG, (byte)summedB, (byte)summedA);
                }

            }
            

            this.Free();
            
            this.bitmap = newBitmap.bitmap;
            this.bitmapData = newBitmap.bitmapData;
        }
        public static Dictionary <String, int> CalculateKerning(char[] charSet, QFontGlyph[] glyphs, List <QBitmap> bitmapPages, QFontKerningConfiguration config)
        {
            var kerningPairs = new Dictionary <String, int>();



            //we start by computing the index of the first and last non-empty pixel in each row of each glyph
            XLimits[][] limits    = new XLimits[charSet.Length][];
            int         maxHeight = 0;

            for (int n = 0; n < charSet.Length; n++)
            {
                var rect = glyphs[n].rect;
                var page = bitmapPages[glyphs[n].page];

                limits[n] = new XLimits[rect.Height];

                maxHeight = Math.Max(rect.Height, maxHeight);

                int yStart = rect.Y;
                int yEnd   = rect.Y + rect.Height;
                int xStart = rect.X;
                int xEnd   = rect.X + rect.Width;

                for (int j = yStart; j < yEnd; j++)
                {
                    int last = xStart;

                    bool yetToFindFirst = true;
                    for (int i = xStart; i < xEnd; i++)
                    {
                        if (!QBitmap.EmptyAlphaPixel(page.bitmapData, i, j, config.alphaEmptyPixelTolerance))
                        {
                            if (yetToFindFirst)
                            {
                                limits[n][j - yStart].Min = i - xStart;
                                yetToFindFirst            = false;
                            }
                            last = i;
                        }
                    }

                    limits[n][j - yStart].Max = last - xStart;

                    if (yetToFindFirst)
                    {
                        limits[n][j - yStart].Min = xEnd - 1;
                    }
                }
            }


            //we now bring up each row to the max (or min) of it's two adjacent rows, this is to stop glyphs sliding together too closely
            var tmp = new XLimits[maxHeight];

            for (int n = 0; n < charSet.Length; n++)
            {
                //clear tmp
                for (int j = 0; j < limits[n].Length; j++)
                {
                    tmp[j] = limits[n][j];
                }

                for (int j = 0; j < limits[n].Length; j++)
                {
                    if (j != 0)
                    {
                        tmp[j].Min = Math.Min(limits[n][j - 1].Min, tmp[j].Min);
                        tmp[j].Max = Math.Max(limits[n][j - 1].Max, tmp[j].Max);
                    }

                    if (j != limits[n].Length - 1)
                    {
                        tmp[j].Min = Math.Min(limits[n][j + 1].Min, tmp[j].Min);
                        tmp[j].Max = Math.Max(limits[n][j + 1].Max, tmp[j].Max);
                    }
                }

                for (int j = 0; j < limits[n].Length; j++)
                {
                    limits[n][j] = tmp[j];
                }
            }

            //поправил сам
            if (config.KerningPairs == null)
            {
                for (int i = 0; i < charSet.Length; i++)
                {
                    for (int j = 0; j < charSet.Length; j++)
                    {
                        kerningPairs.Add("" + charSet[i] + charSet[j], 1 - Kerning(glyphs[i], glyphs[j], limits[i], limits[j], config));
                    }
                }
            }
            else
            {
                var chatSetList = charSet.ToList();
                var indices     = config.KerningPairs.Select(x => Tuple.Create(chatSetList.IndexOf(x[0]), chatSetList.IndexOf(x[1]))).ToList();
                foreach (var pair in indices)
                {
                    int i = pair.Item1;
                    int j = pair.Item2;
                    kerningPairs.Add("" + charSet[i] + charSet[j], 1 - Kerning(glyphs[i], glyphs[j], limits[i], limits[j], config));
                }
            }
            return(kerningPairs);
        }
Example #22
0
        /*

        public void Blur(int radius, int passes)
        {
            QBitmap tmp = new QBitmap(new Bitmap(this.bitmap.Width, this.bitmap.Height, bitmap.PixelFormat));

            byte r=0,g=0,b=0,a=0;
            int summedR, summedG, summedB, summedA;
            int weight = 0;
            int xpos, ypos, x, y, kx, ky;


            for (int pass = 0; pass < passes; pass++)
            {

                //horizontal pass
                for (y = 0; y < bitmap.Height; y++)
                {
                    for (x = 0; x < bitmap.Width; x++)
                    {
                        summedR = summedG = summedB = summedA = weight = 0;
                        for (kx = -radius; kx <= radius; kx++)
                        {
                            xpos = x + kx;
                            if (xpos >= 0 && xpos < bitmap.Width)
                            {
                                GetPixel32(xpos, y, ref r, ref g, ref b, ref a);


                                summedR += r;
                                summedG += g;
                                summedB += b;
                                summedA += a;
                                weight++;
                            }

                        }

                        summedR /= weight;
                        summedG /= weight;
                        summedB /= weight;
                        summedA /= weight;

                        tmp.PutPixel32(x, y, (byte)summedR, (byte)summedG, (byte)summedB, (byte)summedA);
                    }
                }



                
                //vertical pass
                for (x = 0; x < bitmap.Width; ++x)
                {
                    for (y = 0; y < bitmap.Height; ++y)
                    {
                        summedR = summedG = summedB = summedA = weight = 0;
                        for (ky = -radius; ky <= radius; ky++)
                        {
                            ypos = y + ky;
                            if (ypos >= 0 && ypos < bitmap.Height)
                            {
                                tmp.GetPixel32(x, ypos, ref r, ref g, ref b, ref a);

                                summedR += r;
                                summedG += g;
                                summedB += b;
                                summedA += a;
                                weight++;
                            }
                        }

                        summedR /= weight;
                        summedG /= weight;
                        summedB /= weight;
                        summedA /= weight;

                        PutPixel32(x, y, (byte)summedR, (byte)summedG, (byte)summedB, (byte)summedA);

                    }
                } 

            }

            tmp.Free();

        }*/




        public void BlurAlpha(int radius, int passes)
        {
            QBitmap tmp = new QBitmap(new Bitmap(this.bitmap.Width, this.bitmap.Height, bitmap.PixelFormat));

            byte a = 0;
            int summedA;
            int weight = 0;
            int xpos, ypos, x, y, kx, ky;
            int width = bitmap.Width;
            int height = bitmap.Height;

            for (int pass = 0; pass < passes; pass++)
            {

                //horizontal pass
                for (y = 0; y < height; y++)
                {
                    for (x = 0; x < width; x++)
                    {
                        summedA = weight = 0;
                        for (kx = -radius; kx <= radius; kx++)
                        {
                            xpos = x + kx;
                            if (xpos >= 0 && xpos < width)
                            {
                                GetAlpha32(xpos, y, ref a);
                                summedA += a;
                                weight++;
                            }
                        }

                        summedA /= weight;
                        tmp.PutAlpha32(x, y, (byte)summedA);
                    }
                }




                //vertical pass
                for (x = 0; x <width; ++x)
                {
                    for (y = 0; y < height; ++y)
                    {
                        summedA = weight = 0;
                        for (ky = -radius; ky <= radius; ky++)
                        {
                            ypos = y + ky;
                            if (ypos >= 0 && ypos < height)
                            {
                                tmp.GetAlpha32(x, ypos,ref a);
                                summedA += a;
                                weight++;
                            }
                        }

                        summedA /= weight;

                        PutAlpha32(x, y, (byte)summedA);

                    }
                }

            }

            tmp.Free();

        }
Example #23
0
        private static void RetargetGlyphRectangleInwards(BitmapData bitmapData, QFontGlyph glyph, bool setYOffset)
        {
            int startX, endX;
            int startY, endY;

            var rect = glyph.rect;

            EmptyDel emptyPix;

            if (bitmapData.PixelFormat == PixelFormat.Format32bppArgb)
            {
                emptyPix = delegate(BitmapData data, int x, int y) { return(QBitmap.EmptyAlphaPixel(data, x, y)); }
            }
            ;
            else
            {
                emptyPix = delegate(BitmapData data, int x, int y) { return(QBitmap.EmptyPixel(data, x, y)); }
            };


            unsafe
            {
                for (startX = rect.X; startX < bitmapData.Width; startX++)
                {
                    for (int j = rect.Y; j <= rect.Y + rect.Height; j++)
                    {
                        if (!emptyPix(bitmapData, startX, j))
                        {
                            goto Done1;
                        }
                    }
                }
Done1:

                for (endX = rect.X + rect.Width; endX >= 0; endX--)
                {
                    for (int j = rect.Y; j <= rect.Y + rect.Height; j++)
                    {
                        if (!emptyPix(bitmapData, endX, j))
                        {
                            goto Done2;
                        }
                    }
                }
Done2:

                for (startY = rect.Y; startY < bitmapData.Height; startY++)
                {
                    for (int i = startX; i <= endX; i++)
                    {
                        if (!emptyPix(bitmapData, i, startY))
                        {
                            goto Done3;
                        }
                    }
                }

Done3:

                for (endY = rect.Y + rect.Height; endY >= 0; endY--)
                {
                    for (int i = startX; i <= endX; i++)
                    {
                        if (!emptyPix(bitmapData, i, endY))
                        {
                            goto Done4;
                        }
                    }
                }
                Done4 :;
            }



            glyph.rect = new Rectangle(startX, startY, endX - startX + 1, endY - startY + 1);

            if (setYOffset)
            {
                glyph.yOffset = glyph.rect.Y;
            }
        }
Example #24
0
        /// <summary>
        /// Generates the final bitmap sheet for the font
        /// </summary>
        /// <param name="sourceGlyphs">A collection of <see cref="QFontGlyph"/>s. These are written to the final bitmap</param>
        /// <param name="sourceBitmaps"> The source bitmaps for the font (initial bitmap)</param>
        /// <param name="destSheetWidth">The destination bitmap width</param>
        /// <param name="destSheetHeight">The destination bitmap height</param>
        /// <param name="destGlyphs">A collection of <see cref="QFontGlyph"/>s that are placed on the final bitmap sheet</param>
        /// <param name="destMargin">The margin for the final bitmap sheet</param>
        /// <returns>A collection of <see cref="QBitmap"/>s. These are the final bitmap sheets</returns>
        private static List <QBitmap> GenerateBitmapSheetsAndRepack(QFontGlyph[] sourceGlyphs, BitmapData[] sourceBitmaps, int destSheetWidth, int destSheetHeight, out QFontGlyph[] destGlyphs, int destMargin)
        {
            var pages = new List <QBitmap>();

            destGlyphs = new QFontGlyph[sourceGlyphs.Length];

            QBitmap currentPage = null;

            int maxY = 0;

            foreach (var glph in sourceGlyphs)
            {
                maxY = Math.Max(glph.Rect.Height, maxY);
            }

            int finalPageIndex          = 0;
            int finalPageRequiredWidth  = 0;
            int finalPageRequiredHeight = 0;

            // We loop through the whole process twice. The first time is to determine
            // the size of the final page, so that we can crop it in advance
            for (int k = 0; k < 2; k++)
            {
                // Whether this is the pre-processing step
                bool pre = k == 0;

                int xPos       = 0;
                int yPos       = 0;
                int maxYInRow  = 0;
                int totalTries = 0;

                // Loop through all the glyphs
                for (int i = 0; i < sourceGlyphs.Length; i++)
                {
                    // If this is the second stage and we don't already have a bitmap page, create one
                    if (!pre && currentPage == null)
                    {
                        if (finalPageIndex == pages.Count)
                        {
                            int width  = Math.Min(destSheetWidth, finalPageRequiredWidth);
                            int height = Math.Min(destSheetHeight, finalPageRequiredHeight);

                            currentPage = new QBitmap(new Bitmap(width, height, PixelFormat.Format32bppArgb));
                            currentPage.Clear32(255, 255, 255, 0); //clear to white, but totally transparent
                        }
                        else
                        {
                            currentPage = new QBitmap(new Bitmap(destSheetWidth, destSheetHeight, PixelFormat.Format32bppArgb));
                            currentPage.Clear32(255, 255, 255, 0); //clear to white, but totally transparent
                        }
                        pages.Add(currentPage);
                    }

                    // Keep track of the number of times we've tried to fit the font onto the texture page
                    totalTries++;

                    if (totalTries > 10 * sourceGlyphs.Length)
                    {
                        throw new Exception("Failed to fit font into texture pages");
                    }

                    var rect = sourceGlyphs[i].Rect;

                    // If we can fit the glyph onto the page, place it
                    if (xPos + rect.Width + 2 * destMargin <= destSheetWidth && yPos + rect.Height + 2 * destMargin <= destSheetHeight)
                    {
                        if (!pre)
                        {
                            // Add to page
                            if (sourceBitmaps[sourceGlyphs[i].Page].PixelFormat == PixelFormat.Format32bppArgb)
                            {
                                QBitmap.Blit(sourceBitmaps[sourceGlyphs[i].Page], currentPage.BitmapData, rect.X, rect.Y, rect.Width, rect.Height, xPos + destMargin, yPos + destMargin);
                            }
                            else
                            {
                                QBitmap.BlitMask(sourceBitmaps[sourceGlyphs[i].Page], currentPage.BitmapData, rect.X, rect.Y, rect.Width, rect.Height, xPos + destMargin, yPos + destMargin);
                            }

                            // Add to destination glyph collection
                            destGlyphs[i] = new QFontGlyph(pages.Count - 1, new Rectangle(xPos + destMargin, yPos + destMargin, rect.Width, rect.Height), sourceGlyphs[i].YOffset, sourceGlyphs[i].Character);
                        }
                        else
                        {
                            // Update the final dimensions
                            finalPageRequiredWidth  = Math.Max(finalPageRequiredWidth, xPos + rect.Width + 2 * destMargin);
                            finalPageRequiredHeight = Math.Max(finalPageRequiredHeight, yPos + rect.Height + 2 * destMargin);
                        }

                        // Update the current x position
                        xPos += rect.Width + 2 * destMargin;

                        // Update the maximum row height so far
                        maxYInRow = Math.Max(maxYInRow, rect.Height);

                        continue;
                    }

                    // If we reach this, haven't been able to fit glyph onto row
                    // Move down one row and try again
                    if (xPos + rect.Width + 2 * destMargin > destSheetWidth)
                    {
                        // Retry the current glyph on the next row
                        i--;

                        // Change coordinates to next row
                        yPos += maxYInRow + 2 * destMargin;
                        xPos  = 0;

                        // Is the next row off the bitmap sheet?
                        if (yPos + maxY + 2 * destMargin > destSheetHeight)
                        {
                            // Reset y position
                            yPos = 0;

                            if (!pre)
                            {
                                // If this is not the second stage, reset the currentPage
                                // This will create a new one on next loop
                                currentPage = null;
                            }
                            else
                            {
                                // If this is the pre-processing stage, update
                                // the finalPageIndex. Reset width and height
                                // since we clearly need one full page and extra
                                finalPageRequiredWidth  = 0;
                                finalPageRequiredHeight = 0;
                                finalPageIndex++;
                            }
                        }
                    }
                }
            }

            return(pages);
        }