C#GDI +剪辑画等等

时间:2016-03-29 15:14:02

标签: c# zoom gdi+ clip pan

我正在编写一个应用程序,其中有一个面板,我在其中显示:

  • 图片背景
  • 大量绘制的对象(使用GDI +线条,路径等)
  • 所述对象在鼠标移动事件中有一些命中检测。

面板平移和缩放。该面板是双缓冲的。

所以一切都运转良好 - 事情看起来很好,没有闪烁,但我正处于我试图专注于表现的地步。我用不到1毫秒来绘制我的物体(每个物体)但是当缩小时我可以有超过500个物体来绘制,这开始使得从绘图到命中检测的一切都变得缓慢。

我已经做了一些尝试来提高性能,比如制作一个只有屏幕(可绘制)对象的列表 - 但如前所述,当缩小时,它仍然可能很多。我得到了一个伟大的想法,也许不是每次都更新每个对象,我可以实现一个简单的Invalidate(),它会告诉对象它做了一个值得绘制的视觉变化。在对象绘制代码(通过e.graphics)中,我试图将剪切区域设置为对象的大小,并且只更新面板BG的那部分(同样在完成时,我重置了e.Grpahics.clip) 。结果只是无效的对象绘制 - 其他一切都是空白的。

我确信这是C#/ GDI noob出现在我身上,你们都会告诉我我可能忽略的那个愚蠢的错误。

在撰写本文时,我意识到我可以通过使对象的路径保持不变来保存一些时间,而不是每次在绘制函数中都使它新鲜(因为所有对象路径都是相同)。我会随着时间的推移更新,我很快就会刮掉。

以下是绘制BG图像(并确定要绘制哪个OBJS)和OBJ绘画代码的代码。

