Bitmap
A bitmap is what actually stores the pixel data in the background. You can create a bitmap from an image file, or create a blank bitmap with a given size. There is currently no optimized way to create a bitmap from an array of pixel data, however you can use the SetPixel method to do so.
Loading an image file into a bitmap is very simple.
Bitmap b = new Bitmap("icon.png");
Console.WriteLine($"Icon size: {b.Width}x{b.Height}"); // Icon size: 268x268If the filename specified cannot be found, odl automatically tries to locate it anyway by appending.png. This means that .png is not necessary when specifying the file to load.
It is highly recommended not to load files that exceed your GPU's texture size limit. This texture size limit can be found with Graphics.MaxTextureSize. More information on this topic can be found under Large Bitmaps.
To create a blank bitmap, just pass in two Width/Height integers.
Bitmap b = new Bitmap(268, 268);
Console.WriteLine($"Icon size: {b.Width}x{b.Height}"); // Icon size: 268x268When a Bitmap is no longer used, it must be disposed with the Dispose() method. If you don't dispose a bitmap that's no longer referenced, you will create a memory leak! odl prints to the console when it's destructing an undisposed Bitmap - it's up to you to find where your memory leak is!
By default, whenever a Sprite object is disposed, it will automatically also dispose its Bitmap object. This can be disabled by setting the sprite's DestroyBitmap property to false.
There are a lot of methods available to manipulate bitmap data once it's been loaded. However, before you may manipulate a Bitmap, you must Unlock() it first. When you're done manipulating the bitmap, you should Lock() it again. This "locking bits" concept is often abstracted away and unavailable to the user, but by manually controlling when to lock or unlock the bitmap data, performance is drastically increased.
In the example below, we're creating a 10x10 bitmap and filling it with a red color using the SetPixel() method.
Bitmap b = new Bitmap(10, 10);
b.Unlock();
for (int x = 0; x < b.Width; x++)
{
for (int y = 0; y < b.Height; y++)
{
b.SetPixel(x, y, Color.RED);
}
}
b.Lock();We've now created a 10x10 bitmap, and filled it with a red color. To now display this bitmap to the screen, we're just going to quickly create a sprite and attach our newly created bitmap to it:
And as you can see, we've produced a 10x10 red square.

To find the color of a certain pixel, use GetPixel(int X, int Y). This will return a Color object. The bitmap does not need to be unlocked to retrieve a pixel's color.
But of course, setting each pixel individually is very inefficient. As such, there are more optimized methods for drawing filled (or just outlined) squares. Let's see them in action:
This time, we've produced a 25x25 square with a red filler color, and given it a blue outline.
If we wanted to draw a cross, we could make use of the DrawLine method, which draws a line between two points.
Note that the black you see in this image comes from the window background color; the bitmap itself is transparent, aside from the red cross!
Worth noting too, is that DrawLine takes two points. That means that (24, 24) is the bottom right of the image. In contrast, FillRect and DrawRect in the example above took x, y, width and height. An x of 0 and a width of 25 will end up at an x of 24 too.
To draw or fill a circle, we have the DrawCircle() and FillCircle() methods. These take the center point of the circle, the radius and the color.
Most methods that accept x/y parameters also accept a Point object instead. Methods that take width/height parameters usually also take a Size object. Methods that have x, y, width and height parameters, typically also accept a Rect instead.
Rather than drawing a whole circle, there are also DrawQuadrant() and FillQuadrant() methods, to just draw one section of a circle.

Circles and quadrants are all drawn anti-aliased. There is no built-in way to draw an aliased line (although you could draw it at twice the size, then downscale via the sprite's ZoomX/Y properties and set the scale mode to linear through SDL itself).
If you want to copy a part of a bitmap over to a different bitmap, you can use the Build() method. The Build() method has two main variants: one that scales the part of the source bitmap to fill the destination rectangle, and one that doesn't.

This example above copies the center 50x50 pixels of icon.png and blits it onto our newly created bitmap. We then dispose the src bitmap, as we've copied the pixels over and don't need the bitmap any longer. The build arguments here represent the destination x/y position (0, 0), the bitmap to copy from, and the rectangle inside the source bitmap to copy over.
We can also scale the bitmap while we're copying it over, as mentioned in the example above. To do so, we have to add two more integers after the destination x/y position: the destination width and height.

As you can see, it has scaled our 268x268 down into a 50x50 rather nicely.
Last updated