/**********************************************************************
 *<
	FILE: SiteObject.cpp

	DESCRIPTION:	Appwizard generated plugin

	CREATED BY: 

	HISTORY: 

 *>	Copyright (c) 1997, All Rights Reserved.
 **********************************************************************/


#include "stdafx.h"



#include "SiteObject.h"

#pragma pack(push,8)

static void DrawAxis(ViewExp *vpt, const Matrix3 &tm, float length, BOOL sel=FALSE, BOOL frozen=FALSE);
static Box3 GetAxisBox(ViewExp *vpt, const Matrix3 &tm,float length,int resetTM);


#define MIN_ZOOM 0.0001f
#define RU_UPDATE WM_USER + 666


#define NUMVERTS 7
static Point3 arrow_side[7]=
{ 
	Point3( 0.000000, -1.000000 , 0.00000),
	Point3( 0.000000, -0.500000 , 0.40000),
	Point3( 0.000000, -0.500000,  0.20000),
	Point3( 0.000000, -0.000000,  0.20000),
	Point3( 0.000000, -0.000000, 0.00000),
	Point3( 0.000000, -0.500000, 0.00000),
	Point3( 0.000000, -0.500000, 0.00000)
};

static Point3 arrow_flat[7]=
{ 
	Point3(  -0.00000,  -1.000000,    0.0),
	Point3(   0.400000, -0.50000,     0.0),
	Point3(   0.200000, -0.50000,     0.0),
	Point3(   0.200000, -0.0,         0.0),
	Point3(  -0.200000, -0.0,         0.0),
	Point3(  -0.200000, -0.50000,     0.0),
	Point3(  -0.400000, -0.50000,     0.0)
};



//TODO: Add Parameter block indices for various parameters
#define PB_TRIGGER_COUNT		0
#define PB_SITE_SCALE			1

#define PB_TRIGGER_0			2
#define PB_TRIGGER_1			3
#define PB_TRIGGER_2			4
#define PB_TRIGGER_3			5
#define PB_TRIGGER_4			6
#define PB_TRIGGER_5			7
#define PB_TRIGGER_6			8
#define PB_TRIGGER_7			9
#define PB_TRIGGER_8			10
#define PB_TRIGGER_9			11
#define PB_TRIGGER_10			12
#define PB_TRIGGER_11			13
#define PB_TRIGGER_12			14
#define PB_TRIGGER_13			15
#define PB_TRIGGER_14			16
#define PB_TRIGGER_15			17


