#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
#include <stdlib.h>
#include <math.h>
#include "pointcloud.h"

void changeDestiny(PointCloud pc, double param1, double param2){
   int i = 0;
   double theta, phi, r;

   for(theta = 0.0; theta < 2.0 * M_PI; theta += 0.01){
      for(phi = 0.0; phi < M_PI; phi += 0.01){
         r = 2.0 + (sin(phi * param1) / param2);
         pc.destiny[i++] = r * cos(theta) * sin(phi);
         pc.destiny[i++] = r * sin(theta) * sin(phi);
         pc.destiny[i++] = r * cos(phi);
      }
   }

}

PointCloud createPC(int numofpc, double time){
   PointCloud pc;
   int i;

   pc.vbo         = malloc(sizeof(GLuint)  * PC_VBONUM);
   pc.destiny     = malloc(sizeof(GLfloat) * numofpc * 3);
   pc.birth       = malloc(sizeof(GLfloat) * numofpc);
   pc.percentages = malloc(sizeof(GLfloat) * numofpc);
   pc.rand        = malloc(sizeof(GLfloat) * numofpc);
   pc.pcnum       = numofpc;

   for(i = 0; i < numofpc; i++){
      pc.rand[i] = drand48() / 10.0;
      pc.birth[i] = time - (PC_DEATHTIME * drand48());
   }

   changeDestiny(pc, 10.0, 2.0);

   glGenVertexArrays(1, &pc.vao);
   glBindVertexArray(pc.vao);
   glGenBuffers(PC_VBONUM, pc.vbo);

   glBindBuffer(GL_ARRAY_BUFFER, pc.vbo[0]);
   glBufferData(GL_ARRAY_BUFFER, sizeof(GL_FLOAT) * numofpc * 3, pc.destiny, GL_DYNAMIC_DRAW);
   glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
   glEnableVertexAttribArray(0);

   glBindBuffer(GL_ARRAY_BUFFER, pc.vbo[1]);
   glBufferData(GL_ARRAY_BUFFER, sizeof(GL_FLOAT) * numofpc, pc.percentages, GL_DYNAMIC_DRAW);
   glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, 0);
   glEnableVertexAttribArray(1);

   return(pc);
}

void freePC(PointCloud pc){
   glDeleteBuffers(PC_VBONUM, pc.vbo);
   glDeleteVertexArrays(1, &pc.vao);

   free(pc.destiny);
   free(pc.birth);
   free(pc.percentages);
   free(pc.rand);
   free(pc.vbo);
}

void updatePC(PointCloud pc, double time, int reborn){
   int i;

   glBindBuffer(GL_ARRAY_BUFFER, pc.vbo[1]);
   pc.percentages = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);

   /* Calculate new positions */
   for(i = 0; i < pc.pcnum; i++){
      pc.percentages[i] = (time - pc.birth[i]) / PC_DEATHTIME;
      /* Dead particle. Need reborn */
      if( (pc.percentages[i] + pc.rand[i]) > 1.0 && reborn){
         pc.birth[i] = time;
         pc.percentages[i] = 0.0;
      }
   }

   glUnmapBuffer(GL_ARRAY_BUFFER);
   glBindBuffer(GL_ARRAY_BUFFER, 0);
}

/* Drawing without shaders */
void drawPC(PointCloud pc){
   glBindVertexArray(pc.vao);
   glDrawArrays(GL_POINTS, 0, pc.pcnum);
}
