/*---------------------------------------------------------------------------
				PatchTool
				---------

	Patch tool class

	(C) Silicon Dream Ltd 1994

  ---------------------------------------------------------------------------

Changes:							Date:
* Created file							27/12/94
*/

#include <tool.h>

#include "resource.h"

#define POINT_BUFFER_SIZE	256

class PatchTool: public Tool
	{
	private:
		Vec		avecPoint[POINT_BUFFER_SIZE];
		ushort		usNumPoints;
		HanVertex	ahver[POINT_BUFFER_SIZE];
		ushort		usNumVerts;
		HanPatch	ahpat[POINT_BUFFER_SIZE-2];
		ushort		usNumPats;
		char		szErrTitle[20];
		HanObject	hobj;
		HanCoorSys	hcsysPatch;

	private:
		Redraw _cppdyn OnSelect(Vec &vec);
		Redraw _cppdyn OnUnSelect(bool *pbOkToChange);
		void _cppdyn OnConfigure();
		Redraw _cppdyn OnSet(Vec &vec);
		Redraw _cppdyn OnUndo();
		Redraw _cppdyn OnDo(Vec &vec);
		void _cppdyn DrawSoFar(HDC hdc, HanCoorSys hcsys, void *pvViewData, bool bInvalid);

	public:
		_cppdyn ~PatchTool() {};
	};

IMPLEMENT_OBJECT(PatchTool)

//---------------------------------------------------------------------------
// OnSelect - Called when the tool is selected from the control bar's
//	      button box

Redraw _cppdyn PatchTool::OnSelect(Vec &vec)
	{
	/* Initially no points */

	usNumPoints=0;

	/* Write message (resource with id IDS_ONSELECT) in status bar */

	WriteMessage(IDS_ONSELECT);
	return REDRAW_NONE;
	}

//---------------------------------------------------------------------------
// OnUnSelect - Simply remove points drawn

Redraw _cppdyn PatchTool::OnUnSelect(bool *pbOkToChange)
	{
	*pbOkToChange=TRUE;
	usNumPoints=0;
	EditInThisView(NULL_HANDLE);
	return REDRAW_REFRESH;
	}

//---------------------------------------------------------------------------
// OnConfigure - Calls up the autosmooth dialog for configuration

void _cppdyn PatchTool::OnConfigure()
	{
	AutosmoothDlg();
	return;
	}

//---------------------------------------------------------------------------
// OnSet - Called when the control bar's 'Set' button is pressed

Redraw _cppdyn PatchTool::OnSet(Vec &vec)
	{
	ulong		ulRef;
	CoorSysInfo	csi;

	/* Find currently selected object */

	if (usNumPoints==0)
		{
		hcsysPatch=hcsysActive;
		ulRef=0;
		hobj=GetNextSelected(hcsysPatch, &ulRef, OBJECT_HANDLE);
		if (hobj==NULL_HANDLE)
			{
			MessageBox(IDS_ERR_TITLE, IDS_NO_OBJECT_SELECTED, MB_ICONEXCLAMATION);
			return REDRAW_NONE;
			}
		if (GetNextSelected(hcsysPatch, &ulRef, OBJECT_HANDLE)!=NULL_HANDLE)
			{
			MessageBox(IDS_ERR_TITLE, IDS_ONLY_SELECT_ONE_OBJECT, MB_ICONEXCLAMATION);
			return REDRAW_NONE;
			}
		EditInThisView(hcsysPatch);
		}

	/* Do not allow user to create more points than buffer will hold */

	if (usNumPoints==POINT_BUFFER_SIZE)
		{
		MessageBox(IDS_ERR_TITLE, IDS_TOO_MANY_POINTS, MB_ICONEXCLAMATION);
		return REDRAW_NONE;
		}

	/* Add point to list */

	avecPoint[usNumPoints++]=vec;
	return REDRAW_TOOL;
	}

//---------------------------------------------------------------------------
// OnUndo - Called when 'Undo' is selected from the 'Edit' menu

Redraw _cppdyn PatchTool::OnUndo()
	{
	ushort			us, usNorm;
	HanNormal		ahnor[MAX_PATCH_EDGES];
	PatchInfo		pi;

	/* Remove patches */

	pi.ahver=NULL;
	pi.ahnor=ahnor;
	for (us=usNumPats; us--;)
		{
		pi.usNumEdges=MAX_PATCH_EDGES;
		QryPatch(hobj, ahpat[us], &pi);
		DelPatch(hobj, ahpat[us]);

		/* If curved, delete normals for this patch */

		if (!(pi.usFlags & PI_FLAT))
			{
			for (usNorm=pi.usNumEdges; usNorm--;)
				DelNormal(hobj, ahnor[usNorm]);	// Dont check for in use (all will eventually be del.)
			}
		}

	/* Remove all verticies */

	for (us=usNumVerts; us--;)
		DelVertex(hobj, ahver[us]);

	usNumPoints=0;
	EditInThisView(NULL_HANDLE);
	return REDRAW_ALL;
	}

