Ejemplo n.º 1
0
		/// <summary>
		/// Retrieves the pixel data that is currently stored in video memory.
		/// </summary>
		/// <returns></returns>
		public Pixmap.Layer RetrievePixelData()
		{
			DualityApp.GuardSingleThreadState();

			int lastTexId;
			GL.GetInteger(GetPName.TextureBinding2D, out lastTexId);
			GL.BindTexture(TextureTarget.Texture2D, this.glTexId);
			
			byte[] data = new byte[this.texWidth * this.texHeight * 4];
			GL.GetTexImage(TextureTarget.Texture2D, 0, 
				GLPixelFormat.Rgba, PixelType.UnsignedByte, 
				data);

			GL.BindTexture(TextureTarget.Texture2D, lastTexId);

			Pixmap.Layer result = new Pixmap.Layer();
			result.SetPixelDataRgba(data, this.texWidth, this.texHeight);
			return result;
		}
Ejemplo n.º 2
0
		private bool AreImagesEqual(Bitmap referenceImage, Action<Canvas> renderMethod)
		{
			Pixmap.Layer image = this.RenderToTexture(referenceImage.Width, referenceImage.Height, renderMethod);
			Pixmap.Layer reference = new Pixmap.Layer(referenceImage);
			return this.AreImagesEqual(reference, image);
		}
Ejemplo n.º 3
0
		private Pixmap.Layer CreateDiffImage(Pixmap.Layer first, Pixmap.Layer second)
		{
			if (first == second) return new Pixmap.Layer(first.Width, first.Height);
			if (first.Width != second.Width) return new Pixmap.Layer(1, 1);
			if (first.Height != second.Height) return new Pixmap.Layer(1, 1);

			Pixmap.Layer diff = new Pixmap.Layer(first.Width, first.Height);
			ColorRgba[] firstData = first.Data;
			ColorRgba[] secondData = second.Data;
			ColorRgba[] diffData = diff.Data;
			for (int i = 0; i < firstData.Length; i++)
			{
				diffData[i].R = (byte)MathF.Abs(firstData[i].R - secondData[i].R);
				diffData[i].G = (byte)MathF.Abs(firstData[i].G - secondData[i].G);
				diffData[i].B = (byte)MathF.Abs(firstData[i].B - secondData[i].B);
				diffData[i].A = (byte)MathF.Abs(firstData[i].A - secondData[i].A);
			}

			return diff;
		}
Ejemplo n.º 4
0
		private void TestImagesEqual(Bitmap referenceImage, Action<Canvas> renderMethod)
		{
			Pixmap.Layer image = this.RenderToTexture(referenceImage.Width, referenceImage.Height, renderMethod);
			Pixmap.Layer reference = new Pixmap.Layer(referenceImage);
			bool equal = this.AreImagesEqual(reference, image);
			if (!equal && Debugger.IsAttached)
			{
				// If the debugger is attached, create a nice diff image for the programmer to view.
				Pixmap.Layer diff = this.CreateDiffImage(image, reference);
			}
			Assert.IsTrue(equal);
		}
Ejemplo n.º 5
0
 /// <summary>
 /// Retrieves the rasterized <see cref="System.Drawing.Bitmap"/> for a single glyph.
 /// </summary>
 /// <param name="glyph">The glyph of which to retrieve the Bitmap.</param>
 /// <returns>The Bitmap that has been retrieved, or null if the glyph is not supported.</returns>
 public Pixmap.Layer GetGlyphBitmap(char glyph)
 {
     Rect targetRect;
     int charIndex = (int)glyph > CharLookup.Length ? 0 : CharLookup[(int)glyph];
     this.pixelData.LookupAtlas(charIndex, out targetRect);
     Pixmap.Layer subImg = new Pixmap.Layer(
         MathF.RoundToInt(targetRect.W),
         MathF.RoundToInt(targetRect.H));
     this.pixelData.MainLayer.DrawOnto(subImg, BlendMode.Solid,
         -MathF.RoundToInt(targetRect.X),
         -MathF.RoundToInt(targetRect.Y));
     return subImg;
 }
