  | 
   Texture Generation Utility 
   Submitted by  |   
  
  
 I was just reading Terrain Texture Generation by Tobias Franke on flipcode
today. I had written a similar utility some time back which had support for
config-files and multiple texture images. The textures wrap around if the
heightmap is larger than the base textures. I thought that ppl who're
writing terrain engines could use it.
I write and use most of my utilities in Linux. This one was hastily
converted to win32 just for this post.
  
 | 
 
 
 
Currently browsing [texgen.zip] (9,084 bytes) - [main.cpp] - (4,225 bytes)
 
 /*
  This is the unique texture generator for the terrain
  
  Limitations: The base textures should be in 24bpp format.
  and the heightmap should be in 8bpp format 
  
  Added config file support
*/
  #include <stdio.h>
#include "tga.h"
#include <stdlib.h>
#include <string.h>
#include <math.h>
  #define CFG_FILE "texgen.cfg"
  typedef struct 
{
  int hi, lo;
} limits;
  int num_textures;
tga **pics, *hmap;
limits *ltable;
  //For every texture image create a reference map and......
void parse_file();
void get_string(char *, int, FILE *);
  void gen_tex_table(int num)
{
  pics=(tga **)malloc(num*sizeof(tga *));
  ltable=(limits *)malloc(num*sizeof(limits));
}
  void add_to_tex_table(char *filename, int index, int hi, int lo)
{
  pics[index]=new tga(filename);
  ltable[index].lo=lo;
  ltable[index].hi=hi;
}
  void destroy_tex_table()
{
  int i;
  for(i=0; i<num_textures; i++)
    {
      free(pics[i]);
    }
  free(pics);
  free(ltable);
}
 
 
  void main(int argc, char **argv)
{
  tga *hmap;
  
  unsigned char *data;
  
  if (argc != 2)
    {
      printf("Usage: %s <8bppheightmap.tga>\n",argv[0]);
      exit(0);
    }
  
  
  parse_file();
  
  hmap=new tga(argv[1]);
  
  data=(unsigned char *)malloc(3*hmap->width*hmap->height);
  memset(data, 0, 3*hmap->width*hmap->height);
  
  //Main processing phase
  int offset=0;
  for(int y=0; y<hmap->height; y++)
    for(int x=0; x< hmap->width; x++)
      {
	unsigned char height=hmap->data[offset++];
	int clean=1;
	float alpha;
	
	for(int i=0; i<num_textures; i++)
	  {
	    //If within limits, add to data suitably
	    if ( (height >= ltable[i].lo) && (height <= ltable[i].hi))
	      {
		//Calculate alpha for the current texture
		alpha=(float)(height-ltable[i].lo) \
		  /(float)(ltable[i].hi-ltable[i].lo);
		
		// This is a real funky way of doing the alpha calculation but
		// who cares
		//Get a value betn 30 & 150
		float degrees=(alpha*120.0f)+30.0f; 
		alpha=sin(degrees*3.14159f/180.0f);
		//Just check the bounds
		if (alpha < 0.0f) alpha=0.0f;
		if (alpha > 1.0f) alpha=1.0f;
		
		colour24 col=pics[i]->getCol(x,y);
  		int offset2=(offset<<1)+offset;
		if (clean) //write directly
		  {
		    data[offset2+1]=col.r;
		    data[offset2+2]=col.g;
		    data[offset2+3]=col.b;
		  }
		else
		  {
#define A1 alpha
#define A2 (1.0f-A1)
  		    //Mix the two colours
		    data[offset2+1]=(A1*col.r+A2*data[offset2+1]);
		    data[offset2+2]=(A1*col.g+A2*data[offset2+2]);
		    data[offset2+3]=(A1*col.b+A2*data[offset2+3]);
		  }
		clean=0;
	      }
	  }
	}
  
  hmap->write_24bpp(hmap->width,hmap->height,data,"texture.tga");
    delete hmap;
  //This crashes in windows. I dunno why ?
  //free(data); 
  destroy_tex_table();
}
  
