/// <summary> /// Data transfer helper for packing <see cref="Vector3"/> data. /// </summary> /// <param name="packet">The packet buffer in which to compose the transfer message.</param> /// <param name="component">The component type.</param> /// <param name="items">Data to transfer.</param> /// <param name="byteLimit">An advisory byte limit used to restrict how much data should be sent (in bytes).</param> /// <param name="progress">Track the transfer progress between calls.</param> protected bool Transfer(PacketBuffer packet, MeshMessageType component, Vector3[] items, int byteLimit, ref TransferProgress progress) { // Compose component message. int elementSize = 12; // 3 * 4 byte floats MeshComponentMessage msg = new MeshComponentMessage(); msg.MeshID = ID; msg.Offset = (uint)progress.Progress; msg.Reserved = 0; msg.Count = (ushort)Math.Min(EstimateTransferCount(elementSize, byteLimit, MeshComponentMessage.Size), (uint)items.Length - msg.Offset); packet.Reset((ushort)RoutingID.Mesh, (ushort)component); msg.Write(packet); uint ii = msg.Offset; for (int i = 0; i < msg.Count; ++i, ++ii) { packet.WriteBytes(BitConverter.GetBytes(items[ii].X), true); packet.WriteBytes(BitConverter.GetBytes(items[ii].Y), true); packet.WriteBytes(BitConverter.GetBytes(items[ii].Z), true); } progress.Progress += msg.Count; return(progress.Progress == items.Length); }
/// <summary> /// Process data for a <see cref="MeshMessageType.Vertex"/> message. /// </summary> /// <param name="msg">Message details.</param> /// <param name="vertices">New vertices read from the message payload.</param> /// <returns>True on success.</returns> protected override bool ProcessVertices(MeshComponentMessage msg, Vector3[] vertices) { for (int i = 0; i < msg.Count; ++i) { SetVertex(i + (int)msg.Offset, vertices[i]); } return(true); }
/// <summary> /// Process data for a <see cref="MeshMessageType.Index"/> message when receiving 4-byte indices. /// </summary> /// <param name="msg">Message details.</param> /// <param name="indices">New 4-byte indices read from the message payload.</param> /// <returns>True on success.</returns> protected override bool ProcessIndices(MeshComponentMessage msg, int[] indices) { for (int i = 0; i < msg.Count; ++i) { SetIndex(i + (int)msg.Offset, indices[i]); } return(true); }
/// <summary> /// Handles <see cref="MeshComponentMessage"/> of type <see cref="MeshMessageType.Normal"/>. /// </summary> /// <param name="packet"></param> /// <param name="reader"></param> /// <returns></returns> protected Error AddNormals(PacketBuffer packet, BinaryReader reader) { MeshComponentMessage msg = new MeshComponentMessage(); if (!msg.Read(reader)) { return(new Error(ErrorCode.MalformedMessage, (ushort)MeshMessageType.Normal)); } MeshDetails meshDetails; if (!_meshes.TryGetValue(msg.MeshID, out meshDetails)) { return(new Error(ErrorCode.InvalidObjectID, msg.MeshID)); } if (msg.Count == 0) { return(new Error()); } int voffset = (int)msg.Offset; // Bounds check. int vertexCount = (int)meshDetails.VertexCount; if (voffset >= vertexCount || voffset + msg.Count > vertexCount) { return(new Error(ErrorCode.IndexingOutOfRange, (ushort)MeshMessageType.Normal)); } // Check for settings initial bounds. bool ok = true; Vector3 n = Vector3.zero; for (int vInd = 0; ok && vInd < (int)msg.Count; ++vInd) { n.x = reader.ReadSingle(); n.y = reader.ReadSingle(); n.z = reader.ReadSingle(); meshDetails.Builder.UpdateNormal(vInd + voffset, n); meshDetails.Builder.BoundsPadding.x = Mathf.Max(meshDetails.Builder.BoundsPadding.x, Mathf.Abs(n.x)); meshDetails.Builder.BoundsPadding.y = Mathf.Max(meshDetails.Builder.BoundsPadding.y, Mathf.Abs(n.y)); meshDetails.Builder.BoundsPadding.z = Mathf.Max(meshDetails.Builder.BoundsPadding.z, Mathf.Abs(n.z)); } if (!ok) { return(new Error(ErrorCode.MalformedMessage, (ushort)MeshMessageType.Normal)); } return(new Error()); }
/// <summary> /// Handles <see cref="MeshComponentMessage"/> of type <see cref="MeshMessageType.UV"/>. /// </summary> /// <param name="packet"></param> /// <param name="reader"></param> /// <returns></returns> protected Error AddUVs(PacketBuffer packet, BinaryReader reader) { MeshComponentMessage msg = new MeshComponentMessage(); if (!msg.Read(reader)) { return(new Error(ErrorCode.MalformedMessage, (ushort)MeshMessageType.UV)); } MeshDetails meshEntry; if (!_meshes.TryGetValue(msg.MeshID, out meshEntry)) { return(new Error(ErrorCode.InvalidObjectID, msg.MeshID)); } if (msg.Count == 0) { return(new Error()); } int voffset = (int)msg.Offset; // Bounds check. int vertexCount = (int)meshEntry.Mesh.VertexCount; _v2Buffer.Clear(); if (voffset >= vertexCount || voffset + msg.Count > vertexCount) { return(new Error(ErrorCode.IndexingOutOfRange, (ushort)MeshMessageType.UV)); } // Check for settings initial bounds. bool ok = true; Vector2 uv = Vector2.zero; for (int vInd = 0; ok && vInd < msg.Count; ++vInd) { uv.x = reader.ReadSingle(); uv.y = reader.ReadSingle(); _v2Buffer.Add(uv); } meshEntry.Mesh.SetUVs(_v2Buffer, 0, voffset, _v2Buffer.Count); _v2Buffer.Clear(); if (!ok) { return(new Error(ErrorCode.MalformedMessage, (ushort)MeshMessageType.UV)); } return(new Error()); }
/// <summary> /// Handles <see cref="MeshComponentMessage"/> of type <see cref="MeshMessageType.Index"/>. /// </summary> /// <param name="packet"></param> /// <param name="reader"></param> /// <returns></returns> protected Error AddIndices(PacketBuffer packet, BinaryReader reader) { MeshComponentMessage msg = new MeshComponentMessage(); if (!msg.Read(reader)) { return(new Error(ErrorCode.MalformedMessage, (ushort)MeshMessageType.Index)); } MeshDetails meshEntry; if (!_meshes.TryGetValue(msg.MeshID, out meshEntry)) { return(new Error(ErrorCode.InvalidObjectID, msg.MeshID)); } if (msg.Count == 0) { return(new Error()); } int ioffset = (int)msg.Offset; // Bounds check. int indexCount = (int)meshEntry.Mesh.IndexCount; if (ioffset >= indexCount || ioffset + msg.Count > indexCount) { return(new Error(ErrorCode.IndexingOutOfRange, (ushort)MeshMessageType.Index)); } // Check for settings initial bounds. bool ok = true; int index; _intBuffer.Clear(); for (int iInd = 0; ok && iInd < msg.Count; ++iInd) { index = reader.ReadInt32(); _intBuffer.Add(index); } meshEntry.Mesh.SetIndices(_intBuffer, 0, ioffset, _intBuffer.Count); _intBuffer.Clear(); if (!ok) { return(new Error(ErrorCode.MalformedMessage, (ushort)MeshMessageType.Index)); } return(new Error()); }
/// <summary> /// Process data for a <see cref="MeshMessageType.UV"/> message. /// </summary> /// <param name="msg">Message details.</param> /// <param name="uvs">New uvs read from the message payload.</param> /// <returns>True on success.</returns> protected override bool ProcessUVs(MeshComponentMessage msg, Vector2[] uvs) { EnsureUVs(); for (int i = 0; i < msg.Count; ++i) { if (_uvs.Count < i + (int)msg.Offset) { _uvs[i + (int)msg.Offset] = uvs[i]; } else { _uvs.Add(uvs[i]); } } return(true); }
/// <summary> /// Process data for a <see cref="MeshMessageType.VertexColour"/> message. /// </summary> /// <param name="msg">Message details.</param> /// <param name="colours">New colours read from the message payload.</param> /// <returns>True on success.</returns> /// <remarks> /// Colours may be decoded using the <see cref="Colour"/> class. /// </remarks> protected override bool ProcessColours(MeshComponentMessage msg, uint[] colours) { EnsureColours(); for (int i = 0; i < msg.Count; ++i) { if (_colours.Count < i + (int)msg.Offset) { _colours[i + (int)msg.Offset] = colours[i]; } else { _colours.Add(colours[i]); } } return(true); }
/// <summary> /// Process data for a <see cref="MeshMessageType.Normal"/> message. /// </summary> /// <param name="msg">Message details.</param> /// <param name="normals">New normals read from the message payload.</param> /// <returns>True on success.</returns> protected override bool ProcessNormals(MeshComponentMessage msg, Vector3[] normals) { EnsureNormals(); for (int i = 0; i < msg.Count; ++i) { if (_normals.Count < i + (int)msg.Offset) { _normals[i + (int)msg.Offset] = normals[i]; } else { _normals.Add(normals[i]); } } return(true); }
/// <summary> /// Handles <see cref="MeshComponentMessage"/> of type <see cref="MeshMessageType.VertexColour"/>. /// </summary> /// <param name="packet"></param> /// <param name="reader"></param> /// <returns></returns> protected Error AddVertexColours(PacketBuffer packet, BinaryReader reader) { MeshComponentMessage msg = new MeshComponentMessage(); if (!msg.Read(reader)) { return(new Error(ErrorCode.MalformedMessage, (ushort)MeshMessageType.VertexColour)); } MeshDetails meshDetails; if (!_meshes.TryGetValue(msg.MeshID, out meshDetails)) { return(new Error(ErrorCode.InvalidObjectID, msg.MeshID)); } if (msg.Count == 0) { return(new Error()); } int voffset = (int)msg.Offset; // Bounds check. int vertexCount = (int)meshDetails.VertexCount; if (voffset >= vertexCount || voffset + msg.Count > vertexCount) { return(new Error(ErrorCode.IndexingOutOfRange, (ushort)MeshMessageType.VertexColour)); } // Check for settings initial bounds. bool ok = true; uint colour; for (int vInd = 0; ok && vInd < msg.Count; ++vInd) { colour = reader.ReadUInt32(); meshDetails.Builder.UpdateColour(vInd + voffset, ShapeComponent.ConvertColour(colour)); } if (!ok) { return(new Error(ErrorCode.MalformedMessage, (ushort)MeshMessageType.VertexColour)); } return(new Error()); }
/// <summary> /// Write a <see cref="MeshComponentMessage"/> to serialise <c>Vector3</c> data. /// </summary> /// <param name="meshID">Mesh resource ID we are serialising for.</param> /// <param name="type">The mesh component type; e.g., <see cref="MeshMessageType.Vertex"/>.</param> /// <param name="data">The <c>Vector3</c> data array.</param> /// <param name="packet">Packet buffer to compose messages in</param> /// <param name="writer">Writer to export completed message packets to.</param> /// <param name="blockSize">The maximum number of elements per message.</param> /// <remarks> /// Writes multiple messages to <paramref name="writer"/> as required to ensure all /// <paramref name="data"/> are written. /// </remarks> protected void WriteMeshComponent(uint meshID, MeshMessageType type, Vector3[] data, PacketBuffer packet, BinaryWriter writer, uint blockSize) { if (data == null || data.Length == 0) { return; } MeshComponentMessage cmsg = new MeshComponentMessage(); cmsg.MeshID = meshID; cmsg.Offset = 0; cmsg.Reserved = 0; cmsg.Count = 0; while (cmsg.Offset < data.Length) { Vector3 v; cmsg.Count = (ushort)Math.Min(blockSize, (uint)data.Length - cmsg.Offset); packet.Reset((ushort)RoutingID, (ushort)type); cmsg.Write(packet); for (int i = 0; i < cmsg.Count; ++i) { v = data[i + cmsg.Offset]; packet.WriteBytes(BitConverter.GetBytes(v.x), true); packet.WriteBytes(BitConverter.GetBytes(v.y), true); packet.WriteBytes(BitConverter.GetBytes(v.z), true); } if (cmsg.Count > 0) { packet.FinalisePacket(); packet.ExportTo(writer); } cmsg.Offset += cmsg.Count; cmsg.Count = 0; } }
/// <summary> /// Read and handle a <see cref="MeshComponentMessage"/> message. /// </summary> /// <param name="messageType">The <see cref="MeshMessageType"/> identifying the mesh component being read.</param> /// <param name="reader">Stream to read from.</param> /// <returns>True on success.</returns> /// <remarks> /// Handling is deferred to one of the process methods which subclasses should implement. /// /// The <paramref name="messageType"/> identifies the mesh component being read, from the following set; /// <list type="bullet"> /// <item><see cref="MeshMessageType.Vertex"/></item> /// <item><see cref="MeshMessageType.Index"/></item> /// <item><see cref="MeshMessageType.VertexColour"/></item> /// <item><see cref="MeshMessageType.Normal"/></item> /// <item><see cref="MeshMessageType.UV"/></item> /// </list> /// </remarks> public bool ReadTransfer(int messageType, BinaryReader reader) { MeshComponentMessage msg = new MeshComponentMessage(); if (!msg.Read(reader)) { return(false); } switch (messageType) { case (int)MeshMessageType.Vertex: Vector3[] newVertices = new Vector3[msg.Count]; for (int i = 0; i < msg.Count; ++i) { newVertices[i] = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); } return(ProcessVertices(msg, newVertices)); case (int)MeshMessageType.Index: if (IndexSize == 2) { ushort[] newInds = new ushort[msg.Count]; for (int i = 0; i < msg.Count; ++i) { newInds[i] = reader.ReadUInt16(); } return(ProcessIndices(msg, newInds)); } else if (IndexSize == 4) { int[] newInds = new int[msg.Count]; for (int i = 0; i < msg.Count; ++i) { newInds[i] = reader.ReadInt32(); } return(ProcessIndices(msg, newInds)); } // Unknown index size. return(false); case (int)MeshMessageType.VertexColour: uint[] newColours = new uint[msg.Count]; for (int i = 0; i < msg.Count; ++i) { newColours[i] = reader.ReadUInt32(); } return(ProcessColours(msg, newColours)); case (int)MeshMessageType.Normal: Vector3[] newNormals = new Vector3[msg.Count]; for (int i = 0; i < msg.Count; ++i) { newNormals[i] = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); } return(ProcessNormals(msg, newNormals)); case (int)MeshMessageType.UV: Vector2[] newUVs = new Vector2[msg.Count]; for (int i = 0; i < msg.Count; ++i) { newUVs[i] = new Vector2(reader.ReadSingle()); } return(ProcessUVs(msg, newUVs)); default: // Unknown message type. break; } return(false); }
/// <summary> /// Process data for a <see cref="MeshMessageType.UV"/> message. /// </summary> /// <param name="msg">Message details.</param> /// <param name="uvs">New uvs read from the message payload.</param> /// <returns>True on success.</returns> protected virtual bool ProcessUVs(MeshComponentMessage msg, Vector2[] uvs) { return(false); }
/// <summary> /// Process data for a <see cref="MeshMessageType.Normal"/> message. /// </summary> /// <param name="msg">Message details.</param> /// <param name="normals">New normals read from the message payload.</param> /// <returns>True on success.</returns> protected virtual bool ProcessNormals(MeshComponentMessage msg, Vector3[] normals) { return(false); }
/// <summary> /// Process data for a <see cref="MeshMessageType.VertexColour"/> message. /// </summary> /// <param name="msg">Message details.</param> /// <param name="colours">New colours read from the message payload.</param> /// <returns>True on success.</returns> /// <remarks> /// Colours may be decoded using the <see cref="Colour"/> class. /// </remarks> protected virtual bool ProcessColours(MeshComponentMessage msg, uint[] colours) { return(false); }
/// <summary> /// Process data for a <see cref="MeshMessageType.Index"/> message when receiving 4-byte indices. /// </summary> /// <param name="msg">Message details.</param> /// <param name="indices">New 4-byte indices read from the message payload.</param> /// <returns>True on success.</returns> protected virtual bool ProcessIndices(MeshComponentMessage msg, int[] indices) { return(false); }
/// <summary> /// Process data for a <see cref="MeshMessageType.Vertex"/> message. /// </summary> /// <param name="msg">Message details.</param> /// <param name="vertices">New vertices read from the message payload.</param> /// <returns>True on success.</returns> protected virtual bool ProcessVertices(MeshComponentMessage msg, Vector3[] vertices) { return(false); }
/// <summary> /// Handles <see cref="MeshComponentMessage"/> of type <see cref="MeshMessageType.Vertex"/>. /// </summary> /// <param name="packet"></param> /// <param name="reader"></param> /// <returns></returns> protected Error AddVertices(PacketBuffer packet, BinaryReader reader) { MeshComponentMessage msg = new MeshComponentMessage(); if (!msg.Read(reader)) { return(new Error(ErrorCode.MalformedMessage, (ushort)MeshMessageType.Vertex)); } MeshDetails meshEntry; if (!_meshes.TryGetValue(msg.MeshID, out meshEntry)) { return(new Error(ErrorCode.InvalidObjectID, msg.MeshID)); } if (msg.Count == 0) { return(new Error()); } int voffset = (int)msg.Offset; // Bounds check. int vertexCount = meshEntry.Mesh.VertexCount; if (voffset >= vertexCount || voffset + msg.Count > vertexCount) { return(new Error(ErrorCode.IndexingOutOfRange, (ushort)MeshMessageType.Vertex)); } // Check for settings initial bounds. bool ok = true; Vector3 v = Vector3.zero; _v3Buffer.Clear(); Vector3 minBounds = Vector3.zero; Vector3 maxBounds = Vector3.zero; for (int vInd = 0; ok && vInd < msg.Count; ++vInd) { v.x = reader.ReadSingle(); v.y = reader.ReadSingle(); v.z = reader.ReadSingle(); if (vInd > 0) { minBounds.x = Mathf.Min(minBounds.x, v.x); minBounds.y = Mathf.Min(minBounds.y, v.z); minBounds.z = Mathf.Min(minBounds.z, v.y); maxBounds.x = Mathf.Max(maxBounds.x, v.x); maxBounds.y = Mathf.Max(maxBounds.y, v.z); maxBounds.z = Mathf.Max(maxBounds.z, v.y); } else { minBounds = maxBounds = v; } _v3Buffer.Add(v); } meshEntry.Mesh.SetVertices(_v3Buffer, 0, voffset, _v3Buffer.Count); _v3Buffer.Clear(); // Update bounds. if (meshEntry.Mesh.BoundsSet) { minBounds.x = Mathf.Min(minBounds.x, meshEntry.Mesh.MinBounds.x); minBounds.y = Mathf.Min(minBounds.y, meshEntry.Mesh.MinBounds.z); minBounds.z = Mathf.Min(minBounds.z, meshEntry.Mesh.MinBounds.y); maxBounds.x = Mathf.Max(maxBounds.x, meshEntry.Mesh.MaxBounds.x); maxBounds.y = Mathf.Max(maxBounds.y, meshEntry.Mesh.MaxBounds.z); maxBounds.z = Mathf.Max(maxBounds.z, meshEntry.Mesh.MaxBounds.y); } meshEntry.Mesh.MinBounds = minBounds; meshEntry.Mesh.MaxBounds = maxBounds; if (!ok) { return(new Error(ErrorCode.MalformedMessage, (ushort)MeshMessageType.Vertex)); } return(new Error()); }
/// <summary> /// Handles <see cref="MeshComponentMessage"/> of type <see cref="MeshMessageType.Normal"/>. /// </summary> /// <param name="packet"></param> /// <param name="reader"></param> /// <returns></returns> protected Error AddNormals(PacketBuffer packet, BinaryReader reader) { MeshComponentMessage msg = new MeshComponentMessage(); if (!msg.Read(reader)) { return(new Error(ErrorCode.MalformedMessage, (ushort)MeshMessageType.Normal)); } MeshDetails meshEntry; if (!_meshes.TryGetValue(msg.MeshID, out meshEntry)) { return(new Error(ErrorCode.InvalidObjectID, msg.MeshID)); } if (msg.Count == 0) { return(new Error()); } int voffset = (int)msg.Offset; // Bounds check. int vertexCount = (int)meshEntry.Mesh.VertexCount; if (voffset >= vertexCount || voffset + msg.Count > vertexCount) { return(new Error(ErrorCode.IndexingOutOfRange, (ushort)MeshMessageType.Normal)); } // Check for settings initial bounds. bool ok = true; Vector3 n = Vector3.zero; _v3Buffer.Clear(); Vector3 boundsPadding = Vector3.zero; for (int vInd = 0; ok && vInd < (int)msg.Count; ++vInd) { n.x = reader.ReadSingle(); n.y = reader.ReadSingle(); n.z = reader.ReadSingle(); _v3Buffer.Add(n); // Bounds padding used to cater for voxel rendering. boundsPadding.x = Mathf.Max(boundsPadding.x, Mathf.Abs(n.x)); boundsPadding.y = Mathf.Max(boundsPadding.y, Mathf.Abs(n.y)); boundsPadding.z = Mathf.Max(boundsPadding.z, Mathf.Abs(n.z)); } meshEntry.Mesh.SetNormals(_v3Buffer, 0, voffset, _v3Buffer.Count); _v3Buffer.Clear(); // Pad the bounds by largest the normal for voxels. if (meshEntry.Mesh.DrawType == MeshDrawType.Voxels) { boundsPadding.x = Mathf.Max(boundsPadding.x, Mathf.Abs(meshEntry.Mesh.BoundsPadding.x)); boundsPadding.y = Mathf.Max(boundsPadding.y, Mathf.Abs(meshEntry.Mesh.BoundsPadding.y)); boundsPadding.z = Mathf.Max(boundsPadding.z, Mathf.Abs(meshEntry.Mesh.BoundsPadding.z)); meshEntry.Mesh.BoundsPadding = boundsPadding; } if (!ok) { return(new Error(ErrorCode.MalformedMessage, (ushort)MeshMessageType.Normal)); } return(new Error()); }