#include "stdafx.h"
#include "trees.h"
#include <algorithm>


int thevine;

v3 solveintersection(v4 p1, v4 p2, v4 p3)
{
	m44 m;
	m.m44[0][0]=p1.x;
	m.m44[1][0]=p1.y;
	m.m44[2][0]=p1.z;
	m.m44[3][0]=p1.w;

	m.m44[0][1]=p2.x;
	m.m44[1][1]=p2.y;
	m.m44[2][1]=p2.z;
	m.m44[3][1]=p2.w;

	m.m44[0][2]=p3.x;
	m.m44[1][2]=p3.y;
	m.m44[2][2]=p3.z;
	m.m44[3][2]=p3.w;

	m.m44[0][3]=0;
	m.m44[1][3]=0;
	m.m44[2][3]=0;
	m.m44[3][3]=1;

	m.Inverse();

	p1 =  v4(0,0,0,1) * m;

	return v3(p1.x/p1.w,p1.y/p1.w,p1.z/p1.w);
}



CLASSY classifypoint(v3 p, v4 plane)
{
	float d=p.x*plane.x+p.y*plane.y+p.z*plane.z+plane.w;
	if (fabsf(d)<EPS) return COINCIDENT;
	if (d>0) return INFRONT;
	if (d<0) return INBACK;
	return COINCIDENT;
}


v3 minp(0,0,0),maxp(0,0,0);
v3 mulp;
PointSet pointlist;

v3p* grid[MAXZ][MAXY][MAXX];

void boundpoint(const v3 &p, int &ix, int &iy, int &iz)
{	
	ix=(bound(minp.x,p.x,maxp.x) - minp.x) * mulp.x;
	iy=(bound(minp.y,p.y,maxp.y) - minp.y) * mulp.y;
	iz=(bound(minp.z,p.z,maxp.z) - minp.z) * mulp.z;
}

v3 getpoint(int ix, int iy, int iz)
{
	return v3( ix/mulp.x + minp.x, iy/mulp.y + minp.y, iz/mulp.z + minp.z);
	
}

void addpoint(v3 &p)
{
	PointSet::iterator i = pointlist.find(v3p(p));
	if (i==pointlist.end())
	{
		i=pointlist.insert(v3p(p)).first;
		int ix,iy,iz;
		boundpoint(p,ix,iy,iz);
		((v3p*)(&*i))->next = grid[iz][iy][ix];
		grid[iz][iy][ix]=(v3p*)&*i;
	}
}


v3 *findnearestpoint(v3 p, float &bestdist)
{	
	/*
	int ix=(bound(minp.x,p.x,maxp.x) - minp.x) * mulp.x;
	int iy=(bound(minp.y,p.y,maxp.y) - minp.y) * mulp.y;	
	int iz=(bound(minp.z,p.z,maxp.z) - minp.z) * mulp.z;
	v3p *best=NULL;
	float bestd=0;
	for (int r=0;r<4;r++)
	{		
		int r2=r-1;
		for (int z=-r;z<=r;z++)
		for (int y=-r;y<=r;y++)
		for (int x=-r;x<=r;x++) if (abs(z)>r2 || abs(y)>r2 || abs(x)>r2)
		{
			int ix2 = ix+x;
			int iy2 = iy+y;
			int iz2 = iz+z;
			if (ix2>=0 && iy2>=0 && iz2>=0 && ix2<MAXX && iy2<MAXY && iz2<MAXZ)
			{
				if (best)
				{
					for (int c1=0;c1<8;c1++)
					{
						v3 pp = getpoint(ix2 + ((c1&1)?1:0), iy2 + ((c1&2)?1:0), iz2 + ((c1&4)?1:0));
						if (LengthSquared(pp-v3(p))<bestd*bestd) break;
					}
					if (c1==8) continue;
				}
				v3p *cur=grid[iz2][iy2][ix2];
				while (cur)
				{
					float d=LengthSquared(p-*cur);
					if (best==NULL || d<bestd)
					{
						best=cur;
						bestd=d;
					}
					cur=cur->next;
				}
			}			
		}
		if (best) break;		
	}
*/

	PointSet::iterator cur1 = pointlist.lower_bound(p);if (cur1!=pointlist.end() && cur1!=pointlist.begin() && *cur1 != p) --cur1; else 
	{
		cur1=pointlist.end();
		cur1--;
	}
	PointSet::iterator cur2 = pointlist.upper_bound(p);	
		
	
	float bestd=0;
	v3 *best=NULL;
	int dobreak=0;
	for (;cur1!=pointlist.end() && cur2!=pointlist.end();)
	{
		float d=bestd;
		if (cur1!=pointlist.end())
		{		
			if (best)
			{
				float dy = (cur1->y - p.y);
				if (dy*dy>=bestdist) 
				{
					cur1=pointlist.end();
					goto skip1;
				}
			}
			d=LengthSquared(p-*cur1);
			if (best==NULL || d<bestd)
			{
				best=(v3*)&*cur1;
				bestd=d;
			}		
			if (cur1==pointlist.begin()) cur1=pointlist.end(); else --cur1;
		}
skip1:
		if (cur2!=pointlist.end())
		{		
			if (best)
			{
				float dy = (cur2->y - p.y);
				if (dy*dy>=bestdist) 
				{
					cur2=pointlist.end();
					goto skip2;
				}
			}
			d=LengthSquared(p-*cur2);
			if (best==NULL || d<bestd)
			{
				best=(v3*)&*cur2;
				bestd=d;
			}		
			++cur2;
		}
skip2:			;
	}
	
//*/
	bestdist=sqrtf(bestd);
	return best;
	
}


float samplegrid(const v3 &p, v3 *nearest)
{
	if (nearest==NULL)
	{	
		v3 p2 = p;
		p2.y=0;
		return Length(p2)+500.f;
	}
	else
	{
		v3 p2 = p-*nearest;		
		float bestd=Length(p2);		
		//if (bestd<0) bestd=0;
		return bestd;
	}
}

float samplegrid(const v3 &p)
{
	float bestd;
	v3 *nearest = findnearestpoint(p,bestd);
	return samplegrid(p,nearest);
}

int vine;
float vinet;

/*
float samplegridfull(const v3 &p, v3 *nearest)
{
	float f=(samplegrid(p,nearest)-1) ;
	
	float dist = p.x*p.x+ p.z*p.z;
	if (f<0) f=-f*f*100; // very, very negative and bad up to -100 inside the thing itself
	else 
	{
		float updraft = 1-(f-1)*(f-1);
		f=-f; // gets worse (more negative) with increasing distance		
		{
			if (updraft>1) updraft=1;
			if (updraft<0) updraft=0;
		//	f+=updraft * p.y / 10.f;
		}
		f+=p.y ;/// (sqrtf(dist)+2) * 8;
		//
		// wibble
		f+= Perlin::Noise3o(p.x/20.f+vine*20,p.y/20.f-vinet,p.z/20.f+vinet*0.1f) * 10.f; // plus some noise
	}
	
	//if (dist>150*150) f-=(sqrtf(dist)-150);
	
	return f;//-sqrtf(dist)+p.y;
}
*/

int numbigcubes=0;

v3 getgrad(const v3 &p, v3 *nearest)
{

	

	v3 o;
	static const float delta = 0.1f;
	float f = samplegrid(p,nearest);
	o.x = (samplegrid(p + v3(delta,0,0), nearest) - f) / delta;
	o.y = (samplegrid(p + v3(0,delta,0), nearest) - f) / delta;
	o.z = (samplegrid(p + v3(0,0,delta), nearest) - f) / delta;
	return o;
}

void addcube(m44 orient, v3 size, polygonlist &ps)
{
	float wibble = 0.8f;
	v3 nn[6];
	for (int side=0;side<6;side++)
	{
		int axis = side%3;
		v3 n1(orient.m44[axis][0],orient.m44[axis][1],orient.m44[axis][2]);		
		if (side>=3) n1=-n1;
		n1=Normalize(n1+v3(GaussRandom(),GaussRandom(),GaussRandom())*wibble);
		nn[side]=n1;
	}

	for (side=0;side<6;side++)
	{
		
		v3 n1=nn[side];		
		v4 p1(n1.x,n1.y,n1.z,-DotProduct(n1,orient.GetT()+n1*(&size.x)[side%3]));

		polygon myp;
		myp.plane=p1;
		for (int spin=0;spin<4;spin++)
		{	
			
			int axis = (side+1)%3;			
			if (spin==1 || spin==2) axis+=3;
			v3 n2=nn[axis];			
			v4 p2(n2.x,n2.y,n2.z,-DotProduct(n2,orient.GetT()+n2*(&size.x)[axis%3]));

			axis = (side+2)%3;
			if (spin>=2) axis+=3;
			v3 n3=nn[axis];			
			v4 p3(n3.x,n3.y,n3.z,-DotProduct(n3,orient.GetT()+n3*(&size.x)[axis%3]));

			v3 thep = solveintersection(p1,p2,p3);
			if (thep.y<0) thep.y=0;
			/*
			CLASSY debug1 = classifypoint(thep,p1);
			CLASSY debug2 = classifypoint(thep,p2);
			CLASSY debug3 = classifypoint(thep,p3);
			*/
			thep/=5;
			thep.x=int(thep.x*1000+0.5f)/1000.f;
			thep.y=int(thep.y*1000+0.5f)/1000.f;
			thep.z=int(thep.z*1000+0.5f)/1000.f;
			myp.p.push_back(thep);
			if (thep.x< minp.x) minp.x=thep.x;
			if (thep.x> maxp.x) maxp.x=thep.x;
			if (thep.y< minp.y) minp.y=thep.y;
			if (thep.y> maxp.y) maxp.y=thep.y;
			if (thep.z< minp.z) minp.z=thep.z;
			if (thep.z> maxp.z) maxp.z=thep.z;

			//pointlist.insert(thep);
			addpoint(thep);
			numbigcubes++;
		}
		
		ps.push_back(myp);

		

	}
}

v3 splineinterp(v3 *ps, int numps, float t)
{	
	t--;
	if (t>=numps-3.0001f) t=numps-3.0001f;
	if (t<0) t=0;
	float tt,ttt,a,b,c,d;
	int ti=floor(t);
	t=t-ti;
	tt=t*t;
	ttt=t*tt;
	if (ti<0) ti=0;
	float *in=(float*)(&ps[ti]);
	v3 pout;
	float *out=(float*)(&pout);
	const static int num = 3;
	for (int c1=0;c1<num;c1++)
	{
		// and here are simons beautiful equations. thanks simey!
		// interpolation will never be the same again. just ask
		// sp228@cam.ac.uk for all your maths needs!

		a=(-in[0]+3*in[num]-3*in[num*2]+in[num*3])/6;
		b=(in[0]-2*in[num]+in[num*2])/2;
		c=(-2*in[0]-3*in[num]+6*in[num*2]-in[num*3])/6;
		d=in[num];

		*out++=a*ttt+b*tt+c*t+d;
		in++;
	}
	return pout;
}

v3 randvec()
{
    float z = Random(-1.0f, 1.0f);
    float a = Random(0.0f, PI*2);

    float r = sqrtf(1.0f - z*z);

    float x = r * cosf(a);
    float y = r * sinf(a);

    return v3(x , y, z);
}

void makecubestrand(v3 *ps, int numps, int numcubes, v3 minsize, v3 maxsize, polygonlist &polys)
{
	float t=1;
	while (t<numps-3)
	{
		float dt = Random(0,(numps-3)/float(numcubes));
		t+=dt;

		m44 randmat;
		randmat.RotateAngleAxis(Random(-PI,PI),Normalize(randvec()));
		v3 p=splineinterp(ps,numps,t);
		p+=v3(Random(minsize.x,maxsize.x),Random(minsize.y,maxsize.y),Random(minsize.z,maxsize.z));
		randmat.SetT(p);

		v3 sz(Random(minsize.x,maxsize.x),Random(minsize.y,maxsize.y),1);
		sz.z = Random(minsize.z*minsize.x*minsize.y,maxsize.z*maxsize.x*maxsize.y) / (sz.x*sz.y); 

		addcube(randmat,sz,polys);

		t+=dt;
	}
}



void makecubetree(v3 p, v3 d, float power, float dpower, polygonlist &polys, int level)
{
	
	float branchpower = power - dpower * 2;
	while (power>0)
	{
		float yadj = 1-d.y;
		if (yadj<0.12) yadj=0.12f;
		if (yadj>0.5f) yadj=0.5f;

		yadj=0.021f;

		
		float size=pow(power,1.f/2.f) * 0.5f;
		p+=d*size*Random(0.5f,1.f);
		d=Normalize(d+randvec()*0.1f+v3(0,yadj,0));

		m44 randmat;
		randmat.RotateAngleAxis(Random(-PI,PI),Normalize(randvec()));

		int split=(rand()%(80-int(power)));
		if (split<5 && power<branchpower && level<4 )
		{
			v3 d1 = d + randvec();
			float cc=cos(PI*2/3);
			float ss=sin(PI*2/3);
			v3 d2 = v3(d1.x*cc+d1.z*ss,d1.y,d1.z*cc-d1.x*ss) + randvec()*0.4f;
			v3 d3 = v3(d2.x*cc+d2.z*ss,d2.y,d2.z*cc-d2.x*ss) + randvec()*0.4f;
			d1.y*=0.1f;
			d2.y*=0.1f;
			d3.y*=0.1f;
			d1=Normalize(d1);
			d2=Normalize(d2);
			d3=Normalize(d3);
			float bal=GaussRandom(0.1f,0.5f);
			float xpower=power*1.f;
			makecubetree(p+d1*size/2,d1,min(xpower*bal,power+dpower),dpower*0.62f,polys,level+1);
			if (split<2) 
			{
				makecubetree(p+d2*size/2,d2,min(xpower*(1-bal),power+dpower),dpower*0.62f,polys,level+1);
				if (split==0) makecubetree(p+d3*size/2,d3,min(xpower*(bal),power+dpower),dpower*0.62f,polys,level+1);
				return;
			}
			else
			{
				power = min(power,xpower*(1-bal));
			}
		}

		int type = rand() % 4;
		switch (type)
		{
		case 0:
		case 1:
			size*=(type+3);
			randmat.SetT(p);
			addcube(randmat,v3(size+Random(-size/8,size/8),size+Random(-size/8,size/8),size+Random(-size/8,size/8)),polys);
			
			break;
		default:
			randmat.SetT(p+randvec()*size*4);
			addcube(randmat,v3(size+Random(-size/8,size/8),size+Random(-size/8,size/8),size+Random(-size/8,size/8)),polys);
			break;
		}

		
		
		size=pow(power,1.f/3.f);
		p+=d*size*Random(0.6f,1.2f);
		d=Normalize(d+randvec()*0.1f+v3(0,yadj,0));

		power-=dpower * d.y;
	}
}

void buildbsp(bspnode *tree, polygonlist &polylist)
{
	if (polylist.empty()) return;
	polygon &root = *polylist.begin();
	tree->partition = root.plane;
	tree->polygons.push_back(root);
	
	polygonlist frontlist,backlist;
	
	polygonlist::iterator tit = polylist.begin();
	++tit;
	for (;tit!=polylist.end();++tit)
	{
		polygon &poly = *tit;
		switch (poly.classify(tree->partition))
		{
		case COINCIDENT:
			tree->polygons.push_back(poly);
			break;
		case INBACK:
			backlist.push_back(poly);
			break;
		case INFRONT:
			frontlist.push_back(poly);
			break;
		case SPANNING:
			{
				polygon frontbit,backbit;
				poly.split(frontbit,backbit,tree->partition);
				if (backbit.p.size()) backlist.push_back(backbit);
				if (frontbit.p.size()) frontlist.push_back(frontbit);
			}
		}
	}
	if (frontlist.empty()==false)
	{
		tree->front=new bspnode;
		buildbsp(tree->front,frontlist);
	}
	if (backlist.empty()==false)
	{
		tree->back=new bspnode;
		buildbsp(tree->back,backlist);
	}
}



tree::tree()
{
}

void tree::gen(int treeseed)
{
	
	srand(treeseed);

	//srand(GetTickCount());
	makecubetree(v3(0,0,0),v3(0,1,0),25,0.0715f,mainlist,0);

	Report3D("tree size %0.2f %0.2f %0.2f %d bigcubes\n",maxp.x-minp.x,maxp.y-minp.y,maxp.z-minp.z,numbigcubes);
	mulp.x = MAXX / (maxp.x-minp.x+0.1f);
	mulp.y = MAXY / (maxp.y-minp.y+0.1f);
	mulp.z = MAXZ / (maxp.z-minp.z+0.1f);
	
	linetest.primtype = D3DPT_LINELIST;


	char fname[512];
	sprintf(fname,"tree%d.precalc",treeseed);

	FILE *f=1 ? fopen(fname,"rb") : NULL;
	if (f)
	{
		fread(&numvines,1,4,f);
		for (vine=0;vine<numvines;vine++)
		{
			int sz;
			fread(&sz,1,4,f);
			vinepath[vine].resize(sz);
			fread(&*vinepath[vine].begin(),sizeof(v3),sz,f);
		}
	}
	else
	{
	
	
#define NSUBN 8
		FILE *f=fopen(fname,"wb") ;
		numvines=50;
		fwrite(&numvines,1,4,f);
		for (vine =0; vine<numvines;vine++)
		{
			vinepath[vine].clear();

			v3 p(Random(minp.x,maxp.x)/2,0,Random(minp.z,maxp.z)/2);
			//p=v3(0,0,0.01f);
			v3 d=-p;
			//int lastpoint = linetest.AddVertex(p,0xffff0000);
			vinepath[vine].push_back(p);
			vinet=0;
			Report3D("vine %d\n",vine);
			int downcount=0;
			int vinedir = 0;
			for (int n=0;n<400;n++)
			{
				int xcol;
				for (int subn=0;subn<NSUBN;subn++)
				{
				
					if (d.y==0) d.y=0.01f;
					d=Normalize(d);
					
					p+=d/float(NSUBN);

					if (vinedir)
					{
						if (d.y>-0.2f)
						{
							downcount++;
						}
						else downcount-=2;
					}
					else
					{
					
						if (d.y<0.2f)
						{
							downcount++;
						}
						else downcount-=2;
					}
					if (downcount<0) downcount=0;
					if (downcount>8*4) 
					{
						vinedir=1-vinedir;
						downcount=0;
						if (!vinedir) break;
					}
					
					float bestd=1000;
					v3 *nearest = findnearestpoint(p,bestd);

#define BIGTHRESH 4.f
#define SMALLTHRESH 2.f
#define MINY 10.f

					d*=0.1f;
					float wibamount = 1.0f;
					if (p.y < MINY && vinedir)
					{

						v3 d2 = Normalize(p - v3(0,0,0));
						
						d+=d2;
						d.y = (-p.y/MINY) * 2;
						wibamount=1;
						d.y+=vinedir ? -wibamount : wibamount;
					}
					else
					if (nearest==NULL || bestd > BIGTHRESH)
					{
						// head towards 0
						d+= Normalize(v3(0,0,0) - p);

						wibamount=1;

						d.y+=vinedir ? -wibamount : wibamount;

						xcol=0xffff00ff;

					}
					else 
					{
						v3 grad = Normalize(getgrad(p, nearest));
						v3 tang = Normalize(d - grad * DotProduct(grad,d));

						if (bestd >= SMALLTHRESH)
						{
							float fac = (bestd-SMALLTHRESH)/(BIGTHRESH-SMALLTHRESH);
							d+= (1-fac)*tang - (fac)*grad;							
							wibamount *= (1-fac);
							
							d.y+=vinedir ? -wibamount*2 : wibamount*2;

							xcol=0xffff0000;
						}
						else
						{
							float fac = (bestd)/(SMALLTHRESH);
							fac=fac*fac*0.2f;
							d+= fac*tang + (1-fac)*grad;

							wibamount *= (1-fac);
							

							xcol=0xff00ff00;
						}
					}
#define WIBAM 2
#define WIBSCALE 4.f
					d.x+=WIBAM *(wibamount * Perlin::Noise3o(p.x/WIBSCALE+vine*20,p.y/WIBSCALE-vinet,p.z/WIBSCALE+vinet*0.1f) ); // plus some noise
					d.y+=WIBAM *(wibamount * Perlin::Noise3o(p.y/WIBSCALE+vine*20,p.z/WIBSCALE-vinet,p.x/WIBSCALE+vinet*0.1f) ); // plus some noise
					d.z+=WIBAM *(wibamount * Perlin::Noise3o(p.z/WIBSCALE+vine*20,p.x/WIBSCALE-vinet,p.y/WIBSCALE+vinet*0.1f) ); // plus some noise					
					vinet+=0.01f;
				}

				if (subn!=NSUBN) break;
				
				//int npoint = linetest.AddVertex(p,xcol);
				//linetest.AddLine(lastpoint,npoint);
				vinepath[vine].push_back(p);

				if ((n%10)==0) Report3D(".");
				
				/*
				if ((n%3)==0)
				{
					float ff;
					v3 *nearest = findnearestpoint(p,ff);
					if (nearest) 
					{
						
						int opoint=linetest.AddVertex(*nearest,0xff000000);
						linetest.AddLine(npoint,opoint);
					}
					
				}
				*/

				//lastpoint=npoint;
				//Report3D("%0.2f\n",p.y);
			}
		}
		// sort by max min distance
		for (vine=1;vine<numvines;vine++)
		{
			int bestvine=1;
			float bestmaxd=-1;
			for (int tvine=vine;tvine<numvines;tvine++)
			{
				float mind=-1;
				for (int svine=0;svine<vine;svine++)
				{
					float d=LengthSquared(vinepath[svine][0]-vinepath[tvine][0]);
					if (d<mind || mind<0)
					{
						mind=d;
					}
				}
				if (mind>bestmaxd)
				{
					bestmaxd=mind;
					bestvine=tvine;
				}
			}
			PointList t;
			t=vinepath[tvine];vinepath[tvine]=vinepath[bestvine];vinepath[bestvine]=t;
		}
		
		// save
		for (vine=0;vine<numvines;vine++)
		{
			int sz=vinepath[vine].size();
			fwrite(&sz,1,4,f);				
			fwrite(&*vinepath[vine].begin(),sizeof(v3),sz,f);
		}

	} // vine precalc

	// prune
	numvines--;
	for (int c1=0;c1<numvines;c1++)
	{
		for (int c2=0;c2<vinepath[c1].size();c2++)
		{

			v3 p=vinepath[c1][c2];
			float bestd;
			v3 *nearest = findnearestpoint(p,bestd);

			bestd=nearest ? LengthSquared(*nearest - p) : 10;

			if (bestd>50.f)
			{
				vinepath[c1].resize(c2);
				break;
			}

		}
		vinesize[c1]=Random(c1<2 ? 0.6f : 0.1f, c1<2 ? 1.2f : 1.f);
		float f= GaussRandom(0.6f,1.2f);
		int fff=bound(0,f*255,255);
		vinecol[c1]=INTERP(0xff000000,0xffffffff,fff);
	}


	// find the right vine

	
	thevine=numvines-1;
	int bestl=0;
	for (c1=0;c1<numvines;c1++)
	{
		if (vinepath[c1].size() >= bestl)
		{
			bestl=vinepath[c1].size();
			thevine=c1;
		}
	}
	int maxl=bestl;
	bestl=0;
	float bestd=0;
	for (c1=0;c1<numvines;c1++)
	{
		Report3D("sorting vine %d\n",c1);
		if (vinepath[c1].size() >= bestl * 0.6f && vinepath[c1].size() <= maxl)
		{
			float totd=0;
			for (int c2=0;c2<vinepath[c1].size();c2++)
			{

				v3 p=vinepath[c1][c2];
				float bestd;
				v3 *nearest = findnearestpoint(p,bestd);

				bestd=nearest ? LengthSquared(*nearest - p) : 10;
				bestd-=2.7f; // 3 works well
				bestd=(bestd*bestd);
				totd+=bestd;
			}
			totd/=vinepath[c1].size();

			if (totd < bestd || bestd==0)
			{					
				bestl=vinepath[c1].size();
				bestd=totd;
				thevine=c1;
			}
		}
	}
	
	
	
	int tvine=4;
	PointList t;
	t=vinepath[tvine];vinepath[tvine]=vinepath[thevine];vinepath[thevine]=t;
	
	
	thevine=tvine;

	vinesize[thevine] = 0.5f;

	Report3D("sorting all\n");
	std::sort(mainlist.begin(),mainlist.end());

	srand(GetTickCount());

	Report3D("done\n");
}

int tree::drawtree(float frac, float lighting, int alpha, int shadow)
{
	
						
	for (int c1=0;c1<mainlist.size() * frac;c1++) 
	{
		int numv=mainlist[c1].p.size();
		float dot = DotProduct(mainlist[c1].plane,v4(0.707f,0.707f,0.3f,0));
		dot=dot*dot*dot;
		dot=dot*dot*dot*lighting;
		if (dot<0) dot=0;
		if (dot>1) dot=1;
		int idot = dot*255;
		int col=(alpha<<24) | (idot) | (idot<<8) | (idot<<16);

		if (shadow)
		{
			
			v3 p0 = mainlist[c1].p[0]; ShadowProject(p0,true);
			v3 p1 = mainlist[c1].p[1]; ShadowProject(p1,true);		
			int v0=blah2d.AddVertex(p0,	 col);
			int v1=blah2d.AddVertex(p1,col);
			for (int c2=2;c2<numv;c2++)
			{
				
				v3 p2 = mainlist[c1].p[c2]; ShadowProject(p2,true);
				int v2=blah2d.AddVertex(p2,col);
				blah2d.AddTri(v0,v1,v2);
				v1=v2;
			}		
			blah2d.Flush();
		}
		else
		{
		
			int v0=blah.AddVertex(mainlist[c1].p[0],	 col);
			int v1=blah.AddVertex(mainlist[c1].p[1],col);
			for (int c2=2;c2<numv;c2++)
			{
				int v2=blah.AddVertex(mainlist[c1].p[c2],col);
				blah.AddTri(v0,v1,v2);
				v1=v2;
			}		
			blah.Flush();
		}
	}
	if (shadow) blah2d.Draw();
		else blah.Draw();

	
	return 0;
}
