Your Basic Rendering Loop C# .net?

Started by
2 comments, last by Chris27 16 years, 9 months ago
What is your basic rendering loop in C# using .net forms? I've been using the system.drawing class to draw shaps to the surface of a form, but it always flickers each time it redraws. I've tried manually drawing to a bitmap in memory and then drawing to the forms surface, but it still flickers. I've also tried optimizeddoublebuffer and doublebuffered which actually make it flicker more often. Any suggestions? Here is my code.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace Air_Hockey
{
    public partial class frmAirHockey : Form
    {
        private Bitmap m_bmpDrawSurface;
        private Graphics m_objGraphics;
        private SolidBrush m_objSolidBrush = new SolidBrush(Color.Black);
        private int m_intMouseX;
        private int m_intMouseY;

        public frmAirHockey()
        {
            InitializeComponent();
            
            //Create a Bitmap in Memory
            m_bmpDrawSurface = new Bitmap(this.ClientRectangle.Width,
                this.ClientRectangle.Height);
        }

        private void Render()
        {
            //Draw to a bitmap in memory
            m_objGraphics = Graphics.FromImage(m_bmpDrawSurface);
            m_objGraphics.Clear(Color.Aqua);
            m_objGraphics.FillEllipse(m_objSolidBrush,
                m_intMouseX-25, m_intMouseY-25, 50, 50);
            m_objGraphics.Dispose();
        }
        
        private void frmAirHockey_MouseMove(object sender, MouseEventArgs e)
        {
            //Mouse X and Y coidinates for drawing the ellipse
            m_intMouseX = e.X;
            m_intMouseY = e.Y;
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            //Draw to the forms surface
            e.Graphics.DrawImage(m_bmpDrawSurface, 0, 0);
            e.Graphics.Dispose();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            //Draw to the memory and force the form to be repainted every 10 milliseconds
            Render();
            this.Invalidate();
        }
    }
}


Advertisement
You could try the BufferedGraphics classes, although the most FPS I've been able to get out of it is 110, GDI isn't exactly fast.

Here's a basic render loop:

using System;using Drawing = System.Drawing;using Forms = System.Windows.Forms;using Threading = System.Threading;namespace GdiTest{	public static class Application	{				private static Drawing.BufferedGraphics BufferedGraphics = null;				private static Drawing.BufferedGraphicsContext BufferedGraphicsContext = new Drawing.BufferedGraphicsContext();				private static Forms.Form Form = new Forms.Form();				private static int FPS = 0;				private static string Title = "GDI Test";				private static Forms.Timer UpdateTimer = new Forms.Timer();				static Application()		{			Form.Text = Title;			Form.ClientSize = new Drawing.Size( 640, 480 );			Form.Resize += new EventHandler( FormResizeEvent );			BufferedGraphics = BufferedGraphicsContext.Allocate( Drawing.Graphics.FromHwnd( Form.Handle ), Form.ClientRectangle );			UpdateTimer.Interval = 1000;			UpdateTimer.Tick += new EventHandler( UpdateTimerTickEvent );			UpdateTimer.Start();			return;		}				private static void FormResizeEvent( object Sender, EventArgs Arguments )		{			BufferedGraphics.Dispose();			BufferedGraphics = BufferedGraphicsContext.Allocate( Drawing.Graphics.FromHwnd( Form.Handle ), Form.ClientRectangle );			return;		}				private static void Render()		{			BufferedGraphics.Render();			FPS++;			return;		}				private static void UpdateTimerTickEvent( object Sender, EventArgs Arguments )		{			Form.Text = Title + " - " + FPS.ToString() + " FPS";					FPS = 0;			return;		}				[STAThread]		public static void Main( string[] ArgumentArray )		{			Forms.Application.EnableVisualStyles();			Form.Show();			while( Form.Created )			{				if( ( Form.Visible == false ) || ( Form.ContainsFocus == false ) || ( Form.Enabled == false ) )				{					Threading.Thread.Sleep( 100 );				}				else				{					Render();				}				Forms.Application.DoEvents();			}			BufferedGraphics.Dispose();			BufferedGraphicsContext.Dispose();			return;		}			}	}
Because you are working with a form, the normal way of doing a render loop isn't going to fly. The form is not meant to be invalidated like that every few milliseconds, and is why you are getting extreme flickering. There are a few options here:

1) My personal recommendation is to skip trying to use GDI, and move on to something that is designed for fast action and rendering. Either take a look at XNA, MDX, or the SlimDx library that some of these forum members are writing (which is looking really cool by the way). You can then use hardware accelerated drawing, and you won't have any troubles at all.

2) If you don't want to do that, you can always try adding a panel or a picture box to your form, and doing your painting in that. That will help avoid flickering on the rest of the form. You will need to only call Invalidate when necessary, and try to call it with the overloaded version so that you can specify only the portion of the screen that needs to be redrawn.

3) If you are willing to shift your thinking a bit, this method may be the best if you want to stick with GDI. You can do all of your painting to the background image of the form, and don't repaint every "frame". If you need to move your character or whatever, first redraw the old background on the image, and then draw the picture of the character in the new position. You never need to totally redraw, you repaint the background so that it looks like there is nothing there.

If anything isn't clear, feel free to ask!
Mike Popoloski | Journal | SlimDX
Thanks guys. I was thinking of tyring the buffered graphics class. I guess I shouldn't be using GDI+ for a game. I tried Managed DirectX, but it seems a bit beyond my scope. I just finished a introducdtory book for C# using .net and Windows Forms so I thought I would try using GDI+ since it's easier to use not having to deal with a 3D enviroment. I'll have to look into XNA and SlimDX.

Thanks

This topic is closed to new replies.

Advertisement