ClanLib SDK

Raster Graphics

Raster graphics in ClanLib are managed by four types of objects:

Pixel Buffers

A pixel buffer, managed by CL_PixelBuffer, is a container object for a raster image stored in system memory. A pixel buffer consists of a pixel format description (CL_PixelFormat) and then a pointer to the memory in which the image is stored.

The following example creates a pixel buffer and fills it with a raster image that looks like a gradient shade from red to blue:

CL_PixelBuffer create_gradient_image()
{
	CL_PixelBuffer buffer(256, 256, 256*4, CL_PixelFormat::rgba8888);
	unsigned int *pixel_data = (unsigned int *) buffer.get_data();
	for (int y = 0; y < 256; y++)
	{
		for (int x = 0; x < 256; x++)
		{
			unsigned int red = 255-x;
			unsigned int green = 0;
			unsigned int blue = x;
			unsigned int alpha = 255;
			pixel_data[x + y * 256] =
				(red << 24) + (green << 16) + (blue << 8) + alpha;
		}
	}
	return buffer;
}

To draw a pixel buffer on a graphic context, simply call CL_GraphicContext::draw_pixels:

CL_DisplayWindow window(256, 256, "Raster Example");
CL_GraphicContext gc = window.get_gc();
CL_InputContext ic = window.get_ic();
CL_PixelBuffer buffer = create_gradient_image();

while (ic.get_keyboard().get_keycode(CL_KEY_ESCAPE) == false)
{
	gc.draw_pixels(0, 0, buffer);
	window.flip();
	CL_KeepAlive::process();
}

Image Providers

Image providers are classes that can load or save pixel buffers. The interface which all the image providers implement is called CL_ImageProviderType. The interface is simple:

class CL_ImageProviderType
{
public:
	//: Called to load an image with this provider type.
	virtual CL_PixelBuffer load(
		const CL_String &filename,
		CL_VirtualDirectory directory)=0;

	//: Called to save a given PixelBuffer to a file
	virtual void save(
		CL_PixelBuffer buffer,
		const CL_String &filename,
		CL_VirtualDirectory directory)=0;
};

ClanLib itself implements a few image providers for common image formats: CL_PNGProvider, CL_JPEGProvider, CL_PCXProvider and CL_TargaProvider. Each of those providers implement static function versions of the above functions, so to load a PNG image the following syntax would work:

CL_PixelBuffer png_image = CL_PNGProvider::load("test.png");

If you do not know the type of the image format, or if you want to load an image from any of the formats known by ClanLib, you can use the CL_ImageProviderFactory class. All image providers in ClanLib are registered in the factory, allowing you to load images like this:

CL_PixelBuffer image1 = CL_ImageProviderFactory::load("test.png");
CL_PixelBuffer image2 = CL_ImageProviderFactory::load("test.jpg");

Texture Objects

Pixel buffers are images stored in system memory, in a format that can be freely specified. This gives certain limitations - the images can basically only be rendered using CL_GraphicContext::draw_pixels. If an image needs to be drawn in more complex ways, it needs to be placed in a texture object. A texture is an image stored in video memory in a format native to the graphics card's processing unit, and is used by texturing units or fragment shader programs as image sources.

Texture objects are managed by CL_Texture in ClanLib. Textures have many properties that affect how a texture unit may calculate the texels used as input for its texture functions. For example, CL_Texture::set_wrap_mode configures what happens if the texel is located outside the dimensions of the texture. If the wrapping mode is set to cl_wrap_clamp_to_edge it will use the pixel at the edge, or if it is set to cl_wrap_repeat it will set it to tx/width, for example.

To load a pixel buffer into a texture, the following code could be used:

CL_PixelBuffer buffer = create_gradient_image();
CL_Texture texture(gc, cl_texture_2d);
texture.set_image(buffer);

Modern graphics cards are very fast at rendering things, however each time you change the state of the graphic context, such as changing the currently set texture for a texture unit, you lose a lot of performance. It isn't really that important what you change, the key to getting a high speed is to set up the states, then render a lot, then change states, then render a lot, etc.

Since drawing 2D usually means drawing a lot of different images, having a seperate texture for each image will produce a large performance drop. A solution to this problem is to store several images in the same texture, thus avoiding you have to change the state of the graphic context between your images drawn. CL_TextureGroup is a class that help you store images in the same texture:

// Load images:
CL_PixelBuffer image1 = CL_ImageProviderFactory::load("test.png");
CL_PixelBuffer image2 = CL_ImageProviderFactory::load("test.jpg");

// Create a texture of 256x256
CL_TextureGroup texture_group(CL_Size(256, 256));

// Retrieve areas in the texture for our images:
CL_Subtexture subtexture_image1 = texture_group.add(image1.get_size());
CL_Subtexture subtexture_image2 = texture_group.add(image2.get_size());

// Upload images to texture:
subtexture_image1.get_texture().set_subimage(
	subtexture_image1.get_geometry().left,
	subtexture_image1.get_geometry().top,
	image1);
subtexture_image2.get_texture().set_subimage(
	subtexture_image2.get_geometry().left,
	subtexture_image2.get_geometry().top,
	image2);

Sprites

CL_Sprite is a high-level interface that automatically stores images in textures and supports advanced features such as animation. For further information on sprites, see the sprite overview.