#include <math.h>
#include <stdlib.h>
#include <sys/timeb.h>
#include <time.h>
#include <GL/glaux.h>
#include <GL/glut.h>
#include<conio.h>
#include <ode/ode.h>
#pragma comment(lib,"ode.lib")
#pragma comment(lib,"glaux.lib")


#define PI (double)3.14159265358979323846

#define graus(X) (double)(X)*180/PI
#define rad(X)   (double)(X)*PI/180

#define NUM_CUBOS       5

// ODE
dWorldID world;
dSpaceID space;
dJointGroupID contactgroup;
dGeomID groundGeom, envGeomGroup, ballGeom, cubesGeom[NUM_CUBOS];
dBodyID ballBody,cubesBody[NUM_CUBOS];

const double ERP = 0.6;
const double CFM = 0.2;
GLint groundExtents=100;
double raio=5, lado=8;

struct timeb tempo={-1,0,0,0};
double oldtime, newtime, last_fps_time;
int framecount;
float FPS, dt;
float time_per_fps_disp = CLOCKS_PER_SEC * .5;  /* .5 seconds */


// Teclas

typedef struct{
  GLboolean  a,
             q,
             o,
             p,
             f;
}Teclas;


Teclas keys={GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE};

// luzes e materiais

GLint L=1;

GLfloat g_pos_luz1[4] = {-5.0, 5.0, 5.0, 0.0};
GLfloat g_pos_luz2[4] = {5.0, 5.0, -5.0, 0.0};

const GLfloat red_light[] = {1.0, 0.0, 0.0, 1.0};
const GLfloat green_light[] = {0.0, 1.0, 0.0, 1.0};
const GLfloat blue_light[] = {0.0, 0.0, 1.0, 1.0};
const GLfloat white_light[] = {1.0, 1.0, 1.0, 1.0};

const GLfloat brass_ambient[] = {0.33, 0.22, 0.03, 1.0};
const GLfloat brass_diffuse[] = {0.78, 0.57, 0.11, 1.0};
const GLfloat brass_specular[] = {0.99, 0.91, 0.81, 1.0};
const GLfloat brass_shininess = 27.8;

const GLfloat red_plastic_ambient[] = {0.0, 0.0, 0.0};
const GLfloat red_plastic_diffuse[] = {0.5, 0.0, 0.0};
const GLfloat red_plastic_specular[] = {0.7, 0.6, 0.6};
const GLfloat red_plastic_shininess = 32.0;

const GLfloat emerald_ambient[] = {0.0215, 0.1745, 0.0215};
const GLfloat emerald_diffuse[] = {0.07568, 0.61424, 0.07568};
const GLfloat emerald_specular[] = {0.633, 0.727811, 0.633};
const GLfloat emerald_shininess = 76.8;

const GLfloat slate_ambient[] = {0.02, 0.02, 0.02};
const GLfloat slate_diffuse[] = {0.78, 0.78, 0.78};
const GLfloat slate_specular[] = {0.14, 0.14, 0.14};
const GLfloat slate_shininess = 18.78;

const GLfloat solido_azul_ambient[] = {0.0, 0.0, 0.1745};
const GLfloat solido_azul_diffuse[] = {0.0, 0.0,  0.61424};
const GLfloat solido_azul_specular[] = {0.0, 0.0, 0.727811};
const GLfloat solido_azul_shininess = 30.0;

const GLfloat material_preto_ambient[] = {0.02, 0.02, 0.02};
const GLfloat material_preto_diffuse[] = {0.08, 0.08, 0.08};
const GLfloat material_preto_specular[] = {0.03, 0.03, 0.03};
const GLfloat material_preto_shininess = 75.0;

const GLfloat material_cinza_ambient[] = {0.1745, 0.1745, 0.1745};
const GLfloat material_cinza_diffuse[] = {0.61424, 0.61424, 0.61424};
const GLfloat material_cinza_specular[] = {0.727811, 0.727811, 0.727811};
const GLfloat material_cinza_shininess = 60.0;