/*
  # SAMPLE CFG FILE   
  num_textures 2
  # filename1 range.....
  tex1.tga 0 127
  tex2.tga 127 255
*/
void parse_file()
{
  FILE *fp;
  char buffer[256];
  int num_read=0;
  char str[256];
  int hi,lo;
  
  if((fp=fopen(CFG_FILE,"r"))==NULL)
    {
      printf("Cannot open file %s\n", CFG_FILE);
      exit(0);
    }
  
  //read the first string
  get_string(buffer,256,fp);
  while(buffer[0] == '#' || buffer[0] == ' ' || buffer[0] == '\t')
    {
      get_string(buffer,256,fp);
    }
  //If not a comment
  //Get the number of textures
  sscanf(buffer,"num_textures %d",&num_textures);
  printf("TEXGEN: num_textures: %d\n", num_textures);
  gen_tex_table(num_textures);
  
  //Now that we got num_textures, we can proceed further
  while(num_read != num_textures)
    {
      get_string(buffer,256,fp);
      if(buffer[0] != '#')
	{
	  sscanf(buffer,"%s %d %d",str,&lo,&hi);
	  printf("TEXGEN: %s %5d %5d\n",str,lo,hi);
	  add_to_tex_table(str,num_read,hi,lo);
	  num_read++;
	}
    }
  fclose(fp);
}
  
/*
  Slow way to do it but I dont care
  Cut-pasted and modified from my CNC expt
*/
void get_string(char *buff, int size, FILE *stream)
{
  char ch;
  int i=0;
  while( (ch=(char)fgetc(stream)) != '\n')
    {
      if (i<size-1)
        {
          buff[i++]=ch;
        }
    }
  buff[i]='\0';
}
 
 
 
 
     |  
  
 | 
 
  
Currently browsing [texgen.zip] (9,084 bytes) - [tga.cpp] - (4,497 bytes)
 
 #include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "tga.h"
  
#define DEBUG_ON
  tga::~tga()
{
	if (data)
	free(data);
#ifdef DEBUG_ON
	printf("\nUnloaded\n");
#endif
}
  
tga::tga()
{
}
  
tga::tga(char *filename)
{
	load(filename);
}
  
void tga::load(char *filename)
{
	tga_header hdr;
	FILE *fp;
	int size;
	unsigned char temp;
	
	if ( (fp=fopen(filename,"rb")) == NULL)
	{
		perror("TGA_LOADER");
		exit(1);
	}
	
	fread(&hdr,sizeof(tga_header),1,fp);
			
	if (hdr.cmap_type)
	{
		printf("TGA_LOADER: Can't load colour-mapped Images\n");
		exit(1);
	}
	
	pixfmt=hdr.bpp >> 3;
	width=hdr.width;
	height=hdr.height;
	size=width*height*pixfmt;
	data=(byte *)malloc(size);
	//Position the pointer at the raw image data !
	fseek(fp,hdr.id_length,SEEK_CUR);	
  	if(hdr.image_type > 3)
	{
		switch(pixfmt)
		{
		case 3: //24 bpp
			decode24bit(fp);
			break;
		case 1: //8 bpp
			decode8bit(fp);
			break;
		}
	}
	else ///Uncompressed data
	{
		fread(data,1,size,fp);
		if (pixfmt == 3)
		{
			//Convert BGR to RGB
			for(int i=0; i<size; i+=3)
			{
				temp=data[i];
				data[i]=data[i+2];
				data[i+2]=temp;
			}
		}
	}
#ifdef DEBUG_ON
	printf("Loaded %s: %dx%d @ %dbpp\n", filename, width,height,hdr.bpp);
#endif
	fclose(fp);
}
  
void tga::decode8bit(FILE *fp)
{
	byte packet, colour;
	byte *ptr;
	int count, offset=0, size;
	size=height*width;
	ptr=data;
  	while(offset < size)
	{
		fread(&packet,1,1,fp);
		count=(packet&0x7f)+1;
		offset+=count;
		//Runlength packet
		if (packet&0x80)
		{
			//Read BGR and convert to RGB
			fread(&colour,1,1,fp);
			while(count)
			{
				*ptr=colour;
				ptr++;
				--count;
			}
		}
		else
		{
			//Raw packet
			while(count)
			{
				fread(&colour,1,1,fp);
				*ptr=colour;
				ptr++;
				--count;
			}
		}
	}
#ifdef DEBUG_ON
	printf("Offset=%d , Size=%d\n",offset,size);
#endif
}
  
