private StringWriter BuildWavefrontStringForTileObjectMesh(TmxMesh mesh) { Logger.WriteVerbose("Building mesh obj file for tile: '{0}.obj'", mesh.UniqueMeshName); GenericListDatabase <Vertex3> vertexDatabase = new GenericListDatabase <Vertex3>(); HashIndexOf <PointF> uvDatabase = new HashIndexOf <PointF>(); StringBuilder faces = new StringBuilder(); // Get the single tile associated with this mesh TmxTile tmxTile = this.tmxMap.Tiles[mesh.TileIds[0]]; var vertices = CalculateFaceVertices_TileObject(tmxTile.TileSize, tmxTile.Offset); var uvs = CalculateFaceTextureCoordinates(tmxTile, false, false, false); // TileObjects have zero depth on their vertices. Their GameObject parent will set depth. FaceVertices faceVertices = new FaceVertices { Vertices = vertices, Depth_z = 0.0f }; // Adds vertices and uvs to the database as we build the face strings string v0 = String.Format("{0}/{1}/1", vertexDatabase.AddToDatabase(faceVertices.V0) + 1, uvDatabase.Add(uvs[0]) + 1); string v1 = String.Format("{0}/{1}/1", vertexDatabase.AddToDatabase(faceVertices.V1) + 1, uvDatabase.Add(uvs[1]) + 1); string v2 = String.Format("{0}/{1}/1", vertexDatabase.AddToDatabase(faceVertices.V2) + 1, uvDatabase.Add(uvs[2]) + 1); string v3 = String.Format("{0}/{1}/1", vertexDatabase.AddToDatabase(faceVertices.V3) + 1, uvDatabase.Add(uvs[3]) + 1); faces.AppendFormat("f {0} {1} {2} {3}\n", v0, v1, v2, v3); // We have all the data we need to build the wavefront file format return(CreateWavefrontWriter(mesh, vertexDatabase, uvDatabase, faces)); }
private StringWriter BuildWavefrontStringForLayerMesh(TmxLayer layer, TmxMesh mesh, IEnumerable <int> horizontalRange, IEnumerable <int> verticalRange) { Logger.WriteVerbose("Building mesh obj file for '{0}'", mesh.UniqueMeshName); GenericListDatabase <Vertex3> vertexDatabase = new GenericListDatabase <Vertex3>(); HashIndexOf <PointF> uvDatabase = new HashIndexOf <PointF>(); StringBuilder faces = new StringBuilder(); foreach (int y in verticalRange) { foreach (int x in horizontalRange) { int tileIndex = layer.GetTileIndex(x, y); uint tileId = mesh.GetTileIdAt(tileIndex); // Skip blank tiles if (tileId == 0) { continue; } TmxTile tile = this.tmxMap.Tiles[TmxMath.GetTileIdWithoutFlags(tileId)]; // What are the vertex and texture coorindates of this face on the mesh? var position = this.tmxMap.GetMapPositionAt(x, y, tile); var vertices = CalculateFaceVertices(position, tile.TileSize); // If we're using depth shaders then we'll need to set a depth value of this face float depth_z = 0.0f; if (Tiled2Unity.Settings.DepthBufferEnabled) { depth_z = CalculateFaceDepth(position.Y + tmxMap.TileHeight, tmxMap.MapSizeInPixels.Height); } FaceVertices faceVertices = new FaceVertices { Vertices = vertices, Depth_z = depth_z }; // Is the tile being flipped or rotated (needed for texture cooridinates) bool flipDiagonal = TmxMath.IsTileFlippedDiagonally(tileId); bool flipHorizontal = TmxMath.IsTileFlippedHorizontally(tileId); bool flipVertical = TmxMath.IsTileFlippedVertically(tileId); var uvs = CalculateFaceTextureCoordinates(tile, flipDiagonal, flipHorizontal, flipVertical); // Adds vertices and uvs to the database as we build the face strings string v0 = String.Format("{0}/{1}/1", vertexDatabase.AddToDatabase(faceVertices.V0) + 1, uvDatabase.Add(uvs[0]) + 1); string v1 = String.Format("{0}/{1}/1", vertexDatabase.AddToDatabase(faceVertices.V1) + 1, uvDatabase.Add(uvs[1]) + 1); string v2 = String.Format("{0}/{1}/1", vertexDatabase.AddToDatabase(faceVertices.V2) + 1, uvDatabase.Add(uvs[2]) + 1); string v3 = String.Format("{0}/{1}/1", vertexDatabase.AddToDatabase(faceVertices.V3) + 1, uvDatabase.Add(uvs[3]) + 1); faces.AppendFormat("f {0} {1} {2} {3}\n", v0, v1, v2, v3); } } // We have all the data we need to build the wavefront file format return(CreateWavefrontWriter(mesh, vertexDatabase, uvDatabase, faces)); }
private StringWriter CreateWavefrontWriter(TmxMesh mesh, GenericListDatabase <Vertex3> vertexDatabase, HashIndexOf <PointF> uvDatabase, StringBuilder faces) { StringWriter wavefront = new StringWriter(); wavefront.WriteLine("# Tiled2Unity generated file. Do not modify by hand."); wavefront.WriteLine("# Wavefront file for '{0}.obj'", mesh.UniqueMeshName); wavefront.WriteLine(); wavefront.WriteLine("# Vertices (Count = {0})", vertexDatabase.List.Count()); foreach (var v in vertexDatabase.List) { wavefront.WriteLine("v {0} {1} {2}", v.X, v.Y, v.Z); } wavefront.WriteLine(); wavefront.WriteLine("# Texture cooridinates (Count = {0})", uvDatabase.List.Count()); foreach (var uv in uvDatabase.List) { wavefront.WriteLine("vt {0} {1}", uv.X, uv.Y); } wavefront.WriteLine(); // Write the one indexed normal wavefront.WriteLine("# Normal"); wavefront.WriteLine("vn 0 0 -1"); wavefront.WriteLine(); // Now we can copy over the string used to build the databases wavefront.WriteLine("# Mesh description"); wavefront.WriteLine("g {0}", mesh.UniqueMeshName); wavefront.WriteLine(); wavefront.WriteLine("# Faces"); wavefront.WriteLine(faces.ToString()); return(wavefront); }
// Creates the text for a Wavefront OBJ file for the TmxMap private StringWriter BuildObjString() { IGenericDatabase <Vertex3> vertexDatabase = new HashIndexOf <Vertex3>(); HashIndexOf <PointF> uvDatabase = new HashIndexOf <PointF>(); // Are we allowing vertices to be written too (advanced option) if (Tiled2Unity.Settings.WriteableVertices) { // Replace vertex database with class that ensure each vertex (even ones with similar values) are unique Logger.WriteLine("Using writeable-vertices. This will increase the size of the mesh but will allow you mutate vertices through scripting. This is an advanced feature."); vertexDatabase = new GenericListDatabase <Vertex3>(); } float mapLogicalHeight = this.tmxMap.MapSizeInPixels().Height; // Go through every face of every mesh of every visible layer and collect vertex and texture coordinate indices as you go int groupCount = 0; StringBuilder faceBuilder = new StringBuilder(); foreach (var layer in this.tmxMap.Layers) { if (layer.Visible != true) { continue; } if (layer.Ignore == TmxLayer.IgnoreSettings.Visual) { continue; } // We're going to use this layer ++groupCount; // Enumerate over the tiles in the direction given by the draw order of the map var verticalRange = (this.tmxMap.DrawOrderVertical == 1) ? Enumerable.Range(0, layer.Height) : Enumerable.Range(0, layer.Height).Reverse(); var horizontalRange = (this.tmxMap.DrawOrderHorizontal == 1) ? Enumerable.Range(0, layer.Width) : Enumerable.Range(0, layer.Width).Reverse(); foreach (TmxMesh mesh in layer.Meshes) { Logger.WriteLine("Writing '{0}' mesh group", mesh.UniqueMeshName); faceBuilder.AppendFormat("\ng {0}\n", mesh.UniqueMeshName); foreach (int y in verticalRange) { foreach (int x in horizontalRange) { int tileIndex = layer.GetTileIndex(x, y); uint tileId = mesh.GetTileIdAt(tileIndex); // Skip blank tiles if (tileId == 0) { continue; } TmxTile tile = this.tmxMap.Tiles[TmxMath.GetTileIdWithoutFlags(tileId)]; // What are the vertex and texture coorindates of this face on the mesh? var position = this.tmxMap.GetMapPositionAt(x, y); var vertices = CalculateFaceVertices(position, tile.TileSize, this.tmxMap.TileHeight, tile.Offset); // If we're using depth shaders then we'll need to set a depth value of this face float depth_z = 0.0f; if (Tiled2Unity.Settings.DepthBufferEnabled) { depth_z = CalculateFaceDepth(position.Y, mapLogicalHeight); } FaceVertices faceVertices = new FaceVertices { Vertices = vertices, Depth_z = depth_z }; // Is the tile being flipped or rotated (needed for texture cooridinates) bool flipDiagonal = TmxMath.IsTileFlippedDiagonally(tileId); bool flipHorizontal = TmxMath.IsTileFlippedHorizontally(tileId); bool flipVertical = TmxMath.IsTileFlippedVertically(tileId); var uvs = CalculateFaceTextureCoordinates(tile, flipDiagonal, flipHorizontal, flipVertical); // Adds vertices and uvs to the database as we build the face strings string v0 = String.Format("{0}/{1}/1", vertexDatabase.AddToDatabase(faceVertices.V0) + 1, uvDatabase.Add(uvs[0]) + 1); string v1 = String.Format("{0}/{1}/1", vertexDatabase.AddToDatabase(faceVertices.V1) + 1, uvDatabase.Add(uvs[1]) + 1); string v2 = String.Format("{0}/{1}/1", vertexDatabase.AddToDatabase(faceVertices.V2) + 1, uvDatabase.Add(uvs[2]) + 1); string v3 = String.Format("{0}/{1}/1", vertexDatabase.AddToDatabase(faceVertices.V3) + 1, uvDatabase.Add(uvs[3]) + 1); faceBuilder.AppendFormat("f {0} {1} {2} {3}\n", v0, v1, v2, v3); } } } } // Now go through any tile objects we may have and write them out as face groups as well foreach (var tmxMesh in this.tmxMap.GetUniqueListOfVisibleObjectTileMeshes()) { // We're going to use this tile object groupCount++; Logger.WriteLine("Writing '{0}' tile group", tmxMesh.UniqueMeshName); faceBuilder.AppendFormat("\ng {0}\n", tmxMesh.UniqueMeshName); // Get the single tile associated with this mesh TmxTile tmxTile = this.tmxMap.Tiles[tmxMesh.TileIds[0]]; var vertices = CalculateFaceVertices_TileObject(tmxTile.TileSize, tmxTile.Offset); var uvs = CalculateFaceTextureCoordinates(tmxTile, false, false, false); // TileObjects have zero depth on their vertices. Their GameObject parent will set depth. FaceVertices faceVertices = new FaceVertices { Vertices = vertices, Depth_z = 0.0f }; // Adds vertices and uvs to the database as we build the face strings string v0 = String.Format("{0}/{1}/1", vertexDatabase.AddToDatabase(faceVertices.V0) + 1, uvDatabase.Add(uvs[0]) + 1); string v1 = String.Format("{0}/{1}/1", vertexDatabase.AddToDatabase(faceVertices.V1) + 1, uvDatabase.Add(uvs[1]) + 1); string v2 = String.Format("{0}/{1}/1", vertexDatabase.AddToDatabase(faceVertices.V2) + 1, uvDatabase.Add(uvs[2]) + 1); string v3 = String.Format("{0}/{1}/1", vertexDatabase.AddToDatabase(faceVertices.V3) + 1, uvDatabase.Add(uvs[3]) + 1); faceBuilder.AppendFormat("f {0} {1} {2} {3}\n", v0, v1, v2, v3); } // All of our faces have been built and vertex and uv databases have been filled. // Start building out the obj file StringWriter objWriter = new StringWriter(); objWriter.WriteLine("# Wavefront OBJ file automatically generated by Tiled2Unity"); objWriter.WriteLine(); Logger.WriteLine("Writing face vertices"); objWriter.WriteLine("# Vertices (Count = {0})", vertexDatabase.List.Count()); foreach (var v in vertexDatabase.List) { objWriter.WriteLine("v {0} {1} {2}", v.X, v.Y, v.Z); } objWriter.WriteLine(); Logger.WriteLine("Writing face uv coordinates"); objWriter.WriteLine("# Texture cooridinates (Count = {0})", uvDatabase.List.Count()); foreach (var uv in uvDatabase.List) { objWriter.WriteLine("vt {0} {1}", uv.X, uv.Y); } objWriter.WriteLine(); // Write the one indexed normal objWriter.WriteLine("# Normal"); objWriter.WriteLine("vn 0 0 -1"); objWriter.WriteLine(); // Now we can copy over the string used to build the databases objWriter.WriteLine("# Groups (Count = {0})", groupCount); objWriter.WriteLine(faceBuilder.ToString()); return(objWriter); }