#include "global.h"

//MapObject map;

//#define USE_ROAM

//------------ MAP OBJECT -----------------
MapObject::MapObject()
{
	height_data_loaded = false;
	texture_data_loaded = false;
	width = 0;
	length = 0;
	grid_XY_scale = 0;
	grid_Z_scale = 0;
	min_height = max_height = 0;
	mapID = -1;
}

MapObject::~MapObject()
{
	// Maybe delete display lists here!
}

float MapObject::GetHeight(int x, int y)
{
	x /= grid_XY_scale;
	y /= grid_XY_scale;
	// Just return the height at that point.
	return heightmap(x,y);
}

// This function should interpolate the height at x & y
vec3f MapObject::GetNormal(float x, float y)
{
	if (x<0) x=0;
	if (y<0) y=0;
	if (x>=mapwidth) x = mapwidth-1;
	if (y>=maplength) y = maplength-1; 
	// Interpolation Method 1: Round down (not so good)
	//return heightmap(x,y);
	// Interpolation Method 2: Bilinear interp (pretty good)
	x /= grid_XY_scale;
	y /= grid_XY_scale;
	int xi = (int)x, yi = (int)y;
	float xf = x-(float)xi, yf = y-(float)yi;
	vec3f n;

	n = normalmap(xi,yi)*(1-xf)*(1-yf);
	if (xi < width-1)
	{
		n += normalmap(xi+1,yi)*xf*(1-yf);
		if (yi < length-1)
		{
			n += normalmap(xi,yi+1)*(1-xf)*yf;
			n += normalmap(xi+1,yi+1)*xf*yf;
		}
	}
	else if (yi < length-1)
	{
		n += normalmap(xi,yi+1)*(1-xf)*yf;
	}
	return n;
}

// This function should interpolate the height at x & y
float MapObject::GetHeight(float x, float y)
{
	// Interpolation Method 1: Round down (not so good)
	//return heightmap(x,y);
	// Interpolation Method 2: Bilinear interp (pretty good)
	if (x<0) x=0;
	if (y<0) y=0;
	if (x>=mapwidth) x = mapwidth-1;
	if (y>=maplength) y = maplength-1; 

	x /= grid_XY_scale;
	y /= grid_XY_scale;
	int xi = (int)x, yi = (int)y;
	float xf = x-(float)xi, yf = y-(float)yi;
	float h;

  	h = heightmap(xi,yi)*(1-xf)*(1-yf);
	if (xi < width-1)
	{
		h += heightmap(xi+1,yi)*xf*(1-yf);
		if (yi < length-1)
		{
			h += heightmap(xi,yi+1)*(1-xf)*yf;
			h += heightmap(xi+1,yi+1)*xf*yf;
		}
	}
	else if (yi < length-1)
	{
		h += heightmap(xi,yi+1)*(1-xf)*yf;
	}
	return h;
}

