public void RemapSkin(GraphicsStream vertexRemapStream) { if (SkinInformation != null && vertexRemapStream != null) { int[] vertexRemap = vertexRemap = vertexRemapStream.Read(typeof(int), new int[] { MeshData.Mesh.NumberVertices }) as int[]; SkinInformation.Remap(vertexRemap); } }
private void EncodeProcess() { try { // calc info int totalFrames = (int)((float)settings.FramesPerSecond * (float)recording.Duration.Seconds); // start encoding IOutputStream stream = VideoEncodingInterface.CreateVideoStream(outFilename, settings.Codec, settings.Width, settings.Height, 16, settings.FramesPerSecond, TimeSpan.MinValue, null); // create local buffer int pixels = settings.Width * settings.Height; byte[] buffer = new byte[settings.Width * settings.Height * 4]; Device device = renderer.Device; Surface bb = device.GetBackBuffer(0, 0, BackBufferType.Mono); Texture t = new Texture(device, settings.Width, settings.Height, 1, bb.Description.Usage, bb.Description.Format, bb.Description.Pool); Surface target = t.GetSurfaceLevel(0); Texture sysT = new Texture(device, settings.Width, settings.Height, 1, bb.Description.Usage, bb.Description.Format, bb.Description.Pool); Surface sysTarget = sysT.GetSurfaceLevel(0); byte[] pBuf = new byte[4]; for (int frame = 0; frame < totalFrames; frame++) { // Draw frame renderer.Render(0, target); //Bitmap b = new Bitmap(TextureLoader.SaveToStream(ImageFileFormat.Bmp, t)); //BitmapData data = b.LockBits(new Rectangle(0, 0, settings.Width, settings.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); device.GetRenderTargetData(target, sysTarget); GraphicsStream gStream = sysTarget.LockRectangle(LockFlags.ReadOnly); // copy over to right format // Format.X8R8G8B8 > RGBA int bIdx = 0; for (int pixel = 0; pixel < pixels; pixel++) { gStream.Read(pBuf, 0, 4); buffer[bIdx++] = pBuf[1]; // r buffer[bIdx++] = pBuf[2]; // g buffer[bIdx++] = pBuf[3]; // b buffer[bIdx++] = pBuf[0]; // a } // encode frame stream.PutFrame(buffer); } int totalBytes = 0; stream.Close(out totalBytes); } catch (ThreadAbortException) { } complete = true; }
private static void CopyTextureData(GraphicsStream srcData, int srcWidth, int srcHeight, OpsFormatHelper formatHelp, int srcPitch, GraphicsStream dstData, int dstPitch) { Byte[] rowData = new Byte[srcWidth * formatHelp.SizeInBytes]; for (int row = 0; row < srcHeight; row++) { srcData.Position = row * srcPitch; dstData.Position = row * dstPitch; srcData.Read(rowData, 0, rowData.Length); dstData.Write(rowData, 0, rowData.Length); } }
/// <summary> /// Method to load in a directx mesh. /// </summary> /// <param name="filename">Path of the model to load.</param> /// <returns></returns> public Mesh LoadModel(string filename) { Mesh mesh; VertexElement[] vElements = new VertexElement[] { new VertexElement(0, 0, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Position, 0), new VertexElement(0, 12, DeclarationType.Float2, DeclarationMethod.Default, DeclarationUsage.TextureCoordinate, 0), new VertexElement(0, 20, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Normal, 0), new VertexElement(0, 32, DeclarationType.Float4, DeclarationMethod.Default, DeclarationUsage.Tangent, 0), VertexElement.VertexDeclarationEnd }; // Load the mesh from file. mesh = Mesh.FromFile(filename, MeshFlags.Managed | MeshFlags.Use32Bit, device); // Clone the mesh. mesh = mesh.Clone(MeshFlags.Managed | MeshFlags.Use32Bit, vElements, device); // Generates a list of adjacent faces used for generating normals. int[] adjacency = new int[mesh.NumberFaces * 3]; mesh.GenerateAdjacency(0, adjacency); //mesh.ComputeTangentFrame(TangentOptions.GenerateInPlace | TangentOptions.CalculateNormals); mesh.ComputeNormals(adjacency); // Create the variables needed to convert the mesh to right handed coordinates. GraphicsStream gStream = mesh.LockVertexBuffer(LockFlags.None); List <Vertex> vertices = new List <Vertex>(); Vertex vertex; // Convert the mesh to right handed coordinates. for (int i = 0; i < mesh.NumberVertices; i++) { vertex = (Vertex)gStream.Read(typeof(Vertex)); vertex.Position.Z *= -1.0f; vertex.Normal = Vector3.TransformNormal(vertex.Normal, Matrix.Scaling(1.0f, 1.0f, -1.0f)); vertices.Add(vertex); } // Set the vertex buffer mesh.SetVertexBufferData(vertices.ToArray(), LockFlags.None); // Calculate the tangents TangentBuilder.CalculateTangents(mesh); return(mesh); }
Color avcs(GraphicsStream gs, Collection <long> positions) { byte[] bu = new byte[4]; int r = 0; int g = 0; int b = 0; int i = 0; foreach (long pos in positions) { gs.Position = pos; if (gs.Length > positions[positions.Count - 1]) { if (gs.CanRead) { try { gs.Read(bu, 0, 4); } catch { } } } r += bu[2]; g += bu[1]; b += bu[0]; i++; } if (i == 0) { return(Color.Black); } else { int r_Usr = r / i; int g_Usr = g / i; int b_Usr = b / i; if (r_Usr == 0xAA) { r_Usr += 1; } if (g_Usr == 0xAA) { g_Usr += 1; } if (b_Usr == 0xAA) { b_Usr += 1; } return(Color.FromArgb(r_Usr, g_Usr, b_Usr)); } }
//Swizzlin' private static void SwizzleImage(GraphicsStream gs, int width, int height, bool b32BPP) { //since swizzling is only for normals, and those must be saved in dxt5 (or argb8), might as well ensure the texture is in the correct format. if (!b32BPP) { var tTemp = TextureLoader.FromStream(dev, gs, width, height, 1, Usage.None, Format.A8B8G8R8, Pool.SystemMemory, Filter.None, Filter.None, 0); gs = TextureLoader.SaveToStream(ImageFileFormat.Tga, tTemp); tTemp.Dispose(); } var bOri = new byte[gs.Length]; //byte array from original stream var bSwizzled = new byte[gs.Length]; //swizzled array gs.Read(bOri, 0, (int)gs.Length); const int headerSize = 0x1f; //a header for a tga file is usually 18bytes long, but for a reason I don't get, here it start at 0x1F... // Dim headerSize As Integer = 18 for (var i = 0; i <= headerSize - 1; i++) { bSwizzled[i] = bOri[i]; } //there's probably a better way to do that, but this one is self-explanatory... for (var y = 0; y <= height - 1; y++) { for (var x = 0; x <= width - 1; x++) { var pos = (((y * width) + x) * 4) + headerSize; //b = bOri(pos) var g = bOri[pos + 1]; var r = bOri[pos + 2]; //a = bOri(pos + 3) bSwizzled[pos] = 255; bSwizzled[pos + 1] = g; bSwizzled[pos + 2] = 255; bSwizzled[pos + 3] = r; } } gs.Position = 0; gs.Write(bSwizzled, 0, bSwizzled.Length); gs.Position = 0; }
private static GraphicsStream swizzleTga(Stream st, int width, int height) { System.Console.WriteLine("Swizzling normal map"); st.Position = 0; Texture tex = TextureLoader.FromStream(device, st); GraphicsStream gs = TextureLoader.SaveToStream(ImageFileFormat.Tga, tex); var bOri = new byte[gs.Length]; //byte array from original stream var bSwizzled = new byte[gs.Length]; //swizzled array gs.Read(bOri, 0, (int)gs.Length); const int headerSize = 0x1f; //a header for a tga file is usually 18bytes long, but for a reason I don't get, here it start at 0x1F... // Dim headerSize As Integer = 18 for (var i = 0; i <= headerSize - 1; i++) { bSwizzled[i] = bOri[i]; } //there's probably a better way to do that, but this one is self-explanatory... for (var y = 0; y <= height - 1; y++) { for (var x = 0; x <= width - 1; x++) { var pos = (((y * width) + x) * 4) + headerSize; //b = bOri(pos) var g = bOri[pos + 1]; var r = bOri[pos + 2]; //a = bOri(pos + 3) bSwizzled[pos] = 255; bSwizzled[pos + 1] = g; bSwizzled[pos + 2] = 255; bSwizzled[pos + 3] = r; } } gs.Position = 0; gs.Write(bSwizzled, 0, bSwizzled.Length); gs.Position = 0; st.Dispose(); st.Close(); System.Console.WriteLine("Swizzle done"); return(gs); }
/// <summary> /// Calculates the largest and smallest values. /// </summary> public void calcSize() { min = max = 0; Vertex vertex; GraphicsStream gStream = model.LockVertexBuffer(LockFlags.None); // Iterates through the vertex list to find the minimum and maximum position values. for (int i = 0; i < model.NumberVertices; i++) { vertex = (Vertex)gStream.Read(typeof(Vertex)); if (vertex.Position.Y > max) { max = vertex.Position.Y; } if (vertex.Position.Y < min) { min = vertex.Position.Y; } } }
/// <summary> /// Read a Matrix from an XFile node /// </summary> /// <param name="stream">GraphicsStream obtained from locking the Xfile data object</param> public Matrix MatrixFromXFile(GraphicsStream stream) { float v = 0; // elements are floats Matrix m = Matrix.Identity; m.M11 = (float)stream.Read(v.GetType()); // read the matrix m.M12 = (float)stream.Read(v.GetType()); m.M13 = (float)stream.Read(v.GetType()); m.M14 = (float)stream.Read(v.GetType()); m.M21 = (float)stream.Read(v.GetType()); m.M22 = (float)stream.Read(v.GetType()); m.M23 = (float)stream.Read(v.GetType()); m.M24 = (float)stream.Read(v.GetType()); m.M31 = (float)stream.Read(v.GetType()); m.M32 = (float)stream.Read(v.GetType()); m.M33 = (float)stream.Read(v.GetType()); m.M34 = (float)stream.Read(v.GetType()); m.M41 = (float)stream.Read(v.GetType()); m.M42 = (float)stream.Read(v.GetType()); m.M43 = (float)stream.Read(v.GetType()); m.M44 = (float)stream.Read(v.GetType()); return m; }
private void ExportThread() { //create timer so we can check how long it takes to create the whole file Stopwatch stopwatch = new Stopwatch(); // Begin timing stopwatch.Start(); //for (int i = 0; i < _refLibrary.Count; i++) for (int i = Convert.ToInt16(text_test_framemin.Text); i < Convert.ToInt16(text_test_framemax.Text); i++) { showRefImage = false; //turns off the ref image while we render the new library nud_frame.Value = i; //just setting this value and then calling Render() is enough to cycle through the frames backgroundColour = Color.Black; //set the background to black so the crop code can detect the blank areas and remove pure black pixels from the image, if set to any other colour the image will have a solid colour background and not become transparent UpdateTextBoxes(); //this will set the _selectedRefImage for the current frame Render(); #region Save Snapshot of the Directx panel try { Surface backbuffer = device.GetBackBuffer(0, 0, BackBufferType.Mono); //SurfaceLoader.Save("Screenshot.bmp", ImageFileFormat.Bmp, backbuffer); //saves file (to test it is working) //if you continue to Render the DirectX panel while updating the GraphicsStream it causes the device to be lost and crashes //so I just call Render(); when I need to update the panel instead of using the infinite loop thread #region Graphics Lock GraphicsStream gs = backbuffer.LockRectangle(LockFlags.Discard); gs.Position = 0; //set start position int bytesPerPixel = 4; int currentPosition = 0; int heightInPixels = 250; int widthInPixels = 250; //Crop offsets int XMin = 249; int XMax = 0; int YMin = 249; int YMax = 0; for (int y = 0; y < heightInPixels; y++) { //couldn't use the Parallel.For loop as it would overwrite the GraphicsStream.Position because it was working on two or //more pixels at once causing a speckled effect as it misses pixels (well I think that is what was causing the errors I was having) //Parallel.For(0, heightInPixels, y => //{ //int currentLine = (y * ((widthInPixels * bytesPerPixel) + (4 *12))); //4*12 is how many pixels (12 for 500pixel image) was missing from each row (not sure why 12 but I guess the backbuffer extends beyond the screen) int currentLine = (y * (widthInPixels * bytesPerPixel) + (y * (4 * 6))); //4*6 is how many pixels (6 for 250pixel image) was missing from each row (not sure why 6 but I guess the backbuffer extends beyond the screen) for (int x = 0; x < widthInPixels; x++) { byte[] bu = new byte[4]; //new byte to store current pixel data currentPosition = currentLine + (x * bytesPerPixel); //calculate current position gs.Position = currentPosition; //set pixel position in GraphicsStream gs.Read(bu, 0, 4); //read image pixel data //gets RGB values int r = bu[2]; int g = bu[1]; int b = bu[0]; Color c = Color.FromArgb(r, g, b); if (c.R != backgroundColour.R && c.G != backgroundColour.G && c.B != backgroundColour.B) //if not the same as backgroundColour set the min/max values { if (XMin > x) { XMin = x; } if (XMax < x) { XMax = x; } if (YMin > y) { YMin = y; } if (YMax < y) { YMax = y; } } //if (y == YMin) //this is a way to show where the image is cropped //{ // bu[2] = 255; // bu[1] = 0; // bu[0] = 0; //} gs.Position = currentPosition; //sets the position back to the starting pixel gs.Write(bu, 0, 4); //updates the GraphicsStream with the new changes } //}); //end of Parallel.For loop } //Shows the detected bounds of the image for testing //MessageBox.Show("XMin: " + XMin // + Environment.NewLine + "XMax: " + XMax // + Environment.NewLine + "YMin: " + YMin // + Environment.NewLine + "YMax: " + YMax // + Environment.NewLine + "Width: " + (XMax - XMin) // + Environment.NewLine + "Height: " + (YMax - YMin)); backbuffer.UnlockRectangle(); gs.Dispose(); #endregion Bitmap Preview = new Bitmap(SurfaceLoader.SaveToStream(ImageFileFormat.Bmp, backbuffer)); #region crop //create target image and draw cropped part of the Preview image to the target image Bitmap target = new Bitmap((XMax - XMin) + 1, (YMax - YMin) + 1, PixelFormat.Format32bppArgb); using (Graphics g = Graphics.FromImage(target)) { g.DrawImage(Preview, new RectangleF(0, 0, target.Width, target.Height), new RectangleF(XMin, YMin, (XMax - XMin) + 1, (YMax - YMin) + 1), GraphicsUnit.Pixel); } #endregion //Add Image and offsets to the _library _library.AddImage(target, (short)(XMin - characterGlobalOffsetX), (short)(YMin - characterGlobalOffsetY)); //target.Save("Test1.PNG", ImageFormat.Png); //testing screen capture and crop image from directx works by saving to file target.Dispose(); Preview.Dispose(); backbuffer.Dispose(); } catch (Direct3DXException ee) //Display error Messages with the DirectX code { MessageBox.Show("Message: " + ee.Message + Environment.NewLine + "ErrorString: " + ee.ErrorString + Environment.NewLine + "ErrorCode: " + ee.ErrorCode + Environment.NewLine + "StackTrace: " + ee.StackTrace ); } #endregion toolStripProgressBar.Value = i + 1; } //save file as normal .lib (true = reference file, false = normal .lib) _library.Save(false); stopwatch.Stop(); MessageBox.Show(string.Format("Time Taken: {0:n0} Seconds", stopwatch.Elapsed.TotalMilliseconds / 1000)); toolStripProgressBar.Value = 0; showRefImage = true; nud_frame.Value = 0; Render(); }
//IOpsCommand public void Run(OpsContext context, OpsStatement statement) { OpsConsole.WriteLine("Cleaning models"); foreach (OpsModel model in statement.GetContent(context)) { foreach (OpsMeshContainer meshContainer in model.GetMeshEnumerator()) { string errorsAndWarnings; meshContainer.MeshData.Mesh.Validate(meshContainer.GetAdjacencyStream(), out errorsAndWarnings); if (errorsAndWarnings == null || errorsAndWarnings.Length == 0) { continue; } else { OpsConsole.WriteLine("Cleaning '{0}'", meshContainer.FriendlyName(model)); OpsConsole.WriteLine(errorsAndWarnings); } VertexElement[] OldVEs = null; int offsetOfIndex = -1; Mesh dirtyMesh = meshContainer.MeshData.Mesh; if (meshContainer.SkinInformation != null) { int psizeUsageIdx = -1; int remapIdx = -1; OldVEs = meshContainer.MeshData.Mesh.Declaration.Clone() as VertexElement[]; if (!MeshDeclarationHelper.FindValidUsageIndex(OldVEs, DeclarationUsage.PointSize, out psizeUsageIdx)) { throw new OpsException("Could not add remapping-indexing vertex element to declaration"); } VertexElement[] VEs = MeshDeclarationHelper.AddElement(OldVEs, DeclarationType.Float1, DeclarationUsage.PointSize, psizeUsageIdx, out remapIdx); dirtyMesh = meshContainer.MeshData.Mesh.Clone(meshContainer.MeshData.Mesh.Options.Value, VEs, meshContainer.MeshData.Mesh.Device); offsetOfIndex = VEs[remapIdx].Offset; VertexBuffer vb = dirtyMesh.VertexBuffer; GraphicsStream gs = vb.Lock(0, 0, LockFlags.None); for (int iVertex = 0; iVertex < dirtyMesh.NumberVertices; iVertex++) { gs.Seek(dirtyMesh.NumberBytesPerVertex * iVertex + offsetOfIndex, SeekOrigin.Begin); gs.Write(iVertex); } vb.Unlock(); gs = null; vb = null; } int[] adjOut; Mesh cleanedMesh = Mesh.Clean(CleanType.BackFacing | CleanType.BowTies, dirtyMesh, meshContainer.GetAdjacency(), out adjOut, out errorsAndWarnings); if (errorsAndWarnings != null && errorsAndWarnings.Length != 0) { OpsConsole.WriteLine("Remaining Errors and Warnings:"); OpsConsole.WriteLine(errorsAndWarnings); } if (meshContainer.SkinInformation != null) { int[] vertexRemap = new int[cleanedMesh.NumberVertices]; VertexBuffer vb = cleanedMesh.VertexBuffer; GraphicsStream gs = vb.Lock(0, 0, LockFlags.None); for (int iVertex = 0; iVertex < cleanedMesh.NumberVertices; iVertex++) { gs.Seek(cleanedMesh.NumberBytesPerVertex * iVertex + offsetOfIndex, SeekOrigin.Begin); vertexRemap[iVertex] = (int)gs.Read(typeof(int)); } vb.Unlock(); meshContainer.RemapSkin(vertexRemap); cleanedMesh = cleanedMesh.Clone(cleanedMesh.Options.Value, OldVEs, cleanedMesh.Device); } meshContainer.SetAdjacency(adjOut); meshContainer.ReplaceMesh(cleanedMesh); } } }
public void RemapSkin( GraphicsStream vertexRemapStream ) { if(SkinInformation != null && vertexRemapStream != null) { int[] vertexRemap= vertexRemap= vertexRemapStream.Read( typeof(int), new int[]{ MeshData.Mesh.NumberVertices } ) as int[]; SkinInformation.Remap(vertexRemap); } }
/// <summary> /// Read a vector from open xfile stream /// </summary> /// <param name="stream"></param> /// <returns></returns> private static Vector3 ReadVector(GraphicsStream stream) { Vector3 v = new Vector3(); // v = (Vector3)stream.Read(v.GetType()); v.X = (float)stream.Read(v.X.GetType()); v.Y = (float)stream.Read(v.X.GetType()); v.Z = (float)stream.Read(v.X.GetType()); return v; }
/// <summary> /// Read a quaternion from open xfile stream /// </summary> /// <param name="stream"></param> /// <returns></returns> private static Quaternion ReadQuaternion(GraphicsStream stream) { Quaternion q = new Quaternion(); q.W = (float)stream.Read(q.W.GetType()); // must read element by element to get WXYZ order q.X = (float)stream.Read(q.X.GetType()); q.Y = (float)stream.Read(q.Y.GetType()); q.Z = (float)stream.Read(q.Z.GetType()); q.Normalize(); //Debug.WriteLine(ThreeDee.DecodeQuaternion(q)); return q; }
/// <summary> /// Static method to calculate tangents along with the handedness of the tangents. /// </summary> /// <param name="model">Model to calculate the tangents on.</param> public static void CalculateTangents(Mesh model) { // Get a copy of the buffers. GraphicsStream ib = model.LockIndexBuffer(LockFlags.None); GraphicsStream vb = model.LockVertexBuffer(LockFlags.None); // List of the final vertex list. List <Vertex> final = new List <Vertex>(); // Temperary lists to store vectors in. List <Vector3> tan1 = new List <Vector3>(model.NumberVertices); List <Vector3> tan2 = new List <Vector3>(model.NumberVertices); // Loop through and copy the vertex list from the vertex buffer // and to also add empty values to tan1 and tan2. for (int i = 0; i < model.NumberVertices; i++) { final.Add((Vertex)vb.Read(typeof(Vertex))); tan1.Add(new Vector3()); tan2.Add(new Vector3()); } // Various variables used in the calculation. int i1, i2, i3; Vector3 v1, v2, v3; Vector2 w1, w2, w3; float x1, x2, y1, y2, z1, z2; float s1, s2, t1, t2, r; // Loop through and calculate the tangent information. for (int i = 0; i < model.NumberFaces; i++) { i1 = (int)ib.Read(typeof(int)); i2 = (int)ib.Read(typeof(int)); i3 = (int)ib.Read(typeof(int)); // Get the vertex values for the 3 vertices of a face. Vertex vertex1 = final[i1]; Vertex vertex2 = final[i2]; Vertex vertex3 = final[i3]; // Get the positions. v1 = vertex1.Position; v2 = vertex2.Position; v3 = vertex3.Position; // Get the texture coordinates. w1 = vertex1.TexCoord; w2 = vertex2.TexCoord; w3 = vertex3.TexCoord; x1 = v2.X - v1.X; x2 = v3.X - v1.X; y1 = v2.Y - v1.Y; y2 = v3.Y - v1.Y; z1 = v2.Z - v1.Z; z2 = v3.Z - v1.Z; s1 = w2.X - w1.X; s2 = w3.X - w1.X; t1 = w2.Y - w1.Y; t2 = w3.Y - w1.Y; r = 1.0F / (s1 * t2 - s2 * t1); // Calculate the direction of the vector Vector3 sdir = new Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r); // Calculate the direction of the uv Vector3 tdir = new Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r); Vector3 temp1 = tan1[i1]; Vector3 temp2 = tan1[i2]; Vector3 temp3 = tan1[i3]; Vector3 temp4 = tan2[i1]; Vector3 temp5 = tan2[i2]; Vector3 temp6 = tan2[i3]; tan1[i1] = temp1 + sdir; tan1[i2] = temp2 + sdir; tan1[i3] = temp3 + sdir; tan2[i1] = temp4 + tdir; tan2[i2] = temp5 + tdir; tan2[i3] = temp6 + tdir; } for (int i = 0; i < model.NumberVertices; i++) { Vertex tempVertex = final[i]; Vector3 n = tempVertex.Normal; Vector3 t = tan1[i]; Vector3 temp = (t - n * Vector3.Dot(n, t)); temp.Normalize(); // Gram-Schmidt orthogonalize tempVertex.Tangent = new Vector4(temp.X, temp.Y, temp.Z, 1.0f); // Calculate the handedness tempVertex.Tangent.W = (Vector3.Dot(Vector3.Cross(n, t), tan2[i]) < 0.0F) ? -1.0F : 1.0F; final[i] = tempVertex; } ib.Close(); vb.Close(); model.SetVertexBufferData(final.ToArray(), LockFlags.None); }
//IOpsCommand public void Run(OpsContext context, OpsStatement statement) { CloneVDataArguments arguments = statement.Arguments as CloneVDataArguments; OpsConsole.WriteLine(String.Format("Cloning vertex element {0} as {1}", arguments.FriendlySrcName, arguments.FriendlyDstName)); foreach (OpsModel model in statement.GetContent(context)) { foreach (OpsMeshContainer meshContainer in model.GetMeshEnumerator()) { int srcIdx; int dstIdx; VertexElement[] OldVEs = meshContainer.MeshData.Mesh.Declaration.Clone() as VertexElement[]; int srcUsageIdx = arguments.srcUsageIdx; if (arguments.hasSrcUsageIdx == false) { for (int i = 0; i < OldVEs.Length; i++) { if (OldVEs[i].DeclarationUsage == arguments.srcUsage) { srcUsageIdx = OldVEs[i].UsageIndex; break; } } } if (srcUsageIdx < 0) { continue; } if (!MeshDeclarationHelper.FindElement(OldVEs, arguments.srcUsage, srcUsageIdx, out srcIdx)) { throw new OpsException("Could not find source vertex element"); } int dstUsageIdxPerMesh = arguments.dstUsageIdx; if (!arguments.hasDstUsageIdx) { if (MeshDeclarationHelper.FindValidUsageIndex(OldVEs, arguments.dstUsage, out dstUsageIdxPerMesh, out dstIdx)) { throw new OpsException("Could not find open usage index for destination vertex element"); } } int copyIdx; VertexElement[] VEs = MeshDeclarationHelper.AddElement(OldVEs, OldVEs[srcIdx].DeclarationType, arguments.dstUsage, dstUsageIdxPerMesh, out copyIdx); if (!MeshDeclarationHelper.FindElement(VEs, arguments.srcUsage, srcUsageIdx, out srcIdx)) { throw new OpsException("Could not find source vertex element"); } if (!MeshDeclarationHelper.FindElement(VEs, arguments.dstUsage, dstUsageIdxPerMesh, out dstIdx)) { throw new OpsException("Could not find destination vertex element"); } Mesh newMesh = meshContainer.MeshData.Mesh.Clone(meshContainer.MeshData.Mesh.Options.Value, VEs, meshContainer.MeshData.Mesh.Device); int sizeInBytes = MeshDeclarationHelper.GetTypeSize(VEs[srcIdx].DeclarationType); int srcOffset = VEs[srcIdx].Offset; int dstOffset = VEs[dstIdx].Offset; byte[] copyBuffer = new byte[sizeInBytes]; VertexBuffer vb = newMesh.VertexBuffer; GraphicsStream gs = vb.Lock(0, 0, LockFlags.None); for (int iVertex = 0; iVertex < newMesh.NumberVertices; iVertex++) { gs.Seek(newMesh.NumberBytesPerVertex * iVertex + srcOffset, SeekOrigin.Begin); gs.Read(copyBuffer, 0, sizeInBytes); gs.Seek(newMesh.NumberBytesPerVertex * iVertex + dstOffset, SeekOrigin.Begin); gs.Write(copyBuffer, 0, sizeInBytes); } vb.Unlock(); gs = null; vb = null; meshContainer.ReplaceMesh(newMesh); } } }