Lighthouse3d.com

Please send me your comments
Terrain Tutorial

Index

Introduction

A TGA Library
A Simple TGA Library
TGA lib Source

Height Maps
Height Maps from Images

Lighting
Computing Normals
Simulating Lighting
Implementation Details
Screen Shots

Source Code

Artificial Terrain Generation
The Fault Algorithm
Implementation Details
Two Simple Variations
The Circles Algorithm

Mid Point Displacement
The MPD Algorithm

Particle Deposition

Smoothing
Smoothing
Matrix filters
API details

Source (Linux and Win32)

[Previous: A simple TGA lib] [Next: Height Maps from Images]

Terrain Tutorial


Source Code for the TGA library


You may use this library for whatever you want. This library is provide as is, meaning that I won't take any responsability for any damages that you may incur from its usage.


    
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "tga.h"

// this variable is used for image series
static int savedImages=0;

// load the image header fields. We only keep those that matter!
void tgaLoadHeader(FILE *file, tgaInfo *info) {

	unsigned char cGarbage;
	short int iGarbage;

	fread(&cGarbage, sizeof(unsigned char), 1, file);
	fread(&cGarbage, sizeof(unsigned char), 1, file);

// type must be 2 or 3
	fread(&info->type, sizeof(unsigned char), 1, file);

	fread(&iGarbage, sizeof(short int), 1, file);
	fread(&iGarbage, sizeof(short int), 1, file);
	fread(&cGarbage, sizeof(unsigned char), 1, file);
	fread(&iGarbage, sizeof(short int), 1, file);
	fread(&iGarbage, sizeof(short int), 1, file);

	fread(&info->width, sizeof(short int), 1, file);
	fread(&info->height, sizeof(short int), 1, file);
	fread(&info->pixelDepth, sizeof(unsigned char), 1, file);

	fread(&cGarbage, sizeof(unsigned char), 1, file);
}

// loads the image pixels. You shouldn't call this function
// directly
void tgaLoadImageData(FILE *file, tgaInfo *info) {

	int mode,total,i;
	unsigned char aux;

// mode equal the number of components for each pixel
	mode = info->pixelDepth / 8;
// total is the number of bytes we'll have to read
	total = info->height * info->width * mode;
	
	fread(info->imageData,sizeof(unsigned char),total,file);

// mode=3 or 4 implies that the image is RGB(A). However TGA
// stores it as BGR(A) so we'll have to swap R and B.
	if (mode >= 3)
		for (i=0; i < total; i+= mode) {
			aux = info->imageData[i];
			info->imageData[i] = info->imageData[i+2];
			info->imageData[i+2] = aux;
		}
}	

// this is the function to call when we want to load
// an image
tgaInfo * tgaLoad(char *filename) {
	
	FILE *file;
	tgaInfo *info;
	int mode,total;

// allocate memory for the info struct and check!
	info = (tgaInfo *)malloc(sizeof(tgaInfo));
	if (info == NULL)
		return(NULL);


// open the file for reading (binary mode)
	file = fopen(filename, "rb");
	if (file == NULL) {
		info->status = TGA_ERROR_FILE_OPEN;
		return(info);
	}

// load the header
	tgaLoadHeader(file,info);

// check for errors when loading the header
	if (ferror(file)) {
		info->status = TGA_ERROR_READING_FILE;
		fclose(file);
		return(info);
	}

// check if the image is color indexed
	if (info->type == 1) {
		info->status = TGA_ERROR_INDEXED_COLOR;
		fclose(file);
		return(info);
	}
// check for other types (compressed images)
	if ((info->type != 2) && (info->type !=3)) {
		info->status = TGA_ERROR_COMPRESSED_FILE;
		fclose(file);
		return(info);
	}

// mode equals the number of image components
	mode = info->pixelDepth / 8;
// total is the number of bytes to read
	total = info->height * info->width * mode;
// allocate memory for image pixels
	info->imageData = (unsigned char *)malloc(sizeof(unsigned char) * 
								total);

// check to make sure we have the memory required
	if (info->imageData == NULL) {
		info->status = TGA_ERROR_MEMORY;
		fclose(file);
		return(info);
	}
// finally load the image pixels
	tgaLoadImageData(file,info);

// check for errors when reading the pixels
	if (ferror(file)) {
		info->status = TGA_ERROR_READING_FILE;
		fclose(file);
		return(info);
	}
	fclose(file);
	info->status = TGA_OK;
	return(info);
}		

