From fb61ccae4c9abe5d28e5a40901f9a6a91f82edf1 Mon Sep 17 00:00:00 2001
From: Tazpn <tazpn@users.sourceforge.net>
Date: Sat, 24 Jun 2006 22:14:40 +0000
Subject: [PATCH] Add options to force nubs to point back to parent node at the
 expense of the rotation data.  It looks better. Need to alter the zAxis
 instead I think.

---
 NifImport/MaxNifImport.cpp | 34 +++++++++++++++++++++++++---------
 NifImport/MaxNifTools.ini  |  6 ++++++
 NifImport/niutils.cpp      | 18 +++++++++++-------
 NifImport/niutils.h        | 14 +++++++++++++-
 4 files changed, 55 insertions(+), 17 deletions(-)

diff --git a/NifImport/MaxNifImport.cpp b/NifImport/MaxNifImport.cpp
index 5486090..503f24a 100644
--- a/NifImport/MaxNifImport.cpp
+++ b/NifImport/MaxNifImport.cpp
@@ -107,6 +107,11 @@ public:
    bool hasSkeleton;
    bool isBiped;
    bool removeUnusedImportedBones;
+   bool forceRotation;
+
+   float minBoneWidth;
+   float maxBoneWidth;
+   float boneWidthToLengthRatio;
 
    vector<NiObjectRef> blocks;
    vector<NiNodeRef> nodes;
@@ -169,6 +174,8 @@ public:
 
    bool ImportSkin(ImpNode *node, NiTriBasedGeomRef triGeom);
    Texmap* CreateTexture(TexDesc& desc);
+
+   INode *CreateBone(const string& name, Point3 startPos, Point3 endPos, Point3 zAxis);
 };
 
 
@@ -475,6 +482,11 @@ void NifImporter::LoadIniSettings()
    bipedAnkleAttach = GetIniValue<float>(BipedImportSection, "BipedAnkleAttach", 0.2f);
    bipedTrianglePelvis = GetIniValue<bool>(BipedImportSection, "BipedTrianglePelvis", false);
    removeUnusedImportedBones = GetIniValue<bool>(BipedImportSection, "RemoveUnusedImportedBones", false);
+   forceRotation = GetIniValue<bool>(BipedImportSection, "ForceRotation", false);
+
+   minBoneWidth = GetIniValue<float>(BipedImportSection, "MinBoneWidth", 0.5f);
+   maxBoneWidth = GetIniValue<float>(BipedImportSection, "MaxBoneWidth", 3.0f);
+   boneWidthToLengthRatio = GetIniValue<float>(BipedImportSection, "BoneWidthToLengthRatio", 0.25f);
 
    importSkeleton = hasSkeleton = HasSkeleton();
    isBiped = IsBiped();
@@ -738,7 +750,7 @@ void NifImporter::ScaleBiped(IBipMaster* master, NiNodeRef block, bool Recurse)
 }
 
 
