GDI+ Graphics: Adjusting Gamma

Summary

I’m going to do something a little different here. I’m going to start a series of posts about the GDI+ graphics interface (in C#). If you have followed my blog for a while, you already know that I have a demonstration game I wrote Battle Field One. The last version I blogged about uses SVG graphics to render the output in a browser. In a future post I’m going to show how to use GDI+ graphics and replace the web interface with a standard windows forms interface. So I’ll cover a few GDI+ techniques along the way and then I’ll incorporate these techniques in the game changes coming up.

GDI+

First, I need to explain GDI+. GDI+ is the new version of the 2 dimensional graphics engine that can be accessed directly from the forms paint event (GDI stands for Graphic Design Interface). GDI is not fast. For fast, we would need to use DirectX (I’ll blog about DirectX and Direct 3D later). Since Battle Field One is a turn-based game, we don’t need fast. What we need is simple. That’s why I’m going to use GDI+.

To setup a quick and dirty example, you can create a new Visual Studio project of type “Windows Form Application”. Go to the code part of your form. You’ll need to add the following “usings” at the top of your initial form:

using System.Drawing;
using System.Drawing.Imaging;

Now switch back to your form design and switch to the events tab of your properties window:

Scroll down until you find the “Paint” event and double-click on it. A new event called “Form1_Paint” will be created in your code. All of your GDI+ code will be entered into this event for now.

Now let’s put some png files in a folder of the project. Create a new folder named “img”, download and copy this image into that folder:

mountains_01.png

Now put this code inside your Form1_Paint event method:

Image Mountains = Image.FromFile("../../img/mountains_01.png");
Graphics g = pe.Graphics;
g.DrawImage(Mountains, 100, 100, Mountains.Width, Mountains.Height);

Now run your program. You should see a hex shaped image with some mountainous terrain:

Of course, this program is just rendering the png image that is sitting in the img directory. The reason for the double “../” in the path is because the program that executes is inside the bin/Debug folder. So the relative path will be two directories back and then into the img directory. If you don’t specify the path correctly, you’ll get a giant red “X” in your window:

Adjusting the Gamma

One of the capabilities that we’ll need when switching the game to use GDI+ is that we need to darken the hex terrain where the current units cannot see. In the game the visible cells will be rendered with a gamma that is 1.0, and the non-visible cells will be rendered with a gamma of 3.0 (larger numbers are darker, less than one will be brighter).
Now I want to demonstrate three mountain cells that represent a gamma of 1.0, 0.5 and 2.0. In order to modify the gamma setting we’ll need to use the ImageAttributes object:

ImageAttributes imageAttributes = new ImageAttributes();
imageAttributes.SetGamma(1.0f, ColorAdjustType.Bitmap);

The DrawImage object can accept the ImageAttributes as a parameter, but we also need to add a few more parameters. So I’m going to show the code here, and then I’ll discuss it:

Image Mountains = Image.FromFile("../../img/mountains_01.png");
Graphics g = pe.Graphics;
ImageAttributes imageAttributes = new ImageAttributes();
 
// normal gamma
imageAttributes.SetGamma(1.0f, ColorAdjustType.Bitmap);
g.DrawImage(Mountains,
        new Rectangle(100, 100, Mountains.Width, Mountains.Height),
        0,
        0,
        Mountains.Width,
        Mountains.Height,
        GraphicsUnit.Pixel,
        imageAttributes);
// lighter
imageAttributes.SetGamma(0.5f, ColorAdjustType.Bitmap);
g.DrawImage(Mountains,
        new Rectangle(200, 100, Mountains.Width, Mountains.Height),
        0,
        0,
        Mountains.Width,
        Mountains.Height,
        GraphicsUnit.Pixel,
        imageAttributes);
// darker
imageAttributes.SetGamma(2.0f, ColorAdjustType.Bitmap);
g.DrawImage(Mountains,
        new Rectangle(300, 100, Mountains.Width, Mountains.Height),
        0,
        0,
        Mountains.Width,
        Mountains.Height,
        GraphicsUnit.Pixel,
        imageAttributes);

This is all the code you’ll need for this demo to work. When you specify a rectangle for the second parameter, you will need to use the x,y coordinates of that rectangle to determine where the image will be plotted. Leave the DrawImage x,y set to zero. Use the image.Width and image.Height if you want to maintain the scaling of the image itself. Otherwise you can adjust these parameters to blow up or shrink an image.

If you run the sample, you’ll see that there is a normal mountain hex on the left, a lighter hex to the right of it and then a darker hex to the right of that:

Download the Sample Code

You can go here to download the zip file for this demo application:

GDIPlusGammaDemo.zip

Leave a Reply