//---------------------------------------------------------------------------
// OnDo - Called when the control bar's 'Do' button is pressed

Redraw _cppdyn PatchTool::OnDo(Vec &vec)
	{
	ushort			us;
	GeomErr			gerr;
	HanSurf			hsur;
	SurfType		st;

	/* Not enough points */

	if (usNumPoints<3)
		{
		MessageBox(IDS_ERR_TITLE, IDS_NOT_ENOUGH_POINTS);
		return REDRAW_TOOL;
		}

	/* Check to see if a surface is selected */

	hsur=hsurActive;
	if (hsur==NULL_HANDLE)
		{
		/* Use any old surface type, if one exists */

		GetFirstSurfType(&hsur);
		if (hsur==NULL_HANDLE)
			{
			/* No surfaces exist so define a default surface type */

			st.col.byRed=255;
			st.col.byGrn=255;
			st.col.byBlu=255;
			st.usFlags=0;
			st.usSpecRefChar=SRC_DULL;
			st.fShineCoef=1.0;
			st.fTransCoef=0.0;
			DefSurfType(&st, FALSE, &hsur);
			}
		}

	/* Create a Geometry vertex at each point */

	usNumVerts=usNumPoints;
	for (us=0; us<usNumVerts; us++)
		{
		gerr=::AddVertex(hobj, avecPoint[us], ahver+us);
		if (gerr!=GERR_OK)
			{
			/* Many errors can occur during patch creation. Rather than worrying
			   about creating our own error messages for each case, let Geometry
			   build the error string and stick it in a message box */

			usNumPoints=0;
			MessageBox(IDS_ERR_TITLE, gerr);
			return REDRAW_TOOL;
			}
		}

	/* Define patch on Genesis, using info from current settings */

	usNumPats=256;
	gerr=::DefPatch(hobj,
			usNumPoints,
			usSmoothFlags | DP_ATTEMPT_TO_FIX_PLANE,
			fSmoothAng,
			ahver,
			NULL,
			hsur,
			&usNumPats,
			ahpat);
	if (gerr!=GERR_OK)
		{
		/* Remove verticies */

		for (us=usNumPoints; us--;)
			DelVertex(hobj, ahver[us]);

		/* Get description of error from Geometry, and put it in
		   a message box */

		MessageBox(IDS_ERR_TITLE, gerr);
		}
	usNumPoints=0;
	EditInThisView(NULL_HANDLE);
	ModifiedScene();

	return REDRAW_ALL;
	}

//---------------------------------------------------------------------------
// DrawSoFar - Called when the view gets repainted and we're in the middle of
//	       constructing, so we can draw what we have so far

void _cppdyn PatchTool::DrawSoFar(HDC hdc, HanCoorSys hcsys, void *pvViewData, bool bInvalid)
	{
	HPEN			hpen, hpenOld;
	float			fStartX, fStartY, fEndX, fEndY;
	ushort			us;
	int			iOldMode;

	if (usNumPoints==0)
		return;

	/* Create solid and dotted green pens with which to draw the patch */

	hpen=CreatePen(PS_DOT, 1, RGB(0, 200, 0));
	hpenOld=(HPEN) SelectObject(hdc, (HGDIOBJ) hpen);
	iOldMode=SetBkMode(hdc, TRANSPARENT);

	/* Draw each edge of the patch so far */

	for (us=1; us<usNumPoints; us++)
		{
		Get3DLine(hcsysPatch, avecPoint[us], avecPoint[us-1],
			  &fStartX, &fStartY, &fEndX, &fEndY);
		MoveToEx(hdc, (int) fStartX, (int) fStartY, NULL);
		LineTo(hdc, (int) fEndX, (int) fEndY);
		}

	/* Draw endpoint marker */

	if (Get3DPoint(hcsysPatch, avecPoint[usNumPoints-1],
		       &fStartX, &fStartY)==GERR_OK)
		DrawMarker(hdc, (int) fStartX, (int) fStartY, MT_BOX);

	/* We must restore the state of the DC before returning */

	SetBkMode(hdc, iOldMode);
	SelectObject(hdc, hpenOld);
	DeleteObject(hpen);
	return;
	}