bool MapObject::LoadHeightData(char* fname, float xyscale, float zscale)
{
	int x,y;

	//grid_XY_scale = xyscale;
	//grid_Z_scale = zscale;

	printf("Reading %s: ",fname);

	// Load the png into a temp grayscale image
	//glh::array2<unsigned char> tempmap;
	gs_image_type tempmap;
	if (!read_png_grey(fname,tempmap))
	{
		printf("> Error reading terrain map\n");
		return false;
	}

#ifdef USE_ROAM
	oriHeightMap.set_size(tempmap.get_width()+1,tempmap.get_height()+1);
	for (y=0; y < tempmap.get_height(); y++)
	{
		for (x=0; x < tempmap.get_width(); x++)
			oriHeightMap(x,y) = tempmap(x,y);
		oriHeightMap(x,y) = tempmap(x-1,y);
	}
	for (x=0; x < tempmap.get_width(); x++)
		oriHeightMap(x,y) = tempmap(x,y-1);
	oriHeightMap(x,y) = tempmap(x-1,y-1);
#else
	oriHeightMap = tempmap;
#endif

	// Copy the data into the float array, scaling the data at the same time
	max_height = -1E10;
	min_height = 1E10;
	width = oriHeightMap.get_width();
	length = oriHeightMap.get_height();

#ifdef USE_ROAM
	grid_XY_scale = 2048.0 / width;
	grid_Z_scale  = 1;
#else
	grid_XY_scale = xyscale;
	grid_Z_scale = zscale;
#endif

	mapwidth = width * grid_XY_scale;
	maplength = length * grid_XY_scale;
	heightmap.set_size(width,length);
	for (y=0; y<length; y++)
		for (x=0; x<width; x++)
		{
			heightmap(x,y) = grid_Z_scale*oriHeightMap(x,y);
			if (min_height > heightmap(x,y))	min_height = heightmap(x,y);
			if (max_height < heightmap(x,y))	max_height = heightmap(x,y);
		}

	printf("[%dx%d]\nComputing normals...\n",width,length);

	// Compute normals for the map
	normalmap.set_size(width,length);
	gradientmap.set_size(width,length);
	vec3f v1,v2,nrm;
	for (y=1; y<length-1; y++)
		for (x=1; x<width-1; x++)
		{
			float dh_x = heightmap(x+1,y) - heightmap(x-1,y);
			float dh_y = heightmap(x,y+1) - heightmap(x,y-1);
			v1 = vec3f(  2 * grid_XY_scale, 0, dh_x );
			v2 = vec3f(  0, 2 * grid_XY_scale, dh_y );
			nrm = v1.cross(v2);
			nrm.normalize();
			normalmap(x,y) = nrm;
			gradientmap(x,y)[X] = nrm[X]*128 + 128;
			gradientmap(x,y)[Y] = nrm[Y]*128 + 128;
			gradientmap(x,y)[Z] = nrm[Z]*128 + 128;
		}


	height_data_loaded = true;

	return true;
}

double frand();
void MapObject::GenTrees(unsigned int newPosSeed, unsigned int nTrees)
{
	treePosSeed = newPosSeed;
	numTrees = nTrees;

	treeInfo.resize(nTrees);

	srand(newPosSeed);

	int nClusters = (frand()*0.01) * nTrees + 1;
	int treesPerCluster = nTrees / nClusters;

	float clusterDensity = 0.2;

	int c,i;

	int treesSoFar = 0;

	// Don't want trees in water!
	float waterHeightThreshold = (GetMaxHeight()-GetMinHeight()) * 0.05 + GetMinHeight();
	
	printf("Generating %d clusters:\n",nClusters);

	for (c = 0; c < nClusters; c++)
	{
		vec2f clusterPos;
		do {
			clusterPos = vec2f( frand() * GetWidth(), frand() * GetLength() );
		} while (GetHeight(clusterPos[X],clusterPos[Y]) <= waterHeightThreshold);

		float clusterNTrees = treesPerCluster * (frand()*0.85+0.15);
		float clusterSize = clusterNTrees * (frand()*0.3+0.7) / clusterDensity;

		printf("[%d](%d)<%.1f>: ",c,(int)clusterNTrees,clusterSize);
		for (i=0; i < clusterNTrees; i++)
		{
			treeInfoType t;
			vec2f offset = vec2f( clusterSize*(frand()-0.5), clusterSize*(frand()-0.5) );
			
			t.pos = clusterPos+offset;
			t.onFireAndGonnaDieAHorribleFlamingDeath=false;
			treeInfo[i] = t;
			//treePos[i] = clusterPos + offset;

			treesSoFar++;
			//printf("(%.1f,%.1f) ",treePos[i][X],treePos[i][Y]);
		}
		printf("\n");
	}
	// Remainder are randomly distributed across the map, but above waterline
	printf("Remaining %d trees:\n",nTrees - treesSoFar);
	for (i=0; i < nTrees - treesSoFar; i++)
	{
		do {
			treeInfoType t;
			//treePos[i] = vec2f( frand() * GetWidth(), frand() * GetLength() );
			t.pos = vec2f( frand() * GetWidth(), frand() * GetLength() );
			t.onFireAndGonnaDieAHorribleFlamingDeath=false;
			treeInfo[i] = t;

		} while (GetHeight(treeInfo[i].pos[X],treeInfo[i].pos[Y]) <= waterHeightThreshold);
		treesSoFar++;
		/*
		printf("(%.1f,%.1f) ",treePos[i][X],treePos[i][Y]);
		if (((i+1)%10)==0)
			printf("\n");
			*/
	}
	printf("\n");

	srand(timeGetTime());
}


