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

/*
Written by Kenneth E. Moore
December 8, 2004
*/

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[12] = 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 volume with a simple linear grating on one face.

All this DLL really does is define a rectangular volume with 6 sides. What makes
it a grating is the line:
			data[12] = 1; // this will be the front face
below.

When ZEMAX sees that the grating flag is set, any ray traced to a face with that
CSG will call the DLL associated with that CSG. The diffraction DLL itself is
defined separately. See for example diff_samp_1.DLL provided with ZEMAX as a sample file.

*/

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


   xhw  = data[101];
	yhw  = data[102];
	L    = data[103];

	/* do some basic error trapping and handling */
	if (xhw <= 0.0) xhw = 1.0;
	if (yhw <= 0.0) yhw = 1.0;
	if (L   <= 0.0) L   = 1.0;

	/* 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 */
			/* we need 2 on each of 6 faces */
			/* put this value in data[10] */
			data[10] = 12;

			/* is this object a solid? put 1 in data[11], use 0 if shell */
			data[11] = 1;

			/* is this object potentially diffractive? put in data[12] the CSG number that is diffractive, cannot use 0. Use 0 if not diffractive */
			data[12] = 1; // this will be the front face

			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;

			// the following code is tedious and verbose. I wrote it this way to make it easy to read.

			/* front face */
			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] = 000102.0;   // exact 0, CSG 1, refractive, 1-2 and 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] = 000102.0;   // exact 0, CSG 1, refractive, 1-2 and 3-1 invisible
			num_triangles++;

			/* back face */
			tri_list[num_triangles*10 + 0] = -xhw; // x1
			tri_list[num_triangles*10 + 1] = -yhw; // y1
			tri_list[num_triangles*10 + 2] =  L;   // z1
			tri_list[num_triangles*10 + 3] = -xhw; // x2
			tri_list[num_triangles*10 + 4] = +yhw; // y2
			tri_list[num_triangles*10 + 5] =  L;   // z2
			tri_list[num_triangles*10 + 6] = +xhw; // x3
			tri_list[num_triangles*10 + 7] = -yhw; // y3
			tri_list[num_triangles*10 + 8] =  L;   // z3
			tri_list[num_triangles*10 + 9] = 000202.0;   // exact 0, CSG 1, refractive, 1-2 and 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] =  L;   // z1
			tri_list[num_triangles*10 + 3] = -xhw; // x2
			tri_list[num_triangles*10 + 4] = +yhw; // y2
			tri_list[num_triangles*10 + 5] =  L;   // z2
			tri_list[num_triangles*10 + 6] = +xhw; // x3
			tri_list[num_triangles*10 + 7] = -yhw; // y3
			tri_list[num_triangles*10 + 8] =  L;   // z3
			tri_list[num_triangles*10 + 9] = 000202.0;   // exact 0, CSG 2, refractive, 1-2 and 3-1 invisible
			num_triangles++;

			/* top face */
			tri_list[num_triangles*10 + 0] = +xhw; // x1
			tri_list[num_triangles*10 + 1] = +yhw; // y1
			tri_list[num_triangles*10 + 2] =  0;   // z1
			tri_list[num_triangles*10 + 3] = +xhw; // x2
			tri_list[num_triangles*10 + 4] = +yhw; // y2
			tri_list[num_triangles*10 + 5] =  L;   // z2
			tri_list[num_triangles*10 + 6] = -xhw; // x3
			tri_list[num_triangles*10 + 7] = +yhw; // y3
			tri_list[num_triangles*10 + 8] =  0;   // z3
			tri_list[num_triangles*10 + 9] = 000002.0;   // exact 0, CSG 1, refractive, 1-2 and 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] =  L;   // z1
			tri_list[num_triangles*10 + 3] = +xhw; // x2
			tri_list[num_triangles*10 + 4] = +yhw; // y2
			tri_list[num_triangles*10 + 5] =  L;   // z2
			tri_list[num_triangles*10 + 6] = -xhw; // x3
			tri_list[num_triangles*10 + 7] = +yhw; // y3
			tri_list[num_triangles*10 + 8] =  0;   // z3
			tri_list[num_triangles*10 + 9] = 000202.0;   // exact 0, CSG 2, refractive, 1-2 and 3-1 invisible
			num_triangles++;

			/* bottom face */
			tri_list[num_triangles*10 + 0] = +xhw; // x1
			tri_list[num_triangles*10 + 1] = -yhw; // y1
			tri_list[num_triangles*10 + 2] =  0;   // z1
			tri_list[num_triangles*10 + 3] = +xhw; // x2
			tri_list[num_triangles*10 + 4] = -yhw; // y2
			tri_list[num_triangles*10 + 5] =  L;   // z2
			tri_list[num_triangles*10 + 6] = -xhw; // x3
			tri_list[num_triangles*10 + 7] = -yhw; // y3
			tri_list[num_triangles*10 + 8] =  0;   // z3
			tri_list[num_triangles*10 + 9] = 000002.0;   // exact 0, CSG 1, refractive, 1-2 and 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] =  L;   // z1
			tri_list[num_triangles*10 + 3] = +xhw; // x2
			tri_list[num_triangles*10 + 4] = -yhw; // y2
			tri_list[num_triangles*10 + 5] =  L;   // z2
			tri_list[num_triangles*10 + 6] = -xhw; // x3
			tri_list[num_triangles*10 + 7] = -yhw; // y3
			tri_list[num_triangles*10 + 8] =  0;   // z3
			tri_list[num_triangles*10 + 9] = 000202.0;   // exact 0, CSG 2, refractive, 1-2 and 3-1 invisible
			num_triangles++;

			/* left face */
			tri_list[num_triangles*10 + 0] = +xhw; // x1
			tri_list[num_triangles*10 + 1] = +yhw; // y1
			tri_list[num_triangles*10 + 2] =  0;   // z1
			tri_list[num_triangles*10 + 3] = +xhw; // x2
			tri_list[num_triangles*10 + 4] = +yhw; // y2
			tri_list[num_triangles*10 + 5] =  L;   // z2
			tri_list[num_triangles*10 + 6] = +xhw; // x3
			tri_list[num_triangles*10 + 7] = -yhw; // y3
			tri_list[num_triangles*10 + 8] =  0;   // z3
			tri_list[num_triangles*10 + 9] = 000002.0;   // exact 0, CSG 1, refractive, 1-2 and 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] =  L;   // z1
			tri_list[num_triangles*10 + 3] = +xhw; // x2
			tri_list[num_triangles*10 + 4] = +yhw; // y2
			tri_list[num_triangles*10 + 5] =  L;   // z2
			tri_list[num_triangles*10 + 6] = +xhw; // x3
			tri_list[num_triangles*10 + 7] = -yhw; // y3
			tri_list[num_triangles*10 + 8] =  0;   // z3
			tri_list[num_triangles*10 + 9] = 000202.0;   // exact 0, CSG 2, refractive, 1-2 and 3-1 invisible
			num_triangles++;

			/* right face */
			tri_list[num_triangles*10 + 0] = -xhw; // x1
			tri_list[num_triangles*10 + 1] = +yhw; // y1
			tri_list[num_triangles*10 + 2] =  0;   // z1
			tri_list[num_triangles*10 + 3] = -xhw; // x2
			tri_list[num_triangles*10 + 4] = +yhw; // y2
			tri_list[num_triangles*10 + 5] =  L;   // z2
			tri_list[num_triangles*10 + 6] = -xhw; // x3
			tri_list[num_triangles*10 + 7] = -yhw; // y3
			tri_list[num_triangles*10 + 8] =  0;   // z3
			tri_list[num_triangles*10 + 9] = 000002.0;   // exact 0, CSG 1, refractive, 1-2 and 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] =  L;   // z1
			tri_list[num_triangles*10 + 3] = -xhw; // x2
			tri_list[num_triangles*10 + 4] = +yhw; // y2
			tri_list[num_triangles*10 + 5] =  L;   // z2
			tri_list[num_triangles*10 + 6] = -xhw; // x3
			tri_list[num_triangles*10 + 7] = -yhw; // y3
			tri_list[num_triangles*10 + 8] =  0;   // z3
			tri_list[num_triangles*10 + 9] = 000202.0;   // exact 0, CSG 2, refractive, 1-2 and 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:
			{
			/*
			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
  			*/

			/* since all the surfaces are flat, we only need to compute the surface normal vector. */
			// the normal vector is stored in data[11], data[12], data[13]

			/* this will work for the front and back faces */
			data[11] = 0.0;
			data[12] = 0.0;
			data[13] = 1.0;

			if ((int)data[8] == 0) // side faces
				{
				if (fabs(data[2]) - xhw < 1e-12)
					{
					data[11] = 1.0;
					data[12] = 0.0;
					data[13] = 0.0;
					}
				else
					{
					data[11] = 0.0;
					data[12] = 1.0;
					data[13] = 0.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,"Side Faces");
	if (i == -1) strcpy(data,"Front Face");
	if (i == -2) strcpy(data,"Back Face");
	
	if (i == 1) strcpy(data,"X Half Width");
	if (i == 2) strcpy(data,"Y Half Width");
	if (i == 3) strcpy(data,"Length");
	return 0;
	}

