using SharpDX; using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; namespace CodeWalker.GameFiles { [TypeConverter(typeof(ExpandableObjectConverter))] public class ShaderGroup : ResourceSystemBlock { public override long BlockLength { get { return 64; } } // structure data public uint VFT { get; set; } public uint Unknown_4h { get; set; } // 0x00000001 public ulong TextureDictionaryPointer { get; set; } public ulong ShadersPointer { get; set; } public ushort ShadersCount1 { get; set; } public ushort ShadersCount2 { get; set; } public uint Unknown_1Ch { get; set; } // 0x00000000 public uint Unknown_20h { get; set; } // 0x00000000 public uint Unknown_24h { get; set; } // 0x00000000 public uint Unknown_28h { get; set; } // 0x00000000 public uint Unknown_2Ch { get; set; } // 0x00000000 public uint Unknown_30h { get; set; } public uint Unknown_34h { get; set; } // 0x00000000 public uint Unknown_38h { get; set; } // 0x00000000 public uint Unknown_3Ch { get; set; } // 0x00000000 // reference data public TextureDictionary TextureDictionary { get; set; } public ResourcePointerArray64 Shaders { get; set; } /// /// Reads the data-block from a stream. /// public override void Read(ResourceDataReader reader, params object[] parameters) { // read structure data this.VFT = reader.ReadUInt32(); this.Unknown_4h = reader.ReadUInt32(); this.TextureDictionaryPointer = reader.ReadUInt64(); this.ShadersPointer = reader.ReadUInt64(); this.ShadersCount1 = reader.ReadUInt16(); this.ShadersCount2 = reader.ReadUInt16(); this.Unknown_1Ch = reader.ReadUInt32(); this.Unknown_20h = reader.ReadUInt32(); this.Unknown_24h = reader.ReadUInt32(); this.Unknown_28h = reader.ReadUInt32(); this.Unknown_2Ch = reader.ReadUInt32(); this.Unknown_30h = reader.ReadUInt32(); this.Unknown_34h = reader.ReadUInt32(); this.Unknown_38h = reader.ReadUInt32(); this.Unknown_3Ch = reader.ReadUInt32(); // read reference data this.TextureDictionary = reader.ReadBlockAt( this.TextureDictionaryPointer // offset ); this.Shaders = reader.ReadBlockAt>( this.ShadersPointer, // offset this.ShadersCount1 ); } /// /// Writes the data-block to a stream. /// public override void Write(ResourceDataWriter writer, params object[] parameters) { // update structure data this.TextureDictionaryPointer = (ulong)(this.TextureDictionary != null ? this.TextureDictionary.FilePosition : 0); this.ShadersPointer = (ulong)(this.Shaders != null ? this.Shaders.FilePosition : 0); this.ShadersCount1 = (ushort)(this.Shaders != null ? this.Shaders.Count : 0); this.ShadersCount2 = this.ShadersCount1; // write structure data writer.Write(this.VFT); writer.Write(this.Unknown_4h); writer.Write(this.TextureDictionaryPointer); writer.Write(this.ShadersPointer); writer.Write(this.ShadersCount1); writer.Write(this.ShadersCount2); writer.Write(this.Unknown_1Ch); writer.Write(this.Unknown_20h); writer.Write(this.Unknown_24h); writer.Write(this.Unknown_28h); writer.Write(this.Unknown_2Ch); writer.Write(this.Unknown_30h); writer.Write(this.Unknown_34h); writer.Write(this.Unknown_38h); writer.Write(this.Unknown_3Ch); } /// /// Returns a list of data blocks which are referenced by this block. /// public override IResourceBlock[] GetReferences() { var list = new List(); if (TextureDictionary != null) list.Add(TextureDictionary); if (Shaders != null) list.Add(Shaders); return list.ToArray(); } } [TypeConverter(typeof(ExpandableObjectConverter))] public class ShaderFX : ResourceSystemBlock { public override long BlockLength { get { return 48; } } // structure data public ulong ParametersPointer { get; set; } public MetaHash Name { get; set; } //decal_emissive_only, emissive, spec public uint Unknown_Ch { get; set; } // 0x00000000 public byte ParameterCount { get; set; } public byte RenderBucket { get; set; } // 2, 0, public ushort Unknown_12h { get; set; } // 32768 HasComment? public ushort ParameterSize { get; set; } //112, 208, 320 (with 16h) 10485872, 17826000, 26214720 public ushort ParameterDataSize { get; set; } //160, 272, 400 public MetaHash FileName { get; set; } //decal_emissive_only.sps, emissive.sps, spec.sps public uint Unknown_1Ch { get; set; } // 0x00000000 public uint RenderBucketMask { get; set; } //65284, 65281 DrawBucketMask? (1< Parameters { get; set; } //public SimpleArrayOFFSET ParameterHashes { get; set; } public ShaderParametersBlock ParametersList { get; set; } /// /// Reads the data-block from a stream. /// public override void Read(ResourceDataReader reader, params object[] parameters) { // read structure data this.ParametersPointer = reader.ReadUInt64(); this.Name = new MetaHash(reader.ReadUInt32()); this.Unknown_Ch = reader.ReadUInt32(); this.ParameterCount = reader.ReadByte(); this.RenderBucket = reader.ReadByte(); this.Unknown_12h = reader.ReadUInt16(); this.ParameterSize = reader.ReadUInt16(); this.ParameterDataSize = reader.ReadUInt16(); this.FileName = new MetaHash(reader.ReadUInt32()); this.Unknown_1Ch = reader.ReadUInt32(); this.RenderBucketMask = reader.ReadUInt32(); this.Unknown_24h = reader.ReadUInt16(); this.Unknown_26h = reader.ReadByte(); this.TextureParametersCount = reader.ReadByte(); this.Unknown_28h = reader.ReadUInt32(); this.Unknown_2Ch = reader.ReadUInt32(); // read reference data this.ParametersList = reader.ReadBlockAt( this.ParametersPointer, // offset this.ParameterCount ); } /// /// Writes the data-block to a stream. /// public override void Write(ResourceDataWriter writer, params object[] parameters) { // update structure data this.ParametersPointer = (ulong)(this.ParametersList != null ? this.ParametersList.FilePosition : 0); this.ParameterCount = (byte)(this.ParametersList != null ? this.ParametersList.Count : 0); // write structure data writer.Write(this.ParametersPointer); writer.Write(this.Name.Hash); writer.Write(this.Unknown_Ch); writer.Write(this.ParameterCount); writer.Write(this.RenderBucket); writer.Write(this.Unknown_12h); writer.Write(this.ParameterSize); writer.Write(this.ParameterDataSize); writer.Write(this.FileName.Hash); writer.Write(this.Unknown_1Ch); writer.Write(this.RenderBucketMask); writer.Write(this.Unknown_24h); writer.Write(this.Unknown_26h); writer.Write(this.TextureParametersCount); writer.Write(this.Unknown_28h); writer.Write(this.Unknown_2Ch); } /// /// Returns a list of data blocks which are referenced by this block. /// public override IResourceBlock[] GetReferences() { var list = new List(); if (ParametersList != null) list.Add(ParametersList); return list.ToArray(); } public override string ToString() { return Name.ToString() + " (" + FileName.ToString() + ")"; } } [TypeConverter(typeof(ExpandableObjectConverter))] public class ShaderParameter : ResourceSystemBlock { public override long BlockLength { get { return 16; } } // structure data public byte DataType { get; set; } public byte Unknown_1h { get; set; } public ushort Unknown_2h { get; set; } public uint Unknown_4h { get; set; } public ulong DataPointer { get; set; } //public IResourceBlock Data { get; set; } public object Data { get; set; } /// /// Reads the data-block from a stream. /// public override void Read(ResourceDataReader reader, params object[] parameters) { // read structure data this.DataType = reader.ReadByte(); this.Unknown_1h = reader.ReadByte(); this.Unknown_2h = reader.ReadUInt16(); this.Unknown_4h = reader.ReadUInt32(); this.DataPointer = reader.ReadUInt64(); // DONT READ DATA... } /// /// Writes the data-block to a stream. /// public override void Write(ResourceDataWriter writer, params object[] parameters) { // write structure data writer.Write(this.DataType); writer.Write(this.Unknown_1h); writer.Write(this.Unknown_2h); writer.Write(this.Unknown_4h); writer.Write(this.DataPointer); // DONT WRITE DATA } /// /// Returns a list of data blocks which are referenced by this block. /// public override IResourceBlock[] GetReferences() { var list = new List(base.GetReferences()); //if (Data != null) list.Add(Data); return list.ToArray(); } public override string ToString() { return (Data != null) ? Data.ToString() : (DataType.ToString() + ": " + DataPointer.ToString()); } } [TypeConverter(typeof(ExpandableObjectConverter))] public class ShaderParametersBlock : ResourceSystemBlock { public override long BlockLength { get { long offset = 0; foreach (var x in Parameters) { offset += 16; } foreach (var x in Parameters) { offset += 16 * x.DataType; } offset += Parameters.Length * 4; return offset; } } public ushort ParametersSize { get { ushort size = (ushort)((Parameters?.Length??0) * 16); foreach (var x in Parameters) { size += (ushort)(16 * x.DataType); } return size; } } public byte TextureParamsCount { get { byte c = 0; foreach (var x in Parameters) { if (x.DataType == 0) c++; } return c; } } public ShaderParameter[] Parameters { get; set; } public MetaName[] Hashes { get; set; } public int Count { get; set; } private ResourceSystemStructBlock[] ParameterDataBlocks = null; public override void Read(ResourceDataReader reader, params object[] parameters) { Count = Convert.ToInt32(parameters[0]); var paras = new List(); for (int i = 0; i < Count; i++) { paras.Add(reader.ReadBlock()); } int offset = 0; for (int i = 0; i < Count; i++) { var p = paras[i]; // read reference data switch (p.DataType) { case 0: offset += 0; p.Data = reader.ReadBlockAt(p.DataPointer); break; case 1: offset += 16; p.Data = reader.ReadStructAt((long)p.DataPointer); break; default: offset += 16 * p.DataType; p.Data = reader.ReadStructsAt(p.DataPointer, p.DataType); break; } } reader.Position += offset; //Vector4 data gets embedded here... but why pointers in params also??? var hashes = new List(); for (int i = 0; i < Count; i++) { hashes.Add((MetaName)reader.ReadUInt32()); } Parameters = paras.ToArray(); Hashes = hashes.ToArray(); } public override void Write(ResourceDataWriter writer, params object[] parameters) { // update pointers... //foreach (var f in Parameters) // if (f.Data != null) // f.DataPointer = (ulong)f.Data.Position; // else // f.DataPointer = 0; for (int i = 0; i < Parameters.Length; i++) { var param = Parameters[i]; if (param.DataType == 0) { param.DataPointer = (ulong)((param.Data as TextureBase)?.FilePosition ?? 0); } else { var block = (i < ParameterDataBlocks?.Length) ? ParameterDataBlocks[i] : null; if (block != null) { param.DataPointer = (ulong)block.FilePosition; } else { param.DataPointer = 0;//shouldn't happen! } } } // write parameter infos foreach (var f in Parameters) writer.WriteBlock(f); // write vector data //foreach (var f in Parameters) //{ // if (f.DataType != 0) // writer.WriteBlock(f.Data); //} for (int i = 0; i < Parameters.Length; i++) { var param = Parameters[i]; if (param.DataType != 0) { var block = (i < ParameterDataBlocks?.Length) ? ParameterDataBlocks[i] : null; if (block != null) { writer.WriteBlock(block); } else { } //shouldn't happen! } } // write hashes foreach (var h in Hashes) writer.Write((uint)h); } public override IResourceBlock[] GetReferences() { var list = new List(); list.AddRange(base.GetReferences()); foreach (var x in Parameters) if (x.DataType == 0) list.Add(x.Data as TextureBase); return list.ToArray(); } public override Tuple[] GetParts() { var list = new List>(); list.AddRange(base.GetParts()); long offset = 0; foreach (var x in Parameters) { list.Add(new Tuple(offset, x)); offset += 16; } var blist = new List>(); foreach (var x in Parameters) { if (x.DataType != 0) { var vecs = x.Data as Vector4[]; if (vecs == null) { vecs = new[] { (Vector4)x.Data }; } if (vecs == null) { } var block = new ResourceSystemStructBlock(vecs); list.Add(new Tuple(offset, block)); blist.Add(block); } else { blist.Add(null); } offset += 16 * x.DataType; } ParameterDataBlocks = blist.ToArray(); return list.ToArray(); } } [TypeConverter(typeof(ExpandableObjectConverter))] public class Skeleton : ResourceSystemBlock { public override long BlockLength { get { return 112; } } // structure data public uint VFT { get; set; } public uint Unknown_4h { get; set; } = 1; // 0x00000001 public uint Unknown_8h { get; set; } // 0x00000000 public uint Unknown_Ch { get; set; } // 0x00000000 public ulong BoneTagsPointer { get; set; } public ushort Count1 { get; set; } public ushort Count2 { get; set; } public FlagsUint Unknown_1Ch { get; set; } public ulong BonesPointer { get; set; } public ulong TransformationsInvertedPointer { get; set; } public ulong TransformationsPointer { get; set; } public ulong ParentIndicesPointer { get; set; } public ulong ChildIndicesPointer { get; set; } public uint Unknown_48h { get; set; } // 0x00000000 public uint Unknown_4Ch { get; set; } // 0x00000000 public MetaHash Unknown_50h { get; set; } public MetaHash Unknown_54h { get; set; } public MetaHash Unknown_58h { get; set; } public ushort Unknown_5Ch { get; set; } = 1; // 0x0001 public ushort BonesCount { get; set; } public ushort ChildIndicesCount { get; set; } public ushort Unknown_62h { get; set; } // 0x0000 public uint Unknown_64h { get; set; } // 0x00000000 public uint Unknown_68h { get; set; } // 0x00000000 public uint Unknown_6Ch { get; set; } // 0x00000000 // reference data public ResourcePointerArray64 BoneTags { get; set; } public ResourceSimpleArray Bones { get; set; } public Matrix[] TransformationsInverted { get; set; } public Matrix[] Transformations { get; set; } public short[] ParentIndices { get; set; } public short[] ChildIndices { get; set; }//mapping child->parent indices, first child index, then parent private ResourceSystemStructBlock TransformationsInvertedBlock = null;//for saving only private ResourceSystemStructBlock TransformationsBlock = null; private ResourceSystemStructBlock ParentIndicesBlock = null; private ResourceSystemStructBlock ChildIndicesBlock = null; public Dictionary BonesMap { get; set; }//for convienience finding bones by tag public Matrix3_s[] BoneTransforms; //for rendering /// /// Reads the data-block from a stream. /// public override void Read(ResourceDataReader reader, params object[] parameters) { // read structure data this.VFT = reader.ReadUInt32(); this.Unknown_4h = reader.ReadUInt32(); this.Unknown_8h = reader.ReadUInt32(); this.Unknown_Ch = reader.ReadUInt32(); this.BoneTagsPointer = reader.ReadUInt64(); this.Count1 = reader.ReadUInt16(); this.Count2 = reader.ReadUInt16(); this.Unknown_1Ch = reader.ReadUInt32(); this.BonesPointer = reader.ReadUInt64(); this.TransformationsInvertedPointer = reader.ReadUInt64(); this.TransformationsPointer = reader.ReadUInt64(); this.ParentIndicesPointer = reader.ReadUInt64(); this.ChildIndicesPointer = reader.ReadUInt64(); this.Unknown_48h = reader.ReadUInt32(); this.Unknown_4Ch = reader.ReadUInt32(); this.Unknown_50h = new MetaHash(reader.ReadUInt32()); this.Unknown_54h = new MetaHash(reader.ReadUInt32()); this.Unknown_58h = new MetaHash(reader.ReadUInt32()); this.Unknown_5Ch = reader.ReadUInt16(); this.BonesCount = reader.ReadUInt16(); this.ChildIndicesCount = reader.ReadUInt16(); this.Unknown_62h = reader.ReadUInt16(); this.Unknown_64h = reader.ReadUInt32(); this.Unknown_68h = reader.ReadUInt32(); this.Unknown_6Ch = reader.ReadUInt32(); // read reference data this.BoneTags = reader.ReadBlockAt>( this.BoneTagsPointer, // offset this.Count1 ); this.Bones = reader.ReadBlockAt>( this.BonesPointer, // offset this.BonesCount ); this.TransformationsInverted = reader.ReadStructsAt(this.TransformationsInvertedPointer, this.BonesCount); this.Transformations = reader.ReadStructsAt(this.TransformationsPointer, this.BonesCount); this.ParentIndices = reader.ReadShortsAt(this.ParentIndicesPointer, this.BonesCount); this.ChildIndices = reader.ReadShortsAt(this.ChildIndicesPointer, this.ChildIndicesCount); AssignBoneParents(); BuildBonesMap(); } /// /// Writes the data-block to a stream. /// public override void Write(ResourceDataWriter writer, params object[] parameters) { // update structure data this.BoneTagsPointer = (ulong)(this.BoneTags != null ? this.BoneTags.FilePosition : 0); this.Count1 = (ushort)(this.BoneTags != null ? this.BoneTags.Count : 0); this.BonesPointer = (ulong)(this.Bones != null ? this.Bones.FilePosition : 0); this.TransformationsInvertedPointer = (ulong)(this.TransformationsInvertedBlock != null ? this.TransformationsInvertedBlock.FilePosition : 0); this.TransformationsPointer = (ulong)(this.TransformationsBlock != null ? this.TransformationsBlock.FilePosition : 0); this.ParentIndicesPointer = (ulong)(this.ParentIndicesBlock != null ? this.ParentIndicesBlock.FilePosition : 0); this.ChildIndicesPointer = (ulong)(this.ChildIndicesBlock != null ? this.ChildIndicesBlock.FilePosition : 0); this.BonesCount = (ushort)(this.Bones != null ? this.Bones.Count : 0); this.ChildIndicesCount = (ushort)(this.ChildIndicesBlock != null ? this.ChildIndicesBlock.ItemCount : 0); //this.Count2 = BonesCount;//? // write structure data writer.Write(this.VFT); writer.Write(this.Unknown_4h); writer.Write(this.Unknown_8h); writer.Write(this.Unknown_Ch); writer.Write(this.BoneTagsPointer); writer.Write(this.Count1); writer.Write(this.Count2); writer.Write(this.Unknown_1Ch); writer.Write(this.BonesPointer); writer.Write(this.TransformationsInvertedPointer); writer.Write(this.TransformationsPointer); writer.Write(this.ParentIndicesPointer); writer.Write(this.ChildIndicesPointer); writer.Write(this.Unknown_48h); writer.Write(this.Unknown_4Ch); writer.Write(this.Unknown_50h); writer.Write(this.Unknown_54h); writer.Write(this.Unknown_58h); writer.Write(this.Unknown_5Ch); writer.Write(this.BonesCount); writer.Write(this.ChildIndicesCount); writer.Write(this.Unknown_62h); writer.Write(this.Unknown_64h); writer.Write(this.Unknown_68h); writer.Write(this.Unknown_6Ch); } /// /// Returns a list of data blocks which are referenced by this block. /// public override IResourceBlock[] GetReferences() { var list = new List(); if (BoneTags != null) list.Add(BoneTags); if (Bones != null) list.Add(Bones); if (TransformationsInverted != null) { TransformationsInvertedBlock = new ResourceSystemStructBlock(TransformationsInverted); list.Add(TransformationsInvertedBlock); } if (Transformations != null) { TransformationsBlock = new ResourceSystemStructBlock(Transformations); list.Add(TransformationsBlock); } if (ParentIndices != null) { ParentIndicesBlock = new ResourceSystemStructBlock(ParentIndices); list.Add(ParentIndicesBlock); } if (ChildIndices != null) { ChildIndicesBlock = new ResourceSystemStructBlock(ChildIndices); list.Add(ChildIndicesBlock); } return list.ToArray(); } public void AssignBoneParents() { if ((Bones != null) && (ParentIndices != null)) { var maxcnt = Math.Min(Bones.Count, ParentIndices.Length); for (int i = 0; i < maxcnt; i++) { var bone = Bones[i]; var pind = ParentIndices[i]; if ((pind >= 0) && (pind < Bones.Count)) { bone.Parent = Bones[pind]; } } } } public void BuildBonesMap() { BonesMap = new Dictionary(); if (Bones != null) { for (int i = 0; i < Bones.Count; i++) { var bone = Bones[i]; BonesMap[bone.Tag] = bone; bone.UpdateAnimTransform(); bone.BindTransformInv = (i < TransformationsInverted?.Length) ? TransformationsInverted[i] : Matrix.Invert(bone.AnimTransform); bone.BindTransformInv.M44 = 1.0f; bone.UpdateSkinTransform(); } } } public void ResetBoneTransforms() { if (Bones?.Data == null) return; foreach (var bone in Bones.Data) { bone.ResetAnimTransform(); } UpdateBoneTransforms(); } public void UpdateBoneTransforms() { if (Bones?.Data == null) return; if ((BoneTransforms == null) || (BoneTransforms.Length != Bones.Data.Count)) { BoneTransforms = new Matrix3_s[Bones.Data.Count]; } for (int i = 0; i < Bones.Data.Count; i++) { var bone = Bones.Data[i]; Matrix b = bone.SkinTransform; Matrix3_s bt = new Matrix3_s(); bt.Row1 = b.Column1; bt.Row2 = b.Column2; bt.Row3 = b.Column3; BoneTransforms[i] = bt; } } public Skeleton Clone() { var skel = new Skeleton(); skel.Count1 = Count1; skel.Count2 = Count2; skel.Unknown_1Ch = Unknown_1Ch; skel.Unknown_50h = Unknown_50h; skel.Unknown_54h = Unknown_54h; skel.Unknown_58h = Unknown_58h; skel.BonesCount = BonesCount; skel.ChildIndicesCount = ChildIndicesCount; if (BoneTags != null) { skel.BoneTags = new ResourcePointerArray64(); if (BoneTags.data_items != null) { skel.BoneTags.data_items = new SkeletonBoneTag[BoneTags.data_items.Length]; for (int i = 0; i < BoneTags.data_items.Length; i++) { var obt = BoneTags.data_items[i]; var nbt = new SkeletonBoneTag(); skel.BoneTags.data_items[i] = nbt; while (obt != null) { nbt.BoneTag = obt.BoneTag; nbt.BoneIndex = obt.BoneIndex; obt = obt.LinkedTag; if (obt != null) { var nxt = new SkeletonBoneTag(); nbt.LinkedTag = nxt; nbt = nxt; } } } } } if (Bones != null) { skel.Bones = new ResourceSimpleArray(); if (Bones.Data != null) { skel.Bones.Data = new List(); for (int i = 0; i < Bones.Data.Count; i++) { var ob = Bones.Data[i]; var nb = new Bone(); nb.Rotation = ob.Rotation; nb.Translation = ob.Translation; nb.Scale = ob.Scale; nb.NextSiblingIndex = ob.NextSiblingIndex; nb.ParentIndex = ob.ParentIndex; nb.Flags = ob.Flags; nb.Index = ob.Index; nb.Tag = ob.Tag; nb.Index2 = ob.Index2; nb.Name = ob.Name; nb.AnimRotation = ob.AnimRotation; nb.AnimTranslation = ob.AnimTranslation; nb.AnimScale = ob.AnimScale; nb.AnimTransform = ob.AnimTransform; nb.BindTransformInv = ob.BindTransformInv; nb.SkinTransform = ob.SkinTransform; skel.Bones.Data.Add(nb); } } } skel.TransformationsInverted = (Matrix[])TransformationsInverted?.Clone(); skel.Transformations = (Matrix[])Transformations?.Clone(); skel.ParentIndices = (short[])ParentIndices?.Clone(); skel.ChildIndices = (short[])ChildIndices?.Clone(); skel.AssignBoneParents(); skel.BuildBonesMap(); return skel; } } [TypeConverter(typeof(ExpandableObjectConverter))] public class SkeletonBoneTag : ResourceSystemBlock { public override long BlockLength { get { return 16; } } // structure data public uint BoneTag { get; set; } public uint BoneIndex { get; set; } public ulong LinkedTagPointer { get; set; } // reference data public SkeletonBoneTag LinkedTag { get; set; } //don't know why it's linked here /// /// Reads the data-block from a stream. /// public override void Read(ResourceDataReader reader, params object[] parameters) { // read structure data this.BoneTag = reader.ReadUInt32(); this.BoneIndex = reader.ReadUInt32(); this.LinkedTagPointer = reader.ReadUInt64(); // read reference data this.LinkedTag = reader.ReadBlockAt( this.LinkedTagPointer // offset ); } /// /// Writes the data-block to a stream. /// public override void Write(ResourceDataWriter writer, params object[] parameters) { // update structure data this.LinkedTagPointer = (ulong)(this.LinkedTag != null ? this.LinkedTag.FilePosition : 0); // write structure data writer.Write(this.BoneTag); writer.Write(this.BoneIndex); writer.Write(this.LinkedTagPointer); } /// /// Returns a list of data blocks which are referenced by this block. /// public override IResourceBlock[] GetReferences() { var list = new List(); if (LinkedTag != null) list.Add(LinkedTag); return list.ToArray(); } public override string ToString() { return BoneTag.ToString() + ": " + BoneIndex.ToString(); } } [Flags] public enum EBoneFlags : ushort { None = 0, RotX = 0x1, RotY = 0x2, RotZ = 0x4, LimitRotation = 0x8, TransX = 0x10, TransY = 0x20, TransZ = 0x40, LimitTranslation = 0x80, ScaleX = 0x100, ScaleY = 0x200, ScaleZ = 0x400, LimitScale = 0x800, Unk0 = 0x1000, Unk1 = 0x2000, Unk2 = 0x4000, Unk3 = 0x8000, } [TypeConverter(typeof(ExpandableObjectConverter))] public class Bone : ResourceSystemBlock { public override long BlockLength { get { return 80; } } // structure data public Quaternion Rotation { get; set; } public Vector3 Translation { get; set; } public uint Unknown_1Ch { get; set; } // 0x00000000 RHW? public Vector3 Scale { get; set; } public float Unknown_2Ch { get; set; } = 1.0f; // 1.0 RHW? public short NextSiblingIndex { get; set; } //limb end index? IK chain? public short ParentIndex { get; set; } public uint Unknown_34h { get; set; } // 0x00000000 public ulong NamePointer { get; set; } public EBoneFlags Flags { get; set; } public short Index { get; set; } public ushort Tag { get; set; } public short Index2 { get; set; }//same as Index? public uint Unknown_48h { get; set; } // 0x00000000 public uint Unknown_4Ch { get; set; } // 0x00000000 // reference data public string Name { get; set; } public Bone Parent { get; set; } private string_r NameBlock = null; //used by CW for animating skeletons. public Quaternion AnimRotation;//relative to parent public Vector3 AnimTranslation;//relative to parent public Vector3 AnimScale; public Matrix AnimTransform;//absolute world transform, animated public Matrix BindTransformInv;//inverse of bind pose transform public Matrix SkinTransform;//transform to use for skin meshes /// /// Reads the data-block from a stream. /// public override void Read(ResourceDataReader reader, params object[] parameters) { // read structure data this.Rotation = new Quaternion(reader.ReadVector4()); this.Translation = reader.ReadVector3(); this.Unknown_1Ch = reader.ReadUInt32(); this.Scale = reader.ReadVector3(); this.Unknown_2Ch = reader.ReadSingle(); this.NextSiblingIndex = reader.ReadInt16(); this.ParentIndex = reader.ReadInt16(); this.Unknown_34h = reader.ReadUInt32(); this.NamePointer = reader.ReadUInt64(); this.Flags = (EBoneFlags)reader.ReadUInt16(); this.Index = reader.ReadInt16(); this.Tag = reader.ReadUInt16(); this.Index2 = reader.ReadInt16(); this.Unknown_48h = reader.ReadUInt32(); this.Unknown_4Ch = reader.ReadUInt32(); // read reference data this.Name = reader.ReadStringAt(//BlockAt( this.NamePointer // offset ); AnimRotation = Rotation; AnimTranslation = Translation; AnimScale = Scale; } /// /// Writes the data-block to a stream. /// public override void Write(ResourceDataWriter writer, params object[] parameters) { // update structure data this.NamePointer = (ulong)(this.NameBlock != null ? this.NameBlock.FilePosition : 0); // write structure data writer.Write(this.Rotation.ToVector4()); writer.Write(this.Translation); writer.Write(this.Unknown_1Ch); writer.Write(this.Scale); writer.Write(this.Unknown_2Ch); writer.Write(this.NextSiblingIndex); writer.Write(this.ParentIndex); writer.Write(this.Unknown_34h); writer.Write(this.NamePointer); writer.Write((ushort)this.Flags); writer.Write(this.Index); writer.Write(this.Tag); writer.Write(this.Index2); writer.Write(this.Unknown_48h); writer.Write(this.Unknown_4Ch); } /// /// Returns a list of data blocks which are referenced by this block. /// public override IResourceBlock[] GetReferences() { var list = new List(); if (Name != null) { NameBlock = (string_r)Name; list.Add(NameBlock); } return list.ToArray(); } public override string ToString() { return Tag.ToString() + ": " + Name; } public void UpdateAnimTransform() { //AnimTransform = Matrix.AffineTransformation(1.0f, AnimRotation, AnimTranslation);//(local transform) var pos = AnimTranslation; var ori = AnimRotation; var sca = AnimScale; var pbone = Parent; while (pbone != null) { pos = pbone.AnimRotation.Multiply(pos /** pbone.AnimScale*/) + pbone.AnimTranslation; ori = pbone.AnimRotation * ori; pbone = pbone.Parent; } AnimTransform = Matrix.AffineTransformation(1.0f, ori, pos);//(global transform) AnimTransform.ScaleVector *= sca; } public void UpdateSkinTransform() { SkinTransform = BindTransformInv * AnimTransform; //SkinTransform = Matrix.Identity;//(for testing) } public void ResetAnimTransform() { AnimRotation = Rotation; AnimTranslation = Translation; AnimScale = Scale; UpdateAnimTransform(); UpdateSkinTransform(); } public static uint ElfHash_Uppercased(string str) { uint hash = 0; uint x = 0; uint i = 0; for (i = 0; i < str.Length; i++) { var c = ((byte)str[(int)i]); if ((byte)(c - 'a') <= 25u) // to uppercase c -= 32; hash = (hash << 4) + c; if ((x = hash & 0xF0000000) != 0) { hash ^= (x >> 24); } hash &= ~x; } return hash; } public static ushort CalculateBoneHash(string boneName) { return (ushort)(ElfHash_Uppercased(boneName) % 0xFE8F + 0x170); } } [TypeConverter(typeof(ExpandableObjectConverter))] public class Joints : ResourceSystemBlock { public override long BlockLength { get { return 64; } } // structure data public uint VFT { get; set; } public uint Unknown_4h { get; set; } // 0x00000001 public uint Unknown_8h { get; set; } // 0x00000000 public uint Unknown_Ch { get; set; } // 0x00000000 public ulong RotationLimitsPointer { get; set; } public ulong TranslationLimitsPointer { get; set; } public uint Unknown_20h { get; set; } // 0x00000000 public uint Unknown_24h { get; set; } // 0x00000000 public uint Unknown_28h { get; set; } // 0x00000000 public uint Unknown_2Ch { get; set; } // 0x00000000 public ushort RotationLimitsCount { get; set; } public ushort TranslationLimitsCount { get; set; } public ushort Unknown_34h { get; set; } // 0x0000 public ushort Unknown_36h { get; set; } // 0x0001 public uint Unknown_38h { get; set; } // 0x00000000 public uint Unknown_3Ch { get; set; } // 0x00000000 // reference data public JointRotationLimit_s[] RotationLimits { get; set; } public JointTranslationLimit_s[] TranslationLimits { get; set; } private ResourceSystemStructBlock RotationLimitsBlock = null; //for saving only private ResourceSystemStructBlock TranslationLimitsBlock = null; /// /// Reads the data-block from a stream. /// public override void Read(ResourceDataReader reader, params object[] parameters) { // read structure data this.VFT = reader.ReadUInt32(); this.Unknown_4h = reader.ReadUInt32(); this.Unknown_8h = reader.ReadUInt32(); this.Unknown_Ch = reader.ReadUInt32(); this.RotationLimitsPointer = reader.ReadUInt64(); this.TranslationLimitsPointer = reader.ReadUInt64(); this.Unknown_20h = reader.ReadUInt32(); this.Unknown_24h = reader.ReadUInt32(); this.Unknown_28h = reader.ReadUInt32(); this.Unknown_2Ch = reader.ReadUInt32(); this.RotationLimitsCount = reader.ReadUInt16(); this.TranslationLimitsCount = reader.ReadUInt16(); this.Unknown_34h = reader.ReadUInt16(); this.Unknown_36h = reader.ReadUInt16(); this.Unknown_38h = reader.ReadUInt32(); this.Unknown_3Ch = reader.ReadUInt32(); // read reference data //this.RotationLimits = reader.ReadBlockAt>( // this.RotationLimitsPointer, // offset // this.RotationLimitsCount //); //this.TranslationLimits = reader.ReadBlockAt>( // this.TranslationLimitsPointer, // offset // this.TranslationLimitsCount //); this.RotationLimits = reader.ReadStructsAt(this.RotationLimitsPointer, this.RotationLimitsCount); this.TranslationLimits = reader.ReadStructsAt(this.TranslationLimitsPointer, this.TranslationLimitsCount); } /// /// Writes the data-block to a stream. /// public override void Write(ResourceDataWriter writer, params object[] parameters) { // update structure data this.RotationLimitsPointer = (ulong)(this.RotationLimitsBlock != null ? this.RotationLimitsBlock.FilePosition : 0); this.TranslationLimitsPointer = (ulong)(this.TranslationLimitsBlock != null ? this.TranslationLimitsBlock.FilePosition : 0); this.RotationLimitsCount = (ushort)(this.RotationLimitsBlock != null ? this.RotationLimitsBlock.ItemCount : 0); this.TranslationLimitsCount = (ushort)(this.TranslationLimitsBlock != null ? this.TranslationLimitsBlock.ItemCount : 0); // write structure data writer.Write(this.VFT); writer.Write(this.Unknown_4h); writer.Write(this.Unknown_8h); writer.Write(this.Unknown_Ch); writer.Write(this.RotationLimitsPointer); writer.Write(this.TranslationLimitsPointer); writer.Write(this.Unknown_20h); writer.Write(this.Unknown_24h); writer.Write(this.Unknown_28h); writer.Write(this.Unknown_2Ch); writer.Write(this.RotationLimitsCount); writer.Write(this.TranslationLimitsCount); writer.Write(this.Unknown_34h); writer.Write(this.Unknown_36h); writer.Write(this.Unknown_38h); writer.Write(this.Unknown_3Ch); } /// /// Returns a list of data blocks which are referenced by this block. /// public override IResourceBlock[] GetReferences() { var list = new List(); if (RotationLimits != null) { RotationLimitsBlock = new ResourceSystemStructBlock(RotationLimits); list.Add(RotationLimitsBlock); } if (TranslationLimits != null) { TranslationLimitsBlock = new ResourceSystemStructBlock(TranslationLimits); list.Add(TranslationLimitsBlock); } return list.ToArray(); } } [TypeConverter(typeof(ExpandableObjectConverter))] public struct JointRotationLimit_s { // structure data public uint Unknown_0h { get; set; } // 0x00000000 public uint Unknown_4h { get; set; } // 0x00000000 public ushort BoneId { get; set; } public ushort Unknown_Ah { get; set; } public uint Unknown_Ch { get; set; } // 0x00000001 public uint Unknown_10h { get; set; } // 0x00000003 public uint Unknown_14h { get; set; } // 0x00000000 public uint Unknown_18h { get; set; } // 0x00000000 public uint Unknown_1Ch { get; set; } // 0x00000000 public uint Unknown_20h { get; set; } // 0x00000000 public uint Unknown_24h { get; set; } // 0x00000000 public uint Unknown_28h { get; set; } // 0x00000000 public float Unknown_2Ch { get; set; } // 1.0 public uint Unknown_30h { get; set; } // 0x00000000 public uint Unknown_34h { get; set; } // 0x00000000 public uint Unknown_38h { get; set; } // 0x00000000 public uint Unknown_3Ch { get; set; } // 0x00000000 public float Unknown_40h { get; set; } // 1.0 public uint Unknown_44h { get; set; } // 0x00000000 public uint Unknown_48h { get; set; } // 0x00000000 public uint Unknown_4Ch { get; set; } // 0x00000000 public float Unknown_50h { get; set; } // -pi public float Unknown_54h { get; set; } // pi public float Unknown_58h { get; set; } // 1.0 public Vector3 Min { get; set; } public Vector3 Max { get; set; } public float Unknown_74h { get; set; } // pi public float Unknown_78h { get; set; } // -pi public float Unknown_7Ch { get; set; } // pi public float Unknown_80h { get; set; } // pi public float Unknown_84h { get; set; } // -pi public float Unknown_88h { get; set; } // pi public float Unknown_8Ch { get; set; } // pi public float Unknown_90h { get; set; } // -pi public float Unknown_94h { get; set; } // pi public float Unknown_98h { get; set; } // pi public float Unknown_9Ch { get; set; } // -pi public float Unknown_A0h { get; set; } // pi public float Unknown_A4h { get; set; } // pi public float Unknown_A8h { get; set; } // -pi public float Unknown_ACh { get; set; } // pi public float Unknown_B0h { get; set; } // pi public float Unknown_B4h { get; set; } // -pi public float Unknown_B8h { get; set; } // pi public uint Unknown_BCh { get; set; } // 0x00000100 } [TypeConverter(typeof(ExpandableObjectConverter))] public struct JointTranslationLimit_s { public uint Unknown_0h { get; set; } // 0x00000000 public uint Unknown_4h { get; set; } // 0x00000000 public uint BoneId { get; set; } public uint Unknown_Ch { get; set; } // 0x00000000 public uint Unknown_10h { get; set; } // 0x00000000 public uint Unknown_14h { get; set; } // 0x00000000 public uint Unknown_18h { get; set; } // 0x00000000 public uint Unknown_1Ch { get; set; } // 0x00000000 public Vector3 Min { get; set; } public uint Unknown_2Ch { get; set; } // 0x00000000 public Vector3 Max { get; set; } public uint Unknown_3Ch { get; set; } // 0x00000000 } [TypeConverter(typeof(ExpandableObjectConverter))] public class DrawableModel : ResourceSystemBlock { public override long BlockLength { get { return 48; } } // structure data public uint VFT { get; set; } public uint Unknown_4h { get; set; } // 0x00000001 public ulong GeometriesPointer { get; set; } public ushort GeometriesCount1 { get; set; } public ushort GeometriesCount2 { get; set; } public uint Unknown_14h { get; set; } // 0x00000000 public ulong BoundsPointer { get; set; } public ulong ShaderMappingPointer { get; set; } public uint SkeletonBinding { get; set; }//4th byte is bone index, 2nd byte for skin meshes public ushort RenderMaskFlags { get; set; } //First byte is called "Mask" in GIMS EVO public ushort GeometriesCount3 { get; set; } //always equal to GeometriesCount, is it ShaderMappingCount? // reference data public ResourcePointerArray64 Geometries { get; set; } public AABB_s[] BoundsData { get; set; } public ushort[] ShaderMapping { get; set; } private ResourceSystemStructBlock BoundsDataBlock = null; //for saving only private ResourceSystemStructBlock ShaderMappingBlock = null; public long MemoryUsage { get { long val = 0; if ((Geometries != null) && (Geometries.data_items != null)) { foreach(var geom in Geometries.data_items) { if (geom == null) continue; if (geom.VertexData != null) { val += geom.VertexData.MemoryUsage; } if (geom.IndexBuffer != null) { val += geom.IndexBuffer.IndicesCount * 4; } if (geom.VertexBuffer != null) { if ((geom.VertexBuffer.Data1 != null) && (geom.VertexBuffer.Data1 != geom.VertexData)) { val += geom.VertexBuffer.Data1.MemoryUsage; } if ((geom.VertexBuffer.Data2 != null) && (geom.VertexBuffer.Data2 != geom.VertexData)) { val += geom.VertexBuffer.Data2.MemoryUsage; } } } } if (BoundsData != null) { val += BoundsData.Length * 32; } return val; } } /// /// Reads the data-block from a stream. /// public override void Read(ResourceDataReader reader, params object[] parameters) { // read structure data this.VFT = reader.ReadUInt32(); this.Unknown_4h = reader.ReadUInt32(); this.GeometriesPointer = reader.ReadUInt64(); this.GeometriesCount1 = reader.ReadUInt16(); this.GeometriesCount2 = reader.ReadUInt16(); this.Unknown_14h = reader.ReadUInt32(); this.BoundsPointer = reader.ReadUInt64(); this.ShaderMappingPointer = reader.ReadUInt64(); this.SkeletonBinding = reader.ReadUInt32(); this.RenderMaskFlags = reader.ReadUInt16(); this.GeometriesCount3 = reader.ReadUInt16(); // read reference data this.Geometries = reader.ReadBlockAt>( this.GeometriesPointer, // offset this.GeometriesCount1 ); this.BoundsData = reader.ReadStructsAt(this.BoundsPointer, (uint)(this.GeometriesCount1 > 1 ? this.GeometriesCount1 + 1 : this.GeometriesCount1)); this.ShaderMapping = reader.ReadUshortsAt(this.ShaderMappingPointer, this.GeometriesCount1); } /// /// Writes the data-block to a stream. /// public override void Write(ResourceDataWriter writer, params object[] parameters) { // update structure data this.GeometriesPointer = (ulong)(this.Geometries != null ? this.Geometries.FilePosition : 0); this.GeometriesCount1 = (ushort)(this.Geometries != null ? this.Geometries.Count : 0); this.GeometriesCount2 = this.GeometriesCount1;//is this correct? this.GeometriesCount3 = this.GeometriesCount1;//is this correct? this.BoundsPointer = (ulong)(this.BoundsDataBlock != null ? this.BoundsDataBlock.FilePosition : 0); this.ShaderMappingPointer = (ulong)(this.ShaderMappingBlock != null ? this.ShaderMappingBlock.FilePosition : 0); // write structure data writer.Write(this.VFT); writer.Write(this.Unknown_4h); writer.Write(this.GeometriesPointer); writer.Write(this.GeometriesCount1); writer.Write(this.GeometriesCount2); writer.Write(this.Unknown_14h); writer.Write(this.BoundsPointer); writer.Write(this.ShaderMappingPointer); writer.Write(this.SkeletonBinding); writer.Write(this.RenderMaskFlags); writer.Write(this.GeometriesCount3); } /// /// Returns a list of data blocks which are referenced by this block. /// public override IResourceBlock[] GetReferences() { var list = new List(); if (Geometries != null) list.Add(Geometries); if (BoundsData != null) { BoundsDataBlock = new ResourceSystemStructBlock(BoundsData); list.Add(BoundsDataBlock); } if (ShaderMapping != null) { ShaderMappingBlock = new ResourceSystemStructBlock(ShaderMapping); list.Add(ShaderMappingBlock); } return list.ToArray(); } public override string ToString() { return "(" + Geometries.Count + " geometr" + (Geometries.Count != 1 ? "ies)" : "y)"); } } [TypeConverter(typeof(ExpandableObjectConverter))] public class DrawableGeometry : ResourceSystemBlock { public override long BlockLength { get { return 152; } } // structure data public uint VFT { get; set; } public uint Unknown_4h { get; set; } // 0x00000001 public uint Unknown_8h { get; set; } // 0x00000000 public uint Unknown_Ch { get; set; } // 0x00000000 public uint Unknown_10h { get; set; } // 0x00000000 public uint Unknown_14h { get; set; } // 0x00000000 public ulong VertexBufferPointer { get; set; } public uint Unknown_20h { get; set; } // 0x00000000 public uint Unknown_24h { get; set; } // 0x00000000 public uint Unknown_28h { get; set; } // 0x00000000 public uint Unknown_2Ch { get; set; } // 0x00000000 public uint Unknown_30h { get; set; } // 0x00000000 public uint Unknown_34h { get; set; } // 0x00000000 public ulong IndexBufferPointer { get; set; } public uint Unknown_40h { get; set; } // 0x00000000 public uint Unknown_44h { get; set; } // 0x00000000 public uint Unknown_48h { get; set; } // 0x00000000 public uint Unknown_4Ch { get; set; } // 0x00000000 public uint Unknown_50h { get; set; } // 0x00000000 public uint Unknown_54h { get; set; } // 0x00000000 public uint IndicesCount { get; set; } public uint TrianglesCount { get; set; } public ushort VerticesCount { get; set; } public ushort Unknown_62h { get; set; } // 0x0003 public uint Unknown_64h { get; set; } // 0x00000000 public ulong BoneIdsPointer { get; set; } public ushort VertexStride { get; set; } public ushort BoneIdsCount { get; set; } public uint Unknown_74h { get; set; } // 0x00000000 public ulong VertexDataPointer { get; set; } public uint Unknown_80h { get; set; } // 0x00000000 public uint Unknown_84h { get; set; } // 0x00000000 public uint Unknown_88h { get; set; } // 0x00000000 public uint Unknown_8Ch { get; set; } // 0x00000000 public uint Unknown_90h { get; set; } // 0x00000000 public uint Unknown_94h { get; set; } // 0x00000000 // reference data public VertexBuffer VertexBuffer { get; set; } public IndexBuffer IndexBuffer { get; set; } public ushort[] BoneIds { get; set; } public VertexData VertexData { get; set; } public ShaderFX Shader { get; set; } public ushort ShaderID { get; set; } private ResourceSystemStructBlock BoneIdsBlock = null;//for saving only public bool UpdateRenderableParameters { get; set; } = false; //used by model material editor... /// /// Reads the data-block from a stream. /// public override void Read(ResourceDataReader reader, params object[] parameters) { // read structure data this.VFT = reader.ReadUInt32(); this.Unknown_4h = reader.ReadUInt32(); this.Unknown_8h = reader.ReadUInt32(); this.Unknown_Ch = reader.ReadUInt32(); this.Unknown_10h = reader.ReadUInt32(); this.Unknown_14h = reader.ReadUInt32(); this.VertexBufferPointer = reader.ReadUInt64(); this.Unknown_20h = reader.ReadUInt32(); this.Unknown_24h = reader.ReadUInt32(); this.Unknown_28h = reader.ReadUInt32(); this.Unknown_2Ch = reader.ReadUInt32(); this.Unknown_30h = reader.ReadUInt32(); this.Unknown_34h = reader.ReadUInt32(); this.IndexBufferPointer = reader.ReadUInt64(); this.Unknown_40h = reader.ReadUInt32(); this.Unknown_44h = reader.ReadUInt32(); this.Unknown_48h = reader.ReadUInt32(); this.Unknown_4Ch = reader.ReadUInt32(); this.Unknown_50h = reader.ReadUInt32(); this.Unknown_54h = reader.ReadUInt32(); this.IndicesCount = reader.ReadUInt32(); this.TrianglesCount = reader.ReadUInt32(); this.VerticesCount = reader.ReadUInt16(); this.Unknown_62h = reader.ReadUInt16(); this.Unknown_64h = reader.ReadUInt32(); this.BoneIdsPointer = reader.ReadUInt64(); this.VertexStride = reader.ReadUInt16(); this.BoneIdsCount = reader.ReadUInt16(); this.Unknown_74h = reader.ReadUInt32(); this.VertexDataPointer = reader.ReadUInt64(); this.Unknown_80h = reader.ReadUInt32(); this.Unknown_84h = reader.ReadUInt32(); this.Unknown_88h = reader.ReadUInt32(); this.Unknown_8Ch = reader.ReadUInt32(); this.Unknown_90h = reader.ReadUInt32(); this.Unknown_94h = reader.ReadUInt32(); // read reference data this.VertexBuffer = reader.ReadBlockAt( this.VertexBufferPointer // offset ); this.IndexBuffer = reader.ReadBlockAt( this.IndexBufferPointer // offset ); this.BoneIds = reader.ReadUshortsAt(this.BoneIdsPointer, this.BoneIdsCount); if (this.BoneIds != null) //skinned mesh bones to use? peds, also yft props... { } if (this.VertexBuffer != null) { this.VertexData = this.VertexBuffer.Data1; if (this.VertexData == null) { this.VertexData = this.VertexBuffer.Data2; } if ((this.VertexDataPointer != 0) && (VertexDataPointer != VertexBuffer.DataPointer1)) { //some mods hit here! // try // { // this.VertexData = reader.ReadBlockAt( // this.VertexDataPointer, // offset // this.VertexStride, // this.VerticesCount, // this.VertexBuffer.Info // ); // } // catch // { } } } else { } } /// /// Writes the data-block to a stream. /// public override void Write(ResourceDataWriter writer, params object[] parameters) { // update structure data this.VertexBufferPointer = (ulong)(this.VertexBuffer != null ? this.VertexBuffer.FilePosition : 0); this.IndexBufferPointer = (ulong)(this.IndexBuffer != null ? this.IndexBuffer.FilePosition : 0); this.BoneIdsPointer = (ulong)(this.BoneIdsBlock != null ? this.BoneIdsBlock.FilePosition : 0); this.VerticesCount = (ushort)(this.VertexData != null ? this.VertexData.VertexCount : 0); //TODO: fix? this.BoneIdsCount = (ushort)(this.BoneIdsBlock != null ? this.BoneIdsBlock.ItemCount : 0); this.VertexDataPointer = (ulong)(this.VertexData != null ? this.VertexData.FilePosition : 0); // write structure data writer.Write(this.VFT); writer.Write(this.Unknown_4h); writer.Write(this.Unknown_8h); writer.Write(this.Unknown_Ch); writer.Write(this.Unknown_10h); writer.Write(this.Unknown_14h); writer.Write(this.VertexBufferPointer); writer.Write(this.Unknown_20h); writer.Write(this.Unknown_24h); writer.Write(this.Unknown_28h); writer.Write(this.Unknown_2Ch); writer.Write(this.Unknown_30h); writer.Write(this.Unknown_34h); writer.Write(this.IndexBufferPointer); writer.Write(this.Unknown_40h); writer.Write(this.Unknown_44h); writer.Write(this.Unknown_48h); writer.Write(this.Unknown_4Ch); writer.Write(this.Unknown_50h); writer.Write(this.Unknown_54h); writer.Write(this.IndicesCount); writer.Write(this.TrianglesCount); writer.Write(this.VerticesCount); writer.Write(this.Unknown_62h); writer.Write(this.Unknown_64h); writer.Write(this.BoneIdsPointer); writer.Write(this.VertexStride); writer.Write(this.BoneIdsCount); writer.Write(this.Unknown_74h); writer.Write(this.VertexDataPointer); writer.Write(this.Unknown_80h); writer.Write(this.Unknown_84h); writer.Write(this.Unknown_88h); writer.Write(this.Unknown_8Ch); writer.Write(this.Unknown_90h); writer.Write(this.Unknown_94h); } /// /// Returns a list of data blocks which are referenced by this block. /// public override IResourceBlock[] GetReferences() { var list = new List(); if (VertexBuffer != null) list.Add(VertexBuffer); if (IndexBuffer != null) list.Add(IndexBuffer); if (BoneIds != null) { BoneIdsBlock = new ResourceSystemStructBlock(BoneIds); list.Add(BoneIdsBlock); } if (VertexData != null) list.Add(VertexData); return list.ToArray(); } public override string ToString() { return VerticesCount.ToString() + " verts, " + Shader.ToString(); } } [TypeConverter(typeof(ExpandableObjectConverter))] public class VertexBuffer : ResourceSystemBlock { public override long BlockLength { get { return 128; } } // structure data public uint VFT { get; set; } public uint Unknown_4h { get; set; } // 0x00000001 public ushort VertexStride { get; set; } public ushort Unknown_Ah { get; set; } public uint Unknown_Ch { get; set; } // 0x00000000 public ulong DataPointer1 { get; set; } public uint VertexCount { get; set; } public uint Unknown_1Ch { get; set; } // 0x00000000 public ulong DataPointer2 { get; set; } public uint Unknown_28h { get; set; } // 0x00000000 public uint Unknown_2Ch { get; set; } // 0x00000000 public ulong InfoPointer { get; set; } public uint Unknown_38h { get; set; } // 0x00000000 public uint Unknown_3Ch { get; set; } // 0x00000000 public uint Unknown_40h { get; set; } // 0x00000000 public uint Unknown_44h { get; set; } // 0x00000000 public uint Unknown_48h { get; set; } // 0x00000000 public uint Unknown_4Ch { get; set; } // 0x00000000 public uint Unknown_50h { get; set; } // 0x00000000 public uint Unknown_54h { get; set; } // 0x00000000 public uint Unknown_58h { get; set; } // 0x00000000 public uint Unknown_5Ch { get; set; } // 0x00000000 public uint Unknown_60h { get; set; } // 0x00000000 public uint Unknown_64h { get; set; } // 0x00000000 public uint Unknown_68h { get; set; } // 0x00000000 public uint Unknown_6Ch { get; set; } // 0x00000000 public uint Unknown_70h { get; set; } // 0x00000000 public uint Unknown_74h { get; set; } // 0x00000000 public uint Unknown_78h { get; set; } // 0x00000000 public uint Unknown_7Ch { get; set; } // 0x00000000 // reference data public VertexData Data1 { get; set; } public VertexData Data2 { get; set; } public VertexDeclaration Info { get; set; } /// /// Reads the data-block from a stream. /// public override void Read(ResourceDataReader reader, params object[] parameters) { // read structure data this.VFT = reader.ReadUInt32(); this.Unknown_4h = reader.ReadUInt32(); this.VertexStride = reader.ReadUInt16(); this.Unknown_Ah = reader.ReadUInt16(); this.Unknown_Ch = reader.ReadUInt32(); this.DataPointer1 = reader.ReadUInt64(); this.VertexCount = reader.ReadUInt32(); this.Unknown_1Ch = reader.ReadUInt32(); this.DataPointer2 = reader.ReadUInt64(); this.Unknown_28h = reader.ReadUInt32(); this.Unknown_2Ch = reader.ReadUInt32(); this.InfoPointer = reader.ReadUInt64(); this.Unknown_38h = reader.ReadUInt32(); this.Unknown_3Ch = reader.ReadUInt32(); this.Unknown_40h = reader.ReadUInt32(); this.Unknown_44h = reader.ReadUInt32(); this.Unknown_48h = reader.ReadUInt32(); this.Unknown_4Ch = reader.ReadUInt32(); this.Unknown_50h = reader.ReadUInt32(); this.Unknown_54h = reader.ReadUInt32(); this.Unknown_58h = reader.ReadUInt32(); this.Unknown_5Ch = reader.ReadUInt32(); this.Unknown_60h = reader.ReadUInt32(); this.Unknown_64h = reader.ReadUInt32(); this.Unknown_68h = reader.ReadUInt32(); this.Unknown_6Ch = reader.ReadUInt32(); this.Unknown_70h = reader.ReadUInt32(); this.Unknown_74h = reader.ReadUInt32(); this.Unknown_78h = reader.ReadUInt32(); this.Unknown_7Ch = reader.ReadUInt32(); // read reference data this.Info = reader.ReadBlockAt( this.InfoPointer // offset ); this.Data1 = reader.ReadBlockAt( this.DataPointer1, // offset this.VertexStride, this.VertexCount, this.Info ); this.Data2 = reader.ReadBlockAt( this.DataPointer2, // offset this.VertexStride, this.VertexCount, this.Info ); } /// /// Writes the data-block to a stream. /// public override void Write(ResourceDataWriter writer, params object[] parameters) { // update structure data this.VertexCount = (uint)(this.Data1 != null ? this.Data1.VertexCount : this.Data2 != null ? this.Data2.VertexCount : 0); this.DataPointer1 = (ulong)(this.Data1 != null ? this.Data1.FilePosition : 0); this.DataPointer2 = (ulong)(this.Data2 != null ? this.Data2.FilePosition : 0); this.InfoPointer = (ulong)(this.Info != null ? this.Info.FilePosition : 0); // write structure data writer.Write(this.VFT); writer.Write(this.Unknown_4h); writer.Write(this.VertexStride); writer.Write(this.Unknown_Ah); writer.Write(this.Unknown_Ch); writer.Write(this.DataPointer1); writer.Write(this.VertexCount); writer.Write(this.Unknown_1Ch); writer.Write(this.DataPointer2); writer.Write(this.Unknown_28h); writer.Write(this.Unknown_2Ch); writer.Write(this.InfoPointer); writer.Write(this.Unknown_38h); writer.Write(this.Unknown_3Ch); writer.Write(this.Unknown_40h); writer.Write(this.Unknown_44h); writer.Write(this.Unknown_48h); writer.Write(this.Unknown_4Ch); writer.Write(this.Unknown_50h); writer.Write(this.Unknown_54h); writer.Write(this.Unknown_58h); writer.Write(this.Unknown_5Ch); writer.Write(this.Unknown_60h); writer.Write(this.Unknown_64h); writer.Write(this.Unknown_68h); writer.Write(this.Unknown_6Ch); writer.Write(this.Unknown_70h); writer.Write(this.Unknown_74h); writer.Write(this.Unknown_78h); writer.Write(this.Unknown_7Ch); } /// /// Returns a list of data blocks which are referenced by this block. /// public override IResourceBlock[] GetReferences() { var list = new List(); if (Data1 != null) list.Add(Data1); if (Data2 != null) list.Add(Data2); if (Info != null) list.Add(Info); return list.ToArray(); } } [TypeConverter(typeof(ExpandableObjectConverter))] public class VertexData : ResourceSystemBlock { //private int length = 0; public override long BlockLength { get { return VertexBytes?.Length ?? 0; //this.length; } } public VertexDeclaration info { get; set; } public object[] Data { get; set; } public uint[] Types { get; set; } public VertexType VertexType { get; set; } public byte[] VertexBytes { get; set; } public int VertexCount { get; set; } public int VertexStride { get; set; } public long MemoryUsage { get { return (long)VertexCount * (long)VertexStride; } } public override void Read(ResourceDataReader reader, params object[] parameters) { VertexStride = Convert.ToInt32(parameters[0]); VertexCount = Convert.ToInt32(parameters[1]); info = (VertexDeclaration)parameters[2]; VertexType = (VertexType)info.Flags; VertexBytes = reader.ReadBytes(VertexCount * VertexStride); switch (info.Types) { case 8598872888530528662: //YDR - 0x7755555555996996 break; case 216172782140628998: //YFT - 0x030000000199A006 switch (info.Flags) { case 16473: VertexType = VertexType.PCCH2H4; break; // PCCH2H4 default:break; } break; case 216172782140612614: //YFT - 0x0300000001996006 PNCH2H4 switch (info.Flags) { case 89: VertexType = VertexType.PNCH2; break; // PNCH2 default: break; } break; default: break; } } public /*override*/ void ReadOrig(ResourceDataReader reader, params object[] parameters) { int stride = Convert.ToInt32(parameters[0]); int count = Convert.ToInt32(parameters[1]); var info = (VertexDeclaration)parameters[2]; this.VertexCount = count; this.info = info; bool[] IsUsed = new bool[16]; for (int i = 0; i < 16; i++) IsUsed[i] = ((info.Flags >> i) & 0x1) == 1; Types = new uint[16]; for (int i = 0; i < 16; i++) Types[i] = (uint)((info.Types >> (int)(4 * i)) & 0xF); Data = new object[16]; for (int i = 0; i < 16; i++) { if (IsUsed[i]) { switch (Types[i]) { case 0: Data[i] = new ushort[1 * count]; break; case 1: Data[i] = new ushort[2 * count]; break; case 2: Data[i] = new ushort[3 * count]; break; case 3: Data[i] = new ushort[4 * count]; break; case 4: Data[i] = new float[1 * count]; break; case 5: Data[i] = new float[2 * count]; break; case 6: Data[i] = new float[3 * count]; break; case 7: Data[i] = new float[4 * count]; break; case 8: Data[i] = new uint[count]; break; case 9: Data[i] = new uint[count]; break; case 10: Data[i] = new uint[count]; break; default: throw new Exception(); } } } long pos = reader.Position; // read... for (int i = 0; i < count; i++) { for (int k = 0; k < 16; k++) { if (IsUsed[k]) { switch (Types[k]) { // float16 case 0: { var buf = Data[k] as ushort[]; buf[i * 1 + 0] = reader.ReadUInt16(); break; } case 1: { var buf = Data[k] as ushort[]; buf[i * 2 + 0] = reader.ReadUInt16(); buf[i * 2 + 1] = reader.ReadUInt16(); break; } case 2: { var buf = Data[k] as ushort[]; buf[i * 3 + 0] = reader.ReadUInt16(); buf[i * 3 + 1] = reader.ReadUInt16(); buf[i * 3 + 2] = reader.ReadUInt16(); break; } case 3: { var buf = Data[k] as ushort[]; buf[i * 4 + 0] = reader.ReadUInt16(); buf[i * 4 + 1] = reader.ReadUInt16(); buf[i * 4 + 2] = reader.ReadUInt16(); buf[i * 4 + 3] = reader.ReadUInt16(); break; } // float32 case 4: { var buf = Data[k] as float[]; buf[i * 1 + 0] = reader.ReadSingle(); break; } case 5: { var buf = Data[k] as float[]; buf[i * 2 + 0] = reader.ReadSingle(); buf[i * 2 + 1] = reader.ReadSingle(); break; } case 6: { var buf = Data[k] as float[]; buf[i * 3 + 0] = reader.ReadSingle(); buf[i * 3 + 1] = reader.ReadSingle(); buf[i * 3 + 2] = reader.ReadSingle(); break; } case 7: { var buf = Data[k] as float[]; buf[i * 4 + 0] = reader.ReadSingle(); buf[i * 4 + 1] = reader.ReadSingle(); buf[i * 4 + 2] = reader.ReadSingle(); buf[i * 4 + 3] = reader.ReadSingle(); break; } case 8: case 9: case 10: { var buf = Data[k] as uint[]; buf[i * 1 + 0] = reader.ReadUInt32(); break; } default: throw new Exception(); } } } } //this.length = stride * count; } public /*override*/ void WriteOrig(ResourceDataWriter writer, params object[] parameters) { // write... for (int i = 0; i < VertexCount; i++) { for (int k = 0; k < 16; k++) { if (Data[k] != null) { switch (Types[k]) { // float16 case 0: { var buf = Data[k] as ushort[]; writer.Write(buf[i * 1 + 0]); break; } case 1: { var buf = Data[k] as ushort[]; writer.Write(buf[i * 2 + 0]); writer.Write(buf[i * 2 + 1]); break; } case 2: { var buf = Data[k] as ushort[]; writer.Write(buf[i * 3 + 0]); writer.Write(buf[i * 3 + 1]); writer.Write(buf[i * 3 + 2]); break; } case 3: { var buf = Data[k] as ushort[]; writer.Write(buf[i * 4 + 0]); writer.Write(buf[i * 4 + 1]); writer.Write(buf[i * 4 + 2]); writer.Write(buf[i * 4 + 3]); break; } // float32 case 4: { var buf = Data[k] as float[]; writer.Write(buf[i * 1 + 0]); break; } case 5: { var buf = Data[k] as float[]; writer.Write(buf[i * 2 + 0]); writer.Write(buf[i * 2 + 1]); break; } case 6: { var buf = Data[k] as float[]; writer.Write(buf[i * 3 + 0]); writer.Write(buf[i * 3 + 1]); writer.Write(buf[i * 3 + 2]); break; } case 7: { var buf = Data[k] as float[]; writer.Write(buf[i * 4 + 0]); writer.Write(buf[i * 4 + 1]); writer.Write(buf[i * 4 + 2]); writer.Write(buf[i * 4 + 3]); break; } case 8: case 9: case 10: { var buf = Data[k] as uint[]; writer.Write(buf[i * 1 + 0]); break; } default: throw new Exception(); } } } } } public override void Write(ResourceDataWriter writer, params object[] parameters) { if (VertexBytes != null) { writer.Write(VertexBytes); //not dealing with individual vertex data here any more! } } public override string ToString() { return "Type: " + VertexType.ToString() + ", Count: " + VertexCount.ToString(); } } [TypeConverter(typeof(ExpandableObjectConverter))] public class VertexDeclaration : ResourceSystemBlock { public override long BlockLength { get { return 16; } } // structure data public uint Flags { get; set; } public ushort Stride { get; set; } public byte Unknown_6h { get; set; } public byte Count { get; set; } public ulong Types { get; set; } /// /// Reads the data-block from a stream. /// public override void Read(ResourceDataReader reader, params object[] parameters) { // read structure data this.Flags = reader.ReadUInt32(); this.Stride = reader.ReadUInt16(); this.Unknown_6h = reader.ReadByte(); this.Count = reader.ReadByte(); this.Types = reader.ReadUInt64(); } /// /// Writes the data-block to a stream. /// public override void Write(ResourceDataWriter writer, params object[] parameters) { // write structure data writer.Write(this.Flags); writer.Write(this.Stride); writer.Write(this.Unknown_6h); writer.Write(this.Count); writer.Write(this.Types); } public ulong GetDeclarationId() { ulong res = 0; for(int i=0; i < 16; i++) { if (((Flags >> i) & 1) == 1) { res += (Types & (0xFu << (i * 4))); } } return res; } public override string ToString() { return Stride.ToString() + ": " + Count.ToString() + ": " + Flags.ToString() + ": " + Types.ToString(); } } [TypeConverter(typeof(ExpandableObjectConverter))] public class IndexBuffer : ResourceSystemBlock { public override long BlockLength { get { return 96; } } // structure data public uint VFT { get; set; } public uint Unknown_4h { get; set; } // 0x00000001 public uint IndicesCount { get; set; } public uint Unknown_Ch { get; set; } // 0x00000000 public ulong IndicesPointer { get; set; } public uint Unknown_18h { get; set; } // 0x00000000 public uint Unknown_1Ch { get; set; } // 0x00000000 public uint Unknown_20h { get; set; } // 0x00000000 public uint Unknown_24h { get; set; } // 0x00000000 public uint Unknown_28h { get; set; } // 0x00000000 public uint Unknown_2Ch { get; set; } // 0x00000000 public uint Unknown_30h { get; set; } // 0x00000000 public uint Unknown_34h { get; set; } // 0x00000000 public uint Unknown_38h { get; set; } // 0x00000000 public uint Unknown_3Ch { get; set; } // 0x00000000 public uint Unknown_40h { get; set; } // 0x00000000 public uint Unknown_44h { get; set; } // 0x00000000 public uint Unknown_48h { get; set; } // 0x00000000 public uint Unknown_4Ch { get; set; } // 0x00000000 public uint Unknown_50h { get; set; } // 0x00000000 public uint Unknown_54h { get; set; } // 0x00000000 public uint Unknown_58h { get; set; } // 0x00000000 public uint Unknown_5Ch { get; set; } // 0x00000000 // reference data //public ResourceSimpleArray Indices; public ushort[] Indices { get; set; } private ResourceSystemStructBlock IndicesBlock = null; //only used when saving /// /// Reads the data-block from a stream. /// public override void Read(ResourceDataReader reader, params object[] parameters) { // read structure data this.VFT = reader.ReadUInt32(); this.Unknown_4h = reader.ReadUInt32(); this.IndicesCount = reader.ReadUInt32(); this.Unknown_Ch = reader.ReadUInt32(); this.IndicesPointer = reader.ReadUInt64(); this.Unknown_18h = reader.ReadUInt32(); this.Unknown_1Ch = reader.ReadUInt32(); this.Unknown_20h = reader.ReadUInt32(); this.Unknown_24h = reader.ReadUInt32(); this.Unknown_28h = reader.ReadUInt32(); this.Unknown_2Ch = reader.ReadUInt32(); this.Unknown_30h = reader.ReadUInt32(); this.Unknown_34h = reader.ReadUInt32(); this.Unknown_38h = reader.ReadUInt32(); this.Unknown_3Ch = reader.ReadUInt32(); this.Unknown_40h = reader.ReadUInt32(); this.Unknown_44h = reader.ReadUInt32(); this.Unknown_48h = reader.ReadUInt32(); this.Unknown_4Ch = reader.ReadUInt32(); this.Unknown_50h = reader.ReadUInt32(); this.Unknown_54h = reader.ReadUInt32(); this.Unknown_58h = reader.ReadUInt32(); this.Unknown_5Ch = reader.ReadUInt32(); // read reference data //this.Indices = reader.ReadBlockAt>( // this.IndicesPointer, // offset // this.IndicesCount //); this.Indices = reader.ReadUshortsAt(this.IndicesPointer, this.IndicesCount); } /// /// Writes the data-block to a stream. /// public override void Write(ResourceDataWriter writer, params object[] parameters) { // update structure data this.IndicesCount = (uint)(this.IndicesBlock != null ? this.IndicesBlock.ItemCount : 0); this.IndicesPointer = (ulong)(this.IndicesBlock != null ? this.IndicesBlock.FilePosition : 0); // write structure data writer.Write(this.VFT); writer.Write(this.Unknown_4h); writer.Write(this.IndicesCount); writer.Write(this.Unknown_Ch); writer.Write(this.IndicesPointer); writer.Write(this.Unknown_18h); writer.Write(this.Unknown_1Ch); writer.Write(this.Unknown_20h); writer.Write(this.Unknown_24h); writer.Write(this.Unknown_28h); writer.Write(this.Unknown_2Ch); writer.Write(this.Unknown_30h); writer.Write(this.Unknown_34h); writer.Write(this.Unknown_38h); writer.Write(this.Unknown_3Ch); writer.Write(this.Unknown_40h); writer.Write(this.Unknown_44h); writer.Write(this.Unknown_48h); writer.Write(this.Unknown_4Ch); writer.Write(this.Unknown_50h); writer.Write(this.Unknown_54h); writer.Write(this.Unknown_58h); writer.Write(this.Unknown_5Ch); } /// /// Returns a list of data blocks which are referenced by this block. /// public override IResourceBlock[] GetReferences() { var list = new List(); if (Indices != null) { IndicesBlock = new ResourceSystemStructBlock(Indices); list.Add(IndicesBlock); } return list.ToArray(); } } public enum LightType : byte { Point = 1, Spot = 2, Capsule = 4, } [TypeConverter(typeof(ExpandableObjectConverter))] public struct LightAttributes_s { // structure data public uint Unknown_0h { get; set; } // 0x00000000 public uint Unknown_4h { get; set; } // 0x00000000 public Vector3 Position { get; set; } public uint Unknown_14h { get; set; } // 0x00000000 public byte ColorR { get; set; } public byte ColorG { get; set; } public byte ColorB { get; set; } public byte Flashiness { get; set; } public float Intensity { get; set; } public uint Flags { get; set; } public ushort BoneId { get; set; } public LightType Type { get; set; } public byte GroupId { get; set; } public uint TimeFlags { get; set; } public float Falloff { get; set; } public float FalloffExponent { get; set; } public Vector3 CullingPlaneNormal { get; set; } public float CullingPlaneOffset { get; set; } public byte ShadowBlur { get; set; } public byte Unknown_45h { get; set; } public ushort Unknown_46h { get; set; } public uint Unknown_48h { get; set; } // 0x00000000 public float VolumeIntensity { get; set; } public float VolumeSizeScale { get; set; } public byte VolumeOuterColorR { get; set; } public byte VolumeOuterColorG { get; set; } public byte VolumeOuterColorB { get; set; } public byte LightHash { get; set; } public float VolumeOuterIntensity { get; set; } public float CoronaSize { get; set; } public float VolumeOuterExponent { get; set; } public byte LightFadeDistance { get; set; } public byte ShadowFadeDistance { get; set; } public byte SpecularFadeDistance { get; set; } public byte VolumetricFadeDistance { get; set; } public float ShadowNearClip { get; set; } public float CoronaIntensity { get; set; } public float CoronaZBias { get; set; } public Vector3 Direction { get; set; } public Vector3 Tangent { get; set; } public float ConeInnerAngle { get; set; } public float ConeOuterAngle { get; set; } public Vector3 Extent { get; set; } public uint ProjectedTextureHash { get; set; } public uint Unknown_A4h { get; set; } // 0x00000000 } [TypeConverter(typeof(ExpandableObjectConverter))] public class DrawableBase : ResourceFileBase { public override long BlockLength { get { return 168; } } // structure data public ulong ShaderGroupPointer { get; set; } public ulong SkeletonPointer { get; set; } public Vector3 BoundingCenter { get; set; } public float BoundingSphereRadius { get; set; } public Vector4 BoundingBoxMin { get; set; } public Vector4 BoundingBoxMax { get; set; } public ulong DrawableModelsHighPointer { get; set; } public ulong DrawableModelsMediumPointer { get; set; } public ulong DrawableModelsLowPointer { get; set; } public ulong DrawableModelsVeryLowPointer { get; set; } public float LodDistHigh { get; set; } public float LodDistMed { get; set; } public float LodDistLow { get; set; } public float LodDistVlow { get; set; } public uint Unknown_80h { get; set; } public uint Unknown_84h { get; set; } public uint Unknown_88h { get; set; } public uint Unknown_8Ch { get; set; } public ulong JointsPointer { get; set; } public ushort Unknown_98h { get; set; } public ushort Unknown_9Ah { get; set; } public uint Unknown_9Ch { get; set; } // 0x00000000 public ulong DrawableModelsXPointer { get; set; } // reference data public ShaderGroup ShaderGroup { get; set; } public Skeleton Skeleton { get; set; } public ResourcePointerList64 DrawableModelsHigh { get; set; } public ResourcePointerList64 DrawableModelsMedium { get; set; } public ResourcePointerList64 DrawableModelsLow { get; set; } public ResourcePointerList64 DrawableModelsVeryLow { get; set; } public Joints Joints { get; set; } public ResourcePointerList64 DrawableModelsX { get; set; } public DrawableModel[] AllModels { get; set; } public Dictionary VertexDecls { get; set; } public object Owner { get; set; } public long MemoryUsage { get { long val = 0; if (AllModels != null) { foreach(DrawableModel m in AllModels) { if (m != null) { val += m.MemoryUsage; } } } if ((ShaderGroup != null) && (ShaderGroup.TextureDictionary != null)) { val += ShaderGroup.TextureDictionary.MemoryUsage; } return val; } } /// /// Reads the data-block from a stream. /// public override void Read(ResourceDataReader reader, params object[] parameters) { base.Read(reader, parameters); // read structure data this.ShaderGroupPointer = reader.ReadUInt64(); this.SkeletonPointer = reader.ReadUInt64(); this.BoundingCenter = reader.ReadStruct(); this.BoundingSphereRadius = reader.ReadSingle(); this.BoundingBoxMin = reader.ReadStruct(); this.BoundingBoxMax = reader.ReadStruct(); this.DrawableModelsHighPointer = reader.ReadUInt64(); this.DrawableModelsMediumPointer = reader.ReadUInt64(); this.DrawableModelsLowPointer = reader.ReadUInt64(); this.DrawableModelsVeryLowPointer = reader.ReadUInt64(); this.LodDistHigh = reader.ReadSingle(); this.LodDistMed = reader.ReadSingle(); this.LodDistLow = reader.ReadSingle(); this.LodDistVlow = reader.ReadSingle(); this.Unknown_80h = reader.ReadUInt32(); this.Unknown_84h = reader.ReadUInt32(); this.Unknown_88h = reader.ReadUInt32(); this.Unknown_8Ch = reader.ReadUInt32(); this.JointsPointer = reader.ReadUInt64(); this.Unknown_98h = reader.ReadUInt16(); this.Unknown_9Ah = reader.ReadUInt16(); this.Unknown_9Ch = reader.ReadUInt32(); this.DrawableModelsXPointer = reader.ReadUInt64(); // read reference data this.ShaderGroup = reader.ReadBlockAt( this.ShaderGroupPointer // offset ); this.Skeleton = reader.ReadBlockAt( this.SkeletonPointer // offset ); this.DrawableModelsHigh = reader.ReadBlockAt>( this.DrawableModelsHighPointer // offset ); this.DrawableModelsMedium = reader.ReadBlockAt>( this.DrawableModelsMediumPointer // offset ); this.DrawableModelsLow = reader.ReadBlockAt>( this.DrawableModelsLowPointer // offset ); this.DrawableModelsVeryLow = reader.ReadBlockAt>( this.DrawableModelsVeryLowPointer // offset ); this.Joints = reader.ReadBlockAt( this.JointsPointer // offset ); this.DrawableModelsX = reader.ReadBlockAt>( this.DrawableModelsXPointer // offset ); var allModels = new List(); if (DrawableModelsHigh != null) allModels.AddRange(DrawableModelsHigh.data_items); if (DrawableModelsMedium != null) allModels.AddRange(DrawableModelsMedium.data_items); if (DrawableModelsLow != null) allModels.AddRange(DrawableModelsLow.data_items); if (DrawableModelsVeryLow != null) allModels.AddRange(DrawableModelsVeryLow.data_items); if ((DrawableModelsX != null) && (DrawableModelsX != DrawableModelsHigh)) { allModels.AddRange(DrawableModelsX.data_items); } AllModels = allModels.ToArray(); var vds = new Dictionary(); foreach (DrawableModel model in AllModels) { foreach (var geom in model.Geometries.data_items) { var info = geom.VertexBuffer.Info; var declid = info.GetDeclarationId(); if (!vds.ContainsKey(declid)) { vds.Add(declid, info); } //else //debug test //{ // if ((VertexDecls[declid].Stride != info.Stride)||(VertexDecls[declid].Types != info.Types)) // { // } //} } } VertexDecls = new Dictionary(vds); AssignGeometryShaders(ShaderGroup); } public void AssignGeometryShaders(ShaderGroup shaderGrp) { if (shaderGrp != null) { ShaderGroup = shaderGrp; } //map the shaders to the geometries if (ShaderGroup != null) { var shaders = ShaderGroup.Shaders.data_items; foreach (DrawableModel model in AllModels) { if (model.Geometries == null) continue; if (model.Geometries.data_items == null) continue; if (model.ShaderMapping == null) continue; int geomcount = model.Geometries.data_items.Length; for (int i = 0; i < geomcount; i++) { var geom = model.Geometries.data_items[i]; ushort sid = (i < model.ShaderMapping.Length) ? model.ShaderMapping[i] : (ushort)0; geom.Shader = (sid < shaders.Length) ? shaders[sid] : null; geom.ShaderID = sid; } } } else { } } /// /// Writes the data-block to a stream. /// public override void Write(ResourceDataWriter writer, params object[] parameters) { base.Write(writer, parameters); // update structure data this.ShaderGroupPointer = (ulong)(this.ShaderGroup != null ? this.ShaderGroup.FilePosition : 0); this.SkeletonPointer = (ulong)(this.Skeleton != null ? this.Skeleton.FilePosition : 0); this.DrawableModelsHighPointer = (ulong)(this.DrawableModelsHigh != null ? this.DrawableModelsHigh.FilePosition : 0); this.DrawableModelsMediumPointer = (ulong)(this.DrawableModelsMedium != null ? this.DrawableModelsMedium.FilePosition : 0); this.DrawableModelsLowPointer = (ulong)(this.DrawableModelsLow != null ? this.DrawableModelsLow.FilePosition : 0); this.DrawableModelsVeryLowPointer = (ulong)(this.DrawableModelsVeryLow != null ? this.DrawableModelsVeryLow.FilePosition : 0); this.JointsPointer = (ulong)(this.Joints != null ? this.Joints.FilePosition : 0); this.DrawableModelsXPointer = (ulong)(this.DrawableModelsX != null ? this.DrawableModelsX.FilePosition : 0); // write structure data writer.Write(this.ShaderGroupPointer); writer.Write(this.SkeletonPointer); writer.Write(this.BoundingCenter); writer.Write(this.BoundingSphereRadius); writer.Write(this.BoundingBoxMin); writer.Write(this.BoundingBoxMax); writer.Write(this.DrawableModelsHighPointer); writer.Write(this.DrawableModelsMediumPointer); writer.Write(this.DrawableModelsLowPointer); writer.Write(this.DrawableModelsVeryLowPointer); writer.Write(this.LodDistHigh); writer.Write(this.LodDistMed); writer.Write(this.LodDistLow); writer.Write(this.LodDistVlow); writer.Write(this.Unknown_80h); writer.Write(this.Unknown_84h); writer.Write(this.Unknown_88h); writer.Write(this.Unknown_8Ch); writer.Write(this.JointsPointer); writer.Write(this.Unknown_98h); writer.Write(this.Unknown_9Ah); writer.Write(this.Unknown_9Ch); writer.Write(this.DrawableModelsXPointer); } /// /// Returns a list of data blocks which are referenced by this block. /// public override IResourceBlock[] GetReferences() { var list = new List(base.GetReferences()); if (ShaderGroup != null) list.Add(ShaderGroup); if (Skeleton != null) list.Add(Skeleton); if (DrawableModelsHigh != null) list.Add(DrawableModelsHigh); if (DrawableModelsMedium != null) list.Add(DrawableModelsMedium); if (DrawableModelsLow != null) list.Add(DrawableModelsLow); if (DrawableModelsVeryLow != null) list.Add(DrawableModelsVeryLow); if (Joints != null) list.Add(Joints); if (DrawableModelsX != null) list.Add(DrawableModelsX); return list.ToArray(); } public DrawableBase ShallowCopy() { DrawableBase r = null; if (this is FragDrawable fd) { var f = new FragDrawable(); f.Unknown_0A8h = fd.Unknown_0A8h; f.Unknown_0ACh = fd.Unknown_0ACh; f.FragMatrix = fd.FragMatrix; f.FragMatricesIndsCount = fd.FragMatricesIndsCount; f.FragMatricesCount = fd.FragMatricesCount; f.Count3 = fd.Count3; f.Count4 = fd.Count4; f.Bound = fd.Bound; f.FragMatricesInds = fd.FragMatricesInds; f.FragMatrices = fd.FragMatrices; f.Name = fd.Name; f.OwnerFragment = fd.OwnerFragment; f.OwnerFragmentPhys = fd.OwnerFragmentPhys; r = f; } if (this is Drawable dd) { var d = new Drawable(); d.LightAttributes = dd.LightAttributes; d.Name = dd.Name; d.Bound = dd.Bound; r = d; } if (r != null) { r.BoundingCenter = BoundingCenter; r.BoundingSphereRadius = BoundingSphereRadius; r.BoundingBoxMin = BoundingBoxMin; r.BoundingBoxMax = BoundingBoxMax; r.LodDistHigh = LodDistHigh; r.LodDistMed = LodDistMed; r.LodDistLow = LodDistLow; r.LodDistVlow = LodDistVlow; r.Unknown_80h = Unknown_80h; r.Unknown_84h = Unknown_84h; r.Unknown_88h = Unknown_88h; r.Unknown_8Ch = Unknown_8Ch; r.Unknown_98h = Unknown_98h; r.Unknown_9Ah = Unknown_9Ah; r.ShaderGroup = ShaderGroup; r.Skeleton = Skeleton?.Clone(); r.DrawableModelsHigh = DrawableModelsHigh; r.DrawableModelsMedium = DrawableModelsMedium; r.DrawableModelsLow = DrawableModelsLow; r.DrawableModelsVeryLow = DrawableModelsVeryLow; r.DrawableModelsX = DrawableModelsX; r.Joints = Joints; r.AllModels = AllModels; r.VertexDecls = VertexDecls; r.Owner = Owner; } return r; } } [TypeConverter(typeof(ExpandableObjectConverter))] public class Drawable : DrawableBase { public override long BlockLength { get { return 208; } } // structure data public ulong NamePointer { get; set; } public ResourceSimpleList64_s LightAttributes { get; set; } public uint Unknown_C0h { get; set; } // 0x00000000 public uint Unknown_C4h { get; set; } // 0x00000000 public ulong BoundPointer { get; set; } // reference data public string Name { get; set; } public Bounds Bound { get; set; } public string ErrorMessage { get; set; } private string_r NameBlock = null;//only used when saving.. /// /// Reads the data-block from a stream. /// public override void Read(ResourceDataReader reader, params object[] parameters) { base.Read(reader, parameters); // read structure data this.NamePointer = reader.ReadUInt64(); this.LightAttributes = reader.ReadBlock>(); this.Unknown_C0h = reader.ReadUInt32(); this.Unknown_C4h = reader.ReadUInt32(); this.BoundPointer = reader.ReadUInt64(); try { // read reference data this.Name = reader.ReadStringAt(//BlockAt( this.NamePointer // offset ); this.Bound = reader.ReadBlockAt( this.BoundPointer // offset ); if (Bound != null) { Bound.Owner = this; } } catch (Exception ex) //sometimes error here for loading particles! different drawable type? base only? { ErrorMessage = ex.ToString(); } } /// /// Writes the data-block to a stream. /// public override void Write(ResourceDataWriter writer, params object[] parameters) { base.Write(writer, parameters); // update structure data this.NamePointer = (ulong)(this.NameBlock != null ? this.NameBlock.FilePosition : 0); this.BoundPointer = (ulong)(this.Bound != null ? this.Bound.FilePosition : 0); // write structure data writer.Write(this.NamePointer); writer.WriteBlock(this.LightAttributes); writer.Write(this.Unknown_C0h); writer.Write(this.Unknown_C4h); writer.Write(this.BoundPointer); } /// /// Returns a list of data blocks which are referenced by this block. /// public override IResourceBlock[] GetReferences() { var list = new List(base.GetReferences()); if (Name != null) { NameBlock = (string_r)Name; list.Add(NameBlock); } if (Bound != null) list.Add(Bound); return list.ToArray(); } public override Tuple[] GetParts() { return new Tuple[] { new Tuple(0xB0, LightAttributes), }; } public override string ToString() { return Name; } } [TypeConverter(typeof(ExpandableObjectConverter))] public class DrawableBaseDictionary : ResourceFileBase { public override long BlockLength { get { return 64; } } // structure data public uint Unknown_10h { get; set; } public uint Unknown_14h { get; set; } public uint Unknown_18h { get; set; } public uint Unknown_1Ch { get; set; } public ulong HashesPointer { get; set; } public ushort HashesCount1 { get; set; } public ushort HashesCount2 { get; set; } public uint Unknown_2Ch { get; set; } public ulong DrawablesPointer { get; set; } public ushort DrawablesCount1 { get; set; } public ushort DrawablesCount2 { get; set; } public uint Unknown_3Ch { get; set; } // reference data //public ResourceSimpleArray Hashes { get; set; } public uint[] Hashes { get; set; } public ResourcePointerArray64 Drawables { get; set; } private ResourceSystemStructBlock HashesBlock = null;//only used for saving /// /// Reads the data-block from a stream. /// public override void Read(ResourceDataReader reader, params object[] parameters) { base.Read(reader, parameters); // read structure data this.Unknown_10h = reader.ReadUInt32(); this.Unknown_14h = reader.ReadUInt32(); this.Unknown_18h = reader.ReadUInt32(); this.Unknown_1Ch = reader.ReadUInt32(); this.HashesPointer = reader.ReadUInt64(); this.HashesCount1 = reader.ReadUInt16(); this.HashesCount2 = reader.ReadUInt16(); this.Unknown_2Ch = reader.ReadUInt32(); this.DrawablesPointer = reader.ReadUInt64(); this.DrawablesCount1 = reader.ReadUInt16(); this.DrawablesCount2 = reader.ReadUInt16(); this.Unknown_3Ch = reader.ReadUInt32(); // read reference data //this.Hashes = reader.ReadBlockAt>( // this.HashesPointer, // offset // this.HashesCount1 //); this.Hashes = reader.ReadUintsAt(this.HashesPointer, this.HashesCount1); this.Drawables = reader.ReadBlockAt>( this.DrawablesPointer, // offset this.DrawablesCount1 ); } /// /// Writes the data-block to a stream. /// public override void Write(ResourceDataWriter writer, params object[] parameters) { base.Write(writer, parameters); // update structure data this.HashesPointer = (ulong)(this.HashesBlock != null ? this.HashesBlock.FilePosition : 0); this.HashesCount1 = (ushort)(this.HashesBlock != null ? this.HashesBlock.ItemCount : 0); this.HashesCount2 = (ushort)(this.HashesBlock != null ? this.HashesBlock.ItemCount : 0); this.DrawablesPointer = (ulong)(this.Drawables != null ? this.Drawables.FilePosition : 0); this.DrawablesCount1 = (ushort)(this.Drawables != null ? this.Drawables.Count : 0); this.DrawablesCount2 = (ushort)(this.Drawables != null ? this.Drawables.Count : 0); // write structure data writer.Write(this.Unknown_10h); writer.Write(this.Unknown_14h); writer.Write(this.Unknown_18h); writer.Write(this.Unknown_1Ch); writer.Write(this.HashesPointer); writer.Write(this.HashesCount1); writer.Write(this.HashesCount2); writer.Write(this.Unknown_2Ch); writer.Write(this.DrawablesPointer); writer.Write(this.DrawablesCount1); writer.Write(this.DrawablesCount2); writer.Write(this.Unknown_3Ch); } /// /// Returns a list of data blocks which are referenced by this block. /// public override IResourceBlock[] GetReferences() { var list = new List(base.GetReferences()); if (Hashes != null) { HashesBlock = new ResourceSystemStructBlock(Hashes); list.Add(HashesBlock); } if (Drawables != null) list.Add(Drawables); return list.ToArray(); } } [TypeConverter(typeof(ExpandableObjectConverter))] public class DrawableDictionary : ResourceFileBase { public override long BlockLength { get { return 64; } } // structure data public uint Unknown_10h { get; set; } // 0x00000000 public uint Unknown_14h { get; set; } // 0x00000000 public uint Unknown_18h { get; set; } // 0x00000001 public uint Unknown_1Ch { get; set; } // 0x00000000 public ulong HashesPointer { get; set; } public ushort HashesCount1 { get; set; } public ushort HashesCount2 { get; set; } public uint Unknown_2Ch { get; set; } // 0x00000000 public ulong DrawablesPointer { get; set; } public ushort DrawablesCount1 { get; set; } public ushort DrawablesCount2 { get; set; } public uint Unknown_3Ch { get; set; } // 0x00000000 // reference data //public ResourceSimpleArray Hashes { get; set; } public uint[] Hashes { get; set; } public ResourcePointerArray64 Drawables { get; set; } private ResourceSystemStructBlock HashesBlock = null;//only used for saving public long MemoryUsage { get { long val = 0; if ((Drawables != null) && (Drawables.data_items != null)) { foreach(var drawable in Drawables.data_items) { val += drawable.MemoryUsage; } } return val; } } /// /// Reads the data-block from a stream. /// public override void Read(ResourceDataReader reader, params object[] parameters) { base.Read(reader, parameters); // read structure data this.Unknown_10h = reader.ReadUInt32(); this.Unknown_14h = reader.ReadUInt32(); this.Unknown_18h = reader.ReadUInt32(); this.Unknown_1Ch = reader.ReadUInt32(); this.HashesPointer = reader.ReadUInt64(); this.HashesCount1 = reader.ReadUInt16(); this.HashesCount2 = reader.ReadUInt16(); this.Unknown_2Ch = reader.ReadUInt32(); this.DrawablesPointer = reader.ReadUInt64(); this.DrawablesCount1 = reader.ReadUInt16(); this.DrawablesCount2 = reader.ReadUInt16(); this.Unknown_3Ch = reader.ReadUInt32(); // read reference data this.Hashes = reader.ReadUintsAt(this.HashesPointer, this.HashesCount1); this.Drawables = reader.ReadBlockAt>( this.DrawablesPointer, // offset this.DrawablesCount1 ); } /// /// Writes the data-block to a stream. /// public override void Write(ResourceDataWriter writer, params object[] parameters) { base.Write(writer, parameters); // update structure data this.HashesPointer = (ulong)(this.HashesBlock != null ? this.HashesBlock.FilePosition : 0); this.HashesCount1 = (ushort)(this.HashesBlock != null ? this.HashesBlock.ItemCount : 0); this.HashesCount2 = (ushort)(this.HashesBlock != null ? this.HashesBlock.ItemCount : 0); this.DrawablesPointer = (ulong)(this.Drawables != null ? this.Drawables.FilePosition : 0); this.DrawablesCount1 = (ushort)(this.Drawables != null ? this.Drawables.Count : 0); this.DrawablesCount2 = (ushort)(this.Drawables != null ? this.Drawables.Count : 0); // write structure data writer.Write(this.Unknown_10h); writer.Write(this.Unknown_14h); writer.Write(this.Unknown_18h); writer.Write(this.Unknown_1Ch); writer.Write(this.HashesPointer); writer.Write(this.HashesCount1); writer.Write(this.HashesCount2); writer.Write(this.Unknown_2Ch); writer.Write(this.DrawablesPointer); writer.Write(this.DrawablesCount1); writer.Write(this.DrawablesCount2); writer.Write(this.Unknown_3Ch); } /// /// Returns a list of data blocks which are referenced by this block. /// public override IResourceBlock[] GetReferences() { var list = new List(base.GetReferences()); if (Hashes != null) { HashesBlock = new ResourceSystemStructBlock(Hashes); list.Add(HashesBlock); } if (Drawables != null) list.Add(Drawables); return list.ToArray(); } } }