UINT cagdAddPoint(const CCagdPoint *where)
{
  UINT id = findUnused();
  SEGMENT *segment = &list[id];
  segment->type = CAGD_SEGMENT_POINT;
  segment->visible = TRUE;
  memcpy(segment->color, color, sizeof(GLubyte) * 3);
  segment->where = (CCagdPoint *)malloc(sizeof(CCagdPoint));
  *segment->where = *where;
  segment->length = 1;
  return id;
}
UINT cagdAddPolyline(const CCagdPoint *where, UINT length, UINT type)
{
  UINT id = findUnused();
  SEGMENT *segment = &list[id];
  if(length < 2)
    return 0;
  segment->type = type;
  segment->visible = TRUE;
  memcpy(segment->color, color, sizeof(GLubyte) * 3);
  segment->where = (CCagdPoint *)malloc(sizeof(CCagdPoint) * length);
  memcpy(segment->where, where, sizeof(CCagdPoint) * length);
  segment->length = length;
  return id;
}
UINT cagdAddText(const CCagdPoint *where, PCSTR text)
{
  UINT id = findUnused();
  SEGMENT *segment = &list[id];
  if(!text)
    return 0;
  segment->type = CAGD_SEGMENT_TEXT;
  segment->visible = TRUE;
  memcpy(segment->color, color, sizeof(GLubyte) * 3);
  segment->where = (CCagdPoint *)malloc(sizeof(CCagdPoint));
  *segment->where = *where;
  if (!text)
	  text = "";
  segment->text = _strdup(text);
  segment->length = strlen(text);
  return id;
}
static UINT findUnused()
{
  UINT id;
  for(id = 1; id < nSegments; id++)
    if(list[id].type == CAGD_SEGMENT_UNUSED)
      break;
  if(nSegments <= id){
    list = (SEGMENT*)realloc(list, sizeof(SEGMENT) * (nSegments += 20));
    for(id = nSegments - 20; id < nSegments; id++){
      SEGMENT *segment = &list[id];	
      segment->type = CAGD_SEGMENT_UNUSED;
      segment->visible = FALSE;
      segment->length = 0;
      segment->text = NULL;
      segment->where = NULL;
    }
    return findUnused();
  }
  return id;
}
/* Update the particle animation and draw the particles */
void DragonBreath::draw(glm::mat4 ProjectionMatrix, glm::mat4 ViewMatrix, glm::vec3 modelpos, glm::vec3 modelrotation, glm::vec3 positionFix)
{
	double currentTime = glfwGetTime();
	double delta = currentTime - lastTime;
	lastTime = currentTime;

	if (loc != -1)
	{
		glUniform1f(loc, false);
	}
	if (loc2 != -1)
	{
		glUniform1f(loc2, false);
	}

	glBindVertexArray(ID.VertexArray);

	// We will need the camera's position in order to sort the particles
	// w.r.t the camera's distance
	glm::vec3 CameraPosition(glm::inverse(ViewMatrix)[3]);
	glm::mat4 ViewProjectionMatrix = ProjectionMatrix * ViewMatrix;

	// Generate 10 new particule each millisecond,
	// but limit this to 16 ms (60 fps), or if you have 1 long frame (1sec),
	// newparticles will be huge and the next frame even longer.
	int newparticles = (int)(delta*1000.0);
	if (newparticles > (int)(0.016f*1000.0))
		newparticles = (int)(0.016f*1000.0);

	for (int i = 0; i<newparticles; i++){
		int particleIndex = findUnused();
		ParticlesContainer[particleIndex].life = 2.0f; // This particle will live 5 seconds.
		ParticlesContainer[particleIndex].pos = modelpos + positionFix;

		float spread = 2.5f;
		glm::vec3 maindir = modelrotation;
		// Very bad way to generate a random direction; 
		// See for instance http://stackoverflow.com/questions/5408276/python-uniform-spherical-distribution instead,
		// combined with some user-controlled parameters (main direction, spread, etc)
		glm::vec3 randomdir = glm::vec3(
			(rand() % 2000 - 1000.0f) / 1000.0f,
			(rand() % 2000 - 1000.0f) / 1000.0f,
			(rand() % 2000 - 1000.0f) / 1000.0f
			);

		ParticlesContainer[particleIndex].speed = maindir + randomdir*spread;

		// Very bad way to generate a random color
		ParticlesContainer[particleIndex].colour.r = 0;
		ParticlesContainer[particleIndex].colour.g = 0;
		ParticlesContainer[particleIndex].colour.b = 1;
		ParticlesContainer[particleIndex].colour.a = (rand() % 256) / 3;

		ParticlesContainer[particleIndex].size = 0.1;
	}

	// Simulate all particles
	int ParticlesCount = 0;
	for (int i = 0; i<MaxParticles; i++){

		Spark& p = ParticlesContainer[i]; // shortcut

		if (p.life > 0.0f){

			// Decrease life
			p.life -= delta;
			if (p.life > 0.0f){

				// Simulate simple physics : gravity only, no collisions
				p.speed += glm::vec3(0.0f, -0.1f, 0.0f) * (float)delta * 0.1f;
				p.pos += p.speed * (float)delta;
				p.cameradistance = glm::length2(p.pos - CameraPosition);
				//ParticlesContainer[i].pos += glm::vec3(0.0f,10.0f, 0.0f) * (float)delta;

				// Fill the GPU buffer
				g_particule_position_size_data[4 * ParticlesCount + 0] = p.pos.x;
				g_particule_position_size_data[4 * ParticlesCount + 1] = p.pos.y;
				g_particule_position_size_data[4 * ParticlesCount + 2] = p.pos.z;

				g_particule_position_size_data[4 * ParticlesCount + 3] = p.size;

				g_particule_color_data[4 * ParticlesCount + 0] = p.colour.r;
				g_particule_color_data[4 * ParticlesCount + 1] = p.colour.g;
				g_particule_color_data[4 * ParticlesCount + 2] = p.colour.b;
				g_particule_color_data[4 * ParticlesCount + 3] = p.colour.a;

			}
			else{
				// Particles that just died will be put at the end of the buffer in SortParticles();
				p.cameradistance = -1.0f;
			}

			ParticlesCount++;
		}
	}

	Sort();
	// Use our shader
	glUseProgram(ID.program);
	// Update the buffers that OpenGL uses for rendering.
	// There are much more sophisticated means to stream data from the CPU to the GPU, 
	// but this is outside the scope of this tutorial.
	// http://www.opengl.org/wiki/Buffer_Object_Streaming

	glBindBuffer(GL_ARRAY_BUFFER, buffer.position);
	glBufferData(GL_ARRAY_BUFFER, MaxParticles * 4 * sizeof(GLfloat), NULL, GL_STREAM_DRAW); // Buffer orphaning, a common way to improve streaming perf. See above link for details.
	glBufferSubData(GL_ARRAY_BUFFER, 0, ParticlesCount * sizeof(GLfloat) * 4, g_particule_position_size_data);

	glBindBuffer(GL_ARRAY_BUFFER, buffer.colour);
	glBufferData(GL_ARRAY_BUFFER, MaxParticles * 4 * sizeof(GLubyte), NULL, GL_STREAM_DRAW); // Buffer orphaning, a common way to improve streaming perf. See above link for details.
	glBufferSubData(GL_ARRAY_BUFFER, 0, ParticlesCount * sizeof(GLubyte) * 4, g_particule_color_data);

	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	

	if (ID.Texture != -1)
	{
		glUniform1f(ID.Texture, true);
	}

	// Bind our texture in Texture Unit 0
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, Texture);
	// Set our "myTextureSampler" sampler to user Texture Unit 0
	glUniform1i(ID.Texture, 0);

	// Same as the billboards tutorial
	glUniform3f(ID.CameraRight_worldspace, ViewMatrix[0][0], ViewMatrix[1][0], ViewMatrix[2][0]);
	glUniform3f(ID.CameraUp_worldspace, ViewMatrix[0][1], ViewMatrix[1][1], ViewMatrix[2][1]);

	glUniformMatrix4fv(ID.ViewProjMatrix, 1, GL_FALSE, &ViewProjectionMatrix[0][0]);

	// 1rst attribute buffer : vertices
	glEnableVertexAttribArray(0);
	glBindBuffer(GL_ARRAY_BUFFER, buffer.vertex);
	glVertexAttribPointer(
		0,                  // attribute. No particular reason for 0, but must match the layout in the shader.
		3,                  // size
		GL_FLOAT,           // type
		GL_FALSE,           // normalized?
		0,                  // stride
		(void*)0            // array buffer offset
		);

	// 2nd attribute buffer : positions of particles' centers
	glEnableVertexAttribArray(1);
	glBindBuffer(GL_ARRAY_BUFFER, buffer.position);
	glVertexAttribPointer(
		1,                                // attribute. No particular reason for 1, but must match the layout in the shader.
		4,                                // size : x + y + z + size => 4
		GL_FLOAT,                         // type
		GL_FALSE,                         // normalized?
		0,                                // stride
		(void*)0                          // array buffer offset
		);

	// 3rd attribute buffer : particles' colors
	glEnableVertexAttribArray(2);
	glBindBuffer(GL_ARRAY_BUFFER, buffer.colour);
	glVertexAttribPointer(
		2,                                // attribute. No particular reason for 1, but must match the layout in the shader.
		4,                                // size : r + g + b + a => 4
		GL_UNSIGNED_BYTE,                 // type
		GL_TRUE,                          // normalized?    *** YES, this means that the unsigned char[4] will be accessible with a vec4 (floats) in the shader ***
		0,                                // stride
		(void*)0                          // array buffer offset
		);

	glVertexAttribDivisor(0, 0); 
	glVertexAttribDivisor(1, 1); 
	glVertexAttribDivisor(2, 1); 

	glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, ParticlesCount);

	glVertexAttribDivisor(0, 0);
	glVertexAttribDivisor(1, 0);
	glVertexAttribDivisor(2, 0);
	glDisable(GL_TEXTURE_2D);
	glDisable(GL_BLEND);
}