Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug: FillPath and DrawPath do not work on Memory Bitmap #81

Open
MightyM7 opened this issue Jan 14, 2022 · 3 comments
Open

Bug: FillPath and DrawPath do not work on Memory Bitmap #81

MightyM7 opened this issue Jan 14, 2022 · 3 comments

Comments

@MightyM7
Copy link

MightyM7 commented Jan 14, 2022

Hi,

I need to draw thousand of pie Elements on my RenderContext. Because the calculation is very time consuming, I need to draw them on a memory bitmap and the the memory bitmap on screen.
But this don't work, simply it's nothing drawn but also no error or exception.

I modified your PieChart Example to demonstrate the issue. All other methods work excelent on memory bitmap, but FillPath and DrawPath will not (I've not tested more).

Can you please fix this?

Regards

namespace unvell.D2DLib.Examples.Demos
{
	public partial class PieChart : DemoForm
	{
		List<PieInfo> pies = new List<PieInfo>();
		D2DBitmapGraphics m_MemoryBitmap;

		public PieChart()
		{
			Size = new Size(800, 1000);
			Text = "PieChart Demo - d2dlib Examples";
			CreateChart();
			m_MemoryBitmap = Device.CreateBitmapGraphics(ClientRectangle.Width, ClientRectangle.Height);
		}

		void CreateChart()
		{
			pies.Clear();

			// define the figure origin and size
			var figureOrigin = new D2DPoint(300, 300);
			var figureSize = new D2DSize(300, 300);
			Random random = new Random();

			var records = new float[2];
			records[0] = random.Next(0, 360);
			records[1] = 360 - records[0];

			float currentAngle = 270 - (records[0] / 2);

			// create pie geometries from records
			foreach (var record in records)
			{
				var angleSpan = record;

				var path = Device.CreatePieGeometry(figureOrigin, figureSize, currentAngle, currentAngle + angleSpan);
				pies.Add(new PieInfo { path = path, color = D2DColor.Randomly() });

				currentAngle += angleSpan;
			}

		}

		protected override void OnRender(D2DGraphics g)
		{
			base.OnRender(g);
			// draw background
			D2DBrush brush = Device.CreateSolidColorBrush(D2DColor.Silver);

			m_MemoryBitmap.BeginRender();
			m_MemoryBitmap.FillRectangle(100, 100, 400, 400, D2DColor.LightYellow);
			m_MemoryBitmap.FillEllipse(100, 300, 400, 400, D2DColor.AliceBlue);
			// draw pie geometries
			m_MemoryBitmap.FillPath(pies[0].path, pies[0].color);
			m_MemoryBitmap.DrawPath(pies[0].path, D2DColor.LightYellow, 2);
			//
			m_MemoryBitmap.FillPathWithBrush(pies[0].path, brush);
			//
			m_MemoryBitmap.DrawText("Click to change color", D2DColor.Red, 250, 550);
			m_MemoryBitmap.EndRender();

			g.DrawBitmap(m_MemoryBitmap, ClientRectangle);
			g.FillPathWithBrush(pies[1].path, brush);
			g.DrawPath(pies[1].path, D2DColor.Blue, 2);

			brush.Dispose();
		}

		protected override void OnMouseUp(MouseEventArgs e)
		{
			base.OnMouseUp(e);

			CreateChart();
			Invalidate();
		}
	}

	class PieInfo
	{
		public D2DGeometry path;
		public D2DColor color;
	}
}
@MightyM7
Copy link
Author

Someone an idea? Thanks.

@MightyM7 MightyM7 mentioned this issue Apr 6, 2022
@jingwood
Copy link
Owner

jingwood commented Nov 4, 2022

I tested your code, and I didn't see any problems there.

Just noticed that there is no FillPathWithBrush method yet, but DrawPath and FillPath work properly with the memory bitmap.

What problem do you get?

m_MemoryBitmap = Device.CreateBitmapGraphics(ClientRectangle.Width, ClientRectangle.Height);

...

m_MemoryBitmap.BeginRender();

foreach (var pie in pies)
{
	// draw pie geometries
	m_MemoryBitmap.FillPath(pie.path, D2DColor.Randomly());
	m_MemoryBitmap.DrawPath(pie.path, D2DColor.Randomly(), 2);
}

//m_MemoryBitmap.FillPathWithBrush(pies[0].path, brush);

m_MemoryBitmap.EndRender();

g.DrawBitmap(m_MemoryBitmap, ClientRectangle);

@Mars007007
Copy link

Same issue (on .NET6,7,8,9)
See code comments

  • FillPath not visible
  • DrawPath not visible
  • PushTransform not working on Path
using System.Numerics;
using unvell.D2DLib;
using unvell.D2DLib.WinForm;

namespace Direct2dLib
{
    public class Form3 : D2DForm
    {
        float zoom = 1;
        Vector2 panOffset = Vector2.Zero;
        Vector2 lastMousePos;
        bool isPanning = false;
        bool needsUpdate = true;
        D2DBitmapGraphics bmpGraphics;

        public Form3()
        {
            this.Text = "D2DLib Performance Test - Zoom and Pan with Stars (CombinedGeometries with hole and text)";
            this.ClientSize = new Size(1600, 900);

            this.AnimationDraw = true;
            this.ShowFPS = true;
            this.WindowState = FormWindowState.Maximized;
        }

        protected override void OnRender(D2DGraphics g)
        {
            base.OnRender(g);

            if (needsUpdate)
            {
                needsUpdate = false;

                if (bmpGraphics == null)
                {
                    bmpGraphics = this.Device.CreateBitmapGraphics(this.ClientSize.Width, this.ClientSize.Height);
                }

                bmpGraphics.BeginRender();
                bmpGraphics.Clear(D2DColor.Transparent);
                bmpGraphics.FillRectangle(170, 790, 670, 80, new D2DColor(0.4f, D2DColor.Black));                 // works fine
                bmpGraphics.DrawText("This is Direct2D device bitmap", D2DColor.Goldenrod, this.Font, 180, 800);  // works fine

                var star = Star3.CreateStar(this.Device, 200, 200, 200, D2DColor.Green);
                bmpGraphics.FillPath(star.Geometry, star.Color);    // Only visible when needsUpdate is true. Position is wrong.
                bmpGraphics.DrawPath(star.Geometry, star.Color);    // Only visible when needsUpdate is true. Position is wrong.

                for (int i = 0; i < star.CornerPoints.Count; i++)
                {
                    var point = star.CornerPoints[i];
                    Vector2 direction = Vector2.Normalize(point - star.Center);
                    Vector2 textPosition = point + direction * Star3.CornerTextDistance;
                    bmpGraphics.DrawText(i.ToString(), D2DColor.Gray, textPosition.X - 6, textPosition.Y - 6);  // works fine
                }

                bmpGraphics.EndRender();
            }

            g.PushTransform();
            g.TranslateTransform(panOffset.X, panOffset.Y);
            g.ScaleTransform(zoom, zoom);
            g.DrawBitmap(bmpGraphics, this.ClientRectangle);
            g.PopTransform();
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);

            if (e.Button == MouseButtons.Left)
            {
                isPanning = true;
                lastMousePos = new Vector2(e.X, e.Y);
                this.Cursor = Cursors.Hand;
            }
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            if (isPanning)
            {
                float dx = e.X - lastMousePos.X;
                float dy = e.Y - lastMousePos.Y;

                panOffset.X += dx;
                panOffset.Y += dy;

                lastMousePos = new Vector2(e.X, e.Y);

                needsUpdate = true;
                Invalidate();
            }
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);

            if (e.Button == MouseButtons.Left)
            {
                isPanning = false;
                this.Cursor = Cursors.Default;
            }
        }

        protected override void OnMouseWheel(MouseEventArgs e)
        {
            base.OnMouseWheel(e);

            float scaleFactor = (e.Delta > 0) ? 1.1f : 0.9f;

            Vector2 mousePos = new Vector2(e.X, e.Y);

            // Convert mouse position to world coordinates before zoom
            Vector2 worldPos = (mousePos - panOffset) / zoom;

            // Apply zoom
            zoom *= scaleFactor;

            // Adjust panOffset to keep the world position under the mouse the same
            panOffset = mousePos - worldPos * zoom;

            needsUpdate = true;
            Invalidate();
        }
    }

    public class Star3
    {
        public const int CornerCount = 10;
        public const float CornerTextDistance = 8;

        public D2DGeometry Geometry { get; set; }
        public List<Vector2> CornerPoints { get; set; }
        public D2DColor Color { get; set; }
        public Vector2 Center { get; set; }


        public static Star3 CreateStar(D2DDevice device, float centerX, float centerY, float radius, D2DColor color)
        {
            D2DPathGeometry geo = device.CreatePathGeometry();

            double angleStep = Math.PI / CornerCount;
            float innerRadius = radius / 2.5f;
            List<Vector2> points = new List<Vector2>();
            List<Vector2> cornerPoints = new List<Vector2>();

            for (int i = 0; i < CornerCount * 2; i++)
            {
                double angle = i * angleStep - Math.PI / 2;

                float r = (i % 2 == 0) ? radius : innerRadius;

                float x = centerX + (float)(Math.Cos(angle) * r);
                float y = centerY + (float)(Math.Sin(angle) * r);

                points.Add(new Vector2(x, y));

                if (i % 2 == 0)
                {
                    cornerPoints.Add(new Vector2(x, y));
                }
            }

            geo.SetStartPoint(points[0]);
            geo.AddLines(points.ToArray());
            geo.ClosePath();

            // Create circle geometry for the hole
            var circleGeo = device.CreateEllipseGeometry(new Vector2(centerX, centerY), new D2DSize(radius / 3, radius / 3));

            // Combine star and circle to create a hole
            var combinedGeo = device.CreateCombinedGeometry(geo, circleGeo, D2D1CombineMode.Exclude);

            // Clean up
            geo.Dispose();
            circleGeo.Dispose();

            return new Star3
            {
                Geometry = combinedGeo,
                CornerPoints = cornerPoints,
                Color = color,
                Center = new Vector2(centerX, centerY)
            };
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants