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_VRTF(this StreamWriter w, MyProgressBar mpb, VRTF vrtf) { w.WriteLine(string.Format("vrtf {0} {1}", vrtf.Layouts.Count, vrtf.Stride)); mpb.Init("Export VRTF...", vrtf.Layouts.Count); for (int i = 0; i < vrtf.Layouts.Count; i++) { var l = vrtf.Layouts[i]; w.WriteLine(string.Format("{0} {1} {2} {3} {4}", i, (byte)l.Usage, l.UsageIndex, (byte)l.Format, l.Offset)); mpb.Value++; } w.Flush(); mpb.Done(); }
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 static void ReadUVData(byte[] data, VRTF.ElementLayout layout, ref float[] output, float scale) { byte[] element = new byte[VRTF.ByteSizeFromFormat(layout.Format)]; Array.Copy(data, layout.Offset, element, 0, element.Length); switch (layout.Format) { case VRTF.ElementFormat.Short2: for (int i = 0; i < output.Length; i++) { output[i] += (float)BitConverter.ToInt16(element, i * sizeof(short)) * scale; } break; case VRTF.ElementFormat.Short4: for (int i = 0; i < output.Length; i++) output[i] += (float)BitConverter.ToInt16(element, i * sizeof(short)) / short.MaxValue; break; case VRTF.ElementFormat.Short4_DropShadow: for (int i = 0; i < output.Length - 1; i++) output[i] += (float)BitConverter.ToInt16(element, i * sizeof(short)) / short.MaxValue; output[output.Length - 1] += (float)BitConverter.ToInt16(element, (output.Length - 1) * sizeof(short)) / 511; break; default: ReadFloatData(data, layout, ref output); break; } }
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 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); }
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; }
public static void Export_VBUF(this StreamWriter w, MyProgressBar mpb, meshExpImp.ModelBlocks.Vertex[] av, VRTF vrtf) { mpb.Init("Export VBUF...", av.Length); for (int i = 0; i < av.Length; i++) { meshExpImp.ModelBlocks.Vertex v = av[i]; int nUV = 0; foreach (var layout in vrtf.Layouts) { w.Write(string.Format("{0} {1}", i, (byte)layout.Usage)); switch (layout.Usage) { case VRTF.ElementUsage.Position: if (v.Position != null) { foreach (float f in v.Position) { w.Write(string.Format(" {0:F6}", f)); } } else { w.Write(" Position is null."); } break; case VRTF.ElementUsage.Normal: if (v.Normal != null) { foreach (float f in v.Normal) { w.Write(string.Format(" {0:F6}", f)); } } else { w.Write(" Normal is null."); } break; case VRTF.ElementUsage.UV: if (v.UV != null) { foreach (float f in v.UV[nUV]) { w.Write(string.Format(" {0:F6}", f)); } } else { w.Write(string.Format(" UV[{0}] is null.", nUV)); } nUV++; break; case VRTF.ElementUsage.BlendIndex: if (v.BlendIndices != null) { foreach (byte b in v.BlendIndices) { w.Write(string.Format(" {0}", b)); } } else { w.Write(" BlendIndices is null."); } break; case VRTF.ElementUsage.BlendWeight: if (v.BlendWeights != null) { foreach (float f in v.BlendWeights) { w.Write(string.Format(" {0:F6}", f)); } } else { w.Write(" BlendWeight is null."); } break; case VRTF.ElementUsage.Tangent: if (v.Tangents != null) { foreach (float f in v.Tangents) { w.Write(string.Format(" {0:F6}", f)); } } else { w.Write(" Tangents is null."); } break; case VRTF.ElementUsage.Colour: if (v.Color != null) { foreach (float f in v.Color) { w.Write(string.Format(" {0:F6}", f)); } } else { w.Write(" Colour is null."); } break; } w.WriteLine(); mpb.Value++; } } w.Flush(); mpb.Done(); }
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(); }
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 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); }
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); }
private static bool SetVertices(MemoryStream s, VRTF vrtf, IEnumerable<Vertex> vertices, float[] uvscales) { bool okay = true; PositionMinMax(vrtf, vertices); byte[] output = new byte[vrtf.Stride]; var position = vrtf.Layouts .FirstOrDefault(x => x.Usage == VRTF.ElementUsage.Position); var normal = vrtf.Layouts .FirstOrDefault(x => x.Usage == VRTF.ElementUsage.Normal); var uv = vrtf.Layouts .Where(x => x.Usage == VRTF.ElementUsage.UV) .ToArray(); var blendIndices = vrtf.Layouts .FirstOrDefault(x => x.Usage == VRTF.ElementUsage.BlendIndex); var blendWeights = vrtf.Layouts .FirstOrDefault(x => x.Usage == VRTF.ElementUsage.BlendWeight); var tangents = vrtf.Layouts .FirstOrDefault(x => x.Usage == VRTF.ElementUsage.Tangent); var color = vrtf.Layouts .FirstOrDefault(x => x.Usage == VRTF.ElementUsage.Colour); if (uvscales == null) uvscales = defaultUVScales; foreach (var v in vertices) { if (v.Position != null) WritePositionData(v.Position, position, output, positionMax); if (v.Normal != null) WriteFloatData(v.Normal, normal, output); for (int u = 0; u < uv.Length; u++) { var scale = u < uvscales.Length && uvscales[u] != 0 ? uvscales[u] : uvscales[0]; if (v.UV[u] != null) if (!WriteUVData(v.UV[u], uv[u], output, scale)) okay = false; } if (v.BlendIndices != null) Array.Copy(v.BlendIndices, 0, output, blendIndices.Offset, VRTF.ByteSizeFromFormat(blendIndices.Format)); if (v.BlendWeights != null) WriteFloatData(v.BlendWeights, blendWeights, output); if (v.Tangents != null) WriteFloatData(v.Tangents, tangents, output); if (v.Color != null) WriteFloatData(v.Color, color, output); s.Write(output, 0, output.Length); } s.Flush(); return okay; }
private static bool WriteUVData(float[] input, VRTF.ElementLayout layout, byte[] output, float scale) { bool okay = true; switch (layout.Format) { case VRTF.ElementFormat.Short2: for (int i = 0; i < input.Length; i++) { if ((short)Math.Round(input[i] / scale) != (long)Math.Round(input[i] / scale)) okay = false; Array.Copy(BitConverter.GetBytes((short)Math.Round(input[i] / scale)), 0, output, layout.Offset + i * sizeof(short), sizeof(short)); } break; case VRTF.ElementFormat.Short4: for (int i = 0; i < input.Length; i++) Array.Copy(BitConverter.GetBytes((short)Math.Round(input[i] * short.MaxValue)), 0, output, layout.Offset + i * sizeof(short), sizeof(short)); break; case VRTF.ElementFormat.Short4_DropShadow: for (int i = 0; i < input.Length - 1; i++) Array.Copy(BitConverter.GetBytes((short)Math.Round(input[i] * short.MaxValue)), 0, output, layout.Offset + i * sizeof(short), sizeof(short)); Array.Copy(BitConverter.GetBytes((short)Math.Round(input[input.Length - 1] * 511)), 0, output, layout.Offset + (input.Length - 1) * sizeof(short), sizeof(short)); break; default: WriteFloatData(input, layout, output); break; } return okay; }
public static void Import_VRTF(this StreamReader r, MyProgressBar mpb, VRTF vrtf) { string tagLine = r.ReadTag(); string[] split; split = tagLine.Split(new char[] { ' ', }, StringSplitOptions.RemoveEmptyEntries); if (split.Length != 3) { throw new InvalidDataException("Invalid tag line read for 'vrtf'."); } if (split[0] != "vrtf") { throw new InvalidDataException("Expected line tag 'vrtf' not found."); } int count; if (!int.TryParse(split[1], out count)) { throw new InvalidDataException("'vrtf' line has invalid count."); } int stride; if (!int.TryParse(split[2], out stride)) { throw new InvalidDataException("'vrtf' line has invalid stride."); } if (count == 0) { return; } vrtf.Layouts = new VRTF.VertexElementLayoutList(null); vrtf.Stride = stride; mpb.Init("Import VRTF...", count); for (int l = 0; l < count; l++) { split = r.ReadLine().Split(new char[] { ' ', }, StringSplitOptions.RemoveEmptyEntries); if (split.Length != 5) { throw new InvalidDataException(string.Format("'vrtf' line {0} has invalid format.", l)); } int index; if (!int.TryParse(split[0], out index)) { throw new InvalidDataException(string.Format("'vrtf' line {0} has invalid line index.", l)); } if (index != l) { throw new InvalidDataException(string.Format("'vrtf' line {0} has incorrect line index value {1}.", l, index)); } byte[] values = split.ConvertAll <byte>(1); if (values.Length != 4) { throw new InvalidDataException(string.Format("'vrtf' line {0} has incorrect number of byte values {1}.", l, values.Length)); } vrtf.Layouts.Add(new VRTF.ElementLayout(0, null, (VRTF.ElementFormat)values[2], values[3], (VRTF.ElementUsage)values[0], values[1])); mpb.Value++; } mpb.Done(); }
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 static meshExpImp.ModelBlocks.Vertex[] Import_VBUF(this StreamReader r, MyProgressBar mpb, int count, VRTF vrtf, bool milkShapeFix) { meshExpImp.ModelBlocks.Vertex[] vertices = new meshExpImp.ModelBlocks.Vertex[count]; int uvLength = vrtf.Layouts.FindAll(x => x.Usage == VRTF.ElementUsage.UV).Count; int line = 0; mpb.Init("Import VBUF...", count); for (int v = 0; v < count; v++) { meshExpImp.ModelBlocks.Vertex vertex = new meshExpImp.ModelBlocks.Vertex(); int nUV = 0; vertex.UV = new float[uvLength][]; foreach (var layout in vrtf.Layouts) { string[] split = r.ReadLine().Split(new char[] { ' ', }, StringSplitOptions.RemoveEmptyEntries); if (split.Length < 2) { throw new InvalidDataException(string.Format("'vbuf' line {0} has invalid format.", line)); } int index; if (!int.TryParse(split[0], out index)) { throw new InvalidDataException(string.Format("'vbuf' line {0} has invalid line index.", line)); } if (index != v) { throw new InvalidDataException(string.Format("'vbuf' line {0} has incorrect line index value {1}.", line, index)); } byte usage; if (!byte.TryParse(split[1], out usage)) { throw new InvalidDataException(string.Format("'vbuf' line {0} has invalid line index.", v)); } if (usage != (byte)layout.Usage) { throw new InvalidDataException(string.Format("'vbuf' line {0} has incorrect line Usage value {1}.", line, usage)); } switch (usage) { case (byte)VRTF.ElementUsage.Position: vertex.Position = GetFloats(layout.Format, line, split.ConvertAll <Single>(2)); break; case (byte)VRTF.ElementUsage.Normal: vertex.Normal = GetFloats(layout.Format, line, split.ConvertAll <Single>(2)); break; case (byte)VRTF.ElementUsage.UV: vertex.UV[nUV++] = GetFloats(layout.Format, line, split.ConvertAll <Single>(2)); //Wes's MilkShape plug-in sends back the first line in all subsequent lines of a dropShadow. //Usually the values should be zero, so zero them. Program.UseFormat == Program.Format.s3asc && if (nUV > 1 && milkShapeFix) { for (int u = 0; u < vertex.UV[nUV - 1].Length; u++) { vertex.UV[nUV - 1][u] = 0f; } } break; case (byte)VRTF.ElementUsage.BlendIndex: byte[] BlendIndices = split.ConvertAll <byte>(2); if (!(BlendIndices.Length == VRTF.ByteSizeFromFormat(layout.Format) || BlendIndices.Length + 1 == VRTF.ByteSizeFromFormat(layout.Format))) { throw new InvalidDataException(string.Format("'vbuf' line {0} has incorrect format.", line)); } vertex.BlendIndices = BlendIndices; break; case (byte)VRTF.ElementUsage.BlendWeight: vertex.BlendWeights = GetFloats(layout.Format, line, split.ConvertAll <Single>(2)); break; case (byte)VRTF.ElementUsage.Tangent: vertex.Tangents = GetFloats(layout.Format, line, split.ConvertAll <Single>(2)); break; case (byte)VRTF.ElementUsage.Colour: vertex.Color = GetFloats(layout.Format, line, split.ConvertAll <Single>(2)); break; } line++; } vertices[v] = vertex; if (nUV != uvLength) { throw new InvalidDataException(string.Format("'vbuf' vertex {0} read {1} UV lines, expected {2}.", v, nUV, uvLength)); } mpb.Value++; } mpb.Done(); return(vertices); }
public Vertex[] GetVertices(MLOD.Mesh mesh, VRTF vrtf, float[] uvscales) { return GetVertices(vrtf, mesh.StreamOffset, mesh.VertexCount, uvscales); }
static float[] GetFloats(VRTF.ElementFormat format, int line, float[] source) { float[] res = new float[VRTF.FloatCountFromFormat(format)]; Array.Copy(source, res, Math.Min(source.Length, res.Length)); return(res); }
public Vertex[] GetVertices(VRTF vrtf, long offset, int count, float[] uvscales) { long streamOffset = offset; Stream s = new MemoryStream(mBuffer); s.Seek(streamOffset, SeekOrigin.Begin); var position = vrtf.Layouts .FirstOrDefault(x => x.Usage == VRTF.ElementUsage.Position); var normal = vrtf.Layouts .FirstOrDefault(x => x.Usage == VRTF.ElementUsage.Normal); var uv = vrtf.Layouts .Where(x => x.Usage == VRTF.ElementUsage.UV) .ToArray(); var blendIndices = vrtf.Layouts .FirstOrDefault(x => x.Usage == VRTF.ElementUsage.BlendIndex); var blendWeights = vrtf.Layouts .FirstOrDefault(x => x.Usage == VRTF.ElementUsage.BlendWeight); var tangents = vrtf.Layouts .FirstOrDefault(x => x.Usage == VRTF.ElementUsage.Tangent); var color = vrtf.Layouts .FirstOrDefault(x => x.Usage == VRTF.ElementUsage.Colour); Vertex[] verts = new Vertex[count]; if (uvscales == null) uvscales = new float[3]; for (int i = 0; i < count; i++) { Vertex v = new Vertex(); byte[] data = new byte[vrtf.Stride]; s.Read(data, 0, vrtf.Stride); if (position != null) { float[] posPoints = new float[VRTF.FloatCountFromFormat(position.Format)]; ReadFloatData(data, position, ref posPoints); v.Position = posPoints; } if (normal != null) { float[] normPoints = new float[VRTF.FloatCountFromFormat(normal.Format)]; ReadFloatData(data, normal, ref normPoints); v.Normal = normPoints; } v.UV = new float[uv.Length][]; for (int j = 0; j < uv.Length; j++) { var u = uv[j]; float[] uvPoints = new float[VRTF.FloatCountFromFormat(u.Format)]; var scale = j < uvscales.Length && uvscales[j] != 0 ? uvscales[j] : uvscales[0]; ReadUVData(data, u, ref uvPoints, scale); v.UV[j] = uvPoints; } if (blendIndices != null) { byte[] blendIPoints = new byte[VRTF.ByteSizeFromFormat(blendIndices.Format)]; Array.Copy(data, blendIndices.Offset, blendIPoints, 0, blendIPoints.Length); v.BlendIndices = blendIPoints; } if (blendWeights != null) { float[] blendWPoints = new float[VRTF.FloatCountFromFormat(blendWeights.Format)]; ReadFloatData(data, blendWeights, ref blendWPoints); v.BlendWeights = blendWPoints; } if (tangents != null) { float[] tangentPoints = new float[VRTF.FloatCountFromFormat(tangents.Format)]; ReadFloatData(data, tangents, ref tangentPoints); v.Tangents = tangentPoints; } if (color != null) { float[] colorPoints = new float[VRTF.FloatCountFromFormat(color.Format)]; ReadFloatData(data, color, ref colorPoints); v.Color = colorPoints; } verts[i] = v; } return verts; }
public static void Export_VBUF(this StreamWriter w, MyProgressBar mpb, meshExpImp.ModelBlocks.Vertex[] av, VRTF vrtf) { mpb.Init("Export VBUF...", av.Length); for (int i = 0; i < av.Length; i++) { meshExpImp.ModelBlocks.Vertex v = av[i]; int nUV = 0; foreach (var layout in vrtf.Layouts) { w.Write(string.Format("{0} {1}", i, (byte)layout.Usage)); switch (layout.Usage) { case VRTF.ElementUsage.Position: if (v.Position != null) foreach (float f in v.Position) w.Write(string.Format(" {0:F6}", f)); else w.Write(" Position is null."); break; case VRTF.ElementUsage.Normal: if (v.Normal != null) foreach (float f in v.Normal) w.Write(string.Format(" {0:F6}", f)); else w.Write(" Normal is null."); break; case VRTF.ElementUsage.UV: if (v.UV != null) foreach (float f in v.UV[nUV]) w.Write(string.Format(" {0:F6}", f)); else w.Write(string.Format(" UV[{0}] is null.", nUV)); nUV++; break; case VRTF.ElementUsage.BlendIndex: if (v.BlendIndices != null) foreach (byte b in v.BlendIndices) w.Write(string.Format(" {0}", b)); else w.Write(" BlendIndices is null."); break; case VRTF.ElementUsage.BlendWeight: if (v.BlendWeights != null) foreach (float f in v.BlendWeights) w.Write(string.Format(" {0:F6}", f)); else w.Write(" BlendWeight is null."); break; case VRTF.ElementUsage.Tangent: if (v.Tangents != null) foreach (float f in v.Tangents) w.Write(string.Format(" {0:F6}", f)); else w.Write(" Tangents is null."); break; case VRTF.ElementUsage.Colour: if (v.Color != null) foreach (float f in v.Color) w.Write(string.Format(" {0:F6}", f)); else w.Write(" Colour is null."); break; } w.WriteLine(); mpb.Value++; } } w.Flush(); mpb.Done(); }
//Currently not supported: //UByte4N, //Short2N, Short4N, UShort2N, //Dec3N, UDec3N, //Float16_2, Float16_4 public static void ReadFloatData(byte[] data, VRTF.ElementLayout layout, ref float[] output) { byte[] element = new byte[VRTF.ByteSizeFromFormat(layout.Format)]; Array.Copy(data, layout.Offset, element, 0, element.Length); float scalar; switch (layout.Format) { case VRTF.ElementFormat.Float1: case VRTF.ElementFormat.Float2: case VRTF.ElementFormat.Float3: case VRTF.ElementFormat.Float4: for (int i = 0; i < output.Length; i++) output[i] += BitConverter.ToSingle(element, i * sizeof(float)); break; case VRTF.ElementFormat.ColorUByte4: switch (layout.Usage) { case VRTF.ElementUsage.Colour: for (int i = 0; i < output.Length; i++) output[i] += element[i] / (float)byte.MaxValue; break; case VRTF.ElementUsage.BlendWeight: for (int i = 0; i < output.Length; i++) output[i] += element[kColorUByte4Map[i]] / (float)byte.MaxValue; break; case VRTF.ElementUsage.Normal: case VRTF.ElementUsage.Tangent: for (int i = 0; i < output.Length - 1; i++) output[i] += element[2 - i] == 0 ? -1 : (((element[2 - i] + 1) / 128f) - 1); //-- // Wes: (signed char) bytes[0]=vert[2+vrtfp.offset[j]]; // (float) norms[0]=(float)bytes[0]; // norms[0]=(norms[0]<(float)0.0)?(norms[0]+(float)128.0):(norms[0]-(float)128.0); //??? //-- // input: 255 > 128 > 127 > 0 // map step1: +2 > 0 // map step2: +1 > -1 //for (int i = 0; i < output.Length - 1; i++) // output[i] += (element[2 - i] / 127.5f) - 1f; switch (element[3]) { case 0: output[output.Length - 1] = -1f; break; // -1 determinant case 127: output[output.Length - 1] = 0f; break; // There is no determinant case 255: output[output.Length - 1] = +1f; break; // +1 determinant default: System.Diagnostics.Debug.WriteLine(String.Format("Unexpected handedness {0}.", element[3])); break; } break; } break; case VRTF.ElementFormat.Short2: for (int i = 0; i < output.Length; i++) output[i] += BitConverter.ToInt16(element, i * sizeof(short)) / (float)short.MaxValue; break; case VRTF.ElementFormat.Short4: scalar = BitConverter.ToUInt16(element, 3 * sizeof(short)); if (scalar == 0) scalar = short.MaxValue; //scalar++; for (int i = 0; i < output.Length; i++) output[i] += BitConverter.ToInt16(element, i * sizeof(short)) / scalar; break; case VRTF.ElementFormat.UShort4N: scalar = BitConverter.ToUInt16(element, 3 * sizeof(ushort)); if (scalar == 0) scalar = 511; //scalar++; for (int i = 0; i < output.Length; i++) output[i] += BitConverter.ToInt16(element, i * sizeof(short)) / scalar; break; } }
public static void Import_VRTF(this StreamReader r, MyProgressBar mpb, VRTF vrtf) { string tagLine = r.ReadTag(); string[] split; split = tagLine.Split(new char[] { ' ', }, StringSplitOptions.RemoveEmptyEntries); if (split.Length != 3) throw new InvalidDataException("Invalid tag line read for 'vrtf'."); if (split[0] != "vrtf") throw new InvalidDataException("Expected line tag 'vrtf' not found."); int count; if (!int.TryParse(split[1], out count)) throw new InvalidDataException("'vrtf' line has invalid count."); int stride; if (!int.TryParse(split[2], out stride)) throw new InvalidDataException("'vrtf' line has invalid stride."); if (count == 0) return; vrtf.Layouts = new VRTF.VertexElementLayoutList(null); vrtf.Stride = stride; mpb.Init("Import VRTF...", count); for (int l = 0; l < count; l++) { split = r.ReadLine().Split(new char[] { ' ', }, StringSplitOptions.RemoveEmptyEntries); if (split.Length != 5) throw new InvalidDataException(string.Format("'vrtf' line {0} has invalid format.", l)); int index; if (!int.TryParse(split[0], out index)) throw new InvalidDataException(string.Format("'vrtf' line {0} has invalid line index.", l)); if (index != l) throw new InvalidDataException(string.Format("'vrtf' line {0} has incorrect line index value {1}.", l, index)); byte[] values = split.ConvertAll<byte>(1); if (values.Length != 4) throw new InvalidDataException(string.Format("'vrtf' line {0} has incorrect number of byte values {1}.", l, values.Length)); vrtf.Layouts.Add(new VRTF.ElementLayout(0, null, (VRTF.ElementFormat)values[2], values[3], (VRTF.ElementUsage)values[0], values[1])); mpb.Value++; } mpb.Done(); }
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 static meshExpImp.ModelBlocks.Vertex[] Import_VBUF(this StreamReader r, MyProgressBar mpb, int count, VRTF vrtf) { meshExpImp.ModelBlocks.Vertex[] vertices = new meshExpImp.ModelBlocks.Vertex[count]; int uvLength = vrtf.Layouts.FindAll(x => x.Usage == VRTF.ElementUsage.UV).Count; int line = 0; mpb.Init("Import VBUF...", count); for (int v = 0; v < count; v++) { meshExpImp.ModelBlocks.Vertex vertex = new meshExpImp.ModelBlocks.Vertex(); int nUV = 0; vertex.UV = new float[uvLength][]; foreach (var layout in vrtf.Layouts) { string[] split = r.ReadLine().Split(new char[] { ' ', }, StringSplitOptions.RemoveEmptyEntries); if (split.Length < 2) throw new InvalidDataException(string.Format("'vbuf' line {0} has invalid format.", line)); int index; if (!int.TryParse(split[0], out index)) throw new InvalidDataException(string.Format("'vbuf' line {0} has invalid line index.", line)); if (index != v) throw new InvalidDataException(string.Format("'vbuf' line {0} has incorrect line index value {1}.", line, index)); byte usage; if (!byte.TryParse(split[1], out usage)) throw new InvalidDataException(string.Format("'vbuf' line {0} has invalid Usage.", v)); if (usage != (byte)layout.Usage) throw new InvalidDataException(string.Format("'vbuf' line {0} has incorrect line Usage value {1}.", line, usage)); switch (usage) { case (byte)VRTF.ElementUsage.Position: vertex.Position = GetFloats(layout.Format, line, split.ConvertAll<Single>(2)); break; case (byte)VRTF.ElementUsage.Normal: vertex.Normal = GetFloats(layout.Format, line, split.ConvertAll<Single>(2)); break; case (byte)VRTF.ElementUsage.UV: vertex.UV[nUV++] = GetFloats(layout.Format, line, split.ConvertAll<Single>(2)); break; case (byte)VRTF.ElementUsage.BlendIndex: byte[] BlendIndices = split.ConvertAll<byte>(2); if (!(BlendIndices.Length == VRTF.ByteSizeFromFormat(layout.Format) || BlendIndices.Length + 1 == VRTF.ByteSizeFromFormat(layout.Format))) throw new InvalidDataException(string.Format("'vbuf' line {0} has incorrect format.", line)); vertex.BlendIndices = BlendIndices; break; case (byte)VRTF.ElementUsage.BlendWeight: vertex.BlendWeights = GetFloats(layout.Format, line, split.ConvertAll<Single>(2)); break; case (byte)VRTF.ElementUsage.Tangent: vertex.Tangents = GetFloats(layout.Format, line, split.ConvertAll<Single>(2)); break; case (byte)VRTF.ElementUsage.Colour: vertex.Color = GetFloats(layout.Format, line, split.ConvertAll<Single>(2)); break; } line++; } vertices[v] = vertex; if (nUV != uvLength) throw new InvalidDataException(string.Format("'vbuf' vertex {0} read {1} UV lines, expected {2}.", v, nUV, uvLength)); mpb.Value++; } mpb.Done(); return vertices; }
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; }
static float[] GetFloats(VRTF.ElementFormat format, int line, float[] source) { float[] res = new float[VRTF.FloatCountFromFormat(format)]; Array.Copy(source, res, Math.Min(source.Length, res.Length)); return res; }
private static void PositionMinMax(VRTF vrtf, IEnumerable<Vertex> vertices) { positionMin = 0f; positionMax = 0f; var layout = vrtf.Layouts.FirstOrDefault(x => x.Format == VRTF.ElementFormat.UShort4N && x.Usage == VRTF.ElementUsage.Position); if (layout == null) return; List<float> positionFloats = new List<float>(); foreach (float[] fs in vertices.Select(x => x.Position)) if (fs != null) positionFloats.AddRange(fs); if (positionFloats.Count > 0) { positionMax = positionMin = Math.Abs(positionFloats[0]); foreach (float f in positionFloats) { float x = Math.Abs(f); if (positionMin > x) positionMin = x; if (positionMax < x) positionMax = x; } } //positionMin = positionFloats.Count > 0 ? positionFloats.Min(x => Math.Abs(x)) : 0; //positionMax = positionFloats.Count > 0 ? positionFloats.Max(x => Math.Abs(x)) : 0; }
public List <offScale> VertsToVBUFs(GenericRCOLResource rcolResource, MLOD mlod, IResourceKey defaultRK, List <meshExpImp.ModelBlocks.Vertex[]> lmverts, 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]); 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 static void WritePositionData(float[] input, VRTF.ElementLayout layout, byte[] output, float max) { switch (layout.Format) { case VRTF.ElementFormat.UShort4N: //scalar = (max >= 1) ? 511 : (ulong)short.MaxValue; //-- could try "max < 1.0 / 512.0"? //ulong scalar = (ulong)(max < 1 ? short.MaxValue : 511); //scalar++; //2011-08-30 changed to fixed 512 as LoveseatDanishModern had problems ulong scalar = 512; for (int i = 0; i < input.Length; i++) Array.Copy(BitConverter.GetBytes((short)Math.Round(input[i] * scalar)), 0, output, layout.Offset + i * sizeof(short), sizeof(short)); Array.Copy(BitConverter.GetBytes((short)(scalar == 512 ? 0 : scalar - 1)), 0, output, layout.Offset + 3 * sizeof(short), sizeof(short)); break; default: WriteFloatData(input, layout, output); break; } }
//-- 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)); }
private static void WriteFloatData(float[] input, VRTF.ElementLayout layout, byte[] output) { ulong scalar; double max; switch (layout.Format) { case VRTF.ElementFormat.Float1: case VRTF.ElementFormat.Float2: case VRTF.ElementFormat.Float3: case VRTF.ElementFormat.Float4: for (int i = 0; i < input.Length; i++) Array.Copy(BitConverter.GetBytes(input[i]), 0, output, layout.Offset + i * sizeof(float), sizeof(float)); break; case VRTF.ElementFormat.ColorUByte4: switch (layout.Usage) { case VRTF.ElementUsage.Colour: for (int i = 0; i < input.Length; i++) output[layout.Offset + i] = (byte)Math.Round(input[i] * byte.MaxValue); break; case VRTF.ElementUsage.BlendWeight: for (int i = 0; i < input.Length; i++) output[layout.Offset + kColorUByte4Map[i]] = (byte)Math.Round(input[i] * byte.MaxValue); break; case VRTF.ElementUsage.Normal: case VRTF.ElementUsage.Tangent: // -0.98828125 == (((0.5 + 1) / 128f) - 1) for (int i = 0; i < input.Length - 1; i++) output[layout.Offset + 2 - i] = (byte)(input[i] < -0.98828125 ? 0 : (Math.Round((input[i] + 1) * 128) - 1)); //-- // Wes: (signed char) bytes[0]=vert[2+vrtfp.offset[j]]; // (float) norms[0]=(float)bytes[0]; // norms[0]=(norms[0]<(float)0.0)?(norms[0]+(float)128.0):(norms[0]-(float)128.0); //?? //-- // input: +1 > 0 > -1 // map step1: +2 > +1 > 0 // map step2: 255 > 127.5 > 0 //for (int i = 0; i < input.Length - 1; i++) // output[layout.Offset + 2 - i] = (byte)Math.Round((input[i] + 1) * 127.5); if (input[input.Length - 1] == -1) output[layout.Offset + 3] = 0; else if (input[input.Length - 1] == 0) output[layout.Offset + 3] = 127; else if (input[input.Length - 1] == 1) output[layout.Offset + 3] = 255; else System.Diagnostics.Debug.WriteLine(String.Format("Unexpected handedness {0}.", input[input.Length - 1])); break; } break; case VRTF.ElementFormat.Short2: for (int i = 0; i < input.Length; i++) Array.Copy(BitConverter.GetBytes((short)Math.Round(input[i] * short.MaxValue)), 0, output, layout.Offset + i * sizeof(short), sizeof(short)); break; case VRTF.ElementFormat.Short4: max = Math.Ceiling(input.Max(x => Math.Abs(x))); scalar = (ulong)(max < 1 ? short.MaxValue : short.MaxValue / max); //scalar++; for (int i = 0; i < input.Length; i++) Array.Copy(BitConverter.GetBytes((short)Math.Round(input[i] * scalar)), 0, output, layout.Offset + i * sizeof(short), sizeof(short)); Array.Copy(BitConverter.GetBytes((short)(scalar /*- 1/**/)), 0, output, layout.Offset + 3 * sizeof(short), sizeof(short)); break; case VRTF.ElementFormat.UShort4N: max = Math.Ceiling(input.Max(x => Math.Abs(x))); scalar = (ulong)(max < 1.0 ? short.MaxValue : 512); //scalar++; for (int i = 0; i < input.Length; i++) Array.Copy(BitConverter.GetBytes((short)Math.Round(input[i] * scalar)), 0, output, layout.Offset + i * sizeof(short), sizeof(short)); Array.Copy(BitConverter.GetBytes((short)(scalar == 512 ? 0 : scalar /*- 1/**/)), 0, output, layout.Offset + 3 * sizeof(short), sizeof(short)); break; } }
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); }