/// <summary> /// /// </summary> private void RecursiveExport(HSD_JOBJ jobj, Node parent, Matrix4 parentTransform, Dictionary <int, string> indexToName) { Node root = new Node(); root.Name = "JOBJ_" + Jobjs.Count; if (indexToName.ContainsKey(Jobjs.Count)) { root.Name = indexToName[Jobjs.Count]; } else if (!string.IsNullOrEmpty(jobj.ClassName)) { root.Name = jobj.ClassName; } jobjToIndex.Add(jobj, Jobjs.Count); Matrix4 Transform = Matrix4.CreateScale(jobj.SX, jobj.SY, jobj.SZ) * Matrix4.CreateFromQuaternion(Math3D.FromEulerAngles(jobj.RZ, jobj.RY, jobj.RX)) * Matrix4.CreateTranslation(jobj.TX, jobj.TY, jobj.TZ); var worldTransform = Transform * parentTransform; JobjNodes.Add(root); Jobjs.Add(jobj); WorldTransforms.Add(worldTransform); root.Transform = Matrix4ToMatrix4x4(Transform); parent.Children.Add(root); foreach (var c in jobj.Children) { RecursiveExport(c, root, worldTransform, indexToName); } }
/// <summary> /// /// </summary> /// <param name="cache"></param> /// <param name="newWorldMatrices"></param> /// <param name="root"></param> /// <param name="parentTransform"></param> private static void ZeroOutRotations(Dictionary <HSD_JOBJ, Matrix4> newTransforms, HSD_JOBJ root, Matrix4 oldParent, Matrix4 parentTransform) { var oldTransform = Matrix4.CreateScale(root.SX, root.SY, root.SZ) * Matrix4.CreateFromQuaternion(Math3D.FromEulerAngles(root.RZ, root.RY, root.RX)) * Matrix4.CreateTranslation(root.TX, root.TY, root.TZ) * oldParent; var targetPoint = Vector3.TransformPosition(Vector3.Zero, oldTransform); var trimName = root.ClassName; if (trimName != null && FighterDefaults.ContainsKey(trimName)) { root.TX = 0; root.TY = 0; root.TZ = 0; root.RX = FighterDefaults[trimName].X; root.RY = FighterDefaults[trimName].Y; root.RZ = FighterDefaults[trimName].Z; } else { root.TX = 0; root.TY = 0; root.TZ = 0; root.RX = 0; root.RY = 0; root.RZ = 0; } Matrix4 currentTransform = Matrix4.CreateScale(root.SX, root.SY, root.SZ) * Matrix4.CreateFromQuaternion(Math3D.FromEulerAngles(root.RZ, root.RY, root.RX)) * parentTransform; var relPoint = Vector3.TransformPosition(targetPoint, parentTransform.Inverted()); root.TX = relPoint.X; root.TY = relPoint.Y; root.TZ = relPoint.Z; if (trimName != null && trimName.Equals("TransN")) // special case { root.TX = 0; root.TY = 0; root.TZ = 0; } var newTransform = Matrix4.CreateScale(root.SX, root.SY, root.SZ) * Matrix4.CreateFromQuaternion(Math3D.FromEulerAngles(root.RZ, root.RY, root.RX)) * Matrix4.CreateTranslation(root.TX, root.TY, root.TZ) * parentTransform; newTransforms.Add(root, newTransform); foreach (var c in root.Children) { ZeroOutRotations(newTransforms, c, oldTransform, newTransform); } }
/// <summary> /// /// </summary> /// <param name="jobj"></param> public static void CleanRootNode(this HSD_JOBJ jobj) { var joints = jobj.BreathFirstList; Matrix4 rot = Matrix4.Identity;; for (int i = 0; i < joints.Count; i++) { var j = joints[i]; if (i == 0) { rot = Matrix4.CreateFromQuaternion(Math3D.FromEulerAngles(j.RZ, j.RY, j.RX)); j.RX = 0; j.RY = 0; j.RZ = 0; } else { // fix position var pos = Vector3.TransformNormal(new Vector3(j.TX, j.TY, j.TZ), rot); j.TX = pos.X; j.TY = pos.Y; j.TZ = pos.Z; } // clean scale j.SX = 1; j.SY = 1; j.SZ = 1; } }
/// <summary> /// /// </summary> /// <param name="mobj"></param> public void BindMOBJ(Shader shader, HSD_MOBJ mobj, HSD_JOBJ parentJOBJ, MatAnimManager animation) { if (mobj == null) { return; } GL.Enable(EnableCap.Texture2D); GL.Enable(EnableCap.Blend); GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); GL.Enable(EnableCap.AlphaTest); GL.AlphaFunc(AlphaFunction.Greater, 0f); GL.DepthMask(!mobj.RenderFlags.HasFlag(RENDER_MODE.NO_ZUPDATE)); // Pixel Processing shader.SetInt("alphaOp", -1); // none shader.SetInt("alphaComp0", 7); // always shader.SetInt("alphaComp1", 7); // Materials var color = mobj.Material; if (color != null) { MaterialState.Ambient.X = color.AMB_R / 255f; MaterialState.Ambient.Y = color.AMB_G / 255f; MaterialState.Ambient.Z = color.AMB_B / 255f; MaterialState.Ambient.W = color.AMB_A / 255f; MaterialState.Diffuse.X = color.DIF_R / 255f; MaterialState.Diffuse.Y = color.DIF_G / 255f; MaterialState.Diffuse.Z = color.DIF_B / 255f; MaterialState.Diffuse.W = color.DIF_A / 255f; MaterialState.Specular.X = color.SPC_R / 255f; MaterialState.Specular.Y = color.SPC_G / 255f; MaterialState.Specular.Z = color.SPC_B / 255f; MaterialState.Specular.W = color.SPC_A / 255f; MaterialState.Shininess = color.Shininess; MaterialState.Alpha = color.Alpha; if (animation != null) { animation.GetMaterialState(mobj, ref MaterialState); } shader.SetVector4("ambientColor", MaterialState.Ambient); shader.SetVector4("diffuseColor", MaterialState.Diffuse); shader.SetVector4("specularColor", MaterialState.Specular); shader.SetFloat("shinniness", MaterialState.Shininess); shader.SetFloat("alpha", MaterialState.Alpha); } var pp = mobj.PEDesc; if (pp != null) { MaterialState.Ref0 = pp.AlphaRef0 / 255f; MaterialState.Ref1 = pp.AlphaRef1 / 255f; if (animation != null) { animation.GetMaterialState(mobj, ref MaterialState); } GL.BlendFunc(GXTranslator.toBlendingFactor(pp.SrcFactor), GXTranslator.toBlendingFactor(pp.DstFactor)); GL.DepthFunc(GXTranslator.toDepthFunction(pp.DepthFunction)); shader.SetInt("alphaOp", (int)pp.AlphaOp); shader.SetInt("alphaComp0", (int)pp.AlphaComp0); shader.SetInt("alphaComp1", (int)pp.AlphaComp1); shader.SetFloat("alphaRef0", MaterialState.Ref0); shader.SetFloat("alphaRef1", MaterialState.Ref1); } var enableAll = mobj.RenderFlags.HasFlag(RENDER_MODE.DF_ALL); shader.SetBoolToInt("no_zupdate", mobj.RenderFlags.HasFlag(RENDER_MODE.NO_ZUPDATE)); shader.SetBoolToInt("enableSpecular", parentJOBJ.Flags.HasFlag(JOBJ_FLAG.SPECULAR) && mobj.RenderFlags.HasFlag(RENDER_MODE.SPECULAR)); shader.SetBoolToInt("enableDiffuse", parentJOBJ.Flags.HasFlag(JOBJ_FLAG.LIGHTING) && mobj.RenderFlags.HasFlag(RENDER_MODE.DIFFUSE)); shader.SetBoolToInt("useConstant", mobj.RenderFlags.HasFlag(RENDER_MODE.CONSTANT)); shader.SetBoolToInt("useVertexColor", mobj.RenderFlags.HasFlag(RENDER_MODE.VERTEX)); shader.SetBoolToInt("useToonShading", mobj.RenderFlags.HasFlag(RENDER_MODE.TOON)); // Textures for (int i = 0; i < MAX_TEX; i++) { shader.SetBoolToInt($"hasTEX[{i}]", mobj.RenderFlags.HasFlag(RENDER_MODE.TEX0 + (i << 4)) || enableAll); } shader.SetInt("BumpTexture", -1); //LoadTextureConstants(shader); // Bind Textures if (mobj.Textures != null) { var textures = mobj.Textures.List; for (int i = 0; i < textures.Count; i++) { if (i > MAX_TEX) { break; } var tex = textures[i]; var displayTex = tex; if (tex.ImageData == null) { continue; } var blending = tex.Blending; var transform = Matrix4.CreateScale(tex.SX, tex.SY, tex.SZ) * Matrix4.CreateFromQuaternion(Math3D.FromEulerAngles(tex.RZ, tex.RY, tex.RX)) * Matrix4.CreateTranslation(tex.TX, tex.TY, tex.TZ); if (tex.SY != 0 && tex.SX != 0 && tex.SZ != 0) { transform.Invert(); } if (animation != null) { var state = animation.GetTextureAnimState(tex); if (state != null) { displayTex = state.TOBJ; blending = state.Blending; transform = state.Transform; } } // make sure texture is loaded PreLoadTexture(displayTex); // grab texture id var texid = TextureManager.Get(imageBufferTextureIndex[displayTex.ImageData.ImageData]); // set texture GL.ActiveTexture(TextureUnit.Texture0 + i); GL.BindTexture(TextureTarget.Texture2D, texid); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)GXTranslator.toWrapMode(tex.WrapS)); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)GXTranslator.toWrapMode(tex.WrapT)); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)GXTranslator.toMagFilter(tex.MagFilter)); var wscale = tex.WScale; var hscale = tex.HScale; var mirrorX = tex.WrapS == GXWrapMode.MIRROR; var mirrorY = tex.WrapT == GXWrapMode.MIRROR; var flags = tex.Flags; int coordType = (int)flags & 0xF; int colorOP = ((int)flags >> 16) & 0xF; int alphaOP = ((int)flags >> 20) & 0xF; if (flags.HasFlag(TOBJ_FLAGS.BUMP)) { colorOP = 4; } shader.SetInt($"sampler{i}", i); shader.SetInt($"TEX[{i}].gensrc", (int)tex.GXTexGenSrc); shader.SetBoolToInt($"TEX[{i}].is_ambient", flags.HasFlag(TOBJ_FLAGS.LIGHTMAP_AMBIENT)); shader.SetBoolToInt($"TEX[{i}].is_diffuse", flags.HasFlag(TOBJ_FLAGS.LIGHTMAP_DIFFUSE)); shader.SetBoolToInt($"TEX[{i}].is_specular", flags.HasFlag(TOBJ_FLAGS.LIGHTMAP_SPECULAR)); shader.SetBoolToInt($"TEX[{i}].is_ext", flags.HasFlag(TOBJ_FLAGS.LIGHTMAP_EXT)); shader.SetBoolToInt($"TEX[{i}].is_bump", flags.HasFlag(TOBJ_FLAGS.BUMP)); shader.SetInt($"TEX[{i}].color_operation", colorOP); shader.SetInt($"TEX[{i}].alpha_operation", alphaOP); shader.SetInt($"TEX[{i}].coord_type", coordType); shader.SetFloat($"TEX[{i}].blend", blending); shader.SetBoolToInt($"TEX[{i}].mirror_fix", mirrorY); shader.SetVector2($"TEX[{i}].uv_scale", wscale, hscale); shader.SetMatrix4x4($"TEX[{i}].transform", ref transform); var tev = tex.TEV; bool useTev = tev != null && tev.active.HasFlag(TOBJ_TEVREG_ACTIVE.COLOR_TEV); shader.SetBoolToInt($"hasTev[{i}]", useTev); if (useTev) { shader.SetInt($"Tev[{i}].color_op", (int)tev.color_op); shader.SetInt($"Tev[{i}].color_bias", (int)tev.color_bias); shader.SetInt($"Tev[{i}].color_scale", (int)tev.color_scale); shader.SetBoolToInt($"Tev[{i}].color_clamp", tev.color_clamp); shader.SetInt($"Tev[{i}].color_a", (int)tev.color_a_in); shader.SetInt($"Tev[{i}].color_b", (int)tev.color_b_in); shader.SetInt($"Tev[{i}].color_c", (int)tev.color_c_in); shader.SetInt($"Tev[{i}].color_d", (int)tev.color_d_in); shader.SetInt($"Tev[{i}].alpha_op", (int)tev.alpha_op); shader.SetInt($"Tev[{i}].alpha_bias", (int)tev.alpha_bias); shader.SetInt($"Tev[{i}].alpha_scale", (int)tev.alpha_scale); shader.SetBoolToInt($"Tev[{i}].alpha_clamp", tev.alpha_clamp); shader.SetInt($"Tev[{i}].alpha_a", (int)tev.alpha_a_in); shader.SetInt($"Tev[{i}].alpha_b", (int)tev.alpha_b_in); shader.SetInt($"Tev[{i}].alpha_c", (int)tev.alpha_c_in); shader.SetInt($"Tev[{i}].alpha_d", (int)tev.alpha_d_in); shader.SetColor($"Tev[{i}].konst", tev.constant, tev.constantAlpha); shader.SetColor($"Tev[{i}].tev0", tev.tev0, tev.tev0Alpha); shader.SetColor($"Tev[{i}].tev1", tev.tev1, tev.tev1Alpha); } } } }
/// <summary> /// /// </summary> /// <param name="cam"></param> /// <param name="frame"></param> public void Render(Camera cam, float frame) { if (frame == -1 && entryAnimation.Count > 0) { entryAnimation.Clear(); } if (frame == 0) { entryAnimation.Clear(); // Load Animation foreach (var i in Icons) { if (i.AnimJoint == null) { continue; } var a = new JointAnimManager(); a.FromAnimJoint(i.AnimJoint); entryAnimation.Add(i, a); } } for (int i = 0; i < Icons.Length; i++) { var ico = Icons[i]; if (ico.Joint == null) { continue; } var transform = Matrix4.Identity; if (entryAnimation.ContainsKey(ico)) { transform = entryAnimation[ico].GetAnimatedMatrix(frame, 0, ico.Joint); } else { transform = Matrix4.CreateScale(ico.Joint.SX, ico.Joint.SY, ico.Joint.SZ) * Matrix4.CreateFromQuaternion(Math3D.FromEulerAngles(ico.Joint.RZ, ico.Joint.RY, ico.Joint.RX)) * Matrix4.CreateTranslation(ico.Joint.TX, ico.Joint.TY, ico.Joint.TZ); } if (IconJOBJManager.JointCount > 0) { IconJOBJManager.SetWorldTransform(0, transform); ico.IconTOBJ.Flags = TOBJ_FLAGS.LIGHTMAP_DIFFUSE | TOBJ_FLAGS.COLORMAP_MODULATE | TOBJ_FLAGS.ALPHAMAP_MODULATE; IconJOBJManager.GetJOBJ(0).Child.Dobj.Next.Mobj.Textures = ico.IconTOBJ; IconJOBJManager.Render(cam, false); } if (sssEditor.SelectedIndices.Contains(i)) { if (sssEditor.SelectedIndices.Count == 1 && StageNameJOBJManager.JointCount > 0) { ico.NameTOBJ.Flags = TOBJ_FLAGS.LIGHTMAP_DIFFUSE | TOBJ_FLAGS.COLORMAP_MODULATE | TOBJ_FLAGS.ALPHAMAP_MODULATE; StageNameJOBJManager.GetJOBJ(0).Child.Child.Dobj.Mobj.Textures = ico.NameTOBJ; } var rect = ico.ToRectangle(); DrawShape.DrawRectangle(rect.X, rect.Y, rect.X + rect.Width, rect.Y + rect.Height, ico.Joint.TZ, 2, MEX_CSSIconEntry.SelectedIconColor); if (Dragging) { DrawShape.Line(new Vector3(-100, rect.Y, 0), new Vector3(100, rect.Y, 0), SnapColor, 1); DrawShape.Line(new Vector3(rect.X, -100, 0), new Vector3(rect.X, 100, 0), SnapColor, 1); DrawShape.Line(new Vector3(-100, rect.Y + rect.Height, 0), new Vector3(100, rect.Y + rect.Height, 0), SnapColor, 1); DrawShape.Line(new Vector3(rect.X + rect.Width, -100, 0), new Vector3(rect.X + rect.Width, 100, 0), SnapColor, 1); } } } StageNameJOBJManager.Render(cam); }
/// <summary> /// /// </summary> /// <param name="cache"></param> /// <param name="newWorldMatrices"></param> /// <param name="root"></param> /// <param name="parentTransform"></param> private static void ZeroOutRotations(ProcessingCache cache, Dictionary <HSD_JOBJ, Matrix4> newWorldMatrices, HSD_JOBJ root, Matrix4 oldParent, Matrix4 parentTransform) { var targetPoint = Vector3.TransformPosition(Vector3.Zero, cache.jobjToWorldTransform[root]); //targetPoint -= Vector3.TransformPosition(Vector3.Zero, oldParent); var trimName = root.ClassName.Replace("Armature_", ""); if (FighterDefaults.ContainsKey(trimName)) { root.TX = 0; root.TY = 0; root.TZ = 0; root.RX = FighterDefaults[trimName].X; root.RY = FighterDefaults[trimName].Y; root.RZ = FighterDefaults[trimName].Z; root.SX = 1; root.SY = 1; root.SZ = 1; } else { root.TX = 0; root.TY = 0; root.TZ = 0; root.RX = 0; root.RY = 0; root.RZ = 0; root.SX = 1; root.SY = 1; root.SZ = 1; } Matrix4 currentTransform = Matrix4.CreateScale(root.SX, root.SY, root.SZ) * Matrix4.CreateFromQuaternion(Math3D.FromEulerAngles(root.RZ, root.RY, root.RX)) * parentTransform; var relPoint = Vector3.TransformPosition(targetPoint, parentTransform.Inverted()); root.TX = relPoint.X; root.TY = relPoint.Y; root.TZ = relPoint.Z; if (trimName.Equals("TransN")) // special case { root.TX = 0; root.TY = 0; root.TZ = 0; } var finalTransform = Matrix4.CreateScale(root.SX, root.SY, root.SZ) * Matrix4.CreateFromQuaternion(Math3D.FromEulerAngles(root.RZ, root.RY, root.RX)) * Matrix4.CreateTranslation(root.TX, root.TY, root.TZ) * parentTransform; newWorldMatrices.Add(root, finalTransform); foreach (var c in root.Children) { ZeroOutRotations(cache, newWorldMatrices, c, cache.jobjToWorldTransform[root], finalTransform); } }