public static void TravelTree(ModelBone bone, ref CNT parent, bool root = false) { var cnt = new CNT(); if (root) { cnt = parent; } cnt.Name = bone.Name; cnt.Transform = new Matrix3D( bone.Transform.M11, bone.Transform.M12, bone.Transform.M13, bone.Transform.M21, bone.Transform.M22, bone.Transform.M23, bone.Transform.M31, bone.Transform.M32, bone.Transform.M33, bone.Transform.M41, bone.Transform.M42, bone.Transform.M43 ); switch (bone.Type) { case BoneType.Mesh: cnt.Section = CNT.NodeType.MODL; cnt.Model = bone.Mesh.Name; break; case BoneType.Light: cnt.Section = CNT.NodeType.LITg; cnt.EmbeddedLight = (bone.AttachmentFile == null); if (cnt.EmbeddedLight) { cnt.Light = (ToxicRagers.CarmageddonReincarnation.Formats.LIGHT)bone.Attachment; } else { cnt.LightName = bone.AttachmentFile; var light = bone.Attachment as ToxicRagers.CarmageddonReincarnation.Formats.LIGHT; if (light != null) { light.Save(Path.Combine(rootPath, cnt.LightName + ".light")); } } break; case BoneType.VFX: cnt.Section = CNT.NodeType.VFXI; cnt.VFXFile = bone.AttachmentFile; break; default: cnt.Section = CNT.NodeType.NULL; break; } foreach (var b in bone.Children) { TravelTree(b, ref cnt); } if (!root) { parent.Children.Add(cnt); } }
public override void Export(Asset asset, string path) { rootPath = Path.GetDirectoryName(path); var model = (asset as Model); var cnt = new CNT(); TravelTree(model.Root, ref cnt, true); cnt.Save(path); }
static void ProcessCNT(CNT cnt, Model model, int ParentBoneIndex = 0) { int boneIndex; SceneManager.Current.UpdateProgress(string.Format("Processing {0}", cnt.Name)); if (cnt.Section == CNT.NodeType.MODL || cnt.Section == CNT.NodeType.SKIN) { var m = SceneManager.Current.Content.Load<Model, MDLImporter>(cnt.Model, rootPath); boneIndex = model.AddMesh(m.Meshes[0], ParentBoneIndex); } else { boneIndex = model.AddMesh(null, ParentBoneIndex); switch (cnt.Section) { case CNT.NodeType.LITg: model.Bones[boneIndex].Type = BoneType.Light; if (cnt.EmbeddedLight) { model.Bones[boneIndex].Attachment = cnt.Light; } else { model.Bones[boneIndex].Attachment = SceneManager.Current.Content.Load<Model, LIGHTImporter>(cnt.LightName, rootPath).Bones[0].Attachment; model.Bones[boneIndex].AttachmentFile = cnt.LightName; } break; case CNT.NodeType.VFXI: model.Bones[boneIndex].Type = BoneType.VFX; model.Bones[boneIndex].AttachmentFile = cnt.VFXFile; break; } } model.SetName(cnt.Name, boneIndex); model.SetTransform( new Matrix4 ( cnt.Transform.M11, cnt.Transform.M12, cnt.Transform.M13, 0, cnt.Transform.M21, cnt.Transform.M22, cnt.Transform.M23, 0, cnt.Transform.M31, cnt.Transform.M32, cnt.Transform.M33, 0, cnt.Transform.M41, cnt.Transform.M42, cnt.Transform.M43, 1 ), boneIndex); foreach (CNT subcnt in cnt.Children) { ProcessCNT(subcnt, model, boneIndex); } }
private static void Save(BinaryWriter bw, CNT cnt) { int nameLength = cnt.Name.Length; int padding = (((nameLength / 4) + (nameLength % 4 > 0 ? 1 : 0)) * 4) - nameLength; bw.Write(nameLength); bw.WriteString(cnt.Name); bw.Write(new byte[padding]); bw.Write((byte)0); bw.Write((int)0); bw.Write(cnt.Transform.M11); bw.Write(cnt.Transform.M12); bw.Write(cnt.Transform.M13); bw.Write(cnt.Transform.M21); bw.Write(cnt.Transform.M22); bw.Write(cnt.Transform.M23); bw.Write(cnt.Transform.M31); bw.Write(cnt.Transform.M32); bw.Write(cnt.Transform.M33); bw.Write(cnt.Transform.M41); bw.Write(cnt.Transform.M42); bw.Write(cnt.Transform.M43); bw.WriteString(cnt.Section.ToString()); switch (cnt.Section) { case NodeType.LITg: if (cnt.EmbeddedLight) { bw.Write(2); LIGHT.Save(bw, cnt.Light); } else { bw.Write(3); nameLength = cnt.LightName.Length; padding = (((nameLength / 4) + (nameLength % 4 > 0 ? 1 : 0)) * 4) - nameLength; bw.Write(cnt.LightName.Length); bw.WriteString(cnt.LightName); bw.Write(new byte[padding]); } break; case NodeType.MODL: case NodeType.SKIN: nameLength = cnt.Model.Length; padding = (((nameLength / 4) + (nameLength % 4 > 0 ? 1 : 0)) * 4) - nameLength; bw.Write(nameLength); bw.WriteString(cnt.Model); bw.Write(new byte[padding]); break; case NodeType.NULL: break; default: throw new NotImplementedException(string.Format("Save code for CNT section {0} does not exist!", cnt.Section)); } bw.Write(cnt.Children.Count); foreach (CNT c in cnt.Children) { Save(bw, c); } bw.Write((int)0); }
// The Load(BinaryReader) version skips the header check and is used for recursive loading private static CNT Load(BinaryReader br, Version version, CNT parent = null) { CNT cnt = new CNT(); int nameLength, padding; if (parent != null) { cnt.parent = parent; } cnt.version = version; if (version.Major == 3) { cnt.name = br.ReadBytes(16).ToName(); Logger.LogToFile(Logger.LogLevel.Debug, "Name: \"{0}\"", cnt.Name); } else { nameLength = (int)br.ReadUInt32(); padding = (((nameLength / 4) + (nameLength % 4 > 0 ? 1 : 0)) * 4) - nameLength; cnt.name = br.ReadString(nameLength); br.ReadBytes(padding); Logger.LogToFile(Logger.LogLevel.Debug, "Name: \"{0}\" of length {1}, padding of {2}", cnt.Name, nameLength, padding); } byte flags = br.ReadByte(); while (flags != 0) { Logger.LogToFile(Logger.LogLevel.Debug, "Flags: {0}", flags); flags = br.ReadByte(); } br.ReadUInt32(); // zero terminator? cnt.transform = new Matrix3D( br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle() ); cnt.section = br.ReadString(4).ToEnum<NodeType>(); switch (cnt.section) { case NodeType.LITg: int resourceType = (int)br.ReadUInt32(); switch (resourceType) { case 2: // Embedded cnt.bEmbeddedLight = true; cnt.light = LIGHT.Load(br); break; case 3: // External nameLength = (int)br.ReadUInt32(); padding = (((nameLength / 4) + (nameLength % 4 > 0 ? 1 : 0)) * 4) - nameLength; cnt.lightName = br.ReadString(nameLength); br.ReadBytes(padding); Logger.LogToFile(Logger.LogLevel.Debug, "LITg: \"{0}\" of length {1}, padding of {2}", cnt.lightName, nameLength, padding); break; default: throw new NotImplementedException(string.Format("Unknown resource type: {0}. Aborting", resourceType)); } break; case NodeType.MODL: case NodeType.SKIN: if (version.Major == 3) { cnt.modelName = br.ReadBytes(16).ToName(); Logger.LogToFile(Logger.LogLevel.Debug, "MODL: \"{0}\"", cnt.Name); br.ReadBytes(16); } else { nameLength = (int)br.ReadUInt32(); padding = (((nameLength / 4) + (nameLength % 4 > 0 ? 1 : 0)) * 4) - nameLength; cnt.modelName = br.ReadString(nameLength); br.ReadBytes(padding); Logger.LogToFile(Logger.LogLevel.Debug, "{0}: \"{1}\" of length {2}, padding of {3}", cnt.section, cnt.modelName, nameLength, padding); } break; case NodeType.VFXI: nameLength = (int)br.ReadUInt32(); cnt.effectName = br.ReadString(nameLength); Logger.LogToFile(Logger.LogLevel.Debug, "VFXI: \"{0}\" of length {1}, padding of {2}", cnt.effectName, nameLength, 0); break; case NodeType.SPLN: Logger.LogToFile(Logger.LogLevel.Warning, "SPLN, skipping 88 bytes"); br.ReadBytes(88); break; case NodeType.NULL: break; // EMIT, EMT2 and LITd no longer occur in C:R case NodeType.LITd: Logger.LogToFile(Logger.LogLevel.Debug, "LITd, skipping 16 bytes"); br.ReadBytes(16); break; case NodeType.EMIT: // <= v4.0 int emitVersion = br.ReadByte(); int toSkip = (emitVersion == 6 ? 128 : 136); br.ReadBytes(25); Logger.LogToFile(Logger.LogLevel.Debug, "EMIT v{0}, skipping 26 bytes, reading a name (\"{1}\") and then skipping {2} bytes", emitVersion, br.ReadString((int)br.ReadUInt32()), toSkip); br.ReadBytes(toSkip); break; case NodeType.EMT2: // no longer in C:R br.ReadBytes(34); Logger.LogToFile(Logger.LogLevel.Debug, "EMT2, skipping 34 bytes, reading a name (\"{0}\") and then skipping 612 bytes", br.ReadString((int)br.ReadUInt32())); br.ReadBytes(612); break; default: Logger.LogToFile(Logger.LogLevel.Error, "Unknown section \"{0}\"; Aborting", cnt.section); return null; } int childNodes = (int)br.ReadUInt32(); for (int i = 0; i < childNodes; i++) { Logger.LogToFile(Logger.LogLevel.Debug, "Loading child {0} of {1}", (i + 1), childNodes); cnt.childNodes.Add(Load(br, version, cnt)); } br.ReadUInt32(); // Terminator return cnt; }