// converts RGB to greyscale
void tgaRGBtogreyscale(tgaInfo *info) {

	int mode,i,j;

	unsigned char *newImageData;

// if the image is already greyscale do nothing
	if (info->pixelDepth == 8)
		return;

// compute the number of actual components
	mode = info->pixelDepth / 8;

// allocate an array for the new image data
	newImageData = (unsigned char *)malloc(sizeof(unsigned char) * 
						info->height * info->width);
	if (newImageData == NULL) {
		return;
	}

// convert pixels: greyscale = o.30 * R + 0.59 * G + 0.11 * B
	for (i = 0,j = 0; j < info->width * info->height; i +=mode, j++)
		newImageData[j] =	
			(unsigned char)(0.30 * info->imageData[i] + 
					0.59 * info->imageData[i+1] +
					0.11 * info->imageData[i+2]);


//free old image data
	free(info->imageData);

// reassign pixelDepth and type according to the new image type
	info->pixelDepth = 8;
	info->type = 3;
// reassing imageData to the new array.
	info->imageData = newImageData;
}

// takes a screen shot and saves it to a TGA image
int tgaGrabScreenSeries(char *filename, int xmin,int ymin, int xmax, int ymax) {
	
	int w, h;
	unsigned char *imageData;

// compute width and heidth of the image
	w = xmax - xmin;
	h = ymax - ymin;

// allocate memory for the pixels
	imageData = (unsigned char *)malloc(sizeof(unsigned char) * w * h * 4);

// read the pixels from the frame buffer
	glReadPixels(xmin,ymin,xmax,ymax,GL_RGBA,GL_UNSIGNED_BYTE, (GLvoid *)imageData);

// save the image 
	return(tgaSaveSeries(filename,w,h,32,imageData));
}




// saves an array of pixels as a TGA image
int tgaSave(	char 		*filename, 
		short int	width, 
		short int	height, 
		unsigned char	pixelDepth,
		unsigned char	*imageData) {

	unsigned char cGarbage = 0, type,mode,aux;
	short int iGarbage = 0;
	int i;
	FILE *file;

// open file and check for errors
	file = fopen(filename, "wb");
	if (file == NULL) {
		return(TGA_ERROR_FILE_OPEN);
	}

// compute image type: 2 for RGB(A), 3 for greyscale
	mode = pixelDepth / 8;
	if ((pixelDepth == 24) || (pixelDepth == 32))
		type = 2;
	else
		type = 3;

// write the header
	fwrite(&cGarbage, sizeof(unsigned char), 1, file);
	fwrite(&cGarbage, sizeof(unsigned char), 1, file);

	fwrite(&type, sizeof(unsigned char), 1, file);

	fwrite(&iGarbage, sizeof(short int), 1, file);
	fwrite(&iGarbage, sizeof(short int), 1, file);
	fwrite(&cGarbage, sizeof(unsigned char), 1, file);
	fwrite(&iGarbage, sizeof(short int), 1, file);
	fwrite(&iGarbage, sizeof(short int), 1, file);

	fwrite(&width, sizeof(short int), 1, file);
	fwrite(&height, sizeof(short int), 1, file);
	fwrite(&pixelDepth, sizeof(unsigned char), 1, file);

	fwrite(&cGarbage, sizeof(unsigned char), 1, file);

// convert the image data from RGB(a) to BGR(A)
	if (mode >= 3)
	for (i=0; i < width * height * mode ; i+= mode) {
		aux = imageData[i];
		imageData[i] = imageData[i+2];
		imageData[i+2] = aux;
	}

// save the image data
	fwrite(imageData, sizeof(unsigned char), 
			width * height * mode, file);
	fclose(file);
// release the memory
	free(imageData);

	return(TGA_OK);
}

// saves a series of files with names "filenameX.tga"
int tgaSaveSeries(char		*filename, 
			 short int		width, 
			 short int		height, 
			 unsigned char	pixelDepth,
			 unsigned char	*imageData) {
	
	char *newFilename;
	int status;
	
// compute the new filename by adding the 
// series number and the extension
	newFilename = (char *)malloc(sizeof(char) * strlen(filename)+8);

	sprintf(newFilename,"%s%d.tga",filename,savedImages);
	
// save the image
	status = tgaSave(newFilename,width,height,pixelDepth,imageData);
	
//increase the counter
	if (status == TGA_OK)
		savedImages++;
	free(newFilename);
	return(status);
}


// releases the memory used for the image
void tgaDestroy(tgaInfo *info) {

	if (info != NULL) {
		if (info->imageData != NULL)
			free(info->imageData);
		free(info);
	}
}



[Previous: A simple TGA lib] [Next: Height Maps from Images]