//This will set the formation
void FormationBhvr::SetFormation(TimeValue t)
{
	INode *node;
	Matrix3 tempMatrix;


	//Make sure that the leader is not part of the follower array..
	RemoveLeaderFromFormation(t);


	INode *leader =  GetLeader(t);

	if(leader==NULL)
		return;
	Matrix3 leaderPosition = GetCurrentMatrix(leader,t);
	leaderPosition.NoScale(); //kill any scale if we have it 
	leaderPosition.Invert();  //it's inverted...


	int numDelegates = GetFollowerCount(t);	

	//zero out the formation matrix that's used for saving it out.
	pblock->ZeroCount(follower_matrix1);
	pblock->ZeroCount(follower_matrix2);
	pblock->ZeroCount(follower_matrix3);
	pblock->ZeroCount(follower_matrix4);

	for(int i =0;i<numDelegates;i++)
	{

		node = GetFollower(t,i);
		if(node)
		{
			tempMatrix = GetCurrentMatrix(node,t);
			tempMatrix.NoScale();
			Matrix3 leaderMat =tempMatrix*leaderPosition;
			AppendFollowerMatrix(t,leaderMat);

			//killed because matrix3 wasn't working ...pblock->Append(follower_matrix,1,&leaderMat);
		 
		
		}
		else
		{
			//we still set up follower_matrix so that the counts
			//of the follower_matrix tab and the follower tab are equal.
			tempMatrix.IdentityMatrix();
			AppendFollowerMatrix(t,tempMatrix);

			//pblock->Append(follower_matrix,1,&tempMat);
	
		}
	}

}
Exemple #2
0
Matrix3 Exporter::getObjectTransform(INode *node, TimeValue t, bool local)
{
   Matrix3 tm = node->GetObjTMAfterWSM(t);
   if (local)
   {
      INode *parent = node->GetParentNode();
      if (parent != NULL) {
         Matrix3 pm = parent->GetNodeTM(t);
         pm.Invert();
         tm *= pm;
      }
   }
   return tm;
}
bool CExporter::generateSkinBone(grp::SkinnedMeshExporter* skinnedMesh, INode* node, ISkin* skin)
{
	Matrix3 mSkinOffset;
	if (!skin->GetSkinInitTM(node, mSkinOffset, true))
	{
		setLastError("获取Skin偏移矩阵失败");
		return false;
	}

	int iNumBone = skin->GetNumBones();
	skinnedMesh->m_boneNames.resize(iNumBone);
	skinnedMesh->m_offsetMatrices.resize(iNumBone);
	for (int i = 0; i < iNumBone; ++i)
	{
		//mbs only
		INode* pBone = skin->GetBone(i);
		if (NULL == pBone)
		{
			setLastError("找不到skin依赖的骨骼");
			return false;
		}
		if (ENUM_NODE_DUMMY == checkNodeType(pBone))
		{
			char szError[1024];
			::StringCchPrintf(szError, sizeof(szError), "发现绑定到虚拟体[%s]的顶点", pBone->GetName());
			setLastError(szError);
			return false;
		}

		wchar_t unicodeString[256];
		mbstowcs(unicodeString, pBone->GetName(), 255);
		skinnedMesh->m_boneNames[i] = unicodeString;

		Matrix3 mBoneOffset;
		skin->GetBoneInitTM(pBone, mBoneOffset);
		mBoneOffset.Invert();
		Matrix3 meshOffset = node->GetObjectTM(0);
		mBoneOffset = meshOffset * mBoneOffset;
		//mBoneOffset = mSkinOffset * mBoneOffset;
		grp::Matrix& mCore = skinnedMesh->m_offsetMatrices[i];
		::MatrixFromMatrix3(mCore, mBoneOffset);
	}
	return true;
}
Matrix3 CActionExporter::get_bone_tm(CSkeletonExporter* pSkeleton,int boneIndex,unsigned int iMaxTime)
{
         sMaxBoneNode_t bone = pSkeleton->m_MaxBones[boneIndex];
         Matrix3        boneInitMTInv;
         if(G_MaxEnv().m_bUseBeforeSkeletonPose)
             boneInitMTInv = bone.m_SkinInitMT;
         else
             boneInitMTInv = bone.m_InitNodeTM0;

         boneInitMTInv.Invert();
         INode* pNode = bone.m_pNode;

         Matrix3 BoneTM = boneInitMTInv * pNode->GetNodeTM(iMaxTime); //>GetNodeTM(iMaxTime);
         Point3 Trans = BoneTM.GetTrans();
         BoneTM.NoTrans();
         //对骨骼进行缩放
         Trans.x *= pSkeleton->m_fScale;
         Trans.y *= pSkeleton->m_fScale;
         Trans.z *= pSkeleton->m_fScale;
         BoneTM.SetTrans(Trans);

         return BoneTM;

}
//=============================================================================================
NL3D::IShape *CExportNel::buildRemanence(INode& node, TimeValue time)
{
	std::auto_ptr<CSegRemanenceShape> srs(new CSegRemanenceShape);
	uint  numSlices = getScriptAppData (&node, NEL3D_APPDATA_REMANENCE_SLICE_NUMBER, 2);
	float samplingPeriod = getScriptAppData (&node, NEL3D_APPDATA_REMANENCE_SAMPLING_PERIOD, 0.02f);
	float rollupRatio    = getScriptAppData (&node, NEL3D_APPDATA_REMANENCE_ROLLUP_RATIO, 1.f);

	if (samplingPeriod <= 0.f) samplingPeriod = 0.02f;
	if (numSlices <= 2) numSlices = 2;
	if (rollupRatio <= 0) rollupRatio = 1.f;
	
	srs->setNumSlices((uint32) numSlices);
	srs->setSliceTime(samplingPeriod);
	srs->setRollupRatio(rollupRatio);

	// get material from this node
	std::vector<NL3D::CMaterial> materials;
	CMaxMeshBaseBuild mmbb;
	buildMaterials(materials, mmbb, node, time);
	if (materials.size() != 1)
	{	
		buildRemanenceError(this, node, "The remanent segment %s should have a single material");
		return NULL;
	}
	srs->setMaterial(materials[0]);
	// 
	// get geometry

	ObjectState os = node.EvalWorldState(_Ip->GetTime());		
	Object *obj = node.EvalWorldState(time).obj;	
	if (obj->SuperClassID() != SHAPE_CLASS_ID)
	{
		buildRemanenceError(this, node, "Can't get curves from %s");
		return NULL;
	}
	
	ShapeObject *so = (ShapeObject *) obj;	
	if (so->NumberOfCurves() != 1 || so->NumberOfPieces(time, 0) == 0)
	{
		buildRemanenceError(this, node, "Remanence export : %s should only contain one curve with at least one segment!");		
		return NULL;
	}

	int numPieces = so->NumberOfPieces(time, 0);
	srs->setNumCorners(numPieces + 1);

	// build offset matrix
	Matrix3 invNodeTM = node.GetNodeTM(time);
	invNodeTM.Invert();

	// Get the object matrix
	Matrix3 objectTM = node.GetObjectTM(time);

	// Compute the local to world matrix
	Matrix3 objectToLocal = objectTM*invNodeTM;	


	for(uint k = 0; k <= (uint) numPieces; ++k)
	{
		Point3 pos;		
		pos = (k == 0) ? so->InterpPiece3D(time, 0, 0, 0.f)
					   : so->InterpPiece3D(time, 0, k - 1, 1.f);		
		NLMISC::CVector nelPos;		
		convertVector(nelPos, objectToLocal * pos);
		srs->setCorner(k, nelPos);
	}

	
	srs->setTextureShifting(CExportNel::getScriptAppData (&node, NEL3D_APPDATA_REMANENCE_SHIFTING_TEXTURE, 0) != 0);	


	if (CExportNel::getScriptAppData (&node, NEL3D_APPDATA_EXPORT_ANIMATED_MATERIALS, 0) != 0)
	{
		srs->setAnimatedMaterial(mmbb.MaterialInfo[0].MaterialName);
	}					
	

	// ********************************
	// *** Export default transformation
	// ********************************

	// Get the node matrix
	Matrix3 localTM;
	getLocalMatrix (localTM, node, time);

	// Get the translation, rotation, scale of the node
	CVector pos, scale;
	CQuat rot;
	decompMatrix (scale, rot, pos, localTM);

	// Set the default values
	srs->getDefaultPos()->setDefaultValue(pos);					
	srs->getDefaultScale()->setDefaultValue(scale);					
	srs->getDefaultRotQuat()->setDefaultValue(rot);


	return srs.release();

	/*ObjectState os = node.EvalWorldState(_Ip->GetTime());		
	Object *obj = node.EvalWorldState(time).obj;	
	TriObject *tri = (TriObject *) obj->ConvertToType(0, Class_ID(TRIOBJ_CLASS_ID, 0));	
	bool deleteIt=false;
	if (obj != tri) 
		deleteIt = true;
	Mesh *pMesh = &tri->mesh;
	if (pMesh && pMesh->numVerts > 1) 
	{
	  	Point3 v = pMesh->getVert(0);
		NLMISC::CVector minV, maxV;
		convertVector(minV, v);
		maxV = minV;
		for(uint k = 1; k < (uint) pMesh->numVerts; ++k)
		{
			NLMISC::CVector nv;
			v = pMesh->getVert(k);
			convertVector(nv, v);
			maxV.maxof(maxV, nv);
			minV.minof(minV, nv);
		}
		srs->setSeg(0, minV);
		srs->setSeg(1, maxV);	
	}
	else
	{
		buildRemanenceError(this, node, "Can't get mesh from %s or empty mesh");
	}*/

	//	
}
	//---------------------------------------------------------------
	void ControllerExporter::exportSkinController( ExportNode* exportNode, SkinController* skinController, const String& controllerId, const String& skinSource )
	{
		INode* iNode = exportNode->getINode();

		if ( !skinController )
			return;

		// We cannot use skin->GetContextInterface to get ISkinContextData if we are exporting an XRef, since we cannot access
		// the INode the object belongs to in the referenced file. To solve this problem, we temporarily create an INode, that references
		// the object and delete it immediately. 
		ISkinInterface* skinInterface = getISkinInterface( exportNode, skinController );

		if ( !skinInterface )
			return;

		openSkin(controllerId, skinSource);
	
		Matrix3 bindShapeTransformationMatrix;
		skinInterface->getSkinInitTM(bindShapeTransformationMatrix, true);	
		double  bindShapeTransformationArray[4][4];
		VisualSceneExporter::matrix3ToDouble4x4(bindShapeTransformationArray, bindShapeTransformationMatrix);

		addBindShapeTransform(bindShapeTransformationArray);

		int jointCount = skinInterface->getNumBones();
		INodeList boneINodes;


		// Export joints source
		String jointsId = controllerId + JOINTS_SOURCE_ID_SUFFIX;
		COLLADASW::NameSource jointSource(mSW);
		jointSource.setId(jointsId);
		jointSource.setArrayId(jointsId + ARRAY_ID_SUFFIX);
		jointSource.setAccessorStride(1);
		jointSource.getParameterNameList().push_back("JOINT");
		jointSource.setAccessorCount(jointCount);
		jointSource.prepareToAppendValues();

		for (int i = 0; i <  jointCount; ++i)
		{
			// there should not be any null bone.
			// the ISkin::GetBone, not GetBoneFlat, function is called here.
			INode* boneNode = skinInterface->getBone(i);
			assert(boneNode);
			boneINodes.push_back(boneNode);

			ExportNode* jointExportNode = mExportSceneGraph->getExportNode(boneNode);
			assert(jointExportNode);

			if ( !jointExportNode->hasSid() )
				jointExportNode->setSid(mExportSceneGraph->createJointSid());

			jointExportNode->setIsJoint();

			jointSource.appendValues(jointExportNode->getSid());
		}
		jointSource.finish();

		determineReferencedJoints(exportNode, skinController);

		//export inverse bind matrix source
		String inverseBindMatrixId = controllerId + BIND_POSES_SOURCE_ID_SUFFIX;
		COLLADASW::Float4x4Source inverseBindMatrixSource(mSW);
		inverseBindMatrixSource.setId(inverseBindMatrixId);
		inverseBindMatrixSource.setArrayId(inverseBindMatrixId + ARRAY_ID_SUFFIX);
		inverseBindMatrixSource.setAccessorStride(16);
		inverseBindMatrixSource.getParameterNameList().push_back("TRANSFORM");
		inverseBindMatrixSource.setAccessorCount(jointCount);
		inverseBindMatrixSource.prepareToAppendValues();

		for (int i = 0; i <  jointCount; ++i)
		{
			INode* boneNode = boneINodes[i];

			Matrix3 bindPose;
			if ( !skinInterface->getBoneInitTM(boneNode, bindPose) )
			{
				bindPose = VisualSceneExporter::getWorldTransform( boneNode, mDocumentExporter->getOptions().getAnimationStart() );
			}
			bindPose.Invert();

			double bindPoseArray[4][4];
			VisualSceneExporter::matrix3ToDouble4x4(bindPoseArray, bindPose);
			inverseBindMatrixSource.appendValues(bindPoseArray);
		}
		inverseBindMatrixSource.finish();

		int vertexCount = skinInterface->getNumVertices();
		
		//count weights, excluding the ones equals one
		int weightsCount = 1;
		for (int i = 0; i < vertexCount; ++i)
		{
			int jointCount = skinInterface->getNumAssignedBones(i);
			for (int p = 0; p < jointCount; ++p)
			{
				float weight = skinInterface->getBoneWeight(i, p);
				if ( !COLLADASW::MathUtils::equals(weight, 1.0f) )
					weightsCount++;
			}
		}

		//export weights source
		String weightsId = controllerId + WEIGHTS_SOURCE_ID_SUFFIX;
		COLLADASW::FloatSource weightsSource(mSW);
		weightsSource.setId(weightsId);
		weightsSource.setArrayId(weightsId + ARRAY_ID_SUFFIX);
		weightsSource.setAccessorStride(1);
		weightsSource.getParameterNameList().push_back("WEIGHT");
		weightsSource.setAccessorCount(weightsCount);
		weightsSource.prepareToAppendValues();

		weightsSource.appendValues(1.0);
		for (int i = 0; i < vertexCount; ++i)
		{
			int jointCount = skinInterface->getNumAssignedBones(i);
			for (int p = 0; p < jointCount; ++p)
			{
				float weight = skinInterface->getBoneWeight(i, p);
				if ( !COLLADASW::MathUtils::equals(weight, 1.0f) )
					weightsSource.appendValues(weight);
			}
		}
		weightsSource.finish();

		COLLADASW::JointsElement joints(mSW);
		joints.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::JOINT, "#" + jointsId));
		joints.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::BINDMATRIX, "#" + inverseBindMatrixId));
		joints.add();

		COLLADASW::VertexWeightsElement vertexWeights(mSW);
		COLLADASW::Input weightInput(COLLADASW::InputSemantic::WEIGHT, "#" + weightsId);
		vertexWeights.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::JOINT, "#" + jointsId, 0));
		vertexWeights.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::WEIGHT, "#" + weightsId, 1));
		vertexWeights.setCount(vertexCount);

		vertexWeights.prepareToAppendVCountValues();

		for (int i = 0; i < vertexCount; ++i)
			vertexWeights.appendValues(skinInterface->getNumAssignedBones(i));

		vertexWeights.CloseVCountAndOpenVElement();

		int currentIndex = 1;
		for (int i = 0; i < vertexCount; ++i)
		{
			int jointCount = skinInterface->getNumAssignedBones(i);
			for (int p = 0; p < jointCount; ++p)
			{
				vertexWeights.appendValues(skinInterface->getAssignedBone(i, p));
				float weight = skinInterface->getBoneWeight(i, p);
				if ( !COLLADASW::MathUtils::equals(weight, 1.0f) )
				{
					vertexWeights.appendValues(currentIndex++);
				}
				else
				{
					vertexWeights.appendValues(0);
				}
			}
		}
		vertexWeights.finish();
		closeSkin();
		skinInterface->releaseMe();
	}
