module br.particleImpl;

private import opengl;
private import std.math;
private import util.particle;
private import br.gamemanager;
private import util.parts;
private import util.vector;
private import util.shape;
private import util.matrix;
private import util.log;
public class ParticleImpl:Particle{
	
	public void draw(){
		
//		glDisable(GL_BLEND);
		//glLoadIdentity();
//		double size = 10.0;
//		Matrix rpose = poseBase;
		
		//		Matrix drawpose = rpose
		//Matrix p = matRotateX(rposeX) * matRotateY(rposeY) * matRotateZ(rposeZ) * matScale(size * scaleX ,size * scaleY ,size * scaleZ) * poseBase;
		
		
		glTranslatef(pos.x ,pos.y ,pos.z);
		glScaled(size ,size ,size);
		glRotated(pose ,poseX ,poseY ,poseZ);
		
		if(shape !is null && (1e-6) < size){
		
//			shape.transformMatrix(rpose);
			
			
			
			
			Vector3[] av = shape.v;
			

			glEnable(GL_BLEND);
//			glEnable(GL_POLYGON_SMOOTH);
			
			Vector3 ave;
			if(drawing & Parts.POLYGON){
				polygon[] pr = shape.polygons;
				for(int i = 0; i < pr.length ;i ++){
					Vector3 normal = shape.polygons[i].normal;
					glBegin(GL_POLYGON);
					
						ave = new Vector3((av[pr[i].v[0]] + av[pr[i].v[1]] + av[pr[i].v[2]]) / 3.0);
						double a = fmax(0.0,(1.0 + (pos.z + ave.z) / 1600.0) * alpha);
//						glColor3d((R - bg.R)*a+bg.R ,(G - bg.G)*a+bg.G  ,(B - bg.B)*a + bg.B );
						glColor4d(R  ,G  ,B ,a);
					//glColor4d(R ,G ,B ,fmax(0.0,(1.0 + (pos.z + ave.z) / 1600.0) * alpha)); //glColor4f(1.0f ,1.0f ,1.0f,(1.0 + (pos.z + ave.z) / 1600.0) * 0.6);
					for(int j = 0;j < 3 ;j ++){
						glVertex3f(av[pr[i].v[j]].x,av[pr[i].v[j]].y,av[pr[i].v[j]].z);
					}
					
					glEnd();
				}
			}
			
			
			glEnable(GL_BLEND);
			glEnable(GL_LINE_SMOOTH);
			if(drawing & Parts.WIRE){
				
				
				int[][] wires = shape.wires;
				
//				double a = fmin(1.0 ,fmax(0.0 ,alpha));
				for(int i = 0; i < wires.length ;i ++){
//					glColor3d(R * a ,G * a ,B * a);
//					glColor4d(R ,G ,B ,fmax(0.0,alpha));
					
					
					

					glBegin(GL_LINE_STRIP);
					
					glVertex3f(0 ,0,0);
					glVertex3f(0 ,0,0);
					
					
					glColor4d(wR ,wG ,wB ,fmax(0.0,alpha));
					
		   			for(int j = 0; j < wires[i].length;j ++){
//						double a = alpha * fmax(0.0,(1.0 + (pos.z + av[wires[i][j]].z + 600.0) / 1200.0));
//						glColor4d(R ,G ,B ,fmax(0.0,a));

	 	  	 			glVertex3f(av[wires[i][j]].x ,av[wires[i][j]].y ,av[wires[i][j]].z);


						//glVertex3f(av[wires[i][j + 1]].x ,av[wires[i][j + 1]].y ,av[wires[i][j + 1]].z);
	  	  			}
					
					
					
					glEnd();
					
					
				
				}
				
			}
			
			
			
			glDisable(GL_LINE_SMOOTH);
			glDisable(GL_BLEND);
			
//			shape.resetVertex();
			
			
		}
		
		
//		drawn = true;
	}
	
	
	
	
}

