/*---------------------------------------------------------------------------*/ NiTriShapeRef NifConvertUtility::convertNiTri(NiTriShapeRef pDstNode, NiTriShapeRef pTmplNode, NiAlphaPropertyRef pTmplAlphaProp) { BSLightingShaderPropertyRef pTmplLShader(NULL); BSLightingShaderPropertyRef pDstLShader (NULL); NiGeometryDataRef pDstGeo (pDstNode->GetData()); vector<NiPropertyRef> dstPropList (pDstNode->GetProperties()); vector<NiPropertyRef> dstPropArray; list<NiExtraDataRef> dstExtraList(pDstNode->GetExtraData()); short bsPropIdx (0); bool forceAlpha (pTmplAlphaProp != NULL); bool hasAlpha (false); bool tanWasCopied(false); // copy new style properties if (pDstNode->GetBSProperty(0) != NULL) dstPropArray.push_back(pDstNode->GetBSProperty(0)); if (pDstNode->GetBSProperty(1) != NULL) dstPropArray.push_back(pDstNode->GetBSProperty(1)); // look for tangent space data for (auto pIter=dstExtraList.begin(), pEnd=dstExtraList.end(); pIter != pEnd; ++pIter) { if ((DynamicCast<NiBinaryExtraData>(*pIter) != NULL) && (pDstGeo != NULL)) { vector<byte> vecByte(DynamicCast<NiBinaryExtraData>(*pIter)->GetData()); vector<Vector3> vecTan; vector<Vector3> vecBin; float* pStartT((float*) &(vecByte[0])); int numVert(pDstGeo->GetVertexCount() * 3); // extract tangent space for (int i(0); i < numVert; i += 3) { vecTan.push_back(Vector3(pStartT[i], pStartT[i+1], pStartT[i+2])); vecBin.push_back(Vector3(pStartT[numVert+i], pStartT[numVert+i+1], pStartT[numVert+i+2])); } // set tangent space pDstGeo->SetTangents (vecTan); pDstGeo->SetBitangents(vecBin); // enable tangent space pDstGeo->SetTspaceFlag(0x10); tanWasCopied = true; } // if ((DynamicCast<NiBinaryExtraData>(*pIter) != NULL) && (pDstGeo != NULL)) } // for (auto pIter=dstExtraList.begin(), pEnd=dstExtraList.end(); pIter != pEnd; ++pIter) // remove extra data pDstNode->ClearExtraData(); // data node if (pDstGeo != NULL) { // set flags if (pTmplNode->GetData() != NULL) { pDstGeo->SetConsistencyFlags(pTmplNode->GetData()->GetConsistencyFlags()); // nessessary ??? } // update tangent space? if (_updateTangentSpace && !tanWasCopied && (DynamicCast<NiTriShapeData>(pDstGeo) != NULL)) { // update tangent space if (updateTangentSpace(DynamicCast<NiTriShapeData>(pDstGeo))) { // enable tangent space pDstGeo->SetTspaceFlag(0x10); } } // if (_updateTangentSpace) } // if (pDstGeo != NULL) // properties - get them from template for (short index(0); index < 2; ++index) { // BSLightingShaderProperty if (DynamicCast<BSLightingShaderProperty>(pTmplNode->GetBSProperty(index)) != NULL) { pTmplLShader = DynamicCast<BSLightingShaderProperty>(pTmplNode->GetBSProperty(index)); } // NiAlphaProperty else if (DynamicCast<NiAlphaProperty>(pTmplNode->GetBSProperty(index)) != NULL) { pTmplAlphaProp = DynamicCast<NiAlphaProperty>(pTmplNode->GetBSProperty(index)); } } // for (short index(0); index < 2; ++index) // parse properties of destination node //dstPropList = pDstNode->GetProperties(); pDstNode->ClearProperties(); pDstNode->SetBSProperties(Niflib::array<2, NiPropertyRef>()); for (auto ppIter=dstPropList.begin(), pEnd=dstPropList.end(); ppIter != pEnd; ppIter++) { // NiAlphaProperty if (DynamicCast<NiAlphaProperty>(*ppIter) != NULL) { NiAlphaPropertyRef pPropAlpha(DynamicCast<NiAlphaProperty>(*ppIter)); // set new property to node pDstNode->SetBSProperty(bsPropIdx++, &(*pPropAlpha)); // own alpha, reset forced alpha forceAlpha = false; // mark alpha property hasAlpha = true; } // NiTexturingProperty else if (DynamicCast<NiTexturingProperty>(*ppIter) != NULL) { char* pTextPos (NULL); BSShaderTextureSetRef pDstSText(new BSShaderTextureSet()); TexDesc baseTex ((DynamicCast<NiTexturingProperty>(*ppIter))->GetTexture(BASE_MAP)); string texture (baseTex.source->GetTextureFileName()); string::size_type result (string::npos); // clone shader property from template pDstLShader = cloneBSLightingShaderProperty(pTmplLShader); // copy textures from template to copy pDstSText->SetTextures(pTmplLShader->GetTextureSet()->GetTextures()); // separate filename from path result = texture.rfind('\\'); if (result == string::npos) result = texture.find_last_of('/'); if (result != string::npos) texture = texture.substr(result + 1); // build texture name if (_forceDDS) { result = texture.rfind('.'); if (result != string::npos) texture.erase(result); texture += ".dds"; } // build full path texture = _pathTexture + texture; // set new texture map pDstSText->SetTexture(0, texture); logMessage(NCU_MSG_TYPE_TEXTURE, string("Txt-Used: ") + texture); if (!checkFileExists(texture)) { _newTextures.insert(string("Txt-Missed: ") + texture); } // build normal map name result = texture.rfind('.'); if (result == string::npos) { texture += "_n"; } else { string extension(texture.substr(result)); texture.erase(result); texture += "_n" + extension; } // set new normal map pDstSText->SetTexture(1, texture); if (!checkFileExists(texture)) { _newTextures.insert(string("Txt-Missed: ") + texture); } // add texture set to texture property pDstLShader->SetTextureSet(pDstSText); // check for existing vertex colors if ((pDstGeo != NULL) && (pDstGeo->GetColors().size() <= 0) && ((pDstLShader->GetShaderFlags2() & Niflib::SLSF2_VERTEX_COLORS) != 0)) { switch (_vcHandling) { case NCU_VC_REMOVE_FLAG: { pDstLShader->SetShaderFlags2((SkyrimShaderPropertyFlags2) (pDstLShader->GetShaderFlags2() & ~Niflib::SLSF2_VERTEX_COLORS)); break; } case NCU_VC_ADD_DEFAULT: { pDstGeo->SetVertexColors(vector<Color4>(pDstGeo->GetVertexCount(), _vcDefaultColor)); break; } } } // if ((pDstGeo != NULL) && (pDstGeo->GetColors().size() <= 0) && ... // set new property to node pDstNode->SetBSProperty(bsPropIdx++, &(*pDstLShader)); } // NiMaterialProperty else if (DynamicCast<NiMaterialProperty>(*ppIter) != NULL) { // remove property from node pDstNode->RemoveProperty(*ppIter); } } // for (vector<NiPropertyRef>::iterator ppIter = dstPropList.begin(); ppIter != dstPropList.end(); ppIter++) // add forced NiAlphaProperty? if (forceAlpha) { NiAlphaPropertyRef pPropAlpha(new NiAlphaProperty()); // set values from template pPropAlpha->SetFlags (pTmplAlphaProp->GetFlags()); pPropAlpha->SetTestThreshold(pTmplAlphaProp->GetTestThreshold()); // set new property to node pDstNode->SetBSProperty(bsPropIdx++, &(*pPropAlpha)); // mark alpha property hasAlpha = true; } // if (forceAlpha) // add default vertex colors if alpha property and no colors if (hasAlpha && (pDstGeo != NULL) && (pDstGeo->GetColors().size() <= 0)) { pDstGeo->SetVertexColors(vector<Color4>(pDstGeo->GetVertexCount(), _vcDefaultColor)); // force flag in BSLightingShaderProperty if (pDstLShader != NULL) { pDstLShader->SetShaderFlags2((SkyrimShaderPropertyFlags2) (pDstLShader->GetShaderFlags2() | Niflib::SLSF2_VERTEX_COLORS)); } } // add allowed properties to fee slots for (auto pIter=dstPropArray.begin(), pEnd=dstPropArray.end(); (pIter != pEnd) && (bsPropIdx < 2); ++pIter) { // skip old style properties if ((*pIter)->GetType().GetTypeName() == "NiMaterialProperty") continue; // add property to free slot pDstNode->SetBSProperty(bsPropIdx++, *pIter); } // reorder properties - only necessary in case of both are set if (_reorderProperties && (pDstNode->GetBSProperty(0) != NULL) && (pDstNode->GetBSProperty(1) != NULL)) { NiPropertyRef tProp01(pDstNode->GetBSProperty(0)); NiPropertyRef tProp02(pDstNode->GetBSProperty(1)); // make sure BSLightingShaderProperty comes before NiAlphaProperty - seems a 'must be' if ((tProp01->GetType().GetTypeName() == "NiAlphaProperty") && (tProp02->GetType().GetTypeName() == "BSLightingShaderProperty") ) { pDstNode->SetBSProperty(0, tProp02); pDstNode->SetBSProperty(1, tProp01); } } // if (_reorderProperties) 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; }