#include "lib_hair.h"
#include "c4d_objectdata.h"
#include "c4d_scenehookplugin.h"

//////////////////////////////////////////////////////////////////////////

HairObjectLib *lib_hair = NULL;
HairColliderLib *lib_hair_collider = NULL;

static HairObjectLib *CheckHairObjectLib(LONG offset)
{
	return (HairObjectLib*)CheckLib(LIBRARY_HAIR,offset,(C4DLibrary**)&lib_hair);
}

static HairColliderLib *CheckHairColliderLib(LONG offset)
{
	return (HairColliderLib*)CheckLib(LIBRARY_HAIR_COLLIDER,offset,(C4DLibrary**)&lib_hair_collider);
}

#define HairObjectLibCall(b) 	HairObjectLib *lib = CheckHairObjectLib(LIBOFFSET(HairObjectLib, b)); \
															if (!lib || !lib->b) return; \
															(lib->b)

#define HairObjectLibCallR(a,b)  HairObjectLib *lib = CheckHairObjectLib(LIBOFFSET(HairObjectLib, b)); \
															if (!lib || !lib->b) return a; \
															return (lib->b)

#define HairColliderLibCall(b) 	HairColliderLib *lib = CheckHairColliderLib(LIBOFFSET(HairColliderLib, b)); \
															if (!lib || !lib->b) return; \
															(((iHairCollider*)this)->*lib->b)

#define HairColliderLibCallR(a,b)  HairColliderLib *lib = CheckHairColliderLib(LIBOFFSET(HairColliderLib, b)); \
															if (!lib || !lib->b) return a; \
															return (((iHairCollider*)this)->*lib->b)

//////////////////////////////////////////////////////////////////////////


#ifndef __API_INTERN__

Bool HairObject::Lock(BaseDocument *pDoc, BaseThread *pThread, Bool bValidate, LONG flags) { HairObjectLibCallR(FALSE,Lock)(this,pDoc,pThread,bValidate,flags); }
void HairObject::Unlock() { HairObjectLibCall(Unlock)(this); }
Bool HairObject::IsLocked() { HairObjectLibCallR(FALSE,hairIsLocked)(this); }
#endif

HairGuides *HairObject::GetGuides() { HairObjectLibCallR(NULL,GetGuides)(this); }
HairGuides *HairObject::GetDynamicGuides() { HairObjectLibCallR(NULL,GetDynamicGuides)(this); }
Bool HairObject::GetRootObject(BaseObject **pObject, BaseTag **pTag, RootObjectData *pData) { HairObjectLibCallR(FALSE,GetRootObject)(this,pObject,pTag,pData); }
HairGuides *HairObject::GenerateHair(LONG flags, LONG count, LONG segments, HairMaterialData **pMaterial, HairInterpolationMap *pMap) { HairObjectLibCallR(NULL,GenerateHair)(this,flags,count,segments,pMaterial,pMap); }
Bool HairObject::SetGuides(HairGuides *guides, Bool clone) { HairObjectLibCallR(FALSE,SetGuides)(this,guides,clone); }
void HairObject::RemoveGuides() { HairObjectLibCall(RemoveGuides)(this); }
Bool HairObject::Update(BaseDocument *doc)
{
	ObjectData *odata=(ObjectData*)GetNodeData(); if (!odata) return FALSE;
	return odata->Execute(this,doc,NULL,0,EXECUTIONFLAGS_EXPRESSION)==EXECUTIONRESULT_OK;
}
HairMaterialData *HairObject::InitMaterials(const InitRenderStruct &irs, BaseDocument *pDoc, HairGuides *guides, VolumeData *vd) { HairObjectLibCallR(NULL,InitMaterials)(irs,this,pDoc,guides,vd); }
void HairObject::FreeMaterials(HairMaterialData *&pMaterials) { HairObjectLibCall(FreeMaterials)(this,pMaterials); }


//////////////////////////////////////////////////////////////////////////

