• We see that you're not registered. Please read this thread and if you want, sign up on the forum.

C# CrimeWorld Devblog #1 - GDI/+ TextRendering and DoubleBuffering

Space Pirate

Working on it!
Nov 1, 2019
Reaction score
Quality Posts
@Shenandoah said i should blog about the development of CrimeWorld, mine and @Psy little child that we've been trying to make now for years.

We have decided to use WinForms with C# as the language with heavily customized UI controls using GDI/GDI+. I believe that we will be able to deliver a enjoyable user experience for end-users with a mid-range computer. We're both experienced in making UI systems from scratch using OpenTK and SFML however we will not go down this route too much as the time required to make such systems is the reason why we lost motivation in our previous attempts. WinForms is easier and much faster to develop for rather than making our custom UI system ourselves.

Enough with the backstory and excuses, let's goto the meat.

If all you want to draw a simple string without any regard for clipping and layout using the older version GDI+ called GDI your best bet is using TextOut. TextOut is faster at drawing simple strings than GDI+ DrawString() or TextRenderer(). It's perfect for updating labels where the text changes frequently and you don't have any concerns about overdrawing and layout.

You can get the class here: https://pastebin.com/BFpaf4jw I found it on Stackoverflow or somewhere else.
Keep in mind that it caches the fonts as you use the Draw-functions, if you have different fonts you might be inclined to preload them before starting to draw strings.

WinForms is known to be a flickering piece of shit especially if you're making custom controls. To solve this we need DoubleBuffering. In a nutshell we draw the entire control to a Bitmap first and when BackColor, Text or images are finished drawing we then render it to the Form or parent control.

Some guy called NT Almond made a functioning DoubleBuffering class for C# back in 2003 that still works flawlessly you can get it here: https://pastebin.com/ZTqzvX6b
It's a bit modified for my use case but you get the idea.

  1. Define internal readonly DBGraphics _buffer, we use internal so you can draw to the buffer from descending controls.
  2. Initialize the buffer in constructor: _buffer = new DBGraphics().
  3. Override OnPaintBackground() and leave the function empty.
  4. Draw to the buffer: _buffer.g.DrawRectangle(PEN, RECT)
  5. Render the buffer: _buffer.Render(e.Graphics)

Here's a gif with some custom buttons and a progressbar: