public static void Import(FullModelData fmd, string path) { AnimationFile animationFile = new AnimationFile(); animationFile.Read(path); foreach (AnimationFileObject animationObject in animationFile.Objects) { Object3D object3D = fmd.GetObject3DByHash(new HashName(animationObject.Name)); Log.Default.Info("Trying to add animation to " + animationObject.Name); if (object3D != null) { Log.Default.Info("Found " + animationObject.Name); object3D.Animations.Clear(); // Kill the old anims. if (animationObject.RotationKeyframes.Count > 0) { QuatLinearRotationController quatLinearRotationController = AddRotations(object3D, animationObject.RotationKeyframes); fmd.AddSection(quatLinearRotationController); } if (animationObject.PositionKeyframes.Count > 0) { LinearVector3Controller linearVector3Controller = AddPositions(object3D, animationObject.PositionKeyframes); fmd.AddSection(linearVector3Controller); } } else { Log.Default.Info("Not Found " + animationObject.Name); } } }
public static void ExportFile(FullModelData data, string path) { //you remove items from the parsed_sections //you edit items in the parsed_sections, they will get read and exported //Sort the sections List <Animation> animation_sections = new List <Animation>(); List <Author> author_sections = new List <Author>(); List <ISection> material_sections = new List <ISection>(); List <Object3D> object3D_sections = new List <Object3D>(); List <Model> model_sections = new List <Model>(); List <ISection> other_sections = new List <ISection>(); // Discard the old hashlist // Note that we use ToArray, which allows us to mutate the list without breaking anything foreach (SectionHeader header in data.sections.ToArray()) { if (header.type == Tags.custom_hashlist_tag) { data.RemoveSection(header.id); } } CustomHashlist hashlist = new CustomHashlist(); data.AddSection(hashlist); foreach (SectionHeader sectionheader in data.sections) { if (!data.parsed_sections.Keys.Contains(sectionheader.id)) { Log.Default.Warn($"BUG: SectionHeader with id {sectionheader.id} has no counterpart in parsed_sections"); continue; } var section = data.parsed_sections[sectionheader.id]; if (section is Animation) { animation_sections.Add(section as Animation); } else if (section is Author) { author_sections.Add(section as Author); } else if (section is MaterialGroup) { foreach (var matsec in (section as MaterialGroup).Items) { if (!data.parsed_sections.ContainsKey(matsec.SectionId)) { throw new Exception($"BUG: In MaterialGroup {section.SectionId}, Material {matsec.SectionId} isn't registered as part of the .model we're saving"); } if (!material_sections.Contains(matsec)) { material_sections.Add(matsec); } } material_sections.Add(section); } else if (section is Model) // Has to be before Object3D, since it's a subclass. { model_sections.Add(section as Model); } else if (section is Object3D) { object3D_sections.Add(section as Object3D); } else if (section != null) { other_sections.Add(section as ISection); } else { Log.Default.Warn("BUG: Somehow a null or non-section found its way into the list of sections."); } if (section is IHashContainer container) { container.CollectHashes(hashlist); } } var sections_to_write = Enumerable.Empty <ISection>() .Concat(animation_sections) .Concat(author_sections) .Concat(material_sections) .Concat(object3D_sections) .Concat(model_sections) .Concat(other_sections) .OrderedDistinct() .ToList(); //after each section, you go back and enter it's new size using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write)) { using (BinaryWriter bw = new BinaryWriter(fs)) { bw.Write(-1); //the - (yyyy) bw.Write((UInt32)100); //Filesize (GO BACK AT END AND CHANGE!!!) int sectionCount = data.sections.Count; bw.Write(sectionCount); //Sections count foreach (var sec in sections_to_write) { sec.StreamWrite(bw); } if (sections_to_write.Count != sectionCount) { Log.Default.Warn($"BUG : There were {sectionCount} sections to write but {sections_to_write.Count} were written"); } if (data.leftover_data != null) { bw.Write(data.leftover_data); } fs.Position = 4; bw.Write((UInt32)fs.Length); } } }
public static void ImportNewObj(FullModelData fmd, String filepath, bool addNew, Func <string, Object3D> root_point, Importers.IOptionReceiver _) { Log.Default.Info("Importing new obj with file: {0}", filepath); //Preload the .obj List <obj_data> objects = new List <obj_data>(); List <obj_data> toAddObjects = new List <obj_data>(); using (FileStream fs = new FileStream(filepath, FileMode.Open, FileAccess.Read)) { using (StreamReader sr = new StreamReader(fs)) { string line; obj_data obj = new obj_data(); bool reading_faces = false; int prevMaxVerts = 0; int prevMaxUvs = 0; int prevMaxNorms = 0; string current_shade_group = null; while ((line = sr.ReadLine()) != null) { //preloading objects if (line.StartsWith("#")) { continue; } else if (line.StartsWith("o ") || line.StartsWith("g ")) { if (reading_faces) { reading_faces = false; prevMaxVerts += obj.verts.Count; prevMaxUvs += obj.uv.Count; prevMaxNorms += obj.normals.Count; objects.Add(obj); obj = new obj_data(); current_shade_group = null; } if (String.IsNullOrEmpty(obj.object_name)) { obj.object_name = line.Substring(2); Log.Default.Debug("Object {0} named: {1}", objects.Count + 1, obj.object_name); } } else if (line.StartsWith("usemtl ")) { obj.material_name = line.Substring(7); } else if (line.StartsWith("v ")) { if (reading_faces) { reading_faces = false; prevMaxVerts += obj.verts.Count; prevMaxUvs += obj.uv.Count; prevMaxNorms += obj.normals.Count; objects.Add(obj); obj = new obj_data(); } String[] verts = line.Replace(" ", " ").Split(' '); Vector3 vert = new Vector3(); vert.X = Convert.ToSingle(verts[1], CultureInfo.InvariantCulture); vert.Y = Convert.ToSingle(verts[2], CultureInfo.InvariantCulture); vert.Z = Convert.ToSingle(verts[3], CultureInfo.InvariantCulture); obj.verts.Add(vert); } else if (line.StartsWith("vt ")) { if (reading_faces) { reading_faces = false; prevMaxVerts += obj.verts.Count; prevMaxUvs += obj.uv.Count; prevMaxNorms += obj.normals.Count; objects.Add(obj); obj = new obj_data(); } String[] uvs = line.Split(' '); Vector2 uv = new Vector2(); uv.X = Convert.ToSingle(uvs[1], CultureInfo.InvariantCulture); uv.Y = Convert.ToSingle(uvs[2], CultureInfo.InvariantCulture); obj.uv.Add(uv); } else if (line.StartsWith("vn ")) { if (reading_faces) { reading_faces = false; prevMaxVerts += obj.verts.Count; prevMaxUvs += obj.uv.Count; prevMaxNorms += obj.normals.Count; objects.Add(obj); obj = new obj_data(); } String[] norms = line.Split(' '); Vector3 norm = new Vector3(); norm.X = Convert.ToSingle(norms[1], CultureInfo.InvariantCulture); norm.Y = Convert.ToSingle(norms[2], CultureInfo.InvariantCulture); norm.Z = Convert.ToSingle(norms[3], CultureInfo.InvariantCulture); obj.normals.Add(norm); } else if (line.StartsWith("s ")) { current_shade_group = line.Substring(2); } else if (line.StartsWith("f ")) { reading_faces = true; if (current_shade_group != null) { if (obj.shading_groups.ContainsKey(current_shade_group)) { obj.shading_groups[current_shade_group].Add(obj.faces.Count); } else { List <int> newfaces = new List <int>(); newfaces.Add(obj.faces.Count); obj.shading_groups.Add(current_shade_group, newfaces); } } String[] faces = line.Substring(2).Split(' '); for (int x = 0; x < 3; x++) { ushort fa = 0, fb = 0, fc = 0; if (obj.verts.Count > 0) { fa = (ushort)(Convert.ToUInt16(faces[x].Split('/')[0]) - prevMaxVerts - 1); } if (obj.uv.Count > 0) { fb = (ushort)(Convert.ToUInt16(faces[x].Split('/')[1]) - prevMaxUvs - 1); } if (obj.normals.Count > 0) { fc = (ushort)(Convert.ToUInt16(faces[x].Split('/')[2]) - prevMaxNorms - 1); } if (fa < 0 || fb < 0 || fc < 0) { throw new Exception("What the actual flapjack, something is *VERY* wrong"); } obj.faces.Add(new Face(fa, fb, fc)); } } } if (!objects.Contains(obj)) { objects.Add(obj); } } } //Read each object foreach (obj_data obj in objects) { //One would fix Tatsuto's broken shading here. //Locate the proper model var hashname = HashName.FromNumberOrString(obj.object_name); Model modelSection = fmd.parsed_sections .Where(i => i.Value is Model mod && hashname.Hash == mod.HashName.Hash) .Select(i => i.Value as Model) .FirstOrDefault(); //Apply new changes if (modelSection == null) { toAddObjects.Add(obj); continue; } PassthroughGP passthrough_section = modelSection.PassthroughGP; Geometry geometry_section = passthrough_section.Geometry; Topology topology_section = passthrough_section.Topology; AddObject(false, obj, modelSection, passthrough_section, geometry_section, topology_section); } //Add new objects if (addNew) { foreach (obj_data obj in toAddObjects) { //create new Model Material newMat = new Material(obj.material_name); fmd.AddSection(newMat); MaterialGroup newMatG = new MaterialGroup(newMat); fmd.AddSection(newMatG); Geometry newGeom = new Geometry(obj); fmd.AddSection(newGeom); Topology newTopo = new Topology(obj); fmd.AddSection(newTopo); PassthroughGP newPassGP = new PassthroughGP(newGeom, newTopo); fmd.AddSection(newPassGP); TopologyIP newTopoIP = new TopologyIP(newTopo); fmd.AddSection(newTopoIP); Object3D parent = root_point.Invoke(obj.object_name); Model newModel = new Model(obj, newPassGP, newTopoIP, newMatG, parent); fmd.AddSection(newModel); AddObject(true, obj, newModel, newPassGP, newGeom, newTopo); //Add new sections } } }