enum tipo_material {brass, slate, red_plastic, emerald, solido_azul, material_preto, material_cinza};

GLfloat escala=0.2;
int cor_cubo = brass;
GLfloat theta[] = { 0.0, 0.0, 0.0 };
GLboolean wireframe=GL_FALSE;
GLboolean texturas=GL_TRUE;
GLuint texture[10];
 

void material(enum tipo_material mat)
{
	switch (mat)
	{
		case brass:
			glMaterialfv(GL_FRONT, GL_AMBIENT, brass_ambient);
			glMaterialfv(GL_FRONT, GL_DIFFUSE, brass_diffuse);
			glMaterialfv(GL_FRONT, GL_SPECULAR, brass_specular);
			glMaterialf(GL_FRONT, GL_SHININESS, brass_shininess);
		break;
		case red_plastic:
			glMaterialfv(GL_FRONT, GL_AMBIENT, red_plastic_ambient);
			glMaterialfv(GL_FRONT, GL_DIFFUSE, red_plastic_diffuse);
			glMaterialfv(GL_FRONT, GL_SPECULAR, red_plastic_specular);
			glMaterialf(GL_FRONT, GL_SHININESS, red_plastic_shininess);
		break;
		case emerald:
			glMaterialfv(GL_FRONT, GL_AMBIENT, emerald_ambient);
			glMaterialfv(GL_FRONT, GL_DIFFUSE, emerald_diffuse);
			glMaterialfv(GL_FRONT, GL_SPECULAR, emerald_specular);
			glMaterialf(GL_FRONT, GL_SHININESS, emerald_shininess);
		break;
		case slate:
			glMaterialfv(GL_FRONT, GL_AMBIENT, slate_ambient);
			glMaterialfv(GL_FRONT, GL_DIFFUSE, slate_diffuse);
			glMaterialfv(GL_FRONT, GL_SPECULAR, slate_specular);
			glMaterialf(GL_FRONT, GL_SHININESS, slate_shininess);
		break;
		case solido_azul:
			glMaterialfv(GL_FRONT, GL_AMBIENT, solido_azul_ambient);
			glMaterialfv(GL_FRONT, GL_DIFFUSE, solido_azul_diffuse);
			glMaterialfv(GL_FRONT, GL_SPECULAR, solido_azul_specular);
			glMaterialf(GL_FRONT, GL_SHININESS, solido_azul_shininess);
		break;
		case material_preto:
			glMaterialfv(GL_FRONT, GL_AMBIENT, material_preto_ambient);
			glMaterialfv(GL_FRONT, GL_DIFFUSE, material_preto_diffuse);
			glMaterialfv(GL_FRONT, GL_SPECULAR, material_preto_specular);
			glMaterialf(GL_FRONT, GL_SHININESS, material_preto_shininess);
		break;
		case material_cinza:
			glMaterialfv(GL_FRONT, GL_AMBIENT, material_cinza_ambient);
			glMaterialfv(GL_FRONT, GL_DIFFUSE, material_cinza_diffuse);
			glMaterialfv(GL_FRONT, GL_SPECULAR, material_cinza_specular);
			glMaterialf(GL_FRONT, GL_SHININESS, material_cinza_shininess);
		break;
	}
}



void putLights(GLfloat* diffuse)
{
	glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
	glLightfv(GL_LIGHT0, GL_SPECULAR, white_light);
	glLightfv(GL_LIGHT0, GL_POSITION, g_pos_luz1);

	glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse);
	glLightfv(GL_LIGHT1, GL_SPECULAR, white_light);
	glLightfv(GL_LIGHT1, GL_POSITION, g_pos_luz2);

	/* desenhar luz */
    material(red_plastic);
	glPushMatrix();
		glTranslatef(g_pos_luz1[0], g_pos_luz1[1], g_pos_luz1[2]);
		glDisable(GL_LIGHTING);
		glColor3f(1.0, 1.0, 1.0);
		glutSolidCube(0.1);
		glEnable(GL_LIGHTING);
	glPopMatrix();
	glPushMatrix();
		glTranslatef(g_pos_luz2[0], g_pos_luz2[1], g_pos_luz2[2]);
		glDisable(GL_LIGHTING);
		glColor3f(1.0, 1.0, 1.0);
		glutSolidCube(0.1);
		glEnable(GL_LIGHTING);
	glPopMatrix();

	//glEnable(GL_LIGHT0);
	glEnable(GL_LIGHT1);
}