bool MapObject::LoadTextureData(char* fname)
{
	printf("MAP: Reading texture map (%s): ",fname);
	if (!read_png_rgb(fname,textureimage))
	{
		printf("> Error loading texture\n");
		return false;
	}
	printf("[%d,%d]\n",textureimage.get_width(),textureimage.get_height());

	printf("MAP: Reading tree map : ");
	rgb_image_type tempRGB;
	if (!read_png_rgb("../data/tree1_tex.png",tempRGB))
	{
		printf("Could not load tree1_tex.png\n");
		return false;
	}
	gs_image_type tempAlpha;
	if (!read_png_grey("../data/tree1_mask.png",tempAlpha))
	{
		printf("Could not load tree1_mask.png\n");
		return false;
	}
	int x,y;
	treeTex.set_size(tempRGB.get_width(),tempRGB.get_height());
	for (y=0; y<treeTex.get_height();y++)
		for(x=0; x<treeTex.get_width();x++)
		{
			treeTex(x,y)[0] = tempRGB(x,y)[0];
			treeTex(x,y)[1] = tempRGB(x,y)[1];
			treeTex(x,y)[2] = tempRGB(x,y)[2];
			treeTex(x,y)[3] = tempAlpha(x,y); 
		}

	texture_data_loaded = true;

	return true;
}

void MapObject::RegisterModelData()
{
#ifdef USE_ROAM
	roamLandscape.xyscale = grid_XY_scale;
	roamLandscape.zscale  = grid_Z_scale;
	roamLandscape.Init(&oriHeightMap,&normalmap);
#endif

	/*
	if (mapID == 1)
	{
		tiletexob.reserve(tiletex.size());
		for (int i=0; i < tiletex.size(); i++)
		{
			tiletexob[i].bind();
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
				glTexImage2D(GL_TEXTURE_2D,		// 2D texture mode
					0,										// mipmap level
					GL_RGBA,								// internal format
					tiletex[i].get_width(),			// image width
					tiletex[i].get_height(),		// image height
					0,										// image border (0/1)
					GL_RGB,								// image pixel format
					GL_UNSIGNED_BYTE,					// image pixel size/type
					tiletex[i].get_pointer());		// ptr to image data
			tiletexob[i].unbind();
		}
	}
	else
	*/
	{
		// Register the texture data:
		texob.bind();
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
			glTexImage2D(GL_TEXTURE_2D,		// 2D texture mode
				0,										// mipmap level
				GL_RGBA,								// internal format
				textureimage.get_width(),		// image width
				textureimage.get_height(),		// image height
				//gradientmap.get_width(),
				//gradientmap.get_height(),
				0,										// image border (0/1)
				GL_RGB,								// image pixel format
				GL_UNSIGNED_BYTE,					// image pixel size/type
				textureimage.get_pointer());	// ptr to image data
				//gradientmap.get_pointer());
		texob.unbind();
	}

	// Register the vertex data:
	CreateDisplayList();

	// Register the texture data:
	treeTexOb.bind();
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexImage2D(GL_TEXTURE_2D,		// 2D texture mode
			0,										// mipmap level
			GL_RGBA,								// internal format
			treeTex.get_width(),			// image width
			treeTex.get_height(),		// image height
			0,										// image border (0/1)
			GL_RGBA,								// image pixel format
			GL_UNSIGNED_BYTE,					// image pixel size/type
			treeTex.get_pointer());	// ptr to image data
	treeTexOb.unbind();

}

void MapObject::ReleaseModelData()
{
	treeTexOb.del();
	texob.del();
	dlist.del();
}

display_list& MapObject::CreateDisplayList()
{
	GLenum mode = GL_COMPILE;
	if (!dlist.is_valid())
	{
		texob.enable();
		//texob.bind();
		dlist.new_list(mode);
		DrawMapMesh();
		dlist.end_list();
		//texob.unbind();
		texob.disable();
	}
	return dlist;
}