HairGuides *HairGuides::Alloc(LONG count, LONG segments) { HairObjectLibCallR(NULL,AllocGuides)(count,segments); }
void HairGuides::Free(HairGuides *&guides) { HairObjectLibCall(FreeGuides)(guides); }
LONG HairGuides::GetCount() { HairObjectLibCallR(0,GetGuideCount)(this); }
LONG HairGuides::GetSegmentCount() { HairObjectLibCallR(0,GetGuideSegmentCount)(this); }
Vector *HairGuides::GetPoints() { HairObjectLibCallR(NULL,GetGuidePoints)(this); }
HairGuideDynamics *HairGuides::GetDynamics() { HairObjectLibCallR(NULL,GetGuideDynamics)(this); }
Matrix HairGuides::GetMg() { HairObjectLibCallR(Matrix(),GetGuideMg)(this); }
void HairGuides::SetMg(const Matrix &mg) { HairObjectLibCall(SetGuideMg)(this,mg); }
HairRootData HairGuides::GetRoot(LONG index) { HairObjectLibCallR(HairRootData(),GetGuideRoot)(this,index); }
void HairGuides::SetRoot(LONG index, const HairRootData &root, Bool update) { HairObjectLibCall(SetGuideRoot)(this,index,root,update); }
HairObject *HairGuides::GetObject() { HairObjectLibCallR(NULL,GetGuideObject)(this); }
Bool HairGuides::GetSelected(LONG mode, BaseSelect *select) { HairObjectLibCallR(FALSE,GetGuideSelected)(this,mode,select); }
Bool HairGuides::CopyFrom(const HairGuides *src) { HairObjectLibCallR(FALSE,CopyGuidesFrom)(this,src); }
Bool HairGuides::SetSelected(LONG mode, BaseSelect *select) { HairObjectLibCallR(FALSE,SetGuideSelected)(this,mode,select); }
Bool HairGuides::ConvertSelection(LONG from_mode, LONG to_mode, BaseSelect *from_select, BaseSelect *to_select) { HairObjectLibCallR(FALSE,ConvertGuideSelection)(this,from_mode,to_mode,from_select,to_select); }
Vector HairGuides::GetTangent(LONG guide, LONG segment, Real t) { HairObjectLibCallR(FALSE,GetGuideTangent)(this,guide,segment,t); }
SplineObject *HairGuides::CreateSpline() { HairObjectLibCallR(NULL,CreateGuideSpline)(this); }

void HairGuides::ToLocal() { HairObjectLibCall(guideToLocal)(this); }
void HairGuides::ToWorld() { HairObjectLibCall(guideToWorld)(this); }
void HairGuides::ToInitial(Bool align) { HairObjectLibCall(guideToInitial)(this,align); }
void HairGuides::UndisplaceRoots() { HairObjectLibCall(guideUndisplaceRoots)(this); }
void HairGuides::DisplaceRoots() { HairObjectLibCall(guideDisplaceRoots)(this); }

Bool HairGuides::GetRootAxis(LONG index, Matrix &m, Bool bAlign, Bool bLocal, Bool bInitial, Bool bZAxis) { HairObjectLibCallR(FALSE,guideGetRootAxis)(this,index,m,bAlign,bLocal,bInitial,bZAxis); }
Vector HairGuides::GetRootUV(LONG index) { HairObjectLibCallR(Vector(),guideGetRootUV)(this,index); }
Bool HairGuides::GetRootData(LONG index, Vector *p, Vector *n, LONG *ply_id, Bool bLocal, Bool bDisplaced, Bool bInitial) { HairObjectLibCallR(FALSE,guideGetRootData)(this,index,p,n,ply_id,bLocal,bDisplaced,bInitial); }