//Cálculo FPS
float delta_time ()
{
  oldtime = newtime;
  newtime = clock ();   /* for real use, this should be something like
                         * SDL_GetTicks() or something */
  framecount++;
  if ((newtime - last_fps_time) > time_per_fps_disp)
    {
      FPS = (CLOCKS_PER_SEC * framecount) / (newtime - last_fps_time);
      framecount = 0;
      last_fps_time = newtime;
    }
  return (newtime - oldtime) / CLOCKS_PER_SEC;
}


dReal calcStep()
{
  struct timeb tp;
  dReal ret=0;
  ftime(&tp);

  if(tempo.time!=-1)
  {
    ret=tp.time+tp.millitm/1000.0-(tempo.time+tempo.millitm/1000.0);
  }

  ret*=5;

  tempo=tp;
  return(ret);

}

void printMatrix(const dReal mat[])
{
  int i;
  for(i=0;i<16;i++)
  {
    if(i%4==0)
      printf("\n");
    printf("%f ",(float)mat[i]);
  }
      printf("\n");

}
void printVector(const dReal mat[])
{
  int i;
  for(i=0;i<3;i++)
  {
    printf("%f ",(float)mat[i]);
  }
  printf("\n");

}

void esfera(GLfloat raio, GLint seg, GLint fatias) {
	GLdouble alpha,teta;
	int      i,j;

  alpha = 2* M_PI / seg;
  teta = M_PI / fatias;

  if(texturas && !wireframe)
    glBindTexture(GL_TEXTURE_2D,texture[0]);

	glPushMatrix();
    for(j=0-fatias/2; j<fatias/2; j++)
		for(i=0; i<seg ;i++)
		{
				
			if (!wireframe)
			  glBegin(GL_POLYGON);
			else
			  glBegin(GL_LINE_LOOP);
				  glColor3f(1.0,0.0,0.0);
				  glTexCoord2f((1.0/seg)*(i+1),(1.0/fatias)*(j+fatias/2));
				  glNormal3f(cos(teta*j)*cos(alpha*(i+1))*raio,cos(teta*j)*sin(alpha*(i+1))*raio,sin(teta*j)*raio);
				  glVertex3f(cos(teta*j)*cos(alpha*(i+1))*raio,cos(teta*j)*sin(alpha*(i+1))*raio,sin(teta*j)*raio);

				  glTexCoord2f((1.0/seg)*(i+1),(1.0/fatias)*(j+fatias/2+1));
				  glNormal3f(cos(teta*(j+1))*cos(alpha*(i+1))*raio,cos(teta*(j+1))*sin(alpha*(i+1))*raio,sin(teta*(j+1))*raio);
				  glVertex3f(cos(teta*(j+1))*cos(alpha*(i+1))*raio,cos(teta*(j+1))*sin(alpha*(i+1))*raio,sin(teta*(j+1))*raio);

				  glTexCoord2f((1.0/seg)*(i),(1.0/fatias)*(j+fatias/2+1));
				  glNormal3f(cos(teta*(j+1))*cos(alpha*i)*raio,cos(teta*(j+1))*sin(alpha*i)*raio,sin(teta*(j+1))*raio);
				  glVertex3f(cos(teta*(j+1))*cos(alpha*i)*raio,cos(teta*(j+1))*sin(alpha*i)*raio,sin(teta*(j+1))*raio);

				  glTexCoord2f((1.0/seg)*(i),(1.0/fatias)*(j+fatias/2));
				  glNormal3f(cos(teta*j)*cos(alpha*i)*raio,cos(teta*j)*sin(alpha*i)*raio,sin(teta*j)*raio);
				  glVertex3f(cos(teta*j)*cos(alpha*i)*raio,cos(teta*j)*sin(alpha*i)*raio,sin(teta*j)*raio);


			glEnd();
				//glRotatef(alpha*360/(2*3.141592),0.0,0.0,1.0);
		}
	glPopMatrix();

  glBindTexture(GL_TEXTURE_2D,0);

}
GLdouble *rotPosToMatrix(GLdouble m[],dReal rot[], dReal pos[])
{

  m[0]=rot[0];
  m[1]=rot[4];
  m[2]=rot[8];
  m[3]=0;

  m[4]=rot[1];
  m[5]=rot[5];
  m[6]=rot[9];
  m[7]=0;

  m[8]=rot[2];
  m[9]=rot[6];
  m[10]=rot[10];
  m[11]=0;

  m[12]=pos[0];
  m[13]=pos[1];
  m[14]=pos[2];
  m[15]=1;

  return(m);
}


