#include <GL/glut.h>
#include <stdio.h> 
#include <stdlib.h>
#include <time.h>
#include <assert.h>
#include <string.h>
#include <pthread.h>
#include "gltypes.h"
#include <math.h>
#include <sched.h>
#include <unistd.h>

#define MAX 100
#define dt 0.003
int pt_cnt = 0, shape_cnt = 0;

struct point pt_arr[MAX];
struct shape shape_arr[MAX];

int pop_point(){
	pt_cnt --;
	if(pt_cnt<0) pt_cnt=0;
}
int pop_shape(){
	shape_cnt --;
	if(shape_cnt<0) shape_cnt=0;
}
int add_point(struct point pt){
  pt_arr[pt_cnt] = pt;
  pt_cnt ++;
  assert(pt_cnt < MAX);
  return 0;
}

int add_shape(struct shape shp){
  shape_arr[shape_cnt] = shp;
  shape_cnt ++;
  assert(shape_cnt < MAX);
  return 0;
}

int display_points(){
  int i;
  glPointSize(5);
  glBegin(GL_POINTS);
  for(i = 0; i < pt_cnt; i++){
	glColor3d(pt_arr[i].r, pt_arr[i].g, pt_arr[i].b);
    glVertex2f(pt_arr[i].x, pt_arr[i].y); 
  }
  glEnd();
  for(i = 0; i < pt_cnt; i++){
	pt_arr[i].x+=dt*pt_arr[i].vx;
	pt_arr[i].y+=dt*pt_arr[i].vy;
	if(pt_arr[i].x>1||pt_arr[i].x<-1)pt_arr[i].vx=-pt_arr[i].vx;
	if(pt_arr[i].y>1||pt_arr[i].y<-1)pt_arr[i].vy=-pt_arr[i].vy;
  }
  return 0;
}

#define c(x) cos((x)/180.*M_PI+shp.theta)
#define s(x) sin((x)/180.*M_PI+shp.theta)
int display_shapes(){
  int i;
  glBegin(GL_QUADS);
  for(i = 0; i < shape_cnt; i++){
    struct shape shp = shape_arr[i];
	glColor3d(shp.r, shp.g, shp.b);
    glVertex2f(shp.x + shp.size/2 * c(45.), shp.y + shp.size/2*s(45.));
    glVertex2f(shp.x + shp.size/2 * c(135.), shp.y + shp.size/2*s(135.));
    glVertex2f(shp.x + shp.size/2 * c(225.) , shp.y + shp.size/2*s(225.));
    glVertex2f(shp.x + shp.size/2 * c(315.), shp.y + shp.size/2*s(315.));
  }
  for(i = 0; i < shape_cnt; i++){
    struct shape *shp = &shape_arr[i];
	shp->x+=dt*shp->vx;
	shp->y+=dt*shp->vy;
	shp->theta+=dt*shp->omega;
	if(shp->x>1||shp->x<-1)shp->vx=-shp->vx;
	if(shp->y>1||shp->y<-1)shp->vy=-shp->vy;
  }
  glEnd();
  return 0;
}

int display(){
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glColor3f(0.0f, 0.0f, 0.0f);
  display_points();
  display_shapes();
  glutSwapBuffers();
  return 0;
}

int keyboard (unsigned char key, int x, int y){
	switch(key){
		case 27:
			exit(0);
			break;
		case 'q':
			exit(0);
			break;
	}
}
void* run_func(void* args){
  glutDisplayFunc(display);
  glutIdleFunc(display);
  glutKeyboardFunc(keyboard);
  glutMainLoop();
  return NULL;
}

int setup() {
  char *prog_name = "draw";
  int argc = 1;

  memset((void*)pt_arr, 0, sizeof(struct point)*MAX);
  memset((void*)shape_arr, 0, sizeof(struct point)*MAX);

  glutInit(&argc, &prog_name);
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
  glutInitWindowSize(500, 500);
  glutInitWindowPosition(200, 200);
  glutCreateWindow("sample draw");
  glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
  pthread_t th;
  pthread_create(&th,NULL,run_func,NULL);
  printf("Entering opengl mainloop...\n");
  printf("Press ESC to exit...\n");
  return 0;
}
int run(){
	return 0;
}
int wait(double seconds){
	unsigned int t=0;
	if(seconds<=0.)
		t=10000000000;
	else
		t=seconds*1000000.;
	usleep(t);
	return 0;
}
int byebye(){
	printf("Exiting in 3...\n");
	wait(1.0);
	printf("Exiting in 2...\n");
	wait(1.0);
	printf("Exiting in 1...\n");
	wait(1.0);
	exit(0);
}