Matrix *HairGuides::GetTransformMatrix() { HairObjectLibCallR(NULL,guideGetTransformMatrix)(this); }
void HairGuides::SetTransformMatrix(Matrix *tm) { HairObjectLibCall(guideSetTransformMatrix)(this,tm); }
Bool HairGuides::Delete(BaseSelect *bs) { HairObjectLibCallR(FALSE,guideDelete)(this,bs); }
Bool HairGuides::AddRoot(LONG ply_id, Real s, Real t, Real len) { HairObjectLibCallR(FALSE,guideAddRoot)(this,ply_id,s,t,len); }
Bool HairGuides::GetRootObject(RootObjectData *pData) { HairObjectLibCallR(FALSE,guideGetRootObject)(this,pData); }
Bool HairGuides::LinkToObject(HairObject *pHair) { HairObjectLibCallR(FALSE,guideLinkToObject)(this,pHair); }

LONG HairGuides::GetFlags() { HairObjectLibCallR(FALSE,guideGetFlags)(this); }
LONG HairGuides::SetFlags(LONG flags) { HairObjectLibCallR(FALSE,guideSetFlags)(this,flags); }

//////////////////////////////////////////////////////////////////////////

HairGuides *HairGuideDynamics::GetGuides() { HairObjectLibCallR(NULL,GetDynamicsGuides)(this); }

Vector HairGuideDynamics::GetPosition(LONG i) { HairObjectLibCallR(Vector(),GetDynamicsPosition)(this,i); }
void HairGuideDynamics::SetPosition(LONG i, const Vector &p) { HairObjectLibCall(SetDynamicsPosition)(this,i,p); }
Vector HairGuideDynamics::GetLastPosition(LONG i) { HairObjectLibCallR(Vector(),GetDynamicsLastPosition)(this,i); }
void HairGuideDynamics::SetLastPosition(LONG i, const Vector &p) { HairObjectLibCall(SetDynamicsLastPosition)(this,i,p); }
Vector HairGuideDynamics::GetVelocity(LONG i) { HairObjectLibCallR(Vector(),GetDynamicsVelocity)(this,i); }
void HairGuideDynamics::SetVelocity(LONG i, const Vector &v) { HairObjectLibCall(SetDynamicsVelocity)(this,i,v); }
Real HairGuideDynamics::GetMass(LONG i) { HairObjectLibCallR(0.0,GetDynamicsMass)(this,i); }
void HairGuideDynamics::SetMass(LONG i, Real m) { HairObjectLibCall(SetDynamicsMass)(this,i,m); }
Vector HairGuideDynamics::GetForce(LONG i) { HairObjectLibCallR(Vector(),GetDynamicsForce)(this,i); }
void HairGuideDynamics::AddForce(LONG i, const Vector &f) { HairObjectLibCall(AddDynamicsForce)(this,i,f); }
LONG HairGuideDynamics::GetPolygonIntersections(HairPolygonHit **hits) { HairObjectLibCallR(0,GetDynamicsPolygonIntersections)(this,hits); }

//////////////////////////////////////////////////////////////////////////

LONG HairLibrary::GetMode(BaseDocument *doc) { HairObjectLibCallR(0,hairGetMode)(doc); }
void HairLibrary::SetMode(BaseDocument *doc, LONG mode) { HairObjectLibCall(hairSetMode)(doc,mode); }
Bool HairLibrary::GetHairGlobal(BaseDocument* doc) { HairObjectLibCallR(0,hairGetHairGlobal)(doc); }
void HairLibrary::SetHairGlobal(BaseDocument* doc, Bool enable) { HairObjectLibCall(hairSetHairGlobal)(doc,enable); }
Vector HairLibrary::BlendColors(LONG mode, const Vector &colA, const Vector &colB) { HairObjectLibCallR(0,hairBlendColors)(mode,colA,colB); }
Vector HairLibrary::MixST(Real s, Real t, const Vector &pa, const Vector &pb, const Vector &pc, const Vector &pd, Bool bQuad) { HairObjectLibCallR(0,hairMixST)(s,t,pa,pb,pc,pd,bQuad); }
Real HairLibrary::MixST(Real s, Real t, Real va, Real vb, Real vc, Real vd, Bool bQuad) { HairObjectLibCallR(0,hairMixSTReal)(s,t,va,vb,vc,vd,bQuad); }
void HairLibrary::GetPolyPointST(const Vector &p, Real &s, Real &t, const Vector &pa, const Vector &pb, const Vector &pc, const Vector &pd, Bool bQuad) { HairObjectLibCall(hairGetPolyPointST)(p,s,t,pa,pb,pc,pd,bQuad); }
void *HairLibrary::GetHook(BaseDocument *doc, LONG type) { HairObjectLibCallR(NULL,hairGetHook)(doc,type); }
void *HairLibrary::SetHook(BaseDocument *doc, LONG type, void *fn) { HairObjectLibCallR(NULL,hairSetHook)(doc,type,fn); }
BaseContainer *HairLibrary::GetPrefsInstance() { HairObjectLibCallR(NULL,hairGetPrefsInstance)(); }
LONG HairLibrary::GetHairVersion() { HairObjectLibCallR(0,hairGetHairVersion)(); }

