/// <summary> /// Calcuates the previous state hitboxes positions and returns them as a dictionary /// </summary> /// <returns></returns> private Dictionary <int, Vector3> CalculatePreviousState() { if (viewport.Frame == 0 || !interpolationToolStripMenuItem.Checked) { return(null); } Dictionary <int, Vector3> previousPosition = new Dictionary <int, Vector3>(); JointManager.Frame = viewport.Frame - 1; JointManager.UpdateNoRender(); SubactionProcess.SetFrame(viewport.Frame - 1); foreach (var hb in SubactionProcess.Hitboxes) { var boneID = hb.BoneID; if (boneID == 0) { boneID = 1; } var transform = Matrix4.CreateTranslation(hb.Point1) * JointManager.GetWorldTransform(boneID); transform = transform.ClearScale(); var pos = Vector3.TransformPosition(Vector3.Zero, transform); previousPosition.Add(hb.ID, pos); } return(previousPosition); }
public void Render(JOBJManager jobjManager, List <SBM_Hurtbox> hurtboxes, HSDAccessor selected, Dictionary <int, int> states = null, int bodyState = -1) { foreach (SBM_Hurtbox v in hurtboxes) { var clr = HurtboxColor; var a = 0.25f; if (selected == v) { clr = SelectedHurtboxColor; a = 0.6f; } if (states != null) { if (states.ContainsKey(v.BoneIndex)) { switch (states[v.BoneIndex]) { case 1: clr = InvulColor; break; case 2: clr = IntanColor; break; } } } if (bodyState == 1) { clr = InvulColor; } if (bodyState == 2) { clr = IntanColor; } var transform = jobjManager.GetWorldTransform(v.BoneIndex); if (!HurtboxToCapsule.ContainsKey(v)) { HurtboxToCapsule.Add(v, new Capsule(new Vector3(v.X1, v.Y1, v.Z1), new Vector3(v.X2, v.Y2, v.Z2), v.Size)); } var cap = HurtboxToCapsule[v]; cap.SetParameters(new Vector3(v.X1, v.Y1, v.Z1), new Vector3(v.X2, v.Y2, v.Z2), v.Size); cap.Draw(transform, new Vector4(clr, a)); } }
/// <summary> /// /// </summary> /// <param name="cam"></param> /// <param name="windowWidth"></param> /// <param name="windowHeight"></param> public void Draw(Camera cam, int windowWidth, int windowHeight) { // store previous hitbox state info Dictionary <int, Vector3> previousPosition = CalculatePreviousState(); // reset model parts if (ModelPartsIndices != null) { for (int i = 0; i < ModelPartsIndices.Length; i++) { ModelPartsIndices[i].AnimIndex = -1; } } // process ftcmd SubactionProcess.SetFrame(viewport.Frame); // update display info JointManager.DOBJManager.OverlayColor = SubactionProcess.OverlayColor; JointManager._settings.RenderBones = bonesToolStripMenuItem.Checked; // apply model animations JointManager.Frame = viewport.Frame; JointManager.UpdateNoRender(); // character invisibility if (!SubactionProcess.CharacterInvisibility && modelToolStripMenuItem.Checked) { JointManager.Render(cam, false); } // hurtbox collision if (hurtboxesToolStripMenuItem.Checked) { HurtboxRenderer.Render(JointManager, Hurtboxes, null, SubactionProcess.BoneCollisionStates, SubactionProcess.BodyCollisionState); } // hitbox collision foreach (var hb in SubactionProcess.Hitboxes) { var boneID = hb.BoneID; if (boneID == 0) { if (JointManager.GetJOBJ(1).Child == null) // special case for character like mewtwo with a leading bone { boneID = 2; } else { boneID = 1; } } var transform = Matrix4.CreateTranslation(hb.Point1) * JointManager.GetWorldTransform(boneID); transform = transform.ClearScale(); float alpha = 0.4f; Vector3 hbColor = HitboxColor; if (hb.Element == 8) { hbColor = GrabboxColor; } // drawing a capsule takes more processing power, so only draw it if necessary if (interpolationToolStripMenuItem.Checked && previousPosition != null && previousPosition.ContainsKey(hb.ID)) { var pos = Vector3.TransformPosition(Vector3.Zero, transform); var cap = new Capsule(pos, previousPosition[hb.ID], hb.Size); cap.Draw(Matrix4.Identity, new Vector4(hbColor, alpha)); } else { DrawShape.DrawSphere(transform, hb.Size, 16, 16, hbColor, alpha); } // draw hitbox angle if (hitboxInfoToolStripMenuItem.Checked) { if (hb.Angle != 361) { DrawShape.DrawAngleLine(cam, transform, hb.Size, MathHelper.DegreesToRadians(hb.Angle)); } else { DrawShape.DrawSakuraiAngle(cam, transform, hb.Size); } GLTextRenderer.RenderText(cam, hb.ID.ToString(), transform, StringAlignment.Center, true); } } // environment collision if (ECB != null) { var topN = JointManager.GetWorldTransform(1).ExtractTranslation(); var bone1 = Vector3.TransformPosition(Vector3.Zero, JointManager.GetWorldTransform(ECB.ECBBone1)); var bone2 = Vector3.TransformPosition(Vector3.Zero, JointManager.GetWorldTransform(ECB.ECBBone2)); var bone3 = Vector3.TransformPosition(Vector3.Zero, JointManager.GetWorldTransform(ECB.ECBBone3)); var bone4 = Vector3.TransformPosition(Vector3.Zero, JointManager.GetWorldTransform(ECB.ECBBone4)); var bone5 = Vector3.TransformPosition(Vector3.Zero, JointManager.GetWorldTransform(ECB.ECBBone5)); var bone6 = Vector3.TransformPosition(Vector3.Zero, JointManager.GetWorldTransform(ECB.ECBBone6)); var minx = float.MaxValue; var miny = float.MaxValue; var maxx = float.MinValue; var maxy = float.MinValue; foreach (var p in new Vector3[] { bone1, bone2, bone3, bone4, bone5, bone6 }) { minx = Math.Min(minx, p.Z); maxx = Math.Max(maxx, p.Z); miny = Math.Min(miny, p.Y); maxy = Math.Max(maxy, p.Y); } // ecb diamond if (eCBToolStripMenuItem.Checked) { DrawShape.DrawECB(topN, minx, miny, maxx, maxy, groundECH.Checked); } // ledge grav if (ledgeGrabBoxToolStripMenuItem.Checked) { var correct = Math.Abs(minx - maxx) / 2; //behind DrawShape.DrawLedgeBox( topN.Z, topN.Y + ECB.VerticalOffsetFromTop - ECB.VerticalScale / 2, topN.Z - (correct + ECB.HorizontalScale), topN.Y + ECB.VerticalOffsetFromTop + ECB.VerticalScale / 2, Color.Red); // in front DrawShape.DrawLedgeBox( topN.Z, topN.Y + ECB.VerticalOffsetFromTop - ECB.VerticalScale / 2, topN.Z + correct + ECB.HorizontalScale, topN.Y + ECB.VerticalOffsetFromTop + ECB.VerticalScale / 2, Color.Blue); } } // throw dummy if (throwModelToolStripMenuItem.Checked && !SubactionProcess.ThrownFighter && ThrowDummyManager.JointCount > 0) { if (viewport.Frame < ThrowDummyManager.Animation.FrameCount) { ThrowDummyManager.Frame = viewport.Frame; } ThrowDummyManager.SetWorldTransform(4, JointManager.GetWorldTransform(JointManager.JointCount - 2)); ThrowDummyManager.Render(cam, false); DrawShape.DrawSphere(ThrowDummyManager.GetWorldTransform(35), 1.5f, 16, 16, ThrowDummyColor, 0.5f); DrawShape.DrawSphere(ThrowDummyManager.GetWorldTransform(4), 1.5f, 16, 16, ThrowDummyColor, 0.5f); DrawShape.DrawSphere(ThrowDummyManager.GetWorldTransform(10), 1f, 16, 16, ThrowDummyColor, 0.5f); DrawShape.DrawSphere(ThrowDummyManager.GetWorldTransform(15), 1f, 16, 16, ThrowDummyColor, 0.5f); DrawShape.DrawSphere(ThrowDummyManager.GetWorldTransform(22), 1f, 16, 16, ThrowDummyColor, 0.5f); DrawShape.DrawSphere(ThrowDummyManager.GetWorldTransform(40), 1f, 16, 16, ThrowDummyColor, 0.5f); } // sword trail //AfterImageRenderer.RenderAfterImage(JointManager, viewport.Frame, after_desc); }
/// <summary> /// /// </summary> /// <param name="table"></param> /// <param name="icons"></param> /// <returns></returns> public static MEX_mexSelectChr GenerateMEXMapFromVanilla(SBM_SelectChrDataTable table, MEX_CSSIconEntry[] icons) { // generate icon model var icon_joint = HSDAccessor.DeepClone <HSD_JOBJ>(table.MenuModel.Children[2].Child); icon_joint.TX = 0; icon_joint.TY = 0; icon_joint.TZ = 0; icon_joint.Next = null; var center = RegenerateIcon(icon_joint); var icon_matanim_joint = HSDAccessor.DeepClone <HSD_MatAnimJoint>(table.MenuMaterialAnimation.Children[2].Child); icon_matanim_joint.Next = null; // generate mat anim node var joints = table.MenuModel.BreathFirstList; HSD_TOBJ[] tobjs = new HSD_TOBJ[icons.Max(e => e.FighterExternalID) + 1]; JOBJManager m = new JOBJManager(); m.SetJOBJ(table.MenuModel); m.SetAnimJoint(table.MenuAnimation); m.Frame = 600; m.UpdateNoRender(); var csps = table.MenuMaterialAnimation.Children[6].Child.MaterialAnimation.TextureAnimation.ToTOBJs(); var cspKeys = table.MenuMaterialAnimation.Children[6].Child.MaterialAnimation.TextureAnimation.AnimationObject.FObjDesc.GetDecodedKeys(); var stride = 30; foreach (var ico in icons) { if (joints[ico.icon.JointID].Dobj == null) { continue; } HSD_JOBJ pos = HSDAccessor.DeepClone <HSD_JOBJ>(icon_joint); pos.Dobj.Pobj.Attributes = icon_joint.Dobj.Pobj.Attributes; pos.Dobj.Next.Pobj.Attributes = icon_joint.Dobj.Pobj.Attributes; pos.Dobj.Next.Mobj.Textures = HSDAccessor.DeepClone <HSD_TOBJ>(joints[ico.icon.JointID].Dobj.Next.Mobj.Textures); var worldPosition = Vector3.TransformPosition(Vector3.Zero, m.GetWorldTransform(ico.icon.JointID)); pos.TX = worldPosition.X + center.X; pos.TY = worldPosition.Y + center.Y; pos.TZ = worldPosition.Z + center.Z; ico.Joint = pos; ico.Animation = new MexMenuAnimation(); ico.MatAnimJoint = HSDAccessor.DeepClone <HSD_MatAnimJoint>(icon_matanim_joint); // load csps // find key at stride var icocsps = new List <HSD_TOBJ>(); int cspIndex = 0; while (true) { var key = ico.FighterExternalID + (cspIndex * stride); if (ico.FighterExternalID > 0x13) { key = ico.FighterExternalID + (cspIndex * stride) - 1; } var k = cspKeys.Find(e => e.Frame == key); if (k == null) { break; } icocsps.Add(csps[(int)k.Value]); cspIndex++; } ico.CSPs = icocsps.Select(e => new TOBJProxy() { TOBJ = e }).ToArray(); } m.RefreshRendering = true; MEX_mexSelectChr mex = new MEX_mexSelectChr(); SetMexNode(mex, icons); return(mex); }
/// <summary> /// /// </summary> /// <param name="source"></param> /// <param name="target"></param> /// <param name="animation"></param> /// <param name="sourceMap"></param> /// <param name="targetMap"></param> /// <returns></returns> public static JointAnimManager SmartPort(HSD_JOBJ source, HSD_JOBJ target, JointAnimManager animation, JointMap sourceMap = null, JointMap targetMap = null) { var sourceManager = new JOBJManager(); sourceManager.SetJOBJ(source); var sourceInverseWorldTransforms = new List <Matrix4>(); for (int i = 0; i < sourceManager.JointCount; i++) { sourceInverseWorldTransforms.Add(sourceManager.GetWorldTransform(i).Inverted()); } sourceManager.Animation = animation; var targetManager = new JOBJManager(); targetManager.SetJOBJ(target); JointAnimManager newAnim = new JointAnimManager(); newAnim.FrameCount = sourceManager.Animation.FrameCount; newAnim.Nodes.Clear(); for (int i = 0; i < targetManager.JointCount; i++) { newAnim.Nodes.Add(new AnimNode()); } for (int i = 0; i < sourceManager.JointCount; i++) { int targetIndex = i; int sourceIndex = i; Console.WriteLine(sourceMap[i]); // remap bone if joint maps are present if (sourceMap != null && targetMap != null && !string.IsNullOrEmpty(sourceMap[i])) { targetIndex = targetMap.IndexOf(sourceMap[i]); } if (targetIndex == -1) { continue; } var sourceJoint = sourceManager.GetJOBJ(sourceIndex); var targetJoint = targetManager.GetJOBJ(targetIndex); Console.WriteLine($"\t {sourceJoint.RX} {sourceJoint.RY} {sourceJoint.RZ}"); Console.WriteLine($"\t {targetJoint.RX} {targetJoint.RY} {targetJoint.RZ}"); /*if(sourceMap[i] == "RLegJ") * { * var track = animation.Nodes[sourceIndex].Tracks.Find(e => e.JointTrackType == JointTrackType.HSD_A_J_ROTX); * * if (track != null) * foreach (var k in track.Keys) * k.Value += (float)Math.PI / 2; * * track = animation.Nodes[sourceIndex].Tracks.Find(e => e.JointTrackType == JointTrackType.HSD_A_J_ROTZ); * * if (track != null) * foreach (var k in track.Keys) * k.Value += (float)Math.PI / 2; * }*/ newAnim.Nodes[targetIndex].Tracks = animation.Nodes[sourceIndex].Tracks;; } return(newAnim); }
/// <summary> /// /// </summary> /// <param name="source"></param> /// <param name="target"></param> /// <param name="animation"></param> /// <returns></returns> public static JointAnimManager Retarget(HSD_JOBJ source, HSD_JOBJ target, JointAnimManager animation, JointMap sourceMap = null, JointMap targetMap = null) { var sourceManager = new JOBJManager(); sourceManager.SetJOBJ(source); var sourceInverseWorldTransforms = new List <Matrix4>(); for (int i = 0; i < sourceManager.JointCount; i++) { sourceInverseWorldTransforms.Add(sourceManager.GetWorldTransform(i).Inverted()); } sourceManager.Animation = animation; var targetManager = new JOBJManager(); targetManager.SetJOBJ(target); JointAnimManager newAnim = new JointAnimManager(); newAnim.FrameCount = sourceManager.Animation.FrameCount; var targetWorldTransforms = new List <Matrix4>(); for (int i = 0; i < targetManager.JointCount; i++) { targetWorldTransforms.Add(targetManager.GetWorldTransform(i)); newAnim.Nodes.Add(new AnimNode()); } targetManager.Animation = newAnim; for (int f = 0; f <= sourceManager.Animation.FrameCount; f++) { sourceManager.Frame = f - 1; sourceManager.UpdateNoRender(); targetManager.Frame = f; targetManager.UpdateNoRender(); // bake animation on target skeleton for (int i = 0; i < sourceManager.JointCount; i++) { int targetIndex = i; int sourceIndex = i; // remap bone if joint maps are present if (sourceMap != null && targetMap != null && !string.IsNullOrEmpty(sourceMap[i])) { targetIndex = targetMap.IndexOf(sourceMap[i]); } if (targetIndex == -1) { continue; } int targetParentIndex = targetManager.ParentIndex(targetManager.GetJOBJ(targetIndex)); var inverseSourceWorldRotation = sourceInverseWorldTransforms[sourceIndex]; var sourceAnimatedWorldRotation = sourceManager.GetWorldTransform(sourceIndex); var targetWorldRotation = targetWorldTransforms[targetIndex]; var rel = targetWorldRotation * inverseSourceWorldRotation * sourceAnimatedWorldRotation; if (targetParentIndex != -1) { rel *= targetManager.GetWorldTransform(targetParentIndex).Inverted(); } var rot = Math3D.ToEulerAngles(rel.ExtractRotation().Inverted()); var targetJOBJ = targetManager.GetJOBJ(targetIndex); var sourceJOBJ = sourceManager.GetJOBJ(sourceIndex); sourceManager.Animation.GetAnimatedState(f - 1, sourceIndex, sourceJOBJ, out float TX, out float TY, out float TZ, out float RX, out float RY, out float RZ, out float SX, out float SY, out float SZ); var relTranslate = new Vector3(sourceJOBJ.TX - TX, sourceJOBJ.TY - TY, sourceJOBJ.TZ - TZ); //relTranslate = Vector3.TransformNormal(relTranslate, Matrix4.CreateFromQuaternion(Math3D.FromEulerAngles(sourceJOBJ.RZ, sourceJOBJ.RY, sourceJOBJ.RX).Inverted())); //relTranslate = Vector3.TransformNormal(relTranslate, Matrix4.CreateFromQuaternion(Math3D.FromEulerAngles(targetJOBJ.RZ, targetJOBJ.RY, targetJOBJ.RX))); var relScale = new Vector3(sourceJOBJ.SX - SX, sourceJOBJ.SY - SY, sourceJOBJ.SZ - SZ); //relScale = Vector3.TransformNormal(relScale, inverseSourceWorldRotation); //relScale = Vector3.TransformNormal(relScale, targetWorldRotation); AddKey(targetIndex, f, targetJOBJ.TX - relTranslate.X, JointTrackType.HSD_A_J_TRAX, newAnim); AddKey(targetIndex, f, targetJOBJ.TY - relTranslate.Y, JointTrackType.HSD_A_J_TRAY, newAnim); AddKey(targetIndex, f, targetJOBJ.TZ - relTranslate.Z, JointTrackType.HSD_A_J_TRAZ, newAnim); AddKey(targetIndex, f, rot.X, JointTrackType.HSD_A_J_ROTX, newAnim); AddKey(targetIndex, f, rot.Y, JointTrackType.HSD_A_J_ROTY, newAnim); AddKey(targetIndex, f, rot.Z, JointTrackType.HSD_A_J_ROTZ, newAnim); AddKey(targetIndex, f, targetJOBJ.SX - relScale.X, JointTrackType.HSD_A_J_SCAX, newAnim); AddKey(targetIndex, f, targetJOBJ.SY - relScale.Y, JointTrackType.HSD_A_J_SCAY, newAnim); AddKey(targetIndex, f, targetJOBJ.SZ - relScale.Z, JointTrackType.HSD_A_J_SCAZ, newAnim); targetManager.UpdateNoRender(); } } EulerFilter(newAnim); var targetAnim = newAnim.ToAnimJoint(target, AOBJ_Flags.ANIM_LOOP); AnimationCompressor.AdaptiveCompressAnimation(targetAnim, targetMap); RemoveUnusedTracks(target, targetAnim); newAnim.FromAnimJoint(targetAnim); // apply additional single frame filter check for (int i = 0; i < sourceManager.JointCount; i++) { int targetIndex = i; int sourceIndex = i; // remap bone if joint maps are present if (sourceMap != null && targetMap != null && !string.IsNullOrEmpty(sourceMap[i])) { targetIndex = targetMap.IndexOf(sourceMap[i]); } if (targetIndex == -1) { continue; } var sourceNode = animation.Nodes[sourceIndex]; var targetNode = newAnim.Nodes[targetIndex]; FOBJ_Player sourceXRot = null; FOBJ_Player sourceYRot = null; FOBJ_Player sourceZRot = null; foreach (var t in sourceNode.Tracks) { if (t.JointTrackType == JointTrackType.HSD_A_J_ROTX) { sourceXRot = t; } if (t.JointTrackType == JointTrackType.HSD_A_J_ROTY) { sourceYRot = t; } if (t.JointTrackType == JointTrackType.HSD_A_J_ROTZ) { sourceZRot = t; } } if (sourceXRot != null && sourceYRot != null && sourceZRot != null && sourceXRot.Keys.Count == 1 && sourceYRot.Keys.Count == 1 && sourceZRot.Keys.Count == 1) { foreach (var t in targetNode.Tracks) { if (t.JointTrackType == JointTrackType.HSD_A_J_ROTX || t.JointTrackType == JointTrackType.HSD_A_J_ROTY || t.JointTrackType == JointTrackType.HSD_A_J_ROTZ) { t.Keys.RemoveAll(e => e.Frame > 0); t.Keys[0].InterpolationType = GXInterpolationType.HSD_A_OP_KEY; } } } } return(newAnim); }
/// <summary> /// /// </summary> /// <param name="manager"></param> /// <param name="after_image"></param> public static void RenderAfterImage(JOBJManager manager, float frame, AfterImageDesc after_image) { if (manager.Animation == null) { return; } // process previous keys AfterImageKey[] keys = new AfterImageKey[3]; for (int i = 0; i < keys.Length; i++) { manager.Frame = frame - i; manager.UpdateNoRender(); var bone = manager.GetWorldTransform(after_image.Bone); keys[i] = new AfterImageKey() { pos = bone.ExtractTranslation(), rot = bone.ExtractRotation() }; } // calculate point positions var top = new Vector3(after_image.Top, 0, 0); var bot = new Vector3(after_image.Bottom, 0, 0); Vector3[] points_top = new Vector3[keys.Length]; Vector3[] points_bottom = new Vector3[keys.Length]; for (int i = 0; i < keys.Length; i++) { points_top[i] = keys[i].Transform(top); points_bottom[i] = keys[i].Transform(bot); } float term1 = 1 / (keys[0].pos - keys[1].pos).Length; float term2 = 1 / (keys[1].pos - keys[2].pos).Length; Vector3 tan_bottom = new Vector3( CalculateTangent(term1, term2, points_bottom[0].X, points_bottom[1].X, points_bottom[2].X), CalculateTangent(term1, term2, points_bottom[0].Y, points_bottom[1].Y, points_bottom[2].Y), CalculateTangent(term1, term2, points_bottom[0].Z, points_bottom[1].Z, points_bottom[2].Z)); Vector3 tan_top = new Vector3( CalculateTangent(term1, term2, points_top[0].X, points_top[1].X, points_top[2].X), CalculateTangent(term1, term2, points_top[0].Y, points_top[1].Y, points_top[2].Y), CalculateTangent(term1, term2, points_top[0].Z, points_top[1].Z, points_top[2].Z)); // render sword trail GL.PushAttrib(AttribMask.AllAttribBits); GL.Disable(EnableCap.CullFace); GL.Disable(EnableCap.DepthTest); GL.Enable(EnableCap.Blend); GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); // draw strips interpolated GL.Begin(PrimitiveType.TriangleStrip); int slices = 10; float total_indices = (keys.Length - 1) * slices; float index = total_indices; for (int s = 0; s < keys.Length - 1; s++) { float length = (keys[s].pos - keys[s + 1].pos).Length; for (float i = 0; i < length; i += length / slices) { float alpha = index / total_indices; GL.Color4(after_image.Color1.X, after_image.Color1.Y, after_image.Color1.Z, alpha); GL.Vertex3(Herp(1 / length, i, points_top[s], points_top[s + 1], tan_top)); GL.Color4(after_image.Color2.X, after_image.Color2.Y, after_image.Color2.Z, alpha); GL.Vertex3(Herp(1 / length, i, points_bottom[s], points_bottom[s + 1], tan_bottom)); index--; } tan_bottom *= -1; tan_top *= -1; } /* * GL.Color3(after_image.Color1); * GL.Vertex3(keys[0].Transform(top)); * GL.Color3(after_image.Color2); * GL.Vertex3(keys[0].Transform(bot)); * * GL.Color3(after_image.Color1); * GL.Vertex3(keys[1].Transform(top)); * GL.Color3(after_image.Color2); * GL.Vertex3(keys[1].Transform(bot)); * * GL.Color3(after_image.Color1); * GL.Vertex3(keys[2].Transform(top)); * GL.Color3(after_image.Color2); * GL.Vertex3(keys[2].Transform(bot)); */ GL.End(); GL.PopAttrib(); }
/// <summary> /// /// </summary> /// <param name="manager"></param> /// <param name="after_image"></param> public static void RenderAfterImage(JOBJManager manager, float frame, AfterImageDesc after_image) { if (manager.Animation == null) { return; } // process previous keys AfterImageKey[] keys = new AfterImageKey[3]; for (int i = 0; i < keys.Length; i++) { manager.Frame = frame - i; manager.UpdateNoRender(); var bone = manager.GetWorldTransform(after_image.Bone); keys[i] = new AfterImageKey() { pos = bone.ExtractTranslation(), rot = bone.ExtractRotation() }; } //// render sword trail GL.PushAttrib(AttribMask.AllAttribBits); GL.Disable(EnableCap.CullFace); GL.Disable(EnableCap.DepthTest); GL.Enable(EnableCap.Blend); GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); // draw strips interpolated GL.Begin(PrimitiveType.TriangleStrip); var top = new Vector3(after_image.Top, 0, 0); var bot = new Vector3(after_image.Bottom, 0, 0); int slices = 10; float total_indices = (keys.Length - 1) * slices; float index = total_indices; for (int s = 0; s < keys.Length - 1; s++) { var key1 = keys[s]; var key2 = keys[s + 1]; float length = (keys[s].pos - keys[s + 1].pos).Length; for (float i = 0; i < length; i += length / slices) { float alpha = index / total_indices; index--; float blend = i / length; // lerp angle var rot = Quaternion.Slerp(key1.rot, key2.rot, blend); var pos = Vector3.Lerp(key1.pos, key2.pos, blend); var mat = Matrix4.CreateFromQuaternion(rot) * Matrix4.CreateTranslation(pos); var start_top = Vector3.TransformPosition(top, mat); var start_bot = Vector3.TransformPosition(bot, mat); GL.Color4(after_image.Color1.X, after_image.Color1.Y, after_image.Color1.Z, alpha); GL.Vertex3(start_top); GL.Color4(after_image.Color2.X, after_image.Color2.Y, after_image.Color2.Z, alpha); GL.Vertex3(start_bot); } } GL.End(); GL.PopAttrib(); }
/// <summary> /// /// </summary> /// <param name="cam"></param> /// <param name="windowWidth"></param> /// <param name="windowHeight"></param> public void Draw(Camera cam, int windowWidth, int windowHeight) { // if model not loaded do nothing if (JointManager == null) { return; } // store previous hitbox state info CalculatePreviousState(); // reset model parts if (ModelPartsIndices != null) { for (int i = 0; i < ModelPartsIndices.Length; i++) { ModelPartsIndices[i].AnimIndex = -1; } } // process ftcmd SubactionProcess.SetFrame(viewport.Frame); // update display info JointManager.DOBJManager.OverlayColor = SubactionProcess.OverlayColor; JointManager._settings.RenderBones = bonesToolStripMenuItem.Checked; // apply model animations JointManager.Frame = viewport.Frame; JointManager.UpdateNoRender(); // character invisibility if (!SubactionProcess.CharacterInvisibility && modelToolStripMenuItem.Checked) { JointManager.Render(cam, false); } // hurtbox collision if (hurtboxesToolStripMenuItem.Checked) { HurtboxRenderer.Render(JointManager, Hurtboxes, null, SubactionProcess.BoneCollisionStates, SubactionProcess.BodyCollisionState); } // hitbox collision int hitboxId = 0; bool isHitboxSelected = false; foreach (var hb in SubactionProcess.Hitboxes) { if (!hb.Active) { hitboxId++; continue; } float alpha = 0.4f; Vector3 hbColor = HitboxColor; var worldPosition = hb.GetWorldPosition(JointManager); var worldTransform = Matrix4.CreateTranslation(worldPosition); if (hb.Element == 8) { hbColor = GrabboxColor; } if (subActionList.SelectedIndices.Count == 1 && hb.CommandIndex == subActionList.SelectedIndex) { hbColor = HitboxSelectedColor; isHitboxSelected = true; _transWidget.Transform = hb.GetWorldTransform(JointManager); } // drawing a capsule takes more processing power, so only draw it if necessary if (hb.Interpolate && interpolationToolStripMenuItem.Checked) { capsule.SetParameters(worldPosition, PreviousPositions[hitboxId], hb.Size); capsule.Draw(Matrix4.Identity, new Vector4(hbColor, alpha)); } else { DrawShape.DrawSphere(worldTransform, hb.Size, 16, 16, hbColor, alpha); } // draw hitbox angle if (hitboxInfoToolStripMenuItem.Checked) { if (hb.Angle != 361) { DrawShape.DrawAngleLine(cam, worldTransform, hb.Size, MathHelper.DegreesToRadians(hb.Angle)); } else { DrawShape.DrawSakuraiAngle(cam, worldTransform, hb.Size); } GLTextRenderer.RenderText(cam, hitboxId.ToString(), worldTransform, StringAlignment.Center, true); } hitboxId++; } // draw shield during guard animation if (DisplayShieldSize > 0) { DrawShape.DrawSphere(JointManager.GetWorldTransform(JointManager.JointCount - 2), DisplayShieldSize, 16, 16, ShieldColor, 0.5f); } // gfx spawn indicator foreach (var gfx in SubactionProcess.GFXOnFrame) { var boneID = gfx.Bone; if (boneID == 0) { if (JointManager.GetJOBJ(1) != null && JointManager.GetJOBJ(1).Child == null) // special case for character like mewtwo with a leading bone { boneID = 2; } else { boneID = 1; } } var transform = Matrix4.CreateTranslation(gfx.Position) * JointManager.GetWorldTransform(boneID); transform = transform.ClearScale(); DrawShape.DrawSphere(transform, 1f, 16, 16, ThrowDummyColor, 0.5f); } // environment collision if (ECB != null) { var topN = JointManager.GetWorldTransform(1).ExtractTranslation(); var bone1 = Vector3.TransformPosition(Vector3.Zero, JointManager.GetWorldTransform(ECB.ECBBone1)); var bone2 = Vector3.TransformPosition(Vector3.Zero, JointManager.GetWorldTransform(ECB.ECBBone2)); var bone3 = Vector3.TransformPosition(Vector3.Zero, JointManager.GetWorldTransform(ECB.ECBBone3)); var bone4 = Vector3.TransformPosition(Vector3.Zero, JointManager.GetWorldTransform(ECB.ECBBone4)); var bone5 = Vector3.TransformPosition(Vector3.Zero, JointManager.GetWorldTransform(ECB.ECBBone5)); var bone6 = Vector3.TransformPosition(Vector3.Zero, JointManager.GetWorldTransform(ECB.ECBBone6)); var minx = float.MaxValue; var miny = float.MaxValue; var maxx = float.MinValue; var maxy = float.MinValue; foreach (var p in new Vector3[] { bone1, bone2, bone3, bone4, bone5, bone6 }) { minx = Math.Min(minx, p.Z); maxx = Math.Max(maxx, p.Z); miny = Math.Min(miny, p.Y); maxy = Math.Max(maxy, p.Y); } // ecb diamond if (eCBToolStripMenuItem.Checked) { DrawShape.DrawECB(topN, minx, miny, maxx, maxy, groundECH.Checked); } // ledge grav if (ledgeGrabBoxToolStripMenuItem.Checked) { var correct = Math.Abs(minx - maxx) / 2; //behind DrawShape.DrawLedgeBox( topN.Z, topN.Y + ECB.VerticalOffsetFromTop - ECB.VerticalScale / 2, topN.Z - (correct + ECB.HorizontalScale), topN.Y + ECB.VerticalOffsetFromTop + ECB.VerticalScale / 2, Color.Red); // in front DrawShape.DrawLedgeBox( topN.Z, topN.Y + ECB.VerticalOffsetFromTop - ECB.VerticalScale / 2, topN.Z + correct + ECB.HorizontalScale, topN.Y + ECB.VerticalOffsetFromTop + ECB.VerticalScale / 2, Color.Blue); } } // throw dummy if (ThrowDummyManager.Animation.NodeCount != 0 && throwModelToolStripMenuItem.Checked && !SubactionProcess.ThrownFighter && ThrowDummyManager.JointCount > 0) { if (viewport.Frame < ThrowDummyManager.Animation.FrameCount) { ThrowDummyManager.Frame = viewport.Frame; } ThrowDummyManager.SetWorldTransform(4, JointManager.GetWorldTransform(JointManager.JointCount - 2)); ThrowDummyManager.Render(cam, false); if (ThrowDummyLookupTable.Count == 0) { DrawShape.DrawSphere(ThrowDummyManager.GetWorldTransform(35), 1.5f, 16, 16, ThrowDummyColor, 0.5f); DrawShape.DrawSphere(ThrowDummyManager.GetWorldTransform(4), 1.5f, 16, 16, ThrowDummyColor, 0.5f); DrawShape.DrawSphere(ThrowDummyManager.GetWorldTransform(10), 1f, 16, 16, ThrowDummyColor, 0.5f); DrawShape.DrawSphere(ThrowDummyManager.GetWorldTransform(15), 1f, 16, 16, ThrowDummyColor, 0.5f); DrawShape.DrawSphere(ThrowDummyManager.GetWorldTransform(22), 1f, 16, 16, ThrowDummyColor, 0.5f); DrawShape.DrawSphere(ThrowDummyManager.GetWorldTransform(40), 1f, 16, 16, ThrowDummyColor, 0.5f); } } if (isHitboxSelected) { _transWidget.Render(cam); } // sword trail //AfterImageRenderer.RenderAfterImage(JointManager, viewport.Frame, after_desc); }