void quatern(GLdouble mat[],dReal q[], dReal pos[])
{
   double X=q[0];
   double Y=q[1];
   double Z=q[2];
   double W=q[3];

   double xx      = X * X;
   double xy      = X * Y;
   double xz      = X * Z;
   double xw      = X * W;

   double yy      = Y * Y;
   double yz      = Y * Z;
   double yw      = Y * W;

   double zz      = Z * Z;
   double zw      = Z * W;

    mat[0]  = 1 - 2 * ( yy + zz );
    mat[1]  =     2 * ( xy + zw );
    mat[2]  =     2 * ( xz - yw );

    mat[4]  =     2 * ( xy - zw );
    mat[5]  = 1 - 2 * ( xx + zz );
    mat[6]  =     2 * ( yz + xw );

    mat[8]  =     2 * ( xz + yw );
    mat[9]  =     2 * ( yz - xw );
    mat[10] = 1 - 2 * ( xx + yy );

    mat[12] = pos[0];
    mat[13] = pos[1];
    mat[14] = pos[2];
    mat[3] = mat[7] = mat[11] = 0;
    mat[15] = 1;

}

void display(void)
{
  GLdouble m[16];
  int i;

  const dReal *pos;

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();

  material((tipo_material)material_cinza);	

  glBegin(GL_POLYGON);
    glNormal3f(0.0f, 0.0f, 1.0f);
    glVertex3f( groundExtents,   groundExtents,  0.f);
    glVertex3f(-groundExtents,   groundExtents,  0.0f);
    glVertex3f(-groundExtents,  -groundExtents,  0.0f);
    glVertex3f( groundExtents,  -groundExtents,  0.0f);
  glEnd();

	material((tipo_material)cor_cubo);	
  glLoadMatrixd(rotPosToMatrix(m, (dReal *)dBodyGetRotation(ballBody),(dReal *)dBodyGetPosition(ballBody)));
  esfera(raio,16,16);

	material((tipo_material)emerald);	
  for(i=0;i<NUM_CUBOS;i++)
  {
    glLoadMatrixd(rotPosToMatrix(m, (dReal *)dBodyGetRotation(cubesBody[i]),(dReal *)dBodyGetPosition(cubesBody[i])));
    glScalef(lado,lado,lado);
    glutSolidCube(1);
  }

	glFlush();
	glutSwapBuffers();

}



