Introduction
In procedural texture generation , that I've already faced here and in which I get involved here , can become useful to have a tool to manage Color Gradients. Searching the web I didn't find a c# control to implement what I needed. I decide to do it my self.
Background
I faced two cases where may become usefully color control gradient, first is in the gdi+ .net library (here) , the second in texture generation. I the second case you start with a noise function to generate a heightmap, than you may want to associate a height value to a color; here come in hand a color gradient.
Let's suppose we generate the following noise:
applying a color gradient like this:
we get the following (landscape-like) bitmap:
applying a different color gradient from the same starting noise we can get a (sky) bitmap like this:
Using the code
Using the control in design.
To add the control ColGradCtr
at design drag it into your form and size it like you want. It contains two default colors White (starting) and Black (ending).
Then you can reset the two starting colors in the load event of the contol (or in the load event of the form). At the same time you can add others colors.
private void colGradCtr1_Load_1(object sender, EventArgs e)
{
colGradCtr1.reset(Color.Blue, Color.White); colGradCtr1.addColor(Color.FromArgb(0, 128, 128), 0.06f); colGradCtr1.addColor(Color.FromArgb(0, 0, 159), 0.60f);
colGradCtr1.addColor(Color.FromArgb(6, 20, 203), 0.70f);
colGradCtr1.addColor(Color.FromArgb(146, 96, 53), 0.75f);
colGradCtr1.addColor(Color.FromArgb(0, 100, 0), 0.80f);
colGradCtr1.addColor(Color.FromArgb(64, 0, 0), 0.90f);
}
The control need at leaast two colors (start and ending) that are respectively in position 0 and 1. All the other colors are in position >0 and <1.
Getting a sample color from ColGradCtr
. If you give a float input >=0 and <=1 you get the corrisponding color.
Let's see the landscape generation routine:
private void reColor(PictureBox pct, ColGradCtr col){
Bitmap b2 = new Bitmap(pct.Width, pct.Height);
for (int i = 0; i < pct.Width; i++)
for (int j = 0; j < pct.Height; j++)
{
b2.SetPixel(i, j, col.getColor(heightMap[i, j]));
}
pct.Image = b2;
}
where heightMap
is a float matrix containing the samples (heights) between 0 and 1.
The gdi+ aproach. If you ned a linear gradient you can get it fom ColGradCtr
in this manner :
LinearGradientBrush br = new LinearGradientBrush(this.pictureBox1.ClientRectangle, Color.Black
, Color.Black,LinearGradientMode.BackwardDiagonal);
ColorBlend cb = BackGradCtr.getColorBlend();br.InterpolationColors = cb;
offScreenDC.FillRectangle(br, this.pictureBox1.ClientRectangle);
Using the control at runtime. Pressing left mouse on a handle, you can move it, changing the color position. If you drag the handle out to the of control (to the right), you erase that color. Pressing right mouse near an handle let you modify the color value, pressing right mouse in empty place let you add a new color. Start and end colors can not be moved or erased, but you can change them.
The event management : I implemented two events , ColorChanged
and ColorChanging
. The first fires when you are moving a color , the second when you release mouse buttons and commit a change (modify a color, add a color , erase a color). Follows as I used ColorChanged event in thr example aplication:
private void colGradCtr1_ColorChanged(object sender, EventArgs e)
{
reColor(pictureBox2, colGradCtr1);
}
The example application:
Click "generate new noise" to test the gradients with a new noise.
Click gdi+ example to get the second example form:
Points of Interest
ColGradCtr is not a "wrapper" of gdi+ ColrBlend , its a "wrapper" of the class
class Wgrad<T>
as I created it; its a "ordered" list of objects
public class gradObj<T>
{
public T ele { get; set; }
public float w {get;set;}
public gradObj(T e, float p)
{
ele = e;
if (p > 1f)
p = 1f;
if (p < 0f)
p = 0f;
w = p;
}
}
where T in our case is Color, and w is the position in the 0..1 scale.
Follows an explanation of the data structure behind the color gradient:
The class Wgrad<T>
manages a List of obects T (in this case Color) mantaining them ordered depending on a float value that ranges between 0 and 1.
Some methods of Wgrad<T>
:
public void <code>addEle</code>
Finaly the noiseGen is the class i developed to manage noise functions. It contains a c# implementation of 2d Perlin Noise.
History
Added Wgrad<T> explanation.