bool NifImporter::ImportMeshes(NiNodeRef node) { bool ok = true; try { #if 1 vector<NiTriShapeRef> trinodes = DynamicCast<NiTriShape>(node->GetChildren()); for (vector<NiTriShapeRef>::iterator itr = trinodes.begin(), end = trinodes.end(); itr != end; ++itr){ ok |= ImportMesh(*itr); } vector<NiTriStripsRef> tristrips = DynamicCast<NiTriStrips>(node->GetChildren()); for (vector<NiTriStripsRef>::iterator itr = tristrips.begin(), end = tristrips.end(); itr != end; ++itr){ ok |= ImportMesh(*itr); } #else // Only do multiples on object that have same name and use XXX:# notation vector<NiTriBasedGeomRef> trigeom = DynamicCast<NiTriBasedGeom>(node->GetChildren()); ok |= ImportMultipleGeometry(node, trigeom); #endif vector<NiNodeRef> nodes = DynamicCast<NiNode>(node->GetChildren()); for (vector<NiNodeRef>::iterator itr = nodes.begin(), end = nodes.end(); itr != end; ++itr){ ok |= ImportMeshes(*itr); } } catch( exception & e ) { e=e; ok = false; } catch( ... ) { ok = false; } return ok; }
/*---------------------------------------------------------------------------*/ void NifCollisionUtility::cleanTreeCollision(NiNodeRef pNode) { vector<NiAVObjectRef> srcChildList(pNode->GetChildren()); // children of node // remove collision object (new style [>= Oblivion]) pNode->SetCollisionObject(NULL); // iterate over source nodes and remove possible old-style [Morrowind] collision node for (auto ppIter=srcChildList.begin(), pEnd=srcChildList.end(); ppIter != pEnd; ppIter++) { // RootCollisionNode if (DynamicCast<RootCollisionNode>(*ppIter) != NULL) { pNode->RemoveChild(*ppIter); } // NiNode else if (DynamicCast<NiNode>(*ppIter) != NULL) { cleanTreeCollision(DynamicCast<NiNode>(*ppIter)); } // other children else { (*ppIter)->SetCollisionObject(NULL); } } // for (vector<NiAVObjectRef>::iterator ppIter = srcChildList.begin(); .... }
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; }
void Exporter::sortNodes(NiNodeRef node) { node->SortChildren(SortNodeEquivalence()); vector<NiNodeRef> children = DynamicCast<NiNode>(node->GetChildren()); for (vector<NiNodeRef>::iterator itr = children.begin(); itr != children.end(); ++itr) sortNodes(*itr); }
static void BuildNodes(NiNodeRef object, vector<NiNodeRef>& nodes) { if (!object) return; nodes.push_back(object); vector<NiNodeRef> links = DynamicCast<NiNode>(object->GetChildren()); for (vector<NiNodeRef>::iterator itr = links.begin(), end = links.end(); itr != end; ++itr) BuildNodes(*itr, nodes); }
/*---------------------------------------------------------------------------*/ 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(); }
/*---------------------------------------------------------------------------*/ NiNodeRef NifPrepareUtility::parse4Blender(NiNodeRef pNode) { vector<NiAVObjectRef> childList(pNode->GetChildren()); list<NiExtraDataRef> extraList(pNode->GetExtraData()); // parse extra data for BSInvMarker for (auto pIter(extraList.begin()), pEnd(extraList.end()); pIter != pEnd; pIter++) { if (_remBSInvMarker && (DynamicCast<BSInvMarker>(*pIter) != NULL)) { pNode->RemoveExtraData(*pIter); } } // unlink children pNode->ClearChildren(); // iterate over children for (auto pIter(childList.begin()), pEnd(childList.end()); pIter != pEnd; pIter++) { // NiTriShape => remove BSLightingShaderProperty if (DynamicCast<NiTriShape>(*pIter) != NULL) { if (_remBSProperties) { NiTriShapeRef pShape (DynamicCast<NiTriShape>(*pIter)); // remove properties (Bethesda uses max. 2) pShape->SetBSProperty(0, NULL); pShape->SetBSProperty(1, NULL); } // add shape to node pNode->AddChild(*pIter); } // BSInvMarker => remove whole object else if (_remBSInvMarker && (DynamicCast<BSInvMarker>(*pIter) != NULL)) { // skip entry => do not add to final list } // NiNode (and derived classes?) => iterate subnodes else if (DynamicCast<NiNode>(*pIter) != NULL) { pNode->AddChild(&(*parse4Blender(DynamicCast<NiNode>(*pIter)))); } } // for (auto pIter(childList.begin()), pEnd(childList.end()); pIter != pEnd; pIter++) return pNode; }
void Exporter::ApplyAllSkinOffsets( NiAVObjectRef & root ) { NiGeometryRef niGeom = DynamicCast<NiGeometry>(root); if ( niGeom != NULL && niGeom->IsSkin() == true ) { niGeom->ApplySkinOffset(); } NiNodeRef niNode = DynamicCast<NiNode>(root); if ( niNode != NULL ) { //Call this function on all children vector<NiAVObjectRef> children = niNode->GetChildren(); for ( unsigned i = 0; i < children.size(); ++i ) { ApplyAllSkinOffsets( children[i] ); } } }
/*---------------------------------------------------------------------------*/ NiNodeRef NifConvertUtility::convertNiNode(NiNodeRef pSrcNode, NiTriShapeRef pTmplNode, NiNodeRef pRootNode, NiAlphaPropertyRef pTmplAlphaProp) { NiNodeRef pDstNode (pSrcNode); vector<NiAVObjectRef> srcShapeList(pDstNode->GetChildren()); // find NiAlphaProperty and use as template in sub-nodes if (DynamicCast<NiAlphaProperty>(pDstNode->GetPropertyByType(NiAlphaProperty::TYPE)) != NULL) { pTmplAlphaProp = DynamicCast<NiAlphaProperty>(pDstNode->GetPropertyByType(NiAlphaProperty::TYPE)); } // unlink protperties -> not used in new format pDstNode->ClearProperties(); // shift extra data to new version pDstNode->ShiftExtraData(VER_20_2_0_7); // unlink children pDstNode->ClearChildren(); // iterate over source nodes and convert using template for (vector<NiAVObjectRef>::iterator ppIter = srcShapeList.begin(); ppIter != srcShapeList.end(); ppIter++) { // NiTriShape //Type t = (*ppIter)->GetType(); if (DynamicCast<NiTriShape>(*ppIter) != NULL) { pDstNode->AddChild(&(*convertNiTriShape(DynamicCast<NiTriShape>(*ppIter), pTmplNode, pTmplAlphaProp))); } // NiNode (and derived classes?) else if (DynamicCast<NiNode>(*ppIter) != NULL) { pDstNode->AddChild(&(*convertNiNode(DynamicCast<NiNode>(*ppIter), pTmplNode, pRootNode, pTmplAlphaProp))); } } return pDstNode; }
/*---------------------------------------------------------------------------*/ unsigned int NifCollisionUtility::getGeometryFromNifFile(string fileName, vector<hkGeometry>& geometryMap) { NiNodeRef pRootInput (NULL); bhkCollisionObjectRef pCollObject(NULL); vector<NiAVObjectRef> srcChildList; vector<Matrix44> transformAry; vector<hkGeometry> geometryMapColl; vector<hkGeometry> geometryMapShape; bool fakedRoot (false); // read input NIF if ((pRootInput = getRootNodeFromNifFile(fileName, "collSource", fakedRoot, true)) == NULL) { return NCU_ERROR_CANT_OPEN_INPUT; } // get geometry from collision object pCollObject = DynamicCast<bhkCollisionObject>(pRootInput->GetCollisionObject()); if (pCollObject != NULL) { // search for embedded shape bhkRigidBodyRef pRBody(DynamicCast<bhkRigidBody>(pCollObject->GetBody())); if (pRBody != NULL) { getGeometryFromCollShape(pRBody->GetShape(), geometryMapColl, transformAry); } } // if (pCollObject != NULL) // get list of children from input node srcChildList = pRootInput->GetChildren(); // iterate over source nodes and get geometry for (vector<NiAVObjectRef>::iterator ppIter = srcChildList.begin(); ppIter != srcChildList.end(); ppIter++) { // NiTriShape if (DynamicCast<NiTriShape>(*ppIter) != NULL) { getGeometryFromTriShape(DynamicCast<NiTriShape>(*ppIter), geometryMapShape, transformAry); } // NiTriStrips else if (DynamicCast<NiTriStrips>(*ppIter) != NULL) { getGeometryFromTriStrips(DynamicCast<NiTriStrips>(*ppIter), geometryMapShape, 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), geometryMapShape, geometryMapColl, transformAry); } } // which geomertry should be used? if ((_cnHandling == NCU_CN_COLLISION) || (_cnHandling == NCU_CN_FALLBACK)) { geometryMap.swap(geometryMapColl); } else if (_cnHandling == NCU_CN_SHAPES) { geometryMap.swap(geometryMapShape); } if ((_cnHandling == NCU_CN_FALLBACK) && (geometryMap.size() <= 0)) { geometryMap.swap(geometryMapShape); } return geometryMap.size(); }
void NifMeshExporterSkyrim::ExportMesh( MObject dagNode ) { //out << "NifTranslator::ExportMesh {"; ComplexShape cs; MStatus stat; MObject mesh; //Find Mesh child of given transform object MFnDagNode nodeFn(dagNode); cs.SetName(this->translatorUtils->MakeNifName(nodeFn.name())); for (int i = 0; i != nodeFn.childCount(); ++i) { // get a handle to the child if (nodeFn.child(i).hasFn(MFn::kMesh)) { MFnMesh tempFn(nodeFn.child(i)); //No history items if (!tempFn.isIntermediateObject()) { //out << "Found a mesh child." << endl; mesh = nodeFn.child(i); break; } } } MFnMesh visibleMeshFn(mesh, &stat); if (stat != MS::kSuccess) { //out << stat.errorString().asChar() << endl; throw runtime_error("Failed to create visibleMeshFn."); } //out << visibleMeshFn.name().asChar() << ") {" << endl; MFnMesh meshFn; MObject dataObj; MPlugArray inMeshPlugArray; MPlug childPlug; MPlug geomPlug; MPlug inputPlug; // this will hold the returned vertex positions MPointArray vts; //For now always use the visible mesh meshFn.setObject(mesh); //out << "Use the function set to get the points" << endl; // use the function set to get the points stat = meshFn.getPoints(vts); if (stat != MS::kSuccess) { //out << stat.errorString().asChar() << endl; throw runtime_error("Failed to get points."); } //Maya won't store any information about objects with no vertices. Just skip it. if (vts.length() == 0) { MGlobal::displayWarning("An object in this scene has no vertices. Nothing will be exported."); return; } vector<WeightedVertex> nif_vts(vts.length()); for (int i = 0; i != vts.length(); ++i) { nif_vts[i].position.x = float(vts[i].x); nif_vts[i].position.y = float(vts[i].y); nif_vts[i].position.z = float(vts[i].z); } //Set vertex info later since it includes skin weights //cs.SetVertices( nif_vts ); //out << "Use the function set to get the colors" << endl; MColorArray myColors; meshFn.getFaceVertexColors(myColors); //out << "Prepare NIF color vector" << endl; vector<Color4> niColors(myColors.length()); for (unsigned int i = 0; i < myColors.length(); ++i) { niColors[i] = Color4(myColors[i].r, myColors[i].g, myColors[i].b, myColors[i].a); } cs.SetColors(niColors); // this will hold the returned vertex positions MFloatVectorArray nmls; //out << "Use the function set to get the normals" << endl; // use the function set to get the normals stat = meshFn.getNormals(nmls, MSpace::kTransform); if (stat != MS::kSuccess) { //out << stat.errorString().asChar() << endl; throw runtime_error("Failed to get normals"); } //out << "Prepare NIF normal vector" << endl; vector<Vector3> nif_nmls(nmls.length()); for (int i = 0; i != nmls.length(); ++i) { nif_nmls[i].x = float(nmls[i].x); nif_nmls[i].y = float(nmls[i].y); nif_nmls[i].z = float(nmls[i].z); } cs.SetNormals(nif_nmls); //out << "Use the function set to get the UV set names" << endl; MStringArray uvSetNames; MString baseUVSet; MFloatArray myUCoords; MFloatArray myVCoords; bool has_uvs = false; // get the names of the uv sets on the mesh meshFn.getUVSetNames(uvSetNames); vector<TexCoordSet> nif_uvs; //Record assotiation between name and uv set index for later map<string, int> uvSetNums; int set_num = 0; for (unsigned int i = 0; i < uvSetNames.length(); ++i) { if (meshFn.numUVs(uvSetNames[i]) > 0) { TexType tt; string set_name = uvSetNames[i].asChar(); if (set_name == "base" || set_name == "map1") { tt = BASE_MAP; } else if (set_name == "dark") { tt = DARK_MAP; } else if (set_name == "detail") { tt = DETAIL_MAP; } else if (set_name == "gloss") { tt = GLOSS_MAP; } else if (set_name == "glow") { tt = GLOW_MAP; } else if (set_name == "bump") { tt = BUMP_MAP; } else if (set_name == "decal0") { tt = DECAL_0_MAP; } else if (set_name == "decal1") { tt = DECAL_1_MAP; } else { tt = BASE_MAP; } //Record the assotiation uvSetNums[set_name] = set_num; //Get the UVs meshFn.getUVs(myUCoords, myVCoords, &uvSetNames[i]); //Make sure this set actually has some UVs in it. Maya sometimes returns empty UV sets. if (myUCoords.length() == 0) { continue; } //Store the data TexCoordSet tcs; tcs.texType = tt; tcs.texCoords.resize(myUCoords.length()); for (unsigned int j = 0; j < myUCoords.length(); ++j) { tcs.texCoords[j].u = myUCoords[j]; //Flip the V coords tcs.texCoords[j].v = 1.0f - myVCoords[j]; } nif_uvs.push_back(tcs); baseUVSet = uvSetNames[i]; has_uvs = true; set_num++; } } cs.SetTexCoordSets(nif_uvs); // this will hold references to the shaders used on the meshes MObjectArray Shaders; // this is used to hold indices to the materials returned in the object array MIntArray FaceIndices; //out << "Get the connected shaders" << endl; // get the shaders used by the i'th mesh instance // Assume this is not instanced for now // TODO support instancing properly stat = visibleMeshFn.getConnectedShaders(0, Shaders, FaceIndices); if (stat != MS::kSuccess) { //out << stat.errorString().asChar() << endl; throw runtime_error("Failed to get connected shader list."); } vector<ComplexFace> nif_faces; //Add shaders to propGroup array vector< vector<NiPropertyRef> > propGroups; for (unsigned int shader_num = 0; shader_num < Shaders.length(); ++shader_num) { //Maya sometimes lists shaders that are not actually attached to any face. Disregard them. bool shader_is_used = false; for (size_t f = 0; f < FaceIndices.length(); ++f) { if (FaceIndices[f] == shader_num) { shader_is_used = true; break; } } if (shader_is_used == false) { //Shader isn't actually used, so continue to the next one. continue; } //out << "Found attached shader: "; //Attach all properties previously associated with this shader to //this NiTriShape MFnDependencyNode fnDep(Shaders[shader_num]); //Find the shader that this shading group connects to MPlug p = fnDep.findPlug("surfaceShader"); MPlugArray plugs; p.connectedTo(plugs, true, false); for (unsigned int i = 0; i < plugs.length(); ++i) { if (plugs[i].node().hasFn(MFn::kLambert)) { fnDep.setObject(plugs[i].node()); break; } } //out << fnDep.name().asChar() << endl; vector<NiPropertyRef> niProps = this->translatorData->shaders[fnDep.name().asChar()]; propGroups.push_back(niProps); } cs.SetPropGroups(propGroups); //out << "Export vertex and normal data" << endl; // attach an iterator to the mesh MItMeshPolygon itPoly(mesh, &stat); if (stat != MS::kSuccess) { throw runtime_error("Failed to create polygon iterator."); } // Create a list of faces with vertex IDs, and duplicate normals so they have the same ID for (; !itPoly.isDone(); itPoly.next()) { int poly_vert_count = itPoly.polygonVertexCount(&stat); if (stat != MS::kSuccess) { throw runtime_error("Failed to get vertex count."); } //Ignore polygons with less than 3 vertices if (poly_vert_count < 3) { continue; } ComplexFace cf; //Assume all faces use material 0 for now cf.propGroupIndex = 0; for (int i = 0; i < poly_vert_count; ++i) { ComplexPoint cp; cp.vertexIndex = itPoly.vertexIndex(i); cp.normalIndex = itPoly.normalIndex(i); if (niColors.size() > 0) { int color_index; stat = meshFn.getFaceVertexColorIndex(itPoly.index(), i, color_index); if (stat != MS::kSuccess) { //out << stat.errorString().asChar() << endl; throw runtime_error("Failed to get vertex color."); } cp.colorIndex = color_index; } //Get the UV set names used by this particular vertex MStringArray vertUvSetNames; itPoly.getUVSetNames(vertUvSetNames); for (unsigned int j = 0; j < vertUvSetNames.length(); ++j) { TexCoordIndex tci; tci.texCoordSetIndex = uvSetNums[vertUvSetNames[j].asChar()]; int uv_index; itPoly.getUVIndex(i, uv_index, &vertUvSetNames[j]); tci.texCoordIndex = uv_index; cp.texCoordIndices.push_back(tci); } cf.points.push_back(cp); } nif_faces.push_back(cf); } //Set shader/face association if (nif_faces.size() != FaceIndices.length()) { throw runtime_error("Num faces found do not match num faces reported."); } for (unsigned int face_index = 0; face_index < nif_faces.size(); ++face_index) { nif_faces[face_index].propGroupIndex = FaceIndices[face_index]; } cs.SetFaces(nif_faces); //--Skin Processing--// //Look up any skin clusters if (this->translatorData->meshClusters.find(visibleMeshFn.fullPathName().asChar()) != this->translatorData->meshClusters.end()) { const vector<MObject> & clusters = this->translatorData->meshClusters[visibleMeshFn.fullPathName().asChar()]; if (clusters.size() > 1) { throw runtime_error("Objects with multiple skin clusters affecting them are not currently supported. Try deleting the history and re-binding them."); } vector<MObject>::const_iterator cluster = clusters.begin(); if (cluster->isNull() != true) { MFnSkinCluster clusterFn(*cluster); //out << "Processing skin..." << endl; //Get path to visible mesh MDagPath meshPath; visibleMeshFn.getPath(meshPath); //out << "Getting a list of all verticies in this mesh" << endl; //Get a list of all vertices in this mesh MFnSingleIndexedComponent compFn; MObject vertices = compFn.create(MFn::kMeshVertComponent); MItGeometry gIt(meshPath); MIntArray vertex_indices(gIt.count()); for (int vert_index = 0; vert_index < gIt.count(); ++vert_index) { vertex_indices[vert_index] = vert_index; } compFn.addElements(vertex_indices); //out << "Getting Influences" << endl; //Get influences MDagPathArray myBones; clusterFn.influenceObjects(myBones, &stat); //out << "Creating a list of NiNodeRefs of influences." << endl; //Create list of NiNodeRefs of influences vector<NiNodeRef> niBones(myBones.length()); for (unsigned int bone_index = 0; bone_index < niBones.size(); ++bone_index) { const char* boneName = myBones[bone_index].fullPathName().asChar(); if (this->translatorData->nodes.find(myBones[bone_index].fullPathName().asChar()) == this->translatorData->nodes.end()) { //There is a problem; one of the joints was not exported. Abort. throw runtime_error("One of the joints necessary to export a bound skin was not exported."); } niBones[bone_index] = this->translatorData->nodes[myBones[bone_index].fullPathName().asChar()]; } //out << "Getting weights from Maya" << endl; //Get weights from Maya MDoubleArray myWeights; unsigned int bone_count = myBones.length(); stat = clusterFn.getWeights(meshPath, vertices, myWeights, bone_count); if (stat != MS::kSuccess) { //out << stat.errorString().asChar() << endl; throw runtime_error("Failed to get vertex weights."); } //out << "Setting skin influence list in ComplexShape" << endl; //Set skin information in ComplexShape cs.SetSkinInfluences(niBones); //out << "Adding weights to ComplexShape vertices" << endl; //out << "Number of weights: " << myWeights.length() << endl; //out << "Number of bones: " << myBones.length() << endl; //out << "Number of Maya vertices: " << gIt.count() << endl; //out << "Number of NIF vertices: " << int(nif_vts.size()) << endl; unsigned int weight_index = 0; SkinInfluence sk; for (unsigned int vert_index = 0; vert_index < nif_vts.size(); ++vert_index) { for (unsigned int bone_index = 0; bone_index < myBones.length(); ++bone_index) { //out << "vert_index: " << vert_index << " bone_index: " << bone_index << " weight_index: " << weight_index << endl; // Only bother with weights that are significant if (myWeights[weight_index] > 0.0f) { sk.influenceIndex = bone_index; sk.weight = float(myWeights[weight_index]); nif_vts[vert_index].weights.push_back(sk); } ++weight_index; } } } MPlugArray connected_dismember_plugs; MObjectArray dismember_nodes; meshFn.findPlug("message").connectedTo(connected_dismember_plugs, false, true); bool has_valid_dismemember_partitions = true; int faces_count = cs.GetFaces().size(); int current_face_index; vector<BodyPartList> body_parts_list; vector<uint> dismember_faces(faces_count, 0); for (int x = 0; x < connected_dismember_plugs.length(); x++) { MFnDependencyNode dependency_node(connected_dismember_plugs[x].node()); if (dependency_node.typeName() == "nifDismemberPartition") { dismember_nodes.append(dependency_node.object()); } } if (dismember_nodes.length() == 0) { has_valid_dismemember_partitions = false; } else { int blind_data_id; int blind_data_value; MStatus status; MPlug target_faces_plug; MItMeshPolygon it_polygons(meshFn.object()); MString mel_command; MStringArray current_body_parts_flags; MFnDependencyNode current_dismember_node; MFnDependencyNode current_blind_data_node; //Naive sort here, there is no reason and is extremely undesirable and not recommended to have more //than 10-20 dismember partitions out of many reasons, so it's okay here //as it makes the code easier to understand vector<int> dismember_nodes_id(dismember_nodes.length(), -1); for (int x = 0; x < dismember_nodes.length(); x++) { current_dismember_node.setObject(dismember_nodes[x]); connected_dismember_plugs.clear(); current_dismember_node.findPlug("targetFaces").connectedTo(connected_dismember_plugs, true, false); if (connected_dismember_plugs.length() == 0) { has_valid_dismemember_partitions = false; break; } current_blind_data_node.setObject(connected_dismember_plugs[0].node()); dismember_nodes_id[x] = current_blind_data_node.findPlug("typeId").asInt(); } for (int x = 0; x < dismember_nodes.length() - 1; x++) { for (int y = x + 1; y < dismember_nodes.length(); y++) { if (dismember_nodes_id[x] > dismember_nodes_id[y]) { MObject aux = dismember_nodes[x]; blind_data_id = dismember_nodes_id[x]; dismember_nodes[x] = dismember_nodes[y]; dismember_nodes_id[x] = dismember_nodes_id[y]; dismember_nodes[y] = aux; dismember_nodes_id[y] = blind_data_id; } } } for (int x = 0; x < dismember_nodes.length(); x++) { current_dismember_node.setObject(dismember_nodes[x]); target_faces_plug = current_dismember_node.findPlug("targetFaces"); connected_dismember_plugs.clear(); target_faces_plug.connectedTo(connected_dismember_plugs, true, false); if (connected_dismember_plugs.length() > 0) { current_blind_data_node.setObject(connected_dismember_plugs[0].node()); current_face_index = 0; blind_data_id = current_blind_data_node.findPlug("typeId").asInt(); for (it_polygons.reset(); !it_polygons.isDone(); it_polygons.next()) { if (it_polygons.polygonVertexCount() >= 3) { status = meshFn.getIntBlindData(it_polygons.index(), MFn::Type::kMeshPolygonComponent, blind_data_id, "dismemberValue", blind_data_value); if (status == MStatus::kSuccess && blind_data_value == 1 && meshFn.hasBlindDataComponentId(it_polygons.index(), MFn::Type::kMeshPolygonComponent, blind_data_id)) { dismember_faces[current_face_index] = x; } current_face_index++; } } } else { has_valid_dismemember_partitions = false; break; } mel_command = "getAttr "; mel_command += current_dismember_node.name(); mel_command += ".bodyPartsFlags"; status = MGlobal::executeCommand(mel_command, current_body_parts_flags); BSDismemberBodyPartType body_part_type = NifDismemberPartition::stringArrayToBodyPartType(current_body_parts_flags); current_body_parts_flags.clear(); mel_command = "getAttr "; mel_command += current_dismember_node.name(); mel_command += ".partsFlags"; status = MGlobal::executeCommand(mel_command, current_body_parts_flags); BSPartFlag part_type = NifDismemberPartition::stringArrayToPart(current_body_parts_flags); current_body_parts_flags.clear(); BodyPartList body_part; body_part.bodyPart = body_part_type; body_part.partFlag = part_type; body_parts_list.push_back(body_part); } } if (has_valid_dismemember_partitions == false) { MGlobal::displayWarning("No proper dismember partitions, generating default ones for " + meshFn.name()); for (int x = 0; x < dismember_faces.size(); x++) { dismember_faces[x] = 0; } BodyPartList body_part; body_part.bodyPart = (BSDismemberBodyPartType)0; body_part.partFlag = (BSPartFlag)(PF_EDITOR_VISIBLE | PF_START_NET_BONESET); body_parts_list.clear(); body_parts_list.push_back(body_part); } cs.SetDismemberPartitionsBodyParts(body_parts_list); cs.SetDismemberPartitionsFaces(dismember_faces); } //out << "Setting vertex info" << endl; //Set vertex info now that any skins have been processed cs.SetVertices(nif_vts); //ComplexShape is now complete, so split it //Get parent NiNodeRef parNode = this->translatorUtils->GetDAGParent(dagNode); Matrix44 transform = Matrix44::IDENTITY; vector<NiNodeRef> influences = cs.GetSkinInfluences(); if (influences.size() > 0) { //This is a skin, so we use the common ancestor of all influences //as the parent vector<NiAVObjectRef> objects; for (size_t i = 0; i < influences.size(); ++i) { objects.push_back(StaticCast<NiAVObject>(influences[i])); } //Get world transform of existing parent Matrix44 oldParWorld = parNode->GetWorldTransform(); //Set new parent node parNode = FindCommonAncestor(objects); transform = oldParWorld * parNode->GetWorldTransform().Inverse(); } //Get transform using temporary NiAVObject NiAVObjectRef tempAV = new NiAVObject; this->nodeExporter->ExportAV(tempAV, dagNode); NiAVObjectRef avObj; if (this->translatorOptions->exportTangentSpace == "falloutskyrimtangentspace") { //out << "Split ComplexShape from " << meshFn.name().asChar() << endl; avObj = cs.Split(parNode, tempAV->GetLocalTransform() * transform, this->translatorOptions->exportBonesPerSkinPartition, this->translatorOptions->exportAsTriStrips, true, this->translatorOptions->exportMinimumVertexWeight, 16); } else { avObj = cs.Split(parNode, tempAV->GetLocalTransform() * transform, this->translatorOptions->exportBonesPerSkinPartition, this->translatorOptions->exportAsTriStrips, false, this->translatorOptions->exportMinimumVertexWeight); } //out << "Get the NiAVObject portion of the root of the split" <<endl; //Get the NiAVObject portion of the root of the split avObj->SetName(tempAV->GetName()); avObj->SetVisibility(tempAV->GetVisibility()); avObj->SetFlags(tempAV->GetFlags()); //If polygon mesh is hidden, hide tri_shape MPlug vis = visibleMeshFn.findPlug(MString("visibility")); bool visibility; vis.getValue(visibility); NiNodeRef splitRoot = DynamicCast<NiNode>(avObj); if (splitRoot != NULL) { //Root is a NiNode with NiTriBasedGeom children. vector<NiAVObjectRef> children = splitRoot->GetChildren(); for (unsigned c = 0; c < children.size(); ++c) { //Set the default collision propogation flag to "use triangles" children[c]->SetFlags(2); // Make the mesh invisible if necessary if (visibility == false) { children[c]->SetVisibility(false); } } } else { //Root must be a NiTriBasedGeom. Make it invisible if necessary if (visibility == false) { avObj->SetVisibility(false); } } }
/*---------------------------------------------------------------------------*/ 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; }
NiNodeRef NifConvertUtility::convertNiNode(NiNodeRef pSrcNode, NiTriShapeRef pTmplNode, NiNodeRef pRootNode, NiAlphaPropertyRef pTmplAlphaProp) { NiNodeRef pDstNode (pSrcNode); //pDstNode->SetName(pDstNode->GetName().replace( string node_name_in = pDstNode->GetName(); string node_name_out = ""; for (int i = 0; i < node_name_in.length(); i++) { if (node_name_in[i] != '.' && node_name_in[i] != '_' && node_name_in[i] != ' ') { node_name_out = node_name_out + node_name_in[i]; } } pDstNode->SetName(node_name_out); node_name_in = node_name_out; if (node_name_in.compare("AttachLight") == 0) { Vector3 tr = pDstNode->GetLocalTranslation(); tr.z += 10.0f; pDstNode->SetLocalTranslation(tr); } if (node_name_in.compare("ShadowBox") == 0) { cout << "Removing ShadowBox" << endl; pDstNode->ClearChildren(); } if (toLower(node_name_in).find("fireemit") != -1) { NiExtraDataRef ed = root_bsafade->GetExtraData().front(); NiIntegerExtraDataRef iref = DynamicCast<NiIntegerExtraData>(ed); iref->SetData(147); cout << "Adding TorchFlame Addon" << endl; BSValueNodeRef candle_flame = new BSValueNode(); candle_flame->SetName("AddOnNode"); candle_flame->value = 46; pDstNode->AddChild(DynamicCast<NiAVObject>(candle_flame)); } else if (node_name_in.find("CandleFlame") != -1) { NiExtraDataRef ed = root_bsafade->GetExtraData().front(); NiIntegerExtraDataRef iref = DynamicCast<NiIntegerExtraData>(ed); iref->SetData(147); cout << "Adding CandleFlame Addon" << endl; BSValueNodeRef candle_flame = new BSValueNode(); candle_flame->SetName("AddOnNode"); candle_flame->value = 49; pDstNode->AddChild(DynamicCast<NiAVObject>(candle_flame)); } vector<NiAVObjectRef> srcShapeList(pDstNode->GetChildren()); //if (!pDstNode->GetType().IsSameType(NiNode::TYPE) && !pDstNode->GetType().IsSameType(BSFadeNode::TYPE) && !pDstNode->GetType().IsSameType(NiTriShape::TYPE) && !pDstNode->GetType().IsSameType(NiTriStrips::TYPE)) { } // find NiAlphaProperty and use as template in sub-nodes if (DynamicCast<NiAlphaProperty>(pDstNode->GetPropertyByType(NiAlphaProperty::TYPE)) != NULL) { pTmplAlphaProp = DynamicCast<NiAlphaProperty>(pDstNode->GetPropertyByType(NiAlphaProperty::TYPE)); } // unlink protperties -> not used in new format pDstNode->ClearProperties(); // shift extra data to new version pDstNode->ShiftExtraData(VER_20_2_0_7); // unlink children pDstNode->ClearChildren(); pDstNode->ClearEffects(); pDstNode->ClearControllers(); if (!pDstNode->GetType().IsSameType(BSFadeNode::TYPE)) { pDstNode->ClearExtraData(); } // iterate over source nodes and convert using template for (auto ppIter=srcShapeList.begin(), pEnd=srcShapeList.end(); ppIter != pEnd; ppIter++) { //DynamicCast<NiTriShape>(*ppIter) == NULL && DynamicCast<NiTriStrips>(*ppIter) == NULL ** DynamicCast<NiTriStrips>(*ppIter) != NULL // NiTriShape if (DynamicCast<NiTriShape>(*ppIter) != NULL) { pDstNode->AddChild(&(*convertNiTriShape(DynamicCast<NiTriShape>(*ppIter), pTmplNode, pTmplAlphaProp))); } // NiTriStrips else if (DynamicCast<NiTriStrips>(*ppIter) != NULL) { pDstNode->AddChild(&(*convertNiTriStrips(DynamicCast<NiTriStrips>(*ppIter), pTmplNode, pTmplAlphaProp))); } // RootCollisionNode else if ((DynamicCast<RootCollisionNode>(*ppIter) != NULL) && _cleanTreeCollision) { // ignore node } // NiNode (and derived classes?) else if (DynamicCast<NiNode>(*ppIter) != NULL) { NiNode* node_hashmi = DynamicCast<NiNode>(*ppIter); if (node_hashmi->GetType().IsSameType(NiNode::TYPE) || node_hashmi->GetType().IsSameType(BSFadeNode::TYPE) || node_hashmi->GetType().IsSameType(BSValueNode::TYPE)) { pDstNode->AddChild(&(*convertNiNode(DynamicCast<NiNode>(*ppIter), pTmplNode, pRootNode, pTmplAlphaProp))); } } } // remove collision object (newer version) if (_cleanTreeCollision) { pDstNode->SetCollisionObject(NULL); } else if (DynamicCast<bhkCollisionObject>(pDstNode->GetCollisionObject()) != NULL) { bhkRigidBodyRef pBody(DynamicCast<bhkRigidBody>((DynamicCast<bhkCollisionObject>(pDstNode->GetCollisionObject()))->GetBody())); if (pBody != NULL) { parseCollisionTree(pBody->GetShape()); } } return pDstNode; }
/*---------------------------------------------------------------------------*/ NiNodeRef NifPrepareUtility::parse4Armor(NiNodeRef pNode, BSLightingShaderPropertyRef pShaderTmpl) { vector<NiAVObjectRef> childList(pNode->GetChildren()); // unlink children pNode->ClearChildren(); // iterate over children for (auto pIter(childList.begin()), pEnd(childList.end()); pIter != pEnd; pIter++) { // NiTriShape => remodel BSLightingShaderProperty if (DynamicCast<NiTriShape>(*pIter) != NULL) { NiTriShapeRef pShape (DynamicCast<NiTriShape>(*pIter)); BSDismemberSkinInstanceRef pSkin (DynamicCast<BSDismemberSkinInstance>(pShape->GetSkinInstance())); vector<NiPropertyRef> propList(pShape->GetProperties()); // part of skin data? => modify skin code if (pSkin != NULL) { vector<BodyPartList> bPartList(pSkin->GetPartitions()); for (auto pIter(bPartList.begin()), pEnd(bPartList.end()); pIter != pEnd; pIter++) { if (_bodyPartMap.count(pIter->bodyPart) > 0) { pIter->bodyPart = (BSDismemberBodyPartType) _bodyPartMap[pIter->bodyPart]; } } // for (auto pIter(bPartList.begin()), pEnd(bPartList.end()); pIter != pEnd; pIter++) // set modified parts pSkin->SetPartitions(bPartList); } // if (pSkin != NULL) // remove all properties pShape->ClearProperties(); // create new BSLightingShaderProperty if template given if (pShaderTmpl != NULL) { // check properties for (auto pIterProp(propList.begin()), pEnd(propList.end()); pIterProp != pEnd; pIterProp++) { // convert BSShaderPPLightingProperty to BSLightingShaderProperty if (DynamicCast<BSShaderPPLightingProperty>(*pIterProp) != NULL) { BSShaderPPLightingProperty* pPProp(DynamicCast<BSShaderPPLightingProperty>(*pIterProp)); BSLightingShaderProperty* pLProp(new BSLightingShaderProperty()); // move texture set pLProp->SetTextureSet(pPProp->GetTextureSet()); pPProp->SetTextureSet(NULL); pLProp->SetShaderFlags1 (pShaderTmpl->GetShaderFlags1()); pLProp->SetShaderFlags2 (pShaderTmpl->GetShaderFlags2()); pLProp->SetEmissiveMultiple (pShaderTmpl->GetEmissiveMultiple()); pLProp->SetEmissiveColor (pShaderTmpl->GetEmissiveColor()); pLProp->SetLightingEffect1 (pShaderTmpl->GetLightingEffect1()); pLProp->SetLightingEffect2 (pShaderTmpl->GetLightingEffect2()); pLProp->SetEnvironmentMapScale(pShaderTmpl->GetEnvironmentMapScale()); pLProp->SetSkyrimShaderType (pShaderTmpl->GetSkyrimShaderType()); pLProp->SetSpecularColor (pShaderTmpl->GetSpecularColor()); pLProp->SetSpecularStrength (pShaderTmpl->GetSpecularStrength()); pLProp->SetTextureClampMode (pShaderTmpl->GetTextureClampMode()); pLProp->SetUnknownFloat2 (pShaderTmpl->GetUnknownFloat2()); pLProp->SetGlossiness (pShaderTmpl->GetGlossiness()); // add property to shape pShape->SetBSProperty(0, pLProp); } } // for (auto pIterProp(propList.begin()), pEnd(propList.end()); pIterProp != pEnd; pIterProp++) } // if (pShaderTmpl != NULL) // add shape to node pNode->AddChild(*pIter); } // NiNode (and derived classes?) => iterate subnodes else if (DynamicCast<NiNode>(*pIter) != NULL) { pNode->AddChild(&(*parse4Armor(DynamicCast<NiNode>(*pIter), pShaderTmpl))); } } // for (auto pIter(childList.begin()), pEnd(childList.end()); pIter != pEnd; pIter++) return pNode; }
/*---------------------------------------------------------------------------*/ bool NifCollisionUtility::parseTreeCollision(NiNodeRef pNode, string fileNameCollTmpl, vector<hkGeometry>& geometryMapColl) { vector<NiAVObjectRef> srcChildList (pNode->GetChildren()); // get list of children from input node bool haveCollision(false); // check for own collision object if (DynamicCast<bhkCollisionObject>(pNode->GetCollisionObject()) != NULL) { bhkCollisionObjectRef pCollObj(DynamicCast<bhkCollisionObject>(pNode->GetCollisionObject())); bhkRigidBodyRef pRBody (DynamicCast<bhkRigidBody> (pCollObj->GetBody())); // check on valid body if (pRBody != NULL) { array<7, unsigned short> unknown7(pRBody->GetUnknown7Shorts()); // force SKYRIM values unknown7[3] = 0; unknown7[4] = 0; unknown7[5] = 1; unknown7[6] = 65535; pRBody->SetUnknown7Shorts(unknown7); pRBody->SetTranslation(pRBody->GetTranslation() * 0.1f); pRBody->SetShape(parseCollisionShape(fileNameCollTmpl, pRBody->GetShape(), pRBody)); } // if (pRBody != NULL) haveCollision |= true; } // if (DynamicCast<bhkCollisionObject>(pNode->GetCollisionObject()) != NULL) // iterate over source nodes and get geometry for (vector<NiAVObjectRef>::iterator ppIter = srcChildList.begin(); ppIter != srcChildList.end(); ppIter++) { // RootCollisionNode if (DynamicCast<RootCollisionNode>(*ppIter) != NULL) { NiNodeRef pRootTemplate(DynamicCast<BSFadeNode>(ReadNifTree((const char*) fileNameCollTmpl.c_str()))); vector<hkGeometry> geometryMapCollLocal; vector<Matrix44> transformAryLocal; // get template if (pRootTemplate != NULL) { bhkCollisionObjectRef pCollNodeTmpl(DynamicCast<bhkCollisionObject>(pRootTemplate->GetCollisionObject())); if (pCollNodeTmpl != NULL) { // get collision data from sub-nodes getGeometryFromNode(&(*DynamicCast<RootCollisionNode>(*ppIter)), geometryMapCollLocal, geometryMapCollLocal, transformAryLocal); // replace collision object pNode->SetCollisionObject(createCollNode(geometryMapCollLocal, pCollNodeTmpl, pNode)); pNode->RemoveChild(*ppIter); haveCollision |= true; } // if (pCollNodeTmpl == NULL) } // if (pRootTemplate != NULL) } // NiNode (and derived classes?) else if (DynamicCast<NiNode>(*ppIter) != NULL) { haveCollision |= parseTreeCollision(DynamicCast<NiNode>(*ppIter), fileNameCollTmpl, geometryMapColl); } } // for (vector<NiAVObjectRef>::iterator ppIter = srcChildList.begin(); ppIter != srcChildList.end(); ppIter++) return haveCollision; }
void NifImporter::AlignBiped(IBipMaster* master, NiNodeRef node) { #ifdef USE_BIPED NiNodeRef parent = node->GetParent(); string name = node->GetName(); vector<NiAVObjectRef> children = node->GetChildren(); vector<NiNodeRef> childNodes = DynamicCast<NiNode>(children); TSTR s1 = FormatText("Processing %s:", name.c_str()); TSTR s2 = FormatText("Processing %s:", name.c_str()); INode *bone = GetNode(node); if (bone != NULL) { if (uncontrolledDummies) BuildControllerRefList(node, ctrlCount); Matrix44 m4 = node->GetWorldTransform(); Vector3 pos; Matrix33 rot; float scale; m4.Decompose(pos, rot, scale); Matrix3 m = TOMATRIX3(m4); Point3 p = m.GetTrans(); Quat q(m); s1 += FormatText(" ( %s)", PrintMatrix3(m).data()); if (strmatch(name, master->GetRootName())) { // Align COM //PosRotScaleNode(bone, p, q, 1.0f, prsPos); PosRotScaleBiped(master, bone, p, q, 1.0f, prsPos); } else if (INode *pnode = bone->GetParentNode()) { // Reparent if necessary if (!strmatch(parent->GetName(), pnode->GetName())) { if (pnode = FindNode(parent)) { bone->Detach(0); pnode->AttachChild(bone); } } // Hack to scale the object until it fits for (int i=0; i<10; ++i) { float s = CalcScale(bone, node, childNodes); if (fabs(s-1.0f) < (FLT_EPSILON*100.0f)) break; s1 += FormatText(" (%g)", s); master->SetBipedScale(TRUE, ScaleValue(Point3(s,s,s)), 0, bone); } PosRotScale prs = prsDefault; PosRotScaleBiped(master, bone, p, q, scale, prs); // Rotation with Clavicle is useless in Figure Mode using the standard interface // I was tring unsuccessfully to correct for it //if (wildcmpi("Bip?? ? Clavicle", name.c_str())) { // AngAxis a1 = CalcTransform(bone, node, childNodes); // Matrix3 tm1 = GenerateRotMatrix(a1); // Quat nq = TransformQuat(tm1, q); // PosRotScaleNode(bone, p, nq, scale, prsRot); //} } s2 += FormatText(" ( %s)", PrintMatrix3(bone->GetNodeTM(0)).data()); } else { ImportBones(node, false); } for (char *p = s1; *p != 0; ++p) if (isspace(*p)) *p = ' '; for (char *p = s2; *p != 0; ++p) if (isspace(*p)) *p = ' '; OutputDebugString(s1 + "\n"); OutputDebugString(s2 + "\n"); for (vector<NiNodeRef>::iterator itr = childNodes.begin(), end = childNodes.end(); itr != end; ++itr){ AlignBiped(master, *itr); } #endif }
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( ... ) { } }
unsigned long CMesh::Load_Mesh(unsigned long want_formID) { unsigned long index; CStat_Record *dastat; MeshData *dameshdata; char tmppath[MAX_PATH]; dastat=pTreeManager->GetStat(want_formID); if(dastat==NULL) return 1; formID=want_formID; strcpy_s(tmppath,MAX_PATH,"data\\meshes\\"); strcat_s(tmppath,MAX_PATH,dastat->Get_Filename()); //output_text_char(L"Filename: ",tmppath); NiObjectRef root=ReadNifTree(tmppath); NiNodeRef node = DynamicCast<NiNode>(root); if(node==NULL) return 2; vector<NiAVObjectRef> refs=node->GetChildren(); for(index=0;index<refs.size();index++) { if(refs[index]->IsSameType(NiTriStrips::TYPE)) { NiTriStripsRef datristrip=DynamicCast<NiTriStrips>(refs[index]); //Add a tri strip buffer to the mesh dameshdata=AddTriStrips(datristrip); if(dameshdata==NULL) { output_text(L"Error AddTriStrips\r\n"); return 3; } Vector3 translation=datristrip->GetLocalTranslation(); dameshdata->local_translation[0]=translation.x; dameshdata->local_translation[1]=translation.y; dameshdata->local_translation[2]=translation.z; dameshdata->tristrip=1; } else { if(refs[index]->IsSameType(NiTriShape::TYPE)) { NiTriShapeRef datrishape=DynamicCast<NiTriShape>(refs[index]); //Add a tri shape to the mesh dameshdata=AddTriShape(datrishape); if(dameshdata==NULL) { output_text(L"Error AddTriShape\r\n"); return 3; } Vector3 translation=datrishape->GetLocalTranslation(); dameshdata->local_translation[0]=translation.x; dameshdata->local_translation[1]=translation.y; dameshdata->local_translation[2]=translation.z; dameshdata->tristrip=0; } } } //Load the collision data /*NiCollisionObjectRef dacol=node->GetCollisionObject(); if(dacol->IsSameType(bhkCollisionObject::TYPE)) { bhkCollisionObjectRef bhkCol=DynamicCast<bhkCollisionObject>(dacol); NiObjectRef daobj=bhkCol->GetBody(); if(daobj->IsSameType(bhkRigidBody::TYPE)) { bhkRigidBody } }*/ return 0; }
bool NifImporter::DoImport() { bool ok = true; if (!suppressPrompts) { if (!ShowDialog()) return true; ApplyAppSettings(); SaveIniSettings(); } vector<string> importedBones; if (!isBiped && importSkeleton && importBones) { if (importSkeleton && !skeleton.empty()) { try { NifImporter skelImport(skeleton.c_str(), i, gi, suppressPrompts); if (skelImport.isValid()) { // Enable Skeleton specific items skelImport.isBiped = true; skelImport.importBones = true; // Disable undesirable skeleton items skelImport.enableCollision = false; skelImport.enableAnimations = false; skelImport.suppressPrompts = true; skelImport.DoImport(); if (!skelImport.useBiped && removeUnusedImportedBones) importedBones = GetNamesOfNodes(skelImport.nodes); } } catch (RuntimeError &error) { // ignore import errors and continue } } } else if (hasSkeleton && useBiped && importBones) { ImportBipeds(nodes); } if (isValid()) { if (root->IsDerivedType(NiNode::TYPE)) { NiNodeRef rootNode = root; if (importBones) { if (ignoreRootNode || strmatch(rootNode->GetName(), "Scene Root")) { RegisterNode(root, gi->GetRootNode()); ImportBones(DynamicCast<NiNode>(rootNode->GetChildren())); } else { ImportBones(rootNode); } } if (enableLights){ ok = ImportLights(rootNode); } ok = ImportMeshes(rootNode); // Import Havok Collision Data surrounding node if (enableCollision) { ImportCollision(rootNode); } if (importSkeleton && removeUnusedImportedBones){ vector<string> importedNodes = GetNamesOfNodes(nodes); sort(importedBones.begin(), importedBones.end()); sort(importedNodes.begin(), importedNodes.end()); vector<string> results; results.resize(importedBones.size()); vector<string>::iterator end = set_difference ( importedBones.begin(), importedBones.end(), importedNodes.begin(), importedNodes.end(), results.begin()); for (vector<string>::iterator itr = results.begin(); itr != end; ++itr){ if (INode *node = gi->GetINodeByName((*itr).c_str())){ gi->DeleteNode(node, FALSE); } } } } else if (root->IsDerivedType(NiTriShape::TYPE)) { ok |= ImportMesh(NiTriShapeRef(root)); } else if (root->IsDerivedType(NiTriStrips::TYPE)) { ok |= ImportMesh(NiTriStripsRef(root)); } } ClearAnimation(); ImportAnimation(); return true; }