/*
 * Small program to visualize .hul's through pov-ray,
 * by Alexander Kroeller.
 */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>


typedef float                rvfloat;
typedef          short int   rvshort;
typedef unsigned short int   rvushort;
typedef                int   rvlong;
typedef unsigned       int   rvulong;

#define SQR(a)  ((a)*(a))

class Vector
{
public:

  void topov(FILE *f)
    { fprintf(f,"<%g, %g, %g> ", x, -y, z); };
  void toscreen(void)
    { printf("<%g, %g, %g> ", x, y, z); };

  rvfloat x,y,z;
};

class Edge
{
public:
  void topov(FILE *f, Vector *vertlist)
    { 
      if(v[0] != v[1]) // pov doesn't like degenerated cones
	{
	  fprintf(f,"object { cone { ");
	  vertlist[v[0]].topov(f); fprintf(f,", EdgeRadius, ");
	  vertlist[v[1]].topov(f); fprintf(f,", EdgeRadius } texture { EdgeTexture } }\n");
	}
      else
	printf("(skipping degenerated edge on vertex %d)\n",v[0]);
    };

  rvushort v[2];
};

class Plane
{
public:
  void topov(FILE *f)
    {
      if( fabs( SQR(normal.x) + SQR(normal.y) + SQR(normal.z) - 1.0 ) < 0.2 )
	{
	  fprintf(f, "    plane { ");
	  normal.topov(f);
	  fprintf(f,", %g }\n", -distance);
	}
      else
	{
	  printf("(skipping degenerated face with normal ");
	  normal.toscreen();
	  printf(")\n");
	};
    };

  Vector  normal;
  rvfloat distance;
};



struct CHull_Header
{
  rvshort  vertex_count;
  rvshort  edge_count;
  rvshort  face_count;

  rvfloat  bbox_xlo, bbox_xhi;
  rvfloat  bbox_ylo, bbox_yhi;
  rvfloat  bbox_zlo, bbox_zhi;

  Vector   unknown_vector;
};

class ConvexHull
{
public:
  void topov(FILE *, rvushort);
  void read(FILE *);
  ~ConvexHull();

  CHull_Header  head;
  Vector       *vertices;
  Edge         *edges;
  Plane        *faces;
};

ConvexHull::~ConvexHull(void)
{
  delete vertices;
  delete edges;
  delete faces;
}

void ConvexHull::read(FILE *f)
{
  // cannot be read directly. The 32-bit memory alignment screws the
  // structure up.
  fread(&head.vertex_count, sizeof(rvushort), 1, f);
  fread(&head.edge_count, sizeof(rvushort), 1, f);
  fread(&head.face_count, sizeof(rvushort), 1, f);
  
  fread(&head.bbox_xlo, sizeof(rvfloat), 6, f); // reads the full box
  fread(&head.unknown_vector, sizeof(rvfloat),3, f);

  vertices=new Vector[head.vertex_count];
  fread(vertices, sizeof(Vector), head.vertex_count, f);

  edges=new Edge[head.edge_count];
  fread(edges, sizeof(Edge), head.edge_count, f);

  faces=new Plane[head.face_count];
  fread(faces, sizeof(Plane), head.face_count, f);
}

void ConvexHull::topov(FILE *f, rvushort hullnum)
{
  rvushort i;

  fprintf(f,"// Vertices in ConvexHull #%d:\n", hullnum);
  for(i=0;i<head.vertex_count;i++)
    {
      fprintf(f,"object { sphere { ");
      vertices[i].topov(f);
      fprintf(f,", VertexRadius } texture { VertexTexture } }\n");
    };
  
  fprintf(f,"\n\n// Edges in ConvexHull #%d:\n", hullnum);
  for(i=0;i<head.edge_count;i++)
    edges[i].topov(f, vertices);
  

  fprintf(f,"\n\n// Faces in ConvexHull #%d:\nobject {\n  intersection {\n", hullnum);
  for(i=0;i<head.face_count;i++)
    faces[i].topov(f);
  fprintf(f,"  }\n  texture { FacesTexture%d }\n}\n\n", hullnum);
}



class Sphere
{
public:
  void topov(FILE *f, rvushort setnum)
    { 
      fprintf(f,"object{ sphere { ");
      center.topov(f);
      fprintf(f,", %g } texture { InteriorTexture%d } }\n", radius, setnum);
    };

  Vector  center;
  rvfloat radius;
};



void writepovheader(FILE *f, const char *hulname, rvushort num_hulls)
{
  rvushort i;

  fprintf(f,"\
// Hull file '%s'
#include \"colors.inc\"\n\
\n\
camera {\n\
  location <-150,150,-150>\n\
  look_at <0,0,0>\n\
}\n\n\n\
// Vertex balls:\n\
#declare VertexRadius  = 2\n\
#declare VertexTexture = texture { pigment { color Yellow } }\n\n\
// Edges:\n\
#declare EdgeRadius    = 1\n\
#declare EdgeTexture   = texture { pigment { color Blue } }\n\n\
// Faces textures. They are all set to Clear, as it is obvious where they\n\
// are, but if you want to see them, use a different color:\n\
", hulname);

    for(i=0;i<num_hulls;i++)
      fprintf(f,"#declare FacesTexture%d  = texture { pigment { color Clear } }\n",i);

  fprintf(f,"\n\n\
// Interior textures:\n\
#declare InteriorTexture0 =  texture { pigment { color Green  } finish { phong 1 } }\n\
#declare InteriorTexture1 = texture { pigment { color Red    } finish { phong 1 } }\n\
#declare InteriorTexture2 = texture { pigment { color Pink   } finish { phong 1 } }\n\
\n\n\n\
// lighting and a surrounding sphere:
object { light_source { <-1000, 1000,  1000> color White } }\n\
object { light_source { <-1000, 1000, -1000> color White } }\n\
object { light_source { < 1000, 1000, -1000> color White } }\n\
object { light_source { < 1000, 1000,  1000> color White } }\n\
object { sphere { <0,0,0>, 10000 } texture { pigment { checker color White color Gray30 } scale 600 } }\n\n\n\n");

}



int main(int argc, char **argv)
{
  char outname[200];
  FILE *fhul, *fpov;
  rvushort hull_count, sphere_count, i, j;
  Sphere sphere;

  if(argc != 2)
    { printf("Give file name!\n"); exit(1); }

  fhul=fopen(argv[1],"rb");
  if(fhul==NULL)
    { perror(argv[1]); exit(1); };

  sprintf(outname,"%s.pov", argv[1]);
  fpov=fopen(outname,"w");
  if(fpov==NULL)
    { perror(outname); fclose(fhul); exit(1); };

  fread(&hull_count, sizeof(rvushort),1, fhul);

  writepovheader(fpov, argv[1], hull_count);

  for(i=0;i<hull_count;i++)
    {
      ConvexHull hull;

      hull.read(fhul);
      hull.topov(fpov, i);
    };



  for(i=0;i<3;i++)
    if(fread(&sphere_count, sizeof(rvushort), 1, fhul)!=0)
      {
	fprintf(fpov,"\n\n// Interior #%d:\n", i);
	for(j=0;j<sphere_count;j++)
	  {
	    fread(&sphere, sizeof(Sphere), 1, fhul);
	    sphere.topov(fpov, i);
	  };
      };



  fclose(fpov);
  fclose(fhul);

  printf("created %s\n",outname);
  return 0;
}

