/* (c) 1999-2000 Tino Schwarze, see COPYING for details */
/**
 * implementation of class cHoledPlane
 *
 * -lglut
	*/

// get glut library functions
#include <GL/glut.h>

#include "cHoledPlane.hh"

/**
 * default constructor w/ optional object name
 	* @param name name of object (optional)
	*/
cHoledPlane::cHoledPlane (
	cEventDispatcher *disp,
	const char *name)
: 	cPlane (disp, name),
	mHoleFromX (-1.0),
	mHoleToX (-1.0),
	mHoleFromY (-1.0),
	mHoleToY (-1.0)
{
	ENTER_OBJECT_METHOD("cHoledPlane::cHoledPlane (const char *)");
}


/**
 * constructor w/ optional size and object name
 	* @param size_x x size of plane (default: 1.0)
 	* @param size_y y size of plane (default: 1.0)
 	* @param name name of object (optional)
	*/
cHoledPlane::cHoledPlane (
	cEventDispatcher *disp,
	GLdouble size_x, 
	GLdouble size_y, 
	const char *name)
:	cPlane (disp, size_x, size_y, name),
	mHoleFromX (-1.0),
	mHoleToX (-1.0),
	mHoleFromY (-1.0),
	mHoleToY (-1.0)
{
	ENTER_OBJECT_METHOD("cHoledPlane::cHoledPlane (GLdouble, const char *)");
}


/**
 * constructor w/ optional size and object name
 	* @param size_x x size of plane (default: 1.0)
 	* @param size_y y size of plane (default: 1.0)
	* @param hole_start_percent_x where does the hole start in x direction?
	* @param hole_end_percent_x where does the hole end in x direction?
	* @param hole_start_percent_y where does the hole start in x direction?
	* @param hole_end_percent_y where does the hole end in x direction?
 	* @param name name of object (optional)
	*/
cHoledPlane::cHoledPlane (
	cEventDispatcher *disp,
	GLdouble size_x, 
	GLdouble size_y, 
	GLfloat hole_start_percent_x,
	GLfloat hole_end_percent_x,
	GLfloat hole_start_percent_y,
	GLfloat hole_end_percent_y,
	const char *name)
:	cPlane (disp, size_x, size_y, name),
	mHoleFromX (hole_start_percent_x),
	mHoleToX (hole_end_percent_x),
	mHoleFromY (hole_start_percent_y),
	mHoleToY (hole_end_percent_y)
{
	ENTER_OBJECT_METHOD("cHoledPlane::cHoledPlane (GLdouble, const char *)");
}

/**
 * constructor w/ initialization of size, solid and name
 	* @param size_x x size of plane (default: 1.0)
 	* @param size_y y size of plane (default: 1.0)
	* @param solid solid or wire frame? (default: solid)
	* @param hole_start_percent_x where does the hole start in x direction?
	* @param hole_end_percent_x where does the hole end in x direction?
	* @param hole_start_percent_y where does the hole start in x direction?
	* @param hole_end_percent_y where does the hole end in x direction?
	* @param name name of object (optional)
 	*/
cHoledPlane::cHoledPlane (
	cEventDispatcher *disp,
	GLdouble size_x, 
	GLdouble size_y, 
	GLfloat hole_start_percent_x,
	GLfloat hole_end_percent_x,
	GLfloat hole_start_percent_y,
	GLfloat hole_end_percent_y,
	tePlaneType solid,
	const char *name)
: 	cPlane (disp, size_x, size_y, solid, name), 
	mHoleFromX (hole_start_percent_x),
	mHoleToX (hole_end_percent_x),
	mHoleFromY (hole_start_percent_y),
	mHoleToY (hole_end_percent_y)
{
	ENTER_OBJECT_METHOD ("cHoledPlane::cHoledPlane (GLdouble size, GLboolean solid)");
	// this is enough (mDisplayList is aquired during Init()
}

/**
 * constructor w/ initialization of size, solid and name
 	* @param size_x x size of plane (default: 1.0)
 	* @param size_y y size of plane (default: 1.0)
	* @param hole_start_percent_x where does the hole start in x direction?
	* @param hole_end_percent_x where does the hole end in x direction?
	* @param hole_start_percent_y where does the hole start in x direction?
	* @param hole_end_percent_y where does the hole end in x direction?
	* @param solid solid or wire frame? (default: solid)
	* @param resolution subdivisions per side
	* @param name name of object (optional)
 	*/
cHoledPlane::cHoledPlane (
	cEventDispatcher *disp,
	GLdouble size_x, 
	GLdouble size_y, 
	GLfloat hole_start_percent_x,
	GLfloat hole_end_percent_x,
	GLfloat hole_start_percent_y,
	GLfloat hole_end_percent_y,
	tePlaneType solid,
	int resolution,
	const char *name)
: 	cPlane (disp, size_x, size_y, solid, resolution, name), 
	mHoleFromX (hole_start_percent_x),
	mHoleToX (hole_end_percent_x),
	mHoleFromY (hole_start_percent_y),
	mHoleToY (hole_end_percent_y)
{
	ENTER_OBJECT_METHOD ("cHoledPlane::cHoledPlane (GLdouble size, GLboolean solid)");
	// this is enough (mDisplayList is aquired during Init()
}