//////////////////////////////////////////////////////////////////////////

Bool HairSelectionTag::GetSelected(BaseSelect *bs) { HairObjectLibCallR(FALSE,HairSelectionGetSelected)(this,bs); }
Bool HairSelectionTag::SetSelected(BaseSelect *bs) { HairObjectLibCallR(FALSE,HairSelectionSetSelected)(this,bs); }
LONG HairSelectionTag::GetSelectionType() { HairObjectLibCallR(FALSE,HairSelectionGetType)(this); }
void HairSelectionTag::SetSelectionType(LONG mode) { HairObjectLibCall(HairSelectionSetType)(this,mode); }
LONG HairSelectionTag::GetCount() { HairObjectLibCallR(FALSE,HairSelectionGetCount)(this); }
LONG HairSelectionTag::GetSegments() { HairObjectLibCallR(FALSE,HairSelectionGetSegments)(this); }

//////////////////////////////////////////////////////////////////////////

LONG HairVertexMapTag::GetCount() { HairObjectLibCallR(FALSE,HairVertexGetCount)(this); }
LONG HairVertexMapTag::GetSegments() { HairObjectLibCallR(FALSE,HairVertexGetSegments)(this); }
LONG HairVertexMapTag::GetPointCount() { HairObjectLibCallR(FALSE,HairVertexGetPointCount)(this); }
UWORD *HairVertexMapTag::GetMap() { HairObjectLibCallR(FALSE,HairVertexGetMap)(this); }

//////////////////////////////////////////////////////////////////////////

LONG HairTangentTag::GetPolygonsSegments() { HairObjectLibCallR(FALSE,HairTangentGetPolygonsSegments)(this); }
LONG HairTangentTag::GetPointCount() { HairObjectLibCallR(FALSE,HairTangentGetPointCount)(this); }
LONG HairTangentTag::GetCount() { HairObjectLibCallR(FALSE,HairTangentGetCount)(this); }
LONG HairTangentTag::GetSegments() { HairObjectLibCallR(FALSE,HairTangentGetSegments)(this); }
Vector *HairTangentTag::GetTangent() { HairObjectLibCallR(FALSE,HairTangentGetTangent)(this); }

//////////////////////////////////////////////////////////////////////////

