private List <XElement> CreateAssignMaterialsElements() { // Need to match all "submeshes" with a material // The material will have the same name as the texture // Each "submesh" is a Layer+Texture combination since Wavefront Obj meshes support only 1 set of texture coordinates var faces = from layer in tmxMap.Layers where layer.Visible == true from y in Enumerable.Range(0, layer.Height) from x in Enumerable.Range(0, layer.Width) let tileId = layer.GetTileIdAt(x, y) where tileId != 0 let tile = this.tmxMap.Tiles[tileId] select new { LayerName = layer.UniqueName, ImageName = Path.GetFileNameWithoutExtension(tile.TmxImage.Path), TransparentColor = tile.TmxImage.TransparentColor, SortingLayer = layer.Properties.GetPropertyValueAsString("unity:sortingLayerName", ""), SortingOrder = layer.Properties.GetPropertyValueAsInt("unity:sortingOrder", tmxMap.Layers.IndexOf(layer)), }; var groups = from f in faces group f by TiledMapExpoterUtils.UnityFriendlyMeshName(tmxMap, f.LayerName, f.ImageName); var assignments = from g in groups select new { MeshName = g.Key, MaterialName = g.First().ImageName, TransparentColor = g.First().TransparentColor, SortingLayer = g.First().SortingLayer, SortingOrder = g.First().SortingOrder, }; List <XElement> elements = new List <XElement>(); foreach (var ass in assignments) { XElement assignment = new XElement("AssignMaterial", new XAttribute("mesh", ass.MeshName), new XAttribute("material", ass.MaterialName), new XAttribute("sortingLayerName", ass.SortingLayer), new XAttribute("sortingOrder", ass.SortingOrder)); // Is there a transparent color key? if (!String.IsNullOrEmpty(ass.TransparentColor)) { assignment.SetAttributeValue("alphaColorKey", ass.TransparentColor); } elements.Add(assignment); } return(elements); }
private List <XElement> CreateMeshElementsForLayer(TmxLayer layer) { // Mesh elements look like this: // <GameObject copy="LayerName+TilesetName" /> // (The importer in Unity will look a submesh of that name and copy it to our prefab) // (This is complicated by potential tile animations now) var meshes = from rawTileId in layer.TileIds where rawTileId != 0 let tileId = TmxMath.GetTileIdWithoutFlags(rawTileId) let tile = this.tmxMap.Tiles[tileId] let name = TiledMapExpoterUtils.UnityFriendlyMeshName(tmxMap, layer.UniqueName, Path.GetFileNameWithoutExtension(tile.TmxImage.Path)) group tile.Animation by name into meshGroup select meshGroup; List <XElement> xmlMeshes = new List <XElement>(); foreach (var m in meshes) { XElement xmlMesh = new XElement("GameObject", new XAttribute("copy", m.Key)); // Do we have any animations? var animations = m.Distinct(); foreach (var anim in animations) { if (anim != null) { XElement xmlAnim = new XElement("TileAnimator"); foreach (var frame in anim.Frames) { xmlAnim.Add(new XElement("Frame", new XAttribute("vertex_z", frame.UniqueFrameId * Program.Vertex_ZScale), new XAttribute("duration", frame.DurationMs))); } xmlMesh.Add(xmlAnim); } } xmlMeshes.Add(xmlMesh); } return(xmlMeshes); }
private StringWriter BuildObjString() { // Creates the text for a Wavefront OBJ file for the TmxMap StringWriter objWriter = new StringWriter(); // Gather the information for every face var faces = from layer in this.tmxMap.Layers where layer.Visible == true where layer.Properties.GetPropertyValueAsBoolean("unity:collisionOnly", false) == false // Draw order forces us to visit tiles in a particular order from y in (this.tmxMap.DrawOrderVertical == 1) ? Enumerable.Range(0, layer.Height) : Enumerable.Range(0, layer.Height).Reverse() from x in (this.tmxMap.DrawOrderHorizontal == 1) ? Enumerable.Range(0, layer.Width) : Enumerable.Range(0, layer.Width).Reverse() let rawTileId = layer.GetRawTileIdAt(x, y) let tileId = TmxMath.GetTileIdWithoutFlags(rawTileId) where tileId != 0 let fd = TmxMath.IsTileFlippedDiagonally(rawTileId) let fh = TmxMath.IsTileFlippedHorizontally(rawTileId) let fv = TmxMath.IsTileFlippedVertically(rawTileId) let animTile = this.tmxMap.Tiles[tileId] // Enumerate through all frames of a tile. (Tiles without animation are treated as a single frame) from frame in TileFrame.EnumerateFramesFromTile(animTile, this.tmxMap) select new { LayerName = layer.UniqueName, Vertices = CalculateFaceVertices(this.tmxMap.GetMapPositionAt(x, y), frame.Tile.TileSize, this.tmxMap.TileHeight, frame.Position_z), TextureCoordinates = CalculateFaceTextureCoordinates(frame.Tile, fd, fh, fv), ImagePath = frame.Tile.TmxImage.Path, ImageName = Path.GetFileNameWithoutExtension(frame.Tile.TmxImage.Path), }; // We have all the information we need now to build our list of vertices, texture coords, and grouped faces // (Faces are grouped by LayerName.TextureName combination because Wavefront Obj only supports one texture per face) objWriter.WriteLine("# Wavefront OBJ file automatically generated by Tiled2Unity"); objWriter.WriteLine(); // We may have a ton of vertices so use a set right now HashSet <Vector3D> vertexSet = new HashSet <Vector3D>(); Program.WriteLine("Building face vertices"); foreach (var face in faces) { // Index the vertices foreach (var v in face.Vertices) { vertexSet.Add(v); } } HashSet <PointF> textureCoordinateSet = new HashSet <PointF>(); Program.WriteLine("Building face texture coordinates"); foreach (var face in faces) { // Index the texture coordinates foreach (var tc in face.TextureCoordinates) { textureCoordinateSet.Add(tc); } } // Write the indexed vertices Program.WriteLine("Writing indexed vertices"); IList <Vector3D> vertices = vertexSet.ToList(); objWriter.WriteLine("# Vertices (Count = {0})", vertices.Count); foreach (var v in vertices) { objWriter.WriteLine("v {0} {1} {2}", v.X, v.Y, v.Z); } objWriter.WriteLine(); // Write the indexed texture coordinates Program.WriteLine("Writing indexed texture coordinates"); IList <PointF> textureCoordinates = textureCoordinateSet.ToList(); objWriter.WriteLine("# Texture Coorindates (Count = {0})", textureCoordinates.Count); foreach (var vt in textureCoordinates) { objWriter.WriteLine("vt {0} {1}", vt.X, vt.Y); } objWriter.WriteLine(); // Write the one indexed normal objWriter.WriteLine("# Normal"); objWriter.WriteLine("vn 0 0 -1"); objWriter.WriteLine(); // Group faces by Layer+TileSet var groups = from f in faces group f by TiledMapExpoterUtils.UnityFriendlyMeshName(tmxMap, f.LayerName, f.ImageName); // Write out the faces objWriter.WriteLine("# Groups (Count = {0})", groups.Count()); // Need dictionaries with index as value. var vertexDict = Enumerable.Range(0, vertices.Count()).ToDictionary(i => vertices[i], i => i); var texCoordDict = Enumerable.Range(0, textureCoordinates.Count()).ToDictionary(i => textureCoordinates[i], i => i); foreach (var g in groups) { Program.WriteLine("Writing '{0}' mesh group", g.Key); objWriter.WriteLine("g {0}", g.Key); foreach (var f in g) { objWriter.Write("f "); for (int i = 0; i < 4; ++i) { int vertexIndex = vertexDict[f.Vertices[i]] + 1; int textureCoordinateIndex = texCoordDict[f.TextureCoordinates[i]] + 1; objWriter.Write(" {0}/{1}/1 ", vertexIndex, textureCoordinateIndex); } objWriter.WriteLine(); } } Program.WriteLine("Done writing Wavefront Obj data for '{0}'", tmxMap.Name); return(objWriter); }