void MapObject::DrawMap()
{
	/*
	texob.enable();
	if (dlist.is_valid())
		dlist.call_list();
	else
		DrawMapMesh();
	texob.disable();
	*/

#ifndef USE_ROAM
	texob.enable();
	texob.bind();
	if (dlist.is_valid())
		dlist.call_list();
	else
		DrawMapMesh();
	texob.unbind();
	texob.disable();

	DrawTrees();

#else

	glPushMatrix();

	roamLandscape.Reset();
	roamLandscape.Tessellate();
	//SetDrawModeContext();
	//glDisable(GL_LIGHTING);
	//glDisable(GL_CULL_FACE);

	texob.enable();
	texob.bind();

	//glEnable(GL_NORMALIZE);

			glTexGeni(GL_S,GL_TEXTURE_GEN_MODE,GL_OBJECT_LINEAR);
			glTexGeni(GL_T,GL_TEXTURE_GEN_MODE,GL_OBJECT_LINEAR);

			GLfloat texplane[] = { 0, 0, 0, 0 };
			GLfloat scale = 1.0/grid_XY_scale;
			texplane[0] = 1.0/width;
			glTexGenfv(GL_S,GL_OBJECT_PLANE,texplane);

			texplane[0] = 0;
			texplane[1] = 1.0/length;
			glTexGenfv(GL_T,GL_OBJECT_PLANE,texplane);

			GLfloat difmat[] = { 1, 1, 1, 1 };
			GLfloat nomat[]  = { 0, 0, 0, 1 };
			glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,difmat);
			glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,nomat);
			glMaterialfv(GL_FRONT_AND_BACK,GL_EMISSION,nomat);
			glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,nomat);

			glEnable(GL_TEXTURE_GEN_S);
			glEnable(GL_TEXTURE_GEN_T);

	roamLandscape.Render();

		glDisable(GL_TEXTURE_GEN_S);
		glDisable(GL_TEXTURE_GEN_T);

	//glEnable(GL_CULL_FACE);

	//glDisable(GL_NORMALIZE);
	
	texob.unbind();
	texob.disable();

	//glEnable(GL_LIGHTING);
	glPopMatrix();

#endif

	return;
}