Ejemplo n.º 6
0
        private void GenerateResources()
        {
            if (this.mat != null || this.texture != null || this.pixelData != null)
                this.ReleaseResources();

            TextRenderingHint textRenderingHint;
            if (this.renderMode == RenderMode.MonochromeBitmap)
                textRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;
            else
                textRenderingHint = TextRenderingHint.AntiAliasGridFit;

            int cols;
            int rows;
            cols = rows = (int)Math.Ceiling(Math.Sqrt(SupportedChars.Length));

            Pixmap.Layer pixelLayer = new Pixmap.Layer(MathF.RoundToInt(cols * this.internalFont.Size * 1.2f), MathF.RoundToInt(rows * this.internalFont.Height * 1.2f));
            Pixmap.Layer glyphTemp;
            Pixmap.Layer glyphTempTypo;
            Bitmap bm;
            Bitmap measureBm = new Bitmap(1, 1);
            Rect[] atlas = new Rect[SupportedChars.Length];
            using (Graphics measureGraphics = Graphics.FromImage(measureBm))
            {
                Brush fntBrush = new SolidBrush(Color.Black);

                StringFormat formatDef = StringFormat.GenericDefault;
                formatDef.LineAlignment = StringAlignment.Near;
                formatDef.FormatFlags = 0;
                StringFormat formatTypo = StringFormat.GenericTypographic;
                formatTypo.LineAlignment = StringAlignment.Near;

                int x = 1;
                int y = 1;
                for (int i = 0; i < SupportedChars.Length; ++i)
                {
                    string str = SupportedChars[i].ToString(CultureInfo.InvariantCulture);
                    bool isSpace = str == " ";
                    SizeF charSize = measureGraphics.MeasureString(str, this.internalFont, pixelLayer.Width, formatDef);

                    // Rasterize a single glyph for rendering
                    bm = new Bitmap((int)Math.Ceiling(Math.Max(1, charSize.Width)), this.internalFont.Height + 1);
                    using (Graphics glyphGraphics = Graphics.FromImage(bm))
                    {
                        glyphGraphics.Clear(Color.Transparent);
                        glyphGraphics.TextRenderingHint = textRenderingHint;
                        glyphGraphics.DrawString(str, this.internalFont, fntBrush, new RectangleF(0, 0, bm.Width, bm.Height), formatDef);
                    }
                    glyphTemp = new Pixmap.Layer(bm);

                    // Rasterize a single glyph in typographic mode for metric analysis
                    if (!isSpace)
                    {
                        Rectangle glyphTempBounds = glyphTemp.OpaqueBounds();
                        glyphTemp.SubImage(glyphTempBounds.X, 0, glyphTempBounds.Width, glyphTemp.Height);
                        if (BodyAscentRef.Contains(SupportedChars[i]))
                            this.bodyAscent += glyphTempBounds.Height;

                        bm = new Bitmap((int)Math.Ceiling(Math.Max(1, charSize.Width)), this.internalFont.Height + 1);
                        using (Graphics glyphGraphics = Graphics.FromImage(bm))
                        {
                            glyphGraphics.Clear(Color.Transparent);
                            glyphGraphics.TextRenderingHint = textRenderingHint;
                            glyphGraphics.DrawString(str, this.internalFont, fntBrush, new RectangleF(0, 0, bm.Width, bm.Height), formatTypo);
                        }
                        glyphTempTypo = new Pixmap.Layer(bm);
                        glyphTempTypo.Crop(true, false);
                    }
                    else
                    {
                        glyphTempTypo = glyphTemp;
                    }

                    // Update xy values if it doesn't fit anymore
                    if (x + glyphTemp.Width + 2 > pixelLayer.Width)
                    {
                        x = 1;
                        y += this.internalFont.Height + MathF.Clamp((int)MathF.Ceiling(this.internalFont.Height * 0.1875f), 3, 10);
                    }

                    // Memorize atlas coordinates & glyph data
                    this.maxGlyphWidth = Math.Max(this.maxGlyphWidth, glyphTemp.Width);
                    this.glyphs[i].width = glyphTemp.Width;
                    this.glyphs[i].height = glyphTemp.Height;
                    this.glyphs[i].offsetX = glyphTemp.Width - glyphTempTypo.Width;
                    if (isSpace)
                    {
                        this.glyphs[i].width /= 2;
                        this.glyphs[i].offsetX /= 2;
                    }
                    atlas[i].X = x;
                    atlas[i].Y = y;
                    atlas[i].W = glyphTemp.Width;
                    atlas[i].H = (this.internalFont.Height + 1);

                    // Draw it onto the font surface
                    glyphTemp.DrawOnto(pixelLayer, BlendMode.Solid, x, y);

                    x += glyphTemp.Width + MathF.Clamp((int)MathF.Ceiling(this.internalFont.Height * 0.125f), 2, 10);
                }
            }

            // White out texture except alpha channel.
            for (int i = 0; i < pixelLayer.Data.Length; i++)
            {
                pixelLayer.Data[i].R = 255;
                pixelLayer.Data[i].G = 255;
                pixelLayer.Data[i].B = 255;
            }

            // Determine Font properties
            this.height = this.internalFont.Height;
            this.ascent = (int)Math.Round(this.internalFont.FontFamily.GetCellAscent(this.internalFont.Style) * this.internalFont.Size / this.internalFont.FontFamily.GetEmHeight(this.internalFont.Style));
            this.bodyAscent /= BodyAscentRef.Length;
            this.descent = (int)Math.Round(this.internalFont.FontFamily.GetCellDescent(this.internalFont.Style) * this.internalFont.GetHeight() / this.internalFont.FontFamily.GetLineSpacing(this.internalFont.Style));
            this.baseLine = (int)Math.Round(this.internalFont.FontFamily.GetCellAscent(this.internalFont.Style) * this.internalFont.GetHeight() / this.internalFont.FontFamily.GetLineSpacing(this.internalFont.Style));

            // Create internal Pixmap and Texture Resources
            this.pixelData = new Pixmap(pixelLayer);
            this.pixelData.Atlas = new List<Rect>(atlas);
            this.texture = new Texture(this.pixelData,
                Texture.SizeMode.Enlarge,
                this.IsPixelGridAligned ? TextureMagFilter.Nearest : TextureMagFilter.Linear,
                this.IsPixelGridAligned ? TextureMinFilter.Nearest : TextureMinFilter.LinearMipmapLinear);

            // Select DrawTechnique to use
            ContentRef<DrawTechnique> technique;
            if (this.renderMode == RenderMode.MonochromeBitmap)
                technique = DrawTechnique.Mask;
            else if (this.renderMode == RenderMode.GrayscaleBitmap)
                technique = DrawTechnique.Alpha;
            else if (this.renderMode == RenderMode.SmoothBitmap)
                technique = DrawTechnique.Alpha;
            else
                technique = DrawTechnique.SharpAlpha;

            // Create and configure internal BatchInfo
            BatchInfo matInfo = new BatchInfo(technique, ColorRgba.White, this.texture);
            if (technique == DrawTechnique.SharpAlpha)
            {
                matInfo.SetUniform("smoothness", this.size * 3.0f);
            }
            this.mat = new Material(matInfo);
        }
