public override AquaObject Clone() { NGSAquaObject aqp = new NGSAquaObject(); aqp.afp = afp; aqp.objc = objc; aqp.vsetList = new List <VSET>(vsetList); aqp.vtxeList = vtxeList.ConvertAll(vtxe => vtxe.Clone()).ToList(); aqp.vtxlList = vtxlList.ConvertAll(vtxl => vtxl.Clone()).ToList(); aqp.psetList = new List <PSET>(psetList); aqp.meshList = new List <MESH>(meshList); aqp.mateList = new List <MATE>(mateList); aqp.rendList = new List <REND>(rendList); aqp.shadList = shadList.ConvertAll(shad => shad.Clone()).ToList(); aqp.tstaList = new List <TSTA>(tstaList); aqp.tsetList = tsetList.ConvertAll(tset => tset.Clone()).ToList(); aqp.texfList = new List <TEXF>(texfList); if (aqp.unrms != null) { aqp.unrms = unrms.Clone(); } aqp.strips = strips.ConvertAll(stp => stp.Clone()).ToList(); //*** 0xC33 only aqp.bonePalette = new List <uint>(bonePalette); //Unclear the purpose of these, but when present they have a smaller count than initial mesh and psets. aqp.unkStruct1List = new List <unkStruct1>(unkStruct1List); aqp.mesh2List = new List <MESH>(mesh2List); aqp.pset2List = new List <PSET>(pset2List); aqp.strips2 = strips2.ConvertAll(stp => stp.Clone()).ToList(); aqp.strips3Lengths = new List <int>(strips3Lengths); aqp.strips3 = strips3.ConvertAll(stp => stp.Clone()).ToList(); aqp.unkPointArray1 = new List <Vector3>(unkPointArray1); //Noooooooo idea what these are. Count matches the strips3Lengths count aqp.unkPointArray2 = new List <Vector3>(unkPointArray2); //*** aqp.applyNormalAveraging = applyNormalAveraging; //Custom model related data aqp.tempTris = tempTris.ConvertAll(tri => tri.Clone()).ToList(); aqp.tempMats = tempMats.ConvertAll(mat => mat.Clone()).ToList(); return(aqp); }
//Takes in an Assimp model and generates a full PSO2 model and skeleton from it. public static AquaObject AssimpAquaConvertFull(string initialFilePath, float scaleFactor, bool preAssignNodeIds, bool isNGS) { AquaUtil aquaUtil = new AquaUtil(); float baseScale = 1f / 100f * scaleFactor; //We assume that this will be 100x the true scale because 1 unit to 1 meter isn't the norm Assimp.AssimpContext context = new Assimp.AssimpContext(); context.SetConfig(new Assimp.Configs.FBXPreservePivotsConfig(false)); Assimp.Scene aiScene = context.ImportFile(initialFilePath, Assimp.PostProcessSteps.Triangulate | Assimp.PostProcessSteps.JoinIdenticalVertices | Assimp.PostProcessSteps.FlipUVs); AquaObject aqp; AquaNode aqn = new AquaNode(); if (isNGS) { aqp = new NGSAquaObject(); } else { aqp = new ClassicAquaObject(); } //Construct Materials Dictionary <string, int> matNameTracker = new Dictionary <string, int>(); foreach (var aiMat in aiScene.Materials) { string name; if (matNameTracker.ContainsKey(aiMat.Name)) { name = $"{aiMat.Name} ({matNameTracker[aiMat.Name]})"; matNameTracker[aiMat.Name] += 1; } else { name = aiMat.Name; matNameTracker.Add(aiMat.Name, 1); } AquaObject.GenericMaterial genMat = new AquaObject.GenericMaterial(); List <string> shaderList = new List <string>(); AquaObjectMethods.GetMaterialNameData(ref name, shaderList, out string alphaType, out string playerFlag); genMat.matName = name; genMat.shaderNames = shaderList; genMat.blendType = alphaType; genMat.specialType = playerFlag; genMat.texNames = new List <string>(); genMat.texUVSets = new List <int>(); //Texture assignments. Since we can't rely on these to export properly, we dummy them or just put diffuse if a playerFlag isn't defined. //We'll have the user set these later if needed. if (genMat.specialType != null) { AquaObjectMethods.GenerateSpecialMaterialParameters(genMat); } else if (aiMat.TextureDiffuse.FilePath != null) { genMat.texNames.Add(Path.GetFileName(aiMat.TextureDiffuse.FilePath)); } else { genMat.texNames.Add("tex0_d.dds"); } genMat.texUVSets.Add(0); AquaObjectMethods.GenerateMaterial(aqp, genMat, true); } //Default to this so ids can be assigned by order if needed Dictionary <string, int> boneDict = new Dictionary <string, int>(); if (aiScene.RootNode.Name == null || !aiScene.RootNode.Name.Contains("(") || preAssignNodeIds == true) { int nodeCounter = 0; BuildAiNodeDictionary(aiScene.RootNode, ref nodeCounter, boneDict); } IterateAiNodesAQP(aqp, aqn, aiScene, aiScene.RootNode, Matrix4x4.Transpose(GetMat4FromAssimpMat4(aiScene.RootNode.Transform)), baseScale); //Assimp data is gathered, proceed to processing model data for PSO2 AquaUtil.ModelSet set = new AquaUtil.ModelSet(); set.models.Add(aqp); aquaUtil.aquaModels.Add(set); aquaUtil.ConvertToNGSPSO2Mesh(false, false, false, true, false, false, true); //AQPs created this way will require more processing to finish. //-Texture lists in particular, MUST be generated as what exists is not valid without serious errors return(aqp); }