void keyboard(unsigned char key, int x, int y)
{

    switch (key)
    {
      case 27 :
        exit(0);
         case 'c':
            if (cor_cubo == material_cinza)
                cor_cubo=brass;
            else
                cor_cubo++;
            glutPostRedisplay();
        break;
         case 'F':
         case 'f':
              keys.f=GL_TRUE;             
          break;
         case 'Q':
         case 'q':
             keys.q=GL_TRUE;
          break;

         case 'A':
         case 'a':
             keys.a=GL_TRUE;
          break;

         case 'O':
         case 'o':
             keys.o=GL_TRUE;
          break;

         case 'P':
         case 'p':
             keys.p=GL_TRUE;
          break;

         case ' ': 
             dBodySetPosition  (ballBody, 0, 0, 100);
             dBodySetLinearVel  (ballBody, 0,0,0);
             dBodySetTorque  (ballBody, 0,0,0);
          break;

    }
}

void keyboardUp(unsigned char key, int x, int y)
{

    switch (key)
    {
         case 'F':
         case 'f':
              keys.f=GL_FALSE;             
          break;
         case 'Q':
         case 'q':
             keys.q=GL_FALSE;
          break;

         case 'A':
         case 'a':
             keys.a=GL_FALSE;
          break;

         case 'O':
         case 'o':
             keys.o=GL_FALSE;
          break;

         case 'P':
         case 'p':
             keys.p=GL_FALSE;
          break;
    }
}

void myReshape(int w, int h)
{	
	glViewport(0, 0, w, h);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();

  gluPerspective(60,(float)w/h,0.1,500);
  gluLookAt(100,100,100,0,0,0,0,0,1);

  glMatrixMode(GL_MODELVIEW);
}

void nearCallback (void *data, dGeomID o1, dGeomID o2)
{
  int i,n;
  const int N = 10;
  dContact contact[N];

  dBodyID b1 = dGeomGetBody(o1);
  dBodyID b2 = dGeomGetBody(o2);


  n = dCollide (o1,o2,N,&contact[0].geom,sizeof(dContact));
  if (n > 0) {
    for (i=0; i<n; i++) {

      // choque entre a bola e o chão
      if(b1==ballBody && o2==groundGeom || b2==ballBody && o1==groundGeom ) //bola com o chao
      {
        printf("chao\n");
        contact[i].surface.mode = dContactBounce | dContactSoftCFM;
        contact[i].surface.mu = dInfinity;
        contact[i].surface.mu2 = 0;
        contact[i].surface.bounce = 0.9;    // changed
        contact[i].surface.bounce_vel = 0.5;     // changed
        contact[i].surface.soft_cfm = 0.1;
      }
      // outros choques
        else 
      {
        contact[i].surface.mode = dContactSlip1 | dContactSlip2 | dContactSoftERP |
                                  dContactSoftCFM | dContactApprox1;
        contact[i].surface.mu = dInfinity;
        contact[i].surface.slip1 = 0.1;
        contact[i].surface.slip2 = 0.1;
        contact[i].surface.soft_erp = 0.6;
        contact[i].surface.soft_cfm = 0.3;
      }

        dJointID c = dJointCreateContact (world,contactgroup,&contact[i]);
        dJointAttach (c,dGeomGetBody(contact[i].geom.g1),
		      dGeomGetBody(contact[i].geom.g2));
    }
  }
}
// this is called by dSpaceCollide when two objects in space are
// potentially colliding.


/*void nearCallback (void *data, dGeomID o1, dGeomID o2)
{
  printf("COLISAO ",o1,o2);


  if (dGeomIsSpace (o1) || dGeomIsSpace (o2)) {
    // colliding a space with something
    dSpaceCollide2 (o1,o2,data,&nearCallback);

    // collide all geoms internal to the space(s)
    if (dGeomIsSpace (o1)) 
      dSpaceCollide ((struct dxSpace *)o1,data,&nearCallback);
    if (dGeomIsSpace (o2)) 
      dSpaceCollide ((struct dxSpace *)o2,data,&nearCallback);
  }
  else 
  {
    // colliding two non-space geoms, so generate contact
    // points between o1 and o2
    int num_contact = dCollide (o1,o2,max_contacts,contact_array,skip);
    // add these contact points to the simulation
    //...
  }
}
*/
void timerKeys(int valor)
{

  if(keys.f)
    dBodySetForce  (ballBody, 0, 0, 100);
  if(keys.q)
    dBodySetForce  (ballBody, 1, 0, 0 );
  else
    dBodySetForce  (ballBody, 0, 0, 0 );
  if(keys.a)
    dBodySetForce  (ballBody, -1, 0, 0 );
  if(keys.o)
    dBodySetForce  (ballBody, 0, 1, 0 );
  if(keys.p)
    dBodySetForce  (ballBody, 0, -1, 0 );

  glutTimerFunc(10,timerKeys, 0);
}


