public TextureBrowserWindow(Window owner, OptFile optFile) { InitializeComponent(); this.Owner = owner; this.DataContext = optFile; }
public OptCache(OptFile opt) { this.file = opt; this.BuildTextures(opt); this.BuildMeshes(opt); this.BuildMeshesWireframes(opt); }
public static IEnumerable <PlayabilityMessage> CheckTextures(OptFile opt) { if (opt == null) { yield break; } if (opt.Textures.Count != 0 && opt.TexturesBitsPerPixel == 0) { yield return(new PlayabilityMessage( PlayabilityMessageLevel.Error, "Textures", "All textures have not the same bpp.")); } if (opt.Textures.Count > 200) { yield return(new PlayabilityMessage( PlayabilityMessageLevel.Warning, "Textures", "This opt requires the textures count patch to work.")); } if (opt.Textures.Values.Any(t => t.Width > 256 || t.Height > 256)) { yield return(new PlayabilityMessage( PlayabilityMessageLevel.Warning, "Textures", "This opt requires the textures size patch to work.")); } if (opt.TexturesBitsPerPixel == 32) { yield return(new PlayabilityMessage( PlayabilityMessageLevel.Warning, "Textures", "This opt requires the 32-bit textures patch to work.")); } if (opt.TexturesBitsPerPixel == 32) { if (opt.Textures.Values.Any(t => t.MaximumMipmapsCount != t.MipmapsCount && t.MipmapsCount < 6)) { yield return(new PlayabilityMessage( PlayabilityMessageLevel.Error, "Textures", "Textures mipmaps have not been generated.")); } } }
public static IList <PlayabilityMessage> CheckPlayability(OptFile opt) { var messages = new List <PlayabilityMessage>(); messages.AddRange(PlayabilityChecker.OptInformations(opt)); messages.AddRange(PlayabilityChecker.CheckTextures(opt)); messages.AddRange(PlayabilityChecker.CheckGeometry(opt)); messages.AddRange(PlayabilityChecker.CheckEngineGlows(opt)); messages.AddRange(PlayabilityChecker.CheckHardpoints(opt)); messages.Sort(); return(messages); }
public static IList<PlayabilityMessage> CheckPlayability(OptFile opt) { var messages = new List<PlayabilityMessage>(); messages.AddRange(PlayabilityChecker.OptInformations(opt)); messages.AddRange(PlayabilityChecker.CheckTextures(opt)); messages.AddRange(PlayabilityChecker.CheckGeometry(opt)); messages.AddRange(PlayabilityChecker.CheckEngineGlows(opt)); messages.AddRange(PlayabilityChecker.CheckHardpoints(opt)); messages.Sort(); return messages; }
public static IEnumerable<PlayabilityMessage> CheckTextures(OptFile opt) { if (opt == null) { yield break; } if (opt.Textures.Count != 0 && opt.TexturesBitsPerPixel == 0) { yield return new PlayabilityMessage( PlayabilityMessageLevel.Error, "Textures", "All textures have not the same bpp."); } if (opt.Textures.Count > 200) { yield return new PlayabilityMessage( PlayabilityMessageLevel.Warning, "Textures", "This opt requires the textures count patch to work."); } if (opt.Textures.Values.Any(t => t.Width > 256 || t.Height > 256)) { yield return new PlayabilityMessage( PlayabilityMessageLevel.Warning, "Textures", "This opt requires the textures size patch to work."); } if (opt.TexturesBitsPerPixel == 32) { yield return new PlayabilityMessage( PlayabilityMessageLevel.Warning, "Textures", "This opt requires the 32-bit textures patch to work."); } if (opt.TexturesBitsPerPixel == 32) { if (opt.Textures.Values.Any(t => t.MaximumMipmapsCount != t.MipmapsCount && t.MipmapsCount < 6)) { yield return new PlayabilityMessage( PlayabilityMessageLevel.Error, "Textures", "Textures mipmaps have not been generated."); } } }
public static IEnumerable <PlayabilityMessage> CheckHardpoints(OptFile opt) { if (opt == null) { yield break; } if (opt.Meshes.SelectMany(t => t.Hardpoints).Count(t => t.HardpointType == HardpointType.CockpitSparks) > 16) { yield return(new PlayabilityMessage( PlayabilityMessageLevel.Error, "Hardpoints", "The maximun cockpit sparks count for an opt is 16")); } }
public static IEnumerable <PlayabilityMessage> CheckEngineGlows(OptFile opt) { if (opt == null) { yield break; } if (opt.EngineGlowsCount > 16) { yield return(new PlayabilityMessage( PlayabilityMessageLevel.Error, "Engine Glows", "The maximum engine glows count for an opt is 16")); } }
private void Execute_Open(object sender, ExecutedRoutedEventArgs e) { Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog(); dlg.Filter = "Xwa OPT files|*.opt"; if (dlg.ShowDialog() == true) { try { this.OptFile = OptFile.FromFile(dlg.FileName); } catch (Exception ex) { MessageBox.Show(ex.Message, ex.Source, MessageBoxButton.OK, MessageBoxImage.Error); } } }
public static IEnumerable <PlayabilityMessage> OptInformations(OptFile opt) { if (opt == null) { yield break; } yield return(new PlayabilityMessage( PlayabilityMessageLevel.Information, "Opt", "FileName: {0}", opt.FileName)); yield return(new PlayabilityMessage( PlayabilityMessageLevel.Information, "Textures", "Textures Bits Per Pixel: {0}", opt.TexturesBitsPerPixel)); }
public static IEnumerable<PlayabilityMessage> OptInformations(OptFile opt) { if (opt == null) { yield break; } yield return new PlayabilityMessage( PlayabilityMessageLevel.Information, "Opt", "FileName: {0}", opt.FileName); yield return new PlayabilityMessage( PlayabilityMessageLevel.Information, "Textures", "Textures Bits Per Pixel: {0}", opt.TexturesBitsPerPixel); }
public static IEnumerable <PlayabilityMessage> CheckGeometry(OptFile opt) { if (opt == null) { yield break; } if (opt.Meshes.Count > 50) { yield return(new PlayabilityMessage( PlayabilityMessageLevel.Error, "Meshes", "The maximum meshes count for an opt is 50.")); } if (opt.Meshes.Any(t => t.Vertices.Count > 512)) { yield return(new PlayabilityMessage( PlayabilityMessageLevel.Error, "Meshes", "The maximum vertices count for a mesh is 512")); } }
public static void OptToObj(OptFile opt, string objPath, bool scale) { if (opt == null) { throw new ArgumentNullException("opt"); } string objDirectory = Path.GetDirectoryName(objPath); string objName = Path.GetFileNameWithoutExtension(objPath); var objMaterials = new ObjMaterialDictionary(); foreach (var texture in opt.Textures.Values) { var material = new ObjMaterial { Name = texture.Name, DiffuseMapFileName = string.Format(CultureInfo.InvariantCulture, "{0}.png", texture.Name) }; texture.Save(Path.Combine(objDirectory, material.DiffuseMapFileName)); if (texture.HasAlpha) { material.AlphaMapFileName = string.Format(CultureInfo.InvariantCulture, "{0}_alpha.png", texture.Name); texture.SaveAlphaMap(Path.Combine(objDirectory, material.AlphaMapFileName)); } objMaterials.Add(texture.Name, material); } objMaterials.Save(Path.ChangeExtension(objPath, "mtl")); var distances = opt.Meshes .SelectMany(t => t.Lods) .Select(t => t.Distance) .Distinct() .OrderByDescending(t => t) .ToArray(); for (int distance = 0; distance < distances.Length; distance++) { var obj = new ObjFile(); int objectsIndex = 0; int verticesIndex = 0; int verticesTexIndex = 0; int verticesNormalIndex = 0; foreach (var mesh in opt.Meshes) { var lod = mesh.Lods.FirstOrDefault(t => t.Distance <= distances[distance]); if (lod == null) { continue; } var objMesh = new ObjMesh(string.Format(CultureInfo.InvariantCulture, "{0}.{1:D3}", mesh.Descriptor.MeshType, objectsIndex)); obj.Meshes.Add(objMesh); objectsIndex++; if (scale) { foreach (var v in mesh.Vertices) { obj.Vertices.Add(new ObjVector3(v.X * OptFile.ScaleFactor, v.Z * OptFile.ScaleFactor, v.Y * OptFile.ScaleFactor)); } } else { foreach (var v in mesh.Vertices) { obj.Vertices.Add(new ObjVector3(v.X, v.Z, v.Y)); } } foreach (var v in mesh.TextureCoordinates) { obj.VertexTexCoords.Add(new ObjVector2(v.U, -v.V)); } foreach (var v in mesh.VertexNormals) { obj.VertexNormals.Add(new ObjVector3(v.X, v.Z, v.Y)); } foreach (var faceGroup in lod.FaceGroups) { var objFaceGroup = new ObjFaceGroup(); if (faceGroup.Textures.Count > 0) { objFaceGroup.MaterialName = faceGroup.Textures[0]; } objMesh.FaceGroups.Add(objFaceGroup); foreach (var face in faceGroup.Faces) { if (face.VerticesIndex.D < 0) { objFaceGroup.Faces.Add(new ObjFace() { VerticesIndex = new ObjIndex( verticesIndex + face.VerticesIndex.A, verticesIndex + face.VerticesIndex.B, verticesIndex + face.VerticesIndex.C ), VertexTexCoordsIndex = new ObjIndex( verticesTexIndex + face.TextureCoordinatesIndex.A, verticesTexIndex + face.TextureCoordinatesIndex.B, verticesTexIndex + face.TextureCoordinatesIndex.C), VertexNormalsIndex = new ObjIndex( verticesNormalIndex + face.VertexNormalsIndex.A, verticesNormalIndex + face.VertexNormalsIndex.B, verticesNormalIndex + face.VertexNormalsIndex.C) }); } else { objFaceGroup.Faces.Add(new ObjFace() { VerticesIndex = new ObjIndex( verticesIndex + face.VerticesIndex.A, verticesIndex + face.VerticesIndex.B, verticesIndex + face.VerticesIndex.C, verticesIndex + face.VerticesIndex.D ), VertexTexCoordsIndex = new ObjIndex( verticesTexIndex + face.TextureCoordinatesIndex.A, verticesTexIndex + face.TextureCoordinatesIndex.B, verticesTexIndex + face.TextureCoordinatesIndex.C, verticesTexIndex + face.TextureCoordinatesIndex.D), VertexNormalsIndex = new ObjIndex( verticesNormalIndex + face.VertexNormalsIndex.A, verticesNormalIndex + face.VertexNormalsIndex.B, verticesNormalIndex + face.VertexNormalsIndex.C, verticesNormalIndex + face.VertexNormalsIndex.D) }); } } } verticesIndex += mesh.Vertices.Count; verticesTexIndex += mesh.TextureCoordinates.Count; verticesNormalIndex += mesh.VertexNormals.Count; } obj.Save(Path.Combine(objDirectory, string.Format(CultureInfo.InvariantCulture, "{0}_{1}.obj", objName, distance)), objName); } }
public static void OptToObj(OptFile opt, string objPath) { Converter.OptToObj(opt, objPath, true); }
public static OptFile ObjToOpt(string objPath, bool scale) { string objDirectory = Path.GetDirectoryName(objPath); var obj = ObjFile.FromFile(objPath); var opt = new OptFile(); foreach (var mesh in obj.Meshes) { var optMesh = new Mesh(); opt.Meshes.Add(optMesh); if (scale) { foreach (var v in obj.Vertices) { optMesh.Vertices.Add(new Vector(v.X / OptFile.ScaleFactor, v.Z / OptFile.ScaleFactor, v.Y / OptFile.ScaleFactor)); } } else { foreach (var v in obj.Vertices) { optMesh.Vertices.Add(new Vector(v.X, v.Z, v.Y)); } } foreach (var v in obj.VertexTexCoords) { optMesh.TextureCoordinates.Add(new TextureCoordinates(v.U, -v.V)); } foreach (var v in obj.VertexNormals) { optMesh.VertexNormals.Add(new Vector(v.X, v.Z, v.Y)); } optMesh.TextureCoordinates.Add(new TextureCoordinates(0, 0)); optMesh.TextureCoordinates.Add(new TextureCoordinates(1, 0)); optMesh.TextureCoordinates.Add(new TextureCoordinates(1, 1)); optMesh.TextureCoordinates.Add(new TextureCoordinates(0, 1)); var optLod = new MeshLod(); optMesh.Lods.Add(optLod); foreach (var faceGroup in mesh.FaceGroups) { var optFaceGroup = new FaceGroup(); optLod.FaceGroups.Add(optFaceGroup); if (!string.IsNullOrEmpty(faceGroup.MaterialName)) { optFaceGroup.Textures.Add(faceGroup.MaterialName); } foreach (var face in faceGroup.Faces) { Index verticesIndex = new Index( face.VerticesIndex.A, face.VerticesIndex.B, face.VerticesIndex.C, face.VerticesIndex.D); if (verticesIndex.A >= optMesh.Vertices.Count) { verticesIndex.A = 0; } if (verticesIndex.B >= optMesh.Vertices.Count) { verticesIndex.B = 0; } if (verticesIndex.C >= optMesh.Vertices.Count) { verticesIndex.C = 0; } if (verticesIndex.D >= optMesh.Vertices.Count) { verticesIndex.D = 0; } Index textureCoordinatesIndex = new Index( face.VertexTexCoordsIndex.A, face.VertexTexCoordsIndex.B, face.VertexTexCoordsIndex.C, face.VertexTexCoordsIndex.D); if (textureCoordinatesIndex.A >= optMesh.TextureCoordinates.Count) { textureCoordinatesIndex.A = 0; } if (textureCoordinatesIndex.B >= optMesh.TextureCoordinates.Count) { textureCoordinatesIndex.B = 0; } if (textureCoordinatesIndex.C >= optMesh.TextureCoordinates.Count) { textureCoordinatesIndex.C = 0; } if (textureCoordinatesIndex.D >= optMesh.TextureCoordinates.Count) { textureCoordinatesIndex.D = 0; } Index vertexNormalsIndex = new Index( face.VertexNormalsIndex.A, face.VertexNormalsIndex.B, face.VertexNormalsIndex.C, face.VertexNormalsIndex.D); if (vertexNormalsIndex.A >= optMesh.VertexNormals.Count) { vertexNormalsIndex.A = 0; } if (vertexNormalsIndex.B >= optMesh.VertexNormals.Count) { vertexNormalsIndex.B = 0; } if (vertexNormalsIndex.C >= optMesh.VertexNormals.Count) { vertexNormalsIndex.C = 0; } if (vertexNormalsIndex.D >= optMesh.VertexNormals.Count) { vertexNormalsIndex.D = 0; } if (textureCoordinatesIndex.A < 0 || textureCoordinatesIndex.B < 0 || textureCoordinatesIndex.C < 0 || (verticesIndex.D >= 0 && textureCoordinatesIndex.D < 0)) { textureCoordinatesIndex.A = optMesh.TextureCoordinates.Count - 4; textureCoordinatesIndex.B = optMesh.TextureCoordinates.Count - 3; textureCoordinatesIndex.C = optMesh.TextureCoordinates.Count - 2; textureCoordinatesIndex.D = verticesIndex.D < 0 ? -1 : optMesh.TextureCoordinates.Count - 1; } Vector normal = Vector.Normal( optMesh.Vertices.ElementAtOrDefault(verticesIndex.A), optMesh.Vertices.ElementAtOrDefault(verticesIndex.B), optMesh.Vertices.ElementAtOrDefault(verticesIndex.C)); if (vertexNormalsIndex.A < 0 || vertexNormalsIndex.B < 0 || vertexNormalsIndex.C < 0 || (verticesIndex.D >= 0 && vertexNormalsIndex.D < 0)) { optMesh.VertexNormals.Add(normal); vertexNormalsIndex.A = optMesh.VertexNormals.Count - 1; vertexNormalsIndex.B = optMesh.VertexNormals.Count - 1; vertexNormalsIndex.C = optMesh.VertexNormals.Count - 1; vertexNormalsIndex.D = verticesIndex.D < 0 ? -1 : optMesh.VertexNormals.Count - 1; } var optFace = new Face() { VerticesIndex = verticesIndex, TextureCoordinatesIndex = textureCoordinatesIndex, VertexNormalsIndex = vertexNormalsIndex, Normal = normal }; optFaceGroup.Faces.Add(optFace); } } } opt.CompactBuffers(); opt.ComputeHitzones(); foreach (var material in obj.Materials.Values) { Texture texture; if (material.DiffuseMapFileName == null) { var color = material.DiffuseColor; byte r = (byte)(color.X * 255.0f); byte g = (byte)(color.Y * 255.0f); byte b = (byte)(color.Z * 255.0f); int width = 8; int height = 8; int length = width * height; byte[] data = new byte[length * 4]; for (int i = 0; i < length; i++) { data[i * 4 + 0] = b; data[i * 4 + 1] = g; data[i * 4 + 2] = r; data[i * 4 + 3] = 255; } texture = new Texture(); texture.Name = material.Name; texture.Width = width; texture.Height = height; texture.ImageData = data; } else { string colorFileName = Path.Combine(objDirectory, material.DiffuseMapFileName); texture = Texture.FromFile(colorFileName); texture.Name = material.Name; } if (material.AlphaMapFileName != null) { string alphaFileName = Path.Combine(objDirectory, material.AlphaMapFileName); texture.SetAlphaMap(alphaFileName); } else if (material.DissolveFactor > 0.0f && material.DissolveFactor < 1.0f) { byte alpha = (byte)(material.DissolveFactor * 255.0f); int length = texture.Width * texture.Height; byte[] alphaData = new byte[length]; var data = texture.ImageData; for (int i = 0; i < length; i++) { alphaData[i] = alpha; data[i * 4 + 3] = alpha; } texture.AlphaData = alphaData; } opt.Textures.Add(texture.Name, texture); } opt.GenerateTexturesMipmaps(); return opt; }
public static OptFile FromFile(string path) { OptFile opt = new OptFile(); opt.FileName = path; OptFileNodes optNodes = OptFileNodes.FromFile(path); List <string> globalTexture = null; for (int meshId = 0; meshId < optNodes.Nodes.Count; meshId++) { if (meshId == 0 && optNodes.Nodes[meshId].NodeType == NodeType.Texture) { TextureNode textureNode = (TextureNode)optNodes.Nodes[meshId]; opt.CreateTexture(textureNode); globalTexture = new List <string>() { textureNode.Name }; continue; } if (optNodes.Nodes[meshId].NodeType != NodeType.NodeGroup) { throw new InvalidDataException("invalid mesh"); } NodeGroupNode meshNode = (NodeGroupNode)optNodes.Nodes[meshId]; var meshNodes = meshNode.Nodes.Union((meshNode.Nodes.Where(t => t.NodeType == NodeType.NodeGroup).FirstOrDefault() ?? new NodeGroupNode()).Nodes).ToList(); RotationScaleNode rotationScaleNode = (RotationScaleNode)meshNodes.FirstOrDefault(t => t.NodeType == NodeType.RotationScale); MeshDescriptorNode descriptorNode = (MeshDescriptorNode)meshNodes.FirstOrDefault(t => t.NodeType == NodeType.MeshDescriptor); MeshVerticesNode verticesNode = (MeshVerticesNode)meshNodes.First(t => t.NodeType == NodeType.MeshVertices); TextureCoordinatesNode textureVerticesNode = (TextureCoordinatesNode)meshNodes.First(t => t.NodeType == NodeType.TextureCoordinates); VertexNormalsNode vertexNormalsNode = (VertexNormalsNode)meshNodes.First(t => t.NodeType == NodeType.VertexNormals); var hardpointsNodes = meshNodes.Where(t => t.NodeType == NodeType.Hardpoint).Select(t => (HardpointNode)t).ToList(); var engineGlowsNodes = meshNodes.Where(t => t.NodeType == NodeType.EngineGlow).Select(t => (EngineGlowNode)t).ToList(); FaceGroupingNode faceGroupingNode = (FaceGroupingNode)meshNodes.First(t => t.NodeType == NodeType.FaceGrouping); Mesh mesh = new Mesh(); if (rotationScaleNode != null) { mesh.RotationScale.Pivot = rotationScaleNode.Pivot; mesh.RotationScale.Look = rotationScaleNode.Look; mesh.RotationScale.Up = rotationScaleNode.Up; mesh.RotationScale.Right = rotationScaleNode.Right; } if (descriptorNode != null) { mesh.Descriptor.MeshType = descriptorNode.MeshType; mesh.Descriptor.ExplosionType = descriptorNode.ExplosionType; mesh.Descriptor.Span = descriptorNode.Span; mesh.Descriptor.Center = descriptorNode.Center; mesh.Descriptor.Min = descriptorNode.Min; mesh.Descriptor.Max = descriptorNode.Max; mesh.Descriptor.TargetId = descriptorNode.TargetId; mesh.Descriptor.Target = descriptorNode.Target; } foreach (Vector vertex in verticesNode.Vertices) { mesh.Vertices.Add(vertex); } foreach (TextureCoordinates textureVertex in textureVerticesNode.TextureVertices) { mesh.TextureCoordinates.Add(textureVertex); } foreach (Vector normal in vertexNormalsNode.Normals) { mesh.VertexNormals.Add(normal); } foreach (var hardpoint in hardpointsNodes) { mesh.Hardpoints.Add(new Hardpoint() { HardpointType = hardpoint.HardpointType, Position = hardpoint.Position }); } foreach (var engineGlow in engineGlowsNodes) { mesh.EngineGlows.Add(new EngineGlow() { IsDisabled = engineGlow.IsDisabled, CoreColor = engineGlow.CoreColor, OuterColor = engineGlow.OuterColor, Position = engineGlow.Position, Format = engineGlow.Format, Look = engineGlow.Look, Up = engineGlow.Up, Right = engineGlow.Right }); } if (faceGroupingNode.Distances.Count != faceGroupingNode.Nodes.Count) { throw new InvalidDataException("invalid face groups count in face grouping"); } for (int lodId = 0; lodId < faceGroupingNode.Distances.Count; lodId++) { List <string> texture = globalTexture; MeshLod lod = new MeshLod(); lod.Distance = faceGroupingNode.Distances[lodId]; foreach (Node node in faceGroupingNode.Nodes[lodId].Nodes) { switch (node.NodeType) { case NodeType.Texture: { TextureNode textureNode = (TextureNode)node; opt.CreateTexture(textureNode); texture = new List <string>() { textureNode.Name }; break; } case NodeType.NodeReference: texture = new List <string>() { ((NodeReferenceNode)node).Reference }; break; case NodeType.NodeSwitch: { NodeSwitchNode switchNode = (NodeSwitchNode)node; texture = new List <string>(); foreach (Node nodeSwitch in switchNode.Nodes) { switch (nodeSwitch.NodeType) { case NodeType.Texture: { TextureNode textureNode = (TextureNode)nodeSwitch; opt.CreateTexture(textureNode); texture.Add(textureNode.Name); break; } case NodeType.NodeReference: texture.Add(((NodeReferenceNode)nodeSwitch).Reference); break; } } break; } case NodeType.FaceData: { FaceDataNode faceDataNode = (FaceDataNode)node; FaceGroup faceGroup = new FaceGroup(); if (texture != null) { foreach (var name in texture) { faceGroup.Textures.Add(name); } } foreach (var face in faceDataNode.Faces) { faceGroup.Faces.Add(new Face() { VerticesIndex = face.VerticesIndex, EdgesIndex = face.EdgesIndex, TextureCoordinatesIndex = face.TextureCoordinatesIndex, VertexNormalsIndex = face.VertexNormalsIndex, Normal = face.Normal, TexturingDirection = face.TexturingDirection, TexturingMagniture = face.TexturingMagniture }); } foreach (var face in faceGroup.Faces) { if (face.VertexNormalsIndex.A >= mesh.VertexNormals.Count) { face.VertexNormalsIndex = face.VertexNormalsIndex.SetA(0); } if (face.VertexNormalsIndex.B >= mesh.VertexNormals.Count) { face.VertexNormalsIndex = face.VertexNormalsIndex.SetB(0); } if (face.VertexNormalsIndex.C >= mesh.VertexNormals.Count) { face.VertexNormalsIndex = face.VertexNormalsIndex.SetC(0); } if (face.VertexNormalsIndex.D >= mesh.VertexNormals.Count) { face.VertexNormalsIndex = face.VertexNormalsIndex.SetD(0); } if (face.TextureCoordinatesIndex.A >= mesh.TextureCoordinates.Count) { face.TextureCoordinatesIndex = face.TextureCoordinatesIndex.SetA(0); } if (face.TextureCoordinatesIndex.B >= mesh.TextureCoordinates.Count) { face.TextureCoordinatesIndex = face.TextureCoordinatesIndex.SetB(0); } if (face.TextureCoordinatesIndex.C >= mesh.TextureCoordinates.Count) { face.TextureCoordinatesIndex = face.TextureCoordinatesIndex.SetC(0); } if (face.TextureCoordinatesIndex.D >= mesh.TextureCoordinates.Count) { face.TextureCoordinatesIndex = face.TextureCoordinatesIndex.SetD(0); } if (face.VerticesIndex.A >= 0 && face.TextureCoordinatesIndex.A < 0) { face.TextureCoordinatesIndex = face.TextureCoordinatesIndex.SetA(0); } if (face.VerticesIndex.B >= 0 && face.TextureCoordinatesIndex.B < 0) { face.TextureCoordinatesIndex = face.TextureCoordinatesIndex.SetB(0); } if (face.VerticesIndex.C >= 0 && face.TextureCoordinatesIndex.C < 0) { face.TextureCoordinatesIndex = face.TextureCoordinatesIndex.SetC(0); } if (face.VerticesIndex.D >= 0 && face.TextureCoordinatesIndex.D < 0) { face.TextureCoordinatesIndex = face.TextureCoordinatesIndex.SetD(0); } } lod.FaceGroups.Add(faceGroup); texture = null; break; } } } mesh.Lods.Add(lod); } opt.Meshes.Add(mesh); } opt.SetFaceGroupTextureWhenEmpty(); return(opt); }
public OptModel() { this.PlayabilityMessages = new ObservableCollection<PlayabilityMessage>(); this.file = new OptFile(); }
public static OptFile FromFile(string path) { OptFile opt = new OptFile(); opt.FileName = path; OptFileNodes optNodes = OptFileNodes.FromFile(path); List<string> globalTexture = null; for (int meshId = 0; meshId < optNodes.Nodes.Count; meshId++) { if (meshId == 0 && optNodes.Nodes[meshId].NodeType == NodeType.Texture) { TextureNode textureNode = (TextureNode)optNodes.Nodes[meshId]; opt.CreateTexture(textureNode); globalTexture = new List<string>() { textureNode.Name }; continue; } if (optNodes.Nodes[meshId].NodeType != NodeType.NodeGroup) { throw new InvalidDataException("invalid mesh"); } NodeGroupNode meshNode = (NodeGroupNode)optNodes.Nodes[meshId]; var meshNodes = meshNode.Nodes.Union((meshNode.Nodes.Where(t => t.NodeType == NodeType.NodeGroup).FirstOrDefault() ?? new NodeGroupNode()).Nodes).ToList(); RotationScaleNode rotationScaleNode = (RotationScaleNode)meshNodes.FirstOrDefault(t => t.NodeType == NodeType.RotationScale); MeshDescriptorNode descriptorNode = (MeshDescriptorNode)meshNodes.FirstOrDefault(t => t.NodeType == NodeType.MeshDescriptor); MeshVerticesNode verticesNode = (MeshVerticesNode)meshNodes.First(t => t.NodeType == NodeType.MeshVertices); TextureCoordinatesNode textureVerticesNode = (TextureCoordinatesNode)meshNodes.First(t => t.NodeType == NodeType.TextureCoordinates); VertexNormalsNode vertexNormalsNode = (VertexNormalsNode)meshNodes.First(t => t.NodeType == NodeType.VertexNormals); var hardpointsNodes = meshNodes.Where(t => t.NodeType == NodeType.Hardpoint).Select(t => (HardpointNode)t).ToList(); var engineGlowsNodes = meshNodes.Where(t => t.NodeType == NodeType.EngineGlow).Select(t => (EngineGlowNode)t).ToList(); FaceGroupingNode faceGroupingNode = (FaceGroupingNode)meshNodes.First(t => t.NodeType == NodeType.FaceGrouping); Mesh mesh = new Mesh(); if (rotationScaleNode != null) { mesh.RotationScale.Pivot = rotationScaleNode.Pivot; mesh.RotationScale.Look = rotationScaleNode.Look; mesh.RotationScale.Up = rotationScaleNode.Up; mesh.RotationScale.Right = rotationScaleNode.Right; } if (descriptorNode != null) { mesh.Descriptor.MeshType = descriptorNode.MeshType; mesh.Descriptor.ExplosionType = descriptorNode.ExplosionType; mesh.Descriptor.Span = descriptorNode.Span; mesh.Descriptor.Center = descriptorNode.Center; mesh.Descriptor.Min = descriptorNode.Min; mesh.Descriptor.Max = descriptorNode.Max; mesh.Descriptor.TargetId = descriptorNode.TargetId; mesh.Descriptor.Target = descriptorNode.Target; } foreach (Vector vertex in verticesNode.Vertices) { mesh.Vertices.Add(vertex); } foreach (TextureCoordinates textureVertex in textureVerticesNode.TextureVertices) { mesh.TextureCoordinates.Add(textureVertex); } foreach (Vector normal in vertexNormalsNode.Normals) { mesh.VertexNormals.Add(normal); } foreach (var hardpoint in hardpointsNodes) { mesh.Hardpoints.Add(new Hardpoint() { HardpointType = hardpoint.HardpointType, Position = hardpoint.Position }); } foreach (var engineGlow in engineGlowsNodes) { mesh.EngineGlows.Add(new EngineGlow() { IsDisabled = engineGlow.IsDisabled, CoreColor = engineGlow.CoreColor, OuterColor = engineGlow.OuterColor, Position = engineGlow.Position, Format = engineGlow.Format, Look = engineGlow.Look, Up = engineGlow.Up, Right = engineGlow.Right }); } if (faceGroupingNode.Distances.Count != faceGroupingNode.Nodes.Count) { throw new InvalidDataException("invalid face groups count in face grouping"); } for (int lodId = 0; lodId < faceGroupingNode.Distances.Count; lodId++) { List<string> texture = globalTexture; MeshLod lod = new MeshLod(); lod.Distance = faceGroupingNode.Distances[lodId]; foreach (Node node in faceGroupingNode.Nodes[lodId].Nodes) { switch (node.NodeType) { case NodeType.Texture: { TextureNode textureNode = (TextureNode)node; opt.CreateTexture(textureNode); texture = new List<string>() { textureNode.Name }; break; } case NodeType.NodeReference: texture = new List<string>() { ((NodeReferenceNode)node).Reference }; break; case NodeType.NodeSwitch: { NodeSwitchNode switchNode = (NodeSwitchNode)node; texture = new List<string>(); foreach (Node nodeSwitch in switchNode.Nodes) { switch (nodeSwitch.NodeType) { case NodeType.Texture: { TextureNode textureNode = (TextureNode)nodeSwitch; opt.CreateTexture(textureNode); texture.Add(textureNode.Name); break; } case NodeType.NodeReference: texture.Add(((NodeReferenceNode)nodeSwitch).Reference); break; } } break; } case NodeType.FaceData: { FaceDataNode faceDataNode = (FaceDataNode)node; FaceGroup faceGroup = new FaceGroup(); if (texture != null) { foreach (var name in texture) { faceGroup.Textures.Add(name); } } foreach (var face in faceDataNode.Faces) { faceGroup.Faces.Add(new Face() { VerticesIndex = face.VerticesIndex, EdgesIndex = face.EdgesIndex, TextureCoordinatesIndex = face.TextureCoordinatesIndex, VertexNormalsIndex = face.VertexNormalsIndex, Normal = face.Normal, TexturingDirection = face.TexturingDirection, TexturingMagniture = face.TexturingMagniture }); } foreach (var face in faceGroup.Faces) { if (face.VertexNormalsIndex.A >= mesh.VertexNormals.Count) { face.VertexNormalsIndex = face.VertexNormalsIndex.SetA(0); } if (face.VertexNormalsIndex.B >= mesh.VertexNormals.Count) { face.VertexNormalsIndex = face.VertexNormalsIndex.SetB(0); } if (face.VertexNormalsIndex.C >= mesh.VertexNormals.Count) { face.VertexNormalsIndex = face.VertexNormalsIndex.SetC(0); } if (face.VertexNormalsIndex.D >= mesh.VertexNormals.Count) { face.VertexNormalsIndex = face.VertexNormalsIndex.SetD(0); } if (face.TextureCoordinatesIndex.A >= mesh.TextureCoordinates.Count) { face.TextureCoordinatesIndex = face.TextureCoordinatesIndex.SetA(0); } if (face.TextureCoordinatesIndex.B >= mesh.TextureCoordinates.Count) { face.TextureCoordinatesIndex = face.TextureCoordinatesIndex.SetB(0); } if (face.TextureCoordinatesIndex.C >= mesh.TextureCoordinates.Count) { face.TextureCoordinatesIndex = face.TextureCoordinatesIndex.SetC(0); } if (face.TextureCoordinatesIndex.D >= mesh.TextureCoordinates.Count) { face.TextureCoordinatesIndex = face.TextureCoordinatesIndex.SetD(0); } if (face.VerticesIndex.A >= 0 && face.TextureCoordinatesIndex.A < 0) { face.TextureCoordinatesIndex = face.TextureCoordinatesIndex.SetA(0); } if (face.VerticesIndex.B >= 0 && face.TextureCoordinatesIndex.B < 0) { face.TextureCoordinatesIndex = face.TextureCoordinatesIndex.SetB(0); } if (face.VerticesIndex.C >= 0 && face.TextureCoordinatesIndex.C < 0) { face.TextureCoordinatesIndex = face.TextureCoordinatesIndex.SetC(0); } if (face.VerticesIndex.D >= 0 && face.TextureCoordinatesIndex.D < 0) { face.TextureCoordinatesIndex = face.TextureCoordinatesIndex.SetD(0); } } lod.FaceGroups.Add(faceGroup); texture = null; break; } } } mesh.Lods.Add(lod); } opt.Meshes.Add(mesh); } opt.SetFaceGroupTextureWhenEmpty(); return opt; }
public static IEnumerable<PlayabilityMessage> CheckEngineGlows(OptFile opt) { if (opt == null) { yield break; } if (opt.EngineGlowsCount > 16) { yield return new PlayabilityMessage( PlayabilityMessageLevel.Error, "Engine Glows", "The maximum engine glows count for an opt is 16"); } }
public static void OptToAn8(OptFile opt, string an8Path) { Converter.OptToAn8(opt, an8Path, true); }
public TextureBrowserMessage(OptFile optFile) { this.OptFile = optFile; }
private static BitmapSource CreateTexture(OptFile opt, string name) { if (!opt.Textures.ContainsKey(name)) { return null; } var texture = opt.Textures[name]; int size = texture.Width * texture.Height; int bpp = texture.BitsPerPixel; if (bpp == 8) { var palette = new BitmapPalette(Enumerable.Range(0, 256) .Select(i => { ushort c = BitConverter.ToUInt16(texture.Palette, 8 * 512 + i * 2); byte r = (byte)((c & 0xF800) >> 11); byte g = (byte)((c & 0x7E0) >> 5); byte b = (byte)(c & 0x1F); r = (byte)((r * (0xffU * 2) + 0x1fU) / (0x1fU * 2)); g = (byte)((g * (0xffU * 2) + 0x3fU) / (0x3fU * 2)); b = (byte)((b * (0xffU * 2) + 0x1fU) / (0x1fU * 2)); return Color.FromRgb(r, g, b); }) .ToList()); if (texture.AlphaData == null) { byte[] imageData = new byte[size]; Array.Copy(texture.ImageData, imageData, size); return BitmapSource.Create(texture.Width, texture.Height, 96, 96, PixelFormats.Indexed8, palette, imageData, texture.Width); } else { byte[] imageData = new byte[size * 4]; for (int i = 0; i < size; i++) { int colorIndex = texture.ImageData[i]; imageData[i * 4 + 0] = palette.Colors[colorIndex].B; imageData[i * 4 + 1] = palette.Colors[colorIndex].G; imageData[i * 4 + 2] = palette.Colors[colorIndex].R; imageData[i * 4 + 3] = texture.AlphaData[i]; } return BitmapSource.Create(texture.Width, texture.Height, 96, 96, PixelFormats.Bgra32, null, imageData, texture.Width * 4); } } else if (bpp == 32) { byte[] imageData = new byte[size * 4]; Array.Copy(texture.ImageData, imageData, size * 4); return BitmapSource.Create(texture.Width, texture.Height, 96, 96, PixelFormats.Bgra32, null, imageData, texture.Width * 4); } else { return null; } }
public static IEnumerable<PlayabilityMessage> CheckHardpoints(OptFile opt) { if (opt == null) { yield break; } if (opt.Meshes.SelectMany(t => t.Hardpoints).Count(t => t.HardpointType == HardpointType.CockpitSparks) > 16) { yield return new PlayabilityMessage( PlayabilityMessageLevel.Error, "Hardpoints", "The maximun cockpit sparks count for an opt is 16"); } }
private void BuildMeshes(OptFile opt) { this.meshes = null; if (opt == null) { return; } this.meshes = new MeshGeometry3D[opt.Meshes.Count][][][]; for (int meshIndex = 0; meshIndex < opt.Meshes.Count; meshIndex++) { var mesh = opt.Meshes[meshIndex]; var positions = new Point3DCollection( mesh.Vertices .Select(t => new Point3D(-t.Y, -t.X, t.Z))); var normals = new Vector3DCollection( mesh.VertexNormals .Select(t => new Vector3D(-t.Y, -t.X, t.Z))); var textureCoordinates = new PointCollection( mesh.TextureCoordinates .Select(t => new Point(t.U, t.V))); this.meshes[meshIndex] = new MeshGeometry3D[mesh.Lods.Count][][]; for (int lodIndex = 0; lodIndex < mesh.Lods.Count; lodIndex++) { var lod = mesh.Lods[lodIndex]; this.meshes[meshIndex][lodIndex] = new MeshGeometry3D[lod.FaceGroups.Count][]; for (int faceGroupIndex = 0; faceGroupIndex < lod.FaceGroups.Count; faceGroupIndex++) { var faceGroup = lod.FaceGroups[faceGroupIndex]; MeshGeometry3D[] geometries = new MeshGeometry3D[faceGroup.Faces.Count + 1]; for (int faceIndex = 0; faceIndex < faceGroup.Faces.Count; faceIndex++) { var face = faceGroup.Faces[faceIndex]; MeshGeometry3D geometry = new MeshGeometry3D(); int index = 0; Index positionsIndex = face.VerticesIndex; Index normalsIndex = face.VertexNormalsIndex; Index textureCoordinatesIndex = face.TextureCoordinatesIndex; geometry.Positions.Add(positions.ElementAtOrDefault(positionsIndex.A)); geometry.Normals.Add(normals.ElementAtOrDefault(normalsIndex.A)); geometry.TextureCoordinates.Add(textureCoordinates.ElementAtOrDefault(textureCoordinatesIndex.A)); geometry.TriangleIndices.Add(index); index++; geometry.Positions.Add(positions.ElementAtOrDefault(positionsIndex.B)); geometry.Normals.Add(normals.ElementAtOrDefault(normalsIndex.B)); geometry.TextureCoordinates.Add(textureCoordinates.ElementAtOrDefault(textureCoordinatesIndex.B)); geometry.TriangleIndices.Add(index); index++; geometry.Positions.Add(positions.ElementAtOrDefault(positionsIndex.C)); geometry.Normals.Add(normals.ElementAtOrDefault(normalsIndex.C)); geometry.TextureCoordinates.Add(textureCoordinates.ElementAtOrDefault(textureCoordinatesIndex.C)); geometry.TriangleIndices.Add(index); index++; if (positionsIndex.D >= 0) { geometry.TriangleIndices.Add(index - 3); geometry.TriangleIndices.Add(index - 1); geometry.Positions.Add(positions.ElementAtOrDefault(positionsIndex.D)); geometry.Normals.Add(normals.ElementAtOrDefault(normalsIndex.D)); geometry.TextureCoordinates.Add(textureCoordinates.ElementAtOrDefault(textureCoordinatesIndex.D)); geometry.TriangleIndices.Add(index); index++; } geometry.Freeze(); geometries[1 + faceIndex] = geometry; } MeshGeometry3D geometryGroup = new MeshGeometry3D(); for (int i = 1; i < geometries.Length; i++) { MergeGeometry(geometryGroup, geometries[i]); } geometryGroup.Freeze(); geometries[0] = geometryGroup; this.meshes[meshIndex][lodIndex][faceGroupIndex] = geometries; } } } }
private void BuildMeshesWireframes(OptFile opt) { this.meshesWireframes = null; if (opt == null) { return; } this.meshesWireframes = opt.Meshes .AsParallel() .AsOrdered() .Select(mesh => { var positions = new Point3DCollection( mesh.Vertices .Select(t => new Point3D(-t.Y, -t.X, t.Z))); var wireframes = new IList<Point3D>[mesh.Lods.Count]; for (int lodIndex = 0; lodIndex < mesh.Lods.Count; lodIndex++) { var lod = mesh.Lods[lodIndex]; var lines = new List<Tuple<int, int>>(lod.TrianglesCount * 3); var addLine = new Action<int, int>((a, b) => { if (a < b) { lines.Add(new Tuple<int, int>(a, b)); } else { lines.Add(new Tuple<int, int>(b, a)); } }); for (int faceGroupIndex = 0; faceGroupIndex < lod.FaceGroups.Count; faceGroupIndex++) { var faceGroup = lod.FaceGroups[faceGroupIndex]; for (int faceIndex = 0; faceIndex < faceGroup.Faces.Count; faceIndex++) { var face = faceGroup.Faces[faceIndex]; Index positionsIndex = face.VerticesIndex; addLine(positionsIndex.A, positionsIndex.B); addLine(positionsIndex.B, positionsIndex.C); if (positionsIndex.D < 0) { addLine(positionsIndex.C, positionsIndex.A); } else { addLine(positionsIndex.C, positionsIndex.D); addLine(positionsIndex.D, positionsIndex.A); } } } var points = lines .Distinct() .SelectMany(t => new List<Point3D> { positions.ElementAtOrDefault(t.Item1), positions.ElementAtOrDefault(t.Item2) }) .ToList(); wireframes[lodIndex] = points; } return wireframes; }) .ToArray(); }
private List<ModelVisual3D> CreateMeshModelWireframe(OptFile opt, int meshIndex, int lodIndex) { if (opt == null || opt.Meshes.ElementAtOrDefault(meshIndex) == null || opt.Meshes[meshIndex].Lods.ElementAtOrDefault(lodIndex) == null) { return new List<ModelVisual3D>(); } var cache = this.Cache; if (meshIndex >= cache.meshesWireframes.Length || lodIndex >= cache.meshesWireframes[meshIndex].Length) { return new List<ModelVisual3D>(); } return new List<ModelVisual3D> { new LinesVisual3D { Points = new Point3DCollection(cache.meshesWireframes[meshIndex][lodIndex]), DepthOffset = 0.0001, Color = Colors.White } }; }
private void BuildTextures(OptFile opt) { this.nullTexture = null; this.textures = null; if (opt == null) { return; } this.nullTexture = new DiffuseMaterial(Brushes.White); this.textures = new Dictionary<string, Material>(); foreach (var texture in opt.Textures.Values) { var image = CreateTexture(opt, texture.Name); image.Freeze(); var brush = new ImageBrush(image) { ViewportUnits = BrushMappingMode.Absolute, Stretch = Stretch.Fill, TileMode = TileMode.Tile, Opacity = texture.HasAlpha ? 0.999 : 1.0 }; brush.Freeze(); var material = new DiffuseMaterial(brush); material.Freeze(); this.textures.Add(texture.Name, material); } }
public static IEnumerable<PlayabilityMessage> CheckGeometry(OptFile opt) { if (opt == null) { yield break; } if (opt.Meshes.Count > 50) { yield return new PlayabilityMessage( PlayabilityMessageLevel.Error, "Meshes", "The maximum meshes count for an opt is 50."); } if (opt.Meshes.Any(t => t.Vertices.Count > 512)) { yield return new PlayabilityMessage( PlayabilityMessageLevel.Error, "Meshes", "The maximum vertices count for a mesh is 512"); } }
public static void OptToRhino(OptFile opt, string rhinoPath) { Converter.OptToRhino(opt, rhinoPath, true); }
public static OptFile RhinoToOpt(string rhinoPath, bool scale) { string rhinoDirectory = Path.GetDirectoryName(rhinoPath); var opt = new OptFile(); using (var file = Rhino.FileIO.File3dm.Read(rhinoPath)) { float scaleFactor = scale ? (1.0f / OptFile.ScaleFactor) : 1.0f; if (file.Settings.ModelUnitSystem != Rhino.UnitSystem.Meters) { scaleFactor *= (float)Rhino.RhinoMath.UnitScale(file.Settings.ModelUnitSystem, Rhino.UnitSystem.Meters); scale = true; } var groups = file.Objects .Where(t => { using (var geometry = t.Geometry) { return geometry.ObjectType == Rhino.DocObjects.ObjectType.Mesh; } }) .GroupBy(t => { using (var attributes = t.Attributes) { return attributes.LayerIndex; } }) .ToList(); foreach (var group in groups) { var mesh = new Mesh(); opt.Meshes.Add(mesh); var lod = new MeshLod(); mesh.Lods.Add(lod); foreach (var obj in group) { var faceGroup = new FaceGroup(); lod.FaceGroups.Add(faceGroup); int baseIndex = mesh.Vertices.Count; using (var geometry = (Rhino.Geometry.Mesh)obj.Geometry) { if (scale) { foreach (var vertex in geometry.Vertices) { mesh.Vertices.Add(new Vector(vertex.X * scaleFactor, vertex.Y * scaleFactor, vertex.Z * scaleFactor)); } } else { foreach (var vertex in geometry.Vertices) { mesh.Vertices.Add(new Vector(vertex.X, vertex.Y, vertex.Z)); } } foreach (var texCoords in geometry.TextureCoordinates) { mesh.TextureCoordinates.Add(new TextureCoordinates(texCoords.X, -texCoords.Y)); } foreach (var normal in geometry.Normals) { mesh.VertexNormals.Add(new Vector(normal.X, normal.Y, normal.Z)); } foreach (var geoFace in geometry.Faces) { var face = new Face(); faceGroup.Faces.Add(face); Index index = geoFace.IsTriangle ? new Index(baseIndex + geoFace.C, baseIndex + geoFace.B, baseIndex + geoFace.A) : new Index(baseIndex + geoFace.D, baseIndex + geoFace.C, baseIndex + geoFace.B, baseIndex + geoFace.A); face.VerticesIndex = index; face.VertexNormalsIndex = index; face.TextureCoordinatesIndex = index; face.Normal = Vector.Normal(mesh.Vertices[index.A], mesh.Vertices[index.B], mesh.Vertices[index.C]); } } using (var attributes = obj.Attributes) { if (attributes.MaterialIndex != -1) { using (var material = file.Materials[attributes.MaterialIndex]) { faceGroup.Textures.Add(material.Name); } } } } } opt.CompactBuffers(); opt.ComputeHitzones(); for (int materialIndex = 0; materialIndex < file.Materials.Count; materialIndex++) { using (var material = file.Materials[materialIndex]) { if (opt.Textures.ContainsKey(material.Name)) { continue; } string colorMap = null; string alphaMap = null; using (var tex = material.GetBitmapTexture()) { if (tex != null && !string.IsNullOrEmpty(tex.FileName)) { colorMap = Path.GetFileName(tex.FileName); } } using (var tex = material.GetTransparencyTexture()) { if (tex != null && !string.IsNullOrEmpty(tex.FileName)) { alphaMap = Path.GetFileName(tex.FileName); } } Texture texture; if (colorMap == null) { var color = material.DiffuseColor; byte r = color.R; byte g = color.G; byte b = color.B; int width = 8; int height = 8; int length = width * height; byte[] data = new byte[length * 4]; for (int i = 0; i < length; i++) { data[i * 4 + 0] = b; data[i * 4 + 1] = g; data[i * 4 + 2] = r; data[i * 4 + 3] = 255; } texture = new Texture(); texture.Name = material.Name; texture.Width = width; texture.Height = height; texture.ImageData = data; } else { string colorFileName = Path.Combine(rhinoDirectory, colorMap); texture = Texture.FromFile(colorFileName); texture.Name = material.Name; } if (alphaMap != null) { string alphaFileName = Path.Combine(rhinoDirectory, alphaMap); texture.SetAlphaMap(alphaFileName); } else if (material.Transparency > 0.0 && material.Transparency < 1.0) { byte alpha = (byte)(material.Transparency * 255.0f); int length = texture.Width * texture.Height; byte[] alphaData = new byte[length]; var data = texture.ImageData; for (int i = 0; i < length; i++) { alphaData[i] = alpha; data[i * 4 + 3] = alpha; } texture.AlphaData = alphaData; } opt.Textures.Add(texture.Name, texture); } } opt.GenerateTexturesMipmaps(); } return opt; }
public static OptFile An8ToOpt(string an8Path, bool scale) { string an8Directory = Path.GetDirectoryName(an8Path); var an8 = An8File.FromFile(an8Path); var opt = new OptFile(); foreach (var mesh in an8.Objects .SelectMany(t => t.Components) .SelectMany(t => Converter.EnumMeshes(t))) { var optMesh = new Mesh(); opt.Meshes.Add(optMesh); if (scale) { foreach (var v in mesh.Points) { optMesh.Vertices.Add(new Vector(v.X / OptFile.ScaleFactor, v.Z / OptFile.ScaleFactor, v.Y / OptFile.ScaleFactor)); } } else { foreach (var v in mesh.Points) { optMesh.Vertices.Add(new Vector(v.X, v.Z, v.Y)); } } foreach (var v in mesh.TexCoords) { optMesh.TextureCoordinates.Add(new TextureCoordinates(v.U, -v.V)); } foreach (var v in mesh.Normals) { optMesh.VertexNormals.Add(new Vector(v.X, v.Z, v.Y)); } optMesh.TextureCoordinates.Add(new TextureCoordinates(0, 0)); optMesh.TextureCoordinates.Add(new TextureCoordinates(1, 0)); optMesh.TextureCoordinates.Add(new TextureCoordinates(1, 1)); optMesh.TextureCoordinates.Add(new TextureCoordinates(0, 1)); var optLod = new MeshLod(); optMesh.Lods.Add(optLod); foreach (var face in mesh.Faces) { if (face.PointIndexes.Length < 3) { continue; } bool isQuad = face.PointIndexes.Length > 3; var optFaceGroup = new FaceGroup(); optLod.FaceGroups.Add(optFaceGroup); var materialName = mesh.MaterialList.ElementAtOrDefault(face.MaterialIndex); if (!string.IsNullOrEmpty(materialName)) { optFaceGroup.Textures.Add(materialName); } Index verticesIndex = new Index( face.PointIndexes[0], face.PointIndexes[1], face.PointIndexes[2], isQuad ? face.PointIndexes[3] : -1); if (verticesIndex.A >= optMesh.Vertices.Count) { verticesIndex.A = 0; } if (verticesIndex.B >= optMesh.Vertices.Count) { verticesIndex.B = 0; } if (verticesIndex.C >= optMesh.Vertices.Count) { verticesIndex.C = 0; } if (verticesIndex.D >= optMesh.Vertices.Count) { verticesIndex.D = 0; } Index textureCoordinatesIndex = new Index( face.TexCoordIndexes[0], face.TexCoordIndexes[1], face.TexCoordIndexes[2], isQuad ? face.TexCoordIndexes[3] : -1); if (textureCoordinatesIndex.A >= optMesh.TextureCoordinates.Count) { textureCoordinatesIndex.A = 0; } if (textureCoordinatesIndex.B >= optMesh.TextureCoordinates.Count) { textureCoordinatesIndex.B = 0; } if (textureCoordinatesIndex.C >= optMesh.TextureCoordinates.Count) { textureCoordinatesIndex.C = 0; } if (textureCoordinatesIndex.D >= optMesh.TextureCoordinates.Count) { textureCoordinatesIndex.D = 0; } Index vertexNormalsIndex = new Index( face.NormalIndexes[0], face.NormalIndexes[1], face.NormalIndexes[2], isQuad ? face.NormalIndexes[3] : -1); if (vertexNormalsIndex.A >= optMesh.VertexNormals.Count) { vertexNormalsIndex.A = 0; } if (vertexNormalsIndex.B >= optMesh.VertexNormals.Count) { vertexNormalsIndex.B = 0; } if (vertexNormalsIndex.C >= optMesh.VertexNormals.Count) { vertexNormalsIndex.C = 0; } if (vertexNormalsIndex.D >= optMesh.VertexNormals.Count) { vertexNormalsIndex.D = 0; } if (textureCoordinatesIndex.A < 0 || textureCoordinatesIndex.B < 0 || textureCoordinatesIndex.C < 0 || (verticesIndex.D >= 0 && textureCoordinatesIndex.D < 0)) { textureCoordinatesIndex.A = optMesh.TextureCoordinates.Count - 4; textureCoordinatesIndex.B = optMesh.TextureCoordinates.Count - 3; textureCoordinatesIndex.C = optMesh.TextureCoordinates.Count - 2; textureCoordinatesIndex.D = verticesIndex.D < 0 ? -1 : optMesh.TextureCoordinates.Count - 1; } Vector normal = Vector.Normal( optMesh.Vertices.ElementAtOrDefault(verticesIndex.A), optMesh.Vertices.ElementAtOrDefault(verticesIndex.B), optMesh.Vertices.ElementAtOrDefault(verticesIndex.C)); if (vertexNormalsIndex.A < 0 || vertexNormalsIndex.B < 0 || vertexNormalsIndex.C < 0 || (verticesIndex.D >= 0 && vertexNormalsIndex.D < 0)) { optMesh.VertexNormals.Add(normal); vertexNormalsIndex.A = optMesh.VertexNormals.Count - 1; vertexNormalsIndex.B = optMesh.VertexNormals.Count - 1; vertexNormalsIndex.C = optMesh.VertexNormals.Count - 1; vertexNormalsIndex.D = verticesIndex.D < 0 ? -1 : optMesh.VertexNormals.Count - 1; } var optFace = new Face() { VerticesIndex = verticesIndex, TextureCoordinatesIndex = textureCoordinatesIndex, VertexNormalsIndex = vertexNormalsIndex, Normal = normal }; optFaceGroup.Faces.Add(optFace); } } opt.CompactBuffers(); opt.ComputeHitzones(); foreach (var material in an8.Materials .Concat(an8.Objects.SelectMany(t => t.Materials)) .Where(t => t.FrontSurface != null) .Select(t => new { Name = t.Name, Diffuse = t.FrontSurface.Diffuse, Alpha = t.FrontSurface.Alpha })) { Texture texture; var an8Texture = material.Diffuse.TextureName != null ? an8.Textures.FirstOrDefault(t => string.Equals(t.Name, material.Diffuse.TextureName, StringComparison.Ordinal)) : null; if (an8Texture == null) { byte r = material.Diffuse.Red; byte g = material.Diffuse.Green; byte b = material.Diffuse.Blue; int width = 8; int height = 8; int length = width * height; byte[] data = new byte[length * 4]; for (int i = 0; i < length; i++) { data[i * 4 + 0] = b; data[i * 4 + 1] = g; data[i * 4 + 2] = r; data[i * 4 + 3] = 255; } texture = new Texture(); texture.Name = material.Name; texture.Width = width; texture.Height = height; texture.ImageData = data; } else { string colorFileName = Path.Combine(an8Directory, Path.GetFileName(an8Texture.Files[0])); texture = Texture.FromFile(colorFileName); texture.Name = material.Name; } if (material.Alpha > 0 && material.Alpha < 255) { byte alpha = (byte)material.Alpha; int length = texture.Width * texture.Height; byte[] alphaData = new byte[length]; var data = texture.ImageData; for (int i = 0; i < length; i++) { alphaData[i] = alpha; data[i * 4 + 3] = alpha; } texture.AlphaData = alphaData; } opt.Textures.Add(texture.Name, texture); } opt.GenerateTexturesMipmaps(); return opt; }
public static void OptToRhino(OptFile opt, string rhinoPath, bool scale) { if (opt == null) { throw new ArgumentNullException("opt"); } string rhinoDirectory = Path.GetDirectoryName(rhinoPath); string rhinoName = Path.GetFileNameWithoutExtension(rhinoPath); var distances = opt.Meshes .SelectMany(t => t.Lods) .Select(t => t.Distance) .Distinct() .OrderByDescending(t => t) .ToArray(); for (int distance = 0; distance < distances.Length; distance++) { using (var file = new Rhino.FileIO.File3dm()) { file.Settings.ModelUnitSystem = Rhino.UnitSystem.Meters; int objectsIndex = 0; List<string> textureNames = new List<string>(); foreach (var mesh in opt.Meshes) { var lod = mesh.Lods.FirstOrDefault(t => t.Distance <= distances[distance]); if (lod == null) { continue; } foreach (var textureName in lod.FaceGroups .Where(t => t.Textures.Count > 0) .Select(t => t.Textures[0])) { if (!textureNames.Contains(textureName)) { textureNames.Add(textureName); } } string meshName = string.Format(CultureInfo.InvariantCulture, "{0}.{1:D3}", mesh.Descriptor.MeshType, objectsIndex); using (var layer = new Rhino.DocObjects.Layer()) { layer.Name = meshName; file.Layers.Add(layer); } foreach (var faceGroup in lod.FaceGroups) { using (var rhinoMesh = new Rhino.Geometry.Mesh()) using (var rhinoAttributes = new Rhino.DocObjects.ObjectAttributes()) { rhinoAttributes.Name = meshName; rhinoAttributes.LayerIndex = objectsIndex; if (faceGroup.Textures.Count > 0) { rhinoAttributes.MaterialIndex = textureNames.IndexOf(faceGroup.Textures[0]); } Action<Vector> addVertex; if (scale) { addVertex = vertex => rhinoMesh.Vertices.Add(vertex.X * OptFile.ScaleFactor, vertex.Y * OptFile.ScaleFactor, vertex.Z * OptFile.ScaleFactor); } else { addVertex = vertex => rhinoMesh.Vertices.Add(vertex.X, vertex.Y, vertex.Z); } Action<TextureCoordinates> addTexCoords = texCoords => rhinoMesh.TextureCoordinates.Add(texCoords.U, -texCoords.V); Action<Vector> addNormal = normal => rhinoMesh.Normals.Add(normal.X, normal.Y, normal.Z); int facesIndex = 0; foreach (var face in faceGroup.Faces) { var verticesIndex = face.VerticesIndex; var texCoordsIndex = face.TextureCoordinatesIndex; var normalsIndex = face.VertexNormalsIndex; addVertex(mesh.Vertices[verticesIndex.A]); addTexCoords(mesh.TextureCoordinates[texCoordsIndex.A]); addNormal(mesh.VertexNormals[normalsIndex.A]); facesIndex++; addVertex(mesh.Vertices[verticesIndex.B]); addTexCoords(mesh.TextureCoordinates[texCoordsIndex.B]); addNormal(mesh.VertexNormals[normalsIndex.B]); facesIndex++; addVertex(mesh.Vertices[verticesIndex.C]); addTexCoords(mesh.TextureCoordinates[texCoordsIndex.C]); addNormal(mesh.VertexNormals[normalsIndex.C]); facesIndex++; if (verticesIndex.D >= 0) { addVertex(mesh.Vertices[verticesIndex.D]); addTexCoords(mesh.TextureCoordinates[texCoordsIndex.D]); addNormal(mesh.VertexNormals[normalsIndex.D]); facesIndex++; } if (verticesIndex.D < 0) { rhinoMesh.Faces.AddFace(facesIndex - 1, facesIndex - 2, facesIndex - 3); } else { rhinoMesh.Faces.AddFace(facesIndex - 1, facesIndex - 2, facesIndex - 3, facesIndex - 4); } } rhinoMesh.Compact(); file.Objects.AddMesh(rhinoMesh, rhinoAttributes); } } objectsIndex++; } foreach (var textureName in textureNames) { Texture texture; opt.Textures.TryGetValue(textureName, out texture); using (var material = new Rhino.DocObjects.Material()) { material.Name = textureName; if (texture == null) { material.DiffuseColor = System.Drawing.Color.White; } else { texture.Save(Path.Combine(rhinoDirectory, textureName + ".png")); material.SetBitmapTexture(textureName + ".png"); if (texture.HasAlpha) { texture.SaveAlphaMap(Path.Combine(rhinoDirectory, textureName + "_alpha.png")); material.SetTransparencyTexture(textureName + "_alpha.png"); } } file.Materials.Add(material); } } file.Write(Path.Combine(rhinoDirectory, string.Format(CultureInfo.InvariantCulture, "{0}_{1}.3dm", rhinoName, distance)), 4); } } }
public static void OptToAn8(OptFile opt, string an8Path, bool scale) { if (opt == null) { throw new ArgumentNullException("opt"); } string an8Directory = Path.GetDirectoryName(an8Path); string an8Name = Path.GetFileNameWithoutExtension(an8Path); foreach (var texture in opt.Textures.Values) { texture.Save(Path.Combine(an8Directory, string.Concat(texture.Name, ".png"))); } var distances = opt.Meshes .SelectMany(t => t.Lods) .Select(t => t.Distance) .Distinct() .OrderByDescending(t => t) .ToArray(); for (int distance = 0; distance < distances.Length; distance++) { var an8 = new An8File(); foreach (var texture in opt.Textures.Values) { var an8Texture = new An8Texture(); an8Texture.Name = texture.Name; an8Texture.Files.Add(string.Concat(texture.Name, ".png")); an8.Textures.Add(an8Texture); var an8Material = new An8Material(); an8Material.Name = texture.Name; an8Material.FrontSurface = new An8Surface(); an8Material.FrontSurface.Diffuse = new An8MaterialColor { TextureName = texture.Name, TextureParams = new An8TextureParams { AlphaMode = texture.HasAlpha ? An8AlphaMode.Final : An8AlphaMode.None, BlendMode = An8BlendMode.Darken } }; an8.Materials.Add(an8Material); } var an8Object = new An8Object(); an8Object.Name = Path.GetFileNameWithoutExtension(opt.FileName); an8.Objects.Add(an8Object); int objectsIndex = 0; foreach (var mesh in opt.Meshes) { var lod = mesh.Lods.FirstOrDefault(t => t.Distance <= distances[distance]); if (lod == null) { continue; } var an8Mesh = new An8Mesh(); an8Mesh.Name = string.Format(CultureInfo.InvariantCulture, "{0}.{1:D3}", mesh.Descriptor.MeshType, objectsIndex); an8Object.Components.Add(an8Mesh); objectsIndex++; foreach (var texture in mesh.Lods .SelectMany(t => t.FaceGroups) .SelectMany(t => t.Textures) .Distinct()) { an8Mesh.MaterialList.Add(texture); } if (scale) { foreach (var v in mesh.Vertices) { an8Mesh.Points.Add(new An8Point { X = v.X * OptFile.ScaleFactor, Y = v.Z * OptFile.ScaleFactor, Z = v.Y * OptFile.ScaleFactor }); } } else { foreach (var v in mesh.Vertices) { an8Mesh.Points.Add(new An8Point { X = v.X, Y = v.Z, Z = v.Y }); } } foreach (var v in mesh.TextureCoordinates) { an8Mesh.TexCoords.Add(new An8TexCoord { U = v.U, V = -v.V }); } foreach (var v in mesh.VertexNormals) { an8Mesh.Normals.Add(new An8Point { X = v.X, Y = v.Z, Z = v.Y }); } int verticesIndex = 0; int verticesTexIndex = 0; int verticesNormalIndex = 0; foreach (var faceGroup in lod.FaceGroups) { int materialIndex = 0; if (faceGroup.Textures.Count > 0) { materialIndex = an8Mesh.MaterialList.IndexOf(faceGroup.Textures[0]); } foreach (var face in faceGroup.Faces) { if (face.VerticesIndex.D < 0) { var an8Face = new An8Face { MaterialIndex = materialIndex, FlatNormalIndex = -1 }; an8Face.PointIndexes = new int[] { verticesIndex + face.VerticesIndex.A, verticesIndex + face.VerticesIndex.B, verticesIndex + face.VerticesIndex.C }; an8Face.TexCoordIndexes = new int[] { verticesTexIndex + face.TextureCoordinatesIndex.A, verticesTexIndex + face.TextureCoordinatesIndex.B, verticesTexIndex + face.TextureCoordinatesIndex.C }; an8Face.NormalIndexes = new int[] { verticesNormalIndex + face.VertexNormalsIndex.A, verticesNormalIndex + face.VertexNormalsIndex.B, verticesNormalIndex + face.VertexNormalsIndex.C }; an8Mesh.Faces.Add(an8Face); } else { var an8Face = new An8Face { MaterialIndex = materialIndex, FlatNormalIndex = -1 }; an8Face.PointIndexes = new int[] { verticesIndex + face.VerticesIndex.A, verticesIndex + face.VerticesIndex.B, verticesIndex + face.VerticesIndex.C, verticesIndex + face.VerticesIndex.D }; an8Face.TexCoordIndexes = new int[] { verticesTexIndex + face.TextureCoordinatesIndex.A, verticesTexIndex + face.TextureCoordinatesIndex.B, verticesTexIndex + face.TextureCoordinatesIndex.C, verticesTexIndex + face.TextureCoordinatesIndex.D }; an8Face.NormalIndexes = new int[] { verticesNormalIndex + face.VertexNormalsIndex.A, verticesNormalIndex + face.VertexNormalsIndex.B, verticesNormalIndex + face.VertexNormalsIndex.C, verticesNormalIndex + face.VertexNormalsIndex.D }; an8Mesh.Faces.Add(an8Face); } } } verticesIndex += mesh.Vertices.Count; verticesTexIndex += mesh.TextureCoordinates.Count; verticesNormalIndex += mesh.VertexNormals.Count; } an8.Save(Path.Combine(an8Directory, string.Format(CultureInfo.InvariantCulture, "{0}_{1}.an8", an8Name, distance))); } }
private List<ModelVisual3D> CreateMeshModel(OptFile opt, int meshIndex, int lodIndex, int version) { if (opt == null || opt.Meshes.ElementAtOrDefault(meshIndex) == null || opt.Meshes[meshIndex].Lods.ElementAtOrDefault(lodIndex) == null) { return new List<ModelVisual3D>(); } var cache = this.Cache; var mesh = opt.Meshes[meshIndex]; var lod = mesh.Lods[lodIndex]; if (meshIndex >= cache.meshes.Length || lodIndex >= cache.meshes[meshIndex].Length || lod.FaceGroups.Count > cache.meshes[meshIndex][lodIndex].Length) { return new List<ModelVisual3D>(); } List<ModelVisual3D> group = new List<ModelVisual3D>(); for (int faceGroupIndex = 0; faceGroupIndex < lod.FaceGroups.Count; faceGroupIndex++) { var faceGroup = lod.FaceGroups[faceGroupIndex]; Material texture = null; bool alpha = false; if (faceGroup.Textures.Count != 0) { int currentVersion = version; if (version < 0 || version >= faceGroup.Textures.Count) { currentVersion = faceGroup.Textures.Count - 1; } string textureName = faceGroup.Textures[currentVersion]; if (cache.textures.ContainsKey(textureName)) { texture = cache.textures[textureName]; alpha = opt.Textures[textureName].HasAlpha; } } var geometries = cache.meshes[meshIndex][lodIndex][faceGroupIndex]; if (alpha) { for (int i = 1; i < geometries.Length; i++) { GeometryModel3D model = new GeometryModel3D(); model.Geometry = geometries[i]; model.Material = texture == null ? cache.nullTexture : texture; model.BackMaterial = texture == null ? cache.nullTexture : texture; model.Freeze(); group.Add(new ModelVisual3D() { Content = model }); this.ModelToMeshLodFace.Add(model, new MeshLodFace(opt.Meshes[meshIndex], opt.Meshes[meshIndex].Lods[lodIndex], faceGroup)); } } else { GeometryModel3D model = new GeometryModel3D(); model.Geometry = geometries[0]; model.Material = texture == null ? cache.nullTexture : texture; model.Freeze(); group.Add(new ModelVisual3D() { Content = model }); this.ModelToMeshLodFace.Add(model, new MeshLodFace(opt.Meshes[meshIndex], opt.Meshes[meshIndex].Lods[lodIndex], faceGroup)); } } return group; }