Lighthouse3d.com

 Terrain Tutorial Index A TGA Library A Simple TGA Library TGA lib Source Height Maps Height Maps from Images Artificial Terrain Generation The Fault Algorithm Implementation Details Two Simple Variations The Circles Algorithm Smoothing Smoothing Matrix filters API details

# Terrain Tutorial

## A TGA library

This library is introduced here in order to make this tutorial self-contained. The library is pretty simple, handling only uncompressed images, RGBA or greyscale. No support for color palettes is provided. If you're interested in a full-blown TGA library I would suggest a look at Paul Groves' TGA loader. Check out his home page.

The functions in this library include loading and saving TGA images, colour reduction from RGB to greyscale, and a screen grabber.

## TGA file structure

A TGA file has a header that consists of 12 fields. These are:
• id (unsigned char)
• colour map type (unsigned char)
• image type (unsigned char)
• colour map first entry (short int)
• colour map length (short int)
• map entry size (short int)
• horizontal origin (short int)
• vertical origin (short int)
• width (short int)
• height (short int)
• pixel depth (unsigned char)
• image descriptor (unsigned char)
• From all these fields we only really care about the image type, in order to find out if the image is uncompressed and it is not color indexed, the width and height of the image, the pixel depth, and finally the image descriptor that contains the image pixels.

Some possible values for the image type are:
• 1 - colour map image
• 2 - RGB(A) uncompressed
• 3 - greyscale uncompressed
• 9 - greyscale RLE (compressed)
• 10 - RGB(A) RLE (compressed)
• The only types that we're dealing with here are 2 and 3. As for the pixel depth, it represents the number of bits per pixel used, i.e. a greyscale image has 8 for pixel depth, where as a RGBA has 32.

One note of interest is that a TGA stores the pixels in BGR mode, i.e. the red and blue components are swapped, relative to RGB. This implies that we'll have to swap them when we load or save the image.

Now for some library details. The following status codes where defined:
• TGA_ERROR_FILE_OPEN
• TGA_ERROR_INDEXED_COLOR - when we're presented with a color indexed file
• TGA_ERROR_MEMORY
• TGA_ERROR_COMPRESSED_FILE - when we're presented with a compressed file
• TGA_OK - This is what we want!
• The following structure provides the necessary fields to hold the image information and pixels:

typedef struct {
int status;
unsigned char type, pixelDepth;
short int width, height;
unsigned char *imageData;
}tgaInfo;

The following functions are available in the library:

Parameters:
filename - the name of the image file

This functions returns a structure with all the image info and pixels. Pixels are stored in imageData, which is an one-dimensional array with values from 0 to 255. In order to read this array correctly, we'll need to check the values of pixelDepth, width and height. The value of pixelDepth tells us which information is in the array. There are 3 possible values with the following meaning:
• 8 - The image is greyscale, each array value corresponds to a pixels intensity.
• 24 - The image is RGB, each pixel requires 3 components of the array. The array should look like R,G,B,R,G,B,...
• 32 - An RGBA image, where each pixel requires 4 components. The array looks like R,G,B,A,R,G,B,A,...
• When calling this function is it always a good idea to check the value of the fieldstatus to see if there were any errors.

The next function allows us to save pixels as a TGA image

int tgaSave(char *filename, short int width, short int height, unsigned char pixelDepth, unsigned char *imageData);

Parameters:
filename - The file name where we want to save the image (extension is required!).
width - The width of the image
height - The height of the image
pixelDepth - The number of bits per pixel, 8 for greyscale, 24 for RGB, and 32 for RGBA
imageData - The image pixels

This function returns a status code. TGA_OK means everything went smoothly.

The next function is provided so that we can save series of images. For instance, if the file name is "foo" then the first time this function is called it will save an image as "foo0.tga", the second time "foo1.tga", and so on.

int tgaSaveSeries(char *filename, short int width, short int height, unsigned char pixelDepth, unsigned char *imageData);

Parameters:
filename - The file name where we want to save the image (no extensions in here please).
width - The width of the image
height - The height of the image
pixelDepth - The number of bits per pixel, 8 for greyscale, 24 for RGB, and 32 for RGBA
imageData - The image pixels

As always, it is a good idea to check the return value of the function to see if the operation was completed successfully. The next function allows you to take a screen shot and save it to a TGA image. With this function it is possible to grab the entire viewport, or just a part of it. The syntax is as follows:

int tgaGrabScreenSeries(char *filename, int x,int y, int width, int height);

Parameters:
filename - the image file name
x - The x component of the lower left corner of the image.
y - The y component of the lower left corner of the image.
width - The width of the image.
height - The height of the image.

The following code snipet illutrates how to capture the whole viewport (assuming a viewport from 0,0 to w,h) , and only its top half.

tgaGrabSeries("bla", 0,0,w,h);
tgaGrabSeries("bla", 0,h/2,w,h/2);

The code for the above function is:

int tgaGrabScreenSeries(char *filename,
int xmin,int ymin,
int xmax, int ymax) {

int w, h;
unsigned char *imageData;

w = xmax - xmin;
h = ymax - ymin;

imageData = (unsigned char *)malloc(
sizeof(unsigned char)
* w * h * 4);

GL_RGBA,GL_UNSIGNED_BYTE, (GLvoid *)imageData);

return(tgaSaveSeries(filename,w,h,32,imageData));
}

The key is the OpenGL function glReadPixels. This function reads a rectangular area from the frame buffer and stores it in an array (this array must have previously allocated memory). This function has the following syntax:

void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);

Parameters:
x - the x component of the lower left corner of the requested area
y - the y component of the lower left corner of the requested area
width - the width in pixels of the area
height - the height in pixels of the area
format - determines which data we're going to read. See bellow for some possible values.
type - the data type of the data we're going to read.
pixels - An array with the pixel information. The array data depends on the format and type.

The format specifies if we're getting RGBA data, or just the Green component. Some possible values are:
• GL_RGB - Read the three color components
• GL_RGBA - RGB + alpha channel
• GL_GREEN - Read only the green component
• GL_BGR, GL_BGRA - This format reads the same information as GL_RGB, and GL_RGBA, but returns the Blue component first instead of the Red one.
• NBote that GL_BGR and GL_BGRA were only introduced in OpenGL 1.2. As for type the value we want is:
• GL_UNSIGNED_BYTE - each component is represented has a number between 0 and 255
• This is the data type of each component in a TGA image.

This next function converts a RGB image to a greyscale image. The formula used was posted on the openGL.org discussion groups some time ago.

greyscale = 0.30 * R + 0.59 * G + 0.11 * B

This function returns the modified image information. Besides imageData, the fields pixelDepth and type are also altered accordingly to reflect the new image type.

void tgaRGBtogreyscale(tgaInfo *info);

Parameters:

This last function releases the memory, so when using the image for a texture or a height map, the image can be destroyed afterwards.