void timer(int valor)
{
  char str[255];
  dReal *veloc;

  system("cls");
  printf("timeKEYS ");
  delta_time();
	sprintf (str, "ODE Sample - %3.2f FPS", FPS);
  glutSetWindowTitle(str);

  //dBodySetForce  (ballBody, 0, 0.1, 0);
	dSpaceCollide(space, 0, &nearCallback);
  dWorldStep (world, calcStep());
	dJointGroupEmpty(contactgroup);

  veloc=(double*)dBodyGetLinearVel (ballBody);
  printf("veloc: x:%f y:%f z:%f\n",veloc[0],veloc[1],veloc[2]);
  glutPostRedisplay();

  glutTimerFunc(10,timer,0);

/*  if(dBodyIsEnabled(ballBody))
    printf("sim\n");
  else
    printf("nao\n");*/
}



AUX_RGBImageRec *LoadBMP(char *Filename)				// Loads A Bitmap Image
{
	FILE *File=NULL;									// File Handle

	if (!Filename)										// Make Sure A Filename Was Given
	{
		return NULL;									// If Not Return NULL
	}

	File=fopen(Filename,"r");							// Check To See If The File Exists

	if (File)											// Does The File Exist?
	{
		fclose(File);									// Close The Handle
		return auxDIBImageLoad(Filename);				// Load The Bitmap And Return A Pointer
	}

	return NULL;										// If Load Failed Return NULL
}

int LoadAllTextures()									// Load Bitmaps And Convert To Textures
{
	int Status=FALSE;									// Status Indicator

	AUX_RGBImageRec *TextureImage[1];					// Create Storage Space For The Texture

	memset(TextureImage,0,sizeof(void *)*1);           	// Set The Pointer To NULL

	// Load The Bitmap, Check For Errors, If Bitmap's Not Found Quit
	if (TextureImage[0]=LoadBMP("xadrez.bmp"))
	{
		Status=TRUE;									// Set The Status To TRUE

		// Create Nearest Filtered Texture
		glBindTexture(GL_TEXTURE_2D, texture[0]);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
		glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);

		// Create Linear Filtered Texture
		glBindTexture(GL_TEXTURE_2D, texture[1]);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
		glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);

		// Create MipMapped Texture
		glBindTexture(GL_TEXTURE_2D, texture[2]);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
		gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
	}

	if (TextureImage[0])								// If Texture Exists
	{
		if (TextureImage[0]->data)						// If Texture Image Exists
		{
			free(TextureImage[0]->data);				// Free The Texture Image Memory
		}

		free(TextureImage[0]);							// Free The Image Structure
	}

	return Status;										// Return The Status
}

#define LI 64 
#define LH 64 
  GLubyte image[LI][LH][3]; 
void makeImage(void) { 
  int i,j,c; 
  for( i = 0 ; i < LI ; i++ ) { 
    for( j = 0 ; j < LH ; j++ ) { 
      c =(((i&0x4)==0)^((j&0x4)==0))*255; 
      image[i][j][0] =(GLubyte) c; 
      image[i][j][1] =(GLubyte) c; 
      image[i][j][2] =(GLubyte) c; } } 
} 