LONG HairMaterialData::GetCount() { HairObjectLibCallR(0,matGetCount)(this); }
LONG HairMaterialData::GetGuideMaterial(LONG i, LONG prev) { HairObjectLibCallR(NOTOK,matGetGuideMaterial)(this,i,prev); }
BaseTag *HairMaterialData::GetMaterialTag(LONG i) { HairObjectLibCallR(NULL,matGetMaterialTag)(this,i); }
Bool HairMaterialData::ApplyMaterial(LONG i, HairGuides *guides, VolumeData *vd, LONG vindex) { HairObjectLibCallR(FALSE,matApplyMaterial)(this,i,guides,vd,vindex); }
Bool HairMaterialData::ApplyMaterials(HairGuides *guides, VolumeData *vd, LONG vindex) { HairObjectLibCallR(FALSE,matApplyMaterials)(this,guides,vd,vindex); }
Real HairMaterialData::GetThickness(LONG guide, Real t, LONG i) { HairObjectLibCallR(0.0,matGetThickness)(this,guide,t,i); }
Vector HairMaterialData::GetColor(LONG guide, Real t, const Vector &r, const Vector &wp, const Vector &p, const Vector &n, VolumeData *vd, const RayHitID &plyid, LONG i) { HairObjectLibCallR(0.0,matGetColor)(this,guide,t,r,wp,p,n,vd,plyid,i); }
Vector HairMaterialData::GetBackColor(LONG guide, Real t, const Vector &col, const Vector &r, const Vector &wp, const Vector &p, const Vector &n, VolumeData *vd, const RayHitID &plyid, LONG i) { HairObjectLibCallR(0.0,matGetBackColor)(this,guide,t,col,r,wp,p,n,vd,plyid,i); }
Bool HairMaterialData::GetSpecularColor(LONG guide, Real t, const Vector &wp, const Vector &p, const Vector &n, VolumeData *vd, const RayHitID &plyid, Vector &speccol, Vector &ispeccol) { HairObjectLibCallR(FALSE, matGetSpecularColor)(this,guide,t,wp,p,n,vd,plyid,speccol,ispeccol); }
Real HairMaterialData::GetTransparency(LONG guide, Real t, const Vector &p, const Vector &n, LONG i) { HairObjectLibCallR(0.0,matGetTransparency)(this,guide,t,p,n,i); }
Bool HairMaterialData::GetTagSelection(LONG i, BaseSelect *bs) { HairObjectLibCallR(FALSE,matGetTagSelection)(this,i,bs); }
Bool HairMaterialData::GetMaterialData(LONG guide, Real &shadows, Real &selfshadows, Real &backshadows, Real &transparency, Real &diffuse, Real &reflect, Real &transmit, Bool &roughenable, Real &roughvar, Real &roughness, Bool &specularenable, Real &specular, Real &specularpower, Real &specularback, Bool &ispecularenable, Bool &ispecularshader, Real &ispecular, Real &ispecularpower, Real &ispecularmix, Real &ispecularblend) { HairObjectLibCallR(FALSE,matGetMaterialData)(this, guide, shadows, selfshadows, backshadows, transparency, diffuse, reflect, transmit, roughenable, roughvar, roughness, specularenable, specular, specularpower, specularback, ispecularenable, ispecularshader, ispecular, ispecularpower, ispecularmix, ispecularblend); }
Bool HairMaterialData::GetGIData(LONG guide, Bool &receive, Real &strength) { HairObjectLibCallR(FALSE, matGetGIData)(this,guide,receive,strength); }
Bool HairMaterialData::AdjustHUV(LONG guide, Vector &huv, Real tline) { HairObjectLibCallR(FALSE,matAdjustHUV)(this,guide,huv,tline); }

//////////////////////////////////////////////////////////////////////////

LONG HairVideoPost::GetObjectCount() { HairObjectLibCallR(0,vpGetObjectCount)(this); }
void HairVideoPost::GetObject(LONG i, HairRenderObject *hro) { HairObjectLibCall(vpGetObject)(this,i,hro); }
LONG HairVideoPost::FindObject(BaseList2D *bl) { HairObjectLibCallR(NOTOK,vpFindObject)(this,bl); }
Bool HairVideoPost::TracerEnabled() { HairObjectLibCallR(FALSE,vpTracerEnabled)(this); }
LONG HairVideoPost::TraceRay(const Vector &p, const Vector &v, Vector &hit, Real &d, LONG cpu, Real tf, LONG flags) { HairObjectLibCallR(NOTOK,vpTraceRay)(this,p,v,hit,d,cpu,tf,flags); }
void HairVideoPost::GetHitInfo(LONG id, HairHitData *hdata) { HairObjectLibCall(vpGetHitInfo)(this,id,hdata); }
Bool HairVideoPost::IsLightEnabled(LONG oindex, RayLight *light, Bool *nodiff, Bool *nospec) { HairObjectLibCallR(FALSE,vpIsLightEnabled)(this,oindex,light,nodiff,nospec); }
Bool HairVideoPost::ShadowsEnabled() { HairObjectLibCallR(FALSE,vpShadowsEnabled)(this); }
ULONG HairVideoPost::GetCompositeFlags(LONG oindex) { HairObjectLibCallR(0, vpGetCompositeFlags)(this, oindex); }

