public void AddMorph(IPEPluginHost host, Form1 form) { if (basePos.Count < 1) { MessageBox.Show("モデル形状に変化がありません"); return; } IPXMorph nmorph = host.Builder.Pmx.Morph(); nmorph.Kind = MorphKind.UV; nmorph.Name = form.MorphName; nmorph.Panel = form.MorphPanel; var pmx = host.Connector.Pmx.GetCurrentState(); foreach (var i in basePos.Keys) { IPXUVMorphOffset offset = host.Builder.Pmx.UVMorphOffset(); offset.Vertex = pmx.Vertex[i]; Vector3 offsetVec = morphedPos[i] - basePos[i]; offset.Offset = new V4(offsetVec, 0); nmorph.Offsets.Add(offset); } pmx.Morph.Add(nmorph); host.Connector.Pmx.Update(pmx); host.Connector.Form.UpdateList(PEPlugin.Pmd.UpdateObject.All); host.Connector.View.PMDView.UpdateModel(); host.Connector.View.PMDView.UpdateView(); ReSetUVList(host.Connector, form); MessageBox.Show(nmorph.Name + "を追加しました"); }
private void PopulateList(MorphKind kind) { _pmx = GetCurrentScene(); morphList.Items.Clear(); for (int i = 0; i < _pmx.Morph.Count; ++i) { IPXMorph morph = _pmx.Morph[i]; if (MorphIsOfKind(morph, kind)) { ListViewItem item = new ListViewItem(new string[] { morph.Name, morph.NameE }); item.Tag = i; morphList.Items.Add(item); } } }
private bool MorphIsOfKind(IPXMorph morph, MorphKind kind) { switch (kind) { case MorphKind.Vertex: return(morph.Kind == PEPlugin.Pmx.MorphKind.Vertex); case MorphKind.UV: return(morph.Kind == PEPlugin.Pmx.MorphKind.UV || morph.Kind == PEPlugin.Pmx.MorphKind.UVA1 || morph.Kind == PEPlugin.Pmx.MorphKind.UVA2 || morph.Kind == PEPlugin.Pmx.MorphKind.UVA3 || morph.Kind == PEPlugin.Pmx.MorphKind.UVA4); case MorphKind.BoneRotation: case MorphKind.BoneTranslation: return(morph.Kind == PEPlugin.Pmx.MorphKind.Bone); default: return(false); } }
private void applyButton_Click(object sender, EventArgs e) { _pmx = GetCurrentScene(); foreach (ListViewItem item in morphList.SelectedItems) { int index = (int)item.Tag; _pmx = _args.Host.Connector.Pmx.GetCurrentState(); // Create a working copy to make sure the original remains unaffected IPXMorph workingCopy = (IPXMorph)_pmx.Morph[index].Clone(); // Scale offsets switch (SelectedMorphKind) { case MorphKind.Vertex: foreach (IPXVertexMorphOffset offset in workingCopy.Offsets) { offset.Offset = new V3(offset.Offset.X * (float)scaleX.Value, offset.Offset.Y * (float)scaleY.Value, offset.Offset.Z * (float)scaleZ.Value); } break; case MorphKind.UV: // TBI break; default: break; } // Apply morph to the scene foreach (IPXVertexMorphOffset offset in workingCopy.Offsets) { offset.Vertex.Position += offset.Offset; } } // Update the scene and PMXView _args.Host.Connector.Pmx.Update(_pmx); _args.Host.Connector.View.PmxView.UpdateModel_Vertex(); _args.Host.Connector.View.PmxView.UpdateModel_Bone(); }
internal void LoadUVMorph(IPXMorph morph) { if (!morph.IsUV) { throw new ArgumentException("UVモーフ以外のモーフが指定されました。"); } var materialMap = new ConcurrentDictionary <IPXUVMorphOffset, Material>(morph.Offsets.ToDictionary(o => (IPXUVMorphOffset)o, _ => (Material)null)); materialMap.Keys.AsParallel().ForAll(offset => { materialMap[offset] = Materials.First(m => m.Vertices.Contains(offset.Vertex)); }); var offsetsGroupByMaterial = materialMap.GroupBy(p => p.Value, p => p.Key); foreach (var offsetGroup in offsetsGroupByMaterial) { Do(offsetGroup.Key, new CommandMoveVerticesByMorph(offsetGroup)); } }
/// <summary> /// Executes the provided XmlDocument on the PMX object. /// </summary> public static RunnerResult Execute(XmlDocument doc, IPXPmx pmx, IPXPmxBuilder builder, RunnerProgress progress) { XmlElement root = doc.DocumentElement; progress.Report(0, "> Execution started."); // Begin processing // Only the first level of elements are interpreted as commands. XmlElement[] commands = root.ChildNodes.OfType <XmlElement>().ToArray(); for (int i = 0; i < commands.Length; ++i) { try { XmlElement node = commands[i]; // The meaningful content of each case constitutes a separate block to avoid mixing variables. Might be unnecessary, but right now I'm not feeling too hot and my output WILL be sloppy. // Should review this code later. switch (node.Name.ToLowerInvariant()) { // Creates a new bone with the provided properties. case "bone": { string name = Math.Abs(Guid.NewGuid().GetHashCode()).ToString(); IPXBone bone = null; // Get name and check for collision if (node["name"] != null) { name = node["name"].InnerText; IPXBone existing = pmx.Bone.Where(b => b.Name == name).FirstOrDefault(); if (existing != null) { // If there is a collision, refer to the collision attribute switch (node["name"].GetAttribute("collision")) { // If the attribute is "update" or "replace", refer to the existing bone for the rest of the command. case "replace": case "update": bone = existing; break; // If the attribute is "skip", don't do anything with the bone and skip the command. case "skip": continue; // If the attribute is not valid, create a new bone and ignore the old one. default: bone = builder.Bone(); bone.Name = bone.NameE = name; break; } } else { bone = builder.Bone(); bone.Name = bone.NameE = name; } } else { bone = builder.Bone(); bone.Name = bone.NameE = name; } if (node["position"] != null) { bone.Position = node["position"].GetV3(); } if (node["translation"] != null) { bone.IsTranslation = bool.TryParse(node["translation"].InnerText, out bool translation) ? translation : false; } if (node["parent"] != null) { bone.Parent = Selector.Bone.Selector(node["parent"], pmx).FirstOrDefault(); } if (node["axis"] != null) { V3 v = node["axis"].GetV3(); v.Normalize(); bone.IsFixAxis = true; bone.FixAxis = v; } if (node["weight"] != null) { //IEnumerable<IPXVertex> vertices = Selector.Vertex.SelectorList(node["weight"].ChildNodes, pmx); IEnumerable <IPXVertex> vertices = Selector.Vertex.SelectorNode(node["weight"], pmx); foreach (IPXVertex v in vertices) { v.Bone1 = bone; v.Weight1 = 1; v.Bone2 = v.Bone3 = v.Bone4 = null; v.Weight2 = v.Weight3 = v.Weight4 = 0; } } pmx.Bone.Add(bone); progress.Report(Percent(i + 1, commands.Length), string.Format("[bone] Added new bone {0}.", bone.Name)); } break; // Assigns the selected vertices to the selected bone using BDEF1. case "weight": { IPXBone bone = null; if (node["target"] != null) { bone = Selector.Bone.Selector(node["target"], pmx).FirstOrDefault(); if (bone == null) { progress.Report(Percent(i + 1, commands.Length), string.Format("[weight] Bone was not found.", node["target"].InnerText)); break; } } else { progress.Report(Percent(i + 1, commands.Length), "[weight] Bone selector was not specified."); break; } // Set vertex weights if (node["select"] == null) { progress.Report(Percent(i + 1, commands.Length), "[weight] No vertices were selected."); break; } IEnumerable <IPXVertex> vertices = Selector.Vertex.SelectorNode(node["select"], pmx); foreach (IPXVertex v in vertices) { v.Bone1 = bone; v.Weight1 = 1; v.Bone2 = v.Bone3 = v.Bone4 = null; v.Weight2 = v.Weight3 = v.Weight4 = 0; } progress.Report(Percent(i + 1, commands.Length), string.Format("[weight] Weighted {0} vertices to {1} ({2}).", vertices.Count(), bone.Name, bone.NameE)); } break; // Creates a new UV morph. case "uvmorph": { // The morph's properties are defined in attributes. IPXMorph morph = builder.Morph(); morph.Kind = MorphKind.UV; // Set the UV channel if (int.TryParse(node.GetAttribute("channel"), out int ch)) { switch (ch) { case 1: morph.Kind = MorphKind.UVA1; break; case 2: morph.Kind = MorphKind.UVA2; break; case 3: morph.Kind = MorphKind.UVA3; break; case 4: morph.Kind = MorphKind.UVA4; break; default: morph.Kind = MorphKind.UV; break; } } // Set the group panel if (int.TryParse(node.GetAttribute("group"), out int group) && group <= 4 && group >= 0) { morph.Panel = group; } else { switch (node.GetAttribute("group").ToLowerInvariant()) { case "hidden": case "hide": case "none": case "0": morph.Panel = 0; break; case "eyebrow": case "eyebrows": case "1": morph.Panel = 1; break; case "eye": case "eyes": case "2": morph.Panel = 2; break; case "mouth": case "3": morph.Panel = 3; break; default: morph.Panel = 4; break; } } // Set the name, ignore collisions if (node.HasAttribute("name")) { morph.Name = morph.NameE = node.GetAttribute("name"); } else { morph.Name = morph.NameE = morph.GetHashCode().ToString(); } // Each morph contains one or more steps. Each step has its own selectors and transforms, which are applied independently. foreach (XmlElement step in node.ChildNodes.OfType <XmlElement>().Where(el => el.Name.ToLowerInvariant() == "step")) { // Skip steps that have no selectors if (step["select"] == null) { continue; } // Select vertices IEnumerable <IPXVertex> vertices = Selector.Vertex.SelectorNode(step["select"], pmx); foreach (XmlElement e in step) { switch (e.Name.ToLowerInvariant()) { case "pan": case "translate": { V2 v = e.GetV2(); foreach (IPXVertex vertex in vertices) { IPXUVMorphOffset offset = builder.UVMorphOffset(); offset.Vertex = vertex; offset.Offset = new V4(v.X, v.Y, 0, 0); morph.Offsets.Add(offset); } } break; case "rotate": // TODO: UV morph rotation case "scale": // TODO: UV morph scaling default: break; } } } pmx.Morph.Add(morph); progress.Report(Percent(i + 1, commands.Length), string.Format("[uvmorph] Created UV morph {0} with {1} offsets.", morph.Name, morph.Offsets.Count)); } break; // No particular functionality, testing only. case "test": { //foreach (IPXMorph morph in pmx.Morph.Where(m => m.Kind == MorphKind.UV)) //{ // foreach (IPXUVMorphOffset o in morph.Offsets) // { // _report(string.Format("{0:f2}, {1:f2}, {2:f2}, {3:f2}", o.Offset.X, o.Offset.Y, o.Offset.Z, o.Offset.W), -1); // } //} } break; // Sets up the selected vertices for use with AutoLuminous. case "autoluminous": { if (node["select"] == null) { progress.Report(Percent(i + 1, commands.Length), "[weight] No vertices were selected."); break; } IEnumerable <IPXVertex> vertices = Selector.Vertex.SelectorNode(node["select"], pmx); // Set required values. pmx.Header.UVACount = Math.Max(pmx.Header.UVACount, 3); // UV1 int texture = 0; int hsv = 0; float flashFrequency = 0; // UV2 V4 baseColor = new V4(0, 0, 0, 0); // UV3 float texSubtract = 0; float flashBias = 0; float push = 0; // Base emissive color if (node["color"] != null) { baseColor = node["color"].GetV4(); } // Base emissive power if (node["power"] != null) { baseColor.W = node["power"].GetSingle(); } if (node["texture"] != null) { int.TryParse(node["texture"].InnerText, System.Globalization.NumberStyles.Integer, System.Globalization.NumberFormatInfo.InvariantInfo, out texture); } if (node["colormode"] != null) { switch (node["colormode"].InnerText.ToLowerInvariant()) { case "hsv": hsv = 10; break; default: hsv = 0; break; } } if (node["flash"] != null) { float.TryParse(node["flash"].GetAttribute("bias"), System.Globalization.NumberStyles.Float, System.Globalization.NumberFormatInfo.InvariantInfo, out flashBias); flashFrequency = node["flash"].GetSingle(); } if (node["subtract"] != null) { texSubtract = node["subtract"].GetSingle(); } if (node["push"] != null) { push = node["push"].GetSingle(); } foreach (IPXVertex v in vertices) { v.UVA1.X = 0.2f; // Required value v.UVA1.Y = 0.7f; // Required value v.UVA1.Z = flashFrequency; v.UVA1.W = texture + hsv; v.UVA2 = baseColor; v.UVA3.X = texSubtract; v.UVA3.Y = flashBias; v.UVA3.Z = push; } } break; // Creates a vertex morph for AutoLuminous properties. case "almorph": { if (node["select"] == null) { progress.Report(Percent(i + 1, commands.Length), "[weight] No vertices were selected."); break; } HashSet <IPXVertex> vertices = new HashSet <IPXVertex>(Selector.Vertex.SelectorNode(node["select"], pmx)); V4 color = new V4(); if (node["color"] != null) { color = node["color"].GetV4(); } // TODO: Implement the rest of the AL properties in ALMorph IPXMorph morph = builder.Morph(); morph.Kind = MorphKind.UVA2; if (node.HasAttribute("name")) { morph.Name = morph.NameE = node.GetAttribute("name"); } else { morph.Name = morph.NameE = morph.GetHashCode().ToString(); } foreach (IPXVertex v in vertices) { // Set required values in case the vertex isn't already AL-enabled v.UVA1.X = 0.2f; v.UVA1.Y = 0.7f; // Create the offset morph.Offsets.Add(builder.UVMorphOffset(v, color)); } } break; // Sets environment variables. case "settings": { foreach (XmlElement child in node.ChildNodes.OfType <XmlElement>()) { switch (child.Name.ToLowerInvariant()) { case "exception": break; case "regex": bool regexCI = GlobalSettings.RegexCaseInsensitive; bool.TryParse(child.GetAttributeCI("caseinsensitive"), out regexCI); break; case "colortype": GlobalSettings.ColorIsFloat = child.InnerText.ToLowerInvariant() == "float"; break; default: break; } } } break; // Displays a MessageBox with the provided content. Optionally perform certain actions based on user input. case "mbox": case "messagebox": case "prompt": { if (int.TryParse(node.GetAttributeCI("skip"), out int skipNumber) && skipNumber > 0) { StringBuilder sb = new StringBuilder(string.Format("Would you like to skip the following {0} command(s)?\n", skipNumber)); for (int j = 1; j <= skipNumber; ++j) { sb.Append(commands[i + j].Name); } MessageBox.Show(sb.ToString(), "Prompt: skip", MessageBoxButtons.YesNo, MessageBoxIcon.Question); } else { MessageBox.Show(node.InnerText, "Message", MessageBoxButtons.OK, MessageBoxIcon.Information); } } break; // Prints a line in the console. case "echo": case "print": progress.Report(Percent(i + 1, commands.Length), node.InnerText); break; default: progress.Report(Percent(i + 1, commands.Length), "Skipping unknown command " + node.Name); break; } } catch (Exception ex) { if (GlobalSettings.Exception == GlobalSettings.ErrorHandling.Ask) { if (MessageBox.Show(string.Format("The following exception has occured:\n\n{0}\n\nWould you like to continue execution?", ex.ToString()), "Exception", System.Windows.Forms.MessageBoxButtons.YesNo, System.Windows.Forms.MessageBoxIcon.Error) == System.Windows.Forms.DialogResult.No) { return(RunnerResult.Fail); } } else if (GlobalSettings.Exception == GlobalSettings.ErrorHandling.Abort) { return(RunnerResult.Fail); } } } // If control has reached this point, the execution is considered successful. return(RunnerResult.Success); }
private void scaleButton_Click(object sender, EventArgs e) { // Only a quaternion's magnitude can be scaled - notify the user if (SelectedMorphKind == MorphKind.BoneRotation && !uniformCheck.Checked && MessageBox.Show("For bone rotation morphs, only the magnitude can be scaled, and only uniformly. If you proceed, the rotation magnitude will be scaled by the factor in the X field.\n\nWould you like to proceed?", "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.No) { return; } _pmx = GetCurrentScene(); // If new morphs are added, update the list automatically bool updateList = false; foreach (ListViewItem item in morphList.SelectedItems) { int index = (int)item.Tag; // Create a working copy to make sure the original remains unaffected IPXMorph workingCopy = (IPXMorph)_pmx.Morph[index].Clone(); switch (SelectedMorphKind) { case MorphKind.Vertex: foreach (IPXVertexMorphOffset offset in workingCopy.Offsets) { offset.Offset = new V3(offset.Offset.X * (float)scaleX.Value, offset.Offset.Y * (float)scaleY.Value, offset.Offset.Z * (float)scaleZ.Value); } break; case MorphKind.UV: // TBI break; case MorphKind.BoneRotation: foreach (IPXBoneMorphOffset offset in workingCopy.Offsets) { // Scale the rotation's magnitude Q q = offset.Rotation; float theta = 2 * (float)Math.Acos(q.W); offset.Rotation.W = (float)Math.Cos((theta * (float)scaleX.Value) / 2); //float s = (float)Math.Sin(theta / 2); //V3 axis = new V3(); //axis.X = q.X / s; //axis.Y = q.Y / s; //axis.Z = q.Z / s; } break; case MorphKind.BoneTranslation: foreach (IPXBoneMorphOffset offset in workingCopy.Offsets) { offset.Translation = new V3(offset.Translation.X * (float)scaleX.Value, offset.Translation.Y * (float)scaleY.Value, offset.Translation.Z * (float)scaleZ.Value); } break; default: break; } if (createNewCheck.Checked) { // Add a new morph workingCopy.Name += " scaled"; workingCopy.NameE += " scaled"; _pmx.Morph.Add(workingCopy); updateList = true; } else { // Replace the old morph with the clone _pmx.Morph[index] = workingCopy; } } if (updateList) { PopulateList(SelectedMorphKind); } // Commit the changes to the PMX scene _args.Host.Connector.Pmx.Update(_pmx); _args.Host.Connector.Form.UpdateList(PEPlugin.Pmd.UpdateObject.Morph); }
public IPXGroupMorphOffset GroupMorphOffset(IPXMorph morph, float ratio) { throw new NotImplementedException(); }
public IPXMorphNodeItem MorphNodeItem(IPXMorph morph) { throw new NotImplementedException(); }
private void ButtonExecute_Click(object sender, EventArgs e) { IPXPmx pmx = args.Host.Builder.Pmx.Pmx(); pmx.ModelInfo.ModelName = textBoxModelName.Text; pmx.ModelInfo.Comment = textBoxModelText.Text; // 作成したpmxにマテリアルをコピー foreach (int i in listBoxMaterial.SelectedIndices) { pmx.Material.Add(currentPmx.Material[i]); } // マテリアルに含まれる頂点のリストを作成 List <IPXVertex> vertices = new List <IPXVertex>(); foreach (var m in pmx.Material) { foreach (var f in m.Faces) { vertices.Add(f.Vertex1); vertices.Add(f.Vertex2); vertices.Add(f.Vertex3); } } // 重複を除去 vertices = vertices.Distinct().ToList(); foreach (var v in vertices) { pmx.Vertex.Add(v); } // 頂点のウェイトに基づいてボーンをコピー if (checkBoxBone.Checked) { if (radioAllBone.Checked) { foreach (var b in currentPmx.Bone) { pmx.Bone.Add(b); } if (checkBoxPhysics.Checked) { foreach (var b in currentPmx.Body) { pmx.Body.Add(b); } foreach (var j in currentPmx.Joint) { pmx.Joint.Add(j); } } } else { // 元のボーン順を保存 Dictionary <IPXBone, int> boneIndex = new Dictionary <IPXBone, int>(); for (int i = 0; i < currentPmx.Bone.Count; i++) { boneIndex.Add(currentPmx.Bone[i], i); } // 関連ボーン List <IPXBone> bones = new List <IPXBone>(); foreach (var v in vertices) { if (v.Bone1 != null) { bones.Add(v.Bone1); } if (v.Bone2 != null) { bones.Add(v.Bone2); } if (v.Bone3 != null) { bones.Add(v.Bone3); } if (v.Bone4 != null) { bones.Add(v.Bone4); } } bones = bones.Distinct().ToList(); if (checkBoxPhysics.Checked) { // 関連ボーンの関連剛体 List <IPXBody> bodies = new List <IPXBody>(); foreach (var b in bones) { bodies.AddRange(currentPmx.Body.Where(x => x.Bone == b)); } bodies = bodies.Distinct().ToList(); // 関連剛体の関連ジョイント List <IPXJoint> joints = new List <IPXJoint>(); foreach (var b in bodies) { joints.AddRange(currentPmx.Joint.Where(x => x.BodyA == b || x.BodyB == b)); } joints = joints.Distinct().ToList(); // ジョイントに必要な剛体がbodiesに不足していた場合追加 foreach (var j in joints) { if (!bodies.Any(b => b == j.BodyA)) { bodies.Add(j.BodyA); } if (!bodies.Any(b => b == j.BodyB)) { bodies.Add(j.BodyB); } } // 剛体に必要なボーンがbonesに不足していた場合追加 foreach (var b in bodies) { if (!bones.Any(x => x == b.Bone)) { bones.Add(b.Bone); } } // 剛体・ジョイントの並び順を戻す Dictionary <IPXBody, int> bodyIndex = new Dictionary <IPXBody, int>(); for (int i = 0; i < currentPmx.Body.Count; i++) { bodyIndex.Add(currentPmx.Body[i], i); } Dictionary <IPXJoint, int> jointIndex = new Dictionary <IPXJoint, int>(); for (int i = 0; i < currentPmx.Joint.Count; i++) { jointIndex.Add(currentPmx.Joint[i], i); } bodies.Sort((a, b) => bodyIndex[a] - bodyIndex[b]); joints.Sort((a, b) => jointIndex[a] - jointIndex[b]); foreach (var b in bodies) { pmx.Body.Add(b); } foreach (var j in joints) { pmx.Joint.Add(j); } } bones.Sort((a, b) => boneIndex[a] - boneIndex[b]); if (radioRelationBone.Checked) { foreach (var b in bones) { pmx.Bone.Add(b); } } if (radioRelationBoneAndParent.Checked) { List <IPXBone> bonesWithParent = new List <IPXBone>(); //関連ボーンの親を遡って保持 for (int i = 0; i < bones.Count; i++) { IPXBone b = bones[i]; IPXBone forcus = b; while (forcus != null) { if (bonesWithParent.Exists(x => x == forcus)) { break; } bonesWithParent.Add(forcus); if (forcus.AppendParent != null && !bones.Exists(x => x == forcus.AppendParent)) { bones.Add(forcus.AppendParent); } forcus = forcus.Parent; } } bonesWithParent.Sort((a, b) => boneIndex[a] - boneIndex[b]); foreach (var b in bonesWithParent) { pmx.Bone.Add(b); } } } } // モーフをコピー if (checkBoxMorph.Checked) { foreach (var m in currentPmx.Morph) { IPXMorph morph = m; bool morphExists = true; switch (m.Kind) { case MorphKind.Vertex: List <IPXVertexMorphOffset> vmo = m.Offsets.ToList().ConvertAll(o => (IPXVertexMorphOffset)o); foreach (var o in vmo) { if (!vertices.Exists(v => v == o.Vertex)) { morph.Offsets.Remove(o); } } break; case MorphKind.UV: case MorphKind.UVA1: case MorphKind.UVA2: case MorphKind.UVA3: case MorphKind.UVA4: List <IPXUVMorphOffset> umo = m.Offsets.ToList().ConvertAll(o => (IPXUVMorphOffset)o); foreach (var o in umo) { if (!vertices.Exists(v => v == o.Vertex)) { morph.Offsets.Remove(o); } } break; case MorphKind.Material: List <IPXMaterialMorphOffset> mmo = m.Offsets.ToList().ConvertAll(o => (IPXMaterialMorphOffset)o); foreach (var o in mmo) { if (!pmx.Material.Contains(o.Material)) { morph.Offsets.Remove(o); } } break; default: morphExists = false; break; } if (morphExists && morph.Offsets.Count != 0) { pmx.Morph.Add(morph); } } } Update(args.Host.Connector, pmx, PmxUpdateObject.All); MessageBox.Show("完了"); Reload(); }