/**
 * destructor
 	*/
cHoledPlane::~cHoledPlane ()
{
	ENTER_OBJECT_METHOD ("cHoledPlane::~cHoledPlane ()");
	// cleanup done by cPlane::~cPlane
}

// DrawThisObject is inherited

/**
 * create solid plane
 	*/
void cHoledPlane::MakeSolidPlane ()
{
#define OUTOFBOUND(x,a,b) ((x < a) || (x > b))

	// check whether we've got a "valid" hole (remember: it's percentages)
	if (OUTOFBOUND (mHoleFromX, 0, 100) ||
		OUTOFBOUND (mHoleToX, 0, 100) ||
		OUTOFBOUND (mHoleFromY, 0, 100) ||
		OUTOFBOUND (mHoleToY, 0, 100))
	{
		cPlane::MakeSolidPlane ();
		return;
	}

	if (mHoleFromX > mHoleToX)
	{
		const GLfloat totmp = mHoleToX;
		mHoleToX = mHoleFromX;
		mHoleFromX = totmp;
	}

	if (mHoleFromY > mHoleToY)
	{
		const GLfloat totmp = mHoleToY;
		mHoleToY = mHoleFromY;
		mHoleFromY = totmp;
	}

	GLfloat start_x = -mSizeX/2.0;
	GLfloat first_start_x = start_x;

	GLfloat start_tx = mTexFromX;
	GLfloat first_start_tx = start_tx;

	GLfloat start_y = -mSizeY/2.0;
	GLfloat start_ty = mTexFromY;

	const GLfloat hole_start_x = start_x + mSizeX * mHoleFromX/100.0;
	const GLfloat hole_end_x = start_x + mSizeX * mHoleToX/100.0;
	const GLfloat hole_start_y = start_y + mSizeY * mHoleFromY/100.0;
	const GLfloat hole_end_y = start_y + mSizeY * mHoleToY/100.0;

	const GLfloat dist_tx = (mTexToX - mTexFromX);
	const GLfloat dist_ty = (mTexToY - mTexFromY);

	const GLfloat hole_start_tx = mTexFromX + dist_tx * mHoleFromX/100.0;
	const GLfloat hole_end_tx = mTexFromX + dist_tx * mHoleToX/100.0;
	const GLfloat hole_start_ty = mTexFromY + dist_ty * mHoleFromY/100.0;
	const GLfloat hole_end_ty = mTexFromY + dist_ty * mHoleToY/100.0;

	const GLfloat x_end_arr[3] = { hole_start_x, hole_end_x, mSizeX/2.0 };
	const GLfloat y_end_arr[3] = { hole_start_y, hole_end_y, mSizeY/2.0 };
	const GLfloat tx_end_arr[3] = { hole_start_tx, hole_end_tx, mTexToX };
	const GLfloat ty_end_arr[3] = { hole_start_ty, hole_end_ty, mTexToY };

	GLfloat end_y = start_y;
	GLfloat end_ty = start_ty;

	for (int yapos = 0; yapos < 3; yapos ++)
	{
		start_y = end_y;
		start_ty = end_ty;
		end_y = y_end_arr[yapos];
		end_ty = ty_end_arr[yapos];

		GLfloat end_x = first_start_x;
		GLfloat end_tx = first_start_tx;

		const GLfloat diff_y = (end_y - start_y);
		const GLfloat diff_ty = (end_ty - start_ty);
		const GLfloat step_y = (diff_y/(mResolution));
		const GLfloat step_ty = (diff_ty)/(mResolution);

		for (int xapos = 0; xapos < 3; xapos++)
		{
			start_x = end_x;
			start_tx = end_tx;
			end_x = x_end_arr[xapos];
			end_tx = tx_end_arr[xapos];

			// skip the hole
			if ((xapos == 1) && (yapos == 1))
				continue;

			const GLfloat diff_x = (end_x - start_x);
			const GLfloat diff_tx = (end_tx - start_tx);
			const GLfloat step_x = (diff_x/(mResolution));
			const GLfloat step_tx = (diff_tx)/(mResolution);

			GLfloat cur_x, cur_tx;
			GLfloat cur_y = start_y, cur_ty = start_ty;

			// normal points "up" in Z direction
			glNormal3f (0.0, 0.0, 1.0);

			for (int y = 0; y < mResolution; y++)
			{
				const GLfloat next_y = cur_y + step_y;
				const GLfloat next_ty = cur_ty + step_ty;

				glBegin (GL_TRIANGLE_STRIP);

				cur_x = start_x;
				cur_tx = start_tx;

				for (int x = 0; x <= mResolution; x++)
				{
					glTexCoord2f (cur_tx, next_ty);
					glVertex3f (cur_x, next_y, 0);
					glTexCoord2f (cur_tx, cur_ty);
					glVertex3f (cur_x, cur_y, 0);

					cur_x += step_x;
					cur_tx += step_tx;
				}	// X-loop within region

				glEnd ();

				cur_y = next_y;
				cur_ty = next_ty;
			}	// Y-loop within

		}	// X-loop for regions

	}	// Y-loop for regions

}

/**
 * create wire framed plane
 	*/
void cHoledPlane::MakeWirePlane ()
{
	cerr << "MakeWirePlane not yet supported." << endl;
}