public void makeParticle(Shape shape, double size, ubyte drawing, Vector3 pos ,Vector3 vel ,Matrix rpose ,double R ,double G ,double B ,double wR,double wG,double wB ,double alpha ,float speed = 5.0f){
	if(shape !is null){
		foreach(r;shape.polygons){
			Vector3[] v;
			int[][] wires;
			polygon[] polygons;
			v.length = r.v.length;
			for(int i=0;i<v.length;i++){v[i]=shape.v[r.v[i]];}
			wires.length = 1;
			wires[0].length = r.v.length + 1;
			for(int i=0;i<wires[0].length;i++){
				if(i == wires[0].length-1)wires[0][i]=0;
				else wires[0][i]=i;
			}
			polygons.length = 1;
			for(int i=0;i<polygons[0].v.length;i++){polygons[0].v[i]=i;}
			
			Vector3 average = new Vector3();
			
			foreach(Vector3 vec;v){
				average += vec;
			}
			
			average = average / cast(double)v.length;
			
			foreach(inout Vector3 vec;v){
				vec = vec - average;
			}
			
			Vector3 rpos = pos + vec3translate(average , rpose);
			
			Shape s = new Shape(v ,wires ,polygons);
			Vector3 velocity = vec3Normalize(average) * speed + vel;
			
//			new Particle_old(s ,1.0 ,drawing ,rpos ,velocity ,rpose  ,R ,G ,B ,alpha);
			ParticleImpl p = particleManager.getInstance;
			if(p !is null)p.set(s ,size ,drawing ,rpos ,velocity ,rpose ,R ,G ,B ,wR,wG,wB,alpha);
			//new Particle(s ,size ,drawing ,rpos ,velocity ,poseBase ,poseX ,poseY ,poseZ ,R ,G ,B ,alpha);
		}
	}
}
private Shape simpleParticleShape;
public void makeSimpleParticle(int num ,double size, ubyte drawing, Vector3 pos ,double R ,double G ,double B  ,double wR,double wG,double wB,double alpha){
	if(simpleParticleShape is null){
		Vector3[] v;
		int[][] wires;
		polygon[] polygons;
		v.length = 3;
//		v[0] = new Vector3(0.7 ,0.0 ,0.0);
		v[0] = new Vector3(0.7 ,-0.0 ,0.0);
		v[1] = new Vector3(-0.7 ,-0.5 ,0.0);
		v[2] = new Vector3(-0.7 ,0.5 ,0.0);
		
		wires.length = 1;
		wires[0].length = 4;
		wires[0][0] = 0;wires[0][1] = 1;wires[0][2] = 2;wires[0][3] = 0;//wires[0][4] =0;
		
		polygons.length = 1;
		polygons[0].v[0]=0;polygons[0].v[1]=1;polygons[0].v[2]=2;//rects[0].v[3]=3;
		simpleParticleShape = new Shape(v ,wires ,polygons);
	}
	
	Shape s = cast(Shape)simpleParticleShape.clone();
	for(int i=0;i<num;i++){
		
		ParticleImpl p = particleManager.getInstance;
		if(p !is null){
			Vector3 velocity = new Vector3(4.0 - rand.nextFloat(8.0) ,4.0 - rand.nextFloat(8.0) ,4.0 - rand.nextFloat(8.0) );
			double theta ,phi;
			theta = rand.nextFloat(360);
			phi = rand.nextFloat(180);
			p.set(s ,size ,drawing ,pos ,velocity ,matRotateX(theta)*matRotateY(phi) ,R ,G ,B ,wR,wG,wB,alpha);
		}
	}
	
}

public void makeParticleByShape(Shape shape, int num ,double size, ubyte drawing, Vector3 pos ,Vector3 vel  ,double R ,double G ,double B ,double wR,double wG,double wB,double alpha ,double speed = 4.0){
	
	Shape s = cast(Shape)shape.clone();
	for(int i=0;i<num;i++){
		
		ParticleImpl p = particleManager.getInstance;
		if(p !is null){
			Vector3 velocity = new Vector3(speed - rand.nextFloat(speed * 2.0) ,speed - rand.nextFloat(speed*2.0) ,speed - rand.nextFloat(speed*2.0) );
			double theta ,phi;
			theta = rand.nextFloat(360);
			phi = rand.nextFloat(180);
			p.set(s ,size ,drawing ,pos ,velocity ,matRotateX(theta)*matRotateY(phi) ,R ,G ,B ,wR,wG,wB,alpha);
		}
	}
	
}

public class ParticleImplManager{
	
	public:
	ParticleImpl[] particles;
	//List!(Parts) parts;
	protected:
	//List!(int) van = new List!(int)();
  int particleIdx = 0;
	const int maxParticle;
	public this() {
		maxParticle = 16;
		particles.length = maxParticle;
		foreach(inout ParticleImpl p;particles){
			p = new ParticleImpl();
		}
		//parts = new List!(Parts)();
		particleIdx = 0;
	}

  public this(int n) {
		maxParticle = n;
		particles.length = maxParticle;
		foreach(inout ParticleImpl p;particles){
			p = new ParticleImpl();
		}
		//parts = new List!(Parts)();
		particleIdx = 0;
  }
  public ParticleImpl getInstance(){
		
		for(int i = 0;i < particles.length;i ++){
			particleIdx ++;
			if(particles.length <= particleIdx)particleIdx = 0;
			if(!particles[particleIdx].exists()){
				return particles[particleIdx];
			}
			
		}
		
		return null;
		
		//if(maxParts <= parts.size)return false;
		//parts.push_back(p);
		
	}
	public void run() {
		
		for (int i = 0;i < particles.length;i ++){
			ParticleImpl an = particles[i];
			
    	  	if (an.exists){
				
        		an.move();
    	  	}
			
    	}
		  

   }
		
		
  public void draw() {
		
		for (int i = 0;i < particles.length;i ++){
			ParticleImpl an = particles[i];
			if (an.exists){
				glPushMatrix();
       			an.draw();
				glPopMatrix();
			}
		}
  }


  public void clear() {
		foreach(inout ParticleImpl a;particles){
			if(a !is null && a.exists){
				a.vanish();
			}
		}
   	//parts.length = 0;
    particleIdx = 0;
  }
}