void Export_IBUF_Main(StreamWriter w, IBUF ibuf, MLOD.Mesh mesh) { if (ibuf == null) { w.WriteLine("; ibuf is null"); w.WriteLine("ibuf 0"); return; } w.WriteLine(string.Format("ibuf {0}", mesh.PrimitiveCount)); w.Export_IBUF(mpb, ibuf.GetIndices(mesh), IBUF.IndexCountFromPrimitiveType(mesh.PrimitiveType), mesh.PrimitiveCount); }
// Token: 0x06000004 RID: 4 RVA: 0x000022B8 File Offset: 0x000004B8 private static bool convertP3dFile(string srcPath, string dstPath = null, bool allowOverwriting = false) { if (!allowOverwriting && srcPath == dstPath) { Trace.WriteLine("Overwriting the source file is disabled."); return(false); } Trace.WriteLine(string.Format("Reading the p3d ('{0}')...", srcPath)); P3D instance = P3D.GetInstance(srcPath); if (instance is MLOD) { Trace.WriteLine(string.Format("'{0}' is already in editable MLOD format", srcPath)); } else { ODOL odol = instance as ODOL; if (odol != null) { Trace.WriteLine("ODOL was loaded successfully."); Trace.WriteLine("Start conversion..."); MLOD mlod = Conversion.ODOL2MLOD(odol); Trace.WriteLine("Conversion successful."); string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(srcPath); string directoryName = Path.GetDirectoryName(srcPath); dstPath = (dstPath ?? Path.Combine(directoryName, fileNameWithoutExtension + "_mlod.p3d")); Trace.WriteLine("Saving..."); mlod.writeToFile(dstPath, allowOverwriting); Trace.WriteLine(string.Format("MLOD successfully saved to '{0}'", dstPath)); return(true); } Trace.WriteLine(string.Format("'{0}' could not be loaded.", srcPath)); } return(false); }
void Export_VBUF_Main(StreamWriter w, VBUF vbuf, VRTF vrtf, float[] uvScales, MLOD.Mesh mesh) { if (vbuf == null) { w.WriteLine("; vbuf is null"); w.WriteLine("vbuf 0"); return; } meshExpImp.ModelBlocks.Vertex[] av = vbuf.GetVertices(mesh, vrtf, uvScales); w.WriteLine(string.Format("vbuf {0}", av.Length)); w.Export_VBUF(mpb, av, vrtf); }
public static void Export_SKIN(this StreamWriter w, MyProgressBar mpb, SKIN skin, MLOD.Mesh mesh) { if (skin == null) { w.WriteLine("; skin is null"); w.WriteLine("skin 0"); return; } if (!mesh.JointReferences.TrueForAll(x => skin.Bones.Exists(y => y.NameHash == x))) { w.WriteLine("; mesh.JointReferences references unknown bone."); w.WriteLine("skin 0"); return; } List<uint> seen = new List<uint>(); if (!mesh.JointReferences.TrueForAll(x => { if (seen.Contains(x)) return false; seen.Add(x); return true; })) { w.WriteLine("; mesh.JointReferences contains non-unique references."); w.WriteLine("skin 0"); return; } seen = null; w.WriteLine(string.Format("skin {0}", skin.Bones.Count)); mpb.Init("Export SKIN...", skin.Bones.Count); int i = 0; //Referenced bones //pre-20120601: foreach (var bone in skin.Bones.FindAll(x => mesh.JointReferences.Contains(x.NameHash))) foreach (var bone in ((IEnumerable<uint>)mesh.JointReferences).Select(hash => skin.Bones.Find(x => x.NameHash == hash))) { w.WriteLine(string.Format( //"{0} {1:X8} {2:R} {3:R} {4:R} {5:R} {6:R} {7:R} {8:R} {9:R} {10:R} {11:R} {12:R} {13:R}", "{0} {1:X8} {2:F6} {3:F6} {4:F6} {5:F6} {6:F6} {7:F6} {8:F6} {9:F6} {10:F6} {11:F6} {12:F6} {13:F6}", i++, bone.NameHash, bone.InverseBindPose.Right.X, bone.InverseBindPose.Right.Y, bone.InverseBindPose.Right.Z, bone.InverseBindPose.Translate.X, bone.InverseBindPose.Up.X, bone.InverseBindPose.Up.Y, bone.InverseBindPose.Up.Z, bone.InverseBindPose.Translate.Y, bone.InverseBindPose.Back.X, bone.InverseBindPose.Back.Y, bone.InverseBindPose.Back.Z, bone.InverseBindPose.Translate.Z)); mpb.Value++; } //Unreferenced bones foreach (var bone in skin.Bones.FindAll(x => !mesh.JointReferences.Contains(x.NameHash))) { w.WriteLine(string.Format( //"{0} {1:X8} {2:R} {3:R} {4:R} {5:R} {6:R} {7:R} {8:R} {9:R} {10:R} {11:R} {12:R} {13:R}", "{0} {1:X8} {2:F6} {3:F6} {4:F6} {5:F6} {6:F6} {7:F6} {8:F6} {9:F6} {10:F6} {11:F6} {12:F6} {13:F6}", i++, bone.NameHash, bone.InverseBindPose.Right.X, bone.InverseBindPose.Right.Y, bone.InverseBindPose.Right.Z, bone.InverseBindPose.Translate.X, bone.InverseBindPose.Up.X, bone.InverseBindPose.Up.Y, bone.InverseBindPose.Up.Z, bone.InverseBindPose.Translate.Y, bone.InverseBindPose.Back.X, bone.InverseBindPose.Back.Y, bone.InverseBindPose.Back.Z, bone.InverseBindPose.Translate.Z)); mpb.Value++; } w.Flush(); mpb.Done(); }
public static float[] GetUVScales(this GenericRCOLResource rcolResource, MLOD.Mesh mesh) { MATD matd = GetMATDforMesh(rcolResource, mesh.MaterialIndex); if (matd != null) { ShaderData data = (matd.Version < 0x0103 ? matd.Mtrl.SData : matd.Mtnf.SData).Find(x => x.Field == FieldType.UVScales); if (data != null) { if (data is ElementFloat3) { ElementFloat3 e = data as ElementFloat3; return new float[] { e.Data0, e.Data1, e.Data2, }; } else throw new InvalidOperationException(String.Format("Found UVScales of type '{0}'; expected 'ElementFloat3'.", data.GetType().Name)); } } return new float[] { 1f / 32767f, 0f, 0f, }; }
public void Export_MLOD(StreamWriter w, GenericRCOLResource rcolResource, MLOD mlod, MLOD.Mesh mesh) { float[] uvScales = rcolResource.GetUVScales(mesh); if (mesh.GeometryStates.Count > 0) { w.WriteLine(";"); w.WriteLine("; Extended format: GeoStates follow IBUF"); w.WriteLine(";"); } if (mesh.Flags != 0) { w.WriteLine(";"); w.WriteLine("; Extended format: MeshFlags follow IBUF" + (mesh.GeometryStates.Count > 0 ? " and GeoStates" : "")); w.WriteLine("; (They are ignored on import.)"); w.WriteLine(";"); } VRTF vrtf = GenericRCOLResource.ChunkReference.GetBlock(rcolResource, mesh.VertexFormatIndex) as VRTF; bool isDefault = vrtf == null; if (isDefault) { vrtf = VRTF.CreateDefaultForMesh(mesh); w.WriteLine(";;-marker: vrtf is default for mesh"); } w.Export_VRTF(mpb, vrtf); w.Export_SKIN(mpb, GenericRCOLResource.ChunkReference.GetBlock(rcolResource, mesh.SkinControllerIndex) as SKIN, mesh); Export_VBUF_Main(w, GenericRCOLResource.ChunkReference.GetBlock(rcolResource, mesh.VertexBufferIndex) as VBUF, vrtf, uvScales, mesh); Export_IBUF_Main(w, GenericRCOLResource.ChunkReference.GetBlock(rcolResource, mesh.IndexBufferIndex) as IBUF, mesh); //For backward compatibility, these come after the IBUFs Export_MeshGeoStates(w, vrtf, uvScales, mlod, mesh, GenericRCOLResource.ChunkReference.GetBlock(rcolResource, mesh.VertexBufferIndex) as VBUF, GenericRCOLResource.ChunkReference.GetBlock(rcolResource, mesh.IndexBufferIndex) as IBUF); if (mesh.Flags != 0) { w.WriteLine(";"); w.WriteLine("; Extended format: MeshFlags"); w.WriteLine(";"); w.WriteLine("flags " + mesh.Flags); w.Flush(); } }
public void Export_MLOD(StreamWriter w, GenericRCOLResource rcolResource, MLOD mlod, MLOD.Mesh mesh) { float[] uvScales = rcolResource.GetUVScales(mesh); VRTF vrtf = GenericRCOLResource.ChunkReference.GetBlock(rcolResource, mesh.VertexFormatIndex) as VRTF; bool isDefault = vrtf == null; if (isDefault) { vrtf = VRTF.CreateDefaultForMesh(mesh); w.WriteLine(";;-marker: vrtf is default for mesh"); } w.Export_VRTF(mpb, vrtf); w.Export_SKIN(mpb, GenericRCOLResource.ChunkReference.GetBlock(rcolResource, mesh.SkinControllerIndex) as SKIN, mesh); Export_VBUF_Main(w, GenericRCOLResource.ChunkReference.GetBlock(rcolResource, mesh.VertexBufferIndex) as VBUF, vrtf, uvScales, mesh); Export_IBUF_Main(w, GenericRCOLResource.ChunkReference.GetBlock(rcolResource, mesh.IndexBufferIndex) as IBUF, mesh); }
void Export_MeshGeoStates(StreamWriter w, VRTF vrtf, float[] uvScales, MLOD mlod, MLOD.Mesh mesh, VBUF vbuf, IBUF ibuf) { if (mesh.GeometryStates.Count <= 0) { return; } w.WriteLine(";"); w.WriteLine("; Extended format: GeoStates"); w.WriteLine(";"); w.Export_GEOS(mpb, mesh); for (int g = 0; g < mesh.GeometryStates.Count; g++) { Export_VBUF_Geos(w, vbuf, vrtf, uvScales, mesh, g); Export_IBUF_Geos(w, ibuf, mesh, g); } w.Flush(); }
//Match what Wes's compiler does public static void FixUVScales(this GenericRCOLResource rcolResource, MLOD.Mesh mesh) { MATD matd = GetMATDforMesh(rcolResource, mesh.MaterialIndex); if (matd == null) throw new ArgumentException("No MATD found for requested mesh"); foreach (FieldType ft in new FieldType[] { FieldType.UVScales, FieldType.DiffuseUVSelector, FieldType.SpecularUVSelector, }) { ShaderData data = (matd.Version < 0x0103 ? matd.Mtrl.SData : matd.Mtnf.SData).Find(x => x.Field == ft); if (data == null) continue; if (!(data is ElementFloat3)) throw new InvalidOperationException(String.Format("Found " + ft + " of type '{0}'; expected 'ElementFloat3'.", data.GetType().Name)); ElementFloat3 e = data as ElementFloat3; e.Data0 = 1f / short.MaxValue; e.Data1 = 0f; e.Data2 = 0f; } }
//find the chunk, replace the chunk, perhaps create or remove the reference public static void ReplaceChunk(this GenericRCOLResource rcolResource, MLOD.Mesh mesh, string field, IResourceKey rk, ARCOLBlock block) { ARCOLBlock current = GenericRCOLResource.ChunkReference.GetBlock(rcolResource, (GenericRCOLResource.ChunkReference)mesh[field].Value) as ARCOLBlock; if (block != null) { if (current != null) // replacing is easy { if (current.Tag != block.Tag) throw new Exception(string.Format("mesh field {0} is '{1}' but replacement is '{2}'.", field, current.Tag, block.Tag)); // ...not entirely sure if these are required... current.Data = block.Data; block = current; } else // adding is okay { rcolResource.ChunkEntries.Add(new GenericRCOLResource.ChunkEntry(0, null, new TGIBlock(0, null, rk), block)); mesh[field] = new TypedValue(typeof(GenericRCOLResource.ChunkReference), GenericRCOLResource.ChunkReference.CreateReference(rcolResource, rk), "X"); } } else // deleting is not allowed - we can only null the reference, not remove the chunk { mesh[field] = new TypedValue(typeof(GenericRCOLResource.ChunkReference), new GenericRCOLResource.ChunkReference(0, null, 0), "X"); } }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (String.IsNullOrEmpty(value as string)) { return(null); } var path = value as string; if (path != null && File.Exists(path)) { using (FileStream s = File.OpenRead(path)) { var rcol = new GenericRCOLResource(0, s); MLOD mlod = rcol.ChunkEntries .Where(x => x.RCOLBlock is MLOD) .Select(x => x.RCOLBlock) .Cast <MLOD>() .FirstOrDefault(); double minX = double.MaxValue, minZ = double.MaxValue, maxX = double.MinValue, maxZ = double.MinValue; var pnty = new List <Point[]>(); foreach (MLOD.Mesh mesh in mlod.Meshes) { var vbuf = GenericRCOLResource.ChunkReference.GetBlock(rcol, mesh.VertexBufferIndex) as VBUF; var ibuf = GenericRCOLResource.ChunkReference.GetBlock(rcol, mesh.IndexBufferIndex) as IBUF; var vrtf = GenericRCOLResource.ChunkReference.GetBlock(rcol, mesh.VertexFormatIndex) as VRTF; if (vrtf == null) { continue; } Vertex[] verts = vbuf.GetVertices(mesh, vrtf, null); int[] indices = ibuf.GetIndices(mesh); for (int i = 0; i < indices.Length / 3; i++) { var tst = new int[3]; var poly = new Point[3]; for (int j = 0; j < 3; j++) { Vertex vert = verts[indices[i * 3 + j]]; double x = (Offset + (vert.Position[0] * Scale)); double z = -(Offset + (vert.Position[2] * Scale)); poly[j] = new Point((int)x, (int)z); if (poly[j].X > maxX) { maxX = poly[j].X; } if (poly[j].X < minX) { minX = poly[j].X; } if (poly[j].Y > maxZ) { maxZ = poly[j].Y; } if (poly[j].Y < minZ) { minZ = poly[j].Y; } } pnty.Add(poly); } } var width = (int)(maxX - minX); var height = (int)(maxZ - minZ); var bmp = new Bitmap(width, height); Graphics gBmp = Graphics.FromImage(bmp); gBmp.CompositingMode = CompositingMode.SourceCopy; float bright = 1.1f; System.Drawing.Color c = System.Drawing.Color.FromArgb(255, Fill.R, Fill.G, Fill.B); System.Drawing.Color c2 = System.Drawing.Color.FromArgb(255, Stroke.R, Stroke.G, Stroke.B); var b = new SolidBrush(c); var b2 = new SolidBrush(c2); var pen = new Pen(b2); foreach (Point[] pointse in pnty) { Point[] scaled = pointse.Select(old => new Point((int)(old.X - minX), (int)(old.Y - minZ))).ToArray(); gBmp.FillPolygon(b, scaled); } foreach (Point[] pointse in pnty) { Point[] scaled = pointse.Select(old => new Point((int)(old.X - minX), (int)(old.Y - minZ))).ToArray(); gBmp.DrawPolygon(pen, scaled); } var bmpImg = new BitmapImage(); var ms = new MemoryStream(); bmp.Save(ms, ImageFormat.Png); ms.Position = 0L; bmpImg.BeginInit(); bmpImg.StreamSource = ms; bmpImg.EndInit(); return(bmpImg); } } return(null); }
//-- public void Import_Mesh(StreamReader r, MLOD.Mesh mesh, GenericRCOLResource rcolResource, MLOD mlod, IResourceKey defaultRK, out meshExpImp.ModelBlocks.Vertex[] mverts) { #region Import VRTF bool isDefaultVRTF = false; VRTF defaultForMesh = VRTF.CreateDefaultForMesh(mesh); VRTF vrtf = new VRTF(rcolResource.RequestedApiVersion, null) { Version = 2, Layouts = null, }; r.Import_VRTF(mpb, vrtf); IResourceKey vrtfRK = GenericRCOLResource.ChunkReference.GetKey(rcolResource, mesh.VertexFormatIndex); if (vrtfRK == null) { vrtfRK = GenericRCOLResource.ChunkReference.GetKey(rcolResource, mesh.SkinControllerIndex); if (vrtfRK == null) { vrtfRK = GenericRCOLResource.ChunkReference.GetKey(rcolResource, mesh.ScaleOffsetIndex); } if (vrtfRK == null) { vrtfRK = new TGIBlock(0, null, 0, 0, System.Security.Cryptography.FNV64.GetHash(DateTime.UtcNow.ToString() + defaultRK.ToString())); } vrtfRK = new TGIBlock(0, null, vrtfRK) { ResourceType = vrtf.ResourceType, }; } if (vrtf.Equals(defaultForMesh)) { isDefaultVRTF = true; mesh.VertexFormatIndex = new GenericRCOLResource.ChunkReference(0, null, 0);//Clear the reference } else { rcolResource.ReplaceChunk(mesh, "VertexFormatIndex", vrtfRK, vrtf); } #endregion #region Import SKIN // we need to read the data in the file... SKIN skin = new SKIN(rcolResource.RequestedApiVersion, null) { Version = 1, Bones = null, }; r.Import_SKIN(mpb, skin); // However, we do *NOT* want to update the RCOL with what we read - we are not replacing the object skeleton here #if UNDEF if (skin.Bones != null) { IResourceKey skinRK = GenericRCOLResource.ChunkReference.GetKey(rcolResource, mesh.SkinControllerIndex); if (skinRK == null) { skinRK = new TGIBlock(0, null, vrtfRK) { ResourceType = skin.ResourceType, } } ; rcolResource.ReplaceChunk(mesh, "SkinControllerIndex", skinRK, skin); } #endif #endregion mverts = Import_VBUF_Main(r, mlod, mesh, vrtf, isDefaultVRTF); #region Import IBUF IBUF ibuf = GenericRCOLResource.ChunkReference.GetBlock(rcolResource, mesh.IndexBufferIndex) as IBUF; if (ibuf == null) { ibuf = new IBUF(rcolResource.RequestedApiVersion, null) { Version = 2, Flags = IBUF.FormatFlags.DifferencedIndices, DisplayListUsage = 0, } } ; Import_IBUF_Main(r, mlod, mesh, ibuf); IResourceKey ibufRK = GenericRCOLResource.ChunkReference.GetKey(rcolResource, mesh.IndexBufferIndex); if (ibufRK == null) { ibufRK = new TGIBlock(0, null, defaultRK) { ResourceType = ibuf.ResourceType, } } ; rcolResource.ReplaceChunk(mesh, "IndexBufferIndex", ibufRK, ibuf); #endregion #region Update the JointReferences UIntList joints = CreateJointReferences(mesh, mverts, skin); List <uint> added = new List <uint>(joints); List <uint> removed = new List <uint>(); foreach (var j in mesh.JointReferences) { if (joints.Contains(j)) { added.Remove(j); } else { removed.Add(j); } } // Remove root removed.Remove(0xCD68F001); if (added.Count != 0) { mesh.JointReferences.AddRange(added); System.Windows.Forms.CopyableMessageBox.Show(String.Format("Mesh: 0x{0:X8}\nJointReferences with newly assigned (via BlendIndex) vertex: {1}\n({2})", mesh.Name, added.Count, String.Join(", ", added.ConvertAll <string>(a => "0x" + a.ToString("X8")).ToArray())), "Warning", System.Windows.Forms.CopyableMessageBoxButtons.OK, System.Windows.Forms.CopyableMessageBoxIcon.Warning); } // with the 20120601 change to export, this warning on import has lost its severity... and been dropped. #if UNDEF if (removed.Count != 0) { //#if UNDEF // http://dino.drealm.info/den/denforum/index.php?topic=394.msg3876#msg3876 removed.ForEach(j => mesh.JointReferences[mesh.JointReferences.IndexOf(j)] = 0); //#endif // However, OM felt more comfortable if there was some indication something a little odd was going on. System.Windows.Forms.CopyableMessageBox.Show(String.Format("Mesh: 0x{0:X8}\nJointReferences with no assigned (via BlendIndex) vertex: {1}\n({2})", mesh.Name, removed.Count, String.Join(", ", removed.ConvertAll <string>(a => "0x" + a.ToString("X8")).ToArray())), "Warning", System.Windows.Forms.CopyableMessageBoxButtons.OK, System.Windows.Forms.CopyableMessageBoxIcon.Warning); } #endif #endregion } ModelBlocks.Vertex[] Import_VBUF_Main(StreamReader r, MLOD mlod, MLOD.Mesh mesh, VRTF vrtf, bool isDefaultVRTF) { string tagLine = r.ReadTag(); string[] split = tagLine.Split(new char[] { ' ', }, StringSplitOptions.RemoveEmptyEntries); if (split.Length != 2) { throw new InvalidDataException("Invalid tag line read for 'vbuf'."); } if (split[0] != "vbuf") { throw new InvalidDataException("Expected line tag 'vbuf' not found."); } int count; if (!int.TryParse(split[1], out count)) { throw new InvalidDataException("'vbuf' line has invalid count."); } //Wes's MilkShape plug-in sends back the first line in all subsequent lines of a dropShadow. return(r.Import_VBUF(mpb, count, vrtf, (mesh.Flags & MeshFlags.ShadowCaster) == 0)); } void Import_IBUF_Main(StreamReader r, MLOD mlod, MLOD.Mesh mesh, IBUF ibuf) { string tagLine = r.ReadTag(); string[] split = tagLine.Split(new char[] { ' ', }, StringSplitOptions.RemoveEmptyEntries); if (split.Length != 2) { throw new InvalidDataException("Invalid tag line read for 'ibuf'."); } if (split[0] != "ibuf") { throw new InvalidDataException("Expected line tag 'ibuf' not found."); } int count; if (!int.TryParse(split[1], out count)) { throw new InvalidDataException("'ibuf' line has invalid count."); } ibuf.SetIndices(mlod, mesh, r.Import_IBUF(mpb, IBUF.IndexCountFromPrimitiveType(mesh.PrimitiveType), count)); } UIntList CreateJointReferences(MLOD.Mesh mesh, ModelBlocks.Vertex[] mverts, SKIN skin) { if (skin == null || skin.Bones == null) { return(new UIntList(null)); } int maxReference = -1; foreach (var vert in mverts) { if (vert.BlendIndices != null) { foreach (var reference in vert.BlendIndices) { if ((sbyte)reference > maxReference) { maxReference = reference; } } } } return(maxReference > -1 ? new UIntList(null, skin.Bones.GetRange(0, maxReference + 1).ConvertAll <uint>(x => x.NameHash)) : new UIntList(null)); }
void Export_VBUF_Geos(StreamWriter w, VBUF vbuf, VRTF vrtf, float[] uvScales, MLOD.Mesh mesh, int geoStateIndex) { if (vbuf == null) { w.WriteLine("; vbuf is null for geoState"); w.WriteLine(string.Format("vbuf {0} 0 0", geoStateIndex)); return; } MLOD.GeometryState geoState = mesh.GeometryStates[geoStateIndex]; if (geosVBUFIsContained(geoState, mesh)) w.WriteLine("; vbuf is contained within main mesh"); w.WriteLine(string.Format("vbuf {0} {1} {2}", geoStateIndex, geoState.MinVertexIndex, geoState.VertexCount)); if (geosVBUFIsContained(geoState, mesh)) return; w.Export_VBUF(mpb, vbuf.GetVertices(mesh, vrtf, geoState, uvScales), vrtf); }
public static void Import_GEOS(this StreamReader r, MyProgressBar mpb, MLOD.Mesh mesh) { if (r.EndOfStream) { mesh.GeometryStates = new MLOD.GeometryStateList(null); return; } string tagLine = r.ReadTag(); string[] split = tagLine.Split(new char[] { ' ', }, StringSplitOptions.RemoveEmptyEntries); if (split.Length != 2 || split[0] != "geos") return; int count; if (!int.TryParse(split[1], out count)) throw new InvalidDataException("'geos' line has invalid count."); mpb.Init("Import MeshGeoStates...", count); int sizePerPrimitive = IBUF.IndexCountFromPrimitiveType(mesh.PrimitiveType); int lastMinVertexIndex = mesh.MinVertexIndex; int lastVertexCount = 0; int lastStartIndex = mesh.PrimitiveCount * IBUF.IndexCountFromPrimitiveType(mesh.PrimitiveType); int lastPrimitiveCount = 0; for (int g = 0; g < count; g++) { split = r.ReadLine().Split(new char[] { ' ', }, StringSplitOptions.RemoveEmptyEntries); if (split.Length != 2) throw new InvalidDataException(string.Format("'geos' line {0} has invalid format.", g)); int index; if (!int.TryParse(split[0], out index)) throw new InvalidDataException(string.Format("'geos' line {0} has invalid line index.", g)); if (index != g) throw new InvalidDataException(string.Format("'geos' line {0} has incorrect line index value {1}.", g, index)); uint name; if (!uint.TryParse(split[1], System.Globalization.NumberStyles.HexNumber, null, out name)) throw new InvalidDataException(string.Format("'geos' line {0} has invalid name hash.", g)); if (g < mesh.GeometryStates.Count) { mesh.GeometryStates[g].Name = name; lastMinVertexIndex = mesh.GeometryStates[g].MinVertexIndex; lastVertexCount = mesh.GeometryStates[g].VertexCount; lastStartIndex = mesh.GeometryStates[g].StartIndex; lastPrimitiveCount = mesh.GeometryStates[g].PrimitiveCount; } else mesh.GeometryStates.Add(new MLOD.GeometryState(0, null) { Name = name, MinVertexIndex = lastMinVertexIndex + lastVertexCount, VertexCount = 0, StartIndex = lastStartIndex + lastPrimitiveCount * sizePerPrimitive, PrimitiveCount = 0, }); mpb.Value = g; } mpb.Done(); }
public static void Export_GEOS(this StreamWriter w, MyProgressBar mpb, MLOD.Mesh mesh) { w.WriteLine(string.Format("geos {0}", mesh.GeometryStates.Count)); for (int g = 0; g < mesh.GeometryStates.Count; g++) w.WriteLine(string.Format("{0} {1:X8}", g, mesh.GeometryStates[g].Name)); }
bool geosIBUFIsContained(MLOD.GeometryState geoState, int sizePerPrimitive, MLOD.Mesh mesh) { return geoState.StartIndex + geoState.PrimitiveCount * sizePerPrimitive <= mesh.StartIndex + mesh.PrimitiveCount * sizePerPrimitive; }
void Export_MeshGeoStates(StreamWriter w, VRTF vrtf, float[] uvScales, MLOD mlod, MLOD.Mesh mesh, VBUF vbuf, IBUF ibuf) { if (mesh.GeometryStates.Count <= 0) return; w.WriteLine(";"); w.WriteLine("; Extended format: GeoStates"); w.WriteLine(";"); w.Export_GEOS(mpb, mesh); for (int g = 0; g < mesh.GeometryStates.Count; g++) { Export_VBUF_Geos(w, vbuf, vrtf, uvScales, mesh, g); Export_IBUF_Geos(w, ibuf, mesh, g); } w.Flush(); }
private bool SetVertices(MLOD mlod, s3pi.GenericRCOLResource.GenericRCOLResource.ChunkReference myVBI, long beforeLength, int count, VRTF vrtf, IEnumerable<Vertex> vertices, float[] uvscales) { bool okay = true; byte[] before = new byte[beforeLength]; Array.Copy(mBuffer, before, before.Length); long afterPos = Math.Min(mBuffer.Length, beforeLength + (count * vrtf.Stride)); byte[] after = new byte[mBuffer.Length - afterPos]; Array.Copy(mBuffer, afterPos, after, 0, after.Length); long offset = 0; using (MemoryStream mg = new MemoryStream()) { if (!SetVertices(mg, vrtf, vertices, uvscales)) okay = false; offset = beforeLength + mg.Length - afterPos; mBuffer = new byte[before.Length + mg.Length + after.Length]; Array.Copy(before, mBuffer, before.Length); Array.Copy(mg.ToArray(), 0, mBuffer, before.Length, mg.Length); Array.Copy(after, 0, mBuffer, before.Length + mg.Length, after.Length); mg.Close(); } int voffset = (int)offset / vrtf.Stride; if (offset != 0) foreach (var m in mlod.Meshes.Where(m => m.VertexBufferIndex.Equals(myVBI) && m.StreamOffset > beforeLength)) { m.StreamOffset = (uint)(m.StreamOffset + offset); foreach (var g in m.GeometryStates) if (g.MinVertexIndex * vrtf.Stride > beforeLength) g.MinVertexIndex += voffset; } return okay; }
public bool SetVertices(MLOD mlod, MLOD.Mesh mesh, int geoIndex, VRTF vrtf, Vertex[] vertices, float[] uvscales) { return SetVertices(mlod, mesh, mesh.GeometryStates[geoIndex], vrtf, vertices, uvscales); }
public bool SetVertices(MLOD mlod, int meshIndex, VRTF vrtf, Vertex[] vertices, float[] uvscales) { return SetVertices(mlod, mlod.Meshes[meshIndex], vrtf, vertices, uvscales); }
public Vertex[] GetVertices(MLOD.Mesh mesh, VRTF vrtf, float[] uvscales) { return GetVertices(vrtf, mesh.StreamOffset, mesh.VertexCount, uvscales); }
public Int32[] GetIndices(MLOD.Mesh mesh, int geoStateIndex) { return GetIndices(mesh, mesh.GeometryStates[geoStateIndex]); }
public Int32[] GetIndices(MLOD.Mesh mesh) { return GetIndices(mesh.PrimitiveType, mesh.StartIndex, mesh.PrimitiveCount); }
//-- public void Import_Mesh(StreamReader r, MLOD.Mesh mesh, GenericRCOLResource rcolResource, MLOD mlod, IResourceKey defaultRK, out meshExpImp.ModelBlocks.Vertex[] mverts, out List <meshExpImp.ModelBlocks.Vertex[]> lverts) { #region Import VRTF bool isDefaultVRTF = false; VRTF defaultForMesh = VRTF.CreateDefaultForMesh(mesh); VRTF vrtf = new VRTF(rcolResource.RequestedApiVersion, null) { Version = 2, Layouts = null, }; r.Import_VRTF(mpb, vrtf); IResourceKey vrtfRK = GenericRCOLResource.ChunkReference.GetKey(rcolResource, mesh.VertexFormatIndex); if (vrtfRK == null) { vrtfRK = GenericRCOLResource.ChunkReference.GetKey(rcolResource, mesh.SkinControllerIndex); if (vrtfRK == null) { vrtfRK = GenericRCOLResource.ChunkReference.GetKey(rcolResource, mesh.ScaleOffsetIndex); } if (vrtfRK == null) { vrtfRK = new TGIBlock(0, null, 0, 0, System.Security.Cryptography.FNV64.GetHash(DateTime.UtcNow.ToString() + defaultRK.ToString())); } vrtfRK = new TGIBlock(0, null, vrtfRK) { ResourceType = vrtf.ResourceType, }; } if (vrtf.Equals(defaultForMesh)) { isDefaultVRTF = true; mesh.VertexFormatIndex = new GenericRCOLResource.ChunkReference(0, null, 0);//Clear the reference } else { rcolResource.ReplaceChunk(mesh, "VertexFormatIndex", vrtfRK, vrtf); } #endregion #region Import SKIN // we need to read the data in the file... SKIN skin = new SKIN(rcolResource.RequestedApiVersion, null) { Version = 1, Bones = null, }; r.Import_SKIN(mpb, skin); // However, we do *NOT* want to update the RCOL with what we read - we are not replacing the object skeleton here #if UNDEF if (skin.Bones != null) { IResourceKey skinRK = GenericRCOLResource.ChunkReference.GetKey(rcolResource, mesh.SkinControllerIndex); if (skinRK == null) { skinRK = new TGIBlock(0, null, vrtfRK) { ResourceType = skin.ResourceType, } } ; rcolResource.ReplaceChunk(mesh, "SkinControllerIndex", skinRK, skin); } #endif #endregion mverts = Import_VBUF_Main(r, mlod, mesh, vrtf, isDefaultVRTF); #region Import IBUF IBUF ibuf = GenericRCOLResource.ChunkReference.GetBlock(rcolResource, mesh.IndexBufferIndex) as IBUF; if (ibuf == null) { ibuf = new IBUF(rcolResource.RequestedApiVersion, null) { Version = 2, Flags = IBUF.FormatFlags.DifferencedIndices, DisplayListUsage = 0, } } ; Import_IBUF_Main(r, mlod, mesh, ibuf); IResourceKey ibufRK = GenericRCOLResource.ChunkReference.GetKey(rcolResource, mesh.IndexBufferIndex); if (ibufRK == null) { ibufRK = new TGIBlock(0, null, defaultRK) { ResourceType = ibuf.ResourceType, } } ; rcolResource.ReplaceChunk(mesh, "IndexBufferIndex", ibufRK, ibuf); #endregion // This reads both VBUF Vertex[]s and the ibufs; but the ibufs just go straight in quite happily lverts = Import_MeshGeoStates(r, mlod, mesh, vrtf, isDefaultVRTF, ibuf); #region Update the JointReferences UIntList joints = CreateJointReferences(mesh, mverts, lverts ?? new List <meshExpImp.ModelBlocks.Vertex[]>(), skin); List <uint> added = new List <uint>(joints); List <uint> removed = new List <uint>(); foreach (var j in mesh.JointReferences) { if (joints.Contains(j)) { added.Remove(j); } else { removed.Add(j); } } // Remove root removed.Remove(0xCD68F001); if (added.Count != 0) { mesh.JointReferences.AddRange(added); System.Windows.Forms.CopyableMessageBox.Show(String.Format("Mesh: 0x{0:X8}\nJointReferences with newly assigned (via BlendIndex) vertex: {1}\n({2})", mesh.Name, added.Count, String.Join(", ", added.ConvertAll <string>(a => "0x" + a.ToString("X8")).ToArray())), "Warning", System.Windows.Forms.CopyableMessageBoxButtons.OK, System.Windows.Forms.CopyableMessageBoxIcon.Warning); } // with the 20120601 change to export, this warning on import has lost its severity... and been dropped. #if UNDEF if (removed.Count != 0) { //#if UNDEF // http://dino.drealm.info/den/denforum/index.php?topic=394.msg3876#msg3876 removed.ForEach(j => mesh.JointReferences[mesh.JointReferences.IndexOf(j)] = 0); //#endif // However, OM felt more comfortable if there was some indication something a little odd was going on. System.Windows.Forms.CopyableMessageBox.Show(String.Format("Mesh: 0x{0:X8}\nJointReferences with no assigned (via BlendIndex) vertex: {1}\n({2})", mesh.Name, removed.Count, String.Join(", ", removed.ConvertAll <string>(a => "0x" + a.ToString("X8")).ToArray())), "Warning", System.Windows.Forms.CopyableMessageBoxButtons.OK, System.Windows.Forms.CopyableMessageBoxIcon.Warning); } #endif #endregion } meshExpImp.ModelBlocks.Vertex[] Import_VBUF_Main(StreamReader r, MLOD mlod, MLOD.Mesh mesh, VRTF vrtf, bool isDefaultVRTF) { string tagLine = r.ReadTag(); string[] split = tagLine.Split(new char[] { ' ', }, StringSplitOptions.RemoveEmptyEntries); if (split.Length != 2) { throw new InvalidDataException("Invalid tag line read for 'vbuf'."); } if (split[0] != "vbuf") { throw new InvalidDataException("Expected line tag 'vbuf' not found."); } int count; if (!int.TryParse(split[1], out count)) { throw new InvalidDataException("'vbuf' line has invalid count."); } return(r.Import_VBUF(mpb, count, vrtf)); } void Import_IBUF_Main(StreamReader r, MLOD mlod, MLOD.Mesh mesh, IBUF ibuf) { string tagLine = r.ReadTag(); string[] split = tagLine.Split(new char[] { ' ', }, StringSplitOptions.RemoveEmptyEntries); if (split.Length != 2) { throw new InvalidDataException("Invalid tag line read for 'ibuf'."); } if (split[0] != "ibuf") { throw new InvalidDataException("Expected line tag 'ibuf' not found."); } int count; if (!int.TryParse(split[1], out count)) { throw new InvalidDataException("'ibuf' line has invalid count."); } ibuf.SetIndices(mlod, mesh, r.Import_IBUF(mpb, IBUF.IndexCountFromPrimitiveType(mesh.PrimitiveType), count)); } List <meshExpImp.ModelBlocks.Vertex[]> Import_MeshGeoStates(StreamReader r, MLOD mlod, MLOD.Mesh mesh, VRTF vrtf, bool isDefaultVRTF, IBUF ibuf) { MLOD.GeometryStateList oldGeos = new MLOD.GeometryStateList(null, mesh.GeometryStates); r.Import_GEOS(mpb, mesh); if (mesh.GeometryStates.Count <= 0) { return(null); } List <meshExpImp.ModelBlocks.Vertex[]> lverts = new List <meshExpImp.ModelBlocks.Vertex[]>(); for (int g = 0; g < mesh.GeometryStates.Count; g++) { lverts.Add(Import_VBUF_Geos(r, mlod, mesh, g, vrtf, isDefaultVRTF)); Import_IBUF_Geos(r, mlod, mesh, g, ibuf); } return(lverts); } UIntList CreateJointReferences(MLOD.Mesh mesh, meshExpImp.ModelBlocks.Vertex[] mverts, List <meshExpImp.ModelBlocks.Vertex[]> lverts, SKIN skin) { if (skin == null || skin.Bones == null) { return(new UIntList(null)); } int maxReference = -1; lverts.Insert(0, mverts); foreach (var vertices in lverts) { if (vertices != null) { foreach (var vert in vertices) { if (vert.BlendIndices != null) { foreach (var reference in vert.BlendIndices) { if ((sbyte)reference > maxReference) { maxReference = reference; } } } } } } lverts.Remove(mverts); return(maxReference > -1 ? new UIntList(null, skin.Bones.GetRange(0, maxReference + 1).ConvertAll <uint>(x => x.NameHash)) : new UIntList(null)); } meshExpImp.ModelBlocks.Vertex[] Import_VBUF_Geos(StreamReader r, MLOD mlod, MLOD.Mesh mesh, int geoStateIndex, VRTF vrtf, bool isDefaultVRTF) { //w.WriteLine(string.Format("vbuf {0} {1} {2}", geoStateIndex, mesh.GeometryStates[geoStateIndex].MinVertexIndex, mesh.GeometryStates[geoStateIndex].VertexCount)); string tagLine = r.ReadTag(); string[] split = tagLine.Split(new char[] { ' ', }, StringSplitOptions.RemoveEmptyEntries); if (split.Length != 4) { throw new InvalidDataException(string.Format("Invalid tag line read for geoState {0} 'vbuf'.", geoStateIndex)); } if (split[0] != "vbuf") { throw new InvalidDataException("Expected line tag 'vbuf' not found."); } int lineIndex; if (!int.TryParse(split[1], out lineIndex)) { throw new InvalidDataException(string.Format("geoState {0} 'vbuf' line has invalid geoStateIndex.", geoStateIndex)); } if (lineIndex != geoStateIndex) { throw new InvalidDataException(string.Format("geoState {0} 'vbuf' line has incorrect geoStateIndex value {1}.", geoStateIndex, lineIndex)); } int minVertexIndex; if (!int.TryParse(split[2], out minVertexIndex)) { throw new InvalidDataException(string.Format("geoState {0} 'vbuf' line has invalid MinVertexIndex.", geoStateIndex)); } int vertexCount; if (!int.TryParse(split[3], out vertexCount)) { throw new InvalidDataException(string.Format("geoState {0} 'vbuf' line has invalid VertexCount.", geoStateIndex)); } if (minVertexIndex + vertexCount <= mesh.MinVertexIndex + mesh.VertexCount) { mesh.GeometryStates[geoStateIndex].MinVertexIndex = minVertexIndex; mesh.GeometryStates[geoStateIndex].VertexCount = vertexCount; return(null); } if (minVertexIndex != mesh.GeometryStates[geoStateIndex].MinVertexIndex) { throw new InvalidDataException(string.Format("geoState {0} 'vbuf' line has unexpected MinVertexIndex {1}; expected {2}.", geoStateIndex, minVertexIndex, mesh.GeometryStates[geoStateIndex].MinVertexIndex)); } return(r.Import_VBUF(mpb, vertexCount, vrtf)); } void Import_IBUF_Geos(StreamReader r, MLOD mlod, MLOD.Mesh mesh, int geoStateIndex, IBUF ibuf) { //w.WriteLine(string.Format("ibuf {0} {1} {2}", geoStateIndex, mesh.GeometryStates[geoStateIndex].StartIndex, mesh.GeometryStates[geoStateIndex].PrimitiveCount)); string tagLine = r.ReadTag(); string[] split = tagLine.Split(new char[] { ' ', }, StringSplitOptions.RemoveEmptyEntries); if (split.Length != 4) { throw new InvalidDataException("Invalid tag line read for 'ibuf'."); } if (split[0] != "ibuf") { throw new InvalidDataException("Expected line tag 'ibuf' not found."); } int lineIndex; if (!int.TryParse(split[1], out lineIndex)) { throw new InvalidDataException(string.Format("geoState {0} 'ibuf' line has invalid geoStateIndex.", geoStateIndex)); } if (lineIndex != geoStateIndex) { throw new InvalidDataException(string.Format("geoState {0} 'ibuf' line has incorrect geoStateIndex value {1}.", geoStateIndex, lineIndex)); } int startIndex; if (!int.TryParse(split[2], out startIndex)) { throw new InvalidDataException(string.Format("geoState {0} 'ibuf' line has invalid StartIndex.", geoStateIndex)); } int primitiveCount; if (!int.TryParse(split[3], out primitiveCount)) { throw new InvalidDataException(string.Format("geoState {0} 'ibuf' line has invalid PrimitiveCount.", geoStateIndex)); } int sizePerPrimitive = IBUF.IndexCountFromPrimitiveType(mesh.PrimitiveType); if (startIndex + primitiveCount * sizePerPrimitive <= mesh.StartIndex + mesh.PrimitiveCount * sizePerPrimitive) { mesh.GeometryStates[geoStateIndex].StartIndex = startIndex; mesh.GeometryStates[geoStateIndex].PrimitiveCount = primitiveCount; return; } if (startIndex != mesh.GeometryStates[geoStateIndex].StartIndex) { throw new InvalidDataException(string.Format("geoState {0} 'ibuf' line has unexpected StartIndex {1}; expected {2}.", geoStateIndex, startIndex, mesh.GeometryStates[geoStateIndex].StartIndex)); } ibuf.SetIndices(mlod, mesh, geoStateIndex, r.Import_IBUF(mpb, IBUF.IndexCountFromPrimitiveType(mesh.PrimitiveType), primitiveCount)); }
public Int32[] GetIndices(MLOD.Mesh mesh, MLOD.GeometryState geometryState) { return GetIndices(mesh.PrimitiveType, geometryState.StartIndex, geometryState.PrimitiveCount) .Select(x => x - geometryState.MinVertexIndex).ToArray(); }
void Export_IBUF_Geos(StreamWriter w, IBUF ibuf, MLOD.Mesh mesh, int geoStateIndex) { if (ibuf == null) { w.WriteLine("; ibuf is null for geoState"); w.WriteLine(string.Format("ibuf {0} 0 0", geoStateIndex)); return; } int sizePerPrimitive = IBUF.IndexCountFromPrimitiveType(mesh.PrimitiveType); MLOD.GeometryState geoState = mesh.GeometryStates[geoStateIndex]; if (geosIBUFIsContained(geoState, sizePerPrimitive, mesh)) w.WriteLine("; ibuf is contained within main mesh"); w.WriteLine(string.Format("ibuf {0} {1} {2}", geoStateIndex, geoState.StartIndex, geoState.PrimitiveCount)); if (geosIBUFIsContained(geoState, sizePerPrimitive, mesh)) return; w.Export_IBUF(mpb, ibuf.GetIndices(mesh, geoStateIndex), sizePerPrimitive, geoState.PrimitiveCount); }
public BoundingBox GetBoundingBox(MLOD.Mesh mesh, VRTF vrtf) { BoundingBox bbox = null; GetBoundingBox(GetVertices(mesh, vrtf, null), ref bbox); foreach (var geos in mesh.GeometryStates) GetBoundingBox(GetVertices(mesh, vrtf, geos, null), ref bbox); return bbox ?? new BoundingBox(0, null); }
public void SetIndices(MLOD mlod, MLOD.Mesh mesh, Int32[] indices) { SetIndices(mlod, mesh.IndexBufferIndex, mesh.PrimitiveType, mesh.StartIndex, mesh.PrimitiveCount, indices); mesh.PrimitiveCount = indices.Length / IndexCountFromPrimitiveType(mesh.PrimitiveType); }
public Vertex[] GetVertices(MLOD.Mesh mesh, VRTF vrtf, MLOD.GeometryState geo, float[] uvscales) { return GetVertices(vrtf, mesh.StreamOffset + (geo.MinVertexIndex * vrtf.Stride), geo.VertexCount, uvscales); }
public void SetIndices(MLOD mlod, MLOD.Mesh mesh, int geoStateIndex, Int32[] indices) { MLOD.GeometryState geometryState = mesh.GeometryStates[geoStateIndex]; SetIndices(mlod, mesh, geometryState, indices); }
public bool SetVertices(MLOD mlod, MLOD.Mesh mesh, VRTF vrtf, Vertex[] vertices, float[] uvscales) { bool okay = SetVertices(mlod, mesh.VertexBufferIndex, mesh.StreamOffset, mesh.VertexCount, vrtf, vertices, uvscales); mesh.VertexCount = vertices.Length; return okay; }
public void SetIndices(MLOD mlod, MLOD.Mesh mesh, MLOD.GeometryState geometryState, Int32[] indices) { SetIndices(mlod, mesh.IndexBufferIndex, mesh.PrimitiveType, geometryState.StartIndex, geometryState.PrimitiveCount, indices.Select(x => x + geometryState.MinVertexIndex).ToArray()); geometryState.PrimitiveCount = indices.Length / IndexCountFromPrimitiveType(mesh.PrimitiveType); }
public bool SetVertices(MLOD mlod, MLOD.Mesh mesh, MLOD.GeometryState geo, VRTF vrtf, Vertex[] vertices, float[] uvscales) { long beforeLength = mesh.StreamOffset + (geo.MinVertexIndex * vrtf.Stride); bool okay = SetVertices(mlod, mesh.VertexBufferIndex, beforeLength, geo.VertexCount, vrtf, vertices, uvscales); geo.VertexCount = vertices.Length; return okay; }
void SetIndices(MLOD mlod, s4pi.GenericRCOLResource.GenericRCOLResource.ChunkReference myIBI, ModelPrimitiveType type, Int32 startIndex, Int32 primCount, Int32[] indices) { SetIndices(mlod, myIBI, startIndex, startIndex + primCount * IndexCountFromPrimitiveType(type), indices); }
private void Export_Shown(object sender, EventArgs e) { try { sfdExport.Title += " -- Test version " + typeof(ExportForm).Assembly.GetName().Version.ToString(); DialogResult dr = sfdExport.ShowDialog(); if (dr != DialogResult.OK) { Environment.ExitCode = 1; return; } string folder = Path.GetDirectoryName(sfdExport.FileName); string filebase = Path.GetFileNameWithoutExtension(sfdExport.FileName).Replace("_filebase", ""); try { using (FileStream fs = new FileStream(Path.Combine(folder, string.Format("{0}_filebase.s3asc", filebase)), FileMode.Create, FileAccess.Write)) { fs.Close(); } GenericRCOLResource rcolResource = new GenericRCOLResource(0, stream); MLOD mlod = null; if (rcolResource.ChunkEntries[0].TGIBlock.ResourceType == 0x01661233)//MODL { this.Text = "Export MODL..."; var lodRef = rcolResource.GetMLODChunkRefforMODL(); if (lodRef == null) { CopyableMessageBox.Show("MODL (0x01661233) with no MLOD (0x01D10F34).", "Invalid MODL resource", CopyableMessageBoxButtons.OK, CopyableMessageBoxIcon.Error); Environment.ExitCode = 1; return; } mlod = GenericRCOLResource.ChunkReference.GetBlock(rcolResource, lodRef) as MLOD; } else if (rcolResource.ChunkEntries[0].TGIBlock.ResourceType == 0x01D10F34)//MLOD { this.Text = "Export MLOD..."; mlod = rcolResource.ChunkEntries[0].RCOLBlock as MLOD; } else { CopyableMessageBox.Show("RCOL resource must be MODL (0x01661233) or MLOD (0x01D10F34).", "Invalid RCOL resource", CopyableMessageBoxButtons.OK, CopyableMessageBoxIcon.Error); Environment.ExitCode = 1; return; } Export export = new Export(new MyProgressBar(label1, pb)); for (int m = 0; m < mlod.Meshes.Count; m++) { string fnMesh = Path.Combine(folder, string.Format("{0}_group{1:D2}.s3ascg", filebase, m)); using (FileStream fsMesh = new FileStream(fnMesh, FileMode.Create, FileAccess.Write)) { export.Export_MLOD(new StreamWriter(fsMesh), rcolResource, mlod, mlod.Meshes[m]); fsMesh.Close(); } } Environment.ExitCode = 0; } catch (Exception ex) { CopyableMessageBox.IssueException(ex, "Error processing " + Program.Filename); throw ex; } } finally { this.Close(); } }
void SetIndices(MLOD mlod, s4pi.GenericRCOLResource.GenericRCOLResource.ChunkReference myIBI, Int32 beforeLength, Int32 afterPos, Int32[] indices) { Int32[] before = new Int32[beforeLength]; Array.Copy(mBuffer, 0, before, 0, before.Length); Int32[] after = new Int32[mBuffer.Length - afterPos]; Array.Copy(mBuffer, afterPos, after, 0, after.Length); mBuffer = new Int32[before.Length + indices.Length + after.Length]; Array.Copy(before, 0, mBuffer, 0, before.Length); Array.Copy(indices, 0, mBuffer, before.Length, indices.Length); Array.Copy(after, 0, mBuffer, before.Length + indices.Length, after.Length); int offset = beforeLength + indices.Length - afterPos; if (offset != 0) foreach (var m in mlod.Meshes.FindAll(m => m.IndexBufferIndex.Equals(myIBI))) if (m.StartIndex > beforeLength) { m.StartIndex += offset; foreach (var g in m.GeometryStates) if (g.StartIndex > beforeLength) g.StartIndex += offset; } }
public List <offScale> VertsToVBUFs(GenericRCOLResource rcolResource, MLOD mlod, IResourceKey defaultRK, List <meshExpImp.ModelBlocks.Vertex[]> lmverts, List <List <meshExpImp.ModelBlocks.Vertex[]> > llverts, bool updateBBs, bool updateUVs) { // List of UV elements going off scale List <offScale> offScales = new List <offScale>(); // Find everything for each mesh group Dictionary <GenericRCOLResource.ChunkReference, List <int> > meshGroups = new Dictionary <GenericRCOLResource.ChunkReference, List <int> >(); Dictionary <int, VRTF> meshVRTF = new Dictionary <int, VRTF>(); Dictionary <int, float[]> meshUVScales = new Dictionary <int, float[]>(); for (int m = 0; m < mlod.Meshes.Count; m++) { if (meshGroups.ContainsKey(mlod.Meshes[m].MaterialIndex)) { meshGroups[mlod.Meshes[m].MaterialIndex].Add(m); } else { meshGroups.Add(mlod.Meshes[m].MaterialIndex, new List <int> { m }); } VRTF vrtf = GenericRCOLResource.ChunkReference.GetBlock(rcolResource, mlod.Meshes[m].VertexFormatIndex) as VRTF ?? VRTF.CreateDefaultForMesh(mlod.Meshes[m]); meshVRTF.Add(m, vrtf); if (updateUVs) { rcolResource.FixUVScales(mlod.Meshes[m]); } meshUVScales.Add(m, rcolResource.GetUVScales(mlod.Meshes[m])); } // Update the VBUFs for each mesh group and set the mesh bounds whilst we're here foreach (var key in meshGroups.Keys) { foreach (int m in meshGroups[key]) { VBUF vbuf = GenericRCOLResource.ChunkReference.GetBlock(rcolResource, mlod.Meshes[m].VertexBufferIndex) as VBUF; if (vbuf == null) { vbuf = new VBUF(rcolResource.RequestedApiVersion, null) { Version = 0x00000101, Flags = VBUF.FormatFlags.None, SwizzleInfo = new GenericRCOLResource.ChunkReference(0, null, 0), } } ; offScales.AddRange(getOffScales(m, -1, lmverts[m], meshUVScales[m])); vbuf.SetVertices(mlod, m, meshVRTF[m], lmverts[m], meshUVScales[m]); if (llverts[m] != null) { for (int g = 0; g < llverts[m].Count; g++) { if (llverts[m][g] != null) { offScales.AddRange(getOffScales(m, g, llverts[m][g], meshUVScales[m])); vbuf.SetVertices(mlod, mlod.Meshes[m], g, meshVRTF[m], llverts[m][g], meshUVScales[m]); } } } IResourceKey vbufRK = GenericRCOLResource.ChunkReference.GetKey(rcolResource, mlod.Meshes[m].VertexBufferIndex); if (vbufRK == null)//means we created the VBUF: create a RK and add it { vbufRK = new TGIBlock(0, null, defaultRK) { ResourceType = vbuf.ResourceType, } } ; rcolResource.ReplaceChunk(mlod.Meshes[m], "VertexBufferIndex", vbufRK, vbuf); if (updateBBs) { mlod.Meshes[m].Bounds = vbuf.GetBoundingBox(mlod.Meshes[m], meshVRTF[m]); } } } return(offScales); }
private void Import_Shown(object sender, EventArgs e) { try { ofdImport.Title += " -- Test version " + typeof(ImportForm).Assembly.GetName().Version.ToString(); DialogResult dr = ofdImport.ShowDialog(); if (dr != DialogResult.OK) { Environment.ExitCode = 1; return; } string folder = Path.GetDirectoryName(ofdImport.FileName); string filebase = Path.GetFileNameWithoutExtension(ofdImport.FileName).Replace("_filebase", ""); if (!File.Exists(Path.Combine(folder, string.Format("{0}_filebase.s3m2b", filebase)))) { CopyableMessageBox.Show("File name must end \"_filebase.s3m2b\"", "Base file not found", CopyableMessageBoxButtons.OK, CopyableMessageBoxIcon.Error); Environment.ExitCode = 1; return; } bool updateBBs = false; int q = CopyableMessageBox.Show("Update mesh bounding boxes?", Application.ProductName, CopyableMessageBoxButtons.YesNoCancel, CopyableMessageBoxIcon.Question); if (q == 0) { updateBBs = true; } else if (q == 2) { Environment.ExitCode = 1; return; } bool updateUVs = false; q = CopyableMessageBox.Show("Maximise mapping area?", Application.ProductName, CopyableMessageBoxButtons.YesNoCancel, CopyableMessageBoxIcon.Question); if (q == 0) { updateUVs = true; } else if (q == 2) { Environment.ExitCode = 1; return; } try { GenericRCOLResource rcolResource = new GenericRCOLResource(0, stream); MLOD mlod = null; IResourceKey rk = null; if (rcolResource.ChunkEntries[0].TGIBlock.ResourceType == 0x01661233)//MODL { this.Text = "Import MODL..."; var lodRef = rcolResource.GetMLODChunkRefforMODL(); if (lodRef == null) { CopyableMessageBox.Show("MODL (0x01661233) with no MLOD (0x01D10F34).", "Invalid MODL resource", CopyableMessageBoxButtons.OK, CopyableMessageBoxIcon.Error); Environment.ExitCode = 1; return; } rk = GenericRCOLResource.ChunkReference.GetKey(rcolResource, lodRef); mlod = GenericRCOLResource.ChunkReference.GetBlock(rcolResource, lodRef) as MLOD; } else if (rcolResource.ChunkEntries[0].TGIBlock.ResourceType == 0x01D10F34)//MLOD { this.Text = "Import MLOD..."; rk = rcolResource.ChunkEntries[0].TGIBlock; mlod = rcolResource.ChunkEntries[0].RCOLBlock as MLOD; } else { CopyableMessageBox.Show("RCOL resource must be MODL (0x01661233) or MLOD (0x01D10F34).", "Invalid RCOL resource", CopyableMessageBoxButtons.OK, CopyableMessageBoxIcon.Error); Environment.ExitCode = 1; return; } Import import = new Import(new MyProgressBar(label1, pb)); int m = 0; List <meshExpImp.ModelBlocks.Vertex[]> lmverts = new List <meshExpImp.ModelBlocks.Vertex[]>(); List <List <meshExpImp.ModelBlocks.Vertex[]> > llverts = new List <List <meshExpImp.ModelBlocks.Vertex[]> >(); while (true) { string fnMesh = Path.Combine(folder, string.Format("{0}_group{1:D2}.s3m2bg", filebase, m)); if (!File.Exists(fnMesh)) { break; } using (FileStream fsMesh = new FileStream(fnMesh, FileMode.Open, FileAccess.Read)) { meshExpImp.ModelBlocks.Vertex[] mverts; List <meshExpImp.ModelBlocks.Vertex[]> lverts; import.Import_Mesh(new StreamReader(fsMesh), mlod.Meshes[m++], rcolResource, mlod, rk, out mverts, out lverts); lmverts.Add(mverts); llverts.Add(lverts); fsMesh.Close(); } } List <Import.offScale> offScales = import.VertsToVBUFs(rcolResource, mlod, rk, lmverts, llverts, updateBBs, updateUVs); if (offScales.Count > 0) { while (true) { switch ( CopyableMessageBox.Show( Application.ProductName + " has detected some off-scale UV mappings.\n" + "This may mean your mapping is not stored as you intended.\n" + "This is often caused by UV-mapping too close to the edge of the map.\n\n" + "Click 'Commit' to commit the change or 'Cancel' to abandon.", Application.ProductName, CopyableMessageBoxIcon.Warning, new String[] { "C&ommit", "&View", "C&ancel", }, 0, 2)) { case 0: //commit goto Commit; case 1: //view System.Text.StringBuilder sb = new System.Text.StringBuilder(); offScales.ForEach(x => sb.AppendLine(x.ToString())); CopyableMessageBox.Show(sb.ToString(), Application.ProductName, CopyableMessageBoxButtons.OK, CopyableMessageBoxIcon.Information); break; default: //cancel Environment.ExitCode = 1; return; } } } Commit: result = (byte[])rcolResource.AsBytes.Clone(); Environment.ExitCode = 0; } catch (Exception ex) { CopyableMessageBox.IssueException(ex, "Error processing " + Program.Filename); throw ex; } } finally { this.Close(); } }