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); }
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); }
//-- 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)); }
private void InitScene() { GeostatesPanel.Visibility = Visibility.Collapsed; GenericRCOLResource.ChunkEntry chunk = rcol.ChunkEntries.FirstOrDefault(x => x.RCOLBlock is MLOD); int polyCount = 0; int vertCount = 0; if (chunk != null) { var mlod = chunk.RCOLBlock as MLOD; foreach (MLOD.Mesh m in mlod.Meshes) { try { vertCount += m.VertexCount; polyCount += m.PrimitiveCount; var vbuf = (VBUF)GenericRCOLResource.ChunkReference.GetBlock(rcol, m.VertexBufferIndex); var ibuf = (IBUF)GenericRCOLResource.ChunkReference.GetBlock(rcol, m.IndexBufferIndex); VRTF vrtf = (VRTF)GenericRCOLResource.ChunkReference.GetBlock(rcol, m.VertexFormatIndex) ?? VRTF.CreateDefaultForMesh(m); IRCOLBlock material = GenericRCOLResource.ChunkReference.GetBlock(rcol, m.MaterialIndex); MATD matd = FindMainMATD(rcol, material); float[] uvscale = GetUvScales(matd); if (uvscale != null) { Debug.WriteLine(string.Format("{0} - {1} - {2}", uvscale[0], uvscale[2], uvscale[2])); } else { Debug.WriteLine("No scales"); } GeometryModel3D model = DrawModel(vbuf.GetVertices(m, vrtf, uvscale), ibuf.GetIndices(m), mNonSelectedMaterial); var sceneMesh = new SceneMlodMesh(m, model); if (matd != null) { sceneMesh.Shader = matd.Shader; switch (matd.Shader) { case ShaderType.ShadowMap: case ShaderType.DropShadow: break; default: var maskWidth = GetMATDParam <ElementInt>(matd, FieldType.MaskWidth); var maskHeight = GetMATDParam <ElementInt>(matd, FieldType.MaskHeight); if (maskWidth != null && maskHeight != null) { float scalar = Math.Max(maskWidth.Data, maskHeight.Data); mCheckerBrush.Transform = new ScaleTransform(maskHeight.Data / scalar, maskWidth.Data / scalar); } break; } } try { var sceneGeostates = new SceneGeostate[m.GeometryStates.Count]; for (int i = 0; i < sceneGeostates.Length; i++) { GeometryModel3D state = DrawModel(vbuf.GetVertices(m, vrtf, m.GeometryStates[i], uvscale), ibuf.GetIndices(m, m.GeometryStates[i]), mHiddenMaterial); mGroupMeshes.Children.Add(state); sceneGeostates[i] = new SceneGeostate(sceneMesh, m.GeometryStates[i], state); } sceneMesh.States = sceneGeostates; } catch (Exception ex) { MessageBox.Show("Unable to load Geostates. You may have some corrupted data: " + ex.ToString(), "Unable to load Geostates..."); } mGroupMeshes.Children.Add(model); mSceneMeshes.Add(sceneMesh); } catch (Exception ex) { MessageBox.Show(String.Format("Unable to load mesh id 0x{0:X8}", m.Name)); } } } else { GenericRCOLResource.ChunkEntry geomChunk = rcol.ChunkEntries.FirstOrDefault(); var geom = new GEOM(0, null, geomChunk.RCOLBlock.Stream); var verts = new List <Vertex>(); polyCount = geom.Faces.Count; vertCount = geom.VertexData.Count; foreach (GEOM.VertexDataElement vd in geom.VertexData) { var v = new Vertex(); var pos = (GEOM.PositionElement)vd.Vertex.FirstOrDefault(e => e is GEOM.PositionElement); if (pos != null) { v.Position = new[] { pos.X, pos.Y, pos.Z }; } var norm = (GEOM.NormalElement)vd.Vertex.FirstOrDefault(e => e is GEOM.NormalElement); if (norm != null) { v.Normal = new[] { norm.X, norm.Y, norm.Z }; } var uv = (GEOM.UVElement)vd.Vertex.FirstOrDefault(e => e is GEOM.UVElement); if (uv != null) { v.UV = new[] { new[] { uv.U, uv.V } }; } verts.Add(v); } var facepoints = new List <int>(); foreach (GEOM.Face face in geom.Faces) { facepoints.Add(face.VertexDataIndex0); facepoints.Add(face.VertexDataIndex1); facepoints.Add(face.VertexDataIndex2); } GeometryModel3D model = DrawModel(verts.ToArray(), facepoints.ToArray(), mNonSelectedMaterial); var sceneMesh = new SceneGeomMesh(geom, model); mGroupMeshes.Children.Add(model); mSceneMeshes.Add(sceneMesh); } foreach (SceneMesh s in mSceneMeshes) { mMeshListView.Items.Add(s); } if (mSceneMeshes.Count <= 1) { MeshesPanel.Visibility = Visibility.Collapsed; } VertexCount.Text = String.Format("Vertices: {0}", vertCount); PolygonCount.Text = String.Format("Polygons: {0}", polyCount); }
//-- 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)); }