#define PB_TRIGGER_DEF(x) \
	ParamUIDesc( \
		PB_TRIGGER_##x, \
		TYPE_SINGLECHEKBOX,IDC_SPIN_TRIGGER_##x)


//TODO: Add ParamUIDesc's for the various parameters
static ParamUIDesc descParam[] = 
{
	// Spinner
	ParamUIDesc(
		PB_TRIGGER_COUNT,
		EDITTYPE_INT,
		IDC_EDIT_NUM_TRIGGER,IDC_SPIN_NUM_TRIGGER,
		0,32,
		32),
	ParamUIDesc(
		PB_SITE_SCALE,
		EDITTYPE_FLOAT,
		IDC_EDIT_SIZE,IDC_SPIN_SIZE,
		0.0f,1000.0f,
		10.0f),

	PB_TRIGGER_DEF(0),
	PB_TRIGGER_DEF(1),
	PB_TRIGGER_DEF(2),
	PB_TRIGGER_DEF(3),
	PB_TRIGGER_DEF(4),
	PB_TRIGGER_DEF(5),
	PB_TRIGGER_DEF(6),
	PB_TRIGGER_DEF(7),
	PB_TRIGGER_DEF(8),
	PB_TRIGGER_DEF(9),
	PB_TRIGGER_DEF(10),
	PB_TRIGGER_DEF(11),
	PB_TRIGGER_DEF(12),
	PB_TRIGGER_DEF(13),
	PB_TRIGGER_DEF(14),
	PB_TRIGGER_DEF(15)
}; 	

#define PARAMDESC_LENGTH 18
#define PBLOCK_LENGTH	18


//TODO: Add ParamBlockDescID's for the various parameters
static ParamBlockDescID descVer1[] = {
		{ TYPE_INT, NULL, FALSE, 0 },
		{ TYPE_FLOAT, NULL, FALSE, 1 },
		{ TYPE_BOOL, NULL, TRUE, 2 },
		{ TYPE_BOOL, NULL, TRUE, 3 },
		{ TYPE_BOOL, NULL, TRUE, 4 },
		{ TYPE_BOOL, NULL, TRUE, 5 },
		{ TYPE_BOOL, NULL, TRUE, 6 },
		{ TYPE_BOOL, NULL, TRUE, 7 },
		{ TYPE_BOOL, NULL, TRUE, 8 },
		{ TYPE_BOOL, NULL, TRUE, 9 },
		{ TYPE_BOOL, NULL, TRUE, 10 },
		{ TYPE_BOOL, NULL, TRUE, 11 },
		{ TYPE_BOOL, NULL, TRUE, 12 },
		{ TYPE_BOOL, NULL, TRUE, 13 },
		{ TYPE_BOOL, NULL, TRUE, 14 },
		{ TYPE_BOOL, NULL, TRUE, 15 },
		{ TYPE_BOOL, NULL, TRUE, 16 },
		{ TYPE_BOOL, NULL, TRUE, 17 }
	};

#define CURRENT_DESCRIPTOR descVer1
#define CURRENT_VERSION	1


// class variable for point class.
HWND SiteObject::m_hParams = NULL;
IObjParam *SiteObject::m_iObjParams;
IParamMap *SiteObject::m_pmapParam = NULL;

BOOL CALLBACK PointParamProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
	SiteObject *po = (SiteObject*)GetWindowLong(hWnd,GWL_USERDATA);
	if (!po && msg!=WM_INITDIALOG) return FALSE;

	return TRUE;
} 

ParamDimension *SiteObject::GetParameterDim(int pbIndex)
{
	switch (pbIndex) {
		case PB_TRIGGER_COUNT:
			return defaultDim;
		case PB_SITE_SCALE:
			return defaultDim;
		default:
			return stdNormalizedDim;
		}
}


Animatable* SiteObject::SubAnim(int i)
{
	switch (i) {
		case 0: return m_pblock; // Parameter block
		default: return NULL;
		}
}


TSTR SiteObject::SubAnimName(int i)

{
	switch (i) {
		case 0: return TSTR(_T("Parameters"));
		default: return TSTR(_T(""));
		}
	}



void SiteObject::BeginEditParams(
		IObjParam *ip, ULONG flags,Animatable *prev)
{	
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	HINSTANCE loc_hInstance = AfxGetResourceHandle ();

	m_iObjParams = ip;
	if (m_pmapParam) 
	{		
		// Left over
		m_pmapParam->SetParamBlock(m_pblock);
	} else 
	{		
		
		// Gotta make a new one.
		m_pmapParam = CreateCPParamMap(
			descParam,PARAMDESC_LENGTH,
			m_pblock,
			ip,
			loc_hInstance,
			MAKEINTRESOURCE(IDD_SITE_PANEL),
			GetString(IDS_PARAMS),
			0);
		
	}
}
		
void SiteObject::EndEditParams(IObjParam *ip, ULONG flags,Animatable *next)
{	
	
	if (flags&END_EDIT_REMOVEUI ) 
	{		
		DestroyCPParamMap(m_pmapParam);
		m_pmapParam = NULL;		
	}	
	m_iObjParams = NULL;
}

ObjectState SiteObject::Eval(TimeValue time)
{
	return ObjectState(this);
}

#define BOOL_CONTROL_CLASS_ID Class_ID(0x984b8d27,0x938f3e43)

