int main(int argc, char **argv)
{

  using namespace std;
  int numObjects;
  long nRows, nCols;



  char **error;

			 
  if (argc < 4)
    {
      fprintf(stderr,"Usage: lab1 <input file> <output file> <rows>\n");
      return -1;
    }

  filename = (char*)malloc(sizeof(char)*strlen(argv[2]));
  strcpy(filename, argv[2]);

  error = (char**)malloc(sizeof(char**)*10);
  nRows = strtol(argv[3],error,10);
  
  if (**error)
    {
      fprintf(stderr,"Error! use a number for rows!\n");
      return -2;
    }
  
  free(error);
  
  

  SoDB::init();
  OSUInventorScene *scene = new OSUInventorScene(argv[1]);


  //check to see if there are objects
  if (numObjects = scene->Objects.getLength() < 1)
    {
      fprintf(stderr,"Error, no objects");
      return -2;
    }
  
  //get the objects and put them into a list
  for (int i = 0; i < scene->Objects.getLength(); i++)
    {
      OSUObjectData *obj = (OSUObjectData *)scene->Objects[i];
      /*
      if (!obj->Check())
	{
	  fprintf(stderr,"Error detected in OSUObjectData for object %i.\n",i);
	  return 20;
	}
      */
      

      SoType shape_type = obj->shape->getTypeId(); 

      if (shape_type == SoSphere::getClassTypeId()) 
	{ 
	  Sphere *sp = new Sphere;


	  SoSphere * sphere = (SoSphere *) obj->shape; 
	  SoTransform * transformation = obj->transformation; 
	  SbVec3f scale_vector = transformation->scaleFactor.getValue(); 
	  SbVec3f translation_vector = transformation->translation.getValue();
	
	  sp->radius = 1;
	  sp->center = Point(0,0,0,1);
	  
	  //do the materials stuff
	  SoMaterial * material = obj->material;
	  
	  sp->color = rgb(material->diffuseColor[0][0],material->diffuseColor[0][1],material->diffuseColor[0][2]);
	  sp->specular = rgb(material->specularColor[0][0], material->specularColor[0][1],material->specularColor[0][2]);
	  sp->ambient = rgb(material->ambientColor[0][0], material->ambientColor[0][1], material->ambientColor[0][2]);
	  sp->shininess = material->shininess[0];
	  sp->trans = material->transparency[0];
			  
	  printf("Object %d has shininess %f\n", sp->object_number, sp->shininess);
	  //let's get our translation space matrix
	  //void getTranslationSpaceMatrix(SbMatrix &mat, SbMatrix &inv) const
	  SbMatrix tmat, tinv, smat, sinv, rmat, rinv;
	  
	  transformation->getTranslationSpaceMatrix(tmat, tinv);
	  //	  transformation->getScaleSpaceMatrix(smat,sinv);
	  transformation->getRotationSpaceMatrix(rmat, rinv);

	  //	  SbMatrix & multRight(const SbMatrix &m)
	  sp->M =   tmat;
	  sp->Mi =  tinv;
	  
	  sp->M.transpose();
	  sp->Mi.transpose();
	 

	  sp->type = eSPHERE;
	  

	  //texture data
    

	  SoSFImage  image;
	  int      nc;
	  SbVec2s  size;
	  const unsigned char *texelArray;

	  // get properties of object
	  //obj = (OSUObjectData *)worldptr->scene->Objects[i];
	 
	  if (obj->texture != NULL)
	    {
	  
	      image = obj->texture->image;
	      
	      
	      texelArray = image.getValue(size,nc);     // sets 'size', 'nc', 'texelArray'
	      sp->image = texelArray[0];
	      printf("\nimage value = %d\n",texelArray[0]);
	    }


	

	  
	  objects.push_back(sp);
	  sp->object_number = i;
	  
	}

      if (shape_type == SoCube::getClassTypeId()) 
	{ 
	  Box *sp = new Box;
	  
	      
	  SoSphere * sphere = (SoSphere *) obj->shape; 
	  SoTransform * transformation = obj->transformation; 
	  SbVec3f scale_vector = transformation->scaleFactor.getValue(); 
	  SbVec3f translation_vector = transformation->translation.getValue();
	  sp->center = Point(0,0,0,1);
	  
	  //do the materials stuff
	  SoMaterial * material = obj->material;
	  
	  sp->color = rgb(material->diffuseColor[0][0],material->diffuseColor[0][1],material->diffuseColor[0][2]);
	  sp->specular = rgb(material->specularColor[0][0], material->specularColor[0][1],material->specularColor[0][2]);
	  sp->ambient = rgb(material->ambientColor[0][0], material->ambientColor[0][1], material->ambientColor[0][2]);
	      sp->shininess = material->shininess[0];
	      sp->trans = material->transparency[0];
	      
	      printf("Object %d has shininess %f\n", sp->object_number, sp->shininess);
	      //let's get our translation space matrix
	      //void getTranslationSpaceMatrix(SbMatrix &mat, SbMatrix &inv) const
	      SbMatrix tmat, tinv, smat, sinv, rmat, rinv;
	      
	      transformation->getTranslationSpaceMatrix(tmat, tinv);
	      //	  transformation->getScaleSpaceMatrix(smat,sinv);
	      transformation->getRotationSpaceMatrix(rmat, rinv);
	       // list triangles
       
	    
	      //	  SbMatrix & multRight(const SbMatrix &m)
	      sp->M =   tmat;
	      sp->Mi =  tinv;
	      
	      sp->M.transpose();
	      sp->Mi.transpose();
	    

	  SoSFImage  image;
	  int      nc;
	  SbVec2s  size;
	  const unsigned char *texelArray;
	  
	  // get properties of object
	  //obj = (OSUObjectData *)worldptr->scene->Objects[i];
	  if (obj->texture != NULL)
	    {
	      
	      image = obj->texture->image;
	      
	      
	      texelArray = image.getValue(size,nc);     // sets 'size' // list triangles
	    printf("\nimage value = %d\n",texelArray[0]);
	    	      sp->image = texelArray[0];
	  }
		  
	
	  
	  
	  objects.push_back(sp);
	  sp->type = eCUBE;
	  sp->object_number = i;
	}
      
      
      if (shape_type == SoIndexedTriangleStripSet::getClassTypeId()) 
	{
	  SoIndexedTriangleStripSet * triangle_strip_set =
	    (SoIndexedTriangleStripSet *) obj->shape;
	  
	  if (obj->points == NULL)
	    {
	      cout << "  Error: Points missing for indexed triangle strip set.";
	    }
	  else if (obj->points->getTypeId() != SoCoordinate3::getClassTypeId()) 
	    {
	      cout << "  Error: Incorrect format for point list." << endl;
	      cout << "         Expected list of 3D coordinates.";
	    }
	  else 
	    {
	      SoCoordinate3 * coord = (SoCoordinate3 *) obj->points;
	      int numv = coord->point.getNum();
	      cout << "  Surface has " << numv << " vertices." << endl;
	      for (int i = 0; i < numv; i++) 
		{
		  cout << "  Vertex " << i << " = ("
		       << coord->point[i][0] << ", "
		       << coord->point[i][1] << ", "
		       << coord->point[i][2] << ")." << endl;
		}
	  
	      if (obj->normals == NULL) 
		{
		  cout << "  No stored normals." << endl;
		}
	      else 
		{
		  int num_normals = obj->normals->vector.getNum();
		  if (num_normals != numv) 
		    {
		      // assume PER_VERTEX normal binding
		      cout << "Error: Number of normals does not equal number of vertices." << endl;
		    }
		  else 
		    {
		      
		      for (int i = 0; i < num_normals; i++) {
			cout << "  Normal " << i << " = ("
			     << obj->normals->vector[i][0] << ", "
			     << obj->normals->vector[i][1] << ", "
			     << obj->normals->vector[i][2] << ")." << endl;
		      }
		    }
		}
	      /*
	      // list triangles
	      int itriangle = 0;
	      int icoord = 0;
	      int coord_list_length = triangle_strip_set->coordIndex.getNum();
	      while (icoord < coord_list_length) {
		int c0 = SO_END_STRIP_INDEX;
		int c1 = SO_END_STRIP_INDEX;
		int c2 = SO_END_STRIP_INDEX;
		while (icoord < coord_list_length &&
		       triangle_strip_set->coordIndex[icoord] != SO_END_STRIP_INDEX) {            c2 = triangle_strip_set->coordIndex[icoord];
		       if (c0 != SO_END_STRIP_INDEX && c1 != SO_END_STRIP_INDEX) {
			 cout << "  Triangle " << itriangle
			      << " coordinate indices = ( "
			      << c0 << ", " << c1 << ", " << c2 << " )." << endl;
			 itriangle++;
		       };
		       icoord++;
		       c0 = c1;
		       c1 = c2;
		       
		}
	      }
	      */
	    }	
	      
	}
      free(obj);
    }
  



  printf("Number of objects seen %d\n", objects.size());
  printf("Setting up camera\n");
  

  /*********************************************************************
   *   Camera Setup
   *
   *********************************************************************/


  SoCamera * cam = scene->Camera; 
  
  
  if (scene->Camera == NULL)
    {
      printf("No camera found.  Setting Default/n");
      camera.aspect = 1;
      camera.position = Point(0,0,0,1);
      camera.n = Vector(0,0,-1,0);
      camera.v = Vector(0,1,0,0);
      camera.u = cross(camera.n,camera.v);
      camera.height_angle = M_PI/2;
      
    }
  else 
    {
      SbVec3f camera_position = cam->position.getValue(); 
      SbRotation cam_orientation = cam->orientation.getValue(); 
      SbVec3f camera_rotation_axis; 
      float cam_rotation_angle; 
      cam_orientation.getValue(camera_rotation_axis, cam_rotation_angle); 
      float cam_aspect_ratio = cam->aspectRatio.getValue(); 
      SoType cam_type = cam->getTypeId(); 
      
      
      
      //Let's grab the aspect ratio   
      nCols =(int)( nRows*cam_aspect_ratio);   
      camera.aspect = cam_aspect_ratio;   
      printf("Number of rows is %d columns is %d with an aspect ratio of %f\n",nRows,nCols,cam_aspect_ratio);   
      
      
      // calculate camera direction and camera up direction 
      SbVec3f camera_direction, camera_up; 
      cam_orientation.multVec(SbVec3f(0, 0, -1), camera_direction); 
      cam_orientation.multVec(SbVec3f(0, 1, 0), camera_up); 
      
      camera.n = -1*Vector(camera_direction[0],camera_direction[1],camera_direction[2],0); 
      camera.v = -1*Vector(camera_up[0],camera_up[1],camera_up[2],0); 
      
      
      camera.position = Point(camera_position[0],camera_position[1],camera_position[2],1); 
      
      camera.u = cross(camera.n,camera.v);  
      
      if (cam_type == SoPerspectiveCamera::getClassTypeId()) {
	
	// camera is a perspective camera

	SoPerspectiveCamera * perspective_camera = (SoPerspectiveCamera *) cam;
	float camera_height_angle = perspective_camera->heightAngle.getValue();
	camera.height_angle = camera_height_angle;
	
      }
    }

  N = 1; 
  pixH = 2*tan(camera.height_angle/2)/nCols; 
  pixW = 2*tan(camera.height_angle/2)/nRows; 
     
  
  printf("Camera position is %f %f %f\n",camera.position.x,camera.position.y, camera.position.z);   
  printf("Camera n is %f %f %f\n",camera.n.x,camera.n.y, camera.n.z);  
  printf("Camera v is %f %f %f\n",camera.v.x,camera.v.y, camera.v.z);  
  printf("Camera u is %f %f %f\n",camera.u.x,camera.u.y, camera.u.z); 
  printf("N is %f\n",N); 
 
  
 
  //setup for lights

  // list lights
  for (int j = 0; j < scene->Lights.getLength(); j++) {
    SoLight * flight = (SoLight *) scene->Lights[j];
    SoType light_type = flight->getTypeId();
    SoSFColor lightColor;
    SbColor   lightClr;
    float     lightr,lightg,lightb;
    
    lightColor = flight->color;

    light *l = new light;
    l->color = rgb(lightClr[0],lightClr[1],lightClr[2]);
    l->intensity = flight->intensity.getValue();

    if (light_type == SoPointLight::getClassTypeId())
      {
	SoPointLight * point_light = (SoPointLight *) flight; 
	SbVec3f location = point_light->location.getValue();
    	l->center = Point(location[0],location[1],location[2],1);
	l->type = ePOINT;
      }

    else if (light_type == SoSpotLight::getClassTypeId())
      {
	
	SoSpotLight * spot_light = (SoSpotLight *) flight;
	SbVec3f location = spot_light->location.getValue();

	l->center = Point(location[0], location[1], location[2],1);
	l->theta = spot_light->cutOffAngle.getValue();
	l->drop_off = spot_light->dropOffRate.getValue();
	
	SbVec3f direction = spot_light->direction.getValue();
	Vector lightDir(direction[0], direction[1], direction[2],0);
	l->dir = lightDir;
	l->type=eHOOD;
      }
    
    else if (light_type == SoDirectionalLight::getClassTypeId())
      {
	
	l->type = eDIR;
	SoDirectionalLight * dir_light = (SoDirectionalLight *) flight;
	
	SbVec3f direction = dir_light->direction.getValue();
	Vector lightDir(direction[0], direction[1], direction[2],0);
	l->dir = lightDir;
	
      }
    

    lights.push_back(l);
  }

  //start our tracer
  trace(objects, nRows, nCols, 1);
  

  //let's free our vector pointers
  int x = objects.size() - 1;
  fprintf(stderr,"Freeing objects\n");
  while (x >= 0)
    {
      delete objects[x];
      //  printf("freeing object %d\n",x);
      x--;
    }


  x = lights.size() - 1;
  fprintf(stderr,"Freeing lights\n");
  while (x >= 0)
    {
      delete lights[x];
      x--;
    }
  
    
}