void tga::decode24bit(FILE *fp)
{
	byte packet, colour[3];
	byte *ptr;
	int count, offset=0, size;
	size=height*width;
	ptr=data;
  	//Sometimes offset exceeds size !
	while(offset < size)
	{
		fread(&packet,1,1,fp);
		count=(packet&0x7f)+1;
		offset+=count;
		//Runlength packet
		if (packet&0x80)
		{
			//Read BGR and convert to RGB
			fread(colour,3,1,fp);
			while(count)
			{
				ptr[0]=colour[2];
				ptr[1]=colour[1];
				ptr[2]=colour[0];
				ptr+=3;
				--count;
			}
		}
		else
		{
			//Raw packet
			while(count)
			{
				fread(colour,3,1,fp);
				ptr[0]=colour[2];
				ptr[1]=colour[1];
				ptr[2]=colour[0];
				ptr+=3;
				--count;
			}
		}
	}
#ifdef DEBUG_ON
	printf("Offset=%d , Size=%d\n",offset,size);
#endif
}
  
//Will be defined for future use!
void tga::decode32bit(FILE *fp)
{
}
  
void tga::write_24bpp(int w, int h, unsigned char *data, char *filename)
{
	FILE *fp;
	char *header=
		"\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00";
	//Open o/p file
	unsigned char info[6];
	unsigned char temp;
	unsigned char *copy;
	int size;
	
	size=w*h*3;
  	info[0]=w;             //lo
	info[1]=(w>>8);        //hi 
	info[2]=h;             //lo
	info[3]=(h>>8);        //hi
	info[4]=24;
	info[5]=0;
  	fp=fopen(filename,"wb");
	fwrite(header,1,12,fp);
	fwrite(info,1,6,fp);		
	
	//Just write the data in RGB fmt
	copy=(unsigned char *)malloc(size);
	memcpy(copy,data,size);
	//Convert this buffer to BGR fmt
	for(int i=0; i<size; i+=3)
	{
		temp=copy[i];
		copy[i]=copy[i+2];
		copy[i+2]=temp;
	}
	
	fwrite(copy,1,size,fp);
	fclose(fp);
	free(copy);
}
 
 
  void tga::write_8bpp(int w, int h, unsigned char *data, char *filename)
{
	FILE *fp;
	char *header=
		"\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00";
	//Open o/p file
	unsigned char info[6];
	int size;
	
	size=w*h;
  	info[0]=w;             //lo
	info[1]=(w>>8);        //hi 
	info[2]=h;             //lo
	info[3]=(h>>8);        //hi
	info[4]=8;
	info[5]=0;
  	fp=fopen(filename,"wb");
	fwrite(header,1,12,fp);
	fwrite(info,1,6,fp);		
	
	fwrite(data,1,size,fp);
	fclose(fp);
}
  // Slightly expensive but who cares..
// this is used in the preprocess stage
colour24 tga::getCol(int x, int y)
{
  colour24 a;
  int offset;
  while( y >= height)
    y=y-height;
  
  while( x >= width)
    x=x - width;
  
  offset=y*width+x;
  offset*=3;
  a.r=data[offset+1];
  a.g=data[offset+2];
  a.b=data[offset+3];
  return a;
}
     |  
  
 | 
 
  
Currently browsing [texgen.zip] (9,084 bytes) - [tga.h] - (1,136 bytes)
 
 /*
	TGA CLASS:
	Author: Darshan A Patil
	Date:   2000-2001
	e-mail: dapatil@hotmail.com
  	Notes:
	This TGA class,
	Can load 8bit and 24bit TGA files.
	Writes 8 and 24 bit TGA files w/o RLE compression
*/
#ifndef TGA_H
#define TGA_H
#include <stdio.h>
  typedef unsigned char byte;
  typedef struct
{
	byte id_length;
	byte cmap_type;
	byte image_type;
	byte cmap_specs[5];
	unsigned short int xorg, yorg,width, height;
	byte bpp; //bits per pixel
	byte img_descriptor;
}tga_header;
  typedef struct
{
  unsigned char r,g,b;
} colour24;
  class tga
{
private:
	void decode8bit(FILE *fp);
	void decode32bit(FILE *fp);
	void decode24bit(FILE *fp);
public:
	int width, height;
	byte pixfmt; //Bytes per pixel.
	byte *data;  //Raw Image Data
	
	tga();
	tga(char *filename);
	~tga();
	
	void load(char *filename);
	void write_24bpp(int width, int height, unsigned char *data, char *filename);
	void write_8bpp(int width, int height, unsigned char *data, char *filename);
	// To be used only for the synthesizer....
	// Uses wrap around mode
	colour24 getCol(int x,int y);
};
  
#endif
  
   |  
  
 | 
 
 
 
The zip file viewer built into the Developer Toolbox made use
of the zlib library, as well as the zlibdll source additions.
 
 
 |