SiteObject::SiteObject()
{	
	m_suspendSnap = FALSE;
	m_triggerCount = 0;
	m_siteScale = 0.0f;


	MakeRefByID( FOREVER, 0, CreateParameterBlock( descVer1, PARAMDESC_LENGTH, CURRENT_VERSION ) );

#if 0
	Control *c;
	
	c = (Control *) CreateInstance(CTRL_FLOAT_CLASS_ID,BOOL_CONTROL_CLASS_ID); 
	m_pblock->SetController(PB_TRIGGER_0, c, TRUE);
	
	c = (Control *) CreateInstance(CTRL_FLOAT_CLASS_ID,BOOL_CONTROL_CLASS_ID); 
	m_pblock->SetController(PB_TRIGGER_1, c, TRUE);

	c = (Control *) CreateInstance(CTRL_FLOAT_CLASS_ID,BOOL_CONTROL_CLASS_ID); 
	m_pblock->SetController(PB_TRIGGER_2, c, TRUE);

	c = (Control *) CreateInstance(CTRL_FLOAT_CLASS_ID,BOOL_CONTROL_CLASS_ID); 
	m_pblock->SetController(PB_TRIGGER_3, c, TRUE);

	c = (Control *) CreateInstance(CTRL_FLOAT_CLASS_ID,BOOL_CONTROL_CLASS_ID); 
	m_pblock->SetController(PB_TRIGGER_4, c, TRUE);

	c = (Control *) CreateInstance(CTRL_FLOAT_CLASS_ID,BOOL_CONTROL_CLASS_ID); 
	m_pblock->SetController(PB_TRIGGER_5, c, TRUE);

	c = (Control *) CreateInstance(CTRL_FLOAT_CLASS_ID,BOOL_CONTROL_CLASS_ID); 
	m_pblock->SetController(PB_TRIGGER_6, c, TRUE);

	c = (Control *) CreateInstance(CTRL_FLOAT_CLASS_ID,BOOL_CONTROL_CLASS_ID); 
	m_pblock->SetController(PB_TRIGGER_7, c, TRUE);

	c = (Control *) CreateInstance(CTRL_FLOAT_CLASS_ID,BOOL_CONTROL_CLASS_ID); 
	m_pblock->SetController(PB_TRIGGER_8, c, TRUE);

	c = (Control *) CreateInstance(CTRL_FLOAT_CLASS_ID,BOOL_CONTROL_CLASS_ID); 
	m_pblock->SetController(PB_TRIGGER_9, c, TRUE);

	c = (Control *) CreateInstance(CTRL_FLOAT_CLASS_ID,BOOL_CONTROL_CLASS_ID); 
	m_pblock->SetController(PB_TRIGGER_10, c, TRUE);

	c = (Control *) CreateInstance(CTRL_FLOAT_CLASS_ID,BOOL_CONTROL_CLASS_ID); 
	m_pblock->SetController(PB_TRIGGER_11, c, TRUE);

	c = (Control *) CreateInstance(CTRL_FLOAT_CLASS_ID,BOOL_CONTROL_CLASS_ID); 
	m_pblock->SetController(PB_TRIGGER_12, c, TRUE);

	c = (Control *) CreateInstance(CTRL_FLOAT_CLASS_ID,BOOL_CONTROL_CLASS_ID); 
	m_pblock->SetController(PB_TRIGGER_13, c, TRUE);

	c = (Control *) CreateInstance(CTRL_FLOAT_CLASS_ID,BOOL_CONTROL_CLASS_ID); 
	m_pblock->SetController(PB_TRIGGER_14, c, TRUE);

	c = (Control *) CreateInstance(CTRL_FLOAT_CLASS_ID,BOOL_CONTROL_CLASS_ID); 
	m_pblock->SetController(PB_TRIGGER_15, c, TRUE);

#endif

	m_pblock->SetValue(PB_TRIGGER_0, 0, 0);
	m_pblock->SetValue(PB_TRIGGER_1, 0, 0);
	m_pblock->SetValue(PB_TRIGGER_2, 0, 0);
	m_pblock->SetValue(PB_TRIGGER_3, 0, 0);
	m_pblock->SetValue(PB_TRIGGER_4, 0, 0);
	m_pblock->SetValue(PB_TRIGGER_5, 0, 0);
	m_pblock->SetValue(PB_TRIGGER_6, 0, 0);
	m_pblock->SetValue(PB_TRIGGER_7, 0, 0);
	m_pblock->SetValue(PB_TRIGGER_8, 0, 0);
	m_pblock->SetValue(PB_TRIGGER_9, 0, 0);
	m_pblock->SetValue(PB_TRIGGER_10, 0, 0);
	m_pblock->SetValue(PB_TRIGGER_11, 0, 0);
	m_pblock->SetValue(PB_TRIGGER_12, 0, 0);
	m_pblock->SetValue(PB_TRIGGER_13, 0, 0);
	m_pblock->SetValue(PB_TRIGGER_14, 0, 0);
	m_pblock->SetValue(PB_TRIGGER_15, 0, 0);



	m_pblock->SetValue(PB_TRIGGER_COUNT,0,m_triggerCount);
	m_pblock->SetValue(PB_SITE_SCALE,0,m_siteScale);


}


