Skip to main content
GameDev.net gamedev.net

PRO Tired of ads? Read GameDev.net ad-free and help keep the community independent with GameDev Pro — $3/month.

Generic pattern maps

Generic pattern maps

Norman Barrows
Gamedev info · · 3 min read
2,523 1
generic pattern maps

often times you need a pattern for something in a game.
for example: what texture tile to use with a given ground quad.

i used to create randomly generated pattern maps for different things:
plants, rocks, bushes, trees, ground quad textures, etc.

then it occurred to me that you could use a generic random pattern map,
and write functions to return whatever you needed.

a generic pattern map is an array of ints with random values.

some examples (from Caveman 3.0)...

Caveman uses a 100x100 generic random pattern map with values from 1
through 100.

// ####### GENERIC RANDOM PATTERN MAP ############ int randmap[100][100]; void init_randmap(){int a,b;for (a=0; a<100; a++) { for (b=0; b<100; b++) { randmap[a]=dice(100); } } } // ####### END GENERIC RANDOM PATTERN MAP ######## // used by hm_canyon2// x and z get divded by 20 to scale them down to the pattern map.// then they get modded by 100 to map them into the pattern map // range of 0..99 by 0..99// the value at that location in the pattern map is then returned. int get_randmap_value(float x,float z){int x2,z2;x2=(int)x;x2/=20;x2=x2%100;z2=(int)z;z2/=20;z2=z2%100;return(randmap[x2][z2]);} // heightmap formula for canyon floors// the heightmap repeats every 2000 units.// 20 units in the heightmap = one unit in the generic // pattern map.// the formula does a double interpolation.// first it determines the height of the four closest // pattern map cells.// then it does a lerp from cell x,z to x+1,z // and x,z+1, to x+1,z+1.// it then lerps between these two results to get the // final interpolated height at the desired location.// 100 is then subtracted from this value, so the results// range from -100 (canyon floor) to 0 (even with canyon rim). float hm_canyon2(float x,float z){int y0,y1,y2,y3;// rem is remainderfloat rem,y4,y5,y6;rem=x;while (rem>=2000.0f) { rem-=2000.0f; }while (rem>=20.0f) { rem-=20.0f; }y0=get_randmap_value(x,z);y1=get_randmap_value(x+20.0f,z);y2=get_randmap_value(x,z+20.0f);y3=get_randmap_value(x+20.0f,z+20.0f);y4=f_lerp(rem,0.0f,20.0f,(float)y0,(float)y1);y5=f_lerp(rem,0.0f,20.0f,(float)y2,(float)y3);rem=z;while (rem>=2000.0f) { rem-=2000.0f; }while (rem>=20.0f) { rem-=20.0f; }y6=f_lerp(rem,0.0f,20.0f,y4,y5);// / y6 2.0fy6-=100.0f;return(y6);} // returns tall grass plant texture ID number to use int grasstex(int x,int z){x=x%100;z=z%100;if (randmap[x][z] < 51) { return(21); }return(121);} // returns prairie grass plant texture ID number to use int prairie_grasstex(int x,int z){x=x%100;z=z%100;if (randmap[x][z] < 31) { return(348); }if (randmap[x][z] < 61) { return(349); }if (randmap[x][z] < 81) { return(346); } return(347);} // returns savanna grass plant texture ID number to use int savanna_grasstex(int x,int z){x=x%100;z=z%100;if (randmap[x][z] < 31) { return(359); }if (randmap[x][z] < 61) { return(360); }if (randmap[x][z] < 81) { return(361); } return(362);} // returns grass plant mesh scale to use int grass_scale(int x,int z){int scale;x=x%100;z=z%100;scale=250+randmap[x][z];scale/=10;return(scale);} // returns grass plant mesh y rotation to use float grass_rotation(int x,int z){float rot;x=x%100;z=z%100;// rot = 0 thru 99% * 2pirot=(float)(randmap[x][z]-1);rot*=pi*2.0f;rot/=100.0f;return(rot);} // returns grass plant mesh offset (jitter) to use float grass_offset(int x,int z){float ofs;x=x%100;z=z%100;// grass step size is 5. offset is -2 thru 2.// offset = -2 + 4 * rand / 100ofs=(float)randmap[x][z];ofs*=4.0f;ofs/=100.0f;ofs-=2.0f;return(ofs);} // adds grass plant meshes to a terrain chunk// grass_stepsize is #defined as 5 void generate_terrain_grass(int c) // c is chunk #{int x1,z1, // SW corner of area to draw x2,z2, // NE corner of area to draw x,z, // un-normalized grass coords scale;Zdrawinfo a;get_chunk_area(c,&x1,&z1,&x2,&z2);ZeroMemory(&a,sizeof(Zdrawinfo));a.materialID=2;a.meshID=27; // 27 = plant2.x a.cull=0;a.alphatest=1;a.clamp=1;a.rad=6;a.cliprng=grass_cliprng;for (z=z1; z<=z2; z+=grass_stepsize) { for (x=x1; x<=x2; x+=grass_stepsize) {if (waterinway(CL[c].mx,CL[c].mz,x,z)) continue;if (storepit_in_way(CL[c].mx,CL[c].mz,x,z)) continue; scale=grass_scale(x,z); a.sx=(float)scale*0.1f; a.sy=(float)scale*0.09f; a.sz=(float)scale*0.1f; a.x=(float)x+grass_offset(x,z); a.z=(float)z+grass_offset(x,z); a.y=heightmap(CL[c].mx,CL[c].mz,(float)x,(float)z); a.ry=grass_rotation(x,z); a.texID=grasstex(x,z); add_zdrawinfo(c,&a); } }}

Discussion

Loading comments...