void MeshRenderer::DoRender( BufferIndex bufferIndex, const Matrix& modelViewMatrix, const Matrix& modelMatrix, const Matrix& viewMatrix, const Matrix& projectionMatrix, const Vector4& color )
{
  MeshInfo& meshInfo = mMeshInfo[bufferIndex];
  Mesh*           mesh              =    meshInfo.mesh;
  RenderMaterial& material          =  *(meshInfo.material);
  BoneTransforms& boneTransforms    =    meshInfo.boneTransforms;

  if( ! meshInfo.boneTransforms.transforms.empty() )
  {
    ApplyViewToBoneTransforms( meshInfo.boneTransforms, viewMatrix );
  }

  const int stride = sizeof(Dali::MeshData::Vertex);
  Dali::MeshData::Vertex *v = 0;

  mesh->UploadVertexData( *mContext, bufferIndex );
  mesh->BindBuffers( *mContext );

  GeometryType geometryType = GEOMETRY_TYPE_TEXTURED_MESH;
  if( ! material.HasTexture() )
  {
    geometryType = GEOMETRY_TYPE_MESH;
  }

  GLsizei numBoneMatrices = (GLsizei)mesh->GetMeshData(Mesh::RENDER_THREAD).GetBoneCount();

  // Select program type
  ShaderSubTypes shaderType = SHADER_DEFAULT;
  if( mShader->AreSubtypesRequired( geometryType ) )
  {
    if( numBoneMatrices )
    {
      if( mesh->GetMeshData(Mesh::RENDER_THREAD).HasColor() )
      {
        shaderType = SHADER_RIGGED_AND_VERTEX_COLOR;
      }
      else if( mAffectedByLighting )
      {
        shaderType = SHADER_RIGGED_AND_LIT;
      }
      else
      {
        shaderType = SHADER_RIGGED_AND_EVENLY_LIT;
      }
    }
    else
    {
      if( mesh->GetMeshData(Mesh::RENDER_THREAD).HasColor() )
      {
        shaderType = SHADER_VERTEX_COLOR;
      }
      else if( ! mAffectedByLighting )
      {
        shaderType = SHADER_EVENLY_LIT;
      } // else default
    }
  }

  if( geometryType != mGeometryType || shaderType != mShaderType )
  {
    mGeometryType = geometryType;
    mShaderType = shaderType;
    ResetCustomUniforms();
  }

  Program& program = mShader->Apply( *mContext, bufferIndex, geometryType, modelMatrix, viewMatrix, modelViewMatrix, projectionMatrix, color, mShaderType );

  GLint location       = Program::UNIFORM_UNKNOWN;
  GLint positionLoc    = program.GetAttribLocation(Program::ATTRIB_POSITION);
  GLint texCoordLoc    = Program::ATTRIB_UNKNOWN;
  GLint boneWeightsLoc = Program::ATTRIB_UNKNOWN;
  GLint boneIndicesLoc = Program::ATTRIB_UNKNOWN;
  GLint normalLoc      = Program::ATTRIB_UNKNOWN;
  GLint colorLoc       = Program::ATTRIB_UNKNOWN;

  mContext->VertexAttribPointer( positionLoc, 3, GL_FLOAT, GL_FALSE, stride, &v->x );
  mContext->EnableVertexAttributeArray( positionLoc );

  if( numBoneMatrices > 0 )
  {
    location = mCustomUniform[ shaderType ][ 0 ].GetUniformLocation( program, "uBoneCount" );
    if( Program::UNIFORM_UNKNOWN != location )
    {
      program.SetUniform1i(location, numBoneMatrices);
    }

    location = mCustomUniform[ shaderType ][ 1 ].GetUniformLocation( program, "uBoneMatrices" );
    if( Program::UNIFORM_UNKNOWN != location )
    {
      program.SetUniformMatrix4fv(location, numBoneMatrices, boneTransforms.viewTransforms[0].AsFloat());
    }
    if( mesh->GetMeshData(Mesh::RENDER_THREAD).HasNormals() )
    {
      location = mCustomUniform[ shaderType ][ 2 ].GetUniformLocation( program, "uBoneMatricesIT" );
      if( Program::UNIFORM_UNKNOWN != location )
      {
        program.SetUniformMatrix3fv( location, numBoneMatrices, boneTransforms.inverseTransforms[0].AsFloat() );
      }
    }

    boneWeightsLoc = program.GetAttribLocation( Program::ATTRIB_BONE_WEIGHTS );
    if( Program::ATTRIB_UNKNOWN != boneWeightsLoc )
    {
      mContext->VertexAttribPointer( boneWeightsLoc, 4, GL_FLOAT, GL_FALSE, stride, &v->boneWeights[0] );
      mContext->EnableVertexAttributeArray( boneWeightsLoc );
    }

    boneIndicesLoc = program.GetAttribLocation( Program::ATTRIB_BONE_INDICES );
    if( Program::ATTRIB_UNKNOWN != boneIndicesLoc )
    {
      mContext->VertexAttribPointer( boneIndicesLoc, 4, GL_UNSIGNED_BYTE, GL_FALSE, stride, &v->boneIndices[0] );
      mContext->EnableVertexAttributeArray( boneIndicesLoc );
    }
  }

  if( material.HasTexture() )
  {
    material.BindTextures( program );
  }
  // Always use UV's - may be being used for another purpose by a custom shader!
  texCoordLoc = program.GetAttribLocation(Program::ATTRIB_TEXCOORD);
  if( Program::ATTRIB_UNKNOWN != texCoordLoc )
  {
    mContext->VertexAttribPointer( texCoordLoc, 2, GL_FLOAT, GL_FALSE, stride, &v->u );
    mContext->EnableVertexAttributeArray( texCoordLoc );
  }

  if( mesh->GetMeshData(Mesh::RENDER_THREAD).HasNormals() )
  {
    normalLoc = program.GetAttribLocation(Program::ATTRIB_NORMAL);
    if( Program::ATTRIB_UNKNOWN != normalLoc )
    {
      mContext->VertexAttribPointer( normalLoc, 3, GL_FLOAT, GL_FALSE, stride, &v->nX );
      mContext->EnableVertexAttributeArray( normalLoc );
    }
  }
  else if( mesh->GetMeshData(Mesh::RENDER_THREAD).HasColor() )  // Normals & color are mutually exclusive
  {
    colorLoc = program.GetAttribLocation(Program::ATTRIB_COLOR);
    if( Program::ATTRIB_UNKNOWN != colorLoc)
    {
      mContext->VertexAttribPointer( colorLoc, 3, GL_FLOAT, GL_FALSE, stride, &v->vertexR );
      mContext->EnableVertexAttributeArray( colorLoc );
    }
  }

  material.SetUniforms( mRenderMaterialUniforms, program, shaderType );

  if( mAffectedByLighting )
  {
    // Set light parameters
    location = mCustomUniform[ shaderType ][ 3 ].GetUniformLocation( program, "uNumberOfLights" );
    if( Program::UNIFORM_UNKNOWN != location )
    {
      program.SetUniform1i( location, mLightController->GetNumberOfLights() );
    }

    // Model View IT matrix required for vertex normal lighting calculation
    location = mCustomUniform[ shaderType ][ 4 ].GetUniformLocation( program, "uModelViewIT" );
    if( Program::UNIFORM_UNKNOWN != location )
    {
      Matrix3 modelViewInverseTranspose = modelViewMatrix;
      modelViewInverseTranspose.Invert();
      modelViewInverseTranspose.Transpose();

      program.SetUniformMatrix3fv( location, 1, modelViewInverseTranspose.AsFloat() );
    }

    // only one active light supported at the moment (due to performance)
    //if( numberOfLights > 0 )
    {
      Vector2 tempVector2;
      Vector3 tempVector3;

      Node& lightNode = mLightController->GetLight( 0 );

      LightAttachment& light = dynamic_cast< LightAttachment& >( lightNode.GetAttachment() );

      location = mCustomUniform[ shaderType ][ 5 ].GetUniformLocation( program, "uLight0.mType" );
      if( Program::UNIFORM_UNKNOWN != location )
      {
        program.SetUniform1i( location, (GLint)light.GetType() );
      }

      location = mCustomUniform[ shaderType ][ 6 ].GetUniformLocation( program, "uLight0.mFallOff" );
      if( Program::UNIFORM_UNKNOWN != location )
      {
        tempVector2 = light.GetFallOff();
        program.SetUniform2f( location, tempVector2.x, tempVector2.y );
      }

      location = mCustomUniform[ shaderType ][ 7 ].GetUniformLocation( program, "uLight0.mSpotAngle" );
      if( Program::UNIFORM_UNKNOWN != location )
      {
        tempVector2 = light.GetSpotAngle();
        program.SetUniform2f( location, tempVector2.x, tempVector2.y );
      }

      location = mCustomUniform[ shaderType ][ 8 ].GetUniformLocation( program, "uLight0.mLightPos" );
      if( Program::UNIFORM_UNKNOWN != location )
      {
        // light position in eyespace
        Vector3 tempVector3( viewMatrix * Vector4(lightNode.GetWorldPosition(bufferIndex)) );
        program.SetUniform3f( location, tempVector3.x, tempVector3.y, tempVector3.z );
      }

      location = mCustomUniform[ shaderType ][ 9 ].GetUniformLocation( program, "uLight0.mLightDir" );
      if( Program::UNIFORM_UNKNOWN != location )
      {
        tempVector3 = light.GetDirection();
        tempVector3.Normalize();
        program.SetUniform3f( location, tempVector3.x, tempVector3.y, tempVector3.z );
      }

      location = mCustomUniform[ shaderType ][ 10 ].GetUniformLocation( program, "uLight0.mAmbient" );
      if( Program::UNIFORM_UNKNOWN != location )
      {
        tempVector3 = light.GetAmbientColor();
        program.SetUniform3f( location, tempVector3.r, tempVector3.g, tempVector3.b );
      }

      location = mCustomUniform[ shaderType ][ 11 ].GetUniformLocation( program, "uLight0.mDiffuse" );
      if( Program::UNIFORM_UNKNOWN != location )
      {
        tempVector3 = light.GetDiffuseColor();
        program.SetUniform3f( location, tempVector3.r, tempVector3.g, tempVector3.b );
      }

      location = mCustomUniform[ shaderType ][ 12 ].GetUniformLocation( program, "uLight0.mSpecular" );
      if( Program::UNIFORM_UNKNOWN != location )
      {
        tempVector3 = light.GetSpecularColor();
        program.SetUniform3f( location, tempVector3.r, tempVector3.g, tempVector3.b );
      }
    }
  }

  Dali::MeshData::VertexGeometryType vertexGeometry = mesh->GetMeshData(Mesh::RENDER_THREAD).GetVertexGeometryType();
  switch( vertexGeometry )
  {
    case Dali::MeshData::TRIANGLES:
      mContext->DrawElements(GL_TRIANGLES, mesh->GetFaceIndexCount(Mesh::RENDER_THREAD), GL_UNSIGNED_SHORT, 0);
      DRAW_ELEMENT_RECORD(mesh->GetFaceIndexCount());
      break;
    case Dali::MeshData::LINES:
      mContext->DrawElements(GL_LINES, mesh->GetFaceIndexCount(Mesh::RENDER_THREAD), GL_UNSIGNED_SHORT, 0);
      DRAW_ELEMENT_RECORD(mesh->GetFaceIndexCount());
      break;
    case Dali::MeshData::POINTS:
      mContext->DrawArrays(GL_POINTS, 0, mesh->GetFaceIndexCount(Mesh::RENDER_THREAD) );
      DRAW_ARRAY_RECORD(mesh->GetFaceIndexCount());
  }

  if( normalLoc != Program::ATTRIB_UNKNOWN )
  {
    mContext->DisableVertexAttributeArray( normalLoc );
  }

  if( colorLoc != Program::ATTRIB_UNKNOWN )
  {
    mContext->DisableVertexAttributeArray( colorLoc );
  }

  mContext->DisableVertexAttributeArray( positionLoc );

  if( texCoordLoc != Program::ATTRIB_UNKNOWN )
  {
    mContext->DisableVertexAttributeArray( texCoordLoc );
  }

  if( boneWeightsLoc != Program::ATTRIB_UNKNOWN )
  {
    mContext->DisableVertexAttributeArray( boneWeightsLoc );
  }

  if( boneIndicesLoc != Program::ATTRIB_UNKNOWN )
  {
    mContext->DisableVertexAttributeArray( boneIndicesLoc );
  }

  return;
}
Void SoftBody::_SetupPose( Bool bIsVolume, Bool bIsFrame )
{
    const Node * pNode;
    UInt iNodeIndex;

    // Update links
    EnumLinks();
    Link * pLink = EnumNextLink();
    while( pLink != NULL ) {
        pLink->UpdateConstants();
        pLink = EnumNextLink();
    }

    // Compute total mass
    Scalar fTotalMass = _ComputeMass();
    Scalar fMassK = fTotalMass * 1000.0f * (Scalar)( GetNodeCount() );

    EnumNodes();
    pNode = EnumNextNode();
    while( pNode != NULL ) {
        if ( pNode->InvMass == 0.0f )
            fTotalMass += fMassK;
        pNode = EnumNextNode();
    }
    Scalar fInvTotalMass = MathFn->Invert( fTotalMass );

    // Flags
    m_hPose.bIsVolume = bIsVolume;
    m_hPose.bIsFrame = bIsFrame;

    // Weights
    m_hPose.arrWeights.Clear();

    EnumNodes();
    pNode = EnumNextNode();
    while( pNode != NULL ) {
        if ( pNode->InvMass > 0.0f )
            m_hPose.arrWeights.Push( pNode->Mass * fInvTotalMass );
        else
            m_hPose.arrWeights.Push( fMassK * fInvTotalMass );
        pNode = EnumNextNode();
    }

    // COM
    m_hPose.vCenterOfMass = _ComputeCenterOfMass();

    // Deltas
    m_hPose.arrDeltas.Clear();

    EnumNodes();
    pNode = EnumNextNode();
    while( pNode != NULL ) {
        m_hPose.arrDeltas.Push( pNode->Position - m_hPose.vCenterOfMass );
        pNode = EnumNextNode();
    }

    // Volume
    m_hPose.fVolume = ( (bIsVolume) ? _ComputeVolume() : 0.0f );

    // BaseScaling
    Matrix3 matBaseScaling;
    matBaseScaling.MakeNull();

    Vector3 vTmpRow;

    EnumNodes();
    pNode = EnumNextNode();
    while( pNode != NULL ) {
        iNodeIndex = pNode->GetIndex();
        const Vector3 & vDelta = m_hPose.arrDeltas[iNodeIndex];
        const Vector3 & vWeightedDelta = ( vDelta * m_hPose.arrWeights[iNodeIndex] );
        matBaseScaling.GetRow( vTmpRow, 0 );
        matBaseScaling.SetRow( 0, vTmpRow + (vDelta * vWeightedDelta.X) );
        matBaseScaling.GetRow( vTmpRow, 1 );
        matBaseScaling.SetRow( 1, vTmpRow + (vDelta * vWeightedDelta.Y) );
        matBaseScaling.GetRow( vTmpRow, 2 );
        matBaseScaling.SetRow( 2, vTmpRow + (vDelta * vWeightedDelta.Z) );
        pNode = EnumNextNode();
    }
    matBaseScaling.Invert( m_hPose.matBaseScaling );

    // Rotation & Scaling
    m_hPose.matRotation.MakeIdentity();
    m_hPose.matScaling.MakeIdentity();
}
void CExportNel::addSkeletonBindPos (INode& skinedNode, mapBoneBindPos& boneBindPos)
{
	// Return success
	uint ok=NoError;

	// Get the skin modifier
	Modifier* skin=getModifier (&skinedNode, SKIN_CLASS_ID);

	// Found it ?
	if (skin)
	{
		// Get a com_skin2 interface
		ISkin *comSkinInterface=(ISkin*)skin->GetInterface (SKIN_INTERFACE);

		// Should been controled with isSkin before.
		nlassert (comSkinInterface);

		// Found com_skin2 ?
		if (comSkinInterface)
		{
			// Get local data
			ISkinContextData *localData=comSkinInterface->GetContextInterface(&skinedNode);

			// Should been controled with isSkin before.
			nlassert (localData);

			// Found ?
			if (localData)
			{
				// Check same vertices count
				uint vertCount=localData->GetNumPoints();

				// For each vertex
				for (uint vert=0; vert<vertCount; vert++)
				{
					// Get bones count for this vertex
					uint boneCount=localData->GetNumAssignedBones (vert);

					// For each bones
					for (uint bone=0; bone<boneCount; bone++)
					{
						// Get the bone id
						int boneId=localData->GetAssignedBone(vert, bone);

						// Get bone INode*
						INode *boneNode=comSkinInterface->GetBone(boneId);

						// Get the bind matrix of the bone
						Matrix3 bindPos;
						comSkinInterface->GetBoneInitTM(boneNode, bindPos);

						// Add an entry inthe map
						boneBindPos.insert (mapBoneBindPos::value_type (boneNode, bindPos));
					}
				}
			}

			// Release the interface
			skin->ReleaseInterface (SKIN_INTERFACE, comSkinInterface);
		}
	}
	else
	{
		// Get the skin modifier
		Modifier* skin=getModifier (&skinedNode, PHYSIQUE_CLASS_ID);

		// Should been controled with isSkin before.
		nlassert (skin);

		// Found it ?
		if (skin)
		{
			// Get a com_skin2 interface
			IPhysiqueExport *physiqueInterface=(IPhysiqueExport *)skin->GetInterface (I_PHYINTERFACE);

			// Should been controled with isSkin before.
			nlassert (physiqueInterface);

			// Found com_skin2 ?
			if (physiqueInterface)
			{
				// Get local data
				IPhyContextExport *localData=physiqueInterface->GetContextInterface(&skinedNode);

				// Should been controled with isSkin before.
				nlassert (localData);

				// Found ?
				if (localData)
				{
					// Use rigid export
					localData->ConvertToRigid (TRUE);

					// Allow blending
					localData->AllowBlending (TRUE);

					// Check same vertices count
					uint vertCount=localData->GetNumberVertices();

					// For each vertex
					for (uint vert=0; vert<vertCount; vert++)
					{
						if (vert==111)
							int toto=0;
						// Get a vertex interface
						IPhyVertexExport *vertexInterface=localData->GetVertexInterface (vert);

						// Check if it is a rigid vertex or a blended vertex
						int type=vertexInterface->GetVertexType ();
						if (type==RIGID_TYPE)
						{
							// this is a rigid vertex
							IPhyRigidVertex			*rigidInterface=(IPhyRigidVertex*)vertexInterface;

							// Get bone INode*
							INode *bone=rigidInterface->GetNode();

							// Get the bind matrix of the bone
							Matrix3 bindPos;
							int res=physiqueInterface->GetInitNodeTM (bone, bindPos);
							nlassert (res==MATRIX_RETURNED);

							// Add an entry inthe map
							if (boneBindPos.insert (mapBoneBindPos::value_type (bone, bindPos)).second)
							{
#ifdef NL_DEBUG
								// *** Debug info

								// Bone name
								std::string boneName=getName (*bone);

								// Local matrix
								Matrix3 nodeTM;
								nodeTM=bone->GetNodeTM (0);

								// Offset matrix
								Matrix3 offsetScaleTM (TRUE);
								Matrix3 offsetRotTM (TRUE);
								Matrix3 offsetPosTM (TRUE);
								ApplyScaling (offsetScaleTM, bone->GetObjOffsetScale ());
								offsetRotTM.SetRotate (bone->GetObjOffsetRot ());
								offsetPosTM.SetTrans (bone->GetObjOffsetPos ());
								Matrix3 offsetTM = offsetScaleTM * offsetRotTM * offsetPosTM;

								// Local + offset matrix
								Matrix3 nodeOffsetTM = offsetTM * nodeTM;

								// Init TM
								Matrix3 initTM;
								int res=physiqueInterface->GetInitNodeTM (bone, initTM);
								nlassert (res==MATRIX_RETURNED);

								// invert
								initTM.Invert();
								Matrix3 compNode=nodeTM*initTM;
								Matrix3 compOffsetNode=nodeOffsetTM*initTM;
								Matrix3 compOffsetNode2=nodeOffsetTM*initTM;
#endif // NL_DEBUG
							}
						}
						else
						{
							// It must be a blendable vertex
							nlassert (type==RIGID_BLENDED_TYPE);
							IPhyBlendedRigidVertex	*blendedInterface=(IPhyBlendedRigidVertex*)vertexInterface;

							// For each bones
							uint boneIndex;
							uint count=(uint)blendedInterface->GetNumberNodes ();
							for (boneIndex=0; boneIndex<count; boneIndex++)
							{
								// Get the bone pointer
								INode *bone = blendedInterface->GetNode(boneIndex);

								if (bone == NULL)
								{
									nlwarning("bone == NULL; boneIndex = %i / %i", boneIndex, count);
								}
								else
								{
									// Get the bind matrix of the bone
									Matrix3 bindPos;
									int res = physiqueInterface->GetInitNodeTM (bone, bindPos);

									if (res != MATRIX_RETURNED)
									{
										nlwarning("res != MATRIX_RETURNED; res = %i; boneIndex = %i / %i", res, boneIndex, count);
										nlwarning("bone = %i", (uint32)(void *)bone);
										std::string boneName = getName (*bone);
										nlwarning("boneName = %s", boneName.c_str());
										nlassert(false);
									}

									// Add an entry inthe map
									if (boneBindPos.insert (mapBoneBindPos::value_type (bone, bindPos)).second)
									{
	#ifdef NL_DEBUG
										// *** Debug info

										// Bone name
										std::string boneName=getName (*bone);

										// Local matrix
										Matrix3 nodeTM;
										nodeTM=bone->GetNodeTM (0);

										// Offset matrix
										Matrix3 offsetScaleTM (TRUE);
										Matrix3 offsetRotTM (TRUE);
										Matrix3 offsetPosTM (TRUE);
										ApplyScaling (offsetScaleTM, bone->GetObjOffsetScale ());
										offsetRotTM.SetRotate (bone->GetObjOffsetRot ());
										offsetPosTM.SetTrans (bone->GetObjOffsetPos ());
										Matrix3 offsetTM = offsetScaleTM * offsetRotTM * offsetPosTM;

										// Local + offset matrix
										Matrix3 nodeOffsetTM = offsetTM * nodeTM;

										// Init TM
										Matrix3 initTM;
										int res=physiqueInterface->GetInitNodeTM (bone, initTM);
										nlassert (res==MATRIX_RETURNED);

										// invert
										initTM.Invert();
										Matrix3 compNode=nodeTM*initTM;
										Matrix3 compOffsetNode=nodeOffsetTM*initTM;
										Matrix3 compOffsetNode2=nodeOffsetTM*initTM;
#endif // NL_DEBUG
									}
								}
							}
						}
					
						// Release vertex interfaces
						localData->ReleaseVertexInterface (vertexInterface);
					}

					// Release locaData interface
					physiqueInterface->ReleaseContextInterface (localData);
				}

				// Release the interface
				skin->ReleaseInterface (SKIN_INTERFACE, physiqueInterface);
			}
		}
	}
}
void HavokExport::makeHavokRigidBody(NiNodeRef parent, INode *ragdollParent, float scale) {

	this->scale = scale;

	Object *Obj = ragdollParent->GetObjectRef();

	Modifier* rbMod = nullptr;
	Modifier* shapeMod = nullptr;
	Modifier* constraintMod = nullptr;

	SimpleObject* havokTaperCapsule = nullptr;

	//get modifiers
	

	while (Obj->SuperClassID() == GEN_DERIVOB_CLASS_ID) {
		IDerivedObject *DerObj = static_cast<IDerivedObject *> (Obj);
		const int nMods = DerObj->NumModifiers(); //it is really the last modifier on the stack, and not the total number of modifiers

		for (int i = 0; i < nMods; i++)
		{
			Modifier *Mod = DerObj->GetModifier(i);
			if (Mod->ClassID() == HK_RIGIDBODY_MODIFIER_CLASS_ID) {
				rbMod = Mod;
			}
			if (Mod->ClassID() == HK_SHAPE_MODIFIER_CLASS_ID) {
				shapeMod = Mod;
			}
			if (Mod->ClassID() == HK_CONSTRAINT_RAGDOLL_CLASS_ID || Mod->ClassID() == HK_CONSTRAINT_HINGE_CLASS_ID) {
				constraintMod = Mod;
			}
		}
		if (Obj->SuperClassID() == GEOMOBJECT_CLASS_ID) {
			havokTaperCapsule = (SimpleObject*)Obj;
		}
		Obj = DerObj->GetObjRef();
	}

	
	if (!rbMod) {
		throw exception(FormatText("No havok rigid body modifier found on %s", ragdollParent->GetName()));
	}
	if (!shapeMod) {
		throw exception(FormatText("No havok shape modifier found on %s", ragdollParent->GetName()));
	}

//	Object* taper = ragdollParent->GetObjectRef();
	IParamBlock2* taperParameters = Obj->GetParamBlockByID(PB_TAPEREDCAPSULE_OBJ_PBLOCK);
	float radius;
	enum
	{
		// GENERAL PROPERTIES ROLLOUT
		PA_TAPEREDCAPSULE_OBJ_RADIUS = 0,
		PA_TAPEREDCAPSULE_OBJ_TAPER,
		PA_TAPEREDCAPSULE_OBJ_HEIGHT,
		PA_TAPEREDCAPSULE_OBJ_VERSION_INTERNAL,
	};
	taperParameters->GetValue(PA_TAPEREDCAPSULE_OBJ_RADIUS, 0, radius, FOREVER);
	

	int shapeType;
	if (IParamBlock2* shapeParameters = shapeMod->GetParamBlockByID(PB_SHAPE_MOD_PBLOCK)) {
		shapeParameters->GetValue(PA_SHAPE_MOD_SHAPE_TYPE,0,shapeType,FOREVER);
	}

	//Havok Shape
	bhkShapeRef shape;

	if (shapeType == 2) {

		// Capsule
		bhkCapsuleShapeRef capsule = new bhkCapsuleShape();
		capsule->SetRadius(radius/scale);
		capsule->SetRadius1(radius/scale);
		capsule->SetRadius2(radius/scale);
		float length; 
		taperParameters->GetValue(PA_TAPEREDCAPSULE_OBJ_HEIGHT, 0, length, FOREVER);
		//get the normal
		Matrix3 axis(true);
		ragdollParent->GetObjOffsetRot().MakeMatrix(axis);
		Point3 normalAx = axis.GetRow(2);
		//capsule center
		Point3 center = ragdollParent->GetObjOffsetPos();
		//min and max points
		Point3 pt1 = center - normalAx*(length/2);
		Point3 pt2 = center + normalAx*(length/2);

		capsule->SetFirstPoint(TOVECTOR3(pt1)/scale);
		capsule->SetSecondPoint(TOVECTOR3(pt2)/scale);
		capsule->SetMaterial(HAV_MAT_SKIN);

		shape = StaticCast<bhkShape>(capsule);
		
	}
	else {
		// Sphere
		//CalcBoundingSphere(node, tm.GetTrans(), radius, 0);

		bhkSphereShapeRef sphere = new bhkSphereShape();
		sphere->SetRadius(radius/scale);
		sphere->SetMaterial(HAV_MAT_SKIN);
		shape = StaticCast<bhkShape>(sphere);
	}

	bhkRigidBodyRef body;

	if (shape)
	{
		bhkBlendCollisionObjectRef blendObj = new bhkBlendCollisionObject();
		body = new bhkRigidBody();

		Matrix3 tm = ragdollParent->GetObjTMAfterWSM(0);
		
		//Calculate Object Offset Matrix
		Matrix3 otm(1);
		Point3 pos = ragdollParent->GetObjOffsetPos();
		otm.PreTranslate(pos);
		Quat quat = ragdollParent->GetObjOffsetRot();
		PreRotateMatrix(otm, quat);
		Matrix3 otmInvert = otm;
		otmInvert.Invert();

		//correct object tm
		Matrix3 tmbhk = otmInvert * tm;

		//set geometric parameters
		body->SetRotation(TOQUATXYZW(Quat(tmbhk).Invert()));
		body->SetTranslation(TOVECTOR4(tmbhk.GetTrans() / scale));
		body->SetCenter(TOVECTOR4(ragdollParent->GetObjOffsetPos())/scale);

		//set physics
		if (IParamBlock2* rbParameters = rbMod->GetParamBlockByID(PB_RB_MOD_PBLOCK)) {
			//These are fundamental parameters

			int lyr = NP_DEFAULT_HVK_LAYER;
			int mtl = NP_DEFAULT_HVK_MATERIAL;
			int msys = NP_DEFAULT_HVK_MOTION_SYSTEM;
			int qtype = NP_DEFAULT_HVK_QUALITY_TYPE;
			float mass = NP_DEFAULT_HVK_MASS;
			float lindamp = NP_DEFAULT_HVK_LINEAR_DAMPING;
			float angdamp = NP_DEFAULT_HVK_ANGULAR_DAMPING;
			float frict = NP_DEFAULT_HVK_FRICTION;
			float maxlinvel = NP_DEFAULT_HVK_MAX_LINEAR_VELOCITY;
			float maxangvel = NP_DEFAULT_HVK_MAX_ANGULAR_VELOCITY;
			float resti = NP_DEFAULT_HVK_RESTITUTION;
			float pendepth = NP_DEFAULT_HVK_PENETRATION_DEPTH;
			Point3 InertiaTensor;


			rbParameters->GetValue(PA_RB_MOD_MASS, 0, mass, FOREVER);
			rbParameters->GetValue(PA_RB_MOD_RESTITUTION, 0, resti, FOREVER);
			rbParameters->GetValue(PA_RB_MOD_FRICTION, 0, frict, FOREVER);
			rbParameters->GetValue(PA_RB_MOD_INERTIA_TENSOR, 0, InertiaTensor, FOREVER);


			rbParameters->GetValue(PA_RB_MOD_LINEAR_DAMPING, 0, lindamp, FOREVER);
			rbParameters->GetValue(PA_RB_MOD_CHANGE_ANGULAR_DAMPING, 0, angdamp, FOREVER);

			rbParameters->GetValue(PA_RB_MOD_MAX_LINEAR_VELOCITY, 0, maxlinvel, FOREVER);
			rbParameters->GetValue(PA_RB_MOD_MAX_ANGULAR_VELOCITY, 0, maxangvel, FOREVER);

			rbParameters->GetValue(PA_RB_MOD_ALLOWED_PENETRATION_DEPTH, 0, pendepth, FOREVER);
			rbParameters->GetValue(PA_RB_MOD_QUALITY_TYPE, 0, qtype, FOREVER);

			body->SetMass(mass);
			body->SetRestitution(resti);
			body->SetFriction(frict);
			body->SetLinearDamping(lindamp);
			body->SetMaxLinearVelocity(maxlinvel);
			body->SetMaxAngularVelocity(maxangvel);
			body->SetPenetrationDepth(pendepth);
			InertiaMatrix im;
			im[0][0] = InertiaTensor[0];
			im[1][1] = InertiaTensor[1];
			im[2][2] = InertiaTensor[2];

			body->SetInertia(im);

			/*switch (qtype) {
			case QT_FIXED:
				body->SetQualityType(MO_QUAL_FIXED);
				break;
			case QT_KEYFRAMED:
				body->SetQualityType(MO_QUAL_KEYFRAMED);
				break;
			case QT_DEBRIS:
				body->SetQualityType(MO_QUAL_DEBRIS);
				break;
			case QT_MOVING:
				body->SetQualityType(MO_QUAL_MOVING);
				break;
			case QT_CRITICAL:
				body->SetQualityType(MO_QUAL_CRITICAL);
				break;
			case QT_BULLET:
				body->SetQualityType(MO_QUAL_BULLET);
				break;
			case QT_KEYFRAMED_REPORTING:
				body->SetQualityType(MO_QUAL_KEYFRAMED_REPORT);
				break;
			}*/

			body->SetSkyrimLayer(SkyrimLayer::SKYL_BIPED);
			body->SetSkyrimLayerCopy(SkyrimLayer::SKYL_BIPED);

			body->SetMotionSystem(MotionSystem::MO_SYS_BOX);
			body->SetDeactivatorType(DeactivatorType::DEACTIVATOR_NEVER);
			body->SetSolverDeactivation(SolverDeactivation::SOLVER_DEACTIVATION_LOW);
			body->SetQualityType(MO_QUAL_FIXED);

		}
		
		if (constraintMod && ragdollParent->GetParentNode() && parent->GetParent()) {
			if (constraintMod->ClassID() == HK_CONSTRAINT_RAGDOLL_CLASS_ID) {
				bhkRagdollConstraintRef ragdollConstraint = new bhkRagdollConstraint();
				
				//entities
				ragdollConstraint->AddEntity(body);
				NiNodeRef parentRef = parent->GetParent();
				bhkRigidBodyRef nifParentRigidBody;
				while (parentRef) {
					if (parentRef->GetCollisionObject()) {
						nifParentRigidBody = StaticCast<bhkRigidBody>(StaticCast<bhkBlendCollisionObject>(parentRef->GetCollisionObject())->GetBody());
						break;
					}
					parentRef = parentRef->GetParent();
				}
				if (!nifParentRigidBody)
					throw exception(FormatText("Unable to find NIF constraint parent for ragdoll node %s", ragdollParent->GetName()));
				ragdollConstraint->AddEntity(nifParentRigidBody);

				RagdollDescriptor desc;
				//parameters
				if (IParamBlock2* constraintParameters = constraintMod->GetParamBlockByID(PB_CONSTRAINT_MOD_COMMON_SPACES_PARAMS)) {
					Point3 pivotA;
					Matrix3 parentRotation;
					Point3 pivotB;
					Matrix3 childRotation;
					constraintParameters->GetValue(PA_CONSTRAINT_MOD_CHILD_SPACE_TRANSLATION, 0, pivotB, FOREVER);
					constraintParameters->GetValue(PA_CONSTRAINT_MOD_CHILD_SPACE_ROTATION, 0, childRotation, FOREVER);
					constraintParameters->GetValue(PA_CONSTRAINT_MOD_PARENT_SPACE_TRANSLATION, 0, pivotA, FOREVER);
					constraintParameters->GetValue(PA_CONSTRAINT_MOD_PARENT_SPACE_ROTATION, 0, parentRotation, FOREVER);
					
					desc.pivotA = TOVECTOR4(pivotA);
					desc.pivotB = TOVECTOR4(pivotB);
					desc.planeA = TOVECTOR4(parentRotation.GetRow(0));
					desc.motorA = TOVECTOR4(parentRotation.GetRow(1));
					desc.twistA = TOVECTOR4(parentRotation.GetRow(2));
					desc.planeB = TOVECTOR4(childRotation.GetRow(0));
					desc.motorB = TOVECTOR4(childRotation.GetRow(1));
					desc.twistB = TOVECTOR4(childRotation.GetRow(2));
					
				}
				if (IParamBlock2* constraintParameters = constraintMod->GetParamBlockByID(PB_RAGDOLL_MOD_PBLOCK)) {
					float coneMaxAngle;
					float planeMinAngle;
					float planeMaxAngle;
					float coneMinAngle;
					float twistMinAngle;
					float maxFriction;

					constraintParameters->GetValue(PA_RAGDOLL_MOD_CONE_ANGLE, 0, coneMaxAngle, FOREVER);
					constraintParameters->GetValue(PA_RAGDOLL_MOD_PLANE_MIN, 0, planeMinAngle, FOREVER);
					constraintParameters->GetValue(PA_RAGDOLL_MOD_PLANE_MAX, 0, planeMaxAngle, FOREVER);
					constraintParameters->GetValue(PA_RAGDOLL_MOD_TWIST_MIN, 0, coneMinAngle, FOREVER);
					constraintParameters->GetValue(PA_RAGDOLL_MOD_TWIST_MAX, 0, twistMinAngle, FOREVER);
					constraintParameters->GetValue(PA_RAGDOLL_MOD_MAX_FRICTION_TORQUE, 0, maxFriction, FOREVER);

					desc.coneMaxAngle = TORAD(coneMaxAngle);
					desc.planeMinAngle = TORAD(planeMinAngle);
					desc.planeMaxAngle = TORAD(planeMaxAngle);
					desc.coneMaxAngle = TORAD(coneMinAngle);
					desc.twistMinAngle = TORAD(twistMinAngle);
					desc.maxFriction = maxFriction;


				}
				ragdollConstraint->SetRagdoll(desc);
				body->AddConstraint(ragdollConstraint);
			}
			else if (constraintMod->ClassID() == HK_CONSTRAINT_HINGE_CLASS_ID) {
				bhkLimitedHingeConstraintRef limitedHingeConstraint = new bhkLimitedHingeConstraint();

				//entities
				limitedHingeConstraint->AddEntity(body);
				NiNodeRef parentRef = parent->GetParent();
				bhkRigidBodyRef nifParentRigidBody;
				while (parentRef) {
					if (parentRef->GetCollisionObject()) {
						nifParentRigidBody = StaticCast<bhkRigidBody>(StaticCast<bhkBlendCollisionObject>(parentRef->GetCollisionObject())->GetBody());
						break;
					}
					parentRef = parentRef->GetParent();
				}
				if (!nifParentRigidBody)
					throw exception(FormatText("Unable to find NIF constraint parent for limited hinge node %s", ragdollParent->GetName()));
				limitedHingeConstraint->AddEntity(nifParentRigidBody);

				LimitedHingeDescriptor lh;

				if (IParamBlock2* constraintParameters = constraintMod->GetParamBlockByID(PB_CONSTRAINT_MOD_COMMON_SPACES_PARAMS)) {
					Matrix3 parentRotation;
					Matrix3 childRotation;
					constraintParameters->GetValue(PA_CONSTRAINT_MOD_CHILD_SPACE_ROTATION, 0, childRotation, FOREVER);
					constraintParameters->GetValue(PA_CONSTRAINT_MOD_PARENT_SPACE_ROTATION, 0, parentRotation, FOREVER);

					lh.perp2AxleInA1 = TOVECTOR4(parentRotation.GetRow(0));
					lh.perp2AxleInA2 = TOVECTOR4(parentRotation.GetRow(1));
					lh.axleA = TOVECTOR4(parentRotation.GetRow(2));
					lh.perp2AxleInB1 = TOVECTOR4(childRotation.GetRow(0));
					lh.perp2AxleInB2 = TOVECTOR4(childRotation.GetRow(1));
					lh.axleB = TOVECTOR4(childRotation.GetRow(2));
					
				}
				if (IParamBlock2* constraintParameters = constraintMod->GetParamBlockByID(PB_HINGE_MOD_PBLOCK)) {
					float minAngle;
					float maxAngle;
					float maxFriction;

					constraintParameters->GetValue(PA_HINGE_MOD_LIMIT_MIN, 0, minAngle, FOREVER);
					constraintParameters->GetValue(PA_HINGE_MOD_LIMIT_MAX, 0, maxAngle, FOREVER);
					constraintParameters->GetValue(PA_HINGE_MOD_MAX_FRICTION_TORQUE, 0, maxFriction, FOREVER);
					//	constraintParameters->SetValue(PA_HINGE_MOD_MOTOR_TYPE, 0, lh.motor., 0);

					lh.minAngle = TORAD(minAngle);
					lh.maxAngle = TORAD(maxAngle);
					lh.maxAngle = maxFriction;

				}
				limitedHingeConstraint->SetLimitedHinge(lh);
				body->AddConstraint(limitedHingeConstraint);
			}
		}


		//InitializeRigidBody(body, node);
		body->SetShape(shape);
		blendObj->SetBody(StaticCast<NiObject>(body));
		parent->SetCollisionObject(StaticCast<NiCollisionObject>(blendObj));
	}

	////rigid body parameters
	//	// get data from node
	//int lyr = NP_DEFAULT_HVK_LAYER;
	//int mtl = NP_DEFAULT_HVK_MATERIAL;
	//int msys = NP_DEFAULT_HVK_MOTION_SYSTEM;
	//int qtype = NP_DEFAULT_HVK_QUALITY_TYPE;
	//float mass = NP_DEFAULT_HVK_MASS;
	//float lindamp = NP_DEFAULT_HVK_LINEAR_DAMPING;
	//float angdamp = NP_DEFAULT_HVK_ANGULAR_DAMPING;
	//float frict = NP_DEFAULT_HVK_FRICTION;
	//float maxlinvel = NP_DEFAULT_HVK_MAX_LINEAR_VELOCITY;
	//float maxangvel = NP_DEFAULT_HVK_MAX_ANGULAR_VELOCITY;
	//float resti = NP_DEFAULT_HVK_RESTITUTION;
	//float pendepth = NP_DEFAULT_HVK_PENETRATION_DEPTH;
	//BOOL transenable = TRUE;

	//if (IParamBlock2* rbParameters = rbMod->GetParamBlockByID(PB_SHAPE_MOD_PBLOCK))
	//{
	//	//These are fundamental parameters
	//	rbParameters->GetValue(PA_RB_MOD_MASS, 0, mass, FOREVER);
	//	rbParameters->GetValue(PA_RB_MOD_RESTITUTION, 0, resti, FOREVER);
	//	rbParameters->GetValue(PA_RB_MOD_FRICTION, 0, frict, FOREVER);

	//	rbParameters->GetValue(PA_RB_MOD_LINEAR_DAMPING, 0, lindamp, FOREVER);
	//	rbParameters->GetValue(PA_RB_MOD_CHANGE_ANGULAR_DAMPING, 0, angdamp, FOREVER);

	//	rbParameters->GetValue(PA_RB_MOD_MAX_LINEAR_VELOCITY, 0, maxlinvel, FOREVER);
	//	rbParameters->GetValue(PA_RB_MOD_MAX_ANGULAR_VELOCITY, 0, maxangvel, FOREVER);

	//	rbParameters->GetValue(PA_RB_MOD_ALLOWED_PENETRATION_DEPTH, 0, pendepth, FOREVER);

	//	rbParameters->GetValue(PA_RB_MOD_QUALITY_TYPE, 0, qtype, FOREVER);


	//	switch (qtype) {
	//	case MO_QUAL_INVALID:
	//		break;
	//	case QT_FIXED:
	//		rbParameters->SetValue(PA_RB_MOD_QUALITY_TYPE, 0, MO_QUAL_FIXED, 0);
	//		break;
	//	case MO_QUAL_KEYFRAMED:
	//		rbParameters->SetValue(PA_RB_MOD_QUALITY_TYPE, 0, QT_KEYFRAMED, 0);
	//		break;
	//	case MO_QUAL_DEBRIS:
	//		rbParameters->SetValue(PA_RB_MOD_QUALITY_TYPE, 0, QT_DEBRIS, 0);
	//		break;
	//	case MO_QUAL_MOVING:
	//		rbParameters->SetValue(PA_RB_MOD_QUALITY_TYPE, 0, QT_MOVING, 0);
	//		break;
	//	case MO_QUAL_CRITICAL:
	//		rbParameters->SetValue(PA_RB_MOD_QUALITY_TYPE, 0, QT_CRITICAL, 0);
	//		break;
	//	case MO_QUAL_BULLET:
	//		rbParameters->SetValue(PA_RB_MOD_QUALITY_TYPE, 0, QT_BULLET, 0);
	//		break;
	//	case MO_QUAL_USER:
	//		break;
	//	case MO_QUAL_CHARACTER:
	//		break;
	//	case MO_QUAL_KEYFRAMED_REPORT:
	//		rbParameters->SetValue(PA_RB_MOD_QUALITY_TYPE, 0, QT_KEYFRAMED_REPORTING, 0);
	//		break;
	//	}

	//	// setup body
	//	bhkRigidBodyRef body = transenable ? new bhkRigidBodyT() : new bhkRigidBody();

	//	OblivionLayer obv_layer; SkyrimLayer sky_layer;
	//	GetHavokLayersFromIndex(lyr, (int*)&obv_layer, (int*)&sky_layer);
	//	body->SetLayer(obv_layer);
	//	body->SetLayerCopy(obv_layer);
	//	body->SetSkyrimLayer(sky_layer);

	//	body->SetMotionSystem(MotionSystem(msys));
	//	body->SetQualityType(MotionQuality(qtype));
	//	body->SetMass(mass);
	//	body->SetLinearDamping(lindamp);
	//	body->SetAngularDamping(angdamp);
	//	body->SetFriction(frict);
	//	body->SetRestitution(resti);
	//	body->SetMaxLinearVelocity(maxlinvel);
	//	body->SetMaxAngularVelocity(maxangvel);
	//	body->SetPenetrationDepth(pendepth);
	//	body->SetCenter(center);
	//	QuaternionXYZW q; q.x = q.y = q.z = 0; q.w = 1.0f;
	//	body->SetRotation(q);
	//}
}