#include <windows.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>

/*
Written by Kenneth E. Moore
March 21, 2003
*/

int __declspec(dllexport) APIENTRY UserObjectDefinition(double *data, double *tri_list);
int __declspec(dllexport) APIENTRY UserParamNames(char *data);

#define PI 3.14159265358979323846

BOOL WINAPI DllMain (HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
	{
   return TRUE;
   }

/* the data is stored as follows:

For calls to UserObjectDefinition:
data[1]  = code indicating what data the DLL should compute (see code sample below)
data[10] = data back from the DLL (see code sample below)

data[100] = the number of data parameters passed to the DLL
data[101+] = the value of parameter 1, 2, etc...

For calls to UserParamNames:
data = the parameter number whose name is requested, stored as an ASCII integer;

*/

/*

This DLL models a rectangular surface. The parameters are the x and y half widths.

This DLL also shows how to implement user defined coating data. This sample coating
transmits the intensity factor x, and reflects 0% of the light inside a circle of radius a, where x is
parameter 3 and a is parameter 4. Outside of this circle the transmission is 100%.

*/

int __declspec(dllexport) APIENTRY UserObjectDefinition(double *data, double *tri_list)
	{
	int code;
   double xhw, yhw, xtran, circa;


   xhw   = data[101];
	yhw   = data[102];
	xtran = data[103];
	circa = data[104];

	/* do some basic error trapping and handling */
   xhw   = max(1E-6, xhw);
   yhw   = max(1E-6, yhw);
	xtran = min(1.0, max(0.0, xtran));

	/* what we do now depends upon what was requested */
	code = (int) data[1];

	switch(code)
		{

		/* basic data */
		case 0:
			/* Compute the total number of triangular facets used to render and trace this object */
			/* put this value in data[10] */
			data[10] = 2.0;
			/* is this object a solid? put 1 in data[11], use 0 if shell */
			data[11] = 0.0;
			/* does this object compute it's own coating data? put 1 in data[20], else 0 */
			data[20] = 1.0;
			return 0;

		/* generate triangles */
		case 1:
			{
			int num_triangles;

			/*
			We are being asked to generate the triangle list.
			A triangle consists of 3 triplets of coordinates (x, y, and z for each of the 3 corners),
			plus a 6 digit integer that indicates the properties of the triangle.
			That is 10 numbers for each triangle.
			The triangle data will be stored in the tri_list array

			The 6 digit number is constructed as follows.

			The "visible" flag is in the 1's place. If all 3 sides of a
			triangle are visible, use 0. If the side from point 1 to point
			2 is invisible, use 1. If the side from point 2 to point 3 is
			invisible, use 2. If the side from point 3 to point 1 is invisible,
			use 4. Add these flags if more than one side is invisible. For example,
			if all 3 sides are invisible, use 7. Note invisible simply means the
			side is not drawn on the 3D Layout plot, it has nothing to do with ray
			tracing.

			The "reflective" flag is in the 10's place, use zero for refractive and 1 for reflective.

			The "coat scatter group" is a 2 digit integer in the 1,000 and 100's place.
			Only CSG 0-3 are currently supported, but 2 digits are provided for future
			expansion.

			The "exact group" flag is a 2 digit integer in the 100,000 and 10,000's place.
			The exact group number indicates which set of exact formulas are used to iterate
			to the actual object surface. Use 0 to indicate the flat triangular facet is the
			correct solution. The exact flags are used in the intercept portion of the code that is case 2 below.

			Example: 030212 means the exact group is 3, the CSG is 2, the facet
			is reflective, and the side of the triangle from point 2 to point 3 is not drawn.

			*/

			num_triangles = 0;

			tri_list[num_triangles*10 + 0] =  xhw; // x1
			tri_list[num_triangles*10 + 1] = -yhw; // y1
			tri_list[num_triangles*10 + 2] =  0.0; // z1
			tri_list[num_triangles*10 + 3] = -xhw; // x2
			tri_list[num_triangles*10 + 4] = -yhw; // y2
			tri_list[num_triangles*10 + 5] =  0.0; // z2
			tri_list[num_triangles*10 + 6] = -xhw; // x3
			tri_list[num_triangles*10 + 7] =  yhw; // y3
			tri_list[num_triangles*10 + 8] =  0.0; // z3
			tri_list[num_triangles*10 + 9] = 000104.0;   // exact 0, CSG 1, refractive, 3-1 invisible
			num_triangles++;

			tri_list[num_triangles*10 + 0] =  xhw; // x1
			tri_list[num_triangles*10 + 1] = -yhw; // y1
			tri_list[num_triangles*10 + 2] =  0.0; // z1
			tri_list[num_triangles*10 + 3] =  xhw; // x2
			tri_list[num_triangles*10 + 4] =  yhw; // y2
			tri_list[num_triangles*10 + 5] =  0.0; // z2
			tri_list[num_triangles*10 + 6] = -xhw; // x3
			tri_list[num_triangles*10 + 7] =  yhw; // y3
			tri_list[num_triangles*10 + 8] =  0.0; // z3
			tri_list[num_triangles*10 + 9] = 000104.0;   // exact 0, CSG 1, refractive, 3-1 invisible
			num_triangles++;

			data[10] = num_triangles; /* how many we actually wrote out */
			return 0;
			}

		/* iterate to exact solution given starting point */
		case 2:
			{
			/*
			We are giving starting data, and must compute the distance to the actual surface.
			We also need to compute the normal vector at the point.

			This is simple iteration. All surfaces must be described as:
			F(x,y,z) = 0
			We will also need Fx = dF/dx, Fy = dF/dy, and Fz = dF/dz

			For the elliptical face, we have set the triangles to exact = 1
			F  = 1.0 - X*X/Rx*Rx - Y*Y/Ry*Ry
			Fx = -2X/Rx*Rx
			Fy = -2Y/Ry*Ry
			Fz = 0.0

			then compute
			Fp = Fx*l + Fy*m + Fz*n where l, m, and n are the ray cosines

			the propagation distance is just
			delt = -F/Fp;
			keep a running total on the position
			t += delt;
							
			increment the ray coordinates
			x += l*delt;
			y += m*delt;
			z += n*delt;

			repeat until delt is small!

			The data ZEMAX sends is formatted as follows:
			data[2], data[3], data[4] = x, y, z
			data[5], data[6], data[7] = l, m, n
			data[8] = exact code

			*/

			/* no need to iterate, use exact solution on flat triangle face */
			return 0;
			}
		case 3:
			{
			double r, xamp;
			/*
			Compute the coating data for this object.

			The data ZEMAX sends is formatted as follows:
			data[2], data[3], data[4] = x, y, z
			data[5], data[6], data[7] = l, m, n
			data[8] = coat group number
			data[9], data[10], data[11] = normal nx, ny, nz
			data[12], data[13] = current and next index of refraction
			data[14] = cosine of normal incidence angle
			data[15] = wavelength in microns
			data[20] =  zero flag. Set this to 1.0 to indicate the DLL
			computes the coating data, otherwise, ZEMAX will compute using
			object settings.
			
			The DLL must compute these values:

			set data[20] = 1.0

			for s polarization:
			data[21] = amplitude reflection real
			data[22] = amplitude reflection imaginary
			data[23] = amplitude transmission real
			data[24] = amplitude transmission imaginary
			for p polarization:
			data[31] = amplitude reflection real
			data[32] = amplitude reflection imaginary
			data[33] = amplitude transmission real
			data[34] = amplitude transmission imaginary


			*/
			/* the code that follows would be altered by the user for the particular application */
			r = sqrt(data[2]*data[2] + data[3]*data[3]);
			if (r <= circa)
				{
				/* inside */
				xamp = sqrt(xtran);
				}
			else
				{
				/* outside */
				xamp = 1.0;
				}
			data[20] = 1.0;
			data[21] = 0.0;
			data[22] = 0.0;
			data[23] = xamp;
			data[24] = 0.0;
			data[31] = 0.0;
			data[32] = 0.0;
			data[33] = xamp;
			data[34] = 0.0;

			/*
			Note this sample is for a surface, not a solid.
			For refractive solids, the TIR case must be
			considered and the coefficients modifed accordingly.
			*/

			return 0;
			}
		}

	/* we did not recognize the request */
	return -1;
   }

int __declspec(dllexport) APIENTRY UserParamNames(char *data)
	{
	/* this function returns the name of the parameter requested */
	int i;
	i = atoi(data);
	strcpy(data,""); // blank means unused

	/* negative numbers or zero mean names for coat/scatter groups */
	if (i ==  0) strcpy(data,"All Faces");
	
	if (i == 1) strcpy(data,"X Half Width");
	if (i == 2) strcpy(data,"Y Half Width");
	if (i == 3) strcpy(data,"Transmission");
	if (i == 4) strcpy(data,"Radius A");
	return 0;
	}

