static void setTilesetTextureIfNecessary(TmxTileset tileset, ContentProcessorContext context) { if (tileset.image != null) { return; } tileset.isStandardTileset = false; var imagePaths = new List <string>(); foreach (var tile in tileset.tiles) { if (tile.image != null && !imagePaths.Contains(tile.image.source)) { imagePaths.Add(tile.image.source); } } context.Logger.LogMessage("\n\t --- need to pack images: {0}\n", imagePaths.Count); var sourceSprites = new List <BitmapContent>(); // Loop over each input sprite filename foreach (var inputFilename in imagePaths) { // Store the name of this sprite. var spriteName = Path.GetFileName(inputFilename); var absolutePath = PathHelper.getAbsolutePath(inputFilename, tileset.mapFolder); context.Logger.LogMessage("Adding texture: {0}", spriteName); // Load the sprite texture into memory. var textureReference = new ExternalReference <TextureContent>(absolutePath); var texture = context.BuildAndLoadAsset <TextureContent, TextureContent>(textureReference, "TextureProcessor"); sourceSprites.Add(texture.Faces[0][0]); } var spriteRectangles = new List <Rectangle>(); // pack all the sprites into a single large texture. var packedSprites = TextureAtlasPacker.packSprites(sourceSprites, spriteRectangles, false, context); context.Logger.LogMessage("packed: {0}", packedSprites); // save out a PNG with our atlas var bm = new System.Drawing.Bitmap(packedSprites.Width, packedSprites.Height); for (var x = 0; x < packedSprites.Width; x++) { for (var y = 0; y < packedSprites.Height; y++) { var col = packedSprites.GetPixel(x, y); var color = System.Drawing.Color.FromArgb(col.A, col.R, col.G, col.B); bm.SetPixel(x, y, color); } } var atlasFilename = tileset.name + "-atlas.png"; bm.Save(Path.Combine(tileset.mapFolder, atlasFilename), System.Drawing.Imaging.ImageFormat.Png); context.Logger.LogImportantMessage("\n-- generated atlas {0}. Make sure you add it to the Pipeline tool!", atlasFilename); // set the new atlas as our tileset source image tileset.image = new TmxImage(); tileset.image.source = atlasFilename; // last step: set the new atlas info and source rectangle for each tile foreach (var tile in tileset.tiles) { if (tile.image == null) { continue; } tile.sourceRect = spriteRectangles[imagePaths.IndexOf(tile.image.source)]; } }
public override TiledMap Process(TmxMap input, ContentProcessorContext context) { foreach (var tileSet in input.TileSets) { if (tileSet.Image == null) { var images = new HashSet <string>(); foreach (var tile in tileSet.Tiles) { if (tile.Image != null) { images.Add(tile.Image.Source); } } context.Logger.LogMessage("Packing {0} images\n", images.Count); var bitmaps = new Dictionary <string, Bitmap>(); foreach (var image in images) { bitmaps.Add(image, new Bitmap(image)); } var packedSprites = TextureAtlasPacker.PackSprites(bitmaps.Values.ToList()); var atlasPath = input.OriginalFileName + "-atlas.png"; packedSprites.OutputBitmap.Save(atlasPath, System.Drawing.Imaging.ImageFormat.Png); var assetFileName = context.BuildAsset <string, Texture2DContent>( new ExternalReference <string>(atlasPath), nameof(TextureProcessor)).Filename; tileSet.Image = new TmxImage { Source = ImportPathHelper.GetAssetName(context.OutputDirectory, assetFileName) }; File.Delete(atlasPath); foreach (var tile in tileSet.Tiles) { if (tile.Image == null) { continue; } var rect = packedSprites.SpritePositions[bitmaps[tile.Image.Source]]; tile.SourceRect = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height); } } else { var assetFileName = context.BuildAsset <string, Texture2DContent>( new ExternalReference <string>(tileSet.Image.Source), nameof(TextureProcessor)).Filename; tileSet.Image.Source = ImportPathHelper.GetAssetName(context.OutputDirectory, assetFileName); } } foreach (var layer in input.Layers.OfType <TmxImageLayer>()) { if (layer.Image != null) { var assetFileName = context.BuildAsset <string, Texture2DContent>( new ExternalReference <string>(layer.Image.Source), nameof(TextureProcessor)).Filename; layer.Image.Source = ImportPathHelper.GetAssetName(context.OutputDirectory, assetFileName); } } var output = new TiledMap { FirstGid = input.FirstGid, Width = input.Width, Height = input.Height, TileWidth = input.TileWidth, TileHeight = input.TileHeight, Orientation = (TiledMapOrientation)input.Orientation, BackgroundColor = HexToColor(input.BackgroundColor), RenderOrder = (TiledRenderOrder)input.RenderOrder, Properties = input.Properties?.ToDictionary(a => a.Name, a => a.Value), ObjectGroups = input.ObjectGroups?.Select( a => new TiledObjectGroup { Name = a.Name, Color = HexToColor(a.Color), Opacity = a.Opacity, Visible = a.Visible, Properties = a.Properties?.ToDictionary(b => b.Name, b => b.Value), Objects = a.Objects?.Select( b => { var tiledObject = new TiledObject { Id = b.Id, Name = b.Name, Type = b.Type, X = (int)b.X, Y = (int)b.Y, Width = (int)b.Width, Height = (int)b.Height, Rotation = b.Rotation, Gid = b.Gid, Visible = b.Visible, Properties = b.Properties?.ToDictionary(c => c.Name, c => c.Value), ObjectType = b.Type, }; if (b.Ellipse != null) { tiledObject.TiledObjectType = TiledObject.TiledObjectTypes.Ellipse; } else if (b.Image != null) { tiledObject.TiledObjectType = TiledObject.TiledObjectTypes.Image; } else if (b.Polygon != null) { tiledObject.TiledObjectType = TiledObject.TiledObjectTypes.Polygon; tiledObject.PolyPoints = GetPoints(b.Polygon.Points); } else if (b.PolyLine != null) { tiledObject.TiledObjectType = TiledObject.TiledObjectTypes.Polyline; tiledObject.PolyPoints = GetPoints(b.PolyLine.Points); } else { tiledObject.TiledObjectType = TiledObject.TiledObjectTypes.None; } return(tiledObject); }).ToList() }).ToList(), TileSets = input.TileSets?.Select( a => { var tileSet = TiledTileSet.Build(a.Image.Width, a.Image.Height, a.TileWidth, a.TileHeight, a.Spacing, a.Margin, a.Columns); tileSet.FirstGid = a.FirstGid; tileSet.Image = a.Image.Source; tileSet.Properties = a.Properties.ToDictionary(b => b.Name, b => b.Value); foreach (var tile in a.Tiles) { var tiledTile = tileSet.Tiles.FirstOrDefault(b => b.Id == tile.Id); if (tiledTile == null) { tiledTile = new TiledTileSetTile { Id = tile.Id }; tileSet.Tiles.Add(tiledTile); } tiledTile.SourceRect = tile.SourceRect != Rectangle.Empty ? tile.SourceRect : tiledTile.SourceRect; tiledTile.AnimationFrames = tile.AnimationFrames == null || tile.AnimationFrames.Count == 0 ? null : tile.AnimationFrames.Select(b => new TiledTileSetAnimationFrame { TileId = b.TileId, Duration = b.Duration }).ToList(); tile.Properties.ForEach(b => tiledTile.Properties[b.Name] = b.Value); } return(tileSet); }).ToList() }; var existingIds = output.TileSets.SelectMany(a => a.Tiles.Select(b => (uint)(b.Id + a.FirstGid))).ToHashSet(); output.Layers = input.Layers?.Select( a => { var imageLayer = a as TmxImageLayer; var tiledLayer = a as TmxTileLayer; TiledLayer result; if (imageLayer != null) { result = new TiledImageLayer { AssetName = imageLayer.Image.Source }; } else if (tiledLayer != null) { result = new TiledTileLayer { Width = tiledLayer.Width, Height = tiledLayer.Height, X = tiledLayer.X, Y = tiledLayer.Y, Tiles = tiledLayer.Data.Tiles.Select( b => { var flippedHorizontally = (b.Gid & FlippedHorizontallyFlag) != 0; var flippedVertically = (b.Gid & FlippedVerticallyFlag) != 0; var flippedDiagonally = (b.Gid & FlippedDiagonallyFlag) != 0; if (flippedHorizontally || flippedVertically || flippedDiagonally) { b.Gid &= ~(FlippedHorizontallyFlag | FlippedVerticallyFlag | FlippedDiagonallyFlag); b.FlippedHorizontally = flippedHorizontally; b.FlippedVertically = flippedVertically; b.FlippedDiagonally = flippedDiagonally; } if (!existingIds.Contains(b.Gid)) { return(null); } return(new TiledTile { Id = (int)b.Gid, FlippedDiagonally = b.FlippedDiagonally, FlippedHorizonally = b.FlippedHorizontally, FlippedVertically = b.FlippedVertically, }); }).ToArray() }; } else { throw new Exception($"Unknown layer type {a.GetType()}"); } result.Name = a.Name; result.Offset = new Vector2(a.OffsetX, a.OffsetY); result.Opacity = a.Opacity; result.Visible = a.Visible; result.Properties = a.Properties.ToDictionary(b => b.Name, b => b.Value); return(result); }).ToList(); return(output); }