Ejemplo n.º 7
0
		private void GenerateResources()
		{
			if (this.mat != null || this.texture != null || this.pixelData != null)
				this.ReleaseResources();

			int cols;
			int rows;
			cols = rows = (int)Math.Ceiling(Math.Sqrt(SupportedChars.Length));

			Pixmap.Layer pixelLayer = new Pixmap.Layer(MathF.RoundToInt(cols * this.internalFont.Size), MathF.RoundToInt(rows * (this.internalFont.Height + 1)));
			Pixmap.Layer glyphTemp;
			Pixmap.Layer glyphTempTypo;
			Bitmap bm;
			Bitmap measureBm = new Bitmap(1, 1);
			Rect[] atlas = new Rect[SupportedChars.Length];
			using (Graphics measureGraphics = Graphics.FromImage(measureBm))
			{
				Brush fntBrush = new SolidBrush(Color.Black);

				StringFormat formatDef = StringFormat.GenericDefault;
				formatDef.LineAlignment = StringAlignment.Near;
				formatDef.FormatFlags = 0;
				StringFormat formatTypo = StringFormat.GenericTypographic;
				formatTypo.LineAlignment = StringAlignment.Near;

				int x = 0;
				int y = 0;
				for (int i = 0; i < SupportedChars.Length; ++i)
				{
					string str = SupportedChars[i].ToString(CultureInfo.InvariantCulture);
					bool isSpace = str == " ";
					SizeF charSize = measureGraphics.MeasureString(str, this.internalFont, pixelLayer.Width, formatDef);

					// Render a single glyph
					bm = new Bitmap((int)Math.Ceiling(Math.Max(1, charSize.Width)), this.internalFont.Height + 1);
					using (Graphics glyphGraphics = Graphics.FromImage(bm))
					{
						glyphGraphics.Clear(Color.Transparent);
						glyphGraphics.TextRenderingHint = (System.Drawing.Text.TextRenderingHint)this.hint;
						glyphGraphics.DrawString(str, this.internalFont, fntBrush, new RectangleF(0, 0, bm.Width, bm.Height), formatDef);
					}
					glyphTemp = new Pixmap.Layer(bm);
					
					if (!isSpace)
					{
						Rectangle glyphTempBounds = glyphTemp.OpaqueBounds();
						glyphTemp.SubImage(glyphTempBounds.X, 0, glyphTempBounds.Width, glyphTemp.Height);
						if (BodyAscentRef.Contains(SupportedChars[i]))
							this.bodyAscent += glyphTempBounds.Height;
						
						// Render a single glyph in typographic mode
						bm = new Bitmap((int)Math.Ceiling(Math.Max(1, charSize.Width)), this.internalFont.Height + 1);
						using (Graphics glyphGraphics = Graphics.FromImage(bm))
						{
							glyphGraphics.Clear(Color.Transparent);
							glyphGraphics.TextRenderingHint = (System.Drawing.Text.TextRenderingHint)this.hint;
							glyphGraphics.DrawString(str, this.internalFont, fntBrush, new RectangleF(0, 0, bm.Width, bm.Height), formatTypo);
						}
						glyphTempTypo = new Pixmap.Layer(bm);
						glyphTempTypo.Crop(true, false);
					}
					else
						glyphTempTypo = glyphTemp;

					// Update xy values if it doesn't fit anymore
					if (x + glyphTemp.Width + 2 > pixelLayer.Width)
					{
						x = 0;
						y += (this.internalFont.Height + 1) + 2;
					}
					
					// Memorize atlas coordinates & glyph data
					this.maxGlyphWidth = Math.Max(this.maxGlyphWidth, glyphTemp.Width);
					this.glyphs[i].width = glyphTemp.Width;
					this.glyphs[i].height = glyphTemp.Height;
					this.glyphs[i].offsetX = glyphTemp.Width - glyphTempTypo.Width;
					if (isSpace)
					{
						this.glyphs[i].width /= 2;
						this.glyphs[i].offsetX /= 2;
					}
					atlas[i].X = x;
					atlas[i].Y = y;
					atlas[i].W = glyphTemp.Width;
					atlas[i].H = (this.internalFont.Height + 1);

					// Draw it onto the font surface
					glyphTemp.DrawOnto(pixelLayer, BlendMode.Solid, x, y);

					x += glyphTemp.Width + 2;
				}
			}

			// Adjust colors based on alpha value
			//for (int i = 0; i < pixelLayer.Data.Length; i++)
			System.Threading.Tasks.Parallel.For(0, pixelLayer.Data.Length, i =>
			{
				float factor = pixelLayer.Data[i].A / 255.0f;
				float invFactor = 1.0f - factor;
				pixelLayer.Data[i].R = (byte)Math.Min(255.0f, Math.Max(0.0f, this.bgColor.R * invFactor + this.color.R * factor));
				pixelLayer.Data[i].G = (byte)Math.Min(255.0f, Math.Max(0.0f, this.bgColor.G * invFactor + this.color.G * factor));
				pixelLayer.Data[i].B = (byte)Math.Min(255.0f, Math.Max(0.0f, this.bgColor.B * invFactor + this.color.B * factor));
				pixelLayer.Data[i].A = (byte)Math.Min(255.0f, Math.Max(0.0f, this.bgColor.A * invFactor + this.color.A * factor));
			});

			this.height = this.internalFont.Height;
			this.ascent = (int)Math.Round(this.internalFont.FontFamily.GetCellAscent(this.internalFont.Style) * this.internalFont.Size / this.internalFont.FontFamily.GetEmHeight(this.internalFont.Style));
			this.bodyAscent /= BodyAscentRef.Length;
			this.descent = (int)Math.Round(this.internalFont.FontFamily.GetCellDescent(this.internalFont.Style) * this.internalFont.GetHeight() / this.internalFont.FontFamily.GetLineSpacing(this.internalFont.Style));
			this.baseLine = (int)Math.Round(this.internalFont.FontFamily.GetCellAscent(this.internalFont.Style) * this.internalFont.GetHeight() / this.internalFont.FontFamily.GetLineSpacing(this.internalFont.Style));

			bool useNearest = this.hint == RenderHint.Monochrome || !this.filtering;

			this.pixelData = new Pixmap(pixelLayer);
			this.pixelData.Atlas = new List<Rect>(atlas);
			this.texture = new Texture(this.pixelData, 
				Texture.SizeMode.Enlarge, 
				useNearest ? OpenTK.Graphics.OpenGL.TextureMagFilter.Nearest : OpenTK.Graphics.OpenGL.TextureMagFilter.Linear,
				useNearest ? OpenTK.Graphics.OpenGL.TextureMinFilter.Nearest : OpenTK.Graphics.OpenGL.TextureMinFilter.LinearMipmapLinear);

			this.mat = new Material(this.hint == RenderHint.Monochrome ? DrawTechnique.Mask : DrawTechnique.Alpha, ColorRgba.White, this.texture);
		}