-INode *CreateBone(const string& name, Point3 startPos, Point3 endPos, Point3 zAxis)
+INode *NifImporter::CreateBone(const string& name, Point3 startPos, Point3 endPos, Point3 zAxis)
 {
    if (FPInterface * fpBones = GetCOREInterface(Interface_ID(0x438aff72, 0xef9675ac)))
    {
@@ -751,12 +763,8 @@ INode *CreateBone(const string& name, Point3 startPos, Point3 endPos, Point3 zAx
          if (INode *n = result.n)
          {
             n->SetName(const_cast<TCHAR*>(name.c_str()));
-
-            const float wmin = 0.5f;
-            const float wmax = 3.0f;
             float len = fabs(Length(startPos)-Length(endPos));
-            float width = max(wmin, min(wmax, len / 4.0f));
-
+            float width = max(minBoneWidth, min(maxBoneWidth, len * boneWidthToLengthRatio));
             if (Object* o = n->GetObjectRef())
             {
                setMAXScriptValue(o->GetReference(0), "width", 0, width);
@@ -784,6 +792,7 @@ void NifImporter::ImportBones(NiNodeRef node)
       vector<NiNodeRef> children = DynamicCast<NiNode>(node->GetChildren());
       NiNodeRef parent = node->GetParent();
 
+      PosRotScale prs = prsDefault;
       Matrix3 im = TOMATRIX3(node->GetWorldTransform(), true);
       Point3 p = im.GetTrans();
       Quat q(im);
@@ -795,13 +804,14 @@ void NifImporter::ImportBones(NiNodeRef node)
          INode *pinode = bone->GetParentNode();
          if (pinode)
             bone->Detach(0,1);
-         PositionAndRotateNode(bone, p, q);
+         PositionAndRotateNode(bone, p, q, prs);
          if (pinode)
             pinode->AttachChild(bone, 1);
       }
       else
       {
          Vector3 ppos;
+         Point3 zAxis(0,1,0);
          if (!children.empty()) {
             for (vector<NiNodeRef>::iterator itr=children.begin(), end = children.end(); itr != end; ++itr) {
                Matrix44 cwt = (*itr)->GetWorldTransform();
@@ -816,12 +826,18 @@ void NifImporter::ImportBones(NiNodeRef node)
             Matrix44 pwt = parent->GetWorldTransform();
             Matrix33 prot; float pscale;
             pwt.Decompose(ppos, prot, pscale);
+            if (forceRotation)
+               prs = prsPos;
+         }
+         else
+         {
+            if (forceRotation)
+               prs = prsPos;
          }
          Point3 pp(ppos.x, ppos.y, ppos.z);
-         Point3 zAxis(0,1,0);
          if (bone = CreateBone(name, p, pp, zAxis))
          {
-            PositionAndRotateNode(bone, p, q);
+            PositionAndRotateNode(bone, p, q, prs);
             if (parent)
             {
                if (INode *pn = gi->GetINodeByName(parent->GetName().c_str()))
diff --git a/NifImport/MaxNifTools.ini b/NifImport/MaxNifTools.ini
index f452380..fb8ea1b 100644
--- a/NifImport/MaxNifTools.ini
+++ b/NifImport/MaxNifTools.ini
@@ -44,6 +44,12 @@ BipedAnkleAttach=0.2
 BipedTrianglePelvis=0
 ; Remove unused bones from the biped on import of a mesh. Default: 1
 RemoveUnusedImportedBones=1
+; Minimum Bone Width / Maximum Bone Width / Ratio of Width to Length
+MinBoneWidth=0.5
+MaxBoneWidth=3
+BoneWidthToLengthRatio=0.25
+; Force nub to point back to parent at expense of loss of rotation. Default: 1
+ForceRotation=1
 
 
 ;; [Applications]
diff --git a/NifImport/niutils.cpp b/NifImport/niutils.cpp
index f730127..1a494b1 100644
--- a/NifImport/niutils.cpp
+++ b/NifImport/niutils.cpp
@@ -356,7 +356,7 @@ Modifier *GetSkin(INode *node)
 
 // Set Position and Rotation on a standard controller will need to handle bipeds
 //   Always in World Transform coordinates
-void PositionAndRotateNode(INode *n, Point3 p, Quat& q, TimeValue t)
+void PositionAndRotateNode(INode *n, Point3 p, Quat& q, PosRotScale prs, TimeValue t)
 {
    if (Control *c = n->GetTMController()) {
 
@@ -368,15 +368,19 @@ void PositionAndRotateNode(INode *n, Point3 p, Quat& q, TimeValue t)
          // Get the Biped Export Interface from the controller 
          //IBipedExport *BipIface = (IBipedExport *) c->GetInterface(I_BIPINTERFACE);
          IOurBipExport *BipIface = (IOurBipExport *) c->GetInterface(I_OURINTERFACE);
-         BipIface->SetBipedRotation(q, t, n, 0/*???*/);
-         BipIface->SetBipedPosition(p, t, n);
+         if (prs & prsRot)
+            BipIface->SetBipedRotation(q, t, n, 0/*???*/);
+         if (prs & prsPos)
+            BipIface->SetBipedPosition(p, t, n);
       }
       else
       {
-         if (Control *rotCtrl = c->GetRotationController())
-            rotCtrl->SetValue(t, &q, 1, CTRL_ABSOLUTE);
-         if (Control *posCtrl = c->GetPositionController())
-            posCtrl->SetValue(t, &p, 1, CTRL_ABSOLUTE);
+         if (prs & prsRot)
+            if (Control *rotCtrl = c->GetRotationController())
+               rotCtrl->SetValue(t, &q, 1, CTRL_ABSOLUTE);
+         if (prs & prsPos)
+            if (Control *posCtrl = c->GetPositionController())
+               posCtrl->SetValue(t, &p, 1, CTRL_ABSOLUTE);
       }
    }
 }
diff --git a/NifImport/niutils.h b/NifImport/niutils.h
index 2408100..6e2f12b 100644
--- a/NifImport/niutils.h
+++ b/NifImport/niutils.h
@@ -194,7 +194,15 @@ extern void FindImages(NameValueCollection& images, const string& rootPath, cons
 extern void RenameNode(Interface *gi, LPCTSTR SrcName, LPCTSTR DstName);
 extern TriObject* GetTriObject(Object *o);
 extern Modifier *GetSkin(INode *node);
-extern void PositionAndRotateNode(INode *n, Point3 p, Quat& q, TimeValue t = 0);
+
+enum PosRotScale
+{
+   prsPos = 0x1,
+   prsRot = 0x2,
+   prsScale = 0x4,
+   prsDefault = prsPos | prsRot | prsScale,
+};
+extern void PositionAndRotateNode(INode *n, Point3 p, Quat& q, PosRotScale prs = prsDefault, TimeValue t = 0);
 
 extern Niflib::NiNodeRef FindNodeByName( const vector<Niflib::NiNodeRef>& blocks, const string& name );
 extern std::vector<Niflib::NiNodeRef> SelectNodesByName( const vector<Niflib::NiNodeRef>& blocks, LPCTSTR match);
@@ -218,4 +226,8 @@ static inline Matrix3 TOMATRIX3(const Niflib::Matrix44 &tm, bool invert = true){
    return m;
 }
 
+static inline Quat TOQUAT(const Niflib::Quaternion& q){
+   return Quat(q.x, q.y, q.z, q.w);
+}
+
 #endif // _NIUTILS_H_
\ No newline at end of file
-- 
GitLab