RefTargetHandle SiteObject::GetReference(int i)  
{ 
	if (i==0) return m_pblock;
	return NULL;
}

// This methods sets the ith reference - there are two.
void SiteObject::SetReference(int i, RefTargetHandle rtarg)
{
	if (i==0)
	{
		m_pblock = (IParamBlock *)rtarg;
	}
}

int SiteObjectCreateCallBack::proc(ViewExp *vpt,int msg, int point, int flags, IPoint2 m, Matrix3& mat ) 
{	
	if (msg==MOUSE_POINT||msg==MOUSE_MOVE) 
	{
		switch(point) 
		{
			case 0:
				m_ob->m_suspendSnap = TRUE;
				m_p0 = vpt->SnapPoint(m,m,NULL,SNAP_IN_PLANE);
				mat.SetTrans(m_p0);
				break;
			case 1:
//				mat.SetTrans(vpt->SnapPoint(m,m,NULL,SNAP_IN_PLANE));
				m_p1 = vpt->SnapPoint(m,m,NULL,SNAP_IN_PLANE);

				m_ob->m_pblock->SetValue(PB_SITE_SCALE,0,Length(m_p1-m_p0));


				if (msg==MOUSE_POINT) 
				{
					m_ob->m_suspendSnap = FALSE;
					return 0;
				}
				break;			
		}
	} 
	else 
	{
		if (msg == MOUSE_ABORT) 
		{		
			return CREATE_ABORT;
		}
	}
	return 1;
}

static SiteObjectCreateCallBack siteObjectCreateCB;

CreateMouseCallBack* SiteObject::GetCreateMouseCallBack()
{
	siteObjectCreateCB.SetObj(this);
	return(&siteObjectCreateCB);
}

RefTargetHandle SiteObject::Clone(RemapDir& remap) 
{
	SiteObject* newob = new SiteObject();	
	newob->m_triggerCount = m_triggerCount;
	newob->m_siteScale = m_siteScale;

	newob->ReplaceReference(0, m_pblock->Clone(remap));

	return(newob);
}




RefResult SiteObject::NotifyRefChanged(
		Interval changeInt, 
		RefTargetHandle hTarget, 
   		PartID& partID, 
   		RefMessage message) 
{
	switch (message) 
	{
		case REFMSG_CHANGE:
		{
			if (m_pblock)
			{


				if (m_iObjParams)
				{
					m_pblock->GetValue(PB_SITE_SCALE,m_iObjParams->GetTime(),m_siteScale, FOREVER);

				}
				else
				{	
					m_pblock->GetValue(PB_SITE_SCALE, 0,m_siteScale, FOREVER);	
				}



			}

			if (m_pmapParam) m_pmapParam->Invalidate();
			NotifyDependents(FOREVER,PART_OBJ,REFMSG_CHANGE);
			if (m_iObjParams) m_iObjParams->RedrawViews(m_iObjParams->GetTime());

			break;
		}

		case REFMSG_GET_PARAM_DIM: 
		{
			GetParamDim *gpd = (GetParamDim*)partID;
			switch (gpd->index) 
			{				
				case 0:
				default: gpd->dim = defaultDim; break;
			}			
			return REF_STOP; 
		}

		case REFMSG_GET_PARAM_NAME: 
		{
			GetParamName *gpn = (GetParamName*)partID;
			switch (gpn->index) 
			{			
				case  PB_TRIGGER_COUNT:	gpn->name = TSTR(_T("Trigger Count")); break;
				case  PB_SITE_SCALE:	gpn->name = TSTR(_T("Site Scale")); break;
				case  PB_TRIGGER_0:	gpn->name = TSTR(_T("Trigger 0")); break;
				case  PB_TRIGGER_1:	gpn->name = TSTR(_T("Trigger 1")); break;
				case  PB_TRIGGER_2:	gpn->name = TSTR(_T("Trigger 2")); break;
				case  PB_TRIGGER_3:	gpn->name = TSTR(_T("Trigger 3")); break;
				case  PB_TRIGGER_4:	gpn->name = TSTR(_T("Trigger 4")); break;
				case  PB_TRIGGER_5:	gpn->name = TSTR(_T("Trigger 5")); break;
				case  PB_TRIGGER_6:	gpn->name = TSTR(_T("Trigger 6")); break;
				case  PB_TRIGGER_7:	gpn->name = TSTR(_T("Trigger 7")); break;
				case  PB_TRIGGER_8:	gpn->name = TSTR(_T("Trigger 8")); break;
				case  PB_TRIGGER_9:	gpn->name = TSTR(_T("Trigger 9")); break;
				case  PB_TRIGGER_10: gpn->name = TSTR(_T("Trigger 10")); break;
				case  PB_TRIGGER_11: gpn->name = TSTR(_T("Trigger 11")); break;
				case  PB_TRIGGER_12: gpn->name = TSTR(_T("Trigger 12")); break;
				case  PB_TRIGGER_13: gpn->name = TSTR(_T("Trigger 13")); break;
				case  PB_TRIGGER_14: gpn->name = TSTR(_T("Trigger 14")); break;
				case  PB_TRIGGER_15: gpn->name = TSTR(_T("Trigger 15")); break;
				default:		gpn->name = TSTR(_T("")); break;
			}
			return REF_STOP; 
		}
	}


	return REF_SUCCEED;
}