Ejemplo n.º 8
0
        private void LoadOrCreatePixelData(int cols, int rows, TextRenderingHint textRenderingHint)
        {
            Pixmap.Layer pixelLayer = new Pixmap.Layer(MathF.RoundToInt(cols*this.internalFont.Size*1.2f), MathF.RoundToInt(rows*this.internalFont.Height*1.2f));
            Pixmap.Layer glyphTemp;
            Pixmap.Layer glyphTempTypo;
            Bitmap bm;
            Bitmap measureBm = new Bitmap(1, 1);
            Rect[] atlas = new Rect[SupportedChars.Length];
            using (Graphics measureGraphics = Graphics.FromImage(measureBm))
            {
                Brush fntBrush = new SolidBrush(Color.Black);

                StringFormat formatDef = StringFormat.GenericDefault;
                formatDef.LineAlignment = StringAlignment.Near;
                formatDef.FormatFlags = 0;
                StringFormat formatTypo = StringFormat.GenericTypographic;
                formatTypo.LineAlignment = StringAlignment.Near;

                int x = 1;
                int y = 1;
                for (int i = 0; i < SupportedChars.Length; ++i)
                {
                    string str = SupportedChars[i].ToString(CultureInfo.InvariantCulture);
                    bool isSpace = str == " ";
                    SizeF charSize = measureGraphics.MeasureString(str, this.internalFont, pixelLayer.Width, formatDef);

                    // Rasterize a single glyph for rendering
                    bm = new Bitmap((int)Math.Ceiling(Math.Max(1, charSize.Width)), this.internalFont.Height + 1);
                    using (Graphics glyphGraphics = Graphics.FromImage(bm))
                    {
                        glyphGraphics.Clear(Color.Transparent);
                        glyphGraphics.TextRenderingHint = textRenderingHint;
                        glyphGraphics.DrawString(str, this.internalFont, fntBrush, new RectangleF(0, 0, bm.Width, bm.Height), formatDef);
                    }
                    glyphTemp = new Pixmap.Layer(bm);

                    // Rasterize a single glyph in typographic mode for metric analysis
                    if (!isSpace)
                    {
                        Rectangle glyphTempBounds = glyphTemp.OpaqueBounds();
                        glyphTemp.SubImage(glyphTempBounds.X, 0, glyphTempBounds.Width, glyphTemp.Height);
                        if (BodyAscentRef.Contains(SupportedChars[i]))
                            this.bodyAscent += glyphTempBounds.Height;

                        bm = new Bitmap((int) Math.Ceiling(Math.Max(1, charSize.Width)), this.internalFont.Height + 1);
                        using (Graphics glyphGraphics = Graphics.FromImage(bm))
                        {
                            glyphGraphics.Clear(Color.Transparent);
                            glyphGraphics.TextRenderingHint = textRenderingHint;
                            glyphGraphics.DrawString(str, this.internalFont, fntBrush, new RectangleF(0, 0, bm.Width, bm.Height), formatTypo);
                        }
                        glyphTempTypo = new Pixmap.Layer(bm);
                        glyphTempTypo.Crop(true, false);
                    }
                    else
                    {
                        glyphTempTypo = glyphTemp;
                    }

                    // Update xy values if it doesn't fit anymore
                    if (x + glyphTemp.Width + 2 > pixelLayer.Width)
                    {
                        x = 1;
                        y += this.internalFont.Height + MathF.Clamp((int) MathF.Ceiling(this.internalFont.Height*0.1875f), 3, 10);
                    }

                    // Memorize atlas coordinates & glyph data
                    this.maxGlyphWidth = Math.Max(this.maxGlyphWidth, glyphTemp.Width);
                    this.glyphs[i].width = glyphTemp.Width;
                    this.glyphs[i].height = glyphTemp.Height;
                    this.glyphs[i].offsetX = glyphTemp.Width - glyphTempTypo.Width;
                    if (isSpace)
                    {
                        this.glyphs[i].width /= 2;
                        this.glyphs[i].offsetX /= 2;
                    }
                    atlas[i].X = x;
                    atlas[i].Y = y;
                    atlas[i].W = glyphTemp.Width;
                    atlas[i].H = (this.internalFont.Height + 1);

                    // Draw it onto the font surface
                    glyphTemp.DrawOnto(pixelLayer, BlendMode.Solid, x, y);

                    x += glyphTemp.Width + MathF.Clamp((int) MathF.Ceiling(this.internalFont.Height*0.125f), 2, 10);

                    if(glyphTempTypo != glyphTemp)
                        glyphTempTypo.Dispose();

                    glyphTemp.Dispose();
                }
            }

            // White out texture except alpha channel.
            for (int i = 0; i < pixelLayer.Data.Length; i++)
            {
                pixelLayer.Data[i].R = 255;
                pixelLayer.Data[i].G = 255;
                pixelLayer.Data[i].B = 255;
            }

            this.pixelData = new Pixmap(pixelLayer) {Atlas = new List<Rect>(atlas)};
        }