bool Exporter::removeUnreferencedBones(NiNodeRef node) { NiNodeRef parent = node->GetParent(); bool remove = (NULL != parent) && !node->IsSkinInfluence(); Matrix44 ntm = node->GetLocalTransform(); vector<NiAVObjectRef> children = node->GetChildren(); for (vector<NiAVObjectRef>::iterator itr = children.begin(); itr != children.end(); ++itr) { NiAVObjectRef& child = (*itr); bool childRemove = false; if (child->IsDerivedType(NiNode::TYPE)) { childRemove = removeUnreferencedBones(StaticCast<NiNode>(child)); } if (childRemove) { node->RemoveChild(child); } else if (remove) // Reparent abandoned nodes to root { Matrix44 tm = child->GetLocalTransform(); child->SetLocalTransform( ntm * tm ); node->RemoveChild(child); mNiRoot->AddChild(child); } } return remove; }
/*---------------------------------------------------------------------------*/ unsigned int NifCollisionUtility::getGeometryFromNode(NiNodeRef pNode, vector<hkGeometry>& geometryMap, vector<hkGeometry>& geometryMapColl, vector<Matrix44>& transformAry) { bhkCollisionObjectRef pCollObject(DynamicCast<bhkCollisionObject>(pNode->GetCollisionObject())); vector<NiAVObjectRef> childList (pNode->GetChildren()); // add own translation to list transformAry.push_back(pNode->GetLocalTransform()); // get geometry from collision object if (pCollObject != NULL) { // search for embedded shape bhkRigidBodyRef pRBody(DynamicCast<bhkRigidBody>(pCollObject->GetBody())); if (pRBody != NULL) { getGeometryFromCollShape(pRBody->GetShape(), geometryMapColl, transformAry); } } // if (pCollObject != NULL) // iterate over children for (vector<NiAVObjectRef>::iterator ppIter = childList.begin(); ppIter != childList.end(); ppIter++) { // NiTriShape if (DynamicCast<NiTriShape>(*ppIter) != NULL) { getGeometryFromTriShape(DynamicCast<NiTriShape>(*ppIter), geometryMap, transformAry); } // NiTriStrips else if (DynamicCast<NiTriStrips>(*ppIter) != NULL) { getGeometryFromTriStrips(DynamicCast<NiTriStrips>(*ppIter), geometryMap, transformAry); } // RootCollisionNode else if (DynamicCast<RootCollisionNode>(*ppIter) != NULL) { getGeometryFromNode(&(*DynamicCast<RootCollisionNode>(*ppIter)), geometryMapColl, geometryMapColl, transformAry); } // NiNode (and derived classes?) else if (DynamicCast<NiNode>(*ppIter) != NULL) { getGeometryFromNode(DynamicCast<NiNode>(*ppIter), geometryMap, geometryMapColl, transformAry); } } // for (vector<NiAVObjectRef>::iterator ppIter = childList.begin(); ppIter != childList.end(); ppIter++) // remove own translation from list transformAry.pop_back(); return geometryMap.size(); }
/*---------------------------------------------------------------------------*/ unsigned int NifConvertUtility::convertShape(string fileNameSrc, string fileNameDst, string fileNameTmpl) { NiNodeRef pRootInput (NULL); NiNodeRef pRootOutput (NULL); NiNodeRef pRootTemplate (NULL); NiTriShapeRef pNiTriShapeTmpl(NULL); vector<NiAVObjectRef> srcChildList; bool fakedRoot (false); // test on existing file names if (fileNameSrc.empty()) return NCU_ERROR_MISSING_FILE_NAME; if (fileNameDst.empty()) return NCU_ERROR_MISSING_FILE_NAME; if (fileNameTmpl.empty()) return NCU_ERROR_MISSING_FILE_NAME; // initialize user messages _userMessages.clear(); logMessage(NCU_MSG_TYPE_INFO, "Source: " + (fileNameSrc.empty() ? "- none -" : fileNameSrc)); logMessage(NCU_MSG_TYPE_INFO, "Template: " + (fileNameTmpl.empty() ? "- none -" : fileNameTmpl)); logMessage(NCU_MSG_TYPE_INFO, "Destination: " + (fileNameDst.empty() ? "- none -" : fileNameDst)); logMessage(NCU_MSG_TYPE_INFO, "Texture: " + (_pathTexture.empty() ? "- none -" : _pathTexture)); // initialize used texture list _usedTextures.clear(); _newTextures.clear(); // read input NIF if ((pRootInput = getRootNodeFromNifFile(fileNameSrc, "source", fakedRoot)) == NULL) { logMessage(NCU_MSG_TYPE_ERROR, "Can't open '" + fileNameSrc + "' as input"); return NCU_ERROR_CANT_OPEN_INPUT; } // get template nif pRootTemplate = DynamicCast<BSFadeNode>(ReadNifTree((const char*) fileNameTmpl.c_str())); if (pRootTemplate == NULL) { logMessage(NCU_MSG_TYPE_ERROR, "Can't open '" + fileNameTmpl + "' as template"); return NCU_ERROR_CANT_OPEN_TEMPLATE; } // get shapes from template // - shape root pNiTriShapeTmpl = DynamicCast<NiTriShape>(pRootTemplate->GetChildren().at(0)); if (pNiTriShapeTmpl == NULL) { logMessage(NCU_MSG_TYPE_INFO, "Template has no NiTriShape."); } // template root is used as root of output pRootOutput = pRootTemplate; // get rid of unwanted subnodes pRootOutput->ClearChildren(); // remove all children pRootOutput->SetCollisionObject(NULL); // unlink collision object // hold extra data and property nodes // copy translation from input node pRootOutput->SetLocalTransform(pRootInput->GetLocalTransform()); // copy name of root node pRootOutput->SetName(pRootInput->GetName()); // get list of children from input node srcChildList = pRootInput->GetChildren(); // unlink children 'cause moved to output pRootInput->ClearChildren(); // iterate over source nodes and convert using template for (vector<NiAVObjectRef>::iterator ppIter = srcChildList.begin(); ppIter != srcChildList.end(); ppIter++) { // NiTriShape if (DynamicCast<NiTriShape>(*ppIter) != NULL) { pRootOutput->AddChild(&(*convertNiTriShape(DynamicCast<NiTriShape>(*ppIter), pNiTriShapeTmpl))); } // RootCollisionNode else if (DynamicCast<RootCollisionNode>(*ppIter) != NULL) { // ignore node } // NiNode (and derived classes?) else if (DynamicCast<NiNode>(*ppIter) != NULL) { pRootOutput->AddChild(&(*convertNiNode(DynamicCast<NiNode>(*ppIter), pNiTriShapeTmpl, pRootOutput))); } } // write missing textures to log - as block for (set<string>::iterator pIter(_newTextures.begin()); pIter != _newTextures.end(); ++pIter) { logMessage(NCU_MSG_TYPE_TEXTURE_MISS, *pIter); } // write modified nif file WriteNifTree((const char*) fileNameDst.c_str(), pRootOutput, NifInfo(VER_20_2_0_7, 12, 83)); return NCU_OK; }
/*---------------------------------------------------------------------------*/ unsigned int NifConvertUtility::convertShape(string fileNameSrc, string fileNameDst, string fileNameTmpl) { cout << "Here3" << endl; NiNodeRef pRootInput (NULL); NiNodeRef pRootOutput (NULL); NiNodeRef pRootTemplate (NULL); NiTriShapeRef pNiTriShapeTmpl(NULL); NiCollisionObjectRef pRootCollObject(NULL); NifInfo nifInfo; vector<NiAVObjectRef> srcChildList; bool fakedRoot (false); cout << "Here4" << endl; // test on existing file names if (fileNameSrc.empty()) return NCU_ERROR_MISSING_FILE_NAME; if (fileNameDst.empty()) return NCU_ERROR_MISSING_FILE_NAME; if (fileNameTmpl.empty()) return NCU_ERROR_MISSING_FILE_NAME; cout << "Here5" << endl; // initialize user messages _userMessages.clear(); logMessage(NCU_MSG_TYPE_INFO, "Source: " + (fileNameSrc.empty() ? "- none -" : fileNameSrc)); logMessage(NCU_MSG_TYPE_INFO, "Template: " + (fileNameTmpl.empty() ? "- none -" : fileNameTmpl)); logMessage(NCU_MSG_TYPE_INFO, "Destination: " + (fileNameDst.empty() ? "- none -" : fileNameDst)); logMessage(NCU_MSG_TYPE_INFO, "Texture: " + (_pathTexture.empty() ? "- none -" : _pathTexture)); cout << "Here6" << endl; // initialize used texture list _usedTextures.clear(); _newTextures.clear(); cout << "Here7" << endl; // read input NIF if ((pRootInput = getRootNodeFromNifFile(fileNameSrc, "source", fakedRoot, &nifInfo)) == NULL) { logMessage(NCU_MSG_TYPE_ERROR, "Can't open '" + fileNameSrc + "' as input"); return NCU_ERROR_CANT_OPEN_INPUT; } cout << "Here8" << endl; // get template nif pRootTemplate = DynamicCast<BSFadeNode>(ReadNifTree((const char*) fileNameTmpl.c_str())); if (pRootTemplate == NULL) { logMessage(NCU_MSG_TYPE_ERROR, "Can't open '" + fileNameTmpl + "' as template"); return NCU_ERROR_CANT_OPEN_TEMPLATE; } cout << "Here9" << endl; // get shapes from template // - shape root pNiTriShapeTmpl = DynamicCast<NiTriShape>(pRootTemplate->GetChildren().at(0)); if (pNiTriShapeTmpl == NULL) { logMessage(NCU_MSG_TYPE_INFO, "Template has no NiTriShape."); } cout << "Here10" << endl; // get data from input node srcChildList = pRootInput->GetChildren(); pRootCollObject = pRootInput->GetCollisionObject(); cout << "Here11" << endl; // template root is used as root of output pRootOutput = pRootTemplate; // move date from input to output pRootInput ->SetCollisionObject(NULL); pRootOutput->SetCollisionObject(pRootCollObject); pRootOutput->SetLocalTransform(pRootInput->GetLocalTransform()); pRootOutput->SetName(pRootInput->GetName()); cout << "Here12" << endl; // get rid of unwanted subnodes pRootOutput->ClearChildren(); pRootInput->ClearChildren(); cout << "Here13" << endl; // move children to output for (auto pIter=srcChildList.begin(), pEnd=srcChildList.end(); pIter != pEnd; ++pIter) { pRootOutput->AddChild(*pIter); } cout << "Here14" << endl; // iterate over source nodes and convert using template root_bsafade = pRootOutput; pRootOutput = convertNiNode(pRootOutput, pNiTriShapeTmpl, pRootOutput); cout << "Here15" << endl; // write missing textures to log - as block for (auto pIter=_newTextures.begin(), pEnd=_newTextures.end(); pIter != pEnd; ++pIter) { logMessage(NCU_MSG_TYPE_TEXTURE_MISS, *pIter); } cout << "Here16" << endl; // set version information stringstream sStream; cout << "Here17" << endl; sStream << nifInfo.version << ';' << nifInfo.userVersion; nifInfo.version = VER_20_2_0_7; nifInfo.userVersion = 12; nifInfo.userVersion2 = 83; nifInfo.creator = "NifConvert"; nifInfo.exportInfo1 = MASTER_PRODUCT_VERSION_STR; nifInfo.exportInfo2 = sStream.str(); cout << "Here18" << endl; // write modified nif file WriteNifTree((const char*) fileNameDst.c_str(), pRootOutput, nifInfo); cout << "Here19" << endl; return NCU_OK; }
void NifImporter::ImportBones(NiNodeRef node, bool recurse) { try { if (uncontrolledDummies) BuildControllerRefList(node, ctrlCount); string name = node->GetName(); vector<NiAVObjectRef> children = node->GetChildren(); vector<NiNodeRef> childNodes = DynamicCast<NiNode>(children); NiAVObject::CollisionType cType = node->GetCollisionMode(); if (children.empty() && name == "Bounding Box") return; // Do all node manipulations here NiNodeRef parent = node->GetParent(); string parentname = (parent ? parent->GetName() : ""); Matrix44 m4 = node->GetWorldTransform(); // Check for Prn strings and change parent if necessary if (supportPrnStrings) { list<NiStringExtraDataRef> strings = DynamicCast<NiStringExtraData>(node->GetExtraData()); for (list<NiStringExtraDataRef>::iterator itr = strings.begin(); itr != strings.end(); ++itr){ if (strmatch((*itr)->GetName(), "Prn")) { parentname = (*itr)->GetData(); if (INode *pn = gi->GetINodeByName(parentname.c_str())){ // Apparently Heads tend to need to be rotated 90 degrees on import for if (!rotate90Degrees.empty() && wildmatch(rotate90Degrees, parentname)) { m4 *= TOMATRIX4(RotateYMatrix(TORAD(90))); } m4 *= TOMATRIX4(pn->GetObjTMAfterWSM(0, NULL)); } } } } float len = node->GetLocalTranslation().Magnitude(); // Remove NonAccum nodes and merge into primary bone if (mergeNonAccum && wildmatch("* NonAccum", name) && parent) { string realname = name.substr(0, name.length() - 9); if (strmatch(realname, parent->GetName())) { Matrix44 tm = parent->GetLocalTransform() * node->GetLocalTransform(); name = realname; len += tm.GetTranslation().Magnitude(); parent = parent->GetParent(); } } PosRotScale prs = prsDefault; Vector3 pos; Matrix33 rot; float scale; m4.Decompose(pos, rot, scale); Matrix3 im = TOMATRIX3(m4); Point3 p = im.GetTrans(); Quat q(im); //q.Normalize(); Vector3 ppos; Point3 zAxis(0,0,0); bool hasChildren = !children.empty(); if (hasChildren) { float len = 0.0f; for (vector<NiAVObjectRef>::iterator itr=children.begin(), end = children.end(); itr != end; ++itr) { len += GetObjectLength(*itr); } len /= float(children.size()); ppos = pos + Vector3(len, 0.0f, 0.0f); // just really need magnitude as rotation will take care of positioning } else if (parent) { ppos = pos + Vector3(len/3.0f, 0.0f, 0.0f); } Point3 pp(ppos.x, ppos.y, ppos.z); Point3 qp = TORAD(TOEULER(im)); INode *bone = NULL; if (!doNotReuseExistingBones) // Games like BC3 reuse the same bone names { bone = FindNode(node); if (bone == NULL) bone = gi->GetINodeByName(name.c_str()); } if (bone) { // Is there a better way of "Affect Pivot Only" behaviors? INode *pinode = bone->GetParentNode(); if (pinode) bone->Detach(0,1); PosRotScaleNode(bone, p, q, scale, prs); if (pinode) pinode->AttachChild(bone, 1); } else { bool isDummy = ( (uncontrolledDummies && !HasControllerRef(ctrlCount, name)) || (!dummyNodeMatches.empty() && wildmatch(dummyNodeMatches, name)) || (convertBillboardsToDummyNodes && node->IsDerivedType(NiBillboardNode::TYPE)) ); if (wildmatch("Camera*", name)) { if (enableCameras) { if (bone = CreateCamera(name)) { PosRotScaleNode(bone, p, q, scale, prs); bone->Hide(node->GetVisibility() ? FALSE : TRUE); } } }else if (isDummy && createNubsForBones) bone = CreateHelper(name, p); else if (bone = CreateBone(name, p, pp, zAxis)) { PosRotScaleNode(bone, p, q, scale, prs); bone->Hide(node->GetVisibility() ? FALSE : TRUE); } if (bone) { if (!parentname.empty()) { if (mergeNonAccum && wildmatch("* NonAccum", parentname)) { parentname = parentname.substr(0, parentname.length() - 9); } if (INode *pn = gi->GetINodeByName(parentname.c_str())) pn->AttachChild(bone, 1); } RegisterNode(node, bone); } } // Import UPB if (bone) ImportUPB(bone, node); // Import Havok Collision Data surrounding node, // unfortunately this causes double import of collision so I'm disabling it for now. if (enableCollision && node->GetParent()) { ImportCollision(node); } if (bone && recurse) { ImportBones(childNodes); } } catch( exception & e ) { e=e; } catch( ... ) { } }