/// <summary> /// Handles <see cref="MeshFinaliseMessage"/>. /// </summary> /// <param name="packet"></param> /// <param name="reader"></param> /// <returns></returns> /// <remarks> /// This creates the required Unity <c>Mesh</c> objects and emits <see cref="OnMeshFinalised"/>. /// </remarks> protected Error FinaliseMesh(PacketBuffer packet, BinaryReader reader) { MeshFinaliseMessage msg = new MeshFinaliseMessage(); if (!msg.Read(reader)) { return(new Error(ErrorCode.MalformedMessage, MeshFinaliseMessage.MessageID)); } MeshDetails meshEntry; if (!_meshes.TryGetValue(msg.MeshID, out meshEntry)) { return(new Error(ErrorCode.InvalidObjectID, msg.MeshID)); } if (meshEntry.Finalised) { return(new Error(ErrorCode.MeshAlreadyFinalised, meshEntry.ID)); } bool generateNormals = (msg.Flags & (uint)MeshBuildFlags.CalculateNormals) != 0; if (generateNormals) { meshEntry.Mesh.CalculateNormals(); } SelectMaterial(meshEntry.Mesh); // Generate the meshes here. meshEntry.Finalised = true; NotifyMeshFinalised(meshEntry); return(new Error()); }
/// <summary> /// Handles transfer of mesh content. /// </summary> /// <param name="packet">The packet buffer in which to compose the transfer message.</param> /// <param name="byteLimit">An advisory byte limit used to restrict how much data should be sent (in bytes).</param> /// <param name="progress">The progress value from the last call to this method.</param> /// <returns>A new value for <paramref name="progress"/> to use on the next call.</returns> /// <remarks> /// Supports amortised transfer via the <paramref name="progress"/> argument. /// On first call, this is the default initialised structure (zero). On subsequent /// calls it is the last returned value unless <c>Failed</c> was true. /// /// The semantics of this value are entirely dependent on the internal implementation. /// </remarks> public void Transfer(PacketBuffer packet, int byteLimit, ref TransferProgress progress) { // Initial call? bool phaseComplete = false; switch (progress.Phase) { case (int)Phase.Vertex: phaseComplete = Transfer(packet, MeshMessageType.Vertex, Vertices(), byteLimit, ref progress); break; case (int)Phase.Index: if (IndexSize == 2) { phaseComplete = Transfer(packet, MeshMessageType.Index, Indices2(), byteLimit, ref progress); } else if (IndexSize == 4) { phaseComplete = Transfer(packet, MeshMessageType.Index, Indices4(), byteLimit, ref progress); } break; case (int)Phase.Normal: phaseComplete = Transfer(packet, MeshMessageType.Normal, Normals(), byteLimit, ref progress); break; case (int)Phase.Colour: phaseComplete = Transfer(packet, MeshMessageType.VertexColour, Colours(), byteLimit, ref progress); break; case (int)Phase.UV: phaseComplete = Transfer(packet, MeshMessageType.UV, UVs(), byteLimit, ref progress); break; case (int)Phase.Finalise: MeshFinaliseMessage msg = new MeshFinaliseMessage(); msg.MeshID = ID; msg.Flags = 0; if (CalculateNormals && (Components & MeshComponentFlag.Normal) != MeshComponentFlag.Normal) { msg.Flags |= (uint)MeshFinaliseFlag.CalculateNormals; } packet.Reset((ushort)RoutingID.Mesh, MeshFinaliseMessage.MessageID); msg.Write(packet); progress.Phase = (int)Phase.End; phaseComplete = true; break; } if (!progress.Failed) { if (phaseComplete) { progress.Phase = (int)NextPhase((Phase)progress.Phase); progress.Progress = 0; progress.Complete = progress.Phase == (int)Phase.End; } } }
/// <summary> /// Handles <see cref="MeshFinaliseMessage"/>. /// </summary> /// <param name="packet"></param> /// <param name="reader"></param> /// <returns></returns> /// <remarks> /// This creates the required Unity <c>Mesh</c> objects and emits <see cref="OnMeshFinalised"/>. /// </remarks> protected Error FinaliseMesh(PacketBuffer packet, BinaryReader reader) { MeshFinaliseMessage msg = new MeshFinaliseMessage(); if (!msg.Read(reader)) { return(new Error(ErrorCode.MalformedMessage, MeshFinaliseMessage.MessageID)); } MeshDetails meshDetails; if (!_meshes.TryGetValue(msg.MeshID, out meshDetails)) { return(new Error(ErrorCode.InvalidObjectID, msg.MeshID)); } if (meshDetails.Finalised) { return(new Error(ErrorCode.MeshAlreadyFinalised, meshDetails.ID)); } bool generateNormals = (msg.Flags & (uint)MeshBuildFlags.CalculateNormals) != 0; bool haveNormals = meshDetails.Builder.Normals.Length > 0; switch (meshDetails.Topology) { case MeshTopology.Triangles: case MeshTopology.Quads: if (haveNormals || generateNormals) { meshDetails.Material = LitMaterial; } else { meshDetails.Material = UnlitMaterial; } break; case MeshTopology.Points: generateNormals = false; if (meshDetails.DrawType == (byte)MeshDrawType.Voxels) { meshDetails.Material = VoxelsMaterial; generateNormals = !haveNormals; } else if (haveNormals) { meshDetails.Material = PointsLitMaterial; meshDetails.Material.SetInt("_LeftHanded", ServerInfo.IsLeftHanded ? 1 : 0); } else { meshDetails.Material = PointsUnlitMaterial; meshDetails.Material.SetInt("_LeftHanded", ServerInfo.IsLeftHanded ? 1 : 0); } //if (entry.VertexColours == null) //{ // entry.VertexColours = new Color32[entry.VertexCount]; // for (int i = 0; i < entry.VertexCount; ++i) // { // entry.VertexColours[i] = new Color32(1, 1, 1, 1); // } //} break; default: case MeshTopology.Lines: case MeshTopology.LineStrip: generateNormals = false; meshDetails.Material = UnlitMaterial; break; } // Generate the meshes here. Error err = new Error(); meshDetails.Builder.CalculateNormals = generateNormals; meshDetails.Builder.GetMeshes(); meshDetails.Finalised = true; NotifyMeshFinalised(meshDetails); return(err); }