#ifndef DATA_S

#define DATA_S

#define MAXCHANNELS 3
#define MAXSOURCES 10

#define EPSILON 0.00001
#define LARGE 1e30

#define UNDEFINED -1

#define MAX_REFLECTION_TYPE 3
/* For surface_reflection_type */
#define DIFFUSE 0
#define MIRROR 1
#define OTHER_REFLECTION 2

#define For_Grids_Only 0
#define For_Main_Surfaces_Only 1
#define MAX_GEOMETRY_TYPE 10
/* For surface_geometry_type */
#define QUADRILATERAL 0
#define SPHERE 1
#define BUBBLE 2
#define CYLINDER 3
#define TUBE 4
#define CONE 5
#define CUP  6
#define RING 7
#define POLYGON 8
#define OTHER_GEOMETRY 9

#define point_on_line(s,d,t,p) {(p).x=(s).x+t*(d).x;(p).y=(s).y+t*(d).y;(p).z=(s).z+t*(d).z;}
#define project_point(p,P,i) {\
	switch(i){\
		case 0 : /* X axis */\
			p.x = (P).y; p.y = (P).z; break;\
		case 1 : /* Y axis */\
			p.x = (P).z; p.y = (P).x; break;\
		case 2 : /* Z axis */\
			p.x = (P).x; p.y = (P).y; break;\
	}\
}
		
#define set_t(lo,hi)   if ((nroots > 1)&&(roots[1] > EPSILON)&&\
			((roots[0] < EPSILON)||(roots[1] < roots[0]))&&\
			check(roots[1],ray_start,ray_direction,lo,hi))\
				 t = roots[1];\
                else if((roots[0] > EPSILON)&&\
			check(roots[0],ray_start,ray_direction,lo,hi))\
				t = roots[0]
#define circle_inverse_mapping(r,x,y,u) {\
		double value=x/r;\
		if (value > 1.) u = 0;\
		else if (value < -1.) u = 0.5;\
		else u = acos(value)/(2.*PI);\
		if (y < 0.) u = 1. - u;\
}

	typedef struct SECONDARYRAY{
		Point3 start;
		Vector3 direction;
		double weight;
		struct SECONDARYRAY *next;
	} SecondaryRay;

	typedef struct{
		Point3 start;
		Vector3 direction;
		double path_length;
		long number;
		int channel;
		int source_number;
		double weight;
		SecondaryRay *sec_ray_list;
#if defined (DEBUG)
        	long intersections;
#endif
	}Ray;

typedef struct {
		double strength[MAXCHANNELS]; 
			/*Related to Wattage of the Source Light.*/
		int oindex;
		int emission_type; /* 0 - Diffuse, 1 - Directional,...*/
		Vector3 dir;
		double spread;
		Matrix4 xform;
}Source;

	typedef struct{
		double normalized_flux_density[MAXCHANNELS];
		double area;
	}Surface_Grid_structure;
#define grid_u(n,u) (object[n].grid_h_reso*u)
#define grid_v(n,v) (object[n].grid_v_reso*v)
#define gridindex(n,u,v) (\
	(((v)<0)?0:(((v)>=object[n].grid_v_reso)?(object[n].grid_v_reso-1):(v)))\
	*object[n].grid_h_reso+\
	(((u)<0)?0:(((u)>=object[n].grid_h_reso)?(object[n].grid_h_reso-1):(u)))\
	)

typedef struct{
	Surface_Grid_structure *grid;
	int grid_v_reso,grid_h_reso;
	char surface_geometry_type;
	char surface_reflection_type;
	double reflectance[MAXCHANNELS]; /* Hemispherical Reflectance */
	void *object_specific_structure;
	/* Following two entities for acceleration of ray object
	   intersection using Spacial Enumeration Technique. */
	struct {			 
		long ray_num;
		double t,u,v;
	}mail_box;
	Box3 bbox;
	int start_grid_index; /* For Radiosity Use */
	double normalized_flux_density[MAXCHANNELS];
} Obj;


        /* Begin object_specific_structures */
		typedef struct{
			int nvertices;
			Point3 *vertex_list;
			/* Computed data */
                        Vector3 plane_normal;
                        double plane_constant;
			char dominant_axis_flag;
				/* 0 - for X-axis, 1 - for Y-axis, 2 - for Z axis */
			Matrix4 local_trans;
		}Polygon;

				typedef struct{
                        Point3 P00,P10,P11,P01;
			/* Computed data */
                        Vector3 plane_normal;
                        double plane_constant;
                        Vector3 Na,Nb,Nc;
                        Vector3 Qux,Quy,Qvx,Qvy;
                        double Du0,Du1,Du2,Dux,Duy,Dv0,Dv1,Dv2,Dvx,Dvy;
                        Matrix4 local_trans;
                }Quadrilateral;

                typedef struct{
                        Point3 center;
                        double radius;
                }Sphere;

		typedef struct{
			Point3 base_point1, base_point2;
			double radius;
			/* Computed data */
			double height;
			Matrix4 world_to_object, object_to_world;
		} Cylinder;

		typedef struct{
			Point3 apex_point;
			double apex_radius;
			Point3 base_point;
			/* Computed data */
			double base_radius;
			Vector3 axis;
			Matrix4 world_to_object, object_to_world;
			double distance;
		} Cone; /* 0 <= apex_radius <= base_radius */

		typedef struct{
			Point3 center;
			Vector3 normal;
			double inner_radius,outer_radius ;
			/* Computed data */
			Matrix4 world_to_object,object_to_world;
		} Ring;

typedef struct{
	Box3 extent;
	int *intersecting_object_list;
	int nobjects;
} Voxel;


typedef struct{
        Box3 extent;
        Voxel *voxels;
        int x_subdivision,y_subdivision,z_subdivision;
        Point3 voxel_size;
        Point3 voxel_density;
}Volume_grid;

#define x2voxel(v,a) (((a)-(v).extent.min.x)*(v).voxel_density.x)
#define y2voxel(v,a) (((a)-(v).extent.min.y)*(v).voxel_density.y)
#define z2voxel(v,a) (((a)-(v).extent.min.z)*(v).voxel_density.z)
#define voxel2x(v,a) ((a)*(v).voxel_size.x+(v).extent.min.x)
#define voxel2y(v,a) ((a)*(v).voxel_size.y+(v).extent.min.y)
#define voxel2z(v,a) ((a)*(v).voxel_size.z+(v).extent.min.z)
#define voxel_index(v,x,y,z) ((x*(v).y_subdivision+y)*(v).z_subdivision+z)
#define voxel_addr(v,x,y,z) ((v).voxels+voxel_index(v,x,y,z))

extern int color_channels;
extern int number_objects;
extern int light_sources;
extern Obj *object;
extern Source source[];
extern Volume_grid volume_grid;
extern int total_surface_grid_points;
extern long total_rays;
extern int intensity_out_flag;
extern int verbose_output_flag;

void mirror_reflection();
void align_Z_to_axis();
void align_axis_to_Z();
Vector3 transform_vector();
int bounds_overlap();
Point3 get_bilinear();
double *alloc_counters();
void scale();
void translate();
void *calloc();
void bound_transform();

#endif