private void PaintImage(PaintEventArgs e)
        {
            int scale = 10;  //TARGET ICON BASE SCALE....
            var watch2 = System.Diagnostics.Stopwatch.StartNew();
            if (bitmap != null && redrawBG)
            {



                float widthZoomed = TgtPanel.Width / Zoom;
                float heigthZoomed = TgtPanel.Height / Zoom;
                //Do checks the reason 30,000 is used is because 
                //much over this will cause DrawImage to crash
                if (widthZoomed > 30000.0f)
                {
                    Zoom = TgtPanel.Width / 30000.0f;
                    widthZoomed = 30000.0f;
                }
                if (heigthZoomed > 30000.0f)
                {
                    Zoom = TgtPanel.Height / 30000.0f;
                    heigthZoomed = 30000.0f;
                }
                //we stop at 2 because at this point you have almost zoomed into a single pixel
                if (widthZoomed < 2.0f)
                {
                    Zoom = TgtPanel.Width / 2.0f;
                    widthZoomed = 2.0f;
                }
                if (heigthZoomed < 2.0f)
                {
                    Zoom = TgtPanel.Height / 2.0f;
                    heigthZoomed = 2.0f;
                }
                float wz2 = widthZoomed / 2.0f;
                float hz2 = heigthZoomed / 2.0f;
                Rectangle drawRect = new Rectangle(
                    (int)(viewPortCenter.X - wz2),
                    (int)(viewPortCenter.Y - hz2),
                    (int)(widthZoomed),
                    (int)(heigthZoomed));


                e.Graphics.Clear(Color.White); //Clear the Back buffer
                //Draw the image, Write image to back buffer, and [render back buffer - no longer using my own backbuffer]
                e.Graphics.DrawImage(bitmap,
                         this.TgtPanel.DisplayRectangle, drawRect, GraphicsUnit.Pixel);
                //                e.Graphics.ScaleTransform(Zoom, Zoom);
                //              e.Graphics.DrawImage(bitmap,
                //                    0,0);


                if (draging)
                {  //line to visualize the drag
                    e.Graphics.DrawLine(new Pen(Color.Yellow, 10), StartDrag.X, StartDrag.Y, lastMouse.X, lastMouse.Y);
                }

                //this checks for offscreen - works
                if (drawRect.X > iconbitmap.Width || drawRect.X < -(drawRect.Width) ||
                    drawRect.Y > 0 + iconbitmap.Height || drawRect.Y < -(drawRect.Height))
                {
                    label1.Text = "OFF";
                }



            } //if bitmap != null & redraw
                // Font and Brush for the text graphics
                Point mypoint = WorldToScreen(0.75f * scale, 7.0f * scale);
                RectangleF bgrect = new RectangleF();
                bgrect.X = mypoint.X;
                bgrect.Y = mypoint.Y;
                bgrect.Width = (3.5f * scale * Zoom);
                bgrect.Height = (2.0f * scale * Zoom);

                int aFontSizeDefault = 40;
                int aFontSizeMinimum = 2;
                String adrawString = "AAA"; //test this length
                Font aDefaultFont = new Font("MS Sans Serif", aFontSizeDefault, FontStyle.Regular);
                FontAdjustment afa = new FontAdjustment();
                Font AAdjustedFont = afa.GetAdjustedFont(e.Graphics, adrawString,
                aDefaultFont, Convert.ToInt32(bgrect.Width), aFontSizeDefault, aFontSizeMinimum, true);

                //DRAW TGT BG
                var Point1 = ScreenToWorld(0, 0);
                var Point2 = ScreenToWorld(TgtPanel.Width, TgtPanel.Height);
                //getVisible Screen == on;y draw visible targets

                if (redrawBG)
                {
                    VISIBLETARGETS.Clear(); //erase visible tgts array - we're going to update it
                    foreach (Target TGT in THETARGETS)
                        if (TGT.PosX >= Point1.X - 40 && TGT.PosX <= Point2.X - 9) 
                        if (TGT.PosY >= Point1.Y - 83 && TGT.PosY <= Point2.Y - 5)
                        {
                            TGT.OnScreen = true;
                            //drawTarget(TGT, AAdjustedFont, e);
                            VISIBLETARGETS.Add(TGT); //update as visible
                        }
                        else TGT.OnScreen = false;

                    //redrawBG = false;
                }

            var watch = System.Diagnostics.Stopwatch.StartNew();
            foreach(Target TGT in VISIBLETARGETS)
            {
                if(TGT.Invalidated || redrawBG) //  THIS IS DRAWING ONLY TGT -- NOT OTHERS, OR BG - FIX THIS WITH CLIPPING? 
                    drawTarget(TGT, AAdjustedFont, e);
            }
            watch.Stop();
            watch2.Stop();
            var elapsedMs = watch.ElapsedMilliseconds;//ElapsedTicks;
            label6.Text = "TotalDrawTime = " + watch2.ElapsedMilliseconds.ToString();
            label4.Text = "AvgDrawTime = " + elapsedMs.ToString();
            label5.Text = "VisibleTgts = " + VISIBLETARGETS.Count.ToString();

                AAdjustedFont.Dispose();
                aDefaultFont.Dispose();

                //------------- DRAWING TGT WITH GDI - WITH ORIGINAL BACKBUFFER
              ///  myBuffer.Render(this.TgtPanel.CreateGraphics());

                redrawBG = false;

        }



        public void drawTarget(Target Tgt, Font AAdjustedFont, PaintEventArgs e)
        { 
            var watch = System.Diagnostics.Stopwatch.StartNew();
            const float scale = 10; //10 is at 1 zoom
            var bgrect = new RectangleF();

            Point mypoint = WorldToScreen(Tgt.PosX + 0.75f * scale, Tgt.PosY + 1.0f * scale);
            bgrect.X = mypoint.X;
            bgrect.Y = mypoint.Y;
            bgrect.Width = 3.5f * scale * Zoom;
            bgrect.Height = 7.5f * scale * Zoom;


            //PLAY WITH CLIP
            e.Graphics.Clip = new Region(bgrect);

            //var hbrush = new HatchBrush(HatchStyle.DarkDownwardDiagonal, Color.White);
            var hbrush = new SolidBrush(Color.White);

            //if(WantToDrawIconBG() ....
            //e.Graphics.FillRectangle(hbrush, bgrect);  //ICON BACKGROUND

            //ADDR RECT
           // mypoint = WorldToScreen(0, Tgt.PosY + 7.0f * scale);
            mypoint = WorldToScreen(0, Tgt.PosY + 6.90f * scale); //moved Y up a bit from above
            bgrect.Y = mypoint.Y;
            bgrect.Height = 1.5f * scale * Zoom;
            /////brush.Color = (Color.GhostWhite);
             e.Graphics.FillRectangle(hbrush, bgrect);
             hbrush.Dispose();

            string adrawString = Tgt.Address;
            System.Drawing.Font adrawFont = new System.Drawing.Font("Arial", 16);
            System.Drawing.SolidBrush adrawBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Red);
            System.Drawing.StringFormat adrawFormat = new System.Drawing.StringFormat();
            adrawFormat.Alignment = StringAlignment.Center;
            e.Graphics.DrawString(adrawString, AAdjustedFont, adrawBrush, bgrect, adrawFormat); //draw addr
            //======= LETS MAKE THE TGT ICON SHAPE =======

            GraphicsPath path = new GraphicsPath(FillMode.Alternate);

            //TARGET POINTS      (w = 3, h = 6) 
            var h1 = WorldToScreen(Tgt.PosX + 2 * scale, Tgt.PosY + 1.1f * scale);
            var h2 = WorldToScreen(Tgt.PosX + 3 * scale, Tgt.PosY + 1.1f * scale);
            var n1 = WorldToScreen(Tgt.PosX + 2 * scale, Tgt.PosY + 2 * scale);
            var n2 = WorldToScreen(Tgt.PosX + 3 * scale, Tgt.PosY + 2 * scale);
            var s1 = WorldToScreen(Tgt.PosX + 1 * scale, Tgt.PosY + 3 * scale);
            var s2 = WorldToScreen(Tgt.PosX + 4 * scale, Tgt.PosY + 3 * scale);
            var b1 = WorldToScreen(Tgt.PosX + 1 * scale, Tgt.PosY + 7 * scale);
            var b2 = WorldToScreen(Tgt.PosX + 4 * scale, Tgt.PosY + 7 * scale);
            var controln2 = WorldToScreen(Tgt.PosX + 1 * scale, (Convert.ToInt32(Tgt.PosY + 0.5 * scale)));
            var controls2 = WorldToScreen(Tgt.PosX + 1 * scale, Tgt.PosY + 1 * scale);


            Pen pen = new Pen(Color.FromArgb(255, 0, 0, 255));
            PointF[] npoints = { n2, s2, b2 };
            PointF[] npoints2 = { n1, s1, b1 };
            e.Graphics.DrawCurve(pen, npoints, 0.5f);
            path.AddCurve(npoints, 0.5f); /////
            e.Graphics.DrawLine(pen, b2, b1);
            path.AddLine(b2, b1); /////
            e.Graphics.DrawCurve(pen, npoints2, 0.5f);
            path.AddCurve(npoints2, 0.5f); /////

            PointF[] hpoints = { n1, h1, h2, n2 };
            e.Graphics.DrawCurve(pen, hpoints, 0.1f);
            path.AddCurve(hpoints, 0.1f); /////

            path.CloseAllFigures();
            e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;

            if (Zoom > 0.9)  //only draw stroke if big enough to see (and there arent a million targets to draw
            {
                pen.Color = Tgt.Selected ? Color.Chartreuse : Color.FromName(comboBox1.Text); //black default
                pen.Width = Tgt.Selected ? 2 * Zoom : 1 * Zoom;  //draw thicker border if selected

                e.Graphics.DrawPath(pen, path);   ///------------------------------------------STROKE PATH.....
                //e.Graphics.FillPath(new SolidBrush(Color.ForestGreen), path);
            }

         // how much time is wasted making 2 gradient brushes? One we wont even use.
                LinearGradientBrush linGrBrush = new LinearGradientBrush(
                  WorldToScreen(Tgt.PosX + 0 * scale, Tgt.PosY + 5 * scale),
                  WorldToScreen(Tgt.PosX + 5.5f * scale, Tgt.PosY + 5 * scale),
                Color.ForestGreen,   // Opaque red
                Color.FromArgb(255, 0, 255, 0));  // Opaque blue

                LinearGradientBrush linRedBrush = new LinearGradientBrush(
                  WorldToScreen(Tgt.PosX + 0 * scale, Tgt.PosY + 5 * scale),
                 WorldToScreen(Tgt.PosX + 5.5f * scale, Tgt.PosY + 5 * scale),
                Color.FromArgb(255, 255, 0, 0),   // Opaque red
                Color.Firebrick);  // Opaque blue


            //FILL TARGET ICON WITH COLOR - UP or DOWN
            if (Tgt.IsUp) e.Graphics.FillPath(linGrBrush, path);
             else e.Graphics.FillPath(linRedBrush, path);
            //------------

            //tgt lines  (cosmetic only)
            if (Zoom > 0.9)  //only draw if big enough to see (and there arent a million targets to draw
            {
                var transPen = new Pen(Color.FromArgb(150, 200, 200, 200));
                var l1a = WorldToScreen(Tgt.PosX + 2.5f * scale, Tgt.PosY + 1.5f * scale);
                var l1b = WorldToScreen(Tgt.PosX + 2.5f * scale, Tgt.PosY + 6 * scale);
                e.Graphics.DrawLine(transPen, l1a, l1b);
                var l2a = WorldToScreen(Tgt.PosX + 1.5f * scale, Tgt.PosY + 2.5f * scale);
                var l2b = WorldToScreen(Tgt.PosX + 1.5f * scale, Tgt.PosY + 6.5f * scale);
                e.Graphics.DrawLine(transPen, l2a, l2b);
                var l3a = WorldToScreen(Tgt.PosX + 3.5f * scale, Tgt.PosY + 2.5f * scale);
                var l3b = WorldToScreen(Tgt.PosX + 3.5f * scale, Tgt.PosY + 6.5f * scale);
                e.Graphics.DrawLine(transPen, l3a, l3b);
            }

            //Draw Hits....
            mypoint = WorldToScreen(Tgt.PosX + 1.0f * scale, Tgt.PosY + 3.0f * scale);
            bgrect.X = mypoint.X;
            bgrect.Y = mypoint.Y;
            bgrect.Width = 3.0f * scale * Zoom;
            bgrect.Height = 1.5f * scale * Zoom;
            adrawString = Tgt.Hits.ToString();

            adrawFormat.Alignment = StringAlignment.Center;
            if (Zoom > 0.9)  //only draw if big enough to see (and there arent a million targets to draw
            {
                adrawBrush.Color = Color.FromArgb(100, 100, 100, 100);
                e.Graphics.FillRectangle(adrawBrush, bgrect);
            }
            adrawBrush.Color = Color.White; 
            e.Graphics.DrawString(adrawString, AAdjustedFont, adrawBrush, bgrect, adrawFormat); //draw hits


            //Draw Score....
            mypoint = WorldToScreen(Tgt.PosX + 1.0f * scale, Tgt.PosY + 5.0f * scale);
            bgrect.X = mypoint.X;
            bgrect.Y = mypoint.Y;
            bgrect.Width = 3.0f * scale * Zoom;
            bgrect.Height = 1.5f * scale * Zoom;
            adrawString = Tgt.Score.ToString();

            adrawFormat.Alignment = StringAlignment.Center;
            if (Zoom > 0.9)  //only draw if big enough to see (and there arent a million targets to draw
            {
                adrawBrush.Color = Color.FromArgb(100, 100, 100, 100);
                e.Graphics.FillRectangle(adrawBrush, bgrect);
            }
            adrawBrush.Color = Color.White;
            e.Graphics.DrawString(adrawString, AAdjustedFont, adrawBrush, bgrect, adrawFormat); //draw hits



            adrawFont.Dispose();
            adrawBrush.Dispose();
            adrawFormat.Dispose();
            path.Dispose();

            watch.Stop();
            var elapsedMs = watch.ElapsedTicks;
            //14279 original ticks
            //12764 removing label and reducing font size calcs...
            // 1695 !  removed font size to external calc so it happens only once

            e.Graphics.ResetClip();
            e.Graphics.Clip.Dispose();
            Tgt.Invalidated = false; //dont draw again until change
        }

0 个答案:

没有答案