#define TRIGGER_COUNT_CHUNK		0x0100
#define SITE_SCALE_CHUNK		0x0110
#define TRIGGER_CHUNK			0x0120


IOResult SiteObject::Load(ILoad *iload)
{

	ULONG nb;
	IOResult res = IO_OK;

	
	while (IO_OK==(res=iload->OpenChunk())) 
	{
		switch (iload->CurChunkID()) 
		{
			case TRIGGER_COUNT_CHUNK:
				res = iload->Read(&m_triggerCount,sizeof(m_triggerCount),&nb);
				break;
			case SITE_SCALE_CHUNK:
				res = iload->Read(&m_siteScale,sizeof(m_siteScale),&nb);
				break;
			//case TRIGGER_CHUNK:
			//	res = iload->Read(&trigger,sizeof(int)*16,&nb);
			//	break;
		}

		res = iload->CloseChunk();
		if (res!=IO_OK)  
		{
			return res;
		}
	}



	return IO_OK;
}

IOResult SiteObject::Save(ISave *isave)
{

	ULONG nb;

	isave->BeginChunk(TRIGGER_COUNT_CHUNK);
	isave->Write(&m_triggerCount,sizeof(m_triggerCount),&nb);
	isave->EndChunk();

	isave->BeginChunk(SITE_SCALE_CHUNK);
	isave->Write(&m_siteScale,sizeof(m_siteScale),&nb);
	isave->EndChunk();
	
	//isave->BeginChunk(TRIGGER_CHUNK);
	//isave->Write(&trigger,sizeof(int)*16,&nb);
	//isave->EndChunk();

	return IO_OK;
}





void SiteObject::SetExtendedDisplay(int flags)
{
	m_extDispFlags = flags;
}

void SiteObject::GetLocalBoundBox(TimeValue t, INode* inode, ViewExp* vpt, Box3& box ) 
{
	Matrix3 tm(1);
	tm.SetTrans(inode->GetObjectTM(t).GetTrans());
	box = GetAxisBox(vpt,tm,m_siteScale, TRUE);
}

void SiteObject::GetWorldBoundBox(TimeValue t, INode* inode, ViewExp* vpt, Box3& box )
{
	Matrix3 tm;
	tm = inode->GetObjectTM(t);
	if(!(m_extDispFlags & EXT_DISP_ZOOM_EXT))
	{
		box = GetAxisBox(vpt,tm,m_siteScale, FALSE);
	}
	else
	{
		box = Box3(tm.GetTrans(), tm.GetTrans());
	}
}


