/// <summary> /// A utility function that iterates through all of the nodes recursively, as some may store mesh data.<para/> /// This does not decode the rig. It strictly grabs meshes out of the rig. /// </summary> /// <param name="baseModel">The <see cref="ModelConfig"/> that contained this <see cref="ArticulatedConfig"/>.</param> /// <param name="model">A reference to the <see cref="ArticulatedConfig"/> that contains these nodes.</param> /// <param name="sourceFile">The file where the <see cref="ArticulatedConfig"/> is stored.</param> /// <param name="parent">The parent node to iterate through.</param> /// <param name="models">The <see cref="List{T}"/> of all models ripped from the source .dat file in this current chain (which may include references to other .dat files)</param> /// <param name="latestTransform">The latest transform that has been applied. This is used for recursive motion since nodes inherit the transform of their parent.</param> /// <param name="initialTransform"></param> /// <param name="nodeModels">A lookup from a <see cref="Node"/> to a <see cref="Model3D"/>, which does include potentially empty models for standard, non-mesh nodes.</param> /// <param name="fullDepthName">The complete path to this model from rsrc, rsrc included.</param> public static void RecursivelyIterateNodes(ModelConfig baseModel, ArticulatedConfig model, FileInfo sourceFile, Node parent, List <Model3D> models, Transform3D latestTransform, Transform3D initialTransform, Dictionary <string, Model3D> nodeModels, string fullDepthName) { foreach (Node node in parent.children) { // Transform3D newTransform = latestTransform; if (node is MeshNode meshNode) { VisibleMesh mesh = meshNode.visible; if (mesh != null) { // "Let's use a node designed to store meshes for something that doesn't contain meshes!" // -- Some knucklehead at OOO. // ...No offense. string meshTitle = "-MeshNodes[\"" + node.name + "\"]"; Model3D meshToModel = GeometryConfigTranslator.GetGeometryInformation(mesh.geometry, fullDepthName + meshTitle); meshToModel.Name = ResourceDirectoryGrabber.GetDirectoryDepth(sourceFile) + meshTitle; meshToModel.RawName = node.name; (List <string> textureFiles, string active) = ModelPropertyUtility.FindTexturesAndActiveFromDirects(baseModel, mesh.texture); meshToModel.Textures.SetFrom(textureFiles); meshToModel.ActiveTexture = active; /* * meshToModel.Textures.SetFrom(ModelPropertyUtility.FindTexturesFromDirects(baseModel)); * meshToModel.ActiveTexture = mesh.texture; */ // Modify the transform that it already has to the node's transform. meshToModel.Transform.composeLocal(latestTransform); meshToModel.Transform.composeLocal(node.transform); nodeModels[node.name] = meshToModel; models.Add(meshToModel); } } else { string meshTitle = "-Nodes[\"" + node.name + "\"]"; Model3D emptyModel = Model3D.NewEmpty(); emptyModel.Name = ResourceDirectoryGrabber.GetDirectoryDepth(sourceFile) + meshTitle; emptyModel.Transform.composeLocal(latestTransform); emptyModel.Transform.composeLocal(node.transform); nodeModels[node.name] = emptyModel; models.Add(emptyModel); } //VertexGroup group = new VertexGroup(); //group.Name = node.name; SKAnimatorToolsProxy.IncrementProgress(); if (node.children.Length > 0) { RecursivelyIterateNodes(baseModel, model, sourceFile, node, models, latestTransform.compose(node.transform), initialTransform, nodeModels, fullDepthName); } } }
public void HandleModelConfig(FileInfo sourceFile, ModelConfig baseModel, List <Model3D> modelCollection, DataTreeObject dataTreeParent = null, Transform3D globalTransform = null, Dictionary <string, dynamic> extraData = null) { // ModelConfigHandler.SetupCosmeticInformation(baseModel, dataTreeParent); StaticConfig model = (StaticConfig)baseModel.implementation; SetupCosmeticInformation(model, dataTreeParent); //Model3D mdl = new Model3D(); MeshSet meshes = model.meshes; VisibleMesh[] renderedMeshes = meshes.visible; SKAnimatorToolsProxy.IncrementEnd(renderedMeshes.Length); int idx = 0; string depth1Name = ResourceDirectoryGrabber.GetDirectoryDepth(sourceFile); string fullDepthName = ResourceDirectoryGrabber.GetDirectoryDepth(sourceFile, -1); foreach (VisibleMesh mesh in renderedMeshes) { string meshTitle = "-Mesh[" + idx + "]"; Model3D meshToModel = GeometryConfigTranslator.GetGeometryInformation(mesh.geometry, fullDepthName + meshTitle); meshToModel.Name = depth1Name + meshTitle; meshToModel.Transform = meshToModel.Transform.compose(globalTransform).compose(new Transform3D(meshes.bounds.getCenter(), Quaternion.IDENTITY, 1f)); //meshToModel.Textures.SetFrom(ModelConfigHandler.GetTexturesFromModel(sourceFile, model)); //meshToModel.Textures.SetFrom(ModelPropertyUtility.FindTexturesFromDirects(baseModel)); //meshToModel.Textures.SetFrom(new List<string>() { mesh.texture }); //meshToModel.ActiveTexture = mesh.texture; (List <string> textureFiles, string active) = ModelPropertyUtility.FindTexturesAndActiveFromDirects(baseModel, mesh.texture); meshToModel.Textures.SetFrom(textureFiles); meshToModel.ActiveTexture = active; modelCollection.Add(meshToModel); idx++; SKAnimatorToolsProxy.IncrementProgress(); } }
public void HandleModelConfig(FileInfo sourceFile, ModelConfig baseModel, List <Model3D> modelCollection, DataTreeObject dataTreeParent = null, Transform3D globalTransform = null, Dictionary <string, dynamic> extraData = null) { StaticSetConfig staticSet = (StaticSetConfig)baseModel.implementation; SetupCosmeticInformation(staticSet, dataTreeParent); string depth1Name = ResourceDirectoryGrabber.GetDirectoryDepth(sourceFile); string fullDepthName = ResourceDirectoryGrabber.GetDirectoryDepth(sourceFile, -1); if (staticSet.meshes != null) { SKAnimatorToolsProxy.IncrementEnd(staticSet.meshes.size()); if (extraData != null && extraData.ContainsKey("DirectArgs")) { Dictionary <string, dynamic> directs = extraData["DirectArgs"]; SKAnimatorToolsProxy.IncrementEnd(1); SKAnimatorToolsProxy.SetProgressState(ProgressBarState.ExtraWork); bool got = false; foreach (string key in directs.Keys) { Parameter param = baseModel.getParameter(key); if (param is Parameter.Direct direct) { if (direct.paths.Contains("implementation.model")) { staticSet.model = directs[key]; XanLogger.WriteLine("Set model to " + staticSet.model, XanLogger.DEBUG); SKAnimatorToolsProxy.IncrementProgress(); got = true; break; } } else if (param is Parameter.Choice choice) { foreach (Parameter.Direct dir in choice.directs) { if (dir.paths.Contains("implementation.model")) { staticSet.model = directs[key]; XanLogger.WriteLine("Set model to " + staticSet.model, XanLogger.DEBUG); SKAnimatorToolsProxy.IncrementProgress(); got = true; break; } } } } if (!got) { SKAnimatorToolsProxy.IncrementProgress(); // Just inc anyway } } // Export them all! object[] keys = staticSet.meshes.keySet().toArray(); SKAnimatorToolsProxy.IncrementEnd(keys.Length); foreach (object key in keys) { MeshSet subModel = (MeshSet)staticSet.meshes.get(key); VisibleMesh[] meshes = subModel.visible; int idx = 0; SKAnimatorToolsProxy.IncrementEnd(meshes.Length); foreach (VisibleMesh mesh in meshes) { string meshTitle = "-MeshSets[" + key.ToString() + "].Mesh[" + idx + "]"; Model3D meshToModel = GeometryConfigTranslator.GetGeometryInformation(mesh.geometry, fullDepthName + meshTitle); meshToModel.Name = depth1Name + meshTitle; meshToModel.ExtraData["StaticSetEntryName"] = key.ToString(); meshToModel.ExtraData["StaticSetConfig"] = staticSet; if (globalTransform != null) { meshToModel.Transform = globalTransform.compose(meshToModel.Transform); } //meshToModel.Textures.SetFrom(ModelPropertyUtility.FindTexturesFromDirects(baseModel)); //meshToModel.ActiveTexture = mesh.texture; (List <string> textureFiles, string active) = ModelPropertyUtility.FindTexturesAndActiveFromDirects(baseModel, mesh.texture); meshToModel.Textures.SetFrom(textureFiles); meshToModel.ActiveTexture = active; modelCollection.Add(meshToModel); idx++; SKAnimatorToolsProxy.IncrementProgress(); } SKAnimatorToolsProxy.IncrementProgress(); } } }
public void HandleModelConfig(FileInfo sourceFile, ModelConfig baseModel, List <Model3D> modelCollection, DataTreeObject dataTreeParent = null, Transform3D globalTransform = null, Dictionary <string, dynamic> extraData = null) { // ModelConfigHandler.SetupCosmeticInformation(baseModel, dataTreeParent); // ArticulatedConfig has a lot of steps. SKAnimatorToolsProxy.IncrementEnd(4); ArticulatedConfig model = (ArticulatedConfig)baseModel.implementation; SetupCosmeticInformation(model, dataTreeParent); MeshSet meshes = model.skin; VisibleMesh[] renderedMeshes = meshes.visible; Dictionary <string, Armature> allInstantiatedArmatures = new Dictionary <string, Armature>(); List <Model3D> allModelsAndNodes = new List <Model3D>(); // 1 SKAnimatorToolsProxy.IncrementProgress(); int idx = 0; string depth1Name = ResourceDirectoryGrabber.GetDirectoryDepth(sourceFile); string fullDepthName = ResourceDirectoryGrabber.GetDirectoryDepth(sourceFile, -1); SKAnimatorToolsProxy.IncrementEnd(renderedMeshes.Length); foreach (VisibleMesh mesh in renderedMeshes) { string meshTitle = "-Skin-Mesh[" + idx + "]"; Model3D meshToModel = GeometryConfigTranslator.GetGeometryInformation(mesh.geometry, fullDepthName + meshTitle, model.root); meshToModel.Name = depth1Name + meshTitle; if (globalTransform != null) { meshToModel.Transform.composeLocal(globalTransform); } (List <string> textureFiles, string active) = ModelPropertyUtility.FindTexturesAndActiveFromDirects(baseModel, mesh.texture); meshToModel.Textures.SetFrom(textureFiles); meshToModel.ActiveTexture = active; if (meshToModel.Mesh.HasBoneData) { XanLogger.WriteLine("Model has bone data, setting that up.", XanLogger.TRACE); // meshToModel.Mesh.SetBones(model.root); // ^ now called by GetGeometryInformation foreach (KeyValuePair <string, Armature> boneNamesToBones in meshToModel.Mesh.AllBones) { allInstantiatedArmatures[boneNamesToBones.Key] = boneNamesToBones.Value; } allModelsAndNodes.Add(meshToModel); } modelCollection.Add(meshToModel); idx++; SKAnimatorToolsProxy.IncrementProgress(); } // 2 SKAnimatorToolsProxy.IncrementProgress(); SKAnimatorToolsProxy.IncrementEnd(GetNodeCount(model.root)); Dictionary <string, Model3D> nodeModels = new Dictionary <string, Model3D>(); RecursivelyIterateNodes(baseModel, model, sourceFile, model.root, modelCollection, globalTransform, globalTransform, nodeModels, fullDepthName); allModelsAndNodes.AddRange(nodeModels.Values); SKAnimatorToolsProxy.SetProgressState(ProgressBarState.ExtraWork); SKAnimatorToolsProxy.IncrementEnd(model.attachments.Length); foreach (Attachment attachment in model.attachments) { List <Model3D> attachmentModels = ConfigReferenceUtil.HandleConfigReference(sourceFile, attachment.model, modelCollection, dataTreeParent, globalTransform); if (attachmentModels == null) { SKAnimatorToolsProxy.IncrementProgress(); continue; // A lot of attachments have null models and I'm not sure why. } // NEW BEHAVIOR: Is the model root-less but rigged? // Set its root to *this* model foreach (Model3D mdl in attachmentModels) { if (mdl.Mesh != null && mdl.Mesh.UsesExternalRoot) { mdl.Mesh.SetBones(model.root); } } SKAnimatorToolsProxy.IncrementEnd(attachmentModels.Count); foreach (Model3D referencedModel in attachmentModels) { referencedModel.Transform.composeLocal(attachment.transform); if (allInstantiatedArmatures.ContainsKey(attachment.node ?? string.Empty)) { referencedModel.AttachmentNode = allInstantiatedArmatures[attachment.node]; XanLogger.WriteLine("Attached [" + referencedModel.Name + "] to [" + attachment.node + "]", XanLogger.TRACE); } else { // New catch case: This might actually be the name of a model! if (nodeModels.ContainsKey(attachment.node ?? string.Empty)) { // Indeed it is! referencedModel.AttachmentModel = nodeModels[attachment.node]; referencedModel.AttachmentModel.Transform.setScale(1f); // TODO: Is this okay? if (referencedModel.Transform.getType() < Transform3D.AFFINE) { float scale = referencedModel.Transform.getScale(); referencedModel.Transform.set(new Transform3D(new Vector3f(), Quaternion.IDENTITY, scale)); } else { Vector3f scale = referencedModel.Transform.extractScale(); referencedModel.Transform.set(new Transform3D(new Vector3f(), Quaternion.IDENTITY, scale)); } XanLogger.WriteLine("Attached [" + referencedModel.Name + "] to [" + attachment.node + "]", XanLogger.TRACE); } else { XanLogger.WriteLine("Attachment wanted to attach to node or model [" + attachment.node + "] but it does not exist!"); } } SKAnimatorToolsProxy.IncrementProgress(); } SKAnimatorToolsProxy.IncrementProgress(); } SKAnimatorToolsProxy.SetProgressState(ProgressBarState.OK); // 3 SKAnimatorToolsProxy.IncrementProgress(); SKAnimatorToolsProxy.IncrementEnd(model.animationMappings.Length); foreach (AnimationMapping animationMapping in model.animationMappings) { ConfigReference animationRef = animationMapping.animation; if (animationRef.IsFileReference()) { object animationObj = animationRef.ResolveFile(); if (animationObj is AnimationConfig animation) { SKAnimatorToolsProxy.SetProgressState(ProgressBarState.ExtraWork); AnimationConfigHandler.HandleAnimationImplementation(animationRef, animationMapping.name, animation, animation.implementation, allModelsAndNodes); SKAnimatorToolsProxy.SetProgressState(ProgressBarState.OK); } } SKAnimatorToolsProxy.IncrementProgress(); } // 4 SKAnimatorToolsProxy.IncrementProgress(); }