void myInit()
{
	GLfloat LuzAmbiente[]={0.5,0.5,0.5, 0.0};
  int i;

	glClearColor (0.0, 0.0, 0.0, 0.0);
	putLights((GLfloat*)white_light);

    glEnable(GL_SMOOTH); /*enable smooth shading */
    glEnable(GL_LIGHTING); /* enable lighting */
    glEnable(GL_LIGHT0);  /* enable light 0 */
    glEnable(GL_DEPTH_TEST); /* enable z buffer */
    glDepthFunc(GL_LESS);
	glEnable(GL_NORMALIZE);
  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

	glLightModelfv(GL_LIGHT_MODEL_AMBIENT, LuzAmbiente); 
	glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, L); 
  //  glLightModelf(GL_LIGHT_MODEL_TWO_SIDE,1);
  glGenTextures(1, &texture[0]);					// Create Three Textures
	glBindTexture(GL_TEXTURE_2D, texture[0]);


  makeImage(); 
  glPixelStorei(GL_UNPACK_ALIGNMENT,1); 
 // glTexImage2D(GL_TEXTURE_2D,0,3,LI,LH,0,GL_RGB,GL_UNSIGNED_BYTE,&image[0][0][0]); 
	gluBuild2DMipmaps(GL_TEXTURE_2D, 3, LI, LH, GL_RGB, GL_UNSIGNED_BYTE, &image[0][0][0]);
  glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP); 
  glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP); 
  glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); 
  glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); /**/
  glEnable(GL_TEXTURE_2D);
  glShadeModel(GL_SMOOTH); 

  srand( (unsigned)time( NULL ) );
  for( i = 0;   i < 10;i++ )
    printf( "  %6d\n", rand() );

}



void criaMundoOde()
{
	dMass m;
  int i;

  world = dWorldCreate();
  space = dHashSpaceCreate (0);
  contactgroup = dJointGroupCreate (0);
	dWorldSetGravity(world, 0, 0, -9.81);
  dWorldSetCFM(world, CFM);
//  dWorldSetERP(world, ERP);
//  dWorldSetContactMaxCorrectingVel(world, 0.9);
//  dWorldSetContactSurfaceLayer(world, 0);
//  dWorldSetAutoDisableFlag(world, 0);

  //chao

	groundGeom = dCreatePlane(space,  0, 0,  1, 0); // x,y,z,d
  dCreatePlane(space,  1,  0,  0, -groundExtents); // x,y,z,d
  dCreatePlane(space, -1,  0,  0, -groundExtents); // x,y,z,d
  dCreatePlane(space,  0,  1,  0, -groundExtents); // x,y,z,d
  dCreatePlane(space,  0, -1,  0, -groundExtents); // x,y,z,d

	// Ball
	ballBody = dBodyCreate(world);
	dBodySetPosition(ballBody, 0,0,80);
	dMassSetSphere(&m, 1, raio);
	dMassAdjust(&m, .5 );
	dBodySetMass(ballBody, &m);

	ballGeom = dCreateSphere(space, raio);
	dGeomSetBody(ballGeom, ballBody);

  // Cubes

  for(i=0;i<NUM_CUBOS;i++)
  {
	  cubesBody[i] = dBodyCreate(world);
	  dBodySetPosition(cubesBody[i], rand()%180-90,rand()%180-90,rand()%40+10);
	  dMassSetBox(&m, 1, lado,lado,lado);
	  dMassAdjust(&m, .1);
	  dBodySetMass(cubesBody[i], &m);

	  cubesGeom[i] = dCreateBox(space, lado,lado,lado);
	  dGeomSetBody(cubesGeom[i], cubesBody[i]); 
  }

}

void main(int argc, char **argv)
{
    glutInit(&argc, argv);

/* need both double buffering and z buffer */

    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(640, 480);
    glutCreateWindow("OpenGL");
    glutReshapeFunc(myReshape);
    glutDisplayFunc(display);
	  glutKeyboardFunc(keyboard);
	  glutKeyboardUpFunc(keyboardUp);
    glutTimerFunc(10,timer,0);
    glutTimerFunc(50,timerKeys, 0);

	  myInit();
    criaMundoOde();


    glutMainLoop();
}
