#include "MaxNode.h"
#include <SimpObj.h>
#include "MxUtils.h"
#include "MaxWorld.h"
#include "PxPlugin.h"
ccMaxNode::ccMaxNode(INode* node) : MaxINode(node), MaxNodeTM(true), ScaledIsUnified(true), ShapeType(NX_SHAPE_MESH)
{
SetNode(node);
}
ccMaxNode::~ccMaxNode()
{
}
void ccMaxNode::SetNode(INode* node)
{
MaxINode = node;
SimpleMesh.release();
ScaledIsUnified = true;
MaxNodeTM.IdentityMatrix();
if(MaxINode) {
SyncFromMaxMesh();
}
}
/*
Transfer the max Node's mesh to PhysX unit and store it.
*/
void ccMaxNode::SyncFromMaxMesh()
{
ShapeType = NX_SHAPE_MESH;
const TimeValue t = ccMaxWorld::MaxTime();
MaxNodeTM = MaxINode->GetNodeTM(t);
MaxNodeTM = ccMaxWorld::ChangeToPhysXUnit(MaxNodeTM);
// get pivot TM
MaxPivotTM.IdentityMatrix();
MaxPivotTM.SetTrans(MaxINode->GetObjOffsetPos() * ccMaxWorld::GetUnitChange());
PreRotateMatrix(MaxPivotTM, MaxINode->GetObjOffsetRot());
ScaleValue scaleValue = MaxINode->GetObjOffsetScale();
ApplyScaling(MaxPivotTM, scaleValue);
// get scale TM
Point3 maxNodeScale = ccMaxWorld::ParseScale(MaxNodeTM, MaxNodeScaleTM, MaxNodePoseTM);
////modify pivotTM with scale
//Point3 pivot = MaxPivotTM.GetRow(3);
//NxMat34 scMat = MxMathUtils::MaxMatrixToNx(MaxNodeScaleTM);
//scMat.multiply(NxVec3(pivot.x, pivot.y, pivot.z), (NxVec3&) pivot);
//MaxPivotTM.SetRow(3, pivot);
////MaxPivotTM = MaxPivotTM * MaxNodeScaleTM;
MaxNodePoseTMInv = Inverse(MaxNodePoseTM);
NxReal tolerence = 0.01f;
// check whether the Node's mesh is scaled equally at x/y/z
ScaledIsUnified = (fabs((maxNodeScale.x - maxNodeScale.z)/maxNodeScale.z) < tolerence) && (fabs((maxNodeScale.y - maxNodeScale.z)/maxNodeScale.z) < tolerence);
Object* obj = MaxINode->EvalWorldState(t).obj;
if (obj != NULL)
{
SimpleObject* so = (SimpleObject*)obj;
Class_ID id = obj->ClassID();
if (id == Class_ID(SPHERE_CLASS_ID, 0)) {
ShapeType = NX_SHAPE_SPHERE;
so->pblock->GetValue(SPHERE_RADIUS, 0, PrimaryShapePara.Radius, FOREVER);
PrimaryShapePara.Radius *= maxNodeScale.x; // x/y/z is scaled with a same value
}
else if (id == Class_ID(BOXOBJ_CLASS_ID, 0)) {
ShapeType = NX_SHAPE_BOX;
so->pblock->GetValue(BOXOBJ_WIDTH , 0, PrimaryShapePara.BoxDimension.x, FOREVER);
so->pblock->GetValue(BOXOBJ_LENGTH, 0, PrimaryShapePara.BoxDimension.y, FOREVER);
so->pblock->GetValue(BOXOBJ_HEIGHT, 0, PrimaryShapePara.BoxDimension.z, FOREVER);
PrimaryShapePara.BoxDimension *= (0.5f * maxNodeScale.x); // x/y/z is scaled with a same value // Physics box is half the size
}
else if (id == CAPS_CLASS_ID) {
ShapeType = NX_SHAPE_CAPSULE;
int centersflag = 0;
so->pblock->GetValue(CAPS_RADIUS , 0, PrimaryShapePara.Radius, FOREVER);
so->pblock->GetValue(CAPS_HEIGHT , 0, PrimaryShapePara.Height, FOREVER);
so->pblock->GetValue(CAPS_CENTERS, 0, centersflag, FOREVER);
if(!centersflag) //there are some different ways in which you can specify a capsule in 3ds max, adjust length if "center" mode is not used
PrimaryShapePara.Height -= PrimaryShapePara.Radius * 2.0f;
PrimaryShapePara.Radius *= maxNodeScale.x; // x/y/z is scaled with a same value
PrimaryShapePara.Height *= maxNodeScale.x; // x/y/z is scaled with a same value
}
}
if(! ScaledIsUnified)
ShapeType = NX_SHAPE_MESH;
// Disable backface culling for cloth
//MaxINode->BackCull(FALSE);
// get mesh
BOOL needDel = FALSE;
TriObject* tri = MxUtils::GetTriObjectFromNode(MaxINode, t, needDel);
if (tri == NULL) return;
Mesh& mesh = tri->GetMesh();
SimpleMesh.alloc(mesh.getNumVerts(), mesh.getNumFaces());
for(NxU32 i = 0; i < SimpleMesh.numPoints; i++)
{
Point3 tmp = mesh.verts[i] * MaxNodeScaleTM;
((Point3*)SimpleMesh.points)[i] = tmp; // systemTM is unit change TM.
}
for(NxU32 i = 0; i < SimpleMesh.numFaces; i++)
{
for(NxU32 j = 0; j < 3; j++)
{
SimpleMesh.faces[i*3+j] = mesh.faces[i].v[j];
}
}
if (needDel)
tri->DeleteMe();
}
// transfer the Max node pose to PhysX pose. Need consider unit scaling
Matrix3& ccMaxNode::PoseToMax(NxMat34& pose)
{
Matrix3 p = MxMathUtils::NxMatrixToMax(pose);
p = ccMaxWorld::ChangeToMaxUnit(p);
return (MaxNodeScaleTM * p);
}
/*
use simulated PhysX Pose to update Max Node's pose. Need consider unit scaling
*/
void ccMaxNode::SetSimulatedPose(NxMat34& pose)
{
Matrix3 p = PoseToMax(pose);
MaxINode->SetNodeTM(ccMaxWorld::MaxTime(), p);
}
/*
Use stored original pose to reset the Max node
*/
void ccMaxNode::RestorePose()
{
Matrix3 org = MaxNodeTM;
org = ccMaxWorld::ChangeToMaxUnit(org);
MaxINode->SetNodeTM(ccMaxWorld::MaxTime(), org);
}
Matrix3& ccMaxNode::GetCurrentTM()
{
return ccMaxWorld::GetCurrentTM(MaxINode);
}