void HairVideoPost::Sample(LONG oindex, VolumeData *vd, LONG cpu, LONG lid, LONG seg, LONG p, Real lined, const Vector &linep, const Vector &v, Vector &col, const Vector &n, const Vector &lp, const Vector &t, const Vector &r, Vector huv, LONG flags) { HairObjectLibCall(vpSample)(this,oindex,vd,cpu,lid,seg,p,lined,linep,v,col,n,lp,t,r,huv,flags); }
Real HairVideoPost::SampleTransparency(LONG oindex, VolumeData *vd, LONG lid, LONG seg, LONG p, Real lined, const Vector &n, const Vector &linep, const Vector &lp, Vector huv, LONG cpu, LONG flags, RayLight *light) { HairObjectLibCallR(1.0,vpSampleTransparency)(this,oindex,vd,lid,seg,p,lined,n,linep,lp,huv,cpu,flags,light); }
Real HairVideoPost::SampleShadow(VolumeData *vd, RayLight *light, const Vector &p, Real delta, LONG cpu, LONG flags) { HairObjectLibCallR(1.0,vpSampleShadow)(this,vd,light,p,delta,cpu,flags); }

Bool HairVideoPost::GetTopFragment(LONG x, LONG y, HairFragment *frag, LONG cpu) { HairObjectLibCallR(FALSE,vpGetTopFragment)(this,x,y,frag,cpu); }
Bool HairVideoPost::GetFragmentLink(LONG x, LONG y, HairFragmentLink  *frag, LONG cpu, Bool first) { HairObjectLibCallR(FALSE,vpGetFragmentLink)(this,x,y,frag,cpu,first); }
HairFragment *HairVideoPost::GetFragments(LONG x, LONG y, LONG &cnt, LONG cpu) { HairObjectLibCallR(NULL,vpGetFragments)(this,x,y,cnt,cpu); }

Bool HairVideoPost::SetFragments(LONG x, LONG y, HairFragment *frag, LONG cnt, LONG cpu) { HairObjectLibCallR(FALSE,vpSetFragments)(this,x,y,frag,cnt,cpu); }
Bool HairVideoPost::InsertFragment(LONG x, LONG y, HairFragment *frag, LONG cnt, LONG cpu) { HairObjectLibCallR(FALSE,vpInsertFragment)(this,x,y,frag,cnt,cpu); }
Bool HairVideoPost::InsertFragmentLine(LONG x, LONG y, LONG xcnt, HairFragment **frag, LONG *cnt, LONG cpu) { HairObjectLibCallR(FALSE,vpInsertFragmentLine)(this,x,y,xcnt,frag,cnt,cpu); }

//////////////////////////////////////////////////////////////////////////

HairCollider* HairCollider::Alloc()
{
	HairColliderLib *lib = CheckHairColliderLib(LIBOFFSET(HairColliderLib,Alloc)); if (!lib) return NULL;
	return (HairCollider*)lib->Alloc();
}

void HairCollider::Free(HairCollider *&p)
{
	if (!p) return;
	HairColliderLib *lib = CheckHairColliderLib(LIBOFFSET(HairColliderLib,Free)); if (!lib) return;
	iHairCollider* i = (iHairCollider*)p;
	lib->Free(i);
	p = NULL;
}