void MapObject::DrawMapMesh()
{
	// Must have height data to draw!
	if (!height_data_loaded)
	{
		printf("MapObject Error: Attempting to draw map with invalid height data!\n");
		return;
	}

	glTexGeni(GL_S,GL_TEXTURE_GEN_MODE,GL_OBJECT_LINEAR);
	glTexGeni(GL_T,GL_TEXTURE_GEN_MODE,GL_OBJECT_LINEAR);

	GLfloat texplane[] = { 0, 0, 0, 0 };
	GLfloat scale = 1.0/grid_XY_scale;
	texplane[0] = scale/width;
	glTexGenfv(GL_S,GL_OBJECT_PLANE,texplane);

	texplane[0] = 0;
	texplane[1] = scale/length;
	glTexGenfv(GL_T,GL_OBJECT_PLANE,texplane);

	/*
	BYTE curTileTex=tilemap(0,0);
	tiletexob[curTileTex].bind();
	*/

	GLfloat difmat[] = { 1, 1, 1, 1 };
	GLfloat nomat[]  = { 0, 0, 0, 1 };
	glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,difmat);
	glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,nomat);
	glMaterialfv(GL_FRONT_AND_BACK,GL_EMISSION,nomat);
	glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,nomat);

	glEnable(GL_TEXTURE_GEN_S);
	glEnable(GL_TEXTURE_GEN_T);

			/*
			if (curTileTex != tilemap(px,py))
			{
				glEnd();
				tiletexob[curTileTex].unbind();
				curTileTex = tilemap(px,py);
				glBegin(GL_QUAD_STRIP);
				tiletexob[curTileTex].bind();
			}
			*/

	int x,y,px,py;
	//*
	glBegin(GL_QUAD_STRIP);
	glColor4f(1.0,1.0,1.0,1.0);
	for (y=1; y < length-2; y++)
	{
		for (x=1; x < width-1; x++)
		{
			px = x;	py = y+1;
			glNormal( normalmap(px,py) );
			glVertex3f( grid_XY_scale*px , grid_XY_scale*py, heightmap(px,py) );
			//glVertex3f( px , py, heightmap(px,py) );

			px = x;	py = y;
			glNormal( normalmap(px,py) );
			glVertex3f( grid_XY_scale*px , grid_XY_scale*py, heightmap(px,py) );
			//glVertex3f( px , py, heightmap(px,py) );
		}
		y++;
		for (; x >= 1; x--)
		{
			px = x;	py = y;
			glNormal( normalmap(px,py) );
			glVertex3f( grid_XY_scale*px , grid_XY_scale*py, heightmap(px,py) );
			//glVertex3f( px , py, heightmap(px,py) );

			px = x;	py = y+1;
			glNormal( normalmap(px,py) );
			glVertex3f( grid_XY_scale*px , grid_XY_scale*py, heightmap(px,py) );
			//glVertex3f( px , py, heightmap(px,py) );
		}

	}
	glEnd();
	//*/

	/*
	tiletexob[curTileTex].unbind();
	*/

	glDisable(GL_TEXTURE_GEN_S);
	glDisable(GL_TEXTURE_GEN_T);

	/*
	// Draw vertex normals for debugging:
	tex_object_2D::disable();
	glDisable(GL_LIGHTING);
	glColor4f(1.0,1.0,0.0,1.0);
	glBegin(GL_LINES);
	vec3f p1, p2;
	for (y=0; y < length; y++)
		for (x=0; x < width; x++)
		{
			p1 = vec3f ( grid_XY_scale*x , grid_XY_scale*y, heightmap(x,y) );
			p2 = p1 + normalmap(x,y) * 20;
			glVertex( p1 );
			glVertex( p2 );
		}
	glEnd();
	glEnable(GL_LIGHTING);
	*/

	return;
}

bool MapObject::LoadMapByID(BYTE newMapID)
{
	mapID = newMapID;

	switch (mapID)
	{
		case 0:
#ifdef USE_ROAM
			if (!LoadHeightData("../data/terrain2c.png",DEFAULT_XYSCALE,DEFAULT_ZSCALE))
#else
			if (!LoadHeightData("../data/terrain2b.png",DEFAULT_XYSCALE*2,DEFAULT_ZSCALE*3))
			//if (!LoadHeightData("../data/terrain3.png",DEFAULT_XYSCALE*2,DEFAULT_ZSCALE*3))
#endif
			{
				game.error("Could not load terrain2c.png");
				return false;
			}
			if (!LoadTextureData("../data/terrain2tex_m.png"))
			//if (!LoadTextureData("../data/terrain3_tex.png"))
			{
				game.error("Could not load terrain2tex_m.png");
				return false;
			}
			break;

		case 1:
			if (!LoadHeightData("../data/menu_terrain.png",DEFAULT_XYSCALE,DEFAULT_ZSCALE*1.5))
			{
				game.error("Could not load menu_terrain.png");
				return false;
			}
			if (!LoadTextureData("../data/menu_terrain_tex.png"))
			{
				game.error("Could not load menu_terrain_tex.png");
				return false;
			}
			break;

			/*
		case 1:
		{
			if (!LoadHeightData("../data/terrain2b.png"))
			{
				game.error("Could not load terrain2b.png");
				return false;
			}
			tiletex.resize(3);
			tiletexob.resize(3);
			bool work = true;
			work &= read_png_rgb("../data/tile_water.png",tiletex[0]);
			work &= read_png_rgb("../data/tile_sand.png",tiletex[1]);
			work &= read_png_rgb("../data/tile_rock.png",tiletex[2]);
			work &= read_png_grey("../data/terrain2_tilemap.png",tilemap);
			if (!work)
			{
				game.error("Could not load tile maps\n");
				return false;
			}
			break;
		}
		*/
		default:
			game.error("Unknown map ID (%d)",(int)mapID);
			return false;
	}

	return true;
}

