#include "BaseParticleSystem.h"

BaseParticleSystem::BaseParticleSystem(dReal posx, dReal posy, dReal posz, int size, std::string file)
: Base3DObject(false, false, "", "", posx, posy, posz)
{
	//origin[0] = 0;
	//origin[1] = 0;
	//origin[2] = 0;
	force[0] = 0;
	force[1] = -9.81;
	force[2] = 0;

	assert(size >= 1 && size <= 10);

	maxParticles = size*20;
	magnitude = size;
	//slowdown = 2;
	//zoom=-40.0;

	particleList = new particles[maxParticles];

	if (file == "")
	{
		imageFilename = "";
		usingTexture = false;
	}
	else
	{
		imageFilename = file;
		usingTexture = true;
	}
}

BaseParticleSystem::~BaseParticleSystem(void)
{
	delete [] particleList;

	//This now gets done externally so other systems can use the same display list.
//#ifdef USING_VRJUGGLER //using Juggler's special context-specific data types
//	glDeleteLists(1, *displayListID);
//#else //using normal data types
//	glDeleteLists(1, displayListID);
//#endif
}

void BaseParticleSystem::KillSystem(void)
{
	for (int loop=0;loop<maxParticles;loop++)			// Initials All The Textures
	{
		particleList[loop].active=false;				// Make All The Particles not Active
	}
}

bool BaseParticleSystem::SystemIsActive()
{
	for (int loop=0;loop<maxParticles;loop++)
	{
		if(particleList[loop].active==true)
		{
			return true;
		}
	}

	return false;
}

void BaseParticleSystem::MakeDisplayList()
{
	if (!usingTexture)
	{
		return;
	}

#ifdef USING_VRJUGGLER //using Juggler's special context-specific data type
	*textureID = CreateTexture(imageFilename);
	(*displayListID) = glGenLists(1);
	glNewList(*displayListID,GL_COMPILE);
#else //using normal data types
	textureID = CreateTexture(imageFilename);
	displayListID = glGenLists(1);
	glNewList(displayListID,GL_COMPILE);
#endif

	//glDisable(GL_DEPTH_TEST);
	glDepthMask(GL_FALSE);
	glEnable(GL_BLEND);
	glEnable(GL_TEXTURE_2D);
	//glDisable(GL_LIGHTING);
	glDisable(GL_CULL_FACE); //draw both sides
	glDisable(GL_FOG); //Fog messes up the color of the particles
	//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	//glBlendFunc(GL_SRC_ALPHA,GL_DST_ALPHA);
	glBlendFunc(GL_SRC_ALPHA,GL_ONE);

#ifdef USING_VRJUGGLER //using Juggler's special context-specific data type
	glBindTexture(GL_TEXTURE_2D, *textureID);
#else //using normal data types
	glBindTexture(GL_TEXTURE_2D, textureID);
#endif

	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
	glBegin(GL_QUADS);
		glTexCoord2f(0.0, 1.0);
		glVertex3f(-0.5, 0.5, 0.0);
		glTexCoord2f(1.0, 1.0);
		glVertex3f(0.5, 0.5, 0.0);
		glTexCoord2f(1.0, 0.0);
		glVertex3f(0.5, -0.5, 0.0);
		glTexCoord2f(0.0, 0.0);
		glVertex3f(-0.5, -0.5, 0.0);
	glEnd();

	glEnable(GL_FOG);
	glDisable(GL_BLEND);
	glDisable(GL_TEXTURE_2D);
	//glEnable(GL_LIGHTING);
	//glEnable(GL_DEPTH_TEST);
	glDepthMask(GL_TRUE);
	glEnable(GL_CULL_FACE);

	glEndList();
}

//	// Context-Specific Data -> handle differently in VRJuggler
//#ifdef USING_VRJUGGLER //using Juggler's special context-specific data types
//vrj::GlContextData<GLuint> BaseParticleSystem::GetDisplayList()
//{
//	return (*displayListID);
//}
//
//void BaseParticleSystem::SetDisplayList(vrj::GlContextData<GLuint> newDisplayListID)
//{
//	*displayListID = newDisplayListID;
//}
//#else //using normal data types
//GLuint BaseParticleSystem::GetDisplayList()
//{
//	return displayListID;
//}
//
//void BaseParticleSystem::SetDisplayList(GLuint newDisplayListID)
//{
//	displayListID = newDisplayListID;
//}
//#endif

GLuint BaseParticleSystem::CreateTexture(std::string file)
{
	GLuint newTextureID;
	
	if(file == "")
	{
		std::cout << "No image filename given." << std::endl;
		std::cout << "Quitting..." << std::endl;
		exit(0);
	}
	
	corona::Image* image = corona::OpenImage(file.c_str(), corona::PF_R8G8B8);

	if (!image)
	{
		std::cout << "Error loading image file: " << file << std::endl;
		std::cout << "Quitting..." << std::endl;
		exit(0);
	}

	//since texture coordinates are upside-down in the build list function...
	image = corona::FlipImage(image, corona::CA_X);

	// Generate a texture
	glGenTextures(1, &newTextureID);

	// This sets the alignment requirements for the start of each pixel row in memory.
	glPixelStorei (GL_UNPACK_ALIGNMENT, 1);

	// Bind the texture to newTextureID
	glBindTexture(GL_TEXTURE_2D, newTextureID);

	// Build Mipmaps (builds different versions of the picture for distances - looks better)
	gluBuild2DMipmaps(GL_TEXTURE_2D, 3, image->getWidth(), image->getHeight(), GL_RGB, GL_UNSIGNED_BYTE, image->getPixels());

	// Lastly, we need to tell OpenGL the quality of our texture map.  GL_LINEAR_MIPMAP_LINEAR
	// is the smoothest.  GL_LINEAR_MIPMAP_NEAREST is faster than GL_LINEAR_MIPMAP_LINEAR, 
	// but looks blochy and pixilated.  Good for slower computers though. 
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR_MIPMAP_LINEAR);	

	// The default GL_TEXTURE_WRAP_S and ""_WRAP_T property is GL_REPEAT.
	// We need to turn this to GL_CLAMP_TO_EDGE, otherwise it creates ugly seems
	// in our sky box.  GL_CLAMP_TO_EDGE does not repeat when bound to an object.
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

	// Now we need to free the image data that we loaded since OpenGL stored it as a texture
	delete image;

	return newTextureID;
}