Bool HairCollider::Init(HairGuides *hair) { HairColliderLibCallR(FALSE,Init)(hair); }
void HairCollider::Release() { HairColliderLibCall(Release)(); }
LONG HairCollider::GetClosestPoint(const Vector &p) { HairColliderLibCallR(NOTOK,GetClosestPoint)(p); }
Bool HairCollider::GetParticleIntersection(const Vector &p, const Vector &v, Real r, LONG *guide, LONG *segment, Real *segt, Real *rayt) { HairColliderLibCallR(FALSE,GetParticleIntersection)(p,v,r,guide,segment,segt,rayt); }
Bool HairCollider::GetClosestSegment(const Vector &p, LONG *guide, LONG* segment, Real* segt) { HairColliderLibCallR(FALSE,GetClosestSegment)(p,guide,segment,segt); }

//////////////////////////////////////////////////////////////////////////

LReal HairInterpolationMap::GetTotalWeight(LONG index)
{
	if (!m_pMap) return 0.0;

	LReal total=0.0;
	LONG i,j=index*m_WeightCount;

	for (i=0;i<m_WeightCount;i++)
	{
		if (m_pMap[j+i].m_Index==NOTOK) continue;
		total+=m_pMap[j+i].m_Weight;
	}

	return total;
}

LReal HairInterpolationMap::GetTotalInvWeight(LONG index)
{
	if (!m_pMap) return 0.0;

	LReal total=0.0;
	LONG i,j=index*m_WeightCount;

	if (m_pMap[j].m_Weight<2e-4) return 1.0;

	for (i=0;i<m_WeightCount;i++)
	{
		if (m_pMap[j+i].m_Index==NOTOK) continue;
		total+=1.0/m_pMap[j+i].m_Weight;
	}

	return total;
}

SReal HairInterpolationMap::GetInterpolateReal(LONG index, SReal *v)
{
	if (!v) return 0.0;
	if (!m_pMap) return *v;

	LONG i,j=index*m_WeightCount;

	if (m_pMap[j].m_Weight<2e-4) return *v;

	LReal total=GetTotalInvWeight(index);
	LReal rv=0.0;

	if (total==0.0) return *v;

	for (i=0;i<m_WeightCount;i++)
	{
		if (m_pMap[j+i].m_Index==NOTOK) continue;
		rv+=v[i]/m_pMap[j+i].m_Weight;
	}

	return SReal(rv/total);
}

LReal HairInterpolationMap::GetInterpolateReal(LONG index, LReal *v)
{
	if (!v) return 0.0;
	if (!m_pMap) return *v;

	LONG i,j=index*m_WeightCount;

	if (m_pMap[j].m_Weight<2e-4) return *v;

	LReal total=GetTotalInvWeight(index);
	LReal rv=0.0;

	if (total==0.0) return *v;

	for (i=0;i<m_WeightCount;i++)
	{
		if (m_pMap[j+i].m_Index==NOTOK) continue;
		rv+=v[i]/m_pMap[j+i].m_Weight;
	}

	return rv/total;
}

SVector HairInterpolationMap::GetInterpolatedVector(LONG index, SVector *v)
{
	if (!v) return 0.0;
	if (!m_pMap) return *v;

	LONG i,j=index*m_WeightCount;

	if (m_pMap[j].m_Weight<2e-4) return *v;

	LReal total=GetTotalInvWeight(index);
	LVector rv=0.0;

	if (total==0.0) return *v;

	for (i=0;i<m_WeightCount;i++)
	{
		if (m_pMap[j+i].m_Index==NOTOK) continue;
		rv+=v[i].ToLV()/m_pMap[j+i].m_Weight;
	}

	return (rv/total).ToSV();
}

LVector HairInterpolationMap::GetInterpolatedVector(LONG index, LVector *v)
{
	if (!v) return 0.0;
	if (!m_pMap) return *v;

	LONG i,j=index*m_WeightCount;

	if (m_pMap[j].m_Weight<2e-4) return *v;

	LReal total=GetTotalInvWeight(index);
	LVector rv=0.0;

	if (total==0.0) return *v;

	for (i=0;i<m_WeightCount;i++)
	{
		if (m_pMap[j+i].m_Index==NOTOK) continue;
		rv+=v[i]/m_pMap[j+i].m_Weight;
	}

	return rv/total;
}