double frand();
vec3f MapObject::GetStartingLocation(int nLoc)
{
	vec3f loc;
	// -1 is the default = random starting location for this map
	if (nLoc == -1)
	{
		float p1 = frand() * 0.9 + 0.05;
		float p2 = frand() * 0.9 + 0.05;
		loc = vec3f( p1 * mapwidth, p2 * maplength, 0 );
	}
	else
	{
		if (nLoc == 0)			loc = vec3f( 0.15 * mapwidth, 0.15 * maplength, 0 );
		else if (nLoc == 1)	loc = vec3f( 0.15 * mapwidth, 0.85 * maplength, 0 );
		else if (nLoc == 2)	loc = vec3f( 0.85 * mapwidth, 0.15 * maplength, 0 );
		else if (nLoc == 3)	loc = vec3f( 0.85 * mapwidth, 0.85 * maplength, 0 );
		else if (nLoc == 4)	loc = vec3f( 0.50 * mapwidth, 0.50 * maplength, 0 );

		else
			loc = vec3f( 0.50 * mapwidth, 0.50 * maplength, 0 );
	}

	loc[Z] = GetHeight(loc);
	return loc;
}

void MapObject::DrawTrees()
{
	glDisable(GL_CULL_FACE);
	//glEnable(GL_BLEND);
	//glDisable(GL_LIGHTING);

	//glDepthMask(GL_FALSE);
	glEnable(GL_ALPHA_TEST);
	glAlphaFunc(GL_GREATER, 0.25);

	glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);

	int i;
	vec3f pos;

	// These can instead be crossed with the cam dir
	// to support billboarding
	//vec3f udir = vec3f(1,0,0);
	//vec3f u2dir = vec3f(0,1,0);
	//vec3f vdir = vec3f(0,0,1);
	vec3f udir = game.world.eyeDirection.cross(UP);
	udir.normalize();
	vec3f u2dir = vec3f(0,1,0);
	vec3f vdir = UP;

	float usize = 30;
	float vsize = 70;

	vec3f uoff = udir * usize;
	vec3f u2off = u2dir * usize;
	vec3f voff = vdir * vsize;

	GLfloat difmat[] = { 1, 1, 1, 0.75 };
	GLfloat nomat[]  = { 0, 0, 0, 1 };
	glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,difmat);
	glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,nomat);
	glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,nomat);
	glMaterialfv(GL_FRONT_AND_BACK,GL_EMISSION,nomat);

	tex_object_2D::enable();
	treeTexOb.bind();
	glColor4i(1,1,1,1);
	for (i=0; i < treeInfo.size(); i++)
	{
		if ((treeInfo[i].lifeleft > 0) ||
			 (!treeInfo[i].onFireAndGonnaDieAHorribleFlamingDeath))
		{
			pos[X] = treeInfo[i].pos[X];
			pos[Y] = treeInfo[i].pos[Y];
			pos[Z] = GetHeight(pos) + 65;

			glBegin(GL_TRIANGLE_STRIP);
				glNormal( GetNormal(pos) );
				glTexCoord2d(1,1);	glVertex( pos + uoff + voff );
				glTexCoord2d(1,0);	glVertex( pos + uoff - voff );
				glTexCoord2d(0,1);	glVertex( pos - uoff + voff );
				glTexCoord2d(0,0);	glVertex( pos - uoff - voff );
			glEnd();
			/*
			glBegin(GL_TRIANGLE_STRIP);
				glNormal( GetNormal(pos) );
				glTexCoord2d(1,1);	glVertex( pos + u2off + voff );
				glTexCoord2d(1,0);	glVertex( pos + u2off - voff );
				glTexCoord2d(0,1);	glVertex( pos - u2off + voff );
				glTexCoord2d(0,0);	glVertex( pos - u2off - voff );
			glEnd();
			*/
		}
	}
	treeTexOb.unbind();
	tex_object_2D::disable();

	//glDepthMask(GL_TRUE);
	glDisable(GL_ALPHA_TEST);

	//glEnable(GL_LIGHTING);
	//glDisable(GL_BLEND);
	glEnable(GL_CULL_FACE);
}
