This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.


  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 [] (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 [] (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 [] (9,084 bytes) - [tga.h] - (1,136 bytes)

	Author: Darshan A Patil
	Date:   2000-2001

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); };


The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.


Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.