// From BaseObject
int SiteObject::HitTest(TimeValue t, INode *inode, int type, int crossing, int flags, IPoint2 *p, ViewExp *vpt) 
{
	Matrix3 tm(1);	
	HitRegion hitRegion;
	DWORD	savedLimits;
	Point3 pt(0,0,0);

	GraphicsWindow *gw = vpt->getGW();	
   	tm = inode->GetObjectTM(t);		
	MakeHitRegion(hitRegion, type, crossing, 4, p);

	gw->setRndLimits(((savedLimits = gw->getRndLimits())|GW_PICK)&~GW_ILLUM);
	gw->setHitRegion(&hitRegion);
	gw->clearHitCode();

	DrawAxis(vpt,tm,m_siteScale);
	
	vpt->getGW()->setTransform(tm);
	vpt->getGW()->marker(&pt,X_MRKR);

	gw->setRndLimits(savedLimits);
	
	if((hitRegion.type != POINT_RGN) && !hitRegion.crossing)
	{
		return TRUE;
	}
	return gw->checkHitCode();
}

void SiteObject::Snap(TimeValue t, INode* inode, SnapInfo *snap, IPoint2 *p, ViewExp *vpt)
{

//	if(m_suspendSnap)
//	{
//		return;
//	}

	Matrix3 tm = inode->GetObjectTM(t);	
	GraphicsWindow *gw = vpt->getGW();	
	gw->setTransform(tm);

	Matrix3 invPlane = Inverse(snap->plane);
	// Check for upside-down coordinate system in viewport
	float ybias = (float)gw->getWinSizeY() - 1.0f;

	// Make sure the vertex priority is active and at least as important as the best snap so far
	if(snap->vertPriority > 0 && snap->vertPriority <= snap->priority) 
	{
		Point2 fp = Point2((float)p->x, (float)p->y);
		Point3 screen3;
		Point2 screen2;

		Point3 thePoint(0,0,0);
		// If constrained to the plane, make sure this point is in it!
		if(snap->snapType == SNAP_2D || snap->flags & SNAP_IN_PLANE) 
		{
			Point3 test = thePoint * tm * invPlane;
			if(fabs(test.z) > 0.0001)	// Is it in the plane (within reason)?
			{
				return;
			}
		}
		//gw->transPointFWin(&thePoint,&screen3);  //this is for MAX 1.2
		gw->transPoint(&thePoint, &screen3);
		screen3.y = ybias - screen3.y;
		screen2.x = screen3.x;
		screen2.y = screen3.y;

		// Are we within the snap radius?
		int len = (int)Length(screen2 - fp);
		if(len <= snap->strength) 
		{
			// Is this priority better than the best so far?
			if(snap->vertPriority < snap->priority) 
			{
				snap->priority = snap->vertPriority;
				snap->bestWorld = thePoint * tm;
				snap->bestScreen = screen2;
				snap->bestDist = len;
			}
			else
			if(len < snap->bestDist) 
			{
				snap->priority = snap->vertPriority;
				snap->bestWorld = thePoint * tm;
				snap->bestScreen = screen2;
				snap->bestDist = len;
			}
		}
	}
}


int SiteObject::Display(TimeValue t, INode* inode, ViewExp *vpt, int flags) 
{
	Matrix3 tm = inode->GetObjectTM(t);
	Point3 pt(0,0,0);
	vpt->getGW()->setTransform(tm);
	
	DrawAxis(vpt,tm,m_siteScale,inode->Selected(),inode->IsFrozen());
	
	if(!inode->IsFrozen())
	{
		vpt->getGW()->setColor(LINE_COLOR,1.0f,0.9f,0.0f);
	}
	vpt->getGW()->marker(&pt,X_MRKR);
	return(0);
	
}




/*--------------------------------------------------------------------*/
// 
// Stole this from scene.cpp
// Probably couldn't hurt to make an API...
//
//


static void Text( ViewExp *vpt, TCHAR *str, Point3 &pt )
{	
	vpt->getGW()->text( &pt, str );	
}

static void DrawAStar( ViewExp *vpt, float len )
{
	Point3 v[NUMVERTS+1];
	//we'll scale the points to fill out the dlg size, almost
	float mult = len;
/*
	for(int i= 0; i < NUMVERTS-1;i++){ 
		v[0] = mult * roseverts[i];
		v[1] = mult * roseverts[i+1];
		vpt->getGW()->polyline( 2, v, NULL, NULL, FALSE, NULL );
		}

	//close up the polyline
	v[0] = mult * roseverts[0];
	v[1] = mult * roseverts[NUMVERTS-1];
	vpt->getGW()->polyline( 2, v, NULL, NULL, FALSE, NULL );
*/
	for (int k= 0; k<NUMVERTS;k++)
	{
		v[k]=arrow_side[k]*mult;
	}
 	vpt->getGW()->polyline( NUMVERTS, v, NULL, NULL, TRUE, NULL );


	for (k= 0; k<NUMVERTS;k++)
	{
		v[k]=arrow_flat[k]*mult;
	}
 	vpt->getGW()->polyline( NUMVERTS, v, NULL, NULL, TRUE, NULL );


	//draw an extra line in the north driection
	//	v[0] = Point3(0.0f,0.0f,0.0f);
	//	v[1] = mult * roseverts[3];
	//	vpt->getGW()->polyline( 2, v, NULL, NULL, FALSE, NULL );
}

#define ZFACT (float).005;
#define AXIS_COLOR		0.4f,0.4f,0.4f
#define SELAXIS_COLOR	1.0f,1.0f,1.0f

static void DrawAxis( ViewExp *vpt, const Matrix3 &tm, float length, BOOL sel, BOOL frozen )
{
	Matrix3 tmn = tm;
	//float zoom;
	int limits;	

	// Get width of viewport in world units:  --DS
	//zoom = vpt->GetScreenScaleFactor(tmn.GetTrans())*ZFACT;
	
	//tmn.Scale( Point3(zoom,zoom,zoom) );
	vpt->getGW()->setTransform( tmn );

	limits = vpt->getGW()->getRndLimits();
//	vpt->getGW()->setRndLimits( limits & ~GW_Z_BUFFER );  JH

	if (sel) 
	{
		vpt->getGW()->setColor( TEXT_COLOR, SELAXIS_COLOR );
		vpt->getGW()->setColor( LINE_COLOR, SELAXIS_COLOR );
	} 
	else if (!frozen) 
	{
		vpt->getGW()->setColor( TEXT_COLOR, AXIS_COLOR );
		vpt->getGW()->setColor( LINE_COLOR, AXIS_COLOR );
	}
#if 0
	float corners = .9f * length;
	Text( vpt, GetString(IDS_EAST_MARK), Point3(corners,0.0f,0.0f) ); 
	Text( vpt, GetString(IDS_WEST_MARK), Point3(-corners,0.0f,0.0f) ); 
	Text( vpt, GetString(IDS_NORTH_MARK), Point3(0.0f,corners,0.0f) ); 
	Text( vpt, GetString(IDS_SOUTH_MARK), Point3(0.0f,-corners,0.0f) ); 
#endif
	DrawAStar( vpt, length);	
	
	vpt->getGW()->setRndLimits( limits );
}

static Box3 GetAxisBox(ViewExp *vpt, const Matrix3 &tm,float length,int resetTM)
{
	Matrix3 tmn = tm;

	float zoom;

	// Get width of viewport in world units:  --DS
	zoom = vpt->GetScreenScaleFactor(tmn.GetTrans())*ZFACT;
	if (zoom < MIN_ZOOM) zoom = 1.0f;
//	tmn.Scale(Point3(zoom,zoom,zoom));
	length *= zoom;
	if(resetTM)
	{
		tmn.IdentityMatrix();
	}



	Box3 box;

	box += Point3(0.0f,			0.0f,			0.0f) * tmn;
	box += Point3(4.0f*length,	0.0f,			0.0f) * tmn;
	box += Point3(0.0f,			-9.0f*length,	0.0f) * tmn;
	box += Point3(0.0f,			0.0f,			4.0f*length) * tmn;	
	box += Point3(-4.0f*length,	0.0f,			0.0f) * tmn;
	box += Point3(0.0f,			0.0f,			-4.0f*length) * tmn;
	box.EnlargeBy(10.0f/zoom);
	return box;
}

#pragma pack(pop)
